Interpolation von NaN-Zellen in 2D-Matrix

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
StanKitz
User
Beiträge: 3
Registriert: Dienstag 21. September 2010, 10:11

Suche einen geeignete numpy/Scipy Methode zum Interpolieren von nicht gesetzten Werten (np.NaN) in einem 2D-Numpy array. Scipy interp2D liefert leider NaN auf dem ganzen Ergebnisarray sobald ein einzelner Wert des Eingagsarrays auf NaN gesetzt wird. Stattdessen sollte die Funktion eigentlich den Wert "8" auf der nicht gesetzten Zelle interpolieren.
Hat jemand eine Idee ?
Gibt es evtl. andere Lösungen, z.B. über MatPlotLib oder image ?

Hier ist mein Code auf der Basis von interp2D :

Code: Alles auswählen

    import numpy as np
    from scipy import interpolate
    
    vX = np.linspace(-5, 5, 11)
    vY = vX
    vvX, vvY = np.meshgrid(vX, vY)
    vvZ = 10 + vvX + vvY # init all valid data

    vvZ[4, 4] = np.NaN # set single cell to not measured  -> causes NaN in interpolated matrix vvZnew !!!
    
    """
    vvZ
    array([[  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.],
           [  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.],
           [  2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.],
           [  3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.],
           [  4.,   5.,   6.,   7.,  NaN,   9.,  10.,  11.,  12.,  13.,  14.],
           [  5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.],
           [  6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.],
           [  7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.],
           [  8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.],
           [  9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.],
           [ 10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.,  20.]])    
    """
    
    #vvZmasked=np.ma.masked_invalid(vvZ) # masking does not help   
    myFunc = interpolate.interp2d(vX, vY, vvZ, kind='linear')

    vXnew = np.linspace(-5, 5, 11) # keep original grid
    #vXnew = np.linspace(-5, 5, 21) # expand original grid
    vYnew = vXnew
    
    # Returns the cross product
    vvZnew = np.round(myFunc(vXnew, vYnew)) # interpolated z array

    print vvZ
    print vvZnew
    
    """
    vvZnew
    [[ NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN]
     [ NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN]
     [ NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN]
     [ NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN]
     [ NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN]
     [ NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN]
     [ NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN]
     [ NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN]
     [ NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN]
     [ NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN]
     [ NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN]]    
    """
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Nach etwas Stöbern vermute ich, dass du masked Arrays benutzen müsstest.
Nachtrag: Es wäre toll, wenn die Doku zu scipy und numpy auch als HTML vorliegen würde, das durchsucht sich einfach besser!
StanKitz
User
Beiträge: 3
Registriert: Dienstag 21. September 2010, 10:11

Danke für den Hinweis, aber hatte ich auch schon ausprobiert. Habe inzwischen eine ähnliche Frage auf der Scipy-user mailing list gefunden, allerdings ohne konkrete Lösung - scheint also kein ganz einfaches Problem zu sein. :K
Bzgl. der Numpy/Scipy Doku: Ich verwende meist die Online-Hilfe auf der Scipy-Seite, dort findet man recht schnell was man sucht über Search-Felder oder inhaltliche und alphabetische Listen.
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

du könntest mit der 'numpy.nan_to_num(x)' Funktion das NaN durch 0 ersetzen.

Code: Alles auswählen

>>> x = np.array([np.inf, -np.inf, np.nan, -128, 128])
>>> np.nan_to_num(x)
array([  1.79769313e+308,  -1.79769313e+308,   0.00000000e+000,
        -1.28000000e+002,   1.28000000e+002])
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

Vielleicht hilft dir das folgende weiter:

Code: Alles auswählen

In [86]: A
Out[86]: 
array([[  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.],
       [  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.],
       [  2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.],
       [  3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.],
       [  4.,   5.,   6.,   7.,  NaN,   9.,  10.,  11.,  12.,  13.,  14.],
       [  5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.],
       [  6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.],
       [  7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.],
       [  8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.],
       [  9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.],
       [ 10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.,  20.]])

In [87]: n,m = A.shape

In [88]: x,y = mgrid[0:n,0:m]

In [89]: mask = ~isnan(A)

In [90]: interp = interpolate.interp2d(x[mask], y[mask], A[mask])
Warning:     No more knots can be added because the number of B-spline coefficients
    already exceeds the number of data points m. Probably causes: either
    s or m too small. (fp>s)
    kx,ky=1,1 nx,ny=15,12 m=120 fp=0.000000 s=0.000000

In [91]: xn,yn = arange(n), arange(m)

In [92]: interp(xn,yn).round()
Out[92]: 
array([[ -0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.],
       [  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.],
       [  2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.],
       [  3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.],
       [  4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.],
       [  5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.],
       [  6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.],
       [  7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.],
       [  8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.],
       [  9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.],
       [ 10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.,  20.]])
Grüße
Gerrit
StanKitz
User
Beiträge: 3
Registriert: Dienstag 21. September 2010, 10:11

Vielen Dank, die von gkuhl vorgeschlagene mask-Methode funktioniert wunderbar selbst für größere zusammenhängene NaN-Bereiche. Die Ergebnisse liegen näher an den ganzen Zahlen (im Beispiel) wenn man das kwarg kind='quintic' oder kind='cubic' setzt statt den Defaultwert kind='linear' zu benutzen.
Ich hatte es bislang nur mit numpy.maskedArrays versucht was nicht funktionierte.
Antworten