Какой более эффективный способ вычислить максимум каждой строки в матрице, исключая ее собственный столбец? - PullRequest
7 голосов
/ 30 апреля 2020

Для данной двумерной матрицы np.array([[1,3,1],[2,0,5]]), если нужно вычислить максимум каждой строки в матрице, исключая ее собственный столбец, с ожидаемым примером возврата np.array([[3,1,3],[5,5,2]]), какой будет наиболее эффективный способ сделать это? В настоящее время я реализовал это с помощью al oop, чтобы исключить собственный индекс col:

n=x.shape[0]
row_max_mat=np.zeros((n,n))
rng=np.arange(n)
for i in rng:
  row_max_mat[:,i] = np.amax(s_a_array_sum[:,rng!=i],axis=1)

Есть ли более быстрый способ сделать это?

Ответы [ 4 ]

3 голосов
/ 30 апреля 2020

Аналогично вашей (исключая столбцы один за другим), но с индексированием:

mask = ~np.eye(cols, dtype=bool)
a[:,np.where(mask)[1]].reshape((a.shape[0], a.shape[1]-1, -1)).max(1)

Вывод:

array([[3, 1, 3],
       [5, 5, 2]])
2 голосов
/ 30 апреля 2020

Вы можете сделать это, используя np.accumulate. Вычислите накопленные максимумы в прямом и обратном направлениях вдоль горизонтальной оси, а затем объедините их со смещением, равным единице:

import numpy as np

m = np.array([[1,3,1],[2,0,5]])

fmax = np.maximum.accumulate(m,axis=1)
bmax = np.maximum.accumulate(m[:,::-1],axis=1)[:,::-1]

r = np.full(m.shape,np.min(m))
r[:,:-1] = np.maximum(r[:,:-1],bmax[:,1:])
r[:,1:]  = np.maximum(r[:,1:],fmax[:,:-1])

print(r)

# [[3 1 3]
#  [5 5 2]]

Это потребует 3-кратного размера матрицы для обработки (хотя вы можете уменьшить это до 2 раза, если вы хотите обновление на месте). Добавление 3-го и 4-го измерений может также работать с использованием маски, но для обработки потребуется столбцы ^ в 2 раза превышающие размер матрицы и, вероятно, будет медленнее.

При необходимости вы можете применять один и тот же метод столбцов или к обоим измерениям ( объединяя результаты по строкам и столбцам).

1 голос
/ 01 мая 2020

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

def max_exclude_own_col(m):
    out = np.full(m.shape, m.max(1, keepdims=True))
    sidx = np.argpartition(-m,2,axis=1)
    R = np.arange(len(sidx))
    s0,s1 = sidx[:,0], sidx[:,1]
    mask =  m[R,s0]>m[R,s1]  
    L1c,L2c = np.where(mask,s0,s1), np.where(mask,s1,s0)
    out[R,L1c] = m[R,L2c]
    return out

Сравнительный анализ

Другие рабочие решения для больших массивов -

# @Alain T.'s soln
def max_accum(m):
    fmax = np.maximum.accumulate(m,axis=1)
    bmax = np.maximum.accumulate(m[:,::-1],axis=1)[:,::-1]

    r = np.full(m.shape,np.min(m))
    r[:,:-1] = np.maximum(r[:,:-1],bmax[:,1:])
    r[:,1:]  = np.maximum(r[:,1:],fmax[:,:-1])
    return r

Использование benchit Пакет (несколько инструментов сравнения, упакованных вместе; отказ от ответственности: я его автор) для сравнения предлагаемых решений.

Итак, мы будем тестировать большие массивы различных форм для определения времени и ускорений -

In [54]: import benchit

In [55]: funcs = [max_exclude_own_col, max_accum]

In [170]: inputs = [np.random.randint(0,100,(100000,n)) for n in [10, 20, 50, 100, 200, 500]]

In [171]: T = benchit.timings(funcs, inputs, indexby='shape')                                                             

In [172]: T
Out[172]: 
Functions   max_exclude_own_col  max_accum
Shape                                     
100000x10              0.017721   0.014580
100000x20              0.028078   0.028124
100000x50              0.056355   0.089285
100000x100             0.103563   0.200085
100000x200             0.188760   0.407956
100000x500             0.439726   0.976510

# Speedups with max_exclude_own_col over max_accum
In [173]: T.speedups(ref_func_by_index=1)
Out[173]: 
Functions   max_exclude_own_col  Ref:max_accum
Shape                                         
100000x10              0.822783            1.0
100000x20              1.001660            1.0
100000x50              1.584334            1.0
100000x100             1.932017            1.0
100000x200             2.161241            1.0
100000x500             2.220725            1.0
1 голос
/ 30 апреля 2020
a = np.array([[1,3,1],[2,0,5]])

row_max = a.max(axis=1).reshape(-1,1)
b = (((a // row_max)+1)%2)
c = b*row_max
d = (a // row_max)*((a*b).max(axis=1).reshape(-1,1))

c+d # result
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...