2011-09-08 33 views
13

私はプログラミングが新しく、線形補間関数を書こうと思っていました。線形補間 - Python

は、以下のように、私はデータを与えてい言う: X = [1、2.5、3.4、5.8、6] Y = [2、4、5.8、4.3、4]

I関数を設計しますPythonを使用して1と2.5,2.5〜3.4などの線形補間を行います。

私は http://docs.python.org/tutorial/に目を通してみましたが、それでも私の頭の中で頭を上げることはできません。

+0

これは...簡単ではありません。何を試しましたか? – zellio

+0

-1これはあまりにも一般的です。あなたはどのようにプログラムするか、またはPythonでアルゴリズムを行う方法を理解していないのですか? – steabert

+0

さて、私は新しい学習者であり、話すために自分自身を深いところに投げ込んでしまった。 アルゴリズムで 'for'または 'if'文を使用することを考えていました。だからxの数多くの範囲の間。 – Helpless

答えて

13

ご質問のとおり、y = interpolate(x_values, y_values, x)という機能を記述すると、yの値はxになりますか?基本的な考え方は、次の手順を実行します。

  1. xを含む間隔を定義x_values内の値のインデックスを検索します。たとえば、あなたの例のリストを持つx=3ために、含む区間は[x1,x2]=[2.5,3.4]だろう、とインデックスはi1=1i2=2
  2. (すなわちdy/dx(y_values[i2]-y_values[i1])/(x_values[i2]-x_values[i1])することにより、この区間の勾配を計算になります。
  3. xの値は、x1の値と、スロープにx1の距離を掛けた値になりました。

あなたはさらにxx_valuesの区間外にある、のいずれか、それは誤りだ、またはあなたが「後方」補間することができ、傾きが最後の/最初の間隔と同じであると仮定した場合に何が起こるかを決定する必要があります。

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

+0

いいえ、それは完璧です、ありがとうございます! – Helpless

+3

y_values [i2]をそれ自体から減算することは正しくできません。それは '(y_values [i2] -y_values [i1])'でしょうか? –

+3

@MartinBurch:数年後、しかし...ありがとう、修正! :) – carlpett

10

は私はむしろエレガント溶液(私見)をアップ考え、私はそれ転記抵抗することはできません。私はキックしないであろうように、整数除算float(パイソン< = 2.7)にマップ

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]) 

を何かを繰り返すと、x1,x2y1y2はすべて整数です。

私はself.x_listを迅速 self.x_listxよりも小さい最大の要素のインデックスを見つける(非常に)に bisect_leftを使用して昇順にソートされているという事実を利用してい __getitem__

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

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] 

私は簡単にするため、ここですべての境界条件を扱っていませんでした。そのままで、x < 1i[x]は、(2.5、4)から(1,2)までの直線がマイナスの無限大に伸びたように機能し、x == 1またはx > 6i[x]IndexErrorになります。すべてのケースでIndexErrorを上げる方が良いでしょうが、これは読者の練習として残されています。:)

+1

私は '__getitem__'の代わりに' __call__'を使うのが一般的です。通常は補間*関数*です。 – Dave

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

scipy.interpolate.interp1dエラー状態を処理するために線形補間を行い、カスタマイズすることができます。

1

解決策は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]) 
1

、あなたがy_listのエクステントを返すことができます:私はそれを動作させるためにこれにコードを変更する必要がありました。ほとんどの場合、アプリケーションは正常に動作し、Interpolate[x]x_listになります。端から外挿する(おそらく)線形の影響は、データが正常に動作していると誤認する可能性があります。

あなたのプログラムの動作が大幅に x_list外の値のために問題を警告する( x_listy_listの内容で囲まれた)非線形結果を返す
  • 。 (非線形入力を与えられたとき、リニア動作がバナナを行く!)

  • x_listInterpolate[x]外のためy_listのエクステントを返すも、あなたの出力値の範囲を知っていることを意味します。 xに基づいて推定すると、x_list[0]またはxよりもはるかに大きく、x_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]) 
    
+0

私は '__getitem__'の代わりに' __call__'を使うのが一般的です。通常は補間*関数*です。 – Dave