基于布尔值从一片多索引数据帧中删除行
Posted
技术标签:
【中文标题】基于布尔值从一片多索引数据帧中删除行【英文标题】:Drop rows from a slice of Multi-Index DataFrame based on boolean 【发布时间】:2021-12-18 21:28:32 【问题描述】:编辑:根据要求,我提供了一个更接近我正在使用的真实数据的示例。
所以我有一张桌子data
,看起来像
value0 value1 value2
run step
0 0 0.12573 -0.132105 0.640423
1 0.1049 -0.535669 0.361595
2 1.304 0.947081 -0.703735
3 -1.265421 -0.623274 0.041326
4 -2.325031 -0.218792 -1.245911
5 -0.732267 -0.544259 -0.3163
1 0 0.411631 1.042513 -0.128535
1 1.366463 -0.665195 0.35151
2 0.90347 0.094012 -0.743499
3 -0.921725 -0.457726 0.220195
4 -1.009618 -0.209176 -0.159225
5 0.540846 0.214659 0.355373
(想想:时间序列的集合)和第二张表valid_range
start stop
run
0 1 3
1 2 5
对于每个run
,我想删除所有不满足start≤step≤stop
的行。
我尝试了以下(最后生成表格的代码)
for idx in valid_range.index:
slc = data.loc[idx]
start, stop = valid_range.loc[idx]
cond = (start <= slc.index) & (slc.index <= stop)
data.loc[idx] = data.loc[idx][cond]
但是,这会导致:
value0 value1 value2
run step
0 0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
5 NaN NaN NaN
1 0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
5 NaN NaN NaN
我也试过data.loc[idx].drop(slc[cond].index, inplace=True)
,但没有任何效果...
为表格生成代码
import numpy as np
from pandas import DataFrame, MultiIndex, Index
rng = np.random.default_rng(0)
valid_range = DataFrame("start": [1, 2], "stop":[3, 5], index=Index(range(2), name="run"))
midx = MultiIndex(levels=[[],[]], codes=[[],[]], names=["run", "step"])
data = DataFrame(columns=[f"valuek" for k in range(3)], index=midx)
for run in range(2):
for step in range(6):
data.loc[(run, step), :] = rng.normal(size=(3))
)
【问题讨论】:
预期输出是什么?你不想要df[df['small'] > 1]
@HarryPlotter 这只是虚拟数据和虚拟条件。我的真实数据和情况比较复杂。
那么你应该在描述中说明这一点。提供一个更复杂、更有洞察力的示例来演示过滤的复杂性。因为正确的方法取决于它。为什么需要将它分别应用于每个动物组?条件是否取决于每个组的特定值?你想根据组做一些完全不同的事情吗?
@HarryPlotter 我用非常接近我的实际数据的东西更新了这个问题
@HarryPlotter 我经常犹豫不决的原因是因为 imo 通过使事情尽可能通用,它会导致更通用的代码适用于更多人,而不是专门针对特定案例的解决方案。
【参考方案1】:
我会像这样继续分组:
(df.groupby(level=0)
.apply(lambda x: x[x['small']>1])
.reset_index(level=0, drop=True) # remove duplicate index
)
给出:
big small
animal animal attribute
cow cow speed 30.0 20.0
weight 250.0 150.0
falcon falcon speed 320.0 250.0
lama lama speed 45.0 30.0
weight 200.0 100.0
【讨论】:
嘿,很遗憾,我不确定是否以及如何应用它。该解决方案没有为更复杂的条件留出空间(例如,需要几行代码来设置条件)。正如@HarryPlotter 所建议的,我提供了一个更复杂的示例,该示例更接近我的真实数据。【参考方案2】:首先,基于'run'合并data
和valid range
,使用merge
方法
>>> data
value0 value1 value2
run step
0 0 0.12573 -0.132105 0.640423
1 0.1049 -0.535669 0.361595
2 1.304 0.947081 -0.703735
3 -1.26542 -0.623274 0.041326
4 -2.32503 -0.218792 -1.24591
5 -0.732267 -0.544259 -0.3163
1 0 0.411631 1.04251 -0.128535
1 1.36646 -0.665195 0.35151
2 0.90347 0.0940123 -0.743499
3 -0.921725 -0.457726 0.220195
4 -1.00962 -0.209176 -0.159225
5 0.540846 0.214659 0.355373
>>> valid_range
start stop
run
0 1 3
1 2 5
>>> merged = data.reset_index().merge(valid_range, how='left', on='run')
>>> merged
run step value0 value1 value2 start stop
0 0 0 0.12573 -0.132105 0.640423 1 3
1 0 1 0.1049 -0.535669 0.361595 1 3
2 0 2 1.304 0.947081 -0.703735 1 3
3 0 3 -1.26542 -0.623274 0.041326 1 3
4 0 4 -2.32503 -0.218792 -1.24591 1 3
5 0 5 -0.732267 -0.544259 -0.3163 1 3
6 1 0 0.411631 1.04251 -0.128535 2 5
7 1 1 1.36646 -0.665195 0.35151 2 5
8 1 2 0.90347 0.0940123 -0.743499 2 5
9 1 3 -0.921725 -0.457726 0.220195 2 5
10 1 4 -1.00962 -0.209176 -0.159225 2 5
11 1 5 0.540846 0.214659 0.355373 2 5
然后使用eval
选择满足条件的行。使用布尔数组屏蔽data
>>> cond = merged.eval('start < step < stop').to_numpy()
>>> data[cond]
value0 value1 value2
run step
0 2 1.304 0.947081 -0.703735
1 3 -0.921725 -0.457726 0.220195
4 -1.00962 -0.209176 -0.159225
或者,如果您愿意,这里是使用 query
的类似方法
res = (
data.reset_index()
.merge(valid_range, on='run', how='left')
.query('start < step < stop')
.drop(columns=['start','stop'])
.set_index(['run', 'step'])
)
【讨论】:
感谢它就像一个魅力。可能会使用轻微的变化:可能会使用轻微的变化merged = data[[]].join(valid_range, on="run")
step = merged.index.get_level_values("step")
cond = (merged["start"] <= step) & (step <= merged["stop"])
data[cond]
以上是关于基于布尔值从一片多索引数据帧中删除行的主要内容,如果未能解决你的问题,请参考以下文章
Pentaho 数据集成 (PDI):将布尔值从源插入到目标