【问题标题】:Selecting rows from pandas by subset of multiindex通过多索引的子集从熊猫中选择行
【发布时间】:2014-04-26 14:46:59
【问题描述】:

我在 pandas 中有一个多索引数据框,索引中有 4 列,还有一些数据列。下面是一个例子:

import pandas as pd
import numpy as np
cnames = ['K1', 'K2', 'K3', 'K4', 'D1', 'D2']
rdata = pd.DataFrame(np.random.randint(1, 3, size=(8, len(cnames))), columns=cnames)
rdata.set_index(cnames[:4], inplace=True)
rdata.sortlevel(inplace=True)
print(rdata)
             D1  D2
K1 K2 K3 K4        
1  1  1  1    1   2
         1    1   2
      2  1    2   1
   2  1  2    2   1
      2  1    2   1
2  1  2  2    2   1
   2  1  2    1   1
         2    1   1

[8 rows x 2 columns]

我想要做的是选择在 K3 级别恰好有 2 个值的行。不是 2 行,而是两个不同的值。我已经找到了如何为我想要的东西生成一种掩码:

filterFunc = lambda x: len(set(x.index.get_level_values('K3'))) == 2
mask = rdata.groupby(level=cnames[:2]).apply(filterFunc)
print(mask)
K1  K2
1   1      True
    2      True
2   1     False
    2     False
dtype: bool

而且我希望由于rdata.loc[1, 2] 允许您仅匹配索引的一部分,因此可以使用像这样的布尔向量来做同样的事情。不幸的是,rdata.loc[mask]IndexingError: Unalignable boolean Series key provided 失败。

This question 看起来很相似,但那里给出的答案除了顶级索引外,其他任何东西都不起作用,因为 index.get_level_values 仅适用于单个级别,而不适用于多个级别。

按照here的建议,我设法完成了我想要的

rdata[[mask.loc[k1, k2] for k1, k2, k3, k4 in rdata.index]]

但是,使用len(set(index.get_level_values(...))) 获取不同值的计数以及之后通过迭代每一行来构建布尔向量感觉更像是我在与框架作斗争以实现在多索引设置中看似简单的任务。有没有更好的解决方案?

这是使用 pandas 0.13.1。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    可能会有更好的东西,但您至少可以通过使用 groupby-filter 绕过定义 mask

    rdata.groupby(level=cnames[:2]).filter(
          lambda grp: (grp.index.get_level_values('K3')
                          .unique().size) == 2)
    
    Out[83]: 
                 D1  D2
    K1 K2 K3 K4        
    1  1  1  1    1   2
             1    1   2
          2  1    2   1
       2  1  2    2   1
          2  1    2   1
    
    [5 rows x 2 columns]
    

    这比我之前的建议要快。它非常适合小型 DataFrame:

    In [84]: %timeit rdata.groupby(level=cnames[:2]).filter(lambda grp: grp.index.get_level_values('K3').unique().size == 2)
    100 loops, best of 3: 3.84 ms per loop
    
    In [76]: %timeit rdata2.groupby(level=cnames[:2]).filter(lambda grp: grp.groupby(level=['K3']).ngroups == 2)
    100 loops, best of 3: 11.9 ms per loop
    
    In [77]: %timeit rdata2.groupby(level=cnames[:2]).filter(lambda grp: len(set(grp.index.get_level_values('K3'))) == 2)
    100 loops, best of 3: 13.4 ms per loop
    

    对于大型 DataFrames 来说仍然是最快的,尽管速度不是那么快:

    In [78]: rdata2 = pd.concat([rdata]*100000)
    
    In [85]: %timeit rdata2.groupby(level=cnames[:2]).filter(lambda grp: grp.index.get_level_values('K3').unique().size == 2)
    1 loops, best of 3: 756 ms per loop
    
    In [79]: %timeit rdata2.groupby(level=cnames[:2]).filter(lambda grp: grp.groupby(level=['K3']).ngroups == 2)
    1 loops, best of 3: 772 ms per loop
    
    In [80]: %timeit rdata2.groupby(level=cnames[:2]).filter(lambda grp: len(set(grp.index.get_level_values('K3'))) == 2)
    1 loops, best of 3: 1 s per loop
    

    【讨论】:

      猜你喜欢
      • 2014-06-21
      • 2020-01-12
      • 1970-01-01
      • 2017-03-12
      • 2018-09-27
      • 2019-01-26
      • 1970-01-01
      • 2020-07-17
      • 2017-10-30
      相关资源
      最近更新 更多