Python 根据组大小进行筛选时pd.groupby.filter的最快替代方案

Python 根据组大小进行筛选时pd.groupby.filter的最快替代方案,python,pandas,performance,dataframe,numpy,Python,Pandas,Performance,Dataframe,Numpy,我有一个非常庞大的数据框,有数百万行,大约20-30列,包含各种类型的数据,例如字符串、num、日期等 df 索引t1 num1浮动1。。。str2 0 2014-10-21 3456 0.000 ... AYZKCXSCUY 1 2014-10-21 2453 0.000 ... jZygJWtxyVnS ... ... ... ... ... ...

我有一个非常庞大的数据框,有数百万行,大约20-30列,包含各种类型的数据,例如字符串、num、日期等

df
索引t1 num1浮动1。。。str2
0       2014-10-21      3456     0.000  ...  AYZKCXSCUY
1       2014-10-21      2453     0.000  ...  jZygJWtxyVnS
...            ...       ...       ...  ...           ...           
n-112020-11-06708735670.818。。。UWVhmKCfmzVj
n 2020-11-06 70630 670.817。。。EvhreYZotqVS
让我们说它很疯狂,但我需要每一行及其所有值。现在我想对某些列进行分组,并根据组大小从原始数据帧
df
中删除组和行。特别是,我想消除所有大小为1的组

第一种天真的方法

我搜索并尝试使用以下答案:

lst=[“t1”、“str1”、“num1”、“str2”、“num2”]
df=df.groupby(lst).过滤器(lambda x:len(x.index)>1).重置索引(drop=True)
这确实如预期的那样有效。我的数据帧
df
现在从大小为1的组中出现的所有行中筛选出来。问题是使用filter方法与我的数据帧的维度相关的时间太长了。为了更好地理解这一点,对这些样本列进行分组将产生约165000个组,其中250万行数据帧,其中约三分之一的组大小为1。我不得不中止这个脚本的执行,因为它需要很长时间。我进一步尝试使用此链接的灵感,但无法使其与
map
一起工作,因为我在数据帧上分组,而不是在序列上分组。使用
transform
方法,性能恶化

旁注

进一步调查后,我发现在具有
datetime64[ns,UTC]
和/或
datetime64[ns]
列的数据帧上使用
filter
时出现了一个问题。我使用
deldf[x]
删除了这三个列,这使filter方法的性能提高了大约三分之一。这还不够,但在这里提到这一点意义重大,特别是当我需要这些列并且不能直接删除它们时

第二种“聪明”方法

然后,我尝试使用link中的
.value\u counts()
,巧妙地对数据进行索引,以避免使用groupby、筛选或转换

vc=df[lst]。值_计数()
vc_index=vc.index[vc.gt(1)]
df=data[data[lst].isin(vc_索引)]
我正在获取值counts
vc
来定位计数为1的所有索引,然后创建一个只包含所需索引(即
count>1
)的多索引
新索引。在那之后,我尝试用链接中的
.isin()
来过滤我的
df
,它将
df
的所有值设置为NaN/NaT。我被困在这里——我不确定我做错了什么

df
索引t1 num1浮动1。。。str2
0纳南南。。。楠
1纳南南。。。楠
...       ...       ...       ...  ...     ...           
n-1纳南。。。楠
n纳南南。。。楠
在另一次尝试中,我尝试使用
pd.index.difference()
方法

vc=data[lst].value_counts()
df=数据。设置索引(键=lst)
df.index=df.index.difference(其他=vc.index[vc.gt(1)])

但是这只给了我一个
TypeError:“对于这个特定的用例(count>1的组),
duplicated
要快得多:

df[df.duplicated(lst, keep=False)]
# 231 ms ± 10.2 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
另一个选项,虽然速度不太快,但比
过滤器
快得多,并且通常可以使用
groupby()。transform('size')

与之相比:

df.groupby(lst).filter(lambda x: len(x) > 1)
# CPU times: user 38.8 s, sys: 482 ms, total: 39.3 s
# Wall time: 39.4 s

来自@Quang Hoang的解决方案非常有效。我用我的数据集做了一些基准测试:

(rs=df
df
的行,ngrps=
df.groupby(lst).ngroups


使用duplicated可以很好地进行缩放,但请注意:如果列表中的列中有NaN值(在我的示例中,您要对其进行分组,
lst
),duplicate将不会删除它们

谢谢!你的答案很有效!
df.groupby(lst).filter(lambda x: len(x) > 1)
# CPU times: user 38.8 s, sys: 482 ms, total: 39.3 s
# Wall time: 39.4 s
method   100k rs/82.488 ngrps  200k rs/164.466 ngrps  400k rs/331.351 ngrps  800k rs/672.905 ngrps  1.600k rs/1.351.525 ngrps

duplicated     0:00:00.031236         0:00:00.078112         0:00:00.181825         0:00:00.331095             0:00:00.683959
transform      0:00:00.062507         0:00:00.109386         0:00:00.261506         0:00:00.528166             0:00:01.029606
filter         0:00:09.039214         0:00:18.422355         0:00:37.372117         0:01:15.531945             0:02:32.075144