Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Version
~VetiverModel
~vetiver_pin_write
~vetiver_create_ptype
~model_card

Deploy
==================
Expand Down
800 changes: 699 additions & 101 deletions vetiver/data/chicago.csv

Large diffs are not rendered by default.

78 changes: 73 additions & 5 deletions vetiver/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def compute_metrics(
metric_set: list,
truth: str,
estimate: str,
**kw,
) -> pd.DataFrame:
"""
Compute metrics for given time period
Expand All @@ -32,6 +33,8 @@ def compute_metrics(

Example
-------
>>> from datetime import timedelta
>>> import pandas as pd
>>> from sklearn.metrics import mean_squared_error, mean_absolute_error
>>> df = pd.DataFrame(
... {
Expand Down Expand Up @@ -62,7 +65,9 @@ def compute_metrics(
"index": i.index[0],
"n": len(i),
"metric": m.__qualname__,
"estimate": m(y_pred=i[truth], y_true=i[estimate]),
# TODO: non-y_pred and y_true metrics
# TODO: multioutput metrics
"estimate": m(y_pred=i[estimate], y_true=i[truth], **kw),
}
]

Expand Down Expand Up @@ -105,11 +110,50 @@ def pin_metrics(
The column in df_metrics containing the aggregated dates or datetimes.
Note that this defaults to a column named "index".
overwrite: bool
If TRUE (the default), overwrite any metrics for
dates that exist both in the existing pin and
new metrics with the new values. If FALSE, error
when the new metrics contain overlapping dates with
If True, overwrite any metrics for dates that exist both
in the existing pin and new metrics with the new values.
If False, error when the new metrics contain overlapping dates with
the existing pin.

Example
-------
>>> import pins
>>> import vetiver
>>> df = pd.DataFrame(
... {'index': {0: pd.Timestamp('2021-01-01 00:00:00'),
... 1: pd.Timestamp('2021-01-01 00:00:00'),
... 2: pd.Timestamp('2021-01-02 00:00:00'),
... 3: pd.Timestamp('2021-01-02 00:00:00')},
... 'n': {0: 1, 1: 1, 2: 1, 3: 1},
... 'metric': {0: 'mean_squared_error',
... 1: 'mean_absolute_error',
... 2: 'mean_squared_error',
... 3: 'mean_absolute_error'},
... 'estimate': {0: 4.0, 1: 2.0, 2: 1.0, 3: 1.0}}
... )
>>> board = pins.board_temp()

>>> board.pin_write(df, "metrics", type = "csv") # doctest: +SKIP
>>> df = pd.DataFrame(
... {'index': {0: pd.Timestamp('2021-01-02 00:00:00'),
... 1: pd.Timestamp('2021-01-02 00:00:00'),
... 2: pd.Timestamp('2021-01-03 00:00:00'),
... 3: pd.Timestamp('2021-01-03 00:00:00')},
... 'n': {0: 1, 1: 1, 2: 1, 3: 1},
... 'metric': {0: 'mean_squared_error',
... 1: 'mean_absolute_error',
... 2: 'mean_squared_error',
... 3: 'mean_absolute_error'},
... 'estimate': {0: 4.0, 1: 6.0, 2: 2.0, 3: 1.0}}
... )
>>> vetiver.pin_metrics( # doctest: +SKIP
... board=board,
... df_metrics=df2,
... metrics_pin_name="metrics",
... index_name="index",
... overwrite=True)


"""

old_metrics_raw = board.pin_read(metrics_pin_name)
Expand Down Expand Up @@ -170,6 +214,30 @@ def plot_metrics(
Column in `df_metrics` containing metric name
n: str
Column in `df_metrics` containing number of observations

Example
-------
>>> import vetiver
>>> import pandas as pd
>>> df = pd.DataFrame(
... {'index': {0: pd.Timestamp('2021-01-01 00:00:00'),
... 1: pd.Timestamp('2021-01-01 00:00:00'),
... 2: pd.Timestamp('2021-01-02 00:00:00'),
... 3: pd.Timestamp('2021-01-02 00:00:00')},
... 'n': {0: 1, 1: 1, 2: 1, 3: 1},
... 'metric': {0: 'mean_squared_error',
... 1: 'mean_absolute_error',
... 2: 'mean_squared_error',
... 3: 'mean_absolute_error'},
... 'estimate': {0: 4.0, 1: 2.0, 2: 1.0, 3: 1.0}}
... )
>>> plot = vetiver.plot_metrics(
... df_metrics = df,
... date = "index",
... estimate = "estimate",
... metric = "metric",
... n = "n")
>>> plot.show() # doctest: +SKIP
"""

fig = px.line(
Expand Down
14 changes: 11 additions & 3 deletions vetiver/pin_read_write.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import warnings
from .vetiver_model import VetiverModel
from .utils import inform
import warnings
import logging

_log = logging.getLogger(__name__)


class ModelCard(UserWarning):
Expand Down Expand Up @@ -30,8 +34,12 @@ def vetiver_pin_write(board, model: VetiverModel, versioned: bool = True):
if not board.allow_pickle_read:
raise NotImplementedError # must be pickle-able

warnings.simplefilter("once", ModelCard)
warnings.warn(ModelCard().message)
inform(
_log,
"Model Cards provide a framework for transparent, responsible "
"reporting. \n Use the vetiver `.qmd` Quarto template as a place to start, \n "
"with vetiver.model_card()",
)

board.pin_write(
model.model,
Expand Down
9 changes: 5 additions & 4 deletions vetiver/tests/test_rsconnect.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,17 @@ def test_board_pin_write(rsc_short):

@pytest.mark.xfail
def test_deploy(rsc_short):
# TODO: test in Dockerfile
v = vetiver.VetiverModel(
model=model, ptype_data=X_df, model_name="susan/model", versioned=None
)

vetiver.vetiver_pin_write(board=rsc_short, model=v)

connect_server = RSConnectServer(
url=RSC_SERVER_URL, api_key=server_from_key("susan")
)
vetiver.deploy_rsconnect(
connect_server=server_from_key("susan"), board=rsc_short, pin_name="susan/model"
connect_server=connect_server, board=rsc_short, pin_name="susan/model"
)
response = vetiver.predict(RSC_SERVER_URL + "/predict/", json=X_df)
response = vetiver.predict(RSC_SERVER_URL + "/predict", json=X_df)
assert response.status_code == 200, response.text
assert response.json() == {"prediction": [44.47, 44.47]}, response.json()
13 changes: 13 additions & 0 deletions vetiver/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import nest_asyncio
import warnings
import sys
from types import SimpleNamespace

no_notebook = False
try:
Expand All @@ -18,3 +20,14 @@ def _jupyter_nb():
nest_asyncio.apply()
else:
return False


modelcard_options = SimpleNamespace(quiet=False)


def inform(log, msg):
if log is not None:
log.info(msg)

if not modelcard_options.quiet:
print(msg, file=sys.stderr)