<jupyter_start><jupyter_text>Model TrainingThe purpose of this script is simply to create a functional machine learning model that can be serialized for reuse. I'm incorporating sklearn's pipeline and gridsearch utilities.This model uses sklearn's [wine](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_wine.htmlsklearn.datasets.load_wine) dataset. Helpful references* [sklearn: Selecting dimensionality reduction with Pipeline and GridSearchCV](https://scikit-learn.org/stable/auto_examples/compose/plot_compare_reduction.html)* [sklearn: Putting it all together](https://scikit-learn.org/stable/tutorial/statistical_inference/putting_together.html)* [Importance of feature scaling](https://scikit-learn.org/stable/auto_examples/preprocessing/plot_scaling_importance.htmlsphx-glr-auto-examples-preprocessing-plot-scaling-importance-py) Documentation* [sklearn: SelectKBest](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectKBest.html)* [sklearn: RandomForestClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html)* [sklearn: Pipeline](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html)* [sklearn: GridSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html)* [sklearn: Normalizer](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.Normalizer.htmlsklearn.preprocessing.Normalizer)<jupyter_code>from sklearn.datasets import load_wine
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import Pipeline
from sklearn.feature_selection import SelectKBest, chi2
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.metrics import classification_report, accuracy_score, f1_score

features, target = load_wine(return_X_y=True)

X_train, X_test, y_train, y_test = train_test_split(features, target,
                                                    test_size=0.30)
scaler = StandardScaler()
clf = RandomForestClassifier(n_estimators=100, min_samples_leaf=5)
pipeline = Pipeline(steps=[('reduce_dim', SelectKBest(chi2)),
                           ('scaler', scaler),
                           ('clf', clf)])
n_feature_options = [2, 4, 8, 10, 12]
n_estimators_options = [10, 50, 100, 200]
min_samples_leaf_options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
param_grid = [
    {
        'reduce_dim__k': n_feature_options,
        'clf__criterion': ['gini', 'entropy'],
        'clf__n_estimators': n_estimators_options,
        'clf__min_samples_leaf': min_samples_leaf_options
    }
]

grid = GridSearchCV(pipeline, cv=5, param_grid=param_grid, iid=False)
grid.fit(X_train, y_train)
grid.best_params_
y_pred = grid.predict(X_test)
print('accuracy_score:', accuracy_score(y_test, y_pred))
print('f1_score:', f1_score(y_test, y_pred, average='weighted'))
print(classification_report(y_test, y_pred))<jupyter_output>accuracy_score: 0.9814814814814815
f1_score: 0.9814814814814815
              precision    recall  f1-score   support

           0       0.95      1.00      0.98        20
           1       1.00      0.95      0.98        21
           2       1.00      1.00      1.00        13

    accuracy                           0.98        54
   macro avg       0.98      0.98      0.98        54
weighted avg       0.98      0.98      0.98        54<jupyter_text>GridSearchCV IntrospectionWe'll need to see which features were selected by the model in order to use it for future prediction.<jupyter_code>features = load_wine().feature_names
selected = grid.best_estimator_.named_steps['reduce_dim'].get_support()

print('< included >')
for f, s in zip(features, selected):
    if s:
        print(f)
        
print('\n< excluded >')
for f, s in zip(features, selected):
    if not s:
        print(f)<jupyter_output>< included >
alcohol
malic_acid
alcalinity_of_ash
magnesium
total_phenols
flavanoids
nonflavanoid_phenols
proanthocyanins
color_intensity
hue
od280/od315_of_diluted_wines
proline

< excluded >
ash<jupyter_text>Upload serialized model to S3<jupyter_code>import os
import boto3
import pickle

session = boto3.Session(aws_access_key_id=os.getenv('AWS_ADMIN_ACCESS'),
                        aws_secret_access_key=os.getenv('AWS_ADMIN_SECRET'))

s3 = session.resource('s3')

bytes_obj = pickle.dumps(grid.best_estimator_, protocol=pickle.HIGHEST_PROTOCOL)

bucket = 'gwilson253awsprojects'
key = 'neptune/wine_model.pkl'

s3.Object(bucket,key).put(Body=bytes_obj)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10165073848827107, 'fraction_numerical': 0.03366637706342311, 'mean_word_length': 4.1625560538116595, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 9, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '166969', 'license': 'MIT', 'n_tokens_mistral': 1615, 'n_tokens_neox': 1503, 'n_words': 286, 'path': 'jupyter_lab/model_training.ipynb', 'repo_name': 'gwilson253/neptune', 'size': '4604'}