ปรับปรุง Adaboost ที่ใช้การถดถอยโลจิสติกส์แบบถ่วงน้ำหนักแทนทรีการตัดสินใจ

Aug 20 2020

ฉันใช้ Adaboost ที่ใช้การถดถอยโลจิสติกส์แบบถ่วงน้ำหนักแทนต้นไม้การตัดสินใจและฉันได้รับข้อผิดพลาด 0.5% ฉันพยายามปรับปรุงอยู่หลายวันโดยไม่ประสบความสำเร็จและฉันรู้ว่ามันเป็นไปได้ที่จะทำให้เขามีข้อผิดพลาด 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

Adaboost ของฉันโดยใช้ 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()

ผลการทำซ้ำครั้งที่ 20:

ผลการทำซ้ำครั้งที่ 50:

สำหรับฉันแล้วดูเหมือนว่าเครื่องไม่ได้เรียนรู้ในทุก ๆ การถดถอยซ้ำ ฉันได้ผลลัพธ์เดียวกันแม้ว่าจะทำซ้ำครั้งที่ 50 แล้วก็ตาม ฉันอยากทราบว่าฉันทำอะไรผิดบางทีฟังก์ชันที่พอดีของฉันใช้งานได้ไม่ดี? หรืออาจจะเป็นฟังก์ชันต้นทุนของฉัน

คำตอบ

4 BenReiniger Aug 20 2020 at 02:34

ดูเหมือนจะค่อนข้างได้มาตรฐาน ด้วยการถดถอยโลจิสติกเป็นตัวประมาณค่าพื้นฐานการเพิ่มค่าแบบปรับได้จะหยุดเพิ่มมูลค่าหลังจากการทำซ้ำน้อยมาก ฉันรวบรวมสมุดบันทึกเล่มเล็กเพื่อแสดงโดยใช้sklearns AdaBoostClassifierซึ่งช่วยให้คุณตั้งค่าของคุณเองbase_estimatorได้)

โปรดทราบว่าในทางทฤษฎีจะแตกต่างจากการเพิ่มการไล่ระดับสีตรงที่คุณสามารถหาแบบจำลองที่ไม่ใช่เชิงเส้นได้ในทางทฤษฎีเนื่องจากฟังก์ชันลิงก์ sigmoid จะถูกนำไปใช้กับโมเดลพื้นฐานแต่ละแบบก่อนที่จะทำการคาดคะเนค่าเฉลี่ยไม่ใช่หลังจากการสรุปผล อย่างไรก็ตามตัวอย่างในสมุดบันทึกจะไม่แสดงผลลัพธ์ที่ไม่เป็นเชิงเส้นอย่างชัดเจน ฉันสงสัยว่านี่เป็นเพียงเพราะการถดถอยโลจิสติกส์พอดีเกินไปดังนั้นจุดที่จัดประเภทผิดจะ "สมดุล" ในลักษณะที่การทำซ้ำในภายหลังไม่มีผลมากนัก

1 Tylerr Aug 21 2020 at 02:13

ในการสร้างความคิดเห็นอื่นการเพิ่มด้วยตัวประมาณฐานเชิงเส้นไม่ได้เพิ่มความซับซ้อนเหมือนที่ทำกับต้นไม้ ดังนั้นเพื่อเพิ่มความแม่นยำในการตั้งค่านี้คุณต้องฉีดความซับซ้อนนั้น (มิติพิเศษที่ข้อมูลสามารถแยกออกได้ในเชิงเส้น) โดยทั่วไปโดยการเพิ่มเงื่อนไขการโต้ตอบหรือเงื่อนไขการขยายพหุนามและปล่อยให้การส่งเสริมดูแลการกำหนดค่าสัมประสิทธิ์ของคุณให้เป็นมาตรฐาน

Sklearn มีวิธีง่ายๆในการขยายพหุนามที่มีและไม่มีเงื่อนไขการโต้ตอบ: https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.PolynomialFeatures.html