我想创建一个python函数,在一个部分空的网格内进行线性插值,得到一个最接近边界的外推。
我们说我在pandas DataFrame中存储了以下数据:
In [1]: import numpy as np
In [2]: import pandas as pd
In [3]: x = [0,1,2,3,4]
In [4]: y = [0.5,1.5,2.5,3.5,4.5,5.5]
In [5]: z = np.array([[np.nan,np.nan,1.5,2.0,5.5,3.5],[np.nan,1.0,4.0,2.5,4.5,3.0],[2.0,0.5,6.0,1.5,3.5,np.nan],[np.nan,1.5,4.0,2.0,np.nan,np.nan],[np.nan,np.nan,2.0,np.nan,np.nan,np.nan]])
In [6]: df = pd.DataFrame(t,index=x,columns=y)
In [7]: df
Out[7]:
0.5 1.5 2.5 3.5 4.5 5.5
0 NaN NaN 1.5 2.0 5.5 3.5
1 NaN 1.0 4.0 2.5 4.5 3.0
2 2.0 0.5 6.0 1.5 3.5 NaN
3 NaN 1.5 4.0 2.0 NaN NaN
4 NaN NaN 2.0 NaN NaN NaN
我想得到函数myInterp
,它返回数据边界内的线性插值(即不是NaN值),并在边界外得到最接近的外推(即NaN或无值),例如:
In [1]: myInterp([1.5,2.5]) #linear interpolation
Out[1]: 5.0
In [2]: myInterp([1.5,4.0]) #bi-linear interpolation
Out[2]: 3.0
In [3]: myInterp([0.0,2.0]) #nearest extrapolation (inside grid)
Out[3]: 1.5
In [4]: myInterp([5.0,2.5]) #nearest extrapolation (outside grid)
Out[4]: 2.0
我尝试了许多scipy.interpolate
包的组合但没有成功,有没有人有建议怎么做?
答案 0 :(得分:1)
是的,不幸的是,scipy并没有处理nans
来自文档:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="0dp"
tools:context=".MainActivity"
tools:ignore="MergeRootFrame">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:orientation="vertical">
<WebView
android:id="@+id/activity_main_webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/ad_view"
/>
<com.google.android.gms.ads.AdView
android:id="@+id/ad_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
ads:adSize="SMART_BANNER"
ads:adUnitId="ca-app-pub-3940256099942544/6300978111"
/>
</RelativeLayout>
</RelativeLayout>
即使在Note that calling interp2d with NaNs present in input values results in undefined behaviour.
中屏蔽nans也没有成功。
所以我的建议是从np.masked_array
删除所有的nan条目,借此机会只为有效数据提供z
x和y坐标的完整列表,并留下z 1D:
sp.interp2d
这样至少sp.interp2d可以工作并给出结果:
X=[];Y=[];Z=[] # initialize new 1-D-lists for interp2
for i, xi in enumerate(x): # iterate through x
for k, yk in enumerate(y): # iterate through y
if not np.isnan(z[i, k]): # check if z-value is valid...
X.append(xi) # ...and if so, append coordinates and value to prepared lists
Y.append(yk)
Z.append(z[i, k])
但是,结果中的值不会让您满意:
ip = sp.interpolate.interp2d(X,Y,Z)
与输入数据进行比较:
In: ip(x,y)
Out:
array([[ 18.03583061, -0.44933642, 0.83333333, -1. , -1.46105542],
[ 9.76791531, 1.3014037 , 2.83333333, 1.5 , 0.26947229],
[ 1.5 , 3.05214381, 4.83333333, 4. , 2. ],
[ 2. , 3.78378051, 1.5 , 2. , 0.8364618 ],
[ 5.5 , 3.57039277, 3.5 , -0.83019815, -0.7967441 ],
[ 3.5 , 3.29227922, 17.29607177, 0. , 0. ]])
但恕我直言,这是因为你的数据中的梯度变化太高了。关于数据样本数量较少的情况更多。
我希望这只是一个测试数据集,您的实际应用程序具有更平滑的渐变和更多样本。然后,我很高兴听到它是否有效......
然而,使用零梯度数组进行的微不足道的测试 - 仅由nans稍微破坏 - 可以提示插值应该有效,而外推只是部分正确:
In:z
Out:
array([[ nan, nan, 1.5, 2. , 5.5, 3.5],
[ nan, 1. , 4. , 2.5, 4.5, 3. ],
[ 2. , 0.5, 6. , 1.5, 3.5, nan],
[ nan, 1.5, 4. , 2. , nan, nan],
[ nan, nan, 2. , nan, nan, nan]])
由琐碎的测试输入
产生In:ip(x,y)
Out:
array([[ 3. , 3. , 3. , 3. , 0. ],
[ 3. , 3. , 3. , 3. , 1.94701008],
[ 3. , 3. , 3. , 3. , 3. ],
[ 3. , 3. , 3. , 3. , 1.54973345],
[ 3. , 3. , 3. , 3. , 0.37706713],
[ 3. , 3. , 2.32108317, 0.75435203, 0. ]])
PS:靠近右侧:甚至有效的条目完全改变,即错误,这在以下分析中引入了错误。
但令人惊讶的是:立方版在这里表现得更好:
In:z
Out:
array([[ nan, nan, 3., 3., 3., 3.],
[ nan, 3., 3., nan, 3., 3.],
[ 3., 3., 3., 3., 3., nan],
[ nan, 3., 3., 3., nan, nan],
[ nan, nan, 3., nan, nan, nan]])
答案 1 :(得分:0)
由于scipy.interp2d不处理Nans,因此解决方案是在使用interp2d之前在DataFrame中填充NaN。这可以通过使用pandas.interpolate函数来完成。
在前面的示例中,以下内容提供了所需的输出:
In [1]: from scipy.interpolate import interp2d
In [2]: df = df.interpolate(limit_direction='both',axis=1,inplace=True)
In [3]: myInterp = interp2d(df.index,df.columns,df.values.T)
In [4]: myInterp(1.5,2.5)
Out[4]: array([5.])
In [5]: myInterp(1.5,4.0)
Out[5]: array([3.])
In [6]: myInterp(0.0,2.0)
Out[6]: array([1.5])
In [7]: myInterp(5.0,2.5)
Out[7]: array([2.])