注:該文是上了開智學堂數據科學入門班的課後作的筆記,主講人是肖凱老師。html
機器學習、統計模型和數據挖掘有什麼異同?python
機器學習和統計模型區別不是很大,機器學習和統計模型中的迴歸都同樣,底層算法都是差很少的,只是側重點不同,在統計學的角度,迴歸主要解決的問題側重點在於模型的解釋能力,關注的是 x 和 y 之間的關係,關注的更可能是係數,從機器學習的角度看,關注的重點是預測的準確性。算法
機器學習和數據挖掘也沒什麼不同,二者的算法基本上是同樣的,只是在一些流程步驟上,數據挖掘會有一些特徵工程的工做,以及對具體應用問題的解釋。api
有監督學習和無監督學習有什麼區別?dom
有監督學習就是指有 y 做爲數據的一部分,被稱爲目標變量,或被解釋變量。無監督學習是指一堆數據,沒有特定的 y,要從一堆 x 裏找到模式或者規律出來。機器學習
有監督學習能夠分爲兩個子類:分類和迴歸。分類問題中要預測的 y 偏離散,好比性別、血型;迴歸問題 y 都是連續的,實數域中的,好比收入、天氣。ide
分類問題和聚類問題有什麼區別?學習
分類問題是預測一個未知類別的對象屬於哪一個類別,而聚類是根據選定的指標,對一羣對象進行劃分,它不屬於預測問題。測試
交叉驗證是什麼?ui
交叉驗證是指用來創建模型的數據,和最後用來模型驗證的數據,是不同的。實踐中拿到數據後,應該分爲幾個部分,最簡單的分爲兩部分,一部分用於訓練模型,另一部分用於檢驗模型,這就是交叉驗證。
什麼時候用到特徵工程?
特徵工程是指要把原始數據作些整理,作些轉換,主要目的是暴露出預測 y 的信息。
如何加載 sklearn 的內置數據集?
from sklearn import datasets from sklearn import cross_validation from sklearn import linear_model from sklearn import metrics from sklearn import tree from sklearn import neighbors from sklearn import svm from sklearn import ensemble from sklearn import cluster
%matplotlib inline import matplotlib.pyplot as plt
import numpy as np import seaborn as sns
skearn 有不少內置的數據集,上面已經加載了 sklearn 的 datasets,datasets 有一些能夠用的數據,好比說加載 boston 數據集,加載後返回的就是個數據字典。
boston = datasets.load_boston() print boston.keys()
['data', 'feature_names', 'DESCR', 'target']
數據集的大小/格式/類型等信息如何得知?
print boston.DESCR
Boston House Prices dataset Notes ------ Data Set Characteristics: :Number of Instances: 506 :Number of Attributes: 13 numeric/categorical predictive :Median Value (attribute 14) is usually the target :Attribute Information (in order): - CRIM per capita crime rate by town - ZN proportion of residential land zoned for lots over 25,000 sq.ft. - INDUS proportion of non-retail business acres per town - CHAS Charles River dummy variable (= 1 if tract bounds river; 0 otherwise) - NOX nitric oxides concentration (parts per 10 million) - RM average number of rooms per dwelling - AGE proportion of owner-occupied units built prior to 1940 - DIS weighted distances to five Boston employment centres - RAD index of accessibility to radial highways - TAX full-value property-tax rate per $10,000 - PTRATIO pupil-teacher ratio by town - B 1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town - LSTAT % lower status of the population - MEDV Median value of owner-occupied homes in $1000's :Missing Attribute Values: None :Creator: Harrison, D. and Rubinfeld, D.L. This is a copy of UCI ML housing dataset. http://archive.ics.uci.edu/ml/datasets/Housing This dataset was taken from the StatLib library which is maintained at Carnegie Mellon University. The Boston house-price data of Harrison, D. and Rubinfeld, D.L. 'Hedonic prices and the demand for clean air', J. Environ. Economics & Management, vol.5, 81-102, 1978. Used in Belsley, Kuh & Welsch, 'Regression diagnostics ...', Wiley, 1980. N.B. Various transformations are used in the table on pages 244-261 of the latter. The Boston house-price data has been used in many machine learning papers that address regression problems. **References** - Belsley, Kuh & Welsch, 'Regression diagnostics: Identifying Influential Data and Sources of Collinearity', Wiley, 1980. 244-261. - Quinlan,R. (1993). Combining Instance-Based and Model-Based Learning. In Proceedings on the Tenth International Conference of Machine Learning, 236-243, University of Massachusetts, Amherst. Morgan Kaufmann. - many more! (see http://archive.ics.uci.edu/ml/datasets/Housing)
boston.data # 自變量矩陣,面積、傢俱等特徵
array([[ 6.32000000e-03, 1.80000000e+01, 2.31000000e+00, ..., 1.53000000e+01, 3.96900000e+02, 4.98000000e+00], [ 2.73100000e-02, 0.00000000e+00, 7.07000000e+00, ..., 1.78000000e+01, 3.96900000e+02, 9.14000000e+00], [ 2.72900000e-02, 0.00000000e+00, 7.07000000e+00, ..., 1.78000000e+01, 3.92830000e+02, 4.03000000e+00], ..., [ 6.07600000e-02, 0.00000000e+00, 1.19300000e+01, ..., 2.10000000e+01, 3.96900000e+02, 5.64000000e+00], [ 1.09590000e-01, 0.00000000e+00, 1.19300000e+01, ..., 2.10000000e+01, 3.93450000e+02, 6.48000000e+00], [ 4.74100000e-02, 0.00000000e+00, 1.19300000e+01, ..., 2.10000000e+01, 3.96900000e+02, 7.88000000e+00]])
boston.data.shape
(506, 13)
boston.target.shape # 目標變量,房價
(506,)
datasets 除了現有的數據,還能夠造一些數據,經過人造數據,來研究不一樣算法的特色。
datasets.make_regression
<function sklearn.datasets.samples_generator.make_regression>
迴歸問題中,y 是個連續的數值,不只能夠採起線性迴歸,還可使用決策樹等作迴歸,只要輸出是連續值,均可以用迴歸模型。
sklearn 的迴歸和 statsmodel 中的迴歸有什麼異同?
若是使用一樣的模型,二者的迴歸的解都是同樣的,只是 statsmodel 輸出更多些,比較偏向對參數作更多的解釋,而 sklearn 更注重預測準確性。
如何使用交叉驗證?它和過擬合有什麼關係?
來個完整的例子。
np.random.seed(123) X_all, y_all = datasets.make_regression(n_samples=50, n_features=50, n_informative=10) # 真正有用的變量只有 10 個,另外 40 個都是噪音 print X_all.shape, y_all.shape
(50, 50) (50,)
這個數據集比較棘手,樣本數比較少,變量多,容易過擬合,並且有用的變量很少,有不少噪音在裏面,在作迴歸時,很容易把噪音放到方程裏,用傳統的方法比較難於處理,這裏用機器學習處理。
爲了防止過擬合,要用交叉驗證,把數據分爲兩部分,一部分用於訓練,一部分用於驗證。
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X_all, y_all, train_size=0.5) print X_train.shape, y_train.shape print X_test.shape, y_test.shape print type(X_train)
(25, 50) (25,) (25, 50) (25,) <type 'numpy.ndarray'>
如何以線性模型擬合數據集?
model = linear_model.LinearRegression() # 實例化 model.fit(X_train, y_train) # 作線性迴歸擬合數據
LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False)
殘差(residual)是什麼?如何評估模型是個好模型?
殘差是真實的 y 和預測的 y 的差,殘差越小,擬合越好。
def sse(resid): return sum(resid**2) # 殘差平方和,是迴歸效果的一個指標
殘差平方和是迴歸效果的一個指標,值越小,說明模型越好。
resid_train = y_train - model.predict(X_train) sse_train = sse(resid_train) print sse_train
5.87164948974e-25
resid_test = y_test - model.predict(X_test) sse_test = sse(resid_test) sse_test
194948.84691187815
model.score(X_train, y_train) # 計算斷定係數 R-squared
1.0
model.score(X_test, y_test)
0.26275088549060643
模型在測試集上的分數只有 0.26,效果並很差。
畫出各個樣本對應的殘差,和各個變量的係數。
def plot_residuals_and_coeff(resid_train, resid_test, coeff): fig, axes = plt.subplots(1, 3, figsize=(12, 3)) axes[0].bar(np.arange(len(resid_train)), resid_train) # 各個樣本對應的殘差 axes[0].set_xlabel("sample number") axes[0].set_ylabel("residual") axes[0].set_title("training data") axes[1].bar(np.arange(len(resid_test)), resid_test) # 各個樣本對應的殘差 axes[1].set_xlabel("sample number") axes[1].set_ylabel("residual") axes[1].set_title("testing data") axes[2].bar(np.arange(len(coeff)), coeff) # 各個變量的係數 axes[2].set_xlabel("coefficient number") axes[2].set_ylabel("coefficient") fig.tight_layout() return fig, axes
fig, ax = plot_residuals_and_coeff(resid_train, resid_test, model.coef_); # 訓練集的殘差,測試集的殘差,各個係數的大小
能夠看到第一幅圖訓練集中的殘差不算大,範圍在 -3 到 5 之間,測試集的殘差就過大,範圍在 -150 到 250 之間,可見模型過擬合了,在訓練集上還行,測試集上就很糟糕。
真實變量裏只有 10 個是有用的,而上面的變量係數圖有不少都不是 0,有不少冗餘。變量多,樣本少,怎麼解決呢?
變量比樣本多時,如何處理?
一種方法是作個主成分分析,降維,對變量作個篩選,再放到模型裏來,但這種方法比較麻煩。
還有種是正則化的方法。
正則化是什麼?有哪兩種方法?
正則化在統計學裏有兩種思路,一種叫嶺迴歸,把係數放到 loss function 中,經典的 loss function 是殘差平方和,這裏把 50 個係數平方求和,放到 loss function 中,因此最終既要使殘差平方和小,又要使權重小,能夠壓制一些過於冗餘的權重。
model = linear_model.Ridge(alpha=5) # 參數 alpha 表示對於權重係數的決定因子 model.fit(X_train, y_train)
Ridge(alpha=5, copy_X=True, fit_intercept=True, max_iter=None, normalize=False, random_state=None, solver='auto', tol=0.001)
resid_train = y_train - model.predict(X_train) sse_train = sum(resid_train**2) print sse_train
2963.35374445
resid_test = y_test - model.predict(X_test) sse_test = sum(resid_test**2) print sse_test
187177.590437
殘差平方和還比較高。
model.score(X_train, y_train), model.score(X_test, y_test)
(0.99197132152011414, 0.29213988699168503)
以前測試集的 R 方是 0.26,這裏是 0.29,略有改善。
fig, ax = plot_residuals_and_coeff(resid_train, resid_test, model.coef_)
從圖上看,training 的殘差增長了,testing 的有所減小,係數大小沒有太多改善,因此在這裏使用嶺迴歸有一點點效果,並不明顯。
下面使用正則化的另外一種方法,稱爲 Lasso,思路跟嶺迴歸是同樣的,都是把殘差平方和以及係數放到 loss function 中,既要使殘差平方和小,又要使係數小,但 Losso 公式有點不同,Losso 是把權重的絕對值加起來,而嶺迴歸是把權重的方法加起來,有這麼一點不同,就可使得不少權重回爲 0。看小效果。
model = linear_model.Lasso(alpha=1.0) model.fit(X_train, y_train)
Lasso(alpha=1.0, copy_X=True, fit_intercept=True, max_iter=1000, normalize=False, positive=False, precompute=False, random_state=None, selection='cyclic', tol=0.0001, warm_start=False)
resid_train = y_train - model.predict(X_train) sse_train = sse(resid_train) print sse_train
256.539066413
resid_test = y_test - model.predict(X_test) sse_test = sse(resid_test) print sse_test
691.523154567
fig, ax = plot_residuals_and_coeff(resid_train, resid_test, model.coef_)
testing 的殘差有明顯的減少,範圍減少到 -10 到 15 之間。不少係數也變爲 0,真正的起做用的只有少數幾個。這是 lasso 的優勢,它能夠應付有不少噪音的狀況,對於維度比較高噪音比較多的狀況,lasso 能夠在建模的同時作降維。
alphas = np.logspace(-4, 2, 100) # 嘗試 100 個不一樣的 alpha
coeffs = np.zeros((len(alphas), X_train.shape[1])) sse_train = np.zeros_like(alphas) sse_test = np.zeros_like(alphas) for n, alpha in enumerate(alphas): model = linear_model.Lasso(alpha=alpha) model.fit(X_train, y_train) coeffs[n, :] = model.coef_ resid = y_train - model.predict(X_train) sse_train[n] = sum(resid**2) resid = y_test - model.predict(X_test) sse_test[n] = sum(resid**2)
fig, axes = plt.subplots(1, 2, figsize=(12, 4), sharex=True) for n in range(coeffs.shape[1]): axes[0].plot(np.log10(alphas), coeffs[:, n], color='k', lw=0.5) axes[1].semilogy(np.log10(alphas), sse_train, label="train") axes[1].semilogy(np.log10(alphas), sse_test, label="test") axes[1].legend(loc=0) axes[0].set_xlabel(r"${\log_{10}}\alpha$", fontsize=18) axes[0].set_ylabel(r"coefficients", fontsize=18) axes[1].set_xlabel(r"${\log_{10}}\alpha$", fontsize=18) axes[1].set_ylabel(r"sse", fontsize=18) fig.tight_layout()
alpha 爲 0 時,表示沒有在 loss function 中放權重項,即沒有懲罰,這時作迴歸,跟前面結果是同樣的。
alpha 增大,不少噪音的因子就會降爲 0,即對變量作篩選。
咱們的目標是要使模型的預測效果最佳,天然要選擇測試集上殘差平方和最小的地方所對應的 alpha。
怎麼求這個點,實際用時用 LassoCV 自動找出最好的 alpha。
model = linear_model.LassoCV() # 能夠去嘗試不一樣的參數值
model.fit(X_all, y_all)
LassoCV(alphas=None, copy_X=True, cv=None, eps=0.001, fit_intercept=True, max_iter=1000, n_alphas=100, n_jobs=1, normalize=False, positive=False, precompute='auto', random_state=None, selection='cyclic', tol=0.0001, verbose=False)
model.alpha_ # 自動找出最好的 alpha
0.06559238747534718
resid_train = y_train - model.predict(X_train) sse_train = sse(resid_train) print sse_train
1.76481994041
resid_test = y_test - model.predict(X_test) sse_test = sse(resid_test) print sse_test
1.31238073253
效果很是不錯。
model.score(X_train, y_train), model.score(X_test, y_test)
(0.9999952185351132, 0.99999503689532787)
fig, ax = plot_residuals_and_coeff(resid_train, resid_test, model.coef_)
training 和 testing 的殘差都比較小,無關變量的係數都被壓到 0。效果很是好。
分類問題和迴歸問題有什麼區別?
分類的目標和迴歸不同,雖然都是作預測,迴歸的 y 是連續的數值,分類預測的 y 是離散的數值,好比預測明天會不會下雨,就有會下雨和不會下雨兩種狀況,這是二元分類問題,編碼時可編爲 0 和 1 兩種狀況,還有是判斷一個圖形是什麼阿拉伯數字,多是 0,1,...,9,有 10 個可能的分類,是多元分類問題。
以前用的 statsmodels 的 logistic 迴歸就是分類模型,這裏用 sklearn 中更多的分類模型。
sklearn 內有哪些分類模型?
廣義線性模型
支持向量機
最近鄰
樸素貝葉斯
決策樹
iris = datasets.load_iris() # 載入鳶尾花數據集
print iris.target_names print iris.feature_names
['setosa' 'versicolor' 'virginica'] ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
print iris.data.shape print iris.target.shape
(150, 4) (150,)
X_train, X_test, y_train, y_test = cross_validation.train_test_split(iris.data, iris.target, train_size=0.7) # 70% 用於訓練,30% 用於檢驗
classifier = linear_model.LogisticRegression() classifier.fit(X_train, y_train)
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1, penalty='l2', random_state=None, solver='liblinear', tol=0.0001, verbose=0, warm_start=False)
y_test_pred = classifier.predict(X_test)
如何評估分類效果?confusion matrix 是什麼?
用 metrics 模塊來檢查模型效果,其中的 classification_report 是分類報告,顯示各類指標,來衡量模型的效果。
print(metrics.classification_report(y_test, y_test_pred)) # 真實的 y 和預測的 y
precision recall f1-score support 0 1.00 1.00 1.00 15 1 1.00 0.75 0.86 16 2 0.78 1.00 0.88 14 avg / total 0.93 0.91 0.91 45
precision 是精準度,recall 是召回率,fs-score 是 F1 值。從這幾個值能夠看到模型很完美。
還能夠用混淆矩陣 confusion matrix 來評估分類器。混淆矩陣的每一列表明瞭預測類別,每一列的總數表示預測爲該類別的數據的數目;每一行表明了數據的真實歸屬類別,每一行的數據總數表示該類別的數據實例的數目。每一列中的數值表示真實數據被預測爲該類的數。若是混淆矩陣的全部數據都在對角線上,就說明預測是徹底正確的。
metrics.confusion_matrix(y_test, y_test_pred)
array([[15, 0, 0], [ 0, 12, 4], [ 0, 0, 14]])
y_test.shape
(45,)
classifier = tree.DecisionTreeClassifier() # 決策樹 classifier.fit(X_train, y_train) y_test_pred = classifier.predict(X_test) metrics.confusion_matrix(y_test, y_test_pred)
array([[12, 0, 0], [ 0, 13, 2], [ 0, 2, 16]])
classifier = neighbors.KNeighborsClassifier() # K 近鄰 classifier.fit(X_train, y_train) y_test_pred = classifier.predict(X_test) metrics.confusion_matrix(y_test, y_test_pred)
array([[12, 0, 0], [ 0, 14, 1], [ 0, 2, 16]])
classifier = svm.SVC() # 支持向量機 classifier.fit(X_train, y_train) y_test_pred = classifier.predict(X_test) metrics.confusion_matrix(y_test, y_test_pred)
array([[12, 0, 0], [ 0, 15, 0], [ 0, 3, 15]])
classifier = ensemble.RandomForestClassifier() classifier.fit(X_train, y_train) y_test_pred = classifier.predict(X_test) metrics.confusion_matrix(y_test, y_test_pred)
array([[12, 0, 0], [ 0, 14, 1], [ 0, 2, 16]])
train_size_vec = np.linspace(0.1, 0.9, 30) # 嘗試不一樣的樣本大小
classifiers = [tree.DecisionTreeClassifier, neighbors.KNeighborsClassifier, svm.SVC, ensemble.RandomForestClassifier ]
cm_diags = np.zeros((3, len(train_size_vec), len(classifiers)), dtype=float) # 用來放結果
for n, train_size in enumerate(train_size_vec): X_train, X_test, y_train, y_test = \ cross_validation.train_test_split(iris.data, iris.target, train_size=train_size) for m, Classifier in enumerate(classifiers): classifier = Classifier() classifier.fit(X_train, y_train) y_test_pred = classifier.predict(X_test) cm_diags[:, n, m] = metrics.confusion_matrix(y_test, y_test_pred).diagonal() cm_diags[:, n, m] /= np.bincount(y_test)
fig, axes = plt.subplots(1, len(classifiers), figsize=(12, 3)) for m, Classifier in enumerate(classifiers): axes[m].plot(train_size_vec, cm_diags[2, :, m], label=iris.target_names[2]) axes[m].plot(train_size_vec, cm_diags[1, :, m], label=iris.target_names[1]) axes[m].plot(train_size_vec, cm_diags[0, :, m], label=iris.target_names[0]) axes[m].set_title(type(Classifier()).__name__) axes[m].set_ylim(0, 1.1) axes[m].set_xlim(0.1, 0.9) axes[m].set_ylabel("classification accuracy") axes[m].set_xlabel("training size ratio") axes[m].legend(loc=4) fig.tight_layout()
樣本大小對預測分類結果有影響嗎?
從上圖可看出,當樣本過小時,有些模型會表現不好,好比決策樹、K 最近鄰 和SVC,KNN 和 SVM 是比較依賴數據規模的。當 train size 變大後,分類準確率就比較高了。
聚類是一種無監督學習方法。
聚類問題的應用場景是什麼?
主要解決把一羣對象劃分爲若干個組的問題。例如用戶細分:選擇若干指標把用戶羣聚爲若干個組,組內特徵相似,組件特徵差別明顯。
應用最普遍的聚類方法是什麼?
K-means 聚類。
X, y = iris.data, iris.target np.random.seed(123) n_clusters = 3 # 能夠嘗試其它值 c = cluster.KMeans(n_clusters=n_clusters) # 實例化 c.fit(X) # 這裏的 fit 沒有 y
KMeans(copy_x=True, init='k-means++', max_iter=300, n_clusters=3, n_init=10, n_jobs=1, precompute_distances='auto', random_state=None, tol=0.0001, verbose=0)
y_pred = c.predict(X) print y_pred[::8] print y[::8]
[1 1 1 1 1 1 1 2 2 2 2 2 2 0 0 0 0 0 0] [0 0 0 0 0 0 0 1 1 1 1 1 1 2 2 2 2 2 2]
聚類結果是 一、二、0,真實結果是 0、一、2。爲了跟真實值作比對,須要作個轉換。
idx_0, idx_1, idx_2 = (np.where(y_pred == n) for n in range(3)) # 作轉換 y_pred[idx_0], y_pred[idx_1], y_pred[idx_2] = 2, 0, 1 print y_pred[::8] print y[::8]
[0 0 0 0 0 0 0 1 1 1 1 1 1 2 2 2 2 2 2] [0 0 0 0 0 0 0 1 1 1 1 1 1 2 2 2 2 2 2]
print metrics.confusion_matrix(y, y_pred) # 固然在實際場景中是不可能有混淆矩陣的,由於根本就沒有真實的 y
[[50 0 0] [ 0 48 2] [ 0 14 36]]