如何利用pandas的melt()方法,实现宽表转长表的操作?
发布于 作者:苏南大叔 来源:程序如此灵动~
在pandas里面有一个melt()方法,操作对象是dataframe。可以把一部分列数据变成横向的行数据。这个列变成行的效果,转换的也并不完全。这个函数的主要功能是把部分列数据变成行数据,也有部分列数据保持不变。同时也会有数据增生的现象发生,原列标签会变成主体内容,同时生成新的列标签。总之,就是和行列互换的需求是完全不同的结果。

大家好,这里是苏南大叔的"程序如此灵动"博客,本文记录pandas的melt()方法。测试环境:win10,python@3.11.0,numpy@1.24.2,pandas@1.5.3。而且这个melt()函数还有个副作用,就是会增大数据量,作为主键的列数据量会明显成倍增加。
melt,融化。melt()函数原型
Pandas.melt(frame, id_vars=None, value_vars=None, var_name=None, value_name='value', col_level=None)frame:要处理的dataframe数据。id_vars:tuple/list/ndarray,用作标识变量的列,即不需要被转换的列名。value_vars:tuple/list/ndarray,即将被转换的列。 如果未指定,则使未被设置为id_vars的所有列。var_name:标量,用于“变量”列的名称。 如果未指定,则使用variable。value_name:标量,默认为value,用于value列的名称。col_level:int或str,如果列是多重索引的,则使用此级别来融化。这个一般情况下用不到。ignore_index:默认为True,也就是忽略原有的行名,从头开始计数行名。
原始数据
import pandas as pd
df = pd.DataFrame({
'name': ['虎子', '老许', '小黑'],
'foot': [10, 20, 30],
'height': [80, 30, 50]
},index=["a1","a2","a3"])
print(df)输出:
name foot height
a1 虎子 10 80
a2 老许 20 30
a3 小黑 30 50默认melt()效果
默认的转换效果,全部的列都被横过来了。新生成
df_melt = pd.melt(df)
print(df_melt)输出:
variable value
0 name 虎子
1 name 老许
2 name 小黑
3 age 10
4 age 5
5 age 3
6 height 80
7 height 30
8 height 50
指定主键id_vars
df_melt = pd.melt(df, id_vars=['name'])
print(df_melt)输出:
name variable value
0 虎子 age 10
1 老许 age 5
2 小黑 age 3
3 虎子 height 80
4 老许 height 30
5 小黑 height 50df_melt = pd.melt(df, id_vars=['name','age'])
print(df_melt)输出:
name age variable value
0 虎子 10 height 80
1 老许 5 height 30
2 小黑 3 height 50修改新列名
df_melt = pd.melt(df, id_vars=['name'], var_name='new_column_name', value_name='new_column_value')
print(df_melt)输出:
name new_column_name new_column_value
0 虎子 age 10
1 老许 age 5
2 小黑 age 3
3 虎子 height 80
4 老许 height 30
5 小黑 height 50
同时指定id_vars和value_vars
df_melt = pd.melt(df, id_vars=['name'], value_vars=['age'])
print(df_melt)输出:
name variable value
0 虎子 age 10
1 老许 age 5
2 小黑 age 3值得说明的是:本操作故意丢失了height数据。ignore_index,忽略原有行名
不忽略的话,似乎很不妥当。
df_melt = pd.melt(df,ignore_index=False)
print(df_melt)输出:
variable value
a1 name 虎子
a2 name 老许
a3 name 小黑
a1 foot 10
a2 foot 20
a3 foot 30
a1 height 80
a2 height 30
a3 height 50多重索引col_index
多重索引的情况,目前还没有涉及过,这里仅仅放个例子,以后待议。
import pandas as pd
df = pd.DataFrame({'A': {0: '苏', 1: '南'},
'B': {0: "大", 1: "叔"},
'C': {0: 666, 1: 888}})
df.columns = pd.MultiIndex.from_arrays([list('ABC'), list('DEF')], names=list('ab'))
print (df)
print (df.melt(col_level='b'))输出:
a A B C
b D E F
0 苏 大 666
1 南 叔 888 b value
0 D 苏
1 D 南
2 E 大
3 E 叔
4 F 666
5 F 888melt()对比.T操作
melt()作用是宽表变长表,而.T作用是行列互换。
| 区分 | 主体.size | 旧列名 | 旧行名 |
|---|---|---|---|
| melt() | id_vars的数据重复增加 | 旧的变成数据,新列名可指定 | 默认重置,也可以随数据增多而增多 |
| .T | 不变 | 变成行名 | 变成列名 |
melt()之后可能需要的操作
melt()之后,肉眼可见的标签(行名列名)大混乱。所以,您可能需要下面的操作:
df.columns = ["col1","col2","col3"]或者:
df.index= ["row1","row2"]或者:
df.rename(
columns={"name": "姓名", "age": "年龄", "label": "标签", "无关": "瞎写"},
index={"a1": "第一行", "a2": "第二行"},
inplace=True,
)参考文章:
结束语
这个melt可以丢失数据(指定value_vars),默认增多数据,行名索引也会默认被重置。总之,不是很好用。列转行的操作,仅仅是把部分列数据变成了行,和期待的行列数据互换还有较大差距。