Pandas: 项目:综合分析

最后更新:2026-08-26

真实项目从来不是一张表——5 个 CSV + 1 个 Excel + 数据库查询,merge 4 次,groupby 3 个维度,pivot 2 个透视表,style 1 份报告。本课是全课程的终局之战,把 24 课学到的所有技能整合到一个项目里:多源整合 → 质量审计 → 复杂关联 → 多维分析 → 自动化报告。

⚠️ 注意: 以下代码需在本地 Python 环境中运行。

1. 你将学到


2. 项目背景:跨国电商综合分析

(1) 任务

Bob 需要分析跨国电商 Q1-Q3 数据:4 个 CSV(订单/产品/客户/地区)+ 1 个 SQLite 数据库(库存)→ 整合 → 分析 → 报告。

(2) 全流程

100%
graph TB
    A["5 数据源加载"] --> B["数据质量审计"]
    B --> C["4 表 merge"]
    C --> D["清洗流水线"]
    D --> E["多维 groupby"]
    E --> F["pivot 交叉分析"]
    F --> G["Styler 报告"]
    G --> H["多 Sheet 导出"]
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

3. 多源数据加载

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:5 源数据加载(难度⭐⭐⭐)

PYTHON
import pandas as pd
import numpy as np
import sqlite3
from io import StringIO, BytesIO

# ============================================
# Step 1: Multi-source Data Loading
# ============================================

np.random.seed(42)

# Source 1: Customers (CSV)
customers = pd.DataFrame({
    'customer_id': range(1, 501),
    'name': [f'Customer_{i:04d}' for i in range(1, 501)],
    'segment': np.random.choice(['Consumer', 'Corporate', 'Home Office'], 500),
    'city': np.random.choice(['New York', 'Los Angeles', 'Chicago', 'Houston', 'London', 'Tokyo'], 500),
    'country': np.random.choice(['US', 'US', 'US', 'US', 'UK', 'JP'], 500)
})

# Source 2: Products (CSV)
products = pd.DataFrame({
    'product_id': range(1, 51),
    'product_name': [f'Product_{i:02d}' for i in range(1, 51)],
    'category': np.random.choice(['Electronics', 'Clothing', 'Home', 'Sports', 'Books'], 50),
    'unit_price': np.round(np.random.uniform(10, 500, 50), 2)
})

# Source 3: Orders (CSV)
orders = pd.DataFrame({
    'order_id': [f'ORD-{i:05d}' for i in range(1, 2001)],
    'customer_id': np.random.randint(1, 501, 2000),
    'product_id': np.random.randint(1, 51, 2000),
    'order_date': pd.to_datetime(np.random.choice(
        pd.date_range('2024-01-01', '2024-09-30'), 2000)),
    'quantity': np.random.randint(1, 10, 2000),
    'discount': np.random.choice([0, 0.05, 0.1, 0.2, 0.3], 2000)
})

# Source 4: Regions (Excel)
regions = pd.DataFrame({
    'country': ['US', 'UK', 'JP', 'DE', 'FR'],
    'region': ['North America', 'Europe', 'Asia Pacific', 'Europe', 'Europe'],
    'currency': ['USD', 'GBP', 'JPY', 'EUR', 'EUR']
})

# Source 5: Inventory (SQLite)
conn = sqlite3.connect(':memory:')
inventory = pd.DataFrame({
    'product_id': range(1, 51),
    'stock': np.random.randint(0, 500, 50),
    'reorder_level': np.random.randint(20, 100, 50)
})
inventory.to_sql('inventory', conn, index=False, if_exists='replace')

# Load from database
inv_df = pd.read_sql('SELECT * FROM inventory', conn)
conn.close()

print(f"✅ Loaded: customers({len(customers)}), products({len(products)}), "
      f"orders({len(orders)}), regions({len(regions)}), inventory({len(inv_df)})")
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

4. 数据质量审计

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:质量审计(难度⭐⭐)

PYTHON
# ============================================
# Step 2: Data Quality Audit
# ============================================

def audit_quality(df, name):
    """Run quality audit on a DataFrame"""
    issues = []
    # Missing values
    missing = df.isnull().sum()
    if missing.sum() > 0:
        issues.append(f"Missing: {dict(missing[missing > 0])}")
    # Duplicates
    dups = df.duplicated().sum()
    if dups > 0:
        issues.append(f"Duplicates: {dups}")
    # Types
    object_cols = df.select_dtypes(include='object').columns.tolist()
    if object_cols:
        issues.append(f"Object columns: {object_cols}")
    status = "⚠️ ISSUES" if issues else "✅ CLEAN"
    print(f"{name}: {status}")
    for issue in issues:
        print(f"  - {issue}")
    return issues

audit_quality(customers, 'Customers')
audit_quality(products, 'Products')
audit_quality(orders, 'Orders')
audit_quality(regions, 'Regions')
audit_quality(inv_df, 'Inventory')

# Inject issues for demo
orders.loc[np.random.choice(2000, 100, replace=False), 'discount'] = np.nan
dups = orders.sample(30)
orders = pd.concat([orders, dups], ignore_index=True)
print(f"\nAfter injecting issues: orders shape = {orders.shape}")
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

5. 4 表 merge + 清洗

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:复杂 merge + pipe 清洗(难度⭐⭐⭐)

PYTHON
# ============================================
# Step 3-4: 4-table Merge + Cleaning
# ============================================

def clean_orders(df):
    df = df.drop_duplicates(subset='order_id', keep='last')
    df['discount'] = df['discount'].fillna(0)
    return df

# Step 1: Clean orders
clean_orders_df = orders.pipe(clean_orders)

# Step 2: Merge orders + products
op = pd.merge(clean_orders_df, products, on='product_id', how='left')

# Step 3: Merge + customers
opc = pd.merge(op, customers, on='customer_id', how='left')

# Step 4: Merge + regions
full = pd.merge(opc, regions, on='country', how='left')

# Step 5: Merge + inventory
full = pd.merge(full, inv_df, on='product_id', how='left')

# Derived columns
full['revenue'] = full['unit_price'] * full['quantity'] * (1 - full['discount'])
full['cost_estimate'] = full['unit_price'] * full['quantity'] * 0.6
full['profit'] = full['revenue'] - full['cost_estimate']
full['month'] = full['order_date'].dt.to_period('M')
full['is_low_stock'] = full['stock'] < full['reorder_level']

print(f"✅ Full dataset: {full.shape}")
print(f"Columns: {full.columns.tolist()}")
print(f"Missing: {full.isnull().sum().sum()}")
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

6. 多维 groupby + pivot 分析

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:多维聚合与交叉分析(难度⭐⭐⭐)

PYTHON
# ============================================
# Step 5-6: Multi-dim Analysis
# ============================================

# 1. Revenue by region × category
region_cat = full.groupby(['region', 'category']).agg(
    revenue=('revenue', 'sum'),
    orders=('order_id', 'count'),
    avg_order_value=('revenue', 'mean'),
    profit_margin=('profit', lambda x: x.sum() / full.loc[x.index, 'revenue'].sum())
).round(2)
print("=== Revenue by Region × Category ===")
print(region_cat.head(8))

# 2. Monthly trend by region
monthly_region = full.groupby(['month', 'region'])['revenue'].sum().unstack()
print(f"\n=== Monthly by Region ===\n{monthly_region.tail(3)}")

# 3. Pivot table: segment × category
seg_cat = pd.pivot_table(
    full, values='revenue', index='segment', columns='category',
    aggfunc='sum', margins=True, margins_name='Total'
).round(0)
print(f"\n=== Segment × Category Pivot ===\n{seg_cat}")

# 4. Top products
top_products = full.groupby('product_name').agg(
    revenue=('revenue', 'sum'),
    quantity=('quantity', 'sum'),
    avg_discount=('discount', 'mean')
).nlargest(5, 'revenue')
print(f"\n=== Top 5 Products ===\n{top_products}")

# 5. Low stock alert
low_stock = full[full['is_low_stock']].groupby('product_name').agg(
    stock=('stock', 'first'),
    reorder_level=('reorder_level', 'first'),
    total_orders=('order_id', 'count')
).sort_values('total_orders', ascending=False)
print(f"\n=== Low Stock Alert ===\n{low_stock.head(5)}")
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

7. Styler 报告与多 Sheet 导出

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:Styler 报告 + Excel 导出(难度⭐⭐⭐)

PYTHON
# ============================================
# Step 7: Styled Report + Export
# ============================================

# Style the segment × category pivot
styled_pivot = (seg_cat.style
    .format('${:,.0f}')
    .background_gradient(cmap='RdYlGn', axis=None)
    .set_caption('Revenue by Segment × Category')
)

# Style top products
styled_products = (top_products.style
    .format({'revenue': '${:,.0f}', 'quantity': '{:,}', 'avg_discount': '{:.1%}'})
    .bar(subset=['revenue'], color='lightblue')
    .highlight_max(subset=['revenue'], color='lightgreen')
)

# Style low stock alert
styled_stock = (low_stock.head(10).style
    .format({'stock': '{:.0f}', 'reorder_level': '{:.0f}', 'total_orders': '{:,}'})
    .background_gradient(subset=['total_orders'], cmap='YlOrRd')
    .set_caption('Low Stock Alert — High Demand Products')
)

# Export to Excel with multiple sheets
output_path = 'ecommerce_report.xlsx'
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
    # Summary sheet
    summary = pd.DataFrame({
        'Metric': ['Total Revenue', 'Total Profit', 'Total Orders',
                    'Unique Customers', 'Unique Products', 'Avg Order Value',
                    'Profit Margin'],
        'Value': [full['revenue'].sum(), full['profit'].sum(), len(full),
                  full['customer_id'].nunique(), full['product_id'].nunique(),
                  full['revenue'].mean(), full['profit'].sum() / full['revenue'].sum()]
    })
    summary.to_excel(writer, sheet_name='Summary', index=False)

    # Region × Category
    region_cat.to_excel(writer, sheet_name='Region-Category')

    # Monthly trend
    monthly_region.to_excel(writer, sheet_name='Monthly-Trend')

    # Segment × Category (styled)
    styled_pivot.to_excel(writer, sheet_name='Segment-Category')

    # Top Products
    top_products.to_excel(writer, sheet_name='Top-Products')

print(f"✅ Report exported: {output_path}")

# Final summary
print("\n" + "=" * 50)
print("  E-COMMERCE COMPREHENSIVE ANALYSIS COMPLETE")
print("=" * 50)
print(f"  Revenue: ${full['revenue'].sum():,.0f}")
print(f"  Profit: ${full['profit'].sum():,.0f}")
print(f"  Margin: {full['profit'].sum() / full['revenue'].sum():.1%}")
print(f"  Top Region: {full.groupby('region')['revenue'].sum().idxmax()}")
print(f"  Top Category: {full.groupby('category')['revenue'].sum().idxmax()}")
print(f"  Low Stock Items: {len(low_stock)}")
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

❓ 常见问题

Q 多数据源如何统一格式?
A 三步统一:① 列名标准化(同一键用同一名称,如 customer_id);② 类型统一(日期列全部 to_datetime,ID 列全部 int);③ 编码统一(UTF-8 优先,GBK 转 UTF-8)。merge 前先检查键列的 dtype 和 unique 值,确认可以匹配。
Q 数据质量怎么量化?
A 四个维度:① 完整性(缺失率=缺失数/总数,目标<5%);② 一致性(键列在关联表中是否都有匹配);③ 准确性(异常值比例,如负金额/超大值);④ 时效性(数据更新时间,是否过时)。每个维度打分 1-5,综合评估。
Q merge 链太长怎么办?
A 分步 merge 并逐步验证——每次 merge 后检查行数和缺失数。5 表 merge 不要一口气写,写成 4 步:orders+products → +customers → +regions → +inventory。每步后 print(shape, missing) 确认正确再继续。
Q 报告自动化?
A 用 ExcelWriter 写多 Sheet(summary + 各维度分析 + styled pivot),或 Styler.to_html() 输出网页报告。进阶:用 Jupyter Notebook + nbconvert 自动生成 PDF。终极:用 papermill 参数化 Notebook,定时运行出报告。
Q 与 BI 工具对比?
A Pandas 适合灵活的定制分析——不受 BI 工具功能限制,可以写任意复杂逻辑。BI 工具(Tableau/PowerBI)适合标准化报表和交互式探索——拖拽出图快但复杂计算受限。策略:Pandas 做深度分析+数据准备,BI 做可视化展示。
Q pivot_table 多维度怎么做?
A index 多列=pd.pivot_table(df, index=['region','segment'], columns='category'),产生 MultiIndex 列。margins=True 加行列总计。交叉分析=一个维度做行、一个做列、一个做值——这是最直观的三维数据展示方式。
Q 低库存预警怎么做?
A 比较 stock 和 reorder_level——df[df['stock'] < df['reorder_level']]。进一步结合订单量排序:低库存+高订单量=最紧急。用 Styler 的 background_gradient 标记紧急程度,红色=需立即补货。

📖 小节


📝 作业

  1. 基础题(难度⭐):创建 2 个 DataFrame(客户+订单),用 merge 关联后按地区统计总销售额,用 indicator 检查匹配情况。
  2. 进阶题(难度⭐⭐):模拟 3 源数据(客户/产品/订单),3 次 merge → 清洗 → groupby 多维聚合 → pivot_table 交叉表 → Styler 格式化。
  3. 挑战题(难度⭐⭐⭐):完成本课完整项目:5 源加载 → 质量审计 → 4 表 merge → pipe 清洗 → 多维 groupby + pivot → Styler 报告 → ExcelWriter 多 Sheet 导出。

← 上一课:项目-时间序列 · 🎉 课程完结 →

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏