在第一次满足列条件之前对pandas数据框架进行子集的快速方法



与这个问题有关

我有一个数据帧,我想为每个id行,直到状态是1的第一次。在上面的线程中提出的解决方案工作完美,但速度很慢。我的数据集中有70,000行。

我的数据集:

d = {'id': [1,1,1,1,1,1,1,2,2,2,2,2,2,2], 'status': [0,0,0,0,1,1,1,0,0,0,0,1,0,1]}
df = pd.DataFrame(data=d)
id  status
0    1       0
1    1       0
2    1       0
3    1       0
4    1       1
5    1       1
6    1       1
7    2       0
8    2       0
9    2       0
10   2       0
11   2       1
12   2       0
13   2       1

我想要的子集是:

id  status
0    1       0
1    1       0
2    1       0
3    1       0
4    1       1
5    2       0
6    2       0
7    2       0
8    2       0
9    2       1

在相关线程中尝试解决方案:

lambda x: x.cumsum().cumsum().le(1)

可以,但是速度很慢。

您可以在此线程中使用parallel-pandas并行化解决方案。下面是一个用法示例

import pandas as pd
#pip install parallel-pandas
from parallel_pandas import ParallelPandas
#initialize parallel-pandas
ParallelPandas.initialize(n_cpu=8)
#p_apply is parallel analogue of apply method
df = df.groupby('id', group_keys=False)
.p_apply(lambda x: x[x.status.cumsum().cumsum().le(1)])
.reset_index(drop=1)

您可以尝试:

df[~df.groupby('id', group_keys=False)['status'].apply(lambda s: s.shift().eq(1).cummax())]

获得cummax可能比获得cumsum更快

或者,假设只有0/1的值:

df.groupby('id', group_keys=False).apply(lambda g: g.loc[:g['status'].idxmax()])

这里有一个可能的解决方案。这当然可以改进,但它是有效的。

df.groupby("id")['status'].apply(lambda x: x[:x.values.tolist().index(1) + 1]).swaplevel()

解释:

.apply(lambda x: x[:x.values.tolist().index(1) + 1])

这一行由两个主要部分组成。

我们寻找第一次出现的值1,得到它的索引x.values.tolist().index(1)然后加1,这样就可以包含我们找到的数字了。我们把所有东西从头到尾切成薄片。

对每个id组执行此操作。

/p>这个版本处理在组值中找不到1的情况:

def magic(x):
values = x.values.tolist()
if 1 in values:
return x[:values.index(1) + 1]
else:
return x
df.groupby("id")['status'].apply(magic)

相关内容

  • 没有找到相关文章

最新更新