卓越飞翔博客卓越飞翔博客

卓越飞翔 - 您值得收藏的技术分享站
技术文章35086本站已运行394

如何融化 pandas 数据框?

如何融化 pandas 数据框?

问题内容

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

我要澄清:

  1. 什么是熔化?

  2. 如何使用melt?

  3. 什么时候使用melt?

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

  • 使用 pandas 将列转换为行:这个实际上可能很好,但更多的解释会更好。

  • pandas melt function:一个很好的问题,答案也很好,但是有点太模糊了,没有太多解释。

  • 融化 pandas 数据框:也是一个很好的答案!但这只是针对特定情况,这很简单,只有 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

问题:

问题 1:

如何融化数据框以使原始数据框变为以下内容?

    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

我希望输出如上所示。

问题 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

我需要对其进行排序,名称用逗号分隔,并且 subjects 分别以相同的顺序用逗号分隔。

问题 4:

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

df = 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

那么我如何将其转换回原始数据框,如下所示?

   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

问题 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

我想要一个像上面这样的数据框。

问题 6:

如果我要完全融化我的数据框,所有列都作为值,我会怎么做?

     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

我想要一个像上面这样的数据框。所有列作为值。


正确答案


pandas 版本 < 0.20.0 的注意事项:我将使用 df.melt(...) 作为我的示例,但您需要使用 pd.melt(df, .. .) 代替。

文档参考:

这里的大多数解决方案都将与 melt< 一起使用/a>,所以要知道方法melt ,请参阅文档说明。

熔化逻辑:

melting合并多列,将dataframe由宽转长,解决问题1(见下文),步骤为:

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

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

  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 像下面这样:

print(
    df.set_index(["name", "age"])
    .stack()
    .reset_index(name="grade")
    .rename(columns={"level_2": "subject"})
    .sort_values("subject")
    .reset_index(drop=true)
)

此代码将 nameage 列设置为索引,并堆叠其余列 mathenglish,并重置索引并指定 grade 作为列名称,然后将其他列重命名为 level_2phpcnendcphp cn 到 subject 然后按subject 列,最后再次重置索引。

这两个解决方案输出:

    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:

这和我的第一个问题类似,但是这个我只在 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 grade
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

问题 3:

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

print(
    df.melt(id_vars=["name", "age"])
    .groupby("value", as_index=false)
    .agg(", ".join)
)

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

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

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                subjects
0     a         foo, tom           math, english
1    a+         bob, bar           math, english
2     b  john, john, foo  math, english, english
3     c         bob, tom           english, math
4     d             alex                    math
5     f        bar, alex           math, english

问题 4:

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

我们可以用下面的代码来解决这个问题:

print(
    df.pivot_table("grades", ["name", "age"], "subject", aggfunc="first")
    .reset_index()
    .rename_axis(columns=none)
)

输出:

   name  age english math
0  alex   15       f    d
1   bar   15      a+    f
2   bob   13       c   a+
3   foo   16       b    a
4  john   16       b    b
5   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

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 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

问题 6:

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

print(df.melt(var_name='column', value_name='value'))

这会融化整个数据框。

或者您可以stack

print(
    df.stack()
    .reset_index(level=1)
    .sort_values("level_1")
    .reset_index(drop=true)
    .set_axis(["column", "value"], axis=1)
)

两个代码输出:

     Column Value
0       Age    16
1       Age    15
2       Age    15
3       Age    16
4       Age    13
5       Age    13
6   English    A+
7   English     B
8   English     B
9   English     A
10  English     F
11  English     C
12     Math     C
13     Math    A+
14     Math     D
15     Math     B
16     Math     F
17     Math     A
18     Name  Alex
19     Name   Bar
20     Name   Tom
21     Name   Foo
22     Name  John
23     Name   Bob
卓越飞翔博客
上一篇: Go 是否有可以打开 2 位颜色深度的调色板 png 的库?
下一篇: 返回列表
留言与评论(共有 0 条评论)
   
验证码:
隐藏边栏