platform = 'lendingclub'

store = pd.HDFStore(
    dc.home_path+'/justin_tinkering/data_science/lendingclub/{0}_store.h5'.
    format(platform),
    append=True)

loan_info = store['train_filtered_columns']
store.close()
columns = loan_info.columns.values
# checking dtypes to see which columns need one hotting, and which need null or not
to_one_hot = []
to_null_or_not = []
do_nothing = []
for col in columns:
    if loan_info[col].dtypes == np.dtype('O'):
#         print(col, loan_info[col].isnull().value_counts(dropna=False).to_dict())
        to_one_hot.append(col)
    elif len(loan_info[col].isnull().value_counts(dropna=False)) > 1:
#         print(col, loan_info[col].isnull().value_counts(dropna=False).to_dict())
        to_null_or_not.append(col)
    else:
#         print(col, loan_info[col].isnull().value_counts(dropna=False).to_dict())
        do_nothing.append(col)

"""
Explanation: DO NOT FORGET TO DROP ISSUE_D AFTER PREPPING
End of explanation
"""


standardized, eval_cols, mean_series, std_dev_series = data_prep.process_data_train(
    loan_info)

# for col in standardized.columns:
#     if len(standardized[standardized[col].isnull()]) > 0:
#         print(col)

"""
Explanation: Until I figure out a good imputation method (e.g. bayes PCA), just drop columns with null still
End of explanation
"""


regr = RandomForestRegressor()

def report(results, n_top=3):
    for i in range(1, n_top + 1):
        candidates = np.flatnonzero(results['rank_test_score'] == i)
        for candidate in candidates:
            print("Model with rank: {0}".format(i))
            print("Mean validation score: {0:.3f} (std: {1:.3f})".format(
                  results['mean_test_score'][candidate],
                  results['std_test_score'][candidate]))
            print("Parameters: {0}".format(results['params'][candidate]))
            print("")

fit_params_dict = {'n_estimators': np.arange(1,201),
                   'criterion': ['mse'],#, 'mae'
                   'max_features': [3,10, 50, 70, 100, 150, 200],
                   'min_samples_split': [20, 200, 2000],
                   'min_samples_leaf': [10, 100, 1000],
                   'bootstrap': [True],
                   'oob_score': [True],
                   'n_jobs': [-1],
                   'verbose': [10]}

n_iter = 20
random_search = RandomizedSearchCV(
    regr, param_distributions=fit_params_dict, n_iter=n_iter)

start = time.time()
random_search.fit(standardized, eval_cols)
print("RandomizedSearchCV took %.2f seconds for %d candidates"
      " parameter settings." % ((time.time() - start), n_iter))

report(random_search.cv_results_)
# Model with rank: 1
# Mean validation score: 0.078 (std: 0.001)
# Parameters: {'verbose': 10, 'oob_score': True, 'n_jobs': -1, 'n_estimators': 175, 'min_samples_split': 200, 'min_samples_leaf': 10, 'max_features': 70, 'criterion': 'mse', 'bootstrap': True}

# Model with rank: 2
# Mean validation score: 0.078 (std: 0.001)
# Parameters: {'verbose': 10, 'oob_score': True, 'n_jobs': -1, 'n_estimators': 185, 'min_samples_split': 200, 'min_samples_leaf': 10, 'max_features': 100, 'criterion': 'mse', 'bootstrap': True}

# Model with rank: 3
# Mean validation score: 0.077 (std: 0.002)
# Parameters: {'verbose': 10, 'oob_score': True, 'n_jobs': -1, 'n_estimators': 139, 'min_samples_split': 20, 'min_samples_leaf': 10, 'max_features': 100, 'criterion': 'mse', 'bootstrap': True}

"""
Explanation: random search RF hyperparams, and build with best one
End of explanation
"""


regr = RandomForestRegressor(
    n_estimators=175,
    random_state=0,
    max_features=70,
    min_samples_split=200,
    min_samples_leaf=10,
    n_jobs=-1,
    oob_score=True,
    bootstrap=True,
    criterion='mse',
)
regr.fit(standardized, eval_cols)

regr.score(standardized, eval_cols)

# dump the model
joblib.dump(regr, 'model_dump/model_0.2.1.pkl')
joblib.dump((mean_series, std_dev_series), 'model_dump/mean_stddev.pkl')

now = time.strftime("%Y_%m_%d_%Hh_%Mm_%Ss")
# info to stick in detailed dataframe describing each model
model_info = {'model_version': '0.2.1',
              'target': 'npv_roi_10',
              'weights': 'None',
              'algo_model': 'RF_regr',
              'hyperparams': "bootstrap=True, criterion='mse', max_depth=None, max_features=70, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=10, min_samples_split=200, min_weight_fraction_leaf=0.0, n_estimators=175, n_jobs=-1, oob_score=True, random_state=0, verbose=0, warm_start=False",
              'cost_func': 'sklearn default, which I think is mse',
              'useful_notes': 'R2 score of .3830649 (regr.score())',
              'date': now}

model_info_df = pd.DataFrame(model_info, index = ['0.2.1'])

store.open()
model_info = store['model_info']
model_info.ix['0.2.1',:] = model_info_df.values
model_info.sort_index(inplace=True)
store.append(
            'model_info',
            model_info_df,
            data_columns=True,
            index=True,
            append=False,
)
store.close()

"""
Explanation: take best hyperparams from report
End of explanation
"""


store.open()
test = store['test_filtered_columns']
train = store['train_filtered_columns']
loan_npv_rois = store['loan_npv_rois']
default_series = test['target_strict']
results = store['results']
store.close()

train_X, train_y = data_prep.process_data_test(train)
train_y = train_y['npv_roi_10'].values
test_X, test_y = data_prep.process_data_test(test)
test_y = test_y['npv_roi_10'].values
regr = joblib.load('model_dump/model_0.2.1.pkl')
regr_version = '0.2.1'
test_yhat = regr.predict(test_X)
train_yhat = regr.predict(train_X)

test_mse = np.sum((test_yhat - test_y)**2)/len(test_y)
train_mse = np.sum((train_yhat - train_y)**2)/len(train_y)

test_mse

train_mse

def eval_models(trials, port_size, available_loans, regr, regr_version, test, loan_npv_rois,
                default_series):
    results = {}
    pct_default = {}
    test_copy = test.copy()
    for trial in tqdm_notebook(np.arange(trials)):
        loan_ids = np.random.choice(
            test_copy.index.values, available_loans, replace=False)
        loans_to_pick_from = test_copy.loc[loan_ids, :]
        scores = regr.predict(loans_to_pick_from)
        scores_series = pd.Series(dict(zip(loan_ids, scores)))
        scores_series.sort_values(ascending=False, inplace=True)
        picks = scores_series[:900].index.values
        results[trial] = loan_npv_rois.loc[picks, :].mean().to_dict()
        pct_default[trial] = (default_series.loc[picks].sum()) / port_size
    pct_default_series = pd.Series(pct_default)
    results_df = pd.DataFrame(results).T
    results_df['pct_def'] = pct_default_series
    return results_df

# as per done with baseline models, say 3000 loans available
# , pick 900 of them
trials = 20000
port_size = 900
available_loans = 3000
model_results = eval_models(trials, port_size, available_loans, regr, regr_version, test_X, loan_npv_rois, default_series)

multi_index = []
for col in model_results.columns.values:
    multi_index.append((str(col),regr_version))
append_results = model_results.copy()
append_results.columns = pd.MultiIndex.from_tuples(multi_index, names = ['discount_rate', 'model'])    

multi_index_results = []
for col in results.columns.values:
    multi_index_results.append((str(col[0]), col[1]))
results.columns = pd.MultiIndex.from_tuples(multi_index_results, names = ['discount_rate', 'model'])    

try:
    results = results.join(append_results)
except ValueError:
    results.loc[:, (slice(None), slice('0.2.1','0.2.1'))] = append_results
results.sort_index(axis=1, inplace = True)

full_results = results

full_results.describe()

store.open()
store['results'] = full_results
store.close()

"""
Explanation: Examine performance on test set
End of explanation
"""


