Tingkatkan Adaboost yang menggunakan regresi logistik tertimbang sebagai pengganti pohon keputusan
Saya menerapkan Adaboost yang menggunakan regresi logistik berbobot alih-alih pohon keputusan dan saya berhasil mendapatkan kesalahan 0,5%, saya mencoba memperbaikinya selama berhari-hari tanpa hasil dan saya tahu mungkin untuk membuatnya kesalahan 0%, harap Anda orang bisa membantu saya melakukannya.
Algoritme regresi logistik saya:
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
Adaboost saya menggunakan WLR:
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()
Hasil iterasi ke-20:

Hasil iterasi ke-50:

Menurut saya, mesin tidak belajar di setiap iterasi regresi. Saya mendapatkan hasil yang sama, bahkan setelah iterasi ke-50. Saya ingin tahu apa yang saya lakukan salah, mungkin fungsi fit saya tidak diterapkan dengan baik? atau mungkin fungsi biaya saya?
Jawaban
Ini sepertinya cukup standar. Dengan regresi logistik sebagai penduga dasar, peningkatan adaptif berhenti menambahkan nilai setelah beberapa iterasi. Saya mengumpulkan buku catatan kecil untuk diilustrasikan, menggunakan sklearn
s AdaBoostClassifier, yang memungkinkan Anda untuk mengaturnya sendiri base_estimator
.)
Perhatikan bahwa tidak seperti dalam peningkatan gradien, Anda secara teoritis bisa mendapatkan model nonlinear di bagian akhir, karena fungsi tautan sigmoid diterapkan ke setiap model dasar sebelum menghitung rata-rata prediksi, bukan setelah menjumlahkan. Namun, contoh di notebook tidak menunjukkan hasil nonlinear yang kuat. Saya menduga ini hanya karena regresi logistik sangat cocok, sehingga poin yang salah diklasifikasikan "seimbang" sedemikian rupa sehingga pengulangan selanjutnya tidak berpengaruh banyak.
Untuk membangun komentar lain, meningkatkan dengan penduga basis linier tidak menambah kompleksitas seperti halnya dengan pohon. Jadi untuk meningkatkan keakuratan dalam penyiapan ini, Anda harus memasukkan kompleksitas tersebut (dimensi ekstra di mana data dapat dipisahkan secara linier) biasanya dengan menambahkan istilah interaksi atau istilah ekspansi polinomial dan biarkan penguat menangani regularisasi koefisien Anda.
Sklearn memiliki metode sederhana untuk ekspansi polinomial dengan dan tanpa istilah interaksi: https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.PolynomialFeatures.html