From a60adec4b04f366d49c64e5d4a9004729afef4b3 Mon Sep 17 00:00:00 2001 From: Ashay Athalye Date: Thu, 30 Jan 2020 09:40:37 -0500 Subject: [PATCH 1/2] initial commit --- montecarlo/econml_dml_te.py | 180 +++++++++++++++++++++ montecarlo/mc_from_config.py | 15 ++ montecarlo/mcpy/__init__.py | 0 montecarlo/mcpy/metrics.py | 63 ++++++++ montecarlo/mcpy/monte_carlo.py | 169 ++++++++++++++++++++ montecarlo/mcpy/plotting.py | 244 +++++++++++++++++++++++++++++ montecarlo/mcpy/utils.py | 12 ++ montecarlo/sweep_config_dml_te.py | 90 +++++++++++ montecarlo/sweep_mc_from_config.py | 15 ++ 9 files changed, 788 insertions(+) create mode 100644 montecarlo/econml_dml_te.py create mode 100644 montecarlo/mc_from_config.py create mode 100644 montecarlo/mcpy/__init__.py create mode 100644 montecarlo/mcpy/metrics.py create mode 100644 montecarlo/mcpy/monte_carlo.py create mode 100644 montecarlo/mcpy/plotting.py create mode 100644 montecarlo/mcpy/utils.py create mode 100644 montecarlo/sweep_config_dml_te.py create mode 100644 montecarlo/sweep_mc_from_config.py diff --git a/montecarlo/econml_dml_te.py b/montecarlo/econml_dml_te.py new file mode 100644 index 000000000..190768cb9 --- /dev/null +++ b/montecarlo/econml_dml_te.py @@ -0,0 +1,180 @@ +from econml.dml import DMLCateEstimator, LinearDMLCateEstimator, SparseLinearDMLCateEstimator, ForestDMLCateEstimator +import numpy as np +from itertools import product +from sklearn.linear_model import Lasso, LassoCV, LogisticRegression, LogisticRegressionCV,LinearRegression,MultiTaskElasticNet,MultiTaskElasticNetCV +from sklearn.ensemble import RandomForestRegressor,RandomForestClassifier +from sklearn.preprocessing import PolynomialFeatures +import matplotlib.pyplot as plt +import matplotlib +from sklearn.model_selection import train_test_split + +# Treatment effect function +def exp_te(x): + return np.exp(2*x[0]) + +def instance_params(opts, seed): + n_controls = opts['n_controls'] + n_features = opts['n_features'] + n_samples = opts['n_samples'] + support_size = opts['support_size'] + + instance_params = {} + instance_params['support_Y'] = np.random.choice(np.arange(n_controls), size=support_size, replace=False) + instance_params['coefs_Y'] = np.random.uniform(0, 1, size=support_size) + instance_params['support_T'] = instance_params['support_Y'] + instance_params['coefs_T'] = np.random.uniform(0, 1, size=support_size) + return instance_params + +def gen_data(opts, instance_params, seed): + n_controls = opts['n_controls'] + n_features = opts['n_features'] + n_samples = opts['n_samples'] + # for k, v in instance_params.items(): + # locals()[k]=v + support_Y = instance_params['support_Y'] + coefs_Y = instance_params['coefs_Y'] + support_T = instance_params['support_T'] + coefs_T = instance_params['coefs_T'] + + # Outcome support + # support_Y = np.random.choice(np.arange(n_controls), size=support_size, replace=False) + # coefs_Y = np.random.uniform(0, 1, size=support_size) + epsilon_sample = lambda n: np.random.uniform(-1, 1, size=n) + + # Treatment support + # support_T = support_Y + # coefs_T = np.random.uniform(0, 1, size=support_size) + eta_sample = lambda n: np.random.uniform(-1, 1, size=n) + + # Generate controls, covariates, treatments, and outcomes + W = np.random.normal(0, 1, size=(n_samples, n_controls)) + X = np.random.uniform(0, 1, size=(n_samples, n_features)) + + # Heterogenous treatment effects + TE = np.array([exp_te(x) for x in X]) + T = np.dot(W[:, support_T], coefs_T) + eta_sample(n_samples) + Y = TE * T + np.dot(W[:, support_T], coefs_Y) + epsilon_sample(n_samples) + Y_train, Y_val, T_train, T_val, X_train, X_val, W_train, W_val = train_test_split(Y, T, X, W, test_size=.2) + # why use train_test_split at all? + + # Generate test data + X_test = np.array(list(product(np.arange(0, 1, 0.01), repeat=n_features))) + expected_te = np.array([exp_te(x_i) for x_i in X_test]) + + # data, true_param + return (X_test, Y_train, T_train, X_train, W_train), expected_te + +def linear_dml_fit(data, opts, seed): + X_test, Y, T, X, W = data + model_y = opts['model_y'] + model_t = opts['model_t'] + inference = opts['inference'] + + est = LinearDMLCateEstimator(model_y=model_y, model_t=model_t, random_state=seed) + est.fit(Y, T, X, W, inference=inference) + const_marginal_effect = est.const_marginal_effect(X_test) # same as est.effect(X) + lb, ub = est.const_marginal_effect_interval(X_test, alpha=0.05) + + return (X_test, const_marginal_effect), (lb, ub) + +def sparse_linear_dml_poly_fit(data, opts, seed): + X_test, Y, T, X, W = data + model_y = opts['model_y'] + model_t = opts['model_t'] + featurizer = opts['featurizer'] + inference = opts['inference'] + + est = SparseLinearDMLCateEstimator(model_y=model_y, + model_t=model_t, + featurizer=featurizer, + random_state=seed) + est.fit(Y, T, X, W, inference=inference) + const_marginal_effect = est.const_marginal_effect(X_test) # same as est.effect(X) + lb, ub = est.const_marginal_effect_interval(X_test, alpha=0.05) + + return (X_test, const_marginal_effect), (lb, ub) + +def dml_poly_fit(data, opts ,seed): + X_test, Y, T, X, W = data + model_y = opts['model_y'] + model_t = opts['model_t'] + featurizer = opts['featurizer'] + model_final = opts['model_final'] + inference = opts['inference'] + + est = DMLCateEstimator(model_y=model_y, + model_t=model_t, + model_final=model_final, + featurizer=featurizer, + random_state=seed) + est.fit(Y, T, X, W, inference=inference) + const_marginal_effect = est.const_marginal_effect(X_test) # same as est.effect(X) + lb, ub = est.const_marginal_effect_interval(X_test, alpha=0.05) + + return (X_test, const_marginal_effect), (lb, ub) + +def forest_dml_fit(data, opts, seed): + X_test, Y, T, X, W = data + model_y = opts['model_y'] + model_t = opts['model_t'] + discrete_treatment = opts['discrete_treatment'] + n_estimators = opts['n_estimators'] + subsample_fr = opts['subsample_fr'] + min_samples_leaf = opts['min_samples_leaf'] + min_impurity_decrease = opts['min_impurity_decrease'] + verbose = opts['verbose'] + min_weight_fraction_leaf = opts['min_weight_fraction_leaf'] + inference = opts['inference'] + + est = ForestDMLCateEstimator(model_y=model_y, + model_t=model_t, + discrete_treatment=discrete_treatment, + n_estimators=n_estimators, + subsample_fr=subsample_fr, + min_samples_leaf=min_samples_leaf, + min_impurity_decrease=min_impurity_decrease, + verbose=verbose, + min_weight_fraction_leaf=min_weight_fraction_leaf) + est.fit(Y, T, X, W, inference=inference) + const_marginal_effect = est.const_marginal_effect(X_test) # same as est.effect(X) + lb, ub = est.const_marginal_effect_interval(X_test, alpha=0.05) + + return (X_test, const_marginal_effect), (lb, ub) + +def main(): + opts = { + 'n_controls':30, + 'n_features':1, + 'n_samples':1000, + 'support_size':5 + } + method_opts = { + 'model_y': RandomForestRegressor(), + 'model_t': RandomForestRegressor(), + 'inference': 'statsmodels' + } + mc_opts = {'seed':123} + data, true_param = gen_data(opts, mc_opts) + X_test, Y_train, T_train, X_train, W_train = data + te_pred = linear_dml_fit(data, method_opts, mc_opts['seed']) + import pdb; pdb.set_trace() + print(te_pred[0][1]) + + # print(lb[0:5]) + # print(ub[0:5]) + # print(np.array(ub-lb)[0:5]) + # print(np.mean(np.array(ub-lb))) + + # def l2_error(x, y): return np.linalg.norm(x-y, ord=2) + # error = l2_error(X_train, te_pred) + # print(error) + # plt.figure(figsize=(10,6)) + # plt.plot(X_test, te_pred, label='DML default') + # plt.plot(X_test, true_param, 'b--', label='True effect') + # plt.ylabel('Treatment Effect') + # plt.xlabel('x') + # plt.legend() + # plt.show() + +if __name__=="__main__": + main() diff --git a/montecarlo/mc_from_config.py b/montecarlo/mc_from_config.py new file mode 100644 index 000000000..ffd6ccb10 --- /dev/null +++ b/montecarlo/mc_from_config.py @@ -0,0 +1,15 @@ +import sys +import argparse +from mcpy.monte_carlo import MonteCarlo +import importlib + +def monte_carlo_main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('--config', type=str, help='config file') + args = parser.parse_args(sys.argv[1:]) + + config = importlib.import_module(args.config, __name__) + MonteCarlo(config.CONFIG).run() + +if __name__=="__main__": + monte_carlo_main() \ No newline at end of file diff --git a/montecarlo/mcpy/__init__.py b/montecarlo/mcpy/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/montecarlo/mcpy/metrics.py b/montecarlo/mcpy/metrics.py new file mode 100644 index 000000000..d4f96b0aa --- /dev/null +++ b/montecarlo/mcpy/metrics.py @@ -0,0 +1,63 @@ +import numpy as np + +def l1_error(x, y): return np.linalg.norm(x-y, ord=1) +def l2_error(x, y): return np.linalg.norm(x-y, ord=2) +def bias(x, y): return x - y +def raw_estimate(x, y): return x +def truth(x, y): return y +def raw_estimate_nonzero_truth(x, y): return x[y>0] + +def rmse(param_estimates, true_params): + X_test = param_estimates[0][0][0] + pred = np.array([param_estimates[i][0][1] for i in range(len(param_estimates))]) + rmse = np.sqrt(np.mean(np.array(pred-true_params)**2, axis=0)) + return (X_test, rmse) + +def std(param_estimates, true_params): + X_test = param_estimates[0][0][0] + pred = np.array([param_estimates[i][0][1] for i in range(len(param_estimates))]) + return (X_test, np.std(pred, axis=0)) + +def conf_length(param_estimates, true_params): + X_test = param_estimates[0][0][0] + lb = np.array([param_estimates[i][1][0] for i in range(len(param_estimates))]) + ub = np.array([param_estimates[i][1][1] for i in range(len(param_estimates))]) + conf_length = np.mean(np.array(ub-lb), axis=0) + return (X_test, conf_length) + +def coverage(param_estimates, true_params): + X_test = param_estimates[0][0][0] + coverage = [] + for i, param_estimate in enumerate(param_estimates): + lb, ub = param_estimate[1] + coverage.append((lb <= true_params[i]) & (true_params[i] <= ub)) + return (X_test, np.mean(coverage, axis=0)) + +def coverage_band(param_estimates, true_params): + coverage_band = [] + for i, param_estimate in enumerate(param_estimates): + lb, ub = param_estimate[1] + covered = (lb<=true_params[i]).all() & (true_params[i]<=ub).all() + coverage_band.append(covered) + return np.array(coverage_band) + +def transform_identity(x, dgp, method, metric, config): + return x[dgp][method][metric] + +def transform_diff(x, dgp, method, metric, config): + return x[dgp][method][metric] - x[dgp][config['proposed_method']][metric] + +def transform_ratio(x, dgp, method, metric, config): + return 100 * (x[dgp][method][metric] - x[dgp][config['proposed_method']][metric]) / x[dgp][method][metric] + +def transform_agg_mean(x, dgp, method, metric, config): + return np.mean(x[dgp][method][metric], axis=1) + +def transform_agg_median(x, dgp, method, metric, config): + return np.median(x[dgp][method][metric], axis=1) + +def transform_agg_max(x, dgp, method, metric, config): + return np.max(x[dgp][method][metric], axis=1) + +def transform_diff_positive(x, dgp, method, metric, config): + return x[dgp][method][metric] - x[dgp][config['proposed_method']][metric] >= 0 diff --git a/montecarlo/mcpy/monte_carlo.py b/montecarlo/mcpy/monte_carlo.py new file mode 100644 index 000000000..a3f526a77 --- /dev/null +++ b/montecarlo/mcpy/monte_carlo.py @@ -0,0 +1,169 @@ +import os +import sys +import numpy as np +from joblib import Parallel, delayed +import joblib +import argparse +import importlib +from itertools import product +import collections +from copy import deepcopy +from mcpy.utils import filesafe +from mcpy import plotting + +def _check_valid_config(config): + assert 'dgps' in config, "config dict must contain dgps" + assert 'dgp_opts' in config, "config dict must contain dgp_opts" + assert 'method_opts' in config, "config dict must contain method_opts" + assert 'mc_opts' in config, "config dict must contain mc_opts" + assert 'metrics' in config, "config dict must contain metrics" + assert 'methods' in config, "config dict must contain methods" + assert 'plots' in config, "config dict must contain plots" + assert 'target_dir' in config, "config must contain target_dir" + assert 'reload_results' in config, "config must contain reload_results" + assert 'n_experiments' in config['mc_opts'], "config[mc_opts] must contain n_experiments" + assert 'seed' in config['mc_opts'], "config[mc_opts] must contain seed" + +class MonteCarlo: + + def __init__(self, config): + self.config = config + _check_valid_config(self.config) + config['param_str'] = '_'.join(['{}_{}'.format(filesafe(k), v) for k,v in self.config['mc_opts'].items()]) + config['param_str'] += '_' + '_'.join(['{}_{}'.format(filesafe(k), v) for k,v in self.config['dgp_opts'].items()]) + config['param_str'] += '_' + '_'.join(['{}_{}'.format(filesafe(k), v) for k,v in self.config['method_opts'].items()]) + return + + # TODO: add dgp-specific, method-specific parameters and metrics + def experiment(self, instance_params, seed): + ''' Runs an experiment on a single randomly generated instance and sample and returns + the parameter estimates for each method and the evaluated metrics for each method + ''' + np.random.seed(seed) + + param_estimates = {} + true_params = {} + for dgp_name, dgp_fn in self.config['dgps'].items(): + data, true_param = dgp_fn(self.config['dgp_opts'][dgp_name], instance_params[dgp_name], seed) + true_params[dgp_name] = true_param + param_estimates[dgp_name] = {} + + for method_name, method in self.config['methods'].items(): + param_estimates[dgp_name][method_name] = method(data, self.config['method_opts'][method_name], seed) + + return param_estimates, true_params + + def run(self): + ''' Runs multiple experiments in parallel on randomly generated instances and samples and returns + the parameter estimates for each method and the evaluated metrics for each method across all + experiments + ''' + random_seed = self.config['mc_opts']['seed'] + + if not os.path.exists(self.config['target_dir']): + os.makedirs(self.config['target_dir']) + + instance_params = {} + for dgp_name in self.config['dgps']: + instance_params[dgp_name] = self.config['dgp_instance_fns'][dgp_name](self.config['dgp_opts'][dgp_name], random_seed) + + # results_file = os.path.join(self.config['target_dir'], 'results_{}.jbl'.format(self.config['param_str'])) + # what exactly is reload results for? + results_file = os.path.join(self.config['target_dir'], 'results_seed{}.jbl'.format(random_seed)) + if self.config['reload_results'] and os.path.exists(results_file): + results = joblib.load(results_file) + else: + results = Parallel(n_jobs=-1, verbose=1)( + delayed(self.experiment)(instance_params, random_seed + exp_id) + for exp_id in range(self.config['mc_opts']['n_experiments'])) + joblib.dump(results, results_file) + + # import pdb; pdb.set_trace() + + param_estimates = {} + metric_results = {} + true_params = {} + for dgp_name in self.config['dgps'].keys(): + param_estimates[dgp_name] = {} + metric_results[dgp_name] = {} + for method_name in self.config['methods'].keys(): + # param_estimates[dgp_name][method_name] = np.array([results[i][0][dgp_name][method_name] for i in range(self.config['mc_opts']['n_experiments'])]) + param_estimates[dgp_name][method_name] = [results[i][0][dgp_name][method_name] for i in range(self.config['mc_opts']['n_experiments'])] + true_params[dgp_name] = [results[i][1][dgp_name] for i in range(self.config['mc_opts']['n_experiments'])] + # import pdb; pdb.set_trace() + metric_results[dgp_name][method_name] = {} + for metric_name, metric_fn in self.config['metrics'].items(): + # for metric_name, metric_fn in self.config['metrics'][method_name].items(): # for method specific parameters + param_estimate_inputs = [results[i][0][dgp_name][method_name] for i in range(self.config['mc_opts']['n_experiments'])] + true_param_inputs = [results[i][1][dgp_name] for i in range(self.config['mc_opts']['n_experiments'])] + # import pdb; pdb.set_trace() + metric_results[dgp_name][method_name][metric_name] = metric_fn(param_estimate_inputs, true_param_inputs) + + for plot_name, plot_fn in self.config['plots'].items(): + # for plot_name, plot_fn in self.config['plots'][method_name].items(): # for method specific plots + if isinstance(plot_fn, dict): + plotting.instance_plot(plot_name, param_estimates, metric_results, self.config, plot_fn) + else: + plot_fn(plot_name, param_estimates, metric_results, true_params, self.config) + + return param_estimates, metric_results, true_params + +class MonteCarloSweep: + + def __init__(self, config): + self.config = config + _check_valid_config(self.config) + config['param_str'] = '_'.join(['{}_{}'.format(filesafe(k), self._stringify_param(v)) for k,v in self.config['mc_opts'].items()]) + config['param_str'] += '_' + '_'.join(['{}_{}'.format(filesafe(k), self._stringify_param(v)) for k,v in self.config['dgp_opts'].items()]) + config['param_str'] += '_' + '_'.join(['{}_{}'.format(filesafe(k), self._stringify_param(v)) for k,v in self.config['method_opts'].items()]) + return + + def _stringify_param(self, param): + if hasattr(param, "__len__"): + return '{}_to_{}'.format(np.min(param), np.max(param)) + else: + return param + + def run(self): + # currently duplicates computation for the dgps because all only one dgp param changed each config + # need to make it so that every inst_config is different for each dgp + for dgp_name in self.config['dgp_opts'].keys(): + dgp_sweep_params = [] + dgp_sweep_param_vals = [] + for dgp_key, dgp_val in self.config['dgp_opts'][dgp_name].items(): + if hasattr(dgp_val, "__len__"): + dgp_sweep_params.append(dgp_key) + dgp_sweep_param_vals.append(dgp_val) + sweep_keys = [] + sweep_params = [] + sweep_metrics = [] + sweep_true_params = [] + inst_config = deepcopy(self.config) + for vec in product(*dgp_sweep_param_vals): + setting = list(zip(dgp_sweep_params, vec)) + for k,v in setting: + inst_config['dgp_opts'][dgp_name][k] = v + params, metrics, true_params = MonteCarlo(inst_config).run() + sweep_keys.append(setting) + sweep_params.append(params) + sweep_metrics.append(metrics) + sweep_true_params.append(true_params) + + for plot_name, plot_fn in self.config['sweep_plots'].items(): + if isinstance(plot_fn, dict): + plotting.sweep_plot(plot_key, sweep_keys, sweep_params, sweep_metrics, self.config, plot_fn) + else: + plot_fn(plot_name, sweep_keys, sweep_params, sweep_metrics, sweep_true_params, self.config) + + return sweep_keys, sweep_params, sweep_metrics, sweep_true_params + +def monte_carlo_main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('--config', type=str, help='config file') + args = parser.parse_args(sys.argv[1:]) + + config = importlib.import_module(args.config) + MonteCarlo(config.CONFIG).run() + +if __name__=="__main__": + monte_carlo_main() diff --git a/montecarlo/mcpy/plotting.py b/montecarlo/mcpy/plotting.py new file mode 100644 index 000000000..923c4a8ff --- /dev/null +++ b/montecarlo/mcpy/plotting.py @@ -0,0 +1,244 @@ +import os +import numpy as np +import matplotlib +# matplotlib.use('Agg') +import matplotlib.pyplot as plt +from matplotlib.mlab import griddata +plt.style.use('ggplot') +from mcpy.utils import filesafe +import mcpy.metrics +import itertools + +def plot_sweep(plot_name, sweep_keys, sweep_params, sweep_metrics, sweep_true_params, config): + pass + +def plot_metrics(plot_name, param_estimates, metric_results, true_params, config): + # plt.figure(figsize=(10,6)) + for dgp_name in config['dgps'].keys(): # just one right now + for metric_name in config['metrics'].keys(): + if metric_name not in config['per_plots']: + for method_name in config['methods'].keys(): + x, y = metric_results[dgp_name][method_name][metric_name] + plt.plot(x, y, label=method_name) + plt.xlabel("X_test") + plt.ylabel(metric_name) + plt.legend() + plt.show() + # mean_rmse = np.mean(metric_results[dgp_name][method_name]['rmse']) + # mean_conf_length = np.mean(metric_results[dgp_name][method_name]['conf_length']) + # mean_coverage = np.mean(metric_results[dgp_name][method_name]['coverage']) + # print("means for {}: rmse: {}, conf_length: {}, coverage: {}".format(method_name, mean_rmse, mean_conf_length, mean_coverage)) + +def plot_visualization(plot_name, param_estimates, metric_results, true_params, config): + X_test = [] + for dgp_name in config['dgps'].keys(): # just one right now + for method_name in config['methods'].keys(): + X_test = param_estimates[dgp_name][method_name][0][0][0] + pred = np.array([param_estimates[dgp_name][method_name][i][0][1] for i in range(len(param_estimates[dgp_name][method_name]))]) + mean = np.mean(pred, axis=0) + plt.plot(X_test, mean, label=method_name) + plt.xlabel("X_test") + plt.ylabel("Treatment Effect") + lb = np.array([param_estimates[dgp_name][method_name][i][1][0] for i in range(len(param_estimates[dgp_name][method_name]))]) + ub = np.array([param_estimates[dgp_name][method_name][i][1][1] for i in range(len(param_estimates[dgp_name][method_name]))]) + lb_ = np.min(lb, axis=0) + ub_ = np.max(ub, axis=0) + plt.fill_between(X_test.reshape(100,), lb_, ub_, alpha=0.25) + + true = true_params[dgp_name][0] + plt.plot(X_test, true, label='true effect') + plt.legend() + plt.show() + +def plot_violin(plot_name, param_estimates, metric_results, true_params, config): + for dgp_name, dgp_fn in metric_results.items(): + n_methods = len(list(dgp_fn.keys())) + for metric_name in next(iter(dgp_fn.values())).keys(): + if metric_name in config['per_plots']: + plt.figure(figsize=(1.5 * n_methods, 2.5)) + plt.violinplot([dgp_fn[method_name][metric_name] for method_name in dgp_fn.keys()], showmedians=True) + plt.xticks(np.arange(1, n_methods + 1), list(dgp_fn.keys())) + plt.ylabel(metric_name) + plt.tight_layout() + plt.show() + +def plot_subset_param_histograms(param_estimates, metric_results, config, subset): + for dgp_name, pdgp in param_estimates.items(): + n_methods = len(list(pdgp.keys())) + n_params = config['dgp_opts']['kappa_gamma'] + 1 + plt.figure(figsize=(4 * n_params, 2 * n_methods)) + for it, m_name in enumerate(pdgp.keys()): + for inner_it, i in enumerate(subset): + plt.subplot(n_methods, n_params, it * n_params + inner_it + 1) + plt.hist(pdgp[m_name][:, i]) + plt.title("{}[{}]. $\\mu$: {:.2f}, $\\sigma$: {:.2f}".format(m_name, i, np.mean(pdgp[m_name][:, i]), np.std(pdgp[m_name][:, i]))) + plt.tight_layout() + plt.savefig(os.path.join(config['target_dir'], 'dist_dgp_{}_{}.png'.format(dgp_name, config['param_str'])), dpi=300) + plt.close() + return + +def plot_param_histograms2(param_estimates, metric_results, config): + for dgp_name, pdgp in param_estimates.items(): + n_methods = len(list(pdgp.keys())) + n_params = next(iter(pdgp.values())).shape[1] + plt.figure(figsize=(4 * n_params, 2 * n_methods)) + for it, m_name in enumerate(pdgp.keys()): + for i in range(pdgp[m_name].shape[1]): + plt.subplot(n_methods, n_params, it * n_params + i + 1) + plt.hist(pdgp[m_name][:, i]) + plt.title("{}[{}]. $\\mu$: {:.2f}, $\\sigma$: {:.2f}".format(m_name, i, np.mean(pdgp[m_name][:, i]), np.std(pdgp[m_name][:, i]))) + plt.tight_layout() + plt.savefig(os.path.join(config['target_dir'], 'dist_dgp_{}_{}.png'.format(dgp_name, config['param_str'])), dpi=300) + plt.close() + return + +def plot_metrics2(param_estimates, metric_results, config): + for dgp_name, mdgp in metric_results.items(): + n_methods = len(list(mdgp.keys())) + for metric_name in next(iter(mdgp.values())).keys(): + plt.figure(figsize=(1.5 * n_methods, 2.5)) + plt.violinplot([mdgp[method_name][metric_name] for method_name in mdgp.keys()], showmedians=True) + plt.xticks(np.arange(1, n_methods + 1), list(mdgp.keys())) + plt.ylabel(metric_name) + plt.tight_layout() + plt.savefig(os.path.join(config['target_dir'], '{}_dgp_{}_{}.png'.format(filesafe(metric_name), dgp_name, config['param_str'])), dpi=300) + plt.close() + return + +def plot_metric_comparisons(param_estimates, metric_results, config): + for dgp_name, mdgp in metric_results.items(): + n_methods = len(list(mdgp.keys())) + for metric_name in next(iter(mdgp.values())).keys(): + plt.figure(figsize=(1.5 * n_methods, 2.5)) + plt.violinplot([mdgp[method_name][metric_name] - mdgp[config['proposed_method']][metric_name] for method_name in mdgp.keys() if method_name != config['proposed_method']], showmedians=True) + plt.xticks(np.arange(1, n_methods), [method_name for method_name in mdgp.keys() if method_name != config['proposed_method']]) + plt.ylabel('decrease in {}'.format(metric_name)) + plt.tight_layout() + plt.savefig(os.path.join(config['target_dir'], '{}_decrease_dgp_{}_{}.png'.format(filesafe(metric_name), dgp_name, config['param_str'])), dpi=300) + plt.close() + return + +def instance_plot(plot_name, param_estimates, metric_results, config, plot_config): + methods = plot_config['methods'] if 'methods' in plot_config else list(config['methods'].keys()) + metrics = plot_config['metrics'] if 'metrics' in plot_config else list(config['metrics'].keys()) + dgps = plot_config['dgps'] if 'dgps' in plot_config else list(config['dgps'].keys()) + metric_transforms = plot_config['metric_transforms'] if 'metric_transforms' in plot_config else {'': mcpy.metrics.transform_identity} + + for tr_name, tr_fn in metric_transforms.items(): + for dgp_name in dgps: + for metric_name in metrics: + plt.figure(figsize=(1.5 * len(methods), 2.5)) + plt.violinplot([tr_fn(metric_results, dgp_name, method_name, metric_name, config) for method_name in methods], showmedians=True) + plt.xticks(np.arange(1, len(methods) + 1), methods) + plt.ylabel('{}({})'.format(tr_name, metric_name)) + plt.tight_layout() + plt.savefig(os.path.join(config['target_dir'], '{}_{}_{}_dgp_{}_{}.png'.format(plot_name, filesafe(metric_name), tr_name, dgp_name, config['param_str'])), dpi=300) + plt.close() + return + +def _select_config_keys(sweep_keys, select_vals, filter_vals): + + if select_vals is not None: + mask_select = [all(any((p, v) in key for v in vlist) for p, vlist in select_vals.items()) for key in sweep_keys] + else: + mask_select = [True]*len(sweep_keys) + if filter_vals is not None: + mask_filter = [all(all((p, v) not in key for v in vlist) for p, vlist in filter_vals.items()) for key in sweep_keys] + else : + mask_filter = [True]*len(sweep_keys) + mask = [ms and mf for ms, mf in zip(mask_select, mask_filter)] + return mask + +def sweep_plot_marginal_transformed_metric(transform_fn, transform_name, dgps, methods, metrics, plot_name, sweep_keys, sweep_params, sweep_metrics, config, param_subset={}, select_vals={}, filter_vals={}): + + sweeps = {} + for dgp_key, dgp_val in config['dgp_opts'].items(): + if hasattr(dgp_val, "__len__"): + sweeps[dgp_key] = dgp_val + + mask = _select_config_keys(sweep_keys, select_vals, filter_vals) + if np.sum(mask) == 0: + print("Filtering resulted in no valid configurations!") + return + + for dgp in dgps: + for metric in metrics: + for param, param_vals in sweeps.items(): + if param_subset is not None and param not in param_subset: + continue + plt.figure(figsize=(5, 3)) + for method in methods: + medians = [] + mins = [] + maxs = [] + for val in param_vals: + subset = [transform_fn(metrics, dgp, method, metric, config) for key, metrics, ms + in zip(sweep_keys, sweep_metrics, mask) + if (param, val) in key and ms] + if len(subset) > 0: + grouped_results = np.concatenate(subset) + medians.append(np.median(grouped_results)) + mins.append(np.min(grouped_results)) + maxs.append(np.max(grouped_results)) + plt.plot(param_vals, medians, label=method) + plt.fill_between(param_vals, maxs, mins, alpha=0.3) + plt.legend() + plt.xlabel(param) + plt.ylabel('{}({})'.format(transform_name, metric)) + plt.tight_layout() + plt.savefig(os.path.join(config['target_dir'], '{}_{}_{}_dgp_{}_growing_{}_{}.png'.format(plot_name, filesafe(metric), transform_name, dgp, filesafe(param), config['param_str'])), dpi=300) + plt.close() + + for param1, param2 in itertools.combinations(sweeps.keys(), 2): + if param_subset is not None and (param1, param2) not in param_subset and (param2, param1) not in param_subset: + continue + x, y, z = [], [], [] + for method_it, method in enumerate(methods): + x.append([]), y.append([]), z.append([]) + for val1, val2 in itertools.product(*[sweeps[param1], sweeps[param2]]): + subset = [transform_fn(metrics, dgp, method, metric, config) for key, metrics, ms + in zip(sweep_keys, sweep_metrics, mask) + if (param1, val1) in key and (param2, val2) in key and ms] + if len(subset) > 0: + grouped_results = np.concatenate(subset) + x[method_it].append(val1) + y[method_it].append(val2) + z[method_it].append(np.median(grouped_results)) + vmin = np.min(z) + vmax = np.max(z) + fig, axes = plt.subplots(nrows=1, ncols=len(methods), figsize=(4 * len(methods), 3)) + if not hasattr(axes, '__len__'): + axes = [axes] + for method_it, (method, ax) in enumerate(zip(methods, axes)): + xi = np.linspace(np.min(x[method_it]), np.max(x[method_it]), 5*len(x[method_it])) + yi = np.linspace(np.min(y[method_it]), np.max(y[method_it]), 5*len(y[method_it])) + zi = griddata(np.array(x[method_it]), np.array(y[method_it]), np.array(z[method_it]), xi, yi, interp='linear') + ax.contour(xi, yi, zi, 15, linewidths=0.2, colors='k') + im = ax.pcolormesh(xi, yi, zi, cmap=plt.cm.Reds, vmin=vmin, vmax=vmax) + ax.contourf(xi, yi, zi, 15, cmap=plt.cm.Reds, vmin=vmin, vmax=vmax) + ax.scatter(np.array(x[method_it]), np.array(y[method_it]), alpha=0.5, s=3, c='b') + ax.set_xlabel(param1) + ax.set_ylabel(param2) + ax.set_title(method) + + plt.tight_layout() + fig.subplots_adjust(right=0.8) + cbar_ax = fig.add_axes([0.81, 0.15, 0.02, 0.72]) + cbar = fig.colorbar(im, cax=cbar_ax) + cbar.ax.tick_params(labelsize=8) + cbar.ax.set_ylabel('median {}({})'.format(transform_name, metric)) + plt.savefig(os.path.join(config['target_dir'], '{}_{}_{}_dgp_{}_growing_{}_and_{}_{}.png'.format(plot_name, filesafe(metric), transform_name, dgp, filesafe(param1), filesafe(param2), config['param_str'])), dpi=300) + plt.close() + +def sweep_plot(plot_name, sweep_keys, sweep_params, sweep_metrics, config, plot_config): + param_subset = plot_config['varying_params'] if 'varying_params' in plot_config else None + select_vals = plot_config['select_vals'] if 'select_vals' in plot_config else {} + filter_vals = plot_config['filter_vals'] if 'filter_vals' in plot_config else {} + methods = plot_config['methods'] if 'methods' in plot_config else list(config['methods'].keys()) + metrics = plot_config['metrics'] if 'metrics' in plot_config else list(config['metrics'].keys()) + dgps = plot_config['dgps'] if 'dgps' in plot_config else list(config['dgps'].keys()) + metric_transforms = plot_config['metric_transforms'] if 'metric_transforms' in plot_config else {'': mcpy.metrics.transform_identity} + + for tr_name, tr_fn in metric_transforms.items(): + sweep_plot_marginal_transformed_metric(tr_fn, tr_name, dgps, methods, metrics, plot_name, sweep_keys, sweep_params, sweep_metrics, config, + param_subset=param_subset, select_vals=select_vals, filter_vals=filter_vals) diff --git a/montecarlo/mcpy/utils.py b/montecarlo/mcpy/utils.py new file mode 100644 index 000000000..411c07803 --- /dev/null +++ b/montecarlo/mcpy/utils.py @@ -0,0 +1,12 @@ +import numpy as np + +def cross_product(X1, X2): + """ Cross product of features in matrices X1 and X2 + """ + n = np.shape(X1)[0] + assert n == np.shape(X2)[0] + return (X1.reshape(n,1,-1) * X2.reshape(n,-1,1)).reshape(n,-1) + + +def filesafe(str): + return "".join([c for c in str if c.isalpha() or c.isdigit() or c==' ']).rstrip().replace(' ', '_') diff --git a/montecarlo/sweep_config_dml_te.py b/montecarlo/sweep_config_dml_te.py new file mode 100644 index 000000000..11375e248 --- /dev/null +++ b/montecarlo/sweep_config_dml_te.py @@ -0,0 +1,90 @@ +import os +import numpy as np +import econml_dml_te +from mcpy import metrics +from mcpy import plotting +from mcpy import utils +from sklearn.linear_model import Lasso, LassoCV, LogisticRegression, LogisticRegressionCV,LinearRegression,MultiTaskElasticNet,MultiTaskElasticNetCV +from sklearn.ensemble import RandomForestRegressor,RandomForestClassifier +from sklearn.preprocessing import PolynomialFeatures + +CONFIG = { + "dgps": { + "dgp1": econml_dml_te.gen_data + }, + "dgp_instance_fns": { + 'dgp1': econml_dml_te.instance_params + }, + "dgp_opts": { + 'dgp1': { + 'n_samples': [100, 2000], + 'n_features': 1, + 'n_controls': 30, + 'support_size': 5 + }, + }, + "methods": { + "LinearDMLCate": econml_dml_te.linear_dml_fit, + "SparseLinearDMLCate": econml_dml_te.sparse_linear_dml_poly_fit, + # "DMLCate": econml_dml_te.dml_poly_fit, + # "ForestDMLCate": econml_dml_te.forest_dml_fit + }, + "method_opts": { + 'LinearDMLCate': { + 'model_y': RandomForestRegressor(), + 'model_t': RandomForestRegressor(), + 'inference': 'statsmodels' + }, + 'SparseLinearDMLCate': { + 'model_y': RandomForestRegressor(), + 'model_t': RandomForestRegressor(), + 'featurizer': PolynomialFeatures(degree=3), + 'inference': 'debiasedlasso' + }, + # 'DMLCate': { + # 'model_y': RandomForestRegressor(), + # 'model_t': RandomForestRegressor(), + # 'model_final': Lasso(alpha=0.1, fit_intercept=False), + # 'featurizer': PolynomialFeatures(degree=10), + # 'inference': 'bootstrap' + # }, + # 'ForestDMLCate': { + # 'model_y': RandomForestRegressor(), + # 'model_t': RandomForestRegressor(), + # 'discrete_treatment': False, + # 'n_estimators': 1000, + # 'subsample_fr': 0.8, + # 'min_samples_leaf': 10, + # 'min_impurity_decrease': 0.001, + # 'verbose': 0, + # 'min_weight_fraction_leaf': 0.01, + # 'inference': 'bootstrap' + # } + }, + "metrics": { + 'rmse': metrics.rmse, + 'conf_length': metrics.conf_length, + 'coverage': metrics.coverage, + 'std': metrics.std, + 'coverage_band': metrics.coverage_band + }, + "plots": { + 'plot1': plotting.plot_metrics, + 'plot2': plotting.plot_visualization, + 'plot3': plotting.plot_violin + }, + "per_plots": ['coverage_band'], + "sweep_plots": { + # 'plot4': plotting.plot_sweep + # "plot1": {'varying_params': ['$k_g$'], 'select_vals': {'$\\sigma_\\epsilon$': [1.0], '$\\sigma_\\eta$': [1.0]}}, + # "plot2": {'varying_params': [n('$k_g$', '$\\sigma_\\eta$')], 'select_vals': {'$\\sigma_\\epsilon$':[1.0]}, 'methods': ["Direct"], 'metric_transforms': {'% decrease': metrics.transform_ratio}}, + # "plot3": {'varying_params': [('$k_g$', '$\\sigma_\\epsilon$')], 'select_vals': {'$\\sigma_\\eta$':[1.0]}, 'methods': ["Direct"], 'metric_transforms': {'% decrease': metrics.transform_ratio}} + }, + "mc_opts": { + 'n_experiments': 5, # number of monte carlo experiments + "seed": 123 + }, + "proposed_method": "CrossOrtho", + "target_dir": "sweep_econml_test", + "reload_results": False + } diff --git a/montecarlo/sweep_mc_from_config.py b/montecarlo/sweep_mc_from_config.py new file mode 100644 index 000000000..dd83220b5 --- /dev/null +++ b/montecarlo/sweep_mc_from_config.py @@ -0,0 +1,15 @@ +import sys +import argparse +from mcpy.monte_carlo import MonteCarloSweep +import importlib + +def monte_carlo_main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('--config', type=str, help='config file') + args = parser.parse_args(sys.argv[1:]) + + config = importlib.import_module(args.config, __name__) + MonteCarloSweep(config.CONFIG).run() + +if __name__=="__main__": + monte_carlo_main() \ No newline at end of file From db6d0b78b006521c2ddcd24c0b23751c6619cf56 Mon Sep 17 00:00:00 2001 From: Ashay Athalye Date: Fri, 31 Jan 2020 18:15:01 -0500 Subject: [PATCH 2/2] rename files, document and clean code, write README --- montecarlo/README.md | 100 ++++++++ montecarlo/dml_te_config.py | 92 +++++++ .../{econml_dml_te.py => dml_te_functions.py} | 180 ++++++++++---- montecarlo/dml_te_test/results_seed123.jbl | Bin 0 -> 40231 bytes .../example_plots/plot1_conf_length.png | Bin 0 -> 32552 bytes montecarlo/example_plots/plot1_coverage.png | Bin 0 -> 28491 bytes montecarlo/example_plots/plot1_rmse.png | Bin 0 -> 33703 bytes montecarlo/example_plots/plot1_std.png | Bin 0 -> 32914 bytes montecarlo/example_plots/plot2.png | Bin 0 -> 41900 bytes montecarlo/example_plots/plot3.png | Bin 0 -> 12358 bytes montecarlo/mc_from_config.py | 15 -- montecarlo/mcpy/monte_carlo.py | 177 +++++++++----- montecarlo/mcpy/plotting.py | 224 +++--------------- montecarlo/mcpy/utils.py | 11 +- montecarlo/run_mc_from_config.py | 31 +++ montecarlo/sweep_config_dml_te.py | 90 ------- montecarlo/sweep_mc_from_config.py | 15 -- 17 files changed, 510 insertions(+), 425 deletions(-) create mode 100644 montecarlo/README.md create mode 100644 montecarlo/dml_te_config.py rename montecarlo/{econml_dml_te.py => dml_te_functions.py} (54%) create mode 100644 montecarlo/dml_te_test/results_seed123.jbl create mode 100644 montecarlo/example_plots/plot1_conf_length.png create mode 100644 montecarlo/example_plots/plot1_coverage.png create mode 100644 montecarlo/example_plots/plot1_rmse.png create mode 100644 montecarlo/example_plots/plot1_std.png create mode 100644 montecarlo/example_plots/plot2.png create mode 100644 montecarlo/example_plots/plot3.png delete mode 100644 montecarlo/mc_from_config.py create mode 100644 montecarlo/run_mc_from_config.py delete mode 100644 montecarlo/sweep_config_dml_te.py delete mode 100644 montecarlo/sweep_mc_from_config.py diff --git a/montecarlo/README.md b/montecarlo/README.md new file mode 100644 index 000000000..9d7dce89c --- /dev/null +++ b/montecarlo/README.md @@ -0,0 +1,100 @@ + + + +# Monte Carlo Library +The folder mcpy contains code related to running monte carlo experiments from config files and saving and running the results. +Look at dml_te_confi.py and dml_te_functions.py as an example. + +We can run a monte carlo simulation with the following from the command line: +``` +python3 run_mc_from_config.py --config dml_te_config +``` + +The config dictionary allows one to run monte carlo experiments for some configuration of the parameters of the dgp, estimation methods, metrics, and plot functions. The MonteCarlo class will run experiments for each dgp, for each method, and on those results of each of those, calculate metrics and plots. DGPs, estimation methods, metrics, and plot functions can all be user defined. Thus this is a general framework to make monte carlo simulations easy to automate. + +The config looks like the following: +```python +CONFIG = { + # whether to do a simulation for a fixed set of parameters vs. 'sweep_parameter', + # where it will run multiple simulations for all permutations of the parameters + "type" : 'single_parameter, + # references to dgp functions + "dgps" : { + 'dgp1': dml_te_functions.instance_params + }, + # dgp options for each dgp + "dgp_opts" : { + 'dgp1': { + 'n_samples': 2000, + 'n_features': 1, + 'n_controls': 30, + 'support_size': 5 + }, + }, + # references to methods + "methods" : { + + }, + # method options, for each method + "method_opts" : { + "method1": { + "LinearDMLCate": dml_te_functions.linear_dml_fit, + }, + "method2": { + + } + }, + # references to metric functions + "metrics" : { + 'rmse': metrics.rmse, + 'conf_length': metrics.conf_length, + 'coverage': metrics.coverage, + 'std': metrics.std, + 'coverage_band': metrics.coverage_band + }, + # references to plot functions + "plots" : { + 'plot1': plotting.plot_metrics, + 'plot2': plotting.plot_visualization, + 'plot3': plotting.plot_violin + }, + # different metrics are plotted differently + # single summary metrics are single value per dgp and method + "single_summary_metrics" : ['coverage_band'], # list of the metrics that are single summary metrics + # plot to run for when the type is sweep_parameter. + "sweep_plots" :{ + }, + # monte carlo simulation options + "mc_opts" : { + 'n_experiments': 5, # number of monte carlo experiments + "seed": 123 + }, + # comparison method reference # not supported currently + "proposed_method" : { + }, + # directory to save things to + "target_dir" : "", + "reload_results" : False # to rerun or load previous results +} +``` + +# Some Next Steps + +- Use cloud computing service to run all simulations with a lot of cores, in parallel, on the cloud. This will yield better simulation results and allow us to run simulations over many more parameters and better evaluate the empirical performance of the estimators. +- A lot of HTE are calculated for some treatment T0 to T1. When evaluating the performance, the user should perhaps specify those specific vectors on their own in the dgp amd method functions that they write, or perhaps they should also be swept over in the MonteCarloSweep. A question is for how to sweep over different values for them, e.g, in what increments, especially as they get to be high dimensional. +- Construct more dgps, and look at more real data sets to perform simulations on +- Integrate this with the rest of the code suite such that whenever significant updates to the implementations of the estimators are made, a host of MC simulations are run and the results are compared to previous ones before the implementation changes. This would allow us to understand the change in empirical performance of the estimators after the change in implementation. +- More metrics and plotting functions, try to generalize them and not have them specific to specific DGP/method/ implementations. +- Overall challenge of how to keep the framework general and but also be able to define nitty-gritty DGPs/methods/metrics/plots. Return types that are more vague like lists or tuples or dictionaries may allow for lots of different DGP/method implementations that use the framework at the same time, where each of those is specified in the references from the config file. Best way to realize what small adjustments to make is to implement a bunch of DGPs/methods/metrics/plots and see what return types need to be made more general or more specific/tailored. For example, when X_test is multidimensional there's an issue for how to plot the metrics. Do you plot them with respect to the first column or X_test? or? This means we may have to make the plot functions specific to that DGP/method set up. The framework allows for anyone to write their own dgps/methods/metrics/plot functions, but achieving more generality would be preferable. Maybe for sets/classes of certain DGPs that are used in testing a lot together. Anything to avoid lots of specific code for each dgp/etc., otherwise the test codebase will get big. + +# Example Plots +

+ + + + + + +
+ Example plots for DGP in dml_te_config.py +

diff --git a/montecarlo/dml_te_config.py b/montecarlo/dml_te_config.py new file mode 100644 index 000000000..ca18b541c --- /dev/null +++ b/montecarlo/dml_te_config.py @@ -0,0 +1,92 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import os +import numpy as np +import dml_te_functions +from mcpy import metrics +from mcpy import plotting +from mcpy import utils +from sklearn.linear_model import Lasso, LassoCV, LogisticRegression, LogisticRegressionCV,LinearRegression,MultiTaskElasticNet,MultiTaskElasticNetCV +from sklearn.ensemble import RandomForestRegressor,RandomForestClassifier +from sklearn.preprocessing import PolynomialFeatures + +CONFIG = { + "type": 'single_parameter', + "dgps": { + "dgp1": dml_te_functions.gen_data + }, + "dgp_instance_fns": { + 'dgp1': dml_te_functions.instance_params + }, + "dgp_opts": { + 'dgp1': { + 'n_samples': 2000, + 'n_features': 1, + 'n_controls': 30, + 'support_size': 5 + }, + }, + "methods": { + "LinearDMLCate": dml_te_functions.linear_dml_fit, + "SparseLinearDMLCate": dml_te_functions.sparse_linear_dml_poly_fit, + # "DMLCate": dml_te_functions.dml_poly_fit, + # "ForestDMLCate": dml_te_functions.forest_dml_fit + }, + "method_opts": { + 'LinearDMLCate': { + 'model_y': RandomForestRegressor(), + 'model_t': RandomForestRegressor(), + 'inference': 'statsmodels' + }, + 'SparseLinearDMLCate': { + 'model_y': RandomForestRegressor(), + 'model_t': RandomForestRegressor(), + 'featurizer': PolynomialFeatures(degree=3), + 'inference': 'debiasedlasso' + }, + 'DMLCate': { + 'model_y': RandomForestRegressor(), + 'model_t': RandomForestRegressor(), + 'model_final': Lasso(alpha=0.1, fit_intercept=False), + 'featurizer': PolynomialFeatures(degree=10), + 'inference': 'bootstrap' + }, + 'ForestDMLCate': { + 'model_y': RandomForestRegressor(), + 'model_t': RandomForestRegressor(), + 'discrete_treatment': False, + 'n_estimators': 1000, + 'subsample_fr': 0.8, + 'min_samples_leaf': 10, + 'min_impurity_decrease': 0.001, + 'verbose': 0, + 'min_weight_fraction_leaf': 0.01, + 'inference': 'bootstrap' + } + }, + "metrics": { + 'rmse': metrics.rmse, + 'conf_length': metrics.conf_length, + 'coverage': metrics.coverage, + 'std': metrics.std, + 'coverage_band': metrics.coverage_band + }, + "plots": { + 'plot1': plotting.plot_metrics, + 'plot2': plotting.plot_visualization, + 'plot3': plotting.plot_violin + }, + # different metrics are plotted differnetly + # single summary metrics are a single value per dgp and method + "single_summary_metrics": ['coverage_band'], + "sweep_plots": { + }, + "mc_opts": { + 'n_experiments': 5, # number of monte carlo experiments + "seed": 123 + }, + "proposed_method": "CrossOrtho", + "target_dir": "dml_te_test", + "reload_results": False + } diff --git a/montecarlo/econml_dml_te.py b/montecarlo/dml_te_functions.py similarity index 54% rename from montecarlo/econml_dml_te.py rename to montecarlo/dml_te_functions.py index 190768cb9..1f3aa3da6 100644 --- a/montecarlo/econml_dml_te.py +++ b/montecarlo/dml_te_functions.py @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + from econml.dml import DMLCateEstimator, LinearDMLCateEstimator, SparseLinearDMLCateEstimator, ForestDMLCateEstimator import numpy as np from itertools import product @@ -8,11 +11,23 @@ import matplotlib from sklearn.model_selection import train_test_split -# Treatment effect function -def exp_te(x): - return np.exp(2*x[0]) - def instance_params(opts, seed): + """ + Generates the instance parameters for the following DGP from double machine + learning juypter notebook at + https://github.com/microsoft/EconML/blob/master/notebooks/Double%20Machine%20Learning%20Examples.ipynb: + + Parameters + ---------- + opts : dictionary + dgp-speific options from config file + seed : int + random seed for random data generation + + Returns + ------- + instance_params : dictionary of instance parameters for DGP + """ n_controls = opts['n_controls'] n_features = opts['n_features'] n_samples = opts['n_samples'] @@ -26,36 +41,61 @@ def instance_params(opts, seed): return instance_params def gen_data(opts, instance_params, seed): + """ + Implements the following DGP from + double machine learning jupyter notebook at + https://github.com/microsoft/EconML/blob/master/notebooks/Double%20Machine%20Learning%20Examples.ipynb: + + Y = T * Theta(X) + + epsilon, epsilon ~ N(0, 1) + T = + eta, eta ~ N(0, 1) + W ~ N(O, I_n_controls) + X ~ N(0, 1)^n_controls + + Parameters + ---------- + opts : dictionary + dgp-specific options from config file + instance_params : dictionary + instance parameters beta, gamma, etc. for DGP. These are + fixed for each time the DGP is run, so that each experiment uses the same instance + parameters but different Y, X, T, W. + seed : int + random seed for random data generation + + Returns + ------- + (X_test, Y_rain, T_train, X_train, W_train), expected_te : tuple consisting of + training and test data, and true_parameters. + X_test : test data to evaluate metohd on, n x n_features + Y_train : outcome data + T_train : treatment data + W_train : controls data + expected_te : true value of treatment effect + """ n_controls = opts['n_controls'] n_features = opts['n_features'] n_samples = opts['n_samples'] - # for k, v in instance_params.items(): - # locals()[k]=v support_Y = instance_params['support_Y'] coefs_Y = instance_params['coefs_Y'] support_T = instance_params['support_T'] coefs_T = instance_params['coefs_T'] - - # Outcome support - # support_Y = np.random.choice(np.arange(n_controls), size=support_size, replace=False) - # coefs_Y = np.random.uniform(0, 1, size=support_size) epsilon_sample = lambda n: np.random.uniform(-1, 1, size=n) - - # Treatment support - # support_T = support_Y - # coefs_T = np.random.uniform(0, 1, size=support_size) eta_sample = lambda n: np.random.uniform(-1, 1, size=n) # Generate controls, covariates, treatments, and outcomes W = np.random.normal(0, 1, size=(n_samples, n_controls)) X = np.random.uniform(0, 1, size=(n_samples, n_features)) + # Treatment effect function + def exp_te(x): + return np.exp(2*x[0]) + # Heterogenous treatment effects TE = np.array([exp_te(x) for x in X]) T = np.dot(W[:, support_T], coefs_T) + eta_sample(n_samples) Y = TE * T + np.dot(W[:, support_T], coefs_Y) + epsilon_sample(n_samples) Y_train, Y_val, T_train, T_val, X_train, X_val, W_train, W_val = train_test_split(Y, T, X, W, test_size=.2) - # why use train_test_split at all? + # why use train_test_split at all here? # Generate test data X_test = np.array(list(product(np.arange(0, 1, 0.01), repeat=n_features))) @@ -65,6 +105,25 @@ def gen_data(opts, instance_params, seed): return (X_test, Y_train, T_train, X_train, W_train), expected_te def linear_dml_fit(data, opts, seed): + """ + Trains the LinearDMLCateEstimator to predict the heterogenous treatment effects + + Parameters + ---------- + data : tuple + relevant data that comes from the data generating process + opts : dictionary + method-specific options + seed : int + random seed for random data generation + + Returns + ------- + (X_test, const_marginal_effect), (lb, ub) : tuple of HTE and confidence interval + X_test : Test data for use in plotting downstream + const_marginal_effect : desired treatment effect + (lb, ub) : tuple of confidence intervals for each data point in X_test + """ X_test, Y, T, X, W = data model_y = opts['model_y'] model_t = opts['model_t'] @@ -78,6 +137,25 @@ def linear_dml_fit(data, opts, seed): return (X_test, const_marginal_effect), (lb, ub) def sparse_linear_dml_poly_fit(data, opts, seed): + """ + Trains the SparseLinearDMLCateEstimator to predict the heterogenous treatment effects + + Parameters + ---------- + data : tuple + relevant data that comes from the data generating process + opts : dictionary + method-specific options + seed : int + random seed for random data generation + + Returns + ------- + (X_test, const_marginal_effect), (lb, ub) : tuple of HTE and confidence interval + X_test : Test data for use in plotting downstream + const_marginal_effect : desired treatment effect + (lb, ub) : tuple of confidence intervals for each data point in X_test + """ X_test, Y, T, X, W = data model_y = opts['model_y'] model_t = opts['model_t'] @@ -95,6 +173,25 @@ def sparse_linear_dml_poly_fit(data, opts, seed): return (X_test, const_marginal_effect), (lb, ub) def dml_poly_fit(data, opts ,seed): + """ + Trains the DMLCateEstimator to predict the heterogenous treatment effects + + Parameters + ---------- + data : tuple + relevant data that comes from the data generating process + opts : dictionary + method-specific options + seed : int + random seed for random data generation + + Returns + ------- + (X_test, const_marginal_effect), (lb, ub) : tuple of HTE and confidence interval + X_test : Test data for use in plotting downstream + const_marginal_effect : desired treatment effect + (lb, ub) : tuple of confidence intervals for each data point in X_test + """ X_test, Y, T, X, W = data model_y = opts['model_y'] model_t = opts['model_t'] @@ -114,6 +211,25 @@ def dml_poly_fit(data, opts ,seed): return (X_test, const_marginal_effect), (lb, ub) def forest_dml_fit(data, opts, seed): + """ + Trains the ForestDMLCateEstimator to predict the heterogenous treatment effects + + Parameters + ---------- + data : tuple + relevant data that comes from the data generating process + opts : dictionary + method-specific options + seed : int + random seed for random data generation + + Returns + ------- + (X_test, const_marginal_effect), (lb, ub) : tuple of HTE and confidence interval + X_test : Test data for use in plotting downstream + const_marginal_effect : desired treatment effect + (lb, ub) : tuple of confidence intervals for each data point in X_test + """ X_test, Y, T, X, W = data model_y = opts['model_y'] model_t = opts['model_t'] @@ -142,39 +258,7 @@ def forest_dml_fit(data, opts, seed): return (X_test, const_marginal_effect), (lb, ub) def main(): - opts = { - 'n_controls':30, - 'n_features':1, - 'n_samples':1000, - 'support_size':5 - } - method_opts = { - 'model_y': RandomForestRegressor(), - 'model_t': RandomForestRegressor(), - 'inference': 'statsmodels' - } - mc_opts = {'seed':123} - data, true_param = gen_data(opts, mc_opts) - X_test, Y_train, T_train, X_train, W_train = data - te_pred = linear_dml_fit(data, method_opts, mc_opts['seed']) - import pdb; pdb.set_trace() - print(te_pred[0][1]) - - # print(lb[0:5]) - # print(ub[0:5]) - # print(np.array(ub-lb)[0:5]) - # print(np.mean(np.array(ub-lb))) - - # def l2_error(x, y): return np.linalg.norm(x-y, ord=2) - # error = l2_error(X_train, te_pred) - # print(error) - # plt.figure(figsize=(10,6)) - # plt.plot(X_test, te_pred, label='DML default') - # plt.plot(X_test, true_param, 'b--', label='True effect') - # plt.ylabel('Treatment Effect') - # plt.xlabel('x') - # plt.legend() - # plt.show() + pass if __name__=="__main__": main() diff --git a/montecarlo/dml_te_test/results_seed123.jbl b/montecarlo/dml_te_test/results_seed123.jbl new file mode 100644 index 0000000000000000000000000000000000000000..d01932cdd92dd4eb2cb7a207031dfbaf0533ba63 GIT binary patch literal 40231 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 L`e_IjuLb`Dr4=sK literal 0 HcmV?d00001 diff --git a/montecarlo/example_plots/plot1_conf_length.png b/montecarlo/example_plots/plot1_conf_length.png new file mode 100644 index 0000000000000000000000000000000000000000..2b5891f0d4530644f573bf0b13f76e8a1787de65 GIT binary patch literal 32552 zcmeGEbyQYu^fe0KfMS7&NJuJ5C?%kD7$7JmAl)D>Al;#;+%yQ%C4z)>cXvy7N=SFd zS)1qgzVA8XJLCKJ`{!c}pWu$Y_jRpnt-0o$OV2lwBDhycucA;W+*hJPGAI07{cjGGArPcKN{=*ri6CM;wnEU$3!8Y8-r zP}*GgyDo;pK)u@2i)2607Z`}1;$Qf8M>O+ez~^m&pyEnF>YqB8pW4Jl=T7+W@J5Sm zJNPZ{Otlv$h2hjbx`7Wr{!?-Tgy;XYCxf~Lzu0(m)r}f{C|_c{5fT!rtEESIq0wkN zl8aA~_v8IU(Zj3LTDMTb@G_qdW*oeV_K^PnfB63g3npN#_VMc-78bnUeT&-`_wL_D3%Et9(L~SU;SBNLzSO@#Pu`X*~#fL9-gg??;_pBr*v7$>57a*Ng;-8;mf*Y zU#EI=>I45DpGZ!R7V&rc|GL3JPgT?6<3D+Mc}?t$=j5$k?$Gk~P`wN<+}m+UI&N)TTAI(dZ#OZq zu$Hp);1e(W-PD?l@^9X_v0hpei%vp5df`IRJ0=Ny{FG?SxN8sgJ)`)Y%hBi}|Nk9- z!In3Pi5rt*U6cpoP1Sk~IGFbQlGt7u8EAi!s-~<=YHn^`S6?3( z5b$)Qz~uHLO;k^kR8m$}*VM4|&zJb{Jp@vG(m$grPj@nfgoRm+dg(ouqz15)-cM9S z3!WWxS}pc^5-}-%7}5>h*q`ywHJhl&J;l+tq=F-&FN=bEAtaQWZ?z`*sula_203}# zFNsLSN*8{y5Js(qt{;r5MFE1xQ+V(6^mxixI5Gt-%J zJ=XP10D%UoX!m*dFAxy>aDWyu6@><7=vr|XY;#nf)g7>cqO~=9>X<;TNChl%|6ERH> z8)wqc(0u8L=4H3|D{5h3u{^JksV<(RwcBxsntrXrv4?x>TUjQM!l7jW7TUTaoApXhTQh?W^4EpyZAKl}%E`Gc{-!O_Q_D=ObUe^mPV(Ri zQ&1m}GYq(e8f$ul#cgB8ej@52`((TJ#ZCFUPQlmcwLN z2=>PtX)B^jHSa4o$^H?Pl{U*Zqf1{PZ(H$|f+|H!G(J@+*A?cp* zC2lMw2XmyhFm`9Q((EiCqU@BP>i9VNt+E8Nf(q*PG$@@$zeI>#az48N`E+Ggodz7! ziUYmX$}<;~a-Ko;#OW@lY59)4y4}>p9vy{ZvV6Fw!RCMqeZceJ}A9?kQe%4PrK@v+l;4l>m3+qV-E5(Xy* zvUM7BGkQ|gJ2f(y28zse4)@kNKV7``2*=&!S zib~ynmN4S6;q#X-v2Dlg^?e(oF)%Rn)so5`_imDti`&`R`C7VP!kbG;ior}~m0W)h zabM%&Z#q^Iy;}k)hgLGG>GKtWh5mH1j~_p_g|WIzL~=xDJ4Lp?Z1khBpZ%_26lL6< z(9AucAe2x+pZ|8F#kLWns6>uLZRXQr(M#M=%s8@e@n4n>w~W~$S?&AQVx4%b7OFDT zN=0A4PTe{77d#a;HDz`^S<>+I_QukL!#!`^85KoN#G>BTr=Z~*s?e^L;e524e`$#! zqi8y+b*(1}&zFo-ufgYbTMU0`!@;Ldn9pClP%1Q~fa9(^n5DIA>2aOHqNsmhps<0f z{yGIumeoHQfFzf%Ul*7^^hEb6rKtd3RoE_2lrv==wRKJ$4WypD^DZlV_jp4inyGdo$Y6QIg5@~ONa7}iCN0G zyOl!CNU)WZlt{il)6%+2#_@jgyMp@N`}aT7#X9Bm@7Xyz=4#hpJ&Ki@w=zL8F%$|Z zO1nvnuef9l>r=I_UcaV>43H=m`YkZ9+UGXA!FU<>HDcy>kVfv`zn=xCy5RlL^XJb$ zm6z@B+sUUXR*#oE8jcpRR##V#TC_4D8wB|-6f%5NSQrT#8yk{s?bfR=dHVYDFYQ8c zWa+11n)Y_S80OaK&~QUDV}jxiG0(-PDSZ)7jEfEze^aQFJvQj#4(%y0QGxnZ_qREy zcs4`@!db69!W^C#v(Nu=l2mMmH%mp+Qf8$j9F1@&7JCrfO5Zi!z7;YudPp1O2{i~x zNi)=$2Isvo+lKMn+OUHXXom*YgevZIT)MeF~NyDrUl3mm66`Lw}j_jyrKh zhvv#3?VHb?!);6~oyv_h5<8SkOgJJveYTfH+LSLLn0T=*r~G0Xzp{@%@$qc;V9!@U zbLRXUK*7D9J~glP%(yVB#-i^T{u#73?)SQPj+@PS#lBbfn)yph>vpm7xRJ5&6h2X! zJ^l|{kF<}3)K-jId~zzcOVh_uuT(D5P!&6e-=m8j1c{7?Q}(v%-%`h5M|(^M#z_q@sF} z(k(^XJQ6Av0v#6b9#bl7(evx5n!1{Do4s$t)>JgQ&y@dHEE>82|G`bHzwK+$fmHJq#u zcI5yrA%`MZ4C+2bhM*en(;coTsH~9~Sl9tkQBVdgwvB+;&+Kpr%Hh zot$21^kRH`Wqm4;k~J(3o@Fa#>1xxL`O~AdM(ynNZZVcWX-e!lxw%UDMuZ0k2h62O z_1e|%ZC2P&zNAm$0Rb|XHx4DIrPU1#5WD?&;lTzaijnAAczC$e;lCsw64p;6W|h&d z$1_yd*SvjwX_%ON;TeWCj<$QGuHfMC%~wW>P&o%f_6uvIbo4lI zOf|2s96gk2AZ-(fpWw>3o7GXsA^llqCq5GU$rSHN|p+ zUyQq+IiGIDo~M$yDDUpb** zw!@L2b73VO6H19wPlBN(>QU#^ zZMl_Ey2=y6q|(4tI9k&bcyB0I-~RoC0+2&#<_@7f zJ*VITItQDxK9u|s2x3Fl`zTF0-;3XIcO6nctA0lmd%q#T&(B}JY&6rwa+Qr|>xjUT zFZ-j}+1M0IZI}wj9hSJA=Kx*x&_6M_}=X+84T{(5Xk@NOj z`P){$xPJ?5Bo<3vZ(eh_u>6ux4%@xQru3x3&|P+YkGph(NI*b9JXRpue5PSzcf_ox z!r2izi)snZF(H6}D+9PBkKAA_3EYr3>{FOHE^udb_*_P zd9+e^7W1oGFPGK%(5j}kHd~Pq2|!rVt8U%hGDsSLE_AHK8Y>R!ozvOL9H1`KTO_By zidp&hgRS`hWw>{#Cs&${-?$Ot;UvCob zY$>a=R35VdK+ijiehj!Cffi6{H$p3qXQLJ$Qt!y_IJkzBGvwUBpR7$5)5-4}x%f-{ zLKWY{Q1&a%?dN-|V=MExwVKtR zE;_+}A}vBxR2y;vA%Ij*0+|g4G+g;lj`s9nLEaB$eVlC#WrtP-y4)H7&luzlKcaa~ zr#z^Z8v&x<&DCq4hF=E<2fvY%6Mpk1pw=ARBA4+eOuT5&z~=NI0y?1n{U3`*%d0aUHes576tH{ zs|-p-7evm{#%Qsn{aX1Rm%}#w?CdNQg5iAQ`SloYNQ7xM6J`j0vYYxs%w@H3V{5*1 zzIZ-{cb*NWmg_ghAU8L+csSb^v&xeY0KKWHsnEm$OEcrMHd12Epi=POd|?B?eQ;=~ zti1f(W;P_9J%Q2hjf=Iy`*zhutuv2T*D&9*U{1o_BgxHhD2GN)P7c{`q^Llynp)F1 z;&~4DJqMwv4Y6RgHXd!g)Q`knjN>Zzx1b;l#hiCnsGPU)@4fW7LreP=K~u=5Axk#X z1YJBXlSsgoTPztEO=UWmwtBGyXmTrSir!fG!!@ZlJ!)&xEMANv<6Sw60U@MWEdb&2_{^sHYLNi`{%V|AUeLfTC|GHk`WxLVSZdK?r=vrJ z+OzSDw-y?cstAf$tS700B5YYts1N{T(bil$(mBAkE>BdR<*gk+?O7Piz6Yo6J~Ol5 zN32Ugc{mCjF5HVd6ih+tKm5v~nI<$KEUXDiKuU6QmLR4TM^N+UO8?RQzTBLgrp`{=1zpz2_B@l35a|BQ`{We*=zFxYxwc&(Y#ck^zEJ9+hnDIRrJWn^ zYLPpz0yl2ms)L#fC;e+}!bd#8;{eHM9&=c*T)Pcz4zuw#2xAOrPO0zRbBCzyN|B|j z0J@2kfYd10eC8#PAi}W%&Vc1LVHf_+%?&%gZ}hoc3tckwm%o52c`GlUW4$E5xwU0K z`SH^7EV+PF7}8e;M+XO6b(rA8^|A2ys&YF8yxaADI_|APy32(`j){p`1S#I||E=e< z=&!xp(%RbG(o$oT|1CTm3anENl<LCMukVp#0oEJE{FQGSxt4mdC=$ z4zwgfrUlVT3>I6`vFmrd18fD*^2uYf@hHGEf8gl=jo6(Y%o}ePH8wWp8udM7uGrUx z=Jv|9YdYHte?~1k`GKip)2u?3m6bu|xg>bHe@}{Uqwe<7=$i^Z<_k%~GA4@-MoUKW zk=4Owe&*0tIH6hmx6$T@ctG{er`Te2J;Ff%sW7pcRYOcHP$)GuHRS5ou3gK`47FL@ z>*{*rVGKvtQ=lYYAoy>A#98JWsQz&KPib>|&9NIN112J{p>R+_!Z(qZj-U-76q zfIzih_~8L$H4Zsf0Me*KZQb;VB}}dSSPpO&fwYi=Zc#+Khcbv*tN=`wo9=erwhQTF7u{B*MTo_uR9EiGTFroVga z;o^|sg2Kb?CB>dK7t5;DwqRWpKiMTgN$q+jiPWscM%mJK7#UMh#rD{Y+j%+kVeJE~ z%hjsI29|3-QcUAGr*JJ8*rX%ZM@bHswzjq?Fek%L3D_drlU4$^dRZLs^}7cGw{Cy^ zVPj1oWwLZqJX^LoW{$$nH?E=Cc*bmYNy@}nKb81i4nP^W%QUsp5LoMBt@i95=zGlv z^HHgxNusY(V!n_O5(+CSk^uRaA6uxLzC4)i-k+|*yN3mNywZOq%< ztnnGY@9U=kq=NQf3t7WK9sfVc()S?2GYj`v_ok%8+YDQJK6viuo2SR{-irz zQ&SWCQ$Q0?&u+FHFeytJr5zOwlK`OYcls1Iwzhs}qcXT!nwkvW_`3=V{T)>@!9Lrk zbtkANig#~2PE=qVSC5F2*68&Xse&d5YjQ|G*4oaw4vnvBUQhURCqBP2imafmZ+H6JszG2Xpe{VgE2>~dL$qhvKjX?g1BSQmr4kmYuikUh=;h%OJtH+J3WSjfnDkGto7z}A5Sz6jhu1gsyGU`DnK z^PH#2$xw{bX)ZH?8=YgLxu-X+^KnG(@bG&M$K(3}4jY#hfreqm8IcO!oLKu^JJBVH zZ+gvjTJ@?MvyBliD?T^Bb2PdakIsw1ej_PbfZ3R+EzU+?J@5rH@|IgSZakHi4m`Ca z;06--rL^=P?v+qR>Qx1!6zy&=9IuC|21A3fB93(iB7P2O>f)FwnNFae;ou|`746%W zPYetUX#L79@;jHhma3|r9!WA$TTG=K8b%hrxJdZ<$Z_jkEZ4D9ugBZif4mvq2mAZS z86Q_-xRQ%9lGDdTOqgWOpmA>7p&PU-yP#o4Fq4UfQf@;?(!pvX%S|8BuJQ&gFI` z8kiD!qhjufh&((!C7HfcxNE?w$3if3R2M|Ds4&oXllc5|8y^fuB!>qM$;KGI+DH#a zWdD#wq~i@us+E?RauaUU=tTO1@|&H`dk<4w&mVxV7moU|*~t~uS1a`7VgHo1>OFJf z^T)=^yZbZDHJ$r<)y@MgoYk%bKjZtW3Fo(bx*X2yaW6z}W`MYjK!7htaV z^vdUhqh9O$znGwAQd4)Mq8anodx`s|GJ)Nm&lFF1c0VZg0V3Z&zEi9#A9Fa}BsJCP0Ux{bP;^R)-0+SY8ZC+yC~KruBgO9; zh#|n|s!J{5?zB{*Y=LpUTZWL+9Jp&dwZ8}+n4GV}&ge!wJgIruvJAtYXL_gog3|uZ zvp(m~xtRU)BBA*H=4H6r^mC^Jm9q=&yWc0yH$+B?qK#qxU#8!iH|oNn9Pf7n( z+8mf1D!}^5;GKl2HNd94kum%!Ttr21L~|ovIA)fy&)f9@ug&rue*S0x*#V)Ujet@9 zjh7!8X1YR_Q!2L5^&Oa*nF$9T0R`=s{#4DE>+>&OyZ~D8mn8!W1mn9%|Iqcl?;{TBK*Yo4RMUPsL-R z+`<&t&7C*pm)+)kll0%C|MAos5SRIi;)6)8?j z`o!qnSuT6@!_J}E*AkFgrBzD(Aw!M+>Hn&gweAsAmd{P*_FMTY+w?b*vU0wqHHEW` z=%ngPRb^#-2r&NXFR-}oU}1r<0rvrW0gOW^wit)S2XL*IA3l6Y*JV;K8`K)r{13Th z;4?-);Ncn8)%CsywEB5wTM@`GGLF=GwDOxj;pEoo=^%fghhyRP!i@yif%#0h7$JlF z4H6PXo$e+Ust0tmw9u~9-1FzFY5C3oGW^qYU0iamuBp)!mWt)&_i6IKWtU9Y!qI+y zwCwBzwU45d3%F$ddoHjy%(N5~yd4UwI3)Rfoe<-LM&Yl~u$!WKdcS1XWHq>cBc=z{ zVS8Ds#|tO}671GcmU%!^jg9kdRDD1>*3}6?xp5gbh89ZCa>d)YWRWaQi{x-_h4%lf zUes7W&37o**4Qdi!P7Gr{das4ZMSZmILEsVbacff;jTb!Z)+1j+*#U-98hK?0!9Qe zTD)k70wu{(T34eXDA?9dkob6WWBOmkm2Fc>nSs7<*a_;}sF2W5UMpLDU0sC!`}FA( zfP={~+X)&(C8ly2oO0H1-XVnDzE4ZrPj9(8T5Pq{?~6tQY`vNxlo2C5Q?>TNZG4R?%GJ40SZFr=$N1RO@w}Y%ek7>>F0LF{{o~VBr*a9te)g}e z5r)4qi#*QNkI0p_hqGTY+3Ay$smlWKpfUxHCP>2~@uAOOCu16k>~yW{tTS>?_#hZl zLLGxfwQm#tXN)q(`rWSCe@NhzLq~-iSH59(Y}Z)qayoa_xbx(vnie7Yg%x-r=S2o@Y(wyuEkaEH2K$kTrds%J#)FNlF?o4Or*b)t*0CQ4{geroGA7 z6-EyCFim#Av~;Y!nUD+O&x_gnkcVXK1Ns|7h*)-Z{T?6g>nQ zTzb$lhn%3#n|GqW;)*)y8XfVC^D0Rw6>NQ^x>hL?iNhM{+ zJhVbTc~Wxs%X?HTFI8nung%A)c1{vp&e6&NE}=XbC|J`${Cx!c${f4%8?D-&SNiX1 zq{N;tQpe;|b#5efet!9m8Xf(`YHRIPm8Mi7g&&XG_H`TGQ;pCwF%xNO}b@saSRnU)7%1P|Dw+!I6>WDi#!?+y*t-e=_?fS_}Q; z$p}XqpFf1iaD-9~!vqE0@4Bm1xaqaUrIzkAmoN08%$6!={4+yM=_?a?vygq_z2qg#Rn?soYYw&_ao{atYNB)92(2y%WeyC zi|T^DI|Rsf1!6Zm!U>_G|GR@rN1vKErTZz8*{ChR4?kjxVKWF)mhJN3GY1ErOV`Q4 z-sTT3jBYSB^r)ZJ;t4)N`twZ4V$sn19&JFcD*{|Pon%xTFoa-B`s*|6g>L$?Vkb?L zncn(tOUiMd_RG=6It^={(X>Y66N2KbUT>75wDdEe^Ztz#vdAV$@-OXyz%K?oz@Yz& z=g*g2f%xPE&HpAMi~)&*h;jdVlD2>@35<$b?mYyQZVdet)p8q+iOTiwa@YWMZ2_Ln z75L^ydWbUpA0QAlK}<^eT2pgHhaVvZd2E)OfWE{a;reg~fXyV7U2WhH=H)c-@y%n^ zxOK})ID%dr5TYPSY6|TcXn%5ED$=7S&VWU6%>)`mD_arm?>`@+V)_GEwp~kv`-M)| zwx|N0!wKl^B&JU7Y|U)N(I!Muk_(9mj2IYU=o))AbiHNs8(66{m;Br@Muf8*S{JU0@$T zL5B(?lBJynw7Q_8CNbFpWdhE&E|(}E7D1@;^zpH3zl0J0^QW5p|E}Al+A3sUtLb

8rxsB7RbCJ{|EKpCZ@NhbIh5wYBl>8E1FC$ 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 literal 0 HcmV?d00001 diff --git a/montecarlo/example_plots/plot1_coverage.png b/montecarlo/example_plots/plot1_coverage.png new file mode 100644 index 0000000000000000000000000000000000000000..44874bc0b71f6a20d03c32e7a5d63c065b885cf6 GIT binary patch literal 28491 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 QMc~iy$O*kd9qXX~15$$NDgXcg literal 0 HcmV?d00001 diff --git a/montecarlo/example_plots/plot1_rmse.png b/montecarlo/example_plots/plot1_rmse.png new file mode 100644 index 0000000000000000000000000000000000000000..adc164971c0d94aed4dc7d75ea7eb261e1760c75 GIT binary patch literal 33703 zcmeFZcR1GZ`#yZzD`byElVm5dm5~t{Wp6S<*(>8li4e)o%!sm+WZo!y6(O0~d++&N zZ$97e_xF3&zt2BU$Kg=-{a&weUDtV?=lSlH>U}vm;S{kP!ZO5k3lne-qiu>o}oMl;WB5?mSytQmft`i3n~9@2 z>WPW7y{(1ZSz>9e%p+& z=k`suM5pVQISOiAxkTwsjjEd2nC;e%fgSW>za?{wkcfzVH76v~9&UQzR`8ndk-53U z-p1p)@86%~D#={2pP??Ko1B<9OH1pj^H1f9Dx9jV9jDdXMNJV=$Budy;h!S^Yj#>z z=7-z=>`UrL;wlh4d)rvsrH1%_FE%Lii*LFJ|)&YroYl;VGhbtL_N1SN$9w* z2nv4H7Rc2u@*l9nBrPo14tuRDYv$?JpR=pHBO`-L#j5mejhy|`r7>AzUv*B5B%asK ziixSI>CQx?%FGBx^3|(XgYM(6;g-M5Qb^AU{w%dKqNJjFJn)sPQ+%7rvLn#}BY{5h zdbYKo@Eo7?+umFbgZQ(Xj~_o?>g&tZk%pPf(acM;>`eaA*jW5@NaVtDogbrswSA9< zmKw&#d#QY$o0eO@X|_AdW3`@6e9mgPQkajAkJF(1_u*hy=Dm*^IkfHX1UMYYKY#x0 zKK6=jrZ?|g_Xp*4r|FL0`34ESd3x&y>z$ENQMk9CKIK-C*uBzc;C3FKTOWP6S-IXJ zx-?!1Pt}$r8f)GfQzmx<9t-ETqvH*7u@#i^yPNMHcYhf4T&`l0@cPyy5F8ZclJ8

6I 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

%UvSG9IocJgCXjElC4-R6o3Ibi79g zf%D^^J=9iwo`+irPGv9e6mPq4iWBpDs^YW|=*j*Sgq9Qn?S|`u_AvU``<;MIgG--5 z<9WBiJCUpy($?*{o{)>uFHyX3K=s}n$I;<38ksRHk95Ob=-d8a(2}q-#~@!gN-jH# zct8MTYvwVc0Nz|?V+%x<`p+M2R5(Qi?DVAR6m&9tMB@vy4E-N7a!*JA?!tKh3;AFR ze0uoNzk4>r2;-A$SjE`1KWW?&#g612z)#q!S@+Ki+Wx88U&g2a-h%D=5Ad@iOTqsR zU$@syOiWJD>H`ejxV=zNc=&Wv#AQ6gb2qKd7F)EZ!POzq1D_6+m+fmkBp_qDz{j`x zb^ual^SFb$IwkZqCX0VdkbJSUod<9TdQW@1Z2;`N&o->KQxuX!T<8II!-`x|5nGih zvZjfsG2TkXpfalOAMXW^;MTOlwlP|1<-x2#!a~qMMJv0&(~3pGa<}CU*b)e;G4fi) z1FT_D_k!pQ<4wXEGiKeRaVX#wEIc}&U$_l>1U@GqcZ7!A(aGtfc2QcR1e6x$f0+uA ztj=@4Uo8z)bZ6e9D|eo)dr~@d7kYhR*9CgX;{$$Z<1!jQ?m-^}h=zN=xS_t@dBtP-+R z3OF3V))?Q|v||}^R~;Q4!<2dUOXeYb_*;vpo5!88*n%ilHa32zDJ6i$Dypig5nB!- zNzmwXwmKR;REnbD!C<)*8#Z2m6U|+71JzVEdvM-zt_chmnP7$?zY}pof$JzNyqwB88Q{W0hStOIE zlRd*=Z&ETdcL3CcPH|mUa=w0IYRYl6221y=tCMg{{kS;H+KO(O<0N;votjTrhSi$q z$K+=z&%6WF!){M05R%q^(pygRepqnt{%!o*(6&Hws0ARJt&uYmsZ7VIT?5ZF7(PBe zuAr!x22EzbQ=>mtat@8YErI$6EJ{X?e`iy)#&9{Ilc8J;dlSBb51QPO6wTa|K z!1-H}3kKOQ;WGaI{)3$YPyR+ZPPRn6eJce}hs3+!^|@P)?E-zgjuZ0RPLhWkk&O;K z8#-LA*T3|ZIZeNfh`0l&S=_L7WDBbNRDQ+MScDw&d#~NKrLuRmwY33Hk4N^lmpcI< zby}u)YhK7;FcWf_qlQKySFbb-Qsp*Htz03@f9Ar>91Y|!`YXi{z?78_c z*U9c=UPjET=}PBss&an0T?d)fYxLaRc4Kf6zh`vQ)!rY7zF_VRR%AI`!4 z$T9xf(LeqMUiTH_qqSI!d*WDYUzQ3BOzosk;_*3oYisNGT0$0}2;bqGZn{;kvrInZG3*(9+uul}Cq$o`GkXl<4roAs`N|sc&qoI1VMwxrph5;9Z(- ziRNg8hRS`ZY}#HV>5ENYSX-Nt;L|~QZEbp(zYIvXNdAN|oTZ~{JlI{|h1&WmB&1@- zGN5v~3~-qf^zn|4j`9i$CQucX;%@{<9{eNM_gpMt-iO#2a~3IscBcR9lXGy94f^Pg z=H^u(_PoDs_Ug?JRonuAH3noKLQ_4=(R>a3#tripYM>Bnxk?A60Di>tTaqCS)bEcE zkVZ0!$7tAq;I^$Tr;*R@)jYjYfVELDjP*Ze;SNBxojreExxlarSPW>Co*PuSB4EL2 zWnV;8bl@<=UthTOb5K|q>(#57+I0R3s~`KcSl!HqWnKDR<_y-Bec#Tx*xRq*5!hkN z-o~#Xrn$b-!cpKZR_e9u=(F>W0GZ@)qD2fHC8cBS?!BWmX%=SY`}4hd@qmOOQtD=% z)q$~id4{3xa=6&o@KQ5d%A{g}~J{iY`}518RUeAa;DP?mXX1>I>Cb^}Q4xt4eYkv~tK2y=D{`gTP%E z>VTb3!sH2PFt#VW$gGi)hNeD4A#!InDXswRqfe#7`gR(kd9PVklImhI6t`Z#uU)Oc)s9O+>V%AK*+ z@|OUJZ~`(-1&DXB+lijCL+>Xvt|p_8JhnB4fBpJ}MC`ez-~6BpMUddI&;An#oNQ=( z{K}#NR%27ryRIC^>a9v_?yXH2VcGWBs81ZhGIiYW>8b@J0nIk{#9{hjpyYuc6g0IW zQ(1_GI6#t(;Vjet0$I47kA#q&k`MsghY-fo3XU-7FYi|=1bJ5qTl&Y$|SP$v*i?;nIYgRG*Mc4Jcs+|=! zMXp?tx$Nsor>efSJhIF;2BhT~6jGXJex)mbG{D8xp1%gI?gS=oUF(>V4&A)McD2PcC6#{L9YlW}!=tQaX2)QPd-4zeVh!l*_)yOI=Lg&jThq zs572F-hRV)7>5hB=ycM(j(P68J?B$RXVuKS?y5y)e?rOsnD)UOgzO|^r^Zf>+*gv} zR+419apTI_{Uk`WXVL0n%pFkpop3A(W4g53+(?FpntM2SWMJku71}#I~X{ zz*~@ojQb)mFfu;gLuWtm<;%B-(4g^OLIXhjB~O76d6dvMa!1DtX_WdJtxML}Z;u)_ zKaY-%ww71;X~t}y-~8+L+lIn#gbQVWA&N2Y*HiNCIuSTlKSJj%a%jVH(zUNLjJE`= zU-s2}ZXu{e_3d;ZZe%Pka`{y+o*A3_YoJ`Ce$vFJ@Ok<)?WY-1amu}^s>kI$Jw5&a zWhG!`?R3>o`9u)&s{5w@28|`}jdxr0genNKJ2;?9l)#&8kxqIBbM^D|7Hos-$CT$x z9h6WGdLwRv3>f9OC< zPMtb{Dpn)ahj^s`TA|=>o3(zE|3u6~gh0G_agXie63TP` z2)W93(ID`tp>UCg5(dNo9YyqYjq*`f1ONy8{iY zo|UmoALGA$_fGNt{rj(a&2?xY@n&RX7>Ba|`rj|S^(ge>_C6^pG3?c}lB46R^A#D- z&NDGB^wcJNzL1JD3amat8Kd{QQ>=!{H?NkG6A@j!awX$uU*)E>UFa{PYZ7Vy%cwot zex-~)#DDS9bgq|xXG5l{+7TfVlEv?V^0vPUoNo(s`q1KBQd3iFOB9X-EW8fwHIB!> z<-F2i)18%nH?4m90%}1)DIy{vDW2qq6d2`VvE5tALwU~3!1$-k!t^aHdk_Etln)=e zH-s{voM*cN069e_C*RlAeYd{}v`Q%SM2L_CX@014+Kva-wLWXos0ANGatc}Jo! zzY)`u|MCLRc^zV;hoEWD;?cSS^1F5@2c0WBDhBUAyk)~b9D7!(7A@Z$d{?c@bnj0> z_iEk3;M;B4=N8&`?rhOsraPrD;nTJX)DP>yt|`R{^^@3}2xiEl+Im7jjcUa{iM=vM z$tC{<+o0StCDsE5uk}x}g?wZ#MGpFJ4!*QeK{HEXlmKJLN0 zU>LGtfMLdnE;YE?0>hI-`rPBK=LIiG09$l>Lpi<)I?Fe~+-6~N@j)-U`y)VmpzKT7gjAX&40p)MlTe2UN5;Dm)3+aUUaKZ{lm^v7t(ootKr_T}*Zxne^;Og?09ce{6$L_Ch>ItIdKV06 z+`usffRoci69w=mQqVP(?M@|lKP&=LoZ+)K6-skmP>}A@)mpo||0{hL@%4DK&&Xpo zGZrLNJ|G;y9T4a?;vH*;IqYqX21-4OtAW0ae7f)0=I`Gr>x?Tq?S#f4QdsqTnsK6x z;W4`Z@F6wGiv$;-aRr7O(OjTS6XDT-gsF~yUYL+AOxj8~d*t_$bp|eSvcuv~MJy1P z?qY60Y_5Zr`!+Jt>;a;@WQOlvT;AY$t!o_c;*VZv6d@#G&U}b@kklqt^)nTto7&qa zA#fi87Oer|f-0+f*2h+d7Wiy?w87i8aILP!Xn!z1oaDx>q}wwtJ}Bp#c4qU_XI>cY zE7suOzP3a9D3pC;*X#e1VavDkUj~PTZT&5(kNj`f#&|)MYf{I=42YZhJ)5-tHoafU zE*&qH@Zi~^a`nq@FfcGMcOqg)YU%~36WTLC2X4Fv%(~RLdxuXzpyY?jIlUNJXXl&j z?CeX%*N5N#cT(K(ECBWW_ETu8O(EVB-?5r*|@>{f_Qt!obBSb7H&2IF#&?(}B^kKHQG0Um< zH58W1ez|Jfnus1u7+#XcxU-Kzry+d@&?f4_|D;(uFK=Lo@RDu7_yJpQnDd^DOh#J^ z%VD|+f9_95ND)_C?CxWM8YbWD2wKpPRCB#zBC)mBa#NlCvq zajM9n;5kK9)jGYD z#aBCQvkQXEIo2)}trR?`sA$Btrw8MAiXc(E!oqQj2m*M=f!gCgNfph-Xu3pUQku&b z-un&p1ks&5J0Z$KZ+MMIvsmyX!%^6s!d+AwKufD#I!x9{_Kf>YEiZ9~j6kzn(>3<8 zAsAjDj+W|EKK9{q<_JaXm%>ti63wDkx`MZC^66 zJq&;O&H;*;#7T*v9Btd4$12n{3^CUc)Vf@K`eBXI(xa82_stUIf*HuOQf8}%)f6iQ=BUOX`UE&ENCL=$^shIV=A~ z?oouh12fPSaq;uMv4+oHfvW^@DCmB%s(pQH*vcsYrsSwGQ7Mqc4ac}d6?Nw3*Dw?) zO);e-J_$g%AMG?sKC6VtssT#+$tNWlnID*Vu5&f?*$>EbtfPh|gTnh6QIbbHW>3HU z!#}YjUG|3ln@QO5$A=bpoP&gZ$D<_{-2>qZa9}u-uvBB%c@pnD)B4~?78ZNoEJCPdUt`V4(mC z*zPxAdZ9K`^6LZSDjUgKe)TnkgaZEvnq= zHNqq#?hgbU19>ajN(Crdl=aqj=`K1izqpLCC?pSy7o;F_PL9bt%BdG1^;Ew;mF%VXWev^@zNx{I-T+(OQidX?iNvj6K!84)$DSmk^M!Og` z8x8d%CjnEs0UYD%nHj6J^mHsxD7jq;^@=S>0i}-vtC4Q<{iPRBBnKcwSb|$jMwUi@ zWM;kqV*$d5*v{y41Sw8TJVF=*)Jt*}pZXLz$Shy@xalm`A$sx#2J~P5Y3_YcW7C^! z(*N0fsS%PhqVOP02<)|L?baGj;NL+V_yw%(_KXn}xz<=79_M|aVt*EzNQ=14$pFV< z)&Kb_bTbo;Ea=Ly&Z{tx>*oha7#dUc@vH{BmaKo=g`LI?!p_zrdY^QnYI}Gb3hdys z`8-6_IDY7>1eLMV}x9m zP6G8>G0zPC!Y)PcPSSyR<6GHXt@qW|1SnesE9;h67rC#FUBasYRbtGs42&Re8`q&F zxpet*`cH2W*M%nVV|V~7h(by+7-6{2UP9Y}eASk4tMgC@j2A$^eZ(u7EZe$>T=f1 zD5lfyik+iMP>wuef8B(T?BZoXKdRlBJT}1|m-5)5Cwj=H7hV^#ajZ zVfJ8m6V(6^8~V4R4s+%p#DsTu|9+y7n(;&45iq084wmu5;u54na6vkYK_AW=Z7dGZ z1*VT~G$FNJN{U$A@YT^zBPa1(?I7VV;e)dL4rjazC&IYs0J!v^J@%>o^Ms34u1|C$ zw`IFERr94j=5MMidKR=|>+xVe?#n+9BG*{7mf=58KS0_iTk1n}8x1W3jf`VorRvP;A&O%I?W9M2Nh3wBXiEi3d>%LTwuyvA!o!wg&i~cp% z>EDiJ4<0l`eTs^rhB){ELg7E3MKJKB1Dhx-0j+G+4j2k`${erCg)y0cSPoI|(5-w6 zix*5Q79EMR!`0AeAwE9b4@7E`KGczd#!i)l02PH|hlXU{87KQb^mnOKMBvKD#G(xv=bB94* zE9+d%%FOf#-PxS)BX9kT$UVRYvfa4x7UUs&Fgh9>5nMNkUiOZPBF!;reb%=0M4L2( zIS350Yw_(K>FAqQFKH+q+wrMik9rr7dQU2xSsaKux%UN!n+51icP4Nmfzm?HYwSyY zy+Z7wgG*8Qp#Sa|mA=zR{c0PBcBZj2RIC=-?O7wPBhKl5W)wM-Pz`j?3d+ix+GgZy z`CAO4uDQz5(PUu*%a`01>FljoEDp7_`-Y6&6ky(8#)X=#m<_-C*4y*$n9T!r9l~z| zJ{KeleBRU~@Bdu9^_Nt*v8-mpTt7?ksCb({LtO7-QOoF9(xpqLEKF#9tlWfQQ25_ej#&lkJ~94rt3Ipp6~6|yPXgGQ9A|!B z6m7jm#TkgxShF4?jjm#H+F(oIprnZC>hRtxRhCQOi0EqQ74{`%yqO9le&~787{qWV zL<4OAm~jg~mUlH;|2(5>K#+i`7g!#_J)A9YjfKuVGwS|vOZ^`a?48v{mUZ}{Vqj2! zwE8M2Xk|ym35UdS;~d$YJ1gJa;#jI-s$fK!&U;$i4ZRdKnfGG5N^G>2Fvmyg4*Mma zYsx>-YW5BArf}5>EE_N>>zWGtFK`2VRb)syiVi6fa7hBYAZ$kV1DePlo3k%8UZe-| z=4kyf2!oF5hR7jDtf|eKHK=Y7Aw|V6ZZs2z*OYsoMNN&9^XgdI=F7vSsNhofiUd$l zmaC9pfiQgoosuQHd6>)hJk@mCL=it7k-jBIsBP4I=ho@ay|YH_iFr<_W3WF&CM2|i zE6(3sCyGOBh1L=jnbP;4yE=)|9r3LGR z0_gpV*VC1XIY}B*CCBzs8u=2cYZr$6G=Ky!hiQJ@)=+?DaL7StIlxo{!rSNKV(^$& z8eHAM;{e3m{TlVn0`uIV>}2>0reTNg+%^l$O$@r5;a=3mo0r~z-vhCAir!lx=}nS; z?}aDyg?xSSIv{NdiiEh$({R-&dskI2|Ixw*wa}eKj+A&H(hflEfwwJ!LB$F`p6JSL zx~^SHhFilK=O^seI|b0|2N?t%N_#QC6n6WfEe14D5KY>W^mf!)L0s4}S1^xp8DESm zkO=r<#GBI5SZPKF)9Tm1B4E+!T5%69X9T3X`hyEMsdLOlD{>-k z+{XIZsqL_;-8X`3r9)28& zOtv99q~HE%7y}zrHUl*im>Z<1U4@TjOj{Y)EMkU~fiVHkuisydpQR;J)&qVjih|hJ zr)AFdoIVW>8$a)HyxGZxt}ca0>blhs6BU&)vIDtv7)8V6Z#GJZYMTz>#T=X#lrE(( zs^Z6_sofZLF=F4NTn{~~UPebp`}TNiHvz~IT|R$sEpNP6r?L9e2IRpRHPnXLlDUb$ zzwtbN+gIh2puXBv;!5-8)}AHAAJ^R$Y8aNKY@?|Q=DZMwQz@()S=o#$aozESF5)Q7 z{io1(0B2>4Dtvklmm+#JHa#x--U2tELq*^IZ*cPqAILQID~BfK8PZYosN6#P+-fwc zhBG-pIN~WXe8tg1<;Dkkhc>aJvw{tTym)Rs-+w zHa@;Nj?c^rk|HSCi0cIC{l3zGfttBqpzHqqCTdF~Uqsd_xJjs(?;HjnvU7f@Q7CF^ zVqyhoB**C_w`XD_AOpBA4;#!#fLAfi=WtIcNhBI<29%KP;gQS0g6AMa+*yy1N9&~l zQCzKQ;DlT%xTk)!s<`(Jr73@H&_y!;Ri|0?4!QG^AI*cTA0t`0D;5R+#R~0w?z0%U zE9AuZNybFLn!+Aky;sdG>_dT4Nfvw6I++G<6)<;deR}vRG&EFddl$UE^2*AYU`Px- zcPk9q5+I+0;V|^^QNU6$c)}p5P5Ushu&99T2u99RM!s$YeNUCs=sN)gy=^=lo9YYh z!xazFvng1|IFluY_pnZ15gHFM%#A%fs`1Tjj=T+T@5zHps3{K48vSd( z>CHgoeFR%Vh=~k5=Jsqn&*PNe`MFYM0p^z?L~VQP`LkUA`%kq3~D z*gqX$^)b9jCs#3FwI-37#Pf{H>uMeUr< z^Ofu*@DO+J-W{_SA`ab35^_kZ$u_PAHJ%D21c≪DZHP59|SiWZZw={TJ>{?vr}Q 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 literal 0 HcmV?d00001 diff --git a/montecarlo/example_plots/plot1_std.png b/montecarlo/example_plots/plot1_std.png new file mode 100644 index 0000000000000000000000000000000000000000..21c3f0f104b8fffe1d6c696c20d3b8fa1e7e0885 GIT binary patch literal 32914 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 R=+NMgqMWL1G0NoC{{UF@mDT_N literal 0 HcmV?d00001 diff --git a/montecarlo/example_plots/plot2.png b/montecarlo/example_plots/plot2.png new file mode 100644 index 0000000000000000000000000000000000000000..a4e3e20165753342a2e04d29fd6743573ad5f1bd GIT binary patch literal 41900 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 literal 0 HcmV?d00001 diff --git a/montecarlo/mc_from_config.py b/montecarlo/mc_from_config.py deleted file mode 100644 index ffd6ccb10..000000000 --- a/montecarlo/mc_from_config.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys -import argparse -from mcpy.monte_carlo import MonteCarlo -import importlib - -def monte_carlo_main(): - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('--config', type=str, help='config file') - args = parser.parse_args(sys.argv[1:]) - - config = importlib.import_module(args.config, __name__) - MonteCarlo(config.CONFIG).run() - -if __name__=="__main__": - monte_carlo_main() \ No newline at end of file diff --git a/montecarlo/mcpy/monte_carlo.py b/montecarlo/mcpy/monte_carlo.py index a3f526a77..8d783ab1b 100644 --- a/montecarlo/mcpy/monte_carlo.py +++ b/montecarlo/mcpy/monte_carlo.py @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + import os import sys import numpy as np @@ -7,11 +10,22 @@ import importlib from itertools import product import collections + from copy import deepcopy from mcpy.utils import filesafe from mcpy import plotting -def _check_valid_config(config): +def check_valid_config(config): + """ + Performs a basic check of the config file, checking if the necessary + subsections are present. + + If multiple config files are being made that use the same dgps and/or methods, + it may be helpful to tailor the config check to those dgps and methods. That way, + one can check that the correct parameters are being provided for those dgps and methods. + This is specific to one's implementation, however. + """ + assert 'type' in config, "config dict must specify config type" assert 'dgps' in config, "config dict must contain dgps" assert 'dgp_opts' in config, "config dict must contain dgp_opts" assert 'method_opts' in config, "config dict must contain method_opts" @@ -19,45 +33,88 @@ def _check_valid_config(config): assert 'metrics' in config, "config dict must contain metrics" assert 'methods' in config, "config dict must contain methods" assert 'plots' in config, "config dict must contain plots" + assert 'single_summary_metrics' in config, "config dict must specify which metrics are plotted in a y-x plot vs. as a single value per dgp and method" assert 'target_dir' in config, "config must contain target_dir" assert 'reload_results' in config, "config must contain reload_results" assert 'n_experiments' in config['mc_opts'], "config[mc_opts] must contain n_experiments" assert 'seed' in config['mc_opts'], "config[mc_opts] must contain seed" class MonteCarlo: + """ + This class contains methods to run (multiple) monte carlo experiments + + Experiments are constructed from a config file, which mainly consists of + references to the implementations of four different kinds of items, in + addition to various parameters for the experiment. See the README for + a descriptoin of the config file, or look at an example in the configs directory. + The four main items are: + - data generating processes (dgps): functions that generate data according to + some assumed underlying model + - methods: functions that take in data and produce other data. In our case, + they train on data produced by DGPs and then produce counterfactual estimates + - metrics: functions that take in the results of estimators and calculate metrics + - plots: functions that take in the metric results, etc. and generate plots + """ def __init__(self, config): self.config = config - _check_valid_config(self.config) + check_valid_config(self.config) + # these param strings are for properly naming results saved to disk config['param_str'] = '_'.join(['{}_{}'.format(filesafe(k), v) for k,v in self.config['mc_opts'].items()]) config['param_str'] += '_' + '_'.join(['{}_{}'.format(filesafe(k), v) for k,v in self.config['dgp_opts'].items()]) config['param_str'] += '_' + '_'.join(['{}_{}'.format(filesafe(k), v) for k,v in self.config['method_opts'].items()]) - return - # TODO: add dgp-specific, method-specific parameters and metrics def experiment(self, instance_params, seed): - ''' Runs an experiment on a single randomly generated instance and sample and returns - the parameter estimates for each method and the evaluated metrics for each method - ''' + """ + Given instance parameters to pass on to the data generating processes, + runs an experiment on a single randomly generated instance of data and returns the + parameter estimates for each method and the evaluated metrics for each method. + + Parameters + ---------- + instance_params : dictionary + instance paramaters that DGP functions may use + seed : int + random seed for random data generation + + Returns + ------- + experiment_results : dictionary + results of the experiment, depending on what the methods return. + These are stored by dgp_name and then by method_name. + true_params : dictionary + true parameters of the DGP, indexed by dgp_name, used for metrics + calculation downstream + """ np.random.seed(seed) - param_estimates = {} + experiment_results = {} true_params = {} for dgp_name, dgp_fn in self.config['dgps'].items(): data, true_param = dgp_fn(self.config['dgp_opts'][dgp_name], instance_params[dgp_name], seed) true_params[dgp_name] = true_param - param_estimates[dgp_name] = {} + experiment_results[dgp_name] = {} for method_name, method in self.config['methods'].items(): - param_estimates[dgp_name][method_name] = method(data, self.config['method_opts'][method_name], seed) + experiment_results[dgp_name][method_name] = method(data, self.config['method_opts'][method_name], seed) - return param_estimates, true_params + return experiment_results, true_params def run(self): - ''' Runs multiple experiments in parallel on randomly generated instances and samples and returns - the parameter estimates for each method and the evaluated metrics for each method across all - experiments - ''' + """ + Runs multiple experiments in parallel on randomly generated instances and samples and returns + the results for each method and the evaluated metrics for each method across all + experiments. + + Returns + ------- + simulation_results : dictionary + dictionary indexed by [dgp_name][method_name] for individual experiment results + metric_results : dictionary + dictionary indexed by [dgp_name][method_name][metric_name] + true_param : dictinoary + dictionary indexed by [dgp_name] + """ random_seed = self.config['mc_opts']['seed'] if not os.path.exists(self.config['target_dir']): @@ -68,7 +125,6 @@ def run(self): instance_params[dgp_name] = self.config['dgp_instance_fns'][dgp_name](self.config['dgp_opts'][dgp_name], random_seed) # results_file = os.path.join(self.config['target_dir'], 'results_{}.jbl'.format(self.config['param_str'])) - # what exactly is reload results for? results_file = os.path.join(self.config['target_dir'], 'results_seed{}.jbl'.format(random_seed)) if self.config['reload_results'] and os.path.exists(results_file): results = joblib.load(results_file) @@ -78,53 +134,77 @@ def run(self): for exp_id in range(self.config['mc_opts']['n_experiments'])) joblib.dump(results, results_file) - # import pdb; pdb.set_trace() - - param_estimates = {} + simulation_results = {} # note that simulation_results is a vector of individual experiment_results. from experiment() metric_results = {} true_params = {} for dgp_name in self.config['dgps'].keys(): - param_estimates[dgp_name] = {} + simulation_results[dgp_name] = {} metric_results[dgp_name] = {} for method_name in self.config['methods'].keys(): - # param_estimates[dgp_name][method_name] = np.array([results[i][0][dgp_name][method_name] for i in range(self.config['mc_opts']['n_experiments'])]) - param_estimates[dgp_name][method_name] = [results[i][0][dgp_name][method_name] for i in range(self.config['mc_opts']['n_experiments'])] + simulation_results[dgp_name][method_name] = [results[i][0][dgp_name][method_name] for i in range(self.config['mc_opts']['n_experiments'])] true_params[dgp_name] = [results[i][1][dgp_name] for i in range(self.config['mc_opts']['n_experiments'])] - # import pdb; pdb.set_trace() metric_results[dgp_name][method_name] = {} for metric_name, metric_fn in self.config['metrics'].items(): # for metric_name, metric_fn in self.config['metrics'][method_name].items(): # for method specific parameters - param_estimate_inputs = [results[i][0][dgp_name][method_name] for i in range(self.config['mc_opts']['n_experiments'])] - true_param_inputs = [results[i][1][dgp_name] for i in range(self.config['mc_opts']['n_experiments'])] - # import pdb; pdb.set_trace() - metric_results[dgp_name][method_name][metric_name] = metric_fn(param_estimate_inputs, true_param_inputs) + metric_results[dgp_name][method_name][metric_name] = metric_fn(simulation_results[dgp_name][method_name], true_params[dgp_name]) for plot_name, plot_fn in self.config['plots'].items(): # for plot_name, plot_fn in self.config['plots'][method_name].items(): # for method specific plots if isinstance(plot_fn, dict): - plotting.instance_plot(plot_name, param_estimates, metric_results, self.config, plot_fn) + plotting.instance_plot(plot_name, simulation_results, metric_results, self.config, plot_fn) else: - plot_fn(plot_name, param_estimates, metric_results, true_params, self.config) + plot_fn(plot_name, simulation_results, metric_results, true_params, self.config) - return param_estimates, metric_results, true_params + return simulation_results, metric_results, true_params class MonteCarloSweep: + """ + This class contains methods to run sets of multiple monte carlo experiments + where each set of experiments has different parameters (for the dgps and methods, etc.). + This enables sweeping through parameter values to generate results for each permutation + of parameters. For example, running a simulation when the number of samples a specific DGP + generates is 100, 1000, or 10000. + """ def __init__(self, config): self.config = config - _check_valid_config(self.config) - config['param_str'] = '_'.join(['{}_{}'.format(filesafe(k), self._stringify_param(v)) for k,v in self.config['mc_opts'].items()]) - config['param_str'] += '_' + '_'.join(['{}_{}'.format(filesafe(k), self._stringify_param(v)) for k,v in self.config['dgp_opts'].items()]) - config['param_str'] += '_' + '_'.join(['{}_{}'.format(filesafe(k), self._stringify_param(v)) for k,v in self.config['method_opts'].items()]) - return - - def _stringify_param(self, param): + check_valid_config(self.config) + config['param_str'] = '_'.join(['{}_{}'.format(filesafe(k), self.stringify_param(v)) for k,v in self.config['mc_opts'].items()]) + config['param_str'] += '_' + '_'.join(['{}_{}'.format(filesafe(k), self.stringify_param(v)) for k,v in self.config['dgp_opts'].items()]) + config['param_str'] += '_' + '_'.join(['{}_{}'.format(filesafe(k), self.stringify_param(v)) for k,v in self.config['method_opts'].items()]) + + def stringify_param(self, param): + """ + Parameters + ---------- + param : list + list denoting the various values a parameter should take + + Returns + ------- + A string representation of the range of the values that parameter will take + """ if hasattr(param, "__len__"): return '{}_to_{}'.format(np.min(param), np.max(param)) else: return param def run(self): + """ + Runs many monte carlo simulations for all the permutations of parameters + specified in the config file. + + Returns + ------- + sweep_keys : list + list of all the permutations of parameters for each dgp + sweep_sim_results : list + list of simulation results for each permutation of parameters for each dgp + sweep_metrics : list + list of metric results for each permutation of parameters for each dgp + sweep_true_params : list + list of true parameters for each permutation of parameters for each dgp + """ # currently duplicates computation for the dgps because all only one dgp param changed each config # need to make it so that every inst_config is different for each dgp for dgp_name in self.config['dgp_opts'].keys(): @@ -135,7 +215,7 @@ def run(self): dgp_sweep_params.append(dgp_key) dgp_sweep_param_vals.append(dgp_val) sweep_keys = [] - sweep_params = [] + sweep_sim_results = [] sweep_metrics = [] sweep_true_params = [] inst_config = deepcopy(self.config) @@ -143,27 +223,16 @@ def run(self): setting = list(zip(dgp_sweep_params, vec)) for k,v in setting: inst_config['dgp_opts'][dgp_name][k] = v - params, metrics, true_params = MonteCarlo(inst_config).run() + simulation_results, metrics, true_params = MonteCarlo(inst_config).run() sweep_keys.append(setting) - sweep_params.append(params) + sweep_sim_results.append(simulation_results) sweep_metrics.append(metrics) sweep_true_params.append(true_params) for plot_name, plot_fn in self.config['sweep_plots'].items(): if isinstance(plot_fn, dict): - plotting.sweep_plot(plot_key, sweep_keys, sweep_params, sweep_metrics, self.config, plot_fn) + plotting.sweep_plot(plot_key, sweep_keys, sweep_sim_results, sweep_metrics, self.config, plot_fn) else: - plot_fn(plot_name, sweep_keys, sweep_params, sweep_metrics, sweep_true_params, self.config) - - return sweep_keys, sweep_params, sweep_metrics, sweep_true_params - -def monte_carlo_main(): - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('--config', type=str, help='config file') - args = parser.parse_args(sys.argv[1:]) - - config = importlib.import_module(args.config) - MonteCarlo(config.CONFIG).run() + plot_fn(plot_name, sweep_keys, sweep_sim_results, sweep_metrics, sweep_true_params, self.config) -if __name__=="__main__": - monte_carlo_main() + return sweep_keys, sweep_sim_results, sweep_metrics, sweep_true_params diff --git a/montecarlo/mcpy/plotting.py b/montecarlo/mcpy/plotting.py index 923c4a8ff..4f97bd07b 100644 --- a/montecarlo/mcpy/plotting.py +++ b/montecarlo/mcpy/plotting.py @@ -9,38 +9,45 @@ import mcpy.metrics import itertools +# example-dgp-specific def plot_sweep(plot_name, sweep_keys, sweep_params, sweep_metrics, sweep_true_params, config): pass -def plot_metrics(plot_name, param_estimates, metric_results, true_params, config): - # plt.figure(figsize=(10,6)) +# example-dgp-specific +def plot_metrics(plot_name, experiment_results, metric_results, true_params, config): + """ + Plots all metrics that are listed in the metrics section of a config file + which are not single summary statistics. Thus, this plots metrics that are a + function of the points X. These metrics are all based on Theta(X). + """ for dgp_name in config['dgps'].keys(): # just one right now for metric_name in config['metrics'].keys(): - if metric_name not in config['per_plots']: + if metric_name not in config['single_summary_metrics']: for method_name in config['methods'].keys(): x, y = metric_results[dgp_name][method_name][metric_name] plt.plot(x, y, label=method_name) plt.xlabel("X_test") plt.ylabel(metric_name) plt.legend() + plt.savefig(plot_name + "_" + metric_name) plt.show() - # mean_rmse = np.mean(metric_results[dgp_name][method_name]['rmse']) - # mean_conf_length = np.mean(metric_results[dgp_name][method_name]['conf_length']) - # mean_coverage = np.mean(metric_results[dgp_name][method_name]['coverage']) - # print("means for {}: rmse: {}, conf_length: {}, coverage: {}".format(method_name, mean_rmse, mean_conf_length, mean_coverage)) -def plot_visualization(plot_name, param_estimates, metric_results, true_params, config): +# example-dgp-specific +def plot_visualization(plot_name, experiment_results, metric_results, true_params, config): + """ + Plots the results of each method for each dgp vs. the true effect. + """ X_test = [] for dgp_name in config['dgps'].keys(): # just one right now for method_name in config['methods'].keys(): - X_test = param_estimates[dgp_name][method_name][0][0][0] - pred = np.array([param_estimates[dgp_name][method_name][i][0][1] for i in range(len(param_estimates[dgp_name][method_name]))]) + X_test = experiment_results[dgp_name][method_name][0][0][0] + pred = np.array([experiment_results[dgp_name][method_name][i][0][1] for i in range(len(experiment_results[dgp_name][method_name]))]) mean = np.mean(pred, axis=0) plt.plot(X_test, mean, label=method_name) plt.xlabel("X_test") plt.ylabel("Treatment Effect") - lb = np.array([param_estimates[dgp_name][method_name][i][1][0] for i in range(len(param_estimates[dgp_name][method_name]))]) - ub = np.array([param_estimates[dgp_name][method_name][i][1][1] for i in range(len(param_estimates[dgp_name][method_name]))]) + lb = np.array([experiment_results[dgp_name][method_name][i][1][0] for i in range(len(experiment_results[dgp_name][method_name]))]) + ub = np.array([experiment_results[dgp_name][method_name][i][1][1] for i in range(len(experiment_results[dgp_name][method_name]))]) lb_ = np.min(lb, axis=0) ub_ = np.max(ub, axis=0) plt.fill_between(X_test.reshape(100,), lb_, ub_, alpha=0.25) @@ -48,197 +55,24 @@ def plot_visualization(plot_name, param_estimates, metric_results, true_params, true = true_params[dgp_name][0] plt.plot(X_test, true, label='true effect') plt.legend() + plt.savefig(plot_name) plt.show() -def plot_violin(plot_name, param_estimates, metric_results, true_params, config): +# example-dgp-specific +def plot_violin(plot_name, experiment_results, metric_results, true_params, config): + """ + Plots all metrics that are single summary statistics, for each method. These + are single numbers produced for each method for each experiment. They are not a function + of X. + """ for dgp_name, dgp_fn in metric_results.items(): n_methods = len(list(dgp_fn.keys())) for metric_name in next(iter(dgp_fn.values())).keys(): - if metric_name in config['per_plots']: + if metric_name in config['single_summary_metrics']: plt.figure(figsize=(1.5 * n_methods, 2.5)) plt.violinplot([dgp_fn[method_name][metric_name] for method_name in dgp_fn.keys()], showmedians=True) plt.xticks(np.arange(1, n_methods + 1), list(dgp_fn.keys())) plt.ylabel(metric_name) plt.tight_layout() + plt.savefig(plot_name) plt.show() - -def plot_subset_param_histograms(param_estimates, metric_results, config, subset): - for dgp_name, pdgp in param_estimates.items(): - n_methods = len(list(pdgp.keys())) - n_params = config['dgp_opts']['kappa_gamma'] + 1 - plt.figure(figsize=(4 * n_params, 2 * n_methods)) - for it, m_name in enumerate(pdgp.keys()): - for inner_it, i in enumerate(subset): - plt.subplot(n_methods, n_params, it * n_params + inner_it + 1) - plt.hist(pdgp[m_name][:, i]) - plt.title("{}[{}]. $\\mu$: {:.2f}, $\\sigma$: {:.2f}".format(m_name, i, np.mean(pdgp[m_name][:, i]), np.std(pdgp[m_name][:, i]))) - plt.tight_layout() - plt.savefig(os.path.join(config['target_dir'], 'dist_dgp_{}_{}.png'.format(dgp_name, config['param_str'])), dpi=300) - plt.close() - return - -def plot_param_histograms2(param_estimates, metric_results, config): - for dgp_name, pdgp in param_estimates.items(): - n_methods = len(list(pdgp.keys())) - n_params = next(iter(pdgp.values())).shape[1] - plt.figure(figsize=(4 * n_params, 2 * n_methods)) - for it, m_name in enumerate(pdgp.keys()): - for i in range(pdgp[m_name].shape[1]): - plt.subplot(n_methods, n_params, it * n_params + i + 1) - plt.hist(pdgp[m_name][:, i]) - plt.title("{}[{}]. $\\mu$: {:.2f}, $\\sigma$: {:.2f}".format(m_name, i, np.mean(pdgp[m_name][:, i]), np.std(pdgp[m_name][:, i]))) - plt.tight_layout() - plt.savefig(os.path.join(config['target_dir'], 'dist_dgp_{}_{}.png'.format(dgp_name, config['param_str'])), dpi=300) - plt.close() - return - -def plot_metrics2(param_estimates, metric_results, config): - for dgp_name, mdgp in metric_results.items(): - n_methods = len(list(mdgp.keys())) - for metric_name in next(iter(mdgp.values())).keys(): - plt.figure(figsize=(1.5 * n_methods, 2.5)) - plt.violinplot([mdgp[method_name][metric_name] for method_name in mdgp.keys()], showmedians=True) - plt.xticks(np.arange(1, n_methods + 1), list(mdgp.keys())) - plt.ylabel(metric_name) - plt.tight_layout() - plt.savefig(os.path.join(config['target_dir'], '{}_dgp_{}_{}.png'.format(filesafe(metric_name), dgp_name, config['param_str'])), dpi=300) - plt.close() - return - -def plot_metric_comparisons(param_estimates, metric_results, config): - for dgp_name, mdgp in metric_results.items(): - n_methods = len(list(mdgp.keys())) - for metric_name in next(iter(mdgp.values())).keys(): - plt.figure(figsize=(1.5 * n_methods, 2.5)) - plt.violinplot([mdgp[method_name][metric_name] - mdgp[config['proposed_method']][metric_name] for method_name in mdgp.keys() if method_name != config['proposed_method']], showmedians=True) - plt.xticks(np.arange(1, n_methods), [method_name for method_name in mdgp.keys() if method_name != config['proposed_method']]) - plt.ylabel('decrease in {}'.format(metric_name)) - plt.tight_layout() - plt.savefig(os.path.join(config['target_dir'], '{}_decrease_dgp_{}_{}.png'.format(filesafe(metric_name), dgp_name, config['param_str'])), dpi=300) - plt.close() - return - -def instance_plot(plot_name, param_estimates, metric_results, config, plot_config): - methods = plot_config['methods'] if 'methods' in plot_config else list(config['methods'].keys()) - metrics = plot_config['metrics'] if 'metrics' in plot_config else list(config['metrics'].keys()) - dgps = plot_config['dgps'] if 'dgps' in plot_config else list(config['dgps'].keys()) - metric_transforms = plot_config['metric_transforms'] if 'metric_transforms' in plot_config else {'': mcpy.metrics.transform_identity} - - for tr_name, tr_fn in metric_transforms.items(): - for dgp_name in dgps: - for metric_name in metrics: - plt.figure(figsize=(1.5 * len(methods), 2.5)) - plt.violinplot([tr_fn(metric_results, dgp_name, method_name, metric_name, config) for method_name in methods], showmedians=True) - plt.xticks(np.arange(1, len(methods) + 1), methods) - plt.ylabel('{}({})'.format(tr_name, metric_name)) - plt.tight_layout() - plt.savefig(os.path.join(config['target_dir'], '{}_{}_{}_dgp_{}_{}.png'.format(plot_name, filesafe(metric_name), tr_name, dgp_name, config['param_str'])), dpi=300) - plt.close() - return - -def _select_config_keys(sweep_keys, select_vals, filter_vals): - - if select_vals is not None: - mask_select = [all(any((p, v) in key for v in vlist) for p, vlist in select_vals.items()) for key in sweep_keys] - else: - mask_select = [True]*len(sweep_keys) - if filter_vals is not None: - mask_filter = [all(all((p, v) not in key for v in vlist) for p, vlist in filter_vals.items()) for key in sweep_keys] - else : - mask_filter = [True]*len(sweep_keys) - mask = [ms and mf for ms, mf in zip(mask_select, mask_filter)] - return mask - -def sweep_plot_marginal_transformed_metric(transform_fn, transform_name, dgps, methods, metrics, plot_name, sweep_keys, sweep_params, sweep_metrics, config, param_subset={}, select_vals={}, filter_vals={}): - - sweeps = {} - for dgp_key, dgp_val in config['dgp_opts'].items(): - if hasattr(dgp_val, "__len__"): - sweeps[dgp_key] = dgp_val - - mask = _select_config_keys(sweep_keys, select_vals, filter_vals) - if np.sum(mask) == 0: - print("Filtering resulted in no valid configurations!") - return - - for dgp in dgps: - for metric in metrics: - for param, param_vals in sweeps.items(): - if param_subset is not None and param not in param_subset: - continue - plt.figure(figsize=(5, 3)) - for method in methods: - medians = [] - mins = [] - maxs = [] - for val in param_vals: - subset = [transform_fn(metrics, dgp, method, metric, config) for key, metrics, ms - in zip(sweep_keys, sweep_metrics, mask) - if (param, val) in key and ms] - if len(subset) > 0: - grouped_results = np.concatenate(subset) - medians.append(np.median(grouped_results)) - mins.append(np.min(grouped_results)) - maxs.append(np.max(grouped_results)) - plt.plot(param_vals, medians, label=method) - plt.fill_between(param_vals, maxs, mins, alpha=0.3) - plt.legend() - plt.xlabel(param) - plt.ylabel('{}({})'.format(transform_name, metric)) - plt.tight_layout() - plt.savefig(os.path.join(config['target_dir'], '{}_{}_{}_dgp_{}_growing_{}_{}.png'.format(plot_name, filesafe(metric), transform_name, dgp, filesafe(param), config['param_str'])), dpi=300) - plt.close() - - for param1, param2 in itertools.combinations(sweeps.keys(), 2): - if param_subset is not None and (param1, param2) not in param_subset and (param2, param1) not in param_subset: - continue - x, y, z = [], [], [] - for method_it, method in enumerate(methods): - x.append([]), y.append([]), z.append([]) - for val1, val2 in itertools.product(*[sweeps[param1], sweeps[param2]]): - subset = [transform_fn(metrics, dgp, method, metric, config) for key, metrics, ms - in zip(sweep_keys, sweep_metrics, mask) - if (param1, val1) in key and (param2, val2) in key and ms] - if len(subset) > 0: - grouped_results = np.concatenate(subset) - x[method_it].append(val1) - y[method_it].append(val2) - z[method_it].append(np.median(grouped_results)) - vmin = np.min(z) - vmax = np.max(z) - fig, axes = plt.subplots(nrows=1, ncols=len(methods), figsize=(4 * len(methods), 3)) - if not hasattr(axes, '__len__'): - axes = [axes] - for method_it, (method, ax) in enumerate(zip(methods, axes)): - xi = np.linspace(np.min(x[method_it]), np.max(x[method_it]), 5*len(x[method_it])) - yi = np.linspace(np.min(y[method_it]), np.max(y[method_it]), 5*len(y[method_it])) - zi = griddata(np.array(x[method_it]), np.array(y[method_it]), np.array(z[method_it]), xi, yi, interp='linear') - ax.contour(xi, yi, zi, 15, linewidths=0.2, colors='k') - im = ax.pcolormesh(xi, yi, zi, cmap=plt.cm.Reds, vmin=vmin, vmax=vmax) - ax.contourf(xi, yi, zi, 15, cmap=plt.cm.Reds, vmin=vmin, vmax=vmax) - ax.scatter(np.array(x[method_it]), np.array(y[method_it]), alpha=0.5, s=3, c='b') - ax.set_xlabel(param1) - ax.set_ylabel(param2) - ax.set_title(method) - - plt.tight_layout() - fig.subplots_adjust(right=0.8) - cbar_ax = fig.add_axes([0.81, 0.15, 0.02, 0.72]) - cbar = fig.colorbar(im, cax=cbar_ax) - cbar.ax.tick_params(labelsize=8) - cbar.ax.set_ylabel('median {}({})'.format(transform_name, metric)) - plt.savefig(os.path.join(config['target_dir'], '{}_{}_{}_dgp_{}_growing_{}_and_{}_{}.png'.format(plot_name, filesafe(metric), transform_name, dgp, filesafe(param1), filesafe(param2), config['param_str'])), dpi=300) - plt.close() - -def sweep_plot(plot_name, sweep_keys, sweep_params, sweep_metrics, config, plot_config): - param_subset = plot_config['varying_params'] if 'varying_params' in plot_config else None - select_vals = plot_config['select_vals'] if 'select_vals' in plot_config else {} - filter_vals = plot_config['filter_vals'] if 'filter_vals' in plot_config else {} - methods = plot_config['methods'] if 'methods' in plot_config else list(config['methods'].keys()) - metrics = plot_config['metrics'] if 'metrics' in plot_config else list(config['metrics'].keys()) - dgps = plot_config['dgps'] if 'dgps' in plot_config else list(config['dgps'].keys()) - metric_transforms = plot_config['metric_transforms'] if 'metric_transforms' in plot_config else {'': mcpy.metrics.transform_identity} - - for tr_name, tr_fn in metric_transforms.items(): - sweep_plot_marginal_transformed_metric(tr_fn, tr_name, dgps, methods, metrics, plot_name, sweep_keys, sweep_params, sweep_metrics, config, - param_subset=param_subset, select_vals=select_vals, filter_vals=filter_vals) diff --git a/montecarlo/mcpy/utils.py b/montecarlo/mcpy/utils.py index 411c07803..9847ea0f0 100644 --- a/montecarlo/mcpy/utils.py +++ b/montecarlo/mcpy/utils.py @@ -1,12 +1,7 @@ -import numpy as np - -def cross_product(X1, X2): - """ Cross product of features in matrices X1 and X2 - """ - n = np.shape(X1)[0] - assert n == np.shape(X2)[0] - return (X1.reshape(n,1,-1) * X2.reshape(n,-1,1)).reshape(n,-1) +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +import numpy as np def filesafe(str): return "".join([c for c in str if c.isalpha() or c.isdigit() or c==' ']).rstrip().replace(' ', '_') diff --git a/montecarlo/run_mc_from_config.py b/montecarlo/run_mc_from_config.py new file mode 100644 index 000000000..1c9756ce6 --- /dev/null +++ b/montecarlo/run_mc_from_config.py @@ -0,0 +1,31 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import sys +import argparse +from mcpy.monte_carlo import MonteCarlo, MonteCarloSweep +import importlib + +def monte_carlo_main(): + """ + Entry point to run monte carlo simulations with specifications from a config file + run this file with command line arguments '--config [config_file]' + """ + parser = argparse.ArgumentParser(description='Process a config file for the monte carlo simulation.') + parser.add_argument('--config', type=str, help='config file') + args = parser.parse_args(sys.argv[1:]) + config = importlib.import_module(args.config, __name__) + + print("Running monte carlo simulation from {}.".format(args.config)) + # one may want to define new config types + # the sweep over the parameters could be done differently depending on type + # imagine, a different MonteCarloSweep function + # or where MonteCarloSweep sweeps over the parameters differently + # depending on the type specified + if config.CONFIG['type'] == 'single_parameter': + MonteCarlo(config.CONFIG).run() + elif config.CONFIG['type'] == 'sweep_parameter': + MonteCarloSweep(config.CONFIG).run() + +if __name__=="__main__": + monte_carlo_main() diff --git a/montecarlo/sweep_config_dml_te.py b/montecarlo/sweep_config_dml_te.py deleted file mode 100644 index 11375e248..000000000 --- a/montecarlo/sweep_config_dml_te.py +++ /dev/null @@ -1,90 +0,0 @@ -import os -import numpy as np -import econml_dml_te -from mcpy import metrics -from mcpy import plotting -from mcpy import utils -from sklearn.linear_model import Lasso, LassoCV, LogisticRegression, LogisticRegressionCV,LinearRegression,MultiTaskElasticNet,MultiTaskElasticNetCV -from sklearn.ensemble import RandomForestRegressor,RandomForestClassifier -from sklearn.preprocessing import PolynomialFeatures - -CONFIG = { - "dgps": { - "dgp1": econml_dml_te.gen_data - }, - "dgp_instance_fns": { - 'dgp1': econml_dml_te.instance_params - }, - "dgp_opts": { - 'dgp1': { - 'n_samples': [100, 2000], - 'n_features': 1, - 'n_controls': 30, - 'support_size': 5 - }, - }, - "methods": { - "LinearDMLCate": econml_dml_te.linear_dml_fit, - "SparseLinearDMLCate": econml_dml_te.sparse_linear_dml_poly_fit, - # "DMLCate": econml_dml_te.dml_poly_fit, - # "ForestDMLCate": econml_dml_te.forest_dml_fit - }, - "method_opts": { - 'LinearDMLCate': { - 'model_y': RandomForestRegressor(), - 'model_t': RandomForestRegressor(), - 'inference': 'statsmodels' - }, - 'SparseLinearDMLCate': { - 'model_y': RandomForestRegressor(), - 'model_t': RandomForestRegressor(), - 'featurizer': PolynomialFeatures(degree=3), - 'inference': 'debiasedlasso' - }, - # 'DMLCate': { - # 'model_y': RandomForestRegressor(), - # 'model_t': RandomForestRegressor(), - # 'model_final': Lasso(alpha=0.1, fit_intercept=False), - # 'featurizer': PolynomialFeatures(degree=10), - # 'inference': 'bootstrap' - # }, - # 'ForestDMLCate': { - # 'model_y': RandomForestRegressor(), - # 'model_t': RandomForestRegressor(), - # 'discrete_treatment': False, - # 'n_estimators': 1000, - # 'subsample_fr': 0.8, - # 'min_samples_leaf': 10, - # 'min_impurity_decrease': 0.001, - # 'verbose': 0, - # 'min_weight_fraction_leaf': 0.01, - # 'inference': 'bootstrap' - # } - }, - "metrics": { - 'rmse': metrics.rmse, - 'conf_length': metrics.conf_length, - 'coverage': metrics.coverage, - 'std': metrics.std, - 'coverage_band': metrics.coverage_band - }, - "plots": { - 'plot1': plotting.plot_metrics, - 'plot2': plotting.plot_visualization, - 'plot3': plotting.plot_violin - }, - "per_plots": ['coverage_band'], - "sweep_plots": { - # 'plot4': plotting.plot_sweep - # "plot1": {'varying_params': ['$k_g$'], 'select_vals': {'$\\sigma_\\epsilon$': [1.0], '$\\sigma_\\eta$': [1.0]}}, - # "plot2": {'varying_params': [n('$k_g$', '$\\sigma_\\eta$')], 'select_vals': {'$\\sigma_\\epsilon$':[1.0]}, 'methods': ["Direct"], 'metric_transforms': {'% decrease': metrics.transform_ratio}}, - # "plot3": {'varying_params': [('$k_g$', '$\\sigma_\\epsilon$')], 'select_vals': {'$\\sigma_\\eta$':[1.0]}, 'methods': ["Direct"], 'metric_transforms': {'% decrease': metrics.transform_ratio}} - }, - "mc_opts": { - 'n_experiments': 5, # number of monte carlo experiments - "seed": 123 - }, - "proposed_method": "CrossOrtho", - "target_dir": "sweep_econml_test", - "reload_results": False - } diff --git a/montecarlo/sweep_mc_from_config.py b/montecarlo/sweep_mc_from_config.py deleted file mode 100644 index dd83220b5..000000000 --- a/montecarlo/sweep_mc_from_config.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys -import argparse -from mcpy.monte_carlo import MonteCarloSweep -import importlib - -def monte_carlo_main(): - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('--config', type=str, help='config file') - args = parser.parse_args(sys.argv[1:]) - - config = importlib.import_module(args.config, __name__) - MonteCarloSweep(config.CONFIG).run() - -if __name__=="__main__": - monte_carlo_main() \ No newline at end of file