Pandas Serving
Make sure you have installed Foxcross with the pandas extra using:
pip install foxcross[pandas]
Overview
Serving pandas based models works very similar to the basic model serving with a few caveats:
- The class to subclass changes from
ModelServing
toDataFrameModelServing
- The internal data structure for the model should be either a pandas DataFrame or a dictionary of pandas DataFrames with string keys
- Running the model serving requires using
run_pandas_serving
fromfoxcross.pandas_serving
- Composing serving models requires using
compose_pandas
fromfoxcross.pandas_serving
Basic Example
directory structure
.
+-- data.json
+-- models.py
data.json
{
"A": [12,4,5,null,1],
"B": [null,2,54,3,null],
"C": [20,16,null,3,8],
"D": [14, 3,null,null,6]
}
models.py
from foxcross.pandas_serving import DataFrameModelServing, run_pandas_serving
import pandas
class InterpolateModel(DataFrameModelServing):
test_data_path = "data.json"
def predict(self, data: pandas.DataFrame) -> pandas.DataFrame:
return data.interpolate(limit_direction="both")
if __name__ == "__main__":
run_pandas_serving()
Run the model locally:
python models.py
Navigate to localhost:8000/predict-test/
in your web browser, and you should see the
the null
values replaced. You can visit localhost:8000/
to see all the available
endpoints for your model.
Serving a dictionary of DataFrames model
Foxcross DataFrameModelServing
uses either a pandas DataFrame or a dictionary of pandas
DataFrames as its data structure.
To serve a dictionary of DataFrames, you must add "multi_dataframe": true
to your
input data.
Example
data.json
{
"multi_dataframe": true,
"interp_dict": {
"A": [12,4,5,null,1],
"B": [null,2,54,3,null],
"C": [20,16,null,3,8],
"D": [14, 3,null,null,6]
},
"interp_list": [
0.0, null, -1.0, 1.0,
null, 2.0, null, null,
2.0, 3.0, null, 9.0,
null, 4.0, -4.0, 16.0
]
}
models.py
from typing import Dict
from foxcross.pandas_serving import DataFrameModelServing
import pandas
class InterpolateMultiDataFrameModel(DataFrameModelServing):
test_data_path = "data.json"
def predict(
self, data: Dict[str, pandas.DataFrame]
) -> Dict[str, pandas.DataFrame]:
return {
key: value.interpolate(limit_direction="both")
for key, value in data.items()
}
Serving pandas and regular models
Foxcross can serve both your regular models that inherit from ModelServing
and
DataFrameModelServing
together. You must use either run_pandas_serving
or
compose_pandas
whenever your models use DataFrameModelServing
.
Example
directory structure
.
+-- add.json
+-- interpolate.json
+-- models.py
interpolate.json
{
"A": [12,4,5,null,1],
"B": [null,2,54,3,null],
"C": [20,16,null,3,8],
"D": [14, 3,null,null,6]
}
add.json
[1,2,3,4,5]
models.py
from foxcross.pandas_serving import DataFrameModelServing, run_pandas_serving
from foxcross.serving import ModelServing
import pandas
class InterpolateModel(DataFrameModelServing):
test_data_path = "interpolate.json"
def predict(self, data: pandas.DataFrame) -> pandas.DataFrame:
return data.interpolate(limit_direction="both")
class AddOneModel(ModelServing):
test_data_path = "add.json"
def predict(self, data):
return [x + 1 for x in data]
if __name__ == "__main__":
run_pandas_serving()
Run the model locally:
python models.py
Navigate to localhost:8000/
in your web browser, and you should see both the
/addonemodel
and the /interpolatemodel
.
Changing the orient of Pandas output
Foxcross uses the Pandas to_dict
method before turning results into JSON. The to_dict
method uses an orient
argument to
determine the output format. The default orient used by Foxcross is index
, but
this can be changed.
Example
models.py
from foxcross.pandas_serving import DataFrameModelServing
import pandas
class InterpolateModel(DataFrameModelServing):
test_data_path = "data.json"
pandas_orient = "records"
def predict(self, data: pandas.DataFrame) -> pandas.DataFrame:
return data.interpolate(limit_direction="both")