Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python2D列表性能,无numpy_Python_Numpy - Fatal编程技术网

Python2D列表性能,无numpy

Python2D列表性能,无numpy,python,numpy,Python,Numpy,我正在尝试用Python创建一个2D列表。我发现了两种可能性 def cArray(size): c = [[0. for i in range(size)] for j in range(size)] return c def npArray(size): np = numpy.zeros((size,size)) return np 现在这两个函数都给出了正确的答案。这里的问题在于性能。我使用timeit运行了这两个程序,下面是我的结果: list siz

我正在尝试用Python创建一个2D列表。我发现了两种可能性

def cArray(size):
    c = [[0. for i in range(size)] for j in range(size)]
    return c

def npArray(size):
    np = numpy.zeros((size,size))
    return np
现在这两个函数都给出了正确的答案。这里的问题在于性能。我使用timeit运行了这两个程序,下面是我的结果:

list size is 5000
number of times run is 5

cArray average time: 3.73241295815
npArray average time: 0.210782241821

所以很明显,我想避免使用第一种解决方案,特别是因为它将在100k以下的尺寸下运行。但是,我也不想使用太多的依赖项。有没有一种方法可以让我在不使用numpy的情况下高效地创建2D阵列?它不需要完全跟上速度,只要速度不慢17倍。

我尝试了几种选择

编辑:原来的耳环有问题,它创建了对同一列表的引用

Edit2:根据塞巴斯蒂安的建议添加了
array.array

import time
import numpy as np
import array

t1 = 0

def starttimer():
    global t1
    t1 = time.clock()

def stoptimer(s):
    t2 = time.clock()
    print 'elapsed time for "{}": {:.3f} seconds'.format(s, t2-t1)

def cArray(size):
    c = [[0. for i in range(size)] for j in range(size)]
    return c

def dArray(size):
    d = [[0. for i in xrange(size)] for j in xrange(size)]
    return d

def eArray2(size):
    return [[0.]*size for j in xrange(size)]

def fArray(size):
    return np.zeros((size,size))

def gArray(size):
    return [array.array('d', [0])*size for j in xrange(size)]

sz = 5000

starttimer()
cArray(sz)
stoptimer('cArray')

starttimer()
dArray(sz)
stoptimer('dArray')

starttimer()
fArray(sz)
stoptimer('fArray')

starttimer()
gArray(sz)
stoptimer('gArray')
结果(如果有人关心的话,FreeBSD amd64上的cpython 2.7.3):


如果您想达到真正的低级别,可以使用
ctypes

a = (ctypes.c_int * 5000 * 5000)()
但是NumPy在运行Python的大多数平台上都是可用的

所以很明显,我想避免使用第一种解决方案,特别是因为它将在100k以下的尺寸下运行。但是,我也不想使用太多的依赖项

你必须选择其中哪一个对你更重要。Numpy具有更好的性能,正是因为它不使用内置的Python类型,而是使用自己的类型,这些类型针对数值计算进行了优化。如果您的数据将是数字的,并且将有10万行/列,那么您将看到numpy的性能有了巨大的提高。如果你想避免numpy依赖,你将不得不忍受性能下降。(显然,您可以编写自己的Python库或C扩展来针对特定用例进行优化,但这些库和其他库一样都是依赖项。)


就我个人而言,我建议你只使用numpy。它的应用如此广泛,以至于任何考虑使用处理100k多维数组的库的人都可能已经安装了numpy。

我的使用案例是,在一些在线judge平台上,库的依赖性是有限的,但在进行动态编程时需要2D数组(也很难矢量化)。我的python代码经常超过时间限制

有一些事情需要提醒:

  • 虽然pythonlist是一个指针数组,但是朴素的对象非常快

  • 在创建对象时,使用像numpy这样的紧凑结构可能会很快,但访问元素会花费额外的开销,这与朴素的python对象不同

  • 除非使用了JIT之类的东西

  • 使用玩具DP示例测试代码:

    import timeit
    
    size = 1000
    
    range_init_0 = "size={}".format(size)
    range_init_1 = "a = [[0 for i in range(size)] for j in range(size)]"
    
    multi_init_0 = "size={}".format(size)
    multi_init_1 = "a = [[0]*size for _ in range(size)]"
    
    numpy_init_0 = "from numpy import zeros; size={}".format(size)
    numpy_init_1 = "a = zeros((size, size), dtype=int)"
    
    array_init_0 = "from array import array; size={}".format(size)
    array_init_1 = "a = [array('d', [0])*size for j in range(size)]"
    
    ctyps_init_0 = "from ctypes import c_int; size={}".format(size)
    ctypes_init_1 = "a = (c_int * size * size)()"
    
    dp = '''
    MOD = int(1e9+7)
    for i in range(size):
        a[i][0] = 1
    for j in range(size):
        a[0][i] = 1
    for i in range(1, size):
        for j in range(1, size):
            a[i][j] = (a[i][j] + a[i-1][j] + a[i][j-1]) % MOD
    '''
    
    def test(name, init_0, init_1, dp, n=10):
        t = timeit.timeit(init_1, setup=init_0, number=n)
        print("{} initial time:\t{:.8f}".format(name, t))
        t = timeit.timeit(dp, setup=init_0 + '\n' + init_1, number=n)
        print("{} calculate time:\t{:.8f}".format(name, t))
    
    test("range", range_init_0, range_init_1, dp)
    test("multi", multi_init_0, multi_init_1, dp)
    test("numpy", numpy_init_0, numpy_init_1, dp)
    test("array", array_init_0, array_init_1, dp)
    test("ctypes", ctyps_init_0, ctypes_init_1, dp)
    
    print('------')
    numba_init_0 = '''
    import numpy as np
    size = {}
    a = np.zeros((size, size), dtype=np.int32)
    '''.format(size)
    numba_init_1 = '''
    import numba
    def dp1(a):
        size = len(a)
        MOD = int(1e9+7)
        for i in range(size):
            a[i][0] = 1
        for j in range(size):
            a[0][i] = 1
        for i in range(1, size):
            for j in range(1, size):
                a[i][j] = (a[i][j] + a[i-1][j] + a[i][j-1]) % MOD
    dp_jit = numba.jit('void(i4[:,:])')(dp1)
    '''
    dp = "dp_jit(a)"
    
    test("numba", numba_init_0, numba_init_1, dp)
    
    结果:

    range initial time:     0.56781153
    range calculate time:   5.08359793
    multi initial time:     0.03682878
    multi calculate time:   5.14657282
    numpy initial time:     0.00883761
    numpy calculate time:   12.15619322
    array initial time:     0.02656035
    array calculate time:   5.27542352
    ctypes initial time:    0.00523795
    ctypes calculate time:  7.88469346
    ------
    numba initial time:     2.98394509
    numba calculate time:   0.05321887
    
    (此处的Numba初始化时间不包括numpy初始化)

    正如我们所看到的,numpy和CTYPE在计算时都比本机列表慢

    Numba JIT需要一些时间,但计算时间要短得多


    (不要在在线判断平台上使用Python进行2D动态编程!)

    如果这让您感到震惊,请尝试测量内存消耗。它可能不会大17倍,但肯定会很糟糕。ctypes可能会有所帮助,但肯定不会像numpy看到这个问题那样多。。大到100k?然后我希望你的数组(1)不是正方形的,尽管你的例子是正方形的,或者(2)非常稀疏,因为要跟踪的单元格太多了。我真的认为,如果不知道对数据做了什么,这个问题就无法真正回答。还有一个导入数组,它被限制为1D,但是可以列出数组。将它放入[[0]*size for uuin xrange(size)],或数组('d',[0])中[0](它是类型识别的,因此占用的空间要小得多),可以消除一个循环。@Sebastian:这是一个用于实现的,这个计时代码不起作用:
    t1=time.clock()
    设置一个局部变量。这就是为什么
    d
    e
    有相同的时间,而
    e
    应该快得多。如果您解决了这个问题(例如
    starttimer
    中的
    global t1
    ),您会得到更合理的结果。使用
    timeit
    模块通常更容易。顺便说一句,
    array
    并不是一个公平的比较,因为它实际上并没有生成5000^2个单元格。还要记住,它们做的事情并不相同。例如,尝试更改
    耳环的一个元素,然后查看结果。@JoeKington我已更改耳环。我想我知道哪里出了问题-/既然您已经做到了,那么可以为array添加导入数组、array.array('d',[0])*大小,而不是[0]*大小。
    
    range initial time:     0.56781153
    range calculate time:   5.08359793
    multi initial time:     0.03682878
    multi calculate time:   5.14657282
    numpy initial time:     0.00883761
    numpy calculate time:   12.15619322
    array initial time:     0.02656035
    array calculate time:   5.27542352
    ctypes initial time:    0.00523795
    ctypes calculate time:  7.88469346
    ------
    numba initial time:     2.98394509
    numba calculate time:   0.05321887