2012-10-31 10 views
7

Mam jednowymiarową tablicę A, która jest w większości dobra, ale brakuje kilku wartości. Brakujące dane zastępuje się nan (nie liczbą). Muszę zastąpić brakujące wartości w tablicy za pomocą interpolacji liniowej z pobliskich dobrych wartości. Tak więc, na przykład:Interpolacja liniowa za pomocą numpy.interp

F7(np.array([10.,20.,nan,40.,50.,nan,30.])) 

powinien powrócić

np.array([10.,20.,30.,40.,50.,40.,30.]). 

Jaki jest najlepszy sposób na to zrobić za pomocą Python?

Każda pomoc będzie mile widziane

Dzięki

+3

Czy naprawdę znaczy interpolacji liniowej? Czy rzeczywiście masz na myśli średnią? - Zakładam też, że pierwsza i ostatnia wartość są gwarantowane, że nie są NaN? – mgilson

+0

To była tylko średnia na przykładzie. Interpolacja liniowa powinna po prostu znaleźć brakujące wartości w równaniu liniowym. I tak, pierwsza i ostatnia wartość to nie NaN. –

Odpowiedz

11

Można użyć scipy.interpolate.interp1d:

>>> from scipy.interpolate import interp1d 
>>> import numpy as np 
>>> x = np.array([10., 20., np.nan, 40., 50., np.nan, 30.]) 
>>> not_nan = np.logical_not(np.isnan(x)) 
>>> indices = np.arange(len(x)) 
>>> interp = interp1d(indices[not_nan], x[not_nan]) 
>>> interp(indices) 
array([ 10., 20., 30., 40., 50., 40., 30.]) 

EDIT: zajęło mi trochę czasu, aby dowiedzieć się, jak np.interp działa, ale że może wykonaj także zadanie:

>>> np.interp(indices, indices[not_nan], x[not_nan]) 
array([ 10., 20., 30., 40., 50., 40., 30.]) 
+1

Myślę, że użyłbym 'len (x)' zamiast '* x.shape'. Wydaje się nieco bardziej jednoznaczne, ponieważ i tak robimy tylko 1D (i to nie generalizuje więcej wymiarów) - ale +1 dla działającego rozwiązania interpolacyjnego. – mgilson

+0

Zamiast generować dwukrotnie 'np.arange (len (x))', dlaczego nie zrobić tego tylko raz i zapisać wynik? Ponadto, nie sądzę, że potrzebujesz 'scipy' do tego. 'np.interp' wydaje się, że zrobiłoby to samo w tym scenariuszu – mgilson

+0

@mgilson: miałeś rację trzy razy. Dzięki, zaktualizowałeś odpowiedź. –

6

Poszedłbym z pandas. Minimalistyczny podejście z oneliner:

from pandas import * 
a=np.array([10.,20.,nan,40.,50.,nan,30.]) 
Series(a).interpolate() 

Out[219]: 
0 10 
1 20 
2 30 
3 40 
4 50 
5 40 
6 30 

Lub jeśli chcesz zachować go jako tablica:

Series(a).interpolate().values 

Out[221]: 
array([ 10., 20., 30., 40., 50., 40., 30.]) 
+0

@larsmans - chciałem tylko zasugerować .values, które również zwraca tablicę :) – root

+0

Widziałem to, skasowałem mój komentarz. Panda wciąż znajduje się na liście "biblioteki do nauki" :) –