{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Supervised Learning with scikit-learn" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "plt.style.use('ggplot')\n", "\n", "import sklearn\n", "from sklearn import datasets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Classification" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### KNN (binary)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 讀資料集" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
partyinfantswaterbudgetphysiciansalvadorreligioussatelliteaidmissileimmigrationsynfuelseducationsuperfundcrimeduty_free_exportseaa_rsa
4democrat0110110000001111
7republican0101110000011101
18democrat1110001110100011
22democrat1110001110000011
24democrat1010001111000011
......................................................
422democrat0110011110100111
425democrat1010001111000011
426republican0001111101011101
429republican0011110011011101
430democrat0010001111000001
\n", "

232 rows × 17 columns

\n", "
" ], "text/plain": [ " party infants water budget physician salvador religious \\\n", "4 democrat 0 1 1 0 1 1 \n", "7 republican 0 1 0 1 1 1 \n", "18 democrat 1 1 1 0 0 0 \n", "22 democrat 1 1 1 0 0 0 \n", "24 democrat 1 0 1 0 0 0 \n", ".. ... ... ... ... ... ... ... \n", "422 democrat 0 1 1 0 0 1 \n", "425 democrat 1 0 1 0 0 0 \n", "426 republican 0 0 0 1 1 1 \n", "429 republican 0 0 1 1 1 1 \n", "430 democrat 0 0 1 0 0 0 \n", "\n", " satellite aid missile immigration synfuels education superfund \\\n", "4 0 0 0 0 0 0 1 \n", "7 0 0 0 0 0 1 1 \n", "18 1 1 1 0 1 0 0 \n", "22 1 1 1 0 0 0 0 \n", "24 1 1 1 1 0 0 0 \n", ".. ... ... ... ... ... ... ... \n", "422 1 1 1 0 1 0 0 \n", "425 1 1 1 1 0 0 0 \n", "426 1 1 0 1 0 1 1 \n", "429 0 0 1 1 0 1 1 \n", "430 1 1 1 1 0 0 0 \n", "\n", " crime duty_free_exports eaa_rsa \n", "4 1 1 1 \n", "7 1 0 1 \n", "18 0 1 1 \n", "22 0 1 1 \n", "24 0 1 1 \n", ".. ... ... ... \n", "422 1 1 1 \n", "425 0 1 1 \n", "426 1 0 1 \n", "429 1 0 1 \n", "430 0 0 1 \n", "\n", "[232 rows x 17 columns]" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vote_raw = pd.read_csv(\"data/house-votes-84.csv\")\n", "\n", "vote = vote_raw.copy()\n", "col_names = ['party', 'infants', 'water', 'budget', 'physician', 'salvador',\n", " 'religious', 'satellite', 'aid', 'missile', 'immigration', 'synfuels',\n", " 'education', 'superfund', 'crime', 'duty_free_exports', 'eaa_rsa']\n", "vote.columns = col_names\n", "vote[vote == \"?\"] = np.nan # 把 ? 改成 na\n", "vote = vote.dropna()\n", "for i in col_names[1:]:\n", " vote[i] = vote[i].replace({\"y\": 1, \"n\": 0})\n", "vote" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Int64Index: 232 entries, 4 to 430\n", "Data columns (total 17 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 party 232 non-null object\n", " 1 infants 232 non-null int64 \n", " 2 water 232 non-null int64 \n", " 3 budget 232 non-null int64 \n", " 4 physician 232 non-null int64 \n", " 5 salvador 232 non-null int64 \n", " 6 religious 232 non-null int64 \n", " 7 satellite 232 non-null int64 \n", " 8 aid 232 non-null int64 \n", " 9 missile 232 non-null int64 \n", " 10 immigration 232 non-null int64 \n", " 11 synfuels 232 non-null int64 \n", " 12 education 232 non-null int64 \n", " 13 superfund 232 non-null int64 \n", " 14 crime 232 non-null int64 \n", " 15 duty_free_exports 232 non-null int64 \n", " 16 eaa_rsa 232 non-null int64 \n", "dtypes: int64(16), object(1)\n", "memory usage: 32.6+ KB\n" ] } ], "source": [ "vote.info()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 這筆資料共 232 個列,每一列是一個立委 \n", "* y 是 party(該立委所屬的政黨,民主黨或共和黨) \n", "* 剩下的全都是x,這些x都是各大議題的投票結果。以 `infants` 這個變數來說,就是在嬰兒這個議題上,此立委是投贊成票(1)還是反對票(0). \n", "* 那這筆資料的任務,就是根據這些議題的投票結果,來猜這個立委屬於哪個政黨" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 最簡單流程" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 先來講最簡單的流程 \n", " * 分 train/test \n", " * ~~定 pipeline.~~ \n", " * ~~定義 preprocessing steps.~~ \n", " * 定義 classifier. \n", " * ~~hyper-parameter tunning~~ \n", " * ~~grid search~~\n", " * ~~random search~~\n", " * 用整個 training set 做 fitting. \n", " * 對 testing set 做 predict. \n", " * 評估模型表現 \n", " * threshold. \n", " * non-trheshold\n", " * 細節資訊探索(e.g. fitting後的參數,...)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 分 train/test" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# 分 train/test\n", "X = vote.drop(\"party\", axis = 1)\n", "y = vote[\"party\"]\n", "\n", "from sklearn.model_selection import train_test_split\n", "X_train, X_test, y_train, y_test = train_test_split(\n", " X, \n", " y, \n", " test_size = 0.3, \n", " random_state = 21, \n", " stratify = y\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 可以看看,X_train 和 X_test 的資料筆數分配" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The shape of X_train is: (162, 16)\n", "The shape of X_test is: (70, 16)\n" ] } ], "source": [ "print(f\"The shape of X_train is: {X_train.shape}\")\n", "print(f\"The shape of X_test is: {X_test.shape}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 可以看, y_train 和 y_test 的分佈是不是一樣(因為我有做 stratify)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "republican% in whole data set is: 0.46551724137931033\n", "republican% in training set is: 0.46296296296296297\n", "republican% in testing set is: 0.4714285714285714\n" ] } ], "source": [ "print(f\"republican% in whole data set is: {(y == 'republican').sum()/y.size}\")\n", "print(f\"republican% in training set is: {(y_train == 'republican').sum()/y_train.size}\")\n", "print(f\"republican% in testing set is: {(y_test == 'republican').sum()/y_test.size}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 做 pipeline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* pipeline 包括 preprocessing + model,那這邊只做 model" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "# 定 pipeline\n", "## 定 preprocessing steps. (略)\n", "## 定 classifier\n", "from sklearn.neighbors import KNeighborsClassifier\n", "knn = KNeighborsClassifier(n_neighbors = 5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 很簡單的就定義完我要使用的 model (knn,以及 neighbor 數選了 5). \n", "* 我們可以看他的文件,來看這個 classifier 的細節" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\u001b[0;31mInit signature:\u001b[0m\n", "\u001b[0mKNeighborsClassifier\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mn_neighbors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mweights\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'uniform'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0malgorithm\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'auto'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mleaf_size\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m30\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mp\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mmetric\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'minkowski'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mmetric_params\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mn_jobs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mDocstring:\u001b[0m \n", "Classifier implementing the k-nearest neighbors vote.\n", "\n", "Read more in the :ref:`User Guide `.\n", "\n", "Parameters\n", "----------\n", "n_neighbors : int, default=5\n", " Number of neighbors to use by default for :meth:`kneighbors` queries.\n", "\n", "weights : {'uniform', 'distance'} or callable, default='uniform'\n", " Weight function used in prediction. Possible values:\n", "\n", " - 'uniform' : uniform weights. All points in each neighborhood\n", " are weighted equally.\n", " - 'distance' : weight points by the inverse of their distance.\n", " in this case, closer neighbors of a query point will have a\n", " greater influence than neighbors which are further away.\n", " - [callable] : a user-defined function which accepts an\n", " array of distances, and returns an array of the same shape\n", " containing the weights.\n", "\n", "algorithm : {'auto', 'ball_tree', 'kd_tree', 'brute'}, default='auto'\n", " Algorithm used to compute the nearest neighbors:\n", "\n", " - 'ball_tree' will use :class:`BallTree`\n", " - 'kd_tree' will use :class:`KDTree`\n", " - 'brute' will use a brute-force search.\n", " - 'auto' will attempt to decide the most appropriate algorithm\n", " based on the values passed to :meth:`fit` method.\n", "\n", " Note: fitting on sparse input will override the setting of\n", " this parameter, using brute force.\n", "\n", "leaf_size : int, default=30\n", " Leaf size passed to BallTree or KDTree. This can affect the\n", " speed of the construction and query, as well as the memory\n", " required to store the tree. The optimal value depends on the\n", " nature of the problem.\n", "\n", "p : int, default=2\n", " Power parameter for the Minkowski metric. When p = 1, this is\n", " equivalent to using manhattan_distance (l1), and euclidean_distance\n", " (l2) for p = 2. For arbitrary p, minkowski_distance (l_p) is used.\n", "\n", "metric : str or callable, default='minkowski'\n", " The distance metric to use for the tree. The default metric is\n", " minkowski, and with p=2 is equivalent to the standard Euclidean\n", " metric. For a list of available metrics, see the documentation of\n", " :class:`~sklearn.metrics.DistanceMetric`.\n", " If metric is \"precomputed\", X is assumed to be a distance matrix and\n", " must be square during fit. X may be a :term:`sparse graph`,\n", " in which case only \"nonzero\" elements may be considered neighbors.\n", "\n", "metric_params : dict, default=None\n", " Additional keyword arguments for the metric function.\n", "\n", "n_jobs : int, default=None\n", " The number of parallel jobs to run for neighbors search.\n", " ``None`` means 1 unless in a :obj:`joblib.parallel_backend` context.\n", " ``-1`` means using all processors. See :term:`Glossary `\n", " for more details.\n", " Doesn't affect :meth:`fit` method.\n", "\n", "Attributes\n", "----------\n", "classes_ : array of shape (n_classes,)\n", " Class labels known to the classifier\n", "\n", "effective_metric_ : str or callble\n", " The distance metric used. It will be same as the `metric` parameter\n", " or a synonym of it, e.g. 'euclidean' if the `metric` parameter set to\n", " 'minkowski' and `p` parameter set to 2.\n", "\n", "effective_metric_params_ : dict\n", " Additional keyword arguments for the metric function. For most metrics\n", " will be same with `metric_params` parameter, but may also contain the\n", " `p` parameter value if the `effective_metric_` attribute is set to\n", " 'minkowski'.\n", "\n", "n_features_in_ : int\n", " Number of features seen during :term:`fit`.\n", "\n", " .. versionadded:: 0.24\n", "\n", "feature_names_in_ : ndarray of shape (`n_features_in_`,)\n", " Names of features seen during :term:`fit`. Defined only when `X`\n", " has feature names that are all strings.\n", "\n", " .. versionadded:: 1.0\n", "\n", "n_samples_fit_ : int\n", " Number of samples in the fitted data.\n", "\n", "outputs_2d_ : bool\n", " False when `y`'s shape is (n_samples, ) or (n_samples, 1) during fit\n", " otherwise True.\n", "\n", "See Also\n", "--------\n", "RadiusNeighborsClassifier: Classifier based on neighbors within a fixed radius.\n", "KNeighborsRegressor: Regression based on k-nearest neighbors.\n", "RadiusNeighborsRegressor: Regression based on neighbors within a fixed radius.\n", "NearestNeighbors: Unsupervised learner for implementing neighbor searches.\n", "\n", "Notes\n", "-----\n", "See :ref:`Nearest Neighbors ` in the online documentation\n", "for a discussion of the choice of ``algorithm`` and ``leaf_size``.\n", "\n", ".. warning::\n", "\n", " Regarding the Nearest Neighbors algorithms, if it is found that two\n", " neighbors, neighbor `k+1` and `k`, have identical distances\n", " but different labels, the results will depend on the ordering of the\n", " training data.\n", "\n", "https://en.wikipedia.org/wiki/K-nearest_neighbor_algorithm\n", "\n", "Examples\n", "--------\n", ">>> X = [[0], [1], [2], [3]]\n", ">>> y = [0, 0, 1, 1]\n", ">>> from sklearn.neighbors import KNeighborsClassifier\n", ">>> neigh = KNeighborsClassifier(n_neighbors=3)\n", ">>> neigh.fit(X, y)\n", "KNeighborsClassifier(...)\n", ">>> print(neigh.predict([[1.1]]))\n", "[0]\n", ">>> print(neigh.predict_proba([[0.9]]))\n", "[[0.666... 0.333...]]\n", "\u001b[0;31mFile:\u001b[0m /Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/neighbors/_classification.py\n", "\u001b[0;31mType:\u001b[0m ABCMeta\n", "\u001b[0;31mSubclasses:\u001b[0m \n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "KNeighborsClassifier?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 用整個 training set 做 fitting." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "KNeighborsClassifier()" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "knn.fit(X_train, y_train)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* fitting 完後,可以簡要看一下他學到了啥" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'euclidean'" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "knn.effective_metric_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 對 testing set 做 predict" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "y_pred = knn.predict(X_test)\n", "y_pred_prob = knn.predict_proba(X_test)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 我們看看預測結果(label)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
pred_label
0democrat
1democrat
2republican
3democrat
4republican
\n", "
" ], "text/plain": [ " pred_label\n", "0 democrat\n", "1 democrat\n", "2 republican\n", "3 democrat\n", "4 republican" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.DataFrame(y_pred, columns= [\"pred_label\"]).head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 這個預測值,就是去比預測此委員為 democrat 的機率,和 republican 的機率,哪個大,而做出的判斷. (因為只有兩類,所以其實就是 threshold = 0.5 -> 如果 republican 的機率值 > 0.5,就判定為 republican (y的positive是republican)\n", "* 所以我們來看一下預測機率值" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
democratrepublican
01.00.0
11.00.0
20.01.0
31.00.0
40.01.0
\n", "
" ], "text/plain": [ " democrat republican\n", "0 1.0 0.0\n", "1 1.0 0.0\n", "2 0.0 1.0\n", "3 1.0 0.0\n", "4 0.0 1.0" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.DataFrame(y_pred_prob, columns= y_test.unique()).head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 這個機率的算法,就是找最近的 k 個 neighbor後,去統計 democrat 的比例,和 republican 的比例. \n", "* 所以以 index = 0 這一列來說,就是離此委員最近的 k 個 neighbor,全都是 democrat。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 效果評估" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[32 5]\n", " [ 2 31]]\n", " precision recall f1-score support\n", "\n", " democrat 0.94 0.86 0.90 37\n", " republican 0.86 0.94 0.90 33\n", "\n", " accuracy 0.90 70\n", " macro avg 0.90 0.90 0.90 70\n", "weighted avg 0.90 0.90 0.90 70\n", "\n" ] } ], "source": [ "from sklearn.metrics import confusion_matrix, classification_report, roc_curve, roc_auc_score\n", "# 評估結果\n", "print(confusion_matrix(y_test, y_pred))\n", "print(classification_report(y_test, y_pred))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 可以看到,如果你把 `republican` 當 positive 的話,就看第二列 \n", " * precision: 0.86,表示你預測他是republican的人中,有86%真的是republican. \n", " * recall: 0.94,表示實際上是republican的人中,有94%被你抓到. \n", " * f1-score: 是precision和recall的調和平均數. \n", "* 接著看 index = `accuracy` 那一列,可以看到,準確率是 0.90. " ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1. , 0. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [1. , 0. ],\n", " [1. , 0. ],\n", " [0.4, 0.6],\n", " [1. , 0. ],\n", " [1. , 0. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [1. , 0. ],\n", " [0.8, 0.2],\n", " [1. , 0. ],\n", " [0.4, 0.6],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [0.8, 0.2],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [0.2, 0.8],\n", " [0.8, 0.2],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [0.4, 0.6],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [0. , 1. ],\n", " [0. , 1. ],\n", " [1. , 0. ],\n", " [0. , 1. ]])" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y_pred_prob" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "auc: 0.9492219492219492\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "y_test_trans = (y_test==\"republican\") # republican = 1, democrat = 0\n", "y_pred_prob_trans = y_pred_prob[:,1] # 預測是 republican 的 機率\n", "\n", "auc = roc_auc_score(y_test_trans, y_pred_prob_trans)\n", "\n", "print(f\"auc: {auc}\")\n", "\n", "fpr, tpr, thresholds = roc_curve(y_test_trans, y_pred_prob_trans)\n", "plt.plot([0,1],[0, 1], \"k--\")\n", "plt.plot(fpr, tpr, label = \"KNN (K = 5)\")\n", "plt.xlabel(\"False Positive Rate\")\n", "plt.ylabel(\"True Positive Rate\")\n", "plt.title(\"KNN ROC Curve\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 最完整流程整理" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 來講最完整的流程 \n", " * 分 train/test \n", " * 定 pipeline \n", " * 定義 preprocessing steps \n", " * 定義 classifier. \n", " * hyper-parameter tunning \n", " * grid search \n", " * random search \n", " * 用整個 training set 做 fitting. \n", " * 對 testing set 做 predict. \n", " * 評估模型表現 \n", " * threshold. \n", " * non-trheshold\n", " * 細節資訊探索(e.g. fitting後的參數,...)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 分 train/test" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [], "source": [ "# 分 train/test\n", "X = vote.drop(\"party\", axis = 1)\n", "y = vote[\"party\"]\n", "\n", "from sklearn.model_selection import train_test_split\n", "X_train, X_test, y_train, y_test = train_test_split(\n", " X, \n", " y, \n", " test_size = 0.3, \n", " random_state = 21, \n", " stratify = y\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 做 pipeline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 對 knn 這種依賴 euclidean distance 的演算法,必須先做 normalization,再開始算距離,所以 pipeline寫成這樣:" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [], "source": [ "from sklearn.pipeline import Pipeline\n", "from sklearn.preprocessing import StandardScaler\n", "from sklearn.neighbors import KNeighborsClassifier\n", "\n", "# preprocess\n", "scaler = StandardScaler()\n", "\n", "# model\n", "knn = KNeighborsClassifier()\n", "\n", "# pipeline\n", "my_pipe = Pipeline([\n", " (\"scaler\", scaler),\n", " (\"knn\", knn)\n", "])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 做 hyper-parameter tunning" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 先來做 grid_search" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import GridSearchCV\n", "\n", "parameters = {\"knn__n_neighbors\": np.arange(1, 50)}\n", "grid_cv = GridSearchCV(my_pipe, \n", " param_grid = parameters, \n", " cv = 5,\n", " scoring='roc_auc');\n", "grid_cv.fit(X_train, y_train);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 這邊看一下,第二列的 parameters 裡面,\"knn__\"的knn,是用我的 my_pipe 物件裡的名稱 (\"knn\"); \"n_neighbors\" 是超參數的名稱\n", "* 做完 fitting 後的物件就是 grid_cv 了,我們可以看最佳參數是多少:" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'knn__n_neighbors': 17}" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid_cv.best_params_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 可以知道,最佳參數是 17. " ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Object `ref:scoring_parameter` not found.\n" ] } ], "source": [ "?ref:scoring_parameter" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\u001b[0;31mInit signature:\u001b[0m\n", "\u001b[0mGridSearchCV\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mestimator\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mparam_grid\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mscoring\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mn_jobs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mrefit\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mcv\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mverbose\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mpre_dispatch\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'2*n_jobs'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0merror_score\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mnan\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mreturn_train_score\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mDocstring:\u001b[0m \n", "Exhaustive search over specified parameter values for an estimator.\n", "\n", "Important members are fit, predict.\n", "\n", "GridSearchCV implements a \"fit\" and a \"score\" method.\n", "It also implements \"score_samples\", \"predict\", \"predict_proba\",\n", "\"decision_function\", \"transform\" and \"inverse_transform\" if they are\n", "implemented in the estimator used.\n", "\n", "The parameters of the estimator used to apply these methods are optimized\n", "by cross-validated grid-search over a parameter grid.\n", "\n", "Read more in the :ref:`User Guide `.\n", "\n", "Parameters\n", "----------\n", "estimator : estimator object\n", " This is assumed to implement the scikit-learn estimator interface.\n", " Either estimator needs to provide a ``score`` function,\n", " or ``scoring`` must be passed.\n", "\n", "param_grid : dict or list of dictionaries\n", " Dictionary with parameters names (`str`) as keys and lists of\n", " parameter settings to try as values, or a list of such\n", " dictionaries, in which case the grids spanned by each dictionary\n", " in the list are explored. This enables searching over any sequence\n", " of parameter settings.\n", "\n", "scoring : str, callable, list, tuple or dict, default=None\n", " Strategy to evaluate the performance of the cross-validated model on\n", " the test set.\n", "\n", " If `scoring` represents a single score, one can use:\n", "\n", " - a single string (see :ref:`scoring_parameter`);\n", " - a callable (see :ref:`scoring`) that returns a single value.\n", "\n", " If `scoring` represents multiple scores, one can use:\n", "\n", " - a list or tuple of unique strings;\n", " - a callable returning a dictionary where the keys are the metric\n", " names and the values are the metric scores;\n", " - a dictionary with metric names as keys and callables a values.\n", "\n", " See :ref:`multimetric_grid_search` for an example.\n", "\n", "n_jobs : int, default=None\n", " Number of jobs to run in parallel.\n", " ``None`` means 1 unless in a :obj:`joblib.parallel_backend` context.\n", " ``-1`` means using all processors. See :term:`Glossary `\n", " for more details.\n", "\n", " .. versionchanged:: v0.20\n", " `n_jobs` default changed from 1 to None\n", "\n", "refit : bool, str, or callable, default=True\n", " Refit an estimator using the best found parameters on the whole\n", " dataset.\n", "\n", " For multiple metric evaluation, this needs to be a `str` denoting the\n", " scorer that would be used to find the best parameters for refitting\n", " the estimator at the end.\n", "\n", " Where there are considerations other than maximum score in\n", " choosing a best estimator, ``refit`` can be set to a function which\n", " returns the selected ``best_index_`` given ``cv_results_``. In that\n", " case, the ``best_estimator_`` and ``best_params_`` will be set\n", " according to the returned ``best_index_`` while the ``best_score_``\n", " attribute will not be available.\n", "\n", " The refitted estimator is made available at the ``best_estimator_``\n", " attribute and permits using ``predict`` directly on this\n", " ``GridSearchCV`` instance.\n", "\n", " Also for multiple metric evaluation, the attributes ``best_index_``,\n", " ``best_score_`` and ``best_params_`` will only be available if\n", " ``refit`` is set and all of them will be determined w.r.t this specific\n", " scorer.\n", "\n", " See ``scoring`` parameter to know more about multiple metric\n", " evaluation.\n", "\n", " .. versionchanged:: 0.20\n", " Support for callable added.\n", "\n", "cv : int, cross-validation generator or an iterable, default=None\n", " Determines the cross-validation splitting strategy.\n", " Possible inputs for cv are:\n", "\n", " - None, to use the default 5-fold cross validation,\n", " - integer, to specify the number of folds in a `(Stratified)KFold`,\n", " - :term:`CV splitter`,\n", " - An iterable yielding (train, test) splits as arrays of indices.\n", "\n", " For integer/None inputs, if the estimator is a classifier and ``y`` is\n", " either binary or multiclass, :class:`StratifiedKFold` is used. In all\n", " other cases, :class:`KFold` is used. These splitters are instantiated\n", " with `shuffle=False` so the splits will be the same across calls.\n", "\n", " Refer :ref:`User Guide ` for the various\n", " cross-validation strategies that can be used here.\n", "\n", " .. versionchanged:: 0.22\n", " ``cv`` default value if None changed from 3-fold to 5-fold.\n", "\n", "verbose : int\n", " Controls the verbosity: the higher, the more messages.\n", "\n", " - >1 : the computation time for each fold and parameter candidate is\n", " displayed;\n", " - >2 : the score is also displayed;\n", " - >3 : the fold and candidate parameter indexes are also displayed\n", " together with the starting time of the computation.\n", "\n", "pre_dispatch : int, or str, default='2*n_jobs'\n", " Controls the number of jobs that get dispatched during parallel\n", " execution. Reducing this number can be useful to avoid an\n", " explosion of memory consumption when more jobs get dispatched\n", " than CPUs can process. This parameter can be:\n", "\n", " - None, in which case all the jobs are immediately\n", " created and spawned. Use this for lightweight and\n", " fast-running jobs, to avoid delays due to on-demand\n", " spawning of the jobs\n", "\n", " - An int, giving the exact number of total jobs that are\n", " spawned\n", "\n", " - A str, giving an expression as a function of n_jobs,\n", " as in '2*n_jobs'\n", "\n", "error_score : 'raise' or numeric, default=np.nan\n", " Value to assign to the score if an error occurs in estimator fitting.\n", " If set to 'raise', the error is raised. If a numeric value is given,\n", " FitFailedWarning is raised. This parameter does not affect the refit\n", " step, which will always raise the error.\n", "\n", "return_train_score : bool, default=False\n", " If ``False``, the ``cv_results_`` attribute will not include training\n", " scores.\n", " Computing training scores is used to get insights on how different\n", " parameter settings impact the overfitting/underfitting trade-off.\n", " However computing the scores on the training set can be computationally\n", " expensive and is not strictly required to select the parameters that\n", " yield the best generalization performance.\n", "\n", " .. versionadded:: 0.19\n", "\n", " .. versionchanged:: 0.21\n", " Default value was changed from ``True`` to ``False``\n", "\n", "Attributes\n", "----------\n", "cv_results_ : dict of numpy (masked) ndarrays\n", " A dict with keys as column headers and values as columns, that can be\n", " imported into a pandas ``DataFrame``.\n", "\n", " For instance the below given table\n", "\n", " +------------+-----------+------------+-----------------+---+---------+\n", " |param_kernel|param_gamma|param_degree|split0_test_score|...|rank_t...|\n", " +============+===========+============+=================+===+=========+\n", " | 'poly' | -- | 2 | 0.80 |...| 2 |\n", " +------------+-----------+------------+-----------------+---+---------+\n", " | 'poly' | -- | 3 | 0.70 |...| 4 |\n", " +------------+-----------+------------+-----------------+---+---------+\n", " | 'rbf' | 0.1 | -- | 0.80 |...| 3 |\n", " +------------+-----------+------------+-----------------+---+---------+\n", " | 'rbf' | 0.2 | -- | 0.93 |...| 1 |\n", " +------------+-----------+------------+-----------------+---+---------+\n", "\n", " will be represented by a ``cv_results_`` dict of::\n", "\n", " {\n", " 'param_kernel': masked_array(data = ['poly', 'poly', 'rbf', 'rbf'],\n", " mask = [False False False False]...)\n", " 'param_gamma': masked_array(data = [-- -- 0.1 0.2],\n", " mask = [ True True False False]...),\n", " 'param_degree': masked_array(data = [2.0 3.0 -- --],\n", " mask = [False False True True]...),\n", " 'split0_test_score' : [0.80, 0.70, 0.80, 0.93],\n", " 'split1_test_score' : [0.82, 0.50, 0.70, 0.78],\n", " 'mean_test_score' : [0.81, 0.60, 0.75, 0.85],\n", " 'std_test_score' : [0.01, 0.10, 0.05, 0.08],\n", " 'rank_test_score' : [2, 4, 3, 1],\n", " 'split0_train_score' : [0.80, 0.92, 0.70, 0.93],\n", " 'split1_train_score' : [0.82, 0.55, 0.70, 0.87],\n", " 'mean_train_score' : [0.81, 0.74, 0.70, 0.90],\n", " 'std_train_score' : [0.01, 0.19, 0.00, 0.03],\n", " 'mean_fit_time' : [0.73, 0.63, 0.43, 0.49],\n", " 'std_fit_time' : [0.01, 0.02, 0.01, 0.01],\n", " 'mean_score_time' : [0.01, 0.06, 0.04, 0.04],\n", " 'std_score_time' : [0.00, 0.00, 0.00, 0.01],\n", " 'params' : [{'kernel': 'poly', 'degree': 2}, ...],\n", " }\n", "\n", " NOTE\n", "\n", " The key ``'params'`` is used to store a list of parameter\n", " settings dicts for all the parameter candidates.\n", "\n", " The ``mean_fit_time``, ``std_fit_time``, ``mean_score_time`` and\n", " ``std_score_time`` are all in seconds.\n", "\n", " For multi-metric evaluation, the scores for all the scorers are\n", " available in the ``cv_results_`` dict at the keys ending with that\n", " scorer's name (``'_'``) instead of ``'_score'`` shown\n", " above. ('split0_test_precision', 'mean_train_precision' etc.)\n", "\n", "best_estimator_ : estimator\n", " Estimator that was chosen by the search, i.e. estimator\n", " which gave highest score (or smallest loss if specified)\n", " on the left out data. Not available if ``refit=False``.\n", "\n", " See ``refit`` parameter for more information on allowed values.\n", "\n", "best_score_ : float\n", " Mean cross-validated score of the best_estimator\n", "\n", " For multi-metric evaluation, this is present only if ``refit`` is\n", " specified.\n", "\n", " This attribute is not available if ``refit`` is a function.\n", "\n", "best_params_ : dict\n", " Parameter setting that gave the best results on the hold out data.\n", "\n", " For multi-metric evaluation, this is present only if ``refit`` is\n", " specified.\n", "\n", "best_index_ : int\n", " The index (of the ``cv_results_`` arrays) which corresponds to the best\n", " candidate parameter setting.\n", "\n", " The dict at ``search.cv_results_['params'][search.best_index_]`` gives\n", " the parameter setting for the best model, that gives the highest\n", " mean score (``search.best_score_``).\n", "\n", " For multi-metric evaluation, this is present only if ``refit`` is\n", " specified.\n", "\n", "scorer_ : function or a dict\n", " Scorer function used on the held out data to choose the best\n", " parameters for the model.\n", "\n", " For multi-metric evaluation, this attribute holds the validated\n", " ``scoring`` dict which maps the scorer key to the scorer callable.\n", "\n", "n_splits_ : int\n", " The number of cross-validation splits (folds/iterations).\n", "\n", "refit_time_ : float\n", " Seconds used for refitting the best model on the whole dataset.\n", "\n", " This is present only if ``refit`` is not False.\n", "\n", " .. versionadded:: 0.20\n", "\n", "multimetric_ : bool\n", " Whether or not the scorers compute several metrics.\n", "\n", "classes_ : ndarray of shape (n_classes,)\n", " The classes labels. This is present only if ``refit`` is specified and\n", " the underlying estimator is a classifier.\n", "\n", "n_features_in_ : int\n", " Number of features seen during :term:`fit`. Only defined if\n", " `best_estimator_` is defined (see the documentation for the `refit`\n", " parameter for more details) and that `best_estimator_` exposes\n", " `n_features_in_` when fit.\n", "\n", " .. versionadded:: 0.24\n", "\n", "feature_names_in_ : ndarray of shape (`n_features_in_`,)\n", " Names of features seen during :term:`fit`. Only defined if\n", " `best_estimator_` is defined (see the documentation for the `refit`\n", " parameter for more details) and that `best_estimator_` exposes\n", " `feature_names_in_` when fit.\n", "\n", " .. versionadded:: 1.0\n", "\n", "Notes\n", "-----\n", "The parameters selected are those that maximize the score of the left out\n", "data, unless an explicit score is passed in which case it is used instead.\n", "\n", "If `n_jobs` was set to a value higher than one, the data is copied for each\n", "point in the grid (and not `n_jobs` times). This is done for efficiency\n", "reasons if individual jobs take very little time, but may raise errors if\n", "the dataset is large and not enough memory is available. A workaround in\n", "this case is to set `pre_dispatch`. Then, the memory is copied only\n", "`pre_dispatch` many times. A reasonable value for `pre_dispatch` is `2 *\n", "n_jobs`.\n", "\n", "See Also\n", "---------\n", "ParameterGrid : Generates all the combinations of a hyperparameter grid.\n", "train_test_split : Utility function to split the data into a development\n", " set usable for fitting a GridSearchCV instance and an evaluation set\n", " for its final evaluation.\n", "sklearn.metrics.make_scorer : Make a scorer from a performance metric or\n", " loss function.\n", "\n", "Examples\n", "--------\n", ">>> from sklearn import svm, datasets\n", ">>> from sklearn.model_selection import GridSearchCV\n", ">>> iris = datasets.load_iris()\n", ">>> parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]}\n", ">>> svc = svm.SVC()\n", ">>> clf = GridSearchCV(svc, parameters)\n", ">>> clf.fit(iris.data, iris.target)\n", "GridSearchCV(estimator=SVC(),\n", " param_grid={'C': [1, 10], 'kernel': ('linear', 'rbf')})\n", ">>> sorted(clf.cv_results_.keys())\n", "['mean_fit_time', 'mean_score_time', 'mean_test_score',...\n", " 'param_C', 'param_kernel', 'params',...\n", " 'rank_test_score', 'split0_test_score',...\n", " 'split2_test_score', ...\n", " 'std_fit_time', 'std_score_time', 'std_test_score']\n", "\u001b[0;31mFile:\u001b[0m /Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/model_selection/_search.py\n", "\u001b[0;31mType:\u001b[0m ABCMeta\n", "\u001b[0;31mSubclasses:\u001b[0m \n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "?GridSearchCV" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'mean_fit_time': array([0.00410557, 0.00349936, 0.00289578, 0.00251188, 0.00247269,\n", " 0.00252709, 0.00272069, 0.00246129, 0.00306287, 0.00371184,\n", " 0.00294638, 0.00308042, 0.00299649, 0.00300522, 0.00273948,\n", " 0.00361261, 0.00310259, 0.00313864, 0.00295277, 0.00384784,\n", " 0.00304828, 0.00281844, 0.00319686, 0.00302219, 0.00305853,\n", " 0.00290966, 0.00289521, 0.00281544, 0.00308471, 0.00267277,\n", " 0.00285001, 0.0030632 , 0.00333405, 0.00302234, 0.00311818,\n", " 0.00305524, 0.00284081, 0.00307274, 0.00295916, 0.00310979,\n", " 0.00310645, 0.00305629, 0.00277839, 0.00244412, 0.00253983,\n", " 0.00268669, 0.00238819, 0.00241308, 0.00232444]),\n", " 'std_fit_time': array([7.88619106e-04, 9.42372814e-04, 5.09592826e-04, 2.05940145e-04,\n", " 1.30329147e-04, 1.39555875e-04, 4.71658495e-04, 9.38250994e-05,\n", " 7.01362537e-04, 9.40648512e-04, 5.46725004e-04, 6.70972481e-04,\n", " 6.49284812e-04, 6.08038812e-04, 4.14937119e-04, 5.44774122e-04,\n", " 4.02125639e-04, 7.85894654e-04, 4.22827063e-04, 3.05221040e-04,\n", " 4.93310674e-04, 4.91984687e-04, 6.07253808e-04, 3.68679192e-04,\n", " 7.83753444e-04, 3.84013546e-04, 5.97170735e-04, 3.48093033e-04,\n", " 5.59792474e-04, 1.83740436e-04, 5.59706703e-04, 6.29626715e-04,\n", " 6.91515668e-04, 5.43012236e-04, 4.23518716e-04, 4.46913336e-04,\n", " 2.66436123e-04, 5.09237350e-04, 2.87175098e-04, 5.41384761e-04,\n", " 3.48689486e-04, 4.61566522e-04, 4.62282743e-05, 1.11534301e-04,\n", " 2.85003914e-04, 3.43765774e-04, 4.60957275e-05, 6.26801311e-05,\n", " 2.83467783e-04]),\n", " 'mean_score_time': array([0.0031558 , 0.00250463, 0.00250649, 0.00215402, 0.00216942,\n", " 0.00229611, 0.00228481, 0.00209074, 0.00282593, 0.00295038,\n", " 0.00259624, 0.00252881, 0.00267229, 0.00262327, 0.00244746,\n", " 0.00306764, 0.00275512, 0.00263891, 0.00269318, 0.00277519,\n", " 0.00260739, 0.00271072, 0.00273805, 0.0025115 , 0.00240846,\n", " 0.00260949, 0.00252876, 0.00271316, 0.00271668, 0.00248637,\n", " 0.00258036, 0.00288286, 0.0027564 , 0.00256944, 0.00278878,\n", " 0.00260425, 0.0026751 , 0.00264025, 0.00280237, 0.0027246 ,\n", " 0.00317144, 0.00274553, 0.00256987, 0.00226922, 0.00251756,\n", " 0.00245085, 0.0023438 , 0.00224037, 0.00238848]),\n", " 'std_score_time': array([1.11923762e-03, 5.02003516e-04, 6.28364240e-04, 2.53515694e-04,\n", " 1.18820261e-04, 2.69056802e-04, 2.76645180e-04, 7.58113199e-05,\n", " 6.51008842e-04, 6.12322828e-04, 5.13428608e-04, 4.03309776e-04,\n", " 4.90662646e-04, 4.82464803e-04, 2.78491622e-04, 2.98720787e-04,\n", " 3.83199448e-04, 4.57812113e-04, 3.96594125e-04, 4.14270047e-04,\n", " 4.59691211e-04, 4.23115014e-04, 3.26109745e-04, 2.89609198e-04,\n", " 2.27550939e-04, 4.39541240e-04, 3.07336423e-04, 6.50968867e-04,\n", " 3.49868736e-04, 1.77414479e-04, 2.67554022e-04, 4.83264888e-04,\n", " 4.17323549e-04, 2.95681527e-04, 2.24535524e-04, 3.38101453e-04,\n", " 2.95083632e-04, 3.19394449e-04, 4.91383988e-04, 3.39971364e-04,\n", " 5.14225423e-04, 4.11409220e-04, 9.38881830e-05, 3.99615144e-05,\n", " 2.96201578e-04, 2.11339188e-04, 8.54063938e-05, 6.91232000e-05,\n", " 3.91190910e-04]),\n", " 'param_knn__n_neighbors': masked_array(data=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,\n", " 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,\n", " 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,\n", " 45, 46, 47, 48, 49],\n", " mask=[False, False, False, False, False, False, False, False,\n", " False, False, False, False, False, False, False, False,\n", " False, False, False, False, False, False, False, False,\n", " False, False, False, False, False, False, False, False,\n", " False, False, False, False, False, False, False, False,\n", " False, False, False, False, False, False, False, False,\n", " False],\n", " fill_value='?',\n", " dtype=object),\n", " 'params': [{'knn__n_neighbors': 1},\n", " {'knn__n_neighbors': 2},\n", " {'knn__n_neighbors': 3},\n", " {'knn__n_neighbors': 4},\n", " {'knn__n_neighbors': 5},\n", " {'knn__n_neighbors': 6},\n", " {'knn__n_neighbors': 7},\n", " {'knn__n_neighbors': 8},\n", " {'knn__n_neighbors': 9},\n", " {'knn__n_neighbors': 10},\n", " {'knn__n_neighbors': 11},\n", " {'knn__n_neighbors': 12},\n", " {'knn__n_neighbors': 13},\n", " {'knn__n_neighbors': 14},\n", " {'knn__n_neighbors': 15},\n", " {'knn__n_neighbors': 16},\n", " {'knn__n_neighbors': 17},\n", " {'knn__n_neighbors': 18},\n", " {'knn__n_neighbors': 19},\n", " {'knn__n_neighbors': 20},\n", " {'knn__n_neighbors': 21},\n", " {'knn__n_neighbors': 22},\n", " {'knn__n_neighbors': 23},\n", " {'knn__n_neighbors': 24},\n", " {'knn__n_neighbors': 25},\n", " {'knn__n_neighbors': 26},\n", " {'knn__n_neighbors': 27},\n", " {'knn__n_neighbors': 28},\n", " {'knn__n_neighbors': 29},\n", " {'knn__n_neighbors': 30},\n", " {'knn__n_neighbors': 31},\n", " {'knn__n_neighbors': 32},\n", " {'knn__n_neighbors': 33},\n", " {'knn__n_neighbors': 34},\n", " {'knn__n_neighbors': 35},\n", " {'knn__n_neighbors': 36},\n", " {'knn__n_neighbors': 37},\n", " {'knn__n_neighbors': 38},\n", " {'knn__n_neighbors': 39},\n", " {'knn__n_neighbors': 40},\n", " {'knn__n_neighbors': 41},\n", " {'knn__n_neighbors': 42},\n", " {'knn__n_neighbors': 43},\n", " {'knn__n_neighbors': 44},\n", " {'knn__n_neighbors': 45},\n", " {'knn__n_neighbors': 46},\n", " {'knn__n_neighbors': 47},\n", " {'knn__n_neighbors': 48},\n", " {'knn__n_neighbors': 49}],\n", " 'split0_test_score': array([0.87222222, 0.91851852, 0.97222222, 0.96666667, 0.97407407,\n", " 0.97037037, 0.96481481, 0.97222222, 0.98148148, 0.98518519,\n", " 0.98148148, 0.97962963, 0.97777778, 0.97592593, 0.97222222,\n", " 0.96851852, 0.97407407, 0.97037037, 0.96666667, 0.97037037,\n", " 0.97777778, 0.97777778, 0.97777778, 0.97777778, 0.97777778,\n", " 0.98148148, 0.97777778, 0.97777778, 0.97777778, 0.97777778,\n", " 0.97777778, 0.97777778, 0.97592593, 0.97037037, 0.96851852,\n", " 0.96851852, 0.97592593, 0.97592593, 0.97592593, 0.97592593,\n", " 0.97407407, 0.97407407, 0.97407407, 0.97407407, 0.97407407,\n", " 0.97407407, 0.97407407, 0.97407407, 0.97777778]),\n", " 'split1_test_score': array([0.97222222, 0.97222222, 0.97222222, 0.97222222, 0.97222222,\n", " 1. , 1. , 0.99814815, 1. , 1. ,\n", " 1. , 1. , 1. , 1. , 1. ,\n", " 1. , 1. , 1. , 1. , 1. ,\n", " 0.99814815, 0.99814815, 0.99814815, 0.99814815, 0.99814815,\n", " 0.99814815, 0.99814815, 0.9962963 , 1. , 1. ,\n", " 1. , 1. , 1. , 1. , 1. ,\n", " 1. , 1. , 1. , 1. , 1. ,\n", " 0.99814815, 0.99814815, 1. , 1. , 1. ,\n", " 1. , 1. , 1. , 1. ]),\n", " 'split2_test_score': array([0.93333333, 0.95882353, 0.95686275, 0.95686275, 0.95686275,\n", " 0.95294118, 0.95098039, 0.95098039, 0.94901961, 0.94705882,\n", " 0.95294118, 0.95294118, 0.98039216, 0.99019608, 0.99215686,\n", " 0.99019608, 0.98823529, 0.98823529, 0.98823529, 0.98627451,\n", " 0.98627451, 0.98431373, 0.98039216, 0.97647059, 0.9745098 ,\n", " 0.9745098 , 0.97254902, 0.97647059, 0.97647059, 0.98235294,\n", " 0.97843137, 0.97843137, 0.97843137, 0.97647059, 0.97647059,\n", " 0.9745098 , 0.9745098 , 0.97058824, 0.97058824, 0.96862745,\n", " 0.96666667, 0.96666667, 0.9627451 , 0.96078431, 0.96078431,\n", " 0.9627451 , 0.9627451 , 0.9627451 , 0.96078431]),\n", " 'split3_test_score': array([0.90784314, 0.9372549 , 0.9372549 , 0.92941176, 0.92941176,\n", " 0.95882353, 0.95882353, 0.96470588, 0.9627451 , 0.9627451 ,\n", " 0.98627451, 0.98627451, 0.99215686, 0.99411765, 0.99019608,\n", " 0.98823529, 0.98823529, 0.98627451, 0.98431373, 0.98235294,\n", " 0.98039216, 0.97647059, 0.97058824, 0.96862745, 0.96862745,\n", " 0.97254902, 0.97647059, 0.9745098 , 0.9745098 , 0.97058824,\n", " 0.97647059, 0.9745098 , 0.9745098 , 0.97254902, 0.97254902,\n", " 0.97058824, 0.96862745, 0.96862745, 0.96862745, 0.96862745,\n", " 0.96862745, 0.9745098 , 0.9745098 , 0.97254902, 0.9745098 ,\n", " 0.97647059, 0.97647059, 0.97647059, 0.97843137]),\n", " 'split4_test_score': array([0.9372549 , 0.9372549 , 0.93333333, 0.92941176, 0.9254902 ,\n", " 0.92352941, 0.94901961, 0.94705882, 0.94705882, 0.94705882,\n", " 0.94705882, 0.94705882, 0.94705882, 0.94705882, 0.94705882,\n", " 0.94705882, 0.97058824, 0.97058824, 0.97647059, 0.97647059,\n", " 0.9745098 , 0.9745098 , 0.9745098 , 0.9745098 , 0.9745098 ,\n", " 0.9745098 , 0.97254902, 0.9745098 , 0.97254902, 0.97254902,\n", " 0.97254902, 0.97254902, 0.97254902, 0.97254902, 0.96862745,\n", " 0.96862745, 0.96470588, 0.96470588, 0.96666667, 0.96470588,\n", " 0.96666667, 0.96666667, 0.97058824, 0.97058824, 0.96862745,\n", " 0.96666667, 0.96666667, 0.96470588, 0.96470588]),\n", " 'mean_test_score': array([0.92457516, 0.94481481, 0.95437908, 0.95091503, 0.9516122 ,\n", " 0.9611329 , 0.96472767, 0.96662309, 0.968061 , 0.96840959,\n", " 0.9735512 , 0.97318083, 0.97947712, 0.98145969, 0.9803268 ,\n", " 0.97880174, 0.98422658, 0.98309368, 0.98313725, 0.98309368,\n", " 0.98342048, 0.98224401, 0.98028322, 0.97910675, 0.9787146 ,\n", " 0.98023965, 0.97949891, 0.97991285, 0.98026144, 0.98065359,\n", " 0.98104575, 0.98065359, 0.98028322, 0.9783878 , 0.97723312,\n", " 0.9764488 , 0.97675381, 0.9759695 , 0.97636166, 0.97557734,\n", " 0.9748366 , 0.97601307, 0.97638344, 0.97559913, 0.97559913,\n", " 0.97599129, 0.97599129, 0.97559913, 0.97633987]),\n", " 'std_test_score': array([0.03325211, 0.01872544, 0.01660774, 0.0182333 , 0.02064992,\n", " 0.02482919, 0.01851883, 0.0182006 , 0.02016003, 0.02108635,\n", " 0.02025305, 0.02012114, 0.01809218, 0.01894378, 0.01895695,\n", " 0.01887616, 0.01067725, 0.01131942, 0.01120224, 0.01002235,\n", " 0.00831217, 0.00860608, 0.00951598, 0.01002235, 0.01015531,\n", " 0.00945584, 0.00955541, 0.00828506, 0.01002709, 0.0105113 ,\n", " 0.00969438, 0.00990881, 0.01004308, 0.01098385, 0.01175462,\n", " 0.01197354, 0.01230688, 0.01254751, 0.0122156 , 0.01273875,\n", " 0.01196711, 0.01158181, 0.01253933, 0.01305082, 0.01316813,\n", " 0.01298256, 0.01298256, 0.0132844 , 0.01373731]),\n", " 'rank_test_score': array([49, 48, 45, 47, 46, 44, 43, 42, 41, 40, 38, 39, 18, 7, 11, 20, 1,\n", " 4, 3, 4, 2, 6, 12, 19, 21, 15, 17, 16, 14, 9, 8, 9, 12, 22,\n", " 23, 25, 24, 32, 27, 36, 37, 29, 26, 33, 33, 30, 30, 33, 28],\n", " dtype=int32)}" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid_cv.cv_results_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 用整個 training set 做 fitting. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 剛剛的 grid_cv 物件,再找完最佳參數後,就已經幫你把整個 training set 給 fit 完了" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 用 testing set 做 predict" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [], "source": [ "pred_label_test = grid_cv.predict(X_test)\n", "pred_prob_test = grid_cv.predict_proba(X_test)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 效果評估" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.9426699426699426\n", "[[31 6]\n", " [ 3 30]]\n", " precision recall f1-score support\n", "\n", " democrat 0.91 0.84 0.87 37\n", " republican 0.83 0.91 0.87 33\n", "\n", " accuracy 0.87 70\n", " macro avg 0.87 0.87 0.87 70\n", "weighted avg 0.87 0.87 0.87 70\n", "\n" ] } ], "source": [ "# 評估結果\n", "print(grid_cv.score(X_test, y_test))\n", "print(confusion_matrix(y_test, pred_label_test))\n", "print(classification_report(y_test, pred_label_test))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### KNN (multi_class)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 讀資料集" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 要來引入數字辨認資料集" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "from sklearn import datasets\n", "digits = datasets.load_digits()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 這筆資料,x 分成兩種: \n", " * images: 1797張image x 8 x 8 的 3d-array. \n", " * data: 每張 image 拉成 64 個 column,所以變成 1797x64 的 2d-array\n", "* 看一下 shape 是不是真的是這樣:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(1797, 8, 8)\n", "(1797, 64)\n" ] } ], "source": [ "print(digits.images.shape)\n", "print(digits.data.shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 我們可以看一張圖片:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.imshow(digits.images[1010], cmap=plt.cm.gray_r, interpolation='nearest');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 那這個任務,蠻熟悉的,就是給我一張圖片,然後我要辨認出他是 0 ~ 9 的哪個數字" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### fit model & predict" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.9805555555555555\n", "[[36 0 0 0 0 0 0 0 0 0]\n", " [ 0 36 0 0 0 0 0 0 0 0]\n", " [ 0 0 35 0 0 0 0 0 0 0]\n", " [ 0 0 0 37 0 0 0 0 0 0]\n", " [ 0 0 0 0 36 0 0 0 0 0]\n", " [ 0 0 0 0 0 37 0 0 0 0]\n", " [ 0 0 0 0 0 0 35 0 1 0]\n", " [ 0 0 0 0 0 0 0 36 0 0]\n", " [ 0 3 0 0 0 0 0 1 31 0]\n", " [ 0 0 0 0 1 0 0 0 1 34]]\n", " precision recall f1-score support\n", "\n", " 0 1.00 1.00 1.00 36\n", " 1 0.92 1.00 0.96 36\n", " 2 1.00 1.00 1.00 35\n", " 3 1.00 1.00 1.00 37\n", " 4 0.97 1.00 0.99 36\n", " 5 1.00 1.00 1.00 37\n", " 6 1.00 0.97 0.99 36\n", " 7 0.97 1.00 0.99 36\n", " 8 0.94 0.89 0.91 35\n", " 9 1.00 0.94 0.97 36\n", "\n", " accuracy 0.98 360\n", " macro avg 0.98 0.98 0.98 360\n", "weighted avg 0.98 0.98 0.98 360\n", "\n" ] } ], "source": [ "# 切資料\n", "from sklearn.model_selection import train_test_split\n", "X_train, X_test, y_train, y_test = train_test_split(\n", " digits.data, \n", " digits.target, \n", " test_size = 0.2, \n", " random_state = 42, \n", " stratify = digits.target\n", ")\n", "\n", "# fit model\n", "from sklearn.neighbors import KNeighborsClassifier\n", "knn = KNeighborsClassifier(n_neighbors = 6)\n", "knn.fit(X_train, y_train)\n", "\n", "# 預測 training/testing set\n", "pred_label_train = knn.predict(X_train)\n", "pred_prob_train = knn.predict_proba(X_train)\n", "\n", "pred_label_test = knn.predict(X_test)\n", "pred_prob_test = knn.predict_proba(X_test)\n", "\n", "# 評估結果\n", "print(knn.score(X_test, y_test))\n", "print(confusion_matrix(y_test, pred_label_test))\n", "print(classification_report(y_test, pred_label_test))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### overfitting exploration" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 最後,我們來玩點新的,看看 overfitting 的狀況" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "neighbors = np.arange(1, 9) # knn的 k,從複雜(1)到簡單(9)\n", "train_accuracy = np.empty(len(neighbors)) # 先擺個 placeholder\n", "test_accuracy = np.empty(len(neighbors))\n", "\n", "for i, k in enumerate(neighbors):\n", " \n", " knn = KNeighborsClassifier(n_neighbors = k)\n", " knn.fit(X_train, y_train)\n", " \n", " train_accuracy[i] = knn.score(X_train, y_train)\n", " test_accuracy[i] = knn.score(X_test, y_test)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 畫個圖看看" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "image/png": "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VqTlbvzHef78eeXk5KQWL16slLp1EVFKqVmzZil3d3eVlJSklCpYRObMmaMaNmx4x203atRIDRs2zPx63bp1ClAHDx4sdP7c3FxVtWrVfPsGqOHDh+ebLzMzU3l6eqoFCxaYpz366KOqT58+5teFFRG9Xp/vi2zFihVK0zSVkZGhlFJq8ODB+YqKUkrNmzevyEVEKaVefPFFVa9ePZWdna2UKnkReeihh/IdlypVqqjevXvnm1a1alU1Z86cfOt+4okn8q37scceM+/Tli1blL29vbpy5Uq+eYYNG2be3o0i8s4779xyf2/w9/dXr7zySr5pL774oqpTp4759b//DrdS1M9ply5d1IQJE/Ite+bMGQWo/fv3F7rNDh06FDguEyZMKFBEALV3717zPLt27VKAOnLkiFLq/4rIjSKplFI5OTmqZs2aauLEiUoppSZOnKj8/PxUVlaWeZ7o6GgFqK1bt5rzaZqmzpw5ky+Tq6trvs+KtZPmrApo/fr1DBkyhBUrVvD444/ne69Jkya4uLjg4uJCkyZNCix7o+lr0qRJZGRk3HY7Y8aMwWAw8O677xb6/vPPP8+RI0fumHfUqFF88803pKamArBgwQI6duxoznfq1CmGDBlCvXr1cHV1xdXVlatXr3LmzJl862nTpk2+1/b29gwdOtTcXJaUlMT333/P008/fds81atXx8vLK99rpZS5qSEmJoZ27drlW6Z9+/Z33M+bTZo0icTERObNm1es5f4tODjY/G+dToeXlxfNmjXLN83b2ztfM0lheTt27MihQ4cAiIqKIjs7Gz8/P/NnxcXFhWXLlhVo1vv3Mf+31NRU4uLiCA0NzTe9S5cunD59mvT09KLv7E3u9DmNiopi1qxZ+fI3btwYoMA+3FDUv6umafmOe/Xq1QG4fPnyLZe1sbGhTZs25mN86NAh2rVrl+/aT3BwMG5ubuZ5AKpVq0bNmjXzrXf8+PGMHDmSsLAwJk+ezL59+wrdH2shRaQCCgoKok6dOixYsKDANYt169YRHR1NdHQ069atK3T5V199ldzcXGbOnHnb7dja2jJt2jTmzp3LyZMnS5z3qaeewmg08tVXX3H58mXWrl2b71pG7969OXv2LHPnzmXXrl1ER0fj7e1dYN+cnZ0LrHv06NFERUVx4MABli5dipeXFw888MBt8/z7oq6maUDehc1/Tyspg8HAf//7X9555x2uXr1a4H1N0wpcw8rJySkwn62tbYHlCpt2c/Y7MZlMuLm5mT8nN/4XExPDL7/8km/ewo55ebnd59RkMjFhwoQC+3Ds2LHb/v2L8nfV6XTo9foCyxTnGBdVYcd30qRJxMbGMmjQIA4ePEi7du2YOHFiqW+7vEgRqYD8/f3ZunUrR44coW/fvmRlZZnfq1WrFvXq1aNevXrUqlWr0OVdXFx4++23mT59eoFfV/82YMAAWrVqxWuvvVbivDdfYP/iiy+oUqWK+TbYpKQkYmJieO211+jevTuNGzfGwcGhwC/rW6lXrx5du3ZlwYIFLFy4kOHDh+f7AiiJxo0b88cff+SbVpK7rcaOHUuVKlWYOnVqgfe8vb25cOGC+XVWVhYxMTHFD3sL/867c+dO8y/1kJAQrly5QmZmpvmzcuN///5VfCeurq74+/uzbdu2fNO3bt1KnTp1cHJyKvE+3O5zGhISwqFDhwrkr1evHi4uLoWur7T+roUtazQa2b17t/kYN2nShF27duX7IfTXX39x9epVgoKC7rjuunXrMmbMGFavXs0777xz12e0liRFpILy8/Nj69atnD59mj59+tyxaerfRowYQY0aNVi0aNEd5505cyarV6/m/Pnz+aZ/8sknNGrUqEjbGzVqFPv37+eDDz5gyJAhODg4AODu7o6XlxcLFiwgNjaWP/74g8ceewxHR8ci78vo0aP5/PPPOXz4cKk8iPmf//yH33//nTfffJPY2FjWrFlj/jVcnDMUe3t73nvvPWbPnl3gV2xERATz58/njz/+4ODBgwwdOvSu7oT7t59++olPPvmEY8eOMWfOHFauXMnLL78MQNeuXYmIiKBfv3788MMPnDx5kr179zJnzpxC76S7k9dff9287LFjx/jss8+YN28eb7zxxl3vx60+p++88w4//vgj//nPf4iOjubEiROsX7+eESNG3PK/hZdffpkVK1YwZ84cjh8/zpdffsmXX34JlOzMc9q0aaxbt47Dhw/z7LPPkpCQwJgxY4C8pt7U1FSGDh3KwYMH2bFjB0OGDKFz58507tz5luu8du0azz33HJs3b+bUqVPs37+f9evXm4uTNZIiUoH5+PgQGRnJpUuX6N27d7Han/V6PdOnTy9S8Wnfvj39+/cnMzMz3/TExESOHj1apO2FhobSqFEjUlJS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c/ToUbZt20bNmjV55ZVXAHjsscdo2bKlhZMVLiUlhblz52IymVBK0b59e1q1amXpWJXC1atXmTFjBpDXXNSpUyeaN29u2VC3MXz4cGbPno3RaMTb25sxY8ZYOtJt3SjMo0aNsnSU26pfvz7t2rVjwoQJ6PV6ateuXarXxqTbEyGEECUm10SEEEKUmBQRIYQQJSZFRAghRIlJERFCCFFiUkSEEEKUmBQRcU+bO3cuK1assMi2lVJ8+umnDBs2jNdff73U15+YmMiQIUMwmUx3nPdGL7S5ubmFvv/NN99U+AcrhWVIEREVynPPPcfIkSPJzMw0T9u0aROTJ0+2XKgycuTIEQ4cOMC8efN4//33C7wfGRnJoEGD+PHHH/NNf+aZZzh06NAd1+/p6cnSpUvR6eQ/c1F25NMlKhyTycS6dessHaPYivKL/2YJCQl4eXndtpNBFxcX1qxZY1UdPt5JcY+TqNjkiXVR4fTp04cff/yR7t27F+gOPD4+nueff56vv/4avV4PwOTJk+ncuTPdunUjMjKSTZs2ERAQQGRkJC4uLowdO5aLFy+ycuVKcnJyeOKJJwgLCzOvMzU1lSlTpnDs2DHq1KnD888/b+7W+/z58yxevJiTJ0/i6urKI488QocOHYC8pjA7OzsSExOJiYnhlVdeoVmzZvnyJicns2DBAo4cOYKLiwsPPfQQERERbN68mUWLFmE0GhkyZAgPPvhgoYNx+fn54ezszE8//cTAgQMLvG8ymVizZg2bNm3i+vXrBAUFMWrUKFxcXAocq/j4eObOncupU6eoX78+vr6+pKen5+u6Zfv27axcuZLs7Gx69epFv379zO/l5OTw0UcfsX//fnx9fXn22WepXbs2AHFxcSxcuJDTp09jMBgYPHgwISEhtzxORqORpUuXkpSUhKOjI7169aJPnz5F/YiICkTORESFU7duXZo0acLatWtLtPyxY8eoVasWixcvplOnTsyaNYvjx48ze/Zsxo4dy+LFi/M1l+3YsYP+/fuzaNEiateubW77z8zM5N1336VTp04sXLiQF198kUWLFhEXF5dv2b59+/K///2PRo0aFcjy8ccf4+HhwWeffcbLL7/M119/zcGDB+natStPP/00DRo0YOnSpbcdzfHRRx9l3bp1XLt2rcB769evJyoqismTJ/PZZ5/h4uLCwoULC13Pxx9/TEBAAIsXL2bgwIFs3769wDxHjhzh448/ZtKkSaxevTrfvu7Zs4f27duzePFiOnbsyIcffojRaMRoNPLBBx/QrFkzFi5caO6+5MKFC7c8TvPnz2fUqFF8+eWXzJw5k6CgoFvuv6jYpIiICmnQoEH88ssvpKamFntZb29vwsPD0el0dOjQgaSkJAYMGICtrS3BwcHY2Nhw6dIl8/wtW7akcePG2Nra8thjjxEbG0tiYiL79u3Dy8uL8PBw9Ho9derUoW3btvzxxx/mZVu3bk2jRo3Q6XQFhhtNTEzkyJEjPP7449jZ2VG7dm26devG1q1bi7U/tWvXpmnTpoV2jb5hwwYeffRRPDw8sLW1ZeDAgfz5558FLpAnJiZy4sQJHnnkEWxsbGjUqFGhfZQNHDjQnLVWrVqcOXPG/F7dunVp164dNjY29O7dm5ycHI4dO8axY8fIzMzk4YcfxsbGhqCgIFq2bMmOHTtueZz0ej1xcXGkp6fj4uJiVd3ri/ykOUtUSDVr1qRVq1b88MMP+Pn5FWtZNzc3879vfLHf3FW3nZ1dvjMRDw8P878dHBxwcXEhJSWFhIQEjh07xtChQ83v5+bmEhoaWuiy/5aSkoKLiwuOjo7maZ6enpw4caJY+wPwyCOP8MYbbxTomTkhIYEZM2bkGw1Sp9Nx9erVfPMlJyfj4uKCvb19viyJiYn55rv5ONnb29/yOOl0Ojw8PEhJSTGv6+YL+F5eXvlG1Pz3cXr55Zf57rvvWL58OTVr1uTxxx+vsOOpi9uTIiIqrEGDBjFhwoR8X5w3LkJnZWWZB9u6cuXKXW0nKSnJ/O/MzEyuXbuGu7s7Hh4eNG7cmEmTJt1y2dsN5evu7s61a9fIyMgwF5LExETzGB/F4efnR5s2bfjuu+/yTffw8ODZZ58ttCktPj6+QJasrCxzIfl3AbmTm4+TyWQiKSnJPMxqYmIiJpPJXEgSExPx9fU1z//v41SvXj1effVVjEYj69ev56OPPmLevHnFyiMqBmnOEhWWj48P7du355dffjFPc3V1xWAwsH37dkwmE5s3b+by5ct3tZ39+/dz5MgRjEYjK1asoEGDBnh6etKqVSsuXrzItm3bzG3/x48fz3ed4HY8PT1p2LAhy5cvJzs7mzNnzrBlyxY6d+5copwDBw4kMjKS69evm6fdd999rFixgoSEBCDvJoGoqKgCy3p5eREQEMCqVaswGo3Exsayd+/eYm3/5MmT5qaydevWYWtrS/369alfvz729vasWbMGo9HIoUOH2Lt37y3H2TAajWzfvp309HRsbGxwcnK6bTEWFZuciYgKbcCAAQUuAI8ePZqFCxfy9ddf07Vr17tuBunYsSOrVq0iNjaWunXrMnbsWAAcHR2ZOHEi//vf//jf//6HUopatWrx1FNPFXndL7zwAgsWLGD06NG4uLgwcODAAndwFZW3tzehoaH89ttv5mk9e/YE4N133yUlJQU3Nzfat29P69atCyw/duxYPv30U4YPH069evXo0KFDsW63DQkJYefOncydOxcfHx9efvllbGzyvkImTJjAwoUL+f777zEYDDz//PO3bYbctm0bixcvxmQyUb169Qo9uJe4PRlPRIh71EcffYSfn99t7wwT4k6kOUuIe8Tx48e5dOkSJpOJ6Oho9uzZU+gZixDFIc1ZQtwjrly5wsyZM0lLS8PDw4ORI0dSp04dS8cSVk6as4QQQpSYNGcJIYQoMSkiQgghSkyKiBBCiBKTIiKEEKLEpIgIIYQosf8PDBKRQLbnehEAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots()\n", "ax.plot(neighbors, train_accuracy, label = \"train\");\n", "ax.plot(neighbors, test_accuracy, label = \"test\");\n", "ax.legend();\n", "ax.set(\n", " xlabel='Number of Neighbors', \n", " ylabel='Accuracy',\n", " title='k-NN: Varying Number of Neighbors'\n", ");" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Logistic (binary)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 讀資料集" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
pregnanciesglucosediastolictricepsinsulinbmidpfagediabetes
061487235033.60.627501
11856629026.60.351310
28183640023.30.672321
318966239428.10.167210
40137403516843.12.288331
..............................
76310101764818032.90.171630
76421227027036.80.340270
7655121722311226.20.245300
7661126600030.10.349471
7671937031030.40.315230
\n", "

768 rows × 9 columns

\n", "
" ], "text/plain": [ " pregnancies glucose diastolic triceps insulin bmi dpf age \\\n", "0 6 148 72 35 0 33.6 0.627 50 \n", "1 1 85 66 29 0 26.6 0.351 31 \n", "2 8 183 64 0 0 23.3 0.672 32 \n", "3 1 89 66 23 94 28.1 0.167 21 \n", "4 0 137 40 35 168 43.1 2.288 33 \n", ".. ... ... ... ... ... ... ... ... \n", "763 10 101 76 48 180 32.9 0.171 63 \n", "764 2 122 70 27 0 36.8 0.340 27 \n", "765 5 121 72 23 112 26.2 0.245 30 \n", "766 1 126 60 0 0 30.1 0.349 47 \n", "767 1 93 70 31 0 30.4 0.315 23 \n", "\n", " diabetes \n", "0 1 \n", "1 0 \n", "2 1 \n", "3 0 \n", "4 1 \n", ".. ... \n", "763 0 \n", "764 0 \n", "765 0 \n", "766 1 \n", "767 0 \n", "\n", "[768 rows x 9 columns]" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diabetes = pd.read_csv(\"data/diabetes.csv\")\n", "diabetes" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "RangeIndex: 768 entries, 0 to 767\n", "Data columns (total 9 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 pregnancies 768 non-null int64 \n", " 1 glucose 768 non-null int64 \n", " 2 diastolic 768 non-null int64 \n", " 3 triceps 768 non-null int64 \n", " 4 insulin 768 non-null int64 \n", " 5 bmi 768 non-null float64\n", " 6 dpf 768 non-null float64\n", " 7 age 768 non-null int64 \n", " 8 diabetes 768 non-null int64 \n", "dtypes: float64(2), int64(7)\n", "memory usage: 54.1 KB\n" ] } ], "source": [ "diabetes.info()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### fit, predict, and evaluate" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/model_selection/_validation.py:372: FitFailedWarning: \n", "75 fits failed out of a total of 150.\n", "The score on these train-test partitions for these parameters will be set to nan.\n", "If these failures are not expected, you can try to debug them by setting error_score='raise'.\n", "\n", "Below are more details about the failures:\n", "--------------------------------------------------------------------------------\n", "75 fits failed with the following error:\n", "Traceback (most recent call last):\n", " File \"/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/model_selection/_validation.py\", line 680, in _fit_and_score\n", " estimator.fit(X_train, y_train, **fit_params)\n", " File \"/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py\", line 1461, in fit\n", " solver = _check_solver(self.solver, self.penalty, self.dual)\n", " File \"/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py\", line 447, in _check_solver\n", " raise ValueError(\n", "ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.\n", "\n", " warnings.warn(some_fits_failed_message, FitFailedWarning)\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/model_selection/_search.py:969: UserWarning: One or more of the test scores are non-finite: [ nan 0.72391304 nan 0.7673913 nan 0.77608696\n", " nan 0.7826087 nan 0.77391304 nan 0.78913043\n", " nan 0.78043478 nan 0.78043478 nan 0.77391304\n", " nan 0.77391304 nan 0.76956522 nan 0.77391304\n", " nan 0.7673913 nan 0.77608696 nan 0.77391304]\n", " warnings.warn(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):\n", "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n", "\n", "Increase the number of iterations (max_iter) or scale the data as shown in:\n", " https://scikit-learn.org/stable/modules/preprocessing.html\n", "Please also refer to the documentation for alternative solver options:\n", " https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n", " n_iter_i = _check_optimize_result(\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Tuned Logistic Regression Parameters: {'C': 0.4393970560760795, 'penalty': 'l2'}\n", "Best score is 0.7891304347826086\n", "[[169 32]\n", " [ 47 60]]\n", " precision recall f1-score support\n", "\n", " 0 0.78 0.84 0.81 201\n", " 1 0.65 0.56 0.60 107\n", "\n", " accuracy 0.74 308\n", " macro avg 0.72 0.70 0.71 308\n", "weighted avg 0.74 0.74 0.74 308\n", "\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "0.7007718417259498\n" ] } ], "source": [ "# 切資料\n", "from sklearn.model_selection import train_test_split\n", "\n", "# preprocess (沒用到)\n", "# from sklearn.impute import SimpleImputer\n", "# from sklearn.pipeline import Pipeline\n", "\n", "# modeling\n", "from sklearn.linear_model import LogisticRegression\n", "\n", "# hyper-parameter tunning\n", "from sklearn.model_selection import GridSearchCV\n", "\n", "# evaluation\n", "from sklearn.metrics import confusion_matrix, classification_report, roc_curve, roc_auc_score\n", "\n", "\n", "# 切資料\n", "X = diabetes.drop(\"diabetes\", axis = 1)\n", "y = diabetes[\"diabetes\"]\n", "X_train, X_test, y_train, y_test = train_test_split(\n", " X, \n", " y, \n", " test_size = 0.4, \n", " random_state = 42, \n", " stratify = y\n", ")\n", "\n", "# model\n", "logreg = LogisticRegression()\n", "\n", "# hyper-parameter tunning\n", "# logistic regression 的 regularization parameter 是 C ,代表 inverse of the regularization strength, \n", "# 所以,C 越大,regularize能力越爛,越容易 overfit model; \n", "# C 越小,regularize能力越強,越容易 underfit model\n", "c_space = np.logspace(-5, 8, 15)\n", "param_grid = {\"C\": c_space, \"penalty\": ['l1', 'l2']}\n", "logreg_cv = GridSearchCV(logreg, param_grid, cv=5)\n", "logreg_cv.fit(X_train, y_train)\n", "print(\"Tuned Logistic Regression Parameters: {}\".format(logreg_cv.best_params_)) \n", "print(\"Best score is {}\".format(logreg_cv.best_score_))\n", "\n", "# 預測 training/testing set\n", "y_pred = logreg_cv.predict(X_test)\n", "y_pred_prob = logreg_cv.predict_proba(X_test)[:,1]\n", "\n", "\n", "# 評估結果\n", "print(\"AUC: {}\".format(roc_auc_score(y_test, y_pred_prob)))\n", "print(confusion_matrix(y_test, y_pred))\n", "print(classification_report(y_test, y_pred))\n", "\n", "fpr, tpr, thresholds = roc_curve(y_test, y_pred_prob)\n", "plt.plot([0,1],[0, 1], \"k--\")\n", "plt.plot(fpr, tpr, label = \"Logistic Regression\")\n", "plt.xlabel(\"False Positive Rate\")\n", "plt.ylabel(\"True Positive Rate\")\n", "plt.title(\"Logistic Regression ROC Curve\")\n", "plt.show()\n", "\n", "print(roc_auc_score(y_test, y_pred))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* precision & recall\n", " * precision = 你說是 positive 的人中,有多少個是真的 positive\n", " * recall = true positive rate = 真的是positive的人中,你揪出了幾個?\n", " * cutpoint -> 1, precision ->1,因為惜字如金,只要我說是positive,幾乎一定是 positive。\n", " * cutpoint -> 0, recall -> 1, 因為cutpoint接近0的時候,幾乎所有人全被說 positive,那recall的分子就幾乎全中了" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### DecisionTree (binary)" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tuned Decision Tree Parameters: {'criterion': 'entropy', 'max_depth': 3, 'max_features': 5, 'min_samples_leaf': 5}\n", "Best score is 0.7608695652173914\n", "AUC: 0.7851629701957501\n", "[[174 27]\n", " [ 57 50]]\n", " precision recall f1-score support\n", "\n", " 0 0.75 0.87 0.81 201\n", " 1 0.65 0.47 0.54 107\n", "\n", " accuracy 0.73 308\n", " macro avg 0.70 0.67 0.67 308\n", "weighted avg 0.72 0.73 0.71 308\n", "\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# 切資料\n", "from sklearn.model_selection import train_test_split\n", "\n", "# preprocess (沒用到)\n", "# from sklearn.impute import SimpleImputer\n", "# from sklearn.pipeline import Pipeline\n", "\n", "# modeling\n", "from sklearn.tree import DecisionTreeClassifier\n", "\n", "# hyper-parameter tunning\n", "from sklearn.model_selection import RandomizedSearchCV\n", "\n", "# evaluation\n", "from sklearn.metrics import confusion_matrix, classification_report, roc_curve, roc_auc_score\n", "\n", "# utils \n", "from scipy.stats import randint\n", "\n", "\n", "\n", "# 讀檔 & 切資料\n", "diabetes = pd.read_csv(\"data/diabetes.csv\")\n", "X = diabetes.drop(\"diabetes\", axis = 1)\n", "y = diabetes[\"diabetes\"]\n", "X_train, X_test, y_train, y_test = train_test_split(\n", " X, \n", " y, \n", " test_size = 0.4, \n", " random_state = 42, \n", " stratify = y\n", ")\n", "\n", "# model\n", "tree = DecisionTreeClassifier()\n", "\n", "# hyper-parameter tunning\n", "param_dist = {\"max_depth\": [3, None],\n", " \"max_features\": randint(1, 9),\n", " \"min_samples_leaf\": randint(1, 9),\n", " \"criterion\": [\"gini\", \"entropy\"]}\n", "tree_randomcv = RandomizedSearchCV(tree, param_dist, cv=5)\n", "tree_randomcv.fit(X_train, y_train)\n", "print(\"Tuned Decision Tree Parameters: {}\".format(tree_randomcv.best_params_))\n", "print(\"Best score is {}\".format(tree_randomcv.best_score_))\n", "\n", "# 預測 training/testing set\n", "y_pred = tree_randomcv.predict(X_test)\n", "y_pred_prob = tree_randomcv.predict_proba(X_test)[:,1]\n", "\n", "\n", "# 評估結果\n", "print(\"AUC: {}\".format(roc_auc_score(y_test, y_pred_prob)))\n", "print(confusion_matrix(y_test, y_pred))\n", "print(classification_report(y_test, y_pred))\n", "\n", "fpr, tpr, thresholds = roc_curve(y_test, y_pred_prob)\n", "plt.plot([0,1],[0, 1], \"k--\")\n", "plt.plot(fpr, tpr, label = \"Decision Tree\")\n", "plt.xlabel(\"False Positive Rate\")\n", "plt.ylabel(\"True Positive Rate\")\n", "plt.title(\"Logistic Regression ROC Curve\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### SVC (binary)" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tuned Model Parameters: {'SVM__C': 10, 'SVM__gamma': 0.01}\n", "Accuracy: 0.9541984732824428\n", " precision recall f1-score support\n", "\n", " democrat 0.99 0.94 0.96 83\n", " republican 0.90 0.98 0.94 48\n", "\n", " accuracy 0.95 131\n", " macro avg 0.95 0.96 0.95 131\n", "weighted avg 0.96 0.95 0.95 131\n", "\n" ] } ], "source": [ "# Import necessary modules\n", "from sklearn.impute import SimpleImputer\n", "from sklearn.pipeline import Pipeline\n", "from sklearn.svm import SVC\n", "\n", "# 讀資料\n", "vote_raw = pd.read_csv(\"data/house-votes-84.csv\")\n", "vote = vote_raw.copy()\n", "col_names = ['party', 'infants', 'water', 'budget', 'physician', 'salvador',\n", " 'religious', 'satellite', 'aid', 'missile', 'immigration', 'synfuels',\n", " 'education', 'superfund', 'crime', 'duty_free_exports', 'eaa_rsa']\n", "vote.columns = col_names\n", "vote[vote == \"?\"] = np.nan # 把 ? 改成 na\n", "for i in col_names[1:]:\n", " vote[i] = vote[i].replace({\"y\": 1, \"n\": 0})\n", "X = vote.drop(\"party\", axis = 1)\n", "y = vote[\"party\"]\n", "\n", "# 切資料\n", "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 42)\n", "\n", "# pipeline: 前處理 & model\n", "steps = [('imputation', SimpleImputer(missing_values=np.nan, strategy='most_frequent')),\n", " (\"scaler\", StandardScaler()),\n", " ('SVM', SVC())]\n", "\n", "# Create the pipeline: pipeline\n", "pipeline = Pipeline(steps)\n", "\n", "\n", "# hyper-parameter tunning\n", "parameters = {'SVM__C':[1, 10, 100],\n", " 'SVM__gamma':[0.1, 0.01]}\n", "cv = GridSearchCV(pipeline, parameters, cv = 3)\n", "cv.fit(X_train, y_train)\n", "print(\"Tuned Model Parameters: {}\".format(cv.best_params_))\n", "\n", "# 預測\n", "y_pred = cv.predict(X_test)\n", "\n", "# performance\n", "print(\"Accuracy: {}\".format(cv.score(X_test, y_test)))\n", "print(classification_report(y_test, y_pred))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Regression" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Gapminder Data" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
populationfertilityHIVCO2BMI_maleGDPBMI_femalelifechild_mortalityRegion
034811059.02.730.13.32894524.5962012314.0129.904975.329.5Middle East & North Africa
119842251.06.432.01.47435322.250837103.0130.124758.3192.0Sub-Saharan Africa
240381860.02.240.54.78517027.5017014646.0118.891575.515.4America
32975029.01.400.11.80410625.355427383.0132.810872.520.0Europe & Central Asia
421370348.01.960.118.01631327.5637341312.0117.375581.55.2East Asia & Pacific
\n", "
" ], "text/plain": [ " population fertility HIV CO2 BMI_male GDP BMI_female life \\\n", "0 34811059.0 2.73 0.1 3.328945 24.59620 12314.0 129.9049 75.3 \n", "1 19842251.0 6.43 2.0 1.474353 22.25083 7103.0 130.1247 58.3 \n", "2 40381860.0 2.24 0.5 4.785170 27.50170 14646.0 118.8915 75.5 \n", "3 2975029.0 1.40 0.1 1.804106 25.35542 7383.0 132.8108 72.5 \n", "4 21370348.0 1.96 0.1 18.016313 27.56373 41312.0 117.3755 81.5 \n", "\n", " child_mortality Region \n", "0 29.5 Middle East & North Africa \n", "1 192.0 Sub-Saharan Africa \n", "2 15.4 America \n", "3 20.0 Europe & Central Asia \n", "4 5.2 East Asia & Pacific " ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "gapminder = pd.read_csv(\"data/gm_2008_region.csv\")\n", "gapminder.head()" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "RangeIndex: 139 entries, 0 to 138\n", "Data columns (total 10 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 population 139 non-null float64\n", " 1 fertility 139 non-null float64\n", " 2 HIV 139 non-null float64\n", " 3 CO2 139 non-null float64\n", " 4 BMI_male 139 non-null float64\n", " 5 GDP 139 non-null float64\n", " 6 BMI_female 139 non-null float64\n", " 7 life 139 non-null float64\n", " 8 child_mortality 139 non-null float64\n", " 9 Region 139 non-null object \n", "dtypes: float64(9), object(1)\n", "memory usage: 11.0+ KB\n" ] } ], "source": [ "gapminder.info()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Linear Regression" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### train/test" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R^2: 0.8219419939587727\n", "Root Mean Squared Error: 3.405248115733344\n" ] } ], "source": [ "from sklearn.model_selection import train_test_split\n", "from sklearn.linear_model import LinearRegression\n", "from sklearn.metrics import mean_squared_error\n", "\n", "# preprocess. \n", "# gapminder_onehot = pd.get_dummies(gapminder)\n", "gapminder_dummy = pd.get_dummies(gapminder, drop_first = True)\n", "\n", "# 分割資料\n", "X = gapminder_dummy.drop(\"life\", axis = 1)\n", "y = gapminder_dummy[\"life\"]\n", "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state=42)\n", "\n", "# fit model\n", "reg_all = LinearRegression()\n", "reg_all.fit(X_train, y_train)\n", "\n", "# Predict on the test data: y_pred\n", "y_pred = reg_all.predict(X_test)\n", "\n", "# Compute and print R^2 and RMSE\n", "print(\"R^2: {}\".format(reg_all.score(X_test, y_test)))\n", "rmse = np.sqrt(mean_squared_error(y_test, y_pred))\n", "print(\"Root Mean Squared Error: {}\".format(rmse))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### CV" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0.8196741 0.80301541 0.89758712 0.80425614 0.94015848]\n", "Average 5-Fold CV Score: 0.8529382494240787\n" ] } ], "source": [ "from sklearn.linear_model import LinearRegression\n", "from sklearn.model_selection import cross_val_score\n", "\n", "# 分割資料\n", "# 不分割了,因為等等直接用 cv\n", "\n", "# fit model\n", "reg = LinearRegression()\n", "cv_scores = cross_val_score(reg, X, y, cv = 5)\n", "\n", "print(cv_scores) # 5-fold cv 結果\n", "\n", "print(f\"Average 5-Fold CV Score: {str(np.mean(cv_scores))}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Lasso Regression" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R^2: 0.8401265152705228\n", "Root Mean Squared Error: 3.2266824659707334\n" ] } ], "source": [ "# Import Lasso\n", "from sklearn.linear_model import Lasso\n", "from sklearn.preprocessing import StandardScaler\n", "from sklearn.pipeline import make_pipeline\n", "\n", "# pipeline\n", "lasso_pipe = make_pipeline(\n", " StandardScaler(),\n", " Lasso(alpha = 0.4)\n", ")\n", "\n", "# Fit the regressor to the data\n", "lasso_pipe.fit(X_train, y_train)\n", "\n", "y_pred = lasso_pipe.predict(X_test)\n", "\n", "# Compute and print R^2 and RMSE\n", "print(\"R^2: {}\".format(lasso_pipe.score(X_test, y_test)))\n", "rmse = np.sqrt(mean_squared_error(y_test, y_pred))\n", "print(\"Root Mean Squared Error: {}\".format(rmse))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 看一下哪些變數被 shrinkage 到 0 ,哪些變數最重要:" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[-0. -0.08591553 -2.91968634 -0. 0.58693244 1.6922106\n", " -1.11083667 -4.3362549 -0.48746711 0. 0. 0.\n", " -0.1705074 ]\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Compute and print the coefficients\n", "lasso_coef = lasso_pipe.named_steps[\"lasso\"].coef_\n", "print(lasso_coef)\n", "\n", "# Plot the coefficients\n", "\n", "plt.plot(range(len(X_train.columns)), lasso_coef)\n", "plt.xticks(range(len(X_train.columns)), X_train.columns.values, rotation=60)\n", "plt.margins(0.02)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ridge Regression" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [], "source": [ "def display_plot(cv_scores, cv_scores_std):\n", " fig = plt.figure()\n", " ax = fig.add_subplot(1,1,1)\n", " ax.plot(alpha_space, cv_scores)\n", "\n", " std_error = cv_scores_std / np.sqrt(10)\n", "\n", " ax.fill_between(alpha_space, cv_scores + std_error, cv_scores - std_error, alpha=0.2)\n", " ax.set_ylabel('CV Score +/- Std Error')\n", " ax.set_xlabel('Alpha')\n", " ax.axhline(np.max(cv_scores), linestyle='--', color='.5')\n", " ax.set_xlim([alpha_space[0], alpha_space[-1]])\n", " ax.set_xscale('log')\n", " plt.show()" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Import necessary modules\n", "from sklearn.linear_model import Ridge\n", "from sklearn.model_selection import cross_val_score\n", "\n", "# Setup the array of alphas and lists to store scores\n", "alpha_space = np.logspace(-4, 0, 50)\n", "ridge_scores = []\n", "ridge_scores_std = []\n", "\n", "# ridge = Ridge(normalize=True)\n", "\n", "# Compute scores over range of alphas\n", "for alpha in alpha_space:\n", "\n", " # Specify the alpha value to use: ridge.alpha\n", " \n", " ridge = make_pipeline(\n", " StandardScaler(),\n", " Ridge(alpha = alpha)\n", " )\n", " # ridge.named_steps[\"ridge\"].alpha = alpha\n", " #ridge.alpha = alpha\n", " \n", " # Perform 10-fold CV: ridge_cv_scores\n", " ridge_cv_scores = cross_val_score(ridge, X, y, cv=10)\n", " \n", " # Append the mean of ridge_cv_scores to ridge_scores\n", " ridge_scores.append(np.mean(ridge_cv_scores))\n", " \n", " # Append the std of ridge_cv_scores to ridge_scores_std\n", " ridge_scores_std.append(np.std(ridge_cv_scores))\n", "\n", "# Display the plot\n", "display_plot(ridge_scores, ridge_scores_std)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Elastic net" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_coordinate_descent.py:647: ConvergenceWarning: Objective did not converge. You might want to increase the number of iterations, check the scale of the features or consider increasing regularisation. Duality gap: 8.126e+02, tolerance: 5.589e-01 Linear regression models with null weight for the l1 regularization term are more efficiently fitted using one of the solvers implemented in sklearn.linear_model.Ridge/RidgeCV instead.\n", " model = cd_fast.enet_coordinate_descent(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_coordinate_descent.py:647: ConvergenceWarning: Objective did not converge. You might want to increase the number of iterations, check the scale of the features or consider increasing regularisation. Duality gap: 8.410e+02, tolerance: 5.893e-01 Linear regression models with null weight for the l1 regularization term are more efficiently fitted using one of the solvers implemented in sklearn.linear_model.Ridge/RidgeCV instead.\n", " model = cd_fast.enet_coordinate_descent(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_coordinate_descent.py:647: ConvergenceWarning: Objective did not converge. You might want to increase the number of iterations, check the scale of the features or consider increasing regularisation. Duality gap: 7.983e+02, tolerance: 5.890e-01 Linear regression models with null weight for the l1 regularization term are more efficiently fitted using one of the solvers implemented in sklearn.linear_model.Ridge/RidgeCV instead.\n", " model = cd_fast.enet_coordinate_descent(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_coordinate_descent.py:647: ConvergenceWarning: Objective did not converge. You might want to increase the number of iterations, check the scale of the features or consider increasing regularisation. Duality gap: 8.506e+02, tolerance: 5.814e-01 Linear regression models with null weight for the l1 regularization term are more efficiently fitted using one of the solvers implemented in sklearn.linear_model.Ridge/RidgeCV instead.\n", " model = cd_fast.enet_coordinate_descent(\n", "/Volumes/GoogleDrive/我的雲端硬碟/0. codepool_python/python_ds/python_ds_env/lib/python3.8/site-packages/sklearn/linear_model/_coordinate_descent.py:647: ConvergenceWarning: Objective did not converge. You might want to increase the number of iterations, check the scale of the features or consider increasing regularisation. Duality gap: 8.375e+02, tolerance: 5.802e-01 Linear regression models with null weight for the l1 regularization term are more efficiently fitted using one of the solvers implemented in sklearn.linear_model.Ridge/RidgeCV instead.\n", " model = cd_fast.enet_coordinate_descent(\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Tuned ElasticNet l1 ratio: {'elasticnet__l1_ratio': 1.0}\n", "Tuned ElasticNet R squared: 0.8862016549771035\n", "Tuned ElasticNet MSE: 8.594868215979249\n" ] } ], "source": [ "# Import necessary modules\n", "from sklearn.model_selection import train_test_split\n", "from sklearn.model_selection import GridSearchCV\n", "from sklearn.linear_model import ElasticNet\n", "from sklearn.metrics import mean_squared_error\n", "\n", "# 讀資料 & 切資料\n", "gapminder = pd.read_csv(\"data/gm_2008_region.csv\")\n", "X = gapminder_dummy.drop(\"life\", axis = 1)\n", "y = gapminder_dummy[\"life\"]\n", "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.4, random_state = 42)\n", "\n", "# pipeline: 前處理 & model\n", "steps = [('imputation', SimpleImputer(missing_values=np.nan, strategy='mean')),\n", " (\"scaler\", StandardScaler()),\n", " (\"elasticnet\", ElasticNet())]\n", "pipeline = Pipeline(steps)\n", "\n", "# hyper-parameter tunning\n", "parameters = {\"elasticnet__l1_ratio\":np.linspace(0,1,30)} # l1_ratio*L1_loss + (1-l1_ratio)*L2_loss\n", "gm_cv = GridSearchCV(pipeline, parameters, cv = 5)\n", "gm_cv.fit(X_train, y_train)\n", "print(\"Tuned ElasticNet l1 ratio: {}\".format(gm_cv.best_params_))\n", "\n", "# Predict\n", "y_pred = gm_cv.predict(X_test)\n", "\n", "# performance\n", "r2 = gm_cv.score(X_test, y_test)\n", "mse = mean_squared_error(y_test, y_pred)\n", "print(\"Tuned ElasticNet R squared: {}\".format(r2))\n", "print(\"Tuned ElasticNet MSE: {}\".format(mse))" ] } ], "metadata": { "kernelspec": { "display_name": "python_ds_env", "language": "python", "name": "python_ds_env" }, "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.8.0" } }, "nbformat": 4, "nbformat_minor": 4 }