实现 SVM 分类器
from sklearn.svm import SVC
svc = SVC(gamma='auto', probability=True, decision_function_shape='ovo')
svc.fit(x_train, y_train)
result = svc.predict_proba(x_test)
gamma
:核系数,默认为1 / n_features
probability
:是否显示概率估计
decision_function_shape
:多分类问题中最常使用 ovo 策略
fit()
:训练模型
predict_proba()
:计算测试集中数据属于某一类别的概率
设置以上参数,其他参数为默认的情况下,采用 ngram(ngram_range=(1, 3))提交得到的结果为 1.393962
优化 xgboost 遇到的问题
- 设置训练集权重
xgboost 参数中有一个 scale_pos_weight
参数,用来控制正负权重的平衡。一般的取值是:负样本个数/正样本个数。但是查阅的资料都是用于二分类问题,对多分类问题应该并不适用。
- 标签平滑
softmax 交叉熵优化时,为了减少 loss 可能会造成过拟合问题,可以通过标签平滑的方法解决。但是 xgboost 模型调用 Dmatrix() 方法时接收的 label
参数是一个一维的 list,因此无法使用标签平滑的方法优化。
本周训练结果
- 词袋模型 + xgboost 5折交叉验证
0.473048
ngram_range(1, 3)
0.476422
ngram_range(1, 3) min_df=3 max_df=0.9
train-mlogloss:0.070641 val-mlogloss:0.2973
0.484424
ngram_range(2, 3)
train-mlogloss:0.074861 val-mlogloss:0.297651
0.482929
ngram_range(2, 4)
train-mlogloss:0.077568 val-mlogloss:0.294211
推测结论
- ngram_range 都是(1, 3)时,默认参数比设置的参数效果好,应该是因为 api 种类很少,每一种 api 对程序的检测都很重要,不能剔除 api 序列。
- ngram_range 为(2, 3)和(2, 4)时结果也会变差,说明不只是特定序列长度的 api,单个的 api 对于程序的类别也很重要
- svm 模型和 xgboost 模型都为默认参数
两个模型都是词袋模型向量化,ngram_range(1, 3)
svm:1.393962
xgboost:0.525662
train-mlogloss:0.084493 val-mlogloss:0.301482
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=0)
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, y_test)
dout = xgb.DMatrix(x_test)
param = {'eval_metric': 'mlogloss', 'objective': 'multi:softprob',
'num_class': 8} # 参数
evallist = [(dtrain, 'train'), (dtest, 'val')] # 测试 , (dtrain, 'train')
num_round = 300 # 循环次数
bst = xgb.train(param, dtrain, num_round, evallist, early_stopping_rounds=50)
# dtr = xgb.DMatrix(train_features)
pred_val = bst.predict(dtest)
pred_test = bst.predict(dout)
result = pred_test
查阅资料,xgboost 效果优于 svm 的原因有以下几点:
- tree-ensemble 这样的模型可控性更好,更不容易过拟合
- 数据存在噪声,基于树的算法通常抗噪能力更强