【发布时间】:2021-03-31 16:06:09
【问题描述】:
我有一个非常庞大的 DataFrame,其中包含数百万行和大约 20-30 列,其中包含各种类型的数据,例如。字符串、数字、日期等
df
index t1 num1 float1 ... str2
0 2014-10-21 3456 0.000 ... ayzkcxtoScUy
1 2014-10-21 2453 0.000 ... jZygJWtxyVnS
... ... ... ... ... ...
n-1 2020-11-06 708735 670.818 ... UWVhmKCfmzVj
n 2020-11-06 70630 670.817 ... EvhreYZotqVS
让我们说它很疯狂,但我需要每一行都有它的所有值。我现在想对某些列进行分组,并根据组大小从原始 DataFrame df 中消除组和行。特别是,我想消除所有大小为 1 的组。
第一种天真的方法
我搜索并尝试使用这个答案:How to select rows in Pandas dataframe where value appears more than once
lst = ["t1", "str1", "num1", "str2", "num2"]
df = df.groupby(lst).filter(lambda x: len(x.index) > 1).reset_index(drop=True)
这确实按预期工作。我的 DataFrame df 现在从大小为 1 的组中出现的所有行中过滤出来。问题是使用 filter 方法与我的 DataFrame 的尺寸相关的时间,这需要太长时间。从这个角度来看,对这些样本列进行分组将产生大约 165,000 个组和 250 万行 DataFrame,其中大约三分之一的组的大小为 1。我不得不中止这个脚本的执行,因为它需要年龄。我进一步尝试使用来自此链接How do I improve the performance of pandas GroupBy filter operation? 的灵感,但无法使其与map 一起使用,因为我在 DataFrame 上而不是在 Series 上进行分组。使用transform 方法,性能变差。
旁注
进一步调查,我发现在具有datetime64[ns, UTC] 和/或datetime64[ns] 列的DataFrame 上使用filter 时出现问题。我使用Del df[x] 删除了所有这三个列,这将过滤方法的性能提高了大约三分之一。仍然不够,但足以在此处提及它,尤其是当我需要这些列并且不能只删除它们时。
第二种“聪明”方法
然后,我尝试使用来自链接1 的.value_counts() 对我的数据进行巧妙的索引来规避groupby、过滤或转换的使用。
vc = df[lst].value_counts()
vc_index = vc.index[vc.gt(1)]
df = data[data[lst].isin(vc_index)]
我正在获取值计数 vc 以定位计数为 1 的所有索引,然后创建一个 MultiIndex new_index 仅包含所需的索引(即 count > 1)。之后,我尝试使用链接1 中的.isin() 过滤我的df,它将df 的所有值设置为NaN/NaT。我被困在这里 - 我不确定我在这里做错了什么。
df
index t1 num1 float1 ... str2
0 NaT NaN NaN ... NaN
1 NaT NaN NaN ... NaN
... ... ... ... ... ...
n-1 NaT NaN NaN ... NaN
n NaT NaN NaN ... NaN
在另一次尝试中,我尝试使用pd.index.difference() 方法
vc = data[lst].value_counts()
df = data.set_index(keys=lst)
df.index = df.index.difference(other=vc.index[vc.gt(1)])
但这只是给了我一个TypeError: '<' not supported between instances of 'float' and 'str'。
老实说,自从两天以来我一直在处理这个问题,我有点不知道什么是最好的。我什至考虑过并行化(也许使用 Dask?),但我不确定如何使用它,因为我从未使用过它。非常感谢您的帮助。
【问题讨论】:
标签: python pandas performance dataframe numpy