强制 Mathematica 在非结构化张量网格上进行插值

发布于 2024-09-09 18:44:13 字数 1777 浏览 8 评论 0原文

该列表是一个简单的函数,它将 2D 点映射到数字,如果 你将每个 {{x,y},z} 视为 f[x,y]=z

{ 
 {{1,3},9}, {{1,4},16}, 
 {{2,4},8}, {{2,5},10} 
} 

我现在想要一个可以插值/外推 f[x ,y] 对于任何 {x,y}

Mathematica 拒绝这样做:

Interpolation[{{{1,3},9}, {{1,4},16},{{2,4},8}, {{2,5},10}},  
 InterpolationOrder->1] 

插值::indim: 坐标不位于结构化上 张量积网格。

我明白为什么(Mathematica 想要一个“矩形”域),但是 强制 Mathematica 创建插值的最简单方法是什么?

这不起作用:

f[1,3]=9; f[1,4]=16; f[2,4]=8; f[2,5]=10; 
g=FunctionInterpolation[f[x,y],{x,1,2},{y,3,5}] 

函数插值::nreal:
16 在 {x, y} = {1, --} 附近,函数没有 评估为实数。 5 函数插值::nreal:
17 在 {x, y} = {1, --} 附近,函数没有 评估为实数。 5 函数插值::nreal:
18 在 {x, y} = {1, --} 附近,函数没有 评估为实数。 5 General::stop:进一步输出 函数插值::nreal 在此计算过程中将被抑制。

即使您忽略上面的警告,评估 g 也会给出错误

g[1.5,4] // FortranForm 


     f(1.5,4) + 0.*(-9.999999999999991*(f(1.4,4) - f(1.5,4)) +  
 -      0.10000000000000009* 
 -       (9.999999999999991* 
 -          (9.999999999999991*(f(1.4,4) - f(1.5,4)) +  
 -            4.999999999999996*(-f(1.4,4) + f(1.6,4))) +  
 -         0.5000000000000006* 
 -          (-10.000000000000014* 
 -             (-3.333333333333333*(f(1.3,4) - f(1.6,4)) -  
 -               4.999999999999996*(-f(1.4,4) + f(1.6,4))) -  
 -            9.999999999999991* 
 -             (9.999999999999991*(f(1.4,4) - f(1.5,4)) +  
 -               4.999999999999996*(-f(1.4,4) + f(1.6,4)))))) 

另一个“明显”的想法(插值插值函数 他们自己)也不起作用。

This list is a simple function that maps a 2D point to a number, if
you regard each {{x,y},z} as f[x,y]=z

{ 
 {{1,3},9}, {{1,4},16}, 
 {{2,4},8}, {{2,5},10} 
} 

I now want a function that interpolates/extrapolates f[x,y] for any {x,y}.

Mathematica refuses to do this:

Interpolation[{{{1,3},9}, {{1,4},16},{{2,4},8}, {{2,5},10}},  
 InterpolationOrder->1] 

Interpolation::indim: The
coordinates do not lie on a structured
tensor product grid.

I understand why (Mathematica wants a "rectangular" domain), but
what's the easiest way to force Mathematica to create an interpolation?

This doesn't work:

f[1,3]=9; f[1,4]=16; f[2,4]=8; f[2,5]=10; 
g=FunctionInterpolation[f[x,y],{x,1,2},{y,3,5}] 

FunctionInterpolation::nreal:
16 Near {x, y} = {1, --}, the function did not
evaluate to a real number.
5 FunctionInterpolation::nreal:
17 Near {x, y} = {1, --}, the function did not
evaluate to a real number.
5 FunctionInterpolation::nreal:
18 Near {x, y} = {1, --}, the function did not
evaluate to a real number.
5 General::stop: Further output of
FunctionInterpolation::nreal
will be suppressed during this calculation.

Even if you ignore the warnings above, evaluating g gives errors

g[1.5,4] // FortranForm 


     f(1.5,4) + 0.*(-9.999999999999991*(f(1.4,4) - f(1.5,4)) +  
 -      0.10000000000000009* 
 -       (9.999999999999991* 
 -          (9.999999999999991*(f(1.4,4) - f(1.5,4)) +  
 -            4.999999999999996*(-f(1.4,4) + f(1.6,4))) +  
 -         0.5000000000000006* 
 -          (-10.000000000000014* 
 -             (-3.333333333333333*(f(1.3,4) - f(1.6,4)) -  
 -               4.999999999999996*(-f(1.4,4) + f(1.6,4))) -  
 -            9.999999999999991* 
 -             (9.999999999999991*(f(1.4,4) - f(1.5,4)) +  
 -               4.999999999999996*(-f(1.4,4) + f(1.6,4)))))) 

The other "obvious" idea (interpolating interpolating functions
themselves) doesn't work either.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

妞丶爷亲个 2024-09-16 18:44:13

如果多项式插值可接受,则 InterpolatingPolynomial 会执行您的操作想要(其中 data 是上面的要点列表):

In[63]:= InterpolatingPolynomial[data, {x, y}]

Out[63]= -24 + x (12 - 5 y) + 12 y

In[64]:= f[2, 3]

Out[64]= 6

您还可以使用 Fit 对第二个参数中指定的函数的线性组合进行最小二乘拟合:

In[65]:= Fit[Flatten /@ data, {1, x, y}, {x, y}]

Out[65]= 4.75 - 8. x + 4.5 y

当然,拟合函数可能无法精确地插值您的数据点。如果这种拟合是可以接受的,FindFit 可以拟合到您指定的任何(线性或非线性)模型函数:

In[72]:= FindFit[Flatten/@data, x y (a Sin[x] + b Cos[y]) + c, {a,b,c}, {x,y}]

Out[72]= {a -> -0.683697, b -> 0.414257, c -> 15.3805}

HTH!

If polynomial interpolation is acceptable, InterpolatingPolynomial does what you want (where data is your list of points above):

In[63]:= InterpolatingPolynomial[data, {x, y}]

Out[63]= -24 + x (12 - 5 y) + 12 y

In[64]:= f[2, 3]

Out[64]= 6

You could also use Fit to do least-squares fitting on the linear combination of functions specified in the second argument:

In[65]:= Fit[Flatten /@ data, {1, x, y}, {x, y}]

Out[65]= 4.75 - 8. x + 4.5 y

Of course, a fitted function may not exactly interpolate your data points. If such fitting is acceptable though, FindFit can fit to any (linear or non-linear) model function you specify:

In[72]:= FindFit[Flatten/@data, x y (a Sin[x] + b Cos[y]) + c, {a,b,c}, {x,y}]

Out[72]= {a -> -0.683697, b -> 0.414257, c -> 15.3805}

HTH!

过去的过去 2024-09-16 18:44:13

不幸的是,多项式太不稳定,但线性函数却不然
够扭动的。我相信正确的模型是几条线段,
但它们都有不同的坡度。

这是一个可怕的解决方法,可以满足我的要求。


(* data in format {{x,y},z} *) 
data = {{{1,3},9}, {{1,4},16}, {{2,4},8}, {{2,5},10}} 

(* find the ranges of x and y *) 
datax = DeleteDuplicates[Transpose[Transpose[data][[1]]][[1]]] 
datay = DeleteDuplicates[Transpose[Transpose[data][[1]]][[2]]] 

(* extract the values of y and z for each x *) 
datamap[t_]:=Map[{#[[1,2]], #[[2]]} &, Select[data, #[[1,1]] == t &]] 

(* interpolate for each value of x, create a rectangular array, and then 
   interpolate in y *) 
Map[(f[#]=Interpolation[datamap[#],InterpolationOrder->1])&, datax] 

(* and now apply f to the expanded grid I've created *) 

datatab = Flatten[Table[ 
 {{datax[[i]], datay[[j]]}, f[datax[[i]]][datay[[j]]]}, 
 {i,1,Length[datax]}, {j,1,Length[datay]}], 1] 

(* now mathematica will let me interpolate *) 
dataint = Interpolation[datatab, InterpolationOrder->1] 

(* The resulting function agrees with my original*) 

Flatten[Table[{{x,y},dataint[x,y]},{x,1,2},{y,3,5}],1] 

Out[29]= {{{1, 3}, 9}, {{1, 4}, 16}, {{1, 5}, 23}, {{2, 3}, 6}, {{2, 4}, 8},  
{{2, 5}, 10}} 

(* above contains all my original points [plus a few extra] *) 

(* and does a reasonable job of interpolating *) 

dataint[1.5,3.5] 

9.75 

which is the average of the four corner values: 

{dataint[1,3], dataint[1,4], dataint[2,3], dataint[2,4]} 

{9, 16, 6, 8} 

Unfortunately, polynomials are too wiggly, but linear functions aren't
wiggly enough. I believe the correct model is several line segments,
but they'll all have different slopes.

Here's a hideous workaround that does what I want.


(* data in format {{x,y},z} *) 
data = {{{1,3},9}, {{1,4},16}, {{2,4},8}, {{2,5},10}} 

(* find the ranges of x and y *) 
datax = DeleteDuplicates[Transpose[Transpose[data][[1]]][[1]]] 
datay = DeleteDuplicates[Transpose[Transpose[data][[1]]][[2]]] 

(* extract the values of y and z for each x *) 
datamap[t_]:=Map[{#[[1,2]], #[[2]]} &, Select[data, #[[1,1]] == t &]] 

(* interpolate for each value of x, create a rectangular array, and then 
   interpolate in y *) 
Map[(f[#]=Interpolation[datamap[#],InterpolationOrder->1])&, datax] 

(* and now apply f to the expanded grid I've created *) 

datatab = Flatten[Table[ 
 {{datax[[i]], datay[[j]]}, f[datax[[i]]][datay[[j]]]}, 
 {i,1,Length[datax]}, {j,1,Length[datay]}], 1] 

(* now mathematica will let me interpolate *) 
dataint = Interpolation[datatab, InterpolationOrder->1] 

(* The resulting function agrees with my original*) 

Flatten[Table[{{x,y},dataint[x,y]},{x,1,2},{y,3,5}],1] 

Out[29]= {{{1, 3}, 9}, {{1, 4}, 16}, {{1, 5}, 23}, {{2, 3}, 6}, {{2, 4}, 8},  
{{2, 5}, 10}} 

(* above contains all my original points [plus a few extra] *) 

(* and does a reasonable job of interpolating *) 

dataint[1.5,3.5] 

9.75 

which is the average of the four corner values: 

{dataint[1,3], dataint[1,4], dataint[2,3], dataint[2,4]} 

{9, 16, 6, 8} 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文