对于具有 3 个类别(1、2、3)的序数回归问题,我正在运行以下算法:
class OrdinalClassifier():
def __init__(self, clf):
self.clf = clf
self.clfs = {}
def fit(self, X, y):
self.unique_class = np.sort(np.unique(y))
if self.unique_class.shape[0] > 2:
for i in range(self.unique_class.shape[0]-1):
# for each k - 1 ordinal value we fit a binary classification problem
binary_y = (y > self.unique_class[i]).astype(np.uint8)
clf = clone(self.clf)
clf.fit(X, binary_y)
self.clfs[i] = clf
def predict_proba(self, X):
clfs_predict = {k:self.clfs[k].predict_proba(X) for k in self.clfs}
predicted = []
for i,y in enumerate(self.unique_class):
if i == 0:
# V1 = 1 - Pr(y > V1)
predicted.append(1 - clfs_predict[y-1][:,1])
#elif y in clfs_predict:
elif y < self.unique_class.shape[0]:
# Vi = Pr(y > Vi-1) - Pr(y > Vi)
predicted.append(clfs_predict[y-2][:,1] - clfs_predict[y-1][:,1])
else:
# Vk = Pr(y > Vk-1)
predicted.append(clfs_predict[y-2][:,1])
return np.vstack(predicted).T
def predict(self, X):
return np.argmax(self.predict_proba(X), axis=1)
我通过给它一个 clf 来调用它:
clf = RandomForestClassifier()
forest = OrdinalClassifier(clf)
并通过调用 fit 来训练它:
forest.fit(X_train, y_train)
最后我通过调用得到预测:
#add 1 so 0->1, 1 -> 2, 2 -> 3
pred = forest.predict(y_test) + 1
我相信这个算法应该像我想要的那样工作。然而,在使用不同的超参数集运行模型时,这些类似乎以某种方式混淆了。对于几乎所有的超参数集,我发现了相同的模式。
- 被预测为第 1 类的类占实际第 2 类的百分比最大
- 被预测为第 2 类的类在实际第 3 类中所占的百分比最大
- 被预测为第 3 类的类占实际第 1 类的百分比最大
我觉得实际上似乎可以找到正确序数的一两个超参数组合更多是由运气引起的,而不是实际上导致了一个好的模型。总之,我的算法似乎确实在数据中找到了序数关系,但这些关系不正确/解码不正确。
问题:我的模型有问题吗?我应该只选择在验证集上按预期执行的超参数的确切组合吗?或者我应该将我的预测解码为第 3 类 => 第 1 类、第 1 类 => 第 2 类、第 2 类 => 第 3 类?
在此先感谢您的帮助!
编辑:对于任何感兴趣的人,我的 LGBM 模型开始以正确顺序看到模式的参数是当学习率变得非常高(接近或等于 1)而 l1 正则化的参数 >0 时。