Importación de los paquetes básicos
import itertools import numpy as np import matplotlib.pyplot as plt from matplotlib.ticker import NullFormatter import pandas as pd import numpy as np import matplotlib.ticker as ticker from sklearn import preprocessing %matplotlib inline
Importación de los datos
Imagina un proveedor de telecomunicaciones que ha segmentado la base de sus clientes por servicio, categorizando a los clientes en cuatro grupos. Si los datos demográficos se pueden usar para predecir la pertenencia de grupo del envío, la compañía podría personalizar las ofertas para los prospectos. Es un problema de clasificación. Este ejemplo hace foco en datos demográficos, sean region, edad, estado civil, para predecir patrones de uso. El campo objetivo (target), llamado custcat, tiene cuatro valores posibles que corresponden a los cuatro grupos de clientes: 1- Servicio Básico 2- E-Servicio 3- Servicio Plus 4- Servicio Total
Nuestro objetivo es construir un clasificador para predecir la clase de casos desconocidos. Utilizaremos un tipo específico de clasificación llamado K vecino más cercano.
!wget -O teleCust1000t.csv https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/ML0101ENv3/labs/teleCust1000t.csv df = pd.read_csv('teleCust1000t.csv') df.head()
region | tenure | age | marital | address | income | ed | employ | retire | gender | reside | custcat | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2 | 13 | 44 | 1 | 9 | 64.0 | 4 | 5 | 0.0 | 0 | 2 | 1 |
1 | 3 | 11 | 33 | 1 | 7 | 136.0 | 5 | 5 | 0.0 | 0 | 6 | 4 |
2 | 3 | 68 | 52 | 1 | 24 | 116.0 | 1 | 29 | 0.0 | 1 | 2 | 3 |
3 | 2 | 33 | 33 | 0 | 12 | 33.0 | 2 | 0 | 0.0 | 1 | 1 | 1 |
4 | 2 | 23 | 30 | 1 | 9 | 30.0 | 1 | 2 | 0.0 | 0 | 4 | 3 |
Veamos cuántos de cada clase están en nuestro set de datos
df['custcat'].value_counts()
3 281 1 266 4 236 2 217 Name: custcat, dtype: int64
Puedes explorar fácilmente tus datos utilizando técnicas de visualización:
df.hist(column='income', bins=50)
Definamos feature sets, X:
df.columns
Index(['region', 'tenure', 'age', 'marital', 'address', 'income', 'ed', 'employ', 'retire', 'gender', 'reside', 'custcat'], dtype='object')
Para utilizar la librería scikit-learn, tenemos que convertir el data frame de Panda en un Numpy array:
X = df[['region', 'tenure','age', 'marital', 'address', 'income', 'ed', 'employ','retire', 'gender', 'reside']] .values #.astype(float) X[0:5]
array([[ 2., 13., 44., 1., 9., 64., 4., 5., 0., 0., 2.], [ 3., 11., 33., 1., 7., 136., 5., 5., 0., 0., 6.], [ 3., 68., 52., 1., 24., 116., 1., 29., 0., 1., 2.], [ 2., 33., 33., 0., 12., 33., 2., 0., 0., 1., 1.], [ 2., 23., 30., 1., 9., 30., 1., 2., 0., 0., 4.]])
¿Cuáles son nuestras etiquetas?
y = df['custcat'].values y[0:5]
array([1, 4, 3, 1, 3])
Normalizar los Datos
La estandarización de datos haciendo que la media sea 0 y la varianza uno es buena práctica, especialmente para algoritmos tales como KNN el cual se basa en distancia de casos:
X = preprocessing.StandardScaler().fit(X).transform(X.astype(float)) X[0:5]
array([[-0.02696767, -1.055125 , 0.18450456, 1.0100505 , -0.25303431, -0.12650641, 1.0877526 , -0.5941226 , -0.22207644, -1.03459817, -0.23065004], [ 1.19883553, -1.14880563, -0.69181243, 1.0100505 , -0.4514148 , 0.54644972, 1.9062271 , -0.5941226 , -0.22207644, -1.03459817, 2.55666158], [ 1.19883553, 1.52109247, 0.82182601, 1.0100505 , 1.23481934, 0.35951747, -1.36767088, 1.78752803, -0.22207644, 0.96655883, -0.23065004], [-0.02696767, -0.11831864, -0.69181243, -0.9900495 , 0.04453642, -0.41625141, -0.54919639, -1.09029981, -0.22207644, 0.96655883, -0.92747794], [-0.02696767, -0.58672182, -0.93080797, 1.0100505 , -0.25303431, -0.44429125, -1.36767088, -0.89182893, -0.22207644, -1.03459817, 1.16300577]])
Dividimos la muestra en los conjuntos de datos para el entrenamiento y para la prueba de exactitud
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=4) print ('Set de Entrenamiento:', X_train.shape, y_train.shape) print ('Set de Prueba:', X_test.shape, y_test.shape)
Set de Entrenamiento: (800, 11) (800,) Set de Prueba: (200, 11) (200,)
Clasificación
importar librería del Clasificador que implementa k-vecinos más cercanos.
from sklearn.neighbors import KNeighborsClassifier
Para el entrenamiento vamos a comenzar con el algoritmo con k=4 por ahora:
k = 4 #Entrenar el Modelo y Predecir neigh = KNeighborsClassifier(n_neighbors = k).fit(X_train,y_train) neigh
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski', metric_params=None, n_jobs=None, n_neighbors=4, p=2, weights='uniform')
Usamos el modelo para predecir el set de prueba:
yhat = neigh.predict(X_test) yhat[0:5]
array([1, 1, 3, 2, 4])
Para evaluar la certeza usamos la función classification accuracy score que computa la certeza del subconjunto. Esta función es igual a la función jaccard_similarity_score. Básicamente, calcula cómo se relacionan las etiquetas actuales con las etiquetas predichas dentro del set de pruebas.
from sklearn import metrics print("Entrenar el set de Certeza: ", metrics.accuracy_score(y_train, neigh.predict(X_train))) print("Probar el set de Certeza: ", metrics.accuracy_score(y_test, yhat))
Entrenar el set de Certeza: 0.5475 Probar el set de Certeza: 0.32
Para un K=6 tenemos los siguientes resultados
k = 6 neigh6 = KNeighborsClassifier(n_neighbors = k).fit(X_train,y_train) yhat6 = neigh6.predict(X_test) print("Certeza del Set de Entrenamiento: ", metrics.accuracy_score(y_train, neigh6.predict(X_train))) print("Certeza del Set de Prueba: ", metrics.accuracy_score(y_test, yhat6))
Certeza del Set de Entrenamiento: 0.51625 Certeza del Set de Prueba: 0.31
Cálculo del mejor k
Elegimos k =1, lo utilizamos como parte del entrenamiento para modelar, y calculamos la certeza de la predicción utilizando todas las muestras del set de pruebas. Repetir este proceso, aumentando el k, y viendo luego, cual es el mejor k para el modelo.
Ks = 10 mean_acc = np.zeros((Ks-1)) std_acc = np.zeros((Ks-1)) ConfustionMx = []; for n in range(1,Ks): #Entrenar el Modelo y Predecir neigh = KNeighborsClassifier(n_neighbors = n).fit(X_train,y_train) yhat=neigh.predict(X_test) mean_acc[n-1] = metrics.accuracy_score(y_test, yhat) std_acc[n-1]=np.std(yhat==y_test)/np.sqrt(yhat.shape[0]) mean_acc
array([0.3 , 0.29 , 0.315, 0.32 , 0.315, 0.31 , 0.335, 0.325, 0.34 ])
Dibujo de la certeza del modelo para diferentes números de vecinos
plt.plot(range(1,Ks),mean_acc,'g') plt.fill_between(range(1,Ks),mean_acc - 1 * std_acc,mean_acc + 1 * std_acc, alpha=0.10) plt.legend(('Certeza ', '+/- 3xstd')) plt.ylabel('Certeza ') plt.xlabel('Número de Vecinos (K)') plt.tight_layout() plt.show()
print( "La mejor aproximación de certeza fue con ", mean_acc.max(), "con k=", mean_acc.argmax()+1)
La mejor aproximación de certeza fue con 0.34 con k= 9