从 NumPy 或 PyTorch 中的矩阵获取对角线 "stripe"
Getting diagonal "stripe" from matrix in NumPy or PyTorch
我需要得到矩阵的对角“条纹”。假设我有一个大小为 KxN (K>N) 的矩阵:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
我需要从中提取对角条纹,在本例中,是通过截断原始条纹创建的矩阵 MxV 大小:
[[ 0 x x]
[ 3 4 x]
[ x 7 8]
[ x x 11]]
所以结果矩阵为:
[[ 0 4 8]
[ 3 7 11]]
我可以像这样定义一个布尔掩码:
import numpy as np
X=np.arange(12).reshape(4,3)
mask=np.asarray([
[ True, False, False],
[ True, True, False],
[ False, True, True],
[ False, False, True]
])
>>> X
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
>>> X.T[mask.T].reshape(3,2).T
array([[ 0, 4, 8],
[ 3, 7, 11]])
但我看不出如何将这样的掩码自动生成到任意 KxN 矩阵(例如 39x9、360x96)
在 numpy
、scipy
或 pytorch
中是否有自动执行此操作的函数?
附加问题:是否可以改用“反条纹”?即
[[ x x 2]
[ x 4 5]
[ 6 7 x]
[ 9 x x]]
stride_tricks
试试看:
>>> import numpy as np
>>>
>>> def stripe(a):
... a = np.asanyarray(a)
... *sh, i, j = a.shape
... assert i >= j
... *st, k, m = a.strides
... return np.lib.stride_tricks.as_strided(a, (*sh, i-j+1, j), (*st, k, k+m))
...
>>> a = np.arange(24).reshape(6, 4)
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])
>>> stripe(a)
array([[ 0, 5, 10, 15],
[ 4, 9, 14, 19],
[ 8, 13, 18, 23]])
如果 a
是一个数组,这将创建一个可写视图,这意味着如果您愿意,您可以做类似
的事情
>>> stripe(a)[...] *= 10
>>> a
array([[ 0, 1, 2, 3],
[ 40, 50, 6, 7],
[ 80, 90, 100, 11],
[ 12, 130, 140, 150],
[ 16, 17, 180, 190],
[ 20, 21, 22, 230]])
更新:左下角到右上角的条纹可以以同样的精神获得。唯一的小麻烦:它不是基于与原始数组相同的地址。
>>> def reverse_stripe(a):
... a = np.asanyarray(a)
... *sh, i, j = a.shape
... assert i >= j
... *st, k, m = a.strides
... return np.lib.stride_tricks.as_strided(a[..., j-1:, :], (*sh, i-j+1, j), (*st, k, m-k))
...
>>> a = np.arange(24).reshape(6, 4)
>>> reverse_stripe(a)
array([[12, 9, 6, 3],
[16, 13, 10, 7],
[20, 17, 14, 11]])
扩展 Paul 的回答。您可以在 PyTorch 中多次使用 diag 执行相同的操作(我认为在 PyTorch 中没有任何直接的功能可以大步前进)
import torch
def stripe(a):
i, j = a.size()
assert(i>=j)
out = torch.zeros((i-j+1, j))
for diag in range(0, i-j+1):
out[diag] = torch.diag(a, -diag)
return out
a = torch.randn((6, 3))
>>> a
0.7669 0.6808 -0.6102
-1.0624 -1.2016 -0.7308
1.4054 -1.0621 0.2618
-0.9505 -0.9322 -0.4321
-0.0134 -1.3684 0.1883
-0.8499 0.2533 -0.3976
[torch.FloatTensor of size 6x3]
>>> stripe(a)
0.7669 -1.2016 0.2618
-1.0624 -1.0621 -0.4321
1.4054 -0.9322 0.1883
-0.9505 -1.3684 -0.3976
[torch.FloatTensor of size 4x3]
是的,您可以在 NumPy 中通过为其内置的 numpy.diagonal()
:
提供一个 offset
值来做到这一点
a = np.array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[9,10,11]])
stripe = np.array([a.diagonal(),
a.diagonal(-1)])
>>> stripe
array([[ 0, 4, 8],
[ 3, 7, 11]])
对于任意 KxN 矩阵,您可以获得可变宽度的条纹:
stripe = [a.diagonal(i) for i in range(K,N,-1)]
PyTorch 的 torch.diagonal()
具有完全相同的功能。
我需要得到矩阵的对角“条纹”。假设我有一个大小为 KxN (K>N) 的矩阵:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
我需要从中提取对角条纹,在本例中,是通过截断原始条纹创建的矩阵 MxV 大小:
[[ 0 x x]
[ 3 4 x]
[ x 7 8]
[ x x 11]]
所以结果矩阵为:
[[ 0 4 8]
[ 3 7 11]]
我可以像这样定义一个布尔掩码:
import numpy as np
X=np.arange(12).reshape(4,3)
mask=np.asarray([
[ True, False, False],
[ True, True, False],
[ False, True, True],
[ False, False, True]
])
>>> X
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
>>> X.T[mask.T].reshape(3,2).T
array([[ 0, 4, 8],
[ 3, 7, 11]])
但我看不出如何将这样的掩码自动生成到任意 KxN 矩阵(例如 39x9、360x96)
在 numpy
、scipy
或 pytorch
中是否有自动执行此操作的函数?
附加问题:是否可以改用“反条纹”?即
[[ x x 2]
[ x 4 5]
[ 6 7 x]
[ 9 x x]]
stride_tricks
试试看:
>>> import numpy as np
>>>
>>> def stripe(a):
... a = np.asanyarray(a)
... *sh, i, j = a.shape
... assert i >= j
... *st, k, m = a.strides
... return np.lib.stride_tricks.as_strided(a, (*sh, i-j+1, j), (*st, k, k+m))
...
>>> a = np.arange(24).reshape(6, 4)
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])
>>> stripe(a)
array([[ 0, 5, 10, 15],
[ 4, 9, 14, 19],
[ 8, 13, 18, 23]])
如果 a
是一个数组,这将创建一个可写视图,这意味着如果您愿意,您可以做类似
>>> stripe(a)[...] *= 10
>>> a
array([[ 0, 1, 2, 3],
[ 40, 50, 6, 7],
[ 80, 90, 100, 11],
[ 12, 130, 140, 150],
[ 16, 17, 180, 190],
[ 20, 21, 22, 230]])
更新:左下角到右上角的条纹可以以同样的精神获得。唯一的小麻烦:它不是基于与原始数组相同的地址。
>>> def reverse_stripe(a):
... a = np.asanyarray(a)
... *sh, i, j = a.shape
... assert i >= j
... *st, k, m = a.strides
... return np.lib.stride_tricks.as_strided(a[..., j-1:, :], (*sh, i-j+1, j), (*st, k, m-k))
...
>>> a = np.arange(24).reshape(6, 4)
>>> reverse_stripe(a)
array([[12, 9, 6, 3],
[16, 13, 10, 7],
[20, 17, 14, 11]])
扩展 Paul 的回答。您可以在 PyTorch 中多次使用 diag 执行相同的操作(我认为在 PyTorch 中没有任何直接的功能可以大步前进)
import torch
def stripe(a):
i, j = a.size()
assert(i>=j)
out = torch.zeros((i-j+1, j))
for diag in range(0, i-j+1):
out[diag] = torch.diag(a, -diag)
return out
a = torch.randn((6, 3))
>>> a
0.7669 0.6808 -0.6102
-1.0624 -1.2016 -0.7308
1.4054 -1.0621 0.2618
-0.9505 -0.9322 -0.4321
-0.0134 -1.3684 0.1883
-0.8499 0.2533 -0.3976
[torch.FloatTensor of size 6x3]
>>> stripe(a)
0.7669 -1.2016 0.2618
-1.0624 -1.0621 -0.4321
1.4054 -0.9322 0.1883
-0.9505 -1.3684 -0.3976
[torch.FloatTensor of size 4x3]
是的,您可以在 NumPy 中通过为其内置的 numpy.diagonal()
:
offset
值来做到这一点
a = np.array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[9,10,11]])
stripe = np.array([a.diagonal(),
a.diagonal(-1)])
>>> stripe
array([[ 0, 4, 8],
[ 3, 7, 11]])
对于任意 KxN 矩阵,您可以获得可变宽度的条纹:
stripe = [a.diagonal(i) for i in range(K,N,-1)]
PyTorch 的 torch.diagonal()
具有完全相同的功能。