Iti0210lab112
Sisukord
Klassifitseerimine: otsustuspuu ja närvivõrk
Sissejuhatus
Kodutöös proovime otsustuspuu ja närvivõrguga andmete klassifitseerimist. Katsetamiseks on andmestik autode mõnedest parameetritest, iga auto kohta on antud hinnang, kas see on hea või halb ost. Andmestikul on mõningad eripärad: see on sünteetiline, ehk siis mitte korjatud päris klientidelt, vaid tekitatud mingi statistika alusel. Teiseks ei ole andmestik tasakaalus.
Vali masinõppeks sobiv tarkvarapakett. Allolev juhend eeldab, et kasutad Pythonit, muude vahenditega tuleb iseseisvalt hakkama saada.
Soovitatud masinõppe teegid (vali üks):
- http://scikit-learn.org/stable/index.html - Python; juhend eeldab, et kasutatakse seda
- http://www.cs.waikato.ac.nz/ml/weka/ - Java
Ülesanne koosneb mõnedest katsetest, mille tulemustest tuleb koostada logi või raport ja see moodles esitada.
Andmete kirjeldus
Väljavõtted täielikust kirjeldusest:
Car Evaluation Database was derived from a simple hierarchical decision model originally developed for the demonstration of DEX (M. Bohanec, V. Rajkovic: Expert system for decision making. Sistemica 1(1), pp. 145-157, 1990.). The model evaluates cars according to the following concept structure: CAR car acceptability . PRICE overall price . . buying buying price . . maint price of the maintenance . TECH technical characteristics . . COMFORT comfort . . . doors number of doors . . . persons capacity in terms of persons to carry . . . lug_boot the size of luggage boot . . safety estimated safety of the car
Statistika:
Number of Instances: 1728 (instances completely cover the attribute space) Number of Attributes: 6
Tunnused ja nende väärtused:
Attribute Values: buying v-high, high, med, low maint v-high, high, med, low doors 2, 3, 4, 5-more persons 2, 4, more lug_boot small, med, big safety low, med, high Missing Attribute Values: none
Klassid (päris andmetes on "vgood", mitte "v-good"):
class N N[%] ----------------------------- unacc 1210 (70.023 %) acc 384 (22.222 %) good 69 ( 3.993 %) v-good 65 ( 3.762 %)
Ettevalmistus
Andmed lae alla siit.
Kõigepealt tuleb andmed sisse lugeda. Käsitsi ei ole seda keeruline teha, aga näiteks Anacondaga tuleb kaasa pandas
pakett:
import pandas # veergude nimed võetud kirjeldusest features = ["buying", "maint", "doors", "persons", "lug_boot", "safety"] car_data = pandas.read_csv("car.data", header=None, names=features + ["class"])
Tulemuseks on DataFrame
tüüpi objekt. See formaat on scikit-learn
paketi poolt hästi toetatud ning paljud meetodid oskavad seda otse sisse süüa.
Kategooriate teisendamine numbriteks
Osad masinõppe tehnikad nõuavad juba oma olemuselt numbrilist sisendit (närvivõrk), teiste puhul võib see tuleneda implementatsioonist. Korrektne viis kategooriate teisendamiseks on need asendada umbes nii:
Algandmed:
uksi 2 2 4 2 5more
Teisendatud:
uksi_2 uksi_4 uksi_5more 1 0 0 1 0 0 0 1 0 1 0 0 0 0 1
Lihtsalt numbritega asendamine on ka võimalik (näiteks, low - 0, med - 0.5, high - 1.0), aga üldiselt on abstraktsete nähtuste, nagu suur, väike, punane või roheline, ühele numbrilisele skaalale paigutamine kahtlane idee.
pandas
paketiga:
X_text = car_data.loc[:, features] X = pandas.get_dummies(X_text) print(X.columns) y = car_data["class"]
Otsustuspuu
Jaotame andmed treening- ja testandmeteks. Selleks on juba valmisfunktsioon. Esialgu teeme andmed lihtsalt kaheks suureks tükiks: 70% treeninguks ja 30% testiks:
from sklearn.model_selection import train_test_split # no shuffling X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, shuffle=False)
Nüüd treenime otsustuspuu (kui tahad täpsemalt uurida, vt juhend):
from sklearn import tree dtc=tree.DecisionTreeClassifier() dtc.fit(X_train, y_train) # puu on treenitud, vaatame kiirelt, kui hästi ta testandmeid klassifitseerib: dtc.score(X_test, y_test)
Täpsus on üsna madal. Mis juhtus? Kui vaatad sisendfaili, siis on seal read sorteeritud. Test- ja treeningandmeteks tükeldamisel satuvad ühte poolde rohkem ühesugused näited ja teise poolde teistsugused. See ei ole hea mõte, sest see tähendab, et treenime tahtlikult ebasobivate andmetega. Lubame nüüd train_test_split
meetodil read juhuslikult ära segada:
X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3)
Puu uuesti treenimisel peaks tulema palju parem klassifitseerimise täpsus.
Tegeleme nüüd teise küsimusega: saadud täpsus on keskmine üle kõigi klasside, mis siis kui meid huvitavad just need autod, mis on "väga head"?
from sklearn.metrics import precision_recall_fscore_support y_predicted = dtc.predict(X_test) precision, recall, _, _ = precision_recall_fscore_support( y_predicted, y_test, average=None, labels=["vgood"])
Siin precision
ütleb meile, kui palju autosid, mille kohta otsustuspuu ütles "väga hea" ehk "vgood", olid õigesti klassifitseeritud - kui see arv ei ole 1.0, oli meil valepositiivseid tulemusi. recall
on aga number, mis ütleb, kui suur osa "väga häid" autosid kogu testandmestikust üles leiti. Teisiti öeldes, kas leidus ka valenegatiivseid tulemusi.
Närvivõrk
Jätkame sama treening- ja testandmete jaotusega, et erinevaid tehnikaid omavahel otse võrrelda.
Esimene kiire test (põhjaliku närvivõrkude õpetuse leiad siit).
from sklearn import neural_network nnc = neural_network.MLPClassifier(hidden_layer_sizes=(10,)) nnc.fit(X_train, y_train) nnc.score(X_test, y_test)
Ainukese kasutatud parameetriga hidden_layer_sizes
ütlesime ette, et võrk peaks koosnema sisenditest (leitakse automaatselt), 10 neuroniga peidetud kihist ning väljundkihist (tekitatakse automaatselt sõltuvalt treeningandmetest). Võimalik, et treenimisel kaebab närvivõrk, et tal ei olnud piisavalt aega kaalude konvergeerumiseks. Siis lisame iteratsioone:
nnc = neural_network.MLPClassifier(hidden_layer_sizes=(10,), max_iter=1000)
Närvivõrgu võib teha ka ambitsioonikama, näiteks lisame mitu kihti, mis on sama suured kui sisendkiht:
n_features = X_train.shape[1] nnc_shape = (n_features, n_features, 10) nnc = neural_network.MLPClassifier(hidden_layer_sizes=nnc_shape, max_iter=1000)
Proovi, kas klassifitseerimise täpsuse skoor kasvas, võrreldes väiksema võrguga.
Otsustuspuu puhul proovisime ka, kui täpselt ühte konkreetset klassi suudetakse leida. Kordame seda katset:
y_nnc = nnc.predict(X_test) precision, recall, _, _ = precision_recall_fscore_support(y_nnc, y_test, average=None, labels=["vgood"])
Andmete balansseerimine
Katsetame hüpoteesi, et andmete tasakaalustatus mõjutab seda, kui edukalt kõige haruldlasemat klassi "vgood" leitakse. Ehk siis, võibolla läheb närvivõrk mõnikord lihtsama vastupanu teed ja kipub ennustama muid klasse, kuna "vgood"-i niikuinii eriti ei esine. Testandmeid me ei puutu, muudame ainult treeningandmeid, mille pealt närvivõrku õpetatakse. Paneme kõikide vähem esinenud klasside kohta ridu juurde, nii et neid oleks võrdselt "unacc" klassiga ja klasside jaotus oleks 25% iga klassi kohta.
Tükeldame treeningandmed:
X1 = X_train[y_train == "unacc"] X2 = X_train[y_train == "acc"] X3 = X_train[y_train == "good"] X4 = X_train[y_train == "vgood"] y1 = y_train[y_train == "unacc"] y2 = y_train[y_train == "acc"] y3 = y_train[y_train == "good"] y4 = y_train[y_train == "vgood"]
Genereerime juhuslikult juurde samasuguseid ridu, kui andmetes juba esineb (uusi "juhtumeid" ei leiutata):
from sklearn.utils import resample biggest_class = X1.shape[0] X2r, y2r = resample(X2, y2, n_samples=biggest_class) X3r, y3r = resample(X3, y3, n_samples=biggest_class) X4r, y4r = resample(X4, y4, n_samples=biggest_class) print(X4r.shape)
Paneme tükid uuesti kokku. Seejuures "unacc" klassi näiteid ei puudutatud.
X_balanced = pandas.concat([X1, X2r, X3r, X4r]) y_balanced = pandas.concat([y1, y2r, y3r, y4r])
Treeni nüüd närvivõrk uuesti *_balanced
andmetega ja vaata, mida annab score
meetod ning kas paraneb klassi "vgood" leidmine.
Lahenduse esitamine
Tekita oma tegevustest logi, kus on näha kõikide katsetuste numbrilised tulemused (klassifitseerimise tulemused, precision, recall). Kõiki käske/programmikoodi ära logisse kopeeri - asenda see lühikese selgitusega, mida tehti.
Mida veel saab teha
Need viited on huvi pärast edasi uurimiseks, seda osa pole kohustuslik teha.