数据分析实战 #
案例概述 #
本案例将通过一个完整的销售数据分析项目,演示 Pandas 在实际数据分析中的应用。
text
┌─────────────────────────────────────────────────────────────┐
│ 数据分析流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 数据获取 │
│ └── 读取数据源 │
│ │
│ 2. 数据清洗 │
│ ├── 处理缺失值 │
│ ├── 处理重复值 │
│ └── 处理异常值 │
│ │
│ 3. 数据探索 │
│ ├── 描述统计 │
│ ├── 分布分析 │
│ └── 相关性分析 │
│ │
│ 4. 数据分析 │
│ ├── 分组分析 │
│ ├── 时间序列分析 │
│ └── 对比分析 │
│ │
│ 5. 结果输出 │
│ ├── 可视化 │
│ └── 报告生成 │
│ │
└─────────────────────────────────────────────────────────────┘
准备数据 #
python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 设置中文显示
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 生成模拟销售数据
np.random.seed(42)
n_records = 1000
dates = pd.date_range('2023-01-01', '2023-12-31', freq='D')
products = ['Product A', 'Product B', 'Product C', 'Product D', 'Product E']
regions = ['North', 'South', 'East', 'West']
channels = ['Online', 'Store', 'Phone']
sales_data = pd.DataFrame({
'date': np.random.choice(dates, n_records),
'product': np.random.choice(products, n_records),
'region': np.random.choice(regions, n_records),
'channel': np.random.choice(channels, n_records),
'quantity': np.random.randint(1, 50, n_records),
'unit_price': np.random.uniform(10, 100, n_records)
})
# 计算销售额
sales_data['revenue'] = sales_data['quantity'] * sales_data['unit_price']
# 添加一些缺失值和异常值
sales_data.loc[np.random.choice(n_records, 20, replace=False), 'quantity'] = np.nan
sales_data.loc[np.random.choice(n_records, 10, replace=False), 'revenue'] = np.nan
# 添加一些重复值
sales_data = pd.concat([sales_data, sales_data.sample(10)])
print("原始数据:")
print(sales_data.head())
print(f"\n数据形状: {sales_data.shape}")
数据清洗 #
检查数据质量 #
python
# 数据信息
print(sales_data.info())
# 缺失值统计
print("\n缺失值统计:")
print(sales_data.isna().sum())
# 重复值统计
print(f"\n重复值数量: {sales_data.duplicated().sum()}")
# 数据类型
print("\n数据类型:")
print(sales_data.dtypes)
处理缺失值 #
python
# 删除完全重复的行
sales_data = sales_data.drop_duplicates()
# 填充缺失值
sales_data['quantity'] = sales_data['quantity'].fillna(sales_data['quantity'].median())
sales_data['revenue'] = sales_data['revenue'].fillna(sales_data['quantity'] * sales_data['unit_price'])
# 检查缺失值
print("处理后缺失值:")
print(sales_data.isna().sum())
处理异常值 #
python
# 检测异常值
def detect_outliers_iqr(df, column):
Q1 = df[column].quantile(0.25)
Q3 = df[column].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
return df[(df[column] < lower) | (df[column] > upper)]
outliers_quantity = detect_outliers_iqr(sales_data, 'quantity')
outliers_revenue = detect_outliers_iqr(sales_data, 'revenue')
print(f"数量异常值: {len(outliers_quantity)}")
print(f"销售额异常值: {len(outliers_revenue)}")
# 处理异常值(用边界值替换)
Q1 = sales_data['quantity'].quantile(0.25)
Q3 = sales_data['quantity'].quantile(0.75)
IQR = Q3 - Q1
sales_data['quantity'] = sales_data['quantity'].clip(Q1 - 1.5 * IQR, Q3 + 1.5 * IQR)
数据探索 #
描述统计 #
python
# 数值列统计
print("数值列统计:")
print(sales_data.describe())
# 分类列统计
print("\n分类列统计:")
for col in ['product', 'region', 'channel']:
print(f"\n{col}:")
print(sales_data[col].value_counts())
分布分析 #
python
# 销售额分布
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
sales_data['revenue'].hist(bins=50, ax=axes[0])
axes[0].set_title('Revenue Distribution')
axes[0].set_xlabel('Revenue')
axes[0].set_ylabel('Frequency')
sales_data['quantity'].hist(bins=30, ax=axes[1])
axes[1].set_title('Quantity Distribution')
axes[1].set_xlabel('Quantity')
plt.tight_layout()
plt.show()
数据分析 #
产品分析 #
python
# 按产品分组
product_analysis = sales_data.groupby('product').agg({
'revenue': ['sum', 'mean', 'count'],
'quantity': 'sum'
}).round(2)
product_analysis.columns = ['total_revenue', 'avg_revenue', 'transaction_count', 'total_quantity']
product_analysis = product_analysis.sort_values('total_revenue', ascending=False)
print("产品分析:")
print(product_analysis)
# 可视化
product_analysis['total_revenue'].plot(kind='bar', figsize=(10, 5))
plt.title('Revenue by Product')
plt.xlabel('Product')
plt.ylabel('Total Revenue')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
区域分析 #
python
# 按区域分组
region_analysis = sales_data.groupby('region').agg({
'revenue': 'sum',
'quantity': 'sum'
}).sort_values('revenue', ascending=False)
print("区域分析:")
print(region_analysis)
# 饼图
region_analysis['revenue'].plot(kind='pie', autopct='%1.1f%%', figsize=(8, 8))
plt.title('Revenue Distribution by Region')
plt.ylabel('')
plt.show()
渠道分析 #
python
# 按渠道分组
channel_analysis = sales_data.groupby('channel').agg({
'revenue': ['sum', 'mean'],
'quantity': 'sum'
})
channel_analysis.columns = ['total_revenue', 'avg_revenue', 'total_quantity']
print("渠道分析:")
print(channel_analysis)
时间序列分析 #
python
# 按日期分组
sales_data['date'] = pd.to_datetime(sales_data['date'])
daily_sales = sales_data.groupby('date')['revenue'].sum()
# 月度销售
monthly_sales = daily_sales.resample('M').sum()
# 可视化
fig, axes = plt.subplots(2, 1, figsize=(12, 8))
daily_sales.plot(ax=axes[0])
axes[0].set_title('Daily Sales')
axes[0].set_xlabel('Date')
axes[0].set_ylabel('Revenue')
monthly_sales.plot(kind='bar', ax=axes[1])
axes[1].set_title('Monthly Sales')
axes[1].set_xlabel('Month')
axes[1].set_ylabel('Revenue')
axes[1].tick_params(axis='x', rotation=45)
plt.tight_layout()
plt.show()
多维度分析 #
python
# 产品-区域交叉分析
pivot_table = pd.pivot_table(
sales_data,
values='revenue',
index='product',
columns='region',
aggfunc='sum',
fill_value=0
)
print("产品-区域交叉分析:")
print(pivot_table)
# 热力图
import seaborn as sns
plt.figure(figsize=(10, 6))
sns.heatmap(pivot_table, annot=True, fmt='.0f', cmap='YlOrRd')
plt.title('Revenue by Product and Region')
plt.tight_layout()
plt.show()
分析报告 #
python
def generate_report(df):
print("=" * 60)
print("销售数据分析报告")
print("=" * 60)
print("\n1. 数据概览")
print(f" - 记录数: {len(df)}")
print(f" - 日期范围: {df['date'].min()} 至 {df['date'].max()}")
print(f" - 总销售额: ${df['revenue'].sum():,.2f}")
print(f" - 平均订单金额: ${df['revenue'].mean():,.2f}")
print("\n2. 产品表现")
top_product = df.groupby('product')['revenue'].sum().idxmax()
print(f" - 最畅销产品: {top_product}")
print("\n3. 区域表现")
top_region = df.groupby('region')['revenue'].sum().idxmax()
print(f" - 最佳区域: {top_region}")
print("\n4. 渠道表现")
top_channel = df.groupby('channel')['revenue'].sum().idxmax()
print(f" - 最佳渠道: {top_channel}")
print("\n5. 时间趋势")
monthly = df.groupby(df['date'].dt.to_period('M'))['revenue'].sum()
best_month = monthly.idxmax()
print(f" - 最佳月份: {best_month}")
print("\n" + "=" * 60)
generate_report(sales_data)
下一步 #
完成实战案例后,接下来学习 数据管道,了解如何构建可复用的数据处理流程!
最后更新:2026-04-04