为什么numpy ndarray比简单循环的列表慢得多? [英] Why is numpy ndarray much slower than lists for simple loops?

查看:594
本文介绍了为什么numpy ndarray比简单循环的列表慢得多?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Python的新手,所以我决定解决一些常见的挑战,以提高我的语言知识.我了解了numpy及其有效的ndarrays,因此尝试了以下实验:

I'm new to Python so I've decided to solve some common challenges to improve my knowledge of the language. I learned about numpy and its efficient ndarrays so I attempted the following experiment:

考虑2和问题(例如,此处),然后解决它天真的方式(此问题的目的无关紧要). 这是使用python列表的解决方案:

Consider the 2 sum problem (e.g. here) and let's solve it the naive way (it doesn't matter for the purpose of this question). Here's a solution with python's lists:

from  itertools import combinations

def twosum1(n_lst):
    pairs=list(combinations(n_lst,2))
    solutions=[]
    for pair in pairs:
        if sum(pair)==7: solutions.append(pair)
    return(solutions)

然后我使用np.arrays创建了一个版本,希望它可以大大加快计算速度:

Then I created a version using np.arrays expecting it will drastically speed up the calculation:

from  itertools import combinations
import numpy as np

def twosum2(n_lst):
    pairs=np.array(list(combinations(n_lst,2)),dtype=int)
    return pairs[pairs[:,1]+pairs[:,0]==7]

但是,在对两个函数进行计时之后,twosum2比twosum1慢大约2倍.因此,我认为问题可能出在元素的动态选择上,因此我用ndarrays替换了列表,从而编写了twosum1的精确副本...

However, after timing the two functions, twosum2 is about 2x slower than twosum1. So I thought that the problem maybe in the dynamical selection of elements, so I've written an exact copy of twosum1 by replacing lists with ndarrays ...

def twosum3(n_lst):
    pairs=np.array(list(combinations(n_lst,2)))
    solutions=np.empty((0,2))
    for pair in pairs:
        if np.sum(pair)==7: 
            solutions=np.append(solutions,[pair],axis=0)
    return(solutions)

...并且生成的功能比原始功能慢10倍!

... and the resulting function was 10x slower than the original!

这怎么可能?我在这里做错了什么?显然,删除循环并用ndarrays替换列表不足以提高速度(与我阅读).

How is this possible? What I'm I doing wrong here? Clearly, removing loops and replacing lists with ndarrays is not enough to gain speed (contrary to what I learned reading this).

  • 我在jupyter中使用%timeit来计时功能.
  • 我为所有要使用的功能采用相同的基准.
  • 我在3个函数中以相同的方式计算组合的事实告诉我,减速是由于numpy引起的,但是看不到如何实现.

推荐答案

代价高昂的操作是np.array(list(combinations(n_lst,2)),dtype=int),因为python必须扫描列表中的每个成员,检查成员是否与int兼容,将其转换为整数并将其存储在数组中.

The costly operation is np.array(list(combinations(n_lst,2)),dtype=int) because python must scan each member of the list, check if member is 'int compatible', convert it in integer and store it in the array.

要达到numpy性能,必须在numpy中构思所有算法.例如:

To reach numpy performance, you must conceive all the algorithm in numpy. For example :

In [63]: n_lst=list(range(100))

In [64]: %timeit twosum1(n_lst)
11.2 ms ± 1.64 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)


In [65]: np.vstack(np.where(np.add.outer(n_lst,n_lst)==7)).T
Out[65]: 
array([[0, 7],
       [1, 6],
       [2, 5],
       [3, 4],
       [4, 3],
       [5, 2],
       [6, 1],
       [7, 0]], dtype=int64)

In [66]: %timeit np.vstack(np.where(np.add.outer(n_lst,n_lst)==7)).T
306 µs ± 19 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

通过这种方式,您将赢得30到100的系数,具体取决于问题.

This way you will win a 30 to 100 factor , depending of the problem.

这篇关于为什么numpy ndarray比简单循环的列表慢得多?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆