前兩篇博客分別對拉勾中關於 python 數據分析有關的信息進行獲取(https://www.cnblogs.com/lyuzt/p/10636501.html)和對獲取的數據進行可視化分析(https://www.cnblogs.com/lyuzt/p/10643941.html),這次我們就用 sklearn 對不同學歷和工作經驗的 python 數據分析師做一個簡單的工資預測。由於在前面兩篇博客中已經了解了數據集的大概,就直接進入正題。
一、對薪資進行轉換
在這之前先導入模塊並讀入文件,不僅有訓練數據文件,還有一組自擬的測試數據文件。
import pandas as pd import numpy as np import matplotlib.pyplot as plt train_file = "analyst.csv" test_file = "test.csv" # 讀取文件獲得數據 train_data = pd.read_csv(train_file, encoding="gbk") train_data = train_data.drop('ID', axis=1) test_data = pd.read_csv(test_file, encoding="gbk") train_data.shape, test_data.shape
為了更好地進行分析,我們要對薪資做一個預處理。由於其分布比較散亂,很多值的個數只有1。為了不造成過大的誤差,根據其分布情況,可以將它分成【5k 以下、5k-10k、10k-20k、20k-30k、30k-40k、40k 以上】,為了更加方便我們分析,取每個薪資范圍的中位數,並划分到我們指定的范圍內。
salarys = train_data['薪資'].unique() # 獲取到薪資的不同值 for salary in salarys: # 根據'-'進行分割並去掉'k',分別將兩端的值轉換成整數 min_sa = int(salary.split('-')[0][:-1]) max_sa = int(salary.split('-')[1][:-1]) # 求中位數 median_sa = (min_sa + max_sa) / 2 # 判斷其值並划分到指定范圍 if median_sa < 5: train_data.replace(salary, '5k以下', inplace=True) elif median_sa >= 5 and median_sa < 10: train_data.replace(salary, '5k-10k', inplace=True) elif median_sa >= 10 and median_sa < 20: train_data.replace(salary, '10k-20k', inplace=True) elif median_sa >= 20 and median_sa < 30: train_data.replace(salary, '20k-30k', inplace=True) elif median_sa >= 30 and median_sa < 40: train_data.replace(salary, '30k-40k', inplace=True) else: train_data.replace(salary, '40k以上', inplace=True)
處理完成后,我們可以將“薪資”單獨提取出來當作訓練集的 label。
y_train = train_data.pop('薪資').values
二、對變量進行轉換
把category的變量轉變成numerical表達式
由於變量都不是numerical變量,在訓練的時候計算機沒辦法識別,因此要對它們進行轉換。 當我們用numerical來表達categorical的時候,要注意,數字本身有大小的含義,所以亂用數字會給之后的模型學習帶來麻煩。於是我們可以用One-Hot的方法來表達category。
pandas自帶的get_dummies方法,可以一鍵做到One-Hot。 這里按我的理解解釋一下One-Hot:比如說data['學歷要求']有'大專', '本科', '碩士', '不限'。但data['學歷要求']=='本科',則他可以用字典表示成這樣{'大專': 0, '本科':1, '碩士':0, '不限':0},用向量表示為[0, 1, 0, 0] 。
在此之前,將測試集和訓練集組合起來一起處理,稍微方便一點。
data = pd.concat((train_data, test_data), axis=0) dummied_data = pd.get_dummies(data) dummied_data.head()
為了更好地理解 One-Hot ,把處理后的結果展示出來,得到的結果是這樣的:
當然,也可以用別的方法,比如用數字代替不同的值,這也是可以的。
上次可視化分析的時候就已經知道數據集中不存在缺失值了,為了走一下流程並確保正確性,再次看一下是否有缺失值。
dummied_data.isnull().sum().sort_values(ascending=False).head(10)
OK,很好,沒有缺失值。這些值比較簡單,不需要做那么多工作,但還是要先把訓練集和測試集分開。
X_train = dummied_data[:train_data.shape[0]].values
X_test = dummied_data[-test_data.shape[0]:].values
三、選擇參數
1、DecisionTree(決策樹)
from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import cross_val_score features_scores = [] max_features = [.1, .2, .3, .4, .5, .6, .7, .8, .9] for max_feature in max_features: clf = DecisionTreeClassifier(max_features=max_feature) features_score = cross_val_score(clf, X_train, y_train, cv=5) features_scores.append(np.mean(features_score)) plt.plot(max_features, features_scores)
這個過程主要是通過交叉驗證獲得使模型更好時的參數,交叉驗證大概可以理解為,把訓練集分成幾部分,然后分別把他們設置為訓練集和測試集,重復循環訓練得到的結果取平均值。Emmm... 感覺這樣講還是有點籠統,還是上網查來得詳細吧哈哈。
然后我們得到的參數和值得關系如圖所示:
可見當 max_features = 0.2 時達到最大,大概有0.5418。
2、ensemble(集成算法)
集成學習簡單理解就是指采用多個分類器對數據集進行預測,從而提高整體分類器的泛化能力。這里將采用sklearn 的 AdaBoostClassifier(adaptive boosting) 通過改變訓練樣本的權值,學習多個分類器,並將這些分類器進行線性組合,提高泛化性能。
from sklearn.ensemble import AdaBoostClassifier n_scores = [] estimator_nums = [5, 10, 15, 20, 25, 30, 35, 40] for estimator_num in estimator_nums: clf = AdaBoostClassifier(n_estimators=estimator_num, base_estimator=dtc) n_score = cross_val_score(clf, X_train, y_train, cv=5) n_scores.append(np.mean(n_score)) plt.plot(estimator_nums, n_scores)
當 estimators=20 的時候,score最高,大概有0.544,雖然跟單個決策樹的 score 的值相差不大,但總體還是有所提升。
四、建立模型
參數選擇完畢,就可以建立模型了。
dtc = DecisionTreeClassifier(max_features=0.2) abc = AdaBoostClassifier(n_estimators=20)
# 訓練
abc.fit(X_train, y_train)
dtc.fit(X_train, y_train)
# 預測
y_dtc = dtc.predict(X_test)
y_abc = abc.predict(X_test)
test_data['薪資(單個決策樹)'] = y_dtc
test_data['薪資(boosting)'] = y_abc
至於結果,總不可能預測得很完美,而且不同模型的結果也會有所不同,更何況它預測出來的結果是否符合常理還有待商榷,所以就把它當作一個小項目就好了,具體代碼在這里:https://github.com/MaxLyu/Lagou_Analyze