Skip to content

Commit

Permalink
add wine
Browse files Browse the repository at this point in the history
  • Loading branch information
willeasp committed Nov 12, 2023
1 parent 2d4ea8f commit fd02d00
Show file tree
Hide file tree
Showing 8 changed files with 8,808 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/wine/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#If you have windows, install twofish
#twofish
hopsworks
joblib
scikit-learn==1.1.1
seaborn
dataframe-image
modal
gradio==3.14
1,600 changes: 1,600 additions & 0 deletions src/wine/wine+quality/winequality-red.csv

Large diffs are not rendered by default.

4,899 changes: 4,899 additions & 0 deletions src/wine/wine+quality/winequality-white.csv

Large diffs are not rendered by default.

72 changes: 72 additions & 0 deletions src/wine/wine+quality/winequality.names
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
Citation Request:
This dataset is public available for research. The details are described in [Cortez et al., 2009].
Please include this citation if you plan to use this database:

P. Cortez, A. Cerdeira, F. Almeida, T. Matos and J. Reis.
Modeling wine preferences by data mining from physicochemical properties.
In Decision Support Systems, Elsevier, 47(4):547-553. ISSN: 0167-9236.

Available at: [@Elsevier] http://dx.doi.org/10.1016/j.dss.2009.05.016
[Pre-press (pdf)] http://www3.dsi.uminho.pt/pcortez/winequality09.pdf
[bib] http://www3.dsi.uminho.pt/pcortez/dss09.bib

1. Title: Wine Quality

2. Sources
Created by: Paulo Cortez (Univ. Minho), Antonio Cerdeira, Fernando Almeida, Telmo Matos and Jose Reis (CVRVV) @ 2009

3. Past Usage:

P. Cortez, A. Cerdeira, F. Almeida, T. Matos and J. Reis.
Modeling wine preferences by data mining from physicochemical properties.
In Decision Support Systems, Elsevier, 47(4):547-553. ISSN: 0167-9236.

In the above reference, two datasets were created, using red and white wine samples.
The inputs include objective tests (e.g. PH values) and the output is based on sensory data
(median of at least 3 evaluations made by wine experts). Each expert graded the wine quality
between 0 (very bad) and 10 (very excellent). Several data mining methods were applied to model
these datasets under a regression approach. The support vector machine model achieved the
best results. Several metrics were computed: MAD, confusion matrix for a fixed error tolerance (T),
etc. Also, we plot the relative importances of the input variables (as measured by a sensitivity
analysis procedure).

4. Relevant Information:

The two datasets are related to red and white variants of the Portuguese "Vinho Verde" wine.
For more details, consult: http://www.vinhoverde.pt/en/ or the reference [Cortez et al., 2009].
Due to privacy and logistic issues, only physicochemical (inputs) and sensory (the output) variables
are available (e.g. there is no data about grape types, wine brand, wine selling price, etc.).

These datasets can be viewed as classification or regression tasks.
The classes are ordered and not balanced (e.g. there are munch more normal wines than
excellent or poor ones). Outlier detection algorithms could be used to detect the few excellent
or poor wines. Also, we are not sure if all input variables are relevant. So
it could be interesting to test feature selection methods.

5. Number of Instances: red wine - 1599; white wine - 4898.

6. Number of Attributes: 11 + output attribute

Note: several of the attributes may be correlated, thus it makes sense to apply some sort of
feature selection.

7. Attribute information:

For more information, read [Cortez et al., 2009].

Input variables (based on physicochemical tests):
1 - fixed acidity
2 - volatile acidity
3 - citric acid
4 - residual sugar
5 - chlorides
6 - free sulfur dioxide
7 - total sulfur dioxide
8 - density
9 - pH
10 - sulphates
11 - alcohol
Output variable (based on sensory data):
12 - quality (score between 0 and 10)

8. Missing Attribute Values: None
109 changes: 109 additions & 0 deletions src/wine/wine-batch-inference-pipeline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import os
import modal

LOCAL=True

if LOCAL == False:
stub = modal.Stub()
hopsworks_image = modal.Image.debian_slim().pip_install(["hopsworks","joblib","seaborn","scikit-learn==1.2.2","dataframe-image"])
@stub.function(image=hopsworks_image, schedule=modal.Period(days=1), secret=modal.Secret.from_name("hopsworks api key"))
def f():
g()

def g():
import pandas as pd
import hopsworks
import joblib
import datetime
from PIL import Image
from datetime import datetime
import dataframe_image as dfi
from sklearn.metrics import confusion_matrix
from matplotlib import pyplot
import seaborn as sns
import requests

project = hopsworks.login()
fs = project.get_feature_store()

mr = project.get_model_registry()
model = mr.get_model("iris_model", version=2)
model_dir = model.download()
model = joblib.load(model_dir + "/iris_model.pkl")

feature_view = fs.get_feature_view(name="iris", version=1)
batch_data = feature_view.get_batch_data()

y_pred = model.predict(batch_data)
#print(y_pred)
offset = 1
flower = y_pred[y_pred.size-offset]
flower_url = "https://raw.githubusercontent.com/featurestoreorg/serverless-ml-course/main/src/01-module/assets/" + flower + ".png"
print("Flower predicted: " + flower)
img = Image.open(requests.get(flower_url, stream=True).raw)
img.save("./latest_iris.png")
dataset_api = project.get_dataset_api()
dataset_api.upload("./latest_iris.png", "Resources/images", overwrite=True)

iris_fg = fs.get_feature_group(name="iris", version=1)
df = iris_fg.read()
#print(df)
label = df.iloc[-offset]["variety"]
label_url = "https://raw.githubusercontent.com/featurestoreorg/serverless-ml-course/main/src/01-module/assets/" + label + ".png"
print("Flower actual: " + label)
img = Image.open(requests.get(label_url, stream=True).raw)
img.save("./actual_iris.png")
dataset_api.upload("./actual_iris.png", "Resources/images", overwrite=True)

monitor_fg = fs.get_or_create_feature_group(name="iris_predictions",
version=1,
primary_key=["datetime"],
description="Iris flower Prediction/Outcome Monitoring"
)

now = datetime.now().strftime("%m/%d/%Y, %H:%M:%S")
data = {
'prediction': [flower],
'label': [label],
'datetime': [now],
}
monitor_df = pd.DataFrame(data)
monitor_fg.insert(monitor_df, write_options={"wait_for_job" : False})

history_df = monitor_fg.read()
# Add our prediction to the history, as the history_df won't have it -
# the insertion was done asynchronously, so it will take ~1 min to land on App
history_df = pd.concat([history_df, monitor_df])


df_recent = history_df.tail(4)
dfi.export(df_recent, './df_recent.png', table_conversion = 'matplotlib')
dataset_api.upload("./df_recent.png", "Resources/images", overwrite=True)

predictions = history_df[['prediction']]
labels = history_df[['label']]

# Only create the confusion matrix when our iris_predictions feature group has examples of all 3 iris flowers
print("Number of different flower predictions to date: " + str(predictions.value_counts().count()))
if predictions.value_counts().count() == 3:
results = confusion_matrix(labels, predictions)

df_cm = pd.DataFrame(results, ['True Setosa', 'True Versicolor', 'True Virginica'],
['Pred Setosa', 'Pred Versicolor', 'Pred Virginica'])

cm = sns.heatmap(df_cm, annot=True)
fig = cm.get_figure()
fig.savefig("./confusion_matrix.png")
dataset_api.upload("./confusion_matrix.png", "Resources/images", overwrite=True)
else:
print("You need 3 different flower predictions to create the confusion matrix.")
print("Run the batch inference pipeline more times until you get 3 different iris flower predictions")


if __name__ == "__main__":
if LOCAL == True :
g()
else:
with stub.run():
f()

Loading

0 comments on commit fd02d00

Please sign in to comment.