【问题标题】:pandas select multiple columns conditionally熊猫有条件地选择多列
【发布时间】:2017-05-16 04:09:14
【问题描述】:

假设我有一个数据框:

C1 V1 C2 V2 Cond
1  2  3  4  X  
5  6  7  8  Y  
9  10 11 12 X

语句应返回:if Cond == X, pick C1 and C2, else pick C2 and V2

输出数据框类似于:

C  V 
1  2 
7  8
9  10

** 编辑:再添加一个要求:列数可以更改,但遵循一些命名模式。在这种情况下,选择其中包含“1”的所有列,否则选择“2”。我认为硬编码的解决方案可能不起作用。

【问题讨论】:

  • indexer = {'X': ['C1', 'V1'], 'Y': ['C2', 'V2']}; pd.concat([pd.DataFrame(df.loc[df.Cond==k, v].values, columns= ['C','V']) for k,v in indexer.items()]) 是这样做的一种方法,但它不保留行的顺序。

标签: python pandas conditional extract multiple-columns


【解决方案1】:

DataFrame.where() 的另一个选项:

df[['C1', 'V1']].where(df.Cond == "X", df[['C2', 'V2']].values)

#  C1   V1
#0  1    2
#1  7    8
#2  9   10

【讨论】:

    【解决方案2】:

    我尝试使用filternumpy.where 创建更通用的解决方案,对于新列名使用extract

    #if necessary sort columns
    df = df.sort_index(axis=1)
    
    #filter df by 1 and 2
    df1 = df.filter(like='1')
    df2 = df.filter(like='2')
    print (df1)
       C1  V1
    0   1   2
    1   5   6
    2   9  10
    
    print (df2)
       C2  V2
    0   3   4
    1   7   8
    2  11  12
    
    #np.where need same shape of mask as df1 and df2
    mask = pd.concat([df.Cond == 'X']*len(df1.columns), axis=1)
    print (mask)
        Cond   Cond
    0   True   True
    1  False  False
    2   True   True
    
    cols = df1.columns.str.extract('([A-Za-z])', expand=False)
    print (cols)
    Index(['C', 'V'], dtype='object')
    
    print (np.where(mask, df1,df2))
    Index(['C', 'V'], dtype='object')
    [[ 1  2]
     [ 7  8]
     [ 9 10]]
    
    print (pd.DataFrame(np.where(mask, df1, df2), index=df.index, columns=cols))
       C   V
    0  1   2
    1  7   8
    2  9  10
    

    【讨论】:

      【解决方案3】:
      • drop Cond 专注于我从中选择的值
      • reshape numpy 数组,所以我可以用布尔值区分
      • 使用np.arange(len(df)) 索引第一个维度,每行一次
      • df.Cond.ne('X').mul(1) 索引第二个维度。 0 等于 X
      • 构建最终数据帧

      pd.DataFrame(
          df.drop('Cond', 1).values.reshape(3, 2, 2)[
              np.arange(len(df)),
              df.Cond.ne('X').mul(1)
          ], df.index, ['C', 'V'])
      
         C   V
      0  1   2
      1  7   8
      2  9  10
      

      【讨论】:

        【解决方案4】:

        如果行的顺序不重要,您可以使用df.locdf.append

        ndf1 = df.loc[df['Cond'] == 'X', ['C1','V1']]
        ndf2 = df.loc[df['Cond'] == 'Y', ['C2','V2']]
        ndf1.columns = ['C','V']
        ndf2.columns = ['C','V']
        
        result = ndf1.append(ndf2).reset_index(drop=True)
        print(result)
           C   V
        0  1   2
        1  9  10
        2  7   8
        

        【讨论】:

          【解决方案5】:

          您可以尝试使用类似于this post 的方法

          首先,定义几个函数:

          def cond(row):
              return row['Cond'] == 'X'
          
          def helper(row, col_if, col_ifnot):
              return row[col_if] if cond(row) else row[col_ifnot]
          

          然后,假设您的数据框名为df

          df_new = pd.DataFrame(index=df.index)
          for col in ['C', 'V']:
              col_1 = col + '1'
              col_2 = col + '2'
              df_new[col] = df.apply(lambda row: helper(row, col_1, col_2), axis=1)
          

          请记住,这种方法对于大型数据帧可能会很慢,因为apply 没有利用矢量化。但是,它甚至可以使用任意列名(只需将 ['C', 'V'] 替换为您的实际列名)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-04-27
            • 1970-01-01
            • 2013-08-19
            • 1970-01-01
            • 2021-12-21
            • 1970-01-01
            • 2019-08-14
            • 2023-02-20
            相关资源
            最近更新 更多