Использовать метод Math.NET Fit.Polynomial для функций с несколькими параметрами

Я ранее использовал библиотеку Math.NET Numerics Fit.Polynomial, чтобы поместить кубический многочлен на набор данных, который можно было бы моделировать как функцию одного параметра y=f(x).
Теперь я хотел бы также найти многочлен 2 или 3 порядка, который подходит для данных, которые могут быть смоделированы как функция, зависящая от нескольких параметров y=f(x1, x2, x3, x4).

Есть ли уже встроенная функция в Math.NET, которая может вычислить этот многочлен?
Если нет, вы видите, как я могу манипулировать моими данными, чтобы отправить их в Fit.Polynomial?

Ответ 1

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

Fit.Polynomial: Подгонка полиномиальных кривых с высокими порядками немного проблематична, поэтому были разработаны специализированные алгоритмы и подпрограммы для настройки/уточнения параметров в конце. Однако Math.NET Numerics просто использует QR-декомпозицию (хотя в какой-то момент планируется замена реализации):

public static double[] Polynomial(double[] x, double[] y, int order)
{
    var design = Matrix<double>.Build.Dense(x.Length, order + 1, (i, j) => Math.Pow(x[i], j));
    return MultipleRegression.QR(design, Vector<double>.Build.Dense(y)).ToArray();
}

Fit.MultiDim, с другой стороны, использует нормальные уравнения по умолчанию, что намного быстрее, но менее численно устойчиво, чем QR-разложение. Вот почему вы видели уменьшенную точность с помощью этого метода.

public static double[] MultiDim(double[][] x, double[] y)
{
    return MultipleRegression.NormalEquations(x, y);
}

В вашем случае я бы попытался использовать класс MultipleRegression напрямую, либо с QR (если это достаточно хорошо), либо Svd (если требуется еще большая надежность, гораздо медленнее (подумайте о том, чтобы использовать собственный провайдер if слишком медленно)):

var x1 = new double[] { ... };
var x2 = new double[] { ... };
var y = new double[] { ... };

var design = Matrix<double>.Build.DenseOfRowArrays(
    Generate.Map2(x1,x2,(x1, x2) => new double[] { x1*x1, x1, x2*x2, x2, 1d }));
double[] p = MultipleRegression.QR(design, Vector<double>.Build.Dense(y)).ToArray();

(Использование Math.NET Numerics v3.0.0-alpha7)

Ответ 2

RosettaCode предлагает это решение для полиномиальной регрессии (используя Math. Net):

    public static double[] Polyfit(double[] x, double[] y, int degree)
    {
        // Vandermonde matrix
        var v = new DenseMatrix(x.Length, degree + 1);
        for (int i = 0; i < v.RowCount; i++)
            for (int j = 0; j <= degree; j++) v[i, j] = Math.Pow(x[i], j);
        var yv = new DenseVector(y).ToColumnMatrix();
        QR qr = v.QR();
        // Math.Net doesn't have an "economy" QR, so:
        // cut R short to square upper triangle, then recompute Q
        var r = qr.R.SubMatrix(0, degree + 1, 0, degree + 1);
        var q = v.Multiply(r.Inverse());
        var p = r.Inverse().Multiply(q.TransposeThisAndMultiply(yv));
        return p.Column(0).ToArray();
    }

Ответ 3

Обратите внимание, что x в линейной модели также может быть вектором x = [x1 x2 ⋯ xk], а произвольные функции fi (x) может принимать векторы вместо скаляров.
Здесь что-то почти о том, что вы хотите.