在实际的数据处理工作中,我们经常会拿到结构松散的多行多列数据,比如同一用户的多条行为记录分散在不同行,或者同一产品的多个属性分散在不同列,这时候就需要将这些数据合并成单行,方便后续的统计分析或者入库存储。Pandas作为Python生态中最常用的数据处理库,提供了多种实现这类需求的方法,下面我们逐一介绍。
方法一:使用groupby配合聚合函数拼接
如果数据是按照某个分组键分散在多行,需要将同一分组下的多列数据合并到单行,最常用的是groupby加聚合函数的方式。比如我们有一个用户订单数据,每个用户有多条订单记录,现在要把同一用户的所有订单编号和订单金额合并到一行。
先构造示例数据:
import pandas as pd
# 构造示例数据
data = {
'user_id': [1, 1, 2, 2, 3],
'order_id': ['A001', 'A002', 'B001', 'B002', 'C001'],
'amount': [100, 200, 150, 250, 300]
}
df = pd.DataFrame(data)
print(df)
运行后会得到如下数据:
user_id order_id amount 0 1 A001 100 1 1 A002 200 2 2 B001 150 3 2 B002 250 4 3 C001 300
现在要把同一user_id的order_id和amount合并成单行,使用groupby配合agg函数即可:
# 按user_id分组,拼接order_id和amount
result = df.groupby('user_id').agg({
'order_id': lambda x: ','.join(x),
'amount': lambda x: ','.join(map(str, x))
}).reset_index()
print(result)
输出结果如下,每个用户的所有订单信息都合并到了单行:
user_id order_id amount 0 1 A001,A002 100,200 1 2 B001,B002 150,250 2 3 C001 300
方法二:使用pivot_table透视表转换
如果数据的多列是同一属性的不同取值,比如不同月份的销售数据分散在不同列,需要合并到单行,可以使用pivot_table方法。比如我们有如下按月份记录的销售数据:
# 构造月份销售数据
sales_data = {
'product': ['苹果', '苹果', '香蕉', '香蕉'],
'month': ['1月', '2月', '1月', '2月'],
'sales': [500, 600, 300, 400]
}
sales_df = pd.DataFrame(sales_data)
print(sales_df)
原始数据如下:
product month sales 0 苹果 1月 500 1 苹果 2月 600 2 香蕉 1月 300 3 香蕉 2月 400
使用pivot_table将月份转为列,合并为单行:
# 透视转换,将month作为列,sales作为值 pivot_result = sales_df.pivot_table(index='product', columns='month', values='sales', aggfunc='sum').reset_index() print(pivot_result)
转换后的结果,每个产品的不同月份销售数据都在同一行:
month product 1月 2月 0 苹果 500 600 1 香蕉 300 400
方法三:使用stack和unstack组合操作
对于结构更复杂的数据,比如多行多列都是需要合并的属性,可以使用stack先将列转为行,处理后再用unstack转回列。比如我们有学生多科目的多次考试成绩,需要合并为单行:
# 构造学生成绩数据
score_data = {
'student': ['张三', '张三', '李四', '李四'],
'subject': ['语文', '数学', '语文', '数学'],
'score': [90, 95, 85, 88]
}
score_df = pd.DataFrame(score_data)
print(score_df)
原始成绩数据:
student subject score 0 张三 语文 90 1 张三 数学 95 2 李四 语文 85 3 李四 数学 88
使用stack和unstack组合合并为单行:
# 先设置多级索引,再unstack转换 score_result = score_df.set_index(['student', 'subject']).unstack(fill_value=0).reset_index() # 处理列名,去掉多层索引 score_result.columns = ['student', '语文', '数学'] print(score_result)
合并后的结果:
student 语文 数学 0 张三 90 95 1 李四 85 88
不同方法的适用场景总结
- 如果是按照某个分组键将多行的字符串或数值拼接,优先选择groupby加聚合函数的方式,实现简单且灵活度高。
- 如果数据是需要将某一列的枚举值转为新的列名,适合使用pivot_table透视表,自动处理列名转换。
- 如果数据结构更复杂,需要灵活调整行和列的映射关系,可以使用stack和unstack组合,自定义转换逻辑。
在实际使用时,还需要注意处理缺失值,比如groupby拼接时如果分组内有缺失值,需要先做填充,避免拼接结果出现多余的空值。另外如果数据量较大,groupby的聚合操作性能会更优,优先选择向量化的操作而不是逐行遍历。