U10*_*ard 6 python dataframe pandas pandas-melt
在pandas标签上,我经常看到用户询问有关在 pandas 中融合数据框的问题。我将尝试针对此主题进行规范的问答(自我回答)。
我要澄清:
什么是熔体?
我如何使用熔体?
我什么时候使用熔体?
我看到一些关于融化的热门问题,例如:
pandas 将一些列转换为行:这实际上可能很好,但更多的解释会更好。
Pandas Melt Function : Nice question answer是好的,但是有点太含糊了,没有太多的展开。
融化熊猫数据框:也是一个不错的答案!但这仅适用于特定情况,这很简单,仅pd.melt(df)
Pandas 数据框使用列作为行(融化):非常整洁!但问题是它仅适用于 OP 提出的特定问题,这也需要使用pivot_table。
所以我将尝试针对这个主题进行规范的问答。
我将在这个随机成绩数据集上为随机年龄的随机人提供我所有的答案(更容易解释答案:D):
import pandas as pd
df = 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 Age
0 Bob A+ C 13
1 John B B 16
2 Foo A B 16
3 Bar F A+ 15
4 Alex D F 15
5 Tom C A 13
>>>
Run Code Online (Sandbox Code Playgroud)
我会遇到一些问题,它们将在我下面的自我回答中得到解决。
如何融化数据帧,使原始数据帧变为:
Name Age Subject Grade
0 Bob 13 English C
1 John 16 English B
2 Foo 14 English B
3 Bar 15 English A+
4 Alex 17 English F
5 Tom 12 English A
6 Bob 13 Math A+
7 John 16 Math B
8 Foo 14 Math A
9 Bar 15 Math F
10 Alex 17 Math D
11 Tom 12 Math C
Run Code Online (Sandbox Code Playgroud)
我想将其转置,以便一列是每个主题,而其他列将是学生的重复姓名以及年龄和分数。
这和问题1类似,但是这次我想让问题1输出Subject列只有Math,我想过滤掉该English列:
Name Age Subject Grades
0 Bob 13 Math A+
1 John 16 Math B
2 Foo 16 Math A
3 Bar 15 Math F
4 Alex 15 Math D
5 Tom 13 Math C
Run Code Online (Sandbox Code Playgroud)
我希望输出像上面那样。
如果我要对融化进行分组并按分数对学生进行排序,我将如何做到这一点,以获得如下所示的所需输出:
value Name Subjects
0 A Foo, Tom Math, English
1 A+ Bob, Bar Math, English
2 B John, John, Foo Math, English, English
3 C Tom, Bob Math, English
4 D Alex Math
5 F Bar, Alex Math, English
Run Code Online (Sandbox Code Playgroud)
我需要对它进行排序,名称以逗号分隔,并且名称Subjects以相同的顺序以逗号分隔
我将如何解开融化的数据框?假设我已经融化了这个数据框:
print(df.melt(id_vars=['Name', 'Age'], var_name='Subject', value_name='Grades'))
Run Code Online (Sandbox Code Playgroud)
成为:
Name Age Subject Grades
0 Bob 13 Math A+
1 John 16 Math B
2 Foo 16 Math A
3 Bar 15 Math F
4 Alex 15 Math D
5 Tom 13 Math C
6 Bob 13 English C
7 John 16 English B
8 Foo 16 English B
9 Bar 15 English A+
10 Alex 15 English F
11 Tom 13 English A
Run Code Online (Sandbox Code Playgroud)
那么我将如何将其转换回原始数据帧,如下所示:
Name Math English Age
0 Bob A+ C 13
1 John B B 16
2 Foo A B 16
3 Bar F A+ 15
4 Alex D F 15
5 Tom C A 13
Run Code Online (Sandbox Code Playgroud)
我该怎么做呢?
如果按学生姓名分组,用逗号分隔科目和成绩,我该怎么做?
Name Subject Grades
0 Alex Math, English D, F
1 Bar Math, English F, A+
2 Bob Math, English A+, C
3 Foo Math, English A, B
4 John Math, English B, B
5 Tom Math, English C, A
Run Code Online (Sandbox Code Playgroud)
我想要一个像上面这样的数据框。
U10*_*ard 32
注意 pandas 版本 < 0.20.0:我将df.melt(...)在我的示例中使用,但您需要pd.melt(df, ...)改为使用。
这里的大多数解决方案都会使用with melt,因此要了解该方法melt,请参阅文档说明。
\n\n将 DataFrame 从宽格式逆透视为长格式,可选择保留\n标识符集。
\n此函数可用于将 DataFrame 调整为一种格式,其中一个\n或多列是标识符变量(id_vars),而所有其他\n列(被视为测量变量(value_vars) )是 \xe2\x80\x9cunpivoted\xe2\x80\x9d \n到行轴,只留下两个非标识符列,\xe2\x80\x98variable\xe2\x80\x99\n和\xe2\x80\x98value\xe2\x80\x99。
\n参数
\n\n
\n- \n
id_vars:元组、列表或 ndarray,可选
\n用作标识符变量的列。
\n- \n
value_vars:元组、列表或 ndarray,可选
\n要取消透视的列。如果未指定,则使用未设置为 id_vars 的所有列。
\n- \n
var_name:标量
\n用于 \xe2\x80\x98variable\xe2\x80\x99 列的名称。如果没有,则使用frame.columns.name或\xe2\x80\x98variable\xe2\x80\x99。
\n- \n
value_name:标量,默认 \xe2\x80\x98value\xe2\x80\x99
\n用于 \xe2\x80\x98value\xe2\x80\x99 列的名称。
\n- \n
col_level : int 或 str,可选
\n如果列是多重索引,则使用此级别来融化。
\n- \n
ignore_index : bool, 默认 True
\n如果为 True,则忽略原始索引。如果为 False,则保留原始索引。必要时将重复索引标签。
\n1.1.0 版本中的新增内容。
\n
Melting合并多列并将数据框从宽转为长,对于问题1的解决方案(见下文),步骤是:
\n\n这是该函数的简单逻辑melt。
问题1可以使用pd.DataFrame.melt以下代码解决:
print(df.melt(id_vars=[\'Name\', \'Age\'], var_name=\'Subject\', value_name=\'Grades\'))\nRun Code Online (Sandbox Code Playgroud)\n此代码将id_vars参数传递给[\'Name\', \'Age\'],然后自动value_vars将 设定为其他列 ( [\'Math\', \'English\']),并将其转置为该格式。
您还可以使用stack如下方法解决问题 1:
print(\n df.set_index(["Name", "Age"])\n .stack()\n .reset_index(name="Grade")\n .rename(columns={"level_2": "Subject"})\n .sort_values("Subject")\n .reset_index(drop=True)\n)\nRun Code Online (Sandbox Code Playgroud)\n此代码将Name和Age列设置为索引,并堆叠其余列Math和English,重置索引并指定Grade为列名,然后将另一列重命名level_2为Subject,然后按该Subject列排序,最后再次重置索引。
这两个解决方案都会输出:
\nprint(df.melt(id_vars=[\'Name\', \'Age\'], var_name=\'Subject\', value_name=\'Grades\'))\nRun Code Online (Sandbox Code Playgroud)\n这和我的第一个问题类似,但是这个我只在Math列中进行过滤,这时候value_vars参数就可以派上用场了,如下所示:
print(\n df.melt(\n id_vars=["Name", "Age"],\n value_vars="Math",\n var_name="Subject",\n value_name="Grades",\n )\n)\nRun Code Online (Sandbox Code Playgroud)\n或者我们也可以使用stack列规范:
print(\n df.set_index(["Name", "Age"])[["Math"]]\n .stack()\n .reset_index(name="Grade")\n .rename(columns={"level_2": "Subject"})\n .sort_values("Subject")\n .reset_index(drop=True)\n)\nRun Code Online (Sandbox Code Playgroud)\n这两种解决方案都给出:
\nprint(\n df.set_index(["Name", "Age"])\n .stack()\n .reset_index(name="Grade")\n .rename(columns={"level_2": "Subject"})\n .sort_values("Subject")\n .reset_index(drop=True)\n)\nRun Code Online (Sandbox Code Playgroud)\nmelt问题 3 可以通过和来解决groupby,使用agg函数 with \', \'.join,如下所示:
print(\n df.melt(id_vars=["Name", "Age"])\n .groupby("value", as_index=False)\n .agg(", ".join)\n)\nRun Code Online (Sandbox Code Playgroud)\n它熔化数据框,然后按等级分组并聚合它们并用逗号将它们连接起来。
\nstack也可以用来解决这个问题,stack如下groupby所示:
print(\n df.set_index(["Name", "Age"])\n .stack()\n .reset_index()\n .rename(columns={"level_2": "Subjects", 0: "Grade"})\n .groupby("Grade", as_index=False)\n .agg(", ".join)\n)\nRun Code Online (Sandbox Code Playgroud)\n该stack函数只是以相当于 的方式转置数据帧melt,然后重置索引,重命名列、组和聚合。
两种解决方案输出:
\n Name Age Subject Grade\n0 Bob 13 English C\n1 John 16 English B\n2 Foo 16 English B\n3 Bar 15 English A+\n4 Alex 17 English F\n5 Tom 12 English A\n6 Bob 13 Math A+\n7 John 16 Math B\n8 Foo 16 Math A\n9 Bar 15 Math F\n10 Alex 17 Math D\n11 Tom 12 Math C\nRun Code Online (Sandbox Code Playgroud)\n\n\n我如何解开融化的数据框?假设我已经融化了这个数据框:
\nRun Code Online (Sandbox Code Playgroud)\ndf = df.melt(id_vars=[\'Name\', \'Age\'], var_name=\'Subject\', value_name=\'Grades\')\n
这可以通过 来解决pivot_table。我们必须指定参数values、index和columns。aggfunc
我们可以用下面的代码来解决:
\nprint(\n df.pivot_table("Grades", ["Name", "Age"], "Subject", aggfunc="first")\n .reset_index()\n .rename_axis(columns=None)\n)\nRun Code Online (Sandbox Code Playgroud)\n输出:
\nprint(\n df.melt(\n id_vars=["Name", "Age"],\n value_vars="Math",\n var_name="Subject",\n value_name="Grades",\n )\n)\nRun Code Online (Sandbox Code Playgroud)\n融化的数据帧被转换回与原始数据帧完全相同的格式。
\n我们首先旋转融化的数据框,然后重置索引并删除列轴名称。
\nprint(\n df.melt(id_vars=["Name", "Age"], var_name="Subject", value_name="Grades")\n .groupby("Name", as_index=False)\n .agg(", ".join)\n)\nRun Code Online (Sandbox Code Playgroud)\n融化并按 分组Name。
或者你可以stack:
print(\n df.set_index(["Name", "Age"])\n .stack()\n .reset_index()\n .groupby("Name", as_index=False)\n .agg(", ".join)\n .rename({"level_2": "Subjects", 0: "Grades"}, axis=1)\n)\nRun Code Online (Sandbox Code Playgroud)\n两个代码都输出:
\nprint(\n df.set_index(["Name", "Age"])[["Math"]]\n .stack()\n .reset_index(name="Grade")\n .rename(columns={"level_2": "Subject"})\n .sort_values("Subject")\n .reset_index(drop=True)\n)\nRun Code Online (Sandbox Code Playgroud)\n问题 6 可以解决melt,不需要指定列,只需指定预期的列名称:
print(df.melt(var_name=\'Column\', value_name=\'Value\'))\nRun Code Online (Sandbox Code Playgroud)\n这会融化整个数据框。
\n或者你可以stack:
print(\n df.stack()\n .reset_index(level=1)\n .sort_values("level_1")\n .reset_index(drop=True)\n .set_axis(["Column", "Value"], axis=1)\n)\nRun Code Online (Sandbox Code Playgroud)\n两个代码都输出:
\n Name Age Subject Grade\n0 Bob 13 Math A+\n1 John 16 Math B\n2 Foo 16 Math A\n3 Bar 15 Math F\n4 Alex 15 Math D\n5 Tom 13 Math C\nRun Code Online (Sandbox Code Playgroud)\n
问题中没有提到另一种类型melt,即列标题包含公共前缀的数据框,并且您希望将后缀融化为列值。
这与如何旋转数据框?中的问题 11相反。
假设您有一个以下 DataFrame,并且您想要将1970,融化1980为列值
A1970 A1980 B1970 B1980 X id
0 a d 2.5 3.2 -1.085631 0
1 b e 1.2 1.3 0.997345 1
2 c f 0.7 0.1 0.282978 2
Run Code Online (Sandbox Code Playgroud)
在这种情况下你可以尝试pandas.wide_to_long
pd.wide_to_long(df, stubnames=["A", "B"], i="id", j="year")
Run Code Online (Sandbox Code Playgroud)
X A B
id year
0 1970 -1.085631 a 2.5
1 1970 0.997345 b 1.2
2 1970 0.282978 c 0.7
0 1980 -1.085631 d 3.2
1 1980 0.997345 e 1.3
2 1980 0.282978 f 0.1
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
172 次 |
| 最近记录: |