의사 결정 트리 대신 가중 로지스틱 회귀를 사용하는 Adaboost 개선
나는 의사 결정 트리 대신 가중 로지스틱 회귀를 사용하여 0.5 % 오류를 얻을 수있는 Adaboost를 구현했으며 성공하지 못한 채 며칠 동안 개선하려고 노력하고 있으며 그와 함께 0 % 오류를 얻을 수 있다는 것을 알고 있습니다. 사람들이 나를 도울 수 있습니다.
내 로지스틱 회귀 알고리즘 :
Lg.py :
import numpy as np
from scipy.optimize import fmin_tnc
class LogistReg:
def __init__(self,X,y,w):
self.X = np.c_[np.ones((X.shape[0],1)),X]
self.y = np.copy(y[:,np.newaxis])
self.y[self.y==-1]=0
self.theta = np.zeros((self.X.shape[1],1))
self.weights = w
def sigmoid(self, x):
return 1.0/(1.0 + np.exp(-x))
def net_input(self, theta, x):
return np.dot(x,theta)
def probability(self,theta, x):
return self.sigmoid(self.net_input(theta,x))
def cost_function(self,theta,x,y):
m = x.shape[0]
tmp = (y*np.log(self.probability(theta,x)) + (1-y)*np.log(1-self.probability(theta,x)))
total_cost = -(1.0/m )* np.sum(tmp*self.weights)/np.sum(self.weights)
return total_cost
def gradient(self,theta,x,y):
m = x.shape[0]
return (1.0/m)*np.dot(x.T,(self.sigmoid(self.net_input(theta,x))-y)*self.weights)
def fit(self):
opt_weights = fmin_tnc(func=self.cost_function,x0=self.theta,fprime=self.gradient,
args=(self.X,self.y.flatten()))
self.theta = opt_weights[0][:,np.newaxis]
return self
def predict(self,x):
tmp_x = np.c_[np.ones((x.shape[0],1)),x]
probs = self.probability(self.theta,tmp_x)
probs[probs<0.5] = -1
probs[probs>=0.5] = 1
return probs.squeeze()
def accuracy(self,x, actual_clases, probab_threshold = 0.5):
predicted_classes = (self.predict(x)>probab_threshold).astype(int)
predicted_classes = predicted_classes.flatten()
accuracy = np.mean(predicted_classes == actual_clases)
return accuracy*100.0
WLR을 사용하는 내 Adaboost :
adaboost_lg.py :
import numpy as np
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
import matplotlib.pyplot as plt
from sklearn.datasets import make_gaussian_quantiles
from sklearn.model_selection import train_test_split
from plotting import plot_adaboost, plot_staged_adaboost
from Lg import LogistReg
class AdaBoostLg:
""" AdaBoost enemble classifier from scratch """
def __init__(self):
self.stumps = None
self.stump_weights = None
self.errors = None
self.sample_weights = None
def _check_X_y(self, X, y):
""" Validate assumptions about format of input data"""
assert set(y) == {-1, 1}, 'Response variable must be ±1'
return X, y
def fit(self, X: np.ndarray, y: np.ndarray, iters: int):
""" Fit the model using training data """
X, y = self._check_X_y(X, y)
n = X.shape[0]
# init numpy arrays
self.sample_weights = np.zeros(shape=(iters, n))
self.stumps = np.zeros(shape=iters, dtype=object)
self.stump_weights = np.zeros(shape=iters)
self.errors = np.zeros(shape=iters)
# initialize weights uniformly
self.sample_weights[0] = np.ones(shape=n) / n
for t in range(iters):
# fit weak learner
curr_sample_weights = self.sample_weights[t]
stump = LogistReg(X,y,curr_sample_weights)
#stump = LogisticRegression()
#stump = stump.fit(X, y, sample_weight=curr_sample_weights)
stump = stump.fit()
# calculate error and stump weight from weak learner prediction
stump_pred = stump.predict(X)
err = curr_sample_weights[(stump_pred != y)].sum()# / n
stump_weight = np.log((1 - err) / err) / 2
# update sample weights
new_sample_weights = (
curr_sample_weights * np.exp(-stump_weight * y * stump_pred)
)
new_sample_weights /= new_sample_weights.sum()
# If not final iteration, update sample weights for t+1
if t+1 < iters:
self.sample_weights[t+1] = new_sample_weights
# save results of iteration
self.stumps[t] = stump
self.stump_weights[t] = stump_weight
self.errors[t] = err
return self
def predict(self, X):
""" Make predictions using already fitted model """
stump_preds = np.array([stump.predict(X) for stump in self.stumps])
return np.sign(np.dot(self.stump_weights, stump_preds))
def make_toy_dataset(n: int = 100, random_seed: int = None):
""" Generate a toy dataset for evaluating AdaBoost classifiers """
n_per_class = int(n/2)
if random_seed:
np.random.seed(random_seed)
X, y = make_gaussian_quantiles(n_samples=n, n_features=2, n_classes=2)
return X, y*2-1
# assign our individually defined functions as methods of our classifier
if __name__ =='__main__':
X, y = make_toy_dataset(n=10, random_seed=10)
# y[y==-1] = 0
plot_adaboost(X, y)
clf = AdaBoostLg().fit(X, y, iters=20)
#plot_adaboost(X, y, clf)
train_err = (clf.predict(X) != y).mean()
#print(f'Train error: {train_err:.1%}')
plot_staged_adaboost(X, y, clf, 20)
plt.show()
20 번째 반복 결과 :

50 번째 반복 결과 :

기계가 모든 회귀 반복에서 학습하지 않는 것 같습니다. 50 번째 반복 후에도 동일한 결과를 얻습니다. 내가 뭘 잘못하고 있는지 알고 싶습니다. 내 맞춤 기능이 제대로 구현되지 않았을 수 있습니까? 아니면 내 비용 함수?
답변
이것은 꽤 표준적인 것 같습니다. 로지스틱 회귀를 기본 추정량으로 사용하면 적응 형 부스팅이 매우 적은 반복 후에 값 추가를 중지합니다. 설명하기 위해 s를 사용하여 작은 노트북 을 모아서 직접 설정할 수 있습니다 .)sklearn
AdaBoostClassifierbase_estimator
그래디언트 부스팅과는 달리 시그 모이 드 링크 함수는 합산 후가 아니라 예측을 평균화하기 전에 각 기본 모델에 적용되기 때문에 이론적으로 끝에 비선형 모델을 얻을 수 있습니다. 그러나 노트북의 예에는 강력한 비선형 결과가 표시되지 않습니다. 나는 이것이 로지스틱 회귀가 너무 잘 맞아서 잘못 분류 된 포인트가 나중의 반복이 많은 영향을 미치지 않도록 "균형"이되어 있기 때문이라고 생각합니다.
다른 의견을 바탕으로 선형 기본 추정기로 부스팅해도 나무처럼 복잡성이 추가되지는 않습니다. 따라서이 설정에서 정확도를 높이려면 일반적으로 상호 작용 항 또는 다항식 확장 항을 추가하여 복잡성 (데이터가 선형으로 분리 가능한 추가 차원)을 주입하고 부스팅이 계수의 정규화를 처리하도록해야합니다.
Sklearn에는 상호 작용 항이 있거나없는 다항식 확장을위한 간단한 방법이 있습니다. https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.PolynomialFeatures.html