Python深度學習簡明實戰教程來了。別猶豫了,趕忙從零開始,搭建你本身的第一個深度學習模型吧!html
想不想了解如何用Python快速搭建深度神經網絡,完成數據分類任務?本文一步步爲你展現這一過程,讓你初步領略深度學習模型的強大和易用。python
做爲一名數據分析師,你來到這家跨國銀行工做已經半年了。git
今天上午,老闆把你叫到辦公室,面色凝重。github
你內心直打鼓,覺得本身捅了什麼簍子。幸虧老闆的話讓你很快打消了顧慮。算法
他發愁,是由於最近歐洲區的客戶流失嚴重,許多客戶都跑到了競爭對手那裏接受服務了。老闆問你該怎麼辦?數組
你脫口而出「作好客戶關係管理啊!」瀏覽器
老闆看了你一眼,緩慢地說「咱們想知道哪些客戶最可能在近期流失」。bash
沒錯,在有魚的地方釣魚,纔是上策。微信
你明白了本身的任務——經過數據鎖定即將流失的客戶。這個工做,確實是你這個數據分析師份內的事兒。網絡
你很慶幸,這半年作了不少的數據動態採集和整理工做,使得你手頭就有一個比較完備的客戶數據集。
下面你須要作的,就是如何從數據中「沙裏淘金」,找到那些最可能流失的客戶。
但是,該怎麼作呢?
你拿出歐洲區客戶的數據,端詳起來。
客戶主要分佈在法國、德國和西班牙。
你手裏掌握的信息,包括他們的年齡、性別、信用、辦卡信息等。客戶是否已流失的信息在最後一列(Exited)。
怎麼用這些數據來判斷顧客是否會流失呢?
以你的專業素養,很容易就判斷出這是一個分類問題,屬於機器學習中的監督式學習。可是,你以前並無作過實際項目,該如何着手呢?
別發愁,我一步步給你演示如何用Python和深度神經網絡(或者叫「深度學習」)來完成這個分類任務,幫你鎖定那些即將流失的客戶。
工欲善其事,必先利其器。咱們先來安裝和搭建環境。
首先是安裝Python。
請到這個網址下載Anaconda的最新版本。
請選擇左側的Python 3.6版本下載安裝。
其次是新建文件夾,起名爲demo-customer-churn-ann,而且從這個連接下載數據,放到該文件夾下。
(注:樣例數據來自於匿名化處理後的真實數據集,下載自superdatascience官網。)
打開終端(或者命令行工具),進入demo-customer-churn-ann目錄,執行如下命令:
jupyter notebook
複製代碼
瀏覽器中會顯示以下界面:
點擊界面右上方的New按鈕,新建一個Python 3 Notebook,起名爲customer-churn-ann。
準備工做結束,下面咱們開始清理數據。
首先,讀入數據清理最經常使用的pandas和numpy包。
import numpy as np
import pandas as pd
複製代碼
從customer_churn.csv
裏讀入數據:
df = pd.read_csv('customer_churn.csv')
複製代碼
看看讀入效果如何:
df.head()
複製代碼
這裏咱們使用了head()
函數,只顯示前5行。
能夠看到,數據完整無誤讀入。可是並不是全部的列都對咱們預測用戶流失有做用。咱們一一甄別一下:
上述數據列甄別過程,就叫作「特徵工程」(Feature Engineering),這是機器學習裏面最經常使用的數據預處理方法。若是咱們的數據量足夠大,機器學習模型足夠複雜,是能夠跳過這一步的。可是因爲咱們的數據只有10000條,還須要手動篩選特徵。
選定了特徵以後,咱們來生成特徵矩陣X,把剛纔咱們決定保留的特徵都寫進來。
X = df.loc[:,['CreditScore', 'Geography', 'Gender', 'Age', 'Tenure', 'Balance', 'NumOfProducts', 'HasCrCard', 'IsActiveMember', 'EstimatedSalary']]
複製代碼
看看特徵矩陣的前幾行:
X.head()
複製代碼
顯示結果以下:
特徵矩陣構建準確無誤,下面咱們構建目標數據y,也就是用戶是否流失。
y = df.Exited
複製代碼
y.head()
複製代碼
0 1
1 0
2 1
3 0
4 0
Name: Exited, dtype: int64
複製代碼
此時咱們須要的數據基本上齊全了。可是咱們發現其中有幾列數據還不符合咱們的要求。
要作機器學習,只能給機器提供數值,而不能是字符串。但是看看咱們的特徵矩陣:
X.head()
複製代碼
顯然其中的Geography和Gender兩項數據都不符合要求。它們都是分類數據。咱們須要作轉換,把它們變成數值。
在Scikit-learn工具包裏面,專門提供了方便的工具LabelEncoder
,讓咱們能夠方便地將類別信息變成數值。
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
labelencoder1 = LabelEncoder()
X.Geography= labelencoder1.fit_transform(X.Geography)
labelencoder2 = LabelEncoder()
X.Gender = labelencoder2.fit_transform(X.Gender)
複製代碼
咱們須要轉換兩列,因此創建了兩個不一樣的labelencoder。轉換的函數叫作fit_transform
。
通過轉換,此時咱們再來看看特徵矩陣的樣子:
X.head()
複製代碼
顯然,Geography和Gender這兩列都從原先描述類別的字符串,變成了數字。
這樣是否是就完事大吉了呢?
不對,Gender還好說,只有兩種取值方式,要麼是男,要麼是女。咱們能夠把「是男性」定義爲1,那麼女性就取值爲0。兩種取值只是描述類別不一樣,沒有歧義。
而Geography就不一樣了。由於數據集裏面可能的國家地區取值有3種,因此就轉換成了0(法國)、1(德國)、2(西班牙)。問題是,這三者之間真的有序列(大小)關係嗎?
答案天然是否認的。咱們其實仍是打算用數值描述分類而已。可是取值有數量的序列差別,就會給機器帶來歧義。它並不清楚不一樣的取值只是某個國家的代碼,可能會把這種大小關係帶入模型計算,從而產生錯誤的結果。
解決這個問題,咱們就須要引入OneHotEncoder
。它也是Scikit-learn提供的一個類,能夠幫助咱們把類別的取值轉變爲多個變量組合表示。
我們這個數據集裏,能夠把3個國家分別用3個數字組合來表示。例如法國從原先的0,變成(1, 0, 0)
,德國從1變成(0, 1, 0)
,而西班牙從2變成(0, 0, 1)
。
這樣,不再會出現0和1以外的數字來描述類別,從而避免機器產生誤會,錯把類別數字當成大小來計算了。
特徵矩陣裏面,咱們只須要轉換國別這一列。由於它在第1列的位置(從0開始計數),於是categorical_features
只填寫它的位置信息。
onehotencoder = OneHotEncoder(categorical_features = [1])
X = onehotencoder.fit_transform(X).toarray()
複製代碼
這時候,咱們的特徵矩陣數據框就被轉換成了一個數組。注意全部被OneHotEncoder轉換的列會排在最前面,而後纔是那些保持原樣的數據列。
咱們只看轉換後的第一行:
X[0]
複製代碼
array([ 1.00000000e+00, 0.00000000e+00, 0.00000000e+00,
6.19000000e+02, 0.00000000e+00, 4.20000000e+01,
2.00000000e+00, 0.00000000e+00, 1.00000000e+00,
1.00000000e+00, 1.00000000e+00, 1.01348880e+05])
複製代碼
這樣,總算轉換完畢了吧?
沒有。
由於本例中,OneHotEncoder轉換出來的3列數字,其實是不獨立的。給定其中兩列的信息,你本身均可以計算出其中的第3列取值。
比如說,某一行的前兩列數字是(0, 0)
,那麼第三列確定是1。由於這是轉換規則決定的。3列裏只能有1個是1,其他都是0。
若是你作過多元線性迴歸,應該知道這種狀況下,咱們是須要去掉其中一列,才能繼續分析的。否則會落入「虛擬變量陷阱」(dummy variable trap)。
咱們刪掉第0列,避免掉進坑裏。
X = np.delete(X, [0], 1)
複製代碼
再次打印第一行:
X[0]
複製代碼
array([ 0.00000000e+00, 0.00000000e+00, 6.19000000e+02,
0.00000000e+00, 4.20000000e+01, 2.00000000e+00,
0.00000000e+00, 1.00000000e+00, 1.00000000e+00,
1.00000000e+00, 1.01348880e+05])
複製代碼
檢查完畢,如今我們的特徵矩陣處理基本完成。
可是監督式學習,最重要的是有標籤(label)數據。本例中的標籤就是用戶是否流失。咱們目前的標籤數據框,是這個樣子的。
y.head()
複製代碼
0 1
1 0
2 1
3 0
4 0
Name: Exited, dtype: int64
複製代碼
它是一個行向量,咱們須要把它先轉換成爲列向量。你能夠想象成把它「豎過來」。
y = y[:, np.newaxis]
y
複製代碼
array([[1],
[0],
[1],
...,
[1],
[1],
[0]])
複製代碼
這樣在後面訓練的時候,他就能夠和前面的特徵矩陣一一對應來操做計算了。
既然標籤表明了類別,咱們也把它用OneHotEncoder轉換,這樣方便咱們後面作分類學習。
onehotencoder = OneHotEncoder()
y = onehotencoder.fit_transform(y).toarray()
複製代碼
此時的標籤變成兩列數據,一列表明顧客存留,一列表明顧客流失。
y
複製代碼
array([[ 0., 1.],
[ 1., 0.],
[ 0., 1.],
...,
[ 0., 1.],
[ 0., 1.],
[ 1., 0.]])
複製代碼
整體的數據已經齊全了。可是咱們不能把它們都用來訓練。
這就好像老師不該該把考試題目拿來給學生作做業和練習同樣。只有考學生沒見過的題,才能區分學生是掌握了正確的解題方法,仍是死記硬背了做業答案。
咱們拿出20%的數據,放在一邊,等着用來作測試。其他8000條數據用來訓練機器學習模型。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
複製代碼
咱們看看訓練集的長度:
len(X_train)
複製代碼
8000
複製代碼
再看看測試集的長度:
len(X_test)
複製代碼
2000
複製代碼
確認無誤。
是否是能夠開始機器學習了?
能夠,可是下面這一步也很關鍵。咱們須要把數據進行標準化處理。由於原先每一列數字的取值範圍都各不相同,所以有的列方差要遠遠大於其餘列。這樣對機器來講,也是很困擾的。數據的標準化處理,能夠在保持列內數據多樣性的同時,儘可能減小不一樣類別之間差別的影響,可讓機器公平對待所有特徵。
咱們調用Scikit-learn的StandardScaler
類來完成這一過程。
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
複製代碼
注意,咱們只對特徵矩陣作標準化,標籤是不能動的。另外訓練集和測試集須要按照統一的標準變化。因此你看,訓練集上,咱們用了fit_transform
函數,先擬合後轉換;而在測試集上,咱們直接用訓練集擬合的結果,只作轉換。
X_train
複製代碼
array([[-0.5698444 , 1.74309049, 0.16958176, ..., 0.64259497,
-1.03227043, 1.10643166],
[ 1.75486502, -0.57369368, -2.30455945, ..., 0.64259497,
0.9687384 , -0.74866447],
[-0.5698444 , -0.57369368, -1.19119591, ..., 0.64259497,
-1.03227043, 1.48533467],
...,
[-0.5698444 , -0.57369368, 0.9015152 , ..., 0.64259497,
-1.03227043, 1.41231994],
[-0.5698444 , 1.74309049, -0.62420521, ..., 0.64259497,
0.9687384 , 0.84432121],
[ 1.75486502, -0.57369368, -0.28401079, ..., 0.64259497,
-1.03227043, 0.32472465]])
複製代碼
你會發現,許多列的方差比原先小得多。機器學習起來,會更加方便。
數據清理和轉換工做至此完成。
若是讀過個人《貸仍是不貸:如何用Python和機器學習幫你決策?》一文,你應該有一種感受——這個問題和貸款審批決策很像啊!既然在該文中,決策樹很好使,咱們繼續用決策樹不就行了?
好的,咱們先測試一下經典機器學習算法表現如何。
從Scikit-learn中,讀入決策樹工具。而後擬合訓練集數據。
from sklearn import tree
clf = tree.DecisionTreeClassifier()
clf = clf.fit(X_train, y_train)
複製代碼
而後,利用咱們創建的決策樹模型作出預測。
y_pred = clf.predict(X_test)
複製代碼
打印預測結果:
y_pred
複製代碼
array([[ 1., 0.],
[ 0., 1.],
[ 1., 0.],
...,
[ 1., 0.],
[ 1., 0.],
[ 0., 1.]])
複製代碼
這樣看不出來什麼。讓咱們調用Scikit-learn的classification_report
模塊,生成分析報告。
from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))
複製代碼
precision recall f1-score support
複製代碼
0 0.89 0.86 0.87 1595
1 0.51 0.58 0.54 405
複製代碼
avg / total 0.81 0.80 0.81 2000
複製代碼
經檢測,決策樹在我們的數據集上,表現得仍是不錯的。整體的準確率爲0.81,召回率爲0.80,f1分數爲0.81,已經很高了。對10個客戶作流失可能性判斷,它有8次都能判斷正確。
可是,這樣是否足夠?
咱們或許能夠調整決策樹的參數作優化,嘗試改進預測結果。
或者咱們能夠採用深度學習。
深度學習的使用場景,每每是由於原有的模型經典機器學習模型過於簡單,沒法把握複雜數據特性。
我不許備給你講一堆數學公式,我們動手作個實驗。
請你打開這個網址。
你會看到以下圖所示的深度學習遊樂場:
右側的圖形,裏面是藍色數據,外圈是黃色數據。你的任務就是要用模型分類兩種不一樣數據。
你說那還不容易?我一眼就看出來了。
你看出來沒有用。經過你的設置,讓機器也能正確區分,纔算數。
圖中你看到許多加減號。我們就經過操縱它們來玩兒一玩兒模型。
首先,點圖中部上方的"2 HIDDEN LAYERS"左側減號,把中間隱藏層數下降爲1。
而後,點擊"2 neurons"上面的減號,把神經元數量減小爲1。
把頁面上方的Activation函數下拉框打開,選擇「Sigmoid」。
如今的模型,其實就是經典的邏輯迴歸(Logistic Regression)。
點擊左上方的運行按鈕,咱們看看執行效果。
因爲模型過於簡單,因此機器絞盡腦汁,試圖用一條直線切分二維平面上的兩類節點。
損失(loss)居高不下。訓練集和測試集損失都在0.4左右,顯然不符合咱們的分類需求。
下面咱們試試增長層數和神經元數量。此次點擊加號,把隱藏層數加回到2,兩層神經元數量都取2。
再次點擊運行。
通過一段時間,結果穩定了下來,你發現此次電腦用了兩條線,把平面切分紅了3部分。
測試集損失降低到了0.25左右,而訓練集損失更是下降到了0.2如下。
模型複雜了,效果彷佛更好一些。
再接再礪,咱們把第一個隱藏層的神經元數量增長爲4看看。
點擊運行,不一下子有趣的事情就發生了。
機器用一條近乎完美的曲線把平面分紅了內外兩個部分。測試集和訓練集損失都極速降低,訓練集損失甚至接近於0。
這告訴咱們,許多時候模型過於簡單帶來的問題,能夠經過加深隱藏層次、增長神經元的方法提高模型複雜度,加以改進。
目前流行的劃分方法,是用隱藏層的數量多少來區分是否「深度」。當神經網絡中隱藏層數量達到3層以上時,就被稱爲「深度神經網絡」,或者「深度學習」。
久聞大名的深度學習,原來就是這麼簡單。
若是有時間的話,建議你本身在這個遊樂場裏多動手玩兒一玩兒。你會很快對神經網絡和深度學習有個感性認識。
遊樂場背後使用的引擎,就是Google的深度學習框架Tensorflow。
所謂框架,就是別人幫你構造好的基礎軟件應用。你能夠經過調用它們,避免本身重複發明輪子,大幅度節省時間,提高效率。
支持Python語言的深度學習的框架有不少,除了Tensorflow外,還有PyTorch, Theano和MXNet等。
我給你的建議是,找到一個你喜歡的軟件包,深刻學習使用,不斷實踐來提高本身的技能。千萬不要跟別人爭論哪一個深度學習框架更好。一來蘿蔔白菜各有所愛,每一個人都有本身的偏好;二來深度學習的江湖水很深,言多有失。說錯了話,別的門派可能會不高興喲。
我比較喜歡Tensorflow。可是Tensorflow自己是個底層庫。雖然隨着版本的更迭,界面愈來愈易用。可是對初學者來講,許多細節依然有些過於瑣碎,不容易掌握。
初學者的耐心有限,挫折過多容易放棄。
幸虧,還有幾個高度抽象框架,是創建在Tensorflow之上的。若是你的任務是應用現成的深度學習模型,那麼這些框架會給你帶來很是大的便利。
這些框架包括Keras, TensorLayer等。我們今天將要使用的,叫作TFlearn。
它的特色,就是長得很像Scikit-learn。這樣若是你熟悉經典機器學習模型,學起來會特別輕鬆省力。
閒話就說這麼多,下面我們繼續寫代碼吧。
寫代碼以前,請回到終端下,運行如下命令,安裝幾個軟件包:
pip install tensorflow
pip install tflearn
複製代碼
執行完畢後,回到Notebook裏。
咱們呼叫tflearn框架。
import tflearn
複製代碼
而後,咱們開始搭積木同樣,搭神經網絡層。
首先是輸入層。
net = tflearn.input_data(shape=[None, 11])
複製代碼
注意這裏的寫法,由於咱們輸入的數據,是特徵矩陣。而通過咱們處理後,特徵矩陣如今有11列,所以shape的第二項寫11。
shape的第一項,None,指的是咱們要輸入的特徵矩陣行數。由於咱們如今是搭建模型,後面特徵矩陣有可能一次輸入,有可能分紅組塊輸入,長度可大可小,沒法事先肯定。因此這裏填None。tflearn會在咱們實際執行訓練的時候,本身讀入特徵矩陣的尺寸,來處理這個數值。
下面咱們搭建隱藏層。這裏咱們要使用深度學習,搭建3層。
net = tflearn.fully_connected(net, 6, activation='relu')
net = tflearn.fully_connected(net, 6, activation='relu')
net = tflearn.fully_connected(net, 6, activation='relu')
複製代碼
activation剛纔在深度學習遊樂場裏面咱們遇到過,表明激活函數。若是沒有它,全部的輸入輸出都是線性關係。
Relu函數是激活函數的一種。它大概長這個樣子。
若是你想了解激活函數的更多知識,請參考後文的學習資源部分。
隱藏層裏,每一層咱們都設置了6個神經元。其實至今爲之,也不存在最優神經元數量的計算公式。工程界的一種作法,是把輸入層的神經元數量,加上輸出層神經元數量,除以2取整。我們這裏就是用的這種方法,得出6個。
搭好了3箇中間隱藏層,下面咱們來搭建輸出層。
net = tflearn.fully_connected(net, 2, activation='softmax')
net = tflearn.regression(net)
複製代碼
這裏咱們用兩個神經元作輸出,而且說明使用迴歸方法。輸出層選用的激活函數爲softmax。處理分類任務的時候,softmax比較合適。它會告訴咱們每一類的可能性,其中數值最高的,能夠做爲咱們的分類結果。
積木搭完了,下面咱們告訴TFlearn,以剛剛搭建的結構,生成模型。
model = tflearn.DNN(net)
複製代碼
有了模型,咱們就可使用擬合功能了。你看是否是跟Scikit-learn的使用方法很類似呢?
model.fit(X_train, y_train, n_epoch=30, batch_size=32, show_metric=True)
複製代碼
注意這裏多了幾個參數,咱們來解釋一下。
n_epoch
:數據訓練幾個輪次。batch_size
:每一次輸入給模型的數據行數。show_metric
:訓練過程當中要不要打印結果。如下就是電腦輸出的最終訓練結果。其實中間運行過程看着更激動人心,你本身試一下就知道了。
Training Step: 7499 | total loss: [1m[32m0.39757[0m[0m | time: 0.656s
| Adam | epoch: 030 | loss: 0.39757 - acc: 0.8493 -- iter: 7968/8000
Training Step: 7500 | total loss: [1m[32m0.40385[0m[0m | time: 0.659s
| Adam | epoch: 030 | loss: 0.40385 - acc: 0.8487 -- iter: 8000/8000
--
複製代碼
咱們看到訓練集的損失(loss)大概爲0.4左右。
打開終端,咱們輸入
tensorboard --logdir=/tmp/tflearn_logs/
複製代碼
而後在瀏覽器裏輸入http://localhost:6006/
能夠看到以下界面:
這是模型訓練過程的可視化圖形,能夠看到準確度的攀升和損失下降的曲線。
打開GRAPHS標籤頁,咱們能夠查看神經網絡的結構圖形。
咱們搭積木的過程,在此處一目瞭然。
訓練好了模型,咱們來嘗試作個預測吧。
看看測試集的特徵矩陣第一行。
X_test[0]
複製代碼
array([ 1.75486502, -0.57369368, -0.55204276, -1.09168714, -0.36890377,
1.04473698, 0.8793029 , -0.92159124, 0.64259497, 0.9687384 ,
1.61085707])
複製代碼
咱們就用它來預測一下分類結果。
y_pred = model.predict(X_test)
複製代碼
打印出來看看:
y_pred[0]
複製代碼
array([ 0.70956731, 0.29043278], dtype=float32)
複製代碼
模型判斷該客戶不流失的可能性爲0.70956731。
咱們看看實際標籤數據:
y_test[0]
複製代碼
array([ 1., 0.])
複製代碼
客戶果真沒有流失。這個預測是對的。
可是一個數據的預測正確與否,是沒法說明問題的。咱們下面跑整個測試集,而且使用evaluate函數評價模型。
score = model.evaluate(X_test, y_test)
print('Test accuarcy: %0.4f%%' % (score[0] * 100))
複製代碼
Test accuarcy: 84.1500%
複製代碼
在測試集上,準確性達到84.15%,好樣的!
但願在你的努力下,機器作出的準確判斷能夠幫助銀行有效鎖定可能流失的客戶,下降客戶的流失率,繼續日進斗金。
你可能以爲,深度學習也沒有什麼厲害的嘛。原先的決策樹算法,那麼簡單就能實現,也能夠達到80%以上的準確度。寫了這麼多語句,深度學習結果也無非只提高了幾個百分點而已。
首先,準確度達到某種高度後,提高是不容易的。這就好像學生考試,從不及格到及格,付出的努力並不須要很高;從95分提高到100,倒是許多人一生也沒有完成的目標。
其次,在某些領域裏,1%的提高意味着以百萬美圓計的利潤,或者幾千我的的生命所以獲得拯救。
第三,深度學習的崛起,是由於大數據的環境。在許多狀況下,數據越多,深度學習的優點就越明顯。本例中只有10000條記錄,與「大數據」的規模還相去甚遠。
若是你對深度學習感興趣,推薦如下學習資源。
首先是教材。
第一本是Deep Learning,絕對的經典。
第二本是Hands-On Machine Learning with Scikit-Learn and TensorFlow: Concepts, Tools, and Techniques to Build Intelligent Systems,深刻淺出,通俗易懂。
其次是MOOC。
推薦吳恩達(Andrew Ng)教授在Coursera上的兩門課程。
一門是機器學習。這課推出有年頭了,可是很是有趣和實用。具體的介紹請參考拙做《機器學習哪裏有這麼玄?》以及《如何用MOOC組合掌握機器學習?》。
一門是深度學習。這是個系列課程,包括5門子課程。今年推出的新課,自成體系,可是最好有前面那門課程做爲基礎。
你對深度學習感興趣嗎?以前有沒有作過深度學習項目?你掌握了哪些深度學習框架?有沒有什麼建議給初學者?歡迎留言,把心得分享給你們,咱們一塊兒交流討論。
喜歡請點贊。還能夠微信關注和置頂個人公衆號「玉樹芝蘭」(nkwangshuyi)。
若是你對數據科學感興趣,不妨閱讀個人系列教程索引貼《如何高效入門數據科學?》,裏面還有更多的有趣問題及解法。