扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
目录
创新互联长期为成百上千客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为白云企业提供专业的成都网站建设、网站设计,白云网站改版等技术服务。拥有10余年丰富建站经验和众多成功案例,为您定制开发。引言
逻辑回归
Matlab代码
效果展示
Python代码
效果展示
C++代码
效果展示
本专栏第三个机器学习算法:逻辑回归算法,全部代码通过Github下载,使用Matlab,Python以及C++三种语言进行实现。其中Matlab的代码可以直接运行,Python与C++的代码需要分别安装Numpy以及Numcpp两个库才能运行。
逻辑回归以二分类为例,假设待分类样本的特征是二维的即可以用坐标(x,y)表示一个样本,逻辑回归的主要任务就是找到一条分类线,这条分类线我们又称之为决策边界,使得两个类别的样本分布在分类线的两侧如下图所示。当输入一个新的样本时只需要判断其在分类线的哪一侧即可知道它所属哪类。
那么如何得到这条分类线呢?以下为实现步骤(训练阶段):
1、随机初始化这条分类线,可以是 y=x , y=0 , x=0 , y=x+1等等,代码中为初始化权重参数w和b,分类线使用w*x+b表示
2、定义损失函数如下图所示
3、运行梯度下降不断更新w和b,直到达到要求(损失值低于某一设定值或是已经全部分类正确),梯度下降以及损失函数的相关计算公式如下(假设一共有m个样本,表示第i个样本,代表第i个样本的标签)
之后的代码都将完成以下任务:
训练集坐标:
Class_1:(220,90)(240,95)(220,95)(180,95)(140,90)
Class_2:(180,90)(210,90)(140,90)(90,80)(78,80)
测试集坐标:
Test_Data :(180,90)(210,90)(140,90)(90,80)(78,80)
通过对训练集的训练,绘制一条决策边界(分类线)能够得到测试集的类别。
Matlab代码这里的权重参数是随机初始化的所以每次运行效果都不同,但都能分类正确
clc;
close all;
clear all;
%% 定义训练样本
Class_1_o= [220 90;240 95;220 95;180 95;140 90];
Class_2_o= [80 85;85 80;85 85;82 80;78 80];
Test_Data_o = [180 90;210 90;140 90;90 80;78 80];
% 数据集归一化
Class_x = mapminmax([Class_1_o(:,1)',Class_2_o(:,1)',Test_Data_o(:,1)'], 0, 1);
Class_y = mapminmax([Class_1_o(:,2)',Class_2_o(:,2)',Test_Data_o(:,2)'], 0, 1);
Class_1 = [Class_x(1:5)',Class_y(1:5)'];
Class_2 = [Class_x(6:10)',Class_y(6:10)'];
Test_Data = [Class_x(11:15)',Class_y(11:15)'];
[m_1,n_1] = size(Class_1);
[m_2,n_2] = size(Class_2);
%% 绘图程序
figure;
plot(Class_1(:,1),Class_1(:,2),'r*','LineWidth',2); hold on;
plot(Class_2(:,1),Class_2(:,2),'bo','LineWidth',2); hold on;
plot(Test_Data(:,1),Test_Data(:,2),'gs','LineWidth',2); hold on;
%% 定义训练参数
Train_Data = [Class_1;Class_2];
[m_3,n_3] = size(Train_Data);
Y = [1,1,1,1,1,0,0,0,0,0]; % 定义标签值
w = randn([2 1]); % 随机初始化权重以及参数
b = randn(1);
a = 0.01; % 学习率
epoch = 0; % 定义迭代次数
%% 使用批处理方式计算权值修正量
while epoch<=100
epoch = epoch + 1;
for i=1:m_3
fx = w'*Train_Data(i,:)' + b;
gz = 1/(1+exp(-fx));
w(1) = w(1) - a*Train_Data(i,1)'*(gz - Y(i));
w(2) = w(2) - a*Train_Data(i,2)'*(gz - Y(i));
b = b- a*(gz-Y(i));
end
% 判断何时停止
fx = w'*Train_Data' + b;
gz = 1./(1+exp(-fx));
Loss = (-Y*log(gz)' - (1-Y)*log(1-gz)')/m_3;
if Loss<= 0.3
break;
end
end
%% 打印结果
f=[num2str(w(1)) '*x+(' num2str(w(2)) ')*y+(' num2str(b) ')'];
h = ezplot(f,[-0.5,1.5]);
grid on;
set(h,'Color','r');
legend('class1','class2','decisionboundary')
效果展示Python代码python需要用到numpy库,没安装的朋友运行不了哦,此处w初始化为[1,1]与b初始化为1,方便与C++结果进行对比
import matplotlib.pyplot as plt
import torch
import numpy as np
# 进行归一化
def normalization(Data1, Data2, Data3):
# 要对全部的X坐标单独归一化,全部的Y坐标同理
Data_x = np.concatenate((Data1[:, 0], Data2[:, 0], Data3[:, 0]))
Data_y = np.concatenate((Data1[:, 1], Data2[:, 1], Data3[:, 1]))
# 参照Matlab的mapminmax函数进行归一化
Data_x = (Data_x - np.min(Data_x)) / (np.max(Data_x) - np.min(Data_x))
Data_y = (Data_y - np.min(Data_y)) / (np.max(Data_y) - np.min(Data_y))
Data_x = np.expand_dims(Data_x, 1)
Data_y = np.expand_dims(Data_y, 1)
Data1 = np.concatenate((Data_x[:5], Data_y[:5]), 1)
Data2 = np.concatenate((Data_x[5:10], Data_y[5:10]), 1)
Data3 = np.concatenate((Data_x[10:], Data_y[10:]), 1)
return Data1, Data2, Data3
if __name__ == "__main__":
# 定义数据集
class_1_o = np.array([[220, 90], [240, 95], [220, 95], [180, 95], [140, 90]], dtype=np.float)
class_2_o = np.array([[80, 85], [85, 80], [85, 85], [82, 80], [78, 80]], dtype=np.float)
Test_Data_o = np.array([[180, 90], [210, 90], [140, 90], [90, 80], [78, 80]], dtype=np.float)
Class_1, Class_2, Test_Data = normalization(class_1_o, class_2_o, Test_Data_o)
# 开始绘图
plt.figure()
plt.plot(Class_1[:, 0], Class_1[:, 1], 'r*', label='Class_1')
plt.plot(Class_2[:, 0], Class_2[:, 1], 'b*', label='Class_2')
plt.plot(Test_Data[:, 0], Test_Data[:, 1], 'gs', label='Test_Data')
plt.legend(loc='best')
# 定义训练参数
Train_Data = np.concatenate((Class_1, Class_2), axis=0)
Y = np.array([[1, 1, 1, 1, 1, 0, 0, 0, 0, 0]], dtype=np.float)
c = Train_Data.shape
# w = np.random.randn(3, 1)
w = np.array([[1], [1]], dtype=np.float) # 使用[1;1;1]方便与C++的运行结果比对(因为C++无法使用matlpotlib绘图)
b = np.array([1])
a = 0.01
epoch = 0
# 开始训练
while True:
epoch = epoch + 1
for i in range(0, c[0]): # 遍历训练集
fx = np.matmul(w.T, Train_Data[i, :].T) + b # matmul为矩阵乘法(线代知识)
gz = 1 / (1 + np.exp(-fx))
# 开始梯度下降
w[0] = w[0] - a * Train_Data[i, 0] * (gz[0] - Y[0, i])
w[1] = w[1] - a * Train_Data[i, 1] * (gz[0] - Y[0, i])
b = b - a * (gz[0] - Y[0, i])
# 判断何时停止训练
fx = np.matmul(w.T, Train_Data.T) + b
gz = 1 / (1 + np.exp(-fx))
Loss = (np.matmul(-Y, np.log(gz).T) - np.matmul((1-Y), np.log(1 - gz).T)) / c[0]
if Loss<= 0.3:
break
print(w)
# 绘制分类线
xlist = np.linspace(-0.5, 1.5, 100)
ylist = np.linspace(-0.5, 1.5, 100)
x, y = np.meshgrid(xlist, ylist) # 计算圆所在区域的网格
f = w[0] * x + w[1] * y + b< 0
plt.contourf(x, y, f, cmap="cool")
plt.show()
print('w的值为\n{}\n,b的值为\n{}'.format(w, b))
效果展示C++代码C++使用到了Numcpp库,没安装的朋友运行不了哦!
#include"NumCpp.hpp"
#include"boost/filesystem.hpp" // 这一行貌似可以去掉
#includeusing namespace std;
tuple, nc::NdArray, nc::NdArray>normalization(nc::NdArrayData1, nc::NdArrayData2, nc::NdArrayData3);
void main()
{
// 定义数据集
nc::NdArrayclass_1_o = { {220,90},{240,95},{220,95},{180,95},{140,90} };
nc::NdArrayclass_2_o = { {80,85},{85,80},{85,85},{82,80},{78,80} };
nc::NdArrayTest_Data_o = { {180,90},{210,90},{140,90},{90,80},{78,80} };
// 进行归一化Data是一个元组
auto Data = normalization(class_1_o, class_2_o, Test_Data_o);
auto Class_1 = get<0>(Data);
auto Class_2 = get<1>(Data);
auto Test_Data = get<2>(Data);
// 定义训练参数
auto Train_Data = nc::vstack({ Class_1, Class_2 });
auto m = Train_Data.shape();
nc::NdArrayY = { 1,1,1,1,1,0,0,0,0,0 };
//auto w = nc::random::randN({ 3,1 });
nc::NdArrayw = {1,1};
w = w.reshape(2, 1);
nc::NdArrayb = { 1 };
float a = 0.01;
int epoch = 0;
// 开始训练
while (true)
{
epoch += 1;
for (int i = 0; i< m.rows; i++)
{
// 这里与python不同numcpp进行向量相乘后得出的是一个1*1的矩阵,必须先用at()将数据提取出来后再进行运算
auto fx = nc::matmul(w.transpose(), Train_Data(i, Train_Data.cSlice()).transpose()) + b;
auto gz = 1 / (1 + nc::exp(-fx).at(0));
// 开始梯度下降
w[0] -= a * Train_Data(i, 0) * (gz - Y[i]);
w[1] -= a * Train_Data(i, 1) * (gz - Y[i]);
b -= a * (gz - Y[i]);
}
auto fx = nc::matmul(w.transpose(), Train_Data.transpose()) + b.at(0);
auto gz = 1.0f / (1.0f + nc::exp(-fx));
auto Loss = (nc::matmul(-Y, nc::log(gz).transpose()) - nc::matmul((1.0f - Y), nc::log(1.0f - gz).transpose())) / (float)m.rows;
cout<< Loss<< endl;
if (Loss.at(0)<= 0.3)
{
break;
}
}
cout<< "w的值为 \n"<< w<< endl; // 输出训练结果
cout<< "b的值为 \n"<< b<< endl;
}
// 归一化函数
tuple, nc::NdArray, nc::NdArray>normalization(nc::NdArrayData1, nc::NdArrayData2, nc::NdArrayData3)
{
// AXis::Row相当于python的axis=0 Data1(Data1.rSlice(),0)相当于python的 Data1[:,0]
auto Data_x = nc::concatenate({ Data1(Data1.rSlice(),0),Data2(Data2.rSlice(),0),Data3(Data3.rSlice(),0) }, nc::Axis::ROW);
auto Data_y = nc::concatenate({ Data1(Data1.rSlice(),1),Data2(Data2.rSlice(),1),Data3(Data3.rSlice(),1) }, nc::Axis::ROW);
// nc::min(Data_x) 返回1*1的矩阵需要用at(0)将数字提取出来再运算
Data_x = (Data_x - nc::min(Data_x).at(0)) / (nc::max(Data_x).at(0) - nc::min(Data_x).at(0));
Data_y = (Data_y - nc::min(Data_y).at(0)) / (nc::max(Data_y).at(0) - nc::min(Data_y).at(0));
Data1 = nc::concatenate({ Data_x({0,5},0), Data_y({0,5},0) },nc::Axis::COL);
Data2 = nc::concatenate({ Data_x({5,10},0), Data_y({5,10},0) }, nc::Axis::COL);
Data3 = nc::concatenate({ Data_x({10,15},0), Data_y({10,15},0) }, nc::Axis::COL);
tuple, nc::NdArray, nc::NdArray>Data(Data1,Data2,Data3); // 定义一个元组作为返回值
return Data;
}
效果展示貌似也存在Matplotlib的C++版本,但是我没有安装。。。所以就直接打印训练结果了,可以看到训练结果与Python的一致,代表分类正确。
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流