多元线性回归OpenCV代码



前言

本文的实现主要是参照了Andrew NG的机器学习课程所讲的内容。理论知识上一篇博文已经介绍。由于刚接触C++,代码写得比较粗糙,望见谅。

实验环境

Visual Studio 2013

OpenCV 2.4

实验代码

1.定义一个线性回归的类Regression:

头文件 Regression.h

#ifndef  _Regression_H_
#define  _Regression_H_
#include <vector>
#include <string>
#include <iostream>
#include <strstream>
#include <fstream>
#include <opencv2\core\core.hpp>
using namespace cv;
using namespace std;
class Regression
{
public:
	//加载数据
	void loadData(string filePath, string regx);
	//数据返回
	Mat& getX();
	Mat& getEX();
	Mat& getTheta();
	Mat& getY();
	//特征归一化
	void featureNormalize(Mat& x);
	//预测
	float predict(Mat& x);
	//假设函数,此处设成静态函数,是方便在其他类中直接调用
    static void calculateHx(Mat& x, Mat& theta, Mat& Hx);
private:
	Mat originalX;
	Mat extendX;
	Mat y;
	int dim;//数据维数
	Mat theta;//列向量
};
#endif

实现文件 Regression.cpp

#include "Regression.h"

//把字符串转换成数值类型
template<typename T>
T convertStringData(string data)
{
	strstream ss;
	T y;
	ss <<data;
	ss >> y;
	return y;
}

//字符串分割函数 
inline vector<string> split(string str, string pattern)
{
	string::size_type pos;
	vector<string> result;
	str += pattern;//扩展字符串以方便操作
	int size = str.size();

	for (int i = 0; i<size; i++)
	{
		pos = str.find(pattern, i);
		if (pos<size)
		{
			std::string s = str.substr(i, pos - i);
			result.push_back(s);
			i = pos + pattern.size() - 1;
		}
	}
	return result;
}

//加载数据
void Regression::loadData(string filePath,string regx)
{
	ifstream fin(filePath);
	while (!fin.eof())
	{
		string temp;
		getline(fin, temp);
		if (strcmp(temp.c_str(), "") == 0) continue;
		vector<string> resStr = split(temp, regx);
		//设置x的维数
		dim = resStr.size() - 1;
		float yi=convertStringData<float>(resStr[resStr.size() - 1]);
		y.push_back(yi);
		Mat data = Mat::zeros(1, dim,CV_32FC1);//临时存放每一行的数据
		for (int i = 0; i < dim; i++)
		{
			data.row(0).col(i) = convertStringData<float>(resStr[i]);;
		}
		originalX.push_back(data);
	}
	extendX = Mat::ones(originalX.rows, dim + 1, CV_32FC1);
	originalX.copyTo(extendX.colRange(1, extendX.cols));
	extendX.col(0) = Mat::ones(extendX.rows, 1, extendX.type());
	theta = Mat::zeros(dim+1,1,originalX.type());
	fin.close();
}


//数据返回
Mat& Regression::getX()
{
	return originalX;
}

Mat& Regression::getY()
{
	return y;
}

Mat& Regression::getEX()
{
	return extendX;
}

Mat& Regression::getTheta()
{
	return theta;
}

//特征归一化
void Regression::featureNormalize(Mat& ex)
{
	if (ex.cols <= 2) return;//只有一个特征的时候不用归一化
	for (int col = 1; col < ex.cols; col++)
	{
		Mat mean;
		Mat stddev;
		meanStdDev(ex.col(col), mean, stddev);
		//归一化
		ex.col(col) = ex.col(col) - mean;
		ex.col(col) = ex.col(col) / stddev;
	}
}


//预测
//x:一个样本
//theta 训练得到的参数
float Regression::predict(Mat& x)
{
	Mat hx;
	calculateHx(x, this->getTheta(), hx);
	return hx.at<float>(0,0);
}

//计算假设函数
void Regression::calculateHx(Mat& x, Mat& theta, Mat& Hx)
{
	Hx = x*theta;
}

2.定义一个梯度下降的类GradientDescent:
头文件 GradientDescent.h

#ifndef _GRADIENTDESCENT_H
#define _GRADIENTDESCENT_H
#include <opencv2\core\core.hpp>
using namespace cv;
class GradientDescent
{
public:
	//批量梯度下降
	void gradientDescent(Mat& x, Mat& y, Mat &theta, int num_iters, float alpha);
	//计算代价
	float computeCost(Mat& x, Mat& y, Mat &theta);
	void normalizeEquation(Mat& x, Mat& y, Mat &theta);
};
#endif

实现文件 GradientDescent.cpp

#include "GradientDescent.h"
#include "Regression.h"
#include <iostream>
using namespace std;
void GradientDescent::gradientDescent(Mat& x, Mat& y, Mat &theta, int num_iters, float alpha)
{
	int dataSize = x.rows;//数据总数
	int dim = theta.rows;//theta的维数
	for (int i = 0; i < num_iters; i++)
	{
		//矢量化编程
		Mat hx;
		Regression::calculateHx(x, theta, hx);
		Mat thetaNew = theta-alpha*x.t()*(hx - y)/dataSize;
		thetaNew.copyTo(theta);
	}
}

float GradientDescent::computeCost(Mat& x, Mat& y, Mat &theta)
{
	float error = .0;
	Mat hx;
	Mat j;
	hx = x*theta;
	j = (hx - y).t()*(hx - y);
	error = j.at<float>(0, 0) / (2 * x.rows);
	return error;
}

void GradientDescent::normalizeEquation(Mat& x, Mat& y, Mat &theta)
{
	theta=(x.t()*x).inv()*x.t()*y;
}

3.代码测试:

样本集由Andrew NG机器学习课程提供,可在网上下载

main.cpp内容如下:

#include "Regression.h"
#include "GradientDescent.h"
#include <iostream>
#include <opencv2\opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
	Regression regression;
	regression.loadData("test_data/ex1data1.txt",",");
	regression.featureNormalize(regression.getEX());
	GradientDescent gd;
	float error=gd.computeCost(regression.getEX(), regression.getY(), regression.getTheta());
	cout << "cost:" << error << endl;
	gd.gradientDescent(regression.getEX(), regression.getY(), regression.getTheta(), 1500, 0.01);
	//gd.normalizeEquation(regression.getEX(), regression.getY(), regression.getTheta());
	cout << regression.getTheta() << endl;
	getchar();
	return 0;
}

输出结果:

与matlab运行结果一致




  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值