39

次のようなデータが与えられたとします。

x = [1, 2.5, 3.4, 5.8, 6]
y = [2, 4, 5.8, 4.3, 4]

Python を使用して、1and 2.52.5toなどの間を線形補間する関数を設計したいと考えています。3.4

この Python チュートリアルを調べてみましたが、まだ理解できません。

4

7 に答える 7

55
import scipy.interpolate
y_interp = scipy.interpolate.interp1d(x, y)
print y_interp(5.0)

scipy.interpolate.interp1dによって線形補間を行い、エラー状態を処理するようにカスタマイズできます。

于 2012-12-03T17:44:05.557 に答える
31

あなたの質問を理解しているので、いくつかの関数を書きたいと思っていますy = interpolate(x_values, y_values, x)。基本的な考え方は、次の手順に従います。yx

  1. x_valuesを含む区間を定義する値のインデックスを見つけますx。たとえば、x=3リストの例では、含まれる間隔は[x1,x2]=[2.5,3.4]、インデックスはi1=1i2=2
  2. この区間の傾きを(y_values[i2]-y_values[i1])/(x_values[i2]-x_values[i1])(つまりdy/dx) で計算します。
  3. での値xは、 での値にx1勾配を加えて からの距離を掛けたものになりましたx1

xさらに、 が の間隔の外にある場合に何が起こるかを決定する必要がありx_valuesます。これはエラーであるか、勾配が最初/最後の間隔と同じであると仮定して「逆方向」に補間できます。

これは役に立ちましたか、それとももっと具体的なアドバイスが必要でしたか?

于 2011-09-08T06:11:21.630 に答える
18

私はかなりエレガントな解決策(IMHO)を考え出したので、投稿せずにはいられません:

from bisect import bisect_left

class Interpolate(object):
    def __init__(self, x_list, y_list):
        if any(y - x <= 0 for x, y in zip(x_list, x_list[1:])):
            raise ValueError("x_list must be in strictly ascending order!")
        x_list = self.x_list = map(float, x_list)
        y_list = self.y_list = map(float, y_list)
        intervals = zip(x_list, x_list[1:], y_list, y_list[1:])
        self.slopes = [(y2 - y1)/(x2 - x1) for x1, x2, y1, y2 in intervals]

    def __getitem__(self, x):
        i = bisect_left(self.x_list, x) - 1
        return self.y_list[i] + self.slopes[i] * (x - self.x_list[i])

、 、、およびがすべてある間隔の整数である場合に、float整数除算 (python <= 2.7) が作動して台無しにならないように、にマップします。x1x2y1y2

でself.x_list__getitem__が昇順でソートされているという事実を利用して、 inbisect_leftよりも小さい最大の要素のインデックスを (非常に) すばやく見つけます。xself.x_list

次のようにクラスを使用します。

i = Interpolate([1, 2.5, 3.4, 5.8, 6], [2, 4, 5.8, 4.3, 4])
# Get the interpolated value at x = 4:
y = i[4]

簡単にするために、ここでは境界条件をまったく扱いませんでした。そのままでは、i[x]forx < 1は (2.5, 4) から (1, 2) への直線が負の無限大に拡張されたかのように機能しますが、i[x]for x == 1orx > 6IndexError. すべての場合に IndexError を送出する方がよいでしょうが、これは読者の課題として残されています。:)

于 2011-09-08T09:10:56.573 に答える
7
def interpolate(x1: float, x2: float, y1: float, y2: float, x: float):
    """Perform linear interpolation for x between (x1,y1) and (x2,y2) """

    return ((y2 - y1) * x + x2 * y1 - x1 * y2) / (x2 - x1)
于 2020-06-10T23:35:47.877 に答える
4

両端を外挿する代わりに、 の範囲を返すことができますy_list。ほとんどの場合、アプリケーションは正常に動作しており、Interpolate[x]x_list. 端から外挿することの (おそらく) 線形効果により、データが正常に動作していると誤解される可能性があります。

  • 非線形の結果 ( と の内容によって制限される) を返すx_listy_list、プログラムの動作によって、 の外側にある値の問題が警告される場合がありますx_list。(非線形入力が与えられると、線形動作はバナナになります!)

  • の範囲外をy_list返すことは、出力値の範囲を知っていることも意味します。大幅に下回る、または大幅に上回るに基づいて外挿すると、返される結果が期待値の範囲外になる可能性があります。Interpolate[x]x_listxx_list[0]xx_list[-1]

    def __getitem__(self, x):
        if x <= self.x_list[0]:
            return self.y_list[0]
        elif x >= self.x_list[-1]:
            return self.y_list[-1]
        else:
            i = bisect_left(self.x_list, x) - 1
            return self.y_list[i] + self.slopes[i] * (x - self.x_list[i])
    
于 2014-04-24T13:16:57.463 に答える
0

あなたのソリューションは Python 2.7 では機能しませんでした。x 要素の順序を確認中にエラーが発生しました。これを機能させるには、コードを次のように変更する必要がありました。

from bisect import bisect_left
class Interpolate(object):
    def __init__(self, x_list, y_list):
        if any([y - x <= 0 for x, y in zip(x_list, x_list[1:])]):
            raise ValueError("x_list must be in strictly ascending order!")
        x_list = self.x_list = map(float, x_list)
        y_list = self.y_list = map(float, y_list)
        intervals = zip(x_list, x_list[1:], y_list, y_list[1:])
        self.slopes = [(y2 - y1)/(x2 - x1) for x1, x2, y1, y2 in intervals]
    def __getitem__(self, x):
        i = bisect_left(self.x_list, x) - 1
        return self.y_list[i] + self.slopes[i] * (x - self.x_list[i])
于 2013-06-14T18:57:52.020 に答える