如何融化 pandas 数据框?
在 pandas 标签上,我经常看到用户询问有关在 pandas 中融化数据帧的问题。我将尝试针对这个主题进行规范的问答(自我回答)。
我要澄清:
什么是熔化?
如何使用melt?
什么时候使用melt?
我看到一些有关融化的热门问题,例如:
所以我将尝试针对这个主题进行规范的问答。
数据集:
我将在这个随机年龄的随机人的随机成绩数据集中找到所有答案(更容易解释答案:d):
import pandas as pddf = pd.dataframe({'name': ['bob', 'john', 'foo', 'bar', 'alex', 'tom'], 'math': ['a+', 'b', 'a', 'f', 'd', 'c'], 'english': ['c', 'b', 'b', 'a+', 'f', 'a'], 'age': [13, 16, 16, 15, 15, 13]})
>>> df name math english age0 bob a+ c 131 john b b 162 foo a b 163 bar f a+ 154 alex d f 155 tom c a 13
问题:
问题 1:
如何融化数据框以使原始数据框变为以下内容?
name age subject grade0 bob 13 english c1 john 16 english b2 foo 16 english b3 bar 15 english a+4 alex 17 english f5 tom 12 english a6 bob 13 math a+7 john 16 math b8 foo 16 math a9 bar 15 math f10 alex 17 math d11 tom 12 math c
我想对其进行转置,以便一列是每个科目,其他列是学生的重复姓名及其年龄和分数。
问题 2:
这和问题1类似,但是这次我想让问题1输出subject列只有math,我想过滤掉english列:
name age subject grades0 bob 13 math a+1 john 16 math b2 foo 16 math a3 bar 15 math f4 alex 15 math d5 tom 13 math c
我希望输出如上所示。
问题 3:
如果我要对熔化进行分组并按学生的分数排序,我该如何做到这一点,以获得如下所示的所需输出:
value name subjects0 a foo, tom math, english1 a+ bob, bar math, english2 b john, john, foo math, english, english3 c tom, bob math, english4 d alex math5 f bar, alex math, english
我需要对其进行排序,名称用逗号分隔,并且 subjects 分别以相同的顺序用逗号分隔。
问题 4:
我如何解冻一个熔化的数据框?假设我已经融化了这个数据框:
df = df.melt(id_vars=['name', 'age'], var_name='subject', value_name='grades')
成为:
name age subject grades0 bob 13 math a+1 john 16 math b2 foo 16 math a3 bar 15 math f4 alex 15 math d5 tom 13 math c6 bob 13 english c7 john 16 english b8 foo 16 english b9 bar 15 english a+10 alex 15 english f11 tom 13 english a
那么我如何将其转换回原始数据框,如下所示?
name math english age0 bob a+ c 131 john b b 162 foo a b 163 bar f a+ 154 alex d f 155 tom c a 13
问题 5:
如果我要按学生姓名分组并用逗号分隔科目和成绩,我会怎么做?
name subject grades0 alex math, english d, f1 bar math, english f, a+2 bob math, english a+, c3 foo math, english a, b4 john math, english b, b5 tom math, english c, a
我想要一个像上面这样的数据框。
问题 6:
如果我要完全融化我的数据框,所有列都作为值,我会怎么做?
Column Value0 Name Bob1 Name John2 Name Foo3 Name Bar4 Name Alex5 Name Tom6 Math A+7 Math B8 Math A9 Math F10 Math D11 Math C12 English C13 English B14 English B15 English A+16 English F17 English A18 Age 1319 Age 1620 Age 1621 Age 1522 Age 1523 Age 13
我想要一个像上面这样的数据框。所有列作为值。
正确答案
pandas 版本 :我将使用 df.melt(...) 作为我的示例,但您需要使用 pd.melt(df, .. .) 代替。
文档参考:
这里的大多数解决方案都将与 melt,所以要知道方法melt ,请参阅文档说明。
熔化逻辑:
melting合并多列,将dataframe由宽转长,解决问题1(见下文),步骤为:
首先我们得到了原始数据帧。
然后,melt 首先合并 math 和 english 列,并使数据帧复制(更长)。
最后它添加了 subject 列,它分别是 grades 列值的主题:
这是 melt 函数的简单逻辑。
解决方案:
问题 1:
问题 1 可以使用 pd.dataframe.melt 解决 使用以下代码:
print(df.melt(id_vars=['name', 'age'], var_name='subject', value_name='grades'))
此代码将 id_vars 参数传递给 ['name', 'age'],然后自动将 value_vars 设置为其他列(['math', 'english']),这是转置的转换为该格式。
您还可以使用 stack解决问题 1 > 像下面这样:
print( df.set_index(["name", "age"]) .stack() .reset_index(name="grade") .rename(columns={"level_2": "subject"}) .sort_values("subject") .reset_index(drop=true))
此代码将 name 和 age 列设置为索引,并堆叠其余列 math 和 english,并重置索引并指定 grade 作为列名称,然后将其他列重命名为 level_2phpcnendcphp cn 到 subject 然后按subject 列,最后再次重置索引。
这两个解决方案输出:
name age subject grade0 bob 13 english c1 john 16 english b2 foo 16 english b3 bar 15 english a+4 alex 17 english f5 tom 12 english a6 bob 13 math a+7 john 16 math b8 foo 16 math a9 bar 15 math f10 alex 17 math d11 tom 12 math c
问题 2:
这和我的第一个问题类似,但是这个我只在 math 列中进行过滤,这时候 value_vars 参数就可以派上用场了,如下所示:
print( df.melt( id_vars=["name", "age"], value_vars="math", var_name="subject", value_name="grades", ))
或者我们也可以使用 stack 与列规格:
print( df.set_index(["name", "age"])[["math"]] .stack() .reset_index(name="grade") .rename(columns={"level_2": "subject"}) .sort_values("subject") .reset_index(drop=true))
这两种解决方案都给出:
name age subject grade0 bob 13 math a+1 john 16 math b2 foo 16 math a3 bar 15 math f4 alex 15 math d5 tom 13 math c
问题 3:
问题3可以通过melt解决和 groupby,使用 agg 函数和 ' , '.join,如下所示:
print( df.melt(id_vars=["name", "age"]) .groupby("value", as_index=false) .agg(", ".join))
它会融合数据框,然后按等级进行分组,聚合它们并用逗号将它们连接起来。
stack也可以用来解决这个问题,与 stack 和 groupby 如下所示:
print( df.set_index(["name", "age"]) .stack() .reset_index() .rename(columns={"level_2": "subjects", 0: "grade"}) .groupby("grade", as_index=false) .agg(", ".join))
这个 stack 函数只是转置数据帧以相当于 melt 的方式,然后重置索引,重命名列、组和聚合。
两种解决方案输出:
grade name subjects0 a foo, tom math, english1 a+ bob, bar math, english2 b john, john, foo math, english, english3 c bob, tom english, math4 d alex math5 f bar, alex math, english
问题 4:
这可以通过 pivot_table 来解决。我们必须指定参数 values、index、columns 以及 aggfunc。
我们可以用下面的代码来解决这个问题:
print( df.pivot_table("grades", ["name", "age"], "subject", aggfunc="first") .reset_index() .rename_axis(columns=none))
输出:
name age english math0 alex 15 f d1 bar 15 a+ f2 bob 13 c a+3 foo 16 b a4 john 16 b b5 tom 13 a c
融化的数据帧被转换回与原始数据帧完全相同的格式。
我们首先旋转融化的数据框,然后重置索引并删除列轴名称。
问题 5:
问题5可以通过melt解决和 groupby 如下所示:
print( df.melt(id_vars=["name", "age"], var_name="subject", value_name="grades") .groupby("name", as_index=false) .agg(", ".join))
融化并按 name 分组。
或者您可以stack: p>
print( df.set_index(["name", "age"]) .stack() .reset_index() .groupby("name", as_index=false) .agg(", ".join) .rename({"level_2": "subjects", 0: "grades"}, axis=1))
两个代码输出:
name subjects grades0 alex math, english d, f1 bar math, english f, a+2 bob math, english a+, c3 foo math, english a, b4 john math, english b, b5 tom math, english c, a
问题 6:
问题6可以通过melt解决并且不需要指定列,只需指定预期的列名称:
print(df.melt(var_name='column', value_name='value'))
这会融化整个数据框。
或者您可以stack: p>
print( df.stack() .reset_index(level=1) .sort_values("level_1") .reset_index(drop=true) .set_axis(["column", "value"], axis=1))
两个代码输出:
Column Value0 Age 161 Age 152 Age 153 Age 164 Age 135 Age 136 English A+7 English B8 English B9 English A10 English F11 English C12 Math C13 Math A+14 Math D15 Math B16 Math F17 Math A18 Name Alex19 Name Bar20 Name Tom21 Name Foo22 Name John23 Name Bob