如何融化熊猫数据框?

U10*_*ard 6 python dataframe pandas pandas-melt

标签上,我经常看到用户询问有关在 pandas 中融合数据框的问题。我将尝试针对此主题进行规范的问答(自我回答)。

我要澄清:

  1. 什么是熔体?

  2. 我如何使用熔体?

  3. 我什么时候使用熔体?

我看到一些关于融化的热门问题,例如:

所以我将尝试针对这个主题进行规范的问答。



数据集:

我将在这个随机成绩数据集上为随机年龄的随机人提供我所有的答案(更容易解释答案: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)

问题:

我会遇到一些问题,它们将在我下面的自我回答中得到解决。

问题1:

如何融化数据帧,使原始数据帧变为:

    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)

我想将其转置,以便一列是每个主题,而其他列将是学生的重复姓名以及年龄和分数。

问题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
Run Code Online (Sandbox Code Playgroud)

我希望输出像上面那样。

问题 3:

如果我要对融化进行分组并按分数对学生进行排序,我将如何做到这一点,以获得如下所示的所需输出:

  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以相同的顺序以逗号分隔

问题 4:

我将如何解开融化的数据?假设我已经融化了这个数据框:

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)

我该怎么做呢?

问题 5:

如果按学生姓名分组,用逗号分隔科目和成绩,我该怎么做?

   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, ...)改为使用。

\n

文档参考:

\n

这里的大多数解决方案都会使用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
  • 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,则保留原始索引。必要时将重复索引标签。

    \n

    1.1.0 版本中的新增内容。

    \n
  • \n
\n
\n

熔化逻辑:

\n

Melting合并多列并将数据框从宽转为长,对于问题1的解决方案(见下文),步骤是:

\n
    \n
  1. 首先我们得到原始数据框。

    \n
  2. \n
  3. 然后熔化首先合并MathEnglish列并使数据帧复制(更长)。

    \n
  4. \n
  5. Subject最后它分别添加作为列值主题的列Grades

    \n

    \n
  6. \n
\n

这是该函数的简单逻辑melt

\n

解决方案:

\n

问题一:

\n

问题1可以使用pd.DataFrame.melt以下代码解决:

\n
print(df.melt(id_vars=[\'Name\', \'Age\'], var_name=\'Subject\', value_name=\'Grades\'))\n
Run Code Online (Sandbox Code Playgroud)\n

此代码将id_vars参数传递给[\'Name\', \'Age\'],然后自动value_vars将 设定为其他列 ( [\'Math\', \'English\']),并将其转置为该格式。

\n

您还可以使用stack如下方法解决问题 1:

\n
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)\n
Run Code Online (Sandbox Code Playgroud)\n

此代码将NameAge列设置为索引,并堆叠其余列MathEnglish,重置索引并指定Grade为列名,然后将另一列重命名level_2Subject,然后按该Subject列排序,最后再次重置索引。

\n

这两个解决方案都会输出:

\n
print(df.melt(id_vars=[\'Name\', \'Age\'], var_name=\'Subject\', value_name=\'Grades\'))\n
Run Code Online (Sandbox Code Playgroud)\n

问题2:

\n

这和我的第一个问题类似,但是这个我只在Math列中进行过滤,这时候value_vars参数就可以派上用场了,如下所示:

\n
print(\n    df.melt(\n        id_vars=["Name", "Age"],\n        value_vars="Math",\n        var_name="Subject",\n        value_name="Grades",\n    )\n)\n
Run Code Online (Sandbox Code Playgroud)\n

或者我们也可以使用stack列规范:

\n
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)\n
Run Code Online (Sandbox Code Playgroud)\n

这两种解决方案都给出:

\n
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)\n
Run Code Online (Sandbox Code Playgroud)\n

问题3:

\n

melt问题 3 可以通过和来解决groupby,使用agg函数 with \', \'.join,如下所示:

\n
print(\n    df.melt(id_vars=["Name", "Age"])\n    .groupby("value", as_index=False)\n    .agg(", ".join)\n)\n
Run Code Online (Sandbox Code Playgroud)\n

它熔化数据框,然后按等级分组并聚合它们并用逗号将它们连接起来。

\n

stack也可以用来解决这个问题,stack如下groupby所示:

\n
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)\n
Run Code Online (Sandbox Code Playgroud)\n

stack函数只是以相当于 的方式转置数据帧melt,然后重置索引,重命名列、组和聚合。

\n

两种解决方案输出:

\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\n
Run Code Online (Sandbox Code Playgroud)\n

问题4:

\n
\n

我如何解开融化的数据框?假设我已经融化了这个数据框:

\n
df = df.melt(id_vars=[\'Name\', \'Age\'], var_name=\'Subject\', value_name=\'Grades\')\n
Run Code Online (Sandbox Code Playgroud)\n
\n

这可以通过 来解决pivot_table。我们必须指定参数valuesindexcolumnsaggfunc

\n

我们可以用下面的代码来解决:

\n
print(\n    df.pivot_table("Grades", ["Name", "Age"], "Subject", aggfunc="first")\n    .reset_index()\n    .rename_axis(columns=None)\n)\n
Run Code Online (Sandbox Code Playgroud)\n

输出:

\n
print(\n    df.melt(\n        id_vars=["Name", "Age"],\n        value_vars="Math",\n        var_name="Subject",\n        value_name="Grades",\n    )\n)\n
Run Code Online (Sandbox Code Playgroud)\n

融化的数据帧被转换回与原始数据帧完全相同的格式。

\n

我们首先旋转融化的数据框,然后重置索引并删除列轴名称。

\n

问题5:

\n

melt问题 5 可以通过groupby以下方式解决:

\n
print(\n    df.melt(id_vars=["Name", "Age"], var_name="Subject", value_name="Grades")\n    .groupby("Name", as_index=False)\n    .agg(", ".join)\n)\n
Run Code Online (Sandbox Code Playgroud)\n

融化并按 分组Name

\n

或者你可以stack

\n
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)\n
Run Code Online (Sandbox Code Playgroud)\n

两个代码都输出:

\n
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)\n
Run Code Online (Sandbox Code Playgroud)\n

问题6:

\n

问题 6 可以解决melt,不需要指定列,只需指定预期的列名称:

\n
print(df.melt(var_name=\'Column\', value_name=\'Value\'))\n
Run Code Online (Sandbox Code Playgroud)\n

这会融化整个数据框。

\n

或者你可以stack

\n
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)\n
Run 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\n
Run Code Online (Sandbox Code Playgroud)\n


Ynj*_*jmh 6

问题中没有提到另一种类型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 次

最近记录:

4 年,6 月 前