0% encontró este documento útil (0 votos)
66 vistas7 páginas

Random Forest

El documento describe el uso de Random Forest, un método de ensamble que combina múltiples árboles de decisión para mitigar el sobreajuste. Se explica cómo implementar Random Forest utilizando Scikit-Learn, incluyendo la generación de datos sintéticos y la visualización de fronteras de decisión. Además, se presenta un caso práctico de clasificación de imágenes de letras utilizando un conjunto de datos del repositorio UCI.

Cargado por

Gabriel aquino
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
66 vistas7 páginas

Random Forest

El documento describe el uso de Random Forest, un método de ensamble que combina múltiples árboles de decisión para mitigar el sobreajuste. Se explica cómo implementar Random Forest utilizando Scikit-Learn, incluyendo la generación de datos sintéticos y la visualización de fronteras de decisión. Además, se presenta un caso práctico de clasificación de imágenes de letras utilizando un conjunto de datos del repositorio UCI.

Cargado por

Gabriel aquino
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 7

!

pip install make-spirals

Random Forest
Como hemos comprobado, los árboles de decisión tienden a hacer sobreajuste o overfitting.
Este sobreajuste resulta ser una propiedad general de los árboles de decisión: es muy fácil ir
demasiado profundo en el árbol, y así ajustar los detalles de los datos particulares en lugar de
las propiedades generales de las distribuciones de las que se extraen.

Al mismo tiempo hemos podido comprobar que es fácil generar árboles de decisión diferentes
para un mismo conjunto de datos de entrada. Además, limitando las posibilidades del algoritmo
para añadir nodos al árbol podemos generar modelos que, si bien presentan problemas de
sobreajuste, están focalizados en subconjunto específico del conjunto de datos. Por lo tanto,
parece razonable combinar varios de estos modelos sobreajustados para intentar mitigar el
efecto de sus sobreajustes.

Esta idea de que se pueden combinar múltiples estimadores con overfitting para reducir el
efecto de este sobreajuste es lo que subyace a un método de ensamble llamado "bagging". El
"bagging" hace uso de un conjunto de estimadores paralelos, cada uno de los cuales se ajusta en
exceso (con overfitting) a los datos, y promedia los resultados para encontrar una mejor
clasificación. Un conjunto de árboles de decisión aleatorios se conoce como random forest.

Random Forests 'a mano'


Como ya se ha dicho, un Random Forest no es más que un ensemble bagging de árboles de
decisión aleatorio. Scikit-learn nos proporciona un objeto para instanciar y usar baggings de
algún otro modelo de aprendizaje computacional. En nuestro caso, vamos a usar este método
para definir y entrenar un Random Forest construido a partir de árboles aleatorios de decisión:

## Función auxiliar para pintar las fronteras de decisión de un


clasificador
def visualize_classifier(model, X, y, ax=None, cmap='rainbow'):
plt.figure(figsize=(10, 5))
ax = ax or plt.gca()

# Plot the training points


ax.scatter(X[:, 0], X[:, 1], c=y, s=30, cmap=cmap,
clim=(y.min(), y.max()), zorder=3)
ax.axis('tight')
ax.axis('off')
xlim = ax.get_xlim()
ylim = ax.get_ylim()

# fit the estimator


model.fit(X, y)
xx, yy = np.meshgrid(np.linspace(*xlim, num=200),
np.linspace(*ylim, num=200))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)

# Create a color plot with the results


n_classes = len(np.unique(y))
contours = ax.contourf(xx, yy, Z, alpha=0.3,
levels=np.arange(n_classes + 1) - 0.5,
cmap=cmap, clim=(y.min(), y.max()),
zorder=1)

ax.set(xlim=xlim, ylim=ylim)

Primero vamos a generar un dataset sintético con la función make_blobs. Este dataset
constará de 300 observaciones con 4 categorías:

from sklearn.datasets import make_blobs


import matplotlib.pyplot as plt

X, y = make_blobs(n_samples=300, centers=4, random_state=0,


cluster_std=1.0)

plt.figure()

plt.xlabel('X1')
plt.ylabel('X2')

plt.scatter(X[:, 0], X[:, 1], c=y, cmap='rainbow')

plt.show()

Cuando construimos un Random Forest a partir del BaggingClassifier debemos especificar:

• n_estimators: el número de árboles de que se compondrá nuestro bosque.


• max_samples: el porcentaje de muestras del dataset que se usarán para construir cada
bosque.

Podemos ilustrar gráficamente qué cómo se combinan las árboles comparando las fronteras de
decisión de cada árbol que compone el bosque recuperándolas mediante el atributo
estimators_:

from sklearn.tree import DecisionTreeClassifier


from sklearn.ensemble import BaggingClassifier
import numpy as np

tree = DecisionTreeClassifier()
bag = BaggingClassifier(tree, n_estimators=8, max_samples=0.3,
random_state=1)
bag.fit(X, y)

fig, axs = plt.subplots(nrows=3, ncols=3, figsize=(15,15))


fig.tight_layout(pad=4.0)
min, max = np.amin(X, axis=0), np.amax(X, axis=0)
diff = max - min
min, max = min - 0.1 * diff, max + 0.1 * diff

for i in range(3):
for j in range(3):

axs[i,j].set_xlabel('X1')
axs[i,j].set_ylabel('X2')

axs[i,j].set_xlim(min[0], max[0])
axs[i,j].set_ylim(min[1], max[1])

xx, yy = np.meshgrid(np.linspace(min[0], max[0], 100),


np.linspace(min[1], max[1], 100))

if i == 0 and j == 0:
axs[i,j].set_title('Random Forest')
Z = bag.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
axs[i,j].contourf(xx, yy, Z, alpha=0.4, cmap='rainbow')

else:
t = 3 * i + j - 1 # tree index

axs[i,j].set_title('Decision Tree #' + str(t+1))


Z = bag.estimators_[t].predict(np.c_[xx.ravel(),
yy.ravel()])
Z = Z.reshape(xx.shape)
axs[i,j].contourf(xx, yy, Z, alpha=0.4, cmap='rainbow')

axs[i,j].scatter(X[:,0], X[:,1], c=y, edgecolor='black', s=20,


cmap='rainbow')

plt.show()

En este ejemplo, hemos aleatorizado los datos ajustando cada modelo con un subconjunto
aleatorio del 30% de los puntos de entrenamiento. En la práctica, los árboles de decisión se
aleatorizan en mayor medida, inyectando cierta aleatoriedad en la forma en que se eligen las
divisiones: de esta manera todos los datos contribuyen al ajuste cada vez, pero los resultados del
ajuste siguen teniendo la aleatoriedad deseada. Por ejemplo, al determinar la característica en la
que se va a dividir, el árbol aleatorio podría seleccionar entre las varias características
principales.

También posible aleatoreizar las características que se van a usar para cada uno de los árboles
mediante el parámetro max_features.
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier
import numpy as np

tree = DecisionTreeClassifier()
bag = BaggingClassifier(tree, n_estimators=8, max_samples=0.3,
max_features=1, random_state=1)
bag.fit(X, y)

fig, axs = plt.subplots(nrows=3, ncols=3, figsize=(15,15))


fig.tight_layout(pad=4.0)

min, max = np.amin(X, axis=0), np.amax(X, axis=0)


diff = max - min
min, max = min - 0.1 * diff, max + 0.1 * diff

for i in range(3):
for j in range(3):

axs[i,j].set_xlabel('X1')
axs[i,j].set_ylabel('X2')

axs[i,j].set_xlim(min[0], max[0])
axs[i,j].set_ylim(min[1], max[1])

x1, x2 = np.meshgrid(np.linspace(min[0], max[0], 100),


np.linspace(min[1], max[1], 100))
grid = np.c_[x1.ravel(), x2.ravel()]

if i == 0 and j == 0:
axs[i,j].set_title('Random Forest')
Z = bag.predict(grid)
Z = Z.reshape(x1.shape)
axs[i,j].contourf(x1, x2, Z, alpha=0.4, cmap='rainbow')

else:
t = 3 * i + j - 1 # tree index

axs[i,j].set_title('Decision Tree #' + str(t+1))


xt = grid[:,bag.estimators_features_[t]]
Z = bag.estimators_[t].predict(xt)
Z = Z.reshape(x1.shape)
axs[i,j].contourf(x1, x2, Z, alpha=0.4, cmap='rainbow')

axs[i,j].scatter(X[:,0], X[:,1], c=y, edgecolor='black', s=20,


cmap='rainbow')

plt.show()
Random Forest con Scikit-Learn
En Scikit-Learn, este conjunto optimizado de árboles de decisión aleatorios se implementa en el
modelo RandomForestClassifier, que se encarga de toda la aleatorización de forma
automática. Al igual que sucedía con el bagging, debemos seleccionar su número de árboles
(n_estimators) así como la profundidad máxima (max_depth), el número de features a usar
(max_features) y el número de muestras (max_samples) de cada árbol.

Veamos su desempeño sobre diferentes conjuntos de datos:

import matplotlib.pyplot as plt


import numpy as np

from sklearn.ensemble import RandomForestClassifier


from sklearn.datasets import make_blobs, make_moons, make_circles

from make_spirals import make_spirals

def plot_clasification(X, y, axs):


min = np.amin(X, axis=0)
max = np.amax(X, axis=0)

diff = max - min

min = min - 0.1 * diff


max = max + 0.1 * diff

axs[0].set_title('Raw data')
axs[0].set_xlabel('X1')
axs[0].set_ylabel('X2')

axs[0].set_xlim(min[0], max[0])
axs[0].set_ylim(min[1], max[1])

axs[0].scatter(X[:,0], X[:,1], c=y, cmap=plt.cm.bwr)

for i, max_depth in enumerate([1,2,3]):


clf = RandomForestClassifier(n_estimators=100,
max_depth=max_depth, random_state=1)
clf.fit(X, y)

xx, yy = np.meshgrid(np.linspace(min[0], max[0], 100),


np.linspace(min[1], max[1], 100))
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

axs[i+1].set_title('max_depth=' + str(max_depth))
axs[i+1].set_xlabel('X1')
axs[i+1].set_ylabel('X2')
axs[i+1].set_xlim(min[0], max[0])
axs[i+1].set_ylim(min[1], max[1])

axs[i+1].contourf(xx, yy, Z, alpha=0.5, cmap=plt.cm.bwr)


axs[i+1].scatter(X[:,0], X[:,1], c=y, edgecolor='black', s=20,
cmap=plt.cm.bwr )

fig, axs = plt.subplots(nrows=4, ncols=4, figsize=(20,20))


fig.tight_layout(pad=4.0)

X, y = make_blobs(n_samples=300, n_features=2, centers=2,


cluster_std=2, random_state=42)
plot_clasification(X, y, axs[0])

X, y = make_moons(n_samples=300, noise=0.1, random_state=42)


plot_clasification(X, y, axs[1])

X, y = make_circles(n_samples=300, noise=0.1, factor=0.5,


random_state=42)
plot_clasification(X, y, axs[2])

X, y = make_spirals(n_samples=1000, random_state=42)
plot_clasification(X, y, axs[3])

Podemos observar que promediando 100 estimadores aleatorios, los cuales probablemente
sufran de overfitting, obtenemos un modelo que mitiga el efecto de dicha sobre-estimación.

Probando el rendimiento de Random Forest


Para probar el rendimiento de este modelo vamos a utilizar un conjunto de datos sobre
imágenes escaneadas de caracteres del alfabeto anglosajón alojado en el repositorio UCI.

Según la descripción del dataset:

el objetivo es identificar imágenes rectangulares en blanco y negro como una de las 26


letras mayúsculas del alfabeto inglés. Las imágenes de los caracteres se basaron en 20
fuentes diferentes y cada letra dentro de estas 20 fuentes fue distorsionada
aleatoriamente para producir un archivo de 20.000 observaciones únicas.

import pandas as pd
features = [
'target', 'x-box', 'y-box', 'width', 'high ', 'onpix', 'x-
bar',
'y-bar', 'x2bar', 'y2bar', 'xybar', 'x2ybr', 'xy2br', 'x-
ege',
'xegvy', 'y-ege', 'yegvx'
]
letras = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-
databases/letter-recognition/letter-recognition.data', names=features)
X = letras.iloc[:,1:]
y = letras.target

Una vez cargados los datos, procedemos a realizar el ajuste y validación del modelo. Para ello
vamos a usar validación cruzada:

from sklearn.model_selection import cross_validate, KFold

cv = KFold(n_splits=5, shuffle=True, random_state=1337)

# Primera aproximación, random forest con parámetros por defecto


rf1 = RandomForestClassifier(n_jobs=-1)

scores = cross_validate(rf1, X, y, cv=cv, scoring=('accuracy',


'precision_weighted', 'recall_weighted', 'f1_weighted'))

scores

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y,


test_size=0.75)

from sklearn.metrics import plot_confusion_matrix

rf = RandomForestClassifier(n_estimators=50, n_jobs=-1)

rf.fit(X_train, y_train)

plt.rcParams["figure.figsize"] = [20, 20]


plot_confusion_matrix(rf, X_test, y_test, cmap='Blues',
normalize='true')

Creado por Raúl Lara Cabrera ([email protected]) y Fernando Ortega


([email protected])

También podría gustarte