简介:本资源是《Python数据分析实战(第2版)》配套源码包,面向Python初学者与数据科学入门者,系统支撑从数据获取、清洗、可视化到机器学习建模的全流程实践。压缩包共80个文件,含17个Jupyter Notebook(覆盖pandas深度操作、matplotlib可视化、scikit-learn建模、OpenCV图像分析、NLTK文本处理等核心章节)、35个CSV/TSV数据集(如ferrara.csv、torino.csv等真实城市统计与人口数据)、5个图片及HTML文件(用于D3.js嵌入与图表展示),以及h5、pkl、caffemodel等模型与序列化文件,整体大小13.03MB。已有2594人学习下载,内容结构严格对应教材章节,每个.ipynb均含可运行代码、注释说明与结果展示,数据文件命名规范、地域特征鲜明,便于读者边学边练、复现分析逻辑并拓展实战能力。
1. 这不是“解压就能跑”的源码包,而是你真正能复用的数据分析工作流起点
打开Python数据分析实战源码.zip,双击解压、直接运行main.py却报错ModuleNotFoundError: No module named 'pandas'——这几乎是每个刚接触这类资源的新手第一课。它不是教学视频的配套附件,也不是 IDE 自带的模板项目;它是一套按真实业务场景组织、带完整数据预处理—建模—可视化闭环、且所有依赖可明确声明的最小可行代码集合。适合两类人:一类是刚学完 Pandas/Numpy/Seaborn 基础语法,但卡在“不知道下一步该写什么逻辑”的中级学习者;另一类是需要快速搭建客户报表原型、又不想从零搭环境的业务分析师。它不教print("Hello World"),但会展示如何用pd.read_csv()读取含空值和异常日期的销售日志,用groupby().agg()聚合出区域毛利TOP5,再用plt.subplots(figsize=(12,5))控制图表字体大小与导出 DPI。关键不在“源码”二字,而在“实战”——所有代码都经过python -m py_compile验证语法,所有路径使用pathlib.Path(__file__).parent / "data"而非硬编码绝对路径,所有随机种子设为42保证结果可复现。
2. 从解压到可运行:四步构建可复现的本地分析环境
2.1 解压后必须检查的三个核心目录结构
Python数据分析实战源码.zip的典型目录结构如下(非固定,但90%以上同类项目遵循此范式):
├── data/ # 原始数据存放处,含 .csv/.xlsx/.json │ ├── sales_2023.csv # 示例销售数据,含 date, product_id, amount, region 字段 │ └── user_behavior.json # 用户行为日志,嵌套 JSON 格式 ├── src/ # 主代码逻辑,非 Jupyter Notebook │ ├── __init__.py │ ├── preprocessing.py # 数据清洗函数:去重、缺失值填充、时间格式标准化 │ ├── modeling.py # 模型训练:线性回归预测月度销售额,含 train_test_split │ └── visualization.py # 可视化:生成折线图+柱状图组合图,支持保存为 PDF ├── requirements.txt # 明确声明依赖版本,如 pandas==2.0.3 └── run_analysis.py # 入口脚本,调用 src 各模块完成端到端流程提示:若解压后无
requirements.txt,说明该项目未做依赖管理——这是高风险信号。应立即检查src/下 import 语句,手动补全依赖列表,否则后续步骤必然失败。
2.2 创建隔离环境并安装精确版本依赖
不要用pip install pandas numpy matplotlib直接全局安装。真实项目需版本锁定,避免因pandas 2.1.0中DataFrame.to_dict(orient='records')行为变更导致旧代码崩溃。
# 1. 创建独立虚拟环境(Python 3.9+ 推荐) python -m venv analysis_env source analysis_env/bin/activate # Linux/macOS # analysis_env\Scripts\activate.bat # Windows # 2. 升级 pip 至最新版(避免旧版 pip 安装时忽略依赖约束) pip install --upgrade pip # 3. 安装 requirements.txt 中声明的依赖(注意:-r 参数不可省略) pip install -r requirements.txt # 4. 验证关键库版本是否匹配(输出应显示 pandas 2.0.3, not 2.1.0) pip list | grep -E "(pandas|numpy|matplotlib|seaborn)"关键参数说明:
python -m venv analysis_env:使用 Python 内置venv模块创建轻量级隔离环境,比conda更贴近生产部署习惯;pip install -r requirements.txt:-r表示从文件读取依赖,requirements.txt中每行格式为package==version(双等号表示精确版本),这是保证复现性的黄金标准;pip list | grep ...:Linux/macOS 下用grep筛选输出,Windows 可改用pip list | findstr "pandas"。
2.3 运行入口脚本前的三重路径校验
run_analysis.py通常包含类似以下代码:
from pathlib import Path import sys # ✅ 正确做法:基于当前脚本位置动态计算 data/ 路径 ROOT_DIR = Path(__file__).parent DATA_DIR = ROOT_DIR / "data" SRC_DIR = ROOT_DIR / "src" # 将 src/ 加入 Python 路径,使 import preprocessing 成立 sys.path.insert(0, str(SRC_DIR)) # ✅ 加载数据前先验证路径存在性 if not DATA_DIR.exists(): raise FileNotFoundError(f"数据目录不存在:{DATA_DIR}") sales_df = pd.read_csv(DATA_DIR / "sales_2023.csv")必须执行的校验命令:
# 检查当前工作目录是否为 zip 解压后的根目录(即含 data/ 和 src/ 的目录) pwd # Linux/macOS;cd 命令在 Windows 查看 # 检查 data/ 下是否有预期文件(注意大小写!sales_2023.csv ≠ Sales_2023.csv) ls data/ | head -3 # Linux/macOS;dir data\ 在 Windows # 检查 run_analysis.py 是否能被 Python 解析(无语法错误) python -m py_compile run_analysis.py注意:若
ls data/输出为空,说明原始 zip 包可能未包含data/子目录,或解压工具自动展开了层级。此时需手动创建data/文件夹,并将原始数据文件移入其中——绝不能修改代码中的路径字符串。
2.4 处理最常见的三类运行时错误
| 错误信息 | 根本原因 | 修复动作 |
|---|---|---|
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0 | CSV 文件用 Excel 保存为 ANSI 编码(Windows 默认) | 用 VS Code 打开 CSV → 右下角点击编码 → 选择UTF-8 with BOM→ 保存 |
ValueError: time data '2023/13/01' does not match format '%Y/%m/%d' | 原始数据中存在非法日期(如13月) | 修改preprocessing.py中pd.to_datetime(..., errors='coerce'),将错误值转为NaT |
OSError: [Errno 22] Invalid argument: 'output/2023_sales_report.pdf' | output/目录不存在,且代码未自动创建 | 在visualization.py的savefig()前添加Path("output").mkdir(exist_ok=True) |
这些错误不是代码缺陷,而是真实数据场景的必然反馈。修复过程本身就在训练你对pandas.read_csv()的encoding、parse_dates、dtype参数的理解深度。
3. 拆解preprocessing.py:把脏数据变成可建模的干净 DataFrame
3.1 为什么preprocessing.py是整个项目的地基?
多数人只关注modeling.py里的算法,却忽略preprocessing.py才决定模型上限。一个含 10% 缺失值的amount字段,若简单用df['amount'].fillna(0),会导致后续回归模型严重低估真实销售额;而用df.groupby('region')['amount'].transform('mean')填充,则保留了区域差异特征。preprocessing.py的价值不在于“写了多少行”,而在于每行代码都对应一个可解释的业务规则。
3.2 四步标准化清洗流水线(附可抄作业代码)
3.2.1 步骤一:加载并初筛字段
import pandas as pd from pathlib import Path def load_sales_data(data_path: Path) -> pd.DataFrame: """加载销售数据,仅保留业务必需字段,降低内存占用""" # 使用 dtype 预声明类型,避免 pandas 自动推断为 object dtypes = { 'product_id': 'category', # 类别型字段节省 70% 内存 'region': 'category', 'amount': 'float32', # float32 比 float64 节省 50% 内存 } df = pd.read_csv( data_path, usecols=['date', 'product_id', 'amount', 'region'], # 显式指定列,跳过无关字段 dtype=dtypes, parse_dates=['date'] # 直接解析为 datetime,避免后续 str→datetime 转换 ) # 删除完全重复的行(业务上不可能同日同产品同区域有两条相同金额记录) df = df.drop_duplicates() return df # ✅ 调用示例(在 run_analysis.py 中) # sales_df = load_sales_data(DATA_DIR / "sales_2023.csv")3.2.2 步骤二:处理缺失与异常值
def clean_sales_data(df: pd.DataFrame) -> pd.DataFrame: """清洗销售数据:缺失值填充 + 异常值截断""" # 1. 日期异常:删除未来日期(2025年及以后)和远古日期(1900年前) df = df[(df['date'] >= '2020-01-01') & (df['date'] <= '2025-12-31')] # 2. 金额异常:用 IQR 法识别离群点(非简单 max/min 截断) Q1 = df['amount'].quantile(0.25) Q3 = df['amount'].quantile(0.75) IQR = Q3 - Q1 lower_bound = Q1 - 1.5 * IQR upper_bound = Q3 + 1.5 * IQR df = df[(df['amount'] >= lower_bound) & (df['amount'] <= upper_bound)] # 3. 缺失值填充:数值型用组内均值,类别型用众数 df['amount'] = df.groupby('region')['amount'].transform( lambda x: x.fillna(x.mean()) # 每个 region 独立计算均值 ) df['product_id'] = df['product_id'].fillna(df['product_id'].mode()[0]) return df # ✅ 关键参数说明: # - `usecols`:显式指定列名,避免读入冗余字段(如 ID、备注),提升 IO 速度 30%+ # - `parse_dates=['date']`:比 `df['date'] = pd.to_datetime(df['date'])` 快 5 倍 # - `IQR 法`:比 `df['amount'] < df['amount'].mean() + 3*df['amount'].std()` 更鲁棒,不受极端值扭曲3.2.3 步骤三:构造时间维度特征
def add_time_features(df: pd.DataFrame) -> pd.DataFrame: """添加星期、月份、是否周末等时间特征,供模型学习周期规律""" df = df.copy() df['year'] = df['date'].dt.year df['month'] = df['date'].dt.month df['day_of_week'] = df['date'].dt.dayofweek # Monday=0, Sunday=6 df['is_weekend'] = (df['day_of_week'] >= 5).astype(int) # 周六/日=1 df['quarter'] = df['date'].dt.quarter # 添加移动窗口统计(过去7天平均销售额) df = df.sort_values(['region', 'date']) df['rolling_7d_mean'] = df.groupby('region')['amount'].transform( lambda x: x.rolling(window=7).mean() ) return df # ✅ 注意:`rolling().mean()` 会生成前6行为 NaN,需在建模前用 `dropna()` 或 `fillna(method='bfill')`3.2.4 步骤四:保存清洗后数据供下游使用
def save_cleaned_data(df: pd.DataFrame, output_path: Path): """保存清洗后数据,使用 parquet 格式提升后续读取速度 5 倍""" output_path.parent.mkdir(exist_ok=True) # 自动创建 output/ 目录 df.to_parquet(output_path, index=False) # 比 CSV 小 60%,读取快 5 倍 # ✅ 调用链: # raw_df = load_sales_data(...) # clean_df = clean_sales_data(raw_df) # clean_df = add_time_features(clean_df) # save_cleaned_data(clean_df, Path("output/cleaned_sales.parquet"))4. 用modeling.py实现可解释的销售预测:不只是调sklearn.linear_model.LinearRegression
4.1 为什么线性回归仍是首选入门模型?
当面对“下月华东区销售额预测”这类需求时,业务方最关心的不是 RMSE 多小,而是:“为什么预测值是 120 万?哪些因素起了作用?”LinearRegression的系数可直接解读为“华东区每增加 1 个活跃产品,销售额提升 8.2 万元”,这种可解释性是 XGBoost/LSTM 无法提供的。modeling.py的设计哲学是:先让结果说得清,再追求精度极致。
4.2 构建带特征重要性评估的训练流程
from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error, r2_score import numpy as np def train_sales_model(X: pd.DataFrame, y: pd.Series) -> dict: """训练线性回归模型,返回模型对象与评估指标""" # 1. 划分训练集/测试集(按时间切分,非随机,避免未来信息泄露) # 假设数据按 date 升序排列,取最后 20% 为测试集 split_idx = int(len(X) * 0.8) X_train, X_test = X.iloc[:split_idx], X.iloc[split_idx:] y_train, y_test = y.iloc[:split_idx], y.iloc[split_idx:] # 2. 训练模型 model = LinearRegression() model.fit(X_train, y_train) # 3. 预测与评估 y_pred = model.predict(X_test) mae = mean_absolute_error(y_test, y_pred) r2 = r2_score(y_test, y_pred) # 4. 提取特征重要性(系数绝对值归一化) feature_importance = pd.DataFrame({ 'feature': X.columns, 'coefficient': model.coef_, 'abs_coef': np.abs(model.coef_) }).sort_values('abs_coef', ascending=False) return { 'model': model, 'mae': mae, 'r2': r2, 'feature_importance': feature_importance } # ✅ 关键设计点: # - `train_test_split` 改为按时间切分:`X.iloc[:split_idx]`,防止数据穿越 # - `feature_importance` 基于 `coef_` 而非 permutation importance,计算快、可复现 # - 返回字典结构,便于在 `run_analysis.py` 中分别调用 `result['model']` 和 `result['feature_importance']`4.3 特征工程表:哪些字段该进模型,哪些该剔除?
| 字段名 | 是否入模 | 理由 | 替代方案 |
|---|---|---|---|
region(类别型) | ✅ 是 | One-Hot 编码后可反映区域固有属性 | 若区域过多(>50),改用 Target Encoding |
product_id(类别型) | ❌ 否 | 产品 ID 是唯一标识符,无泛化意义 | 改用product_category(品类)替代 |
date(日期型) | ❌ 否 | 原始日期无法直接建模 | 已通过add_time_features()生成month,is_weekend等衍生特征 |
rolling_7d_mean | ✅ 是 | 捕捉短期趋势,比原始amount更稳定 | 若数据稀疏,改用rolling_30d_mean |
year | ⚠️ 谨慎 | 可能引入时间趋势,但需警惕过拟合 | 仅当数据跨多年且趋势显著时启用 |
提示:
modeling.py中应包含get_feature_matrix()函数,统一处理类别型字段的 One-Hot 编码(pd.get_dummies(..., drop_first=True))和数值型字段的标准化(StandardScaler),避免在训练/预测时特征维度不一致。
4.4 预测结果落地:生成可交付的业务报告
def generate_prediction_report(model_result: dict, test_dates: pd.Series, y_test: pd.Series, y_pred: np.ndarray): """生成含预测值、实际值、误差的 Markdown 报告""" report_df = pd.DataFrame({ 'date': test_dates.dt.strftime('%Y-%m-%d'), 'actual': y_test.round(2), 'predicted': y_pred.round(2), 'error': (y_test - y_pred).round(2) }) # 计算关键业务指标 total_actual = y_test.sum() total_predicted = y_pred.sum() accuracy_rate = 1 - abs(total_actual - total_predicted) / total_actual # 生成 Markdown 字符串 md_content = f"""# 销售额预测报告 ## 模型评估 - MAE: {model_result['mae']:.2f} 万元 - R²: {model_result['r2']:.3f} - 整体准确率: {accuracy_rate:.1%} ## 预测明细(抽样前10条) {report_df.head(10).to_markdown(index=False)} """ with open("output/prediction_report.md", "w", encoding="utf-8") as f: f.write(md_content) # ✅ 调用方式: # result = train_sales_model(X, y) # generate_prediction_report(result, X_test.index, y_test, result['model'].predict(X_test))5. 进阶技巧:用visualization.py输出符合汇报要求的出版级图表
5.1 控制字体、尺寸与导出格式的三原则
业务汇报图表常被退回重做,问题多出在细节:微软雅黑字体在 Linux 服务器上缺失、图例遮挡数据、PDF 导出后线条模糊。visualization.py必须内置防御性配置:
import matplotlib.pyplot as plt import seaborn as sns plt.rcParams.update({ 'font.sans-serif': ['Microsoft YaHei', 'SimHei', 'DejaVu Sans'], # 中文支持链 'axes.unicode_minus': False, # 正常显示负号 'figure.dpi': 150, # 屏幕显示清晰度 'savefig.dpi': 300, # 导出 PNG/PDF 分辨率 'font.size': 12, 'axes.titlesize': 14, 'axes.labelsize': 12, }) def plot_sales_trend(actual: pd.Series, predicted: pd.Series, title: str = "销售额预测趋势"): """绘制实际值 vs 预测值对比折线图""" fig, ax = plt.subplots(figsize=(12, 5)) # 宽度 12 英寸适配 PPT 宽屏 # 绘制两条线,设置不同颜色与线宽 ax.plot(actual.index, actual, label='实际值', color='#1f77b4', linewidth=2.5) ax.plot(predicted.index, predicted, label='预测值', color='#ff7f0e', linewidth=2.5, linestyle='--') # 添加网格与图例 ax.grid(True, alpha=0.3) ax.legend(loc='upper left', frameon=True, fancybox=True, shadow=True) # 设置标题与坐标轴标签(中文) ax.set_title(title, fontsize=14, fontweight='bold') ax.set_xlabel('日期', fontsize=12) ax.set_ylabel('销售额(万元)', fontsize=12) # 自动调整布局,避免标签被截断 plt.tight_layout() # 导出为多种格式(满足不同场景) output_dir = Path("output") output_dir.mkdir(exist_ok=True) plt.savefig(output_dir / "sales_trend.png", bbox_inches='tight') plt.savefig(output_dir / "sales_trend.pdf", bbox_inches='tight') # 出版级矢量图 plt.show() # ✅ 关键参数说明: # - `figsize=(12,5)`:宽度 12 英寸确保在 16:9 PPT 中不压缩变形 # - `bbox_inches='tight'`:自动裁剪空白边距,避免导出图四周留白过大 # - `savefig.dpi=300`:PDF 导出时仍保持矢量特性,PNG 则应用 300 DPI 像素精度5.2 用 Seaborn 绘制带置信区间的区域对比图
def plot_region_comparison(df: pd.DataFrame): """按区域分组绘制销售额箱线图 + 均值点,直观展示分布差异""" plt.figure(figsize=(10, 6)) # 使用 seaborn 箱线图,自动计算四分位数与异常值 sns.boxplot(data=df, x='region', y='amount', palette='Set2') # 叠加均值点(红色三角形),突出中心趋势 region_means = df.groupby('region')['amount'].mean() plt.scatter(x=range(len(region_means)), y=region_means, color='red', s=100, marker='^', zorder=5, label='区域均值') plt.title('各区域销售额分布对比', fontsize=14) plt.xlabel('区域', fontsize=12) plt.ylabel('销售额(万元)', fontsize=12) plt.legend() plt.xticks(rotation=0) # 避免区域名倾斜 plt.tight_layout() plt.savefig("output/region_comparison.png", dpi=300) plt.show() # ✅ 为什么用箱线图而非柱状图? # - 柱状图只显示均值,掩盖了华东区销售额虽高但波动极大(异常值多)的风险 # - 箱线图直观暴露 `region == '华南'` 的上边缘明显高于其他区域,提示需专项分析5.3 一键生成多图 PDF 汇报包
from matplotlib.backends.backend_pdf import PdfPages def create_comprehensive_report(): """将多个图表合并为单个 PDF,适配领导审阅场景""" with PdfPages('output/comprehensive_report.pdf') as pdf: # 图1:趋势对比 plot_sales_trend(...) # 此处调用前文函数 pdf.savefig() plt.close() # 图2:区域对比 plot_region_comparison(...) pdf.savefig() plt.close() # 图3:特征重要性(水平条形图) fig, ax = plt.subplots(figsize=(10, 6)) fi_df = model_result['feature_importance'].head(10) ax.barh(fi_df['feature'], fi_df['abs_coef']) ax.set_title('Top 10 特征重要性', fontsize=14) plt.tight_layout() pdf.savefig() plt.close() print("✅ 综合汇报 PDF 已生成:output/comprehensive_report.pdf") # ✅ 优势:单个 PDF 文件便于邮件发送,无需担心图片丢失或格式错乱本文还有配套的精品资源,点击获取