Rewrite lab with BoW
This commit is contained in:
46
classifiers/bag_of_words.py
Normal file
46
classifiers/bag_of_words.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from collections import Counter
|
||||
|
||||
import numpy as np
|
||||
from sklearn.base import BaseEstimator, ClassifierMixin
|
||||
from sklearn.feature_extraction import DictVectorizer
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
from sklearn.pipeline import Pipeline
|
||||
|
||||
from classifiers.feature_classifier import FeatureExtractor
|
||||
from cleaning.transformers import LowercaseTransformer, PunctuationRemover
|
||||
|
||||
|
||||
class BagOfWordsClassifier(BaseEstimator, ClassifierMixin):
|
||||
def __init__(self):
|
||||
self.cleaning = Pipeline([
|
||||
("lowercase", LowercaseTransformer()),
|
||||
("punctuation", PunctuationRemover()),
|
||||
])
|
||||
|
||||
def fit(self, X, y):
|
||||
X_clean = self.cleaning.fit_transform(X)
|
||||
self._pipeline = Pipeline([
|
||||
("features", FeatureExtractor(self.extract_features)),
|
||||
("vectorizer", DictVectorizer()),
|
||||
("classifier", LogisticRegression(max_iter=1000)),
|
||||
])
|
||||
y_binary = (np.array(y) == "spam").astype(int)
|
||||
self._pipeline.fit(X_clean, y_binary)
|
||||
return self
|
||||
|
||||
def predict(self, X):
|
||||
X_clean = self.cleaning.transform(X)
|
||||
y_binary = self._pipeline.predict(X_clean)
|
||||
return np.where(y_binary == 1, "spam", "ham")
|
||||
|
||||
def extract_features(self, message):
|
||||
return dict(Counter(message.split()))
|
||||
|
||||
def feature_weights(self, top_n=10):
|
||||
vectorizer = self._pipeline.named_steps["vectorizer"]
|
||||
classifier = self._pipeline.named_steps["classifier"]
|
||||
names = vectorizer.get_feature_names_out()
|
||||
weights = classifier.coef_[0]
|
||||
pairs = sorted(zip(names, weights), key=lambda x: x[1])
|
||||
half = top_n // 2
|
||||
return pairs[-half:][::-1] + pairs[:half]
|
||||
@@ -4,8 +4,6 @@ from sklearn.feature_extraction import DictVectorizer
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
from sklearn.pipeline import Pipeline
|
||||
|
||||
from cleaning.transformers import LowercaseTransformer
|
||||
|
||||
|
||||
class FeatureExtractor(BaseEstimator, TransformerMixin):
|
||||
def __init__(self, extract_fn):
|
||||
@@ -24,10 +22,9 @@ class FeatureClassifier(BaseEstimator, ClassifierMixin):
|
||||
|
||||
def fit(self, X, y):
|
||||
self._pipeline = Pipeline([
|
||||
("lowercase", LowercaseTransformer()),
|
||||
("features", FeatureExtractor(self.extract_features)),
|
||||
("vec", DictVectorizer()),
|
||||
("clf", LogisticRegression(C=self.C, max_iter=1000)),
|
||||
("vectorizer", DictVectorizer()),
|
||||
("classifier", LogisticRegression(C=self.C, max_iter=1000)),
|
||||
])
|
||||
y_binary = (np.array(y) == "spam").astype(int)
|
||||
self._pipeline.fit(X, y_binary)
|
||||
@@ -39,15 +36,15 @@ class FeatureClassifier(BaseEstimator, ClassifierMixin):
|
||||
|
||||
def extract_features(self, message):
|
||||
return {
|
||||
"contains_free": int("free" in message),
|
||||
"contains_free": int("free" in message.lower()),
|
||||
"num_exclamations": message.count("!"),
|
||||
"length": len(message),
|
||||
}
|
||||
|
||||
def feature_weights(self, top_n=10):
|
||||
vec = self._pipeline.named_steps["vec"]
|
||||
clf = self._pipeline.named_steps["clf"]
|
||||
names = vec.get_feature_names_out()
|
||||
weights = clf.coef_[0]
|
||||
vectorizer = self._pipeline.named_steps["vectorizer"]
|
||||
classifier = self._pipeline.named_steps["classifier"]
|
||||
names = vectorizer.get_feature_names_out()
|
||||
weights = classifier.coef_[0]
|
||||
pairs = sorted(zip(names, weights), key=lambda x: abs(x[1]), reverse=True)
|
||||
return pairs[:top_n]
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import numpy as np
|
||||
from sklearn.pipeline import Pipeline
|
||||
|
||||
from classifiers.manual import ManualClassifier
|
||||
from cleaning.transformers import LowercaseTransformer
|
||||
|
||||
|
||||
class ManualCleaningClassifier(ManualClassifier):
|
||||
def __init__(self):
|
||||
self.cleaning = Pipeline([
|
||||
("lowercase", LowercaseTransformer()),
|
||||
])
|
||||
|
||||
def fit(self, X, y):
|
||||
self.cleaning.fit(X)
|
||||
return self
|
||||
|
||||
def predict(self, X):
|
||||
X_clean = self.cleaning.transform(X)
|
||||
return np.array([self.predict_one(msg) for msg in X_clean])
|
||||
Reference in New Issue
Block a user