Диагональная карта - PullRequest
       10

Диагональная карта

2 голосов
/ 29 октября 2019

Допустим, у меня есть следующий фрейм данных:

idx = ['H',"A","B","C","D"]
idxp = idx[1:] + [idx[0]]
idxm = [idx[-1]] + idx[:-1]
idx, idxp, idxm
j = np.arange(25).reshape(5,5)
J = pd.DataFrame(j, index=idx, columns=idx)
np.fill_diagonal(J.values, 0)
J

enter image description here

В качестве вывода я хотел бы получить массив такой, что:

  • мы имеем нули повсюду в нижней части матрицы внизу и на диагонали
  • имеют значения в верхней части матрицы, рассчитанные путем взятия чисел чуть выше диагонали матрицыJ, поэтому вектор v = [1, 7, 13, 19].
  • Используя v, вычислите первую строку как совокупную сумму v от начала до конца и получите [1, 8, 21, 40]
  • Используя v, вычислите во второй строке совокупную сумму v от второго индекса до конца и получите [7, 20, 39]
  • и т. Д., Пока не достигнете последнего индекса v

Другими словами, это даст нам следующую матрицу:

m_exp = np.array([[0,1,8,21,40],
             [0,0,7,20,39],
             [0,0,0,13,32],
             [0,0,0,0,19],
             [0,0,0,0,0],
             ])

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

travelup = np.array([np.pad(np.cumsum(J.values.diagonal(1)[n:]), (n+1,0), 'constant') for n in range(J.values.shape[0])])

Однако это включало список понимания, и на практике моя матрица намного больше иs-код вызывается тысячи раз.

Есть ли способ преобразовать процесс, используя отображение, чтобы сделать его быстрее, избегая циклов?

1 Ответ

2 голосов
/ 29 октября 2019

Перечислено несколько методов.

I. Базовый метод

a = J.values
p = np.r_[0,a.ravel()[1::a.shape[1]+1]] # or np.r_[0,np.diag(a,1)]
n = len(p)
out = np.triu(np.broadcast_to(p,(n,n)),1).cumsum(1)

p и n будет использоваться повторно в перечисленных ниже альтернативах.

A. Альтернатива # 1

Альтернативно с broadcasted-multiplication для получения окончательного результата -

out = (~np.tri(n, dtype=bool)*p).cumsum(1)

B. Альтернатива # 2

Альтернативно с outer-subtraction на cumsum -

c = p.cumsum()
out = np.triu(c-c[:,None])

C. Альтернатива # 3

В качестве альтернативы np.tri для замены np.triu -

out = (c-c[:,None])*~np.tri(n, dtype=bool)

c будет использоваться повторно в перечисленных ниже альтернативах.

II. С numexpr

Для больших массивов используйте многоядерные процессоры с numexpr. Следовательно, альтернативы будут -

import numexpr as ne

out = ne.evaluate('(c-c2D)*M',{'c2D':c[:,None],'M':~np.tri(n, dtype=bool)})

A. Альтернатива # 1

out = ne.evaluate('(c-c2D)*(~M)',{'c2D':c[:,None],'M':np.tri(n, dtype=bool)})

B. Альтернатива № 2

r = np.arange(n)
out = ne.evaluate('(c-c2D)*(r2D<r)',{'c2D':c[:,None],'r2D':r[:,None]})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...