一、 数学上的逻辑回归
前面提到,逻辑回归是判别分析方法来分类的,即 通过给定的数据x, 来直接得到其后验概率。且 它 得到的是线性分类边界。
回顾在贝叶斯准则中, 利用0-1损失进行分类时, 我们做法是 以最大的后验概率 的类 k, 来作为依据。
从而 第k 类 和 第 l 类的分类边界通过 使其概率相等来决定: 即 样本 x 在 第k 类和第l 类有相等的后验概率。
如果我们 我们对两个概率进行相除 ,并且取 log 的话 ,这样得到一个比率, 在上述情况有
如果我们想要强制得到一个线性分类边界, 我们可以假设这个函数可以线性表示, 即
逻辑回归就是在这样一个假设的的基础上得到的。 其中 对不同的两类类,有不同的系数上标(k,l), 其系数也不同。
这样看着 很容易理解, 那肯定也会有这样的疑问, 那岂不是每两类就要找一个 , 那计算量岂不是很大 !
然而在 逻辑回归中, 我们并不用每两类 都要找一组 系数, 对于 K 类, 我们只需要进行 K-1 对配对, 找K-1 组系数就可以了。
,因为 这两者后验概率和为1。
因为 K = 2, 我们只有一个线性多项式, 一个分类决策边界, 参数列表为 , 现在 我们在这里表示为
, 这是一个列向量。
现在我们要做的就是一步步, 简化, 计算, 求解
/*
@Newton-Method :
@iteratively reweighted least squares
@x_train : train sample of data
@y_train : train result of data
@weight : the train weight result.
@use the Computational Efficiency
@use the matrix term to express the process
*/
void IterReweightedLS(Matrix &x_train, Matrix &y_train, Matrix &weight)
{
//change the y as 1->1, 2->0
for (int row = 0; row < y_train.GetMatrixRow(); row++)
{
if (y_train.GetMatrixValue(row, 0) == 2.0)
y_train.SetMatrixOnePosition(row, 0, 0.0);
}
//use the pro-resadual to judge weather converge
Matrix odl_pro_use_for_converge(y_train.GetMatrixRow(), y_train.GetMatrixCol());
odl_pro_use_for_converge.SetMatrixAllOne();
odl_pro_use_for_converge = odl_pro_use_for_converge.MatrixMultiNumPerRow(-1, 0);
int iter_count = IterNumber;
while (iter_count--)
{
// use the matrix to express the culculate
// the probability of the sigmoid express form
Matrix temp(x_train.GetMatrixRow(), 1);
Matrix probability(y_train.GetMatrixRow(), y_train.GetMatrixCol());
temp = x_train.MatrixMulti(weight);
//another thing the probability all be exp(xw)/exp(xw)+1, because we have connected it all together
for (int pro_row = 0; pro_row < y_train.GetMatrixRow(); pro_row++)
{
double pro = sigmoid(temp.GetMatrixValue(pro_row, 0));
probability.SetMatrixOnePosition(pro_row, 0, pro);
}
//the W of diagonal matrix use the value p*(1-p)
Matrix W(y_train.GetMatrixRow(), y_train.GetMatrixRow());
W.SetMatrixAllZero();
Matrix one_cut_pro(probability.GetMatrixRow(),1);
one_cut_pro.SetMatrixAllOne();
Matrix pro_multi_one_cut_pro(probability);
pro_multi_one_cut_pro = probability.MatrixPointMlutiMatrix((one_cut_pro.MatrixCut(probability)));
W.SetDialogUsVector(pro_multi_one_cut_pro);
//x_hat for culmulate efficient
// remember the iter pre and after.
Matrix x_hat = x_train;
for (int row = 0; row < x_train.GetMatrixRow(); row++)
{
x_hat = x_hat.MatrixMultiNumPerRow(pro_multi_one_cut_pro.GetMatrixValue(row, 0), row);
}
//culmulate the (x^T x_hat)^(-1)*x^T*(Y-P)
// first LUP factorization
// and then culmulate the parameter w_redisual
Matrix x_trans = x_train.MatrixTrans();
Matrix x_factorization = x_trans.MatrixMulti(x_hat);
Matrix right_value = x_trans.MatrixMulti(y_train.MatrixCut(probability));
//(x^T x_hat)^(-1) if the x_factorization
//use the lup factorization to culmulate
LUPFactorization matrix_factor(x_factorization);
matrix_factor.Factorization();
right_value = (matrix_factor.GetP()).MatrixMulti(right_value);
//use the l-down triangle and u-up triange to compute it
Matrix intermediray_vector = right_value.MatrixDivideDownTriangle(matrix_factor.GetL());
Matrix terminal_vector = intermediray_vector.MatrixDivideUpTriangle(matrix_factor.GetU());
weight = weight.MatrixPlus(terminal_vector);
Matrix pro_redasual = probability.MatrixCut(odl_pro_use_for_converge);
//whether converged
double sum_pro_resudal = pro_redasual.VectorL1Norm();
//cout << sum_pro_resudal << endl;
if (sum_pro_resudal < (NumberSamble * Epsilon))
{
cout << "the gradient l2 norm is: " << sum_pro_resudal << endl;
cout << "the iter number is: " << IterNumber - iter_count << endl;
weight.ShowMatrix();
break;
}
odl_pro_use_for_converge = probability;
}
}
最终结果: 收敛,迭代次数, 最终更新参数, 误差率。
并且利用 opencv 将结果进行了显示:
分类来看,效果还是不错的。