import dir_constants as dir_con

dir_con.home_path

import torch
import torch.nn as nn
import torch.optim as optim
from torch.autograd import Variable
import torch.nn.functional as F
from torch.utils.data import Dataset, DataLoader
from model_dump.nn_1_0_0 import net_class

import modeling_utils.data_prep_new as data_prep
from sklearn.externals import joblib
import time
from tqdm import tqdm_notebook
%matplotlib notebook

home = os.path.expanduser("~")

platform = 'lendingclub'


store = pd.HDFStore(
    os.path.join(home,'justin_tinkering/data_science/lendingclub/{0}_store.h5'.format(platform)),
    append=True)

"""
Explanation: If I plan to run the scorer every batch to select loans, I should have a minimum score that a loan must receive to even be considered for investing in, and the remaining loans can be selected from in descending score order
End of explanation
"""


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

train_ids = set(train.index.values)
test_ids = set(test.index.values)
assert len(train_ids.intersection(test_ids)) == 0

"""
Explanation: Make sure no loan in test set was in train set
End of explanation
"""


PATH = 'model_dump/nn_1_0_0/1.0.0_e500'

net = net_class.Net()
net.load_state_dict(torch.load(PATH))

train_X, train_y = data_prep.process_data_test(train)
test_X, test_y = data_prep.process_data_test(test)
train_y = train_y['npv_roi_10'].values
test_y = test_y['npv_roi_10'].values
regr_version = '1.0.0'

train_yhat = net_class.torch_version(train_X, net)
test_yhat = net_class.torch_version(test_X, net)
test['1.0.0_scores'] = test_yhat
train['1.0.0_scores'] = train_yhat
test['npv_roi_5'] = loan_npv_rois[.05]

"""
Explanation: Add scores and npv_roi_5 to test set
End of explanation
"""


test['1.0.0_scores'].hist(bins=100)

test['1.0.0_scores'].describe()

test[test['1.0.0_scores'] > 0]['grade'].value_counts(dropna=False)

train['1.0.0_scores'].hist(bins=100)

"""
Explanation: See what the range of predictions is, to tell if we predict outliers later
End of explanation
"""


good_percentiles = np.arange(71,101,1)
good_percentiles = good_percentiles[::-1]

def find_min_score_models(trials, available_loans, test, percentiles):
    # looks at loans that scored in top 30%, computes avg npv_roi_5 in each of those
    # top percentiles
    results = {}
    results_scores = {}
    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, :]
        loans_to_pick_from.sort_values('1.0.0_scores', ascending=False, inplace = True)
        chunksize = int(len(loans_to_pick_from)/100)
        results_dict = {}
        results_scores_dict = {}
        for k,perc in enumerate(percentiles):
            subset = loans_to_pick_from[k*chunksize:(k+1)*chunksize]
            results_dict[perc] = subset['npv_roi_5'].mean()
            results_scores_dict[perc] = subset['1.0.0_scores'].mean()

        results[trial] = pd.Series(results_dict)
        results_scores[trial] = pd.Series(results_scores_dict)

    return pd.DataFrame.from_dict(results).T, pd.DataFrame.from_dict(results_scores).T

# assume there's 200 loans per batch
trials = 20000
available_loans = 200
results, results_scores = find_min_score_models(trials, available_loans, test, good_percentiles)

summaries = results.describe()
summaries_scores = results_scores.describe()

plt.figure()
plt.plot(summaries.columns.values, summaries.loc['mean',:], 'o', label='mean')
plt.plot(summaries.columns.values, summaries.loc['25%',:], 'ro', label='25%')
# plt.plot(summaries.columns.values, summaries.loc['50%',:], '-.')
plt.plot(summaries.columns.values, summaries.loc['75%',:], 'ko', label='75%')
plt.title('return per percentile over batches')
plt.legend(loc='best')
plt.xlabel('percentile of 1.0.0_score')
plt.ylabel('npv_roi_5')
plt.show()

plt.figure()
plt.plot(summaries_scores.columns.values, summaries_scores.loc['mean',:], 'o', label='mean')
plt.plot(summaries_scores.columns.values, summaries_scores.loc['25%',:], 'ro', label='25%')
# plt.plot(summaries_scores.columns.values, summaries_scores.loc['50%',:], '-.')
plt.plot(summaries_scores.columns.values, summaries_scores.loc['75%',:], 'ko', label='75%')
plt.title('scores per percentile over batches')
plt.legend(loc='best')
plt.xlabel('percentile of 1.0.0_score')
plt.ylabel('npv_roi_5')
plt.show()

summaries

summaries_scores.loc['mean', 75]

# lets take one sided 99% cofidence interval at score is greater than mean -3 std_dev at 90th percentile

cutoff = summaries_scores.loc['mean', 90] - 3*summaries_scores.loc['std', 90]

summaries_scores

cutoff

results

"""
Explanation: find what is a good percentile to cutoff at, and what the distribution for scores is at that percentile
End of explanation
"""


picks = test[test['1.0.0_scores'] >= -0.05]

# grade distribution of picks
picks['grade'].value_counts(dropna=False)/len(picks)

# compared to grade distribution of all test loans
test['grade'].value_counts(dropna=False)/len(test)

cutoff

cd dataprep_and_modeling/

"""
Explanation: Say I wanted the 75pctile of the 80th percentile (-0.36289), what grade distribution of loans are those?
End of explanation
"""


