2016-10-07 7 views
2

Я пытаюсь вычислить скользящую среднюю в большом массиве numpy, который содержит NaN. В настоящее время я использую:Рассчитать скользящее среднее в массиве numpy с NaNs

import numpy as np 

def moving_average(a,n=5): 
     ret = np.cumsum(a,dtype=float) 
     ret[n:] = ret[n:]-ret[:-n] 
     return ret[-1:]/n 

При расчете с замаскированным массивом:

x = np.array([1.,3,np.nan,7,8,1,2,4,np.nan,np.nan,4,4,np.nan,1,3,6,3]) 
mx = np.ma.masked_array(x,np.isnan(x)) 
y = moving_average(mx).filled(np.nan) 

print y 

>>> array([3.8,3.8,3.6,nan,nan,nan,2,2.4,nan,nan,nan,2.8,2.6]) 

Результатом Ищу (ниже) в идеале должны иметь пренебрежимы малый только в том месте, где исходный массив, х, были Nans и усреднение должны быть сделаны по числу элементов, не NaN в группировке (я нужен способ, чтобы изменить размер п в функции.)

y = array([4.75,4.75,nan,4.4,3.75,2.33,3.33,4,nan,nan,3,3.5,nan,3.25,4,4.5,3]) 

я мог цикл по всему массиву и с heck index по индексу, но массив, который я использую, очень велик, и это займет много времени. Существует ли несколько способов сделать это?

+0

Итак, что '[4.75.4.75, nan, 4.4.3.75,2.33,3.33,4, nan, nan, 3,3.5, nan, 3.25]' ожидаемый выход? Если да, то почему существует «NaN» как третий элемент? – Divakar

+0

@Divakar Это ожидаемый результат. В исходном массиве (x) в качестве третьей записи есть «nan». – krakenwagon

+0

Итак, почему у нас есть NaN как вторая последняя запись в ожидаемом выходе? – Divakar

ответ

1

Я просто добавить в большие ответы, прежде чем, что вы можете все еще использовать cumsum для достижения этого:

import numpy as np 

def moving_average(a, n=5): 
    ret = np.cumsum(a.filled(0)) 
    ret[n:] = ret[n:] - ret[:-n] 
    counts = np.cumsum(~a.mask) 
    counts[n:] = counts[n:] - counts[:-n] 
    ret[~a.mask] /= counts[~a.mask] 
    ret[a.mask] = np.nan 

    return ret 

x = np.array([1.,3,np.nan,7,8,1,2,4,np.nan,np.nan,4,4,np.nan,1,3,6,3]) 
mx = np.ma.masked_array(x,np.isnan(x)) 
y = moving_average(mx) 
0

Вы можете создать временный массив и использовать np.nanmean() (новое в версии 1.8, если я не ошибаюсь):

import numpy as np 
temp = np.vstack([x[i:-(5-i)] for i in range(5)]) # stacks vertically the strided arrays 
means = np.nanmean(temp, axis=0) 

и поставить оригинальный нан на место с means[np.isnan(x[:-5])] = np.nan

Однако это выглядит избыточным как с точки зрения памяти (укладка одного массива 5 раз), так и вычисление.

+0

np.nanmean() не возвращает' nan' в любом месте в выходном массиве. – krakenwagon

+0

@krakenwagon, да, вы добавляете их обратно с строкой, которую я редактировал прямо перед вашим комментарием. –

0

Если я правильно понял, вы хотите создать скользящее среднее, а затем заполнить полученные элементы как nan, если их индекс в исходном массиве был nan.

import numpy as np 

>>> inc = 5 #the moving avg increment 

>>> x = np.array([1.,3,np.nan,7,8,1,2,4,np.nan,np.nan,4,4,np.nan,1,3,6,3]) 
>>> mov_avg = np.array([np.nanmean(x[idx:idx+inc]) for idx in range(len(x))]) 

# Determine indices in x that are nans 
>>> nan_idxs = np.where(np.isnan(x))[0] 

# Populate output array with nans 
>>> mov_avg[nan_idxs] = np.nan 
>>> mov_avg 
array([ 4.75, 4.75, nan, 4.4, 3.75, 2.33333333, 3.33333333, 4., nan, nan, 3., 3.5, nan, 3.25, 4., 4.5, 3.]) 
0

Вот подход, использующий шаги -

w = 5 # Window size 
n = x.strides[0]  
avgs = np.nanmean(np.lib.stride_tricks.as_strided(x, \ 
         shape=(x.size-w+1,w), strides=(n,n)),1) 

x_rem = np.append(x[-w+1:],np.full(w-1,np.nan)) 
avgs_rem = np.nanmean(np.lib.stride_tricks.as_strided(x_rem, \ 
           shape=(w-1,w), strides=(n,n)),1) 
avgs = np.append(avgs,avgs_rem)        
avgs[np.isnan(x)] = np.nan