2011-01-07 2 views
15

Я пытаюсь группировать массив numpy на меньший размер, беря среднее значение из этих элементов. Например, для создания массива размера 20x20 требуется средний массив 5x5 foreach размером 100x100. Насколько мне нужно обрабатывать огромные данные, это эффективный способ сделать это?Группировка массива 2D numpy в среднем

+0

Аналогично [это] (https://stackoverflow.com/questions/18645013/windowed-maximum-in-numpy/18645174#18645174) ответить так же. – Daniel

ответ

23

Я попытался это для меньшего массива, поэтому проверить его с вашим:

import numpy as np 

nbig = 100 
nsmall = 20 
big = np.arange(nbig * nbig).reshape([nbig, nbig]) # 100x100 

small = big.reshape([nsmall, nbig//nsmall, nsmall, nbig//nsmall]).mean(3).mean(1) 

Пример с 6x6 -> 3x3:

nbig = 6 
nsmall = 3 
big = np.arange(36).reshape([6,6]) 
array([[ 0, 1, 2, 3, 4, 5], 
     [ 6, 7, 8, 9, 10, 11], 
     [12, 13, 14, 15, 16, 17], 
     [18, 19, 20, 21, 22, 23], 
     [24, 25, 26, 27, 28, 29], 
     [30, 31, 32, 33, 34, 35]]) 

small = big.reshape([nsmall, nbig//nsmall, nsmall, nbig//nsmall]).mean(3).mean(1) 

array([[ 3.5, 5.5, 7.5], 
     [ 15.5, 17.5, 19.5], 
     [ 27.5, 29.5, 31.5]]) 
4

Это довольно просто, хотя я чувствую, что это может быть быстрее:

from __future__ import division 
import numpy as np 
Norig = 100 
Ndown = 20 
step = Norig//Ndown 
assert step == Norig/Ndown # ensure Ndown is an integer factor of Norig 
x = np.arange(Norig*Norig).reshape((Norig,Norig)) #for testing 
y = np.empty((Ndown,Ndown)) # for testing 
for yr,xr in enumerate(np.arange(0,Norig,step)): 
    for yc,xc in enumerate(np.arange(0,Norig,step)): 
     y[yr,yc] = np.mean(x[xr:xr+step,xc:xc+step]) 

Вы также можете найти scipy.signal.decimate интересное. Он применяет более сложный фильтр нижних частот, чем простое усреднение, до понижающей дискретизации данных, хотя вам придется децитировать одну ось, а затем другую.

2

Среднее 2D-массив над подмассивами размера NxN:

height, width = data.shape 
data = average(split(average(split(data, width // N, axis=1), axis=-1), height // N, axis=1), axis=-1) 
+1

Хороший! Просто уточнение, что среднее и раскол - это бесчисленные функции. – MonkeyButter

0

Обратите внимание, что eumiro's approach не работает для замаскированных массивов в .mean(3).mean(1), как суммирует, что каждое среднее по оси 3 вычислялось из того же числа значений. Если в вашем массиве есть маскированные элементы, это предположение больше не выполняется. В этом случае вам необходимо отслеживать количество значений, используемых для вычисления .mean(3), и заменить .mean(1) на средневзвешенное значение. Веса - это нормированное число значений, используемых для вычисления .mean(3).

Вот пример:

import numpy as np 


def gridbox_mean_masked(data, Nbig, Nsmall): 
    # Reshape data 
    rshp = data.reshape([Nsmall, Nbig//Nsmall, Nsmall, Nbig//Nsmall]) 

    # Compute mean along axis 3 and remember the number of values each mean 
    # was computed from 
    mean3 = rshp.mean(3) 
    count3 = rshp.count(3) 

    # Compute weighted mean along axis 1 
    mean1 = (count3*mean3).sum(1)/count3.sum(1) 
    return mean1 


# Define test data 
big = np.ma.array([[1, 1, 2], 
        [1, 1, 1], 
        [1, 1, 1]]) 
big.mask = [[0, 0, 0], 
      [0, 0, 1], 
      [0, 0, 0]] 
Nbig = 3 
Nsmall = 1 

# Compute gridbox mean 
print gridbox_mean_masked(big, Nbig, Nsmall) 
Смежные вопросы