将 df 列逆透视为多列和多行

时间:2021-01-18 16:07:41

标签: python pandas pivot

我有一个这样的 df:

Country  Industry   2011_0-9_AF    2011_0-9_AP
US        AB            0               0
US        AC           12.34           12.4
UK        AB            1               2
UK        AC            12              5

因此,在我的原始数据框中,对于我拥有 3 个行业的每个国家/地区,我有 4 个国家/地区,并且我有 1120 列,例如 2011_0-9_AF 等。

我需要像这样转换df:

Country  Industry   Year   Group_Type    Tags    Value
US        AB         2011   0-9          AF      0
US        AB         2011   0-9          AP      0
US        AC         2011   0-9          AF      12.34
US        AC         2011   0-9          AP      12.4

对于英国和其他国家/地区也是如此。所以,我希望将列分成 4 列,从开始到第一个下划线的值是 Year,然后是 Group_Type,然后是 Tags,然后是它在 Value 中的值专栏

我能够在 PowerBI 中创建相同的文件,但由于它有 1120 列,因此已经花费了 2 个多小时并且仍在运行,我有 5 个这样的文件。

正在寻找可以在 Python 中更快的解决方案?

4 个答案:

答案 0 :(得分:7)

你可以试试melt它然后split变量列_

long_df = pd.melt(df, id_vars=['Country', 'Industry'])
long_df[['Year', 'Group_Type', 'Tags']] = long_df.variable.str.split('_', expand=True)

long_df.drop('variable', axis=1)
#  Country Industry  value  Year Group_Type Tags
#0      US       AB   0.00  2011        0-9   AF
#1      US       AC  12.34  2011        0-9   AF
#2      UK       AB   1.00  2011        0-9   AF
#3      UK       AC  12.00  2011        0-9   AF
#4      US       AB   0.00  2011        0-9   AP
#5      US       AC  12.40  2011        0-9   AP
#6      UK       AB   2.00  2011        0-9   AP
#7      UK       AC   5.00  2011        0-9   AP

答案 1 :(得分:2)

你应该检查https://pandas.pydata.org/docs/reference/api/pandas.melt.html

import pandas as pd
import io

df = pd.read_csv(io.StringIO("""Country  Industry   2011_0-9_AF    2011_0-9_AP
US        AB            0               0
US        AC           12.34           12.4
UK        AB            1               2
UK        AC            12              5"""), sep='\s+')

# First melt (unpivot) the columns
df_melted = df.melt(id_vars=['Country', 'Industry'], var_name='Var', value_name='Value')

# Split "Var" column
df_2 = df_melted.Var.str.split('_',expand=True)
df_2.columns = ['Year', 'Group_Type' ,'Tags']
final_df = pd.concat([df_melted.drop(columns=['Var']), df_2], axis=1)

print(final_df)
>>>
  Country Industry  Value  Year Group_Type Tags
0      US       AB   0.00  2011        0-9   AF
1      US       AC  12.34  2011        0-9   AF
2      UK       AB   1.00  2011        0-9   AF
3      UK       AC  12.00  2011        0-9   AF
4      US       AB   0.00  2011        0-9   AP
5      US       AC  12.40  2011        0-9   AP
6      UK       AB   2.00  2011        0-9   AP
7      UK       AC   5.00  2011        0-9   AP

答案 2 :(得分:1)

试试 stackpd.MultiIndex

df = df.set_index(['Country','Industry'])
df.columns=pd.MultiIndex.from_tuples(df.columns.str.split('_').map(tuple))
out = df.stack(level=[0,1,2]).reset_index()

out
Out[56]: 
  Country Industry level_2 level_3 level_4      0
0      US       AB    2011     0-9      AF   0.00
1      US       AB    2011     0-9      AP   0.00
2      US       AC    2011     0-9      AF  12.34
3      US       AC    2011     0-9      AP  12.40
4      UK       AB    2011     0-9      AF   1.00
5      UK       AB    2011     0-9      AP   2.00
6      UK       AC    2011     0-9      AF  12.00
7      UK       AC    2011     0-9      AP   5.00

答案 3 :(得分:1)

使用pivot_longer中的pyjanitor函数可以抽象出重塑过程;目前您必须从 github:

安装最新的开发版本
 # install latest dev version
# pip install git+https://github.com/ericmjl/pyjanitor.git
 import janitor

df.pivot_longer(
    index=["Country", "Industry"],
    names_to=("Year", "Group_Type", "Tags"),
    names_sep="_",
    values_to="Value",
)

      Country     Industry  Year    Group_Type  Tags    Value
0        US          AB     2011        0-9     AF      0.00
1        US          AC     2011        0-9     AF      12.34
2        UK          AB     2011        0-9     AF      1.00
3        UK          AC     2011        0-9     AF      12.00
4        US          AB     2011        0-9     AP      0.00
5        US          AC     2011        0-9     AP      12.40
6        UK          AB     2011        0-9     AP      2.00
7        UK          AC     2011        0-9     AP      5.00

上面的代码根据 _ 字符拆分列并将输出分配给 names_to 中的新列名