删除列名的后缀并取消透视

Posted

技术标签:

【中文标题】删除列名的后缀并取消透视【英文标题】:Remove suffix of the column names and unpivot 【发布时间】:2021-09-11 08:15:56 【问题描述】:

我想使用列名“Year”、“Item”和“$”对下表进行反透视。我的解决方法是将表格分成两个数据框并删除后缀,然后垂直连接两列。还有其他更简单的方法来解决这个问题吗?

示例数据框:

data = 'Year_x': [1993, 1994, 1995, 1996], 
       'Year_y': [2000, 2001, 2002, 2003],
       'Item_x':['A','B','C','D'],
       'Item_y':['E','F','G','H'],
       '$':[3,4,5,6]

pd.DataFrame.from_dict(data)
Year_x Year_y Item_x Item_y $
1993 2000 A E 3
1994 2001 B F 4
1995 2002 C G 5
1996 2003 D H 6

我想要达到的目标:

Year Item $
1993 A 3
1994 B 4
1995 C 5
1995 D 6
2000 E 3
2001 F 4
2002 G 5
2003 H 6

【问题讨论】:

使用pyjanitor,您也可以实现这一点:import janitor; df.pivot_longer(index = "$", names_to=".value", names_pattern=r"(.+)_.*") 【参考方案1】:

使用DataFrame.set_index 将不带分隔符的列_ 转换为索引,然后将列名称拆分为MultiIndex

cols = ['$']
#if multiple columns
cols = ['$', '$Column1', '$Column2']
df1 = df.set_index(cols)

df1.columns = df1.columns.str.split('_', expand=True)
df1 = (df1.stack()
          .sort_values(['Item','Year'])
          .reset_index()[['Year','Item'] + cols])
print (df1)
   Year Item  $
0  1993    A  3
1  1994    B  4
2  1995    C  5
3  1996    D  6
4  2000    E  3
5  2001    F  4
6  2002    G  5
7  2003    H  6

【讨论】:

感谢您的回复。如果我有多个值列,例如 $Column1、$ Column2、$Column3,该怎么办?我不能将它们全部设置为索引对吗? @Jamie - 当然,准确。 如果有'$Column1'和'$Column2',我认为reset_index级别部分会消除它们 @Jamie - 你是对的,先删除reset_index【参考方案2】:

与列表理解的连接

>>> pd.concat([df[["Year_" + c, "Item_" + c, "$"]].rename("Year_" + c : "Year", "Item_" + c : "Item", axis=1) for c in ("x", "y")]).reset_index(drop=True)
   Year Item  $
0  1993    A  3
1  1994    B  4
2  1995    C  5
3  1996    D  6
4  2000    E  3
5  2001    F  4
6  2002    G  5
7  2003    H  6

或者,通过pd.wide_to_long(...)

>>> pd.wide_to_long(df, ["Year", "Item"], i=["$"], j="Var", sep="_", suffix="\w+").reset_index()
   $ Var  Year Item
0  3   x  1993    A
1  4   x  1994    B
2  5   x  1995    C
3  6   x  1996    D
4  3   y  2000    E
5  4   y  2001    F
6  5   y  2002    G
7  6   y  2003    H

【讨论】:

感谢您的回复。如果像我上面给出的示例那样只需要编辑几个列名,这将非常有效,但通常会有更多。 添加了另一个使用标准 pandas 工具的示例wide_to_long 我喜欢你的第二种方法。我知道这是正则表达式,但你能解释一下“\w+”吗?它有什么作用? @Jamie \w+ 匹配sep='_' 符号后面的一个或多个字符。默认情况下, pd.wide_to_long 会查找数字。查看它的帮助页面,写得很好pandas.pydata.org/pandas-docs/stable/reference/api/…【参考方案3】: step1,查找列的后缀
df_col = pd.DataFrame(df.columns.str.split('_').tolist())
df_col['col'] = df.columns.tolist()
print(df_col)

    #       0     1     col
    # 0  Year     x  Year_x
    # 1  Year     y  Year_y
    # 2  Item     x  Item_x
    # 3  Item     y  Item_y
    # 4     $  None       $
第二步,处理输出列
cond =  df_col[1].isnull()
cols_without_subfix = df_col.loc[cond, 'col'].tolist()
obj = df_col[~cond].groupby(1)['col'].agg(list)
obj = obj.map(lambda x: x + cols_without_subfix)
print(obj)

    # 1
    # x    [Year_x, Item_x, $]
    # y    [Year_y, Item_y, $]
    # Name: col, dtype: object
第三步,迭代输出列并连接它们。
df_list = []
for i in obj:
    dfn = df[i]
    dfn.columns = dfn.columns.str.split('_').str[0]
    df_list.append(dfn)
df_output = pd.concat(df_list)    
print(df_output)

    #    Year Item  $
    # 0  1993    A  3
    # 1  1994    B  4
    # 2  1995    C  5
    # 3  1996    D  6
    # 0  2000    E  3
    # 1  2001    F  4
    # 2  2002    G  5
    # 3  2003    H  6

【讨论】:

以上是关于删除列名的后缀并取消透视的主要内容,如果未能解决你的问题,请参考以下文章

Pandas批量删除dataframe列名中的后缀实战:使用rstrip函数批量删除列名中的后缀(suffix)使用replace函数批量删除列名中的后缀(suffix)

使用列名取消透视

如何删除透视表中的很多汇总行

怎么全部取消excel2003数据透视表中的分类汇总

快速取消数据透视表的分类汇总行和总计行

使用 column_name 函数取消透视表