Интерполяция по массиву (или двум)

Я ищу 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.


person Robert    schedule 03.08.2009    source источник
comment
Ваш вопрос немного не ясен. Не могли бы вы привести банальный конкретный пример?   -  person skaffman    schedule 03.08.2009
comment
Я отредактировал, чтобы показать пример, хотя это не обязательно тот результат, который функция могла бы/должна дать, но я думаю, что он демонстрирует один приемлемый результат.   -  person Robert    schedule 03.08.2009


Ответы (8)


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

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

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


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

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

  • Апплеты сплайна с кодом: ссылка
  • Arkan сплайн, подгоняющий полилинии к сплайнам Безье
  • теория сплайнов и немного математики для подгонки. Больше математики, меньше кода может помочь, если библиотеки этого не сделают.
person BobMcGee    schedule 03.08.2009
comment
Да, это именно то, что мне нужно... точнее, что и где эти библиотеки. - person Robert; 03.08.2009
comment
Я добавил ссылки на некоторые библиотеки и код+теорию для работы со сплайнами, если в библиотеках их нет. Не забудьте принять ответ, если он вам полезен! - person BobMcGee; 03.08.2009

Предназначен для массива данных 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
person Golgauth    schedule 27.10.2011
comment
возвращает ноль. - person 3xCh1_23; 12.05.2017
comment
@3xCh1_23 последнее значение в массиве не должно быть нулевым - person Developer66; 17.07.2021

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

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

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

person Ian Will    schedule 19.07.2013

Простую линейную интерполяцию можно рассчитать, используя что-то вроде:

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

Это помогает?

person KitsuneYMG    schedule 03.08.2009

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

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

person Stroboskop    schedule 03.08.2009
comment
хорошо, я не продумал свой пример должным образом - предположим, что каждый индекс массива является значением x для ввода - тогда после интерполяции значение x больше не интересует нас. - person Robert; 03.08.2009

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

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);
    }
}
person Dmide    schedule 21.03.2014

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

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

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

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

person user192127    schedule 11.01.2015

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

person alex    schedule 25.06.2015
comment
Для этих целей также есть специальный LinerarInterpolator. - person Slava; 10.02.2016