Detecting Toxic Comments: Building a Classifier with Naive Bayes Weighted Logistic Regression
As the digital world grows, so does the challenge of moderating online conversations. Toxic comments- those that are harmful, offensive, or…
Detecting Toxic Comments: Building a Classifier with Naive Bayes Weighted Logistic Regression
As the digital world grows, so does the challenge of moderating online conversations. Toxic comments- those that are harmful, offensive, or disruptive- are increasingly common across platforms, leading to negative experiences in online communities. Moderating such content manually is nearly impossible, but what if we automate the process?
In this article, we’ll build a toxic comment classifier that flags offensive language using a combination of Naive Bayes and Logistic Regression. This hybrid approach allows us to leverage the strengths of both algorithms, enabling us to create a robust model capable of detecting toxic comments across multiple categories. Ready to dive in ? Let’s go!
The Dataset: A Quick Overview
Before diving into the code, let’s get familiar with the dataset we’ll be using. This dataset is popular, and commonly used for toxic comment classification tasks (like on Kaggle competitions). It contains user-generated comments and six labels indicating different types of toxicity:
- Toxic: The comment is rude, disrespectful, or likely to cause harm.
- Severe Toxic: More aggressive and harmful comments.
- Obscene: Contains vulgar or inappropriate language.
- Threat: Indicates a potential threat of harm.
- Insult: Comments that demean or insult others.
- Identity Hate: Targeted hate speech against someone’s identity (e.g., race, religion, etc.).
Each comment can have more than one label, making this a multi-label classification problem.
Dataset Sample

What are we building?
We’re building a model that reads through user comments and predicts the probability that a comment is toxic or fits into any of the six categories mentioned above. Our solution uses a combination of TF-IDF vectorization for feature extraction and Naive Bayes-weighted Logistic Regression to perform the classification.
Here’s what this hybrid approach works so well:
- Naive Bayes is a great choice for text classification because it’s fast and effective at capturing word-level information.
- Logistic Regression adds the power of learning feature interactions, enabling more nuanced predictions.
By combining these techniques, we can build a classifier that’s both accurate and efficient.
Step 1: Preprocessing the Data
Let’s start by preprocessing the data. We need to clean up the comments, handle missing data, and prepare the labels.
COMMENT = 'comment_text'
# Fill missing values in the comment_text column
train[COMMENT] = train[COMMENT].fillna("unknown")
test[COMMENT] = test[COMMENT].fillna("unknown")
Explanation:
- Why fill in missing value? In real-world datasets, it’s common to encounter missing or incomplete data. Here, we replace any missing comments with the word “unknown” to ensure that the model can handle such cases gracefully.
- The none label: We also create a none label to track comments that don’t belong to any toxic category.
label_cols = ['toxic', 'severe_toxic', 'obscene', 'threat', 'insult', 'identity_hate']
train['none'] = 1 - train[label_cols].max(axis=1)
Step 2: Tokenization and TF-IDF Vectorization
Text data can’t be fed directly into a machine-learning model, so we need to convert the comments into numerical form. For this, we use TF-IDF (Term Frequency-Inverse Document Frequency), which helps determine how important a word in relation to the overall dataset.
import re, string
re_tok = re.compile(f'([{string.punctuation}“”¨«»®´·º½¾¿¡§£₤‘’])')
def tokenize(s):
return re_tok.sub(r'\1', s).split()
Why this matters
- We use a custom tokenizer to separate words from punctuation. This ensures that punctuation marks are treated as separate tokens, which helps the model better understand the context of certain phrases.
Vectorizing Text with TF-IDF
from sklearn.feature_extraction.text import TfidfVectorizer
vec = TfidfVectorizer(
ngram_range=(1, 2),
tokenizer=tokenize,
min_df=3,
max_df=0.9,
strip_accents='unicode',
use_idf=True,
smooth_idf=True,
sublinear_tf=True,
token_pattern=None
)
trn_term_doc = vec.fit_transform(train[COMMENT])
test_term_doc = vec.transform(test[COMMENT])
Explanation:
- TF-IDF assigns a score to each work based on its frequency in a comment relative to how often it appears in other comments. Words that appear frequently but are common across many comments (like “the”) are given lower scores, while rare but important words (like “threat”) are given higher scores.
- N-gram range: We use both unigrams (individual words) and bigrams (pairs of words) to capture richer context.
Step 3: Naive Bayes-Weighted Logistic Regression
Here comes the exciting part: combining Naive Bayes and Logistic Regression for classification!
Naive Bayes Probability Function
def pr(y_i, y):
p = x[y == y_i].sum(0)
return (p + 1) / ((y == y_i).sum() + 1)
This function calculates the class-specific word probabilities, adding smoothing to avoid zero probabilities. It helps determine how likely a word appear in a toxic comment versus a non-toxic comment.
Model Training
from sklearn.linear_model import LogisticRegression
import numpy as np
x = trn_term_doc
test_x = test_term_doc
def get_mdl(y):
y = y.values
r = np.log(pr(1, y) / pr(0, y))
x_nb = x.multiply(r)
m = LogisticRegression(C=4, dual=False)
return m.fit(x_nb, y), r
How it works:
- Naive Bayes Weighting: We compute the log odds of each word being present in toxic comments versus non-toxic ones, and these weights (
r) transform the original TF-IDF matrix. - Logistic Regression: The transformed features are then fed into a Logistic Regression model, which learns to predict whether a comment is toxic or belongs to any other toxic category.
Step 4: Training, Prediction, and Saving Models
Now that we have our model training function, we can apply it to each label (toxic, severe_toxic, etc.), make predictions, and save the models for future use.
import joblib
# Initialize predictions and storage for models
preds = np.zeros((len(test), len(label_cols)))
models = {}
rs = {}
for i, j in enumerate(label_cols):
print('fit', j)
m, r = get_mdl(train[j])
preds[:, i] = m.predict_proba(test_x.multiply(r))[:, 1]
# Save each model and its corresponding 'r' value
joblib.dump((m, r), f'model_{j}.pkl')
models[j] = m
rs[j] = r
np.save('predictions.npy', preds)
Explanation:
- For each label, we train a model and store both the Logistic Regression model and the Naive Bayes weights (
r) usingjoblib.dump(). This way, we can reuse the models without retraining them. - We also store the predictions in a NumPy array and save them as a
.npyfile for further analysis.
Conclusion
And that’s it! We’ve built a fully functioning toxic comment classifier using Naive Bayes-weighted Logistic Regression. This model can predict the probability that a comment belongs to one or more toxic categories, helping to automate the detection and moderation of harmful content.
Why this approach works:
- Naive Bayes efficiently captures word-level importance, while Logistic Regression allows us to make nuanced predictions by learning feature interactions.
- This combination is powerful for text classification tasks, especially when dealing with high-dimensional data like comments.
What’s Next?
- Deploy your model using a framework like Flask or FastAPI to create a web service that flags toxic comments in real time.
- Analyze the predictions to see how your model performs across different categories.
- Fine-tune your model by experimenting with hyperparameters, adding more advanced models, or incorporating additional features.
메타데이터
- post_id
- 6f54ad7d8e8a
- slug
- detecting-toxic-comments-building-a-classifier-with-naive-bayes-weighted-logistic-regression-6f54ad7d8e8a
- url
- https://medium.com/@albinlamichhane9/detecting-toxic-comments-building-a-classifier-with-naive-bayes-weighted-logistic-regression-6f54ad7d8e8a
- canonical_url
- https://medium.com/@albinlamichhane9/detecting-toxic-comments-building-a-classifier-with-naive-bayes-weighted-logistic-regression-6f54ad7d8e8a
- author_url
- https://medium.com/@albinlamichhane9
- status
- ok
- fetched_at
- 2026-06-21 19:25:17