Pandas 实战案例

理论知识学得再多,不实践也难以真正掌握。本章将带你完成一个完整的电商销售数据分析项目,从模拟数据生成、数据清洗、特征工程,到分组聚合、透视表分析,最后用可视化呈现结论。通过这个案例,你将综合运用前面所学的几乎所有Pandas技巧。

🎯 案例背景

我们是一家电商平台,拥有以下数据:

  • 订单表:包含订单ID、用户ID、产品ID、订单日期、数量、单价、支付金额等。
  • 用户表:包含用户ID、注册日期、性别、城市、会员等级。
  • 产品表:包含产品ID、产品名称、类别、成本价。

目标:分析2024年上半年的销售情况,包括整体销售趋势、用户行为分析、产品类别表现等,为运营决策提供数据支持。

📦 步骤1:模拟生成数据

由于没有真实数据,我们先用Python生成模拟数据。这部分不是Pandas的重点,但为了案例完整性,我们快速生成三个DataFrame。

import pandas as pd
import numpy as np
from datetime import datetime, timedelta

# 设置随机种子以便复现
np.random.seed(42)

# 生成用户表 (1000个用户)
users = pd.DataFrame({
    'user_id': range(1, 1001),
    '注册日期': pd.date_range('2023-01-01', periods=1000, freq='D') + pd.to_timedelta(np.random.randint(0, 86400, 1000), unit='s'),
    '性别': np.random.choice(['男', '女'], 1000, p=[0.48, 0.52]),
    '城市': np.random.choice(['北京', '上海', '广州', '深圳', '杭州', '成都'], 1000),
    '会员等级': np.random.choice(['普通', '黄金', '铂金', '钻石'], 1000, p=[0.5, 0.3, 0.15, 0.05])
})

# 生成产品表 (50个产品)
products = pd.DataFrame({
    'product_id': range(1, 51),
    '产品名称': [f'商品{i}' for i in range(1, 51)],
    '类别': np.random.choice(['电子产品', '服装', '家居', '食品', '图书'], 50),
    '成本价': np.random.randint(20, 500, 50)
})

# 生成订单表 (2024年1-6月的5000个订单)
order_ids = range(1, 5001)
user_ids = np.random.choice(users['user_id'], 5000, replace=True)
product_ids = np.random.choice(products['product_id'], 5000, replace=True)
order_dates = [datetime(2024,1,1) + timedelta(days=np.random.randint(0, 181)) for _ in range(5000)]
quantities = np.random.randint(1, 5, 5000)
prices = products.set_index('product_id').loc[product_ids, '成本价'].values * np.random.uniform(1.2, 2.0, 5000)  # 售价=成本价*随机加成

orders = pd.DataFrame({
    'order_id': order_ids,
    'user_id': user_ids,
    'product_id': product_ids,
    '订单日期': order_dates,
    '数量': quantities,
    '单价': prices.round(2),
    '支付金额': (quantities * prices).round(2)
})

print("数据生成完成。")
print(f"用户表: {users.shape}")
print(f"产品表: {products.shape}")
print(f"订单表: {orders.shape}")

🧹 步骤2:数据加载与初步探索

通常数据是从CSV或数据库读取,这里我们直接从内存中的DataFrame开始。先查看各表的基本信息。

# 查看订单表前几行
print(orders.head())

# 基本信息
print(orders.info())

# 检查缺失值
print(orders.isna().sum())

# 描述统计
print(orders.describe())

🔧 步骤3:数据清洗与预处理

检查并处理可能的问题:

  • 确保日期列是datetime类型(已满足)。
  • 检查是否有异常值(如支付金额为负、数量为0等)。
  • 将类别列转为category类型以优化内存。
  • 合并用户和产品信息到订单表,方便分析。
# 检查异常值
print(orders[orders['支付金额'] <= 0])   # 应该为空
print(orders[orders['数量'] <= 0])       # 应该为空

# 数据类型优化
users['性别'] = users['性别'].astype('category')
users['城市'] = users['城市'].astype('category')
users['会员等级'] = users['会员等级'].astype('category')
products['类别'] = products['类别'].astype('category')

# 合并用户信息到订单表
orders = orders.merge(users, on='user_id', how='left')
orders = orders.merge(products, on='product_id', how='left')

print(orders.head())

📅 步骤4:特征工程

从订单日期中提取年、月、季度、星期几等特征,方便后续按时间聚合。同时计算一些衍生指标,如利润、是否周末等。

# 提取时间特征
orders['订单月份'] = orders['订单日期'].dt.month
orders['订单季度'] = orders['订单日期'].dt.quarter
orders['订单星期'] = orders['订单日期'].dt.dayofweek  # 周一=0,周日=6
orders['是否周末'] = orders['订单星期'].isin([5,6]).astype(int)  # 周六周日

# 计算利润(支付金额 - 成本价*数量)
orders['利润'] = orders['支付金额'] - (orders['成本价'] * orders['数量'])

print(orders[['订单日期','订单月份','订单季度','订单星期','是否周末','利润']].head())

📊 步骤5:整体销售趋势分析

按日、周、月聚合销售额和订单量,绘制趋势图。

# 按日聚合
daily_sales = orders.groupby(orders['订单日期'].dt.date)['支付金额'].sum().reset_index()
daily_sales.columns = ['日期', '日销售额']

# 按月聚合
monthly_sales = orders.groupby('订单月份')['支付金额'].sum().reset_index()
monthly_sales.columns = ['月份', '月销售额']

print("月度销售额:")
print(monthly_sales)

# 绘制折线图(需先导入matplotlib)
import matplotlib.pyplot as plt

plt.figure(figsize=(12,5))
plt.subplot(1,2,1)
plt.plot(daily_sales['日期'], daily_sales['日销售额'])
plt.title('日销售额趋势')
plt.xticks(rotation=45)

plt.subplot(1,2,2)
plt.bar(monthly_sales['月份'], monthly_sales['月销售额'])
plt.title('月销售额')
plt.xlabel('月份')
plt.ylabel('销售额')

plt.tight_layout()
plt.show()

👥 步骤6:用户行为分析

分析不同性别、城市、会员等级的消费情况。

# 按性别统计消费金额
gender_spend = orders.groupby('性别')['支付金额'].sum()
print(gender_spend)

# 按城市统计订单量
city_orders = orders.groupby('城市')['order_id'].count().sort_values(ascending=False)
print(city_orders)

# 会员等级与消费金额的关系
member_spend = orders.groupby('会员等级')['支付金额'].mean().sort_index()
print("各等级平均支付金额:")
print(member_spend)

# 绘制饼图
plt.figure(figsize=(10,4))
plt.subplot(1,2,1)
gender_spend.plot(kind='pie', autopct='%1.1f%%')
plt.title('消费金额性别分布')

plt.subplot(1,2,2)
city_orders.head(5).plot(kind='bar')
plt.title('订单量Top5城市')
plt.ylabel('订单数')
plt.tight_layout()
plt.show()

📦 步骤7:产品类别分析

各类别的销售额、利润、销量排名。

# 各类别销售额
category_sales = orders.groupby('类别')['支付金额'].sum().sort_values(ascending=False)
print("各类别销售额:")
print(category_sales)

# 各类别利润
category_profit = orders.groupby('类别')['利润'].sum().sort_values(ascending=False)
print("各类别利润:")
print(category_profit)

# 各类别销量
category_quantity = orders.groupby('类别')['数量'].sum().sort_values(ascending=False)
print("各类别销量:")
print(category_quantity)

# 绘制横向柱状图
category_sales.plot(kind='barh', title='各类别销售额')
plt.xlabel('销售额')
plt.show()

🔄 步骤8:透视表分析

创建透视表,查看不同类别在不同月份的销售额。

pivot = pd.pivot_table(orders,
                        values='支付金额',
                        index='类别',
                        columns='订单月份',
                        aggfunc='sum',
                        fill_value=0)
print(pivot)

# 热力图展示(需seaborn)
import seaborn as sns
plt.figure(figsize=(10,6))
sns.heatmap(pivot, annot=True, fmt='.0f', cmap='YlOrRd')
plt.title('各类别月度销售额')
plt.show()

📈 步骤9:高价值用户识别

找出消费总额前10的用户及其信息。

user_total = orders.groupby('user_id')['支付金额'].sum().sort_values(ascending=False).head(10)
top_users = users[users['user_id'].isin(user_total.index)]
print("高价值用户信息:")
print(top_users)

🧪 步骤10:结论与建议

基于以上分析,我们可以得出一些初步结论:

  • 销售额在1-6月整体呈上升趋势,其中3月和6月有显著增长(可能受促销活动影响)。
  • 女性用户贡献了约60%的销售额,是主要消费群体。
  • 电子产品销售额最高,但利润可能因成本高而并非最大;服装类销量最大。
  • 钻石会员平均消费远超其他等级,值得重点维护。
  • 北京、上海、广州是订单量前三的城市。

建议:针对女性用户推送相关产品;对钻石会员提供专属优惠;加强电子产品的利润管理;在Top城市加大营销投入。

案例总结:

通过这个实战案例,我们完整演示了如何使用Pandas进行真实数据分析:

  • 数据生成与加载
  • 数据清洗与预处理
  • 特征工程
  • 分组聚合与透视表
  • 数据可视化
  • 结论提炼

你可以替换为真实数据,按照类似流程进行分析。Pandas的强大之处在于,一旦数据进入DataFrame,你就可以用统一的方式探索和处理它。

注意:以上代码假设你已安装matplotlib和seaborn(用于热力图)。如果未安装,请先运行 pip install matplotlib seaborn