摘要: 本文以knn算法為例簡要介紹如何使用分類算法來完成回歸任務(wù)。
關(guān)鍵字: knn算法,回歸任務(wù)。
之前的文章(K近鄰(knn)算法是如何完成分類的?)已經(jīng)介紹了knn算法的思想以及如何使用sklearn去實(shí)現(xiàn)這個(gè)算法了,其實(shí)大多的分類算法也是可以做回歸的,特別是當(dāng)訓(xùn)練數(shù)據(jù)比較多的時(shí)候效果就更加明顯。下面讓我們看看如何使用分類算法來做回歸分析。
本文部分內(nèi)容參考文獻(xiàn)[1]。
1 構(gòu)建回歸分析的數(shù)據(jù)
為了仿真回歸分析,我們也不得不自己構(gòu)造能夠滿足回歸分析的數(shù)據(jù)了。其構(gòu)造如下:
import numpy as np
def makeRegressionData(n_samples=100):
rnd = np.random.RandomState(42) # 設(shè)置偽隨機(jī)狀態(tài)
x = rnd.uniform(-3, 3, size=n_samples) # 隨機(jī)生成范圍在[-3,3) n_samples個(gè)點(diǎn)的隨機(jī)數(shù)
y_no_noise = (np.sin(4 * x) + x) # 目標(biāo)函數(shù)
y = (y_no_noise + rnd.normal(size=len(x))) / 2 # 加入滿足標(biāo)注正太分布的隨機(jī)噪聲
return x.reshape(-1, 1), y
數(shù)據(jù)可視化:
import matplotlib.pyplot as plt
X, y = makeRegressionData(n_samples=40)
plt.plot(X, y, 'o')
plt.ylim(-3, 3)
plt.xlabel('Feature')
plt.ylabel('Target')
plt.show()

2 n鄰居預(yù)測結(jié)果
原理展示圖代碼:
from sklearn.metrics import euclidean_distances
from sklearn.neighbors import KNeighborsRegressor
def plot_knn_regression(X, y, X_test, n_neighbors=1):
dist = euclidean_distances(X, X_test) # 計(jì)算歐式距離
closest = np.argsort(dist, axis=0) # 對(duì)距離進(jìn)行排序
plt.figure(figsize=(10, 6))
# knn回歸
reg = KNeighborsRegressor(n_neighbors=n_neighbors).fit(X, y)
# 預(yù)測值
y_pred = reg.predict(X_test) # 找出預(yù)測值
# 測試點(diǎn)與最近的n個(gè)點(diǎn)之間的連線
for x, y_, neighbors in zip(X_test, y_pred, closest.T):
for neighbor in neighbors[:n_neighbors]:
plt.arrow(x[0], y_, X[neighbor, 0] - x[0], y[neighbor] - y_, head_width=0, fc='k', ec='k')
# 各種數(shù)據(jù)繪制
train, = plt.plot(X, y, 'o', c='#0000aa')
test, = plt.plot(X_test, -3 * np.ones(len(X_test)), '*', c='#50ff50', markersize=20)
pred, = plt.plot(X_test, y_pred, '*', c='#0000aa', markersize=20)
# x, ymin, ymax
plt.vlines(X_test, -3.1, 3.1, linestyle="--")
# 顯示圖例
plt.legend([train, test, pred],
["training data/target", "test data", "test prediction"],
ncol=3, loc=(.1, 1.025))
# 坐標(biāo)軸設(shè)置
plt.ylim(-3.1, 3.1)
plt.xlabel("Feature")
plt.ylabel("Target")
X_test = np.array([[-1.5], [0.9], [1.5]]) # 測試數(shù)據(jù)
plot_knn_regression(X,y,X_test) # k=1
plot_knn_regression(X,y,X_test, n_neighbors=3) # k=3
結(jié)果圖:


注: 特征只有一個(gè),測試數(shù)據(jù)點(diǎn)與數(shù)據(jù)集之間的具體體現(xiàn)在x軸之間的距離
從上圖就可以很容易理解,k近鄰算法回歸分析的思路了,找到最近的幾個(gè)點(diǎn),計(jì)算均值即可。
3 模型使用
有了之前的基礎(chǔ),構(gòu)建一個(gè)模型就簡單多了,如下:
from sklearn.model_selection import train_test_split
# 劃分?jǐn)?shù)據(jù)集
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=40)
# 構(gòu)建模型并訓(xùn)練
reg = KNeighborsRegressor(n_neighbors=3)
reg.fit(X_train, y_train)
"""
KNeighborsRegressor(algorithm='auto', leaf_size=30, metric='minkowski',
metric_params=None, n_jobs=None, n_neighbors=3, p=2,
weights='uniform')
"""
# 模型預(yù)測
print("Test set predictions:n{}".format(reg.predict(X_test)))
"""
Test set predictions:
[ 0.82597372 -0.5856804 0.0836095 -1.02040464 0.41271285 -0.23052151
-1.62784743 -1.62784743 0.82597372 -0.23052151]
"""
print("Test set R^2:{:.2f}".format(reg.score(X_test, y_test)))
"""
Test set R^2:0.71
"""
需要說明的是:在sklearn中使用score來蘋果模型,在回歸問題上,返回的是R^2分?jǐn)?shù),也叫做決定系數(shù),是回歸模型預(yù)測的優(yōu)度度量,位于0與1之間。R^2等于1對(duì)應(yīng)完美預(yù)測。
4 KNeighborsRegressor分析
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
line = np.linspace(-3, 3, 1000).reshape(-1, 1)
for n_neighbors, ax in zip([1, 3, 9], axes):
reg = KNeighborsRegressor(n_neighbors=n_neighbors) # 根據(jù)參數(shù)構(gòu)建模型
reg.fit(X_train, y_train)
ax.plot(line, reg.predict(line)) # 繪制預(yù)測值
# 繪制訓(xùn)練數(shù)據(jù)、測試數(shù)據(jù)
ax.plot(X_train, y_train, '^', c='#0000aa', markersize=8)
ax.plot(X_test, y_test, 'v', c='#ff5050', markersize=8)
ax.set_title("{} neightbor(s)n train score:{:.2f} test score:{:.2f}".format(n_neighbors, reg.score(X_train, y_train), reg.score(X_test, y_test)))
ax.set_xlabel('Feature')
ax.set_ylabel('Target')
axes[0].legend(["Model predictions", "Training data/target", "Test data/target"], loc='best')
繪制結(jié)果如下:

結(jié)果總結(jié):從結(jié)果圖可以看出,當(dāng)僅使用1個(gè)鄰居時(shí),訓(xùn)練集的正確率為100%,測試集得分不高,隨著鄰居個(gè)數(shù)增多,擬合的曲線變得更加平滑,但訓(xùn)練集得分降低,測試集得分先增高后降低。
總結(jié)
KNN模型容易理解,不需要過多的調(diào)節(jié)就可以得到不錯(cuò)的結(jié)果,但如果訓(xùn)練集數(shù)據(jù)比較多,預(yù)測速度就會(huì)變慢,并且還要有比較好的數(shù)據(jù)預(yù)處理。如果要解決的數(shù)據(jù)是稀疏數(shù)據(jù),效果就不好了。當(dāng)然本部分內(nèi)容是參考《Python機(jī)器學(xué)習(xí)基礎(chǔ)教程》內(nèi)容并結(jié)合自己的理解寫出,所以我還是推薦?一下這本書,或者可以在訂閱號(hào)“AIAS編程有道”中回復(fù)“Python機(jī)器學(xué)習(xí)基礎(chǔ)教程”獲取電子檔后決定?是否要購買,建議購買正版書籍。?