比賽用到的庫
-
numpy:提供(多維)數組操作
-
pandas:提供數據結構、數據分析
-
catboost:用于機器學習的庫,特別是分類和回歸任務
-
sklearn.model_selection:包含模型選擇的多種方法,如交叉驗證
-
sklearn.metrics:包含評估模型性能的多種指標,提供如accuracy_score這樣的方法
-
sklearn.feature_extraction.text:提供將文本轉換為特征向量的TF-idf向量化器
-
rdkit:化學信息學和機器學習軟件,處理化學結構
-
tqdm:用于在長循環中添加進度條的庫
-
sys:與Python解釋器密切相關的模塊和由解釋器使用或維護的變量和函數
-
os:提供與操作系統交互的功能
-
gc:垃圾收集器接口:用于手動標記對象為可刪除
-
re:正則表達式庫,用于字符串搜索和替換
-
argparse:用于編寫用戶友好的命令行接口
-
warnings:用于發出警告,或忽略警告。
使用到的關鍵的庫文檔鏈接:
numpy:NumPy 參考 — NumPy v2.0 手冊
pandas:API reference — pandas 2.2.2 documentation (pydata.org)
catboost:CatBoost | CatBoost
sklearn:API Reference — scikit-learn 1.5.1 documentation
rdkit:RDKit中文教程 — RDKit 中文教程 2020.09 文檔 (chenzhaoqiang.com)
sys:sys — System-specific parameters and functions — Python 3.12.4 documentation
庫的導入
import numpy as np
import pandas as pd
from catboost import CatBoostClassifier
from sklearn.model_selection import StratifiedKFold, KFold, GroupKFold
from sklearn.metrics import f1_score
from rdkit import Chem
from rdkit.Chem import Descriptors
from sklearn.feature_extraction.text import TfidfVectorizer
import tqdm, sys, os, gc, re, argparse, warnings
warnings.filterwarnings('ignore') # 忽略警告
數據預處理
train = pd.read_excel('./dataset-new/traindata-new.xlsx')
test = pd.read_excel('./dataset-new/testdata-new.xlsx')# test數據不包含 DC50 (nM) 和 Dmax (%)
train = train.drop(['DC50 (nM)', 'Dmax (%)'], axis=1)# 定義了一個空列表drop_cols,用于存儲在測試數據集中非空值小于10個的列名。
drop_cols = []
for f in test.columns:if test[f].notnull().sum() < 10:drop_cols.append(f)# 使用drop方法從訓練集和測試集中刪除了這些列,以避免在后續的分析或建模中使用這些包含大量缺失值的列
train = train.drop(drop_cols, axis=1)
test = test.drop(drop_cols, axis=1)# 使用pd.concat將清洗后的訓練集和測試集合并成一個名為data的DataFrame,便于進行統一的特征工程處理
data = pd.concat([train, test], axis=0, ignore_index=True)
cols = data.columns[2:]
除此之外,數據預處理可以使用數據增強、數據清洗、手動擴充等方法。
特征工程
# 將SMILES轉換為分子對象列表,并轉換為SMILES字符串列表
data['smiles_list'] = data['Smiles'].apply(lambda x:[Chem.MolToSmiles(mol, isomericSmiles=True) for mol in [Chem.MolFromSmiles(x)]])
data['smiles_list'] = data['smiles_list'].map(lambda x: ' '.join(x)) # 使用TfidfVectorizer計算TF-IDF
tfidf = TfidfVectorizer(max_df = 0.9, min_df = 1, sublinear_tf = True)
res = tfidf.fit_transform(data['smiles_list'])# 將結果轉為dataframe格式
tfidf_df = pd.DataFrame(res.toarray())
tfidf_df.columns = [f'smiles_tfidf_{i}' for i in range(tfidf_df.shape[1])]# 按列合并到data數據
data = pd.concat([data, tfidf_df], axis=1)# 自然數編碼
def label_encode(series):unique = list(series.unique())return series.map(dict(zip(unique, range(series.nunique()))))for col in cols:if data[col].dtype == 'object':data[col] = label_encode(data[col])train = data[data.Label.notnull()].reset_index(drop=True)
test = data[data.Label.isnull()].reset_index(drop=True)# 特征篩選
features = [f for f in train.columns if f not in ['uuid','Label','smiles_list']]# 構建訓練集和測試集
x_train = train[features]
x_test = test[features]# 訓練集標簽
y_train = train['Label'].astype(int)
特征工程是構建一個良好的機器學習模型的關鍵步驟。有用的特征使得模型表現更好。
在這個特征工程中,使用了具有關鍵特征的簡單模型,要想用最佳方式完成特征工程,必須對問題的領域有一定的了解,并且很大程度上取決于相關數據。
特征方程不僅僅是創建新特征,還包括不同類型的歸一化和轉換。
在這一段代碼里,沒有歸一化流程,只有轉換。
常見的歸一化手段:
- Min-Max縮放
- Z-score標準化
- Robust縮放
而在這段代碼里:
-
SMILES轉換:使用RDKit庫將數據集中的SMILES字符串轉換回字符串的列表。這是特征工程的一部分:這是為了便于下一步特征的提取,SMILES可以使用TF-IDF計算方法。這是一種數據預處理的手段。
-
字符串處理:將SMILES字符串列表轉換為單個字符串,每個SMILES之間用空格分隔。
-
TF-IDF計算:使用TfidfVectorizer從處理后的SMILES字符串創建TF-IDF特征矩陣,TF-IDF是一種詞文本的統計學方法,用于統計詞文本在文件中出現的頻率,衡量該詞條的重要程度。這是一種特征提取手段。
-
自然數編碼:定義了一個函數
label_encode
,將分類特征(對象類型)轉換為整數編碼。首先,它接受一個pandas Series作為輸入,獲取Series中的唯一值列表,然后創建一個字典,將每個唯一值映射到一個整數,最后使用這個字典將原始Series中的每個值映射到相應的整數。檢測到object類型,就應用label_encode
進行編碼。這樣的編碼方式比較直觀,同時符合需要順序的特點。 -
特征和標簽準備:對于所有的特征列(
cols
),如果它們的數據類型是對象(通常表示為字符串),則應用自然數編碼;從合并后的數據集中分離出訓練集和測試集,其中訓練集包含標簽(Label
),測試集不包含。 -
特征和標簽的篩選:由于不需要uuid、Label和smiles_list,剔除并提取標簽列。
-
數據類型轉換:將Label轉換為整數類型,便于訓練。
模型訓練與預測
def cv_model(clf, train_x, train_y, test_x, clf_name, seed=2022):kf = KFold(n_splits=5, shuffle=True, random_state=seed)train = np.zeros(train_x.shape[0])test = np.zeros(test_x.shape[0])cv_scores = []# 100, 1 2 3 4 5# 1 2 3 4 5# 1 2 3 5。 4# 1for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):print('************************************ {} {}************************************'.format(str(i+1), str(seed)))trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], train_y[valid_index]params = {'learning_rate': 0.1, 'depth': 6, 'l2_leaf_reg': 10, 'bootstrap_type':'Bernoulli','random_seed':seed,'od_type': 'Iter', 'od_wait': 100, 'allow_writing_files': False, 'task_type':'CPU'}model = clf(iterations=20000, **params, eval_metric='AUC')model.fit(trn_x, trn_y, eval_set=(val_x, val_y),metric_period=100,cat_features=[], use_best_model=True, verbose=1)val_pred = model.predict_proba(val_x)[:,1]test_pred = model.predict_proba(test_x)[:,1]train[valid_index] = val_predtest += test_pred / kf.n_splitscv_scores.append(f1_score(val_y, np.where(val_pred>0.5, 1, 0)))print(cv_scores)print("%s_score_list:" % clf_name, cv_scores)print("%s_score_mean:" % clf_name, np.mean(cv_scores))print("%s_score_std:" % clf_name, np.std(cv_scores))return train, testcat_train, cat_test = cv_model(CatBoostClassifier, x_train, y_train, x_test, "cat")pd.DataFrame({'uuid': test['uuid'],'Label': np.where(cat_test>0.5, 1, 0)}
).to_csv('submit.csv', index=None)
代碼定義了一個名為cv_model的函數,用于交叉驗證和預測。這段代碼的核心是交叉驗證和CatBoost訓練模型。
K折交叉驗證
交叉檢驗是評估模型性能的常用方法。交叉檢驗是使用訓練數據集來訓練模型,然后使用測試數據集來評估模型性能。*一輪交叉驗證包括將數據樣本劃分為互補子集,對一個子集(稱為訓練集)執行分析,并在另一個子集(稱為驗證集或測試集)上驗證分析結果。為了減少可變性,在大多數方法中,使用不同的分區執行多輪交叉驗證,并且在這些回合中驗證結果被組合(例如,平均)以估計最終的預測模型。(引自:維基百科)*作者使用了暫留集(hold-out set)這種方法:在一部分上訓練模型,然后在另一部分上檢查其性能。這也是交叉檢驗的一種。
選擇正確的交叉檢驗取決于所處理的數據集。在一個數據集上適用的交叉檢驗并不一定就適合別的數據集。
有幾種交叉檢驗技術最為流行和廣泛使用:
-
k折交叉檢驗
-
分層k折交叉檢驗
-
留一交叉檢驗
-
分組k折交叉檢驗
交叉檢驗是將訓練數據分層幾個部分,在一部分上訓練模型,在其余部分上測試。
得到一個數據集來構建機器學習模型時,可以把他們分為兩個不同的集:訓練集和驗證集。訓練集用來訓練模型,驗證集用來評估模型。實際上很多人會用第三個集:測試集,在下述代碼中只使用兩個集。
我們可以將數據分為k個互不關聯的不同集合,即所謂的k折交叉驗證。這樣每一個不同的集合稱為一個“褶皺”。
注意,交叉驗證非常強大,幾乎所有類型的數據集都可以使用此流程。
在本例Baseline里,Kfold進行了5折交叉驗證。
CatBoost分類器訓練模型
最大迭代次數是iterations=20000,eval_metric=‘AUC’,表示使用AUC作為評估指標。
AUC(Area Under the ROC Curve)是一種評價二分類模型性能的指標之一,ROC(Receiver Operating Characteristic)曲線是基于不同的分類閾值計算得出的,展示了在各種閾值下真陽性率(True Positive Rate,即召回率)和假陽性率(False Positive Rate)之間的權衡。
具體來說:
-
ROC 曲線:ROC 曲線是以假陽性率(FPR)為橫軸,真陽性率(TPR)為縱軸繪制的曲線。在理想情況下,ROC 曲線應該盡量靠近左上角,表示在保持高真陽性率的同時,盡量低假陽性率。
-
AUC 值:AUC 值是 ROC 曲線下的面積,即 Area Under the ROC Curve。AUC 的取值范圍在 0 到 1 之間,通常用來表示分類器的性能。AUC 值越大,說明模型在不同閾值下的性能越好。
接著,使用驗證集val_x
和val_y
對模型進行評估,獲取預測概率val_pred。
使用測試集test_x
獲取測試集預測概率test_pred
。
F1_score(F1分數): F 1 = 2 ? T F 2 ? T F + F P + F N F1=\frac{2*TF}{2*TF+FP+FN} F1=2?TF+FP+FN2?TF?,它是精確度和召回率的調和平均值,是衡量測試準確度的標準。可能的最高值為1,表示完美的精確度和召回率。
精準率(P,Precision):它用于衡量模型的查準性能,正確預測的樣本中,預測為正的樣本的比例。
召回率(R,Recall):它用于衡量模型的查全性能,預測為正的樣本中,實際為正的樣本的比例。
CatBoost 是一種高效的梯度提升算法(Gradient Boosting),專為處理分類特征和提高機器學習模型性能而設計。以下是 CatBoost 的主要特點和使用說明:
1. 梯度提升算法
CatBoost 屬于梯度提升算法家族,通過迭代訓練一組弱學習器(通常是決策樹)來提高預測準確性。每一步都會根據前一步模型的錯誤來改進當前模型。
2. 處理分類特征
CatBoost 的一個顯著優勢是能夠直接處理分類特征,無需將它們轉換為數值形式(如獨熱編碼)。CatBoost 采用了專門的技術來編碼分類特征,簡化了數據預處理過程,并且往往能提升模型性能。
3. 高性能
- 優化的計算效率:CatBoost 進行了許多優化,能夠高效地進行梯度提升訓練。
- 支持并行計算和 GPU 加速:CatBoost 支持多線程計算和 GPU 加速,能顯著縮短訓練時間。
4. 正則化
CatBoost 默認包含 L2 正則化等技術來防止模型過擬合,提高模型的泛化能力。
5. 兼容性
CatBoost 支持分類(如二分類、多分類)和回歸任務。你可以在 CPU 或 GPU 上訓練模型,適用于各種硬件配置。
CatBoost接收的主要的參數有最大迭代次數iterations,最大深度depth,學習率learning_rate(梯度學習算法中控制每棵樹貢獻的步長大小的參數,通常小于1),分類特征cat_features,它是一個用于指定哪些特征是分類變量的列表。CatBoost可以直接處理這些分類特征,而不依賴于數值轉換。