Интерполяция по массиву (или два) - PullRequest
8 голосов
/ 03 августа 2009

Я ищу библиотеку Java или некоторую помощь для написания собственной функции интерполяции. То есть у меня есть два массива двойников, которые потенциально разных размеров, но упорядочены. Мне нужно иметь возможность оценить промежуточные значения и вставить так, чтобы оба массива стали одинакового размера. Фактически, общее количество точек, появляющихся в интерполяции, является суммой двух размеров массива минус 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.

Ответы [ 8 ]

13 голосов
/ 03 августа 2009

Другие ответы дают вам линейные интерполяции - они на самом деле не работают для сложных, нелинейных данных. Вы хотите подгонку сплайна , (сплайн-интерполяция) Я полагаю.

Сплайн-аппроксимации описывают области данных с использованием набора контрольных точек из данных, затем применяют полиномиальную интерполяцию между контрольными точками. Больше контрольных точек дает вам более точное соответствие, а не более общее соответствие. Сплайны намного точнее, чем линейные, лучше использовать, чем обычное регрессионное соответствие, лучше, чем полином высокого порядка, потому что между контрольными точками ничего не получится.

Я не могу вспомнить имена в верхней части головы, но в Java есть несколько превосходно подходящих библиотек - я предлагаю вам искать одну, а не писать свою собственную функцию.


** РЕДАКТИРОВАТЬ: библиотеки, которые могут быть полезны: **

** Теория / код, который может быть полезен: **

  • Сплайн-апплеты с кодом: ссылка
  • Аркан фитинг сплайнов для ломаных линий к сплайнам Безье
  • Теория сплайнов и немного математики для подгонки. Если математика не поможет, может помочь больше математики, меньше кода.
2 голосов
/ 19 июля 2013

Я знаю, что это старый ответ, но это первый хит Google при поиске интерполяции Java. Принятый ответ содержит несколько полезных ссылок, но JMSL необходимо приобрести, и веб-сайт JSpline + выглядит схематично.

В Apache Commons Math реализованы линейные и сплайн-интерполяции, которые кажутся простыми, функциональными и заслуживающими доверия.

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

2 голосов
/ 27 октября 2011

Предназначен для массива данных 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
0 голосов
/ 25 июня 2015

вы можете использовать apache commons-math интерполяция функции , такие как SplineInterpolator

0 голосов
/ 11 января 2015

Будьте очень осторожны со сплайнами и полиномами. Эти два могут привести к бессмысленному поведению, которое может нарушить многие виды использования (что считается представлением) данных.

Все, что использует производные (наклоны) данных, может быть полностью уничтожено.

Лучшее, что вы можете сделать, это построить данные, понять, что они делают, и только потом подгонять (линейную, полиномиальную, лог-логическую) регрессию; После того, как вы это сделаете, вы должны нанести свое соответствие оригинальным данным и убедиться, что вы видите разумное согласие. Пропуск этого шага сравнения - очень плохая идея.

Некоторые наборы данных не подойдут для подгонки полиномов, log-log и т.д .; если ваши точки данных надлежащим образом распределены по диапазону данных, нет ничего плохого в кусочной интерполяции (линейной или полиномиальной и т. д.). Чтобы победить мертвую лошадь, если вы используете кусочную интерполяцию, избегайте всего, что использует производные / наклоны вашей кусочной интерполяции, потому что это будет иметь разрывы и приведет к плохому поведению.

0 голосов
/ 21 марта 2014

Облегченная версия линейного интерполятора с одномерным массивом:

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);
    }
}
0 голосов
/ 03 августа 2009

Вам необходимо получить значения x, соответствующие значениям y. В противном случае ни один алгоритм не сможет определить, является ли [1, 16, 81] x ^ 2 для [1, 4, 9] или x ^ 4 для [1, 2, 3]. Будете ли вы интерполировать шесть значений или нет?

И затем, когда вам даны значения x, вы можете использовать некоторую интерполяцию (линейный, кубический сплайн, назовите его) для аппроксимации пропущенных значений.

0 голосов
/ 03 августа 2009

Простая линейная интерполяция может быть рассчитана с использованием чего-то вроде:

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

Помогает ли это?

...