为什么数据分析绕不开 pandas

拿到一份 CSV 或者数据库导出的表,很多人的第一反应是用 Excel 打开、拖拖拽拽做个透视表。数据量小的时候这完全没问题,但一旦行数超过十万、或者要把同一段分析重复跑十几遍,Excel 就开始卡顿甚至崩溃。pandas 就是 Python 生态里替代这一切的工具:用代码描述你的分析过程,可复现、可批量、可版本管理。

它的名字来自"面板数据"(panel data),核心能力是让你像操作表格一样操作数据:选列、过滤、排序、分组、汇总、合并,每一步都有对应的一行代码,而不是鼠标点来点去。更重要的是,它和 NumPy、Matplotlib、scikit-learn 无缝衔接,是从"数据处理"走向"机器学习"的必经之路。

写 pandas 的核心心法:把每一步操作都当成一条声明式指令——"我要哪几列、按什么条件过滤、按什么分组、聚合出什么指标",而不是写循环逐行处理。
本文核心知识点
  • DataFrame带行列标签的二维表格,是 pandas 最核心的数据结构。
  • 数据清洗处理缺失值、重复行、类型错误,是分析前的必经工序。
  • groupby拆分、应用、合并三步法,是分组聚合的标准套路。
  • 透视表一行代码做出 Excel 数据透视表的效果,还能多层嵌套。
pandas 数据分析示意:蓝色渐变背景上的数据表格网格向上生长出柱状图与折线图,旁边漂浮数据库圆柱体与半透明仪表盘面板
从一张原始表到一张结论图:pandas 负责中间所有的清洗、聚合与变形。

Series 与 DataFrame:pandas 的两块积木

pandas 只有两个核心数据结构。Series 是带标签的一维数组,相当于 Excel 里的一列;DataFrame 是带行列标签的二维表格,相当于整个工作表。你可以把 DataFrame 想象成一堆 Series 按列拼起来,每一列有自己的名字和数据类型。

import pandas as pd

# 从字典创建一个 DataFrame
df = pd.DataFrame({
    "name": ["张三", "李四", "王五", "赵六"],
    "age":  [28, 34, 22, 41],
    "city": ["北京", "上海", "广州", "北京"],
    "salary": [15000, 22000, 9000, 30000],
})

print(df.head())        # 看前 5 行
print(df.dtypes)        # 每列的数据类型
print(df.shape)         # (4, 4) 行数列数

操作 DataFrame 最常用的三种方式:

  • 选列:df["salary"] 返回一个 Series;df[["name", "salary"]] 返回一个新 DataFrame。
  • 过滤行:df[df["age"] > 30],条件表达式放在方括号里,pandas 会自动选出满足条件的行。
  • 新增列:df["annual"] = df["salary"] * 12,直接赋值就会加一列。

注意 pandas 的布尔索引用 & 和 |,不是 Python 的 and 和 or,而且每个条件必须用括号包起来。这是新手最常见的语法错误。

数据读取与初步探查

真实项目里,数据很少是手写字典来的,大多来自 CSV、Excel 或数据库。pandas 提供了 read_csv、read_excel、read_sql 等一系列读取函数,一行就能把外部文件变成 DataFrame。

# 读取 CSV,指定编码和分隔符
df = pd.read_csv("orders.csv", encoding="utf-8", parse_dates=["order_date"])

# 读取 Excel,指定 sheet
df = pd.read_excel("report.xlsx", sheet_name="销售明细")

# 初步探查三板斧
print(df.head(3))          # 前 3 行长什么样
print(df.info())           # 每列非空数量、类型、内存占用
print(df.describe())       # 数值列的 count / mean / std / min / max / 分位数

拿到一份陌生数据,养成先跑这三板斧的习惯:head 看长什么样,info 看有没有缺失和类型问题,describe 看数值分布是否合理。比如订单金额列的最小值是负数、或者某列 90% 都是空值,这些问题在这一步就会暴露出来,而不是分析到一半才发现。

探查方法看什么常见发现
df.head(n)前 n 行数据样例列名是否正确、有没有错位
df.info()每列非空数与类型缺失率、被识别成 object 的数值列
df.describe()数值列统计分布异常值、量级是否合理
df["col"].value_counts()某列取值频次分类是否有拼写不一致

数据清洗:缺失值、重复值与类型转换

真实数据从来不干净。电商导出的表里,可能有几行缺了用户 ID、有重复订单、日期列被识别成了字符串。分析之前必须先清洗,否则后面算出来的指标全是错的。

# 1. 缺失值处理
df.isna().sum()                    # 每列缺失多少个
df = df.dropna(subset=["user_id"]) # 关键字段缺失的行直接丢
df["city"] = df["city"].fillna("未知")  # 分类缺失填充默认值

# 2. 重复值处理
df.duplicated().sum()              # 有多少重复行
df = df.drop_duplicates()          # 全列重复才删
df = df.drop_duplicates(subset=["order_id"])  # 按订单号去重

# 3. 类型转换
df["price"] = df["price"].astype(float)       # 字符串转数值
df["order_date"] = pd.to_datetime(df["order_date"])  # 转日期

清洗的原则是先理解、再处理:缺失值不是越多越坏,得先看缺失是不是有规律——比如"用户没填手机号"本身就是一个信号。删行和填充都要有理由,不能见到空值就一刀切。

  • 删行:关键字段缺失、且占比很小(<5%)时用。
  • 填充:数值列用中位数(抗极端值),分类列用众数或"未知"。
  • 保留标记:重要的缺失可以加一列布尔值"是否缺失",告诉模型这一行本来就缺。

分组聚合:groupby 三步走

分组聚合是数据分析里用得最多的操作:"按城市统计平均工资"、"按月看订单总量"、"按用户算消费频次"——这些都是 groupby 的事。它的套路是固定的三步:拆分(split)→ 应用(apply)→ 合并(combine)。

# 按城市分组,算每个城市的平均工资和人数
result = df.groupby("city")["salary"].agg(["mean", "count"])
print(result)

# 按多列分组:先按城市、再按年龄档
df["age_group"] = pd.cut(df["age"], bins=[0, 25, 35, 50], labels=["青年", "中年", "资深"])
result2 = df.groupby(["city", "age_group"])["salary"].mean().unstack()
print(result2)

agg 可以一次传多个聚合函数,也可以对不同列用不同的聚合方式:

agg_result = df.groupby("city").agg(
    avg_salary=("salary", "mean"),
    total_salary=("salary", "sum"),
    user_count=("name", "count"),
    max_age=("age", "max"),
)
print(agg_result)

这种命名聚合(named aggregation)是 pandas 0.25 之后的写法,可读性远好于字典传参。unstack() 则把多层行索引展开成列,结果从长表变成宽表,直接就能画热力图或者导出 Excel。