隨機森林算法
決策樹算法可以很容易的將模型進行可視化,同時它是將每個樣本特徵進行單獨處理,故而不需要的對數據進行轉換。但是決策樹會很容易出現過擬合,爲了避免過擬合現象,可以使用集合學習的方法,像:隨機森林算法。
隨機森林又被稱爲:隨機決策森林,是一種集合學習方法(參見下圖),既可以用於分類,也可以用作迴歸。分類:在森林內部會進行“投票”,每棵樹預測出數據類別的概率,隨機森林會把這些概率值求平均,讓後將樣本放入概率最大的分類中。迴歸:隨機森林會把所有決策樹預測的值取平均數。
隨機森林算法之所以可以解決過擬合問題:因爲隨機森林是把不同的幾棵決策樹打包到一起,每棵樹的參數都不相同,然後我們把每棵樹預測的結果取平均值,這樣不僅可以保留決策樹工作的高效,又可以降低過擬合的風險。
隨機森林算法可以大致分爲兩個步驟:第一,創建決策樹,第二,根據第一步中決策樹的分類器結果做出預測。隨機森林算法與決策樹算法之間的區別是:前者查找根節點和分割特徵節點的過程是隨機進行的。
- 構建過程:
(1)數據的隨機選取,若訓練集中有個樣本,又放回的隨機抽取個。這個樣本就作爲生成該決策樹的訓練集。
(2)特徵的隨機選取,對於每個樣本,如果有個輸入變量(特徵),指定一個常數,然後隨機的從中選取個最優的分裂特徵開分裂節點。
- 預測過程:
(1)使用每一個隨機創建的決策樹的規則來測試特徵的結果(標籤)
(2)計算每個預測目標的票數
(3)獲得票數最高的結果將作爲隨機森林算法的最終預測。
注:隨機森林算法也不要求對數據進行預處理,同時支持並行處理。此外,隨機森林生成每一棵決策樹的方法是隨機的,則不同的random_state參數會導致模型完全不同,所以爲了模型的相對穩定,要固化random_state這個參數的值。但是!!!隨機森林,對於高維數據集、稀疏數據集來說,很不適應。
構建決策樹
author by xiaoyao
# 導入libraries
import numpy as np
# 導入畫圖工具
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
# 導入tree模型和數據集加載工具
from sklearn import datasets
from sklearn.ensemble import RandomForestClassifier
# 導入數據集拆分工具
from sklearn.model_selection import train_test_split
wine = datasets.load_wine()
# 這裏只選取數據集的前兩個特徵
X = wine.data[:,:2]
y = wine.target
# 將數據集劃分爲訓練集個測試集
X_train, X_test, y_train, y_test = train_test_split(X, y)
# 忽略警告
import warnings
warnings.filterwarnings("ignore")
# 暫時設定隨機森林中有6棵樹
forest = RandomForestClassifier(n_estimators=6, random_state=3)
# 使用模型擬合數據
forest.fit(X_train, y_train)
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
max_depth=None, max_features='auto', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=6,
n_jobs=None, oob_score=False, random_state=3, verbose=0,
warm_start=False)
其中,bootstrap參數:代表的是bootstrap sample。也就是又放回抽樣,bootstrap生成的數據集和原始數據集在數據量上是一致的,但由於進行了重複採樣,因此其中有一些數據點會丟失。通過重新生成數據集,可以讓隨機森林中的每一棵決策樹在構建的時候,彼此之間有差異。max_features的取值越高,隨機森林中的每一棵樹就會"越相似",從而因爲有更多的不同特徵值可以取,也就會更容易取擬合數據。
# 定義圖像中分區的顏色和散點的顏色
cmap_light = ListedColormap(["#FFAAAA", "#AAFFAA", "#AAAAFF"])
cmap_bold = ListedColormap(["#FF0000", "#00FF00", "#0000FF"])
# 分別用樣本的兩個特徵值創建圖像和橫軸、縱軸
x_min, x_max = X_train[:,0].min() - 1, X_train[:,0].max() + 1
y_min, y_max = X_train[:,1].min() - 1, X_train[:,1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, .02),np.arange(y_min, y_max, .02))
z = forest.predict(np.c_[xx.ravel(), yy.ravel()])
# 給每個分類中的樣本分配不同的顏色
z = z.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx, yy, z, cmap=cmap_light)
# 使用散點圖進行表示
plt.scatter(X[:,0], X[:,1], c=y, cmap=cmap_bold, edgecolor="k",s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("Classifier:(max_depth = 3)")
plt.show()
隨機森林實例
author by xiaoyao
# 導入相應的libraries
import pandas as pd
from sklearn import tree
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
# 忽略警告
import warnings
warnings.filterwarnings("ignore")
# 導入數據集,數據集下載地址:http://archive.ics.uci.edu/ml/machine-learning-databases/adult/
# 原始數據無列名(屬性名)
data = pd.read_csv("./datasets/adult.csv", header=None,index_col=False,
names=['年齡','單位性質','權重','學歷','受教育時常',
'婚姻狀況','職業','家庭情況','種族','性別',
'資產所得','資產損失','周工作時長','原籍','收入'])
data.head()
年齡 | 單位性質 | 權重 | 學歷 | 受教育時常 | 婚姻狀況 | 職業 | 家庭情況 | 種族 | 性別 | 資產所得 | 資產損失 | 周工作時長 | 原籍 | 收入 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 39 | State-gov | 77516 | Bachelors | 13 | Never-married | Adm-clerical | Not-in-family | White | Male | 2174 | 0 | 40 | United-States | <=50K |
1 | 50 | Self-emp-not-inc | 83311 | Bachelors | 13 | Married-civ-spouse | Exec-managerial | Husband | White | Male | 0 | 0 | 13 | United-States | <=50K |
2 | 38 | Private | 215646 | HS-grad | 9 | Divorced | Handlers-cleaners | Not-in-family | White | Male | 0 | 0 | 40 | United-States | <=50K |
3 | 53 | Private | 234721 | 11th | 7 | Married-civ-spouse | Handlers-cleaners | Husband | Black | Male | 0 | 0 | 40 | United-States | <=50K |
4 | 28 | Private | 338409 | Bachelors | 13 | Married-civ-spouse | Prof-specialty | Wife | Black | Female | 0 | 0 | 40 | Cuba | <=50K |
import pandas_profiling
rep = pandas_profiling.ProfileReport(data)
# 將生成的數據分析報告保存至本地html文件
rep.to_file("./rep.html")
報告具體形式:
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 32561 entries, 0 to 32560
Data columns (total 15 columns):
年齡 32561 non-null int64
單位性質 32561 non-null object
權重 32561 non-null int64
學歷 32561 non-null object
受教育時常 32561 non-null int64
婚姻狀況 32561 non-null object
職業 32561 non-null object
家庭情況 32561 non-null object
種族 32561 non-null object
性別 32561 non-null object
資產所得 32561 non-null int64
資產損失 32561 non-null int64
周工作時長 32561 non-null int64
原籍 32561 non-null object
收入 32561 non-null object
dtypes: int64(6), object(9)
memory usage: 3.7+ MB
可以看到在數據集中,很多的列取值都是字符串,不方便進行建模。我將其處理爲:整型數值,操作如下:
# 使用get_dummies將文本數據轉化爲數值
data_dummies = pd.get_dummies(data)
# 分別輸出原始特徵和處理之後的特徵
print("原始特徵:",(data.columns))
print("處理後的特徵:",(data_dummies.columns))
原始特徵: Index(['年齡', '單位性質', '權重', '學歷', '受教育時常', '婚姻狀況', '職業', '家庭情況', '種族', '性別',
'資產所得', '資產損失', '周工作時長', '原籍', '收入'],
dtype='object')
處理後的特徵: Index(['年齡', '權重', '受教育時常', '資產所得', '資產損失', '周工作時長', '單位性質_ ?',
'單位性質_ Federal-gov', '單位性質_ Local-gov', '單位性質_ Never-worked',
...
'原籍_ Scotland', '原籍_ South', '原籍_ Taiwan', '原籍_ Thailand',
'原籍_ Trinadad&Tobago', '原籍_ United-States', '原籍_ Vietnam',
'原籍_ Yugoslavia', '收入_ <=50K', '收入_ >50K'],
dtype='object', length=110)
data.head()
年齡 | 單位性質 | 權重 | 學歷 | 受教育時常 | 婚姻狀況 | 職業 | 家庭情況 | 種族 | 性別 | 資產所得 | 資產損失 | 周工作時長 | 原籍 | 收入 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 39 | State-gov | 77516 | Bachelors | 13 | Never-married | Adm-clerical | Not-in-family | White | Male | 2174 | 0 | 40 | United-States | <=50K |
1 | 50 | Self-emp-not-inc | 83311 | Bachelors | 13 | Married-civ-spouse | Exec-managerial | Husband | White | Male | 0 | 0 | 13 | United-States | <=50K |
2 | 38 | Private | 215646 | HS-grad | 9 | Divorced | Handlers-cleaners | Not-in-family | White | Male | 0 | 0 | 40 | United-States | <=50K |
3 | 53 | Private | 234721 | 11th | 7 | Married-civ-spouse | Handlers-cleaners | Husband | Black | Male | 0 | 0 | 40 | United-States | <=50K |
4 | 28 | Private | 338409 | Bachelors | 13 | Married-civ-spouse | Prof-specialty | Wife | Black | Female | 0 | 0 | 40 | Cuba | <=50K |
data_dummies.head()
年齡 | 權重 | 受教育時常 | 資產所得 | 資產損失 | 周工作時長 | 單位性質_ ? | 單位性質_ Federal-gov | 單位性質_ Local-gov | 單位性質_ Never-worked | ... | 原籍_ Scotland | 原籍_ South | 原籍_ Taiwan | 原籍_ Thailand | 原籍_ Trinadad&Tobago | 原籍_ United-States | 原籍_ Vietnam | 原籍_ Yugoslavia | 收入_ <=50K | 收入_ >50K | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 39 | 77516 | 13 | 2174 | 0 | 40 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
1 | 50 | 83311 | 13 | 0 | 0 | 13 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
2 | 38 | 215646 | 9 | 0 | 0 | 40 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
3 | 53 | 234721 | 7 | 0 | 0 | 40 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
4 | 28 | 338409 | 13 | 0 | 0 | 40 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
5 rows × 110 columns
將各列分配給特徵向量和分類標籤
# 定義數據集的特徵值
features = data_dummies.loc[:, '年齡':'原籍_ Yugoslavia']
X = features.values
# 將收入大於50k作爲預測的目標
y = data_dummies['收入_ >50K'].values
# 輸出特徵與標籤的形態
print("特徵形態:{} 標籤形態:{}".format(X.shape, y.shape))
特徵形態:(32561, 108) 標籤形態:(32561,)
# 先使用決策數模型進行預測
# 將數據拆分爲訓練集和測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 1)
# 設最大深度爲5
dt_tree =tree.DecisionTreeClassifier(max_depth=5)
dt_tree.fit(X_train, y_train)
dt_tree.score(X_test, y_test)
0.8550546615894853
# 使用交叉驗證,平均水平依然接近上面的
from sklearn.model_selection import cross_val_score
scores = cross_val_score(dt_tree, X, y, cv=20,scoring='accuracy')
print(scores)
print(scores.mean())
[0.83977901 0.84275184 0.8482801 0.84336609 0.85012285 0.8531941
0.82555283 0.84398034 0.8458231 0.85380835 0.85995086 0.83783784
0.85257985 0.84889435 0.86425061 0.85257985 0.8507371 0.86302211
0.84766585 0.84643735]
0.8485307193180122
# 使用隨機森林算法
forest = RandomForestClassifier(n_estimators = 5,random_state=0)
forest.fit(X_train, y_train)
forest.score(X_test, y_test)
0.8431396634320109
# 使用交叉驗證
scores = cross_val_score(forest, X, y,cv=5,scoring='accuracy')
print(scores)
print(scores.mean())
[0.82320442 0.83968059 0.83230958 0.84336609 0.82862408 0.85012285
0.82678133 0.8458231 0.84336609 0.83108108 0.83722359 0.83046683
0.84336609 0.83599509 0.8482801 0.84213759 0.84766585 0.85257985
0.83169533 0.84459459]
0.8389182062524604