Numpy和Pandas之间有性能差异吗?

62

我已经写了很多代码,以为我将使用Numpy数组。结果发现我获取的数据是通过Pandas加载的。我现在记得我加载它在Pandas中,因为我在Numpy中加载时遇到了一些问题。我相信数据量太大了。

因此,我想知道,使用Numpy和Pandas有计算性能上的区别吗?

如果Pandas更高效,那我宁愿重写所有代码用Pandas,但如果没有更高效的话,我就只使用一个Numpy数组...


7
这可能是一个过于宽泛的问题,没有太多实际用途。pandas 提供了一些经过 C 或 Cython 优化的程序,可以比 numpy 更快地处理一些操作,比如读取文本等。对于像点积这样的操作,pandas 的数据框通常会比 numpy 数组慢,因为 pandas 需要做很多其他的事情,比如对齐标签、处理异构类型等。 - TomAugspurger
@TomAugspurger 嗯,好的...有没有地方可以阅读它擅长的和不太优化的方面? - Terence Chow
我不确定是否有单一的来源。我可以轻松地说,自己动手做 :). 分析性能可能非常重要。这个并没有直接回答你的问题,但仍然可能有用。 - TomAugspurger
什么样的差异?容量差异、性能差异(内存/CPU/并行性/两者都有?)、算法差异、精度差异(float vs double,int vs int64)、行主序列与列主序列...?请具体说明。 - smci
3个回答

35

这个链接只涉及Pandas Series和NumPy数组,但是他们的发现是否也适用于填充二维NumPy数组和Pandas数据框? - develarist

13

我认为更多地是基于性能使用这两者并在它们之间转移数据(从numpy到pandas或反之亦然)。最近的一个例子是,我尝试使用numpy连接4个每个有10k行的小pickle文件 data.shape -> (10,000, 4)

代码大致如下:

n_concat = np.empty((0,4))
for file_path in glob.glob('data/0*', recursive=False):
    n_data = joblib.load(file_path)
    n_concat = np.vstack((co_np, filtered_snp))
joblib.dump(co_np, 'data/save_file.pkl', compress = True)

这导致我的笔记本电脑崩溃了(8 GB,i5),令人惊讶的是,因为卷并不是真正的非常巨大。这4个压缩的pickle文件大约每个都是5 MB。

对于pandas来说,同样的事情效果很好。

for file_path in glob.glob('data/0*', recursive=False):
    n_data = joblib.load(sd)
    try:
        df = pd.concat([df, pd.DataFrame(n_data, columns = [...])])
    except NameError:
        df = pd.concat([pd.DataFrame(n_data,columns = [...])])
joblib.dump(df, 'data/save_file.pkl', compress = True)

另一方面,当我使用 pandas 数据框架进行梯度下降实现时,速度非常慢,而使用 numpy 则要快得多。

总的来说,我发现 pandas 通常更适合处理中等大小的数据块和常见列操作,而 numpy 最适合在较小的数据集上进行向量化和递归工作(也许是更数学密集型的工作)。

在两者之间移动数据非常方便,因此我想,策略性地使用两者是正确的选择。


13
在我的大型数值数据实验中,相比于Numpy,Pandas的表现一直慢20倍。考虑到只执行了简单的算术操作:对一列进行切片、mean()和searchsorted() - 可见下面的内容,这是一个巨大的差异。一开始,我认为Pandas是基于Numpy或者至少像Numpy一样使用C优化的实现。然而,这些假设都被证明是错误的,鉴于巨大的性能差距。

在下面的示例中,data是一个有8M行3列(int32, float32, float32),没有NaN值,第0列(时间)已排序的Pandas frame。 data_np是通过data.values.astype('float32')创建的。Python 3.8,Ubuntu上的结果:

A. 列切片和平均值:

# Pandas 
%%timeit 
x = data.x 
for k in range(100): x[100000:100001+k*100].mean() 

15.8 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# Numpy
%%timeit 
for k in range(100): data_np[100000:100001+k*100,1].mean() 

874 µs ± 4.34 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Pandas比Numpy慢18倍(15.8毫秒对0.874毫秒)。

B. 在排序列中搜索:

# Pandas
%timeit data.time.searchsorted(1492474643)                                                                                                                                                               
20.4 µs ± 920 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

# Numpy
%timeit data_np[0].searchsorted(1492474643)                                                                                                                                                              
1.03 µs ± 3.55 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Pandas比Numpy慢20倍(20.4µs vs 1.03µs)。

编辑:我实现了一个名为namedarray的类,它填补了Pandas和Numpy之间的差距,因为它基于Numpy的ndarray类,因此比Pandas性能更好(通常快大约7倍),并且完全兼容Numpy的API和所有运算符;但同时它保持了类似于Pandas的DataFrame的列名,使得对单个列进行操作更加容易。这是一个原型实现。与Pandas不同,namedarray不允许不同数据类型的列。代码可以在这里找到:https://github.com/mwojnars/nifty/blob/master/math.py(搜索“namedarray”)。


“大量数值数据”是指多少?百万?十万?谢谢 :) - David Miedema
我对100万到1000万行的数据进行了比较,涉及到多个列,就像上面的示例一样。 - Marcin Wojnarski
这是一个不错的比较,但我认为至少可以说它是不完整的。如果我们有200列(常见情况),然后我们对其进行切片呢?显然,这些列不会是形状为(200,...)的numpy矩阵,而是200个变量,组合在一个Python对象中。我非常想看到那个比较。 - Gulzar
还有转换为numpy进行计算的成本呢? - Gulzar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接