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.
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:
- Aprendizaje automático con scikit-learn
- 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:
- Estandarizar la variable: `StandardScaler()“
- 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)
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)
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 |