Se agregan todas las columnas por cuenta del conjunto de datos usando funciones definida de clean_import.
from importlib import reload
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import ipywidgets as widgets
from ipywidgets import interact, interact_manual
import clean_import
reload(clean_import)
import clasificadores
reload(clasificadores)
from clasificadores import ClassifierGenerator
import visualization
reload(visualization)
from visualization import *
import warnings
warnings.filterwarnings("ignore")
data_dir = "../datos/"
data = clean_import.import_dataset(data_dir)
data = clean_import.filter_lang(data, 'English')
col = data.groupby('author').agg({'content' : 'count'})['content']
print('Hay {} cuentas en total'.format(col.size))
@interact
def graph_hist_count(percentil=(1,100,5), nmax=(0,10000,100)):
nmax = 20
percentil_val = np.percentile(col,percentil)
print('El percentil {} corresponde a aquellos con menos de {} tweets'.format(percentil, percentil_val))
print('Hay {1} cuentas con menos de {0} tweets, de un total de {2}'.format(percentil_val,
col[col > percentil_val].size,
col.size))
col_cut = col[col < nmax]
plt.figure(figsize=(10, 5))
plt.hist(col_cut, bins=50)
plt.title('Histograma para cuentas con mas de {} tweets'.format(nmax))
plt.show()
reload(clean_import)
account_data = clean_import.get_accounts(data, 1, 2)
del data
col = account_data['followers']['linear_slope']
percentil_val = np.percentile(col,90)
print('Hay {1} cuentas con mas de {0} popularidad, de un total de {2}'.format(percentil_val,
col[col > percentil_val].size,
col.size))
account_data.head()
Se analizan los n-gramas entre ngrammin y ngrammax, y las clases se dividen en los percentiles de percentiles.
# Configs
percentiles = np.array([50, 90]) # Percentiles para las clases
account_data_filtered = account_data.dropna(subset=[('followers', 'linear_slope')])
class_col = account_data_filtered['followers']['linear_slope'].values
ngrammin = 1
ngrammax = 3
training_frac = .2
# Clasificacion segun pais
countries = account_data_filtered['region']['first'].unique()
country_ids = np.arange(countries.size)
country_dict = dict(zip(country_ids, countries))
country_dict_inv = dict(zip(countries, country_ids))
country_id_col = account_data_filtered.loc[:, ('region','first')].apply(
lambda country : country_dict_inv[country])
account_categories = account_data_filtered['account_category']['first'].unique()
account_categories_ids = np.arange(account_categories.size)
account_categories_dict = dict(zip(account_categories_ids, account_categories))
account_categories_dict_inv = dict(zip(account_categories, account_categories_ids))
account_category_id_col = account_data_filtered.loc[:, ('region','first')].apply(
lambda country : country_dict_inv[country])
election_distance_col = account_data_filtered.loc[:, ('publish_date','election_distance_score')]
"""
Configura los distintos classifiergen que se usaran, para clasificacion numerica y de texto,
y para regresión numérica y de texto. Asi hacemos el preprocesamiento solo una vez
"""
# Set up clasificacion de texto
classifiergen_text = ClassifierGenerator()
classifiergen_text.set_classes(class_col, percentiles)
## Agregar atributos
classifiergen_text.add_attrib(account_data_filtered['content']['aggregate_content'], name='content')
## Preprocesar
classifiergen_text.preprocess_data(frac=training_frac, ngrammin=ngrammin, ngrammax=ngrammax)
# Set up clasificacion numerica
classifiergen_numeric = ClassifierGenerator()
classifiergen_numeric.set_classes(class_col, percentiles)
## Agregar atributos
classifiergen_numeric.add_attrib(account_data_filtered['updates']['max'], name='Maximum updates')
classifiergen_numeric.add_attrib(account_data_filtered['following']['max'], name='Maximum following')
classifiergen_numeric.add_attrib(country_id_col, name='Country ID')
classifiergen_numeric.add_attrib(election_distance_col, name='Election Activity Distance')
#classifiergen_numeric.add_attrib(account_category_id_col, name='Category_id')
# Preprocesar
classifiergen_numeric.preprocess_data(frac=training_frac)
# Set up regresion de texto
regressiongen_text = ClassifierGenerator()
regressiongen_text.set_values(class_col)
## Agregar atributos
regressiongen_text.add_attrib(account_data_filtered['content']['aggregate_content'], name='content')
## Preprocesar
regressiongen_text.preprocess_data(frac=training_frac, ngrammin=ngrammin, ngrammax=ngrammax)
# Set up regresion numerica
regressiongen_numeric = ClassifierGenerator()
regressiongen_numeric.set_values(class_col)
## Agregar atributos
regressiongen_numeric.add_attrib(account_data_filtered['updates']['max'], name='Maximum updates')
regressiongen_numeric.add_attrib(account_data_filtered['following']['max'], name='Maximum following')
regressiongen_numeric.add_attrib(country_id_col, name='Country ID')
regressiongen_numeric.add_attrib(election_distance_col, name='Election Activity Distance')
#regressiongen_numeric.add_attrib(account_category_id_col, name='Category_id')
## Preprocesar
regressiongen_numeric.preprocess_data(frac=training_frac)
El clasificador tiene mejor performance con los parametros por defecto, pero es mucho mas compacto con los parametros encontrados por grid search. El F1-Score de la clase 2 (Popularidad muy) es de 0.5, que significa que hay mas falsos positivos y negativos que en las otras clases.
from sklearn.tree import DecisionTreeClassifier
classifiergen_numeric.set_classifier(DecisionTreeClassifier())
classifiergen_numeric.train()
classifiergen_numeric.classifier_report()
graph_tree(classifiergen_numeric, 'decision_num_tree')
graph_2D(classifiergen_numeric, plot_decision_regions, 'decision_num_surf')
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
param_grid = {
'max_depth': [10, 50, 100, 500, 1000, None],
'min_samples_split' : np.arange(2, 10),
'min_samples_leaf' : [.1, 0.3, 0.5],
'criterion': ['gini', 'entropy']
}
classifiergen_numeric.set_classifier(GridSearchCV(estimator=DecisionTreeClassifier(),
param_grid=param_grid, scoring='accuracy',
cv=5, n_jobs=-1, refit=True))
classifiergen_numeric.train()
classifiergen_numeric.classifier = classifiergen_numeric.classifier.best_estimator_
classifiergen_numeric.classifier_report()
graph_tree(classifiergen_numeric, 'decision_num_tree_cross')
graph_2D(classifiergen_numeric, plot_decision_regions, 'decision_num_surf_cross')
from sklearn.tree import DecisionTreeClassifier
classifiergen_text.set_classifier(DecisionTreeClassifier())
classifiergen_text.train()
classifiergen_text.classifier_report()
graph_tree(classifiergen_text, 'decision_text')
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
param_grid = {
'max_depth': [50, 100, 1000, None],
'min_samples_split' : np.linspace(0.1, 1.0, 2, endpoint=True),
'min_samples_leaf' : [.1, .25, .5],
'criterion': ['gini', 'entropy']
}
classifiergen_text.set_classifier(GridSearchCV(estimator=DecisionTreeClassifier(),
param_grid=param_grid, scoring='accuracy',
cv=5, n_jobs=-1, refit=True))
classifiergen_text.train()
classifiergen_text.classifier = classifiergen_text.classifier.best_estimator_
classifiergen_text.classifier_report()
graph_tree(classifiergen_text, 'decision_cross_text')
#graph_2D(classifiergen_numeric, plot_decision_regions)
El bosque de decision trees entrega mejores estadÃsticas que usar un solo decision tree
El parámetro mas importante, con 44% de importancia dado por el clasificador, es la distancia al dia de eleccion, y la región no resulta ser muy relevante. El recall y f-score de la clases 2 resulta ser de los mas altos.
from sklearn.ensemble import RandomForestClassifier
classifiergen_numeric.set_classifier(RandomForestClassifier(n_estimators=100))
classifiergen_numeric.train()
classifiergen_numeric.classifier_report()
graph_2D(classifiergen_numeric, plot_decision_regions, 'random_fortest_num_surf')
print('Las impotancias de los parametros son', np.array(classifiergen_numeric.classifier.feature_importances_))
print('Para los parametros', classifiergen_numeric.feature_names)
La importancia entregada por el clasificador permite hacer una nube de palabras que representa la relevancia de las palabras.
from sklearn.ensemble import RandomForestClassifier
classifiergen_text.set_classifier(RandomForestClassifier(n_estimators=100, n_jobs=-1, random_state=1313))
classifiergen_text.train()
classifiergen_text.classifier_report()
#graph_2D(classifiergen_text, plot_decision_regions
importances = np.array(classifiergen_text.classifier.feature_importances_)
names = np.array(classifiergen_text.feature_names)
word_cloud(names, importances, ngrammin, ngrammax)
No funciona con el texto, entrega mejores resultados que los decision trees pero no mejores que el bosuqe. Tiene mayor Ãndice de falsos negativos para las clases de popularidad alta y muy alta
from sklearn.neighbors import KNeighborsClassifier
param_grid = {
'algorithm' : ['ball_tree', 'kd_tree'],
'p' : [1, 2, 5],
'n_neighbors' : [3, 5, 7, 9, 12]
}
classifiergen_numeric.set_classifier(GridSearchCV(estimator=KNeighborsClassifier(),
param_grid=param_grid, scoring='accuracy',
cv=5, n_jobs=-1, refit=True))
classifiergen_numeric.train()
classifiergen_numeric.classifier_report()
graph_2D(classifiergen_numeric, plot_decision_regions, 'kneigh_num_surf')
Naive bayes no es apropiado para clasificacion numerica. No tiene mayor capacidad predictiva que otros de los metodos usados
from sklearn.naive_bayes import BernoulliNB
classifiergen_text.set_classifier(BernoulliNB())
classifiergen_text.train()
classifiergen_text.classifier_report()
Falla pues los valores de f1-score y recall quedan indefinidos
from sklearn.naive_bayes import MultinomialNB
classifiergen_text.set_classifier(MultinomialNB())
classifiergen_text.train()
classifiergen_text.classifier_report()
Ocurre lo mismo que en el caso anterior.
from sklearn.naive_bayes import ComplementNB
classifiergen_text.set_classifier(ComplementNB())
classifiergen_text.train()
classifiergen_text.classifier_report()
SVC no lineal es util para clasificacion de texto. SVC lineal es multiproposito
No entrega mejores resultados que naive bayes, recall y f-score bajos para la clase de popularidad muy alta, comparado con otros métodos.
from sklearn.svm import LinearSVC
classifiergen_numeric.set_classifier(LinearSVC(C=.5, max_iter=10000))
classifiergen_numeric.train()
classifiergen_numeric.classifier_report()
graph_2D(classifiergen_numeric, plot_decision_regions, 'LinearSVC_num_surf')
SVC lineal resulta ser uno de los mejores clasificadores, pero el recall y f1-score no superan otro de los métodos usados.
from sklearn.svm import LinearSVC
classifiergen_text.set_classifier(LinearSVC(C=.5, max_iter=10000))
classifiergen_text.train()
classifiergen_text.classifier_report()
El performance es mas cercano a naive bayes, para la clasificacion numérica y de texto.
from sklearn.svm import SVC
classifiergen_numeric.set_classifier(SVC(gamma=10.0, C=.5, cache_size=1200, kernel='rbf'))
classifiergen_numeric.train()
classifiergen_numeric.classifier_report()
graph_2D(classifiergen_numeric, plot_decision_regions, 'SVC_rbf_num_surf')
from sklearn.svm import SVC
classifiergen_text.set_classifier(SVC(gamma=10.0, C=.5, cache_size=1200, kernel='rbf'))
classifiergen_text.train()
classifiergen_text.classifier_report()
Ninguno de los métodos de regresión usados entregó un valor de R^2 positivo, por lo que todos resultaron ser peores que elegir el promedio para todos los valores.
from sklearn.svm import SVR
regressiongen_numeric.set_classifier(SVR(gamma=1.0, C=.5, cache_size=1200, kernel='linear'))
regressiongen_numeric.train()
regressiongen_numeric.regression_report()
Los mejores clasificadores fueron los bosques de decision trees para la clasifición numérica y de texto, K-neighbors supervisado para la clasificación numérica, y LinearSVC para la clasificación de texto, y la regresión no entrego buenos resultados. Aún asi, todos los clasificadores usados entregaron mejores resultados que la eleccion aleatoria (accuracy > 0.3).
En general el F1-score para la clase de popularidad muy alta es relativamente bajo (<0.5). Sin embargo, los valores clasificación numérica usando forest de decision trees entregaron los mejores valores de F1-score de todos los demás clasificadores, por lo que si el interés es de predecir si la popularidad de una cuenta estará en los percentiles mas altos, este seria el clasificador mas util.