Frage

Da sind meine Daten (x- und y-Spalten sind relevant):https://www.dropbox.com/s/b61a7enhoa0p57p/Simple1.csv

Ich muss die Daten an die Polylinie anpassen.Der Matlab-Code, der dies tut, ist:

spline_fit.m:
function [score, params] = spline_fit (points, x, y)

min_f = min(x)-1;
max_f = max(x);

points = [min_f points max_f];
params = zeros(length(points)-1, 2);

score = 0;
for i = 1:length(points)-1
    in = (x > points(i)) & (x <= points(i+1));
    if sum(in) > 2
        p = polyfit(x(in), y(in), 1);
        pred = p(1)*x(in) + p(2);
        score = score + norm(pred - y(in));
        params(i, :) = p;
    else
       params(i, :) = nan;
    end
end


test.m:
%Find the parameters
r = [100,250,400];
p = fminsearch('spline_fit', r, [], x, y)
[score, param] = spline_fit(p, x, y)

%Plot the result
y1 = zeros(size(x));
p1 = [-inf, p, inf];
for i = 1:size(param, 1)
    in = (x > p1(i)) & (x <= p1(i+1));
    y1(in) = x(in)*param(i,1) + param(i,2);
end

[x1, I] = sort(x);
y1 = y1(I);

plot(x,y,'x',x1,y1,'k','LineWidth', 2)

Und das funktioniert gut und führt zu folgender Optimierung:[102.9842, 191.0006, 421.9912]

Ich habe die gleiche Idee in R umgesetzt:

library(pracma);
spline_fit <- function(x, xx, yy) {

  min_f = min(xx)-1;
  max_f = max(xx);

  points = c(min_f, x, max_f)
  params = array(0, c(length(points)-1, 2));

  score = 0;
  for( i in 1:length(points)-1)
  {
    inn <- (xx > points[i]) & (xx <= points[i+1]);
    if (sum(inn) > 2)
    {
      p <- polyfit(xx[inn], yy[inn], 1);
      pred <- p[1]*xx[inn] + p[2];
      score <- score + norm(as.matrix(pred - yy[inn]),"F");
      params[i,] <- p;
    }
    else
      params[i,] <- NA;
  }  
  score
}

Aber ich bekomme sehr schlechte Ergebnisse:

> fminsearch(spline_fit,c(100,250,400), xx = Simple1$x, yy = Simple1$y)
$xval
[1] 100.1667 250.0000 400.0000

$fval
[1] 4452.761

$niter
[1] 2

Wie Sie sehen, stoppt es nach zwei Iterationen und bringt keine guten Punkte.

Ich würde mich sehr über jede Hilfe bei der Lösung dieses Problems freuen.

Wenn jemand weiß, wie man dies in C# mithilfe einer kostenlosen Bibliothek implementiert, wird es sogar noch besser.Ich weiß, wo ich Polyfit bekommen kann, aber nicht Fminsearch.

War es hilfreich?

Lösung

Das Problem hierbei ist, dass sich die Wahrscheinlichkeitsoberfläche sehr schlecht verhält – es gibt sowohl mehrere Minima als auch diskontinuierliche Sprünge –, wodurch die Ergebnisse, die Sie mit verschiedenen Optimierern erhalten, nahezu willkürlich werden.Ich gebe zu, dass die Optimierer von MATLAB bemerkenswert robust sind, aber ich würde sagen, dass es eher eine Frage des Zufalls ist (und wo man anfängt), ob ein Optimierer in diesem Fall das globale Minimum erreicht, es sei denn, man verwendet irgendeine Form der stochastischen globalen Optimierung wie zum Beispiel simuliertes Glühen.

Ich habe mich dafür entschieden, den integrierten Optimierer von R (der standardmäßig Nelder-Mead verwendet) zu verwenden fminsearch von dem pracma Paket.

spline_fit <- function(x, xx = Simple1$x, yy=Simple1$y) {

    min_f = min(xx)-1
    max_f = max(xx)

    points = c(min_f, x, max_f)
    params = array(0, c(length(points)-1, 2))

    score = 0
    for( i in 1:(length(points)-1))
    {
        inn <- (xx > points[i]) & (xx <= points[i+1]);
        if (sum(inn) > 2)
        {
            p <- polyfit(xx[inn], yy[inn], 1);
            pred <- p[1]*xx[inn] + p[2];
            score <- score + norm(as.matrix(pred - yy[inn]),"F");
            params[i,] <- p;
        }
        else
            params[i,] <- NA;
    }  
    score
}

library(pracma) ## for polyfit
Simple1 <- read.csv("Simple1.csv")
opt1 <- optim(fn=spline_fit,c(100,250,400), xx = Simple1$x, yy = Simple1$y)
## [1] 102.4365 201.5835 422.2503

Das ist besser als das fminsearch Ergebnisse, aber immer noch anders als die MATLAB-Ergebnisse und schlechter als diese:

## Matlab results:
matlab_fit <- c(102.9842, 191.0006, 421.9912)
spline_fit(matlab_fit, xx = Simple1$x, yy = Simple1$y)
## 3724.3
opt1$val
## 3755.5  (worse)

Der bbmle Das Paket bietet einen experimentellen/nicht sehr gut dokumentierten Satz von Werkzeugen zum Erkunden von Optimierungsoberflächen:

library(bbmle)
ss <- slice2D(fun=spline_fit,opt1$par,nt=51)
library(lattice)

Ein 2D-„Schnitt“ um das optim-geschätzte Parameter.Die Kreise zeigen die optimale Anpassung (durchgezogen) und den Minimalwert innerhalb jeder Schicht (offen).

png("splom1.png")
print(splom(ss))
dev.off()

enter image description here

Ein „Schnitt“ zwischen den Matlab- und Optim-Anpassungen zeigt, dass die Oberfläche ziemlich rau ist:

ss2 <- bbmle:::slicetrans(matlab_fit,opt1$par,spline_fit)
png("slice1.png")
print(plot(ss2))
dev.off()

enter image description here

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top