กรณีศึกษาแบบ End-too-End เพื่อคาดการณ์เงินเดือนของการลงประกาศรับสมัครงานสำหรับเครื่องมือค้นหางานโดยใช้การเรียนรู้ของเครื่องด้วยการใช้ Python
“การศึกษาไม่ใช่การทำให้ฝูงสัตว์ผอมบาง การศึกษาคือการช่วยให้นักเรียนทุกคนประสบความสำเร็จ”
แอนดรูว์ อึ้ง
ในกรณีศึกษาวิทยาศาสตร์ข้อมูลแบบครบวงจรนี้ เราจะใช้โมเดลการเรียนรู้ของเครื่องที่หลากหลายเพื่อประเมินเงินเดือนสำหรับการลงประกาศรับสมัครงานสำหรับเครื่องมือค้นหางาน แน่นอน เราจะฝึกอบรมและประเมินประสิทธิภาพของโมเดล ML หลายรายการโดยใช้ K-Fold Cross Validation และ RMSE/MSE/MAE โดยประมาณ แบบจำลองที่มีประสิทธิภาพดีที่สุดจะถูกเลือกในตอนท้าย และจะบันทึกเงินเดือนที่คาดการณ์ไว้สำหรับการลงประกาศงานการทดสอบด้วย
พื้นที่เก็บข้อมูล GitHub พร้อมข้อมูลและโค้ด Python ที่นี่
เนื้อหาของบล็อก
<แข็งแกร่ง>1. การกำหนดเป้าหมายทางธุรกิจและวิทยาศาสตร์ข้อมูล
<แข็งแกร่ง>2. การประมวลผลข้อมูลล่วงหน้า
<แข็งแกร่ง>4. วิธีการ (การเปรียบเทียบและคำอธิบายโมเดล ML)
<แข็งแกร่ง>5. กระบวนการฝึกอบรมแบบทีละขั้นตอนของโมเดล Machine Learning
<แข็งแกร่ง>6. การประเมินโมเดลการเรียนรู้ของเครื่องของเรา
<แข็งแกร่ง>7. ความสำคัญของคุณลักษณะ
1. การกำหนดเป้าหมายทางธุรกิจและวิทยาศาสตร์ข้อมูล
หากคุณเคยลองใช้เครื่องมือค้นหางานสมัยใหม่ เช่น “Glassdoor”, “Indeed” สำหรับ “LinkedIn ” คุณอาจสังเกตเห็นว่าประกาศรับสมัครงานบางรายการมีเงินเดือนระบุไว้ ในขณะที่ส่วนใหญ่ไม่ได้ให้ข้อมูลนั้น ข้อมูลเงินเดือนต่อการลงประกาศรับสมัครงานมีประโยชน์มากสำหรับผู้สมัคร เนื่องจากช่วยประหยัดเวลาล่วงหน้าได้มาก วิธีนี้จะหลีกเลี่ยงไม่ให้ผู้สมัครต้องผ่านกระบวนการต่างๆ และพบว่าในตอนท้ายพวกเขาจะไม่ได้รับค่าตอบแทนตามนั้นหรือตามที่คาดไว้
นี่เป็นปัญหาสำคัญสำหรับเครื่องมือค้นหางานใดๆ เนื่องจากการลงประกาศรับสมัครงานส่วนใหญ่ไม่รวมเงินเดือน และการเพิ่มฟีเจอร์เหล่านี้อาจเพิ่มความพึงพอใจและการมีส่วนร่วมของผู้ใช้เครื่องมือค้นหาได้
สิ่งแรกสุดที่เราต้องทำในกรณีศึกษาใดๆ ก็คือการกำหนดและกำหนดเป้าหมายทางธุรกิจและเป้าหมายทางเทคนิค (วิทยาศาสตร์ข้อมูล) ที่คุณตั้งเป้าที่จะบรรลุโดยการทำกรณีศึกษาหรือโครงการให้เสร็จสิ้น
เป้าหมายทางธุรกิจ
ในกรณีศึกษานี้ เรามุ่งมั่นที่จะสร้างคุณลักษณะการประมาณการเงินเดือนสำหรับเครื่องมือค้นหางาน เงินเดือนโดยประมาณสำหรับการลงประกาศรับสมัครงานใหม่สามารถปรับปรุงประสบการณ์ของผู้หางานได้โดยการให้ข้อมูลเงินเดือนแก่พวกเขา
เป้าหมายด้านเทคนิค (วิทยาศาสตร์ข้อมูล)
เป้าหมายทางเทคนิคของกรณีศึกษานี้คือการใช้แมชชีนเลิร์นนิงเพื่อคาดการณ์เงินเดือนของโอกาสในการทำงานตามลักษณะงาน
เราจะตอบคำถามต่อไปนี้:
- คุณใช้ภาษาและไลบรารีซอฟต์แวร์ใดในการแก้ปัญหา เหตุใดคุณจึงเลือกภาษา/ห้องสมุดเหล่านี้
- เราทำตามขั้นตอนอะไรบ้างในการเตรียมข้อมูลสำหรับโครงการ จำเป็นต้องทำความสะอาดหรือไม่?
- มีการใช้วิธีแมชชีนเลิร์นนิงอย่างไร
- ทำไมเราถึงเลือกวิธีนี้?
- เราพิจารณาวิธีการอื่นใดอีกบ้าง?
- อธิบายวิธีการทำงานของอัลกอริทึมการเรียนรู้ของเครื่อง
- จำเป็นต้องมีการเข้ารหัสหรือการเปลี่ยนแปลงคุณสมบัติใดๆ หรือไม่ และอันใด
- คุณสมบัติใดมีผลกระทบต่อเงินเดือนมากที่สุด? เราระบุสิ่งเหล่านี้ให้มีความสำคัญมากที่สุดได้อย่างไร คุณสมบัติใดมีผลกระทบต่อเงินเดือนน้อยที่สุด? เราระบุสิ่งเหล่านี้ได้อย่างไร?
- เราฝึกโมเดล Machine Learning อย่างไร ในระหว่างการฝึกอบรม มีปัญหาอะไรบ้างที่น่ากังวล?
- คุณสร้างค่าประมาณสำหรับเมตริกประสิทธิภาพ RMSE ได้อย่างไร
- ตัวชี้วัดใดนอกเหนือจาก 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.
ขอให้มีความสุขกับการเรียนรู้!