用Nan填充numpy上三角矩阵而不是零

use*_*757 8 python numpy matplotlib

我生成了一个matplotlib 3d曲面图.我只需要在图上看到矩阵的上三角形一半,因为另一半是多余的.

np.triu()使矩阵零的冗余一半,但我更喜欢如果我可以使它们为Nans,那么这些单元格在表面图上根本不显示.

什么是pythonic方式来填充NaN而不是零?我无法使用NaN进行搜索和替换0,因为零将出现在我想要显示的合法数据中.

ACh*_*ion 13

您可以使用numpy.tril_indices()NaN值分配给下三角形,例如:

>>> import numpy as np
>>> m = np.triu(np.arange(0, 12, dtype=np.float).reshape(4,3))
>>> m
array([[ 0.,  1.,  2.],
       [ 0.,  4.,  5.],
       [ 0.,  0.,  8.],
       [ 0.,  0.,  0.]])
>>> m[np.tril_indices(m.shape[0], -1)] = np.nan
>>> m
array([[  0.,   1.,   2.],
       [ nan,   4.,   5.],
       [ nan,  nan,   8.],
       [ nan,  nan,  nan]])
Run Code Online (Sandbox Code Playgroud)


Div*_*kar 6

tril_indices()可能是这里生成下三角索引的明显方法,然后您可以使用它们将输入数组中的索引设置为NaNs

现在,如果您关心性能,则可以boolean indexing在创建此类下三角形状的蒙版后使用,然后将其设置为NaNs。实施看起来像这样 -

m[np.arange(m.shape[0])[:,None] > np.arange(m.shape[1])] = np.nan
Run Code Online (Sandbox Code Playgroud)

那么,np.arange(m.shape[0])[:,None] > np.arange(m.shape[1])这里的掩码是使用创建的broadcasting

样本运行 -

In [51]: m
Out[51]: 
array([[ 11.,  49.,  23.,  30.],
       [ 40.,  41.,  19.,  26.],
       [ 32.,  36.,  30.,  25.],
       [ 15.,  27.,  25.,  40.],
       [ 33.,  18.,  45.,  43.]])

In [52]: np.arange(m.shape[0])[:,None] > np.arange(m.shape[1]) # mask
Out[52]: 
array([[False, False, False, False],
       [ True, False, False, False],
       [ True,  True, False, False],
       [ True,  True,  True, False],
       [ True,  True,  True,  True]], dtype=bool)

In [53]: m[np.arange(m.shape[0])[:,None] > np.arange(m.shape[1])] = np.nan

In [54]: m
Out[54]: 
array([[ 11.,  49.,  23.,  30.],
       [ nan,  41.,  19.,  26.],
       [ nan,  nan,  30.,  25.],
       [ nan,  nan,  nan,  40.],
       [ nan,  nan,  nan,  nan]])
Run Code Online (Sandbox Code Playgroud)

运行时测试 -

本节将本解决方案中列出的基于布尔索引的方法与性能np.tril_indices中基于布尔索引的方法进行比较。other solution

In [38]: m = np.random.randint(10,50,(1000,1100)).astype(float)

In [39]: %timeit m[np.tril_indices(m.shape[0], -1)] = np.nan
10 loops, best of 3: 62.8 ms per loop

In [40]: m = np.random.randint(10,50,(1000,1100)).astype(float)

In [41]: %timeit m[np.arange(m.shape[0])[:,None] > np.arange(m.shape[1])] = np.nan
100 loops, best of 3: 8.03 ms per loop
Run Code Online (Sandbox Code Playgroud)