数组插值(或两个)

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

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

结果可能是例如。

a1 = [1,2.25,5,2.65,9,12.25,16,25,36]和a2 = [6,6.5625,7.25,9,10.2625,11.25,14,25.25,30]

这些例子是f(x) = x^2 and g(x) = x^2 + 5 ,但是很容易就是任何多项式 – 这一点是能够从数据集中很好地估计/近似函数来提供足够的插值。 这里的x值只是输入数组的索引。 在输出中,只有y值很重要。

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

样条拟合使用来自数据的一组控制点描述数据的区域,然后在控制点之间应用多项式插值。 更多的控制点可以让您更精确地贴合,而不是更适合您。 样条比线性拟合精确得多,使用比一般回归拟合更快,优于高阶多项式,因为它不会在控制点之间做出疯狂的事情。

我无法记住我的头脑中的名字,但是Java中有一些非常好的拟合库 – 我建议你寻找一个而不是编写自己的函数。


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

  • JMSL
  • JSpline +
  • 屈服图书馆 (希望你能读懂德文)

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

  • 样条小程序包含代码: link
  • Arkan样条拟合多线到贝塞尔样条
  • 样条理论和一些拟合数学。 如果图书馆没有,更多的数学,更少的代码可能会有所帮助。

专为ONE Dimension数据arrays而设计

 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 non_null_idx = new ArrayList(); ArrayList steps = new ArrayList(); int step_cnt = 0; for (int i=0; i> " + 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 

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

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

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

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

 Point2D interp1_lin(Point2D p1, Point2D p2, double x) { //Pre conditions assert p1.x 

这有帮助吗?

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

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

轻量版的一维arrays线性插值器:

 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); } } 

对样条拟合和多项式拟合要非常小心。 这两者可以给出荒谬的行为,这些行为可以破坏数据的许多用途(被认为是数据的代表)。

任何使用数据衍生物(斜率)的东西都可以完全脱轨。

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

某些数据集不会产生多项式,log-log等的拟合。 如果您的数据点在数据范围内适当分布,则分段插值(线性或多项式等)没有任何问题。 要击败死马,如果使用分段插值,请避免使用分段插值的导数/斜率,因为它会产生不连续性并导致事情表现不佳。

你可以使用apache commons-math插值函数 ,比如SplineInterpolator