Разница между R.loess и org.apache.commons.math LoessInterpolator
Я пытаюсь вычислить преобразование R script в java, используя библиотеку apache.commons.math. Могу ли я использовать org.apache.commons.math.analysis.interpolation.LoessInterpolator вместо R leess? Я не могу получить тот же результат.
ИЗМЕНИТЬ.
здесь представляет собой java-программу, которая создает случайный массив (x, y) и вычисляет лесс с помощью LoessInterpolator или вызовом R. В конце результаты печатаются.
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();
}
}
компиляция и exec:
javac -cp commons-math-2.2.jar TestLoess.java && java -cp commons-math-2.2.jar:. TestLoess
выход:
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
выходные значения для y явно не совпадают между R и Java; Столбец Y.R выглядит хорошо (он близок к исходной колонке Y). Как мне изменить это, чтобы получить Y.java ~ Y.R?
Ответы
Ответ 1
Вам нужно изменить значения по умолчанию для трех входных параметров, чтобы идентичные версии Java и R:
-
Java LoessInterpolator выполняет только линейную локальную полиномиальную регрессию, но R поддерживает линейную (градус = 1), квадратичную (степень = 2) и странную степень = 0. Поэтому вам нужно указать degree=1
в R, чтобы быть идентичным Java.
-
LoessInterpolator задает количество итераций DEFAULT_ROBUSTNESS_ITERS=2
, но R по умолчанию iterations=4
. Поэтому вам нужно установить control = loess.control(iterations=X)
в R (X - количество итераций).
-
Значение LoessInterpolator по умолчанию DEFAULT_BANDWIDTH=0.3
, но R по умолчанию span=0.75
.
Ответ 2
Я не могу говорить о реализации java, но lowess
имеет ряд параметров, которые управляют полосой пропускания. Если вы не используете одинаковые параметры управления, вы должны ожидать, что результаты будут отличаться. Моя рекомендация всякий раз, когда люди сглаживают данные, заключается в том, чтобы строить исходные данные, а также подгонку, и решать для себя, какие параметры управления дают желаемый компромисс между точностью и данными и сглаживанием (например, удаление шума).
Ответ 3
Здесь есть две проблемы. Во-первых, если вы создаете данные, которые вы генерируете, они выглядят почти случайными, а подгонка, создаваемая лёссой в R, очень плохая, например.
plot(T$x, T$y)
lines(T$s, T2$fitted, col="blue", lwd=3)
![plot of the data generated by the Java code above with a loess fit generated by R]()
Затем в вашем R script вы пишете остатки, а не прогнозы, поэтому в этой строке
out.println("write.table(residuals(T2),'',
col.names= F,row.names=F,sep='\\t')");
вам нужно изменить residuals(T2)
на predict(T2)
, например.
out.println("write.table(predict(T2),'',
col.names= F,row.names=F,sep='\\t')");
Таким образом, в вашем примере кода было чистой случайностью, что первые две строки остатков, сгенерированных R, выглядели хорошо.
Для меня, если я попытаюсь подобрать более подходящие данные, тогда Java и R вернут похожие, но не идентичные результаты. Также я обнаружил, что результаты были ближе, если я не настроил настройки robustnessIter по умолчанию.