有条件地从dfs列表中选择数据帧

时间:2017-09-01 14:15:22

标签: python pandas numpy

我尝试使用函数对数据帧列表进行子集化。该函数将仅需要返回例如具有Z-列的总数> df的df。 14和X列值(行0-4)比这5个值的平均值低30%或高于30%。因此,在下面的示例中,将返回df1而不返回df2。

可以这样做,用这些条件评估每个数据帧吗?有人能指出我正确的方向吗?

N = 5                                                                                                                                    
np.random.seed(0)                                                                                                                                                    

df1 = pd.DataFrame(                                                                                                                                                  
         {'X':np.random.uniform(0,5,N),                                                                                                                               
          'Y':np.random.uniform(0,5,N),                                                                                                                               
          'Z':np.random.uniform(0,5,N),                                                                                                                               
               })                                                                                                                                                     
df2 = pd.DataFrame(                                                                                                                                                  
          {'X':np.random.uniform(0,5,N),                                                                                                                               
          'Y':np.random.uniform(0,5,N),                                                                                                                               
           'Z':np.random.uniform(0,5,N),                                                                                                                               
                })                                                                                                                                                     

df1.loc['total'] = df1.sum()                                                                                                                                         
df2.loc['total'] = df2.sum()                                                                                                                                         

df_list = (df1, df2)

               X          Y          Z
0       2.744068   3.229471   3.958625
1       3.575947   2.187936   2.644475
2       3.013817   4.458865   2.840223
3       2.724416   4.818314   4.627983
4       2.118274   1.917208   0.355180
total  14.176521  16.611793  14.426486
--------------------------------------
               X          Y          Z
0       0.435646   4.893092   3.199605
1       0.101092   3.995793   0.716766
2       4.163099   2.307397   4.723345
3       3.890784   3.902646   2.609242
4       4.350061   0.591372   2.073310
total  12.940682  15.690299  13.322267

2 个答案:

答案 0 :(得分:2)

可以使用列表理解,具有2个陈述的条件。

Z条件非常简单易行。关于X条件,我创建了一个小函数,如果数据帧与条件匹配则返回True,否则为False。

In [156]: def check_X(df):
     ...:     avg = df.drop('total')['X'].mean()
     ...:     for val in df.drop('total')['X']:
     ...:         if val/avg < 0.7 or val/avg > 1.3:  #30% more or less
     ...:             return False
     ...:     return True
     ...: 

因此,我们可以通过以下方式获得预期结果:

In [157]: [df for df in df_list if df.drop('total')['Z'].sum() > 14 and check_X(df)]
Out[157]: 
[               X          Y          Z
 0       2.744068   3.229471   3.958625
 1       3.575947   2.187936   2.644475
 2       3.013817   4.458865   2.840223
 3       2.724416   4.818314   4.627983
 4       2.118274   1.917208   0.355180
 total  14.176522  16.611794  14.426486]

编辑:一个更好的单线解决方案,不使用任何用户定义的功能:

In [205]: [df for df in df_list if df['Z'].sum() > 14 and ((df['X'] > df['X'].mean()*0.7) & (df['X'] < df['X'].mean()*1.3)).all()]
Out[205]: 
[          X         Y         Z
 0  2.744068  3.229471  3.958625
 1  3.575947  2.187936  2.644475
 2  3.013817  4.458865  2.840223
 3  2.724416  4.818314  4.627983
 4  2.118274  1.917208  0.355180]

为简单起见,我放弃了总数&#39;在处理前从两个df行:

In [204]: df_list = [df.drop('total') for df in df_list]

答案 1 :(得分:1)

如果您有数据框列表,则使用列表推导有条件地选择数据框,您可以使用切片(iloc[0:-1]排除最后一行)。

new_list= [x for x in df_list if (x.loc['total','Z']>14) and 
      ((x.iloc[0:-1]['X'] > x.iloc[0:-1]['X'].mean()*0.7) & (x.iloc[0:-1]['X'] < x.iloc[0:-1]['X'].mean()*1.3)).all()]

输出:

[               X          Y          Z
 0       2.744068   3.229471   3.958625
 1       3.575947   2.187936   2.644475
 2       3.013817   4.458865   2.840223
 3       2.724416   4.818314   4.627983
 4       2.118274   1.917208   0.355180
 total  14.176521  16.611793  14.426486]