Как суммировать/усреднить определенное подмножество столбцов или строк и вернуть новый ndarray в numpy?

Для иллюстрации изображения у меня есть следующий ndarray:

x = [[0.5,  0.3,  0.1,  0.1],
     [0.4,  0.1,  0.3,  0.2],
     [0.4,  0.3,  0.2,  0.1],
     [0.6,  0.1,  0.1,  0.2]]

Я хочу суммировать два вектора в столбцах 1 и 2 (начиная отсчет с 0), чтобы новый ndarray был:

y = [[0.5,  0.4,  0.1],
     [0.4,  0.4,  0.2],
     [0.4,  0.5,  0.1],
     [0.6,  0.2,  0.2]]

И затем я хочу усреднить векторы в строках 1 и 2, чтобы окончательный результат был:

z = [[0.5,  0.4,   0.1 ],
     [0.4,  0.45,  0.15],
     [0.6,  0.2,   0.2 ]]

Есть ли эффективный способ сделать это в numpy одной командой? Мне действительно нужна эффективность, так как эта операция будет применяться во вложенном цикле.

заранее спасибо


person YACINE GACI    schedule 22.01.2020    source источник
comment
I really need efficiency as this operation is going to be applied in a nested loop, хорошо, если вы не используете вложенный цикл   -  person yatu    schedule 22.01.2020
comment
@yatu, я имею в виду, что буду использовать это матричное преобразование внутри вложенного цикла, а не реализовывать его с помощью вложенного цикла. Вот почему я искал эффективные реализации.   -  person YACINE GACI    schedule 23.01.2020


Ответы (3)


Решение @hpaulj очень хорошее, обязательно прочитайте его

Вы можете легко sum столбцы:

a_summed = np.sum(a[:,1:3], axis=1)

Вы также можете взять среднее значение нескольких строк:

a_mean = np.mean(a[1:3], axis=0)

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

import numpy as np

a_summed = np.sum(a[:,1:3], axis=1)
a[:, 1] = a_summed
a = np.delete(a, 2, 1)
a_mean = np.mean(a[1:3], axis=0)
a[1] = a_mean
a = np.delete(a, 2, 0)
print(a)
person Nathan    schedule 22.01.2020

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

import numpy as np

x = np.array(([0.5,  0.3,  0.1,  0.1, 1],
                [0.4,  0.1,  0.3,  0.2, 1],
                [0.4,  0.3,  0.2,  0.1, 1],
                [0.6,  0.1,  0.1,  0.2, 1]))

def sum_columns(matrix, col_start, col_end):
    return np.column_stack((matrix[:, 0:col_start],
                            np.sum(matrix[:, col_start:col_end + 1], axis=1),
                            matrix[:, col_end + 1:]))

def avgRows_summedColumns(matrix, row_start, row_end):
    return np.row_stack((matrix[0:row_start, :],
                        np.mean(matrix[row_start:row_end + 1, :], axis=0),
                        matrix[row_end:-1, :]))

# call the entire operation in one command
print(avgRows_summedColumns(sum_columns(x, 1, 2), 1, 2))

Таким образом, не имеет значения, насколько велика ваша матрица.

person jodobear    schedule 22.01.2020
comment
Мне нравится это решение. Довольно элегантно! - person YACINE GACI; 23.01.2020

In [68]: x = [[0.5,  0.3,  0.1,  0.1], 
    ...:      [0.4,  0.1,  0.3,  0.2], 
    ...:      [0.4,  0.3,  0.2,  0.1], 
    ...:      [0.6,  0.1,  0.1,  0.2]]                                                           
In [69]: x=np.array(x)

ufunc, как и np.add, имеют метод reduceat, который позволяет нам выполнять действие над группами строк или столбцов. При этом первое сокращение легко (но нужно немного поиграть, чтобы понять параметры):

In [70]: np.add.reduceat(x,[0,1,3], axis=1)                                                      
Out[70]: 
array([[0.5, 0.4, 0.1],
       [0.4, 0.4, 0.2],
       [0.4, 0.5, 0.1],
       [0.6, 0.2, 0.2]])

По-видимому, mean не является ufunc, поэтому мне пришлось довольствоваться add, чтобы уменьшить количество строк:

In [71]: np.add.reduceat(Out[70],[0,1,3],axis=0)                                                 
Out[71]: 
array([[0.5, 0.4, 0.1],
       [0.8, 0.9, 0.3],
       [0.6, 0.2, 0.2]])

а затем разделите на количество строк, чтобы получить среднее значение. Я мог бы обобщить это, чтобы использовать тот же [0,1,3], что и в reduceat, но пока просто используйте массив столбцов:

In [72]: np.add.reduceat(Out[70],[0,1,3],axis=0)/np.array([1,2,1])[:,None]                       
Out[72]: 
array([[0.5 , 0.4 , 0.1 ],
       [0.4 , 0.45, 0.15],
       [0.6 , 0.2 , 0.2 ]])

и все дело в одном выражении:

In [73]: np.add.reduceat(np.add.reduceat(x,[0,1,3], axis=1),[0,1,3],axis=0)/ np.array([1,2,1])[:,None]                                                                                    
Out[73]: 
array([[0.5 , 0.4 , 0.1 ],
       [0.4 , 0.45, 0.15],
       [0.6 , 0.2 , 0.2 ]])
person hpaulj    schedule 22.01.2020
comment
Я не знал, что это также существует, гораздо лучшее решение - person Nathan; 23.01.2020