3.2.3 kNN用于回归分析
首先使用make_regression
创建一个数据集, 然后用KNeighborsRegressor
构建回归模型. 最后看看影响因素. 对比kNN用于分类, 回归的效果要差些.
-
make_regression
: 产生随机回归问题的数据点.-
n_samples=100
: 数据点数. -
n_features=100
: 特征数.默认100个变量. -
n_targets=1
:目标值的向量的大小. 默认是一个标量值. -
n_informative=10
: 有效特征数. 用于构建模型使用的特征数. -
noise=0.0
: 高斯噪音的标准差. -
bias=0.0
: 偏差. 体现出来类似截距, 但不是一个概念. -
effective_rank=None
: -
tail_strength=0.5
: -
coef=False
: 如设置为True, 返回时会返回线性模型的特征的系数. -
shuffle=True
,random_state=None
: 同上. - 返回
(X, y, coef)
, coef要在参数设置后才有返回.
-
这里构建了100样本(默认), 特征数1, 有效特征1, 噪音标准差50的数据集.
# 使用make_regression 生成特征1,噪音50
from sklearn.datasets import make_regression
X, y = make_regression(n_features=1,n_informative=1,noise=50,random_state=8)
plt.scatter(X,y,c='orange',edgecolor='k')
plt.show()
make_regression生成数据集
# 导入kNN回归分析的模型
from sklearn.neighbors import KNeighborsRegressor
reg = KNeighborsRegressor()
# 拟合数据并评分
reg.fit(X,y)
print('模型评分:{:.2f}'.format(reg.score(X,y)))
# 预测结果可视化.
z = np.linspace(-3,3,200).reshape(-1,1)
plt.scatter(X,y,c='orange',edgecolor='k')
plt.plot(z, reg.predict(z),c='k',linewidth=3)
plt.title('KNN Regressor')
plt.show()
kNN回归分析(k=5)
# 导入kNN回归分析的模型
from sklearn.neighbors import KNeighborsRegressor
reg2 = KNeighborsRegressor(n_neighbors=20)
# 拟合数据并评分
reg2.fit(X,y)
print('模型评分:{:.2f}'.format(reg2.score(X,y)))
# 预测结果可视化.
z = np.linspace(-3,3,200).reshape(-1,1)
plt.scatter(X,y,c='orange',edgecolor='k')
plt.plot(z, reg2.predict(z),c='k',linewidth=3)
plt.title('KNN Regressor: n_neighbors=20')
plt.show()
# k = 2: 模型评分:0.86
# k = 5: 模型评分:0.77 (上面默认的5)
# k = 10: 模型评分:0.75
# k = 20: 模型评分:0.67
# k = 50: 模型评分:0.54
kNN回归分析(k=2)
kNN回归分析(k=5)
kNN回归分析(k=10)
kNN回归分析(k=20)
kNN回归分析(k=50)
从上述可以看出, 随着k的增大, 评分下降. 但k太小的时候, 显然存在一定过拟合的情况.
# 尝试使用线性回归求解
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(X,y)
print('模型评分:{:.2f}'.format(lr.score(X,y)))
# 预测结果可视化.
z = np.linspace(-3,3,200).reshape(-1,1)
plt.scatter(X,y,c='orange',edgecolor='k')
plt.plot(z, lr.predict(z),c='k',linewidth=3)
plt.title('Linear Regressor')
plt.show()
# 模型评分: 0.69
线性回归分析
对比线性回归, kNN=20时较为接近. 太大时拟合不好, 太小时过拟合.
那究竟分开训练集和测试集后是不是能明显看出这种差异呢?
# 重新测试分割训练集合测试集后的效果
# 点数越多, 拟合越稳定, 效果更稳定
X, y = make_regression(n_samples=200, n_features=1,n_informative=1,noise=50,random_state=8)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,random_state=4)
# 喜欢的可以把下面的random_state=4去掉,看多个效果
# 测试分割训练集和测试集
for n in [2,5,10,20,50]:
reg3 = KNeighborsRegressor(n_neighbors=n)
reg3.fit(X_train, y_train)
print('训练集评分:{:.2f}'.format(reg3.score(X_train, y_train)))
print('测试集评分:{:.2f}'.format(reg3.score(X_test, y_test)))
# 预测结果可视化.
z = np.linspace(-3,3,200).reshape(-1,1)
plt.scatter(X_train, y_train,c='orange',edgecolor='k')
plt.scatter(X_test, y_test,c='green',edgecolor='k')
plt.plot(z, reg3.predict(z),c='k',linewidth=2)
plt.title('KNN Regressor: n_neighbors=2')
plt.show()
lr2 = LinearRegression()
lr2.fit(X_train, y_train)
print('训练集评分:{:.2f}'.format(lr2.score(X_train, y_train)))
print('测试集评分:{:.2f}'.format(lr2.score(X_test, y_test)))
# 预测结果可视化.
z = np.linspace(-3,3,200).reshape(-1,1)
plt.scatter(X_train, y_train,c='orange',edgecolor='k')
plt.scatter(X_test, y_test,c='green',edgecolor='k')
plt.plot(z, lr2.predict(z),c='k',linewidth=2)
plt.title('Linear Regressor')
plt.show()
- k = 2 训练集评分:0.87 测试集评分:0.66
- k = 5 训练集评分:0.82 测试集评分:0.71
- k = 10 训练集评分:0.80 测试集评分:0.72
- k = 20 训练集评分:0.78 测试集评分:0.76
- k = 50 训练集评分:0.68 测试集评分:0.64
- 线性回归 训练集评分:0.77 测试集评分:0.70
从上面结果来看, 的确存在过拟合现象, 尤其当k=2时最严重. k=5和10差不多, k=20时尽管训练集评分低些, 但测试集评分最高. 当k=50时, 出现欠拟合现象, 训练集和测试集评分均不高.
# 重新测试分割训练集合测试集后的效果
# 点数越多, 拟合越稳定, 效果更稳定
import pandas as pd
kv1 = [100, 200, 500, 1000, 2000]
kv2 = [2, 5, 10, 20, 50]
final_out = []
for sn in kv1:
X, y = make_regression(n_samples=sn, n_features=1,
n_informative=1, noise=50, random_state=8)
output = []
for i in range(100):
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,random_state=i)
scores = []
# 测试分割训练集和测试集
for n in kv2:
reg3 = KNeighborsRegressor(n_neighbors=n)
reg3.fit(X_train, y_train)
scores += [reg3.score(X_train, y_train), reg3.score(X_test, y_test)]
lr2 = LinearRegression()
lr2.fit(X_train, y_train)
scores += [lr2.score(X_train, y_train), lr2.score(X_test, y_test)]
output.append(scores)
final_out.append(pd.DataFrame(output).mean().tolist())
pd.DataFrame(final_out,
columns=pd.MultiIndex.from_product([['k=2', 'k=5', 'k=10','k=20','k=50','LR']
,['train', 'test']]),
index = kv1).round(decimals=3)
多次测试
上述做了个多次测试, 主要对采样训练和测试做了随机100次, 而不同的k, 以及不同的样本数的情况. 从上表中可以看到一个比较奇怪的是500样本时比较反常, 因为此时(随机为8)时, 样本点比较分散, 因此回归和kNN的效果都不甚好, 甚至在kNN中的测试集出现了负数.
从上表也可以看出, 当k较小时, 容易出现过拟合, 当k=5或10时, 其实已经比较稳定了, 继续增大时(k=50)部分就出现欠拟合情况(点多的情况, k=50也开始稳定.)在多次的随机训练可以看出, 线性回归在这里的测试表现最佳, 训练和测试的成功率相当.
500次样本时的点分布书中说, k=2时覆盖更多点, 评分比k=5时显著提高. 这实在说得不科学. 上面测试做了更丰富的结果供参考.
网友评论