Numpy 在所有元素之间进行乘积,然后插入到三角形二维数组中
Numpy make the product between all elemens and then insert into a triangular 2d array
假设我们得到下面的一维数组
arr = np.array([a,b,c])
我需要做的第一件事是制作所有元素的乘积,即
[ab,ac,bc]
然后用这个元素构造一个二维三角数组
[
[a,ab,ac],
[0,b,bc],
[0,0,c]
]
一种方法是计算一维数组的外积,然后根据您只需要二维三角矩阵的上三角的知识使用掩码。
import numpy as np
a = np.array([5,4,3])
n = len(a)
outer = np.outer(a, a)
outer[np.tril_indices(n)] = 0
outer[np.diag_indices(n)] = a
outer
array([[ 5, 20, 15],
[ 0, 4, 12],
[ 0, 0, 3]])
用你的一维数组创建一条对角线,并用 outer
:
的上三角填充它的上三角
out = np.diag(arr)
#upper triangle indices
uidx = np.triu_indices(arr.size,k=1)
#replacing upper triangle with outer
out[uidx]=np.outer(arr,arr)[uidx]
我们可以使用遮罩来达到我们想要的效果,像这样-
def upper_outer(a):
out = a[:,None]*a
out[np.tri(len(a), k=-1, dtype=bool)] = 0
np.fill_diagonal(out,a)
return out
样本运行-
In [84]: a = np.array([3,6,2])
In [86]: upper_outer(a)
Out[86]:
array([[ 3, 18, 6],
[ 0, 6, 12],
[ 0, 0, 2]])
基准测试
其他方法:
# @Nick Becker's soln
def tril_diag(a):
n = len(a)
outer = np.outer(a, a)
outer[np.tril_indices(n)] = 0
outer[np.diag_indices(n)] = a
return outer
# @Ehsan's soln
def triu_outer(arr):
out = np.diag(arr)
uidx = np.triu_indices(arr.size,k=1)
out[uidx]=np.outer(arr,arr)[uidx]
return out
使用 benchit
包(几个基准测试工具打包在一起;免责声明:我是它的作者)对提议的解决方案进行基准测试。
import benchit
in_ = [np.random.rand(n) for n in [10,100,200,500,1000,5000]]
funcs = [upper_outer, tril_diag, triu_outer]
t = benchit.timings(funcs, in_)
t.rank()
t.plot(logx=True, save='timings.png')
对于大型数据集,我们还可以使用numexpr
来利用多核-
import numexpr as ne
def upper_outer_v2(a):
mask = ~np.tri(len(a), dtype=bool)
out = ne.evaluate('a2D*a*mask',{'a2D':a[:,None], 'a':a, 'mask':mask})
np.fill_diagonal(out,a)
return out
新时序图:
有一个 blas
函数(几乎)用于:
# example
a = np.array([1.,2.,5.])
from scipy.linalg.blas import dsyr
# apply blas function; transpose since blas uses FORTRAN order
out = dsyr(1,a,1).T
# fix diagonal
out.reshape(-1)[::a.size+1] = a
out
# array([[ 1., 2., 5.],
# [ 0., 2., 10.],
# [ 0., 0., 5.]])
benchit
(感谢@Divakar)
假设我们得到下面的一维数组
arr = np.array([a,b,c])
我需要做的第一件事是制作所有元素的乘积,即
[ab,ac,bc]
然后用这个元素构造一个二维三角数组
[
[a,ab,ac],
[0,b,bc],
[0,0,c]
]
一种方法是计算一维数组的外积,然后根据您只需要二维三角矩阵的上三角的知识使用掩码。
import numpy as np
a = np.array([5,4,3])
n = len(a)
outer = np.outer(a, a)
outer[np.tril_indices(n)] = 0
outer[np.diag_indices(n)] = a
outer
array([[ 5, 20, 15],
[ 0, 4, 12],
[ 0, 0, 3]])
用你的一维数组创建一条对角线,并用 outer
:
out = np.diag(arr)
#upper triangle indices
uidx = np.triu_indices(arr.size,k=1)
#replacing upper triangle with outer
out[uidx]=np.outer(arr,arr)[uidx]
我们可以使用遮罩来达到我们想要的效果,像这样-
def upper_outer(a):
out = a[:,None]*a
out[np.tri(len(a), k=-1, dtype=bool)] = 0
np.fill_diagonal(out,a)
return out
样本运行-
In [84]: a = np.array([3,6,2])
In [86]: upper_outer(a)
Out[86]:
array([[ 3, 18, 6],
[ 0, 6, 12],
[ 0, 0, 2]])
基准测试
其他方法:
# @Nick Becker's soln
def tril_diag(a):
n = len(a)
outer = np.outer(a, a)
outer[np.tril_indices(n)] = 0
outer[np.diag_indices(n)] = a
return outer
# @Ehsan's soln
def triu_outer(arr):
out = np.diag(arr)
uidx = np.triu_indices(arr.size,k=1)
out[uidx]=np.outer(arr,arr)[uidx]
return out
使用 benchit
包(几个基准测试工具打包在一起;免责声明:我是它的作者)对提议的解决方案进行基准测试。
import benchit
in_ = [np.random.rand(n) for n in [10,100,200,500,1000,5000]]
funcs = [upper_outer, tril_diag, triu_outer]
t = benchit.timings(funcs, in_)
t.rank()
t.plot(logx=True, save='timings.png')
对于大型数据集,我们还可以使用numexpr
来利用多核-
import numexpr as ne
def upper_outer_v2(a):
mask = ~np.tri(len(a), dtype=bool)
out = ne.evaluate('a2D*a*mask',{'a2D':a[:,None], 'a':a, 'mask':mask})
np.fill_diagonal(out,a)
return out
新时序图:
有一个 blas
函数(几乎)用于:
# example
a = np.array([1.,2.,5.])
from scipy.linalg.blas import dsyr
# apply blas function; transpose since blas uses FORTRAN order
out = dsyr(1,a,1).T
# fix diagonal
out.reshape(-1)[::a.size+1] = a
out
# array([[ 1., 2., 5.],
# [ 0., 2., 10.],
# [ 0., 0., 5.]])
benchit
(感谢@Divakar)