Supongamos que tiene dos matrices:
index = [1, 2, 3] counts = [2, 3, 2]o una matriz singular
arr = [1, 1, 2, 2, 2, 3, 3]¿Cómo puedo construir eficientemente la matriz?
[ [1, 1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 0, 0, 0, 3, 3], [0, 0, 0, 0, 0, 3, 3] ]con numpy?
Yo sé eso
square = np.zeros((7, 7)) np.fill_diagnol(square, arr) # see arr aboveproduce
[ [1, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0], [0, 0, 2, 0, 0, 0, 0], [0, 0, 0, 2, 0, 0, 0], [0, 0, 0, 0, 2, 0, 0], [0, 0, 0, 0, 0, 3, 0], [0, 0, 0, 0, 0, 0, 3] ] ¿Cómo "expando" la diagonal por n donde n es counts[index-1] para los valores especificados por index[I]
tmp = np.array((arr * N)).reshape((len(arr), len(arr)) np.floor( (tmp + tmp.T) / 2 ) # <-- this is closer array([[1., 1., 1., 1., 1., 2., 2.], [1., 1., 1., 1., 1., 2., 2.], [1., 1., 2., 2., 2., 2., 2.], [1., 1., 2., 2., 2., 2., 2.], [1., 1., 2., 2., 2., 2., 2.], [2., 2., 2., 2., 2., 3., 3.], [2., 2., 2., 2., 2., 3., 3.]])Esto obtiene lo que quiero, pero probablemente no escale tan bien.
riffled = list(zip(index, counts)) riffled # [(1, 2), (2, 3), (3, 2)] a = np.zeros((len(arr), len(arr))) # 7, 7 square last = 0 # <-- keep track of current sub square for i, c in riffled: a[last:last+c, last:last+c] = np.ones((c, c)) * i last += c # <-- shift squareproducir
array([[1., 1., 0., 0., 0., 0., 0.], [1., 1., 0., 0., 0., 0., 0.], [0., 0., 2., 2., 2., 0., 0.], [0., 0., 2., 2., 2., 0., 0.], [0., 0., 2., 2., 2., 0., 0.], [0., 0., 0., 0., 0., 3., 3.], [0., 0., 0., 0., 0., 3., 3.]])Puede usar scipy.linalg.block_diag para que funcione:
import numpy as np import scipy.linalg as linalg a = 1*np.ones((2,2)) b = 2*np.ones((3,3)) c = 3*np.ones((2,2)) superBlock = linalg.block_diag(a,b,c) print(superBlock) #returns #[[1. 1. 0. 0. 0. 0. 0.] # [1. 1. 0. 0. 0. 0. 0.] # [0. 0. 2. 2. 2. 0. 0.] # [0. 0. 2. 2. 2. 0. 0.] # [0. 0. 2. 2. 2. 0. 0.] # [0. 0. 0. 0. 0. 3. 3.] # [0. 0. 0. 0. 0. 3. 3.]]si desea llegar allí desde una lista de valores y una lista de recuentos, puede hacer esto:
values = [1,2,3] counts = [2,3,2] mats = [] for v,c in zip(values,counts): thisMatrix = v*np.ones((c,c)) mats.append( thisMatrix ) superBlock = linalg.block_diag(*mats) print(superBlock)Aquí hay una solución genérica.
index = [1, 2, 1] counts = [2, 3, 2] arr = np.repeat(index, counts) arr2 = np.repeat(range(len(index)), counts) np.where(arr2 == arr2[:, None], arr, 0)producción:
array([[1, 1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1]]) arr = np.array([1, 1, 2, 2, 2, 1, 2]) arr2 = np.cumsum(np.diff(arr,prepend=np.nan) != 0) np.where(arr2 == arr2[:, None], arr, 0)producción:
array([[1, 1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 2]])Intenta transmitir:
idx = np.repeat(np.arange(len(counts)), counts) np.where(idx==idx[:,None], arr, 0) # or # arr * (idx==idx[:,None])Producción;
array([[1, 1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 2, 2, 2, 0, 0], [0, 0, 0, 0, 0, 3, 3], [0, 0, 0, 0, 0, 3, 3]])