多个numpy数组上的多步线性代数运算

时间:2016-11-30 06:47:51

标签: python arrays numpy

我有3个numpy数组:

import numpy
arr_a = numpy.random.random((300, 300))
arr_b = numpy.random.random((300, 300))
arr_c = numpy.random.random((300, 300))

我想从3个数组的组合中创建第4个数组(arr_d)。规则如下:

如果arr_a网格单元格值> 0.2和arr_b值< 0.4和arr_c> 0.6然后用1

填充arr_d

如果arr_a网格单元格值> 0.3和arr_b值< 0.5和arr_c> 0.6然后用2

填充arr_d

如果arr_a网格单元格值> 0.1和arr_b值< 0.2和arr_c> 0.5然后用3

填充arr_d

在所有其他情况下,用4

填充arr_d

我可以使用嵌套循环来做到这一点,但这非常慢而且不是非常pythonic。此外,这是一个测试用例,真正的数组大小为1000 * 1000,所以我想要一个可扩展的解决方案,最好是并行的。

2 个答案:

答案 0 :(得分:2)

使用纯Python和for循环绝对不是要走的路。您可以使用NumPy中的数组操作编写程序,有效地在C中进行循环,极大地加速了代码。但是,这会为每个规则实例化一个全新的数组,每个规则都与数据大小相同。相反,你可以使用像Numba这样的东西,例如用Anaconda分发Python。使用Numba,您可以使用循环编写代码,但不会浪费时间(它会将代码编译为本机机器指令)。此外,不需要额外的大型阵列,使其比NumPy更具内存效率。 Numba也恰好更快,正如这个例子所示:

import numpy, numba, time

def using_numpy(shape):
    arr_a = numpy.random.random(shape)
    arr_b = numpy.random.random(shape)
    arr_c = numpy.random.random(shape)
    mask1 = numpy.logical_and(numpy.logical_and((arr_a > 0.2), (arr_b < 0.4)), (arr_c > 0.6))
    mask2 = numpy.logical_and(numpy.logical_and((arr_a > 0.3), (arr_b < 0.5)), (arr_c > 0.6))
    mask3 = numpy.logical_and(numpy.logical_and((arr_a > 0.1), (arr_b < 0.2)), (arr_c > 0.5))
    result = numpy.ones(arr_a.shape)*4
    result[mask1] = 1
    result[mask2] = 2
    result[mask3] = 3
    return result

@numba.jit
def using_numba(shape):
    arr_a = numpy.random.random(shape)
    arr_b = numpy.random.random(shape)
    arr_c = numpy.random.random(shape)
    result = numpy.empty(shape)
    for i in range(result.shape[0]):
        for j in range(result.shape[1]):
            if arr_a[i, j] > 0.2 and arr_b[i, j] < 0.4 and arr_c[i, j] > 0.6:
                result[i, j] = 1
            elif arr_a[i, j] > 0.3 and arr_b[i, j] < 0.5 and arr_c[i, j] > 0.6:
                result[i, j] = 2
            elif arr_a[i, j] > 0.1 and arr_b[i, j] < 0.2 and arr_c[i, j] > 0.5:
                result[i, j] = 3
            else:
                result[i, j] = 4
    return result
# Compile the using_numba function
using_numba((0, 0))

t0 = time.time()
result = using_numpy((3000, 3000))
print('NumPy took', time.time() - t0, 'seconds')

t0 = time.time()
result = using_numba((3000, 3000))
print('Numba took', time.time() - t0, 'seconds')

这里我使用了(3000, 3000)数组。在我的机器上,使用NumPy需要0.47秒,而使用Numba需要0.29秒。

答案 1 :(得分:1)

一种方法是使用布尔映射

condition_1 = numpy.logical_and(numpy.logical_and((arr_a > 0.2), (arr_b < 0.4)), (arr_c > 0.6))
condition_2 = numpy.logical_and(numpy.logical_and((arr_a > 0.3), (arr_b < 0.5)), (arr_c > 0.6))
condition_3 = numpy.logical_and(numpy.logical_and((arr_a > 0.1), (arr_b < 0.2)), (arr_c > 0.5))
result = numpy.ones((300, 300)) * 4
result[numpy.where(condition_3)] = 3
result[numpy.where(condition_2)] = 2
result[numpy.where(condition_1)] = 1

它避免了嵌套循环,但是分配了三个专用数组并进行了大量多余的分配。必须有一个更优化的方法......