Python: как создать полную матрицу расстояний из строки значений?

Привет, я хотел бы построить матрицу расстояний размером 10 x 10, и я создал список значений, который представляет собой 45 действительных чисел для заполнения матриц 10 x 10. Матрица расстояний, также известная как симметричная матрица, является зеркалом другой стороны матрицы. Моя текущая ситуация такова, что у меня есть 45 значений. Я хотел бы знать, как создать матрицу расстояний с заполненным 0 в диагональной части матрицы и создать зеркальную матрицу, чтобы сформировать полную удаленную матрицу.

Например,
1, 2, 4, 3, 5, 6

Вывод:
0, 1, 2, 4
1, 0, 3, 5
2, 3, 0, 6
4, 5, 6, 0

Спасибо.


person Allyson    schedule 23.04.2015    source источник
comment
я запутался в том, как ввод в вашем примере сопоставляется с выводом. как получить матрицу 4 X 4 из шести значений?   -  person dbliss    schedule 23.04.2015


Ответы (5)


Предполагая, что вы хотите создать матрицы расстояний произвольного размера:

import math

def distance_matrix(pattern):
    # to get the side length, solve for n where len(pattern) = n*(n + 1)/2 (triangular number formula)
    side_length = (int(math.sqrt(1 + 8 * len(pattern))) - 1) // 2 + 1
    assert (side_length * (side_length - 1)) // 2 == len(pattern), "Pattern length must be a triangular number."

    # create the grid
    grid = [[0] * side_length for i in range(side_length)]

    # fill in the grid
    position = 0
    for i in range(0, side_length - 1):
        for j in range(0, side_length - 1 - i):
            element = pattern[position]; position += 1
            grid[i][i + j + 1] = element # fill in the upper triangle
            grid[i + j + 1][i] = element # fill in the lower triangle

    return grid

def matrix_to_string(matrix): return "\n".join("\t".join(str(x) for x in row) for row in distance_matrix([1, 2, 4, 3, 5, 6]))

if __name__ == "__main__":
    print(matrix_to_string(distance_matrix([1, 2, 4, 3, 5, 6])))

РЕДАКТИРОВАТЬ: длина стороны должна быть int. В противном случае вы получите эту ошибку: объект 'float' не может быть интерпретирован как целое число. Исправление состоит в том, чтобы добавить оператор деления этажа \.

person Anthony Zhang    schedule 23.04.2015

Если вы используете NumPy, это идеальное задание для numpy.triu_indices , который возвращает пару массивов индексов, подходящих для выбора верхнего треугольника матрицы. Первый аргумент — это длина стороны матрицы, а второй — с какой диагонали начинать:

In [1]: import numpy

In [2]: x = numpy.zeros([4, 4]) # 4x4 array of zeros

In [3]: x[numpy.triu_indices(4, 1)] = [1, 2, 4, 3, 5, 6]

In [4]: x
Out[4]: 
array([[ 0.,  1.,  2.,  4.],
       [ 0.,  0.,  3.,  5.],
       [ 0.,  0.,  0.,  6.],
       [ 0.,  0.,  0.,  0.]])

In [5]: x += x.T

In [6]: x
Out[6]: 
array([[ 0.,  1.,  2.,  4.],
       [ 1.,  0.,  3.,  5.],
       [ 2.,  3.,  0.,  6.],
       [ 4.,  5.,  6.,  0.]])
person user2357112 supports Monica    schedule 23.04.2015
comment
Ха! Я знал, что это уже должно было быть сделано в numpy. - person Tom; 23.04.2015

Как насчет чего-то подобного?

# Create a zero matrix of w x h
w, h = 10, 10
matrix = [[0] * w for i in range(h)] 

# List of your numbers
numbers = range(1,46)

# Fill your numbers in
# go one row at a time and fill until you reach the diagonal
for i in range(10):
    for j in range(0, i):
            matrix[i][j] = matrix[j][i] = numbers.pop(0)

# Print all rows
for row in matrix:
    print row

Результат, который вы получаете:

[0, 1, 2, 4, 7, 11, 16, 22, 29, 37]
[1, 0, 3, 5, 8, 12, 17, 23, 30, 38]
[2, 3, 0, 6, 9, 13, 18, 24, 31, 39]
[4, 5, 6, 0, 10, 14, 19, 25, 32, 40]
[7, 8, 9, 10, 0, 15, 20, 26, 33, 41]
[11, 12, 13, 14, 15, 0, 21, 27, 34, 42]
[16, 17, 18, 19, 20, 21, 0, 28, 35, 43]
[22, 23, 24, 25, 26, 27, 28, 0, 36, 44]
[29, 30, 31, 32, 33, 34, 35, 36, 0, 45]
[37, 38, 39, 40, 41, 42, 43, 44, 45, 0]
person ashwinjv    schedule 23.04.2015

В SciPy используйте scipy.spatial.distance.squareform:

>>> scipy.spatial.distance.squareform([1,2,3,4,5,6])
array([[ 0.,  1.,  2.,  3.],
       [ 1.,  0.,  4.,  5.],
       [ 2.,  4.,  0.,  6.],
       [ 3.,  5.,  6.,  0.]])
person Yuval    schedule 05.04.2017

Итак, похоже, вы хотите использовать массив numpy.

import numpy as np
yourarray = np.zeros([10,10])

Это создает массив десять на десять, заполненный нулями.

Затем, чтобы заполнить его, вы хотите выйти в треугольник и заполнить каждый последующий объект следующим значением. Итак, в вашем базовом случае каждый объект просто является следующим целым числом,

count = 1
for ii in range(1,10):
    for jj in range(ii):
        yourarray[ii,jj] = yourarray[jj,ii] = count
        count +=1

Если вместо этого у вас есть список из 45 номеров, которые вы хотите вставить, вы можете заменить

yourarray[ii,jj] = yourarray[jj,ii] = count

с участием

yourarray[ii,jj] = yourarray[jj,ii] = vallist[count]

где vallist — это список ваших 45 объектов. В этом случае замените count = 1 на count = 0 в начале кода (поскольку Python имеет индекс 0).

Подробности Чтобы избежать заполнения диагонали, для jj установлено значение range(ii). Поскольку диапазон (N) в python возвращает [0, 1, 2, ... N - 2, N -1], у вас никогда не может быть jj=ii. Кроме того, поскольку jj увеличивается только до ii, но не становится больше (как это произошло бы, если бы jj также было равно in range(1,10)), это будет иметь дело только с каждой стороной массива на правильной стороне диагонали.

person Tom    schedule 23.04.2015