2015-07-18 5 views
10

У меня есть 1D NumPy массив следующим образом:Расчет местных средств в 1D Numpy массиве

import numpy as np 
d = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]) 

Я хочу, чтобы рассчитать средства (1,2,6,7), (3,4,8,9), и так далее. Это включает в себя среднее из 4 элементов: два последовательных элемента и два последовательных элемента 5 позиций после.

Я попытался следующие:

>> import scipy.ndimage.filters as filt 
>> res = filt.uniform_filter(d,size=4) 
>> print res 
[ 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19] 

К сожалению, это не дает мне желаемых результатов. Как мне это сделать?

+1

Как вы выбрали эти цифры 1,2,6,7? Каковы правила? –

+0

@omri_saadon два последовательных элемента и после 5 элементов другие два последовательных элемента. – Borys

+0

Я вижу, что здесь вы сделали интерполированные данные, возможно, данные изображения. Почему бы не перефразировать вопрос, чтобы было ясно, какая последовательность вам нужна для каждого из двух наборов? – gburton

ответ

11

Вместо индексации вы можете приблизиться к этому с точки зрения обработки сигналов. Вы в основном выполняете discrete convolution вашего входного сигнала с ядром с 7 кранами, где три коэффициента центра равны 0, а конечности равны 1, и поскольку вы хотите вычислить среднее значение, вам нужно умножить все значения на (1/4). Однако вы не вычисляете свертку всех элементов, но мы рассмотрим это позже. Один из способов заключается в использовании scipy.ndimage.filters.convolve1d для этого:

import numpy as np 
from scipy.ndimage import filters 
d = np.arange(1, 21, dtype=np.float) 
ker = (1.0/4.0)*np.array([1,1,0,0,0,1,1], dtype=np.float) 
out = filters.convolve1d(d, ker)[3:-3:2] 

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

Мы получаем это для out:

In [47]: out 
Out[47]: array([ 4., 6., 8., 10., 12., 14., 16.]) 

Чтобы перепроверить, чтобы увидеть, если у нас есть правильный результат, попробуйте некоторые вычисления выборки для каждого элемента. Первый элемент равен (1+2+6+7)/4 = 4. Второй элемент равен (3+4+8+9)/4 = 6 и т. Д.


Для решения с меньшим количеством головных болей, попробуйте numpy.convolve с mode=valid флагом. Это позволяет избежать вырезания из дополнительных накладок слева и справа, но вам все равно придется пропустить любой другой элемент, хотя:

import numpy as np 
d = np.arange(1, 21, dtype=np.float) 
ker = (1.0/4.0)*np.array([1,1,0,0,0,1,1], dtype=np.float) 
out = np.convolve(d, ker, mode='valid')[::2] 

Мы также получаем:

In [59]: out 
Out[59]: array([ 4., 6., 8., 10., 12., 14., 16.]) 

Наконец, если вы хотите индексации, что-то вроде этого может быть достаточно:

length = len(d[6::2]) 
out = np.array([(a+b+c+e)/4.0 for (a,b,c,e) in zip(d[::2][:length], d[1::2][:length], d[5::2][:length], d[6::2])]) 

Мы получаем:

In [69]: out 
Out[69]: array([ 4., 6., 8., 10., 12., 14., 16.]) 

Это действительно уродливое, но оно работает. Общая длина вашего сигнала определяется тем, что конец каждого окна находится в 7-м индексе. Длина этого массива, который содержит эти индексы, определяет конечную длину вашего сигнала. Также обратите внимание, что для элемента в окне его следующий элемент можно найти, пропуская все остальные элементы до конца массива. Всего 4 из этих последовательностей, и мы просто zip по этим 4 последовательностям, где каждая последовательность пропускает каждый другой элемент, но есть смещение, с которого мы начинаем.Первая последовательность начинается со смещения 0, следующего в 1, следующего в 5 и следующего в 6. Мы собираем эти четыре элемента и усредняем их, а затем пропускаем все в массиве до тех пор, пока не закончим.

BTW, мне все еще нравится свертка лучше.

+0

Комментарии не предназначены для расширенного обсуждения; этот разговор был [перемещен в чат] (http://chat.stackoverflow.com/rooms/83631/discussion-on-answer-by-rayryeng-array-indexing-for-calculating-mean). –

1

Вы можете использовать numpy.lib.stride_tricks.as_strided(), чтобы получить массив группирования применимый для более общего случая:

import numpy as np 
from numpy.lib.stride_tricks import as_strided 

d = np.arange(1, 21) 

consec = 2 
offset = 5 
nsub = 2 
pace = 2 

s = d.strides[0] 
ngroups= (d.shape[0] - (consec + (nsub-1)*offset - 1))//pace 
a = as_strided(d, shape=(ngroups, nsub, consec), 
       strides=(pace*s, offset*s, 1*s)) 

Где:

  • consec является количество последовательных чисел в подгруппе
  • offset смещение между первой записью в каждой подгруппе
  • nsub номер из подгрупп (1, 2 одна подгруппа, отделена от второй подгруппы 6, 7 по offset
  • pace указывает шаг между первой записью двух групп, которые в вашем случае является pace=consec, но может быть различным в более общий случай

в вашем случае (с использованием заданных значений) a будет:

array([[[ 1, 2], 
     [ 6, 7]], 

     [[ 3, 4], 
     [ 8, 9]], 

     [[ 5, 6], 
     [10, 11]], 

     [[ 7, 8], 
     [12, 13]], 

     [[ 9, 10], 
     [14, 15]], 

     [[11, 12], 
     [16, 17]], 

     [[13, 14], 
     [18, 19]]]) 

от того, где он вполне готов получить желаемое среднее, выполнив:

a.mean(axis=-1).mean(axis=-1) 

#array([ 4., 6., 8., 10., 12., 14., 16.]) 
+1

очень классный трюк ... заставляю меня luv numpy больше каждый день, когда я вышел из MATLAB. Я передаю свертку, но приятно видеть ... – wbg