Python之《机器学习系统设计》第七章

第七章:回归,推荐

用回归来预测放假

Boston数据集是Scikit-learn里面的一个内置数据集

我们从一维回归开始,根据平均住房数这个属性来对价格进行回归

from sklearn.datasets import load_boston
#导入Boston数据集
boston = load_boston()

#画出图形
from matplotlib import pyplot as plt
plt.scatter(boston.data[:,5], boston.target, color='r')
plt.show()


#提取出感兴趣的属性作为X
import numpy as np
x=boston.data[:,5]
x=np.array([[v] for v in x])
print x

#计算Y
y=boston.target
print y

#进行最小二乘法线性回归,并且只使用斜率(一维模型)
slope,_,_,_=np.linalg.lstsq(x,y)
print slope

计算出来了斜率,可以画出直线,想显示直线,需要注释掉之前的plt.show()

#展示线性回归的结果
plt.plot(range(10),range(10)*slope)
plt.show()



效果很糟糕,我们加上偏移项,实现技巧就是在所有的x前加1

#加上偏移量,重新计算X,做线性回归
x=boston.data[:,5]
x=np.array([[v,1] for v in x])
print x
y=boston.target
(slope,bias),_,_,_=np.linalg.lstsq(x,y)
print slope
plt.scatter(boston.data[:,5], boston.target, color='r')
plt.plot([3,10],[3*slope+bias,10*slope+bias])
plt.show()


现在看起来好多了


之前都只有一个变量参与了回归,这里我们使用多维回归

#多维回归
x = boston.data
#我们仍然要添加一个偏移项,但必须使用np.concatenate
#他会将两个数组/列表合并起来,因为我们在v里有几个输入变量
x = np.array([np.concatenate((v,[1])) for v in x])
y = boston.target
s,total_error,_,_ = np.linalg.lstsq(x,y)
一定要注意

np.concatenate((v,[1]))中间有两个括号,书上只有一个,会报错。顺便吐槽一句,书上代码错误也太多了,建议出问题后去看看源码



接下来我们使用scikit里面的线性回归

#sklearn的LinearRegression
from sklearn.linear_model import LinearRegression
lr = LinearRegression(fit_intercept=True) #fit_intercept=True 用来加入偏移量
lr.fit(x,y)
p = map(lr.predict,x)
e = p - y
total_error = np.sum(e*e)
rmse_train = np.sqrt(total_error/len(p))
print('RMSE on training: {}'.format(rmse_train))

输出

RMSE on training: 4.67950630064

结果和之前计算的一样


现在我们使用KFold类来构建一个10折交叉验证

#10折交叉验证
from sklearn.cross_validation import KFold
kf = KFold(len(x),n_folds=10)
err = 0
for train,test in kf:
    lr.fit(x[train],y[train])
    p = map(lr.predict,x[test])
    e = p-y[test]
    err += np.sum(e*e)
rmse_10cv = np.sqrt(err/len(x))
print('RMSE on 10-fold CV: {}'.format(rmse_10cv))


#试试用弹性网回归
from sklearn.linear_model import ElasticNet
en = ElasticNet(fit_intercept=True, alpha=0.5)

当特征数比样本数还大时

#当特征数大于样本数时
from sklearn.datasets import load_svmlight_file
data,target = load_svmlight_file('E2006.train')
from sklearn.linear_model import LinearRegression
lr = LinearRegression(fit_intercept=True)
lr.fit(data,target)
p - np.array(map(lr.predict,data))
p = p.ravel()
e = p-target
total_sq_error = np.sum(e*e)
rmse_train = np.sqrt(total_sq_error/len(p))
print(rmse_train)

误差很小,但使用交叉验证会发现有0.78.可见特征数很大时,这种模型泛化能力很差

一个解决方法就是利用正则化对过拟合施加反作用力,用弹性网络学习器来进行交叉验证循环


那么如何设置惩罚参数呢?一个办法是使用交叉验证

#sklearn内部对参数进行了交叉检查
from sklearn.linear_model import ElasticNetCV
met = ElasticNetCV(fit_intercept=True)
kf = KFold(len(target),n_folds=10)
for train,test in kf:
    met.fit(data[train],target[train])
    p = map(met.predict,data[test])
    p = np.array(p).ravel()
    e = p-target[test]
    err += np.dot(e,e)
rmse_10cv = np.sqrt(err/len(target))


下面来看一个对用户观看电影的推荐系统

from sklearn.linear_model import LassoCV
reg = LassoCV(fit_intercept=True, alphas=[0.125, 0.25, 0.5, 1, 2, 4])
#我们将一组明确的alpha值传递给构造器
#将用户分离,
u=reviews[i]
u=u.array().ravel()
ps,=np.where(u>0)
#建立一个索引。处i以外的数值
us = np.delete(np.arange(reviews.shape[0]),i)
x=reviews[us][:,ps].T
y=u[ps]
err=0
kf = KFold(len(y),n_folds=4)
for train,test in kf:
    xc,xl=movie_norm(x[train])
    reg.fit(data[train],target[train])
    xc,xl=movie_norm(x[test])
    p = map(reg.predict,xc)
    p = np.array(p).ravel()
    e = (p+xl)-y[test]
    err += np.sum(e*e)
rmse_10cv = np.sqrt(err/len(target))

def movie_norm(x):
    xc = x.copy().toarray()

#我们不想有0计算的均值
xl=np.array([xi[xi>0].mean() for xi in xc])
#在一般情况下,数据里并没有评分信息,我们得到了一个Nan值,将其转换为0
xl = np.nan_to_num(xl)
#从非0项中减去均值对输入数据进行归一化
for i in xrange(xc.shape[0]):
    xc[i] -= (xc[i]>0)*xl[i]







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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值