PHP前端开发

如何融化 pandas 数据框?

百变鹏仔 1天前 #Python
文章标签 数据
问题内容

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

我要澄清:

  1. 什么是熔化?

  2. 如何使用melt?

  3. 什么时候使用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(见下文),步骤为:

  1. 首先我们得到了原始数据帧。

  2. 然后,melt 首先合并 math 和 english 列,并使数据帧复制(更长)。

  3. 最后它添加了 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