<jupyter_start><jupyter_text>Load raw data<jupyter_code>def clean_text(text):
    text = text.lower()
    text = re.findall(r'\b[a-z]+\b', text)
    return ' '.join(text)
training_data = pd.read_csv('./train.csv')
training_data.head()<jupyter_output><empty_output><jupyter_text>Cleaning data<jupyter_code>training_data['cleaned_comment'] = training_data['Comment'].apply(clean_text)
training_data.head()
training_data.shape
training_data['Insult'].value_counts()
# How does it look the insults
training_data.query('Insult == 1')<jupyter_output><empty_output><jupyter_text>Make some features Formulate the problem into mathematical terms. The function `CountVectorizer` transform all the words of each tweet into a vector. The lenght of this vector is equal to the total number of unique representative words in the dataset. The function finaly returns a matrix with all these vectors.<jupyter_code>count_vectorizer = CountVectorizer(analyzer='word', ngram_range=(1,3), stop_words='english', max_features=5000)
count_vectorizer.fit(training_data['cleaned_comment'])
#count_vectorizer.vocabulary_
# Featurizing tags
X = count_vectorizer.transform(training_data['cleaned_comment'])
y = training_data['Insult']
CountVectorizer?
# Compress representation of the matrix
X<jupyter_output><empty_output><jupyter_text>Cross-validate Now the data is going to be divided in train data and test data.  Split data<jupyter_code>def split_data (X, y, p=0.75):
    """ 
    X = Feature matrix
    y = vector
    p = percentage of data in training data
    """
    mask = np.array([ bool(np.random.binomial(1,p)) for _ in range(X.shape[0])])
    X_train = X[mask]
    y_train = y[mask]
    X_test = X[~mask]
    y_test = y[~mask]
    
    return X_train, y_train, X_test, y_test
# Explanation of previus code
p = 0.2
mask = np.array([ bool(np.random.binomial(1,p)) for _ in range(X.shape[0])])
pd.Series(mask).value_counts() / X.shape[0]
X_train, y_train, X_test, y_test = split_data(X,y)<jupyter_output><empty_output><jupyter_text>Fit a model on training data<jupyter_code>from sklearn.linear_model import LogisticRegression

# Classifier ~ Classifier
clf = LogisticRegression(verbose=1)
clf.fit(X_train, y_train)<jupyter_output>[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.2s finished<jupyter_text>Validate model on test data<jupyter_code>from sklearn.metrics import accuracy_score

predictions = clf.predict(X_test)
validation_score = accuracy_score(y_test, predictions)
print('Validation score: ', validation_score)<jupyter_output>Validation score:  0.8352570828961176<jupyter_text>Remeber, everything is a hyper-parameter It is important to automatize the process of testing models and hyperparameters, in that way you can look faster which model works fine and focus in it.<jupyter_code>from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import LinearSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
class PredictionPipeline:
    
    def __init__(self, ngram_range, vectorizer_class, model_class, training_data):
        self.ngram_range = ngram_range
        self.vectorizer_class = vectorizer_class
        self.model_class = model_class
        self.training_data = training_data
        self.vectorizer = None
        self.X = None
        self.y = None
        self.model = None
        self.validation_score = None
        
    def run(self):
        self._fit_vectorizer()
        self._featurize_text()
        self._split_train_and_validation_sets()
        self._fit_model_on_training_data()
        self._validate_model_on_validation_set()
        
        print(
        """
        Vectorizer Class: {vectorizer_class}\n
        N-gram Range: {ngram_range}\n
        Model Class: {model_class}\n
        Validation Score: {validation_score}
            
        """.format(

            vectorizer_class=repr(self.vectorizer_class.__name__), 
            ngram_range=self.ngram_range, 
            model_class=repr(self.model_class.__name__), 
            validation_score=round(self.validation_score, 4)

                )
            )
        
        
    def _fit_vectorizer(self):
        self.vectorizer = vectorizer_class(analyzer='word', ngram_range=ngram_range,
                                           stop_words='english', max_features=50000)
        self.vectorizer.fit(self.training_data['cleaned_comment'])
       
    
    def _featurize_text(self):
        self.X = self.vectorizer.transform(self.training_data['cleaned_comment'])
        self.y = self.training_data['Insult']
        
    
    def _split_train_and_validation_sets(self):
        self.X_train, self.X_validation, self.y_train, self.y_validation = train_test_split(
        self.X, self.y, test_size=0.25, random_state=123)
       
    
    def _fit_model_on_training_data(self):
        self.model = self.model_class()
        self.model.fit(self.X_train, self.y_train)
        
    def _validate_model_on_validation_set(self):
        predictions = self.model.predict(self.X_validation)
        self.validation_score = accuracy_score(self.y_validation, predictions)
        
    
results = {}

for ngram_range in [(1,1), (1,2), (1,3), (1,4)]:
    for vectorizer_class in [CountVectorizer, TfidfVectorizer]:
        for model_class in [LogisticRegression, LinearSVC, RandomForestClassifier]:
            
            # Run prediction pipeline
            prediction_pipeline = PredictionPipeline(
                ngram_range = ngram_range,
                vectorizer_class = vectorizer_class,
                model_class = model_class,
                training_data =  training_data
            )
            prediction_pipeline.run()
            
            results[str(prediction_pipeline.validation_score)] = {
                'vectorizer_class': prediction_pipeline.vectorizer_class,
                'ngram_range': prediction_pipeline.ngram_range,
                'model_class': prediction_pipeline.model_class
            }
            
top_3_scores = sorted(results.keys(), reverse=True)[:3]

for score in top_3_scores:
    print(f'Score: {score}\nParameters: {results[score]}')
top_3_scores<jupyter_output><empty_output><jupyter_text>Train final model<jupyter_code>top_score_key = top_3_scores[0]
vectorizer_class = results[top_score_key]['vectorizer_class']
ngram_range = results[top_score_key]['ngram_range']
model_class = results[top_score_key]['model_class']

# Fit vectorizer
vectorizer = vectorizer_class(analyzer='word', ngram_range=ngram_range, stop_words='english', max_features=50000)
vectorizer.fit(training_data['cleaned_comment']) #Generates the vector with all the vocabulary
# transform text
X = vectorizer.transform(training_data['cleaned_comment'])
y = training_data['Insult']
# Fit model on training data
model = model_class()
model.fit(X,y)<jupyter_output><empty_output><jupyter_text>Run it live<jupyter_code>input_string = input('Please enter a string: ')
input_string = clean_text(input_string)
X_test = vectorizer.transform([input_string])

prediction = model.predict(X_test)[0]

print('Insult: ', bool(prediction))<jupyter_output>Please enter a string: you are a dumb
Insult:  True
{'fraction_non_alphanumeric': 0.09737673396511468, 'fraction_numerical': 0.010163439088037357, 'mean_word_length': 3.85790527018012, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '420241', 'license': 'MIT', 'n_tokens_mistral': 2339, 'n_tokens_neox': 2282, 'n_words': 460, 'path': 'insults_prediction/insults-prediction.ipynb', 'repo_name': 'AngelFA04/datascience_course_platzi', 'size': '7281'}