概述
本文探讨了量化在树模型构建中的理论应用,不使用复杂的数学方程。在写这篇文章的时候,我发现不同作者的科学著作中缺乏既定的统一术语,所以我会选择我认为最能反映其含义的术语选项。此外,在其他研究人员没有注意到的问题上,我将使用我自己的术语。本文将使用我之前在文章“来自Yandex的CatBoost机器学习算法而不学习Python或R”中描述的术语和概念。因此,我建议您在阅读当前文章之前先熟悉它。
1. 标准用途
那么什么是量化,为什么要使用量化呢?让我们来弄清楚!
首先,让我们谈谈数据。因此,为了创建模型(进行训练),我们需要在表中仔细收集数据。此类数据的来源可以是能够解释目标数据的任何信息(由模型确定,例如交易信号)。数据源被称为不同的预测因素、特征、属性或因素。数据线的出现频率由现象的可比过程观察的发生来确定,关于哪些信息正在被收集,哪些信息将使用机器学习进行研究。所获得的全部数据称为样本。
样本可以是有代表性的——这是指其中记录的观察结果描述了所研究现象的整个过程,也可以是不具有代表性的,因为有尽可能多的数据可以收集,这只允许对所研究现象过程进行部分描述。通常,当我们处理金融市场时,我们处理的是非代表性样本,因为可能发生的一切还没有发生。因此,我们不知道金融工具在发生新事件(以前从未发生过)时会如何表现。然而,每个人都知道“历史会重演”的格言。算法交易员在研究中依赖的正是这一观察结果,希望在新的事件中会有与以前类似的事件,并且它们的结果将与确定的概率相似。
我喜欢较短的定义:
数据量化是一种压缩(编码)观测信息的方法,其测量尺度具有可接受的精度损失。压缩(编码)意味着对象的离散性,这意味着它们的类型和同质性,或者简单地说是相似性。相似性标准可能不同,这取决于所选择的算法和嵌入其中的逻辑。
数据量化在任何地方都被使用,特别是在模拟信号到数字信号的转换中,以及在数字信号的后续压缩中。例如,从相机矩阵接收的数据可以记录为原始文件,然后立即(或稍后在计算机上)压缩为jpg或其他方便的数据存储格式。
看看MetaTrader 5终端中蜡烛或柱形的数据图形表示,我们已经看到了在我们选择的时间尺度上量化刻度的结果。随着时间的推移对连续数据流进行量化通常称为采样(或离散化)。
通常,采样是在一段时间内以给定频率记录观测特征的过程。然而,如果我们假设这是将数据收集到样本中的频率,则定义应调整为以下内容:“采样是记录观测特征的过程,其频率由给定函数在其阈值激活期间确定”。这里的函数指的是根据其固有逻辑给出信号以接收数据的任何算法。例如,在MetaTrader 5中,我们看到的正是这种方法,因为在非交易日,收盘价不是一个持续一段时间的过程,而是图表上没有任何信息,即采样率降至零。
2. 在MQL5中实现量化算法
之前,我们看了一个量化如何工作的简单例子,但它缺少量化中经常使用的步骤之一,即对经过一些计算后获得的尺度进行重新划分,以找到区间的平均值,这通常被称为质心。量化的间隔将最终由两个附近质心的边界之间的距离的一半来确定。
让我们考虑将占用内存8个字节的实数(如double)逐步量化为仅占用8位的整个uchar数据类型:
1. 在输入数据中查找最大值和最小值:
1.1. 在arr_in_Data数组中查找最大值和最小值-Max和Min变量。
2. 计算间隔之间的窗口大小:
2.1. 找出最大值和最小值之间的差值,并将其存储在Delta变量中。
2.2. 查找一个窗口的大小Delta/nQ,其中nQ是分隔符(边界)的数量,将结果保存在Interval_size变量中。
3. 执行量化和误差计算:
3.1. 将输入数据的最小值移位为零arr_In_data_Min。
3.2. 将点3.1的结果除以Interval_Size间隔的数量,后者比分隔符的数量多一个。
3.3. 现在,我们应该将“round”函数应用于3.2中获得的结果,该函数将数字四舍五入到最接近的整数。结果将保存在arr_Output_Q_Interval数组中。
3.4. 将arr_Output_Q_Interval数组的值乘以Interval_Size,再加上最小值。现在我们有了这个数字的转换(量化)值,我们将把它保存在arr_Output_Q_Data数组中。
3.5. 让我们将误差计算为累计总数。为此,我们将原始值与量化结果之间的绝对值差除以范围。将得到的总数除以arr_in_Data数组中的元素数。
4. 将分隔符(边界)保存到arr_Output_Q_Book数组中:
4.1. 对于第一个间隔,我们进行了修改-将间隔大小的一半(interval_size)添加到最小值(Min)。
4.2. 随后的间隔是通过将间隔值与前一步的arr_Output_Q_Book数组的值相加来计算的。
下面是一个函数代码示例,其中包含变量和数组的描述。
/+---------------------------------------------------------------------------------+
//|Quantization of transformation (encoding) type to a given integer bitness
//+---------------------------------------------------------------------------------+
double Q_Bit(
double &arr_Input_Data[],//Quantization data array
int &arr_Output_Q_Interval[],//Outgoing array with intervals containing data
double &arr_Output_Q_Data[],//Outgoing array with restored values of the original data
float &arr_Output_Q_Book[],//Outgoing array - "Book with boundaries" or "Quantization table"
int N_Intervals=2,//Number of intervals the original data should be divided (quantized) into
bool Use_Max_Min=false,//Use/do not use incoming maximum and minimum values
double Min_arr=0.0,//Maximum value
double Max_arr=100.0//Minimum value
)
{
if(N_Intervals<2)return -1;//There may be at least two intervals, in this case, there is one separator
//---0. Initialize the variables and copy the arr_Input_Data array
double arr_In_Data[];
double Max=0.0;//Maximum
double Min=0.0;//Minimum
int Index_Max=0;//Maximum index in the array
int Index_Min=0;//Minimum index in the array
double Delta=0.0;//Difference between maximum and minimum
int nQ=0;//Number of separators (borders)
double Interval_Size=0.0;//Interval size
int Size_arr_In_Data=0;//arr_In_Data array size
double Summ_Error=0.0;//To calculate error/data loss
nQ=N_Intervals-1;//Number of separators
Size_arr_In_Data=ArrayCopy(arr_In_Data,arr_Input_Data,0,0,WHOLE_ARRAY);
ArrayResize(arr_Output_Q_Interval,Size_arr_In_Data);
ArrayResize(arr_Output_Q_Data,Size_arr_In_Data);
ArrayResize(arr_Output_Q_Book,nQ);
//---1. Finding the maximum and minimum in the input data
if(Use_Max_Min==false)//If enforced array limits are not used
{
Index_Max=ArrayMaximum(arr_In_Data,0,WHOLE_ARRAY);
Index_Min=ArrayMinimum(arr_In_Data,0,WHOLE_ARRAY);
Max=arr_In_Data[Index_Max];
Min=arr_In_Data[Index_Min];
}
else//Otherwise enforce the maximum and minimum
{
Max=Max_arr;
Min=Min_arr;
}
//---2. Calculate the window size between intervals
Delta=Max-Min;//Difference between maximum and minimum
Interval_Size=Delta/nQ;//Size of one window
//---3. Perform quantization and error calculation
for(int i=0; i<Size_arr_In_Data; i++)
{
arr_Output_Q_Interval[i]=(int)round((arr_In_Data[i]-Min)/Interval_Size);
arr_Output_Q_Data[i]=arr_Output_Q_Interval[i]*Interval_Size+Min;
Summ_Error=Summ_Error+(MathAbs(arr_Output_Q_Data[i]-arr_In_Data[i]))/Delta;
}
//---4. Save separators (borders) into the array
for(int i=0; i<nQ; i++)
{
switch(i)
{
case 0:
arr_Output_Q_Book[i]=float(Min+Interval_Size*0.5);
break;
default:
arr_Output_Q_Book[i]=float(arr_Output_Q_Book[i-1]+Interval_Size);
break;
}
}
return Summ_Error=Summ_Error/(double)Size_arr_In_Data*100.0;
}