
除了建立出來的模型有基本的準確度(Accuracy)之外,其實還可以使用不同的圖表來說明,這就是累積收益圖(Cumulative Gains Chart)與提升圖(Lift Chart),此圖表可以明確的表示模型在預測上,準確度實際提升的尺度,也就能夠向客戶說明新模型的效能表現囉!
累積收益圖和提升圖介紹
當我們想要了解一個預測模型相較於隨機預測所能帶來的提升或增益時,累積收益圖 (Cumulative Gains Chart) 和提升圖 (Lift Chart) 是非常有用的工具。這兩種圖表主要用於評估二元分類模型的效能,透過它們,我們可以清楚地看到模型是否比隨機預測更具準確性,以及準確性提升或增益的程度。
目的
累積收益圖和提升圖的主要目的是評估模型在預測正類別 (class 1) 的能力。理想情況下,當我們選擇前一定比例的樣本時,這些樣本中實際為正類別的比例應該遠高於隨機選擇的結果。這意味著我們能夠在樣本比例較低的情況下捕捉到更多的正類樣本,從而提高整體預測的效率和效果。
組成
累積收益圖和提升圖主要是針對二元分類中的正類樣本 (class 1) 進行分析,因此在一開始就需要將目標類別標記為正類。這兩種圖表都是以折線圖的形式呈現,包含X軸與Y軸,並展示模型預測的曲線 (實線) 以及隨機預測的基線 (虛線):
- X軸:百分比樣本 (Percentage of Samples)
- X軸表示模型預測樣本的比例,通常以累積的方式顯示,範圍從0%到100%。
- Y軸:
- 在累積收益圖中,Y軸表示累積捕捉到的正類樣本數量的比例 (累積增益值,Cumulative Gain)。累積增益值越高,表示模型在不同樣本比例下的預測效果越好。
- 在提升圖中,Y軸表示模型的預測效果相較於隨機預測所帶來的提升 (提升值,Lift Value)。提升值越高,表示模型的預測效果越好。
- 累積收益曲線與提升曲線 (實線)
- 這兩個圖表的核心部分是它們的曲線,通常以實線的形式呈現。
- 累積收益曲線 在累積收益圖中,這條曲線顯示了模型隨著樣本比例的增加,累積捕捉到正類樣本的能力。曲線越靠近左上角,表示模型的效能越好,因為在樣本比例較低的情況下就能捕捉到較多的正類樣本。
- 提升曲線 在提升圖中,這條曲線展示了模型相較於隨機預測的效果提升。一般來說,提升曲線越靠近上方,表示模型的效能越好,因為在樣本比例較低的情況下就能識別出大量的正類樣本。
- 這兩個圖表的核心部分是它們的曲線,通常以實線的形式呈現。
- 隨機預測的基線 (虛線)
- 隨機預測的基線通常以虛線的形式呈現,是這兩種圖表中的對照標準。
- 在累積收益圖中,基線通常是一條45度的斜線,表示隨機情況下,隨著樣本比例的增加,捕捉到的正類樣本數量與樣本比例成正比。
- 在提升圖中,基線通常是一條水平線,表示隨機選擇樣本時的預測效果,提升值為1。這條基線的作用是為提升曲線提供一個參考基準點,以便清楚地看到模型相較於隨機預測的效果提升。
- 隨機預測的基線通常以虛線的形式呈現,是這兩種圖表中的對照標準。
- 如果累積收益曲線或提升曲線在這條基線之上,則表示模型的預測
計算過程
累積收益圖和提升圖的計算過程非常類似,主要分為以下幾個步驟:
- 排序 (Sorting):根據模型的預測概率將樣本排序。這是確保高概率樣本(預測為正類的可能性較大)排在前面的關鍵步驟。
- 分箱 (Binning):將排序後的樣本分成多個區間 (bins),通常每個區間包含相同數量的樣本,這稱為等頻分箱 (quantile)。
- 計算累積增益或提升值:
- 累積收益圖:對於每個區間,計算該區間內捕捉到的正例數量,並與隨機預測的正例數量進行比較,得出累積增益值。
- 提升圖:對於每個區間,計算該區間內的正例數量,並與隨機預測的正例數量進行比較,得出提升值。
累積收益圖和提升圖的範例Code
我們會使用sklearn上的開源資料load_breast_cancer()乳癌資料集進行分類模型的建立,我們會建議帶有預測概率(predict_proba)的隨機森林模型(RandomForestClassifier),並畫出累積收益圖和提升圖,最後我們會將於測完成的模型結果進一步解釋模型結果,可以使用我的colab範例進行運算。
# 載入需要的套件
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
# 加載乳癌資料集
data = load_breast_cancer()
# 定義資料特徵(X)和有無癌症(y)
X = data.data
y = data.target
# 設定Seaborn樣式(美化最後輸出的圖片)
sns.set(style="darkgrid")
# 分割訓練集(80%:20%)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=28)
# 訓練隨機森林模型
model = RandomForestClassifier(random_state=28)
model.fit(X_train, y_train)
# 評估模型的預測概率
y_prob = model.predict_proba(X_test)[:, 1]
# 將樣本按照預測概率排序
sorted_indices = np.argsort(y_prob)[::-1]
sorted_y_true = y_test[sorted_indices]
# X軸的部分,每10個百分點計算一次區間
percent_points = np.arange(0.1, 1.1, 0.1)
cumulative_gains = []
lift_values = []
for percent in percent_points:
cutoff_index = int(percent * len(sorted_y_true))
cumulative_gain = np.sum(sorted_y_true[:cutoff_index]) / np.sum(sorted_y_true)
lift = cumulative_gain / percent
cumulative_gains.append(cumulative_gain)
lift_values.append(lift)
# 繪製圖表
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
# 繪製Cumulative Gains Chart
sns.lineplot(x=percent_points, y=cumulative_gains, marker='o', color='b', ax=ax1, label='RandomForest Model')
ax1.plot([0, 1], [0, 1], color='gray', linestyle='--', label='Baseline')
ax1.set_title('Cumulative Gains Chart')
ax1.set_xlabel('Percentage of Samples')
ax1.set_ylabel('Cumulative Gain')
ax1.legend()
# 繪製Lift Chart
sns.lineplot(x=percent_points, y=lift_values, marker='o', color='g', ax=ax2, label='RandomForest Model')
ax2.plot([0, 1], [1, 1], color='gray', linestyle='--', label='Baseline')
ax2.set_title('Lift Chart')
ax2.set_xlabel('Percentage of Samples')
ax2.set_ylabel('Lift')
ax2.legend()
plt.tight_layout()
plt.show()

最後需要計算一下在預測正類樣本概率最高的前10%以及前50%,使用隨機森林模型預測的提升度實際上比較隨機預測的能力提升了多少,所以寫一小段code來做計算。
# 使用模型預測測試資料的概率
y_prob = model.predict_proba(X_test)[:, 1]
# 將樣本按照預測概率排序
sorted_indices = np.argsort(y_prob)[::-1] # 降序排序
sorted_X_test = X_test[sorted_indices]
sorted_y_test = y_test[sorted_indices]
sorted_y_prob = y_prob[sorted_indices]
# 計算總正例數量(在測試集中)
total_positive = np.sum(y_test)
# 選擇前10%的數據
percent_10 = int(0.1 * len(sorted_X_test))
X_top_10_percent = sorted_X_test[:percent_10]
y_top_10_percent = sorted_y_test[:percent_10]
y_prob_top_10_percent = sorted_y_prob[:percent_10]
# 選擇前50%的數據
percent_50 = int(0.5 * len(sorted_X_test))
X_top_50_percent = sorted_X_test[:percent_50]
y_top_50_percent = sorted_y_test[:percent_50]
y_prob_top_50_percent = sorted_y_prob[:percent_50]
# 計算提升度
positive_in_top_10 = np.sum(y_top_10_percent)
positive_in_top_50 = np.sum(y_top_50_percent)
# 估算提升度
lift_10 = (positive_in_top_10 / total_positive) / 0.1
lift_50 = (positive_in_top_50 / total_positive) / 0.5
# 將前10%和前50%的數據保存為CSV文件
top_10_percent_df = pd.DataFrame(X_top_10_percent, columns=data.feature_names)
top_10_percent_df['target'] = y_top_10_percent
top_10_percent_df['predicted_prob'] = y_prob_top_10_percent
print(f"依照隨機森林模型的預測概率降序排列 \n前10%的資料有 {len(top_10_percent_df)} 筆,\n相較於隨機預測,提升約 {lift_10:.2f} 倍。\n")
top_50_percent_df = pd.DataFrame(X_top_50_percent, columns=data.feature_names)
top_50_percent_df['target'] = y_top_50_percent
top_50_percent_df['predicted_prob'] = y_prob_top_50_percent
print(f"依照隨機森林模型的預測概率降序排列 \n前50%的資料有 {len(top_50_percent_df)} 筆,\n相較於隨機預測,提升約 {lift_50:.2f} 倍。")

# 找到提升度的最高點
max_lift_index = np.argmax(lift_values)
max_lift_value = lift_values[max_lift_index]
max_lift_percent = percent_points[max_lift_index]
# 計算該位置的累積提升度
cumulative_gain_at_max_lift = cumulative_gains[max_lift_index]
# 輸出結果
print(f"最高的提升度發生在 {max_lift_percent * 100:.0f}% 的位置,提升度為 {max_lift_value:.2f}。")
print(f"在這個位置的累積提升度為 {cumulative_gain_at_max_lift:.2f}。")

結論
累積增益圖的結果
- 表示在X軸 0.5 的位置累積增益為 0.78,意思是在這前 50% 的樣本中,我們正確預測所有正類樣本(class 1)當中的 78%。
提升度圖的結果
- 假設在隨機預測的條件下,沒有使用任何預測模型,而是隨機選擇樣本進行預測,那在前50%的樣本中,理論上應該會有 50% 的正類樣本(class 1)。
- 而訓練的模型能夠讓我們在前50%的樣本中正確預測到了 78% 的正類樣本,則提升度就是隨機情況下的 1.56 倍( 0.78 / 0.5 = 1.56)。
