繁体   English   中英

使用来自单独的部​​分 MultiIndex 的条目从 Pandas DataFrame 中选择行的子集

[英]Select subset of rows from pandas DataFrame using entries from a separate partial MultiIndex

我在带有 MultiIndex 的 Pandas DataFrame 中有数据。 让我们将我的 MultiIndex 的标签称为“Run”、“Trigger”和“Cluster”。 另外,我有一个预先计算的选择标准列表,作为传递的条目列表(这些往往是稀疏的,因此列出传递索引的空间效率最高)。 选择剪切可以仅部分索引,例如可以仅指定“运行”或(“运行”、“触发”)对。

我如何有效地应用这些切割,理想情况下无需检查它们以找到它们的水平?

例如,考虑以下数据:

index = pandas.MultiIndex.from_product([[0,1,2],[0,1,2],[0,1]], names=['Run','Trigger','Cluster'])
df = pandas.DataFrame(np.random.rand(len(index),3), index=index, columns=['a','b','c'])
print(df)

                            a         b         c
Run Trigger Cluster                              
0   0       0        0.789090  0.776966  0.764152
            1        0.196648  0.635954  0.479195
    1       0        0.007268  0.675339  0.966958
            1        0.055030  0.794982  0.660357
    2       0        0.987798  0.907868  0.583545
            1        0.114886  0.839434  0.070730
1   0       0        0.520827  0.626102  0.088976
            1        0.377423  0.934224  0.404226
    1       0        0.081669  0.485830  0.442296
            1        0.620439  0.537927  0.406362
    2       0        0.155784  0.243656  0.830895
            1        0.734176  0.997579  0.226272
2   0       0        0.867951  0.353823  0.541483
            1        0.615694  0.202370  0.229423
    1       0        0.912423  0.239199  0.406443
            1        0.188609  0.053396  0.222914
    2       0        0.698515  0.493518  0.201951
            1        0.415195  0.975365  0.687365

选择标准可以采用以下任何一种形式:

set1:
Int64Index([0], dtype='int64', name='Run')

set2:
MultiIndex([(0, 1),
            (1, 2)],
           names=['Run', 'Trigger'])
set3:
MultiIndex([(0, 0, 1),
            (1, 0, 1),
            (2, 1, 0)],
           names=['Run', 'Trigger', 'Cluster'])

使用假设的select方法应用这些选择列表将导致:

>>> print(df.select(set1))
                            a         b         c
Run Trigger Cluster                              
0   0       0        0.789090  0.776966  0.764152
            1        0.196648  0.635954  0.479195
    1       0        0.007268  0.675339  0.966958
            1        0.055030  0.794982  0.660357
    2       0        0.987798  0.907868  0.583545
            1        0.114886  0.839434  0.070730

>>> print(df.select(set2))
                            a         b         c
Run Trigger Cluster                              
0   1       0        0.007268  0.675339  0.966958
            1        0.055030  0.794982  0.660357
1   2       0        0.155784  0.243656  0.830895
            1        0.734176  0.997579  0.226272

>>> print(df.select(set3))
                            a         b         c
Run Trigger Cluster                              
0   0       1        0.196648  0.635954  0.479195
1   0       1        0.377423  0.934224  0.404226
2   1       0        0.912423  0.239199  0.406443

pandas 可以很容易地加入这些类型的混合级索引,所以这看起来应该是一个简单的操作,但我无法弄清楚写调用。 loc适用于 set3,因为索引的深度相同,但我需要一个通用的解决方案。

df.loc[set3]有效,因为set3具有索引的所有 3 个级别。 您可以通过用slicer(None)替换缺失的级别来模拟set1set2的这种行为:

def select(df, index):
    slicer = []
    for name in df.index.names:
        if name in index.names:
            values = index.get_level_values(name).values
        else:
            values = slice(None)
        slicer.append(values)

    return df.loc[tuple(slicer), :]

然后你可以使用:

select(df, set1)
select(df, set2)
select(df, set3)

如果您希望将其作为数据帧上的方法:

pd.DataFrame.select = select
df.select(set1) # etc.

请注意,这将忽略df.index不存在的index级别:

# there's no level "FooBar" in df
set4 = pd.MultiIndex.from_tuples([(0, 42)], names=['Trigger', 'FooBar'])
df.select(set4) # works just fine

我还没有测试过性能,如果你在一个紧密的循环中这样做,可能不会太快。

使用纯熊猫实现此目的的一种方法如下:

df.align(setN.to_series(), axis=0, join='inner')[0]

也就是说,将“其他”索引转换为系列并选择在内部联接操作期间将保留的每个部分。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM