機器學習開放課程(四)線性分類與線性回歸

2021-03-02 論智

編者按:機器學習開放課程第四課,Mail.Ru數據科學家Yury Kashnitsky深入講解線性分類和線性回歸的理論與實踐。

xkcd

譯文:「如你所見,到下個月底,你會有48位丈夫。值得吃一大塊蛋糕慶祝下。」(橫軸為日期:昨天、今天;縱軸為丈夫數量。)

歡迎參加我們的第4課。這次我們將呈現最重要的主題——線性模型。如果你準備好了數據,打算開始訓練模型,那麼你最有可能首先嘗試線性回歸或邏輯回歸(具體取決於你的任務是回歸還是分類)。

本文包括線性模型的理論和實踐(在實際任務中的使用)。此外,你將參加一項Kaggle競賽,解決一個基於瀏覽歷史識別用戶的問題。

回歸

最小二乘法

最大似然估計

偏置-方差分解

線性回歸正則化

線性分類

線性分類器

作為線性分類器的邏輯回歸

最大似然估計和邏輯回歸

邏輯損失的L2正則化

邏輯回歸正則化示例

邏輯回歸的優缺點

驗證和學習曲線

課內Kaggle競賽「我知道你是誰」

作業四

相關資源

我們的線性模型學習從線性回歸開始。首先,需要指定一個模型將因變量y和解釋因素(特徵)聯繫起來;對線性模型而言,依賴函數的形式如下:

如果我們為每項觀測加上一個虛維度x0 = 1 (偏置),那麼上面的線性形式可以改寫為一個略微緊湊的形式:

如果我們有一個特徵觀測矩陣,其中矩陣的行是數據集中的觀測,那麼需要在左邊加上一列。

我們可以定義模型為:

其中:

上述表達式也可以寫成這樣(寫出每項觀察):

模型具有如下限制(否則它就不是線性回歸了):

權重wi的估計滿足如下條件時,我們稱其為線性:

其中,∀k,ωki僅依賴於X中的樣本,而且幾乎一定以非線性的方式。由於尋求最佳權重的解是一個線性估計,這一模型被稱為線性回歸。讓我們再引入一項定義。當期望值等於真實而未知的估計參數的值時,權重估計稱為無偏(unbiased):

計算這些權重的方法之一是普通最小二乘法(OLS)。OLS最小化因變量的實際值和模型給出的預測值之間的均方誤差:

為了解決這一優化問題,我們需要計算模型參數的導數。我們將導數設為零,然後求解所得關於w的等式。

矩陣求導小抄:

讓我們開始計算:

基於上述定義和條件,我們可以說,根據高斯-馬爾可夫定理,模型參數的OLS估計是所有線性無偏估計中最優的,即,它們給出最低的方差。

最大似然估計

有人可能會問,為何我們選擇最小化均方誤差而不是別的什麼?畢竟,我們可以最小化殘差的平均絕對值。如果我們改變了最小化的值,唯一會發生的事就是我們將超出高斯-馬爾可夫定理的條件,因此我們的估計將不再是最佳的線性無偏估計。

在我們繼續之前,讓我們稍微離題一下,通過一個簡單的例子講解下最大似然估計。

許多人大概都記得乙醇的化學式,所以我決定做一個試驗判定人們是否記得簡單的甲醇化學式:CH3OH. 我們調查了400人,發現只有117個人記得甲醇的化學式。那麼,下一個受訪者知道甲醇化學式的概率為117/400 ≈ 29%會是一個合理的假定。讓我們展示下這個直觀的估計不僅很好,同時也是最大似然估計。估計來自哪裡?回憶下伯努利分布的定義:如果一個隨機變量只有兩個值(1和0,相應的概率為θ和1 - θ),那麼該隨機變量滿足伯努利分布,遵循以下概率分布函數:

這一分布正是我們所需要的,分布參數θ是一個人知道甲醇化學式的概率估計。在我們的400個獨立試驗中,讓我們將試驗的結果記為x = (x1, x2, ..., x400)。讓我們寫下數據(觀測)的似然,即正好觀測到117個隨機變量θ = 1的實例和283個隨機變量θ = 0的實例:

接著,我們將最大化這一θ的表達式。最常見的情況是,我們並不最大化似然p(x | θ),轉而最大化其對數(這一單調變換不影響解答,但大大簡化了計算):

為了找到最大化上式的θ,我們求θ的導數,設為零,求解所得等式:

結果發現,我們的直觀估計正好是最大似然估計。現在讓我們將這一推理過程應用到線性回歸問題上,嘗試找出均方誤差背後有什麼。為此,我們需要從概率論的角度來看線性回歸。我們的模型和之前是一樣的:

不過,現在讓我們假定隨機誤差符合均值為零的正態分布:

據此改寫模型:

由於樣本是獨立抽取的(不相關誤差是高斯-馬爾可夫定理的條件之一),數據的似然看起來會是密度函數p(yi)的積。讓我們考慮對數似然,對數似然允許我們用和替換積:

我們想要找到最大似然假設,即,我們需要最大化表達式p(y ∣ Xw) 以得到wML。這和最大化其對數是一回事。注意,當我們針對某個參數最大化函數時,我們可以丟棄所有不依賴這一參數的成員:

所以,我們看到了,最大化數據的似然和最小化均方誤差是一回事(給定以上的假定)。實際上,這是因為誤差是正態分布的。

偏置-方差分解

讓我們稍微談下線性回歸預測的誤差性質(實際上,這一討論在所有機器學習算法上都成立)。我們已經提到:

因此,點x的誤差可分解為:

為了簡明,我們將省略函數的參數。讓我們分別考慮每個成員。據以下公式:

我們很容易就能分解前兩項:

注意:

最後我們來處理和的最後一項。回憶一下,誤差和目標變量相互獨立:

最後,讓我們把這些合併到一起:

我們已經達到了我們的終極目標——最後的等式告訴我們,任何線性模型的預測誤差由三部分組成:

儘管我們對σ2無能為力,我們可以影響前兩項。理想情況下,我們希望同時取消這兩項(見下圖中左上),但是,在實踐中,常常需要在偏置和不穩定(高方差)間尋找平衡。

一般而言,當模型的計算增加了(例如,自由參數的數量增加了),估計的方差(分散程度)也會增加,但偏置會下降。由於模型完全記下了訓練集而沒能概括訓練集,小小的變動將導致未預期的結果(過擬合)。另一方面,如果模型太弱,它將不能夠學習模式,導致學習偏離正解較遠的不同答案。

高斯-馬爾可夫定理斷言,在線性模型參數估計問題中,OLS估計是最佳的線性無偏估計。這意味著,如果存在任何無偏線性模型g,我們可以確信

線性回歸正則化

在一些情形下,我們可能會為了穩定性(降低模型的方差)特意增加模型的偏置。高斯-馬爾可夫定理的條件之一就是矩陣X是滿秩的。否則,OLS解w = (XTX)-1XTy不存在,因為逆矩陣(XTX)-1不存在。換句話說,矩陣XTX將是奇異矩陣或退化矩陣。這被稱為病態問題。這類問題必須加以矯正,也就是說,矩陣XTX需要變為非退化矩陣或非奇異矩陣(這正是這一過程叫做正則化的原因)。我們常常能在這類數據中觀察到所謂的多重共線性:當兩個或更多特徵高度相關,也就是矩陣X的列之間「幾乎」存在線性依賴。例如,在基於參數預測房價這一問題中,屬性「含陽臺面積」和「不含陽臺面積」會有一個「幾乎是」線性的關係。形式化地說,包含這類數據的矩陣XTX是可逆的,但由於多重共線性,一些本徵值會接近零。在XTX的逆矩陣中,會出現一些極端巨大的本徵值,因為逆矩陣的本徵值為1/(λi)。這一本徵值的波動會導致模型參數估計的不穩定,即,在訓練數據中加入一組新的觀測會導致完全不同的解。有一種正則化的方法稱為吉洪諾夫正則化,大致上是在均方誤差中加上一個新成員:

吉洪諾夫矩陣常常表達為單位矩陣乘上一個係數:

在這一情形下,最小化均方誤差問題變為一個L2正則限定問題。如果我們對新的損失函數求導,設所得函數為零,據w重整等式,我們便得到了這一問題的解:

這類回歸被稱為嶺回歸。嶺為對角矩陣,我們在XTX矩陣上加上這一對角矩陣,以確保我們能得到一個常規矩陣。

這樣的解降低了分散程度,但增加了偏置,因為參數的正則向量同時最小化了,這導致解朝零移動。在下圖中,OLS解為白色虛線的交點。藍點表示嶺回歸的不同解。可以看到,通過增加正則化參數λ,我們使解朝零移動。

線性分類器

線性分類器背後的基本思路是,目標分類的值可以被特徵空間中的一個超平面分開。如果這可以無誤差地達成,那麼訓練集被稱為線性可分

我們之前已經了解了線性回歸和普通最小二乘法(OLS)。現在考慮一個二元分類問題,將目標分類記為「+1」(正面樣本)和「-1」(負面樣本)。最簡單的線性分類器可以通過回歸定義:

其中

x是特徵向量(包括標識);

w是線性模型中的權重向量(偏置為w0);

sign()是符號函數,返回參數的符號;

a(x)是分類x的分類器。

作為線性分類器的邏輯回歸

邏輯回歸是線性分類器的一個特殊情形,邏輯回歸有一個額外的好處,可以預測樣本xi為分類「+」的概率p+。

不僅能夠預測一個回應(「+1」或「-1」),還能預測相應的概率,對於很多業務問題(比如,信用評分,這一問題傳統上使用邏輯回歸)而言,這是一個非常重要的需求。

銀行選擇一個閾值p*以預測貸款違約的概率(上圖中閾值為0.15),超過閾值就不批准貸款。此外,還可以將預測概率乘以未償還金額,以得到客戶造成的期望損失,這可以構成有用的業務指標。

為了預測概率p+ ∈ [0, 1],我們可以從使用OLS構造線性預測開始:

不過,為了將所得結果轉換為[0, 1]區間內的概率,我們需要某個函數

邏輯回歸使用如下函數:

%matplotlib inline

from matplotlib import pyplot as plt

import seaborn as sns

import numpy as np

def sigma(z):

   return 1. / (1 + np.exp(-z))

xx = np.linspace(-10, 10, 1000)

plt.plot(xx, [sigma(x) for x in xx]);

plt.xlabel('z');

plt.ylabel('sigmoid(z)')

plt.title('Sigmoid function');

我們將事件X的概率記為P(X),則比值比OR(X)由下式判定P(X)/(1-P(X)),這是某一事件是否發生的概率之比。顯然,概率和比值比包含同樣的信息,不過P(X)的範圍是0到1,而OR(X)的範圍是0到∞。

如果我們計算OR(X)的對數,那麼顯然我們有log OR(X) ∈ ℝ. 我們在OLS中將用到這個。

讓我們看看邏輯回歸是如何做出預測的:

目前而言,讓我們假設我們已經通過某種方式得到了權重w,即,模型已經訓練好了。之後我們將看下這是如何做的。

步驟一 計算

等式WTX = 0定義了將樣本分為兩類的超空間。

步驟二 計算對數比值比:

步驟三 現在我們已經有了將一個樣本分配到「+」分類的概率OR+,我們可以據此計算p+:

我們看到,上式的右邊我們得到了sigmoid函數。

所以,邏輯回歸預測將一個樣本分配為「+」分類的概率(假定我們已知模型的特徵和權重),這一過程是通過對權重向量和特徵向量的線性組合進行sigmoid變換完成的:

下面我們將看下模型是如何訓練的。我們將再次依靠最大似然估計。

最大似然估計和邏輯回歸

現在,讓我們看下從MLE出發如何進行邏輯回歸優化,也就是最小化邏輯損失函數。我們前面已經見過了將樣本分配為「+」分類的邏輯回歸模型:

「-」分類相應的表達式為:

這兩個表達式可以組合成一個:

表達式M(xi) = yiwTxi稱為目標xi的分類邊緣。如果邊緣非負,則模型正確選擇了目標xi的分類;如果邊緣為負,則目標xi被錯誤分類了。注意,邊緣僅針對訓練集中的目標(真實目標分類標籤yi已知的目標)而言。

為了精確地理解我們為何得出這一結論,讓我們轉向線性分類器的幾何解釋。

首先,我會建議看下線性代數的一個經典入門問題:找出向徑xA與平面wTx = 0的距離。

答案:

從答案中,我們可以看到,表達式wTxi的絕對值越大,點xi離平面wTx = 0的距離就越遠。

因此,表達式M(xi) = yiwTxi是模型對目標xi分類的「信心」:

如果邊緣的絕對值較大,且為正值,那麼分類的標籤是正確的,且目標離分界超平面很遠,也就是模型對分類很自信。如下圖點x3所示;

如果邊緣的絕對值較大,且為負值,那麼分類的標籤是錯誤的,且目標離分界超平面很遠(目標很可能是一個異常值;例如,它可能是訓練集中一個錯誤標記的值)。如下圖點x1所示;

如果邊緣的絕對值較小,那麼目標距離分界超平面很近,邊緣的符號決定目標是否被正確分類了。如下圖點x2和x4所示。

現在讓我們計算數據集的似然,即基於數據集X觀測到給定向量y的概率。我們將做一個強假設:目標來自一個獨立分布(i.i.d.)。

其中,ℓ為數據集X的長度(行數)。

像我們經常幹的那樣,對這個表達式取對數,因為和要比積容易優化得多:

最大化似然等價於最小化以下表達式:

這就是邏輯損失函數。

用邊緣改寫邏輯損失函數,我們有:

我們將這一函數的圖像和0-1損失函數的圖像繪製在一張圖上。0-1損失函數簡單地懲罰模型誤差(邊緣為負)為1:

上圖體現了這樣一個想法,如果我們不能夠直接最小化分類問題的誤差數量(至少無法通過梯度方法最小化——0-1損失函數在零處的導數趨向無窮),我們可以最小化它的上界。對邏輯損失函數而言,以下是成立的:

我們希望能通過降低分類誤差數的上界,降低分類誤差數本身。

邏輯損失的L2正則化

邏輯回歸的L2正則化和嶺回歸的情況基本一樣。我們轉而最小化下式:

在邏輯回歸中,通常使用正則化係數的倒數C = 1/λ:

下面我們將通過一個例子直觀地理解正則化。

讓我們看下正則化是如何影響分類的質量的(數據集為吳恩達機器學習課程中的微晶片測試)。我們將使用基於多項式特徵的邏輯回歸,然後改變正則化參數C. 首先,我們將看看正則化是如何影響分類器的分界的,並直觀地識別欠擬合和過擬合。接著,我們將通過交叉驗證和網格搜索選擇數值上接近最優值的正則化參數。

# 關閉警告

# 如果你喜歡開著警告,可以注釋掉下面兩行

import warnings

warnings.filterwarnings('ignore')

%matplotlib inline

from matplotlib import pyplot as plt

import seaborn as sns

import numpy as np

import pandas as pd

from sklearn.preprocessing import PolynomialFeatures

from sklearn.linear_model import LogisticRegression, LogisticRegressionCV

from sklearn.model_selection import cross_val_score, StratifiedKFold

from sklearn.model_selection import GridSearchCV

讓我們使用pandas庫的read_csv方法加載數據。這個數據集內有118個微晶片(目標),其中有兩項質量控制測試的結果(兩個數值變量)和微晶片是否投產的信息。變量已經居中了,也就是列中的值已經減去其均值。所以,「平均」微晶片的測試值為零。

# 加載數據

data = pd.read_csv('../../data/microchip_tests.txt',

                  header=None, names = ('test1','test2','released'))

# 了解數據集的基本信息

data.info()

<class 'pandas.core.frame.DataFrame'>

RangeIndex: 118 entries, 0 to 117

Data columns (total 3 columns):

test1       118 non-null float64

test2       118 non-null float64

released    118 non-null int64

dtypes: float64(2), int64(1)

memory usage: 2.8 KB

讓我們看下開始五行和最後五行:

data.head(5)

data.tail(5)

分離訓練集和目標分類標籤:

X = data.iloc[:,:2].values

y = data.iloc[:,2].values

繪製數據,橙點對應有缺陷的晶片,藍點對應正常晶片。

plt.scatter(X[y == 1, 0], X[y == 1, 1], c='blue', label='Released')

plt.scatter(X[y == 0, 0], X[y == 0, 1], c='orange', label='Faulty')

plt.xlabel("Test 1")

plt.ylabel("Test 2")

plt.title('2 tests of microchips. Logit with C=1')

plt.legend();

定義一個顯示分類器的分界曲線的函數。

def plot_boundary(clf, X, y, grid_step=.01, poly_featurizer=None):

   x_min, x_max = X[:, 0].min() - .1, X[:, 0].max() + .1

   y_min, y_max = X[:, 1].min() - .1, X[:, 1].max() + .1

   xx, yy = np.meshgrid(np.arange(x_min, x_max, grid_step),

                        np.arange(y_min, y_max, grid_step))

   Z = clf.predict(poly_featurizer.transform(np.c_[xx.ravel(), yy.ravel()]))

   Z = Z.reshape(xx.shape)

   plt.contour(xx, yy, Z, cmap=plt.cm.Paired)

我們為兩個變量x1和x2定義如下多形式特徵:

例如,d = 3時的特徵如下:

特徵的數量呈指數型增長,為100個變量創建d較大(例如d = 10)的多項式特徵成本很高。更重要的是,不需要如此。

我們將使用sklearn的邏輯回歸實現。我們將創建一個對象,為矩陣X加上多項式特徵(d不超過7)。

poly = PolynomialFeatures(degree=7)

X_poly = poly.fit_transform(X)

X_poly.shape

結果:

(118, 36)

讓我們訓練邏輯回歸,正則化係數C = 10-2。

C = 1e-2

logit = LogisticRegression(C=C, random_state=17)

logit.fit(X_poly, y)

plot_boundary(logit, X, y, grid_step=.01, poly_featurizer=poly)

plt.scatter(X[y == 1, 0], X[y == 1, 1], c='blue', label='Released')

plt.scatter(X[y == 0, 0], X[y == 0, 1], c='orange', label='Faulty')

plt.xlabel("Test 1")

plt.ylabel("Test 2")

plt.title('2 tests of microchips. Logit with C=%s' % C)

plt.legend();

print("Accuracy on training set:",

     round(logit.score(X_poly, y), 3))

Accuracy on training set: 0.627

我們可以嘗試將C增加到1,也就是說,我們削弱了正則化,現在的模型權重可以比之前有更大的值(絕對值更大)。這使得分類器在訓練集上的精確度改善了(提高到0.831)。

C = 1

logit = LogisticRegression(C=C, random_state=17)

logit.fit(X_poly, y)

plot_boundary(logit, X, y, grid_step=.005, poly_featurizer=poly)

plt.scatter(X[y == 1, 0], X[y == 1, 1], c='blue', label='Released')

plt.scatter(X[y == 0, 0], X[y == 0, 1], c='orange', label='Faulty')

plt.xlabel("Test 1")

plt.ylabel("Test 2")

plt.title('2 tests of microchips. Logit with C=%s' % C)

plt.legend();

print("Accuracy on training set:",

     round(logit.score(X_poly, y), 3))

Accuracy on training set: 0.831

我們為什麼不接著進一步增加C呢?比如,將C增加到10000?這回,很明顯正則化不夠強,我們看到了過擬合。注意,C = 1時,「平滑」邊界對應的訓練集上的正確解答並沒有低多少。但我們很容易可以想像得到,我們之前的模型將在新數據上工作得更好。

C = 1e4

logit = LogisticRegression(C=C, random_state=17)

logit.fit(X_poly, y)

plot_boundary(logit, X, y, grid_step=.005, poly_featurizer=poly)

plt.scatter(X[y == 1, 0], X[y == 1, 1], c='blue', label='Released')

plt.scatter(X[y == 0, 0], X[y == 0, 1], c='orange', label='Faulty')

plt.xlabel("Test 1")

plt.ylabel("Test 2")

plt.title('2 tests of microchips. Logit with C=%s' % C)

plt.legend();

print("Accuracy on training set:",

     round(logit.score(X_poly, y), 3))

Accuracy on training set: 0.873

為了討論以上這些結果,讓我們改寫一下邏輯回歸優化的函數:

部分和:

參數C越大,模型可恢復的數據中的關係就越複雜(直觀地說,C對應模型的「複雜度」——模型能力)。

如果正則化過強,即C值很小,最小化邏輯損失函數問題的解可能是一個許多權重過小或為零的解。這樣的模型對誤差的「懲罰」也不夠(即,在函數J中,權重的平方和「權重過高」,誤差L可能相對很大)。在這一情形下,模型將會欠擬合,如我們在第一個情形下所看到的那樣。

相反,如果正則化過弱,即C值很大,由絕對值很大的分量組成的向量w可能變成優化問題的解。在這一情形下,L對優化的函數J貢獻較大。大致上,這樣的模型對在訓練集的目標上犯錯過於「恐懼」,因而會過擬合,如我們在第三個情形下所看到的那樣。

邏輯回歸不會「理解」(或「學習」)選擇C的值,這和權重w的情況不一樣。這就是說,C的值無法通過解決邏輯回歸的優化問題而確定。我們之前碰到過類似的情況——決策樹無法在訓練過程中「學習」選擇深度限制。因此,C是模型的超參數,通過交叉驗證調節;決策樹的max_depth同理。

正則化參數調整

讓我們確定上述例子中正則化參數C的最優值。我們可以使用LogisticRegressionCV——網格搜索參數後進行交叉驗證。這個類是專門為邏輯回歸設計的。對任意模型而言,使用GridSearchCV或RandomizedSearchCV,或者特殊的超參數優化算法,比如hyperopt中實現的算法。

skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=17)

c_values = np.logspace(-2, 3, 500)

logit_searcher = LogisticRegressionCV(Cs=c_values, cv=skf, verbose=1, n_jobs=-1)

logit_searcher.fit(X_poly, y)

logit_searcher.C_

結果:

array([198.8827857])

讓我們看下超參數C是如何影響模型的質量的:

plt.plot(c_values, np.mean(logit_searcher.scores_[1], axis=0))

plt.xlabel('C')

plt.ylabel('Mean CV-accuracy');

最後,選擇C值「最佳」(C值較大加重算力負擔,也容易導致過擬合)的區域:

plt.plot(c_values, np.mean(logit_searcher.scores_[1], axis=0))

plt.xlabel('C')

plt.ylabel('Mean CV-accuracy');

plt.xlim((0,10));

回憶一下,這些曲線被稱為驗證曲線。之前我們手工創建了驗證曲線,不過sklearn有構建這些曲線的特殊方法,我們以後將直接使用sklearn的相應方法。

分析IMDB影評

現在讓我們做個小練習!我們想要解決IMDB影評的二元分類問題。我們有一個訓練集,其中包含標記好的影評,12500條好評,12500條差評。直接開始機器學習並不容易,因為我們並沒有矩陣X;我們需要準備它。我們將使用一個簡單方法:詞袋模型。影評的特徵將由整個語料庫中的每個詞的出現情況表示。語料庫是所有用戶影評。下圖展示了這一思路:

%matplotlib inline

import seaborn as sns

import numpy as np

from sklearn.datasets import load_files

from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer, TfidfVectorizer

from sklearn.linear_model import LogisticRegression

from sklearn.svm import LinearSVC

數據集可通過以下地址下載:

http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz

數據集的簡要描述: ai.stanford.edu/~amaas/data/sentiment/

# 請修改文件路徑

reviews_train = load_files("/Users/y.kashnitsky/Yandex.Disk.localized/ML/data/aclImdb/train")

text_train, y_train = reviews_train.data, reviews_train.target

看看訓練集和測試集中各有多少條數據:

print("Number of documents in training data: %d" % len(text_train))

print(np.bincount(y_train))

Number of documents in training data: 25000

[12500 12500]

# 請修改文件路徑

reviews_test = load_files("/Users/y.kashnitsky/Yandex.Disk.localized/ML/data/aclImdb/test")

text_test, y_test = reviews_test.data, reviews_test.target

print("Number of documents in test data: %d" % len(text_test))

print(np.bincount(y_test))

Number of documents in test data: 25000

[12500 12500]

下面是影評的一些例子。

print(text_train[1])

b'Words can\'t describe how bad this movie is. I can\'t explain it by writing only. You have too see it for yourself to get at grip of how horrible a movie really can be. Not that I recommend you to do that. There are so many clich\xc3\xa9s, mistakes (and all other negative things you can imagine) here that will just make you cry. To start with the technical first, there are a LOT of mistakes regarding the airplane. I won\'t list them here, but just mention the coloring of the plane. They didn\'t even manage to show an airliner in the colors of a fictional airline, but instead used a 747 painted in the original Boeing livery. Very bad. The plot is stupid and has been done many times before, only much, much better. There are so many ridiculous moments here that i lost count of it really early. Also, I was on the bad guys\' side all the time in the movie, because the good guys were so stupid. "Executive Decision" should without a doubt be you\'re choice over this one, even the "Turbulence"-movies are better. In fact, every other movie in the world is better than this one.'

上面這條影評是差評還是好評?

y_train[1]

0

沒錯,和我們預料的一樣,這是一條差評。

text_train[2]

b'Everyone plays their part pretty well in this "little nice movie". Belushi gets the chance to live part of his life differently, but ends up realizing that what he had was going to be just as good or maybe even better. The movie shows us that we ought to take advantage of the opportunities we have, not the ones we do not or cannot have. If U can get this movie on video for around $10, it\xc2\xb4d be an investment!'

這條呢?

y_train[2]

1

是好評。

單詞簡單計數

首先,我們使用CountVectorizer創建包含所有單詞的字典。

cv = CountVectorizer()

cv.fit(text_train)

len(cv.vocabulary_)

74849

如果你查看下「單詞」的樣本(我們還是稱作token吧),你會發現我們省略了文本處理的許多重要步驟(自動化文本處理自身就可以成為一個獨立的文章系列)。

print(cv.get_feature_names()[:50])

print(cv.get_feature_names()[50000:50050])

['00', '000', '0000000000001', '00001', '00015', '000s', '001', '003830', '006', '007', '0079', '0080', '0083', '0093638', '00am', '00pm', '00s', '01', '01pm', '02', '020410', '029', '03', '04', '041', '05', '050', '06', '06th', '07', '08', '087', '089', '08th', '09', '0f', '0ne', '0r', '0s', '10', '100', '1000', '1000000', '10000000000000', '1000lb', '1000s', '1001', '100b', '100k', '100m']

['pincher', 'pinchers', 'pinches', 'pinching', 'pinchot', 'pinciotti', 'pine', 'pineal', 'pineapple', 'pineapples', 'pines', 'pinet', 'pinetrees', 'pineyro', 'pinfall', 'pinfold', 'ping', 'pingo', 'pinhead', 'pinheads', 'pinho', 'pining', 'pinjar', 'pink', 'pinkerton', 'pinkett', 'pinkie', 'pinkins', 'pinkish', 'pinko', 'pinks', 'pinku', 'pinkus', 'pinky', 'pinnacle', 'pinnacles', 'pinned', 'pinning', 'pinnings', 'pinnochio', 'pinnocioesque', 'pino', 'pinocchio', 'pinochet', 'pinochets', 'pinoy', 'pinpoint', 'pinpoints', 'pins', 'pinsent']

接著,我們將使用單詞的索引編碼訓練集文本的句子。我們將使用稀疏矩陣。

X_train = cv.transform(text_train)

X_train

<25000x74849 sparse matrix of type '<class 'numpy.int64'>'

   with 3445861 stored elements in Compressed Sparse Row format>

讓我們看下這一轉換是如何進行的。

print(text_train[19726])

b'This movie is terrible but it has some good effects.'

X_train[19726].nonzero()[1]

array([ 9881, 21020, 28068, 29999, 34585, 34683, 44147, 61617, 66150, 66562], dtype=int32)

接下來,我們對測試集應用同樣的操作。

X_test = cv.transform(text_test)

下一步是訓練邏輯回歸。

%%time

logit = LogisticRegression(n_jobs=-1, random_state=7)

logit.fit(X_train, y_train)

CPU times: user 40.9 s, sys: 524 ms, total: 41.4 s

Wall time: 10.5 s

讓我們看下訓練集和測試集上的精確度。

round(logit.score(X_train, y_train), 3), round(logit.score(X_test, y_test), 3)

(0.998, 0.86699999999999999)

模型的係數可以美觀地顯示。

def visualize_coefficients(classifier, feature_names, n_top_features=25):

   # 獲取絕對值較大的係數

   coef = classifier.coef_.ravel()

   positive_coefficients = np.argsort(coef)[-n_top_features:]

   negative_coefficients = np.argsort(coef)[:n_top_features]

   interesting_coefficients = np.hstack([negative_coefficients, positive_coefficients])

   # 繪圖

   plt.figure(figsize=(15, 5))

   colors = ["red" if c < 0 else "blue" for c in coef[interesting_coefficients]]

   plt.bar(np.arange(2 * n_top_features), coef[interesting_coefficients], color=colors)

   feature_names = np.array(feature_names)

   plt.xticks(np.arange(1, 1 + 2 * n_top_features), feature_names[interesting_coefficients], rotation=60, ha="right");

def plot_grid_scores(grid, param_name):

   plt.plot(grid.param_grid[param_name], grid.cv_results_['mean_train_score'],

       color='green', label='train')

   plt.plot(grid.param_grid[param_name], grid.cv_results_['mean_test_score'],

       color='red', label='test')

   plt.legend();

visualize_coefficients(logit, cv.get_feature_names())

為了讓我們的模型更好,我們可以優化邏輯回歸的正則化係數。我們將使用sklearn.pipeline,因為CountVectorizer只應該應用於訓練數據(為了避免「偷窺」測試集和在測試集上計算詞頻)。在這一情形下,pipeline確定正確的行動序列:應用CountVectorizer,然後訓練邏輯回歸。

%%time

from sklearn.pipeline import make_pipeline

text_pipe_logit = make_pipeline(CountVectorizer(),

                               LogisticRegression(n_jobs=-1, random_state=7))

text_pipe_logit.fit(text_train, y_train)

print(text_pipe_logit.score(text_test, y_test))

0.86672

CPU times: user 49.9 s, sys: 571 ms, total: 50.5 s

Wall time: 20.5 s

%%time

from sklearn.model_selection import GridSearchCV

param_grid_logit = {'logisticregression__C': np.logspace(-5, 0, 6)}

grid_logit = GridSearchCV(text_pipe_logit, param_grid_logit, cv=3, n_jobs=-1)

grid_logit.fit(text_train, y_train)

CPU times: user 26.7 s, sys: 1.33 s, total: 28.1 s

Wall time: 1min 16s

讓我們查看下最佳C,以及相應的交叉驗證評分:

grid_logit.best_params_, grid_logit.best_score_

({'logisticregression__C': 0.10000000000000001}, 0.88527999999999996)

plot_grid_scores(grid_logit, 'logisticregression__C')

驗證集上的結果:

grid_logit.score(text_test, y_test)

0.87907999999999997

現在讓我們用隨機森林來分類。我們看到,邏輯回歸事半功倍。

from sklearn.ensemble import RandomForestClassifier

forest = RandomForestClassifier(n_estimators=200, n_jobs=-1, random_state=17)

%%time

forest.fit(X_train, y_train)

CPU times: user 3min 39s, sys: 1.2 s, total: 3min 40s

Wall time: 30.7 s

RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',

           max_depth=None, max_features='auto', max_leaf_nodes=None,

           min_impurity_split=1e-07, min_samples_leaf=1,

           min_samples_split=2, min_weight_fraction_leaf=0.0,

           n_estimators=200, n_jobs=-1, oob_score=False, random_state=17,

           verbose=0, warm_start=False)

round(forest.score(X_test, y_test), 3)

0.85499999999999998

XOR問題

現在讓我們看一個線性模型表現不佳的例子。

線性分類定義的是一個非常簡單的分界平面——一個超平面。最著名的超平面(或直線)無法無誤差地切分的玩具例子是XOR問題。

XOR即異或,其真值表如下:

XOR是一個簡單的二元分類問題,其中兩個分類呈對角交叉分布。

# 創建數據集

rng = np.random.RandomState(0)

X = rng.randn(200, 2)

y = np.logical_xor(X[:, 0] > 0, X[:, 1] > 0)

plt.scatter(X[:, 0], X[:, 1], s=30, c=y, cmap=plt.cm.Paired);

顯然,我們無法劃出一條直線無誤差地將兩個分類分開。因此,邏輯回歸在這一任務上的表現很差。

def plot_boundary(clf, X, y, plot_title):

   xx, yy = np.meshgrid(np.linspace(-3, 3, 50),

                    np.linspace(-3, 3, 50))

   clf.fit(X, y)

   # 為網格上的每個數據點繪製判定函數

   Z = clf.predict_proba(np.vstack((xx.ravel(), yy.ravel())).T)[:, 1]

   Z = Z.reshape(xx.shape)

   image = plt.imshow(Z, interpolation='nearest',

                          extent=(xx.min(), xx.max(), yy.min(), yy.max()),

                          aspect='auto', origin='lower', cmap=plt.cm.PuOr_r)

   contours = plt.contour(xx, yy, Z, levels=[0], linewidths=2,

                              linetypes='--')

   plt.scatter(X[:, 0], X[:, 1], s=30, c=y, cmap=plt.cm.Paired)

   plt.xticks(())

   plt.yticks(())

   plt.xlabel(r'$x_1$')

   plt.ylabel(r'$x_2$')

   plt.axis([-3, 3, -3, 3])

   plt.colorbar(image)

   plt.title(plot_title, fontsize=12);

plot_boundary(LogisticRegression(), X, y,

             "Logistic Regression, XOR problem")

然而,如果我們給出多項式特徵作為輸入(這裡d = 2),那麼問題解決了。

from sklearn.preprocessing import PolynomialFeatures

from sklearn.pipeline import Pipeline

logit_pipe = Pipeline([('poly', PolynomialFeatures(degree=2)),

                      ('logit', LogisticRegression())])

plot_boundary(logit_pipe, X, y,

             "Logistic Regression + quadratic features. XOR problem")

這裡,邏輯回歸仍然生成了一個超平面,不過是6維特徵空間(1、x1、x2、x12、x1x2、x22)中的超平面。當我們將這個超平面投影到原特徵空間(x1、x2)時,分界是非線性的。

在實踐中,多項式特徵確實有幫助,不過顯式創建它們在算力上是低效的。使用核技巧的SVM要快很多。在這一方法中,只計算高維空間中目標之間的距離(由核函數定義),而不用生成大量特徵組合。

現在,我們對模型驗證、交叉驗證、正則化已經有所了解,讓我們考慮一個更大的問題:

如果模型的質量不盡人意,該怎麼辦?

我們應該讓模型更複雜還是更簡單?

我們應該加入更多特徵嗎?

我們是否只是需要更多數據用於訓練?

這些問題的答案並不明顯。特別是,有時候一個更複雜的模型會導致表現退化。另一些時候,增加新的觀測並不會帶來可以觀察得到的變化。事實上,做出正確決定,選擇正確方法,從而改進模型的能力區分了優秀的專業人員和糟糕的專業人員。

讓我們回頭看看電信運營商離網率數據集。

%matplotlib inline

from matplotlib import pyplot as plt

import seaborn as sns

import numpy as np

import pandas as pd

from sklearn.preprocessing import PolynomialFeatures

from sklearn.pipeline import Pipeline

from sklearn.preprocessing import StandardScaler

from sklearn.linear_model import LogisticRegression, LogisticRegressionCV, SGDClassifier

from sklearn.model_selection import validation_curve

data = pd.read_csv('../../data/telecom_churn.csv').drop('State', axis=1)

data['International plan'] = data['International plan'].map({'Yes': 1, 'No': 0})

data['Voice mail plan'] = data['Voice mail plan'].map({'Yes': 1, 'No': 0})

y = data['Churn'].astype('int').values

X = data.drop('Churn', axis=1).values

我們將使用隨機梯度下降訓練邏輯回歸。我們將在之後的課程專門討論梯度下降。

alphas = np.logspace(-2, 0, 20)

sgd_logit = SGDClassifier(loss='log', n_jobs=-1, random_state=17)

logit_pipe = Pipeline([('scaler', StandardScaler()), ('poly', PolynomialFeatures(degree=2)),

                      ('sgd_logit', sgd_logit)])

val_train, val_test = validation_curve(logit_pipe, X, y,

                                      'sgd_logit__alpha', alphas, cv=5,

                                      scoring='roc_auc')

我們將繪製ROC-AUC曲線,查看下不同正則化參數導致的模型在訓練集和參數集上的不同表現。

趨勢相當明顯,這樣的趨勢在其他問題中也同樣常見:

需要多少數據?

數據是越多越好。但我們如何理解新數據是否在任何情況下都有幫助呢?例如,如何評估花費N來加倍數據集是否合理呢?

由於新數據可能無法取得,合理的做法是改變訓練集的大小,然後看解答的質量如何依賴於訓練數據的數量。這樣我們就得到了學習曲線。

這個想法很簡單:我們將誤差顯示為訓練中使用的樣本數的函數。模型的參數事先固定。

from sklearn.model_selection import learning_curve

def plot_learning_curve(degree=2, alpha=0.01):

   train_sizes = np.linspace(0.05, 1, 20)

   logit_pipe = Pipeline([('scaler', StandardScaler()), ('poly', PolynomialFeatures(degree=degree)),

                          ('sgd_logit', SGDClassifier(n_jobs=-1, random_state=17, alpha=alpha))])

   N_train, val_train, val_test = learning_curve(logit_pipe,

                                                 X, y, train_sizes=train_sizes, cv=5,

                                                 scoring='roc_auc')

   plot_with_err(N_train, val_train, label='training scores')

   plot_with_err(N_train, val_test, label='validation scores')

   plt.xlabel('Training Set Size'); plt.ylabel('AUC')

   plt.legend()

讓我們看看線性模型的結果。我們將把正則化係數設定為較大的數。

plot_learning_curve(degree=2, alpha=10)

一個典型的狀況:對於少量數據而言,訓練集和交叉驗證集之間的誤差差別相當大,這暗示了過擬合。同樣的模型,不過使用大量數據,誤差「收斂」,暗示了欠擬合。

如果我們加入更多數據,訓練集的誤差不會增加。另一方面,測試集上的誤差也不會下降。

所以,我們看到誤差「收斂」,加入新數據無濟於事。事實上這個情況對業務來說很重要。我們可能把數據集大小增大10倍,但是,如果我們不改變模型的複雜度,數據的增加沒有幫助。因此「設定一次,使用十次」的策略可能無法奏效。

如果我們將正則化係數降低到0.05,會怎麼樣?

我們看到了好兆頭——曲線逐漸收斂,如果我們移動到更右,也就是加入更多數據,我們可以進一步改善模型在驗證集上的表現。

plot_learning_curve(degree=2, alpha=0.05)

如果我們把alpha設為10-4,讓模型更複雜,會出現什麼情況?

我們看到了過擬合——在訓練集和驗證集上,AUC都下降了。

plot_learning_curve(degree=2, alpha=1e-4)

構建這些曲線可以幫助我們理解朝哪個方向走,如何恰當地為新數據調整模型複雜度。

學習曲線和驗證曲線的一些結論:

訓練集上的誤差本身不能說明模型的質量。

交叉驗證誤差顯示了模型對數據擬合得有多好(數據的現有趨勢)同時保留了多少對新數據的概括能力。

驗證曲線是一個根據模型複雜度顯示訓練集和驗證集上的結果的圖形:

學習曲線是一個根據觀測數量顯示訓練集和驗證集上的結果的圖形:

Kaggle競賽頁面:

https://www.kaggle.com/c/catch-me-if-you-can-intruder-detection-through-webpage-session-tracking2

我們將解決一個入侵者檢測問題(通過分析上網用戶的行為)。這是一個結合了數據分析和行為心理學的複雜而有趣的問題。例如,Yandex根據用戶的行為模式解決郵箱入侵檢測問題。概括起來,入侵者的行為模式可能和郵箱所有者不一樣:

所以我們可以檢測到入侵者,將其扔出郵箱,要求通過簡訊驗證碼認證身份。

Google Analytics研發了類似的技術,並發表了相應的論文。你可以通過搜索「Traversal Pattern Mining」(遍歷模式挖掘)和「Sequential Pattern Mining」(序列模式挖掘)了解更多關於這一主題的信息。

在這一競賽中,我們將解決一個類似的問題:我們的算法將分析特定用戶頻繁訪問的網站序列,預測這個人是不是一個名為Alice的用戶還是一個入侵者(其他人)。我們將使用ROC-AUC作為指標。

數據下載和轉換

如果你之前沒有註冊過Kaggle帳號的話,註冊一下。然後到競賽頁面,下載數據。

首先,加載訓練集和測試集。探索下數據:

%matplotlib inline

from matplotlib import pyplot as plt

import seaborn as sns

import pickle

import numpy as np

import pandas as pd

from scipy.sparse import csr_matrix

from scipy.sparse import hstack

from sklearn.preprocessing import StandardScaler

from sklearn.metrics import roc_auc_score

from sklearn.linear_model import LogisticRegression

# 加載訓練集和測試集

train_df = pd.read_csv('../../data/websites_train_sessions.csv',

                      index_col='session_id')

test_df = pd.read_csv('../../data/websites_test_sessions.csv',

                     index_col='session_id')

# 轉換time1、……、time10列至datetime類

times = ['time%s' % i for i in range(1, 11)]

train_df[times] = train_df[times].apply(pd.to_datetime)

test_df[times] = test_df[times].apply(pd.to_datetime)

# 據時間排序數據

train_df = train_df.sort_values(by='time1')

# 查看下訓練集的開始幾行

train_df.head()

訓練集包含以下特徵:

用戶會話的選取方式保證這些會話不超過半小時或包含超過十個網站,也就是說,一旦一個用戶訪問過了十個網站,或者會話時長超過了半小時,我們就認為這一會話結束了。

表中有一些空值,意味著某些會話包含不到十個網站。將這些空值替換為0,並將列類型改為整數。同時,加載網站字典,看看是什麼樣的:

# 將site1、……、site10列類型轉為整數,同時用零填充NA值

sites = ['site%s' % i for i in range(1, 11)]

train_df[sites] = train_df[sites].fillna(0).astype('int')

test_df[sites] = test_df[sites].fillna(0).astype('int')

# 加載網站字典

with open(r"../../data/site_dic.pkl", "rb") as input_file:

   site_dict = pickle.load(input_file)

# 創建字典的dataframe

sites_dict = pd.DataFrame(list(site_dict.keys()),

                         index=list(site_dict.values()), columns=['site'])

print(u'Websites total:', sites_dict.shape[0])

sites_dict.head()

# Websites total: 48371

簡單起見,我們將只使用會話中訪問的站點(不考慮訪問時長)。這一數據選擇背後的依據是:Alice有她偏愛的站點,我們在會話中看到更多這些站點,這一會話是Alice的會話的可能性就越高,反之亦然。

讓我們準備下數據。首先,我們從訓練集中排除目標變量,這樣,訓練集和測試集就有了相同數量的列,我們可以將其合併為一個dataframe,對其一併進行轉換。

# 目標變量

y_train = train_df['target']

# 合併為一個dataframe

full_df = pd.concat([train_df.drop('target', axis=1), test_df])

# 分割訓練集和測試集的索引

idx_split = train_df.shape[0]

只保留dataframe的site1, site2, ..., site10。

# 訪問過的網站索引構成的dataframe

full_sites = full_df[sites]

full_sites.head()

會話是網站索引的序列,這一數據表示不便於通過線性方法處理。我們需要將其轉換為如下表示形式:每個網站對應一個特徵(列),其值為會話中訪問該網站的次數。

# 索引序列

sites_flatten = full_sites.values.flatten()

# 我們想要的矩陣

full_sites_sparse = csr_matrix(([1] * sites_flatten.shape[0],

                               sites_flatten,

                               range(0, sites_flatten.shape[0] + 10, 10)))[:, 1:]

如果你明白剛剛發生了什麼,那你可以直接跳到下一節(也許你也可以處理邏輯回歸?),否則,讓我們一起來搞明白髮生了什麼。

稀疏矩陣

讓我們估計一下,在上面的例子中,儲存我們的數據需要多少內存。合併後的dataframe包含336k樣本,每個樣本包含48k整數特徵。因此我們大致需要的內存為:

336K * 48K * 8 bytes = 16G * 8 Bytes = 128 GB

顯然,凡夫俗子沒有這麼多內存(嚴格來說,Python可能允許你創建這樣一個矩陣,但對其進行任何操作都不容易)。一個有趣的事實是,我們的矩陣的大多數元素值為零。如果我們計算非零元素,那麼大概有一百八十萬,所佔比例略高於所有矩陣元素的0.01%. 這樣一種大多數元素為零的矩陣,稱為稀疏矩陣,零元素數量和總元素的比例則稱為矩陣的稀疏度。

scipy.sparse庫可用於處理稀疏矩陣,參考它的文檔了解稀疏矩陣的類型,如何處理,何時使用稀疏矩陣最高效。注意,稀疏矩陣只包含非零元素。最後,讓我們看看稀疏矩陣佔用的內存大小(顯然,稀疏矩陣顯著節省了內存):

# 稀疏矩陣佔用多少內存?

print('{0} elements * {1} bytes = {2} bytes'.

     format(full_sites_sparse.count_nonzero(), 8,

full_sites_sparse.count_nonzero() * 8))

# 或者直接:

print('sparse_matrix_size = {0} bytes'.

     format(full_sites_sparse.data.nbytes))

1866898 elements * 8 bytes = 14935184 bytes

sparse_matrix_size = 14935184 bytes

讓我們通過一個迷你的例子探索下這一矩陣是如何形成的。假設我們的用戶會話表是這樣的:

總共有3個會話,每次會話不超過3個站點。用戶訪問的不同站點總數為4(表中的1到4表示這4個站點)。讓我們假定這4個站點是:

vk.com

habrahabr.ru

yandex.ru

ods.ai

如果用戶在會話時訪問了不到三個站點,後面的值將為零。我們想要將原dataframe轉換為每個會話顯示某一特定站點的訪問數,如下表所示:

為此,我們使用csr_matrix ((data, indices, indptr))創建一個頻率表。這裡,我們顯式地設定所有參數,讓你能更清楚地理解這一過程:

# 創建由1組成的列表,長度等於原dataframe中元素的數量(9)

data = [1] * 9

# 網站id

indices = [1, 0, 0, 1, 3, 1, 2, 3, 4]

# 切分行(會話)的索引

indptr = [0, 3, 6, 9]

# 將上述三個變量聚合為一個元組,然後構建矩陣

# 顯示矩陣時,將其轉為通常的「密集」矩陣

csr_matrix((data, indices, indptr)).todense()

matrix([[2, 1, 0, 0, 0],

         [0, 2, 0, 1, 0],

         [0, 0, 1, 1, 1]])

你也許注意到了,所得矩陣的列數目不是四(不同網站的總數),而是五。第零列是額外增加的列,顯示每次會話少訪問了幾個站點(在我們的迷你例子中,會話的長度為3)。這一列是多餘的,需要從dataframe中移除。

使用稀疏矩陣的另一個好處是,有為其特製的矩陣操作和機器學習算法實現,有時能通過利用數據結構的特點顯著加速操作。邏輯回歸也適用。現在,萬事俱備,我們可以創建第一個模型了。

訓練第一個模型

我們將使用sklearn的邏輯回歸實現(默認參數)。數據集的前90%用於訓練(數據集按時間排序),剩餘10%用於驗證。

def get_auc_lr_valid(X, y, C=1.0, seed=17, ratio = 0.9):

   # 將數據分為訓練集和驗證集

   idx = int(round(X.shape[0] * ratio))

   # 訓練分類器

   lr = LogisticRegression(C=C, random_state=seed,

                           solver='lbfgs', n_jobs=-1).fit(X[:idx, :], y[:idx])

   # 為驗證集做出預測

   y_pred = lr.predict_proba(X[idx:, :])[:, 1]

   # 計算質量

   score = roc_auc_score(y[idx:], y_pred)

   return score

%%time

# 選擇訓練集

X_train = full_sites_sparse[:idx_split, :]

# 在驗證集上計算量度

print(get_auc_lr_valid(X_train, y_train))

0.9198622553850315

CPU times: user 138 ms, sys: 77.1 ms, total: 216 ms

Wall time: 2.74 s

第一個模型在驗證集上的表現接近0.92 ROC-AUC。讓我們將其作為第一條基線(作為一個開始)。為了在測試集上進行預測,我們需要在整個訓練集上再次訓練模型(到此為止,我們的模型只使用了數據的一部分進行訓練),這將增加模型的概括能力:

# 將預測寫入文件的函數

def write_to_submission_file(predicted_labels, out_file,

                            target='target', index_label="session_id"):

   predicted_df = pd.DataFrame(predicted_labels,

                               index = np.arange(1,

                                                 predicted_labels.shape[0] + 1),

                               columns=[target])

   predicted_df.to_csv(out_file, index_label=index_label)

# 在整個訓練數據集上訓練模型

# 為了可重複性,將random_state設為17

# 顯式設置C=1(這是默認值)

lr = LogisticRegression(C=1.0, solver='lbfgs',

                       random_state=17).fit(X_train, y_train)

# 在測試數據集上進行預測

X_test = full_sites_sparse[idx_split:,:]

y_test = lr.predict_proba(X_test)[:, 1]

# 寫入預測結果至提交文件

write_to_submission_file(y_test, 'baseline_1.csv')

如果你遵循這些步驟,並將答案上傳到競賽頁面,你將在公開排行榜上取得ROC AUC = 0.91707的成績。

你的任務是通過特徵工程、特徵縮放和正則化進一步改善模型。你將首先嘗試添加一些明顯的特徵(比如瀏覽網站的時刻,會話中的網站數目,等等)。我們鼓勵你在課程的學習過程中嘗試新的想法和模型,並參與競賽——這很有趣!

截止日期:March 11, 23:59 CET

I. Goodfellow、Y. Bengio、A. Courville所著《Deep Learning》(深度學習)一書提供了緊湊而出色的線性模型綜述。

基本上每本ML教材都涉及線性模型。我們推薦C. Bishop的《Pattern Recognition and Machine Learning》和K. Murphy的《Machine Learning: A Probabilistic Perspective》。

如果你打算從統計學的視角概覽線性模型,可以看下T. Hastie、R. Tibshirani、J. Friedman的《The elements of statistical learning》。

P. Harrington的《Machine Learning in Action》將引導你完全使用Python實現經典ML算法。

scikit-learn庫。scikit-learn的開發者致力於編寫極為清晰的文檔。

Scipy 2017 scikit-learn教程(Alex Gramfort、Andreas Mueller)。

MTH594課程 Advanced data mining: theory and applications包含很多非常好的材料。

GitHub倉庫rushter/MLAlgorithms裡有許多ML算法的實現,其中包括線性回歸和邏輯回歸。

歡迎留言分享其他資源。

原文地址:https://medium.com/open-machine-learning-course/open-machine-learning-course-topic-4-linear-classification-and-regression-44a41b9b5220

相關焦點

  • 數據科學&機器學習的筆記1:分類、線性回歸和邏輯回歸
    這課兩周內把前四章基礎的東西講完了,數據導入和簡單數據預處理之類的,比我想像中快,我還比較期待後面能學到新東西。第五章開了個頭,講的是「選擇和評價模型」,大抵是介紹機器學習中的常用模型,分清遇到不同數據分析需求時適用的模型。令我失望的是,真的真的只是講了一下模型的種類,告訴你模型可以用來做什麼,連一點點原理都沒有涉及。
  • python機器學習--線性回歸
    python機器學習--線性回歸線性回歸是最簡單的機器學習模型,其形式簡單,易於實現,同時也是很多機器學習模型的基礎。對於一個給定的訓練集數據,線性回歸的目的就是找到一個與這些數據最吻合的線性函數。針對線性回歸算法在之前的數模案例也有涉及喔,歡迎去看看上一篇博客數學建模預測模型實例--大學生體測數據模型在這裡插入圖片描述OLS線性回歸Ordinary Least Squares 最小二乘法一般情況下,線性回歸假設模型為下,其中w為模型參數
  • 機器學習 | 線性回歸大家族Part1
    目前,機器學習在疾病的鑑別診斷,藥物的生產研究,臨床試驗研究,放射影像學等醫學領域已有十分廣泛的應用。今天推出機器學習系列筆記第20期,本期分享內容為:機器學習之線性回歸大家族Part1。(筆者使用的是Windows系統)sklearn中的線性回歸大家族1 概述1.1 線性回歸大家族 回歸是一種應用廣泛的預測建模技術,這種技術的核心在於預測的結果是連續型變量。決策樹,隨機森林,支持向量機的分類器等分類算法的預測標籤是分類變量,多以{0,1}來表示,而無監督學習算法比如PCA,KMeans並不求解標籤,注意加以區別。
  • 機器學習套路:線性回歸
    (點擊上方藍字,快速關注我們)轉自:sharkdtuhttp://sharkdtu.com/posts/ml-linear-regression.html好文投稿, 請點擊 → 這裡了解詳情線性回歸可以說是機器學習中最簡單
  • 入門機器學習之線性回歸
    最常用的回歸方法如下:1、Linear Regression線性回歸:它是最為人熟知的建模技術之一。線性回歸通常是人們在學習預測模型時首選的技術之一。在這種技術中,因變量是連續的,自變量可以是連續的也可以是離散的,回歸線的性質是線性的。線性回歸使用最佳的擬合直線(也就是回歸線)在因變量(Y)和一個或多個自變量(X)之間建立一種關係。
  • Python 機器學習:多元線性回歸
    公眾號: datayx接著上一次的一元線性回歸python機器學習:線性回歸往下講,這篇文章要講解的多元線性回歸。1、什麼是多元線性回歸模型?當y值的影響因素不唯一時,採用多元線性回歸模型。例如商品的銷售額可能不電視廣告投入,收音機廣告投入,報紙廣告投入有關係,可以有 sales =β0+β1*TV+β2* radio+β3*newspaper.
  • 文科生都能看懂的機器學習教程:梯度下降、線性回歸、邏輯回歸
    本文試圖將機器學習這本深奧的課程,以更加淺顯易懂的方式講出來,讓沒有理科背景的讀者都能看懂。  把複雜的東西簡單化,讓非專業人士也能短時間內理解,並露出恍然大悟的表情,是一項非常厲害的技能。  舉個例子。你正在應聘機器學習工程師,面對的是文科出身的HR,如果能在最短時間內讓她了解你的專業能力,就能極大地提升面試成功率。
  • 機器學習基本概念-維度災難和線性回歸
    KNN分類器結構簡單,只要有良好的距離度量和足夠的標記訓練數據,就可以很好地工作,然而,KNN分類器的主要問題是它們不能很好地處理高維輸入。為了解釋維度災難,我們給出了一些來自(Hastie et al. 2009, p22)的例子。考慮將KNN分類器應用於輸入為均勻分布在d維單位立方體中的數據。
  • sklearn機器學習心得—線性回歸|粉絲投稿1
    ,也是重要的算法之一,基本上第一次接觸的機器學習算法就是線性回歸了。因為相對其他算法而言,我覺得線性回歸是相對比較容易的算法,從某種意義上來說,在學習函數的時候已經開始接觸線性回歸了,只不過那個時候並沒有涉及到誤差項,其實在中學的時候就有接觸了,學習的最小二乘法就是啦~~1).對於坐標系中給定的點,我們希望用一條線或是一個類似於:f(x)=θ0+θ1*x1+θ2*x2_...θn*xn 方程來擬合這寫數據點,這就是我們說的回歸了2).這次我們要用的是
  • 廣義線性模型與邏輯回歸
    分類問題是機器學習中常見的一種方法,本文將以二分類為切入點,引出邏輯回歸模型。
  • 線性模型(一)普通線性回歸到廣義線性模型
    普通線性回歸線性回歸線性模型如何解決非線性問題建模方法論背景線性模型為什麼能解決非線性問題。本章將帶領讀者從普通的線性回歸自然遷移到廣義線性模型中常用的邏輯回歸模型(包含正則的邏輯回歸)和金融領域的評分卡模型,從而形成線性模型的知識體系。
  • 初學TensorFlow機器學習:如何實現線性回歸?(附練習題)
    Nishant Shukla 一直以來兼任 Microsoft、Facebook 和 Foursquare 的開發者,以及 SpaceX 的機器學習工程師。他還是《Haskell Data Analysis Cookbook》的作者。TensorFlow 入門級文章:還記得你小學時學習的科學課程嗎?
  • 機器學習算法實踐:標準與局部加權線性回歸
    ,與分類的目標變量是標稱型不同,回歸是對連續型數據進預測。當然還是從最簡單的線性回歸開始,本文主要介紹無偏差的標準線性回歸和有偏局部加權線性回歸的理論基礎以及相應的Python實現。標準線性回歸標準線性回歸的理論知識很簡單,我們既可以寫出它的標量表達式也可以寫成矩陣的形式,其中矩陣的形式也可以通過投影矩陣進行推到得到。本部分就對標準線性回歸的表達式進行下簡單的推導。
  • Python數據科學:線性回歸
    ②雙樣本t檢驗:一個二分分類變量與一個連續變量間的關係。③方差分析:一個多分類分類變量與一個連續變量間的關係。④卡方檢驗:一個二分分類變量或多分類分類變量與一個二分分類變量間的關係。本次介紹:線性回歸:多個連續變量與一個連續變量間的關係。其中線性回歸分為簡單線性回歸和多元線性回歸。/ 01 / 數據分析與數據挖掘資料庫:一個存儲數據的工具。
  • python線性回歸
    一.理論基礎1.回歸公式  對於單元的線性回歸,我們有:f(x) = kx + b 的方程(k代表權重,b代表截距)。
  • 機器學習算法——線性回歸算法介紹
    1 線性回歸模型簡介線性回歸,就是能夠用一個直線較為精確地描述數據之間的關係。這樣當出現新的數據的時候,就能夠預測出一個簡單的值。線性回歸中最常見的就是房價的問題。一直存在很多房屋面積和房價的數據,如下圖所示:在這種情況下,就可以利用線性回歸構造出一條直線來近似地描述放假與房屋面積之間的關係,從而就可以根據房屋面積推測出房價。2 線性回歸的函數模型通過線性回歸構造出來的函數一般稱之為了線性回歸模型。
  • 機器學習sklearn線性回歸
    回歸算法是機器學習的一個基礎算法,簡單的就是線性回歸,還有非線性回歸。本節我們講解簡單的線性回歸。
  • 【深度】機器學習進化史:從線性模型到神經網絡
    說說你在斯坦福的工作吧在史丹福大學,我設計並教授分布式算法和優化,此外我還教授一門離散數學和算法的課程。在離散數學課程裡,我是完全從理論角度來教算法的,這意味著我所教授的算法完全不依賴於任何程式語言或框架,我們會直接把許多理論和證明寫在白板上。
  • 各種線性回歸
    一.sklearn中的各種線性回歸1,普通線性回歸
  • R數據分析:一般線性回歸的做法和解釋
    發現大家做分析做的最多的還是線性回歸,很多人諮詢的都是線性回歸的問題,今天專門出一個線性回歸的文章。