import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'SimHei' # 設(shè)置中文顯示
plt.rcParams['axes.unicode_minus'] = False
import warnings
# 忽略所有警告
warnings.filterwarnings("ignore")
df = pd.read_excel('多類別數(shù)據(jù).xlsx')
df.head()
原始數(shù)據(jù)包含12個(gè)特征,5個(gè)類別。
類別編碼
from sklearn.preprocessing import LabelEncoder
# 創(chuàng)建一個(gè)LabelEncoder對(duì)象
label_encoder = LabelEncoder()
# 對(duì)Type列進(jìn)行編碼
df['Type_encoded'] = label_encoder.fit_transform(df['Type'])
# 查看編碼后的結(jié)果
encoded_types = df[['Type', 'Type_encoded']].drop_duplicates().reset_index(drop=True)
print(encoded_types)
使用 LabelEncoder 將數(shù)據(jù)框 df 中的 Type 列的類別標(biāo)簽轉(zhuǎn)換為數(shù)值編碼,并輸出每個(gè)類別標(biāo)簽及其對(duì)應(yīng)的編碼結(jié)果。
數(shù)據(jù)集分割
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from hyperopt import fmin, tpe, hp, rand
from sklearn.metrics import accuracy_score
from sklearn import svm
from sklearn import datasets
# 分割數(shù)據(jù)集
X = df.drop(['Type', 'Type_encoded'], axis = 1)
y = df['Type_encoded']
Xtrain,Xtest,Ytrain,Ytest = train_test_split(X, y, test_size = 0.3,
stratify=df['Type_encoded']) #分離訓(xùn)練集和測(cè)試集
# 定義超參數(shù)空間
parameter_space_svc = {
'C': hp.loguniform('C', np.log(100), np.log(1000)), # 懲罰項(xiàng)
'kernel': hp.choice('kernel', ['rbf', 'poly']), # 核函數(shù)類型(選擇rbf或poly)
'gamma': hp.loguniform('gamma', np.log(100), np.log(1000)), # 核函數(shù)的系數(shù)
}
# 初始化計(jì)數(shù)器
count = 0
# 定義優(yōu)化目標(biāo)函數(shù)
def func(args):
global count
count += 1
print(f"\nIteration {count}: Hyperparameters - {args}")
# 創(chuàng)建SVM分類器,傳遞超參數(shù)
clf = svm.SVC(**args)
# 訓(xùn)練模型
clf.fit(Xtrain, Ytrain)
# 預(yù)測(cè)測(cè)試集
prediction = clf.predict(Xtest)
# 計(jì)算準(zhǔn)確率
score = accuracy_score(Ytest, prediction)
print(f'Test accuracy: {score}')
# 由于fmin函數(shù)默認(rèn)是最小化目標(biāo)函數(shù),所以返回負(fù)準(zhǔn)確率作為目標(biāo)
return -score
# 使用TPE算法進(jìn)行超參數(shù)優(yōu)化,最大評(píng)估次數(shù)為100
best = fmin(func, parameter_space_svc, algo=tpe.suggest, max_evals=100)
# 將最佳的核函數(shù)類型從索引值轉(zhuǎn)換為相應(yīng)的字符串
kernel_list = ['rbf', 'poly']
best['kernel'] = kernel_list[best['kernel']]
# 將最佳超參數(shù)保存到 best_params_ 中
best_params_ = {
'C': best['C'],
'kernel': best['kernel'],
'gamma': best['gamma']
}
# 輸出最佳超參數(shù)
print('\nBest hyperparameters:', best_params_)
使用貝葉斯優(yōu)化方法通過定義懲罰項(xiàng) 、核函數(shù)類型和核函數(shù)系數(shù) 的超參數(shù)空間,并利用 hyperopt 庫中的 TPE 算法在 100 次迭代內(nèi)尋找支持向量機(jī) (SVM) 的最佳超參數(shù)組合,以最大化模型在測(cè)試集上的預(yù)測(cè)準(zhǔn)確率,最終輸出優(yōu)化后的超參數(shù)配置。
# 創(chuàng)建SVM分類器,并使用最佳超參數(shù)進(jìn)行配置
clf = SVC(
C=best_params_['C'], # 懲罰項(xiàng)參數(shù)
kernel=best_params_['kernel'], # 核函數(shù)類型
gamma=best_params_['gamma'], # 核函數(shù)系數(shù)
decision_function_shape='ovr', # 多分類問題時(shí)使用"ovr"(一對(duì)多)策略
cache_size=5000, # 緩存大小,單位為MB
probability=True
)
# 使用訓(xùn)練數(shù)據(jù)進(jìn)行模型訓(xùn)練
clf.fit(Xtrain, Ytrain)
最優(yōu)超參數(shù)下在訓(xùn)練集上訓(xùn)練模型。
from sklearn.metrics import classification_report
pred = clf.predict(Xtest) # 預(yù)測(cè)測(cè)試集
print(classification_report(Ytest, pred)) # 輸出模型完整評(píng)價(jià)指標(biāo)
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
# 輸出混淆矩陣
conf_matrix = confusion_matrix(Ytest, pred)
# 繪制熱力圖
plt.figure(figsize=(10, 7), dpi = 1200)
sns.heatmap(conf_matrix, annot=True, annot_kws={'size':15}, fmt='d', cmap='YlGnBu')
plt.xlabel('Predicted Label', fontsize=12)
plt.ylabel('True Label', fontsize=12)
plt.title('Confusion matrix heat map', fontsize=15)
plt.show()
SHAP值計(jì)算
import shap
# 使用一個(gè)小的子集作為背景數(shù)據(jù)(可以是Xtest的一個(gè)子集)
background = shap.sample(Xtest, 100)
# 使用KernelExplainer
explainer = shap.KernelExplainer(clf.predict_proba, background)
# 計(jì)算測(cè)試集的shap值
shap_values = explainer.shap_values(Xtest.iloc[0:20,:]) # 這里自己定義用多少個(gè)樣本或者用全部 運(yùn)行速度相關(guān) 我使用了20個(gè)樣本
計(jì)算各類別的特征貢獻(xiàn)度
# 計(jì)算每個(gè)類別的特征貢獻(xiàn)度
importance_class_0 = np.abs(shap_values_class_0).mean(axis=0)
importance_class_1 = np.abs(shap_values_class_1).mean(axis=0)
importance_class_2 = np.abs(shap_values_class_2).mean(axis=0)
importance_class_3 = np.abs(shap_values_class_3).mean(axis=0)
importance_class_4 = np.abs(shap_values_class_4).mean(axis=0)
整理為DataFrame
importance_df = pd.DataFrame({
'類別0': importance_class_0,
'類別1': importance_class_1,
'類別2': importance_class_2,
'類別3': importance_class_3,
'類別4': importance_class_4
}, index=Xtrain.columns)
# 根據(jù)Type和Type_encoded對(duì)照表修改列名
type_mapping = {
0: '類型A',
1: '類型B',
2: '類型C',
3: '類型D',
4: '類型E'
}
importance_df.columns = [type_mapping[int(col.split('類別')[1])] for col in importance_df.columns]
importance_df
創(chuàng)建一個(gè)數(shù)據(jù)框 importance_df,將每個(gè)類別的特征重要性值進(jìn)行匯總,并根據(jù) Type 和 Type_encoded 對(duì)照表將列名從類別編號(hào)轉(zhuǎn)換為實(shí)際的類別名稱。
貢獻(xiàn)度可視化
# 添加一列用于存儲(chǔ)行的和
importance_df['row_sum'] = importance_df.sum(axis=1)
# 按照行和對(duì)DataFrame進(jìn)行排序
sorted_importance_df = importance_df.sort_values(by='row_sum', ascending=True)
# 刪除用于排序的行和列
sorted_importance_df = sorted_importance_df.drop(columns=['row_sum'])
elements = sorted_importance_df.index
# 使用 Seaborn 的顏色調(diào)色板,設(shè)置為 Set2,以獲得對(duì)比度更高的顏色
colors = sns.color_palette("Set2", n_colors=len(sorted_importance_df.columns))
# 創(chuàng)建圖形和坐標(biāo)軸對(duì)象,設(shè)置圖形大小為12x6英寸,分辨率為1200 DPI
fig, ax = plt.subplots(figsize=(12, 6), dpi=1200)
# 初始化一個(gè)數(shù)組,用于記錄每個(gè)條形圖的底部位置,初始為0
bottom = np.zeros(len(elements))
# 遍歷每個(gè)類別并繪制水平條形圖
for i, column in enumerate(sorted_importance_df.columns):
ax.barh(
sorted_importance_df.index, # y軸的特征名稱
sorted_importance_df[column], # 當(dāng)前類別的SHAP值
left=bottom, # 設(shè)置條形圖的起始位置
color=colors[i], # 使用調(diào)色板中的顏色
label=column # 為圖例添加類別名稱
)
# 更新底部位置,以便下一個(gè)條形圖能夠正確堆疊
bottom += sorted_importance_df[column]
# 設(shè)置x軸標(biāo)簽和標(biāo)題
ax.set_xlabel('mean(SHAP value|)(average impact on model output magnitude)', fontsize=12)
ax.set_ylabel('Features (特征)', fontsize=12)
ax.set_title('Feature Importance by Class (各類別下的特征重要性)', fontsize=15)
# 設(shè)置y軸刻度和標(biāo)簽
ax.set_yticks(np.arange(len(elements)))
ax.set_yticklabels(elements, fontsize=10)
# 在條形圖的末尾添加文本標(biāo)簽
for i, el in enumerate(elements):
ax.text(bottom[i], i, ' ' + str(el), va='center', fontsize=9)
# 添加圖例,并設(shè)置圖例的字體大小和標(biāo)題
ax.legend(title='Class (類別)', fontsize=10, title_fontsize=12)
# 禁用y軸的刻度和標(biāo)簽
ax.set_yticks([]) # 移除y軸刻度
ax.set_yticklabels([]) # 移除y軸刻度標(biāo)簽
ax.set_ylabel('') # 移除y軸標(biāo)簽
# 移除頂部和右側(cè)的邊框,以獲得更清晰的圖形
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.show()
對(duì)特征的 SHAP 重要性值進(jìn)行排序,以便在水平堆疊條形圖中按從最長(zhǎng)到最短的順序展示每個(gè)特征在各類別下的貢獻(xiàn)度,同時(shí)使用 Seaborn 的調(diào)色板和 matplotlib 繪制了圖形,以清晰地展示每個(gè)類別的特征重要性。
文章轉(zhuǎn)自微信公眾號(hào)@Python機(jī)器學(xué)習(xí)AI
對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力
一鍵對(duì)比試用API 限時(shí)免費(fèi)