Заставить Mathematica выполнять интерполяцию на неструктурированной тензорной сетке

Этот список представляет собой простую функцию, которая сопоставляет 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] 

Interpolation::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}] 

FunctionInterpolation::nreal:
16 Рядом с {x, y} = {1, --} функция не дала действительное число. 5 FunctionInterpolation::nreal:
17 Рядом с {x, y} = {1, --} функция не дала действительное число. 5 FunctionInterpolation::nreal:
18 Рядом с {x, y} = {1, --} функция не дала действительное число. 5 General::stop: Дальнейший вывод FunctionInterpolation::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)))))) 

Другая «очевидная» идея (интерполяция самих интерполирующих функций) тоже не работает.


person Community    schedule 14.07.2010    source источник


Ответы (3)


Если полиномиальная интерполяция допустима, 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 может соответствовать любой (линейной или нелинейной). linear) функция модели, которую вы указываете:

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}

ХТХ!

person Michael Pilat    schedule 14.07.2010

Пожалуйста, используйте мой пакет!

http://library.wolfram.com/infocenter/MathSource/7760/

person Yasushi Iwasaki    schedule 07.05.2011
comment
Ясуши Ивасаки, добро пожаловать в сообщество StackOverflow Mathematica и спасибо за участие. - person Mr.Wizard; 07.05.2011

К сожалению, полиномы слишком извилисты, а линейные функции недостаточно извилисты. Я считаю, что правильная модель состоит из нескольких отрезков, но все они будут иметь разные наклоны.

Вот отвратительный обходной путь, который делает то, что я хочу.


(* 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} 
person Community    schedule 06.08.2010