├── 1장
├── 1.3 넘파이.ipynb
├── 1.4 데이터 핸들링 - 판다스.ipynb
└── titanic
│ ├── aggregate_clicks.txt
│ ├── gender_submission.csv
│ ├── test.csv
│ └── train.csv
├── 2장
├── 2.2 첫 번째 머신러닝 만들어 보기 _ 붓꽃 품종 예측하기.ipynb
├── 2.3 사이킷런의 내장 예제 데이터.ipynb
├── 2.4 Model Selection 모듈 소개.ipynb
├── 2.5 데이터_전처리.ipynb
└── 2.6 사이킷런으로 수행하는 타이타닉 생존자 예측 .ipynb
├── 3장
├── 3.1정확도(Accuracy) ~ 3-5_ROC_AUC까지 예제.ipynb
└── 3.6 피마 인디언 당뇨병 예측.ipynb
├── 4장
├── 4.10_ 분류실습_신용카드_사기검출.ipynb
├── 4.11_스태킹앙상블.ipynb
├── 4.2_결정트리.ipynb
├── 4.3_앙상블학습_4.4_랜덤포레스트_4.5_GBM.ipynb
├── 4.6_XGBoost(eXtra Gradient Boost).ipynb
├── 4.7_LightGBM.ipynb
├── 4.8_베이지안_최적화로_hyperparameter_튜닝.ipynb
├── 4.9_ 분류실습_산탄데르_고객만족예측.ipynb
└── feature_selection_basic.ipynb
├── 5장
├── 5.10 Regression 실습 - Kaggle House Price.ipynb
├── 5.3_Gradient_Descent_5.4_LinearModel_5.5_Polynomial_5.6_Regularized_model.ipynb
├── 5.7_로지스틱 회귀_5.8_회귀 트리.ipynb
└── 5.9 Regression실습-Bike Sharing Demand.ipynb
├── 6장
├── 6-2_PCA.ipynb
├── 6-3_LDA(Linear Discriminant Analysis).ipynb
└── 6-4_6_5_SVD & NMF.ipynb
├── 7장
├── 7-1_KMeans.ipynb
├── 7-2_Cluster evaluation.ipynb
├── 7-3 Mean_Shift.ipynb
├── 7-4_Gaussian_Mixture_Model.ipynb
├── 7-5_DBSCAN.ipynb
└── 7-6_Clustering_Practice_Customer_Segmentation.ipynb
├── 8장
├── 8.10 Text Analysis 실습 _ 캐글 Mercari Price Suggestion Challenge_kaggle용.ipynb
├── 8.10 Text Analysis 실습 _ 캐글 Mercari Price Suggestion Challenge_local용.ipynb
├── 8.2 텍스트 사전 준비 작업(텍스트 전처리) - 텍스트 정규화_8.3 Bag of Words _ BOW.ipynb
├── 8.4 텍스트 분류 실습 _ 20 뉴스그룹 분류.ipynb
├── 8.5 감성 분석.ipynb
├── 8.6 토픽 모델링(Topic Modeling) - 20 뉴스그룹.ipynb
├── 8.7 문서 군집화 소개와 실습(Opinion Review 데이터 세트).ipynb
├── 8.8 문서 유사도 .ipynb
└── 8.9 한글 텍스트 처리 _ 네이버 영화 평점 감성 분석.ipynb
├── 9장
├── 9.1 컨텐츠 기반 필터링 실습 _ TMDB 5000 Movie Dataset.ipynb
├── 9.2 아이템 기반 인접 이웃 협업 필터링 실습.ipynb
├── 9.3 잠재 요인 기반 협업 필터링 실습.ipynb
└── 9.4 파이썬 추천 시스템 패키지 Surprise 실습.ipynb
└── Visual
├── Visualization_Matplotlib.ipynb
├── Visualization_Seaborn.ipynb
└── titanic_train.csv
/1장/titanic/aggregate_clicks.txt:
--------------------------------------------------------------------------------
1 | sessionid productname pagetype clicktime referrer productprice
2 | 1 sneakers home 2009-07-29 20:17 Company1 100
3 | 1 sneakers page1 2009-07-29 20:18 Company1 100
4 | 1 sneakers page1 2009-07-29 20:23 Company1 100
5 | 1 sneakers page2 2009-07-29 20:30 Company1 100
6 | 1 desk home 2009-07-29 20:40 Company2 200
7 | 1 desk page3 2009-07-29 20:55 Company2 200
8 | 2 books home 2009-04-21 13:17 Company4 300
9 | 2 books page1 2009-04-21 13:21 Company4 300
10 | 2 books page1 2009-04-21 13:25 Company4 300
11 | 2 Appliances home 2009-04-21 13:40 Company6 1500
12 | 3 television home 2009-05-23 14:17 Company2 500
13 | 3 television home 2009-05-23 14:27 Company2 500
14 | 3 television page1 2009-05-23 14:32 Company2 500
15 | 3 television page3 2009-05-23 14:47 Company2 500
16 | 3 television checkout 2009-05-23 15:05 Company2 500
17 | 4 envelopes home1 2009-07-16 11:17 Company3 10
18 | 4 envelopes page1 2009-07-16 11:18 Company3 10
19 | 4 envelopes page1 2009-07-16 11:20 Company3 10
20 | 4 chairs page2 2009-07-16 11:37 Company3 400
21 | 4 chairs page3 2009-07-16 11:39 Company3 400
22 | 4 chairs checkout 2009-07-16 11:41 Company3 400
23 | 4 chairs page3 2009-07-16 11:45 Company3 400
24 | 4 chairs home 2009-07-16 11:48 Company3 400
25 | 5 bookcases home 2009-08-19 22:17 Company5 150
26 | 5 bookcases page1 2009-08-19 22:19 Company5 150
27 | 5 bookcases page1 2009-08-19 22:22 Company5 150
28 | 5 bookcases checkout 2009-08-19 22:24 Company5 150
29 | 5 bookcases page2 2009-08-19 22:28 Company5 150
30 | 5 bookcases page2 2009-08-19 22:29 Company5 150
31 | 5 bookcases page2 2009-08-19 22:32 Company5 150
32 | 6 cellphones home 2009-08-24 14:30 Company8 600
33 | 6 cellphones home1 2009-08-24 14:35 Company8 600
34 | 6 cellphones page1 2009-08-24 14:40 Company8 600
35 | 6 cellphones page2 2009-08-24 14:45 Company8 600
36 | 6 cellphones checkout 2009-08-24 14:50 Company8 600
37 | 6 cellphones page3 2009-08-24 14:52 Company8 600
38 | 6 laptops home 2009-08-24 14:54 Company7 800
39 | 6 laptops page2 2009-08-24 14:56 Company7 800
40 | 6 laptops page2 2009-08-24 14:57 Company7 800
--------------------------------------------------------------------------------
/1장/titanic/gender_submission.csv:
--------------------------------------------------------------------------------
1 | PassengerId,Survived
2 | 892,0
3 | 893,1
4 | 894,0
5 | 895,0
6 | 896,1
7 | 897,0
8 | 898,1
9 | 899,0
10 | 900,1
11 | 901,0
12 | 902,0
13 | 903,0
14 | 904,1
15 | 905,0
16 | 906,1
17 | 907,1
18 | 908,0
19 | 909,0
20 | 910,1
21 | 911,1
22 | 912,0
23 | 913,0
24 | 914,1
25 | 915,0
26 | 916,1
27 | 917,0
28 | 918,1
29 | 919,0
30 | 920,0
31 | 921,0
32 | 922,0
33 | 923,0
34 | 924,1
35 | 925,1
36 | 926,0
37 | 927,0
38 | 928,1
39 | 929,1
40 | 930,0
41 | 931,0
42 | 932,0
43 | 933,0
44 | 934,0
45 | 935,1
46 | 936,1
47 | 937,0
48 | 938,0
49 | 939,0
50 | 940,1
51 | 941,1
52 | 942,0
53 | 943,0
54 | 944,1
55 | 945,1
56 | 946,0
57 | 947,0
58 | 948,0
59 | 949,0
60 | 950,0
61 | 951,1
62 | 952,0
63 | 953,0
64 | 954,0
65 | 955,1
66 | 956,0
67 | 957,1
68 | 958,1
69 | 959,0
70 | 960,0
71 | 961,1
72 | 962,1
73 | 963,0
74 | 964,1
75 | 965,0
76 | 966,1
77 | 967,0
78 | 968,0
79 | 969,1
80 | 970,0
81 | 971,1
82 | 972,0
83 | 973,0
84 | 974,0
85 | 975,0
86 | 976,0
87 | 977,0
88 | 978,1
89 | 979,1
90 | 980,1
91 | 981,0
92 | 982,1
93 | 983,0
94 | 984,1
95 | 985,0
96 | 986,0
97 | 987,0
98 | 988,1
99 | 989,0
100 | 990,1
101 | 991,0
102 | 992,1
103 | 993,0
104 | 994,0
105 | 995,0
106 | 996,1
107 | 997,0
108 | 998,0
109 | 999,0
110 | 1000,0
111 | 1001,0
112 | 1002,0
113 | 1003,1
114 | 1004,1
115 | 1005,1
116 | 1006,1
117 | 1007,0
118 | 1008,0
119 | 1009,1
120 | 1010,0
121 | 1011,1
122 | 1012,1
123 | 1013,0
124 | 1014,1
125 | 1015,0
126 | 1016,0
127 | 1017,1
128 | 1018,0
129 | 1019,1
130 | 1020,0
131 | 1021,0
132 | 1022,0
133 | 1023,0
134 | 1024,1
135 | 1025,0
136 | 1026,0
137 | 1027,0
138 | 1028,0
139 | 1029,0
140 | 1030,1
141 | 1031,0
142 | 1032,1
143 | 1033,1
144 | 1034,0
145 | 1035,0
146 | 1036,0
147 | 1037,0
148 | 1038,0
149 | 1039,0
150 | 1040,0
151 | 1041,0
152 | 1042,1
153 | 1043,0
154 | 1044,0
155 | 1045,1
156 | 1046,0
157 | 1047,0
158 | 1048,1
159 | 1049,1
160 | 1050,0
161 | 1051,1
162 | 1052,1
163 | 1053,0
164 | 1054,1
165 | 1055,0
166 | 1056,0
167 | 1057,1
168 | 1058,0
169 | 1059,0
170 | 1060,1
171 | 1061,1
172 | 1062,0
173 | 1063,0
174 | 1064,0
175 | 1065,0
176 | 1066,0
177 | 1067,1
178 | 1068,1
179 | 1069,0
180 | 1070,1
181 | 1071,1
182 | 1072,0
183 | 1073,0
184 | 1074,1
185 | 1075,0
186 | 1076,1
187 | 1077,0
188 | 1078,1
189 | 1079,0
190 | 1080,1
191 | 1081,0
192 | 1082,0
193 | 1083,0
194 | 1084,0
195 | 1085,0
196 | 1086,0
197 | 1087,0
198 | 1088,0
199 | 1089,1
200 | 1090,0
201 | 1091,1
202 | 1092,1
203 | 1093,0
204 | 1094,0
205 | 1095,1
206 | 1096,0
207 | 1097,0
208 | 1098,1
209 | 1099,0
210 | 1100,1
211 | 1101,0
212 | 1102,0
213 | 1103,0
214 | 1104,0
215 | 1105,1
216 | 1106,1
217 | 1107,0
218 | 1108,1
219 | 1109,0
220 | 1110,1
221 | 1111,0
222 | 1112,1
223 | 1113,0
224 | 1114,1
225 | 1115,0
226 | 1116,1
227 | 1117,1
228 | 1118,0
229 | 1119,1
230 | 1120,0
231 | 1121,0
232 | 1122,0
233 | 1123,1
234 | 1124,0
235 | 1125,0
236 | 1126,0
237 | 1127,0
238 | 1128,0
239 | 1129,0
240 | 1130,1
241 | 1131,1
242 | 1132,1
243 | 1133,1
244 | 1134,0
245 | 1135,0
246 | 1136,0
247 | 1137,0
248 | 1138,1
249 | 1139,0
250 | 1140,1
251 | 1141,1
252 | 1142,1
253 | 1143,0
254 | 1144,0
255 | 1145,0
256 | 1146,0
257 | 1147,0
258 | 1148,0
259 | 1149,0
260 | 1150,1
261 | 1151,0
262 | 1152,0
263 | 1153,0
264 | 1154,1
265 | 1155,1
266 | 1156,0
267 | 1157,0
268 | 1158,0
269 | 1159,0
270 | 1160,1
271 | 1161,0
272 | 1162,0
273 | 1163,0
274 | 1164,1
275 | 1165,1
276 | 1166,0
277 | 1167,1
278 | 1168,0
279 | 1169,0
280 | 1170,0
281 | 1171,0
282 | 1172,1
283 | 1173,0
284 | 1174,1
285 | 1175,1
286 | 1176,1
287 | 1177,0
288 | 1178,0
289 | 1179,0
290 | 1180,0
291 | 1181,0
292 | 1182,0
293 | 1183,1
294 | 1184,0
295 | 1185,0
296 | 1186,0
297 | 1187,0
298 | 1188,1
299 | 1189,0
300 | 1190,0
301 | 1191,0
302 | 1192,0
303 | 1193,0
304 | 1194,0
305 | 1195,0
306 | 1196,1
307 | 1197,1
308 | 1198,0
309 | 1199,0
310 | 1200,0
311 | 1201,1
312 | 1202,0
313 | 1203,0
314 | 1204,0
315 | 1205,1
316 | 1206,1
317 | 1207,1
318 | 1208,0
319 | 1209,0
320 | 1210,0
321 | 1211,0
322 | 1212,0
323 | 1213,0
324 | 1214,0
325 | 1215,0
326 | 1216,1
327 | 1217,0
328 | 1218,1
329 | 1219,0
330 | 1220,0
331 | 1221,0
332 | 1222,1
333 | 1223,0
334 | 1224,0
335 | 1225,1
336 | 1226,0
337 | 1227,0
338 | 1228,0
339 | 1229,0
340 | 1230,0
341 | 1231,0
342 | 1232,0
343 | 1233,0
344 | 1234,0
345 | 1235,1
346 | 1236,0
347 | 1237,1
348 | 1238,0
349 | 1239,1
350 | 1240,0
351 | 1241,1
352 | 1242,1
353 | 1243,0
354 | 1244,0
355 | 1245,0
356 | 1246,1
357 | 1247,0
358 | 1248,1
359 | 1249,0
360 | 1250,0
361 | 1251,1
362 | 1252,0
363 | 1253,1
364 | 1254,1
365 | 1255,0
366 | 1256,1
367 | 1257,1
368 | 1258,0
369 | 1259,1
370 | 1260,1
371 | 1261,0
372 | 1262,0
373 | 1263,1
374 | 1264,0
375 | 1265,0
376 | 1266,1
377 | 1267,1
378 | 1268,1
379 | 1269,0
380 | 1270,0
381 | 1271,0
382 | 1272,0
383 | 1273,0
384 | 1274,1
385 | 1275,1
386 | 1276,0
387 | 1277,1
388 | 1278,0
389 | 1279,0
390 | 1280,0
391 | 1281,0
392 | 1282,0
393 | 1283,1
394 | 1284,0
395 | 1285,0
396 | 1286,0
397 | 1287,1
398 | 1288,0
399 | 1289,1
400 | 1290,0
401 | 1291,0
402 | 1292,1
403 | 1293,0
404 | 1294,1
405 | 1295,0
406 | 1296,0
407 | 1297,0
408 | 1298,0
409 | 1299,0
410 | 1300,1
411 | 1301,1
412 | 1302,1
413 | 1303,1
414 | 1304,1
415 | 1305,0
416 | 1306,1
417 | 1307,0
418 | 1308,0
419 | 1309,0
420 |
--------------------------------------------------------------------------------
/2장/2.2 첫 번째 머신러닝 만들어 보기 _ 붓꽃 품종 예측하기.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### 사이킷런을 이용하여 붓꽃(Iris) 데이터 품종 예측하기\n",
8 | "\n"
9 | ]
10 | },
11 | {
12 | "cell_type": "code",
13 | "execution_count": 1,
14 | "metadata": {},
15 | "outputs": [
16 | {
17 | "name": "stdout",
18 | "output_type": "stream",
19 | "text": [
20 | "1.0.2\n"
21 | ]
22 | }
23 | ],
24 | "source": [
25 | "# 사이킷런 버전 확인\n",
26 | "import sklearn\n",
27 | "print(sklearn.__version__)"
28 | ]
29 | },
30 | {
31 | "cell_type": "markdown",
32 | "metadata": {},
33 | "source": [
34 | "**붓꽃 예측을 위한 사이킷런 필요 모듈 로딩**"
35 | ]
36 | },
37 | {
38 | "cell_type": "code",
39 | "execution_count": 2,
40 | "metadata": {},
41 | "outputs": [],
42 | "source": [
43 | "from sklearn.datasets import load_iris\n",
44 | "from sklearn.tree import DecisionTreeClassifier\n",
45 | "from sklearn.model_selection import train_test_split"
46 | ]
47 | },
48 | {
49 | "cell_type": "markdown",
50 | "metadata": {},
51 | "source": [
52 | "**데이터 세트를 로딩**"
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "execution_count": 3,
58 | "metadata": {},
59 | "outputs": [
60 | {
61 | "name": "stdout",
62 | "output_type": "stream",
63 | "text": [
64 | "iris target값: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n",
65 | " 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n",
66 | " 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2\n",
67 | " 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2\n",
68 | " 2 2]\n",
69 | "iris target명: ['setosa' 'versicolor' 'virginica']\n"
70 | ]
71 | },
72 | {
73 | "data": {
74 | "text/html": [
75 | "
\n",
76 | "\n",
89 | "
\n",
90 | " \n",
91 | " \n",
92 | " | \n",
93 | " sepal length (cm) | \n",
94 | " sepal width (cm) | \n",
95 | " petal length (cm) | \n",
96 | " petal width (cm) | \n",
97 | " label | \n",
98 | "
\n",
99 | " \n",
100 | " \n",
101 | " \n",
102 | " 0 | \n",
103 | " 5.1 | \n",
104 | " 3.5 | \n",
105 | " 1.4 | \n",
106 | " 0.2 | \n",
107 | " 0 | \n",
108 | "
\n",
109 | " \n",
110 | " 1 | \n",
111 | " 4.9 | \n",
112 | " 3.0 | \n",
113 | " 1.4 | \n",
114 | " 0.2 | \n",
115 | " 0 | \n",
116 | "
\n",
117 | " \n",
118 | " 2 | \n",
119 | " 4.7 | \n",
120 | " 3.2 | \n",
121 | " 1.3 | \n",
122 | " 0.2 | \n",
123 | " 0 | \n",
124 | "
\n",
125 | " \n",
126 | "
\n",
127 | "
"
128 | ],
129 | "text/plain": [
130 | " sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) \\\n",
131 | "0 5.1 3.5 1.4 0.2 \n",
132 | "1 4.9 3.0 1.4 0.2 \n",
133 | "2 4.7 3.2 1.3 0.2 \n",
134 | "\n",
135 | " label \n",
136 | "0 0 \n",
137 | "1 0 \n",
138 | "2 0 "
139 | ]
140 | },
141 | "execution_count": 3,
142 | "metadata": {},
143 | "output_type": "execute_result"
144 | }
145 | ],
146 | "source": [
147 | "import pandas as pd\n",
148 | "\n",
149 | "# 붓꽃 데이터 세트를 로딩합니다. \n",
150 | "iris = load_iris()\n",
151 | "\n",
152 | "# iris.data는 Iris 데이터 세트에서 피처(feature)만으로 된 데이터를 numpy로 가지고 있습니다. \n",
153 | "iris_data = iris.data\n",
154 | "\n",
155 | "# iris.target은 붓꽃 데이터 세트에서 레이블(결정 값) 데이터를 numpy로 가지고 있습니다. \n",
156 | "iris_label = iris.target\n",
157 | "print('iris target값:', iris_label)\n",
158 | "print('iris target명:', iris.target_names)\n",
159 | "\n",
160 | "# 붓꽃 데이터 세트를 자세히 보기 위해 DataFrame으로 변환합니다. \n",
161 | "iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names)\n",
162 | "iris_df['label'] = iris.target\n",
163 | "iris_df.head(3)"
164 | ]
165 | },
166 | {
167 | "cell_type": "markdown",
168 | "metadata": {},
169 | "source": [
170 | "**학습 데이터와 테스트 데이터 세트로 분리**"
171 | ]
172 | },
173 | {
174 | "cell_type": "code",
175 | "execution_count": 4,
176 | "metadata": {},
177 | "outputs": [],
178 | "source": [
179 | "X_train, X_test, y_train, y_test = train_test_split(iris_data, iris_label, \n",
180 | " test_size=0.2, random_state=11)"
181 | ]
182 | },
183 | {
184 | "cell_type": "markdown",
185 | "metadata": {},
186 | "source": [
187 | "**학습 데이터 세트로 학습(Train)수행**"
188 | ]
189 | },
190 | {
191 | "cell_type": "code",
192 | "execution_count": 5,
193 | "metadata": {},
194 | "outputs": [
195 | {
196 | "data": {
197 | "text/plain": [
198 | "DecisionTreeClassifier(random_state=11)"
199 | ]
200 | },
201 | "execution_count": 5,
202 | "metadata": {},
203 | "output_type": "execute_result"
204 | }
205 | ],
206 | "source": [
207 | "# DecisionTreeClassifier 객체 생성 \n",
208 | "dt_clf = DecisionTreeClassifier(random_state=11)\n",
209 | "\n",
210 | "# 학습 수행 \n",
211 | "dt_clf.fit(X_train, y_train)"
212 | ]
213 | },
214 | {
215 | "cell_type": "markdown",
216 | "metadata": {},
217 | "source": [
218 | "**테스트 데이터 세트로 예측(Predict) 수행**"
219 | ]
220 | },
221 | {
222 | "cell_type": "code",
223 | "execution_count": 6,
224 | "metadata": {},
225 | "outputs": [],
226 | "source": [
227 | "# 학습이 완료된 DecisionTreeClassifier 객체에서 테스트 데이터 세트로 예측 수행. \n",
228 | "pred = dt_clf.predict(X_test)"
229 | ]
230 | },
231 | {
232 | "cell_type": "code",
233 | "execution_count": 7,
234 | "metadata": {},
235 | "outputs": [
236 | {
237 | "data": {
238 | "text/plain": [
239 | "array([2, 2, 1, 1, 2, 0, 1, 0, 0, 1, 1, 1, 1, 2, 2, 0, 2, 1, 2, 2, 1, 0,\n",
240 | " 0, 1, 0, 0, 2, 1, 0, 1])"
241 | ]
242 | },
243 | "execution_count": 7,
244 | "metadata": {},
245 | "output_type": "execute_result"
246 | }
247 | ],
248 | "source": [
249 | "pred"
250 | ]
251 | },
252 | {
253 | "cell_type": "markdown",
254 | "metadata": {},
255 | "source": [
256 | "**예측 정확도 평가**"
257 | ]
258 | },
259 | {
260 | "cell_type": "code",
261 | "execution_count": 8,
262 | "metadata": {},
263 | "outputs": [
264 | {
265 | "name": "stdout",
266 | "output_type": "stream",
267 | "text": [
268 | "예측 정확도: 0.9333\n"
269 | ]
270 | }
271 | ],
272 | "source": [
273 | "from sklearn.metrics import accuracy_score\n",
274 | "print('예측 정확도: {0:.4f}'.format(accuracy_score(y_test,pred)))"
275 | ]
276 | },
277 | {
278 | "cell_type": "code",
279 | "execution_count": null,
280 | "metadata": {},
281 | "outputs": [],
282 | "source": []
283 | }
284 | ],
285 | "metadata": {
286 | "kernelspec": {
287 | "display_name": "Python 3 (ipykernel)",
288 | "language": "python",
289 | "name": "python3"
290 | },
291 | "language_info": {
292 | "codemirror_mode": {
293 | "name": "ipython",
294 | "version": 3
295 | },
296 | "file_extension": ".py",
297 | "mimetype": "text/x-python",
298 | "name": "python",
299 | "nbconvert_exporter": "python",
300 | "pygments_lexer": "ipython3",
301 | "version": "3.9.7"
302 | }
303 | },
304 | "nbformat": 4,
305 | "nbformat_minor": 2
306 | }
307 |
--------------------------------------------------------------------------------
/2장/2.3 사이킷런의 내장 예제 데이터.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### 사이킷런 내장 예제 데이터"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": 1,
13 | "metadata": {},
14 | "outputs": [
15 | {
16 | "name": "stdout",
17 | "output_type": "stream",
18 | "text": [
19 | "\n"
20 | ]
21 | }
22 | ],
23 | "source": [
24 | "from sklearn.datasets import load_iris\n",
25 | "\n",
26 | "iris_data = load_iris()\n",
27 | "print(type(iris_data))\n"
28 | ]
29 | },
30 | {
31 | "cell_type": "code",
32 | "execution_count": 2,
33 | "metadata": {},
34 | "outputs": [
35 | {
36 | "name": "stdout",
37 | "output_type": "stream",
38 | "text": [
39 | "붓꽃 데이터 세트의 키들: dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])\n"
40 | ]
41 | }
42 | ],
43 | "source": [
44 | "keys = iris_data.keys()\n",
45 | "print('붓꽃 데이터 세트의 키들:', keys)\n"
46 | ]
47 | },
48 | {
49 | "cell_type": "markdown",
50 | "metadata": {},
51 | "source": [
52 | "키는 보통 data, target, target_name, feature_names, DESCR로 구성돼 있습니다. \n",
53 | "개별 키가 가리키는 의미는 다음과 같습니다.\n",
54 | "* data는 피처의 데이터 세트를 가리킵니다.\n",
55 | "* target은 분류 시 레이블 값, 회귀일 때는 숫자 결괏값 데이터 세트입니다..\n",
56 | "* target_names는 개별 레이블의 이름을 나타냅니다.\n",
57 | "* feature_names는 피처의 이름을 나타냅니다.\n",
58 | "* DESCR은 데이터 세트에 대한 설명과 각 피처의 설명을 나타냅니다."
59 | ]
60 | },
61 | {
62 | "cell_type": "code",
63 | "execution_count": 3,
64 | "metadata": {},
65 | "outputs": [
66 | {
67 | "name": "stdout",
68 | "output_type": "stream",
69 | "text": [
70 | "\n",
71 | " feature_names 의 type: \n",
72 | " feature_names 의 shape: 4\n",
73 | "['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']\n",
74 | "\n",
75 | " target_names 의 type: \n",
76 | " feature_names 의 shape: 3\n",
77 | "['setosa' 'versicolor' 'virginica']\n",
78 | "\n",
79 | " data 의 type: \n",
80 | " data 의 shape: (150, 4)\n",
81 | "[[5.1 3.5 1.4 0.2]\n",
82 | " [4.9 3. 1.4 0.2]\n",
83 | " [4.7 3.2 1.3 0.2]\n",
84 | " [4.6 3.1 1.5 0.2]\n",
85 | " [5. 3.6 1.4 0.2]\n",
86 | " [5.4 3.9 1.7 0.4]\n",
87 | " [4.6 3.4 1.4 0.3]\n",
88 | " [5. 3.4 1.5 0.2]\n",
89 | " [4.4 2.9 1.4 0.2]\n",
90 | " [4.9 3.1 1.5 0.1]\n",
91 | " [5.4 3.7 1.5 0.2]\n",
92 | " [4.8 3.4 1.6 0.2]\n",
93 | " [4.8 3. 1.4 0.1]\n",
94 | " [4.3 3. 1.1 0.1]\n",
95 | " [5.8 4. 1.2 0.2]\n",
96 | " [5.7 4.4 1.5 0.4]\n",
97 | " [5.4 3.9 1.3 0.4]\n",
98 | " [5.1 3.5 1.4 0.3]\n",
99 | " [5.7 3.8 1.7 0.3]\n",
100 | " [5.1 3.8 1.5 0.3]\n",
101 | " [5.4 3.4 1.7 0.2]\n",
102 | " [5.1 3.7 1.5 0.4]\n",
103 | " [4.6 3.6 1. 0.2]\n",
104 | " [5.1 3.3 1.7 0.5]\n",
105 | " [4.8 3.4 1.9 0.2]\n",
106 | " [5. 3. 1.6 0.2]\n",
107 | " [5. 3.4 1.6 0.4]\n",
108 | " [5.2 3.5 1.5 0.2]\n",
109 | " [5.2 3.4 1.4 0.2]\n",
110 | " [4.7 3.2 1.6 0.2]\n",
111 | " [4.8 3.1 1.6 0.2]\n",
112 | " [5.4 3.4 1.5 0.4]\n",
113 | " [5.2 4.1 1.5 0.1]\n",
114 | " [5.5 4.2 1.4 0.2]\n",
115 | " [4.9 3.1 1.5 0.2]\n",
116 | " [5. 3.2 1.2 0.2]\n",
117 | " [5.5 3.5 1.3 0.2]\n",
118 | " [4.9 3.6 1.4 0.1]\n",
119 | " [4.4 3. 1.3 0.2]\n",
120 | " [5.1 3.4 1.5 0.2]\n",
121 | " [5. 3.5 1.3 0.3]\n",
122 | " [4.5 2.3 1.3 0.3]\n",
123 | " [4.4 3.2 1.3 0.2]\n",
124 | " [5. 3.5 1.6 0.6]\n",
125 | " [5.1 3.8 1.9 0.4]\n",
126 | " [4.8 3. 1.4 0.3]\n",
127 | " [5.1 3.8 1.6 0.2]\n",
128 | " [4.6 3.2 1.4 0.2]\n",
129 | " [5.3 3.7 1.5 0.2]\n",
130 | " [5. 3.3 1.4 0.2]\n",
131 | " [7. 3.2 4.7 1.4]\n",
132 | " [6.4 3.2 4.5 1.5]\n",
133 | " [6.9 3.1 4.9 1.5]\n",
134 | " [5.5 2.3 4. 1.3]\n",
135 | " [6.5 2.8 4.6 1.5]\n",
136 | " [5.7 2.8 4.5 1.3]\n",
137 | " [6.3 3.3 4.7 1.6]\n",
138 | " [4.9 2.4 3.3 1. ]\n",
139 | " [6.6 2.9 4.6 1.3]\n",
140 | " [5.2 2.7 3.9 1.4]\n",
141 | " [5. 2. 3.5 1. ]\n",
142 | " [5.9 3. 4.2 1.5]\n",
143 | " [6. 2.2 4. 1. ]\n",
144 | " [6.1 2.9 4.7 1.4]\n",
145 | " [5.6 2.9 3.6 1.3]\n",
146 | " [6.7 3.1 4.4 1.4]\n",
147 | " [5.6 3. 4.5 1.5]\n",
148 | " [5.8 2.7 4.1 1. ]\n",
149 | " [6.2 2.2 4.5 1.5]\n",
150 | " [5.6 2.5 3.9 1.1]\n",
151 | " [5.9 3.2 4.8 1.8]\n",
152 | " [6.1 2.8 4. 1.3]\n",
153 | " [6.3 2.5 4.9 1.5]\n",
154 | " [6.1 2.8 4.7 1.2]\n",
155 | " [6.4 2.9 4.3 1.3]\n",
156 | " [6.6 3. 4.4 1.4]\n",
157 | " [6.8 2.8 4.8 1.4]\n",
158 | " [6.7 3. 5. 1.7]\n",
159 | " [6. 2.9 4.5 1.5]\n",
160 | " [5.7 2.6 3.5 1. ]\n",
161 | " [5.5 2.4 3.8 1.1]\n",
162 | " [5.5 2.4 3.7 1. ]\n",
163 | " [5.8 2.7 3.9 1.2]\n",
164 | " [6. 2.7 5.1 1.6]\n",
165 | " [5.4 3. 4.5 1.5]\n",
166 | " [6. 3.4 4.5 1.6]\n",
167 | " [6.7 3.1 4.7 1.5]\n",
168 | " [6.3 2.3 4.4 1.3]\n",
169 | " [5.6 3. 4.1 1.3]\n",
170 | " [5.5 2.5 4. 1.3]\n",
171 | " [5.5 2.6 4.4 1.2]\n",
172 | " [6.1 3. 4.6 1.4]\n",
173 | " [5.8 2.6 4. 1.2]\n",
174 | " [5. 2.3 3.3 1. ]\n",
175 | " [5.6 2.7 4.2 1.3]\n",
176 | " [5.7 3. 4.2 1.2]\n",
177 | " [5.7 2.9 4.2 1.3]\n",
178 | " [6.2 2.9 4.3 1.3]\n",
179 | " [5.1 2.5 3. 1.1]\n",
180 | " [5.7 2.8 4.1 1.3]\n",
181 | " [6.3 3.3 6. 2.5]\n",
182 | " [5.8 2.7 5.1 1.9]\n",
183 | " [7.1 3. 5.9 2.1]\n",
184 | " [6.3 2.9 5.6 1.8]\n",
185 | " [6.5 3. 5.8 2.2]\n",
186 | " [7.6 3. 6.6 2.1]\n",
187 | " [4.9 2.5 4.5 1.7]\n",
188 | " [7.3 2.9 6.3 1.8]\n",
189 | " [6.7 2.5 5.8 1.8]\n",
190 | " [7.2 3.6 6.1 2.5]\n",
191 | " [6.5 3.2 5.1 2. ]\n",
192 | " [6.4 2.7 5.3 1.9]\n",
193 | " [6.8 3. 5.5 2.1]\n",
194 | " [5.7 2.5 5. 2. ]\n",
195 | " [5.8 2.8 5.1 2.4]\n",
196 | " [6.4 3.2 5.3 2.3]\n",
197 | " [6.5 3. 5.5 1.8]\n",
198 | " [7.7 3.8 6.7 2.2]\n",
199 | " [7.7 2.6 6.9 2.3]\n",
200 | " [6. 2.2 5. 1.5]\n",
201 | " [6.9 3.2 5.7 2.3]\n",
202 | " [5.6 2.8 4.9 2. ]\n",
203 | " [7.7 2.8 6.7 2. ]\n",
204 | " [6.3 2.7 4.9 1.8]\n",
205 | " [6.7 3.3 5.7 2.1]\n",
206 | " [7.2 3.2 6. 1.8]\n",
207 | " [6.2 2.8 4.8 1.8]\n",
208 | " [6.1 3. 4.9 1.8]\n",
209 | " [6.4 2.8 5.6 2.1]\n",
210 | " [7.2 3. 5.8 1.6]\n",
211 | " [7.4 2.8 6.1 1.9]\n",
212 | " [7.9 3.8 6.4 2. ]\n",
213 | " [6.4 2.8 5.6 2.2]\n",
214 | " [6.3 2.8 5.1 1.5]\n",
215 | " [6.1 2.6 5.6 1.4]\n",
216 | " [7.7 3. 6.1 2.3]\n",
217 | " [6.3 3.4 5.6 2.4]\n",
218 | " [6.4 3.1 5.5 1.8]\n",
219 | " [6. 3. 4.8 1.8]\n",
220 | " [6.9 3.1 5.4 2.1]\n",
221 | " [6.7 3.1 5.6 2.4]\n",
222 | " [6.9 3.1 5.1 2.3]\n",
223 | " [5.8 2.7 5.1 1.9]\n",
224 | " [6.8 3.2 5.9 2.3]\n",
225 | " [6.7 3.3 5.7 2.5]\n",
226 | " [6.7 3. 5.2 2.3]\n",
227 | " [6.3 2.5 5. 1.9]\n",
228 | " [6.5 3. 5.2 2. ]\n",
229 | " [6.2 3.4 5.4 2.3]\n",
230 | " [5.9 3. 5.1 1.8]]\n",
231 | "\n",
232 | " target 의 type: \n",
233 | " target 의 shape: (150,)\n",
234 | "[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n",
235 | " 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n",
236 | " 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2\n",
237 | " 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2\n",
238 | " 2 2]\n"
239 | ]
240 | }
241 | ],
242 | "source": [
243 | "print('\\n feature_names 의 type:',type(iris_data.feature_names))\n",
244 | "print(' feature_names 의 shape:',len(iris_data.feature_names))\n",
245 | "print(iris_data.feature_names)\n",
246 | "\n",
247 | "print('\\n target_names 의 type:',type(iris_data.target_names))\n",
248 | "print(' feature_names 의 shape:',len(iris_data.target_names))\n",
249 | "print(iris_data.target_names)\n",
250 | "\n",
251 | "print('\\n data 의 type:',type(iris_data.data))\n",
252 | "print(' data 의 shape:',iris_data.data.shape)\n",
253 | "print(iris_data['data'])\n",
254 | "\n",
255 | "print('\\n target 의 type:',type(iris_data.target))\n",
256 | "print(' target 의 shape:',iris_data.target.shape)\n",
257 | "print(iris_data.target)\n"
258 | ]
259 | },
260 | {
261 | "cell_type": "code",
262 | "execution_count": null,
263 | "metadata": {},
264 | "outputs": [],
265 | "source": []
266 | },
267 | {
268 | "cell_type": "code",
269 | "execution_count": null,
270 | "metadata": {},
271 | "outputs": [],
272 | "source": []
273 | }
274 | ],
275 | "metadata": {
276 | "kernelspec": {
277 | "display_name": "Python 3 (ipykernel)",
278 | "language": "python",
279 | "name": "python3"
280 | },
281 | "language_info": {
282 | "codemirror_mode": {
283 | "name": "ipython",
284 | "version": 3
285 | },
286 | "file_extension": ".py",
287 | "mimetype": "text/x-python",
288 | "name": "python",
289 | "nbconvert_exporter": "python",
290 | "pygments_lexer": "ipython3",
291 | "version": "3.9.7"
292 | }
293 | },
294 | "nbformat": 4,
295 | "nbformat_minor": 2
296 | }
297 |
--------------------------------------------------------------------------------
/2장/2.5 데이터_전처리.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### 데이터 인코딩"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "* 레이블 인코딩(Label encoding)"
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": 1,
20 | "metadata": {},
21 | "outputs": [
22 | {
23 | "name": "stdout",
24 | "output_type": "stream",
25 | "text": [
26 | "인코딩 변환값: [0 1 4 5 3 3 2 2]\n"
27 | ]
28 | }
29 | ],
30 | "source": [
31 | "from sklearn.preprocessing import LabelEncoder\n",
32 | "\n",
33 | "items=['TV','냉장고','전자렌지','컴퓨터','선풍기','선풍기','믹서','믹서']\n",
34 | "\n",
35 | "# LabelEncoder를 객체로 생성한 후 , fit( ) 과 transform( ) 으로 label 인코딩 수행. \n",
36 | "encoder = LabelEncoder()\n",
37 | "encoder.fit(items)\n",
38 | "labels = encoder.transform(items)\n",
39 | "print('인코딩 변환값:',labels)"
40 | ]
41 | },
42 | {
43 | "cell_type": "code",
44 | "execution_count": 2,
45 | "metadata": {},
46 | "outputs": [
47 | {
48 | "name": "stdout",
49 | "output_type": "stream",
50 | "text": [
51 | "인코딩 클래스: ['TV' '냉장고' '믹서' '선풍기' '전자렌지' '컴퓨터']\n"
52 | ]
53 | }
54 | ],
55 | "source": [
56 | "print('인코딩 클래스:',encoder.classes_)"
57 | ]
58 | },
59 | {
60 | "cell_type": "code",
61 | "execution_count": 3,
62 | "metadata": {},
63 | "outputs": [
64 | {
65 | "name": "stdout",
66 | "output_type": "stream",
67 | "text": [
68 | "디코딩 원본 값: ['전자렌지' '컴퓨터' '믹서' 'TV' '냉장고' '냉장고' '선풍기' '선풍기']\n"
69 | ]
70 | }
71 | ],
72 | "source": [
73 | "print('디코딩 원본 값:',encoder.inverse_transform([4, 5, 2, 0, 1, 1, 3, 3]))"
74 | ]
75 | },
76 | {
77 | "cell_type": "markdown",
78 | "metadata": {},
79 | "source": [
80 | "* 원-핫 인코딩(One-Hot encoding)"
81 | ]
82 | },
83 | {
84 | "cell_type": "code",
85 | "execution_count": 4,
86 | "metadata": {},
87 | "outputs": [
88 | {
89 | "name": "stdout",
90 | "output_type": "stream",
91 | "text": [
92 | "원-핫 인코딩 데이터\n",
93 | "[[1. 0. 0. 0. 0. 0.]\n",
94 | " [0. 1. 0. 0. 0. 0.]\n",
95 | " [0. 0. 0. 0. 1. 0.]\n",
96 | " [0. 0. 0. 0. 0. 1.]\n",
97 | " [0. 0. 0. 1. 0. 0.]\n",
98 | " [0. 0. 0. 1. 0. 0.]\n",
99 | " [0. 0. 1. 0. 0. 0.]\n",
100 | " [0. 0. 1. 0. 0. 0.]]\n",
101 | "원-핫 인코딩 데이터 차원\n",
102 | "(8, 6)\n"
103 | ]
104 | }
105 | ],
106 | "source": [
107 | "from sklearn.preprocessing import OneHotEncoder\n",
108 | "import numpy as np\n",
109 | "\n",
110 | "items=['TV','냉장고','전자렌지','컴퓨터','선풍기','선풍기','믹서','믹서']\n",
111 | "\n",
112 | "# 2차원 ndarray로 변환합니다. \n",
113 | "items = np.array(items).reshape(-1, 1)\n",
114 | "\n",
115 | "# 원-핫 인코딩을 적용합니다. \n",
116 | "oh_encoder = OneHotEncoder()\n",
117 | "oh_encoder.fit(items)\n",
118 | "oh_labels = oh_encoder.transform(items)\n",
119 | "\n",
120 | "# OneHotEncoder로 변환한 결과는 희소행렬(Sparse Matrix)이므로 toarray()를 이용하여 밀집 행렬(Dense Matrix)로 변환. \n",
121 | "print('원-핫 인코딩 데이터')\n",
122 | "print(oh_labels.toarray())\n",
123 | "print('원-핫 인코딩 데이터 차원')\n",
124 | "print(oh_labels.shape)"
125 | ]
126 | },
127 | {
128 | "cell_type": "code",
129 | "execution_count": 12,
130 | "metadata": {},
131 | "outputs": [
132 | {
133 | "data": {
134 | "text/html": [
135 | "\n",
136 | "\n",
149 | "
\n",
150 | " \n",
151 | " \n",
152 | " | \n",
153 | " item_TV | \n",
154 | " item_냉장고 | \n",
155 | " item_믹서 | \n",
156 | " item_선풍기 | \n",
157 | " item_전자렌지 | \n",
158 | " item_컴퓨터 | \n",
159 | "
\n",
160 | " \n",
161 | " \n",
162 | " \n",
163 | " 0 | \n",
164 | " 1 | \n",
165 | " 0 | \n",
166 | " 0 | \n",
167 | " 0 | \n",
168 | " 0 | \n",
169 | " 0 | \n",
170 | "
\n",
171 | " \n",
172 | " 1 | \n",
173 | " 0 | \n",
174 | " 1 | \n",
175 | " 0 | \n",
176 | " 0 | \n",
177 | " 0 | \n",
178 | " 0 | \n",
179 | "
\n",
180 | " \n",
181 | " 2 | \n",
182 | " 0 | \n",
183 | " 0 | \n",
184 | " 0 | \n",
185 | " 0 | \n",
186 | " 1 | \n",
187 | " 0 | \n",
188 | "
\n",
189 | " \n",
190 | " 3 | \n",
191 | " 0 | \n",
192 | " 0 | \n",
193 | " 0 | \n",
194 | " 0 | \n",
195 | " 0 | \n",
196 | " 1 | \n",
197 | "
\n",
198 | " \n",
199 | " 4 | \n",
200 | " 0 | \n",
201 | " 0 | \n",
202 | " 0 | \n",
203 | " 1 | \n",
204 | " 0 | \n",
205 | " 0 | \n",
206 | "
\n",
207 | " \n",
208 | " 5 | \n",
209 | " 0 | \n",
210 | " 0 | \n",
211 | " 0 | \n",
212 | " 1 | \n",
213 | " 0 | \n",
214 | " 0 | \n",
215 | "
\n",
216 | " \n",
217 | " 6 | \n",
218 | " 0 | \n",
219 | " 0 | \n",
220 | " 1 | \n",
221 | " 0 | \n",
222 | " 0 | \n",
223 | " 0 | \n",
224 | "
\n",
225 | " \n",
226 | " 7 | \n",
227 | " 0 | \n",
228 | " 0 | \n",
229 | " 1 | \n",
230 | " 0 | \n",
231 | " 0 | \n",
232 | " 0 | \n",
233 | "
\n",
234 | " \n",
235 | "
\n",
236 | "
"
237 | ],
238 | "text/plain": [
239 | " item_TV item_냉장고 item_믹서 item_선풍기 item_전자렌지 item_컴퓨터\n",
240 | "0 1 0 0 0 0 0\n",
241 | "1 0 1 0 0 0 0\n",
242 | "2 0 0 0 0 1 0\n",
243 | "3 0 0 0 0 0 1\n",
244 | "4 0 0 0 1 0 0\n",
245 | "5 0 0 0 1 0 0\n",
246 | "6 0 0 1 0 0 0\n",
247 | "7 0 0 1 0 0 0"
248 | ]
249 | },
250 | "execution_count": 12,
251 | "metadata": {},
252 | "output_type": "execute_result"
253 | }
254 | ],
255 | "source": [
256 | "import pandas as pd\n",
257 | "\n",
258 | "df = pd.DataFrame({'item':['TV','냉장고','전자렌지','컴퓨터','선풍기','선풍기','믹서','믹서'] })\n",
259 | "pd.get_dummies(df)"
260 | ]
261 | },
262 | {
263 | "cell_type": "markdown",
264 | "metadata": {},
265 | "source": [
266 | "### 피처 스케일링과 정규화"
267 | ]
268 | },
269 | {
270 | "cell_type": "markdown",
271 | "metadata": {},
272 | "source": [
273 | "* StandardScaler"
274 | ]
275 | },
276 | {
277 | "cell_type": "code",
278 | "execution_count": 15,
279 | "metadata": {},
280 | "outputs": [
281 | {
282 | "name": "stdout",
283 | "output_type": "stream",
284 | "text": [
285 | "feature 들의 평균 값\n",
286 | "sepal length (cm) 5.843333\n",
287 | "sepal width (cm) 3.057333\n",
288 | "petal length (cm) 3.758000\n",
289 | "petal width (cm) 1.199333\n",
290 | "dtype: float64\n",
291 | "\n",
292 | "feature 들의 분산 값\n",
293 | "sepal length (cm) 0.685694\n",
294 | "sepal width (cm) 0.189979\n",
295 | "petal length (cm) 3.116278\n",
296 | "petal width (cm) 0.581006\n",
297 | "dtype: float64\n"
298 | ]
299 | }
300 | ],
301 | "source": [
302 | "from sklearn.datasets import load_iris\n",
303 | "import pandas as pd\n",
304 | "# 붓꽃 데이터 셋을 로딩하고 DataFrame으로 변환합니다. \n",
305 | "iris = load_iris()\n",
306 | "iris_data = iris.data\n",
307 | "iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names)\n",
308 | "\n",
309 | "print('feature 들의 평균 값')\n",
310 | "print(iris_df.mean())\n",
311 | "print('\\nfeature 들의 분산 값')\n",
312 | "print(iris_df.var())\n"
313 | ]
314 | },
315 | {
316 | "cell_type": "code",
317 | "execution_count": 16,
318 | "metadata": {},
319 | "outputs": [
320 | {
321 | "name": "stdout",
322 | "output_type": "stream",
323 | "text": [
324 | "feature 들의 평균 값\n",
325 | "sepal length (cm) -1.690315e-15\n",
326 | "sepal width (cm) -1.842970e-15\n",
327 | "petal length (cm) -1.698641e-15\n",
328 | "petal width (cm) -1.409243e-15\n",
329 | "dtype: float64\n",
330 | "\n",
331 | "feature 들의 분산 값\n",
332 | "sepal length (cm) 1.006711\n",
333 | "sepal width (cm) 1.006711\n",
334 | "petal length (cm) 1.006711\n",
335 | "petal width (cm) 1.006711\n",
336 | "dtype: float64\n"
337 | ]
338 | }
339 | ],
340 | "source": [
341 | "from sklearn.preprocessing import StandardScaler\n",
342 | "\n",
343 | "# StandardScaler객체 생성\n",
344 | "scaler = StandardScaler()\n",
345 | "# StandardScaler 로 데이터 셋 변환. fit( ) 과 transform( ) 호출. \n",
346 | "scaler.fit(iris_df)\n",
347 | "iris_scaled = scaler.transform(iris_df)\n",
348 | "\n",
349 | "#transform( )시 scale 변환된 데이터 셋이 numpy ndarry로 반환되어 이를 DataFrame으로 변환\n",
350 | "iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)\n",
351 | "print('feature 들의 평균 값')\n",
352 | "print(iris_df_scaled.mean())\n",
353 | "print('\\nfeature 들의 분산 값')\n",
354 | "print(iris_df_scaled.var())"
355 | ]
356 | },
357 | {
358 | "cell_type": "markdown",
359 | "metadata": {},
360 | "source": [
361 | "* MinMaxScaler"
362 | ]
363 | },
364 | {
365 | "cell_type": "code",
366 | "execution_count": 17,
367 | "metadata": {},
368 | "outputs": [
369 | {
370 | "name": "stdout",
371 | "output_type": "stream",
372 | "text": [
373 | "feature들의 최소 값\n",
374 | "sepal length (cm) 0.0\n",
375 | "sepal width (cm) 0.0\n",
376 | "petal length (cm) 0.0\n",
377 | "petal width (cm) 0.0\n",
378 | "dtype: float64\n",
379 | "\n",
380 | "feature들의 최대 값\n",
381 | "sepal length (cm) 1.0\n",
382 | "sepal width (cm) 1.0\n",
383 | "petal length (cm) 1.0\n",
384 | "petal width (cm) 1.0\n",
385 | "dtype: float64\n"
386 | ]
387 | }
388 | ],
389 | "source": [
390 | "from sklearn.preprocessing import MinMaxScaler\n",
391 | "\n",
392 | "# MinMaxScaler객체 생성\n",
393 | "scaler = MinMaxScaler()\n",
394 | "# MinMaxScaler 로 데이터 셋 변환. fit() 과 transform() 호출. \n",
395 | "scaler.fit(iris_df)\n",
396 | "iris_scaled = scaler.transform(iris_df)\n",
397 | "\n",
398 | "# transform()시 scale 변환된 데이터 셋이 numpy ndarry로 반환되어 이를 DataFrame으로 변환\n",
399 | "iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)\n",
400 | "print('feature들의 최소 값')\n",
401 | "print(iris_df_scaled.min())\n",
402 | "print('\\nfeature들의 최대 값')\n",
403 | "print(iris_df_scaled.max())\n"
404 | ]
405 | },
406 | {
407 | "cell_type": "markdown",
408 | "metadata": {},
409 | "source": [
410 | "* Scaler를 이용하여 학습 데이터와 테스트 데이터에 fit(), transform(), fit_transform() 적용 시 유의사항. "
411 | ]
412 | },
413 | {
414 | "cell_type": "code",
415 | "execution_count": 18,
416 | "metadata": {},
417 | "outputs": [],
418 | "source": [
419 | "from sklearn.preprocessing import MinMaxScaler\n",
420 | "import numpy as np\n",
421 | "\n",
422 | "# 학습 데이터는 0 부터 10까지, 테스트 데이터는 0 부터 5까지 값을 가지는 데이터 세트로 생성\n",
423 | "# Scaler클래스의 fit(), transform()은 2차원 이상 데이터만 가능하므로 reshape(-1, 1)로 차원 변경\n",
424 | "train_array = np.arange(0, 11).reshape(-1, 1)\n",
425 | "test_array = np.arange(0, 6).reshape(-1, 1)"
426 | ]
427 | },
428 | {
429 | "cell_type": "code",
430 | "execution_count": 19,
431 | "metadata": {},
432 | "outputs": [
433 | {
434 | "name": "stdout",
435 | "output_type": "stream",
436 | "text": [
437 | "원본 train_array 데이터: [ 0 1 2 3 4 5 6 7 8 9 10]\n",
438 | "Scale된 train_array 데이터: [0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]\n"
439 | ]
440 | }
441 | ],
442 | "source": [
443 | "# 최소값 0, 최대값 1로 변환하는 MinMaxScaler객체 생성\n",
444 | "scaler = MinMaxScaler()\n",
445 | "# fit()하게 되면 train_array 데이터의 최소값이 0, 최대값이 10으로 설정. \n",
446 | "scaler.fit(train_array)\n",
447 | "# 1/10 scale로 train_array 데이터 변환함. 원본 10-> 1로 변환됨.\n",
448 | "train_scaled = scaler.transform(train_array)\n",
449 | " \n",
450 | "print('원본 train_array 데이터:', np.round(train_array.reshape(-1), 2))\n",
451 | "print('Scale된 train_array 데이터:', np.round(train_scaled.reshape(-1), 2))"
452 | ]
453 | },
454 | {
455 | "cell_type": "code",
456 | "execution_count": 20,
457 | "metadata": {},
458 | "outputs": [
459 | {
460 | "name": "stdout",
461 | "output_type": "stream",
462 | "text": [
463 | "원본 test_array 데이터: [0 1 2 3 4 5]\n",
464 | "Scale된 test_array 데이터: [0. 0.2 0.4 0.6 0.8 1. ]\n"
465 | ]
466 | }
467 | ],
468 | "source": [
469 | "# 앞에서 생성한 MinMaxScaler에 test_array를 fit()하게 되면 원본 데이터의 최소값이 0, 최대값이 5으로 설정됨 \n",
470 | "scaler.fit(test_array)\n",
471 | "# 1/5 scale로 test_array 데이터 변환함. 원본 5->1로 변환. \n",
472 | "test_scaled = scaler.transform(test_array)\n",
473 | "# train_array 변환 출력\n",
474 | "print('원본 test_array 데이터:', np.round(test_array.reshape(-1), 2))\n",
475 | "print('Scale된 test_array 데이터:', np.round(test_scaled.reshape(-1), 2))\n"
476 | ]
477 | },
478 | {
479 | "cell_type": "code",
480 | "execution_count": 21,
481 | "metadata": {},
482 | "outputs": [
483 | {
484 | "name": "stdout",
485 | "output_type": "stream",
486 | "text": [
487 | "원본 train_array 데이터: [ 0 1 2 3 4 5 6 7 8 9 10]\n",
488 | "Scale된 train_array 데이터: [0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]\n",
489 | "\n",
490 | "원본 test_array 데이터: [0 1 2 3 4 5]\n",
491 | "Scale된 test_array 데이터: [0. 0.1 0.2 0.3 0.4 0.5]\n"
492 | ]
493 | }
494 | ],
495 | "source": [
496 | "scaler = MinMaxScaler()\n",
497 | "scaler.fit(train_array)\n",
498 | "train_scaled = scaler.transform(train_array)\n",
499 | "print('원본 train_array 데이터:', np.round(train_array.reshape(-1), 2))\n",
500 | "print('Scale된 train_array 데이터:', np.round(train_scaled.reshape(-1), 2))\n",
501 | "\n",
502 | "# test_array에 Scale 변환을 할 때는 반드시 fit()을 호출하지 않고 transform() 만으로 변환해야 함. \n",
503 | "test_scaled = scaler.transform(test_array)\n",
504 | "print('\\n원본 test_array 데이터:', np.round(test_array.reshape(-1), 2))\n",
505 | "print('Scale된 test_array 데이터:', np.round(test_scaled.reshape(-1), 2))\n"
506 | ]
507 | },
508 | {
509 | "cell_type": "code",
510 | "execution_count": null,
511 | "metadata": {},
512 | "outputs": [],
513 | "source": []
514 | }
515 | ],
516 | "metadata": {
517 | "kernelspec": {
518 | "display_name": "Python 3 (ipykernel)",
519 | "language": "python",
520 | "name": "python3"
521 | },
522 | "language_info": {
523 | "codemirror_mode": {
524 | "name": "ipython",
525 | "version": 3
526 | },
527 | "file_extension": ".py",
528 | "mimetype": "text/x-python",
529 | "name": "python",
530 | "nbconvert_exporter": "python",
531 | "pygments_lexer": "ipython3",
532 | "version": "3.9.7"
533 | }
534 | },
535 | "nbformat": 4,
536 | "nbformat_minor": 2
537 | }
538 |
--------------------------------------------------------------------------------
/3장/3.6 피마 인디언 당뇨병 예측.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [
8 | {
9 | "name": "stdout",
10 | "output_type": "stream",
11 | "text": [
12 | "0 500\n",
13 | "1 268\n",
14 | "Name: Outcome, dtype: int64\n"
15 | ]
16 | },
17 | {
18 | "data": {
19 | "text/html": [
20 | "\n",
21 | "\n",
34 | "
\n",
35 | " \n",
36 | " \n",
37 | " | \n",
38 | " Pregnancies | \n",
39 | " Glucose | \n",
40 | " BloodPressure | \n",
41 | " SkinThickness | \n",
42 | " Insulin | \n",
43 | " BMI | \n",
44 | " DiabetesPedigreeFunction | \n",
45 | " Age | \n",
46 | " Outcome | \n",
47 | "
\n",
48 | " \n",
49 | " \n",
50 | " \n",
51 | " 0 | \n",
52 | " 6 | \n",
53 | " 148 | \n",
54 | " 72 | \n",
55 | " 35 | \n",
56 | " 0 | \n",
57 | " 33.6 | \n",
58 | " 0.627 | \n",
59 | " 50 | \n",
60 | " 1 | \n",
61 | "
\n",
62 | " \n",
63 | " 1 | \n",
64 | " 1 | \n",
65 | " 85 | \n",
66 | " 66 | \n",
67 | " 29 | \n",
68 | " 0 | \n",
69 | " 26.6 | \n",
70 | " 0.351 | \n",
71 | " 31 | \n",
72 | " 0 | \n",
73 | "
\n",
74 | " \n",
75 | " 2 | \n",
76 | " 8 | \n",
77 | " 183 | \n",
78 | " 64 | \n",
79 | " 0 | \n",
80 | " 0 | \n",
81 | " 23.3 | \n",
82 | " 0.672 | \n",
83 | " 32 | \n",
84 | " 1 | \n",
85 | "
\n",
86 | " \n",
87 | "
\n",
88 | "
"
89 | ],
90 | "text/plain": [
91 | " Pregnancies Glucose BloodPressure SkinThickness Insulin BMI \\\n",
92 | "0 6 148 72 35 0 33.6 \n",
93 | "1 1 85 66 29 0 26.6 \n",
94 | "2 8 183 64 0 0 23.3 \n",
95 | "\n",
96 | " DiabetesPedigreeFunction Age Outcome \n",
97 | "0 0.627 50 1 \n",
98 | "1 0.351 31 0 \n",
99 | "2 0.672 32 1 "
100 | ]
101 | },
102 | "execution_count": 1,
103 | "metadata": {},
104 | "output_type": "execute_result"
105 | }
106 | ],
107 | "source": [
108 | "import numpy as np\n",
109 | "import pandas as pd\n",
110 | "import matplotlib.pyplot as plt\n",
111 | "%matplotlib inline\n",
112 | "\n",
113 | "from sklearn.model_selection import train_test_split\n",
114 | "from sklearn.metrics import accuracy_score, precision_score, recall_score, roc_auc_score\n",
115 | "from sklearn.metrics import f1_score, confusion_matrix, precision_recall_curve, roc_curve\n",
116 | "from sklearn.preprocessing import StandardScaler\n",
117 | "from sklearn.linear_model import LogisticRegression\n",
118 | "\n",
119 | "diabetes_data = pd.read_csv('diabetes.csv')\n",
120 | "print(diabetes_data['Outcome'].value_counts())\n",
121 | "diabetes_data.head(3)"
122 | ]
123 | },
124 | {
125 | "cell_type": "markdown",
126 | "metadata": {},
127 | "source": [
128 | "* Pregnancies: 임신 횟수\n",
129 | "* Glucose: 포도당 부하 검사 수치\n",
130 | "* BloodPressure: 혈압(mm Hg)\n",
131 | "* SkinThickness: 팔 삼두근 뒤쪽의 피하지방 측정값(mm)\n",
132 | "* Insulin: 혈청 인슐린(mu U/ml)\n",
133 | "* BMI: 체질량지수(체중(kg)/(키(m))^2)\n",
134 | "* DiabetesPedigreeFunction: 당뇨 내력 가중치 값\n",
135 | "* Age: 나이\n",
136 | "* Outcome: 클래스 결정 값(0또는 1)"
137 | ]
138 | },
139 | {
140 | "cell_type": "code",
141 | "execution_count": 2,
142 | "metadata": {},
143 | "outputs": [
144 | {
145 | "name": "stdout",
146 | "output_type": "stream",
147 | "text": [
148 | "\n",
149 | "RangeIndex: 768 entries, 0 to 767\n",
150 | "Data columns (total 9 columns):\n",
151 | " # Column Non-Null Count Dtype \n",
152 | "--- ------ -------------- ----- \n",
153 | " 0 Pregnancies 768 non-null int64 \n",
154 | " 1 Glucose 768 non-null int64 \n",
155 | " 2 BloodPressure 768 non-null int64 \n",
156 | " 3 SkinThickness 768 non-null int64 \n",
157 | " 4 Insulin 768 non-null int64 \n",
158 | " 5 BMI 768 non-null float64\n",
159 | " 6 DiabetesPedigreeFunction 768 non-null float64\n",
160 | " 7 Age 768 non-null int64 \n",
161 | " 8 Outcome 768 non-null int64 \n",
162 | "dtypes: float64(2), int64(7)\n",
163 | "memory usage: 54.1 KB\n"
164 | ]
165 | }
166 | ],
167 | "source": [
168 | "diabetes_data.info( )"
169 | ]
170 | },
171 | {
172 | "cell_type": "markdown",
173 | "metadata": {},
174 | "source": [
175 | "**앞 예제에서 사용된 get_clf_eval()과 precision_recall_curve_plot() 재 로딩**"
176 | ]
177 | },
178 | {
179 | "cell_type": "code",
180 | "execution_count": 3,
181 | "metadata": {},
182 | "outputs": [],
183 | "source": [
184 | "# 수정된 get_clf_eval() 함수 \n",
185 | "def get_clf_eval(y_test, pred=None, pred_proba=None):\n",
186 | " confusion = confusion_matrix( y_test, pred)\n",
187 | " accuracy = accuracy_score(y_test , pred)\n",
188 | " precision = precision_score(y_test , pred)\n",
189 | " recall = recall_score(y_test , pred)\n",
190 | " f1 = f1_score(y_test,pred)\n",
191 | " # ROC-AUC 추가 \n",
192 | " roc_auc = roc_auc_score(y_test, pred_proba)\n",
193 | " print('오차 행렬')\n",
194 | " print(confusion)\n",
195 | " # ROC-AUC print 추가\n",
196 | " print('정확도: {0:.4f}, 정밀도: {1:.4f}, 재현율: {2:.4f},\\\n",
197 | " F1: {3:.4f}, AUC:{4:.4f}'.format(accuracy, precision, recall, f1, roc_auc))\n"
198 | ]
199 | },
200 | {
201 | "cell_type": "code",
202 | "execution_count": 4,
203 | "metadata": {},
204 | "outputs": [],
205 | "source": [
206 | "def precision_recall_curve_plot(y_test=None, pred_proba_c1=None):\n",
207 | " # threshold ndarray와 이 threshold에 따른 정밀도, 재현율 ndarray 추출. \n",
208 | " precisions, recalls, thresholds = precision_recall_curve( y_test, pred_proba_c1)\n",
209 | " \n",
210 | " # X축을 threshold값으로, Y축은 정밀도, 재현율 값으로 각각 Plot 수행. 정밀도는 점선으로 표시\n",
211 | " plt.figure(figsize=(8,6))\n",
212 | " threshold_boundary = thresholds.shape[0]\n",
213 | " plt.plot(thresholds, precisions[0:threshold_boundary], linestyle='--', label='precision')\n",
214 | " plt.plot(thresholds, recalls[0:threshold_boundary],label='recall')\n",
215 | " \n",
216 | " # threshold 값 X 축의 Scale을 0.1 단위로 변경\n",
217 | " start, end = plt.xlim()\n",
218 | " plt.xticks(np.round(np.arange(start, end, 0.1),2))\n",
219 | " \n",
220 | " # x축, y축 label과 legend, 그리고 grid 설정\n",
221 | " plt.xlabel('Threshold value'); plt.ylabel('Precision and Recall value')\n",
222 | " plt.legend(); plt.grid()\n",
223 | " plt.show()"
224 | ]
225 | },
226 | {
227 | "cell_type": "markdown",
228 | "metadata": {},
229 | "source": [
230 | "**Logistic Regression으로 학습 및 예측 수행**"
231 | ]
232 | },
233 | {
234 | "cell_type": "code",
235 | "execution_count": 5,
236 | "metadata": {},
237 | "outputs": [
238 | {
239 | "name": "stdout",
240 | "output_type": "stream",
241 | "text": [
242 | "오차 행렬\n",
243 | "[[87 13]\n",
244 | " [22 32]]\n",
245 | "정확도: 0.7727, 정밀도: 0.7111, 재현율: 0.5926, F1: 0.6465, AUC:0.8083\n"
246 | ]
247 | }
248 | ],
249 | "source": [
250 | "# 피처 데이터 세트 X, 레이블 데이터 세트 y를 추출. \n",
251 | "# 맨 끝이 Outcome 컬럼으로 레이블 값임. 컬럼 위치 -1을 이용해 추출 \n",
252 | "X = diabetes_data.iloc[:, :-1]\n",
253 | "y = diabetes_data.iloc[:, -1]\n",
254 | "\n",
255 | "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=156, stratify=y)\n",
256 | "\n",
257 | "# 로지스틱 회귀로 학습,예측 및 평가 수행. \n",
258 | "lr_clf = LogisticRegression(solver='liblinear')\n",
259 | "lr_clf.fit(X_train, y_train)\n",
260 | "pred = lr_clf.predict(X_test)\n",
261 | "pred_proba = lr_clf.predict_proba(X_test)[:, 1]\n",
262 | "\n",
263 | "get_clf_eval(y_test , pred, pred_proba)"
264 | ]
265 | },
266 | {
267 | "cell_type": "markdown",
268 | "metadata": {},
269 | "source": [
270 | "**precision recall 곡선 그림**"
271 | ]
272 | },
273 | {
274 | "cell_type": "code",
275 | "execution_count": null,
276 | "metadata": {},
277 | "outputs": [],
278 | "source": [
279 | "pred_proba_c1 = lr_clf.predict_proba(X_test)[:, 1]\n",
280 | "precision_recall_curve_plot(y_test, pred_proba_c1)"
281 | ]
282 | },
283 | {
284 | "cell_type": "markdown",
285 | "metadata": {},
286 | "source": [
287 | "**각 피처들의 값 4분위 분포 확인**"
288 | ]
289 | },
290 | {
291 | "cell_type": "code",
292 | "execution_count": null,
293 | "metadata": {},
294 | "outputs": [],
295 | "source": [
296 | "diabetes_data.describe()"
297 | ]
298 | },
299 | {
300 | "cell_type": "markdown",
301 | "metadata": {},
302 | "source": [
303 | "**Glucose 피처의 분포도**"
304 | ]
305 | },
306 | {
307 | "cell_type": "code",
308 | "execution_count": null,
309 | "metadata": {},
310 | "outputs": [],
311 | "source": [
312 | "plt.hist(diabetes_data['Glucose'], bins=100)\n",
313 | "plt.show()"
314 | ]
315 | },
316 | {
317 | "cell_type": "markdown",
318 | "metadata": {},
319 | "source": [
320 | "**0값이 있는 피처들에서 0값의 데이터 건수와 퍼센트 계산**"
321 | ]
322 | },
323 | {
324 | "cell_type": "code",
325 | "execution_count": null,
326 | "metadata": {},
327 | "outputs": [],
328 | "source": [
329 | "# 0값을 검사할 피처명 리스트 객체 설정\n",
330 | "zero_features = ['Glucose', 'BloodPressure','SkinThickness','Insulin','BMI']\n",
331 | "\n",
332 | "# 전체 데이터 건수\n",
333 | "total_count = diabetes_data['Glucose'].count()\n",
334 | "\n",
335 | "# 피처별로 반복 하면서 데이터 값이 0 인 데이터 건수 추출하고, 퍼센트 계산\n",
336 | "for feature in zero_features:\n",
337 | " zero_count = diabetes_data[diabetes_data[feature] == 0][feature].count()\n",
338 | " print('{0} 0 건수는 {1}, 퍼센트는 {2:.2f} %'.format(feature, zero_count, 100*zero_count/total_count))\n"
339 | ]
340 | },
341 | {
342 | "cell_type": "markdown",
343 | "metadata": {},
344 | "source": [
345 | "**0값을 평균값으로 대체**"
346 | ]
347 | },
348 | {
349 | "cell_type": "code",
350 | "execution_count": null,
351 | "metadata": {},
352 | "outputs": [],
353 | "source": [
354 | "# zero_features 리스트 내부에 저장된 개별 피처들에 대해서 0값을 평균 값으로 대체\n",
355 | "diabetes_data[zero_features] = diabetes_data[zero_features].replace(0, diabetes_data[zero_features].mean())"
356 | ]
357 | },
358 | {
359 | "cell_type": "markdown",
360 | "metadata": {},
361 | "source": [
362 | "**StandardScaler 클래스를 이용해 피처 데이터 세트에 일괄적으로 스케일링 적용하고 0값을 평균값으로 대체한 데이터 세트로 학습/예측**"
363 | ]
364 | },
365 | {
366 | "cell_type": "code",
367 | "execution_count": null,
368 | "metadata": {
369 | "scrolled": true
370 | },
371 | "outputs": [],
372 | "source": [
373 | "X = diabetes_data.iloc[:, :-1]\n",
374 | "y = diabetes_data.iloc[:, -1]\n",
375 | "\n",
376 | "# StandardScaler 클래스를 이용해 피처 데이터 세트에 일괄적으로 스케일링 적용\n",
377 | "scaler = StandardScaler( )\n",
378 | "X_scaled = scaler.fit_transform(X)\n",
379 | "\n",
380 | "X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size = 0.2, random_state = 156, stratify=y)\n",
381 | "\n",
382 | "# 로지스틱 회귀로 학습, 예측 및 평가 수행. \n",
383 | "lr_clf = LogisticRegression(solver='liblinear')\n",
384 | "lr_clf.fit(X_train , y_train)\n",
385 | "pred = lr_clf.predict(X_test)\n",
386 | "pred_proba = lr_clf.predict_proba(X_test)[:, 1]\n",
387 | "\n",
388 | "get_clf_eval(y_test , pred, pred_proba)"
389 | ]
390 | },
391 | {
392 | "cell_type": "markdown",
393 | "metadata": {},
394 | "source": [
395 | "**분류결정 임곗값을 변경하면서 성능 측정**"
396 | ]
397 | },
398 | {
399 | "cell_type": "code",
400 | "execution_count": null,
401 | "metadata": {},
402 | "outputs": [],
403 | "source": [
404 | "from sklearn.preprocessing import Binarizer\n",
405 | "\n",
406 | "def get_eval_by_threshold(y_test , pred_proba_c1, thresholds):\n",
407 | " # thresholds 리스트 객체내의 값을 차례로 iteration하면서 Evaluation 수행.\n",
408 | " for custom_threshold in thresholds:\n",
409 | " binarizer = Binarizer(threshold=custom_threshold).fit(pred_proba_c1) \n",
410 | " custom_predict = binarizer.transform(pred_proba_c1)\n",
411 | " print('임곗값:',custom_threshold)\n",
412 | " get_clf_eval(y_test , custom_predict, pred_proba_c1)"
413 | ]
414 | },
415 | {
416 | "cell_type": "code",
417 | "execution_count": null,
418 | "metadata": {},
419 | "outputs": [],
420 | "source": [
421 | "thresholds = [0.3 , 0.33 ,0.36,0.39, 0.42 , 0.45 ,0.48, 0.50]\n",
422 | "pred_proba = lr_clf.predict_proba(X_test)\n",
423 | "get_eval_by_threshold(y_test, pred_proba[:,1].reshape(-1,1), thresholds )"
424 | ]
425 | },
426 | {
427 | "cell_type": "code",
428 | "execution_count": null,
429 | "metadata": {},
430 | "outputs": [],
431 | "source": [
432 | "# 임곗값를 0.48로 설정한 Binarizer 생성\n",
433 | "binarizer = Binarizer(threshold=0.48)\n",
434 | "\n",
435 | "# 위에서 구한 lr_clf의 predict_proba() 예측 확률 array에서 1에 해당하는 컬럼값을 Binarizer변환. \n",
436 | "pred_th_048 = binarizer.fit_transform(pred_proba[:, 1].reshape(-1,1)) \n",
437 | "\n",
438 | "get_clf_eval(y_test , pred_th_048, pred_proba[:, 1])"
439 | ]
440 | },
441 | {
442 | "cell_type": "code",
443 | "execution_count": null,
444 | "metadata": {},
445 | "outputs": [],
446 | "source": []
447 | }
448 | ],
449 | "metadata": {
450 | "kernelspec": {
451 | "display_name": "Python 3 (ipykernel)",
452 | "language": "python",
453 | "name": "python3"
454 | },
455 | "language_info": {
456 | "codemirror_mode": {
457 | "name": "ipython",
458 | "version": 3
459 | },
460 | "file_extension": ".py",
461 | "mimetype": "text/x-python",
462 | "name": "python",
463 | "nbconvert_exporter": "python",
464 | "pygments_lexer": "ipython3",
465 | "version": "3.9.7"
466 | }
467 | },
468 | "nbformat": 4,
469 | "nbformat_minor": 2
470 | }
471 |
--------------------------------------------------------------------------------
/4장/4.11_스태킹앙상블.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import numpy as np\n",
10 | "\n",
11 | "from sklearn.neighbors import KNeighborsClassifier\n",
12 | "from sklearn.ensemble import RandomForestClassifier\n",
13 | "from sklearn.ensemble import AdaBoostClassifier\n",
14 | "from sklearn.tree import DecisionTreeClassifier\n",
15 | "from sklearn.linear_model import LogisticRegression\n",
16 | "\n",
17 | "from sklearn.datasets import load_breast_cancer\n",
18 | "from sklearn.model_selection import train_test_split\n",
19 | "from sklearn.metrics import accuracy_score\n",
20 | "\n",
21 | "cancer_data = load_breast_cancer()\n",
22 | "\n",
23 | "X_data = cancer_data.data\n",
24 | "y_label = cancer_data.target\n",
25 | "\n",
26 | "X_train , X_test , y_train , y_test = train_test_split(X_data , y_label , test_size=0.2 , random_state=0)"
27 | ]
28 | },
29 | {
30 | "cell_type": "code",
31 | "execution_count": 2,
32 | "metadata": {},
33 | "outputs": [],
34 | "source": [
35 | "# 개별 ML 모델을 위한 Classifier 생성.\n",
36 | "knn_clf = KNeighborsClassifier(n_neighbors=4)\n",
37 | "rf_clf = RandomForestClassifier(n_estimators=100, random_state=0)\n",
38 | "dt_clf = DecisionTreeClassifier()\n",
39 | "ada_clf = AdaBoostClassifier(n_estimators=100)\n",
40 | "\n",
41 | "# 최종 Stacking 모델을 위한 Classifier생성. \n",
42 | "lr_final = LogisticRegression()\n"
43 | ]
44 | },
45 | {
46 | "cell_type": "code",
47 | "execution_count": 3,
48 | "metadata": {},
49 | "outputs": [
50 | {
51 | "data": {
52 | "text/plain": [
53 | "AdaBoostClassifier(n_estimators=100)"
54 | ]
55 | },
56 | "execution_count": 3,
57 | "metadata": {},
58 | "output_type": "execute_result"
59 | }
60 | ],
61 | "source": [
62 | "# 개별 모델들을 학습. \n",
63 | "knn_clf.fit(X_train, y_train)\n",
64 | "rf_clf.fit(X_train , y_train)\n",
65 | "dt_clf.fit(X_train , y_train)\n",
66 | "ada_clf.fit(X_train, y_train)"
67 | ]
68 | },
69 | {
70 | "cell_type": "code",
71 | "execution_count": 4,
72 | "metadata": {},
73 | "outputs": [
74 | {
75 | "name": "stdout",
76 | "output_type": "stream",
77 | "text": [
78 | "KNN 정확도: 0.9211\n",
79 | "랜덤 포레스트 정확도: 0.9649\n",
80 | "결정 트리 정확도: 0.9123\n",
81 | "에이다부스트 정확도: 0.9561\n"
82 | ]
83 | }
84 | ],
85 | "source": [
86 | "# 학습된 개별 모델들이 각자 반환하는 예측 데이터 셋을 생성하고 개별 모델의 정확도 측정. \n",
87 | "knn_pred = knn_clf.predict(X_test)\n",
88 | "rf_pred = rf_clf.predict(X_test)\n",
89 | "dt_pred = dt_clf.predict(X_test)\n",
90 | "ada_pred = ada_clf.predict(X_test)\n",
91 | "\n",
92 | "print('KNN 정확도: {0:.4f}'.format(accuracy_score(y_test, knn_pred)))\n",
93 | "print('랜덤 포레스트 정확도: {0:.4f}'.format(accuracy_score(y_test, rf_pred)))\n",
94 | "print('결정 트리 정확도: {0:.4f}'.format(accuracy_score(y_test, dt_pred)))\n",
95 | "print('에이다부스트 정확도: {0:.4f}'.format(accuracy_score(y_test, ada_pred)))"
96 | ]
97 | },
98 | {
99 | "cell_type": "code",
100 | "execution_count": 5,
101 | "metadata": {},
102 | "outputs": [
103 | {
104 | "name": "stdout",
105 | "output_type": "stream",
106 | "text": [
107 | "(4, 114)\n",
108 | "(114, 4)\n"
109 | ]
110 | }
111 | ],
112 | "source": [
113 | "pred = np.array([knn_pred, rf_pred, dt_pred, ada_pred])\n",
114 | "print(pred.shape)\n",
115 | "\n",
116 | "# transpose를 이용해 행과 열의 위치 교환. 컬럼 레벨로 각 알고리즘의 예측 결과를 피처로 만듦. \n",
117 | "pred = np.transpose(pred)\n",
118 | "print(pred.shape)"
119 | ]
120 | },
121 | {
122 | "cell_type": "code",
123 | "execution_count": 6,
124 | "metadata": {},
125 | "outputs": [
126 | {
127 | "name": "stdout",
128 | "output_type": "stream",
129 | "text": [
130 | "최종 메타 모델의 예측 정확도: 0.9737\n"
131 | ]
132 | }
133 | ],
134 | "source": [
135 | "lr_final.fit(pred, y_test)\n",
136 | "final = lr_final.predict(pred)\n",
137 | "\n",
138 | "print('최종 메타 모델의 예측 정확도: {0:.4f}'.format(accuracy_score(y_test , final)))"
139 | ]
140 | },
141 | {
142 | "cell_type": "markdown",
143 | "metadata": {},
144 | "source": [
145 | "### CV 셋 기반의 Stacking"
146 | ]
147 | },
148 | {
149 | "cell_type": "code",
150 | "execution_count": 7,
151 | "metadata": {},
152 | "outputs": [],
153 | "source": [
154 | "from sklearn.model_selection import KFold\n",
155 | "from sklearn.metrics import mean_absolute_error\n",
156 | "\n",
157 | "# 개별 기반 모델에서 최종 메타 모델이 사용할 학습 및 테스트용 데이터를 생성하기 위한 함수. \n",
158 | "def get_stacking_base_datasets(model, X_train_n, y_train_n, X_test_n, n_folds ):\n",
159 | " # 지정된 n_folds값으로 KFold 생성.\n",
160 | " kf = KFold(n_splits=n_folds, shuffle=False)\n",
161 | " #추후에 메타 모델이 사용할 학습 데이터 반환을 위한 넘파이 배열 초기화 \n",
162 | " train_fold_pred = np.zeros((X_train_n.shape[0] ,1 ))\n",
163 | " test_pred = np.zeros((X_test_n.shape[0],n_folds))\n",
164 | " print(model.__class__.__name__ , ' model 시작 ')\n",
165 | " \n",
166 | " for folder_counter , (train_index, valid_index) in enumerate(kf.split(X_train_n)):\n",
167 | " #입력된 학습 데이터에서 기반 모델이 학습/예측할 폴드 데이터 셋 추출 \n",
168 | " print('\\t 폴드 세트: ',folder_counter,' 시작 ')\n",
169 | " X_tr = X_train_n[train_index] \n",
170 | " y_tr = y_train_n[train_index] \n",
171 | " X_te = X_train_n[valid_index] \n",
172 | " \n",
173 | " #폴드 세트 내부에서 다시 만들어진 학습 데이터로 기반 모델의 학습 수행.\n",
174 | " model.fit(X_tr , y_tr) \n",
175 | " #폴드 세트 내부에서 다시 만들어진 검증 데이터로 기반 모델 예측 후 데이터 저장.\n",
176 | " train_fold_pred[valid_index, :] = model.predict(X_te).reshape(-1,1)\n",
177 | " #입력된 원본 테스트 데이터를 폴드 세트내 학습된 기반 모델에서 예측 후 데이터 저장. \n",
178 | " test_pred[:, folder_counter] = model.predict(X_test_n)\n",
179 | " \n",
180 | " # 폴드 세트 내에서 원본 테스트 데이터를 예측한 데이터를 평균하여 테스트 데이터로 생성 \n",
181 | " test_pred_mean = np.mean(test_pred, axis=1).reshape(-1,1) \n",
182 | " \n",
183 | " #train_fold_pred는 최종 메타 모델이 사용하는 학습 데이터, test_pred_mean은 테스트 데이터\n",
184 | " return train_fold_pred , test_pred_mean"
185 | ]
186 | },
187 | {
188 | "cell_type": "code",
189 | "execution_count": 8,
190 | "metadata": {},
191 | "outputs": [
192 | {
193 | "name": "stdout",
194 | "output_type": "stream",
195 | "text": [
196 | "KNeighborsClassifier model 시작 \n",
197 | "\t 폴드 세트: 0 시작 \n",
198 | "\t 폴드 세트: 1 시작 \n",
199 | "\t 폴드 세트: 2 시작 \n",
200 | "\t 폴드 세트: 3 시작 \n",
201 | "\t 폴드 세트: 4 시작 \n",
202 | "\t 폴드 세트: 5 시작 \n",
203 | "\t 폴드 세트: 6 시작 \n",
204 | "RandomForestClassifier model 시작 \n",
205 | "\t 폴드 세트: 0 시작 \n",
206 | "\t 폴드 세트: 1 시작 \n",
207 | "\t 폴드 세트: 2 시작 \n",
208 | "\t 폴드 세트: 3 시작 \n",
209 | "\t 폴드 세트: 4 시작 \n",
210 | "\t 폴드 세트: 5 시작 \n",
211 | "\t 폴드 세트: 6 시작 \n",
212 | "DecisionTreeClassifier model 시작 \n",
213 | "\t 폴드 세트: 0 시작 \n",
214 | "\t 폴드 세트: 1 시작 \n",
215 | "\t 폴드 세트: 2 시작 \n",
216 | "\t 폴드 세트: 3 시작 \n",
217 | "\t 폴드 세트: 4 시작 \n",
218 | "\t 폴드 세트: 5 시작 \n",
219 | "\t 폴드 세트: 6 시작 \n",
220 | "AdaBoostClassifier model 시작 \n",
221 | "\t 폴드 세트: 0 시작 \n",
222 | "\t 폴드 세트: 1 시작 \n",
223 | "\t 폴드 세트: 2 시작 \n",
224 | "\t 폴드 세트: 3 시작 \n",
225 | "\t 폴드 세트: 4 시작 \n",
226 | "\t 폴드 세트: 5 시작 \n",
227 | "\t 폴드 세트: 6 시작 \n"
228 | ]
229 | }
230 | ],
231 | "source": [
232 | "knn_train, knn_test = get_stacking_base_datasets(knn_clf, X_train, y_train, X_test, 7)\n",
233 | "rf_train, rf_test = get_stacking_base_datasets(rf_clf, X_train, y_train, X_test, 7)\n",
234 | "dt_train, dt_test = get_stacking_base_datasets(dt_clf, X_train, y_train, X_test, 7) \n",
235 | "ada_train, ada_test = get_stacking_base_datasets(ada_clf, X_train, y_train, X_test, 7)"
236 | ]
237 | },
238 | {
239 | "cell_type": "code",
240 | "execution_count": 9,
241 | "metadata": {},
242 | "outputs": [
243 | {
244 | "name": "stdout",
245 | "output_type": "stream",
246 | "text": [
247 | "원본 학습 피처 데이터 Shape: (455, 30) 원본 테스트 피처 Shape: (114, 30)\n",
248 | "스태킹 학습 피처 데이터 Shape: (455, 4) 스태킹 테스트 피처 데이터 Shape: (114, 4)\n"
249 | ]
250 | }
251 | ],
252 | "source": [
253 | "Stack_final_X_train = np.concatenate((knn_train, rf_train, dt_train, ada_train), axis=1)\n",
254 | "Stack_final_X_test = np.concatenate((knn_test, rf_test, dt_test, ada_test), axis=1)\n",
255 | "print('원본 학습 피처 데이터 Shape:',X_train.shape, '원본 테스트 피처 Shape:',X_test.shape)\n",
256 | "print('스태킹 학습 피처 데이터 Shape:', Stack_final_X_train.shape,\n",
257 | " '스태킹 테스트 피처 데이터 Shape:',Stack_final_X_test.shape)"
258 | ]
259 | },
260 | {
261 | "cell_type": "code",
262 | "execution_count": 10,
263 | "metadata": {},
264 | "outputs": [
265 | {
266 | "name": "stdout",
267 | "output_type": "stream",
268 | "text": [
269 | "최종 메타 모델의 예측 정확도: 0.9825\n"
270 | ]
271 | }
272 | ],
273 | "source": [
274 | "lr_final.fit(Stack_final_X_train, y_train)\n",
275 | "stack_final = lr_final.predict(Stack_final_X_test)\n",
276 | "\n",
277 | "print('최종 메타 모델의 예측 정확도: {0:.4f}'.format(accuracy_score(y_test, stack_final)))"
278 | ]
279 | },
280 | {
281 | "cell_type": "code",
282 | "execution_count": null,
283 | "metadata": {},
284 | "outputs": [],
285 | "source": []
286 | },
287 | {
288 | "cell_type": "code",
289 | "execution_count": null,
290 | "metadata": {},
291 | "outputs": [],
292 | "source": []
293 | }
294 | ],
295 | "metadata": {
296 | "kernelspec": {
297 | "display_name": "Python 3 (ipykernel)",
298 | "language": "python",
299 | "name": "python3"
300 | },
301 | "language_info": {
302 | "codemirror_mode": {
303 | "name": "ipython",
304 | "version": 3
305 | },
306 | "file_extension": ".py",
307 | "mimetype": "text/x-python",
308 | "name": "python",
309 | "nbconvert_exporter": "python",
310 | "pygments_lexer": "ipython3",
311 | "version": "3.9.7"
312 | }
313 | },
314 | "nbformat": 4,
315 | "nbformat_minor": 2
316 | }
317 |
--------------------------------------------------------------------------------
/5장/5.7_로지스틱 회귀_5.8_회귀 트리.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "## 로지스틱 회귀"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": null,
13 | "metadata": {},
14 | "outputs": [],
15 | "source": [
16 | "import pandas as pd\n",
17 | "import matplotlib.pyplot as plt\n",
18 | "%matplotlib inline\n",
19 | "\n",
20 | "from sklearn.datasets import load_breast_cancer\n",
21 | "from sklearn.linear_model import LogisticRegression\n",
22 | "\n",
23 | "cancer = load_breast_cancer()"
24 | ]
25 | },
26 | {
27 | "cell_type": "code",
28 | "execution_count": null,
29 | "metadata": {},
30 | "outputs": [],
31 | "source": [
32 | "from sklearn.preprocessing import StandardScaler\n",
33 | "from sklearn.model_selection import train_test_split\n",
34 | "\n",
35 | "# StandardScaler( )로 평균이 0, 분산 1로 데이터 분포도 변환\n",
36 | "scaler = StandardScaler()\n",
37 | "data_scaled = scaler.fit_transform(cancer.data)\n",
38 | "\n",
39 | "X_train , X_test, y_train , y_test = train_test_split(data_scaled, cancer.target, test_size=0.3, random_state=0)"
40 | ]
41 | },
42 | {
43 | "cell_type": "code",
44 | "execution_count": null,
45 | "metadata": {},
46 | "outputs": [],
47 | "source": [
48 | "from sklearn.metrics import accuracy_score, roc_auc_score\n",
49 | "\n",
50 | "# 로지스틱 회귀를 이용하여 학습 및 예측 수행. \n",
51 | "# solver인자값을 생성자로 입력하지 않으면 solver='lbfgs' \n",
52 | "lr_clf = LogisticRegression() # solver='lbfgs'\n",
53 | "lr_clf.fit(X_train, y_train)\n",
54 | "lr_preds = lr_clf.predict(X_test)\n",
55 | "\n",
56 | "# accuracy와 roc_auc 측정\n",
57 | "print('accuracy: {0:.3f}, roc_auc:{1:.3f}'.format(accuracy_score(y_test, lr_preds),\n",
58 | " roc_auc_score(y_test , lr_preds)))"
59 | ]
60 | },
61 | {
62 | "cell_type": "code",
63 | "execution_count": null,
64 | "metadata": {},
65 | "outputs": [],
66 | "source": [
67 | "solvers = ['lbfgs', 'liblinear', 'newton-cg', 'sag', 'saga']\n",
68 | "# 여러개의 solver값 별로 LogisticRegression 학습 후 성능 평가\n",
69 | "for solver in solvers:\n",
70 | " lr_clf = LogisticRegression(solver=solver, max_iter=600)\n",
71 | " lr_clf.fit(X_train, y_train)\n",
72 | " lr_preds = lr_clf.predict(X_test)\n",
73 | "\n",
74 | " # accuracy와 roc_auc 측정\n",
75 | " print('solver:{0}, accuracy: {1:.3f}, roc_auc:{2:.3f}'.format(solver, \n",
76 | " accuracy_score(y_test, lr_preds),\n",
77 | " roc_auc_score(y_test , lr_preds))) "
78 | ]
79 | },
80 | {
81 | "cell_type": "code",
82 | "execution_count": null,
83 | "metadata": {},
84 | "outputs": [],
85 | "source": [
86 | "from sklearn.model_selection import GridSearchCV\n",
87 | "\n",
88 | "params={'solver':['liblinear', 'lbfgs'],\n",
89 | " 'penalty':['l2', 'l1'],\n",
90 | " 'C':[0.01, 0.1, 1, 1, 5, 10]}\n",
91 | "\n",
92 | "lr_clf = LogisticRegression()\n",
93 | "\n",
94 | "grid_clf = GridSearchCV(lr_clf, param_grid=params, scoring='accuracy', cv=3 )\n",
95 | "grid_clf.fit(data_scaled, cancer.target)\n",
96 | "print('최적 하이퍼 파라미터:{0}, 최적 평균 정확도:{1:.3f}'.format(grid_clf.best_params_, \n",
97 | " grid_clf.best_score_))"
98 | ]
99 | },
100 | {
101 | "cell_type": "markdown",
102 | "metadata": {},
103 | "source": [
104 | "## 5.8 회귀 트리"
105 | ]
106 | },
107 | {
108 | "cell_type": "code",
109 | "execution_count": null,
110 | "metadata": {},
111 | "outputs": [],
112 | "source": [
113 | "from sklearn.datasets import load_boston\n",
114 | "from sklearn.model_selection import cross_val_score\n",
115 | "from sklearn.ensemble import RandomForestRegressor\n",
116 | "import pandas as pd\n",
117 | "import numpy as np\n",
118 | "import warnings\n",
119 | "warnings.filterwarnings('ignore') #사이킷런 1.2 부터는 보스턴 주택가격 데이터가 없어진다는 warning 메시지 출력 제거\n",
120 | "\n",
121 | "# 보스턴 데이터 세트 로드\n",
122 | "boston = load_boston()\n",
123 | "bostonDF = pd.DataFrame(boston.data, columns = boston.feature_names)\n",
124 | "\n",
125 | "bostonDF['PRICE'] = boston.target\n",
126 | "y_target = bostonDF['PRICE']\n",
127 | "X_data = bostonDF.drop(['PRICE'], axis=1,inplace=False)\n",
128 | "\n",
129 | "rf = RandomForestRegressor(random_state=0, n_estimators=1000)\n",
130 | "neg_mse_scores = cross_val_score(rf, X_data, y_target, scoring=\"neg_mean_squared_error\", cv = 5)\n",
131 | "rmse_scores = np.sqrt(-1 * neg_mse_scores)\n",
132 | "avg_rmse = np.mean(rmse_scores)\n",
133 | "\n",
134 | "print(' 5 교차 검증의 개별 Negative MSE scores: ', np.round(neg_mse_scores, 2))\n",
135 | "print(' 5 교차 검증의 개별 RMSE scores : ', np.round(rmse_scores, 2))\n",
136 | "print(' 5 교차 검증의 평균 RMSE : {0:.3f} '.format(avg_rmse))\n"
137 | ]
138 | },
139 | {
140 | "cell_type": "code",
141 | "execution_count": null,
142 | "metadata": {},
143 | "outputs": [],
144 | "source": [
145 | "def get_model_cv_prediction(model, X_data, y_target):\n",
146 | " neg_mse_scores = cross_val_score(model, X_data, y_target, scoring=\"neg_mean_squared_error\", cv = 5)\n",
147 | " rmse_scores = np.sqrt(-1 * neg_mse_scores)\n",
148 | " avg_rmse = np.mean(rmse_scores)\n",
149 | " print('##### ',model.__class__.__name__ , ' #####')\n",
150 | " print(' 5 교차 검증의 평균 RMSE : {0:.3f} '.format(avg_rmse))"
151 | ]
152 | },
153 | {
154 | "cell_type": "code",
155 | "execution_count": null,
156 | "metadata": {},
157 | "outputs": [],
158 | "source": [
159 | "from sklearn.tree import DecisionTreeRegressor\n",
160 | "from sklearn.ensemble import GradientBoostingRegressor\n",
161 | "from xgboost import XGBRegressor\n",
162 | "from lightgbm import LGBMRegressor\n",
163 | "\n",
164 | "dt_reg = DecisionTreeRegressor(random_state=0, max_depth=4)\n",
165 | "rf_reg = RandomForestRegressor(random_state=0, n_estimators=1000)\n",
166 | "gb_reg = GradientBoostingRegressor(random_state=0, n_estimators=1000)\n",
167 | "xgb_reg = XGBRegressor(n_estimators=1000)\n",
168 | "lgb_reg = LGBMRegressor(n_estimators=1000)\n",
169 | "\n",
170 | "# 트리 기반의 회귀 모델을 반복하면서 평가 수행 \n",
171 | "models = [dt_reg, rf_reg, gb_reg, xgb_reg, lgb_reg]\n",
172 | "for model in models: \n",
173 | " get_model_cv_prediction(model, X_data, y_target)"
174 | ]
175 | },
176 | {
177 | "cell_type": "code",
178 | "execution_count": null,
179 | "metadata": {},
180 | "outputs": [],
181 | "source": [
182 | "import seaborn as sns\n",
183 | "%matplotlib inline\n",
184 | "\n",
185 | "rf_reg = RandomForestRegressor(n_estimators=1000)\n",
186 | "\n",
187 | "# 앞 예제에서 만들어진 X_data, y_target 데이터 셋을 적용하여 학습합니다. \n",
188 | "rf_reg.fit(X_data, y_target)\n",
189 | "\n",
190 | "feature_series = pd.Series(data=rf_reg.feature_importances_, index=X_data.columns)\n",
191 | "feature_series = feature_series.sort_values(ascending=False)\n",
192 | "sns.barplot(x= feature_series, y=feature_series.index)\n"
193 | ]
194 | },
195 | {
196 | "cell_type": "code",
197 | "execution_count": null,
198 | "metadata": {},
199 | "outputs": [],
200 | "source": [
201 | "import matplotlib.pyplot as plt\n",
202 | "%matplotlib inline\n",
203 | "\n",
204 | "bostonDF_sample = bostonDF[['RM','PRICE']]\n",
205 | "bostonDF_sample = bostonDF_sample.sample(n=100,random_state=0)\n",
206 | "print(bostonDF_sample.shape)\n",
207 | "plt.figure()\n",
208 | "plt.scatter(bostonDF_sample.RM , bostonDF_sample.PRICE,c=\"darkorange\")"
209 | ]
210 | },
211 | {
212 | "cell_type": "code",
213 | "execution_count": null,
214 | "metadata": {},
215 | "outputs": [],
216 | "source": [
217 | "import numpy as np\n",
218 | "from sklearn.linear_model import LinearRegression\n",
219 | "\n",
220 | "# 선형 회귀와 결정 트리 기반의 Regressor 생성. DecisionTreeRegressor의 max_depth는 각각 2, 7\n",
221 | "lr_reg = LinearRegression()\n",
222 | "rf_reg2 = DecisionTreeRegressor(max_depth=2)\n",
223 | "rf_reg7 = DecisionTreeRegressor(max_depth=7)\n",
224 | "\n",
225 | "# 실제 예측을 적용할 테스트용 데이터 셋을 4.5 ~ 8.5 까지 100개 데이터 셋 생성. \n",
226 | "X_test = np.arange(4.5, 8.5, 0.04).reshape(-1, 1)\n",
227 | "\n",
228 | "# 보스턴 주택가격 데이터에서 시각화를 위해 피처는 RM만, 그리고 결정 데이터인 PRICE 추출\n",
229 | "X_feature = bostonDF_sample['RM'].values.reshape(-1,1)\n",
230 | "y_target = bostonDF_sample['PRICE'].values.reshape(-1,1)\n",
231 | "\n",
232 | "# 학습과 예측 수행. \n",
233 | "lr_reg.fit(X_feature, y_target)\n",
234 | "rf_reg2.fit(X_feature, y_target)\n",
235 | "rf_reg7.fit(X_feature, y_target)\n",
236 | "\n",
237 | "pred_lr = lr_reg.predict(X_test)\n",
238 | "pred_rf2 = rf_reg2.predict(X_test)\n",
239 | "pred_rf7 = rf_reg7.predict(X_test)\n"
240 | ]
241 | },
242 | {
243 | "cell_type": "code",
244 | "execution_count": null,
245 | "metadata": {},
246 | "outputs": [],
247 | "source": [
248 | "fig , (ax1, ax2, ax3) = plt.subplots(figsize=(14,4), ncols=3)\n",
249 | "\n",
250 | "# X축값을 4.5 ~ 8.5로 변환하며 입력했을 때, 선형 회귀와 결정 트리 회귀 예측 선 시각화\n",
251 | "# 선형 회귀로 학습된 모델 회귀 예측선 \n",
252 | "ax1.set_title('Linear Regression')\n",
253 | "ax1.scatter(bostonDF_sample.RM, bostonDF_sample.PRICE, c=\"darkorange\")\n",
254 | "ax1.plot(X_test, pred_lr,label=\"linear\", linewidth=2 )\n",
255 | "\n",
256 | "# DecisionTreeRegressor의 max_depth를 2로 했을 때 회귀 예측선 \n",
257 | "ax2.set_title('Decision Tree Regression: \\n max_depth=2')\n",
258 | "ax2.scatter(bostonDF_sample.RM, bostonDF_sample.PRICE, c=\"darkorange\")\n",
259 | "ax2.plot(X_test, pred_rf2, label=\"max_depth:2\", linewidth=2 )\n",
260 | "\n",
261 | "# DecisionTreeRegressor의 max_depth를 7로 했을 때 회귀 예측선 \n",
262 | "ax3.set_title('Decision Tree Regression: \\n max_depth=7')\n",
263 | "ax3.scatter(bostonDF_sample.RM, bostonDF_sample.PRICE, c=\"darkorange\")\n",
264 | "ax3.plot(X_test, pred_rf7, label=\"max_depth:7\", linewidth=2)"
265 | ]
266 | },
267 | {
268 | "cell_type": "code",
269 | "execution_count": null,
270 | "metadata": {},
271 | "outputs": [],
272 | "source": []
273 | }
274 | ],
275 | "metadata": {
276 | "kernelspec": {
277 | "display_name": "Python 3 (ipykernel)",
278 | "language": "python",
279 | "name": "python3"
280 | },
281 | "language_info": {
282 | "codemirror_mode": {
283 | "name": "ipython",
284 | "version": 3
285 | },
286 | "file_extension": ".py",
287 | "mimetype": "text/x-python",
288 | "name": "python",
289 | "nbconvert_exporter": "python",
290 | "pygments_lexer": "ipython3",
291 | "version": "3.9.7"
292 | }
293 | },
294 | "nbformat": 4,
295 | "nbformat_minor": 2
296 | }
297 |
--------------------------------------------------------------------------------
/6장/6-3_LDA(Linear Discriminant Analysis).ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### 붓꽃 데이터 셋에 LDA 적용하기 "
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": 2,
13 | "metadata": {},
14 | "outputs": [],
15 | "source": [
16 | "from sklearn.discriminant_analysis import LinearDiscriminantAnalysis\n",
17 | "from sklearn.preprocessing import StandardScaler\n",
18 | "from sklearn.datasets import load_iris\n",
19 | "\n",
20 | "iris = load_iris()\n",
21 | "iris_scaled = StandardScaler().fit_transform(iris.data)"
22 | ]
23 | },
24 | {
25 | "cell_type": "code",
26 | "execution_count": 3,
27 | "metadata": {},
28 | "outputs": [
29 | {
30 | "name": "stdout",
31 | "output_type": "stream",
32 | "text": [
33 | "(150, 2)\n"
34 | ]
35 | }
36 | ],
37 | "source": [
38 | "lda = LinearDiscriminantAnalysis(n_components=2)\n",
39 | "# fit()호출 시 target값 입력 \n",
40 | "lda.fit(iris_scaled, iris.target)\n",
41 | "iris_lda = lda.transform(iris_scaled)\n",
42 | "print(iris_lda.shape)"
43 | ]
44 | },
45 | {
46 | "cell_type": "code",
47 | "execution_count": 4,
48 | "metadata": {},
49 | "outputs": [
50 | {
51 | "data": {
52 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYgAAAELCAYAAADDZxFQAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzt3Xl8VPW9+P/XOyEQWRS9gkQoCLW4oCiIimhxo2gNam3hyr22ar3+LNoqdvuqaGva+u3PpRvcVvlZr+JtaQVR0BatIEgRBTEgi4gs0qhhC4sJa0KW9++PORMnyZnJnJkzc2Z5Px+PeZg5c5YPJ/G857O9P6KqGGOMMa0VBF0AY4wxmckChDHGGFcWIIwxxriyAGGMMcaVBQhjjDGuLEAYY4xxZQHCGGOMKwsQxhhjXAUaIESkWESWi8hqEVknIj8LsjzGGGM+J0HOpBYRAbqo6gERKQKWABNVdVm0Y44//ng96aST0lVEY4zJCStWrNitqj28HNMhVYWJh4ai0wHnbZHzihmxTjrpJMrLy1NdNGOMySki8rHXYwLvgxCRQhFZBVQB81X1HZd9bhORchEp37VrV/oLaYwxeSjwAKGqjap6NtAHOE9EznDZ50lVHaaqw3r08FRDMsYYk6DAA0SYqlYDi4ArAy6KMcYYAu6DEJEeQL2qVovIUcAo4JEgy2SMSa/6+noqKyupra0Nuig5obi4mD59+lBUVJT0uQINEEAJ8KyIFBKqzcxU1b8HXCZjTBpVVlbSrVs3TjrpJEIDG02iVJU9e/ZQWVlJ//79kz5f0KOY1gBDgiyDMSZYtbW1Fhx8IiL827/9G34N5smYPohMUrWvlpGPvkHVfqvyGpMOFhz84+e9tADhYsqCTXz62SGmLNgcdFGMMSYwFiBaqdpXy/MrKlGFWeWfWi3CmDxQXVfNxr0bWbd7HRv3bqS6rjrqvtOmTWPbtm1pLF1wLEC0MmXBJpqc9CONqlaLMCbHVddVs+3ANuqb6gGob6pn24FtUYOEBYg8Fa491DeGAkR9o1otwpgM5Gc/YdXBKg4eOMjt/3E7X7/k63zty1/jlRdfYeFbC7n44os555xzuOKKK9i+fTuzZs2ivLycG264gbPPPpvDhw+zYMEChgwZwplnnsktt9xCXV0dAPfeey+nn346gwcP5kc/+hEAf/vb3zj//PMZMmQIo0aNYufOnUmXP5UsQESIrD2EWS3CmMzjZz9hfVM9by18i569evLioheZ8+YcLrr8In5+78+ZNWsWK1as4JZbbuH+++9n7NixDBs2jOnTp7Nq1SpEhJtvvpkZM2awdu1aGhoaeOKJJ9i7dy+zZ89m3bp1rFmzhgceeACAiy66iGXLlvHee+8xfvx4Hn300aTLn0oWICLMX7+zufYQVt+ozP9gR0AlMsa05nc/YVFBEV86/UssW7yM3/z8N6xYuoIdW3ewef1mvvKVr3D22Wfz0EMPUVlZ2ebYDRs20L9/fwYOHAjATTfdxOLFizn66KMpLi7m1ltv5cUXX6Rz585AaM7HFVdcwZlnnsljjz3GunXrkip7qgU9US6jvDNpVNBFMMa0w62f8KGvtUnhFreeXXrScHIDM1+fyeLXF/O7h37HiEtGcPqg01m+bHnMY6Mtl9ChQweWL1/OggULeO655/j973/PwoULufPOO/nBD37ANddcw6JFiygrK0u43OlgNQhjTNZIRT9h907dkX1Cty7duHrc1dz6vVvZsHoDe3fvZenSpaHr1Nc3f9vv1q0b+/fvB+DUU0+loqKCzZtDTV1/+tOfuPjiizlw4AA1NTVcddVV/O53v2PVqlUA1NTU0Lt3bwCeffbZhMucLlaDMMZkjVj9hMnUIj7Z+Ak//vGPKSgooKioiCeeeIIOHTpw1113UVNTQ0NDA3fffTeDBg3i5ptvZsKECRx11FEsXbqUZ555hnHjxtHQ0MC5557LhAkT2Lt3L9deey21tbWoKr/97W8BKCsrY9y4cfTu3Zvhw4fzr3/9K6n7kWqBriiXiGHDhqktGGRM7li/fj2nnXZaXPue/8vX2bmvrs32E47uZE3EEdzuqYisUNVhXs5jNQhjTNawIJBeFiCMMXmluq6aqoNV1DfVU1RQRM8uPeneqXvQxcpIFiCMMXkjPGs63LQenjV9qP4QB44csKDRigUIY0zeqDpY1WZoqqryWe1nze/DQQPI+yBhw1yNMXkjnG+pPapK1cGqFJcm81kNwhiTE+LpWygqKIo7SMS7Xy6zGoQxJuvFm5G1Z5eecS+oU1SQ+JrOP/3pT3n99dc9H7do0SLGjBmT8HX9ZjUIY0zWi9a3UHWwqkUtIvxzZE2ja8euVNdVtzheROjZpWfMa6oqqkpBQdvv2T//+c+T+efEraGhgQ4dUvcYtwBhjMkev+wNRw602fzFos58+J2239jdmom6d+reImjcc8899Ojdg2u+eQ31TfVMfWwqJxx3Ap0KOjFz5kzq6uq47rrr+NnPfkZFRQVf/epXufTSS1m6dClz5szhwQcfpLy8HBHhlltu4fvf/z4333wzY8aMYezYsbz77rtMnDiRgwcP0qlTJxYsWEBRURG333475eXldOjQgd/85jdceumlLcq5d+9ebrnlFrZs2ULnzp158sknGTx4MGVlZWzbto2KigqOP/54/vKXv/hwY91ZgDDGZA+X4ABQWH/IdXs8zUTjx4/n7rvv5kd3hdZsWPC3Bdx7770sWbKE5cuXo6pcc801LF68mL59+7JhwwaeeeYZHn/8cVasWMHWrVt5//33AaiubtmkdeTIEa6//npmzJjBueeey759+zjqqKOYPHkyAGvXruXDDz9k9OjRbNy4scWxDz74IEOGDGHOnDksXLiQG2+8sTmn04oVK1iyZAlHHXVUu/++ZFiAMMbkBBHx3EwEMGTIEKqqqti2bRu7du3i2GOPZc2aNcybN48hQ4YAcODAATZt2kTfvn3p168fw4cPB2DAgAFs2bKFO++8k9LSUkaPHt3i3Bs2bKCkpIRzzz0XgKOPPhqAJUuWcOeddwKhhH/9+vVrEyCWLFnCCy+8AMBll13Gnj17qKmpAeCaa65JeXAACxDGmBxxYtcTE54hPXbsWGbNmsWOHTsYP348FRUV3HfffXznO99psV9FRQVdunRpfn/ssceyevVqXnvtNf7whz8wc+ZMnn766ebPVdW1UzyeHHhu+4TPFVmGVLJRTMaYnNC9U3cGHjeQQccPYuBxAz1Nchs/fjzPPfccs2bNYuzYsVxxxRU8/fTTHDgQatLaunUrVVVt50Xs3r2bpqYmLh9zObf+6FbeXv42G/du5EjjESBUO9i2bRvvvvsuAPv376ehoYGRI0cyffp0ADZu3Mgnn3zCKaec0uLckfssWrSI448/vrkGki5WgzDG5L1Bgwaxf/9+evfuTUlJCSUlJaxfv54LLrgAgK5du/LnP/+ZwsLCFsdt3bqVG2++kbqGOlC4+4G7qW+q51DDIQ7WH6Rjx47MmDGDO++8k8OHD3PUUUfx+uuvc8cddzBhwgTOPPNMOnTowLRp0+jUqVOLc5eVlfHtb3+bwYMH07lz50DWj7B038aYQHlJ9x1tFBMdu8Kkrf4WLE4b9250HS1VVFDEwOMGBlAiS/dtjMlHAQWBWKLNuM6FmdiB9kGIyBdE5A0RWS8i60RkYpDlMcYYr6INpU1mJnamCLoG0QD8UFVXikg3YIWIzFfVDwIulzEmYF7WbQhyjYeeXXq2SCEO8Q+xzXSBBghV3Q5sd37eLyLrgd6ABQhj8li0dRugbQpuL/umglv6jlxZTyLoGkQzETkJGAK84/LZbcBtAH379k1ruYwx6RdvbiWv+6ZK6/QduSIj5kGISFfgBeBuVd3X+nNVfVJVh6nqsB49eqS/gMaYtPLS8ZvLncRBCzxAiEgRoeAwXVVfDLo8xpjgeen4TUUn8bZt2xg7dqzn42699VY++CB2C/nUqVP53//930SLllZBj2IS4H+A9ar6myDKULWvlpGPvkHV/tq0HGeMaZ/bug3ROn697BuvE088kVmzZrXZ3tDQEPO4p556itNPPz3mPhMmTODGG29MuGzpFHQN4kLgW8BlIrLKeV2VzgJMWbCJTz87xJQFm9NynDGmfd07defEric21wKKCoo4seuJdO/Unblb5jJ61mgGPzuY0bNG89bWt6LuG4977rmHxx9/vPl9WVkZv/71rznjjDMAmDZtGuPGjePqq69m9OjRNDU1cccddzBo0CDGjBnDVVdd1RxMLrnkEsITebt27cr999/PWWedxfDhw9m5c2fz+X/1q18BsHnzZkaNGsVZZ53F0KFD+eijjzhw4ACXX345Q4cO5cwzz+Sll17y4Y4mJtAAoapLVFVUdbCqnu28XknX9av21fL8ikpUYVb5p3HXBhI9zhgTP7fcSnO3zKXs7TK2H9yOomw/uJ2yt8t4a+tbnvMwVddVs3HvRs694lymTZ/WvPrczJkzm7Ovhi1dupRnn32WhQsX8uKLL1JRUcHatWt56qmnWLp0qev5Dx48yPDhw1m9ejUjR47kj3/8Y5t9brjhBr773e+yevVq3n77bUpKSiguLmb27NmsXLmSN954gx/+8IdxJfdLhaBrEIGasmATTc6Nb1SNuzaQ6HHGmORMXjmZ2saWX8hqG2uZvHKyp/NELlF62uDT2L1rN6s2reLNd9/k2GOPbTNa8itf+QrHHXccEErDPW7cOAoKCujVq1ebhX7COnbs2Lx86DnnnENFRUWLz/fv38/WrVu57rrrACguLqZz586oKpMmTWLw4MGMGjWKrVu3Ntc+0i1vA0S4FlDf6IydbtS4agOJHmeMSd6Ogzs8bY91nshv5aOvHs1rL7/G9L9MZ/z48W32j0yvHe+3+aKioua+kcLCwjb9F9HOM336dHbt2sWKFStYtWoVJ5xwArW1wTxf8jZARNYCwuKpDSR6nDEmeb269PK03U11XTWNTY0ttn31uq/y6pxX+cfL/2h39NJFF13ECy+8QFNTEzt37mTRokVxXzvS0UcfTZ8+fZgzZw4AdXV1HDp0iJqaGnr27ElRURFvvPEGH3/8cULn90PeBoj563c21wLC6huV+R/E/iaS6HHGmORNHDqR4sLiFtuKC4uZODT+NG5VB9uu63DyqSdz6MAhTjjxBEpKSmIe/41vfIM+ffpwxhln8J3vfIfzzz+fY445Ju7rR/rTn/7ElClTGDx4MCNGjGDHjh3ccMMNlJeXM2zYMKZPn86pp56a0Ln9YOm+jTGB8pTuG5i7ZS6TV05mx8Ed9Ozck/GnjOeCEy+IO8XFut3ron7Wu1vvuDq4Dxw4QNeuXdmzZw/nnXceb731Fr16xV+LSTVL9+1R1b5axk5dyqzbL6Bnt+L2DzDGZKTSAaWUDiiNOwdT60R+hVJIoza2OW+hFMY9NHbMmDFUV1dz5MgRfvKTn2RUcPBT3gSIyHkLD33tjKCLY4xJUjw5mNyCiIggCErL7Ku9usb/kE+03yHb5EUfhM1bMCazJdLUHU8OpmhBpKCgoHliXWFBIQUUsHX/Vjbu3dg8HyJb+dltkBcBwuYtGJO5iouL2bNnj+cHWzw5mKIFkcamRgYeN5De3XrTpE3NTU7hZqpsDRKqyp49eygu9qcZPeebmKLNW7jr8pOtL8KYDNCnTx8qKyvZtWuXp+MONxymura6ZVMRQvfi7qzfuR6AXYd2tRnSCqFaw/pd69l5aKfr51UFVZzQ+QSP/5LMUFxcTJ8+fXw5V84HiFjzFoLoi7DOcmNaKioqon///gkdGzmiqVeXXkwcOpHLBlzW/PmWLVsoe7usxezr4sJiykaUcdqA07j+2etbBJgwQVhz05qEypRLcj5AxJq3EESAsM5yY+LnFgBKB5Q2fx4e0RRN+LNo5+jVpRfbD25vc5yXiXe5LOcDxDuTRgVdhGatO8utmcuY6MKJ+cLf/sOJ+YCYQaG1WEFk4tCJbWoYACP7jEys0DkmLzqpM4V1lhsTP78S88VSOqCUa0++ts32lza/xNwtc327TrayAJEmluTPGG/8SszXnsWVi9ts8zsQZSsLEGliSf6Moc1iP7G+pfuRmC8e6QpE2cgCRJpYkj+T76It9hMtSPiRmC8e6QpE2SjnO6kzRSZ1lhsThFh9Cm6dyO2NQIL2RznFw62jOhWBKBtZgMgBNrfCZINEmnJijUDyc5QTxA5E+cqamFxU7atl5KNvpLQD2c9rRM6tMCZT+d2U4+cop9IBpcwbO481N61h3th5FhwcFiBcpOOB69c1LBGhyRZ+9ylY53LqWRNTK+mYzObnNdzmVtgMbcMve8ORA223d+wKk7amvzz435Rjs6BTz2oQrfg5mS1aM5Jf17C5FSYqt+AQa3ua+NmUk65RTvnMAkQEvx+4bs1Ifl7D5laYXBdr3kTpgFLKRpRR0qUEQSjpUkLZiDLrP/BRuwFCRL4gIs+JyJsiMklEiiI+m5Pa4qWXnw/caH0Dfl7D5laYXBbPvAnrXE6tePogngZeAJYB/wX8U0SuVtU9QL9UFi7d/Mz8Gq1vIJFrRBvGanMrTC7zOm/C+C+eANFDVac6P98pIt8EFovINeCSSD2L+fXAjbVIUSLXsBThJmOlsDPcRikFL54+iCIRaf7aqqp/BiYCrwElyRZARJ4WkSoReT/Zc2WKdDRVGRNTx67eticqhZ3hlgIjePEEiKeA8yM3qOrrwDjAj4f6NOBKH86TMfzsG7AU4SYhk7ZCWU3bV0BDXBNho5SC124Tk6r+Nsr294CvhN+LyH2q+v96LYCqLhaRk7wel8nemTSKB2avZfryT7jh/H4JNwvZetomn1kKjOD5OVFuHOA5QOQivybCZdp62sakW3tLiprU8nMehPh4rpYnFrlNRMpFpHzXrl2pukzc2suj5FezkA1jNcYEyc8aRMpGNKnqk8CTAMOGDQt85FSsUUV+NgvZMFaT8Tp2jT6KyWQ9PwNEymoQmaS95iNrFjJ5JYs6vWPxY12JXBR3E5OIXNjOtucTKYCI/BVYCpwiIpUi8l+JnCdd2ms+smYhY5LjZVlSL/vGOsdP3vpJixnbP3nrJwmdK9eIanwtNiKyUlWHtrct1YYNG6bl5eXpvGSzqn21fPnRN6hraGreVtyhgMX3XNqm+cgW8TEZJwMzvLbWehEgCA1tdcux5GXfWL783Jeprqtus717p+68Of7NBP4VmUlEVqjqMC/HxJOL6QIR+SHQQ0R+EPEqAwoTLGtW8jIBzhbxMRknQzO8RvKyCJBfCwa5BYdY2/NJPE1MHYGuhPorukW89gFjU1e0zBNv85HNfjYmMV7Sa1gqjtSLZ6LcPwkl6Jumqh+noUwZK95RRbaIjzGJ8bIIkF8LBh3T8RhqjtS4bs93XuZBdBKRJ0VknogsDL9SVrIsUrWvlgsfXsiFDy/kg201bYa5Pl/+KRc+vNBqEsa0w0t6Db9Scdx3/n10kJbflTtIB+47/z5P58lFXoa5Pg9MJZSbqTE1xclOUxZsYmv1YQDufm5Vm36K+sYmtlYftpqEMe3wkl7Dr1QcltIjOi+jmFao6jkpLk+7ghzF5KZqXy0XPbKQI43t38doI56MSYssGMUUi81VSE4io5i81CD+JiJ3ALOBuvBGVd3r5YK5ZsqCTS06rgsE/jMiQd8Ds9cyo/xT6huVRlUu+9UiFv7oEhsWa9IvDUEgVQ/x1kNaw6vLARYkUshLH8RNwI+Bt4EVzitzvsoHoGpfLTPLP22RY6RJ4Xln5JJb2o0DdY088uqGNueyYbEm28WzRGii/BrSGo0fE+5yUdwBQlX7u7wGpLJwma517SGsvrGJy361iEf+8WGb/giAOe9VtuiwtmGxJhek8iGeyiGtqQxs2c5Lqo3OIvKAiDzpvP+SiIxJXdEy3/z1O10zFDYpHKhr5JW1O1wDSKPSoqZgiwKZXBDtYb394PakH7apXF0u1bWTbOalD+IZQs1KI5z3lYRGNv3d70JlC7d5EZHpOFSV5fdfDkqbFB3hRH8ocWV/tT4KE1WGdD5Hm5cAJN1fMHHoRNe0Gn6sLmcT7qLz0gfxRVV9FKgHUNXD5EkGVy/cagOxUnTEm74jnj6K9tapMDkqQ1JouM1LCEv2G3npgFLKRpRR0qUEQSjpUuIp51KsPgZb+zo6LwHiiIgchbPug4h8kYjRTPnG7WEcbS2I1z6InqIjnvQd8fZRWEe3CVL4IR5Nst/ISweUMm/sPNbctIZ5Y+d5Cg6x+hhs7evovDQxPQj8A/iCiEwHLgRuTkWhsoHbokHRagNXDOqV1AS5eFJ3+LXMqTHJKB1QyuSVk31JgeGXWH0MkUua2hyLtryMYpoPfJ1QUPgrMExVF6WmWJkt2jd6P9aCaF0ziVYraV2LsI5ukyky7Rt5PH0MidZOcp3XFeWKgc+c404XEVR1sf/FymzRvtH7sURo65pJPCvU+bnMqTHJyrRv5H4l9ctHXoa5PgK8BdxPaMLcj4EfpahcGSveb/SJdBi71UziqZV4WafC5KBY6z//snf6yhEh3m/k6Ziglmk1mmzipQbxNeAUVc3bjmmIf81ptz4KL+cOnzOeWkmsIGLJAfPApK1QFiU1dQYtBtRautJntK7RHN3xaESE+968j8krJ1t/QwxekvW9CoxT1UD/4oJO1nf+L19n5762MfKEozs1P8wj50LEm6DPy3KmxrQRLUAAlLVd6yATjJ412rXpp6RLCfPGzkvJNf1apjQbpTpZ3yFglYgsoGWyvru8XDDbxfONvnVN4OFXP6S84rOYk9zirZkYkyuCmKDW3ogm05KXeRAvA7+gZbK+FakoVDZz66N46b2t7c5P8GMElDHZJIgJajZr2pu4axCq+qyIdAQGOps2qGp9aoqVvdxrAqH/xhpZ5McIKGMyRTxpv6OlzxjZZySjZ41OyQgoG9HkTdwBQkQuAZ4FKgil2PiCiNyUj8NcY3GrCYRZk5FJmY5do+dj8lMceZ/i7Xx2Gw47ss9IXtr8Uso6rlOZ0ykXeVpRDvhPVd3gvB8I/DXdq8wF3UnthXU8m5wTR2d4Mp3P6ei4zteV6VLdSV0UDg4AqrpRRIq8XCzfTFmwicamphbbrBaRxxLJuppMptaAsrwm086fjj6CyPQaJjYvndTlIvI/InKJ8/oj1kkd0/z1O2loGR+s4zmfJZJ1NZlMrQFleU2m89kyq2YWLwHidmAdcBcwEfgAmJCKQuWKv33vIjp1CN3i4g4FLL//cioeLrUOaeOPsmM+fwU0Y9pNMjOXbdZzZvEyiqlORH4PLACaCI1iOpJsAUTkSmAyUAg8paoPJ3vOTOE2M/quy05m7NSlTP3mUCb8eaUtAGT8kWitIFozVCSPTVLJ5GLKtDxO+c7LKKZSYCrwEaFRTP1F5Duq+mqiFxeRQuAPwFcIrVD3roi8rKofJHrOTBEtZ9PhIw18+tkh7n5uledUHMb4zmtTVZyjpZJp57c+gszhpZP618ClqroZmhcMmgskHCCA84DNqrrFOedzwLWEmq+ymtt8iIamJua8tw1V2FgV+p/Msq6arJKmJUwjRxqFcyfV1NXQq0sv+nXrx/Kdy2nSJgqkgHEDx/HA8AfSUq5846UPoiocHBxbgKokr98b+DTifaWzLeu5zYdoaAo1NUWyrKt5JNqchFhzFZKZx5DI9TJA6xXgao7UUF1X3bwa3LIdy2jS0OiPJm1ixoYZPLTsoYBLnZu8zIN4AugHzCS07Og4YAOhFOCo6oueLy4yDrhCVW913n8LOE9V72y1323AbQB9+/Y95+OPP/Z6qcC5zYkIi5wbUbWvlrFTl1rfhHGXTFK+ePobEj23j6LNhYilQApYfePqFJUoNyQyD8JLDaIY2AlcDFwC7AKOA64Gxni5aIRK4AsR7/sA21rvpKpPquowVR3Wo0ePBC8VLLcmp7DIWoStK22iijVSKZ5aQcCpv+Nd+yGROQ/hGkU61pfIJ15GMX07Bdd/F/iSiPQHtgLjgf9MwXUCE64RHK5vjJqCIzw34q7LTrZ1pU1b8XzzT2XfgA9NUl7WfoiWLymWAilI2/oS+cTLinL9ReQ3IvKiiLwcfiVzcVVtAL4HvAasB2aq6rpkzplpwjWCKwb1ouLhUpZPurx5bkShCADfHN6PdyaNsnWljbt0fvPv2DXUnBT58iH4xEqz3ZrbXIj2jBs4ztM1EpGPtRMvTUxzCCXq+29CI5rCr6So6iuqOlBVv6iq/zfZ82UStyVEWwcBCH32wbaauJYyNSalUhSMvKTQKB1QStmIMkq6lCAIx3Q8hu6duiMI3Tt1pygiw48gXH/K9Tww/IGUpulo3XEerp3kepDwMsy1VlWnpKwkOcht4aC5a7a3aWqqbWjie395zxYMMjnLa5ptt7kQ4Yd0fcQqA50KOzGk55CEruFFvi405KUGMVlEHhSRC0RkaPiVspJluWgLB0XrqN6y+6AtGGRSK8DhrX6k0GivCSmVaTrydaEhLzWIM4FvAZcRSrUBoeGul/ldqFwQbeGgxigd1QD9j+9CxZ6D3HB+P6s1mPjF++CP7EuINVw2BfxIodHeQzqVaTrydaEhLwHiOmCAH/mX8kG0hYNOOLoTADv31bX57F+7DwI2gsm0Eiu9RZpmNvsh2RQa8TykU5WmI18XGvISIFYD3Ul+9nReaC9ja6yJc7UNTTzy6gZ+/e9npap4Jpt4CQLJTIaDjJ5l7faQBjhUf4i5W+amtC8gX5MIegkQJwAfisi7QPPXX1W9xvdS5YFYE+cA5rxXyT1fPSVqLcJmXBtXXoNDGmdIJ6L16m/Xnnwtr1W8RnVddfM+NUdq0jLfIR+TCHrppH6QUDPTL/FxmGu+irV2NYT6Kx55dUPUz23Gtcl1bkNLX9r8Em7pgfyc72A+F3eAUNV/Ah8C3ZzXemebScA7k0ZR8XApFQ+XNvdLtPbK2jZZRwD3+RXG5Jpoo5ZqjrjXenJ9RFEQvMyk/ndgOaEkff8OvCMiY1NVsHzyzqRRLWZYh6ni+vC3GdcmH3h94Of6iKIgeOmDuB84V1WrAESkB/A6MCsVBcs37sNiW06Uq9pXy3WPv81tbiVEAAAULElEQVSu/bVtZlzbqKccEa2TufWIpWQ7o8Mih7tm2KioaKOWunfqTm1Dbd6NKAqClz6IgnBwcOzxeLyJwa1PInKiXNW+Wi779SK2Vh9us5/VInJItId+6+2pSIkRQLbXWPmNok18u/e8e1uk4ijpUkLZiLK860BOBy81iH+IyGvAX53315PcanImQnvDYh9+9UMO1DUCodmJkcKBxCbX5bh4J7e1NzIpzZPkomkv+2p7Q0stIKSel3TfPxaRrwMXEVqT+klVnZ2ykplmVftqmbPq86p/UaFw/bl9LSCYrBZPfqN8HFqaSTyl+wZeUdUfqOr3CdUoTkpVwcznHn71Q5oiqg2W6dXkgnzNb5RNvPQhPM/nOZgAGp1tJoVa1x7CrN/BZLtoo45sNFLm8BIgOkTmYXJ+7uh/kUyk0Oimttst02uOSjbVRTzHx9qn7JjYS5v6KJXZV40/vHRS7xKRa1T1ZQARuRbYnZpimbB/rHMPAicc3andjm2ThZLNuBrPMNXwPtHOn6bRTPma3yibeAkQE4DpIvJ7530lofTfJoWuHNSL6cs/QYAmheIOBSy+51Kb85APomVxzSGp7oRuncvJApA3XkYxfQQMF5GugKjq/sjPReQmVX3W7wLms8iUGuFWJsv0mkei1QYyZJhqpmtvGK1pn+eJbqp6oHVwcFjDoU+q9tUy8tE3eOQfH7pmfJ3zXqWNYMpn0foQMjhVdxDaW4Eu08WaRJguXpqY2iM+nivnxUrXPWXBJj7Ze4itnx2m0SVAhDO9Wi0iIPGmw0iVDEqHkcmyeRhtptR+/EyVET13tWkjWrrucLMS4BocwqJlejVpEG86jHT4Ze9Qk1PrVzwjkXK8JpLNw2gzpfZjNYgAtE7XHZlor72FhMLCmV6tszrPJROsAqyJpKPzOJuXCc2U2o+fNYi3fDxXTouWrjscOCKT8RV3KOAbQ3tTVNgy/tpEOZOt3BYCKnu7zPc29tIBpVmb1C9Taj+eahAiUgoMApq/tqrqz53/fs/fouWm1kEgMl13tJTfr6zdETXTq+VjyiF+921kYirvX/Zmcs+jqS1q+ehpnYPJL9mayylTaj9xBwgRmQp0Bi4FngLGElpAyHgQLQjc+8IaFn64q83+9Y3KcV06sP4XV6ariCYoqezbCJ8j6A72IwfY0eFY14+yofM4XTJlEqGXGsQIVR0sImtU9Wci8mvgxVQVLFdFW/chHByOOaoDqx+8wvXYWCOfTBpFm8CW6Z27sRYZSjIIeelT6NXQyPaito+ebOg8TqdMqP14CRCHnf8eEpETCS0Y1D/RC4vIOKAMOA04T1XLEz1XNnFLj7Fk0y6++T+hyljN4QaWbN7FRSf3aLNf5Mgna1oKUCY01YR5mW2dolFWXodkTvysmrLjj6O24PMu0OKmppQ2n/jdKZ4vM7S9dFL/XUS6A48BK4EK4Lkkrv0+8HVgcRLnyAl3TF/Z4v13W72HtiOfPthWw8hH37AJc/lu0tbQAkHhVwC8DsksPXiIst17KalvQFQpqW+gbPfelD1g/e4UT1cneyaIO0Co6i9UtVpVXwD6Aaeq6k8SvbCqrlfVDYkenyuWbNrFvtqGFtvCtYhIrUc+3f3cKtd5FMakWyJDMksPHmJe5TbWVHzKvMptlB48lKri+T6nIFPmKKRDuwFCRL7e+gWUApc7P5sktK49hEXWItxGPm2sOtBcm7BaRI7wY+JaAJPfPA3JDKB8fs8pyJQ5CukQTx/E1c5/ewIjgIXO+0uBRcToqBaR1wG3v577VfWleAspIrcBtwH07ds33sOyQuvaQ1jN4c+3x5o8F54PYX0SOcCPvo1Y54iV5C+JB7SnIZkB9N/06tKL7Qe3u27PhPNlsnZrEKr6bVX9NqFUGqer6jdU9RuE5kO0d+woVT3D5RV3cHDO86SqDlPVYT16tO28zWYVD5fyzfP7Nk+EKyoUvjm8HxUPf94e6zbyKcyWHzVxi/XtPYkHd6ZPSPN7YaJ8WujIyyimk1Q1MmzuBAb6XJ68E2viXHgoa+TIpwdmr2VG+actAobVIkyzgOY5ZMKQzGj8nlOQKXMU0sFLgFgkIq8BfyVUmxgPvJHohUXkOuC/gR7AXBFZparuEwByWLSJc9Ee+NHmUdisagNkViLBDOJ3AMvkgOgnLwsGfc/plP6ys+lJVZ2d6IWdYxM+Pld4feDbMqN5KOjZzyZvecrFpKovYrOnfWUPfNMuqxWYgLQbIERkP+5rPQigqnq076UyxhgTuHYDhKp2S0dBjDHGZBY/FwwyJv9kWv9AtiYSNBnJAoQxyci0/gHrtDY+8nNFOWNMKuT42tEmc1kNwphMl+m1gkxrZnORL+m5/WYBwphclo6Hd6Y1s7Xidb0K8zlrYjIml2X4wzsd8ik9t98sQBiTDOsfyHj5lJ7bb9bEZEwyMqSN3USXT+m5/WY1CGNMTsun9Nx+sxqEMSY5GT45L5/Sc/tNNMpKZZlq2LBhWl5eHnQxjIlP0ENAY60il85ymMCJyApVHeblGKtBGJNKiY4iSldgyaPRTMY7CxDGBC1aMHBjD3STRhYgjAlaNj30g24yM2llo5iMMfGziXd5xQKEMcYYVxYgjEmloGdat3edDBmKajKT9UEYk0qTtrq32x85ENqe6nZ76xcwSbAahDGp1l67vX2LNxnKahDGBM3tW357E9yCkuGzpo2/LEAYY+JnTVZ5xZqYjDHGuLIaRB6q2lfL2KlLmXX7BfTsVtz+ASZ1WjclhSecpaopxya6GQ8sQOShKQs28elnh5iyYDMPfe2MoIuT+6I97N2E90vVw9omuhkPAgsQIvIYcDVwBPgI+LaqVgdVnnxRta+W51dUogqzyj/lrstPtlpEqmVTJ7QxEYLsg5gPnKGqg4GNwH0BliVvTFmwiSYnxXujKlMWbA64RMaYTBVYgFDVeara4LxdBvQJqiz5Ilx7qG8MBYj6RmVW+adU7a9t50hjTD7KlFFMtwCvBl2IXBdZewizWoQxJpqUBggReV1E3nd5XRuxz/1AAzA9xnluE5FyESnftWtXKouc0+av39lcewirb1Tmf7AjoBLlsaByNAWdG8pklUCXHBWRm4AJwOWqeiieY2zJUWNy39wtc20NaZ9l1ZKjInIlcA9wcbzBwRiTe1oHg5F9RvLS5peobQz1jW0/uJ2yt8sALEikWWA1CBHZDHQC9jiblqnqhPaOsxqEMblj7pa5lL1d1hwMYinpUsK8sfPSUKrclFU1CFU9OahrG2Myw+SVk+MKDgA7DlpfWbplyigmY0we8vLQ79WlVwpLYtxYgDDGBCbeh35xYTETh05McWlMaxYgjDGBmTh0IsWFLVO9FBcWc/0p11PSpQRBKOlSQtmIMuugDoAl6zPGBCb80LchrZnJAoQxJlClA0otIGQoa2IyxhjjygKEMcYYVxYgjDHGuLIAYYwxxpUFCGOMMa4sQBhjjHFlAcIYY4wrCxDGGGNcWYAwxhjjymZSG5Opyo6J8VlN+sph8pbVIIwxxriyAGGMMcaVBQhjjDGuLEAYY4xxZQHCGGOMKwsQxhhjXNkwV2MylQ1lNQGzGoQxxhhXFiCMMca4sgBhjDHGlQUIY4wxrixAGGOMcWUBwhhjjCsLEMYYY1xZgDDGGONKVDXoMngiIruAjz0edjywOwXF8Usmly+TywZWvmRkctkgs8uXyWUD9/L1U9UeXk6SdQEiESJSrqrDgi5HNJlcvkwuG1j5kpHJZYPMLl8mlw38K581MRljjHFlAcIYY4yrfAkQTwZdgHZkcvkyuWxg5UtGJpcNMrt8mVw28Kl8edEHYYwxxrt8qUEYY4zxKGcChIiME5F1ItIkIsNafXafiGwWkQ0ickWU4/uLyDsisklEZohIxxSWdYaIrHJeFSKyKsp+FSKy1tmvPFXlaXXNMhHZGlG+q6Lsd6VzPzeLyL3pKJtz3cdE5EMRWSMis0Wke5T90nbv2rsXItLJ+Z1vdv7GTkpleVpd+wsi8oaIrHf+/5joss8lIlIT8Tv/abrK51w/5u9KQqY492+NiAxNU7lOibgnq0Rkn4jc3WqftN47EXlaRKpE5P2IbceJyHzn2TVfRI6NcuxNzj6bROSmuC6oqjnxAk4DTgEWAcMitp8OrAY6Af2Bj4BCl+NnAuOdn6cCt6ep3L8Gfhrlswrg+DTfxzLgR+3sU+jcxwFAR+f+np6m8o0GOjg/PwI8EuS9i+deAHcAU52fxwMz0vj7LAGGOj93Aza6lO8S4O/p/Dvz8rsCrgJeBQQYDrwTQBkLgR2E5hIEdu+AkcBQ4P2IbY8C9zo/3+v2/wRwHLDF+e+xzs/Htne9nKlBqOp6Vd3g8tG1wHOqWqeq/wI2A+dF7iAiAlwGzHI2PQt8LZXljbjuvwN/TfW1fHYesFlVt6jqEeA5Qvc55VR1nqo2OG+XAX3Scd0Y4rkX1xL6m4LQ39jlzu8+5VR1u6qudH7eD6wHeqfj2j66FvhfDVkGdBeRkjSX4XLgI1X1OknXV6q6GNjbanPk31e0Z9cVwHxV3auqnwHzgSvbu17OBIgYegOfRryvpO3/IP8GVEc8eNz2SYUvAztVdVOUzxWYJyIrROS2NJQn7HtOVf7pKNXVeO5pOtxC6Julm3Tdu3juRfM+zt9YDaG/ubRymraGAO+4fHyBiKwWkVdFZFBaC9b+7yoT/t7GE/2LXJD3DuAEVd0OoS8EQE+XfRK6h1m1JrWIvA70cvnoflV9KdphLttaD92KZx9P4izrfxC79nChqm4TkZ7AfBH50PkGkZRYZQOeAH5B6N//C0JNYLe0PoXLsb4Nh4vn3onI/UADMD3KaVJy79yK67It5X9fXolIV+AF4G5V3dfq45WEmk4OOH1Oc4AvpbF47f2uAr1/Tn/kNcB9Lh8Hfe/ildA9zKoAoaqjEjisEvhCxPs+wLZW++wmVG3t4HzDc9vHk/bKKiIdgK8D58Q4xzbnv1UiMptQc0bSD7l476OI/BH4u8tH8dzThMVx724CxgCXq9PA6nKOlNw7F/Hci/A+lc7v/RjaNhOkjIgUEQoO01X1xdafRwYMVX1FRB4XkeNVNS25huL4XaX07y0OXwVWqurO1h8Efe8cO0WkRFW3O01vVS77VBLqLwnrQ6i/NqZ8aGJ6GRjvjCTpTyi6L4/cwXnIvAGMdTbdBESrkfhlFPChqla6fSgiXUSkW/hnQp2z77vt66dWbbvXRbnmu8CXJDTyqyOh6vfLqS6bU74rgXuAa1T1UJR90nnv4rkXLxP6m4LQ39jCaIHNb05fx/8A61X1N1H26RXuExGR8wg9F/akqXzx/K5eBm50RjMNB2rCTSppErWmH+S9ixD59xXt2fUaMFpEjnWajUc722JLV+97ql+EHmaVQB2wE3gt4rP7CY002QB8NWL7K8CJzs8DCAWOzcDzQKcUl3caMKHVthOBVyLKs9p5rSPUvJKO+/gnYC2wxvnDK2ldNuf9VYRGxHyUrrI5191MqC11lfOa2rp86b53bvcC+DmhIAZQ7PxNbXb+xgak8X5dRKgpYU3EPbsKmBD++wO+59yn1YQ6/keksXyuv6tW5RPgD879XUvEKMU0lK8zoQf+MRHbArt3hALVdqDeed79F6H+rAXAJue/xzn7DgOeijj2FudvcDPw7XiuZzOpjTHGuMqHJiZjjDEJsABhjDHGlQUIY4wxrixAGGOMcWUBwhhjjCsLEMYYY1xZgDAZTUQORNk+TUTGun2WT5x00yPa2WekiKwUkQa7Z8YLCxDGZLdLgJgBAvgEuBn4S6oLY3KLBQiTFZw0C78XkQ9EZC4RGStF5Kci8q6IvC8iT8ZKpS0iJ4vI6072zZUi8kXn3I85x68VkeudfS8RkX+KyEwR2SgiD4vIDSKy3Nnvi85+00Rkqoi86ew3xtleLCLPOPu+JyKXOttvFpEXReQfElq85dGI8o0WkaVO2Z53kuyFF9X5mbN9rYicKqHsrBOA70tosZovu/2bVbVCVdcATcn9Fky+sQBhssV1hBaEOhP4f2j5rfn3qnquqp4BHEUokV8004E/qOpZzjm2E0qaeDZwFqEcWY9F5KQ6C5joXPdbwEBVPQ94Crgz4rwnARcDpcBUESkGvgugqmcSyufzrLMd53rXO+e9XkIrvx0PPACMUtWhQDnwg4hr7Ha2P0FoUacKQotb/VZVz1bVN2P8u43xLKuyuZq8NhL4q6o2AttEZGHEZ5eKyP8hlDfnOEK5cf7W+gROUrjeqjobQFVrne0XRZx7p4j8EzgX2Ae8q05iOBH5CJjnnG4tcGnE6WeqahOwSUS2AKcSyoP03861PhSRj4GBzv4LVLXGOe8HQD+gO6EVEN9yKkEdgaUR1whnYl1BKKgZk1IWIEw2aZM4zPlG/jihBG6fikgZoeR4bqI1PcVa3a0u4uemiPdNtPz/p3XZ1MN5G51zCaFVv/6jnWPC+xuTUtbEZLLFYkJp2wud5p/wt/dwMNjttNdHHaWjodz9lSLyNQAJpYDv7Jz7eufcPQjVVpZHO08U40SkwOmXGEAoc/Bi4AbnWgOBvs72aJYBF4rIyc4xnZ3jYtlPaK1pY3xnAcJki9mE0hmvJdQG/08AVa0G/uhsn0NofYZYvgXcJSJrgLcJrVw3m1A67NXAQuD/qOoOj+Xb4JTpVUKpoGsJ1WwKRWQtMAO4WVXrop1AVXcRGm30V6d8ywg1VcXyN+C6WJ3UInKuiFQC44D/T0TWefunmXxl6b6NSZKITAP+rqqzgi6LMX6yGoQxxhhXVoMwOUlE/gBc2GrzZFV9JojypIOI3E+oGSnS86r6f4Moj8l+FiCMMca4siYmY4wxrixAGGOMcWUBwhhjjCsLEMYYY1xZgDDGGOPq/wfeJOe1kEhEeQAAAABJRU5ErkJggg==\n",
53 | "text/plain": [
54 | ""
55 | ]
56 | },
57 | "metadata": {},
58 | "output_type": "display_data"
59 | }
60 | ],
61 | "source": [
62 | "import pandas as pd\n",
63 | "import matplotlib.pyplot as plt\n",
64 | "%matplotlib inline\n",
65 | "\n",
66 | "lda_columns=['lda_component_1','lda_component_2']\n",
67 | "irisDF_lda = pd.DataFrame(iris_lda,columns=lda_columns)\n",
68 | "irisDF_lda['target']=iris.target\n",
69 | "\n",
70 | "#setosa는 세모, versicolor는 네모, virginica는 동그라미로 표현\n",
71 | "markers=['^', 's', 'o']\n",
72 | "\n",
73 | "#setosa의 target 값은 0, versicolor는 1, virginica는 2. 각 target 별로 다른 shape으로 scatter plot\n",
74 | "for i, marker in enumerate(markers):\n",
75 | " x_axis_data = irisDF_lda[irisDF_lda['target']==i]['lda_component_1']\n",
76 | " y_axis_data = irisDF_lda[irisDF_lda['target']==i]['lda_component_2']\n",
77 | "\n",
78 | " plt.scatter(x_axis_data, y_axis_data, marker=marker,label=iris.target_names[i])\n",
79 | "\n",
80 | "plt.legend(loc='upper right')\n",
81 | "plt.xlabel('lda_component_1')\n",
82 | "plt.ylabel('lda_component_2')\n",
83 | "plt.show()"
84 | ]
85 | },
86 | {
87 | "cell_type": "code",
88 | "execution_count": null,
89 | "metadata": {},
90 | "outputs": [],
91 | "source": [
92 | "from sklearn.datasets import load_iris\n",
93 | "import pandas as pd\n",
94 | "import matplotlib.pyplot as plt\n",
95 | "%matplotlib inline\n",
96 | "\n",
97 | "# 사이킷런 내장 데이터 셋 API 호출\n",
98 | "iris = load_iris()\n",
99 | "\n",
100 | "# 넘파이 데이터 셋을 Pandas DataFrame으로 변환\n",
101 | "columns = ['sepal_length','sepal_width','petal_length','petal_width']\n",
102 | "irisDF = pd.DataFrame(iris.data , columns=columns)\n",
103 | "irisDF['target']=iris.target\n",
104 | "irisDF.head(3)\n",
105 | "from sklearn.preprocessing import StandardScaler\n",
106 | "\n",
107 | "iris_scaled = StandardScaler().fit_transform(irisDF.iloc[:, :-1])\n",
108 | "from sklearn.decomposition import PCA\n",
109 | "\n",
110 | "pca = PCA(n_components=2)\n",
111 | "\n",
112 | "#fit( )과 transform( ) 을 호출하여 PCA 변환 데이터 반환\n",
113 | "pca.fit(iris_scaled)\n",
114 | "iris_pca = pca.transform(iris_scaled)\n",
115 | "print(iris_pca.shape)\n",
116 | "pca_columns=['pca_component_1','pca_component_2']\n",
117 | "irisDF_pca = pd.DataFrame(iris_pca,columns=pca_columns)\n",
118 | "irisDF_pca['target']=iris.target\n",
119 | "#setosa를 세모, versicolor를 네모, virginica를 동그라미로 표시\n",
120 | "markers=['^', 's', 'o']\n",
121 | "\n",
122 | "#pca_component_1 을 x축, pc_component_2를 y축으로 scatter plot 수행. \n",
123 | "for i, marker in enumerate(markers):\n",
124 | " x_axis_data = irisDF_pca[irisDF_pca['target']==i]['pca_component_1']\n",
125 | " y_axis_data = irisDF_pca[irisDF_pca['target']==i]['pca_component_2']\n",
126 | " plt.scatter(x_axis_data, y_axis_data, marker=marker,label=iris.target_names[i])\n",
127 | "\n",
128 | "plt.legend()\n",
129 | "plt.xlabel('pca_component_1')\n",
130 | "plt.ylabel('pca_component_2')\n",
131 | "plt.show()"
132 | ]
133 | },
134 | {
135 | "cell_type": "code",
136 | "execution_count": null,
137 | "metadata": {},
138 | "outputs": [],
139 | "source": []
140 | }
141 | ],
142 | "metadata": {
143 | "kernelspec": {
144 | "display_name": "Python 3",
145 | "language": "python",
146 | "name": "python3"
147 | },
148 | "language_info": {
149 | "codemirror_mode": {
150 | "name": "ipython",
151 | "version": 3
152 | },
153 | "file_extension": ".py",
154 | "mimetype": "text/x-python",
155 | "name": "python",
156 | "nbconvert_exporter": "python",
157 | "pygments_lexer": "ipython3",
158 | "version": "3.6.4"
159 | }
160 | },
161 | "nbformat": 4,
162 | "nbformat_minor": 2
163 | }
164 |
--------------------------------------------------------------------------------
/8장/8.10 Text Analysis 실습 _ 캐글 Mercari Price Suggestion Challenge_kaggle용.ipynb:
--------------------------------------------------------------------------------
1 | {"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"### 데이터 전처리","metadata":{}},{"cell_type":"code","source":"from sklearn.linear_model import Ridge , LogisticRegression\nfrom sklearn.model_selection import train_test_split , cross_val_score\nfrom sklearn.feature_extraction.text import CountVectorizer , TfidfVectorizer\nimport pandas as pd\n\nmercari_df= pd.read_csv('mercari_train.tsv',sep='\\t')\nprint(mercari_df.shape)\nmercari_df.head(3)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* train_id: 데이터 id\n* name: 제품명\n* item_condition_id: 판매자가 제공하는 제품 상태\n* category_name: 카테고리 명\n* brand_name: 브랜드 이름\n* price: 제품 가격. 예측을 위한 타깃 속성\n* shipping: 배송비 무료 여부. 1이면 무료(판매자가 지불), 0이면 유료(구매자 지불)\n* item_description: 제품에 대한 설명","metadata":{}},{"cell_type":"code","source":"print(mercari_df.info())","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**타겟값의 분포도 확인**","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport seaborn as sns\n%matplotlib inline\n\ny_train_df = mercari_df['price']\nplt.figure(figsize=(6,4))\nsns.histplot(y_train_df, bins=100)\nplt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**타겟값 로그 변환 후 분포도 확인**","metadata":{}},{"cell_type":"code","source":"import numpy as np\n\ny_train_df = np.log1p(y_train_df)\nsns.histplot(y_train_df, bins=50)\nplt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mercari_df['price'] = np.log1p(mercari_df['price'])\nmercari_df['price'].head(3)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**각 피처들의 유형 살펴보기**","metadata":{}},{"cell_type":"code","source":"print('Shipping 값 유형:\\n',mercari_df['shipping'].value_counts())\nprint('item_condition_id 값 유형:\\n',mercari_df['item_condition_id'].value_counts())\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"boolean_cond= mercari_df['item_description']=='No description yet'\nmercari_df[boolean_cond]['item_description'].count()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**category name이 대/중/소 와 같이 '/' 문자열 기반으로 되어 있음. 이를 개별 컬럼들로 재 생성**","metadata":{}},{"cell_type":"code","source":"'Men/Tops/T-shirts'.split('/')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# apply lambda에서 호출되는 대,중,소 분할 함수 생성, 대,중,소 값을 리스트 반환\ndef split_cat(category_name):\n try:\n return category_name.split('/')\n except:\n return ['Other_Null' , 'Other_Null' , 'Other_Null']\n\n# 위의 split_cat( )을 apply lambda에서 호출하여 대,중,소 컬럼을 mercari_df에 생성. \nmercari_df['cat_dae'], mercari_df['cat_jung'], mercari_df['cat_so'] = \\\n zip(*mercari_df['category_name'].apply(lambda x : split_cat(x)))\n\n# 대분류만 값의 유형과 건수를 살펴보고, 중분류, 소분류는 값의 유형이 많으므로 분류 갯수만 추출\nprint('대분류 유형 :\\n', mercari_df['cat_dae'].value_counts())\nprint('중분류 갯수 :', mercari_df['cat_jung'].nunique())\nprint('소분류 갯수 :', mercari_df['cat_so'].nunique())\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"'Men/Tops/T-shirts'.split('/')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# apply lambda에서 호출되는 대,중,소 분할 함수 생성, 대,중,소 값을 리스트 반환\ndef split_cat(category_name):\n try:\n return category_name.split('/')\n except:\n return ['Other_Null' , 'Other_Null' , 'Other_Null']\n\n# 위의 split_cat( )을 apply lambda에서 호출하여 대,중,소 컬럼을 mercari_df에 생성. \nmercari_df['category_list'] = mercari_df['category_name'].apply(lambda x : split_cat(x))\nmercari_df['category_list'].head()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mercari_df['cat_dae'] = mercari_df['category_list'].apply(lambda x:x[0])\nmercari_df['cat_jung'] = mercari_df['category_list'].apply(lambda x:x[1])\nmercari_df['cat_so'] = mercari_df['category_list'].apply(lambda x:x[2])\n\nmercari_df.drop('category_list', axis=1, inplace=True) ","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mercari_df[['cat_dae','cat_jung','cat_so']].head()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Null값 일괄 처리**","metadata":{}},{"cell_type":"code","source":"mercari_df['brand_name'] = mercari_df['brand_name'].fillna(value='Other_Null')\nmercari_df['category_name'] = mercari_df['category_name'].fillna(value='Other_Null')\nmercari_df['item_description'] = mercari_df['item_description'].fillna(value='Other_Null')\n\n# 각 컬럼별로 Null값 건수 확인. 모두 0가 나와야 합니다.\nmercari_df.isnull().sum()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mercari_df.info()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 피처 인코딩과 피처 벡터화","metadata":{}},{"cell_type":"markdown","source":"**brand name과 name의 종류 확인**","metadata":{}},{"cell_type":"code","source":"print('brand name 의 유형 건수 :', mercari_df['brand_name'].nunique())\nprint('brand name sample 5건 : \\n', mercari_df['brand_name'].value_counts()[:5])","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('name 의 종류 갯수 :', mercari_df['name'].nunique())\nprint('name sample 7건 : \\n', mercari_df['name'][:7])","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**item_description의 문자열 개수 확인**","metadata":{}},{"cell_type":"code","source":"mercari_df['item_description'].str.len().mean()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pd.set_option('max_colwidth', 200)\n\n# item_description의 평균 문자열 개수\nprint('item_description 평균 문자열 개수:',mercari_df['item_description'].str.len().mean())\n\nmercari_df['item_description'][:2]","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc\ngc.collect()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**name은 Count로, item_description은 TF-IDF로 피처 벡터화**","metadata":{}},{"cell_type":"code","source":"# name 속성에 대한 feature vectorization 변환\ncnt_vec = CountVectorizer()\nX_name = cnt_vec.fit_transform(mercari_df['name'])\n\n# item_description 에 대한 feature vectorization 변환 \ntfidf_descp = TfidfVectorizer(max_features = 50000, ngram_range= (1,3) , stop_words='english')\nX_descp = tfidf_descp.fit_transform(mercari_df['item_description'])\n\nprint('name vectorization shape:',X_name.shape)\nprint('item_description vectorization shape:',X_descp.shape)\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**사이킷런의 LabelBinarizer를 이용하여 원-핫 인코딩 변환 후 희소행렬 최적화 형태로 저장**","metadata":{}},{"cell_type":"code","source":"from sklearn import preprocessing\nlb = preprocessing.LabelBinarizer()\nohe_result = lb.fit_transform([1, 2, 6, 4, 2])\nprint(type(ohe_result))\nprint(ohe_result)\n\nlb_sparse = preprocessing.LabelBinarizer(sparse_output=True)\nohe_result_sparse = lb_sparse.fit_transform([1, 2, 6, 4, 2])\nprint(type(ohe_result_sparse))\nprint(ohe_result_sparse)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.preprocessing import LabelBinarizer\n\n# brand_name, item_condition_id, shipping 각 피처들을 희소 행렬 원-핫 인코딩 변환\nlb_brand_name= LabelBinarizer(sparse_output=True)\nX_brand = lb_brand_name.fit_transform(mercari_df['brand_name'])\n\nlb_item_cond_id = LabelBinarizer(sparse_output=True)\nX_item_cond_id = lb_item_cond_id.fit_transform(mercari_df['item_condition_id'])\n\nlb_shipping= LabelBinarizer(sparse_output=True)\nX_shipping = lb_shipping.fit_transform(mercari_df['shipping'])\n\n# cat_dae, cat_jung, cat_so 각 피처들을 희소 행렬 원-핫 인코딩 변환\nlb_cat_dae = LabelBinarizer(sparse_output=True)\nX_cat_dae= lb_cat_dae.fit_transform(mercari_df['cat_dae'])\n\nlb_cat_jung = LabelBinarizer(sparse_output=True)\nX_cat_jung = lb_cat_jung.fit_transform(mercari_df['cat_jung'])\n\nlb_cat_so = LabelBinarizer(sparse_output=True)\nX_cat_so = lb_cat_so.fit_transform(mercari_df['cat_so'])","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(type(X_brand), type(X_item_cond_id), type(X_shipping))\nprint('X_brand_shape:{0}, X_item_cond_id shape:{1}'.format(X_brand.shape, X_item_cond_id.shape))\nprint('X_shipping shape:{0}, X_cat_dae shape:{1}'.format(X_shipping.shape, X_cat_dae.shape))\nprint('X_cat_jung shape:{0}, X_cat_so shape:{1}'.format(X_cat_jung.shape, X_cat_so.shape))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc\ngc.collect()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 사이킷런 버전이 upgrade되면서 아래와 같이 OneHotEncoder를 적용해도 됩니다. ","metadata":{}},{"cell_type":"code","source":"from sklearn.preprocessing import OneHotEncoder\nimport numpy as np\n\n# 원-핫 인코딩을 적용합니다. \noh_encoder = OneHotEncoder()\n\n# brand_name, item_condition_id, shipping 각 피처들을 희소 행렬 원-핫 인코딩 변환\nX_brand = oh_encoder.fit_transform(mercari_df['brand_name'].values.reshape(-1, 1))\nX_item_cond_id = oh_encoder.fit_transform(mercari_df['item_condition_id'].values.reshape(-1, 1))\nX_shipping = oh_encoder.fit_transform(mercari_df['shipping'].values.reshape(-1, 1))\nX_cat_dae= oh_encoder.fit_transform(mercari_df['cat_dae'].values.reshape(-1, 1))\nX_cat_jung = oh_encoder.fit_transform(mercari_df['cat_jung'].values.reshape(-1, 1))\nX_cat_so = oh_encoder.fit_transform(mercari_df['cat_so'].values.reshape(-1, 1))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(type(X_brand), type(X_item_cond_id), type(X_shipping))\nprint('X_brand_shape:{0}, X_item_cond_id shape:{1}'.format(X_brand.shape, X_item_cond_id.shape))\nprint('X_shipping shape:{0}, X_cat_dae shape:{1}'.format(X_shipping.shape, X_cat_dae.shape))\nprint('X_cat_jung shape:{0}, X_cat_so shape:{1}'.format(X_cat_jung.shape, X_cat_so.shape))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**피처 벡터화된 희소 행렬과 원-핫 인코딩된 희소 행렬을 모두 scipy 패키지의 hstack()함수를 이용하여 결합**","metadata":{}},{"cell_type":"code","source":"from scipy.sparse import hstack\nimport gc\n\nsparse_matrix_list = (X_name, X_descp, X_brand, X_item_cond_id,\n X_shipping, X_cat_dae, X_cat_jung, X_cat_so)\n\n# 사이파이 sparse 모듈의 hstack 함수를 이용하여 앞에서 인코딩과 Vectorization을 수행한 데이터 셋을 모두 결합. \nX_features_sparse= hstack(sparse_matrix_list).tocsr()\nprint(type(X_features_sparse), X_features_sparse.shape)\n\n# 데이터 셋이 메모리를 많이 차지하므로 사용 용도가 끝났으면 바로 메모리에서 삭제. \ndel X_features_sparse\ngc.collect()\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 릿지 회귀 모델 구축 및 평가","metadata":{}},{"cell_type":"markdown","source":"**rmsle 정의**","metadata":{}},{"cell_type":"code","source":"def rmsle(y , y_pred):\n # underflow, overflow를 막기 위해 log가 아닌 log1p로 rmsle 계산 \n return np.sqrt(np.mean(np.power(np.log1p(y) - np.log1p(y_pred), 2)))\n\ndef evaluate_org_price(y_test , preds): \n \n # 원본 데이터는 log1p로 변환되었으므로 expm1으로 원복 필요. \n preds_exmpm = np.expm1(preds)\n y_test_exmpm = np.expm1(y_test)\n \n # rmsle로 RMSLE 값 추출\n rmsle_result = rmsle(y_test_exmpm, preds_exmpm)\n return rmsle_result","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**여러 모델에 대한 학습/예측을 수행하기 위해 별도의 함수인 model_train_predict()생성.** \n\n해당 함수는 여러 희소 행렬을 hstack()으로 결합한 뒤 학습과 테스트 데이터 세트로 분할 후 모델 학습 및 예측을 수행 ","metadata":{}},{"cell_type":"code","source":"import gc \nfrom scipy.sparse import hstack\n\ndef model_train_predict(model,matrix_list):\n # scipy.sparse 모듈의 hstack 을 이용하여 sparse matrix 결합\n X= hstack(matrix_list).tocsr() \n \n X_train, X_test, y_train, y_test=train_test_split(X, mercari_df['price'], \n test_size=0.2, random_state=156)\n \n # 모델 학습 및 예측\n model.fit(X_train , y_train)\n preds = model.predict(X_test)\n \n del X , X_train , X_test , y_train \n gc.collect()\n \n return preds , y_test","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**릿지 선형 회귀로 학습/예측/평가. Item Description 피처의 영향도를 알아보기 위한 테스트 함께 수행**","metadata":{}},{"cell_type":"code","source":"linear_model = Ridge(solver = \"lsqr\", fit_intercept=False)\n\nsparse_matrix_list = (X_name, X_brand, X_item_cond_id,\n X_shipping, X_cat_dae, X_cat_jung, X_cat_so)\nlinear_preds , y_test = model_train_predict(model=linear_model ,matrix_list=sparse_matrix_list)\nprint('Item Description을 제외했을 때 rmsle 값:', evaluate_org_price(y_test , linear_preds))\n\nsparse_matrix_list = (X_descp, X_name, X_brand, X_item_cond_id,\n X_shipping, X_cat_dae, X_cat_jung, X_cat_so)\nlinear_preds , y_test = model_train_predict(model=linear_model , matrix_list=sparse_matrix_list)\nprint('Item Description을 포함한 rmsle 값:', evaluate_org_price(y_test ,linear_preds))\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc\ngc.collect()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### LightGBM 회귀 모델 구축과 앙상블을 이용한 최종 예측 평가","metadata":{}},{"cell_type":"code","source":"from lightgbm import LGBMRegressor\n\nsparse_matrix_list = (X_descp, X_name, X_brand, X_item_cond_id,\n X_shipping, X_cat_dae, X_cat_jung, X_cat_so)\n\nlgbm_model = LGBMRegressor(n_estimators=200, learning_rate=0.5, num_leaves=125, random_state=156)\nlgbm_preds , y_test = model_train_predict(model = lgbm_model , matrix_list=sparse_matrix_list)\nprint('LightGBM rmsle 값:', evaluate_org_price(y_test , lgbm_preds))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"preds = lgbm_preds * 0.45 + linear_preds * 0.55\nprint('LightGBM과 Ridge를 ensemble한 최종 rmsle 값:', evaluate_org_price(y_test , preds))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}
--------------------------------------------------------------------------------
/8장/8.2 텍스트 사전 준비 작업(텍스트 전처리) - 텍스트 정규화_8.3 Bag of Words _ BOW.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "## 8.2 텍스트 사전 준비 작업(텍스트 전처리) - 텍스트 정규화"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "### Text Tokenization"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "**문장 토큰화**"
22 | ]
23 | },
24 | {
25 | "cell_type": "code",
26 | "execution_count": 2,
27 | "metadata": {},
28 | "outputs": [
29 | {
30 | "name": "stdout",
31 | "output_type": "stream",
32 | "text": [
33 | " 3\n",
34 | "['The Matrix is everywhere its all around us, here even in this room.', 'You can see it out your window or on your television.', 'You feel it when you go to work, or go to church or pay your taxes.']\n"
35 | ]
36 | }
37 | ],
38 | "source": [
39 | "from nltk import sent_tokenize\n",
40 | "text_sample = 'The Matrix is everywhere its all around us, here even in this room. \\\n",
41 | " You can see it out your window or on your television. \\\n",
42 | " You feel it when you go to work, or go to church or pay your taxes.'\n",
43 | "sentences = sent_tokenize(text=text_sample)\n",
44 | "print(type(sentences),len(sentences))\n",
45 | "print(sentences)"
46 | ]
47 | },
48 | {
49 | "cell_type": "markdown",
50 | "metadata": {},
51 | "source": [
52 | "**단어 토큰화**"
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "execution_count": 3,
58 | "metadata": {},
59 | "outputs": [
60 | {
61 | "name": "stdout",
62 | "output_type": "stream",
63 | "text": [
64 | " 15\n",
65 | "['The', 'Matrix', 'is', 'everywhere', 'its', 'all', 'around', 'us', ',', 'here', 'even', 'in', 'this', 'room', '.']\n"
66 | ]
67 | }
68 | ],
69 | "source": [
70 | "from nltk import word_tokenize\n",
71 | "\n",
72 | "sentence = \"The Matrix is everywhere its all around us, here even in this room.\"\n",
73 | "words = word_tokenize(sentence)\n",
74 | "print(type(words), len(words))\n",
75 | "print(words)"
76 | ]
77 | },
78 | {
79 | "cell_type": "markdown",
80 | "metadata": {},
81 | "source": [
82 | "**여러 문장들에 대한 단어 토큰화**"
83 | ]
84 | },
85 | {
86 | "cell_type": "code",
87 | "execution_count": 4,
88 | "metadata": {},
89 | "outputs": [
90 | {
91 | "name": "stdout",
92 | "output_type": "stream",
93 | "text": [
94 | " 3\n",
95 | "[['The', 'Matrix', 'is', 'everywhere', 'its', 'all', 'around', 'us', ',', 'here', 'even', 'in', 'this', 'room', '.'], ['You', 'can', 'see', 'it', 'out', 'your', 'window', 'or', 'on', 'your', 'television', '.'], ['You', 'feel', 'it', 'when', 'you', 'go', 'to', 'work', ',', 'or', 'go', 'to', 'church', 'or', 'pay', 'your', 'taxes', '.']]\n"
96 | ]
97 | }
98 | ],
99 | "source": [
100 | "from nltk import word_tokenize, sent_tokenize\n",
101 | "\n",
102 | "#여러개의 문장으로 된 입력 데이터를 문장별로 단어 토큰화 만드는 함수 생성\n",
103 | "def tokenize_text(text):\n",
104 | " \n",
105 | " # 문장별로 분리 토큰\n",
106 | " sentences = sent_tokenize(text)\n",
107 | " # 분리된 문장별 단어 토큰화\n",
108 | " word_tokens = [word_tokenize(sentence) for sentence in sentences]\n",
109 | " return word_tokens\n",
110 | "\n",
111 | "#여러 문장들에 대해 문장별 단어 토큰화 수행. \n",
112 | "word_tokens = tokenize_text(text_sample)\n",
113 | "print(type(word_tokens),len(word_tokens))\n",
114 | "print(word_tokens)"
115 | ]
116 | },
117 | {
118 | "cell_type": "markdown",
119 | "metadata": {},
120 | "source": [
121 | "**n-gram**"
122 | ]
123 | },
124 | {
125 | "cell_type": "code",
126 | "execution_count": 6,
127 | "metadata": {},
128 | "outputs": [
129 | {
130 | "name": "stdout",
131 | "output_type": "stream",
132 | "text": [
133 | "[('The', 'Matrix'), ('Matrix', 'is'), ('is', 'everywhere'), ('everywhere', 'its'), ('its', 'all'), ('all', 'around'), ('around', 'us'), ('us', ','), (',', 'here'), ('here', 'even'), ('even', 'in'), ('in', 'this'), ('this', 'room'), ('room', '.')]\n"
134 | ]
135 | }
136 | ],
137 | "source": [
138 | "from nltk import ngrams\n",
139 | "\n",
140 | "sentence = \"The Matrix is everywhere its all around us, here even in this room.\"\n",
141 | "words = word_tokenize(sentence)\n",
142 | "\n",
143 | "all_ngrams = ngrams(words, 2)\n",
144 | "ngrams = [ngram for ngram in all_ngrams]\n",
145 | "print(ngrams)"
146 | ]
147 | },
148 | {
149 | "cell_type": "markdown",
150 | "metadata": {},
151 | "source": [
152 | "### Stopwords 제거"
153 | ]
154 | },
155 | {
156 | "cell_type": "code",
157 | "execution_count": 7,
158 | "metadata": {},
159 | "outputs": [
160 | {
161 | "name": "stdout",
162 | "output_type": "stream",
163 | "text": [
164 | "[nltk_data] Downloading package stopwords to\n",
165 | "[nltk_data] C:\\Users\\KwonChulmin\\AppData\\Roaming\\nltk_data...\n",
166 | "[nltk_data] Unzipping corpora\\stopwords.zip.\n"
167 | ]
168 | },
169 | {
170 | "data": {
171 | "text/plain": [
172 | "True"
173 | ]
174 | },
175 | "execution_count": 7,
176 | "metadata": {},
177 | "output_type": "execute_result"
178 | }
179 | ],
180 | "source": [
181 | "import nltk\n",
182 | "nltk.download('stopwords')"
183 | ]
184 | },
185 | {
186 | "cell_type": "code",
187 | "execution_count": 9,
188 | "metadata": {},
189 | "outputs": [
190 | {
191 | "name": "stdout",
192 | "output_type": "stream",
193 | "text": [
194 | "영어 stop words 갯수: 179\n",
195 | "['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', \"you're\", \"you've\", \"you'll\", \"you'd\", 'your', 'yours', 'yourself', 'yourselves', 'he', 'him', 'his', 'himself', 'she', \"she's\", 'her', 'hers', 'herself', 'it', \"it's\", 'its', 'itself', 'they', 'them', 'their', 'theirs', 'themselves', 'what', 'which', 'who', 'whom', 'this']\n"
196 | ]
197 | }
198 | ],
199 | "source": [
200 | "print('영어 stop words 갯수:',len(nltk.corpus.stopwords.words('english')))\n",
201 | "print(nltk.corpus.stopwords.words('english')[:40])"
202 | ]
203 | },
204 | {
205 | "cell_type": "code",
206 | "execution_count": 10,
207 | "metadata": {},
208 | "outputs": [
209 | {
210 | "name": "stdout",
211 | "output_type": "stream",
212 | "text": [
213 | "[['matrix', 'everywhere', 'around', 'us', ',', 'even', 'room', '.'], ['see', 'window', 'television', '.'], ['feel', 'go', 'work', ',', 'go', 'church', 'pay', 'taxes', '.']]\n"
214 | ]
215 | }
216 | ],
217 | "source": [
218 | "import nltk\n",
219 | "\n",
220 | "stopwords = nltk.corpus.stopwords.words('english')\n",
221 | "all_tokens = []\n",
222 | "# 위 예제의 3개의 문장별로 얻은 word_tokens list 에 대해 stop word 제거 Loop\n",
223 | "for sentence in word_tokens:\n",
224 | " filtered_words=[]\n",
225 | " # 개별 문장별로 tokenize된 sentence list에 대해 stop word 제거 Loop\n",
226 | " for word in sentence:\n",
227 | " #소문자로 모두 변환합니다. \n",
228 | " word = word.lower()\n",
229 | " # tokenize 된 개별 word가 stop words 들의 단어에 포함되지 않으면 word_tokens에 추가\n",
230 | " if word not in stopwords:\n",
231 | " filtered_words.append(word)\n",
232 | " all_tokens.append(filtered_words)\n",
233 | " \n",
234 | "print(all_tokens)"
235 | ]
236 | },
237 | {
238 | "cell_type": "markdown",
239 | "metadata": {},
240 | "source": [
241 | "### Stemming과 Lemmatization"
242 | ]
243 | },
244 | {
245 | "cell_type": "code",
246 | "execution_count": 11,
247 | "metadata": {},
248 | "outputs": [
249 | {
250 | "name": "stdout",
251 | "output_type": "stream",
252 | "text": [
253 | "work work work\n",
254 | "amus amus amus\n",
255 | "happy happiest\n",
256 | "fant fanciest\n"
257 | ]
258 | }
259 | ],
260 | "source": [
261 | "from nltk.stem import LancasterStemmer\n",
262 | "stemmer = LancasterStemmer()\n",
263 | "\n",
264 | "print(stemmer.stem('working'),stemmer.stem('works'),stemmer.stem('worked'))\n",
265 | "print(stemmer.stem('amusing'),stemmer.stem('amuses'),stemmer.stem('amused'))\n",
266 | "print(stemmer.stem('happier'),stemmer.stem('happiest'))\n",
267 | "print(stemmer.stem('fancier'),stemmer.stem('fanciest'))"
268 | ]
269 | },
270 | {
271 | "cell_type": "code",
272 | "execution_count": 12,
273 | "metadata": {},
274 | "outputs": [
275 | {
276 | "name": "stdout",
277 | "output_type": "stream",
278 | "text": [
279 | "amuse amuse amuse\n",
280 | "happy happy\n",
281 | "fancy fancy\n"
282 | ]
283 | }
284 | ],
285 | "source": [
286 | "from nltk.stem import WordNetLemmatizer\n",
287 | "\n",
288 | "lemma = WordNetLemmatizer()\n",
289 | "print(lemma.lemmatize('amusing','v'),lemma.lemmatize('amuses','v'),lemma.lemmatize('amused','v'))\n",
290 | "print(lemma.lemmatize('happier','a'),lemma.lemmatize('happiest','a'))\n",
291 | "print(lemma.lemmatize('fancier','a'),lemma.lemmatize('fanciest','a'))"
292 | ]
293 | },
294 | {
295 | "cell_type": "markdown",
296 | "metadata": {},
297 | "source": [
298 | "### 8.3 Bag of Words – BOW"
299 | ]
300 | },
301 | {
302 | "cell_type": "markdown",
303 | "metadata": {},
304 | "source": [
305 | "**사이킷런 CountVectorizer 테스트**"
306 | ]
307 | },
308 | {
309 | "cell_type": "code",
310 | "execution_count": null,
311 | "metadata": {},
312 | "outputs": [],
313 | "source": [
314 | "text_sample_01 = 'The Matrix is everywhere its all around us, here even in this room. \\\n",
315 | " You can see it out your window or on your television. \\\n",
316 | " You feel it when you go to work, or go to church or pay your taxes.'\n",
317 | "text_sample_02 = 'You take the blue pill and the story ends. You wake in your bed and you believe whatever you want to believe\\\n",
318 | " You take the red pill and you stay in Wonderland and I show you how deep the rabbit-hole goes.'\n",
319 | "text=[]\n",
320 | "text.append(text_sample_01); text.append(text_sample_02)\n",
321 | "print(text,\"\\n\", len(text))"
322 | ]
323 | },
324 | {
325 | "cell_type": "markdown",
326 | "metadata": {},
327 | "source": [
328 | "**CountVectorizer객체 생성 후 fit(), transform()으로 텍스트에 대한 feature vectorization 수행**"
329 | ]
330 | },
331 | {
332 | "cell_type": "code",
333 | "execution_count": null,
334 | "metadata": {},
335 | "outputs": [],
336 | "source": [
337 | "from sklearn.feature_extraction.text import CountVectorizer\n",
338 | "\n",
339 | "# Count Vectorization으로 feature extraction 변환 수행. \n",
340 | "cnt_vect = CountVectorizer()\n",
341 | "cnt_vect.fit(text)"
342 | ]
343 | },
344 | {
345 | "cell_type": "code",
346 | "execution_count": null,
347 | "metadata": {},
348 | "outputs": [],
349 | "source": [
350 | "ftr_vect = cnt_vect.transform(text)"
351 | ]
352 | },
353 | {
354 | "cell_type": "markdown",
355 | "metadata": {},
356 | "source": [
357 | "**피처 벡터화 후 데이터 유형 및 여러 속성 확인**"
358 | ]
359 | },
360 | {
361 | "cell_type": "code",
362 | "execution_count": null,
363 | "metadata": {},
364 | "outputs": [],
365 | "source": [
366 | "print(type(ftr_vect), ftr_vect.shape)\n",
367 | "print(ftr_vect)"
368 | ]
369 | },
370 | {
371 | "cell_type": "code",
372 | "execution_count": null,
373 | "metadata": {},
374 | "outputs": [],
375 | "source": [
376 | "print(cnt_vect.vocabulary_)"
377 | ]
378 | },
379 | {
380 | "cell_type": "code",
381 | "execution_count": null,
382 | "metadata": {},
383 | "outputs": [],
384 | "source": [
385 | "cnt_vect = CountVectorizer(max_features=5, stop_words='english')\n",
386 | "cnt_vect.fit(text)\n",
387 | "ftr_vect = cnt_vect.transform(text)\n",
388 | "print(type(ftr_vect), ftr_vect.shape)\n",
389 | "print(cnt_vect.vocabulary_)\n"
390 | ]
391 | },
392 | {
393 | "cell_type": "markdown",
394 | "metadata": {},
395 | "source": [
396 | "**ngram_range 확인**"
397 | ]
398 | },
399 | {
400 | "cell_type": "code",
401 | "execution_count": null,
402 | "metadata": {},
403 | "outputs": [],
404 | "source": [
405 | "cnt_vect = CountVectorizer(ngram_range=(1,3))\n",
406 | "cnt_vect.fit(text)\n",
407 | "ftr_vect = cnt_vect.transform(text)\n",
408 | "print(type(ftr_vect), ftr_vect.shape)\n",
409 | "print(cnt_vect.vocabulary_)"
410 | ]
411 | },
412 | {
413 | "cell_type": "markdown",
414 | "metadata": {},
415 | "source": []
416 | },
417 | {
418 | "cell_type": "markdown",
419 | "metadata": {},
420 | "source": [
421 | "### 희소 행렬 - COO 형식"
422 | ]
423 | },
424 | {
425 | "cell_type": "code",
426 | "execution_count": null,
427 | "metadata": {},
428 | "outputs": [],
429 | "source": [
430 | "import numpy as np\n",
431 | "\n",
432 | "dense = np.array( [ [ 3, 0, 1 ], \n",
433 | " [0, 2, 0 ] ] )"
434 | ]
435 | },
436 | {
437 | "cell_type": "code",
438 | "execution_count": null,
439 | "metadata": {},
440 | "outputs": [],
441 | "source": [
442 | "from scipy import sparse\n",
443 | "\n",
444 | "# 0 이 아닌 데이터 추출\n",
445 | "data = np.array([3,1,2])\n",
446 | "\n",
447 | "# 행 위치와 열 위치를 각각 array로 생성 \n",
448 | "row_pos = np.array([0,0,1])\n",
449 | "col_pos = np.array([0,2,1])\n",
450 | "\n",
451 | "# sparse 패키지의 coo_matrix를 이용하여 COO 형식으로 희소 행렬 생성\n",
452 | "sparse_coo = sparse.coo_matrix((data, (row_pos,col_pos)))"
453 | ]
454 | },
455 | {
456 | "cell_type": "code",
457 | "execution_count": null,
458 | "metadata": {},
459 | "outputs": [],
460 | "source": [
461 | "print(type(sparse_coo))\n",
462 | "print(sparse_coo)\n",
463 | "dense01=sparse_coo.toarray()\n",
464 | "print(type(dense01),\"\\n\", dense01)"
465 | ]
466 | },
467 | {
468 | "cell_type": "markdown",
469 | "metadata": {},
470 | "source": [
471 | "### 희소 행렬 – CSR 형식"
472 | ]
473 | },
474 | {
475 | "cell_type": "code",
476 | "execution_count": null,
477 | "metadata": {},
478 | "outputs": [],
479 | "source": [
480 | "from scipy import sparse\n",
481 | "\n",
482 | "dense2 = np.array([[0,0,1,0,0,5],\n",
483 | " [1,4,0,3,2,5],\n",
484 | " [0,6,0,3,0,0],\n",
485 | " [2,0,0,0,0,0],\n",
486 | " [0,0,0,7,0,8],\n",
487 | " [1,0,0,0,0,0]])\n",
488 | "\n",
489 | "# 0 이 아닌 데이터 추출\n",
490 | "data2 = np.array([1, 5, 1, 4, 3, 2, 5, 6, 3, 2, 7, 8, 1])\n",
491 | "\n",
492 | "# 행 위치와 열 위치를 각각 array로 생성 \n",
493 | "row_pos = np.array([0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 4, 4, 5])\n",
494 | "col_pos = np.array([2, 5, 0, 1, 3, 4, 5, 1, 3, 0, 3, 5, 0])\n",
495 | "\n",
496 | "# COO 형식으로 변환 \n",
497 | "sparse_coo = sparse.coo_matrix((data2, (row_pos,col_pos)))\n",
498 | "\n",
499 | "# 행 위치 배열의 고유한 값들의 시작 위치 인덱스를 배열로 생성\n",
500 | "row_pos_ind = np.array([0, 2, 7, 9, 10, 12, 13])\n",
501 | "\n",
502 | "# CSR 형식으로 변환 \n",
503 | "sparse_csr = sparse.csr_matrix((data2, col_pos, row_pos_ind))\n",
504 | "\n",
505 | "print('COO 변환된 데이터가 제대로 되었는지 다시 Dense로 출력 확인')\n",
506 | "print(sparse_coo.toarray())\n",
507 | "print('CSR 변환된 데이터가 제대로 되었는지 다시 Dense로 출력 확인')\n",
508 | "print(sparse_csr.toarray())\n"
509 | ]
510 | },
511 | {
512 | "cell_type": "code",
513 | "execution_count": null,
514 | "metadata": {},
515 | "outputs": [],
516 | "source": [
517 | "print(sparse_csr)"
518 | ]
519 | },
520 | {
521 | "cell_type": "code",
522 | "execution_count": null,
523 | "metadata": {},
524 | "outputs": [],
525 | "source": [
526 | "dense3 = np.array([[0,0,1,0,0,5],\n",
527 | " [1,4,0,3,2,5],\n",
528 | " [0,6,0,3,0,0],\n",
529 | " [2,0,0,0,0,0],\n",
530 | " [0,0,0,7,0,8],\n",
531 | " [1,0,0,0,0,0]])\n",
532 | "\n",
533 | "coo = sparse.coo_matrix(dense3)\n",
534 | "csr = sparse.csr_matrix(dense3)"
535 | ]
536 | },
537 | {
538 | "cell_type": "code",
539 | "execution_count": null,
540 | "metadata": {},
541 | "outputs": [],
542 | "source": []
543 | }
544 | ],
545 | "metadata": {
546 | "kernelspec": {
547 | "display_name": "Python 3",
548 | "language": "python",
549 | "name": "python3"
550 | },
551 | "language_info": {
552 | "codemirror_mode": {
553 | "name": "ipython",
554 | "version": 3
555 | },
556 | "file_extension": ".py",
557 | "mimetype": "text/x-python",
558 | "name": "python",
559 | "nbconvert_exporter": "python",
560 | "pygments_lexer": "ipython3",
561 | "version": "3.6.4"
562 | }
563 | },
564 | "nbformat": 4,
565 | "nbformat_minor": 2
566 | }
567 |
--------------------------------------------------------------------------------
/8장/8.4 텍스트 분류 실습 _ 20 뉴스그룹 분류.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### 20 뉴스그룹 분류\n",
8 | "\n",
9 | "**데이터 로딩과 데이터 구성 확인**"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [],
17 | "source": [
18 | "from sklearn.datasets import fetch_20newsgroups\n",
19 | "\n",
20 | "news_data = fetch_20newsgroups(subset='all',random_state=156)"
21 | ]
22 | },
23 | {
24 | "cell_type": "code",
25 | "execution_count": 2,
26 | "metadata": {},
27 | "outputs": [
28 | {
29 | "data": {
30 | "text/plain": [
31 | "sklearn.utils.Bunch"
32 | ]
33 | },
34 | "execution_count": 2,
35 | "metadata": {},
36 | "output_type": "execute_result"
37 | }
38 | ],
39 | "source": [
40 | "type(news_data)"
41 | ]
42 | },
43 | {
44 | "cell_type": "code",
45 | "execution_count": 3,
46 | "metadata": {},
47 | "outputs": [
48 | {
49 | "name": "stdout",
50 | "output_type": "stream",
51 | "text": [
52 | "dict_keys(['data', 'filenames', 'target_names', 'target', 'DESCR'])\n"
53 | ]
54 | }
55 | ],
56 | "source": [
57 | "print(news_data.keys())"
58 | ]
59 | },
60 | {
61 | "cell_type": "code",
62 | "execution_count": 4,
63 | "metadata": {},
64 | "outputs": [
65 | {
66 | "data": {
67 | "text/plain": [
68 | "['alt.atheism',\n",
69 | " 'comp.graphics',\n",
70 | " 'comp.os.ms-windows.misc',\n",
71 | " 'comp.sys.ibm.pc.hardware',\n",
72 | " 'comp.sys.mac.hardware',\n",
73 | " 'comp.windows.x',\n",
74 | " 'misc.forsale',\n",
75 | " 'rec.autos',\n",
76 | " 'rec.motorcycles',\n",
77 | " 'rec.sport.baseball',\n",
78 | " 'rec.sport.hockey',\n",
79 | " 'sci.crypt',\n",
80 | " 'sci.electronics',\n",
81 | " 'sci.med',\n",
82 | " 'sci.space',\n",
83 | " 'soc.religion.christian',\n",
84 | " 'talk.politics.guns',\n",
85 | " 'talk.politics.mideast',\n",
86 | " 'talk.politics.misc',\n",
87 | " 'talk.religion.misc']"
88 | ]
89 | },
90 | "execution_count": 4,
91 | "metadata": {},
92 | "output_type": "execute_result"
93 | }
94 | ],
95 | "source": [
96 | "news_data.target_names"
97 | ]
98 | },
99 | {
100 | "cell_type": "code",
101 | "execution_count": 5,
102 | "metadata": {},
103 | "outputs": [
104 | {
105 | "name": "stdout",
106 | "output_type": "stream",
107 | "text": [
108 | "target 클래스의 값과 분포도 \n",
109 | " 0 799\n",
110 | "1 973\n",
111 | "2 985\n",
112 | "3 982\n",
113 | "4 963\n",
114 | "5 988\n",
115 | "6 975\n",
116 | "7 990\n",
117 | "8 996\n",
118 | "9 994\n",
119 | "10 999\n",
120 | "11 991\n",
121 | "12 984\n",
122 | "13 990\n",
123 | "14 987\n",
124 | "15 997\n",
125 | "16 910\n",
126 | "17 940\n",
127 | "18 775\n",
128 | "19 628\n",
129 | "dtype: int64\n",
130 | "target 클래스의 이름들 \n",
131 | " ['alt.atheism', 'comp.graphics', 'comp.os.ms-windows.misc', 'comp.sys.ibm.pc.hardware', 'comp.sys.mac.hardware', 'comp.windows.x', 'misc.forsale', 'rec.autos', 'rec.motorcycles', 'rec.sport.baseball', 'rec.sport.hockey', 'sci.crypt', 'sci.electronics', 'sci.med', 'sci.space', 'soc.religion.christian', 'talk.politics.guns', 'talk.politics.mideast', 'talk.politics.misc', 'talk.religion.misc']\n"
132 | ]
133 | }
134 | ],
135 | "source": [
136 | "import pandas as pd\n",
137 | "\n",
138 | "print('target 클래스의 값과 분포도 \\n',pd.Series(news_data.target).value_counts().sort_index())\n",
139 | "print('target 클래스의 이름들 \\n',news_data.target_names)"
140 | ]
141 | },
142 | {
143 | "cell_type": "markdown",
144 | "metadata": {},
145 | "source": [
146 | "**학습과 테스트용 데이터 생성**"
147 | ]
148 | },
149 | {
150 | "cell_type": "code",
151 | "execution_count": 6,
152 | "metadata": {},
153 | "outputs": [
154 | {
155 | "name": "stdout",
156 | "output_type": "stream",
157 | "text": [
158 | "From: egreen@east.sun.com (Ed Green - Pixel Cruncher)\n",
159 | "Subject: Re: Observation re: helmets\n",
160 | "Organization: Sun Microsystems, RTP, NC\n",
161 | "Lines: 21\n",
162 | "Distribution: world\n",
163 | "Reply-To: egreen@east.sun.com\n",
164 | "NNTP-Posting-Host: laser.east.sun.com\n",
165 | "\n",
166 | "In article 211353@mavenry.altcit.eskimo.com, maven@mavenry.altcit.eskimo.com (Norman Hamer) writes:\n",
167 | "> \n",
168 | "> The question for the day is re: passenger helmets, if you don't know for \n",
169 | ">certain who's gonna ride with you (like say you meet them at a .... church \n",
170 | ">meeting, yeah, that's the ticket)... What are some guidelines? Should I just \n",
171 | ">pick up another shoei in my size to have a backup helmet (XL), or should I \n",
172 | ">maybe get an inexpensive one of a smaller size to accomodate my likely \n",
173 | ">passenger? \n",
174 | "\n",
175 | "If your primary concern is protecting the passenger in the event of a\n",
176 | "crash, have him or her fitted for a helmet that is their size. If your\n",
177 | "primary concern is complying with stupid helmet laws, carry a real big\n",
178 | "spare (you can put a big or small head in a big helmet, but not in a\n",
179 | "small one).\n",
180 | "\n",
181 | "---\n",
182 | "Ed Green, former Ninjaite |I was drinking last night with a biker,\n",
183 | " Ed.Green@East.Sun.COM |and I showed him a picture of you. I said,\n",
184 | "DoD #0111 (919)460-8302 |\"Go on, get to know her, you'll like her!\"\n",
185 | " (The Grateful Dead) --> |It seemed like the least I could do...\n",
186 | "\n",
187 | "\n"
188 | ]
189 | }
190 | ],
191 | "source": [
192 | "print(news_data.data[0])"
193 | ]
194 | },
195 | {
196 | "cell_type": "code",
197 | "execution_count": 7,
198 | "metadata": {},
199 | "outputs": [
200 | {
201 | "name": "stdout",
202 | "output_type": "stream",
203 | "text": [
204 | "\n",
205 | "학습 데이터 크기 11314 , 테스트 데이터 크기 7532\n"
206 | ]
207 | }
208 | ],
209 | "source": [
210 | "from sklearn.datasets import fetch_20newsgroups\n",
211 | "\n",
212 | "# subset='train'으로 학습용(Train) 데이터만 추출, remove=('headers', 'footers', 'quotes')로 내용만 추출\n",
213 | "train_news= fetch_20newsgroups(subset='train', remove=('headers', 'footers', 'quotes'), random_state=156)\n",
214 | "X_train = train_news.data\n",
215 | "y_train = train_news.target\n",
216 | "print(type(X_train))\n",
217 | "\n",
218 | "# subset='test'으로 테스트(Test) 데이터만 추출, remove=('headers', 'footers', 'quotes')로 내용만 추출\n",
219 | "test_news= fetch_20newsgroups(subset='test',remove=('headers', 'footers','quotes'),random_state=156)\n",
220 | "X_test = test_news.data\n",
221 | "y_test = test_news.target\n",
222 | "print('학습 데이터 크기 {0} , 테스트 데이터 크기 {1}'.format(len(train_news.data) , len(test_news.data)))\n"
223 | ]
224 | },
225 | {
226 | "cell_type": "markdown",
227 | "metadata": {},
228 | "source": [
229 | "### 피처 벡터화 변환과 머신러닝 모델 학습/예측/평가\n",
230 | "**주의: 학습 데이터에 대해 fit( )된 CountVectorizer를 이용해서 테스트 데이터를 피처 벡터화 해야함.** \n",
231 | "\n",
232 | "테스트 데이터에서 다시 CountVectorizer의 fit_transform()을 수행하거나 fit()을 수행 하면 안됨. \n",
233 | "이는 이렇게 테스트 데이터에서 fit()을 수행하게 되면 기존 학습된 모델에서 가지는 feature의 갯수가 달라지기 때문임."
234 | ]
235 | },
236 | {
237 | "cell_type": "code",
238 | "execution_count": 12,
239 | "metadata": {},
240 | "outputs": [
241 | {
242 | "name": "stdout",
243 | "output_type": "stream",
244 | "text": [
245 | "학습 데이터 Text의 CountVectorizer Shape: (11314, 101631)\n"
246 | ]
247 | }
248 | ],
249 | "source": [
250 | "from sklearn.feature_extraction.text import CountVectorizer\n",
251 | "\n",
252 | "# Count Vectorization으로 feature extraction 변환 수행. \n",
253 | "cnt_vect = CountVectorizer()\n",
254 | "cnt_vect.fit(X_train)\n",
255 | "X_train_cnt_vect = cnt_vect.transform(X_train)\n",
256 | "\n",
257 | "# 학습 데이터로 fit( )된 CountVectorizer를 이용하여 테스트 데이터를 feature extraction 변환 수행. \n",
258 | "X_test_cnt_vect = cnt_vect.transform(X_test)\n",
259 | "\n",
260 | "print('학습 데이터 Text의 CountVectorizer Shape:',X_train_cnt_vect.shape)"
261 | ]
262 | },
263 | {
264 | "cell_type": "code",
265 | "execution_count": 13,
266 | "metadata": {},
267 | "outputs": [
268 | {
269 | "name": "stdout",
270 | "output_type": "stream",
271 | "text": [
272 | "CountVectorized Logistic Regression 의 예측 정확도는 0.616\n"
273 | ]
274 | }
275 | ],
276 | "source": [
277 | "from sklearn.linear_model import LogisticRegression\n",
278 | "from sklearn.metrics import accuracy_score\n",
279 | "import warnings\n",
280 | "warnings.filterwarnings('ignore')\n",
281 | "\n",
282 | "# LogisticRegression을 이용하여 학습/예측/평가 수행. \n",
283 | "# LogisticRegression의 solver를 기본값인 lbfgs이 아닌 liblinear로 설정해야 학습이 오래 걸리지 않음. \n",
284 | "lr_clf = LogisticRegression(solver='liblinear')\n",
285 | "\n",
286 | "lr_clf.fit(X_train_cnt_vect , y_train)\n",
287 | "pred = lr_clf.predict(X_test_cnt_vect)\n",
288 | "\n",
289 | "print('CountVectorized Logistic Regression 의 예측 정확도는 {0:.3f}'.format(accuracy_score(y_test,pred)))"
290 | ]
291 | },
292 | {
293 | "cell_type": "markdown",
294 | "metadata": {},
295 | "source": [
296 | "**TF-IDF 피처 변환과 머신러닝 학습/예측/평가**"
297 | ]
298 | },
299 | {
300 | "cell_type": "code",
301 | "execution_count": 14,
302 | "metadata": {},
303 | "outputs": [
304 | {
305 | "name": "stdout",
306 | "output_type": "stream",
307 | "text": [
308 | "TF-IDF Logistic Regression 의 예측 정확도는 0.678\n"
309 | ]
310 | }
311 | ],
312 | "source": [
313 | "from sklearn.feature_extraction.text import TfidfVectorizer\n",
314 | "\n",
315 | "# TF-IDF Vectorization 적용하여 학습 데이터셋과 테스트 데이터 셋 변환. \n",
316 | "tfidf_vect = TfidfVectorizer()\n",
317 | "tfidf_vect.fit(X_train)\n",
318 | "X_train_tfidf_vect = tfidf_vect.transform(X_train)\n",
319 | "X_test_tfidf_vect = tfidf_vect.transform(X_test)\n",
320 | "\n",
321 | "# LogisticRegression을 이용하여 학습/예측/평가 수행. \n",
322 | "lr_clf = LogisticRegression(solver='liblinear')\n",
323 | "lr_clf.fit(X_train_tfidf_vect , y_train)\n",
324 | "pred = lr_clf.predict(X_test_tfidf_vect)\n",
325 | "print('TF-IDF Logistic Regression 의 예측 정확도는 {0:.3f}'.format(accuracy_score(y_test ,pred)))\n"
326 | ]
327 | },
328 | {
329 | "cell_type": "markdown",
330 | "metadata": {},
331 | "source": [
332 | "**stop words 필터링을 추가하고 ngram을 기본(1,1)에서 (1,2)로 변경하여 피처 벡터화**"
333 | ]
334 | },
335 | {
336 | "cell_type": "code",
337 | "execution_count": 15,
338 | "metadata": {},
339 | "outputs": [
340 | {
341 | "name": "stdout",
342 | "output_type": "stream",
343 | "text": [
344 | "TF-IDF Vectorized Logistic Regression 의 예측 정확도는 0.690\n"
345 | ]
346 | }
347 | ],
348 | "source": [
349 | "# stop words 필터링을 추가하고 ngram을 기본(1,1)에서 (1,2)로 변경하여 Feature Vectorization 적용.\n",
350 | "tfidf_vect = TfidfVectorizer(stop_words='english', ngram_range=(1,2), max_df=300)\n",
351 | "tfidf_vect.fit(X_train)\n",
352 | "X_train_tfidf_vect = tfidf_vect.transform(X_train)\n",
353 | "X_test_tfidf_vect = tfidf_vect.transform(X_test)\n",
354 | "\n",
355 | "lr_clf = LogisticRegression(solver='liblinear')\n",
356 | "lr_clf.fit(X_train_tfidf_vect , y_train)\n",
357 | "pred = lr_clf.predict(X_test_tfidf_vect)\n",
358 | "print('TF-IDF Vectorized Logistic Regression 의 예측 정확도는 {0:.3f}'.format(accuracy_score(y_test ,pred)))\n"
359 | ]
360 | },
361 | {
362 | "cell_type": "markdown",
363 | "metadata": {},
364 | "source": [
365 | "**GridSearchCV로 LogisticRegression C 하이퍼 파라미터 튜닝**"
366 | ]
367 | },
368 | {
369 | "cell_type": "code",
370 | "execution_count": 17,
371 | "metadata": {},
372 | "outputs": [
373 | {
374 | "name": "stdout",
375 | "output_type": "stream",
376 | "text": [
377 | "Fitting 3 folds for each of 5 candidates, totalling 15 fits\n",
378 | "Logistic Regression best C parameter : {'C': 10}\n",
379 | "TF-IDF Vectorized Logistic Regression 의 예측 정확도는 0.704\n"
380 | ]
381 | }
382 | ],
383 | "source": [
384 | "from sklearn.model_selection import GridSearchCV\n",
385 | "\n",
386 | "# 최적 C 값 도출 튜닝 수행. CV는 3 Fold셋으로 설정. \n",
387 | "params = { 'C':[0.01, 0.1, 1, 5, 10]}\n",
388 | "grid_cv_lr = GridSearchCV(lr_clf ,param_grid=params , cv=3 , scoring='accuracy' , verbose=1 )\n",
389 | "grid_cv_lr.fit(X_train_tfidf_vect , y_train)\n",
390 | "print('Logistic Regression best C parameter :',grid_cv_lr.best_params_ )\n",
391 | "\n",
392 | "# 최적 C 값으로 학습된 grid_cv로 예측 수행하고 정확도 평가. \n",
393 | "pred = grid_cv_lr.predict(X_test_tfidf_vect)\n",
394 | "print('TF-IDF Vectorized Logistic Regression 의 예측 정확도는 {0:.3f}'.format(accuracy_score(y_test ,pred)))\n"
395 | ]
396 | },
397 | {
398 | "cell_type": "markdown",
399 | "metadata": {},
400 | "source": [
401 | "### 사이킷런 파이프라인(Pipeline) 사용 및 GridSearchCV와의 결합"
402 | ]
403 | },
404 | {
405 | "cell_type": "code",
406 | "execution_count": 18,
407 | "metadata": {},
408 | "outputs": [
409 | {
410 | "name": "stdout",
411 | "output_type": "stream",
412 | "text": [
413 | "Pipeline을 통한 Logistic Regression 의 예측 정확도는 0.704\n"
414 | ]
415 | }
416 | ],
417 | "source": [
418 | "from sklearn.pipeline import Pipeline\n",
419 | "\n",
420 | "# TfidfVectorizer 객체를 tfidf_vect 객체명으로, LogisticRegression객체를 lr_clf 객체명으로 생성하는 Pipeline생성\n",
421 | "pipeline = Pipeline([\n",
422 | " ('tfidf_vect', TfidfVectorizer(stop_words='english', ngram_range=(1,2), max_df=300)),\n",
423 | " ('lr_clf', LogisticRegression(solver='liblinear', C=10))\n",
424 | "])\n",
425 | "\n",
426 | "# 별도의 TfidfVectorizer객체의 fit_transform( )과 LogisticRegression의 fit(), predict( )가 필요 없음. \n",
427 | "# pipeline의 fit( ) 과 predict( ) 만으로 한꺼번에 Feature Vectorization과 ML 학습/예측이 가능. \n",
428 | "pipeline.fit(X_train, y_train)\n",
429 | "pred = pipeline.predict(X_test)\n",
430 | "print('Pipeline을 통한 Logistic Regression 의 예측 정확도는 {0:.3f}'.format(accuracy_score(y_test ,pred)))\n"
431 | ]
432 | },
433 | {
434 | "cell_type": "code",
435 | "execution_count": 19,
436 | "metadata": {},
437 | "outputs": [
438 | {
439 | "name": "stdout",
440 | "output_type": "stream",
441 | "text": [
442 | "Fitting 3 folds for each of 27 candidates, totalling 81 fits\n",
443 | "{'lr_clf__C': 10, 'tfidf_vect__max_df': 700, 'tfidf_vect__ngram_range': (1, 2)} 0.7550828826229531\n",
444 | "Pipeline을 통한 Logistic Regression 의 예측 정확도는 0.702\n"
445 | ]
446 | }
447 | ],
448 | "source": [
449 | "from sklearn.pipeline import Pipeline\n",
450 | "\n",
451 | "pipeline = Pipeline([\n",
452 | " ('tfidf_vect', TfidfVectorizer(stop_words='english')),\n",
453 | " ('lr_clf', LogisticRegression(solver='liblinear'))\n",
454 | "])\n",
455 | "\n",
456 | "# Pipeline에 기술된 각각의 객체 변수에 언더바(_)2개를 연달아 붙여 GridSearchCV에 사용될 \n",
457 | "# 파라미터/하이퍼 파라미터 이름과 값을 설정. . \n",
458 | "params = { 'tfidf_vect__ngram_range': [(1,1), (1,2), (1,3)],\n",
459 | " 'tfidf_vect__max_df': [100, 300, 700],\n",
460 | " 'lr_clf__C': [1,5,10]\n",
461 | "}\n",
462 | "\n",
463 | "# GridSearchCV의 생성자에 Estimator가 아닌 Pipeline 객체 입력\n",
464 | "grid_cv_pipe = GridSearchCV(pipeline, param_grid=params, cv=3 , scoring='accuracy',verbose=1)\n",
465 | "grid_cv_pipe.fit(X_train , y_train)\n",
466 | "print(grid_cv_pipe.best_params_ , grid_cv_pipe.best_score_)\n",
467 | "\n",
468 | "pred = grid_cv_pipe.predict(X_test)\n",
469 | "print('Pipeline을 통한 Logistic Regression 의 예측 정확도는 {0:.3f}'.format(accuracy_score(y_test ,pred)))\n",
470 | "\n"
471 | ]
472 | },
473 | {
474 | "cell_type": "code",
475 | "execution_count": null,
476 | "metadata": {},
477 | "outputs": [],
478 | "source": []
479 | }
480 | ],
481 | "metadata": {
482 | "kernelspec": {
483 | "display_name": "Python 3 (ipykernel)",
484 | "language": "python",
485 | "name": "python3"
486 | },
487 | "language_info": {
488 | "codemirror_mode": {
489 | "name": "ipython",
490 | "version": 3
491 | },
492 | "file_extension": ".py",
493 | "mimetype": "text/x-python",
494 | "name": "python",
495 | "nbconvert_exporter": "python",
496 | "pygments_lexer": "ipython3",
497 | "version": "3.9.7"
498 | }
499 | },
500 | "nbformat": 4,
501 | "nbformat_minor": 2
502 | }
503 |
--------------------------------------------------------------------------------
/8장/8.5 감성 분석.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### 지도학습 기반 감성 분석 실습 – IMDB 영화평"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": 11,
13 | "metadata": {},
14 | "outputs": [
15 | {
16 | "data": {
17 | "text/html": [
18 | "\n",
19 | "\n",
32 | "
\n",
33 | " \n",
34 | " \n",
35 | " | \n",
36 | " id | \n",
37 | " sentiment | \n",
38 | " review | \n",
39 | "
\n",
40 | " \n",
41 | " \n",
42 | " \n",
43 | " 0 | \n",
44 | " \"5814_8\" | \n",
45 | " 1 | \n",
46 | " \"With all this stuff going down at the moment ... | \n",
47 | "
\n",
48 | " \n",
49 | " 1 | \n",
50 | " \"2381_9\" | \n",
51 | " 1 | \n",
52 | " \"\\\"The Classic War of the Worlds\\\" by Timothy ... | \n",
53 | "
\n",
54 | " \n",
55 | " 2 | \n",
56 | " \"7759_3\" | \n",
57 | " 0 | \n",
58 | " \"The film starts with a manager (Nicholas Bell... | \n",
59 | "
\n",
60 | " \n",
61 | "
\n",
62 | "
"
63 | ],
64 | "text/plain": [
65 | " id sentiment review\n",
66 | "0 \"5814_8\" 1 \"With all this stuff going down at the moment ...\n",
67 | "1 \"2381_9\" 1 \"\\\"The Classic War of the Worlds\\\" by Timothy ...\n",
68 | "2 \"7759_3\" 0 \"The film starts with a manager (Nicholas Bell..."
69 | ]
70 | },
71 | "execution_count": 11,
72 | "metadata": {},
73 | "output_type": "execute_result"
74 | }
75 | ],
76 | "source": [
77 | "import pandas as pd\n",
78 | "\n",
79 | "review_df = pd.read_csv('./labeledTrainData.tsv', header=0, sep=\"\\t\", quoting=3)\n",
80 | "review_df.head(3)"
81 | ]
82 | },
83 | {
84 | "cell_type": "code",
85 | "execution_count": null,
86 | "metadata": {},
87 | "outputs": [],
88 | "source": [
89 | "print(review_df['review'][0])"
90 | ]
91 | },
92 | {
93 | "cell_type": "markdown",
94 | "metadata": {},
95 | "source": [
96 | "**데이터 사전 처리 html태그 제거 및 숫자문자 제거**"
97 | ]
98 | },
99 | {
100 | "cell_type": "code",
101 | "execution_count": 12,
102 | "metadata": {},
103 | "outputs": [],
104 | "source": [
105 | "import re\n",
106 | "\n",
107 | "#
html 태그는 replace 함수로 공백으로 변환\n",
108 | "review_df['review'] = review_df['review'].str.replace('
',' ')\n",
109 | "\n",
110 | "# 파이썬의 정규 표현식 모듈인 re를 이용하여 영어 문자열이 아닌 문자는 모두 공백으로 변환 \n",
111 | "review_df['review'] = review_df['review'].apply( lambda x : re.sub(\"[^a-zA-Z]\", \" \", x) )\n"
112 | ]
113 | },
114 | {
115 | "cell_type": "markdown",
116 | "metadata": {},
117 | "source": [
118 | "**학습/테스트 데이터 분리**"
119 | ]
120 | },
121 | {
122 | "cell_type": "code",
123 | "execution_count": null,
124 | "metadata": {},
125 | "outputs": [],
126 | "source": [
127 | "from sklearn.model_selection import train_test_split\n",
128 | "\n",
129 | "class_df = review_df['sentiment']\n",
130 | "feature_df = review_df.drop(['id','sentiment'], axis=1, inplace=False)\n",
131 | "\n",
132 | "X_train, X_test, y_train, y_test= train_test_split(feature_df, class_df, test_size=0.3, random_state=156)\n",
133 | "\n",
134 | "X_train.shape, X_test.shape"
135 | ]
136 | },
137 | {
138 | "cell_type": "markdown",
139 | "metadata": {},
140 | "source": [
141 | "**Pipeline을 통해 Count기반 피처 벡터화 및 머신러닝 학습/예측/평가**"
142 | ]
143 | },
144 | {
145 | "cell_type": "code",
146 | "execution_count": null,
147 | "metadata": {},
148 | "outputs": [],
149 | "source": [
150 | "from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer\n",
151 | "from sklearn.pipeline import Pipeline\n",
152 | "from sklearn.linear_model import LogisticRegression\n",
153 | "from sklearn.metrics import accuracy_score, roc_auc_score\n",
154 | "\n",
155 | "# 스톱 워드는 English, filtering, ngram은 (1,2)로 설정해 CountVectorization수행. \n",
156 | "# LogisticRegression의 C는 10으로 설정. \n",
157 | "pipeline = Pipeline([\n",
158 | " ('cnt_vect', CountVectorizer(stop_words='english', ngram_range=(1,2) )),\n",
159 | " ('lr_clf', LogisticRegression(C=10))])\n",
160 | "\n",
161 | "# Pipeline 객체를 이용하여 fit(), predict()로 학습/예측 수행. predict_proba()는 roc_auc때문에 수행. \n",
162 | "pipeline.fit(X_train['review'], y_train)\n",
163 | "pred = pipeline.predict(X_test['review'])\n",
164 | "pred_probs = pipeline.predict_proba(X_test['review'])[:,1]\n",
165 | "\n",
166 | "print('예측 정확도는 {0:.4f}, ROC-AUC는 {1:.4f}'.format(accuracy_score(y_test ,pred),\n",
167 | " roc_auc_score(y_test, pred_probs)))"
168 | ]
169 | },
170 | {
171 | "cell_type": "markdown",
172 | "metadata": {},
173 | "source": [
174 | "**Pipeline을 통해 TF-IDF기반 피처 벡터화 및 머신러닝 학습/예측/평가**"
175 | ]
176 | },
177 | {
178 | "cell_type": "code",
179 | "execution_count": null,
180 | "metadata": {},
181 | "outputs": [],
182 | "source": [
183 | "# 스톱 워드는 english, filtering, ngram은 (1,2)로 설정해 TF-IDF 벡터화 수행. \n",
184 | "# LogisticRegression의 C는 10으로 설정. \n",
185 | "pipeline = Pipeline([\n",
186 | " ('tfidf_vect', TfidfVectorizer(stop_words='english', ngram_range=(1,2) )),\n",
187 | " ('lr_clf', LogisticRegression(C=10))])\n",
188 | "\n",
189 | "pipeline.fit(X_train['review'], y_train)\n",
190 | "pred = pipeline.predict(X_test['review'])\n",
191 | "pred_probs = pipeline.predict_proba(X_test['review'])[:,1]\n",
192 | "\n",
193 | "print('예측 정확도는 {0:.4f}, ROC-AUC는 {1:.4f}'.format(accuracy_score(y_test ,pred),\n",
194 | " roc_auc_score(y_test, pred_probs)))"
195 | ]
196 | },
197 | {
198 | "cell_type": "markdown",
199 | "metadata": {},
200 | "source": [
201 | "### 비지도학습 기반 감성 분석 소개\n",
202 | "### SentiWordNet을 이용한 Sentiment Analysis \n",
203 | "* WordNet Synset과 SentiWordNet SentiSynset 클래스의 이해"
204 | ]
205 | },
206 | {
207 | "cell_type": "code",
208 | "execution_count": null,
209 | "metadata": {},
210 | "outputs": [],
211 | "source": [
212 | "import nltk\n",
213 | "nltk.download('all')"
214 | ]
215 | },
216 | {
217 | "cell_type": "code",
218 | "execution_count": null,
219 | "metadata": {},
220 | "outputs": [],
221 | "source": [
222 | "from nltk.corpus import wordnet as wn\n",
223 | "\n",
224 | "term = 'present'\n",
225 | "\n",
226 | "# 'present'라는 단어로 wordnet의 synsets 생성. \n",
227 | "synsets = wn.synsets(term)\n",
228 | "print('synsets() 반환 type :', type(synsets))\n",
229 | "print('synsets() 반환 값 갯수:', len(synsets))\n",
230 | "print('synsets() 반환 값 :', synsets)"
231 | ]
232 | },
233 | {
234 | "cell_type": "code",
235 | "execution_count": null,
236 | "metadata": {},
237 | "outputs": [],
238 | "source": [
239 | "for synset in synsets :\n",
240 | " print('##### Synset name : ', synset.name(),'#####')\n",
241 | " print('POS :',synset.lexname())\n",
242 | " print('Definition:',synset.definition())\n",
243 | " print('Lemmas:',synset.lemma_names())"
244 | ]
245 | },
246 | {
247 | "cell_type": "code",
248 | "execution_count": null,
249 | "metadata": {},
250 | "outputs": [],
251 | "source": [
252 | "# synset 객체를 단어별로 생성합니다. \n",
253 | "tree = wn.synset('tree.n.01')\n",
254 | "lion = wn.synset('lion.n.01')\n",
255 | "tiger = wn.synset('tiger.n.02')\n",
256 | "cat = wn.synset('cat.n.01')\n",
257 | "dog = wn.synset('dog.n.01')\n",
258 | "\n",
259 | "entities = [tree , lion , tiger , cat , dog]\n",
260 | "similarities = []\n",
261 | "entity_names = [ entity.name().split('.')[0] for entity in entities]\n",
262 | "\n",
263 | "# 단어별 synset 들을 iteration 하면서 다른 단어들의 synset과 유사도를 측정합니다. \n",
264 | "for entity in entities:\n",
265 | " similarity = [ round(entity.path_similarity(compared_entity), 2) for compared_entity in entities ]\n",
266 | " similarities.append(similarity)\n",
267 | " \n",
268 | "# 개별 단어별 synset과 다른 단어의 synset과의 유사도를 DataFrame형태로 저장합니다. \n",
269 | "similarity_df = pd.DataFrame(similarities , columns=entity_names,index=entity_names)\n",
270 | "similarity_df"
271 | ]
272 | },
273 | {
274 | "cell_type": "code",
275 | "execution_count": null,
276 | "metadata": {},
277 | "outputs": [],
278 | "source": [
279 | "import nltk\n",
280 | "from nltk.corpus import sentiwordnet as swn\n",
281 | "\n",
282 | "senti_synsets = list(swn.senti_synsets('slow'))\n",
283 | "print('senti_synsets() 반환 type :', type(senti_synsets))\n",
284 | "print('senti_synsets() 반환 값 갯수:', len(senti_synsets))\n",
285 | "print('senti_synsets() 반환 값 :', senti_synsets)\n"
286 | ]
287 | },
288 | {
289 | "cell_type": "code",
290 | "execution_count": null,
291 | "metadata": {},
292 | "outputs": [],
293 | "source": [
294 | "import nltk\n",
295 | "from nltk.corpus import sentiwordnet as swn\n",
296 | "\n",
297 | "father = swn.senti_synset('father.n.01')\n",
298 | "print('father 긍정감성 지수: ', father.pos_score())\n",
299 | "print('father 부정감성 지수: ', father.neg_score())\n",
300 | "print('father 객관성 지수: ', father.obj_score())\n",
301 | "print('\\n')\n",
302 | "fabulous = swn.senti_synset('fabulous.a.01')\n",
303 | "print('fabulous 긍정감성 지수: ',fabulous .pos_score())\n",
304 | "print('fabulous 부정감성 지수: ',fabulous .neg_score())"
305 | ]
306 | },
307 | {
308 | "cell_type": "code",
309 | "execution_count": null,
310 | "metadata": {},
311 | "outputs": [],
312 | "source": [
313 | "from nltk.corpus import wordnet as wn\n",
314 | "\n",
315 | "# 간단한 NTLK PennTreebank Tag를 기반으로 WordNet기반의 품사 Tag로 변환\n",
316 | "def penn_to_wn(tag):\n",
317 | " if tag.startswith('J'):\n",
318 | " return wn.ADJ\n",
319 | " elif tag.startswith('N'):\n",
320 | " return wn.NOUN\n",
321 | " elif tag.startswith('R'):\n",
322 | " return wn.ADV\n",
323 | " elif tag.startswith('V'):\n",
324 | " return wn.VERB\n",
325 | " return \n"
326 | ]
327 | },
328 | {
329 | "cell_type": "code",
330 | "execution_count": null,
331 | "metadata": {},
332 | "outputs": [],
333 | "source": [
334 | "from nltk.stem import WordNetLemmatizer\n",
335 | "from nltk.corpus import sentiwordnet as swn\n",
336 | "from nltk import sent_tokenize, word_tokenize, pos_tag\n",
337 | "\n",
338 | "def swn_polarity(text):\n",
339 | " # 감성 지수 초기화 \n",
340 | " sentiment = 0.0\n",
341 | " tokens_count = 0\n",
342 | " \n",
343 | " lemmatizer = WordNetLemmatizer()\n",
344 | " raw_sentences = sent_tokenize(text)\n",
345 | " # 분해된 문장별로 단어 토큰 -> 품사 태깅 후에 SentiSynset 생성 -> 감성 지수 합산 \n",
346 | " for raw_sentence in raw_sentences:\n",
347 | " # NTLK 기반의 품사 태깅 문장 추출 \n",
348 | " tagged_sentence = pos_tag(word_tokenize(raw_sentence))\n",
349 | " for word , tag in tagged_sentence:\n",
350 | " \n",
351 | " # WordNet 기반 품사 태깅과 어근 추출\n",
352 | " wn_tag = penn_to_wn(tag)\n",
353 | " if wn_tag not in (wn.NOUN , wn.ADJ, wn.ADV):\n",
354 | " continue \n",
355 | " lemma = lemmatizer.lemmatize(word, pos=wn_tag)\n",
356 | " if not lemma:\n",
357 | " continue\n",
358 | " # 어근을 추출한 단어와 WordNet 기반 품사 태깅을 입력해 Synset 객체를 생성. \n",
359 | " synsets = wn.synsets(lemma , pos=wn_tag)\n",
360 | " if not synsets:\n",
361 | " continue\n",
362 | " # sentiwordnet의 감성 단어 분석으로 감성 synset 추출\n",
363 | " # 모든 단어에 대해 긍정 감성 지수는 +로 부정 감성 지수는 -로 합산해 감성 지수 계산. \n",
364 | " synset = synsets[0]\n",
365 | " swn_synset = swn.senti_synset(synset.name())\n",
366 | " sentiment += (swn_synset.pos_score() - swn_synset.neg_score()) \n",
367 | " tokens_count += 1\n",
368 | " \n",
369 | " if not tokens_count:\n",
370 | " return 0\n",
371 | " \n",
372 | " # 총 score가 0 이상일 경우 긍정(Positive) 1, 그렇지 않을 경우 부정(Negative) 0 반환\n",
373 | " if sentiment >= 0 :\n",
374 | " return 1\n",
375 | " \n",
376 | " return 0\n"
377 | ]
378 | },
379 | {
380 | "cell_type": "code",
381 | "execution_count": null,
382 | "metadata": {},
383 | "outputs": [],
384 | "source": [
385 | "review_df['preds'] = review_df['review'].apply( lambda x : swn_polarity(x) )\n",
386 | "y_target = review_df['sentiment'].values\n",
387 | "preds = review_df['preds'].values"
388 | ]
389 | },
390 | {
391 | "cell_type": "code",
392 | "execution_count": null,
393 | "metadata": {},
394 | "outputs": [],
395 | "source": [
396 | "from sklearn.metrics import accuracy_score, confusion_matrix, precision_score \n",
397 | "from sklearn.metrics import recall_score, f1_score, roc_auc_score\n",
398 | "\n",
399 | "print(confusion_matrix( y_target, preds))\n",
400 | "print(\"정확도:\", accuracy_score(y_target , preds))\n",
401 | "print(\"정밀도:\", precision_score(y_target , preds))\n",
402 | "print(\"재현율:\", recall_score(y_target, preds))"
403 | ]
404 | },
405 | {
406 | "cell_type": "code",
407 | "execution_count": null,
408 | "metadata": {},
409 | "outputs": [],
410 | "source": []
411 | },
412 | {
413 | "cell_type": "markdown",
414 | "metadata": {},
415 | "source": [
416 | "### VADER lexicon을 이용한 Sentiment Analysis"
417 | ]
418 | },
419 | {
420 | "cell_type": "code",
421 | "execution_count": 13,
422 | "metadata": {},
423 | "outputs": [
424 | {
425 | "name": "stdout",
426 | "output_type": "stream",
427 | "text": [
428 | "{'neg': 0.13, 'neu': 0.743, 'pos': 0.127, 'compound': -0.7943}\n"
429 | ]
430 | }
431 | ],
432 | "source": [
433 | "from nltk.sentiment.vader import SentimentIntensityAnalyzer\n",
434 | "\n",
435 | "senti_analyzer = SentimentIntensityAnalyzer()\n",
436 | "senti_scores = senti_analyzer.polarity_scores(review_df['review'][0])\n",
437 | "print(senti_scores)"
438 | ]
439 | },
440 | {
441 | "cell_type": "code",
442 | "execution_count": 14,
443 | "metadata": {},
444 | "outputs": [],
445 | "source": [
446 | "def vader_polarity(review,threshold=0.1):\n",
447 | " analyzer = SentimentIntensityAnalyzer()\n",
448 | " scores = analyzer.polarity_scores(review)\n",
449 | " \n",
450 | " # compound 값에 기반하여 threshold 입력값보다 크면 1, 그렇지 않으면 0을 반환 \n",
451 | " agg_score = scores['compound']\n",
452 | " final_sentiment = 1 if agg_score >= threshold else 0\n",
453 | " return final_sentiment\n",
454 | "\n",
455 | "# apply lambda 식을 이용하여 레코드별로 vader_polarity( )를 수행하고 결과를 'vader_preds'에 저장\n",
456 | "review_df['vader_preds'] = review_df['review'].apply( lambda x : vader_polarity(x, 0.1) )\n",
457 | "y_target = review_df['sentiment'].values\n",
458 | "vader_preds = review_df['vader_preds'].values\n",
459 | "\n"
460 | ]
461 | },
462 | {
463 | "cell_type": "code",
464 | "execution_count": 15,
465 | "metadata": {},
466 | "outputs": [
467 | {
468 | "name": "stdout",
469 | "output_type": "stream",
470 | "text": [
471 | "#### VADER 예측 성능 평가 ####\n",
472 | "[[ 6736 5764]\n",
473 | " [ 1867 10633]]\n",
474 | "정확도: 0.69476\n",
475 | "정밀도: 0.6484722815149113\n",
476 | "재현율: 0.85064\n"
477 | ]
478 | }
479 | ],
480 | "source": [
481 | "print('#### VADER 예측 성능 평가 ####')\n",
482 | "from sklearn.metrics import accuracy_score, confusion_matrix, precision_score \n",
483 | "from sklearn.metrics import recall_score, f1_score, roc_auc_score\n",
484 | "\n",
485 | "print(confusion_matrix( y_target, vader_preds))\n",
486 | "print(\"정확도:\", accuracy_score(y_target , vader_preds))\n",
487 | "print(\"정밀도:\", precision_score(y_target , vader_preds))\n",
488 | "print(\"재현율:\", recall_score(y_target, vader_preds))\n"
489 | ]
490 | },
491 | {
492 | "cell_type": "code",
493 | "execution_count": null,
494 | "metadata": {},
495 | "outputs": [],
496 | "source": []
497 | }
498 | ],
499 | "metadata": {
500 | "kernelspec": {
501 | "display_name": "Python 3",
502 | "language": "python",
503 | "name": "python3"
504 | },
505 | "language_info": {
506 | "codemirror_mode": {
507 | "name": "ipython",
508 | "version": 3
509 | },
510 | "file_extension": ".py",
511 | "mimetype": "text/x-python",
512 | "name": "python",
513 | "nbconvert_exporter": "python",
514 | "pygments_lexer": "ipython3",
515 | "version": "3.6.4"
516 | }
517 | },
518 | "nbformat": 4,
519 | "nbformat_minor": 2
520 | }
521 |
--------------------------------------------------------------------------------
/8장/8.9 한글 텍스트 처리 _ 네이버 영화 평점 감성 분석.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "from konlpy.tag import Twitter\n",
10 | "from konlpy.tag import Okt\n",
11 | "from konlpy.tag import Kkma"
12 | ]
13 | },
14 | {
15 | "cell_type": "code",
16 | "execution_count": 5,
17 | "metadata": {},
18 | "outputs": [
19 | {
20 | "data": {
21 | "text/html": [
22 | "\n",
23 | "\n",
36 | "
\n",
37 | " \n",
38 | " \n",
39 | " | \n",
40 | " id | \n",
41 | " document | \n",
42 | " label | \n",
43 | "
\n",
44 | " \n",
45 | " \n",
46 | " \n",
47 | " 0 | \n",
48 | " 9976970 | \n",
49 | " 아 더빙.. 진짜 짜증나네요 목소리 | \n",
50 | " 0 | \n",
51 | "
\n",
52 | " \n",
53 | " 1 | \n",
54 | " 3819312 | \n",
55 | " 흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나 | \n",
56 | " 1 | \n",
57 | "
\n",
58 | " \n",
59 | " 2 | \n",
60 | " 10265843 | \n",
61 | " 너무재밓었다그래서보는것을추천한다 | \n",
62 | " 0 | \n",
63 | "
\n",
64 | " \n",
65 | " 3 | \n",
66 | " 9045019 | \n",
67 | " 교도소 이야기구먼 ..솔직히 재미는 없다..평점 조정 | \n",
68 | " 0 | \n",
69 | "
\n",
70 | " \n",
71 | " 4 | \n",
72 | " 6483659 | \n",
73 | " 사이몬페그의 익살스런 연기가 돋보였던 영화!스파이더맨에서 늙어보이기만 했던 커스틴 ... | \n",
74 | " 1 | \n",
75 | "
\n",
76 | " \n",
77 | " 5 | \n",
78 | " 5403919 | \n",
79 | " 막 걸음마 뗀 3세부터 초등학교 1학년생인 8살용영화.ㅋㅋㅋ...별반개도 아까움. | \n",
80 | " 0 | \n",
81 | "
\n",
82 | " \n",
83 | " 6 | \n",
84 | " 7797314 | \n",
85 | " 원작의 긴장감을 제대로 살려내지못했다. | \n",
86 | " 0 | \n",
87 | "
\n",
88 | " \n",
89 | " 7 | \n",
90 | " 9443947 | \n",
91 | " 별 반개도 아깝다 욕나온다 이응경 길용우 연기생활이몇년인지..정말 발로해도 그것보단... | \n",
92 | " 0 | \n",
93 | "
\n",
94 | " \n",
95 | " 8 | \n",
96 | " 7156791 | \n",
97 | " 액션이 없는데도 재미 있는 몇안되는 영화 | \n",
98 | " 1 | \n",
99 | "
\n",
100 | " \n",
101 | " 9 | \n",
102 | " 5912145 | \n",
103 | " 왜케 평점이 낮은건데? 꽤 볼만한데.. 헐리우드식 화려함에만 너무 길들여져 있나? | \n",
104 | " 1 | \n",
105 | "
\n",
106 | " \n",
107 | "
\n",
108 | "
"
109 | ],
110 | "text/plain": [
111 | " id document label\n",
112 | "0 9976970 아 더빙.. 진짜 짜증나네요 목소리 0\n",
113 | "1 3819312 흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나 1\n",
114 | "2 10265843 너무재밓었다그래서보는것을추천한다 0\n",
115 | "3 9045019 교도소 이야기구먼 ..솔직히 재미는 없다..평점 조정 0\n",
116 | "4 6483659 사이몬페그의 익살스런 연기가 돋보였던 영화!스파이더맨에서 늙어보이기만 했던 커스틴 ... 1\n",
117 | "5 5403919 막 걸음마 뗀 3세부터 초등학교 1학년생인 8살용영화.ㅋㅋㅋ...별반개도 아까움. 0\n",
118 | "6 7797314 원작의 긴장감을 제대로 살려내지못했다. 0\n",
119 | "7 9443947 별 반개도 아깝다 욕나온다 이응경 길용우 연기생활이몇년인지..정말 발로해도 그것보단... 0\n",
120 | "8 7156791 액션이 없는데도 재미 있는 몇안되는 영화 1\n",
121 | "9 5912145 왜케 평점이 낮은건데? 꽤 볼만한데.. 헐리우드식 화려함에만 너무 길들여져 있나? 1"
122 | ]
123 | },
124 | "execution_count": 5,
125 | "metadata": {},
126 | "output_type": "execute_result"
127 | }
128 | ],
129 | "source": [
130 | "import pandas as pd\n",
131 | "import warnings\n",
132 | "warnings.filterwarnings('ignore')\n",
133 | "\n",
134 | "# 컬럼 분리 문자 \\t \n",
135 | "train_df = pd.read_csv('ratings_train.txt', sep='\\t') # 한글 encoding시 encoding='cp949' 적용.\n",
136 | "train_df.head(10)"
137 | ]
138 | },
139 | {
140 | "cell_type": "code",
141 | "execution_count": 6,
142 | "metadata": {},
143 | "outputs": [
144 | {
145 | "data": {
146 | "text/plain": [
147 | "0 75173\n",
148 | "1 74827\n",
149 | "Name: label, dtype: int64"
150 | ]
151 | },
152 | "execution_count": 6,
153 | "metadata": {},
154 | "output_type": "execute_result"
155 | }
156 | ],
157 | "source": [
158 | "train_df['label'].value_counts( )"
159 | ]
160 | },
161 | {
162 | "cell_type": "code",
163 | "execution_count": 7,
164 | "metadata": {},
165 | "outputs": [
166 | {
167 | "name": "stdout",
168 | "output_type": "stream",
169 | "text": [
170 | "\n",
171 | "RangeIndex: 150000 entries, 0 to 149999\n",
172 | "Data columns (total 3 columns):\n",
173 | " # Column Non-Null Count Dtype \n",
174 | "--- ------ -------------- ----- \n",
175 | " 0 id 150000 non-null int64 \n",
176 | " 1 document 149995 non-null object\n",
177 | " 2 label 150000 non-null int64 \n",
178 | "dtypes: int64(2), object(1)\n",
179 | "memory usage: 3.4+ MB\n"
180 | ]
181 | }
182 | ],
183 | "source": [
184 | "train_df.info()"
185 | ]
186 | },
187 | {
188 | "cell_type": "code",
189 | "execution_count": 8,
190 | "metadata": {},
191 | "outputs": [],
192 | "source": [
193 | "import re\n",
194 | "\n",
195 | "train_df = train_df.fillna(' ')\n",
196 | "# 정규 표현식을 이용하여 숫자를 공백으로 변경(정규 표현식으로 \\d 는 숫자를 의미함.) \n",
197 | "train_df['document'] = train_df['document'].apply( lambda x : re.sub(r\"\\d+\", \" \", x) )\n",
198 | "\n",
199 | "# 테스트 데이터 셋을 로딩하고 동일하게 Null 및 숫자를 공백으로 변환. \n",
200 | "test_df = pd.read_csv('ratings_test.txt', sep='\\t') # 한글 encoding시 encoding='cp949' 적용.\n",
201 | "test_df = test_df.fillna(' ')\n",
202 | "test_df['document'] = test_df['document'].apply( lambda x : re.sub(r\"\\d+\", \" \", x) )\n",
203 | "\n",
204 | "# id 컬럼 삭제 수행. \n",
205 | "train_df.drop('id', axis=1, inplace=True) \n",
206 | "test_df.drop('id', axis=1, inplace=True)\n"
207 | ]
208 | },
209 | {
210 | "cell_type": "code",
211 | "execution_count": 13,
212 | "metadata": {},
213 | "outputs": [
214 | {
215 | "data": {
216 | "text/plain": [
217 | "['아버지', '가방', '에', '들어가신다']"
218 | ]
219 | },
220 | "execution_count": 13,
221 | "metadata": {},
222 | "output_type": "execute_result"
223 | }
224 | ],
225 | "source": [
226 | "from konlpy.tag import Okt\n",
227 | "\n",
228 | "okt = Okt()\n",
229 | "def tw_tokenizer(text):\n",
230 | " # 입력 인자로 들어온 text 를 형태소 단어로 토큰화 하여 list 객체 반환\n",
231 | " tokens_ko = okt.morphs(text)\n",
232 | " return tokens_ko\n",
233 | "\n",
234 | "#tw_tokenizer('아버지가방에 들어가신다')\n",
235 | "okt.morphs('아버지가방에 들어가신다')"
236 | ]
237 | },
238 | {
239 | "cell_type": "code",
240 | "execution_count": 14,
241 | "metadata": {},
242 | "outputs": [],
243 | "source": [
244 | "from sklearn.feature_extraction.text import TfidfVectorizer\n",
245 | "from sklearn.linear_model import LogisticRegression\n",
246 | "from sklearn.model_selection import GridSearchCV\n",
247 | "\n",
248 | "# Okt 객체의 morphs( ) 객체를 이용한 tokenizer를 사용. ngram_range는 (1,2) \n",
249 | "tfidf_vect = TfidfVectorizer(tokenizer=tw_tokenizer, ngram_range=(1,2), min_df=3, max_df=0.9)\n",
250 | "tfidf_vect.fit(train_df['document'])\n",
251 | "tfidf_matrix_train = tfidf_vect.transform(train_df['document'])"
252 | ]
253 | },
254 | {
255 | "cell_type": "code",
256 | "execution_count": 15,
257 | "metadata": {},
258 | "outputs": [
259 | {
260 | "name": "stdout",
261 | "output_type": "stream",
262 | "text": [
263 | "(150000, 129276)\n"
264 | ]
265 | }
266 | ],
267 | "source": [
268 | "print(tfidf_matrix_train.shape)"
269 | ]
270 | },
271 | {
272 | "cell_type": "code",
273 | "execution_count": 16,
274 | "metadata": {},
275 | "outputs": [
276 | {
277 | "name": "stdout",
278 | "output_type": "stream",
279 | "text": [
280 | "Fitting 3 folds for each of 5 candidates, totalling 15 fits\n",
281 | "{'C': 3.5} 0.8593\n"
282 | ]
283 | }
284 | ],
285 | "source": [
286 | "# Logistic Regression 을 이용하여 감성 분석 Classification 수행. \n",
287 | "lg_clf = LogisticRegression(random_state=0, solver='liblinear')\n",
288 | "\n",
289 | "# Parameter C 최적화를 위해 GridSearchCV 를 이용. \n",
290 | "params = { 'C': [1 ,3.5, 4.5, 5.5, 10 ] }\n",
291 | "grid_cv = GridSearchCV(lg_clf , param_grid=params , cv=3 ,scoring='accuracy', verbose=1 )\n",
292 | "grid_cv.fit(tfidf_matrix_train , train_df['label'] )\n",
293 | "print(grid_cv.best_params_ , round(grid_cv.best_score_,4))\n"
294 | ]
295 | },
296 | {
297 | "cell_type": "code",
298 | "execution_count": 17,
299 | "metadata": {},
300 | "outputs": [
301 | {
302 | "data": {
303 | "text/html": [
304 | "\n",
305 | "\n",
318 | "
\n",
319 | " \n",
320 | " \n",
321 | " | \n",
322 | " document | \n",
323 | " label | \n",
324 | "
\n",
325 | " \n",
326 | " \n",
327 | " \n",
328 | " 0 | \n",
329 | " 굳 ㅋ | \n",
330 | " 1 | \n",
331 | "
\n",
332 | " \n",
333 | " 1 | \n",
334 | " GDNTOPCLASSINTHECLUB | \n",
335 | " 0 | \n",
336 | "
\n",
337 | " \n",
338 | " 2 | \n",
339 | " 뭐야 이 평점들은.... 나쁘진 않지만 점 짜리는 더더욱 아니잖아 | \n",
340 | " 0 | \n",
341 | "
\n",
342 | " \n",
343 | " 3 | \n",
344 | " 지루하지는 않은데 완전 막장임... 돈주고 보기에는.... | \n",
345 | " 0 | \n",
346 | "
\n",
347 | " \n",
348 | " 4 | \n",
349 | " D만 아니었어도 별 다섯 개 줬을텐데.. 왜 D로 나와서 제 심기를 불편하게 하죠?? | \n",
350 | " 0 | \n",
351 | "
\n",
352 | " \n",
353 | "
\n",
354 | "
"
355 | ],
356 | "text/plain": [
357 | " document label\n",
358 | "0 굳 ㅋ 1\n",
359 | "1 GDNTOPCLASSINTHECLUB 0\n",
360 | "2 뭐야 이 평점들은.... 나쁘진 않지만 점 짜리는 더더욱 아니잖아 0\n",
361 | "3 지루하지는 않은데 완전 막장임... 돈주고 보기에는.... 0\n",
362 | "4 D만 아니었어도 별 다섯 개 줬을텐데.. 왜 D로 나와서 제 심기를 불편하게 하죠?? 0"
363 | ]
364 | },
365 | "execution_count": 17,
366 | "metadata": {},
367 | "output_type": "execute_result"
368 | }
369 | ],
370 | "source": [
371 | "test_df.head()"
372 | ]
373 | },
374 | {
375 | "cell_type": "code",
376 | "execution_count": 18,
377 | "metadata": {},
378 | "outputs": [
379 | {
380 | "name": "stdout",
381 | "output_type": "stream",
382 | "text": [
383 | "Logistic Regression 정확도: 0.86172\n"
384 | ]
385 | }
386 | ],
387 | "source": [
388 | "from sklearn.metrics import accuracy_score\n",
389 | "\n",
390 | "# 학습 데이터를 적용한 TfidfVectorizer를 이용하여 테스트 데이터를 TF-IDF 값으로 Feature 변환함. \n",
391 | "tfidf_matrix_test = tfidf_vect.transform(test_df['document'])\n",
392 | "\n",
393 | "# classifier 는 GridSearchCV에서 최적 파라미터로 학습된 classifier를 그대로 이용\n",
394 | "best_estimator = grid_cv.best_estimator_\n",
395 | "preds = best_estimator.predict(tfidf_matrix_test)\n",
396 | "\n",
397 | "print('Logistic Regression 정확도: ',accuracy_score(test_df['label'],preds))"
398 | ]
399 | },
400 | {
401 | "cell_type": "code",
402 | "execution_count": null,
403 | "metadata": {},
404 | "outputs": [],
405 | "source": []
406 | }
407 | ],
408 | "metadata": {
409 | "kernelspec": {
410 | "display_name": "Python 3 (ipykernel)",
411 | "language": "python",
412 | "name": "python3"
413 | },
414 | "language_info": {
415 | "codemirror_mode": {
416 | "name": "ipython",
417 | "version": 3
418 | },
419 | "file_extension": ".py",
420 | "mimetype": "text/x-python",
421 | "name": "python",
422 | "nbconvert_exporter": "python",
423 | "pygments_lexer": "ipython3",
424 | "version": "3.9.7"
425 | }
426 | },
427 | "nbformat": 4,
428 | "nbformat_minor": 2
429 | }
430 |
--------------------------------------------------------------------------------
/9장/9.3 잠재 요인 기반 협업 필터링 실습.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### 경사하강을 이용한 행렬 분해"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "**원본 행렬 R 및 R을 분해할 P와 Q를 임의의 정규분포를 가진 랜덤값으로 초기화**"
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": 1,
20 | "metadata": {},
21 | "outputs": [
22 | {
23 | "name": "stdout",
24 | "output_type": "stream",
25 | "text": [
26 | "P: [[ 0.54144845 -0.2039188 -0.17605725]\n",
27 | " [-0.35765621 0.28846921 -0.76717957]\n",
28 | " [ 0.58160392 -0.25373563 0.10634637]\n",
29 | " [-0.08312346 0.48736931 -0.68671357]]\n",
30 | "Q: [[-0.1074724 -0.12801812 0.37792315]\n",
31 | " [-0.36663042 -0.05747607 -0.29261947]\n",
32 | " [ 0.01407125 0.19427174 -0.36687306]\n",
33 | " [ 0.38157457 0.30053024 0.16749811]\n",
34 | " [ 0.30028532 -0.22790929 -0.04096341]]\n"
35 | ]
36 | }
37 | ],
38 | "source": [
39 | "import numpy as np\n",
40 | "\n",
41 | "# 원본 행렬 R 생성, 분해 행렬 P와 Q 초기화, 잠재요인 차원 K는 3 설정. \n",
42 | "R = np.array([[4, np.NaN, np.NaN, 2, np.NaN ],\n",
43 | " [np.NaN, 5, np.NaN, 3, 1 ],\n",
44 | " [np.NaN, np.NaN, 3, 4, 4 ],\n",
45 | " [5, 2, 1, 2, np.NaN ]])\n",
46 | "\n",
47 | "num_users, num_items = R.shape\n",
48 | "K=3\n",
49 | "\n",
50 | "# P와 Q 매트릭스의 크기를 지정하고 정규분포를 가진 random한 값으로 입력합니다. \n",
51 | "np.random.seed(1)\n",
52 | "P = np.random.normal(scale=1./K, size=(num_users, K))\n",
53 | "Q = np.random.normal(scale=1./K, size=(num_items, K))\n",
54 | "print(\"P:\",P)\n",
55 | "print(\"Q:\",Q)"
56 | ]
57 | },
58 | {
59 | "cell_type": "markdown",
60 | "metadata": {},
61 | "source": [
62 | "**비용계산 함수를 생성. 분해된 행렬 P와 Q.T를 내적하여 예측 행렬 생성하고**\n",
63 | "\n",
64 | "**실제 행렬에서 널이 아닌 값의 위치에 있는 값만 예측 행렬의 값과 비교하여 RMSE값을 계산하고 반환**"
65 | ]
66 | },
67 | {
68 | "cell_type": "code",
69 | "execution_count": 2,
70 | "metadata": {},
71 | "outputs": [],
72 | "source": [
73 | "from sklearn.metrics import mean_squared_error\n",
74 | "\n",
75 | "def get_rmse(R, P, Q, non_zeros):\n",
76 | " error = 0\n",
77 | " # 두개의 분해된 행렬 P와 Q.T의 내적으로 예측 R 행렬 생성\n",
78 | " full_pred_matrix = np.dot(P, Q.T)\n",
79 | " \n",
80 | " # 실제 R 행렬에서 널이 아닌 값의 위치 인덱스 추출하여 실제 R 행렬과 예측 행렬의 RMSE 추출\n",
81 | " x_non_zero_ind = [non_zero[0] for non_zero in non_zeros]\n",
82 | " y_non_zero_ind = [non_zero[1] for non_zero in non_zeros]\n",
83 | " R_non_zeros = R[x_non_zero_ind, y_non_zero_ind]\n",
84 | " full_pred_matrix_non_zeros = full_pred_matrix[x_non_zero_ind, y_non_zero_ind]\n",
85 | " \n",
86 | " mse = mean_squared_error(R_non_zeros, full_pred_matrix_non_zeros)\n",
87 | " rmse = np.sqrt(mse)\n",
88 | " \n",
89 | " return rmse\n"
90 | ]
91 | },
92 | {
93 | "cell_type": "markdown",
94 | "metadata": {},
95 | "source": [
96 | "**경사하강법에 기반하여 P와 Q의 원소들을 업데이트 수행**\n",
97 | ""
98 | ]
99 | },
100 | {
101 | "cell_type": "code",
102 | "execution_count": 3,
103 | "metadata": {},
104 | "outputs": [
105 | {
106 | "name": "stdout",
107 | "output_type": "stream",
108 | "text": [
109 | "### iteration step : 0 rmse : 3.2388050277987723\n",
110 | "### iteration step : 50 rmse : 0.4876723101369648\n",
111 | "### iteration step : 100 rmse : 0.1564340384819247\n",
112 | "### iteration step : 150 rmse : 0.07455141311978046\n",
113 | "### iteration step : 200 rmse : 0.04325226798579314\n",
114 | "### iteration step : 250 rmse : 0.029248328780878973\n",
115 | "### iteration step : 300 rmse : 0.022621116143829466\n",
116 | "### iteration step : 350 rmse : 0.019493636196525135\n",
117 | "### iteration step : 400 rmse : 0.018022719092132704\n",
118 | "### iteration step : 450 rmse : 0.01731968595344266\n",
119 | "### iteration step : 500 rmse : 0.016973657887570753\n",
120 | "### iteration step : 550 rmse : 0.016796804595895633\n",
121 | "### iteration step : 600 rmse : 0.01670132290188466\n",
122 | "### iteration step : 650 rmse : 0.01664473691247669\n",
123 | "### iteration step : 700 rmse : 0.016605910068210026\n",
124 | "### iteration step : 750 rmse : 0.016574200475705\n",
125 | "### iteration step : 800 rmse : 0.01654431582921597\n",
126 | "### iteration step : 850 rmse : 0.01651375177473524\n",
127 | "### iteration step : 900 rmse : 0.01648146573819501\n",
128 | "### iteration step : 950 rmse : 0.016447171683479155\n"
129 | ]
130 | }
131 | ],
132 | "source": [
133 | "# R > 0 인 행 위치, 열 위치, 값을 non_zeros 리스트에 저장. \n",
134 | "non_zeros = [ (i, j, R[i,j]) for i in range(num_users) for j in range(num_items) if R[i,j] > 0 ]\n",
135 | "\n",
136 | "steps=1000\n",
137 | "learning_rate=0.01\n",
138 | "r_lambda=0.01\n",
139 | "\n",
140 | "# SGD 기법으로 P와 Q 매트릭스를 계속 업데이트. \n",
141 | "for step in range(steps):\n",
142 | " for i, j, r in non_zeros:\n",
143 | " # 실제 값과 예측 값의 차이인 오류 값 구함\n",
144 | " eij = r - np.dot(P[i, :], Q[j, :].T)\n",
145 | " # Regularization을 반영한 SGD 업데이트 공식 적용\n",
146 | " P[i,:] = P[i,:] + learning_rate*(eij * Q[j, :] - r_lambda*P[i,:])\n",
147 | " Q[j,:] = Q[j,:] + learning_rate*(eij * P[i, :] - r_lambda*Q[j,:])\n",
148 | "\n",
149 | " rmse = get_rmse(R, P, Q, non_zeros)\n",
150 | " if (step % 50) == 0 :\n",
151 | " print(\"### iteration step : \", step,\" rmse : \", rmse)\n",
152 | "\n"
153 | ]
154 | },
155 | {
156 | "cell_type": "code",
157 | "execution_count": 4,
158 | "metadata": {},
159 | "outputs": [
160 | {
161 | "name": "stdout",
162 | "output_type": "stream",
163 | "text": [
164 | "예측 행렬:\n",
165 | " [[3.991 0.897 1.306 2.002 1.663]\n",
166 | " [6.696 4.978 0.979 2.981 1.003]\n",
167 | " [6.677 0.391 2.987 3.977 3.986]\n",
168 | " [4.968 2.005 1.006 2.017 1.14 ]]\n"
169 | ]
170 | }
171 | ],
172 | "source": [
173 | "pred_matrix = np.dot(P, Q.T)\n",
174 | "print('예측 행렬:\\n', np.round(pred_matrix, 3))"
175 | ]
176 | },
177 | {
178 | "cell_type": "code",
179 | "execution_count": null,
180 | "metadata": {},
181 | "outputs": [],
182 | "source": [
183 | "R = np.array([[4, np.NaN, np.NaN, 2, np.NaN ],\n",
184 | " [np.NaN, 5, np.NaN, 3, 1 ],\n",
185 | " [np.NaN, np.NaN, 3, 4, 4 ],\n",
186 | " [5, 2, 1, 2, np.NaN ]])"
187 | ]
188 | },
189 | {
190 | "cell_type": "code",
191 | "execution_count": null,
192 | "metadata": {},
193 | "outputs": [],
194 | "source": []
195 | },
196 | {
197 | "cell_type": "markdown",
198 | "metadata": {},
199 | "source": [
200 | "### 행렬 분해 기반의 잠재 요인 협업 필터링 실습\n",
201 | "\n",
202 | "**경사하강법 기반의 행렬 분해 함수 생성**"
203 | ]
204 | },
205 | {
206 | "cell_type": "code",
207 | "execution_count": 5,
208 | "metadata": {},
209 | "outputs": [],
210 | "source": [
211 | "def matrix_factorization(R, K, steps=200, learning_rate=0.01, r_lambda = 0.01):\n",
212 | " num_users, num_items = R.shape\n",
213 | " # P와 Q 매트릭스의 크기를 지정하고 정규분포를 가진 랜덤한 값으로 입력합니다. \n",
214 | " np.random.seed(1)\n",
215 | " P = np.random.normal(scale=1./K, size=(num_users, K))\n",
216 | " Q = np.random.normal(scale=1./K, size=(num_items, K))\n",
217 | "\n",
218 | " break_count = 0\n",
219 | " \n",
220 | " # R > 0 인 행 위치, 열 위치, 값을 non_zeros 리스트 객체에 저장. \n",
221 | " non_zeros = [ (i, j, R[i,j]) for i in range(num_users) for j in range(num_items) if R[i,j] > 0 ]\n",
222 | " \n",
223 | " # SGD기법으로 P와 Q 매트릭스를 계속 업데이트. \n",
224 | " for step in range(steps):\n",
225 | " for i, j, r in non_zeros:\n",
226 | " # 실제 값과 예측 값의 차이인 오류 값 구함\n",
227 | " eij = r - np.dot(P[i, :], Q[j, :].T)\n",
228 | " # Regularization을 반영한 SGD 업데이트 공식 적용\n",
229 | " P[i,:] = P[i,:] + learning_rate*(eij * Q[j, :] - r_lambda*P[i,:])\n",
230 | " Q[j,:] = Q[j,:] + learning_rate*(eij * P[i, :] - r_lambda*Q[j,:])\n",
231 | " \n",
232 | " rmse = get_rmse(R, P, Q, non_zeros)\n",
233 | " if (step % 10) == 0 :\n",
234 | " print(\"### iteration step : \", step,\" rmse : \", rmse)\n",
235 | " \n",
236 | " return P, Q"
237 | ]
238 | },
239 | {
240 | "cell_type": "code",
241 | "execution_count": 6,
242 | "metadata": {},
243 | "outputs": [],
244 | "source": [
245 | "import pandas as pd\n",
246 | "import numpy as np\n",
247 | "\n",
248 | "movies = pd.read_csv('./ml-latest-small/movies.csv')\n",
249 | "ratings = pd.read_csv('./ml-latest-small/ratings.csv')\n",
250 | "ratings = ratings[['userId', 'movieId', 'rating']]\n",
251 | "ratings_matrix = ratings.pivot_table('rating', index='userId', columns='movieId')\n",
252 | "\n",
253 | "# title 컬럼을 얻기 이해 movies 와 조인 수행\n",
254 | "rating_movies = pd.merge(ratings, movies, on='movieId')\n",
255 | "\n",
256 | "# columns='title' 로 title 컬럼으로 pivot 수행. \n",
257 | "ratings_matrix = rating_movies.pivot_table('rating', index='userId', columns='title')"
258 | ]
259 | },
260 | {
261 | "cell_type": "code",
262 | "execution_count": 7,
263 | "metadata": {},
264 | "outputs": [
265 | {
266 | "name": "stdout",
267 | "output_type": "stream",
268 | "text": [
269 | "### iteration step : 0 rmse : 2.9023619751336867\n",
270 | "### iteration step : 10 rmse : 0.7335768591017927\n",
271 | "### iteration step : 20 rmse : 0.5115539026853442\n",
272 | "### iteration step : 30 rmse : 0.37261628282537446\n",
273 | "### iteration step : 40 rmse : 0.2960818299181014\n",
274 | "### iteration step : 50 rmse : 0.2520353192341642\n",
275 | "### iteration step : 60 rmse : 0.22487503275269854\n",
276 | "### iteration step : 70 rmse : 0.20685455302331537\n",
277 | "### iteration step : 80 rmse : 0.19413418783028685\n",
278 | "### iteration step : 90 rmse : 0.18470082002720403\n",
279 | "### iteration step : 100 rmse : 0.17742927527209104\n",
280 | "### iteration step : 110 rmse : 0.17165226964707486\n",
281 | "### iteration step : 120 rmse : 0.1669518194687172\n",
282 | "### iteration step : 130 rmse : 0.16305292191997542\n",
283 | "### iteration step : 140 rmse : 0.15976691929679643\n",
284 | "### iteration step : 150 rmse : 0.1569598699945732\n",
285 | "### iteration step : 160 rmse : 0.15453398186715428\n",
286 | "### iteration step : 170 rmse : 0.15241618551077643\n",
287 | "### iteration step : 180 rmse : 0.15055080739628307\n",
288 | "### iteration step : 190 rmse : 0.1488947091323209\n"
289 | ]
290 | }
291 | ],
292 | "source": [
293 | "P, Q = matrix_factorization(ratings_matrix.values, K=50, steps=200, learning_rate=0.01, r_lambda = 0.01)\n",
294 | "pred_matrix = np.dot(P, Q.T)"
295 | ]
296 | },
297 | {
298 | "cell_type": "code",
299 | "execution_count": 12,
300 | "metadata": {},
301 | "outputs": [
302 | {
303 | "data": {
304 | "text/html": [
305 | "\n",
306 | "\n",
319 | "
\n",
320 | " \n",
321 | " \n",
322 | " title | \n",
323 | " '71 (2014) | \n",
324 | " 'Hellboy': The Seeds of Creation (2004) | \n",
325 | " 'Round Midnight (1986) | \n",
326 | " 'Salem's Lot (2004) | \n",
327 | " 'Til There Was You (1997) | \n",
328 | " 'Tis the Season for Love (2015) | \n",
329 | " 'burbs, The (1989) | \n",
330 | " 'night Mother (1986) | \n",
331 | " (500) Days of Summer (2009) | \n",
332 | " *batteries not included (1987) | \n",
333 | " ... | \n",
334 | " Zulu (2013) | \n",
335 | " [REC] (2007) | \n",
336 | " [REC]² (2009) | \n",
337 | " [REC]³ 3 Génesis (2012) | \n",
338 | " anohana: The Flower We Saw That Day - The Movie (2013) | \n",
339 | " eXistenZ (1999) | \n",
340 | " xXx (2002) | \n",
341 | " xXx: State of the Union (2005) | \n",
342 | " ¡Three Amigos! (1986) | \n",
343 | " À nous la liberté (Freedom for Us) (1931) | \n",
344 | "
\n",
345 | " \n",
346 | " userId | \n",
347 | " | \n",
348 | " | \n",
349 | " | \n",
350 | " | \n",
351 | " | \n",
352 | " | \n",
353 | " | \n",
354 | " | \n",
355 | " | \n",
356 | " | \n",
357 | " | \n",
358 | " | \n",
359 | " | \n",
360 | " | \n",
361 | " | \n",
362 | " | \n",
363 | " | \n",
364 | " | \n",
365 | " | \n",
366 | " | \n",
367 | " | \n",
368 | "
\n",
369 | " \n",
370 | " \n",
371 | " \n",
372 | " 1 | \n",
373 | " 3.055084 | \n",
374 | " 4.092018 | \n",
375 | " 3.564130 | \n",
376 | " 4.502167 | \n",
377 | " 3.981215 | \n",
378 | " 1.271694 | \n",
379 | " 3.603274 | \n",
380 | " 2.333266 | \n",
381 | " 5.091749 | \n",
382 | " 3.972454 | \n",
383 | " ... | \n",
384 | " 1.402608 | \n",
385 | " 4.208382 | \n",
386 | " 3.705957 | \n",
387 | " 2.720514 | \n",
388 | " 2.787331 | \n",
389 | " 3.475076 | \n",
390 | " 3.253458 | \n",
391 | " 2.161087 | \n",
392 | " 4.010495 | \n",
393 | " 0.859474 | \n",
394 | "
\n",
395 | " \n",
396 | " 2 | \n",
397 | " 3.170119 | \n",
398 | " 3.657992 | \n",
399 | " 3.308707 | \n",
400 | " 4.166521 | \n",
401 | " 4.311890 | \n",
402 | " 1.275469 | \n",
403 | " 4.237972 | \n",
404 | " 1.900366 | \n",
405 | " 3.392859 | \n",
406 | " 3.647421 | \n",
407 | " ... | \n",
408 | " 0.973811 | \n",
409 | " 3.528264 | \n",
410 | " 3.361532 | \n",
411 | " 2.672535 | \n",
412 | " 2.404456 | \n",
413 | " 4.232789 | \n",
414 | " 2.911602 | \n",
415 | " 1.634576 | \n",
416 | " 4.135735 | \n",
417 | " 0.725684 | \n",
418 | "
\n",
419 | " \n",
420 | " 3 | \n",
421 | " 2.307073 | \n",
422 | " 1.658853 | \n",
423 | " 1.443538 | \n",
424 | " 2.208859 | \n",
425 | " 2.229486 | \n",
426 | " 0.780760 | \n",
427 | " 1.997043 | \n",
428 | " 0.924908 | \n",
429 | " 2.970700 | \n",
430 | " 2.551446 | \n",
431 | " ... | \n",
432 | " 0.520354 | \n",
433 | " 1.709494 | \n",
434 | " 2.281596 | \n",
435 | " 1.782833 | \n",
436 | " 1.635173 | \n",
437 | " 1.323276 | \n",
438 | " 2.887580 | \n",
439 | " 1.042618 | \n",
440 | " 2.293890 | \n",
441 | " 0.396941 | \n",
442 | "
\n",
443 | " \n",
444 | "
\n",
445 | "
3 rows × 9719 columns
\n",
446 | "
"
447 | ],
448 | "text/plain": [
449 | "title '71 (2014) 'Hellboy': The Seeds of Creation (2004) \\\n",
450 | "userId \n",
451 | "1 3.055084 4.092018 \n",
452 | "2 3.170119 3.657992 \n",
453 | "3 2.307073 1.658853 \n",
454 | "\n",
455 | "title 'Round Midnight (1986) 'Salem's Lot (2004) \\\n",
456 | "userId \n",
457 | "1 3.564130 4.502167 \n",
458 | "2 3.308707 4.166521 \n",
459 | "3 1.443538 2.208859 \n",
460 | "\n",
461 | "title 'Til There Was You (1997) 'Tis the Season for Love (2015) \\\n",
462 | "userId \n",
463 | "1 3.981215 1.271694 \n",
464 | "2 4.311890 1.275469 \n",
465 | "3 2.229486 0.780760 \n",
466 | "\n",
467 | "title 'burbs, The (1989) 'night Mother (1986) (500) Days of Summer (2009) \\\n",
468 | "userId \n",
469 | "1 3.603274 2.333266 5.091749 \n",
470 | "2 4.237972 1.900366 3.392859 \n",
471 | "3 1.997043 0.924908 2.970700 \n",
472 | "\n",
473 | "title *batteries not included (1987) \\\n",
474 | "userId \n",
475 | "1 3.972454 \n",
476 | "2 3.647421 \n",
477 | "3 2.551446 \n",
478 | "\n",
479 | "title ... Zulu (2013) [REC] (2007) \\\n",
480 | "userId ... \n",
481 | "1 ... 1.402608 4.208382 \n",
482 | "2 ... 0.973811 3.528264 \n",
483 | "3 ... 0.520354 1.709494 \n",
484 | "\n",
485 | "title [REC]² (2009) [REC]³ 3 Génesis (2012) \\\n",
486 | "userId \n",
487 | "1 3.705957 2.720514 \n",
488 | "2 3.361532 2.672535 \n",
489 | "3 2.281596 1.782833 \n",
490 | "\n",
491 | "title anohana: The Flower We Saw That Day - The Movie (2013) \\\n",
492 | "userId \n",
493 | "1 2.787331 \n",
494 | "2 2.404456 \n",
495 | "3 1.635173 \n",
496 | "\n",
497 | "title eXistenZ (1999) xXx (2002) xXx: State of the Union (2005) \\\n",
498 | "userId \n",
499 | "1 3.475076 3.253458 2.161087 \n",
500 | "2 4.232789 2.911602 1.634576 \n",
501 | "3 1.323276 2.887580 1.042618 \n",
502 | "\n",
503 | "title ¡Three Amigos! (1986) À nous la liberté (Freedom for Us) (1931) \n",
504 | "userId \n",
505 | "1 4.010495 0.859474 \n",
506 | "2 4.135735 0.725684 \n",
507 | "3 2.293890 0.396941 \n",
508 | "\n",
509 | "[3 rows x 9719 columns]"
510 | ]
511 | },
512 | "execution_count": 12,
513 | "metadata": {},
514 | "output_type": "execute_result"
515 | }
516 | ],
517 | "source": [
518 | "ratings_pred_matrix = pd.DataFrame(data=pred_matrix, index= ratings_matrix.index,\n",
519 | " columns = ratings_matrix.columns)\n",
520 | "\n",
521 | "ratings_pred_matrix.head(3)"
522 | ]
523 | },
524 | {
525 | "cell_type": "code",
526 | "execution_count": 13,
527 | "metadata": {},
528 | "outputs": [],
529 | "source": [
530 | "def get_unseen_movies(ratings_matrix, userId):\n",
531 | " # userId로 입력받은 사용자의 모든 영화정보 추출하여 Series로 반환함. \n",
532 | " # 반환된 user_rating 은 영화명(title)을 index로 가지는 Series 객체임. \n",
533 | " user_rating = ratings_matrix.loc[userId,:]\n",
534 | " \n",
535 | " # user_rating이 0보다 크면 기존에 관람한 영화임. 대상 index를 추출하여 list 객체로 만듬\n",
536 | " already_seen = user_rating[ user_rating > 0].index.tolist()\n",
537 | " \n",
538 | " # 모든 영화명을 list 객체로 만듬. \n",
539 | " movies_list = ratings_matrix.columns.tolist()\n",
540 | " \n",
541 | " # list comprehension으로 already_seen에 해당하는 movie는 movies_list에서 제외함. \n",
542 | " unseen_list = [ movie for movie in movies_list if movie not in already_seen]\n",
543 | " \n",
544 | " return unseen_list"
545 | ]
546 | },
547 | {
548 | "cell_type": "code",
549 | "execution_count": 14,
550 | "metadata": {},
551 | "outputs": [],
552 | "source": [
553 | "def recomm_movie_by_userid(pred_df, userId, unseen_list, top_n=10):\n",
554 | " # 예측 평점 DataFrame에서 사용자id index와 unseen_list로 들어온 영화명 컬럼을 추출하여\n",
555 | " # 가장 예측 평점이 높은 순으로 정렬함. \n",
556 | " recomm_movies = pred_df.loc[userId, unseen_list].sort_values(ascending=False)[:top_n]\n",
557 | " return recomm_movies"
558 | ]
559 | },
560 | {
561 | "cell_type": "code",
562 | "execution_count": 15,
563 | "metadata": {},
564 | "outputs": [
565 | {
566 | "data": {
567 | "text/html": [
568 | "\n",
569 | "\n",
582 | "
\n",
583 | " \n",
584 | " \n",
585 | " | \n",
586 | " pred_score | \n",
587 | "
\n",
588 | " \n",
589 | " title | \n",
590 | " | \n",
591 | "
\n",
592 | " \n",
593 | " \n",
594 | " \n",
595 | " Rear Window (1954) | \n",
596 | " 5.704612 | \n",
597 | "
\n",
598 | " \n",
599 | " South Park: Bigger, Longer and Uncut (1999) | \n",
600 | " 5.451100 | \n",
601 | "
\n",
602 | " \n",
603 | " Rounders (1998) | \n",
604 | " 5.298393 | \n",
605 | "
\n",
606 | " \n",
607 | " Blade Runner (1982) | \n",
608 | " 5.244951 | \n",
609 | "
\n",
610 | " \n",
611 | " Roger & Me (1989) | \n",
612 | " 5.191962 | \n",
613 | "
\n",
614 | " \n",
615 | " Gattaca (1997) | \n",
616 | " 5.183179 | \n",
617 | "
\n",
618 | " \n",
619 | " Ben-Hur (1959) | \n",
620 | " 5.130463 | \n",
621 | "
\n",
622 | " \n",
623 | " Rosencrantz and Guildenstern Are Dead (1990) | \n",
624 | " 5.087375 | \n",
625 | "
\n",
626 | " \n",
627 | " Big Lebowski, The (1998) | \n",
628 | " 5.038690 | \n",
629 | "
\n",
630 | " \n",
631 | " Star Wars: Episode V - The Empire Strikes Back (1980) | \n",
632 | " 4.989601 | \n",
633 | "
\n",
634 | " \n",
635 | "
\n",
636 | "
"
637 | ],
638 | "text/plain": [
639 | " pred_score\n",
640 | "title \n",
641 | "Rear Window (1954) 5.704612\n",
642 | "South Park: Bigger, Longer and Uncut (1999) 5.451100\n",
643 | "Rounders (1998) 5.298393\n",
644 | "Blade Runner (1982) 5.244951\n",
645 | "Roger & Me (1989) 5.191962\n",
646 | "Gattaca (1997) 5.183179\n",
647 | "Ben-Hur (1959) 5.130463\n",
648 | "Rosencrantz and Guildenstern Are Dead (1990) 5.087375\n",
649 | "Big Lebowski, The (1998) 5.038690\n",
650 | "Star Wars: Episode V - The Empire Strikes Back ... 4.989601"
651 | ]
652 | },
653 | "execution_count": 15,
654 | "metadata": {},
655 | "output_type": "execute_result"
656 | }
657 | ],
658 | "source": [
659 | "# 사용자가 관람하지 않는 영화명 추출 \n",
660 | "unseen_list = get_unseen_movies(ratings_matrix, 9)\n",
661 | "\n",
662 | "# 잠재요인 기반 협업 필터링으로 영화 추천 \n",
663 | "recomm_movies = recomm_movie_by_userid(ratings_pred_matrix, 9, unseen_list, top_n=10)\n",
664 | "\n",
665 | "# 평점 데이타를 DataFrame으로 생성. \n",
666 | "recomm_movies = pd.DataFrame(data=recomm_movies.values,index=recomm_movies.index,columns=['pred_score'])\n",
667 | "recomm_movies"
668 | ]
669 | },
670 | {
671 | "cell_type": "code",
672 | "execution_count": null,
673 | "metadata": {},
674 | "outputs": [],
675 | "source": []
676 | }
677 | ],
678 | "metadata": {
679 | "kernelspec": {
680 | "display_name": "Python 3",
681 | "language": "python",
682 | "name": "python3"
683 | },
684 | "language_info": {
685 | "codemirror_mode": {
686 | "name": "ipython",
687 | "version": 3
688 | },
689 | "file_extension": ".py",
690 | "mimetype": "text/x-python",
691 | "name": "python",
692 | "nbconvert_exporter": "python",
693 | "pygments_lexer": "ipython3",
694 | "version": "3.6.4"
695 | }
696 | },
697 | "nbformat": 4,
698 | "nbformat_minor": 2
699 | }
700 |
--------------------------------------------------------------------------------
/9장/9.4 파이썬 추천 시스템 패키지 Surprise 실습.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import surprise \n",
10 | "\n",
11 | "print(surprise.__version__)"
12 | ]
13 | },
14 | {
15 | "cell_type": "markdown",
16 | "metadata": {},
17 | "source": [
18 | "### Surprise 를 이용한 추천 시스템 구축"
19 | ]
20 | },
21 | {
22 | "cell_type": "code",
23 | "execution_count": null,
24 | "metadata": {},
25 | "outputs": [],
26 | "source": [
27 | "from surprise import SVD\n",
28 | "from surprise import Dataset \n",
29 | "from surprise import accuracy \n",
30 | "from surprise.model_selection import train_test_split"
31 | ]
32 | },
33 | {
34 | "cell_type": "markdown",
35 | "metadata": {},
36 | "source": [
37 | "**내장 데이터를 로드하고 학습과 테스트 데이터로 분리**"
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "execution_count": null,
43 | "metadata": {},
44 | "outputs": [],
45 | "source": [
46 | "data = Dataset.load_builtin('ml-100k') \n",
47 | "trainset, testset = train_test_split(data, test_size=.25, random_state=0) "
48 | ]
49 | },
50 | {
51 | "cell_type": "markdown",
52 | "metadata": {},
53 | "source": [
54 | "**추천 행렬 분해 알고리즘으로 SVD객체를 생성하고 학습수행**"
55 | ]
56 | },
57 | {
58 | "cell_type": "code",
59 | "execution_count": null,
60 | "metadata": {},
61 | "outputs": [],
62 | "source": [
63 | "algo = SVD()\n",
64 | "algo.fit(trainset) "
65 | ]
66 | },
67 | {
68 | "cell_type": "markdown",
69 | "metadata": {},
70 | "source": [
71 | "**테스트 데이터 세트에 예상 평점 데이터 예측. test()메소드 호출 시 Prediction 객체의 리스트로 평점 예측 데이터 반환**"
72 | ]
73 | },
74 | {
75 | "cell_type": "code",
76 | "execution_count": null,
77 | "metadata": {},
78 | "outputs": [],
79 | "source": [
80 | "predictions = algo.test(testset)\n",
81 | "print('prediction type :',type(predictions), ' size:',len(predictions))\n",
82 | "print('prediction 결과의 최초 5개 추출')\n",
83 | "predictions[:5]"
84 | ]
85 | },
86 | {
87 | "cell_type": "code",
88 | "execution_count": null,
89 | "metadata": {},
90 | "outputs": [],
91 | "source": [
92 | "[ (pred.uid, pred.iid, pred.est) for pred in predictions[:3] ]"
93 | ]
94 | },
95 | {
96 | "cell_type": "markdown",
97 | "metadata": {},
98 | "source": [
99 | "**predict()메소드는 개별 사용자,아이템에 대한 예측 평점 정보를 반환**"
100 | ]
101 | },
102 | {
103 | "cell_type": "code",
104 | "execution_count": null,
105 | "metadata": {},
106 | "outputs": [],
107 | "source": [
108 | "# 사용자 아이디, 아이템 아이디는 문자열로 입력해야 함. \n",
109 | "uid = str(196)\n",
110 | "iid = str(302)\n",
111 | "pred = algo.predict(uid, iid)\n",
112 | "print(pred)"
113 | ]
114 | },
115 | {
116 | "cell_type": "markdown",
117 | "metadata": {},
118 | "source": [
119 | "**반환된 Prediction의 리스트 객체를 기반으로 RMSE 평가**"
120 | ]
121 | },
122 | {
123 | "cell_type": "code",
124 | "execution_count": null,
125 | "metadata": {},
126 | "outputs": [],
127 | "source": [
128 | "accuracy.rmse(predictions)"
129 | ]
130 | },
131 | {
132 | "cell_type": "markdown",
133 | "metadata": {},
134 | "source": [
135 | "### Surprise 주요 모듈 소개\n",
136 | "**csv 파일로 사용자 평점 데이터 생성**"
137 | ]
138 | },
139 | {
140 | "cell_type": "code",
141 | "execution_count": null,
142 | "metadata": {},
143 | "outputs": [],
144 | "source": [
145 | "import pandas as pd\n",
146 | "\n",
147 | "ratings = pd.read_csv('./ml-latest-small/ratings.csv')\n",
148 | "# ratings_noh.csv 파일로 unload 시 index 와 header를 모두 제거한 새로운 파일 생성. \n",
149 | "ratings.to_csv('./ml-latest-small/ratings_noh.csv', index=False, header=False)\n"
150 | ]
151 | },
152 | {
153 | "cell_type": "markdown",
154 | "metadata": {},
155 | "source": [
156 | "**Reader클래스로 파일의 포맷팅 지정하고 Dataset의 load_from_file()을 이용하여 데이터셋 로딩**"
157 | ]
158 | },
159 | {
160 | "cell_type": "code",
161 | "execution_count": null,
162 | "metadata": {},
163 | "outputs": [],
164 | "source": [
165 | "from surprise import Reader\n",
166 | "\n",
167 | "reader = Reader(line_format='user item rating timestamp', sep=',', rating_scale=(0.5, 5))\n",
168 | "data=Dataset.load_from_file('./ml-latest-small/ratings_noh.csv',reader=reader)"
169 | ]
170 | },
171 | {
172 | "cell_type": "markdown",
173 | "metadata": {},
174 | "source": [
175 | "**학습과 테스트 데이터 세트로 분할하고 SVD로 학습후 테스트데이터 평점 예측 후 RMSE평가**"
176 | ]
177 | },
178 | {
179 | "cell_type": "code",
180 | "execution_count": null,
181 | "metadata": {},
182 | "outputs": [],
183 | "source": [
184 | "trainset, testset = train_test_split(data, test_size=.25, random_state=0)\n",
185 | "\n",
186 | "# 수행시마다 동일한 결과 도출을 위해 random_state 설정 \n",
187 | "algo = SVD(n_factors=50, random_state=0)\n",
188 | "\n",
189 | "# 학습 데이터 세트로 학습 후 테스트 데이터 세트로 평점 예측 후 RMSE 평가\n",
190 | "algo.fit(trainset) \n",
191 | "predictions = algo.test( testset )\n",
192 | "accuracy.rmse(predictions)\n"
193 | ]
194 | },
195 | {
196 | "cell_type": "markdown",
197 | "metadata": {},
198 | "source": [
199 | "**판다스 DataFrame기반에서 동일하게 재 수행**"
200 | ]
201 | },
202 | {
203 | "cell_type": "code",
204 | "execution_count": null,
205 | "metadata": {},
206 | "outputs": [],
207 | "source": [
208 | "import pandas as pd\n",
209 | "from surprise import Reader, Dataset\n",
210 | "\n",
211 | "ratings = pd.read_csv('./ml-latest-small/ratings.csv') \n",
212 | "reader = Reader(rating_scale=(0.5, 5.0))\n",
213 | "\n",
214 | "# ratings DataFrame 에서 컬럼은 사용자 아이디, 아이템 아이디, 평점 순서를 지켜야 합니다. \n",
215 | "data = Dataset.load_from_df(ratings[['userId', 'movieId', 'rating']], reader)\n",
216 | "trainset, testset = train_test_split(data, test_size=.25, random_state=0)\n",
217 | "\n",
218 | "algo = SVD(n_factors=50, random_state=0)\n",
219 | "algo.fit(trainset) \n",
220 | "predictions = algo.test( testset )\n",
221 | "accuracy.rmse(predictions)\n"
222 | ]
223 | },
224 | {
225 | "cell_type": "markdown",
226 | "metadata": {},
227 | "source": [
228 | "### 교차 검증(Cross Validation)과 하이퍼 파라미터 튜닝\n",
229 | "\n",
230 | "**cross_validate()를 이용한 교차 검증**"
231 | ]
232 | },
233 | {
234 | "cell_type": "code",
235 | "execution_count": null,
236 | "metadata": {},
237 | "outputs": [],
238 | "source": [
239 | "from surprise.model_selection import cross_validate \n",
240 | "\n",
241 | "# Pandas DataFrame에서 Surprise Dataset으로 데이터 로딩 \n",
242 | "ratings = pd.read_csv('./ml-latest-small/ratings.csv') # reading data in pandas df\n",
243 | "reader = Reader(rating_scale=(0.5, 5.0))\n",
244 | "data = Dataset.load_from_df(ratings[['userId', 'movieId', 'rating']], reader)\n",
245 | "\n",
246 | "algo = SVD(random_state=0) \n",
247 | "cross_validate(algo, data, measures=['RMSE', 'MAE'], cv=5, verbose=True) "
248 | ]
249 | },
250 | {
251 | "cell_type": "markdown",
252 | "metadata": {},
253 | "source": [
254 | "**GridSearchCV 이용**"
255 | ]
256 | },
257 | {
258 | "cell_type": "code",
259 | "execution_count": null,
260 | "metadata": {},
261 | "outputs": [],
262 | "source": [
263 | "from surprise.model_selection import GridSearchCV\n",
264 | "\n",
265 | "# 최적화할 파라미터들을 딕셔너리 형태로 지정. \n",
266 | "param_grid = {'n_epochs': [20, 40, 60], 'n_factors': [50, 100, 200] }\n",
267 | "\n",
268 | "# CV를 3개 폴드 세트로 지정, 성능 평가는 rmse, mse 로 수행 하도록 GridSearchCV 구성\n",
269 | "gs = GridSearchCV(SVD, param_grid, measures=['rmse', 'mae'], cv=3)\n",
270 | "gs.fit(data)\n",
271 | "\n",
272 | "# 최고 RMSE Evaluation 점수와 그때의 하이퍼 파라미터\n",
273 | "print(gs.best_score['rmse'])\n",
274 | "print(gs.best_params['rmse'])\n",
275 | "\n",
276 | "\n"
277 | ]
278 | },
279 | {
280 | "cell_type": "markdown",
281 | "metadata": {},
282 | "source": [
283 | "### Surprise 를 이용한 개인화 영화 추천 시스템 구축"
284 | ]
285 | },
286 | {
287 | "cell_type": "markdown",
288 | "metadata": {},
289 | "source": [
290 | "**SVD 학습은 TrainSet 클래스를 이용해야 함**"
291 | ]
292 | },
293 | {
294 | "cell_type": "code",
295 | "execution_count": 28,
296 | "metadata": {},
297 | "outputs": [
298 | {
299 | "ename": "AttributeError",
300 | "evalue": "'DatasetAutoFolds' object has no attribute 'global_mean'",
301 | "output_type": "error",
302 | "traceback": [
303 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
304 | "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)",
305 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mDataset\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mload_from_df\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mratings\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'userId'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'movieId'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'rating'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mreader\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0malgo\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mSVD\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mn_factors\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m50\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mrandom_state\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0malgo\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
306 | "\u001b[1;32mC:\\ProgramData\\Anaconda3\\lib\\site-packages\\surprise\\prediction_algorithms\\matrix_factorization.pyx\u001b[0m in \u001b[0;36msurprise.prediction_algorithms.matrix_factorization.SVD.fit\u001b[1;34m()\u001b[0m\n",
307 | "\u001b[1;32mC:\\ProgramData\\Anaconda3\\lib\\site-packages\\surprise\\prediction_algorithms\\matrix_factorization.pyx\u001b[0m in \u001b[0;36msurprise.prediction_algorithms.matrix_factorization.SVD.sgd\u001b[1;34m()\u001b[0m\n",
308 | "\u001b[1;31mAttributeError\u001b[0m: 'DatasetAutoFolds' object has no attribute 'global_mean'"
309 | ]
310 | }
311 | ],
312 | "source": [
313 | "# 아래 코드는 train_test_split( )으로 분리되지 않는 Dataset에 fit( )을 호출하여 오류를 발생합니다.\n",
314 | "data = Dataset.load_from_df(ratings[['userId', 'movieId', 'rating']], reader)\n",
315 | "algo = SVD(n_factors=50, random_state=0)\n",
316 | "algo.fit(data)\n"
317 | ]
318 | },
319 | {
320 | "cell_type": "markdown",
321 | "metadata": {},
322 | "source": [
323 | "**DatasetAutoFolds를 이용한 전체 데이터를 TrainSet클래스 변환**"
324 | ]
325 | },
326 | {
327 | "cell_type": "code",
328 | "execution_count": 29,
329 | "metadata": {},
330 | "outputs": [],
331 | "source": [
332 | "from surprise.dataset import DatasetAutoFolds\n",
333 | "\n",
334 | "reader = Reader(line_format='user item rating timestamp', sep=',', rating_scale=(0.5, 5))\n",
335 | "# DatasetAutoFolds 클래스를 ratings_noh.csv 파일 기반으로 생성. \n",
336 | "data_folds = DatasetAutoFolds(ratings_file='./ml-latest-small/ratings_noh.csv', reader=reader)\n",
337 | "\n",
338 | "#전체 데이터를 학습데이터로 생성함. \n",
339 | "trainset = data_folds.build_full_trainset()\n"
340 | ]
341 | },
342 | {
343 | "cell_type": "markdown",
344 | "metadata": {},
345 | "source": [
346 | "**SVD로 학습**"
347 | ]
348 | },
349 | {
350 | "cell_type": "code",
351 | "execution_count": 30,
352 | "metadata": {},
353 | "outputs": [
354 | {
355 | "data": {
356 | "text/plain": [
357 | ""
358 | ]
359 | },
360 | "execution_count": 30,
361 | "metadata": {},
362 | "output_type": "execute_result"
363 | }
364 | ],
365 | "source": [
366 | "algo = SVD(n_epochs=20, n_factors=50, random_state=0)\n",
367 | "algo.fit(trainset)\n"
368 | ]
369 | },
370 | {
371 | "cell_type": "code",
372 | "execution_count": 31,
373 | "metadata": {},
374 | "outputs": [
375 | {
376 | "name": "stdout",
377 | "output_type": "stream",
378 | "text": [
379 | "사용자 아이디 9는 영화 아이디 42의 평점 없음\n",
380 | " movieId title genres\n",
381 | "38 42 Dead Presidents (1995) Action|Crime|Drama\n"
382 | ]
383 | }
384 | ],
385 | "source": [
386 | "# 영화에 대한 상세 속성 정보 DataFrame로딩\n",
387 | "movies = pd.read_csv('./ml-latest-small/movies.csv')\n",
388 | "\n",
389 | "# userId=9 의 movieId 데이터 추출하여 movieId=42 데이터가 있는지 확인. \n",
390 | "movieIds = ratings[ratings['userId']==9]['movieId']\n",
391 | "if movieIds[movieIds==42].count() == 0:\n",
392 | " print('사용자 아이디 9는 영화 아이디 42의 평점 없음')\n",
393 | "\n",
394 | "print(movies[movies['movieId']==42])\n"
395 | ]
396 | },
397 | {
398 | "cell_type": "code",
399 | "execution_count": 32,
400 | "metadata": {},
401 | "outputs": [
402 | {
403 | "name": "stdout",
404 | "output_type": "stream",
405 | "text": [
406 | "user: 9 item: 42 r_ui = None est = 3.13 {'was_impossible': False}\n"
407 | ]
408 | }
409 | ],
410 | "source": [
411 | "uid = str(9)\n",
412 | "iid = str(42)\n",
413 | "\n",
414 | "pred = algo.predict(uid, iid, verbose=True)\n"
415 | ]
416 | },
417 | {
418 | "cell_type": "code",
419 | "execution_count": 33,
420 | "metadata": {},
421 | "outputs": [
422 | {
423 | "name": "stdout",
424 | "output_type": "stream",
425 | "text": [
426 | "평점 매긴 영화수: 46 추천대상 영화수: 9696 전체 영화수: 9742\n"
427 | ]
428 | }
429 | ],
430 | "source": [
431 | "def get_unseen_surprise(ratings, movies, userId):\n",
432 | " #입력값으로 들어온 userId에 해당하는 사용자가 평점을 매긴 모든 영화를 리스트로 생성\n",
433 | " seen_movies = ratings[ratings['userId']== userId]['movieId'].tolist()\n",
434 | " \n",
435 | " # 모든 영화들의 movieId를 리스트로 생성. \n",
436 | " total_movies = movies['movieId'].tolist()\n",
437 | " \n",
438 | " # 모든 영화들의 movieId중 이미 평점을 매긴 영화의 movieId를 제외하여 리스트로 생성\n",
439 | " unseen_movies= [movie for movie in total_movies if movie not in seen_movies]\n",
440 | " print('평점 매긴 영화수:',len(seen_movies), '추천대상 영화수:',len(unseen_movies), \\\n",
441 | " '전체 영화수:',len(total_movies))\n",
442 | " \n",
443 | " return unseen_movies\n",
444 | "\n",
445 | "unseen_movies = get_unseen_surprise(ratings, movies, 9)"
446 | ]
447 | },
448 | {
449 | "cell_type": "code",
450 | "execution_count": 34,
451 | "metadata": {},
452 | "outputs": [
453 | {
454 | "name": "stdout",
455 | "output_type": "stream",
456 | "text": [
457 | "평점 매긴 영화수: 46 추천대상 영화수: 9696 전체 영화수: 9742\n",
458 | "##### Top-10 추천 영화 리스트 #####\n",
459 | "Usual Suspects, The (1995) : 4.306302135700814\n",
460 | "Star Wars: Episode IV - A New Hope (1977) : 4.281663842987387\n",
461 | "Pulp Fiction (1994) : 4.278152632122759\n",
462 | "Silence of the Lambs, The (1991) : 4.226073566460876\n",
463 | "Godfather, The (1972) : 4.1918097904381995\n",
464 | "Streetcar Named Desire, A (1951) : 4.154746591122658\n",
465 | "Star Wars: Episode V - The Empire Strikes Back (1980) : 4.122016128534504\n",
466 | "Star Wars: Episode VI - Return of the Jedi (1983) : 4.108009609093436\n",
467 | "Goodfellas (1990) : 4.083464936588478\n",
468 | "Glory (1989) : 4.07887165526957\n"
469 | ]
470 | }
471 | ],
472 | "source": [
473 | "def recomm_movie_by_surprise(algo, userId, unseen_movies, top_n=10):\n",
474 | " # 알고리즘 객체의 predict() 메서드를 평점이 없는 영화에 반복 수행한 후 결과를 list 객체로 저장\n",
475 | " predictions = [algo.predict(str(userId), str(movieId)) for movieId in unseen_movies]\n",
476 | " \n",
477 | " # predictions list 객체는 surprise의 Predictions 객체를 원소로 가지고 있음.\n",
478 | " # [Prediction(uid='9', iid='1', est=3.69), Prediction(uid='9', iid='2', est=2.98),,,,]\n",
479 | " # 이를 est 값으로 정렬하기 위해서 아래의 sortkey_est 함수를 정의함.\n",
480 | " # sortkey_est 함수는 list 객체의 sort() 함수의 키 값으로 사용되어 정렬 수행.\n",
481 | " def sortkey_est(pred):\n",
482 | " return pred.est\n",
483 | " \n",
484 | " # sortkey_est( ) 반환값의 내림 차순으로 정렬 수행하고 top_n개의 최상위 값 추출.\n",
485 | " predictions.sort(key=sortkey_est, reverse=True)\n",
486 | " top_predictions= predictions[:top_n]\n",
487 | " \n",
488 | " # top_n으로 추출된 영화의 정보 추출. 영화 아이디, 추천 예상 평점, 제목 추출\n",
489 | " top_movie_ids = [ int(pred.iid) for pred in top_predictions]\n",
490 | " top_movie_rating = [ pred.est for pred in top_predictions]\n",
491 | " top_movie_titles = movies[movies.movieId.isin(top_movie_ids)]['title']\n",
492 | " top_movie_preds = [ (id, title, rating) for id, title, rating in zip(top_movie_ids, top_movie_titles, top_movie_rating)]\n",
493 | " \n",
494 | " return top_movie_preds\n",
495 | "\n",
496 | "unseen_movies = get_unseen_surprise(ratings, movies, 9)\n",
497 | "top_movie_preds = recomm_movie_by_surprise(algo, 9, unseen_movies, top_n=10)\n",
498 | "print('##### Top-10 추천 영화 리스트 #####')\n",
499 | "\n",
500 | "for top_movie in top_movie_preds:\n",
501 | " print(top_movie[1], \":\", top_movie[2])"
502 | ]
503 | },
504 | {
505 | "cell_type": "code",
506 | "execution_count": null,
507 | "metadata": {},
508 | "outputs": [],
509 | "source": []
510 | }
511 | ],
512 | "metadata": {
513 | "kernelspec": {
514 | "display_name": "Python 3",
515 | "language": "python",
516 | "name": "python3"
517 | },
518 | "language_info": {
519 | "codemirror_mode": {
520 | "name": "ipython",
521 | "version": 3
522 | },
523 | "file_extension": ".py",
524 | "mimetype": "text/x-python",
525 | "name": "python",
526 | "nbconvert_exporter": "python",
527 | "pygments_lexer": "ipython3",
528 | "version": "3.6.4"
529 | }
530 | },
531 | "nbformat": 4,
532 | "nbformat_minor": 2
533 | }
534 |
--------------------------------------------------------------------------------