5分鐘教你玩轉 sklearn 機器學習(上)

騰訊雲加社群發表於2017-10-09

假期結束,你的狀態有沒有迴歸?那麼,放空腦袋後,先來學習學習,歡迎大家繼續關注騰訊雲技術社群

作者:趙成龍

這是一篇很難寫的文章,因為我希望這篇文章能對大家有所幫助。我不會給大家介紹機器學習,資料探勘的行業背景,也不會具體介紹邏輯迴歸,SVM,GBDT,神經網路等學習演算法的理論依據和數學推導,本文更多的是在流程化上幫助大家快速的入門機器學習和資料建模。

本文主要分為四個部分(限於時間關係會分為上下兩篇):

上篇:

  1. 準備篇,主要涉及環境搭建以及pandas基本知識。
  2. 應用篇,我會以kaggle上的Titanic為例,從資料來源獲取,資料清洗,特徵處理,模型選擇,模型輸出與運用。

下篇:

  1. 優化篇,介紹了幾種優化的方法。
  2. 思考篇,提出幾個困擾我的問題,希望能得到大家的幫助吧。

一 準備篇

1環境搭建

整個sklearn的實驗環境是:python 2.7 + pycharm + Anaconda。

2 pandas基礎

這裡只能大家介紹下面會用到的pandas知識,有興趣的可以去具體的學習。給大家推薦一本參考書:《Python for Data Analysis》。有基礎的可以直接跳到應用篇。

pandas主要會用到Series 和DataFrame兩種資料結構。Series像是一維的陣列,而DataFrame更像是一種二維的表結構。

Series的構造方法:

label=[1,0,1,0,1]
data = pd.Series(data=label,index=['a','b','c','d','e'],dtype=int,name="label")
print data
複製程式碼

Series取資料,通過index取數

data['a']
data[['a','b']]
複製程式碼

DataFrame的構造

(1)以字典的形式構造

frame = pd.DataFrame({'name':['Time','Jack','Lily'],'Age':[20,30,12],"weight":[56.7,64.0,50.0]})
複製程式碼

(2)由DataFrame 構建DataFrame

frame1 = pd.DataFrame(frame,columns=["name","Age"])
複製程式碼

從frame中讀取了兩列構成新的DataFrame。

DataFrame的操作

1 增加列

frame1["friends_num"]=[10,12,14]
複製程式碼

2 刪除列

frame2 = frame1.drop(["name","Age"],axis=1)
複製程式碼

3 查詢資料行

frame1[frame1["friends_num"]>10]
複製程式碼

結果如下:

DataFrame的統計方法

1 apply 配合lambda 處理列,如將frame1的Age列進行分段。

 frame1["Age_group"] = frame1["Age"].apply(lambda x: 0 if x < 20 else 1)
複製程式碼

2 describe輸出統計資訊,非常強大

frame1.describe()
複製程式碼

給出了8個統計量,對我們的資料處理特別有用。有個問題,直接使用describe方法只能統計數值類的列,對於字元類的變數沒有統計。加個引數就行。

frame1.describe(include=['O'])
複製程式碼

3 缺失值處理
pandas 對缺失值一般填充NAN。

#以0填充缺失值
frame1.fillna(0)
#丟掉任何包含NAN的行 
frame1.dropna()
#刪除全為nan的行
frame1.dropna(how="all")
複製程式碼

二 應用篇

1 資料讀取

本例以Titanic作為資料來源。大家可以在附件獲取到資料。

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'])
複製程式碼

資料的初始統計資訊:

2 資料清洗

1 缺失值處理。
Age和Embarked列存在少量缺失值,分別處理。

#用眾數填充缺失值
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 特徵處理

特徵處理是基於具體的資料的,所以在特徵處理之前要對資料做充分的理解。特徵處理沒有固定方法之說,主要靠個人的經驗與觀察,通過不斷的嘗試和變換,以期望挖掘出較好的特徵變數。所以說,特徵處理是模型建立過程中最耗時和耗神的工作。

1)單變數特徵提取。

#根據name的長度,抽象出name_len特徵 
data_set["name_len"] = data_set["Name"].apply(len)
複製程式碼

觀察name列

通過觀察Name列資料,可以發現名字中帶有性別和婚否的稱謂資訊。提取這些資訊(可能是有用的特徵)。

data_set["name_class"] = data_set["Name"].apply(lambda x : x.split(",")[1]).apply(lambda x :x.split()[0])
複製程式碼

2)多變數的組合
sibsp 代表兄弟姐妹和配偶的數量
parch 代表父母和子女的數量
因此可以將sibsp和parch結合獲得家庭成員的數量

data_set["family_num"] = data_set["Parch"] + data_set["SibSp"] +1
複製程式碼

3)名義變數轉數值變數

#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)資料分段

根據統計資訊和經驗分段

#[7.91,14.45,31.0]根據Fare的統計資訊進行分段
data_set["Fare"] = data_set["Fare"].apply(lambda x:cutFeature([7.91,14.45,31.0],x))
#[18,48,64]按照經驗分段
data_set["Age"] = data_set["Age"].apply(lambda x:cutFeature([18,48,64],x))
複製程式碼

簡單的資料處理後,我們得到了如下12維資料:

4 模型選擇與測試

初步選取了5種模型進行試驗

RandomForestClassifier

ExtraTreesClassifier

AdaBoostClassifier

GradientBoostingClassifier

SVC

模型引數:

#隨機森林
    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()
複製程式碼

選擇結果如下:

從上圖可以看出,randomForest的一般表現要優於其他演算法。初步選擇randomforest演算法。
模型的在訓練集上的表現:

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%。由於時間關係,優化篇和思考篇將放在下篇文章與大家分享,敬請期待。

如有任何錯誤或疑問,歡迎大家留言。期待與大家共同成長,共同進步!

溫馨提示:文章相關的資料請閱讀原文獲取

相關閱讀

機器學習:從入門到第一個模型

機器學習概念總結筆記(四)

當強化學習遇見泛函分析

此文已由作者授權騰訊雲技術社群釋出,轉載請註明文章出處
原文連結:https://cloud.tencent.com/community/article/229506


相關文章