Сглаживание экспериментальных данных кусочными функциями

1

У меня есть набор данных для одного измерения по времени (около 3000 точек). Я хотел бы сгладить данные, установив через него кривую. Эксперимент представляет собой многоэтапный физический процесс, поэтому я уверен, что один полином не будет соответствовать всему набору.

Поэтому я смотрю на кусочную серию многочленов. Я хотел бы указать, сколько полиномов используется. Мне кажется, что это довольно простая вещь, и я надеялся, что для этого будет создана некоторая библиотека. Я видел org.apache.commons.math3.fitting.PolynomialFitter в Apache Commons Math, но, похоже, работает только с одним полиномом.

Может ли кто-нибудь предложить лучший способ сделать это? Java предпочла, но я мог бы работать на Python.

  • 0
    Один полином - хорошее начало для кусочной интерполяции - если только вы не можете указать дифференциалы на границах.
  • 0
    Не могли бы вы уточнить это немного. Что (я думаю) я хочу сделать, это поделить временную ось и подогнать полином низкой степени в каждом из них так, чтобы они были непрерывными. Насколько я понимаю, полиномы высокой степени не очень подходят для подгонки.
Показать ещё 2 комментария
Теги:
curve-fitting

2 ответа

1
Лучший ответ

В finmath lib существует класс, называемый кривой, который реализует некоторые интерполяционные схемы (линейные, сплайны, акимы и т.д.). Эти кривые могут предоставить свои точки в качестве параметров решателю, и затем вы можете использовать глобальную оптимизацию (например, оптимизатор Levenberg Marquardt), чтобы минимизировать расстояние ваших данных до кривой (определяя некоторую предпочтительную норму).

Фактически это делается в " Калибровке кривой ", которая является приложением из математического финансирования. Если у вас столько точек (параметров) на кривой, сколько данных, вы, вероятно, получите идеальную форму. Если у вас меньше очков, чем данных, вы получите наилучшее соответствие вашей норме.

Levenberg Marquardt в finmath lib многопоточный и очень быстрый (> 200 точек установлены в << 1 сек).

Видеть

Отказ от ответственности: Я/разработчик этой библиотеки.

Примечание: Мне также нравится commons-math, но для подгонки кривой я не использую его (пока), так как мне нужны (некоторые) подходящие свойства, характерные для моего приложения (математическое финансирование).

(Редактировать)

Вот небольшая демонстрация: (Примечание: для этой демонстрации требуется finmath-lib 1.2.13 или текущий 1.2.12-SNAPSHOT, доступный на mvn.finmath.net или github.com/finmath/finmath-lib (он несовместим с 1.2. 12)

package net.finmath.tests.marketdata.curves;

import java.text.DecimalFormat;
import java.text.NumberFormat;

import org.junit.Test;

import net.finmath.marketdata.model.curves.Curve;
import net.finmath.marketdata.model.curves.CurveInterface;
import net.finmath.optimizer.LevenbergMarquardt;
import net.finmath.optimizer.SolverException;

/**
 * A short demo on how to use {@link net.finmath.marketdata.model.curves.Curve}.
 * 
 * @author Christian Fries
 */
public class CurveTest {

    private static NumberFormat numberFormat = new DecimalFormat("0.0000");

    /**
     * Run a short demo on how to use {@link net.finmath.marketdata.model.curves.Curve}.
     * 
     * @param args Not used.
     * @throws SolverException Thrown if optimizer fails.
     * @throws CloneNotSupportedException Thrown if curve cannot be cloned for optimization.
     */
    public static void main(String[] args) throws SolverException, CloneNotSupportedException {
        (new CurveTest()).testCurveFitting();
    }

    /**
     * Tests fitting of curve to given data.
     * 
     * @throws SolverException Thrown if optimizer fails.
     * @throws CloneNotSupportedException Thrown if curve cannot be cloned for optimization.
     */
    @Test
    public void testCurveFitting() throws SolverException, CloneNotSupportedException {

        /*
         * Build a curve (initial guess for our fitting problem, defines the times).
         */
        Curve.CurveBuilder curveBuilder = new Curve.CurveBuilder();

        curveBuilder.setInterpolationMethod(Curve.InterpolationMethod.LINEAR);
        curveBuilder.setExtrapolationMethod(Curve.ExtrapolationMethod.LINEAR);
        curveBuilder.setInterpolationEntity(Curve.InterpolationEntity.VALUE);

        // Add some points - which will not be fitted
        curveBuilder.addPoint(-1.0 /* time */, 1.0 /* value */, false /* isParameter */);
        curveBuilder.addPoint( 0.0 /* time */, 1.0 /* value */, false /* isParameter */);

        // Add some points - which will be fitted
        curveBuilder.addPoint( 0.5  /* time */, 2.0 /* value */, true /* isParameter */);
        curveBuilder.addPoint( 0.75 /* time */, 2.0 /* value */, true /* isParameter */);
        curveBuilder.addPoint( 1.0 /* time */, 2.0 /* value */, true /* isParameter */);
        curveBuilder.addPoint( 2.2 /* time */, 2.0 /* value */, true /* isParameter */);
        curveBuilder.addPoint( 3.0 /* time */, 2.0 /* value */, true /* isParameter */);

        final Curve curve = curveBuilder.build();

        /*
         * Create data to which the curve should be fitted to
         */
        final double[] givenTimes   = { 0.0,  0.5, 0.75, 1.0, 1.5, 1.75, 2.5 };
        final double[] givenValues  = { 3.5, 12.3, 13.2, 7.5, 5.5, 2.9,  4.4 };

        /*
         * Find a best fitting curve.
         */

        // Define the objective function
        LevenbergMarquardt optimizer = new LevenbergMarquardt(
                curve.getParameter()    /* initial parameters */,
                givenValues             /* target values */,
                100,                    /* max iterations */
                Runtime.getRuntime().availableProcessors() /* max number of threads */  
                ) {

            @Override
            public void setValues(double[] parameters, double[] values) throws SolverException {

                CurveInterface curveGuess = null;
                try {
                    curveGuess = curve.getCloneForParameter(parameters);
                } catch (CloneNotSupportedException e) {
                    throw new SolverException(e);
                }

                for(int valueIndex=0; valueIndex<values.length; valueIndex++) {
                    values[valueIndex] = curveGuess.getValue(givenTimes[valueIndex]);
                }
            }
        };

        // Fit the curve (find best parameters)
        optimizer.run();

        CurveInterface fittedCurve = curve.getCloneForParameter(optimizer.getBestFitParameters());

        // Print out fitted curve
        for(double time = -2.0; time < 5.0; time += 0.1) {
            System.out.println(numberFormat.format(time) + "\t" + numberFormat.format(fittedCurve.getValue(time)));
        }

        // Check fitted curve
        double errorSum = 0.0;
        for(int pointIndex = 0; pointIndex<givenTimes.length; pointIndex++) {
            errorSum += fittedCurve.getValue(givenTimes[pointIndex]) - givenValues[pointIndex];
        }
        System.out.println("Mean deviation: " + errorSum);

        /*
         * Test: With the given data, the fit cannot over come that at 0.0 we have an error of -2.5.
         * Hence we test if the mean deviation is -2.5 (the optimizer reduces the variance)
         */
        org.junit.Assert.assertTrue(Math.abs(errorSum - -2.5) < 1E-5);
    }
}
  • 0
    Это звучит идеально. Я взгляну на finmath - просто нужно разобраться с финансовой терминологией!
  • 0
    Если вам интересно, я могу опубликовать небольшую демонстрацию, которая более независима от приложения (например, математические финансы).
2

Если вы ищете местную регрессию, Commons Math реализует ее как LoessInterpolator. Вы получите конечный результат как "сплайн", гладкую последовательность кусочно-кубических многочленов.

  • 0
    Это почти все, но я хотел бы указать, на сколько секций разделена временная последовательность. Если я введу 3000 точек в LoessInterpolator, он сгенерирует 2999 полиномиальных функций. Я хотел бы сказать, разделить кривую на 10 и подобрать лучший полином для каждого сечения. (Это не было ясно в исходном вопросе, поэтому я отредактировал его)
  • 0
    Вы хотите, чтобы десять частей плавно соединились?
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню