Python 根据组大小进行筛选时pd.groupby.filter的最快替代方案
我有一个非常庞大的数据框,有数百万行,大约20-30列,包含各种类型的数据,例如字符串、num、日期等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 ... ... ... ... ... ...
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_索引)]
我正在获取值countsvc
来定位计数为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=dfdf
的行,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