Начиная с списка поплавков, т.е.
register = [11, 12, 13, 23, 24, 34]
Я хотел бы создать симметричные матрицы, где элементы диагонали равны нулю, т.е.
[[ 0. 11. 12. 13.]
[ 11. 0. 23. 24.]
[ 12. 23. 0. 34.]
[ 13. 24. 34. 0.]]
Поэтому я решил создать нуль с размером 4 х 4, чтобы заполнить элементы моего списка. После установки индикатора прогресса и учета смещения, чтобы не перезаписывать нули диагонали, я тогда либо переместился бы на восток (или на юг), пока не будет использовано количество ранее определенных шагов для достижения предела матрицы. После увеличения хода и сброса счетчика начальных шагов я могу ввести следующий столбец (строка), чтобы продолжить. Тем не менее, я ошибся в своем нынешнем коде (хотя бы один раз - это мой первый контакт с numpy) и только сбор урожая
[[ 0. 11. 12. 13.]
[ 11. 0. 23. 0.]
[ 12. 23. 0. 0.]
[ 13. 0. 0. 0.]]
Мой код:
import numpy as np
dimension = 4 # other matrices' dimensions will be larger
matrix = np.zeros((dimension,dimension))
register = [11, 12, 13, 23, 24, 34]
progress = 0
inner_step = 0
i = 0
for progress in range(0, (dimension + 1)):
permitted_steps = dimension - progress
for i in range(progress, permitted_steps-1):
matrix[(progress, inner_step+1+offset)] = register[0]
matrix[(inner_step+1+offset, progress)] = register[0]
inner_step += 1
del register[0]
progress += 1
inner_step = 0
offset += 1
В качестве целевой среды используется Python 2.7 (Continuum Anaconda) для Windows.
Вы были довольно близки, ваша проблема возникает, когда progress
равен или больше, чем permitted_steps-1
поскольку там нет диапазона для повторения. попробуй это:
import numpy as np
dimension = 4
matrix = np.zeros((dimension,dimension))
register = [11, 12, 13, 23, 24, 34]
progress = 0
inner_step = 0
i = 0
offset = 0
for progress in range(0, (dimension + 1)):
permitted_steps = dimension - progress
for i in range(0, permitted_steps-1):
matrix[(progress, inner_step+1+offset)] = register[0]
matrix[(inner_step+1+offset, progress)] = register[0]
inner_step += 1
del register[0]
progress += 1
inner_step = 0
offset +=1
print matrix
И это распечатает:
[[ 0. 11. 12. 13.]
[ 11. 0. 23. 24.]
[ 12. 23. 0. 34.]
[ 13. 24. 34. 0.]]
если вы измените массив регистров на длину 10:
register = [11, 12, 13, 23, 24, 34, 37, 39, 40, 43]
ты получишь:
[[ 0. 11. 12. 13. 23.]
[ 11. 0. 24. 34. 37.]
[ 12. 24. 0. 39. 40.]
[ 13. 34. 39. 0. 43.]
[ 23. 37. 40. 43. 0.]]
Просто позвоните в scipy.spatial.distance.squareform
:
>>> import scipy.spatial.distance
>>> scipy.spatial.distance.squareform([11, 12, 13, 23, 24, 34])
array([[ 0, 11, 12, 13],
[11, 0, 23, 24],
[12, 23, 0, 34],
[13, 24, 34, 0]])
Преобразование, которое вы хотите, такое же, как преобразование из матрицы с уплотненным расстоянием в квадратную матрицу расстояния, а scipy.spatial.distance.squareform
выполняет это преобразование (и его обратное). Однако будьте осторожны с dtypes; [11, 12, 13, 23, 24, 34]
- это список int, а не floats, и передача его в squareform
даст вам массив int. Вы можете преобразовать входные данные в float или вызвать result.astype(float)
если вы хотите поплавки.
Здесь один векторный подход, использующий broadcasting
и masking/boolean-indexing
-
r = np.arange(dimension)
mask = r[:,None] < r # Or in one step : ~np.tri(dimension,dtype=bool)
matrix[mask] = register
matrix.T[mask] = register
Если вам нужно вычислить dimension
из данного register
, мы могли бы использовать:
dimension = int(np.ceil(np.sqrt(2*len(register))))
И для утверждения для длины, данного dimension
, мы могли бы:
assert dimension*(dimension-1)//2 == len(register)
Кроме того, для производительности рассмотрите возможность подачи в register
массива.
Пример прогона -
In [43]: import numpy as np
...: dimension = 4 # other matrices' dimensions will be larger
...: matrix = np.zeros((dimension,dimension))
...:
...: register = [11, 12, 13, 23, 24, 34]
In [44]: r = np.arange(dimension)
...: mask = r[:,None] < r
...: matrix[mask] = register
...: matrix.T[mask] = register
In [45]: matrix
Out[45]:
array([[ 0., 11., 12., 13.],
[11., 0., 23., 24.],
[12., 23., 0., 34.],
[13., 24., 34., 0.]])
Как masking
может быть лучше, чем генерация всех треугольных индексов
Генерация индексов занимала бы больше памяти, чем создание логического массива, который по своей природе был бы эффективным с точки зрения памяти и, следовательно, обеспечивал бы лучшую производительность, особенно на больших массивах. Сроки этого будут пытаться это доказать -
In [3]: import numpy as np
...: dimension = 5000 # other matrices' dimensions will be larger
...: register = np.random.randint(0,10,dimension*(dimension-1)//2)
# With masking and boolean-indexing
In [4]: %%timeit
...: matrix = np.zeros((dimension,dimension),dtype=int)
...: r = np.arange(dimension)
...: mask = r[:,None] < r
...: matrix[mask] = register
...: matrix.T[mask] = register
10 loops, best of 3: 108 ms per loop
# With triangular indices indexing
In [5]: %%timeit
...: N = dimension
...: matrix = np.zeros((dimension,dimension),dtype=int)
...: idx = np.triu_indices(N, k=1)
...: matrix = np.zeros((N, N))
...: matrix[idx] = register
...: matrix.T[idx] = register
1 loop, best of 3: 364 ms per loop
np.triu_indices()
?
Здесь другой векторный подход с triu_indices
:
N = 4
idx = np.triu_indices(N, k=1)
matrix = np.zeros((N, N))
matrix[idx] = register
matrix.T[idx] = register
Создайте индексы для верхней треугольной матрицы с диагональным смещением 1 и затем соответствующим образом назначьте.
Убедитесь, что в регистре достаточно элементов для выполнения этой операции. Вы можете выполнить проверку предварительных условий, используя
assert len(register) == np.count_nonzero(1 - np.tri(N))