Pandas中df.nunique()效率低怎么办?
2024-07-13 13:48:23
如何突破 Pandas 中 df.nunique() 的效率瓶颈?
在数据分析领域,统计数据集中唯一值的个数是一项常见任务。Pandas 提供的 df.nunique()
方法为此类任务提供了便捷的解决方案。但随着数据量的增加,df.nunique()
的计算时间会线性增长,在处理大规模数据集时可能成为性能瓶颈,大幅拖慢分析效率。
本文将探讨如何突破这一瓶颈,并介绍几种更高效的替代方案,帮助你提升数据处理速度。
以一个包含五千万行数据的 DataFrame 为例,使用 df.nunique()
计算唯一值个数,耗时大约为 10 秒。当数据量翻倍时,执行时间也会相应地增加到 20 秒左右。
import numpy as np
import pandas as pd
def createList(r1, r2):
"""创建一个包含指定范围内数值的列表。
例如:createList(1,3) == [1, 2, 3]
"""
return np.arange(r1, r2+1, 1)
sample_df = pd.DataFrame(
data = {
'a' : createList(1, 50_000_000),
'b' : createList(1, 50_000_000),
'c' : createList(1, 50_000_000),
'd' : createList(1, 50_000_000),
'e' : createList(1, 50_000_000),
'f' : createList(1, 50_000_000),
'g' : createList(1, 50_000_000),
}
)
# 使用%%timeit进行性能测试
%timeit sample_df.nunique()
为了提升效率,我们可以采用以下几种更高效的方法:
利用 numba
加速:
numba
是一个用于优化 Python 代码的库,它可以将 Python 函数编译成机器码,从而显著提高代码的执行速度。
from numba import jit
@jit(nopython=True)
def nunique_numba(df):
result = np.zeros(len(df.columns), dtype=np.int64)
for i in range(len(df.columns)):
result[i] = len(np.unique(df.iloc[:, i]))
return result
# 使用%%timeit进行性能测试
%timeit nunique_numba(sample_df)
通过使用 numba
,我们可以将 df.nunique()
的执行速度提高数倍。
借助 set
数据结构:
Python 中的 set
数据结构可以高效地存储和查找唯一值。我们可以利用这一特性来计算唯一值的个数。
def nunique_set(df):
result = []
for col in df.columns:
result.append(len(set(df[col])))
return result
# 使用%%timeit进行性能测试
%timeit nunique_set(sample_df)
这种方法的效率略低于 numba
,但仍然比 df.nunique()
快得多。
采用 dask
进行并行计算:
对于更大规模的数据集,我们可以考虑使用 dask
库进行并行计算。dask
可以将 DataFrame 分割成多个块,并在多个 CPU 核心上并行处理这些块,从而大幅度提高计算速度。
import dask.dataframe as dd
# 将Pandas DataFrame转换为Dask DataFrame
ddf = dd.from_pandas(sample_df, npartitions=4)
# 使用%%timeit进行性能测试
%timeit ddf.nunique().compute()
通过使用 dask
,我们可以充分利用多核 CPU 的计算能力,进一步提升处理效率。
选择最优方案:
上述三种方法都能有效提高 df.nunique()
的执行效率,但最优方案需要根据具体的数据规模和硬件环境选择。
- 如果你的数据集相对较小,
numba
或set
方法都是不错的选择; - 如果你的数据集非常庞大,
dask
则是更理想的解决方案,能够充分发挥硬件性能。
常见问题解答:
-
为什么
df.nunique()
在大规模数据集上效率较低?df.nunique()
方法会遍历 DataFrame 的每一列,并统计唯一值的个数。这种计算方式在数据量较小时效率很高,但当数据量很大时,遍历操作会非常耗时。 -
numba
、set
和dask
三种方法各有哪些优缺点?numba
:优点是速度最快,缺点是需要安装额外的库,并且只适用于数值型数据。set
:优点是代码简洁,无需安装额外库,缺点是速度略慢于numba
。dask
:优点是可以并行计算,适合处理超大规模数据集,缺点是需要安装额外库,并且代码相对复杂。
-
如何选择合适的
dask
分区数量?dask
分区数量应该根据数据量和 CPU 核心数进行调整。一般来说,分区数量应该大于等于 CPU 核心数,以充分利用 CPU 资源。 -
除了上述方法之外,还有哪些方法可以提高
df.nunique()
的效率?- 减少数据量:如果可以预先筛选数据,只保留必要的列和行,可以有效减少计算量。
- 使用更高效的硬件:例如使用固态硬盘、增加内存容量等。
-
如何进一步优化
numba
和dask
的性能?numba
:可以使用@jit(nopython=True)
装饰器,将 Python 代码编译成机器码,从而提高执行速度。dask
:可以使用client.scheduler_info()
方法查看集群状态,并根据实际情况调整分区数量和 worker 数量。