升级后Pandas系列操作非常慢

3 投票
1 回答
519 浏览
提问于 2025-04-18 08:31

我发现pandas 0.11和pandas 0.13在处理简单的序列操作时,性能差别非常大。

In [7]: df = pandas.DataFrame({'a':np.arange(1000000), 'b':np.arange(1000000)})

In [8]: pandas.__version__                                
Out[8]: '0.13.0'

In [9]: %timeit df['a'].values+df['b'].values
100 loops, best of 3: 4.33 ms per loop

In [10]: %timeit df['a']+df['b']                      
10 loops, best of 3: 42.5 ms per loop

在0.11版本上(在同一台机器上),

In [10]: pandas.__version__                               
Out[10]: '0.11.0'

In [11]: df = pandas.DataFrame({'a':np.arange(1000000), 'b':np.arange(1000000)})

In [12]: %timeit df['a'].values+df['b'].valuese
100 loops, best of 3: 2.22 ms per loop

In [13]: %timeit df['a']+df['b']     
100 loops, best of 3: 2.3 ms per loop

所以在0.13版本上,速度大约慢了20倍。经过分析,我发现

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.047    0.047 <string>:1(<module>)
        1    0.000    0.000    0.047    0.047 ops.py:462(wrapper)
        3    0.000    0.000    0.044    0.015 series.py:134(__init__)
        1    0.000    0.000    0.044    0.044 series.py:2394(_sanitize_array)
        1    0.000    0.000    0.044    0.044 series.py:2407(_try_cast)
        1    0.000    0.000    0.044    0.044 common.py:1708(_possibly_cast_to_datetime)
        1    0.044    0.044    0.044    0.044 {pandas.lib.infer_dtype}
        1    0.000    0.000    0.003    0.003 ops.py:442(na_op)
        1    0.000    0.000    0.003    0.003 expressions.py:193(evaluate)
        1    0.000    0.000    0.003    0.003 expressions.py:93(_evaluate_numexpr)

它在处理一些函数,比如_possibly_cash_to_datetime和pandas.lib.infer_dtype时,花费了大量时间。

这个变化是预期中的吗?我该如何恢复到以前更快的性能呢?

注意:看起来问题出在输出的数据类型是整数。如果我把其中一列改成双精度类型,它又变得快了……

1 个回答

2

这个问题很奇怪,可能和cython中的某种查找有关。出于某种原因,

_TYPE_MAP = { np.int64 : 'integer' }
np.int64 in _TYPE_MAP

在处理int64时没有正确计算,但对于其他所有数据类型都能正常工作。可能是np.dtype对象的哈希值出现了问题。无论如何,这个问题在这里修复了:https: github.com/pydata/pandas/pull/7342,所以我们改用了名称哈希。

下面是性能比较:

主版本

In [1]: df = pandas.DataFrame({'a':np.arange(1000000), 'b':np.arange(1000000)})

In [2]: %timeit df['a'] + df['b']
100 loops, best of 3: 2.49 ms per loop

0.14.0

In [6]: df = pandas.DataFrame({'a':np.arange(1000000), 'b':np.arange(1000000)})

In [7]: %timeit df['a'] + df['b']
10 loops, best of 3: 35.1 ms per loop

撰写回答