使用另一个DataFrame过滤Pandas DataFrame

5

我有一个多级索引的DataFrame,第一级是组ID,第二级是元素名称。有许多组,但仅下面显示了第一组。

                   2000-01-04  2000-01-05 
Group Element                                     
1       A          -0.011374    0.035895 
        X          -0.006910    0.047714 
        C          -0.016609    0.038705 
        Y          -0.088110   -0.052775 
        H           0.000000    0.008082 

我有另一个仅包含组ID的DataFrame,索引为1。两者的列都相同,都是日期。

         2000-01-04  2000-01-05 
Group                                     
1        -0.060623   -0.025429 
2        -0.066765   -0.005318 
3        -0.034459   -0.011243 
4        -0.051813   -0.019521 
5        -0.064367    0.014810 

我希望使用第二个数据框来过滤第一个数据框,通过检查每个元素是否小于该日期对应组的值,以获得如下结果:
                   2000-01-04  2000-01-05 
Group Element                                     
1       A          False        False     
        X          False        False     
        C          False        False     
        Y          True         True
        H          False        False     

最终,我只对那些为真的元素和它们为真的日期感兴趣。列出一份在日期迭代中为真的元素清单将是很好的,我已经想到了把False替换成NaN,并使用dropNa()函数来实现这个目标。
我知道我可以编写一堆嵌套的for循环来完成这个任务,但时间非常重要;我无法想到一种使用pandas数据框架本质上和pythonically去完成这个任务的方法。希望能得到任何帮助!
1个回答

4
你可以使用groupby apply来实现这个功能:
In [11]: g = df1.groupby(level='Group')

In [12]: g.apply(lambda x: x <= df2.loc[x.name])
Out[12]: 
              2000-01-04 2000-01-05
Group Element                      
1     A            False      False
      X            False      False
      C            False      False
      Y             True       True
      H            False      False

非常感谢!它运行得很好。只是出于兴趣,df2的值对应于每个组的平均值-标准差。我基本上正在尝试找到异常值。除了我现在所做的方法,还有更好的方法吗?此外,这仅查找低于阈值的异常值;我打算为上限创建另一个。但是否有更优雅的方法? - rmalhotra
@rmalhotra 我认为可能有,因为在上面的lambda表达式中,你可以访问组(作为x),所以你可以在那时计算它... - Andy Hayden
成功找到如下异常值:df.groupby(level=0).apply(lambda x: x < (x.mean() - x.std() * 2)),但是当我尝试这样做时:df.groupby(level=0).apply(lambda x: "Below" if x < (x.mean() - x.std() * 2) else "False"),我收到了一个数值错误。此外,是否有可能有多个if语句来检查“above”异常值? - rmalhotra
@rmalhotra 我认为你最好创建一个单独的函数(而不是将其放在lambda中),这样更容易进行测试。我怀疑这是将数组转换为布尔值(这将在0.13中正确引发),您可以使用类似于.where x.where((x < (x.mean() - x.std() * 2)), 'Below')的东西。但我建议使用布尔值或整数而不是字符串。例如:def f(x): mean = x.mean(); std_2 = x.std() * 2; return 1 * (x < mean - std_2) - 1 * (x > mean + std_2) - Andy Hayden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接