Tutorial de Scikit-Learn: Cómo instalar y ejemplos de Scikit-Learn

¿Qué es Scikit-learn?

Scikit-learn es un código abierto Python Biblioteca para aprendizaje automático. Admite algoritmos de última generación como KNN, XGBoost, random forest y SVM. Está construida sobre NumPy. Scikit-learn se usa ampliamente en la competencia Kaggle, así como en importantes empresas tecnológicas. Ayuda en el preprocesamiento, la reducción de dimensionalidad (selección de parámetros), la clasificación, la regresión, la agrupación y la selección de modelos.

Scikit-learn tiene la mejor documentación de todas las bibliotecas de código abierto. Le proporciona un gráfico interactivo en https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html.

Cómo funciona Scikit Learn
Cómo funciona Scikit Learn

Scikit-learn no es muy difícil de usar y proporciona excelentes resultados. Sin embargo, scikit learn no admite cálculos paralelos. Es posible ejecutar un algoritmo de aprendizaje profundo con él, pero no es una solución óptima, especialmente si sabes cómo usar TensorFlow.

Cómo descargar e instalar Scikit-learn

Ahora en esto Python Tutorial de Scikit-learn, aprenderemos cómo descargar e instalar Scikit-learn:

Opción 1 AWS

scikit-learn se puede utilizar en AWS. Por favor remitir La imagen de la ventana acoplable que tiene scikit-learn preinstalado.

Para usar la versión de desarrollador use el comando en Jupyter

import sys
!{sys.executable} -m pip install git+git://github.com/scikit-learn/scikit-learn.git

Opción 2 Mac o Windows usando anaconda

Para obtener más información sobre la instalación de Anaconda, consulte https://www.guru99.com/download-install-tensorflow.html

Recientemente, los desarrolladores de scikit lanzaron una versión de desarrollo que aborda el problema común que enfrenta la versión actual. Nos pareció más conveniente utilizar la versión para desarrolladores en lugar de la versión actual.

Cómo instalar scikit-learn con Conda Environment

Si instaló scikit-learn con el entorno conda, siga los pasos para actualizar a la versión 0.20

Paso 1) Activar el entorno de tensorflow

source activate hello-tf

Paso 2) Eliminar scikit lean usando el comando conda

conda remove scikit-learn

Paso 3) Instale la versión para desarrolladores.
Instale la versión para desarrolladores de scikit learn junto con las bibliotecas necesarias.

conda install -c anaconda git
pip install Cython
pip install h5py
pip install git+git://github.com/scikit-learn/scikit-learn.git

NOTA: Windows el usuario deberá instalar Microsoft Visual C++ 14. Puedes conseguirlo en aquí

Ejemplo de Scikit-Learn con aprendizaje automático

Este tutorial de Scikit se divide en dos partes:

  1. Aprendizaje automático con scikit-learn
  2. Cómo confiar en tu modelo con LIME

La primera parte detalla cómo construir una canalización, crear un modelo y ajustar los hiperparámetros, mientras que la segunda parte proporciona información de última generación en términos de selección de modelos.

Paso 1) Importar los datos

Durante este tutorial de aprendizaje de Scikit, utilizará el conjunto de datos para adultos.

Para conocer los antecedentes de este conjunto de datos, consulte Si está interesado en saber más sobre las estadísticas descriptivas, utilice las herramientas de inmersión y descripción general.

Remitir este tutorial aprende más sobre buceo y descripción general

Importas el conjunto de datos con Pandas. Tenga en cuenta que necesita convertir el tipo de variables continuas en formato flotante.

Este conjunto de datos incluye ocho variables categóricas:

Las variables categóricas se enumeran en CATE_FEATURES

  • clase de trabajo
  • educación
  • marital
  • Ocupación.
  • relación
  • raza
  • vie
  • patria

además, seis variables continuas:

Las variables continuas se enumeran en CONTI_FEATURES

  • edad
  • fnlwgt
  • núm_educación
  • ganancia capital
  • perdida de capital
  • horas_semana

Tenga en cuenta que completamos la lista a mano para que tenga una mejor idea de qué columnas estamos usando. Una forma más rápida de construir una lista categórica o continua es utilizar:

## List Categorical
CATE_FEATURES = df_train.iloc[:,:-1].select_dtypes('object').columns
print(CATE_FEATURES)

## List continuous
CONTI_FEATURES =  df_train._get_numeric_data()
print(CONTI_FEATURES)

Aquí está el código para importar los datos:

# Import dataset
import pandas as pd

## Define path data
COLUMNS = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital',
           'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss',
           'hours_week', 'native_country', 'label']
### Define continuous list
CONTI_FEATURES  = ['age', 'fnlwgt','capital_gain', 'education_num', 'capital_loss', 'hours_week']
### Define categorical list
CATE_FEATURES = ['workclass', 'education', 'marital', 'occupation', 'relationship', 'race', 'sex', 'native_country']

## Prepare the data
features = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital',
           'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss',
           'hours_week', 'native_country']

PATH = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data"

df_train = pd.read_csv(PATH, skipinitialspace=True, names = COLUMNS, index_col=False)
df_train[CONTI_FEATURES] =df_train[CONTI_FEATURES].astype('float64')
df_train.describe()
edad fnlwgt núm_educación ganancia capital perdida de capital horas_semana
contar 32561.000000 3.256100e + 04 32561.000000 32561.000000 32561.000000 32561.000000
mean 38.581647 1.897784e + 05 10.080679 1077.648844 87.303830 40.437456
enfermedades de transmisión sexual 13.640433 1.055500e + 05 2.572720 7385.292085 402.960219 12.347429
min 17.000000 1.228500e + 04 1.000000 0.000000 0.000000 1.000000
25% 28.000000 1.178270e + 05 9.000000 0.000000 0.000000 40.000000
50% 37.000000 1.783560e + 05 10.000000 0.000000 0.000000 40.000000
75% 48.000000 2.370510e + 05 12.000000 0.000000 0.000000 45.000000
max 90.000000 1.484705e + 06 16.000000 99999.000000 4356.000000 99.000000

Puede comprobar el recuento de valores únicos de las características de país_nativo. Se puede ver que sólo un hogar proviene de Holanda-Países Bajos. Este hogar no nos traerá ninguna información, pero sí lo hará por un error durante el entrenamiento.

df_train.native_country.value_counts()
United-States                 29170
Mexico                          643
?                               583
Philippines                     198
Germany                         137
Canada                          121
Puerto-Rico                     114
El-Salvador                     106
India                           100
Cuba                             95
England                          90
Jamaica                          81
South                            80
China                            75
Italy                            73
Dominican-Republic               70
Vietnam                          67
Guatemala                        64
Japan                            62
Poland                           60
Columbia                         59
Taiwan                           51
Haiti                            44
Iran                             43
Portugal                         37
Nicaragua                        34
Peru                             31
France                           29
Greece                           29
Ecuador                          28
Ireland                          24
Hong                             20
Cambodia                         19
Trinadad&Tobago                  19
Thailand                         18
Laos                             18
Yugoslavia                       16
Outlying-US(Guam-USVI-etc)       14
Honduras                         13
Hungary                          13
Scotland                         12
Holand-Netherlands                1
Name: native_country, dtype: int64

Puede excluir esta fila no informativa del conjunto de datos.

## Drop Netherland, because only one row
df_train = df_train[df_train.native_country != "Holand-Netherlands"]

A continuación, almacena la posición de las entidades continuas en una lista. Lo necesitará en el siguiente paso para construir la tubería.

El siguiente código recorrerá todos los nombres de las columnas en CONTI_FEATURES y obtendrá su ubicación (es decir, su número) y luego lo agregará a una lista llamada conti_features

## Get the column index of the categorical features
conti_features = []
for i in CONTI_FEATURES:
    position = df_train.columns.get_loc(i)
    conti_features.append(position)
print(conti_features)  
[0, 2, 10, 4, 11, 12]

El siguiente código hace el mismo trabajo que el anterior pero para la variable categórica. El siguiente código repite lo que ha hecho anteriormente, excepto con las características categóricas.

## Get the column index of the categorical features
categorical_features = []
for i in CATE_FEATURES:
    position = df_train.columns.get_loc(i)
    categorical_features.append(position)
print(categorical_features)  
[1, 3, 5, 6, 7, 8, 9, 13]

Puedes echar un vistazo al conjunto de datos. Tenga en cuenta que cada característica categórica es una cadena. No puede alimentar un modelo con un valor de cadena. Necesita transformar el conjunto de datos utilizando una variable ficticia.

df_train.head(5)

De hecho, necesitas crear una columna para cada grupo de la función. Primero, puede ejecutar el código siguiente para calcular la cantidad total de columnas necesarias.

print(df_train[CATE_FEATURES].nunique(),
      'There are',sum(df_train[CATE_FEATURES].nunique()), 'groups in the whole dataset')
workclass          9
education         16
marital            7
occupation        15
relationship       6
race               5
sex                2
native_country    41
dtype: int64 There are 101 groups in the whole dataset

El conjunto de datos completo contiene 101 grupos, como se muestra arriba. Por ejemplo, las características de workclass tienen nueve grupos. Puedes visualizar el nombre de los grupos con los siguientes códigos

Unique() devuelve los valores únicos de las características categóricas.

for i in CATE_FEATURES:
    print(df_train[i].unique())
['State-gov' 'Self-emp-not-inc' 'Private' 'Federal-gov' 'Local-gov' '?'
 'Self-emp-inc' 'Without-pay' 'Never-worked']
['Bachelors' 'HS-grad' '11th' 'Masters' '9th' 'Some-college' 'Assoc-acdm'
 'Assoc-voc' '7th-8th' 'Doctorate' 'Prof-school' '5th-6th' '10th'
 '1st-4th' 'Preschool' '12th']
['Never-married' 'Married-civ-spouse' 'Divorced' 'Married-spouse-absent'
 'Separated' 'Married-AF-spouse' 'Widowed']
['Adm-clerical' 'Exec-managerial' 'Handlers-cleaners' 'Prof-specialty'
 'Other-service' 'Sales' 'Craft-repair' 'Transport-moving'
 'Farming-fishing' 'Machine-op-inspct' 'Tech-support' '?'
 'Protective-serv' 'Armed-Forces' 'Priv-house-serv']
['Not-in-family' 'Husband' 'Wife' 'Own-child' 'Unmarried' 'Other-relative']
['White' 'Black' 'Asian-Pac-Islander' 'Amer-Indian-Eskimo' 'Other']
['Male' 'Female']
['United-States' 'Cuba' 'Jamaica' 'India' '?' 'Mexico' 'South'
 'Puerto-Rico' 'Honduras' 'England' 'Canada' 'Germany' 'Iran'
 'Philippines' 'Italy' 'Poland' 'Columbia' 'Cambodia' 'Thailand' 'Ecuador'
 'Laos' 'Taiwan' 'Haiti' 'Portugal' 'Dominican-Republic' 'El-Salvador'
 'France' 'Guatemala' 'China' 'Japan' 'Yugoslavia' 'Peru'
 'Outlying-US(Guam-USVI-etc)' 'Scotland' 'Trinadad&Tobago' 'Greece'
 'Nicaragua' 'Vietnam' 'Hong' 'Ireland' 'Hungary']

Por lo tanto, el conjunto de datos de entrenamiento contendrá 101 + 7 columnas. Las últimas siete columnas son las características continuas.

Scikit-learn puede encargarse de la conversión. Se realiza en dos pasos:

  • Primero, necesitas convertir la cadena a ID. Por ejemplo, State-gov tendrá el ID 1, Self-emp-not-inc ID 2, etc. La función LabelEncoder hace esto por usted
  • Transponga cada ID a una nueva columna. Como se mencionó anteriormente, el conjunto de datos tiene 101 ID de grupo. Por lo tanto, habrá 101 columnas que capturarán todos los grupos de características categóricas. Scikit-learn tiene una función llamada OneHotEncoder que realiza esta operación

Paso 2) Crear el conjunto de tren/prueba

Ahora que el conjunto de datos está listo, podemos dividirlo 80/20.

80 por ciento para el conjunto de entrenamiento y 20 por ciento para el conjunto de prueba.

Puedes usar train_test_split. El primer argumento es el marco de datos de las características y el segundo argumento es el marco de datos de la etiqueta. Puede especificar el tamaño del conjunto de prueba con test_size.

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(df_train[features],
                                                    df_train.label,
                                                    test_size = 0.2,
                                                    random_state=0)
X_train.head(5)
print(X_train.shape, X_test.shape)
(26048, 14) (6512, 14)

Paso 3) Construya la tubería

La canalización facilita la alimentación del modelo con datos consistentes.

La idea detrás es poner los datos sin procesar en una "canalización" para realizar operaciones.

Por ejemplo, con el conjunto de datos actual, es necesario estandarizar las variables continuas y convertir los datos categóricos. Tenga en cuenta que puede realizar cualquier operación dentro de la tubería. Por ejemplo, si tiene "NA" en el conjunto de datos, puede reemplazarlos por la media o mediana. También puedes crear nuevas variables.

Tienes la opción; codifique los dos procesos o cree una canalización. La primera opción puede provocar una fuga de datos y crear inconsistencias con el tiempo. Una mejor opción es utilizar la tubería.

from sklearn.preprocessing import StandardScaler, OneHotEncoder, LabelEncoder
from sklearn.compose import ColumnTransformer, make_column_transformer
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression

El oleoducto realizará dos operaciones antes de alimentar el clasificador logístico:

  1. Estandarizar la variable: `StandardScaler()“
  2. Convierta las características categóricas: OneHotEncoder(sparse=False)

Puede realizar los dos pasos utilizando make_column_transformer. Esta función no está disponible en la versión actual de scikit-learn (0.19). Con la versión actual no es posible realizar el codificador de etiquetas y un codificador activo en proceso. Es una de las razones por las que decidimos utilizar la versión para desarrolladores.

make_column_transformer es fácil de usar. Debe definir qué columnas aplicar la transformación y qué transformación operar. Por ejemplo, para estandarizar la característica continua, puede hacer:

  • conti_features, StandardScaler() dentro de make_column_transformer.
    • conti_features: lista con la variable continua
    • StandardScaler: estandariza la variable

El objeto OneHotEncoder dentro de make_column_transformer codifica automáticamente la etiqueta.

preprocess = make_column_transformer(
    (conti_features, StandardScaler()),
    ### Need to be numeric not string to specify columns name 
    (categorical_features, OneHotEncoder(sparse=False))
)

Puede probar si la canalización funciona con fit_transform. El conjunto de datos debe tener la siguiente forma: 26048, 107

preprocess.fit_transform(X_train).shape
(26048, 107)

El transformador de datos está listo para usar. Puede crear la canalización con make_pipeline. Una vez transformados los datos, puede alimentar la regresión logística.

model = make_pipeline(
    preprocess,
    LogisticRegression())

Entrenar un modelo con scikit-learn es trivial. Debe utilizar el ajuste del objeto precedido por la canalización, es decir, el modelo. Puede imprimir la precisión con el objeto de puntuación de la biblioteca scikit-learn

model.fit(X_train, y_train)
print("logistic regression score: %f" % model.score(X_test, y_test))
logistic regression score: 0.850891

Finalmente, puedes predecir las clases con predict_proba. Devuelve la probabilidad de cada clase. Tenga en cuenta que suma uno.

model.predict_proba(X_test)
array([[0.83576663, 0.16423337],
       [0.94582765, 0.05417235],
       [0.64760587, 0.35239413],
       ...,
       [0.99639252, 0.00360748],
       [0.02072181, 0.97927819],
       [0.56781353, 0.43218647]])

Paso 4) Usar nuestro pipeline en una búsqueda en grid

Ajustar los hiperparámetros (variables que determinan la estructura de la red como unidades ocultas) puede resultar tedioso y agotador.

Una forma de evaluar el modelo podría ser cambiar el tamaño del conjunto de entrenamiento y evaluar el desempeño.

Puede repetir este método diez veces para ver las métricas de puntuación. Sin embargo, es demasiado trabajo.

En cambio, scikit-learn proporciona una función para realizar el ajuste de parámetros y la validación cruzada.

Validación cruzada

La validación cruzada significa que durante el entrenamiento, el conjunto de entrenamiento se desliza n veces en pliegues y luego evalúa el modelo n veces. Por ejemplo, si cv se establece en 10, el conjunto de entrenamiento se entrena y se evalúa diez veces. En cada ronda, el clasificador elige aleatoriamente nueve pliegues para entrenar el modelo, y el décimo pliegue está destinado a la evaluación.

búsqueda de cuadrícula

Cada clasificador tiene hiperparámetros para ajustar. Puede probar diferentes valores o puede establecer una cuadrícula de parámetros. Si visita el sitio web oficial de scikit-learn, podrá ver que el clasificador logístico tiene diferentes parámetros para ajustar. Para hacer que el entrenamiento sea más rápido, elige ajustar el parámetro C. Controla el parámetro de regularización. Debería ser positivo. Un valor pequeño le da más peso al regularizador.

Puedes utilizar el objeto GridSearchCV. Debe crear un diccionario que contenga los hiperparámetros para ajustar.

Enumera los hiperparámetros seguidos de los valores que desea probar. Por ejemplo, para ajustar el parámetro C, se utiliza:

  • ‘logisticregression__C’: [0.1, 1.0, 1.0]: El parámetro está precedido por el nombre, en minúscula, del clasificador y dos guiones bajos.

El modelo probará cuatro valores diferentes: 0.001, 0.01, 0.1 y 1.

Entrenas el modelo usando 10 pliegues: cv=10

from sklearn.model_selection import GridSearchCV
# Construct the parameter grid
param_grid = {
    'logisticregression__C': [0.001, 0.01,0.1, 1.0],
    }

Puedes entrenar el modelo usando GridSearchCV con los parámetros gri y cv.

# Train the model
grid_clf = GridSearchCV(model,
                        param_grid,
                        cv=10,
                        iid=False)
grid_clf.fit(X_train, y_train)

SALIDA

GridSearchCV(cv=10, error_score='raise-deprecating',
       estimator=Pipeline(memory=None,
     steps=[('columntransformer', ColumnTransformer(n_jobs=1, remainder='drop', transformer_weights=None,
         transformers=[('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True), [0, 2, 10, 4, 11, 12]), ('onehotencoder', OneHotEncoder(categorical_features=None, categories=None,...ty='l2', random_state=None, solver='liblinear', tol=0.0001,
          verbose=0, warm_start=False))]),
       fit_params=None, iid=False, n_jobs=1,
       param_grid={'logisticregression__C': [0.001, 0.01, 0.1, 1.0]},
       pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',
       scoring=None, verbose=0)

Para acceder a los mejores parámetros, utilice best_params_

grid_clf.best_params_

SALIDA

{'logisticregression__C': 1.0}

Después de entrenar el modelo con cuatro valores de regularización diferentes, el parámetro óptimo es

print("best logistic regression from grid search: %f" % grid_clf.best_estimator_.score(X_test, y_test))

mejor regresión logística de búsqueda en cuadrícula: 0.850891

Para acceder a las probabilidades previstas:

grid_clf.best_estimator_.predict_proba(X_test)
array([[0.83576677, 0.16423323],
       [0.9458291 , 0.0541709 ],
       [0.64760416, 0.35239584],
       ...,
       [0.99639224, 0.00360776],
       [0.02072033, 0.97927967],
       [0.56782222, 0.43217778]])

Modelo XGBoost con scikit-learn

Probemos ejemplos de Scikit-learn para entrenar uno de los mejores clasificadores del mercado. XGBoost es una mejora con respecto al bosque aleatorio. Los antecedentes teóricos del clasificador fuera del alcance de este Python Tutorial de ciencia ficción. Tenga en cuenta que XGBoost ha ganado muchas competiciones de Kaggle. Con un tamaño de conjunto de datos promedio, puede funcionar tan bien como un algoritmo de aprendizaje profundo o incluso mejor.

El clasificador es un desafío de entrenar porque tiene una gran cantidad de parámetros que ajustar. Por supuesto, puede utilizar GridSearchCV para elegir el parámetro por usted.

En cambio, veamos cómo utilizar una mejor manera de encontrar los parámetros óptimos. GridSearchCV puede ser tedioso y muy largo de entrenar si pasas muchos valores. El espacio de búsqueda crece junto con el número de parámetros. Una solución preferible es utilizar RandomizedSearchCV. Este método consiste en elegir los valores de cada hiperparámetro después de cada iteración de forma aleatoria. Por ejemplo, si el clasificador se entrena durante 1000 iteraciones, se evalúan 1000 combinaciones. Funciona más o menos así. CuadrículaBuscarCV

Necesitas importar xgboost. Si la biblioteca no está instalada, utilice pip3 install xgboost o

use import sys
!{sys.executable} -m pip install xgboost

In Jupyter entorno empresarial

Siguiente,

import xgboost
from sklearn.model_selection import RandomizedSearchCV
from sklearn.model_selection import StratifiedKFold

El siguiente paso en este Scikit Python El tutorial incluye la especificación de los parámetros a ajustar. Puede consultar la documentación oficial para ver todos los parámetros a ajustar. Por el bien de Python En el tutorial de Sklearn, solo elige dos hiperparámetros con dos valores cada uno. XGBoost requiere mucho tiempo para entrenar; cuantos más hiperparámetros haya en la cuadrícula, más tiempo deberá esperar.

params = {
        'xgbclassifier__gamma': [0.5, 1],
        'xgbclassifier__max_depth': [3, 4]
        }

Construye una nueva canalización con el clasificador XGBoost. Elige definir 600 estimadores. Ten en cuenta que n_estimators es un parámetro que puedes ajustar. Un valor alto puede provocar un sobreajuste. Puedes probar con distintos valores por tu cuenta, pero ten en cuenta que puede llevar horas. Utiliza el valor predeterminado para los demás parámetros.

model_xgb = make_pipeline(
    preprocess,
    xgboost.XGBClassifier(
                          n_estimators=600,
                          objective='binary:logistic',
                          silent=True,
                          nthread=1)
)

Puede mejorar la validación cruzada con el validador cruzado Stratified K-Folds. Aquí construye solo tres pliegues para acelerar el cálculo pero reduciendo la calidad. Incrementa este valor a 5 o 10 en casa para mejorar los resultados.

Eliges entrenar el modelo en cuatro iteraciones.

skf = StratifiedKFold(n_splits=3,
                      shuffle = True,
                      random_state = 1001)

random_search = RandomizedSearchCV(model_xgb,
                                   param_distributions=params,
                                   n_iter=4,
                                   scoring='accuracy',
                                   n_jobs=4,
                                   cv=skf.split(X_train, y_train),
                                   verbose=3,
                                   random_state=1001)

La búsqueda aleatoria está lista para usar, puedes entrenar el modelo

#grid_xgb = GridSearchCV(model_xgb, params, cv=10, iid=False)
random_search.fit(X_train, y_train)
Fitting 3 folds for each of 4 candidates, totalling 12 fits
[CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5 ............
[CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5 ............
[CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5 ............
[CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5 ............
[CV]  xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5, score=0.8759645283888057, total= 1.0min
[CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5 ............
[CV]  xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5, score=0.8729701715996775, total= 1.0min
[CV]  xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5, score=0.8706519235199263, total= 1.0min
[CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5 ............
[CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1 ..............
[CV]  xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5, score=0.8735460094437406, total= 1.3min
[CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1 ..............
[CV]  xgbclassifier__max_depth=3, xgbclassifier__gamma=1, score=0.8722791661868018, total=  57.7s
[CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1 ..............
[CV]  xgbclassifier__max_depth=3, xgbclassifier__gamma=1, score=0.8753886905447426, total= 1.0min
[CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1 ..............
[CV]  xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5, score=0.8697304768486523, total= 1.3min
[CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1 ..............
[CV]  xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5, score=0.8740066797189912, total= 1.4min
[CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1 ..............
[CV]  xgbclassifier__max_depth=3, xgbclassifier__gamma=1, score=0.8707671043538355, total= 1.0min
[CV]  xgbclassifier__max_depth=4, xgbclassifier__gamma=1, score=0.8729701715996775, total= 1.2min
[Parallel(n_jobs=4)]: Done  10 out of  12 | elapsed:  3.6min remaining:   43.5s
[CV]  xgbclassifier__max_depth=4, xgbclassifier__gamma=1, score=0.8736611770125533, total= 1.2min
[CV]  xgbclassifier__max_depth=4, xgbclassifier__gamma=1, score=0.8692697535130154, total= 1.2min
[Parallel(n_jobs=4)]: Done  12 out of  12 | elapsed:  3.6min finished
/Users/Thomas/anaconda3/envs/hello-tf/lib/python3.6/site-packages/sklearn/model_selection/_search.py:737: DeprecationWarning: The default of the `iid` parameter will change from True to False in version 0.22 and will be removed in 0.24. This will change numeric results when test-set sizes are unequal. DeprecationWarning)
RandomizedSearchCV(cv=<generator object _BaseKFold.split at 0x1101eb830>,
          error_score='raise-deprecating',
          estimator=Pipeline(memory=None,
     steps=[('columntransformer', ColumnTransformer(n_jobs=1, remainder='drop', transformer_weights=None,
         transformers=[('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True), [0, 2, 10, 4, 11, 12]), ('onehotencoder', OneHotEncoder(categorical_features=None, categories=None,...
       reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None,
       silent=True, subsample=1))]),
          fit_params=None, iid='warn', n_iter=4, n_jobs=4,
          param_distributions={'xgbclassifier__gamma': [0.5, 1], 'xgbclassifier__max_depth': [3, 4]},
          pre_dispatch='2*n_jobs', random_state=1001, refit=True,
          return_train_score='warn', scoring='accuracy', verbose=3)

Como puede ver, XGBoost tiene una mejor puntuación que la regresión logística anterior.

print("Mejores parameter", random_search.best_params_)
print("best logistic regression from grid search: %f" % random_search.best_estimator_.score(X_test, y_test))
Mejores parameter {'xgbclassifier__max_depth': 3, 'xgbclassifier__gamma': 0.5}
best logistic regression from grid search: 0.873157
random_search.best_estimator_.predict(X_test)
array(['<=50K', '<=50K', '<=50K', ..., '<=50K', '>50K', '<=50K'],      dtype=object)

Cree DNN con MLPClassifier en scikit-learn

Finalmente, puedes entrenar un algoritmo de aprendizaje profundo con scikit-learn. El método es el mismo que el del otro clasificador. El clasificador está disponible en MLPClassifier.

from sklearn.neural_network import MLPClassifier

Define el siguiente algoritmo de aprendizaje profundo:

  • Adán solucionador
  • Función de activación de Relu
  • Alfa = 0.0001
  • tamaño de lote de 150
  • Dos capas ocultas con 100 y 50 neuronas respectivamente
model_dnn = make_pipeline(
    preprocess,
    MLPClassifier(solver='adam',
                  alpha=0.0001,
                  activation='relu',
                    batch_size=150,
                    hidden_layer_sizes=(200, 100),
                    random_state=1))

Puedes cambiar el número de capas para mejorar el modelo.

model_dnn.fit(X_train, y_train)
  print("DNN regression score: %f" % model_dnn.score(X_test, y_test))

Puntuación de regresión DNN: 0.821253

LIME: Confía en tu modelo

Ahora que tienes un buen modelo, necesitas una herramienta en la que confiar. Aprendizaje automático Se sabe que los algoritmos, especialmente los de bosque aleatorio y redes neuronales, son algoritmos de caja negra. Dicho de otro modo, funcionan, pero nadie sabe por qué.

Tres investigadores han ideado una gran herramienta para ver cómo el ordenador hace una predicción. El documento se llama ¿Por qué debería confiar en ti?

Desarrollaron un algoritmo llamado Explicaciones locales interpretables agnósticas del modelo (LIME).

Tome un ejemplo:

A veces no sabes si puedes confiar en una predicción de aprendizaje automático:

Un médico, por ejemplo, no puede confiar en un diagnóstico sólo porque una computadora lo dice. También necesita saber si puede confiar en el modelo antes de ponerlo en producción.

Imaginemos que podemos entender por qué cualquier clasificador hace una predicción incluso en modelos increíblemente complicados como redes neuronales, bosques aleatorios o svms con cualquier núcleo.

Será más accesible confiar en una predicción si podemos entender las razones detrás de ella. Del ejemplo del médico, si el modelo le dijera qué síntomas son esenciales usted confiaría en él, también es más fácil determinar si no debe confiar en el modelo.

Lime puede decirte qué características afectan las decisiones del clasificador.

Preparación de datos

Son un par de cosas que debes cambiar para ejecutar LIME. pitón. En primer lugar, necesitas instalar cal en el terminal. Puedes usar pip install lime

Lime utiliza el objeto LimeTabularExplainer para aproximar el modelo localmente. Este objeto requiere:

  • un conjunto de datos en formato numpy
  • El nombre de las funciones: feature_names
  • El nombre de las clases: class_names
  • El índice de la columna de características categóricas: categorical_features
  • El nombre del grupo para cada característica categórica: categorical_names

Crear un conjunto de trenes numeroso

Puedes copiar y convertir df_train de pandas a numpy muy facilmente

df_train.head(5)
# Create numpy data
df_lime = df_train
df_lime.head(3)

Obtener el nombre de la clase Se puede acceder a la etiqueta con el objeto único(). Debería ver:

  • '<= 50 K'
  • '> 50K'
# Get the class name
class_names = df_lime.label.unique()
class_names
array(['<=50K', '>50K'], dtype=object)

índice de la columna de las características categóricas

Puede utilizar el método que utilizó antes para obtener el nombre del grupo. Codifica la etiqueta con LabelEncoder. Repites la operación en todas las características categóricas.

## 
import sklearn.preprocessing as preprocessing
categorical_names = {}
for feature in CATE_FEATURES:
    le = preprocessing.LabelEncoder()
    le.fit(df_lime[feature])
    df_lime[feature] = le.transform(df_lime[feature])
    categorical_names[feature] = le.classes_
print(categorical_names)    
{'workclass': array(['?', 'Federal-gov', 'Local-gov', 'Never-worked', 'Private',
       'Self-emp-inc', 'Self-emp-not-inc', 'State-gov', 'Without-pay'],
      dtype=object), 'education': array(['10th', '11th', '12th', '1st-4th', '5th-6th', '7th-8th', '9th',
       'Assoc-acdm', 'Assoc-voc', 'Bachelors', 'Doctorate', 'HS-grad',
       'Masters', 'Preschool', 'Prof-school', 'Some-college'],
      dtype=object), 'marital': array(['Divorced', 'Married-AF-spouse', 'Married-civ-spouse',
       'Married-spouse-absent', 'Never-married', 'Separated', 'Widowed'],
      dtype=object), 'occupation': array(['?', 'Adm-clerical', 'Armed-Forces', 'Craft-repair',
       'Exec-managerial', 'Farming-fishing', 'Handlers-cleaners',
       'Machine-op-inspct', 'Other-service', 'Priv-house-serv',
       'Prof-specialty', 'Protective-serv', 'Sales', 'Tech-support',
       'Transport-moving'], dtype=object), 'relationship': array(['Husband', 'Not-in-family', 'Other-relative', 'Own-child',
       'Unmarried', 'Wife'], dtype=object), 'race': array(['Amer-Indian-Eskimo', 'Asian-Pac-Islander', 'Black', 'Other',
       'White'], dtype=object), 'sex': array(['Female', 'Male'], dtype=object), 'native_country': array(['?', 'Cambodia', 'Canada', 'China', 'Columbia', 'Cuba',
       'Dominican-Republic', 'Ecuador', 'El-Salvador', 'England',
       'France', 'Germany', 'Greece', 'Guatemala', 'Haiti', 'Honduras',
       'Hong', 'Hungary', 'India', 'Iran', 'Ireland', 'Italy', 'Jamaica',
       'Japan', 'Laos', 'Mexico', 'Nicaragua',
       'Outlying-US(Guam-USVI-etc)', 'Peru', 'Philippines', 'Poland',
       'Portugal', 'Puerto-Rico', 'Scotland', 'South', 'Taiwan',
       'Thailand', 'Trinadad&Tobago', 'United-States', 'Vietnam',
       'Yugoslavia'], dtype=object)}

df_lime.dtypes
age               float64
workclass           int64
fnlwgt            float64
education           int64
education_num     float64
marital             int64
occupation          int64
relationship        int64
race                int64
sex                 int64
capital_gain      float64
capital_loss      float64
hours_week        float64
native_country      int64
label              object
dtype: object

Ahora que el conjunto de datos está listo, puede construir el conjunto de datos diferente como se muestra en los ejemplos de aprendizaje de Scikit a continuación. En realidad, transforma los datos fuera de la canalización para evitar errores con LIME. El conjunto de entrenamiento en LimeTabularExplainer debe ser una matriz numerosa sin cadena. Con el método anterior, ya tienes un conjunto de datos de entrenamiento convertido.

from sklearn.model_selection import train_test_split
X_train_lime, X_test_lime, y_train_lime, y_test_lime = train_test_split(df_lime[features],
                                                    df_lime.label,
                                                    test_size = 0.2,
                                                    random_state=0)
X_train_lime.head(5)

Puedes hacer el pipeline con los parámetros óptimos de XGBoost

model_xgb = make_pipeline(
    preprocess,
    xgboost.XGBClassifier(max_depth = 3,
                          gamma = 0.5,
                          n_estimators=600,
                          objective='binary:logistic',
                          silent=True,
                          nthread=1))

model_xgb.fit(X_train_lime, y_train_lime)
/Users/Thomas/anaconda3/envs/hello-tf/lib/python3.6/site-packages/sklearn/preprocessing/_encoders.py:351: FutureWarning: The handling of integer data will change in version 0.22. Currently, the categories are determined based on the range [0, max(values)], while in the future they will be determined based on the unique values.
If you want the future behavior and silence this warning, you can specify "categories='auto'."In case you used a LabelEncoder before this OneHotEncoder to convert the categories to integers, then you can now use the OneHotEncoder directly.
  warnings.warn(msg, FutureWarning)
Pipeline(memory=None,
     steps=[('columntransformer', ColumnTransformer(n_jobs=1, remainder='drop', transformer_weights=None,
         transformers=[('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True), [0, 2, 10, 4, 11, 12]), ('onehotencoder', OneHotEncoder(categorical_features=None, categories=None,...
       reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None,
       silent=True, subsample=1))])

Recibirá una advertencia. La advertencia explica que no necesita crear un codificador de etiquetas antes de la canalización. Si no desea utilizar LIME, puede utilizar el método de la primera parte del tutorial de aprendizaje automático con Scikit-learn. De lo contrario, puede continuar con este método. Primero, cree un conjunto de datos codificados y configure el codificador de etiquetas dentro de la canalización.

print("best logistic regression from grid search: %f" % model_xgb.score(X_test_lime, y_test_lime))
best logistic regression from grid search: 0.873157
model_xgb.predict_proba(X_test_lime)
array([[7.9646105e-01, 2.0353897e-01],
       [9.5173013e-01, 4.8269872e-02],
       [7.9344827e-01, 2.0655173e-01],
       ...,
       [9.9031430e-01, 9.6856682e-03],
       [6.4581633e-04, 9.9935418e-01],
       [9.7104281e-01, 2.8957171e-02]], dtype=float32)

Antes de utilizar LIME en acción, vamos a crear una matriz numpy con las características de la clasificación incorrecta. Puede utilizar esa lista más adelante para tener una idea de qué fue lo que engañó al clasificador.

temp = pd.concat([X_test_lime, y_test_lime], axis= 1)
temp['predicted'] = model_xgb.predict(X_test_lime)
temp['wrong']=  temp['label'] != temp['predicted']
temp = temp.query('wrong==True').drop('wrong', axis=1)
temp= temp.sort_values(by=['label'])
temp.shape

(826, 16)

Crea una función lambda para recuperar la predicción del modelo con los nuevos datos. Lo necesitarás pronto.

predict_fn = lambda x: model_xgb.predict_proba(x).astype(float)
X_test_lime.dtypes
age               float64
workclass           int64
fnlwgt            float64
education           int64
education_num     float64
marital             int64
occupation          int64
relationship        int64
race                int64
sex                 int64
capital_gain      float64
capital_loss      float64
hours_week        float64
native_country      int64
dtype: object
predict_fn(X_test_lime)
array([[7.96461046e-01, 2.03538969e-01],
       [9.51730132e-01, 4.82698716e-02],
       [7.93448269e-01, 2.06551731e-01],
       ...,
       [9.90314305e-01, 9.68566816e-03],
       [6.45816326e-04, 9.99354184e-01],
       [9.71042812e-01, 2.89571714e-02]])

Conviertes el marco de datos de pandas en una matriz numpy

X_train_lime = X_train_lime.values
X_test_lime = X_test_lime.values
X_test_lime
array([[4.00000e+01, 5.00000e+00, 1.93524e+05, ..., 0.00000e+00,
        4.00000e+01, 3.80000e+01],
       [2.70000e+01, 4.00000e+00, 2.16481e+05, ..., 0.00000e+00,
        4.00000e+01, 3.80000e+01],
       [2.50000e+01, 4.00000e+00, 2.56263e+05, ..., 0.00000e+00,
        4.00000e+01, 3.80000e+01],
       ...,
       [2.80000e+01, 6.00000e+00, 2.11032e+05, ..., 0.00000e+00,
        4.00000e+01, 2.50000e+01],
       [4.40000e+01, 4.00000e+00, 1.67005e+05, ..., 0.00000e+00,
        6.00000e+01, 3.80000e+01],
       [5.30000e+01, 4.00000e+00, 2.57940e+05, ..., 0.00000e+00,
        4.00000e+01, 3.80000e+01]])
model_xgb.predict_proba(X_test_lime)
array([[7.9646105e-01, 2.0353897e-01],
       [9.5173013e-01, 4.8269872e-02],
       [7.9344827e-01, 2.0655173e-01],
       ...,
       [9.9031430e-01, 9.6856682e-03],
       [6.4581633e-04, 9.9935418e-01],
       [9.7104281e-01, 2.8957171e-02]], dtype=float32)
print(features,
      class_names,
      categorical_features,
      categorical_names)
['age', 'workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country'] ['<=50K' '>50K'] [1, 3, 5, 6, 7, 8, 9, 13] {'workclass': array(['?', 'Federal-gov', 'Local-gov', 'Never-worked', 'Private',
       'Self-emp-inc', 'Self-emp-not-inc', 'State-gov', 'Without-pay'],
      dtype=object), 'education': array(['10th', '11th', '12th', '1st-4th', '5th-6th', '7th-8th', '9th',
       'Assoc-acdm', 'Assoc-voc', 'Bachelors', 'Doctorate', 'HS-grad',
       'Masters', 'Preschool', 'Prof-school', 'Some-college'],
      dtype=object), 'marital': array(['Divorced', 'Married-AF-spouse', 'Married-civ-spouse',
       'Married-spouse-absent', 'Never-married', 'Separated', 'Widowed'],
      dtype=object), 'occupation': array(['?', 'Adm-clerical', 'Armed-Forces', 'Craft-repair',
       'Exec-managerial', 'Farming-fishing', 'Handlers-cleaners',
       'Machine-op-inspct', 'Other-service', 'Priv-house-serv',
       'Prof-specialty', 'Protective-serv', 'Sales', 'Tech-support',
       'Transport-moving'], dtype=object), 'relationship': array(['Husband', 'Not-in-family', 'Other-relative', 'Own-child',
       'Unmarried', 'Wife'], dtype=object), 'race': array(['Amer-Indian-Eskimo', 'Asian-Pac-Islander', 'Black', 'Other',
       'White'], dtype=object), 'sex': array(['Female', 'Male'], dtype=object), 'native_country': array(['?', 'Cambodia', 'Canada', 'China', 'Columbia', 'Cuba',
       'Dominican-Republic', 'Ecuador', 'El-Salvador', 'England',
       'France', 'Germany', 'Greece', 'Guatemala', 'Haiti', 'Honduras',
       'Hong', 'Hungary', 'India', 'Iran', 'Ireland', 'Italy', 'Jamaica',
       'Japan', 'Laos', 'Mexico', 'Nicaragua',
       'Outlying-US(Guam-USVI-etc)', 'Peru', 'Philippines', 'Poland',
       'Portugal', 'Puerto-Rico', 'Scotland', 'South', 'Taiwan',
       'Thailand', 'Trinadad&Tobago', 'United-States', 'Vietnam',
       'Yugoslavia'], dtype=object)}
import lime
import lime.lime_tabular
### Train should be label encoded not one hot encoded
explainer = lime.lime_tabular.LimeTabularExplainer(X_train_lime ,
                                                   feature_names = features,
                                                   class_names=class_names,
                                                   categorical_features=categorical_features, 
                                                   categorical_names=categorical_names,
                                                   kernel_width=3)

Elijamos un hogar aleatorio del conjunto de prueba y veamos la predicción del modelo y cómo la computadora hizo su elección.

import numpy as np
np.random.seed(1)
i = 100
print(y_test_lime.iloc[i])
>50K
X_test_lime[i]
array([4.20000e+01, 4.00000e+00, 1.76286e+05, 7.00000e+00, 1.20000e+01,
       2.00000e+00, 4.00000e+00, 0.00000e+00, 4.00000e+00, 1.00000e+00,
       0.00000e+00, 0.00000e+00, 4.00000e+01, 3.80000e+01])

Puede utilizar el explicador con explicó_instancia para comprobar la explicación detrás del modelo.

exp = explainer.explain_instance(X_test_lime[i], predict_fn, num_features=6)
exp.show_in_notebook(show_all=False)

Preparación de datos

Podemos ver que el clasificador predijo correctamente el hogar. De hecho, los ingresos están por encima de los 50.

Lo primero que podemos decir es que el clasificador no está tan seguro de las probabilidades predichas. La máquina predice que el hogar tiene ingresos superiores a 50 con una probabilidad del 64%. Este 64% está compuesto por Ganancia de Capital y Matrimonial. El color azul contribuye negativamente a la clase positiva y la línea naranja, positivamente.

El clasificador se confunde porque la ganancia de capital de este hogar es nula, mientras que la ganancia de capital suele ser un buen predictor de la riqueza. Además, el hogar trabaja menos de 40 horas por semana. La edad, la ocupación y el sexo contribuyen positivamente al clasificador.

Si el estado civil fuera soltero, el clasificador habría predicho un ingreso inferior a 50 (0.64-0.18 = 0.46)

Podemos probar con otro hogar que haya sido clasificado erróneamente.

temp.head(3)
temp.iloc[1,:-2]
age                  58
workclass             4
fnlwgt            68624
education            11
education_num         9
marital               2
occupation            4
relationship          0
race                  4
sex                   1
capital_gain          0
capital_loss          0
hours_week           45
native_country       38
Name: 20931, dtype: object
i = 1
print('This observation is', temp.iloc[i,-2:])
This observation is label        <=50K
predicted     >50K
Name: 20931, dtype: object
exp = explainer.explain_instance(temp.iloc[1,:-2], predict_fn, num_features=6)
exp.show_in_notebook(show_all=False)

Preparación de datos

El clasificador predijo un ingreso inferior a 50, aunque esto no es cierto. Esta casa parece extraña. No tiene ganancia de capital, ni pérdida de capital. Está divorciado, tiene 60 años y es una persona educada, es decir, núm_educación > 12. Según el patrón general, este hogar debería, como lo explica el clasificador, obtener un ingreso inferior a 50 XNUMX.

Intentas jugar con LIME. Notará errores graves por parte del clasificador.

Puedes consultar el GitHub del propietario de la biblioteca. Proporcionan documentación adicional para la clasificación de imágenes y textos.

Resumen

A continuación se muestra una lista de algunos comandos útiles con la versión de scikit learn >=0.20

crear un conjunto de datos de tren/prueba los alumnos se dividen
construir una tubería
seleccione la columna y aplique la transformación hacer transformador de columna
tipo de transformación
estandarizar Escalador estándar
mínimo máximo Escalador MínMáx
Normalizar Normalizador
Imputar valor faltante imputar
Convertir categórico OneHotEncoder
Ajustar y transformar los datos encajar_transformar
hacer la tubería hacer_tubería
Modelo basica
regresión logística Regresión logística
XGBoost Clasificador XGB
Red neuronal Clasificador MLP
búsqueda de cuadrícula CuadrículaBuscarCV
Búsqueda aleatoria Búsqueda aleatoriaCV