在pandas标签上,我经常看到用户问关于在Pandas中融化 Dataframe 的问题,我将尝试一个关于这个主题的经典问答(自我回答)。
我要澄清一下:
1.什么是融化?
1.如何使用融化?
1.何时使用融化?
我看到一些关于融化的热门问题,例如:
- Convert columns into rows with Pandas:这一个实际上可能很好,但更多的解释会更好。
- Pandas Melt Function:好问题答案是好的,但是有点太模糊了,没有太多的扩展。
- Melting a pandas dataframe:这也是一个不错的答案!但它只适用于特定的情况,这非常简单,只有
pd.melt(df)
- Pandas dataframe use columns as rows (melt):非常简洁!但问题是它只针对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
>>>
问题:
我会有一些问题,他们将在我下面的自我答案解决。
问题1:
如何融化 Dataframe ,使原始 Dataframe 变为:
Name Age Subject Grade
0 Bob 13 English C
1 John 16 English B
2 Foo 16 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 16 Math A
9 Bar 15 Math F
10 Alex 17 Math D
11 Tom 12 Math C
我想调换一下,这样一栏是每门课,另一栏是学生的重复姓名、年龄和分数。
问题2:
这与问题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
我希望输出像上面一样。
问题三:
如果我是分组融化和排序的学生有分数,我将如何能够做到这一点,以获得所需的输出像下面:
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
我需要它的顺序和名称分隔逗号和Subjects
分隔逗号在相同的顺序分别
问题4:
我如何 unmelt 一个融化的 Dataframe ?假设我已经融化了这个 Dataframe :
print(df.melt(id_vars=['Name', 'Age'], var_name='Subject', value_name='Grades'))
成为:
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
那么,我如何将其转换回原始 Dataframe ,如下所示:
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
我该怎么做呢?
问题五:
如果我按学生的名字分组,用逗号分隔科目和成绩,我会怎么做?
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
我想有一个像上面的 Dataframe 。
问题6:
如果我要完全融化我的 Dataframe ,所有列都是值,我该怎么做?
Column Value
0 Name Bob
1 Name John
2 Name Foo
3 Name Bar
4 Name Alex
5 Name Tom
6 Math A+
7 Math B
8 Math A
9 Math F
10 Math D
11 Math C
12 English C
13 English B
14 English B
15 English A+
16 English F
17 English A
18 Age 13
19 Age 16
20 Age 16
21 Age 15
22 Age 15
23 Age 13
我想有一个像上面的数据框。所有列的值。
3条答案
按热度按时间nkoocmlb1#
df.melt(...)
,但您需要使用pd.melt(df, ...)
。文件参考:
这里的大多数解都将与
melt
一起使用,因此要了解melt
方法,请参见documentaion说明将DataFrame从宽格式取消透视为长格式,可以选择保留设置的标识符。
此函数可用于将DataFrame转换为一种格式,其中一个或多个列是标识符变量 (id_vars),而所有其他列(被视为测量变量 (value_vars))"取消透视"到行轴,只留下两个非标识符列,"variable"和"value"。
要用作标识符变量的列。
要取消透视的列。如果未指定,则使用未设置为id_vars的所有列。
Name to use for the ‘variable’ column. If None it uses frame.columns.name or ‘variable’.
用于"值"列的名称。
如果列是MultiIndex,则使用此级别进行融合。
如果为True,则忽略原始索引。如果为False,则保留原始索引。将根据需要重复索引标签。
熔化逻辑:
熔解合并多个列并将 Dataframe 从宽转换为长,对于问题1的解决方案(见下文),步骤是:
1.首先我们得到了原始 Dataframe 。
1.然后,熔解首先合并
Math
和English
列,并复制 Dataframe (更长)。1.最后添加列
Subject
,该列分别是Grades
列值的主题。这是
melt
函数的简单逻辑。溶液:
我会自己解决问题。
问题1:
问题1可以使用
pd.DataFrame.melt
和以下代码解决:此代码将
id_vars
参数传递给['Name', 'Age']
,然后value_vars
将自动设置为其他列(['Math', 'English']
),并转换为该格式。您还可以使用
stack
解决问题1,如下所示:这段代码将
Name
和Age
列设置为索引,堆叠其余的Math
和English
列,重置索引并将Grade
指定为列名,然后将另一列level_2
重命名为Subject
,然后按Subject
列排序,最后再次重置索引。这两种解决方案都输出:
问题2:
这和我的第一个问题类似,不过这一个我只在
Math
列中过滤一个,这个时候value_vars
参数就可以派上用场了,如下所示:或者我们也可以使用
stack
和列规范:这两种解决方案给出:
问题三:
问题3可以用
melt
和groupby
解决,使用agg
函数和', '.join
,如下所示:它先分解 Dataframe ,然后按等级分组,然后聚合它们,最后用逗号连接它们。
stack
也可用于解决此问题,stack
和groupby
如下所示:这个
stack
函数只是以与melt
等效的方式转置 Dataframe ,然后重置索引,重命名列、组和聚合。两种解决方案输出:
问题4:
我们首先融化输入数据的 Dataframe :
那么现在我们可以开始解决问题4了。
问题4可以用
pivot_table
来解决,我们必须指定pivot_table
参数,values
,index
,columns
和aggfunc
。我们可以用下面的代码来解决这个问题:
输出:
融化的 Dataframe 被转换回与原始 Dataframe 完全相同的格式。
我们首先透视融化的 Dataframe ,然后重置索引并删除列轴名称。
问题五:
问题5可以使用
melt
和groupby
解决,如下所示:它熔化并组成
Name
。或者您可以
stack
:两个代码输出:
问题6:
问题6可以用
melt
来解决,不需要指定列,只需要指定期望的列名:这会融化整个 Dataframe
或者您可以
stack
:两个代码输出:
结论:
melt
是一个非常方便的函数,通常是必需的,一旦你遇到这类问题,不要忘记尝试melt
,它可能会很好地解决你的问题。oymdgrw72#
还有一种
melt
在问题中没有提到,那就是对于列标题包含公共前缀的 Dataframe ,您希望将后缀融化到列值中。这与How can I pivot a dataframe?中的 * 问题11 * 正好相反
假设您有一个下面的DataFrame,并且希望将
1970
、1980
融合为列值在这种情况下,您可以尝试
pandas.wide_to_long
x一个一个一个一个x一个一个二个x
csga3l583#
如U12-Forward中的here所述,
melt
处理 Dataframe 主要意味着将数据从宽格式重新整形为长格式。通常情况下,与原始 Dataframe 相比,新 Dataframe 将具有更多的行和更少的列。当涉及到融合时有不同的场景-所有列标签可以被融合到单个列或多个列中;列标签的某些部分可以保留为标题,而其余部分则整理成一列,以此类推。这个答案展示了如何使用
pd.stack
、pd.melt
、pd.wide_to_long
和pivot_longger from pyjanitor来融化panda Dataframe (我是pyjanitor库的贡献者)。这些例子并不详尽,但希望能为您指出正确的方向,当谈到重塑 Dataframe 从宽到长的形式。示例数据
方案1 -熔化所有列:
在本例中,我们希望将所有指定的列标题转换为行--这可以用
pd.melt
或pd.stack
来完成,问题1的solutions已经涵盖了这一点。就像在
pd.melt
中一样,您可以通过向names_to
和values_to
参数传递参数来重命名variable
和value
列:您还可以保留原始索引,并根据出现顺序保留 Dataframe :
默认情况下,
names_to
中的值为字符串;它们可以通过names_transform
参数转换为其他数据类型--这对于大型 Dataframe 可能很有帮助/很有性能,因为与整形后转换数据类型相比,它通常更高效。请注意,此功能目前仅在开发版本中可用:方案2 -将列标签合并为多列:
到目前为止,我们已经将数据融合到了单列中,一列用于列名,一列用于值。但是,可能会出现这样的情况:我们希望将列标签拆分到不同的列中,甚至将值拆分到不同的列中。继续我们的示例数据,我们更希望将
sepal
和petal
放在part
列下。而length
和width
在dimension
列中:pd.melt
-熔化后进行分离:pd.stack
-提供了一种更有效的拆分列的方法;拆分是在列上完成的,这意味着随着数据大小的增加,要处理的行数更少,结果可能更快:pivot_longer
--关于pivot_longer
,需要注意的关键是它寻找模式,列标签用点.
分隔,只需将新名称的列表/元组传递给names_to
,并将分隔符传递给names_sep
(实际上它只使用pd.str.split
):到目前为止,我们已经看到了melt、stack和pivot_longger是如何将列标签拆分成多个新列的,只要有一个定义好的分隔符。如果没有一个明确定义的分隔符,比如下面的数据框:
在第二列中,我们有多个
_
,而第三列只有一个_
。(sp
和rel
到diagnosis
列,m
和f
到gender
列,数字到age
列)。pd.melt
-再次通过pd.melt
,在熔化 * 之后 * 发生整形:注意正则表达式是如何按组提取的(括号中的那个)。
pd.stack
-与上一个示例相同,拆分是在列上完成的,因此效率更高:同样,正则表达式的提取是分组进行的。
pivot_longer
--同样我们知道了模式和新的列名,我们只需要将它们传递给函数,这次我们使用names_pattern
,因为我们处理的是正则表达式,提取的内容将匹配组中的正则表达式(括号中的那些):方案3 -将列标签 * 和 * 值合并到多列中:
如果我们也想将值拆分到多个列中呢?让我们使用一个简单的popular question on SO:
目标是将
Mango
、Orange
和Watermelon
整理到结果列中,将Gin
和Vodka
整理到Drinks
列中,并将各自的值分别整理到Pounds
和Ounces
中。pd.melt
-我正在逐字复制优秀的solution:pd.stack
-我想不出通过堆栈的解决方案,所以我将跳过pivot_longer
-通过将名称列表传递给names_to
和values_to
,并将正则表达式列表传递给names_pattern
,可以高效地完成整形-当将值拆分为多列时,需要将正则表达式列表传递给names_pattern
:随着 Dataframe 大小的增加,效率甚至更高。
方案4 -将相似的列组合在一起:
将合并的概念扩展到多个列中,假设我们希望将相似的列组合在一起。我们不关心保留列标签,只是将相似列的值组合到新列中。
对于上面的代码,我们希望将相似的列(以相同字母开头的列)合并为新的唯一列-所有
x*
列将集中在x_mean
下,而所有y*
列将整理在y_mean
下。我们不保存列标签,我们只对这些列的值感兴趣:pivot_longer
来说,这一切都与模式有关,只需将新列名的列表传递给names_to
,并将相应的正则表达式传递给names_pattern
:请注意,对于此模式,它是基于先到先得的原则-如果列顺序颠倒,
pivot_longer
将给予不同的输出。由于顺序已经改变,
x_1_mean
将与y_2_mean
配对,因为这是它看到的第一个y
列,而x_2_mean
将与y_1_mean
配对:注意与前一次运行相比输出中的差异。这是在序列中使用names_pattern时需要注意的。顺序很重要。
方案5 -保留部分列名作为标题:
这可能是将列标签重新整形为长格式时最大的用例之一。我们可能希望保留列标签的某些部分作为标题,并将其余列移动到新列(甚至忽略它们)。
让我们回顾一下虹膜 Dataframe :
这里我们的目标是保留
Sepal
、Petal
作为列名,其余的(Length
、Width
)整理到dimension
列中:这不如下面的其他选项有效,因为这涉及宽到长,* 然后 * 长到宽,这可能在足够大的 Dataframe 上性能较差。
随着数据大小的增加,
pd.wide_to_long
的效率可能会降低。.value
作为占位符。函数看到.value
,并知道该子标签必须保留为标题。列中的拆分可以是names_sep
或names_pattern
。在这种情况下,使用names_sep
更简单:当列用
.
拆分时,我们有Petal, Length
。当与('.value', 'dimension')
比较时,Petal
与.value
相关联,而Length
与dimension
相关联。Petal
仍然作为列标题。而Length
被集中到dimension
列,我们不需要明确列名称,我们只使用.value
,让函数来完成繁重的工作,这样,如果你有很多列,只要通过names_sep
或names_pattern
获得了正确的模式,就不需要计算作为标题的列应该是什么。如果我们想用
Length
/Width
作为列名,而Petal/Sepal
被集中到part
列中,该怎么办?Length
/Width
位于前面:注意,我们不需要进行任何列重排序(有些情况下列重排序是不可避免的),函数只是简单地将
.value
与从names_sep
拆分得到的任何 Dataframe 配对,并输出整形后的 Dataframe 。在适用的情况下,您甚至可以使用多个.value
。让我们回顾一下前面的 Dataframe :一个三个一个一个一个二个一个
这一切都是关于看到模式并利用它们。
pivot_longer
只是在常见的整形场景中提供了高效和性能的抽象-在引擎盖下,它只是Pandas/numpy/python。希望当你需要从宽到长重塑时,各种答案能为你指明正确的方向。