Pandas 数据处理进阶:缺失值、合并、分组聚合与透视表
Pandas 数据处理进阶:缺失值、合并、分组聚合与透视表
在完成 pandas 的基础操作(索引、筛选、赋值、函数应用)之后,下一步便是处理真实数据中常见的问题:缺失值、多表合并、分组统计以及数据透视。本文带你系统掌握这些核心技能,并提供可直接运行的代码示例。
目录
- 数据清洗:缺失值处理
- 1.1 检测缺失值
- 1.2 删除缺失值
- 1.3 填充缺失值
- 1.4 自定义替换为 NaN
- 数据合并:concat 与 merge
- 2.1 concat:轴向拼接
- 2.2 merge:键值关联
- 2.3 join:基于索引的合并
- 分组与聚合:groupby 的威力
- 3.1 基础分组
- 3.2 多列分组
- 3.3 聚合函数 agg
- 3.4 过滤与变换
- 透视表与交叉表
- 4.1 交叉表 crosstab:频数统计
- 4.2 透视表 pivot_table:灵活聚合
- 4.3 多级透视
- 综合实战:电商订单数据分析
- 小结与进阶建议
1. 数据清洗:缺失值处理
真实数据往往不完整,pandas 提供了丰富的缺失值处理工具。
1.1 检测缺失值
isna()/isnull():返回布尔型 DataFrame,True 表示缺失。isna().any(axis=?):检查每列/行是否有缺失。isna().sum():统计每列缺失数量。
importpandasaspdimportnumpyasnp df=pd.DataFrame({'A':[1,2,np.nan,4],'B':[5,np.nan,np.nan,8],'C':[9,10,11,12]})print(df.isna())print(df.isna().any())# 每列是否有缺失print(df.isna().sum())# 每列缺失个数1.2 删除缺失值:dropna
# 删除任何含有缺失值的行df_clean=df.dropna()# 删除任何含有缺失值的列df_clean=df.dropna(axis=1)# 仅当某列全部缺失时才删除df_clean=df.dropna(how='all')# 指定 subset:仅检查特定列df_clean=df.dropna(subset=['A','B'])1.3 填充缺失值:fillna
# 用常数填充df_filled=df.fillna(0)# 用前一个值填充(向前填充)df_filled=df.fillna(method='ffill')# 用后一个值填充df_filled=df.fillna(method='bfill')# 针对不同列用不同值df_filled=df.fillna({'A':0,'B':df['B'].mean()})1.4 自定义替换为 NaN
某些数据中,特殊值(如"N/A"、-1、0)应视为缺失。
df=df.replace({'N/A':np.nan,-1:np.nan,0:np.nan})# 或原地修改df.replace({'N/A':np.nan,0:np.nan},inplace=True)2. 数据合并:concat 与 merge
2.1concat:轴向拼接
axis=0:纵向拼接(上下堆叠),要求列名一致。axis=1:横向拼接(左右并排),要求行索引对齐。ignore_index=True:重置索引。
df1=pd.DataFrame({'A':[1,2],'B':[3,4]})df2=pd.DataFrame({'A':[5,6],'B':[7,8]})# 纵向拼接df_vertical=pd.concat([df1,df2],axis=0,ignore_index=True)# 横向拼接df_horizontal=pd.concat([df1,df2],axis=1)2.2merge:键值关联(类似 SQL JOIN)
left=pd.DataFrame({'key':['X','Y','Z'],'value_left':[1,2,3]})right=pd.DataFrame({'key':['X','Y','W'],'value_right':[4,5,6]})# 内连接(默认)inner=pd.merge(left,right,on='key',how='inner')# 左连接left_join=pd.merge(left,right,on='key',how='left')# 右连接right_join=pd.merge(left,right,on='key',how='right')# 外连接(全连接)outer=pd.merge(left,right,on='key',how='outer')# 多列关联:on=['col1', 'col2']# 处理重复列名:suffixes=('_x', '_y')2.3join:基于索引的合并
left=pd.DataFrame({'A':[1,2]},index=['a','b'])right=pd.DataFrame({'B':[3,4]},index=['a','c'])result=left.join(right,how='left')# 默认左连接,基于索引3. 分组与聚合:groupby 的威力
分组聚合是数据分析的核心范式:split-apply-combine。
3.1 单字段分组
df=pd.DataFrame({'类别':['A','A','B','B','C'],'销售额':[100,150,200,250,300],'成本':[60,80,120,140,180]})grouped=df.groupby('类别')print(grouped['销售额'].mean())# 每类平均销售额print(grouped['销售额'].sum())3.2 多字段分组
df['城市']=['北京','上海','北京','上海','北京']grouped_multi=df.groupby(['类别','城市'])print(grouped_multi['销售额'].sum())3.3 聚合函数agg
- 单列单函数:
.agg({'列名': 'mean'}) - 单列多函数:
.agg({'销售额': ['sum', 'mean', 'count']}) - 多列不同函数:
.agg({'销售额': 'sum', '成本': 'mean'}) - 自定义函数:
.agg(lambda x: x.max() - x.min())
result=df.groupby('类别').agg({'销售额':['sum','mean'],'成本':'min'})print(result)3.4 过滤与变换
filter:根据分组条件过滤组(保留满足条件的整个组)。transform:将聚合结果广播回原始行,常用于添加组内统计列。
# 保留销售额总和大于 400 的组filtered=df.groupby('类别').filter(lambdax:x['销售额'].sum()>400)# 添加组内平均值列df['销售额_组内均指']=df.groupby('类别')['销售额'].transform('mean')4. 透视表与交叉表
4.1 交叉表crosstab:频数统计
pd.crosstab用于计算两个(或多个)分类变量的频数分布。
df=pd.DataFrame({'性别':['男','女','男','女','男'],'城市':['北京','上海','北京','北京','上海'],'购买次数':[1,3,2,1,4]})# 性别 vs 城市的频数表ct=pd.crosstab(df['性别'],df['城市'])print(ct)# 添加行/列总计ct_margins=pd.crosstab(df['性别'],df['城市'],margins=True,margins_name='总计')4.2 透视表pivot_table:灵活聚合
类似 Excel 数据透视表,可指定行、列、值、聚合函数。
# 按性别和城市,统计购买次数的平均值pt=pd.pivot_table(df,values='购买次数',index='性别',columns='城市',aggfunc='mean')print(pt)# 多个聚合函数pt_multi=pd.pivot_table(df,values='购买次数',index='性别',columns='城市',aggfunc=['sum','count'])4.3 多级 index / 多 values
# 多级行索引pt_levels=pd.pivot_table(df,values='购买次数',index=['性别','城市'],aggfunc='sum')# 多 values 列pt_multi_values=pd.pivot_table(df,values=['购买次数','性别'],index='城市',aggfunc='count')5. 综合实战:电商订单数据分析
模拟一个电商订单数据集,完成从清洗到聚合的全流程。
importpandasaspdimportnumpyasnp# 创建订单数据orders=pd.DataFrame({'order_id':range(1,11),'user_id':[101,102,101,103,104,101,102,105,103,106],'category':['电子产品','服装','电子产品','食品','服装','电子产品','服装','食品','食品','电子产品'],'amount':[299,89,450,35,120,310,150,45,60,520],'discount':[0.1,0.0,0.15,0.0,0.05,0.1,0.0,0.0,0.05,0.2]})# 故意引入一个缺失值orders.loc[5,'amount']=np.nanprint("原始数据:")print(orders)# 1. 缺失值处理:用该品类平均金额填充category_avg=orders.groupby('category')['amount'].transform('mean')orders['amount'].fillna(category_avg,inplace=True)# 2. 计算实际支付金额(金额 * (1 - 折扣))orders['paid']=orders['amount']*(1-orders['discount'])# 3. 分组聚合:每用户的总支付金额和订单数user_stats=orders.groupby('user_id').agg(总支付=('paid','sum'),订单数=('order_id','count')).reset_index()print("\n用户统计:")print(user_stats)# 4. 透视表:各类别在不同折扣区间的平均支付金额orders['discount_bin']=pd.cut(orders['discount'],bins=[-0.01,0.05,0.15,0.21],labels=['低折扣','中折扣','高折扣'])pt=pd.pivot_table(orders,values='paid',index='category',columns='discount_bin',aggfunc='mean')print("\n透视表(品类×折扣区间 平均支付):")print(pt)# 5. 交叉表:用户 vs 品类购买频数ct=pd.crosstab(orders['user_id'],orders['category'])print("\n用户购买品类频次:")print(ct)6. 小结与进阶建议
本文系统介绍了 pandas 中四个核心进阶功能:
| 功能 | 核心方法 | 典型场景 |
|---|---|---|
| 缺失值处理 | isna(),dropna(),fillna() | 数据清洗 |
| 数据合并 | concat(),merge(),join() | 多表关联 |
| 分组聚合 | groupby(),agg(),transform(),filter() | 统计分析 |
| 透视表/交叉表 | pivot_table(),crosstab() | 多维汇总 |
经验法则:
- 处理缺失时,优先分析缺失原因,合理填充或删除。
- 合并数据前确保关联键的数据类型一致。
- 分组聚合时使用
agg一次完成多个统计,代码更清晰。 - 透视表是快速生成报表的利器,尤其是多维度交叉分析。
进阶方向:
- 时间序列数据的重采样(
resample) - 窗口函数(
rolling,expanding) - 性能优化:使用
eval()和query()处理大数据 - 结合
matplotlib/seaborn做可视化分析
建议读者将本文代码逐一运行,并尝试修改参数观察结果。掌握这些技能,你就能应对绝大多数数据处理需求。
