帮助写一个线性回归 - 页 5

 
Rosh писал (а)>>

而这是Excel 2007给出的结果



因此,可能有必要检查一下Matcad。

如果我没有理解错的话,Excel给出的是第三种结果,与前两种不同)。真相在哪里?B与Matcad相同,但系数A却不同。

 
Prival писал (а)>>

如果我没有理解错的话,Excel给出的是第三种结果,与前两种不同)。真相在哪里?B与Matcad中的相同,但系数A却不同。

一般来说,有这么多的有效数字和这么大的范围,计算会在尾数的后面某个地方进行。也就是说,即使是随机性的元素也可能被引入答案中。我认为只有在一些高精确度的特殊算法中才能期待正确性。在这种情况下,你最好把坐标的原点移近X范围



P.S. 特别是在计算X*X的总和时,这些信息就直接进入了厕所 :)

 
lna01 писал (а)>>

一般来说,有这么多的有效数字和这么大的范围,计算会在尾数的后面某个地方进行。也就是说,即使是随机性的元素也可以被引入到答案中。我认为正确性只能寄希望于一些特殊的算法,准确度提高。但在这种情况下,最好,将坐标的原点移到更靠近X范围。

问题是我已经开始为冠军赛做准备。我开始将我在Matkadec中的开发成果翻译成MQL。如果你还记得,我们正在建立ACF(自相关函数),我从它开始,决定使用直接公式,因为我通过傅里叶变换给CPU带来了太多的负担。

这就是为什么我开始分析问题开始增长的地方。

我将尝试把X(时间)转移到0。但我将不得不再次重新检查一切。我已经不得不放弃了大约50%的想法。

 
Prival писал (а)>>

问题是,我已经开始为冠军赛做准备。我开始将我在Matcadet的开发成果转移到MQL。如果你还记得,我们正在建立ACF(自相关函数),我从它开始,决定用直接公式计算,因为我正在用傅里叶变换大量加载处理器。

这就是为什么我开始分析问题开始增长的地方。

我将尝试把X(时间)转移到0。但我将不得不再次重新检查一切。现在,我已经不得不放弃了50%的想法。

MT在尾数上保留15位。如果我们提取根,我们得到10^7。也就是说,你必须对大于10000000的数字进行平方和,见上一篇文章的后记:)。幸运的是,这个限制与真实历史中的分钟条数相对应,所以如果是它,应该仍然可以工作。但如果是时间,那么坐标原点的转移就是不可避免的。


顺便说一下,如果你要在冠军赛上使用你的函数,请添加防止被零除的保护。否则,你的指标有可能只是站在冠军的中间。或在开始时。请记住,在傅里叶那里有这样的事情。

 

在Java中的相同算法

import java.util.ArrayList;

public class Prival {
public static void main(String arg[]){
int N = 6;
double Y[];
double X[];
ArrayList<Double> Parameters = new ArrayList<Double>();
Parameters.add(0.0);
Parameters.add(0.0);
X = new double[6];
Y = new double[6];
for ( int i = 0; i < N; i ++ )
{
// массивы Y и X для проверки работоспособности
// intercept = -3.33333333 slope = 5.00000000

X[i]=i;
Y[i]=i*i;
}

LinearRegr(X, Y, N,Parameters);
System.out.println("intercept = "+Parameters.get(0)+" slope = "+ Parameters.get(1));

// вторая проверка
X[0]=1216640160;
X[1]=1216640100;
X[2]=1216640040;
X[3]=1216639980;
X[4]=1216639920;
X[5]=1216639860;

Y[0]=1.9971;
Y[1]=1.9970;
Y[2]=1.9967;
Y[3]=1.9969;
Y[4]=1.9968;
Y[5]=1.9968;


LinearRegr(X, Y, N, Parameters);
System.out.println("intercept = "+Parameters.get(0)+" slope = "+ Parameters.get(1));

}
public static void LinearRegr(double X[], double Y[], int N, ArrayList<Double> Parameters){
double sumY = 0.0, sumX = 0.0, sumXY = 0.0, sumX2 = 0.0;
double A=0,B=0;
for ( int i = 0; i < N; i ++ ){
sumY +=Y[i];
sumXY +=X[i]*Y[i];
sumX +=X[i];
sumX2 +=X[i]*X[i];
}
B=(sumXY*N-sumX*sumY)/(sumX2*N-sumX*sumX);
A=(sumY-sumX*B)/N;
Parameters.set(0, A);
Parameters.set(1, B);
}
}


结果。


截距=-3.333333333335 斜率=5.0
截距=-1102.169141076954 斜率=9.075536028198574E-7

进程结束,退出代码为0

 

罗什

我同意这些公式将给出相同的结果,这里是matcad

我看到结果与MQL和Java相吻合,但matcad以前从未让我失望过,所以我有疑虑。我已经检查过了,并对结果进行了分类。

我检查了一下,并按X 进行了排序,又计算了系数。

结果已经改变了!!!这不应该是这样的。最有可能的是由于对大数字进行平方运算而导致的误差积累(Candid 是正确的)。我调查了文献,发现了一个更简单的公式,没有平方,似乎计算量更少。

其结果与matcad中一样,而且不依赖于排序。

我建议使用这个公式来计算线性回归系数。

//+------------------------------------------------------------------+
//|                                                       LinReg.mq4 |
//|                                                    Привалов С.В. |
//|                                             Skype -> privalov-sv |
//+------------------------------------------------------------------+
#property copyright "Привалов С.В."
#property link      "Skype -> privalov-sv"

//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----
   int      N=6;                 // Размер массива
   double   Y[],X[],A=0.0, B=0.0;
   
  ArrayResize(X,N);
  ArrayResize(Y,N);
      
// проверка 
    X[0]=1216640160;
    X[1]=1216640100;
    X[2]=1216640040;
    X[3]=1216639980;
    X[4]=1216639920;
    X[5]=1216639860;
    
    Y[0]=1.9971;
    Y[1]=1.9970;    
    Y[2]=1.9967;
    Y[3]=1.9969;    
    Y[4]=1.9968;    
    Y[5]=1.9968;
    
    
  LinearRegr(X, Y, N, A, B);
  
  Print("A = ", DoubleToStr(A,8)," B = ",DoubleToStr(B,8));
           
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Рассчет коэффициентов A и B в уравнении                          |
//| y(x)=A*x+B                                                       |
//| используються формулы https://forum.mql4.com/ru/10780/page5       |
//+------------------------------------------------------------------+

void LinearRegr(double X[], double Y[], int N, double& A, double& B)
{
      double mo_X = 0.0, mo_Y = 0.0, var_0 = 0.0, var_1 = 0.0;
      
    for ( int i = 0; i < N; i ++ )
      {
        mo_X +=X[i];
        mo_Y +=Y[i];
      }
    mo_X /=N;
    mo_Y /=N;
        
    for ( i = 0; i < N; i ++ )
      {
        var_0 +=(X[i]-mo_X)*(Y[i]-mo_Y);
        var_1 +=(X[i]-mo_X)*(X[i]-mo_X);
      }
        A = var_0 / var_1;
        B = mo_Y - A * mo_X;
}

附上脚本,如果有人能清理一下LinearRegr(以防止在处理真实数据时出错,并提高性能),那就太好了。我把AB 互换了,因为

符号y(x)=a*x+b 更加熟悉(对我来说是来自书本)。

附加的文件:
linreg_1.mq4  2 kb
 

我不明白结果怎么会取决于排序。在公式的任何地方都没有明确使用排序。


此外,后者的算法使用X和Y的期望值,有可能也会在计算中引入错误。还有一点:用两个循环对付一个循环,不太可能提高性能。


如果我们需要对一些价格序列进行大规模的线性回归计算,最好是在一个指标中选择单独的缓冲区,并使用累积总数法进行计算。它可以使计算速度加快几个 数量级。例子 -考夫曼AMA优化:佩里-考夫曼AMA优化

 
Rosh писал (а)>>

我不明白结果怎么会取决于排序。在公式的任何地方都没有明确使用排序。


此外,最后一种算法使用了X和Y值的期望值,也有可能在计算中引入一些误差。还有一件事:用两个循环对抗一个循环,很难提高性能。

如果我们需要对一些价格序列进行线性回归的批量计算,最好在一个指标中选择单独的缓冲区,并使用累积累加方法。它可以使计算速度加快几个 数量级。例子 -考夫曼AMA优化:佩里-考夫曼AMA优化

1.问题是,结果不应该取决于排序,而算法却取决于排序。看看吧。

//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----
   int      N=6;                 // Размер массива
   double   Y[],X[],Y1[],X1[],A=0.0, B=0.0;
   
  ArrayResize(X,N);
  ArrayResize(Y,N);
  ArrayResize(X1,N);
  ArrayResize(Y1,N);
      
// проверка 
    X[0]=1216640160;
    X[1]=1216640100;
    X[2]=1216640040;
    X[3]=1216639980;
    X[4]=1216639920;
    X[5]=1216639860;
    
    Y[0]=1.9971;
    Y[1]=1.9970;    
    Y[2]=1.9967;
    Y[3]=1.9969;    
    Y[4]=1.9968;    
    Y[5]=1.9968;
    

// отсортируем массив по возрастанию X (исходный массив был по убыванию)
  for (int i = 0; i < N; i++)
   {
   X1[i]=X[N-i-1];
   Y1[i]=Y[N-i-1];
//   Print(X[i], " ", X1[i], " ", Y[i], " ", Y1[i]);
   }            
//----
// 
  LinearRegr(X, Y, N, A, B);
  Print("A = ", DoubleToStr(A,8)," B = ",DoubleToStr(B,8));
  LinearRegr(X1, Y1, N, A, B);
  Print(" A = ", DoubleToStr(A,8)," B = ",DoubleToStr(B,8));

  LinearRegr1(X, Y, N, A, B);
  Print("A = ", DoubleToStr(A,8)," B = ",DoubleToStr(B,8));
  LinearRegr1(X1, Y1, N, A, B);
  Print(" A = ", DoubleToStr(A,8)," B = ",DoubleToStr(B,8));

   return(0);
  }

//-------------------------------------------------------------------------------
// использование этой формулы приводит к ошибкам если X=Time
// формула предложена вот тут https://forum.mql4.com/ru/10780/page4
//| y(x)=A+B*x  

void LinearRegr(double X[], double Y[], int N, double& A, double& B)
{
      double sumY = 0.0, sumX = 0.0, sumXY = 0.0, sumX2 = 0.0;
      
    for ( int i = 0; i < N; i ++ )
    {
        sumY   +=Y[i];
        sumXY  +=X[i]*Y[i];
        sumX   +=X[i];
        sumX2  +=X[i]*X[i];
    }
   B=(sumXY*N-sumX*sumY)/(sumX2*N-sumX*sumX);
   A=(sumY-sumX*B)/N;
}

//+------------------------------------------------------------------+
//| Формула предлагаемая мной                                        |
//| Рассчет коэффициентов A и B в уравнении                          |
//| y(x)=A*x+B                                                       |
//| используються формулы https://forum.mql4.com/ru/10780/page5       |
//+------------------------------------------------------------------+

void LinearRegr1(double X[], double Y[], int N, double& A, double& B)
{
      double mo_X = 0.0, mo_Y = 0.0, var_0 = 0.0, var_1 = 0.0;
      
    for ( int i = 0; i < N; i ++ )
      {
        mo_X +=X[i];
        mo_Y +=Y[i];
      }
    mo_X /=N;
    mo_Y /=N;
        
    for ( i = 0; i < N; i ++ )
      {
        var_0 +=(X[i]-mo_X)*(Y[i]-mo_Y);
        var_1 +=(X[i]-mo_X)*(X[i]-mo_X);
      }
        A = var_0 / var_1;
        B = mo_Y - A * mo_X;
}

其结果是

2008.07.30 13:51:08 LinReg EURUSD,M1:A= 0.00000090B= -1098.77264952

2008.07.30 13:51:08 LinReg EURUSD,M1: A = 0.00000090 B = -1098.77264952

2008.07.30 13:51:08 LinReg EURUSD,M1: A = -1078.77267965 B = 0.00000089

2008.07.30 13:51:08 LinReg EURUSD,M1: A = -1102.16914108 B = 0.00000091

情况不应该是这样的。

我可以看到出现了两个循环,这就是为什么我要求更快的性能。回归:是什么?" 算法可能更快,但我们也应该优化它(我认为Vinin 已经做到了)。

3.谢谢考夫曼,这是个好指标。如果你还没有忘记,在第二个冠军赛之前,我就在捕捉其中的不准确之处。谢谢你对他们的纠正。

Z.U. 我问谁有数学。 输入这些数组并计算内置公式(据我记得,有),并将结果发布在这里。为了达成共识。谢谢你。帮助))。罗什是相当难以说服的,但我也有一个军人的额头 ))

 
Prival писал (а)>>

2.我可以看到有两个循环出现,这就是我要求加速的原因。回归:是什么?" 算法可能更快,但我们也应该优化它(我认为Vinin 已经做到了)。

LWMA确实比X*X更安全,所以你在Mathemat 的工作有了新的意义:)。但我仍然认为我的第一个建议(转移坐标的原点)是最好的选择。用Time[pos]-Time[Bars-1]正式替换各地的Time[pos]是否有这样的错误风险?

 
Prival писал (а)>>

1.这就是问题所在:结果不应该取决于排序,但在该算法中却取决于排序。看看吧。

结果

2008.07.30 13:51:08 LinReg EURUSD,M1:A= 0.00000090B= -1098.77264952

2008.07.30 13:51:08 LinReg EURUSD,M1: A = 0.00000090 B = -1098.77264952

2008.07.30 13:51:08 LinReg EURUSD,M1: A = -1078.77267965 B = 0.00000089

2008.07.30 13:51:08 LinReg EURUSD,M1: A = -1102.16914108 B = 0.00000091

情况不应该是这样的。



在你的代码中插入ristrintokwa。

//-------------------------------------------------------------------------------
// использование этой формулы приводит к ошибкам если X=Time
// формула предложена вот тут https://forum.mql4.com/ru/10780/page4
//| y(x)=A+B*x  
 
void LinearRegr(double X[], double Y[], int N, double& A, double& B)
{
      double sumY = 0.0, sumX = 0.0, sumXY = 0.0, sumX2 = 0.0;
      
    for ( int i = 0; i < N; i ++ )
    {
        sumY   +=Y[i];
        sumXY  +=X[i]*Y[i];
        sumX   +=X[i];
        sumX2  +=X[i]*X[i];
    }
   Print("sumY = ",DoubleToStr(sumY,8)," sumX = ",DoubleToStr(sumX,8)," sumXY = ",DoubleToStr(sumXY,8)," sumX2 = ",DoubleToStr(sumX2,8));
   Print("sumXY*dN-sumX*sumY = ",DoubleToStr(sumXY*dN-sumX*sumY,8));    
   Print("sumX2*dN-sumX*sumX = ",DoubleToStr(sumX2*dN-sumX*sumX,8));    
 
   B=(sumXY*N-sumX*sumY)/(sumX2*N-sumX*sumX);
   A=(sumY-sumX*B)/N;
}

得到这样的东西。

首次通话
sumY = 11.98130000 sumX = 7299840060.00000000 sumXY = 14576928951.87000100 sumX2 = 8881277483596863500.00000000
sumXY*dN-sumX*sumY = 0.34199524
sumX2*dN-sumX*sumX=376832.00000000
a = -1102.16914108 b = 0.00000091
第二次通话
sumY = 11.98130000 sumX = 7299840060.00000000 sumXY = 14576928951.87000300 sumX2 = 8881277483596864500.00000000
sumXY*dN-sumX*sumY = 0.34202576
sumX2*dN-sumX*sumX=385024.00000000
a = -1078.77267965 b = 0.00000089

这是计算机计算和四舍五入的另一个隐患。一方面,我自己没有想到会有这样的收获,但另一方面,当两个系列的值(X和Y)在价值顺序上有太大的差异时,这样的差异是可以理解的。

原因: