# Praktikum 4 (Opsional)

Pada percobaan ini, kita akan menggunakan nilai multinomial untuk melakukan klasifikasi dengan Naive Bayes. Nilai multinomial adalah data yang nilainya didapatkan dari proses menghitung. Sehingga, pada konteks fitur, nilai multinomial fitur berdasarkan proses perhitungan (counting) probabilitas kemunculan fitur tersebut dalam sebuah data. Contoh klasik fitur multinomial adalah perhitungan jumlah kata pada klasifikasi teks.Pada percobaan ini, kasus klasifikasi teks diberikan untuk mempermudah pemahaman terhadap algoritma Naive Bayes tipe Multinomial.

Kita akan menggunakan data `spam.csv` yang berisi data teks sms dengan label **spam** dan **ham**. Spam adalah sms sampah, sedangkan ham adalah sebaliknya

{% file src="/files/HSVlWkc4em2YzMoNsqPa" %}

## Load Data <a href="#load-data" id="load-data"></a>

Pada tahap ini kita akan *loading* data ke dalam data frame dan melakukan inspeksi sederhana untuk memastikan apakah kita perlu proses pra pengolahan data sebelum melakukan ekstraksi fitur dan permodelan

```
import numpy as np
import pandas as pd

df = pd.read_csv('spam.csv', encoding='latin-1') # spesifiksi encoding diperlukan karena data tidak menggunakan UTF-8

df.head()
```

|   | v1   | v2                                                | Unnamed: 2 | Unnamed: 3 | Unnamed: 4 |
| - | ---- | ------------------------------------------------- | ---------- | ---------- | ---------- |
| 0 | ham  | Go until jurong point, crazy.. Available only ... | NaN        | NaN        | NaN        |
| 1 | ham  | Ok lar... Joking wif u oni...                     | NaN        | NaN        | NaN        |
| 2 | spam | Free entry in 2 a wkly comp to win FA Cup fina... | NaN        | NaN        | NaN        |
| 3 | ham  | U dun say so early hor... U c already then say... | NaN        | NaN        | NaN        |
| 4 | ham  | Nah I don't think he goes to usf, he lives aro... | NaN        | NaN        | NaN        |

Terdapat 3 kolom yang tidak bermanfaat untuk proses selanjutnya, maka kita perlu membuang kolom tersebut. Selain itu, untuk memudahkan pembacaan data, kita juga akan mengubah nama kolom **v1** yang berupa label dan **v2** yang berupa teks sms

## Pra Pengolahan Data <a href="#pra-pengolahan-data" id="pra-pengolahan-data"></a>

Beberapa hal yang akan dilakukan pada tahap ini yaitu,

1. Drop kolom yang tidak digunakan
2. Ubah nama kolom v1 (label) dan v2 (teks sms)
3. Inspeksi Data
4. Encode label
5. Memisahkan fitur dengan label

### Drop Kolom <a href="#drop-kolom" id="drop-kolom"></a>

```
# Drop 3 kolom terakhir dengan fungsi iloc
df = df.drop(df.iloc[:,2:], axis=1)

# Cek data
df.head()
```

|   | v1   | v2                                                |
| - | ---- | ------------------------------------------------- |
| 0 | ham  | Go until jurong point, crazy.. Available only ... |
| 1 | ham  | Ok lar... Joking wif u oni...                     |
| 2 | spam | Free entry in 2 a wkly comp to win FA Cup fina... |
| 3 | ham  | U dun say so early hor... U c already then say... |
| 4 | ham  | Nah I don't think he goes to usf, he lives aro... |

### Ubah Nama Kolom V1 dan V2 <a href="#ubah-nama-kolom-v1-dan-v2" id="ubah-nama-kolom-v1-dan-v2"></a>

```
# Data untuk rename kolom v1 dan v2
new_cols = {
    'v1': 'Labels',
    'v2': 'SMS'
}

# Rename nama kolom v1 dan v2
df = df.rename(columns=new_cols)

# cek data
df.head()
```

|   | Labels | SMS                                               |
| - | ------ | ------------------------------------------------- |
| 0 | ham    | Go until jurong point, crazy.. Available only ... |
| 1 | ham    | Ok lar... Joking wif u oni...                     |
| 2 | spam   | Free entry in 2 a wkly comp to win FA Cup fina... |
| 3 | ham    | U dun say so early hor... U c already then say... |
| 4 | ham    | Nah I don't think he goes to usf, he lives aro... |

### Inspeksi Data <a href="#inspeksi-data" id="inspeksi-data"></a>

```
# Cek Jumlah Data Per Kelas
print(df['Labels'].value_counts())
print('\n')

# Cek Kelengkapan Data
print(df.info())
print('\n')

# Cek Statistik Deskriptif
print(df.describe())
```

```
ham     4825
spam     747
Name: Labels, dtype: int64


<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5572 entries, 0 to 5571
Data columns (total 2 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   Labels  5572 non-null   object
 1   SMS     5572 non-null   object
dtypes: object(2)
memory usage: 87.2+ KB
None


       Labels                     SMS
count    5572                    5572
unique      2                    5169
top       ham  Sorry, I'll call later
freq     4825                      30
```

### Encode Label <a href="#encode-label" id="encode-label"></a>

```
# Data untuk label
new_labels = {
    'spam': 1,
    'ham': 0
}

# Encode label
df['Labels'] = df['Labels'].map(new_labels)

# Cek data
df.head()
```

|   | Labels | SMS                                               |
| - | ------ | ------------------------------------------------- |
| 0 | 0      | Go until jurong point, crazy.. Available only ... |
| 1 | 0      | Ok lar... Joking wif u oni...                     |
| 2 | 1      | Free entry in 2 a wkly comp to win FA Cup fina... |
| 3 | 0      | U dun say so early hor... U c already then say... |
| 4 | 0      | Nah I don't think he goes to usf, he lives aro... |

#### Memisahkan Fitur dengan Label <a href="#memisahkan-fitur-dengan-label" id="memisahkan-fitur-dengan-label"></a>

```
X = df['SMS'].values
y = df['Labels'].values
```

## Ekstraksi fitur <a href="#ekstraksi-fitur" id="ekstraksi-fitur"></a>

Ekstraksi fitur untuk setiap SMS akan menggunakan konsep Bag of Words. Kita dapat menggunakan fungsi `CountVectorizer` dari scikit-learn. Akan tetapi untuk mencegah **leaking information** kita akan melakukan split data terlebih dahulu, baru melakukan transformasi terhadap data training dan testing.

```
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer

# Split data training dan testing
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=50)

# Inisiasi CountVectorizer
bow = CountVectorizer()

# Fitting dan transform X_train dengan CountVectorizer
X_train = bow.fit_transform(X_train)

# Transform X_test
# Mengapa hanya transform? Alasan yang sama dengan kasus pada percobaan ke-3
# Kita tidak menginginkan model mengetahui paramter yang digunakan oleh CountVectorizer untuk fitting data X_train
# Sehingga, data testing dapat tetap menjadi data yang asing bagi model nantinya
X_test = bow.transform(X_test)
```

```
print(len(bow.get_feature_names()))
print(f'Dimensi data: {X_train.shape}')
```

```
['00',
 '000',
 '000pes',
 '008704050406',
 '0089',
 '01223585334',
 '0125698789',
 '02',
 '0207',
 '02072069400',
 '02073162414',
 '021',
 '03',
 '04',
 '0430',
 '05',
 '050703',
 '0578',
 '06',
 '07',
 '07008009200',
 '07046744435',
 '07090201529',
 '07123456789',
 '0721072',
 '07732584351',
 '07734396839',
 '07742676969',
 '07753741225',
 '0776xxxxxxx',
 '07781482378',
 '07786200117',
 '077xxx',
 '07808',
 '07808247860',
 '07815296484',
 '07821230901',
 '07880867867',
 '0789xxxxxxx',
 '07946746291',
 '0796xxxxxx',
 '07973788240',
 '07xxxxxxxxx',
 '08',
 '0800',
 '08000407165',
 '08000776320',
 '08000839402',
 '08000930705',
 '08000938767',
 '08001950382',
 '08002888812',
 '08002986030',
 '08002986906',
 '08002988890',
 '08006344447',
 '0808',
 '08081263000',
 '08081560665',
 '0825',
 '083',
 '0844',
 '08448350055',
 '08448714184',
 '0845',
 '08452810071',
 '08452810073',
 '08452810075over18',
 '0870',
 '08700435505150p',
 '08701213186',
 '08701417012',
 '08701417012150p',
 '0870141701216',
 '087016248',
 '08701752560',
 '087018728737',
 '0870241182716',
 '08702490080',
 '08702840625',
 '08704050406',
 '08704439680',
 '08704439680ts',
 '08706091795',
 '0870737910216yrs',
 '08707500020',
 '08707509020',
 '08707808226',
 '08708034412',
 '08708800282',
 '08709222922',
 '0871',
 '087104711148',
 '08712101358',
 '08712103738',
 '0871212025016',
 '08712300220',
 '087123002209am',
 '08712317606',
 '08712400200',
 '08712400602450p',
 '08712402050',
 '08712402578',
 '08712402779',
 '08712402902',
 '08712404000',
 '08712405020',
 '08712405022',
 '08712460324',
 '08712466669',
 '0871277810810',
 '0871277810910p',
 '08714342399',
 '08714712379',
 '08714712388',
 '08714712394',
 '08714712412',
 '08714714011',
 '08715203028',
 '08715203649',
 '08715203652',
 '08715203656',
 '08715203677',
 '08715203685',
 '08715203694',
 '08715205273',
 '08715500022',
 '08715705022',
 '08717111821',
 '08717168528',
 '08717205546',
 '0871750',
 '08717509990',
 '08717898035',
 '08718711108',
 '08718720201',
 '08718723815',
 '08718725756',
 '08718726270',
 '087187262701',
 '08718726970',
 '08718726971',
 '08718726978',
 '087187272008',
 '08718727868',
 '08718727870',
 '08718727870150ppm',
 '08718730666',
 '08718738001',
 '08718738002',
 '08718738034',
 '08719180248',
 '08719181259',
 '08719181503',
 '08719181513',
 '08719839835',
 '08719899217',
 '08719899229',
 '09',
 '09050000301',
 '09050000332',
 '09050000460',
 '09050000555',
 '09050000878',
 '09050000928',
 '09050001808',
 '09050002311',
 '09050003091',
 '09050090044',
 '09050280520',
 '09053750005',
 '09056242159',
 '09057039994',
 '09058091854',
 '09058091870',
 '09058094454',
 '09058094455',
 '09058094507',
 '09058094565',
 '09058094583',
 '09058094594',
 '09058094597',
 '09058095107',
 '09058097189',
 '09058097218',
 '09058098002',
 '09058099801',
 '09061104276',
 '09061209465',
 '09061213237',
 '09061221061',
 '09061221066',
 '09061701444',
 '09061701461',
 '09061701851',
 '09061701939',
 '09061702893',
 '09061743386',
 '09061743806',
 '09061743810',
 '09061743811',
 '09061744553',
 '09061790121',
 '09061790125',
 '09063442151',
 '09063458130',
 '0906346330',
 '09064011000',
 '09064012160',
 '09064015307',
 '09064018838',
 '09064019014',
 '09064019788',
 '09065069154',
 '09065171142',
 '09065174042',
 '09065394973',
 '09065989180',
 '09065989182',
 '09066350750',
 '09066358152',
 '09066358361',
 '09066361921',
 '09066362206',
 '09066362231',
 '09066364311',
 '09066364349',
 '09066364589',
 '09066368327',
 '09066368470',
 '09066368753',
 '09066380611',
 '09066382422',
 '09066612661',
 '09066660100',
 '09071512432',
 '09071512433',
 '09071517866',
 '09077818151',
 '09094100151',
 '09094646631',
 '09095350301',
 '09099725823',
 '09099726481',
 '09099726553',
 '09701213186',
 '0quit',
 '10',
 '100',
 '1000',
 '1000call',
 '1000s',
 '100percent',
 '100txt',
 '1013',
 '1030',
 '10am',
 '10k',
 '10p',
 '10ppm',
 '10th',
 '11',
 '1120',
 '113',
 '1131',
 '114',
 '1172',
 '11mths',
 '11pm',
 '12',
 '1205',
 '120p',
 '121',
 '1225',
 '123',
 '125',
 '1250',
 '125gift',
 '128',
 '12hours',
 '12hrs',
 '12mths',
 '13',
 '130',
 '1327',
 '14',
 '1405',
 '140ppm',
 '145',
 '1450',
 '146tf150p',
 '14tcr',
 '14thmarch',
 '15',
 '150',
 '1500',
 '150p',
 '150p16',
 '150pm',
 '150ppermesssubscription',
 '150ppm',
 '150ppmpobox10183bhamb64xe',
 '150ppmsg',
 '150pw',
 '151',
 '153',
 '15541',
 '15pm',
 '16',
 '165',
 '1680',
 '169',
 '177',
 '18',
 '1843',
 '18p',
 '18yrs',
 '1956669',
 '1apple',
 '1b6a5ecef91ff9',
 '1cup',
 '1da',
 '1er',
 '1hr',
 '1im',
 '1lemon',
 '1million',
 '1pm',
 '1st',
 '1stchoice',
 '1thing',
 '1tulsi',
 '1win150ppmx3',
 '1winaweek',
 '1winawk',
 '1x150p',
 '20',
 '200',
 '2000',
 '2003',
 '2004',
 '2005',
 '2006',
 '2007',
 '20p',
 '21',
 '21870000',
 '21st',
 '22',
 '220',
 '2309',
 '23f',
 '23g',
 '24',
 '24hrs',
 '24th',
 '25',
 '250',
 '250k',
 '255',
 '25p',
 '26',
 '2667',
 '26th',
 '27',
 '28',
 '2814032',
 '28days',
 '28thfeb',
 '29',
 '2c',
 '2channel',
 '2day',
 '2end',
 '2exit',
 '2ez',
 '2find',
 '2getha',
 '2geva',
 '2go',
 '2gthr',
 '2hrs',
 '2kbsubject',
 '2lands',
 '2marrow',
 '2moro',
 '2morow',
 '2morro',
 '2morrow',
 '2morrowxxxx',
 '2mro',
 '2mrw',
 '2nd',
 '2nhite',
 '2nights',
 '2nite',
 '2optout',
 '2p',
 '2price',
 '2px',
 '2rcv',
 '2stop',
 '2stoptx',
 '2stoptxt',
 '2u',
 '2u2',
 '2waxsto',
 '2wks',
 '2wt',
 '2years',
 '2yr',
 '30',
 '300',
 '3000',
 '300603',
 '300603t',
 '300p',
 '3030',
 '30ish',
 '30pm',
 '30s',
 '30th',
 '31',
 '3100',
 '310303',
 '31p',
 '32000',
 '3230',
 '32323',
 '326',
 '33',
 '330',
 '350',
 '3510i',
 '35p',
 '3650',
 '36504',
 '3680',
 '373',
 '3750',
 '37819',
 '38',
 '382',
 '391784',
 '3aj',
 '3d',
 '3g',
 '3gbp',
 '3hrs',
 '3lions',
 '3lp',
 '3miles',
 '3mins',
 '3mobile',
 '3pound',
 '3qxj9',
 '3rd',
 '3ss',
 '3uz',
 '3wks',
 '3xx',
 '3xå',
 '40',
 '400',
 '400mins',
 '4041',
 '40411',
 '40533',
 '40gb',
 '40mph',
 '41685',
 '41782',
 '420',
 '42049',
 '42478',
 '42810',
 '430',
 '434',
 '44',
 '440',
 '4403ldnw1a7rw18',
 '44345',
 '447797706009',
 '447801259231',
 '448712404000',
 '449050000301',
 '449071512431',
 '450',
 '450p',
 '450pw',
 '45239',
 '45pm',
 '47',
 '4742',
 '47per',
 '48',
 '4882',
 '48922',
 '49',
 '49557',
 '4a',
 '4d',
 '4eva',
 '4fil',
 '4get',
 '4give',
 '4got',
 '4goten',
 '4info',
 '4jx',
 '4mths',
 '4t',
 '4th',
 '4the',
 '4thnov',
 '4txt',
 '4u',
 '4utxt',
 '4w',
 '4ward',
 '4wrd',
 '4xx26',
 '4years',
 '50',
 '500',
 '5000',
 '505060',
 '50award',
 '50ea',
 '50gbp',
 '50p',
 '50perweeksub',
 '50perwksub',
 '50pmmorefrommobile2bremoved',
 '50ppm',
 '50rcvd',
 '50s',
 '5226',
 '526',
 '530',
 '54',
 '542',
 '5ish',
 '5k',
 '5min',
 '5mls',
 '5p',
 '5pm',
 '5th',
 '5wb',
 '5we',
 '5wkg',
 '5wq',
 '5years',
 '600',
 '6031',
 '6089',
 '60p',
 '61',
 '61200',
 '61610',
 '6230',
 '62468',
 '62735',
 '630',
 '63miles',
 '645',
 '65',
 '650',
 '66',
 '674',
 '67441233',
 '68866',
 '69101',
 '69200',
 '69669',
 '69696',
 '69698',
 '69855',
 '69876',
 '69888',
 '69911',
 '69969',
 '69988',
 '6days',
 '6hl',
 '6hrs',
 '6ish',
 '6months',
 '6ph',
 '6pm',
 '6th',
 '6times',
 '6wu',
 '700',
 '71',
 '7250',
 '7250i',
 '730',
 '731',
 '74355',
 '75',
 '750',
 '7548',
 '75max',
 '762',
 '7634',
 '7684',
 '77',
 '7732584351',
 '78',
 '786',
 '7876150ppm',
 '79',
 '7am',
 '7cfca1a',
 '7ish',
 '7oz',
 '7pm',
 '7th',
 '7ws',
 '7zs',
 '800',
 '80062',
 '8007',
 '80082',
 '80086',
 '80122300p',
 '80160',
 '80182',
 '8027',
 '80488',
 '80608',
 '8077',
 '80878',
 '81010',
 '81151',
 '81303',
 '81618',
 '82050',
 '820554ad0a1705572711',
 '82242',
 '82277',
 '82324',
 '82468',
 '83021',
 '83039',
 '83049',
 '83110',
 '83118',
 '83222',
 '83332',
 '83355',
 '83383',
 '83600',
 '83738',
 '84025',
 '84128',
 '84199',
 '85',
 '850',
 '85023',
 '85069',
 '85233',
 '8552',
 '85555',
 '86021',
 '861',
 '86688',
 '86888',
 '87021',
 '87066',
 '87070',
 '87077',
 '87121',
 '87131',
 '872',
 '87239',
 '87575',
 '8800',
 '88039',
 '88066',
 '88088',
 '88222',
 '88600',
 '88800',
 '88877',
 '88888',
 '89034',
 '89070',
 '89080',
 '89105',
 '89123',
 '89545',
 '89555',
 '89693',
 '89938',
 '8am',
 '8lb',
 '8p',
 '8pm',
 '8th',
 '8wp',
 '900',
 '910',
 '9153',
 '930',
 '946',
 '95',
 '9755',
 '97n7qp',
 '98321561',
 '99',
 '9996',
 '9ae',
 '9am',
 '9ja',
 '9pm',
 '9th',
 '9yt',
 '____',
 'a30',
 'aa',
 'aah',
 'aaniye',
 'aaooooright',
 'aathi',
 'ab',
 'abbey',
 'abdomen',
 'abeg',
 'aberdeen',
 'abi',
 'ability',
 'abiola',
 'abj',
 'able',
 'abnormally',
 'about',
 'aboutas',
 'above',
 'absence',
 'absolutely',
 'absolutly',
 'abstract',
 'abt',
 'abta',
 'aburo',
 'abuse',
 'abusers',
 'ac',
 'academic',
 'acc',
 'accent',
 'accenture',
 'accept',
 'access',
 'accidant',
 'accident',
 'accidentally',
 'accommodation',
 'accommodationvouchers',
 'accomodate',
 'accomodations',
 'accordin',
 'accordingly',
 'account',
 'accounts',
 'achan',
 'ache',
 'achieve',
 'acknowledgement',
 'acl03530150pm',
 'acnt',
 'aco',
 'across',
 'act',
 'acted',
 'actin',
 'acting',
 'action',
 'activ8',
 'activate',
 'active',
 'activities',
 'actor',
 'actual',
 'actually',
 'ad',
 'adam',
 'add',
 'addamsfa',
 'added',
 'addicted',
 'addie',
 'adding',
 'address',
 'adds',
 'adewale',
 'adi',
 'admin',
 'administrator',
 'admirer',
 'admission',
 'admit',
 'adore',
 'adoring',
 'adp',
 'adress',
 'adrian',
 'ads',
 'adsense',
 'adult',
 'adults',
 'advance',
 'adventure',
 'advice',
 'advise',
 'aeronautics',
 'aeroplane',
 'affair',
 'affairs',
 'affection',
 'affectionate',
 'affections',
 'affidavit',
 'afford',
 'afghanistan',
 'afraid',
 'africa',
 'african',
 'aft',
 'after',
 'afternon',
 'afternoon',
 'afternoons',
 'afterwards',
 'aftr',
 'ag',
 'again',
 'against',
 'agalla',
 'age',
 'age16',
 'agent',
 'ages',
 'aging',
 'ago',
 'agree',
 'ah',
 'aha',
 'ahead',
 'ahhh',
 'ahhhh',
 'ahmad',
 'ahold',
 'aids',
 'aig',
 'aight',
 'ain',
 'aint',
 'air',
 'airport',
 'airtel',
 'aiya',
 'aiyah',
 'aiyar',
 'aiyo',
 'ajith',
 'ak',
 'aka',
 'al',
 'alaikkum',
 'alaipayuthe',
 'albi',
 'album',
 'alcohol',
 'aldrine',
 'alert',
 'alertfrom',
 'aletter',
 'alex',
 'alfie',
 'algarve',
 'algebra',
 'algorithms',
 'ali',
 'alian',
 'alibi',
 'alive',
 'all',
 'allah',
 'allalo',
 'allday',
 'alle',
 'allow',
 'allowed',
 'almost',
 'alone',
 'along',
 'alot',
 'already',
 'alright',
 'alrite',
 'also',
 'alter',
 'alternative',
 'although',
 'alto18',
 'aluable',
 'always',
 'alwys',
 'am',
 'amanda',
 'amazing',
 'ambitious',
 'ambrith',
 'american',
 'ami',
 'amigos',
 'amk',
 'amla',
 'amma',
 'ammae',
 'ammo',
 'among',
 'amongst',
 'amount',
 'amp',
 'amplikater',
 'amrca',
 'amt',
 'amused',
 'amy',
 'an',
 'ana',
 'anal',
 'analysis',
 'anand',
 'and',
 'anderson',
 'andres',
 'andrews',
 'angry',
 'anjie',
 'anjola',
 'anna',
 'annie',
 'anniversary',
 'annoncement',
 'announced',
 'announcement',
 'annoyin',
 'annoying',
 'anonymous',
 'anot',
 'another',
 'ans',
 'ansr',
 'answer',
 'answered',
 'answering',
 'answers',
 'answr',
 'anthony',
 'anti',
 'antibiotic',
 'any',
 'anybody',
 'anymore',
 'anyone',
 'anyplaces',
 'anythiing',
 'anythin',
 'anything',
 'anythingtomorrow',
 'anytime',
 'anyway',
 'anyways',
 'anywhere',
 'aom',
 'apart',
 'apartment',
 'apeshit',
 'apo',
 'apologetic',
 'apologise',
 'apologize',
 'apology',
 'app',
 'apparently',
 'appear',
 'appendix',
 'applausestore',
 'apples',
 'application',
 'apply',
 'applyed',
 'appointment',
 'appointments',
 ...]
```

## Training dan Evaluasi Model <a href="#training-dan-evaluasi-model" id="training-dan-evaluasi-model"></a>

Kita akan menggunakan algoritma Multinomial Naive Bayes. Fungsi `MultinomialNB` dari scikit-learn dapat digunakan pada kasus ini.

```
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score

# Inisiasi MultinomialNB
mnb = MultinomialNB()

# Fit model
mnb.fit(X_train, y_train)

# Prediksi dengan data training
y_pred_train = mnb.predict(X_train)

# Evaluasi akurasi data training
acc_train = accuracy_score(y_train, y_pred_train)

# Prediksi dengan data training
y_pred_test = mnb.predict(X_test)

# Evaluasi akurasi data training
acc_test = accuracy_score(y_test, y_pred_test)

# Print hasil evaluasi
print(f'Hasil akurasi data train: {acc_train}')
print(f'Hasil akurasi data test: {acc_test}')
```

```
Hasil akurasi data train: 0.9946152120260264
Hasil akurasi data test: 0.9775784753363229
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://polinema.gitbook.io/jti-modul-praktikum-pembelajaran-mesin/klasifikasi/job-sheet-4-klasifikasi/praktikum-4-opsional.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
