Python Сципи: интерполяция RBF дает «неправильный» результат - PullRequest
0 голосов
/ 01 мая 2020

Это мои данные:

a   b   c
732018  2.501   95.094
732018  3.001   91.658
732018  3.501   89.164
732018  3.751   88.471
732018  4.001   88.244
732018  4.251   88.53
732018  4.501   89.8
732018  4.751   90.66
732018  5.001   92.429
732018  5.251   94.58
732018  5.501   97.043
732018  6.001   102.64
732018  6.501   108.798
732079  2.543   94.153
732079  3.043   90.666
732079  3.543   88.118
732079  3.793   87.399
732079  4.043   87.152
732079  4.293   87.425
732079  4.543   88.643
732079  4.793   89.551
732079  5.043   91.326
732079  5.293   93.489
732079  5.543   95.964
732079  6.043   101.587
732079  6.543   107.766
732170  2.597   95.394
732170  3.097   91.987
732170  3.597   89.515
732170  3.847   88.83
732170  4.097   88.61
732170  4.347   88.902
732170  4.597   90.131
732170  4.847   91.035
732170  5.097   92.803
732170  5.347   94.953
732170  5.597   97.414
732170  6.097   103.008
732170  6.597   109.164
732353  4.685   91.422

Я пытаюсь получить c для a=732107 и b=4.92. Я ожидаю ~ 90,79 на основе следующего расчета с использованием базовой c линейной интерполяции (светло-зеленый - исходные данные, темно-зеленые промежуточные шаги и жирный черный - результат):

enter image description here

Но когда я подаю всю поверхность в Rbf, я получаю странные результаты:

import pandas
from scipy.interpolate import Rbf

interp_fun = Rbf(df["a"], df["b"], df["c"], function='cubic',smooth=0)
vol = interp_fun(732107,4.92)
print(vol)

array(207.6631648)

Похоже, что это экстраполяция там, где не должно быть к.

Чего мне не хватает?

1 Ответ

1 голос
/ 01 мая 2020

Я думаю, что есть проблема с данными и что ваш прогноз может быть немного оптимистичным c. Чтобы увидеть это, я использовал алгоритм KrigingAlgorithm , чтобы получить значение и доверительный интервал. Более того, я нанес данные на график, чтобы получить представление о ситуации.

Сначала я превратил данные в пригодный для использования массив Numpy:

import openturns as ot
import numpy as np
data = [
    732018,  2.501,   95.094,
    732018,  3.001,   91.658,
    732018,  3.501,   89.164,
    732018,  3.751,   88.471,
    732018,  4.001,   88.244,
    732018,  4.251,   88.53,
    732018,  4.501,   89.8,
    732018,  4.751,   90.66,
    732018,  5.001,   92.429,
    732018,  5.251,   94.58,
    732018,  5.501,   97.043,
    732018,  6.001,   102.64,
    732018,  6.501,   108.798,
    732079,  2.543,   94.153,
    732079,  3.043,   90.666,
    732079,  3.543,   88.118,
    732079,  3.793,   87.399,
    732079,  4.043,   87.152,
    732079,  4.293,   87.425,
    732079,  4.543,   88.643,
    732079,  4.793,   89.551,
    732079,  5.043,   91.326,
    732079,  5.293,   93.489,
    732079,  5.543,   95.964,
    732079,  6.043,   101.587,
    732079,  6.543,   107.766,
    732170,  2.597,   95.394,
    732170,  3.097,   91.987,
    732170,  3.597,   89.515,
    732170,  3.847,   88.83,
    732170,  4.097,   88.61,
    732170,  4.347,   88.902,
    732170,  4.597,   90.131,
    732170,  4.847,   91.035,
    732170,  5.097,   92.803,
    732170,  5.347,   94.953,
    732170,  5.597,   97.414,
    732170,  6.097,   103.008,
    732170,  6.597,   109.164,
    732353,  4.685,   91.422,
]
dimension = 3
array = np.array(data)
nrows = len(data) // dimension
ncols = len(data) // nrows
data = array.reshape((nrows, ncols))

Затем я создал Sample с данными масштабируя a, чтобы упростить вычисления.

x = ot.Sample(data[:, [0, 1]])
x[:, 0] /= 1.e5
y = ot.Sample(data[:, [2]])

Создать метамодель кригинга просто с трендом ConstantBasisFactory и ковариационной моделью SquaredExponential.

inputDimension = 2
basis = ot.ConstantBasisFactory(inputDimension).build()
covarianceModel = ot.SquaredExponential([0.1]*inputDimension, [1.0])
algo = ot.KrigingAlgorithm(x, y, covarianceModel, basis)
algo.run()
result = algo.getResult()
metamodel = result.getMetaModel()

Метамодель кригинга может затем использоваться для предсказания:

a = 732107 / 1.e5
b = 4.92
inputPrediction = [a, b]
outputPrediction = metamodel([inputPrediction])[0, 0]
print(outputPrediction)

Это печатает:

95.3261715192566

Это не соответствует вашему предсказанию и имеет меньшую амплитуду, чем предсказание RBF.

Чтобы увидеть это более четко, я создал график данных, метамодели и точки для прогнозирования.

graph = metamodel.draw([7.320, 2.0], [7.325,6.597], [50]*2)
cloud = ot.Cloud(x)
graph.add(cloud)
point = ot.Cloud(ot.Sample([inputPrediction]))
point.setColor("red")
graph.add(point)
graph.setXTitle("a")
graph.setYTitle("b")

Это дает следующую графику:

Kriging

Вы видите, что справа есть выброс: это последний пункт в таблице. Точка, которая должна быть предсказана, отмечена красным в левом верхнем углу графика. В окрестности этой точки слева направо мы видим, что кригинг увеличивается с 92 до 95, затем снова уменьшается. Это генерируется очень высокими значениями (близкими к 100) в верхней части домена.

Затем я вычисляю доверительный интервал прогноза кригинга.

conditionalVariance = result.getConditionalMarginalVariance(
    inputPrediction)
sigma = np.sqrt(conditionalVariance)
[outputPrediction - 2 * sigma, outputPrediction + 2 * sigma]

Это приводит к:

[84.26731758315441, 106.3850254553588]

Следовательно, ваш прогноз 90,79 содержится в 95% доверительном интервале, но с довольно высокой неопределенностью.

Исходя из этого, я бы сказал, что кубический c RBF преувеличивает изменения в данных, что приводит к довольно высокому значению.

...