Tôi đang cố gắng chuyển đổi mã Python sang Julia sử dụng scipy.interpolate.interp1d
và tôi đang gặp khó khăn trong việc tìm cách tốt nhất để thực hiện việc này trong Julia. Hàm interp1d
thực hiện phép nội suy 1D dọc theo một chiều nhất định của mảng nhiều chiều
Tôi đã sử dụng Interpolations.jl
nhưng cách tiếp cận của tôi có vẻ không phải là tốt nhất [xem bên dưới]. Có một câu hỏi tương tự được hỏi ba năm trước, nhưng câu trả lời được chấp nhận không cung cấp câu trả lời đơn giản
Đây là một ví dụ đơn giản về những gì tôi đang tìm kiếm
# Test data
x = [0., 2., 5., 10., 11.]
y = repeat[x .^ 2, outer=[1, 3, 3]]
# We want to interpolate y [a 3D array] along the first dimension,
# so that the output is another 3D array
itp = interp1d[x, y; dims=1, k=1]
# Expected results
itp[2.0]
3×3 Matrix{Float64}:
4.0 4.0 4.0
4.0 4.0 4.0
4.0 4.0 4.0
itp[3]
3×3 Matrix{Float64}:
11.0 11.0 11.0
11.0 11.0 11.0
11.0 11.0 11.0
Dữ liệu của tôi đều ở dạng lưới không đều
Điều này có vẻ hiệu quả, nhưng tôi tự hỏi liệu đó có phải là cách tiếp cận tốt nhất không
itp = interpolate[[x, 1:3, 1:3], y, Gridded[Linear[]]]
itp[3, 1:3, 1:3]
3×3 Matrix{Float64}:
11.0 11.0 11.0
11.0 11.0 11.0
11.0 11.0 11.0
Và có vẻ như với Gridded
phép nội suy bậc cao nhất được hỗ trợ là tuyến tính
Bất kỳ ai khác có cách tiếp cận tốt hơn cho loại nội suy này?
Tương tự như lập chỉ mục, cũng chấp nhận dạng mảng, cho kết quả được nội suy dưới dạng mảng
# label lookup In [4]: da.sel[time=[2, 3]] Out[4]: array[[[ 0.974, 0.863, 0.675], [ 0.427, 0.141, -0.158]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 0.3 # interpolation In [5]: da.interp[time=[2.5, 3.5]] Out[5]: array[[[0.701, 0.502, 0.259], [ nan, nan, nan]]] Coordinates: * space [space] float64 0.1 0.2 0.3 * time [time] float64 2.5 3.5
Để nội suy dữ liệu bằng numpy. datetime64 tọa độ bạn có thể chuyển một chuỗi.
In [6]: da_dt64 = xr.DataArray[ ...: [1, 3], [["time", pd.date_range["1/1/2000", "1/3/2000", periods=2]]] ...: ] ...: In [7]: da_dt64.interp[time="2000-01-02"] Out[7]: array[2.] Coordinates: time datetime64[ns] 2000-01-02
Dữ liệu nội suy có thể được hợp nhất vào dữ liệu gốc bằng cách chỉ định khoảng thời gian cần thiết
In [8]: da_dt64.interp[time=pd.date_range["1/1/2000", "1/3/2000", periods=3]] Out[8]: array[[1., 2., 3.]] Coordinates: * time [time] datetime64[ns] 2000-01-01 2000-01-02 2000-01-03
Nội suy dữ liệu được lập chỉ mục bởi a cũng được cho phép. Xem ví dụ
Ghi chú
Hiện tại, phép nội suy của chúng tôi chỉ hoạt động đối với các lưới thông thường. Do đó, tương tự như , chỉ các tọa độ 1D dọc theo một chiều mới có thể được sử dụng làm tọa độ ban đầu được nội suy
Nội suy đa chiều
Like , chấp nhận nhiều tọa độ. Trong trường hợp này, nội suy nhiều chiều được thực hiện
# label lookup In [9]: da.sel[time=2, space=0.1] Out[9]: array[0.974] Coordinates: time int64 2 space float64 0.1 # interpolation In [10]: da.interp[time=2.5, space=0.15] Out[10]: array[0.601] Coordinates: time float64 2.5 space float64 0.15
Các tọa độ giống như mảng cũng được chấp nhận
# label lookup In [11]: da.sel[time=[2, 3], space=[0.1, 0.2]] Out[11]: array[[[0.974, 0.863], [0.427, 0.141]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 # interpolation In [12]: da.interp[time=[1.5, 2.5], space=[0.15, 0.25]] Out[12]: array[[[0.888, 0.867], [0.601, 0.381]]] Coordinates: * time [time] float64 1.5 2.5 * space [space] float64 0.15 0.25
phương pháp là một phím tắt hữu ích. Phương thức này nội suy một đối tượng xarray lên tọa độ của một đối tượng xarray khác. Ví dụ: nếu chúng tôi muốn tính toán sự khác biệt giữa hai s [
In [6]: da_dt64 = xr.DataArray[ ...: [1, 3], [["time", pd.date_range["1/1/2000", "1/3/2000", periods=2]]] ...: ] ...: In [7]: da_dt64.interp[time="2000-01-02"] Out[7]: array[2.] Coordinates: time datetime64[ns] 2000-01-029 và
In [8]: da_dt64.interp[time=pd.date_range["1/1/2000", "1/3/2000", periods=3]] Out[8]: array[[1., 2., 3.]] Coordinates: * time [time] datetime64[ns] 2000-01-01 2000-01-02 2000-01-030] ở trên các tọa độ hơi khác nhau,
In [13]: other = xr.DataArray[ ....: np.sin[0.4 * np.arange[9].reshape[3, 3]], ....: [["time", [0.9, 1.9, 2.9]], ["space", [0.15, 0.25, 0.35]]], ....: ] ....:
có thể là một ý kiến hay trước tiên khi nội suy
In [6]: da_dt64 = xr.DataArray[ ...: [1, 3], [["time", pd.date_range["1/1/2000", "1/3/2000", periods=2]]] ...: ] ...: In [7]: da_dt64.interp[time="2000-01-02"] Out[7]: array[2.] Coordinates: time datetime64[ns] 2000-01-029 để nó nằm trên cùng tọa độ của
In [8]: da_dt64.interp[time=pd.date_range["1/1/2000", "1/3/2000", periods=3]] Out[8]: array[[1., 2., 3.]] Coordinates: * time [time] datetime64[ns] 2000-01-01 2000-01-02 2000-01-030, sau đó trừ nó đi. có thể được sử dụng cho một trường hợp như vậy,
# interpolate da along other's coordinates In [14]: interpolated = da.interp_like[other] In [15]: interpolated Out[15]: array[[[0.787, 0.911, nan], [0.912, 0.789, nan], [0.348, 0.069, nan]]] Coordinates: * time [time] float64 0.9 1.9 2.9 * space [space] float64 0.15 0.25 0.35
Bây giờ có thể tính toán chênh lệch một cách an toàn
In [8]: da_dt64.interp[time=pd.date_range["1/1/2000", "1/3/2000", periods=3]] Out[8]: array[[1., 2., 3.]] Coordinates: * time [time] datetime64[ns] 2000-01-01 2000-01-02 2000-01-034
phương pháp nội suy
Chúng tôi sử dụng cho phép nội suy 1 chiều. Đối với nội suy nhiều chiều, trước tiên, một nỗ lực được thực hiện để phân tách phép nội suy thành một loạt các phép nội suy 1 chiều, trong trường hợp này được sử dụng. Nếu không thể thực hiện phân tách [e. g. với nội suy nâng cao], được sử dụng
Phương pháp nội suy có thể được chỉ định bởi đối số tùy chọn
In [8]: da_dt64.interp[time=pd.date_range["1/1/2000", "1/3/2000", periods=3]] Out[8]: array[[1., 2., 3.]] Coordinates: * time [time] datetime64[ns] 2000-01-01 2000-01-02 2000-01-038
In [16]: da = xr.DataArray[ ....: np.sin[np.linspace[0, 2 * np.pi, 10]], ....: dims="x", ....: coords={"x": np.linspace[0, 1, 10]}, ....: ] ....: In [17]: da.plot.line["o", label="original"] Out[17]: [] In [18]: da.interp[x=np.linspace[0, 1, 100]].plot.line[label="linear [default]"] Out[18]: [] In [19]: da.interp[x=np.linspace[0, 1, 100], method="cubic"].plot.line[label="cubic"] Out[19]: [] In [20]: plt.legend[] Out[20]:
Các đối số từ khóa bổ sung có thể được chuyển đến các chức năng của scipy
# fill 0 for the outside of the original coordinates. In [21]: da.interp[x=np.linspace[-0.5, 1.5, 10], kwargs={"fill_value": 0.0}] Out[21]: array[[ 0. , 0. , 0. , 0.814, 0.604, -0.604, -0.814, 0. , 0. , 0. ]] Coordinates: * x [x] float64 -0.5 -0.2778 -0.05556 0.1667 .. 0.8333 1.056 1.278 1.5 # 1-dimensional extrapolation In [22]: da.interp[x=np.linspace[-0.5, 1.5, 10], kwargs={"fill_value": "extrapolate"}] Out[22]: array[[-2.893, -1.607, -0.321, 0.814, 0.604, -0.604, -0.814, 0.321, 1.607, 2.893]] Coordinates: * x [x] float64 -0.5 -0.2778 -0.05556 0.1667 .. 0.8333 1.056 1.278 1.5 # multi-dimensional extrapolation In [23]: da = xr.DataArray[ ....: np.sin[0.3 * np.arange[12].reshape[4, 3]], ....: [["time", np.arange[4]], ["space", [0.1, 0.2, 0.3]]], ....: ] ....: In [24]: da.interp[ ....: time=4, space=np.linspace[-0.1, 0.5, 10], kwargs={"fill_value": "extrapolate"} ....: ] ....: Out[24]: array[[ 0.805, 0.497, 0.189, -0.119, -0.427, -0.718, -0.991, -1.264, -1.538, -1.811]] Coordinates: time int64 4 * space [space] float64 -0.1 -0.03333 0.03333 0.1 .. 0.3 0.3667 0.4333 0.5
Nội suy nâng cao
chấp nhận tương tự như , cho phép chúng tôi nội suy nâng cao hơn. Dựa trên kích thước của tọa độ mới được chuyển đến, kích thước của kết quả được xác định
Ví dụ: nếu bạn muốn nội suy một mảng hai chiều dọc theo một chiều cụ thể, như minh họa bên dưới, bạn có thể chuyển hai s 1 chiều với một chiều chung làm tọa độ mới
Ví dụ
# label lookup In [4]: da.sel[time=[2, 3]] Out[4]: array[[[ 0.974, 0.863, 0.675], [ 0.427, 0.141, -0.158]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 0.3 # interpolation In [5]: da.interp[time=[2.5, 3.5]] Out[5]: array[[[0.701, 0.502, 0.259], [ nan, nan, nan]]] Coordinates: * space [space] float64 0.1 0.2 0.3 * time [time] float64 2.5 3.50
trong đó các giá trị trên tọa độ ban đầu
# label lookup In [9]: da.sel[time=2, space=0.1] Out[9]: array[0.974] Coordinates: time int64 2 space float64 0.1 # interpolation In [10]: da.interp[time=2.5, space=0.15] Out[10]: array[0.601] Coordinates: time float64 2.5 space float64 0.154 thu được bằng phép nội suy 2 chiều và được ánh xạ dọc theo một chiều mới
# label lookup In [9]: da.sel[time=2, space=0.1] Out[9]: array[0.974] Coordinates: time int64 2 space float64 0.1 # interpolation In [10]: da.interp[time=2.5, space=0.15] Out[10]: array[0.601] Coordinates: time float64 2.5 space float64 0.155. Vì không có đối số từ khóa nào được chuyển đến quy trình nội suy nên không có phép ngoại suy nào được thực hiện dẫn đến giá trị
# label lookup In [9]: da.sel[time=2, space=0.1] Out[9]: array[0.974] Coordinates: time int64 2 space float64 0.1 # interpolation In [10]: da.interp[time=2.5, space=0.15] Out[10]: array[0.601] Coordinates: time float64 2.5 space float64 0.156
Nếu bạn muốn thêm tọa độ vào thứ nguyên mới
# label lookup In [9]: da.sel[time=2, space=0.1] Out[9]: array[0.974] Coordinates: time int64 2 space float64 0.1 # interpolation In [10]: da.interp[time=2.5, space=0.15] Out[10]: array[0.601] Coordinates: time float64 2.5 space float64 0.155, bạn có thể cung cấp s với tọa độ. Phép ngoại suy có thể đạt được bằng cách chuyển các đối số bổ sung cho hàm
# label lookup In [9]: da.sel[time=2, space=0.1] Out[9]: array[0.974] Coordinates: time int64 2 space float64 0.1 # interpolation In [10]: da.interp[time=2.5, space=0.15] Out[10]: array[0.601] Coordinates: time float64 2.5 space float64 0.159 của SciPy,
# label lookup In [4]: da.sel[time=[2, 3]] Out[4]: array[[[ 0.974, 0.863, 0.675], [ 0.427, 0.141, -0.158]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 0.3 # interpolation In [5]: da.interp[time=[2.5, 3.5]] Out[5]: array[[[0.701, 0.502, 0.259], [ nan, nan, nan]]] Coordinates: * space [space] float64 0.1 0.2 0.3 * time [time] float64 2.5 3.51
Để biết chi tiết về lập chỉ mục nâng cao, xem
Nội suy mảng với NaN
Chúng tôi làm việc với các mảng có NaN giống như cách mà scipy. nội suy. interp1d và scipy. nội suy. thực tập làm. Các phương thức
# label lookup In [11]: da.sel[time=[2, 3], space=[0.1, 0.2]] Out[11]: array[[[0.974, 0.863], [0.427, 0.141]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 # interpolation In [12]: da.interp[time=[1.5, 2.5], space=[0.15, 0.25]] Out[12]: array[[[0.888, 0.867], [0.601, 0.381]]] Coordinates: * time [time] float64 1.5 2.5 * space [space] float64 0.15 0.251 và
# label lookup In [11]: da.sel[time=[2, 3], space=[0.1, 0.2]] Out[11]: array[[[0.974, 0.863], [0.427, 0.141]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 # interpolation In [12]: da.interp[time=[1.5, 2.5], space=[0.15, 0.25]] Out[12]: array[[[0.888, 0.867], [0.601, 0.381]]] Coordinates: * time [time] float64 1.5 2.5 * space [space] float64 0.15 0.252 trả về các mảng bao gồm NaN, trong khi các phương thức khác như
# label lookup In [11]: da.sel[time=[2, 3], space=[0.1, 0.2]] Out[11]: array[[[0.974, 0.863], [0.427, 0.141]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 # interpolation In [12]: da.interp[time=[1.5, 2.5], space=[0.15, 0.25]] Out[12]: array[[[0.888, 0.867], [0.601, 0.381]]] Coordinates: * time [time] float64 1.5 2.5 * space [space] float64 0.15 0.253 hoặc
# label lookup In [11]: da.sel[time=[2, 3], space=[0.1, 0.2]] Out[11]: array[[[0.974, 0.863], [0.427, 0.141]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 # interpolation In [12]: da.interp[time=[1.5, 2.5], space=[0.15, 0.25]] Out[12]: array[[[0.888, 0.867], [0.601, 0.381]]] Coordinates: * time [time] float64 1.5 2.5 * space [space] float64 0.15 0.254 trả về tất cả các mảng NaN
# label lookup In [4]: da.sel[time=[2, 3]] Out[4]: array[[[ 0.974, 0.863, 0.675], [ 0.427, 0.141, -0.158]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 0.3 # interpolation In [5]: da.interp[time=[2.5, 3.5]] Out[5]: array[[[0.701, 0.502, 0.259], [ nan, nan, nan]]] Coordinates: * space [space] float64 0.1 0.2 0.3 * time [time] float64 2.5 3.52
Để tránh điều này, bạn có thể loại bỏ NaN bằng , sau đó thực hiện phép nội suy
# label lookup In [4]: da.sel[time=[2, 3]] Out[4]: array[[[ 0.974, 0.863, 0.675], [ 0.427, 0.141, -0.158]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 0.3 # interpolation In [5]: da.interp[time=[2.5, 3.5]] Out[5]: array[[[0.701, 0.502, 0.259], [ nan, nan, nan]]] Coordinates: * space [space] float64 0.1 0.2 0.3 * time [time] float64 2.5 3.53
Nếu NaN được phân phối ngẫu nhiên trong mảng đa chiều của bạn, việc loại bỏ tất cả các cột chứa nhiều NaN có thể làm mất một lượng thông tin đáng kể. Trong trường hợp như vậy, bạn có thể điền NaN bằng , tương tự như
# label lookup In [4]: da.sel[time=[2, 3]] Out[4]: array[[[ 0.974, 0.863, 0.675], [ 0.427, 0.141, -0.158]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 0.3 # interpolation In [5]: da.interp[time=[2.5, 3.5]] Out[5]: array[[[0.701, 0.502, 0.259], [ nan, nan, nan]]] Coordinates: * space [space] float64 0.1 0.2 0.3 * time [time] float64 2.5 3.54
Điều này lấp đầy NaN bằng cách nội suy dọc theo thứ nguyên đã chỉ định. Sau khi điền NaN, bạn có thể nội suy
# label lookup In [4]: da.sel[time=[2, 3]] Out[4]: array[[[ 0.974, 0.863, 0.675], [ 0.427, 0.141, -0.158]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 0.3 # interpolation In [5]: da.interp[time=[2.5, 3.5]] Out[5]: array[[[0.701, 0.502, 0.259], [ nan, nan, nan]]] Coordinates: * space [space] float64 0.1 0.2 0.3 * time [time] float64 2.5 3.55
Để biết chi tiết về , xem
Thí dụ
Hãy xem cách hoạt động trên dữ liệu thực
# label lookup In [4]: da.sel[time=[2, 3]] Out[4]: array[[[ 0.974, 0.863, 0.675], [ 0.427, 0.141, -0.158]]] Coordinates: * time [time] int64 2 3 * space [space] float64 0.1 0.2 0.3 # interpolation In [5]: da.interp[time=[2.5, 3.5]] Out[5]: array[[[0.701, 0.502, 0.259], [ nan, nan, nan]]] Coordinates: * space [space] float64 0.1 0.2 0.3 * time [time] float64 2.5 3.56
Nội suy nâng cao của chúng tôi có thể được sử dụng để ánh xạ lại dữ liệu sang tọa độ mới. Xét tọa độ mới x và z trên mặt phẳng hai chiều. Việc ánh xạ lại có thể được thực hiện như sau