Pandas 入门到实用:数据读取、清洗、合并、聚合与项目流程
Pandas 是 Python 中最常用的数据分析库之一。它适合处理表格数据,例如 CSV、Excel、实验记录、Kaggle 数据集、推荐系统日志和机器学习训练数据。
如果说 NumPy 更像“高效数组计算工具”,那么 Pandas 更像“带行列标签的表格处理工具”。它最适合做数据分析项目的前半段:读取数据、检查质量、清洗字段、构造特征、合并多张表、聚合统计,最后把干净的数据交给模型或可视化工具。
1. Pandas 的核心对象
Pandas 里最重要的是两个对象:
Series:一列数据,类似带索引的一维数组。DataFrame:二维表格,类似 Excel 表或数据库表。
1 | import pandas as pd |
可以这样理解:
1 | DataFrame = 多个 Series 按列拼在一起 |
所以 Pandas 的很多操作,本质是在回答三个问题:
- 我要选哪些行?
- 我要选哪些列?
- 我要对这些行列做什么变换或统计?
2. 读取数据
机器学习项目里最常见的数据入口是 CSV:
1 | df = pd.read_csv("train.csv") |
如果文件是 tab 分隔,例如 .tsv:
1 | df = pd.read_csv("data.tsv", sep="\t") |
如果中文乱码,可以指定编码:
1 | df = pd.read_csv("data.csv", encoding="utf-8") |
有些中文 Windows 文件可能是 gbk:
1 | df = pd.read_csv("data.csv", encoding="gbk") |
读取 Excel:
1 | df = pd.read_excel("data.xlsx", sheet_name="Sheet1") |
读取 JSON:
1 | df = pd.read_json("data.json") |
读取大 CSV 时,可以先只读部分行:
1 | df_sample = pd.read_csv("large.csv", nrows=1000) |
这样能先看字段结构,避免一开始就把大文件全部读进内存。
3. 数据开箱检查
拿到一个 DataFrame 后,不要马上写复杂逻辑。先做基础检查:
1 | df.head() |
这些方法分别回答:
| 方法 | 用途 |
|---|---|
head() |
看前几行,确认数据长什么样 |
tail() |
看后几行,检查尾部是否异常 |
shape |
看行数和列数 |
columns |
看列名 |
info() |
看字段类型、非空数量、内存占用 |
describe() |
看数值列统计信息 |
更实用的检查清单:
1 | df.isna().sum() # 每列缺失值数量 |
如果某个分类字段想看分布:
1 | df["label"].value_counts() |
如果想看比例:
1 | df["label"].value_counts(normalize=True) |
这是分类任务里非常常见的一步,可以快速判断类别是否不平衡。
4. 选择列:单中括号和双中括号
按列名取一列:
1 | df["score"] |
返回的是 Series。
取多列:
1 | df[["name", "score"]] |
返回的是 DataFrame。
即使只取一列,双中括号仍然返回 DataFrame:
1 | df[["score"]] |
这个区别很重要:
1 | type(df["score"]) # pandas.Series |
实际项目里,如果你要传给模型,通常希望保持二维结构,可以用双中括号:
1 | X = df[["age", "score"]] |
5. 选择行:条件筛选
按条件筛选:
1 | high_score = df[df["score"] >= 90] |
多个条件要用 & 或 |,每个条件要加括号:
1 | filtered = df[(df["score"] >= 90) & (df["name"] != "Bob")] |
不要写成:
1 | # 错误示范 |
因为 Pandas 的条件不是单个 True/False,而是一整列 boolean values。
常见筛选写法:
1 | df[df["city"].isin(["Hong Kong", "Shenzhen"])] |
6. loc 和 iloc
loc 按标签选:
1 | df.loc[0, "name"] |
iloc 按位置选:
1 | df.iloc[0, 1] |
简单记忆:
loc看名字。iloc看数字位置。
选择多行多列:
1 | df.loc[0:5, ["name", "score"]] |
如果要修改某些行的值,推荐用 loc:
1 | df.loc[df["score"] < 60, "passed"] = False |
这样比链式赋值更稳。
7. 类型转换
很多 bug 来自字段类型不对。比如数字被读成字符串,日期被读成普通文本。
查看类型:
1 | df.dtypes |
转成数字:
1 | df["score"] = pd.to_numeric(df["score"], errors="coerce") |
errors="coerce" 表示无法转换的值变成 NaN。
转成字符串:
1 | df["text"] = df["text"].astype(str) |
转成日期:
1 | df["date"] = pd.to_datetime(df["date"], errors="coerce") |
日期转好后,可以提取年月日:
1 | df["year"] = df["date"].dt.year |
这在日志分析、交易数据、用户行为数据里非常常用。
8. 缺失值处理
查看缺失值:
1 | df.isna().sum() |
查看缺失比例:
1 | df.isna().mean().sort_values(ascending=False) |
填充缺失值:
1 | df["score"] = df["score"].fillna(0) |
用均值填充:
1 | df["score"] = df["score"].fillna(df["score"].mean()) |
用众数填充分类字段:
1 | df["city"] = df["city"].fillna(df["city"].mode()[0]) |
删除缺失行:
1 | df = df.dropna() |
只根据某些关键列删除:
1 | df = df.dropna(subset=["text", "label"]) |
实用经验:
- 标签列缺失,通常直接删除。
- 文本列缺失,通常删除或填空字符串。
- 数值特征缺失,可以用均值、中位数、业务默认值填充。
- 缺失本身可能有信息时,可以新增一列记录是否缺失。
1 | df["score_missing"] = df["score"].isna() |
9. 重复值和异常值
检查重复行:
1 | df.duplicated().sum() |
删除完全重复的行:
1 | df = df.drop_duplicates() |
按某些列去重:
1 | df = df.drop_duplicates(subset=["user_id", "item_id"]) |
异常值可以先用 describe() 粗看:
1 | df["score"].describe() |
也可以看分位数:
1 | df["score"].quantile([0.01, 0.05, 0.5, 0.95, 0.99]) |
如果发现年龄为 999、价格为负数、评分超过上限,就要回到业务含义判断是删除、截断还是修正。
10. 新增列和 apply
如果列之间有计算关系,可以直接生成新列:
1 | df["passed"] = df["score"] >= 60 |
简单运算尽量用向量化写法:
1 | df["score_10"] = df["score"] / 10 |
不要写 for loop:
1 | # 不推荐 |
复杂逻辑可以用 apply:
1 | def grade(score): |
如果要按行读取多个列:
1 | def combine_name(row): |
但要注意:apply(axis=1) 在大数据上可能慢。能用向量化、np.where、map、replace 的时候,优先不用逐行 apply。
11. 字符串处理
NLP 和日志分析里,字符串处理非常常见。
Pandas 的字符串方法通常通过 .str 调用:
1 | df["text"] = df["text"].astype(str) |
去掉前后空格:
1 | df["text"] = df["text"].str.strip() |
判断是否包含关键词:
1 | df[df["text"].str.contains("spark", case=False, na=False)] |
替换文本:
1 | df["text"] = df["text"].str.replace(r"\s+", " ", regex=True) |
拆分:
1 | df["tokens"] = df["text"].str.split() |
如果是情感分析数据,常见格式是:
1 | text,label |
可以这样读取:
1 | df = pd.read_csv("sentiment.csv") |
12. 排序、排名和抽样
排序:
1 | df.sort_values("score", ascending=False) |
按多个字段排序:
1 | df.sort_values(["class", "score"], ascending=[True, False]) |
取前几行:
1 | df.nlargest(10, "score") |
随机抽样:
1 | df_sample = df.sample(n=100, random_state=42) |
按比例抽样:
1 | df_sample = df.sample(frac=0.1, random_state=42) |
random_state 可以保证每次抽样结果一致,方便复现实验。
13. merge:合并多张表
真实项目里,数据通常不在一张表里。例如:
- 用户表:
user_id, age, gender - 物品表:
item_id, category, price - 行为表:
user_id, item_id, rating
用 merge 合并:
1 | merged = pd.merge( |
常见 join 类型:
| join 类型 | 含义 |
|---|---|
inner |
只保留两边都匹配的行 |
left |
保留左表全部行,右表匹配不到填 NaN |
right |
保留右表全部行,左表匹配不到填 NaN |
outer |
左右两边全部保留,匹配不到填 NaN |
如果左右表的 key 名字不同:
1 | pd.merge( |
merge 后一定要检查行数:
1 | print(df1.shape) |
如果行数突然暴涨,可能是 key 不唯一导致 many-to-many join。
14. groupby:从明细到统计
groupby 是 Pandas 里最实用的功能之一。
基本模式:
1 | df.groupby("label").size() |
按类别求平均:
1 | df.groupby("label")["score"].mean() |
多个聚合:
1 | summary = df.groupby("label").agg( |
按多个字段分组:
1 | df.groupby(["gender", "label"])["score"].mean().reset_index() |
推荐系统里常见问题:计算每部电影的平均评分。
1 | movie_rating = ( |
实用提醒:只看平均分可能会误导。如果一部电影只有 1 个评分且是 5 分,它会排很高。所以通常要加评分数量门槛:
1 | movie_rating = movie_rating[movie_rating["rating_count"] >= 20] |
15. pivot_table:做交叉统计
pivot_table 可以做类似 Excel 透视表的统计。
例如按性别和标签统计平均分:
1 | table = pd.pivot_table( |
如果想统计数量:
1 | table = pd.pivot_table( |
这在做 EDA 时很好用,可以快速看不同群体之间的差异。
16. 时间序列基础
如果有时间字段,先转成 datetime:
1 | df["timestamp"] = pd.to_datetime(df["timestamp"], errors="coerce") |
按日期统计数量:
1 | daily_count = ( |
按月统计:
1 | monthly_count = ( |
如果是用户行为日志,这些操作可以用来观察活跃趋势、季节性和异常峰值。
17. 链式写法:让清洗流程更清楚
简单清洗可以写成链式:
1 | clean_df = ( |
优点是每一步都清楚,适合写成可复现的数据处理流程。
如果步骤太复杂,可以拆成多个函数:
1 | def clean_text_columns(df): |
pipe 适合把数据清洗流程模块化。
18. 保存结果
保存 CSV:
1 | df.to_csv("output.csv", index=False) |
index=False 很常用,表示不要把 DataFrame 的行索引额外保存成一列。
保存 Excel:
1 | df.to_excel("output.xlsx", index=False) |
保存 Parquet:
1 | df.to_parquet("output.parquet", index=False) |
Parquet 比 CSV 更适合大数据和机器学习中间结果,因为它保留列类型,读取速度也通常更快。
19. 和机器学习的关系
Pandas 经常用在机器学习流程的前半段:
- 读取原始数据。
- 查看缺失值、重复值和异常值。
- 清洗文本或数值。
- 合并多张表。
- 构造特征。
- 划分训练集和测试集。
- 保存训练数据或预测结果。
例如一个简单的 NLP 分类数据:
1 | df = pd.read_csv("sentiment.csv") |
再交给 scikit-learn 或 PyTorch:
1 | from sklearn.model_selection import train_test_split |
stratify=df["label"] 可以尽量保持训练集和测试集类别比例一致。
20. 性能和常见坑
不要在大 DataFrame 上频繁 for loop。
优先使用向量化、groupby、merge、map、replace。
避免链式赋值。
不要写:
1 | df[df["score"] > 90]["grade"] = "A" |
推荐写:
1 | df.loc[df["score"] > 90, "grade"] = "A" |
注意 copy 和 view。
如果从原 DataFrame 切出一部分后要修改,可以明确 .copy():
1 | sub_df = df[df["score"] > 90].copy() |
大文件先读样本。
1 | sample = pd.read_csv("large.csv", nrows=1000) |
合适时指定 dtype。
1 | df = pd.read_csv("data.csv", dtype={"user_id": "string"}) |
ID 字段不一定要读成数字,尤其是有前导 0 的 ID。
21. 一个实用项目模板
以后做数据分析或机器学习项目,可以按这个模板走:
1 | import pandas as pd |
如果有多张表:
1 | users = pd.read_csv("users.csv") |
如果要做 groupby 特征:
1 | user_features = ( |
这就是很多推荐系统、用户画像、数据挖掘项目的雏形。
22. 小结
Pandas 初学阶段要掌握:
read_csvhead/info/describe- 选列和条件筛选
loc/iloc- 类型转换
- 缺失值处理
- 字符串处理
- 新增列
mergegroupbypivot_tableto_csv
更进一步,要形成项目意识:每次拿到数据,先检查质量,再清洗,再构造特征,再保存可复现结果。
后面学 Dask 和 Spark 时,你会发现很多概念都来自 Pandas:DataFrame、filter、select、groupby、join。Pandas 学扎实了,大数据工具就不会显得那么陌生。
Pandas 入门到实用:数据读取、清洗、合并、聚合与项目流程