将 pandas 数据帧传递给 FastAPI 用于 NLP ML
Posted
技术标签:
【中文标题】将 pandas 数据帧传递给 FastAPI 用于 NLP ML【英文标题】:Passing a pandas dataframe to FastAPI for NLP ML 【发布时间】:2020-11-20 17:48:15 【问题描述】:我第一次尝试部署 NLP ML 模型。为此,建议我使用 FastAPI 和 uvicorn。我在让 FastAPI 做出响应方面取得了一些成功;但是,我无法成功传递数据帧并让它处理它。我尝试过使用字典,甚至尝试将传递的 json 转换为数据帧。
data_dict = data.dict()
我得到:
ValueError: Iterable over raw text documents expected, string object received.
data_dict = pd.DataFrame(data.dict())
我得到:
ValueError: If using all scalar values, you must pass an index
我相信我理解这个问题,我的 Data 类需要一个字符串,而这不是;但是,我无法确定如何设置和/或传递预期数据,以便 fit_transform() 起作用。最终,我将根据提交的消息值返回预测。如果我可以传递 1 行或更多行的数据帧并为每一行做出并返回预测,则奖励。响应将包括 id、项目和预测,以便我们将来能够利用此响应将预测发布回原始(请求)系统。
test_connection.py
#%%
import requests
import pandas as pd
import json
import os
from pprint import pprint
url = 'http://127.0.0.1:8000/predict'
print(os.getcwd())
#%%
df = pd.DataFrame(
'id': ['ab410483801c38', 'cd34148639180'],
'project': ['project1', 'project2'],
'messages': ['This is message 1', 'This is message 2']
)
to_predict_dict = df.iloc[0].to_dict()
#%%
r = requests.post(url, json=to_predict_dict)
main.py
#!/usr/bin/env python
# coding: utf-8
import pickle
import pandas as pd
import numpy as np
from pydantic import BaseModel
from sklearn.feature_extraction.text import TfidfVectorizer
# Server
import uvicorn
from fastapi import FastAPI
# Model
import xgboost as xgb
app = FastAPI()
clf = pickle.load(open('data/xgbmodel.pickle', 'rb'))
class Data(BaseModel):
# id: str
project: str
messages: str
@app.get("/ping")
async def test():
return "ping": "pong"
@app.post("/predict")
async def predict(data: Data):
# data_dict = data.dict()
data_dict = pd.DataFrame(data.dict())
tfidf_vect = TfidfVectorizer(stop_words="english", analyzer='word', token_pattern=r'\w1,')
tfidf_vect.fit_transform(data_dict['messages'])
# to_predict = tfidf_vect.transform(data_dict['messages'])
# prediction = clf.predict(to_predict)
return "response": "Success"
【问题讨论】:
如果没有DataFrame
in main.py
就不能这样做吗? fit_transform(data.messages)
?
不,那是我收到 ValueError 字符串的时候。抱歉,我的帖子中没有明确说明,但这些错误实际上发生在 fit_transform() 步骤中。
我要补充一点,我没有尝试过使用点表示法,我只尝试过使用括号。不确定有什么不同,但会试一试。
跳过整个 data_dict = data.dict() 并简单地使用 data.messages 不起作用。问题是我的 Data 类,其中我将数据特征定义为 str 并且 fit_transofrm 需要原始文本文档。
我的错误 - 名称 messages
具有误导性 - 我认为它提供了消息列表。对于单个消息(单个字符串),我将使用名称 message
而不使用 s
【参考方案1】:
可能不是最优雅的解决方案,但我使用以下方法取得了进展:
def predict(data: Data):
data_dict = pd.DataFrame(
'id': [data.id],
'project': [data.project],
'messages': [data.messages]
)
【讨论】:
取消注释剩余代码,tfidf_vect,to_predict,预测,并尝试return "Prediction": prediction results in a dump of data ending in
in input data`和错误JSONDecodeError: Expecting value: line 1 column 1 (char 0)
如果我有很多(例如40+)列,这个解决方案会不会很难实现?【参考方案2】:
我可以通过简单地将data.messages
转换为一个列表来解决这个问题。我还必须进行一些不相关的更改,我未能腌制我的矢量化器(字符串标记器)。
import pickle
import pandas as pd
import numpy as np
import json
import time
from pydantic import BaseModel
from sklearn.feature_extraction.text import TfidfVectorizer
# Server / endpoint
import uvicorn
from fastapi import FastAPI
# Model
import xgboost as xgb
app = FastAPI(debug=True)
clf = pickle.load(open('data/xgbmodel.pickle', 'rb'))
vect = pickle.load(open('data/tfidfvect.pickle', 'rb'))
class Data(BaseModel):
id: str = None
project: str
messages: str
@app.get("/ping")
async def ping():
return "ping": "pong"
@app.post("/predict/")
def predict(data: Data):
start = time.time()
data_l = [data.messages] # make messages iterable.
to_predict = vect.transform(data_l)
prediction = clf.predict(to_predict)
exec_time = round((time.time() - start), 3)
return
"id": data.id,
"project": data.project,
"prediction": prediction[0],
"execution_time": exec_time
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8000)
【讨论】:
【参考方案3】:首先,将您的数据帧df
编码为面向 JSON 记录:
r = requests.post(url, json=df.to_json(orient='records'))
.
然后,解码/predict/
端点内的数据:
df = pd.DataFrame(jsonable_encoder(data))
记得导入模块from fastapi.encoders import jsonable_encoder
。
【讨论】:
正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center。以上是关于将 pandas 数据帧传递给 FastAPI 用于 NLP ML的主要内容,如果未能解决你的问题,请参考以下文章