(本文所使用的Python庫和版本號: Python 3.5, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )git
分類問題,就是將數據點按照不一樣的類別區分開來,所謂人以類聚,物以羣分,就是這個道理。之前的【機器學習001-007】都是講解的迴歸問題,二者的不一樣之處在於:迴歸輸出的結果是實數,而且通常是連續的實數值,而分類問題的輸出結果是離散的某一個類別或不一樣類別的機率。github
最簡單的分類問題是二元分類,將整個樣本劃分爲兩個類別,好比將整我的類分爲男人和女人(泰國人妖不在考慮範圍內,呵呵)。稍微複雜一點的分類問題是多元分類,它將整個樣本劃分爲多個(通常大於兩個)不一樣類別,好比將家禽數據集能夠劃分爲:雞,鴨,鵝等,將家畜樣本劃分爲:狗,豬,牛,羊等等。dom
下面從一個最簡單的二元分類問題入手,看看二元分類器是如何構建的。機器學習
因爲二元分類問題比較簡單,此處咱們本身構建了一些數據點,並將這些數據點按照不一樣類別放入不一樣變量中,好比把全部第0類別的數據點都放置到class_0中,把全部第1類別的數據點放入class_1中,以下所示。學習
# 首先準備數據集
# 特徵向量
X = np.array([[3,1], [2,5], [1,8], [6,4], [5,2], [3,5], [4,7], [4,-1]]) # 自定義的數據集
# 標記
y = [0, 1, 1, 0, 0, 1, 1, 0]
# 因爲標記中只含有兩類,故而將特徵向量按照標記分割成兩部分
class_0=np.array([feature for (feature,label) in zip(X,y) if label==0])
print(class_0) # 確保沒有問題
class_1=np.array([feature for (feature,label) in zip(X,y) if label==1])
print(class_1)
# 劃分也能夠採用以下方法:兩個打印後結果同樣
# class_0=np.array([X[i] for i in range(len(X)) if y[i]==0])
# print(class_0)
# class_1=np.array([X[i] for i in range(len(X)) if y[i]==1])
# print(class_1)
複製代碼
-------------------------------------輸---------出--------------------------------測試
[[ 3 1] [ 6 4] [ 5 2] [ 4 -1]] [[2 5] [1 8] [3 5] [4 7]]spa
--------------------------------------------完-------------------------------------code
上面雖然構建了數據點,可是難以直觀的看清這個二分類問題的數據點有什麼特色,因此爲了有更加直觀的認識,通常會把數據點的散點圖畫出來,以下所示:orm
# 在圖中畫出這兩個不一樣類別的數據集,方便觀察不一樣類別數據的特色
plt.figure()
plt.scatter(class_0[:,0],class_0[:,1],marker='s',label='class_0')
plt.scatter(class_1[:,0],class_1[:,1],marker='x',label='class_1')
plt.legend()
複製代碼
########################小**********結###############################cdn
1,本次研究的二分類問題是極其簡單的分類問題,故而構建了8個樣本的兩個類別的數據點,每一個類別有四個點。
2,爲了更加直觀的查看數據點的分佈特色,通常咱們要把數據點畫在平面上,對數據點的分佈狀況有一個初步的瞭解,便於後面咱們採用哪一種分類器。
3,本次構建的數據集是由8行2列構成的特徵矩陣,即8個樣本,每一個樣本有兩個features.
#################################################################
所謂線性可分問題,是指在平面上能夠經過一條直線(或更高維度上的,一個平面)來將全部數據點劃分開來的問題,「能夠用直線分開」是線性可分問題的本質。相對應的,「不能夠用直線分開」即是線性不可分問題的本質,對於線性不可分問題,須要用曲線或曲面來將這些數據分開,對應的就是非線性問題。好比,上面本身定義的數據集能夠用簡單的直線劃分開來,好比能夠採用y=x這條直線分開,以下所示:
# 從上面圖中能夠看出,能夠畫一條直線輕鬆的將class_0和class_1兩個數據點分開
# 其實有不少直線能夠起到分類器的效果,此處咱們只用最簡單的y=x做爲演示
plt.figure()
plt.scatter(class_0[:,0],class_0[:,1],marker='s',label='class_0')
plt.scatter(class_1[:,0],class_1[:,1],marker='x',label='class_1')
plt.plot(range(10),range(10),label='line_classifier') # 此處x=range(10), y=x
plt.legend()
複製代碼
實際上,能夠採用很是多的直線來將本數據集的兩個類別區分開來,以下圖所示,這些直線是在斜率和截距上稍微調整而來。
那麼,這麼多直線均可以解決簡單分類問題,確定會有一條最佳直線,可以達到最佳的分類效果。下面,使用sklearn模塊中的SGD分類器構建最佳直線分類器。以下代碼:
# 上面雖然隨機的選擇了一條直線(y=x)做爲分類器,但不少時候咱們不知道分類
# 下面構建一個SGD分類器,它使用隨機梯度降低法來訓練
# 訓練以前須要對數據進行標準化,保證每一個維度的特徵數據方差爲1,均值爲0,避免某個特徵值過大而成爲影響分類的主因
from sklearn.preprocessing import StandardScaler
ss=StandardScaler()
X_train=ss.fit_transform(X) # 因爲本項目數據集太少,故而所有用來train
# 構建SGD分類器進行訓練
from sklearn.linear_model import SGDClassifier
sgdClassifier=SGDClassifier(random_state=42)
sgdClassifier.fit(X_train,y) # y做爲label已是0,1形式,不需進一步處理
# 使用訓練好的SGD分類器對陌生數據進行分類
X_test=np.array([[3,2],[2,3],[2.5,2.4],[2.4,2.5],[5,8],[6.2,5.9]])
X_test=ss.fit_transform(X_test) # test set也要記過一樣的處理
test_predicted=sgdClassifier.predict(X_test)
print(test_predicted)
複製代碼
-------------------------------------輸---------出--------------------------------
[0 1 1 1 1 0]
--------------------------------------------完-------------------------------------
########################小**********結###############################
1,使用sklearn中的SGDClassifier能夠對數據集進行簡單的線性分類,達到比較好的分類效果。
2,在數據集的特徵上,貌似x>y時,數據屬於class_0, 而x<y時,數據屬於class_1,SGDClassifier模型在測試數據集上也基本可以正確劃分,只有在x和y大致相等的關鍵點處容易出現錯誤判斷。
#################################################################
注:本部分代碼已經所有上傳到(個人github)上,歡迎下載。
參考資料:
1, Python機器學習經典實例,Prateek Joshi著,陶俊傑,陳小莉譯