graph LR A[Feature A > X?<br>Node] -->|Yes| B(Feature B ≤ Y?<br>Node) A -->|No| C{Feature C > Z?<br>Node} B -->|Yes| D((Class 1<br>Leaf)) B -->|No| E((Class 2<br>Leaf)) C -->|Yes| F((Class 3<br>Leaf)) C -->|No| G((Class 4<br>Leaf)) style A fill:#f9f,stroke:#333,stroke-width:2px style B fill:#f9f,stroke:#333,stroke-width:2px style C fill:#f9f,stroke:#333,stroke-width:2px style D fill:#ccf,stroke:#333,stroke-width:2px style E fill:#ccf,stroke:#333,stroke-width:2px style F fill:#ccf,stroke:#333,stroke-width:2px style G fill:#ccf,stroke:#333,stroke-width:2px
Forelesningsnotat: Beslutningstrær
Videre til beslutningstrær
Vi skal først se på hva beslutningstrær er for noe, og prøve å designe et par slike. Så kjører vi litt live-programmering av beslutningstrær med scikit-learn. Vi venter med skoger og boosting til neste gang.
Beslutningstre
- En trestruktur for prediksjoner.
- Hver node representerer en test
- Hver gren representerer utfallet av testen
- Hvert blad representerer en prediksjon.
Eksempel: Boston housing
import numpy as np
import pandas as pd
= pd.read_csv("data/HousingData.csv")
df
print(df.drop(columns=["AGE", "CHAS", "ZN", "DIS"]))
CRIM INDUS NOX RM RAD TAX PTRATIO B LSTAT MEDV
0 0.00632 2.31 0.538 6.575 1 296 15.3 396.90 4.98 24.0
1 0.02731 7.07 0.469 6.421 2 242 17.8 396.90 9.14 21.6
2 0.02729 7.07 0.469 7.185 2 242 17.8 392.83 4.03 34.7
3 0.03237 2.18 0.458 6.998 3 222 18.7 394.63 2.94 33.4
4 0.06905 2.18 0.458 7.147 3 222 18.7 396.90 NaN 36.2
.. ... ... ... ... ... ... ... ... ... ...
501 0.06263 11.93 0.573 6.593 1 273 21.0 391.99 NaN 22.4
502 0.04527 11.93 0.573 6.120 1 273 21.0 396.90 9.08 20.6
503 0.06076 11.93 0.573 6.976 1 273 21.0 396.90 5.64 23.9
504 0.10959 11.93 0.573 6.794 1 273 21.0 393.45 6.48 22.0
505 0.04741 11.93 0.573 6.030 1 273 21.0 396.90 7.88 11.9
[506 rows x 10 columns]
Verdi på husene
Vi ønsker å estimere median verdi på husene i et område, fra andre kolonner i datasettet.
print(f"Mean value: {np.mean(df.MEDV)}")
print(f"Variance of value: {np.var(df.MEDV)}")
Mean value: 22.532806324110677
Variance of value: 84.41955615616556
Grunt beslutningstre
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import train_test_split
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt
= pd.read_csv("data/HousingData.csv")
df
= df.drop(columns=["MEDV"]).values
X = df.drop(columns=["MEDV"]).columns
feature_names = df["MEDV"].values
y
# Trener modellen
= DecisionTreeRegressor(max_depth=2, random_state=4)
tree
tree.fit(X, y)
= list(feature_names)
feature_names "RM")] = "Rooms per dwelling"
feature_names[feature_names.index(
=(12, 7))
plt.figure(figsize=feature_names, filled=True)
plot_tree(tree, feature_names
plt.show()
Litt dypere
= pd.read_csv("data/HousingData.csv")
df
= df.drop(columns=["MEDV"]).values
X = df.drop(columns=["MEDV"]).columns
feature_names = df["MEDV"].values
y
# Trener modellen
= DecisionTreeRegressor(max_depth=3, random_state=4)
tree
tree.fit(X, y)
= list(feature_names)
feature_names "RM")] = "Rooms per dwelling"
feature_names[feature_names.index(
=(12, 7))
plt.figure(figsize=feature_names, filled=True)
plot_tree(tree, feature_names
plt.show()
Fordeler
- Intuitivt og lett å tolke: Kan ligne menneskelig beslutningstaking.
- Kan uten videre predikere flere klasser (i motsetning til vanlig logistisk regresjon)
Ulemper:
- Tendens til overtilpasning: Kan bli for komplekse og tilpasse seg treningsdataene for godt.
- Ustabile: Små endringer i dataene kan føre til store endringer i treet.
- “Grådig” algoritme: Lokal optimalisering, ikke garantert globalt optimalt tre.
På grunn av disse ulempene lager man gjerne en random forest av beslutningstrær for å få en bedre prediktor. Det skal vi se på en annen dag.
Eksempel: iris-datasettet
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
= mpl.rcParams['axes.prop_cycle']
prop_cycle = prop_cycle.by_key()['color']
colors
= load_iris()
iris = np.array(iris.data), np.array(iris.target)
X, y = iris.target_names
target_names = iris.feature_names
feature_names = [colors[i] for i in y]
color_list = [target_names[i] for i in y]
names
= pd.DataFrame({
df 0] : X[:,0],
feature_names[1] : X[:,1],
feature_names[2] : X[:,2],
feature_names[3] : X[:,3],
feature_names["species" : names
})
= [[0,1], [2, 3], [0, 2], [0, 3], [1, 2], [1,3]]
plot_pairs =(10, 5))
plt.figure(figsizefor i, pair in enumerate(plot_pairs):
2,3,i+1)
plt.subplot(for species, frame in df.groupby("species"):
0]]], frame[feature_names[pair[1]]], "o", label=species)
plt.plot(frame[feature_names[pair[0]])
plt.xlabel(feature_names[pair[1]])
plt.ylabel(feature_names[pair[
plt.legend() plt.tight_layout()
Er det potensiale for å bruke et beslutningstre for å vurdere iris-arter her?
Lage beslutningstre med scikit-learn
(Men dette skal vi live-kode helst)
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
# Laster inn Iris datasettet
= load_iris()
iris = iris.data, iris.target
X, y = ["sepal length"]
predictor_names
# Initialiserer og trener et beslutningstre
= DecisionTreeClassifier(max_depth=3, random_state=0) #
dtree
#Begrenser dybden for visualisering
dtree.fit(X, y)
# Visualiserer beslutningstreet
=(12, 7))
plt.figure(figsize=iris.feature_names, class_names=iris.target_names, filled=True)
plot_tree(dtree, feature_names plt.show()
Kommer dette beslutningstreet til å score bra eller dårlig?
Med test-train-split
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
= load_iris()
iris = iris.data, iris.target
X, y = DecisionTreeClassifier(max_depth=3, random_state=0) #
dtree
dtree.fit(X, y)= dtree.predict([[0.1, 0.1, 0.1, 0.1]])
dummy_prediction print(iris.target_names[dummy_prediction])
['setosa']
Bruk from sklearn.model_selection
sin train_test_split
til å lage et beslutningstre med treningsdata og sjekk hvor god presisjon det har på valideringsdataene.
Visualisering av prediksjonen
= X[:, 2:4] # Sepal length and sepal width
X_2d # --- Visualisering av beslutningsgrenser og datapunkter ---
# 1. Lag et meshgrid for å plotte beslutningsregionene
= X_2d[:, 0].min() - 1, X_2d[:, 0].max() + 1
x_min, x_max = X_2d[:, 1].min() - 1, X_2d[:, 1].max() + 1
y_min, y_max = np.meshgrid(np.arange(x_min, x_max, 0.02),
xx, yy 0.02))
np.arange(y_min, y_max,
# 2. Prediker klassen for hvert punkt i meshgridet
= dtree.predict(np.c_[xx.ravel(), yy.ravel(), xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
Z
# 3. Plot beslutningsregionene som en contour plot
=(10, 7))
plt.figure(figsize=0.4, cmap=plt.cm.RdYlBu) # Fyll regionene med farger
plt.contourf(xx, yy, Z, alpha
# 4. Plot de faktiske datapunktene oppå
= ['r', 'y', 'b'] # Farger for hver Iris klasse
colors for i, color in zip(range(len(target_names)), colors):
= np.where(y == i)
idx 0], X_2d[idx, 1], c=color, label=target_names[i],
plt.scatter(X_2d[idx, =plt.cm.RdYlBu, edgecolor='black', s=20)
cmap
# 5. Legg til labels og tittel
2])
plt.xlabel(feature_names[3])
plt.ylabel(feature_names['Beslutningstre beslutningsgrenser på Iris datasettet (2 features)')
plt.title(='best', shadow=False, scatterpoints=1)
plt.legend(loc
min(), xx.max())
plt.xlim(xx.min(), yy.max())
plt.ylim(yy.
plt.show()
/var/folders/qn/3_cqp_vx25v4w6yrx68654q80000gp/T/ipykernel_59382/4173824724.py:21: UserWarning:
No data for colormapping provided via 'c'. Parameters 'cmap' will be ignored
Neste gang
- Random forest og boosting
- Hvordan lære noe av trær og skoger, feature importance, partial dependence.