Генерация симметричных матриц в Numpy

Я пытаюсь создать симметричные матрицы в numpy. В частности, эти матрицы должны иметь записи случайных мест, и в каждой записи содержимое может быть случайным. Вдоль главной диагонали нас не интересует, что там внутри, поэтому я их тоже произвольно распределил.

Подход, который я использовал, состоит в том, чтобы сначала сгенерировать полностью нулевую матрицу nxn и просто перебрать индексы матриц. Однако, учитывая, что использование циклов в Python относительно дорого, мне интересно, смогу ли я добиться того же без использования циклов for в Python.

Есть ли какие-то вещи, встроенные в 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

person Ryan    schedule 29.05.2012    source источник


Ответы (7)


Вы можете просто сделать что-то вроде:

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:

http://networkx.lanl.gov

который имеет ряд встроенных подпрограмм для построения графиков:

http://networkx.lanl.gov/reference/generators.html

Также, если вы хотите добавить некоторое количество случайно размещенных нулей, вы всегда можете сгенерировать случайный набор индексов и заменить значения на ноль.

person JoshAdel    schedule 29.05.2012
comment
Спасибо! Это эффективное решение. Однако есть ли способ заставить его случайным образом расставлять нули в местах? Эта матрица должна представлять своего рода матрицу смежности для графа, поэтому предпочтительнее иметь матрицу со случайно распределенными нулями. - person Ryan; 30.05.2012
comment
@Ryan: Тебе важно, какое распределение имеют случайные записи? Если вы добавите b + b.T, вы получите неравномерное распределение, сосредоточенное около 0. - person unutbu; 30.05.2012
comment
Проверяю некоторые свойства матриц. Это больше попытка предоставить убедительные доказательства некоторых математических свойств, поэтому распределение здесь не так важно. Спасибо хоть! - person Ryan; 30.05.2012
comment
@unutbu, правда, тогда используйте np.tril(a) + np.tril(a, -1).T. - person Ben Usman; 06.12.2014
comment
np.random.randint(-5,5,size=(N,N)), похоже, устарел, необходимо использовать randint - person sushmit; 30.06.2021

Лучше я сделаю:

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

потому что в этом случае все элементы матрицы относятся к одному и тому же распределению (в данном случае однородному).

person Ben Usman    schedule 06.12.2014
comment
Это очень элегантный способ сохранить такое же распределение! - person Arash; 17.11.2016

Матрицы обладают математическим свойством, которое позволяет легко создавать такую ​​структуру: A.T * A, где A - вектор-строка, а A.t - транспонирование (вектор-столбец). Это всегда возвращает квадратную положительно определенную симметричную матрицу, которая всегда обратима, поэтому вам не о чем беспокоиться с нулевыми точками поворота;)

# 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

person Bruno    schedule 21.04.2020
comment
ps: всегда обратимый верно для матриц, а не для векторов. Таким образом, было бы численно более надежным выполнить mt.rand (size, size). В любом случае он вернет матрицу размера x, но более затратную в вычислительном отношении. - person Bruno; 21.04.2020

import numpy as np

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

Это сработало для меня

person Apoorv Mote    schedule 16.06.2020

Если вы не против, чтобы на диагонали были нули, вы можете использовать следующий фрагмент:

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 случайных величин из-за симметрии.

person Aetienne Sardon    schedule 04.11.2015

Я использую следующую функцию, чтобы сделать матрицу симметричной как по вертикали, так и по горизонтали:

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]])
person a5kin    schedule 16.12.2016

Здесь есть элегантный ответ, который создает матрицу, в которой все элементы соответствуют одному и тому же распределению. Однако этот ответ отбрасывает (n-1)*n/2 случайные числа без их использования.

Если вы хотите, чтобы все значения следовали одному и тому же распределению, сгенерировать их все сразу и сгенерировать только те, которые вы собираетесь использовать, вы можете запустить следующее:

>>> import numpy as np
>>> n = 5
>>> r = np.random.rand(n*(n+1)//2)
>>> sym = np.zeros((n,n))
>>> for i in range(n):
...     t = i*(i+1)//2
...     sym[i,0:i+1] = r[t:t+i+1]
...     sym[0:i,i] = r[t:t+i]
... 
>>> print(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, заполните текущую строку до диагонали включительно и текущий столбец до диагонали (но не включая).

person Fábio Reale    schedule 08.10.2019