gpt4 book ai didi

python - Numpy 数组与 Python 列表在一维矩阵(矢量)上的性能

转载 作者:行者123 更新时间:2023-12-04 15:05:04 25 4
gpt4 key购买 nike

我想计算 pi,它总结了 GaussianMixture 模型中特定类别中的几个标签/标签总数。

enter image description here

tr_y 是一个 pandas 数据框

<表类="s-表"><头>索引标签<正文>0615263546

1000 行 × 1 列。


然后我尝试比较两种方法:

  • 第一个是使用列表:
%%timeit
y_list = tr_y.values.flatten().tolist()
>>> 12.3 µs ± 193 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%%timeit
sum([1 if y == 5 else 0 for y in y_list]) / len(y_list)
54.9 µs ± 1.21 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  • 第二种方法是使用 numpy 数组:
%%timeit
arr = tr_y.to_numpy()
>>> 4.55 µs ± 92.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%%timeit
sum([1 for i in arr if i == 5 ])/arr.__len__()
>>> 883 µs ± 48 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

更新方法,如果它使用 tolist() 将 NumPy 转换为列表比前两种方法快得多。

arr = tr_y.to_numpy().tolist()
%%timeit
sum([1 for i in arr if i == 5 ])/arr.__len__()
>>> 43.1 µs ± 410 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

source最后一种方法


So using lists is faster than using NumPy array.

我已经搜索过这个,我发现 NumPy 必须用 python 类型包装返回的对象(例如,在本例中为 NumPy.float64 或 NumPy.int64),如果您逐项迭代,这会花费时间-item1。迭代时进一步证明了这一点——我们看到在迭代数组时我们在 2 个单独的 ID 之间交替。这意味着 python 的内存分配器和垃圾收集器加类工作以创建新对象然后释放它们。

列表没有这种内存分配器/垃圾收集器开销。列表中的对象已经作为 python 对象存在(并且它们在迭代后仍然存在),因此它们在列表的迭代中都没有任何作用。

我的搜索得出的结论是,如果我们需要处理多维矩阵或进行一些矢量化,我们必须更快地使用 NumPy 数组并占用更少的内存。是真的吗?

我要计算的另一件事是 Numpy 数组和列表的内存消耗。不过,我发现 sys.sizeOf不可靠,给了我们指针数组的大小和容器的 header ,越来越多地考虑了这一点。有没有可靠的方法来计算内存消耗?

另一项调查表明,当我将 NumPy 数组转换为列表时,我将其转换为立即上传到 L1 缓存中的行矩阵,而不是在 L1 缓存中造成很多未命中的 col 向量。 source

那么如果我们使用 Fortran 顺序的向量呢?

最佳答案

长话短说

像这样使用 np.sum():

np.sum(tr_y.labels.to_numpy()==5)/len(tr_y)

测试

现在让我们做一些实验。我们将使用以下设置:

import pandas as pd
import numpy as np
tr_y = pd.DataFrame({'labels': [6, 5, 6, 5, 6]*200000})

我们使用更大的数据集来查看这些方法是否可以很好地扩展到更大的输入。这里我们将有一个包含 1,000,000 行的数据集。我们将尝试几种不同的方法,看看它们的效果如何。

表现最差的是:

sum(tr_y.labels.to_numpy()==5)/len(tr_y) 

每个循环 1.91 秒 ± 42.1 毫秒(7 次运行的平均值 ± 标准偏差,每次 1 个循环)

下一个选项平均快 14 倍:

y_list = tr_y.to_numpy().tolist()
sum([1 if y == 5 else 0 for y in y_list]) / len(y_list)

每次循环 132 毫秒 ± 2.14 毫秒(7 次运行的平均值 ± 标准偏差,每次 10 次循环)

之后我们得到 1.6 倍的增长:

sum(tr_y.labels==5)/len(tr_y)

每个循环 79.3 毫秒 ± 796 µs(7 次运行的平均值 ± 标准偏差,每次 10 次循环)

然而,这些方法都没有使用 numpy 进行优化。他们使用 numpy 数组,但被 python 的 sum() 困住了。如果我们使用优化的 NumPy 版本,我们会得到:

np.sum(tr_y.labels.to_numpy()==5)/len(tr_y)

每个循环 1.36 毫秒 ± 6.7 µs(7 次运行的平均值 ± 标准偏差,每次 1000 次循环)

此操作平均比我们之前的最佳操作快 58 倍。这更像是我们所 promise 的 NumPy 的强大功能。通过使用 np.sum() 而不是 python 的标准 sum(),我们可以将相同的操作快 1,400 倍(1.9秒对 1.4 毫秒)

结束语

由于 Pandas 系列是基于 NumPy 数组构建的,因此以下代码提供了与我们的最佳设置非常相似的性能。

np.sum(tr_y.labels==5)/len(tr_y)

每个循环 1.83 毫秒 ± 39.6 µs(7 次运行的平均值 ± 标准偏差,每次 100 次循环)

除非优化您的代码是必不可少的,否则我个人会选择此选项,因为它在不损失太多性能的情况下阅读起来最清晰。

关于python - Numpy 数组与 Python 列表在一维矩阵(矢量)上的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66313883/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com