我的朴素贝叶斯分类器适用于我的模型,但不接受用户对我的应用程序的输入
My Naive Bayes classifier works for my model but will not accept user input on my application
我正在尝试将我的机器学习朴素贝叶斯情绪分析模型部署到 Web 应用程序中。这个想法是用户应该键入一些文本,应用程序对其执行情感分析,然后将具有指定情感的文本存储在数据库中的另一列中,稍后通过 html 作为列表调用。
虽然模型和矢量化器在 Google Colab 上工作正常,但当我将模型加载到我的应用程序并尝试 运行 用户通过它输入时,它不起作用。根据我尝试过的不同解决方案,我收到了很多错误代码。
最近的是:
ValueError: DataFrame constructor not properly called!
但是当我尝试解决这个问题时,我收到了其他错误消息,例如:
'numpy.ndarray' object has no attribute 'lower'
或:
ValueError: X has 1 features, but MultinomialNB is expecting 26150 features as input.
或:
sklearn.exceptions.NotFittedError: Vocabulary not fitted or provided
基本上我不知道自己在做什么,几周来我一直在努力弄清楚。我的倾向是,问题要么是模型无法读取来自用户的格式,要么是矢量化器无法处理输入。
或者我的整个方法可能是错误的,并且我缺少一些步骤。对此的任何帮助将不胜感激。
我的模型代码如下所示(预处理后):
#Split into training and testing data
x = df['text']
y = df['sentiment']
df1 = df[df["text"].notnull()]
x1 = df1['text']
y1 = df1['sentiment']
x1_train, x1_test, y1_train, y1_test = train_test_split(x1, y1, test_size=0.2, random_state=30)
# Vectorize text
vec = CountVectorizer(stop_words='english')
x1 = vec.fit_transform(x1).toarray()
x1_test = vec.transform(x1_test).toarray()
df1 = df1.replace(r'^\s*$', np.nan, regex=True)
from sklearn.naive_bayes import MultinomialNB
sentiment_model = MultinomialNB()
sentiment_model.fit(x1, y1)
sentiment_model.score(x1_test, y1_test)
# Save model to disk
pickle.dump(sentiment_model, open('sentiment_model.pkl','wb'))
我的应用程序代码如下所示:
@app.route('/journal', methods=['GET', 'POST'])
def entry():
if request.method == 'POST':
journals = request.form
entry_date = journals['entry_date']
journal_entry = journals['journal_entry']
vec = CountVectorizer(stop_words='english')
sdf = pd.DataFrame('journal_entry')
sdf = vec.fit_transform(sdf).toarray()
sdf = vec.transform(sdf).toarray()
sentiment = sentiment_model.predict(sdf)
journals['sentiment'] = sentiment
cur = mysql.connection.cursor()
#insert the values with sentiment attribute into database
cur.execute("INSERT INTO journals(entry_date, journal_entry, sentiment) VALUES(%s, %s, %s)",(entry_date, journal_entry, sentiment))
mysql.connection.commit()
return render_template('journal.html')
对于开始这一旅程的人来说,数据科学管道可能会很棘手。目前的代码只有一个主要问题。您正在使用每个新的传入数据重新创建预处理步骤。您训练模型的矢量器不再使用,因此功能不匹配。请记住,我们在 fitting/training 期间只 .fit_tranform
。我们在使用的时候,只.transform
.
您可以像处理模型一样,通过保存经过训练的向量化器来修复它。然后模型和向量化器都将用于 API 个端点 model.predict(vec.transform(data))
.
更好的方法是将您的预处理(向量化器)和分类器合并为一个。
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
sentiment_model = Pipeline(
steps=[
(
"count_verctorizer",CountVectorizer(stop_words='english')
),
(
"naive_bayes", MultinomialNB()
)
])
# now, it performs transformation in a pipeline
sentiment_model.fit(X1, y1)
# now we can use it/save it to use in our API we’re you will only need the model as the model will do `vectorizer tranform` for you
在API上,可以确保如果没有值和正则表达式也执行过滤的其他步骤。如果需要,您可以将它们添加到管道中。
...
journal_entry = journals['journal_entry']
X = pd.DataFrame(journal_entry) # this should be like your X1
X = X.replace(r'^\s*$', np.nan, regex=True)
X = X[X ["text"].notnull()]
# assuming we have loaded our model
sentiment = sentiment_model.predict(X)
...
所以在我看来,这里有多个问题在起作用。
首先,sdf = pd.DataFrame('journal_entry')
没有意义——您从文字字符串 'journal_entry' 创建数据框,而不是它的实际内容?我建议您完全摆脱 entry
函数中的 DataFrame,因为它不是 sklearn 对象必需的输入结构。
其次,您通过调用 fit_transform
复制功能,然后在 entry
函数中再次调用 transform
。调用 fit_transform
就足够了,因为它正在做两件事:1) 它学习字典 2) 它转换为文档术语矩阵。
第三,您使用特定的 CountVectorizer 模型训练了您的模型。该模型将使用学习的文档术语矩阵将每个文档转换为向量,该矩阵在您调用 fit
或 fit_transform
函数时获得固定大小。然后使用这个固定大小的向量训练你的朴素贝叶斯模型。因此,当它在推理时获得不同大小的向量时它会抱怨——这是因为您在每次 entry
调用时再次重新初始化 CountVectorizer
。如果要保留特征大小,还需要保存 CountVectorizer
。
此外,我建议检查您的 entry
函数,确保您在 POST 请求中获得算法的有效字符串。
# load both CountVectorizer and the model
vec = pickle.load(open("my_count_vec.pkl", "rb"))
sentiment_model = pickle.load(open("my_sentiment_model", "rb"))
@app.route('/journal', methods=['GET', 'POST'])
def entry():
if request.method == 'POST':
journals = request.form
entry_date = journals['entry_date']
journal_entry = journals['journal_entry']
sdf = vec.transform([journal_entry]).reshape(1, -1)
sentiment = sentiment_model.predict(sdf)
...
sdf = vec.transform([journal_entry]).reshape(1, -1)
假定日记条目是单个字符串,因此需要重塑以进行进一步处理。
我正在尝试将我的机器学习朴素贝叶斯情绪分析模型部署到 Web 应用程序中。这个想法是用户应该键入一些文本,应用程序对其执行情感分析,然后将具有指定情感的文本存储在数据库中的另一列中,稍后通过 html 作为列表调用。
虽然模型和矢量化器在 Google Colab 上工作正常,但当我将模型加载到我的应用程序并尝试 运行 用户通过它输入时,它不起作用。根据我尝试过的不同解决方案,我收到了很多错误代码。
最近的是:
ValueError: DataFrame constructor not properly called!
但是当我尝试解决这个问题时,我收到了其他错误消息,例如:
'numpy.ndarray' object has no attribute 'lower'
或:
ValueError: X has 1 features, but MultinomialNB is expecting 26150 features as input.
或:
sklearn.exceptions.NotFittedError: Vocabulary not fitted or provided
基本上我不知道自己在做什么,几周来我一直在努力弄清楚。我的倾向是,问题要么是模型无法读取来自用户的格式,要么是矢量化器无法处理输入。
或者我的整个方法可能是错误的,并且我缺少一些步骤。对此的任何帮助将不胜感激。
我的模型代码如下所示(预处理后):
#Split into training and testing data
x = df['text']
y = df['sentiment']
df1 = df[df["text"].notnull()]
x1 = df1['text']
y1 = df1['sentiment']
x1_train, x1_test, y1_train, y1_test = train_test_split(x1, y1, test_size=0.2, random_state=30)
# Vectorize text
vec = CountVectorizer(stop_words='english')
x1 = vec.fit_transform(x1).toarray()
x1_test = vec.transform(x1_test).toarray()
df1 = df1.replace(r'^\s*$', np.nan, regex=True)
from sklearn.naive_bayes import MultinomialNB
sentiment_model = MultinomialNB()
sentiment_model.fit(x1, y1)
sentiment_model.score(x1_test, y1_test)
# Save model to disk
pickle.dump(sentiment_model, open('sentiment_model.pkl','wb'))
我的应用程序代码如下所示:
@app.route('/journal', methods=['GET', 'POST'])
def entry():
if request.method == 'POST':
journals = request.form
entry_date = journals['entry_date']
journal_entry = journals['journal_entry']
vec = CountVectorizer(stop_words='english')
sdf = pd.DataFrame('journal_entry')
sdf = vec.fit_transform(sdf).toarray()
sdf = vec.transform(sdf).toarray()
sentiment = sentiment_model.predict(sdf)
journals['sentiment'] = sentiment
cur = mysql.connection.cursor()
#insert the values with sentiment attribute into database
cur.execute("INSERT INTO journals(entry_date, journal_entry, sentiment) VALUES(%s, %s, %s)",(entry_date, journal_entry, sentiment))
mysql.connection.commit()
return render_template('journal.html')
对于开始这一旅程的人来说,数据科学管道可能会很棘手。目前的代码只有一个主要问题。您正在使用每个新的传入数据重新创建预处理步骤。您训练模型的矢量器不再使用,因此功能不匹配。请记住,我们在 fitting/training 期间只 .fit_tranform
。我们在使用的时候,只.transform
.
您可以像处理模型一样,通过保存经过训练的向量化器来修复它。然后模型和向量化器都将用于 API 个端点 model.predict(vec.transform(data))
.
更好的方法是将您的预处理(向量化器)和分类器合并为一个。
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
sentiment_model = Pipeline(
steps=[
(
"count_verctorizer",CountVectorizer(stop_words='english')
),
(
"naive_bayes", MultinomialNB()
)
])
# now, it performs transformation in a pipeline
sentiment_model.fit(X1, y1)
# now we can use it/save it to use in our API we’re you will only need the model as the model will do `vectorizer tranform` for you
在API上,可以确保如果没有值和正则表达式也执行过滤的其他步骤。如果需要,您可以将它们添加到管道中。
...
journal_entry = journals['journal_entry']
X = pd.DataFrame(journal_entry) # this should be like your X1
X = X.replace(r'^\s*$', np.nan, regex=True)
X = X[X ["text"].notnull()]
# assuming we have loaded our model
sentiment = sentiment_model.predict(X)
...
所以在我看来,这里有多个问题在起作用。
首先,sdf = pd.DataFrame('journal_entry')
没有意义——您从文字字符串 'journal_entry' 创建数据框,而不是它的实际内容?我建议您完全摆脱 entry
函数中的 DataFrame,因为它不是 sklearn 对象必需的输入结构。
其次,您通过调用 fit_transform
复制功能,然后在 entry
函数中再次调用 transform
。调用 fit_transform
就足够了,因为它正在做两件事:1) 它学习字典 2) 它转换为文档术语矩阵。
第三,您使用特定的 CountVectorizer 模型训练了您的模型。该模型将使用学习的文档术语矩阵将每个文档转换为向量,该矩阵在您调用 fit
或 fit_transform
函数时获得固定大小。然后使用这个固定大小的向量训练你的朴素贝叶斯模型。因此,当它在推理时获得不同大小的向量时它会抱怨——这是因为您在每次 entry
调用时再次重新初始化 CountVectorizer
。如果要保留特征大小,还需要保存 CountVectorizer
。
此外,我建议检查您的 entry
函数,确保您在 POST 请求中获得算法的有效字符串。
# load both CountVectorizer and the model
vec = pickle.load(open("my_count_vec.pkl", "rb"))
sentiment_model = pickle.load(open("my_sentiment_model", "rb"))
@app.route('/journal', methods=['GET', 'POST'])
def entry():
if request.method == 'POST':
journals = request.form
entry_date = journals['entry_date']
journal_entry = journals['journal_entry']
sdf = vec.transform([journal_entry]).reshape(1, -1)
sentiment = sentiment_model.predict(sdf)
...
sdf = vec.transform([journal_entry]).reshape(1, -1)
假定日记条目是单个字符串,因此需要重塑以进行进一步处理。