Java曲线拟合库

发布于 2024-07-19 09:34:33 字数 1539 浏览 9 评论 0原文

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

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

发布评论

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

评论(2

江挽川 2024-07-26 09:34:33

Apache Commons Math 有一系列很好的算法,特别是“SplineInterpolator”,请参阅API 文档

我们调用 alpha 插值函数的示例来自 Groovy 的 (x)、beta(x):

package example.com

import org.apache.commons.math3.analysis.interpolation.SplineInterpolator
import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction

import statec.Extrapolate.Value;

class Interpolate {

    enum Value {
        ALPHA, BETA
    }

    def static xValues     = [
        -284086,
        -94784,
        31446,
        354837,
        667782,
        982191
    ]
    def static alphaValues = [
        71641,
        78245,
        80871,
        94045,
        105780,
        119616
    ]
    def static betaValues = [
        95552,
        103413,
        108667,
        128456,
        144686,
        171953
    ]

    static def getValueByName(Value value, int i) {
        def res
        switch (value) {
            case Value.ALPHA:
                res = alphaValues[i]
                break
            case Value.BETA:
                res = betaValues[i]
                break
            default:
                assert false
        }
        return res
    }

    static PolynomialSplineFunction interpolate(Value value) {
        def yValues = []
        int i = 0
        xValues.each {
            def y = getValueByName(value, i++)
            yValues << (y as Double)
        }
        SplineInterpolator spi = new SplineInterpolator()
        return spi.interpolate(xValues as double[], yValues as double[])
    }

    static void main(def argv) {
        //
        // Create a map mapping a Value instance to its interpolating function
        //
        def interpolations = [:]
        Value.values().each {
            interpolations[it] = interpolate(it)
        }
        //
        // Create an array of new x values to compute display.
        // Make sure the last "original" value is in there!
        // Note that the newxValues MUST stay within the range of the original xValues!
        //
        def newxValues = []
        for (long x = xValues[0] ; x < xValues[-1] ; x+=25000) {
            newxValues << x
        }
        newxValues << xValues[-1]
        //
        // Write interpolated values for ALPHA and BETA, adding the original values in columns 4 and 5
        //
        System.out << "X , ALPHA, BETA, X_orig, ALPHA_orig, BETA_orig" << "\n"
        int origIndex = 0
        newxValues.each { long x ->
            def alpha_ipol = interpolations[Value.ALPHA].value(x)
            def beta_ipol  = interpolations[Value.BETA].value(x)
            String out = "${x} ,  ${alpha_ipol} , ${beta_ipol}"
            if (x >= xValues[origIndex]) {
                out += ", ${xValues[origIndex]}, ${alphaValues[origIndex]}, ${betaValues[origIndex]}"
                origIndex++
            }
            System.out << out << "\n"
        }
    }
}

结果输出,在 LibreOffice Calc 中绘制

现在来说一个题外话外推法的例子,因为它很有趣。 这里我们使用与上面相同的数据,但使用二次多项式进行推断。 当然还有适当的课程。 同样,在 Groovy 中:

package example.com

import org.apache.commons.math3.analysis.polynomials.PolynomialFunction
import org.apache.commons.math3.fitting.PolynomialFitter
import org.apache.commons.math3.fitting.WeightedObservedPoint
import org.apache.commons.math3.optim.SimpleVectorValueChecker
import org.apache.commons.math3.optim.nonlinear.vector.jacobian.GaussNewtonOptimizer

class Extrapolate {

    enum Value {
        ALPHA, BETA
    }

    def static xValues     = [
        -284086,
        -94784,
        31446,
        354837,
        667782,
        982191
    ]
    def static alphaValues = [
        71641,
        78245,
        80871,
        94045,
        105780,
        119616
    ]
    def static betaValues = [
        95552,
        103413,
        108667,
        128456,
        144686,
        171953
    ]

    static def getValueByName(Value value, int i) {
        def res
        switch (value) {
            case Value.ALPHA:
                res = alphaValues[i]
                break
            case Value.BETA:
                res = betaValues[i]
                break
            default:
                assert false
        }
        return res
    }

    static PolynomialFunction extrapolate(Value value) {
        //
        // how to check that we converged
        //
        def checker
        A: {
            double relativeThreshold = 0.01
            double absoluteThreshold = 10
            int maxIter = 1000
            checker = new SimpleVectorValueChecker(relativeThreshold, absoluteThreshold, maxIter)
        }
        //
        // how to fit
        //
        def fitter
        B: {
            def useLUdecomposition = true
            def optimizer = new GaussNewtonOptimizer(useLUdecomposition, checker)
            fitter = new PolynomialFitter(optimizer)
            int i = 0
            xValues.each {
                def weight = 1.0
                def y = getValueByName(value, i++)
                fitter.addObservedPoint(new WeightedObservedPoint(weight, it, y))
            }
        }
        //
        // fit using a 2-degree polynomial; guess at a linear function at first
        // "a0 + (a1 * x) + (a2 * x²)"; a linear guess mean a2 == 0
        //
        def params
        C: {
            def mStart = getValueByName(value,0)
            def mEnd   = getValueByName(value,-1)
            def xStart = xValues[0]
            def xEnd   = xValues[-1]
            def a2 = 0
            def a1 = (mEnd - mStart) / (xEnd - xStart) // slope
            def a0 = mStart - (xStart * a1) // 0-intersection
            def guess = [a0 , a1 , a2]
            params = fitter.fit(guess as double[])
        }
        //
        // make polynomial
        //
        return new PolynomialFunction(params)
    }

    static void main(def argv) {
        //
        // Create a map mapping a Value instance to its interpolating function
        //
        def extrapolations = [:]
        Value.values().each {
            extrapolations[it] = extrapolate(it)
        }
        //
        // New x, this times reaching out past the range of the original xValues
        //
        def newxValues = []
        for (long x = xValues[0] - 400000L ; x < xValues[-1] + 400000L ; x += 10000) {
            newxValues << x
        }
        //
        // Write the extrapolated series ALPHA and BETA, adding the original values in columns 4 and 5
        //
        System.out << "X , ALPHA, BETA, X_orig, ALPHA_orig, BETA_orig" << "\n"
        int origIndex = 0
        newxValues.each { long x ->
            def alpha_xpol = extrapolations[Value.ALPHA].value(x)
            def beta_xpol  = extrapolations[Value.BETA].value(x)
            String out = "${x} ,  ${alpha_xpol} , ${beta_xpol}"
            if (origIndex < xValues.size() && x >= xValues[origIndex]) {
                out += ", ${xValues[origIndex]}, ${alphaValues[origIndex]}, ${betaValues[origIndex]}"
                origIndex++
            }
            System.out << out << "\n"
        }
    }
}

结果输出,在 LibreOffice Calc 中绘制

Apache Commons Math has a nice series of algorithms, in particular "SplineInterpolator", see the API docs

An example in which we call the interpolation functions for alpha(x), beta(x) from Groovy:

package example.com

import org.apache.commons.math3.analysis.interpolation.SplineInterpolator
import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction

import statec.Extrapolate.Value;

class Interpolate {

    enum Value {
        ALPHA, BETA
    }

    def static xValues     = [
        -284086,
        -94784,
        31446,
        354837,
        667782,
        982191
    ]
    def static alphaValues = [
        71641,
        78245,
        80871,
        94045,
        105780,
        119616
    ]
    def static betaValues = [
        95552,
        103413,
        108667,
        128456,
        144686,
        171953
    ]

    static def getValueByName(Value value, int i) {
        def res
        switch (value) {
            case Value.ALPHA:
                res = alphaValues[i]
                break
            case Value.BETA:
                res = betaValues[i]
                break
            default:
                assert false
        }
        return res
    }

    static PolynomialSplineFunction interpolate(Value value) {
        def yValues = []
        int i = 0
        xValues.each {
            def y = getValueByName(value, i++)
            yValues << (y as Double)
        }
        SplineInterpolator spi = new SplineInterpolator()
        return spi.interpolate(xValues as double[], yValues as double[])
    }

    static void main(def argv) {
        //
        // Create a map mapping a Value instance to its interpolating function
        //
        def interpolations = [:]
        Value.values().each {
            interpolations[it] = interpolate(it)
        }
        //
        // Create an array of new x values to compute display.
        // Make sure the last "original" value is in there!
        // Note that the newxValues MUST stay within the range of the original xValues!
        //
        def newxValues = []
        for (long x = xValues[0] ; x < xValues[-1] ; x+=25000) {
            newxValues << x
        }
        newxValues << xValues[-1]
        //
        // Write interpolated values for ALPHA and BETA, adding the original values in columns 4 and 5
        //
        System.out << "X , ALPHA, BETA, X_orig, ALPHA_orig, BETA_orig" << "\n"
        int origIndex = 0
        newxValues.each { long x ->
            def alpha_ipol = interpolations[Value.ALPHA].value(x)
            def beta_ipol  = interpolations[Value.BETA].value(x)
            String out = "${x} ,  ${alpha_ipol} , ${beta_ipol}"
            if (x >= xValues[origIndex]) {
                out += ", ${xValues[origIndex]}, ${alphaValues[origIndex]}, ${betaValues[origIndex]}"
                origIndex++
            }
            System.out << out << "\n"
        }
    }
}

The resulting output, plotted in LibreOffice Calc

And now for an off-topic example for EXTRAPOLATIONS, because it's fun. Here we use the same data as above, but extrapolate using an 2nd-degree polynomial. And the appropriate classes, of course. Again, in Groovy:

package example.com

import org.apache.commons.math3.analysis.polynomials.PolynomialFunction
import org.apache.commons.math3.fitting.PolynomialFitter
import org.apache.commons.math3.fitting.WeightedObservedPoint
import org.apache.commons.math3.optim.SimpleVectorValueChecker
import org.apache.commons.math3.optim.nonlinear.vector.jacobian.GaussNewtonOptimizer

class Extrapolate {

    enum Value {
        ALPHA, BETA
    }

    def static xValues     = [
        -284086,
        -94784,
        31446,
        354837,
        667782,
        982191
    ]
    def static alphaValues = [
        71641,
        78245,
        80871,
        94045,
        105780,
        119616
    ]
    def static betaValues = [
        95552,
        103413,
        108667,
        128456,
        144686,
        171953
    ]

    static def getValueByName(Value value, int i) {
        def res
        switch (value) {
            case Value.ALPHA:
                res = alphaValues[i]
                break
            case Value.BETA:
                res = betaValues[i]
                break
            default:
                assert false
        }
        return res
    }

    static PolynomialFunction extrapolate(Value value) {
        //
        // how to check that we converged
        //
        def checker
        A: {
            double relativeThreshold = 0.01
            double absoluteThreshold = 10
            int maxIter = 1000
            checker = new SimpleVectorValueChecker(relativeThreshold, absoluteThreshold, maxIter)
        }
        //
        // how to fit
        //
        def fitter
        B: {
            def useLUdecomposition = true
            def optimizer = new GaussNewtonOptimizer(useLUdecomposition, checker)
            fitter = new PolynomialFitter(optimizer)
            int i = 0
            xValues.each {
                def weight = 1.0
                def y = getValueByName(value, i++)
                fitter.addObservedPoint(new WeightedObservedPoint(weight, it, y))
            }
        }
        //
        // fit using a 2-degree polynomial; guess at a linear function at first
        // "a0 + (a1 * x) + (a2 * x²)"; a linear guess mean a2 == 0
        //
        def params
        C: {
            def mStart = getValueByName(value,0)
            def mEnd   = getValueByName(value,-1)
            def xStart = xValues[0]
            def xEnd   = xValues[-1]
            def a2 = 0
            def a1 = (mEnd - mStart) / (xEnd - xStart) // slope
            def a0 = mStart - (xStart * a1) // 0-intersection
            def guess = [a0 , a1 , a2]
            params = fitter.fit(guess as double[])
        }
        //
        // make polynomial
        //
        return new PolynomialFunction(params)
    }

    static void main(def argv) {
        //
        // Create a map mapping a Value instance to its interpolating function
        //
        def extrapolations = [:]
        Value.values().each {
            extrapolations[it] = extrapolate(it)
        }
        //
        // New x, this times reaching out past the range of the original xValues
        //
        def newxValues = []
        for (long x = xValues[0] - 400000L ; x < xValues[-1] + 400000L ; x += 10000) {
            newxValues << x
        }
        //
        // Write the extrapolated series ALPHA and BETA, adding the original values in columns 4 and 5
        //
        System.out << "X , ALPHA, BETA, X_orig, ALPHA_orig, BETA_orig" << "\n"
        int origIndex = 0
        newxValues.each { long x ->
            def alpha_xpol = extrapolations[Value.ALPHA].value(x)
            def beta_xpol  = extrapolations[Value.BETA].value(x)
            String out = "${x} ,  ${alpha_xpol} , ${beta_xpol}"
            if (origIndex < xValues.size() && x >= xValues[origIndex]) {
                out += ", ${xValues[origIndex]}, ${alphaValues[origIndex]}, ${betaValues[origIndex]}"
                origIndex++
            }
            System.out << out << "\n"
        }
    }
}

The resulting output, plotted in LibreOffice Calc

紫轩蝶泪 2024-07-26 09:34:33

我从来没有这样做过,但是快速谷歌搜索显示贝塞尔曲线是在 http://java.sun.com/j2se/1.5.0/docs/api/java/awt/geom/QuadCurve2D.Double.html

然后,您可以从这条曲线中 getPathIterator() ,根据文档的说明,您可以得到“形状边界的坐标”,我想这就是您正在寻找的。

I've never done it, but a quick Google search revealed that Bezier curves are implemented in http://java.sun.com/j2se/1.5.0/docs/api/java/awt/geom/QuadCurve2D.Double.html

Then, you can getPathIterator() from this curve and with that, according to what documentation says, you get the "coordinates of shape boundaries", which, i suppose, is what you are looking for.

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