Python 无Numpy嵌套列表上的递归迭代
我想迭代一个嵌套列表。我只找到了一个使用Numpy(->在else的情况下)的解决方案,但我想知道如果没有Numpy,这是否可能Python 无Numpy嵌套列表上的递归迭代,python,numpy,slice,matrix-multiplication,Python,Numpy,Slice,Matrix Multiplication,我想迭代一个嵌套列表。我只找到了一个使用Numpy(->在else的情况下)的解决方案,但我想知道如果没有Numpy,这是否可能 import numpy as np def matrix_mulitplication(A, B): n = A.shape[0] if n == 1: return A * B else: i = int(n / 2) C = np.zeros((n, n), dtype=np.int)
import numpy as np
def matrix_mulitplication(A, B):
n = A.shape[0]
if n == 1:
return A * B
else:
i = int(n / 2)
C = np.zeros((n, n), dtype=np.int)
C[:i, :i] = matrix_mulitplication(A[:i, :i], B[:i, :i]) + matrix_mulitplication(A[:i, i:], B[i:, :i])
C[:i, i:] = matrix_mulitplication(A[:i, :i], B[:i, i:]) + matrix_mulitplication(A[:i, i:], B[i:, i:])
C[i:, :i] = matrix_mulitplication(A[i:, :i], B[:i, :i]) + matrix_mulitplication(A[i:, i:], B[i:, :i])
C[i:, i:] = matrix_mulitplication(A[i:, :i], B[:i, i:]) + matrix_mulitplication(A[i:, i:], B[i:, i:])
return C
x = np.array([[1, 2], [3, 4]])
y = np.array([[1, 2], [3, 4]])
print(matrix_mulitplication(x, y))
输出:
[[ 7 10]
[15 22]]
我对第一个切片案例的想法是:
c_one = [C[i][0:int(len(C) / 2)] for i in range(0,int(len(C) / 2))]
在
numpy
中,您只需执行二维矩阵乘法,它可以用多种方式表示,例如np.dot
、np.einsum
或(新的)@
运算符
In [1]: x = np.array([[1, 2], [3, 4]])
In [2]: x@x
Out[2]:
array([[ 7, 10],
[15, 22]])
要对列表执行同样的操作,让我们分步骤完成任务
在代数课上,我学会了用一根手指横穿行,另一根手指横穿列。因此,让我们用一个列表来理解:
In [6]: x1 = x.tolist()
In [7]: x2 = x.tolist()
In [8]: [[(row1,col2) for col2 in zip(*x2)] for row1 in x1]
Out[8]: [[([1, 2], (1, 3)), ([1, 2], (2, 4))], [([3, 4], (1, 3)), ([3, 4], (2, 4))]]
行和列的配对看起来是正确的zip(*xl)
是“转置”列表的习惯用法(相当于numpy中的x.T
)
现在定义一个执行1d乘法的辅助函数:
In [9]: def mult(row,col):
...: return [i*j for i,j in zip(row,col)]
...:
...:
In [10]: [[mult(row1,col2) for col2 in zip(*x2)] for row1 in x1]
Out[10]: [[[1, 6], [2, 8]], [[3, 12], [6, 16]]]
现在加上总和。我可以回去修改mult
,但在外部理解中做同样容易
In [12]: [[sum(mult(row1,col2)) for col2 in zip(*x2)] for row1 in x1]
Out[12]: [[7, 10], [15, 22]]
或结合所有列表理解,形成一行不可读的内容:
In [14]: [[sum(i*j for i,j in zip(row1,col2)) for col2 in zip(*x2)] for row1 in x1]
Out[14]: [[7, 10], [15, 22]]
对于这个2x2示例,我的结果与您的结果相同,但您采用了不同的方法,将原始数组拆分为块。可以使用切片良好的
numpy
阵列。但我不确定它对列表是否有帮助。我们还得考虑其他的例子
Mine使用3x3阵列
In [29]: y = np.arange(9).reshape(3,3)
In [30]: [[sum(mult(row1,col2)) for col2 in zip(*y.tolist())] for row1 in y.toli
...: st()]
Out[30]: [[15, 18, 21], [42, 54, 66], [69, 90, 111]]
In [31]: y@y
Out[31]:
array([[ 15, 18, 21],
[ 42, 54, 66],
[ 69, 90, 111]])
在3x3上,由于形状广播错误,您的操作失败,但在4x4上也同样有效
In [32]: y = np.arange(16).reshape(4,4)
In [33]: y@y
Out[33]:
array([[ 56, 62, 68, 74],
[152, 174, 196, 218],
[248, 286, 324, 362],
[344, 398, 452, 506]])
In [34]: [[sum(mult(row1,col2)) for col2 in zip(*y.tolist())] for row1 in y.toli
...: st()]
Out[34]:
[[56, 62, 68, 74],
[152, 174, 196, 218],
[248, 286, 324, 362],
[344, 398, 452, 506]]
In [35]: matrix_mulitplication(y,y)
Out[35]:
array([[ 56, 62, 68, 74],
[152, 174, 196, 218],
[248, 286, 324, 362],
[344, 398, 452, 506]])
所以你的递归就是把4x4分解成2x2块,然后再分解成1x1。Mine将2d数组分解为一维乘积和 尝试复制nxn块细分。我使用了
blk
helper函数来复制2d数组切片:
import numpy as np
def matrix_mulitplication(A, B):
def blk(x,i1,i2):
return [row[i2] for row in x[i1]]
n = len(A) # A.shape[0]
if n == 1:
#print(A)
return A[0][0] * B[0][0]
else:
i = int(n / 2)
i1, i2 = slice(None,i), slice(i,None)
#C = np.zeros((n, n), dtype=np.int)
C1 = matrix_mulitplication(blk(A, i1, i1), blk(B,i1,i1)) +\
matrix_mulitplication(blk(A, i1, i2), blk(B,i2,i1))
C2 = matrix_mulitplication(blk(A, i1, i1), blk(B,i1,i2)) +\
matrix_mulitplication(blk(A, i1, i2), blk(B,i2,i2))
C3 = matrix_mulitplication(blk(A, i2, i1), blk(B,i1,i1)) +\
matrix_mulitplication(blk(A, i2, i2), blk(B,i2,i1))
C4 = matrix_mulitplication(blk(A, i2, i1), blk(B,i1,i2)) +\
matrix_mulitplication(blk(A, i2, i2), blk(B,i2,i2))
C = [[C1,C2],[C3,C4]]
return C
x = np.array([[1, 2], [3, 4]])
y = np.arange(16).reshape(4,4)
z = matrix_mulitplication([[1]],[[2]])
print(z)
z = matrix_mulitplication(x.tolist(), x.tolist())
print(z)
print(x@x)
z = matrix_mulitplication(y.tolist(), y.tolist())
print(z)
print(y@y)
这适用于一个级别的递归,但不适用于两个级别:
1253:~/mypy$ python3 stack50552791.py
2
[[7, 10], [15, 22]]
[[ 7 10]
[15 22]]
[[[[4, 5], [20, 29], [52, 57], [132, 145]], [[6, 7], [38, 47], [62, 67], [158, 171]]], [[[36, 53], [52, 77], [212, 233], [292, 321]], [[70, 87], [102, 127], [254, 275], [350, 379]]]]
[[ 56 62 68 74]
[152 174 196 218]
[248 286 324 362]
[344 398 452 506]]
第二级的问题是matrix\u mulitapplication
返回一个嵌套列表,列表+
被定义为串联,而不是元素添加。因此,我必须定义另一个helper函数(或2)来正确地解决这个问题
好一点
对于4x4的情况
[[[[56, 62], [152, 174]], [[68, 74], [196, 218]]], [[[248, 286], [344, 398]], [[324, 362], [452, 506]]]]
[[ 56 62 68 74]
[152 174 196 218]
[248 286 324 362]
[344 398 452 506]]
数字都在那里,但在一个4深度的嵌套列表中
因此,不仅将嵌套列表分解为2d块比使用数组更为棘手,而且重新组合它们也很棘手
在不详细阅读Strassen算法的情况下,很明显,任何关于其效率的声明都假定A_ij
索引(对于单个元素或块)在获取值和设置(C_ij
)时都是有效的。对于列表,A[i]
或A[i:j]
是相当有效的,但是x[i1]中的行的[row[i2]不是
用[[a,b],[c,d]
组装块是可以的,但是任何类似[[c_11,c_12],[c_21,c_22]
的元素都是块而不是标量,这是很复杂的
Strassen的目标似乎是减少所需的乘法次数。这假设(标量)乘法是矩阵乘法中最昂贵的部分。对于Python列表,情况显然不是这样。访问元素的成本更高
小骗子
我可以用
arr = np.array(z)
arr = arr.transpose(0,2,1,3).reshape(4,4)
这在numpy
两级嵌套中就容易多了?@YakymPirozhenko确切地说是itertools.chain(*nested_list)
?@NickA首先更新了代码,谢谢你的详细解释。我知道矩阵乘法有更简单的方法,但我的方法是使用分治范式(Strassen算法的前一步)。我的问题不是关于不同的方法,而是更多的是关于嵌套列表的切片运算符,这些嵌套列表可以不使用numpy。切片嵌套列表的nxn块是可能的,但很混乱。您将创建新的列表,没有任何类型的视图。[row[:i]用于列表中的row[:i]
。
arr = np.array(z)
arr = arr.transpose(0,2,1,3).reshape(4,4)