Imports generales
In [1]:
import numpy as np
import pandas as pd
from sklearn import preprocessing
from sklearn.cross_validation import train_test_split
from helpers.models import fit_model
from helpers.helpers import make_binary, class_info
# set random state for camparability
random_state = np.random.RandomState(0)
In [2]:
# read data
context = pd.read_csv('data/muestra_variables.csv')
# select variable columns
cols_select = context.columns[6:]
variables = context.ix[:,cols_select]
for c in ['no_se','uname','content','cve_mza']:
del variables[c]
# reclass intervalo as numerical
def intervalo_to_numbers(x):
equiv = {'sun':0,'mon':1,'tue':2,'wed':3,'thu':4,'fri':5,'sat':6,'sun':7}
interval = 0.16666*int(x.split('.')[1])
day = x.split('.')[0]
valor = equiv[day] + interval
return valor
reclass = variables['intervalo'].apply(intervalo_to_numbers)
# drop old 'intervalo' column and replace it with numerical values
del variables['intervalo']
variables = variables.join(reclass,how='inner')
Obtener los datos como np.array y separar los datos en predictor (X) y objetivo (Y)
In [19]:
data = variables.as_matrix()
data_Y = data[:,0]
data_X = data[:,1:]
print("Initial label distribution")
class_info(data_Y)
Eliminar los datos con etiqueta 4 (no sé que sean)
In [20]:
data_X, data_Y = data_X[data_Y != 4], data_Y[data_Y != 4]
Hacemos dos binarizaciones de los datos, en una agregamos las clases Pos y Neu (etiquetas 1 y 2) y en la otra agregamos Neg Y Neu (etiquetas 3 y 2).
En el caso de la primera, el problema se convierte en encontrar todos los tuit no-positivos. Mientras que en la segunda, el problema es encontrar todos los no-negativos. Entonces, la etiqueta positiva en el primer caso son los no-negativos, mientras que en el segundo caso son los no-positivos.
In [21]:
Y_pos_neu = make_binary(data_Y, set((1.,2.)))
Y_neg_neu = make_binary(data_Y, set((3.,2.)))
print("Label distribution after binarization")
print("Pos + Neu")
class_info(Y_pos_neu)
print()
print("Neg + Neu")
class_info(Y_neg_neu)
Separamos en muestras de prueba (40%) y entrenamiento para ambas binarizaciones.
Más adelante podemos utilizar una estrategia de folds e iterar sobre ellos
In [22]:
(X_train_pos_neu, X_test_pos_neu,
Y_train_pos_neu, Y_test_pos_neu) = train_test_split(data_X, Y_pos_neu,
test_size=0.4,
random_state=random_state)
(X_train_neg_neu, X_test_neg_neu,
Y_train_neg_neu, Y_test_neg_neu) = train_test_split(data_X, Y_neg_neu,
test_size=0.4,
random_state=random_state)
Reescalamos las muestras de entrenamiento
In [23]:
X_pos_neu_s = preprocessing.scale(X_train_pos_neu)
X_neg_neu_s = preprocessing.scale(X_train_neg_neu)
In [8]:
param_grid = {'C': [1, 10, 100, 1000], 'gamma': [0.01,0.001, 0.0001],
'kernel': ['rbf']}
metrics = ['f1','accuracy','average_precision','roc_auc','recall']
Ahora sí, ajustamos las SVM con diferentes métricas, primero para la binarización Pos + Neu:
In [9]:
fitted_models_pos_neu = {}
for metric in metrics:
fitted_models_pos_neu[metric] = fit_model(X_pos_neu_s,Y_train_pos_neu,
param_grid,metric,6)
for metric, model in fitted_models_pos_neu.items():
print ("Using metric {}".format(metric))
print("Best parameters set found on development set:")
print()
print(model.best_params_)
print("Grid scores on development set:")
print()
for params, mean_score, scores in model.grid_scores_:
print("%0.3f (+/-%0.03f) for %r"
% (mean_score, scores.std() * 2, params))
print()
Ahora evaluamos sobre la mustra de prueba, para obtener los scores de validación:
In [26]:
#X_pos_neu_s_test = preprocessing.scale(X_test_pos_neu)
for metric, model in fitted_models_pos_neu.items():
this_estimator = fitted_models_pos_neu[metric].best_estimator_
this_score = this_estimator.score(X_pos_neu_s_test, Y_test_pos_neu)
y_pred = this_estimator.fit(X_pos_neu_s_test, Y_test_pos_neu).predict(X_pos_neu_s_test)
#conf_matrix = confusion_matrix(Y_test_pos_neu,y_pred)
df_confusion = pd.crosstab(Y_test_pos_neu, y_pred,
rownames=['Actual'],
colnames=['Predicted'], margins=True)
print ("Using metric {}".format(metric))
print("Validation score {}".format(this_score))
print("Confusion Matrix:")
print(df_confusion)
print()
Ahora lo mismo pero con la otra binarización, para hacer los dos casos comparables vamos a voltear las etiquetas de las clases:
In [24]:
Y_train_neg_neu = np.array([1 if val == 0 else 0 for val in Y_train_neg_neu])
fitted_models_neg_neu = {}
for metric in metrics:
fitted_models_neg_neu[metric] = fit_model(X_neg_neu_s,Y_train_neg_neu,
param_grid,metric,6)
for metric, model in fitted_models_neg_neu.items():
print ("Using metric {}".format(metric))
print("Best parameters set found on development set:")
print()
print(model.best_params_)
print("Grid scores on development set:")
print()
for params, mean_score, scores in model.grid_scores_:
print("%0.3f (+/-%0.03f) for %r"
% (mean_score, scores.std() * 2, params))
print()
Y sus métricas sobre la muestra test:
In [27]:
X_neg_neu_s_test = preprocessing.scale(X_test_neg_neu)
for metric, model in fitted_models_neg_neu.items():
this_estimator = fitted_models_neg_neu[metric].best_estimator_
this_score = this_estimator.score(X_neg_neu_s_test, Y_test_neg_neu)
y_pred = this_estimator.fit(X_neg_neu_s_test, Y_test_neg_neu).predict(X_neg_neu_s_test)
#conf_matrix = confusion_matrix(Y_test_pos_neu,y_pred)
df_confusion = pd.crosstab(Y_test_neg_neu, y_pred,
rownames=['Actual'],
colnames=['Predicted'], margins=True)
print ("Using metric {}".format(metric))
print("Validation score {}".format(this_score))
print()
print("Confusion Matrix:")
print(df_confusion)