Я получил обзоры Amazon для продукта и теперь пытаюсь обучить на нем модель логистической регрессии, чтобы классифицировать отзывы клиентов. Это дает 100-процентную точность. Я не могу понять проблему. Вот образец из моего набора данных:
Вот мой код
import re
import nltk
import numpy as np
import pandas as pd
from bs4 import BeautifulSoup
from nltk.sentiment import SentimentIntensityAnalyzer
from nltk.tokenize import word_tokenize
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from sklearn.model_selection import train_test_split
from sklearn.utils.class_weight import compute_class_weight
# Ensure necessary NLTK datasets and models are downloaded
# nltk.download('punkt')
# nltk.download('vader_lexicon')
# Load the data
df = pd.read_csv("reviews.csv") # Make sure to replace 'reviews.csv' with your actual file path
# Preprocess data
df['Stars'] = df['Stars'].fillna(3.0) # Handle missing values
df['Title'] = df['Title'].str.lower() # Standardize text formats
df['Description'] = df['Description'].str.lower()
df = df.drop(['Name', 'Date'], axis=1) # Drop unnecessary columns
print(df)
# Categorize sentiment based on star ratings
def categorize_sentiment(stars):
if stars >= 4.0:
return 'Positive'
elif stars <= 2.0:
return 'Negative'
else:
return 'Neutral'
df['Sentiment'] = df['Stars'].apply(categorize_sentiment)
# Clean and tokenize text
def clean_text(text):
text = BeautifulSoup(text, "html.parser").get_text()
letters_only = re.sub("[^a-zA-Z]", " ", text)
return letters_only.lower()
def tokenize(text):
return word_tokenize(text)
df['Clean_Description'] = df['Description'].apply(clean_text)
df['Tokens'] = df['Clean_Description'].apply(tokenize)
# Apply NLTK's VADER for sentiment analysis
sia = SentimentIntensityAnalyzer()
def get_sentiment(text):
score = sia.polarity_scores(text)
if score['compound'] >= 0.05:
return 'Positive'
elif score['compound'] <= -0.05:
return 'Negative'
else:
return 'Neutral'
df['NLTK_Sentiment'] = df['Clean_Description'].apply(get_sentiment)
print("df['NLTK_Sentiment'].value_counts()")
print(df['NLTK_Sentiment'].value_counts())
# Prepare data for machine learning
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(tokenizer=tokenize)
X = vectorizer.fit_transform(df['Clean_Description'])
y = df['NLTK_Sentiment'].apply(lambda x: 1 if x == 'Positive' else 0)
# Split the dataset
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=80)
# Train a Logistic Regression model
# Compute class weights
class_weights = compute_class_weight('balanced', classes=np.unique(y_train), y=y_train)
class_weights_dict = dict(enumerate(class_weights))
print(f"class_weights_dict {class_weights_dict}")
# Apply to Logistic Regression
# model = LogisticRegression(class_weight=class_weights_dict)
model = LogisticRegression(C=0.001, penalty='l2', class_weight='balanced')
model.fit(X_train, y_train)
# Predict sentiments on the test set
predictions = model.predict(X_test)
# Evaluate the model
accuracy = accuracy_score(y_test, predictions)
precision = precision_score(y_test, predictions, average='weighted')
recall = recall_score(y_test, predictions, average='weighted')
f1 = f1_score(y_test, predictions, average='weighted')
print(f"Accuracy: {accuracy:.4f}")
print(f"Precision: {precision:.4f}")
print(f"Recall: {recall:.4f}")
print(f"F1 Score: {f1:.4f}")
Вот результаты операторов печати:
НЛТК_Сентимент
Позитив 8000
Негатив 2000
Имя: count, тип d: int64
class_weights_dict {0:2.3696682464454977, 1:0.6337135614702155}
Точность: 1,0000
Точность: 1,0000
Напомним: 1.0000
Оценка F1: 1.0000
Я не могу найти причину, по которой моя модель всегда дает 100-процентную точность.
Столбец NLTK_Sentiment основан на настроении столбца Clean_Description. Столбец X также основан на столбце Clean_Description.
По сути, вы проверяете, существует ли линейная зависимость между количеством появлений каждого токена и категоризацией VADER. Поскольку VADER присваивает каждому слову оценку от -4 до 4 и суммирует их, это линейная зависимость. (Есть некоторые исключения из этого правила — VADER способен распознавать некоторые идиомы, такие как «плохая задница», или отрицания, такие как «плохой», но за пределами этих особых случаев он линеен.)
По этой причине логистическая регрессия, по сути, просто восстанавливает веса на уровне слов в VADER. Вы задаете ему задачу, которая проста, и именно поэтому вы получаете такой высокий балл.
@JAMSHAID Это зависит от того, что вы пытаетесь сделать. Ваша модель логистической регрессии не будет «умнее», чем VADER, а в некоторых отношениях она будет хуже. (например, если есть слово, которое VADER распознает, но не отображается в вашем наборе данных, ваша модель его не выучит.) Но мне это не кажется лишним.
Правилен ли мой подход для выполнения этой задачи? это считается переобучением или нет?