преобразование списка в матрицу с помощью numpy

1

Начиная с списка поплавков, т.е.

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.

Теги:
numpy
type-conversion

4 ответа

1
Лучший ответ

Вы были довольно близки, ваша проблема возникает, когда 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.]]
  • 0
    Считая себя новичком в Python, мне очень нравится этот ответ, потому что он показал, что для успешного выполнения задачи было еще немного. Даже если другие ответы более сжатые, потому что они используют функции в numpy (и scipy), я еще не знал.
5

Просто позвоните в 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) если вы хотите поплавки.

  • 0
    Выбор целых чисел вместо истинных плавающих чисел в вопросе нацелен на упрощение проблемы. Но я согласен с вами, я буду различать их более четко, особенно в отношении Python и будущего использования numpy и, в конечном итоге, scipy.
5

Здесь один векторный подход, использующий 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
  • 0
    Есть ли какое-то преимущество перед np.triu_indices() ?
  • 1
    @ norok2 Хороший вопрос. Добавлен раздел в конце, включая время.
Показать ещё 1 комментарий
4

Здесь другой векторный подход с 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))
  • 1
    Сокращенный до сути (в виду таких сообщений, как ( academia.stackexchange.com/questions/115967/… )) плюс полезная контрольная точка в коде. К сожалению, только один раз признак принятого ответа.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню