Рассчитать статистику одного массива numpy на основе значений во втором массиве numpy - PullRequest
0 голосов
/ 27 ноября 2018

Допустим, у меня есть двумерный массив NumPy

a = np.array([[1, 1, 2, 2],
              [1, 1, 2, 2],
              [3, 3, 4, 4],
              [3, 3, 4, 4]]

и трехмерный массив Numpy, например

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

Я хочу вычислить статистику (mean,median, majority, sum, count, ...) из b в соответствии с «идентификаторами» в a.

Пример: sum должен привести к другому массиву (или списку, если так проще), который дает sum значений в ba есть 4 уникальных идентификатора: 1, 2, 3, 4 и 2 слоя в b.Для 1 в a это сумма 10 (слой 0) и 4 (слой 1).Для 2-х это 32 (слой 0) и 10 (слой 1), и так далее ...

Ожидаемый результат для sum:

sums = [[1, 10,  4],
        [2, 32, 10],
        [3, 26,  8],
        [4,  6, 15]]

Ожидаемый результат для mean:

avgs = [[1, 2.5, 1.0 ],
        [2, 8.0, 2.5 ],
        [3, 6.5, 2.0 ],
        [4, 1.5, 3.75]]

Полагаю, в numpy есть удобная функция, которая уже делает это, но я не уверен, что именно искать.Любые указатели о том, как это сделать или что искать, очень ценятся.

Обновление:

Я придумал этот цикл for, который подходит для очень маленьких массивов.Тем не менее, мои массивы намного больше, чем 4 на 4, и требуется более быстрое имплементация.

result = []
ids = np.unique(a)
for id in ids:
    line = [id]
    for band in range(0, b.shape[0]):
        cell = b[band][np.where(a == id)]
        line.append(cell.mean())
        # line.append(cell.min())
        # line.append(cell.max())
        # line.append(cell.std())
        line.append(cell.sum())
        line.append(np.median(cell))
    result.append(line)

1 Ответ

0 голосов
/ 27 ноября 2018

Вы можете попробовать код ниже

cal_sums = [[b[j, :, :][np.argwhere(a==i)[:,0],np.argwhere(a==i)[:,1]].sum() 
             for i in np.unique(a)] for j in range(2)]
cal_mean = [[b[j, :, :][np.argwhere(a==i)[:,0],np.argwhere(a==i)[:,1]].mean() 
             for i in np.unique(a)] for j in range(2)]

sums  = np.zeros((np.unique(a).size, b.shape[0]+1))
means = np.zeros((np.unique(a).size, b.shape[0]+1))

sums[:, 0] , sums[:,1:] = np.unique(a), np.asarray(cal_sums).T
means[:, 0] , means[:,1:] = np.unique(a), np.asarray(cal_mean).T

print(sums)
[[ 1. 10.  4.]
 [ 2. 32. 10.]
 [ 3. 26.  8.]
 [ 4.  6. 15.]]

print(means)

[[1.   2.5  1.  ]
 [2.   8.   2.5 ]
 [3.   6.5  2.  ]
 [4.   1.5  3.75]]

Я тестировал его в довольно большом размере массива, и он быстрый

n = 1000
a = np.random.randint(1, 5, size=(n, n))
b = np.random.randint(1, 10, size=(2, n, n))

скорость:

377 ms ± 3.04 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
...