代码之家  ›  专栏  ›  技术社区  ›  Russell Leggett

Java曲线拟合库[关闭]

  •  18
  • Russell Leggett  · 技术社区  · 16 年前

    我希望能找到一个简单的库,可以得到一系列的二维点,并给我一个更大的系列点模型的曲线。基本上,我想得到曲线拟合的效果,就像JFreeChart中的这个示例:

    enter image description here

    JFreeChart的问题是代码没有提供这种类型的api。我甚至看了源代码和算法是紧密耦合到实际绘图。

    2 回复  |  直到 6 年前
        1
  •  8
  •   David Tonhofer    11 年前

    Apache Commons Math 有一系列不错的算法,特别是“SplineInterpolator”,请参见 API docs

    我们从Groovy中调用alpha(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"
            }
        }
    }
    

    The resulting output, plotted in LibreOffice Calc

    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

        2
  •  0
  •   jbasko    16 年前

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

    然后,你可以从这条曲线得到getPathIterator(),根据文档所说,你可以得到“形状边界的坐标”,我想这就是你要找的。