30天数据分析实战:从数据清洗到数据挖掘的全流程路线
2026/9/12 20:18:06 网站建设 项目流程

经常有想转行数据分析的朋友问我:资料收藏了一大堆,为什么真的开始学还是不知道从哪下手?是应该先啃 Python,还是先学 Excel?是先做可视化,还是先练数据清洗?数据挖掘听起来很高深,到底要不要碰算法?

这些问题背后有一个共同原因:大家把“数据分析、数据清洗、数据可视化、数据挖掘”当成四门独立的课在学,但实际工作中它们是一条流水线。真正能落地的数据分析项目,往往从一份很乱的表开始,经过清洗加工,再用图表辅助判断,最后通过算法或规则挖掘出可执行的结论。

这篇文章会给你一套完整的 30 天学习路线和项目实战方案。整个输出按“数据清洗 → 数据分析 → 数据可视化 → 数据挖掘”四段式展开,配合可以直接复制的 pandas、Matplotlib、Seaborn、Plotly、Scikit-Learn 代码。无论你是零基础在校学生、准备转行做数据分析的职场人,还是已经有 Python 基础但缺少项目经验的开发者,都能照着这套流程跑通一个端到端项目。

1. 先搞懂四件事:数据分析、数据清洗、数据挖掘、数据可视化

1.1 从“数据到决策”看四者的关系

先放一个最直观的理解方式。

数据清洗解决的是“数据能不能用”的问题。比如表里有空值、重复值、格式混乱的日期、明显异常的价格,如果这些不处理,后面算出来的指标全是错的。数据清洗占据真实数据项目 60% 以上的时间,不是夸张。

数据分析解决的是“发生了什么”的问题。比如这个月销售额环比下降了多少,哪个品类的退货率最高,哪个渠道的获客成本最低。这个环节主要靠分组聚合、同环比、漏斗拆解等方法把业务现状量化出来。

数据可视化解决的是“怎么让结论被看懂”的问题。同样是“华东区销售额最高”这句话,一图胜千言的道理大家都懂。但可视化不只是画图,更重要的是选择图形去匹配业务问题。趋势看折线图,结构看占比图,对比看柱状图,分布看直方图或箱线图。

数据挖掘解决的是“为什么会发生,以及接下来会发生什么”的问题。它比数据分析更进一步,会引入聚类、分类、回归、关联规则等算法,从数据中找到人工经验不容易发现的规律。

它们的关系不是递进关系,而是咬合关系。一个成熟的分析项目,可能先清洗数据,再做探索性可视化,发现某些用户群行为异常,最后用聚类把用户切分出来验证假设。四者缺一不可。

1.2 零基础学习者最容易踩的三个坑

第一个坑是“跳步”。很多初学者刚学完 pandas 基础,就直接去刷大厂算法题,前置数据太少、后置业务问题不清楚,最后只记住了 API,没有建立分析直觉。实际工作里,不是先选算法再找数据,而是先有业务问题,再决定用什么分析方法。

第二个坑是“只抄代码不跑数据”。看教程很容易产生一种“我懂了”的错觉,尤其是代码一段段照着敲完能运行之后,就以为自己掌握了。其实把输入数据换掉、把字段名换掉,很多初学者就会卡住。所以这个 30 天计划里,每一周都安排了“改数据重跑”的环节,目的是训练你迁移代码的能力。

第三个坑是“把画图当分析”。做出一张漂亮的折线图不等于分析完成。如果图表下面不能写出一段话,说清楚这个趋势是什么原因导致的、下一步应该做什么,那这份分析还只停留在技术展示阶段。这也是后文最佳实践部分会专门讲“分析收尾公式”的原因。

1.3 这套 30 天计划适合谁?

不太适合把数据分析当副业噱头、指望一周速成的人。数据分析的难点不在语法,而在业务理解、数据敏感度和推理逻辑,这些都需要持续练习。

比较适合的人群有三类:

  • 零基础转行:没有 Python 基础,但愿意每天花 1.5 到 2 小时动手练习;
  • 会用 Excel 但想提升效率的职场人:希望通过脚本完成周期性报表和清洗工作;
  • 有编程基础但缺少业务视角的开发:想了解数据岗位完整的项目产出方式。

接下来给出 30 天路线时,我会默认你每天能挤出至少 90 分钟。碎片时间用来看概念,整块时间用来跑代码,这是比较现实的学习节奏。

2. 30 天学习路线总览:拆成四周四阶段

2.1 第一周:Python、NumPy、Pandas 打底

第一周不要贪多,目标只有一个:能用 Python 读一张表格,并且能对列做最基本的筛选、计算、分组。

推荐每天安排:

天数学习内容动手任务
第 1 天Python 基础语法:变量、列表、字典、循环、函数读入一个 CSV 文件并输出前 5 行
第 2 天NumPy 核心:数组、常用统计函数、布尔索引对一个数值序列计算均值、中位数、标准差
第 3 天pandas 核心:DataFrame 与 Series选取列、过滤行、新增计算列
第 4 天pandas 分组聚合:groupby、agg按日期统计每天的销售额
第 5 天pandas 合并与连接:merge、concat模拟订单表和用户表合并
第 6 天数据导入导出:read_csv、read_excel、to_csv处理编码与常见分隔符
第 7 天第一周综合练习用一份杂乱订单表完成一次简单统计

第一周最容易出现的问题是纠结“要不要先学爬虫、学面向对象”。暂时不需要。数据分析入门阶段的 Python,重点是数据处理能力,而不是软件工程能力。能写明白函数和脚本,后续项目就够用了。

2.2 第二周:从“脏数据”到可用数据

这一周学数据清洗与预处理,也就是把脏数据变成能够建模的表。

第二周建议内容:

  • 缺失值识别与处理:删除、填充、插值,分别适用什么场景;
  • 重复值处理:为什么不能无脑 drop_duplicates;
  • 异常值检测:业务阈值、3σ 法、IQR 箱线图法;
  • 数据类型转换:字符串日期转 datetime,数值列中的中文逗号清洗;
  • 文本归一化:大小写、空格、全半角、同义词映射;
  • 最后产出数据质量报告,记录“原始数据多少行、清洗后多少行、为什么删”。

很多学生觉得数据清洗“技术含量低”,这是误解。真实工作里,业务部门给你的表可能包含几十张关联表,每张表都有不同的主键和口径。能在一周内把清洗逻辑梳理清楚,已经具备初级数据分析师的核心基本功。

2.3 第三周:可视化与业务拆解

第三周的任务是学会用图表回答业务问题。

具体拆成三块:

  1. Matplotlib 基础:折线图、柱状图、散点图、直方图、子图布局;
  2. Seaborn 统计绘图:箱线图、热力图、分布图、回归拟合图;
  3. 业务图表组合:趋势图、结构图、对比图、相关性矩阵。

这一周要做的不只是“让图出现”,还要练习看图说话。每画完一张图,强迫自己写三行注释:这张图说明什么,可能的原因是什么,下一步要保留或排查什么。长期来看,这种看图写作能力比画图技巧更值钱。

2.4 第四周:数据挖掘建模与项目输出

第四周从 pandas 过渡到 Scikit-Learn,做一个小而完整的挖掘项目。

建议不碰深度学习,先掌握四类经典任务:

任务类型典型算法业务场景
分类逻辑回归、决策树、随机森林用户是否会流失、订单是否会取消
回归线性回归、决策树回归预测销售额、预测房价
聚类KMeans、层次聚类用户分群、商品分组
关联规则Apriori、FP-Growth推荐搭配、购物篮分析

第四周的项目要覆盖完整链路:定义问题 → 准备数据 → 清洗 → 特征加工 → 建模 → 评估 → 输出结论。成品可以是 Jupyter Notebook,也可以是一份 PDF 分析报告,还可以配一个简单的可视化页面。

3. 环境准备与版本说明

3.1 安装 Python 与 IDE

本系列代码以 Python 3.9 以上版本为主要环境,重点使用 pandas、NumPy、Matplotlib、Seaborn、Plotly、Scikit-Learn。由于不同操作系统和 Python 版本存在差异,建议先创建独立虚拟环境再安装依赖。

如果你完全是新手,最简单的方式是安装 Anaconda。它自带 Python、Jupyter Notebook、Spyder 以及常用的数据科学库。下载安装后,打开 Anaconda Prompt 输入:

python --version

如果能正常显示版本号,说明安装成功。

如果你更习惯用官方 Python,可以按下面的命令创建虚拟环境:

python -m venv data_env source data_env/bin/activate # macOS / Linux data_env\Scripts\activate # Windows

IDE 方面,新手推荐 Jupyter Notebook 或者 Jupyter Lab,逐行执行代码、直接看到图表,学习曲线比较平缓。当项目脚本变多、需要工程化时,再切换到 VS Code 或者 PyCharm 也不迟。

3.2 安装核心依赖库

在虚拟环境或 Anaconda 环境中执行:

pip install pandas numpy matplotlib seaborn plotly scikit-learn

为了让项目可复现,项目根目录建议维护一份requirements.txt

pandas>=1.5.0 numpy>=1.23.0 matplotlib>=3.6.0 seaborn>=0.12.0 plotly>=5.13.0 scikit-learn>=1.2.0 jupyterlab>=3.6.0

版本不建议盲目追求最新。pandas 2.x 已经非常稳定,但有些旧教程里的写法在 2.x 中会发出 FutureWarning。遇到警告时,重点看警告信息里的替代写法,不必感到慌张。

3.3 准备一份示例数据:包含脏数据的电商订单

为了让整个项目可复现,也为了让你看到数据清洗前和清洗后的区别,我会使用一段生成脚本构造一份电商订单数据。这份数据会故意包含以下几种问题:

  • 订单编号重复;
  • 用户 ID 缺失;
  • 销售金额存在负数或缺失;
  • 日期格式混乱,甚至包含无效日期;
  • 商品分类带有空格;
  • 订单状态存在同义不同值。

先创建项目目录:

data_analysis_30days/ ├── data/ │ ├── gen_orders.py │ └── orders.csv ├── data_clean.py ├── eda_plot.py ├── model_train.py └── output/

将下面的脚本保存为data/gen_orders.py

# 文件路径:data/gen_orders.py import pandas as pd import numpy as np np.random.seed(42) user_pool = [f'U{str(i).zfill(4)}' for i in range(1, 401)] categories = ['手机数码', '家用电器', '服饰鞋包', '食品生鲜', '美妆个护'] status_list = ['已完成', '已取消', '待付款'] rows = [] date_range = pd.date_range('2023-01-01', '2023-12-31') for i in range(1, 3001): idx = i % 1000 # 前 100 个用户模拟为高频高金额用户,其余为普通用户 if idx <= 100: amount = round(float(np.random.normal(800, 220)), 2) quantity = int(np.random.randint(1, 6)) else: amount = round(float(np.random.normal(180, 90)), 2) quantity = int(np.random.randint(1, 4)) if amount <= 0: amount = 19.9 date = np.random.choice(date_range) # 故意制造格式混乱:每 3 条中 1 条使用斜杠格式 if i % 3 == 0: date_str = date.strftime('%Y/%m/%d') else: date_str = date.strftime('%Y-%m-%d') # 每隔 997 条制造一个无效日期 if i % 997 == 0: date_str = '2023-13-45' category = np.random.choice(categories) if i % 11 == 0: category = ' ' + category + ' ' status = np.random.choice(status_list, p=[0.78, 0.12, 0.10]) user_id = np.random.choice(user_pool) if i % 37 == 0: user_id = None rows.append({ 'order_id': f'ORD{i:05d}', 'user_id': user_id, 'order_date': date_str, 'category': category, 'amount': amount if i % 41 != 0 else None, 'quantity': quantity if i % 31 != 0 else None, 'status': status if i % 29 != 0 else None, }) # 故意制造完全重复的数据行 dup_rows = rows[:60] rows.extend(dup_rows) df = pd.DataFrame(rows) df.to_csv('data/orders.csv', index=False, encoding='utf-8-sig') print('生成完成,总行数:', len(df))

在项目根目录下执行:

python data/gen_orders.py

执行后得到data/orders.csv。这份数据后续会一直使用,覆盖清洗、可视化、挖掘三个环节。

4. 阶段一:Pandas 数据清洗实战

4.1 先摸清数据状况

数据清洗的第一步不是删数据,而是先看数据。新建data_clean.py,写入:

# 文件路径:data_clean.py import pandas as pd df = pd.read_csv('data/orders.csv') print('原始数据 shape:', df.shape) print('\n前 10 行:') print(df.head(10)) print('\n列名与类型:') print(df.dtypes) print('\n缺失值统计:') print(df.isna().sum()) print('\n重复订单数:', df.duplicated(subset=['order_id']).sum())

运行后你会得到类似下面的输出:

原始数据 shape: (3060, 7) 前 10 行: ... 缺失值统计: ... 重复订单数: 60

这里有几个关键判断点:

  1. amount列是否有空值;
  2. quantity是否为空;
  3. order_date是字符串格式,需要在后续步骤解析;
  4. user_id存在空值,需要决定是删除还是填充为“匿名用户”;
  5. 订单号重复达到 60 条,需要进一步判断是否为重复录入。

很多新人拿到数据后第一件事就是调用dropna()把所有有缺失的行删掉,这是错误的。比如status为空,可能代表了某种异常渠道的订单,直接删除会破坏业务口径。正确做法是先观察每一列缺失的比例和原因,再分列处理。

4.2 重复值、缺失值与异常值处理

接下来编写清洗逻辑。按顺序完成去重、修缺失值、处理异常金额和数量。

# data_clean.py 继续追加 # 1. 去重:订单号作为业务主键 before_count = len(df) df = df.drop_duplicates(subset=['order_id'], keep='first').copy() print(f'去重后行数:{before_count} -> {len(df)}') # 2. user_id 缺失:如果后续要做用户分析,先填为 UNKNOWN df['user_id'] = df['user_id'].fillna('UNKNOWN') # 3. amount 缺失:金额是核心指标,缺失且无法修复,只能删除 df = df.dropna(subset=['amount']).copy() # 4. quantity 缺失:先按 1 处理,或删除;这里按业务经验填 1 df['quantity'] = df['quantity'].fillna(1).astype(int) # 5. 金额异常:不能为负数 print('\n删除前金额非正数数量:', (df['amount'] <= 0).sum()) df = df[df['amount'] > 0].copy() # 6. 数量异常:数量至少 1 df = df[df['quantity'] >= 1].copy()

为什么删除amount为空的行,而不是用均值填充?因为如果你要计算销售额,均值填充会伪造一部分本不存在的交易。对金额类指标,更稳妥的原则是能溯源就溯源,无法溯源且缺失占比较低时,删除比填充更安全。但如果是用于预测模型的特征,且缺失比例较高,需要结合业务决定是否填充。

user_id填成'UNKNOWN'而不是删除,是为了后续做商品分析时能保留这些订单。等到做用户画像时,再单独过滤掉匿名用户即可。这种“不同分析目标采用不同清洗口径”的思路,往往是新手和熟练分析师最大的差距。

4.3 日期、文本与类型统一

继续在data_clean.py中追加:

# 日期解析:把多种格式统一为 pandas 的 datetime 类型 df['order_date_raw'] = df['order_date'] df['order_date'] = pd.to_datetime(df['order_date'], errors='coerce') invalid_date_count = df['order_date'].isna().sum() print('无效日期行数:', invalid_date_count) df = df.dropna(subset=['order_date']).copy() # 分类文本去空格 df['category'] = df['category'].str.strip() # 状态归一化:把同义值合并 status_map = { '已完成': '已完成', '完成': '已完成', '已取消': '已取消', '取消': '已取消', '待付款': '待付款', } df['status'] = df['status'].map(status_map).fillna('未知') # 新增月份字段,方便后文按月分析 df['month'] = df['order_date'].dt.to_period('M').astype(str) # 导出清洗后数据 df.to_csv('data/orders_clean.csv', index=False, encoding='utf-8-sig') print('\n清洗后数据 shape:', df.shape) print('\n订单状态分布:') print(df['status'].value_counts()) print('\n清洗后样例:') print(df.head())

运行后,你应该看到重复订单被去掉、缺失金额被删除、日期全部变成标准格式。这里有两个容易踩坑的细节:

  1. pd.to_datetime(errors='coerce')会把无法解析的“2023-13-45”变成NaTNaT是 pandas 中的缺失时间值,判断时要用isna(),不能用== None
  2. 原始字符串中带空格的“ 手机数码 ”,通过str.strip()清理后,才能在做分组时和“手机数码”落到同一组。

清洗脚本执行完,可以顺手生成一份数据质量报告。不需要写成复杂引擎,直接在控制台打印:原始行数、清洗后行数、重复值数量、缺失值数量、无效日期数量、异常金额数量。这份报告在以后写项目 README 或简历作品集时非常有用。

4.4 分组聚合:把订单明细变成业务指标

订单明细表本身不直接产生业务价值,需要经过聚合变成指标。下面用 pandas 完成几种最常见的聚合:

# data_clean.py 继续追加或单独验证 import pandas as pd df = pd.read_csv('data/orders_clean.csv') # 查看哪些用户下单次数最多 user_order_count = ( df.groupby('user_id')['order_id'] .nunique() .sort_values(ascending=False) ) print('下单次数最高的前 10 个用户:') print(user_order_count.head(10)) # 每个商品分类的销售额 category_sales = ( df.groupby('category')['amount'] .sum() .sort_values(ascending=False) ) print('\n分类销售额:') print(category_sales) # 每月的销售额 monthly_sales = ( df.groupby('month')['amount'] .sum() .sort_index() ) print('\n月度销售额:') print(monthly_sales)

这里区分一下sumnunique的语义。统计订单数时如果用count(),会把同一个用户重复下单的订单行也数进去,如果数据里还有同一个订单编号的重复行,结果就会失真。nunique()计算的是不重复订单编号的数量,更适合统计“订单数量”。

聚合结果就是后续可视化输入。很多可视化图表的背后并不是原始明细表,而是一张聚合后的指标表。

5. 阶段二:数据可视化实战

5.1 先解决中文字体和图片保存问题

新建eda_plot.py,把重用的库和字体设置写在顶部。

# 文件路径:eda_plot.py import os import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import warnings warnings.filterwarnings('ignore') # 设置全局中文字体,不同系统需要微调 plt.rcParams['font.family'] = ['Microsoft YaHei', 'SimHei', 'Noto Sans CJK SC', 'Arial Unicode MS'] plt.rcParams['axes.unicode_minus'] = False os.makedirs('output', exist_ok=True) df = pd.read_csv('data/orders_clean.csv') df['order_date'] = pd.to_datetime(df['order_date']) print('数据加载完成,行数:', df.shape[0])

如果你在 Windows 下没有微软雅黑,或者 Linux 服务器缺少上述字体,图表中文会变成方框。解决办法一个是安装中文字体,另一个是代码里指定一台环境内确实存在的字体名。可以先运行:

import matplotlib.font_manager as fm fonts = [f.name for f in fm.fontManager.ttflist if any(k in f.name for k in ['SimHei', 'YaHei', 'Noto', 'WenQuanYi'])] print(set(fonts))

然后再根据输出结果挑选可用的中文字体。代码里设置了一串备选字体,是为了在不同环境下都尽量能显示中文,不保证所有系统都能命中同一个字体名称,所以理解配置思路比照抄更重要。

5.2 业务问题 1:销售额随时间的趋势

先只看状态为“已完成”的订单。这样统计出来的是真实成交额,不包含已取消和待付款订单。

# eda_plot.py 继续追加 df_ok = df[df['status'] == '已完成'].copy() df_ok['month'] = df_ok['order_date'].dt.to_period('M').astype(str) monthly_sales = ( df_ok.groupby('month')['amount'] .sum() .sort_index() ) # 折线图:月度销售趋势 plt.figure(figsize=(10, 5)) plt.plot(monthly_sales.index, monthly_sales.values, marker='o', linewidth=2) plt.title('月度销售额趋势') plt.xlabel('月份') plt.ylabel('销售额') plt.xticks(rotation=45) plt.grid(True, linestyle='--', alpha=0.4) plt.tight_layout() plt.savefig('output/monthly_sales.png', dpi=150) plt.show()

运行后输出output/monthly_sales.png。看到这张图时可以继续问自己:哪个月异常高,哪个月异常低?是和业务淡旺季有关,还是数据本身存在噪声?这一步训练的是结合业务的读图能力。

如果时间字段是字符串而没有转成datetime,按“月份”聚合时月份排序很容易变成字典序,导致折线图出现不合理的上下跳动。数据清洗阶段已经处理过日期,这里仍然重新to_datetime,是因为 CSV 导出后再读入时,日期会恢复成字符串类型。

5.3 业务问题 2:品类结构与客户贡献

继续用柱状图和 Top 用户图观察结构和分布。

# eda_plot.py 继续追加 # 分类销售额柱状图 category_sales = ( df_ok.groupby('category')['amount'] .sum() .sort_values(ascending=True) ) plt.figure(f

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询