diff --git a/.gitignore b/.gitignore index 994f47d..286df4a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ ## Dependency directory ## Commenting this out is preferred by some people, see ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git -node_modules +#node_modules # Book build output _book @@ -13,4 +13,4 @@ _book # eBook build output *.epub *.mobi -*.pdf \ No newline at end of file +*.pdf diff --git a/Classification/ex1_Recognizing_hand-written_digits.md b/Classification/ex1_Recognizing_hand-written_digits.md index 7d288a6..3b3d43b 100644 --- a/Classification/ex1_Recognizing_hand-written_digits.md +++ b/Classification/ex1_Recognizing_hand-written_digits.md @@ -1,3 +1,6 @@ ++ ##分類法/範例一: Recognizing hand-written digits http://scikit-learn.org/stable/auto_examples/classification/plot_digits_classification.html @@ -75,12 +78,12 @@ data = digits.images.reshape((n_samples, -1)) classifier = svm.SVC(gamma=0.001) # 用前半部份的資料來訓練 -classifier.fit(data[:n_samples / 2], digits.target[:n_samples / 2]) +classifier.fit(data[:n_samples // 2], digits.target[:n_samples // 2]) -expected = digits.target[n_samples / 2:] +expected = digits.target[n_samples // 2:] #利用後半部份的資料來測試分類器,共 899筆資料 -predicted = classifier.predict(data[n_samples / 2:]) +predicted = classifier.predict(data[n_samples // 2:]) ``` 若是觀察 `expected` 及 `predicted` 矩陣中之前10個變數可以得到: @@ -173,7 +176,7 @@ avg / total 0.97 0.97 0.97 899 ```python images_and_predictions = list( - zip(digits.images[n_samples / 2:], predicted)) + zip(digits.images[n_samples // 2:], predicted)) for index, (image, prediction) in enumerate(images_and_predictions[:4]): plt.subplot(2, 4, index + 5) plt.axis('off') @@ -205,12 +208,11 @@ from sklearn import datasets, svm, metrics # The digits dataset digits = datasets.load_digits() -# The data that we are interested in is made of 8x8 images of -# digits, let's # have a look at the first 3 images, stored in -# the `images` attribute of the # dataset. If we were working -# from image files, we could load them using # pylab.imread. -# Note that each image must have the same size. For these images, -#we know which digit they represent: it is given in the 'target' of +# The data that we are interested in is made of 8x8 images of digits, let's +# have a look at the first 4 images, stored in the `images` attribute of the +# dataset. If we were working from image files, we could load them using +# matplotlib.pyplot.imread. Note that each image must have the same size. For these +# images, we know which digit they represent: it is given in the 'target' of # the dataset. images_and_labels = list(zip(digits.images, digits.target)) for index, (image, label) in enumerate(images_and_labels[:4]): @@ -228,19 +230,17 @@ data = digits.images.reshape((n_samples, -1)) classifier = svm.SVC(gamma=0.001) # We learn the digits on the first half of the digits -classifier.fit(data[:n_samples / 2], digits.target[:n_samples / 2]) +classifier.fit(data[:n_samples // 2], digits.target[:n_samples // 2]) # Now predict the value of the digit on the second half: -expected = digits.target[n_samples / 2:] -predicted = classifier.predict(data[n_samples / 2:]) +expected = digits.target[n_samples // 2:] +predicted = classifier.predict(data[n_samples // 2:]) print("Classification report for classifier %s:\n%s\n" - % (classifier, metrics.classification_report(expected, predicted))) -print("Confusion matrix:\n%s" - % metrics.confusion_matrix(expected, predicted)) + % (classifier, metrics.classification_report(expected, predicted))) +print("Confusion matrix:\n%s" % metrics.confusion_matrix(expected, predicted)) -images_and_predictions = list( - zip(digits.images[n_samples / 2:], predicted)) +images_and_predictions = list(zip(digits.images[n_samples // 2:], predicted)) for index, (image, prediction) in enumerate(images_and_predictions[:4]): plt.subplot(2, 4, index + 5) plt.axis('off') diff --git a/Classification/ex2_normal_and_shrinkage_linear_discriminant_anal_.md b/Classification/ex2_normal_and_shrinkage_linear_discriminant_anal_.md index c8edc26..fc908af 100644 --- a/Classification/ex2_normal_and_shrinkage_linear_discriminant_anal_.md +++ b/Classification/ex2_normal_and_shrinkage_linear_discriminant_anal_.md @@ -1,7 +1,7 @@ ##分類法/範例二: Normal and Shrinkage Linear Discriminant Analysis for classification -http://scikit-learn.org/stable/auto_examples/classification/plot_digits_classification.html +http://scikit-learn.org/stable/auto_examples/classification/plot_lda.html 這個範例用來展示scikit-learn 如何使用Linear Discriminant Analysis (LDA) 線性判別分析來達成資料分類的目的 diff --git a/Classification/ex5_Linear_and_Quadratic_Discriminant_Analysis_with_confidence_ellipsoid.md b/Classification/ex5_Linear_and_Quadratic_Discriminant_Analysis_with_confidence_ellipsoid.md index a3c7267..df1581a 100644 --- a/Classification/ex5_Linear_and_Quadratic_Discriminant_Analysis_with_confidence_ellipsoid.md +++ b/Classification/ex5_Linear_and_Quadratic_Discriminant_Analysis_with_confidence_ellipsoid.md @@ -352,3 +352,13 @@ plt.show() ```python ``` + +## (一)引入函式庫 + +引入函式如下: + +1. numpy : 產生陣列數值 +2. matplotlib.pyplot : 用來繪製影像 +3. sklearn import datasets, cluster : datasets : 用來繪入內建之手寫數字資料庫 ; cluster : 其內收集非監督clustering演算法 +4. sklearn.feature_extraction.image import grid_to_graph : 定義資料的結構 + diff --git a/Classification/fork_from_sklearnweb/plot_classification_probability.py b/Classification/py_source/plot_classification_probability.py similarity index 100% rename from Classification/fork_from_sklearnweb/plot_classification_probability.py rename to Classification/py_source/plot_classification_probability.py diff --git a/Classification/fork_from_sklearnweb/plot_classifier_comparison.py b/Classification/py_source/plot_classifier_comparison.py similarity index 100% rename from Classification/fork_from_sklearnweb/plot_classifier_comparison.py rename to Classification/py_source/plot_classifier_comparison.py diff --git a/Classification/fork_from_sklearnweb/plot_digits_classification.py b/Classification/py_source/plot_digits_classification.py similarity index 100% rename from Classification/fork_from_sklearnweb/plot_digits_classification.py rename to Classification/py_source/plot_digits_classification.py diff --git a/Classification/fork_from_sklearnweb/plot_lda.py b/Classification/py_source/plot_lda.py similarity index 100% rename from Classification/fork_from_sklearnweb/plot_lda.py rename to Classification/py_source/plot_lda.py diff --git a/Classification/fork_from_sklearnweb/plot_lda_qda.py b/Classification/py_source/plot_lda_qda.py similarity index 100% rename from Classification/fork_from_sklearnweb/plot_lda_qda.py rename to Classification/py_source/plot_lda_qda.py diff --git a/Clustering/EX10_K-means_Clustering.md b/Clustering/EX10_K-means_Clustering.md new file mode 100644 index 0000000..ab37987 --- /dev/null +++ b/Clustering/EX10_K-means_Clustering.md @@ -0,0 +1,231 @@ +# **範例十:K-means Clustering** + +https://scikit-learn.org/stable/auto_examples/cluster/plot_cluster_iris.html#sphx-glr-auto-examples-cluster-plot-cluster-iris-py + +此範例顯示了K-means演算法使用不同數量cluster,以及不同初始值設定產生的結果 + +1. 利用 datasets.load_iris() 來讀取內建資料庫 +2. 利用 KMeans 做分類 +3. 利用 Axes3D 秀出結果 + + +## (一)引入函式庫 + +引入函式如下: + +1. numpy : 產生陣列數值 +2. matplotlib.pyplot : 用來繪製影像 +3. mpl_toolkits.mplot3d import Axes3D : 繪製3D圖形 +4. sklearn.cluster import KMeans : 切割cluster +5. sklearn import datasets : 用來匯入影像資料庫 + +```python +import numpy as np +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D +from sklearn.cluster import KMeans +from sklearn import datasets +``` + +```python +np.random.seed(5) +``` +隨機設定種子,可以用在 KMeans 裡 n_init 的參數 + +```python +iris = datasets.load_iris() +X = iris.data +y = iris.target +``` +iris = datasets.load_iris() : 將一個dict型別資料存入iris + +```python +for key,value in iris.items() : + try: + print (key,value.shape) + except: + print (key) +print(iris['feature_names']) +``` + +| 顯示 | 說明 | +| -- | -- | +| ('target_names', (3L,))| 共有三種鳶尾花 setosa, versicolor, virginica | +| ('data', (150L, 4L)) | 有150筆資料,共四種特徵 | +| ('target', (150L,))| 這150筆資料各是那一種鳶尾花| +| DESCR | 資料之描述 | +| feature_names| 四個特徵代表的意義,分別為 萼片(sepal)之長與寬以及花瓣(petal)之長與寬 + + +## (二)Clustering +```python +estimators = [('k_means_iris_8', KMeans(n_clusters=8)), + ('k_means_iris_3', KMeans(n_clusters=3)), + ('k_means_iris_bad_init', KMeans(n_clusters=3, n_init=1, + init='random'))] +``` +設定 KMeans 參數,各項參數設定如下: +* n_clusters : 需要計算出的群集數 +* init : 設定初始化方式 +* n_init : 使用不同 centroid seeds 運行 k-means 算法的時間 + +```python +fignum = 1 +titles = ['8 clusters', '3 clusters', '3 clusters, bad initialization'] +for name, est in estimators: + fig = plt.figure(fignum, figsize=(4, 3)) + ax = Axes3D(fig, rect=[0, 0, .95, 1], elev=48, azim=134) + est.fit(X) + labels = est.labels_ + + ax.scatter(X[:, 3], X[:, 0], X[:, 2], + c=labels.astype(np.float), edgecolor='k') + + ax.w_xaxis.set_ticklabels([]) + ax.w_yaxis.set_ticklabels([]) + ax.w_zaxis.set_ticklabels([]) + ax.set_xlabel('Petal width') + ax.set_ylabel('Sepal length') + ax.set_zlabel('Petal length') + ax.set_title(titles[fignum - 1]) + ax.dist = 12 + fignum = fignum + 1 +``` +Axes3D : 定義一個3D的圖形 +est.fit : 根據上面 estimators 去 fit 資料庫的圖 +ax.scatter : 畫散點圖,後面的參數用來調整顏色 +ax.dist : 設定與物體之間的距離 + + +![](https://github.com/kenny024241/machine-learning-python/blob/master/Clustering/ex10-1.png) ![](https://github.com/kenny024241/machine-learning-python/blob/master/Clustering/ex10-2.png) ![](https://github.com/kenny024241/machine-learning-python/blob/master/Clustering/ex10-3.png) + + +```python +fig = plt.figure(fignum, figsize=(4, 3)) +ax = Axes3D(fig, rect=[0, 0, .95, 1], elev=48, azim=134) + +for name, label in [('Setosa', 0), + ('Versicolour', 1), + ('Virginica', 2)]: + ax.text3D(X[y == label, 3].mean(), + X[y == label, 0].mean(), + X[y == label, 2].mean() + 2, name, + horizontalalignment='center', + bbox=dict(alpha=.2, edgecolor='w', facecolor='w')) +# Reorder the labels to have colors matching the cluster results +y = np.choose(y, [1, 2, 0]).astype(np.float) +ax.scatter(X[:, 3], X[:, 0], X[:, 2], c=y, edgecolor='k') + +ax.w_xaxis.set_ticklabels([]) +ax.w_yaxis.set_ticklabels([]) +ax.w_zaxis.set_ticklabels([]) +ax.set_xlabel('Petal width') +ax.set_ylabel('Sepal length') +ax.set_zlabel('Petal length') +ax.set_title('Ground Truth') +ax.dist = 12 + +fig.show() +``` +np.choose : 將原本 label 順序的(0 1 2)改成(1 2 0) +ax.text3D : 將不同label的資料標上個別物種類名稱,裡面 X[y == label, 3].mean() 用在調整 text 的 X Y Z 軸位置 + + +![](https://github.com/kenny024241/machine-learning-python/blob/master/Clustering/ex10-4.png) + + +## (三)完整程式碼 +Python source code:plot_cluster_iris.py + +https://scikit-learn.org/stable/_downloads/plot_cluster_iris.py +```python +""" +========================================================= +K-means Clustering +========================================================= + +The plots display firstly what a K-means algorithm would yield +using three clusters. It is then shown what the effect of a bad +initialization is on the classification process: +By setting n_init to only 1 (default is 10), the amount of +times that the algorithm will be run with different centroid +seeds is reduced. +The next plot displays what using eight clusters would deliver +and finally the ground truth. + +""" +print(__doc__) + + +# Code source: Gaël Varoquaux +# Modified for documentation by Jaques Grobler +# License: BSD 3 clause + +import numpy as np +import matplotlib.pyplot as plt +# Though the following import is not directly being used, it is required +# for 3D projection to work +from mpl_toolkits.mplot3d import Axes3D + +from sklearn.cluster import KMeans +from sklearn import datasets + +np.random.seed(5) + +iris = datasets.load_iris() +X = iris.data +y = iris.target + +estimators = [('k_means_iris_8', KMeans(n_clusters=8)), + ('k_means_iris_3', KMeans(n_clusters=3)), + ('k_means_iris_bad_init', KMeans(n_clusters=3, n_init=1, + init='random'))] + +fignum = 1 +titles = ['8 clusters', '3 clusters', '3 clusters, bad initialization'] +for name, est in estimators: + fig = plt.figure(fignum, figsize=(4, 3)) + ax = Axes3D(fig, rect=[0, 0, .95, 1], elev=48, azim=134) + est.fit(X) + labels = est.labels_ + + ax.scatter(X[:, 3], X[:, 0], X[:, 2], + c=labels.astype(np.float), edgecolor='k') + + ax.w_xaxis.set_ticklabels([]) + ax.w_yaxis.set_ticklabels([]) + ax.w_zaxis.set_ticklabels([]) + ax.set_xlabel('Petal width') + ax.set_ylabel('Sepal length') + ax.set_zlabel('Petal length') + ax.set_title(titles[fignum - 1]) + ax.dist = 12 + fignum = fignum + 1 + +# Plot the ground truth +fig = plt.figure(fignum, figsize=(4, 3)) +ax = Axes3D(fig, rect=[0, 0, .95, 1], elev=48, azim=134) + +for name, label in [('Setosa', 0), + ('Versicolour', 1), + ('Virginica', 2)]: + ax.text3D(X[y == label, 3].mean(), + X[y == label, 0].mean(), + X[y == label, 2].mean() + 2, name, + horizontalalignment='center', + bbox=dict(alpha=.2, edgecolor='w', facecolor='w')) +# Reorder the labels to have colors matching the cluster results +y = np.choose(y, [1, 2, 0]).astype(np.float) +ax.scatter(X[:, 3], X[:, 0], X[:, 2], c=y, edgecolor='k') + +ax.w_xaxis.set_ticklabels([]) +ax.w_yaxis.set_ticklabels([]) +ax.w_zaxis.set_ticklabels([]) +ax.set_xlabel('Petal width') +ax.set_ylabel('Sepal length') +ax.set_zlabel('Petal length') +ax.set_title('Ground Truth') +ax.dist = 12 + +fig.show() +``` diff --git a/EX12_spectral_clustering_for_image_segmentation.md b/Clustering/EX12_spectral_clustering_for_image_segmentation.md similarity index 100% rename from EX12_spectral_clustering_for_image_segmentation.md rename to Clustering/EX12_spectral_clustering_for_image_segmentation.md diff --git a/Clustering/EX1_Feature_agglomeration.md b/Clustering/EX1_Feature_agglomeration.md new file mode 100644 index 0000000..80afaa2 --- /dev/null +++ b/Clustering/EX1_Feature_agglomeration.md @@ -0,0 +1,173 @@ +# **範例一:Feature agglomeration** + +https://scikit-learn.org/stable/auto_examples/cluster/plot_digits_agglomeration.html#sphx-glr-auto-examples-cluster-plot-digits-agglomeration-py + +此範例是用FeatureAgglomeration來做特徵聚集 + +1. 利用 sklearn.datasets.load_digits() 來讀取內建資料庫 +2. 利用 FeatureAgglomeration : 將相似特徵聚集並降維,來減少特徵數量,避免特徵過多的問題 + + +## (一)引入函式庫 + +引入函式如下: + +1. numpy : 產生陣列數值 +2. matplotlib.pyplot : 用來繪製影像 +3. sklearn import datasets, cluster : datasets : 用來匯入內建之手寫數字資料庫 ; cluster : 其內收集非監督clustering演算法 +4. sklearn.feature_extraction.image import grid_to_graph : 定義資料的結構 + + +```python +import numpy as np +import matplotlib.pyplot as plt + +from sklearn import datasets, cluster +from sklearn.feature_extraction.image import grid_to_graph +``` + +```python +# The digits dataset +digits = datasets.load_digits() +images = digits.images +``` + +使用 datasets.load_digits() 將資料存入, digits 為一個dict型別資料,我們可以用以下指令來看一下資料的內容。 + +```python +for key,value in digits.items() : + try: + print (key,value.shape) + except: + print (key) +``` + +| 顯示 | 說明 | +| -- | -- | +| ('images', (1797L, 8L, 8L))| 共有 1797 張影像,影像大小為 8x8 | +| ('data', (1797L, 64L)) | data 則是將8x8的矩陣攤平成64個元素之一維向量 | +| ('target_names', (10L,)) | 說明10種分類之對應 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | +| DESCR | 資料之描述 | +| ('target', (1797L,))| 記錄1797張影像各自代表那一個數字 | + +```python +X = np.reshape(images, (len(images), -1)) +``` +將1797x8x8的圖片拉長,變成1797x64 + +## (二)特徵聚集 +```python +connectivity = grid_to_graph(*images[0].shape) + +agglo = cluster.FeatureAgglomeration(connectivity=connectivity, + n_clusters=32) + +agglo.fit(X) +``` +grid_to_graph : 做出像素連接的矩陣 +FeatureAgglomeration : 將相似特徵聚集並降維,來減少特徵數量 + +```python +X_reduced = agglo.transform(X) + +X_restored = agglo.inverse_transform(X_reduced) +``` +transform : 根據上面 n_clusters 的值做轉換,得出[n_samples, n_features_new]新的特徵值 +inverse_transform : 將其轉換回原本的特徵數(64)對應的特徵值 + +```python +images_restored = np.reshape(X_restored, images.shape) +plt.figure(1, figsize=(4, 3.5)) +plt.clf() +``` +plt.clf() : 保留figure但是清除內容,可以讓這figure重複使用 + +最後用下面程式碼將圖秀出來 +```python +plt.subplots_adjust(left=.01, right=.99, bottom=.01, top=.91) +for i in range(4): + plt.subplot(3, 4, i + 1) + plt.imshow(images[i], cmap=plt.cm.gray, vmax=16, interpolation='nearest') + plt.xticks(()) + plt.yticks(()) + if i == 1: + plt.title('Original data') + plt.subplot(3, 4, 4 + i + 1) + plt.imshow(images_restored[i], cmap=plt.cm.gray, vmax=16, + interpolation='nearest') + if i == 1: + plt.title('Agglomerated data') + plt.xticks(()) + plt.yticks(()) + +plt.subplot(3, 4, 10) +plt.imshow(np.reshape(agglo.labels_, images[0].shape), + interpolation='nearest', cmap=plt.cm.nipy_spectral) +plt.xticks(()) +plt.yticks(()) +plt.title('Labels') +plt.show() +``` + +![](https://github.com/kenny024241/machine-learning-python/raw/master/Clustering/ex1.png) + + +## (三)完整程式碼 +Python source code:plot_digits_agglomeration.py + +https://scikit-learn.org/stable/_downloads/plot_digits_agglomeration.py + +```python +print(__doc__) + +# Code source: Gaël Varoquaux +# Modified for documentation by Jaques Grobler +# License: BSD 3 clause + +import numpy as np +import matplotlib.pyplot as plt + +from sklearn import datasets, cluster +from sklearn.feature_extraction.image import grid_to_graph + +digits = datasets.load_digits() +images = digits.images +X = np.reshape(images, (len(images), -1)) +connectivity = grid_to_graph(*images[0].shape) + +agglo = cluster.FeatureAgglomeration(connectivity=connectivity, + n_clusters=32) + +agglo.fit(X) +X_reduced = agglo.transform(X) + +X_restored = agglo.inverse_transform(X_reduced) +images_restored = np.reshape(X_restored, images.shape) +plt.figure(1, figsize=(4, 3.5)) +plt.clf() +plt.subplots_adjust(left=.01, right=.99, bottom=.01, top=.91) +for i in range(4): + plt.subplot(3, 4, i + 1) + plt.imshow(images[i], cmap=plt.cm.gray, vmax=16, interpolation='nearest') + plt.xticks(()) + plt.yticks(()) + if i == 1: + plt.title('Original data') + plt.subplot(3, 4, 4 + i + 1) + plt.imshow(images_restored[i], cmap=plt.cm.gray, vmax=16, + interpolation='nearest') + if i == 1: + plt.title('Agglomerated data') + plt.xticks(()) + plt.yticks(()) + +plt.subplot(3, 4, 10) +plt.imshow(np.reshape(agglo.labels_, images[0].shape), + interpolation='nearest', cmap=plt.cm.nipy_spectral) +plt.xticks(()) +plt.yticks(()) +plt.title('Labels') +plt.show() +``` + + diff --git a/Clustering/EX2_A_demo_of_the_mean-shift_clustering_algorithm.md b/Clustering/EX2_A_demo_of_the_mean-shift_clustering_algorithm.md new file mode 100644 index 0000000..7f5bf40 --- /dev/null +++ b/Clustering/EX2_A_demo_of_the_mean-shift_clustering_algorithm.md @@ -0,0 +1,141 @@ +# **範例二:A demo of the mean-shift clustering algorithm** + +https://scikit-learn.org/stable/auto_examples/cluster/plot_mean_shift.html#sphx-glr-auto-examples-cluster-plot-mean-shift-py + +此範例展示一種強建的特徵空間分析法 + +1. 利用 make_blobs 來建立所需的樣本點 +2. 利用均值漂移算法找到各類質心集合 +3. 通過找到給定樣本的最近質心來給新樣本上標籤 + + +## (一)引入函式庫 + +引入函式如下: + +1. numpy : 產生陣列數值 +2. matplotlib.pyplot : 用來繪製影像 +3. sklearn.cluster import MeanShift, estimate_bandwidth : MeanShift:發現樣本的平滑密度中的點 ; estimate_bandwidth:計算要用於maen-shift演算法的頻寬 +4. sklearn.datasets.samples_generator import make_blobs : 產生用於clustering的等向高斯分布點 +5. itertools import cycle : 產生一個迭代器,對迭代器中的元素反覆執行 + +```python +import numpy as np +from sklearn.cluster import MeanShift, estimate_bandwidth +from sklearn.datasets.samples_generator import make_blobs +``` + +```python +# Generate sample data +centers = [[1, 1], [-1, -1], [1, -1]] +X, _ = make_blobs(n_samples=10000, centers=centers, cluster_std=0.6) +``` +根據提供的3個中心點,產生各10000個等向高斯的點 + + +## (二)Clustering +```python +bandwidth = estimate_bandwidth(X, quantile=0.2, n_samples=500) + +ms = MeanShift(bandwidth=bandwidth, bin_seeding=True) +ms.fit(X) +labels = ms.labels_ +cluster_centers = ms.cluster_centers_ + +labels_unique = np.unique(labels) +n_clusters_ = len(labels_unique) + +print("number of estimated clusters : %d" % n_clusters_) +``` +estimate_bandwidth 算出的 bandwidth 會用來作為提供 RBF krenel 的參數,用在 MeanShift 的 bandwidth 參數裡面 +RBF kernel : 主要用於線性不可分的情形,將資料投射到更高維的空間,讓其變得可以線性分割 +做聚集後就可得各類別的中心點,以及各點的label + +```python +# Plot result +import matplotlib.pyplot as plt +from itertools import cycle + +plt.figure(1) +plt.clf() + +colors = cycle('bgrcmykbgrcmykbgrcmykbgrcmyk') +for k, col in zip(range(n_clusters_), colors): + my_members = labels == k + cluster_center = cluster_centers[k] + plt.plot(X[my_members, 0], X[my_members, 1], col + '.') + plt.plot(cluster_center[0], cluster_center[1], 'o', markerfacecolor=col, + markeredgecolor='k', markersize=14) +plt.title('Estimated number of clusters: %d' % n_clusters_) +plt.show() +``` +colors : 在這用作圖形顏色切換 +plt.plot(X[my_members, 0], X[my_members, 1], col + '.') : 畫出個別label的點 +plt.plot(cluster_center[0], cluster_center[1], 'o', markerfacecolor=col,markeredgecolor='k', markersize=14) : 畫出個別label的中心 +最後秀出結果圖 + +![](https://github.com/kenny024241/machine-learning-python/blob/master/Clustering/ex2.png) + + +## (三)完整程式碼 +Python source code:plot_mean_shift.py + +https://scikit-learn.org/stable/_downloads/plot_mean_shift.py +```python +""" +============================================= +A demo of the mean-shift clustering algorithm +============================================= + +Reference: + +Dorin Comaniciu and Peter Meer, "Mean Shift: A robust approach toward +feature space analysis". IEEE Transactions on Pattern Analysis and +Machine Intelligence. 2002. pp. 603-619. + +""" +print(__doc__) + +import numpy as np +from sklearn.cluster import MeanShift, estimate_bandwidth +from sklearn.datasets.samples_generator import make_blobs + +# ############################################################################# +# Generate sample data +centers = [[1, 1], [-1, -1], [1, -1]] +X, _ = make_blobs(n_samples=10000, centers=centers, cluster_std=0.6) + +# ############################################################################# +# Compute clustering with MeanShift + +# The following bandwidth can be automatically detected using +bandwidth = estimate_bandwidth(X, quantile=0.2, n_samples=500) + +ms = MeanShift(bandwidth=bandwidth, bin_seeding=True) +ms.fit(X) +labels = ms.labels_ +cluster_centers = ms.cluster_centers_ + +labels_unique = np.unique(labels) +n_clusters_ = len(labels_unique) + +print("number of estimated clusters : %d" % n_clusters_) + +# ############################################################################# +# Plot result +import matplotlib.pyplot as plt +from itertools import cycle + +plt.figure(1) +plt.clf() + +colors = cycle('bgrcmykbgrcmykbgrcmykbgrcmyk') +for k, col in zip(range(n_clusters_), colors): + my_members = labels == k + cluster_center = cluster_centers[k] + plt.plot(X[my_members, 0], X[my_members, 1], col + '.') + plt.plot(cluster_center[0], cluster_center[1], 'o', markerfacecolor=col, + markeredgecolor='k', markersize=14) +plt.title('Estimated number of clusters: %d' % n_clusters_) +plt.show() +``` diff --git a/Clustering/EX6_Segmenting_the_picture_of_greek_coins_in_regions.md b/Clustering/EX6_Segmenting_the_picture_of_greek_coins_in_regions.md new file mode 100644 index 0000000..a1b19bd --- /dev/null +++ b/Clustering/EX6_Segmenting_the_picture_of_greek_coins_in_regions.md @@ -0,0 +1,179 @@ +# **範例六:Segmenting the picture of greek coins in regions** + +https://scikit-learn.org/stable/auto_examples/cluster/plot_coin_segmentation.html#sphx-glr-auto-examples-cluster-plot-coin-segmentation-py + +此範例用Spectral Clustering以分割圖中的硬幣 + +1. 利用coins()匯入圖片 +2. 利用spectral_clustering做切割 +3. 最後將結果可視化 + +## (一)引入函式庫 + +引入函式如下: + +1. time : 提供各種與時間相關函數 +2. numpy : 產生陣列數值 +3. scipy.ndimage.filters import gaussian_filter : 做gaussian filter +4. matplotlib.pyplot : 用來繪製影像 +5. skimage.data import coins : 匯入龐貝城的希臘硬幣 +6. skimage.transform import rescale : 用來縮放圖片 +7. sklearn.feature_extraction import image : 將每個像素的梯度關係圖像化 +8. sklearn.cluster import spectral_clustering : 將影像正規化切割 + +```python +import time +import numpy as np +from scipy.ndimage.filters import gaussian_filter +import matplotlib.pyplot as plt +from skimage.data import coins +from skimage.transform import rescale + +from sklearn.feature_extraction import image +from sklearn.cluster import spectral_clustering + +orig_coins = coins() + +smoothened_coins = gaussian_filter(orig_coins, sigma=2) +rescaled_coins = rescale(smoothened_coins, 0.2, mode="reflect") +``` +coins() : 匯入一張303x384的影像 +用 rescale 將圖片 resize 成原圖的20%(61x77)來加快處理,並根據 mode 選擇 padding 方式 + + +## (二)Clustering +```python +# Convert the image into a graph with the value of the gradient on the edges. +graph = image.img_to_graph(rescaled_coins) +``` +img_to_graph : 用來處理邊緣的權重與每個像速間的梯度關聯 + +```python +beta = 10 +eps = 1e-6 +graph.data = np.exp(-beta * graph.data / graph.data.std()) + eps +``` +beta越小,實際圖像會分割的越獨立,當 beta = 1 時,會類似Voronoi Diagram演算法的概念 + +```python +N_REGIONS = 24 + +for assign_labels in ('kmeans', 'discretize'): + t0 = time.time() + labels = spectral_clustering(graph, n_clusters=N_REGIONS, + assign_labels=assign_labels, random_state=42) + t1 = time.time() + labels = labels.reshape(rescaled_coins.shape) + + plt.figure(figsize=(5, 5)) + plt.imshow(rescaled_coins, cmap=plt.cm.gray) + for l in range(N_REGIONS): + plt.contour(labels == l, + colors=[plt.cm.nipy_spectral(l / float(N_REGIONS))]) + plt.xticks(()) + plt.yticks(()) + title = 'Spectral clustering: %s, %.2fs' % (assign_labels, (t1 - t0)) + print(title) + plt.title(title) +plt.show() +``` +用spectral_clustering將連在一起的部分切開,而spectral_clustering中的各項參數設定如下: +* graph: 必須是一個矩陣且大小為nxn的形式 +* n_clusters: 需要提取出的群集數 +* random_state: 偽隨機數產生器,用於初始化特徵向量分解計算 +* assign_labels:選擇assign label的方法(kmeans or discretize) + +用plt.contour畫出等高線,同個label會被框在同個圈內 + + +![](https://github.com/kenny024241/machine-learning-python/blob/master/Clustering/ex6-1.png) ![](https://github.com/kenny024241/machine-learning-python/blob/master/Clustering/ex6-2.png) + + +## (三)完整程式碼 +Python source code:plot_coin_segmentation.py + +https://scikit-learn.org/stable/_downloads/plot_coin_segmentation.py +```python +""" +================================================ +Segmenting the picture of greek coins in regions +================================================ + +This example uses :ref:`spectral_clustering` on a graph created from +voxel-to-voxel difference on an image to break this image into multiple +partly-homogeneous regions. + +This procedure (spectral clustering on an image) is an efficient +approximate solution for finding normalized graph cuts. + +There are two options to assign labels: + +* with 'kmeans' spectral clustering will cluster samples in the embedding space + using a kmeans algorithm +* whereas 'discrete' will iteratively search for the closest partition + space to the embedding space. +""" +print(__doc__) + +# Author: Gael Varoquaux , Brian Cheung +# License: BSD 3 clause + +import time + +import numpy as np +from scipy.ndimage.filters import gaussian_filter +import matplotlib.pyplot as plt +from skimage.data import coins +from skimage.transform import rescale + +from sklearn.feature_extraction import image +from sklearn.cluster import spectral_clustering + + +# load the coins as a numpy array +orig_coins = coins() + +# Resize it to 20% of the original size to speed up the processing +# Applying a Gaussian filter for smoothing prior to down-scaling +# reduces aliasing artifacts. +smoothened_coins = gaussian_filter(orig_coins, sigma=2) +rescaled_coins = rescale(smoothened_coins, 0.2, mode="reflect") + +# Convert the image into a graph with the value of the gradient on the +# edges. +graph = image.img_to_graph(rescaled_coins) + +# Take a decreasing function of the gradient: an exponential +# The smaller beta is, the more independent the segmentation is of the +# actual image. For beta=1, the segmentation is close to a voronoi +beta = 10 +eps = 1e-6 +graph.data = np.exp(-beta * graph.data / graph.data.std()) + eps + +# Apply spectral clustering (this step goes much faster if you have pyamg +# installed) +N_REGIONS = 24 + +############################################################################# +# Visualize the resulting regions + +for assign_labels in ('kmeans', 'discretize'): + t0 = time.time() + labels = spectral_clustering(graph, n_clusters=N_REGIONS, + assign_labels=assign_labels, random_state=42) + t1 = time.time() + labels = labels.reshape(rescaled_coins.shape) + + plt.figure(figsize=(5, 5)) + plt.imshow(rescaled_coins, cmap=plt.cm.gray) + for l in range(N_REGIONS): + plt.contour(labels == l, + colors=[plt.cm.nipy_spectral(l / float(N_REGIONS))]) + plt.xticks(()) + plt.yticks(()) + title = 'Spectral clustering: %s, %.2fs' % (assign_labels, (t1 - t0)) + print(title) + plt.title(title) +plt.show() +``` + diff --git a/Clustering/clustering.md b/Clustering/clustering.md new file mode 100644 index 0000000..223b2ed --- /dev/null +++ b/Clustering/clustering.md @@ -0,0 +1 @@ +# 群聚法 Clustering diff --git a/Datasets/datasets.md b/Datasets/datasets.md new file mode 100644 index 0000000..c9a83a0 --- /dev/null +++ b/Datasets/datasets.md @@ -0,0 +1,4 @@ +# 機器學習資料集 Datasets +這個章節介紹scikit-learn 所提供之機器學習資料集,最常用的主要有: +* 手寫數字辨識 +* 鳶尾花資料集 diff --git a/Datasets/ex1_fig1.png b/Datasets/ex1_fig1.png new file mode 100644 index 0000000..0a80662 Binary files /dev/null and b/Datasets/ex1_fig1.png differ diff --git a/Datasets/ex1_fig2.png b/Datasets/ex1_fig2.png new file mode 100644 index 0000000..0909283 Binary files /dev/null and b/Datasets/ex1_fig2.png differ diff --git a/Datasets/ex1_the_digits_dataset.md b/Datasets/ex1_the_digits_dataset.md new file mode 100644 index 0000000..0ea89f0 --- /dev/null +++ b/Datasets/ex1_the_digits_dataset.md @@ -0,0 +1,147 @@ + +# Datasets + +## 機器學習資料集/ 範例一: The digits dataset + + +http://scikit-learn.org/stable/auto_examples/datasets/plot_digits_last_image.html + +這個範例目的是介紹機器學習範例資料集的操作,對於初學者以及授課特別適合使用。 + +## (一)引入函式庫及內建手寫數字資料庫 + + +```python +#這行是在ipython notebook的介面裏專用,如果在其他介面則可以拿掉 +%matplotlib inline +from sklearn import datasets + +import matplotlib.pyplot as plt + +#載入數字資料集 +digits = datasets.load_digits() + +#畫出第一個圖片 +plt.figure(1, figsize=(3, 3)) +plt.imshow(digits.images[-1], cmap=plt.cm.gray_r, interpolation='nearest') +plt.show() +``` + + +![png](ex1_fig1.png) + + +## (二)資料集介紹 +`digits = datasets.load_digits()` 將一個dict型別資料存入digits,我們可以用下面程式碼來觀察裏面資料 + + +```python +for key,value in digits.items() : + try: + print (key,value.shape) + except: + print (key) + +``` + + ('images', (1797L, 8L, 8L)) + ('data', (1797L, 64L)) + ('target_names', (10L,)) + DESCR + ('target', (1797L,)) + + +| 顯示 | 說明 | +| -- | -- | +| ('images', (1797L, 8L, 8L))| 共有 1797 張影像,影像大小為 8x8 | +| ('data', (1797L, 64L)) | data 則是將8x8的矩陣攤平成64個元素之一維向量 | +| ('target_names', (10L,)) | 說明10種分類之對應 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | +| DESCR | 資料之描述 | +| ('target', (1797L,))| 記錄1797張影像各自代表那一個數字 | + +接下來我們試著以下面指令來觀察資料檔,每張影像所對照的實際數字存在`digits.target`變數中 + + +```python +images_and_labels = list(zip(digits.images, digits.target)) +for index, (image, label) in enumerate(images_and_labels[:4]): + plt.subplot(2, 4, index + 1) + plt.axis('off') + plt.imshow(image, cmap=plt.cm.gray_r, interpolation='nearest') + plt.title('Training: %i' % label) +``` + + +![png](ex1_fig2.png) + + + +```python +#接著我們嘗試將這個機器學習資料之描述檔顯示出來 +print(digits['DESCR']) +``` + + Optical Recognition of Handwritten Digits Data Set + =================================================== + + Notes + ----- + Data Set Characteristics: + :Number of Instances: 5620 + :Number of Attributes: 64 + :Attribute Information: 8x8 image of integer pixels in the range 0..16. + :Missing Attribute Values: None + :Creator: E. Alpaydin (alpaydin '@' boun.edu.tr) + :Date: July; 1998 + + This is a copy of the test set of the UCI ML hand-written digits datasets + http://archive.ics.uci.edu/ml/datasets/Optical+Recognition+of+Handwritten+Digits + + The data set contains images of hand-written digits: 10 classes where + each class refers to a digit. + + Preprocessing programs made available by NIST were used to extract + normalized bitmaps of handwritten digits from a preprinted form. From a + total of 43 people, 30 contributed to the training set and different 13 + to the test set. 32x32 bitmaps are divided into nonoverlapping blocks of + 4x4 and the number of on pixels are counted in each block. This generates + an input matrix of 8x8 where each element is an integer in the range + 0..16. This reduces dimensionality and gives invariance to small + distortions. + + For info on NIST preprocessing routines, see M. D. Garris, J. L. Blue, G. + T. Candela, D. L. Dimmick, J. Geist, P. J. Grother, S. A. Janet, and C. + L. Wilson, NIST Form-Based Handprint Recognition System, NISTIR 5469, + 1994. + + References + ---------- + - C. Kaynak (1995) Methods of Combining Multiple Classifiers and Their + Applications to Handwritten Digit Recognition, MSc Thesis, Institute of + Graduate Studies in Science and Engineering, Bogazici University. + - E. Alpaydin, C. Kaynak (1998) Cascading Classifiers, Kybernetika. + - Ken Tang and Ponnuthurai N. Suganthan and Xi Yao and A. Kai Qin. + Linear dimensionalityreduction using relevance weighted LDA. School of + Electrical and Electronic Engineering Nanyang Technological University. + 2005. + - Claudio Gentile. A New Approximate Maximal Margin Classification + Algorithm. NIPS. 2000. + + + +這個描述檔說明了這個資料集是在 1998年時建立的,由`E. Alpaydin, C. Kaynak ,Department of Computer Engineering +Bogazici University, Istanbul Turkey ` 建立的。數字的筆跡總共來自43個人,一開始取像時為32x32的點陣影像,之後經運算處理形成 8x8影像,其中灰階記錄的範圍則為 0~16的整數。 + +## (三)應用範例介紹 +在整個scikit-learn應用範例中,有以下幾個範例是利用了這組手寫辨識資料集。這個資料集的使用最適合機器學習初學者來理解分類法的原理以及其進階應用 + + * [分類法 Classification](../Classification/Classification.md) + * [Ex 1: Recognizing hand-written digits](../Classification/ex1_Recognizing_hand-written_digits.md) + * [特徵選擇 Feature Selection](../Feature_Selection/intro.md) + * [Ex 2: Recursive Feature Elimination](../Feature_Selection/ex2_Recursive_feature_elimination.md) + * [Ex 3: Recursive Feature Elimination with Cross-Validation](../Feature_Selection/ex3_rfe_crossvalidation__md.md) + + +```python + +``` diff --git a/Datasets/ex3_fig1.png b/Datasets/ex3_fig1.png new file mode 100644 index 0000000..9867be8 Binary files /dev/null and b/Datasets/ex3_fig1.png differ diff --git a/Datasets/ex3_fig2.png b/Datasets/ex3_fig2.png new file mode 100644 index 0000000..b494e02 Binary files /dev/null and b/Datasets/ex3_fig2.png differ diff --git a/Datasets/ex3_the_iris_dataset.md b/Datasets/ex3_the_iris_dataset.md new file mode 100644 index 0000000..d3e8295 --- /dev/null +++ b/Datasets/ex3_the_iris_dataset.md @@ -0,0 +1,183 @@ + +# Datasets + +## 機器學習資料集/ 範例三: The iris dataset + + +http://scikit-learn.org/stable/auto_examples/datasets/plot_iris_dataset.html + +這個範例目的是介紹機器學習範例資料集中的iris 鳶尾花資料集 + + +## (一)引入函式庫及內建手寫數字資料庫 + + +```python +#這行是在ipython notebook的介面裏專用,如果在其他介面則可以拿掉 +%matplotlib inline + +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D +from sklearn import datasets +from sklearn.decomposition import PCA + +# import some data to play with +iris = datasets.load_iris() +X = iris.data[:, :2] # we only take the first two features. +Y = iris.target + +x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5 +y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5 + +plt.figure(2, figsize=(8, 6)) +plt.clf() +# Plot the training points +plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=plt.cm.Paired) +plt.xlabel('Sepal length') +plt.ylabel('Sepal width') + +plt.xlim(x_min, x_max) +plt.ylim(y_min, y_max) +plt.xticks(()) +plt.yticks(()) + +``` + +![png](ex3_fig1.png) + + +## (二)資料集介紹 +`iris = datasets.load_iris()` 將一個dict型別資料存入iris,我們可以用下面程式碼來觀察裏面資料 + + +```python +for key,value in iris.items() : + try: + print (key,value.shape) + except: + print (key) +print(iris['feature_names']) +``` + +| 顯示 | 說明 | +| -- | -- | +| ('target_names', (3L,))| 共有三種鳶尾花 setosa, versicolor, virginica | +| ('data', (150L, 4L)) | 有150筆資料,共四種特徵 | +| ('target', (150L,))| 這150筆資料各是那一種鳶尾花| +| DESCR | 資料之描述 | +| feature_names| 四個特徵代表的意義,分別為 萼片(sepal)之長與寬以及花瓣(petal)之長與寬 + +為了用視覺化方式呈現這個資料集,下面程式碼首先使用PCA演算法將資料維度降低至3 + + +```python +X_reduced = PCA(n_components=3).fit_transform(iris.data) +``` + +接下來將三個維度的資料立用`mpl_toolkits.mplot3d.Axes3D` 建立三維繪圖空間,並利用 `scatter`以三個特徵資料數值當成座標繪入空間,並以三種iris之數值 Y,來指定資料點的顏色。我們可以看出三種iris中,有一種明顯的可以與其他兩種區別,而另外兩種則無法明顯區別。 + + +```python +# To getter a better understanding of interaction of the dimensions +# plot the first three PCA dimensions +fig = plt.figure(1, figsize=(8, 6)) +ax = Axes3D(fig, elev=-150, azim=110) +ax.scatter(X_reduced[:, 0], X_reduced[:, 1], X_reduced[:, 2], c=Y, + cmap=plt.cm.Paired) +ax.set_title("First three PCA directions") +ax.set_xlabel("1st eigenvector") +ax.w_xaxis.set_ticklabels([]) +ax.set_ylabel("2nd eigenvector") +ax.w_yaxis.set_ticklabels([]) +ax.set_zlabel("3rd eigenvector") +ax.w_zaxis.set_ticklabels([]) + +plt.show() +``` + + +![png](ex3_fig2.png) + + + +```python +#接著我們嘗試將這個機器學習資料之描述檔顯示出來 +print(iris['DESCR']) +``` + + Iris Plants Database + + Notes + ----- + Data Set Characteristics: + :Number of Instances: 150 (50 in each of three classes) + :Number of Attributes: 4 numeric, predictive attributes and the class + :Attribute Information: + - sepal length in cm + - sepal width in cm + - petal length in cm + - petal width in cm + - class: + - Iris-Setosa + - Iris-Versicolour + - Iris-Virginica + :Summary Statistics: + + ============== ==== ==== ======= ===== ==================== + Min Max Mean SD Class Correlation + ============== ==== ==== ======= ===== ==================== + sepal length: 4.3 7.9 5.84 0.83 0.7826 + sepal width: 2.0 4.4 3.05 0.43 -0.4194 + petal length: 1.0 6.9 3.76 1.76 0.9490 (high!) + petal width: 0.1 2.5 1.20 0.76 0.9565 (high!) + ============== ==== ==== ======= ===== ==================== + + :Missing Attribute Values: None + :Class Distribution: 33.3% for each of 3 classes. + :Creator: R.A. Fisher + :Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov) + :Date: July, 1988 + + This is a copy of UCI ML iris datasets. + http://archive.ics.uci.edu/ml/datasets/Iris + + The famous Iris database, first used by Sir R.A Fisher + + This is perhaps the best known database to be found in the + pattern recognition literature. Fisher's paper is a classic in the field and + is referenced frequently to this day. (See Duda & Hart, for example.) The + data set contains 3 classes of 50 instances each, where each class refers to a + type of iris plant. One class is linearly separable from the other 2; the + latter are NOT linearly separable from each other. + + References + ---------- + - Fisher,R.A. "The use of multiple measurements in taxonomic problems" + Annual Eugenics, 7, Part II, 179-188 (1936); also in "Contributions to + Mathematical Statistics" (John Wiley, NY, 1950). + - Duda,R.O., & Hart,P.E. (1973) Pattern Classification and Scene Analysis. + (Q327.D83) John Wiley & Sons. ISBN 0-471-22361-1. See page 218. + - Dasarathy, B.V. (1980) "Nosing Around the Neighborhood: A New System + Structure and Classification Rule for Recognition in Partially Exposed + Environments". IEEE Transactions on Pattern Analysis and Machine + Intelligence, Vol. PAMI-2, No. 1, 67-71. + - Gates, G.W. (1972) "The Reduced Nearest Neighbor Rule". IEEE Transactions + on Information Theory, May 1972, 431-433. + - See also: 1988 MLC Proceedings, 54-64. Cheeseman et al"s AUTOCLASS II + conceptual clustering system finds 3 classes in the data. + - Many, many more ... + + + +這個描述檔說明了這個資料集是在 1936年時由Fisher建立,為圖形識別領域之重要經典範例。共例用四種特徵來分類三種鳶尾花 + +## (三)應用範例介紹 +在整個scikit-learn應用範例中,有以下幾個範例是利用了這組iris資料集。 + +* 分類法 Classification + * [EX 3: Plot classification probability](../Classification/ex3_Plot_classification_probability.md) +* 特徵選擇 Feature Selection + * [Ex 5: Test with permutations the significance of a classification score](../Feature_Selection/ex5_test_with_permutations_the_significance_of_a__.md) + * [Ex 6: Univariate Feature Selection](../Feature_Selection/ex6_univariate_feature_selection.md) +* 通用範例 General Examples + * [Ex 2: Concatenating multiple feature extraction methods](../general_examples/Ex2_feature_stacker.md) diff --git a/Datasets/ipython_notebook/ex1_the_digits_dataset.ipynb b/Datasets/ipython_notebook/ex1_the_digits_dataset.ipynb new file mode 100644 index 0000000..1fd21cf --- /dev/null +++ b/Datasets/ipython_notebook/ex1_the_digits_dataset.ipynb @@ -0,0 +1,255 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Datasets\n", + "\n", + "## 機器學習資料集/ 範例一: The digits dataset\n", + "\n", + "\n", + "http://scikit-learn.org/stable/auto_examples/datasets/plot_digits_last_image.html\n", + "\n", + "這個範例目的是介紹機器學習範例資料集的操作,對於初學者以及授課特別適合使用。\n", + "\n", + "## (一)引入函式庫及內建手寫數字資料庫" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMAAAADDCAYAAADUSB6pAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAACuJJREFUeJzt3VGMVdUVxvH/hyiC1KGpRoxUoDHW2KQZSYoP0BTaaqkm\nVB+aak0UH+yLRmkbI/FFeONNTNqXRgRstRpNobRRA4kODTZVVEZRoNpaFK0QmzgaQ2xUVh/uoZnA\njOzh7n3mzuzvl0zmznCyWDD3m3PuOXedrYjArFZTxrsBs/HkAFjVHACrmgNgVXMArGpTcxWS5NNJ\n1rMiQiN9P1sAmr/kpNusXr2a1atX5/xrx1RzxYoVSdsNDg7S39+ftO3AwEDSdkNDQ8yaNStp29Q+\nBwYGWLJkSdK2K1euTNpu7dq1rFq1Kmnb1H/PeP7cpRGf+4APgaxyDoBVrfUApO6ux7vm7Nmzs9c8\n88wzs9ecN29e9pqLFy/OXrNXf+4OwCgcgLx69efuQyCrWlIAJC2TtF/S65LuKt2UWVtOGgBJU4Bf\nAT8AvgFcL+mS0o2ZtSFlD7AQeCMi3oqIT4FHgB+VbcusHSkBuAA4OOzrd5rvmU14Wa8ED78qt2TJ\nkiKv/M1OZmBgIPnqfEoA3gUuHPb1nOZ7J8h9qdvsVBz/y3fNmjWjbptyCLQLuEjSXElnANcBW7vs\n0awnnHQPEBGfS7oN2EYnMOsjYl/xzsxakPQaICKeAr5euBez1vlKsFXNAbCqOQBWNQfAqpb1Qlhu\nBw4cyF5z06ZN2WvOnTs3e80Sb3O2E3kPYFVzAKxqDoBVzQGwqjkAVjUHwKrmAFjVUmaC10s6LOmV\nNhoya1PKHmADnYF4s0nnpAGIiJ3ABy30YtY6vwawqnko3iadsQzFK+We/pLmAn+KiG9+wTaRe8nV\nEm+Gmz9/fvaaJd4MV+IGA9dcc032mqnrA4wnSaMukJF6CKTmw2xSSTkN+jDwV+BiSW9Lurl8W2bt\nSLkrxE/baMRsPPgskFXNAbCqOQBWNQfAqtbTQ/ElBsP7+vqy1xwaGspes8Q1kBL/nyX+7W3yHsCq\n5gBY1RwAq5oDYFVzAKxqDoBVzQGwqqW8G3SOpKclvSZpj6Tb22jMrA0pF8I+A34REYOSZgIvStoW\nEfsL92ZWXMpQ/KGIGGwefwzswwtl2yQxptcAkuYB/cBzJZoxa1vye4Gaw5/HgTuaPcEJPBRvvaDE\nUPxU4M/AkxFx3yjbZB+KL2EiDHEDrFy5MnvNdevWZa85Ed4Ml2Mo/gFg72hPfrOJKuU06CLgBuC7\nknZLeknSsvKtmZWXMhT/LHBaC72Ytc5Xgq1qDoBVzQGwqjkAVrWk6wBJhSbIdYAtW7Zkr3nttddm\nr1nCTTfdlL3mxo0bs9fMLcd1ALNJyQGwqjkAVjUHwKrmAFjVHACr2knfCyRpGvAX4Ixm+8cjYk3p\nxszakPJmuP9KWhoRRySdBjwr6cmIeL6F/syKSjoEiogjzcNpdELT+1e8zBIkBUDSFEm7gUPA9ojY\nVbYts3ak7gGORsRlwBzgckmXlm3LrB1jWiAjIj6S9AywDNh7/J97KN56wViG4lPOAp0DfBoRH0qa\nDlwBrB1p2xKrm5uN1fG/fNesGf2kZcoe4Hxgk6QpdA6ZHo2IJ7rs0awnpJwG3QMsaKEXs9b5SrBV\nzQGwqjkAVjUHwKrmAFjVHACr2piuBE8GJe6Q3NfXl71mCQcOHBjvFnqO9wBWNQfAquYAWNUcAKua\nA2BVSw5AMxX2kqStJRsya9NY9gB3MMIQjNlEljoTPAe4Cri/bDtm7UrdA9wL3InvBmGTTMoqkVcD\nhyNiEFDzYTYppLwVYhGwXNJVwHTgS5IejIgbj9/QQ/HWC7KvFP//jaXvAL+MiOUj/NmEWCGmRCgH\nBwez1yyhv78/e83UJ9p48goxZqMY632BdgA7CvVi1jrvAaxqDoBVzQGwqjkAVjUHwKrmAFjVenoo\nvsRFlh078p/F3bBhQ/aa8+bNy15z6dKl2Wtu3Lgxe80VK1Zkrzka7wGsag6AVc0BsKo5AFY1B8Cq\nlnQWSNIB4EPgKJ31whaWbMqsLamnQY8CSyLig5LNmLUt9RBIY9jWbMJIfVIHsF3SLkm3lGzIrE2p\nh0CLIuI9SefSCcK+iNh5/EaeCbZekHWhbICIeK/5/L6kzcBC4AsDYDZexrJQdsptUWZImtk8Pgu4\nEni16y7NekDKHuA8YLOkaLZ/KCK2lW3LrB0pK8X/C8h/Pw2zHuBTm1Y1B8Cq5gBY1RwAq5oDYFVz\nAKxq1Q3Fl1CizxJD8SVM9NXnvQewqjkAVjUHwKrmAFjVHACrWuo6wX2SHpO0T9Jrki4v3ZhZG1JP\ng94HPBERP5Y0FZhRsCez1pw0AJLOBr4dESsAIuIz4KPCfZm1IuUQaD7wH0kbJL0k6TeSppduzKwN\nKYdAU4EFwK0R8YKkdcAq4J7jN/RQvPWC3EPx7wAHI+KF5uvHgbtG2tBD8dYLsg7FR8Rh4KCki5tv\nfQ/Y212LZr0h9SzQ7cBDkk4H3gRuLteSWXtS7wv0MvCtwr2Ytc5Xgq1qDoBVzQGwqjkAVjUHwKrm\nAFjVFBF5CkmRq9YxQ0NDWesBrFu3LnvNEkPxJYbNSwzab9myJXvNWbNmZa0niYjQSH/mPYBVzQGw\nqjkAVjUHwKrmAFjVUtYIu1jS7mYabLekDyXd3kZzZqWlLJH0OnAZgKQpdAZkNhfuy6wVYz0E+j7w\nz4g4WKIZs7aNNQA/AX5fohGz8ZB8e/RmGmw5nYH4EXko3npB9pXiGz8EXoyI90fbwEPx1guyDsUP\ncz0+/LFJJvXeoDPovAD+Q9l2zNqVOhR/BDi3cC9mrfOVYKuaA2BVaz0AJYZHdu7cmb1miYGUEgM+\nn3zySfaaJfos8TPK8VxyAEbhAOTlAJj1IAfAqpZ1KD5LIbMCRhuKzxYAs4nIh0BWNQfAquYAWNVa\nC4CkZZL2S3pd0ohrjJ1CzfWSDkt6JVO9OZKebhYD35Nj9lnSNEnPNfPUeySdsLhgF7WnNLPaWzPV\nOyDp5abX5zPVzLrIevYZ9Ygo/kEnaP8A5gKnA4PAJRnqLgb6gVcy9Tkb6G8ezwT+nqnPGc3n04C/\nAQsz9ftz4HfA1kz13gS+nPlnvxG4uXk8FTg78/Pq38BXT7VGW3uAhcAbEfFWRHwKPAL8qNuiEbET\n+KDbOsPqHYqIwebxx8A+4IIMdY80D6fReRJ0fepN0hzgKuD+bmsNL0vGo4Jhi6xvgM4i6xGRc5H1\nrmfU2wrABcDwJt8hwxOrJEnz6OxdnstQa4qk3cAhYHtE7Oq2JnAvcCcZwjRMANsl7ZJ0S4Z6pRdZ\n73pG3S+CRyBpJp31kO9o9gRdiYijEXEZMAe4XNKlXfZ3NXC42Vup+chhUUQsoLNnuVXS4i7rHVtk\n/ddN3SN8wUz5WAybUX+smzptBeBd4MJhX89pvtdzJE2l8+T/bUT8MWftZvf/DLCsy1KLgOWS3qTz\nG3CppAcz9Pde8/l9Ovd+WthlyZEWWV/QZc1jTjqjnqKtAOwCLpI0V9IZwHVAljMX5P0NCPAAsDci\n7stRTNI5kvqax9OBK4D93dSMiLsj4sKI+Bqd/8unI+LGLvuc0ez5kHQWcCXwapd9llxkPcuM+lju\nCnHKIuJzSbcB2+iEbn1E7Ou2rqSHgSXAVyS9Ddxz7AXXKdZbBNwA7GmO2QO4OyKe6qLN84FNzV31\npgCPRsQTXdQr5Txgc/OerqnAQxGxLUPd7IusD5tR/1nXtZrTSWZV8otgq5oDYFVzAKxqDoBVzQGw\nqjkAVjUHwKr2P6F3L3i75upIAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#這行是在ipython notebook的介面裏專用,如果在其他介面則可以拿掉\n", + "%matplotlib inline\n", + "from sklearn import datasets\n", + "\n", + "import matplotlib.pyplot as plt\n", + "\n", + "#載入數字資料集\n", + "digits = datasets.load_digits()\n", + "\n", + "#畫出第一個圖片\n", + "plt.figure(1, figsize=(3, 3))\n", + "plt.imshow(digits.images[-1], cmap=plt.cm.gray_r, interpolation='nearest')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## (二)資料集介紹\n", + "`digits = datasets.load_digits()` 將一個dict型別資料存入digits,我們可以用下面程式碼來觀察裏面資料" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('images', (1797L, 8L, 8L))\n", + "('data', (1797L, 64L))\n", + "('target_names', (10L,))\n", + "DESCR\n", + "('target', (1797L,))\n" + ] + } + ], + "source": [ + "for key,value in digits.items() :\n", + " try:\n", + " print (key,value.shape)\n", + " except:\n", + " print (key)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| 顯示 | 說明 |\n", + "| -- | -- |\n", + "| ('images', (1797L, 8L, 8L))| 共有 1797 張影像,影像大小為 8x8 |\n", + "| ('data', (1797L, 64L)) | data 則是將8x8的矩陣攤平成64個元素之一維向量 |\n", + "| ('target_names', (10L,)) | 說明10種分類之對應 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |\n", + "| DESCR | 資料之描述 |\n", + "| ('target', (1797L,))| 記錄1797張影像各自代表那一個數字 |\n", + "\n", + "接下來我們試著以下面指令來觀察資料檔,每張影像所對照的實際數字存在`digits.target`變數中" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\nAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "images_and_labels = list(zip(digits.images, digits.target))\n", + "for index, (image, label) in enumerate(images_and_labels[:4]):\n", + " plt.subplot(2, 4, index + 1)\n", + " plt.axis('off')\n", + " plt.imshow(image, cmap=plt.cm.gray_r, interpolation='nearest')\n", + " plt.title('Training: %i' % label)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](images/ex1_output_7_0.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optical Recognition of Handwritten Digits Data Set\n", + "===================================================\n", + "\n", + "Notes\n", + "-----\n", + "Data Set Characteristics:\n", + " :Number of Instances: 5620\n", + " :Number of Attributes: 64\n", + " :Attribute Information: 8x8 image of integer pixels in the range 0..16.\n", + " :Missing Attribute Values: None\n", + " :Creator: E. Alpaydin (alpaydin '@' boun.edu.tr)\n", + " :Date: July; 1998\n", + "\n", + "This is a copy of the test set of the UCI ML hand-written digits datasets\n", + "http://archive.ics.uci.edu/ml/datasets/Optical+Recognition+of+Handwritten+Digits\n", + "\n", + "The data set contains images of hand-written digits: 10 classes where\n", + "each class refers to a digit.\n", + "\n", + "Preprocessing programs made available by NIST were used to extract\n", + "normalized bitmaps of handwritten digits from a preprinted form. From a\n", + "total of 43 people, 30 contributed to the training set and different 13\n", + "to the test set. 32x32 bitmaps are divided into nonoverlapping blocks of\n", + "4x4 and the number of on pixels are counted in each block. This generates\n", + "an input matrix of 8x8 where each element is an integer in the range\n", + "0..16. This reduces dimensionality and gives invariance to small\n", + "distortions.\n", + "\n", + "For info on NIST preprocessing routines, see M. D. Garris, J. L. Blue, G.\n", + "T. Candela, D. L. Dimmick, J. Geist, P. J. Grother, S. A. Janet, and C.\n", + "L. Wilson, NIST Form-Based Handprint Recognition System, NISTIR 5469,\n", + "1994.\n", + "\n", + "References\n", + "----------\n", + " - C. Kaynak (1995) Methods of Combining Multiple Classifiers and Their\n", + " Applications to Handwritten Digit Recognition, MSc Thesis, Institute of\n", + " Graduate Studies in Science and Engineering, Bogazici University.\n", + " - E. Alpaydin, C. Kaynak (1998) Cascading Classifiers, Kybernetika.\n", + " - Ken Tang and Ponnuthurai N. Suganthan and Xi Yao and A. Kai Qin.\n", + " Linear dimensionalityreduction using relevance weighted LDA. School of\n", + " Electrical and Electronic Engineering Nanyang Technological University.\n", + " 2005.\n", + " - Claudio Gentile. A New Approximate Maximal Margin Classification\n", + " Algorithm. NIPS. 2000.\n", + "\n" + ] + } + ], + "source": [ + "#接著我們嘗試將這個機器學習資料之描述檔顯示出來\n", + "print(digits['DESCR'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "這個描述檔說明了這個資料集是在 1998年時建立的,由`E. Alpaydin, C. Kaynak ,Department of Computer Engineering \n", + "Bogazici University, Istanbul Turkey ` 建立的。數字的筆跡總共來自43個人,一開始取像時為32x32的點陣影像,之後經運算處理形成 8x8影像,其中灰階記錄的範圍則為 0~16的整數。" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## (三)應用範例介紹\n", + "在整個scikit-learn應用範例中,有以下幾個範例是利用了這組手寫辨識資料集。這個資料集的使用最適合機器學習初學者來理解分類法的原理以及其進階應用\n", + "\n", + " * [分類法 Classification](Classification/Classification.md)\n", + " * [Ex 1: Recognizing hand-written digits](Classification/ex1_Recognizing_hand-written_digits.md)\n", + " * [特徵選擇 Feature Selection](Feature_Selection/intro.md)\n", + " * [Ex 2: Recursive Feature Elimination](Feature_Selection/ex2_Recursive_feature_elimination.md)\n", + " * [Ex 3: Recursive Feature Elimination with Cross-Validation](Feature_Selection/ex3_rfe_crossvalidation__md.md)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Datasets/ipython_notebook/ex2_the_iris_dataset-Copy1.ipynb b/Datasets/ipython_notebook/ex2_the_iris_dataset-Copy1.ipynb new file mode 100644 index 0000000..56a8296 --- /dev/null +++ b/Datasets/ipython_notebook/ex2_the_iris_dataset-Copy1.ipynb @@ -0,0 +1,297 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Datasets\n", + "\n", + "## 機器學習資料集/ 範例三: The iris dataset\n", + "\n", + "\n", + "http://scikit-learn.org/stable/auto_examples/datasets/plot_iris_dataset.html\n", + "\n", + "這個範例目的是介紹機器學習範例資料集中的iris 鳶尾花資料集\n", + "\n", + "\n", + "## (一)引入函式庫及內建手寫數字資料庫" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "([], )" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#這行是在ipython notebook的介面裏專用,如果在其他介面則可以拿掉\n", + "%matplotlib inline\n", + "\n", + "import matplotlib.pyplot as plt\n", + "from mpl_toolkits.mplot3d import Axes3D\n", + "from sklearn import datasets\n", + "from sklearn.decomposition import PCA\n", + "\n", + "# import some data to play with\n", + "iris = datasets.load_iris()\n", + "X = iris.data[:, :2] # we only take the first two features.\n", + "Y = iris.target\n", + "\n", + "x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5\n", + "y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5\n", + "\n", + "plt.figure(2, figsize=(8, 6))\n", + "plt.clf()\n", + "# Plot the training points\n", + "plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=plt.cm.Paired)\n", + "plt.xlabel('Sepal length')\n", + "plt.ylabel('Sepal width')\n", + "\n", + "plt.xlim(x_min, x_max)\n", + "plt.ylim(y_min, y_max)\n", + "plt.xticks(())\n", + "plt.yticks(())\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## (二)資料集介紹\n", + "`digits = datasets.load_digits()` 將一個dict型別資料存入digits,我們可以用下面程式碼來觀察裏面資料" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for key,value in iris.items() :\n", + " try:\n", + " print (key,value.shape)\n", + " except:\n", + " print (key)\n", + "print(iris['feature_names'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| 顯示 | 說明 |\n", + "| -- | -- |\n", + "| ('target_names', (3L,))| 共有三種鳶尾花 setosa, versicolor, virginica |\n", + "| ('data', (150L, 4L)) | 有150筆資料,共四種特徵 |\n", + "| ('target', (150L,))| 這150筆資料各是那一種鳶尾花|\n", + "| DESCR | 資料之描述 |\n", + "| feature_names| 四個特徵代表的意義,分別為 萼片(sepal)之長與寬以及花瓣(petal)之長與寬 \n", + "\n", + "為了用視覺化方式呈現這個資料集,下面程式碼首先使用PCA演算法將資料維度降低至3" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "X_reduced = PCA(n_components=3).fit_transform(iris.data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "接下來將三個維度的資料立用`mpl_toolkits.mplot3d.Axes3D` 建立三維繪圖空間,並利用 `scatter`以三個特徵資料數值當成座標繪入空間,並以三種iris之數值 Y,來指定資料點的顏色。我們可以看出三種iris中,有一種明顯的可以與其他兩種區別,而另外兩種則無法明顯區別。" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# To getter a better understanding of interaction of the dimensions\n", + "# plot the first three PCA dimensions\n", + "fig = plt.figure(1, figsize=(8, 6))\n", + "ax = Axes3D(fig, elev=-150, azim=110)\n", + "ax.scatter(X_reduced[:, 0], X_reduced[:, 1], X_reduced[:, 2], c=Y,\n", + " cmap=plt.cm.Paired)\n", + "ax.set_title(\"First three PCA directions\")\n", + "ax.set_xlabel(\"1st eigenvector\")\n", + "ax.w_xaxis.set_ticklabels([])\n", + "ax.set_ylabel(\"2nd eigenvector\")\n", + "ax.w_yaxis.set_ticklabels([])\n", + "ax.set_zlabel(\"3rd eigenvector\")\n", + "ax.w_zaxis.set_ticklabels([])\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iris Plants Database\n", + "\n", + "Notes\n", + "-----\n", + "Data Set Characteristics:\n", + " :Number of Instances: 150 (50 in each of three classes)\n", + " :Number of Attributes: 4 numeric, predictive attributes and the class\n", + " :Attribute Information:\n", + " - sepal length in cm\n", + " - sepal width in cm\n", + " - petal length in cm\n", + " - petal width in cm\n", + " - class:\n", + " - Iris-Setosa\n", + " - Iris-Versicolour\n", + " - Iris-Virginica\n", + " :Summary Statistics:\n", + "\n", + " ============== ==== ==== ======= ===== ====================\n", + " Min Max Mean SD Class Correlation\n", + " ============== ==== ==== ======= ===== ====================\n", + " sepal length: 4.3 7.9 5.84 0.83 0.7826\n", + " sepal width: 2.0 4.4 3.05 0.43 -0.4194\n", + " petal length: 1.0 6.9 3.76 1.76 0.9490 (high!)\n", + " petal width: 0.1 2.5 1.20 0.76 0.9565 (high!)\n", + " ============== ==== ==== ======= ===== ====================\n", + "\n", + " :Missing Attribute Values: None\n", + " :Class Distribution: 33.3% for each of 3 classes.\n", + " :Creator: R.A. Fisher\n", + " :Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov)\n", + " :Date: July, 1988\n", + "\n", + "This is a copy of UCI ML iris datasets.\n", + "http://archive.ics.uci.edu/ml/datasets/Iris\n", + "\n", + "The famous Iris database, first used by Sir R.A Fisher\n", + "\n", + "This is perhaps the best known database to be found in the\n", + "pattern recognition literature. Fisher's paper is a classic in the field and\n", + "is referenced frequently to this day. (See Duda & Hart, for example.) The\n", + "data set contains 3 classes of 50 instances each, where each class refers to a\n", + "type of iris plant. One class is linearly separable from the other 2; the\n", + "latter are NOT linearly separable from each other.\n", + "\n", + "References\n", + "----------\n", + " - Fisher,R.A. \"The use of multiple measurements in taxonomic problems\"\n", + " Annual Eugenics, 7, Part II, 179-188 (1936); also in \"Contributions to\n", + " Mathematical Statistics\" (John Wiley, NY, 1950).\n", + " - Duda,R.O., & Hart,P.E. (1973) Pattern Classification and Scene Analysis.\n", + " (Q327.D83) John Wiley & Sons. ISBN 0-471-22361-1. See page 218.\n", + " - Dasarathy, B.V. (1980) \"Nosing Around the Neighborhood: A New System\n", + " Structure and Classification Rule for Recognition in Partially Exposed\n", + " Environments\". IEEE Transactions on Pattern Analysis and Machine\n", + " Intelligence, Vol. PAMI-2, No. 1, 67-71.\n", + " - Gates, G.W. (1972) \"The Reduced Nearest Neighbor Rule\". IEEE Transactions\n", + " on Information Theory, May 1972, 431-433.\n", + " - See also: 1988 MLC Proceedings, 54-64. Cheeseman et al\"s AUTOCLASS II\n", + " conceptual clustering system finds 3 classes in the data.\n", + " - Many, many more ...\n", + "\n" + ] + } + ], + "source": [ + "#接著我們嘗試將這個機器學習資料之描述檔顯示出來\n", + "print(iris['DESCR'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "這個描述檔說明了這個資料集是在 1936年時由Fisher建立,為圖形識別領域之重要經典範例。共例用四種特徵來分類三種鳶尾花" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## (三)應用範例介紹\n", + "在整個scikit-learn應用範例中,有以下幾個範例是利用了這組iris資料集。\n", + "\n", + "* 分類法 Classification\n", + " * [EX 3: Plot classification probability](../Classification/ex3_Plot_classification_probability.md)\n", + "* 特徵選擇 Feature Selection\n", + " * [Ex 5: Test with permutations the significance of a classification score](../Feature_Selection/ex5_test_with_permutations_the_significance_of_a__.md)\n", + " * [Ex 6: Univariate Feature Selection](../Feature_Selection/ex6_univariate_feature_selection.md)\n", + "* 通用範例 General Examples\n", + " * [Ex 2: Concatenating multiple feature extraction methods](../general_examples/Ex2_feature_stacker.md)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Datasets/ipython_notebook/ex2_the_iris_dataset.ipynb b/Datasets/ipython_notebook/ex2_the_iris_dataset.ipynb new file mode 100644 index 0000000..56a8296 --- /dev/null +++ b/Datasets/ipython_notebook/ex2_the_iris_dataset.ipynb @@ -0,0 +1,297 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Datasets\n", + "\n", + "## 機器學習資料集/ 範例三: The iris dataset\n", + "\n", + "\n", + "http://scikit-learn.org/stable/auto_examples/datasets/plot_iris_dataset.html\n", + "\n", + "這個範例目的是介紹機器學習範例資料集中的iris 鳶尾花資料集\n", + "\n", + "\n", + "## (一)引入函式庫及內建手寫數字資料庫" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "([], )" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#這行是在ipython notebook的介面裏專用,如果在其他介面則可以拿掉\n", + "%matplotlib inline\n", + "\n", + "import matplotlib.pyplot as plt\n", + "from mpl_toolkits.mplot3d import Axes3D\n", + "from sklearn import datasets\n", + "from sklearn.decomposition import PCA\n", + "\n", + "# import some data to play with\n", + "iris = datasets.load_iris()\n", + "X = iris.data[:, :2] # we only take the first two features.\n", + "Y = iris.target\n", + "\n", + "x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5\n", + "y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5\n", + "\n", + "plt.figure(2, figsize=(8, 6))\n", + "plt.clf()\n", + "# Plot the training points\n", + "plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=plt.cm.Paired)\n", + "plt.xlabel('Sepal length')\n", + "plt.ylabel('Sepal width')\n", + "\n", + "plt.xlim(x_min, x_max)\n", + "plt.ylim(y_min, y_max)\n", + "plt.xticks(())\n", + "plt.yticks(())\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## (二)資料集介紹\n", + "`digits = datasets.load_digits()` 將一個dict型別資料存入digits,我們可以用下面程式碼來觀察裏面資料" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for key,value in iris.items() :\n", + " try:\n", + " print (key,value.shape)\n", + " except:\n", + " print (key)\n", + "print(iris['feature_names'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| 顯示 | 說明 |\n", + "| -- | -- |\n", + "| ('target_names', (3L,))| 共有三種鳶尾花 setosa, versicolor, virginica |\n", + "| ('data', (150L, 4L)) | 有150筆資料,共四種特徵 |\n", + "| ('target', (150L,))| 這150筆資料各是那一種鳶尾花|\n", + "| DESCR | 資料之描述 |\n", + "| feature_names| 四個特徵代表的意義,分別為 萼片(sepal)之長與寬以及花瓣(petal)之長與寬 \n", + "\n", + "為了用視覺化方式呈現這個資料集,下面程式碼首先使用PCA演算法將資料維度降低至3" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "X_reduced = PCA(n_components=3).fit_transform(iris.data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "接下來將三個維度的資料立用`mpl_toolkits.mplot3d.Axes3D` 建立三維繪圖空間,並利用 `scatter`以三個特徵資料數值當成座標繪入空間,並以三種iris之數值 Y,來指定資料點的顏色。我們可以看出三種iris中,有一種明顯的可以與其他兩種區別,而另外兩種則無法明顯區別。" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# To getter a better understanding of interaction of the dimensions\n", + "# plot the first three PCA dimensions\n", + "fig = plt.figure(1, figsize=(8, 6))\n", + "ax = Axes3D(fig, elev=-150, azim=110)\n", + "ax.scatter(X_reduced[:, 0], X_reduced[:, 1], X_reduced[:, 2], c=Y,\n", + " cmap=plt.cm.Paired)\n", + "ax.set_title(\"First three PCA directions\")\n", + "ax.set_xlabel(\"1st eigenvector\")\n", + "ax.w_xaxis.set_ticklabels([])\n", + "ax.set_ylabel(\"2nd eigenvector\")\n", + "ax.w_yaxis.set_ticklabels([])\n", + "ax.set_zlabel(\"3rd eigenvector\")\n", + "ax.w_zaxis.set_ticklabels([])\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iris Plants Database\n", + "\n", + "Notes\n", + "-----\n", + "Data Set Characteristics:\n", + " :Number of Instances: 150 (50 in each of three classes)\n", + " :Number of Attributes: 4 numeric, predictive attributes and the class\n", + " :Attribute Information:\n", + " - sepal length in cm\n", + " - sepal width in cm\n", + " - petal length in cm\n", + " - petal width in cm\n", + " - class:\n", + " - Iris-Setosa\n", + " - Iris-Versicolour\n", + " - Iris-Virginica\n", + " :Summary Statistics:\n", + "\n", + " ============== ==== ==== ======= ===== ====================\n", + " Min Max Mean SD Class Correlation\n", + " ============== ==== ==== ======= ===== ====================\n", + " sepal length: 4.3 7.9 5.84 0.83 0.7826\n", + " sepal width: 2.0 4.4 3.05 0.43 -0.4194\n", + " petal length: 1.0 6.9 3.76 1.76 0.9490 (high!)\n", + " petal width: 0.1 2.5 1.20 0.76 0.9565 (high!)\n", + " ============== ==== ==== ======= ===== ====================\n", + "\n", + " :Missing Attribute Values: None\n", + " :Class Distribution: 33.3% for each of 3 classes.\n", + " :Creator: R.A. Fisher\n", + " :Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov)\n", + " :Date: July, 1988\n", + "\n", + "This is a copy of UCI ML iris datasets.\n", + "http://archive.ics.uci.edu/ml/datasets/Iris\n", + "\n", + "The famous Iris database, first used by Sir R.A Fisher\n", + "\n", + "This is perhaps the best known database to be found in the\n", + "pattern recognition literature. Fisher's paper is a classic in the field and\n", + "is referenced frequently to this day. (See Duda & Hart, for example.) The\n", + "data set contains 3 classes of 50 instances each, where each class refers to a\n", + "type of iris plant. One class is linearly separable from the other 2; the\n", + "latter are NOT linearly separable from each other.\n", + "\n", + "References\n", + "----------\n", + " - Fisher,R.A. \"The use of multiple measurements in taxonomic problems\"\n", + " Annual Eugenics, 7, Part II, 179-188 (1936); also in \"Contributions to\n", + " Mathematical Statistics\" (John Wiley, NY, 1950).\n", + " - Duda,R.O., & Hart,P.E. (1973) Pattern Classification and Scene Analysis.\n", + " (Q327.D83) John Wiley & Sons. ISBN 0-471-22361-1. See page 218.\n", + " - Dasarathy, B.V. (1980) \"Nosing Around the Neighborhood: A New System\n", + " Structure and Classification Rule for Recognition in Partially Exposed\n", + " Environments\". IEEE Transactions on Pattern Analysis and Machine\n", + " Intelligence, Vol. PAMI-2, No. 1, 67-71.\n", + " - Gates, G.W. (1972) \"The Reduced Nearest Neighbor Rule\". IEEE Transactions\n", + " on Information Theory, May 1972, 431-433.\n", + " - See also: 1988 MLC Proceedings, 54-64. Cheeseman et al\"s AUTOCLASS II\n", + " conceptual clustering system finds 3 classes in the data.\n", + " - Many, many more ...\n", + "\n" + ] + } + ], + "source": [ + "#接著我們嘗試將這個機器學習資料之描述檔顯示出來\n", + "print(iris['DESCR'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "這個描述檔說明了這個資料集是在 1936年時由Fisher建立,為圖形識別領域之重要經典範例。共例用四種特徵來分類三種鳶尾花" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## (三)應用範例介紹\n", + "在整個scikit-learn應用範例中,有以下幾個範例是利用了這組iris資料集。\n", + "\n", + "* 分類法 Classification\n", + " * [EX 3: Plot classification probability](../Classification/ex3_Plot_classification_probability.md)\n", + "* 特徵選擇 Feature Selection\n", + " * [Ex 5: Test with permutations the significance of a classification score](../Feature_Selection/ex5_test_with_permutations_the_significance_of_a__.md)\n", + " * [Ex 6: Univariate Feature Selection](../Feature_Selection/ex6_univariate_feature_selection.md)\n", + "* 通用範例 General Examples\n", + " * [Ex 2: Concatenating multiple feature extraction methods](../general_examples/Ex2_feature_stacker.md)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Decision_trees/Decision_trees.md b/Decision_trees/Decision_trees.md new file mode 100644 index 0000000..9fd4536 --- /dev/null +++ b/Decision_trees/Decision_trees.md @@ -0,0 +1 @@ +# 決策樹 Decision trees diff --git a/Decision_trees/ex1_Decision_tree_regression.md b/Decision_trees/ex1_Decision_tree_regression.md new file mode 100644 index 0000000..45096ad --- /dev/null +++ b/Decision_trees/ex1_Decision_tree_regression.md @@ -0,0 +1,117 @@ + +## 決策樹/範例一: Decision Tree Regression +http://scikit-learn.org/stable/auto_examples/tree/plot_tree_regression.html#sphx-glr-auto-examples-tree-plot-tree-regression-py + +### 範例目的 +此範例利用Decision Tree從數據中學習一組if-then-else決策規則,逼近加有雜訊的sine curve,因此它模擬出局部的線性迴歸以近似sine curve。 +若決策樹深度越深(可由max_depth參數控制),則決策規則越複雜,模型也會越接近數據,但若數據中含有雜訊,太深的樹就有可能產生過擬合的情形。 +此範例模擬了不同深度的樹,當用帶有雜點的數據可能造成的情況。 + +### (一)引入函式庫及建立隨機數據資料 +#### 引入函式資料庫 +* `matplotlib.pyplot`:用來繪製影像。
+* `sklearn.tree import DecisionTreeRegressor`:利用決策樹方式建立預測模型。
+ +#### 特徵資料 +* `np.random()`:隨機產生介於0~1之間的亂數
+* `RandomState.rand(d0,d1,..,dn)`:給定隨機亂數的矩陣形狀
+* `np.sort`將資料依大小排序。
+ +#### 目標資料 +* `np.sin(X)`:以X做為徑度,計算出相對的sine值。
+* `ravel()`:輸出連續的一維矩陣。
+* `y[::5] += 3 * (0.5 - rng.rand(16))`:為目標資料加入雜訊點。
+ +```python +import numpy as np +from sklearn.tree import DecisionTreeRegressor +import matplotlib.pyplot as plt + +rng = np.random.RandomState(1) +X = np.sort(5* rng.rand(80, 1), axis=0) #0~5之間隨機產生80個數值 + +y = np.sin(X).ravel() +y[::5] += 3 * (0.5 - rng.rand(16)) #每5筆資料加入一個雜訊 +``` + +### (二)建立Decision Tree迴歸模型 +#### 建立模型 +* `DecisionTreeRegressor(max_depth = 最大深度)`:`DecisionTreeRegressor`建立決策樹回歸模型。`max_depth`決定樹的深度,若為None則所有節點被展開。此範例會呈現不同`max_depth`對預測結果的影響。 + +#### 模型訓練 +* `fit(特徵資料, 目標資料)`:利用特徵資料及目標資料對迴歸模型進行訓練。
+ +#### 預測結果 +* `np.arrange(起始點, 結束點, 間隔)`:`np.arange(0.0, 5.0, 0.01)`在0~5之間每0.01取一格,建立預測輸入點矩陣。
+* `np.newaxis`:增加矩陣維度。
+* `predict(輸入矩陣)`:對訓練完畢的模型測試,輸出為預測結果。
+ +```python +regr_1 = DecisionTreeRegressor(max_depth=2) #最大深度為2的決策樹 +regr_2 = DecisionTreeRegressor(max_depth=5) #最大深度為5的決策樹 + +regr_1.fit(X, y) +regr_2.fit(X, y) + +X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis] +y_1 = regr_1.predict(X_test) +y_2 = regr_2.predict(X_test) +``` + +### (三) 繪出預測結果與實際目標圖 +* `plt.scatter(X,y)`:將X、y以點的方式繪製於平面上,c為數據點的顏色,label為圖例。
+* `plt.plot(X,y)`:將X、y以連線方式繪製於平面上,color為線的顏色,label為圖例,linewidth為線的寬度。
+ + +```python +plt.figure() +plt.scatter(X, y, c="darkorange", label="data") +plt.plot(X_test, y_1, color="cornflowerblue", label="max_depth=2", linewidth=2) +plt.plot(X_test, y_2, color="yellowgreen", label="max_depth=5", linewidth=2) +plt.xlabel("data") #x軸代表data數值 +plt.ylabel("target") #y軸代表target數值 +plt.title("Decision Tree Regression") #標示圖片的標題 +plt.legend() #繪出圖例 +plt.show() +``` + +![](./image/DecisionTreeRegression.png) + +### (四)完整程式碼 + +```python +print(__doc__) + +# Import the necessary modules and libraries +import numpy as np +from sklearn.tree import DecisionTreeRegressor +import matplotlib.pyplot as plt + +# Create a random dataset +rng = np.random.RandomState(1) +X = np.sort(5 * rng.rand(80, 1), axis=0) +y = np.sin(X).ravel() +y[::5] += 3 * (0.5 - rng.rand(16)) + +# Fit regression model +regr_1 = DecisionTreeRegressor(max_depth=2) +regr_2 = DecisionTreeRegressor(max_depth=5) +regr_1.fit(X, y) +regr_2.fit(X, y) + +# Predict +X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis] +y_1 = regr_1.predict(X_test) +y_2 = regr_2.predict(X_test) + +# Plot the results +plt.figure() +plt.scatter(X, y, c="darkorange", label="data") +plt.plot(X_test, y_1, color="cornflowerblue", label="max_depth=2", linewidth=2) +plt.plot(X_test, y_2, color="yellowgreen", label="max_depth=5", linewidth=2) +plt.xlabel("data") +plt.ylabel("target") +plt.title("Decision Tree Regression") +plt.legend() +plt.show() +``` diff --git a/Decision_trees/ex2_Multi-output_Decision_Tree_Regression.md b/Decision_trees/ex2_Multi-output_Decision_Tree_Regression.md new file mode 100644 index 0000000..0780456 --- /dev/null +++ b/Decision_trees/ex2_Multi-output_Decision_Tree_Regression.md @@ -0,0 +1,130 @@ + +## 決策樹/範例二:Multi-output Decision Tree Regression +http://scikit-learn.org/stable/auto_examples/tree/plot_tree_regression_multioutput.html#sphx-glr-auto-examples-tree-plot-tree-regression-multioutput-py + +### 範例目的 +此範例用決策樹說明多輸出迴歸的例子,利用帶有雜訊的特徵及目標值模擬出近似圓的局部線性迴歸。 +若決策樹深度越深(可由max_depth參數控制),則決策規則越複雜,模型也會越接近數據,但若數據中含有雜訊,太深的樹就有可能產生過擬合的情形。 +此範例模擬了不同深度的樹,當用帶有雜點的數據可能造成的情況。 + +### (一)引入函式庫及建立隨機數據資料 +#### 引入函式資料庫 +* `matplotlib.pyplot`:用來繪製影像。
+* `sklearn.tree import DecisionTreeRegressor`:利用決策樹方式建立預測模型。
+ +#### 特徵資料 +* `np.random()`:隨機產生介於0~1之間的亂數
+* `RandomState.rand(d0,d1,..,dn)`:給定隨機亂數的矩陣形狀
+* `np.sort`將資料依大小排序。
+ +#### 目標資料 +* `np.sin(X)`:以X做為徑度,計算出相對的sine值。
+* `ravel()`:輸出連續的一維矩陣。
+* `y[::5, :] += (0.5 - rng.rand(20, 2))`:為目標資料加入雜訊點。
+ +```python +import numpy as np +from sklearn.tree import DecisionTreeRegressor +import matplotlib.pyplot as plt + +rng = np.random.RandomState(1) +X = np.sort(200 * rng.rand(100, 1) - 100, axis=0) #在-100~100之間隨機建立100個點 + +y = np.array([np.pi * np.sin(X).ravel(), np.pi * np.cos(X).ravel()]).T #每個X產生兩個輸出分別為sine及cosine值,並存於y中 +y[::5, :] += (0.5 - rng.rand(20, 2)) #每5筆資料加入一個雜訊 +``` + +### (二)建立Decision Tree迴歸模型 +#### 建立模型 +* `DecisionTreeRegressor(max_depth = 最大深度)`:`DecisionTreeRegressor`建立決策樹回歸模型。`max_depth`決定樹的深度,若為None則所有節點被展開。此範例會呈現不同`max_depth`對預測結果的影響。 + +#### 模型訓練 +* `fit(特徵資料, 目標資料)`:利用特徵資料及目標資料對迴歸模型進行訓練。
+ +#### 預測結果 +* `np.arrange(起始點, 結束點, 間隔)`:`np.arange(-100.0, 100.0, 0.01)`在-100~100之間每0.01取一格,建立預測輸入點矩陣。
+* `np.newaxis`:增加矩陣維度。
+* `predict(輸入矩陣)`:對訓練完畢的模型測試,輸出為預測結果。
+ +```python +# Fit regression model +regr_1 = DecisionTreeRegressor(max_depth=2) #最大深度為2的決策樹 +regr_2 = DecisionTreeRegressor(max_depth=5) #最大深度為5的決策樹 +regr_3 = DecisionTreeRegressor(max_depth=8) #最大深度為8的決策樹 +regr_1.fit(X, y) +regr_2.fit(X, y) +regr_3.fit(X, y) + +# Predict +X_test = np.arange(-100.0, 100.0, 0.01)[:, np.newaxis] +y_1 = regr_1.predict(X_test) +y_2 = regr_2.predict(X_test) +y_3 = regr_3.predict(X_test) +``` + +### (三) 繪出預測結果與實際目標圖 +* `plt.scatter(X,y)`:將X、y以點的方式繪製於平面上,c為數據點的顏色,s決定點的大小,label為圖例。
+ + +```python +plt.figure() +s = 50 +plt.scatter(y[:, 0], y[:, 1], c="navy", s=s, label="data") +plt.scatter(y_1[:, 0], y_1[:, 1], c="cornflowerblue", s=s, label="max_depth=2") +plt.scatter(y_2[:, 0], y_2[:, 1], c="c", s=s, label="max_depth=5") +plt.scatter(y_3[:, 0], y_3[:, 1], c="orange", s=s, label="max_depth=8") +plt.xlim([-6, 6]) #設定x軸的上下限 +plt.ylim([-6, 6]) #設定y軸的上下限 +plt.xlabel("target 1") #x軸代表target 1數值 +plt.ylabel("target 2") #x軸代表target 2數值 +plt.title("Multi-output Decision Tree Regression") #標示圖片的標題 +plt.legend() #繪出圖例 +plt.show() +``` + +![](./image/multi-outputDecisionTreeRegression.png) + +### (四)完整程式碼 + +```python +print(__doc__) + +import numpy as np +import matplotlib.pyplot as plt +from sklearn.tree import DecisionTreeRegressor + +# Create a random dataset +rng = np.random.RandomState(1) +X = np.sort(200 * rng.rand(100, 1) - 100, axis=0) +y = np.array([np.pi * np.sin(X).ravel(), np.pi * np.cos(X).ravel()]).T +y[::5, :] += (0.5 - rng.rand(20, 2)) + +# Fit regression model +regr_1 = DecisionTreeRegressor(max_depth=2) +regr_2 = DecisionTreeRegressor(max_depth=5) +regr_3 = DecisionTreeRegressor(max_depth=8) +regr_1.fit(X, y) +regr_2.fit(X, y) +regr_3.fit(X, y) + +# Predict +X_test = np.arange(-100.0, 100.0, 0.01)[:, np.newaxis] +y_1 = regr_1.predict(X_test) +y_2 = regr_2.predict(X_test) +y_3 = regr_3.predict(X_test) + +# Plot the results +plt.figure() +s = 50 +plt.scatter(y[:, 0], y[:, 1], c="navy", s=s, label="data") +plt.scatter(y_1[:, 0], y_1[:, 1], c="cornflowerblue", s=s, label="max_depth=2") +plt.scatter(y_2[:, 0], y_2[:, 1], c="c", s=s, label="max_depth=5") +plt.scatter(y_3[:, 0], y_3[:, 1], c="orange", s=s, label="max_depth=8") +plt.xlim([-6, 6]) +plt.ylim([-6, 6]) +plt.xlabel("target 1") +plt.ylabel("target 2") +plt.title("Multi-output Decision Tree Regression") +plt.legend() +plt.show() +``` diff --git a/Decision_trees/ex3_Plot_the_decision_surface_of_a_decision_tree_on_the_iris_dataset.md b/Decision_trees/ex3_Plot_the_decision_surface_of_a_decision_tree_on_the_iris_dataset.md new file mode 100644 index 0000000..bc81835 --- /dev/null +++ b/Decision_trees/ex3_Plot_the_decision_surface_of_a_decision_tree_on_the_iris_dataset.md @@ -0,0 +1,140 @@ + +## 決策樹/範例三: Plot the decision surface of a decision tree on the iris dataset +http://scikit-learn.org/stable/auto_examples/tree/plot_iris.html#sphx-glr-auto-examples-tree-plot-iris-py + +此範例利用決策樹分類器將資料集進行分類,找出各類別的分類邊界。以鳶尾花資料集當作範例,每次取兩個特徵做訓練,個別繪製不同品種的鳶尾花特徵的分布範圍。對於每對的鳶尾花特徵,決策樹學習推斷出簡單的分類規則,構成決策邊界。 + +### 範例目的: +1. 資料集:iris 鳶尾花資料集 +2. 特徵:鳶尾花特徵 +3. 預測目標:是哪一種鳶尾花 +4. 機器學習方法:decision tree 決策樹 + +### (一)引入函式庫及內建測試資料庫 + +* `from sklearn.datasets import load_iris`將鳶尾花資料庫存入,`iris`為一個dict型別資料。
+* 每筆資料中有4個特徵,一次取2個特徵,共有6種排列方式。
+* X (特徵資料) 以及 y (目標資料)。
+* `DecisionTreeClassifier` 建立決策樹分類器。
+ +```python +import numpy as np +import matplotlib.pyplot as plt + +from sklearn.datasets import load_iris +from sklearn.tree import DecisionTreeClassifier + +iris = load_iris() + +for pairidx, pair in enumerate([[0, 1], [0, 2], [0, 3], + [1, 2], [1, 3], [2, 3]]): + X = iris.data[:, pair] + y = iris.target +``` + +### (二)建立Decision Tree分類器 +#### 建立模型及分類器訓練 +* `DecisionTreeClassifier()`:決策樹分類器。
+* `fit(特徵資料, 目標資料)`:利用特徵資料及目標資料對分類器進行訓練。
+ +```python +clf = DecisionTreeClassifier().fit(X, y) +``` + +### (三)繪製決策邊界及訓練點 +* `np.meshgrid`:利用特徵之最大最小值,建立預測用網格 xx, yy
+* `clf.predict`:預估分類結果。
+* `plt.contourf`:繪製決策邊界。
+* `plt.scatter(X,y)`:將X、y以點的方式繪製於平面上,c為數據點的顏色,label為圖例。
+ +```python +plt.subplot(2, 3, pairidx + 1) + +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, plot_step), + np.arange(y_min, y_max, plot_step)) + + +Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) #np.c_ 串接兩個list,np.ravel將矩陣變為一維 + +Z = Z.reshape(xx.shape) + +cs = plt.contourf(xx, yy, Z, cmap=plt.cm.Paired) + +plt.xlabel(iris.feature_names[pair[0]]) +plt.ylabel(iris.feature_names[pair[1]]) +plt.axis("tight") + +for i, color in zip(range(n_classes), plot_colors): + idx = np.where(y == i) + plt.scatter(X[idx, 0], X[idx, 1], c=color, label=iris.target_names[i], + cmap=plt.cm.Paired) + +plt.axis("tight") +``` + +![](./image/Plot the decision surface of a decision tree on the iris dataset.png) + +### (四)完整程式碼 +```python +print(__doc__) + +import numpy as np +import matplotlib.pyplot as plt + +from sklearn.datasets import load_iris +from sklearn.tree import DecisionTreeClassifier + +# Parameters +n_classes = 3 +plot_colors = "bry" +plot_step = 0.02 + +# Load data +iris = load_iris() + +for pairidx, pair in enumerate([[0, 1], [0, 2], [0, 3], + [1, 2], [1, 3], [2, 3]]): + + # We only take the two corresponding features + X = iris.data[:, pair] + y = iris.target + # Train + clf = DecisionTreeClassifier().fit(X, y) + + # Plot the decision boundary + plt.subplot(2, 3, pairidx + 1) + + 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, plot_step), + np.arange(y_min, y_max, plot_step)) + + + Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) #np.c_ 串接兩個list,np.ravel將矩陣變為一維 + + Z = Z.reshape(xx.shape) + + + cs = plt.contourf(xx, yy, Z, cmap=plt.cm.Paired) + + plt.xlabel(iris.feature_names[pair[0]]) + plt.ylabel(iris.feature_names[pair[1]]) + plt.axis("tight") + + + # Plot the training points + for i, color in zip(range(n_classes), plot_colors): + idx = np.where(y == i) + plt.scatter(X[idx, 0], X[idx, 1], c=color, label=iris.target_names[i], + cmap=plt.cm.Paired) + + plt.axis("tight") + +plt.suptitle("Decision surface of a decision tree using paired features") +plt.legend() +plt.show() +``` diff --git a/Decision_trees/ex4_Understanding_the_decision_tree_structure.md b/Decision_trees/ex4_Understanding_the_decision_tree_structure.md new file mode 100644 index 0000000..6b3203e --- /dev/null +++ b/Decision_trees/ex4_Understanding_the_decision_tree_structure.md @@ -0,0 +1,366 @@ + +## 決策樹範例四: Understanding the decision tree structure +http://scikit-learn.org/stable/auto_examples/tree/plot_unveil_tree_structure.html#sphx-glr-auto-examples-tree-plot-unveil-tree-structure-py + +### 範例目的 +此範例主要在進一步探討決策樹內部的結構,分析以獲得特徵與目標之間的關係,並進而進行預測。
+1. 當每個節點的分支最多只有兩個稱之為二元樹結構。
+2. 判斷每個深度的節點是否為葉,在二元樹中若該節點為判斷的最後一層稱之為葉。
+3. 利用 `decision_path` 獲得決策路徑的資訊。
+4. 利用 `apply` 得到預測結果,也就是決策樹最後抵達的葉。
+5. 建立完成後的規則變能用來預測。
+6. 一組多個樣本可以尋得其中共同的決策路徑。
+ +### (一)引入函式庫及測試資料 +#### 引入函式資料庫 +* `load_iris` 引入鳶尾花資料庫。
+ +```python +from sklearn.model_selection import train_test_split +from sklearn.datasets import load_iris +from sklearn.tree import DecisionTreeClassifier +``` + +#### 建立訓練、測試集及決策樹分類器 +* X (特徵資料) 以及 y (目標資料)。
+* `train_test_split(X, y, random_state)` 將資料隨機分為測試集及訓練集。
+ X為特徵資料集、y為目標資料集,`random_state` 隨機數生成器。
+* `DecisionTreeClassifier(max_leaf_nodes, random_state)` 建立決策樹分類器。
+ `max_leaf_nodes` 節點為葉的最大數目,`random_state` 若存在則為隨機數生成器,若不存在則使用`np.random`。
+* `fit(X, y)` 用做訓練,X為訓練用特徵資料,y為目標資料。
+ +```python +iris = load_iris() +X = iris.data +y = iris.target +X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0) +estimator = DecisionTreeClassifier(max_leaf_nodes=3, random_state=0) +estimator.fit(X_train, y_train) +``` + + +### (二) 決策樹結構探討 +在`DecisionTreeClassifier` 中有個屬性 `tree_`,儲存了整個樹的結構。
+二元樹被表示為多個平行的矩陣,每個矩陣的第i個元素儲存著關於節點"i"的信息,節點0代表樹的根。
+需要注意的是,有些矩陣只適用於有分支的節點,在這種情況下,其他類型的節點的值是任意的。
+ +上述所說的矩陣包含了: +1. `node_count` :總共的節點個數。
+2. `children_left`:節點左邊的節點的ID,"-1"代表該節點底下已無分支。
+3. `children_righ`:節點右邊的節點的ID,"-1"代表該節點底下已無分支。
+4. `feature`:使節點產生分支的特徵,"-2"代表該節點底下已無分支。
+5. `threshold`:節點的閥值。若距離不超過 threshold ,則邊的兩端就視作同一個群集。 + +```python +n_nodes = estimator.tree_.node_count +children_left = estimator.tree_.children_left +children_right = estimator.tree_.children_right +feature = estimator.tree_.feature +threshold = estimator.tree_.threshold +``` +以下為各矩陣的內容 + +```python +n_nodes = 5 +children_left [ 1 -1 3 -1 -1] +children_right [ 2 -1 4 -1 -1] +feature [ 3 -2 2 -2 -2] +threshold [ 0.80000001 -2. 4.94999981 -2. -2. ] +``` + +二元樹的結構所通過的各個屬性是可以被計算的,例如每個節點的深度以及是否為樹的最底層。
+* `node_depth` :節點在決策樹中的深度(層)。
+* `is_leaves` :該節點是否為決策樹的最底層(葉)。
+* `stack`:存放尚未判斷是否達決策樹底層的節點資訊。
+ +將stack的一組節點資訊pop出來,判斷該節點的左邊節點ID是否等於右邊節點ID。
+若不相同分別將左右節點的資訊加入stack中,若相同則該節點已達底層`is_leaves`設為True。
+ + +```python +node_depth = np.zeros(shape=n_nodes) +is_leaves = np.zeros(shape=n_nodes, dtype=bool) + +stack = [(0, -1)] #initial + +while len(stack)> 0: + node_id, parent_depth = stack.pop() + node_depth[node_id] = parent_depth + 1 + + # If we have a test node + if (children_left[node_id] != children_right[node_id]): + stack.append((children_left[node_id], parent_depth + 1)) + stack.append((children_right[node_id], parent_depth + 1)) + else: + is_leaves[node_id] = True +``` + +執行過程 + +```python +stack len 1 +node_id 0 parent_depth -1 +node_depth [ 0. 0. 0. 0. 0.] +stack [(1, 0), (2, 0)] + +stack len 2 +node_id 2 parent_depth 0 +node_depth [ 0. 0. 1. 0. 0.] +stack [(1, 0), (3, 1), (4, 1)] + +stack len 3 +node_id 4 parent_depth 1 +node_depth [ 0. 0. 1. 0. 2.] +stack [(1, 0), (3, 1)] + +stack len 2 +node_id 3 parent_depth 1 +node_depth [ 0. 0. 1. 2. 2.] +stack [(1, 0)] + +stack len 1 +node_id 1 parent_depth 0 +node_depth [ 0. 1. 1. 2. 2.] +stack [] + +``` + +![](./image/Understanding the decision tree structure.png) + + + + +下面這個部分是以程式的方式印出決策樹結構,這個決策樹共有5個節點。
+若遇到的是test node則用閥值決定該往哪個節點前進,直到走到葉為止。
+ +```python +print("The binary tree structure has %s nodes and has " + "the following tree structure:" + % n_nodes) +for i in range(n_nodes): + if is_leaves[i]: + print("%snode=%s leaf node." % (node_depth[i] * "\t", i)) #"\t"縮排 + else: + print("%snode=%s test node: go to node %s if X[:, %s] <= %s else to " + "node %s." + % (node_depth[i] * "\t", + i, + children_left[i], + feature[i], + threshold[i], + children_right[i], + )) +``` + +執行結果 + +```python +The binary tree structure has 5 nodes and has the following tree structure: +node=0 test node: go to node 1 if X[:, 3] <= 0.800000011921 else to node 2. + node=1 leaf node. + node=2 test node: go to node 3 if X[:, 2] <= 4.94999980927 else to node 4. + node=3 leaf node. + node=4 leaf node. +``` + +接下來要來探索每個樣本的決策路徑,利用`decision_path`方法可以讓我們得到這些資訊,`apply`存放所有sample最後抵達哪個葉。
+以第0筆樣本當作範例,`indices`存放每個樣本經過的節點,`indptr`存放每個樣本存放節點的位置,`node_index`中存放了第0筆樣本所經過的節點ID。
+ +```python +node_indicator = estimator.decision_path(X_test) + +# Similarly, we can also have the leaves ids reached by each sample. + +leave_id = estimator.apply(X_test) + +# Now, it's possible to get the tests that were used to predict a sample or +# a group of samples. First, let's make it for the sample. + +sample_id = 0 +node_index = node_indicator.indices[node_indicator.indptr[sample_id]: + node_indicator.indptr[sample_id + 1]] +print('node_index', node_index) +print('Rules used to predict sample %s: ' % sample_id) +for node_id in node_index: + if leave_id[sample_id] != node_id: + continue + + if (X_test[sample_id, feature[node_id]] <= threshold[node_id]): + threshold_sign = "<=" + else: + threshold_sign = ">" + + print("decision id node %s : (X[%s, %s] (= %s) %s %s)" + % (node_id, + sample_id, + feature[node_id], + X_test[i, feature[node_id]], + threshold_sign, + threshold[node_id])) + +``` + +執行結果 + +```python +node_index [0 2 4] +Rules used to predict sample 0: +decision id node 4 : (X[0, -2] (= 1.5)> -2.0) +``` + +接下來是探討多個樣本,是否有經過相同的節點。
+以樣本0、1當作範例,`node_indicator.toarray()`存放多個矩陣0代表沒有經過該節點,1代表經過該節點。`common_nodes`中存放true與false,若同一個節點相加的值等於輸入樣本的各樹,則代表該節點都有被經過。 + + +```python +# For a group of samples, we have the following common node. +sample_ids = [0, 1] +common_nodes = (node_indicator.toarray()[sample_ids].sum(axis=0) == + len(sample_ids)) + +print('node_indicator',node_indicator.toarray()[sample_ids]) +print('common_nodes',common_nodes) + +common_node_id = np.arange(n_nodes)[common_nodes] +print('common_node_id',common_node_id) + + +print("\nThe following samples %s share the node %s in the tree" + % (sample_ids, common_node_id)) +print("It is %s %% of all nodes." % (100 * len(common_node_id) / n_nodes,)) +``` + +執行結果 + +```python +node_indicator [[1 0 1 0 1] + [1 0 1 1 0]] +common_nodes [ True False True False False] +common_node_id [0 2] + +The following samples [0, 1] share the node [0 2] in the tree +It is 40.0 % of all nodes. +``` + +### (三)完整程式碼 + +```python +import numpy as np + +from sklearn.model_selection import train_test_split +from sklearn.datasets import load_iris +from sklearn.tree import DecisionTreeClassifier + +iris = load_iris() +X = iris.data +y = iris.target +X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0) + +estimator = DecisionTreeClassifier(max_leaf_nodes=3, random_state=0) +estimator.fit(X_train, y_train) + +# The decision estimator has an attribute called tree_ which stores the entire +# tree structure and allows access to low level attributes. The binary tree +# tree_ is represented as a number of parallel arrays. The i-th element of each +# array holds information about the node `i`. Node 0 is the tree's root. NOTE: +# Some of the arrays only apply to either leaves or split nodes, resp. In this +# case the values of nodes of the other type are arbitrary! +# +# Among those arrays, we have: +# - left_child, id of the left child of the node +# - right_child, id of the right child of the node +# - feature, feature used for splitting the node +# - threshold, threshold value at the node +# + +# Using those arrays, we can parse the tree structure: + +n_nodes = estimator.tree_.node_count +children_left = estimator.tree_.children_left +children_right = estimator.tree_.children_right +feature = estimator.tree_.feature +threshold = estimator.tree_.threshold + + +# The tree structure can be traversed to compute various properties such +# as the depth of each node and whether or not it is a leaf. +node_depth = np.zeros(shape=n_nodes) +is_leaves = np.zeros(shape=n_nodes, dtype=bool) +stack = [(0, -1)] # seed is the root node id and its parent depth +while len(stack)> 0: + node_id, parent_depth = stack.pop() + node_depth[node_id] = parent_depth + 1 + + # If we have a test node + if (children_left[node_id] != children_right[node_id]): + stack.append((children_left[node_id], parent_depth + 1)) + stack.append((children_right[node_id], parent_depth + 1)) + else: + is_leaves[node_id] = True + +print("The binary tree structure has %s nodes and has " + "the following tree structure:" + % n_nodes) +for i in range(n_nodes): + if is_leaves[i]: + print("%snode=%s leaf node." % (node_depth[i] * "\t", i)) + else: + print("%snode=%s test node: go to node %s if X[:, %s] <= %ss else to " + "node %s." + % (node_depth[i] * "\t", + i, + children_left[i], + feature[i], + threshold[i], + children_right[i], + )) +print() + +# First let's retrieve the decision path of each sample. The decision_path +# method allows to retrieve the node indicator functions. A non zero element of +# indicator matrix at the position (i, j) indicates that the sample i goes +# through the node j. + +node_indicator = estimator.decision_path(X_test) + +# Similarly, we can also have the leaves ids reached by each sample. + +leave_id = estimator.apply(X_test) + +# Now, it's possible to get the tests that were used to predict a sample or +# a group of samples. First, let's make it for the sample. + +sample_id = 0 +node_index = node_indicator.indices[node_indicator.indptr[sample_id]: + node_indicator.indptr[sample_id + 1]] + +print('Rules used to predict sample %s: ' % sample_id) +for node_id in node_index: + if leave_id[sample_id] != node_id: + continue + + if (X_test[sample_id, feature[node_id]] <= threshold[node_id]): + threshold_sign = "<=" + else: + threshold_sign = ">" + + print("decision id node %s : (X[%s, %s] (= %s) %s %s)" + % (node_id, + sample_id, + feature[node_id], + X_test[i, feature[node_id]], + threshold_sign, + threshold[node_id])) + +# For a group of samples, we have the following common node. +sample_ids = [0, 1] +common_nodes = (node_indicator.toarray()[sample_ids].sum(axis=0) == + len(sample_ids)) + +common_node_id = np.arange(n_nodes)[common_nodes] + +print("\nThe following samples %s share the node %s in the tree" + % (sample_ids, common_node_id)) +print("It is %s %% of all nodes." % (100 * len(common_node_id) / n_nodes,)) + +``` diff --git a/Decision_trees/image/DecisionTreeRegression.png b/Decision_trees/image/DecisionTreeRegression.png new file mode 100644 index 0000000..20e63ec Binary files /dev/null and b/Decision_trees/image/DecisionTreeRegression.png differ diff --git a/Decision_trees/image/Plot the decision surface of a decision tree on the iris dataset.png b/Decision_trees/image/Plot the decision surface of a decision tree on the iris dataset.png new file mode 100644 index 0000000..88ffac0 Binary files /dev/null and b/Decision_trees/image/Plot the decision surface of a decision tree on the iris dataset.png differ diff --git a/Decision_trees/image/Understanding the decision tree structure.png b/Decision_trees/image/Understanding the decision tree structure.png new file mode 100644 index 0000000..7d16b3d Binary files /dev/null and b/Decision_trees/image/Understanding the decision tree structure.png differ diff --git a/Decision_trees/image/multi-outputDecisionTreeRegression.png b/Decision_trees/image/multi-outputDecisionTreeRegression.png new file mode 100644 index 0000000..2cad247 Binary files /dev/null and b/Decision_trees/image/multi-outputDecisionTreeRegression.png differ diff --git a/Feature_Selection/ex1_pipeline_anova_svm.md b/Feature_Selection/ex1_pipeline_anova_svm.md index aee6d73..16ed264 100644 --- a/Feature_Selection/ex1_pipeline_anova_svm.md +++ b/Feature_Selection/ex1_pipeline_anova_svm.md @@ -2,7 +2,7 @@ http://scikit-learn.org/stable/auto_examples/feature_selection/feature_selection_pipeline.html -此範例示範佇列的使用,依照順序執行ANOVA挑選主要特徵,並且使用C-SVM來計算特徵的權重與預測。 +此機器學習範例示範佇列的使用,依照順序執行ANOVA挑選主要特徵,並且使用C-SVM來計算特徵的權重與預測。 1. 使用 `make_classification` 建立模擬資料 2. 使用 `SelectKBest` 設定要用哪種目標函式,以挑出可提供信息的特徵 @@ -10,35 +10,10 @@ http://scikit-learn.org/stable/auto_examples/feature_selection/feature_selection 4. 用 `make_pipeline` 合併 SelectKBest物件 與 SVC物件 5. 用 `fit` 做訓練,並且以 `predict` 來做預測 -Python source code: [feature_selection_pipeline.py](http://scikit-learn.org/stable/_downloads/feature_selection_pipeline.py) -```python -from sklearn import svm -from sklearn.datasets import samples_generator -from sklearn.feature_selection import SelectKBest, f_regression -from sklearn.pipeline import make_pipeline - -# import some data to play with -X, y = samples_generator.make_classification( - n_features=20, n_informative=3, n_redundant=0, n_classes=4, - n_clusters_per_class=2) - -# ANOVA SVM-C -# 1) anova filter, take 3 best ranked features -anova_filter = SelectKBest(f_regression, k=3) -# 2) svm -clf = svm.SVC(kernel='linear') - -anova_svm = make_pipeline(anova_filter, clf) -anova_svm.fit(X, y) -anova_svm.predict(X) -``` --- ### (一)建立模擬資料 - - - 在選擇特徵之前需要有整理好的特徵與目標資料。在此範例中,將以`make_classification`功能建立特徵與目標。該功能可以依照使用者想模擬的情況,建立含有不同特性的模擬資料,像是總特徵數目,其中有幾項特徵含有目標資訊性、目標聚集的程度、目標分為幾類等等的特性。 @@ -84,10 +59,33 @@ anova_svm.predict(X) --- -##本章介紹到函式用法 +## (四)原始碼 + +### Python source code: [feature_selection_pipeline.py](http://scikit-learn.org/stable/_downloads/feature_selection_pipeline.py) + +```python +from sklearn import svm +from sklearn.datasets import samples_generator +from sklearn.feature_selection import SelectKBest, f_regression +from sklearn.pipeline import make_pipeline + +# import some data to play with +X, y = samples_generator.make_classification( + n_features=20, n_informative=3, n_redundant=0, n_classes=4, + n_clusters_per_class=2) +# ANOVA SVM-C +# 1) anova filter, take 3 best ranked features +anova_filter = SelectKBest(f_regression, k=3) +# 2) svm +clf = svm.SVC(kernel='linear') +anova_svm = make_pipeline(anova_filter, clf) +anova_svm.fit(X, y) +anova_svm.predict(X) +``` +## (五)函式用法 ###[`make_classification()`](http://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_classification.html) 的參數 diff --git a/Feature_Selection/ex2_Recursive_feature_elimination.md b/Feature_Selection/ex2_Recursive_feature_elimination.md index 43255ec..5cd31d2 100644 --- a/Feature_Selection/ex2_Recursive_feature_elimination.md +++ b/Feature_Selection/ex2_Recursive_feature_elimination.md @@ -1,49 +1,24 @@ + ## 特徵選擇/範例二: Recursive feature elimination http://scikit-learn.org/stable/auto_examples/feature_selection/plot_rfe_digits.html -本範例是示範以不斷減少影響判斷最小的特徵,來篩選特徵數目至指定數目,來作為訓練主要影響特徵。 +本範例主要目的是減少特徵數量來提升機器學習之預測準確度。 +主要方法是去不斷去剔除與資料分類關係轉少之特徵,來篩選特徵數目至指定數目。 1. 以`load_digits`取得內建的數字辨識資料 -2. 以`RFE`疊代方式刪去相對不具有目標影響力的特徵 +2. 以`RFE`疊代方式刪去相對不具有目標影響力的特徵. +### (一)產生內建的數字辨識資料 -Python source code: [plot_rfe_digits.py](http://scikit-learn.org/stable/_downloads/plot_rfe_digits.py) - -```Python -print(__doc__) - -from sklearn.svm import SVC -from sklearn.datasets import load_digits -from sklearn.feature_selection import RFE -import matplotlib.pyplot as plt +```python # Load the digits dataset digits = load_digits() X = digits.images.reshape((len(digits.images), -1)) y = digits.target - -# Create the RFE object and rank each pixel -svc = SVC(kernel="linear", C=1) -rfe = RFE(estimator=svc, n_features_to_select=1, step=1) -rfe.fit(X, y) -ranking = rfe.ranking_.reshape(digits.images[0].shape) - -# Plot pixel ranking -plt.matshow(ranking) -plt.colorbar() -plt.title("Ranking of pixels with RFE") -plt.show() ``` ---- -### (一)產生內建的數字辨識資料 -```Python -# Load the digits dataset -digits = load_digits() -X = digits.images.reshape((len(digits.images), -1)) -y = digits.target -``` 數位數字資料是解析度為8*8的手寫數字影像,總共有1797筆資料。預設為0~9十種數字類型,亦可由n_class來設定要取得多少種數字類型。 輸出的資料包含 @@ -60,38 +35,58 @@ y = digits.target `RFE`以排除最不具目標影響力的特徵,做特徵的影響力排序。並且將訓練用的特徵挑選至`n_features_to_select`所給定的特徵數。因為要看每一個特徵的影響力排序,所以我們將`n_features_to_select`設定為1,一般會根據你所知道的具有影響力特徵數目來設定該參數。而`step`代表每次刪除較不具影響力的特徵數目,因為本範例要觀察每個特徵的影響力排序,所以也是設定為1。若在實際應用時,特徵的數目較大,可以考慮將`step`的參數設高一點。 -```Python +```python # Create the RFE object and rank each pixel svc = SVC(kernel="linear", C=1) rfe = RFE(estimator=svc, n_features_to_select=1, step=1) rfe.fit(X, y) ranking = rfe.ranking_.reshape(digits.images[0].shape) ``` + 可以用方法`ranking_`來看輸入的特徵權重關係。而方法`estimator_`可以取得訓練好的分類機狀態。比較特別的是當我們核函數是以線性來做分類時,`estimator_`下的方法`coef_`即為特徵的分類權重矩陣。權重矩陣的大小會因為`n_features_to_select`與資料的分類類別而改變,譬如本範例是十個數字的分類,並選擇以一個特徵來做分類訓練,就會得到45*1的係數矩陣,其中45是從分類類別所需要的判斷式而來,與巴斯卡三角形的第三層數正比。 ### (三)畫出每個像素所對應的權重順序 -取得每個像素位置對於判斷數字的權重順序後,我們把權重順序依照顏色畫在對應的位置。 -``` +取得每個像素位置對於判斷數字的權重順序後,我們把權重順序依照顏色畫在對應的位置,數值愈大代表該像素是較不重要之特徵。由結果來看,不重要之特徵多半位於影像之外圍部份。而所有的訓練影像中,外圍像素多半為空白,因此較不重要。 + + +```python # Plot pixel ranking -plt.matshow(ranking) +plt.matshow(ranking, cmap=plt.cm.Blues) plt.colorbar() plt.title("Ranking of pixels with RFE") plt.show() ``` -![](http://scikit-learn.org/stable/_images/plot_rfe_digits_001.png) - +![png](images/ex2_fig.png) -##本章介紹到函式用法 +### (四)原始碼 +Python source code: [plot_rfe_digits.py](http://scikit-learn.org/stable/_downloads/plot_rfe_digits.py) +```python +print(__doc__) -###[`load_digits()`](http://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_digits.html#sklearn.datasets.load_digits) 的參數 +from sklearn.svm import SVC +from sklearn.datasets import load_digits +from sklearn.feature_selection import RFE +import matplotlib.pyplot as plt +# Load the digits dataset +digits = load_digits() +X = digits.images.reshape((len(digits.images), -1)) +y = digits.target +# Create the RFE object and rank each pixel +svc = SVC(kernel="linear", C=1) +rfe = RFE(estimator=svc, n_features_to_select=1, step=1) +rfe.fit(X, y) +ranking = rfe.ranking_.reshape(digits.images[0].shape) -```Python -sklearn.datasets.load_digits(n_class=10) +# Plot pixel ranking +plt.matshow(ranking, cmap=plt.cm.Blues) +plt.colorbar() +plt.title("Ranking of pixels with RFE") +plt.show() ``` diff --git a/Feature_Selection/ex3_rfe_crossvalidation__md.md b/Feature_Selection/ex3_rfe_crossvalidation__md.md index 6ae3de6..cda0a27 100644 --- a/Feature_Selection/ex3_rfe_crossvalidation__md.md +++ b/Feature_Selection/ex3_rfe_crossvalidation__md.md @@ -1,49 +1,15 @@ ##特徵選擇/範例三: Recursive feature elimination with cross-validation -http://scikit-learn.org/stable/auto_examples/feature_selection/plot_rfe_with_cross_validation.html#example-feature-selection-plot-rfe-with-cross-validation-py +http://scikit-learn.org/stable/auto_examples/feature_selection/plot_rfe_with_cross_validation.html -[待整理資料] REFCV比REF多一個交叉比對的分數(grid_scores_),代表選擇多少特徵後的準確率。但REFCV不用像REF要給定選擇多少特徵,而是會依照交叉比對的分數而自動選擇訓練的特徵數。 +REFCV比REF多一個交叉比對的分數(grid_scores_),代表選擇多少特徵後的準確率。但REFCV不用像REF要給定選擇多少特徵,而是會依照交叉比對的分數而自動選擇訓練的特徵數。 -本範例示範`RFE`的進階版,當我們在使用`RFE`指令時,需要輸入訓練特徵數目,讓訓練機能排除到其他較不具有影響力的特徵,也就是要有預期的訓練特徵數目。在`RFECV`指令提供了使用交叉驗證來選擇有最好準確率的訓練特徵數目。而交叉驗證也可以幫助我們避免訓練時造成**過度訓練(overfitting)**的現象,也就是當我們從某一組資料中挑出一筆訓練資料,能夠對剩下的測試資料預測出準確度最好的分類,卻發現這個分類機狀態無法準確的辨識新進資料的結果,因為這個最佳狀態只適用在特定的組合情況。因此使用`RFECV`後,我們可以從結果看出,使用多少特徵做分類判斷可以得到的準確率高低。 +本範例示範`RFE`的進階版,當我們在使用`RFE`指令時,需要輸入訓練特徵數目,讓訓練機能排除到其他較不具有影響力的特徵,也就是要有預期的訓練特徵數目。在`RFECV`指令提供了使用交叉驗證來選擇有最好準確率的訓練特徵數目。而交叉驗證也可以幫助我們避免訓練時造成過度訓練(overfitting)的現象,也就是當我們從某一組資料中挑出一筆訓練資料,能夠對剩下的測試資料預測出準確度最好的分類,卻發現這個分類機狀態無法準確的辨識新進資料的結果,因為這個最佳狀態只適用在特定的組合情況。因此使用`RFECV`後,我們可以從結果看出,使用多少特徵做分類判斷可以得到的準確率高低。 1. 以疊代方式計算模型 2. 以交叉驗證來取得影響力特徵 -Python source code: [plot_rfe_digits.py](http://scikit-learn.org/stable/_downloads/plot_rfe_with_cross_validation.py) - -```Python -print(__doc__) - -import matplotlib.pyplot as plt -from sklearn.svm import SVC -from sklearn.cross_validation import StratifiedKFold -from sklearn.feature_selection import RFECV -from sklearn.datasets import make_classification - -# Build a classification task using 3 informative features -X, y = make_classification(n_samples=1000, n_features=25, n_informative=3, - n_redundant=2, n_repeated=0, n_classes=8, - n_clusters_per_class=1, random_state=0) - -# Create the RFE object and compute a cross-validated score. -svc = SVC(kernel="linear") -# The "accuracy" scoring is proportional to the number of correct -# classifications -rfecv = RFECV(estimator=svc, step=1, cv=StratifiedKFold(y, 2), - scoring='accuracy') -rfecv.fit(X, y) - -print("Optimal number of features : %d" % rfecv.n_features_) - -# Plot number of features VS. cross-validation scores -plt.figure() -plt.xlabel("Number of features selected") -plt.ylabel("Cross validation score (nb of correct classifications)") -plt.plot(range(1, len(rfecv.grid_scores_) + 1), rfecv.grid_scores_) -plt.show() -``` - ### (一)建立模擬資料 ```Python @@ -83,11 +49,45 @@ print("Optimal number of features : %d" % rfecv.n_features_) 下圖的曲線表示選擇多少個特徵來做訓練,會得到多少的準確率。 -![](http://scikit-learn.org/stable/_images/plot_rfe_with_cross_validation_001.png) +![](images/ex3_fig.png) 可以看到選擇三個最具有影響力的特徵時,交叉驗證的準確率高達81.8%。與建立模擬資料的n_informative=3是相對應的。 +### (四) 原始碼出處 +Python source code: [plot_rfe_digits.py](http://scikit-learn.org/stable/_downloads/plot_rfe_with_cross_validation.py) + +```Python +print(__doc__) + +import matplotlib.pyplot as plt +from sklearn.svm import SVC +from sklearn.cross_validation import StratifiedKFold +from sklearn.feature_selection import RFECV +from sklearn.datasets import make_classification + +# Build a classification task using 3 informative features +X, y = make_classification(n_samples=1000, n_features=25, n_informative=3, + n_redundant=2, n_repeated=0, n_classes=8, + n_clusters_per_class=1, random_state=0) + +# Create the RFE object and compute a cross-validated score. +svc = SVC(kernel="linear") +# The "accuracy" scoring is proportional to the number of correct +# classifications +rfecv = RFECV(estimator=svc, step=1, cv=StratifiedKFold(y, 2), + scoring='accuracy') +rfecv.fit(X, y) + +print("Optimal number of features : %d" % rfecv.n_features_) + +# Plot number of features VS. cross-validation scores +plt.figure() +plt.xlabel("Number of features selected") +plt.ylabel("Cross validation score (nb of correct classifications)") +plt.plot(range(1, len(rfecv.grid_scores_) + 1), rfecv.grid_scores_) +plt.show() +``` ##本章介紹到函式用法 diff --git a/Feature_Selection/ex4_feature_selection_using_selectfrommodel_md.md b/Feature_Selection/ex4_feature_selection_using_selectfrommodel_md.md index f56a9ec..f809a6f 100644 --- a/Feature_Selection/ex4_feature_selection_using_selectfrommodel_md.md +++ b/Feature_Selection/ex4_feature_selection_using_selectfrommodel_md.md @@ -1,10 +1,8 @@ ##特徵選擇/範例四: Feature selection using SelectFromModel and LassoCV -http://scikit-learn.org/stable/auto_examples/feature_selection/plot_select_from_model_boston.html#example-feature-selection-plot-select-from-model-boston-py - -此範例是示範以`LassoCV`來挑選特徵,Lasso是一種用來計算稀疏矩陣的線性模形。在某些情況下是非常有用的,因為在此演算過程中會以較少數的特徵來找最佳解,基於參數有相依性的情況下,使變數的數目有效的縮減。因此,Lasso法以及它的變形式可算是壓縮參數關係基本方法。 -在某些情況下,此方法可以準確的偵測非零權重的值。([請參考此說明範例](http://scikit-learn.org/stable/auto_examples/applications/plot_tomography_l1_reconstruction.html#example-applications-plot-tomography-l1-reconstruction-py)) +http://scikit-learn.org/stable/auto_examples/feature_selection/plot_select_from_model_boston.html +此範例是示範以`LassoCV`來挑選特徵,Lasso是一種用來計算稀疏矩陣的線性模形。在某些情況下是非常有用的,因為在此演算過程中會以較少數的特徵來找最佳解,基於參數有相依性的情況下,使變數的數目有效的縮減。因此,Lasso法以及它的變形式可算是壓縮參數關係基本方法。在某些情況下,此方法可以準確的偵測非零權重的值。 Lasso最佳化的目標函數: @@ -15,6 +13,34 @@ Lasso最佳化的目標函數: 3. 提高`SelectFromModel`的`.threshold`使目標資訊性特徵數逼近預期的數目 + +### (一)取得波士頓房產資料 +``` +from sklearn.datasets import load_boston +from sklearn.feature_selection import SelectFromModel +from sklearn.linear_model import LassoCV + +# Load the boston dataset. +boston = load_boston() +X, y = boston['data'], boston['target'] +``` + +### (二)使用LassoCV功能來篩選具有影響力的特徵 +1. 由於資料的類型為連續數字,選用LassoCV來做最具有代表性的特徵選取。 +2. 當設定好門檻值,並做訓練後,可以用transform(X)取得計算過後,被認為是具有影響力的特徵以及對應的樣本,可以由其列的數目知道總影響力特徵有幾個。 +3. 後面使用了增加門檻值來達到限制最後特徵數目的 +4. 使用門檻值來決定後來選取的參數,其說明在下一個標題。 +5. 需要用後設轉換 + +### (三)設定選取參數的門檻值 +``` +while n_features> 2: + sfm.threshold += 0.1 + X_transform = sfm.transform(X) + n_features = X_transform.shape[1] +``` + +### (四)原始碼之出處 Python source code: [plot_select_from_model_boston.py](http://scikit-learn.org/stable/_downloads/plot_select_from_model_boston.py) ```Python @@ -62,12 +88,3 @@ plt.ylabel("Feature number 2") plt.ylim([np.min(feature2), np.max(feature2)]) plt.show() ``` -### (一)取得波士頓房產資料 - -### (二)使用LassoCV功能來篩選具有影響力的特徵 -由於資料的類型為連續數字,選用LassoCV來做最具有代表性的特徵選取。 -當設定好門檻值,並做訓練後,可以用transform(X)取得計算過後,被認為是具有影響力的特徵以及對應的樣本,可以由其列的數目知道總影響力特徵有幾個。 -後面使用了增加門檻值來達到限制最後特徵數目的 -使用門檻值來決定後來選取的參數,其說明在下一個標題。 -需要用後設轉換 -### (三)設定選取參數的門檻值 diff --git a/Feature_Selection/ex5_test_with_permutations_the_significance_of_a__.md b/Feature_Selection/ex5_test_with_permutations_the_significance_of_a__.md index 89017c0..1a8785e 100644 --- a/Feature_Selection/ex5_test_with_permutations_the_significance_of_a__.md +++ b/Feature_Selection/ex5_test_with_permutations_the_significance_of_a__.md @@ -2,33 +2,25 @@ http://scikit-learn.org/stable/auto_examples/feature_selection/plot_permutation_test_for_classification.html - -此範例主要是介紹當我們做機器學習分類時,分類標籤的數值是否影響分類的計算。因此隨機置換分類標籤以及隨機的訓練測試資料組(交叉驗證)來輸入分類機,針對不同類型的分類做對應的評分,統計出不同的資料與標籤組合所得到的準確度與標籤的顯著性。 +此範例主要是用於當我們做機器學習分類時,資料標籤為無大小關係的分類,也就是第一類與第二類並無前後大小關係的分類。由於輸入分類器的標籤仍為數值,但數值的大小可能影響分類結果,因此隨機置換分類標籤以及隨機的訓練測試資料組(交叉驗證)來輸入分類機,針對不同類型的分類做對應的評分,統計出不同的資料與標籤組合所得到的準確度與標籤的顯著性。 `permutation_test_score`提供了對分類標籤做隨機置換的功能,並依照給定的置換次數來計算不同的資料組合配上置換過標籤的組合,用交叉驗證來計算準確性分佈,並統計顯著性。計算過後可取得該分類機器的真實分數與經過數次組合後取得的分數。 +![](permutations.png) -1. 隨機置換分類資料的標籤 -2. 評估同一組訓練資料在不同的資料與標籤組合中,所表現的準確度與分佈情形 - - - -Python source code: [plot_select_from_model_boston.py](http://scikit-learn.org/stable/_downloads/plot_permutation_test_for_classification.py) +1. 資料集:鳶尾花 +2. 特徵:萼片(sepal)之長與寬以及花瓣(petal)之長與寬 +3. 預測目標:共有三種鳶尾花 setosa, versicolor, virginica +4. 機器學習方法:線性分類 +5. 探討重點:變換訓練資料分類的目標標籤,減少標籤數值對分類的影響 +6. 關鍵函式: `sklearn.cross_validation.permutation_test_score` -```Python -# Author: Alexandre Gramfort -# License: BSD 3 clause -print(__doc__) - -import numpy as np -import matplotlib.pyplot as plt - -from sklearn.svm import SVC -from sklearn.cross_validation import StratifiedKFold, permutation_test_score -from sklearn import datasets +【1】Ojala and Garriga. Permutation Tests for Studying Classifier Performance. The Journal of Machine Learning Research (2010) vol. 11 +### (一)取得鳶尾花資料 -############################################################################## +本範例使用`datasets.load_iris()`讀取具有4個資訊影響力特徵與150個樣本的鳶尾花資料,該資料被分類為三個類型。並且額外增加2200筆150長度的雜訊做為不具資訊影響力的特徵,來增加辨認複雜度。 +``` # Loading a dataset iris = datasets.load_iris() X = iris.data @@ -41,15 +33,33 @@ E = random.normal(size=(len(X), 2200)) # Add noisy data to the informative features for make the task harder X = np.c_[X, E] +``` +### (二)建立基本的支持向量分類機 +使用`SVC`建立最基本的支持向量分類機。並設定訓練交叉驗證的摺疊系數為2。 + +``` svm = SVC(kernel='linear') cv = StratifiedKFold(y, 2) +``` + +### (三)重複隨機變換訓練資料並統計準確率 +當整理好訓練資料,以及支持向量分類機的設定後,我們以`permutation_test_score`功能來測試不同的隨機訓練資料組合,以及對應的分類機分數。除了基本的支持向量機物件、訓練資料、訓練目標,還需要指定對分類結果的評分方式、交叉驗證物件。與重複隨機變換法有關的參數像是置換次數(預設為100)與使用CPU的數目(預設為1)也可依照使用者使用情況而改變。 +``` score, permutation_scores, pvalue = permutation_test_score( svm, X, y, scoring="accuracy", cv=cv, n_permutations=100, n_jobs=1) print("Classification score %s (pvalue : %s)" % (score, pvalue)) +``` +經過計算的結果,會給予實際的分類機分數、每次隨機置換的分數以及p-value。 + + +### (四)統計隨機置換資料算出來的分類機分數圖表 + +最後一個部分,就是把`permutation_test_score`算出來的結果以圖表的方式呈現。 +``` ############################################################################### # View histogram of permutation scores plt.hist(permutation_scores, 20, label='Permutation scores') @@ -70,10 +80,28 @@ plt.legend() plt.xlabel('Score') plt.show() ``` -### (一)取得鳶尾花資料 +![](http://scikit-learn.org/stable/_images/plot_permutation_test_for_classification_001.png) -本範例使用`datasets.load_iris()`讀取具有4個資訊影響力特徵與150個樣本的鳶尾花資料,該資料被分類為三個類型。並且額外增加2200筆150長度的雜訊做為不具資訊影響力的特徵,來增加辨認複雜度。 -``` + +### 原始碼出處 + +Python source code: [plot_select_from_model_boston.py](http://scikit-learn.org/stable/_downloads/plot_permutation_test_for_classification.py) + +```Python +# Author: Alexandre Gramfort +# License: BSD 3 clause + +print(__doc__) + +import numpy as np +import matplotlib.pyplot as plt + +from sklearn.svm import SVC +from sklearn.cross_validation import StratifiedKFold, permutation_test_score +from sklearn import datasets + + +############################################################################## # Loading a dataset iris = datasets.load_iris() X = iris.data @@ -86,33 +114,15 @@ E = random.normal(size=(len(X), 2200)) # Add noisy data to the informative features for make the task harder X = np.c_[X, E] -``` - -### (二)使用LassoCV功能來篩選具有影響力的特徵 -使用`SVC`建立最基本的支持向量分類機。並設定訓練交叉驗證的摺疊系數為2。 -``` svm = SVC(kernel='linear') cv = StratifiedKFold(y, 2) -``` -### (三)重複隨機變換訓練資料並統計準確率 -當整理好訓練資料,以及支持向量分類機的設定後,我們以`permutation_test_score`功能來測試不同的隨機訓練資料組合,以及對應的分類機分數。除了需要輸入訓練資料、訓練目標、支持向量機物件,還需要指定對分類結果評分的功能物件、交叉驗證形式。其他參數像是置換次數與使用CPU的數目若不輸入也有預設值,亦可由使用者變更。 - -``` score, permutation_scores, pvalue = permutation_test_score( svm, X, y, scoring="accuracy", cv=cv, n_permutations=100, n_jobs=1) print("Classification score %s (pvalue : %s)" % (score, pvalue)) -``` - -經過計算的結果,會給予實際的分類機分數、每次隨機置換的分數以及p-value。 - -### (四)統計隨機置換資料算出來的分類機分數圖表 - -最後一個部分,就是把`permutation_test_score`算出來的結果以圖表的方式呈現。 -``` ############################################################################### # View histogram of permutation scores plt.hist(permutation_scores, 20, label='Permutation scores') @@ -133,4 +143,3 @@ plt.legend() plt.xlabel('Score') plt.show() ``` -![](http://scikit-learn.org/stable/_images/plot_permutation_test_for_classification_001.png) diff --git a/Feature_Selection/ex6_univariate_feature_selection.md b/Feature_Selection/ex6_univariate_feature_selection.md index 9a8431c..dfbd1fa 100644 --- a/Feature_Selection/ex6_univariate_feature_selection.md +++ b/Feature_Selection/ex6_univariate_feature_selection.md @@ -3,14 +3,77 @@ http://scikit-learn.org/stable/auto_examples/feature_selection/plot_feature_selection.html -此範例示範主要影響力特徵的選擇。鳶尾花資料中會加入數個雜訊(不具影響力的特徵資訊)並且選擇主要影響力的特徵。選擇過程會畫出每個特徵的 p-value 與其在支持向量機中的權重。可以從圖表中看出主要影響力特徵的選擇會選出具有主要影響力的特徵,並且這些特徵會在支持向量機有相當大的權重。在所有的特徵裡面,只有最前面的四個特徵是對目標有意義的。我們可以看到在主要影響力特徵的選擇中,這些特徵的評分會相當高。而支持向量機會認定其中一個特徵有很大的權重,但也會用一些不具有影響力的特徵來做選擇判斷。在支持向量機增加權重之前就確定那些特徵較具有影響力,從而增加辨識率。 +此範例示範單變量特徵的選擇。鳶尾花資料中會加入數個雜訊特徵(不具影響力的特徵資訊)並且選擇單變量特徵。選擇過程會畫出每個特徵的 p-value 與其在支持向量機中的權重。可以從圖表中看出主要影響力特徵的選擇會選出具有主要影響力的特徵,並且這些特徵會在支持向量機有相當大的權重。 +在本範例的所有特徵中,只有最前面的四個特徵是對目標有意義的。我們可以看到這些特徵的單變量特徵評分很高。而支持向量機會賦予最主要的權重到這些具影響力的特徵之一,但也會挑選剩下的特徵來做判斷。在支持向量機增加權重之前就確定那些特徵較具有影響力,從而增加辨識率。 +1. 資料集:鳶尾花 +2. 特徵:萼片(sepal)之長與寬以及花瓣(petal)之長與寬 +3. 預測目標:共有三種鳶尾花 setosa, versicolor, virginica +4. 機器學習方法:線性分類 +5. 探討重點:使用單變量選擇(`SelectPercentile`)挑出訓練特徵,與直接將所有訓練特徵輸入的分類器做比較 +6. 關鍵函式: `sklearn.feature_selection.SelectPercentile` -1. 若資料的標籤非常明確,但樣本只是隨機、順序的改變,使得同樣的樣本數目變多。 -2. 因此在本範例中,介紹如何以交叉驗證算出資料的score與p-value +### (一)修改原本的鳶尾花資料 + +用`datasets.load_iris()`讀取鳶尾花的資料做為具有影響力的特徵,並以`np.random.uniform`建立二十個隨機資料做為不具影響力的特徵,並合併做為訓練樣本。 +```############################################################################### +# import some data to play with + +# The iris dataset +iris = datasets.load_iris() + +# Some noisy data not correlated +E = np.random.uniform(0, 0.1, size=(len(iris.data), 20)) + +# Add the noisy data to the informative features +X = np.hstack((iris.data, E)) +y = iris.target +``` +### (二)使用f-value作為判斷的基準來找主要影響力特徵 + +以`SelectPercentile`作單變量特徵的計算,以F-test(`f_classif`)來做為選擇的統計方式,挑選函式輸出結果大於百分之十的特徵。並將計算出來的單便量特徵分數結果做正規化,以便比較每特徵在使用單變量計算與未使用單變量計算的差別。 +``` +############################################################################### +# Univariate feature selection with F-test for feature scoring +# We use the default selection function: the 10% most significant features +selector = SelectPercentile(f_classif, percentile=10) +selector.fit(X, y) +scores = -np.log10(selector.pvalues_) +scores /= scores.max() +plt.bar(X_indices - .45, scores, width=.2, + label=r'Univariate score ($-Log(p_{value})$)', color='g') +``` +### (三)找出不計算單變量特徵的分類權重 +以所有特徵資料,以線性核函數丟入支持向量分類機,找出各特徵的權重。 +``` +############################################################################### +# Compare to the weights of an SVM +clf = svm.SVC(kernel='linear') +clf.fit(X, y) + +svm_weights = (clf.coef_ ** 2).sum(axis=0) +svm_weights /= svm_weights.max() + +plt.bar(X_indices - .25, svm_weights, width=.2, label='SVM weight', color='r') +``` +### (四)找出以單變量特徵選出的分類權重 + +以單變量特徵選擇選出的特徵,做為分類的訓練特徵,差別在於訓練的特徵資料是使用`selector.transform(X)`將`SelectPercentile`選擇的結果讀取出來,並算出以單變量特徵選擇做預先選擇後,該分類器的判斷權重。 +``` +clf_selected = svm.SVC(kernel='linear') +clf_selected.fit(selector.transform(X), y) + +svm_weights_selected = (clf_selected.coef_ ** 2).sum(axis=0) +svm_weights_selected /= svm_weights_selected.max() + +plt.bar(X_indices[selector.get_support()] - .05, svm_weights_selected, + width=.2, label='SVM weights after selection', color='b') +``` + +### (五)原始碼出處 Python source code: [plot_feature_selection.py](http://scikit-learn.org/stable/_downloads/plot_feature_selection.py) ```Python @@ -78,8 +141,3 @@ plt.axis('tight') plt.legend(loc='upper right') plt.show() ``` -### (一)修改原本的鳶尾花資料 - -### (二)使用f-value作為判斷的基準來找主要影響力特徵 -函式 SelectPercentile -### (三)設定選取參數的門檻值 diff --git a/Feature_Selection/ex_7comparison_of_f-test_and_mutual_information.md b/Feature_Selection/ex_7comparison_of_f-test_and_mutual_information.md new file mode 100644 index 0000000..6bc44f0 --- /dev/null +++ b/Feature_Selection/ex_7comparison_of_f-test_and_mutual_information.md @@ -0,0 +1,42 @@ +##特徵選擇/範例七: Comparison of F-test and mutual information + +[http://scikit-learn.org/stable/auto_examples/feature_selection/plot_f_test_vs_mi.html#sphx-glr-auto-examples-feature-selection-plot-f-test-vs-mi-py](http://scikit-learn.org/stable/auto_examples/feature_selection/plot_f_test_vs_mi.html#sphx-glr-auto-examples-feature-selection-plot-f-test-vs-mi-py) + +這個範例是解釋單變量選擇特徵的兩個方法,F-test statistics以及mutual information。單變量特徵選擇可以算是選擇特徵的預處理,用以判斷適當的特徵選擇方式。 + +此範例假設了三個特徵變數x1, x2, x3分布在0與1之間,並且依照下列公式模擬預測目標: +y = x1+ +sin(6 * pi * x2)+0.1 * N(0,1) 第三個特徵變量與預測目標無相關 + +下面的函式畫出了y與每個x_i之間的相依性,並且把F-test statistics以及mutual information的計算分數算出來,可以看到不同的變數影響方式在兩種方法會有不同的結果。 + +F-test 的結果只會關注線性相關的變數影響,該方法選擇x1作為最具有特徵影響力的變量。另一方面,mutual information方法可以選出經過不同函式呈現的目標變數特徵,而他選擇了X2作為最具有影響力的特徵,我們在直覺上認為能找出經過三角函數轉換過的特徵變數,更符合在這個例子中目標變數的影響方式。而兩種方法都準確的判斷x3與目標變數無相關性。 + +![](sphx_glr_plot_f_test_vs_mi_001.png) + +```print(__doc__) + +import numpy as np +import matplotlib.pyplot as plt +from sklearn.feature_selection import f_regression, mutual_info_regression + +np.random.seed(0) +X = np.random.rand(1000, 3) +y = X[:, 0] + np.sin(6 * np.pi * X[:, 1]) + 0.1 * np.random.randn(1000) + +f_test, _ = f_regression(X, y) +f_test /= np.max(f_test) + +mi = mutual_info_regression(X, y) +mi /= np.max(mi) + +plt.figure(figsize=(15, 5)) +for i in range(3): + plt.subplot(1, 3, i + 1) + plt.scatter(X[:, i], y) + plt.xlabel("$x_{}$".format(i + 1), fontsize=14) + if i == 0: + plt.ylabel("$y$", fontsize=14) + plt.title("F-test={:.2f}, MI={:.2f}".format(f_test[i], mi[i]), + fontsize=16) +plt.show() +``` \ No newline at end of file diff --git a/Feature_Selection/images/ex2_fig.png b/Feature_Selection/images/ex2_fig.png new file mode 100644 index 0000000..059ef60 Binary files /dev/null and b/Feature_Selection/images/ex2_fig.png differ diff --git a/Feature_Selection/images/ex3_fig.png b/Feature_Selection/images/ex3_fig.png new file mode 100644 index 0000000..e4fd97d Binary files /dev/null and b/Feature_Selection/images/ex3_fig.png differ diff --git a/Feature_Selection/intro.md b/Feature_Selection/intro.md index a282513..5bfa682 100644 --- a/Feature_Selection/intro.md +++ b/Feature_Selection/intro.md @@ -1,19 +1,27 @@ # Feature Selection 特徵選擇 +特徵選擇主要是以統計特徵與目標的相關性、或以疊代排序特徵影響目標影響力的方式來逐漸排除與目標較不相關的特徵,留下與目標最相近的特徵,使判斷準確率能夠提升。 +###範例一:Pipeline Anova SVM +以anova filter作為選擇特徵的依據,並示範以傳遞(Pipeline)的方式來執行特徵選擇的訓練。 -範例一 ![](images/EX1.png) -範例二 +###範例二:Recursive feature elimination +以重複排除最不具有特徵影響力的特徵,來減少訓練的特徵數目,直到指定的特徵數目。 ![](images/EX2.png) -範例三 +###範例三:Recursive feature elimination with cross-validation +除了重複排除不具影響力的特徵外,對每次排除特徵後計算準確度,以準確度最高的特徵數目作為選定訓練特徵數目的依據。 ![](images/EX3.png) -範例四 +###範例四:Feature selection using SelectFromModel and LassoCV +示範如何使用SelectFromModel函式來選擇給定的函式,並設置輸入函式的門檻值,用以判斷訓練的特徵數目。在本範例是使用LassoCV作為選擇的涵式。 ![](images/EX4.png) -範例五 +###範例五:Test with permutations the significance of a classification score +本範例示範當目標類型的特徵,並無數值的大小區分時,以置換分類目標的方式來找到最高準確率的特徵挑選結果。以避免因為特徵目標分類轉換為用以區分不同類型時造成的誤判。 ![](images/EX5.png) +###範例六:Univariate Feature Selection +本範例示範用SelectPercentile以統計的方式來做特徵的選擇,並比指定的判斷函式來挑選特徵。本範例的輸入涵式為ANOVA,並以計算的F-value來做為挑選特徵的判斷。 diff --git a/Feature_Selection/ipython_notebook/Untitled.ipynb b/Feature_Selection/ipython_notebook/Untitled.ipynb new file mode 100644 index 0000000..7e1370f --- /dev/null +++ b/Feature_Selection/ipython_notebook/Untitled.ipynb @@ -0,0 +1,94 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Automatically created module for IPython interactive environment\n", + "Optimal number of features : 3\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAtUAAAHuCAYAAABQ5vCYAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3Xm4XXV59//3nUAEQgiDEMYwSEFlEAcQhGIEBBwKSAXB\nOg9FKxWLWmirD/H5aRWtPtUH259Uap0RRIXWCaeDs8wkEMKQQJjCPGSETPfzx9qHnBzOsPbZZ521\nh/fruta111p77b3vE7bHT7651/cbmYkkSZKksZtUdwGSJElSpzNUS5IkSS0yVEuSJEktMlRLkiRJ\nLTJUS5IkSS0yVEuSJEktqjxUR8SxETE/Im6NiLOGeH7LiPheRNwQEX+MiOdXXZMkSZI0nioN1REx\nCTgPOAbYBzg1Ip476LJ/BK7LzBcAbwW+UGVNkiRJ0nireqT6IOC2zFyUmauBC4HjB13zfOCXAJl5\nC7BbRGxbcV2SJEnSuKk6VO8E3D3g+J7GuYFuAE4EiIiDgJnAzhXXJUmSJI2bjeouAPgU8PmIuBaY\nC1wHrB18UUS4nrokSZImRGZGM9dXHarvpRh57rdz49zTMnMp8I7+44i4A1g41Jtlmqu1odmzZzN7\n9uy6y1Cb8Xuhofi90FD8XmgoEU3laaD69o+rgD0jYteImAKcAlw28IKImB4RGzf23w1ckZnLKq5L\nkiRJGjeVjlRn5tqIOB24nCLAX5CZN0fEacXTeT7wPOCrEbEOuAl4Z5U1SZIkSeOt8p7qzPwJsPeg\nc18asP/Hwc9LZc2aNavuEtSG/F5oKH4vNBS/Fxov0Sl9yhGRnVKrJEmSOldENH2josuUS5IkSS0y\nVEuSJEktMlRLkiRJLTJUS5IkSS0yVEuSJEktMlRLkiRJLTJUS5IkSS0yVEuSJEktMlRLkiRJLTJU\nS5IkSS0yVEuSJEktMlRLkiRJLTJUS5IkSS0yVEuSJEktMlRLkiRJLTJUS5IkSS0yVEuSJEktMlRL\nkiRJLTJUS5IkSS0yVEuSJEktMlRLkiRJLTJUS5IkSS0yVEuSJEktMlRLkiRJLTJUS5IkSS0yVEuS\nJEktMlRLkiRJLTJUS5IkSS0yVEuSJEktMlRLkiRJLTJUS5IkSS0yVEuSJEktMlRLkiRJLTJUS5Ik\nSS0yVEuSJEktMlRLkiRJLTJUS5IkSS0yVEuSJEktMlRLkiRJLTJUS5IkSS0yVEuSJEktMlRLkiRJ\n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\nN0TEdRFxZUQcWnVNzTBUS5IkaTSVLlMeEZOAW4EjgfuAq4BTMnP+gGs2y8wVjf39gIsy83lDvNeE\nL1O+di1ssQXcfz9MmzahHy1JkqSatOMy5QcBt2XmosxcDVwIHD/wgv5A3bA5sK7imkq7/XbYfnsD\ntSRJkkZWdajeCbh7wPE9jXMbiIgTIuJm4L+Bd1RcU2lz5sB++9VdhSRJktrdRnUXAJCZPwB+EBGH\nAR8HXjnUdbNnz356f9asWcyaNavSuuynliRJ6n59fX309fW19B5V91QfDMzOzGMbx2cDmZnnjvCa\nBcCBmfnooPMT3lN9wgnwpjfB618/oR8rSZKkGrVjT/VVwJ4RsWtETAFOAS4beEFEPGfA/ouAKYMD\ndV0cqZYkSVIZlbZ/ZObaiDgduJwiwF+QmTdHxGnF03k+8JcR8RZgFbASOLnKmspasgQeeACe85zR\nr5UkSVJvq7T9YzxNdPvH738PH/gAXHnlhH2kJEmS2kA7tn90LFs/JEmSVJahehiGakmSJJVlqB6G\noVqSJEll2VM9hEzYcktYuBC22WZCPlKSJEltwp7qcbJoUbE0uYFakiRJZRiqh2DrhyRJkpphqB6C\noVqSJEnNMFQPwVAtSZKkZhiqh2ColiRJUjOc/WOQFSuKGxSXLIGNN6784yRJktRmnP1jHMybB3vt\nZaCWJElSeYbqQWz9kCRJUrMM1YOsXAmHHlp3FZIkSeok9lRLkiRJA9hTLUmSJNXAUC1JkiS1yFAt\nSZIktchQLUmSJLXIUC1JkiS1yFAtSZIktchQLUmSJLXIUC1JkiS1yFAtSZIktchQLUmSJLXIUC1J\nkiS1yFAtSZIktchQLUmSJLXIUC1JkiS1yFAtSZIktchQLUmSJLXIUC1JkiS1yFAtSZIktchQLUmS\nJLXIUC1JkiS1yFAtSZIktchQLUmSJLXIUC1JkiS1yFAtSZIktchQLUmSJLXIUC1JkiS1yFAtSZIk\ntchQLUmSJLXIUC1JkiS1yFAtSZIktchQLUmSJLXIUC1JkiS1yFAtSZIktchQLUmSJLXIUC1JkiS1\nyFAtSZIktchQLUmSJLXIUC1JkiS1yFAtSZIktchQLUmSJLXIUC1JkiS1qPJQHRHHRsT8iLg1Is4a\n4vk3RsQNje23EbFf1TWpe/T19dVdgtqQ3wsNxe+FhuL3QuOl0lAdEZOA84BjgH2AUyPiuYMuWwgc\n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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "print(__doc__)\n", + "\n", + "import matplotlib.pyplot as plt\n", + "from sklearn.svm import SVC\n", + "from sklearn.model_selection import StratifiedKFold\n", + "from sklearn.feature_selection import RFECV\n", + "from sklearn.datasets import make_classification\n", + "\n", + "# Build a classification task using 3 informative features\n", + "X, y = make_classification(n_samples=1000, n_features=25, n_informative=3,\n", + " n_redundant=2, n_repeated=0, n_classes=8,\n", + " n_clusters_per_class=1, random_state=0)\n", + "\n", + "# Create the RFE object and compute a cross-validated score.\n", + "svc = SVC(kernel=\"linear\")\n", + "# The \"accuracy\" scoring is proportional to the number of correct\n", + "# classifications\n", + "rfecv = RFECV(estimator=svc, step=1, cv=StratifiedKFold(2),\n", + " scoring='accuracy')\n", + "rfecv.fit(X, y)\n", + "\n", + "print(\"Optimal number of features : %d\" % rfecv.n_features_)\n", + "\n", + "# Plot number of features VS. cross-validation scores\n", + "#plt.figure()\n", + "fig = plt.figure(figsize=(12,8), dpi=300)\n", + "plt.xlabel(\"Number of features selected\")\n", + "plt.ylabel(\"Cross validation score (nb of correct classifications)\")\n", + "plt.plot(range(1, len(rfecv.grid_scores_) + 1), rfecv.grid_scores_)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Feature_Selection/ipython_notebook/ex2_Recursive_feature_elimination.ipynb b/Feature_Selection/ipython_notebook/ex2_Recursive_feature_elimination.ipynb new file mode 100644 index 0000000..5e6c86a --- /dev/null +++ b/Feature_Selection/ipython_notebook/ex2_Recursive_feature_elimination.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 特徵選擇/範例二: Recursive feature elimination\n", + "\n", + "http://scikit-learn.org/stable/auto_examples/feature_selection/plot_rfe_digits.html\n", + "\n", + "本範例主要目的是減少特徵數量來提升機器學習之預測準確度。\n", + "主要方法是去不斷去剔除與資料分類關係轉少之特徵,來篩選特徵數目至指定數目。\n", + "\n", + "1. 以`load_digits`取得內建的數字辨識資料\n", + "2. 以`RFE`疊代方式刪去相對不具有目標影響力的特徵\n", + "\n", + "### (一)產生內建的數字辨識資料" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Load the digits dataset\n", + "digits = load_digits()\n", + "X = digits.images.reshape((len(digits.images), -1))\n", + "y = digits.target" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "數位數字資料是解析度為8*8的手寫數字影像,總共有1797筆資料。預設為0~9十種數字類型,亦可由n_class來設定要取得多少種數字類型。\n", + "\n", + "輸出的資料包含\n", + "1. ‘data’, 特徵資料(1797*64)\n", + "2. ‘images’, 影像資料(1797\\*8*8)\n", + "3. ‘target’, 資料標籤(1797)\n", + "4. ‘target_names’, 選取出的標籤列表(與n_class給定的長度一樣)\n", + "5. ‘DESCR’, 此資料庫的描述\n", + "\n", + "可以參考Classification的Ex1\n", + "\n", + "### (二)以疊代方式計算模型\n", + "\n", + "`RFE`以排除最不具目標影響力的特徵,做特徵的影響力排序。並且將訓練用的特徵挑選至`n_features_to_select`所給定的特徵數。因為要看每一個特徵的影響力排序,所以我們將`n_features_to_select`設定為1,一般會根據你所知道的具有影響力特徵數目來設定該參數。而`step`代表每次刪除較不具影響力的特徵數目,因為本範例要觀察每個特徵的影響力排序,所以也是設定為1。若在實際應用時,特徵的數目較大,可以考慮將`step`的參數設高一點。" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create the RFE object and rank each pixel\n", + "svc = SVC(kernel=\"linear\", C=1)\n", + "rfe = RFE(estimator=svc, n_features_to_select=1, step=1)\n", + "rfe.fit(X, y)\n", + "ranking = rfe.ranking_.reshape(digits.images[0].shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "可以用方法`ranking_`來看輸入的特徵權重關係。而方法`estimator_`可以取得訓練好的分類機狀態。比較特別的是當我們核函數是以線性來做分類時,`estimator_`下的方法`coef_`即為特徵的分類權重矩陣。權重矩陣的大小會因為`n_features_to_select`與資料的分類類別而改變,譬如本範例是十個數字的分類,並選擇以一個特徵來做分類訓練,就會得到45*1的係數矩陣,其中45是從分類類別所需要的判斷式而來,與巴斯卡三角形的第三層數正比。\n", + "\n", + "### (三)畫出每個像素所對應的權重順序\n", + "\n", + "取得每個像素位置對於判斷數字的權重順序後,我們把權重順序依照顏色畫在對應的位置,數值愈大代表該像素是較不重要之特徵。由結果來看,不重要之特徵多半位於影像之外圍部份。而所有的訓練影像中,外圍像素多半為空白,因此較不重要。" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPIAAADyCAYAAAB3aJikAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAHKpJREFUeJzt3Xu8VNV99/HPdw43EUGuKiAoJigQFFBBQUWNJooJtn1i\noqamMX2a1uQRXzX1VYNtTdLH1DRNovYxfcVEeRkrMZF6aRqjmGJRQAS5yBFQUZA7qAEhCCgcfs8f\ne89hGOayz9l7n7Nn+L19nZdz2fs3a4b5zVp7rb3WlpnhnKttufYugHMuPk9k5+qAJ7JzdcAT2bk6\n4InsXB3wRHauDngiO9eOJPWQ9KiklZKWSxpX8Nw3JB2Q1KtanA7pFtM5V8XdwFNmdpWkDkBXAEkD\ngUuBtVGCeI3sXDuR1B0438ymAZjZfjPbGT79I+CWqLE8kZ1rPycD70maJmmxpPskdZU0GVhvZo1R\nA9VVIku6XdJDZZ77pqT72qFM/SQ9L2mHpO+3Yv8/SDopZhkGh8daqfx7S/o3SbdVeL7sv8sRrgMw\nBrjXzMYAHwDfAqYCtxdsp2qB2jyRJb0tabeknZI2hb9GXRN8iZInj5vZP5nZVxN8nai+CrxjZj3M\nLHJTKc/MjjGztxMoR2on1ZvZDWZ2B4CkiZLWx3n98EfnD+F3ZL2kH0hSwfP/I2lP+Hx+u3El9s3/\n/29iv8lS5ezU3SRF/dtSIsQGgpr35fD+fxAk9knAK5LWAAOBRZL6VSpLe3R2GXCFmT0XFm4m8E3g\n79uhLG1hMLCivQvRhkT8Hw0DTjezNZKGAM8TfIb3Fzz/tfyxZbl9Y5ahun1/oMvoGyNtunfJvx5X\n/JiZbQ1/qIaa2RvAJ4FFZnZJfpswmceY2fZK8duraS0AM3sHeAYY1fyENCk8Xtghaa2k2wueyzcR\nvxQ+946kqSVfQOog6Rdh136HwuZdtTiSukh6UNK2cEjgljK1TH778ZIWSNou6SVJ54aPTwP+DPjb\nsGa4uMS+08Km6cxwm+ckDSp4/oCkIZI6Sloi6f+Ej+ckzZH0d+F9SbpV0puS3pX0iKRjy5T3y5Le\nCl/vLUnXlNimc9hy6hXev03SPkndwvvfkfTDgvfwnbBl9RTQv6A2PD4M2Tn8THdKapQ0ptznSfD9\nyH9HVgNzKfiOFGxTcd82IUX7K28K8LCkpcAZwHeLnjey2LQupKCL/XJgVcHDu4DrzKwHcAXwVwoO\n/gtNAD4OXAL8g6RTi+J2AZ4AdgOfN7P94VPFNUW5ON8CBhE0cS4F/rTEvvnX6gn8F3AX0Jugt/E3\nknqa2fXAw8D3zKy7mc0q81FcC3w73P+VcJ88AzCzfWE5vi3pNIJWTA64I9xuCjAZOB/oD2wHflyi\nvF0Jhjw+bWbdgfHA0uLtzOxDYAEwMXzoAuBtgs+M8PH/KdpnN8G/56bwkKC7meWblJ8FpgM9gF8D\n95b5LIrLe1r4nt6Msn2bUy7aXxlm9oqZnW1mo8zsT8xsR9HzQ8xsW7VitFciPyFpJ7AO2EqQOACY\n2fNmtjy8/SrwCAe/TBB8sb9lZh+Z2TKCL/4ZBc/3AJ4GVpnZn1v5CdeV4lwF3GFmO81sE3BPhfdy\nBfCGmU03swNm9gjwGsEXN6rfmNncMFlvA86VNCB8rvnXOPxc/i/Bj9TNwJ8WvL+/BG4zs81hnO8A\nn1PpDq4mYKSkLma21cxWlinX88BESQ3A6QSfw0RJnYGzgRda8B7nmNkzYXkfCuNVsljSLoIm9XMc\n/qN0T9hi2i7p5RL75p/bJunSFpSzZXIN0f5S1l6JfGVYG0wETgP65J+QNFbSrLC5+z7BF7RP0f5b\nC27vBroV3D8HGAl8L0I5ysXpT9ARkVe2WR1uWzxovxYYUGLbcprjm9kHwLYwbik/JzjufipsduYN\nBh4Pv7jbCBJgH3DIsVlYa34BuAHYLOnXxS2aArOBiwg6YJYBzwIXEnzGq6odtxUp7OzZDXQp8yOT\nN9rMugGfB8YBRxc9P8XMeplZTzM7q8S++ed6mdmzLShny8RvWieivY+RXwAeBH5Q8Nx0ghpngJkd\nC/yECMcIBZ4B/gmYpSo9fRVsJugtzBtUbkNgE0ETvNAgYGMLXu/E/I3wGLRXhf1/TNA0/bSkCQWP\nrwMuD7+4+S/x0Wa2uTiAmT1rZp8CjgdeB35a5rXmAacCfwzMNrPXwvc2iSDJS0mqdzz/HZkBzOfQ\n4ZhI+7aJmE3rpGRhHPku4FJJI8P73YDtZrZP0liC48dCVf+RzOxfCH4Q/ltS7zKbVYrzK+Cbko4N\nm7hfr7DtU8DHJV0tqUHSF4BhBMfNUU0KO8w6Af8IvBg26Q8tsHQdQe34ZeAm4EEdHLr7CfDdfEeZ\npL5FfQsKH+8naXK43z6CPommUoUysz3AIoL3n0/cecBfUT6RtwK9FZy1VElLku1O4C9i/DCn5wiu\nkQ/5xTaz9whq5X8IH/o68I+SdgB/B/yy0v4l7ufj5o8lny3Te1spzncIasQ1BMNjjwIflnmdbcBn\ngL8B3gv/f0VBB0WUGmo6QT/B74HRBJ1ah5RL0onADwk6Aneb2S+AhQSdaxB0YD0JzAw/u3nA2BLv\nL0dwfL0xLO8FBM3scmYDDQQdX/n73QiOn4tjY2avA78AVofN/OMprdLnUvwdeTV83VtKPV9i31d0\n6DjyDytsH09GamS15eJ7ki4jqIFzwP1mFuU4Nkrc+wmSaauZVetEaUncgQTHpKcB3YGpZlap4ytq\n3M4EidCJ4Nh2mZldGDduQfwc8DKwwcyKe/zjxH0b2AEcAPaZ2djKe0SO2wP4GfCJMPZXzOylBOIO\nJagI8kM4Q4C/T+LfMIxvXcaXHP08zN5538XMUqua26xGDr9c/w/4NDACuCYcWkjCtDBuIiQdL2k8\nsJ+gpvuA4Bjt60mUORzaucjMRgP/CXwsPIxIyk2kcxLKAeBCMxudVBKH8jOAhhGMHJTrRW8RM3sj\nLOsY4EyCf8fHk4jdLCM1cls2rccS9HSuDYdHHgGuTCKwmc0hGDdNSieCY85VBD8+jxN82VbSst7o\nssLeYwhqihwJdRKFrYhJBDVc0vJlTS5g5RlASboEeMvMKo1AtFxGhp/a8hTNARw6jLOBQ4/hMsPM\n1hEMYTVTMHFhFBC7yRfGyxF0JJ1CcNL8wiTicnD6W4+E4hUygj6HJuA+MyvX290SzTOACGrjl4Gb\nwo62JH2B4Ng9WW1Q20aRjVJkXDgkNIPgC7YriZjhySOjCYa5xkkaHjempCsI+gmWks6pihPCZuok\ngsOM8xKIWTwDaDdwawJxm0nqSHDW26NJxgUgp2h/KWvLRN7IoeOxA2nZWGu7ULBqwwzgITN7Mun4\nYTPyOeCyBMJNACZLWk1Q+1wk6ecJxAUgPyZtZu8SHG4k0aIqngE0gyCxk3Q5wWSEdxOOe0QeIy8k\n6NQZHI6XXk3Q0ZOUtE6WfwBYYWZ3JxVQUp+wpxZJRxGcz/1a3LhmNtXMBpnZEILPd5aZfSluXAjO\n0S6YMHE08Cng1bhxzWwrsD7sYYZgBlDSHXXXkEazGjIzjtxmx8hm1qRg5s5MDg4/JdI7KWk6wamD\nvSWtA2630lPcWhp3AvBFoFHSEoJjxKlm9nTM0CcQnMyRI/gsfmlmT8WMmbbjCE4BNYLvzcNmNjOh\n2PkZQB2B1cD1CcXNTxK5hGBeePIycozcpuPIztUTSdblkjsjbbv3d7emOo7sq2g6F0cbDC1F4Yns\nXBwZaVp7IjsXRxt0ZEXhiexcHPVWI4e9mc7VvBZ1StVjjdxlVKVpuwft27yAjidEO5eg17mfjPz6\nOxc+Qvezr468/RcnRTuZau70f2XCtdFWSwQY3b94MYvyZvzkh3zuL2+OtO1ZA6peAqjZPd+/gym3\nlF1q+jDv7Cw5S/Mw999zJ38+JfqJVw8s3lB9o9DiR3/MmKu+Fnn73/z365G227XoV3Q78/ORtt36\n06sivz5QfzWyc0ekmIlcbmqopBuBrxHMwPuNmVX89fREdi6O+MNP+amhzbP3JF1IsHjjSDPbL6l4\nzbrDtEsi57olMhPwMJ37fyKVuCeOTG+S1vAzz00l7rjx56cSd/S4JOZJlHbC8LNTidvphBGpxAWS\nOEYuNTX0BuBOC5dxDlfRqahdGvgNx6SUyAPSSeRBI8dV36iVhp+VUiJPuCCVuGPSTOQRKSVy/zQT\nOfakifzU0IWS/nf42FDgAknzFVywoHiV0MN409q5OMrUyE3vvsaB9yJ1xk0ws82S+hKst/Y6QV72\nNLNzJJ1NsBjkkEpBIiVyWmttOVfrVCaRO/QbBv2GNd/f89qvS25XODVU0hMEU0PXA4+Fjy9UcNmg\n3mb2+3LlqNq0TnmtLedqmqRIf2X2LTU1tJFg9deLw8eHAh0rJTFEq5Gb19oKA+fX2oo9f9a5Wqd4\nq3+UnBoaTud8QFIjwTLMVeeUR0nkmllry7m2Vq62jcKCS78WX2Uyf8G+61oSK9HOrn2bFzTfznUb\nkFrvtHNJ+WjTcj7avLzV+8dJ5CRFSeTIa21FPe3Suazo1H/EIcNTHyxu2fp8WUnkKOPIaa+15Vzt\nUsS/lFWtkdNca8u5WpeVGjnSMXK42Fy5a+g6d8SqqUR2zpWWy/k0RudqXzYqZE9k5+LwprVzdcAT\n2bk6UJ+JPDD5eZ/nnjWo+kat1KlDOv8Id898K5W4/3ZN91TiAjy6YksqcZe+UXVOfKs17W9KLXZk\n2chjr5Gdi6M+a2TnjjA+/ORcHfAa2bl6kI089kR2Lg6vkZ2rA57IztWBrCRylMX37pe0VdKytiiQ\nczUlI/ORo/SdTyNYQdM5VySXy0X6q0RSTtISSf8Z3h8l6cXwsQVRFqivmshmNgfYXm07545EcZbD\nLXATULhw2PeA281sNHA78P1qAbIxmu1cjYqbyJIGApOAnxU8fADoEd4+ljJr5BVKdhXN1/+r+Xau\n91Aa+gxNMrxzifto83L2bVnR+gDxj39/BNzCwcQF+GvgGUk/CF9hfLUgiSZyx1M/k2Q451LX6YQR\nh1ytcc/S/2jR/uVq2z3rl7F3Q2O1fa8AtprZ0vBSqnk3ADeZ2ROSPgc8AFxaKVbURG6jvjfnaku5\nRO466Ay6Djqj+f7786eX2mwCMFnSJOAo4BhJDwGfMbObAMxshqT7q5UjyvDTdGAeMFTSOknXV9vH\nuSOFFO2vFDObamaDzGwIwTLTs8zsOmCTpIlBfH0SeKNaOaIsh3ttS96Yc0eSXLxrP5XzVeBuSQ3A\n3vB+RX5ml3MxJHVml5nNBmaHt+cCVceOC3kiOxdDRs7Q9ER2Lo6UmtYt5onsXAxeIztXB7Iy+8kT\n2bkY6rJp3emYbkmGA+C9nXsTj5k38dx0ltr9o1OPSyXuzNXvphIX4ObzTk4l7uubdqYSF2DNqvZf\nDtdrZOfqQEby2BPZuTi8RnauDmQkjz2RnYvDa2Tn6kBG8tgT2bk4sjL8FGUa40BJsyQtl9QoaUpb\nFMy5WpDQml2xRamR9wM3h6sYdAMWSZppZq+lXDbnMq9mmtZmtgXYEt7eJWklMADwRHZHvJrs7JJ0\nEjAKeCmNwjhXazKSx9ETOWxWzyBYFGxXekVyrnbUVI0sqQNBEj9kZk+W225v42MHA/cbRofjhsUu\noHNp2rdlBfu3rmz1/hnJ48g18gPACjO7u9JGXUb+SfwSOdeGOh4/nI7HD2++v3fZYxW2Ply1y8G0\nlSjDTxOALwIXh9eiWSzpsvSL5lz2xVlF82AM5cK8yl/7qaekmZJel/SMpB6VI0S79tNcM2sws1Fm\nNtrMxpjZ01HfqHP1LMFrPxVe7uJW4HdmdiowC/hmtQDZaBc4V6Pi1shlrv10JfBgePtB4I+qlcNP\n0XQuhgR6rUtd++k4M9sKwXkckvpVC+I1snMxxKmRC6/9ROVLMlm1cniN7FwMuTJZum3VYravWlxt\n93LXftoi6Tgz2yrpeOCdaoE8kZ2Lodzspz6nnkmfU89svr/mt4dfh83MpgJTAcJrPX3DzK6T9M/A\nlwkueP5nQNlzN/I8kZ2LIaVZjHcCv5L0FWAt8PlqOySayE37k1/VcPv29FbRPKVP8qt+AqzbtjuV\nuCP7HpNKXIAbH6t8Ld/WevwvxqUSF6DnY7NTix1VStd+2gZc0pL9vUZ2LoZaO0XTOVeCKnY2tx1P\nZOdiyMhKP57IzsVRU9MYnXOlNWSkSvZEdi6GjFTInsjOxVEzTWtJnYHngU7h9jPM7NtpF8y5WpCR\nPI60iuaHki4ys92SGoC5kn5rZgvaoHzOZVq5c63bWqSmtZnlT1XqHO5TdTaGc0eCbKRx9MX3csAi\n4BTgXjNbmGqpnKsRNdVrbWYHgNGSugNPSBpuZiuKt/to+RPNtxv6nkZDv9MSK6hzaWja9hYHtq9u\n9f4109lVyMx2SnoOuIxD1xgCoNOIqiuSOJcpDb1OoaHXKc33m9b8rkX7ZySPI62i2Se/ip+ko4BL\n8cvFOAfU1kXcTgAeDI+Tc8AvzeypdIvlXG3IyCFypOGnRmBMG5TFuZpTk8fIzrlDZSONPZGdi6Wm\nhp+cc6V509q5OpCRPPZEdi6OOOdal5uQFC6H+1ngQ+At4Hoz21mxHK0uhXMu1pUmzOxD4CIzGw2M\nAi6XNBaYCYwws1HAKiJcxC3Z5XDXLEsyHADHjD2l+katNGt11QX8W+X5N99PJe7H+x2dSlyAqRd/\nPJW4+5sOpBIXgF3b0osdUdxj5FITksys8PSy+cD/qhbHa2TnYshF/CsnvDbyEmAL8GyJCUlfAX5b\nrRx+jOxcDOWGnzY0LmDDq9Wn7FeakCTpNmCfmU2vFscT2bkYyg0jDzp9LINOH9t8/6Vf3lsxTvGE\nJElfJrhu8sWRyhGptM65kuJMmig3IUnSZQTXTJ4cdohV5TWyczHEPLGr5IQkSasIhqSeDX8E5pvZ\n1yoF8kR2LoY4ndblJiSZWYuHECIncvir8TKwwcwmt/SFnKtHNbX4XugmglVBuqdUFudqTlY6mSKV\nQ9JAgh60n6VbHOdqS0NOkf7SFrVG/hFBL1qPFMviXM3JSMs60pUmrgC2mtlSSRdSYS71vo0vNt/O\nHTOQhu4nJlFG51LTtGMdB3aua/X+GZmOHKlGngBMljQJOAo4RtLPzexLxRt2HHBu0uVzLlUNPQbR\n0GNQ8/2mjXNbtH9WOruqHiOb2VQzG2RmQ4CrgVmlkti5I1Gc2U9J8nFk52KopaZ1MzObDcxOqSzO\n1RxlZPk9r5Gdi6FDRgaSPZGdi8EX33OuDtTkMbJz7lAZqZA9kZ2LIyvjyJ7IzsVQn03rLt0SDQfQ\npUt6vzVXDu+fStzzBvVJJe5H+9NbkbJf986pxE2zzBx7fHqxI2rwGtm52peRPPZEdi6O+mxaO3eE\nyUpnV0bOS3GuNsWZNCFpoKRZkpZLapQ0pej5b0g6IKlXtXJ4jexcDDFr5P3AzeFc/27AIkkzzey1\ncFWeS4G1kcoRpxTOHeliXsRti5ktDW/vAlYCA8Kn86vyRBKpRpb0NrADOEBwCYuxlfdw7siQ1PCT\npJMIrsj4kqTJwHoza4x6LnfUpvUB4EIz296aQjpXr8ql2cpFL/LaohfLPFsUI2hWzyBYqbYJmErQ\nrK72Ms2iJrLwZrhzhyl3jDzirPGMOGt88/0nfnpXye0kdSBI4ofM7ElJnwBOAl5RUB0PJDh2Hmtm\nZa8DHDWRjeDyFU3AfWb204j7OVfXEmhYPwCsMLO7AczsVaD5lDVJa4Ax1VrDURN5gpltltSXIKFX\nmtmcVhbcuboR5xBZ0gTgi0BjeI1kA6aa2dMFmxlJNa3NbHP4/3clPQ6MBQ5L5H1rD64ClOsxmIZj\nT4oS3rl20/T7Nzmw7c1W7x9nYQEzmws0VNlmSJRYUda17grkzGyXpKOBTwHfLrVtx8ETo7ymc5nR\n0PtjNPT+WPP9preeadH+Wek4ilIjHwc8LsnC7R82s5npFsu52pCVUzSrJrKZrSEY33LOFfE1u5yr\nA7XUtHbOleE1snN1IBtp7InsXCwZqZA9kZ2LI5eROtkT2bkYamb4qUX6Dk40HMD69TsSj5n3aOPG\nVOK+8GY6k8QuH57O6pwAV/ZJZ0XRZ1/fmkpcgP7DhyYec/XT1bcplJE89hrZuTi8ae1cHfAa2bk6\n4InsXB3wC507Vwd8gXrn6kB9Dj85d4TJStM60uQNST0kPSppZbgq/ri0C+ZcLcgp2l/aotbIdwNP\nmdlV4ap/XVMsk3M1o2ZqZEndgfPNbBqAme03s52pl8y5GhDnShPB/rpf0lZJy4oevzFsATdKurNa\nOaI0rU8G3pM0TdJiSfdJOirCfs7VPUX8q2Aa8OlDYkoXAp8FRprZSOBfqpUjStO6AzAG+LqZvSzp\nLuBW4PbiDfetfLL5dq7PqTT0PS1CeOfaz571y9izvrHV+8e9ZIyZzZFUPEnhBuBOM9sfbvNetThR\nEnkDwXVoXg7vzwD+ttSGHYddGSGcc9lx1Imnc9SJpzfff3/+9JYFSOcQeShwgaTvAnuAWwryr6Qo\ni+9tlbRe0lAzewP4JLAikeI6V+NS6uzqAPQ0s3MknQ38Cqi4vnXUXuspwMOSOgKrgetjFdO5OlGu\nZb1o/gssfqnVF2NZDzwGYGYLw4ud9zaz35fbIeqVJl4Bzm5tqZyrV+Xq47POOZ+zzjm/+f7P7vle\ntTCFoZ4ALgZmSxoKdKyUxOBndjkXT8yWtaTpwIVAb0nrCDqRHwCmSWoEPgS+VC2OJ7JzMcQ9Rjaz\na8s8dV1L4ngiOxeDz35yrh54IjtX+7JyrrUnsnMxZGQ6csKJvH1zouEA9u7pl3jMvCuHnZBK3I/2\nH0gl7ry305ur0qNTx1TiDuvbPZW4AF26tH89lJE89hrZuVgyksmeyM7F4MfIztUBH35yrh54IjtX\n+7xp7VwdyMrwU5Q1u4ZKWhIu87NE0g5JU9qicM5lXQJL/SQiysICbwCjASTlCFYMeTzlcjlXGzJS\nI7e0aX0J8JaZrU+jMM7Vmlo9Rv4C8Is0CuJcLaq54adwmZ/JBCtolrRvzazm27ljT6ah58mxCudc\n2j5Y+wofrF1WfcNyai2RgcuBRWb2brkNOp58cfwSOdeGjh58BkcPPqP5/ntz/r1F+9di0/oavFnt\n3CFqZvgJQFJXgo6ux9ItjnO1pWaGnwDMbDfQN+WyOFd7aqlGds6Vpoj/ld1f+mtJr0paJulhSZ1a\nUw5PZOdiiHN9ZEn9gRuBMWZ2OkEL+epWlaO1byCOpu1rUom7d0PrL8ZVybw5s1OJC/DmkvmpxN20\nfEEqcRsXzkslLsCCeS+kEveDta+kEhdI4iC5ATi64Lrjm1pTjHZJ5APvp5TIG9NJ5BfnPJ9KXIA3\nl76UStxNyxemEvfVl9NL5IUvppXIMcaJq4jTtDazTcAPgHXARuB9M/tda8rhs5+ci6Hc8NOLc2Yz\nf27lCkDSscCVwGBgBzBD0rVm1sJLQnoiOxdLuVbz+PMmMv68ic337/rnO0ptdgmw2sy2AUh6DBgP\ntDiRZWYt3ad0ICmZQM61MzOLNKgkydZv2xsp5om9uhwWV9JY4H6CCyR+CEwDFprZvS0rcYI1ctQ3\n71x9af3X3swWSJoBLAH2hf+/r1WlSKpGdu5II8k2bv8w0rYDenZOtbLzY2TnYsjKudaeyM7FUIuz\nn5xzxbKRx57IzsWRkTz2RHYuDj9Gdq4OKCOZ7InsXAzZSGNPZOdiyUiF7InsXBw+/ORcHchKjewr\nhDhXB7xGdi6GrNTInsjOxZDLSCZ7IjsXQzbS2BPZuXgyksmeyM7F4MNPztWBjBwieyI7F0dG8tgT\n2blYMpLJnsjOxeDDT87VvrVHddTgqNumWRBfRdO5OuDnWjtXBzyRnasDnsjO1QFPZOfqgCeyc3Xg\n/wOq7JttMsJxzwAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot pixel ranking\n", + "plt.matshow(ranking, cmap=plt.cm.Blues)\n", + "plt.colorbar()\n", + "plt.title(\"Ranking of pixels with RFE\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### (四)原始碼\n", + "Python source code: [plot_rfe_digits.py](http://scikit-learn.org/stable/_downloads/plot_rfe_digits.py)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(__doc__)\n", + "\n", + "from sklearn.svm import SVC\n", + "from sklearn.datasets import load_digits\n", + "from sklearn.feature_selection import RFE\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Load the digits dataset\n", + "digits = load_digits()\n", + "X = digits.images.reshape((len(digits.images), -1))\n", + "y = digits.target\n", + "\n", + "# Create the RFE object and rank each pixel\n", + "svc = SVC(kernel=\"linear\", C=1)\n", + "rfe = RFE(estimator=svc, n_features_to_select=1, step=1)\n", + "rfe.fit(X, y)\n", + "ranking = rfe.ranking_.reshape(digits.images[0].shape)\n", + "\n", + "# Plot pixel ranking\n", + "plt.matshow(ranking, cmap=plt.cm.Blues)\n", + "plt.colorbar()\n", + "plt.title(\"Ranking of pixels with RFE\")\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Feature_Selection/permutations.png b/Feature_Selection/permutations.png new file mode 100644 index 0000000..ca09fd5 Binary files /dev/null and b/Feature_Selection/permutations.png differ diff --git a/Feature_Selection/sphx_glr_plot_f_test_vs_mi_001.png b/Feature_Selection/sphx_glr_plot_f_test_vs_mi_001.png new file mode 100644 index 0000000..f726573 Binary files /dev/null and b/Feature_Selection/sphx_glr_plot_f_test_vs_mi_001.png differ diff --git a/Introduction/intro.md b/Introduction/intro.md new file mode 100644 index 0000000..a355979 --- /dev/null +++ b/Introduction/intro.md @@ -0,0 +1,32 @@ +### Scikit-learn 套件的安裝 +目前Scikit-learn同時支援Python 2及 3,安裝的方式也非常多種。對於初學者,最建議的方式是直接下載 Anaconda Python (https://www.continuum.io/downloads)。同時支援 Windows / OSX/ Linux 等作業系統。相關數據分析套件如Scipy, Numpy, 及圖形繪製庫 matplotlib, bokeh 會同時安裝。 + +### 開發介面及環境 +筆者目前最常用的開發介面為IPython Notebook (3.0版後已改名為Jupyter Notebook) 以及 Atom.io 文字編輯器。在安裝Anaconda啟用IPython Notebook介面後,本文件連結之程式碼皆能夠以複製貼上的方式執行測試。目前部份章節也附有notebook格式文件 `.ipynb`檔可借下載。 + +![](ipython.PNG) + +### 給機器學習的初學者 +本文件的目的並非探討機器學習的各項理論,我們將以應用範例著手來幫助學習。其中建議以手寫數字辨識來當成的敲門磚。而本文件中,有以下範例介紹手寫數字辨識,並且藉由這個應用來探討機器學習中的一個重要類別「監督式學習」。一開始,建議先從 [機器學習資料集 Datasets](../Datasets/ex1_the_digits_dataset.md),來了解資料集的型態以及取得方式。接下來最重要的是釐清特徵`X`以及預測目標`y`之間的關係。要注意這邊的大寫的`X`通常代表一個矩陣, 每一列代表一筆資料,而每一行則代表其特徵。例如手寫數字辨識是利用 8x8的影像資料,來當成訓練集。而其中一種特徵的取用方法是例用這64個像素的灰階值來當成特徵。而小寫的`y`則代表一個向量,這個向量紀錄著前述訓練資料對應的「答案」。 + + ![](../Classification/images/ex1_output_7_0.png) + + 了解資料集之後,接下來則建議先嘗試 [分類法範例一](../Classification/ex1_Recognizing_hand-written_digits.md)例用最簡單的支持向量機(Support Vector Machine)分類法來達成多目標分類 (Multi-class classification),這裏的「多目標」指的是0到9的數字,該範例利用Scikit-learn內建的SVM分類器,來找出十個目標的分類公式,並介紹如何評估分類法的準確度,以及一些常見的分類指標。例如以下報表標示著對於10個數字的預測準確度。 有了對這個範例的初步認識之後,讀者應該開始感覺到監督式學習(Supervised learning)的意義,這裏「監督」的意思是,我們已經知道資料所對應的預測目標,也就是利用圖形可猜出數字。也就是訓練集中有`y`。而另一大類別「非監督式學習」則是我們一開始並不知道`y`,我們想透過演算法來將`y`找出來。例如透過購買行為及個人資料來分類消費族群。 + + ``` + precision recall f1-score support + + 0 1.00 0.99 0.99 88 + 1 0.99 0.97 0.98 91 + 2 0.99 0.99 0.99 86 + 3 0.98 0.87 0.92 91 + 4 0.99 0.96 0.97 92 + 5 0.95 0.97 0.96 91 + 6 0.99 0.99 0.99 91 + 7 0.96 0.99 0.97 89 + 8 0.94 1.00 0.97 88 + 9 0.93 0.98 0.95 92 + + avg / total 0.97 0.97 0.97 899 + ``` +而有了基本的分類法,接下來的範例則是利用特徵選擇來更增進分類的準確性。以手寫數字辨識來說。上述的例子共使用了64個像素來當成特徵,然而以常理來判斷。這64個像素中,處於影像邊緣的像素參考價值應該不高,因為手寫的筆畫鮮少出現在該處。若能將這些特徵資料排除在分類公式中,通常能再增進預測的準確度。而「特徵選擇」的這項技術,主要就是用來處理這類問題。[特徵選擇範例二:Recursive Feature Elimination](../Feature_Selection/ex2_Recursive_feature_elimination.md)則是利用了Scikit-learn內建的特徵消去法,來找出消去那些特徵能夠最佳化預測的準確度。而 [特徵選擇範例三:Recursive Feature Elimination with Cross-Validation](../Feature_Selection/ex3_rfe_crossvalidation__md.md) 則使用了更進階的交叉驗證法來切分訓練集以及挑戰集來評估準確程度。建議讀者可以嘗試這幾個範例,一步步去深入機器學習的核心。 diff --git a/Introduction/ipython.PNG b/Introduction/ipython.PNG new file mode 100644 index 0000000..16ea80d Binary files /dev/null and b/Introduction/ipython.PNG differ diff --git a/Neural_Networks/Neural_network_models_supervised.md b/Neural_Networks/Neural_network_models_supervised.md new file mode 100644 index 0000000..b57cf7b --- /dev/null +++ b/Neural_Networks/Neural_network_models_supervised.md @@ -0,0 +1,63 @@ ++ +# Multi-layer Perceptron(多層感知器) +http://scikit-learn.org/stable/modules/neural_networks_supervised.html + +Multi-layer Perceptron (MLP):MLP為一種監督式學習的演算法,藉由 f(⋅):R^m→R^o ,m是輸入時的維度、o是輸出時的維度,藉由輸入特徵 $$X=x_1,x_2,.....,x_m$$ 和目標值Y,此算法將可以使用非線性近似將資料分類或進行迴歸運算。MLP可以在輸入層與輸出層中間插入許多非線性層,如圖1所示:,這是有一層隱藏層的網路。 + + + +![](images/multilayerperceptron_network.png) +
圖1:包含一層隱藏層的MLP
+ +最左邊那層稱作輸入層,為一個神經元集合 \{x_i|x_1,x_2,...,x_m\}代表輸入的特徵。每個神經元在隱藏層會根據前一層的輸出的結果,做為此層的輸入$$w_1x_1+w_2x_2+...+w_mx_m$$在將總和使用非線性的活化函數做 f(⋅):R→R轉換,例如:[hyperbolic tan function](https://en.wikipedia.org/wiki/Hyperbolic_function#/media/File:Sinh_cosh_tanh.svg)、[Sigmoid function](https://en.wikipedia.org/wiki/Sigmoid_function),最右邊那層為輸出層,會接收最後的隱藏層的輸出在轉換一次成輸出值。 + +intercepts_為模型訓練後,權重矩陣內包含兩個屬性:$coefs\_$和$intercepts\_$。coefs\_ 此矩陣中第i個指標表示第$i$層與$i+1$層的權重,intercepts_為偏權值(bias)矩陣,此矩陣中第i個指標表示要加在$i+1層$的偏權值。 + +MLP優點: + 1.有能力建立非線性的模型 + 2.可以使用$partial\_fit$建立real-time模型 +MLP缺點: +1.因為[凹函數](https://zh.wikipedia.org/wiki/%E5%87%B9%E5%87%BD%E6%95%B0)擁有大於一個區域最小值,使用不同的初始權重,會讓驗證時的準確率浮動 +2.MLP模型需要調整每層神經元數、層數、疊代次數 +3.MLP對於特徵的預先處理很敏感,建議將特徵X都尺度降至[0,1]或[-1,+1]或讓特徵值降至平均值等於0與變異數等於1的數字區間 + +## MLP分類器 +使用MLP訓練需要使用輸入兩種陣列,一個是特徵X陣列,X陣列包含(樣本數,特徵數),另一個是Y向量包含目標值(分類標籤)下面將會介紹MLP分類器範例。 + +### (一)引入函式庫 +from sklearn.neural_network import MLPClassifier:引進MLP分類器 +### (二)建立模擬資料與設定分類器參數 +建立擁有三種特徵的三筆資料 +X = [[0., 0.,0.], [1., 1.,1.],[2., 2.,2.]] +將三筆資料的分類標上 +y = [0, 1, 2] +設定分類器:最佳化參數的演算法,alpha值,隱藏層的層數與每層神經元數: hidden_layer_sizes=(5,3)表示隱藏層有兩層第一層為五個神經元,第二層為三個神經元 +clf = MLPClassifier(solver='lbfgs', alpha=1e-5, + hidden_layer_sizes=(5,3), random_state=1) +### (三)訓練網路參數與預測 +將資料丟進分類器,訓練網路參數 +clf.fit(X, y) +將要預測的資料丟進網路預測 +clf.predict([[2., 2., 2.], [-1., -2.,0.],[1., 1.,0.]]) +預測結果:array([2, 0, 1]) +結果表示[2., 2., 2.]為第三類,[-1., -2.,0.]為第一類,[1., 1.,0.]為第二類 + + +### 完整程式碼: + +```python +from sklearn.neural_network import MLPClassifier + +X = [[0., 0.,0.], [1., 1.,1.],[2., 2.,2.]] + +y = [0, 1, 2] + +clf = MLPClassifier(solver='lbfgs', alpha=1e-5, + hidden_layer_sizes=(5,3), random_state=1) + +clf.fit(X, y) + +clf.predict([[2., 2., 2.], [-1., -2.,0.],[1., 1.,0.]]) +``` diff --git a/Neural_Networks/images/Compare_Stochastic_learning_strategies_for_MLPClassifier.PNG b/Neural_Networks/images/Compare_Stochastic_learning_strategies_for_MLPClassifier.PNG new file mode 100644 index 0000000..d601801 Binary files /dev/null and b/Neural_Networks/images/Compare_Stochastic_learning_strategies_for_MLPClassifier.PNG differ diff --git a/Neural_Networks/images/Logistic_regression_using_RBM_features.PNG b/Neural_Networks/images/Logistic_regression_using_RBM_features.PNG new file mode 100644 index 0000000..e4014cd Binary files /dev/null and b/Neural_Networks/images/Logistic_regression_using_RBM_features.PNG differ diff --git a/Neural_Networks/images/Logistic_regression_using_raw_pixel_features.PNG b/Neural_Networks/images/Logistic_regression_using_raw_pixel_features.PNG new file mode 100644 index 0000000..ca4955a Binary files /dev/null and b/Neural_Networks/images/Logistic_regression_using_raw_pixel_features.PNG differ diff --git a/Neural_Networks/images/MLP_visualization_loss.PNG b/Neural_Networks/images/MLP_visualization_loss.PNG new file mode 100644 index 0000000..85904e2 Binary files /dev/null and b/Neural_Networks/images/MLP_visualization_loss.PNG differ diff --git a/Neural_Networks/images/Momentum.PNG b/Neural_Networks/images/Momentum.PNG new file mode 100644 index 0000000..4860e88 Binary files /dev/null and b/Neural_Networks/images/Momentum.PNG differ diff --git a/Neural_Networks/images/Nesterov_Momentum.PNG b/Neural_Networks/images/Nesterov_Momentum.PNG new file mode 100644 index 0000000..67f43b9 Binary files /dev/null and b/Neural_Networks/images/Nesterov_Momentum.PNG differ diff --git a/Neural_Networks/images/RBM_100_feature.PNG b/Neural_Networks/images/RBM_100_feature.PNG new file mode 100644 index 0000000..347e032 Binary files /dev/null and b/Neural_Networks/images/RBM_100_feature.PNG differ diff --git a/Neural_Networks/images/Varying_regularization_in_Multi-layer_Perceptron.png b/Neural_Networks/images/Varying_regularization_in_Multi-layer_Perceptron.png new file mode 100644 index 0000000..4247422 Binary files /dev/null and b/Neural_Networks/images/Varying_regularization_in_Multi-layer_Perceptron.png differ diff --git a/Neural_Networks/images/alpha_weight.PNG b/Neural_Networks/images/alpha_weight.PNG new file mode 100644 index 0000000..726389f Binary files /dev/null and b/Neural_Networks/images/alpha_weight.PNG differ diff --git a/Neural_Networks/images/multilayerperceptron_network.png b/Neural_Networks/images/multilayerperceptron_network.png new file mode 100644 index 0000000..90defd3 Binary files /dev/null and b/Neural_Networks/images/multilayerperceptron_network.png differ diff --git a/Neural_Networks/images/weight_matrix_28_28.png b/Neural_Networks/images/weight_matrix_28_28.png new file mode 100644 index 0000000..ab31a9c Binary files /dev/null and b/Neural_Networks/images/weight_matrix_28_28.png differ diff --git a/Neural_Networks/plot_mlp_alpha.md b/Neural_Networks/plot_mlp_alpha.md new file mode 100644 index 0000000..978742f --- /dev/null +++ b/Neural_Networks/plot_mlp_alpha.md @@ -0,0 +1,126 @@ + + +# Varying regularization in Multi-layer Perceptron +http://scikit-learn.org/stable/auto_examples/neural_networks/plot_mlp_alpha.html#sphx-glr-auto-examples-neural-networks-plot-mlp-alpha-py + + +此範例是比較不同的正歸化參數'alpha',對於使用scikit-learn的資料產生器 +,所產生的[circles](http://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_circles.html#sklearn.datasets.make_circles)、 [moon](http://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_moons.html#sklearn.datasets.make_moons) +和[random n-class classification](http://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_classification.html#sklearn.datasets.make_classification),三種資料集的成效。 + +PS:正規化為一種處理無限大、發散以及一些不合理表示式的方法,透過引入一項輔助性的概念——正規子(regulator),去限制函數使得函數不會發散 + +此處的Alpha參數即為正規子,目的是去限制權重(Weight,W)的大小,以防萬一overfitting與underfitting的問題,增加alpha值可能可以處理overfitting,反之減小alpha可能可以解決underfitting的問題,至於權重大小,如何影響輸出請看圖1: + ![](images/alpha_weight.PNG) + 圖1:比較同樣輸入,對於不同大小權重值,對於輸出的影響左圖為權重為5時,當輸入變動0.1時,輸出增加0.5,即輸出改變10%,右圖為權重為1時,當輸入變動0.1時,輸出增加0.1,即輸出改變2%,通常模型對於input較不敏感,模型表現較好 +結果將顯示出:使用不同alpha值去限制權重產生出的決策邊界 + + + +### (一)引入函式庫 + +```python +print(__doc__) + + +# Author: Issam H. Laradji +# License: BSD 3 clause + +import numpy as np +from matplotlib import pyplot as plt +from matplotlib.colors import ListedColormap +from sklearn.model_selection import train_test_split +from sklearn.preprocessing import StandardScaler +from sklearn.datasets import make_moons, make_circles, make_classification +from sklearn.neural_network import MLPClassifier +``` +### (二)設定模型參數與產生資料 +```python + +h = .02 # step size in the mesh + +alphas = np.logspace(-5, 3, 5)# +names = [] +for i in alphas: + names.append('alpha ' + str(i)) + +classifiers = [] +for i in alphas: + classifiers.append(MLPClassifier(alpha=i, random_state=1)) + +X, y = make_classification(n_features=2, n_redundant=0, n_informative=2, + random_state=0, n_clusters_per_class=1) +rng = np.random.RandomState(2) +X += 2 * rng.uniform(size=X.shape) +linearly_separable = (X, y) + +datasets = [make_moons(noise=0.3, random_state=0), + make_circles(noise=0.2, factor=0.5, random_state=1), + linearly_separable] + +figure = plt.figure(figsize=(17, 9)) +i = 1 +# iterate over datasets +for X, y in datasets: + # preprocess dataset, split into training and test part + X = StandardScaler().fit_transform(X) + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.4) + + x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5 + y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5 + xx, yy = np.meshgrid(np.arange(x_min, x_max, h), + np.arange(y_min, y_max, h)) +``` +### (三)繪製圖形 +```python + # just plot the dataset first + cm = plt.cm.RdBu + cm_bright = ListedColormap(['#FF0000', '#0000FF']) + ax = plt.subplot(len(datasets), len(classifiers) + 1, i) + # Plot the training points + ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright) + # and testing points + ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_bright, alpha=0.6) + ax.set_xlim(xx.min(), xx.max()) + ax.set_ylim(yy.min(), yy.max()) + ax.set_xticks(()) + ax.set_yticks(()) + i += 1 + + # iterate over classifiers + for name, clf in zip(names, classifiers): + ax = plt.subplot(len(datasets), len(classifiers) + 1, i) + clf.fit(X_train, y_train) + score = clf.score(X_test, y_test) + + # Plot the decision boundary. For that, we will assign a color to each + # point in the mesh [x_min, x_max]x[y_min, y_max]. + if hasattr(clf, "decision_function"): + Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) + else: + Z = clf.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1] + + # Put the result into a color plot + Z = Z.reshape(xx.shape) + ax.contourf(xx, yy, Z, cmap=cm, alpha=.8) + + # Plot also the training points + ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright) + # and testing points + ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_bright, + alpha=0.6) + + ax.set_xlim(xx.min(), xx.max()) + ax.set_ylim(yy.min(), yy.max()) + ax.set_xticks(()) + ax.set_yticks(()) + ax.set_title(name) + ax.text(xx.max() - .3, yy.min() + .3, ('%.2f' % score).lstrip('0'), + size=15, horizontalalignment='right') + i += 1 + +figure.subplots_adjust(left=.02, right=.98) +plt.show() +``` +![](images/Varying_regularization_in_Multi-layer_Perceptron.png) +圖2:不同alpha結果圖,每張子圖右下角是分辨率,alpha值很大,模型的結果明顯underfitting diff --git a/Neural_Networks/plot_mlp_training_curves.md b/Neural_Networks/plot_mlp_training_curves.md new file mode 100644 index 0000000..d583145 --- /dev/null +++ b/Neural_Networks/plot_mlp_training_curves.md @@ -0,0 +1,204 @@ +# Compare Stochastic learning strategies for MLPClassifier + +http://scikit-learn.org/stable/auto_examples/neural_networks/plot_mlp_training_curves.html#sphx-glr-auto-examples-neural-networks-plot-mlp-training-curves-py + + +此範例將畫出圖表,展現不同的訓練策略(optimizer)下loss curves的變化,訓練策略包括SGD與Adam。 + +###1.Stochastic Gradient Descent(SGD): +.Stochastic Gradient Descent(SGD)為Gradient Descent(GD)的改良,在GD裡是輸入全部的training dataset,根據累積的loss才更新一次權重,因此收歛速度很慢,SGD隨機抽一筆 training sample,依照其 loss 更新權重。 + +###2.Momentum: +Momentum是為了以防GD類的方法陷入局部最小值而衍生的方法,可以利用momentum降低陷入local minimum的機率,此方法是參考物理學動量的觀念。 + +看圖1藍色點的位置,當GD類的方法陷入局部最小值時,因為gd=0將會使電腦認為此處為最小值,於是為了減少此現象,每次更新時會將上次更新權重的一部分拿來加入此次更新。如紅色箭頭所示,將有機會翻過local minimum。 + +![](images/Momentum.PNG) + +圖1:momentum觀念示意圖 + + +###3.Nesterov Momentum: +Nesterov Momentum為另外一種Momentum的變形體,目的也是降低陷入local minimum機率的方法,而兩種方法的差異在於下圖: + +![](images/Nesterov_Momentum.PNG) + +圖2:左圖為momentum,1.先計算 gradient、2.加上 momentum、3.更新權重 + +右圖為Nesterov Momentum,1.先加上momentum、2.計算gradient、3.更新權重。 + +圖2圖片來源:http://cs231n.github.io/neural-networks-3/ + + +###4.Adaptive Moment Estimation (Adam): +Adam為一種自己更新學習速率的方法,會根據GD計算出來的值調整每個參數的學習率(因材施教)。 + +以上所有的最佳化方法都將需要設定learning_rate_init值,此範例結果將呈現四種不同資料的比較:[iris](https://zh.wikipedia.org/wiki/%E5%AE%89%E5%BE%B7%E6%A3%AE%E9%B8%A2%E5%B0%BE%E8%8A%B1%E5%8D%89%E6%95%B0%E6%8D%AE%E9%9B%86)資料集、[digits](http://yann.lecun.com/exdb/mnist/)資料集、與使用sklearn.datasets產生資料集[circles](http://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_circles.html#sklearn.datasets.make_circles)、 [moon](http://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_moons.html#sklearn.datasets.make_moons)。 + +### (一)引入函式庫 + +```python +print(__doc__) +import matplotlib.pyplot as plt +from sklearn.neural_network import MLPClassifier +from sklearn.preprocessing import MinMaxScaler +from sklearn import datasets +``` +### (二)設定模型參數 +```python +# different learning rate schedules and momentum parameters +params = [{'solver': 'sgd', 'learning_rate': 'constant', 'momentum': 0, + 'learning_rate_init': 0.2}, + {'solver': 'sgd', 'learning_rate': 'constant', 'momentum': .9, + 'nesterovs_momentum': False, 'learning_rate_init': 0.2}, + {'solver': 'sgd', 'learning_rate': 'constant', 'momentum': .9, + 'nesterovs_momentum': True, 'learning_rate_init': 0.2}, + {'solver': 'sgd', 'learning_rate': 'invscaling', 'momentum': 0, + 'learning_rate_init': 0.2}, + {'solver': 'sgd', 'learning_rate': 'invscaling', 'momentum': .9, + 'nesterovs_momentum': True, 'learning_rate_init': 0.2}, + {'solver': 'sgd', 'learning_rate': 'invscaling', 'momentum': .9, + 'nesterovs_momentum': False, 'learning_rate_init': 0.2}, + {'solver': 'adam', 'learning_rate_init': 0.01}] + +labels = ["constant learning-rate", "constant with momentum", + "constant with Nesterov's momentum", + "inv-scaling learning-rate", "inv-scaling with momentum", + "inv-scaling with Nesterov's momentum", "adam"] + +plot_args = [{'c': 'red', 'linestyle': '-'}, + {'c': 'green', 'linestyle': '-'}, + {'c': 'blue', 'linestyle': '-'}, + {'c': 'red', 'linestyle': '--'}, + {'c': 'green', 'linestyle': '--'}, + {'c': 'blue', 'linestyle': '--'}, + {'c': 'black', 'linestyle': '-'}] + +``` + +### (三)畫出loss curves +```python +def plot_on_dataset(X, y, ax, name): + # for each dataset, plot learning for each learning strategy + print("\nlearning on dataset %s" % name) + ax.set_title(name) + X = MinMaxScaler().fit_transform(X) + mlps = [] + if name == "digits": + # digits is larger but converges fairly quickly + max_iter = 15 + else: + max_iter = 400 + + for label, param in zip(labels, params): + print("training: %s" % label) + mlp = MLPClassifier(verbose=0, random_state=0, + max_iter=max_iter, **param) + mlp.fit(X, y) + mlps.append(mlp) + print("Training set score: %f" % mlp.score(X, y)) + print("Training set loss: %f" % mlp.loss_) + for mlp, label, args in zip(mlps, labels, plot_args): + ax.plot(mlp.loss_curve_, label=label, **args) + + +fig, axes = plt.subplots(2, 2, figsize=(15, 10)) + +# load / generate some toy datasets +iris = datasets.load_iris() +digits = datasets.load_digits() +data_sets = [(iris.data, iris.target), + (digits.data, digits.target), + datasets.make_circles(noise=0.2, factor=0.5, random_state=1), + datasets.make_moons(noise=0.3, random_state=0)] + +for ax, data, name in zip(axes.ravel(), data_sets, ['iris', 'digits', + 'circles', 'moons']): + plot_on_dataset(*data, ax=ax, name=name) + +fig.legend(ax.get_lines(), labels=labels, ncol=3, loc="upper center") +plt.show() +``` +![](images/Compare_Stochastic_learning_strategies_for_MLPClassifier.PNG) + +
圖3:四種資料對於不同學習方法的loss curves下降比較圖
+ + + +### (四)完整程式碼 +```python +print(__doc__) +import matplotlib.pyplot as plt +from sklearn.neural_network import MLPClassifier +from sklearn.preprocessing import MinMaxScaler +from sklearn import datasets + +# different learning rate schedules and momentum parameters +params = [{'solver': 'sgd', 'learning_rate': 'constant', 'momentum': 0, + 'learning_rate_init': 0.2}, + {'solver': 'sgd', 'learning_rate': 'constant', 'momentum': .9, + 'nesterovs_momentum': False, 'learning_rate_init': 0.2}, + {'solver': 'sgd', 'learning_rate': 'constant', 'momentum': .9, + 'nesterovs_momentum': True, 'learning_rate_init': 0.2}, + {'solver': 'sgd', 'learning_rate': 'invscaling', 'momentum': 0, + 'learning_rate_init': 0.2}, + {'solver': 'sgd', 'learning_rate': 'invscaling', 'momentum': .9, + 'nesterovs_momentum': True, 'learning_rate_init': 0.2}, + {'solver': 'sgd', 'learning_rate': 'invscaling', 'momentum': .9, + 'nesterovs_momentum': False, 'learning_rate_init': 0.2}, + {'solver': 'adam', 'learning_rate_init': 0.01}] + +labels = ["constant learning-rate", "constant with momentum", + "constant with Nesterov's momentum", + "inv-scaling learning-rate", "inv-scaling with momentum", + "inv-scaling with Nesterov's momentum", "adam"] + +plot_args = [{'c': 'red', 'linestyle': '-'}, + {'c': 'green', 'linestyle': '-'}, + {'c': 'blue', 'linestyle': '-'}, + {'c': 'red', 'linestyle': '--'}, + {'c': 'green', 'linestyle': '--'}, + {'c': 'blue', 'linestyle': '--'}, + {'c': 'black', 'linestyle': '-'}] + + +def plot_on_dataset(X, y, ax, name): + # for each dataset, plot learning for each learning strategy + print("\nlearning on dataset %s" % name) + ax.set_title(name) + X = MinMaxScaler().fit_transform(X) + mlps = [] + if name == "digits": + # digits is larger but converges fairly quickly + max_iter = 15 + else: + max_iter = 400 + + for label, param in zip(labels, params): + print("training: %s" % label) + mlp = MLPClassifier(verbose=0, random_state=0, + max_iter=max_iter, **param) + mlp.fit(X, y) + mlps.append(mlp) + print("Training set score: %f" % mlp.score(X, y)) + print("Training set loss: %f" % mlp.loss_) + for mlp, label, args in zip(mlps, labels, plot_args): + ax.plot(mlp.loss_curve_, label=label, **args) + + +fig, axes = plt.subplots(2, 2, figsize=(15, 10)) +# load / generate some toy datasets +iris = datasets.load_iris() +digits = datasets.load_digits() +data_sets = [(iris.data, iris.target), + (digits.data, digits.target), + datasets.make_circles(noise=0.2, factor=0.5, random_state=1), + datasets.make_moons(noise=0.3, random_state=0)] + +for ax, data, name in zip(axes.ravel(), data_sets, ['iris', 'digits', + 'circles', 'moons']): + plot_on_dataset(*data, ax=ax, name=name) + +fig.legend(ax.get_lines(), labels=labels, ncol=3, loc="upper center") +plt.show() +``` diff --git a/Neural_Networks/plot_mnist_filters.md b/Neural_Networks/plot_mnist_filters.md new file mode 100644 index 0000000..1ced043 --- /dev/null +++ b/Neural_Networks/plot_mnist_filters.md @@ -0,0 +1,87 @@ + +# Visualization of MLP weights on MNIST + +http://scikit-learn.org/stable/auto_examples/neural_networks/plot_mnist_filters.html#sphx-glr-auto-examples-neural-networks-plot-mnist-filters-py + + + +此範例將使用MNIST dataset的訓練資料集去訓練MLPClassifier,資料集中每張圖片都是28\*28,對於第一層的每個神經元都會有28\*28個特徵,輸出結果是將訓練資料的每個像素點對於神經元的權重畫成28*28的圖,用來表示圖片上每個像素點對於神經元的權重多寡。 +### (一)引入函式庫與資料 +1.matplotlib.pyplot:用來繪製影像 +2.sklearn.datasets:引入內建的手寫數字資料庫 +3.sklearn.neural_network:引入類神經網路的套件 +```python +import matplotlib.pyplot as plt +from sklearn.datasets import fetch_mldata +from sklearn.neural_network import MLPClassifier +mnist = fetch_mldata("MNIST original") +``` +### (二)將資料切割成訓練集與測試集 +```python +# 將灰階影像降尺度降到[0,1] +X, y = mnist.data / 255., mnist.target +X_train, X_test = X[:60000], X[60000:] +y_train, y_test = y[:60000], y[60000:] +``` +### (三)設定分類器參數與訓練網路並畫出權重矩陣 + +```python +#hidden_layer_sizes=(50)此處使用1層隱藏層,只有50個神經元,max_iter=10疊代訓練10次 +mlp = MLPClassifier(hidden_layer_sizes=(50), max_iter=10, alpha=1e-4, + solver='sgd', verbose=10, tol=1e-4, random_state=1, + learning_rate_init=.1) + +mlp.fit(X_train, y_train) +#畫出16個神經元的權重圖,黑色表示負的權重,越深色表示數值越大,白色表示正的權重,越淺色表示數值越大 +fig, axes = plt.subplots(4, 4) +# use global min / max to ensure all weights are shown on the same scale +vmin, vmax = mlp.coefs_[0].min(), mlp.coefs_[0].max() +for coef, ax in zip(mlp.coefs_[0].T, axes.ravel()): + ax.matshow(coef.reshape(28, 28), cmap=plt.cm.gray, vmin=.5 * vmin, + vmax=.5 * vmax) + ax.set_xticks(()) + ax.set_yticks(()) + +plt.show() +``` +![](images/weight_matrix_28_28.png) +
圖1:16個神經元對於影像的權重圖
+ +![](images/MLP_visualization_loss.PNG) +
圖2:疊代計算時loss下降
+ + +### (四)完整程式碼 +```python +print(__doc__) + +import matplotlib.pyplot as plt +from sklearn.datasets import fetch_mldata +from sklearn.neural_network import MLPClassifier + +mnist = fetch_mldata("MNIST original") + +X, y = mnist.data / 255., mnist.target +X_train, X_test = X[:60000], X[60000:] +y_train, y_test = y[:60000], y[60000:] + + +mlp = MLPClassifier(hidden_layer_sizes=(50), max_iter=10, alpha=1e-4, + solver='sgd', verbose=10, tol=1e-4, random_state=1, + learning_rate_init=.1) + +mlp.fit(X_train, y_train) +print("Training set score: %f" % mlp.score(X_train, y_train)) +print("Test set score: %f" % mlp.score(X_test, y_test)) + +fig, axes = plt.subplots(4, 4) + +vmin, vmax = mlp.coefs_[0].min(), mlp.coefs_[0].max() +for coef, ax in zip(mlp.coefs_[0].T, axes.ravel()): + ax.matshow(coef.reshape(28, 28), cmap=plt.cm.gray, vmin=.5 * vmin, + vmax=.5 * vmax) + ax.set_xticks(()) + ax.set_yticks(()) + +plt.show() +``` diff --git a/Neural_Networks/plot_rbm_logistic_classification.md b/Neural_Networks/plot_rbm_logistic_classification.md new file mode 100644 index 0000000..2306b78 --- /dev/null +++ b/Neural_Networks/plot_rbm_logistic_classification.md @@ -0,0 +1,275 @@ + + + +# Restricted Boltzmann Machine features for digit classification + +http://scikit-learn.org/stable/auto_examples/neural_networks/plot_rbm_logistic_classification.html#sphx-glr-auto-examples-neural-networks-plot-rbm-logistic-classification-py + + + +此範例將使用BernoulliRBM特徵選取方法,提升手寫數字識別的精確率,伯努利限制玻爾茲曼機器模型(`BernoulliRBM +`)將可以對數據做有效的非線性 +特徵提取的處理。 +為了讓此模型訓練出來更為強健,將輸入的圖檔,分別做上左右下,一像素的平移,用以增加更多訓練資料, +訓練網路的參數是使用grid search演算法,但此訓練太耗費時間,因此不再這重現,。 +此範例結果將比較, +1.使用原本的像素值做的邏輯回歸 +2.使用BernoulliRBM做特徵選取的邏輯回歸 +結果將顯示:使用BernoulliRBM將可以提升分類的準確度。 + + +### (一)引入函式庫與資料 + +```python +from __future__ import print_function + +print(__doc__) + +# Authors: Yann N. Dauphin, Vlad Niculae, Gabriel Synnaeve +# License: BSD + +import numpy as np +import matplotlib.pyplot as plt + +from scipy.ndimage import convolve +from sklearn import linear_model, datasets, metrics +from sklearn.model_selection import train_test_split +from sklearn.neural_network import BernoulliRBM +from sklearn.pipeline import Pipeline +``` + +### (二)資料前處理、讀取資料、選取模型 + +```python +def nudge_dataset(X, Y): + """ + 此副函式是用來將輸入資料的數字圖形,分別做上左右下一像素的平移,目的是製造更多的訓練資料讓模型訓練出來更強健 + """ + direction_vectors = [ + [[0, 1, 0], + [0, 0, 0], + [0, 0, 0]], + + [[0, 0, 0], + [1, 0, 0], + [0, 0, 0]], + + [[0, 0, 0], + [0, 0, 1], + [0, 0, 0]], + + [[0, 0, 0], + [0, 0, 0], + [0, 1, 0]]] + + shift = lambda x, w: convolve(x.reshape((8, 8)), mode='constant', + weights=w).ravel() + X = np.concatenate([X] + + [np.apply_along_axis(shift, 1, X, vector) + for vector in direction_vectors]) + Y = np.concatenate([Y for _ in range(5)], axis=0) + return X, Y + +# Load Data +digits = datasets.load_digits() +X = np.asarray(digits.data, 'float32') +X, Y = nudge_dataset(X, digits.target) +X = (X - np.min(X, 0)) / (np.max(X, 0) + 0.0001) # 將灰階影像降尺度降到[0,1] +# 將資料切割成訓練集與測試集 +X_train, X_test, Y_train, Y_test = train_test_split(X, Y, + test_size=0.2, + random_state=0) + +# Models we will use +logistic = linear_model.LogisticRegression() +rbm = BernoulliRBM(random_state=0, verbose=True) + +classifier = Pipeline(steps=[('rbm', rbm), ('logistic', logistic)]) +``` + +### (三)設定模型參數與訓練模型 + + +```python +# 參數選擇需使用cross-validation去比較 +# 此參數是使用GridSearchCV找出來的. Here we are not performing cross-validation to save time. +#GridSratch 就是將參數設定好,跑過全部參數後去找結果最好的一組參數 +rbm.learning_rate = 0.06 +rbm.n_iter = 20 +#.n_components = 100 表示隱藏層單元為100,即表示萃取出100個特徵,特徵萃取的越多準確率會越高,但越耗時間 +rbm.n_components = 100 +logistic.C = 6000.0 + +# Training RBM-Logistic Pipeline +classifier.fit(X_train, Y_train) + +# Training Logistic regression +logistic_classifier = linear_model.LogisticRegression(C=100.0) +logistic_classifier.fit(X_train, Y_train) +``` + +### (四)評估模型的分辨準確率 + + +```python +print() +print("Logistic regression using RBM features:\n%s\n" % ( + metrics.classification_report( + Y_test, + classifier.predict(X_test)))) + +print("Logistic regression using raw pixel features:\n%s\n" % ( + metrics.classification_report( + Y_test, + logistic_classifier.predict(X_test)))) +``` +![](images/Logistic_regression_using_RBM_features.PNG) +
圖1:使用RBM演算法後準確率為0.95
+ +![](images/Logistic_regression_using_raw_pixel_features.PNG) +
圖2:不使用任何特徵選取方法做的做的邏輯回歸準確率0.77
+ + + + +### (五)畫出100個RBM萃取出的特徵 + + +```python +plt.figure(figsize=(4.2, 4)) +for i, comp in enumerate(rbm.components_): + plt.subplot(10, 10, i + 1) + plt.imshow(comp.reshape((8, 8)), cmap=plt.cm.gray_r, + interpolation='nearest') + plt.xticks(()) + plt.yticks(()) +plt.suptitle('100 components extracted by RBM', fontsize=16) +plt.subplots_adjust(0.08, 0.02, 0.92, 0.85, 0.08, 0.23) + +plt.show() +``` +![](images/RBM_100_feature.PNG) +
圖3:使用RBM演算法,尋找出來的特徵
+ + + + +### (六)完整程式碼 + + +```python +from __future__ import print_function + +print(__doc__) + +# Authors: Yann N. Dauphin, Vlad Niculae, Gabriel Synnaeve +# License: BSD + +import numpy as np +import matplotlib.pyplot as plt + +from scipy.ndimage import convolve +from sklearn import linear_model, datasets, metrics +from sklearn.model_selection import train_test_split +from sklearn.neural_network import BernoulliRBM +from sklearn.pipeline import Pipeline + + +############################################################################### +# Setting up + +def nudge_dataset(X, Y): + """ + This produces a dataset 5 times bigger than the original one, + by moving the 8x8 images in X around by 1px to left, right, down, up + """ + direction_vectors = [ + [[0, 1, 0], + [0, 0, 0], + [0, 0, 0]], + + [[0, 0, 0], + [1, 0, 0], + [0, 0, 0]], + + [[0, 0, 0], + [0, 0, 1], + [0, 0, 0]], + + [[0, 0, 0], + [0, 0, 0], + [0, 1, 0]]] + + shift = lambda x, w: convolve(x.reshape((8, 8)), mode='constant', + weights=w).ravel() + X = np.concatenate([X] + + [np.apply_along_axis(shift, 1, X, vector) + for vector in direction_vectors]) + Y = np.concatenate([Y for _ in range(5)], axis=0) + return X, Y + +# Load Data +digits = datasets.load_digits() +X = np.asarray(digits.data, 'float32') +X, Y = nudge_dataset(X, digits.target) +X = (X - np.min(X, 0)) / (np.max(X, 0) + 0.0001) # 0-1 scaling + +X_train, X_test, Y_train, Y_test = train_test_split(X, Y, + test_size=0.2, + random_state=0) + +# Models we will use +logistic = linear_model.LogisticRegression() +rbm = BernoulliRBM(random_state=0, verbose=True) + +classifier = Pipeline(steps=[('rbm', rbm), ('logistic', logistic)]) + +############################################################################### +# Training + +# Hyper-parameters. These were set by cross-validation, +# using a GridSearchCV. Here we are not performing cross-validation to +# save time. +rbm.learning_rate = 0.06 +rbm.n_iter = 20 +# More components tend to give better prediction performance, but larger +# fitting time +rbm.n_components = 100 +logistic.C = 6000.0 + +# Training RBM-Logistic Pipeline +classifier.fit(X_train, Y_train) + +# Training Logistic regression +logistic_classifier = linear_model.LogisticRegression(C=100.0) +logistic_classifier.fit(X_train, Y_train) + +############################################################################### +# Evaluation + +print() +print("Logistic regression using RBM features:\n%s\n" % ( + metrics.classification_report( + Y_test, + classifier.predict(X_test)))) + +print("Logistic regression using raw pixel features:\n%s\n" % ( + metrics.classification_report( + Y_test, + logistic_classifier.predict(X_test)))) + +############################################################################### +# Plotting + +plt.figure(figsize=(4.2, 4)) +for i, comp in enumerate(rbm.components_): + plt.subplot(10, 10, i + 1) + plt.imshow(comp.reshape((8, 8)), cmap=plt.cm.gray_r, + interpolation='nearest') + plt.xticks(()) + plt.yticks(()) +plt.suptitle('100 components extracted by RBM', fontsize=16) +plt.subplots_adjust(0.08, 0.02, 0.92, 0.85, 0.08, 0.23) + +plt.show() +``` diff --git a/README.md b/README.md index bd24d09..184cf4a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ #機器學習:使用Python -這份文件的目的是要提供Python 之機器學習套件 scikit-learn (http://scikit-learn.org/) 的中文使用說明。一開始的主要目標是詳細說明scikit-learn套件中的[範例程式](http://scikit-learn.org/stable/auto_examples/index.html )的使用流程以及相關函式的使用方法。目前使用版本為 scikit-learn version 0.17 以上 +這份文件的目的是要提供Python 之機器學習套件 scikit-learn (http://scikit-learn.org/) 的中文使用說明以及介紹。一開始的主要目標是詳細說明scikit-learn套件中的[範例程式](http://scikit-learn.org/stable/auto_examples/index.html )的使用流程以及相關函式的使用方法。目前使用版本為 scikit-learn version 0.19 以上。也將加入深度學習相關資料。 本書原始資料在 Github 上公開,歡迎大家共同參與維護: [https://github.com/htygithub/machine-learning-python](https://github.com/htygithub/machine-learning-python)。 @@ -9,11 +9,27 @@ * 0.0: 2015年12月21日 * 開始本文件「機器學習:使用Python」的撰寫 * 初期以scikit-learn套件的範例介紹為主軸 - +* 0.1: 2016年4月15日 + * 「機器學習:使用Python」文件 + * Contributor: 陳巧寧、曾裕勝、黃騰毅 、蔡奕甫 + * 新增章節: Classification, Clustering, cross_decomposition, Datasets, feature_selection, general_examples + * 新增 introduction: 說明簡易的Anaconda安裝,以及利用數字辨識範例來入門機器學習的方法 + * 第 10,000個 pageview 達成 +![](images/pg10000.PNG) +* 0.2: 2016年8月30日 + * 新增應用章節,Contributor: 吳尚真 + * 增修章節: Classification, Datasets, feature_selection, general_examples +* 0.3: 2017年2月16日 + * 新增應用章節,Contributor: 楊采玲、歐育年 + * 增修章節: Neural_Network, Decision tree + * 2016年,使用者約四萬人次,頁面流量約15萬次。 +* 0.4: 2019年1月10日 + * 新增應用章節,Contributor: 吳秉宸 + * 增修章節: Cluster + * 網站移至新版gitbook +![](images/2016year.PNG) ## Scikit-learn 套件 Scikit-learn (http://scikit-learn.org/) 是一個機器學習領域的開源套件。整個專案起始於 2007年由David Cournapeau所執行的`Google Summer of Code` 計畫。而2010年之後,則由法國國家資訊暨自動化研究院(INRIA, http://www.inria.fr) 繼續主導及後續的支援及開發。近幾年(2013-2015)則由 INRIA 支持 Olivier Grisel (http://ogrisel.com) 全職負責該套件的維護工作。以開發者的角度來觀察,會發現Scikit-learn的整套使用邏輯設計的極其簡單。往往能將繁雜的機器學習理論簡化到一個步驟完成。Python的機器學習相關套件相當多,為何Scikit-learn會是首選之一呢?其實一個開源套件的選擇,最簡易的指標就是其`contributor: 貢獻者` 、 `commits:版本數量` 以及最新的更新日期。下圖是2016年1月3日 經過了美好的跨年夜後,筆者於官方開源程式碼網站(https://github.com/scikit-learn/scikit-learn) 所擷取的畫面。我們可以發現最新`commit`是四小時前,且`contributor`及`commit`數量分別為531人及 20,331個。由此可知,至少在2016年,這個專案乃然非常積極的在運作。在眾多機器學習套件中,不論是貢獻者及版本數量皆是最龐大的。也因此是本文件介紹機器學習的切入點。未來,我們希望能介紹更多的機器學習套件以及理論,也歡迎有志之士共同參與維護。 -![](sklearn_intro.PNG) - -## Scikit-learn 套件的安裝 +![](images/sklearn_intro.PNG) diff --git a/SUMMARY.md b/SUMMARY.md index 9c06893..dc31b9e 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,6 +1,7 @@ # Summary * [機器學習:使用Python](README.md) + * [簡介Scikit-learn 機器學習](Introduction/intro.md) * [分類法 Classification](Classification/Classification.md) * [Ex 1: Recognizing hand-written digits](Classification/ex1_Recognizing_hand-written_digits.md) * [EX 2: Normal and Shrinkage Linear Discriminant Analysis for classification](Classification/ex2_normal_and_shrinkage_linear_discriminant_anal_.md) @@ -14,6 +15,7 @@ * [Ex 4: Feature Selection using SelectFromModel](Feature_Selection/ex4_feature_selection_using_selectfrommodel_md.md) * [Ex 5: Test with permutations the significance of a classification score](Feature_Selection/ex5_test_with_permutations_the_significance_of_a__.md) * [Ex 6: Univariate Feature Selection](Feature_Selection/ex6_univariate_feature_selection.md) + * [Ex 7: Comparison of F-test and mutual information](Feature_Selection/ex_7comparison_of_f-test_and_mutual_information.md) * [互分解 Cross Decomposition](cross_decomposition/ex1_Compare_cross_decomposition_methods.md) * [通用範例 General Examples](general_examples/general_examplesmd.md) * [Ex 1: Plotting Cross-Validated Predictions](general_examples/Ex1_plotting_cross-validated_predictions.md) @@ -21,7 +23,33 @@ * [Ex 3: Isotonic Regression](general_examples/Ex3_isotonic_regression.md) * [Ex 4: Imputing missing values before building an estimator](general_examples/Ex4_imputing_missing_values_before_building_an_estimat.md) * [Ex 7: Face completion with a multi-output estimators](general_examples/Ex7_face_completion_with_a_multi-output_estimators.md) - -* Clustering - * [EX 12:Spectral clustering for image segmentation](ex_12spectral_clustering_for_image_segmentation.md) - +* [群聚法 Clustering](Clustering/clustering.md) + * [EX 1: Feature_agglomeration.md](Clustering/EX1_Feature_agglomeration.md) + * [EX 2: Mean-shift 群聚法.md](Clustering/EX2_A_demo_of_the_mean-shift_clustering_algorithm.md) + * [EX 6: 以群聚法切割錢幣影像.md](Clustering/EX6_Segmenting_the_picture_of_greek_coins_in_regions.md) + * [EX 10:_K-means群聚法](Clustering/EX10_K-means_Clustering.md) + * [EX 12: Spectral clustering for image segmentation](Clustering/EX12_spectral_clustering_for_image_segmentation.md) +* [支持向量機](SVM/EX1_Non_linear_SVM.md) + * [EX 1:Non_linear_SVM.md](SVM/EX1_Non_linear_SVM.md) + * [EX 4: SVM_with _custom _kernel.md](SVM/EX4_SVM_with _custom _kernel.md) +* [機器學習資料集 Datasets](Datasets/datasets.md) + * [Ex 1: The digits 手寫數字辨識](Datasets/ex1_the_digits_dataset.md) + * [Ex 3: The iris 鳶尾花資料集](Datasets/ex3_the_iris_dataset.md) +* [應用範例 Application](application/application.md) + * [波士頓房地產雲端評估(一)](application/Property_Value/linear_regression.md) + * [波士頓房地產雲端評估(二)](application/Property_Value/SVR.md) +* [類神經網路 Neural_Networks](Neural_Networks/Neural_network_models_supervised.md) + * [Ex 1: Visualization of MLP weights on MNIST](Neural_Networks/plot_mnist_filters.md) + * [Ex 2: Restricted Boltzmann Machine features for digit classification](Neural_Networks/plot_rbm_logistic_classification.md) + * [Ex 3: Compare Stochastic learning strategies for MLPClassifier](Neural_Networks/plot_mlp_training_curves.md) + * [Ex 4: Varying regularization in Multi-layer Perceptron](Neural_Networks/plot_mlp_alpha.md) +* [決策樹 Decision_trees](Decision_trees/Decision_trees.md) + * [Ex 1: Decision Tree Regression](Decision_trees/ex1_Decision_tree_regression.md) + * [Ex 2: Multi-output Decision Tree Regression](Decision_trees/ex2_Multi-output_Decision_Tree_Regression.md) + * [Ex 3: Plot the decision surface of a decision tree on the iris dataset](Decision_trees/ex3_Plot_the_decision_surface_of_a_decision_tree_on_the_iris_dataset.md) + * [Ex 4: Understanding the decision tree structure](Decision_trees/ex4_Understanding_the_decision_tree_structure.md) +* [機器學習:使用 NVIDIA JetsonTX2](nvidia_jetson_tx2/nvidia_jetson_tx2.md) + * [從零開始](nvidia_jetson_tx2/1_host.md) + * [讓 TX2 動起來](nvidia_jetson_tx2/2_init.md) + * [安裝OpenCV](nvidia_jetson_tx2/3_opencv.md) + * [安裝TensorFlow](nvidia_jetson_tx2/4_tensorflow.md) diff --git a/SVM/Custom kernel.PNG b/SVM/Custom kernel.PNG new file mode 100644 index 0000000..9a74cd7 Binary files /dev/null and b/SVM/Custom kernel.PNG differ diff --git a/SVM/EX1_Non_linear_SVM.md b/SVM/EX1_Non_linear_SVM.md new file mode 100644 index 0000000..12a29af --- /dev/null +++ b/SVM/EX1_Non_linear_SVM.md @@ -0,0 +1,113 @@ +# **範例一: Non-linear SVM** + +https://scikit-learn.org/stable/auto_examples/svm/plot_svm_nonlinear.html#sphx-glr-auto-examples-svm-plot-svm-nonlinear-py + +此範例是展示如何使用 RBF Kernel 之非線性 SVC 去做二元分類,去預測出 XOR 的輸入分佈並用 Color Map 去繪製出分類的決策邊界及區域。 + +## (一)引入函式庫 + +引入函式如下: + +1. `numpy` : 產生陣列數值 +2. `matplotlib.pyplot` : 用來繪製影像 +3. `sklearn.svm` : SVM 支持向量機之演算法物件 + +```python +import numpy as np +import matplotlib.pyplot as plt +from sklearn import svm +``` +```python +xx, yy = np.meshgrid(np.linspace(-3, 3, 500), + np.linspace(-3, 3, 500)) +np.random.seed(0) +X = np.random.randn(300, 2) +Y = np.logical_xor(X[:, 0]> 0, X[:, 1]> 0) +``` +利用`np.meshgrid`生成網格採樣點,再利用`np.random.randn()`產生隨機的資料點X,接著利用`np.logical_xor`對隨機生成之資料點做 xor 的分類產生Y。 + +## (二)SVM Model +```python +# fit the model +clf = svm.NuSVC() +clf.fit(X, Y) +``` +`svm.NuSVC`: 與 `svm.SVC` 類似,但是多了可以控制支持向量(Support Vector)個數之參數 + +```python +# plot the decision function for each datapoint on the grid +Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) +Z = Z.reshape(xx.shape) + +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, + edgecolors='k') +plt.xticks(()) +plt.yticks(()) +plt.axis([-3, 3, -3, 3]) +plt.show() +``` +最後繪製出非線性之決策邊界及資料點分布位置,繪圖方式可參考 *EX7: SVM-Kernels* 之解說。 + +下方為非線性分割之結果圖 : + +![Non-linear](nonlinear.PNG "Non-linear") + +## (三)完整程式碼 + +Python source code: plot_svm_nonlinear.py + +https://scikit-learn.org/stable/_downloads/plot_svm_nonlinear.py + +iPython source code: plot_svm_nonlinear.ipynb + +https://scikit-learn.org/stable/_downloads/plot_svm_nonlinear.ipynb + +```python +""" +============== +Non-linear SVM +============== + +Perform binary classification using non-linear SVC +with RBF kernel. The target to predict is a XOR of the +inputs. + +The color map illustrates the decision function learned by the SVC. +""" +print(__doc__) + +import numpy as np +import matplotlib.pyplot as plt +from sklearn import svm + +xx, yy = np.meshgrid(np.linspace(-3, 3, 500), + np.linspace(-3, 3, 500)) +np.random.seed(0) +X = np.random.randn(300, 2) +Y = np.logical_xor(X[:, 0]> 0, X[:, 1]> 0) + +# fit the model +clf = svm.NuSVC() +clf.fit(X, Y) + +# plot the decision function for each datapoint on the grid +Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) +Z = Z.reshape(xx.shape) + +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, + edgecolors='k') +plt.xticks(()) +plt.yticks(()) +plt.axis([-3, 3, -3, 3]) +plt.show() +``` diff --git a/SVM/EX4_SVM_with _custom _kernel.md b/SVM/EX4_SVM_with _custom _kernel.md new file mode 100644 index 0000000..a5bfa1a --- /dev/null +++ b/SVM/EX4_SVM_with _custom _kernel.md @@ -0,0 +1,151 @@ +# **範例四: SVM with custom kernel** + +https://scikit-learn.org/stable/auto_examples/svm/plot_custom_kernel.html#sphx-glr-auto-examples-svm-plot-custom-kernel-py + +在範例七中介紹了SVM 不同內建 Kernel 的比較,此範例用來展示,如何自行設計 SVM 的 Kernel + +## (一)引入函式庫 + +引入函式如下: + +1. `numpy` : 產生陣列數值 +2. `matplotlib.pyplot` : 用來繪製影像 +3. `sklearn.svm` : SVM 支持向量機之演算法物件 +4. `sklearn.datasets` : 匯入內建資料庫 + +```python +import numpy as np +import matplotlib.pyplot as plt +from sklearn import svm, datasets +``` + +```python +# import some data to play with +iris = datasets.load_iris() +X = iris.data[:, :2] # we only take the first two features. We could + # avoid this ugly slicing by using a two-dim dataset +Y = iris.target +``` +iris = datasets.load_iris() : 匯入內建資料庫鳶尾花的資料,將資料存入變數iris中 + +## (二)SVM Model + +```python +def my_kernel(X, Y): + """ + We create a custom kernel: + + (2 0) + k(X, Y) = X ( ) Y.T + (0 1) + """ + M = np.array([[2, 0], [0, 1.0]]) + return np.dot(np.dot(X, M), Y.T) +``` +自行定義函式來設計出自己想要的 Kernel 型式 +```python +h = .02 # step size in the mesh + +# we create an instance of SVM and fit out data. +clf = svm.SVC(kernel=my_kernel) +clf.fit(X, Y) +``` +將 `svm.SVC` 的 Kernel 設成自訂的 Kernel 型式 +```python +# Plot the decision boundary. For that, we will assign a color to each +# point in the mesh [x_min, x_max]x[y_min, y_max]. +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, h), np.arange(y_min, y_max, h)) +Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) +``` +`np.meshgrid` : 生成網格採樣點 +```python +# Put the result into a color plot +Z = Z.reshape(xx.shape) +plt.pcolormesh(xx, yy, Z, cmap=plt.cm.Paired) + +# Plot also the training points +plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=plt.cm.Paired, edgecolors='k') +plt.title('3-Class classification using Support Vector Machine with custom' + ' kernel') +plt.axis('tight') +plt.show() +``` +最後利用以上指令將結果圖顯示出來,`plt.pcolormesh`會根據`clf.predict`的結果繪製分類圖。 + +`plt.pcolormesh` : 能夠利用色塊的方式直觀表現出分類邊界 + +以下為結果圖 : + +![](Custom%20kernel.PNG) + +## (三)完整程式碼 + +Python source code: plot_custom_kernel.py + +https://scikit-learn.org/stable/_downloads/plot_custom_kernel.py + +iPython source code: plot_custom_kernel.ipynb + +https://scikit-learn.org/stable/_downloads/plot_custom_kernel.ipynb + +```python +""" +====================== +SVM with custom kernel +====================== + +Simple usage of Support Vector Machines to classify a sample. It will +plot the decision surface and the support vectors. + +""" +print(__doc__) + +import numpy as np +import matplotlib.pyplot as plt +from sklearn import svm, datasets + +# import some data to play with +iris = datasets.load_iris() +X = iris.data[:, :2] # we only take the first two features. We could + # avoid this ugly slicing by using a two-dim dataset +Y = iris.target + + +def my_kernel(X, Y): + """ + We create a custom kernel: + + (2 0) + k(X, Y) = X ( ) Y.T + (0 1) + """ + M = np.array([[2, 0], [0, 1.0]]) + return np.dot(np.dot(X, M), Y.T) + + +h = .02 # step size in the mesh + +# we create an instance of SVM and fit out data. +clf = svm.SVC(kernel=my_kernel) +clf.fit(X, Y) + +# Plot the decision boundary. For that, we will assign a color to each +# point in the mesh [x_min, x_max]x[y_min, y_max]. +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, h), np.arange(y_min, y_max, h)) +Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) + +# Put the result into a color plot +Z = Z.reshape(xx.shape) +plt.pcolormesh(xx, yy, Z, cmap=plt.cm.Paired) + +# Plot also the training points +plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=plt.cm.Paired, edgecolors='k') +plt.title('3-Class classification using Support Vector Machine with custom' + ' kernel') +plt.axis('tight') +plt.show() +``` diff --git a/SVM/EX7_SVM_Kernels.md b/SVM/EX7_SVM_Kernels.md new file mode 100644 index 0000000..34d5d40 --- /dev/null +++ b/SVM/EX7_SVM_Kernels.md @@ -0,0 +1,207 @@ +# **範例七: SVM-Kernels** + +https://scikit-learn.org/stable/auto_examples/svm/plot_svm_kernels.html#sphx-glr-auto-examples-svm-plot-svm-kernels-py + +此範例展示三種不同 SVM Kernel 所呈現的結果,其中 Polynomial 及 RBF 常用來處理非線性之分類 + +1. Linear +2. Polynomial +3. RBF(Radio Basis Function) + +## (一)引入函式庫 + +引入函式如下: + +1. `numpy` : 產生陣列數值 +2. `matplotlib.pyplot` : 用來繪製影像 +3. `sklearn.svm` : SVM 支持向量機之演算法物件 + +```python +import numpy as np +import matplotlib.pyplot as plt +from sklearn import svm +``` +```python +# Our dataset and targets +X = np.c_[(.4, -.7), + (-1.5, -1), + (-1.4, -.9), + (-1.3, -1.2), + (-1.1, -.2), + (-1.2, -.4), + (-.5, 1.2), + (-1.5, 2.1), + (1, 1), + # -- + (1.3, .8), + (1.2, .5), + (.2, -2), + (.5, -2.4), + (.2, -2.3), + (0, -2.7), + (1.3, 2.1)].T +Y = [0] * 8 + [1] * 8 +``` +首先,第一步先自行產生出資料點X及目標值Y + +## (二)Different SVM Kernels +```python +# figure number +fignum = 1 + +# fit the model +for kernel in ('linear', 'poly', 'rbf'): + clf = svm.SVC(kernel=kernel, gamma=2) + clf.fit(X, Y) + + # plot the line, the points, and the nearest vectors to the plane + plt.figure(fignum, figsize=(4, 3)) + plt.clf() + + plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=80, + facecolors='none', zorder=10, edgecolors='k') + plt.scatter(X[:, 0], X[:, 1], c=Y, zorder=10, cmap=plt.cm.Paired, + edgecolors='k') + + plt.axis('tight') + x_min = -3 + x_max = 3 + y_min = -3 + y_max = 3 + + XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j] + Z = clf.decision_function(np.c_[XX.ravel(), YY.ravel()]) + + # Put the result into a color plot + Z = Z.reshape(XX.shape) + plt.figure(fignum, figsize=(4, 3)) + plt.pcolormesh(XX, YY, Z> 0, cmap=plt.cm.Paired) + plt.contour(XX, YY, Z, colors=['k', 'k', 'k'], linestyles=['--', '-', '--'], + levels=[-.5, 0, .5]) + + plt.xlim(x_min, x_max) + plt.ylim(y_min, y_max) + + plt.xticks(()) + plt.yticks(()) + fignum = fignum + 1 +plt.show() +``` +接著利用`svm.SVC`去設定 SVM 的相關參數,包括Kernel類型及Gamma值等等,其中Gamma值是只有當Kernel為'rbf','poly','sigmoid'時才需設定,設定完 SVM 後利用`fit`這個指令去訓練我們的資料和目標值。 + +最後,利用`plt.scatter`用來畫散點圖的指令幫助我們畫出資料點及標示出 support vector 的資料點位置,在下方結果圖中,標示為雙圈的資料點就是 support vector,接著利用`plt.contour`來畫出 SVM 的 decision boundary,在結果圖中以實線表示;虛線部分則為 margin 的範圍。 + +`plt.scatter`參數設定: + +* s : Size 大小 +* c : Color 設定 +* zorder : 繪圖的順序,類似圖層概念,zorder 值越大代表越上層 + +`plt.contour`參數設定: + +* colors : 設定等高線的顏色 +* linestyles : 設定線所要呈現的方式 +* levels : 該條等高線所代表的值 + +關於 support vector,margin 及 decision boundary 的相關介紹可以參考另外一篇 SVM 的教學 *EX9: SVM Margins Example* 中會有說明。 + +下面分別為 Linear, Polynomial, RBF 三種kernel產生出來的結果圖 : + +![Linear Kernel](https://github.com/I-Yun/machine-learning-python/blob/master/SVM/linear.PNG "Linear Kernel") ![Polynomial Kernel](https://github.com/I-Yun/machine-learning-python/blob/master/SVM/poly.PNG "Polynomial Kernel") ![RBF Kernel](https://github.com/I-Yun/machine-learning-python/blob/master/SVM/rbf.PNG "RBF Kernel") + +當然在 SVM 的 Kernel 選擇上不只能夠使用內建的 Kernel Type ,也可以自行設計 Kernel,在 SVM 的教學 *EX4: SVM with custom kernel* 中會有範例說明。 + +## (三)完整程式碼 + +Python source code: plot_svm_kernels.py + +https://scikit-learn.org/stable/_downloads/plot_svm_kernels.py + +iPython source code: plot_svm_kernels.ipynb + +https://scikit-learn.org/stable/_downloads/plot_svm_kernels.ipynb + +```python +""" +========================================================= +SVM-Kernels +========================================================= + +Three different types of SVM-Kernels are displayed below. +The polynomial and RBF are especially useful when the +data-points are not linearly separable. + + +""" +print(__doc__) + + +# Code source: Gaël Varoquaux +# License: BSD 3 clause + +import numpy as np +import matplotlib.pyplot as plt +from sklearn import svm + + +# Our dataset and targets +X = np.c_[(.4, -.7), + (-1.5, -1), + (-1.4, -.9), + (-1.3, -1.2), + (-1.1, -.2), + (-1.2, -.4), + (-.5, 1.2), + (-1.5, 2.1), + (1, 1), + # -- + (1.3, .8), + (1.2, .5), + (.2, -2), + (.5, -2.4), + (.2, -2.3), + (0, -2.7), + (1.3, 2.1)].T +Y = [0] * 8 + [1] * 8 + +# figure number +fignum = 1 + +# fit the model +for kernel in ('linear', 'poly', 'rbf'): + clf = svm.SVC(kernel=kernel, gamma=2) + clf.fit(X, Y) + + # plot the line, the points, and the nearest vectors to the plane + plt.figure(fignum, figsize=(4, 3)) + plt.clf() + + plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=80, + facecolors='none', zorder=10, edgecolors='k') + plt.scatter(X[:, 0], X[:, 1], c=Y, zorder=10, cmap=plt.cm.Paired, + edgecolors='k') + + plt.axis('tight') + x_min = -3 + x_max = 3 + y_min = -3 + y_max = 3 + + XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j] + Z = clf.decision_function(np.c_[XX.ravel(), YY.ravel()]) + + # Put the result into a color plot + Z = Z.reshape(XX.shape) + plt.figure(fignum, figsize=(4, 3)) + plt.pcolormesh(XX, YY, Z> 0, cmap=plt.cm.Paired) + plt.contour(XX, YY, Z, colors=['k', 'k', 'k'], linestyles=['--', '-', '--'], + levels=[-.5, 0, .5]) + + plt.xlim(x_min, x_max) + plt.ylim(y_min, y_max) + + plt.xticks(()) + plt.yticks(()) + fignum = fignum + 1 +plt.show() +``` diff --git a/SVM/EX9_SVM_Margins_Example.md b/SVM/EX9_SVM_Margins_Example.md new file mode 100644 index 0000000..6d95139 --- /dev/null +++ b/SVM/EX9_SVM_Margins_Example.md @@ -0,0 +1,201 @@ +# **範例九: SVM_Margins_Example** + +https://scikit-learn.org/stable/auto_examples/svm/plot_svm_margin.html#sphx-glr-auto-examples-svm-plot-svm-margin-py + +SVM是一種監督式的學習方法,用統計風險最小化的原則來估計一個分類的超平面(hyperplane),就是找到一個決策邊界(decision boundary)讓兩類之間的邊界(margins)最大化,使其可以完美區隔開來。 + +此範例是在展示參數 C (penalty)對於決策邊界(decision boundary)及邊界(margins)的影響。 + +## (一)引入函式庫 + +引入函式如下: + +1. `numpy` : 產生陣列數值 +2. `matplotlib.pyplot` : 用來繪製影像 +3. `sklearn.svm` : SVM 支持向量機之演算法物件 + +```python +import numpy as np +import matplotlib.pyplot as plt +from sklearn import svm +``` + +```python +# we create 40 separable points +np.random.seed(0) +X = np.r_[np.random.randn(20, 2) - [2, 2], np.random.randn(20, 2) + [2, 2]] +Y = [0] * 20 + [1] * 20 +``` +首先,第一步先利用 `np.random.seed(0)` 及 `np.random.randn()` 自行產生出40個隨機資料點X及目標值Y + +* `np.random.seed(0)` : 使得隨機數據可預測,當設置相同的seed,每次生成的隨機數相同;若不設置seed,則每次會生成不同的隨機數。 +* `np.random.randn()` : 隨機生成高斯分布之資料點。 + +## (二)SVM Model +```python +# figure number +fignum = 1 + +# fit the model +for name, penalty in (('unreg', 1), ('reg', 0.05)): + + clf = svm.SVC(kernel='linear', C=penalty) + clf.fit(X, Y) + + # get the separating hyperplane + w = clf.coef_[0] + a = -w[0] / w[1] + xx = np.linspace(-5, 5) + yy = a * xx - (clf.intercept_[0]) / w[1] + + # plot the parallels to the separating hyperplane that pass through the + # support vectors (margin away from hyperplane in direction + # perpendicular to hyperplane). This is sqrt(1+a^2) away vertically in + # 2-d. + margin = 1 / np.sqrt(np.sum(clf.coef_ ** 2)) + yy_down = yy - np.sqrt(1 + a ** 2) * margin + yy_up = yy + np.sqrt(1 + a ** 2) * margin +``` +利用`svm.SVC`這個指令去設定 SVM 的相關參數,這裡除了要設定 Kernel Type 之外,還需要設定`參數 C `的數值,`參數 C` 的數值大小會影響到 Margin 範圍的大小,`參數 C` 的值越大,Margin 的範圍越小;反之,若`參數 C` 的值越小,Margin 的範圍越大,其中落在邊界上的資料點我們就稱之為 Support Vector + +```python +# plot the line, the points, and the nearest vectors to the plane + plt.figure(fignum, figsize=(4, 3)) + plt.clf() + plt.plot(xx, yy, 'k-') + plt.plot(xx, yy_down, 'k--') + plt.plot(xx, yy_up, 'k--') + + plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=80, + facecolors='none', zorder=10, edgecolors='k') + plt.scatter(X[:, 0], X[:, 1], c=Y, zorder=10, cmap=plt.cm.Paired, + edgecolors='k') + + plt.axis('tight') + x_min = -4.8 + x_max = 4.2 + y_min = -6 + y_max = 6 + + XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j] + Z = clf.predict(np.c_[XX.ravel(), YY.ravel()]) + + # Put the result into a color plot + Z = Z.reshape(XX.shape) + plt.figure(fignum, figsize=(4, 3)) + plt.pcolormesh(XX, YY, Z, cmap=plt.cm.Paired) + + plt.xlim(x_min, x_max) + plt.ylim(y_min, y_max) + + plt.xticks(()) + plt.yticks(()) + fignum = fignum + 1 + +plt.show() +``` +最後畫出結果圖,包含實線的 decision boundary,虛線的 margin 範圍及各個資料點和 support vector,可參考 *EX7 SVM Kernels* 的相關說明。 + +下列為不同`參數 C` 所造成 Margin 大小變化的結果圖 : + +![Large C](https://github.com/I-Yun/machine-learning-python/blob/master/SVM/Large_C.PNG "Large C") ![Small C](https://github.com/I-Yun/machine-learning-python/blob/master/SVM/Small_C.PNG "Small C") + +## (三)完整程式碼 + +Python source code: plot_svm_margin.py + +https://scikit-learn.org/stable/_downloads/plot_svm_margin.py + +iPython source code: plot_svm_margin.ipynb + +https://scikit-learn.org/stable/_downloads/plot_svm_margin.ipynb + +```python +""" +========================================================= +SVM Margins Example +========================================================= +The plots below illustrate the effect the parameter `C` has +on the separation line. A large value of `C` basically tells +our model that we do not have that much faith in our data's +distribution, and will only consider points close to line +of separation. + +A small value of `C` includes more/all the observations, allowing +the margins to be calculated using all the data in the area. + +""" +print(__doc__) + + +# Code source: Gaël Varoquaux +# Modified for documentation by Jaques Grobler +# License: BSD 3 clause + +import numpy as np +import matplotlib.pyplot as plt +from sklearn import svm + +# we create 40 separable points +np.random.seed(0) +X = np.r_[np.random.randn(20, 2) - [2, 2], np.random.randn(20, 2) + [2, 2]] +Y = [0] * 20 + [1] * 20 + +# figure number +fignum = 1 + +# fit the model +for name, penalty in (('unreg', 1), ('reg', 0.05)): + + clf = svm.SVC(kernel='linear', C=penalty) + clf.fit(X, Y) + + # get the separating hyperplane + w = clf.coef_[0] + a = -w[0] / w[1] + xx = np.linspace(-5, 5) + yy = a * xx - (clf.intercept_[0]) / w[1] + + # plot the parallels to the separating hyperplane that pass through the + # support vectors (margin away from hyperplane in direction + # perpendicular to hyperplane). This is sqrt(1+a^2) away vertically in + # 2-d. + margin = 1 / np.sqrt(np.sum(clf.coef_ ** 2)) + yy_down = yy - np.sqrt(1 + a ** 2) * margin + yy_up = yy + np.sqrt(1 + a ** 2) * margin + + # plot the line, the points, and the nearest vectors to the plane + plt.figure(fignum, figsize=(4, 3)) + plt.clf() + plt.plot(xx, yy, 'k-') + plt.plot(xx, yy_down, 'k--') + plt.plot(xx, yy_up, 'k--') + + plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=80, + facecolors='none', zorder=10, edgecolors='k') + plt.scatter(X[:, 0], X[:, 1], c=Y, zorder=10, cmap=plt.cm.Paired, + edgecolors='k') + + plt.axis('tight') + x_min = -4.8 + x_max = 4.2 + y_min = -6 + y_max = 6 + + XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j] + Z = clf.predict(np.c_[XX.ravel(), YY.ravel()]) + + # Put the result into a color plot + Z = Z.reshape(XX.shape) + plt.figure(fignum, figsize=(4, 3)) + plt.pcolormesh(XX, YY, Z, cmap=plt.cm.Paired) + + plt.xlim(x_min, x_max) + plt.ylim(y_min, y_max) + + plt.xticks(()) + plt.yticks(()) + fignum = fignum + 1 + +plt.show() +``` diff --git a/SVM/Large_C.PNG b/SVM/Large_C.PNG new file mode 100644 index 0000000..247c016 Binary files /dev/null and b/SVM/Large_C.PNG differ diff --git a/SVM/Small_C.PNG b/SVM/Small_C.PNG new file mode 100644 index 0000000..2a97a8a Binary files /dev/null and b/SVM/Small_C.PNG differ diff --git a/SVM/linear.PNG b/SVM/linear.PNG new file mode 100644 index 0000000..c44980c Binary files /dev/null and b/SVM/linear.PNG differ diff --git a/SVM/nonlinear.PNG b/SVM/nonlinear.PNG new file mode 100644 index 0000000..5bef07c Binary files /dev/null and b/SVM/nonlinear.PNG differ diff --git a/SVM/poly.PNG b/SVM/poly.PNG new file mode 100644 index 0000000..a6bd064 Binary files /dev/null and b/SVM/poly.PNG differ diff --git a/SVM/rbf.PNG b/SVM/rbf.PNG new file mode 100644 index 0000000..3df6d47 Binary files /dev/null and b/SVM/rbf.PNG differ diff --git a/SVM/test.txt b/SVM/test.txt new file mode 100644 index 0000000..e69de29 diff --git a/application/Property_Value/SVR.md b/application/Property_Value/SVR.md new file mode 100644 index 0000000..26db054 --- /dev/null +++ b/application/Property_Value/SVR.md @@ -0,0 +1,111 @@ +##支持向量機回歸分析: Property value prediction + +此檔案使用scikit-learn 機器學習套件裡的SVR演算法,來達成波士頓房地產價錢預測 + + +## (一)引入函式庫及內建波士頓房地產資料庫 + +引入之函式庫如下 + +1. `sklearn.datasets`: 用來匯入內建之波士頓房地產資料庫 +2. `sklearn.SVR`: 支持向量機回歸分析之演算法 +3. `matplotlib.pyplot`: 用來繪製影像 + +```python +from sklearn import datasets +from sklearn.svm import SVR +import matplotlib.pyplot as plt + +boston = datasets.load_boston() +X=boston.data +y = boston.target +``` + +使用 `datasets.load_boston()` 將資料存入至`boston`。 +使用`datasets.data`將士頓房地產資料的數據資料(data)匯入到`X`。 +使用`datasets.target`將士頓房地產資料的預測數值匯入到`y`。 +為一個dict型別資料,我們看一下資料的內容。 + + +## (二)`SVR`的使用 + +`sklearn.svm.SVR`(kernel='rbf', degree=3, gamma='auto', coef0=0.0, tol=0.001, C=1.0, epsilon=0.1, shrinking=True, cache_size=200, verbose=False, max_iter=-1) + +```python +clf = SVR(kernel='rbf', C=1e3, gamma=0.1) +clf.fit(X, y) +``` +使用`clf = SVR(kernel='rbf', C=1e3, gamma=0.1)`,將SVR演算法引入到clf,並設定SVR演算法的參數。 +使用`clf.fit(X, y)`,用波士頓房地產數據(boston.data)以及預測目標(y)來訓練預測機clf + +## (三)使用`joblib.dump`匯出預測器 + +```python +from sklearn.externals import joblib +joblib.dump(clf,"./machine_SVR.pkl") +``` +使用`joblib.dump`將SVR預測器匯出為pkl檔。 + + +##(四)訓練以及分類 +接著使用`clf=joblib.load("./machine_SVR.pkl")`將pkl檔匯入為一個SVR預測器`clf`。接著使用波士頓房地產數據(boston.data),以及預測目標(y)來訓練預測機clf `clf.fit(boston.data, y)`。最後,使用`predict_y=clf.predict(boston.data[2])`預測第三筆資料的價格,並將結果存入`predicted_y`變數。 + +```python +clf=joblib.load("./machine_SVR.pkl") +clf.fit(boston.data, y) +predict_y=clf.predict(boston.data[2]) +``` + + +##(五)使用`score`計算準確率 +先用`predict=clf.predict(X)`將所有波士頓房地產數據丟入clf預測機預測,並將所預測出的結果存入`predict`。接著使用`clf.score(X, y)`來計算準確率,score=1為最理想情況,本範例中`score`=0.99988275378631286 + +```python +predict=clf.predict(X) +clf.score(X, y) +``` + + +## (六)繪出預測結果與實際目標差異圖 +X軸為預測結果,Y軸為回歸目標。 +並劃出一條斜率=1的理想曲線(用虛線標示)。 +紅點為房地產第三項數據的預測結果 + +因為使用clf的準確率很高,所以預測結果與回歸目標幾乎一樣,scatter的點會幾乎都在理想曲線上。 + +```python +plt.scatter(predict,y,s=2) +plt.plot(predict_y, predict_y, 'ro') +plt.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', lw=2) +plt.xlabel('Predicted') +plt.ylabel('Measured') +``` +![](images/SVR_predict_figure.png) + + +## (六)完整程式碼 + +```python +%matplotlib inline +from sklearn import datasets +from sklearn.svm import SVR +import matplotlib.pyplot as plt + +boston = datasets.load_boston() +X=boston.data +y = boston.target +clf = SVR(kernel='rbf', C=1e3, gamma=0.1) +clf.fit(X, y) +from sklearn.externals import joblib +joblib.dump(clf,"./machine_SVR.pkl") +clf=joblib.load("./machine_SVR.pkl") +clf.fit(boston.data, y) +predict_y=clf.predict(boston.data[2]) +predict=clf.predict(X) +clf.score(X, y) +plt.scatter(predict,y,s=2) +plt.plot(predict_y, predict_y, 'ro') +plt.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', lw=2) +plt.xlabel('Predicted') +plt.ylabel('Measured') +``` diff --git a/application/Property_Value/images/SVR_predict_figure.png b/application/Property_Value/images/SVR_predict_figure.png new file mode 100644 index 0000000..46677d5 Binary files /dev/null and b/application/Property_Value/images/SVR_predict_figure.png differ diff --git a/application/Property_Value/images/lr_predict_figure.png b/application/Property_Value/images/lr_predict_figure.png new file mode 100644 index 0000000..6340265 Binary files /dev/null and b/application/Property_Value/images/lr_predict_figure.png differ diff --git a/application/Property_Value/linear_regression.md b/application/Property_Value/linear_regression.md new file mode 100644 index 0000000..c2753a8 --- /dev/null +++ b/application/Property_Value/linear_regression.md @@ -0,0 +1,120 @@ +##線性回歸分析: Property value prediction + +此檔案使用scikit-learn 機器學習套件裡的linear regression演算法,來達成波士頓房地產價錢預測 + +1. 資料集:波士頓房產 +2. 特徵:房地產客觀數據,如年份、平面大小 +3. 預測目標:房地產價格 +4. 機器學習方法:線性迴歸 +5. 探討重點:10 等分的交叉驗証(10-fold Cross-Validation)來實際測試資料以及預測值的關係 +6. 關鍵函式: `sklearn.cross_validation.cross_val_predict`;`joblib.dump`;`joblib.load` + + +## (一)引入函式庫及內建波士頓房地產資料庫 + +引入之函式庫如下 + +1. `sklearn.datasets`: 用來匯入內建之波士頓房地產資料庫 +2. `sklearn.cross_val_predict`: 使用交叉驗證用來評估辨識準確度 +3. `sklearn.linear_model`: 線性分析之模組 +4. `matplotlib.pyplot`: 用來繪製影像 + +```python +from sklearn import datasets +from sklearn.cross_validation import cross_val_predict +from sklearn import linear_model +import matplotlib.pyplot as plt + +lr = linear_model.LinearRegression() +# The boston dataset +boston = datasets.load_boston() +y = boston.target +``` + +使用`linear_model.LinearRegression()`將線性迴歸分析演算法引入到`lr`。 +使用`datasets.target`將士頓房地產資料的預測數值匯入到`y`。 +使用 `datasets.load_boston()` 將資料存入, `boston` 為一個dict型別資料,我們看一下資料的內容。 + +| 顯示 | 說明 | +| -- | -- | +| ('data', (506, 13))| 房地產的資料集,共506筆房產13個特徵 | +| ('feature_names', (13,)) | 房地產的特徵名 | +| ('target', (506,)) | 回歸目標 | +| DESCR | 資料之描述 | + + +## (二)`cross_val_predict`的使用 + +`sklearn.cross_validation.cross_val_predict`(estimator, X, y=None, cv=None, n_jobs=1, verbose=0, fit_params=None, pre_dispatch='2*n_jobs') + +X為機器學習數據, +y為回歸目標, +cv為交叉驗証時資料切分的依據,範例為10則將資料切分為10等分,以其中9等分為訓練集,另外一等分則為測試集。 +```python +predicted = cross_val_predict(lr, boston.data, y, cv=10) +``` + + +## (三)使用`joblib.dump`匯出預測器 + +```python +from sklearn.externals import joblib + +joblib.dump(lr,"./lr_machine.pkl") +``` +使用`joblib.dump`將線性回歸預測器匯出為pkl檔。 + + +##(四)訓練以及分類 +接著使用`lr=joblib.load("./lr_machine.pkl")`將pkl檔匯入為一個linear regression預測器`lr`。接著使用波士頓房地產數據(boston.data),以及預測目標(y)來訓練預測機lr `lr.fit(boston.data, y)`。最後,使用`predict_y=lr.predict(boston.data[2])`預測第三筆資料的價格,並將結果存入`predicted_y`變數。 + +```python +lr=joblib.load("./lr_machine.pkl") +lr.fit(boston.data, y) +predict_y=lr.predict(boston.data[2]) +``` + + +## (五)繪出預測結果與實際目標差異圖 +X軸為預測結果,Y軸為回歸目標。 +並劃出一條斜率=1的理想曲線(用虛線標示)。 + +紅點為房地產第三項數據的預測結果。 + +```python +plt.scatter(predicted,y,s=2) +plt.plot(predict_y, predict_y, 'ro') +plt.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', lw=2) +plt.xlabel('Predicted') +plt.ylabel('Measured') +``` +![](images/lr_predict_figure.png) + + +## (六)完整程式碼 + +```python +%matplotlib inline +from sklearn import datasets +from sklearn.cross_validation import cross_val_predict +from sklearn import linear_model +import matplotlib.pyplot as plt + +lr = linear_model.LinearRegression() +boston = datasets.load_boston() +y = boston.target +# cross_val_predict returns an array of the same size as `y` where each entry +# is a prediction obtained by cross validated: +predicted = cross_val_predict(lr, boston.data, y, cv=10) +from sklearn.externals import joblib + +joblib.dump(lr,"./lr_machine.pkl") +lr=joblib.load("./lr_machine.pkl") +lr.fit(boston.data, y) +predict_y=lr.predict(boston.data[2]) +plt.scatter(predicted,y,s=2) +plt.plot(predict_y, predict_y, 'ro') +plt.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', lw=2) +plt.xlabel('Predicted') +plt.ylabel('Measured') +``` diff --git a/application/application.md b/application/application.md new file mode 100644 index 0000000..cb2be78 --- /dev/null +++ b/application/application.md @@ -0,0 +1 @@ +# 應用範例 Applications diff --git a/book.json b/book.json index 6492f13..79a149c 100644 --- a/book.json +++ b/book.json @@ -1,11 +1,15 @@ -{ "plugins": ["mathjax"], - "pdf": {"fontSize": 8}, +{ "pdf": {"fontSize": 8}, + "plugins": [ + "header" + ], "styles": { - "pdf": "styles/pdf.css"}, - "plugins": ["ga"], + "pdf": "styles/pdf.css"}, "pluginsConfig": { - "ga": { - "token": "UA-7819893-6" + "mathjax":{ + "forceSVG": true + }, + "layout": { + "headerPath" : "header.html" } } } diff --git a/general_examples/Ex1_plotting_cross-validated_predictions.md b/general_examples/Ex1_plotting_cross-validated_predictions.md index a3dbf9c..3c79684 100644 --- a/general_examples/Ex1_plotting_cross-validated_predictions.md +++ b/general_examples/Ex1_plotting_cross-validated_predictions.md @@ -2,7 +2,12 @@ http://scikit-learn.org/stable/auto_examples/plot_cv_predict.html -這個範例可以看出用`cross_val_predict`的預測誤差。 +1. 資料集:波士頓房產 +2. 特徵:房地產客觀數據,如年份、平面大小 +3. 預測目標:房地產價格 +4. 機器學習方法:線性迴歸 +5. 探討重點:10 等分的交叉驗証(10-fold Cross-Validation)來實際測試資料以及預測值的關係 +6. 關鍵函式: `sklearn.cross_validation.cross_val_predict` ## (一)引入函式庫及內建測試資料庫 @@ -10,8 +15,8 @@ http://scikit-learn.org/stable/auto_examples/plot_cv_predict.html 1. `matplotlib.pyplot`: 用來繪製影像 2. `sklearn.datasets`: 用來繪入內建測試資料庫 -3. `sklearn.cross_validation import cross_val_predict` -4. `sklearn.linear_model` +3. `sklearn.cross_validation import cross_val_predict`:利用交叉驗證的方式來預測 +4. `sklearn.linear_model`:使用線性迴歸 @@ -27,20 +32,20 @@ y = boston.target | 顯示 | 說明 | | -- | -- | -| ('data', (506, 13))| 機器學習數據 | -| ('feature_names', (13,)) | | +| ('data', (506, 13))| 房地產的資料集,共506筆房產13個特徵 | +| ('feature_names', (13,)) | 房地產的特徵名 | | ('target', (506,)) | 回歸目標 | | DESCR | 資料之描述 | -## (三)用`sklearn.cross_validation.cross_val_predict`產生估計值 +## (三)`cross_val_predict`的使用 -`sklearn.cross_validation.cross_val_predict`(estimator, X, y=None, cv=None, n_jobs=1, verbose=0, fit_params=None, pre_dispatch='2*n_jobs')[source] +`sklearn.cross_validation.cross_val_predict`(estimator, X, y=None, cv=None, n_jobs=1, verbose=0, fit_params=None, pre_dispatch='2*n_jobs') X為機器學習數據, y為回歸目標, -cv為疊代次數。 +cv為交叉驗証時資料切分的依據,範例為10則將資料切分為10等分,以其中9等分為訓練集,另外一等分則為測試集。 ```python predicted = cross_val_predict(lr, boston.data, y, cv=10) ``` diff --git a/general_examples/Ex2_feature_stacker.md b/general_examples/Ex2_feature_stacker.md index 662411d..4cc1b13 100644 --- a/general_examples/Ex2_feature_stacker.md +++ b/general_examples/Ex2_feature_stacker.md @@ -3,12 +3,15 @@ http://scikit-learn.org/stable/auto_examples/feature_stacker.html -在許多真的案例中,會有很多方法可以從一個數據集中提取特徵。也常常會組合多個方法來獲得良好的特徵。這個例子說明如何使用` FeatureUnion` 來結合由` PCA` 和` univariate selection` 時的特徵。雖然在這個例子中使用此方法並沒有特殊幫助,只是用來說明如何使用` FeatureUnion` 。 +在許多實際應用中,會有很多方法可以從一個數據集中提取特徵。也常常會組合多個方法來獲得良好的特徵。這個例子說明如何使用` FeatureUnion` 來結合由` PCA` 和` univariate selection` 時的特徵。 這個範例的主要目的: -* 使用iris 鳶尾花資料集 -* 使用`FeatureUnion` - +1. 資料集:iris 鳶尾花資料集 +2. 特徵:鳶尾花特徵 +3. 預測目標:是那一種鳶尾花 +4. 機器學習方法:SVM 支持向量機 +5. 探討重點:特徵結合 +6. 關鍵函式: `sklearn.pipeline.FeatureUnion` # (一)資料匯入及描述 @@ -38,7 +41,7 @@ X, y = iris.data, iris.target | ('data', (150L, 4L)) | 有150筆資料,共四種特徵 | | ('target', (150L,))| 這150筆資料各是那一種鳶尾花| | DESCR | 資料之描述 | -| feature_names| 四個特徵代表的意義 | +| feature_names| 4個特徵代表的意義 | # (二)PCA與SelectKBest * `PCA(n_components = 主要成份數量)`:Principal Component Analysis(PCA)主成份分析,是一個常用的將資料維度減少的方法。它的原理是找出一個新的座標軸,將資料投影到該軸時,數據的變異量會最大。利用這個方式減少資料維度,又希望能保留住原數據點的特性。 @@ -55,8 +58,9 @@ selection = SelectKBest(k=1) ``` # (三)FeatureUnionc -使用sklearn.pipeline.FeatureUnion合併主成分分析(PCA)和綜合篩選(SelectKBest)。
-最後得到選出的特徵。 + +* 使用sklearn.pipeline.FeatureUnion合併主成分分析(PCA)和綜合篩選(SelectKBest)。 +* 最後得到選出的特徵 @@ -70,14 +74,9 @@ X_features = combined_features.fit(X, y).transform(X) ``` # (四)找到最佳的結果 -* Scikit-lenarn的支持向量機分類涵式庫提供使用簡單易懂的指令,可以用 SVC() 建立運算物件,之後並可以用運算物件內的方法 .fit() 與 .predict() 來做訓練與預測。 - -* 使用`GridSearchCV`交叉驗證,得到由參數網格計算出的分數網格,並找到分數網格中最優的點。 - - 最後印出這個點所代表的參數 - - +* Scikit-learn的支持向量機分類函式庫利用 SVC() 建立運算物件,之後並可以用運算物件內的方法 .fit() 與 .predict() 來做訓練與預測。 +* 使用`GridSearchCV`交叉驗證,得到由參數網格計算出的分數網格,並找到分數網格中最佳點。最後顯示這個點所代表的參數 ```python @@ -98,5 +97,54 @@ print(grid_search.best_estimator_) 結果顯示 ``` Fitting 3 folds for each of 18 candidates, totalling 54 fits [CV] features__univ_select__k=1, features__pca__n_components=1, svm__C=0.1 - [CV] features__univ_select__k=1, features__pca__n_components=1, svm__C=0.1, score=0.960784 - 0.0s + [CV] features__univ_select__k=1, features__pca__n_components=1, svm__C=0.1, score=0.960784 - 0.0s +``` + + +## (五)完整程式碼 +Python source code: feature_stacker.py +http://scikit-learn.org/stable/auto_examples/feature_stacker.html + +```python +# Author: Andreas Mueller +# +# License: BSD 3 clause + +from sklearn.pipeline import Pipeline, FeatureUnion +from sklearn.grid_search import GridSearchCV +from sklearn.svm import SVC +from sklearn.datasets import load_iris +from sklearn.decomposition import PCA +from sklearn.feature_selection import SelectKBest + +iris = load_iris() + +X, y = iris.data, iris.target + +# This dataset is way to high-dimensional. Better do PCA: +pca = PCA(n_components=2) + +# Maybe some original features where good, too? +selection = SelectKBest(k=1) + +# Build estimator from PCA and Univariate selection: + +combined_features = FeatureUnion([("pca", pca), ("univ_select", selection)]) + +# Use combined features to transform dataset: +X_features = combined_features.fit(X, y).transform(X) + +svm = SVC(kernel="linear") + +# Do grid search over k, n_components and C: + +pipeline = Pipeline([("features", combined_features), ("svm", svm)]) + +param_grid = dict(features__pca__n_components=[1, 2, 3], + features__univ_select__k=[1, 2], + svm__C=[0.1, 1, 10]) + +grid_search = GridSearchCV(pipeline, param_grid=param_grid, verbose=10) +grid_search.fit(X, y) +print(grid_search.best_estimator_) ``` diff --git a/general_examples/Ex4_imputing_missing_values_before_building_an_estimat.md b/general_examples/Ex4_imputing_missing_values_before_building_an_estimat.md index b3abc04..e30298e 100644 --- a/general_examples/Ex4_imputing_missing_values_before_building_an_estimat.md +++ b/general_examples/Ex4_imputing_missing_values_before_building_an_estimat.md @@ -1,9 +1,8 @@ # 通用範例/範例四: Imputing missing values before building an estimator -http://scikit-learn.org/stable/auto_examples/missing_values.html#example-missing-values-py +http://scikit-learn.org/stable/auto_examples/missing_values.htm -在這範例說明有時輸入missing values可以比對刪掉missing values得到更好的結果。但這並不適用於所有的情況,仍然需要進行交叉驗證。
-missing values可以用均值、中位值,或者頻繁出現的值代替。中位值對大數量級的數據來說是比較穩定的估計值。 +在這範例說明有時補充缺少的數據(missing values),可以得到更好的結果。但仍然需要進行交叉驗證。來驗證填充是否合適
。而missing values可以用均值、中位值,或者頻繁出現的值代替。中位值對大數據之機器學習來說是比較穩定的估計值。 ## (一)引入函式庫及內建測試資料庫 @@ -12,7 +11,7 @@ missing values可以用均值、中位值,或者頻繁出現的值代替。中 1. `sklearn.ensemble.RandomForestRegressor`: 隨機森林回歸 2. `sklearn.pipeline.Pipeline`: 串聯估計器 3. `sklearn.preprocessing.Imputer`: 缺失值填充 -4. `sklearn.cross_validation import cross_val_score`:交叉验证函数 +4. `sklearn.cross_validation import cross_val_score`:交叉驗證 ## (二)引入內建測試資料庫(boston房產資料) 使用 `datasets.load_boston()` 將資料存入, `boston` 為一個dict型別資料,我們看一下資料的內容。
@@ -29,12 +28,13 @@ n_features = X_full.shape[1] | 顯示 | 說明 | | -- | -- | | ('data', (506, 13))| 機器學習數據 | -| ('feature_names', (13,)) | | +| ('feature_names', (13,)) | 房地產相關特徵 | | ('target', (506,)) | 回歸目標 | | DESCR | 資料之描述 | +共有506筆資料及13個特徵('CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD','TAX', 'PTRATIO', 'B', 'LSTAT')用來描述房地產的週邊狀況,如CRIM (per capita crime rate by town)跟該區域之犯罪率有關。而迴歸目標為房地產的價格,以1000美元為單位。也就是說這個範例希望以房地產的週遭客觀數據來預測房地產的價格。 -## (三)估計整個數據集的得分 +## (三)利用整個數據集來預測 全部的資料使用隨機森林回歸函數進行交叉驗證,得到一個分數。
Score with the entire dataset = 0.56 @@ -44,7 +44,8 @@ score = cross_val_score(estimator, X_full, y_full).mean() print("Score with the entire dataset = %.2f" % score) ``` -## (四)設定損失比例,並估計移除missing values後的得分 +## (四)模擬資料損失時之預測情形 +設定損失比例,並估計移除missing values後的得分 損失比例75%,損失樣本數為379筆,剩餘樣本為127筆。
將127筆資料進行隨機森林回歸函數進行交叉驗證,並得到一個分數。
@@ -65,6 +66,7 @@ estimator = RandomForestRegressor(random_state=0, n_estimators=100) score = cross_val_score(estimator, X_filtered, y_filtered).mean() print("Score without the samples containing missing values = %.2f" % score) ``` + ## (五)填充missing values,估計填充後的得分 每一筆樣本資料都在13個特徵中隨機遺失一個特徵資料,
使用`sklearn.preprocessing.Imputer`進行missing values的填充。
@@ -75,8 +77,6 @@ class sklearn.preprocessing.Imputer(missing_values='NaN', strategy='mean', axis= 填充後進行隨機森林回歸函數進行交叉驗證,獲得填充後分數。 -Score before imputation of the missing values = 0.52
-Score after imputation of the missing values = 0.57 ```python X_missing = X_full.copy() @@ -91,6 +91,10 @@ score = cross_val_score(estimator, X_missing, y_missing).mean() print("Score after imputation of the missing values = %.2f" % score) ``` +利用數據填充後的迴歸函數,去測試填充前的資料,預測的準確率獲得提升。
+ +Score after imputation of the missing values = 0.57 + ## (六)完整程式碼 Python source code: missing_values.py
http://scikit-learn.org/stable/auto_examples/missing_values.html#example-missing-values-py diff --git a/googleanalysis.js b/googleanalysis.js new file mode 100644 index 0000000..466ba20 --- /dev/null +++ b/googleanalysis.js @@ -0,0 +1,9 @@ + + + diff --git a/header.html b/header.html new file mode 100644 index 0000000..466ba20 --- /dev/null +++ b/header.html @@ -0,0 +1,9 @@ + + + diff --git a/images/2016year.PNG b/images/2016year.PNG new file mode 100644 index 0000000..c800d11 Binary files /dev/null and b/images/2016year.PNG differ diff --git a/images/pg10000.PNG b/images/pg10000.PNG new file mode 100644 index 0000000..bc75277 Binary files /dev/null and b/images/pg10000.PNG differ diff --git a/sklearn_intro.PNG b/images/sklearn_intro.PNG similarity index 100% rename from sklearn_intro.PNG rename to images/sklearn_intro.PNG diff --git a/nvidia_jetson_tx2/1_host.md b/nvidia_jetson_tx2/1_host.md new file mode 100644 index 0000000..08c9c55 --- /dev/null +++ b/nvidia_jetson_tx2/1_host.md @@ -0,0 +1,25 @@ +## 從零開始 + +灌作業系統一定是我們的首要目標,但在這之前,我們要先有一台運行 Ubuntu x64 (14.04或更新) 的電腦,可以用虛擬機來代替。 + +沒有虛擬機的朋友可以用[VirtualBox](https://www.virtualbox.org/wiki/Downloads)。 + +Ubuntu x64 的映像檔可以在[這邊](https://www.ubuntu.com/download/desktop)下載。 + +### 1. 安裝 VirtualBox + +流程就不在這邊贅述,簡單來說,就是狂按下一步。 + +### 2. 安裝 Ubuntu x64 + +有兩點要注意: + +1. 因為稍後下載回來的安裝包還會有額外的套件需要下載與編譯,所以硬碟空間要大一些,建議設定在 **50G** 以上。 + ![VirtualBox Disk Setting](img/vb_disk.png) + +2. 在設定 TX2 的時候,需要將 TX2 連上與 Ubuntu x64 **相同** 的區網,進行這項設定,請: + + 1. 開啟 Ubuntu x64 的虛擬機設定 + 2. 進入網路設定 + 3. 將網路連線方式選擇**橋接**,並指定主機用來上網的網路介面 + ![VirtualBox Network Setting](img/vb_network.png) diff --git a/nvidia_jetson_tx2/2_init.md b/nvidia_jetson_tx2/2_init.md new file mode 100644 index 0000000..fb5cd4e --- /dev/null +++ b/nvidia_jetson_tx2/2_init.md @@ -0,0 +1,70 @@ +## 讓 TX2 動起來 + +基本上外部的設置已經完成了,接下來就要把目光轉移到 TX2 上面。 + +這邊我們會用到名為 Jet Pack 的官方套件,可以在[這邊](https://developer.nvidia.com/jetson-development-pack)下載他。 + +### 1. 執行 JetPack + +注意:**這個套件要在 Ubuntu x64 上才能執行** + +首先,我們需要更改 JetPack 的權限,讓他可以執行: + +1. 開啟 JetPack 所在的資料夾。 +2. 點右鍵,選`Open in Terminal`。 +3. 執行`chmod +x JetPack-.run`,其中的``請替換成你所下載的版本號。(可以按`tab`讓系統自動補齊檔案名稱) + +基本上接下來按照指示操作即可,當出現 Terminal 視窗時: + +1. 除了要將 TX2 準備在旁邊之外,你還會需要:可以和隨附的變壓器搭配的**電源線**、隨附的**micro-USB線**、夠長且良好的**網路線**、可以用**HDMI**或有HDMI轉接線可以搭配的**螢幕**、**鍵盤**、**滑鼠**。 +2. 將 TX2 接上**電源**、用**micro-USB線**把 TX2 和 Ubuntu x64 連在一起、**網路線**接到和 Ubuntu x64 相同的區域網路下。 +3. 在按按鈕之前,先來介紹按鈕的作用 + + ![Buttons on NVIDIA Jetson TX2](img/btn.jpg) + + 在**電源**接頭**對角**處有**1個_螺絲_**和**4顆_按鈕_**,他們分別是 + + |螺絲|重設|自訂|復原|電源| + |---|---|---|---|---| + | | | | | | + +4. 按下**電源**開機 +5. 按住**復原**別放開 +6. 按下**重設**進入復原模式 +7. 可以放開**復原**鍵 +8. 確認 Ubuntu x64 有成功辨識 TX2,名稱會有 **NVIDIA** 或 **Jetson** 或 **TX2** 字樣 +9. 在 Terminal 內按下`enter`鍵,繼續程序 +10. 等待完成的訊息出現 + +### 2. 安裝環境 + +先來列出預設的帳號與密碼: + +|帳號|密碼| +|---|---| +|nvidia|nvidia| +|ubuntu|ubuntu| + +接下來的事情,我們都會在 Terminal 裡面完成: + +1. 先更新系統 + + ```sh + $ sudo apt-get update + $ sudo apt-get upgrade -y + ``` + +2. 接著安裝常用的套件 + + ```sh + $ sudo apt-get install curl vim git mercurial silversearcher-ag htop python3-pip + $ pip3 install --upgrade pip + $ pip3 install virtualenv numpy + ``` + +3. (Optional)安裝更方便的 zsh + + ```sh + $ sudo apt-get install zsh + $ sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)" + ``` diff --git a/nvidia_jetson_tx2/3_opencv.md b/nvidia_jetson_tx2/3_opencv.md new file mode 100644 index 0000000..74b8e05 --- /dev/null +++ b/nvidia_jetson_tx2/3_opencv.md @@ -0,0 +1,78 @@ +## 安裝 OpenCV + +既然 TX2 上面有相機模組,那我們就來裝個 OpenCV 來做相機的影像處理吧! + +Python3 會是我們的主要語言。 + +1. 安裝依賴套件 + + ```sh + $ sudo apt-get install build-essential cmake git pkg-config libjpeg8-dev libtiff5-dev libjasper-dev libpng12-dev libavcodec-dev libavformat-dev libswscale-dev libv4l-dev libgtk2.0-dev libatlas-base-dev gfortran + ``` + +2. 取得 OpenCV 原始碼 + + ```sh + $ git clone git://github.com/Itseez/opencv + $ cd opencv + $ git checkout <你所要用的 OpenCV 版本,建議是用最新版> + $ git clone git://github.com/Itseez/opencv_contrib + $ cd opencv_contrib + $ git checkout <你所要用的 OpenCV 版本,建議是用最新版> + ``` + +3. 編譯 OpenCV + + ```sh + $ mkdir opencv/build + $ cd opencv/build + $ cmake \ + -D CMAKE_BUILD_TYPE=RELEASE \ + -D CMAKE_INSTALL_PREFIX=/usr/local \ + -D INSTALL_PYTHON_EXAMPLES=ON \ + -D OPENCV_EXTRA_MODULES_PATH= \ + -D BUILD_EXAMPLES=ON .. + $ make -j4 + $ sudo make install + $ sudo ldconfig + ``` + +4. 安裝 OpenCV + + 1. 建立虛擬開發環境 + + ```sh + $ virtualenv OpenCV + ``` + + 2. 進入虛擬開發環境 + + ```sh + $ cd OpenCV + $ source bin/active + ``` + + 3. 找到 OpenCV + + ```sh + $ ls -al /usr/local/lib/python/dist-packages/cv2* + ``` + + 4. 連接 OpenCV 到虛擬環境 + + ```sh + $ ln -s <上一步驟印出的完整路徑> lib/python/site-packages/cv2.so + ``` + + 5. 測試 OpenCV + + ```py + import cv2 + cv2.__version__ + ``` + + 輸出 + + ``` + '' + ``` diff --git a/nvidia_jetson_tx2/4_tensorflow.md b/nvidia_jetson_tx2/4_tensorflow.md new file mode 100644 index 0000000..e599b25 --- /dev/null +++ b/nvidia_jetson_tx2/4_tensorflow.md @@ -0,0 +1,89 @@ +## 安裝 TensorFlow + +1. 安裝依賴套件 + + ```sh + $ sudo apt-get install default-jdk libcupti-dev + $ export JAVA_HOME='/usr/lib/jvm/java-8-openjdk-arm64/' + ``` + +2. 取得 TensorFlow 編譯腳本 + + ```sh + $ git clone git://github.com/jetsonhacks/installTensorFlowTX2 + $ cd installTensorFlowTX2 + ``` + +3. 執行編譯腳本 + + ```sh + $ ./installPrerequisitesPy3.sh + $ ./cloneTensorFlow.sh + $ ./setTensorFlowEVPy3.sh + $ ./buildTensorFlow.sh + $ ./packageTensorFlow.sh + ``` + +4. 安裝 TensorFlow + + 1. 建立虛擬開發環境 + + ```sh + $ virtualenv TensorFlow + ``` + + 2. 進入虛擬開發環境 + + ```sh + $ cd TensorFlow + $ source bin/active + ``` + + 3. 安裝 TensorFlow 到虛擬環境 + + ```sh + pip3 install $HOME/ + ``` + + 4. 測試 TensorFlow + + 1. Hello World + + ```py + import tensorflow as tf + hello = tf.constant('Hello, TensorFlow on NVIDIA Jetson TX2!') + sess = tf.Session() + print(sess.run(hello)) + ``` + + 輸出 + + ``` + Hello, TensorFlow on NVIDIA Jetson TX2! + ``` + + 2. 運算單元 + + ```py + import tensorflow as tf + # Creates a graph. + a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a') + b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b') + c = tf.matmul(a, b) + # Creates a session with log_device_placement set to True. + sess = tf.Session(config=tf.ConfigProto(log_device_placement=True)) + # Runs the op. + print(sess.run(c)) + ``` + + 輸出 + + ``` + name: NVIDIA Tegra X2 + major: 6 minor: 2 memoryClockRate (GHz) 1.3005 + MatMul: (MatMul): /job:localhost/replica:0/task:0/gpu:0 + b: (Const): /job:localhost/replica:0/task:0/gpu:0 + a: (Const): /job:localhost/replica:0/task:0/gpu:0 + [[ 22. 28.] + [ 49. 64.]] + ``` diff --git a/nvidia_jetson_tx2/img/btn.jpg b/nvidia_jetson_tx2/img/btn.jpg new file mode 100644 index 0000000..90faa57 Binary files /dev/null and b/nvidia_jetson_tx2/img/btn.jpg differ diff --git a/nvidia_jetson_tx2/img/vb_disk.png b/nvidia_jetson_tx2/img/vb_disk.png new file mode 100644 index 0000000..3000c00 Binary files /dev/null and b/nvidia_jetson_tx2/img/vb_disk.png differ diff --git a/nvidia_jetson_tx2/img/vb_network.png b/nvidia_jetson_tx2/img/vb_network.png new file mode 100644 index 0000000..6ee83bf Binary files /dev/null and b/nvidia_jetson_tx2/img/vb_network.png differ diff --git a/nvidia_jetson_tx2/nvidia_jetson_tx2.md b/nvidia_jetson_tx2/nvidia_jetson_tx2.md new file mode 100644 index 0000000..36bc3b5 --- /dev/null +++ b/nvidia_jetson_tx2/nvidia_jetson_tx2.md @@ -0,0 +1 @@ +# 機器學習:使用 NVIDIA Jetson TX2

AltStyle によって変換されたページ (->オリジナル) /