数据科学与机器学习(第 02 部分):逻辑回归·综合运用
📉

数据科学与机器学习(第 02 部分):逻辑回归·综合运用

(3/3)· 用二元交叉熵与多重动态挑战,看清逻辑回归在分类任务里的真实边界

偏理论 第 3/3 篇

很多交易者把逻辑回归当成黑箱信号发生器,却没意识到阈值和损失函数直接决定了分类边界的偏移。当多重特征同时动态变化时,静态系数会迅速失效,误把噪声当概率。

「逻辑回归里的二元交叉熵怎么算」

做分类模型时,均方误差不合适,逻辑回归的成本函数一般走二元交叉熵(也就是 log-loss)。它的核心是衡量预测概率 p 和真实标签 y(0 或 1)之间的偏离程度,偏得越多,罚分越大。 真实值 y=1 时,模型输出 p 越靠近 1 越好,罚分用 -log(p):p=0.4 罚约 0.92,p=0.6 罚约 0.51,远离 1 的样本吃亏更明显。y=0 时则要用负类概率 1-p 套同样公式,-log(1-p):此时 p=0.4 罚约 0.51,p=0.6 罚约 0.92,和直觉一致。 把两种情况并成一行就是 penalty = -( y*log(p) + (1-y)*log(1-p) )。y 取 1 或 0 代进去,和上面的 if-else 完全等价。N 个样本的平均对数损失,就是所有 penalty 求和再除以 N。 我们自己的训练集 logloss 测到 0.6858,测试集 0.6599,区间在 0.64–0.68,说实话不算理想。外汇与贵金属行情序列上跑这类模型高风险,过拟合和样本偏移都很常见,数字仅作验证参照。 要拿到「未舍入」的原始预测 p,得在训练/测试循环里、概率四舍五入之前就把值存进 rawpredicted 数组,不然算出来的损失是偏的。下面这段 MT5 代码可直接拷去用:

MQL5 / C++
<span class="keyword">class="type">class="kw">double</span> CLogisticRegression::LogLoss(<span class="keyword">class="type">class="kw">double</span> &amp;rawpredicted[])
 { 
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</span> log_loss =<span class="number">class="num">0</span>;
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</span> penalty=<span class="number">class="num">0</span>;
&nbsp;&nbsp; <span class="keyword">for</span> (<span class="keyword">class="type">int</span> i=<span class="number">class="num">0</span>; i&lt;<span class="functions">ArraySize</span>(rawpredicted); i++ )
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;penalty += -((m_yvalues[i]*<span class="functions">log</span>(rawpredicted[i])) + (<span class="number">class="num">1</span>-m_yvalues[i]) * <span class="functions">log</span>(<span class="number">class="num">1</span>-rawpredicted[i])); <span class="comment">class=class="str">"cmt">//sum all the penalties</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">if</span> (m_debug)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">printf</span>(<span class="class="type">class="kw">string">"penalty =%.5f"</span>,penalty); 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;log_loss = penalty/<span class="functions">ArraySize</span>(rawpredicted); <span class="comment">class=class="str">"cmt">//all the penalties divided by their total number</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">Print</span>(<span class="class="type">class="kw">string">"Logloss ="</span>,log_loss);
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="kw">return</span>(log_loss);
 }

◍ 多重动态回归的 MQL5 实现卡点

在 MT5 里写通用逻辑回归函数库,最头疼的是「多自变量动态接入」。早先我直接硬编码了两套同名函数:一套吃两个自变量数组,另一套吃四个,差异仅在于参数列数量。这种写法能跑,但明显违背 DRY 原则,维护起来很糟心。 Python 那边用 *args/**kwargs 就能灵活收参数,MQL5 没有等价语法。我能想到的出路是用字符串传列号(如 "3,4,5,6,7,8"),再在内部把全部数据塞进一个大数组,靠偏移量切出每一列。下面这段代码就是当时的雏形:用 x_columns 默认串指定列,MLRInit 里按 rows_total 步进拷贝到 EachXDataArray。 尝试把多列压进单一数组后在 for 循环里统一计算,我实测没跑通,模型输出对不上。另一个思路是动态开多个 CSV 当数组用,但文件 IO 加 while 循环在多线程回测时开销偏大,处理十几列时延迟明显上升。外汇与贵金属波动剧烈、杠杆高风险,这类自研回归模块未经严格样本外验证前,别直接挂实盘。 目前这套多动态逻辑回归仍属未完待解,函数库草稿已公开可查。欢迎有 MT5 底层数组操作经验的交易者,在评论里给一套不靠硬编码、不暴增文件 IO 的写法。

MQL5 / C++
class="type">void  MultipleRegressionMain(class="type">class="kw">double& predicted_y[],class="type">class="kw">double& Y[],class="type">class="kw">double& A[],class="type">class="kw">double& B[]); 
class="type">void  MultipleRegressionMain(class="type">class="kw">double& predicted_y[],class="type">class="kw">double& Y[],class="type">class="kw">double& A[],class="type">class="kw">double& B[],class="type">class="kw">double& C[],class="type">class="kw">double& D[]);
class="type">void CMultipleLogisticRegression::MLRInit(class="type">class="kw">string x_columns="class="num">3,class="num">4,class="num">5,class="num">6,class="num">7,class="num">8")
   class="type">int start = class="num">0;
   if (m_debug) class=class="str">"cmt">//if we are on debug mode print Each Array vs its row
      for (class="type">int i=class="num">0;i<x_columns_total; i++)
         {
            ArrayCopy(EachXDataArray,m_AllDataArray,class="num">0,start,rows_total);
            start += rows_total; 
            
            Print("Array Number =",i," From column number ",m_XColsArray[i]);
            ArrayPrint(EachXDataArray);     
         }

为什么选逻辑回归而不是别的方法

逻辑回归做二分类时不要求特征在样本空间里服从某种固定分布,这点对价格行为特征很友好——你不用先证明波动率服从正态才能喂数据。模型给出的输出是 0~1 之间的概率,交易者可以直接拿阈值切信号,而不是只看非黑即白的标签。 训练成本低,在 MT5 里跑几千根日线或几万根tick级样本,几秒内就能出系数。对未知K线做预测也只是一次线性运算,实盘告警不卡顿。 系数符号和大小本身就是特征重要性的粗略指标:比如某回归里 spread_zscore 系数为 2.3、rsi_dif 为 -1.1,说明前者对方向判断拉动更强。外汇与贵金属杠杆高、滑点跳空频繁,概率仅代表历史样本下的倾向,不是下一步必发生的结论。 抗过拟合在简单数据集上表现不错,但特征一旦堆到几十个就得上正则,否则小样本里容易把噪声当规律。

「把逻辑回归函数库当成对比基准来用」

这套逻辑回归实现的核心目的,不是拿去直接对行情做分类预测,而是在 MT5 里跑通函数库,和 GitHub 上那份 Python 版(LogisticRegression-MQL5-and-python)的输出做逐行比对,确认两边数值一致。 附件里 TestScript.mq5 仅 1.69 KB,LogisticRegressionLib.mqh 约 17.79 KB,想验证的人直接把 ZIP 拖进 MT5 的 MQL5/Include 和 Scripts 目录编译即可。 多重回归的练习留给了读者自己,下一篇才会正式用逻辑模型去碰股市崩盘预测的问题。外汇和贵金属杠杆高、回撤快,这类机器学习模块只该当作验证工具,别当成信号源。

把特征诊断交给小布盯盘
这些多变量逻辑回归的边界诊断,小布盯盘的 AIGC 已内置,打开对应品种页即可看到动态权重变化,你只需判断边界是否还符合当下行情。

常见问题

它衡量预测概率分布与真实标签的差距,梯度下降据此调整系数;值越小代表分类边界越贴合样本。
小布盯盘内置了特征权重与边界的可视化诊断,可对接你导出的行情特征,省去重复写预处理代码的时间。
指多个输入特征随时间非平稳变化,固定系数的逻辑方程会漂移,需要滚动重估或引入状态切换。
输出天然是 0 到 1 的概率,配合阈值可直接做多空离散决策,且对极端值的压缩比线性更稳。