8

我正在寻找一个 java 库或一些帮助来编写我自己的插值函数。也就是说,我有两个双精度数组,它们的大小可能不同,但是是有序的。我需要能够估计中间值,并插入以便两个数组的大小相同。事实上,插值中出现的点总数是 2 个数组大小的总和减去 1。但是,每个数组的范围必须保持不变,因此不需要外插。

例如。a1 = [1, 4, 9, 16, 25, 36] 和 a2 = [6, 9, 14, 30]

结果可能是例如。

a1 = [1, 2.25, 4, 6.25, 9, 12.25, 16, 25, 36] 和 a2 = [6, 6.5625, 7.25, 9, 10.0625, 11.25, 14, 25.25, 30]

但是,这些示例f(x) = x^2 and g(x) = x^2 + 5很容易是任何多项式 - 关键是能够从数据集中充分估计/近似函数,以提供足够体面的插值。这里的 x 值只是输入数组的索引。在输出中,只有 y 值很重要。

4

8 回答 8

14

其他答案为您提供线性插值 - 这些对于复杂的非线性数据并不真正适用。 你想要一个样条拟合,(样条插值)我相信。

样条拟合使用数据中的一组控制点来描述数据区域,然后在控制点之间应用多项式插值。更多控制点为您提供更准确的拟合,而不是更一般的拟合。样条曲线比线性拟合更准确,比一般回归拟合更快,比高阶多项式更好,因为它不会在控制点之间做疯狂的事情。

我不记得名字了,但是 Java 中有一些非常适合的库——我建议你寻找一个而不是编写自己的函数。


**编辑:可能有用的库:**

** 可能有用的理论/代码:**

  • 带有代码的样条小程序:链接
  • Arkan样条拟合折线到贝塞尔样条
  • 样条理论,以及一些拟合数学。如果库不这样做,更多的数学,更少的代码可能会有所帮助。
于 2009-08-03T18:08:03.423 回答
4

专为一维数据数组设计

import java.util.ArrayList;

public class Interpolator {

public static Float CosineInterpolate(Float y1,Float y2,Float mu)
{
    double mu2;

    mu2 = (1.0f-Math.cos(mu*Math.PI))/2.0f;
    Float f_mu2 = new Float(mu2);
    return(y1*(1.0f-f_mu2)+y2*f_mu2);
}

public static Float LinearInterpolate(Float y1,Float y2,Float mu)
{
    return(y1*(1-mu)+y2*mu);
}


public static Float[] Interpolate(Float[] a, String mode) {

    // Check that have at least the very first and very last values non-null
    if (!(a[0] != null && a[a.length-1] != null)) return null;

    ArrayList<Integer> non_null_idx = new ArrayList<Integer>();
    ArrayList<Integer> steps = new ArrayList<Integer>();

    int step_cnt = 0;
    for (int i=0; i<a.length; i++)
    {
        if (a[i] != null)
        {
            non_null_idx.add(i);
            if (step_cnt != 0) {
                steps.add(step_cnt);
                System.err.println("aDDed step >> " + step_cnt);
            }
            step_cnt = 0;
        }
        else
        {
            step_cnt++;
        }
    }

    Float f_start = null;
    Float f_end = null;
    Float f_step = null;
    Float f_mu = null;

    int i = 0;
    while (i < a.length - 1) // Don't do anything for the very last element (which should never be null)
    {
        if (a[i] != null && non_null_idx.size() > 1 && steps.size() > 0)
        {
            f_start = a[non_null_idx.get(0)];
            f_end = a[non_null_idx.get(1)];
            f_step = new Float(1.0) / new Float(steps.get(0) + 1);
            f_mu = f_step;
            non_null_idx.remove(0);
            steps.remove(0);
        }
        else if (a[i] == null)
        {
            if (mode.equalsIgnoreCase("cosine"))
                a[i] = CosineInterpolate(f_start, f_end, f_mu);
            else
                a[i] = LinearInterpolate(f_start, f_end, f_mu);
            f_mu += f_step;
        }
        i++;
    }

    return a;
}
}

不知道它是否有帮助......它的编码速度非常快,所以如果有人有更好/性能更好的方法来做同样的事情,感谢您的贡献。

用法:

input : Float[] a = {1.0f, null, null, 2.0f, null, null, null, 15.0f};

call : Interpolator.Interpolate(a, "Linear");

output : 1.0|1.3333333|1.6666667|2.0|5.25|8.5|11.75|15.0
于 2011-10-27T08:50:59.237 回答
3

我知道这是一个旧答案,但它是搜索 Java 插值时谷歌的第一个热门。接受的答案提供了一些有用的链接,但必须购买 JMSL,而且 JSpline+ 网站看起来很粗略。

Apache Commons Math 实现了线性和样条插值,看起来简单、实用且值得信赖。

http://commons.apache.org/proper/commons-math/

于 2013-07-19T13:00:22.803 回答
1

可以使用以下方法计算简单的线性插值:

Point2D interp1_lin(Point2D p1, Point2D p2, double x) {
 //Pre conditions
assert p1.x<x;
assert x<p2.x;
//Calculate slope from p1 to p2
double m = (p2.x-p1.x)/(p2.y-p1.y);
//Calculate y position of x
double y = (x-p1.x)*m+p1.y;
//create new point
return new Point2D.Double(x,y);
}

这有帮助吗?

于 2009-08-03T12:29:24.177 回答
0

您需要获取与 y 值对应的 x 值。否则,任何算法都无法确定 [1, 16, 81] 是 [1, 4, 9] 的 x^2 还是 [1, 2, 3] 的 x^4。你会插入六个值还是没有?

然后,当您获得 x 值时,您可以使用某种插值(线性、kubic 样条,您可以命名)来近似缺失值。

于 2009-08-03T15:47:58.810 回答
0

一维数组线性插值器的轻量级版本:

public static float[] interpolate(float[] data) {
    int startIdx = -1;
    float startValue = 0f;
    float element;
    for (int i = 0; i < data.length - 1; i++) {
        element = data[i];
        if (element != 0f) {
            if (startIdx != -1) {
                doInterpolate(startValue, element, startIdx + 1, i - startIdx - 1, data);
            }
            startValue = element;
            startIdx = i;
        }
    }
    return data;
}

private static void doInterpolate(float start, float end, int startIdx, int count, float[] data) {
    float delta = (end - start) / (count + 1);
    for (int i = startIdx; i < startIdx + count; i++) {
        data[i] = start + delta * (i - startIdx + 1);
    }
}
于 2014-03-21T16:46:39.090 回答
0

使用样条拟合和多项式拟合要非常小心。这两者可能会产生荒谬的行为,从而破坏数据的许多用途(被认为是数据的表示)。

任何使用数据导数(斜率)的东西都可能完全出轨。

您可以做的最好的事情是绘制数据,了解它在做什么,然后才能拟合(线性、多项式、对数对数)回归;一旦你完成了,你应该在原始数据上绘制你的拟合,并确保你看到合理的协议。跳过这个比较步骤是一个非常糟糕的主意。

某些数据集不会屈服于多项式、对数对数等的拟合;如果您的数据点在数据范围内适当分布,则分段插值(线性或多项式等)没有任何问题。为了打败一匹死马,如果您使用分段插值,请避免使用分段插值的导数/斜率的任何内容,因为它会出现不连续性并导致事情表现不佳。

于 2015-01-11T18:24:43.203 回答
0

您可以使用apache commons-math插值函数,例如SplineInterpolator

于 2015-06-25T15:42:03.853 回答