Python 是否将上部三角形项目的平面列表复制到完整矩阵?

Python 是否将上部三角形项目的平面列表复制到完整矩阵?,python,performance,numpy,Python,Performance,Numpy,我有一个平面列表(连接行)中对称矩阵的上部三角形条目(包括对角线),我想用它们填充完整的矩阵,包括下部三角形。最快的方法是什么 这是我目前的做法。这么简单的操作似乎需要做很多工作 import numpy as np def utri2mat(utri,ntotal): iu1 = np.triu_indices(ntotal) ret = np.zeros([ntotal,ntotal]) ret[iu1] = utri ret = ret + ret.tran

我有一个平面列表(连接行)中对称矩阵的上部三角形条目(包括对角线),我想用它们填充完整的矩阵,包括下部三角形。最快的方法是什么

这是我目前的做法。这么简单的操作似乎需要做很多工作

import numpy as np
def utri2mat(utri,ntotal):
    iu1 = np.triu_indices(ntotal)
    ret = np.zeros([ntotal,ntotal])
    ret[iu1] = utri
    ret = ret + ret.transpose() - np.diag(ret.diagonal())
    return ret

此版本与您的略有不同:

import numpy as np

def utri2mat(utri):
    n = int(-1 + np.sqrt(1 + 8*len(utri))) // 2
    iu1 = np.triu_indices(n)
    ret = np.empty((n, n))
    ret[iu1] = utri
    ret.T[iu1] = utri
    return ret
我换了

    ret = ret + ret.transpose() - np.diag(ret.diagonal())
utri
直接赋值到
ret
的转置:

    ret.T[iu1] = utri
我还删除了参数
ntotal
,而是根据
utri

的长度计算出
n
必须基于的长度。受此启发,您可以使用设置元素,因此可能非常有效。这里有一种方法可以实现它-

def mask_based_utri2mat(utri,ntotal):
    # Setup output array
    out = np.empty((ntotal,ntotal))

    # Create upper triang. mask
    mask = np.triu(np.ones((ntotal,ntotal),dtype=bool))

    # Set upper triang. elements with mask
    out[mask] = utri

    # Set lower triang. elements with transposed mask
    out.T[mask] = utri
    return out    
运行时测试-

In [52]: # Inputs
    ...: ntotal = 100
    ...: utri = np.random.rand(np.triu_indices(ntotal)[0].size)
    ...: 

In [53]: np.allclose(mask_based_utri2mat(utri,ntotal),utri2mat(utri,ntotal))
Out[53]: True

In [54]: %timeit utri2mat(utri,ntotal)
1000 loops, best of 3: 270 µs per loop

In [55]: %timeit mask_based_utri2mat(utri,ntotal)
10000 loops, best of 3: 127 µs per loop

In [56]: # Inputs
    ...: ntotal = 1000
    ...: utri = np.random.rand(np.triu_indices(ntotal)[0].size)
    ...: 

In [57]: np.allclose(mask_based_utri2mat(utri,ntotal),utri2mat(utri,ntotal))
Out[57]: True

In [58]: %timeit utri2mat(utri,ntotal)
10 loops, best of 3: 53.9 ms per loop

In [59]: %timeit mask_based_utri2mat(utri,ntotal)
100 loops, best of 3: 15.1 ms per loop

以下是我对一种更快、可能更好的方法的提名,该方法可以从平面值生成对称矩阵:

def make_sym(val, n):
    # uses boolean mask
    # uses the same lower tri as np.triu
    mask = ~np.tri(5,k=-1,dtype=bool)
    out = np.zeros((n,n),dtype=val.dtype)
    out[mask] = val
    out.T[mask] = val
    return out
测试:

In [939]: val=np.arange(1,16)
In [940]: make_sym(val, 5)
Out[940]: 
array([[ 1,  2,  3,  4,  5],
       [ 2,  6,  7,  8,  9],
       [ 3,  7, 10, 11, 12],
       [ 4,  8, 11, 13, 14],
       [ 5,  9, 12, 14, 15]])
与其他答案一样,它使用
out.T[]
分配下三角形

Warren的答案使用了
np.triu_指数
,即
中的值。这种类型的索引比布尔屏蔽慢一点

但正如我所指出的,Divakar使用的
np.triu
在早期的
numpy
版本(例如1.9)中没有返回布尔掩码。这就是促使我深入研究这个问题的原因

在1.10中,该函数被改写为:

mask = np.tri(*m.shape[-2:], k=k-1, dtype=bool)
return np.where(mask, np.zeros(1, m.dtype), m)

通过将
where
替换为
~掩码
,我获得了一点速度。相同的结果,但只是删去了一个中间步骤。

假设你有一个包含对称矩阵(nx n)的上三角值的向量,那么你可以如下重新构建完整的矩阵:

import numpy as np

# dimension of the full matrix
n = 80

# artificial upper triangle entries n(n-1) / 2 if matrix is symmetric
entries = np.array(range((80*79) / 2))

full_matrix = np.zeros((n,n))
inds = np.triu_indices_from(full_matrix, k = 1)
full_matrix[inds] = entries
full_matrix[(inds[1], inds[0])] = entries

print(full_matrix)
核实:

np.allclose(full_matrix, full_matrix.T)

我不知道怎样才能使它变得更简单。你的对称矩阵由3个不同的部分组成,上下三角形和对角线。在我的测试中,
utri2mat
使用平面阵列,基于掩码的utri2mat
需要一个
(ntotal,ntotal)
阵列。问题在于
out[mask]=utri
<代码>输出[np.where(mask)]=utri是否正确
np.triu_索引
做了什么
where
@hpaulj不确定我是否正确遵循了-即使是OP的
utri2mat
也会生成带有
ret=np.zero([ntotal,ntotal])的数组
,对吧?2014年7月有一个
np.triu
的补丁:。旧版本返回的是
int
数组,而不是
bool
。没有这个补丁,沃伦的答案会更好。@hpaulj运行时更好?我使用的是最新的
1.10.1
NumPy版本,使用
ntotal=100
进行了尝试,使用
mask\u-based\u-utri2mat
的运行时比OP和Warren的答案都好。对于
n=1000
它是
3x+
。我想知道'mask=np.tri(n).astype(bool)`是否更快。Warren的解决方案可能会慢一些,因为它使用
where
索引而不是布尔值<代码>np。tri是基本的“tri”功能。