Как суммировать / усреднить указанное c подмножество столбцов или строк и вернуть новый ndarray в numpy? - PullRequest
0 голосов
/ 22 января 2020

Для иллюстрации, изображений у меня есть следующий 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 в одной команде? Мне действительно нужна эффективность, так как эта операция будет применяться во вложенном l oop.

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

Ответы [ 3 ]

2 голосов
/ 22 января 2020

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

Вы можете 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)
1 голос
/ 22 января 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 ]])
1 голос
/ 22 января 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))

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

...