Numpy / Python:高效矩阵作为输入矩阵

时间:2016-01-22 09:11:13

标签: python arrays numpy matrix

问题:

输入是(i,j) - 矩阵M.期望的输出是(i ^ n,j ^ n)矩阵K,其中n是所采用的乘积的数量。获得所需输出的详细方法如下

  • 生成n行排列的所有数组I(总数为i n n阵列)
  • 生成n列排列的所有数组J(总共j ** n个数组)
  • K [i,j] = m [I [0],J [0]] * ... * m [I [n],J [n]]对于范围内的所有n(len(J))

我这样做的直接方法是生成范围内所有n个排列数的标签列表(len(np.shape(m)[0]))和范围(len(np。 shape(m)[1]))分别用于行和列。之后,您可以将它们乘以上面的最后一个项目符号点。然而,这对于大输入矩阵是不实用的 - 所以我正在寻找优化上述方法的方法。提前谢谢

示例:

输入

  

np.array([[1,2,3],[4,5,6]])

n = 3

的输出
  

[[1. 2. 3. 2. 4. 6. 3. 6. 9. 2. 4. 6。        4. 8. 12. 6. 12. 18. 3. 6. 9. 6. 12. 18。        9. 18. 27。]

     

[4. 5. 6. 8. 10. 12. 12. 15. 18. 8. 10. 12。       16. 20. 24. 24. 30. 36. 12. 15. 18. 24. 30. 36。       36. 45. 54。]

     

[4. 8. 12. 5. 10. 15. 6. 12. 18. 8. 16. 24。       10. 20. 30. 12. 24. 36. 12. 24. 36. 15. 30. 45。       18. 36. 54。]

     

[16. 20. 24. 20. 25. 30. 24. 30. 36. 32. 40. 48。       40. 50. 60. 48. 60. 72. 48. 60. 72. 60. 75. 90。       72. 90. 108。]

     

[4. 8. 12. 8. 16. 24. 12. 24. 36. 5. 10. 15。       10. 20. 30. 15. 30. 45. 6. 12. 18. 12. 24. 36。       18. 36. 54。]

     

[16. 20. 24. 32. 40. 48. 48. 60. 72. 20. 25. 30。       40. 50. 60. 60. 75. 90. 24. 30. 36. 48. 48. 60. 72。       72. 90. 108。]

     

[16. 32. 48. 20. 40. 60. 24. 48. 72. 20. 40. 60。       25. 50. 75. 30. 60. 90. 24. 48. 72. 30. 60. 90。       36. 72. 108。]

     

[64. 80. 96. 80. 100. 120. 96. 120. 144. 80. 100. 120。      100. 125. 150. 120. 150. 180. 96. 120. 144. 120. 150. 180。      144. 180. 216。]]

部分解决方案:

我发现的最好的功能是创建这里提出的矩阵的笛卡尔积:https://stackoverflow.com/a/1235363/4003747 问题是输出不是矩阵而是数组数组。将每个数组的元素相乘得到I' m之后的值,但是以无序的方式。我已经尝试了一段时间,但我不知道如何明智地重新排序它们。

n = 3的低效解决方案:

import numpy as np
import itertools

m=np.array([[1,2,3],[4,5,6]])

def f(m):
    labels_i = [list(p) for p in itertools.product(range(np.shape(m)[0]),repeat=3)]
    labels_j = [list(p) for p in itertools.product(range(np.shape(m)[1]),repeat=3)]


    out = np.zeros([len(labels_i),len(labels_j)])
    for i in range(len(labels_i)):
        for j in range(len(labels_j)):
            out[i,j] = m[labels_i[i][0],labels_j[j][0]] * m[labels_i[i][1],labels_j[j][1]] * m[labels_i[i][2],labels_j[j][2]]
    return out

2 个答案:

答案 0 :(得分:6)

以下是使用broadcastinglinear indexing组合的矢量化方法 -

from itertools import product

# Get input array's shape
r,c = A.shape

# Setup arrays corresponding to labels i and j
arr_i = np.array(list(product(range(r), repeat=n)))
arr_j = np.array(list(product(range(c), repeat=n)))

# Use linear indexing with ".ravel()" to extract elements.
# Perform elementwise product along the rows for the final output
out = A.ravel()[(arr_i*c)[:,None,:] + arr_j].prod(2)

运行时测试和输出验证 -

In [167]: # Inputs          
     ...: n = 4
     ...: A = np.array([[1,2,3],[4,5,6]])
     ...: 
     ...: def f(m):
     ...:   labels_i = [list(p) for p in product(range(np.shape(m)[0]),repeat=n)]
     ...:   labels_j = [list(p) for p in product(range(np.shape(m)[1]),repeat=n)]
     ...: 
     ...:   out = np.zeros([len(labels_i),len(labels_j)])
     ...:   for i in range(len(labels_i)):
     ...:      for j in range(len(labels_j)):
     ...:          out[i,j] = m[labels_i[i][0],labels_j[j][0]] \
     ...:                   * m[labels_i[i][1],labels_j[j][1]] \
     ...:                   * m[labels_i[i][2],labels_j[j][2]] \
     ...:                   * m[labels_i[i][3],labels_j[j][3]]
     ...:   return out
     ...: 
     ...: def f_vectorized(A,n):
     ...:   r,c = A.shape
     ...:   arr_i = np.array(list(product(range(r), repeat=n)))
     ...:   arr_j = np.array(list(product(range(c), repeat=n)))
     ...:   return A.ravel()[(arr_i*c)[:,None,:] + arr_j].prod(2)
     ...: 

In [168]: np.allclose(f_vectorized(A,n),f(A))
Out[168]: True

In [169]: %timeit f(A)
100 loops, best of 3: 2.37 ms per loop

In [170]: %timeit f_vectorized(A,n)
1000 loops, best of 3: 202 µs per loop

答案 1 :(得分:0)

这应该有效:

import numpy as np
import itertools

m=np.array([[1,2,3],[4,5,6]])
n=3 # change your n here


def f(m):
    labels_i = [list(p) for p in itertools.product(range(np.shape(m)[0]),repeat=n)]
    labels_j = [list(p) for p in itertools.product(range(np.shape(m)[1]),repeat=n)]


    out = np.zeros([len(labels_i),len(labels_j)])
    for i in range(len(labels_i)):
        for j in range(len(labels_j)):
            out[i,j] = np.prod([m[labels_i[i][k],labels_j[j][k]] for k in range(n)])
    return out