2017-01-30 2 views
0

У меня есть массив й, который выглядит следующим образом:Numpy массив расстояний к списку (строка, столбец, расстояние)

[[ 0.   1.73205081 6.40312424 7.21110255 2.44948974] 
[ 1.73205081 0.   5.09901951 5.91607978 1.  ] 
[ 6.40312424 5.09901951 0.   1.   4.35889894] 
[ 7.21110255 5.91607978 1.   0.   5.09901951] 
[ 2.44948974 1.   4.35889894 5.09901951 0.  ]] 

Каждый элемент в этом массиве является расстоянием, и мне нужно, чтобы превратить это в список со строкой, столбец, расстояние следующим образом:

l = [(0,0,0),(0,1, 1.73205081),(0,2, 6.40312424),...,(1,0, 1.73205081),(1,1,0),...,(4,4,0)] 

Кроме того, было бы круто, чтобы удалить диагональные элементы, а также элементы (J, I) как (I, J) уже есть. По существу, можно ли взять только верхнюю треугольную матрицу?

Возможно ли это сделать эффективно (без большого количества циклов)? Я создал этот массив с квадратом, но не смог найти никаких документов для этого.

+0

Ответ на все ваши вопросы утвердительный. Да, это все возможно. Начать работать. – DyZ

+0

lol Я получил его, но он медленный. У меня есть матрица размером 76800 x 3900. Было просто видно, была ли быстрая реализация, но я думаю, что у Джона было хорошее предложение попробовать это –

ответ

2

Если вход x, первый генерировать индексы:

i0,i1 = np.indices(x.shape) 

Тогда:

np.concatenate((i1,i0,x)).reshape(3,5,5).T 

Это дает первый результат - для всей матрицы.

Что касается принятия только верхнего треугольника, вы можете подумать о том, чтобы попробовать np.triu(), но я точно не знаю, какого результата вы ищете. Вероятно, вы можете выяснить, как замаскировать части, которые вам не нужны сейчас.

+0

. Следующее будет работать хорошо, если 'x' отличен от нуля над диагональю:' i0, i1 = np.triu (x, k = 1) .nonzero(); X = np.concatenate ((i0, i1, x [i0, i1])) .reshape (3, len (i0)). T 'но примечание' X' будет массивом типа 'float64', а индексы (например, 'X [0,0]', который равен 'float (i0 [0])'), необходимо будет преобразовать в 'int' позже для доступа к' x'. –

0

вы можете попробовать это,

print([(x,y, value) for (x,y), value in np.ndenumerate(numpymatrixarray)]) 

output [(0, 0, 0.0), (0, 1, 1.7320508100000001), (0, 2, 6.4031242400000004), (0, 3, 7.2111025499999997), (0, 4, 2.4494897400000002), (1, 0, 1.7320508100000001), (1, 1, 0.0), (1, 2, 5.0990195099999998), (1, 3, 5.9160797799999996), (1, 4, 1.0), (2, 0, 6.4031242400000004), (2, 1, 5.0990195099999998), (2, 2, 0.0), (2, 3, 1.0), (2, 4, 4.3588989400000004), (3, 0, 7.2111025499999997), (3, 1, 5.9160797799999996), (3, 2, 1.0), (3, 3, 0.0), (3, 4, 5.0990195099999998), (4, 0, 2.4494897400000002), (4, 1, 1.0), (4, 2, 4.3588989400000004), (4, 3, 5.0990195099999998), (4, 4, 0.0)] 
+1

Большие петли в NumPy не являются хорошей формой. –

4

squareform делает все это. Прочтите документы и поэкспериментируйте. Он работает в обоих направлениях. Если вы дадите ему матрицу, она вернет значения верхнего треугольника (сгущенная форма). Если вы дадите ему эти значения, он вернет матрицу.

In [668]: M 
Out[668]: 
array([[ 0. , 0.1, 0.5, 0.2], 
     [ 0.1, 0. , 2. , 0.3], 
     [ 0.5, 2. , 0. , 0.2], 
     [ 0.2, 0.3, 0.2, 0. ]]) 
In [669]: spatial.distance.squareform(M) 
Out[669]: array([ 0.1, 0.5, 0.2, 2. , 0.3, 0.2]) 
In [670]: v=spatial.distance.squareform(M) 
In [671]: v 
Out[671]: array([ 0.1, 0.5, 0.2, 2. , 0.3, 0.2]) 
In [672]: spatial.distance.squareform(v) 
Out[672]: 
array([[ 0. , 0.1, 0.5, 0.2], 
     [ 0.1, 0. , 2. , 0.3], 
     [ 0.5, 2. , 0. , 0.2], 
     [ 0.2, 0.3, 0.2, 0. ]]) 

Вы также можете указать force и checks параметр, но без тех, кого он просто идет по форме.

Indicies может исходить от triu

In [677]: np.triu_indices(4,1) 
Out[677]: 
(array([0, 0, 0, 1, 1, 2], dtype=int32), 
array([1, 2, 3, 2, 3, 3], dtype=int32)) 

In [680]: np.vstack((np.triu_indices(4,1),v)).T 
Out[680]: 
array([[ 0. , 1. , 0.1], 
     [ 0. , 2. , 0.5], 
     [ 0. , 3. , 0.2], 
     [ 1. , 2. , 2. ], 
     [ 1. , 3. , 0.3], 
     [ 2. , 3. , 0.2]]) 

Просто, чтобы проверить, можно заполнить матрицу 4x4 с этими значениями

In [686]: A=np.vstack((np.triu_indices(4,1),v)).T 
In [687]: MM = np.zeros((4,4)) 
In [688]: MM[A[:,0].astype(int),A[:,1].astype(int)]=A[:,2] 
In [689]: MM 
Out[689]: 
array([[ 0. , 0.1, 0.5, 0.2], 
     [ 0. , 0. , 2. , 0.3], 
     [ 0. , 0. , 0. , 0.2], 
     [ 0. , 0. , 0. , 0. ]]) 

Эти triu индексы также могут получать значения из M:

In [693]: I,J = np.triu_indices(4,1) 
In [694]: M[I,J] 
Out[694]: array([ 0.1, 0.5, 0.2, 2. , 0.3, 0.2]) 

squareform использует скомпилированный код в spatial.distance._distance_wrap, поэтому я ожидаю, что он будет довольно быстрым для больших массивов. Только проблема только возвращает значения сконденсированной формы, но не индексы. Но, учитывая форму, индексы всегда можно вычислить. Их не нужно хранить со значениями.

0

Действительно ли вы хотите, чтобы верхняя треугольная матрица для матрицы [nxm], где n>m? Это даст вам (nxn-n)/2 элементов и потерять все данные, где m⊖n.

То, что вы, вероятно, хотите, является нижней треугольной матрицей:

def tri_reduce(m): 
    n=m.shape 
    if n[0]>n[1]: 
     i=np.tril_indices(n[0],1,n[1]) 
    else: 
     i=np.triu_indices(n[0],1,n[1]) 
    return np.vstack((i,m[i])).T 

Перестройка его в список кортежей требует петлю, хотя я считаю. list(tri_reduce(m)) предоставит список n-го массива.