私は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パッケージを確認してください。
グラフを作成するための組み込みルーチンがいくつかあります。
http://networkx.lanl.gov/reference/generators.html
また、ランダムに配置されたゼロの数を追加する場合は、常にインデックスのランダムなセットを生成し、値をゼロに置き換えることができます。
私はもっと良いでしょう:
a = np.random.Rand(N, N)
m = np.tril(a) + np.tril(a, -1).T
この場合、マトリックスのすべての要素は同じ分布(この場合は均一)からのものであるためです。
次の関数を使用して、行列を垂直方向と水平方向の両方で対称にします。
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
乱数を破棄します。
すべての値を同じ分布にしたい場合は、一度にすべてを生成し、使用するもののみを生成する場合は、以下を実行できます。
>>> 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
値を指定して、対角線までの現在の行と対角線までの(ただし、対角線を含まない)現在の列を入力します。
対角線上にゼロがあってもかまわない場合は、次のスニペットを使用できます。
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個の確率変数を生成するだけでよいことに注意してください。