Обсуждение статьи "Статистические распределения в MQL5 - берем лучшее из R и делаем быстрее" - страница 20

 
Denis Kirichenko #:

В той же Википедии есть такое:

Т.е. берутся две случайные величины, где первая из нецентрального хи-квадрат распределения, а вторая - из центрального. Наверное код можно исправить на такой:

//--- generate random number using Noncentral ChiSquare
double chi1=MathRandomNoncentralChiSquare(a2,lambda2,error_code);
double chi2=MathRandomChiSquare(b2,error_code);
result[i]=chi1/(chi1+chi2);

Изменённые графики в примере будут ниже.

Спасибо, Вы правы, нужно считать через эту формулу, однако там была еще другая ошибка, параметр нецентральности lambda нужно без множителя 2.

//+------------------------------------------------------------------+
//| Random variate from the Noncentral Beta distribution             |
//+------------------------------------------------------------------+
//| Compute the random variable from the Noncentral Beta             |
//| distribution with parameters a,b and lambda.                     |
//|                                                                  |
//| Arguments:                                                       |
//| a           : First shape parameter                              |
//| b           : Second shape parameter                             |
//| lambda      : Noncentrality parameter                            |
//| error_code  : Variable for error code                            |
//|                                                                  |
//| Return value:                                                    |
//| The random value with Noncentral Beta distribution.              |
//+------------------------------------------------------------------+
double MathRandomNoncentralBeta(const double a,const double b,const double lambda,int &error_code)
  {
//--- if lambda==0, return beta random variate
   if(lambda==0.0)
      return MathRandomBeta(a,b,error_code);
//--- check parameters
   if(!MathIsValidNumber(a) || !MathIsValidNumber(b) || !MathIsValidNumber(lambda))
     {
      error_code=ERR_ARGUMENTS_NAN;
      return QNaN;
     }
//--- a,b,lambda must be positive
   if(a<=0.0 || b<=0.0 || lambda<0)
     {
      error_code=ERR_ARGUMENTS_INVALID;
      return QNaN;
     }

   error_code=ERR_OK;
//--- generate random number using Noncentral ChiSquare
   double chi1=MathRandomNoncentralChiSquare(2*a,lambda,error_code);
   double chi2=MathRandomChiSquare(2*b,error_code);
   return chi1/(chi1+chi2);
  }
//+------------------------------------------------------------------+
//| Random variate from the Noncentral Beta distribution             |
//+------------------------------------------------------------------+
//| Generates random variables from the Noncentral Beta distribution |
//| with parameters a,b, lambda.                                     |
//|                                                                  |
//| Arguments:                                                       |
//| a          : First shape parameter                               |
//| b          : Second shape parameter                              |
//| lambda     : Noncentrality parameter                             |
//| data_count : Number of values needed                             |
//| result     : Output array with random values                     |
//|                                                                  |
//| Return value:                                                    |
//| true if successful, otherwise false.                             |
//+------------------------------------------------------------------+
bool MathRandomNoncentralBeta(const double a,const double b,const double lambda,const int data_count,double &result[])
  {
//--- if lambda==0, return beta random variate
   if(lambda==0.0)
      return MathRandomBeta(a,b,data_count,result);
//--- check parameters
   if(!MathIsValidNumber(a) || !MathIsValidNumber(b) || !MathIsValidNumber(lambda))
      return false;
//--- a,b,lambda must be positive
   if(a<=0.0 || b<=0.0 || lambda<0)
      return false;

   int error_code=0;
//--- prepare output array and calculate random values
   ArrayResize(result,data_count);
   double a2=a*2;
   double b2=b*2;
   for(int i=0; i<data_count; i++)
     {
      //--- generate random number using Noncentral ChiSquare
      double chi1=MathRandomNoncentralChiSquare(a2,lambda,error_code);
      double chi2=MathRandomChiSquare(b2,error_code);
      result[i]=chi1/(chi1+chi2);
     }
   return true;
  }

Тестовый скрипт:

//+------------------------------------------------------------------+
//|                                           TestNoncentralBeta.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <Graphics\Graphic.mqh>
#include <Math\Stat\NoncentralBeta.mqh>
#include <Math\Stat\Math.mqh>
#property script_show_inputs
//--- input parameters
input double a_par=2;    // первый параметр бета-распределения (shape1)
input double b_par=5;    // второй параметр бета-распределения (shape2)
input double l_par=1;    // параметр нецентральности (lambda)
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- отключим показ ценового графика
   ChartSetInteger(0,CHART_SHOW,false);
//--- инициализируем генератор случайных чисел  
   MathSrand(GetTickCount());
//--- сгенерируем выборку случайной величины
   long chart=0;
   string name="GraphicNormal";
   int n=1000000;       // количество значений в выборке
   int ncells=52;       // количество интервалов в гистограмме
   double x[];          // центры интервалов гистограммы
   double y[];          // количество значений из выборки, попавших в интервал
   double data[];       // выборка случайных значений 
   double max,min;      // максимальное и минимальное значения в выборке
//--- получим выборку из нецентрального бета-распределения 
   MathRandomNoncentralBeta(a_par,b_par,l_par,n,data);
//--- рассчитаем данные для построения гистограммы
   CalculateHistogramArray(data,x,y,max,min,ncells);
//--- получим границы последовательности и шаг для построения теоретической кривой
   double step;
   GetMaxMinStepValues(max,min,step);
   step=MathMin(step,(max-min)/ncells);
//--- получим теоретически рассчитанные данные на интервале [min,max]
   double x2[];
   double y2[];
   MathSequence(min,max,step,x2);
   MathProbabilityDensityNoncentralBeta(x2,a_par,b_par,l_par,false,y2);
//--- масштабируем
   double theor_max=y2[ArrayMaximum(y2)];
   double sample_max=y[ArrayMaximum(y)];
   double k=sample_max/theor_max;
   for(int i=0; i<ncells; i++)
      y[i]/=k;
//--- выводим графики
   CGraphic graphic;
   if(ObjectFind(chart,name)<0)
      graphic.Create(chart,name,0,0,0,780,380);
   else
      graphic.Attach(chart,name);
   graphic.BackgroundMain(StringFormat("Noncentral Beta distribution alpha=%G beta=%G lambda=%G",
                          a_par,b_par,l_par));
   graphic.BackgroundMainSize(16);
//--- plot all curves
   graphic.CurveAdd(x,y,CURVE_HISTOGRAM,"Sample").HistogramWidth(6);
//--- а теперь построим теоретическую кривую плотности распределения 
   graphic.CurveAdd(x2,y2,CURVE_LINES,"Theory");
   graphic.CurvePlotAll();
//--- plot all curves
   graphic.Update();
   
   DebugBreak();
  }
//+------------------------------------------------------------------+
//|  Calculate frequencies for data set                              |
//+------------------------------------------------------------------+
bool CalculateHistogramArray(const double &data[],double &intervals[],double &frequency[],
                             double &maxv,double &minv,const int cells=10)
  {
   if(cells<=1) return (false);
   int size=ArraySize(data);
   if(size<cells*10) return (false);
   minv=data[ArrayMinimum(data)];
   maxv=data[ArrayMaximum(data)];
   double range=maxv-minv;
   double width=range/cells;
   if(width==0) return false;
   ArrayResize(intervals,cells);
   ArrayResize(frequency,cells);
//--- зададим центры интервалов
   for(int i=0; i<cells; i++)
     {
      intervals[i]=minv+(i+0.5)*width;
      frequency[i]=0;
     }
//--- заполним частоты попадания в интервал
   for(int i=0; i<size; i++)
     {
      int ind=int((data[i]-minv)/width);
      if(ind>=cells) ind=cells-1;
      frequency[ind]++;
     }
   return (true);
  }
//+------------------------------------------------------------------+
//|  Calculates values for sequence generation                       |
//+------------------------------------------------------------------+
void GetMaxMinStepValues(double &maxv,double &minv,double &stepv)
  {
//--- вычислим абсолютный размах последовательности, чтобы получить точность нормализации
   double range=MathAbs(maxv-minv);
   int degree=(int)MathRound(MathLog10(range));
//--- нормализуем макс. и мин. значения с заданной точностью
   maxv=NormalizeDouble(maxv,degree);
   minv=NormalizeDouble(minv,degree);
//--- шаг генерации последовательности также зададим от заданной точности
   stepv=NormalizeDouble(MathPow(10,-degree),degree);
   if((maxv-minv)/stepv<10)
      stepv/=10.;
  }

Результат:

NoncentralBeta(2,5,1)

NoncentralBeta(2,5,10)

NoncentralBeta(2,15,100)

NoncentralBeta(2,15,20)

Файлы:
 

Проверил ещё функцию CFD для Noncentral Beta Distribution.

#include <Math\Stat\NoncentralBeta.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   matrix nc_beta_params_mx =
     {
      // A B LAMBDA X
        {5, 5, 54, 0.864},
        {5, 5, 140, 0.9},
        {5, 5, 170, 0.956},
        {10, 10, 54, 0.8686},
        {10, 10, 140, 0.9},
        {10, 10, 250, 0.9},
        {20, 20, 54, 0.8787},
        {20, 20, 140, 0.9},
        {20, 20, 250, 0.922},
        {10, 20, 150, 0.868},
        {10, 10, 120, 0.9},
        {15, 5, 80, 0.88},
        {20, 10, 110, 0.85},
        {20, 30, 65, 0.66},
        {20, 50, 130, 0.72},
        {30, 20, 80, 0.72},
        {30, 40, 130, 0.8},
        {10, 5, 20, 0.644},
        {10, 10, 54, 0.7},
        {10, 30, 80, 0.78},
        {15, 20, 120, 0.76},
        {10, 5, 55, 0.795},
        {12, 17, 64, 0.56},
        {30, 30, 140, 0.8},
        {35, 30, 20, 0.67}
     };
// print
   PrintFormat("A - B - LAMBDA - X - CDF");
   for(ulong row = 0; row < nc_beta_params_mx.Rows(); row++)
     {
      double a_par, b_par, l_par, x_val;
      a_par = nc_beta_params_mx[row][0];
      b_par = nc_beta_params_mx[row][1];
      l_par = nc_beta_params_mx[row][2];
      x_val = nc_beta_params_mx[row][3];
      int error_code;
      double res_val = MathCumulativeDistributionNoncentralBeta(x_val, a_par,
                       b_par, l_par, error_code);
      ::PrintFormat("%0.0f, %0.0f, %0.0f, %0.2f -->  %0.5f",
                    a_par, b_par, l_par, x_val, res_val);
     }
  }


Какие-то сомнительные результаты:

A - B - LAMBDA - X - CDF
5, 5, 54, 0.86 -->  0.74058
5, 5, 140, 0.90 -->  0.40096
5, 5, 170, 0.96 -->  1.00000
10, 10, 54, 0.87 -->  1.00000
10, 10, 140, 0.90 -->  0.99296
10, 10, 250, 0.90 -->  1.00000
20, 20, 54, 0.88 -->  1.00000
20, 20, 140, 0.90 -->  1.00000
20, 20, 250, 0.92 -->  1.00000
10, 20, 150, 0.87 -->  1.00000
10, 10, 120, 0.90 -->  1.00000
15, 5, 80, 0.88 -->  1.00000
20, 10, 110, 0.85 -->  1.00000
20, 30, 65, 0.66 -->  1.00000
20, 50, 130, 0.72 -->  1.00000
30, 20, 80, 0.72 -->  1.00000
30, 40, 130, 0.80 -->  1.00000
10, 5, 20, 0.64 -->  0.05069
10, 10, 54, 0.70 -->  0.18781
10, 30, 80, 0.78 -->  1.00000
15, 20, 120, 0.76 -->  1.00000
10, 5, 55, 0.80 -->  0.13001
12, 17, 64, 0.56 -->  0.00231
30, 30, 140, 0.80 -->  1.00000
35, 30, 20, 0.67 -->  0.88671


В альтернативных источниках используется алгоритм ASA310:

23 July 2024 05:23:28 PM

ASA310_PRB:
  C++ version
  Test the ASA310 library.

TEST01:
  NCBETA computes the noncentral incomplete Beta function.
  Compare to tabulated values.

      A        B     LAMBDA        X          FX                        FX2
                                              (Tabulated)               (NCBETA)            DIFF

        5        5       54       0.864                 0.4563021        0.4563022483390367   1.483e-07
        5        5      140         0.9                 0.1041337        0.1041334790875982   2.209e-07
        5        5      170       0.956                 0.6022353        0.6022418158548807   6.516e-06
       10       10       54      0.8686                  0.918777        0.9187759254330974   1.075e-06
       10       10      140         0.9                 0.6008106        0.6008067894096832   3.811e-06
       10       10      250         0.9                  0.090285        0.0902898993260559   4.899e-06
       20       20       54      0.8787                 0.9998655        0.9998614048611703   4.095e-06
       20       20      140         0.9                 0.9925997        0.9925954777347362   4.222e-06
       20       20      250       0.922        0.9641111999999999        0.9641179545701509   6.755e-06
       10       20      150       0.868              0.9376626573        0.9376626555219731   1.778e-09
       10       10      120         0.9              0.7306817858         0.730681784479193   1.321e-09
       15        5       80        0.88              0.1604256918        0.1604256916919781    1.08e-10
       20       10      110        0.85              0.1867485313         0.186748530948068   3.519e-10
       20       30       65        0.66        0.6559386874000001        0.6559386873992288   7.713e-13
       20       50      130        0.72              0.9796881486        0.9796881474202076    1.18e-09
       30       20       80        0.72              0.1162386423        0.1162386421523797   1.476e-10
       30       40      130         0.8              0.9930430054        0.9930430042307262   1.169e-09
       10        5       20       0.644              0.0506899273       0.05068987981355273   4.749e-08
       10       10       54         0.7              0.1030959706        0.1030959706112684   1.127e-11
       10       30       80        0.78        0.9978417832000001        0.9978417830424838   1.575e-10
       15       20      120        0.76              0.2555552369        0.2555552355854933   1.315e-09
       10        5       55       0.795              0.0668307064        0.0668307064085136   8.514e-12
       12       17       64        0.56              0.0113601067       0.01136010666591296   3.409e-11
       30       30      140         0.8              0.7813366615        0.7813366591185901   2.381e-09
       35       30       20        0.67              0.8867126477        0.8867125569354448   9.076e-08

ASA310_PRB:
  Normal end of execution.


К примеру некоторые из результатов в Wolfram Mathematica:

Table[CDF[NoncentralBetaDistribution[5,5,140],0.9]]
= 0.1041335
Table[CDF[NoncentralBetaDistribution[15,5,80],0.88]]
= 0.1604257
Table[CDF[NoncentralBetaDistribution[35, 30, 20], 0.67]]
= 0.8867126

что более менее похоже на правду...