答案 0 :(得分:6)
如果你有scipy,你可以使用sparse.random。下面的sprandsym
函数生成稀疏随机矩阵X,取其上三角形,并将其转置添加到自身以形成对称矩阵。由于这会使对角线值加倍,因此将对角线减去一次。
非零值通常以均值0和标准差分布 1. Kolomogorov-Smirnov检验用于检查非零值是否为 与正态分布的绘图,直方图和 生成QQ图也可以看到分布。
import numpy as np
import scipy.stats as stats
import scipy.sparse as sparse
import matplotlib.pyplot as plt
np.random.seed((3,14159))
def sprandsym(n, density):
rvs = stats.norm().rvs
X = sparse.random(n, n, density=density, data_rvs=rvs)
upper_X = sparse.triu(X)
result = upper_X + upper_X.T - sparse.diags(X.diagonal())
return result
M = sprandsym(5000, 0.01)
print(repr(M))
# <5000x5000 sparse matrix of type '<class 'numpy.float64'>'
# with 249909 stored elements in Compressed Sparse Row format>
# check that the matrix is symmetric. The difference should have no non-zero elements
assert (M - M.T).nnz == 0
statistic, pval = stats.kstest(M.data, 'norm')
# The null hypothesis is that M.data was drawn from a normal distribution.
# A small p-value (say, below 0.05) would indicate reason to reject the null hypothesis.
# Since `pval` below is > 0.05, kstest gives no reason to reject the hypothesis
# that M.data is normally distributed.
print(statistic, pval)
# 0.0015998040114 0.544538788914
fig, ax = plt.subplots(nrows=2)
ax[0].hist(M.data, normed=True, bins=50)
stats.probplot(M.data, dist='norm', plot=ax[1])
plt.show()
PS。我用了
upper_X = sparse.triu(X)
result = upper_X + upper_X.T - sparse.diags(X.diagonal())
而不是
result = (X + X.T)/2.0
因为我无法说服自己(X + X.T)/2.0
中的非零元素具有正确的分布。首先,如果X
密集且正态分布为均值0和方差1,即N(0, 1)
,则(X + X.T)/2.0
将为N(0, 1/2)
。当然,我们可以通过使用
result = (X + X.T)/sqrt(2.0)
代替。然后result
将是N(0, 1)
。但还有另一个问题:如果X
稀疏,那么在非零位置,X + X.T
通常是正态分布的随机变量加零。除以sqrt(2.0)
会将正态分布压缩到接近0的位置,从而使得分布更紧密。随着X
变得更稀疏,这可能越来越不像正态分布。
由于我不知道分布(X + X.T)/sqrt(2.0)
生成了什么,我选择复制X
的上三角半部分(因此重复我所知道的正常分布的非零值)。
答案 1 :(得分:3)
矩阵也需要是对称的,这似乎是由两个答案掩盖了;
def sparseSym(rank, density=0.01, format='coo', dtype=None, random_state=None):
density = density / (2.0 - 1.0/rank)
A = scipy.sparse.rand(rank, rank, density=density, format=format, dtype=dtype, random_state=random_state)
return (A + A.transpose())/2
这将创建一个稀疏矩阵,然后将其转置为自身以使其对称。
考虑到这样一个事实,即当你将两者加在一起时,密度会增加,而且对角线的密度没有额外的增加。
答案 2 :(得分:1)
unutbu的答案是性能和可扩展性最好的答案 - numpy和scipy一起,有很多来自matlab的功能。
如果您因任何原因无法使用它们,或者您正在寻找纯python解决方案,那么您可以尝试
from random import randgauss, randint
sparse = [ [0 for i in range(N)] for j in range(N)]
# alternatively, if you have numpy but not scipy:
# sparse = numpy.zeros(N,N)
for _ in range(num_terms):
(i,j) = (randint(0,n),randint(0,n))
x = randgauss(0,1)
sparse[i][j] = x
sparse[j][i] = x
虽然它可能比unutbu的解决方案给你更多的控制,你应该期望它明显更慢; scipy是你可能不想避免的依赖