长格式和宽格式
长格式和宽格式根据应用场景(如制图、统计和模型输入)的需求不同,转换为合适的数据格式,比如某些模型只能接受宽格式,长格式适合分组统计等。
长格式指每一行记录一个实体的一个属性或者测量值,比如下面的数据,每行记录了张三或者李四的一个科目的结果,即每个人占多行,不同的科目分数在不同行。
姓名,科目,成绩
1,张三,数学,95
2,张三,语文,89
3,李四,数学,80
4,李四,数学,85
宽格式指每一行记录一个实体的所有属性或测量值,比如下面的数据,每行记录了张三或者李四的所有科目的结果,即每个人占一行,所有的科目分数在不同列。
姓名,数学,语文
1,张三,95,89
2,李四,80,85
Pandas中的长格式转宽格式
Pandas中使用pivot和pivot_table将长格式转换为宽格式,他们的区别在于pivot需要索引和列的组合为唯一,比如张三不能出现两次数学,否则就会报错,但是如果数据没有重复组合,pivot的效率要比pivot_table高。
import pandas as pd
data = {
"name": ["张三","张三", "张三", "李四"],
"catetory": ["数学", "语文", "数学", "数学"],
"value": [95, 89, 90, 85]
}
df = pd.DataFrame(data)
df.pivot(index='name', columns='catetory', values='value')
ValueError: Index contains duplicate entries, cannot reshape
pivot_table和pivot的主要区别为对于重复值的处理,pivot_table在遇见重复的index+column的重复数据的时候,通过指定聚合函数(如mean、sum、max等),计算出一个单一的值来填充重塑后的表格。
import pandas as pd
data = {
"name": ["张三","张三", "张三", "李四"],
"catetory": ["数学", "语文", "数学", "数学"],
"value": [95, 89, 90, 85]
}
df = pd.DataFrame(data)
df.pivot_table(index='name', columns='catetory', values='value', aggfunc = 'mean')
# 下面的92.5为 (95 + 90) / 2
catetory 数学 语文
name
张三 92.5 89.0
李四 85.0 NaN
Pandas中的宽格式转长格式
宽格式转换长格式,实际上就是将多个列融化为两列(一个变量标识符)和一个值列,在Pandas中常用melt和wide_to_long方法。
演示长格式的数据情况为:
import pandas as pd
data = {
"name": ["张三","张三", "李四", "李四"],
"catetory": ["数学", "语文", "语文", "数学"],
"value": [95, 89, 90, 85]
}
df = pd.DataFrame(data)
df_long = df.pivot_table(index='name', columns='catetory', values='value', aggfunc = 'mean')
>>> df_long.reset_index(inplace=True)
catetory name 数学 语文
0 张三 95.0 89.0
1 李四 85.0 90.0
使用melt方法,melt方法常用的参数是id_vars(标识变量)、value_vars(溶化的列)、var_name(溶化后,变量名列的名称)、value_name(溶化后,值列的名称)。
>>> df_long.melt(id_vars=['name'], value_vars=['数学', '语文'], var_name='科目', value_name='分数')
name 科目 分数
0 张三 数学 95.0
1 李四 数学 85.0
2 张三 语文 89.0
3 李四 语文 90.0
wide_to_long的方法适用于有特定标识符的列名、并且又非常多的列的情况,具备模式匹配的wide_to_long的方法就比较适合,wide_to_long转换的方式为:
data = {
"name": ["张三", '李四'],
"Y2023_sell": [95, 85],
"Y2024_sell": [89, 90],
"Y2025_sell": [89, 89]
}
df_wide = pd.DataFrame(data)
pd.wide_to_long(df_wide, stubnames='Y', sep='', suffix='\\d+_sell', i='name', j='销售年份').reset_index()
name 销售年份 Y
0 张三 2023_sell 95
1 李四 2023_sell 85
2 张三 2024_sell 89
3 李四 2024_sell 90
4 张三 2025_sell 89
5 李四 2025_sell 89
参数解释:
- stubnames:前缀识别”Y”,表达期望找到以”Y”开头的列名。
- suffix:”\d+_sell”表达是被前缀为stubname+suffix,然后识别到的后缀将会被当做值的列名。
- sep:因为识别的前后之间没有间隔符,所以为空。
- i:为标识变量
- J:为新创建变量名的列名,也就是识别出来的后缀。