กรณีศึกษาแบบ End-too-End เพื่อคาดการณ์เงินเดือนของการลงประกาศรับสมัครงานสำหรับเครื่องมือค้นหางานโดยใช้การเรียนรู้ของเครื่องด้วยการใช้ Python

“การศึกษาไม่ใช่การทำให้ฝูงสัตว์ผอมบาง การศึกษาคือการช่วยให้นักเรียนทุกคนประสบความสำเร็จ”

แอนดรูว์ อึ้ง

ในกรณีศึกษาวิทยาศาสตร์ข้อมูลแบบครบวงจรนี้ เราจะใช้โมเดลการเรียนรู้ของเครื่องที่หลากหลายเพื่อประเมินเงินเดือนสำหรับการลงประกาศรับสมัครงานสำหรับเครื่องมือค้นหางาน แน่นอน เราจะฝึกอบรมและประเมินประสิทธิภาพของโมเดล ML หลายรายการโดยใช้ K-Fold Cross Validation และ RMSE/MSE/MAE โดยประมาณ แบบจำลองที่มีประสิทธิภาพดีที่สุดจะถูกเลือกในตอนท้าย และจะบันทึกเงินเดือนที่คาดการณ์ไว้สำหรับการลงประกาศงานการทดสอบด้วย

พื้นที่เก็บข้อมูล GitHub พร้อมข้อมูลและโค้ด Python ที่นี่

เนื้อหาของบล็อก

<แข็งแกร่ง>1. การกำหนดเป้าหมายทางธุรกิจและวิทยาศาสตร์ข้อมูล

<แข็งแกร่ง>2. การประมวลผลข้อมูลล่วงหน้า

<แข็งแกร่ง>3. การแสดงข้อมูล

<แข็งแกร่ง>4. วิธีการ (การเปรียบเทียบและคำอธิบายโมเดล ML)

<แข็งแกร่ง>5. กระบวนการฝึกอบรมแบบทีละขั้นตอนของโมเดล Machine Learning

<แข็งแกร่ง>6. การประเมินโมเดลการเรียนรู้ของเครื่องของเรา

<แข็งแกร่ง>7. ความสำคัญของคุณลักษณะ

1. การกำหนดเป้าหมายทางธุรกิจและวิทยาศาสตร์ข้อมูล

หากคุณเคยลองใช้เครื่องมือค้นหางานสมัยใหม่ เช่น “Glassdoor”, “Indeed” สำหรับ “LinkedIn ” คุณอาจสังเกตเห็นว่าประกาศรับสมัครงานบางรายการมีเงินเดือนระบุไว้ ในขณะที่ส่วนใหญ่ไม่ได้ให้ข้อมูลนั้น ข้อมูลเงินเดือนต่อการลงประกาศรับสมัครงานมีประโยชน์มากสำหรับผู้สมัคร เนื่องจากช่วยประหยัดเวลาล่วงหน้าได้มาก วิธีนี้จะหลีกเลี่ยงไม่ให้ผู้สมัครต้องผ่านกระบวนการต่างๆ และพบว่าในตอนท้ายพวกเขาจะไม่ได้รับค่าตอบแทนตามนั้นหรือตามที่คาดไว้

นี่เป็นปัญหาสำคัญสำหรับเครื่องมือค้นหางานใดๆ เนื่องจากการลงประกาศรับสมัครงานส่วนใหญ่ไม่รวมเงินเดือน และการเพิ่มฟีเจอร์เหล่านี้อาจเพิ่มความพึงพอใจและการมีส่วนร่วมของผู้ใช้เครื่องมือค้นหาได้

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

เป้าหมายทางธุรกิจ

ในกรณีศึกษานี้ เรามุ่งมั่นที่จะสร้างคุณลักษณะการประมาณการเงินเดือนสำหรับเครื่องมือค้นหางาน เงินเดือนโดยประมาณสำหรับการลงประกาศรับสมัครงานใหม่สามารถปรับปรุงประสบการณ์ของผู้หางานได้โดยการให้ข้อมูลเงินเดือนแก่พวกเขา

เป้าหมายด้านเทคนิค (วิทยาศาสตร์ข้อมูล)

เป้าหมายทางเทคนิคของกรณีศึกษานี้คือการใช้แมชชีนเลิร์นนิงเพื่อคาดการณ์เงินเดือนของโอกาสในการทำงานตามลักษณะงาน

เราจะตอบคำถามต่อไปนี้:

  1. คุณใช้ภาษาและไลบรารีซอฟต์แวร์ใดในการแก้ปัญหา เหตุใดคุณจึงเลือกภาษา/ห้องสมุดเหล่านี้
  2. เราทำตามขั้นตอนอะไรบ้างในการเตรียมข้อมูลสำหรับโครงการ จำเป็นต้องทำความสะอาดหรือไม่?
  3. มีการใช้วิธีแมชชีนเลิร์นนิงอย่างไร
  4. ทำไมเราถึงเลือกวิธีนี้?
  5. เราพิจารณาวิธีการอื่นใดอีกบ้าง?
  6. อธิบายวิธีการทำงานของอัลกอริทึมการเรียนรู้ของเครื่อง
  7. จำเป็นต้องมีการเข้ารหัสหรือการเปลี่ยนแปลงคุณสมบัติใดๆ หรือไม่ และอันใด
  8. คุณสมบัติใดมีผลกระทบต่อเงินเดือนมากที่สุด? เราระบุสิ่งเหล่านี้ให้มีความสำคัญมากที่สุดได้อย่างไร คุณสมบัติใดมีผลกระทบต่อเงินเดือนน้อยที่สุด? เราระบุสิ่งเหล่านี้ได้อย่างไร?
  9. เราฝึกโมเดล Machine Learning อย่างไร ในระหว่างการฝึกอบรม มีปัญหาอะไรบ้างที่น่ากังวล?
  10. คุณสร้างค่าประมาณสำหรับเมตริกประสิทธิภาพ RMSE ได้อย่างไร
  11. ตัวชี้วัดใดนอกเหนือจาก RMSE ที่จะเป็นประโยชน์ในการประเมินความถูกต้องของการประมาณการเงินเดือน ทำไม

2. การประมวลผลข้อมูลล่วงหน้า

มาดูข้อมูลกันอย่างรวดเร็ว

คุณสมบัติการฝึกอบรม

train_features.csv: แต่ละแถวแสดงถึงข้อมูลเมตาสำหรับการลงประกาศรับสมัครงานแต่ละรายการ

คุณสมบัติการทดสอบ

test_features.csv: คล้ายกับ train_features.csv โดยที่แต่ละแถวแสดงถึงข้อมูลเมตาสำหรับประกาศรับสมัครงานแต่ละรายการ

เงินเดือนการฝึกอบรม

train_salaries.csv : แต่ละแถวเชื่อมโยง "jobId" กับ "salary" นี่คือตัวแปรที่ขึ้นกับการฝึกเพื่อควบคุมโมเดล Machine Learning

train_features = 'train_features.csv'
train_response = 'train_salaries.csv'
test_features = 'test_features.csv'
# loading training features
train_featuresDf = pd.read_csv(train_features, header=0)
# loading salaries: dependent variable
train_responseDf = pd.read_csv(train_response, header=0)
# combining job features and salaries 
trainDf = train_featuresDf.merge(train_responseDf,on=None, how="inner")
# loading test features
testDf = pd.read_csv(test_features, header=0)

การทำความสะอาดและการเตรียมข้อมูล

เพื่อเตรียมข้อมูลสำหรับโครงการ ฉันทำตามขั้นตอนต่อไปนี้

  • โหลดชุดข้อมูลและสำรวจชุดข้อมูลเหล่านั้น
  • ผสานคุณลักษณะการฝึกอบรมเข้ากับเงินเดือนการฝึกอบรม
  • ระบุคุณสมบัติเชิงตัวเลขและคุณสมบัติเชิงหมวดหมู่
  • รับสถิติเชิงพรรณนาง่ายๆ เกี่ยวกับข้อมูลและดูว่ามีค่าแปลก ๆ หรือความคลาดเคลื่อนหรือไม่
  • ตรวจสอบจุดข้อมูลที่หายไป (NULL และ NA)
  • ตรวจสอบรายการที่ซ้ำกัน
  • ตรวจสอบค่าที่ไม่ถูกต้องและค่าผิดปกติ (การตรวจสอบค่าที่ไม่ใช่ค่าบวก กฎช่วงควอนไทล์ระหว่างกัน การตรวจสอบด้วยภาพ การสำรวจข้อมูล การแสดงภาพการกระจายข้อมูลสำหรับคุณสมบัติเชิงตัวเลขและบ็อกซ์พล็อตที่เกี่ยวข้องกับตัวแปรตอบสนอง: เงินเดือน)
  • ตั้งค่าสถานะค่าผิดปกติและลบออกจากข้อมูล
  • เข้ารหัสตัวแปรหมวดหมู่
  • ทำให้ JobId เป็นดัชนี
  • บันทึกข้อมูลสำหรับกระบวนการต่อไป

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

# for numeric features only 
        yearsExperience  milesFromMetropolis
count   1000000.000000       1000000.000000
mean         11.992386            49.529260
std           7.212391            28.877733
min           0.000000             0.000000
25%           6.000000            25.000000
50%          12.000000            50.000000
75%          18.000000            75.000000
max          24.000000            99.000000
def process_validate_data(self):
        '''data exploration and validation process'''
        # load and store training data to dataFrame
        self._create_training_df()
        # load and store test data to dataFrame
        self._create_test_df()
        # get information about the features: categorical and numerical features
        self._get_features_info()
        # get training data statistics
        self._get_trainDf_statistics()
        # get test data statistics
        self._get_testDf_statistics()
        # checking for missing data points
        self._check_missing_data(self.trainDf)
        # checking the number of repeatitions/duplicates
        self._check_duplicates()
        # getting all columns containing negative or 0 values which is something we don't expect
        self._get_invalid_data(self.trainDf, pred_response)
def _get_features_info(self):
    '''getting categorical and numerical features'''
    self.features_cat = self._get_cat_features(self.trainDf)
    self.features_num = self._get_num_features(self.trainDf)
def _get_cat_features(self, df):
    '''finding  categorical columns in Dataframe'''
    self.features_cat = df.select_dtypes(include=['O']).columns.tolist()
    print('List of Categorical Features: {}'.format(self.features_cat))
    return (self.features_cat)
def _get_num_features(self, df):
    '''finding numerical columns in Dataframe'''
    self.features_num = df.select_dtypes(exclude=['O']).columns.tolist()
    print('List of Numerical Features: {}'.format(self.features_num))
    return (self.features_num)
def _get_trainDf_statistics(self):
    print('Training Data Statistics')
    self._get_statistics(self.trainDf)
def _get_testDf_statistics(self):
    print('Test Data Statistics')
    self._get_statistics(self.testDf)
def _get_statistics(self, df):
    print('\n  Dataframe Information: \n')
    print('n{}'.format(df.info()))
    print('\n Dataframe Size [#rows, #cols]- {}'.format(df.shape))
    print('\n Numerical Features Statistics: \n \n{}'.format(df.describe()))
    print('\n Categorical Features Stats: \n \n{}'.format(df.describe(include='O')))
def _check_missing_data(self, df):
    '''Checking and finding  null or na values in Dataframe'''
    num_missingval = np.sum(df.isna().sum()) + np.sum(df.isnull().sum())
    if num_missingval == 0:
        print('\n\n : There are no missing data points in the data')
    else:
        print('Features or columns that contain missing values\n\n{}'.format(df.isnull().sum()))
def _check_duplicates(self):
    '''Checking for duplicates'''
    print('\n : There are {} duplicate values in Train Data'.format(self.trainDf.duplicated().sum()))
    # though we found 5 repetitions in salary feature, this is not a duplicate since multiple jobs can have the same salary
    print('\n : There are {} duplicate values in Test Data'.format(self.testDf.duplicated().sum()))
def _get_invalid_data(self, df, cols):
    '''Finding and flagging invalid values'''
    for i in [cols]:
        # we don't expect any of the values to be equal to 0 so we will identify anything <= 0
        inv_counts = np.sum(df[i] <= 0)
        if inv_counts > 0:
            self.invalid_data = True
            print('\n :There are {} duplicates in {} column'.format(inv_counts, i))

การเข้ารหัสคุณสมบัติ

เนื่องจากมีคุณลักษณะสตริงที่เป็นหมวดหมู่ปรากฏอยู่ในข้อมูล เช่น ['companyId', 'jobType', 'degree', 'major', 'industry'] หากต้องการใช้ในโมเดล ตัวแปรเหล่านี้จะต้องได้รับการเข้ารหัสเพื่อแปลงสตริงให้เป็นค่าตัวเลข

เราใช้ LabelEncoder เพื่อทำการเข้ารหัส ฉันกำลังคิดที่จะใช้ One Hot Encoder แต่นั่นอาจทำให้เป็นการยากที่จะตัดสินในแง่ของความสำคัญของฟีเจอร์

def clean_encode_df(self):
    '''Cleaning Data From Invalid Data points/Errors'''
    '''Since salaries equal to 0 (lower limit we found) don't make sense, /n we assume they are outliers and we will fag and remove them'''
    if self.invalid_data:
        print('Number of data points before removing invalid rows:- {}'.format(data.trainDf.shape[0]))
        data.trainDf = data.trainDf[data.trainDf['salary'] > 0]
        print('Number of data points after removing invalid rows with zero salary:- {}'.format(data.trainDf.shape[0]))
    ''' Encoding the categorical labels in training data'''
    trainDf = self.encode_cat_features(data.trainDf, self.features_cat)
    # since this is unique per observations it doesn't make sense to encode it
    # but we still need the jobIds, therefore we will use it as the index
    self.trainDf = trainDf.set_index("jobId").drop("index",1)

    ''' Encoding the categorical labels in test data'''
    testDf = self.encode_cat_features(data.testDf, self.features_cat, test_data=True)
    self.testDf = testDf.set_index("jobId")

def encode_cat_features(self, df, features, test_data=False):
    '''encoding the labels in categorical features'''
    if not test_data:
        for feature in features:
            l_encoder = LabelEncoder()
            l_encoder.fit(df[feature])
            self.labels[feature] = l_encoder
            df[feature] = l_encoder.transform(df[feature])
    else:
        # encoding for test data
        for feature, l_encoder in self.labels.items():
            df[feature] = l_encoder.transform(df[feature])
    return (df)

3. การแสดงข้อมูล

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

def _distplot(self):
    '''Creates Distribution Plots for Numeric Features'''
    fig = plt.figure(figsize=(14, 10))
    for index, col in enumerate(self.features_num):
        fig.add_subplot(len(self.features_num), len(self.features_num), index + 1)
        n, x, _ = plt.hist(self.trainDf[col], bins=20, color='yellow', edgecolor='black', linewidth=0.5)
        bin_centers = 0.5 * (x[1:] + x[:-1])
        plt.plot(bin_centers, n, color='darkgreen', linewidth=2)
        plt.title('Distribution Plot for Numeric Features')
        plt.xlabel(str(col))
        plt.tight_layout()

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

def _boxplot(self):
    '''Creates BoxPlots for Categorical and Numeric Features'''
    df = self.trainDf.copy()
    fig = plt.figure(figsize=(14, 9))
    for index, col in enumerate(self.features_cat):
        if len(self.trainDf[col].unique()) < 10:
            df[col + '_mean'] = df.groupby(col)[self.pred_response].transform('mean')
            fig.add_subplot(4, 2, index + 1)
            sns.boxplot(x=col, y=self.pred_response, data=df.sort_values(col + '_mean'))
            plt.title('Salaries vs {}'.format(col), fontsize=12)
            plt.tight_layout()
            plt.xticks(rotation=45)
    for index, col in enumerate(self.features_num):
        fig.add_subplot(len(self.features_num), len(self.features_num), index + 1)
        sns.boxplot(self.trainDf[col], color='yellow')
        plt.tight_layout()

4. วิธีการ

เราจะใช้โมเดล Machine Learning ต่อไปนี้ ตั้งแต่เทคนิคการถดถอยง่ายๆ เช่น Linear Regression ไปจนถึงโมเดล Ensemble เช่น Ensemble Model GBM และ XGBoost

  • การถดถอยเชิงเส้น
  • การถดถอยแบบ Lasso (การทำให้เป็นมาตรฐาน L1)
  • ป่าสุ่ม
  • โมเดลการเร่งการไล่ระดับสี (GBM)
  • XGBoost

เปรียบเทียบรุ่น ML

เราจะเห็นในตอนท้ายว่าฉันลงเอยด้วยการใช้อัลกอริธึม GBM เป็นแบบจำลองที่เลือกขั้นสุดท้าย เนื่องจากเป็นที่ทราบกันว่าให้ความแม่นยำในการทำนายที่ดีกว่าสำหรับปัญหาประเภทการถดถอย และสามารถจัดการชุดข้อมูลที่ซับซ้อนด้วยแถวนับล้านแถวและคุณลักษณะหมวดหมู่/ตัวเลข ซึ่งเป็นข้อได้เปรียบที่ยิ่งใหญ่เหนือแผนผังการตัดสินใจ การบรรจุถุง และแม้แต่ป่าสุ่ม GBM เช่นเดียวกับโมเดล Boosting อื่นๆ คือเรียนรู้อย่างช้าๆ แต่แม่นยำยิ่งขึ้น และแตกต่างจาก AdaBoost ตรงที่ GBM มันไม่ไวต่อค่าผิดปกติ และสามารถจัดการกับโมเดลที่ไม่ใช่เชิงเส้นที่ซับซ้อนได้ นี่คือเหตุผลว่าทำไมฉันถึงไม่ใช้ AdaBoost

เช่นเดียวกับ Bagging (การหาค่าเฉลี่ยต้นไม้การตัดสินใจที่สัมพันธ์กัน) และ Random Forest (การหาค่าเฉลี่ยต้นไม้การตัดสินใจที่ไม่สัมพันธ์กัน) Boosting มีจุดมุ่งหมายเพื่อปรับปรุงการคาดการณ์ที่เกิดจากแผนผังการตัดสินใจ Boosting คือโมเดล Machine Learning ที่มีการดูแล ซึ่งสามารถใช้ได้ทั้งกับปัญหาการถดถอยและการจัดหมวดหมู่

ต่างจาก Bagging หรือ Random Forest ที่ต้นไม้ถูกสร้างขึ้นแยกจากกันโดยใช้หนึ่งในตัวอย่างที่บู๊ตแบบ B (สำเนาของวันที่ฝึกอบรมครั้งแรก) ใน Boosting ต้นไม้จะถูกสร้างขึ้นตามลำดับและขึ้นอยู่กับแต่ละต้น: ต้นไม้แต่ละต้นถูกปลูกโดยใช้ ข้อมูลจากต้นไม้ที่ปลูกก่อนหน้านี้

การเพิ่มความเร็วเป็นที่ทราบกันดีว่ามีความแปรปรวนต่ำกว่าและมีแนวโน้มที่จะเกิดการโอเวอร์ฟิตน้อยกว่าเมื่อเปรียบเทียบกับรุ่นอื่นๆ สามรุ่นดังที่กล่าวไว้ข้างต้น มันดีกว่าโมเดลรวมอื่นๆ เช่น Bagging (การสร้างต้นไม้ที่สัมพันธ์กัน) หรือ Random Forest (การสร้างต้นไม้ที่ไม่สัมพันธ์กันเนื่องจากองค์ประกอบแบบสุ่ม)

โมเดลการเร่งการไล่ระดับสีทำงานอย่างไร

การส่งเสริมมีจุดมุ่งหมายเพื่อปรับปรุงการคาดการณ์ที่เกิดจากแผนผังการตัดสินใจ Boosting คือโมเดล Machine Learning ที่มีการดูแล ซึ่งสามารถใช้ได้ทั้งกับปัญหาการถดถอยและการจัดหมวดหมู่ ฉันn การส่งเสริม ต้นไม้ถูกสร้างขึ้นตามลำดับและพึ่งพาซึ่งกันและกัน: ต้นไม้แต่ละต้นปลูกโดยใช้ข้อมูลจากต้นไม้ที่ปลูกก่อนหน้านี้

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

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

GBM เริ่มต้นกระบวนการเรียนรู้โดยการเลือกต้นไม้ใบเดียวและสร้างต่อโดยใช้ผู้เรียนที่อ่อนแอจากตราประทับครั้งก่อน ผลลัพธ์ที่สอดคล้องกับลีฟที่เลือกนี้จึงเป็นการเดาเบื้องต้นสำหรับตัวแปรผลลัพธ์

เพื่อให้แน่ใจว่าต้นไม้ไม่ได้พอดีเกินไป การไล่ระดับสีจะใช้อัตราการเรียนรู้ (eta) เพื่อปรับขนาดการไล่ระดับสี การเพิ่มการไล่ระดับสีขึ้นอยู่กับแนวคิดที่ว่าการก้าวเล็กๆ หลายๆ ก้าวไปในทิศทางที่ถูกต้อง (การไล่ระดับสี) จะส่งผลให้เกิดความแปรปรวนที่ลดลง (สำหรับการทดสอบข้อมูล) GBM ระบุข้อบกพร่องของโมเดลก่อนหน้าโดยใช้การไล่ระดับสีของฟังก์ชันการสูญเสีย ฟังก์ชันการสูญเสียเป็นการวัดที่บ่งชี้ว่าค่าสัมประสิทธิ์ของโมเดลเหมาะสมกับข้อมูลพื้นฐานได้ดีเพียงใด

ในการสร้าง GBM สามารถใช้กระบวนการทีละขั้นตอนได้:

  • ขั้นตอนที่ 1:คำนวณค่าเฉลี่ยของตัวแปรผลลัพธ์ และใช้เพื่อคำนวณ หลอกตกค้าง
  • ขั้นตอนที่ 2:ใช้คุณลักษณะที่มีอยู่และ Pseudo Residual เป็นตัวแปรผลลัพธ์เพื่อคาดการณ์ค่าคงเหลือ
  • ขั้นตอนที่ 3:เราใช้ส่วนที่เหลือที่คาดการณ์ไว้เพื่ออัปเดตการคาดการณ์จากขั้นตอนก่อนหน้า ในขณะเดียวกันก็ปรับขนาดการสนับสนุนนี้ไปยังแผนภูมิต้นไม้ด้วยอัตราการเรียนรู้
  • ขั้นตอนที่ 4:กระบวนการนี้จะดำเนินต่อไปเพื่ออัปเดตสิ่งตกค้างหลอกและต้นไม้ในขณะที่ปรับขนาดด้วยอัตราการเรียนรู้ ซึ่งจะช่วยให้เคลื่อนที่ไปในทิศทางที่ถูกต้องอย่างช้าๆ จนกว่าจะไม่มีการปรับปรุงหรือกฎการหยุดของเราอีกต่อไป
from sklearn import linear_model
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from xgboost import XGBRegressor
LR = linear_model.LinearRegression()
Lasso_LR = linear_model.Lasso()
RForest = RandomForestRegressor(n_estimators=60, n_jobs=4, max_depth=15, min_samples_split=80, max_features=8,verbose=0)
GBM = GradientBoostingRegressor(n_estimators=60, max_depth=7, loss='ls', verbose=0)
xgboost = XGBRegressor(n_estimators=60, max_depth=7, eta=0.1, subsample=0.7, colsample_bytree=0.8)
models = [LR, Lasso_LR, RForest, GBM, xgboost]

5. โมเดลการเรียนรู้ของเครื่องฝึกอบรม

ต่อไปนี้เป็นแนวทางทีละขั้นตอนสำหรับการฝึกอบรม Machine Learning Model

ขั้นตอนที่ 1: รวบรวมและจัดเตรียมข้อมูล

ขั้นตอนแรกในการฝึกโมเดล Machine Learning คือการรวบรวมและเตรียมข้อมูลที่จะใช้ในการฝึกโมเดล ซึ่งอาจเกี่ยวข้องกับการล้างข้อมูล การจัดการค่าที่หายไป และการเลือกชุดย่อยของข้อมูลสำหรับการฝึก

ขั้นตอนที่ 2: แบ่งข้อมูลออกเป็นชุดการฝึกอบรมและการตรวจสอบความถูกต้อง

เป็นเรื่องปกติที่จะแบ่งข้อมูลออกเป็นสองชุด: ชุดการฝึกและชุดการตรวจสอบ แบบจำลองจะได้รับการฝึกในชุดการฝึกและประเมินในชุดการตรวจสอบ

ขั้นตอนที่ 3: เลือกรุ่นและตั้งค่าไฮเปอร์พารามิเตอร์

ถัดไป คุณจะต้องเลือกโมเดลแมชชีนเลิร์นนิงและตั้งค่าไฮเปอร์พารามิเตอร์ ไฮเปอร์พารามิเตอร์คือพารามิเตอร์ของโมเดลที่ไม่ได้เรียนรู้จากข้อมูลระหว่างการฝึก เช่น อัตราการเรียนรู้หรือความแข็งแกร่งในการปรับให้เป็นมาตรฐาน

ขั้นตอนที่ 4: ฝึกโมเดล

แบบจำลองได้รับการฝึกฝนโดยใช้ข้อมูลการฝึกอบรมและอัลกอริธึมการปรับให้เหมาะสมที่เลือก อัลกอริธึมการปรับให้เหมาะสมจะอัปเดตพารามิเตอร์โมเดลเพื่อลดฟังก์ชันการสูญเสีย ซึ่งจะวัดความแตกต่างระหว่างเอาต์พุตจริงและเอาต์พุตที่คาดการณ์ไว้

ขั้นตอนที่ 5: ประเมินแบบจำลอง

หลังจากที่โมเดลได้รับการฝึกฝนแล้ว โมเดลจะได้รับการประเมินในชุดการตรวจสอบความถูกต้องเพื่อประเมินประสิทธิภาพ เมทริกการประเมินจะขึ้นอยู่กับปัญหา ML ที่เฉพาะเจาะจง เช่น ความแม่นยำสำหรับงานการจัดหมวดหมู่หรืองานการถดถอย

ขั้นตอนที่ 6: ปรับแต่งโมเดล

หากแบบจำลองทำงานได้ไม่ดีในชุดการตรวจสอบ คุณอาจต้องปรับไฮเปอร์พารามิเตอร์หรือลองใช้วิธีอื่น กระบวนการนี้เรียกว่าการปรับโมเดลอย่างละเอียด

ขั้นตอนที่ 7: ทดสอบโมเดลสุดท้าย

เมื่อคุณพอใจกับประสิทธิภาพของแบบจำลองในชุดการตรวจสอบแล้ว คุณสามารถสรุปแบบจำลองและประเมินผลในชุดทดสอบได้ ข้อมูลนี้จะให้ค่าประมาณประสิทธิภาพของโมเดลกับข้อมูลที่มองไม่เห็น

class SalaryPredictingModel:
    def __init__(self, data, models):
        '''training multiple ML models for predicting salaries'''
        self.data = data
        self.models = models
        self.mse = {}
        self.rmse = {}
        self.mae = {}
        self.best_model = None
        self.predictions = None
        self.pred_response = data.pred_response
        self.train_response = data.trainDf[data.pred_response]
        self.train_features = data.trainDf.drop(data.pred_response, axis=1)
        self.testDf = data.testDf
        self.train_models()
    def train_models(self):
        self.KFold_CV_model()
        self.get_best_model()
    print('Training Process with K-Fold Cross Validation')
    ''' we will use K-fold CV for estimating average test error rate'''
    # defaults is K=5 in K-fold
    def KFold_CV_model(self):
        for model_output in self.models:
            print("Training model" + str(model_output) +" and calculating CV MSE, CV MAE, CV RMSE")
            scores_mse = cross_val_score(model_output, self.train_features, self.train_response, cv=5,scoring='neg_mean_squared_error')
            scores_mae = cross_val_score(model_output, self.train_features, self.train_response, cv=5,scoring='neg_mean_absolute_error')
            scores_rmse = cross_val_score(model_output, self.train_features, self.train_response, cv=5,scoring='neg_root_mean_squared_error')
            self.mse[model_output] = -1.0 * np.mean(scores_mse)
            self.mae[model_output] = -1.0 * np.mean(scores_mae)
            self.rmse[model_output] = -1.0 * np.mean(scores_rmse)
    # picking the model with the least CV RMSE, then fitting and predicting that model
    def get_best_model(self):
        '''Selecting best model with RMSE, fitting the model train data'''
        self.best_model = min(self.rmse, key=self.rmse.get)
        self.get_model_performance()
    def get_model_performance(self):
        print("Model Performance")
        for key, item in self.rmse.items():
            print('\n Score of the model {} :-'.format(key))
            print('\n RMSE - {}'.format(item))
        print('\n Best model with smallest RMSE\n\n {} :-'.format(self.best_model))
        print('\n RMSE - {}'.format(self.rmse[self.best_model]))
        print('\nTraining the Best Model.....')
        self.best_model.fit(self.train_features, self.train_response)
        print('\n Getting Feature Importance')
        self._plot_feature_importance()
        print('\nPrediction for test data with Best Model')
        self.testDf[self.pred_response] = self.best_model.predict(self.testDf)
        
        print('-------------------------- Best Model Performance ------------------------')
        print(self.testDf[self.pred_response])
    def _plot_feature_importance(self):
        '''Printing the feature importance used to train the model'''
        print('\n Feature Importance Calculation')
        features = self.train_features.columns.to_list()
        importances = self.best_model.feature_importances_
        indices = np.argsort(importances)
        plt.figure(figsize=(7, 6))
        plt.title('Feature Importances')
        plt.barh(range(len(indices)),
                 importances[indices], color='r', align='center')
        plt.yticks(range(len(indices)), [features[i] for i in indices])
        plt.xlabel('Relative Importance')
        plt.show()
        
    @staticmethod
    def saving_best_model(model_file, model):
        ''' Saving the best model to a file'''
        print('\n Saving Best Model to file')
        pickle.dump(model, open(model_file, 'wb'))
    print('Saving the Predictions to CSV file')
    def saving_results(self, sub_file, df):
        print('\n Saving job Salary predictions in testDf to a CSV file')
        print('--------------------------------------------------------------------------------')
        self.testDf[self.pred_response].to_csv(sub_file, index=True, header = 0)
    @staticmethod
    def hyperparameter_tuning(estimator, param_grid, n_iter=5, scoring='neg_root_mean_absolute_error', cv=5, n_jobs=-2,
                              refit=False):
        ''' Finding Optimal hyper-parameters used in models'''
        rs_cv = RandomizedSearchCV(estimator=estimator, param_distribution=param_grid,
                                   n_iter=n_iter,
                                   cv=cv,
                                   n_jobs=n_jobs,
                                   refit=refit)
        rs_cv.fit(train_features, train_response)
        return (rs_cv.best_params_)

6. การประเมินโมเดลการเรียนรู้ของเครื่องของเรา

ฉันใช้เทคนิคการสุ่มตัวอย่าง K-Fold Cross Validation ใหม่เพื่อประเมิน RMSE ที่โมเดลของฉันจะได้รับจากชุดข้อมูลทดสอบ นี่คือค่าเฉลี่ยของ RMSE ที่เราได้รับเมื่อฝึกโมเดล K ครั้ง และในแต่ละครั้ง ข้อมูลการพับ Kth จะถูกนำมาใช้เป็นพร็อกซีสำหรับข้อมูลทดสอบ

โมเดลนี้ได้รับการฝึกฝนโดยใช้ การตรวจสอบความถูกต้องแบบข้าม K-fold โดยใช้ K=5 ด้วยเหตุผลด้านความเรียบง่าย คุณลักษณะการฝึกอบรมถูกใช้เป็นชุดของตัวแปรสำรวจ (X_train) เพื่อเรียนรู้และปรับโมเดลให้เหมาะสม พร้อมด้วยเงินเดือนเป็นตัวแปรตาม (Y_train) มีการฝึกโมเดลหลายแบบในลักษณะนี้ จากนั้น CV RMSE ของพวกเขาก็ถูกประเมินเพื่อเปรียบเทียบทุกรุ่น

CV RMSE นี้สำหรับแต่ละรุ่นใช้เพื่ออัปเดตโมเดลที่ดีที่สุดโดยการเปรียบเทียบโมเดลที่ดีที่สุดในปัจจุบันกับ RMSE รุ่นใหม่ และเลือกอันที่มี CV RMSE ที่เล็กที่สุด จากนั้น โมเดลที่ดีที่สุดนี้ ซึ่งก็คือ GBM ซึ่งติดตั้งเข้ากับคุณสมบัติการฝึกอบรม ถูกนำมาใช้ในการทำนายเงินเดือน (Y_test) โดยใช้คุณสมบัติข้อมูลการทดสอบ (X_test)

GBM ท้ายที่สุดจะมี RMSE โดยประมาณที่น้อยที่สุด ดังนั้นนี่คือแบบจำลองที่เลือกซึ่งฉันใช้เพื่อให้เหมาะกับแบบจำลองและคาดการณ์เงินเดือนของข้อมูลการทดสอบ

ปัญหาระหว่างการฝึกอบรม

1: JobID ไม่สามารถใช้เป็นคุณลักษณะได้เนื่องจากไม่ซ้ำกันต่อการสังเกต มีหลายวิธีในการแก้ปัญหานี้ แต่วิธีที่ง่ายที่สุดในการแก้ปัญหาคือการแปลงรหัสงานเป็นดัชนีสำหรับแต่ละเฟรมข้อมูล เพื่อให้สามารถบันทึกพร้อมกับเงินเดือนที่ต้องการในไฟล์สุดท้ายได้

2: เวลาที่โมเดลใช้ในการฝึก ในกรณีนี้ PySpark อาจเป็นตัวเลือกที่ดีกว่าสำหรับการฝึกโมเดลด้วยการสังเกตนับล้านครั้ง และหากมีฟีเจอร์มากกว่านี้ กระบวนการก็จะใช้เวลานานยิ่งขึ้น

3: สมมติฐานที่ฉันต้องทำ:

  • ฉันคิดว่าเงินเดือนสำหรับงานที่ต้องการประสบการณ์สูงต้องไม่เท่ากับ 0 ซึ่งดูไม่สมเหตุสมผลสำหรับฉัน ดังนั้นฉันจึงต้องลบมันออก
  • ฉันยังสันนิษฐานว่าเงินเดือนจำนวนมากนั้นสมเหตุสมผลและต้องอยู่ในข้อมูลเนื่องจากเงินเดือนเหล่านั้นสอดคล้องกับตำแหน่งผู้บริหาร
  • K ใน K-fold CV ซึ่งฉันปล่อยให้มันเป็นค่าเริ่มต้น K= 5 แต่ตามหลักการแล้ว ฉันอยากจะใช้วิธี Elbow สำหรับสิ่งนี้
  • ฉันตั้งสมมติฐานที่เกี่ยวข้องกับจำนวนครั้งในการฝึกฝนโมเดลต่างๆ ซึ่งฉันเลือกไว้มากเพียงพอ (60) เพื่อให้แน่ใจว่าความแม่นยำของโมเดลนั้นดีเพียงพอ
  • ฉันคิดว่า K-fold CV RMSE เป็นค่าประมาณที่เหมาะสมสำหรับการทดสอบ RMSE เนื่องจากเป็นระหว่างการฝึก K-th แต่ละครั้ง K-1 fold จะถูกใช้เป็นชุดการฝึก และ Kth fold ถูกใช้เป็นพร็อกซีสำหรับชุดการทดสอบ รับ RMSE จากนั้นค่าเฉลี่ยของ K RMSE เหล่านี้จะเป็นค่าประมาณที่ดีสำหรับการทดสอบ RMSE

นอกจาก RMSE แล้ว ฉันยังประเมิน MSE และ MAE ซึ่งเป็นตัวชี้วัดทางเลือกแทน RMSE อีกด้วย การวัดทั้งหมดเหล่านี้เป็นหน่วยเมตริกที่สามารถใช้เพื่อประเมินประสิทธิภาพของแบบจำลองการถดถอย เช่นในกรณีของเรา

หากแบบจำลองที่เลือกคือ Linear Regression เราก็สามารถใช้ R-squared หรือ Adjusted R-squared เพื่อประเมินความแม่นยำของแบบจำลองและจำนวนแบบจำลองที่อธิบายเงินเดือน จากนั้นเรายังสามารถดูข้อผิดพลาดมาตรฐานและความกว้างของช่วงความเชื่อมั่นของคุณลักษณะต่างๆ เพื่อสรุปผลได้

7. ความสำคัญของคุณลักษณะ

“ประเภทงาน” ดูเหมือนจะมีผลกระทบต่อเงินเดือนมากที่สุด คุณสมบัติอื่น ๆ ที่มีผลกระทบอย่างมากต่อเงินเดือนคือประสบการณ์และระยะทางจาก Metropolis รหัสบริษัทและปริญญาดูเหมือนจะเป็นคุณลักษณะที่สำคัญน้อยที่สุดซึ่งไม่ได้ช่วยเรามากนักในการอธิบายการเปลี่ยนแปลงของเงินเดือน

ฉันได้ระบุทั้งคุณลักษณะที่มีนัยสำคัญที่สุดและสำคัญน้อยที่สุดโดยการวางแผนกราฟความสำคัญของคุณลักษณะ โดยที่ความสำคัญของคุณลักษณะจะถูกคำนวณตามค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานของการสะสมของ RSS (ผลรวมที่เหลือของ Squared) ที่ลดลงภายในต้นไม้แต่ละต้น คุณลักษณะที่สำคัญที่สุดอยู่ที่ด้านบน ซึ่งสอดคล้องกับแถบที่ใหญ่ที่สุด ในขณะที่คุณลักษณะที่มีนัยสำคัญน้อยที่สุดจะอยู่ที่ด้านล่างของพล็อตนี้ซึ่งมีแถบที่สั้นที่สุด

พื้นที่เก็บข้อมูล GitHub พร้อมชุดข้อมูลและโค้ด Python ที่นี่

หากคุณชอบบทความนี้ นี่คือบทความอื่นๆ ที่คุณอาจชอบ:











ขอบคุณที่อ่าน

ฉันขอแนะนำให้คุณ เข้าร่วม Mediumเพื่อให้เข้าถึงบทความทั้งหมดของฉันเกี่ยวกับ Data Science, Machine Learning, AI และหัวข้ออื่น ๆ ได้อย่างสมบูรณ์

ติดตามฉันใน "สื่อกลาง" เพื่ออ่านบทความเพิ่มเติมเกี่ยวกับหัวข้อต่างๆ ของวิทยาศาสตร์ข้อมูลและการวิเคราะห์ข้อมูล หากต้องการการประยุกต์ใช้แนวคิดการเรียนรู้ของเครื่อง คณิตศาสตร์ และสถิติเชิงปฏิบัติเพิ่มเติม โปรดดูบัญชี Githubของฉัน
ฉันยินดีรับข้อเสนอแนะและสามารถติดต่อได้ที่ LinkedIn.

ขอให้มีความสุขกับการเรียนรู้!