5分鐘教你玩轉(zhuǎn) sklearn 機器學習(上)
這是一篇很難寫的文章,因為我希望這篇文章能對大家有所幫助。我不會給大家介紹機器學習,數(shù)據(jù)挖掘的行業(yè)背景,也不會具體介紹邏輯回歸,SVM,GBDT,神經(jīng)網(wǎng)絡(luò)等學習算法的理論依據(jù)和數(shù)學推導,本文更多的是在流程化上幫助大家快速的入門機器學習和數(shù)據(jù)建模。
本文主要分為四個部分(限于時間關(guān)系會分為上下兩篇):
上篇:
- 準備篇,主要涉及環(huán)境搭建以及pandas基本知識。
- 應(yīng)用篇,我會以kaggle上的Titanic為例,從數(shù)據(jù)源獲取,數(shù)據(jù)清洗,特征處理,模型選擇,模型輸出與運用。
下篇:
- 優(yōu)化篇,介紹了幾種優(yōu)化的方法。
- 思考篇,提出幾個困擾我的問題,希望能得到大家的幫助吧。
一 準備篇
1環(huán)境搭建
整個sklearn的實驗環(huán)境是:python 2.7 + pycharm + Anaconda。
2 pandas基礎(chǔ)
這里只能大家介紹下面會用到的pandas知識,有興趣的可以去具體的學習。給大家推薦一本參考書:《Python for Data Analysis》。有基礎(chǔ)的可以直接跳到應(yīng)用篇。
pandas主要會用到Series 和DataFrame兩種數(shù)據(jù)結(jié)構(gòu)。Series像是一維的數(shù)組,而DataFrame更像是一種二維的表結(jié)構(gòu)。
Series的構(gòu)造方法:
- label=[1,0,1,0,1]
- data = pd.Series(data=label,index=['a','b','c','d','e'],dtype=int,name="label")
- print data
Series取數(shù)據(jù),通過index取數(shù)
- data['a']
- data[['a','b']]
DataFrame的構(gòu)造
(1)以字典的形式構(gòu)造
- frame = pd.DataFrame({'name':['Time','Jack','Lily'],'Age':[20,30,12],"weight":[56.7,64.0,50.0]})
(2)由DataFrame 構(gòu)建DataFrame
- frame1 = pd.DataFrame(frame,columns=["name","Age"])
從frame中讀取了兩列構(gòu)成新的DataFrame。
DataFrame的操作
1 增加列
- frame1["friends_num"]=[10,12,14]
2 刪除列
- frame2 = frame1.drop(["name","Age"],axis=1)
3 查找數(shù)據(jù)行
- frame1[frame1["friends_num"]>10]
結(jié)果如下:
DataFrame的統(tǒng)計方法
1 apply 配合lambda 處理列,如將frame1的Age列進行分段。
- frame1["Age_group"] = frame1["Age"].apply(lambda x: 0 if x < 20 else 1)
2 describe輸出統(tǒng)計信息,非常強大
- frame1.describe()
給出了8個統(tǒng)計量,對我們的數(shù)據(jù)處理特別有用。有個問題,直接使用describe方法只能統(tǒng)計數(shù)值類的列,對于字符類的變量沒有統(tǒng)計。加個參數(shù)就行。
- frame1.describe(include=['O'])
3 缺失值處理
- #以0填充缺失值
- frame1.fillna(0)
- #丟掉任何包含NAN的行
- frame1.dropna()
- #刪除全為nan的行
- frame1.dropna(how="all")
二 應(yīng)用篇
1 數(shù)據(jù)讀取
本例以Titanic作為數(shù)據(jù)源。大家可以在附件獲取到數(shù)據(jù)。
- data = pd.DataFrame(pd.read_csv(train_path))
- data_test = pd.DataFrame(pd.read_csv(test_path))
- data_test = data_test[["Pclass","Name","Sex","Age","SibSp","Parch","Ticket","Fare","Cabin","Embarked"]]
- x = data[["Pclass","Name","Sex","Age","SibSp","Parch","Ticket","Fare","Cabin","Embarked"]]
- y = data[["Survived"]]
- print x.describe()
- print x.describe(include=['O'])
- print data_test.describe()
- print data_test.describe(include=['O'])
數(shù)據(jù)的初始統(tǒng)計信息:
2 數(shù)據(jù)清洗
1 缺失值處理。
Age和Embarked列存在少量缺失值,分別處理。
- #用眾數(shù)填充缺失值
- data_set["Embarked"]=data_set["Embarked"].fillna('S')
- #用均值填充Age缺失值
- data_set["Age"]=data_set["Age"].fillna(data_set["Age"].mean())
2 刪除缺失率較大的列(初步處理時)
Cabin列的缺失率達到了75%,刪除改列。
- data_set = data_set.drop([ "Cabin"], axis=1)
3 特征處理
特征處理是基于具體的數(shù)據(jù)的,所以在特征處理之前要對數(shù)據(jù)做充分的理解。特征處理沒有固定方法之說,主要靠個人的經(jīng)驗與觀察,通過不斷的嘗試和變換,以期望挖掘出較好的特征變量。所以說,特征處理是模型建立過程中最耗時和耗神的工作。
1)單變量特征提取。
- #根據(jù)name的長度,抽象出name_len特征
- data_set["name_len"] = data_set["Name"].apply(len)
觀察name列
通過觀察Name列數(shù)據(jù),可以發(fā)現(xiàn)名字中帶有性別和婚否的稱謂信息。提取這些信息(可能是有用的特征)。
- data_set["name_class"] = data_set["Name"].apply(lambda x : x.split(",")[1]).apply(lambda x :x.split()[0])
2)多變量的組合
sibsp 代表兄弟姐妹和配偶的數(shù)量
parch 代表父母和子女的數(shù)量
因此可以將sibsp和parch結(jié)合獲得家庭成員的數(shù)量
- data_set["family_num"] = data_set["Parch"] + data_set["SibSp"] +1
3)名義變量轉(zhuǎn)數(shù)值變量
- #Embarked
- data_set["Embarked"]=data_set["Embarked"].map({'S':1,'C':2,'Q':3}).astype(int)
- #Sex
- data_set["Sex"] = data_set["Sex"].apply(lambda x : 0 if x=='male' else 1)
4)數(shù)據(jù)分段
根據(jù)統(tǒng)計信息和經(jīng)驗分段
- #[7.91,14.45,31.0]根據(jù)Fare的統(tǒng)計信息進行分段
- data_set["Fare"] = data_set["Fare"].apply(lambda x:cutFeature([7.91,14.45,31.0],x))
- #[18,48,64]按照經(jīng)驗分段
- data_set["Age"] = data_set["Age"].apply(lambda x:cutFeature([18,48,64],x))
簡單的數(shù)據(jù)處理后,我們得到了如下12維數(shù)據(jù):
4 模型選擇與測試
初步選取了5種模型進行試驗
RandomForestClassifier
ExtraTreesClassifier
AdaBoostClassifier
GradientBoostingClassifier
SVC
模型參數(shù):
- #隨機森林
- rf_params = {
- 'n_jobs': -1,
- 'n_estimators': 500,
- 'warm_start': True,
- # 'max_features': 0.2,
- 'max_depth': 6,
- 'min_samples_leaf': 2,
- 'max_features': 'sqrt',
- 'verbose': 0
- }
- # Extra Trees 隨機森林
- et_params = {
- 'n_jobs': -1,
- 'n_estimators': 500,
- # 'max_features': 0.5,
- 'max_depth': 8,
- 'min_samples_leaf': 2,
- 'verbose': 0
- }
- # AdaBoost
- ada_params = {
- 'n_estimators': 500,
- 'learning_rate': 0.75
- }
- # GBDT
- gb_params = {
- 'n_estimators': 500,
- # 'max_features': 0.2,
- 'max_depth': 5,
- 'min_samples_leaf': 2,
- 'verbose': 0
- }
- # SVC
- svc_params = {
- 'kernel': 'linear',
- 'C': 0.025
- }
模型選擇代碼:
- classifiers = [
- ("rf_model", RandomForestClassifier(**rf_params)),
- ("et_model", ExtraTreesClassifier(**et_params)),
- ("ada_model", AdaBoostClassifier(**ada_params)),
- ("gb_model", GradientBoostingClassifier(**gb_params)),
- ("svc_model", SVC(**svc_params)),
- ]
- heldout = [0.95, 0.90, 0.75, 0.50, 0.01]
- rounds = 20
- xx = 1. - np.array(heldout)
- for name, clf in classifiers:
- print("training %s" % name)
- rng = np.random.RandomState(42)
- yy = []
- for i in heldout:
- yy_ = []
- for r in range(rounds):
- X_train_turn, X_test_turn, y_train_turn, y_test_turn = \
- train_test_split(x_train, labels_train, test_size=i, random_state=rng)
- clf.fit(X_train_turn, y_train_turn)
- y_pred = clf.predict(X_test_turn)
- yy_.append(1 - np.mean(y_pred == y_test_turn))
- yy.append(np.mean(yy_))
- plt.plot(xx, yy, label=name)
- plt.legend(loc="upper right")
- plt.xlabel("Proportion train")
- plt.ylabel("Test Error Rate")
- plt.show()
選擇結(jié)果如下:
從上圖可以看出,randomForest的一般表現(xiàn)要優(yōu)于其他算法。初步選擇randomforest算法。
模型的在訓練集上的表現(xiàn):
- def modelScore(x_train,labels_train,x_test,y_test,model_name,et_params):
- print("--------%s------------")%(model_name)
- model = model_name(**et_params)
- model.fit(x_train, labels_train)
- if "feature_importances_" in dir(model):
- print model.feature_importances_
- print classification_report(
- labels_train,
- model.predict(x_train))
- print classification_report(
- y_test,
- model.predict(x_test))
- return model
- modelScore(x_train, labels_train, x_test, y_test, RandomForestClassifier, rf_params)
訓練集的混淆矩陣如下圖:
測試集的混淆矩陣如下圖:
到此,初步的學習模型就建立起來了,測試集的準確度為83%。由于時間關(guān)系,優(yōu)化篇和思考篇將放在下篇文章與大家分享,敬請期待。
原文鏈接:https://cloud.tencent.com/community/article/229506
作者:趙成龍
【本文是51CTO專欄作者“騰訊云技術(shù)社區(qū)”的原創(chuàng)稿件,轉(zhuǎn)載請通過51CTO聯(lián)系原作者獲取授權(quán)】