2013-05-31 3 views
3

Я ищу эффективный способ (желательно векторная быстрая встроенная функция), чтобы сгладить массив numpy в диагональном порядке. Например:Есть ли способ сгладить массив numpy в диагональном порядке эффективно?

A=np.array([[1,2,3], 
      [4,5,6], 
      [7,8,9]]) 
b=flatten_diagonally(A) 

b должен быть [7,4,8,1,5,9,2,6,3].

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

Было бы еще лучше, если бы я мог указать, какое подмножество диагоналей я хотел бы сгладить, например. сплющивание только 1-й и 2-й диагоналей даст [1,5,9,2,6].

+2

Вы должны либо итерации или использовать фантазии индексации. Это непересекающийся кусочек, поэтому нет никакого способа сделать это с помощью «обычной» нарезки. С фантастическим индексированием вам нужно заранее подготовить массив индексов. Таким образом, это, вероятно, лучше всего решить путем итерации. 'numpy.fromiter' часто полезен здесь, если вы хотите избежать копирования в памяти. –

+1

Что было сказано, посмотрите на 'scipy.sparse.dia_matrix' и' scipy.sparse.spdiags'. Один из способов добиться того, что вы хотите, - временно преобразовать вещи в 'scipy.sparse.dia_matrix', но это не будет эффективно для памяти для плотной матрицы. –

+0

@JoeKington Спасибо, к сожалению, я так и думал. Я знаю, что это не смежно, но я надеялся, что может быть функция numpy, жестко закодированная на C, чтобы он мог получить доступ к этим элементам быстрее, чем просто индивидуальный доступ через Python, но я думаю, что такой вещи нет. – Bitwise

ответ

0

numpy.diag возвращает диагональ вдоль определенного индекса. Documentation

Так это должно дать вам желаемый результат: (Обратите внимание, что 0th диагонали нормальных диагоналей, так что если вы хотите subdiagonals, возможно, придется использовать отрицательные значения для диагоналей.)

import numpy as np 

def flatten_diagonally(npA, diagonals = None): 
    diagonals = diagonals or xrange(-npA.shape[0] + 1, npA.shape[1]) 
    return np.concatenate(map(lambda x: np.diag(npA, k = x), diagonals)) 

Обратите внимание: вместо np.diag вы можете использовать np.diagonal, я не совсем уверен, что работает лучше. Documentation

+0

Там мы идем. Я все закончил редактирование :) – James

+0

Спасибо, но я упомянул, что массив будет очень большим (например,10000x10000), поэтому это решение будет неэффективным, как из-за конкатенации, так и для цикла. – Bitwise

+0

Я не думаю, что вы сможете найти решение без цикла - по крайней мере, петли здесь выполняются библиотекой numpy, которая оптимизирована и даже может быть перенесена на c-код (я не уверен в этом один). – James

0

Следующая функция основана на indices сравнений, основанных на том, что каждая диагональ имеет индекс отношения, например, на главной диагонали i==j, и так далее ...

Это действует даже для не - запрограммированные 2D-массивы.

def flatten_diagonally(x, diags=None): 
    diags = np.array(diags) 
    if x.shape[1] > x.shape[0]: 
     diags += x.shape[1]-x.shape[0] 
    n = max(x.shape) 
    ndiags = 2*n-1 
    i,j = np.indices(x.shape) 
    d = np.array([]) 
    for ndi in range(ndiags): 
     if diags != None: 
      if not ndi in diags: 
       continue 
     d = np.concatenate((d,x[i==j+(n-1)-ndi])) 
    return d 

Примеры:

print flatten_diagonally(A) 
#[ 7. 4. 8. 1. 5. 9. 2. 6. 3.] 

print flatten_diagonally(A, diags=(1,2)) 
#[ 4. 8. 1. 5. 9.] 

Для не квадратных массивов:

A=np.array([[1,2,3], 
      [7,8,9]]) 
print flatten_diagonally(A, diags=(1,2)) 
#[ 1. 8. 2. 9.] 
Смежные вопросы