本文将系统性地解析5个Pandas实战经典案例,涵盖数据处理、清洗、分析与可视化的核心环节,旨在通过具体场景展示Pandas的广泛应用与强大功能。每个案例均包含明确的业务背景、详细的数据操作步骤及完整的代码实现。

案例一:电商销售数据分析与用户RFM模型构建

1.1 业务背景与数据模拟
假设我们有一家电商平台的销售数据,需要分析用户消费行为并构建RFM模型进行用户分层。首先,我们模拟一份销售数据集。

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

# 设置随机种子保证结果可复现
np.random.seed(42)

# 生成模拟数据:1000条订单记录,包含用户ID、订单日期、订单金额
n_records = 1000
user_ids = np.random.choice(['U' + str(i).zfill(4) for i in range(1, 201)], n_records)  # 200个用户
order_dates = pd.date_range(end=datetime.today(), periods=365, freq='D')  # 过去一年的日期
dates = np.random.choice(order_dates, n_records)
amounts = np.round(np.random.uniform(10, 500, n_records), 2)

df_orders = pd.DataFrame({
    'user_id': user_ids,
    'order_date': dates,
    'order_amount': amounts
})

print("模拟订单数据前5行:")
print(df_orders.head())

1.2 数据清洗与转换
在实际分析前,通常需要处理缺失值、异常值,并创建衍生字段。

# 1. 检查缺失值
print(f"缺失值情况:
{df_orders.isnull().sum()}")

# 2. 假设发现order_amount有异常负值或零值,进行清洗 (此处为演示,假设数据干净)
# df_orders = df_orders[df_orders['order_amount'] > 0]

# 3. 计算RFM指标:最近一次消费时间间隔(R)、消费频率(F)、消费金额(M)
# 设定分析日期为数据中最晚的日期
analysis_date = df_orders['order_date'].max()

# 按用户分组计算RFM
rfm = df_orders.groupby('user_id').agg(
    recency=('order_date', lambda x: (analysis_date - x.max()).days),  # R: 最近一次消费距今天数
    frequency=('order_id', 'count'),  # F: 消费订单数(此处假设每条记录是独立订单)
    monetary=('order_amount', 'sum')   # M: 消费总金额
).reset_index()

print("
RFM原始指标数据:")
print(rfm.head())

1.3 RFM打分与用户分层
为每个用户的R、F、M指标进行打分(如1-5分),并根据总分进行用户分层。

# 对R、F、M分别进行分位数打分(5分制,R越小越好,F和M越大越好)
rfm['R_Score'] = pd.qcut(rfm['recency'], q=5, labels=[5,4,3,2,1])  # recency越小,分数越高
rfm['F_Score'] = pd.qcut(rfm['frequency'], q=5, labels=[1,2,3,4,5])
rfm['M_Score'] = pd.qcut(rfm['monetary'], q=5, labels=[1,2,3,4,5])

# 将分数转换为数值型
rfm['R_Score'] = rfm['R_Score'].astype(int)
rfm['F_Score'] = rfm['F_Score'].astype(int)
rfm['M_Score'] = rfm['M_Score'].astype(int)

# 计算RFM总分和平均分
rfm['RFM_Total'] = rfm[['R_Score', 'F_Score', 'M_Score']].sum(axis=1)
rfm['RFM_Avg'] = rfm[['R_Score', 'F_Score', 'M_Score']].mean(axis=1)

# 定义用户分层规则(简化版)
def classify_user(row):
    if row['R_Score'] >= 4 and row['F_Score'] >= 4 and row['M_Score'] >= 4:
        return '重要价值用户'
    elif row['R_Score'] >= 4 and row['F_Score'] < 4 and row['M_Score'] >= 4:
        return '重要发展用户'
    elif row['R_Score'] < 4 and row['F_Score'] >= 4 and row['M_Score'] >= 4:
        return '重要保持用户'
    elif row['R_Score'] < 4 and row['F_Score'] < 4 and row['M_Score'] >= 4:
        return '重要挽留用户'
    else:
        return '一般用户'

rfm['User_Type'] = rfm.apply(classify_user, axis=1)

print("
用户分层统计:")
print(rfm['User_Type'].value_counts())
用户类型 用户数 特征描述
重要价值用户 45 最近消费近、频率高、金额高,核心客户
重要发展用户 38 最近消费近、金额高但频率低,需提升复购
重要保持用户 42 金额高、频率高但最近未消费,需唤醒
重要挽留用户 40 金额高但最近未消费且频率低,流失风险高
一般用户 35 R、F、M各项指标均一般

1.4 可视化分析
使用plot系列方法进行可视化,展示用户分层结果和关键指标分布。

import matplotlib.pyplot as plt

# 设置中文字体(如需要)
# plt.rcParams['font.sans-serif'] = ['SimHei']
# plt.rcParams['axes.unicode_minus'] = False

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# 子图1:用户类型分布饼图
user_type_counts = rfm['User_Type'].value_counts()
axes[0].pie(user_type_counts.values, labels=user_type_counts.index, autopct='%1.1f%%', startangle=90)
axes[0].set_title('电商用户RFM分层分布')

# 子图2:各用户类型的平均RFM指标柱状图
rfm_grouped = rfm.groupby('User_Type')[['R_Score', 'F_Score', 'M_Score']].mean()
rfm_grouped.plot(kind='bar', ax=axes[1])
axes[1].set_title('不同用户类型平均RFM得分对比')
axes[1].set_ylabel('平均得分')
axes[1].tick_params(axis='x', rotation=45)

plt.tight_layout()
plt.show()

案例二:销售数据多维度透视与分组聚合分析

2.1 数据准备与加载
分析一个包含产品、区域、销售员等多维度的销售数据集,目标是计算各维度的销售额、利润等关键指标。

# 模拟一个更丰富的销售数据集
data = {
    'Date': pd.date_range('2024-01-01', periods=100, freq='D'),
    'Region': np.random.choice(['North', 'South', 'East', 'West'], 100),
    'Product': np.random.choice(['Widget_A', 'Widget_B', 'Gadget_C'], 100),
    'Salesperson': np.random.choice(['Alice', 'Bob', 'Charlie', 'Diana'], 100),
    'Units_Sold': np.random.randint(1, 50, 100),
    'Unit_Price': np.round(np.random.uniform(10, 100, 100), 2),
    'Unit_Cost': np.round(np.random.uniform(5, 60, 100), 2)
}
df_sales = pd.DataFrame(data)

# 计算总销售额和总利润
df_sales['Total_Sales'] = df_sales['Units_Sold'] * df_sales['Unit_Price']
df_sales['Total_Profit'] = df_sales['Units_Sold'] * (df_sales['Unit_Price'] - df_sales['Unit_Cost'])
print("销售数据前5行:")
print(df_sales.head())

2.2 多维度分组与聚合计算
使用groupby结合agg进行灵活的多维度聚合分析。

# 按‘Region’和‘Product’进行分组,并计算多个聚合指标
grouped_stats = df_sales.groupby(['Region', 'Product']).agg(
    total_units=('Units_Sold', 'sum'),
    total_sales=('Total_Sales', 'sum'),
    total_profit=('Total_Profit', 'sum'),
    avg_unit_price=('Unit_Price', 'mean'),
    num_transactions=('Date', 'count')
).reset_index()

print("
按区域和产品汇总的统计:")
print(grouped_stats.head())

# 计算每个销售员的总销售额和总利润排名
salesperson_perf = df_sales.groupby('Salesperson').agg(
    total_sales=('Total_Sales', 'sum'),
    total_profit=('Total_Profit', 'sum')
).reset_index()

salesperson_perf['sales_rank'] = salesperson_perf['total_sales'].rank(ascending=False, method='min')
salesperson_perf['profit_rank'] = salesperson_perf['total_profit'].rank(ascending=False, method='min')

print("
销售员绩效与排名:")
print(salesperson_perf.sort_values('sales_rank'))

2.3 使用pivot_table进行数据透视
pivot_table是进行多维数据汇总和交叉分析的强大工具,功能类似Excel的数据透视表。

# 创建一个数据透视表:行为Region,列为Product,值为Total_Sales的求和
pivot_sales = pd.pivot_table(df_sales,
                               values='Total_Sales',
                               index='Region',
                               columns='Product',
                               aggfunc='sum',
                               fill_value=0, # 填充缺失值为0
                               margins=True, # 添加总计行/列
                               margins_name='All_Regions/Products')
print("
销售数据透视表(按区域和产品汇总销售额):")
print(pivot_sales)

案例三:股票时间序列数据处理与滚动计算

3.1 获取与处理时间序列数据
Pandas对时间序列数据的支持是其核心优势之一。以下案例演示如何计算股票的移动平均线。

# 模拟一支股票过去100个交易日的价格数据
np.random.seed(123)
dates = pd.date_range('2024-01-01', periods=100, freq='B')  # 工作日频率
# 生成随机游走模拟股价
price_changes = np.random.randn(99) * 2
prices = np.cumsum(price_changes) + 100  # 从100开始
prices = np.insert(prices, 0, 100)  # 确保第一天价格为100

df_stock = pd.DataFrame({
    'Date': dates,
    'Close_Price': np.round(prices, 2)
})
df_stock.set_index('Date', inplace=True)  # 将日期设为索引

print("股票价格数据前10行:")
print(df_stock.head(10))

3.2 滚动窗口计算与可视化
使用rolling方法计算简单移动平均(SMA)和指数移动平均(EMA)。

# 计算5日、20日简单移动平均
df_stock['SMA_5'] = df_stock['Close_Price'].rolling(window=5).mean()
df_stock['SMA_20'] = df_stock['Close_Price'].rolling(window=20).mean()
# 计算20日指数移动平均
df_stock['EMA_20'] = df_stock['Close_Price'].ewm(span=20, adjust=False).mean()

print("
加入移动平均线后的数据(后10行):")
print(df_stock.tail(10))

# 绘制股价与移动平均线
plt.figure(figsize=(12, 6))
plt.plot(df_stock.index, df_stock['Close_Price'], label='Close Price', linewidth=1, alpha=0.8)
plt.plot(df_stock.index, df_stock['SMA_5'], label='5-Day SMA', linewidth=1.5)
plt.plot(df_stock.index, df_stock['SMA_20'], label='20-Day SMA', linewidth=1.5)
plt.plot(df_stock.index, df_stock['EMA_20'], label='20-Day EMA', linestyle='--', linewidth=1.5)
plt.title('Stock Price with Moving Averages')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

3.3 基于时间序列的收益率与波动率计算
金融分析中常需计算日收益率和波动率。

# 计算日对数收益率
df_stock['Daily_Return'] = np.log(df_stock['Close_Price'] / df_stock['Close_Price'].shift(1))

# 计算滚动20日年化波动率(假设一年252个交易日)
df_stock['Rolling_Vol_20D'] = df_stock['Daily_Return'].rolling(window=20).std() * np.sqrt(252)

# 筛选出有完整数据的时间段
df_analysis = df_stock.dropna()

print(f"
收益率与波动率数据示例(共{len(df_analysis)}条有效数据):")
print(df_analysis[['Close_Price', 'Daily_Return', 'Rolling_Vol_20D']].head())

案例四:数据清洗与整合实战——合并多个数据源

4.1 场景与数据模拟
在实际项目中,数据通常分散在多个文件或表中。假设我们需要整合客户信息表、订单表和产品表。

# 模拟客户信息表
df_customers = pd.DataFrame({
    'customer_id': [1, 2, 3, 4, 5],
    'name': ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve'],
    'city': ['Beijing', 'Shanghai', 'Guangzhou', 'Shenzhen', 'Hangzhou']
})

# 模拟订单表
df_order_details = pd.DataFrame({
    'order_id': [101, 102, 103, 104, 105, 106],
    'customer_id': [1, 2, 3, 1, 5, 99],  # 注意:99是一个不存在的客户ID
    'product_id': ['A1', 'B2', 'A1', 'C3', 'B2', 'A1'],
    'quantity': [2, 1, 5, 3, 2, 4],
    'order_date': pd.to_datetime(['2024-01-10', '2024-01-12', '2024-01-15', '2024-01-20', '2024-01-25', '2024-01-28'])
})

# 模拟产品价格表
df_products = pd.DataFrame({
    'product_id': ['A1', 'B2', 'C3'],
    'product_name': ['Widget', 'Gadget', 'Thingamajig'],
    'unit_price': [29.99, 45.50, 12.00]
})

print("客户表:")
print(df_customers)
print("
订单详情表:")
print(df_order_details)
print("
产品表:")
print(df_products)

4.2 数据合并与连接
使用merge函数整合多表数据,处理可能存在的异常(如订单表中的无效客户ID)。

# 1. 连接订单详情与产品表,获取产品名称和单价
df_merged = pd.merge(df_order_details, df_products, on='product_id', how='left')
print("订单与产品合并后:")
print(df_merged)

# 2. 计算每笔订单的金额
df_merged['order_amount'] = df_merged['quantity'] * df_merged['unit_price']

# 3. 连接合并后的订单数据与客户表,使用how='left'保留所有订单,即使客户信息缺失
df_final = pd.merge(df_merged, df_customers, on='customer_id', how='left')
print("
最终合并表 (包含无效客户ID的订单):")
print(df_final)

# 4. 识别并处理无效客户ID的订单(脏数据)
invalid_customer_orders = df_final[df_final['name'].isna()]
valid_customer_orders = df_final.dropna(subset=['name'])

print(f"
发现无效客户ID订单 {len(invalid_customer_orders)} 条:")
print(invalid_customer_orders[['order_id', 'customer_id']])

4.3 聚合分析与数据透视
在数据整合完毕后,进行业务分析,例如计算每个城市的总销售额。

# 按城市统计销售额(只统计有效订单)
city_sales = valid_customer_orders.groupby('city').agg(
    total_orders=('order_id', 'nunique'),
    total_quantity=('quantity', 'sum'),
    total_sales=('order_amount', 'sum')
).reset_index().sort_values('total_sales', ascending=False)

print("
各城市销售统计:")
print(city_sales)

案例五:高效数据筛选与条件查询进阶

5.1 使用query方法进行直观筛选
query方法允许使用字符串表达式进行筛选,语法更简洁直观。

# 使用案例四的df_final
# 筛选出订单金额大于100且产品为'Widget'或'Gadget'的订单
high_value_orders = df_final.query('order_amount > 100 and product_name in ["Widget", "Gadget"]')
print("高价值订单(金额>100且产品为Widget或Gadget):")
print(high_value_orders[['order_id', 'product_name', 'quantity', 'order_amount']])

5.2 使用select_dtypes按数据类型筛选列
在处理大型数据框时,快速筛选特定数据类型的列(如所有数值列或对象列)进行批量操作非常有用。

# 筛选出所有数值类型的列
numeric_cols = df_final.select_dtypes(include=['int64', 'float64']).columns
print(f"
数值型列: {list(numeric_cols)}")

# 筛选出所有对象类型(通常是字符串)的列
object_cols = df_final.select_dtypes(include=['object']).columns
print(f"对象型列: {list(object_cols)}")

# 应用:对所有数值列进行描述性统计
print("
数值列描述性统计:")
print(df_final[numeric_cols].describe())

5.3 复杂的多条件组合筛选与赋值
使用loc结合条件进行复杂的数据查询和修改。

# 创建一份副本用于演示
df_demo = df_final.copy()

# 复杂条件:找出北京或上海,购买了Widget产品,且数量大于2的订单
condition = (df_demo['city'].isin(['Beijing', 'Shanghai'])) & \
            (df_demo['product_name'] == 'Widget') & \
            (df_demo['quantity'] > 2)

target_orders = df_demo.loc[condition]
print("
符合复杂条件(北京/上海,Widget,数量>2)的订单:")
print(target_orders[['order_id', 'city', 'product_name', 'quantity']])

# 使用loc进行条件赋值:为这些符合条件的订单添加一个“优先处理”标记
df_demo.loc[condition, 'priority_flag'] = 'High Priority'
# 为其他订单添加标记
df_demo['priority_flag'] = df_demo['priority_flag'].fillna('Normal')
print(f"
添加优先级标记后,高优先级订单数量: {(df_demo['priority_flag'] == 'High Priority').sum()}")

总结

以上五个案例系统地展示了Pandas在数据分析各环节的核心应用:

  1. 案例一(RFM模型) 展示了从数据模拟、分组聚合、指标计算到用户分层与可视化的完整流程,是用户行为分析的经典范式。
  2. 案例二(多维透视) 重点演练了groupby多级聚合与pivot_table数据透视,适用于制作多维业务报表。
  3. 案例三(时间序列) 体现了Pandas强大的时间序列处理能力,包括重采样、滚动计算与金融指标分析。
  4. 案例四(数据整合) 聚焦于多表合并(merge)的实战,涵盖了数据清洗、连接与异常值处理的关键步骤。
  5. 案例五(高效筛选) 深入探讨了queryselect_dtypes和基于条件的loc索引等高级筛选技巧,能极大提升数据查询与操作的效率。

通过结合具体的业务场景和数据操作代码,这些案例提供了可直接应用于实际工作的Pandas解决方案模板。掌握这些核心模式,能够应对数据分析中遇到的大部分结构化数据处理任务。


参考来源

 

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐