{"cells":[{"metadata":{"_uuid":"c0baa49d-976a-432d-bf79-3844ecfb30f2","_cell_guid":"a09e911d-559c-40cf-a72e-ecade035655d","trusted":true},"cell_type":"markdown","source":"References:\n* https://www.kaggle.com/neithermannormachine/osic-multiple-quantile-regression-starter-ulrich/","execution_count":null},{"metadata":{"_uuid":"68d8d401-1d10-4cc5-a2c3-5737bc072d5a","_cell_guid":"9f3f4228-a593-4009-8d0c-b20a54c86896","trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3ec17609-3665-4ecf-8201-b77566280bf1","_cell_guid":"482739f0-6630-4fea-ac45-e32616ee5c40","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\n'''\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n'''\n\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b6e583de-d6d9-4b70-8214-aa2ab3f8c1f0","_cell_guid":"681b2321-7a51-4bc0-95b2-f63e9db42f04","trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"243da645-1a4e-4025-a059-7001eb33e934","_cell_guid":"e6c3f515-7f28-406f-856b-d7b730adcedc","trusted":true},"cell_type":"markdown","source":"# Load Data","execution_count":null},{"metadata":{"_uuid":"95f515c0-6369-4379-8403-40fc5be5ea01","_cell_guid":"5f331878-0aaa-4418-971d-cdc60ff5b9aa","trusted":true},"cell_type":"code","source":"train_df = pd.read_csv('../input/osic-pulmonary-fibrosis-progression/train.csv')\ntrain_df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"21b2cb0e-a62a-4821-9ad6-1381eee26dd5","_cell_guid":"1c7a8516-078a-4d35-abf1-9fb95a7a0df1","trusted":true},"cell_type":"markdown","source":"# Preprocess Data\n\ntry converting to sklearn pipeline later","execution_count":null},{"metadata":{"_uuid":"92324c35-fed5-4fec-bcce-5bb0eb06eb68","_cell_guid":"74036a9d-ac0c-4c7f-be13-790855817741","trusted":true},"cell_type":"markdown","source":"we already have a test set -- don't need train_test_split, only cross validation\n\nDo transformations on training set alone, THEN transform test -- prevents data leakage for stuff like minmax scaling or normalization","execution_count":null},{"metadata":{"_uuid":"44dd932b-207d-47bf-bf47-a53d65193818","_cell_guid":"0d1e7d0a-4fc4-4369-a824-3321d2737b1d","trusted":true},"cell_type":"markdown","source":"## Engineer Features\n\nReferences:\n\nhttps://www.kaggle.com/mattbast/feature-engineering-with-a-linear-model\n\n\nThis source here describes how to calculate height based on FirstFVC, Age, and Sex; WARNING: assumes European patients -- this assumption may not be valid\n\n* https://www.kaggle.com/c/osic-pulmonary-fibrosis-progression/discussion/166123\n    * https://erj.ersjournals.com/content/erj/11/6/1354.full.pdf - contains actual table for equations\n\nhttps://arxiv.org/pdf/1811.02651.pdf","execution_count":null},{"metadata":{"_uuid":"ce07a05e-15f6-41cf-8591-aa92385198f9","_cell_guid":"1f8fbfd6-228b-4588-ad6c-a9cfa892a9da","trusted":true},"cell_type":"code","source":"def feature_engineer(data):\n    '''\n    method to feature engineer any df, train or test\n    '''\n    \n    df = data.copy()\n    \n    #add columns that indicate when first measurement was taken for each patient\n    df['FirstWeek'] = df.groupby('Patient')['Weeks'].transform('min')\n    \n    first_fvc = (df.loc[df['Weeks'] == df['FirstWeek']][['Patient','FVC']]\n                        .groupby('Patient')\n                        .first() #some patients have multiple measurements in same week - get the first\n                        .reset_index()\n                         .rename(columns = {'FVC': 'FirstFVC'}) )\n    \n    df = df.merge(first_fvc, on = 'Patient') #add FirstFVC column\n    \n    #add column that indicates num weeks since first measurement\n    \n    df['WeeksPassed'] = df['Weeks'] - df['FirstWeek']\n    \n    #use PolyFeatures here instead, this isn't scalable\n    #df['WeeksPassed_sqrt'] = np.maximum(0,df['WeeksPassed']) ** (1/2)\n    df['WeeksPassed_sqrt'] = np.power(df['WeeksPassed'].abs(), 1/2) * np.sign(df['WeeksPassed'])\n    df['WeeksPassed_square'] = df['WeeksPassed'] ** (2)\n    \n    \n    '''\n    \n    \n    '''\n    \n    \n    \n    def calculate_height(row): #height can be predictor of FVC -- this estimates the height of patients\n        if row['Sex'] == 'Male':\n            return row['FirstFVC'] / (27.63 - 0.112 * row['Age'])\n        else:\n            return row['FirstFVC'] / (21.78 - 0.101 * row['Age'])\n\n    df['Height'] = df.apply(calculate_height, axis=1)\n    \n    df['HeightWeeks'] = df['WeeksPassed'] * df['Height']\n    df['AgeWeeks'] = df['WeeksPassed'] * df['Age']\n    \n    return df\n\n\n#feature_engineer(train_df) #just looking","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1a4fb107-1b67-43fc-b8b0-3af5fc2f4622","_cell_guid":"b971e6d9-3c0a-4d85-b594-75278b0deb83","trusted":true},"cell_type":"code","source":"#try to make sklearn estimator for feature engineering\nfrom sklearn.base import BaseEstimator, TransformerMixin\n\nclass MyFeatureEngineerer(BaseEstimator, TransformerMixin):\n    '''\n    this is class so that feature engineering can be done on separate sets\n    \n    \n    To use, call fit on a DataFrame to compute and record values that need to be saved before modification (ie before adding new weeks)\n    Examples of values needed to be saved are: FirstFVC, FirstWeek, ...\n    Then transform after modifications are done\n    \n    can just fit_transform if not modifying DataFrame further\n    \n    '''\n    def __init__(self):\n        #_ convention indicates that this variable is result of fitting\n        pass\n    \n    def fit(self, X, y = None):\n        try:\n            self.df_ = feature_engineer(X)\n        except AttributeError: #fit should only be called on pandas DataFrame\n            raise ValueError('Can only use this estimator on Pandas DataFrame')\n        return self #return fitted self for further method calls\n    \n    def transform(self, X): #honestly fix this up, it's not scalable at all\n        '''\n        X has been modified with additional weeks\n        '''\n        \n        #check if X has been modified (assume everything same except number of weeks)\n        if len(X) != len(self.df_):\n            #recompute WeeksPassed if it has been\n            drop = X.columns.values \n            df = self.df_.drop(drop, axis = 1).join(self.df_['Patient']) #drop columns already in X, except for patient\n            df = X.merge(df, on = 'Patient')\n            df['WeeksPassed'] = df['Weeks'] - df['FirstWeek']\n            df['WeeksPassed_sqrt'] = np.power(df['WeeksPassed'].abs(), 1/2) * np.sign(df['WeeksPassed'])\n            df['WeeksPassed_square'] = df['WeeksPassed'] ** (2)\n            df['HeightWeeks'] = df['WeeksPassed'] * df['Height']\n            df['AgeWeeks'] = df['WeeksPassed'] * df['Age']\n\n        else:\n            df = self.df_ #if not, just return self.df_\n        return df\n    \n'''\nfrom sklearn.utils.estimator_checks import check_estimator\ncheck_estimator(MyFeatureEngineerer())\n'''","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d4fd701f-9faf-4f80-915c-42781d7a2ded","_cell_guid":"f778a6f5-214b-43fe-8dc5-8ae7018e8c21","trusted":true},"cell_type":"markdown","source":"## Encode Features","execution_count":null},{"metadata":{"_uuid":"17468d16-eab8-4a09-9891-bfc24e092c7e","_cell_guid":"8d2a24ac-2b60-4895-ab6f-82c9acf88750","trusted":true},"cell_type":"code","source":"from sklearn.base import BaseEstimator, TransformerMixin\n\nclass ParamMinMaxScaler(BaseEstimator, TransformerMixin):\n    '''\n    custom minmax scaler where min and max are not based on data,\n    but are passed in as parameters\n    \n    pretty good for percentages\n    '''\n    def __init__(self, min_val = 0, max_val = 100):\n        self.min_val = min_val\n        self.max_val = max_val\n    \n    \n    def fit(self, X, y=None): #don't need to fit at all\n        return self\n\n    def transform(self, X): #do minmax scaling\n        data = (X - self.min_val) / (self.max_val - self.min_val)\n        return data\n'''\nfrom sklearn.utils.estimator_checks import check_estimator\ncheck_estimator(ParamMinMaxScaler())'''","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0ca9c887-c50a-418f-a027-4fed1bd1b855","_cell_guid":"5814b855-a409-44c3-92da-232c7f0c4425","trusted":true},"cell_type":"code","source":"def transformed_col_names(col_trans):\n    '''\n    helper function to get column names of dataframe back after column transforming\n    because col_trans.get_feature_names() doesn't work very well\n    Use this after fitting col_trans\n    '''\n    import re\n    \n    new_colnames = []\n    for _, t, col in col_trans.transformers_: #loop thru all transformers\n        try: #try to get new column names\n            temp = t.get_feature_names()\n            temp2 = []\n            #gotta do some legwork to replace the ugly 'x0', 'x1' prefixes returned by default\n            for name in temp: #loop thru feature names returned by t\n                match = re.search('x(\\d+)+_', name) #look for this ugly bit\n                i = int(match.group(1)) #get the feature number\n                new_name = col[i] + '_' + name[match.end():] #replace x0 or whatever number with meaningful feature name\n                temp2.append(new_name)\n            col = temp2\n        except AttributeError: #if transformer t does not provide get_feature_names()\n            pass #no big deal, just ignore it; we'll extend with original column names\n        new_colnames.extend(col) #then append column names to list\n        \n    return new_colnames","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"69ef670b-b3c2-426c-958b-1d598b28ff37","_cell_guid":"9c096748-ee48-4188-a70e-a6f3cd3c02cc","trusted":true},"cell_type":"code","source":"from sklearn_pandas import DataFrameMapper #yes it works!\nhelp(DataFrameMapper) #todo: work this into the pipeline, refactor code so it's less crud\n#use this in some way for feature engineering instead of my crap custom class\n#todo: determine differences between this and ColumnTransformer","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"143e926f-0e9f-4eb2-9e1d-3e80f891b3fb","_cell_guid":"34f3b73c-551b-43a5-a2ea-09945ea3fd67","trusted":true},"cell_type":"code","source":"#where all the preprocessing goes on\n\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.preprocessing import OneHotEncoder, MinMaxScaler\n\n#list features to transform\n\n#this isn't scalable honestly\npassthru_features = ['Patient', 'FVC']\nonehot_features = ['Sex', 'SmokingStatus']\nhundred_features = ['Percent', 'Age']\nminmax_features = ['FirstFVC', 'FirstWeek', 'WeeksPassed',\n                   'WeeksPassed_sqrt', 'WeeksPassed_square', 'Height', 'HeightWeeks',\n                  'AgeWeeks']\n\n#question -- should i do a custom scaling of age, percent columns?\n#instead of minmax scaling, just divide by 100? will ultimately give similar scale (0 to 1)\n#also, maybe do a custom scaling of Weeks as well -- set min to -12, max to 133\n#right now it's doing minmax based on whatever's in train\n\n#define the transformers\noh_enc = OneHotEncoder(sparse = False, drop = 'if_binary')\nhundred_minmax = ParamMinMaxScaler()\nweek_minmax = ParamMinMaxScaler(min_val = -12, max_val = 133)\nminmax = MinMaxScaler()\n\n#ordered like this to kinda preserve order\ncol_trans = ColumnTransformer([\n                ('original', 'passthrough', passthru_features),\n                ('week_minmax', week_minmax, ['Weeks']),\n                ('hundred_minmax', minmax, hundred_features),\n                ('minmax', minmax, minmax_features),\n                ('onehot', oh_enc, onehot_features)\n            ], remainder = 'passthrough', sparse_threshold=0)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"16245540-fc3b-403b-b99b-a1190070b4b9","_cell_guid":"870ff226-4f07-4f7b-994f-e2c03ac3a48c","trusted":true},"cell_type":"code","source":"train_df = MyFeatureEngineerer().fit_transform(train_df)\n\nnew_df = col_trans.fit_transform(train_df)\n\n#get the names of the columns back and convert to dataframe\ntrain_df = pd.DataFrame(new_df, columns = transformed_col_names(col_trans))\ntrain_df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8acaa8bf-beff-482c-85e5-2c7659394ca0","_cell_guid":"79cbce80-bfd8-4755-8802-bb5c9e1e5bc3","trusted":true},"cell_type":"markdown","source":"# Build Model","execution_count":null},{"metadata":{"_uuid":"ca275416-c92e-4e0a-9cd2-f6d20e4950b4","_cell_guid":"1699e0e7-82af-4369-ac36-e67299274edf","trusted":true},"cell_type":"markdown","source":"## Define Metrics\n\nThese are the metrics / losses we will use","execution_count":null},{"metadata":{"_uuid":"7186433a-b8a6-4ba1-b8af-94b8caf6b9a3","_cell_guid":"e960e5ef-5f84-47e3-9d57-006d2a20e63f","trusted":true},"cell_type":"code","source":"from osic_loss_metrics import *\n#this is from my utility script OSIC Loss Metrics","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c19a6970-3ae6-413e-8d17-aacb87396940","_cell_guid":"46a9cabe-8dc6-42af-a832-7d76a3aafcab","trusted":true},"cell_type":"markdown","source":"## Define Model and Fit\n\nhttps://machinelearningmastery.com/multi-output-regression-models-with-python/\n\n\nto do:\n* figure out framework for confidence intervals, current solutions seem pretty hacky\n* try models and ensembles\n* learn how to wrap keras in sklearn estimator","execution_count":null},{"metadata":{"_uuid":"e9dd2253-7cf3-4822-8ad6-a96f357e41c2","_cell_guid":"3b1cfd39-8219-4f28-b835-ab96b4268def","trusted":true},"cell_type":"markdown","source":"Looks like the LB score is peaking without a method to calculate confidence for each prediction -- work on that, it's big bottleneck","execution_count":null},{"metadata":{"_uuid":"0acc96ed-e833-4b33-af39-4453217bf7bd","_cell_guid":"91c0093c-518f-4b8d-8f36-ae468ad4d363","trusted":true},"cell_type":"code","source":"import tensorflow as tf\nfrom sklearn.linear_model import LinearRegression, LassoCV, RidgeCV, ElasticNetCV\nfrom sklearn.neighbors import KNeighborsRegressor\nfrom sklearn.ensemble import VotingRegressor, StackingRegressor\n\ndef make_model(): #let's start with a simple tabular model; integrate images later\n    '''\n    creates and returns a model, but does not fit it\n    '''\n    \n    \n    #define the loss function to use\n    loss = mloss(0.8) #loss has signature f(y_true, y_pred)\n    \n    #model = GammaRegressor(alpha = 0)\n    \n    \n    model_est = ElasticNetCV(l1_ratio = [.1, .5, .7, .9, .95, .99, 1], alphas = [0.1,0.3,1,3,10], cv = 6) #problem -- this is using KFold, as opposed to GroupKFold\n    model_knn = KNeighborsRegressor(n_neighbors = 13)\n    \n    model = StackingRegressor(estimators = [('elasticnet', model_est),\n                                            ('knn', model_knn)])\n    #model = TweedieRegressor(power = 0, alpha = 1, link = 'log', max_iter = 500)\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8c70b09f-372c-434c-803d-0b6db9370159","_cell_guid":"0da11efc-6935-4f40-a4cb-28e627748eaa","trusted":true},"cell_type":"code","source":"train_df #just look over train_df again","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f097a3b-eac1-4d93-ba6d-b739bb3e39c3","_cell_guid":"d9779487-93c8-49d2-be77-6bcf97b2bbe7","trusted":true},"cell_type":"code","source":"#instantiate and fit model\n\n\nmodel = make_model()\n\ndrop_features = ['Patient', 'FVC', 'Weeks', 'Percent'] #features to drop from X training data\n#Why drop?\n#Patient -- id doesn't (or shouldn't, at least) give any info\n#FVC -- it's the target value, duh\n#Weeks -- redundant, we have WeeksPassed, which should be better anyway\n#Percent -- seems like for each patient, Percent is perfectly correlated to FVC over each week\n#can't generate Percent on the fly for each week, since that means we could perfectly generate FVC, so we drop Perccent\n\nX_train = train_df.drop(drop_features, axis = 1)\ny_train = train_df['FVC']\n\nmodel.fit(X_train, y_train)\nX_train","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"352fb6de-7892-4d01-a5a7-ae327fedaa78","_cell_guid":"72ab238e-3a84-4df1-8852-c75795bf5d72","trusted":true},"cell_type":"markdown","source":"## Tune Hyperparameters\n\nGotta find the best hyperparameters, try using sklearn","execution_count":null},{"metadata":{"_uuid":"067f658f-e8e6-48ab-b228-0eae083c32e4","_cell_guid":"bcd011a3-057e-44e6-8056-ee7d526bdaa1","trusted":true},"cell_type":"code","source":"#randomized might be better due to time constraints\nfrom sklearn.model_selection import RandomizedSearchCV\n\n#LinearRegression is model\n'''\nparams = {\n    \n            }\nhyper_search = RandomizedSearchCV(model, param_distributions=params, n_iter = 20)'''","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4df9be2e-92eb-45be-b1bc-330f67038def","_cell_guid":"3ff7e9ea-2dfa-4c40-88fb-6d6f7c5489d8","trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4193672a-ca0f-4845-a23a-633edf2ad5d4","_cell_guid":"1ec4bb69-6e60-4405-9098-3b3558b5f2fb","trusted":true},"cell_type":"markdown","source":"## Cross-Validate","execution_count":null},{"metadata":{"_uuid":"f95ab18a-4885-49bf-be35-c3c699bac011","_cell_guid":"9d9200ab-3325-4def-836f-15576e5334be","trusted":true},"cell_type":"markdown","source":"BIG NOTE: I should refrain from doing normalization on entire train_df (ie before splitting into validation sets), since that's bad for cross validation, cause I get my X_train from the preprocessed train_df -- may cause data leakage (this affects MinMaxScaling stuff especially); instead, try to get it working with pipeline","execution_count":null},{"metadata":{"_uuid":"ae525518-3d46-473c-a3e0-11083a5b9896","_cell_guid":"0427ccbd-12df-4a03-b596-e44d58301135","trusted":true},"cell_type":"markdown","source":"### disable this cell when actually submitting, very long\n\n\nfrom sklearn.model_selection import cross_val_score, GroupKFold\nfrom sklearn.metrics import make_scorer, mean_absolute_error\n\n#Define cross validation method\nNFOLDS = 6\ngkf = GroupKFold(n_splits = NFOLDS) #use groupkfold to prevent same patient in training and test set\ngroups = train_df['Patient'].values\n\n#loss = mloss()\nscorer = make_scorer(mean_absolute_error)\n\n#pred = model.predict(X_train)\n#print(scorer(model, X_train, y_train))\n\n#print(conf)\n\n\ndef temp_loss(y_true, y_pred): #just a temp loss function to wrap around laplace log score\n    #since right now my model doesn't output quantiles yet\n    CONFIDENCE = c #c is our loop variable\n    y_true = np.expand_dims(y_true, -1)\n    y_mod = np.zeros((y_pred.shape[0],3))\n    y_mod[:, 1] = y_pred\n    y_mod[:, 0] = y_pred - CONFIDENCE / 2\n    y_mod[:, 2] = y_pred + CONFIDENCE / 2\n    return laplace_log_score()(y_true.astype('float32'),y_mod.astype('float32'))\n\n\n\nconf = np.arange(200, 301, 5) #various confidence values\nconf_df = pd.DataFrame(index = conf, columns = ['mean score', 'std score'])\nconf_df.index.name = 'Confidence'\nfor c in conf: #optimize over various confidence values\n    print(c)\n    scorer = make_scorer(temp_loss)\n    #print('With confidence value', c)\n    cv_scores = cross_val_score(model, X_train, y_train, cv = gkf, groups = groups, scoring = scorer)\n    #print(cv_scores)\n    \n    avg_score = np.mean(cv_scores)\n    std_score = np.std(cv_scores)\n    \n    conf_df.loc[c, :] = [avg_score, std_score]\n    \n    #print(f'{avg_score:.4f}, {std_score:.4f}')\n    #print()\n    '''\n    confidence = np.mean(cv_scores) #temp confidence value for submission\n    print(confidence)\n    '''\n\n#since we need to feature engineer train set separately from val set\n\n#determine worst case scenario\n#worst case is 2.3 standard deviations above -- should be 99% chance score is better (assuming normal distribution)\nnum_std = 2.3 #this number seems to produce worst cases that line up pretty well with leaderboard, at least for simple LinearRegression\nconf_df['worst case'] = (conf_df['mean score'] + num_std * conf_df['std score'] )\nconf_df = conf_df.convert_dtypes() #ensure numeric\n\nconf_df","execution_count":null},{"metadata":{"_uuid":"93d3dfe2-247e-4daf-ab53-25649396ac49","_cell_guid":"432133a5-b37c-46b5-a272-be43827d10b7","trusted":true},"cell_type":"markdown","source":"### disable this cell when actually submitting\n\n#this is from my utility script osic_confidence_crossval\nfrom osic_confidence_crossval import confidence_cross_val_score\n\n\n#keep the best confidence values\nconf_df = confidence_cross_val_score(model = model, X_train = X_train, y_train = y_train, groups = train_df['Patient'].values)\nbest = conf_df.nsmallest(10, columns = ['worst case'], keep = 'all')\nbest = best.applymap('{:,.4f}'.format) #format for output to 4 decimal places\n\nbest#.loc[[200,270,300,350]]","execution_count":null},{"metadata":{"_uuid":"32e50111-f45b-4e2d-8e50-f27da9882f15","_cell_guid":"f869c6f0-5082-41a2-b407-192e8f3e0912","trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n\n\nplt.bar(X_train.columns.values, model.estimators_[0].coef_)\nplt.xticks(rotation = 70)\n\nprint(model.estimators_[0].alpha_, model.estimators_[0].l1_ratio_)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d979fe88-0315-4012-a301-6abf62d568d5","_cell_guid":"b23af677-fbef-42ca-8020-77dd1ee007b9","trusted":true},"cell_type":"code","source":"pred_train = model.predict(X_train)\npred_train","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"96847452-a439-4669-8ba4-212aba45588b","_cell_guid":"11ae63ae-8b53-4381-a4ed-3a88875b0386","trusted":true},"cell_type":"code","source":"import random\nfrom sklearn.base import clone\n#visualize\n\n#see how validation set is predicted\nmodel_copy = clone(model)\ni = random.choice(range(NFOLDS)) #choose a random fold\ntrain_index, test_index = list(gkf.split(X_train, y_train, groups))[i]\n\n#for train_index, test_index in gkf.split(X_train, y_train, groups):\np = random.choice(train_df.loc[test_index, 'Patient'].unique()) #get random patient from validation set\nprint(p)\n#print(p, mask.mean())\n\nmask = (train_df['Patient'] == p)\n\n#print(train_df.loc[mask, ['Weeks', 'FVC']])\n\n\nmodel_copy.fit(X_train.iloc[train_index, :], y_train.iloc[train_index]) #do training\npred_val = model_copy.predict(X_train[mask]) #do predicting\n\n#print(pred)\n\nser = pd.Series(pred_val, name = 'FVC_pred', index = train_df[mask].index)\n#print(ser)\n\ntemp_df = train_df.loc[mask, ['Weeks', 'FVC']].join(ser)\ntemp_df.plot(x = 'Weeks', y = ['FVC', 'FVC_pred'])\nplt.title(p)\n#print(temp_df)\n\n\n\n\n#see ground truth","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b99a49c3-96a9-45f3-9d78-41cd827922c3","_cell_guid":"f3623ada-0531-4158-8ce8-dd01167af02d","trusted":true},"cell_type":"markdown","source":"# Structure Pipeline","execution_count":null},{"metadata":{"_uuid":"3c414b79-8114-4762-840c-97e89739ae60","_cell_guid":"304208cb-a0fa-407b-b44e-c4e649c2edff","trusted":true},"cell_type":"code","source":"from sklearn.pipeline import Pipeline\n\n\n#Maybe feature engineer outside of pipeline as compromise -- hmm, but that doesn't work for cross-validation\n'''\npipeline = Pipeline([\n                ('fe', MyFeatureEngineerer()),\n                ('ct', col_trans),\n                ('model', make_model())\n            ])\n\n\npipeline.fit(X_train, y_train)'''","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c6ebc7f3-184d-475b-9a99-c041ba6ccae6","_cell_guid":"de330dca-e687-4d9b-93d8-96b2e2dff5df","trusted":true},"cell_type":"markdown","source":"# Make Predictions\n\nthis section currently sucks in terms of factoring -- rework it so it's easier to try new stuff and is more general","execution_count":null},{"metadata":{"_uuid":"4bbddb89-6d26-4833-a3bd-b7c97aa37f32","_cell_guid":"bc9817f2-f78f-45e9-827e-6b00baf65d80","trusted":true},"cell_type":"code","source":"input_df = pd.read_csv('../input/osic-pulmonary-fibrosis-progression/test.csv')\ninput_df #preprocess this to turn into test_df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"bc1967ee-faa7-4566-849e-efc56a65f12a","_cell_guid":"86648d45-b689-4d89-a00e-786c0dcc380d","trusted":true},"cell_type":"code","source":"#ideally, can use pipeline we used for preprocessing training data\n\n\n#problem with infrastructure: can't feature_engineer before adding weeks -12 to +133, because doesn't update WeeksPassed\n#but can't feature engineer AFTER adding other weeks, because FirstWeek & FirstFVC would be computed wrong\n\n\n#this code is honestly scuffed, gotta refactor so it's not crap\neng = MyFeatureEngineerer()\neng.fit(input_df)\n#then add weeks -12 to +133 to each patient in test set\ninput_df2 = input_df.drop(['FVC', 'Weeks'], axis = 1) #this info is stored in FirstFVC and FirstWeek of eng\nprint(input_df)\nall_weeks = pd.DataFrame(np.array(range(-12, 134)), columns = ['Weeks'])\npatient_weeks = pd.DataFrame()\n\n\n#could probably vectorize this\nfor p in input_df['Patient'].unique(): #this loop creates rows for every week/patient combo\n    tdf = all_weeks.copy()\n    tdf['Patient'] = p\n    patient_weeks = patient_weeks.append(tdf, ignore_index = True)\n\ntemp_df = patient_weeks.merge(input_df2, on = 'Patient')\n\nprint(temp_df)\nprint(eng.df_)\nnew_df = eng.transform(temp_df)\nnew_df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2bb0f868-1cee-44ed-ad29-cd8fdd52c5f4","_cell_guid":"9099d55d-6900-4adc-afab-bc7ea8729833","trusted":true},"cell_type":"code","source":"new_df['FVC'] = 0 #need this for column transforming, can drop afterwards\nprint(new_df.columns)\nnew_df = col_trans.transform(new_df) #col_trans already fit on train, don't worry\ntest_df = pd.DataFrame(new_df, columns = transformed_col_names(col_trans))\ntest_df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"db850988-3904-48df-88bd-d526afe57813","_cell_guid":"b7e36b78-08aa-41ff-9067-4d2b5c64a842","trusted":true},"cell_type":"code","source":"X_test = test_df.drop(drop_features, axis = 1) \nX_test","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2c6cd9da-2134-42d9-b1bf-7b82909ac812","_cell_guid":"91eee459-7f7d-4712-982c-73d3bf21ae03","trusted":true},"cell_type":"code","source":"pred = model.predict(X_test)\n\n\npred","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"111c8cdc-ff7d-47fc-85e4-55d460bdfc60","_cell_guid":"ae49adfd-c01a-4874-8a4d-3082cfa4f8b8","trusted":true},"cell_type":"markdown","source":"# Submit","execution_count":null},{"metadata":{"_uuid":"383d8b17-aabb-4875-8467-07349dd0004a","_cell_guid":"9cec7b69-d7e3-41cf-82fe-57562879a7b4","trusted":true},"cell_type":"code","source":"sub_df = patient_weeks.join(pd.Series(pred, name = 'FVC'))\nsub_df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"846ab417-fa92-4026-94b0-e6b191907ed0","_cell_guid":"56849d0e-5e59-4380-a130-ca3ff1ae2309","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"#visualize results\nplt.figure(figsize = (17,10))\nfor i, (patient, frame) in enumerate(sub_df.groupby('Patient')):\n    ax = plt.subplot(2,3, i+1)\n    frame[['Weeks', 'FVC']].plot(x = 'Weeks', y = 'FVC', title = patient, ax = ax)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"71e7a688-9df3-4b94-8cf4-4557b97588fc","_cell_guid":"63ff49d6-81ae-480b-a761-231321d21eaa","trusted":true},"cell_type":"code","source":"#format the output\n\nsub_df['Patient_Week'] = sub_df['Patient'] + '_' + sub_df['Weeks'].astype(str)\nsub_df['Confidence'] = 260 #choose best confidence (best worst case), as determined by cross-val\n\n\nsub_df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a225684c-1b96-47af-ad00-88cda7645f0b","_cell_guid":"8687c435-902c-45f2-bc4a-99f201b05d9f","trusted":true},"cell_type":"code","source":"sub_df[['Patient_Week', 'FVC', 'Confidence']].to_csv('submission.csv', index = False)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2fbe94ae-ff2b-40e7-a2a7-515232cca708","_cell_guid":"d4d222d4-9fa6-421e-ba80-3b37c84f9586","trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}