Миссия: Разработать классификатор, чтобы определить, является ли фильм Свежим или гнилым, основываясь на отзывах, данных о фильме.
Модель прогнозирования: Наивный Байес
Одной из самых важных вспомогательных функций здесь является CountVectorizer, он преобразует необработанный текст в " мешок слов’ векторов.
По определению, вектор " ЛУК " - это структура данных, которая сообщает вам, сколько раз конкретное слово появляется в рекламном объявлении.
from sklearn.feature_extraction.text import CountVectorizertext = ['machine learning rocks', 'machine learning rules', 'rocks rocks rules']print("Original text is:-\n", '\n'.join(text))
print()vectorizer = CountVectorizer(min_df=0)# call `fit` to build the vocabulary
vectorizer.fit(text)# call `transform` to convert text to a bag of words
x = vectorizer.transform(text)# CountVectorizer uses a sparse array to save memory, but it's easier in this assignment to
# convert back to a "normal" numpy array
x = x.toarray()print("Transformed text vector is \n", x)
print()
# `get_feature_names` tracks which word is associated with each column of the transformed x
print("Words for each feature:-")
print(vectorizer.get_feature_names())
При выполнении описанной выше функции ожидаемый результат будет следующим:
Теперь предположим, что у нас есть входная матрица X(n review, n words) и вектор y(n review), оба они являются массивом:
X: каждая строка соответствует представлению пакета слов для одного обзора (вход)
y: кодирование того, является ли обзор свежим(1) или гнилым(0) (Вывод)
Примечание: убедитесь, что X и y имеют одинаковое измерение в строке (обзор)
Следующий шаг-выполнить разделение тестового поезда (80%/20%) следующим образом:
X_train, X_test, y_train, y_test= train_test_split(X, Y, test_size= .2, random_state = 42, stratify= Y)
Время реализации MultinomialNB (используйте только обучающий набор для обучения вашей модели ), здесь мы используем accuracy_score в качестве целевой функции.
from sklearn.metrics import accuracy_scoreclf = MultinomialNB()
clf.fit(X_train, y_train)
y_train_pred = clf.predict(X_train)
y_test_pred = clf.predict(X_test)
train_pred_score = accuracy_score(y_train, y_train_pred)
test_pred_score = accuracy_score(y_test, y_test_pred)print('Training Set Accuracy Score: \n', (100 * train_pred_score))
print('Testing Set Accuracy Score: \n', (100 * test_pred_score))
Вуаля, это почти слишком просто, не так ли?
Однако мы хотим оптимизировать модель. Наши методы имеют несколько гиперпараметров, и это значения, которые мы хотим настроить с помощью перекрестной проверки.
- min_df в CountVectorizer, который игнорирует слова, которые появляются в меньшей, чем min_df, доле отзывов.
- альфа в MultinomialNB, известном как “параметр сглаживания” — увеличение значения уменьшает чувствительность к любому отдельному признаку и имеет тенденцию приближать вероятность предсказания к 50%
Прежде чем мы проведем перекрестную проверку, нам нужно понять, что определяет " лучшее’ значение параметра.
Цель: найти значение, которое максимизирует логарифмическую вероятность наших данных.
В этом случае мы имеем целевую функцию:
L = Sum_fresh(logo(fresh)) + Some_rotten(log(rotten))
Зачем использовать log_likelibility:
поскольку мы вычисляем кучу очень малых чисел (иначе говоря, вероятностей) и предполагаем, что все события независимы друг от друга (умножения), логарифмическое преобразование облегчит вычисление и позволит избежать того, чтобы конечный продукт был слишком близок к 0.
С этой интуицией нам нужна логоподобная функция, и вот она!
def log_likelihood(model, x, y):
prob = model.predict_log_proba(x)
rotten = y == 0
fresh = ~rotten
return prob[rotten, 0].sum() + prob[fresh, 1].sum()# output the likelihood of test data
log_likelihood(clf, X_test, y_test)
Теперь у вас есть все части, время показать вам какой-то код!
alphas = [0, 1, 5, 10, 50]
min_dfs = [0.0001,0.001,0.01, 0.1, 0.2] min_df, and the best classifier
best_alpha = None
best_min_df = None
max_loglike = -np.inffor alpha in alphas:
print('alpha is : ' + str(alpha))
for min_df in min_dfs:
print('min_df is : ' + str(min_df))
''initialize vecotizer
vectorizer = CountVectorizer(min_df = min_df)
X = vectorizer.fit_transform(x)
X = X.toarray()
Y = y.to_numpy()
''train test split
X_train, X_test, y_train, y_test= train_test_split(X, Y, test_size= .2, random_state = 42, stratify= Y)
''initialize NB model
clf = MultinomialNB(alpha = alpha) ''cross validating the NB model using 5 cv
score = cross_val_score(clf, X_train, y_train, cv=5, scoring = log_likelihood)
print('log scores: {:.2f}'.format(np.mean(score)))
''updating the best parameters
if np.mean(score) > max_loglike:
max_loglike = np.mean(score)
best_alpha = alpha
best_min_df = min_dfprint("best alpha, best min_dfs: ",best_alpha, best_min_df)
Теперь мы можем обучить окончательную модель , используя best_alpha, best_min_df, и повторно оценить точность на обучающих и тестовых наборах.
best_alpha = 5
best_min_df = 0.001 ''final vectorizer model and X, Y data
vectorizer_final = CountVectorizer(min_df = best_min_df)X = vectorizer_final.fit_transform(X)
X = X.toarray()
Y = y.to_numpy() ''train-test split
X_train_final, X_test_final, y_train_final, y_test_final = train_test_split(X, Y, test_size= .2, random_state = 42, stratify= Y_final)#fit NB model on the training datasets
clf_final = MultinomialNB(alpha = best_alpha)
clf_final.fit(X_train_final, y_train_final)#predict y on training data
y_train_pred = clf_final.predict(X_train_final)#predict y on testing data
y_test_pred = clf_final.predict(X_test_final)#accuracy score for training and testing predictions
test_pred_score = accuracy_score(y_test_final, y_test_pred)
train_pred_score = accuracy_score(y_train_final, y_train_pred)print('Training set Accuracy Score: \n', (100 * train_pred_score))
print('Testing set Accuracy Score: \n', (100 * test_pred_score))
Теперь у нас есть базовая наивная модель Байеса, простая, но эффективная.
Мораль в том, что всегда сначала пробуйте простые вещи.
Мы можем попробовать пройти обзор и попросить модель предсказать, является ли фильм "Гнилым" или "Свежим".
В этом примере тестовый обзор, который мы используем, звучит так: “Этот фильм ничем не примечателен, трогателен или превосходен”
''predict the probability of a given reviewdef predict_prob(s, model=clf_final):
s_tf = vectorizer_final.transform([s]).toarray()
proba_s = model.predict_proba(s_t)
return proba_spredict_prob("This movie is not remarkable, touching, or superb in any way")
Учитывая вероятность корреспондента [Гнилой, Свежий], эта модель фактически выдает неправильный ответ; потому что чувство положительных слов перевешивает отрицательное ключевое слово " не’. Такие слова, как “но”, “не” и т. Д.
Однако, поскольку наивный Байес рассматривает каждое слово отдельно, он не способен уловить такого рода словесные взаимодействия.
Зависимости между атрибутами неизбежно уменьшают способность Наивного Байеса различать, что происходит.