目录
源码下载
GitHub - 1578630119/Regression
利用逻辑回归可以实现分类,将直线的两侧划分为两类。现在要利用线性回归实现对连续型的数据做出预测,例如销售量预测或者制造缺陷预测等。
一、用线性回归找到最佳拟合直线
线性回归
优点:结果易于理解,计算上不复杂。
缺点:对非线性的数据拟合不好。
适用数据类型:数值型和标称型数据。
假设输入数据存放在X矩阵[x0,x1,....,xn]中,而回归系数存放在向量w[w0,w1,...,wn]中。我们需要用手里已知的一些X和对应的Y来找到w的。一个常用的方法是找出使误差最小的w,这里的误差是指预测y值和真实的y值之间的差值,使用该误差的简单累加将使得正差值和负差值相互抵消,所以采用平方误差。平方误差可以写做:
用矩阵表示还可以写做,如果对w求导,得到
,令其等于0,解出w如下:
w上方的小标记表示这是当前可以估计出的w的最优解。从现有的数据上估计出的w可能并不是数据中的真实w值,所以这里使用了一个“帽”符号来表示它仅是w的一个最佳估计。这种最佳w求解是统计学中常见问题,在代码中可以调用Numpy库里的矩阵方法,该方法也称作OLS,意思是“普通最小二乘法”(ordinary least squares)。
![](https://img-blog.csdnimg.cn/direct/4cb34ad1775d4641ab01abbafdc77f79.png)
针对于ex0.txt中的数据,利用上面的方法求出该数据的最佳拟合直线
def load_data_set(file_name):
#提取txt文本中的数据,将特征保存在data_mat中,真实标签保存在label_mat中。
num_feat = len(open(file_name).readline().split('\t')) - 1
data_mat = []
label_mat = []
with open(file_name, 'r') as fr:
for line in fr.readlines():
line_arr = []
cur_line = line.strip().split('\t')
for i in range(num_feat):
line_arr.append(float(cur_line[i]))
data_mat.append(line_arr)
label_mat.append(float(cur_line[-1]))
return data_mat, label_mat
def stand_regres(x_arr, y_arr):
x_mat = np.mat(x_arr) #转为numpy矩阵类型
y_mat = np.mat(y_arr).T #转为numpy矩阵类型同时转置
xTx = x_mat.T * x_mat #X的转置 * X
if np.linalg.det(xTx) == 0.0: #判断矩阵的逆矩阵是否存在
print("This matrix is singular, cannot do inverse")
return
ws = xTx.I * (x_mat.T * y_mat) #(X的转置 * X)求逆后*(X的转置 * Y)
return ws
![](https://img-blog.csdnimg.cn/direct/2f3f64ff0fa64a6ea52300826dcc05a1.png)
二、局部加权线性回归
线性回归的一个问题是有可能出现欠拟合现象,上面的数据集和它的最佳拟合直线可以看出,模型欠拟合对预测无法取得最好的效果。处理这种情况的一个方法是局部加权线性回归(Locally weighted Linear Regression,LWLR),该算法给待预测点附近的每个点赋予一定的权重。与第一节类似,在这个子集上基于最小均方差来进行普通的回归,与kNN一样,这种算法每次预测均需要事先选取出对应的数据子集,该算法解出回归系数w的形式如下:
其中w是一个矩阵,用来给每个数据点赋予权重。
LWLR使用“核”来对附近的点赋予更高的权重,核的类型可以自由选择,最常用的核就是高斯核,高斯核对应的权重如下:
这样就构建了一个只含对角元素的权重矩阵w,并且点x与x(i)越近,w(i,i)将会越大。公式中的k是用户指定的参数k,他决定对附近的点赋予多大的权重。
局部加权线性回归函数
def lwlr(test_point, x_arr, y_arr, k=1.0):
x_mat = mat(x_arr)
y_mat = mat(y_arr).T
m = shape(x_mat)[0]
weights = np.mat(np.eye((m))) #生成m*m的单位矩阵
for j in range(m):
diff_mat = test_point - x_mat[j, :] #x-x(i)
weights[j, j] = exp(diff_mat * diff_mat.T / (-2.0 * k**2)) #高斯核
xTx = x_mat.T * (weights * x_mat) #X的转置*(高斯核 * X)
if linalg.det(xTx) == 0.0:
print("This matrix is singular, cannot do inverse")
return
ws = xTx.I * (x_mat.T * (weights * y_mat)) #LWLR
return test_point * ws
def lwlr_test(test_arr, x_arr, y_arr, k=1.0):
#测试函数,得到通过LWLR得到的模型预测结果
m = shape(test_arr)[0]
y_hat = zeros(m)
for i in range(m):
y_hat[i] = lwlr(test_arr[i], x_arr, y_arr, k)
return y_hat
![](https://img-blog.csdnimg.cn/direct/9072d315a66e498bad1abd79a2bcec86.png)
![](https://img-blog.csdnimg.cn/direct/c2e0c1aced9d4858a6c0cb4932b1cc34.png)
![](https://img-blog.csdnimg.cn/direct/fa7faf417cbf4b8589962bbd73a8f7cc.png)
上面三张图是高斯核中k在三种不同取值下的结果图,当k=1.0时权重很大,如同将所有的数据视为等权重,得出的最佳拟合直线与标准的回归一致。使用k=0.01得到了非常好的效果,抓住了数据的潜在模式。下图使用k=0.003纳入了太多的噪声点,拟合的直线与数据点过于贴近。局部加权线性回归也存在一个问题,即增加了计算量,因为它对每个点做预测时都必须使用整个数据集。
三、示例:预测鲍鱼的年龄
本节将利用回归用于真实数据,在data目录下有一份来自UCI数据集合的数据,记录了鲍鱼(一种介壳类水生动物)的年龄。鲍鱼的年龄可以从鲍鱼壳的层数推算得到。
需要添加以下代码计算预测结果和真是结果之间的差距。
def rss_error(y_arr, y_hat_arr):
return ((y_arr - y_hat_arr) ** 2).sum()
结果如下: