使用 Pandas 将列转换为行

Posted

技术标签:

【中文标题】使用 Pandas 将列转换为行【英文标题】:Convert columns into rows with Pandas 【发布时间】:2022-01-08 17:37:06 【问题描述】:

所以我的数据集有 n 个日期的位置信息。问题是每个日期实际上是不同的列标题。例如 CSV 看起来像

location    name    Jan-2010    Feb-2010    March-2010
A           "test"  12          20          30
B           "foo"   18          20          25

我希望它看起来像

location    name    Date        Value
A           "test"  Jan-2010    12       
A           "test"  Feb-2010    20
A           "test"  March-2010  30
B           "foo"   Jan-2010    18       
B           "foo"   Feb-2010    20
B           "foo"   March-2010  25

我的问题是我不知道该列中有多少个日期(尽管我知道它们总是以名称开头)

【问题讨论】:

***.com/questions/19842066/… 【参考方案1】:

更新 从 v0.20 开始,melt 是一阶函数,现在可以使用

df.melt(id_vars=["location", "name"], 
        var_name="Date", 
        value_name="Value")

  location    name        Date  Value
0        A  "test"    Jan-2010     12
1        B   "foo"    Jan-2010     18
2        A  "test"    Feb-2010     20
3        B   "foo"    Feb-2010     20
4        A  "test"  March-2010     30
5        B   "foo"  March-2010     25

旧(ER)版本:

您可以使用pd.melt 获取大部分路径,然后进行排序:

>>> df
  location  name  Jan-2010  Feb-2010  March-2010
0        A  test        12        20          30
1        B   foo        18        20          25
>>> df2 = pd.melt(df, id_vars=["location", "name"], 
                  var_name="Date", value_name="Value")
>>> df2
  location  name        Date  Value
0        A  test    Jan-2010     12
1        B   foo    Jan-2010     18
2        A  test    Feb-2010     20
3        B   foo    Feb-2010     20
4        A  test  March-2010     30
5        B   foo  March-2010     25
>>> df2 = df2.sort(["location", "name"])
>>> df2
  location  name        Date  Value
0        A  test    Jan-2010     12
2        A  test    Feb-2010     20
4        A  test  March-2010     30
1        B   foo    Jan-2010     18
3        B   foo    Feb-2010     20
5        B   foo  March-2010     25

(可能想输入.reset_index(drop=True),只是为了保持输出干净。)

注意pd.DataFrame.sorthas been deprecated支持pd.DataFrame.sort_values

【讨论】:

@DSM 这个函数的反函数是什么。即如何将df2 [返回] 转换为df @3kstc 试试here 或here。你想研究枢轴。可能是pandas.pivot_table(df2,values='Value',index=['location','name'],columns='Date').reset_index() @DSM 有没有办法倒退?这意味着我有很多同名的行,我希望所有日期都在不同的列上 @Adrian 您可以在 df 操作上取消熔化/反向熔化(也称为旋转)。有关更多详细信息,请查看此***.com/questions/28337117/…【参考方案2】:

set_indexstack 一起用于MultiIndex Series,然后为DataFrame 添加reset_indexrename

df1 = (df.set_index(["location", "name"])
         .stack()
         .reset_index(name='Value')
         .rename(columns='level_2':'Date'))
print (df1)
  location  name        Date  Value
0        A  test    Jan-2010     12
1        A  test    Feb-2010     20
2        A  test  March-2010     30
3        B   foo    Jan-2010     18
4        B   foo    Feb-2010     20
5        B   foo  March-2010     25

【讨论】:

【参考方案3】:

我想我找到了一个更简单的解决方案

temp1 = pd.melt(df1, id_vars=["location"], var_name='Date', value_name='Value')
temp2 = pd.melt(df1, id_vars=["name"], var_name='Date', value_name='Value')

连接整个temp1temp2 的列name

temp1['new_column'] = temp2['name']

你现在得到了你想要的。

【讨论】:

【参考方案4】:

pd.wide_to_long

您可以在年份列中添加前缀,然后直接提供给pd.wide_to_long。我不会假装这是高效,但在某些情况下它可能比pd.melt 更方便,例如当您的列已经有适当的前缀时。

df.columns = np.hstack((df.columns[:2], df.columns[2:].map(lambda x: f'Valuex')))

res = pd.wide_to_long(df, stubnames=['Value'], i='name', j='Date').reset_index()\
        .sort_values(['location', 'name'])

print(res)

   name        Date location  Value
0  test    Jan-2010        A     12
2  test    Feb-2010        A     20
4  test  March-2010        A     30
1   foo    Jan-2010        B     18
3   foo    Feb-2010        B     20
5   foo  March-2010        B     25

【讨论】:

【参考方案5】:

添加一个可以复制的笔记本的链接,使用pandas.melt 演示@DMS 的答案:

df.melt(id_vars=["location", "name"], 
    var_name="date", 
    value_name="value")

https://deepnote.com/@DataScience/Unpivot-a-DataFrame-from-wide-to-long-format-lN7WlqOdSlqroI_7DGAkoA

【讨论】:

以上是关于使用 Pandas 将列转换为行的主要内容,如果未能解决你的问题,请参考以下文章

使用R将行转换为列,将列转换为行

Pandas - 在groupby之后将列转换为新行

MySQL将列转换为行

sql 将列数据转换为行

将列转换为行

将列转换为行