
Alibabacloud Odps Maxframe Coding
- 172 installs
- 208 repo stars
- Updated August 4, 2026
- aliyun/alibabacloud-aiops-skills
Author MaxFrame Python jobs on Alibaba ODPS/MaxCompute to transform warehouse tables, train features, and ship reproducible batch analytics without leaving the agent session.
About
alibabacloud-odps-maxframe-coding enables agents to write MaxFrame Python for Alibaba ODPS/MaxCompute: define data transforms, query partitioned tables, optimize job performance, and deliver reproducible batch analytics pipelines on managed big-data compute.
- MaxFrame Python job authoring
- ODPS table read/write patterns
- Partitioning and performance tuning
- Reproducible batch analytics workflows
- MaxCompute integration best practices
Alibabacloud Odps Maxframe Coding by the numbers
- 172 all-time installs (skills.sh)
- Ranked #711 of 2,064 Data Science & ML skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aliyun/alibabacloud-aiops-skills --skill alibabacloud-odps-maxframe-codingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 172 |
|---|---|
| repo stars | ★ 208 |
| Last updated | August 4, 2026 |
| Repository | aliyun/alibabacloud-aiops-skills ↗ |
What it does
Author MaxFrame Python jobs on Alibaba ODPS/MaxCompute to transform warehouse tables, train features, and ship reproducible batch analytics without leaving the agent session.
Files
"""
Example: Basic AI function usage with MaxFrame ManagedTextLLM.
This example demonstrates the minimum setup for using MaxFrame's AI functions
with the managed LLM models. It shows how to perform basic Q&A tasks using
the built-in managed models without requiring external API keys.
Environment variables required:
- ODPS_PROJECT, ODPS_ACCESS_ID, ODPS_ACCESS_KEY, ODPS_ENDPOINT
"""
import os
import dotenv
import maxframe.dataframe as md
from maxframe import options
from maxframe.learn.contrib.llm.models.managed import ManagedTextLLM
from maxframe.session import new_session
from odps import ODPS
# Load environment variables from .env file
# Replace with your actual .env file path or use environment variables directly
dotenv.load_dotenv()
# Configure SQL settings for AI functions
options.sql.settings = {
"odps.sql.split.dop": '{"*":10}',
}
# Create ODPS connection
o = ODPS(
access_id=os.getenv("ODPS_ACCESS_ID"),
secret_access_key=os.getenv("ODPS_ACCESS_KEY"),
project=os.getenv("ODPS_PROJECT"),
endpoint=os.getenv("ODPS_ENDPOINT"),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
# Create MaxFrame session
session = new_session(o)
print(f"Session created: {session.session_id}")
# Create a DataFrame with questions
df = md.DataFrame(
{
"query": [
"地球距离太阳的平均距离是多少?",
"美国独立战争是从哪一年开始的?",
"什么是水的沸点?",
]
}
)
df.execute()
# Use ManagedTextLLM for inference
# Available managed models: qwen2.5-0.5b-instruct, qwen2.5-1.5b-instruct,
# qwen2.5-3b-instruct, Qwen2.5-7B-instruct, DeepSeek-R1-Distill-Qwen-1.5B, etc.
llm = ManagedTextLLM(name="qwen2.5-1.5b-instruct")
# Define prompt template
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "{query}"},
]
# Generate responses
result = llm.generate(df, prompt_template=messages)
result.execute()
# Display results
print("AI Function Results:")
print(
result.response.mf.flatjson(
["$.choices[0].message.content"],
dtypes=["str"],
)
.execute()
.fetch()
)
# Clean up session
session.destroy()
print("Session destroyed")
"""
Example: Processing complex Arrow structures with groupby operations.
This example demonstrates how to work with complex Arrow data types
and process them using groupby with apply_chunk.
Environment variables required:
- ODPS_PROJECT, ODPS_ACCESS_ID, ODPS_ACCESS_KEY, ODPS_ENDPOINT
"""
import json
import os
import dotenv
import maxframe.dataframe as md
import pandas as pd
import pyarrow as pa
from maxframe import options
from maxframe.session import new_session
from odps import ODPS
# Load environment variables
dotenv.load_dotenv()
# Configure SQL settings
options.sql.enable_mcqa = False
options.sql.settings = {
"odps.namespace.schema": "true",
"odps.sql.allow.fullscan": "true",
"odps.sql.enable.distributed.limit": "true",
"odps.session.image": "common",
"odps.maxframe.resolve_dlf_tables": "true",
"odps.sql.type.system.odps2": "true",
}
options.dag.settings = {
"engine_order": ["MCSQL", "DPE"],
}
# Create ODPS connection
o = ODPS(
access_id=os.getenv("ODPS_ACCESS_ID"),
secret_access_key=os.getenv("ODPS_ACCESS_KEY"),
project=os.getenv("ODPS_PROJECT"),
endpoint=os.getenv("ODPS_ENDPOINT"),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
session = new_session(o)
# Define Arrow struct type
struct_type = [
pa.field("calibration_bucket", pa.string()),
pa.field("calibration_file_name", pa.string()),
pa.field("calibration_path", pa.string()),
pa.field("data_id", pa.string()),
pa.field("datanode_info", pa.string()),
pa.field("hdfs_path", pa.string()),
pa.field("meta_uuid", pa.string()),
pa.field("sensor_type", pa.string()),
pa.field("timestamp_bucket", pa.string()),
pa.field("timestamp_path", pa.string()),
]
# Sample data
data = {
"calibration_bucket": ["bucket1", "bucket1", "bucket2", "bucket2", "bucket1"],
"calibration_file_name": ["file1", "file2", "file3", "file4", "file5"],
"calibration_path": ["/path1", "/path2", "/path3", "/path4", "/path5"],
"data_id": ["id1", "id2", "id3", "id4", "id5"],
"datanode_info": ["node1", "node2", "node3", "node4", "node5"],
"hdfs_path": ["/hdfs1", "/hdfs2", "/hdfs3", "/hdfs4", "/hdfs5"],
"meta_uuid": ["uuid1", "uuid1", "uuid2", "uuid2", "uuid1"],
"sensor_type": ["type1", "type1", "type2", "type2", "type1"],
"timestamp_bucket": ["ts1", "ts1", "ts2", "ts2", "ts1"],
"timestamp_path": ["/ts1", "/ts1", "/ts2", "/ts2", "/ts1"],
}
try:
df = md.DataFrame(pd.DataFrame(data))
def process_group(chunk):
"""Process a group and convert records to JSON."""
records = chunk.to_dict(orient="records")
return pd.DataFrame({"records": [json.dumps(records)]})
# Group by meta_uuid and process
grouped = df.groupby("meta_uuid", group_keys=True).mf.apply_chunk(
process_group,
output_type="dataframe",
dtypes=pd.Series(
[pd.ArrowDtype(pa.string())],
index=["records"],
),
skip_infer=True,
)
result = grouped.execute()
print("Result:")
print(result)
finally:
session.destroy()
"""
Example: Processing complex structured data with groupby and apply_chunk.
This example demonstrates how to process complex data structures using
groupby operations with custom chunk processing.
Environment variables required:
- ODPS_PROJECT, ODPS_ACCESS_ID, ODPS_ACCESS_KEY, ODPS_ENDPOINT
"""
import os
import dotenv
import maxframe.dataframe as md
import pandas as pd
from maxframe import options
from maxframe.dataframe.utils import parse_index
from maxframe.session import new_session
from odps import ODPS
from pandas.api.types import pandas_dtype
# Load environment variables
dotenv.load_dotenv()
# Configure SQL settings
options.sql.enable_mcqa = False
options.sql.settings = {
"odps.namespace.schema": "true",
"odps.sql.allow.fullscan": "true",
"odps.sql.enable.distributed.limit": "true",
"odps.session.image": "common",
"odps.maxframe.resolve_dlf_tables": "true",
"odps.sql.type.system.odps2": "true",
}
options.dag.settings = {
"engine_order": ["MCSQL"],
"unavailable_engines": ["DPE", "SPE"],
}
# Create ODPS connection
o = ODPS(
access_id=os.getenv("ODPS_ACCESS_ID"),
secret_access_key=os.getenv("ODPS_ACCESS_KEY"),
project=os.getenv("ODPS_PROJECT"),
endpoint=os.getenv("ODPS_ENDPOINT"),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
session = new_session(o)
# Sample data
data = {
"department": ["HR", "Tech", "HR", "Tech"],
"salary": [6000, 8000, 7000, 9000],
"experience": [3, 5, 4, 6],
}
try:
df = md.DataFrame(pd.DataFrame(data))
def process_each_department(chunk):
"""Process each department group."""
print(chunk, flush=True)
return pd.DataFrame(
{"salary": [chunk["salary"].mean()], "experience": [chunk["experience"].mean()]}
)
# Apply chunk processing with groupby
grouped = df.groupby(["department"], group_keys=True).mf.apply_chunk(
process_each_department,
output_type="dataframe",
dtypes=pd.Series(
[pandas_dtype("float64"), pandas_dtype("float64")],
index=["salary", "experience"],
),
skip_infer=True,
index=parse_index(pd.MultiIndex.from_product([[""], [0]])),
)
result = grouped.execute()
print("Result:")
print(result)
finally:
session.destroy()
"""
Example: Writing to DLF (Data Lake Formation) external tables.
This example demonstrates how to configure MaxFrame to write to DLF external tables.
Environment variables required:
- ODPS_PROJECT, ODPS_ACCESS_ID, ODPS_ACCESS_KEY, ODPS_ENDPOINT
"""
import os
import dotenv
import maxframe.dataframe as md
from maxframe import options
from maxframe.session import new_session
from odps import ODPS
# Load environment variables
dotenv.load_dotenv()
# Replace with your actual table names
input_table = "your_project.your_schema.your_input_table" # DLF external table
output_table = "your_project.your_schema.your_output_table" # DLF external table
lifecycle = 30
# Configure SQL settings for DLF support
options.sql.enable_mcqa = False
options.sql.settings = {
"odps.namespace.schema": "true",
"odps.sql.allow.fullscan": "true",
"odps.sql.enable.distributed.limit": "true", # Enable distributed limit
"odps.session.image": "maxframe_service_dpe_runtime",
"odps.maxframe.resolve_dlf_tables": "true", # Support DLF external tables
}
options.dag.settings = {
"engine_order": ["MCSQL"],
"unavailable_engines": ["DPE", "SPE"],
}
# Create ODPS connection
o = ODPS(
access_id=os.getenv("ODPS_ACCESS_ID"),
secret_access_key=os.getenv("ODPS_ACCESS_KEY"),
project=os.getenv("ODPS_PROJECT"),
endpoint=os.getenv("ODPS_ENDPOINT"),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
# Create session (adjust major_version if needed)
session = new_session(o)
try:
# Read from DLF table
df = md.read_odps_query(f"SELECT * FROM {input_table} LIMIT 100")
# Write to DLF table
md.to_odps_table(df, output_table, lifecycle=lifecycle, overwrite=True, index=True).execute()
finally:
session.destroy()
"""
Example: Writing to DLF PK (Primary Key) tables with binary data handling.
This example demonstrates how to write to DLF tables with primary keys,
including handling binary data types.
Environment variables required:
- ODPS_PROJECT, ODPS_ACCESS_ID, ODPS_ACCESS_KEY, ODPS_ENDPOINT
"""
import os
import dotenv
import maxframe.dataframe as md
import pandas as pd
import pyarrow as pa
from maxframe import options
from maxframe.session import new_session
from odps import ODPS
# Load environment variables
dotenv.load_dotenv()
# Replace with your actual table names
input_table = "your_project.your_schema.your_input_table" # DLF external table
output_table = "your_project.your_schema.your_output_table" # DLF external table
pk_table = "your_project.your_schema.your_pk_table" # DLF PK table
lifecycle = 30
# Configure SQL settings for DLF and PK table support
options.sql.enable_mcqa = False
options.sql.settings = {
"odps.namespace.schema": "true",
"odps.sql.allow.fullscan": "true",
"odps.sql.enable.distributed.limit": "true", # Enable distributed limit
"odps.session.image": "maxframe_service_dpe_runtime",
"odps.maxframe.resolve_dlf_tables": "true", # Support DLF external tables
"odps.sql.type.system.odps2": "true", # Support DLF PK tables
}
options.dag.settings = {
"engine_order": ["MCSQL"],
"unavailable_engines": ["DPE", "SPE"],
}
# Create ODPS connection
o = ODPS(
access_id=os.getenv("ODPS_ACCESS_ID"),
secret_access_key=os.getenv("ODPS_ACCESS_KEY"),
project=os.getenv("ODPS_PROJECT"),
endpoint=os.getenv("ODPS_ENDPOINT"),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
session = new_session(o)
try:
# Write to DLF Append table (default)
df = md.read_odps_table(input_table)
md.to_odps_table(df, output_table, lifecycle=lifecycle, overwrite=True, index=True).execute()
# Write to DLF PK table with binary data
df = pd.DataFrame(
{
"userid": [11, 22],
"username": ["name1", "name2"],
"userbyte": [b"binary_data_11", b"binary_data_22"],
}
)
# Fix incompatible type STRING with destination column userbyte
# Use Arrow binary type for proper binary data handling
new_data = md.DataFrame(df.astype({"userbyte": pd.ArrowDtype(pa.binary())}))
new_data.to_odps_table(f"{pk_table}", overwrite=True).execute()
finally:
session.destroy()
"""
Example: MaxFrame OSS Mount - Read Model Directory
Demonstrates how to use fs_mount to read files from OSS in a distributed manner.
Environment variables required:
- ODPS_PROJECT, ODPS_ACCESS_ID, ODPS_ACCESS_KEY, ODPS_ENDPOINT
- OSS_MOUNT_PATH, OSS_MOUNT_ROLE_ARN
"""
import os
import time
import numpy as np
import pandas as pd
from dotenv import load_dotenv
from maxframe import dataframe as md
from maxframe.config import options
from maxframe.session import new_session
from maxframe.udf import with_fs_mount, with_running_options
from odps import ODPS
load_dotenv()
# MaxFrame configuration
options.sql.enable_mcqa = False
options.sql.settings = {"odps.session.image": "maxframe_service_dpe_runtime"}
options.dag.settings = {"engine_order": ["DPE", "MCSQL", "SPE"]}
# ODPS connection
o = ODPS(
access_id=os.getenv("ODPS_ACCESS_ID"),
secret_access_key=os.getenv("ODPS_ACCESS_KEY"),
project=os.getenv("ODPS_PROJECT"),
endpoint=os.getenv("ODPS_ENDPOINT"),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
session = new_session(o)
print(f"Session: {session.session_id}")
print(f"Logview: {session.get_logview_address()}")
# Define function to read entire directory
# NOTE: memory parameter is in GIGABYTES (GB), not MB!
# memory=4 means 4 GB, NOT 4096 MB
@with_running_options(engine="dpe", cpu=2, memory=4)
@with_fs_mount(
os.getenv("OSS_MOUNT_PATH", "oss://YOUR_BUCKET/YOUR_PATH/"),
"/mnt/model",
storage_options={
"role_arn": os.getenv("OSS_MOUNT_ROLE_ARN", "acs:ram::YOUR_ACCOUNT_ID:role/YOUR_ROLE")
},
)
def read_model_directory(row):
"""Read all files in the model directory"""
import json
import os
import time
worker_id = row.get("worker_id", "UNKNOWN")
model_dir = "/mnt/model"
chunk_size = 4 * 1024 * 1024 # 4 MB
start_time = time.time()
total_bytes = 0
files_read = 0
file_details = []
try:
if not os.path.exists(model_dir):
return {
"worker_id": int(worker_id),
"task_name": str(row.get("task_name", "unknown")),
"status": "directory_not_found",
"total_bytes": 0,
"files_count": 0,
"read_time": 0.0,
"throughput_mbps": 0.0,
"file_details": "[]",
}
for filename in os.listdir(model_dir):
file_path = os.path.join(model_dir, filename)
if not os.path.isfile(file_path):
continue
file_bytes = 0
try:
with open(file_path, "rb") as f:
while chunk := f.read(chunk_size):
file_bytes += len(chunk)
total_bytes += len(chunk)
file_details.append(
{
"filename": filename,
"size_mb": round(file_bytes / 1024 / 1024, 2),
}
)
files_read += 1
except Exception as e:
file_details.append({"filename": filename, "error": str(e)})
read_time = time.time() - start_time
throughput_mbps = (total_bytes / 1024 / 1024) / read_time if read_time > 0 else 0
print(
f"[Worker {worker_id}] Read {files_read} files, {total_bytes / 1024**3:.2f} GB in {read_time:.2f}s ({throughput_mbps:.2f} MB/s)"
)
return {
"worker_id": int(worker_id),
"task_name": str(row.get("task_name", "unknown")),
"status": "success",
"total_bytes": int(total_bytes),
"files_count": int(files_read),
"read_time": float(read_time),
"throughput_mbps": float(throughput_mbps),
"file_details": json.dumps(file_details),
}
except Exception as e:
print(f"[Worker {worker_id}] Error: {str(e)}")
return {
"worker_id": int(worker_id),
"task_name": str(row.get("task_name", "unknown")),
"status": f"error: {str(e)}",
"total_bytes": int(total_bytes),
"files_count": int(files_read),
"read_time": float(time.time() - start_time),
"throughput_mbps": 0.0,
"file_details": "[]",
}
# Create test tasks
num_workers = 10
print(f"\nCreating {num_workers} concurrent tasks...")
data = [{"worker_id": i, "task_name": f"read_dir_{i}"} for i in range(num_workers)]
try:
df = md.DataFrame(pd.DataFrame(data))
df_rebalanced = df.mf.rebalance(num_partitions=num_workers)
# Define output types
output_dtypes = df.dtypes.copy()
output_dtypes.update(
{
"status": np.dtype("O"),
"total_bytes": np.dtype("int64"),
"files_count": np.dtype("int64"),
"read_time": np.dtype("float64"),
"throughput_mbps": np.dtype("float64"),
"file_details": np.dtype("O"),
}
)
# Execute
print("Starting test...")
test_start = time.time()
result = (
df_rebalanced.apply(
read_model_directory,
axis=1,
dtypes=output_dtypes,
output_type="dataframe",
result_type="expand",
)
.execute()
.fetch()
)
total_time = time.time() - test_start
# Statistics
successful = result[result["status"] == "success"]
failed = result[result["status"] != "success"]
print(f"\n{'='*60}")
print(f"Total tasks: {len(result)} | Success: {len(successful)} | Failed: {len(failed)}")
if len(successful) > 0:
normal = successful[(successful["files_count"] > 0) & (successful["read_time"] > 0)]
stats = normal if len(normal) > 0 else successful
print("\nWorker Performance:")
print(f"{'Worker':<8} {'Files':<8} {'Data(GB)':<12} {'Time(s)':<10} {'MB/s':<10}")
print("-" * 60)
for _, row in successful.iterrows():
print(
f"{row['worker_id']:<8} {row['files_count']:<8} "
f"{row['total_bytes']/1024**3:<12.2f} {row['read_time']:<10.2f} {row['throughput_mbps']:<10.2f}"
)
print("\nSummary:")
print(f" Test time: {total_time:.2f}s")
print(
f" Avg read time: {stats['read_time'].mean():.2f}s (min: {stats['read_time'].min():.2f}s, max: {stats['read_time'].max():.2f}s)"
)
print(f" Avg throughput: {stats['throughput_mbps'].mean():.2f} MB/s")
print(f" Total data: {successful['total_bytes'].sum() / 1024**3:.2f} GB")
print(
f" Aggregate throughput: {(successful['total_bytes'].sum() / 1024**2) / total_time:.2f} MB/s"
)
if len(stats) > 0:
speedup = (stats["read_time"].mean() * len(stats)) / total_time if total_time > 0 else 0
print(f" Speedup: {speedup:.2f}x | Efficiency: {speedup / len(stats) * 100:.1f}%")
if len(failed) > 0:
print(f"\nFailed tasks: {failed[['worker_id', 'status']].to_string(index=False)}")
print("Done!")
finally:
session.destroy()
"""
Example: Using GPU Units (GU) with DPE engine for accelerated processing.
This example demonstrates how to use the @with_running_options decorator
to allocate GPU Units (GU) when running operations on the DPE engine.
GU allocation enables GPU-accelerated processing for compute-intensive tasks.
Environment variables required:
- ODPS_PROJECT, ODPS_ACCESS_ID, ODPS_ACCESS_KEY, ODPS_ENDPOINT
"""
import os
import dotenv
import maxframe.dataframe as md
import numpy as np
from maxframe.config import options
from maxframe.session import new_session
from maxframe.udf import with_running_options
from odps import ODPS
# Load environment variables from .env file
# Replace with your actual .env file path or use environment variables directly
dotenv.load_dotenv()
# Configure DPE engine settings
options.dag.settings = {
"engine_order": ["DPE"],
"unavailable_engines": ["MCSQL", "SPE"],
}
options.sql.settings = {"odps.session.image": "maxframe_service_dpe_runtime"}
options.local_execution.enabled = False
# Create ODPS connection
o = ODPS(
access_id=os.getenv("ODPS_ACCESS_ID"),
secret_access_key=os.getenv("ODPS_ACCESS_KEY"),
project=os.getenv("ODPS_PROJECT"),
endpoint=os.getenv("ODPS_ENDPOINT"),
tunnel_endpoint=os.getenv("ODPS_TUNNEL_ENDPOINT"),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
# Create MaxFrame session
session = new_session(o)
print(f"Session created: {session.get_logview_address()}")
# Define a function that uses GPU resources
# Replace 'your_gu_quota' with your actual GU quota name
# NOTE: This example uses GPU Units (GU) instead of CPU/memory
# For CPU/memory allocation, use parameters like: cpu=2, memory=4 (memory in GB!)
@with_running_options(engine="dpe", gu=1, gu_quota="your_gu_quota")
def gpu_accelerated_process(row):
"""
Process data with GPU acceleration.
This function will be executed on DPE engine with 1 GU allocated.
Replace this with your actual GPU-accelerated logic.
"""
# Example: perform some computation
result = row.copy()
result["C"] = result["A"] * result["B"]
return result
# Create sample DataFrame
df_input = md.DataFrame(
{
"A": np.random.randint(1, 100, 1000),
"B": np.random.randint(1, 100, 1000),
}
)
try:
# Apply the GPU-accelerated function
df_result = df_input.apply(
gpu_accelerated_process,
axis=1,
dtypes=df_input.dtypes,
output_type="dataframe",
result_type="expand",
skip_infer=True,
)
# Execute and fetch results
result = df_result.execute().fetch()
print(f"Processing completed. Result shape: {result.shape}")
print(f"First 5 rows:\n{result.head()}")
finally:
# Clean up session
session.destroy()
print("Session destroyed")
"""
Example: GroupBy operations with apply_chunk for batch processing.
This example demonstrates how to use groupby with apply_chunk to process
data in batches efficiently.
Environment variables required:
- ODPS_PROJECT, ODPS_ACCESS_ID, ODPS_ACCESS_KEY, ODPS_ENDPOINT
"""
import logging
import os
import dotenv
import maxframe.dataframe as md
import numpy as np
import pandas as pd
from maxframe.dataframe.utils import parse_index
from maxframe.session import new_session
from odps import ODPS
logging.basicConfig(level=logging.INFO)
# Load environment variables from .env file
# Replace with your actual .env file path or use environment variables directly
dotenv.load_dotenv()
o = ODPS(
access_id=os.getenv("ODPS_ACCESS_ID"),
secret_access_key=os.getenv("ODPS_ACCESS_KEY"),
project=os.getenv("ODPS_PROJECT"),
endpoint=os.getenv("ODPS_ENDPOINT"),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
session = new_session(o)
try:
# Create sample DataFrame
df = md.read_pandas(
pd.DataFrame(
{
"A": np.random.choice(["group1", "group2", "group3"], 3000),
"B": np.random.randn(3000),
"C": np.random.randn(3000),
"D": np.random.randn(3000),
"E": np.random.randn(3000),
}
)
)
df.execute()
def process_batch(chunk):
"""Process a batch of data."""
return chunk[["B"]]
# Apply chunk processing with groupby
result_df = df.groupby(["A"], group_keys=True).mf.apply_chunk(
process_batch,
batch_rows=1000,
output_type="dataframe",
)
print(f"Result dtypes: {result_df.dtypes}")
print(f"Result index: {result_df.index_value}")
result_df.execute()
def process_to_json(chunk):
"""Process chunk and convert to JSON string."""
import json
print(chunk, flush=True)
print(f"Group shape: {chunk.shape}")
list_value = json.dumps(chunk["B"].tolist(), ensure_ascii=False)
result = pd.DataFrame({"B": [list_value]})
print(result, flush=True)
return result
# Apply chunk with custom index
result_df = df.groupby(["A"], group_keys=True).mf.apply_chunk(
process_to_json,
batch_rows=1000,
output_type="dataframe",
index=parse_index(pd.MultiIndex.from_product([[""], [0]])),
)
print(f"Result dtypes: {result_df.dtypes}")
print(f"Result index: {result_df.index_value}")
result_df.execute()
finally:
session.destroy()
"""
Minimum example showing how to use oss_mount with single and multiple mounting.
Environment variables required:
- ODPS_PROJECT, ODPS_ACCESS_ID, ODPS_ACCESS_KEY, ODPS_ENDPOINT
- OSS_BUCKET_NAME, OSS_ENDPOINT, OSS_ROLE_ARN
"""
import os
import dotenv
import maxframe.dataframe as md
from maxframe.config import options
from maxframe.session import new_session
from maxframe.udf import with_fs_mount, with_running_options
from odps import ODPS
# Load environment variables from .env file
dotenv.load_dotenv()
options.sql.enable_mcqa = False
options.sql.settings = {"odps.session.image": "maxframe_service_dpe_runtime"}
options.dag.settings = {"engine_order": ["DPE", "MCSQL", "SPE"]}
# Initialize ODPS and session
o = ODPS(
access_id=os.getenv("ODPS_ACCESS_ID"),
secret_access_key=os.getenv("ODPS_ACCESS_KEY"),
project=os.getenv("ODPS_PROJECT"),
endpoint=os.getenv("ODPS_ENDPOINT"),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
session = new_session(o, major_version=os.getenv("ODPS_MAJOR_VERSION", "default"))
print(f"Logview: {session.get_logview_address()}")
print(f"Session ID: {session.session_id}")
# Example 1: Single OSS mount
# NOTE: memory parameter is in GIGABYTES (GB), not MB!
# memory=2 means 2 GB, NOT 2048 MB
@with_running_options(engine="dpe", cpu=1, memory=2)
@with_fs_mount(
f"oss://{os.getenv('OSS_ENDPOINT')}/{os.getenv('OSS_BUCKET_NAME')}/data/",
"/mnt/oss_data",
storage_options={"role_arn": os.getenv("OSS_ROLE_ARN")},
)
def process_with_single_mount(row):
"""Example with single OSS mount"""
import os
mount_path = "/mnt/oss_data"
if os.path.exists(mount_path):
files = os.listdir(mount_path)
print(f"Single mount successful. Files: {files}")
else:
print("Single mount failed")
return row
# Example 2: Multiple OSS mounts
# NOTE: memory parameter is in GIGABYTES (GB), not MB!
# memory=2 means 2 GB, NOT 2048 MB
@with_running_options(engine="dpe", cpu=1, memory=2)
@with_fs_mount(
f"oss://{os.getenv('OSS_ENDPOINT')}/{os.getenv('OSS_BUCKET_NAME')}/data1/",
"/mnt/oss_data1",
storage_options={"role_arn": os.getenv("OSS_ROLE_ARN")},
)
@with_fs_mount(
f"oss://{os.getenv('OSS_ENDPOINT')}/{os.getenv('OSS_BUCKET_NAME')}/data2/",
"/mnt/oss_data2",
storage_options={"role_arn": os.getenv("OSS_ROLE_ARN")},
)
@with_fs_mount(
f"oss://{os.getenv('OSS_ENDPOINT')}/{os.getenv('OSS_BUCKET_NAME')}/data3/",
"/mnt/oss_data3",
storage_options={"role_arn": os.getenv("OSS_ROLE_ARN")},
)
def process_with_multiple_mounts(row):
"""Example with multiple OSS mounts"""
import os
mount_paths = ["/mnt/oss_data1", "/mnt/oss_data2", "/mnt/oss_data3"]
for mount_path in mount_paths:
if os.path.exists(mount_path):
files = os.listdir(mount_path)
print(f"Mount {mount_path} successful. Files: {files}")
else:
print(f"Mount {mount_path} failed")
return row
# Create a simple test dataframe
df = md.DataFrame({"id": [1, 2, 3]})
# Test single mount
print("\n=== Testing Single Mount ===")
df_single = df.apply(
process_with_single_mount,
axis=1,
dtypes=df.dtypes,
output_type="dataframe",
result_type="expand",
skip_infer=True,
)
result_single = df_single.execute().fetch()
print(result_single)
# Test multiple mounts
print("\n=== Testing Multiple Mounts ===")
df_multi = df.apply(
process_with_multiple_mounts,
axis=1,
dtypes=df.dtypes,
output_type="dataframe",
result_type="expand",
skip_infer=True,
)
result_multi = df_multi.execute().fetch()
print(result_multi)
print("\nAll tests completed!")
# Clean up
session.destroy()
Common Workflow Complete Guide
Detailed guide for the complete MaxFrame development workflow with comprehensive examples.
Session Setup Patterns
Pattern 1: Auto-detect (DataWorks/MaxCompute Notebook)
import os
import maxframe.dataframe as md
from maxframe.session import new_session
from odps import ODPS
# Auto-detect from environment (preferred in DataWorks/MaxCompute Notebook)
session = new_session()Pattern 2: Explicit ODPS Connection
import os
import dotenv
import maxframe.dataframe as md
from maxframe.session import new_session
from odps import ODPS
dotenv.load_dotenv()
o = ODPS(
access_id=os.getenv("ODPS_ACCESS_ID"),
secret_access_key=os.getenv("ODPS_ACCESS_KEY"),
project=os.getenv("ODPS_PROJECT"),
endpoint=os.getenv("ODPS_ENDPOINT"),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
session = new_session(o)Pattern 3: Production-ready Session
import logging
import maxframe.dataframe as md
from maxframe.session import new_session
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
session = new_session()
try:
logger.info(f"Session created. Logview: {session.get_logview_address()}")
# Your operations
...
finally:
session.destroy()
logger.info("Session destroyed")Reading Data Patterns
Pattern 1: Basic Table Read
# Read from MaxCompute table
df = md.read_odps_table("table_name")
# Read with index column
df = md.read_odps_table("table_name", index_col="id")
# With column selection
df = md.read_odps_table("table_name", columns=['id', 'value', 'timestamp'])
# With partition filter
df = md.read_odps_table("table_name", partition='ds=2024-01-01')Pattern 2: SQL Query Read
# Read from SQL query with filters
df = md.read_odps_query(
"SELECT * FROM table WHERE date >= '2024-01-01' AND status = 'active'"
)
# Complex SQL with joins
df = md.read_odps_query(
"SELECT a.*, b.value FROM table_a a JOIN table_b b ON a.id = b.id"
)Pattern 3: Sample Data Construction
When user doesn't provide input table name, construct pandas DataFrame:
import pandas as pd
import numpy as np
# Time series analysis example
example_pd_df = pd.DataFrame({
'timestamp': pd.date_range('2026-01-01', periods=1000, freq='H'),
'metric_name': np.random.choice(['cpu', 'memory', 'disk'], 1000),
'value': np.random.randn(1000) * 10 + 50,
'host_id': np.random.choice(['host1', 'host2', 'host3'], 1000)
})
# Load into MaxFrame
df = md.read_pandas(example_pd_df)Key guidelines for sample data:
- Match data types and structure to job requirements
- Use realistic value ranges for the domain
- Include 100-1000 rows to demonstrate logic
- Use descriptive column names matching operations
Operator Selection Workflow
Step 1: Identify Required Operations
Break down the task into specific operations needed:
- Filtering
- Grouping
- Aggregation
- Transformation
- Merging
- Sorting
Step 2: Find MaxFrame Operators
Use operator-selector agent or script:
# Search for operators by task description
python scripts/lookup_operator.py search "time series resampling"
# Check if a specific operator exists
python scripts/lookup_operator.py info apply_chunk
# Get detailed operator information
python scripts/lookup_operator.py info groupbyStep 3: Present Options to User
For your data aggregation task, I've identified these options:
1. `groupby().agg()` - Standard pandas-compatible approach
- Pros: Familiar API, good for standard aggregations
- Cons: May be slow for large datasets with custom logic
2. `mf.apply_chunk()` - For custom aggregation with large datasets
- Pros: Efficient batch processing, custom logic support
- Cons: More complex, requires batch size tuning
Which approach do you prefer, or would you like me to explore other options?Step 4: Get User Confirmation
MANDATORY: Do not proceed without user confirmation.
Processing Patterns
Pattern 1: Standard pandas Operations
# Filter
filtered = df[df['column'] > 10]
# GroupBy and aggregate
result = df.groupby('category').agg({'value': 'sum'})
# Add columns
df['new_col'] = df['col1'] + df['col2']
# Sort
df_sorted = df.sort_values('column')
# Merge
df_merged = df1.merge(df2, on='key')
# Multiple aggregations
result = df.groupby('category').agg({
'value': ['sum', 'mean', 'count'],
'price': 'max'
})Pattern 2: Batch Processing (Large Datasets)
def process_batch(chunk):
# Custom processing logic
return chunk * 2
result = df.mf.apply_chunk(
process_batch,
batch_rows=1024, # Tune batch size for performance
output_type='dataframe'
)Pattern 3: UDF with Resource Allocation
from maxframe.udf import with_running_options
@with_running_options(engine="dpe", cpu=2, memory=4)
def process_batch(batch):
# CRITICAL: memory=4 means 4 GB, NOT 4 MB
return batch * 2
result = df.mf.apply_chunk(process_batch)Writing Data Patterns
Pattern 1: Write to MaxCompute Table
# Write to MaxCompute table
md.to_odps_table(df, "output_table", overwrite=True).execute()Pattern 2: Write to DLF External Table
from maxframe import options
# Enable DLF support
options.sql.settings = {
"odps.maxframe.resolve_dlf_tables": "true"
}
md.to_odps_table(df, "dlf_table").execute()Pattern 3: Multiple Output Tables
try:
md.to_odps_table(df1, "output_table1").execute()
md.to_odps_table(df2, "output_table2").execute()
finally:
session.destroy()Execution and Cleanup Patterns
Pattern 1: Basic Execution
# Execute operations (required for lazy execution)
result.execute()
# Destroy session when done
session.destroy()Pattern 2: Safe Cleanup (Production)
try:
# Execute operations
result.execute()
finally:
# Destroy session (always runs, even on error)
session.destroy()Pattern 3: Comprehensive Cleanup
import logging
logger = logging.getLogger(__name__)
try:
result.execute()
logger.info("Execution successful")
except Exception as e:
logger.error(f"Execution failed: {e}")
raise
finally:
try:
session.destroy()
logger.info("Session destroyed")
except Exception as cleanup_error:
logger.warning(f"Cleanup error: {cleanup_error}")Verification Pattern
Use py_compile to test generated job script:
python -m py_compile your_script.pyComplete Example Pipeline
import os
import logging
import dotenv
import maxframe.dataframe as md
from maxframe.session import new_session
dotenv.load_dotenv()
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Setup session
session = new_session()
try:
logger.info(f"Session created. Logview: {session.get_logview_address()}")
# Read data
df = md.read_odps_table("source_table", columns=['id', 'value', 'category'])
# Process (after confirming operators with user)
filtered = df[df['value'] > 100]
result = filtered.groupby('category').agg({'value': 'sum'})
# Write output
md.to_odps_table(result, "output_table", overwrite=True).execute()
logger.info("Job completed successfully")
logger.info(f"Final Logview: {session.get_logview_address()}")
finally:
session.destroy()
logger.info("Session destroyed")MaxFrame Installation Guide
This guide provides step-by-step instructions for installing and configuring MaxFrame for distributed data processing on MaxCompute.
Table of Contents
- Prerequisites
- Dependencies
- Environment Configuration
- Required Environment Variables
- Setting Environment Variables
- Find Your MaxCompute Endpoint
- Installation Verification
- Session Setup
- Manual Session Creation
- Auto-Detect from Environment
- Troubleshooting
- Common Issues
- Getting Help
- Next Steps
- Cleanup
Prerequisites
- Python 3.7 or higher
- MaxCompute (ODPS) account with valid credentials
- Access to a MaxCompute project
Dependencies
Install the required Python packages:
pip install maxframe -UThe required packages are:
- maxframe - MaxFrame SDK for distributed data processing
- pyodps - ODPS Python SDK for MaxCompute access
- pandas - Data manipulation library (for pandas-compatible APIs)
Environment Configuration
Required Environment Variables
Configure the following environment variables to authenticate with MaxCompute:
| Variable | Description |
|---|---|
ODPS_ACCESS_ID | MaxCompute access ID (username) |
ODPS_ACCESS_KEY | MaxCompute access key (password) |
ODPS_PROJECT | MaxCompute project name |
ODPS_ENDPOINT | MaxCompute endpoint URL |
Setting Environment Variables
Option 1: Set in Shell
export ODPS_ACCESS_ID="your_access_id"
export ODPS_ACCESS_KEY="your_access_key"
export ODPS_PROJECT="your_project_name"
export ODPS_ENDPOINT="your_endpoint"Option 2: Use .env File
Create a .env file in your project directory:
ODPS_ACCESS_ID=your_access_id
ODPS_ACCESS_KEY=your_access_key
ODPS_PROJECT=your_project_name
ODPS_ENDPOINT=your_endpointThen load the environment variables in Python:
from dotenv import load_dotenv
load_dotenv()Find Your MaxCompute Endpoint
MaxCompute endpoints vary by region, check the MaxCompute documentation for the correct endpoint for your region.
Installation Verification
Verify your installation by running the following Python script:
import os
from dotenv import load_dotenv
from odps import ODPS
from maxframe.session import new_session
# Load environment variables
load_dotenv()
# Create ODPS connection
o = ODPS(
access_id=os.getenv("ODPS_ACCESS_ID"),
secret_access_key=os.getenv("ODPS_ACCESS_KEY"),
project=os.getenv("ODPS_PROJECT"),
endpoint=os.getenv("ODPS_ENDPOINT"),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
# Create MaxFrame session
session = new_session(o)
print("MaxFrame installation verified successfully!")
print(f"Connected to project: {o.project}")
# Destroy session when done
session.destroy()Session Setup
Manual Session Creation
Create a session with explicit credentials:
import os
import maxframe.dataframe as md
from maxframe.session import new_session
from odps import ODPS
# Create ODPS connection
o = ODPS(
access_id=os.getenv("ODPS_ACCESS_ID"),
secret_access_key=os.getenv("ODPS_ACCESS_KEY"),
project=os.getenv("ODPS_PROJECT"),
endpoint=os.getenv("ODPS_ENDPOINT"),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
# Create MaxFrame session
session = new_session(o)Auto-Detect from Environment
In environments like DataWorks or MaxCompute Notebook, ODPS credentials are automatically available:
from maxframe.session import new_session
# Auto-detects ODPS from environment
session = new_session()Troubleshooting
Common Issues
Issue: Connection Authentication Failed
Symptoms: Error message indicating invalid credentials or authentication failure.
Solutions:
- Verify all environment variables are set correctly
- Check that your access key has not expired
- Ensure you have the correct endpoint for your region
- Verify your project name is accurate
# Test environment variables
echo $ODPS_ACCESS_ID
echo $ODPS_PROJECT
echo $ODPS_ENDPOINTIssue: Package Installation Fails
Symptoms: pip install fails with dependency conflicts or permission errors.
Solutions:
- Use a virtual environment to isolate dependencies:
python -m venv maxframe_env
source maxframe_env/bin/activate # On Windows: maxframe_env\Scripts\activate
pip install maxframe pyodps pandas --prefer-binary- Upgrade pip before installing:
pip install --upgrade pip
pip install maxframe pyodps pandas --prefer-binaryIssue: Session Creation Fails
Symptoms: new_session() raises an exception.
Solutions:
- Verify network connectivity to the MaxCompute endpoint
- Check firewall rules allow outbound connections
- Ensure your MaxCompute account has the necessary permissions
- Try the auto-detect method if available in your environment
- Use VPC endpoint if you are in vpc networking
Issue: Lazy Execution Not Working
Symptoms: Operations appear to do nothing until .execute() is called.
Note: This is expected behavior. MaxFrame uses lazy execution. Always call .execute() to trigger computation:
# This does not execute immediately
result = df.groupby('category').sum()
# Execute the computation
result.execute()Getting Help
If you encounter issues not covered here:
1. Check the MaxFrame Documentation 2. Review the MaxFrame Client Repository 3. Consult the sample code in assets/examples/ for working examples 4. Contact your MaxCompute administrator for account-specific issues
Next Steps
After successful installation:
1. Review the MaxFrame Context Guide for comprehensive feature documentation 2. Explore the sample code for working examples 3. Start building your first MaxFrame program using the Common Workflow
Cleanup
Destroy your session when done to free resources:
session.destroy()MaxFrame Local Debug Mode Guide
This guide provides comprehensive instructions for using MaxFrame's local debug mode, which enables offline UDF development with full IDE debugging support.
Overview
MaxFrame Local Debug Mode is designed for data development engineers to debug UDF (User-Defined Functions) locally without connecting to remote MaxCompute services. It provides a seamless development experience with IDE breakpoint support for functions like apply() and apply_chunk().
Core Value
| Feature | Traditional Approach | Local Debug Mode |
|---|---|---|
| Breakpoint Debugging | ❌ Not supported | ✅ Full IDE support |
| Remote Dependency | ❌ Requires cluster connection | ✅ Completely offline |
| Debug Cycle | ❌ Submit to remote each time | ✅ Local immediate execution |
| Code Changes | ❌ Multiple code versions | ✅ Same code for dev/prod |
Key Benefits
1. Zero-Configuration Startup: Simply use debug=True or debug="local" - no additional tools or services required 2. Completely Offline: No dependency on network or remote cluster resources 3. Native IDE Support: Breakpoints, variable inspection, step-by-step execution - all debugging capabilities preserved 4. Flexible Data Sources: Support for in-memory data, local files, or MaxCompute tables 5. Seamless Production Switch: Remove debug=True parameter and code runs directly in production
When to Use Local Debug Mode
Use local debug mode when:
- Developing UDF functions (
apply,apply_chunk) - Need IDE breakpoints and step-by-step debugging
- Want to debug offline without network access
- Working on complex logic that requires iterative testing
- Need to verify data transformation logic quickly
Use remote debug mode instead when:
- Testing with production-scale data on MaxCompute
- Need to verify execution on actual cluster
- Investigating runtime issues that require logview URLs
- Debugging distributed execution problems
Quick Start
Prerequisites
pip install --upgrade maxframe # Requires MaxFrame SDK 2.5.0 or laterBasic Example
from odps import ODPS
from maxframe import new_session
import maxframe.dataframe as md
import pandas as pd
# Initialize ODPS object
# Note: In local debug mode, ODPS object is only used for schema validation
# Actual credentials are not used for execution
o = ODPS(
access_id=os.getenv('ODPS_ACCESS_ID', 'dummy_access_id'),
secret_access_key=os.getenv('ODPS_ACCESS_KEY', 'dummy_secret_key'),
project=os.getenv('ODPS_PROJECT', 'dummy_project'),
endpoint=os.getenv('ODPS_ENDPOINT', 'dummy_endpoint'),
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
# Enable local debug mode
session = new_session(o, debug=True)
# Prepare sample data
df = md.DataFrame(pd.DataFrame({
"sales": [5000, 8000, 12000, 3000],
"region": ["A", "B", "C", "D"]
}))
def calculate_commission(row):
sales = row['sales']
if sales > 10000: # Set breakpoint here
rate = 0.15
print(rate)
elif sales > 5000: # Set breakpoint here
rate = 0.10
print(rate)
else:
rate = 0.05
return sales * rate
# Execute and get results
result = df.apply(calculate_commission, axis=1).execute().fetch()
print(result)Key Features
1. Zero-Configuration Startup
Simply add debug=True or debug="local" when creating a session:
# Local debug mode
session = new_session(o, debug=True)
# or
session = new_session(o, debug="local")
# Production mode (just remove debug parameter)
session = new_session(o)2. IDE-Friendly Debugging
- Supported IDEs: PyCharm, VSCode, and other mainstream IDEs, as well as DataWorks Notebook
- Breakpoints: Set breakpoints anywhere in your UDF functions
- Step-by-Step Execution: Use F5/F6/F7/F8 to navigate through code
- Variable Inspection: View and modify variables during debugging
- Debugging Experience: Identical to local Python development
3. Multiple Data Sources
| Data Source Type | Access Method | Use Case |
|---|---|---|
| In-Memory Data | md.DataFrame(pd.DataFrame()) | Quick logic validation |
| MaxCompute Table | md.read_odps_table() | Real data testing |
| Local Files | pd.read_csv() and other native Pandas interfaces | Offline development |
Example with different data sources:
# 1. In-memory data (fastest for testing)
import pandas as pd
df = md.DataFrame(pd.DataFrame({
"col1": [1, 2, 3],
"col2": ["a", "b", "c"]
}))
# 2. MaxCompute table (real data)
df = md.read_odps_table("your_table_name")
# 3. Local file (offline development)
local_df = pd.read_csv("local_data.csv")
df = md.read_pandas(local_df)4. Code Compatibility
Debugging code is identical to production code. Simply remove the debug parameter when deploying:
# Development environment
session = new_session(o, debug=True)
# ... your code ...
# Production environment
session = new_session(o)
# ... same code ...Application Scenarios
| Scenario | Description |
|---|---|
| UDF Logic Development | Real-time debugging and verification when writing complex business logic |
| Data Transformation Testing | Validate data cleaning and transformation rules |
| Problem Investigation | Identify root causes of UDF execution exceptions |
| Offline Development | Continue development work in environments without network access |
Important Considerations
1. Performance Differences
Local debug mode is designed for development and verification. Performance characteristics differ from production environment:
- Execution happens locally, not distributed
- Performance is not representative of production cluster performance
- Best suited for small-scale sample data
2. Data Volume Limitations
For optimal debugging experience:
- Use small-scale sample data (recommended: 100-1000 rows)
- Large datasets may slow down local execution
- Focus on logic correctness rather than performance
3. Dependency Consistency
Ensure local Python environment matches production:
- Same Python version
- Same package versions (maxframe, pandas, numpy, etc.)
- Use
pip freeze > requirements.txtto capture dependencies
4. Sensitive Data Handling
When debugging with MaxCompute tables:
- Be aware of data permissions and access controls
- Consider data masking for sensitive information
- Use sample/partitioned data to limit exposure
- Never commit sensitive credentials to version control
Common Debugging Patterns
Pattern 1: Breakpoint in Apply Function
def process_row(row):
# Set breakpoint on this line
value = row['column_name']
if value > threshold:
# Set breakpoint here to inspect condition
result = transform(value)
else:
result = default_value
return result
df = md.DataFrame(sample_data)
result = df.apply(process_row, axis=1).execute().fetch()Pattern 2: Debugging Apply_Chunk for Batch Processing
def process_batch(chunk):
# Set breakpoint here to inspect entire chunk
print(f"Processing batch with {len(chunk)} rows")
# Debug data types
print(f"Chunk dtypes:\n{chunk.dtypes}")
# Debug transformations
chunk['new_col'] = chunk['col1'] * 2
# Set breakpoint here to verify results
return chunk
result = df.mf.apply_chunk(
process_batch,
batch_rows=100,
output_type='dataframe'
).execute().fetch()Pattern 3: Debugging with Print Statements
def debug_function(row):
print(f"Input row: {row.to_dict()}")
# Step 1
intermediate = row['col1'] + row['col2']
print(f"After step 1: {intermediate}")
# Step 2
result = intermediate * 2
print(f"Final result: {result}")
return result
# Execute with debug output
result = df.apply(debug_function, axis=1).execute().fetch()Transitioning to Production
Steps to Deploy
1. Test Locally: Develop and debug with local debug mode 2. Verify Logic: Ensure all transformations work correctly 3. Remove Debug Parameter: Change new_session(o, debug=True) to new_session(o) 4. Test on Cluster: Run on MaxCompute with small dataset 5. Production Deploy: Deploy to production environment
Code Checklist
Before deploying to production:
- [ ] Remove
debug=Trueparameter from session creation - [ ] Verify all data source paths are correct for production
- [ ] Test with production-scale data on MaxCompute
- [ ] Remove or reduce print statements used for debugging
- [ ] Add proper error handling and logging
- [ ] Verify resource quotas and permissions
Troubleshooting
Issue: IDE Breakpoints Not Triggering
Possible Causes:
- Session created without
debug=True - Using incompatible IDE or debugger
- Code not actually executing through apply/apply_chunk
Solutions:
- Verify
debug=Trueinnew_session() - Ensure you're using a supported IDE (PyCharm, VSCode)
- Check that
.execute()is called to trigger execution
Issue: Local Execution Too Slow
Possible Causes:
- Dataset too large for local debugging
- Complex operations not optimized for local execution
Solutions:
- Reduce sample data size (use
df.head(100)or sample) - Simplify operations for debugging purposes
- Focus on specific problematic code sections
Issue: Results Differ from Production
Possible Causes:
- Data differences between sample and production data
- Environmental differences (Python version, package versions)
- Distributed vs. local execution semantics
Solutions:
- Verify data consistency between environments
- Check Python and package versions match
- Test on MaxCompute with
debug=Falseto verify
Summary
Local debug mode provides a powerful development experience for MaxFrame UDF development:
- Zero-configuration startup with
debug=True - Full IDE debugging support with breakpoints
- Flexible data source options
- Seamless transition to production
- Perfect for iterative UDF development
Use local debug mode during development for rapid iteration, then switch to remote debug mode for cluster-based testing and validation.
Resources
- MaxFrame Context Guide:
./maxframe-context.md- Comprehensive MaxFrame features and workflows - Interactive Coding Guide:
./remote-debug-guide.md- Remote debug mode with logview support - Key Modules Reference:
./key-modules.md- DataFrame, Tensor, and ML operations
Comparison with other tools
- Comparison with PyODPS DataFrame
- Object abstraction
- Functions
- Execution
Comparison with PyODPS DataFrame
PyODPS DataFrame is a DataFrame-like package provided by MaxCompute as a part of PyODPS package. It provides capability for Python data analyzers to query MaxCompute data with a set of operators similar to pandas. Despite the similarity in operators, the usage between two sets of APIs are quite different. It might not be easy for a developer to dive deep into PyODPS DataFrame with knowledge about pandas only.
Though PyODPS DataFrame is still part of PyODPS, it is recommended to create new applications with MaxFrame to enjoy its compatibility with pandas.
Object abstraction
PyODPS DataFrame does not have indexes. This means that a majority of pandas APIs with indexes cannot be used or not fully supported.
For instance, arithmetic operations in pandas relies on index alignment. That is, two DataFrames are aligned first, and then arithmetic operation is performed.
>>> series1 = pd.Series([2, 1, 3], index=[1, 2, 4])
>>> series2 = pd.Series([1, 5, 6], index=[1, 3, 4])
>>> series1 + series2
1 3.0
2 NaN
3 NaN
4 9.0
dtype: float64However, when indexes are absent, this kind of operation is not supported.
To support this kind of operation, in MaxFrame, it is required to add an index column to DataFrame or Series. If the index is absent, a default RangeIndex is added. Therefore the statement above can be supported.
Another huge difference between PyODPS DataFrame and MaxFrame is that in PyODPS DataFrame, representation of data objects and operators are mixed, and this may confuse newcomers. For instance,
df = o.get_table('table_name').to_df() # df is a DataFrame instance
df2 = df["col1", "col2"] # df2 is a CollectionExpr instanceIn the second line, df2 is an instance of CollectionExpr which means it is an expression and different from a DataFrame instance. However, all DataFrame functions can be applied directly onto df2 and there is nothing different from DataFrame instance.
In MaxFrame, however, data objects and operators are defined separately. Data objects users interact with are all instances of a few data classes, namely DataFrame, Series or Index. For the example above, now all instances are DataFrame now.
df = md.read_odps_table('table_name') # df is a DataFrame instance
df2 = df[["col1", "col2"]] # df2 is also a DataFrame instanceFunctions
Functions in PyODPS DataFrame are not fully compatible with pandas. Therefore to write code with PyODPS DataFrame, users need to read the documents first before start coding. However, the target of MaxFrame is to create a pandas-compatible API. Hence there are API differences between PyODPS DataFrame and MaxFrame. These differences are listed below. Methods starts with mf. mean that these non-pandas methods are added in MaxFrame to facilitate migrating from PyODPS DataFrame to MaxFrame. Note that you need to read API documents of these functions before rewriting your code.
| PyODPS DataFrame API | MaxFrame API |
|---|---|
| DataFrame.append_id | Not needed. DataFrame index is added by default |
| DataFrame.bloom_filter | Not implemented yet |
| DataFrame.boxplot | DataFrame.plot.boxplot |
| DataFrame.concat | maxframe.dataframe.concat |
| DataFrame.describe | DataFrame.describe |
| DataFrame.distinct | DataFrame.drop_duplicates |
| DataFrame.except_ | DataFrame.merge with filter |
| DataFrame.exclude | DataFrame.drop |
| DataFrame.extract_kv | Not implemented yet |
| DataFrame.hist | DataFrame.plot.hist |
| DataFrame.inner_join | DataFrame.merge |
| DataFrame.intersect | DataFrame.merge |
| DataFrame.left_join | DataFrame.merge |
| DataFrame.limit | DataFrame.head |
| DataFrame.map_reduce | DataFrame.mf.map_reduce |
| DataFrame.minmax_scale | Not implemented yet |
| DataFrame.outer_join | DataFrame.merge |
| DataFrame.persist | DataFrame.to_odps_table |
| DataFrame.reshuffle | DataFrame.mf.reshuffle |
| DataFrame.right_join | DataFrame.merge |
| DataFrame.setdiff | DataFrame.merge |
| DataFrame.split | Not implemented yet |
| DataFrame.std_scale | Not implemented yet |
| DataFrame.sort | DataFrame.sort_values |
| DataFrame.switch | maxframe.dataframe.case_when |
| DataFrame.to_kv | Not implemented yet |
| DataFrame.union | maxframe.dataframe.concat |
| DatetimeSequenceExpr.date | Series.dt.date |
| DatetimeSequenceExpr.day | Series.dt.day |
| DatetimeSequenceExpr.dayofweek | Series.dt.dayofweek |
| DatetimeSequenceExpr.dayofyear | Series.dt.dayofyear |
| DatetimeSequenceExpr.hour | Series.dt.hour |
| DatetimeSequenceExpr.is_month_end | Series.dt.is_month_end |
| DatetimeSequenceExpr.is_month_start | Series.dt.is_month_start |
| DatetimeSequenceExpr.is_year_end | Series.dt.is_year_end |
| DatetimeSequenceExpr.is_year_start | Series.dt.is_year_start |
| DatetimeSequenceExpr.microsecond | Series.dt.microsecond |
| DatetimeSequenceExpr.min | Series.dt.min |
| DatetimeSequenceExpr.minute | Series.dt.minute |
| DatetimeSequenceExpr.month | Series.dt.month |
| DatetimeSequenceExpr.second | Series.dt.second |
| DatetimeSequenceExpr.strftime | Series.dt.strftime |
| DatetimeSequenceExpr.unix_timestamp | Not implemented yet |
| DatetimeSequenceExpr.week | Series.dt.week |
| DatetimeSequenceExpr.weekday | Series.dt.weekday |
| DatetimeSequenceExpr.weekofyear | Series.dt.weekofyear |
| DatetimeSequenceExpr.year | Series.dt.year |
| SequenceExpr.degrees | np.degrees(Series) |
| SequenceExpr.radians | np.radians(Series) |
| SequenceExpr.tolist | Series.to_numpy |
| SequenceExpr.to_datetime | maxframe.dataframe.to_datetime |
| SequenceExpr.topk | Not implemented yet |
| SequenceExpr.trunc | np.trunc(Series) |
| SequenceExpr.hll_count | Not implemented yet |
| StringSequenceExpr.capitalize | Series.str.capitalize |
| StringSequenceExpr.contains | Series.str.contains |
| StringSequenceExpr.count | Series.str.count |
| StringSequenceExpr.endswith | Series.str.endswith |
| StringSequenceExpr.find | Series.str.find |
| StringSequenceExpr.len | Series.str.len |
| StringSequenceExpr.ljust | Series.str.ljust |
| StringSequenceExpr.lower | Series.str.lower |
| StringSequenceExpr.lstrip | Series.str.lstrip |
| StringSequenceExpr.pad | Series.str.pad |
| StringSequenceExpr.repeat | Series.str.repeat |
| StringSequenceExpr.replace | Series.str.replace |
| StringSequenceExpr.rfind | Series.str.rfind |
| StringSequenceExpr.rjust | Series.str.rjust |
| StringSequenceExpr.rstrip | Series.str.rstrip |
| StringSequenceExpr.slice | Series.str.slice |
| StringSequenceExpr.startswith | Series.str.startswith |
| StringSequenceExpr.strip | Series.str.strip |
| StringSequenceExpr.swapcase | Series.str.swapcase |
| StringSequenceExpr.title | Series.str.title |
| StringSequenceExpr.translate | Series.str.translate |
| StringSequenceExpr.upper | Series.str.upper |
| StringSequenceExpr.zfill | Series.str.zfill |
| StringSequenceExpr.isalnum | Series.str.isalnum |
| StringSequenceExpr.isalpha | Series.str.isalpha |
| StringSequenceExpr.isdigit | Series.str.isdigit |
| StringSequenceExpr.isspace | Series.str.isspace |
| StringSequenceExpr.islower | Series.str.islower |
| StringSequenceExpr.isupper | Series.str.isupper |
| StringSequenceExpr.istitle | Series.str.istitle |
| StringSequenceExpr.isnumeric | Series.str.isnumeric |
| StringSequenceExpr.isdecimal | Series.str.isdecimal |
Execution
PyODPS DataFrame and MaxFrame both use lazy execution to leverage efficiency of code optimization. However, the way to invoke these jobs is changed.
<a id="getting-started-index"></a>
Getting Started
- Access and installation
- Enable MaxFrame for your MaxCompute project
- Install MaxFrame client locally
- Access MaxFrame with DataWorks
- Access MaxFrame with MaxCompute Notebook
- Overview
- Getting started tutorials
- 10 minutes to MaxFrame
- Comparison with other tools
- Comparison with PyODPS DataFrame
Access and installation
Enable MaxFrame for your MaxCompute project
You need to setup a MaxCompute project Before using MaxFrame. Please take a look at here for more information.
NOTE
Currently MaxFrame is under trial. If you need to enable MaxFrame for your MaxCompute project, please fill the form to apply for trial here.
Install MaxFrame client locally
After created your own MaxCompute project and enabled MaxFrame, you may install MaxFrame client with pip command:
pip install maxframeThen you can create a MaxCompute table, perform some transformation with MaxFrame and then store the result into another MaxCompute table.
import maxframe.dataframe as md
from odps import ODPS
from maxframe import new_session
# create MaxCompute entrance object and test table
o = ODPS(
access_id=os.getenv('ODPS_ACCESS_ID'),
secret_access_key=os.getenv('ODPS_ACCESS_KEY'),
project='your-default-project',
endpoint='your-end-point',
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
table = o.create_table("test_source_table", "a string, b bigint")
with table.open_writer() as writer:
writer.write([
["value1", 0],
["value2", 1],
])
# create maxframe session
session = new_session(o)
# perform data transformation
df = md.read_odps_table("test_source_table")
df["a"] = "prefix_" + df["a"]
md.to_odps_table(df, "test_prefix_source_table").execute()
# destroy maxframe session
session.destroy()Access MaxFrame with DataWorks
DataWorks provides task scheduling capability for MaxCompute projects. You can schedule and run MaxFrame job with DataWorks.
To run MaxFrame job with DataWorks, you need to create a PyODPS 3 node and write your code inside it. PyODPS nodes are executed with embedded MaxCompute accounts and project information, thus you may create your MaxFrame session directly.
import maxframe.dataframe as md
from maxframe import new_session
# create maxframe session
session = new_session(o)
# perform data transformation
df = md.read_odps_table("test_source_table")
df["a"] = "prefix_" + df["a"]
md.to_odps_table(df, "test_prefix_source_table").execute()
# destroy maxframe session
session.destroy()Access MaxFrame with MaxCompute Notebook
MaxCompute Notebook also provides MaxFrame package. It also provides MaxCompute account in environment variables in the notebook, thus account information is not needed.
import maxframe.dataframe as md
from maxframe import new_session
# create MaxCompute entrance object
o = ODPS(
project='your-default-project',
endpoint='your-end-point',
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
# create maxframe session
session = new_session(o)
# perform data transformation
df = md.read_odps_table("test_source_table")
df["a"] = "prefix_" + df["a"]
md.to_odps_table(df, "test_prefix_source_table").execute()
# destroy maxframe session
session.destroy()Overview
MaxFrame is a framework for large-scale data computation built on MaxCompute by Alibaba Cloud with API-compatibility for pandas. It intends to become an inplace replacement for Python users familiar with Numpy or Pandas APIs to utilize MaxCompute to run their code in a distributed environment.
10 minutes to MaxFrame
Here, movielens 100K is used as an example. Assume that three tables already exist, which are maxframe_ml_100k_movies (movie-related data), maxframe_ml_100k_users (user-related data), and maxframe_ml_100k_ratings (rating-related data).
Create a MaxFrame session object before starting the following steps:
import os
from odps import ODPS
from maxframe import new_session
# Make sure environment variable ODPS_ACCESS_ID already set to Access Key ID of user
# while environment variable ODPS_ACCESS_KEY set to Access Key Secret of user.
# Not recommended to hardcode Access Key ID or Access Key Secret in your code.
o = ODPS(
access_id=os.getenv('ODPS_ACCESS_ID'),
secret_access_key=os.getenv('ODPS_ACCESS_KEY'),
project='**your-project**',
endpoint='**your-endpoint**',
user_agent='AlibabaCloud-Agent-Skills/alibabacloud-odps-maxframe-coding'
)
session = new_session(o)You only need to use read_odps_table API to create a DataFrame object. For instance,
import maxframe.dataframe as md
users = md.read_odps_table('pyodps_ml_100k_users')View columns of DataFrame and the types of the columns through the dtypes attribute, as shown in the following code:
>>> users.dtypes
user_id int64
age int64
sex object
occupation object
zip_code object
dtype: objectSimply view the representation of the object will automatically show the first and last rows of the DataFrame.
>>> users
user_id age sex occupation zip_code
0 1 24 M technician 85711
1 2 53 F other 94043
2 3 23 M writer 32067
3 4 24 M technician 43537
4 5 33 F other 15213
...
5 6 42 M executive 98101
6 7 57 M administrator 91344
7 8 36 M administrator 05201
8 9 29 M student 01002
9 10 53 M lawyer 90703You can use the head method to obtain the first N data records for easy and quick data preview. For example:
>>> users.head(10).execute().fetch()
user_id age sex occupation zip_code
0 1 24 M technician 85711
1 2 53 F other 94043
2 3 23 M writer 32067
3 4 24 M technician 43537
4 5 33 F other 15213
5 6 42 M executive 98101
6 7 57 M administrator 91344
7 8 36 M administrator 05201
8 9 29 M student 01002
9 10 53 M lawyer 90703You can add a filter on the columns if you do not want to view all of them. For example:
>>> users[['user_id', 'age']].head(5).execute().fetch()
user_id age
0 1 24
1 2 53
2 3 23
3 4 24
4 5 33You can also drop several columns. For example:
>>> users.drop(columns=['zip_code', 'age']).head(5)
user_id sex occupation
0 1 M technician
1 2 F other
2 3 M writer
3 4 M technician
4 5 F otherWhen excluding some columns, you may want to obtain new columns through computation. For example, add the sex_bool attribute and set it to True if sex is Male. Otherwise, set it to False. For example:
>>> users = users.drop(['zip_code', 'sex'])
>>> users["sex_bool"] = users.sex == "M"
>>> users.head(5).execute().fetch()
user_id age occupation sex_bool
0 1 24 technician True
1 2 53 other False
2 3 23 writer True
3 4 24 technician True
4 5 33 other FalseObtain the number of persons at age of 20 to 25, as shown in the following code:
>>> users[users.age.between(20, 25)].count().execute().fetch()
195Obtain the numbers of male and female users, as shown in the following code:
>>> users.groupby(users.sex).user_id.size()
F 273
M 670
dtype: int64To divide users by job, obtain the first 10 jobs that have the largest population, and sort the jobs in the descending order of population. See the following:
>>> df = users.groupby("occupation").agg({"user_id": "count"})
>>> df.sort_values("user_id", ascending=False)[:10]
user_id
occupation
student 196
other 105
educator 95
administrator 79
engineer 67
programmer 66
librarian 51
writer 45
executive 32
scientist 31DataFrame APIs provide the value_counts method to quickly achieve the same result. An example is shown below.
>>> uses.occupation.value_counts()[:10]
student 196
other 105
educator 95
administrator 79
engineer 67
programmer 66
librarian 51
writer 45
executive 32
scientist 31
dtype: int64Show data in a more intuitive graph, as shown in the following code:
%matplotlib inlineUse a horizontal bar chart to visualize data, as shown in the following code:
>>> users['occupation'].value_counts().plot(kind='barh', x='occupation', ylabel='prefession')
<matplotlib.axes._subplots.AxesSubplot at 0x10653cfd0>\_images/df-value-count-plot.png
Divide ages into 30 groups and view the histogram of age distribution, as shown in the following code:
>>> users.age.hist(bins=30, title="Distribution of users' ages", xlabel='age', ylabel='count of users')
<matplotlib.axes._subplots.AxesSubplot at 0x10667a510>\_images/df-age-hist.png
Use join to join the three tables and save the joined tables as a new table. For example:
>>> movies = md.read_odps_table('pyodps_ml_100k_movies')
>>> ratings = md.read_odps_table('pyodps_ml_100k_ratings')
>>>
>>> o.delete_table('pyodps_ml_100k_lens', if_exists=True)
>>> lens = movies.join(ratings).join(users).persist('pyodps_ml_100k_lens')
>>>
>>> lens.dtypes
odps.Schema {
movie_id int64
title string
release_date string
video_release_date string
imdb_url string
user_id int64
rating int64
unix_timestamp int64
age int64
sex string
occupation string
zip_code string
}<!-- Divide ages of 0 to 80 into eight groups, as shown in the following code: --> <!-- labels = ['0-9', '10-19', '20-29', '30-39', '40-49', '50-59', '60-69', '70-79'] --> <!-- cut_lens = lens[lens, lens.age.cut(range(0, 81, 10), right=False, labels=labels).rename('age_group')] --> <!-- View the first 10 data records of a single age in a group, as shown in the following code: --> <!-- .. code-block:: python --> <!-- >>> cut_lens['age_group', 'age'].distinct()[:10] --> <!-- age_group age --> <!-- 0 0-9 7 --> <!-- 1 10-19 10 --> <!-- 2 10-19 11 --> <!-- 3 10-19 13 --> <!-- 4 10-19 14 --> <!-- 5 10-19 15 --> <!-- 6 10-19 16 --> <!-- 7 10-19 17 --> <!-- 8 10-19 18 --> <!-- 9 10-19 19 --> <!-- View users’ total rating and average rating of each age group, as shown in the following code: --> <!-- cut_lens.groupby('age_group').agg(cut_lens.rating.count().rename('total_rating'), cut_lens.rating.mean().rename('avg_rating')) --> <!-- age_group avg_rating total_rating --> <!-- 0 0-9 3.767442 43 --> <!-- 1 10-19 3.486126 8181 --> <!-- 2 20-29 3.467333 39535 --> <!-- 3 30-39 3.554444 25696 --> <!-- 4 40-49 3.591772 15021 --> <!-- 5 50-59 3.635800 8704 --> <!-- 6 60-69 3.648875 2623 --> <!-- 7 70-79 3.649746 197 -->
Getting started tutorials
- 10 minutes to MaxFrame
<a id="index"></a>
MaxFrame Documentation
MaxFrame is a framework for large-scale data computation built on MaxCompute by Alibaba Cloud with API-compatibility for pandas. It intends to become an inplace replacement for Python users familiar with Numpy or Pandas APIs to utilize MaxCompute to run their code in a distributed environment.
<a id="generated-dataframe"></a>
DataFrame
Constructor
| `DataFrame`([data, index, columns, dtype, ...]) |
|---|
Attributes and underlying data
Axes
| `DataFrame.index` | |
|---|---|
| `DataFrame.columns` |
| `DataFrame.dtypes` | Return the dtypes in the DataFrame. |
|---|---|
| `DataFrame.memory_usage`([index, deep]) | Return the memory usage of each column in bytes. |
| `DataFrame.ndim` | Return an int representing the number of axes / array dimensions. |
| `DataFrame.select_dtypes`([include, exclude]) | Return a subset of the DataFrame's columns based on the column dtypes. |
| `DataFrame.shape` |
Conversion
| `DataFrame.astype`(dtype[, copy, errors]) | Cast a pandas object to a specified dtype dtype. |
|---|---|
| `DataFrame.convert_dtypes`([infer_objects, ...]) | Convert columns to best possible dtypes using dtypes supporting pd.NA. |
| `DataFrame.copy`() | |
| `DataFrame.infer_objects`([copy]) | Attempt to infer better dtypes for object columns. |
Indexing, iteration
| `DataFrame.at` | Access a single value for a row/column label pair. |
|---|---|
| `DataFrame.head`([n]) | Return the first n rows. |
| `DataFrame.iat` | Access a single value for a row/column pair by integer position. |
| `DataFrame.iloc` | Purely integer-location based indexing for selection by position. |
| `DataFrame.insert`(loc, column, value[, ...]) | Insert column into DataFrame at specified location. |
| `DataFrame.loc` | Access a group of rows and columns by label(s) or a boolean array. |
| `DataFrame.mask`(cond[, other, inplace, axis, ...]) | Replace values where the condition is True. |
| `DataFrame.pop`(item) | Return item and drop from frame. |
| `DataFrame.query`(expr[, inplace]) | Query the columns of a DataFrame with a boolean expression. |
| `DataFrame.tail`([n]) | Return the last n rows. |
| `DataFrame.xs`(key[, axis, level, drop_level]) | Return cross-section from the Series/DataFrame. |
| `DataFrame.where`(cond[, other, inplace, ...]) | Replace values where the condition is False. |
Binary operator functions
| `DataFrame.add`(other[, axis, level, fill_value]) | Get Addition of dataframe and other, element-wise (binary operator add). |
|---|---|
| `DataFrame.sub`(other[, axis, level, fill_value]) | Get Subtraction of dataframe and other, element-wise (binary operator subtract). |
| `DataFrame.mul`(other[, axis, level, fill_value]) | Get Multiplication of dataframe and other, element-wise (binary operator mul). |
| `DataFrame.div`(other[, axis, level, fill_value]) | Get Floating division of dataframe and other, element-wise (binary operator truediv). |
| `DataFrame.truediv`(other[, axis, level, ...]) | Get Floating division of dataframe and other, element-wise (binary operator truediv). |
| `DataFrame.floordiv`(other[, axis, level, ...]) | Get Integer division of dataframe and other, element-wise (binary operator floordiv). |
| `DataFrame.mod`(other[, axis, level, fill_value]) | Get Modulo of dataframe and other, element-wise (binary operator mod). |
| `DataFrame.pow`(other[, axis, level, fill_value]) | Get Exponential power of dataframe and other, element-wise (binary operator pow). |
| `DataFrame.dot`(other) | Compute the matrix multiplication between the DataFrame and other. |
| `DataFrame.radd`(other[, axis, level, fill_value]) | Get Addition of dataframe and other, element-wise (binary operator radd). |
| `DataFrame.rsub`(other[, axis, level, fill_value]) | Get Subtraction of dataframe and other, element-wise (binary operator rsubtract). |
| `DataFrame.rmul`(other[, axis, level, fill_value]) | Get Multiplication of dataframe and other, element-wise (binary operator rmul). |
| `DataFrame.rdiv`(other[, axis, level, fill_value]) | Get Floating division of dataframe and other, element-wise (binary operator rtruediv). |
| `DataFrame.rtruediv`(other[, axis, level, ...]) | Get Floating division of dataframe and other, element-wise (binary operator rtruediv). |
| `DataFrame.rfloordiv`(other[, axis, level, ...]) | Get Integer division of dataframe and other, element-wise (binary operator rfloordiv). |
| `DataFrame.rmod`(other[, axis, level, fill_value]) | Get Modulo of dataframe and other, element-wise (binary operator rmod). |
| `DataFrame.rpow`(other[, axis, level, fill_value]) | Get Exponential power of dataframe and other, element-wise (binary operator rpow). |
| `DataFrame.lt`(other[, axis, level, fill_value]) | Get Less than of dataframe and other, element-wise (binary operator lt). |
| `DataFrame.gt`(other[, axis, level, fill_value]) | Get Greater than of dataframe and other, element-wise (binary operator gt). |
| `DataFrame.le`(other[, axis, level, fill_value]) | Get Less than or equal to of dataframe and other, element-wise (binary operator le). |
| `DataFrame.ge`(other[, axis, level, fill_value]) | Get Greater than or equal to of dataframe and other, element-wise (binary operator ge). |
| `DataFrame.ne`(other[, axis, level, fill_value]) | Get Not equal to of dataframe and other, element-wise (binary operator ne). |
| `DataFrame.eq`(other[, axis, level, fill_value]) | Get Equal to of dataframe and other, element-wise (binary operator eq). |
| `DataFrame.combine`(other, func[, fill_value, ...]) | Perform column-wise combine with another DataFrame. |
| `DataFrame.combine_first`(other) | Update null elements with value in the same location in other. |
Function application, GroupBy & window
| `DataFrame.apply`(func[, axis, raw, ...]) | Apply a function along an axis of the DataFrame. |
|---|---|
| `DataFrame.applymap`(func[, na_action, ...]) | Apply a function to a Dataframe elementwise. |
| `DataFrame.agg`([func, axis]) | Aggregate using one or more operations over the specified axis. |
| `DataFrame.aggregate`([func, axis]) | Aggregate using one or more operations over the specified axis. |
| `DataFrame.ewm`([com, span, halflife, alpha, ...]) | Provide exponential weighted functions. |
| `DataFrame.expanding`([min_periods, shift, ...]) | Provide expanding transformations. |
| `DataFrame.groupby`([by, level, as_index, ...]) | Group DataFrame using a mapper or by a Series of columns. |
| `DataFrame.map`(func[, na_action, dtypes, ...]) | Apply a function to a Dataframe elementwise. |
| `DataFrame.rolling`(window[, min_periods, ...]) | Provide rolling window calculations. |
| `DataFrame.transform`(func[, axis, dtypes, ...]) | Call func on self producing a DataFrame with transformed values. |
<a id="generated-dataframe-stats"></a>
Computations / descriptive stats
| `DataFrame.abs`() | |
|---|---|
| `DataFrame.all`([axis, bool_only, skipna, ...]) | |
| `DataFrame.any`([axis, bool_only, skipna, ...]) | |
| `DataFrame.clip`([lower, upper, axis, inplace]) | Trim values at input threshold(s). |
| `DataFrame.count`([axis, level, numeric_only]) | |
| `DataFrame.corr`([method, min_periods]) | Compute pairwise correlation of columns, excluding NA/null values. |
| `DataFrame.corrwith`(other[, axis, drop, method]) | Compute pairwise correlation. |
| `DataFrame.cov`([min_periods, ddof, numeric_only]) | Compute pairwise covariance of columns, excluding NA/null values. |
| `DataFrame.describe`([percentiles, include, ...]) | Generate descriptive statistics. |
| `DataFrame.diff`([periods, axis]) | First discrete difference of element. |
| `DataFrame.eval`(expr[, inplace]) | Evaluate a string describing operations on DataFrame columns. |
| `DataFrame.max`([axis, skipna, level, ...]) | |
| `DataFrame.mean`([axis, skipna, level, ...]) | |
| `DataFrame.median`([axis, skipna, level, ...]) | |
| `DataFrame.min`([axis, skipna, level, ...]) | |
| `DataFrame.mode`([axis, numeric_only, dropna, ...]) | Get the mode(s) of each element along the selected axis. |
| `DataFrame.nunique`([axis, dropna]) | Count distinct observations over requested axis. |
| `DataFrame.pct_change`([periods, fill_method, ...]) | Percentage change between the current and a prior element. |
| `DataFrame.prod`([axis, skipna, level, ...]) | |
| `DataFrame.product`([axis, skipna, level, ...]) | |
| `DataFrame.quantile`([q, axis, numeric_only, ...]) | Return values at the given quantile over requested axis. |
| `DataFrame.rank`([axis, method, numeric_only, ...]) | Compute numerical data ranks (1 through n) along axis. |
| `DataFrame.round`([decimals]) | Round a DataFrame to a variable number of decimal places. |
| `DataFrame.sem`([axis, skipna, level, ddof, ...]) | |
| `DataFrame.std`([axis, skipna, level, ddof, ...]) | |
| `DataFrame.sum`([axis, skipna, level, ...]) | |
| `DataFrame.value_counts`([subset, normalize, ...]) | |
| `DataFrame.var`([axis, skipna, level, ddof, ...]) |
Reindexing / selection / label manipulation
| `DataFrame.add_prefix`(prefix) | Prefix labels with string prefix. |
|---|---|
| `DataFrame.add_suffix`(suffix) | Suffix labels with string suffix. |
| `DataFrame.align`(other[, join, axis, level, ...]) | Align two objects on their axes with the specified join method. |
| `DataFrame.at_time`(time[, axis]) | Select values at particular time of day (e.g., 9:30AM). |
| `DataFrame.between_time`(start_time, end_time) | Select values between particular times of the day (e.g., 9:00-9:30 AM). |
| `DataFrame.drop`([labels, axis, index, ...]) | Drop specified labels from rows or columns. |
| `DataFrame.drop_duplicates`([subset, keep, ...]) | Return DataFrame with duplicate rows removed. |
| `DataFrame.droplevel`(level[, axis]) | Return Series/DataFrame with requested index / column level(s) removed. |
| `DataFrame.duplicated`([subset, keep, method]) | Return boolean Series denoting duplicate rows. |
| `DataFrame.filter`([items, like, regex, axis]) | Subset the dataframe rows or columns according to the specified index labels. |
| `DataFrame.head`([n]) | Return the first n rows. |
| `DataFrame.idxmax`([axis, skipna]) | Return index of first occurrence of maximum over requested axis. |
| `DataFrame.idxmin`([axis, skipna]) | Return index of first occurrence of minimum over requested axis. |
| `DataFrame.reindex`([labels, index, columns, ...]) | Conform Series/DataFrame to new index with optional filling logic. |
| `DataFrame.reindex_like`(other[, method, ...]) | Return an object with matching indices as other object. |
| `DataFrame.rename`([mapper, index, columns, ...]) | Alter axes labels. |
| `DataFrame.rename_axis`([mapper, index, ...]) | Set the name of the axis for the index or columns. |
| `DataFrame.reset_index`([level, drop, ...]) | Reset the index, or a level of it. |
| `DataFrame.sample`([n, frac, replace, ...]) | Return a random sample of items from an axis of object. |
| `DataFrame.set_axis`(labels[, axis, inplace]) | Assign desired index to given axis. |
| `DataFrame.set_index`(keys[, drop, append, ...]) | Set the DataFrame index using existing columns. |
| `DataFrame.take`(indices[, axis]) | Return the elements in the given positional indices along an axis. |
| `DataFrame.truncate`([before, after, axis, copy]) | Truncate a Series or DataFrame before and after some index value. |
<a id="generated-dataframe-missing"></a>
Missing data handling
| `DataFrame.dropna`([axis, how, thresh, ...]) | Remove missing values. |
|---|---|
| `DataFrame.fillna`([value, method, axis, ...]) | Fill NA/NaN values using the specified method. |
| `DataFrame.isna`() | Detect missing values. |
| `DataFrame.isnull`() | Detect missing values. |
| `DataFrame.notna`() | Detect existing (non-missing) values. |
| `DataFrame.notnull`() | Detect existing (non-missing) values. |
Reshaping, sorting, transposing
| `DataFrame.melt`([id_vars, value_vars, ...]) | Unpivot a DataFrame from wide to long format, optionally leaving identifiers set. |
|---|---|
| `DataFrame.nlargest`(n, columns[, keep]) | Return the first n rows ordered by columns in descending order. |
| `DataFrame.nsmallest`(n, columns[, keep]) | Return the first n rows ordered by columns in ascending order. |
| `DataFrame.pivot`(columns[, index, values]) | Return reshaped DataFrame organized by given index / column values. |
| `DataFrame.pivot_table`([values, index, ...]) | Create a spreadsheet-style pivot table as a DataFrame. |
| `DataFrame.reorder_levels`(order[, axis]) | Rearrange index levels using input order. |
| `DataFrame.sort_values`(by[, axis, ascending, ...]) | Sort by the values along either axis. |
| `DataFrame.sort_index`([axis, level, ...]) | Sort object by labels (along an axis). |
| `DataFrame.swaplevel`([i, j, axis]) | Swap levels i and j in a MultiIndex. |
| `DataFrame.stack`([level, dropna]) | Stack the prescribed level(s) from columns to index. |
| `DataFrame.unstack`([level, fill_value]) | Unstack, also known as pivot, Series with MultiIndex to produce DataFrame. |
Combining / comparing / joining / merging
| `DataFrame.append`(other[, ignore_index, ...]) | Append rows of other to the end of caller, returning a new object. |
|---|---|
| `DataFrame.assign`(\\kwargs) | Assign new columns to a DataFrame. |
| `DataFrame.compare`(other[, align_axis, ...]) | Compare to another DataFrame and show the differences. |
| `DataFrame.join`(other[, on, how, lsuffix, ...]) | Join columns of another DataFrame. |
| `DataFrame.merge`(right[, how, on, left_on, ...]) | Merge DataFrame or named Series objects with a database-style join. |
| `DataFrame.update`(other[, join, overwrite, ...]) | Modify in place using non-NA values from another DataFrame. |
Time series-related
| `DataFrame.first_valid_index`() | Return index for first non-NA value or None, if no non-NA value is found. |
|---|---|
| `DataFrame.last_valid_index`() | Return index for last non-NA value or None, if no non-NA value is found. |
| `DataFrame.shift`([periods, freq, axis, ...]) | Shift index by desired number of periods with an optional time freq. |
| `DataFrame.tshift`([periods, freq, axis]) | Shift the time index, using the index's frequency if available. |
<a id="generated-dataframe-plotting"></a>
Plotting
DataFrame.plot is both a callable method and a namespace attribute for specific plotting methods of the form DataFrame.plot.<kind>.
| `DataFrame.plot` | alias of DataFramePlotAccessor |
|---|
| `DataFrame.plot.area`(\args, \\*kwargs) | Draw a stacked area plot. |
|---|---|
| `DataFrame.plot.bar`(\args, \\*kwargs) | Vertical bar plot. |
| `DataFrame.plot.barh`(\args, \\*kwargs) | Make a horizontal bar plot. |
| `DataFrame.plot.box`(\args, \\*kwargs) | Make a box plot of the DataFrame columns. |
| `DataFrame.plot.density`(\args, \\*kwargs) | Generate Kernel Density Estimate plot using Gaussian kernels. |
| `DataFrame.plot.hexbin`(\args, \\*kwargs) | Generate a hexagonal binning plot. |
| `DataFrame.plot.hist`(\args, \\*kwargs) | Draw one histogram of the DataFrame's columns. |
| `DataFrame.plot.kde`(\args, \\*kwargs) | Generate Kernel Density Estimate plot using Gaussian kernels. |
| `DataFrame.plot.line`(\args, \\*kwargs) | Plot Series or DataFrame as lines. |
| `DataFrame.plot.pie`(\args, \\*kwargs) | Generate a pie plot. |
| `DataFrame.plot.scatter`(\args, \\*kwargs) | Create a scatter plot with varying marker point size and color. |
<a id="generated-dataframe-io"></a>
Serialization / IO / conversion
| `DataFrame.from_dict`(data[, orient, dtype, ...]) | Construct DataFrame from dict of array-like or dicts. |
|---|---|
| `DataFrame.from_records`(data[, index, ...]) | Convert structured or record ndarray to DataFrame. |
| `DataFrame.to_clipboard`(\*[, excel, sep, ...]) | Copy object to the system clipboard. |
| `DataFrame.to_csv`(path[, sep, na_rep, ...]) | Write object to a comma-separated values (csv) file. |
| `DataFrame.to_dict`([orient, into, index, ...]) | Convert the DataFrame to a dictionary. |
| `DataFrame.to_json`([path, orient, ...]) | Convert the object to a JSON string. |
| `DataFrame.to_odps_table`(table[, partition, ...]) | Write DataFrame object into a MaxCompute (ODPS) table. |
| `DataFrame.to_pandas`([session]) | |
| `DataFrame.to_parquet`(path[, engine, ...]) | Write a DataFrame to the binary parquet format, each chunk will be written to a Parquet file. |
<a id="generated-dataframe-mf"></a>
MaxFrame Extensions
| `DataFrame.mf.apply_chunk`(func[, batch_rows, ...]) | Apply a function that takes pandas DataFrame and outputs pandas DataFrame/Series. |
|---|---|
| `DataFrame.mf.collect_kv`([columns, kv_delim, ...]) | Merge values in specified columns into a key-value represented column. |
| `DataFrame.mf.extract_kv`([columns, kv_delim, ...]) | Extract values in key-value represented columns into standalone columns. |
| `DataFrame.mf.flatmap`(func[, dtypes, raw, args]) | Apply the given function to each row and then flatten results. |
| `DataFrame.mf.map_reduce`([mapper, reducer, ...]) | Map-reduce API over certain DataFrames. |
| `DataFrame.mf.rebalance`([axis, factor, ...]) | Make data more balanced across entire cluster. |
| `DataFrame.mf.reshuffle`([group_by, sort_by, ...]) | Shuffle data in DataFrame or Series to make data distribution more randomized. |
DataFrame.mf provides methods unique to MaxFrame. These methods are collated from application scenarios in MaxCompute and these can be accessed like DataFrame.mf.<function/property>.
<a id="generated-general-functions"></a>
General functions
Data manipulations
| `concat`(objs[, axis, join, ignore_index, ...]) | Concatenate dataframe objects along a particular axis with optional set logic along the other axes. |
|---|---|
| `factorize`(values[, sort, use_na_sentinel]) | Encode the object as an enumerated type or categorical variable. |
| `get_dummies`(data[, prefix, prefix_sep, ...]) | Convert categorical variable into dummy/indicator variables. |
| `merge`(df, right[, how, on, left_on, ...]) | Merge DataFrame or named Series objects with a database-style join. |
Top-level missing data
| `isna`(obj) | Detect missing values. |
|---|---|
| `isnull`(obj) | Detect missing values. |
| `notna`(obj) | Detect existing (non-missing) values. |
| `notnull`(obj) | Detect existing (non-missing) values. |
Top-level dealing with numeric data
| `to_numeric`(arg[, errors, downcast]) | Convert argument to a numeric type. |
|---|
Top-level dealing with datetimelike
| `to_datetime`(arg[, errors, dayfirst, ...]) | Convert argument to datetime. |
|---|---|
| `date_range`([start, end, periods, freq, tz, ...]) | Return a fixed frequency DatetimeIndex. |
Top-level evaluation
| `eval`(expr[, parser, engine, local_dict, ...]) | Evaluate a Python expression as a string using various backends. |
|---|
maxframe.dataframe.DataFrame.abs
DataFrame.abs()
maxframe.dataframe.DataFrame.add_prefix
DataFrame.add_prefix(prefix)
Prefix labels with string prefix.
For Series, the row labels are prefixed. For DataFrame, the column labels are prefixed.
- Parameters:
prefix (*str*) – The string to add before each label.
- Returns:
New Series or DataFrame with updated labels.
- Return type:
Series or DataFrame
SEE ALSO
`Series.add_suffix` : Suffix row labels with string suffix.
`DataFrame.add_suffix` : Suffix column labels with string suffix.
Examples
>>> import maxframe.dataframe as md
>>> s = md.Series([1, 2, 3, 4])
>>> s.execute()
0 1
1 2
2 3
3 4
dtype: int64>>> s.add_prefix('item_').execute()
item_0 1
item_1 2
item_2 3
item_3 4
dtype: int64>>> df = md.DataFrame({'A': [1, 2, 3, 4], 'B': [3, 4, 5, 6]})
>>> df.execute()
A B
0 1 3
1 2 4
2 3 5
3 4 6>>> df.add_prefix('col_').execute()
col_A col_B
0 1 3
1 2 4
2 3 5
3 4 6maxframe.dataframe.DataFrame.add_suffix
DataFrame.add_suffix(suffix)
Suffix labels with string suffix.
For Series, the row labels are suffixed. For DataFrame, the column labels are suffixed.
- Parameters:
suffix (*str*) – The string to add after each label.
- Returns:
New Series or DataFrame with updated labels.
- Return type:
Series or DataFrame
SEE ALSO
`Series.add_prefix` : Suffix row labels with string prefix.
`DataFrame.add_prefix` : Suffix column labels with string prefix.
Examples
>>> import maxframe.dataframe as md
>>> s = md.Series([1, 2, 3, 4])
>>> s.execute()
0 1
1 2
2 3
3 4
dtype: int64>>> s.add_prefix('_item').execute()
0_item 1
1_item 2
2_item 3
3_item 4
dtype: int64>>> df = md.DataFrame({'A': [1, 2, 3, 4], 'B': [3, 4, 5, 6]})
>>> df.execute()
A B
0 1 3
1 2 4
2 3 5
3 4 6>>> df.add_prefix('_col').execute()
A_col B_col
0 1 3
1 2 4
2 3 5
3 4 6maxframe.dataframe.DataFrame.add
DataFrame.add(other, axis='columns', level=None, fill_value=None)
Get Addition of dataframe and other, element-wise (binary operator add). Equivalent to +, but with support to substitute a fill_value for missing data in one of the inputs. With reverse version, radd. Among flexible wrappers (add, sub, mul, div, mod, pow) to arithmetic operators: +, -, \, /, //, %, \\*.
- Parameters:
- other (scalar , sequence , *Series* , or *DataFrame*) – Any single or multiple element data structure, or list-like object.
- axis ( {0 or 'index' , 1 or 'columns'}) – Whether to compare by the index (0 or ‘index’) or columns
(1 or ‘columns’). For Series input, axis to match Series index on.
- level (*int* or label) – Broadcast across a level, matching Index values on the
passed MultiIndex level.
- fill_value (*float* or None , default None) – Fill existing missing (NaN) values, and any new element needed for
successful DataFrame alignment, with this value before computation. If data in both corresponding DataFrame locations is missing the result will be missing.
- Returns:
Result of the arithmetic operation.
- Return type:
DataFrame
SEE ALSO
`DataFrame.add` : Add DataFrames.
`DataFrame.sub` : Subtract DataFrames.
`DataFrame.mul` : Multiply DataFrames.
`DataFrame.div` : Divide DataFrames (float division).
`DataFrame.truediv` : Divide DataFrames (float division).
`DataFrame.floordiv` : Divide DataFrames (integer division).
`DataFrame.mod` : Calculate modulo (remainder after division).
`DataFrame.pow` : Calculate exponential power.
Notes
Mismatched indices will be unioned together.
Examples
>>> import maxframe.dataframe as md
>>> df = md.DataFrame({'angles': [0, 3, 4],
... 'degrees': [360, 180, 360]},
... index=['circle', 'triangle', 'rectangle'])
>>> df.execute()
angles degrees
circle 0 360
triangle 3 180
rectangle 4 360Add a scalar with operator version which return the same results.
>>> (df + 1).execute()
angles degrees
circle 1 361
triangle 4 181
rectangle 5 361>>> df.add(1).execute()
angles degrees
circle 1 361
triangle 4 181
rectangle 5 361Divide by constant with reverse version.
>>> df.div(10).execute()
angles degrees
circle 0.0 36.0
triangle 0.3 18.0
rectangle 0.4 36.0>>> df.rdiv(10).execute()
angles degrees
circle inf 0.027778
triangle 3.333333 0.055556
rectangle 2.500000 0.027778Subtract a list and Series by axis with operator version.
>>> (df - [1, 2]).execute()
angles degrees
circle -1 358
triangle 2 178
rectangle 3 358>>> df.sub([1, 2], axis='columns').execute()
angles degrees
circle -1 358
triangle 2 178
rectangle 3 358>>> df.sub(md.Series([1, 1, 1], index=['circle', 'triangle', 'rectangle']),
... axis='index').execute()
angles degrees
circle -1 359
triangle 2 179
rectangle 3 359Multiply a DataFrame of different shape with operator version.
>>> other = md.DataFrame({'angles': [0, 3, 4]},
... index=['circle', 'triangle', 'rectangle'])
>>> other.execute()
angles
circle 0
triangle 3
rectangle 4>>> df.mul(other, fill_value=0).execute()
angles degrees
circle 0 0.0
triangle 9 0.0
rectangle 16 0.0