{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from sklearn.datasets import load_iris\n", "\n", "import matplotlib as mpl\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(['setosa', 'versicolor', 'virginica'], dtype='" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(9, 3.5))\n", "\n", "# 1. 꽃의 종류를 구분해서 보자.\n", "plt.subplot(121)\n", "plt.plot(X[y==0, 2], X[y==0, 3], \"yo\", label=\"Iris-Setosa\")\n", "plt.plot(X[y==1, 2], X[y==1, 3], \"bs\", label=\"Iris-Versicolor\")\n", "plt.plot(X[y==2, 2], X[y==2, 3], \"g^\", label=\"Iris-Virginica\")\n", "plt.xlabel(\"Petal length\", fontsize=14)\n", "plt.ylabel(\"Petal width\", fontsize=14)\n", "plt.legend(fontsize=12)\n", "\n", "# 2. 꽃의 종류를 구분하지말고 보자.\n", "plt.subplot(122)\n", "plt.scatter(X[:, 2], X[:, 3], c=\"k\", marker=\".\")\n", "plt.xlabel(\"Petal length\", fontsize=14)\n", "plt.tick_params(labelleft=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Gaussian mixture model" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "from sklearn.mixture import GaussianMixture\n", "import numpy as np" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(150, 4)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X.shape" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n", " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n", " 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n", " 2, 2, 0, 2, 0, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2,\n", " 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y_pred = GaussianMixture(n_components=3, random_state=42).fit(X).predict(X)\n", "y_pred" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYYAAAEKCAYAAAAW8vJGAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjAsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+17YcXAAAgAElEQVR4nO3dfZyVdZ3/8ddnYAQUZeJGEETIXUG2UqtJI8rYNSG3xK3Mu6i0/JFpvzTbh674K2/wtlqr3UWJVUR/opYpappsuopEkoaKGiIsTmLcDQNyIwIzw8xn/zjXwDlnrjNznbvr3Mz7+Xich3O+5zrX9TkzMp+5ruv7+X7M3REREelQU+oARESkvCgxiIhICiUGERFJocQgIiIplBhERCRF71IHkK/Bgwf76NGjSx2GiEhFefHFFze7+5Cw1yo+MYwePZqlS5eWOgwRkYpiZmsyvaZLSSIikkKJQUREUigxiIhICiUGERFJUfE3n7uyY8cONm3aRGtra6lD6XFqa2s59NBDOeSQQ0odiohkKbbEYGYjgbuBoYADs93952nbTAQeAf4SDD3k7tfmcrwdO3bQ2NjIiBEj6NevH2aWe/CSFXdn9+7drFu3DkDJQYqmsXEeDQ1X0tz8Nn36HMGRR17P0KFfyeu9+eyzWsR5xrAX+L67v2RmBwMvmtmT7v562na/d/fP53uwTZs2MWLECA488MB8dyVZMjMOPPBARowYwfr165UYpCgaG+excuU02tt3AdDcvIaVK6cBdPuLPNN7t2//Axs33pXTPqtJbPcY3H2Du78UfP0usAIYUazjtba20q9fv2LtXiLo16+fLuNJ0TQ0XLnvF3iH9vZdNDRcmfN716+fnfM+q0lJbj6b2Wjgw8DzIS+PN7NXzOwJM/tAhvdPM7OlZra0qampq+MUIlzJkb7/UkzNzW9nNR5tm7ac91lNYk8MZtYfeBC4xN13pL38EjDK3Y8F/h14OGwf7j7b3evdvX7IkNCKbhGpcn36HJHVeLRteuW8z2oSa2Iws1oSSWGeuz+U/rq773D3ncHXvwVqzWxwnDGWi6uvvpqpU6eWOgyRsnXkkddTU5N6D7Gm5kCOPPL6nN87fPi0nPdZTWJLDJa4rnAHsMLdb8mwzbBgO8zs+CC+LXHFGLd7772X+vp6+vfvz2GHHcYpp5zC4sWLC7b/t956CzNj7969BdsnwLRp0xg7diw1NTXMnTu3oPsWiWro0K8wduxs+vQZBRh9+oxi7NjZkW4SZ3rvmDG35rzPahLnrKQJwFeB18xsWTA2HTgCwN1nAacD3zazvcBu4CwvQVPqOKar3XLLLdx0003MmjWLyZMnc8ABB7BgwQIeeeQRPvnJTxb0WLnau3cvvXt3/l/k2GOP5cwzz+Tyyy8vQVQi+w0d+pWc/21mem8++6wWcc5KWuzu5u7HuPtxweO37j4rSAq4+3+4+wfc/Vh3/7i7PxdXfB06prE1N68BfN90tcbGeQU7xvbt2/nhD3/IzJkz+eIXv8hBBx1EbW0tp556Kj/+8Y87bb9w4UIOP/zwlLHRo0fz1FNPAfDCCy9QX1/PIYccwtChQ7n00ksBOPHEEwGoq6ujf//+LFmyBIA5c+Ywbtw43ve+9zF58mTWrNm/yKKZMXPmTI466iiOOuqo0PgvuugiTjrpJPr27Zv/N0MqXmPjPJYsGc3ChTUsWTK6oP9Wkq1adSELF/Zm4UJj4cLerFp1YVGOI1oSo5N8psBFtWTJEvbs2cMXvvCFguzv4osv5uKLL2bHjh28+eabnHHGGQAsWrQIgG3btrFz507Gjx/PI488wg033MBDDz1EU1MTn/rUpzj77LNT9vfwww/z/PPP8/rr6SUmIqni+EMKEklh/frb2D9rqI31629TcigSJYY0+UyBi2rLli0MHjw49DJNLmpra1m9ejWbN2+mf//+fPzjH8+47axZs7jiiisYN24cvXv3Zvr06SxbtizlrOGKK65g4MCBqgORbsXxhxTA+vWzsxqX/CgxpMlnClxUgwYNYvPmzQW7KXzHHXewatUqjj76aD72sY/x2GOPZdx2zZo1XHzxxdTV1VFXV8fAgQNx933LVwCMHDmyIHFJ9YvjD6mE8PqCzOOSDyWGNPlMgYtq/Pjx9OnTh4cfDi3T6OSggw5i1679f5W1tbWRXNh31FFHcd9997Fp0yYuv/xyTj/9dN57773QArORI0fyi1/8gm3btu177N69m0984hP7tlFhmkQVxx9SCeH1BZnHJR9KDGnymQIX1YABA7j22mu56KKLePjhh9m1axetra088cQTXHbZZZ22HzNmDHv27OHxxx+ntbWV6667jubm5n2v33PPPTQ1NVFTU0NdXR0ANTU1DBkyhJqaGhoaGvZte8EFF3DjjTeyfPlyIHEj/IEHHsgq/paWFvbs2YO709rayp49e2hvb8/lWyEVLo4/pACGD5+W1bjkp6qX3c5VHNPVvv/97zNs2DCuu+46vvKVr3DwwQfz0Y9+lCuv7HxtdsCAAdx6662cf/75tLW1cdlll6XMUlqwYAGXXnopu3btYtSoUdx///377g9ceeWVTJgwgdbWVhYsWMAXvvAFdu7cyVlnncWaNWsYMGAAJ598Ml/+8pcjxz5p0iSeffZZAJ577jmmTZvGM888w8SJE/P7pkjF6fh3Uuzp3WPG3Ap03FNoA3oxfPi0feNSWFaCMoGCqq+v96VLl3YaX7FiBePGjStBRJJMPweR8mRmL7p7fdhrupQkIiIpdClJRPIStlIAdL68FHUsm8tQUVcpyGY1g0po1FPsGJUYRCRnYQ1vVqw4DzPDvWXf2BtvfIPEZevWLrfLpilO1EY92TT0yaf5T1ziiFGXkkQkZ2EFbtC675d9h8Tz9KZNnbfLpjguanFdNkV4cRXs5SOOGJUYRCRnxWhgE3WfUYvrsinCi69gL3dxxKjEICI5K0YDm6j7jFpcl00RXnwFe7mLI0YlBhHJWViBG9RidkDKSOJ5bbfbZVMcF7W4LpsivLgK9vIRR4xKDCKSs7CVAsaNu5Ojj56TMnb00XMYN+7ObrfLZpWBqKsUZLOaQRwrH+QrjhhV4Famrr76alavXs0999xT6lDyUuk/B5FqpQK3MlWJrT1XrVrFaaedxpAhQxg4cCCTJ09m5cqVBdu/SCZRGwLF1Tio0MopbiWGNMOGgVnnx7BhhT3OLbfcwiWXXML06dNpbGzk7bff5sILL+SRRx4p7IHyEJZQtm3bxpQpU1i5ciWNjY0cf/zxnHbaaSWITnqSqA2B4mocVGjlFrcSQ5rGxuzGc1HJrT2PP/54vvnNbzJw4EBqa2v53ve+x8qVK9myZUthvjkiIYpRs1BOyi1uJYYSqKbWnosWLWLYsGEMGjSoIJ9FJEwxahbKSbnFrcRQAtXS2nPt2rVcdNFF3HLLLQX5HCKZFKNmoZyUW9xKDCVQDa09m5qamDRpEhdeeGGnMw6RQitGzUI5Kbe4lRhKoNJbe27dupVJkyYxZcqU0MZCIoVWjJqFclJucWt11TRDh4bfaB46tHDHSG7t2bt3byZNmkRtbS1PPfUUzzzzDD/60Y9Stk9u7Tlp0iRuuOGGTq09J0+ezJAhQzK29hwzZgyQaO35gx/8gOOOO44PfOADbN++nd/97neRO7jt2LGDyZMnM2HCBG666aYCfUdEuhe1s2IcHRiLoZziVmJIs3FjPMep1Nae8+fP509/+hPLly9n7ty5+8Zff/11jjiivK/jSvnJ1Fcgnx4P+fZjiEO5xZNOlc9SVPo5SCbpfQUgcV192LCvs3HjXWnTN2tTejdAYv2l5B4PHe9PvwST6TilulRTLvGo8llEyk6mufvr18/OucdDJdQ2lFs8YZQYRKQkMs/RbyvofsutRqDc4gmjxCAiJZF5jn6vgu633GoEyi2eMEoMIlISmebuDx8+LeceD5VQ21Bu8YRRYhCRksg0d3/MmFtz7vFQCbUN5RZPGM1KkqLSz0GkPHU1Kym2OgYzGwncDQwFHJjt7j9P28aAnwP/COwCznX3l+KKUUT2y6eWIGysnP4iLpZ86hPKqbYhzgK3vcD33f0lMzsYeNHMnnT35CU8TwGOCh4nALcF/xWRGKXPtW9uXsMbb3wjpW4g09iKFeel1Bx09BYAqjo5hH3Pon7ufN5bDLHdY3D3DR1//bv7u8AKYETaZqcBd3vCH4E6MzssrhjLydVXX83UqVNLHYb0UGFz7cPqBsLGwmoOym2efjHkU59QbrUNJbn5bGajgQ8Dz6e9NAL4a9LztXROHpjZNDNbamZLkxeTqzSV2Npz8+bNTJgwgUGDBlFXV8f48eP5wx/+ULD9S3koxpz6cpqnXwz51CeUW21D7InBzPoDDwKXuPuOXPbh7rPdvd7d64cMGVLYAAMb3t3Ap+d+mo07i7N4UqW29uzfvz9z5syhqamJrVu3cvnll3PqqacWNPlI6RVjTn05zdMvhnzqE8qttiHWxGBmtSSSwjx3fyhkk3VAcjOAw4Ox2M1YNIPFby9mxrMzCr7vSm7t2bdvX8aOHUtNTQ3uTq9evdi6dSvvvPNOYb45UhbC5tqH1Q2EjYXVHJTbPP1iyKc+odxqG2JLDMGMozuAFe6eqeXXo8DXLOHjwHZ33xBXjB02vLuBO5fdSbu3c+eyOwt+1lANrT2POeYY+vbty5QpUzj//PM59NBDC/JZpDyEzbUPqxsIGwurOSi3efrFkE99QrnVNsQ5K2kC8FXgNTNbFoxNB44AcPdZwG9JTFVdTWK66nkxxrfPjEUzaPd2ANq8jRnPzmDm52YWbP/FbO05ePDgyK09AaZPn84NN9zAmjVrGDVqFLC/tWdXXn31Vfbs2cP8+fNpaWnpclupTJn6A+QzVu3y6alQTv0Y4pyVtNjdzd2Pcffjgsdv3X1WkBQIZiNd5O5/4+4fcvfOlWtF1nG20NKW+GXX0tZS8LOGamjtCYnLSmeffTY33XQTr7zySt6fQ0TKg5bESJN8ttCh46yhUCq9tWe61tZWGhoasnqPVKbGxnksWTKahQtrWLJkNI2N81i16kIWLuzNwoXGwoW9WbXqwsjvLUeVEmcxKTGkWbJ2yb6zhQ4tbS08t/a5gh0jubXnww8/zK5du2htbeWJJ57gsssu67R9cmvP1tZWrrvuuk6tPZuamqipqcnY2rPDBRdcwI033sjy5cuBxI3wBx54IHLsf/zjH1m8eDEtLS3s3r2bm2++mcbGRk44QXWI1a6jCKu5eQ3gQYHbuaxffxv7l8puY/362zolh7D3rlw5rex+6VZKnMWm1p5pXv7Wy7Ecp1JbezY3N/Pd736XhoYGamtr+dCHPsTjjz/O8OHDC/ONkbIVXvQWfjl0/frEYnhdvbejgKtcrqtD5cRZbFpET4pKP4fqsXBhDYllzqKZOHH/tpnfa0yc2B4yXhqVEmchqLWniOQtu2Kr1GY75VbAlUmlxFlsSgwiEkl40Vv41ejhw6d1+95yLHqrlDiLTYlBRCIJL3qby/Dh32b/GUIvhg//dsr9hUzvLceit0qJs9h0j0GKSj8HkfJUFo16SqG9vZ2aGp0UlUp7e3XdrKtWy5Z9hm3b/nvf87q6kzjuuKdYtepC1q+fTWIqai+GD5/W6UwAitNgJuzYAwZMiHScqPHkG3c5NdYptKo9Y3j77bcxM4YOHUptbW3WRVuSO3entbWVxsZG3J0jjuhZN+4qSXpS6FBbO5zW1vWdxtMvE6U3mIHENfl8Lr8kksJtIa/UAPv/2Ag7TtR48o27GJ87bl2dMVRtYmhvb2fz5s1s375dS0KXQO/evRkwYACDBw/WWVsZW7gw2z+YejFx4v5/T0uWjA6KwVL16TOK8ePfyjGm3uwvmOta+nGixpNv3MX43HHrkZeSampqOPTQQ7Xqp0hBpf7CLk6DmWhJIew4UePJN+5ya6xTaPpTTkSyEEd9Qq/uN8lwnKjx5Bt3tdc7KDGI9GB1dSeFjtfWhi9xEkd9Qvoxkvbc7XGixpNv3NVe76DEINKDHXfcU52SQ13dSUyYsK5k9Qljxtwaeuxx4+7u9jhR48k37mqvd4h889nMDgSOAw4lLaFkaNMZi0w3n0VEJLO8bz6b2WeA+4BBIS872VwUFJGCi2tOfTXP3Zf9ol5K+jnwOHC4u9ekPZQUREoorh4C6lXQc0RNDKOBGe7eueJFREqqqx4ClXgcKb2oieEPwNhiBiIiuYlrTn21z92X/TLeYzCzjyQ9nQX8xMyGA68BrcnbuvtLxQlPRLrTp88RGapwCzunPq7jSOl1dfN5KYkby8k187NDttPNZ5ESOvLI60PX7Sn0nPq4jiOl11VieH9sUYhIzjpmBRV7tlBcx5HSi1THYGYnAs95WudvS7Rv+oS7LypSfN1SHYOISPYK0fP5GWBgyPiA4DURKbEN727g03M/zcadGwuyXVSNjfNYsmQ0CxfWsGTJ6JJPXy23eCpR1MRgJO4lpBsEvFe4cEQkVzMWzWDx24uZ8eyMgmwXRbnVNpRbPJWqy0tJZvZo8OXngKeA5qSXewEfBFa4+2eLFmE3dClJJHEWcOS/HcmevXvo17sfDRc3MKz/sJy3i6rc+hKUWzzlLJ9LSVuChwFbk55vAdaSmMY6tXChikguZiyaQbsnupu1eVvGs4Go20VVbrUN5RZPpeoyMbj7ee5+HnAN8M2O58HjW+5+o7tvjidUEQmz4d0N3LnsTlraWgBoaWvhzmV3drqHEHW7bJRbX4Jyi6dSRbrH4O7XuLvuJYiUoeSzgA5hZwNRt8tGufUlKLd4KlVXlc9/IfyGcyfufmTBIhKRrCxZu2TfWUCHlrYWnlv7XE7bZaPcahvKLZ5KlfHms5l9P+lpf+BS4AVgSTA2Hjge+Fd3v7aYQXZFN59FRLKXUz8Gd//XpB3MBW529xvSdnwF8IGIQcwBPg9scvcPhrw+EXgE+Esw9FApE46ISE8VtY7hi8CvQsYfAKZE3MdcoLtprb939+OCh5KC9Cj5FJ41Ns7j2ocGYdcY188fvG/eftg+ox6nsXEev1l4OMf+zHhs4UgaG+eFFo+poKz6RE0M7wETQ8YnArtCxjsJls14J+LxRHqcXAvPOoq6ZryW+Od19atb9hV1he0zynE69nn7qnW8th1u/5+1rFhxHm+88Y2U4rGwMRWUVb6oieGnwEwzm2Vm5waPWcC/B68Vyngze8XMnjCzSJeoRKpBx1TSdm/PegppQ8OVPLVhFx0Lme0Fnt64ixdWXN5pn1GP09BwJU27d7GgMTEDZcFGeKelFfeWtC07j6l5T+WLOl31R8BXgQ8BtwSPDwFfd/ebCxTLS8Aodz+WRMJ5ONOGZjbNzJaa2dKmpqYCHV6kdPIpPGtufpsb30gdu34F3L5qXad9Rj1Oc/Pb3L0G2oO5KW0Od3cuKO4yJqlckVZXLdjBzEYDj4XdfA7Z9i2gvrsCOs1KkkqXvExFh2yWq7j2oUFc9Vrnq7S9gLak53179QVgT1v3x/nNwsM5/ffraEkqe+hTA/eeAAMP6P4zaQmK8leI1VWLzsyGmZkFXx9PIrYtpY1KpPjyLTy7fvmO0PG2tOctbS20tKde9sl0nAebjib9b8bEWUP6r4xazFIzhQrKKl9XBW47gCPdfbOZvUsXxW7ufkh3BzKz+0jcrB5sZmuBq4Da4P2zgNOBb5vZXmA3cJbHeTojUiL5Fp61tO/tfiOgnfZO/4ozHeeVd7bQmrbtXofVzSPp04eU4jFQQVm16arA7evA/e7ebGbn0nViuKs44XVPl5JERLKX06Ukd7/L3ZuDr+cGz0MfxQpcpNIUuglOJss2LKPupjpebXw163jC3htX3PlQvUR8It1jMLPpZjY+aOUpIhkUsglOV6bOn8r25u2c8+A5WccT9t644s6VGvDEK+rN51NItPDcama/CxLFJ5QoRPbLpxYhG8s2LGN503IAljctz3jWEBZP2HvjijsfDQ1X0t6eWkureoniiVrH8CngfcAXgOdJJIr/JpEo/qt44YlUjkI3wclk6vzU3liZzhrC4gl7b1xx50MNeOKVdR2DmQ0F/oFEu88zgL3ufmDX7yoe3XyWcpBvLUJUyzYs48OzP9xp/JULXuGYocd0GU+fXn1obmvu9N708WLEnS+17Cy8vOsYzOwMM7vVzFYADcD/Af4HOJnEmYRIj1aMJjhh0v/i75B+1hAWT1hSCBsvx7MGNeCJV9R7BPcDTcBPgJnuHmnhPJGeohhNcMK8ufXNSONh8URVjLjzpQY88Yp0KcnMzgc+HTwOAX4PLCRxQ/rlUhai6VKSiEj28r6U5O63u/tX3f0I4KMkFrj7GIlubl2uZSRSaQo9p//JN5+k97W9efovT+8bC6slyFSbELXuIJ/eCyLJIq+VZGY1ZnYCiaUrziDRjc2AVUWKTaQkCj2n/8xfn0mbt3H6r07fNxZWS5CpNiFq3UGuvRdE0kW9+fwEsJXEJaR/IrFE9peA97n7+OKFJxKvQs/pf/LNJ9m6ZysAW/ds5em/PB1aS5CpNiFq3UHUMZEoot58Xgb8DFjs7u8VMR6Rkgqb0z/zczNz3t+Zvz4z5fnpvzqd4QcPTxkLq0M458Fz+POFfw6tOzhx1ImdYnQ80lg+n0V6jlj7MRSDbj5LoRS6FuHJN59k0j2Tco7nl1/6JWc+eGan8T41fWhu3z/FtG/vvrh7yrTTbHovSM9UEf0YREqt0LUI6WcL2frqw18NHU9OCpCYXtra1tppLGrvBZF0WutIJFDoWoRte7blFU/UOoT0ZAbZ9V4QSafEIBJ4+VsvF3R/7Vd1/oUtUgl0KUmkgPKpJcim5iCf+gTVNkh3lBhECiifWoJsag7yqU9QbYN0p6vWnl32eU4WpedzsWhWkpSL5FlNHTOA3L3TWNisoLD3Zpo9lM22hXyvVJeuZiV1dY/hO0WKR6QqhdVARK0lyKZ+Ip9ai0LXaUh1Uh2DSAGE1UBErSXIpn4in1qLuHpGSGVQHYNIkYXVQEStJcimfiKfWou4ekZI5Yu6VtIBZnaNma0ysz1m1pb8KHaQIuUurAainfbQZJFeS5BN/UQ+tRZx9YyQyhe1H8PNwJnAjcBPgf8HjAbOAn7g7r8oYoxd0qUkEZHsFeJS0hnABUECaAMecffvAleRaO8pIiJVImpiGAq8Hny9E6gLvl4A5L5KmEgGlVCEpcY4Uq2iJoa3gY61glcDk4OvxwO7Cx2USCUUYakxjlSrqIlhPnBS8PXPgWvM7C/AXOD2IsQlPVglNJhRYxypZpEW0XP3K5K+/rWZ/RWYAKxy98eKFZz0TJVQhJVPMZtIuYs6K+lE4Dl335s23hv4hLsvKlJ83dKspOpSCUVYocVsIc1yyi1ukWSFmJX0DDAwZHxA8JpIQVRCEVamYrb0ZjnlFrdIVFH7MRjhC+oNAtQDWgqmEoqwQovZQprllFvcIlF1mRjM7NHgSwfuMbPknoK9gA8C+j9fCqbQzXKKoRJiFMlHd5eStgQPA7YmPd8CrAVmAVOjHMjM5pjZJjP7c4bXzcz+zcxWm9mrZvaRqB9CJNmyDcuou6mOVxtfLch2UPjGOKp3kHLWZWJw9/Pc/TzgGuCbHc+Dx7fc/UZ33xzxWHOBz3bx+inAUcFjGnBbxP2KpJg6fyrbm7dzzoPnFGQ7KHxjHNU7SDmLdPPZ3a9x9/fMrN7MzjSzgwDM7KBgZlKUfSwC3ulik9OAuz3hj0CdmR0WZd8iHZZtWMbypuUALG9anvFsIOp2kF9dheodpBJFXV11qJn9EXgBuJfEEhkAtwD/WqBYRgB/TXq+NhgLi2eamS01s6VNTU0FOrxUg6nzU69sZjobiLodhNcsRBX23nz2JxKHqNNVfwo0kpiFtCtp/AFKsFaSu89293p3rx8yZEjch5cylXwW0CHsbCDqdrD/L/6OWUgtbS2R/8oPe++cl+dw58u57U8kLlETw0nAle6+NW38TeCIAsWyDhiZ9PzwYEwkkvSzgA7pZwNRt4PCN8aJ2rxHpJSiJoZ+QEvI+BBgT8h4Lh4FvhbMTvo4sN3dNxRo39IDvLn1zUjjUbeDwjfGidq8R6SUoi6J8RjwqrtPN7N3gWNIrLj6K6DN3c+IsI/7gInAYBKXpa4CagHcfZaZGfAfJGYu7QLOc/du17rQkhgiItnrakmMqJXPlwHPmtnHgD4kbjh/gMSSGBOi7MDdz+7mdQcuihiPiIgUSdTpqq+TOEtYAvwO6EvixvOH3T38vFxERCpS1DMGguv9PyxiLCIiUga6PGMwswPNbKaZrQuWs7jXzAbHFZyIiMSvu0tJ1wDnAo8D9wMno6UqRESqWneXkr5IYo2k+wHM7B7gD2bWy93bih6diIjErrszhpHA7zueuPsLwF5geDGDEhGR0ukuMfSic2HbXrK4aS0iIpWlu1/wRucGPX2B/zSzfWsmufuUYgQnIiLx6y4x3BUydk8xAhERkfLQZWIImvSIiEgPEnURPRER6SGUGEREJIUSg4iIpFBiEBGRFEoMIiKSQolBRERSKDGIiEgKJQYREUmhxCAiIimUGEREJIUSg4iIpFBiEBGRFEoMIiKSQolBRERSKDHEaNgwMOv8GDas1JGJiOynxBCjxsbsxkVESkGJQUREUigxiIhICiUGERFJocQgIiIplBhiNHRoduMiIqXQu9QB9CQbN5Y6AhGR7sV6xmBmnzWzlWa22sz+JeT1c82sycyWBY/z44yvVFTfICLlJLYzBjPrBcwETgbWAn8ys0fd/fW0TX/p7t+JK65yoPoGESkncZ4xHA+sdvcGd28B7gdOi/H4IiISQZyJYQTw16Tna4OxdF8ys1fN7NdmNjJsR2Y2zcyWmtnSpqamYsQqItJjlduspN8Ao939GOBJ4K6wjdx9trvXu3v9kCFDYg1QRKTaxZkY1gHJZwCHB2P7uPsWd28Ont4OfDSm2EREJBBnYvgTcJSZvd/MDgDOAh5N3sDMDkt6OgVYEWN8JaP6BhEpJ7HNSnL3vWb2HeC/gF7AHHdfbmbXAkvd/VHgu2Y2BdgLvAOcG1d8paT6BhEpJ+bupY4hL/X19b506dLYjvHok0wAAAm2SURBVDdsWPg00qFDU3/Bm0XfZ00NtLd3v8+oxxYR6Y6Zveju9WGvldvN57JXjJqDsKQQtk/VO4hIHJQYREQkhRKDiIikUGIQEZEUSgwiIpJCiSFLxag5qMnwU0jfp+odRCQO6seQpajTQosxC1hTUkUkDjpjyFKvXuG9E6I+wnosqB+DiJQTJYYsZao5iCqs5kD1CSJSTpQYREQkhRKDiIikUGIQEZEUSgwiIpJCiSFLmWoOogqrOVB9goiUE9UxZKmtrfD7VH2CiJQTnTGIiEiKHpcYsikmy7eYLd9HekwqhBOROPS4xJBNMVm+xWz5UqMeESmFHpcYRESka0oMIiKSQolBRERSKDGIiEiKHpcYsikmy7eYLV9q1CMipdDjCtyyKSYrRjFbPlQIJyJx6HFnDJnkUyOQ6b2ZHiIi5UyJIZBPjYDqCESkmigxiIhICiUGERFJocQgIiIplBhERCSFEkMgnxoB1RGISDXpcXUMmeRTI6D6AhGpJrGeMZjZZ81spZmtNrN/CXm9j5n9Mnj9eTMbHWd8IiISY2Iws17ATOAU4O+As83s79I2+yaw1d3/FvgpcHNc8YmISEKcZwzHA6vdvcHdW4D7gdPStjkNuCv4+tfASWaqFRYRiVOciWEE8Nek52uDsdBt3H0vsB0YlL4jM5tmZkvNbGlTU1ORwhUR6ZkqclaSu89293p3rx8yZEipwxERqSpxzkpaB4xMen54MBa2zVoz6w0MALZ0tdMXX3xxs5mtyTGmwcDmHN9bjvR5ylc1fRaors9TTZ8Fon+eUZleiDMx/Ak4yszeTyIBnAWck7bNo8DXgSXA6cDT7u5d7dTdcz5lMLOl7l6f6/vLjT5P+aqmzwLV9Xmq6bNAYT5PbInB3fea2XeA/wJ6AXPcfbmZXQssdfdHgTuA/29mq4F3SCQPERGJUawFbu7+W+C3aWM/TPp6D/DlOGMSEZFUFXnzuYBmlzqAAtPnKV/V9Fmguj5PNX0WKMDnsW4u4YuISA/T088YREQkjRKDiIik6JGJwczmmNkmM/tzqWMpBDMbaWbPmNnrZrbczC4udUy5MrO+ZvaCmb0SfJZrSh1Tvsysl5m9bGaPlTqWfJnZW2b2mpktM7OlpY4nX2ZWZ2a/NrM3zGyFmY0vdUy5MrOxwc+l47HDzC7JaV898R6DmZ0I7ATudvcPljqefJnZYcBh7v6SmR0MvAj8k7u/XuLQshasjXWQu+80s1pgMXCxu/+xxKHlzMwuBeqBQ9z986WOJx9m9hZQ7+5VURBmZncBv3f3283sAOBAd99W6rjyFSxaug44wd2zLgDukWcM7r6IRJ1EVXD3De7+UvD1u8AKOq9DVRE8YWfwtDZ4VOxfL2Z2OPA54PZSxyKpzGwAcCKJ+incvaUakkLgJODNXJIC9NDEUM2CHhYfBp4vbSS5Cy69LAM2AU+6e8V+FuBnwGVAe6kDKRAHfmdmL5rZtFIHk6f3A03AncGlvtvN7KBSB1UgZwH35fpmJYYqYmb9gQeBS9x9R6njyZW7t7n7cSTW0zrezCrycp+ZfR7Y5O4vljqWAvqku3+ERF+Vi4LLspWqN/AR4DZ3/zDwHtCpgVilCS6JTQEeyHUfSgxVIrge/yAwz90fKnU8hRCc1j8DfLbUseRoAjAluC5/P/APZnZPaUPKj7uvC/67CZhPos9KpVoLrE06I/01iURR6U4BXnL3xlx3oMRQBYIbtncAK9z9llLHkw8zG2JmdcHX/YCTgTdKG1Vu3P0Kdz/c3UeTOLV/2t2nljisnJnZQcHkBoJLLpOAip3Z5+4bgb+a2dhg6CSg4iZshDibPC4jQcxrJZULM7sPmAgMNrO1wFXufkdpo8rLBOCrwGvBtXmA6cHaVJXmMOCuYFZFDfArd6/4aZ5VYigwP2iq2Bu4190XlDakvP1fYF5w+aUBOK/E8eQlSNgnA9/Kaz89cbqqiIhkpktJIiKSQolBRERSKDGIiEgKJQYREUmhxCAiIimUGESyZGbnmtnObrZ5y8z+Oa6YumJmo83MzaxqGt5LcSkxSEUys7nBLzs3s1YzazCzn2Sz1k2wj6qqkajGzyTx65EFblI1niJR2FcLfIrECqYHAd8uZVAilU5nDFLJmt19o7v/1d3vBeYB/9Txopn9nZk9bmbvBo2Z7jOzYcFrVwNfBz6XdOYxMXjtJjNbaWa7g0tCPzKzvvkEamYDzGx2EMe7ZvZs8qWdjstTZnaSmf3ZzN4Lmi+9P20/V5hZY7Dt3WZ2VbAWU5efKTDKzJ40s12WaOp0cj6fSaqXEoNUk90kzh46mhctIrGWz/HAZ4D+wCNmVgP8BPgVibOOw4LHc8F+3gO+AYwDLiSxztGVuQYVrGX1OIkeGZ8nsSz6IuDpIM4OfYArgmOPB+qAWUn7OQu4KojlIyT6blya9P6uPhPA9cC/AccCfwLuD1bkFUmhS0lSFczseOAc4L+DoW8Dr7j75UnbfI1Eg6Z6d3/BzHYTnHUk78vdZyQ9fcvMbgD+GfhBjuH9PXAcMMTddwdjPzCzU0lcCvtRMNYbuMjdVwbx/gSYY2bmibVrLgbmuntH058bzezvgTFB3DvDPlOwthHAT939N8HYdOBrQVyLc/xcUqWUGKSSfTaYHdSbxJnCIyQWRQP4KHBihtlDfwO8kGmnZnY6cAnwtyTOMnoFj1x9FDgQaEr6JQ3QN4ilQ3NHUgisBw4A3kcioR0N/Gfavp8nSAwRvJq2b4BDI75XehAlBqlki4BpQCuw3t1bk16rIXH5JmzKaMZ16s3s4yR6J1wDfA/YRqLpyU/yiLMmOOanQl5Lbqi0N+21jhUuC3XJd9/3x909SFK6nCydKDFIJdvl7qszvPYScAawJi1hJGuh85nABGBd8uUkMxuVZ5wvkViyut3dG/LYzxvAx4A5SWPpjXLCPpNIVvTXglSrmcAA4JdmdoKZHWlmnwlmBh0cbPMW8EEzG2tmg4MueKuAEWb2leA93ybR+CQfTwF/IHHj+xQze7+ZjTeza8ws7Cwik58D55rZN8zsKDO7DDiB/WcWmT6TSFaUGKQquft6En/9twMLgOUkkkVz8IDE9foVwFISTeEnBDdnfwz8jMQ1+ZOBH+YZiwP/CDwdHHMlidlDY9l/rT/Kfu4HZgA3AS8DHyQxa2lP0madPlM+sUvPpEY9IhXMzOYDvd391FLHItVD9xhEKoSZHUhiGu4CEjeqvwScFvxXpGB0xiBSIcysH/AbEgVy/YD/AW4Oqr5FCkaJQUREUujms4iIpFBiEBGRFEoMIiKSQolBRERSKDGIiEiK/wU8d9wyab3vegAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.plot(X[y_pred==0, 2], X[y_pred==0, 3], \"yo\", label=\"Cluster 1\")\n", "plt.plot(X[y_pred==1, 2], X[y_pred==1, 3], \"bs\", label=\"Cluster 2\")\n", "plt.plot(X[y_pred==2, 2], X[y_pred==2, 3], \"g^\", label=\"Cluster 3\")\n", "plt.xlabel(\"Petal length\", fontsize=14)\n", "plt.ylabel(\"Petal width\", fontsize=14)\n", "plt.legend(loc=\"best\", fontsize=12)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "정확도를 살펴보자. Plot 정보를 살펴보면 알겠지만, 원래 클래스 `2, 0, 1`이 `0, 1, 2`로 바꼈다." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "y_pred = [[2, 0, 1][i] for i in y_pred]" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "145" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sum(y_pred==y)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9666666666666667" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sum(y_pred==y) / len(y_pred)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Using Clustering for Preprocessing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. 데이터 셋 로딩" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "from sklearn.datasets import load_digits" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "X_digits, y_digits = load_digits(return_X_y=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. 학습셋 / 테스트셋 구분" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import train_test_split" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "X_train, X_test, y_train, y_test = train_test_split(X_digits, y_digits, random_state=42)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. 학습" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### (1) 데이터 전처리 없이 학습" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [], "source": [ "from sklearn.linear_model import LogisticRegression" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n", " intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,\n", " penalty='l2', random_state=42, solver='liblinear', tol=0.0001,\n", " verbose=0, warm_start=False)" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "log_reg = LogisticRegression(multi_class=\"ovr\", solver=\"liblinear\", random_state=42)\n", "log_reg.fit(X_train, y_train)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9666666666666667" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "log_reg.score(X_test, y_test)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### (2) K-Means를 이용하여 데이터 전처리 후 학습" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [], "source": [ "from sklearn.pipeline import Pipeline" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Pipeline(memory=None,\n", " steps=[('kmeans', KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,\n", " n_clusters=50, n_init=10, n_jobs=1, precompute_distances='auto',\n", " random_state=42, tol=0.0001, verbose=0)), ('log_reg', LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n", " intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,\n", " penalty='l2', random_state=42, solver='liblinear', tol=0.0001,\n", " verbose=0, warm_start=False))])" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pipeline = Pipeline([\n", " (\"kmeans\", KMeans(n_clusters=50, random_state=42)),\n", " (\"log_reg\", LogisticRegression(multi_class=\"ovr\", solver=\"liblinear\", random_state=42)),\n", "])\n", "pipeline.fit(X_train, y_train)" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9822222222222222" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pipeline.score(X_test, y_test)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Grid search를 이용하여 최상의 $k$를 찾자." ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import GridSearchCV" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "GridSearchCV(cv=3, error_score='raise',\n", " estimator=Pipeline(memory=None,\n", " steps=[('kmeans', KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,\n", " n_clusters=50, n_init=10, n_jobs=1, precompute_distances='auto',\n", " random_state=42, tol=0.0001, verbose=0)), ('log_reg', LogisticRegression(C=1.0, class_weight=None, dua...lty='l2', random_state=42, solver='liblinear', tol=0.0001,\n", " verbose=0, warm_start=False))]),\n", " fit_params=None, iid=True, n_jobs=1,\n", " param_grid={'kmeans__n_clusters': range(2, 100)},\n", " pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',\n", " scoring=None, verbose=0)" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "param_grid = dict(kmeans__n_clusters=range(2, 100))\n", "grid_clf = GridSearchCV(pipeline, param_grid, cv=3, verbose=0)\n", "grid_clf.fit(X_train, y_train)" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'kmeans__n_clusters': 90}" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid_clf.best_params_" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9844444444444445" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grid_clf.score(X_test, y_test)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$k=90$일 때, 성능이 근소하게나마 상승했다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Clustering for Semi-supervised Learning" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "다수의 unlabeled instances와 매우 적은 labeled instances를 가지고 있을 때, semi-supervised learning을 clustering을 이용하여 수행할 수 있습니다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(1) 데이터는 아까의 image 데이터이며, 50개의 instance에 대해서만 label을 가지고 있다고 가정하겠습니다." ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [], "source": [ "n_labeled = 50" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.8266666666666667" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "log_reg = LogisticRegression(multi_class=\"ovr\", solver=\"liblinear\", random_state=42)\n", "log_reg.fit(X_train[:n_labeled], y_train[:n_labeled])\n", "log_reg.score(X_test, y_test)" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [], "source": [ "k = 50" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(2) Unlabeled + labeled data에서 clustering을 수행합니다." ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[31.33905994, 41.96889871, 39.35726202, ..., 52.16098656,\n", " 43.01099731, 47.0563954 ],\n", " [55.92396284, 43.71133883, 54.31262046, ..., 42.91000488,\n", " 43.32075513, 47.61348001],\n", " [42.70646977, 41.11611364, 18.08113402, ..., 46.43384382,\n", " 43.07657195, 51.59794401],\n", " ...,\n", " [52.03749979, 35.45795409, 47.95964353, ..., 39.43266647,\n", " 43.96234554, 36.1470427 ],\n", " [31.697396 , 34.37452504, 41.17381404, ..., 44.60183936,\n", " 39.03981532, 36.47989321],\n", " [43.72529456, 43.97780117, 47.90725608, ..., 53.60184146,\n", " 18.23619458, 26.30919826]])" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "kmeans = KMeans(n_clusters=k, random_state=42)\n", "X_digits_dist = kmeans.fit_transform(X_train)\n", "X_digits_dist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(3) 각 cluster의 centroid에 대하여 가장 가까운 images를 찾습니다." ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 911, 559, 23, 159, 736, 1056, 776, 795, 753, 598, 737,\n", " 683, 1194, 602, 817, 1284, 73, 702, 94, 891, 805, 1071,\n", " 1314, 1022, 1050, 525, 588, 481, 1005, 766, 848, 731, 749,\n", " 1322, 1336, 705, 1151, 494, 357, 459, 843, 850, 151, 256,\n", " 576, 460, 596, 648, 841, 214])" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "representative_digit_idx = np.argmin(X_digits_dist, axis=0)\n", "representative_digit_idx" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0., 0., 0., ..., 0., 0., 0.],\n", " [ 0., 0., 2., ..., 14., 2., 0.],\n", " [ 0., 0., 4., ..., 6., 0., 0.],\n", " ...,\n", " [ 0., 0., 4., ..., 9., 1., 0.],\n", " [ 0., 0., 6., ..., 3., 0., 0.],\n", " [ 0., 0., 1., ..., 9., 0., 0.]])" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X_representative_digits = X_train[representative_digit_idx]\n", "# 각 centroid와 가장 가깝기 때문에, 각 cluster를 대표하는 image입니다.\n", "X_representative_digits" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(4) 해당 images에 대하여 직접 라벨링을 합니다." ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(8, 2))\n", "for index, X_representative_digit in enumerate(X_representative_digits):\n", " plt.subplot(k // 10, 10, index + 1)\n", " plt.imshow(X_representative_digit.reshape(8, 8), cmap=\"binary\", interpolation=\"bilinear\")\n", " plt.axis('off')" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [], "source": [ "y_representative_digits = np.array([\n", " 4, 8, 0, 6, 8, 3, 7, 7, 9, 2,\n", " 5, 5, 8, 5, 2, 1, 2, 9, 6, 1,\n", " 1, 6, 9, 0, 8, 3, 0, 7, 4, 1,\n", " 6, 5, 2, 4, 1, 8, 6, 3, 9, 2,\n", " 4, 2, 9, 4, 7, 6, 2, 3, 1, 1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(5) 해당 이미지를 이용하여 학습을 합니다." ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9244444444444444" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "log_reg = LogisticRegression(multi_class=\"ovr\", solver=\"liblinear\", random_state=42)\n", "log_reg.fit(X_representative_digits, y_representative_digits)\n", "log_reg.score(X_test, y_test)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(6) 만약에, 50개의 데이터를 이용하여, 같은 클러스터에 속하는 데이터에 라벨을 할당하면?" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [], "source": [ "y_train_propagated = np.empty(len(X_train), dtype=np.int32)\n", "for i in range(k):\n", " y_train_propagated[kmeans.labels_==i] = y_representative_digits[i]" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n", " intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,\n", " penalty='l2', random_state=42, solver='liblinear', tol=0.0001,\n", " verbose=0, warm_start=False)" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "log_reg = LogisticRegression(multi_class=\"ovr\", solver=\"liblinear\", random_state=42)\n", "log_reg.fit(X_train, y_train_propagated)" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9288888888888889" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "log_reg.score(X_test, y_test)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Outlier에 취약하다. 따라서 성능의 큰 발전이 있지는 않다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(7) 만약에 같은 클러스터에 속하는 데이터 전체에 라벨을 할당하는 것이 아니라, centroid에 가까운 데이터에 대해서만 라벨을 할당하면?" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(1347,)\n" ] }, { "data": { "text/plain": [ "array([30.3917992 , 20.3734662 , 15.08582969, ..., 19.36276495,\n", " 19.5626378 , 18.23619458])" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 각 instance에서 가장 가까운 클러스터까지의 거리를 가지고 옵니다.\n", "X_cluster_dist = X_digits_dist[np.arange(len(X_train)), kmeans.labels_]\n", "\n", "print(X_cluster_dist.shape)\n", "X_cluster_dist" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [], "source": [ "percentile_closest = 20\n", "\n", "for i in range(k):\n", " # 클러스터에 해당하는 데이터만 불러옵니다.\n", " in_cluster = (kmeans.labels_ == i)\n", " cluster_dist = X_cluster_dist[in_cluster]\n", " # cluster내에서 상위 20퍼센트에 해당하는 거리(cutoff_distance) 찾습니다.\n", " cutoff_distance = np.percentile(cluster_dist, percentile_closest)\n", " # 임계치보다 큰 거리는 -1로 바꿉니다.\n", " above_cutoff = (X_cluster_dist > cutoff_distance)\n", " X_cluster_dist[in_cluster & above_cutoff] = -1" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [], "source": [ "partially_propagated = (X_cluster_dist != -1)\n", "# X_train은 이전 예제에서 클러스터에 할당된 데이터들에 대해 클러스터가 부여되었습니다. 그 중에서 상위 20%만 선택합니다.\n", "X_train_partially_propagated = X_train[partially_propagated]\n", "y_train_partially_propagated = y_train_propagated[partially_propagated]" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n", " intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,\n", " penalty='l2', random_state=42, solver='liblinear', tol=0.0001,\n", " verbose=0, warm_start=False)" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "log_reg = LogisticRegression(multi_class=\"ovr\", solver=\"liblinear\", random_state=42)\n", "log_reg.fit(X_train_partially_propagated, y_train_partially_propagated)" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9422222222222222" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "log_reg.score(X_test, y_test)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "상위 20%에 할당된 라벨의 accuracy는 상당히 높다." ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9896907216494846" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.mean(y_train_partially_propagated == y_train[partially_propagated])" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.7" } }, "nbformat": 4, "nbformat_minor": 2 }