【问题标题】:Break dataframe header into multiheader将数据帧标头分解为多标头
【发布时间】:2021-04-05 13:00:47
【问题描述】:
Names ABCBaseCIP00 ABCBaseCIP01 ABCBaseCIP02 ABC1CIP00 ABC1CIP01 ABC1CIP02 ABC2CIP00 ABC2CIP01 ABC2CIP02
X 1 2 3 4 5 6 7 8 9
Y 1 2 3 4 5 6 7 8 9
Z 1 2 3 4 5 6 7 8 9

我有上面的数据框,我希望按名称(ABCBase|ABC1|ABC2) 和代码(CIP00|CIP01|CIP02|CIP00|CIP01|CIP02|CIP00|CIP01|CIP02)分解列标题,以获得下表作为输出。

谁能建议如何在熊猫中做到这一点?这是动态数据,所以不想硬编码任何东西。

ABCBase ABCBase ABCBase ABC1 ABC1 ABC1 ABC2 ABC2 ABC2
Names CIP00 CIP01 CIP02 CIP00 CIP01 CIP02 CIP00 CIP01 CIP02
X 1 2 3 4 5 6 7 8 9
Y 1 2 3 4 5 6 7 8 9
Z 1 2 3 4 5 6 7 8 9

【问题讨论】:

  • this 会回答您的问题吗?还是您真的在寻找单独的标题?

标签: python-3.x pandas dataframe


【解决方案1】:

这是一种使用字符串操作和 pd.MultiIndex 与from_arrays 的方法:

df = df.set_index('Names')

cols = df.columns.str.extract('(ABC(?:Base|\d))(.*)')
df.columns = pd.MultiIndex.from_arrays([cols[0], cols[1]], names=[None, None])

df

输出:

      ABCBase              ABC1              ABC2            
        CIP00 CIP01 CIP02 CIP00 CIP01 CIP02 CIP00 CIP01 CIP02
Names                                                        
X           1     2     3     4     5     6     7     8     9
Y           1     2     3     4     5     6     7     8     9
Z           1     2     3     4     5     6     7     8     9

或者,

df.columns = pd.MultiIndex\
               .from_arrays(zip(*df.columns.str.extract('(ABC(?:Base|\d))(.*)')\
               .to_numpy()))

【讨论】:

    【解决方案2】:
    import pandas as pd
    data = { 'names' : ['x','y','z'],
             'ABCBaseCIP00' : [1,1,1],
             'ABCBaseCIP01' : [2,2,2],
             'ABCBaseCIP02' : [3,3,3],
             'ABC1CIP00' : [4,4,4],
             'ABC1CIP01' : [5,5,5]}
    df = pd.DataFrame(data)
    

    给予

        names   ABCBaseCIP00    ABCBaseCIP01    ABCBaseCIP02    ABC1CIP00   ABC1CIP01
    0   x       1               2               3               4           5
    1   y       1               2               3               4           5
    2   z       1               2               3               4           5
    

    现在开始工作

    df1 = df.T
    df1.reset_index(inplace=True)
    df1['name']=df1['index'].str[-5:]
    df1['subname']=df1['index'].str[0:-5]
    
    df1 = df1.drop('index',axis=1)
    df1 = df1.T
    

    给了

                0       1       2       3       4       5
    0           x       1       2       3       4       5
    1           y       1       2       3       4       5
    2           z       1       2       3       4       5
    name        names   CIP00   CIP01   CIP02   CIP00   CIP01
    subname     ABCBase ABCBase ABCBase ABC1    ABC1    ABC1  
    

    这不是你想要的,但它足够接近吗?

    【讨论】:

      【解决方案3】:

      此问题的单行解决方案:

      df.columns = df.columns.str.split('(CIP.+)', expand=True).droplevel(2)
      

      完整示例:

      from pandas import DataFrame, Index
      df = DataFrame(
        { 'ABCBaseCIP00': [1,1,1],
          'ABCBaseCIP01': [2,2,2],
          'ABCBaseCIP02': [3,3,3],
          'ABC1CIP00': [4,4,4],
          'ABC1CIP01': [5,5,5] }, 
        index=Index(list('XYZ'), name='Names')
        )
      df.columns = df.columns.str.split('(CIP.+)', expand=True).droplevel(2)
      # df outputs:
            ABCBase              ABC1      
              CIP00 CIP01 CIP02 CIP00 CIP01
      Names                                
      X           1     2     3     4     5
      Y           1     2     3     4     5
      Z           1     2     3     4     5
      

      它是如何工作的:

      1. 正则表达式CIP.+ 匹配2 级的开始。 方括号 () 创建一个捕获组,以便由.str.split 返回
      2. 拆分和扩展索引会创建一个多索引
      3. 生成的多索引有一个额外的级别,用.droplevel(2) 删除

      【讨论】:

        猜你喜欢
        • 2017-10-08
        • 2017-11-11
        • 2021-08-28
        • 1970-01-01
        • 1970-01-01
        • 2011-04-25
        • 2020-06-30
        • 1970-01-01
        • 2019-02-08
        相关资源
        最近更新 更多