我正在寻找一个java库或一些帮助来编写我自己的插值函数。那就是我有两个双打数组,这两个数组可能有不同的大小,但是是有序的。我需要能够估计中间值,并插入以使两个数组的大小相同。事实上,插值中出现的点总数是2个数组大小减1的总和。但是每个数组的范围必须保持不变,因此不需要外推。
例如。 a1 = [1,4,9,16,25,36]和a2 = [6,9,14,30]
结果可能是例如。
a1 = [1,2.25,5,6.25,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值很重要。
答案 0 :(得分:13)
其他答案为您提供线性插值 - 这些并不适用于复杂的非线性数据。 我想要spline fit,(样条插值)我相信。
样条拟合使用来自数据的一组控制点来描述数据的区域,然后在控制点之间应用多项式插值。更多的控制点可以让您更精确地贴合,而不是更适合您。样条曲线比线性拟合更精确,使用速度比一般回归拟合更快,优于高阶多项式,因为它不会在控制点之间做出疯狂的事情。
我不记得我头脑中的名字,但是Java中有一些非常好的拟合库 - 我建议你寻找一个而不是编写自己的函数。
**编辑:可能有用的库:**
**可能有用的理论/代码:**
答案 1 :(得分:2)
专为ONE Dimension数据阵列设计
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
答案 2 :(得分:2)
我知道这是一个陈旧的答案,但它是搜索Java插值时的第一个谷歌搜索。接受的答案提供了一些有用的链接,但必须购买JMSL,JSpline +网站看起来很粗略。
Apache Commons Math具有线性和样条插值的实现,看起来简单,实用且值得信赖。
答案 3 :(得分:0)
简单的线性插值可以使用类似的方法计算:
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);
}
这有帮助吗?
答案 4 :(得分:0)
您需要获取与y值对应的x值。否则,没有算法能够确定[1,16,81]对于[1,4,9]是否为x ^ 2或对于[1,2,3]是x ^ 4。你会插入六个值还是没有?
然后,当你给出x值时,你可以使用某种插值(线性,kubic样条,你给它命名)来近似缺失值。
答案 5 :(得分: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);
}
}
答案 6 :(得分:0)
对样条拟合和多项式拟合要非常小心。这两者可以提供荒谬的行为,可以破坏数据的许多用途(被认为是数据的代表)。
任何使用数据衍生(斜率)的东西都可以完全脱轨。
你能做的最好的事情是绘制数据,了解它做了什么,然后才适合(线性,多项式,对数 - 对数)回归;一旦你完成了这项工作,你就应该对原始数据进行拟合,并确保你看到合理的协议。跳过这个比较步骤是一个非常糟糕的主意。
某些数据集不会产生拟合多项式,log-log等。如果您的数据点在数据范围内适当分布,则分段插值(线性或多项式等)没有任何问题。要击败死马,如果你使用分段插值避免任何使用分段插值的导数/斜率的东西,因为它会产生不连续性并导致事情表现不佳。
答案 7 :(得分:0)