Reduced Logistic Ordinal Classification Model
该模型基于化简联合求解序分类框架。
未使用强制一致性的版本。但可以证明学习得到的阈值可以保持一致性。
个人感觉使用强制一致性操作,或许是多此一举。
import os
import xlrd
import xlwt
import numpy as np
import pandas as pd
from time import time
from scipy import optimize
from scipy.special import expit
from sklearn import base
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, mean_absolute_error, f1_score, mutual_info_score
from mord import LogisticAT
class RLOC(base.BaseEstimator):
def __init__(self,alpha=1.0, verbose=0, max_iter=1000):
self.alpha = alpha
self.verbose = verbose
self.max_iter = max_iter
self.tol = 1e-12
self.X = None
self.y = None
self.nClass = None
self.nTheta = None
self.w = None
self.theta = None
def objection(self, x0):
w = x0[:self.nDim]
theta = x0[self.nDim:]
Xw = self.X.dot(w)
dist_to_theta = theta[:,None] - Xw
S = np.sign(np.arange(self.nClass - 1)[:, None] - self.y + 0.5)
err = -np.log(expit(S * dist_to_theta))
obj = np.sum(err)
obj += self.alpha * 0.5 * np.dot(w,w)
return obj
def gradient(self, x0):
w = x0[:self.nDim]
theta = x0[self.nDim:]
Xw = self.X.dot(w)
dist_to_theta = theta[:,None] - Xw
S = np.sign(np.arange(self.nClass - 1)[:, None] - self.y + 0.5)
Sigma = S * expit(-S * dist_to_theta)
grad_w = self.X.T.dot(Sigma.sum(0)) + self.alpha * w
grad_theta = -Sigma.sum(1)
return np.concatenate((grad_w, grad_theta), axis=0)
def fit(self, X, y):
self.X = X
self.y = np.array(y).astype(np.int32)
self.nSample, self.nDim = X.shape
self.labels = np.unique(self.y)
self.nClass = len(self.labels)
self.nTheta = self.nClass - 1
"""优化过程"""
x0 = np.zeros(self.nDim + self.nTheta)
x0[self.nDim:] = np.arange(self.nTheta)
options = {'maxiter':self.max_iter, 'disp':self.verbose}
bounds = [(None, None)] * (self.nDim +1 ) + [(None, None)] * (self.nTheta-1)
sol = optimize.minimize(self.objection, x0=x0, method='L-BFGS-B',
jac=self.gradient, bounds=bounds, options=options,tol=self.tol)
self.w, self.theta = sol.x[:self.nDim], sol.x[self.nDim:]
def predict(self, X):
tmp = self.theta[:,None] - np.asarray(X.dot(self.w))
pred = np.sum(tmp<0, axis=0).astype(np.int32)