在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

深入淺出地介紹集成、Bagging、隨機森林、特征重要性

zhKF_jqr_AI ? 來源:未知 ? 作者:胡薇 ? 2018-05-25 09:51 ? 次閱讀

現在,假設你已經為某一特定問題選中了最佳的模型,并在進一步提升其精確度上遇到了困難。在這一情形下,你將需要應用一些更高級的機器學習技術——集成(ensemble)。

集成是一組協作貢獻的元素。一個熟悉的例子是合奏,組合不同的樂器創建動聽的和聲。在集成中,最終的整體輸出比任何單個部分的表現更重要。

1. 集成

某種意義上,孔多塞陪審團定理描述了我們之前提到的集成。該定理的內容為,如果評審團的每個成員做出獨立判斷,并且每個陪審員做出正確決策的概率高于0.5,那么整個評審團做出正確的總體決策的概率隨著陪審員數量的增加而增加,并趨向于一。另一方面,如果每個陪審員判斷正確的概率小于0.5,那么整個陪審團做出正確的總體決策的概率隨著陪審員數量的增加而減少,并趨向于零。

該定理形式化的表述為:

N為陪審員總數;

m是構成多數的最小值,即m= (N+1)/2;

p為評審員做出正確決策的概率;

μ是整個評審團做出正確決策的概率。

則:

由上式可知,若p > 0.5,則μ > p。此外,若N -> ∞,則μ -> 1。

讓我們看另一個集成的例子:群體的智慧。1906年,Francis Galton訪問了普利茅斯的一個農村集市,在那里他看到一項競賽。800個參與者嘗試估計一頭屠宰的牛的重量。真實重量為1198磅。盡管沒人猜中這一數值,所有參與者的預測的平均值為1197磅。

機器學習領域采用類似的思路以降低誤差。

2. Bootstraping

Leo Breiman于1994年提出的Bagging(又稱Bootstrap aggregation,引導聚集)是最基本的集成技術之一。Bagging基于統計學中的bootstraping(自助法),該方法使得評估許多復雜模型的統計數據更可行。

bootstrap方法的流程如下:假設有尺寸為N的樣本X。我們可以從該樣本中有放回地隨機均勻抽取N個樣本,以創建一個新樣本。換句話說,我們從尺寸為N的原樣本中隨機選擇一個元素,并重復此過程N次。選中所有元素的可能性是一樣的,因此每個元素被抽中的概率均為1/N。

假設我們從一個袋子中抽球,每次抽一個。在每一步中,將選中的球放回袋子,這樣下一次抽取是等概率的,即,從同樣數量的N個球中抽取。注意,因為我們把球放回了,新樣本中可能有重復的球。讓我們把這個新樣本稱為X1。

重復這一過程M次,我們創建M個bootstrap樣本X1,……,XM。最后,我們有了足夠數量的樣本,可以計算原始分布的多種統計數據。

讓我們看一個例子,我們將使用之前的telecom_churn數據集。我們曾經討論過這一數據集的特征重要性,其中最重要的特征之一是呼叫客服次數。讓我們可視化這一數據,看看該特征的分布。

import pandas as pd

from matplotlib import pyplot as plt

plt.style.use('ggplot')

plt.rcParams['figure.figsize'] = 10, 6

import seaborn as sns

%matplotlib inline

telecom_data = pd.read_csv('../../data/telecom_churn.csv')

fig = sns.kdeplot(telecom_data[telecom_data['Churn'] == False]['Customer service calls'],

label = 'Loyal')

fig = sns.kdeplot(telecom_data[telecom_data['Churn'] == True]['Customer service calls'],

label = 'Churn')

fig.set(xlabel='Number of calls', ylabel='Density')

plt.show()

如你所見,相比那些逐漸離網的客戶,忠實客戶呼叫客服的次數更少。估計每組客戶的平均呼叫客服數可能是個好主意。由于我們的數據集很小,如果直接計算原樣本的均值,我們得到的估計可能不好。因此我們將應用bootstrap方法。讓我們基于原樣本生成1000新bootstrap樣本,然后計算均值的區間估計。

import numpy as np

def get_bootstrap_samples(data, n_samples):

"""使用bootstrap方法生成bootstrap樣本。"""

indices = np.random.randint(0, len(data), (n_samples, len(data)))

samples = data[indices]

return samples

def stat_intervals(stat, alpha):

"""生成區間估計。"""

boundaries = np.percentile(stat, [100 * alpha / 2., 100 * (1 - alpha / 2.)])

return boundaries

分割數據集,分組為忠實客戶和離網客戶:

loyal_calls = telecom_data[telecom_data['Churn']

== False]['Customer service calls'].values

churn_calls= telecom_data[telecom_data['Churn']

== True]['Customer service calls'].values

固定隨機數種子,以得到可重現的結果。

np.random.seed(0)

使用bootstrap生成樣本,計算各自的均值。

loyal_mean_scores = [np.mean(sample)

for sample in get_bootstrap_samples(loyal_calls, 1000)]

churn_mean_scores = [np.mean(sample)

for sample in get_bootstrap_samples(churn_calls, 1000)]

打印區間估計值。

print("忠實客戶呼叫客服數: 均值區間",

stat_intervals(loyal_mean_scores, 0.05))

print("離網客戶呼叫客服數:均值區間",

stat_intervals(churn_mean_scores, 0.05))

結果:

忠實客戶呼叫客服數: 均值區間 [1.40771931.49473684]

離網客戶呼叫客服數:均值區間 [2.06211182.39761905]

因此,我們看到,有95%的概率,忠實客戶平均呼叫客服的次數在1.4到1.49之間,而離網客戶平均呼叫客服的次數在2.06到2.40之間。另外,注意忠實客戶的區間更窄,這是合理的,因為,相比多次呼叫客服,最終受夠了轉換運營商的離網客戶,忠實客戶呼叫客服的次數更少(0、1、2)。

3. Bagging

理解了bootstrap概念之后,我們來介紹bagging。

假設我們有一個訓練集X。我們使用bootstrap生成樣本X1, ..., XM。現在,我們在每個bootstrap樣本上分別訓練分類器ai(x)。最終分類器將對所有這些單獨的分類器的輸出取均值。在分類情形下,該技術對應投票(voting):

在回歸問題中,通過對回歸結果取均值,bagging將均方誤差降至1/M(M為回歸器數量)。

回顧一下上一課的內容,模型的預測誤差有三部分構成:

bagging通過在不同數據集上訓練模型降低分類器的方差。換句話說,bagging可以預防過擬合。bagging的有效性來自不同訓練數據集上單獨模型的不同,它們的誤差在投票過程中相互抵消。此外,某些bootstrap訓練樣本很可能略去離散值。

讓我們看下bagging的實際效果,并與決策樹比較下。我們將使用sklearn文檔中的一個例子。

從上圖可以看到,就bagging而言,誤差中的方差顯著降低了。

上面的例子不太可能在實際工作中出現。因為我們做了一個很強的假定,單獨誤差是不相關的。對現實世界的應用而言,這經常是過于樂觀了。當這個假定為假時,誤差的下降不會那么顯著。在后續課程中,我們將討論一些更復雜的集成方法,能夠在現實世界的問題中做出更精確的預測。

4. 袋外誤差

隨機森林不需要使用交叉驗證或留置樣本,因為在這一集成技術內置了誤差估計。

隨機森林中的決策樹基于原始數據集中不同的bootstrap樣本構建。對第K棵樹而言,其特定bootstrap樣本大約留置了37%的輸入。

這很容易證明。設數據集中有l個樣本。在每一步,每個數據點最終出現在有放回的bootstrap樣本中的概率均為1/l。bootstrap樣本最終不包含特定數據集元素的概率(即,該元素在l次抽取中都沒抽中)等于(1 - 1/l)l。當l -> +∞時,這一概率等于1/e。因此,選中某一特定樣本的概率為1 - 1/e,約等于63%。

下面讓我們可視化袋外誤差(Out-of-BagError,OOBE)估計是如何工作的:

示意圖上方為原始數據集。我們將其分為訓練集(左)和測試集(右)。在測試集上,我們繪制一副網格,完美地實施了分類。現在,我們應用同一副網格于測試集,以估計分類的正確率。我們可以看到,分類器在4個未曾在訓練中使用的數據點上給出了錯誤的答案。而測試集中共有15個數據點,這15個數據點未在訓練中使用。因此,我們的分類器的精確度為11/15 * 100% = 73.33%.

總結一下,每個基礎算法在約63%的原始樣本上訓練。該算法可以在剩下的約37%的樣本上驗證。袋外估計不過是基礎算法在訓練過程中留置出來的約37%的輸入上的平均估計。

5. 隨機森林

Leo Breiman不僅將bootstrap應用于統計,同時也將其應用于機器學習。他和Adel Cutler擴展并改進了Tin Kam Ho提出的的隨機森林算法。他們組合使用CART、bagging、隨機子空間方法構建無關樹。

在bagging中,決策樹是一個基礎分類器的好選項,因為它們相當復雜,并能在任何樣本上達到零分類誤差。隨機子空間方法降低樹的相關性,從而避免過擬合。基于bagging,基礎算法在不同的原始特征集的隨機子集上訓練。

以下算法使用隨機子空間方法構建模型集成:

設樣本數等于n,特征維度數等于d。

選擇集成中單個模型的數目M。

對于每個模型m,選擇特征數dm < d。所有模型使用相同的dm值。

對每個模型m,通過在整個d特征集合上隨機選擇dm個特征創建一個訓練集。

訓練每個模型。

通過組合M中的所有模型的結果,應用所得集成模型于新輸入。可以使用大多數投票(majority voting)或后驗概率加總(aggregation of the posterior probabilities)。

5.1 算法

構建N樹隨機森林的算法如下:

對每個k = 1, ..., N:

生成bootstrap樣本Xk。

在樣本Xk上創建一棵決策樹bk:

根據給定的標準選擇最佳的特征維度。根據該特征分割樣本以創建樹的新層次。重復這一流程,直到竭盡樣本。

創建樹,直到任何葉節點包含不超過nmin個實例,或者達到特定深度。

對每個分割,我們首先從d個原始特征中隨機選擇m個特征,接著只在該子集上搜索最佳分割。

最終分類器定義為:

分類問題使用多數投票,回歸問題使用均值。

在分類問題中,建議將m設定為d的平方根,取nmin= 1。回歸問題中,一般取m = d/3,nmin= 5。

你可以將隨機森林看成決策樹bagging加上一個改動,在每個分割處選擇一個隨機特征子空間。

5.2 與決策樹和bagging的比較

導入所需包,配置環境:

import warnings

import numpy as np

warnings.filterwarnings('ignore')

%matplotlib inline

from matplotlib import pyplot as plt

plt.style.use('ggplot')

plt.rcParams['figure.figsize'] = 10, 6

import seaborn as sns

from sklearn.ensemble importRandomForestRegressor, RandomForestClassifier

from sklearn.ensemble importBaggingClassifier, BaggingRegressor

from sklearn.tree importDecisionTreeRegressor, DecisionTreeClassifier

from sklearn.datasets import make_circles

from sklearn.model_selection import train_test_split

n_train = 150

n_test = 1000

noise = 0.1

生成數據:

def f(x):

x = x.ravel()

return np.exp(-x ** 2) + 1.5 * np.exp(-(x - 2) ** 2)

def generate(n_samples, noise):

X = np.random.rand(n_samples) * 10 - 5

X = np.sort(X).ravel()

y = np.exp(-X ** 2) + 1.5 * np.exp(-(X - 2) ** 2)\

+ np.random.normal(0.0, noise, n_samples)

X = X.reshape((n_samples, 1))

return X, y

X_train, y_train = generate(n_samples=n_train, noise=noise)

X_test, y_test = generate(n_samples=n_test, noise=noise)

單棵決策樹回歸:

dtree = DecisionTreeRegressor().fit(X_train, y_train)

d_predict = dtree.predict(X_test)

plt.figure(figsize=(10, 6))

plt.plot(X_test, f(X_test), "b")

plt.scatter(X_train, y_train, c="b", s=20)

plt.plot(X_test, d_predict, "g", lw=2)

plt.xlim([-5, 5])

plt.title("Decision tree, MSE = %.2f"

% np.sum((y_test - d_predict) ** 2))

決策樹回歸bagging:

bdt = BaggingRegressor(DecisionTreeRegressor()).fit(X_train, y_train)

bdt_predict = bdt.predict(X_test)

plt.figure(figsize=(10, 6))

plt.plot(X_test, f(X_test), "b")

plt.scatter(X_train, y_train, c="b", s=20)

plt.plot(X_test, bdt_predict, "y", lw=2)

plt.xlim([-5, 5])

plt.title("Bagging for decision trees, MSE = %.2f" % np.sum((y_test - bdt_predict) ** 2));

隨機森林:

rf = RandomForestRegressor(n_estimators=10).fit(X_train, y_train)

rf_predict = rf.predict(X_test)

plt.figure(figsize=(10, 6))

plt.plot(X_test, f(X_test), "b")

plt.scatter(X_train, y_train, c="b", s=20)

plt.plot(X_test, rf_predict, "r", lw=2)

plt.xlim([-5, 5])

plt.title("Random forest, MSE = %.2f" % np.sum((y_test - rf_predict) ** 2));

從上面的圖像和MSE值可以看到,10樹隨機森林比單棵決策樹和10樹bagging的表現要好。(譯者注:實際上,在這個例子中,隨機森林的表現并不穩定,多次運行的結果是,隨機森林和bagging互有勝負。)隨機森林和bagging的主要差別在于,在隨機森林中,分割的最佳特征是從一個隨機特征子空間中選取的,而在bagging中,分割時將考慮所有特征。

接下來,我們將查看隨機森林和bagging在分類問題上的表現:

np.random.seed(42)

X, y = make_circles(n_samples=500, factor=0.1, noise=0.35, random_state=42)

X_train_circles, X_test_circles, y_train_circles, y_test_circles = train_test_split(X, y, test_size=0.2)

dtree = DecisionTreeClassifier(random_state=42)

dtree.fit(X_train_circles, y_train_circles)

x_range = np.linspace(X.min(), X.max(), 100)

xx1, xx2 = np.meshgrid(x_range, x_range)

y_hat = dtree.predict(np.c_[xx1.ravel(), xx2.ravel()])

y_hat = y_hat.reshape(xx1.shape)

plt.contourf(xx1, xx2, y_hat, alpha=0.2)

plt.scatter(X[:,0], X[:,1], c=y, cmap='autumn')

plt.title("Decision tree")

plt.show()

b_dtree = BaggingClassifier(DecisionTreeClassifier(),n_estimators=300, random_state=42)

b_dtree.fit(X_train_circles, y_train_circles)

x_range = np.linspace(X.min(), X.max(), 100)

xx1, xx2 = np.meshgrid(x_range, x_range)

y_hat = b_dtree.predict(np.c_[xx1.ravel(), xx2.ravel()])

y_hat = y_hat.reshape(xx1.shape)

plt.contourf(xx1, xx2, y_hat, alpha=0.2)

plt.scatter(X[:,0], X[:,1], c=y, cmap='autumn')

plt.title("Bagging (decision trees)")

plt.show()

rf = RandomForestClassifier(n_estimators=300, random_state=42)

rf.fit(X_train_circles, y_train_circles)

x_range = np.linspace(X.min(), X.max(), 100)

xx1, xx2 = np.meshgrid(x_range, x_range)

y_hat = rf.predict(np.c_[xx1.ravel(), xx2.ravel()])

y_hat = y_hat.reshape(xx1.shape)

plt.contourf(xx1, xx2, y_hat, alpha=0.2)

plt.scatter(X[:,0], X[:,1], c=y, cmap='autumn')

plt.title("Random forest")

plt.show()

上圖顯示了決策樹判定的邊界相當凹凸不平,有大量銳角,這暗示了過擬合,概括性差。相反,隨機森林和bagging的邊界相當平滑,沒有明顯的過擬合的跡象。

現在,讓我們查看一些有助于提高模型精確度的參數

5.3 參數

scikit-learn庫提供了BaggingRegressor和BaggingClassifier。

下面是創建新模型時需要注意的一些參數:

n_estimators是森林中樹的數量;

criterion是衡量分割質量的函數;

max_features是查找最佳分割時考慮的特征數;

min_samples_leaf是葉節點的最小樣本數;

max_depth是樹的最大深度。

在真實問題中練習隨機森林

我們將使用之前的離網預測作為例子。這是一個分類問題,我們將使用精確度評估模型。

import pandas as pd

from sklearn.model_selection import cross_val_score, StratifiedKFold, GridSearchCV

from sklearn.metrics import accuracy_score

df = pd.read_csv("../../data/telecom_churn.csv")

首先,讓我們創建一個簡單的分類器作為基線。出于簡單性,我們將只使用數值特征。

cols = []

for i in df.columns:

if (df[i].dtype == "float64") or (df[i].dtype == 'int64'):

cols.append(i)

分離數據集為輸入和目標:

X, y = df[cols].copy(), np.asarray(df["Churn"],dtype='int8')

為驗證過程進行分層分割:

skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

基于默認參數初始化分類器:

rfc = RandomForestClassifier(random_state=42, n_jobs=-1, oob_score=True)

在訓練集上進行訓練:

results = cross_val_score(rfc, X, y, cv=skf)

在測試集上評估精確度:

print("交叉驗證精確度評分: {:.2f}%".format(results.mean()*100))

結果:

交叉驗證精確度評分:91.48%

現在,讓我們嘗試改進結果,同時查看下修改基本參數時學習曲線的表現。

讓我們從樹的數量開始:

skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

創建列表儲存訓練集和測試集上的精確度數值:

train_acc = []

test_acc = []

temp_train_acc = []

temp_test_acc = []

進行網格搜索:

trees_grid = [5, 10, 15, 20, 30, 50, 75, 100]

在訓練集上訓練:

for ntrees in trees_grid:

rfc = RandomForestClassifier(n_estimators=ntrees, random_state=42, n_jobs=-1, oob_score=True)

temp_train_acc = []

temp_test_acc = []

for train_index, test_index in skf.split(X, y):

X_train, X_test = X.iloc[train_index], X.iloc[test_index]

y_train, y_test = y[train_index], y[test_index]

rfc.fit(X_train, y_train)

temp_train_acc.append(rfc.score(X_train, y_train))

temp_test_acc.append(rfc.score(X_test, y_test))

train_acc.append(temp_train_acc)

test_acc.append(temp_test_acc)

打印結果:

train_acc, test_acc = np.asarray(train_acc), np.asarray(test_acc)

print("交叉驗證最佳精確度為 {:.2f}% 在 {} 樹時達到".format(max(test_acc.mean(axis=1))*100,

trees_grid[np.argmax(test_acc.mean(axis=1))]))

結果:

交叉驗證最佳精確度為 92.44% 在 50 樹時達到

接下來,我們繪制相應的學習曲線:

plt.style.use('ggplot')

fig, ax = plt.subplots(figsize=(8, 4))

ax.plot(trees_grid, train_acc.mean(axis=1), alpha=0.5, color='blue', label='train')

ax.plot(trees_grid, test_acc.mean(axis=1), alpha=0.5, color='red', label='cv')

ax.fill_between(trees_grid, test_acc.mean(axis=1) - test_acc.std(axis=1), test_acc.mean(axis=1) + test_acc.std(axis=1), color='#888888', alpha=0.4)

ax.fill_between(trees_grid, test_acc.mean(axis=1) - 2*test_acc.std(axis=1), test_acc.mean(axis=1) + 2*test_acc.std(axis=1), color='#888888', alpha=0.2)

ax.legend(loc='best')

ax.set_ylim([0.88,1.02])

ax.set_ylabel("Accuracy")

ax.set_xlabel("N_estimators");

如你所見,當達到特定數量時,測試集上的精確度非常接近漸近線。

上圖同時顯示了我們在訓練集上達到了100%精確度,這意味著我們過擬合了。為了避免過擬合,我們需要給模型加上正則化參數。

下面我們將樹的數目固定為100,然后看看不同的max_depth效果如何:

train_acc = []

test_acc = []

temp_train_acc = []

temp_test_acc = []

max_depth_grid = [3, 5, 7, 9, 11, 13, 15, 17, 20, 22, 24]

for max_depth in max_depth_grid:

rfc = RandomForestClassifier(n_estimators=100, random_state=42, n_jobs=-1, oob_score=True, max_depth=max_depth)

temp_train_acc = []

temp_test_acc = []

for train_index, test_index in skf.split(X, y):

X_train, X_test = X.iloc[train_index], X.iloc[test_index]

y_train, y_test = y[train_index], y[test_index]

rfc.fit(X_train, y_train)

temp_train_acc.append(rfc.score(X_train, y_train))

temp_test_acc.append(rfc.score(X_test, y_test))

train_acc.append(temp_train_acc)

test_acc.append(temp_test_acc)

train_acc, test_acc = np.asarray(train_acc), np.asarray(test_acc)

print("交叉驗證最佳精確度為 {:.2f}% 當 max_depth 為 {} 時達到".format(max(test_acc.mean(axis=1))*100,

max_depth_grid[np.argmax(test_acc.mean(axis=1))]))

結果:

交叉驗證最佳精確度為 92.68% 當 max_depth 為 17 時達到

fig, ax = plt.subplots(figsize=(8, 4))

ax.plot(max_depth_grid, train_acc.mean(axis=1), alpha=0.5, color='blue', label='train')

ax.plot(max_depth_grid, test_acc.mean(axis=1), alpha=0.5, color='red', label='cv')

ax.fill_between(max_depth_grid, test_acc.mean(axis=1) - test_acc.std(axis=1), test_acc.mean(axis=1) + test_acc.std(axis=1), color='#888888', alpha=0.4)

ax.fill_between(max_depth_grid, test_acc.mean(axis=1) - 2*test_acc.std(axis=1), test_acc.mean(axis=1) + 2*test_acc.std(axis=1), color='#888888', alpha=0.2)

ax.legend(loc='best')

ax.set_ylim([0.88,1.02])

ax.set_ylabel("Accuracy")

ax.set_xlabel("Max_depth");

max_depth在我們的模型中起到了正則化的作用,模型不像之前過擬合得那么嚴重了。模型精確度略有提升。

另一個值得調整的重要參數是min_samples_leaf,它也能起到正則化作用。

train_acc = []

test_acc = []

temp_train_acc = []

temp_test_acc = []

min_samples_leaf_grid = [1, 3, 5, 7, 9, 11, 13, 15, 17, 20, 22, 24]

for min_samples_leaf in min_samples_leaf_grid:

rfc = RandomForestClassifier(n_estimators=100, random_state=42, n_jobs=-1,

oob_score=True, min_samples_leaf=min_samples_leaf)

temp_train_acc = []

temp_test_acc = []

for train_index, test_index in skf.split(X, y):

X_train, X_test = X.iloc[train_index], X.iloc[test_index]

y_train, y_test = y[train_index], y[test_index]

rfc.fit(X_train, y_train)

temp_train_acc.append(rfc.score(X_train, y_train))

temp_test_acc.append(rfc.score(X_test, y_test))

train_acc.append(temp_train_acc)

test_acc.append(temp_test_acc)

train_acc, test_acc = np.asarray(train_acc), np.asarray(test_acc)

print("交叉驗證最佳精確度為 {:.2f}% 當 min_samples_leaf 為 {} 時達到".format(max(test_acc.mean(axis=1))*100,

min_samples_leaf_grid[np.argmax(test_acc.mean(axis=1))]))

結果:

交叉驗證最佳精確度為 92.41% 當 min_samples_leaf 為 3 時達到

fig, ax = plt.subplots(figsize=(8, 4))

ax.plot(min_samples_leaf_grid, train_acc.mean(axis=1), alpha=0.5, color='blue', label='train')

ax.plot(min_samples_leaf_grid, test_acc.mean(axis=1), alpha=0.5, color='red', label='cv')

ax.fill_between(min_samples_leaf_grid, test_acc.mean(axis=1) - test_acc.std(axis=1), test_acc.mean(axis=1) + test_acc.std(axis=1), color='#888888', alpha=0.4)

ax.fill_between(min_samples_leaf_grid, test_acc.mean(axis=1) - 2*test_acc.std(axis=1), test_acc.mean(axis=1) + 2*test_acc.std(axis=1), color='#888888', alpha=0.2)

ax.legend(loc='best')

ax.set_ylim([0.88,1.02])

ax.set_ylabel("Accuracy")

ax.set_xlabel("Min_samples_leaf");

在這一情形下,我們沒在驗證集上看到精確度提升,但在驗證集上精確度保持92%以上的同時,降低了2%的過擬合。

考慮max_features這一參數。在分類問題中,所有特征數的平方根是默認選擇。讓我們看下4個特征是否是這個例子中的最佳選擇:

train_acc = []

test_acc = []

temp_train_acc = []

temp_test_acc = []

max_features_grid = [2, 4, 6, 8, 10, 12, 14, 16]

for max_features in max_features_grid:

rfc = RandomForestClassifier(n_estimators=100, random_state=42, n_jobs=-1,

oob_score=True, max_features=max_features)

temp_train_acc = []

temp_test_acc = []

for train_index, test_index in skf.split(X, y):

X_train, X_test = X.iloc[train_index], X.iloc[test_index]

y_train, y_test = y[train_index], y[test_index]

rfc.fit(X_train, y_train)

temp_train_acc.append(rfc.score(X_train, y_train))

temp_test_acc.append(rfc.score(X_test, y_test))

train_acc.append(temp_train_acc)

test_acc.append(temp_test_acc)

train_acc, test_acc = np.asarray(train_acc), np.asarray(test_acc)

print("交叉驗證最佳精確度為 {:.2f}% 當 max_features 為 {} 時達到".format(max(test_acc.mean(axis=1))*100,

max_features_grid[np.argmax(test_acc.mean(axis=1))]))

結果:

交叉驗證最佳精確度為 92.59% 當 max_features 為 10 時達到

fig, ax = plt.subplots(figsize=(8, 4))

ax.plot(max_features_grid, train_acc.mean(axis=1), alpha=0.5, color='blue', label='train')

ax.plot(max_features_grid, test_acc.mean(axis=1), alpha=0.5, color='red', label='cv')

ax.fill_between(max_features_grid, test_acc.mean(axis=1) - test_acc.std(axis=1), test_acc.mean(axis=1) + test_acc.std(axis=1), color='#888888', alpha=0.4)

ax.fill_between(max_features_grid, test_acc.mean(axis=1) - 2*test_acc.std(axis=1), test_acc.mean(axis=1) + 2*test_acc.std(axis=1), color='#888888', alpha=0.2)

ax.legend(loc='best')

ax.set_ylim([0.88,1.02])

ax.set_ylabel("Accuracy")

ax.set_xlabel("Max_features");

在我們的例子中,最佳特征數是10。

我們已經查看了基本參數的不同值的學習曲線。下面讓我們使用GridSearch查找最佳參數:

parameters = {'max_features': [4, 7, 10, 13], 'min_samples_leaf': [1, 3, 5, 7], 'max_depth': [5,10,15,20]}

rfc = RandomForestClassifier(n_estimators=100, random_state=42,

n_jobs=-1, oob_score=True)

gcv = GridSearchCV(rfc, parameters, n_jobs=-1, cv=skf, verbose=1)

gcv.fit(X, y)

gcv.best_estimator_, gcv.best_score_

返回:

(RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',

max_depth=10, max_features=10, 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=100, n_jobs=-1,

oob_score=True, random_state=42, verbose=0, warm_start=False),

0.9270927092709271)

隨機森林最重要的一點是它的精確度不會隨著樹的增加而下降,所以樹的數量不像max_depth和min_samples_leaf那樣錯綜復雜。這意味著你可以使用,比如說,10棵樹調整超參數,接著增加樹的數量至500,放心,精確度只會更好。

5.4 方差和去相關

隨機森林的方差可以用下式表達:

其中

p(x)為任何兩棵樹之間的樣本相關性;

Θ1(Z)和Θ2(Z)為樣本Z上隨機選擇的元素上隨機選擇的一對樹;

T(x, Θi(Z))為第i個樹分類器在輸入向量x上的輸出;

σ2(x)為任何隨機選擇的樹上的樣本方差:

很容易將p(x)誤認為給定的隨機森林中訓練好的樹的平均相關性(將樹視為N維向量)。其實并非如此。

事實上,這一條件相關性并不和平均過程直接相關,p(x)的自變量x提醒了我們這一差別。p(x)是一對隨機樹在輸入x上的估計的理論相關性。它的值源自重復取樣訓練集以及之后隨機選擇的決策樹對。用統計學術語來說,這是由Z和Θ取樣分布導致的相關性。

任何一對樹的條件相關性等于0,因為bootstrap和特征選取是獨立同分布。

如果我們考慮單棵樹的方差,它幾乎不受分割參數的影響(m)。但這一參數在集成中是關鍵。另外,單棵決策樹的方差要比集成高很多。The Elements of Statistical Learning一書中有一個很好的例子:

5.5 偏差

隨機森林、bagging的偏差和單棵決策樹一樣:

從絕對值上說,偏差通常比單棵樹要大,因為隨機過程和樣本空間縮減在模型上施加了它們各自的限制。因此,bagging和隨機森林在預測精確度上的提升單純源自方差降低。

5.6 極端隨機樹

極端隨機樹(Extremely Randomized Trees)在節點分岔時應用了更多隨機性。和隨機森林一樣,極端隨機樹使用一個隨機特征子空間。然而,極端隨機數并不搜尋最佳閾值,相反,為每個可能的特征隨機生成一個閾值,然后根據其中最佳隨機生成閾值對應的特征來分割節點。這通常是用少量偏差的增加交換方差的略微下降。

scikit-learn庫實現了[ ExtraTreesClassifier]和ExtraTreesRegressor。

如果你使用隨機森林或梯度提升遇到了嚴重的過擬合,可以試試極端隨機樹。

5.7 隨機森林和k近鄰的相似性

隨機森林和最近鄰技術有相似之處。隨機森林預測基于訓練集中相似樣本的標簽。這些樣本越常出現在同一葉節點,它們的相似度就越高。下面我們將證明這一點。

讓我們考慮一個二次損失函數的回歸問題。設Tn(x)為輸入x在隨機森林中第n棵樹的葉節點數。算法對輸入向量x的響應等于所有落入葉節點Tn(x)的訓練樣本的平均響應。

其中

故響應的構成為:

如你所見,隨機森林的響應為所有訓練樣本響應的加權和。

同時,值得注意的是,實例x最終出現的葉節點數Tn(x),本身是一個有價值的特征。例如,下面的方法效果不錯:

基于隨機森林或梯度提升技術在樣本上訓練較小數目的決策樹的復合模型

將類別特征T1(x),...,Tn(x)加入樣本

這些新特征是非線性空間分割的結果,它們提供了關于樣本之間的相似性的信息。The Elements of Statistical Learning一書中有一個很好的說明樣例,演示了隨機森林和k-近鄰技術的相似性:

5.8 轉換數據集為高維表示

隨機森林主要用于監督學習,不過也可以在無監督設定下應用。

使用scikit-learn的RandomTreesEmbedding方法,我們可以將數據集轉換為高維的稀疏表示。我們首先創建一些極端隨機樹,接著使用包含樣本的葉節點索引作為新特征。

例如,如果第一個葉節點包含輸入,我們分配1為特征值,否則,分配0. 這稱為二進制編碼(binary coding)。我們可以通過增減樹的數目和深度控制特征數量和稀疏性。由于鄰居的數據點傾向于落入同一葉節點,這一轉換提供了對數據點的密度的一個隱式的非參數估計。

5.9 隨機森林的優勢和劣勢

優勢:

高預測精確度;在大多數問題上表現優于線性算法;精確度與boosting相當;

多虧了隨機取樣,對離散值的魯棒性較好;

隨機子空間選取導致對特征縮放及其他單調轉換不敏感;

不需要精細的參數調整,開箱即用。取決于問題設定和數據,調整參數可能取得0.5%到3%的精確度提升;

在具有大量特征和分類的數據集上很高效;

既可處理連續值,也可處理離散值;

罕見過擬合。在實踐中,增加樹的數量幾乎總是能提升總體表現。不過,當達到特定數量后,學習曲線非常接近漸近線;

有成熟方法用于估計特征重要性;

能夠很好地處理數據缺失,即使當很大一部分數據缺失時,仍能保持較好的精確度;

支持整個數據集及單棵樹樣本上的加權分類;

決策樹底層使用的實例親近性計算可以在后續用于聚類、檢測離散值、感興趣數據表示;

以上功能和性質可以擴展到未標注數據,以支持無監督聚類,數據可視化和離散值檢測;

易于并行化,伸縮性強。

劣勢:

相比單棵決策樹,隨機森林的輸出更難解釋。

特征重要性估計沒有形式化的p值。

在稀疏數據情形(比如,文本輸入、詞袋)下,表現不如線性模型好。

和線性回歸不同,隨機森林無法外推。不過,這也可以看成優勢,因為離散值不會在隨機森林中導致極端值。

在某些問題上容易過擬合,特別是處理高噪聲數據。

處理數量級不同的類別數據時,隨機森林偏重數量級較高的變量,因為這能提高更多精確度;

如果數據集包含對預測分類重要度相似的相關特征分組,那么隨機森林將偏重較小的分組;

所得模型較大,需要大量RAM。

6. 特征重要性

我們常常需要給出算法輸出某個特定答案的原因。或者,在不能完全理解算法的情況下,我們至少想要找出哪個輸入特征對結果的貢獻最大。基于隨機森林,我們可以相當容易地獲取這類信息。

方法精要

下圖很直觀地呈現了,在我們的信用評分問題中,年齡比收入更重要。基于信息增益這一概念,我們可以形式化地解釋這一點。

在隨機森林中,某一特征在所有樹中離樹根的平均距離越近,這一特征在給定的分類或回歸問題中就越重要。按照分割標準,在每棵樹的每處最優分割中取得的增益,例如基尼不純度(Gini impurity),是與分割特征直接相關的重要度測度。每個特征的評分值不同(通過累加所有樹得出)。

讓我們深入一些細節。

某個變量導致的平均精確度下降可以通過計算袋外誤差判定。由于除外或選定某一變量導致的精確度下降約大,該變量的重要性評分(importance score)就越高。

基尼不純度——或回歸問題中的MSE——的平均下降代表每個變量對所得隨機森林模型節點的同質性的貢獻程度。每次選中一個變量進行分割時,計算子節點的基尼不純度,并與原節點進行比較。

基尼不純度是位于0(同質)到1(異質)之間的同質性評分。為每個變量累加分割標準對應值的變動,并在計算過程的最后加以正則化。基尼不純度下降較高標志著基于該變量進行的分割可以得到純度更高的節點。

以上可以用分析形式表達為:

其中,πj表示選中或排除特征。當xj不在樹T中時,VIT(xj) = 0。

現在,我們可以給出集成的特征重要性計算公式。

未經正則化:

使用標準差正則化后:

實際操作例子

讓我們考慮一項調查結果,關于Booking.com和TripAdvisor.com上列出的旅館。這里的特征是不同類別(包括服務質量、房間狀況、性價比等)的平均評分。目標變量為旅館在網站上的總評分。

import warnings

warnings.filterwarnings('ignore')

%matplotlib inline

from matplotlib import pyplot as plt

import seaborn as sns

from matplotlib import rc

font = {'family': 'Verdana',

'weight': 'normal'}

rc('font', **font)

import pandas as pd

import numpy as np

from sklearn.ensemble.forest importRandomForestRegressor

hostel_data = pd.read_csv("../../data/hostel_factors.csv")

features = {"f1":u"Staff",

"f2":u"Hostel booking",

"f3":u"Check-in and check-out",

"f4":u"Room condition",

"f5":u"Shared kitchen condition",

"f6":u"Shared space condition",

"f7":u"Extra services",

"f8":u"General conditions & conveniences",

"f9":u"Value for money",

"f10":u"Customer Co-creation"}

forest = RandomForestRegressor(n_estimators=1000, max_features=10,

random_state=0)

forest.fit(hostel_data.drop(['hostel', 'rating'], axis=1),

hostel_data['rating'])

importances = forest.feature_importances_

indices = np.argsort(importances)[::-1]

num_to_plot = 10

feature_indices = [ind+1for ind in indices[:num_to_plot]]

plt.figure(figsize=(15,5))

plt.title(u"Feature Importance")

bars = plt.bar(range(num_to_plot),

importances[indices[:num_to_plot]],

color=([str(i/float(num_to_plot+1))

for i in range(num_to_plot)]),

align="center")

ticks = plt.xticks(range(num_to_plot),

feature_indices)

plt.xlim([-1, num_to_plot])

plt.legend(bars, [u''.join(features["f"+str(i)])

for i in feature_indices]);

上圖顯示,消費者常常更為關心服務人員和性價比。這兩個因子對最終評分的影響最大。然而,這兩項特征和其他特征的差別不是非常大。因此,排除任何特征都會導致模型精確度的下降。基于我們的分析,我們可以建議旅館業主重點關注服務人員培訓和性價比。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 集成
    +關注

    關注

    1

    文章

    176

    瀏覽量

    30351
  • 隨機森林
    +關注

    關注

    1

    文章

    22

    瀏覽量

    4299
  • Bagging
    +關注

    關注

    0

    文章

    2

    瀏覽量

    2282

原文標題:機器學習開放課程(五):Bagging與隨機森林

文章出處:【微信號:jqr_AI,微信公眾號:論智】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    鑒源實驗室·HTTPS對于網絡安全的重要性

    本文旨在深入解析HTTPS的工作原理、安全以及其在網絡安全中的重要性
    的頭像 發表于 02-19 14:31 ?95次閱讀
    鑒源實驗室·HTTPS對于網絡安全的<b class='flag-5'>重要性</b>

    IPC發布雙重重要性評估白皮書

    IPC近日隆重推出了其最新白皮書——《雙重重要性評估為何重要:合規與競爭優勢》。此份白皮書旨在為電子行業的企業提供一份詳盡的指南,幫助他們深入理解并應對歐盟的《企業可持續發展報告指令
    的頭像 發表于 12-23 17:28 ?441次閱讀

    深入淺出RISC-V調試

    寄存器)定義如圖4所示。 圖4 DTM寄存器 其中紅色框起來的寄存器是必須要實現的。下面簡單介紹一下這幾個寄存器。 ① IDCODE寄存器(0x01) 當TAP狀態機復位時,IR寄存器的值默認為0x01
    發表于 11-28 22:00

    示波器探頭接地的重要性

    精度的保障、操作人員的安全以及設備的保護。本文將深入探討示波器探測頭接地的重要性。 確保測量精度 首先,接地是確保測量精度的關鍵因素。示波器探頭如果不接地,可能會引入地回路干擾,導致測量信號中混入不必要的噪
    的頭像 發表于 10-15 11:32 ?446次閱讀

    閃存隨機讀寫與連續讀寫哪個重要

    閃存隨機讀寫與連續讀寫各有其重要性,具體取決于應用場景和需求。 隨機讀寫的重要性 延遲小,響應快 : 閃存(尤其是SSD)的隨機讀寫性能通常
    的頭像 發表于 10-12 11:44 ?655次閱讀

    深入淺出系列之代碼可讀

    原創聲明:該文章是個人在項目中親歷后的經驗總結和分享,如有搬運需求請注明出處。 這是“深入淺出系列”文章的第一篇,主要記錄和分享程序設計的一些思想和方法論,如果讀者覺得所有受用,還請“一鍵三連
    的頭像 發表于 08-09 16:00 ?325次閱讀

    NLP技術在人工智能領域的重要性

    智能的橋梁,其重要性日益凸顯。本文將從NLP的定義、發展歷程、核心技術、應用領域以及對人工智能領域的深遠影響等多個維度,深入探討NLP技術在人工智能領域的重要性
    的頭像 發表于 07-04 16:03 ?749次閱讀

    深入淺出談TDR阻抗測試

    Chrent為什么要測阻抗?計算機、通信系統、視頻系統和網絡系統等領域的數字系統開發人員正面臨著越來越快的時鐘頻率和數據速率,隨之,信號完整變得越來越重要。在當前的高工作速率下,影響信號上升時間
    的頭像 發表于 06-06 08:28 ?6891次閱讀
    <b class='flag-5'>深入淺出</b>談TDR阻抗測試

    求助,ADC接地的重要性

    ADC接地的重要性
    發表于 06-04 07:56

    露天礦邊坡監測的重要性與方法

    露天礦邊坡監測的重要性與方法
    的頭像 發表于 05-28 16:24 ?559次閱讀

    氣密檢測的重要性

    ,旨在確定產品或系統的密封性能是否符合設計標準和規范要求。接下來,我們將深入探討氣密檢測的幾個關鍵方面,以揭示其不可或缺的重要性。一、安全性氣密檢測的首要目的是確
    的頭像 發表于 04-26 11:51 ?1042次閱讀
    氣密<b class='flag-5'>性</b>檢測的<b class='flag-5'>重要性</b>

    深入淺出Matter創建設計的挑戰以及實踐的重要步驟

    Matter是智能家居和物聯網設備的開源連接標準。它旨在提高不同制造商之間的互操作和兼容,促進互聯網連接設備之間的無縫通信。
    的頭像 發表于 03-27 16:13 ?1211次閱讀

    集成芯片的重要性

    、電容器、電阻等)以微影工藝制造在同一塊半導體襯底上,并且能夠按照設計的功能要求相互連接而形成的一個整體。集成電路芯片具有高度集成、小體積、輕量化、低功耗、高可靠的特點。
    的頭像 發表于 03-19 13:30 ?745次閱讀

    集成芯片的重要性和必要

    集成芯片在現代科技和工業中占據著至關重要的地位,其重要性和必要主要體現在以下幾個方面。
    的頭像 發表于 03-18 15:17 ?1416次閱讀

    什么是隨機森林隨機森林的工作原理

    隨機森林使用名為“bagging”的技術,通過數據集和特征隨機自助抽樣樣本并行構建完整的決策樹。雖然決策樹基于一組固定的
    發表于 03-18 14:27 ?3839次閱讀
    什么是<b class='flag-5'>隨機</b><b class='flag-5'>森林</b>?<b class='flag-5'>隨機</b><b class='flag-5'>森林</b>的工作原理
    主站蜘蛛池模板: 俺来也俺去啦久久综合网 | 国产一级特黄老妇女大片免费 | 亚洲一区二区免费视频 | 成人国产永久福利看片 | 免费在线欧美 | 久久69| 5x性区m免费毛片视频看看 | 免费福利在线播放 | 伊人98| aaaaaaa毛片 | 天天干天天爱天天操 | 久久99国产精品免费观看 | 亚洲男人的天堂在线观看 | 人人看人人看人做人人模 | 美女视频一区二区三区在线 | 亚洲狠狠婷婷综合久久久图片 | 日产乱码免费一卡二卡在线 | 欧美videosex性欧美成人 | 日韩色爱| 人人干日日操 | 啪啪免费视频 | 色老头网址 | 69xxx视频| 美女被羞羞产奶视频网站 | 91拍拍在线观看 | 8x8x极品国产在线 | 天天夜天干天天爽 | 日本黄色大片网站 | 一级特黄aaa大片大全 | 日本极度另类网站 | 久久日精品 | 在线你懂的 | www.91久久| 欧美三级久久 | 禁网站在线观看免费视频 | 奇米影视大全 | 亚洲插| 自拍偷自拍亚洲精品被多人伦好爽 | 国产视频国产 | 激情六月丁香 | 亚洲婷婷国产精品电影人久久 |