generated from ajamj/static-export-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ML_SL_Linear Regression ScikitLearn.jl
2588 lines (2090 loc) · 99.9 KB
/
ML_SL_Linear Regression ScikitLearn.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
### A Pluto.jl notebook ###
# v0.19.26
using Markdown
using InteractiveUtils
# ╔═╡ fc13b945-abc6-40b7-ba49-35b32d13a7b2
using Plots, PlutoUI, Images, DataFrames, Statistics, NamedArrays
# ╔═╡ f42ad2ad-9ee7-47ff-8e53-6b37dd68741c
using ScikitLearn
# ╔═╡ f72009f5-9b4d-49e0-9461-5676365ed5eb
using RDatasets
# ╔═╡ ac47a770-f596-11ed-2044-7f241fac7297
md"""
# Pendahuluan
!!! catatan
Modul ini berisi tentang pengenalan machine learning dasar dengan model `Linear Regression` menggunakan paket `ScikitLearn.jl` dalam Julia. Materi yang tertulis di sini merupakan hasil terjemahan dan penyesuaian dari modul [Data Science](https://www.sololearn.com/learning/1093) dengan Python di [Sololearn](https://sololearn.com). Proses penerjemahan dan penyesuaian kode dari Python ke Julia dibantu oleh [ChatGPT](https://chat.openai.com/).
## Apa itu Machine Learning?
Nah, Machine Learning itu sebenernya bagian kecil dari data science yang lagi ngetrend banget, guys. Jadi, intinya Machine Learning tuh tentang cara ilmiah yang ngoprek algoritma komputasi dan model statistik buat ngelakuin tugas-tugas tertentu berdasarkan pola dan inferensi, bukan dari instruksi jelas. Jadi, kayak punya alat-alat khusus buat bikin model dari data. Para ilmuwan data tuh tuh kece abis, mereka eksplorasi data, pilih-pilih, dan bikin model (machine), trus sesuaiin parameter biar modelnya cocok dengan pengamatan (learning), abis itu dipake buat nebak dan ngertiin hal-hal baru dari data yang belum pernah diliat sebelumnya.
Jadi, Machine Learning itu sebenernya kumpulan alat yang digunain buat bangun model dari data. Bangun model buat ngertiin data dan nebak-nebak itu jadi bagian penting dari kerjaan para ilmuwan data yang keren abis.
"""
# ╔═╡ c11dbd97-7f3a-405d-ab24-ae569f43a17f
md"""
## Supervised dan Unsupervised Learning
Dalam Machine Learning, ada yang namanya "supervised" dan "unsupervised learning". Supervised learning itu ketika kita punya target yang udah diketahui (disebut juga label) berdasarkan data-data masa lalu (misalnya, prediksi harga jual sebuah rumah), sedangkan unsupervised learning itu ketika gak ada jawaban masa lalu yang diketahui (misalnya, menentukan topik-topik yang dibahas dalam ulasan restoran).
Di modul ini, kita bakal bahas tentang Linear Regression (Regresi Linier), salah satu algoritme dalam supervised machine learning. Di modul-modul berikutnya, kita juga bakal bahas algoritme supervised machine learning lainnya, yaitu classification, dan juga algoritme unsupervised machine learning, yaitu clustering.
"""
# ╔═╡ 4b816ac2-9e46-42b2-ae8e-0c2867df76f2
md"""
## Scikit-learn
Bro and Sis!, di modul ini kita bakal pake Scikit-learn, salah satu library machine learning terkenal di Python. Di sini, banyak banget algoritma yang udah siap pakai. Gak peduli jenis algoritmanya apa, syntax-nya mengikuti langkah yang sama: **import > instantiate > fit > predict**. Setelah lo paham dasar penggunaan dan syntax Scikit-learn untuk satu model, gampang banget beralih ke algoritma baru. Jadi, buat sisanya kursus ini, kita bakal pake Scikit-learn buat bikin model machine learning dalam berbagai kasus penggunaan.
Di modul ini, kita bakal belajar cara prediksi harga rumah di Boston, USA pake linear regression.
"""
# ╔═╡ 20a764db-863b-46d9-b6d3-bd9baa002fb6
md"""
## Linear Regression
Kita mulai dengan linear regression, model supervised learning yang sederhana abis. Linear regression ini pasangin garis lurus ke data, secara matematika kayak gini:
* $y = b + mx$
di mana $b$ itu intercept-nya dan $m$ itu kemiringan garisnya, $x$ itu fitur atau input-nya, sementara $y$ itu label atau output-nya. Tugas kita adalah nemuin nilai $m$ dan $b$ yang bikin kesalahan sekecil-kecilnya. Jadi, kita cari $m$ dan $b$ yang pas banget biar error-nya minim.
"""
# ╔═╡ 63103494-3b91-4457-a3e1-2f44bb09de24
load(download("https://api.sololearn.com/DownloadFile?id=3808"))
# ╔═╡ 766a54d9-3fc4-4cdd-b64c-4d6e654a7cb0
load(download("https://api.sololearn.com/DownloadFile?id=3809"))
# ╔═╡ 1ca23bcd-e476-4bbf-92de-33d9d37eb6f6
md"""
Nih, buat bikin gambaran, kita mulai dari lima titik data nih, bro/sis. Titik pertama (1.5, 2.8), titik kedua (2, 5.3), titik ketiga (2.5, 5.5), titik keempat (3, 7), dan titik kelima (3.5, 8.8).
"""
# ╔═╡ dc403f5a-8cb0-4755-9dfb-072e02a7d083
load(download("https://api.sololearn.com/DownloadFile?id=3901"))
# ╔═╡ d9c287dd-3eb8-43d6-808a-fe655f41e924
md"""
Kita mau pasang garis lurus buat ngelewatin kelima titik data ini, tapi, meskipun kita lihat dengan mata telanjang, ga ada garis lurus yang bisa ngelewatin semua lima titik ini, jadi kita usahain yang terbaik deh. Ini artinya, kita bakal cari garis yang paling deket sama titik-titik datanya.
Dari tiga garis yang ditunjukkan di bawah ini, menurut pendapat lu, garis mana yang paling pas dengan datanya? Garis hijau y = 10 + (-2)X, garis biru y = 5.5 + 0X, atau garis merah y = 1 + 2*X?
"""
# ╔═╡ d2bcbe32-717b-4ad0-b581-e465bc5102e7
load(download("https://api.sololearn.com/DownloadFile?id=3902"))
# ╔═╡ e3a02941-3d83-4e82-a5ef-7794313d20c1
md"""
Garis merah kan, bro! Kenapa hayoo? Karena garis merah itu yang paling nyangkutin hubungan linear antara X dan y, dan juga paling deket sama titik-titiknya. Secara matematis, jarak antara garis yang dipasang dengan titik-titik datanya dihitung pake yang namanya residu, yang ditandai dengan garis hitam putus-putus vertikal di gambar di bawah ini:
"""
# ╔═╡ fdebdfa1-3cf5-46f9-82b4-77f4e2be70c9
load(download("https://api.sololearn.com/DownloadFile?id=3903"))
# ╔═╡ 17093bef-b292-42be-866a-1080314b293c
md"""
Nah, jadi garis merah itu yang punya residu paling kecil, alias paling deket sama titik-titik datanya. Makanya garis merah adalah yang paling pas dengan datanya, bro!
Jadi, intinya linear regression itu pada dasarnya adalah mencari garis yang meminimalkan jumlah residu kuadrat, nanti kita bahas lebih lanjut, bro!
Dalam linear regression, tujuannya adalah mencari garis yang bisa mengestimasi atau memprediksi hubungan linear antara dua variabel. Nah, salah satu cara untuk menentukan garis yang paling cocok adalah dengan meminimalkan jumlah residu kuadrat antara garis tersebut dengan titik-titik data yang ada.
Residu sendiri itu adalah selisih antara nilai sebenarnya (y) dengan nilai yang diprediksi oleh garis (y') untuk setiap titik data. Nah, buat ngukur sejauh mana garis kita nyangkutin data, kita bisa kuadratin residu ini, jadi semuanya positif dan jaraknya lebih jelas.
Jadi, dalam linear regression, kita cari garis yang menghasilkan jumlah residu kuadrat yang paling kecil, yang artinya garis itu paling mendekati titik-titik data secara keseluruhan.
Model regresi linear populer karena mereka dapat melakukan fitting dengan cepat dan mudah diinterpretasikan. Memprediksi nilai kontinu dengan regresi linear adalah titik awal yang bagus, bro/sis!
Salah satu keunggulan dari regresi linear adalah kemampuannya untuk dengan cepat menyesuaikan model dengan data dan memberikan hasil yang mudah dipahami. Dengan regresi linear, kita dapat melakukan prediksi terhadap nilai kontinu berdasarkan hubungan linear antara variabel-variabel yang ada.
Gimana, mantap kan? Regresi linear ini jadi pilihan yang bagus buat memulai memprediksi nilai-nilai kontinu, bro/sis!
"""
# ╔═╡ fe02d821-9cee-42ac-bdf0-f94e517b6313
md"""
# Exploratory Data Analysis
## Boston Housing Dataset
Dataset yang kita pake adalah Boston housing dataset, bro/sis. Dataset ini berisi nilai median rumah di berbagai daerah di sekitar Boston. Selain nilai median rumah dalam ribuan dolar (MEDV), juga ada data tentang tingkat kejahatan (CRIM), konsentrasi nitrogen dioksida (NOX), jumlah rata-rata kamar (RM), persentase status sosial rendah dari populasi (LSTAT), dan fitur-fitur lainnya.
Tujuan kita di sini adalah memprediksi harga median rumah (MEDV), yang jadi target dalam skenario ini, menggunakan beberapa fitur yang disediakan.
"""
# ╔═╡ 032ca44c-e9b9-4119-b632-2f4143c3768a
md"""
Sebelum kita load datasetnya, pastikan dulu kalo package-nya udah diinstal, ya!
Di terminal Julia, masukkan perintah:
> using Pkg\
> Pkg.add("RDatasets")
"""
# ╔═╡ 228425b5-a9bf-4ca8-8202-1c3a2f0576c9
md"""
Boston housing dataset udah disiapin di package RDatasets dan kita bakal pake fungsi `RDatasets.datasets()` untuk ngeload objek yang berisi semua informasi yang kita butuhin
"""
# ╔═╡ 1a799c68-d080-4f48-8f31-1877e131c070
boston = dataset("MASS", "Boston")
# ╔═╡ adc558ef-8b28-425b-be44-d87c100ff983
md"""
Keterangan Data:
- CRIM - per capita crime rate by town
- ZN - proportion of residential land zoned for lots over 25,000 sq.ft.
- INDUS - proportion of non-retail business acres per town.
- CHAS - Charles River dummy variable (1 if tract bounds river; 0 otherwise)
- NOX - nitric oxides concentration (parts per 10 million)
- RM - average number of rooms per dwelling
- AGE - proportion of owner-occupied units built prior to 1940
- DIS - weighted distances to five Boston employment centres
- RAD - index of accessibility to radial highways
- TAX - full-value property-tax rate per $10,000
- PTRATIO - pupil-teacher ratio by town
- BLACK - 1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town
- LSTAT - % lower status of the population
- MEDV - Median value of owner-occupied homes in $1000's
"""
# ╔═╡ 0341a92c-0372-4272-8f4e-d12334c90a0e
md"""
Kita jadikan kolom MedV sebagai target.
"""
# ╔═╡ a9b4c35c-bd72-4f4e-ad3b-0cfb947b5c05
boston_target = boston[!,:MedV] # Menetapkan kolom 'MEDV' sebagai variabel target
# ╔═╡ 879120e2-3b91-4720-928b-5ff6113ad691
md"""
Kita bisa ngecek berapa banyak baris dan kolom dari data tersebut dengan perintah berikut:
"""
# ╔═╡ 87269da1-c826-4546-8d44-0ee2a146bcb6
size(boston)
# ╔═╡ 2b134f85-29b5-4ed2-88b3-903b77252467
md"""
Yow, ini berguna banget buat cek-cek apakah DataFrame-nya udah berisi data yang tepat, nih. Biar kita bisa lihat beberapa baris pertama dari DataFrame, kita pake `first(boston, n)`, di mana lo bisa tentuin nilai n buat jumlah baris yang mau dipilih. Kalo n ga diisi, secara default, dia bakal pilih baris pertama.
Coba lo bayangin, kita punya DataFrame namanya boston, nah kita bisa pake first() ini buat lihat beberapa baris pertama dari DataFrame tersebut. Kalo lo mau pilih berapa banyak baris yang mau ditampilin, tinggal lo tentuin nilai n di argumen first(n). Kalo n ga diisi, secara otomatis dia pilih satu baris pertama.
"""
# ╔═╡ b1613e37-8ef0-4cdd-89b2-61e4166af51d
first(boston,5)
# ╔═╡ 6e5b6008-b550-4303-97d8-c09269f33425
md"""
Kalo cuma mau nampilin kolom tertentu aja, bisa pake perintah:
"""
# ╔═╡ 5469aa3f-bdbe-4b84-be9f-d85c030c12c5
first(boston[:, [:Chas, :Rm, :Age, :Rad, :MedV]], 5)
# ╔═╡ 2e75eac5-3b55-4b8d-a90a-2889f6a230b9
md"""
Seringkali dataset di-load dari format file lainnya (misalnya csv, teks), dan ini adalah praktik yang bagus untuk ngecek beberapa baris pertama dan terakhir dari DataFrame serta memastikan data-nya dalam format yang konsisten menggunakan fungsi `first` dan `last`, bro.
Misalnya, kita udah ngeload dataset dari format file tertentu jadi DataFrame, kita bisa pake `first` buat lihat beberapa baris pertama dari DataFrame dan memastikan formatnya konsisten. Selain itu, kita juga bisa pake `last` buat lihat beberapa baris terakhir dan memastikan data di situ juga dalam format yang diharapkan.
Contohnya:
```julia
# Melihat beberapa baris pertama dari DataFrame
first(boston)
# Melihat beberapa baris terakhir dari DataFrame
last(boston)
```
Dengan pake `first` dan `last`, kita bisa dengan gampang cek beberapa baris pertama dan terakhir dari DataFrame buat memastikan data kita dalam format yang konsisten sebelum dilakukan analisis lebih lanjut, bro!
"""
# ╔═╡ eaf357b4-721e-461f-873e-9c03f5499a2e
last(boston)
# ╔═╡ 69123bf3-ece3-4cd1-a826-fe361e2f8798
md"""
## Ringkasan Statistika
Ingat, bro, kalo mencetak seluruh dataset dengan ukuran sampel yang besar itu gak praktis. Sebaliknya, kita pengen merangkum dan mengkarakterisasi data sampel dengan hanya beberapa nilai saja. Buat ngecek statistik ringkasan dari dataset, kita bisa pake:
```julia
# Menghitung statistik ringkasan dari dataset
describe(boston)
```
Dengan menggunakan `describe`, kita bisa dapetin statistik ringkasan dari dataset, termasuk jumlah observasi, rata-rata, standar deviasi, nilai minimum dan maksimum, serta kuartil-kuartilnya.
"""
# ╔═╡ 4fceacfc-f711-469a-9833-c7788f461a3b
describe(boston, :detailed)
# ╔═╡ 33985122-edd4-4215-8020-827c0aa3a37c
md"""
CHAS yang bernilai biner memiliki rata-rata 0.07, dan kuartil ketiga-nya adalah 0. Ini menunjukkan bahwa sebagian besar nilai di CHAS adalah 0. Jumlah rata-rata kamar per hunian berkisar antara 3.56 hingga 8.78, dengan rata-rata 6.28 dan median 6.21. Distribusi RM terlihat simetris.
Jika DataFrame berisi lebih dari hanya nilai numerik, secara default, `describe()` akan menghasilkan statistik deskriptif untuk kolom-kolom numerik. Untuk menampilkan statistik ringkasan dari semua kolom, kita bisa menambahkan `:all` dalam method-nya.
Contoh penggunaan:
```julia
# Menampilkan statistik ringkasan untuk semua kolom
describe(boston, :all)
```
Dengan menggunakan `:all`, kita dapat melihat statistik ringkasan untuk semua kolom dalam DataFrame, termasuk kolom non-numerik.
"""
# ╔═╡ 64708a63-1009-44b1-980d-d84ca9c6bcf6
# Menampilkan statistik ringkasan untuk semua kolom
describe(boston, :all)
# ╔═╡ 69e9a67d-2d81-4e17-a649-ded73d0757ff
md"""
## Visualisasi
Buanyak banget manfaat yang kita dapat dari visualisasi dan periksa distribusi tiap kolom, bro. Biar lebih jelas, kita bisa pake plot yang berbeda-beda, kayak histogram, box plot, atau scatter plot, tergantung karakteristik datanya.
Misalnya, buat lihat distribusi CHAS, kita bisa pake histogram atau bar plot buat lihat sebaran nilai 0 dan 1, bro.
"""
# ╔═╡ 66754cae-9c41-440f-bdfd-1ea16096f021
# Nampilin distribusi CHAS pake histogram
histogram(boston.Chas, legend = false, xlabel = "CHAS", ylabel = "Frequency")
# ╔═╡ 834d295f-d7a6-462c-961c-6526dad98ebb
md"""
CHAS cuma ada dua nilai, yaitu 0 dan 1, dengan sebagian besar nilainya 0. Ini konsisten dengan apa yang dilaporkan oleh `describe()`, khususnya, kuartil ketiga dari CHAS adalah 0.
Kalo buat liat distribusi RM, kita juga bisa pake histogram buat liat sebaran nilai rata-rata jumlah kamar per hunian, bro.
"""
# ╔═╡ 90f0f3fb-d19d-44fa-9acb-5492579c3b14
# Nampilin distribusi RM pake histogram
histogram(boston.Rm, legend = false, xlabel = "RM", ylabel = "Frequency")
# ╔═╡ c89696b0-942c-431a-8dd9-7e9b5791d55c
md"""
Distribusi RM terlihat normal dan simetris. Simetri ini sejalan dengan apa yang kita amati dari output `describe()`, karena rata-rata RM 6.28 mendekati median 6.21.
Visualisasi data yang informatif tidak hanya mengungkap wawasan, tetapi juga sangat berharga untuk mengkomunikasikan temuan kepada pemangku kepentingan.
Dengan cara visualisasinya ini, kita bisa ngecek distribusi CHAS dan RM dengan lebih jelas dan memverifikasi kesimpulan yang udah kita buat sebelumnya, bro.
"""
# ╔═╡ 028580e4-37a6-4c09-807a-ce5b0c9ead3d
md"""
## Correlation Matrix
Nah, buat ngertiin hubungan antara fitur-fitur (kolom-kolom), matriks korelasi itu penting banget dalam analisis data awal. Korelasi itu mengukur hubungan linear antara variabel-variabel, bro. Kita bisa bikin matriks korelasi buat nunjukin koefisien korelasi antara variabel-variabel itu. Matriks korelasi itu simetris, setiap elemennya itu koefisien korelasi yang nilainya antara -1 dan 1. Kalo nilai-nya deket banget sama 1 (atau -1), itu berarti ada korelasi positif yang kuat (atau negatif) antara variabel-variabel tersebut, bro. Buat bikin matriks korelasi, kita bisa pake fungsi "corr" ini:
```julia
correlation_matrix = round.(cor(Matrix(boston)), digits=2)
```
Dengan pake fungsi "cor" ini, kita bisa bikin matriks korelasi dan liat gimana hubungan antara variabel-variabel dalam dataset kita, bro.
"""
# ╔═╡ 1da7e318-472f-4ebe-8f45-5fd4b8568664
# Bikin matriks korelasi
correlation_matrix = round.(cor(Matrix(boston)), digits=2)
# ╔═╡ a13128b2-7895-4527-9558-a9c790a49d7c
md"""
Versi dengan nama kolom:
"""
# ╔═╡ c4b9acdd-1184-4897-91e1-e08d7f8f74dc
NamedArray(cor(Matrix(boston)), (names(boston), names(boston)))
# ╔═╡ f4eb55c0-00e1-422d-ba70-18e3c6d6edd8
md"""
Nah, yang paling terakhir itu baris atau kolom yang dipake buat nyari fitur yang paling nyambung sama target MEDV (harga rumah median dalam ribuan dolar). LSTAT (persentase orang dengan status rendah) adalah yang paling negatif nyambung sama target (-0.74), artinya kalo persentase orang dengan status rendah turun, harga rumah median naik; sementara RM (jumlah rata-rata kamar per hunian) adalah yang paling positif nyambung sama MEDV (0.70), artinya harga rumah naik kalo jumlah kamarnya bertambah.
"""
# ╔═╡ a7fcac44-3030-4f78-8d5c-46627f1f83a8
md"""
Ngertiin data lewat analisis data eksploratori itu langkah penting sebelum bikin model, bro. Dari ukuran sampel dan distribusinya sampe korelasi antara fitur-fitur dan target, kita dapet pemahaman lebih di setiap langkah yang bantu kita pilih fitur-fitur dan algoritma yang pas.
"""
# ╔═╡ 38d3d8b9-26e5-42ad-9fcb-ef3856fe579c
md"""
## Data Preparation - Feature Selection
Di atas udah kita bahas, kita perhatikan bahwa RM dan MEDV memiliki korelasi positif. Ingat ya, scatter plot itu alat yang berguna buat nampilin hubungan antara dua fitur; yuk, kita liat scatter plot-nya:
"""
# ╔═╡ 9596b6e8-03a7-4fea-94a2-d49cf0c2fb96
scatter(boston.Rm, boston.MedV, xlabel="RM (Room Mean - Rerata Jumlah Ruangan per Rumah)", ylabel="MEDV (Median Value - Nilai Tengah Harga Rumah", legend=false, title="Scatter Plot", size=(800, 600))
# ╔═╡ c48d27b4-604d-45b5-8f97-9146aafadabb
md"""
Harga rumah naik seiring dengan bertambahnya nilai RM secara linear. Tapi ada beberapa outliers yang kelihatan di luar pola secara keseluruhan. Misalnya, satu titik di tengah kanan itu menunjuukan rumah dengan hampir 9 kamar tapi nilai median sedikit di atas $20K. Biasanya, rumah-rumah dengan nilai serupa punya sekitar 6 kamar. Selain itu, data ini tampaknya ada batas maksimum; nilai median maksimumnya terbatas di 50.
Di sisi lain, harga cenderung turun dengan peningkatan LSTAT (% lower status of the population); dan trennya gak se-linear itu.
"""
# ╔═╡ 9f93425c-867a-447f-b6f9-285eaa18ee49
scatter(boston.LStat, boston.MedV, xlabel="LSTAT", ylabel="MEDV", legend=false, title="Scatter Plot", size=(800, 600))
# ╔═╡ f93f2e5a-4362-4d32-b51e-6138585df368
md"""
Dari dua fitur itu, RM keliatan lebih oke buat nebak MEDV. Jadi kita mulai aja sama regresi linear univariat: MEDV = b + m * RM.
Di scikit-learn, model-modelnya butuh matriks fitur dua dimensi (X, 2darray atau DataFrame pandas) sama array target satu dimensi (Y).
Di sini kita tentuin matriks fitur sebagai kolom RM dalam boston dan kita kasih nama X.
"""
# ╔═╡ c576c594-985b-4e5b-97ca-ed8d3a913d55
X = reshape(convert(Array, boston.Rm), (506, 1))
# ╔═╡ ef63b9a1-ab98-41f1-a5a5-dc82c0ca59b6
size(X)
# ╔═╡ 957663d1-b79d-4069-9201-49854c5c9399
md"""
Nah, dengan bikin matriks fitur kaya gitu, kita udah siap buat lanjutin regresi linear univariatnya, bro.
"""
# ╔═╡ ba95503e-c2fb-4df2-9dd4-c50391fc1c9e
md"""
Buat variabel baru dengan isi kolom MedV yang akan dijadikan sebagai target.
"""
# ╔═╡ 6926f834-fe32-4140-853d-8363a6ee8449
y = boston.MedV
# ╔═╡ 2a5cccaa-59a3-4e89-b5bd-7cca2dfa5445
begin
# Import the required package
using ScikitLearn.CrossValidation
# Splitting the data into training and testing sets
X_train, X_test, Y_train, Y_test = train_test_split(X, y, test_size=0.3, random_state=42)
end
# ╔═╡ a1e8edd3-1ffe-479b-a589-aacb1ca79281
size(y)
# ╔═╡ 9014e76e-437c-4260-b50a-2db747c7fcdb
md"""
## Fitting a Univariate Linear Regression
Jadi, dalam scikit-learn, setiap kelas model itu direpresentasikan oleh sebuah kelas dalam Python. Kelas model itu beda banget sama objek modelnya, bro. Nah, kita mulai dengan mengimpor kelas regresi linear, terus bikin objek modelnya dengan cara bikin sebuah instansi dari kelas LinearRegression:
```julia
# Impor kelas regresi linear
using ScikitLearn
@sk_import linear_model: LinearRegression
# Bikin objek model
model = LinearRegression()
```
Dengan kode di atas, kita mengimpor kelas LinearRegression dari modul linear_model di ScikitLearn dan bikin objek modelnya dengan cara bikin sebuah instansi dari kelas LinearRegression.
"""
# ╔═╡ e750e5dc-a7bc-4371-9c1e-1f053b0d4e50
@sk_import linear_model: LinearRegression
# ╔═╡ 59373c9f-52f4-46d1-9441-c35ca1ddf6cd
# Bikin objek model
model = LinearRegression()
# ╔═╡ 4fd490db-63f4-4842-a36e-bf606b1ff524
md"""
Sekarang modelnya udah dibuat, tapi belum diaplikasikan ke data. Scikit-learn membedakan antara pemilihan model dan pengaplikasian model ke data dengan sangat jelas, bro.
"""
# ╔═╡ f84f57fd-efa0-485b-a712-60be2f77e6ff
md"""
Sekarang kita bagi data menjadi set pelatihan (training set) dan set pengujian (testing set). Kenapa? Supaya kita bisa mengevaluasi performa model pada data yang belum pernah dilihat sebelumnya. Kita melatih model menggunakan set pelatihan, dan menyimpan set pengujian untuk evaluasi.
Aturan praktis yang bagus adalah membagi data menjadi 70-30, artinya 70% data digunakan untuk pelatihan dan 30% untuk pengujian. Kita akan menggunakan fungsi train_test_split dari paket ScikitLearn untuk membagi data menjadi dua subset secara acak. Kita juga akan mengatur random_state agar hasilnya dapat direproduksi.
Dengan kode di atas, kita menggunakan fungsi `train_test_split` dari paket ScikitLearn untuk membagi fitur dan target menjadi set pelatihan dan set pengujian. Kita menggunakan fitur RM sebagai `X` dan target MEDV sebagai `y`. Kemudian kita membagi data dengan memilih ukuran set pengujian sebesar 30% menggunakan `test_size=0.3` dan mengatur `random_state` menjadi 42 agar hasilnya dapat direproduksi.
"""
# ╔═╡ 59acc995-91f4-424d-8381-3a2bb1b9ca87
size(X_train)
# ╔═╡ 43a31297-dafe-402d-98cf-68723d70eb72
size(X_test)
# ╔═╡ 56a1298a-241b-4bfd-92cf-cd7adc337b43
size(Y_train)
# ╔═╡ 6a772572-95c8-48c2-b184-c1fed7e0b34b
typeof(Y_train)
# ╔═╡ 52e987c0-81fd-45a5-8e1c-7945ccb54997
size(Y_test)
# ╔═╡ e39eccf4-7c75-4647-92b8-d7f15f8918b6
md"""
## Fitting the Model
Yoi, jadi fitting itu sama aja kayak training. Proses ini melibatkan melatih model menggunakan data training dan menemukan koefisien yang ditentukan dalam model regresi linear, yaitu intercept dan slope. Setelah dilatih, model bisa digunakan untuk melakukan prediksi.
Sekarang kita akan mengaplikasikan model ke data. Ingat ya, kita simpan data testing untuk melihat performa model dan hanya menggunakan data training untuk membangun model. Ini sintaksnya:
"""
# ╔═╡ 14ee429e-2c57-4ac4-877f-95506b08af13
# Fitting/training the model
fit!(model, X_train, Y_train)
# ╔═╡ 9614cd5d-1f61-4def-8e09-5d6945b7f888
md"""
Perintah fit!() memicu komputasi dan hasilnya disimpan dalam objek model.
Proses fitting adalah seberapa baik model machine learning cocok dengan data yang digunakan untuk melatihnya. Dengan melatih model menggunakan data tersebut, model belajar menyesuaikan diri dengan pola dan hubungan dalam data tersebut.
"""
# ╔═╡ 278d7a0b-0f1f-4958-b5ab-a9c6146128b2
md"""
## Parameter Estimates
Bro, jadi model regresi linear udah di-fitin, artinya kedua parameter, yaitu intercept dan slope, udah dipelajari. Nah, di Scikit-learn, konvensinya semua parameter model punya trailing underscores, misalnya buat ngakses nilai estimasi intercept dari model, dibulatin ke 2 desimal angka di belakang koma biar lebih enak dilihat, kita bisa pake kode berikut:
"""
# ╔═╡ 8d000943-f1d1-4e2c-b7cc-9af25ac4b553
intercept = round(model.intercept_, digits=2)
# ╔═╡ b216e132-ed19-44fa-b966-5d2081e4c534
md"""
Sama juga untuk memperkirakan nilai coefficient dari `Rm`:
"""
# ╔═╡ 34fe2a25-0b84-46b3-9bf7-979036dbc4d3
coef = round(model.coef_[1], digits=2)
# ╔═╡ 47edcba4-4904-4bfa-9182-4cfd7495b327
md"""
Dua parameter tersebut mewakili intercept dan slope dari garis yang cocok dengan data. Model yang telah kita fitkan memiliki persamaan
* $MedV = -34.66 + 9.12 * Rm$
Untuk setiap peningkatan satu unit pada Rm, harga rumah median akan meningkat sebesar \$9120.
"""
# ╔═╡ 5735b6c1-61ea-4ece-b957-96a69502ff54
md"""
## Prediction
Setelah model dilatih, supervised machine learning akan mengevaluasi data uji berdasarkan prediksi sebelumnya untuk data yang tidak terlihat sebelumnya. Kita dapat membuat prediksi menggunakan metode predict().
"""
# ╔═╡ 392261c3-290b-47c3-8504-9a1a70861e51
new_RM = [[6.5]] # 2d array
# ╔═╡ 92ff3f53-6e51-4593-bf50-fe42a77dc072
prediction = predict(model, new_RM)
# ╔═╡ 3b2b5553-878f-4941-9046-b5b652e78342
md"""
Ketika jumlah rata-rata kamar per hunian adalah 6.5, model memprediksi nilai rumah sebesar $24,605.4.
Perlu dicatat bahwa input harus berupa 2 dimensi, baik itu 2darray atau DataFrame akan berfungsi dalam kasus ini.
Nilai ini sama dengan saat kita memasukkan nilai ke dalam persamaan `b + m*x` di mana `b` adalah intercept yang diestimasi dari model, dan `m` adalah slope yang diestimasi.
"""
# ╔═╡ 636bdcbb-33dd-4b10-8940-4fb417c0eefb
intercept + coef*6.5 # Nah, looh, kok beda...?
# ╔═╡ 57fed991-3bfe-460b-9540-9e6fa3f43396
y_test_predicted = predict(model, X_test)
# ╔═╡ cd380bc1-4c00-4f75-994e-3b2fc3bf61c2
size(y_test_predicted)
# ╔═╡ 01e66068-00bb-4ea1-b08b-d100d7dca6f6
size(Y_test)
# ╔═╡ d54e30f4-66b2-4ac0-a35c-e118602b985b
typeof(y_test_predicted)
# ╔═╡ 5741f048-d756-4582-ba1e-8667468f4a27
md"""
# Evaluating The Model
## Residuals
Kita mau ngecek seberapa bagus prediksi kita, nih. Kita bisa liat dari gambaran visual antara garis yang kita perkirakan dengan observasi yang sebenarnya dalam set data uji.
"""
# ╔═╡ 7e2c6e93-7c82-437f-a9ee-6fc66b436b7c
begin
scatter(X_test, Y_test, label="testing data")
plot!(X_test, y_test_predicted, label="prediction", linewidth=3)
xlabel!("RM")
ylabel!("MEDV")
end
# ╔═╡ 3586d834-fa0b-45f0-9666-f951d365e867
md"""
Nah, bisa kita lihat bahwa ada beberapa titik yang ada di sepanjang garis, tapi ada juga yang agak jauh dari garisnya. Kita bisa ukur jarak antara titik-titik tersebut ke garis dengan menggunakan garis vertikal, dan jarak ini disebut sebagai residual atau error. Residual adalah selisih antara nilai yang diamati dengan nilai yang diprediksi. Semakin kecil nilai residualnya mendekati 0, berarti model kita semakin baik.
Kita bisa menghitung residual dan menggambarkannya dalam scatter plot.
"""
# ╔═╡ b9df89e4-36c3-4cb8-9cfc-6db0fb7c9aa4
residuals = Y_test - y_test_predicted
# ╔═╡ 7947f77a-e2a8-4631-b00f-cdf1bf5e3473
begin
scatter(X_test, residuals, xlabel="RM", ylabel="residuals")
hline!([0], linestyle=:dash)
xlims!(4, 9)
end
# ╔═╡ 3f6c0a6a-61c5-4603-88ab-d8c396607e19
md"""
Residualnya tuh bertebaran nggak karuan di sekitar garis horizontal y = 0, nggak ada pola khusus. Distribusinya yang kelihatan acak menandakan modelnya oke banget. Sebenernya, idealnya residual itu harus tersebar simetris dan acak di sekitar sumbu horizontal; kalo plot residualnya nunjukin pola tertentu, baik yang linear atau non-linear, itu tandanya model kita masih bisa diperbaiki.
Plot residual ini bisa nunjukin kalo modelnya punya bias dan ukuran statistik bisa nunjukin seberapa bagus modelnya nge-fit data.
"""
# ╔═╡ bd4d151e-5bff-4e35-8a7e-62a2c8908a75
md"""
## Mean Squared Error
Sebelumnya, kita udah tau kalo kalo tiap-tiap residualnya mendekati 0 itu menandakan model yang bagus. Misalnya, untuk lima residual pertama dalam model kita:
"""
# ╔═╡ e39faef2-b5e4-4285-9f05-1d93597132ea
residuals[1:5]
# ╔═╡ 7d8c02d8-782a-48e1-ad7f-d309fecc1d78
md"""
Nah, itu hanya sejumlah titik data individual. Bagaimana dengan performa model untuk semua titik data? Kita butuh cara untuk menggabungkan semua residual dan melaporkan satu angka sebagai metriknya. Nah, biasanya kita menggunakan rata-rata dari semua residual:
"""
# ╔═╡ 86b3944f-db81-4d1d-85aa-0c12ac8c3174
mean(residuals)
# ╔═╡ 593531a2-5680-4297-9b2b-aea3c6c74b39
md"""
Iya, -0.36 memang cukup dekat dengan 0, tapi ada masalah: residual bisa positif atau negatif, jadi jika kita hanya mengambil rata-ratanya, maka akan saling menghapus satu sama lain. Itu bukan metrik yang akurat. Untuk mengatasinya, kita mengambil kuadrat dari masing-masing residual, kemudian mengambil rata-rata dari kuadrat-kuadrat tersebut. Ini disebut mean squared error (MSE):
"""
# ╔═╡ fc2f17f7-38d2-44e2-abd0-ab44a3ab58ad
mean(residuals.^2)
# ╔═╡ 45c741c7-e2f1-419c-a9da-12c3c65aa94e
md"""
Bisa juga pake fungsi mean_squared_error yang disediakan oleh ScikitLearn.
"""
# ╔═╡ a33eb768-41f3-48c7-af83-ff775b866f9e
@sk_import metrics: mean_squared_error
# ╔═╡ ca5d782f-2f09-4bf7-b892-d9e3ed09a3be
mse = mean_squared_error(Y_test, y_test_predicted)
# ╔═╡ dab50c21-43e3-4003-8ad8-dd3c9ab8a2eb
md"""
Secara umum, semakin kecil nilai MSE, semakin baik, namun tidak ada ambang batas yang mutlak untuk menentukan baik atau buruknya. Kita bisa mendefinisikannya berdasarkan variabel dependen, yaitu MEDV dalam data uji. Y_test berkisar antara 6.3 hingga 50 dengan varians 92.26. Dibandingkan dengan varians total, MSE sebesar 36.52 sudah tidak buruk.
Untuk membuat skala dari kesalahan sama dengan skala dari target, sering digunakan root mean squared error (RMSE). Ini adalah akar kuadrat dari MSE.
"""
# ╔═╡ 5af8cac9-0aeb-4a84-b088-ca9789173a98
md"""
## R-squared
Ada satu cara lagi buat ngecek kinerja model, yaitu pake R-squared. Cek nilai R-squarednya pake `model.score()`:
"""
# ╔═╡ 152d36fd-17a1-461c-a7ea-b84a13daab70
model.score(X_test, Y_test)
# ╔═╡ 044746c3-6b7b-482e-98aa-e4a812a19b86
md"""
R-squared itu nunjukin proporsi variasi total yang bisa dijelasin sama model. Di sini, sekitar 60% variasi di data pengujian bisa dijelasin sama model kita.
Variasi total diitung dari jumlah kuadrat selisih antara respons sama rata-ratanya, di contoh data pengujian:
"""
# ╔═╡ 399c968a-af6d-489e-9ee4-4f0846a5d432
sum((Y_test .- mean(Y_test)) .^ 2)
# ╔═╡ a6fcb8ed-2f05-41ee-b5b5-1087681b2c24
md"""
Terus variasi yang ga bisa dijelasin sama model diitung dari jumlah kuadrat residu:
"""
# ╔═╡ 02156f5e-3d32-40e7-b7e2-f9049e193497
sum(residuals .^ 2)
# ╔═╡ 8836d109-bc50-4505-8765-e1de70cc6e9c
md"""
Trus proporsi variasi total dari data diitung pake rumus:
"""
# ╔═╡ 2bcd900c-45b5-48d3-929e-e64eb6413696
1 - sum(residuals .^ 2) / sum((Y_test .- mean(Y_test)) .^ 2)
# ╔═╡ 39afe3a6-e99a-45e0-8bb6-07820fdd7944
md"""
Kalo modelnya sempurna, dia bisa jelasin semua variasi dalam data. Tapi inget, R-squarednya berada antara 0 dan 100%: 0% artinya modelnya ga jelasin variasi apa-apa di data respons sekitar rata-ratanya, sedangkan 100% artinya modelnya jelasin semua variasinya.
Evaluasi nilai R-squared ini barengan sama plot residu bisa nunjukin kinerja modelnya.
"""
# ╔═╡ 2cf82e63-a3c4-427a-bd2f-4b6f99d7079f
md"""
# Multivariate Linear Regression
## Overview
Lu inget ga, LSTAT (% status rendah di populasi) itu paling negatif korelasinya sama harga rumah. Kita bisa nambahin fitur ini dan bikin model regresi linear multivariat di mana harga rumah bergantung pada RM dan LSTAT secara linear:
* $MEDV = b0 + b1 * RM + b2 * LSTAT$
Buat nyari intercept b0, dan koefisien b1 dan b2, semua langkahnya sama kecuali bagian persiapan datanya, sekarang kita lagi urusin dua fitur:
"""
# ╔═╡ 20359032-5fd6-4e7a-8402-e2cee856af34
X2 = reshape(convert(Array, [boston.Rm boston.LStat]), (506, 2))
# ╔═╡ 54f77479-8eb0-496c-8a18-9330f05c698f
# Train-Test Split
X2_train, X2_test, Y2_train, Y2_test = train_test_split(X2, y, test_size=0.3, random_state=1)
# ╔═╡ 42322d7d-238b-48a0-9e60-d77304415012
model2 = LinearRegression()
# ╔═╡ f6249407-c163-4396-ae54-cda1e07aaf8d
# Fitting/training the model
fit!(model2, X2_train, Y2_train)
# ╔═╡ 4125f6d7-f926-4dde-adc3-3d4b79999f13
round(model2.intercept_, digits=2)
# ╔═╡ ea32a24b-656a-48bd-9346-c66b590bfa7d
round.(model2.coef_, digits=2)
# ╔═╡ 4bd19e01-61c4-4df6-9a62-e0030657b84f
md"""
Catet ya, koefisiennya disimpan dalam 1darray dengan bentuk (2,). Model kedua ini jadinya:
MEDV = 5.32 + 4.13 * RM + (-0.68) * LSTAT.
Nah, sekarang bisa dipake buat prediksi nih:
"""
# ╔═╡ 30b62ccc-577b-4584-8040-274495c02755
y_test_predicted2 = model2.predict(X2_test)
# ╔═╡ a5409e24-d891-44d2-a578-3e4718cf27be
md"""
Nah, ekstensi dari regresi linear univariat ke multivariat di scikit-learn memang cukup sederhana. Instansiasi model, proses fitting, dan prediksi sama persis, yang beda cuma persiapan datanya aja.
"""
# ╔═╡ d4cb55da-16b9-463a-843c-149ff001edc1
md"""
## Comparing Models
Manakah model yang lebih baik? Salah satu metrik yang umum digunakan untuk regresi linear adalah **mean squared error (MSE)** pada data pengujian. Model yang lebih baik memiliki MSE yang lebih rendah. Ingat ya, MSE dari model pertama pada data pengujian adalah:
"""
# ╔═╡ f4e9dc2c-ab44-481f-aeab-96fd86c15e2c
mean_squared_error(Y_test, y_test_predicted)
# ╔═╡ 5e930ec8-7784-415e-8425-5884f1f0b705
md"""MSE dari model kedua adalah:"""
# ╔═╡ 7f0d7eef-7d93-4794-a58f-9a4013d9719d
mean_squared_error(Y2_test, y_test_predicted2)
# ╔═╡ ba29b86f-aeb2-492f-ad78-d4a00ec4b6bb
md"""
Model kedua memiliki MSE yang lebih rendah, secara khusus mengalami penurunan sebesar 21% ((36.52-28.93)/36.52 = 21%); sehingga model tersebut lebih baik dalam memprediksi nilai rumah median dibandingkan dengan model univariat.
!!! warning
Secara umum, semakin banyak fitur yang dimasukkan ke dalam model, MSE akan semakin rendah. Namun, perlu berhati-hati dalam menyertakan terlalu banyak fitur. Beberapa fitur bisa saja hanya berupa noise acak, yang pada akhirnya akan merusak interpretabilitas model.
"""
# ╔═╡ d0a323e1-2b5c-41bf-9ca4-49bba2bc9156
md"""
## More Variate
"""
# ╔═╡ 14bca17f-921b-4f19-839a-8334ca634afc
X3 = reshape(convert(Array, [boston.Rm boston.LStat boston.Crim boston.Zn boston.Indus boston.Chas boston.NOx boston.Age boston.Dis boston.Rad boston.Tax boston.PTRatio boston.Black]), (506, 13))
# ╔═╡ 3227a0e3-e022-47e7-8ccb-6837c99e0aab
# Train-Test Split
X3_train, X3_test, Y3_train, Y3_test = train_test_split(X3, y, test_size=0.3, random_state=1)
# ╔═╡ 13b84ba3-7f1e-452c-8883-6d9ba71f60d6
model3 = LinearRegression()
# ╔═╡ 5d68092e-f665-496b-b28f-cf808bdbee2f
fit!(model3, X3_train, Y3_train)
# ╔═╡ 2f330afa-9596-401c-8ce8-1fd60ac87aa6
round(model3.intercept_, digits=2)
# ╔═╡ 557ffb3f-8371-4220-8243-5bd682075e40
round.(model3.coef_, digits=2)
# ╔═╡ 7f805c0e-fbf7-4221-b225-ab9439330b9e
y_test_predicted3 = model3.predict(X3_test)
# ╔═╡ 0562d4c6-22d7-49dd-9453-f270befba8b8
mean_squared_error(Y_test, y_test_predicted)
# ╔═╡ 6f08d98e-837e-42c1-9d46-f0a7765a388d
mean_squared_error(Y2_test, y_test_predicted2)
# ╔═╡ e2a47d3d-e3e3-4eec-b173-190136e15a4d
mean_squared_error(Y3_test, y_test_predicted3)
# ╔═╡ 537ee379-a38e-40f6-b4c1-4c3464898d27
md"""
Bisa dilihat bahwa saat kita menambahkan variasi (dalam kasus model 3 adalah semua kolom kecuali MedV), maka MSE-nya semakin kecil. Akan tetapi lebih baik jika ditinjau kembali variasi yang mesti dipilih.
"""
# ╔═╡ 491d22b7-35b3-47b8-933f-eafb0f8b3080
model.score(X_test, Y_test)
# ╔═╡ 11ddb12f-7081-4d14-93ab-6deeafdcd123
model2.score(X2_test, Y2_test)
# ╔═╡ 1f555f4d-59be-4450-a2a1-f03172e91b2f
model3.score(X3_test, Y3_test)
# ╔═╡ d5b5b98a-c379-4e47-8aeb-6d2e83691fe7
md"""
Model 3 juga memiliki score yang lebih tinggi. Semakin mendekati nilai 1, semakin tinggi akurasinya.
"""
# ╔═╡ dbcf484f-1cc8-4c1f-a20b-0b8a7a2a701e
md"""
# Appendix
"""
# ╔═╡ 0f32850b-9cba-48f3-b9f4-e72ab6b3a9ce
TableOfContents(title="📚 Table of Contents", indent=true, depth=4, aside=true)
# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
NamedArrays = "86f7a689-2022-50b4-a561-43c23ac3c673"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b"
ScikitLearn = "3646fa90-6ef7-5e7e-9f22-8aca16db6324"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
[compat]
DataFrames = "~1.5.0"
Images = "~0.25.2"
NamedArrays = "~0.9.8"
Plots = "~1.38.12"
PlutoUI = "~0.7.51"
RDatasets = "~0.7.7"
ScikitLearn = "~0.7.0"
"""
# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised
julia_version = "1.9.0"
manifest_format = "2.0"
project_hash = "6cb0df712984e2c760f6637c93a577b73ddea367"
[[deps.AbstractFFTs]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "16b6dbc4cf7caee4e1e75c49485ec67b667098a0"
uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c"
version = "1.3.1"
weakdeps = ["ChainRulesCore"]
[deps.AbstractFFTs.extensions]
AbstractFFTsChainRulesCoreExt = "ChainRulesCore"
[[deps.AbstractPlutoDingetjes]]
deps = ["Pkg"]
git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481"
uuid = "6e696c72-6542-2067-7265-42206c756150"
version = "1.1.4"
[[deps.Adapt]]
deps = ["LinearAlgebra", "Requires"]
git-tree-sha1 = "76289dc51920fdc6e0013c872ba9551d54961c24"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.6.2"
weakdeps = ["StaticArrays"]
[deps.Adapt.extensions]
AdaptStaticArraysExt = "StaticArrays"
[[deps.ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
version = "1.1.1"
[[deps.ArnoldiMethod]]
deps = ["LinearAlgebra", "Random", "StaticArrays"]
git-tree-sha1 = "62e51b39331de8911e4a7ff6f5aaf38a5f4cc0ae"
uuid = "ec485272-7323-5ecc-a04f-4719b315124d"
version = "0.2.0"
[[deps.Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
[[deps.AxisAlgorithms]]
deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"]
git-tree-sha1 = "66771c8d21c8ff5e3a93379480a2307ac36863f7"
uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950"
version = "1.0.1"
[[deps.AxisArrays]]
deps = ["Dates", "IntervalSets", "IterTools", "RangeArrays"]
git-tree-sha1 = "1dd4d9f5beebac0c03446918741b1a03dc5e5788"
uuid = "39de3d68-74b9-583c-8d2d-e117c070f3a9"
version = "0.4.6"
[[deps.Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
[[deps.BitFlags]]
git-tree-sha1 = "43b1a4a8f797c1cddadf60499a8a077d4af2cd2d"
uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35"
version = "0.1.7"
[[deps.Bzip2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2"
uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
version = "1.0.8+0"
[[deps.CEnum]]
git-tree-sha1 = "eb4cb44a499229b3b8426dcfb5dd85333951ff90"
uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
version = "0.4.2"
[[deps.CSV]]
deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "PrecompileTools", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings", "WorkerUtilities"]
git-tree-sha1 = "ed28c86cbde3dc3f53cf76643c2e9bc11d56acc7"
uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
version = "0.10.10"
[[deps.Cairo_jll]]
deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.1+1"
[[deps.CatIndices]]
deps = ["CustomUnitRanges", "OffsetArrays"]
git-tree-sha1 = "a0f80a09780eed9b1d106a1bf62041c2efc995bc"
uuid = "aafaddc9-749c-510e-ac4f-586e18779b91"
version = "0.2.2"
[[deps.CategoricalArrays]]
deps = ["DataAPI", "Future", "Missings", "Printf", "Requires", "Statistics", "Unicode"]
git-tree-sha1 = "1568b28f91293458345dabba6a5ea3f183250a61"
uuid = "324d7699-5711-5eae-9e2f-1d82baa6b597"
version = "0.10.8"
[deps.CategoricalArrays.extensions]
CategoricalArraysJSONExt = "JSON"
CategoricalArraysRecipesBaseExt = "RecipesBase"
CategoricalArraysSentinelArraysExt = "SentinelArrays"
CategoricalArraysStructTypesExt = "StructTypes"
[deps.CategoricalArrays.weakdeps]
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
SentinelArrays = "91c51154-3ec4-41a3-a24f-3f23e20d615c"
StructTypes = "856f2bd8-1eba-4b0a-8007-ebc267875bd4"
[[deps.ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "e30f2f4e20f7f186dc36529910beaedc60cfa644"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "1.16.0"
[[deps.Clustering]]
deps = ["Distances", "LinearAlgebra", "NearestNeighbors", "Printf", "Random", "SparseArrays", "Statistics", "StatsBase"]
git-tree-sha1 = "a6e6ce44a1e0a781772fc795fb7343b1925e9898"
uuid = "aaaa29a8-35af-508c-8bc3-b662a17a0fe5"
version = "0.15.2"
[[deps.CodecZlib]]
deps = ["TranscodingStreams", "Zlib_jll"]
git-tree-sha1 = "9c209fb7536406834aa938fb149964b985de6c83"
uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
version = "0.7.1"
[[deps.ColorSchemes]]
deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"]
git-tree-sha1 = "be6ab11021cd29f0344d5c4357b163af05a48cba"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.21.0"
[[deps.ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.4"
[[deps.ColorVectorSpace]]
deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"]
git-tree-sha1 = "600cc5508d66b78aae350f7accdb58763ac18589"
uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4"
version = "0.9.10"
[[deps.Colors]]
deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
git-tree-sha1 = "fc08e5930ee9a4e03f84bfb5211cb54e7769758a"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.12.10"
[[deps.Combinatorics]]
git-tree-sha1 = "08c8b6831dc00bfea825826be0bc8336fc369860"
uuid = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
version = "1.0.2"
[[deps.Compat]]
deps = ["UUIDs"]
git-tree-sha1 = "7a60c856b9fa189eb34f5f8a6f6b5529b7942957"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "4.6.1"
weakdeps = ["Dates", "LinearAlgebra"]
[deps.Compat.extensions]
CompatLinearAlgebraExt = "LinearAlgebra"
[[deps.CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
version = "1.0.2+0"
[[deps.ComputationalResources]]
git-tree-sha1 = "52cb3ec90e8a8bea0e62e275ba577ad0f74821f7"
uuid = "ed09eef8-17a6-5b46-8889-db040fac31e3"
version = "0.3.2"
[[deps.ConcurrentUtilities]]
deps = ["Serialization", "Sockets"]
git-tree-sha1 = "96d823b94ba8d187a6d8f0826e731195a74b90e9"
uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb"
version = "2.2.0"
[[deps.Conda]]
deps = ["Downloads", "JSON", "VersionParsing"]
git-tree-sha1 = "e32a90da027ca45d84678b826fffd3110bb3fc90"
uuid = "8f4d0f93-b110-5947-807f-2305c1781a2d"
version = "1.8.0"
[[deps.Contour]]
git-tree-sha1 = "d05d9e7b7aedff4e5b51a029dced05cfb6125781"
uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
version = "0.6.2"
[[deps.CoordinateTransformations]]
deps = ["LinearAlgebra", "StaticArrays"]
git-tree-sha1 = "f9d7112bfff8a19a3a4ea4e03a8e6a91fe8456bf"
uuid = "150eb455-5306-5404-9cee-2592286d6298"
version = "0.6.3"
[[deps.Crayons]]
git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15"
uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
version = "4.1.1"
[[deps.CustomUnitRanges]]
git-tree-sha1 = "1a3f97f907e6dd8983b744d2642651bb162a3f7a"
uuid = "dc8bdbbb-1ca9-579f-8c36-e416f6a65cce"
version = "1.0.2"
[[deps.DataAPI]]
git-tree-sha1 = "8da84edb865b0b5b0100c0666a9bc9a0b71c553c"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.15.0"
[[deps.DataFrames]]
deps = ["Compat", "DataAPI", "Future", "InlineStrings", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrettyTables", "Printf", "REPL", "Random", "Reexport", "SentinelArrays", "SnoopPrecompile", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"]
git-tree-sha1 = "aa51303df86f8626a962fccb878430cdb0a97eee"
uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
version = "1.5.0"
[[deps.DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "d1fff3a548102f48987a52a2e0d114fa97d730f0"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"