枚举具有相同前缀的列

Erf*_*fan 8 python dataframe pandas

假设我们有以下简化数据:

df = pd.DataFrame({'A':list('abcd'),
                   'B':list('efgh'),
                   'Data_mean':[1,2,3,4],
                   'Data_std':[5,6,7,8],
                   'Data_corr':[9,10,11,12],
                   'Text_one':['foo', 'bar', 'foobar', 'barfoo'],
                   'Text_two':['bar', 'foo', 'barfoo', 'foobar'],
                   'Text_three':['bar', 'bar', 'barbar', 'foofoo']})

   A  B  Data_mean  Data_std  Data_corr Text_one Text_two Text_three
0  a  e          1         5          9      foo      bar        bar
1  b  f          2         6         10      bar      foo        bar
2  c  g          3         7         11   foobar   barfoo     barbar
3  d  h          4         8         12   barfoo   foobar     foofoo
Run Code Online (Sandbox Code Playgroud)

我想枚举具有相同前缀的列。在这种情况下,前缀为Data, Text。因此,预期输出为:

   A  B  Data_mean1  Data_std2  Data_corr3 Text_one1 Text_two2 Text_three3
0  a  e           1          5           9       foo       bar         bar
1  b  f           2          6          10       bar       foo         bar
2  c  g           3          7          11    foobar    barfoo      barbar
3  d  h           4          8          12    barfoo    foobar      foofoo
Run Code Online (Sandbox Code Playgroud)

请注意枚举的列。


尝试的解决方案1

def enumerate_cols(dataframe, prefix):
    cols = []
    num = 1
    for col in dataframe.columns:
        if col.startswith(prefix):
            cols.append(col + str(num))
            num += 1
        else:
            cols.append(col)

    return cols
Run Code Online (Sandbox Code Playgroud)
enumerate_cols(df, 'Data')

['A',
 'B',
 'Data_mean1',
 'Data_std2',
 'Data_corr3',
 'Text_one',
 'Text_two',
 'Text_three']
Run Code Online (Sandbox Code Playgroud)

尝试的解决方案2:

[c+str(x+1) for x, c in enumerate([col for col in df.columns if col.startswith('Data')])]
Run Code Online (Sandbox Code Playgroud)
['Data_mean1', 'Data_std2', 'Data_corr3']
Run Code Online (Sandbox Code Playgroud)

问题:是否有更简单的解决方案可以做到这一点,我也查看过df.filter(like='Data')etc。但是那看起来也很牵强。


XY问题
只要确定我没有陷入XY问题。我想使用pd.wide_to_long,但是stubnames列必须加一个数字后缀才能融化数据框。

从文档中引用:

对于存根名称['A','B'],此函数希望查找格式为A-后缀1,A-后缀2,…,B-后缀1,B-后缀2,

pd.wide_to_long(df, stubnames=['Data', 'Text'], i=['A', 'B'], j='grp', sep='_')
Run Code Online (Sandbox Code Playgroud)

这将返回一个空的数据框。

cs9*_*s95 3

这个想法是将具有相同前缀的列分组,并为它们建立一个 cumcount。

GroupBy.cumcount由于我们需要单独处理没有前缀的列,因此我们需要使用和分两步执行此操作np.where

cols = df.columns.str.split('_').str[0].to_series()

df.columns = np.where(
    cols.groupby(level=0).transform('count') > 1, 
    cols.groupby(level=0).cumcount().add(1).astype(str).radd(df.columns), 
    cols
)
Run Code Online (Sandbox Code Playgroud)

df
   A  B  Data_mean1  Data_std2  Data_corr3 Text_one1 Text_two2 Text_three3
0  a  e           1          5           9       foo       bar         bar
1  b  f           2          6          10       bar       foo         bar
2  c  g           3          7          11    foobar    barfoo      barbar
3  d  h           4          8          12    barfoo    foobar      foofoo
Run Code Online (Sandbox Code Playgroud)

一个更简单的解决方案是将您不想添加后缀的列设置为索引。然后你可以简单地做

df.set_index(['A', 'B'], inplace=True)
df.columns = (
    df.columns.str.split('_')
      .str[0]
      .to_series()
      .groupby(level=0)
      .cumcount()
      .add(1)
      .astype(str)
      .radd(df.columns))

df
     Data_mean1  Data_std2  Data_corr3 Text_one1 Text_two2 Text_three3
A B                                                                   
a e           1          5           9       foo       bar         bar
b f           2          6          10       bar       foo         bar
c g           3          7          11    foobar    barfoo      barbar
d h           4          8          12    barfoo    foobar      foofoo
Run Code Online (Sandbox Code Playgroud)