diff --git a/assignments/.gitignore b/assignments/.gitignore new file mode 100644 index 0000000..95ef9dc --- /dev/null +++ b/assignments/.gitignore @@ -0,0 +1 @@ +assign_env diff --git a/assignments/assignment_1/.gitignore b/assignments/assignment_1/.gitignore new file mode 100644 index 0000000..32a441e --- /dev/null +++ b/assignments/assignment_1/.gitignore @@ -0,0 +1 @@ +ph_scratch diff --git a/assignments/assignment_1/assign_1_template.ipynb b/assignments/assignment_1/assign_1_template.ipynb new file mode 100644 index 0000000..ec77847 --- /dev/null +++ b/assignments/assignment_1/assign_1_template.ipynb @@ -0,0 +1,758 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1934d2de", + "metadata": {}, + "source": [ + "## License \n", + "\n", + "Copyright 2021 Patrick Hall (jphall@gwu.edu)\n", + "\n", + "Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "you may not use this file except in compliance with the License.\n", + "You may obtain a copy of the License at\n", + "\n", + " http://www.apache.org/licenses/LICENSE-2.0\n", + "\n", + "Unless required by applicable law or agreed to in writing, software\n", + "distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "See the License for the specific language governing permissions and\n", + "limitations under the License.\n", + "\n", + "*DISCLAIMER*: This notebook is not legal or compliance advice." + ] + }, + { + "cell_type": "markdown", + "id": "c7556803", + "metadata": {}, + "source": [ + "# Assignment 1 Template" + ] + }, + { + "cell_type": "markdown", + "id": "44ddbb28", + "metadata": {}, + "source": [ + "#### Imports and inits" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4baedf75", + "metadata": {}, + "outputs": [], + "source": [ + "import datetime # for timestamp \n", + "import h2o # base h2o package for python\n", + "from h2o.estimators.glm import H2OGeneralizedLinearEstimator # h2o elastic net models class\n", + "from h2o.grid.grid_search import H2OGridSearch # grid search class and syntax for h2o models\n", + "from interpret import show # basic visualizations from interpret package\n", + "from interpret.glassbox import ExplainableBoostingClassifier # interpret ebm class\n", + "from interpret.perf import ROC # ROC measure for ebm\n", + "import itertools # for cartesian product of parameters\n", + "import matplotlib.pyplot as plt # basic plotting\n", + "import numpy as np # for basic array manipulation \n", + "import pandas as pd # for dataframe manipulation\n", + "import seaborn as sns # slightly better plotting \n", + "import time # for timers\n", + "import xgboost as xgb # base xgboost package for python\n", + "\n", + "# set numpy random seed for better reproducibility\n", + "SEED = 12345 \n", + "\n", + "# set number of threads\n", + "NTHREAD = 4\n", + "\n", + "h2o.init(max_mem_size='6G', nthreads=NTHREAD) # start h2o with plenty of memory and threads\n", + "h2o.remove_all() # clears h2o memory\n", + "h2o.no_progress() # turn off h2o progress indicators " + ] + }, + { + "cell_type": "markdown", + "id": "152e8474", + "metadata": {}, + "source": [ + "#### Start global timer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "110ae3e4", + "metadata": {}, + "outputs": [], + "source": [ + "tic = time.time()" + ] + }, + { + "cell_type": "markdown", + "id": "e36c81fd", + "metadata": {}, + "source": [ + "#### Import data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36898e3f", + "metadata": {}, + "outputs": [], + "source": [ + "data = pd.read_csv('data/hmda_train_preprocessed.csv')\n", + "test = pd.read_csv('data/hmda_test_preprocessed.csv')" + ] + }, + { + "cell_type": "markdown", + "id": "02f780ca", + "metadata": {}, + "source": [ + "#### Assign basic modeling roles" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "374364cd", + "metadata": {}, + "outputs": [], + "source": [ + "y_name = 'high_priced'\n", + "x_names = ['term_360', 'conforming', 'debt_to_income_ratio_missing', 'loan_amount_std', 'loan_to_value_ratio_std', 'no_intro_rate_period_std',\n", + " 'intro_rate_period_std', 'property_value_std', 'income_std', 'debt_to_income_ratio_std']" + ] + }, + { + "cell_type": "markdown", + "id": "e594851c", + "metadata": {}, + "source": [ + "## Basic data exploration" + ] + }, + { + "cell_type": "markdown", + "id": "7985deee", + "metadata": {}, + "source": [ + "#### Histograms" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cbbaaf84", + "metadata": {}, + "outputs": [], + "source": [ + "_ = data[x_names + [y_name]].hist(bins=50, figsize=(15, 15))" + ] + }, + { + "cell_type": "markdown", + "id": "5ab0c877", + "metadata": {}, + "source": [ + "#### Correlations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1a420a5", + "metadata": {}, + "outputs": [], + "source": [ + "corr = data[x_names + [y_name]].corr()\n", + "_ = sns.heatmap(corr, \n", + " xticklabels=corr.columns.values,\n", + " yticklabels=corr.columns.values)" + ] + }, + { + "cell_type": "markdown", + "id": "2bd91ac7", + "metadata": {}, + "source": [ + "## Fit interpretable models" + ] + }, + { + "cell_type": "markdown", + "id": "b63c7465", + "metadata": {}, + "source": [ + "#### Split data into train and validation partitions " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d82faabc", + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(SEED) # preserve exact reproducibility for this cell\n", + "\n", + "split_ratio = 0.7 # 70%/30% train/test split\n", + "\n", + "# execute split\n", + "split = np.random.rand(len(data)) < split_ratio\n", + "train = data[split]\n", + "valid = data[~split]\n", + "\n", + "# summarize split\n", + "print('Train data rows = %d, columns = %d' % (train.shape[0], train.shape[1]))\n", + "print('Validation data rows = %d, columns = %d' % (valid.shape[0], valid.shape[1]))\n", + "\n", + "# benchmark - Train data rows = 112253, columns = 23\n", + "# benchmark - Validation data rows = 48085, columns = 23" + ] + }, + { + "cell_type": "markdown", + "id": "c1323de6", + "metadata": {}, + "source": [ + "### Elastic net" + ] + }, + { + "cell_type": "markdown", + "id": "b37508ef", + "metadata": {}, + "source": [ + "#### Define wrapper function for grid search" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e65a8102", + "metadata": {}, + "outputs": [], + "source": [ + "def glm_grid(x_names, y_name, htrain, hvalid, seed):\n", + "\n", + " \"\"\" Wrapper function for penalized GLM with alpha and lambda search.\n", + "\n", + " :param x_names: Names of input features.\n", + " :param y_name: Name of target feature.\n", + " :param htrain: Training H2OFrame.\n", + " :param hvalid: Validation H2OFrame.\n", + " :param seed: Random seed for better reproducibility.\n", + " :return: Best H2OGeneralizedLinearEstimator.\n", + " \"\"\"\n", + "\n", + " alpha_opts = [0.01, 0.25, 0.5, 0.99] # always keep some L2\n", + "\n", + " # define search criteria\n", + " # i.e., over alpha\n", + " # lamda search handled by lambda_search param below\n", + " hyper_parameters = {'alpha': alpha_opts}\n", + "\n", + " # initialize grid search\n", + " grid = H2OGridSearch(\n", + " H2OGeneralizedLinearEstimator(family='binomial',\n", + " lambda_search=True,\n", + " seed=seed), # seed for grid search\n", + " hyper_params=hyper_parameters)\n", + "\n", + " # execute training w/ grid search\n", + " grid.train(y=y_name,\n", + " x=x_names,\n", + " training_frame=htrain,\n", + " validation_frame=hvalid,\n", + " seed=seed) # seed for training\n", + "\n", + " # select best model from grid search\n", + " best_model = grid.get_grid()[0]\n", + " del grid\n", + "\n", + " return best_model" + ] + }, + { + "cell_type": "markdown", + "id": "9927a1f2", + "metadata": {}, + "source": [ + "#### Fit elastic net with grid search" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46a30359", + "metadata": {}, + "outputs": [], + "source": [ + "# start local timer\n", + "glm_tic = time.time()\n", + "\n", + "# convert data to h2o frames\n", + "htrain = h2o.H2OFrame(train)\n", + "hvalid = h2o.H2OFrame(valid)\n", + "\n", + "# train with grid search\n", + "best_glm = glm_grid(x_names, y_name, htrain, hvalid, SEED)\n", + "\n", + "# end local timer\n", + "glm_toc = time.time() - glm_tic\n", + "print('Elastic net GLM training completed in %.2f s.' % (glm_toc))" + ] + }, + { + "cell_type": "markdown", + "id": "21e37f0a", + "metadata": {}, + "source": [ + "#### Basic AUC assessment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a08a632", + "metadata": {}, + "outputs": [], + "source": [ + "print('Validation AUC: %.4f.' % best_glm.auc(valid=True))" + ] + }, + { + "cell_type": "markdown", + "id": "3f69720b", + "metadata": {}, + "source": [ + "#### Write submission file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5a3699b", + "metadata": {}, + "outputs": [], + "source": [ + "best_glm_submit = best_glm.predict(h2o.H2OFrame(test)).as_data_frame() \n", + "best_glm_submit.drop(['predict', 'p0'], axis=1, inplace=True)\n", + "best_glm_submit.columns = ['phat']\n", + "best_glm_submit.to_csv('ph_best_glm_' + str(datetime.datetime.now().strftime(\"%Y_%m_%d_%H_%M_%S\") + '.csv'), \n", + " index=False)" + ] + }, + { + "cell_type": "markdown", + "id": "935f9302", + "metadata": {}, + "source": [ + "### Monotonic XGBoost" + ] + }, + { + "cell_type": "markdown", + "id": "fe03d082", + "metadata": {}, + "source": [ + "#### Define utility function for random grid search" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02f6deef", + "metadata": {}, + "outputs": [], + "source": [ + "def xgb_grid(dtrain, dvalid, mono_constraints=None, gs_params=None, n_models=None,\n", + " ntree=None, early_stopping_rounds=None, verbose=False, seed=None):\n", + " \n", + " \"\"\" Performs a random grid search over n_models and gs_params.\n", + "\n", + " :param dtrain: Training data in LightSVM format.\n", + " :param dvalid: Validation data in LightSVM format.\n", + " :param mono_constraints: User-supplied monotonicity constraints.\n", + " :param gs_params: Dictionary of lists of potential XGBoost parameters over which to search.\n", + " :param n_models: Number of random models to evaluate.\n", + " :param ntree: Number of trees in XGBoost model.\n", + " :param early_stopping_rounds: XGBoost early stopping rounds.\n", + " :param verbose: Whether to display training iterations, default False.\n", + " :param seed: Random seed for better interpretability.\n", + " :return: Best candidate model from random grid search.\n", + "\n", + " \"\"\"\n", + "\n", + " # cartesian product of _cv_params\n", + " keys, values = zip(*gs_params.items())\n", + " experiments = [dict(zip(keys, v)) for v in itertools.product(*values)]\n", + "\n", + " # preserve exact reproducibility for this function\n", + " np.random.seed(SEED) \n", + " \n", + " # select randomly from cartesian product space\n", + " selected_experiments = np.random.choice(len(experiments), n_models)\n", + "\n", + " # set global params for objective, etc.\n", + " params = {'booster': 'gbtree',\n", + " 'eval_metric': 'auc',\n", + " 'nthread': NTHREAD,\n", + " 'objective': 'binary:logistic',\n", + " 'seed': SEED}\n", + "\n", + " # init grid search loop\n", + " best_candidate = None\n", + " best_score = 0\n", + "\n", + " # grid search loop\n", + " for i, exp in enumerate(selected_experiments):\n", + "\n", + " params.update(experiments[exp]) # override global params with current grid run params\n", + "\n", + " print('Grid search run %d/%d:' % (int(i + 1), int(n_models)))\n", + " print('Training with parameters:', params)\n", + "\n", + " # train on current params\n", + " watchlist = [(dtrain, 'train'), (dvalid, 'eval')]\n", + " \n", + " if mono_constraints is not None:\n", + " params['monotone_constraints'] = mono_constraints\n", + " \n", + " candidate = xgb.train(params,\n", + " dtrain,\n", + " ntree,\n", + " early_stopping_rounds=early_stopping_rounds,\n", + " evals=watchlist,\n", + " verbose_eval=verbose) \n", + "\n", + " # determine if current model is better than previous best\n", + " if candidate.best_score > best_score:\n", + " best_candidate = candidate\n", + " best_score = candidate.best_score\n", + " print('Grid search new best score discovered at iteration %d/%d: %.4f.' %\n", + " (int(i + 1), int(n_models), candidate.best_score))\n", + "\n", + " print('---------- ----------')\n", + " \n", + " return best_candidate" + ] + }, + { + "cell_type": "markdown", + "id": "f022e24a", + "metadata": {}, + "source": [ + "#### Fit monotonic XGBoost with random grid search" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac9cb630", + "metadata": {}, + "outputs": [], + "source": [ + "# dictionary of hyperparameter value lists for grid search\n", + "gs_params = {'colsample_bytree': [0.3, 0.5, 0.7, 0.9],\n", + " 'colsample_bylevel': [0.3, 0.5, 0.7, 0.9],\n", + " 'eta': [0.005, 0.05, 0.5],\n", + " 'max_depth': [3, 5, 7],\n", + " 'reg_alpha': [0.0005, 0.005, 0.05],\n", + " 'reg_lambda': [0.0005, 0.005, 0.05],\n", + " 'subsample': [0.3, 0.5, 0.7, 0.9],\n", + " 'min_child_weight': [1, 5, 10], \n", + " 'gamma': [0.0, 0.1, 0.2 , 0.3, 0.4]}\n", + "\n", + "# define monotonicity constraints\n", + "mono_constraints = tuple([int(i) for i in np.sign(train[x_names + [y_name]].corr()[y_name].values[:-1])])\n", + "\n", + "# start local timer\n", + "mxgb_tic = time.time()\n", + "\n", + "# Convert data to SVMLight format\n", + "dtrain = xgb.DMatrix(train[x_names], train[y_name])\n", + "dvalid = xgb.DMatrix(valid[x_names], valid[y_name])\n", + "\n", + "# Monotonic XGBoost grid search\n", + "best_mxgb = xgb_grid(dtrain, dvalid, gs_params=gs_params, n_models=50, ntree=1000, early_stopping_rounds=100, \n", + " mono_constraints=mono_constraints, seed=SEED)\n", + "\n", + "# end local timer\n", + "mxgb_toc = time.time() - mxgb_tic\n", + "print('Monotonic GBM training completed in %.2f s.' % (mxgb_toc))" + ] + }, + { + "cell_type": "markdown", + "id": "a2d6e8e4", + "metadata": {}, + "source": [ + "#### Basic AUC assessment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ce4a042", + "metadata": {}, + "outputs": [], + "source": [ + "print('Validation AUC: %.4f.' % best_mxgb.best_score)" + ] + }, + { + "cell_type": "markdown", + "id": "945ddcd7", + "metadata": {}, + "source": [ + "#### Write submission file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "daf86e7d", + "metadata": {}, + "outputs": [], + "source": [ + "dtest = xgb.DMatrix(test[x_names])\n", + "best_mxgb_submit = pd.DataFrame(best_mxgb.predict(dtest, ntree_limit=best_mxgb.best_ntree_limit), columns=['phat'])\n", + "best_mxgb_submit.to_csv('ph_best_mxgb_' + str(datetime.datetime.now().strftime(\"%Y_%m_%d_%H_%M_%S\") + '.csv'), \n", + " index=False)" + ] + }, + { + "cell_type": "markdown", + "id": "348b7fb0", + "metadata": {}, + "source": [ + "### Explainable Boosting Machine" + ] + }, + { + "cell_type": "markdown", + "id": "223b7489", + "metadata": {}, + "source": [ + "#### Define utility function for random grid search" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb7070a9", + "metadata": {}, + "outputs": [], + "source": [ + "def ebm_grid(train, valid, x_names, y_name, gs_params=None, n_models=None, early_stopping_rounds=None, seed=None):\n", + " \n", + " \"\"\" Performs a random grid search over n_models and gs_params.\n", + "\n", + " :param train: Training data as Pandas DataFrame.\n", + " :param valid: Validation data as Pandas DataFrame.\n", + " :param x_names: Names of input features.\n", + " :param y_name: Name of target feature.\n", + " :param gs_params: Dictionary of lists of potential EBM parameters over which to search. \n", + " :param n_models: Number of random models to evaluate.\n", + " :param early_stopping_rounds: EBM early stopping rounds.\n", + " :param seed: Random seed for better interpretability.\n", + " :return: Best candidate model from random grid search.\n", + "\n", + " \"\"\"\n", + "\n", + " # cartesian product of _cv_params\n", + " keys, values = zip(*gs_params.items())\n", + " experiments = [dict(zip(keys, v)) for v in itertools.product(*values)]\n", + "\n", + " # preserve exact reproducibility for this function\n", + " np.random.seed(SEED) \n", + " \n", + " # select randomly from cartesian product space\n", + " selected_experiments = np.random.choice(len(experiments), n_models)\n", + "\n", + " # set global params for seed, etc.\n", + " params = {'n_jobs': NTHREAD,\n", + " 'early_stopping_rounds': early_stopping_rounds, \n", + " 'random_state': SEED}\n", + "\n", + " # init grid search loop\n", + " best_candidate = None\n", + " best_score = 0\n", + "\n", + " # grid search loop\n", + " for i, exp in enumerate(selected_experiments):\n", + "\n", + " params.update(experiments[exp]) # override global params with current grid run params\n", + "\n", + " print('Grid search run %d/%d:' % (int(i + 1), int(n_models)))\n", + " print('Training with parameters:', params)\n", + " \n", + " # train \n", + " ebm = ExplainableBoostingClassifier(**params)\n", + " candidate = ebm.fit(train[x_names], train[y_name]) \n", + " \n", + " # calculate AUC\n", + " ebm_perf = ROC(ebm.predict_proba).explain_perf(valid[x_names], valid[y_name])\n", + " candidate_best_score = ebm_perf._internal_obj['overall']['auc']\n", + " \n", + " # determine if current model is better than previous best\n", + " if candidate_best_score > best_score:\n", + " best_candidate = candidate\n", + " best_score = candidate_best_score\n", + " print('Grid search new best score discovered at iteration %d/%d: %.4f.' %\n", + " (int(i + 1), int(n_models), candidate_best_score))\n", + "\n", + " print('---------- ----------')\n", + " \n", + " del ebm\n", + " \n", + " return best_candidate" + ] + }, + { + "cell_type": "markdown", + "id": "2aee422c", + "metadata": {}, + "source": [ + "#### Fit EBM with random grid search" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8e7edc7", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# dictionary of hyperparameter value lists for grid search\n", + "gs_params = {'max_bins': [128, 256, 512],\n", + " 'max_interaction_bins': [16, 32, 64],\n", + " 'interactions': [5, 10, 15],\n", + " 'outer_bags': [4, 8, 12], \n", + " 'inner_bags': [0, 4],\n", + " 'learning_rate': [0.001, 0.01, 0.05],\n", + " 'validation_size': [0.1, 0.25, 0.5],\n", + " 'min_samples_leaf': [1, 2, 5, 10],\n", + " 'max_leaves': [1, 3, 5]}\n", + "\n", + "# start local timer\n", + "ebm_tic = time.time()\n", + "\n", + "# EBM grid search\n", + "best_ebm = ebm_grid(train, valid, x_names, y_name, gs_params=gs_params, n_models=10, \n", + " early_stopping_rounds=100, seed=SEED)\n", + "\n", + "# end local timer\n", + "ebm_toc = time.time() - ebm_tic\n", + "print('EBM training completed in %.2f s.' % (ebm_toc))" + ] + }, + { + "cell_type": "markdown", + "id": "0248d5c2", + "metadata": {}, + "source": [ + "#### Basic AUC assessment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd8c96fb", + "metadata": {}, + "outputs": [], + "source": [ + "best_ebm_perf = ROC(best_ebm.predict_proba).explain_perf(valid[x_names], valid[y_name])\n", + "print('Validation AUC: %.4f.' % best_ebm_perf._internal_obj['overall']['auc'])" + ] + }, + { + "cell_type": "markdown", + "id": "9f07ca3f", + "metadata": {}, + "source": [ + "#### Write submission file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee80d09a", + "metadata": {}, + "outputs": [], + "source": [ + "best_ebm_submit = pd.DataFrame(best_ebm.predict_proba(test[x_names])[:, 1], columns=['phat'])\n", + "best_mxgb_submit.to_csv('ph_best_ebm_' + str(datetime.datetime.now().strftime(\"%Y_%m_%d_%H_%M_%S\") + '.csv'), \n", + " index=False)" + ] + }, + { + "cell_type": "markdown", + "id": "35aaaa92", + "metadata": {}, + "source": [ + "#### End timer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e978d190", + "metadata": {}, + "outputs": [], + "source": [ + "toc = time.time() - tic\n", + "print('All tasks completed in %.2f s.' % (toc))" + ] + }, + { + "cell_type": "markdown", + "id": "35f92b13", + "metadata": {}, + "source": [ + "#### Shutdown h2o" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "436bc4fc", + "metadata": {}, + "outputs": [], + "source": [ + "h2o.cluster().shutdown(prompt=False)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/assignments/data/.gitignore b/assignments/data/.gitignore new file mode 100644 index 0000000..afed073 --- /dev/null +++ b/assignments/data/.gitignore @@ -0,0 +1 @@ +*.csv diff --git a/assignments/data/hmda_test_preprocessed.zip b/assignments/data/hmda_test_preprocessed.zip new file mode 100644 index 0000000..33e0f5f Binary files /dev/null and b/assignments/data/hmda_test_preprocessed.zip differ diff --git a/assignments/data/hmda_train_preprocessed.zip b/assignments/data/hmda_train_preprocessed.zip new file mode 100644 index 0000000..33e54b7 Binary files /dev/null and b/assignments/data/hmda_train_preprocessed.zip differ diff --git a/assignments/requirements.txt b/assignments/requirements.txt new file mode 100644 index 0000000..69cf0f8 --- /dev/null +++ b/assignments/requirements.txt @@ -0,0 +1,8 @@ +h2o +jupyter +interpret +numpy +pandas +matplotlib +seaborn +xgboost diff --git a/assignments/tex/assignmet_1.pdf b/assignments/tex/assignmet_1.pdf new file mode 100644 index 0000000..5350c18 Binary files /dev/null and b/assignments/tex/assignmet_1.pdf differ diff --git a/assignments/tex/assignmet_1.tex b/assignments/tex/assignmet_1.tex new file mode 100644 index 0000000..2e62243 --- /dev/null +++ b/assignments/tex/assignmet_1.tex @@ -0,0 +1,41 @@ +% Copyright Patrick Hall 2021 + +\documentclass[fleqn]{article} +\renewcommand\refname{} +\title{Responsible Machine Learning\\\Large{Assignment 1}} +\author{\copyright Patrick Hall 2021} + +\usepackage{graphicx} +\usepackage{fullpage} +\usepackage{pdfpages} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{mathtools} +\usepackage{MnSymbol} +\usepackage{enumerate} +\usepackage{setspace} +\usepackage[colorlinks, breaklinks=true]{hyperref} +\usepackage{float} +\usepackage{caption} +\usepackage{subcaption} +\usepackage{multicol} +\usepackage{color} +\usepackage{listings} +\usepackage{csvsimple} +\usepackage{algorithm} +\usepackage{algorithmic} +\usepackage{verbatim} +\usepackage{mdframed} +\usepackage{changepage} +\usepackage[top=1in, bottom=1in, left=1in, right=1in]{geometry} + +\begin{document} + +\maketitle + +In Assignment 1, you will work with your group to train interpretable machine learning (ML) models. + + + + +\end{document} \ No newline at end of file