الاستقراء بطريقة "الأقرب" في بايثون
-
20-12-2019 - |
سؤال
إنني أتطلع إلى العثور على ما يعادل Python لبيان Matlab التالي:
vq interp1(x,y, xq,'nearest','extrap')
يبدو وكأنه interp(xq, x, y)
يعمل بشكل مثالي من أجل الاستيفاء/الاستقراء الخطي.
نظرت أيضا إلى
F = scipy.interpolate.interp1d(x, y, kind='nearest')
والذي يعمل بشكل مثالي مع الطريقة الأقرب، لكنه لن يؤدي إلى إجراء استقراء.
هل هناك أي شيء آخر أغفلته؟شكرًا.
المحلول
بالنسبة للاستكمال الخطي الذي سيتم استقراءه باستخدام أقرب استيفاء، استخدم numpy.interp
.يفعل هذا بشكل افتراضي.
على سبيل المثال:
yi = np.interp(xi, x, y)
بخلاف ذلك، إذا كنت تريد أقرب استيفاء في كل مكان، كما تصف، فيمكنك القيام بذلك بطريقة قصيرة، ولكن غير فعالة:(يمكنك جعل هذا سطرًا واحدًا، إذا أردت)
def nearest_interp(xi, x, y):
idx = np.abs(x - xi[:,None])
return y[idx.argmin(axis=1)]
أو بطريقة أكثر كفاءة باستخدام searchsorted
:
def fast_nearest_interp(xi, x, y):
"""Assumes that x is monotonically increasing!!."""
# Shift x points to centers
spacing = np.diff(x) / 2
x = x + np.hstack([spacing, spacing[-1]])
# Append the last point in y twice for ease of use
y = np.hstack([y, y[-1]])
return y[np.searchsorted(x, xi)]
لتوضيح الفرق بين numpy.interp
وأقرب أمثلة الاستيفاء أعلاه:
import numpy as np
import matplotlib.pyplot as plt
def main():
x = np.array([0.1, 0.3, 1.9])
y = np.array([4, -9, 1])
xi = np.linspace(-1, 3, 200)
fig, axes = plt.subplots(nrows=2, sharex=True, sharey=True)
for ax in axes:
ax.margins(0.05)
ax.plot(x, y, 'ro')
axes[0].plot(xi, np.interp(xi, x, y), color='blue')
axes[1].plot(xi, nearest_interp(xi, x, y), color='green')
kwargs = dict(x=0.95, y=0.9, ha='right', va='top')
axes[0].set_title("Numpy's $interp$ function", **kwargs)
axes[1].set_title('Nearest Interpolation', **kwargs)
plt.show()
def nearest_interp(xi, x, y):
idx = np.abs(x - xi[:,None])
return y[idx.argmin(axis=1)]
main()
نصائح أخرى
في الإصدارات الأحدث من SciPy (على الأقل الإصدار 0.19.1+)، scipy.interpolate.interp1d
لديه الخيار fill_value = “extrapolate”
.
على سبيل المثال:
import pandas as pd
>>> s = pd.Series([1, 2, 3])
Out[1]:
0 1
1 2
2 3
dtype: int64
>>> t = pd.concat([s, pd.Series(index=s.index + 0.1)]).sort_index()
Out[2]:
0.0 1.0
0.1 NaN
1.0 2.0
1.1 NaN
2.0 3.0
2.1 NaN
dtype: float64
>>> t.interpolate(method='nearest')
Out[3]:
0.0 1.0
0.1 1.0
1.0 2.0
1.1 2.0
2.0 3.0
2.1 NaN
dtype: float64
>>> t.interpolate(method='nearest', fill_value='extrapolate')
Out[4]:
0.0 1.0
0.1 1.0
1.0 2.0
1.1 2.0
2.0 3.0
2.1 3.0
dtype: float64