一、真实问题:Excel搞不定的百万行数据
上个月转岗做数据分析,第一个任务:把部门半年来的销售数据(12个CSV,合计380万行)合并分析,统计各区域周销量趋势。我一开始用Excel的Power Query+VLOOKUP,结果电脑卡死3次,一个数据透视表就要等5分钟。折腾一整天只跑出1/4的数据。
工位旁边的老同事说:“用Python吧,pandas读这玩意儿秒开。” 我半信半疑装了个Anaconda,三天后,同样的数据,清洗+合并+画图+预测总耗时47秒。本文就是这三天踩坑总结的路线图。
二、方案对比:Excel vs Python vs 其他工具
2.1 处理100万行数据的耗时对比
测试环境:i7-10750H,16GB RAM,Windows 11,Excel 2021,Python 3.11.5 (Anaconda),pandas 2.1.4。
| 操作 | Excel 2021 | Python (pandas) | Python (polars) |
|---|---|---|---|
| 读取100万行CSV | 18.3秒 | 0.9秒 | 0.4秒 |
| 分组聚合(Sum) | 6.2秒 | 0.3秒 | 0.1秒 |
| 列计算(新列) | 3.8秒(公式拖拽) | 0.05秒 | 0.02秒 |
| 保存为CSV | 12.1秒 | 1.1秒 | 0.6秒 |
结论:对于超过10万行的数据,Python完胜Excel。而polars虽更快,但入门门槛略高。作为3天速成,pandas足够。
2.2 开发效率对比:Jupyter Notebook vs 终端脚本
刚开始学,建议用 Jupyter Notebook(Python 3内核),因为可以逐段运行,出错马上看见,方便调试。但在生产环境或处理超大数据时,用 .py 脚本执行更稳定。我第一天用Jupyter,第二天就把代码转成脚本了。
三、完整代码实现(3天路线)
Day 1:环境搭建 + Pandas 基础
版本号:Python 3.11.5,pandas 2.1.4,numpy 1.26.2,matplotlib 3.8.2。
安装命令(bash):
# 推荐直接装Anaconda,自带上述所有库
wget https://repo.anaconda.com/archive/Anaconda3-2023.09-0-Linux-x86_64.sh
bash Anaconda3-2023.09-0-Linux-x86_64.sh
# 或者用pip(已有Python)
pip install pandas numpy matplotlib scikit-learn jupyter
第一个程序:读取CSV并查看结构
import pandas as pd
import numpy as np
# 读取前100行测试编码
df = pd.read_csv('sales_2024.csv', nrows=100, encoding='utf-8')
print(df.head())
print(df.info()) # 列名、非空计数、数据类型
print(df.describe()) # 数值列统计摘要
关键坑:编码问题。如果遇到 UnicodeDecodeError,尝试 encoding='gbk' 或 encoding='utf-8-sig'。
Day 2:数据清洗与可视化
真实场景:客户上传的CSV中,有重复行、缺失值、日期格式不一致、金额带¥符号。
代码:
import pandas as pd
import matplotlib.pyplot as plt
# 读取原始数据
df = pd.read_csv('sales_raw.csv', encoding='utf-8')
print(f"原始行数:{len(df)}")
# 1. 去除完全重复行
df.drop_duplicates(inplace=True)
print(f"去重后行数:{len(df)}")
# 2. 处理缺失值:数值列用中位数填充,类别列用众数
numeric_cols = ['price', 'quantity', 'amount']
for col in numeric_cols:
median_val = df[col].median()
df[col].fillna(median_val, inplace=True)
cate_cols = ['region', 'product']
for col in cate_cols:
mode_val = df[col].mode()[0]
df[col].fillna(mode_val, inplace=True)
# 3. 处理金额列:去掉¥符号,转为浮点数
df['amount'] = df['amount'].str.replace('¥', '', regex=False).astype(float)
# 4. 日期格式统一
df['date'] = pd.to_datetime(df['date'], errors='coerce')
# 删除无法解析的日期行
df.dropna(subset=['date'], inplace=True)
# 5. 提取月份用于分组
df['month'] = df['date'].dt.month
# 6. 可视化:各产品月销量趋势
product_group = df.groupby(['product', 'month'])['quantity'].sum().unstack(0)
product_group.plot(figsize=(12,6), marker='o')
plt.title('各产品月销量趋势')
plt.xlabel('月份')
plt.ylabel('销量')
plt.grid(True)
plt.savefig('product_sales_trend.png', dpi=150)
plt.show()
Day 3:数据分析实战 + 简单模型
场景:利用前5个月数据预测第6个月销量,用线性回归。
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
import matplotlib.pyplot as plt
# 按月份聚合总销量
monthly = df.groupby('month')['quantity'].sum().reset_index()
X = monthly[['month']].values # 月份作为特征
y = monthly['quantity'].values
# 划分训练集(1-4月)和测试集(5月)
X_train, X_test = X[:4], X[4:]
y_train, y_test = y[:4], y[4:]
# 训练模型
model = LinearRegression()
model.fit(X_train, y_train)
# 预测第6个月(月份=6)
pred_month6 = model.predict([[6]])
print(f"预测第6个月销量:{pred_month6[0]:.0f}")
# 评估
y_pred = model.predict(X_test)
mae = mean_absolute_error(y_test, y_pred)
print(f"5月份预测MAE:{mae:.2f}")
# 可视化拟合效果
plt.scatter(X_train, y_train, label='训练数据')
plt.scatter(X_test, y_test, color='red', label='测试数据')
plt.plot(np.arange(1,7), model.predict(np.arange(1,7).reshape(-1,1)), '--', label='拟合线')
plt.xlabel('月份')
plt.ylabel('销量')
plt.legend()
plt.savefig('linear_fit.png')
plt.show()
四、效果数据:3天后的产出
以上代码全部应用在380万行销售数据上,结果如下:
| 步骤 | 耗时(秒) | 备注 |
|---|---|---|
| 读取12个CSV并合并 | 3.2 | 使用concat |
| 去重、填充、转换 | 2.8 | 包含日期解析 |
| 分组聚合(周销量) | 1.4 | groupby + resample |
| 画趋势图(4张) | 5.1 | matplotlib |
| 训练线性回归模型 | 0.6 | 仅用5个数据点 |
| 保存结果为Excel | 4.3 | to_excel,包含格式 |
总耗时:约17.4秒(不含交互操作),而Excel做同样事情至少需要重复操作30分钟以上(且数据量越大越慢)。
五、避坑指南(我踩过的5个坑)
5.1 编码问题导致乱码或报错
国内CSV常用GBK,但macOS导出可能是UTF-8 BOM。解决方案:先用 chardet 检测编码,再读取。
import chardet
with open('file.csv', 'rb') as f:
result = chardet.detect(f.read(10000))
encoding = result['encoding'] # 比如 'GB2312'
df = pd.read_csv('file.csv', encoding=encoding)
5.2 内存溢出:读大文件时别一次全读
若CSV超过1GB,用 chunksize 分批处理。
chunk_list = []
for chunk in pd.read_csv('huge.csv', chunksize=50000, encoding='utf-8'):
# 对chunk做清洗
chunk_list.append(chunk)
df = pd.concat(chunk_list)
5.3 SettingWithCopyWarning
你对dataframe切片后再赋值,pandas会警告。解决方法:用 .loc 或 .copy()。
# 错误写法
sub_df = df[df['price'] > 100]
sub_df['price'] = sub_df['price'] * 0.9 # 警告
# 正确写法1
df.loc[df['price'] > 100, 'price'] *= 0.9
# 正确写法2
sub_df = df[df['price'] > 100].copy()
sub_df['price'] *= 0.9
5.4 inplace=True陷阱
df.dropna(inplace=True) 返回 None,如果链式调用会报错。推荐用赋值方式:df = df.dropna()。
5.5 sklearn版本兼容
老代码用 sklearn.cross_validation,新版本已移到 sklearn.model_selection。安装时指定版本:pip install scikit-learn==1.3.2。
六、扩展:第三天还能做什么?
如果时间富余,可以学习以下技巧:
- 用 pandas-profiling 快速生成数据报告(一行代码出HTML)
- 用 matplotlib 调整图表样式(颜色、字体、图例)
- 用 to_excel 写出带格式的Excel(比如自动列宽)
避坑:pandas-profiling 处理大文件会很慢,建议先抽样。安装命令:
pip install pandas-profiling==3.6.6
from pandas_profiling import ProfileReport
sample = df.sample(frac=0.1, random_state=42)
report = ProfileReport(sample, minimal=True)
report.to_file("quick_report.html")
最终建议:别在理论书上浪费三天。直接拿真实数据跑一遍上面的代码,遇到问题去 Stack Overflow 查。三周后,你就可以用Python做完整的数据分析流水线了。
<<>>