如何融化 pandas 数据框?

2024年 2月 10日 32.7k 0

如何融化 pandas 数据框?

问题内容

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

我要澄清:

  • 什么是熔化?

  • 如何使用melt?

  • 什么时候使用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 版本 :我将使用 df.melt(...) 作为我的示例,但您需要使用 pd.melt(df, .. .) 代替。

    文档参考:

    这里的大多数解决方案都将与 melt,所以要知道方法melt ,请参阅文档说明。

    熔化逻辑:

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

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

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

  • 最后它添加了 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)
    )

    登录后复制

    此代码将 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: 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 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: p>

    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

    登录后复制

    以上就是如何融化 pandas 数据框?的详细内容,更多请关注每日运维网(www.mryunwei.com)其它相关文章!

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论