[英]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)
替换缺失的级别来模拟set1
和set2
的这种行为:
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.