In [1]:
import numpy as np
import pandas as pd
import scipy
import nltk
import sklearn
import random
import re
from sklearn.feature_extraction.text import CountVectorizer,TfidfTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.multiclass import OneVsRestClassifier
from sklearn.metrics import f1_score, precision_score, recall_score
from sklearn.linear_model import LogisticRegression, LinearRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.grid_search import GridSearchCV, ParameterGrid
from sklearn.pipeline import Pipeline

In [3]:
nltk.download('reuters')
nltk.download('punkt') # needed for tokenization


[nltk_data] Downloading package reuters to /home/felipe/nltk_data...
[nltk_data]   Package reuters is already up-to-date!
[nltk_data] Downloading package punkt to /home/felipe/nltk_data...
[nltk_data]   Package punkt is already up-to-date!
Out[3]:
True

In [4]:
dataset = nltk.corpus.reuters

In [6]:
# http://scikit-learn.org/stable/modules/feature_extraction.html#text-feature-extraction
corpus_train = []
corpus_test = []
for fileid in dataset.fileids():
    document = dataset.raw(fileid)
    if re.match('training/',fileid):
        corpus_train.append(document)
    else:
        corpus_test.append(document)

In [7]:
def preprocessor(string):
    repl = re.sub('<','',string)
    return repl.lower()

In [8]:
Y_train = []
Y_test = []

for (idx,fileid) in enumerate(dataset.fileids()):    
    categories = '*'.join(dataset.categories(fileid))

    if re.match('training/',fileid):
        Y_train.append(categories)
    else:
        Y_test.append(categories)

series_train = pd.Series(Y_train)
Y_train_df = series_train.str.get_dummies(sep='*')

series_test = pd.Series(Y_test)
Y_test_df = series_test.str.get_dummies(sep='*')

Y_train = Y_train_df.values
Y_test = Y_test_df.values

Y_train.shape,Y_test.shape


Out[8]:
((7769, 90), (3019, 90))

In [16]:
clf = OneVsRestClassifier(Pipeline([
    ('vect', CountVectorizer()),
    ('tfidf', TfidfTransformer()),
    ('clf', LogisticRegression()),
]))
parameters = [
    { 
          "estimator__vect__min_df": [30,40,50,60],
          "estimator__vect__preprocessor":[preprocessor],
          "estimator__vect__stop_words": ['english'],
          "estimator__vect__strip_accents":['ascii']
    }
    ]

In [17]:
best_score = float("-inf")

# I had to manually search over the parameter grid because, since we have a mod-apte split
# we cannot do any cross-validations selecting random train/test sets.
# GridSearchCV does not let one do grid search *without* also doing cross validation so we need to do this
for g in ParameterGrid(parameters):
    clf.set_params(**g)
    clf.fit(corpus_train,Y_train)
    
    Y_pred = clf.predict(corpus_test)
    
    current_score = f1_score(Y_test,Y_pred,average='micro')
    
    print("current_score was {} and the current grid was {}".format(current_score,g))
    
    if current_score > best_score:
        best_score = current_score
        best_grid = g


current_score was 0.780146356984 and the current grid was {'estimator__vect__preprocessor': <function preprocessor at 0x7fe8446cc0c8>, 'estimator__vect__stop_words': 'english', 'estimator__vect__min_df': 30, 'estimator__vect__strip_accents': 'ascii'}
current_score was 0.784910445395 and the current grid was {'estimator__vect__preprocessor': <function preprocessor at 0x7fe8446cc0c8>, 'estimator__vect__stop_words': 'english', 'estimator__vect__min_df': 40, 'estimator__vect__strip_accents': 'ascii'}
current_score was 0.786324786325 and the current grid was {'estimator__vect__preprocessor': <function preprocessor at 0x7fe8446cc0c8>, 'estimator__vect__stop_words': 'english', 'estimator__vect__min_df': 50, 'estimator__vect__strip_accents': 'ascii'}
current_score was 0.779930136551 and the current grid was {'estimator__vect__preprocessor': <function preprocessor at 0x7fe8446cc0c8>, 'estimator__vect__stop_words': 'english', 'estimator__vect__min_df': 60, 'estimator__vect__strip_accents': 'ascii'}

In [18]:
best_score


Out[18]:
0.78632478632478631

In [19]:
best_grid


Out[19]:
{'estimator__vect__min_df': 50,
 'estimator__vect__preprocessor': <function __main__.preprocessor>,
 'estimator__vect__stop_words': 'english',
 'estimator__vect__strip_accents': 'ascii'}