Beslutningstræ i R: Klassifikationstræ med eksempel
⚡ Smart opsummering
Beslutningstræer i R opdeler data i grene ved hjælp af simple ja- eller nej-regler, indtil hvert blad indeholder en enkelt dominerende klasse. Denne gennemgang opbygger, plotter, evaluerer og justerer et rpart-klassifikationstræ på Titanic-overlevelsesdatasættet.

Hvad er beslutningstræer?
Beslutningstræer er en alsidig maskinlæringsalgoritme, der kan udføre både klassifikations- og regressionsopgaver. De er meget kraftfulde algoritmer, der er i stand til at tilpasse komplekse datasæt. Derudover er beslutningstræer grundlæggende komponenter i tilfældige skove, som er blandt de mest potente maskinlæringsalgoritmer, der er tilgængelige i dag.
Før man bygger et i kode, er det nyttigt at vide, hvordan et træ bestemmer, hvor det skal opdeles.
Hvordan fungerer et beslutningstræ?
Et beslutningstræ omdanner et datasæt til et flowdiagram med ja- eller nej-spørgsmål, der er bygget op fra tre slags noder: rod holder alle træningsobservationer, en intern node stiller et spørgsmål om én prædiktor og deler dataene i to, og en blad stopper opdelingen og returnerer majoritetsklassen.
Vækst følger en grådig procedure kaldet rekursiv binær partitionering:
- Evaluer hver kandidatopdeling. For hver prædiktor og grænsepunkt måles, hvor urene de to resulterende grupper ville være.
- Behold den bedste. Den opdeling, der reducerer urenhed mest, bliver spørgsmålet, der stilles ved den node.
- Gentag på hvert barn indtil en kontrolregel stopper den: minsplit, minbucket, maxdepth eller cp.
- Beskær. cp beskærer derefter grene, der ikke betaler sig selv, hvilket forhindrer træet i at huske træningssættet.
Fordi hvert spørgsmål sammenligner én variabel med en tærskelværdi, behøver algoritmen aldrig skalering eller dummy-kodning.
Gini-indeks vs. entropi i beslutningstræer
Den urenhed kan måles på to måder, og rpart lader dig vælge.
| Kriterier | Gini -indeks | Entropi (informationsgevinst) |
|---|---|---|
| Formula | 1 – sum af kvadrerede klasseproportioner | -sum af p gange log²(p) |
| Rækkevidde (to klasser) | 0 til 0.5 | 0 til 1 |
| beregning | Hurtigere, ingen logaritme | Langsommere, bruger logaritmer |
| delindstilling | Standard | parameter = liste(split = "information") |
fit_entropy <- rpart(survived~., data = data_train, method = 'class', parms = list(split = "information"))
I praksis vælger begge kriterier den samme opdeling det meste af tiden, så standard Gini-indekset er et sikkert valg.
Fordele og ulemper ved beslutningstræer
Afvejningerne fortæller dig, hvornår et enkelt træ er nok, og hvornår man skal flytte til et ensemble.
Fordele
- Fuldt fortolkelig: Den tilpassede model er et diagram, som enhver interessent kan læse.
- Minimal forbehandling: ingen skalering eller normalisering er nødvendig, og faktorer fungerer native.
- Håndterer begge opgaver: method = 'class' passer til en klassifikator, og method = 'anova' passer til et regressionstræ.
- Hurtig at træne: Store datasæt passer på få sekunder, så træer udgør en nyttig første basislinje.
Ulemper
- Høj varians: en lille ændring i træningsdataene kan producere et helt andet træ.
- Tilbøjelig til overtilpasning: Et ubegrænset træ vokser, indtil hvert blad er rent, medmindre cp og maxdepth begrænser det.
- Kun akseparallelle opdelinger: Diagonale afgrænsninger kræver mange trappeformede snit.
Løsningen på de to første svagheder er at gennemsnitssætte mange træer, hvilket er hvad en tilfældig skov gør.
Sådan træner og visualiserer du et beslutningstræ i R
For at bygge dit første beslutningstræ i R, skal du arbejde dig igennem syv trin:
- Trin 1: Importer dataene
- Trin 2: Rens datasættet
- Trin 3: Opret tog/testsæt
- Trin 4: Byg modellen
- Trin 5: Lav forudsigelse
- Trin 6: Mål ydeevne
- Trin 7: Indstil hyper-parametrene
Trin 1) Importer dataene
Hvis du er nysgerrig efter titanics skæbne, kan du se denne video på Youtube. Formålet med dette datasæt er at forudsige, hvilke mennesker der er mere tilbøjelige til at overleve efter kollisionen med isbjerget. Datasættet indeholder 13 variabler og 1309 observationer. Datasættet er ordnet efter variablen X.
set.seed(678) path <- 'https://raw.githubusercontent.com/guru99-edu/R-Programming/master/titanic_data.csv' titanic <-read.csv(path) head(titanic)
Output:
## X pclass survived name sex ## 1 1 1 1 Allen, Miss. Elisabeth Walton female ## 2 2 1 1 Allison, Master. Hudson Trevor male ## 3 3 1 0 Allison, Miss. Helen Loraine female ## 4 4 1 0 Allison, Mr. Hudson Joshua Creighton male ## 5 5 1 0 Allison, Mrs. Hudson J C (Bessie Waldo Daniels) female ## 6 6 1 1 Anderson, Mr. Harry male ## age sibsp parch ticket fare cabin embarked ## 1 29.0000 0 0 24160 211.3375 B5 S ## 2 0.9167 1 2 113781 151.5500 C22 C26 S ## 3 2.0000 1 2 113781 151.5500 C22 C26 S ## 4 30.0000 1 2 113781 151.5500 C22 C26 S ## 5 25.0000 1 2 113781 151.5500 C22 C26 S ## 6 48.0000 0 0 19952 26.5500 E12 S ## home.dest ## 1 St Louis, MO ## 2 Montreal, PQ / Chesterville, ON ## 3 Montreal, PQ / Chesterville, ON ## 4 Montreal, PQ / Chesterville, ON ## 5 Montreal, PQ / Chesterville, ON ## 6 New York, NY
tail(titanic)
Output:
## X pclass survived name sex age sibsp ## 1304 1304 3 0 Yousseff, Mr. Gerious male NA 0 ## 1305 1305 3 0 Zabour, Miss. Hileni female 14.5 1 ## 1306 1306 3 0 Zabour, Miss. Thamine female NA 1 ## 1307 1307 3 0 Zakarian, Mr. Mapriededer male 26.5 0 ## 1308 1308 3 0 Zakarian, Mr. Ortin male 27.0 0 ## 1309 1309 3 0 Zimmerman, Mr. Leo male 29.0 0 ## parch ticket fare cabin embarked home.dest ## 1304 0 2627 14.4583 C ## 1305 0 2665 14.4542 C ## 1306 0 2665 14.4542 C ## 1307 0 2656 7.2250 C ## 1308 0 2670 7.2250 C ## 1309 0 315082 7.8750 S
Fra hoved- og haleudgangen kan du bemærke, at dataene ikke blandes. Dette er et stort problem! Når du vil dele dine data mellem et togsæt og et testsæt, skal du vælge kun passageren fra klasse 1 og 2 (Ingen passager fra klasse 3 er i top 80 procent af observationerne), hvilket betyder, at algoritmen aldrig vil se funktionerne for passagerer i klasse 3. Denne fejl vil føre til dårlig forudsigelse.
For at løse dette problem kan du bruge funktionen sample().
shuffle_index <- sample(1:nrow(titanic)) head(shuffle_index)
Beslutningstræ R-kode Forklaring
- sample(1:nrow(titanic)): Generer en tilfældig liste med indeks fra 1 til 1309 (dvs. det maksimale antal rækker).
Output:
## [1] 288 874 1078 633 887 992
Du skal bruge dette indeks til at blande det titaniske datasæt.
titanic <- titanic[shuffle_index, ]
head(titanic)
Output:
## X pclass survived ## 288 288 1 0 ## 874 874 3 0 ## 1078 1078 3 1 ## 633 633 3 0 ## 887 887 3 1 ## 992 992 3 1 ## name sex age ## 288 Sutton, Mr. Frederick male 61 ## 874 Humblen, Mr. Adolf Mathias Nicolai Olsen male 42 ## 1078 O'Driscoll, Miss. Bridget female NA ## 633 Andersson, Mrs. Anders Johan (Alfrida Konstantia Brogren) female 39 ## 887 Jermyn, Miss. Annie female NA ## 992 Mamee, Mr. Hanna male NA ## sibsp parch ticket fare cabin embarked home.dest## 288 0 0 36963 32.3208 D50 S Haddenfield, NJ ## 874 0 0 348121 7.6500 F G63 S ## 1078 0 0 14311 7.7500 Q ## 633 1 5 347082 31.2750 S Sweden Winnipeg, MN ## 887 0 0 14313 7.7500 Q ## 992 0 0 2677 7.2292 C
Trin 2) Rens datasættet
Flere variabler indeholder NA-værdier. Oprydningen foregår i tre dele:
- Fjern variablerne home.dest, cabin, name, X og ticket
- Opret faktorvariabler for pclass og overlevede
- Drop NA
library(dplyr) # Drop variables clean_titanic <- titanic %>% select(-c(home.dest, cabin, name, X, ticket)) %>% #Convert to factor level mutate(pclass = factor(pclass, levels = c(1, 2, 3), labels = c('Upper', 'Middle', 'Lower')), survived = factor(survived, levels = c(0, 1), labels = c('No', 'Yes'))) %>% na.omit() glimpse(clean_titanic)
Code Forklaring
- select(-c(home.dest, cabin, name, X, ticket)): Slip unødvendige variabler
- pclass = factor(pclass, levels = c(1,2,3), labels= c('Upper', 'Middle', 'Lower')): Tilføj et label til variablen pclass. 1 bliver Upper, 2 bliver Middle og 3 bliver Lower
- faktor(overlevede, niveauer = c(0,1), labels = c('Nej', 'Ja')): Tilføj labels til den variable, der overlevede. 0 bliver til Nej, og 1 bliver til Ja
- na.omit(): Fjern NA-observationerne
Output:
## Observations: 1,045 ## Variables: 8 ## $ pclass <fctr> Upper, Lower, Lower, Upper, Middle, Upper, Middle, U... ## $ survived <fctr> No, No, No, Yes, No, Yes, Yes, No, No, No, No, No, Y... ## $ sex <fctr> male, male, female, female, male, male, female, male... ## $ age <dbl> 61.0, 42.0, 39.0, 49.0, 29.0, 37.0, 20.0, 54.0, 2.0, ... ## $ sibsp <int> 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, 0, 1, 1, 0, 0, 0, 1, 1,... ## $ parch <int> 0, 0, 5, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 4, 0,... ## $ fare <dbl> 32.3208, 7.6500, 31.2750, 25.9292, 10.5000, 52.5542, ... ## $ embarked <fctr> S, S, S, S, S, S, S, S, S, C, S, S, S, Q, C, S, S, C...
Trin 3) Opret tog/testsæt
Før du træner din model, skal du udføre to trin:
- Opret et tog og testsæt: Du træner modellen på togsættet og tester forudsigelsen på testsættet (dvs. usete data)
- Installer rpart.plot fra konsollen
Den almindelige praksis er at dele dataene 80/20, 80 procent af dataene tjener til at træne modellen og 20 procent til at lave forudsigelser. Du skal oprette to separate datarammer. Du ønsker ikke at røre ved testsættet, før du er færdig med at bygge din model. Du kan oprette et funktionsnavn create_train_test(), der tager tre argumenter.
create_train_test(df, size = 0.8, train = TRUE) arguments: -df: Dataset used to train the model. -size: Size of the split. By default, 0.8. Numerical value -train: If set to `TRUE`, the function creates the train set, otherwise the test set. Default value sets to `TRUE`. Boolean value.You need to add a Boolean parameter because R does not allow to return two data frames simultaneously.
create_train_test <- function(data, size = 0.8, train = TRUE) { n_row = nrow(data) total_row = size * n_row train_sample <- 1: total_row if (train == TRUE) { return (data[train_sample, ]) } else { return (data[-train_sample, ]) } }
Code Forklaring
- function(data, størrelse=0.8, tog = TRUE): Tilføj argumenterne i funktionen
- n_row = nrow(data): Tæl antallet af rækker i datasættet
- total_row = size*n_row: Returner den n'te række for at konstruere togsættet
- train_sample <- 1:total_row: Vælg den første række til den n'te række
- if (tog ==TRUE){ } else { }: Hvis betingelsen sættes til sand, returneres togsættet, ellers testsættet.
Du kan teste din funktion og kontrollere dimensionen.
data_train <- create_train_test(clean_titanic, 0.8, train = TRUE) data_test <- create_train_test(clean_titanic, 0.8, train = FALSE) dim(data_train)
Output:
## [1] 836 8
dim(data_test)
Output:
## [1] 209 8
Togdatasættet har 836 rækker og 8 kolonner, mens testdatasættet har 209 rækker og de samme 8 kolonner.
Du bruger funktionen prop.table() kombineret med table() for at kontrollere, om randomiseringsprocessen er korrekt.
prop.table(table(data_train$survived))
Output:
## ## No Yes ## 0.5944976 0.4055024
prop.table(table(data_test$survived))
Output:
## ## No Yes ## 0.5789474 0.4210526
I begge datasæt er mængden af overlevende den samme, omkring 40 procent.
Installer rpart.plot
rpart.plot er ikke tilgængelig fra conda-biblioteker. Du kan installere det fra konsollen:
install.packages("rpart.plot")
Trin 4) Byg modellen
Du er klar til at bygge modellen. Syntaksen for beslutningstræfunktionen rpart() er:
rpart(formula, data=, method='') arguments: - formula: The function to predict - data: Specifies the data frame - method: - "class" for a classification tree - "anova" for a regression tree
Du bruger klassemetoden, fordi du forudsiger en klasse.
library(rpart) library(rpart.plot) fit <- rpart(survived~., data = data_train, method = 'class') rpart.plot(fit, extra = 106)
Code Forklaring
- rpart(): Funktion til at passe til modellen. Argumenterne er:
- overlevede ~.: Beslutningstræernes formel
- data = data_tog: Datasæt
- metode = 'klasse': Tilpas en binær model
- rpart.plot(fit, extra= 106): Plot træet. Det ekstra argument sættes til 106, hvilket viser sandsynligheden for den anden klasse plus procentdelen af observationer i hver node. Du kan referere til tegnefilm for mere information om de andre valg.
Output:
Du starter ved rodknuden, øverst i grafen og ved dybde 0 af 3:
- Øverst er det den samlede sandsynlighed for overlevelse. Det viser andelen af passagerer, der overlevede styrtet. 41 procent af passagererne overlevede.
- Denne node spørger, om passagerens køn er mandligt. Hvis ja, går man ned til roden til venstre (dybde 1). 63 procent er mænd med en overlevelsessandsynlighed på 21 procent.
- I den anden knude spørger du, om den mandlige passager er over 3.5 år. Hvis ja, så er chancen for overlevelse 19 procent.
- Du fortsætter sådan for at forstå, hvilke funktioner der påvirker sandsynligheden for overlevelse.
Bemærk, at en af de mange kvaliteter ved beslutningstræer er, at de kræver meget lidt dataforberedelse. De kræver især ikke funktionsskalering eller centrering.
Som standard bruger funktionen rpart() Gini urenhedsmål til at vælge hver opdeling. Jo højere Gini-værdien er, desto mere blandede er klasserne inden for den node, så algoritmen vælger altid den opdeling, der sænker den mest.
Trin 5) Lav en forudsigelse
Du kan forudsige dit testdatasæt. For at lave en forudsigelse kan du bruge funktionen forudsige(). Den grundlæggende syntaks for forudsigelse for R beslutningstræ er:
predict(fitted_model, df, type = 'class') arguments: - fitted_model: This is the object stored after model estimation. - df: Data frame used to make the prediction - type: Type of prediction - 'class': for classification - 'prob': to compute the probability of each class - 'vector': Predict the mean response at the node level
Du forudsiger nu, for hver af de 209 passagerer i testsættet, om modellen forventer, at de vil overleve kollisionen.
predict_unseen <-predict(fit, data_test, type = 'class')
Code Forklaring
- forudsige(tilpas, data_test, type = 'klasse'): Forudsige klassen (0/1) af testsættet
Sammenlign nu de forudsagte klasser med de sande resultater.
table_mat <- table(data_test$survived, predict_unseen)
table_mat
Code Forklaring
- tabel(data_test$survived, predict_unseen): Opbyg en betinget tabel over forudsagte klasser i forhold til det sande resultat
Output:
## predict_unseen ## No Yes ## No 106 15 ## Yes 30 58
Rækker er faktiske værdier, kolonner er forudsigelser. Modellen identificerede korrekt 106 ikke-overlevende og 58 overlevende, men mærkede 15 ikke-overlevende som overlevende og 30 overlevende som døde.
Trin 6) Mål ydeevne
Du kan beregne et nøjagtighedsmål for klassificeringsopgave med forvirringsmatrix:
forvirringsmatrix er et bedre valg til at evaluere klassificeringens ydeevne. Den generelle idé er at tælle antallet af gange, hvor sande tilfælde klassificeres er falske.
Hver række i en forvirringsmatrix repræsenterer et faktisk mål, mens hver kolonne repræsenterer et forudsagt mål. Den første række i denne matrix tager højde for de passagerer, der døde (den negative klasse): 106 blev korrekt klassificeret som døde (Sand negativ), mens 15 fejlagtigt blev klassificeret som overlevende (Falsk positiv). Den anden række omhandler de overlevende: 58 blev korrekt identificeret (Rigtig positiv), mens 30 blev overset (Falsk negativ).
Du kan beregne nøjagtighedstest fra forvirringsmatricen:
Det er andelen af sand positiv og sand negativ over summen af matricen. Med R kan du kode som følger:
accuracy_Test <- sum(diag(table_mat)) / sum(table_mat)
Code Forklaring
- sum(diag(table_mat)): Summen af diagonalen
- sum(tabel_mat): Summen af matricen.
Du kan udskrive nøjagtigheden af testsættet:
print(paste('Accuracy for test', accuracy_Test))
Output:
## [1] "Accuracy for test 0.784688995215311"
Nøjagtigheden på testsættet er 0.7847, det vil sige 78.47 procent. Gentag øvelsen på træningssættet for at se, hvor meget modellen overtilpasser.
Trin 7) Indstil hyper-parametrene
Beslutningstræ i R har forskellige parametre, der styrer aspekter af pasformen. I rpart-beslutningstræbiblioteket kan du styre parametrene ved hjælp af funktionen rpart.control(). I den følgende kode introducerer du de parametre, du vil tune. Du kan henvise til tegnefilm for andre parametre.
rpart.control(minsplit = 20, minbucket = round(minsplit/3), maxdepth = 30) Arguments: -minsplit: Set the minimum number of observations in the node before the algorithm perform a split -minbucket: Set the minimum number of observations in a terminal node, i.e. the leaf -maxdepth: Set the maximum depth of any node of the final tree. The root node is treated as depth 0
Vi fortsætter som følger:
- Konstruer funktion for at returnere nøjagtighed
- Indstil den maksimale dybde
- Indstil det mindste antal sample, en node skal have, før den kan opdeles
- Indstil det mindste antal prøver, som en bladknude skal have
Du kan skrive en funktion for at vise nøjagtigheden. Du pakker blot den kode, du brugte før:
- forudsige: forudsige_usynlig <- forudsige(tilpas, data_test, type = 'klasse')
- Fremstil tabel: table_mat <- table(data_test$survived, predict_unseen)
- Beregn nøjagtighed: nøjagtighed_Test <- sum(diag(tabel_mat))/sum(tabel_mat)
accuracy_tune <- function(fit) { predict_unseen <- predict(fit, data_test, type = 'class') table_mat <- table(data_test$survived, predict_unseen) accuracy_Test <- sum(diag(table_mat)) / sum(table_mat) accuracy_Test }
Justér nu parametrene, og se om du kan forbedre standardmodellen. Som en påmindelse skal du nå en nøjagtighed på 0.7847.
control <- rpart.control(minsplit = 4,
minbucket = round(5 / 3),
maxdepth = 3,
cp = 0)
tune_fit <- rpart(survived~., data = data_train, method = 'class', control = control)
accuracy_tune(tune_fit)
Output:
## [1] 0.7990431
Med følgende parameter:
minsplit = 4
minbucket = round(5/3)
maxdepth = 3
cp = 0
Nøjagtigheden stiger fra 0.7847 til 0.7990, så det justerede træ slår standardkonfigurationen med omkring 1.4 procentpoint.
Beslutningstræer i R: Hurtig funktionsreference
Tabellen nedenfor viser alle funktioner, der bruges i de syv trin ovenfor, sammen med den pakke, der leverer den, og de parametre, den forventer i R.
| Bibliotek | Objektiv | Funktion | Klasse | Driftsparametre | Detaljer |
|---|---|---|---|---|---|
| rpart | Togklassifikationstræ i R | rpart() | klasse | formel, df, metode | |
| rpart | Træn regressionstræ | rpart() | ANOVA | formel, df, metode | |
| rpart | Tegn træerne | rpart.plot() | monteret model | ||
| bund | forudsige | forudsige() | klasse | monteret model, type | |
| bund | forudsige | forudsige() | sandsynlighed | monteret model, type | |
| bund | forudsige | forudsige() | vektor | monteret model, type | |
| rpart | Kontrolparametre | rpart.control() | minsplit | Indstil det mindste antal observationer i noden, før algoritmen udfører en opdeling | |
| minbucket | Indstil det minimale antal observationer i en terminalnode, dvs. bladet | ||||
| maxdepth | Indstil den maksimale dybde for enhver node i det endelige træ. Rodnoden behandles som dybde 0 | ||||
| rpart | Togmodel med kontrolparameter | rpart() | formel, df, metode, kontrol |
Bemærk: Træn modellen på et træningsdata og test ydeevnen på et uset datasæt, dvs. testsæt.



