xarray逆補間(データではなく座標上)


8

次のDataArrayがあります

arr = xr.DataArray([[0.33, 0.25],[0.55, 0.60],[0.85, 0.71],[0.92,0.85],[1.50,0.96],[2.5,1.1]],[('x',[0.25,0.5,0.75,1.0,1.25,1.5]),('y',[1,2])])

これにより、次の出力が得られます

<xarray.DataArray (x: 6, y: 2)>
array([[0.33, 0.25],
       [0.55, 0.6 ],
       [0.85, 0.71],
       [0.92, 0.85],
       [1.5 , 0.96],
       [2.5 , 1.1 ]])
Coordinates:
  * x        (x) float64 0.25 0.5 0.75 1.0 1.25 1.5
  * y        (y) int32 1 2

または、便宜上、xと出力(z)を並べて下に並べ替えます。

x         z (y=1)   z(y=2)
0.25      0.33      0.25
0.50      0.55      0.60
0.75      0.85      0.71
1.00      0.92      0.85
1.25      1.50      0.96
1.50      2.50      1.10

私が持っているデータは、いくつかの入力値の結果です。それらの1つはx値です。他の入力値には、他にもいくつかの次元(yなど)があります。出力値(z)が1.00より大きくなり、他のディメンションを固定してx値を変化させたときに知りたい。上記の2次元の例では、[1.03 1.32]という答えが得られます。xの値が1.03の場合、y = 1の場合、zの値は1.00になり、xの値が1.32の場合、y = 2の場合、zの値は1.00になります。

編集:出力zはxの増加に伴って大きくなるため、zが出力として1.0になる点は1つだけです。

xarrayでこれを実現する効率的な方法はありますか?実際のテーブルははるかに大きく、4つの入力(ディメンション)があります。

助けてくれてありがとう!

回答:


4

xarrayにはこのための非常に便利な関数があります。xr.interpこれは、xarrayの区分線形補間を行います。

あなたのケースでは、それを使用して(x、y1)と(x、y1)ポイントの区分的補間を取得できます。これが完了すると、あとは、補間されたx配列の終値に関連付けられている補間されたy1/y2/..配列の値をターゲット番号(例では1.00)に取得することだけです。

これは次のようになります。

y_dims = [0, 1,] 
target_value = 1.0
# create a 'high resolution` version of your data array:
arr_itp = arr.interp(x=np.linspace(arr.x.min(), arr.x.max(), 10000))
for y in y_dims:
    # get the index of closest data
    x_closest = np.abs(arr_itp.isel(y=y) - target_value).argmin()
    print(arr_itp.isel(y=y, x=x_closest))

>>> <xarray.DataArray ()>
>>> array(0.99993199)
>>> Coordinates:
>>>     y        int64 1
>>>     x        float64 1.034
>>> <xarray.DataArray ()>
>>> array(1.00003)
>>> Coordinates:
>>>     y        int64 2
>>>     x        float64 1.321


これは機能しますが、問題に対処するための本当に効率的な方法ではありません。ここに、2つの理由があります。

  1. xr.interpを使用すると、DataArray全体が区分的に補間されます。さらに、目標値に最も近い2つのポイント間の補間のみが必要です。
  2. ここで、補間は2点間の直線です。しかし、その線上の点の1つの座標(y = 1.00)がわかっている場合は、直線の線形方程式を解くことで他の座標を簡単に計算でき、問題はいくつかの算術演算で解決されます。

これらの理由を考慮して、問題に対するより効率的なソリューションを開発できます。

# solution of linear function between two points (2. reason)
def lin_itp(p1,p2,tv):
    """Get x coord of point on line

    Determine the x coord. of a point (x, target_value) on the line
    through the points p1, p2.

    Approach:
      - parametrize x, y between p1 and p2: 
          x = p1[0] + t*(p2[0]-p1[0])
          y = p1[1] + t*(p2[1]-p1[1])
      - set y = tv and resolve 2nd eqt for t
          t = (tv - p1[1]) / (p2[1] - p1[1])
      - replace t in 1st eqt with solution for t
          x = p1[0] + (tv - p1[1])*(p2[0] - p1[0])/(p2[1] - p1[1])
    """
    return float(p1[0] + (tv - p1[1])*(p2[0] - p1[0])/(p2[1] - p1[1])) 

# target value:
t_v = 1.0
for y in [0, 1]:
    arr_sd = arr.isel(y=y)
    # get index for the value closest to the target value (but smaller)
    s_udim = int(xr.where(arr_sd - t_v <=0, arr_sd, arr_sd.min()).argmax())
    # I'm explicitly defining the two points here
    ps_itp = arr_sd[s_udim:s_udim+2]
    p1, p2 = (ps_itp.x[0], ps_itp[0]), (ps_itp.x[1], ps_itp[1])
    print(lin_itp(p1,p2,t_v))

>>> 1.0344827586206897
>>> 1.3214285714285714


1
「arr_sd = arr.isel(y = 0)」は、「arr_sd = arr.isel(y = y)」という意味でエラーを起こしました
Hoogendijk

@Hoogendijkありがとうございます。それを見なかった。回答がお役に立てば幸いです。:)
jojo

はい、それは便利でしたが、私はそれを改善してforループの必要性を取り除くことができるかどうかを確認することにしました。
Hoogendijk

0

私がジョジョの答えで持っていた問題は、それを多くの次元に拡張し、xarray構造を維持することが難しいことです。したがって、私はこれをさらに調査することにしました。私はジョジョのコードからいくつかのアイデアを使って以下の答えを出しました。

私は2つの配列を作成します。1つは、探している値よりも値が小さいという条件で、もう1つは、値を大きくする必要があるという条件です。2番目のものをx方向にマイナス1だけシフトします。今度は、それらを通常の線形補間式で組み合わせます。2つの配列は、条件の「エッジ」で値が重複しているだけです。-1シフトしない場合、値は重複しません。最後の行では、x方向を合計します。他のすべての値はNaNなので、正しい値を抽出し、プロセスのDataArrayからx方向を削除します。

def interpolate_dimension_x(arr, target_value, step):
    M0 = arr.where(arr - target_value <= 0)
    M1 = arr.where(arr - target_value > 0).shift(x=-1)

    work_mat = M0.x + step * (target_value - M0) / (M1 - M0)

    return work_mat.sum(dim='x')
interpolate_dimension_x(arr, 1, 0.25)

>>> <xarray.DataArray (y: 2)>
array([1.034483, 1.321429])
Coordinates:
  * y        (y) int32 1 2

私のコードにはいくつかの欠点があります。コードは、M0とM1が条件を満たす値を見つけた場合にのみ機能します。それ以外の場合、その行のすべての値はに設定されNaNます。M0の問題を回避するために、目標値は常に0よりも大きいので、x値を0から開始することにしました。M1の問題を回避するために、十分な大きさのxの値を選択して、自分の値がそこにあることを確認します。当然、これらは理想的なソリューションではなく、コードを壊す可能性があります。xarrayとpythonについてもう少し経験があれば、書き直すかもしれません。要約すると、解決したい次の項目があります。

  • X範囲外の値を外挿する方法は?私は現在、私のx範囲が答えがその範囲内に収まるのに十分な大きさであることを確認しています。
  • 可変ステップサイズに対してコードを堅牢にする方法
  • ディメンションを動的に選択できるようにコードを作成する方法(現在は 'x'でのみ機能します)
  • あらゆる最適化を歓迎します。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.