Discusión sobre el artículo "Distribuciones Estadísticas en MQL5: tomando lo mejor de R" - página 20

 

Estos son los resultados.



Tampoco son muy buenos... En general, trabajar con una distribución beta no central pertenece más bien a la clase de tareas no triviales. Nos las arreglamos para ver Boost desde el código fuente abierto. Y será más complicado que el que tenemos ahora en SB.

 
Gracias, lo comprobaremos.
 
Denis Kirichenko #:

La misma Wikipedia lo tiene:

Es decir, se toman dos variables aleatorias, donde la primera es de una distribución chi-cuadrado no central y la segunda es de una distribución central. Probablemente el código se pueda corregir a esto:

//--- generar número aleatorio usando ChiCuadrado No Central
double chi1=MathRandomNoncentralChiSquare(a2,lambda2,error_code);
double chi2=MathRandomChiSquare(b2,error_code);
 result[i]=chi1/(chi1+chi2);

Los gráficos modificados del ejemplo serán los siguientes.

Gracias, tienes razón, hay que calcular a través de esta fórmula, sin embargo había otro error, el parámetro de no centralidad lambda debería ser sin multiplicador 2.

//+------------------------------------------------------------------+
//| Variable aleatoria de la distribución Beta no central.
//+------------------------------------------------------------------+
//| Calcular la variable aleatoria de la Beta no central ||
//| distribución con parámetros a,b y lambda. |||
//||
//| Argumentos:|
//| a : Primer parámetro de forma |
//| b : Segundo parámetro de forma |
//| lambda : Parámetro de no centralidad
//| error_code : Variable para el código de error |
//||
//| Valor de retorno:|
//| Valor aleatorio con distribución Beta no central.
//+------------------------------------------------------------------+
double MathRandomNoncentralBeta(const double a,const double b,const double lambda,int &error_code)
  {
//--- si lambda==0, devuelve la variante aleatoria beta
   if(lambda==0.0)
      return MathRandomBeta(a,b,error_code);
//--- comprobar parámetros
   if(!MathIsValidNumber(a) || !MathIsValidNumber(b) || !MathIsValidNumber(lambda))
     {
      error_code=ERR_ARGUMENTS_NAN;
      return QNaN;
     }
//--- a,b,lambda deben ser positivos
   if(a<=0.0 || b<=0.0 || lambda<0)
     {
      error_code=ERR_ARGUMENTS_INVALID;
      return QNaN;
     }

   error_code=ERR_OK;
//--- generar número aleatorio usando ChiCuadrado No Central
   double chi1=MathRandomNoncentralChiSquare(2*a,lambda,error_code);
   double chi2=MathRandomChiSquare(2*b,error_code);
   return chi1/(chi1+chi2);
  }
//+------------------------------------------------------------------+
//| Variable aleatoria de la distribución Beta no central.
//+------------------------------------------------------------------+
//|| Genera variables aleatorias a partir de la distribución Beta no central ||
//| con parámetros a,b, lambda.|
//||
//| Argumentos:|
//| a : Primer parámetro de forma |
//| b : Segundo parámetro de forma |
//| lambda : Parámetro de no centralidad
//| data_count : Número de valores necesarios ||
//| resultado : Matriz de salida con valores aleatorios |
//||
//| Valor de retorno:|
//| verdadero si tiene éxito, en caso contrario falso. ||
//+------------------------------------------------------------------+
bool MathRandomNoncentralBeta(const double a,const double b,const double lambda,const int data_count,double &result[])
  {
//--- si lambda==0, devuelve la variante aleatoria beta
   if(lambda==0.0)
      return MathRandomBeta(a,b,data_count,result);
//--- comprobar parámetros
   if(!MathIsValidNumber(a) || !MathIsValidNumber(b) || !MathIsValidNumber(lambda))
      return false;
//--- a,b,lambda deben ser positivos
   if(a<=0.0 || b<=0.0 || lambda<0)
      return false;

   int error_code=0;
//--- prepara la matriz de salida y calcula los valores aleatorios
   ArrayResize(result,data_count);
   double a2=a*2;
   double b2=b*2;
   for(int i=0; i<data_count; i++)
     {
      //--- generar número aleatorio usando ChiCuadrado No Central
      double chi1=MathRandomNoncentralChiSquare(a2,lambda,error_code);
      double chi2=MathRandomChiSquare(b2,error_code);
      result[i]=chi1/(chi1+chi2);
     }
   return true;
  }

Script de prueba:

//+------------------------------------------------------------------+
//|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
//--- parámetros de entrada
input double a_par=2;    // primer parámetro de la distribución beta (shape1)
input double b_par=5;    // segundo parámetro de distribución beta (shape2)
input double l_par=1;    // parámetro de no centralidad (lambda)
//+------------------------------------------------------------------+
//| Función de inicio del programa de script|
//+------------------------------------------------------------------+
void OnStart()
  {
//--- desactivar la visualización del gráfico de precios
   ChartSetInteger(0,CHART_SHOW,false);
//--- inicializar el generador de números aleatorios 
   MathSrand(GetTickCount());
//--- generar una muestra de la variable aleatoria
   long chart=0;
   string name="GraphicNormal";
   int n=1000000;       // número de valores de la muestra
   int ncells=52;       // número de intervalos en el histograma
   double x[];          // centros de intervalo del histograma
   double y[];          // número de valores de la muestra que entran en el intervalo
   double data[];       // muestreo de valores aleatorios 
   double max,min;      // valores máximo y mínimo de la muestra
//--- obtener una muestra de la distribución beta no central 
   MathRandomNoncentralBeta(a_par,b_par,l_par,n,data);
//--- calcular los datos para la construcción del histograma
   CalculateHistogramArray(data,x,y,max,min,ncells);
//--- obtener los límites de la secuencia y el paso para la construcción de la curva teórica
   double step;
   GetMaxMinStepValues(max,min,step);
   step=MathMin(step,(max-min)/ncells);
//--- obtenemos datos calculados teóricamente en el intervalo [min,max]
   double x2[];
   double y2[];
   MathSequence(min,max,step,x2);
   MathProbabilityDensityNoncentralBeta(x2,a_par,b_par,l_par,false,y2);
//--- escala
   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;
//--- visualizar gráficos
   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);
//--- trazar todas las curvas
   graphic.CurveAdd(x,y,CURVE_HISTOGRAM,"Sample").HistogramWidth(6);
//--- y ahora vamos a trazar la curva de densidad de distribución teórica 
   graphic.CurveAdd(x2,y2,CURVE_LINES,"Theory");
   graphic.CurvePlotAll();
//--- trazar todas las curvas
   graphic.Update();
   
   DebugBreak();
  }
//+------------------------------------------------------------------+
//| Calcular frecuencias para el conjunto de datos|
//+------------------------------------------------------------------+
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);
//--- fijar los centros de los intervalos
   for(int i=0; i<cells; i++)
     {
      intervals[i]=minv+(i+0.5)*width;
      frequency[i]=0;
     }
//--- rellenar las frecuencias de intervalo
   for(int i=0; i<size; i++)
     {
      int ind=int((data[i]-minv)/width);
      if(ind>=cells) ind=cells-1;
      frequency[ind]++;
     }
   return (true);
  }
//+------------------------------------------------------------------+
//| Calcula valores para la generación de secuencias |
//+------------------------------------------------------------------+
void GetMaxMinStepValues(double &maxv,double &minv,double &stepv)
  {
//--- calcula la magnitud absoluta de la secuencia para obtener la precisión de la normalización
   double range=MathAbs(maxv-minv);
   int degree=(int)MathRound(MathLog10(range));
//--- normalizar los valores máx. y mín. con la precisión especificada
   maxv=NormalizeDouble(maxv,degree);
   minv=NormalizeDouble(minv,degree);
//--- el paso de generación de la secuencia también se establece a partir de la precisión dada
   stepv=NormalizeDouble(MathPow(10,-degree),degree);
   if((maxv-minv)/stepv<10)
      stepv/=10.;
  }

Resultado:

No centralBeta(2,5,1)

No centralBeta(2,5,10)

No centralBeta(2,15,100)

No centralBeta(2,15,20)

Archivos adjuntos:
 

También he comprobado la función CFD para la distribución beta no central.

#include <Math\Stat\NoncentralBeta.mqh>
//+------------------------------------------------------------------+
//| Función de inicio del programa de script|
//+------------------------------------------------------------------+
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}
     };
// imprimir
   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);
     }
  }


Algunos resultados cuestionables:

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


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

ASA310_PRB:
  Normal end of execution.


Por ejemplo algunos de los resultados en 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

Que es más o menos similar a la verdad...