Différence entre R.loess et org.apache.commons.math LoessInterpolator
-
13-12-2019 - |
Question
J'essaie de calculer la conversion d'un script R en Java en utilisant le apache.commons.math bibliothèque.Puis-je utiliser org.apache.commons.math.analysis.interpolation.LoessInterpolator au lieu de R lœss ?Je n'arrive pas à obtenir le même résultat.
MODIFIER.
voici un programme Java qui crée un tableau aléatoire (x, y) et calcule le loess avec LoessInterpolator ou en appelant R.A la fin, les résultats sont imprimés.
import java.io.*;
import java.util.Random;
import org.apache.commons.math.analysis.interpolation.LoessInterpolator;
public class TestLoess
{
private String RScript="/usr/local/bin/Rscript";
private static class ConsummeInputStream
extends Thread
{
private InputStream in;
ConsummeInputStream(InputStream in)
{
this.in=in;
}
@Override
public void run()
{
try
{
int c;
while((c=this.in.read())!=-1)
System.err.print((char)c);
}
catch(IOException err)
{
err.printStackTrace();
}
}
}
TestLoess()
{
}
private void run() throws Exception
{
int num=100;
Random rand=new Random(0L);
double x[]=new double[num];
double y[]=new double[x.length];
for(int i=0;i< x.length;++i)
{
x[i]=rand.nextDouble()+(i>0?x[i-1]:0);
y[i]=Math.sin(i)*100;
}
LoessInterpolator loessInterpolator=new LoessInterpolator(
0.75,//bandwidth,
2//robustnessIters
);
double y2[]=loessInterpolator.smooth(x, y);
Process proc=Runtime.getRuntime().exec(
new String[]{RScript,"-"}
);
ConsummeInputStream errIn=new ConsummeInputStream(proc.getErrorStream());
BufferedReader stdin=new BufferedReader(new InputStreamReader(proc.getInputStream()));
PrintStream out=new PrintStream(proc.getOutputStream());
errIn.start();
out.print("T<-as.data.frame(matrix(c(");
for(int i=0;i< x.length;++i)
{
if(i>0) out.print(',');
out.print(x[i]+","+y[i]);
}
out.println("),ncol=2,byrow=TRUE))");
out.println("colnames(T)<-c('x','y')");
out.println("T2<-loess(y ~ x, T)");
out.println("write.table(residuals(T2),'',col.names= F,row.names=F,sep='\\t')");
out.flush();
out.close();
double y3[]=new double[x.length];
for(int i=0;i< y3.length;++i)
{
y3[i]=Double.parseDouble(stdin.readLine());
}
System.out.println("X\tY\tY.java\tY.R");
for(int i=0;i< y3.length;++i)
{
System.out.println(""+x[i]+"\t"+y[i]+"\t"+y2[i]+"\t"+y3[i]);
}
}
public static void main(String[] args)
throws Exception
{
new TestLoess().run();
}
}
compilation et exécution :
javac -cp commons-math-2.2.jar TestLoess.java && java -cp commons-math-2.2.jar:. TestLoess
sortir:
X Y Y.java Y.R
0.730967787376657 0.0 6.624884763714674 -12.5936186703287
0.9715042030481429 84.14709848078965 6.5263049649584 71.9725380029913
1.6089216283982513 90.92974268256818 6.269100654071115 79.839773167581
2.159358633515885 14.112000805986721 6.051308261720918 3.9270340708818
2.756903911313087 -75.68024953079282 5.818424835586378 -84.9176311089431
3.090122310789737 -95.89242746631385 5.689740879461759 -104.617807889069
3.4753114955304554 -27.941549819892586 5.541837854229562 -36.0902352062634
4.460153035730264 65.6986598718789 5.168028655980764 58.9472823439219
5.339335553602744 98.93582466233818 4.840314399516663 93.3329030534449
6.280584733084859 41.21184852417566 4.49531113985498 36.7282165788057
6.555538699120343 -54.40211108893698 4.395343460231256 -58.5812856445538
6.68443584999412 -99.99902065507035 4.348559404444451 -104.039069260889
6.831037507640638 -53.657291800043495 4.295400167908642 -57.5419313320511
6.854275630124528 42.016703682664094 4.286978656933373 38.1564179414478
7.401015387322993 99.06073556948704 4.089252482141094 95.7504087842369
8.365502247999844 65.02878401571168 3.7422883733498726 62.5865641279576
8.469992934250815 -28.790331666506532 3.704793544880599 -31.145867173504
9.095139297716374 -96.13974918795569 3.4805388562453574 -98.0047896609079
9.505935493207435 -75.09872467716761 3.3330472034239405 -76.6664588290508
les valeurs de sortie pour y ne sont clairement pas les mêmes entre R et Java ;La colonne Y.R a l'air bien (elle est proche de la colonne Y d'origine).Comment dois-je changer cela pour obtenir Y.java ~ Y.R ?
La solution
Vous devez modifier les valeurs par défaut de trois paramètres d'entrée pour rendre les versions Java et R identiques :
Le Java LoessInterpolator effectue uniquement une régression polynomiale locale linéaire, mais R prend en charge l'option linéaire (degré = 1), quadratique (degré = 2) et une étrange option degré = 0.Il faut donc préciser
degree=1
dans R pour être identique à Java.LoessInterpolator par défaut, nombre d'itérations
DEFAULT_ROBUSTNESS_ITERS=2
, mais R par défautiterations=4
.Vous devez donc définircontrol = loess.control(iterations=X)
dans R (X est le nombre d'itérations).Valeurs par défaut de LoessInterpolator
DEFAULT_BANDWIDTH=0.3
mais R par défautspan=0.75
.
Autres conseils
Je ne peux pas parler de la mise en œuvre Java, mais lowess
a un certain nombre de paramètres qui contrôlent la bande passante de l'ajustement.Sauf si vous vous ajustez avec les mêmes paramètres de contrôle, vous devez vous attendre à ce que les résultats diffèrent.Ma recommandation Chaque fois que les gens sont des données de lissage consiste à tracer les données d'origine ainsi qu'à l'ajustement et à déterminer vous-même quels paramètres de contrôle donnent votre compromis désiré entre la fidélité aux données et le détecteur de bruit).
Ici, nous avons deux problèmes.Premièrement, si vous tracez les données que vous générez, elles semblent presque aléatoires et l'ajustement généré par le loess dans R est très médiocre, par ex.
plot(T$x, T$y)
lines(T$s, T2$fitted, col="blue", lwd=3)
Ensuite, dans votre script R, vous écrivez les résidus et non les prédictions, donc dans cette ligne
out.println("write.table(residuals(T2),'',
col.names= F,row.names=F,sep='\\t')");
tu dois changer residuals(T2)
à predict(T2)
par exemple.
out.println("write.table(predict(T2),'',
col.names= F,row.names=F,sep='\\t')");
C'était donc un pur hasard dans votre exemple de code que les deux premières lignes de résidus générés par R semblaient bien correspondre.
Pour moi, si j'essaie d'adapter des données plus appropriées, Java et R renvoient des résultats similaires mais pas identiques.J'ai également trouvé que les résultats étaient plus proches si je n'ajustais pas la valeur par défaut robustesseIter paramètres.