import warnings import boto3 import numpy as np import pandas as pd from sklearn.metrics import precision_score, recall_score, f1_score import utils.s3 as s3 from utils.Snowflake2 import connect import config import query # warnings I never want to see... warnings.filterwarnings("ignore", 'This pattern has match groups') pd.options.mode.chained_assignment = None # global snowflake connection. sf = connect(config.sf_wh) print('\nSnowflake session: {}'.format( sf.q('select current_session()', resp='first')[0])) def sanitize(df): ''' Strips datetime, and descriptive features out of a training and test set. We do this because these dtypes mess up the model, and because they do not get us closer to a better prediction. ''' features = [c for c in df.columns if c not in config.cols_to_drop] return df[features] def read_excel(s3_path, s3_target, run_date): df = pd.read_excel(s3.read(s3_path), sheetname=config.sheetname) df.columns = [config.rep_col.get(col, col) for col in df.columns] s3.to_csv(df[['UPC', 'APPROVED', 'Notes']], s3_target, index=False, sep='\t', compression='gzip') return def batch_update_probs(df, s3_path): ''' Sends file to s3, and snowflake temp table. temp table used to update delivery history table. temp table is wiped, s3 file is purged ''' # sf = connect(config.sf_wh) s3.to_csv(df[['UPC', config.prob]], s3_path, index=False, sep='\t', compression='gzip') sf.create_table(s3_path, config.sf_machine_v_human, config.sf_fmt) sf.s3_2_table(s3_path, config.sf_machine_v_human, config.sf_fmt) resp = sf.q(query.batch_update_pred) # purge! sf.q('DROP TABLE {}'.format(config.sf_machine_v_human)) return resp def upload_weights(clf, latest_model, next_model, model_archive): ''' Moves old weights into archive bucket. Uploads the new weights to most recent bucket. ''' # archive old model s3.mv(latest_model, model_archive) # upload new model to s3. return s3.dump_clf(clf, next_model) def upload_meta(clf, X_train, X_test, y_train, y_test, run_date): meta = dict() y_pred = clf.predict(sanitize(X_test)) meta['TEST_SET'] = len(X_test) meta['TRAIN_SET'] = len(X_train) meta['LABELED_DATA'] = meta['TEST_SET'] + meta['TRAIN_SET'] meta['SCORE_PRECISION'] = precision_score(y_true=y_test, y_pred=y_pred) meta['SCORE_RECALL'] = recall_score(y_true=y_test, y_pred=y_pred) meta['SCORE_F1'] = f1_score(y_true=y_test, y_pred=y_pred) meta['PROCESS_DATE'] = run_date meta['SCORE_ACCURACY_TRAIN'] = clf.score(sanitize(X_train), y_train) meta['SCORE_ACCURACY_TEST'] = clf.score(sanitize(X_test), y_test) meta_toop = (meta['LABELED_DATA'], meta['PROCESS_DATE'], meta['SCORE_ACCURACY_TEST'], meta['SCORE_ACCURACY_TRAIN'], meta['SCORE_F1'], meta['SCORE_PRECISION'], meta['SCORE_RECALL'], meta['TEST_SET'], meta['TRAIN_SET']) danks = ['SCORE_ACCURACY_TEST', 'SCORE_ACCURACY_TRAIN', 'SCORE_PRECISION', 'SCORE_RECALL'] for key in danks: print('{:20s}'.format(key), '{:21.2f}%'.format(meta[key] * 100)) resp = sf.q(query.clear_meta.format(run_date=run_date)) if resp['code'] == 200: return sf.q(query.insert_meta.format(tuple=meta_toop)) def feature_importance(X, clf): feat_labels = X.columns importances = clf.feature_importances_ indicies = np.argsort(importances)[::-1] for f in range(X.shape[1]): print("%2d) %-*s %f" % (f + 1, 30, feat_labels[indicies[f]], importances[indicies[f]])) def get_genremap(): genre_map = {str(k):v for k,v in sf.q(query.genre_name, resp='df').values} return genre_map def email(to,sub,body): ''' Send an email from datarequests to whomever. Make sure the to is a list, sub and body are strings. ''' client = boto3.client('ses', 'us-east-1') FROM = 'datarequests@theorchard.com' response = client.send_email( Source=FROM, Destination={ 'ToAddresses': to }, Message={ 'Subject': { 'Data': sub, 'Charset': 'UTF-8' }, 'Body': { 'Text': { 'Data': body , 'Charset': 'UTF-8' } } } ) return response