96·模块十八:综合项目实战高级

项目实战:完成一个端到端的数据分析项目

projectdata-analysispandasvisualization

第96课:项目实战 - 完成一个端到端的数据分析项目

学习目标

完成本课学习后,你将能够:

  1. 理解并执行一个完整的端到端数据分析项目流程,从数据获取到最终报告。
  2. 熟练运用 pandas 进行数据的读取、清洗、探索性分析与聚合计算。
  3. 使用 matplotlibseaborn 创建信息丰富、具有说服力的数据可视化图表。
  4. 掌握将分析过程和结果整合并自动生成报告的基本方法。

核心概念

端到端数据分析就像一个侦探破案:你手头可能是一堆杂乱无章的线索(原始数据),你的目标是理清头绪(清洗),发现隐藏的模式(分析与可视化),最后向"委托人"(例如你的老板或客户)呈现一个清晰、有说服力的故事(报告)。

这个项目的完整流程通常包括以下阶段:

  1. 明确目标:我们需要解决什么问题?(例如:"找出我们咖啡店最受欢迎的产品以及销售趋势")
  2. 数据获取:从哪里获取数据?(CSV文件、数据库、网络API等)
  3. 数据清洗:处理缺失值、重复值、异常值、数据类型转换。这是最耗时但至关重要的一步。
  4. 探索性数据分析:通过统计和可视化,对数据有一个初步的感性认识。
  5. 深度分析与建模:针对目标进行更深入的分析,例如时间序列分析、相关性分析、分组聚合等。
  6. 数据可视化:创建图表,将分析结果"翻译"成直观的图像。
  7. 生成报告与洞察:总结发现,得出结论,并可能提出建议。我们可以自动化生成报告(如Jupyter Notebook或PDF)。

在本课中,我们将模拟一个咖啡店销售分析项目,完成上述大部分步骤。

代码示例

我们将分析一家虚构的"星空咖啡"店的销售数据。数据已预存在一个CSV文件中(请自行创建starbucks_sales.csv,或使用下方提供的生成代码)。

# 步骤 0: 导入必要的库
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore') # 为了输出整洁,忽略一些警告

# 设置中文字体和风格(根据系统可能需调整)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
sns.set(style="whitegrid") # 设置Seaborn风格

print("库导入完成!")

# ============================================================
# 步骤 1: 模拟生成数据(如果你没有真实数据文件,运行此块)
# ============================================================
def generate_starbucks_data():
    """生成模拟的咖啡店销售数据"""
    np.random.seed(42)
    n_records = 1000
    start_date = datetime(2023, 1, 1)
    dates = [start_date + timedelta(days=i) for i in range(365)]
    
    data = {
        '订单ID': [f'ORD{10001 + i}' for i in range(n_records)],
        '日期': np.random.choice(dates, n_records),
        '产品': np.random.choice(['美式咖啡', '拿铁', '卡布奇诺', '摩卡', '热巧克力', '冰红茶'], n_records, p=[0.3, 0.25, 0.2, 0.15, 0.07, 0.03]),
        '大小': np.random.choice(['小杯', '中杯', '大杯'], n_records, p=[0.2, 0.5, 0.3]),
        '数量': np.random.randint(1, 4, n_records),
        '单价': np.nan # 稍后根据产品和大小设定
    }
    
    df = pd.DataFrame(data)
    
    # 根据产品和大小设定单价
    price_map = {
        ('美式咖啡', '小杯'): 18, ('美式咖啡', '中杯'): 22, ('美式咖啡', '大杯'): 26,
        ('拿铁', '小杯'): 22, ('拿铁', '中杯'): 26, ('拿铁', '大杯'): 30,
        ('卡布奇诺', '小杯'): 23, ('卡布奇诺', '中杯'): 27, ('卡布奇诺', '大杯'): 31,
        ('摩卡', '小杯'): 25, ('摩卡', '中杯'): 29, ('摩卡', '大杯'): 33,
        ('热巧克力', '小杯'): 20, ('热巧克力', '中杯'): 24, ('热巧克力', '大杯'): 28,
        ('冰红茶', '小杯'): 15, ('冰红茶', '中杯'): 18, ('冰红茶', '大杯'): 21,
    }
    
    for idx, row in df.iterrows():
        key = (row['产品'], row['大小'])
        df.at[idx, '单价'] = price_map[key]
        
    # 引入一些缺失值和异常值
    missing_indices = np.random.choice(n_records, 50, replace=False)
    df.loc[missing_indices[:25], '数量'] = np.nan
    df.loc[missing_indices[25:], '单价'] = np.nan
    
    # 添加一个明显异常值
    df.loc[df['订单ID'] == 'ORD10050', '数量'] = 100  # 一个人点了100杯?
    
    return df

# 生成数据并保存到CSV
df_raw = generate_starbucks_data()
df_raw.to_csv('starbucks_sales.csv', index=False)
print("模拟数据已生成并保存至 'starbucks_sales.csv'")

# ============================================================
# 步骤 2: 数据读取与初步查看
# ============================================================
# 从CSV文件读取数据
df = pd.read_csv('starbucks_sales.csv')
print("\n=== 数据读取完成 ===")
print(f"数据形状 (行, 列): {df.shape}")
print("\n--- 数据前5行 ---")
print(df.head())
print("\n--- 数据基本信息 ---")
print(df.info())

# ============================================================
# 步骤 3: 数据清洗
# ============================================================
print("\n=== 开始数据清洗 ===")

# 3.1 处理缺失值
print(f"缺失值统计:\n{df.isnull().sum()}")
# 策略:删除'数量'缺失的行;'单价'缺失的行,用该产品的平均单价填充。
df.dropna(subset=['数量'], inplace=True)
product_avg_price = df.groupby('产品')['单价'].transform('mean')
df['单价'].fillna(product_avg_price, inplace=True)
print("缺失值处理完成。")

# 3.2 处理异常值
print("\n检查异常值...")
# 根据常识,单次订单数量超过10可能为异常
outlier_mask = df['数量'] > 10
print(f"发现 {outlier_mask.sum()} 条数量异常的记录 (数量 > 10):")
print(df[outlier_mask][['订单ID', '产品', '大小', '数量']])
# 策略:删除这些明显异常的记录
df = df[~outlier_mask]
print("异常值已移除。")

# 3.3 数据类型优化与计算
df['日期'] = pd.to_datetime(df['日期'])
df['总金额'] = df['数量'] * df['单价'] # 新增计算列

print("\n--- 清洗后数据概览 ---")
print(df.describe())
print("\n数据清洗完成!")

# ============================================================
# 步骤 4: 探索性数据分析 (EDA)
# ============================================================
print("\n=== 开始探索性数据分析 ===")

# 4.1 哪些产品最受欢迎?(按订单数量)
product_popularity = df['产品'].value_counts()
print("\n产品受欢迎程度(按订单数):")
print(product_popularity)

# 4.2 不同大小的选择情况
size_popularity = df['大小'].value_counts()
print("\n杯型选择分布:")
print(size_popularity)

# 4.3 按月统计总销售额
df['月份'] = df['日期'].dt.to_period('M')
monthly_sales = df.groupby('月份')['总金额'].sum()
print("\n每月总销售额(元):")
print(monthly_sales)

# ============================================================
# 步骤 5: 数据可视化
# ============================================================
print("\n=== 生成数据可视化图表 ===")

# 创建一个2x2的子图布局
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle('星空咖啡店销售数据分析报告', fontsize=16)

# 图表1:产品订单数量柱状图
sns.countplot(data=df, x='产品', order=product_popularity.index, ax=axes[0, 0], palette='viridis')
axes[0, 0].set_title('各产品订单数量')
axes[0, 0].set_xlabel('产品')
axes[0, 0].set_ylabel('订单数量')
axes[0, 0].tick_params(axis='x', rotation=45)

# 图表2:杯型占比饼图
axes[0, 1].pie(size_popularity.values, labels=size_popularity.index, autopct='%1.1f%%', colors=sns.color_palette('Set2'))
axes[0, 1].set_title('杯型选择占比')

# 图表3:月度销售额折线图
monthly_sales.plot(kind='line', marker='o', ax=axes[1, 0], color='coral')
axes[1, 0].set_title('月度销售额趋势')
axes[1, 0].set_xlabel('月份')
axes[1, 0].set_ylabel('总销售额 (元)')
axes[1, 0].tick_params(axis='x', rotation=45)

# 图表4:产品与杯型销售额热力图(交叉表)
cross_tab = df.pivot_table(values='总金额', index='产品', columns='大小', aggfunc='sum', fill_value=0)
sns.heatmap(cross_tab, annot=True, fmt='.0f', cmap='YlOrRd', ax=axes[1, 1], cbar_kws={'label': '总销售额 (元)'})
axes[1, 1].set_title('产品-杯型销售额分布')

plt.tight_layout(rect=[0, 0, 1, 0.96]) # 调整布局,为总标题留空间
plt.savefig('starbucks_sales_report.png', dpi=150, bbox_inches='tight')
plt.show()
print("可视化图表已保存为 'starbucks_sales_report.png'")

# ============================================================
# 步骤 6: 生成自动化文本报告摘要
# ============================================================
print("\n=== 生成分析摘要报告 ===")
summary = f"""
星空咖啡店销售数据分析摘要
===========================
分析周期: {df['日期'].min().strftime('%Y-%m-%d')}{df'日期'].max().strftime('%Y-%m-%d')}
总订单数: {len(df)}
总销售额: {df['总金额'].sum():,.2f} 元

关键发现:
1. 最受欢迎的产品: {product_popularity.index[0]},共{product_popularity.iloc[0]}单。
2. 最常选择的杯型: {size_popularity.index[0]},占比{size_popularity.iloc[0]/len(df)*100:.1f}%。
3. 销售额峰值出现在: {monthly_sales.idxmax()}月,达到{monthly_sales.max():,.2f}元。
4. "{cross_tab.stack().idxmax()[0]}" + "{cross_tab.stack().idxmax()[1]}" 组合创造了最高单项销售额。

建议:
- 重点推广 {product_popularity.index[0]}{product_popularity.index[1]}。
- 确保 {size_popularity.index[0]} 杯的物料充足。
- 在销售低谷月份(如 {monthly_sales.idxmin()}月)策划促销活动。
"""
print(summary)

# 将报告保存为文本文件
with open('starbucks_analysis_report.txt', 'w', encoding='utf-8') as f:
    f.write(summary)
print("文本报告已保存为 'starbucks_analysis_report.txt'")
print("\n🎉 端到端数据分析项目完成!")

实践练习

  1. 基础练习:修改数据生成函数 generate_starbucks_data(),增加一种新产品"燕麦奶拿铁",并为其设定合理的价格。重新运行整个分析流程,观察结果有何变化。
  2. 中级练习:在探索性分析(步骤4)中,添加一个新的分析:计算每周中各天的销售额(周一至周日),并绘制相应的柱状图。哪一天是销售高峰?
  3. 高级挑战:将最终的分析摘要(summary 字符串)和关键的图表(starbucks_sales_report.png)自动整合到一个HTML报告中。你可以使用简单的字符串模板来生成一个 .html 文件。

常见错误

  1. 忽视数据清洗:直接使用原始数据进行分析,导致结果被异常值或缺失值严重扭曲(如我们的数量=100)。
  2. 过度拟合特定分析:只盯着自己关心的指标,而忽略了数据整体的分布和潜在的其他重要关系。
  3. 可视化过于复杂或不清晰:图表信息过载,使用过多的颜色、3D效果或不合适的图表类型,反而让观众困惑。
  4. 忽略业务背景:分析脱离实际业务场景。例如,单纯比较"热巧克力"和"美式咖啡"的销量而不考虑季节因素。
  5. 报告缺乏洞察:报告只罗列数据和图表,没有提炼出"所以呢?"(So What?)的关键见解和行动建议。

小结

在本课中,我们通过一个模拟的咖啡店销售项目,实践了一个端到端数据分析的完整流程。关键要点回顾如下:

  • 流程是核心:明确目标 → 数据获取 → 清洗(重中之重) → EDA → 深度分析 → 可视化 → 报告。
  • Pandas 是基石:掌握 read_csvdropnafillnagroupbypivot_table 等是进行数据操作的根本。
  • 可视化是语言:使用 matplotlibseaborn 将数据转化为易懂的图表,是沟通发现的关键。
  • 自动化提升价值:尝试将重复的分析步骤脚本化,并自动生成报告(文本、HTML、PDF),这将极大提升你的工作效率和项目价值。

记住,每一个数据分析项目都是独特的。不断练习,你将能更快速地诊断数据问题,更精准地选择分析方法,并更有效地讲述数据故事。

练习编辑器

python
Loading...

继续学习

完成本课后,建议继续学习下一课「项目实战:自动化办公脚本(文件处理、邮件、报告)」 以巩固所学知识。