一、數(shù)據(jù)說(shuō)明
這次案例還是使用鳶尾花數(shù)據(jù)分類(lèi)的數(shù)據(jù)。
數(shù)據(jù)路徑: /datas/iris.data
數(shù)據(jù)格式:

數(shù)據(jù)解釋?zhuān)?/strong>
iris_feature_E = 'sepal length', 'sepal width', 'petal length', 'petal width'
iris_feature_C = '花萼長(zhǎng)度', '花萼寬度', '花瓣長(zhǎng)度', '花瓣寬度'
iris_class = 'Iris-setosa', 'Iris-versicolor', 'Iris-virginica'
二、開(kāi)始講代碼
1、引入頭文件
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import warnings
from sklearn import tree #決策樹(shù)
from sklearn.tree import DecisionTreeClassifier #分類(lèi)樹(shù)
from sklearn.model_selection import train_test_split#測(cè)試集和訓(xùn)練集
from sklearn.pipeline import Pipeline #管道
from sklearn.feature_selection import SelectKBest #特征選擇
from sklearn.feature_selection import chi2 #卡方統(tǒng)計(jì)量
from sklearn.preprocessing import MinMaxScaler #數(shù)據(jù)歸一化
from sklearn.decomposition import PCA #主成分分析
from sklearn.model_selection import GridSearchCV #網(wǎng)格搜索交叉驗(yàn)證
feature_selection 是做特征選擇的包
feature_selection 中的方法SelectKBest,幫助我們選擇K個(gè)最優(yōu)的特征
feature_selection 中的方法chi2-卡方檢驗(yàn),表示使用chi2的方法幫助我們?cè)?code>SelectKBest中選擇最優(yōu)的K個(gè)最優(yōu)特征。
2、防中文亂碼、去警告、讀取數(shù)據(jù)
## 設(shè)置屬性防止中文亂碼
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
warnings.filterwarnings('ignore', category=FutureWarning)
iris_feature_E = 'sepal length', 'sepal width', 'petal length', 'petal width'
iris_feature_C = '花萼長(zhǎng)度', '花萼寬度', '花瓣長(zhǎng)度', '花瓣寬度'
iris_class = 'Iris-setosa', 'Iris-versicolor', 'Iris-virginica'
#讀取數(shù)據(jù)
path = './datas/iris.data'
data = pd.read_csv(path, header=None)
x=data[list(range(4))]#獲取X變量
y=pd.Categorical(data[4]).codes#把Y轉(zhuǎn)換成分類(lèi)型的0,1,2
print("總樣本數(shù)目:%d;特征屬性數(shù)目:%d" % x.shape)
data.head(5)
總樣本數(shù)目:150;特征屬性數(shù)目:4

x=data[list(range(4))]
取得樣本前四列特殊數(shù)據(jù) '花萼長(zhǎng)度', '花萼寬度', '花瓣長(zhǎng)度', '花瓣寬度'
iris_class = 'Iris-setosa', 'Iris-versicolor', 'Iris-virginica'
y=pd.Categorical(data[4]).codes#把Y轉(zhuǎn)換成分類(lèi)型的0,1,2
將目標(biāo)的三種分類(lèi)轉(zhuǎn)換成0,1,2
PS: 在之前的例子中:04 分類(lèi)算法 - Logistic回歸 - 信貸審批案例,我們自己寫(xiě)過(guò)一個(gè)分類(lèi)的算法對(duì)部分特征進(jìn)行啞編碼操作: parseRecord(record),其實(shí)pandas自己也集成了這個(gè)轉(zhuǎn)換算法:pd.Categorical(data[4]).codes,可以把y直接轉(zhuǎn)換成0,1,2。
以上是數(shù)據(jù)預(yù)處理的步驟,和之前的例子類(lèi)似。
3、數(shù)據(jù)分割(訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù))
x_train1, x_test1, y_train1, y_test1 = train_test_split(x, y,
train_size=0.8, random_state=14)
x_train, x_test, y_train, y_test = x_train1, x_test1, y_train1, y_test1
print ("訓(xùn)練數(shù)據(jù)集樣本數(shù)目:%d,
測(cè)試數(shù)據(jù)集樣本數(shù)目:%d" % (x_train.shape[0], x_test.shape[0]))
#astype:轉(zhuǎn)換數(shù)組的數(shù)據(jù)類(lèi)型。
y_train = y_train.astype(np.int)
y_test = y_test.astype(np.int)
訓(xùn)練數(shù)據(jù)集樣本數(shù)目:120, 測(cè)試數(shù)據(jù)集樣本數(shù)目:30
注意:這個(gè)demo中的案例在這一步還沒(méi)有做KFold-K折交叉驗(yàn)證。當(dāng)前步驟的主要內(nèi)容是對(duì)數(shù)據(jù)進(jìn)行劃分。K折就要生成K個(gè)互斥的子集。KFold的工作就是幫助我們劃分子集的,劃分完后我們將子集扔進(jìn)建模即可。02 分類(lèi)算法 - Logistic案例中提及過(guò)K折交叉驗(yàn)證的內(nèi)容。
4、數(shù)據(jù)標(biāo)準(zhǔn)化和數(shù)據(jù)歸一化的區(qū)別
思考: 行數(shù)據(jù)和列數(shù)據(jù),哪個(gè)服從正態(tài)分布?顯然,列數(shù)據(jù)是特征,和樣本一樣都服從正態(tài)分布。所以數(shù)據(jù)標(biāo)準(zhǔn)化和歸一化的對(duì)象是列。
數(shù)據(jù)標(biāo)準(zhǔn)化:
StandardScaler (基于特征矩陣的列,將屬性值轉(zhuǎn)換至服從正態(tài)分布)
標(biāo)準(zhǔn)化是依照特征矩陣的列處理數(shù)據(jù),其通過(guò)求z-score: z-score=(x-μ)/σ的方法,將樣本的特征值轉(zhuǎn)換到同一量綱下。z-score是N(0,1)正態(tài)分布,即標(biāo)準(zhǔn)正態(tài)分布。
常用與基于正態(tài)分布的算法,比如回歸。
PS:在04 回歸算法 - 最小二乘線性回歸案例中對(duì)ss = StandardScaler()數(shù)據(jù)標(biāo)準(zhǔn)化操作進(jìn)行了深入分析。
數(shù)據(jù)歸一化:
MinMaxScaler (區(qū)間縮放,基于最大最小值,將數(shù)據(jù)轉(zhuǎn)換到0,1區(qū)間上的)
提升模型收斂速度,提升模型精度。
常見(jiàn)用于神經(jīng)網(wǎng)絡(luò)。
Normalizer (基于矩陣的行,將樣本向量轉(zhuǎn)換為單位向量)
其目的在于樣本向量在點(diǎn)乘運(yùn)算或其他核函數(shù)計(jì)算相似性時(shí),擁有統(tǒng)一的標(biāo)準(zhǔn)。
常見(jiàn)用于文本分類(lèi)和聚類(lèi)、logistic回歸中也會(huì)使用,有效防止過(guò)擬合。
#數(shù)據(jù)歸一化
ss = MinMaxScaler ()
#用標(biāo)準(zhǔn)化方法對(duì)數(shù)據(jù)進(jìn)行處理并轉(zhuǎn)換
x_train = ss.fit_transform(x_train)
x_test = ss.transform(x_test)
print ("原始數(shù)據(jù)各個(gè)特征屬性的調(diào)整最小值:",ss.min_)
print ("原始數(shù)據(jù)各個(gè)特征屬性的縮放數(shù)據(jù)值:",ss.scale_)
原始數(shù)據(jù)各個(gè)特征屬性的調(diào)整最小值:
[-1.19444444 -0.83333333 -0.18965517 -0.04166667]
原始數(shù)據(jù)各個(gè)特征屬性的縮放數(shù)據(jù)值:
[ 0.27777778 0.41666667 0.17241379 0.41666667]
5、特征選擇:
特征選擇:從已有的特征中選擇出影響目標(biāo)值最大的特征屬性
特征選擇是一個(gè)transform的過(guò)程
常用方法:
{ 分類(lèi):F統(tǒng)計(jì)量、卡方系數(shù),互信息mutual_info_classif
{ 連續(xù):皮爾遜相關(guān)系數(shù) F統(tǒng)計(jì)量 互信息mutual_info_classif
這里介紹一種特征選擇方法:K方檢驗(yàn) SelectKBest
補(bǔ)充知識(shí):K方檢驗(yàn)
https://baike.baidu.com/item/%E5%8D%A1%E6%96%B9%E6%A3%80%E9%AA%8C/2591853?fr=aladdin
ch2 = SelectKBest(chi2,k=3)這步操作本質(zhì)是一個(gè)Transformer的步驟。Transformer的概念參考05 回歸算法 - 多項(xiàng)式擴(kuò)展、管道Pipeline。
K方檢驗(yàn)的本質(zhì)是:判斷兩個(gè)特征之間的關(guān)聯(lián)程度。
看下面兩個(gè)樣本:
1、男女性別和是否會(huì)化妝的關(guān)聯(lián)性是很強(qiáng)的:
| 是否化妝 / 性別 | 男 | 女 |
|---|---|---|
| 化妝 | 20 | 80 |
| 不化妝 | 90 | 10 |
2、男女性別和是否出門(mén)帶口罩的關(guān)聯(lián)性不強(qiáng):
| 是否帶口罩 / 性別 | 男 | 女 |
|---|---|---|
| 帶 | 55 | 45 |
| 不帶 | 55 | 45 |
但大部分屬性對(duì)結(jié)果的關(guān)聯(lián)性我們很難用常識(shí)去判斷,所以我們可以首先假設(shè)樣本的特征和目標(biāo)無(wú)關(guān)。
假設(shè)性別和是否會(huì)化妝無(wú)關(guān)。因此我們?cè)O(shè)男人中化妝的比例為55%,男人中不化妝的比例是45%
根據(jù)實(shí)際情況進(jìn)行計(jì)算:(列聯(lián)表)
(20-55)2/55 + (90-55)2/55 + (80-45)2/45 + (10-45)2/45
結(jié)果越大,說(shuō)明性別和是否會(huì)化妝的關(guān)聯(lián)程度越大,當(dāng)數(shù)值較大時(shí)我們可以說(shuō)拒絕原假設(shè),即原假設(shè)錯(cuò)誤,真實(shí)情況下性別和是否會(huì)化妝有很大的影響。(越大越拒絕)
如果結(jié)果越小,說(shuō)明假設(shè)正確,我們稱(chēng)之為不拒絕原假設(shè)。
注意: K方統(tǒng)計(jì)用于離散的特征,對(duì)連續(xù)的特征無(wú)效。
#SelectKBest(卡方系數(shù))
#在當(dāng)前的案例中,使用SelectKBest這個(gè)方法
#從4個(gè)原始的特征屬性,選擇出來(lái)3個(gè)
ch2 = SelectKBest(chi2,k=3)
#K默認(rèn)為10
#如果指定了,那么就會(huì)返回你所想要的特征的個(gè)數(shù)
#訓(xùn)練并轉(zhuǎn)換
#chi2卡方檢驗(yàn)對(duì)應(yīng)的是離散特征和目標(biāo)值之間的關(guān)系
#本質(zhì)上不能處理連續(xù)特征和目標(biāo)值的關(guān)系
x_train = ch2.fit_transform(x_train, y_train)
x_test = ch2.transform(x_test)#轉(zhuǎn)換
select_name_index = ch2.get_support(indices=True)
print ("對(duì)類(lèi)別判斷影響最大的三個(gè)特征屬性分布是:",
ch2.get_support(indices=False))
print(select_name_index)
對(duì)類(lèi)別判斷影響最大的三個(gè)特征屬性分布是:
[ True False True True]
[0 2 3]
這里False的屬性就是K方檢驗(yàn)分?jǐn)?shù)最小的那個(gè),如果只取3個(gè)特征,F(xiàn)alse對(duì)應(yīng)的那個(gè)特征就會(huì)被丟棄。
6、模型的構(gòu)建、訓(xùn)練、預(yù)測(cè):
#模型的構(gòu)建
#另外也可選gini
model = DecisionTreeClassifier(criterion='entropy',random_state=0)
#模型訓(xùn)練
model.fit(x_train, y_train)
#模型預(yù)測(cè)
y_test_hat = model.predict(x_test)
#模型結(jié)果的評(píng)估
y_test2 = y_test.reshape(-1)
result = (y_test2 == y_test_hat)
print ("準(zhǔn)確率:%.2f%%" % (np.mean(result) * 100))
#實(shí)際可通過(guò)參數(shù)獲取
print ("Score:", model.score(x_test, y_test))#準(zhǔn)確率
print ("Classes:", model.classes_)
準(zhǔn)確率:96.67%
Score: 0.966666666667
Classes: [0 1 2]
7、畫(huà)圖:
#畫(huà)圖
N = 100 #橫縱各采樣多少個(gè)值
x1_min = np.min((x_train.T[0].min(), x_test.T[0].min()))
x1_max = np.max((x_train.T[0].max(), x_test.T[0].max()))
x2_min = np.min((x_train.T[1].min(), x_test.T[1].min()))
x2_max = np.max((x_train.T[1].max(), x_test.T[1].max()))
t1 = np.linspace(x1_min, x1_max, N)
t2 = np.linspace(x2_min, x2_max, N)
x1, x2 = np.meshgrid(t1, t2) # 生成網(wǎng)格采樣點(diǎn)
x_show = np.dstack((x1.flat, x2.flat))[0] #測(cè)試點(diǎn)
y_show_hat = model.predict(x_show) #預(yù)測(cè)值
y_show_hat = y_show_hat.reshape(x1.shape) #使之與輸入的形狀相同
print(y_show_hat.shape)
y_show_hat[0]

#畫(huà)圖
plt_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
plt_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
plt.figure(facecolor='w')
plt.pcolormesh(x1, x2, y_show_hat, cmap=plt_light) #對(duì)網(wǎng)格點(diǎn)進(jìn)行上色
plt.scatter(x_test.T[0], x_test.T[1], c=y_test.ravel(), edgecolors='k', s=150, zorder=10, marker='*', cmap=plt_dark) # 測(cè)試數(shù)據(jù)
plt.scatter(x_train.T[0], x_train.T[1], c=y_train.ravel(), edgecolors='k', s=40,cmap=plt_dark ) # 全部數(shù)據(jù)
plt.xlabel(u'特征屬性1', fontsize=15)
plt.ylabel(u'特征屬性2', fontsize=15)
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.grid(True)
plt.title(u'鳶尾花數(shù)據(jù)的決策樹(shù)分類(lèi)', fontsize=18)
plt.show()
