【问题标题】:Pandas combining sparse columns in dataframe熊猫在数据框中组合稀疏列
【发布时间】:2020-07-05 14:18:16
【问题描述】:

我正在使用 Python、Pandas 进行数据分析。我在不同的列中有稀疏分布的数据,如下所示

| id | col1a | col1b | col2a | col2b | col3a | col3b |
|----|-------|-------|-------|-------|-------|-------|
|  1 |   11  |   12  |  NaN  |  NaN  |  NaN  |  NaN  |
|  2 |  NaN  |  NaN  |   21  |   86  |  NaN  |  NaN  |
|  3 |   22  |   87  |  NaN  |  NaN  |  NaN  |  NaN  |
|  4 |  NaN  |  NaN  |   NaN |  NaN  |  545  |   32  |

我想将这些分散在不同列中的数据组合成紧密排列的列,如下所示。

| id | group |  cola |  colb |
|----|-------|-------|-------|
| 1  |  g1   |   11  |   12  |
| 2  |  g2   |   21  |   86  |
| 3  |  g1   |   22  |   87  |
| 4  |  g3   |  545  |   32  |

我尝试做的是跟随,但不能正确地做到这一点

df['cola']=np.nan
df['colb']=np.nan
df['cola'].fillna(df.col1a,inplace=True)
df['colb'].fillna(df.col1b,inplace=True)
df['cola'].fillna(df.col2a,inplace=True)
df['colb'].fillna(df.col2b,inplace=True)
df['cola'].fillna(df.col3a,inplace=True)
df['colb'].fillna(df.col3b,inplace=True)

但我认为必须有更简洁有效的方式来做到这一点。如何以更好的方式做到这一点?

【问题讨论】:

  • 如果你的数字都是正数,你可以fillna(value=0)然后添加列。
  • 请客观地解释您所说的“更好”是什么意思,否则可能会因为主要基于意见而被关闭。具体来说,考虑一下您认为当前的执行方式是不可接受的。
  • 这里我将更好的定义为更简洁、更高效的代码。我也改了问题。

标签: python pandas dataframe


【解决方案1】:

您可以使用df.stack() 假设'id' 是您的索引,否则将'id' 设置为索引。然后使用pd.pivot_table

df = df.stack().reset_index(name='val',level=1)
df['group'] = 'g'+ df['level_1'].str.extract('col(\d+)')
df['level_1'] = df['level_1'].str.replace('col(\d+)','')
df.pivot_table(index=['id','group'],columns='level_1',values='val')

level_1    cola  colb
id group
1  g1      11.0  12.0
2  g2      21.0  86.0
3  g1      22.0  87.0
4  g3     545.0  32.0

【讨论】:

    【解决方案2】:

    pd.wide_to_long 的另一种选择

    m = pd.wide_to_long(df,['col'],'id','j',suffix='\d+\w+').reset_index()
    
    (m.join(pd.DataFrame(m.pop('j').agg(list).tolist()))
      .assign(group=lambda x:x[0].radd('g'))
      .set_index(['id','group',1])['col'].unstack().dropna()
      .rename_axis(None,axis=1).add_prefix('col').reset_index())
    

       id group cola colb
    0   1    g1   11   12
    1   2    g2   21   86
    2   3    g1   22   87
    3   4    g3  545   32
    

    【讨论】:

      【解决方案3】:

      用途:

      import re
      
      def fx(s):
          s = s.dropna()
          group = 'g' + re.search(r'\d+', s.index[0])[0]
          return pd.Series([group] + s.tolist(), index=['group', 'cola', 'colb'])
      
      df1 = df.set_index('id').agg(fx, axis=1).reset_index()
      

      # print(df1)
      
         id   group  cola   colb
      0   1    g1    11.0   12.0
      1   2    g2    21.0   86.0
      2   3    g1    22.0   87.0
      3   4    g3    545.0  32.0
      

      【讨论】:

        【解决方案4】:

        这是一种方法:

        df = pd.DataFrame({'id':[1,2,3,4],
                           'col1a':[11,np.nan,22,np.nan],
                           'col1b':[12,np.nan,87,np.nan],
                           'col2a':[np.nan,21,np.nan,np.nan],
                           'col2b':[np.nan,86,np.nan,np.nan],
                           'col3a':[np.nan,np.nan,np.nan,545],
                           'col3b':[np.nan,np.nan,np.nan,32]})
        df_new = df.copy(deep=False)
        df_new['group'] = 'g'+df_new['id'].astype(str)
        df_new['cola'] = df_new[[x for x in df_new.columns if x.endswith('a')]].sum(axis=1)
        df_new['colb'] = df_new[[x for x in df_new.columns if x.endswith('b')]].sum(axis=1)
        df_new = df_new[['id','group','cola','colb']]
        print(df_new)
        

        输出:

          id group   cola  colb
        0   1    g1   11.0  12.0
        1   2    g2   21.0  86.0
        2   3    g3   22.0  87.0
        3   4    g4  545.0  32.0
        

        因此,如果您有更多后缀(colc、cold、cole、colf 等),您可以创建一个循环,然后使用:

        suffixes = ['a','b','c','d','e','f']
        cols = ['id','group'] + ['col'+x for x in suffixes]
        for i in suffixes:
           df_new['col'+i] = df_new[[x for x in df_new.columns if x.endswith(i)]].sum(axis=1)
        df_new = df_new[cols]
        

        【讨论】:

          【解决方案5】:

          感谢@CeliusStingher 为数据框提供代码:

          一个建议是将 id 设置为索引,重新排列列,并使用从文本中提取的数字。创建一个multiIndex,并堆栈以获得最终结果:

          #set id as index
          df = df.set_index("id")
          
          #pull out the numbers from each column
          #so that you have (cola,1), (colb,1) ...
          #add g to the numbers ... (cola, g1),(colb,g1), ...
          #create a MultiIndex
          #and reassign to the columns
          df.columns = pd.MultiIndex.from_tuples([("".join((first,last)), f"g{second}")
                                                  for first, second, last
                                                  in df.columns.str.split("(\d)")],
                                                 names=[None,"group"])
          
          #stack the data 
          #to get your result
          df.stack()
          
          
                           cola   colb
              id  group       
              1   g1      11.0    12.0
              2   g2      21.0    86.0
              3   g1      22.0    87.0
              4   g3      545.0   32.0
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-09-04
            • 2014-05-06
            • 1970-01-01
            • 2021-12-14
            • 2018-04-28
            • 2018-05-25
            • 1970-01-01
            • 2016-10-03
            相关资源
            最近更新 更多