Python 用Numpy生成对称矩阵

Python 用Numpy生成对称矩阵,python,random,matrix,numpy,adjacency-matrix,Python,Random,Matrix,Numpy,Adjacency Matrix,我试图用numpy生成对称矩阵。具体来说,这些矩阵具有随机位置条目,并且在每个条目中,内容可以是随机的。沿着主对角线,我们不关心实体在那里是什么,所以我也随机化了它们 我采用的方法是首先生成一个nxn全零矩阵,然后简单地循环矩阵的索引。然而,考虑到循环在python中相对昂贵,我想知道我是否可以在不使用python for循环的情况下实现同样的功能 numpy中是否有一些东西可以让我更有效地实现我的目标 这是我目前的代码: import numpy as np import random de

我试图用numpy生成对称矩阵。具体来说,这些矩阵具有随机位置条目,并且在每个条目中,内容可以是随机的。沿着主对角线,我们不关心实体在那里是什么,所以我也随机化了它们

我采用的方法是首先生成一个nxn全零矩阵,然后简单地循环矩阵的索引。然而,考虑到循环在python中相对昂贵,我想知道我是否可以在不使用python for循环的情况下实现同样的功能

numpy中是否有一些东西可以让我更有效地实现我的目标

这是我目前的代码:

import numpy as np
import random

def empty(x, y):
    return x*0

b = np.fromfunction(empty, (n, n), dtype = int)

for i in range(0, n):
    for j in range(0, n):
        if i == j:
            b[i][j] = random.randrange(-2000, 2000)
        else:
            switch = random.random()
            random.seed()
            if switch > random.random():
                a = random.randrange(-2000, 2000)
                b[i][j] = a
                b[j][i] = a
            else:
                b[i][j] = 0
                b[j][i] = 0

你可以这样做:

import numpy as np

N = 100
b = np.random.random_integers(-2000,2000,size=(N,N))
b_symm = (b + b.T)/2
您可以在
np.random
或等效的scipy模块中选择所需的任何分布

更新:如果您试图构建类似图形的结构,请务必查看networkx软件包:

它有许多内置例程来构建图形:

此外,如果您想添加一些随机放置的零,则始终可以生成一组随机索引,并将值替换为零。

我最好执行以下操作:

a = np.random.rand(N, N)
m = np.tril(a) + np.tril(a, -1).T

因为在这种情况下,矩阵的所有元素都来自相同的分布(在这种情况下是一致的)。

如果您不介意对角线上有零,可以使用以下代码片段:

def random_symmetric_matrix(n):
    _R = np.random.uniform(-1,1,n*(n-1)/2)
    P = np.zeros((n,n))
    P[np.triu_indices(n, 1)] = _R
    P[np.tril_indices(n, -1)] = P.T[np.tril_indices(n, -1)]
    return P

注意,由于对称性,您只需要生成n*(n-1)/2个随机变量。

我使用以下函数使矩阵在垂直和水平方向上对称:

def make_sym(a):
    w, h = a.shape
    a[w - w // 2 :, :] = np.flipud(a[:w // 2, :])
    a[:, h - h // 2:] = np.fliplr(a[:, :h // 2])
让我们看看它是如何工作的:

>>> m = (np.random.rand(10, 10) * 10).astype(np.int)
>>> make_sym(m)
>>> m
array([[2, 7, 5, 7, 7, 7, 7, 5, 7, 2],
       [6, 3, 9, 3, 6, 6, 3, 9, 3, 6],
       [1, 4, 6, 7, 2, 2, 7, 6, 4, 1],
       [9, 2, 7, 0, 8, 8, 0, 7, 2, 9],
       [5, 5, 6, 1, 9, 9, 1, 6, 5, 5],
       [5, 5, 6, 1, 9, 9, 1, 6, 5, 5],
       [9, 2, 7, 0, 8, 8, 0, 7, 2, 9],
       [1, 4, 6, 7, 2, 2, 7, 6, 4, 1],
       [6, 3, 9, 3, 6, 6, 3, 9, 3, 6],
       [2, 7, 5, 7, 7, 7, 7, 5, 7, 2]])

这里有一个优雅的答案,即生成一个矩阵,其中所有条目遵循相同的分布。但是,该答案会丢弃
(n-1)*n/2
随机数,而不使用它们

如果希望所有值都遵循相同的分布,请一次生成所有值并仅生成要使用的值,然后可以运行以下操作:

>>将numpy作为np导入
>>>n=5
>>>r=np.random.rand(n*(n+1)//2)
>>>sym=np.零((n,n))
>>>对于范围(n)中的i:
...     t=i*(i+1)//2
...     sym[i,0:i+1]=r[t:t+i+1]
...     sym[0:i,i]=r[t:t+i]
... 
>>>打印(sym)
[[0.03019945 0.30679756 0.85722724 0.78498237 0.56146757]
[0.30679756 0.46276869 0.45104513 0.28677046 0.10779794]
[0.85722724 0.45104513 0.62193894 0.86898652 0.11543257]
[0.78498237 0.28677046 0.86898652 0.13929717 0.45309959]
[0.56146757 0.10779794 0.11543257 0.45309959 0.5671571 ]]

这里的想法是跟随三角形数字,以了解之前已经使用了随机向量中的多少个元素。给定此
t
值,将当前行填充至对角线并包括对角线,将当前列填充至对角线(但不包括对角线)。

矩阵中有一个数学特性,允许轻松创建此类结构:a.t*a其中a是行向量,a.t是转置(列向量)。这总是返回一个平方正定对称矩阵,它总是可逆的,所以您不必担心空枢轴;)


这对我有用

谢谢!这是一个有效的解决办法。然而,有没有什么方法可以让它在随机的地方放置零呢?这个矩阵应该代表一种图的邻接矩阵,所以最好是有一个随机分布的零的矩阵。@Ryan:你关心随机项的分布吗?如果你加上
b+b.T
,你会得到一个集中在0附近的非均匀分布。我正在验证矩阵的一些性质。它更多的是为一些数学性质提供令人信服的证据,所以这里的分布并不重要。谢谢你@没错,那就使用
np.tril(a)+np.tril(a,-1).T
吧。这是保持相同分布的非常优雅的方法!ps:“始终可逆”适用于矩阵,而不是向量。因此,使用mt.rand(大小,大小)在数字上更可靠。它将返回一个大小为x的矩阵,但计算成本更高。
# any matrix algebra will do it, numpy is simpler
import numpy.matlib as mt

# create a row vector of given size
size  = 3
A = mt.rand(1,size)

# create a symmetric matrix size * size
symmA = A.T * A

import numpy as np

n = 5
M = np.random.randint(-2000,2000,(n,n))
symm = M@M.T
# test for symmetry
print(symm == symm.T)