Вопрос или проблема
Пожалуйста, может кто-нибудь помочь мне с этим? Когда я пытаюсь отладить веб-приложение после применения алгоритмов машинного обучения (векторизация BagOfWords и классификаторы), я столкнулся с проблемами, и ошибка была следующей:
File "c:\Users\LENOVO\Desktop\webapp\app2.py", line 42, in predict
tweet_vect = words.transform([tweet]).toarray()
AttributeError: 'numpy.ndarray' object has no attribute 'transform'
127.0.0.1 - - [14/Apr/2023 11:29:54] "POST / HTTP/1.1" 500
Итак, мой код выглядит следующим образом, model.py :
df = pd.read_csv ('C:\\Users\\LENOVO\\Desktop\\webapp\\df.csv')
df.head()
from nltk.stem import WordNetLemmatizer
lemma= WordNetLemmatizer()
stop = stopwords.words('English')
def clean_tweets(text):
text = text.lower()
words= nltk.word_tokenize(text)
# Лемматизация - это еще одна техника, используемая для уменьшения измененных слов до их корневого слова. Она описывает алгоритмический процесс идентификации «леммы» измененного слова (словарная форма) на основе его предполагаемого значения.
words=" ".join ([lemma.lemmatize(word) for word in words
if word not in (stop)])
text="".join(words)
# удаление не буквенных символов
text = re.sub('[^a-z]',' ',text)
return text
# создание корпуса:
from nltk.stem import PorterStemmer
df.head(10)
corpus = []
pstem = PorterStemmer()
for i in range(df['cleaned_tweets'].shape[0]):
tweet = re.sub("[^a-zA-Z]", ' ', df['cleaned_tweets'][i])
#Преобразование слов в строчные
tweet = tweet.split()
#Удаление стоп-слов, затем стемминг
tweet = [pstem.stem(word) for word in tweet if not word in set(stopwords.words('english'))]
tweet=" ".join(tweet)
#Добавление очищенного твита в корпус
corpus.append(tweet)
df = df.drop(['text'],axis=1)
print("Корпус успешно создан")
print(pd.DataFrame(corpus)[0].head(10))
rawTexData = df["cleaned_tweets"].head(10)
cleanTexData = pd.DataFrame(corpus, columns=['corpus'])
frames = [rawTexData, cleanTexData]
result = pd.concat(frames, axis=1, sort=False)
result
#Создание нашего словаря
uniqueWordFrequents = {}
for tweet in corpus:
for word in tweet.split():
if(word in uniqueWordFrequents.keys()):
uniqueWordFrequents[word] += 1
else:
uniqueWordFrequents[word] = 1
#Преобразование словаря в DataFrame
uniqueWordFrequents = pd.DataFrame.from_dict(uniqueWordFrequents,orient="index",columns=['Word Frequent'])
uniqueWordFrequents.sort_values(by=['Word Frequent'], inplace=True, ascending=False)
uniqueWordFrequents.head(10)
uniqueWordFrequents['Word Frequent'].unique()
uniqueWordFrequents = uniqueWordFrequents[uniqueWordFrequents['Word Frequent'] >= 20]
print(uniqueWordFrequents.shape)
from sklearn.feature_extraction.text import CountVectorizer
counVec = CountVectorizer(max_features = uniqueWordFrequents.shape[0])
bagOfWords = counVec.fit_transform(corpus).toarray()
b = bagOfWords
y = df['target']
print("b shape = ",b.shape)
print("y shape = ",y.shape)
b_train , b_test , y_train , y_test = train_test_split(b,y,test_size=0.20, random_state=55, shuffle =True)
print('разделение данных успешно')
multinomialNBModel = MultinomialNB(alpha=0.1)
multinomialNBModel.fit(b_train,y_train)
print("модель multinomialNB выполнена успешно")
passModel=PassiveAggressiveClassifier()
passModel.fit(b_train,y_train)
print ('модель Passive Regressive выполнена успешно')
modelsNames = [('multinomialNBModel',multinomialNBModel),
('PassiveAggressiveClassifier',passModel)]
from sklearn.ensemble import VotingClassifier
votingClassifier = VotingClassifier(voting = 'hard',estimators= modelsNames)
votingClassifier.fit(b_train,y_train)
print("модель votingClassifier выполнена успешно")
models = [multinomialNBModel, passModel, votingClassifier]
for model in models:
print(type(model).__name__,' Тестовый балл: ' ,model.score(b_train, y_train))
print(type(model).__name__,' Балл на тесте: ' ,model.score(b_test, y_test))
y_pred = model.predict(b_test)
print(type(model).__name__,' F1 Балл: ' ,f1_score(y_test,y_pred))
bagOfWords
import pickle
pickle.dump(votingClassifier, open("model.pkl", "wb"))
pickle.dump(bagOfWords, open("words.pkl", "wb"))
app2.py:
from flask import Flask
from flask import render_template
from flask import request
from flask import jsonify
from flask import redirect
from flask import url_for
import re
import nltk
from nltk.corpus import stopwords
from nltk.stem.porter import PorterStemmer
import numpy as np
import joblib
nltk.download('stopwords')
import pickle
app = Flask(__name__)
ps = PorterStemmer()
model = pickle.load(open('model.pkl', 'rb'))
words = pickle.load(open('words.pkl', 'rb'))
# Построение функциональности
@app.route("https://datascience.stackexchange.com/", methods=['GET'])
def home():
return render_template('index2.html')
def predict(text):
tweet = re.sub('[^a-zA-Z]', ' ', text)
tweet = tweet.lower()
tweet = tweet.split()
tweet = [ps.stem(word) for word in tweet if not word in stopwords.words('english')]
tweet=" ".join(tweet)
tweet_vect = words.transform([tweet]).toarray()
prediction = 'FAKE' if model.predict(tweet_vect) == 0 else 'REAL'
return prediction
@app.route("https://datascience.stackexchange.com/", methods=['POST'])
def webapp():
text = request.form['text']
prediction = predict(text)
return render_template('index2.html', text=text, result=prediction)
@app.route('/predict/', methods=['GET','POST'])
def api():
text = request.args.get('text')
prediction = predict(text)
return jsonify(prediction=prediction)
if __name__ == "__main__":
app.run()
пожалуйста, любая помощь
Ошибка возникает, когда выполнение доходит до этой строки в app.py
:
tweet_vect = words.transform([tweet]).toarray()
Помните, что transform
– это один из методов класса CountVectorizer
. Следовательно, если переменная words
хранила такой класс, эта строка сработала бы. Поскольку этого не произошло, это говорит о том, что переменная, вероятно, не хранит экземпляр CountVectorizer
🙂
На самом деле, если вы проверите, как эта переменная была определена ранее в model.py
и затем сохранена, вы найдете эту строку:
bagOfWords = counVec.fit_transform(corpus).toarray()
Обратите внимание, что в этом выражении метод toarray
был последним, который был вызван, что означает, что значение, хранящееся в bagOfWords
, было выводом этого метода, а не фактическим экземпляром CountVectorizer
(который и имеет метод transform
, который здесь потерян).
Вот почему, когда вы пытаетесь вызвать этот метод на объекте, который был сохранен, программа не может его найти.
Эта конкретная ошибка может быть решена заменой этой строки в model.py
:
bagOfWords = counVec.fit_transform(corpus).toarray()
на
bagOfWords = counVec.fit_transform(corpus)
но я не анализировал все возможные зависимости в коде и, если значение этой переменной предполагается использовать в виде массива где-то еще, вы можете вводить новые ошибки, поэтому будьте осторожны с любыми изменениями. В общем, вы всегда хотите сохранить весь экземпляр CountVectorizer
как этот объект, потому что он будет полезен позже для воспроизводимости.
Удачи!
Ответ или решение
Конечно! Давайте разберем вашу проблему с развертыванием проекта классификатора машинного обучения.
Ошибка, с которой вы столкнулись:
AttributeError: 'numpy.ndarray' object has no attribute 'transform'
Происходит она из-за того, что вы вызываете метод transform()
для объекта, который на самом деле является numpy.ndarray
, а не экземпляром класса CountVectorizer
. Это произошло, когда вы сделали следующее в вашем файле model.py
:
bagOfWords = counVec.fit_transform(corpus).toarray()
Метод fit_transform
возвращает матрицу признаков в виде numpy.ndarray
, когда вы вызываете toarray()
, и, таким образом, вы потеряли доступ к объекту CountVectorizer
, который содержит метод transform()
.
Решение проблемы
Чтобы исправить эту ошибку, вам необходимо сохранить сам объект CountVectorizer
, а не только его выходные данные. Вот как вы можете это сделать:
- Замените строку
bagOfWords = counVec.fit_transform(corpus).toarray()
на
bagOfWords = counVec.fit_transform(corpus) # Здесь мы сохраняем только разреженную матрицу
- В конце вашего кода
model.py
, добавьте следующую строчку, чтобы сохранить сам объектCountVectorizer
:
pickle.dump(counVec, open("words.pkl", "wb")) # Сохраняем объект CountVectorizer
Теперь ваш файл words.pkl
будет содержать сам объект CountVectorizer
, и вы сможете вызывать метод transform()
на нем в вашем приложении Flask.
Обновленный код для model.py
Ваш обновленный код в model.py
должен выглядеть так:
from sklearn.feature_extraction.text import CountVectorizer
# Ваш предыдущий код...
# Создаем словарь
uniqueWordFrequents = {}
# Логика создания уникальных частот слов...
# Создаем объект CountVectorizer
counVec = CountVectorizer(max_features = uniqueWordFrequents.shape[0])
bagOfWords = counVec.fit_transform(corpus) # Изменено
# Сохраняем модели и векторы
pickle.dump(votingClassifier, open("model.pkl", "wb"))
pickle.dump(counVec, open("words.pkl", "wb")) # Изменено
Обновленный код для app2.py
Убедитесь, что в app2.py
вы загружаете объект CountVectorizer
следующим образом:
words = pickle.load(open('words.pkl', 'rb')) # Этот объект теперь содержит ваш CountVectorizer
Теперь при вызове метода transform()
у вас не должно быть ошибок, и вы сможете успешно развернуть ваш проект.
Если у вас возникнут дополнительные вопросы или вам потребуется помощь с другими аспектами проекта, не стесняйтесь спрашивать! Желаю удачи в вашей работе над проектом классификации!