diff --git a/CMakeLists.txt b/CMakeLists.txt index e0d4006b2..ce516b8db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ find_package(Graphviz) include_directories(${GRAPHVIZ_INCLUDE_DIRS}) # Add and link pybind11 modules -find_package(Boost COMPONENTS graph REQUIRED) +find_package(Boost COMPONENTS graph program_options REQUIRED) include_directories(lib) include_directories(external) include_directories(${Boost_INCLUDE_DIR}) @@ -77,7 +77,8 @@ add_library(Delphi lib/format_output.cpp lib/database.cpp #lib/PybindTester.hpp -) + lib/head_nodes.cpp + lib/Timer.hpp) target_link_libraries(Delphi PRIVATE ${Boost_LIBRARIES} @@ -96,6 +97,11 @@ add_executable(create_model apps/create_model.cpp) target_link_libraries(create_model PRIVATE Delphi Eigen3::Eigen) add_executable(sandbox_tester apps/sandbox_tester.cpp) target_link_libraries(sandbox_tester PRIVATE Delphi Eigen3::Eigen) +add_executable(timer + apps/timer.cpp + lib/Timer.hpp + lib/CSVWriter.hpp) +target_link_libraries(timer PRIVATE Delphi Eigen3::Eigen ${Boost_LIBRARIES}) #add_executable(pybind_tester_driver apps/pybind_tester_driver.cpp) diff --git a/apps/create_model.cpp b/apps/create_model.cpp index 46de74d20..bdcae8f6f 100644 --- a/apps/create_model.cpp +++ b/apps/create_model.cpp @@ -475,12 +475,13 @@ int main(int argc, char* argv[]) { }; + cout << "Creating model\n"; AnalysisGraph G = AnalysisGraph::from_causemos_json_file( - "../tests/data/delphi/create_model_input_2.json", 4); + "../tests/data/delphi/create_model_rain--temperature--yield.json", 0); + G.train_model(); FormattedProjectionResult proj = G.run_causemos_projection_experiment_from_json_file( - "../tests/data/delphi/experiments_projection_input_2.json", - 10, - 4); + "../tests/data/delphi/experiments_rain--temperature--yield.json"); + return(0); test_simple_path_construction(); test_inference(); @@ -494,13 +495,10 @@ int main(int argc, char* argv[]) { test_merge(); test_debug(); - return(0); string result = G.serialize_to_json_string(false); G = AnalysisGraph::deserialize_from_json_string(result, false); proj = G.run_causemos_projection_experiment_from_json_file( - "../tests/data/delphi/experiments_projection_input_2.json", - 10, - 4); + "../tests/data/delphi/experiments_projection_input_2.json"); string result2 = G.serialize_to_json_string(false); if (result.compare(result2) == 0){ diff --git a/apps/timer.cpp b/apps/timer.cpp new file mode 100644 index 000000000..002c6e475 --- /dev/null +++ b/apps/timer.cpp @@ -0,0 +1,109 @@ +#include "AnalysisGraph.hpp" +#include "Timer.hpp" +#include "CSVWriter.hpp" +#include + +using namespace std; +using namespace boost::program_options; + +int main(int argc, char* argv[]) { + variables_map vm; + bool check = false; + + try { + options_description desc{"Options"}; + desc.add_options() + ("help,h", "Help screen") + ("min-nodes,n", value()->default_value(2), "Minimum number of nodes") + ("max-nodes,x", value()->default_value(3), "Maximum number of nodes") + ("multiplicative-factor,m", value()->default_value(1.0f), "number of nodes in the next graph = number of nodes in the current graph * mf + af") + ("additive-factor,a", value()->default_value(1), "number of nodes in the next graph = number of nodes in the current graph * mf + af") + ("frac-extra-edges,e", value()->default_value(0.0f), "The proportion of extra edges to be added. Zero means the minimum graph, which is a tree. One means a complete graph.") + ("num-repeats,i", value()->default_value(2), "Number of times to repeat the experiment for a particular size graph.") + ("num-obs,d", value()->default_value(48), "Number of observations (training data points) to generate for each node.") + ("pred-timesteps,p", value()->default_value(24), "Number of time steps to predict.") + ("burn,b", value()->default_value(10000), "Number of samples to throw away before starting to retain samples.") + ("res,r", value()->default_value(1000), "Number of samples to retain.") + ("kernels,k", value()->default_value(1000), "The number of KDE kernels to be used when creating prior distributions for betas.") + ("noise-variance,v", value()->default_value(16), "Variance of the emission distribution when generating data.") + ("output-file,o", value()->default_value("timing"), "Output file name. Creates if not exist. Appends otherwise.") + ("check-config,c", bool_switch(&check), "Check the timing configuration."); + + store(parse_command_line(argc, argv, desc), vm); + notify(vm); + + if (vm.count("help")) { + std::cout << desc << '\n'; + return(0); + } + } + catch (const error &ex) + { + std::cerr << ex.what() << '\n'; + } + + int min_nodes = vm["min-nodes"].as(); + int max_nodes = vm["max-nodes"].as(); + double frac_extra_edges = vm["frac-extra-edges"].as(); + double multiplicative_factor = vm["multiplicative-factor"].as(); + int additive_factor = vm["additive-factor"].as(); + int num_repeats = vm["num-repeats"].as(); + + int num_obs = vm["num-obs"].as(); + int pred_timesteps = vm["pred-timesteps"].as(); + int burn = vm["burn"].as(); + int res = vm["res"].as(); + int kde_kernels = vm["kernels"].as(); + double noise_variance = vm["noise-variance"].as(); + string output_file = vm["output-file"].as() + "_" + to_string(min_nodes) + "-" + to_string(max_nodes) + ".csv"; + cout << "The output is stored in: " << output_file << endl; + + std::pair, std::vector> durations; + CSVWriter writer(output_file); + vector headings = {"Runs", "Nodes", "Edges", "Create", "Train", "Predict"}; + writer.write_row(headings.begin(), headings.end()); + + for (int run = 1; run <= num_repeats; ++run) { + cout << "\n\nRun: " << run << "\n"; + for (int nodes = min_nodes; nodes <= max_nodes; nodes = (nodes < 16? nodes + 1 : lround(nodes * multiplicative_factor + additive_factor))) { + int max_extra_edges = nodes - 1; //ceil((nodes - 1) * (nodes - 1) * frac_extra_edges); + for (int extra_edges = 0; extra_edges <= max_extra_edges; extra_edges = (extra_edges < 16? extra_edges + 1 : extra_edges * 2)) { + cout << "\n\tNodes: " << nodes << " \tExtra edges: " << extra_edges << "\n"; + if (check) { + continue; + } + AnalysisGraph G1; + + durations.first.clear(); + durations.second.clear(); + durations.first = {"Runs", "Nodes", "Edges"}; + durations.second = {run, nodes, nodes - 1 + extra_edges}; + + { + Timer t = Timer("create", durations); + G1 = AnalysisGraph::generate_random_CAG(nodes, extra_edges); + G1.generate_synthetic_data(num_obs, + noise_variance, + kde_kernels, + InitialBeta::PRIOR, + InitialDerivative::DERI_PRIOR, + false); + } + { + Timer t = Timer("train", durations); + G1.run_train_model(res, + burn, + InitialBeta::ZERO, + InitialDerivative::DERI_ZERO, + false); + } + { + Timer t = Timer("predict", durations); + G1.generate_prediction(1, pred_timesteps); + } + writer.write_row(durations.second.begin(), durations.second.end()); + } + } + } + return(0); +} diff --git a/delphi/plotter.py b/delphi/plotter.py index 496da6ec4..7d7edf031 100644 --- a/delphi/plotter.py +++ b/delphi/plotter.py @@ -38,10 +38,38 @@ def delphi_plotter(model_state, num_bins=400, rotation=45, out_dir='plots', file if file_name_prefix: file_name_prefix += '_' - concept_indicators, edges, adjectives, polarities, edge_data, derivatives, data_range, data_set, pred_range, predictions, cis = model_state + concept_indicators, edges, adjectives, polarities, edge_data, derivatives, data_range, data_set, pred_range, predictions, cis, log_likelihoods = model_state plot_num = 1 + # Plot log likelihoods + sns.set_style("whitegrid") + fig, ax = plt.subplots(dpi=150, figsize=(10, 5)) + plt.rcParams['font.size'] = 18 + + df_log_likelihood = pd.DataFrame({'Sample Number': list(range(len(log_likelihoods))), 'Log Likelihood': log_likelihoods}) + + sns.lineplot( + ax=ax, + data=df_log_likelihood, + y='Log Likelihood', + x='Sample Number', + color='red', + ) + plt.title(f'Log Likelihood Progression Throughout Training') + plt.xlabel('Sample Number') + plt.ylabel('Log Likelihood') + plt.tight_layout() + + if out_dir: + plt.savefig(f'{out_dir}/{file_name_prefix}{plot_num}_Log_Likelihoods.png') + if save_csv: + df_log_likelihood.to_csv(f'{out_dir}/{file_name_prefix}{plot_num}_Log_Likelihoods.csv', index=False) + plot_num += 1 + else: + plt.show() + plt.close() + # Plot theta prior and sample distributions for idx, thetas in enumerate(edge_data): df_prior = pd.DataFrame({'Prior': thetas[0]}) @@ -150,7 +178,8 @@ def delphi_plotter(model_state, num_bins=400, rotation=45, out_dir='plots', file for box_plot in [True, False]: for ind, preds in predictions.items(): sns.set_style("whitegrid") - fig, ax = plt.subplots(dpi=150, figsize=(8, 4.5)) + fig, ax = plt.subplots(dpi=150, figsize=(10, 5)) + plt.rcParams['font.size'] = 18 df_preds = pd.DataFrame.from_dict(preds) df_preds= pd.melt(df_preds, value_vars=df_preds.columns, @@ -167,9 +196,6 @@ def delphi_plotter(model_state, num_bins=400, rotation=45, out_dir='plots', file sns.boxplot(ax=ax, data=df_preds, x='Time Step', y='Prediction') ax.set_xticklabels(ax.get_xticklabels(), rotation=90) else: - sns.lineplot(ax=ax, data=df_preds, x='Time Step', y='Prediction', - sort=False, marker='D', label='Mean Prediction') - if len(data_set[ind]) > 0: df_data = pd.DataFrame.from_dict(data_set[ind]) @@ -189,14 +215,15 @@ def delphi_plotter(model_state, num_bins=400, rotation=45, out_dir='plots', file if df_data_grp['frequency'].max() == df_data_grp['frequency'].min(): # There are no coinciding data points - sns.scatterplot( + sns.lineplot( ax=ax, data=df_data_grp, y='Data', x='Time Step', marker='o', label='Data', - color='red' + color='red', + alpha=0.3 ) else: sns.scatterplot( @@ -218,6 +245,9 @@ def delphi_plotter(model_state, num_bins=400, rotation=45, out_dir='plots', file ax.legend(handles, labels, handler_map={str: LegendTitle({'fontsize': 12})}, fancybox=True) + sns.lineplot(ax=ax, data=df_preds, x='Time Step', y='Prediction', + sort=False, marker='D', label='Mean Prediction') + # Set x-axis tick marks ''' dates = set(data_range).union(set(pred_range)) @@ -235,6 +265,25 @@ def delphi_plotter(model_state, num_bins=400, rotation=45, out_dir='plots', file plt.title(f'Predictions\n{ind}') else: plt.title(f'Mean Predictions and Data\n{ind}') + + plt.ylabel(ind) + # plt.xlabel('Year/Month') + # plt.legend() + + # xtics = [] + # xlabels = [] + # all_x = set(df_data['Time Step']) + # all_x.update(pred_range) + # all_x = list(all_x) + # all_x.sort() + # for x in all_x: + # if x % 12 == 0: + # xtics.append(x) + # xlabels.append(f'{x // 12 + 1958}/{x % 12 + 1}') + # + # plt.xticks(xtics, xlabels) + plt.tight_layout() + plt.tight_layout() if out_dir: @@ -258,26 +307,8 @@ def delphi_plotter(model_state, num_bins=400, rotation=45, out_dir='plots', file for with_preds in [True, False]: for ind, ind_cis in cis.items(): sns.set_style("whitegrid") - fig, ax = plt.subplots(dpi=150, figsize=(8, 4.5)) - - if with_preds: - df_cis = pd.DataFrame.from_dict(ind_cis) - - if month_year: - df_cis['Time Step'] = pd.to_datetime(pred_range) - else: - df_cis['Time Step'] = pred_range - - sns.lineplot(ax=ax, data=df_cis, x='Time Step', y='Median', - sort=False, marker='D', label='Median Prediction') - ax.fill_between( - x=df_cis['Time Step'], - y1=df_cis['Upper 95% CI'], - y2=df_cis['Lower 95% CI'], - alpha=0.2, - color='blue', - label='95% CI' - ) + fig, ax = plt.subplots(dpi=150, figsize=(10, 5)) + plt.rcParams['font.size'] = 18 if len(data_set[ind]) > 0: df_data = pd.DataFrame.from_dict(data_set[ind]) @@ -287,7 +318,7 @@ def delphi_plotter(model_state, num_bins=400, rotation=45, out_dir='plots', file pd.to_datetime(data_range[int(ts)])) else: df_data['Time Step'] = df_data['Time Step'].apply(lambda ts: - data_range[int(ts)]) + int(data_range[int(ts)])) # Aggregate multiple coinciding data points df_data['frequency'] = df_data['Time Step'].apply(lambda x: 1) @@ -298,14 +329,15 @@ def delphi_plotter(model_state, num_bins=400, rotation=45, out_dir='plots', file if df_data_grp['frequency'].max() == df_data_grp['frequency'].min(): # There are no coinciding data points - sns.scatterplot( + sns.lineplot( ax=ax, data=df_data_grp, y='Data', x='Time Step', marker='o', label='Data', - color='red' + color='red', + alpha=0.3 ) else: sns.scatterplot( @@ -328,12 +360,58 @@ def delphi_plotter(model_state, num_bins=400, rotation=45, out_dir='plots', file 12})}, fancybox=True) + if with_preds: + df_cis = pd.DataFrame.from_dict(ind_cis) + + if month_year: + df_cis['Time Step'] = pd.to_datetime(pred_range) + else: + df_cis['Time Step'] = pred_range + df_cis['Time Step'] = df_cis['Time Step'].apply(lambda ts: int(ts)) + + rmse = -1 + if len(data_set[ind]) > 0: + df_rmse = pd.merge(left=df_cis, right=df_data, on='Time Step')[['Time Step', 'Median', 'Data']] + + if not df_rmse.empty: + df_rmse['se'] = df_rmse.apply(lambda row: (row['Median'] - row['Data']) ** 2, axis=1) + rmse = math.sqrt(sum(df_rmse['se']) / len(df_rmse['se'])) + + sns.lineplot(ax=ax, data=df_cis, x='Time Step', y='Median', + sort=False, marker='D', label='Median Prediction') + ax.fill_between( + x=df_cis['Time Step'], + y1=df_cis['Upper 95% CI'], + y2=df_cis['Lower 95% CI'], + alpha=0.2, + color='blue', + label='95% CI' + ) + ind = ind.split('/')[-1] if with_preds: - plt.title(f'Median Predictions and $95\%$ Credible Interval\n{ind}') + plt.title(f'Median Predictions and $95\%$ Credible Interval\n{ind} (RMSE: {rmse:0.2f})') else: plt.title(f'{ind}\nData') + plt.ylabel(ind) + # plt.xlabel('Year/Month') + plt.legend() + + # xtics = [] + # xlabels = [] + # all_x = set(df_data['Time Step']) + # all_x.update(pred_range) + # all_x = list(all_x) + # all_x.sort() + # for x in all_x: + # if x % 12 == 0: + # xtics.append(x) + # xlabels.append(f'{x // 12 + 1958}/{x % 12 + 1}') + # + # plt.xticks(xtics, xlabels) + plt.tight_layout() + if out_dir: if with_preds: plt.savefig(f'{out_dir}/{file_name_prefix}{plot_num}_Predictions_Median_and_CI_{ind}.png') @@ -347,6 +425,122 @@ def delphi_plotter(model_state, num_bins=400, rotation=45, out_dir='plots', file plt.close() + ############################################# + # Plot predictions and data for the prediction range only + for ind, ind_cis in cis.items(): + sns.set_style("whitegrid") + fig, ax = plt.subplots(dpi=150, figsize=(10, 5)) + plt.rcParams['font.size'] = 18 + + df_cis = pd.DataFrame.from_dict(ind_cis) + + if month_year: + df_cis['Time Step'] = pd.to_datetime(pred_range) + else: + df_cis['Time Step'] = pred_range + all_x = set(pred_range) + + if len(data_set[ind]) > 0: + df_data = pd.DataFrame.from_dict(data_set[ind]) + + if month_year: + df_data['Time Step'] = df_data['Time Step'].apply(lambda ts: + pd.to_datetime(data_range[int(ts)])) + else: + df_data['Time Step'] = df_data['Time Step'].apply(lambda ts: + int(data_range[int(ts)])) + all_x.update(df_data['Time Step']) + + df_data = pd.merge(left=df_data, right=df_cis, on='Time Step')[df_data.columns] + + # Aggregate multiple coinciding data points + df_data['frequency'] = df_data['Time Step'].apply(lambda x: 1) + df_data_grp = df_data.groupby(by=['Time Step', 'Data'], as_index=False).count() + + if month_year: + df_data_grp['Time Step'] = pd.to_datetime(df_data_grp['Time Step']) + + if df_data_grp['frequency'].max() == df_data_grp['frequency'].min(): + # There are no coinciding data points + sns.lineplot( + ax=ax, + data=df_data_grp, + y='Data', + x='Time Step', + marker='o', + label='Data', + color='red', + alpha=0.3 + ) + else: + sns.scatterplot( + ax=ax, + data=df_data_grp, + y='Data', + x='Time Step', + marker='o', + label='Data', + hue=df_data_grp['frequency'].tolist(), + palette='ch:r=-.8, l=.75', + size=df_data_grp['frequency'].tolist(), + sizes=(50, 250) + ) + + handles, labels = ax.get_legend_handles_labels() + handles.insert(2, 'Number of Data Points') + labels.insert(2, '') + ax.legend(handles, labels, handler_map={str: LegendTitle({'fontsize': + 12})}, fancybox=True) + + + rmse = -1 + if len(data_set[ind]) > 0: + df_rmse = pd.merge(left=df_cis, right=df_data, on='Time Step')[['Time Step', 'Median', 'Data']] + + if not df_rmse.empty: + df_rmse['se'] = df_rmse.apply(lambda row: (row['Median'] - row['Data']) ** 2, axis=1) + rmse = math.sqrt(sum(df_rmse['se']) / len(df_rmse['se'])) + + sns.lineplot(ax=ax, data=df_cis, x='Time Step', y='Median', + sort=False, marker='D', label='Median Prediction') + ax.fill_between( + x=df_cis['Time Step'], + y1=df_cis['Upper 95% CI'], + y2=df_cis['Lower 95% CI'], + alpha=0.2, + color='blue', + label='95% CI' + ) + + ind = ind.split('/')[-1] + plt.title(f'Median Predictions and $95\%$ Credible Interval\n{ind} (RMSE: {rmse:0.2f})') + + plt.ylabel(ind) + plt.xlabel('Year/Month') + plt.legend() + + # xtics = [] + # xlabels = [] + # all_x = list(all_x) + # all_x.sort() + # for x in all_x: + # if x % 12 == 0: + # xtics.append(x) + # xlabels.append(f'{x // 12 + 1958}/{x % 12 + 1}') + # + # plt.xticks(xtics, xlabels, rotation=rotation) + plt.tight_layout() + + if out_dir: + plt.savefig(f'{out_dir}/{file_name_prefix}{plot_num}_Predictions_Median_and_CI_{ind}_prediction_range.png') + if save_csv: + df_cis.to_csv(f'{out_dir}/{file_name_prefix}{plot_num}_Predictions_Median_and_CI_{ind}_prediction_range.csv', index=False) + plot_num += 1 + else: + plt.show() + plt.close() +############################################# + # Plot predictions for pairs of indicators related by edges # from the summarized (median, upper and lower confidence # intervals) set of predictions (plots the median) and the summarized data set @@ -410,10 +604,27 @@ def delphi_plotter(model_state, num_bins=400, rotation=45, out_dir='plots', file df_target_data['Time Step'] = df_target_data['Time Step'].apply(lambda ts: data_range[int(ts)]) - sns.scatterplot(ax=ax_left, data=df_source_data, x='Time Step', - y='Data', marker='x', color=color_left, label=f'{source}') - sns.scatterplot(ax=ax_right, data=df_target_data, x='Time Step', - y='Data', marker='x', color=color_right, label=f'{target}') + # Aggregate multiple coinciding data points + df_source_data['frequency'] = df_source_data['Time Step'].apply(lambda x: 1) + df_source_data_grp = df_source_data.groupby(by=['Time Step', 'Data'], as_index=False).count() + df_target_data['frequency'] = df_target_data['Time Step'].apply(lambda x: 1) + df_target_data_grp = df_target_data.groupby(by=['Time Step', 'Data'], as_index=False).count() + + if df_source_data_grp['frequency'].max() == df_source_data_grp['frequency'].min(): + # There are no coinciding data points + sns.lineplot(ax=ax_left, data=df_source_data_grp, x='Time Step', + y='Data', marker='x', color=color_left, alpha=0.3, label=f'{source}') + else: + sns.scatterplot(ax=ax_left, data=df_source_data, x='Time Step', + y='Data', marker='x', color=color_left, label=f'{source}') + + if df_target_data_grp['frequency'].max() == df_target_data_grp['frequency'].min(): + # There are no coinciding data points + sns.lineplot(ax=ax_right, data=df_target_data_grp, x='Time Step', + y='Data', marker='x', color=color_right, alpha=0.3, label=f'{target}') + else: + sns.scatterplot(ax=ax_right, data=df_target_data, x='Time Step', + y='Data', marker='x', color=color_right, label=f'{target}') # Legend handles_left, labels_left = ax_left.get_legend_handles_labels() diff --git a/lib/AnalysisGraph.hpp b/lib/AnalysisGraph.hpp index a6db06f10..d4c4ffe7c 100644 --- a/lib/AnalysisGraph.hpp +++ b/lib/AnalysisGraph.hpp @@ -9,6 +9,8 @@ #include #include +#include + #include "graphviz_interface.hpp" #include "DiGraph.hpp" @@ -50,6 +52,11 @@ typedef std::pair, std::tuple> CausalFragment; +// { concept_name --> (ind_name, [obs_0, obs_1, ... ])} +typedef std::unordered_map>> + ConceptIndicatorAlignedData; + typedef std::tuple, std::vector, std::string> EventCollection; @@ -146,7 +153,9 @@ typedef std::tuple< //std::vector, std::vector, Predictions, - CredibleIntervals + CredibleIntervals, + // Log likelihoods + std::vector > CompleteState; // Access @@ -236,6 +245,11 @@ class AnalysisGraph { // Maps each β to all the transition matrix cells that are dependent on it. std::multimap, std::pair> beta2cell; + std::unordered_set body_nodes = {}; + std::unordered_set head_nodes = {}; + std::vector generated_latent_sequence; + int generated_concept; + /* ============================================================================ Sampler Related Variables @@ -258,11 +272,17 @@ class AnalysisGraph { std::unordered_map e_A_ts; long modeling_period = 1; // Number of epochs per one modeling timestep + std::unordered_map> external_concepts; + std::vector concept_sample_pool; + double t = 0.0; double delta_t = 1.0; double log_likelihood = 0.0; double previous_log_likelihood = 0.0; + double log_likelihood_MAP = 0.0; + int MAP_sample_number = -1; + std::vector log_likelihoods; // To decide whether to perturb a θ or a derivative // If coin_flip < coin_flip_thresh perturb θ else perturb derivative @@ -381,6 +401,8 @@ class AnalysisGraph { // latent_state_constraints.at(time step) std::unordered_map>> one_off_constraints; + std::unordered_map>> + head_node_one_off_constraints; // // Implementing Perpetual constraints: // ------------------------------------------------------------------------- @@ -408,6 +430,11 @@ class AnalysisGraph { std::vector transition_matrix_collection; std::vector initial_latent_state_collection; + //std::vector> latent_mean_collection; + //std::vector> latent_std_collection; + // Access: + // [sample][node id]{partition --> (mean, std)} + //std::vector>>> latent_mean_std_collection; std::vector synthetic_latent_state_sequence; bool synthetic_data_experiment = false; @@ -518,6 +545,8 @@ class AnalysisGraph { long &frequent_gap, int &highest_frequency); + void infer_concept_period(const ConceptIndicatorEpochs &concept_indicator_epochs); + /** * Set the observed state sequence from the create model JSON input received * from the HMI. @@ -547,7 +576,8 @@ class AnalysisGraph { create-experiment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - std::pair timestamp_to_year_month(long timestamp); + // Epoch --> (year, month, date) + std::tuple timestamp_to_year_month_date(long timestamp); void extract_projection_constraints( const nlohmann::json &projection_constraints, long skip_steps); @@ -883,6 +913,38 @@ class AnalysisGraph { void revert_back_to_previous_state(); + + /* + ============================================================================ + Private: Modeling head nodes (in head_nodes.cpp) + ============================================================================ + */ + + void partition_data_and_calculate_mean_std_for_each_partition( + Node& n, std::vector& latent_sequence); + + void apply_constraint_at(int ts, int node_id); + + void generate_head_node_latent_sequence(int node_id, + int num_timesteps, + bool sample, + int seq_no = 0); + + void generate_head_node_latent_sequence_from_changes(Node &n, + int num_timesteps, + bool sample); + + void generate_head_node_latent_sequences(int samp, int num_timesteps); + + void update_head_node_latent_state_with_generated_derivatives( + int ts_current, + int ts_next, + int concept_id, + std::vector& latent_sequence); + + void update_latent_state_with_generated_derivatives(int ts_current, + int ts_next); + /* ============================================================================ Private: Prediction (in prediction.cpp) @@ -941,29 +1003,6 @@ class AnalysisGraph { ============================================================================ */ - void set_random_initial_latent_state(); - - void generate_synthetic_latent_state_sequence(); - - void - generate_synthetic_observed_state_sequence_from_synthetic_latent_state_sequence(); - - // TODO: Need testing - /** - * Sample observed state std::vector. - * This is the implementation of the emission function. - * - * @param latent_state: Latent state std::vector. - * This has 2 * number of vertices in the CAG. - * Even indices track the state of each vertex. - * Odd indices track the state of the derivative. - * - * @return Observed state std::vector. Observed state for each indicator for - * each vertex. Indexed by: [ vertex id ][ indicator id ] - */ - std::vector> - sample_observed_state(Eigen::VectorXd latent_state); - /* ============================================================================ Private: Graph Visualization (in graphviz.cpp) @@ -1037,6 +1076,11 @@ class AnalysisGraph { static AnalysisGraph from_causal_fragments(std::vector causal_fragments); + static AnalysisGraph + from_causal_fragments_with_data(std::pair, + ConceptIndicatorAlignedData> cag_ind_data, + int kde_kernels = 5); + /** From internal string representation output by to_json_string */ static AnalysisGraph from_json_string(std::string); @@ -1089,12 +1133,14 @@ class AnalysisGraph { /* ============================================================================ - Private: Model serialization (in serialize.cpp) + Public: Model serialization (in serialize.cpp) ============================================================================ */ std::string serialize_to_json_string(bool verbose = true); + void export_create_model_json_string(); + static AnalysisGraph deserialize_from_json_string(std::string json_string, bool verbose = true); static AnalysisGraph deserialize_from_json_file(std::string filename, bool verbose = true); @@ -1151,13 +1197,15 @@ class AnalysisGraph { Eigen::VectorXd& get_initial_latent_state() { return this->s0; }; + double get_MAP_log_likelihood() { return this->log_likelihood_MAP; }; + /* ============================================================================ Public: Graph Building (in graph_building.cpp) ============================================================================ */ - void add_node(std::string concept); + int add_node(std::string concept); bool add_edge(CausalFragment causal_fragment); void add_edge(CausalFragmentCollection causal_fragments); @@ -1335,6 +1383,23 @@ class AnalysisGraph { bool use_continuous = true); void run_train_model(int res = 200, + int burn = 10000, + InitialBeta initial_beta = InitialBeta::ZERO, + InitialDerivative initial_derivative = InitialDerivative::DERI_ZERO, + bool use_heuristic = false, + bool use_continuous = true, + int train_start_timestep = 0, + int train_timesteps = -1, + std::unordered_map concept_periods = {}, + std::unordered_map concept_center_measures = {}, + std::unordered_map concept_models = {}, + std::unordered_map concept_min_vals = {}, + std::unordered_map concept_max_vals = {}, + std::unordered_map + > + ext_concepts = {}); + + void run_train_model_2(int res = 200, int burn = 10000, InitialBeta initial_beta = InitialBeta::ZERO, InitialDerivative initial_derivative = InitialDerivative::DERI_ZERO, @@ -1382,10 +1447,17 @@ class AnalysisGraph { int end_year, int end_month, ConstraintSchedule constraints = - ConstraintSchedule(), + ConstraintSchedule(), bool one_off = true, bool clamp_deri = true); + void generate_prediction(int pred_start_timestep, + int pred_timesteps, + ConstraintSchedule constraints = + ConstraintSchedule(), + bool one_off = true, + bool clamp_deri = true); + /** * this->generate_prediction() must be called before calling this method. * Outputs raw predictions for a given indicator that were generated by @@ -1406,21 +1478,23 @@ class AnalysisGraph { ============================================================================ */ - std::pair - test_inference_with_synthetic_data( - int start_year = 2015, - int start_month = 1, - int end_year = 2015, - int end_month = 12, - int res = 100, - int burn = 900, - std::string country = "South Sudan", - std::string state = "", - std::string county = "", - std::map units = {}, - InitialBeta initial_beta = InitialBeta::HALF, - InitialDerivative initial_derivative = InitialDerivative::DERI_ZERO, - bool use_continuous = true); + static AnalysisGraph generate_random_CAG(unsigned int num_nodes, + unsigned int num_extra_edges = 0); + + void generate_synthetic_data(unsigned int num_obs = 48, + double noise_variance = 0.1, + unsigned int kde_kernels = 1000, + InitialBeta initial_beta = InitialBeta::PRIOR, + InitialDerivative initial_derivative = InitialDerivative::DERI_PRIOR, + bool use_continuous = false); + + void initialize_random_CAG(unsigned int num_obs, + unsigned int kde_kernels, + InitialBeta initial_beta, + InitialDerivative initial_derivative, + bool use_continuous); + + void interpolate_missing_months(std::vector &filled_months, Node &n); /* ============================================================================ @@ -1481,5 +1555,14 @@ class AnalysisGraph { ============================================================================ */ + sqlite3* open_delphi_db(int mode = SQLITE_OPEN_READONLY); + void write_model_to_db(std::string model_id); + + AdjectiveResponseMap construct_adjective_response_map( + std::mt19937 gen, + std::uniform_real_distribution& uni_dist, + std::normal_distribution& norm_dist, + size_t n_kernels + ); }; diff --git a/lib/CSVWriter.hpp b/lib/CSVWriter.hpp new file mode 100644 index 000000000..b3fa144aa --- /dev/null +++ b/lib/CSVWriter.hpp @@ -0,0 +1,64 @@ +// +// Created by Varun on 9/23/2017. +// https://thispointer.com/how-to-write-data-in-a-csv-file-in-c/ +// Remy van Elst on 6/16/2019 +// https://raymii.org/s/snippets/Cpp_create_and_write_to_a_csv_file.html +// + +#ifndef DELPHI_CSVWRITER_HPP +#define DELPHI_CSVWRITER_HPP + + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * A class to create and write data in a csv file. + */ +class CSVWriter + { + std::string fileName; + std::string delimeter; + int linesCount; + std::mutex logMutex; + public: + CSVWriter(std::string filename, std::string delm = ",") : + fileName(filename), delimeter(delm), linesCount(0) + {} + /* + * Member function to store a range as comma seperated value + */ + template + void write_row(T first, T last); + }; +/* + * This Function accepts a range and appends all the elements in the range + * to the last row, seperated by delimeter (Default is comma) + */ +template +void CSVWriter::write_row(T first, T last) +{ + std::lock_guard csvLock(logMutex); + std::fstream file; + // Open the file in truncate mode if first line else in Append Mode + file.open(fileName, std::ios::out | (linesCount ? std::ios::app : std::ios::trunc)); + // Iterate over the range and add each lement to file seperated by delimeter. + for (; first != last; ) + { + file << *first; + if (++first != last) + file << delimeter; + } + file << "\n"; + linesCount++; + // Close the file + file.close(); +}; + +#endif // DELPHI_CSVWRITER_HPP diff --git a/lib/DelphiPython.cpp b/lib/DelphiPython.cpp index f5112ebf7..f9184b0a0 100644 --- a/lib/DelphiPython.cpp +++ b/lib/DelphiPython.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "AnalysisGraph.hpp" #include "exceptions.hpp" @@ -61,11 +62,28 @@ PYBIND11_MODULE(DelphiPython, m) { .def_static("from_causal_fragments", &AnalysisGraph::from_causal_fragments, "causal_fragments"_a) + .def_static("from_causal_fragments_with_data", + &AnalysisGraph::from_causal_fragments_with_data, + "cag_ind_data"_a, + "kde_kernels"_a = 5) + .def_static("generate_random_CAG", + &AnalysisGraph::generate_random_CAG, + "num_nodes"_a, + "num_extra_edges"_a = 0) + .def("generate_synthetic_data", + &AnalysisGraph::generate_synthetic_data, + "num_obs"_a = 48, + "noise_variance"_a = 0.1, + "kde_kernels"_a = 1000, + "initial_beta"_a = InitialBeta::PRIOR, + "initial_derivative"_a = InitialDerivative::DERI_PRIOR, + "use_continuous"_a = false) .def("__len__", &AnalysisGraph::num_vertices) .def("__getitem__", [](AnalysisGraph& G, string name) { return G[name]; }) .def("__getitem__", [](AnalysisGraph& G, int node_index) { return G[node_index]; }) .def("get_res", &AnalysisGraph::get_res) + .def("get_MAP_log_likelihood", &AnalysisGraph::get_MAP_log_likelihood) .def("get_subgraph_for_concept", &AnalysisGraph::get_subgraph_for_concept, "concept"_a, @@ -143,21 +161,6 @@ PYBIND11_MODULE(DelphiPython, m) { .def("delete_all_indicators", &AnalysisGraph::delete_all_indicators, "concept"_a) - .def("test_inference_with_synthetic_data", - &AnalysisGraph::test_inference_with_synthetic_data, - "start_year"_a = 2015, - "start_month"_a = 1, - "end_year"_a = 2015, - "end_month"_a = 12, - "res"_a = 100, - "burn"_a = 900, - "country"_a = "South Sudan", - "state"_a = "", - "county"_a = "", - py::arg("units") = map{}, - "initial_beta"_a = InitialBeta::HALF, - "initial_derivative"_a = InitialDerivative::DERI_ZERO, - "use_continuous"_a = true) .def("train_model", &AnalysisGraph::train_model, "start_year"_a = 2012, @@ -181,9 +184,20 @@ PYBIND11_MODULE(DelphiPython, m) { "initial_beta"_a = InitialBeta::ZERO, "initial_derivative"_a = InitialDerivative::DERI_ZERO, "use_heuristic"_a = false, - "use_continuous"_a = true) + "use_continuous"_a = true, + "train_start_timestep"_a = 0, + "train_timesteps"_a = -1, + "concept_periods"_a = unordered_map(), + "concept_center_measures"_a = unordered_map(), + "concept_models"_a = unordered_map(), + "concept_min_vals"_a = unordered_map(), + "concept_max_vals"_a = unordered_map(), + "ext_concepts"_a = + unordered_map>()) .def("generate_prediction", - &AnalysisGraph::generate_prediction, + static_cast + (&AnalysisGraph::generate_prediction), "start_year"_a, "start_month"_a, "end_year"_a, @@ -191,6 +205,15 @@ PYBIND11_MODULE(DelphiPython, m) { "constraints"_a = ConstraintSchedule(), "one_off"_a = true, "clamp_deri"_a = true) + .def("generate_prediction", + static_cast + (&AnalysisGraph::generate_prediction), + "pred_start_timestep"_a, + "pred_timesteps"_a, + "constraints"_a = ConstraintSchedule(), + "one_off"_a = true, + "clamp_deri"_a = true) .def("run_causemos_projection_experiment_from_json_string", &AnalysisGraph::run_causemos_projection_experiment_from_json_string, "json_string"_a) @@ -211,6 +234,8 @@ PYBIND11_MODULE(DelphiPython, m) { .def("serialize_to_json_string", &AnalysisGraph::serialize_to_json_string, "verbose"_a = true) + .def("export_create_model_json_string", + &AnalysisGraph::export_create_model_json_string) .def("get_complete_state", &AnalysisGraph::get_complete_state) .def("write_model_to_db", diff --git a/lib/Indicator.cpp b/lib/Indicator.cpp index 6174bd339..9eab019f4 100644 --- a/lib/Indicator.cpp +++ b/lib/Indicator.cpp @@ -10,17 +10,31 @@ using namespace std; namespace rs = ranges; void Indicator::set_default_unit() { - sqlite3* db; - int rc = sqlite3_open(getenv("DELPHI_DB"), &db); - if (rc) { - fmt::print("Could not open db"); - return; + // TODO: Repeated code block + // An exact copy of the method AnalysisGraph::open_delphi_db() + // defined in database.cpp + // vvvvvvvvvvvvvvvvvvvvvvvvv + char* pPath; + pPath = getenv ("DELPHI_DB"); + if (pPath == NULL) { + cout << "\n\nERROR: DELPHI_DB environment variable containing the path to delphi.db is not set!\n\n"; + exit(1); } + + sqlite3* db = nullptr; + if (sqlite3_open_v2(getenv("DELPHI_DB"), &db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) { + cout << "\n\nERROR: delphi.db does not exist at " << pPath << endl; + cout << sqlite3_errmsg(db) << endl; + exit(1); + } + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // TODO: End repeated code block + vector units; sqlite3_stmt* stmt; string query = "select Unit from indicator where `Variable` like '" + name + "'"; - rc = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL); + int rc = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL); while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { string ind_unit = string(reinterpret_cast(sqlite3_column_text(stmt, 0))); diff --git a/lib/Node.hpp b/lib/Node.hpp index 168431636..1cf4e3df1 100644 --- a/lib/Node.hpp +++ b/lib/Node.hpp @@ -5,10 +5,38 @@ #include "utils.hpp" #include "Indicator.hpp" #include "exceptions.hpp" +#include class Node { public: std::string name = ""; + double mean = 0; + double std = 1; + std::vector generated_latent_sequence = {}; + int period = 1; + // Access: + // {partition --> ([time step], [data value])} + std::unordered_map, std::vector>> partitioned_data = {}; + std::unordered_map, std::vector>> partitioned_absolute_change = {}; + std::unordered_map, std::vector>> partitioned_relative_change = {}; + std::unordered_map> partition_mean_std = {}; + std::vector absolute_change_medians = {}; + std::vector relative_change_medians = {}; + + std::vector centers = {}; + std::vector spreads = {}; + std::vector changes = {}; + std::vector generated_monthly_latent_centers_for_a_year = std::vector(12, 0); + std::vector generated_monthly_latent_spreads_for_a_year = std::vector(12, 0); + + std::string center_measure = "median"; // median or mean + std::string model = "center"; // center, absolute_change, relative_change + + bool has_max = false; + bool has_min = false; + double max_val = std::numeric_limits::max(); + double min_val = std::numeric_limits::min(); + bool visited; LatentVar rv; std::string to_string() { return this->name; } diff --git a/lib/Timer.hpp b/lib/Timer.hpp new file mode 100644 index 000000000..99028cec9 --- /dev/null +++ b/lib/Timer.hpp @@ -0,0 +1,42 @@ +// +// Created by Manujinda Wathugala on 8/25/21. +// + +#ifndef DELPHI_TIMER_H +#define DELPHI_TIMER_H + +#include +#include +#include + +class Timer { + private: + std::string task; + std::chrono::time_point start_timepoint; + std::pair, std::vector> &store; + + public: + Timer(std::string task, std::pair, + std::vector> &store): store(store), task(task){ + start_timepoint = std::chrono::high_resolution_clock::now(); + }; + + ~Timer() { + this->stop(); + }; + + void stop() { + std::chrono::time_point end_timepoint + = std::chrono::high_resolution_clock::now(); + + auto start = std::chrono::time_point_cast + (start_timepoint).time_since_epoch().count(); + auto end = std::chrono::time_point_cast + (end_timepoint).time_since_epoch().count(); + + this->store.first.push_back(task); + this->store.second.push_back(end - start); + }; +}; + +#endif // DELPHI_TIMER_H diff --git a/lib/causemos_integration.cpp b/lib/causemos_integration.cpp index 6cd327f1a..b7a0a35de 100644 --- a/lib/causemos_integration.cpp +++ b/lib/causemos_integration.cpp @@ -11,6 +11,7 @@ using namespace std; using namespace delphi::utils; using namespace fmt::literals; +using fmt::print; /* ============================================================================ @@ -227,8 +228,10 @@ vector AnalysisGraph::infer_modeling_period( vector observation_timesteps(epochs_sorted.size()); transform(epochs_sorted.begin(), epochs_sorted.end(), observation_timesteps.begin(), [&](long epoch) { - return this->epoch_to_timestep(epoch, this->train_start_epoch, - this->modeling_period); + //return this->epoch_to_timestep(epoch, this->train_start_epoch, + // this->modeling_period); + return this->epoch_to_timestep(epoch, 0, + this->modeling_period); }); this->observation_timestep_gaps.clear(); @@ -240,6 +243,123 @@ vector AnalysisGraph::infer_modeling_period( return epochs_sorted; } + +void AnalysisGraph::infer_concept_period(const ConceptIndicatorEpochs &concept_indicator_epochs) { + double milliseconds_per_day = 24 * 60 * 60 * 1000.0; + int min_days_global = INT32_MAX; + int start_day = INT32_MAX; + this->modeling_period = 1; + + for (int concept_id = 0; concept_id < concept_indicator_epochs.size(); + concept_id++) { + vector ind_epochs = concept_indicator_epochs[concept_id]; + sort(ind_epochs.begin(), ind_epochs.end()); + + vector ind_days(ind_epochs.size()); + transform(ind_epochs.begin(), ind_epochs.end(), ind_days.begin(), + [&](long epoch) { + return round(epoch / milliseconds_per_day); + }); + + vector> year_month_dates(ind_epochs.size()); + transform(ind_epochs.begin(), ind_epochs.end(), + year_month_dates.begin(), + [&](long epoch) { + return this->timestamp_to_year_month_date(epoch); + }); + + vector gaps_in_months(year_month_dates.size() - 1); + + int shortest_monthly_gap_ind = INT32_MAX; + for (int ts = 0; ts < year_month_dates.size() - 1; ts++) { + int months = delphi::utils::months_between(year_month_dates[ts], year_month_dates[ts + 1]); + gaps_in_months[ts] = months; + + if (months < shortest_monthly_gap_ind) { + shortest_monthly_gap_ind = months; + } + } + +// vector gaps(ind_epochs.size()); +// adjacent_difference(ind_epochs.begin(), ind_epochs.end(), gaps.begin()); +// +// vector days_between(gaps.size() - 1); +// transform(gaps.begin() + 1, gaps.end(), days_between.begin(), +// [&](long gap) { +// return round(gap / milliseconds_per_day); +// }); + vector days_between(ind_days.size()); + adjacent_difference(ind_days.begin(), ind_days.end(), days_between.begin()); + + int min_days = INT32_MAX; +// for (int days : days_between) { +// if (days < min_days) { +// min_days = days; +// } +// } + for (int idx = 1; idx < days_between.size(); idx++) { + int days = days_between[idx]; + if (days < min_days) { + min_days = days; + } + } + + if (ind_days[0] < start_day) { + start_day = ind_days[0]; + } + + if (min_days < min_days_global) { + min_days_global = min_days; + } + + int period = 1; + if (min_days == 1) { + // Daily + period = 365; + } else if (min_days == 7) { + // Weekly + period = 52; + } else if (28 <= min_days && min_days <= 31) { + // Monthly + period = 12; + } else if (59 <= min_days && min_days <= 62) { + // 2 Months + period = 6; + } else if (89 <= min_days && min_days <= 92) { + // 3 Months + period = 4; + } else if (120 <= min_days && min_days <= 123) { + // 4 Months + period = 3; + } else if (181 <= min_days && min_days <= 184) { + // 6 Months + period = 2; + } + /* + else if (365 <= min_days && min_days <= 366) { + // Yearly + } + else if (730 <= min_days && min_days <= 731) { + // 2 Years + } else if (1095 <= min_days && min_days <= 1096) { + // 3 Years + } else if (1460 <= min_days && min_days <= 1461) { + // 4 Years + } else if (1825 <= min_days && min_days <= 1827) { + // 5 Years + } + */ + this->graph[concept_id].period = period; + this->modeling_period = lcm(this->modeling_period, period); + + for (auto yyyy_mm_dd : year_month_dates) { + cout << "(" << get<0>(yyyy_mm_dd) << "-" << get<1>(yyyy_mm_dd) << "-" << get<2>(yyyy_mm_dd) << "), "; + } + cout << endl; + } +} + + /** * Set the observed state sequence from the create model JSON input received * from the HMI. @@ -277,7 +397,57 @@ AnalysisGraph::set_observed_state_sequence_from_json_dict( this->n_timesteps = 0; vector epochs_sorted; + unordered_map> monthly_to_epoch; + if (this->train_start_epoch <= this->train_end_epoch) { + // Convert epochs to months making train_start_epoch = 0 + tuple train_start_date = this->timestamp_to_year_month_date(this->train_start_epoch); + tuple train_end_date = this->timestamp_to_year_month_date(this->train_end_epoch); + + for (int v = 0; v < num_verts; v++) { + int shortest_monthly_gap_ind = INT32_MAX; + for (int obs = 0; obs < concept_indicator_epochs[v].size(); obs++) { + long epoch = concept_indicator_epochs[v][obs]; + tuple obs_date = this->timestamp_to_year_month_date(epoch); + int month = delphi::utils::months_between(train_start_date, obs_date); + concept_indicator_epochs[v][obs] = month; + + monthly_to_epoch[month].insert(epoch); + + // TODO: There are cases this period estimation goes wrong. Need revision. + // e.g. observation months: 1, 3, 5, 8, 10, 12 + // The good solution is to get the gcd of all the observation gaps for a indicator + if (obs > 0) { + int gap = concept_indicator_epochs[v][obs] - + concept_indicator_epochs[v][obs - 1]; + if (gap < shortest_monthly_gap_ind) { + shortest_monthly_gap_ind = gap; + } + } + } + + int period = 1; + if (shortest_monthly_gap_ind == 1) { + // Monthly + period = 12; + } else if (shortest_monthly_gap_ind == 2) { + // 2 Months + period = 6; + } else if (shortest_monthly_gap_ind == 3) { + // 3 Months + period = 4; + } else if (shortest_monthly_gap_ind == 4) { + // 4 Months + period = 3; + } else if (shortest_monthly_gap_ind == 6) { + // 6 Months + period = 2; + } + this->graph[v].period = period; + } +// cout << "Inferring periods\n"; +// this->infer_concept_period(concept_indicator_epochs); + // Some training data has been provided epochs_sorted = this->infer_modeling_period(concept_indicator_epochs, shortest_gap, @@ -307,12 +477,15 @@ AnalysisGraph::set_observed_state_sequence_from_json_dict( for (int i = 0; i < n.indicators.size(); i++) { this->observed_state_sequence[ts][v][i] = vector(); - pair::iterator, - multimap::iterator> obs = - concept_indicator_data[v][i].equal_range(epochs_sorted[ts]); + for (long epochs_in_ts : monthly_to_epoch[epochs_sorted[ts]]) { + pair::iterator, + multimap::iterator> + obs = concept_indicator_data[v][i].equal_range(epochs_in_ts); - for(auto it = obs.first; it != obs.second; it++) { - this->observed_state_sequence[ts][v][i].push_back(it->second); + for (auto it = obs.first; it != obs.second; it++) { + this->observed_state_sequence[ts][v][i].push_back( + it->second); + } } } } @@ -449,7 +622,8 @@ void AnalysisGraph::from_causemos_json_dict(const nlohmann::json &json_data, create-experiment (private) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -std::pair AnalysisGraph::timestamp_to_year_month(long timestamp) { +std::tuple +AnalysisGraph::timestamp_to_year_month_date(long timestamp) { // The HMI uses milliseconds. So they multiply time-stamps by 1000. // Before converting them back to year and month, we have to divide // by 1000. @@ -460,8 +634,13 @@ std::pair AnalysisGraph::timestamp_to_year_month(long timestamp) { struct tm *ptm = gmtime(×tamp); int year = 1900 + ptm->tm_year; int month = 1 + ptm->tm_mon; + int date = ptm->tm_mday; + + if (date > 1) { + print("* * * * * WARNING: Observation timestamp {0}-{1}-{2} does not adhere to the protocol!\n", year, month, date); + } - return make_pair(year, month); + return make_tuple(year, month, date); } void AnalysisGraph::extract_projection_constraints( @@ -541,12 +720,23 @@ AnalysisGraph::run_causemos_projection_experiment_from_json_dict( this->delta_t = 1; this->pred_timesteps++; } else { + /* this->pred_start_timestep = this->epoch_to_timestep( proj_start_epoch, this->train_start_epoch, this->modeling_period); double pred_end_timestep = this->epoch_to_timestep( proj_end_epoch, this->train_start_epoch, this->modeling_period); this->delta_t = (pred_end_timestep - this->pred_start_timestep) / (this->pred_timesteps - 1.0); + */ + tuple train_start_date = this->timestamp_to_year_month_date(this->train_start_epoch); + tuple pred_start_date = this->timestamp_to_year_month_date(proj_start_epoch); + this->pred_start_timestep = delphi::utils::months_between(train_start_date, pred_start_date); + this->delta_t = 1; + + tuple pred_end_date = this->timestamp_to_year_month_date(proj_end_epoch); + //int num_pred_months = delphi::utils::months_between(pred_start_date, pred_end_date); + //cout << "(" << get<0>(pred_end_date) << "-" << get<1>(pred_end_date) << "-" << get<2>(pred_end_date) << "), "; + //cout << "(" << get<0>(pred_start_date) << "-" << get<1>(pred_start_date) << "-" << get<2>(pred_start_date) << "), "; // To help clamping we predict one additional timestep this->pred_timesteps++; @@ -562,10 +752,12 @@ AnalysisGraph::run_causemos_projection_experiment_from_json_dict( */ } + /* if (this->pred_start_timestep > pred_end_timestep) { throw BadCausemosInputException( "Projection end epoch is before projection start epoch"); } + */ } this->extract_projection_constraints(projection_parameters["constraints"], skip_steps); diff --git a/lib/constructors.cpp b/lib/constructors.cpp index 4a83e7ca2..318125ae8 100644 --- a/lib/constructors.cpp +++ b/lib/constructors.cpp @@ -116,6 +116,64 @@ AnalysisGraph::from_causal_fragments(vector causal_fragments) { return G; } +AnalysisGraph +AnalysisGraph::from_causal_fragments_with_data(pair, + ConceptIndicatorAlignedData> cag_ind_data, + int kde_kernels) { + AnalysisGraph G = from_causal_fragments(cag_ind_data.first); + + G.set_res(kde_kernels); + + G.observed_state_sequence.clear(); + G.n_timesteps = 0; + + // NOTE: Only one indicator per concept + for (const auto & [ concept, ind_data ] : cag_ind_data.second) { + G.set_indicator(concept, ind_data.first, ""); + + if (G.n_timesteps < ind_data.second.size()) { + G.n_timesteps = ind_data.second.size(); + } + } + + // Access (concept is a vertex in the CAG) + // [ timestep ][ concept ][ indicator ][ observation ] + G.observed_state_sequence = ObservedStateSequence(G.n_timesteps); + + int num_verts = G.num_vertices(); + + // Fill in observed state sequence + // NOTE: This code is very similar to the implementations in + // set_observed_state_sequence_from_data and get_observed_state_from_data + for (int ts = 0; ts < G.n_timesteps; ts++) { + G.observed_state_sequence[ts] = vector>>(num_verts); + + for (const auto & [ concept, ind_data ] : cag_ind_data.second) { + int v = G.name_to_vertex.at(concept); + + Node& n = G[v]; + G.observed_state_sequence[ts][v] = vector>(n.indicators.size()); + + // Only one indicator per concept => i = 0 + for (int i = 0; i < n.indicators.size(); i++) { + G.observed_state_sequence[ts][v][i] = vector(); + + if (ts < ind_data.second.size()) { + G.observed_state_sequence[ts][v][i].push_back(ind_data.second[ts]); + } + } + } + } + + G.modeling_period = 1; + G.train_start_epoch = 0; + G.observation_timestep_gaps.clear(); + G.observation_timestep_gaps = vector(G.n_timesteps, 1.0); + G.observation_timestep_gaps[0] = 0; + + return G; +} + AnalysisGraph AnalysisGraph::from_json_string(string json_string) { auto data = nlohmann::json::parse(json_string); AnalysisGraph G; diff --git a/lib/data.cpp b/lib/data.cpp index a6492cd03..efe43be25 100644 --- a/lib/data.cpp +++ b/lib/data.cpp @@ -19,25 +19,35 @@ vector get_observations_for(string indicator, using fmt::print; using namespace fmt::literals; + // TODO: Repeated code block + // An exact copy of the method AnalysisGraph::open_delphi_db() + // defined in database.cpp + // vvvvvvvvvvvvvvvvvvvvvvvvv + char* pPath; + pPath = getenv ("DELPHI_DB"); + if (pPath == NULL) { + cout << "\n\nERROR: DELPHI_DB environment variable containing the path to delphi.db is not set!\n\n"; + exit(1); + } + sqlite3* db = nullptr; + if (sqlite3_open_v2(getenv("DELPHI_DB"), &db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) { + cout << "\n\nERROR: delphi.db does not exist at " << pPath << endl; + cout << sqlite3_errmsg(db) << endl; + exit(1); + } + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // TODO: End repeated code block vector observations = {}; - int rc; - rc = sqlite3_open(getenv("DELPHI_DB"), &db); - if (rc != SQLITE_OK) { - throw runtime_error("Could not open db. Do you have the DELPHI_DB " - "environment correctly set to point to the Delphi database?"); - } - sqlite3_stmt* stmt = nullptr; + string check_q; string query = "select Unit, Value from indicator where `Variable` like '{}'"_format( indicator); - string check_q; - if (!country.empty()) { check_q = "{0} and `Country` is '{1}'"_format(query, country); diff --git a/lib/database.cpp b/lib/database.cpp index c12d8c1df..4981d1b32 100644 --- a/lib/database.cpp +++ b/lib/database.cpp @@ -1,23 +1,39 @@ -#include #include "AnalysisGraph.hpp" using namespace std; +using namespace delphi::utils; + +sqlite3* AnalysisGraph::open_delphi_db(int mode) { + char* pPath; + pPath = getenv ("DELPHI_DB"); + if (pPath == NULL) { + cout << "\n\nERROR: DELPHI_DB environment variable containing the path to delphi.db is not set!\n\n"; + exit(1); + } + + sqlite3* db = nullptr; + if (sqlite3_open_v2(getenv("DELPHI_DB"), &db, mode, NULL) != SQLITE_OK) { + cout << "\n\nERROR: delphi.db does not exist at " << pPath << endl; + cout << sqlite3_errmsg(db) << endl; + exit(1); + } + + return db; +} void AnalysisGraph::write_model_to_db(string model_id) { if (!model_id.empty()) { - sqlite3* db = nullptr; - int rc = sqlite3_open(getenv("DELPHI_DB"), &db); - //int rc = sqlite3_open("/tmp/test.db", &db); + sqlite3* db = this->open_delphi_db(SQLITE_OPEN_READWRITE); - if (rc != SQLITE_OK) { - cout << "Could not open db\n"; - // throw "Could not open db\n"; + if (db == nullptr) { + cout << "\n\nERROR: opening delphi.db" << endl; + exit(1); } char* zErrMsg = 0; string query = "replace into delphimodel values ('" + model_id + "', '" + this->serialize_to_json_string(false) + "');"; - rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg); + int rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg); if (rc != SQLITE_OK) { cout << "Could not write\n"; @@ -27,4 +43,54 @@ void AnalysisGraph::write_model_to_db(string model_id) { sqlite3_close(db); db = nullptr; } -} \ No newline at end of file +} + +/** + * This is a helper function used by construct_theta_pdfs() + */ +AdjectiveResponseMap AnalysisGraph::construct_adjective_response_map( + mt19937 gen, + uniform_real_distribution& uni_dist, + normal_distribution& norm_dist, + size_t n_kernels +) { + sqlite3* db = this->open_delphi_db(SQLITE_OPEN_READONLY); + + if (db == nullptr) { + cout << "\n\nERROR: opening delphi.db" << endl; + exit(1); + } + + sqlite3_stmt* stmt = nullptr; + const char* query = "select * from gradableAdjectiveData"; + int rc = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + + if (rc != SQLITE_OK) { + cout << "\n\nERROR: Could not execute query \"" << query << "\" on delphi.db" << endl; + cout << sqlite3_errmsg(db) << endl; + exit(1); + } + + AdjectiveResponseMap adjective_response_map; + + while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { + string adjective = + string(reinterpret_cast(sqlite3_column_text(stmt, 2))); + double response = sqlite3_column_double(stmt, 6); + if (!in(adjective_response_map, adjective)) { + adjective_response_map[adjective] = {response}; + } + else { + adjective_response_map[adjective].push_back(response); + } + } + + for (auto& [k, v] : adjective_response_map) { + v = KDE(v).resample(n_kernels, gen, uni_dist, norm_dist); + } + sqlite3_finalize(stmt); + sqlite3_close(db); + stmt = nullptr; + db = nullptr; + return adjective_response_map; +} diff --git a/lib/format_output.cpp b/lib/format_output.cpp index a79fa5121..d29e1ab68 100644 --- a/lib/format_output.cpp +++ b/lib/format_output.cpp @@ -119,8 +119,8 @@ CompleteState AnalysisGraph::get_complete_state() { } predictions[ind_name] = preds; - //for (int ts = 0; ts < num_data_points; ts++) { - for (int ts = 0; ts < this->n_timesteps; ts++) { + //for (int ts = 0; ts < this->n_timesteps; ts++) { + for (int ts = 0; ts < this->observed_state_sequence.size(); ts++) { for (double obs : this->observed_state_sequence[ts][vert_id][ind_id]) { data["Time Step"].push_back(ts); data["Data"].push_back(obs); @@ -130,22 +130,26 @@ CompleteState AnalysisGraph::get_complete_state() { } } - std::vector data_range(this->n_timesteps); + //std::vector data_range(this->n_timesteps); + std::vector data_range(this->observed_state_sequence.size()); double timestep = 0; - for (int ts = 0; ts < this->n_timesteps; ts++) { + //for (int ts = 0; ts < this->n_timesteps; ts++) { + for (int ts = 0; ts < this->observed_state_sequence.size(); ts++) { timestep += this->observation_timestep_gaps[ts]; - data_range[ts] = this->train_start_epoch + - timestep * this->modeling_period; + //data_range[ts] = this->train_start_epoch + + // timestep * this->modeling_period; + data_range[ts] = timestep; } std::vector prediction_range(this->pred_timesteps); for (int ts = 0; ts < this->pred_timesteps; ts++) { - prediction_range[ts] = this->train_start_epoch + (this->pred_start_timestep + ts * this->delta_t) * this->modeling_period; + //prediction_range[ts] = this->train_start_epoch + (this->pred_start_timestep + ts * this->delta_t) * this->modeling_period; + prediction_range[ts] = this->pred_start_timestep + ts * this->delta_t; } CredibleIntervals cis = get_credible_interval(predictions); //return std::make_tuple(concept_indicators, edges, adjectives, polarities, thetas, derivatives, data_range, data_set, this->pred_range, predictions, cis); - return std::make_tuple(concept_indicators, edges, adjectives, polarities, thetas, derivatives, data_range, data_set, prediction_range, predictions, cis); + return std::make_tuple(concept_indicators, edges, adjectives, polarities, thetas, derivatives, data_range, data_set, prediction_range, predictions, cis, this->log_likelihoods); } diff --git a/lib/graph_building.cpp b/lib/graph_building.cpp index fb4b0ad3a..27d6d6860 100644 --- a/lib/graph_building.cpp +++ b/lib/graph_building.cpp @@ -12,12 +12,15 @@ using namespace fmt::literals; ============================================================================ */ -void AnalysisGraph::add_node(string concept) { +int AnalysisGraph::add_node(string concept) { if (!in(this->name_to_vertex, concept)) { int v = boost::add_vertex(this->graph); this->name_to_vertex[concept] = v; (*this)[v].name = concept; + this->head_nodes.insert(v); } + + return this->name_to_vertex[concept]; } bool AnalysisGraph::add_edge(CausalFragment causal_fragment) { @@ -29,8 +32,21 @@ bool AnalysisGraph::add_edge(CausalFragment causal_fragment) { if (subj_name.compare(obj_name) != 0) { // Guard against self loops // Add the nodes to the graph if they are not in it already - this->add_node(subj_name); - this->add_node(obj_name); + int subj_id = this->add_node(subj_name); + int obj_id = this->add_node(obj_name); + + // Object is a dependent node + this->body_nodes.insert(obj_id); + + // If Object had been an independent node, it no linger is + if (this->head_nodes.find(obj_id) != this->head_nodes.end()) { + this->head_nodes.erase(obj_id); + } + + // If Subject was not a dependent node, it is independent +// if (this->body_nodes.find(subj_id) == this->body_nodes.end()) { +// this->head_nodes.insert(subj_id); +// } auto [e, exists] = this->add_edge(subj_name, obj_name); this->graph[e].evidence.push_back(Statement{subject, object}); @@ -100,6 +116,14 @@ pair AnalysisGraph::add_edge(int source, int target) { if (!edge.second) { edge = boost::add_edge(source, target, this->graph); + + // Object is a dependent node + this->body_nodes.insert(target); + + // If Object had been an independent node, it no linger is + if (this->head_nodes.find(target) != this->head_nodes.end()) { + this->head_nodes.erase(target); + } } return edge; diff --git a/lib/head_nodes.cpp b/lib/head_nodes.cpp new file mode 100644 index 000000000..ba2a0a460 --- /dev/null +++ b/lib/head_nodes.cpp @@ -0,0 +1,203 @@ +// Modeling independent CAG nodes + +#include "AnalysisGraph.hpp" + +using namespace std; + +void AnalysisGraph::partition_data_and_calculate_mean_std_for_each_partition( + Node& n, vector& latent_sequence) { + unordered_map> partitioned_data; + + for (int ts = 0; ts < latent_sequence.size(); ts++) { + int partition = ts % n.period; + partitioned_data[partition].push_back(latent_sequence[ts]); + } + + for (const auto & [ partition, data ] : partitioned_data) { +// double partition_mean = delphi::utils::mean(data); + double partition_mean = delphi::utils::median(data); + double partition_std = 1; + + if (data.size() > 1) { + partition_std = delphi::utils::standard_deviation(partition_mean, data); + } + +// n.partition_mean_std[partition] = make_pair(partition_mean, partition_std); + n.partition_mean_std[partition] = make_pair(partition_mean, 1); + } +} + + +void AnalysisGraph::apply_constraint_at(int ts, int node_id) { + if (delphi::utils::in(this->head_node_one_off_constraints, ts)) { + vector> constraint_vec = this->head_node_one_off_constraints.at(ts); + for (auto node_const : constraint_vec) { + if (node_id == node_const.first) { + this->generated_latent_sequence[ts] = node_const.second; + } + } + } +} + + +void AnalysisGraph::generate_head_node_latent_sequence(int node_id, + int num_timesteps, + bool sample, + int seq_no) { + Node &n = (*this)[node_id]; + this->generated_latent_sequence = vector(num_timesteps, 0); + + if (!n.centers.empty()) { + if (n.model.compare("center") == 0) { + for (int ts = 0; ts < num_timesteps; ts++) { + //int partition = ts % n.period; + //this->generated_latent_sequence[ts] = n.centers[partition]; + int partition = ts % n.generated_monthly_latent_centers_for_a_year.size(); // (% 12) + this->generated_latent_sequence[ts] = n.generated_monthly_latent_centers_for_a_year[partition]; + + apply_constraint_at(ts, node_id); + } + } + else if (n.model.compare("absolute_change") == 0) { + this->generated_latent_sequence[0] = n.centers[0]; + for (int ts = 0; ts < num_timesteps - 1; ts++) { + int partition = ts % n.period; + this->generated_latent_sequence[ts + 1] = + this->generated_latent_sequence[ts] + n.changes[partition + 1]; + + apply_constraint_at(ts + 1, node_id); + } + } + else if (n.model.compare("relative_change") == 0) { + this->generated_latent_sequence[0] = n.centers[0]; + for (int ts = 0; ts < num_timesteps - 1; ts++) { + int partition = ts % n.period; + this->generated_latent_sequence[ts + 1] = + this->generated_latent_sequence[ts] + + n.changes[partition + 1] * + (this->generated_latent_sequence[ts] + 1); + + apply_constraint_at(ts + 1, node_id); + } + } + + if (sample) { + for (int ts = 0; ts < num_timesteps; ts++) { + //int partition = ts % n.period; + int partition = ts % n.generated_monthly_latent_spreads_for_a_year.size(); // (% 12) + this->generated_latent_sequence[ts] += + n.generated_monthly_latent_spreads_for_a_year[partition] * norm_dist(this->rand_num_generator); + } + } + else if (seq_no > -1) { + //int sections = 5; // an odd number + //int half_sections = (sections - 1) / 2; + //int turn = seq_no % sections; + double deviation = norm_dist(this->rand_num_generator); + + for (int ts = 0; ts < num_timesteps; ts++) { + //int partition = ts % n.period; + int partition = ts % n.generated_monthly_latent_spreads_for_a_year.size(); // (% 12) + //this->generated_latent_sequence[ts] += + // (turn - half_sections) * n.generated_monthly_latent_spreads_for_a_year[partition]; + this->generated_latent_sequence[ts] += + n.generated_monthly_latent_spreads_for_a_year[partition] * deviation; + apply_constraint_at(ts, node_id); + } + } + + if (n.has_max) { + for (int ts = 0; ts < num_timesteps; ts++) { + if (this->generated_latent_sequence[ts] > n.max_val) { + this->generated_latent_sequence[ts] = n.max_val; + } + } + } + if (n.has_min) { + for (int ts = 0; ts < num_timesteps; ts++) { + if (this->generated_latent_sequence[ts] < n.min_val) { + this->generated_latent_sequence[ts] = n.min_val; + } + } + } + } +} + + +void AnalysisGraph::generate_head_node_latent_sequence_from_changes(Node &n, + int num_timesteps, + bool sample) { + this->generated_latent_sequence = vector(num_timesteps); + this->generated_latent_sequence[0] = n.centers[0]; + + for (int ts = 0; ts < num_timesteps - 1; ts++) { + int partition = ts % n.period; + + if (n.model.compare("absolute_change") == 0) { + this->generated_latent_sequence[ts + 1] = + this->generated_latent_sequence[ts] + n.changes[partition + 1]; + } else if (n.model.compare("relative_change") == 0) { + this->generated_latent_sequence[ts + 1] = + this->generated_latent_sequence[ts] + n.changes[partition + 1] + * (this->generated_latent_sequence[ts] + 1); + } + } + + if (sample) { + for (int ts = 0; ts < num_timesteps; ts++) { + int partition = ts % n.period; + this->generated_latent_sequence[ts] += + n.spreads[partition] * norm_dist(this->rand_num_generator); + } + } +} + + +void AnalysisGraph::generate_head_node_latent_sequences(int samp, int num_timesteps) { + for (int v : this->head_nodes) { + Node &n = (*this)[v]; + + unordered_map> partition_mean_std; + vector change_medians; + + /* + if (samp > -1) { + //partition_mean_std = this->latent_mean_std_collection[samp][v]; + } + else { + //partition_mean_std = n.partition_mean_std; + samp = 0; + } + */ + + this->generate_head_node_latent_sequence(v, num_timesteps, false, samp); +// this->generate_head_node_latent_sequence_from_changes(n, num_timesteps, false); + + n.generated_latent_sequence.clear(); + n.generated_latent_sequence = this->generated_latent_sequence; + } +} + +void AnalysisGraph::update_head_node_latent_state_with_generated_derivatives( + int ts_current, + int ts_next, + int concept_id, + vector& latent_sequence) { + if (concept_id > -1 && ts_current < latent_sequence.size() - 1) { + this->current_latent_state[2 * concept_id + 1] = latent_sequence[ts_next] + - latent_sequence[ts_current]; + + if (ts_current == 0) { + this->current_latent_state[2 * concept_id] = latent_sequence[0]; + } + } +} + +void AnalysisGraph::update_latent_state_with_generated_derivatives( + int ts_current, int ts_next) { + for (int v : this->head_nodes) { + Node &n = (*this)[v]; + this->update_head_node_latent_state_with_generated_derivatives( + ts_current, ts_next, v, n.generated_latent_sequence); + } +} diff --git a/lib/indicator_manipulation.cpp b/lib/indicator_manipulation.cpp index a586c7e64..ec5a5b4e4 100644 --- a/lib/indicator_manipulation.cpp +++ b/lib/indicator_manipulation.cpp @@ -42,14 +42,14 @@ void AnalysisGraph::delete_all_indicators(string concept) { void AnalysisGraph::map_concepts_to_indicators(int n_indicators, string country) { - sqlite3* db = nullptr; - int rc = sqlite3_open(getenv("DELPHI_DB"), &db); - if (rc != SQLITE_OK) { - throw runtime_error( - "Could not open db. Do you have the DELPHI_DB " - "environment correctly set to point to the Delphi database?"); + sqlite3* db = this->open_delphi_db(SQLITE_OPEN_READONLY); + + if (db == nullptr) { + cout << "\n\nERROR: opening delphi.db" << endl; + exit(1); } + int rc; sqlite3_stmt* stmt = nullptr; string query_base = "select Indicator from concept_to_indicator_mapping "; string query; diff --git a/lib/parameter_initialization.cpp b/lib/parameter_initialization.cpp index 1dd064181..279a9b6bb 100644 --- a/lib/parameter_initialization.cpp +++ b/lib/parameter_initialization.cpp @@ -1,6 +1,7 @@ #include "AnalysisGraph.hpp" #include #include +#include using namespace std; using namespace delphi::utils; @@ -20,7 +21,8 @@ void AnalysisGraph::initialize_parameters(int res, bool use_heuristic, bool use_continuous) { this->initialize_random_number_generator(); - this->uni_disc_dist = uniform_int_distribution(0, this->num_nodes() - 1); + this->uni_disc_dist = uniform_int_distribution + (0, this->concept_sample_pool.size() - 1); this->res = res; this->continuous = use_continuous; @@ -33,13 +35,24 @@ void AnalysisGraph::initialize_parameters(int res, this->set_transition_matrix_from_betas(); this->derivative_prior_variance = 0.1; this->set_default_initial_state(initial_derivative); + //this->generate_head_node_latent_sequences(-1, this->n_timesteps); + this->generate_head_node_latent_sequences(-1, accumulate(this->observation_timestep_gaps.begin() + 1, + this->observation_timestep_gaps.end(), 0) + 1); this->set_log_likelihood(); + this->log_likelihood_MAP = -(DBL_MAX - 1); this->transition_matrix_collection.clear(); this->initial_latent_state_collection.clear(); + //this->latent_mean_collection.clear(); + //this->latent_std_collection.clear(); + //this->latent_mean_std_collection.clear(); this->transition_matrix_collection = vector(this->res); this->initial_latent_state_collection = vector(this->res); + //this->latent_mean_collection = vector>(this->res); + //this->latent_std_collection = vector>(this->res); + //this->latent_mean_std_collection = vector>>>(this->res); } void AnalysisGraph::init_betas_to(InitialBeta ib) { @@ -215,51 +228,178 @@ void AnalysisGraph::set_indicator_means_and_standard_deviations() { // To avoid division by zero error later on ind.set_mean(0.0001); } - } - } -} -/** - * This is a helper function used by construct_theta_pdfs() - */ -AdjectiveResponseMap construct_adjective_response_map( - mt19937 gen, - uniform_real_distribution& uni_dist, - normal_distribution& norm_dist, - size_t n_kernels - ) { - sqlite3* db = nullptr; - int rc = sqlite3_open(getenv("DELPHI_DB"), &db); - - if (rc == 1) - throw "Could not open db\n"; - - sqlite3_stmt* stmt = nullptr; - const char* query = "select * from gradableAdjectiveData"; - rc = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); - - AdjectiveResponseMap adjective_response_map; - - while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { - string adjective = - string(reinterpret_cast(sqlite3_column_text(stmt, 2))); - double response = sqlite3_column_double(stmt, 6); - if (!in(adjective_response_map, adjective)) { - adjective_response_map[adjective] = {response}; - } - else { - adjective_response_map[adjective].push_back(response); - } - } + // Set mean and standard deviation of the concept based on the mean + // and the standard deviation of the first indicator attached to it. + if (i == 0) { + transform(mean_sequence.begin(), mean_sequence.end(), + mean_sequence.begin(), + [&](double v){return v / n.indicators[0].mean;}); + + for (int ts = 0; ts < ts_sequence.size(); ts++) { + // TODO: I feel that this partitioning is worng. Should be corrected as: + // First we convert the observation time steps for an indicator into a + // zero based contiguous sequence and then take the modules + // int((ts_sequence[ts] - ts_sequence[0]) * n.period / 12) % n.period + //int partition = ts_sequence[ts] % n.period; + int partition = int((ts_sequence[ts] - ts_sequence[0]) * n.period / 12) % n.period; + n.partitioned_data[partition].first.push_back(ts_sequence[ts]); + n.partitioned_data[partition].second.push_back(mean_sequence[ts]); + } + + double center; + vector filled_months; + n.centers = vector(n.period + 1); + n.spreads = vector(n.period); + for (const auto & [ partition, data ] : n.partitioned_data) { + if (n.center_measure.compare("mean") == 0) { + center = delphi::utils::mean(n.partitioned_data[partition].second); + } else { + center = delphi::utils::median(n.partitioned_data[partition].second); + } + n.centers[partition] = center; + + double spread = 0; + if (n.partitioned_data[partition].second.size() > 1) { + if (n.center_measure.compare("mean") == 0) { + spread = delphi::utils::standard_deviation(center, + n.partitioned_data[partition].second); + } else { + spread = delphi::utils::median_absolute_deviation(center, + n.partitioned_data[partition].second); + } + } + n.spreads[partition] = spread; + + if (!n.partitioned_data[partition].first.empty()) { + int month = n.partitioned_data[partition].first[0] % 12; + n.generated_monthly_latent_centers_for_a_year[month] = center; + n.generated_monthly_latent_spreads_for_a_year[month] = spread; + filled_months.push_back(month); + } + } + + sort(filled_months.begin(), filled_months.end()); + + // Interpolate values for the missing months + if (filled_months.size() > 1) { + for (int i = 0; i < filled_months.size(); i++) { + int month_start = filled_months[i]; + int month_end = filled_months[(i + 1) % filled_months.size()]; + + int num_missing_months = 0; + if (month_end > month_start) { + num_missing_months = month_end - month_start - 1; + } + else { + num_missing_months = (11 - month_start) + month_end; + } + + for (int month_missing = 1; + month_missing <= num_missing_months; + month_missing++) { + n.generated_monthly_latent_centers_for_a_year + [(month_start + month_missing) % 12] = + ((num_missing_months - month_missing + 1) * + n.generated_monthly_latent_centers_for_a_year + [month_start] + + (month_missing)*n + .generated_monthly_latent_centers_for_a_year + [month_end]) / + (num_missing_months + 1); + + n.generated_monthly_latent_spreads_for_a_year + [(month_start + month_missing) % 12] = + ((num_missing_months - month_missing + 1) * + n.generated_monthly_latent_spreads_for_a_year + [month_start] + + (month_missing)*n + .generated_monthly_latent_spreads_for_a_year + [month_end]) / + (num_missing_months + 1); + } + } + } else if (filled_months.size() == 1) { + for (int month = 0; month < n.generated_monthly_latent_centers_for_a_year.size(); month++) { + n.generated_monthly_latent_centers_for_a_year[month] = + n.generated_monthly_latent_centers_for_a_year + [filled_months[0]]; + n.generated_monthly_latent_spreads_for_a_year[month] = + n.generated_monthly_latent_spreads_for_a_year + [filled_months[0]]; + } + } - for (auto& [k, v] : adjective_response_map) { - v = KDE(v).resample(n_kernels, gen, uni_dist, norm_dist); + n.changes = vector(n.centers.size(), 0.0); + n.centers[n.period] = n.centers[0]; + if (n.model.compare("center") != 0) { + // model == absolute_change + adjacent_difference( + n.centers.begin(), n.centers.end(), n.changes.begin()); + if (n.model.compare("relative_change") == 0) { + transform(n.centers.begin(), + n.centers.end() - 1, + n.changes.begin() + 1, + n.changes.begin() + 1, + [&](double start_value, double abs_change) { + return abs_change / (start_value + 1); + }); + } + } + + + // Experiment: First calculate adjacent changes, then partition changes + // and compute the center of each changes partition + /* + // Absolute changes + vector absolute_change = vector(mean_sequence.size()); + adjacent_difference(mean_sequence.begin(), + mean_sequence.end(), + absolute_change.begin()); + + // Relative changes + vector relative_change = vector(mean_sequence.size() - 1); + transform(mean_sequence.begin(), mean_sequence.end() - 1, + absolute_change.begin() + 1, relative_change.begin(), + [&](double start_value, double abs_change){return abs_change / (start_value + 1);}); + + // Partition changes + for (int ts = 0; ts < relative_change.size(); ts++) { + int partition = ts % n.period; + n.partitioned_absolute_change[partition].first.push_back(ts_sequence[ts]); + n.partitioned_absolute_change[partition].second.push_back(absolute_change[ts + 1]); + + n.partitioned_relative_change[partition].first.push_back(ts_sequence[ts]); + n.partitioned_relative_change[partition].second.push_back(relative_change[ts]); + } + + // Compute partition centers + //n.changes = vector(n.period + 1); + for (const auto & [ partition, data ] : n.partitioned_absolute_change) { + double partition_median = delphi::utils::median(data.second); + n.changes[partition + 1] = partition_median; + } + //for (const auto & [ partition, data ] : n.partitioned_relative_change) { + // double partition_median = delphi::utils::median(data.second); + // n.changes[partition + 1] = partition_median; + //} + + // Experimenting with zero centering the centers + //vector only_changes = vector(n.changes.begin() + 1, n.changes.end()); + //double change_mean = delphi::utils::mean(only_changes); + //transform(n.changes.begin() + 1, n.changes.end(), + // n.changes.begin() + 1, + // [&](double val){return val - change_mean;}); + */ + + n.mean = delphi::utils::mean(mean_sequence); + + if (mean_sequence.size() > 1) { + n.std = delphi::utils::standard_deviation(n.mean, mean_sequence); + } + } + } } - sqlite3_finalize(stmt); - sqlite3_close(db); - stmt = nullptr; - db = nullptr; - return adjective_response_map; } void AnalysisGraph::construct_theta_pdfs() { @@ -269,7 +409,7 @@ void AnalysisGraph::construct_theta_pdfs() { double sigma_X = 1.0; double sigma_Y = 1.0; AdjectiveResponseMap adjective_response_map = - construct_adjective_response_map( + this->construct_adjective_response_map( this->rand_num_generator, this->uni_dist, this->norm_dist, this->res); vector marginalized_responses; for (auto [adjective, responses] : adjective_response_map) { diff --git a/lib/prediction.cpp b/lib/prediction.cpp index e881f885e..db3752075 100644 --- a/lib/prediction.cpp +++ b/lib/prediction.cpp @@ -37,23 +37,59 @@ void AnalysisGraph::generate_latent_state_sequences( // matrices. MatrixXd A; + this->generate_head_node_latent_sequences( + samp, initial_prediction_step + this->pred_timesteps); + if (this->continuous) { - // Here A = Ac = this->transition_matrix_collection[samp] (continuous) +// // Here A = Ac = this->transition_matrix_collection[samp] (continuous) +// +// // Evolving the system till the initial_prediction_step +// A = (this->transition_matrix_collection[samp] * +// initial_prediction_step).exp(); +// +// this->predicted_latent_state_sequences[samp][0] = +// A * this->initial_latent_state_collection[samp]; +// +// // After jumping to time step ips - 1, we take one step of length Δt +// // at a time. +// // So compute the transition matrix for a single step. +// // Computing the matrix exponential for a Δt time step. +// // By default we are using Δt = 1 +// // A = e^{Ac * Δt) +// A = (this->transition_matrix_collection[samp] * this->delta_t).exp(); + + ///////////////// + A = this->transition_matrix_collection[samp].exp(); // Evolving the system till the initial_prediction_step - A = (this->transition_matrix_collection[samp] * - initial_prediction_step).exp(); - - this->predicted_latent_state_sequences[samp][0] = - A * this->initial_latent_state_collection[samp]; - - // After jumping to time step ips - 1, we take one step of length Δt - // at a time. - // So compute the transition matrix for a single step. - // Computing the matrix exponential for a Δt time step. - // By default we are using Δt = 1 - // A = e^{Ac * Δt) - A = (this->transition_matrix_collection[samp] * this->delta_t).exp(); + this->current_latent_state = this->initial_latent_state_collection[samp]; + + for (int ts = 0; ts < initial_prediction_step; ts++) { + this->update_latent_state_with_generated_derivatives(ts, ts + 1); + + // Set derivatives for frozen nodes + for (const auto & [ v, deriv_func ] : this->external_concepts) { + const Indicator& ind = this->graph[v].indicators[0]; + this->current_latent_state[2 * v + 1] = deriv_func(ts, ind.mean); + } + + this->current_latent_state = A * this->current_latent_state; + } + //this->update_latent_state_with_generated_derivatives(0, initial_prediction_step); + //this->current_latent_state = A * this->current_latent_state; + + this->update_latent_state_with_generated_derivatives( + initial_prediction_step, initial_prediction_step + 1); + + // Set derivatives for frozen nodes + for (const auto & [ v, deriv_func ] : this->external_concepts) { + const Indicator& ind = this->graph[v].indicators[0]; + this->current_latent_state[2 * v + 1] = + deriv_func(initial_prediction_step, ind.mean); + } + + this->predicted_latent_state_sequences[samp][0] = this->current_latent_state; + ///////////////// } else { // Here A = Ad = this->transition_matrix_collection[samp] (discrete) // This is the discrete transition matrix to take a single step of @@ -61,9 +97,31 @@ void AnalysisGraph::generate_latent_state_sequences( A = this->transition_matrix_collection[samp]; // Evolving the system till the initial_prediction_step - this->predicted_latent_state_sequences[samp][0] = - A.pow(initial_prediction_step) * - this->initial_latent_state_collection[samp]; + this->current_latent_state = this->initial_latent_state_collection[samp]; + + for (int ts = 0; ts < initial_prediction_step; ts++) { + this->update_latent_state_with_generated_derivatives(ts, ts + 1); + + // Set derivatives for frozen nodes + for (const auto & [ v, deriv_func ] : this->external_concepts) { + const Indicator& ind = this->graph[v].indicators[0]; + this->current_latent_state[2 * v + 1] = deriv_func(ts, ind.mean); + } + + this->current_latent_state = A * this->current_latent_state; + } + + this->update_latent_state_with_generated_derivatives( + initial_prediction_step, initial_prediction_step + 1); + + // Set derivatives for frozen nodes + for (const auto & [ v, deriv_func ] : this->external_concepts) { + const Indicator& ind = this->graph[v].indicators[0]; + this->current_latent_state[2 * v + 1] = + deriv_func(initial_prediction_step, ind.mean); + } + + this->predicted_latent_state_sequences[samp][0] = this->current_latent_state; } // Clear out perpetual constraints residual from previous sample @@ -103,8 +161,17 @@ void AnalysisGraph::generate_latent_state_sequences( // The actual line of code represents, // s_t = e^{Ac * Δt } * s_{t-1} // When discrete : s_t = Ad * s_{t-1} - this->predicted_latent_state_sequences[samp][ts] = - A * this->predicted_latent_state_sequences[samp][ts - 1]; + this->current_latent_state = A * this->predicted_latent_state_sequences[samp][ts - 1]; + this->update_latent_state_with_generated_derivatives( + initial_prediction_step + ts, initial_prediction_step + ts + 1); + this->predicted_latent_state_sequences[samp][ts] = this->current_latent_state; + + // Set derivatives for frozen nodes + for (const auto & [ v, deriv_func ] : this->external_concepts) { + const Indicator& ind = this->graph[v].indicators[0]; + this->predicted_latent_state_sequences[samp][ts][2 * v + 1] = + deriv_func(initial_prediction_step + ts, ind.mean); + } if (this->clamp_at_derivative ) { if (ts == this->rest_derivative_clamp_ts) { @@ -479,10 +546,6 @@ void AnalysisGraph::add_constraint(int step, string concept_name, string indicat Indicator& ind = n.indicators[ind_id]; - if (!delphi::utils::in(this->one_off_constraints, step)) { - this->one_off_constraints[step] = vector>(); - } - // We have to clamp the latent state value corresponding to this // indicator such that the probability where the emission Gaussian // emitting the requested indicator value is the highest. For a @@ -499,8 +562,22 @@ void AnalysisGraph::add_constraint(int step, string concept_name, string indicat // comments) double latent_clamp_value = indicator_clamp_value / ind.get_mean(); - this->one_off_constraints[step].push_back( - make_pair(concept_id, latent_clamp_value)); + if (this->head_nodes.find(concept_id) == this->head_nodes.end()) { + if (!delphi::utils::in(this->one_off_constraints, step)) { + this->one_off_constraints[step] = vector>(); + } + + this->one_off_constraints[step].push_back( + make_pair(concept_id, latent_clamp_value)); + } else { + step += this->pred_start_timestep; + if (!delphi::utils::in(this->head_node_one_off_constraints, step)) { + this->head_node_one_off_constraints[step] = vector>(); + } + + this->head_node_one_off_constraints[step].push_back( + make_pair(concept_id, latent_clamp_value)); + } } /* @@ -518,6 +595,8 @@ Prediction AnalysisGraph::generate_prediction(int start_year, bool clamp_deri) { this->is_one_off_constraints = one_off; this->clamp_at_derivative = clamp_deri; + this->one_off_constraints.clear(); + this->head_node_one_off_constraints.clear(); for (auto [step, const_vec] : constraints) { for (auto constraint : const_vec) { @@ -535,6 +614,33 @@ Prediction AnalysisGraph::generate_prediction(int start_year, this->training_range, this->pred_range, this->format_prediction_result()); } +void AnalysisGraph::generate_prediction(int pred_start_timestep, + int pred_timesteps, + ConstraintSchedule constraints, + bool one_off, + bool clamp_deri) { + this->is_one_off_constraints = one_off; + this->clamp_at_derivative = clamp_deri; + this->one_off_constraints.clear(); + this->head_node_one_off_constraints.clear(); + + this->pred_start_timestep = pred_start_timestep - 1; + this->pred_timesteps = pred_timesteps + 1; + + for (auto [step, const_vec] : constraints) { + for (auto constraint : const_vec) { + string concept_name = get<0>(constraint); + string indicator_name = get<1>(constraint); + double value = get<2>(constraint); + + this->add_constraint(step, concept_name, indicator_name, value); + } + } + + this->generate_latent_state_sequences(this->pred_start_timestep); + this->generate_observed_state_sequences(); +} + vector> AnalysisGraph::prediction_to_array(string indicator) { int vert_id = -1; int ind_id = -1; diff --git a/lib/printing.cpp b/lib/printing.cpp index a64cfa58a..2e730f95a 100644 --- a/lib/printing.cpp +++ b/lib/printing.cpp @@ -18,6 +18,16 @@ void AnalysisGraph::print_nodes() { for_each(this->node_indices(), [&](int v) { cout << v << " " << this->graph[v].name << endl; }); + + print("Independent nodes\n"); + for (int v : this->head_nodes) { + cout << v << " " << this->graph[v].name << endl; + } + + print("Dependent nodes\n"); + for (int v : this->body_nodes) { + cout << v << " " << this->graph[v].name << endl; + } } void AnalysisGraph::print_edges() { diff --git a/lib/sampling.cpp b/lib/sampling.cpp index 00723681c..6c6abd564 100644 --- a/lib/sampling.cpp +++ b/lib/sampling.cpp @@ -90,6 +90,7 @@ void AnalysisGraph::set_transition_matrix_from_betas() { this->observation_timestep_gaps.end())) { this->e_A_ts.insert(make_pair(gap, (this->A_original * gap).exp())); } + this->e_A_ts.insert(make_pair(1, this->A_original.exp())); } } @@ -134,21 +135,60 @@ void AnalysisGraph::set_log_likelihood() { } } this->current_latent_state = this->s0; - set_log_likelihood_helper(0); + int ts_monthly = 0; + + for (int ts = 0; ts < this->n_timesteps; ts++) { + + // Set derivatives for frozen nodes + for (const auto & [ v, deriv_func ] : this->external_concepts) { + const Indicator& ind = this->graph[v].indicators[0]; + this->current_latent_state[2 * v + 1] = deriv_func(ts, ind.mean); + } + + for (int ts_gap = 0; ts_gap < this->observation_timestep_gaps[ts]; ts_gap++) { + this->update_latent_state_with_generated_derivatives(ts_monthly, + ts_monthly + 1); + this->current_latent_state = + this->e_A_ts[1] * this->current_latent_state; + ts_monthly++; + } + set_log_likelihood_helper(ts); + } + + /* + this->update_latent_state_with_generated_derivatives(0, 1); + + this->set_log_likelihood_helper(0); for (int ts = 1; ts < this->n_timesteps; ts++) { this->current_latent_state = this->e_A_ts[this->observation_timestep_gaps[ts]] * this->current_latent_state; - set_log_likelihood_helper(ts); + this->update_latent_state_with_generated_derivatives(ts, ts + 1); + this->set_log_likelihood_helper(ts); } + */ } else { // Discretized version this->current_latent_state = this->s0; + int ts_monthly = 0; for (int ts = 0; ts < this->n_timesteps; ts++) { + + // Set derivatives for frozen nodes + for (const auto & [ v, deriv_func ] : this->external_concepts) { + const Indicator& ind = this->graph[v].indicators[0]; + this->current_latent_state[2 * v + 1] = deriv_func(ts, ind.mean); + } + + for (int ts_gap = 0; ts_gap < this->observation_timestep_gaps[ts]; ts_gap++) { + this->update_latent_state_with_generated_derivatives( + ts_monthly, ts_monthly + 1); + this->current_latent_state = + this->A_original * this->current_latent_state; + ts_monthly++; + } set_log_likelihood_helper(ts); - this->current_latent_state = this->A_original * this->current_latent_state; } } } @@ -169,13 +209,24 @@ void AnalysisGraph::sample_from_posterior() { if (acceptance_probability < this->uni_dist(this->rand_num_generator)) { // Reject the sample - this->revert_back_to_previous_state(); + if (this->generated_concept == -1) { + this->revert_back_to_previous_state(); + } + this->log_likelihood = this->previous_log_likelihood; } +// else { +// if (this->generated_concept > -1) { +// Node& n = (*this)[this->generated_concept]; +// this->partition_data_and_calculate_mean_std_for_each_partition +// (n, this->generated_latent_sequence); +// } +// } } void AnalysisGraph::sample_from_proposal() { // Flip a coin and decide whether to perturb a θ or a derivative this->coin_flip = this->uni_dist(this->rand_num_generator); + this->generated_concept = -1; if (this->coin_flip < this->coin_flip_thresh) { // Randomly pick an edge ≡ θ @@ -195,11 +246,20 @@ void AnalysisGraph::sample_from_proposal() { this->update_transition_matrix_cells(e[0]); } else { - // Randomly select a concept to change the derivative - this->changed_derivative = - 2 * this->uni_disc_dist(this->rand_num_generator) + 1; - this->previous_derivative = this->s0[this->changed_derivative]; - this->s0[this->changed_derivative] += this->norm_dist(this->rand_num_generator); + // Randomly select a concept + int concept = this->concept_sample_pool[this->uni_disc_dist(this->rand_num_generator)]; + this->changed_derivative = 2 * concept + 1; + + if (this->head_nodes.find(concept) != this->head_nodes.end()) { + this->generated_concept = concept; + this->generate_head_node_latent_sequence(this->generated_concept, this->n_timesteps, true, 0); + } + else { + // to change the derivative + this->previous_derivative = this->s0[this->changed_derivative]; + this->s0[this->changed_derivative] += + this->norm_dist(this->rand_num_generator); + } } } @@ -240,14 +300,28 @@ double AnalysisGraph::calculate_delta_log_prior() { kde.logpdf(this->previous_theta.second); } else { - // A derivative has been sampled - // We assume the prior for derivative is N(0, 0.1) - // We have to return: log( p(ẋ_new )) - log( p( ẋ_old )) - // After some mathematical simplifications we can derive - // (ẋ_old - ẋ_new)(ẋ_old + ẋ_new) / 2σ² - return (this->previous_derivative - this->s0[this->changed_derivative]) - * (this->previous_derivative + this->s0[this->changed_derivative]) - / (2 * this->derivative_prior_variance); + if (this->generated_concept == -1) { + // A derivative has been sampled + // We assume the prior for derivative is N(0, 0.1) + // We have to return: log( p(ẋ_new )) - log( p( ẋ_old )) + // After some mathematical simplifications we can derive + // (ẋ_old - ẋ_new)(ẋ_old + ẋ_new) / 2σ² + return (this->previous_derivative - this->s0[this->changed_derivative]) * + (this->previous_derivative + this->s0[this->changed_derivative]) / + (2 * this->derivative_prior_variance); + } + else { + // A derivative sequence for an independent node has been generated + // When latent state at ts = 0 is 1, it makes the observation 0 the + // highest probable value. + // The standard deviation of ts = 0 latent state is set to 0.01 + /* + return (1 - this->generated_latent_sequence[0]) * + (1 + this->generated_latent_sequence[0]) / + (2 * 0.01); + */ + return 0; + } } } diff --git a/lib/sandbox.cpp b/lib/sandbox.cpp index 81712c4d3..a30314b65 100644 --- a/lib/sandbox.cpp +++ b/lib/sandbox.cpp @@ -56,7 +56,8 @@ void AnalysisGraph::from_delphi_json_dict(const nlohmann::json& json_data, for (auto& concept_arr : json_data["concepts"]) { // print("{0} \n", concept_arr.value()[0]); // this->add_node(get<1>(concept_arr[0]).get()); - this->add_node(concept_arr["concept"].get()); + int v = this->add_node(concept_arr["concept"].get()); + (*this)[v].period = concept_arr["period"].get(); } for (int v = 0; v < this->num_vertices(); v++) { Node& n = (*this)[v]; @@ -95,8 +96,12 @@ void AnalysisGraph::from_delphi_json_dict(const nlohmann::json& json_data, this->training_range.second.second = json_data["end_month"]; } else { - for (auto& concept_name : json_data["concepts"]) { - this->add_node(concept_name); + //for (auto& concept_name : json_data["concepts"]) { + // this->add_node(concept_name); + //} + for (int i = 0; i < json_data["concepts"].size(); i++) { + int v = this->add_node(json_data["concepts"][i]); + (*this)[v].period = json_data["periods"][i].get(); } for (int v = 0; v < this->num_vertices(); v++) { diff --git a/lib/synthetic_data.cpp b/lib/synthetic_data.cpp index 5e3bfacbf..d4d0f113d 100644 --- a/lib/synthetic_data.cpp +++ b/lib/synthetic_data.cpp @@ -1,7 +1,12 @@ #include "AnalysisGraph.hpp" #include +#include +#include +#include +#include using namespace std; +using namespace delphi::utils; using Eigen::VectorXd; using fmt::print; @@ -12,133 +17,238 @@ using fmt::print; ============================================================================ */ -void AnalysisGraph::set_random_initial_latent_state() { - int num_verts = this->num_vertices(); - - this->set_default_initial_state(); +/* + ============================================================================ + Public: Synthetic data experiment + ============================================================================ +*/ - for (int v = 0; v < num_verts; v++) { - this->s0(2 * v + 1) = 0.1 * this->uni_dist(this->rand_num_generator); +AnalysisGraph AnalysisGraph::generate_random_CAG(unsigned int num_nodes, + unsigned int num_extra_edges) { + AnalysisGraph G; + + G.initialize_random_number_generator(); + + // Get all adjectives. + vector adjectives; + AdjectiveResponseMap adjective_response_map = + G.construct_adjective_response_map(G.rand_num_generator, G.uni_dist, G.norm_dist, 100); + boost::range::copy(adjective_response_map | boost::adaptors::map_keys, + back_inserter(adjectives)); + + vector cag_nodes = {0}; + vector rand_node(2); + vector rand_adjectives(2); + int polarity = 0; + string source = ""; + string target = ""; + int src_idx = 0; + + for (rand_node[1] = 1; rand_node[1] < num_nodes; rand_node[1]++) { + rand_node.clear(); + sample(cag_nodes.begin(), cag_nodes.end(), rand_node.begin(), 1, G.rand_num_generator); + cag_nodes.push_back(rand_node[1]); + + src_idx = G.uni_dist(G.rand_num_generator) < 0.5? 0 : 1; + source = to_string(rand_node[src_idx]); + target = to_string(rand_node[1 - src_idx]); + + sample(adjectives.begin(), adjectives.end(), rand_adjectives.begin(), 2, G.rand_num_generator); + polarity = G.uni_dist(G.rand_num_generator) < 0.5 ? 1 : -1; + + auto causal_fragment = + CausalFragment({rand_adjectives[0], 1, source}, + {rand_adjectives[1], polarity, target}); + G.add_edge(causal_fragment); } -} -void AnalysisGraph::generate_synthetic_latent_state_sequence() { - int num_verts = this->num_vertices(); + num_extra_edges = min(num_extra_edges, (num_nodes - 1) * (num_nodes - 1)); - // Allocate memory for synthetic_latent_state_sequence - this->synthetic_latent_state_sequence.clear(); - this->synthetic_latent_state_sequence = - vector(this->n_timesteps, VectorXd(num_verts * 2)); + pair edge; - this->synthetic_latent_state_sequence[0] = this->s0; + for (int _ = 0; _ < num_extra_edges; _++) { + edge.second = true; + while (edge.second) { + sample(cag_nodes.begin(), cag_nodes.end(), rand_node.begin(), 2, G.rand_num_generator); + src_idx = G.uni_dist(G.rand_num_generator) < 0.5? 0 : 1; + source = to_string(rand_node[src_idx]); + target = to_string(rand_node[1 - src_idx]); + edge = boost::edge(G.get_vertex_id(source), + G.get_vertex_id(target), G.graph); + } - for (int ts = 1; ts < this->n_timesteps; ts++) { - this->synthetic_latent_state_sequence[ts] = - this->A_original * this->synthetic_latent_state_sequence[ts - 1]; + sample(adjectives.begin(), adjectives.end(), rand_adjectives.begin(), 2, G.rand_num_generator); + polarity = G.uni_dist(G.rand_num_generator) < 0.5 ? 1 : -1; + + auto causal_fragment = + CausalFragment({rand_adjectives[0], 1, source}, + {rand_adjectives[1], polarity, target}); + G.add_edge(causal_fragment); } + + RNG::release_instance(); + return G; } -void AnalysisGraph:: - generate_synthetic_observed_state_sequence_from_synthetic_latent_state_sequence() { - using ranges::to; - using ranges::views::transform; - // Allocate memory for observed_state_sequences - this->test_observed_state_sequence.clear(); - this->test_observed_state_sequence = PredictedObservedStateSequence( - this->n_timesteps, vector>()); - - this->test_observed_state_sequence = - this->synthetic_latent_state_sequence | - transform([this](VectorXd latent_state) { - return this->sample_observed_state(latent_state); - }) | - to(); +/** + * TODO: This is very similar to initialize_parameters() method defined in + * parameter_initialization.cpp. Might be able to merge the two + * @param kde_kernels Number of KDE kernels to use when constructing beta prior distributions + * @param initial_beta How to initialize betas + * @param initial_derivative How to initialize derivatives + * @param use_continuous Whether to use matrix exponential or not + */ +void AnalysisGraph::initialize_random_CAG(unsigned int num_obs, + unsigned int kde_kernels, + InitialBeta initial_beta, + InitialDerivative initial_derivative, + bool use_continuous) { + this->initialize_random_number_generator(); + this->set_default_initial_state(initial_derivative); + this->set_res(kde_kernels); + this->construct_theta_pdfs(); + this->init_betas_to(initial_beta); + this->pred_timesteps = num_obs + 1; + this->continuous = use_continuous; + this->find_all_paths(); + this->set_transition_matrix_from_betas(); + this->transition_matrix_collection.clear(); + this->initial_latent_state_collection.clear(); + // TODO: We are using this variable for two different purposes. + // create another variable. + this->res = 1; + this->transition_matrix_collection = vector(this->res); + this->initial_latent_state_collection = vector(this->res); + this->transition_matrix_collection[0] = this->A_original; + this->initial_latent_state_collection[0] = this->s0; } -vector> -AnalysisGraph::sample_observed_state(VectorXd latent_state) { - using ranges::to; - using ranges::views::transform; - int num_verts = this->num_vertices(); - assert(num_verts == latent_state.size() / 2); +void AnalysisGraph::generate_synthetic_data(unsigned int num_obs, + double noise_variance, + unsigned int kde_kernels, + InitialBeta initial_beta, + InitialDerivative initial_derivative, + bool use_continuous) { + this->initialize_random_CAG(num_obs, kde_kernels, initial_beta, initial_derivative, use_continuous); + vector periods = {2, 3, 4, 6, 12}; + vector rand_period(1); + uniform_real_distribution centers_dist(-100, 100); + int max_samples_per_period = 12; + for (int v : this->head_nodes) { + Node& n = (*this)[v]; + sample(periods.begin(), periods.end(), rand_period.begin(), 1, this->rand_num_generator); + n.period = rand_period[0]; + int gap_size = max_samples_per_period / n.period; + int offset = 0; // 0 <= offset < period + vector filled_months; + for (int p = 0; p < n.period; p++) { + double center = centers_dist(this->rand_num_generator); + double spread = this->norm_dist(this->rand_num_generator) * 5; + n.centers.push_back(center); + n.spreads.push_back(spread); + int month = offset + gap_size * p; + n.generated_monthly_latent_centers_for_a_year[month] = center; + n.generated_monthly_latent_spreads_for_a_year[month] = spread; + filled_months.push_back(month); + } + this->interpolate_missing_months(filled_months, n); + print("{0} - {1}\n", n.name, n.period); + } - vector> observed_state(num_verts); + for (int v = 0; v < this->num_vertices(); v++) { + Node& n = (*this)[v]; + n.add_indicator("ind_" + n.name, "synthetic"); + n.mean = centers_dist(this->rand_num_generator); + while (n.mean == 0) { + n.mean = centers_dist(this->rand_num_generator); + } + } - for (int v = 0; v < num_verts; v++) { - vector& indicators = (*this)[v].indicators; + this->generate_latent_state_sequences(0); + this->generate_observed_state_sequences(); - observed_state[v] = vector(indicators.size()); + this->observed_state_sequence.clear(); + this->observation_timestep_gaps.clear(); + this->n_timesteps = num_obs; - // Sample observed value of each indicator around the mean of the - // indicator - // scaled by the value of the latent state that caused this observation. - // TODO: Question - Is ind.mean * latent_state[ 2*v ] correct? - // Shouldn't it be ind.mean + latent_state[ 2*v ]? - observed_state[v] = indicators | transform([&](Indicator ind) { - normal_distribution gaussian( - ind.mean * latent_state[2 * v], ind.stdev); + // Access (concept is a vertex in the CAG) + // [ timestep ][ concept ][ indicator ][ observation ] + this->observed_state_sequence = ObservedStateSequence(this->n_timesteps); + this->observation_timestep_gaps = vector(this->n_timesteps, 1); + this->observation_timestep_gaps[0] = 0; - return gaussian(this->rand_num_generator); - }) | - to(); + int num_verts = this->num_vertices(); + // Fill in observed state sequence + // NOTE: This code is very similar to the implementations in + // set_observed_state_sequence_from_data and get_observed_state_from_data + for (int ts = 0; ts < this->n_timesteps; ts++) { + this->observed_state_sequence[ts] = vector>>(num_verts); + + for (int v = 0; v < num_verts; v++) { + Node& n = (*this)[v]; + this->observed_state_sequence[ts][v] = vector>(n.indicators.size()); + + for (int i = 0; i < n.indicators.size(); i++) { + this->observed_state_sequence[ts][v][i] = vector(); + this->observed_state_sequence[ts][v][i].push_back( + this->predicted_observed_state_sequences[0][ts + 1][v][i] + + noise_variance * this->norm_dist(this->rand_num_generator)); + } + } } - - return observed_state; + RNG::release_instance(); } - -/* - ============================================================================ - Public: Synthetic data experiment - ============================================================================ -*/ - -pair -AnalysisGraph::test_inference_with_synthetic_data(int start_year, - int start_month, - int end_year, - int end_month, - int res, - int burn, - string country, - string state, - string county, - map units, - InitialBeta initial_beta, - InitialDerivative initial_derivative, - bool use_continuous) { - synthetic_data_experiment = true; - this->n_timesteps = this->calculate_num_timesteps( - start_year, start_month, end_year, end_month); - this->initialize_parameters(res, initial_beta, initial_derivative, - false, use_continuous); - - // Initialize the latent state vector at time 0 - this->set_random_initial_latent_state(); - this->generate_synthetic_latent_state_sequence(); - this->generate_synthetic_observed_state_sequence_from_synthetic_latent_state_sequence(); - - for (vector> obs : this->test_observed_state_sequence) { - print("({}, {})\n", obs[0][0], obs[1][0]); +void AnalysisGraph::interpolate_missing_months(vector &filled_months, Node &n) { + sort(filled_months.begin(), filled_months.end()); + + // Interpolate values for the missing months + if (filled_months.size() > 1) { + for (int i = 0; i < filled_months.size(); i++) { + int month_start = filled_months[i]; + int month_end = filled_months[(i + 1) % filled_months.size()]; + + int num_missing_months = 0; + if (month_end > month_start) { + num_missing_months = month_end - month_start - 1; + } + else { + num_missing_months = (11 - month_start) + month_end; + } + + for (int month_missing = 1; + month_missing <= num_missing_months; + month_missing++) { + n.generated_monthly_latent_centers_for_a_year + [(month_start + month_missing) % 12] = + ((num_missing_months - month_missing + 1) * + n.generated_monthly_latent_centers_for_a_year + [month_start] + + (month_missing)*n + .generated_monthly_latent_centers_for_a_year + [month_end]) / + (num_missing_months + 1); + + n.generated_monthly_latent_spreads_for_a_year + [(month_start + month_missing) % 12] = + ((num_missing_months - month_missing + 1) * + n.generated_monthly_latent_spreads_for_a_year + [month_start] + + (month_missing)*n + .generated_monthly_latent_spreads_for_a_year + [month_end]) / + (num_missing_months + 1); + } + } + } else if (filled_months.size() == 1) { + for (int month = 0; month < n.generated_monthly_latent_centers_for_a_year.size(); month++) { + n.generated_monthly_latent_centers_for_a_year[month] = + n.generated_monthly_latent_centers_for_a_year + [filled_months[0]]; + n.generated_monthly_latent_spreads_for_a_year[month] = + n.generated_monthly_latent_spreads_for_a_year + [filled_months[0]]; + } } - - this->train_model(start_year, - start_month, - end_year, - end_month, - res, - burn, - country, - state, - county, - units, - InitialBeta::ZERO); - - return make_pair( - this->test_observed_state_sequence, - this->generate_prediction(start_year, start_month, end_year, end_month)); - - RNG::release_instance(); - synthetic_data_experiment = false; } diff --git a/lib/to_json.cpp b/lib/to_json.cpp index e7bf839a0..1b6d32439 100644 --- a/lib/to_json.cpp +++ b/lib/to_json.cpp @@ -55,6 +55,7 @@ string AnalysisGraph::serialize_to_json_string(bool verbose) { // To go for a more compressed version of concepts where array index is the // concept id j["concepts"] = {}; + j["periods"] = {}; // Concept to indicator mapping. This is an array of array of objects // Outer array goes from 0 to this->num_vertices() - 1 and it is indexed by @@ -70,7 +71,8 @@ string AnalysisGraph::serialize_to_json_string(bool verbose) { if (verbose) { j["concepts"].push_back( {{"concept", n.name}, - {"cid", this->name_to_vertex.at(n.name)}}); + {"cid", this->name_to_vertex.at(n.name)}, + {"period", n.period}}); for (Indicator &ind : n.indicators) { j["conceptIndicators"][this->name_to_vertex.at(n.name)].push_back( @@ -88,6 +90,7 @@ string AnalysisGraph::serialize_to_json_string(bool verbose) { // This is a more compressed way to store concept information where // array index keeps track of the concept id j["concepts"][this->name_to_vertex.at(n.name)] = n.name; + j["periods"][this->name_to_vertex.at(n.name)] = n.period; for (Indicator &ind : n.indicators) { // This is a more compressed representation. We do not store iid @@ -228,3 +231,12 @@ string AnalysisGraph::serialize_to_json_string(bool verbose) { return j.dump(4); } + +void AnalysisGraph::export_create_model_json_string() { + nlohmann::json j; + j["id"] = this->id; + j["statements"] = {}; + j["statements"].push_back({{"belief", 1}}); + j["conceptIndicators"] = {}; + cout << j.dump(4) << endl; +} \ No newline at end of file diff --git a/lib/train_model.cpp b/lib/train_model.cpp index e93ffc0a0..dcc119d03 100644 --- a/lib/train_model.cpp +++ b/lib/train_model.cpp @@ -26,6 +26,10 @@ void AnalysisGraph::train_model(int start_year, this->n_timesteps = this->calculate_num_timesteps(start_year, start_month, end_year, end_month); + this->observation_timestep_gaps.clear(); + this->observation_timestep_gaps = vector(this->n_timesteps, 1.0); + this->observation_timestep_gaps[0] = 0; + if(this->n_timesteps > 0) { if (!synthetic_data_experiment && !causemos_call) { // Delphi is run locally using observation data from delphi.db @@ -44,6 +48,187 @@ void AnalysisGraph::train_model(int start_year, } void AnalysisGraph::run_train_model(int res, + int burn, + InitialBeta initial_beta, + InitialDerivative initial_derivative, + bool use_heuristic, + bool use_continuous, + int train_start_timestep, + int train_timesteps, + unordered_map concept_periods, + unordered_map concept_center_measures, + unordered_map concept_models, + unordered_map concept_min_vals, + unordered_map concept_max_vals, + unordered_map> ext_concepts + ) { + if (train_timesteps < 0) { + this->n_timesteps = this->observed_state_sequence.size(); + } + else { + this->n_timesteps = train_timesteps; + } + + unordered_set train_vertices = + unordered_set + (this->node_indices().begin(), this->node_indices().end()); + + for (const auto & [ concept, deriv_func ] : ext_concepts) { + try { + int vert_id = this->name_to_vertex.at(concept); + this->external_concepts[vert_id] = deriv_func; + train_vertices.erase(vert_id); + } + catch (const std::out_of_range& oor) { + cout << "\nERROR: train_model - Concept << concept << is not in CAG!\n"; + } + } + + for (const auto & [ concept, period ] : concept_periods) { + try { + int vert_id = this->name_to_vertex.at(concept); + Node &n = (*this)[vert_id]; + n.period = period; + } + catch (const std::out_of_range& oor) { + cout << "\nERROR: train_model - Concept << concept << is not in CAG!\n"; + } + } + + for (const auto & [ concept, center_measure ] : concept_center_measures) { + try { + int vert_id = this->name_to_vertex.at(concept); + Node &n = (*this)[vert_id]; + n.center_measure = center_measure; + } + catch (const std::out_of_range& oor) { + cout << "\nERROR: train_model - Concept << concept << is not in CAG!\n"; + } + } + + for (const auto & [ concept, model ] : concept_models) { + try { + int vert_id = this->name_to_vertex.at(concept); + Node &n = (*this)[vert_id]; + n.model = model; + } + catch (const std::out_of_range& oor) { + cout << "\nERROR: train_model - Concept << concept << is not in CAG!\n"; + } + } + + for (const auto & [ concept, min_val ] : concept_min_vals) { + try { + int vert_id = this->name_to_vertex.at(concept); + Node &n = (*this)[vert_id]; + n.min_val = min_val; + n.has_min = true; + } + catch (const std::out_of_range& oor) { + cout << "\nERROR: train_model - Concept << concept << is not in CAG!\n"; + } + } + + for (const auto & [ concept, max_val ] : concept_max_vals) { + try { + int vert_id = this->name_to_vertex.at(concept); + Node &n = (*this)[vert_id]; + n.max_val = max_val; + n.has_max = true; + } + catch (const std::out_of_range& oor) { + cout << "\nERROR: train_model - Concept << concept << is not in CAG!\n"; + } + } + + this->concept_sample_pool.clear(); +// this->concept_sample_pool = vector(train_vertices.begin(), +// train_vertices.end()); + for (int vert : train_vertices) { + if (this->head_nodes.find(vert) == this->head_nodes.end()) { + this->concept_sample_pool.push_back(vert); + } + } + + this->initialize_parameters(res, initial_beta, initial_derivative, + use_heuristic, use_continuous); + + this->log_likelihoods.clear(); + this->log_likelihoods = vector(burn + this->res, 0); + this->MAP_sample_number = -1; + + cout << "\nBurning " << burn << " samples out..." << endl; + for (int i : trange(burn)) { + this->sample_from_posterior(); + this->log_likelihoods[i] = this->log_likelihood; + + if (this->log_likelihood > this->log_likelihood_MAP) { + this->log_likelihood_MAP = this->log_likelihood; + this->transition_matrix_collection[this->res - 1] = this->A_original; + this->initial_latent_state_collection[this->res - 1] = this->s0; + this->log_likelihoods[burn + this->res - 1] = this->log_likelihood; + this->MAP_sample_number = this->res - 1; + } + } + + //int num_verts = this->num_vertices(); + + cout << "\nSampling " << this->res << " samples from posterior..." << endl; + for (int i : trange(this->res - 1)) { + this->sample_from_posterior(); + this->transition_matrix_collection[i] = this->A_original; + this->initial_latent_state_collection[i] = this->s0; + + if (this->log_likelihood > this->log_likelihood_MAP) { + this->log_likelihood_MAP = this->log_likelihood; + this->MAP_sample_number = i; + } + + for (auto e : this->edges()) { + this->graph[e].sampled_thetas.push_back(this->graph[e].theta); + } + + this->log_likelihoods[burn + i] = this->log_likelihood; + /* + this->latent_mean_collection[i] = vector(num_verts); + this->latent_std_collection[i] = vector(num_verts); + this->latent_mean_std_collection[i] = vector< + unordered_map>>(num_verts); + + for (int v : this->node_indices()) { + Node &n = (*this)[v]; + this->latent_mean_collection[i][v] = n.mean; + this->latent_std_collection[i][v] = n.std; + this->latent_mean_std_collection[i][v] = n.partition_mean_std; + } + */ + } + + if (this->MAP_sample_number < int(this->res) - 1) { + this->sample_from_posterior(); + this->transition_matrix_collection[this->res - 1] = this->A_original; + this->initial_latent_state_collection[this->res - 1] = this->s0; + this->log_likelihoods[burn + this->res - 1] = this->log_likelihood; + + if ((this->log_likelihood > this->log_likelihood_MAP) or (this->log_likelihood_MAP == -1)) { + this->log_likelihood_MAP = this->log_likelihood; + this->MAP_sample_number = this->res - 1; + } + + for (auto e : this->edges()) { + this->graph[e].sampled_thetas.push_back(this->graph[e].theta); + } + + this->log_likelihoods[burn + this->res - 1] = this->log_likelihood; + } else { + this->MAP_sample_number = this->res - 1; + } + + this->trained = true; + RNG::release_instance(); +} + +void AnalysisGraph::run_train_model_2(int res, int burn, InitialBeta initial_beta, InitialDerivative initial_derivative, diff --git a/lib/utils.cpp b/lib/utils.cpp index 3aeaa7ade..f9468d424 100644 --- a/lib/utils.cpp +++ b/lib/utils.cpp @@ -54,12 +54,46 @@ double standard_deviation(const double mean, const std::vector& v) * Returns the median of a vector of doubles. */ double median(const std::vector &xs) { - using namespace boost::accumulators; - accumulator_set> acc; - for (auto x : xs) { - acc(x); - } - return boost::accumulators::median(acc); + if (xs.size() > 100) { + using namespace boost::accumulators; + accumulator_set> acc; + // accumulator_set> + // acc ( p_square_cumulative_distribution_num_cells = xs.size() ); + + for (auto x : xs) { + acc(x); + } + + return boost::accumulators::median(acc); + } else { + vector x_copy(xs); + sort(x_copy.begin(), x_copy.end()); + int num_els = x_copy.size(); + int mid = num_els / 2; + if (num_els % 2 == 0) { + return (x_copy[mid - 1] + x_copy[mid]) / 2; + } + else { + return x_copy[mid]; + } + } +} + +/** + * Returns the center absolute deviation of a vector of doubles. + * Based on: + * https://en.wikipedia.org/wiki/Median_absolute_deviation + */ +double median_absolute_deviation(const double center, const std::vector& v) +{ + std::vector abs_diff = std::vector(v.size()); + + transform(v.begin(), v.end(), + abs_diff.begin(), + [&](double val){return abs(center - val);}); + + return median(abs_diff); } double log_normpdf(double x, double mean, double sd) { @@ -76,4 +110,13 @@ nlohmann::json load_json(string filename) { return j; } +/** Compute the number of months between two dates **/ +int months_between(tuple earlier_date, tuple latter_date) { + int earlier_year = get<0>(earlier_date); + int earlier_month = get<1>(earlier_date); + int latter_year = get<0>(latter_date); + int latter_month = get<1>(latter_date); + + return 12 * (latter_year - earlier_year) + (latter_month - earlier_month); +} } // namespace delphi::utils diff --git a/lib/utils.hpp b/lib/utils.hpp index bd7474f6b..6cbad8d37 100644 --- a/lib/utils.hpp +++ b/lib/utils.hpp @@ -69,9 +69,17 @@ double standard_deviation(const double mean, const std::vector &v); */ double median(const std::vector &xs); + +/** + * Returns the median absolute deviation of a vector of doubles. + */ +double median_absolute_deviation(const double center, const std::vector& v); + double log_normpdf(double x, double mean, double sd); /** Load JSON data from a file */ nlohmann::json load_json(std::string filename); +/** Compute the number of months between two dates **/ +int months_between(std::tuple earlier_date, std::tuple latter_date); } // namespace delphi::utils diff --git a/notebooks/2021_june_embed/2021_june_embed.ipynb b/notebooks/2021_june_embed/2021_june_embed.ipynb new file mode 100644 index 000000000..0f848c6c8 --- /dev/null +++ b/notebooks/2021_june_embed/2021_june_embed.ipynb @@ -0,0 +1,300 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9df716d1-394f-4c26-9b68-490a1e9a0aa0", + "metadata": {}, + "source": [ + "# 2021 June Embed" + ] + }, + { + "cell_type": "markdown", + "id": "d2b5aeec-2aeb-49b5-8259-8a6aacaf58a2", + "metadata": {}, + "source": [ + "## Imports" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd223475-e5b0-447e-b3c6-5f17600e495d", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import delphi.plotter as dp\n", + "from delphi.cpp.DelphiPython import AnalysisGraph, InitialBeta, InitialDerivative\n", + "import pandas as pd\n", + "import numpy as np\n", + "#import graphviz\n", + "#from IPython.display import display\n", + "from IPython.display import Image\n", + "\n", + "import warnings\n", + "warnings.filterwarnings('ignore')" + ] + }, + { + "cell_type": "markdown", + "id": "457bec18-bf5d-45a8-a945-2a49083e7150", + "metadata": {}, + "source": [ + "## Read Data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b64cc638-399e-4a43-880a-3f97739bbf81", + "metadata": {}, + "outputs": [], + "source": [ + "df_temp = pd.read_csv('../../data/mini_use_case/TerraClimateOromiaMonthlyMaxTemp.csv')\n", + "temperature = df_temp['(deg C) Max Temperature (TerraClimate) at State, 1958-01-01 to 2019-12-31'].tolist()[:72]\n", + "\n", + "df_rain = pd.read_csv('../../data/mini_use_case/TerraClimateOromiaMontlhyPrecip.csv')\n", + "rain = df_rain['(mm) Precipitation (TerraClimate) at State, 1958-01-01 to 2019-12-31'].tolist()[:72]" + ] + }, + { + "cell_type": "markdown", + "id": "5410fae7-ee6c-4cb6-9ad7-b9b8661d274d", + "metadata": {}, + "source": [ + "## Create Base CAG" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d459a6a-6994-41f3-9c1f-2ad821fe2686", + "metadata": {}, + "outputs": [], + "source": [ + "statements = [\n", + " (\n", + " (\"\", 1, \"rain\"),\n", + " (\"\", -1, \"temperature\"),\n", + " )\n", + "]\n", + "\n", + "data = {\"rain\": (\"Monthly Precipitation (mm)\", rain),\n", + " \"temperature\": (\"Monthly Max Temperature (F)\", temperature)\n", + " }\n", + "G = AnalysisGraph.from_causal_fragments_with_data((statements, data), kde_kernels=1000)\n", + "\n", + "G.to_png('2021_june_embed.png', rankdir=\"TB\", simplified_labels=False)\n", + "Image('2021_june_embed.png')" + ] + }, + { + "cell_type": "markdown", + "id": "f2367faf-50b0-434d-8f9f-74d8cb90a178", + "metadata": {}, + "source": [ + "## Train Model\n", + "### Head node modeling related parameteres\n", + "
    \n", + "
  1. concept_periods
  2. \n", + "
      \n", + "
    • Period for each head concept.
    • \n", + "
    • Default is 1.
    • \n", + "
    • A dictionary: {'concept name': period}
    • \n", + "
    \n", + "
  3. concept_center_measures
  4. \n", + "
      \n", + "
    • How to calculate the central tendency for each head concept.
    • \n", + "
    • mean or median.
    • \n", + "
    • Default is median.
    • \n", + "
    \n", + "\n", + "
  5. concept_models
  6. \n", + "
      \n", + "
    • The model to be used for the head concept.
    • \n", + "
    • The choises are:
    • \n", + "
        \n", + "
      1. center - Always predicts the center value for each partition.
      2. \n", + " <--li>absolute_change - Predicts based on the absolute change between adjacent partiton centers. $ac_{i} = center_{i+1} - center_i$\n", + " <--li>relative_change - Predicts based on the absolute change between adjacent partiton centers.\n", + "
      \n", + "
    \n", + "\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46dfa95c-9529-4cbe-ab3c-ed71b7d4e4f1", + "metadata": {}, + "outputs": [], + "source": [ + "def train_predict_plot(G, period, center, model, constraints={}, concept_min_vals=-10000, concept_max_vals=1000):\n", + " # Training\n", + " G.run_train_model(res=70,\n", + " burn=0,\n", + " initial_beta=InitialBeta.ZERO,\n", + " initial_derivative=InitialDerivative.DERI_ZERO,\n", + " use_heuristic=False,\n", + " use_continuous=False,\n", + " train_start_timestep=0,\n", + " train_timesteps=48,\n", + " concept_periods={'rain': period},\n", + " concept_center_measures={'rain': center}, # mean, median\n", + " concept_models={'rain': model}, # center, absolute_change, relative_change\n", + " concept_min_vals={'rain': concept_min_vals},\n", + " concept_max_vals={'rain': concept_max_vals}\n", + " )\n", + "\n", + " # Predicting\n", + " G.generate_prediction(49, 23, constraints=constraints)\n", + "\n", + " # Plotting\n", + " model_state = G.get_complete_state()\n", + " dp.delphi_plotter(model_state, num_bins=400, rotation=45,\n", + " out_dir='plots', file_name_prefix='', save_csv=False)" + ] + }, + { + "cell_type": "markdown", + "id": "124583af-929a-4cfb-b8a5-a0fdc844a4d3", + "metadata": {}, + "source": [ + "#### Using median" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76b4392b-7e4a-43ea-9927-476dbe13f14a", + "metadata": {}, + "outputs": [], + "source": [ + "train_predict_plot(G, period=12, center='median', model='center')\n", + "Image('plots/8_Predictions_Median_and_CI_Monthly Precipitation (mm).png')" + ] + }, + { + "cell_type": "markdown", + "id": "55816e8f-7f47-4a7f-9a3b-2e8add6ec6ad", + "metadata": {}, + "source": [ + "#### Using mean" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "489934e5-366c-46f2-9e4e-6559e4bf2628", + "metadata": {}, + "outputs": [], + "source": [ + "train_predict_plot(G, period=12, center='mean', model='center')\n", + "Image('plots/8_Predictions_Median_and_CI_Monthly Precipitation (mm).png')" + ] + }, + { + "cell_type": "markdown", + "id": "4f23510a-4c5b-4d86-a801-6b8dc10dd1c9", + "metadata": {}, + "source": [ + "#### Let us try a different period" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2d5a74c-7ae1-47c7-bcf1-67b0cbafec19", + "metadata": {}, + "outputs": [], + "source": [ + "train_predict_plot(G, period=24, center='median', model='center')\n", + "Image('plots/8_Predictions_Median_and_CI_Monthly Precipitation (mm).png')" + ] + }, + { + "cell_type": "markdown", + "id": "58d53843-d06e-47a8-bac0-e883c26de74b", + "metadata": {}, + "source": [ + "### Constraints\n", + "\n", + "

Three model options, center, absolute_change and relative_change behave differently upon constraints.

\n", + "\n", + "#### center with constraints" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ade97db-54f7-4488-9118-122f354811fc", + "metadata": {}, + "outputs": [], + "source": [ + "train_predict_plot(G, period=12, center='median', model='center', constraints={12: [('rain', 'Monthly Precipitation (mm)', 120)]})\n", + "Image('plots/8_Predictions_Median_and_CI_Monthly Precipitation (mm).png')" + ] + }, + { + "cell_type": "markdown", + "id": "cdfa6984-173a-4720-a870-7ea5fd7fea5e", + "metadata": {}, + "source": [ + "### Guiding the modeler with bounds" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49329d14-9448-4f82-b90e-6de976b24cb5", + "metadata": {}, + "outputs": [], + "source": [ + "train_predict_plot(G, period=12, center='median', model='absolute_change', constraints={7: [('rain', 'Monthly Precipitation (mm)', 15)]})\n", + "Image('plots/8_Predictions_Median_and_CI_Monthly Precipitation (mm).png')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0177346-4246-4fed-b2ea-7aa89c0d85cd", + "metadata": {}, + "outputs": [], + "source": [ + "train_predict_plot(G, period=12, center='median', model='absolute_change', constraints={7: [('rain', 'Monthly Precipitation (mm)', 15)]}, concept_min_vals=0)\n", + "Image('plots/8_Predictions_Median_and_CI_Monthly Precipitation (mm).png')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "356f04a5-10e4-4927-b331-25558f230ea7", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/scripts/data_processing/process_CauseMos_statements.py b/scripts/data_processing/process_CauseMos_statements.py new file mode 100644 index 000000000..1af09b551 --- /dev/null +++ b/scripts/data_processing/process_CauseMos_statements.py @@ -0,0 +1,262 @@ +import os +import json +import pandas as pd + +statements = [] +evidences = [] +adjective_frequencies = {'sub': {}, 'obj': {}} +_adjective_frequencies = {'sub': {}, 'obj': {}} +adjective_names = {'sub': {}, 'obj': {}} +_adjective_names = {'sub': {}, 'obj': {}} + +adjective_pairs = {} +_adjective_pairs = {} + +with open('../../data/causemos_indra_statements/CauseMos_indra_statements.json', 'r') as f: + lines = f.readlines() + for idx, line in enumerate(lines, 1): + statement = json.loads(line) + #print(json.dumps(statement, indent=4, sort_keys=True)) + belief = statement["_source"]["belief"] + + evidence = statement["_source"]["evidence"] + + for evid_idx, evid in enumerate(evidence, 1): + text = evid["evidence_context"]["text"] + + _adjectives = [] + for key in ["subj_adjectives", "obj_adjectives"]: + _adj = evid["evidence_context"][key] + _adj = _adj if _adj else [] + _adjectives.append(_adj) + + _polarities = [] + for key in ["subj_polarity", "obj_polarity"]: + _pol = evid["evidence_context"][key] + _pol = _pol if _pol else 0 + _polarities.append(_pol) + + evidences.append({ + 'Statement #': idx, + 'Evidence #': evid_idx, + '_Sub Adj': ', '.join(_adjectives[0]), + '_Obj Adj': ', '.join(_adjectives[1]), + '_Sub Pol': _polarities[0], + '_Obj Pol': _polarities[1], + '# _Sub Adj': len(_adjectives[0]), + '# _Obj Adj': len(_adjectives[1]), + 'Text': text + }) + + for idx2, key in enumerate(['sub', 'obj']): + if len(_adjectives[idx2]) in _adjective_frequencies[key].keys(): + _adjective_frequencies[key][len(_adjectives[idx2])] += 1 + else: + _adjective_frequencies[key][len(_adjectives[idx2])] = 1 + + _adjectives[0] = ['None'] if len(_adjectives[0]) == 0 else _adjectives[0] + _adjectives[1] = ['None'] if len(_adjectives[1]) == 0 else _adjectives[1] + + for adj in _adjectives[0]: + if adj in _adjective_names['sub'].keys(): + _adjective_names['sub'][adj] += 1 + else: + _adjective_names['sub'][adj] = 1 + + for adj in _adjectives[1]: + if adj in _adjective_names['obj'].keys(): + _adjective_names['obj'][adj] += 1 + else: + _adjective_names['obj'][adj] = 1 + + for sub in _adjectives[0]: + for obj in _adjectives[1]: + adj_pair = (sub, obj) + if adj_pair in _adjective_pairs.keys(): + _adjective_pairs[adj_pair] += 1 + else: + _adjective_pairs[adj_pair] = 1 + + # print(len(evidence)) + # print(json.dumps(statement, indent=4, sort_keys=True)) + # exit() + # + # continue + + text = evidence[0]["evidence_context"]["text"] + + _adjectives = [] + for key in ["subj_adjectives", "obj_adjectives"]: + _adj = evidence[0]["evidence_context"][key] + _adj = _adj if _adj else [] + _adjectives.append(_adj) + + _polarities = [] + for key in ["subj_polarity", "obj_polarity"]: + _pol = evidence[0]["evidence_context"][key] + _pol = _pol if _pol else 0 + _polarities.append(_pol) + + concepts = [] + for key in ["subj", "obj"]: + con = statement["_source"][key]["concept"] + concepts.append(con) + + adjectives = [] + for key in ["subj", "obj"]: + adj = statement["_source"][key]["adjectives"] + adjectives.append(adj) + + polarities = [] + for key in ["subj", "obj"]: + pol = statement["_source"][key]["polarity"] + polarities.append(pol) + + statements.append({ + 'Statement #': idx, + 'Belief': belief, + 'Subject': concepts[0], + 'Object': concepts[1], + 'Sub Adj': ', '.join(adjectives[0]), + 'Obj Adj': ', '.join(adjectives[1]), + 'Sub Pol': polarities[0], + 'Obj Pol': polarities[1], + '_Sub Adj': ', '.join(_adjectives[0]), + '_Obj Adj': ', '.join(_adjectives[1]), + '_Sub Pol': _polarities[0], + '_Obj Pol': _polarities[1], + '# Sub Adj': len(adjectives[0]), + '# Obj Adj': len(adjectives[1]), + '# _Sub Adj': len(_adjectives[0]), + '# _Obj Adj': len(_adjectives[1]), + '# _Evidence': len(evidence), + 'Text': text + }) + + if len(adjectives[0]) > 1 or len(adjectives[1]) > 1: + with open(f'../../data/causemos_indra_statements/multi_adjective/{idx}.json', 'w') as out: + out.write(json.dumps(statement, indent=4, sort_keys=True)) + + for idx2, key in enumerate(['sub', 'obj']): + if len(adjectives[idx2]) in adjective_frequencies[key].keys(): + adjective_frequencies[key][len(adjectives[idx2])] += 1 + else: + adjective_frequencies[key][len(adjectives[idx2])] = 1 + + adjectives[0] = ['None'] if len(adjectives[0]) == 0 else adjectives[0] + adjectives[1] = ['None'] if len(adjectives[1]) == 0 else adjectives[1] + + for adj in adjectives[0]: + if adj in adjective_names['sub'].keys(): + adjective_names['sub'][adj] += 1 + else: + adjective_names['sub'][adj] = 1 + + for adj in adjectives[1]: + if adj in adjective_names['obj'].keys(): + adjective_names['obj'][adj] += 1 + else: + adjective_names['obj'][adj] = 1 + + for sub in adjectives[0]: + for obj in adjectives[1]: + adj_pair = (sub, obj) + if adj_pair in adjective_pairs.keys(): + adjective_pairs[adj_pair] += 1 + else: + adjective_pairs[adj_pair] = 1 + + + # print(belief) + # print(text) + # print(_adjectives) + # print(_polarities) + # print(adjectives) + # print(_polarities) + # print(concepts) + +df_statements = pd.DataFrame(statements) +df_evidences = pd.DataFrame(evidences) + +df_statements.to_csv('../../data/causemos_indra_statements/statements.csv', index=False, + columns=['Statement #', 'Sub Adj', '_Sub Adj', 'Sub Pol', '_Sub Pol', 'Subject', 'Obj Adj', + '_Obj Adj', 'Obj Pol', '_Obj Pol', '# Sub Adj', '# _Sub Adj', '# Obj Adj', '# _Obj Adj', + '# _Evidence', 'Text']) +df_evidences.to_csv('../../data/causemos_indra_statements/evidence.csv', index=False, + columns=['Statement #', 'Evidence #', '_Sub Adj', '_Sub Pol', '_Obj Adj', '_Obj Pol', '# _Sub Adj', + '# _Obj Adj', 'Text']) + +# df_sub_adj_counts = df_statements.groupby(by='# Sub Adj').count() +# df_obj_adj_counts = df_statements.groupby(by='# Obj Adj').count() +# +# _df_sub_adj_counts = df_statements.groupby(by='# _Sub Adj').count() +# _df_obj_adj_counts = df_statements.groupby(by='# _Obj Adj').count() +# +# df_sub_adj_counts.to_csv('../../data/causemos_indra_statements/sub_adj_counts.csv', index=False) +# df_obj_adj_counts.to_csv('../../data/causemos_indra_statements/obj_adj_counts.csv', index=False) +# +# _df_sub_adj_counts.to_csv('../../data/causemos_indra_statements/_sub_adj_counts.csv', index=False) +# _df_obj_adj_counts.to_csv('../../data/causemos_indra_statements/_obj_adj_counts.csv', index=False) + + +for idx2, key in enumerate(['sub', 'obj']): + multiplicity = [] + frequency = [] + for mult, freq in adjective_frequencies[key].items(): + multiplicity.append(mult) + frequency.append(freq) + + df_freq = pd.DataFrame({'# Adjectives': multiplicity, 'frequency': frequency}) + df_freq.to_csv(f'../../data/causemos_indra_statements/{key}_adj_counts.csv', index=False) + + multiplicity = [] + frequency = [] + for mult, freq in _adjective_frequencies[key].items(): + multiplicity.append(mult) + frequency.append(freq) + + df_freq = pd.DataFrame({'# Adjectives': multiplicity, 'frequency': frequency}) + df_freq.to_csv(f'../../data/causemos_indra_statements/_{key}_adj_counts.csv', index=False) + + adjective = [] + frequency = [] + for adj, freq in adjective_names[key].items(): + adjective.append(adj) + frequency.append(freq) + + df_freq = pd.DataFrame({'Adjective': adjective, 'frequency': frequency}) + df_freq.to_csv(f'../../data/causemos_indra_statements/{key}_adjectives.csv', index=False) + + adjective = [] + frequency = [] + for adj, freq in _adjective_names[key].items(): + adjective.append(adj) + frequency.append(freq) + + df_freq = pd.DataFrame({'Adjective': adjective, 'frequency': frequency}) + df_freq.to_csv(f'../../data/causemos_indra_statements/_{key}_adjectives.csv', index=False) + + +sub = [] +obj = [] +freq = [] +for adj_pair, count in adjective_pairs.items(): + sub.append(adj_pair[0]) + obj.append(adj_pair[1]) + freq.append(count) + +df_pair = pd.DataFrame({'Subject': sub, 'Object': obj, 'frequency': freq}) +df_pair.to_csv(f'../../data/causemos_indra_statements/adjective_pairs.csv', index=False) + + +sub = [] +obj = [] +freq = [] +for adj_pair, count in _adjective_pairs.items(): + sub.append(adj_pair[0]) + obj.append(adj_pair[1]) + freq.append(count) + +df_pair = pd.DataFrame({'Subject': sub, 'Object': obj, 'frequency': freq}) +df_pair.to_csv(f'../../data/causemos_indra_statements/_adjective_pairs.csv', index=False) + diff --git a/scripts/debugger.py b/scripts/debugger.py index 54e487dca..0cb0bea35 100644 --- a/scripts/debugger.py +++ b/scripts/debugger.py @@ -69,10 +69,14 @@ def create_base_CAG(causemos_create_model, grounding_score_cutoff=0, kde_kernels=4): if causemos_create_model: - G = AnalysisGraph.from_causemos_json_file(causemos_create_model, - belief_score_cutoff, - grounding_score_cutoff, - kde_kernels) + if causemos_create_model == "synthetic": + G = AnalysisGraph.generate_random_CAG(4, 1) + G.generate_synthetic_data(24, 16.0, 100, InitialBeta.PRIOR, InitialDerivative.DERI_PRIOR, False) + else: + G = AnalysisGraph.from_causemos_json_file(causemos_create_model, + belief_score_cutoff, + grounding_score_cutoff, + kde_kernels) else: statements = [ ( @@ -114,9 +118,14 @@ def draw_CAG(G, file_name): ""], ["../tests/data/delphi/causemos_create.json", # 8. Oldest test data "../tests/data/delphi/causemos_experiments_projection_input.json"], + ["../tests/data/delphi/create_model_rain--temperature--yield.json", # 9. rain-temperature CAG + "../tests/data/delphi/experiments_rain--temperature--yield.json"], + ["../tests/data/delphi/create_model_rain--temperature.json", # 10. rain-temperature CAG + "../tests/data/delphi/experiments_rain--temperature--yield.json"], + ["synthetic", "synthetic"] # 11. synthetic ] - input_idx = 2 + input_idx = 9 causemos_create_model = json_inputs[input_idx][0] causemos_create_experiment = json_inputs[input_idx][1] @@ -126,30 +135,36 @@ def draw_CAG(G, file_name): grounding_score_cutoff=0, kde_kernels=10) #G = create_base_CAG('', 100) + G.set_random_seed(81) draw_CAG(G, 'plot_testing_CAG.png') print('\nTraining Model') - G.run_train_model(res=10, - burn=100, + use_continuous = False if causemos_create_model == "synthetic" else True + G.run_train_model(res=200, + burn=1000, initial_beta=InitialBeta.ZERO, - initial_derivative=InitialDerivative.DERI_ZERO) + initial_derivative=InitialDerivative.DERI_ZERO, + use_continuous=use_continuous) - try: - preds = G.run_causemos_projection_experiment_from_json_file( - filename=causemos_create_experiment) - except AnalysisGraph.BadCausemosInputException as e: - print(e) - exit() + if causemos_create_model == "synthetic": + G.generate_prediction(1, 24) + else: + try: + preds = G.run_causemos_projection_experiment_from_json_file( + filename=causemos_create_experiment) + except AnalysisGraph.BadCausemosInputException as e: + print(e) + exit() print('\n\nPlotting \n') model_state = G.get_complete_state() - concept_indicators, edges, adjectives, polarities, edge_data, derivatives, data_range, data_set, pred_range, predictions, cis = model_state + concept_indicators, edges, adjectives, polarities, edge_data, derivatives, data_range, data_set, pred_range, predictions, cis, log_likelihoods = model_state print(data_range) print(pred_range[1:]) dp.delphi_plotter(model_state, num_bins=400, rotation=45, - out_dir='plots', file_name_prefix='') + out_dir='plots', file_name_prefix='db', save_csv=False) diff --git a/scripts/modeling_efforts.py b/scripts/modeling_efforts.py new file mode 100644 index 000000000..79955de0f --- /dev/null +++ b/scripts/modeling_efforts.py @@ -0,0 +1,141 @@ +import delphi.plotter as dp +from delphi.cpp.DelphiPython import AnalysisGraph, InitialBeta, InitialDerivative +import pandas as pd +import numpy as np + +df_temp = pd.read_csv('../data/mini_use_case/TerraClimateOromiaMonthlyMaxTemp.csv') +temperature = df_temp['(deg C) Max Temperature (TerraClimate) at State, 1958-01-01 to 2019-12-31'].tolist()[:72] + +df_rain = pd.read_csv('../data/mini_use_case/TerraClimateOromiaMontlhyPrecip.csv') +rain = df_rain['(mm) Precipitation (TerraClimate) at State, 1958-01-01 to 2019-12-31'].tolist()[:72] +# print(len(temperature)/12) +# print(len(rain)) +# exit() +# rain = [56.49,35.32,31.59,16.34,7.52,16.09,74.37,80.28,23.24,11.45,5.76,9.6,31.96,32.4,20.02,14.89,7.67,5.06,67.74,84.23,35.63,8.66,7.37,14.24] +# temperature = [31.0215,29.8736,33.6469,35.6415,38.5646,38.3929,37.0828,35.7634,36.3652,34.8636,33.1313,31.7197,32.1485,31.574,33.1953,36.5846,38.1069,39.3582,36.7342,35.3044,35.1285,34.9057,32.3577,30.9242] +# exit() +# rain = [56.49,35.32,31.59,16.34,7.52,16.09,74.37,80.28,23.24,11.45,5.76,9.6,31.96,32.4,20.02,14.89,7.67,5.06,67.74,84.23,35.63,8.66,7.37,14.24] +# temperature = [31.0215,29.8736,33.6469,35.6415,38.5646,38.3929,37.0828,35.7634,36.3652,34.8636,33.1313,31.7197,32.1485,31.574,33.1953,36.5846,38.1069,39.3582,36.7342,35.3044,35.1285,34.9057,32.3577,30.9242] + +rain = [0.067287097,0.948775,2.294458065,0.980603333,0.75403871,0.243053333,4.698829032,5.648793548,1.395853333,1.71013871,0.088853333,0.612916129,0.628951613,1.117355172,0.422251613,1.00248,1.226922581,0.945253333,3.664290323,4.430374194,1.35189,0.30026129,0.17042,0.156770968,0.262951613,0.3155,0.224541935,3.905033333,3.655470968,1.267846667,6.514112903,4.001903226,2.371223333,1.719193548,0.4052,0.097754839,1.29E-05,0.056485714,0.612593548,1.946536667,1.392032258,1.81064,5.636487097,6.073612903,3.73836,0.189503226,2.109933333,0.041948387,0.002009677,1.537889286,3.029506452,2.414076667,1.838977419,0.624603333,5.903183871,4.708770968,1.73639,1.50136129,0.132553333,1.126558065,0.711512903,0.056417241,3.617506452,2.823293333,2.162712903,1.488246667,5.011274194,6.265332258,1.59045,0.717329032,0.84738,0.038245161,0.312635484,0.008214286,1.990893548,1.447356667,0.611283871,2.711343333,6.126045161,5.360922581,1.009006667,3.353306452,0.68993,0.034229032,0.638777419,0.908292857,0.740129032,0.996463333,1.060212903,0.94176,7.602393548,6.537809677,2.832743333,1.914867742,0.08192,0.002280645,0.542119355,0.043289286,6.901003226,0.370483333,0.326690323,0.971193333,7.747980645,9.463974194,1.966903333,2.199083871,0.10037,0.059132258,0.002958065,0.003248276,0.182054839,0.65317,0.284403226,0.405456667,1.57133871,2.516,1.186123333,0.418283871,0.174276667,0.083293548,0.029319355,0.072082143,1.799454839,0.45108,0.947225806,1.14663,1.599316129,1.979583871,1.509206667,0.456532258,0.119636667,0.097506452,0.390154839,0.015535714,1.517209677,0.810713333,0.321122581,1.09399,2.976754839,1.879745161,1.102033333,0.085403226,0.021313333,0.423958065,0.0621,0.240214286,0.403612903,1.279313333,0.343429032,0.56549,1.357477419,2.878167742,1.3381,0.021722581,0.056593333,1.381941935,0.15293871,0.033848276,0.538754839,1.710623333,0.1561,0.735653333,1.548219355,1.287945161,0.896016667,0.3212,0.25264,1.269251613,0.529767742,0.020303571,0.681948387,5.66678,1.593519355,0.13908,1.427009677,1.426158065,0.819763333,0.111703226,0.162976667,3.55E-05,0.282587097,0.500996429,2.157316129,2.88453,0.847916129,0.825076667,5.779832258,5.873341935,1.80166,0.798580645,0.06097,0.638312903,0.296532258,0.759296429,0.48183871,2.13564,0.914458065,0.57174,4.016754839,2.676712903,1.53357,0.409864516,0.087673333,0.001303226,0.277087097,0.057248276,0.004441935,1.30485,0.584112903,0.351056667,3.051477419,3.621367742,1.480323333,0.256870968,0.91209,0.016370968,0.349096774,0.1044,0.534858065,0.897976667,0.104816129,0.739023333,4.489709677,4.163751613,0.888566667,1.398909677,0.04606,0.3052,0.00486129,1.65225,1.272480645,1.738746667,1.389903226,0.975606667,5.156887097,6.972422581,2.128933333,0.132574194,0.236806667,0.039932258,0.066177419,0.082425,1.075435484,0.657353333,2.481612903,0.225613333,1.453916129,1.706332258,0.67557,0.111554839,0.222553333,0.007632258,0.010341935,6.55E-05,0.146119355,1.21862,0.259967742,0.327793333,3.230758065,2.933706452,1.04061,0.0398,0.02899,0.076187097,0.345690323,0.017175,1.094945161,1.270896667,0.611083871,0.849813333,5.498580645,5.575745161,1.371143333,2.399748387,0.317456667,0.066935484,0.028819355,0.344992857,0.900948387,1.972063333,1.328677419,0.826326667,5.062932258,3.740464516,2.73512,1.170358065,0.141356667,0.082835484,0.284196774,0.030460714,0.380816129,0.023336667,0.799780645,1.522456667,0.990932258,5.702148387,0.964853333,0.196503226,0.575166667,0.818680645,0.259170968,0.318703448,0.818729032,4.820703333,2.27223871,0.494396667,5.14783871,4.638109677,1.609366667,0.295651613,0.161223333,0.043764516,0.001512903,1.785742857,1.725329032,1.322443333,2.432280645,0.32378,2.005419355,4.148558065,2.438363333,0.719467742,0.133733333,0.004945161,0.18523871,0.624142857,0.395341935,2.6592,0.176603226,0.471596667,2.196245161,3.461706452,3.37334,0.965896774,0.785046667,0.029367742,4.52E-05,1.35735,0.978096774,2.444236667,0.311396774,1.11368,0.597845161,2.926635484,5.163923333,1.876280645,0.98977,0.816735484,0.311477419,0.323831034,1.214196774,3.587106667,2.237845161,0.983026667,3.965074194,4.346283871,2.31646] +temperature = [24.86295806,25.13280714,26.54966129,29.79424333,30.95234516,32.11392667,31.3133871,30.89469355,30.93339333,28.55438065,25.50030667,24.46148387,23.27382903,22.39718276,26.38620645,28.46132,31.04445161,31.93411,31.08583548,29.0518871,29.22651333,27.91463871,25.62283333,24.27758387,22.73682258,22.71873571,26.90440645,27.09099333,29.07612903,31.63087333,31.36512581,31.18212581,30.76640333,28.82564839,26.51419667,24.70176129,24.26064516,25.4456,26.72726774,30.16119667,31.55742258,32.18229667,30.27816774,29.77531613,29.76672,28.68954194,26.45734333,24.03178387,24.27689355,25.49820357,26.19175484,28.42569333,31.27456452,32.53478,30.348,29.63275161,30.668,29.14517097,26.29693,25.11856129,24.68018387,26.1728931,27.17660968,28.99057333,29.39485161,31.00897667,31.11190968,30.14581613,29.83478667,28.72504516,25.64455667,24.22446774,23.39774839,24.49352143,26.59564839,28.20723333,31.10853871,32.19592333,31.45016452,31.03982903,31.70886333,27.52415484,26.21632667,25.16447419,24.46216129,25.575925,27.47573871,30.48144,31.88712581,32.94343,31.32420968,29.28708065,29.52118,28.83919355,26.52327667,24.66836452,24.45384516,26.67338571,26.1650871,30.09454,32.29913871,32.17986,30.45177742,30.24866452,30.46502667,27.24491935,26.15418667,24.47020645,24.13077419,25.69715517,27.2236871,29.86323333,30.83724516,31.83559,31.25467742,29.09985161,30.20353667,27.7406,25.47530667,23.6949129,22.95638387,24.76266071,26.65235161,29.95412,31.2869,32.02169333,30.61878065,28.99470645,30.00396,29.5072871,26.20904,24.8518129,23.5442129,25.41718929,27.52885161,28.54994333,31.47550323,32.14381667,32.49455806,31.33065484,30.03016333,29.42600323,26.98337,24.63960645,23.60346129,26.38779643,27.43636774,28.45589333,32.04939677,32.00567,31.26214516,28.87483548,30.23267667,28.85755484,26.54720667,23.94398387,24.50213871,24.27118966,26.94359032,27.94561667,31.54308065,31.89315333,31.87457419,31.04750323,31.08214667,28.86416774,26.74078,24.75294194,23.88877097,26.06273929,27.63122258,29.08497667,30.10806129,32.30074333,30.92069032,31.50618065,30.95165667,29.32583226,26.60961,24.46932581,24.27066129,26.245375,27.30174516,28.40079333,31.40136774,32.36381,31.09376774,30.1714,30.03189333,28.98043548,26.61085667,24.75597419,23.58546129,26.23269286,27.6941129,29.27583,32.08432903,31.97184,30.09358387,30.30682581,30.55679667,28.43743871,26.18127667,24.15435806,24.36885806,24.34289655,27.18429032,29.57276333,31.07354516,31.72307667,31.77259677,31.32441613,30.67252,28.38856129,25.18536667,23.83597742,24.08534194,26.39980714,27.70489355,29.89802333,31.28515806,32.71743333,31.9402129,31.10592903,31.31495333,28.483,26.61731,25.87396452,24.58355484,25.473925,27.04503871,29.63851,31.31575161,32.66308667,30.27800968,30.22356774,30.03330333,29.46778387,26.37985333,24.01269032,24.06503226,25.47452857,26.54421935,29.92544667,30.09432258,31.82947333,31.51112903,29.2929871,30.50952667,28.42188387,25.93507667,23.82311935,24.24770323,25.21965172,26.83623871,29.19745333,31.42051935,32.43823667,31.19894839,31.01210323,31.19151,28.78804839,26.86237667,25.50248065,24.83181613,25.6823,27.39812581,29.04286333,31.74748065,32.39842,31.14796774,29.03381613,30.91547333,28.72963548,26.70407,23.79045484,24.47675161,25.37844643,27.50585161,30.16779333,30.55179032,32.35886667,31.72154839,30.2342129,30.14706333,27.78348065,26.77146667,24.44642903,23.62613548,25.65624643,28.21600323,29.89016,31.10255484,32.18640333,33.03586774,32.23883548,31.72547333,30.40855484,27.57449667,25.3426129,25.09007742,26.18275517,30.29951613,28.54819667,31.26419032,33.11608,30.93897097,30.09242581,31.71994333,29.91460645,26.72585667,25.56935806,24.87566129,24.98533929,28.37990323,30.58911333,30.7755871,33.38314667,33.10136452,31.33474839,31.38021667,29.83076129,27.19399333,23.96029677,23.52738065,26.36581071,28.2635129,29.41648,31.54575806,32.58377333,31.64165806,31.09654516,31.05386,28.96214516,27.13166333,25.68454516,25.28315806,26.65149643,28.37367419,30.04280333,31.15893548,32.30068,32.47812903,30.34747742,31.06539667,28.27787419,27.33406,25.7966129,24.14383548,26.03038966,27.92293548,29.40862,31.62165806,32.35247333,32.12196667] + +def compute_partitioned_mean_std(data, period): + partitions = {} + means = [] + std = [] + + for partition in range(period): + partitions[partition] = [] + std.append(0) + means.append(0) + + for idx, val in enumerate(data): + partitions[idx % period].append(val) + + for partition, vals in partitions.items(): + means[partition] = np.median(vals) #sum(vals) / len(vals) + std[partition] = np.std(vals) + + print(partitions) + print(means) + print(std) + # plt.plot(means) + # plt.plot(std) + # plt.show() + +def create_base_CAG(kde_kernels=4): + statements = [ + ( + ("", 1, "rain"), + ("", -1, "temperature"), + ) + ] + + data = {"rain": ("Monthly Precipitation (mm)", rain), + "temperature": ("Monthly Max Temperature (F)", temperature) + } + G = AnalysisGraph.from_causal_fragments_with_data((statements, data), kde_kernels) + return G + + +def get_rain_derivative(ts, sf): + #print(ts) + return (rain[ts + 1] - rain[ts]) / sf + +def draw_CAG(G, file_name): + G.to_png( + file_name, + rankdir="TB", + simplified_labels=False, + ) + + +if __name__ == "__main__": + json_inputs = [ + ["../tests/data/delphi/create_model_test.json", # 0. Missing data and mixed sampling frequency + "../tests/data/delphi/experiments_projection_test.json"], + ["../tests/data/delphi/create_model_ideal.json", # 1. Ideal data with gaps of 1 + "../tests/data/delphi/experiments_projection_ideal.json"], + ["../tests/data/delphi/create_model_input_2.json", # 2. Usual Data + "../tests/data/delphi/experiments_projection_input_2.json"], + ["../tests/data/delphi/create_model_ideal_10.json", # 3. Ideal data with gaps of 10 + "../tests/data/delphi/experiments_projection_ideal_2.json"], + ["../tests/data/delphi/create_model_ideal_3.json", # 4. Ideal data with real epochs + "../tests/data/delphi/experiments_projection_ideal_3.json"], + ["../tests/data/delphi/create_model_input_2_no_data.json", # 5. No data + "../tests/data/delphi/experiments_projection_input_2.json"], + ["../tests/data/delphi/create_model_input_2_partial_data.json", # 6. Partial data + "../tests/data/delphi/experiments_projection_input_2.json"], + ["../tests/data/delphi/create_model_input_new.json", # 7. Updated create model format + ""], + ["../tests/data/delphi/causemos_create.json", # 8. Oldest test data + "../tests/data/delphi/causemos_experiments_projection_input.json"], + ] + + input_idx = 2 + causemos_create_model = json_inputs[input_idx][0] + causemos_create_experiment = json_inputs[input_idx][1] + + # G = create_base_CAG(causemos_create_model) + G = create_base_CAG(kde_kernels=1000) + #G = create_base_CAG('', 100) + G.set_random_seed(81) + + draw_CAG(G, 'modeling_efforts_CAG.png') + + print('\nTraining Model') + G.run_train_model(res=200, + burn=1000, + initial_beta=InitialBeta.ZERO, + initial_derivative=InitialDerivative.DERI_ZERO, + use_heuristic=False, + use_continuous=False, + train_start_timestep=0, + train_timesteps=-1,#48, #12 * 52, # + concept_periods={'rain': 12}, + concept_center_measures={'rain': "median"}, # mean, median + concept_models={'rain': "center"}, # center, absolute_change, relative_change + #concept_min_vals={'rain': 0} + #ext_concepts={'rain': get_rain_derivative} + #ext_concepts={'test': lambda x, s : x*s } + ) + + # try: + G.generate_prediction(325, 24) # 333 for last 24 months. 325 for two last complete years + # G.generate_prediction(49, 23, constraints={12: [('rain', 'Monthly Precipitation (mm)', 120)]}) + # G.generate_prediction(12 * 52 + 1, 119) + # except AnalysisGraph.BadCausemosInputException as e: + # print(e) + # exit() + + print('\n\nPlotting \n') + model_state = G.get_complete_state() + + concept_indicators, edges, adjectives, polarities, edge_data, derivatives, data_range, data_set, pred_range, predictions, cis, log_likelihoods = model_state + + print(data_range) + print(pred_range[1:]) + + dp.delphi_plotter(model_state, num_bins=400, rotation=90, + out_dir='plots', file_name_prefix='me', save_csv=False) diff --git a/scripts/period_missing_datapoint_interpolation.py b/scripts/period_missing_datapoint_interpolation.py new file mode 100644 index 000000000..30ea32411 --- /dev/null +++ b/scripts/period_missing_datapoint_interpolation.py @@ -0,0 +1,31 @@ +from matplotlib import pyplot as plt + +plt.rcParams['figure.figsize'] = [20, 10] +plt.rcParams.update({'font.size': 18, 'figure.dpi': 150}) + +## Period interpolation check +filled_months = [2, 3, 5, 9] +generated_monthly_latent_sequence_for_a_year = [0, 0, 10, 20, 0, 5, 0, 0, 0, 30, 0, 0] +print(generated_monthly_latent_sequence_for_a_year) +for i in range(len(filled_months)): + month_start = filled_months[i] + month_end = filled_months[(i+1) % len(filled_months)] + + num_missing_months = 0 + if month_end > month_start: + num_missing_months = month_end - month_start - 1 + else: + num_missing_months = (11 - month_start) + month_end + + print(month_start, '|', month_end, '|', num_missing_months) + + for month_missing in range(1, num_missing_months + 1): + print((month_start + month_missing) % 12) + generated_monthly_latent_sequence_for_a_year[(month_start + month_missing) % 12] = \ + ((num_missing_months - month_missing + 1) * generated_monthly_latent_sequence_for_a_year[month_start] + + month_missing * generated_monthly_latent_sequence_for_a_year[month_end]) / (num_missing_months + 1) + +print(generated_monthly_latent_sequence_for_a_year) +plt.plot(generated_monthly_latent_sequence_for_a_year, marker='o', linewidth='2') +plt.plot([0, 0, 10, 20, 0, 5, 0, 0, 0, 30, 0, 0], marker='*', linewidth='2') +plt.show() diff --git a/scripts/rain_analysis.py b/scripts/rain_analysis.py new file mode 100644 index 000000000..84889be75 --- /dev/null +++ b/scripts/rain_analysis.py @@ -0,0 +1,471 @@ +import pathlib +import pandas as pd +import numpy as np +from matplotlib import pyplot as plt +from sklearn.linear_model import LinearRegression +import seaborn as sns + +plt.rcParams['figure.figsize'] = [20, 10] +plt.rcParams.update({'font.size': 18, 'figure.dpi': 150}) + +out_dir = 'plots/rainfall_causemos/' +if out_dir: + out_path = pathlib.Path(out_dir) + if not out_path.is_dir(): + print(f'\nMaking output directory: {out_dir}') + out_path.mkdir(parents=True, exist_ok=True) + +month_names = {0: 'January', + 1: 'February', + 2: 'March', + 3: 'April', + 4: 'May', + 5: 'June', + 6: 'July', + 7: 'August', + 8: 'September', + 9: 'October', + 10: 'November', + 11: 'December'} + +df_rain = pd.read_csv('../data/mini_use_case/TerraClimateOromiaMontlhyPrecip.csv') +rain = np.array(df_rain['(mm) Precipitation (TerraClimate) at State, 1958-01-01 to 2019-12-31'].tolist()) + +rain = [0.067287097,0.948775,2.294458065,0.980603333,0.75403871,0.243053333,4.698829032,5.648793548,1.395853333,1.71013871,0.088853333,0.612916129,0.628951613,1.117355172,0.422251613,1.00248,1.226922581,0.945253333,3.664290323,4.430374194,1.35189,0.30026129,0.17042,0.156770968,0.262951613,0.3155,0.224541935,3.905033333,3.655470968,1.267846667,6.514112903,4.001903226,2.371223333,1.719193548,0.4052,0.097754839,1.29E-05,0.056485714,0.612593548,1.946536667,1.392032258,1.81064,5.636487097,6.073612903,3.73836,0.189503226,2.109933333,0.041948387,0.002009677,1.537889286,3.029506452,2.414076667,1.838977419,0.624603333,5.903183871,4.708770968,1.73639,1.50136129,0.132553333,1.126558065,0.711512903,0.056417241,3.617506452,2.823293333,2.162712903,1.488246667,5.011274194,6.265332258,1.59045,0.717329032,0.84738,0.038245161,0.312635484,0.008214286,1.990893548,1.447356667,0.611283871,2.711343333,6.126045161,5.360922581,1.009006667,3.353306452,0.68993,0.034229032,0.638777419,0.908292857,0.740129032,0.996463333,1.060212903,0.94176,7.602393548,6.537809677,2.832743333,1.914867742,0.08192,0.002280645,0.542119355,0.043289286,6.901003226,0.370483333,0.326690323,0.971193333,7.747980645,9.463974194,1.966903333,2.199083871,0.10037,0.059132258,0.002958065,0.003248276,0.182054839,0.65317,0.284403226,0.405456667,1.57133871,2.516,1.186123333,0.418283871,0.174276667,0.083293548,0.029319355,0.072082143,1.799454839,0.45108,0.947225806,1.14663,1.599316129,1.979583871,1.509206667,0.456532258,0.119636667,0.097506452,0.390154839,0.015535714,1.517209677,0.810713333,0.321122581,1.09399,2.976754839,1.879745161,1.102033333,0.085403226,0.021313333,0.423958065,0.0621,0.240214286,0.403612903,1.279313333,0.343429032,0.56549,1.357477419,2.878167742,1.3381,0.021722581,0.056593333,1.381941935,0.15293871,0.033848276,0.538754839,1.710623333,0.1561,0.735653333,1.548219355,1.287945161,0.896016667,0.3212,0.25264,1.269251613,0.529767742,0.020303571,0.681948387,5.66678,1.593519355,0.13908,1.427009677,1.426158065,0.819763333,0.111703226,0.162976667,3.55E-05,0.282587097,0.500996429,2.157316129,2.88453,0.847916129,0.825076667,5.779832258,5.873341935,1.80166,0.798580645,0.06097,0.638312903,0.296532258,0.759296429,0.48183871,2.13564,0.914458065,0.57174,4.016754839,2.676712903,1.53357,0.409864516,0.087673333,0.001303226,0.277087097,0.057248276,0.004441935,1.30485,0.584112903,0.351056667,3.051477419,3.621367742,1.480323333,0.256870968,0.91209,0.016370968,0.349096774,0.1044,0.534858065,0.897976667,0.104816129,0.739023333,4.489709677,4.163751613,0.888566667,1.398909677,0.04606,0.3052,0.00486129,1.65225,1.272480645,1.738746667,1.389903226,0.975606667,5.156887097,6.972422581,2.128933333,0.132574194,0.236806667,0.039932258,0.066177419,0.082425,1.075435484,0.657353333,2.481612903,0.225613333,1.453916129,1.706332258,0.67557,0.111554839,0.222553333,0.007632258,0.010341935,6.55E-05,0.146119355,1.21862,0.259967742,0.327793333,3.230758065,2.933706452,1.04061,0.0398,0.02899,0.076187097,0.345690323,0.017175,1.094945161,1.270896667,0.611083871,0.849813333,5.498580645,5.575745161,1.371143333,2.399748387,0.317456667,0.066935484,0.028819355,0.344992857,0.900948387,1.972063333,1.328677419,0.826326667,5.062932258,3.740464516,2.73512,1.170358065,0.141356667,0.082835484,0.284196774,0.030460714,0.380816129,0.023336667,0.799780645,1.522456667,0.990932258,5.702148387,0.964853333,0.196503226,0.575166667,0.818680645,0.259170968,0.318703448,0.818729032,4.820703333,2.27223871,0.494396667,5.14783871,4.638109677,1.609366667,0.295651613,0.161223333,0.043764516,0.001512903,1.785742857,1.725329032,1.322443333,2.432280645,0.32378,2.005419355,4.148558065,2.438363333,0.719467742,0.133733333,0.004945161,0.18523871,0.624142857,0.395341935,2.6592,0.176603226,0.471596667,2.196245161,3.461706452,3.37334,0.965896774,0.785046667,0.029367742,4.52E-05,1.35735,0.978096774,2.444236667,0.311396774,1.11368,0.597845161,2.926635484,5.163923333,1.876280645,0.98977,0.816735484,0.311477419,0.323831034,1.214196774,3.587106667,2.237845161,0.983026667,3.965074194,4.346283871,2.31646] +rain = np.array(rain[:12*29]) + +print(len(rain)) +print(len(rain)/12) +# df_rain.rename(columns={'(mm) Precipitation (TerraClimate) at State, 1958-01-01 to 2019-12-31': 'Rainfall (mm)'}) +# df_rain['DateTime'] = df_rain['DateTime'].apply(lambda dt : pd.to_datetime(dt)) +# df_rain['Month'] = df_rain['DateTime'].apply(lambda dt : dt.month) +# df_rain['Year'] = df_rain['DateTime'].apply(lambda dt : dt.year - 100) +# df_rain.to_csv('testrain.csv') +# print(df_rain.head()) +# exit() + +''' +absolute_change = {1, -0.374757, -0.0660294, -0.269959, -0.156134, 0.151708, 1.03169, 0.10462, -1.00974, -0.20871, ... size:48} (std::vector) +mean_sequence = {1, 0.625243, 0.559214, 0.289255, 0.133121, 0.284829, 1.31652, 1.42114, 0.4114, 0.202691, ... size:48} (std::vector) +relative_change = {-0.187378, -0.0406274, -0.173138, -0.121104, 0.133885, 0.802976, 0.0451628, -0.417051, -0.147874, -0.0837504, ... size:47} (std::vector) +n.name = "rain" (std::string) +n.partitioned_data[0].second = {1, 0.565764, 0.322181, 0.482917} (std::vector) +part_means_debug = {0.524341, 0.599398, 0.694282, 0.276421, 0.168879, 0.166755, 1.26615, 1.4561, 0.61294, 0.1718, ... size:12} (std::vector) +n.absolute_change_medians = {0.00761197, -0.0660294, -0.18729, -0.141972, -0.00212427, 1.11869, 0.0455833, -0.935033, -0.519472, 0.0715171, ... size:12} (std::vector) +n.relative_change_medians = {0.524341, 0.599398, 0.694282, 0.276421, 0.168879, 0.166755, 1.26615, 1.4561, 0.61294, 0.1718, ... size:12} (std::vector) + +from median = {0.524341, 0.599398, 0.694282, 0.276421, 0.168879, 0.166755, 1.26615, 1.4561, 0.61294, 0.1718, ... size:71} (std::vector) +abs change = {0.524341, 0.531953, 0.465923, 0.278633, 0.136661, 0.134537, 1.25323, 1.29881, 0.363781, -0.155691, ... size:71} (std::vector) +difference = {0, -0.0674456, -0.228359, 0.00221278, -0.0322181, -0.0322181, -0.0129226, -0.157284, -0.249159, -0.327492, ... size:71} (std::vector) + +''' +def changes_analysis(data, plot_no, modifire, period=12): + scaling_factor = data[0] + scaled_data = np.array(data) / scaling_factor + absolute_change = np.diff(scaled_data) + relative_change = absolute_change / (scaled_data[0: -1] + 1) + + # print(scaled_data[0:11]) + # print(absolute_change[0:11]) + # print(relative_change[0:11]) + + p_data = {} + p_absolute_change = {} + p_relative_change = {} + med_data = [] + mean_data = [] + med_absolute_change = [] + med_relative_change = [] + mean_absolute_change = [] + + for partition in range(period): + p_data[partition] = [] + p_absolute_change[partition] = [] + p_relative_change[partition] = [] + med_data.append(0) + mean_data.append(0) + med_absolute_change.append(0) + med_relative_change.append(0) + mean_absolute_change.append(0) + + for idx in range(len(scaled_data)): + p_data[idx % period].append(scaled_data[idx]) + + if idx < len(absolute_change): + p_absolute_change[idx % period].append(absolute_change[idx]) + p_relative_change[idx % period].append(relative_change[idx]) + + for partition in range(period): + med_data[partition] = np.median(p_data[partition]) + mean_data[partition] = np.mean(p_data[partition]) + med_absolute_change[partition] = np.median(p_absolute_change[partition]) + med_relative_change[partition] = np.median(p_relative_change[partition]) + mean_absolute_change[partition] = np.mean(p_absolute_change[partition]) + + med_absolute_change = np.array(med_absolute_change) + med_absolute_change_0_centered = (med_absolute_change - np.mean(med_absolute_change)) * scaling_factor + print(np.mean(med_absolute_change)) + print(np.mean(med_absolute_change_0_centered)) + print(list(med_absolute_change)) + print(list(med_absolute_change_0_centered)) + + med_data = np.array(med_data) + # mean_data = np.array(mean_data) + # print(p_data[0], '\n') + # print(scaling_factor, '\n') + # print('Median :', med_data * scaling_factor, '\n') + # print('Mean :', mean_data * scaling_factor, '\n') + # print('Diff :', mean_data * scaling_factor - med_data * scaling_factor, '\n') + # print(med_absolute_change, '\n') + # print(med_relative_change, '\n') + + med_data = list(med_data) + med_data.append(med_data[0]) + med_data = np.array(med_data) + med_data_absolute_change = np.diff(med_data) + med_data_relative_change = med_data_absolute_change / (med_data[0: -1] + 1) + + print('\nrel change\n', list(med_data_relative_change)) + + # print(list(med_data), '\n') + # print(list(med_data_absolute_change), '\n') + # + # med_data = np.array(med_data) + # print(list(med_data[1:] - (med_data[:-1] + med_data_absolute_change)), '\n') + # + # pred = [med_data[0]] + # for ts in range(period): + # partition = ts % period + # pred.append(pred[ts] + med_data_absolute_change[partition]) + # + # # print(list(med_data[1:] - np.array(pred)), '\n') + # print(list(med_data)) + # print(pred, '\n') + # # exit() + + pred1 = [med_data[0]] + pred2 = [med_data[0]] + pred3 = [med_data[0]] + pred4 = [med_data[0]] + pred5 = [med_data[0]] + pred6 = [med_data[0]] + pred7 = [med_data[0]] + # for ts in range(1, 48): + for ts in range(1, len(scaled_data)): + # for ts in range(1, 12): + partition = (ts - 1) % period + pred1.append(pred1[ts-1] + med_data_absolute_change[partition]) + pred2.append(pred2[ts-1] + med_absolute_change[partition]) + pred4.append(pred4[ts-1] + mean_absolute_change[partition]) + pred5.append(pred5[ts-1] + (pred5[ts-1] + 1) * med_relative_change[partition]) + pred6.append(pred2[ts-1] + med_absolute_change_0_centered[partition]) + pred7.append(pred7[ts-1] + (pred7[ts-1] + 1) * med_data_relative_change[partition]) + + pred3.append(med_data[ts % period]) + + pred1 = np.array(pred1) * scaling_factor + pred2 = np.array(pred2) * scaling_factor + pred3 = np.array(pred3) * scaling_factor + pred4 = np.array(pred4) * scaling_factor + pred5 = np.array(pred5) * scaling_factor + # pred6 = np.array(pred6) * scaling_factor + pred7 = np.array(pred7) * scaling_factor + + plt.plot(data, marker='o', label='data') + plt.plot(pred3, marker='o', linewidth='8', label='partition - median', alpha=0.4) + plt.plot(pred1, marker='o', label='partition - median - change between partitions') + plt.plot(pred7, marker='o', label='partition - median - relative change between partitions') + plt.plot(pred2, marker='o', label='change between timesteps - partition - median') + plt.plot(pred4, marker='o', label='change between timesteps - partition - mean') + plt.plot(pred5, marker='o', label='relative change between timesteps - partition - median') + plt.plot([0, len(pred2) - 1], [pred2[0], scaling_factor * np.sum(med_absolute_change) / 12 * (len(pred2) - 1) + pred2[0]], marker='o', label=f'y = {scaling_factor * np.sum(med_absolute_change) / 12} x + {pred2[0]}') + plt.plot(pred6, marker='o', label='change between timesteps - partition - 0 centered median') + plt.legend() + plt.tight_layout() + # plt.show() + plt.savefig(f'{out_dir}{plot_no}_{modifire}.png') + plt.close() + plot_no += 1 + + print(np.sum(med_absolute_change)) + print(pred2[0] - pred2[11]) + + return plot_no + + +def compute_partitioned_mean_std(data, period, plot_no, modifire='Rainfall'): + partitions = {} + means = [] + std = [] + months = [] + + for partition in range(period): + partitions[partition] = [] + std.append(0) + means.append(0) + + for idx, val in enumerate(data): + partitions[idx % period].append(val) + months.append(idx % period + 1) + + for partition, vals in partitions.items(): + means[partition] = sum(vals) / len(vals) + std[partition] = np.std(vals) + + means = np.array(means) + std = np.array(std) + + df = pd.DataFrame({'Month': months, modifire: data}) + sns.boxplot(data=df, x='Month', y=modifire) + plt.title(f'Monthly {modifire} Distribution') + plt.savefig(f'{out_dir}{plot_no}_Monthly_{modifire}_Distribution - box.png') + plot_no += 1 + plt.close() + sns.scatterplot(data=df, x='Month', y=modifire) + plt.title(f'Monthly {modifire} Distribution') + ticks = [idx for idx in range(1, period + 1)] + plt.xticks(ticks, ticks) + plt.tight_layout() + plt.savefig(f'{out_dir}{plot_no}_Monthly_{modifire}_Distribution - points.png') + plot_no += 1 + plt.close() + sns.violinplot(data=df, x='Month', y=modifire, scale='count', bw=.15, inner='box') + plt.title(f'Monthly {modifire} Distribution') + plt.savefig(f'{out_dir}{plot_no}_Monthly_{modifire}_Distribution - violin.png') + plot_no += 1 + plt.close() + # sns.lineplot(data=df, x='Month', y=modifire, estimator='mean', marker='o') + # plt.title(f'{modifire} {month_names[partition]}') + + # for partition, vals in partitions.items(): + # partitions[partition] = np.array(vals) + # partitions[partition][partitions[partition] > means[partition] + std[partition]] = 0#means[partition] + std[partition] + # partitions[partition][partitions[partition] < means[partition] - std[partition]] = 0#means[partition] - std[partition] + # means[partition] = sum(partitions[partition]) / len(partitions[partition]) + # std[partition] = np.std(partitions[partition]) + + lr = LinearRegression() + + for partition, vals in partitions.items(): + # x = [partition + 1 + idx * 12 for idx in range(len(vals))] + # x = [partition + 1 + idx for idx in range(len(vals))] + x = [(1958 + idx) + (partition + 1) / 10 for idx in range(len(vals))] + lr.fit(np.array(x).reshape(-1, 1), vals) + plt.plot(x, vals, marker='o', label=modifire) + plt.plot([x[0], x[-1]], [lr.predict([[x[0]]]), lr.predict([[x[-1]]])], label='Linear regression fit') + plt.plot([x[0], x[-1]], [means[partition], means[partition]], label=f'Average {modifire}') + plt.plot([x[0], x[-1]], [means[partition] + std[partition], means[partition] + std[partition]], label='Average + 1 std') + plt.plot([x[0], x[-1]], [means[partition] - std[partition], means[partition] - std[partition]], label='Average - 1 std') + plt.fill_between([x[0], x[-1]], [means[partition] + std[partition], means[partition] + std[partition]], + [means[partition] - std[partition], means[partition] - std[partition]], label='1 std', alpha=0.1, color='b') + plt.xlabel('Year') + plt.ylabel(modifire) + plt.title(f'{modifire} {month_names[partition]}') + plt.legend() + # plt.show() + plt.savefig(f'{out_dir}{plot_no}_{modifire} - {month_names[partition]}.png') + plot_no += 1 + plt.close() + plt.hist(vals) + plt.xlabel(modifire) + plt.ylabel('Number of Years') + plt.title(f'{modifire} Distribution - {month_names[partition]}') + plt.tight_layout() + # plt.show() + plt.savefig(f'{out_dir}{plot_no}_{modifire}_Distribution - {month_names[partition]}.png') + plot_no += 1 + plt.close() + + for partition in range(len(partitions)): + x = partitions[partition] + y = partitions[(partition + 1) % 12] + plt.scatter(x, y) + lr.fit(np.array(x).reshape(-1, 1), y) + plt.plot([min(x), max(x)], [lr.predict([[min(x)]]), lr.predict([[max(x)]])], label='Linear regression fit', color='r') + plt.plot([min(x), max(x)], [min(x), max(x)], label='y = x', color='g') + plt.xlabel(f'{month_names[partition]} {modifire}') + plt.ylabel(f'{month_names[(partition + 1) % 12]} {modifire}') + plt.title(f'{modifire} {month_names[partition]} vs. {month_names[(partition + 1) % 12]}') + plt.legend() + plt.tight_layout() + # plt.show() + plt.savefig(f'{out_dir}{plot_no}_{modifire}_{month_names[partition]}_vs._{month_names[(partition + 1) % 12]}.png') + plot_no += 1 + plt.close() + + # print(partitions) + # print(means + std) + # print(means) + # print(means - std) + # print(std) + periods = [month for month in range(1, period + 1)] + plt.plot(periods, means, label=f'Average {modifire}', color='r', marker='o') + plt.fill_between(periods, means + std, means - std, label='1 std', alpha=0.2, color='b') + plt.legend() + plt.title(f'Average Monthly {modifire}') + plt.xlabel('Month') + plt.ylabel(f'Average {modifire}') + # plt.plot(std) + plt.tight_layout() + # plt.show() + plt.savefig(f'{out_dir}{plot_no}_average_monthly_{modifire}.png') + plot_no += 1 + plt.close() + + return plot_no + +def stacked_rainfall_plot(data, period, num_stacked_years, plot_no, modifire='Rainfall'): + yearly_data = {} + data_matrix = [] + years = [] + for year in range(len(data) // period): + yearly_data[year] = data[year * period : (year + 1) * period] + data_matrix.append(yearly_data[year]) + years.append(1958 + year) + + x = [month for month in range(1, period + 1)] + for year in range(len(yearly_data) - num_stacked_years + 1): + title = f'{modifire} for -' + for stack_num in range(num_stacked_years): + plt.plot(x, yearly_data[year + stack_num], label=1958+year+stack_num, marker='o') + title += ' ' + str(1958+year+stack_num) + plt.legend() + plt.title(title) + plt.xlabel('Month') + plt.ylabel(f'Average {modifire}') + plt.tight_layout() + plt.savefig(f'{out_dir}{plot_no}_{title}.png') + plot_no += 1 + plt.close() + + data_matrix = np.array(data_matrix).T + + fig, ax = plt.subplots() + # im = ax.imshow(data_matrix) + sns.heatmap(data_matrix) + + # Create colorbar + # cbar = ax.figure.colorbar(im, ax=ax) + # cbar.ax.set_ylabel(f'{modifire}', rotation=-90, va="bottom") + + # We want to show all ticks... + ax.set_xticks(np.arange(len(years))) + ax.set_yticks(np.arange(len(x))) + # ... and label them with the respective list entries + ax.set_xticklabels(years) + ax.set_yticklabels(x) + + # Rotate the tick labels and set their alignment. + plt.setp(ax.get_xticklabels(), rotation=90, ha="right", + rotation_mode="anchor") + + # Loop over data dimensions and create text annotations. + # for i in range(len(years)): + # for j in range(len(x)): + # text = ax.text(j, i, rainfall_matrix[i][j], + # ha="center", va="center", color="w") + + ax.set_title(f'{modifire} Year-Month') + fig.tight_layout() + # plt.show() + fig.savefig(f'{out_dir}{plot_no}_{modifire}_heatmap.png') + plot_no += 1 + plt.close() + + return plot_no + + +def this_month_next_month(data, plot_no, modifire='Rainfall'): + this_month = [data[0]] + next_month = [] + + for month in range(1, len(data) - 1): + next_month.append(data[month]) + this_month.append(data[month]) + + next_month.append(data[-1]) + + # print(len(this_month)) + # print(len(next_month)) + + lr = LinearRegression() + + # plt.scatter(this_month, next_month) + x = this_month + y = next_month + plt.scatter(x, y) + lr.fit(np.array(x).reshape(-1, 1), y) + plt.plot([min(x), max(x)], [lr.predict([[min(x)]]), lr.predict([[max(x)]])], label='Linear regression fit', color='r') + plt.plot([min(x), max(x)], [min(x), max(x)], label='y = x', color='g') + plt.xlabel(f'This Month {modifire}') + plt.ylabel(f'Next Month {modifire}') + plt.title(f'{modifire} This Month vs. Next Month') + plt.legend() + plt.tight_layout() + # plt.show() + plt.savefig(f'{out_dir}{plot_no}_{modifire}_This_Month_vs._Next_Month.png') + plot_no += 1 + plt.close() + + return plot_no + +def compute_relative_increase(data): + data = np.array(data) + dy = np.diff(data) + relative_change = [] + + # print(data[150:160]) + # print(dy[150:160]) + for idx in range(len(dy) - 1): + if data[idx] == 0: + print(idx, 'zero division') + relative_change.append(None) + dy[idx] = np.nan + else: + dy[idx] /= data[idx] + + # print(dy[150:160]) + +# plt.plot(rain) +# plt.show() + + +plot_no = 1 +plot_no = changes_analysis(rain[:48], plot_no, 'Rain models') + +# exit() +plot_no = compute_partitioned_mean_std(rain, 12, plot_no, 'Rainfall') +# plot_no = 38 +plot_no = stacked_rainfall_plot(rain, 12, 3, plot_no, 'Rainfall') +# plot_no = 98 +plot_no = this_month_next_month(rain, plot_no, 'Rainfall') + +dy = np.diff(rain)[0 : -11] + +plot_no = compute_partitioned_mean_std(dy, 12, plot_no, 'Absolute Change') +plot_no = stacked_rainfall_plot(dy, 12, 3, plot_no, 'Absolute Change') +plot_no = this_month_next_month(dy, plot_no, 'Absolute Change') + +rain = rain + 1 +dy = np.diff(rain)[0 : -11] +relative_change = dy / (rain[0: -12]) +# relative_change[relative_change == np.inf] = 1 + +# plot_no = 202 +plot_no = compute_partitioned_mean_std(relative_change, 12, plot_no, 'Relative Change') +plot_no = stacked_rainfall_plot(relative_change, 12, 3, plot_no, 'Relative Change') +plot_no = this_month_next_month(relative_change, plot_no, 'Relative Change') + + +# for idx, r in enumerate(rain): +# if r < 1: +# print(idx, r) + +# relative_change = dy / (rain[0 : -12] + 0.001) +# print(rain[0 : -12][relative_change > 5000]) +# exit() +# plt.plot(dy / (rain[0 : -12] + np.mean(rain))) +# plt.show() +# plt.close() + +# compute_relative_increase(rain[0 : -11]) \ No newline at end of file diff --git a/scripts/rainfall_period_analysis.py b/scripts/rainfall_period_analysis.py new file mode 100644 index 000000000..15f9622b0 --- /dev/null +++ b/scripts/rainfall_period_analysis.py @@ -0,0 +1,117 @@ +import pathlib +import pandas as pd +import numpy as np +from matplotlib import pyplot as plt +from sklearn.linear_model import LinearRegression +import seaborn as sns + +plt.rcParams['figure.figsize'] = [20, 10] +plt.rcParams.update({'font.size': 18, 'figure.dpi': 150}) + +out_dir = 'plots/rainfall/periods/' +if out_dir: + out_path = pathlib.Path(out_dir) + if not out_path.is_dir(): + print(f'\nMaking output directory: {out_dir}') + out_path.mkdir(parents=True, exist_ok=True) + +month_names = {0: 'January', + 1: 'February', + 2: 'March', + 3: 'April', + 4: 'May', + 5: 'June', + 6: 'July', + 7: 'August', + 8: 'September', + 9: 'October', + 10: 'November', + 11: 'December'} + +df_rain = pd.read_csv('../data/mini_use_case/CHIRPSOromiaDailyPrecip_1981-01-01_2020-08-31.csv') +df_rain.rename(columns={'(mm) Precipitation (CHIRPS) at , 1981-01-01 to 2020-10-26': 'Rain'}, inplace=True) +df_rain['DateTime'] = pd.to_datetime(df_rain['DateTime']) +df_rain['year'] = df_rain['DateTime'].dt.year +df_rain_grp = df_rain.groupby(by='year') +print(df_rain_grp) + +days_year = 365 +num_years = 15 +start_year = 1981 +block_size = 91 +block_start = 0 +block_end = block_start + block_size + +for block_size in [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,24,26,28,30,33,36,40,45,52,60,73,91,121,182,365]: #[28, 73, 91, 182, 365]:#[1, 5, 7, 14, 28, 73, 91, 182, 365]: + rain_blocked = [] + highlight = [] + do_highlight = True + for year, df_year in df_rain_grp: + if start_year <= year < start_year + num_years: + # print(year) + rain_year = np.array(df_year['Rain'].tolist()) + days_year = len(rain_year) + if days_year % block_size > 0: + rain_year = rain_year[: int(block_size * np.floor(days_year // block_size) - days_year)] + # print(len(rain_year)) + rain_blocked_year = np.reshape(rain_year, (block_size, -1)) + rain_blocked_year = np.sum(rain_blocked_year, axis=0) + do_highlight = not do_highlight + if do_highlight: + start = len(rain_blocked) + end = start + len(rain_blocked_year) + highlight.append((start - 0.5, end - 0.5)) + rain_blocked.extend(rain_blocked_year) + + # print(len(rain_blocked)) + fig, ax = plt.subplots(figsize=(20, 10)) + sns.lineplot(x=range(len(rain_blocked)), y=rain_blocked, marker="o") + for start, end in highlight: + ax.axvspan(start, end, color="green", alpha=0.3) + plt.title(f'Rainfall\nAggregation Days: {block_size}') + plt.ylabel(f'Rainfall for {block_size} days (mm)') + plt.xlabel(f'Blocks of {block_size} days (Aligned to years)') + plt.tight_layout() + # plt.show() + plt.savefig(f'{out_dir}{block_size}.png') + plt.close() + + +exit() +rain = np.array(df_rain['(mm) Precipitation (CHIRPS) at , 1981-01-01 to 2020-10-26'].tolist())[:730] +# rain = np.array(df_rain['DateTime'].tolist())[:730] +# print(rain) + +# plt.plot(rain) +# plt.show() + +# weekly = np.reshape(rain[:-2], (7, -1)) +# weekly = np.sum(weekly, axis=0) +# print(weekly) +# +# plt.plot(weekly) +# plt.show() + + +# weekly = np.reshape(rain[:-2], (14, -1)) +# weekly = np.sum(weekly, axis=0) +# print(weekly) +# +# plt.plot(weekly) +# plt.show() + +# weekly = np.reshape(rain[:-16], (21, -1)) +# weekly = np.sum(weekly, axis=0) +# print(weekly) +# +# plt.plot(weekly) +# plt.show() + + +weekly = np.reshape(rain[:-2], (56, -1)) +weekly = np.sum(weekly, axis=0) +print(weekly) + +sns.lineplot(x=range(len(weekly)), y=weekly, marker="o") +plt.show() + diff --git a/scripts/seasonal_fourier.py b/scripts/seasonal_fourier.py new file mode 100644 index 000000000..46861e2c2 --- /dev/null +++ b/scripts/seasonal_fourier.py @@ -0,0 +1,369 @@ +import numpy as np +import matplotlib.pyplot as plt +import seaborn as sns +from matplotlib.cm import get_cmap +import scipy.linalg as la + +plt.rcParams['figure.figsize'] = [8, 8] +plt.rcParams.update({'font.size': 18}) +sns.set_style("whitegrid") + +np.set_printoptions(precision=3, linewidth=100) #, formatter={'float': '{: 0.3f}'.format}) + +def discretize_line(y1, y2, spl): + dx = 1 / (spl) + x = np.arange(0, 1, dx) + return list(y1 + (y2 - y1) * x) + + +def linear_interpolate_data_sequence(data, spl): + f = [] + for idx in range(len(data)): + f += discretize_line(data[idx], data[(idx + 1) % len(data)], spl) + return f + + +def generate_x(L, num_points): + x = np.array([2 * L / (num_points - 1) * idx - L for idx in range(num_points)]) + return x + + +# Full blown LDS vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv +def generate_sinusoidal_generating_full_blown_LDS(components): + comp4 = components * 4 + A = np.zeros((comp4, comp4)) + s0 = np.zeros((comp4, 1)) + + for i in range(components): + ip1 = i + 1 + i4 = i * 4 + i4p1 = i4 + 1 + i4p2 = i4 + 2 + i4p3 = i4 + 3 + + A[i4, i4p1] = 1 + A[i4p2, i4p3] = 1 + A[i4p1, i4] = -ip1**2 + A[i4p3, i4p2] = -ip1**2 + + s0[i4p1][0] = ip1 * np.cos(-ip1 * np.pi) # (-1)**i*ip1 + s0[i4p2][0] = np.cos(-ip1 * np.pi) # (-1)**(ip1) + + return A, s0 + + +def generate_fourier_coefficients_from_full_blown_LDS_sinusoidals(x, f, dx, components, sinusoidals): + C = np.zeros(components) + D = np.zeros(components) + + C0 = np.sum(f * np.ones_like(x)) * dx + + # f0 = C0/2 + # f0_dot = 0 + + for k in range(components): + cos_nx = sinusoidals[4 * k + 2, :] + sin_nx = sinusoidals[4 * k, :] + + C[k] = np.sum(f * cos_nx) * dx # Inner product + D[k] = np.sum(f * sin_nx) * dx + + # f0 += C[k] * cos_nx[0] + D[k] * sin_nx[0] + # f0 += C[k] * sinusoidals[4 * k + 2, :][0] + D[k] * sinusoidals[4 * k, :][0] + # f0_dot += C[k] * sinusoidals[4 * k + 3, :][0] + D[k] * sinusoidals[4 * k + 1, :][0] + + return C0, C, D + + +def generate_full_full_blown_LDS_for_mat_exp(A_sinusoidal, s0_sinusoidal, C0, C, D, dx, L, spl): + ''' + dx * L * spl = 2 * pi / (m - 1) + ''' + dim = 4 + A_sinusoidal.shape[0] + A = np.zeros((dim, dim)) + # A[0][0] = 1 + A[2:2 + A_sinusoidal.shape[0], 2:2 + A_sinusoidal.shape[0]] = A_sinusoidal + A[2 + A_sinusoidal.shape[0]][0] = 0 + A[np.ix_([-2], np.arange(3, dim - 4, 4))] = D # -2 = 2 + A_sinusoidal.shape[0] + A[np.ix_([-2], np.arange(5, dim - 2, 4))] = C + + for component in np.arange(components): + components4 = component * 4 + componentsp1 = component + 1 + A[-1][components4 + 2] = -(componentsp1 ** 2) * D[component] + A[-1][components4 + 4] = -(componentsp1 ** 2) * C[component] + # print(A) + + s0 = np.zeros((dim, 1)) + s0[0][0] = 1 # C0 / 2 + s0[2:2 + A_sinusoidal.shape[0], 0] = s0_sinusoidal.T + + ft_coef = np.zeros(4 + A_sinusoidal.shape[0]) + ft_coef[0] = C0 / 2 # 1# + ft_coef[np.arange(2, dim - 5, 4)] = D + ft_coef[np.arange(4, dim - 3, 4)] = C + + s0[-2][0] = np.matmul(ft_coef, s0) # f(t0) + s0[-1][0] = np.matmul(A[-2, :], s0) # \dot f(t0) + + A = la.expm(A * dx * L * spl) + + return A, s0 + + +def fourier_curve_from_full_blown_LDS(A, s0, num_pred, L, num_datapoints): + curves = np.zeros((len(s0), num_pred)) + curves[:, 0] = s0[:, 0] + for t in range(1, num_pred): + curves[:, t] = np.matmul(A, curves[:, t - 1]) + + x = np.arange(0, num_pred) * 2 * L / (num_datapoints) - L + + sns.lineplot(x=x, y=curves[-2, :], label='LDS value', marker='o', color='r', linewidth=2) + sns.lineplot(x=x, y=curves[-1, :], label='LDS derivative', marker='o', color='b', linewidth=0.5) + sns.lineplot(x=x[: -1], y=np.diff(curves[-2, :]), label='diff', marker='o', color='g', linewidth=0.5) + + plt.legend() + plt.show() + + +# Have to update this similar to generate_sinusoidal_curves() to be used in the current pipeline +def generate_sinusoidal_curves_from_full_blown_LDS(A, s0, x): + points = np.zeros((len(s0), len(x))) + for idx, t in enumerate(x): + points[:, idx] = np.matmul(la.expm(A * t), s0)[:, 0] + + return points + + +''' +components = 2 +dx = 0.1 +x = np.arange(-np.pi, np.pi + dx, dx) +A, s0 = generate_sinusoidal_generating_full_blown_LDS(components) +print(A) +print(s0) +sinusoidals = generate_sinusoidal_curves_from_full_blown_LDS(A, s0, x) +for k in range(components): + sns.lineplot(x=x, y=sinusoidals[4 * k, :], label=f'$sin({k + 1}t)$')#, marker='o')# + # sns.lineplot(x=x, y=sinusoidals[4 * k + 2, :], label=f'$cos({k + 1}t)$')#, marker='o' + # sns.lineplot(x=x, y=trig_sinus[2 * k, :], label=f'$trigsin({k + 1}t)$')#, marker='o' +plt.show() +exit() +''' +# Full blown LDS ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +def generate_sinusoidal_generating_LDS(components, start_angle): + comp2 = components * 2 + A = np.zeros((comp2, comp2)) + s0 = np.zeros((comp2, 1)) + for i in range(components): + i2 = i * 2 + i2p1 = i2 + 1 + ip1 = i + 1 + A[i2 ][i2p1] = 1 + A[i2p1][i2 ] = -((ip1) ** 2) + s0[i2p1][0] = ip1 * np.cos(ip1 * np.pi) #(-1)**(ip1)*ip1#-ip1 + + return (A, s0) + + +def generate_sinusoidal_curves(A, s0, dx, num_points, L): + A = la.expm(A * dx * L) + sin_t = np.zeros((len(s0), num_points)) + sin_t[:, 0] = s0[:, 0] + + for t in range(1, num_points): + sin_t[:, t] = np.matmul(A, sin_t[:, t - 1]) + + return A, sin_t + + +def generate_sinusoidal_curves_from_trig_functions(x, components, num_points, L): + sin_t = np.zeros((2 * components, num_points)) + + for k in range(components): + sin_t[2 * k + 1, :] = np.cos(np.pi * (k+1) * x / L) + sin_t[2 * k, :] = np.sin(np.pi * (k+1) * x / L) + + return sin_t + + +def generate_fourier_coefficients_from_trig_functions(x, f, dx, components, L): + C = np.zeros(components) + D = np.zeros(components) + + C0 = np.sum(f * np.ones_like(x)) * dx + + for k in range(components): + cos_nx = np.cos(np.pi * (k+1) * x / L) + sin_nx = np.sin(np.pi * (k+1) * x / L) + + C[k] = np.sum(f * cos_nx) * dx # Inner product + D[k] = np.sum(f * sin_nx) * dx + + return C0, C, D + + +def generate_fourier_coefficients_from_LDS_sinusoidals(x, f, dx, components, sinusoidals): + C = np.zeros(components) + D = np.zeros(components) + + C0 = np.sum(f * np.ones_like(x)) * dx + + for k in range(components): + cos_nx = sinusoidals[2 * k + 1, :] + sin_nx = sinusoidals[2 * k, :] + + C[k] = np.sum(f * cos_nx) * dx / (k+1)**2 # Inner product + D[k] = np.sum(f * sin_nx) * dx + + return C0, C, D + + +def generate_full_LDS(A_sinusoidal, s0_sinusoidal, C0, C, D, dx, L, spl): + ''' + dx * L * spl = 2 * pi / (m - 1) + ''' + A_sinusoidal = la.expm(A_sinusoidal * dx * L * spl) + dim = 2 + A_sinusoidal.shape[0] + A = np.zeros((dim, dim)) + A[0][0] = 1 + A[1:1 + A_sinusoidal.shape[0], 1:1 + A_sinusoidal.shape[0]] = A_sinusoidal + A[1 + A_sinusoidal.shape[0]][0] = C0 / 2 + A[np.ix_([1 + A_sinusoidal.shape[0]], np.arange(1, dim - 1, 2))] = D + A[np.ix_([1 + A_sinusoidal.shape[0]], np.arange(2, dim - 1, 2))] = C + + s0 = np.zeros((dim, 1)) + s0[0][0] = 1 + s0[1:1 + A_sinusoidal.shape[0], 0] = s0_sinusoidal.T + s0 = np.matmul(A, s0) + + return A, s0 + + +def generate_full_LDS_for_mat_exp(A_sinusoidal, s0_sinusoidal, C0, C, D, dx, L, spl): + dim = 4 + A_sinusoidal.shape[0] + A = np.zeros((dim, dim)) + # A[0][0] = 1 + A[2:2 + A_sinusoidal.shape[0], 2:2 + A_sinusoidal.shape[0]] = A_sinusoidal + # A[2 + A_sinusoidal.shape[0]][0] = 1 + A[np.ix_([2 + A_sinusoidal.shape[0]], np.arange(2, dim - 2, 2))] = D + A[np.ix_([2 + A_sinusoidal.shape[0]], np.arange(3, dim - 2, 2))] = C + + s0 = np.zeros((dim, 1)) + s0[0][0] = C0 / 2 + s0[2:2 + A_sinusoidal.shape[0], 0] = s0_sinusoidal.T + # s0[-2][0] = np.matmul(A, s0)[-2][0] + # s0[2:2 + A_sinusoidal.shape[0], 0] = np.matmul(A_sinusoidal, s0_sinusoidal)[:, 0] #s0_sin.T + + A = la.expm(A * dx * L * spl) + + return A, s0 + + +def fourier_curve_from_trig_functions(C0, C, D, x, L): + fFS = C0 / 2 + + for k in range(components): + cos_nx = np.cos(np.pi * (k+1) * x / L) + sin_nx = np.sin(np.pi * (k+1) * x / L) + + fFS = fFS + C[k] * cos_nx + D[k] * sin_nx + + # ax.plot(x, sin_nx, '-') + # ax.plot(x, cos_nx, '-') + + sns.lineplot(x=x, y=fFS, label='Trig function', linewidth=3, color='k') + + +def fourier_curve_from_LDS(A, s0, num_pred, L, num_datapoints): + curves = np.zeros((len(s0), num_pred)) + curves[:, 0] = s0[:, 0] + for t in range(1, num_pred): + curves[:, t] = np.matmul(A, curves[:, t - 1]) + + x = np.arange(0, num_pred) * 2 * L / (num_datapoints) - L + sns.lineplot(x=x, y=curves[-1, :], label='LDS', marker='o', color='r', linewidth=2) + + plt.legend() + plt.show() + + +# Define domain +# samples per line segment +spl = 1000 + +# Periodic data sequence +# data = [0, 0, 1, 0, 0] +data = [100, 100, 200, 150, 140] + +# Number of data points +m = len(data) # => number of line segments = m-1 = 4 + +f = linear_interpolate_data_sequence(data, spl) + +# Total number of samples +tns = len(f) # spl * (m - 1) + +dx = 2 / (tns - 1) +L = np.pi +x = generate_x(L, len(f)) # L * np.arange(-1, 1, dx) +dxs = np.diff(x) + +fig, ax = plt.subplots() +sns.lineplot(x=x, y=f, color='y', linewidth=4, label='Original function') +name = 'Accent' +cmap = get_cmap('tab10') +colors = cmap.colors +ax.set_prop_cycle(color=colors) + + +# Compute Fourier series +C0 = np.sum(f * np.ones_like(x)) * dx +fFS = C0 / 2 + +components = 5 + +full_blown = True + +if full_blown: + A_sinusoidal, s0_sinusoidal = generate_sinusoidal_generating_full_blown_LDS(components) + + # Have to update generate_sinusoidal_curves_from_full_blown_LDS() to be used this way + # A_fun, sinusoidals = generate_sinusoidal_curves_from_full_blown_LDS(A_sinusoidal, s0_sinusoidal, x) +else: + A_sinusoidal, s0_sinusoidal = generate_sinusoidal_generating_LDS(components, x[0]) +A_fun, sinusoidals = generate_sinusoidal_curves(A_sinusoidal, s0_sinusoidal, dx, len(f), L) +''' +trig_sinus = generate_sinusoidal_curves_from_trig_functions(x, components, len(f), L) +for k in range(components): + if full_blown: + # sns.lineplot(x=x, y=sinusoidals[4 * k, :], label=f'$sin({k + 1}t)$')#, marker='o')# + sns.lineplot(x=x, y=sinusoidals[4 * k + 2, :], label=f'$cos({k + 1}t)$')#, marker='o' + else: + # sns.lineplot(x=x, y=sinusoidals[2 * k, :], label=f'$sin({k + 1}t)$')#, marker='o')# + sns.lineplot(x=x, y=sinusoidals[2 * k + 1, :] / (k+1), label=f'$cos({k + 1}t)$')#, marker='o' + # sns.lineplot(x=x, y=trig_sinus[2 * k, :], label=f'$trigsin({k + 1}t)$')#, marker='o' +plt.show() +exit() +''' + +C0_trig, C_trig, D_trig = generate_fourier_coefficients_from_trig_functions(x, f, dx, components, L) +if full_blown: + C0, C, D = generate_fourier_coefficients_from_full_blown_LDS_sinusoidals(x, f, dx, components, sinusoidals) +else: + C0, C, D = generate_fourier_coefficients_from_LDS_sinusoidals(x, f, dx, components, sinusoidals) + +if full_blown: + A, s0 = generate_full_full_blown_LDS_for_mat_exp(A_sinusoidal, s0_sinusoidal, C0, C, D, dx, L, spl) + # A, s0 = generate_full_full_blown_LDS_for_mat_exp(A_sinusoidal, s0_sinusoidal, C0_trig, C_trig, D_trig, dx, L, spl) +else: + A, s0 = generate_full_LDS(A_sinusoidal, s0_sinusoidal, C0, C, D, dx, L, spl) + +fourier_curve_from_trig_functions(C0_trig, C_trig, D_trig, x, L) +if full_blown: + fourier_curve_from_full_blown_LDS(A, s0, 15, L, m) +else: + fourier_curve_from_LDS(A, s0, 15, L, m) diff --git a/scripts/snap_diff.py b/scripts/snap_diff.py new file mode 100644 index 000000000..fffb6a815 --- /dev/null +++ b/scripts/snap_diff.py @@ -0,0 +1,50 @@ +""" +Compares two snapshots of how Delphi worked at two points of its implementation +A snapshot taken before and a snapshot taken after a code change such as an +optimization or refactoring could be compared to verify whether the accuracy of the +code got changed as a byproduct of the changes made to the code. If there is no +change at all, the before and after snaps should be identical and the plots produced +by this script should be a single bar at zero. + +If there are only minor changes, the plots should be concentrated at or close to zero. +""" + +import pandas as pd +import sys +import matplotlib.pyplot as plt +import seaborn as sns + +if len(sys.argv) < 3: + print(f'\nUsage: {sys.argv[0].split("/")[-1]} \n') + exit() + +df_before = pd.read_csv(sys.argv[1]) +df_before.rename(columns={'MAP_ll': 'MAP_ll_before'}, inplace=True) +df_after = pd.read_csv(sys.argv[2]) +df_after.rename(columns={'MAP_ll': 'MAP_ll_after'}, inplace=True) + +x = 'MAP LL Difference' +df_diff = pd.merge(left=df_before, right=df_after, on=['Model', 'Seed']) +df_diff[x] = df_diff['MAP_ll_before'] - df_diff['MAP_ll_after'] + +# Plot log likelihoods +sns.set_style("whitegrid") +fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1, dpi=150, figsize=(8, 4.5)) +plt.rcParams['font.size'] = 12 + +sns.histplot(df_diff, x=x, element='step', + color=(0.25, 0.875, 0.8125, 0.5), ax=ax1, stat='probability') + +df_diff_grp = df_diff.groupby(by=[x], as_index=False).count() +df_diff_grp.rename(columns={'Seed': 'Frequency'}, inplace=True) +sns.barplot(x=df_diff_grp[x], y=df_diff_grp['Frequency'], + color=(0.9375, 0.5, 0.5), ax=ax2) + +plt.suptitle(f'MAP Estimate Log Likelihood Difference\nBefore and After a Code Change:\ + $(\mu = {df_diff_grp[x].mean():.2f}, \sigma = {df_diff_grp[x].std()})$') +ax1.set_title('Probability Distribution') +ax2.set_title('Bar Plot') +ax1.set_xlabel('MAP Estimate Log Likelihood Difference') +ax2.set_xlabel('MAP Estimate Log Likelihood Difference') +plt.tight_layout() +plt.show() diff --git a/scripts/take_model_snapshot.py b/scripts/take_model_snapshot.py new file mode 100644 index 000000000..92f400672 --- /dev/null +++ b/scripts/take_model_snapshot.py @@ -0,0 +1,99 @@ +""" +Takes a snapshot of a how Delphi works at a particular point of its implementation +A snapshot taken before and a snapshot taken after a code change such as an +optimization or refactoring could be used to verify whether the accuracy of the +code got changed as a byproduct of the changes made to the code. If there is no +change at all, the before and after snaps should be identical. + +Use the snap_diff.py script to compare before and after snaps. +""" + +from delphi.cpp.DelphiPython import AnalysisGraph, InitialBeta, InitialDerivative +import pandas as pd +import datetime +import argparse + +# _______________________________________________________________________ +# Configuration +# For the snaps to be comparable, the configuration should be the same for before and after snaps +# Total number of runs = Number of seeds X Number of models +# Add enough distinct seeds to initialize the random number generator to sample different runs +# More seeds the better. But it would take longer to complete. We suggest 20 as a start. +seeds = [1, 14, 27, 5, 2020, 66, 2001, 38, 20211013, 81, 59, 100, 325, 774, 15, 92, 204, 571, 999, 76] + +# Add enough different models to sample runs. +# Better to have models with different number of nodes, edges and different topologies. +# Should have at least one model. +# The experiment json is for possible future extensions of the snapshot script. +# At the moment it could be left as an empty string. +models = [ + ("../tests/data/delphi/create_model_rain--temperature.json", + "../tests/data/delphi/experiments_rain--temperature--yield.json") +] + +burn = 10000 +res = 200 +kde_kernels = 1000 +use_continuous = False +initial_beta = InitialBeta.ZERO # ONE, HALF, MEAN, MEDIAN, PRIOR, RANDOM +initial_derivative = InitialDerivative.DERI_ZERO # DERI_PRIOR +belief_score_cutoff = 0 +grounding_score_cutoff = 0 +# End Configuration +# _______________________________________________________________________ + +parser = argparse.ArgumentParser(description='Take Delphi Snapshot') +parser.add_argument('-o', default='', type=str, metavar='Output file name suffix', + help='If provided, this is added as a suffix to the output file name, \ + which would be: snap_.csv. Otherwise, the output file name \ + would be: snap_.csv. We suggest using "before" \ + and "after" as suffixes for before and after snapshots respectively.') + +args = parser.parse_args() +suffix = args.o + +snaps = [] + +for model_id, model in enumerate(models): + for seed in seeds: + create_model, crete_experiment = model + print('\n', model_id, seed, '\n') + G = AnalysisGraph.from_causemos_json_file(filename=create_model, + belief_score_cutoff=belief_score_cutoff, + grounding_score_cutoff=grounding_score_cutoff, + kde_kernels=kde_kernels) + G.set_random_seed(seed) + G.run_train_model(res=res, + burn=burn, + initial_beta=initial_beta, + initial_derivative=initial_derivative, + use_continuous=use_continuous) + MAP_ll = G.get_MAP_log_likelihood() + + ''' + Possible extensions + 1. Take snaps of the sampled parameter distributions + model_state = G.get_complete_state() + concept_indicators, edges, adjectives, polarities, edge_data, derivatives, \ + data_range, data_set,pred_range, predictions, cis, log_likelihoods = model_state + + 2. Perform some projections and take snaps of the projections + (and sampled parameter distributions) + G.run_causemos_projection_experiment_from_json_file(filename=crete_experiment) + model_state = G.get_complete_state() + concept_indicators, edges, adjectives, polarities, edge_data, derivatives, \ + data_range, data_set,pred_range, predictions, cis, log_likelihoods = model_state + ''' + + snaps.append( + {'Model': model_id, + 'Seed': seed, + 'MAP_ll': MAP_ll} + ) + +columns = ('Model', 'Seed', 'MAP_ll') +snaps_df = pd.DataFrame(snaps) + +output_file_name = f'snap_{suffix if suffix else datetime.datetime.now()}.csv' \ + .replace(' ', '_').replace(':', '-') +snaps_df.to_csv(output_file_name, index=False, columns=columns) diff --git a/scripts/timing_analysis.py b/scripts/timing_analysis.py new file mode 100644 index 000000000..0f99d3f33 --- /dev/null +++ b/scripts/timing_analysis.py @@ -0,0 +1,68 @@ +import pathlib +import pandas as pd +import numpy as np +from matplotlib import pyplot as plt +from sklearn.linear_model import LinearRegression +import seaborn as sns +from mpl_toolkits.mplot3d import Axes3D + +plt.rcParams['figure.figsize'] = [20, 10] +plt.rcParams.update({'font.size': 18, 'figure.dpi': 150}) + +out_dir = 'plots/timing_analysis/' +if out_dir: + out_path = pathlib.Path(out_dir) + if not out_path.is_dir(): + print(f'\nMaking output directory: {out_dir}') + out_path.mkdir(parents=True, exist_ok=True) + +df_timing = pd.read_csv('timing.csv') +df_timing['Training (minutes)'] = df_timing['Train'].apply(lambda ms: ms / 60000.0) +df_timing['Predicting (seconds)'] = df_timing['Predict'].apply(lambda ms: ms / 1000.0) + +times = ['Training (minutes)', 'Predicting (seconds)'] +plot_no = 1 + + +for y in times: + sns.boxplot(data=df_timing, x='Nodes', y=y) + plt.title(f'Training Times') + plt.savefig(f'{out_dir}{plot_no}_{y} - box.png') + plt.close() + plot_no += 1 + + sns.violinplot(data=df_timing, x='Nodes', y=y, scale='count', bw=.15, inner='box') + plt.title(f'Training Times') + plt.savefig(f'{out_dir}{plot_no}_{y} - violin.png') + plt.close() + plot_no += 1 + + sns.lineplot(data=df_timing, x='Nodes', y=y, marker='o') + plt.title(f'Prediction Times') + plt.savefig(f'{out_dir}{plot_no}_{y} - line.png') + plt.close() + plot_no += 1 + + sns.scatterplot(data=df_timing, x='Nodes', y=y) + plt.title(f'Training Times') + plt.savefig(f'{out_dir}{plot_no}_{y} - scatter.png') + plt.close() + plot_no += 1 + + +''' +fig = plt.figure() +ax = fig.add_subplot(111, projection='3d') + +Axes3D.plot_surface(df_timing['Nodes'], df_timing['Edges'], df_timing['Training (minutes)']) +plt.show() +''' +''' +for nodes in range(2, 14): + for y in times: + sns.lineplot(data=df_timing[df_timing['Nodes'] == nodes], x='Edges', y=y, marker='o') + plt.title(f'Training Times - {nodes} Nodes CAG') + plt.savefig(f'{out_dir}nodes_{nodes}_{y} - line.png') + plt.close() + #plot_no += 1 +''' \ No newline at end of file diff --git a/tests/data/delphi/create_model_rain--temperature--yield.json b/tests/data/delphi/create_model_rain--temperature--yield.json new file mode 100644 index 000000000..55ac87d5d --- /dev/null +++ b/tests/data/delphi/create_model_rain--temperature--yield.json @@ -0,0 +1 @@ +{"id":"36582cad-1a36-4ce6-a0a8-2682ea0246b5","statements":[{"evidence":[{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"","document_source":"BackgroundSource","publication_date":{"date":1578528000000,"month":1,"year":2020,"day":9},"title":"","analysis":{"sentiment":"positive","sentiment_score":0.62,"subjectivity_score":0.25,"subjectivity":"subjective","stance":""},"doc_id":"3286a7c68f4b57f82e1b9c8635df5aa7"},"evidence_context":{"subj_polarity":null,"source_api":"eidos","obj_adjectives":[],"contradiction_words":[],"subj_adjectives":[],"agents_text":["Improved kiremt rains","increased crop production in the country"],"obj_polarity":1,"hedging_words":[],"text":"Improved kiremt rains have contributed to increased crop production in the country and above average pastures in some areas .","source_hash":3577260213553539000}},{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"USAID - ATLAS","document_source":"BackgroundSource","publication_date":{"date":1466121600000,"month":6,"year":2016,"day":17},"title":"Climate Variability and Change in Ethiopia","analysis":{"sentiment":"neutral","sentiment_score":0.5,"subjectivity_score":0,"subjectivity":"subjective","stance":""},"doc_id":"c632636ebd9f6c4e642d8705b42b2d2b"},"evidence_context":{"subj_polarity":-1,"source_api":"eidos","obj_adjectives":[],"contradiction_words":[],"subj_adjectives":[],"agents_text":["lower amounts of seasonal rains","crop production"],"obj_polarity":-1,"hedging_words":[],"text":"Rising temperatures , increasingly erratic rainfall , shortened rainy seasons , and lower amounts of seasonal rains are reducing crop production ( Figure 2 ) .","source_hash":2627401241796174000}},{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"","document_source":"BackgroundSource","publication_date":{"date":1587340800000,"month":4,"year":2020,"day":20},"title":"","analysis":{"sentiment":"neutral","sentiment_score":0.51,"subjectivity_score":0.1,"subjectivity":"subjective","stance":""},"doc_id":"619152e830bba6bac114ad1cea194968"},"evidence_context":{"subj_polarity":null,"source_api":"eidos","obj_adjectives":[],"contradiction_words":[],"subj_adjectives":["abundant"],"agents_text":["Exceptionally abundant rains","crop yields"],"obj_polarity":1,"hedging_words":[],"text":"Exceptionally abundant rains during the October-December 2019 short rainy season boosted crop yields , but also triggered flooding , causing localized crop losses and damage to infrastructure .","source_hash":-3109862787434654700}},{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"Christina","document_source":"BackgroundSource","publication_date":{"date":1614816000000,"month":3,"year":2021,"day":4},"title":"","analysis":{"sentiment":"neutral","sentiment_score":0.5,"subjectivity_score":0,"subjectivity":"subjective","stance":""},"doc_id":"9457fa07cc9fe9e50a566f5d7e65daad"},"evidence_context":{"subj_polarity":1,"source_api":"eidos","obj_adjectives":[],"contradiction_words":[],"subj_adjectives":[],"agents_text":["heavy rainfall","crop production"],"obj_polarity":null,"hedging_words":["likely"],"text":"However , heavy rainfall is also likely to improve crop production after several years of drought conditions .","source_hash":8758949169130408000}},{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"abaytana","document_source":"BackgroundSource","publication_date":{"date":1535414400000,"month":8,"year":2018,"day":28},"title":"","analysis":{"sentiment":"neutral","sentiment_score":0.51,"subjectivity_score":0.15,"subjectivity":"subjective","stance":""},"doc_id":"6b131373dd59ff46c5f7c9d9799975cc"},"evidence_context":{"subj_polarity":null,"source_api":"eidos","obj_adjectives":[],"contradiction_words":[],"subj_adjectives":[],"agents_text":["rainfall","high crop production by the household"],"obj_polarity":1,"hedging_words":[],"text":"This may be explained by the fact that as one moves from kolla to Woyina Dega agroecology in the study area , the rainfall and vegetation cover increases which result in high crop production by the household and hence enhances food security .","source_hash":2625898162430920000}},{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"brinehart","document_source":"BackgroundSource","publication_date":{"date":1514505600000,"month":12,"year":2017,"day":29},"title":"COUNTRY Food Security Update","analysis":{"sentiment":"neutral","sentiment_score":0.5,"subjectivity_score":0,"subjectivity":"subjective","stance":""},"doc_id":"e377458f1f6928dc3140197b2d3a5551"},"evidence_context":{"subj_polarity":null,"source_api":"eidos","obj_adjectives":[],"contradiction_words":[],"subj_adjectives":["long"],"agents_text":["long rains","crop production"],"obj_polarity":null,"hedging_words":["expect"],"text":"While there are some regional variations in the forecast , the short rains ( October - December ) and long rains ( March - May ) are expected to lead to better livestock productivity and crop production .","source_hash":-1374913166879274500}},{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"USAID - ATLAS","document_source":"BackgroundSource","publication_date":{"date":1450396800000,"month":12,"year":2015,"day":18},"title":"Climate Variability and Change in Ethiopia","analysis":{"sentiment":"neutral","sentiment_score":0.5,"subjectivity_score":0,"subjectivity":"subjective","stance":""},"doc_id":"3fe352bdf88f658d1f0a37d822994aca"},"evidence_context":{"subj_polarity":-1,"source_api":"eidos","obj_adjectives":[],"contradiction_words":[],"subj_adjectives":[],"agents_text":["lower amounts of seasonal rains","crop production"],"obj_polarity":-1,"hedging_words":[],"text":"Rising temperatures , increasingly erratic rainfall , shortened rainy seasons , and lower amounts of seasonal rains are reducing crop production ( Figure 2 ) .","source_hash":2627401241796174000}},{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"FEWS NET","document_source":"BackgroundSource","publication_date":{"date":1571011200000,"month":10,"year":2019,"day":14},"title":"1BSeptember 23, 2019","analysis":{"sentiment":"neutral","sentiment_score":0.5,"subjectivity_score":0,"subjectivity":"subjective","stance":""},"doc_id":"c1cf5a6ccd0ef6816457ae2c0d9604e7"},"evidence_context":{"subj_polarity":null,"source_api":"eidos","obj_adjectives":["likely"],"contradiction_words":[],"subj_adjectives":["likely"],"agents_text":["rains","Season C production of crops"],"obj_polarity":1,"hedging_words":["likely"],"text":"These rains are likely to ease the drierthan-normal conditions in northeastern Burundi bordering Tanzania and will likely enhance Season C production of crops in marshland areas .","source_hash":1640197272265207800}},{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"rogerio.bonifacio@wfp.org","document_source":"BackgroundSource","publication_date":{"date":1498694400000,"month":6,"year":2017,"day":29},"title":"PowerPoint Presentation","analysis":{"sentiment":"neutral","sentiment_score":0.5,"subjectivity_score":0,"subjectivity":"subjective","stance":""},"doc_id":"3711dd876f00b6132f1f94d833731896"},"evidence_context":{"subj_polarity":1,"source_api":"eidos","obj_adjectives":["good"],"contradiction_words":[],"subj_adjectives":[],"agents_text":["late heavy rains","good crop production"],"obj_polarity":null,"hedging_words":["likely"],"text":"Even where rainfall seems average , it is due to late heavy rains which are less likely to result in good crop production .","source_hash":-477934239260735170}},{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"FAO","document_source":"BackgroundSource","publication_date":{"date":1571184000000,"month":10,"year":2019,"day":16},"title":"Early Warning Early Action Report on Food Security and Agriculture ��� October���December 2019","analysis":{"sentiment":"neutral","sentiment_score":0.55,"subjectivity_score":0.23,"subjectivity":"subjective","stance":""},"doc_id":"8dbcfb31e8728cc61ca9eb75be4d6c32"},"evidence_context":{"subj_polarity":null,"source_api":"eidos","obj_adjectives":[],"contradiction_words":[],"subj_adjectives":[],"agents_text":["rains","crop yields"],"obj_polarity":1,"hedging_words":["expect"],"text":"While the rains are expected to boost crop yields , flooding poses a serious threat to livelihoods and infrastructure .","source_hash":7735966961835053000}},{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"Veronique Lee","document_source":"BackgroundSource","publication_date":{"date":1568332800000,"month":9,"year":2019,"day":13},"title":"Template","analysis":{"sentiment":"neutral","sentiment_score":0.5,"subjectivity_score":0,"subjectivity":"subjective","stance":""},"doc_id":"3ad48dc7fa1de128d671625ffd79ebb3"},"evidence_context":{"subj_polarity":-1,"source_api":"eidos","obj_adjectives":[],"contradiction_words":[],"subj_adjectives":[],"agents_text":["rainfall shortages","rainfed crop production of agropastoralists"],"obj_polarity":-1,"hedging_words":[],"text":"Chronic drought and rainfall shortages and unpredictability have repeatedly depleted the livestock assets of pastoralists and the rainfed crop production of agropastoralists .","source_hash":5689318775474947000}}],"obj":{"geo_context":{},"process":"wm/process/produce","time_context":{"start":{"date":1578528000000,"month":1,"year":2020,"day":9},"end":{"date":1578614400000,"month":1,"year":2020,"day":10}},"theme_property":"","concept":"wm/concept/agriculture/crop_produce","concept_score":1.0000001788139343,"theme":"wm/concept/agriculture/crop","process_property":"","factor":"produce of crop","polarity":1,"adjectives":[]},"id":"08539fe0-e8c7-4d67-a895-f7a690951f5f","matches_hash":33847142928807590,"modified_at":1622670140573,"subj":{"geo_context":{},"process":"","time_context":{"start":{"date":1578528000000,"month":1,"year":2020,"day":9},"end":{"date":1578614400000,"month":1,"year":2020,"day":10}},"theme_property":"","concept":"wm/concept/environment/meteorology/precipitation","concept_score":0.8257776498794556,"theme":"wm/concept/environment/meteorology/precipitation","process_property":"","factor":"precipitation","polarity":1,"adjectives":[]},"belief":0.2799649999999934},{"evidence":[{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"","document_source":"BackgroundSource","publication_date":{"date":1587340800000,"month":4,"year":2020,"day":20},"title":"","analysis":{"sentiment":"neutral","sentiment_score":0.51,"subjectivity_score":0.1,"subjectivity":"subjective","stance":""},"doc_id":"619152e830bba6bac114ad1cea194968"},"evidence_context":{"subj_polarity":-1,"source_api":"eidos","obj_adjectives":[],"contradiction_words":[],"subj_adjectives":[],"agents_text":["below-average rains","main season food crop production"],"obj_polarity":-1,"hedging_words":[],"text":"In the Democratic Republic of the Congo flooding , crop pests and below-average rains all disrupted the main season food crop production , which was forecast below the previous five years , limiting market supplies and prompting an early start to the lean season in northern , central-eastern and south-eastern provinces ( FAO and GIEWS , September 2019 ) .","source_hash":-7073711815756055000}}],"obj":{"geo_context":{"name":"Republic of the Congo","location":{"lon":15.5,"lat":-1}},"process":"wm/process/produce","time_context":{"start":{"date":1429488000000,"month":4,"year":2015,"day":20},"end":{"date":1587340800000,"month":4,"year":2020,"day":20}},"theme_property":"","concept":"wm/concept/agriculture/crop_produce","concept_score":1.0000001788139343,"theme":"wm/concept/agriculture/crop","process_property":"","factor":"produce of crop","polarity":-1,"adjectives":[]},"id":"e295d019-628c-4b4c-b612-ad2e9341dcf0","matches_hash":33847142928807590,"modified_at":1622670183127,"subj":{"geo_context":{"name":"Republic of the Congo","location":{"lon":15.5,"lat":-1}},"process":"","time_context":{"start":{"date":1587340800000,"month":4,"year":2020,"day":20},"end":{"date":1587427200000,"month":4,"year":2020,"day":21}},"theme_property":"","concept":"wm/concept/environment/meteorology/precipitation","concept_score":0.8257776498794556,"theme":"wm/concept/environment/meteorology/precipitation","process_property":"","factor":"precipitation","polarity":-1,"adjectives":[]},"belief":0.7053},{"evidence":[{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"FAO","document_source":"BackgroundSource","publication_date":{"date":1611532800000,"month":1,"year":2021,"day":25},"title":"FAO 2020–2021 La Niña advisory","analysis":{"sentiment":"neutral","sentiment_score":0.5,"subjectivity_score":0,"subjectivity":"subjective","stance":""},"doc_id":"782c80059da7859ae2392043c2f4770a"},"evidence_context":{"subj_polarity":null,"source_api":"eidos","obj_adjectives":["most"],"contradiction_words":[],"subj_adjectives":["abundant"],"agents_text":["exceptionally abundant Gu rains","improved crop and livestock production in most areas"],"obj_polarity":null,"hedging_words":[],"text":"Between March and June 2020 , the region has benefitted from exceptionally abundant Gu rains ( the long rains ) , which have resulted in improved crop and livestock production in most areas .","source_hash":520823088667570560}}],"obj":{"geo_context":{},"process":"wm/process/produce","time_context":{"start":{"date":1611532800000,"month":1,"year":2021,"day":25},"end":{"date":1611619200000,"month":1,"year":2021,"day":26}},"theme_property":"","concept":"wm/concept/agriculture/crop_produce","concept_score":1.0000001788139343,"theme":"wm/concept/agriculture/crop","process_property":"","factor":"produce of crop","polarity":1,"adjectives":["most"]},"id":"cbab993a-606c-481e-adc6-f862dde56578","matches_hash":33847142928807590,"modified_at":1622670218473,"subj":{"geo_context":{},"process":"","time_context":{"start":{"date":1611532800000,"month":1,"year":2021,"day":25},"end":{"date":1611619200000,"month":1,"year":2021,"day":26}},"theme_property":"","concept":"wm/concept/environment/meteorology/precipitation","concept_score":0.8257776498794556,"theme":"wm/concept/environment/meteorology/precipitation","process_property":"","factor":"precipitation","polarity":1,"adjectives":["abundant"]},"belief":0.84},{"evidence":[{"document_context":{"publisher_name":"","file_type":"application/pdf","author":"brinehart","document_source":"BackgroundSource","publication_date":{"date":1514419200000,"month":12,"year":2017,"day":28},"title":"COUNTRY Food Security Update","analysis":{"sentiment":"neutral","sentiment_score":0.5,"subjectivity_score":0,"subjectivity":"subjective","stance":""},"doc_id":"dfb96f131631d12265e84539fdcdb0df"},"evidence_context":{"subj_polarity":null,"source_api":"eidos","obj_adjectives":[],"contradiction_words":["not"],"subj_adjectives":[],"agents_text":["additional rainfall","crop yield prospects"],"obj_polarity":null,"hedging_words":["may","could"],"text":"In coastal Kenya , additional rainfall could help to ease seasonal deficits , but may not significantly improve crop yield prospects .","source_hash":-48095575841105200}}],"obj":{"geo_context":{"name":"Republic of Kenya","location":{"lon":38,"lat":1}},"process":"wm/process/produce","time_context":{"start":{"date":1522281600000,"month":3,"year":2018,"day":29},"end":{"date":1522368000000,"month":3,"year":2018,"day":30}},"theme_property":"","concept":"wm/concept/agriculture/crop_produce","concept_score":1.0000001788139343,"theme":"wm/concept/agriculture/crop","process_property":"","factor":"produce of crop","polarity":1,"adjectives":[]},"id":"442f4ab0-2123-4fb9-b1dc-3fb24c2e5649","matches_hash":33847142928807590,"modified_at":1622670247464,"subj":{"geo_context":{"name":"Republic of Kenya","location":{"lon":38,"lat":1}},"process":"","time_context":{"start":{"date":1522281600000,"month":3,"year":2018,"day":29},"end":{"date":1522368000000,"month":3,"year":2018,"day":30}},"theme_property":"","concept":"wm/concept/environment/meteorology/precipitation","concept_score":0.8845658898353577,"theme":"wm/concept/environment/meteorology/precipitation","process_property":"","factor":"precipitation","polarity":1,"adjectives":[]},"belief":0},{"id":"stub_statement","belief":1,"evidence":[{"document_context":{},"evidence_context":{"obj_polarity":-1,"obj_adjectives":[],"subj_polarity":1,"subj_adjectives":[]}}],"subj":{"factor":"user","concept":"wm/concept/environment/meteorology/precipitation","concept_score":1,"adjectives":[],"polarity":1},"obj":{"factor":"user","concept":"wm/concept/environment/meteorology/temperature","concept_score":1,"adjectives":[],"polarity":-1}}],"conceptIndicators":{"wm/concept/environment/meteorology/temperature":{"name":"Mean Temperature","minValue":22.397182758620687,"maxValue":33.38314666666667,"func":"last","values":[{"value":24.86295806451613,"timestamp":662688000000},{"value":25.132807142857143,"timestamp":665366400000},{"value":26.54966129032258,"timestamp":667785600000},{"value":29.79424333333333,"timestamp":670464000000},{"value":30.952345161290317,"timestamp":673056000000},{"value":32.113926666666664,"timestamp":675734400000},{"value":31.313387096774196,"timestamp":678326400000},{"value":30.894693548387096,"timestamp":681004800000},{"value":30.933393333333342,"timestamp":683683200000},{"value":28.554380645161284,"timestamp":686275200000},{"value":25.50030666666667,"timestamp":688953600000},{"value":24.461483870967744,"timestamp":691545600000},{"value":23.273829032258057,"timestamp":694224000000},{"value":22.397182758620687,"timestamp":696902400000},{"value":26.386206451612907,"timestamp":699408000000},{"value":28.46132,"timestamp":702086400000},{"value":31.044451612903224,"timestamp":704678400000},{"value":31.93410999999999,"timestamp":707356800000},{"value":31.08583548387097,"timestamp":709948800000},{"value":29.05188709677419,"timestamp":712627200000},{"value":29.226513333333333,"timestamp":715305600000},{"value":27.914638709677416,"timestamp":717897600000},{"value":25.622833333333332,"timestamp":720576000000},{"value":24.277583870967746,"timestamp":723168000000},{"value":22.73682258064516,"timestamp":725846400000},{"value":22.718735714285714,"timestamp":728524800000},{"value":26.9044064516129,"timestamp":730944000000},{"value":27.090993333333337,"timestamp":733622400000},{"value":29.076129032258063,"timestamp":736214400000},{"value":31.630873333333337,"timestamp":738892800000},{"value":31.365125806451616,"timestamp":741484800000},{"value":31.182125806451612,"timestamp":744163200000},{"value":30.766403333333336,"timestamp":746841600000},{"value":28.825648387096766,"timestamp":749433600000},{"value":26.514196666666667,"timestamp":752112000000},{"value":24.70176129032258,"timestamp":754704000000},{"value":24.260645161290316,"timestamp":757382400000},{"value":25.445599999999995,"timestamp":760060800000},{"value":26.727267741935485,"timestamp":762480000000},{"value":30.161196666666665,"timestamp":765158400000},{"value":31.557422580645166,"timestamp":767750400000},{"value":32.18229666666667,"timestamp":770428800000},{"value":30.27816774193548,"timestamp":773020800000},{"value":29.775316129032255,"timestamp":775699200000},{"value":29.766720000000003,"timestamp":778377600000},{"value":28.68954193548387,"timestamp":780969600000},{"value":26.45734333333333,"timestamp":783648000000},{"value":24.031783870967747,"timestamp":786240000000},{"value":24.276893548387097,"timestamp":788918400000},{"value":25.498203571428572,"timestamp":791596800000},{"value":26.191754838709677,"timestamp":794016000000},{"value":28.425693333333324,"timestamp":796694400000},{"value":31.274564516129036,"timestamp":799286400000},{"value":32.53478000000001,"timestamp":801964800000},{"value":30.347999999999995,"timestamp":804556800000},{"value":29.632751612903217,"timestamp":807235200000},{"value":30.668000000000003,"timestamp":809913600000},{"value":29.145170967741933,"timestamp":812505600000},{"value":26.296929999999996,"timestamp":815184000000},{"value":25.118561290322578,"timestamp":817776000000},{"value":24.68018387096775,"timestamp":820454400000},{"value":26.172893103448274,"timestamp":823132800000},{"value":27.176609677419354,"timestamp":825638400000},{"value":28.990573333333337,"timestamp":828316800000},{"value":29.394851612903228,"timestamp":830908800000},{"value":31.00897666666667,"timestamp":833587200000},{"value":31.11190967741936,"timestamp":836179200000},{"value":30.145816129032255,"timestamp":838857600000},{"value":29.834786666666673,"timestamp":841536000000},{"value":28.72504516129033,"timestamp":844128000000},{"value":25.644556666666666,"timestamp":846806400000},{"value":24.22446774193548,"timestamp":849398400000},{"value":23.397748387096772,"timestamp":852076800000},{"value":24.493521428571434,"timestamp":854755200000},{"value":26.595648387096777,"timestamp":857174400000},{"value":28.207233333333328,"timestamp":859852800000},{"value":31.10853870967741,"timestamp":862444800000},{"value":32.19592333333333,"timestamp":865123200000},{"value":31.450164516129032,"timestamp":867715200000},{"value":31.039829032258073,"timestamp":870393600000},{"value":31.708863333333333,"timestamp":873072000000},{"value":27.524154838709673,"timestamp":875664000000},{"value":26.216326666666667,"timestamp":878342400000},{"value":25.164474193548383,"timestamp":880934400000},{"value":24.462161290322577,"timestamp":883612800000},{"value":25.575925,"timestamp":886291200000},{"value":27.475738709677426,"timestamp":888710400000},{"value":30.48144,"timestamp":891388800000},{"value":31.887125806451614,"timestamp":893980800000},{"value":32.94343,"timestamp":896659200000},{"value":31.324209677419358,"timestamp":899251200000},{"value":29.287080645161293,"timestamp":901929600000},{"value":29.521180000000008,"timestamp":904608000000},{"value":28.839193548387094,"timestamp":907200000000},{"value":26.523276666666668,"timestamp":909878400000},{"value":24.668364516129035,"timestamp":912470400000},{"value":24.45384516129032,"timestamp":915148800000},{"value":26.673385714285708,"timestamp":917827200000},{"value":26.165087096774194,"timestamp":920246400000},{"value":30.094539999999995,"timestamp":922924800000},{"value":32.299138709677415,"timestamp":925516800000},{"value":32.17985999999999,"timestamp":928195200000},{"value":30.451777419354833,"timestamp":930787200000},{"value":30.248664516129026,"timestamp":933465600000},{"value":30.465026666666677,"timestamp":936144000000},{"value":27.244919354838718,"timestamp":938736000000},{"value":26.154186666666664,"timestamp":941414400000},{"value":24.4702064516129,"timestamp":944006400000},{"value":24.130774193548394,"timestamp":946684800000},{"value":25.697155172413794,"timestamp":949363200000},{"value":27.223687096774192,"timestamp":951868800000},{"value":29.863233333333334,"timestamp":954547200000},{"value":30.837245161290326,"timestamp":957139200000},{"value":31.835590000000003,"timestamp":959817600000},{"value":31.25467741935484,"timestamp":962409600000},{"value":29.099851612903223,"timestamp":965088000000},{"value":30.203536666666672,"timestamp":967766400000},{"value":27.740599999999997,"timestamp":970358400000},{"value":25.475306666666665,"timestamp":973036800000},{"value":23.694912903225806,"timestamp":975628800000},{"value":22.95638387096774,"timestamp":978307200000},{"value":24.76266071428571,"timestamp":980985600000},{"value":26.652351612903228,"timestamp":983404800000},{"value":29.954119999999993,"timestamp":986083200000},{"value":31.28690000000001,"timestamp":988675200000},{"value":32.021693333333324,"timestamp":991353600000},{"value":30.61878064516129,"timestamp":993945600000},{"value":28.994706451612902,"timestamp":996624000000},{"value":30.00396,"timestamp":999302400000},{"value":29.507287096774196,"timestamp":1001894400000},{"value":26.209039999999998,"timestamp":1004572800000},{"value":24.85181290322581,"timestamp":1007164800000},{"value":23.5442129032258,"timestamp":1009843200000},{"value":25.41718928571428,"timestamp":1012521600000},{"value":27.52885161290323,"timestamp":1014940800000},{"value":28.54994333333334,"timestamp":1017619200000},{"value":31.475503225806445,"timestamp":1020211200000},{"value":32.14381666666667,"timestamp":1022889600000},{"value":32.494558064516134,"timestamp":1025481600000},{"value":31.330654838709673,"timestamp":1028160000000},{"value":30.03016333333333,"timestamp":1030838400000},{"value":29.42600322580645,"timestamp":1033430400000},{"value":26.98337,"timestamp":1036108800000},{"value":24.6396064516129,"timestamp":1038700800000},{"value":23.603461290322574,"timestamp":1041379200000},{"value":26.387796428571427,"timestamp":1044057600000},{"value":27.436367741935477,"timestamp":1046476800000},{"value":28.45589333333333,"timestamp":1049155200000},{"value":32.049396774193546,"timestamp":1051747200000},{"value":32.005669999999995,"timestamp":1054425600000},{"value":31.262145161290324,"timestamp":1057017600000},{"value":28.87483548387097,"timestamp":1059696000000},{"value":30.23267666666667,"timestamp":1062374400000},{"value":28.85755483870967,"timestamp":1064966400000},{"value":26.547206666666668,"timestamp":1067644800000},{"value":23.94398387096774,"timestamp":1070236800000},{"value":24.50213870967742,"timestamp":1072915200000},{"value":24.271189655172414,"timestamp":1075593600000},{"value":26.943590322580643,"timestamp":1078099200000},{"value":27.94561666666667,"timestamp":1080777600000},{"value":31.54308064516129,"timestamp":1083369600000},{"value":31.89315333333333,"timestamp":1086048000000},{"value":31.874574193548387,"timestamp":1088640000000},{"value":31.047503225806448,"timestamp":1091318400000},{"value":31.082146666666667,"timestamp":1093996800000},{"value":28.864167741935482,"timestamp":1096588800000},{"value":26.740779999999997,"timestamp":1099267200000},{"value":24.752941935483864,"timestamp":1101859200000},{"value":23.888770967741944,"timestamp":1104537600000},{"value":26.06273928571428,"timestamp":1107216000000},{"value":27.63122258064517,"timestamp":1109635200000},{"value":29.084976666666666,"timestamp":1112313600000},{"value":30.108061290322578,"timestamp":1114905600000},{"value":32.30074333333332,"timestamp":1117584000000},{"value":30.920690322580647,"timestamp":1120176000000},{"value":31.506180645161287,"timestamp":1122854400000},{"value":30.951656666666672,"timestamp":1125532800000},{"value":29.325832258064512,"timestamp":1128124800000},{"value":26.60961,"timestamp":1130803200000},{"value":24.469325806451614,"timestamp":1133395200000},{"value":24.27066129032258,"timestamp":1136073600000},{"value":26.245375,"timestamp":1138752000000},{"value":27.301745161290324,"timestamp":1141171200000},{"value":28.400793333333333,"timestamp":1143849600000},{"value":31.40136774193548,"timestamp":1146441600000},{"value":32.363809999999994,"timestamp":1149120000000},{"value":31.093767741935483,"timestamp":1151712000000},{"value":30.1714,"timestamp":1154390400000},{"value":30.031893333333333,"timestamp":1157068800000},{"value":28.980435483870973,"timestamp":1159660800000},{"value":26.610856666666663,"timestamp":1162339200000},{"value":24.755974193548386,"timestamp":1164931200000},{"value":23.58546129032258,"timestamp":1167609600000},{"value":26.232692857142855,"timestamp":1170288000000},{"value":27.694112903225808,"timestamp":1172707200000},{"value":29.275829999999996,"timestamp":1175385600000},{"value":32.08432903225807,"timestamp":1177977600000},{"value":31.97184,"timestamp":1180656000000},{"value":30.093583870967745,"timestamp":1183248000000},{"value":30.306825806451606,"timestamp":1185926400000},{"value":30.55679666666667,"timestamp":1188604800000},{"value":28.43743870967742,"timestamp":1191196800000},{"value":26.18127666666667,"timestamp":1193875200000},{"value":24.15435806451613,"timestamp":1196467200000},{"value":24.368858064516125,"timestamp":1199145600000},{"value":24.34289655172414,"timestamp":1201824000000},{"value":27.184290322580647,"timestamp":1204329600000},{"value":29.57276333333334,"timestamp":1207008000000},{"value":31.073545161290316,"timestamp":1209600000000},{"value":31.723076666666664,"timestamp":1212278400000},{"value":31.772596774193545,"timestamp":1214870400000},{"value":31.32441612903226,"timestamp":1217548800000},{"value":30.672520000000006,"timestamp":1220227200000},{"value":28.38856129032258,"timestamp":1222819200000},{"value":25.185366666666663,"timestamp":1225497600000},{"value":23.835977419354837,"timestamp":1228089600000},{"value":24.08534193548387,"timestamp":1230768000000},{"value":26.399807142857146,"timestamp":1233446400000},{"value":27.704893548387094,"timestamp":1235865600000},{"value":29.898023333333324,"timestamp":1238544000000},{"value":31.28515806451613,"timestamp":1241136000000},{"value":32.71743333333333,"timestamp":1243814400000},{"value":31.94021290322581,"timestamp":1246406400000},{"value":31.10592903225806,"timestamp":1249084800000},{"value":31.314953333333328,"timestamp":1251763200000},{"value":28.483,"timestamp":1254355200000},{"value":26.617309999999996,"timestamp":1257033600000},{"value":25.873964516129032,"timestamp":1259625600000},{"value":24.583554838709674,"timestamp":1262304000000},{"value":25.473925000000005,"timestamp":1264982400000},{"value":27.045038709677417,"timestamp":1267401600000},{"value":29.638510000000007,"timestamp":1270080000000},{"value":31.31575161290323,"timestamp":1272672000000},{"value":32.663086666666665,"timestamp":1275350400000},{"value":30.278009677419355,"timestamp":1277942400000},{"value":30.22356774193548,"timestamp":1280620800000},{"value":30.03330333333333,"timestamp":1283299200000},{"value":29.467783870967736,"timestamp":1285891200000},{"value":26.379853333333337,"timestamp":1288569600000},{"value":24.012690322580646,"timestamp":1291161600000},{"value":24.065032258064516,"timestamp":1293840000000},{"value":25.474528571428575,"timestamp":1296518400000},{"value":26.544219354838706,"timestamp":1298937600000},{"value":29.92544666666667,"timestamp":1301616000000},{"value":30.094322580645166,"timestamp":1304208000000},{"value":31.829473333333333,"timestamp":1306886400000},{"value":31.51112903225806,"timestamp":1309478400000},{"value":29.2929870967742,"timestamp":1312156800000},{"value":30.509526666666662,"timestamp":1314835200000},{"value":28.42188387096775,"timestamp":1317427200000},{"value":25.935076666666678,"timestamp":1320105600000},{"value":23.82311935483871,"timestamp":1322697600000},{"value":24.24770322580645,"timestamp":1325376000000},{"value":25.219651724137936,"timestamp":1328054400000},{"value":26.836238709677417,"timestamp":1330560000000},{"value":29.197453333333335,"timestamp":1333238400000},{"value":31.42051935483871,"timestamp":1335830400000},{"value":32.43823666666667,"timestamp":1338508800000},{"value":31.198948387096774,"timestamp":1341100800000},{"value":31.01210322580646,"timestamp":1343779200000},{"value":31.191509999999994,"timestamp":1346457600000},{"value":28.788048387096772,"timestamp":1349049600000},{"value":26.862376666666663,"timestamp":1351728000000},{"value":25.502480645161295,"timestamp":1354320000000},{"value":24.83181612903226,"timestamp":1356998400000},{"value":25.682299999999998,"timestamp":1359676800000},{"value":27.398125806451617,"timestamp":1362096000000},{"value":29.042863333333333,"timestamp":1364774400000},{"value":31.74748064516129,"timestamp":1367366400000},{"value":32.39842,"timestamp":1370044800000},{"value":31.147967741935478,"timestamp":1372636800000},{"value":29.033816129032257,"timestamp":1375315200000},{"value":30.915473333333342,"timestamp":1377993600000},{"value":28.729635483870968,"timestamp":1380585600000},{"value":26.70407,"timestamp":1383264000000},{"value":23.790454838709678,"timestamp":1385856000000},{"value":24.476751612903225,"timestamp":1388534400000},{"value":25.378446428571433,"timestamp":1391212800000},{"value":27.505851612903225,"timestamp":1393632000000},{"value":30.167793333333332,"timestamp":1396310400000},{"value":30.55179032258064,"timestamp":1398902400000},{"value":32.358866666666664,"timestamp":1401580800000},{"value":31.721548387096778,"timestamp":1404172800000},{"value":30.234212903225814,"timestamp":1406851200000},{"value":30.147063333333335,"timestamp":1409529600000},{"value":27.783480645161287,"timestamp":1412121600000},{"value":26.771466666666676,"timestamp":1414800000000},{"value":24.446429032258067,"timestamp":1417392000000},{"value":23.626135483870968,"timestamp":1420070400000},{"value":25.656246428571432,"timestamp":1422748800000},{"value":28.216003225806453,"timestamp":1425168000000},{"value":29.890159999999998,"timestamp":1427846400000},{"value":31.102554838709683,"timestamp":1430438400000},{"value":32.18640333333333,"timestamp":1433116800000},{"value":33.0358677419355,"timestamp":1435708800000},{"value":32.23883548387097,"timestamp":1438387200000},{"value":31.725473333333337,"timestamp":1441065600000},{"value":30.40855483870968,"timestamp":1443657600000},{"value":27.57449666666667,"timestamp":1446336000000},{"value":25.3426129032258,"timestamp":1448928000000},{"value":25.090077419354834,"timestamp":1451606400000},{"value":26.182755172413792,"timestamp":1454284800000},{"value":30.299516129032256,"timestamp":1456790400000},{"value":28.54819666666667,"timestamp":1459468800000},{"value":31.264190322580635,"timestamp":1462060800000},{"value":33.116080000000004,"timestamp":1464739200000},{"value":30.938970967741938,"timestamp":1467331200000},{"value":30.09242580645161,"timestamp":1470009600000},{"value":31.719943333333333,"timestamp":1472688000000},{"value":29.9146064516129,"timestamp":1475280000000},{"value":26.725856666666665,"timestamp":1477958400000},{"value":25.569358064516138,"timestamp":1480550400000},{"value":24.87566129032258,"timestamp":1483228800000},{"value":24.985339285714286,"timestamp":1485907200000},{"value":28.379903225806455,"timestamp":1488326400000},{"value":30.58911333333333,"timestamp":1491004800000},{"value":30.775587096774196,"timestamp":1493596800000},{"value":33.38314666666667,"timestamp":1496275200000},{"value":33.10136451612903,"timestamp":1498867200000},{"value":31.334748387096774,"timestamp":1501545600000},{"value":31.38021666666665,"timestamp":1504224000000},{"value":29.83076129032258,"timestamp":1506816000000},{"value":27.193993333333342,"timestamp":1509494400000},{"value":23.960296774193544,"timestamp":1512086400000},{"value":23.52738064516129,"timestamp":1514764800000},{"value":26.36581071428571,"timestamp":1517443200000},{"value":28.263512903225802,"timestamp":1519862400000},{"value":29.41648,"timestamp":1522540800000},{"value":31.54575806451613,"timestamp":1525132800000},{"value":32.583773333333326,"timestamp":1527811200000},{"value":31.64165806451613,"timestamp":1530403200000},{"value":31.09654516129033,"timestamp":1533081600000},{"value":31.05386,"timestamp":1535760000000},{"value":28.96214516129032,"timestamp":1538352000000},{"value":27.13166333333333,"timestamp":1541030400000},{"value":25.68454516129033,"timestamp":1543622400000},{"value":25.283158064516122,"timestamp":1546300800000},{"value":26.651496428571424,"timestamp":1548979200000},{"value":28.37367419354839,"timestamp":1551398400000},{"value":30.04280333333334,"timestamp":1554076800000},{"value":31.15893548387097,"timestamp":1556668800000},{"value":32.30068000000001,"timestamp":1559347200000},{"value":32.47812903225805,"timestamp":1561939200000},{"value":30.347477419354842,"timestamp":1564617600000},{"value":31.065396666666672,"timestamp":1567296000000},{"value":28.27787419354838,"timestamp":1569888000000},{"value":27.33406,"timestamp":1572566400000},{"value":25.796612903225803,"timestamp":1575158400000},{"value":24.14383548387097,"timestamp":1577836800000},{"value":26.030389655172414,"timestamp":1580515200000},{"value":27.92293548387097,"timestamp":1583020800000},{"value":29.40862,"timestamp":1585699200000},{"value":31.621658064516133,"timestamp":1588291200000},{"value":32.352473333333336,"timestamp":1590969600000},{"value":32.12196666666667,"timestamp":1593561600000}],"numLevels":31},"wm/concept/environment/meteorology/precipitation":{"name":"Precipitation","minValue":0.000012903225806451613,"maxValue":9.463974193548387,"func":"last","values":[{"value":0.06728709677419355,"timestamp":662688000000},{"value":0.9487749999999998,"timestamp":665366400000},{"value":2.294458064516129,"timestamp":667785600000},{"value":0.9806033333333333,"timestamp":670464000000},{"value":0.7540387096774193,"timestamp":673056000000},{"value":0.24305333333333332,"timestamp":675734400000},{"value":4.698829032258065,"timestamp":678326400000},{"value":5.648793548387096,"timestamp":681004800000},{"value":1.3958533333333334,"timestamp":683683200000},{"value":1.710138709677419,"timestamp":686275200000},{"value":0.08885333333333335,"timestamp":688953600000},{"value":0.612916129032258,"timestamp":691545600000},{"value":0.6289516129032259,"timestamp":694224000000},{"value":1.1173551724137927,"timestamp":696902400000},{"value":0.4222516129032259,"timestamp":699408000000},{"value":1.00248,"timestamp":702086400000},{"value":1.2269225806451611,"timestamp":704678400000},{"value":0.9452533333333333,"timestamp":707356800000},{"value":3.6642903225806447,"timestamp":709948800000},{"value":4.430374193548386,"timestamp":712627200000},{"value":1.35189,"timestamp":715305600000},{"value":0.3002612903225806,"timestamp":717897600000},{"value":0.17042000000000004,"timestamp":720576000000},{"value":0.15677096774193547,"timestamp":723168000000},{"value":0.2629516129032259,"timestamp":725846400000},{"value":0.3155000000000001,"timestamp":728524800000},{"value":0.22454193548387097,"timestamp":730944000000},{"value":3.905033333333334,"timestamp":733622400000},{"value":3.6554709677419353,"timestamp":736214400000},{"value":1.2678466666666666,"timestamp":738892800000},{"value":6.514112903225806,"timestamp":741484800000},{"value":4.00190322580645,"timestamp":744163200000},{"value":2.3712233333333335,"timestamp":746841600000},{"value":1.7191935483870968,"timestamp":749433600000},{"value":0.40519999999999995,"timestamp":752112000000},{"value":0.09775483870967742,"timestamp":754704000000},{"value":0.000012903225806451613,"timestamp":757382400000},{"value":0.056485714285714285,"timestamp":760060800000},{"value":0.6125935483870967,"timestamp":762480000000},{"value":1.9465366666666666,"timestamp":765158400000},{"value":1.3920322580645168,"timestamp":767750400000},{"value":1.81064,"timestamp":770428800000},{"value":5.636487096774194,"timestamp":773020800000},{"value":6.073612903225807,"timestamp":775699200000},{"value":3.7383600000000006,"timestamp":778377600000},{"value":0.1895032258064516,"timestamp":780969600000},{"value":2.1099333333333328,"timestamp":783648000000},{"value":0.0419483870967742,"timestamp":786240000000},{"value":0.0020096774193548387,"timestamp":788918400000},{"value":1.5378892857142863,"timestamp":791596800000},{"value":3.029506451612902,"timestamp":794016000000},{"value":2.414076666666666,"timestamp":796694400000},{"value":1.8389774193548387,"timestamp":799286400000},{"value":0.6246033333333333,"timestamp":801964800000},{"value":5.903183870967741,"timestamp":804556800000},{"value":4.708770967741936,"timestamp":807235200000},{"value":1.7363899999999999,"timestamp":809913600000},{"value":1.5013612903225806,"timestamp":812505600000},{"value":0.13255333333333333,"timestamp":815184000000},{"value":1.126558064516129,"timestamp":817776000000},{"value":0.7115129032258064,"timestamp":820454400000},{"value":0.05641724137931035,"timestamp":823132800000},{"value":3.6175064516129036,"timestamp":825638400000},{"value":2.823293333333333,"timestamp":828316800000},{"value":2.162712903225807,"timestamp":830908800000},{"value":1.4882466666666667,"timestamp":833587200000},{"value":5.011274193548387,"timestamp":836179200000},{"value":6.265332258064516,"timestamp":838857600000},{"value":1.59045,"timestamp":841536000000},{"value":0.7173290322580645,"timestamp":844128000000},{"value":0.8473799999999999,"timestamp":846806400000},{"value":0.03824516129032257,"timestamp":849398400000},{"value":0.31263548387096773,"timestamp":852076800000},{"value":0.008214285714285714,"timestamp":854755200000},{"value":1.9908935483870966,"timestamp":857174400000},{"value":1.4473566666666664,"timestamp":859852800000},{"value":0.6112838709677421,"timestamp":862444800000},{"value":2.711343333333333,"timestamp":865123200000},{"value":6.126045161290323,"timestamp":867715200000},{"value":5.360922580645162,"timestamp":870393600000},{"value":1.0090066666666668,"timestamp":873072000000},{"value":3.353306451612903,"timestamp":875664000000},{"value":0.68993,"timestamp":878342400000},{"value":0.03422903225806452,"timestamp":880934400000},{"value":0.6387774193548386,"timestamp":883612800000},{"value":0.9082928571428571,"timestamp":886291200000},{"value":0.7401290322580645,"timestamp":888710400000},{"value":0.9964633333333334,"timestamp":891388800000},{"value":1.0602129032258065,"timestamp":893980800000},{"value":0.9417599999999999,"timestamp":896659200000},{"value":7.602393548387095,"timestamp":899251200000},{"value":6.537809677419355,"timestamp":901929600000},{"value":2.8327433333333327,"timestamp":904608000000},{"value":1.9148677419354836,"timestamp":907200000000},{"value":0.08191999999999999,"timestamp":909878400000},{"value":0.0022806451612903227,"timestamp":912470400000},{"value":0.5421193548387098,"timestamp":915148800000},{"value":0.04328928571428571,"timestamp":917827200000},{"value":6.901003225806452,"timestamp":920246400000},{"value":0.3704833333333333,"timestamp":922924800000},{"value":0.3266903225806451,"timestamp":925516800000},{"value":0.9711933333333335,"timestamp":928195200000},{"value":7.747980645161291,"timestamp":930787200000},{"value":9.463974193548387,"timestamp":933465600000},{"value":1.9669033333333332,"timestamp":936144000000},{"value":2.1990838709677423,"timestamp":938736000000},{"value":0.10037,"timestamp":941414400000},{"value":0.059132258064516136,"timestamp":944006400000},{"value":0.0029580645161290326,"timestamp":946684800000},{"value":0.003248275862068966,"timestamp":949363200000},{"value":0.18205483870967742,"timestamp":951868800000},{"value":0.65317,"timestamp":954547200000},{"value":0.2844032258064516,"timestamp":957139200000},{"value":0.4054566666666667,"timestamp":959817600000},{"value":1.5713387096774194,"timestamp":962409600000},{"value":2.515999999999999,"timestamp":965088000000},{"value":1.1861233333333336,"timestamp":967766400000},{"value":0.4182838709677419,"timestamp":970358400000},{"value":0.1742766666666667,"timestamp":973036800000},{"value":0.0832935483870968,"timestamp":975628800000},{"value":0.029319354838709684,"timestamp":978307200000},{"value":0.07208214285714287,"timestamp":980985600000},{"value":1.7994548387096772,"timestamp":983404800000},{"value":0.45108,"timestamp":986083200000},{"value":0.9472258064516129,"timestamp":988675200000},{"value":1.1466300000000003,"timestamp":991353600000},{"value":1.599316129032258,"timestamp":993945600000},{"value":1.9795838709677418,"timestamp":996624000000},{"value":1.509206666666667,"timestamp":999302400000},{"value":0.4565322580645162,"timestamp":1001894400000},{"value":0.11963666666666666,"timestamp":1004572800000},{"value":0.09750645161290322,"timestamp":1007164800000},{"value":0.3901548387096774,"timestamp":1009843200000},{"value":0.015535714285714288,"timestamp":1012521600000},{"value":1.5172096774193544,"timestamp":1014940800000},{"value":0.8107133333333333,"timestamp":1017619200000},{"value":0.3211225806451613,"timestamp":1020211200000},{"value":1.09399,"timestamp":1022889600000},{"value":2.976754838709678,"timestamp":1025481600000},{"value":1.8797451612903227,"timestamp":1028160000000},{"value":1.1020333333333334,"timestamp":1030838400000},{"value":0.08540322580645161,"timestamp":1033430400000},{"value":0.02131333333333333,"timestamp":1036108800000},{"value":0.423958064516129,"timestamp":1038700800000},{"value":0.062099999999999995,"timestamp":1041379200000},{"value":0.2402142857142857,"timestamp":1044057600000},{"value":0.40361290322580645,"timestamp":1046476800000},{"value":1.2793133333333335,"timestamp":1049155200000},{"value":0.34342903225806454,"timestamp":1051747200000},{"value":0.5654900000000002,"timestamp":1054425600000},{"value":1.3574774193548387,"timestamp":1057017600000},{"value":2.878167741935484,"timestamp":1059696000000},{"value":1.3381,"timestamp":1062374400000},{"value":0.02172258064516129,"timestamp":1064966400000},{"value":0.056593333333333336,"timestamp":1067644800000},{"value":1.3819419354838707,"timestamp":1070236800000},{"value":0.15293870967741938,"timestamp":1072915200000},{"value":0.03384827586206897,"timestamp":1075593600000},{"value":0.5387548387096774,"timestamp":1078099200000},{"value":1.7106233333333336,"timestamp":1080777600000},{"value":0.15610000000000004,"timestamp":1083369600000},{"value":0.7356533333333333,"timestamp":1086048000000},{"value":1.5482193548387095,"timestamp":1088640000000},{"value":1.2879451612903223,"timestamp":1091318400000},{"value":0.8960166666666668,"timestamp":1093996800000},{"value":0.3212,"timestamp":1096588800000},{"value":0.25264000000000003,"timestamp":1099267200000},{"value":1.2692516129032259,"timestamp":1101859200000},{"value":0.5297677419354838,"timestamp":1104537600000},{"value":0.020303571428571428,"timestamp":1107216000000},{"value":0.6819483870967742,"timestamp":1109635200000},{"value":5.666779999999999,"timestamp":1112313600000},{"value":1.5935193548387092,"timestamp":1114905600000},{"value":0.13908,"timestamp":1117584000000},{"value":1.4270096774193548,"timestamp":1120176000000},{"value":1.4261580645161291,"timestamp":1122854400000},{"value":0.8197633333333335,"timestamp":1125532800000},{"value":0.11170322580645162,"timestamp":1128124800000},{"value":0.1629766666666667,"timestamp":1130803200000},{"value":0.00003548387096774194,"timestamp":1133395200000},{"value":0.2825870967741936,"timestamp":1136073600000},{"value":0.5009964285714285,"timestamp":1138752000000},{"value":2.157316129032258,"timestamp":1141171200000},{"value":2.88453,"timestamp":1143849600000},{"value":0.8479161290322579,"timestamp":1146441600000},{"value":0.8250766666666666,"timestamp":1149120000000},{"value":5.779832258064516,"timestamp":1151712000000},{"value":5.873341935483871,"timestamp":1154390400000},{"value":1.8016600000000005,"timestamp":1157068800000},{"value":0.7985806451612903,"timestamp":1159660800000},{"value":0.06096999999999999,"timestamp":1162339200000},{"value":0.6383129032258064,"timestamp":1164931200000},{"value":0.29653225806451616,"timestamp":1167609600000},{"value":0.7592964285714288,"timestamp":1170288000000},{"value":0.4818387096774193,"timestamp":1172707200000},{"value":2.13564,"timestamp":1175385600000},{"value":0.914458064516129,"timestamp":1177977600000},{"value":0.57174,"timestamp":1180656000000},{"value":4.016754838709677,"timestamp":1183248000000},{"value":2.6767129032258064,"timestamp":1185926400000},{"value":1.5335700000000003,"timestamp":1188604800000},{"value":0.4098645161290323,"timestamp":1191196800000},{"value":0.08767333333333331,"timestamp":1193875200000},{"value":0.0013032258064516128,"timestamp":1196467200000},{"value":0.2770870967741936,"timestamp":1199145600000},{"value":0.05724827586206895,"timestamp":1201824000000},{"value":0.004441935483870968,"timestamp":1204329600000},{"value":1.3048499999999996,"timestamp":1207008000000},{"value":0.5841129032258066,"timestamp":1209600000000},{"value":0.3510566666666667,"timestamp":1212278400000},{"value":3.051477419354838,"timestamp":1214870400000},{"value":3.621367741935484,"timestamp":1217548800000},{"value":1.4803233333333337,"timestamp":1220227200000},{"value":0.25687096774193546,"timestamp":1222819200000},{"value":0.91209,"timestamp":1225497600000},{"value":0.016370967741935485,"timestamp":1228089600000},{"value":0.34909677419354834,"timestamp":1230768000000},{"value":0.10439999999999998,"timestamp":1233446400000},{"value":0.534858064516129,"timestamp":1235865600000},{"value":0.8979766666666665,"timestamp":1238544000000},{"value":0.10481612903225812,"timestamp":1241136000000},{"value":0.7390233333333334,"timestamp":1243814400000},{"value":4.489709677419355,"timestamp":1246406400000},{"value":4.1637516129032255,"timestamp":1249084800000},{"value":0.8885666666666666,"timestamp":1251763200000},{"value":1.3989096774193543,"timestamp":1254355200000},{"value":0.04606,"timestamp":1257033600000},{"value":0.3052,"timestamp":1259625600000},{"value":0.004861290322580645,"timestamp":1262304000000},{"value":1.6522500000000002,"timestamp":1264982400000},{"value":1.2724806451612904,"timestamp":1267401600000},{"value":1.7387466666666662,"timestamp":1270080000000},{"value":1.3899032258064519,"timestamp":1272672000000},{"value":0.975606666666667,"timestamp":1275350400000},{"value":5.156887096774193,"timestamp":1277942400000},{"value":6.972422580645162,"timestamp":1280620800000},{"value":2.128933333333333,"timestamp":1283299200000},{"value":0.1325741935483871,"timestamp":1285891200000},{"value":0.23680666666666667,"timestamp":1288569600000},{"value":0.03993225806451613,"timestamp":1291161600000},{"value":0.06617741935483872,"timestamp":1293840000000},{"value":0.08242500000000001,"timestamp":1296518400000},{"value":1.0754354838709683,"timestamp":1298937600000},{"value":0.6573533333333333,"timestamp":1301616000000},{"value":2.4816129032258067,"timestamp":1304208000000},{"value":0.22561333333333333,"timestamp":1306886400000},{"value":1.453916129032258,"timestamp":1309478400000},{"value":1.706332258064516,"timestamp":1312156800000},{"value":0.67557,"timestamp":1314835200000},{"value":0.11155483870967743,"timestamp":1317427200000},{"value":0.22255333333333335,"timestamp":1320105600000},{"value":0.007632258064516127,"timestamp":1322697600000},{"value":0.01034193548387097,"timestamp":1325376000000},{"value":0.00006551724137931034,"timestamp":1328054400000},{"value":0.1461193548387097,"timestamp":1330560000000},{"value":1.2186200000000005,"timestamp":1333238400000},{"value":0.2599677419354839,"timestamp":1335830400000},{"value":0.3277933333333332,"timestamp":1338508800000},{"value":3.230758064516129,"timestamp":1341100800000},{"value":2.9337064516129026,"timestamp":1343779200000},{"value":1.0406100000000003,"timestamp":1346457600000},{"value":0.0398,"timestamp":1349049600000},{"value":0.028990000000000002,"timestamp":1351728000000},{"value":0.07618709677419355,"timestamp":1354320000000},{"value":0.3456903225806452,"timestamp":1356998400000},{"value":0.017175,"timestamp":1359676800000},{"value":1.094945161290323,"timestamp":1362096000000},{"value":1.2708966666666668,"timestamp":1364774400000},{"value":0.6110838709677421,"timestamp":1367366400000},{"value":0.8498133333333334,"timestamp":1370044800000},{"value":5.49858064516129,"timestamp":1372636800000},{"value":5.575745161290322,"timestamp":1375315200000},{"value":1.3711433333333332,"timestamp":1377993600000},{"value":2.3997483870967744,"timestamp":1380585600000},{"value":0.3174566666666667,"timestamp":1383264000000},{"value":0.06693548387096773,"timestamp":1385856000000},{"value":0.028819354838709677,"timestamp":1388534400000},{"value":0.34499285714285716,"timestamp":1391212800000},{"value":0.900948387096774,"timestamp":1393632000000},{"value":1.9720633333333335,"timestamp":1396310400000},{"value":1.3286774193548385,"timestamp":1398902400000},{"value":0.8263266666666667,"timestamp":1401580800000},{"value":5.062932258064516,"timestamp":1404172800000},{"value":3.7404645161290317,"timestamp":1406851200000},{"value":2.73512,"timestamp":1409529600000},{"value":1.170358064516129,"timestamp":1412121600000},{"value":0.14135666666666666,"timestamp":1414800000000},{"value":0.08283548387096774,"timestamp":1417392000000},{"value":0.2841967741935483,"timestamp":1420070400000},{"value":0.030460714285714285,"timestamp":1422748800000},{"value":0.38081612903225803,"timestamp":1425168000000},{"value":0.02333666666666667,"timestamp":1427846400000},{"value":0.7997806451612904,"timestamp":1430438400000},{"value":1.5224566666666666,"timestamp":1433116800000},{"value":0.990932258064516,"timestamp":1435708800000},{"value":5.702148387096773,"timestamp":1438387200000},{"value":0.9648533333333336,"timestamp":1441065600000},{"value":0.1965032258064516,"timestamp":1443657600000},{"value":0.5751666666666665,"timestamp":1446336000000},{"value":0.8186806451612904,"timestamp":1448928000000},{"value":0.2591709677419355,"timestamp":1451606400000},{"value":0.318703448275862,"timestamp":1454284800000},{"value":0.8187290322580645,"timestamp":1456790400000},{"value":4.820703333333333,"timestamp":1459468800000},{"value":2.272238709677419,"timestamp":1462060800000},{"value":0.4943966666666667,"timestamp":1464739200000},{"value":5.14783870967742,"timestamp":1467331200000},{"value":4.638109677419355,"timestamp":1470009600000},{"value":1.6093666666666664,"timestamp":1472688000000},{"value":0.2956516129032259,"timestamp":1475280000000},{"value":0.16122333333333336,"timestamp":1477958400000},{"value":0.043764516129032247,"timestamp":1480550400000},{"value":0.0015129032258064516,"timestamp":1483228800000},{"value":1.7857428571428573,"timestamp":1485907200000},{"value":1.7253290322580646,"timestamp":1488326400000},{"value":1.3224433333333332,"timestamp":1491004800000},{"value":2.43228064516129,"timestamp":1493596800000},{"value":0.32378,"timestamp":1496275200000},{"value":2.0054193548387094,"timestamp":1498867200000},{"value":4.14855806451613,"timestamp":1501545600000},{"value":2.438363333333333,"timestamp":1504224000000},{"value":0.719467741935484,"timestamp":1506816000000},{"value":0.13373333333333332,"timestamp":1509494400000},{"value":0.00494516129032258,"timestamp":1512086400000},{"value":0.18523870967741934,"timestamp":1514764800000},{"value":0.6241428571428572,"timestamp":1517443200000},{"value":0.3953419354838708,"timestamp":1519862400000},{"value":2.6591999999999993,"timestamp":1522540800000},{"value":0.17660322580645163,"timestamp":1525132800000},{"value":0.47159666666666666,"timestamp":1527811200000},{"value":2.1962451612903227,"timestamp":1530403200000},{"value":3.4617064516129035,"timestamp":1533081600000},{"value":3.3733399999999993,"timestamp":1535760000000},{"value":0.9658967741935485,"timestamp":1538352000000},{"value":0.7850466666666666,"timestamp":1541030400000},{"value":0.029367741935483874,"timestamp":1543622400000},{"value":0.00004516129032258064,"timestamp":1546300800000},{"value":1.3573500000000003,"timestamp":1548979200000},{"value":0.9780967741935485,"timestamp":1551398400000},{"value":2.444236666666667,"timestamp":1554076800000},{"value":0.31139677419354833,"timestamp":1556668800000},{"value":1.1136799999999998,"timestamp":1559347200000},{"value":0.5978451612903224,"timestamp":1561939200000},{"value":2.9266354838709683,"timestamp":1564617600000},{"value":5.163923333333333,"timestamp":1567296000000},{"value":1.8762806451612908,"timestamp":1569888000000},{"value":0.98977,"timestamp":1572566400000},{"value":0.8167354838709676,"timestamp":1575158400000},{"value":0.3114774193548387,"timestamp":1577836800000},{"value":0.3238310344827586,"timestamp":1580515200000},{"value":1.214196774193548,"timestamp":1583020800000},{"value":3.587106666666666,"timestamp":1585699200000},{"value":2.2378451612903234,"timestamp":1588291200000},{"value":0.9830266666666667,"timestamp":1590969600000},{"value":3.9650741935483875,"timestamp":1593561600000},{"value":4.346283870967741,"timestamp":1596240000000},{"value":2.3164600000000006,"timestamp":1598918400000}],"numLevels":31},"wm/concept/agriculture/crop_produce":{"name":"Cereal yield (kg per hectare)","minValue":974.4,"maxValue":2556.1,"func":"last","values":[{"value":1313,"timestamp":725846400000},{"value":974.4,"timestamp":757382400000},{"value":1033.5,"timestamp":788918400000},{"value":1213.6,"timestamp":820454400000},{"value":1263.9,"timestamp":852076800000},{"value":1140.9,"timestamp":883612800000},{"value":1124.6,"timestamp":915148800000},{"value":1116.3,"timestamp":946684800000},{"value":1198,"timestamp":978307200000},{"value":1353.7,"timestamp":1009843200000},{"value":1123.3,"timestamp":1041379200000},{"value":1162.6,"timestamp":1072915200000},{"value":1361.4,"timestamp":1104537600000},{"value":1563.3,"timestamp":1136073600000},{"value":1439,"timestamp":1167609600000},{"value":1446.3,"timestamp":1199145600000},{"value":1682.5,"timestamp":1230768000000},{"value":1832.8,"timestamp":1262304000000},{"value":1961.6,"timestamp":1293840000000},{"value":2046.8,"timestamp":1325376000000},{"value":2193.1,"timestamp":1356998400000},{"value":2325.4,"timestamp":1388534400000},{"value":2556.1,"timestamp":1420070400000},{"value":2484,"timestamp":1451606400000},{"value":2538.2,"timestamp":1483228800000}],"numLevels":31}}} \ No newline at end of file diff --git a/tests/data/delphi/create_model_rain--temperature.json b/tests/data/delphi/create_model_rain--temperature.json new file mode 100644 index 000000000..6e5cb1ace --- /dev/null +++ b/tests/data/delphi/create_model_rain--temperature.json @@ -0,0 +1,2902 @@ +{ + "id": "36582cad-1a36-4ce6-a0a8-2682ea0246b5", + "statements": [ + { + "id": "stub_statement", + "belief": 1, + "evidence": [ + { + "document_context": {}, + "evidence_context": { + "obj_polarity": -1, + "obj_adjectives": [], + "subj_polarity": 1, + "subj_adjectives": [] + } + } + ], + "subj": { + "factor": "user", + "concept": "wm/concept/environment/meteorology/precipitation", + "concept_score": 1, + "adjectives": [], + "polarity": 1 + }, + "obj": { + "factor": "user", + "concept": "wm/concept/environment/meteorology/temperature", + "concept_score": 1, + "adjectives": [], + "polarity": -1 + } + } + ], + "conceptIndicators": { + "wm/concept/environment/meteorology/temperature": { + "name": "Mean Temperature", + "minValue": 22.397182758620687, + "maxValue": 33.38314666666667, + "func": "last", + "values": [ + { + "value": 24.86295806451613, + "timestamp": 662688000000 + }, + { + "value": 25.132807142857143, + "timestamp": 665366400000 + }, + { + "value": 26.54966129032258, + "timestamp": 667785600000 + }, + { + "value": 29.79424333333333, + "timestamp": 670464000000 + }, + { + "value": 30.952345161290317, + "timestamp": 673056000000 + }, + { + "value": 32.113926666666664, + "timestamp": 675734400000 + }, + { + "value": 31.313387096774196, + "timestamp": 678326400000 + }, + { + "value": 30.894693548387096, + "timestamp": 681004800000 + }, + { + "value": 30.933393333333342, + "timestamp": 683683200000 + }, + { + "value": 28.554380645161284, + "timestamp": 686275200000 + }, + { + "value": 25.50030666666667, + "timestamp": 688953600000 + }, + { + "value": 24.461483870967744, + "timestamp": 691545600000 + }, + { + "value": 23.273829032258057, + "timestamp": 694224000000 + }, + { + "value": 22.397182758620687, + "timestamp": 696902400000 + }, + { + "value": 26.386206451612907, + "timestamp": 699408000000 + }, + { + "value": 28.46132, + "timestamp": 702086400000 + }, + { + "value": 31.044451612903224, + "timestamp": 704678400000 + }, + { + "value": 31.93410999999999, + "timestamp": 707356800000 + }, + { + "value": 31.08583548387097, + "timestamp": 709948800000 + }, + { + "value": 29.05188709677419, + "timestamp": 712627200000 + }, + { + "value": 29.226513333333333, + "timestamp": 715305600000 + }, + { + "value": 27.914638709677416, + "timestamp": 717897600000 + }, + { + "value": 25.622833333333332, + "timestamp": 720576000000 + }, + { + "value": 24.277583870967746, + "timestamp": 723168000000 + }, + { + "value": 22.73682258064516, + "timestamp": 725846400000 + }, + { + "value": 22.718735714285714, + "timestamp": 728524800000 + }, + { + "value": 26.9044064516129, + "timestamp": 730944000000 + }, + { + "value": 27.090993333333337, + "timestamp": 733622400000 + }, + { + "value": 29.076129032258063, + "timestamp": 736214400000 + }, + { + "value": 31.630873333333337, + "timestamp": 738892800000 + }, + { + "value": 31.365125806451616, + "timestamp": 741484800000 + }, + { + "value": 31.182125806451612, + "timestamp": 744163200000 + }, + { + "value": 30.766403333333336, + "timestamp": 746841600000 + }, + { + "value": 28.825648387096766, + "timestamp": 749433600000 + }, + { + "value": 26.514196666666667, + "timestamp": 752112000000 + }, + { + "value": 24.70176129032258, + "timestamp": 754704000000 + }, + { + "value": 24.260645161290316, + "timestamp": 757382400000 + }, + { + "value": 25.445599999999995, + "timestamp": 760060800000 + }, + { + "value": 26.727267741935485, + "timestamp": 762480000000 + }, + { + "value": 30.161196666666665, + "timestamp": 765158400000 + }, + { + "value": 31.557422580645166, + "timestamp": 767750400000 + }, + { + "value": 32.18229666666667, + "timestamp": 770428800000 + }, + { + "value": 30.27816774193548, + "timestamp": 773020800000 + }, + { + "value": 29.775316129032255, + "timestamp": 775699200000 + }, + { + "value": 29.766720000000003, + "timestamp": 778377600000 + }, + { + "value": 28.68954193548387, + "timestamp": 780969600000 + }, + { + "value": 26.45734333333333, + "timestamp": 783648000000 + }, + { + "value": 24.031783870967747, + "timestamp": 786240000000 + }, + { + "value": 24.276893548387097, + "timestamp": 788918400000 + }, + { + "value": 25.498203571428572, + "timestamp": 791596800000 + }, + { + "value": 26.191754838709677, + "timestamp": 794016000000 + }, + { + "value": 28.425693333333324, + "timestamp": 796694400000 + }, + { + "value": 31.274564516129036, + "timestamp": 799286400000 + }, + { + "value": 32.53478000000001, + "timestamp": 801964800000 + }, + { + "value": 30.347999999999995, + "timestamp": 804556800000 + }, + { + "value": 29.632751612903217, + "timestamp": 807235200000 + }, + { + "value": 30.668000000000003, + "timestamp": 809913600000 + }, + { + "value": 29.145170967741933, + "timestamp": 812505600000 + }, + { + "value": 26.296929999999996, + "timestamp": 815184000000 + }, + { + "value": 25.118561290322578, + "timestamp": 817776000000 + }, + { + "value": 24.68018387096775, + "timestamp": 820454400000 + }, + { + "value": 26.172893103448274, + "timestamp": 823132800000 + }, + { + "value": 27.176609677419354, + "timestamp": 825638400000 + }, + { + "value": 28.990573333333337, + "timestamp": 828316800000 + }, + { + "value": 29.394851612903228, + "timestamp": 830908800000 + }, + { + "value": 31.00897666666667, + "timestamp": 833587200000 + }, + { + "value": 31.11190967741936, + "timestamp": 836179200000 + }, + { + "value": 30.145816129032255, + "timestamp": 838857600000 + }, + { + "value": 29.834786666666673, + "timestamp": 841536000000 + }, + { + "value": 28.72504516129033, + "timestamp": 844128000000 + }, + { + "value": 25.644556666666666, + "timestamp": 846806400000 + }, + { + "value": 24.22446774193548, + "timestamp": 849398400000 + }, + { + "value": 23.397748387096772, + "timestamp": 852076800000 + }, + { + "value": 24.493521428571434, + "timestamp": 854755200000 + }, + { + "value": 26.595648387096777, + "timestamp": 857174400000 + }, + { + "value": 28.207233333333328, + "timestamp": 859852800000 + }, + { + "value": 31.10853870967741, + "timestamp": 862444800000 + }, + { + "value": 32.19592333333333, + "timestamp": 865123200000 + }, + { + "value": 31.450164516129032, + "timestamp": 867715200000 + }, + { + "value": 31.039829032258073, + "timestamp": 870393600000 + }, + { + "value": 31.708863333333333, + "timestamp": 873072000000 + }, + { + "value": 27.524154838709673, + "timestamp": 875664000000 + }, + { + "value": 26.216326666666667, + "timestamp": 878342400000 + }, + { + "value": 25.164474193548383, + "timestamp": 880934400000 + }, + { + "value": 24.462161290322577, + "timestamp": 883612800000 + }, + { + "value": 25.575925, + "timestamp": 886291200000 + }, + { + "value": 27.475738709677426, + "timestamp": 888710400000 + }, + { + "value": 30.48144, + "timestamp": 891388800000 + }, + { + "value": 31.887125806451614, + "timestamp": 893980800000 + }, + { + "value": 32.94343, + "timestamp": 896659200000 + }, + { + "value": 31.324209677419358, + "timestamp": 899251200000 + }, + { + "value": 29.287080645161293, + "timestamp": 901929600000 + }, + { + "value": 29.521180000000008, + "timestamp": 904608000000 + }, + { + "value": 28.839193548387094, + "timestamp": 907200000000 + }, + { + "value": 26.523276666666668, + "timestamp": 909878400000 + }, + { + "value": 24.668364516129035, + "timestamp": 912470400000 + }, + { + "value": 24.45384516129032, + "timestamp": 915148800000 + }, + { + "value": 26.673385714285708, + "timestamp": 917827200000 + }, + { + "value": 26.165087096774194, + "timestamp": 920246400000 + }, + { + "value": 30.094539999999995, + "timestamp": 922924800000 + }, + { + "value": 32.299138709677415, + "timestamp": 925516800000 + }, + { + "value": 32.17985999999999, + "timestamp": 928195200000 + }, + { + "value": 30.451777419354833, + "timestamp": 930787200000 + }, + { + "value": 30.248664516129026, + "timestamp": 933465600000 + }, + { + "value": 30.465026666666677, + "timestamp": 936144000000 + }, + { + "value": 27.244919354838718, + "timestamp": 938736000000 + }, + { + "value": 26.154186666666664, + "timestamp": 941414400000 + }, + { + "value": 24.4702064516129, + "timestamp": 944006400000 + }, + { + "value": 24.130774193548394, + "timestamp": 946684800000 + }, + { + "value": 25.697155172413794, + "timestamp": 949363200000 + }, + { + "value": 27.223687096774192, + "timestamp": 951868800000 + }, + { + "value": 29.863233333333334, + "timestamp": 954547200000 + }, + { + "value": 30.837245161290326, + "timestamp": 957139200000 + }, + { + "value": 31.835590000000003, + "timestamp": 959817600000 + }, + { + "value": 31.25467741935484, + "timestamp": 962409600000 + }, + { + "value": 29.099851612903223, + "timestamp": 965088000000 + }, + { + "value": 30.203536666666672, + "timestamp": 967766400000 + }, + { + "value": 27.740599999999997, + "timestamp": 970358400000 + }, + { + "value": 25.475306666666665, + "timestamp": 973036800000 + }, + { + "value": 23.694912903225806, + "timestamp": 975628800000 + }, + { + "value": 22.95638387096774, + "timestamp": 978307200000 + }, + { + "value": 24.76266071428571, + "timestamp": 980985600000 + }, + { + "value": 26.652351612903228, + "timestamp": 983404800000 + }, + { + "value": 29.954119999999993, + "timestamp": 986083200000 + }, + { + "value": 31.28690000000001, + "timestamp": 988675200000 + }, + { + "value": 32.021693333333324, + "timestamp": 991353600000 + }, + { + "value": 30.61878064516129, + "timestamp": 993945600000 + }, + { + "value": 28.994706451612902, + "timestamp": 996624000000 + }, + { + "value": 30.00396, + "timestamp": 999302400000 + }, + { + "value": 29.507287096774196, + "timestamp": 1001894400000 + }, + { + "value": 26.209039999999998, + "timestamp": 1004572800000 + }, + { + "value": 24.85181290322581, + "timestamp": 1007164800000 + }, + { + "value": 23.5442129032258, + "timestamp": 1009843200000 + }, + { + "value": 25.41718928571428, + "timestamp": 1012521600000 + }, + { + "value": 27.52885161290323, + "timestamp": 1014940800000 + }, + { + "value": 28.54994333333334, + "timestamp": 1017619200000 + }, + { + "value": 31.475503225806445, + "timestamp": 1020211200000 + }, + { + "value": 32.14381666666667, + "timestamp": 1022889600000 + }, + { + "value": 32.494558064516134, + "timestamp": 1025481600000 + }, + { + "value": 31.330654838709673, + "timestamp": 1028160000000 + }, + { + "value": 30.03016333333333, + "timestamp": 1030838400000 + }, + { + "value": 29.42600322580645, + "timestamp": 1033430400000 + }, + { + "value": 26.98337, + "timestamp": 1036108800000 + }, + { + "value": 24.6396064516129, + "timestamp": 1038700800000 + }, + { + "value": 23.603461290322574, + "timestamp": 1041379200000 + }, + { + "value": 26.387796428571427, + "timestamp": 1044057600000 + }, + { + "value": 27.436367741935477, + "timestamp": 1046476800000 + }, + { + "value": 28.45589333333333, + "timestamp": 1049155200000 + }, + { + "value": 32.049396774193546, + "timestamp": 1051747200000 + }, + { + "value": 32.005669999999995, + "timestamp": 1054425600000 + }, + { + "value": 31.262145161290324, + "timestamp": 1057017600000 + }, + { + "value": 28.87483548387097, + "timestamp": 1059696000000 + }, + { + "value": 30.23267666666667, + "timestamp": 1062374400000 + }, + { + "value": 28.85755483870967, + "timestamp": 1064966400000 + }, + { + "value": 26.547206666666668, + "timestamp": 1067644800000 + }, + { + "value": 23.94398387096774, + "timestamp": 1070236800000 + }, + { + "value": 24.50213870967742, + "timestamp": 1072915200000 + }, + { + "value": 24.271189655172414, + "timestamp": 1075593600000 + }, + { + "value": 26.943590322580643, + "timestamp": 1078099200000 + }, + { + "value": 27.94561666666667, + "timestamp": 1080777600000 + }, + { + "value": 31.54308064516129, + "timestamp": 1083369600000 + }, + { + "value": 31.89315333333333, + "timestamp": 1086048000000 + }, + { + "value": 31.874574193548387, + "timestamp": 1088640000000 + }, + { + "value": 31.047503225806448, + "timestamp": 1091318400000 + }, + { + "value": 31.082146666666667, + "timestamp": 1093996800000 + }, + { + "value": 28.864167741935482, + "timestamp": 1096588800000 + }, + { + "value": 26.740779999999997, + "timestamp": 1099267200000 + }, + { + "value": 24.752941935483864, + "timestamp": 1101859200000 + }, + { + "value": 23.888770967741944, + "timestamp": 1104537600000 + }, + { + "value": 26.06273928571428, + "timestamp": 1107216000000 + }, + { + "value": 27.63122258064517, + "timestamp": 1109635200000 + }, + { + "value": 29.084976666666666, + "timestamp": 1112313600000 + }, + { + "value": 30.108061290322578, + "timestamp": 1114905600000 + }, + { + "value": 32.30074333333332, + "timestamp": 1117584000000 + }, + { + "value": 30.920690322580647, + "timestamp": 1120176000000 + }, + { + "value": 31.506180645161287, + "timestamp": 1122854400000 + }, + { + "value": 30.951656666666672, + "timestamp": 1125532800000 + }, + { + "value": 29.325832258064512, + "timestamp": 1128124800000 + }, + { + "value": 26.60961, + "timestamp": 1130803200000 + }, + { + "value": 24.469325806451614, + "timestamp": 1133395200000 + }, + { + "value": 24.27066129032258, + "timestamp": 1136073600000 + }, + { + "value": 26.245375, + "timestamp": 1138752000000 + }, + { + "value": 27.301745161290324, + "timestamp": 1141171200000 + }, + { + "value": 28.400793333333333, + "timestamp": 1143849600000 + }, + { + "value": 31.40136774193548, + "timestamp": 1146441600000 + }, + { + "value": 32.363809999999994, + "timestamp": 1149120000000 + }, + { + "value": 31.093767741935483, + "timestamp": 1151712000000 + }, + { + "value": 30.1714, + "timestamp": 1154390400000 + }, + { + "value": 30.031893333333333, + "timestamp": 1157068800000 + }, + { + "value": 28.980435483870973, + "timestamp": 1159660800000 + }, + { + "value": 26.610856666666663, + "timestamp": 1162339200000 + }, + { + "value": 24.755974193548386, + "timestamp": 1164931200000 + }, + { + "value": 23.58546129032258, + "timestamp": 1167609600000 + }, + { + "value": 26.232692857142855, + "timestamp": 1170288000000 + }, + { + "value": 27.694112903225808, + "timestamp": 1172707200000 + }, + { + "value": 29.275829999999996, + "timestamp": 1175385600000 + }, + { + "value": 32.08432903225807, + "timestamp": 1177977600000 + }, + { + "value": 31.97184, + "timestamp": 1180656000000 + }, + { + "value": 30.093583870967745, + "timestamp": 1183248000000 + }, + { + "value": 30.306825806451606, + "timestamp": 1185926400000 + }, + { + "value": 30.55679666666667, + "timestamp": 1188604800000 + }, + { + "value": 28.43743870967742, + "timestamp": 1191196800000 + }, + { + "value": 26.18127666666667, + "timestamp": 1193875200000 + }, + { + "value": 24.15435806451613, + "timestamp": 1196467200000 + }, + { + "value": 24.368858064516125, + "timestamp": 1199145600000 + }, + { + "value": 24.34289655172414, + "timestamp": 1201824000000 + }, + { + "value": 27.184290322580647, + "timestamp": 1204329600000 + }, + { + "value": 29.57276333333334, + "timestamp": 1207008000000 + }, + { + "value": 31.073545161290316, + "timestamp": 1209600000000 + }, + { + "value": 31.723076666666664, + "timestamp": 1212278400000 + }, + { + "value": 31.772596774193545, + "timestamp": 1214870400000 + }, + { + "value": 31.32441612903226, + "timestamp": 1217548800000 + }, + { + "value": 30.672520000000006, + "timestamp": 1220227200000 + }, + { + "value": 28.38856129032258, + "timestamp": 1222819200000 + }, + { + "value": 25.185366666666663, + "timestamp": 1225497600000 + }, + { + "value": 23.835977419354837, + "timestamp": 1228089600000 + }, + { + "value": 24.08534193548387, + "timestamp": 1230768000000 + }, + { + "value": 26.399807142857146, + "timestamp": 1233446400000 + }, + { + "value": 27.704893548387094, + "timestamp": 1235865600000 + }, + { + "value": 29.898023333333324, + "timestamp": 1238544000000 + }, + { + "value": 31.28515806451613, + "timestamp": 1241136000000 + }, + { + "value": 32.71743333333333, + "timestamp": 1243814400000 + }, + { + "value": 31.94021290322581, + "timestamp": 1246406400000 + }, + { + "value": 31.10592903225806, + "timestamp": 1249084800000 + }, + { + "value": 31.314953333333328, + "timestamp": 1251763200000 + }, + { + "value": 28.483, + "timestamp": 1254355200000 + }, + { + "value": 26.617309999999996, + "timestamp": 1257033600000 + }, + { + "value": 25.873964516129032, + "timestamp": 1259625600000 + }, + { + "value": 24.583554838709674, + "timestamp": 1262304000000 + }, + { + "value": 25.473925000000005, + "timestamp": 1264982400000 + }, + { + "value": 27.045038709677417, + "timestamp": 1267401600000 + }, + { + "value": 29.638510000000007, + "timestamp": 1270080000000 + }, + { + "value": 31.31575161290323, + "timestamp": 1272672000000 + }, + { + "value": 32.663086666666665, + "timestamp": 1275350400000 + }, + { + "value": 30.278009677419355, + "timestamp": 1277942400000 + }, + { + "value": 30.22356774193548, + "timestamp": 1280620800000 + }, + { + "value": 30.03330333333333, + "timestamp": 1283299200000 + }, + { + "value": 29.467783870967736, + "timestamp": 1285891200000 + }, + { + "value": 26.379853333333337, + "timestamp": 1288569600000 + }, + { + "value": 24.012690322580646, + "timestamp": 1291161600000 + }, + { + "value": 24.065032258064516, + "timestamp": 1293840000000 + }, + { + "value": 25.474528571428575, + "timestamp": 1296518400000 + }, + { + "value": 26.544219354838706, + "timestamp": 1298937600000 + }, + { + "value": 29.92544666666667, + "timestamp": 1301616000000 + }, + { + "value": 30.094322580645166, + "timestamp": 1304208000000 + }, + { + "value": 31.829473333333333, + "timestamp": 1306886400000 + }, + { + "value": 31.51112903225806, + "timestamp": 1309478400000 + }, + { + "value": 29.2929870967742, + "timestamp": 1312156800000 + }, + { + "value": 30.509526666666662, + "timestamp": 1314835200000 + }, + { + "value": 28.42188387096775, + "timestamp": 1317427200000 + }, + { + "value": 25.935076666666678, + "timestamp": 1320105600000 + }, + { + "value": 23.82311935483871, + "timestamp": 1322697600000 + }, + { + "value": 24.24770322580645, + "timestamp": 1325376000000 + }, + { + "value": 25.219651724137936, + "timestamp": 1328054400000 + }, + { + "value": 26.836238709677417, + "timestamp": 1330560000000 + }, + { + "value": 29.197453333333335, + "timestamp": 1333238400000 + }, + { + "value": 31.42051935483871, + "timestamp": 1335830400000 + }, + { + "value": 32.43823666666667, + "timestamp": 1338508800000 + }, + { + "value": 31.198948387096774, + "timestamp": 1341100800000 + }, + { + "value": 31.01210322580646, + "timestamp": 1343779200000 + }, + { + "value": 31.191509999999994, + "timestamp": 1346457600000 + }, + { + "value": 28.788048387096772, + "timestamp": 1349049600000 + }, + { + "value": 26.862376666666663, + "timestamp": 1351728000000 + }, + { + "value": 25.502480645161295, + "timestamp": 1354320000000 + }, + { + "value": 24.83181612903226, + "timestamp": 1356998400000 + }, + { + "value": 25.682299999999998, + "timestamp": 1359676800000 + }, + { + "value": 27.398125806451617, + "timestamp": 1362096000000 + }, + { + "value": 29.042863333333333, + "timestamp": 1364774400000 + }, + { + "value": 31.74748064516129, + "timestamp": 1367366400000 + }, + { + "value": 32.39842, + "timestamp": 1370044800000 + }, + { + "value": 31.147967741935478, + "timestamp": 1372636800000 + }, + { + "value": 29.033816129032257, + "timestamp": 1375315200000 + }, + { + "value": 30.915473333333342, + "timestamp": 1377993600000 + }, + { + "value": 28.729635483870968, + "timestamp": 1380585600000 + }, + { + "value": 26.70407, + "timestamp": 1383264000000 + }, + { + "value": 23.790454838709678, + "timestamp": 1385856000000 + }, + { + "value": 24.476751612903225, + "timestamp": 1388534400000 + }, + { + "value": 25.378446428571433, + "timestamp": 1391212800000 + }, + { + "value": 27.505851612903225, + "timestamp": 1393632000000 + }, + { + "value": 30.167793333333332, + "timestamp": 1396310400000 + }, + { + "value": 30.55179032258064, + "timestamp": 1398902400000 + }, + { + "value": 32.358866666666664, + "timestamp": 1401580800000 + }, + { + "value": 31.721548387096778, + "timestamp": 1404172800000 + }, + { + "value": 30.234212903225814, + "timestamp": 1406851200000 + }, + { + "value": 30.147063333333335, + "timestamp": 1409529600000 + }, + { + "value": 27.783480645161287, + "timestamp": 1412121600000 + }, + { + "value": 26.771466666666676, + "timestamp": 1414800000000 + }, + { + "value": 24.446429032258067, + "timestamp": 1417392000000 + }, + { + "value": 23.626135483870968, + "timestamp": 1420070400000 + }, + { + "value": 25.656246428571432, + "timestamp": 1422748800000 + }, + { + "value": 28.216003225806453, + "timestamp": 1425168000000 + }, + { + "value": 29.890159999999998, + "timestamp": 1427846400000 + }, + { + "value": 31.102554838709683, + "timestamp": 1430438400000 + }, + { + "value": 32.18640333333333, + "timestamp": 1433116800000 + }, + { + "value": 33.0358677419355, + "timestamp": 1435708800000 + }, + { + "value": 32.23883548387097, + "timestamp": 1438387200000 + }, + { + "value": 31.725473333333337, + "timestamp": 1441065600000 + }, + { + "value": 30.40855483870968, + "timestamp": 1443657600000 + }, + { + "value": 27.57449666666667, + "timestamp": 1446336000000 + }, + { + "value": 25.3426129032258, + "timestamp": 1448928000000 + }, + { + "value": 25.090077419354834, + "timestamp": 1451606400000 + }, + { + "value": 26.182755172413792, + "timestamp": 1454284800000 + }, + { + "value": 30.299516129032256, + "timestamp": 1456790400000 + }, + { + "value": 28.54819666666667, + "timestamp": 1459468800000 + }, + { + "value": 31.264190322580635, + "timestamp": 1462060800000 + }, + { + "value": 33.116080000000004, + "timestamp": 1464739200000 + }, + { + "value": 30.938970967741938, + "timestamp": 1467331200000 + }, + { + "value": 30.09242580645161, + "timestamp": 1470009600000 + }, + { + "value": 31.719943333333333, + "timestamp": 1472688000000 + }, + { + "value": 29.9146064516129, + "timestamp": 1475280000000 + }, + { + "value": 26.725856666666665, + "timestamp": 1477958400000 + }, + { + "value": 25.569358064516138, + "timestamp": 1480550400000 + }, + { + "value": 24.87566129032258, + "timestamp": 1483228800000 + }, + { + "value": 24.985339285714286, + "timestamp": 1485907200000 + }, + { + "value": 28.379903225806455, + "timestamp": 1488326400000 + }, + { + "value": 30.58911333333333, + "timestamp": 1491004800000 + }, + { + "value": 30.775587096774196, + "timestamp": 1493596800000 + }, + { + "value": 33.38314666666667, + "timestamp": 1496275200000 + }, + { + "value": 33.10136451612903, + "timestamp": 1498867200000 + }, + { + "value": 31.334748387096774, + "timestamp": 1501545600000 + }, + { + "value": 31.38021666666665, + "timestamp": 1504224000000 + }, + { + "value": 29.83076129032258, + "timestamp": 1506816000000 + }, + { + "value": 27.193993333333342, + "timestamp": 1509494400000 + }, + { + "value": 23.960296774193544, + "timestamp": 1512086400000 + }, + { + "value": 23.52738064516129, + "timestamp": 1514764800000 + }, + { + "value": 26.36581071428571, + "timestamp": 1517443200000 + }, + { + "value": 28.263512903225802, + "timestamp": 1519862400000 + }, + { + "value": 29.41648, + "timestamp": 1522540800000 + }, + { + "value": 31.54575806451613, + "timestamp": 1525132800000 + }, + { + "value": 32.583773333333326, + "timestamp": 1527811200000 + }, + { + "value": 31.64165806451613, + "timestamp": 1530403200000 + }, + { + "value": 31.09654516129033, + "timestamp": 1533081600000 + }, + { + "value": 31.05386, + "timestamp": 1535760000000 + }, + { + "value": 28.96214516129032, + "timestamp": 1538352000000 + }, + { + "value": 27.13166333333333, + "timestamp": 1541030400000 + }, + { + "value": 25.68454516129033, + "timestamp": 1543622400000 + }, + { + "value": 25.283158064516122, + "timestamp": 1546300800000 + }, + { + "value": 26.651496428571424, + "timestamp": 1548979200000 + }, + { + "value": 28.37367419354839, + "timestamp": 1551398400000 + }, + { + "value": 30.04280333333334, + "timestamp": 1554076800000 + }, + { + "value": 31.15893548387097, + "timestamp": 1556668800000 + }, + { + "value": 32.30068000000001, + "timestamp": 1559347200000 + }, + { + "value": 32.47812903225805, + "timestamp": 1561939200000 + }, + { + "value": 30.347477419354842, + "timestamp": 1564617600000 + }, + { + "value": 31.065396666666672, + "timestamp": 1567296000000 + }, + { + "value": 28.27787419354838, + "timestamp": 1569888000000 + }, + { + "value": 27.33406, + "timestamp": 1572566400000 + }, + { + "value": 25.796612903225803, + "timestamp": 1575158400000 + }, + { + "value": 24.14383548387097, + "timestamp": 1577836800000 + }, + { + "value": 26.030389655172414, + "timestamp": 1580515200000 + }, + { + "value": 27.92293548387097, + "timestamp": 1583020800000 + }, + { + "value": 29.40862, + "timestamp": 1585699200000 + }, + { + "value": 31.621658064516133, + "timestamp": 1588291200000 + }, + { + "value": 32.352473333333336, + "timestamp": 1590969600000 + }, + { + "value": 32.12196666666667, + "timestamp": 1593561600000 + } + ], + "numLevels": 31 + }, + "wm/concept/environment/meteorology/precipitation": { + "name": "Precipitation", + "minValue": 0.000012903225806451613, + "maxValue": 9.463974193548387, + "func": "last", + "values": [ + { + "value": 0.06728709677419355, + "timestamp": 662688000000 + }, + { + "value": 0.9487749999999998, + "timestamp": 665366400000 + }, + { + "value": 2.294458064516129, + "timestamp": 667785600000 + }, + { + "value": 0.9806033333333333, + "timestamp": 670464000000 + }, + { + "value": 0.7540387096774193, + "timestamp": 673056000000 + }, + { + "value": 0.24305333333333332, + "timestamp": 675734400000 + }, + { + "value": 4.698829032258065, + "timestamp": 678326400000 + }, + { + "value": 5.648793548387096, + "timestamp": 681004800000 + }, + { + "value": 1.3958533333333334, + "timestamp": 683683200000 + }, + { + "value": 1.710138709677419, + "timestamp": 686275200000 + }, + { + "value": 0.08885333333333335, + "timestamp": 688953600000 + }, + { + "value": 0.612916129032258, + "timestamp": 691545600000 + }, + { + "value": 0.6289516129032259, + "timestamp": 694224000000 + }, + { + "value": 1.1173551724137927, + "timestamp": 696902400000 + }, + { + "value": 0.4222516129032259, + "timestamp": 699408000000 + }, + { + "value": 1.00248, + "timestamp": 702086400000 + }, + { + "value": 1.2269225806451611, + "timestamp": 704678400000 + }, + { + "value": 0.9452533333333333, + "timestamp": 707356800000 + }, + { + "value": 3.6642903225806447, + "timestamp": 709948800000 + }, + { + "value": 4.430374193548386, + "timestamp": 712627200000 + }, + { + "value": 1.35189, + "timestamp": 715305600000 + }, + { + "value": 0.3002612903225806, + "timestamp": 717897600000 + }, + { + "value": 0.17042000000000004, + "timestamp": 720576000000 + }, + { + "value": 0.15677096774193547, + "timestamp": 723168000000 + }, + { + "value": 0.2629516129032259, + "timestamp": 725846400000 + }, + { + "value": 0.3155000000000001, + "timestamp": 728524800000 + }, + { + "value": 0.22454193548387097, + "timestamp": 730944000000 + }, + { + "value": 3.905033333333334, + "timestamp": 733622400000 + }, + { + "value": 3.6554709677419353, + "timestamp": 736214400000 + }, + { + "value": 1.2678466666666666, + "timestamp": 738892800000 + }, + { + "value": 6.514112903225806, + "timestamp": 741484800000 + }, + { + "value": 4.00190322580645, + "timestamp": 744163200000 + }, + { + "value": 2.3712233333333335, + "timestamp": 746841600000 + }, + { + "value": 1.7191935483870968, + "timestamp": 749433600000 + }, + { + "value": 0.40519999999999995, + "timestamp": 752112000000 + }, + { + "value": 0.09775483870967742, + "timestamp": 754704000000 + }, + { + "value": 0.000012903225806451613, + "timestamp": 757382400000 + }, + { + "value": 0.056485714285714285, + "timestamp": 760060800000 + }, + { + "value": 0.6125935483870967, + "timestamp": 762480000000 + }, + { + "value": 1.9465366666666666, + "timestamp": 765158400000 + }, + { + "value": 1.3920322580645168, + "timestamp": 767750400000 + }, + { + "value": 1.81064, + "timestamp": 770428800000 + }, + { + "value": 5.636487096774194, + "timestamp": 773020800000 + }, + { + "value": 6.073612903225807, + "timestamp": 775699200000 + }, + { + "value": 3.7383600000000006, + "timestamp": 778377600000 + }, + { + "value": 0.1895032258064516, + "timestamp": 780969600000 + }, + { + "value": 2.1099333333333328, + "timestamp": 783648000000 + }, + { + "value": 0.0419483870967742, + "timestamp": 786240000000 + }, + { + "value": 0.0020096774193548387, + "timestamp": 788918400000 + }, + { + "value": 1.5378892857142863, + "timestamp": 791596800000 + }, + { + "value": 3.029506451612902, + "timestamp": 794016000000 + }, + { + "value": 2.414076666666666, + "timestamp": 796694400000 + }, + { + "value": 1.8389774193548387, + "timestamp": 799286400000 + }, + { + "value": 0.6246033333333333, + "timestamp": 801964800000 + }, + { + "value": 5.903183870967741, + "timestamp": 804556800000 + }, + { + "value": 4.708770967741936, + "timestamp": 807235200000 + }, + { + "value": 1.7363899999999999, + "timestamp": 809913600000 + }, + { + "value": 1.5013612903225806, + "timestamp": 812505600000 + }, + { + "value": 0.13255333333333333, + "timestamp": 815184000000 + }, + { + "value": 1.126558064516129, + "timestamp": 817776000000 + }, + { + "value": 0.7115129032258064, + "timestamp": 820454400000 + }, + { + "value": 0.05641724137931035, + "timestamp": 823132800000 + }, + { + "value": 3.6175064516129036, + "timestamp": 825638400000 + }, + { + "value": 2.823293333333333, + "timestamp": 828316800000 + }, + { + "value": 2.162712903225807, + "timestamp": 830908800000 + }, + { + "value": 1.4882466666666667, + "timestamp": 833587200000 + }, + { + "value": 5.011274193548387, + "timestamp": 836179200000 + }, + { + "value": 6.265332258064516, + "timestamp": 838857600000 + }, + { + "value": 1.59045, + "timestamp": 841536000000 + }, + { + "value": 0.7173290322580645, + "timestamp": 844128000000 + }, + { + "value": 0.8473799999999999, + "timestamp": 846806400000 + }, + { + "value": 0.03824516129032257, + "timestamp": 849398400000 + }, + { + "value": 0.31263548387096773, + "timestamp": 852076800000 + }, + { + "value": 0.008214285714285714, + "timestamp": 854755200000 + }, + { + "value": 1.9908935483870966, + "timestamp": 857174400000 + }, + { + "value": 1.4473566666666664, + "timestamp": 859852800000 + }, + { + "value": 0.6112838709677421, + "timestamp": 862444800000 + }, + { + "value": 2.711343333333333, + "timestamp": 865123200000 + }, + { + "value": 6.126045161290323, + "timestamp": 867715200000 + }, + { + "value": 5.360922580645162, + "timestamp": 870393600000 + }, + { + "value": 1.0090066666666668, + "timestamp": 873072000000 + }, + { + "value": 3.353306451612903, + "timestamp": 875664000000 + }, + { + "value": 0.68993, + "timestamp": 878342400000 + }, + { + "value": 0.03422903225806452, + "timestamp": 880934400000 + }, + { + "value": 0.6387774193548386, + "timestamp": 883612800000 + }, + { + "value": 0.9082928571428571, + "timestamp": 886291200000 + }, + { + "value": 0.7401290322580645, + "timestamp": 888710400000 + }, + { + "value": 0.9964633333333334, + "timestamp": 891388800000 + }, + { + "value": 1.0602129032258065, + "timestamp": 893980800000 + }, + { + "value": 0.9417599999999999, + "timestamp": 896659200000 + }, + { + "value": 7.602393548387095, + "timestamp": 899251200000 + }, + { + "value": 6.537809677419355, + "timestamp": 901929600000 + }, + { + "value": 2.8327433333333327, + "timestamp": 904608000000 + }, + { + "value": 1.9148677419354836, + "timestamp": 907200000000 + }, + { + "value": 0.08191999999999999, + "timestamp": 909878400000 + }, + { + "value": 0.0022806451612903227, + "timestamp": 912470400000 + }, + { + "value": 0.5421193548387098, + "timestamp": 915148800000 + }, + { + "value": 0.04328928571428571, + "timestamp": 917827200000 + }, + { + "value": 6.901003225806452, + "timestamp": 920246400000 + }, + { + "value": 0.3704833333333333, + "timestamp": 922924800000 + }, + { + "value": 0.3266903225806451, + "timestamp": 925516800000 + }, + { + "value": 0.9711933333333335, + "timestamp": 928195200000 + }, + { + "value": 7.747980645161291, + "timestamp": 930787200000 + }, + { + "value": 9.463974193548387, + "timestamp": 933465600000 + }, + { + "value": 1.9669033333333332, + "timestamp": 936144000000 + }, + { + "value": 2.1990838709677423, + "timestamp": 938736000000 + }, + { + "value": 0.10037, + "timestamp": 941414400000 + }, + { + "value": 0.059132258064516136, + "timestamp": 944006400000 + }, + { + "value": 0.0029580645161290326, + "timestamp": 946684800000 + }, + { + "value": 0.003248275862068966, + "timestamp": 949363200000 + }, + { + "value": 0.18205483870967742, + "timestamp": 951868800000 + }, + { + "value": 0.65317, + "timestamp": 954547200000 + }, + { + "value": 0.2844032258064516, + "timestamp": 957139200000 + }, + { + "value": 0.4054566666666667, + "timestamp": 959817600000 + }, + { + "value": 1.5713387096774194, + "timestamp": 962409600000 + }, + { + "value": 2.515999999999999, + "timestamp": 965088000000 + }, + { + "value": 1.1861233333333336, + "timestamp": 967766400000 + }, + { + "value": 0.4182838709677419, + "timestamp": 970358400000 + }, + { + "value": 0.1742766666666667, + "timestamp": 973036800000 + }, + { + "value": 0.0832935483870968, + "timestamp": 975628800000 + }, + { + "value": 0.029319354838709684, + "timestamp": 978307200000 + }, + { + "value": 0.07208214285714287, + "timestamp": 980985600000 + }, + { + "value": 1.7994548387096772, + "timestamp": 983404800000 + }, + { + "value": 0.45108, + "timestamp": 986083200000 + }, + { + "value": 0.9472258064516129, + "timestamp": 988675200000 + }, + { + "value": 1.1466300000000003, + "timestamp": 991353600000 + }, + { + "value": 1.599316129032258, + "timestamp": 993945600000 + }, + { + "value": 1.9795838709677418, + "timestamp": 996624000000 + }, + { + "value": 1.509206666666667, + "timestamp": 999302400000 + }, + { + "value": 0.4565322580645162, + "timestamp": 1001894400000 + }, + { + "value": 0.11963666666666666, + "timestamp": 1004572800000 + }, + { + "value": 0.09750645161290322, + "timestamp": 1007164800000 + }, + { + "value": 0.3901548387096774, + "timestamp": 1009843200000 + }, + { + "value": 0.015535714285714288, + "timestamp": 1012521600000 + }, + { + "value": 1.5172096774193544, + "timestamp": 1014940800000 + }, + { + "value": 0.8107133333333333, + "timestamp": 1017619200000 + }, + { + "value": 0.3211225806451613, + "timestamp": 1020211200000 + }, + { + "value": 1.09399, + "timestamp": 1022889600000 + }, + { + "value": 2.976754838709678, + "timestamp": 1025481600000 + }, + { + "value": 1.8797451612903227, + "timestamp": 1028160000000 + }, + { + "value": 1.1020333333333334, + "timestamp": 1030838400000 + }, + { + "value": 0.08540322580645161, + "timestamp": 1033430400000 + }, + { + "value": 0.02131333333333333, + "timestamp": 1036108800000 + }, + { + "value": 0.423958064516129, + "timestamp": 1038700800000 + }, + { + "value": 0.062099999999999995, + "timestamp": 1041379200000 + }, + { + "value": 0.2402142857142857, + "timestamp": 1044057600000 + }, + { + "value": 0.40361290322580645, + "timestamp": 1046476800000 + }, + { + "value": 1.2793133333333335, + "timestamp": 1049155200000 + }, + { + "value": 0.34342903225806454, + "timestamp": 1051747200000 + }, + { + "value": 0.5654900000000002, + "timestamp": 1054425600000 + }, + { + "value": 1.3574774193548387, + "timestamp": 1057017600000 + }, + { + "value": 2.878167741935484, + "timestamp": 1059696000000 + }, + { + "value": 1.3381, + "timestamp": 1062374400000 + }, + { + "value": 0.02172258064516129, + "timestamp": 1064966400000 + }, + { + "value": 0.056593333333333336, + "timestamp": 1067644800000 + }, + { + "value": 1.3819419354838707, + "timestamp": 1070236800000 + }, + { + "value": 0.15293870967741938, + "timestamp": 1072915200000 + }, + { + "value": 0.03384827586206897, + "timestamp": 1075593600000 + }, + { + "value": 0.5387548387096774, + "timestamp": 1078099200000 + }, + { + "value": 1.7106233333333336, + "timestamp": 1080777600000 + }, + { + "value": 0.15610000000000004, + "timestamp": 1083369600000 + }, + { + "value": 0.7356533333333333, + "timestamp": 1086048000000 + }, + { + "value": 1.5482193548387095, + "timestamp": 1088640000000 + }, + { + "value": 1.2879451612903223, + "timestamp": 1091318400000 + }, + { + "value": 0.8960166666666668, + "timestamp": 1093996800000 + }, + { + "value": 0.3212, + "timestamp": 1096588800000 + }, + { + "value": 0.25264000000000003, + "timestamp": 1099267200000 + }, + { + "value": 1.2692516129032259, + "timestamp": 1101859200000 + }, + { + "value": 0.5297677419354838, + "timestamp": 1104537600000 + }, + { + "value": 0.020303571428571428, + "timestamp": 1107216000000 + }, + { + "value": 0.6819483870967742, + "timestamp": 1109635200000 + }, + { + "value": 5.666779999999999, + "timestamp": 1112313600000 + }, + { + "value": 1.5935193548387092, + "timestamp": 1114905600000 + }, + { + "value": 0.13908, + "timestamp": 1117584000000 + }, + { + "value": 1.4270096774193548, + "timestamp": 1120176000000 + }, + { + "value": 1.4261580645161291, + "timestamp": 1122854400000 + }, + { + "value": 0.8197633333333335, + "timestamp": 1125532800000 + }, + { + "value": 0.11170322580645162, + "timestamp": 1128124800000 + }, + { + "value": 0.1629766666666667, + "timestamp": 1130803200000 + }, + { + "value": 0.00003548387096774194, + "timestamp": 1133395200000 + }, + { + "value": 0.2825870967741936, + "timestamp": 1136073600000 + }, + { + "value": 0.5009964285714285, + "timestamp": 1138752000000 + }, + { + "value": 2.157316129032258, + "timestamp": 1141171200000 + }, + { + "value": 2.88453, + "timestamp": 1143849600000 + }, + { + "value": 0.8479161290322579, + "timestamp": 1146441600000 + }, + { + "value": 0.8250766666666666, + "timestamp": 1149120000000 + }, + { + "value": 5.779832258064516, + "timestamp": 1151712000000 + }, + { + "value": 5.873341935483871, + "timestamp": 1154390400000 + }, + { + "value": 1.8016600000000005, + "timestamp": 1157068800000 + }, + { + "value": 0.7985806451612903, + "timestamp": 1159660800000 + }, + { + "value": 0.06096999999999999, + "timestamp": 1162339200000 + }, + { + "value": 0.6383129032258064, + "timestamp": 1164931200000 + }, + { + "value": 0.29653225806451616, + "timestamp": 1167609600000 + }, + { + "value": 0.7592964285714288, + "timestamp": 1170288000000 + }, + { + "value": 0.4818387096774193, + "timestamp": 1172707200000 + }, + { + "value": 2.13564, + "timestamp": 1175385600000 + }, + { + "value": 0.914458064516129, + "timestamp": 1177977600000 + }, + { + "value": 0.57174, + "timestamp": 1180656000000 + }, + { + "value": 4.016754838709677, + "timestamp": 1183248000000 + }, + { + "value": 2.6767129032258064, + "timestamp": 1185926400000 + }, + { + "value": 1.5335700000000003, + "timestamp": 1188604800000 + }, + { + "value": 0.4098645161290323, + "timestamp": 1191196800000 + }, + { + "value": 0.08767333333333331, + "timestamp": 1193875200000 + }, + { + "value": 0.0013032258064516128, + "timestamp": 1196467200000 + }, + { + "value": 0.2770870967741936, + "timestamp": 1199145600000 + }, + { + "value": 0.05724827586206895, + "timestamp": 1201824000000 + }, + { + "value": 0.004441935483870968, + "timestamp": 1204329600000 + }, + { + "value": 1.3048499999999996, + "timestamp": 1207008000000 + }, + { + "value": 0.5841129032258066, + "timestamp": 1209600000000 + }, + { + "value": 0.3510566666666667, + "timestamp": 1212278400000 + }, + { + "value": 3.051477419354838, + "timestamp": 1214870400000 + }, + { + "value": 3.621367741935484, + "timestamp": 1217548800000 + }, + { + "value": 1.4803233333333337, + "timestamp": 1220227200000 + }, + { + "value": 0.25687096774193546, + "timestamp": 1222819200000 + }, + { + "value": 0.91209, + "timestamp": 1225497600000 + }, + { + "value": 0.016370967741935485, + "timestamp": 1228089600000 + }, + { + "value": 0.34909677419354834, + "timestamp": 1230768000000 + }, + { + "value": 0.10439999999999998, + "timestamp": 1233446400000 + }, + { + "value": 0.534858064516129, + "timestamp": 1235865600000 + }, + { + "value": 0.8979766666666665, + "timestamp": 1238544000000 + }, + { + "value": 0.10481612903225812, + "timestamp": 1241136000000 + }, + { + "value": 0.7390233333333334, + "timestamp": 1243814400000 + }, + { + "value": 4.489709677419355, + "timestamp": 1246406400000 + }, + { + "value": 4.1637516129032255, + "timestamp": 1249084800000 + }, + { + "value": 0.8885666666666666, + "timestamp": 1251763200000 + }, + { + "value": 1.3989096774193543, + "timestamp": 1254355200000 + }, + { + "value": 0.04606, + "timestamp": 1257033600000 + }, + { + "value": 0.3052, + "timestamp": 1259625600000 + }, + { + "value": 0.004861290322580645, + "timestamp": 1262304000000 + }, + { + "value": 1.6522500000000002, + "timestamp": 1264982400000 + }, + { + "value": 1.2724806451612904, + "timestamp": 1267401600000 + }, + { + "value": 1.7387466666666662, + "timestamp": 1270080000000 + }, + { + "value": 1.3899032258064519, + "timestamp": 1272672000000 + }, + { + "value": 0.975606666666667, + "timestamp": 1275350400000 + }, + { + "value": 5.156887096774193, + "timestamp": 1277942400000 + }, + { + "value": 6.972422580645162, + "timestamp": 1280620800000 + }, + { + "value": 2.128933333333333, + "timestamp": 1283299200000 + }, + { + "value": 0.1325741935483871, + "timestamp": 1285891200000 + }, + { + "value": 0.23680666666666667, + "timestamp": 1288569600000 + }, + { + "value": 0.03993225806451613, + "timestamp": 1291161600000 + }, + { + "value": 0.06617741935483872, + "timestamp": 1293840000000 + }, + { + "value": 0.08242500000000001, + "timestamp": 1296518400000 + }, + { + "value": 1.0754354838709683, + "timestamp": 1298937600000 + }, + { + "value": 0.6573533333333333, + "timestamp": 1301616000000 + }, + { + "value": 2.4816129032258067, + "timestamp": 1304208000000 + }, + { + "value": 0.22561333333333333, + "timestamp": 1306886400000 + }, + { + "value": 1.453916129032258, + "timestamp": 1309478400000 + }, + { + "value": 1.706332258064516, + "timestamp": 1312156800000 + }, + { + "value": 0.67557, + "timestamp": 1314835200000 + }, + { + "value": 0.11155483870967743, + "timestamp": 1317427200000 + }, + { + "value": 0.22255333333333335, + "timestamp": 1320105600000 + }, + { + "value": 0.007632258064516127, + "timestamp": 1322697600000 + }, + { + "value": 0.01034193548387097, + "timestamp": 1325376000000 + }, + { + "value": 0.00006551724137931034, + "timestamp": 1328054400000 + }, + { + "value": 0.1461193548387097, + "timestamp": 1330560000000 + }, + { + "value": 1.2186200000000005, + "timestamp": 1333238400000 + }, + { + "value": 0.2599677419354839, + "timestamp": 1335830400000 + }, + { + "value": 0.3277933333333332, + "timestamp": 1338508800000 + }, + { + "value": 3.230758064516129, + "timestamp": 1341100800000 + }, + { + "value": 2.9337064516129026, + "timestamp": 1343779200000 + }, + { + "value": 1.0406100000000003, + "timestamp": 1346457600000 + }, + { + "value": 0.0398, + "timestamp": 1349049600000 + }, + { + "value": 0.028990000000000002, + "timestamp": 1351728000000 + }, + { + "value": 0.07618709677419355, + "timestamp": 1354320000000 + }, + { + "value": 0.3456903225806452, + "timestamp": 1356998400000 + }, + { + "value": 0.017175, + "timestamp": 1359676800000 + }, + { + "value": 1.094945161290323, + "timestamp": 1362096000000 + }, + { + "value": 1.2708966666666668, + "timestamp": 1364774400000 + }, + { + "value": 0.6110838709677421, + "timestamp": 1367366400000 + }, + { + "value": 0.8498133333333334, + "timestamp": 1370044800000 + }, + { + "value": 5.49858064516129, + "timestamp": 1372636800000 + }, + { + "value": 5.575745161290322, + "timestamp": 1375315200000 + }, + { + "value": 1.3711433333333332, + "timestamp": 1377993600000 + }, + { + "value": 2.3997483870967744, + "timestamp": 1380585600000 + }, + { + "value": 0.3174566666666667, + "timestamp": 1383264000000 + }, + { + "value": 0.06693548387096773, + "timestamp": 1385856000000 + }, + { + "value": 0.028819354838709677, + "timestamp": 1388534400000 + }, + { + "value": 0.34499285714285716, + "timestamp": 1391212800000 + }, + { + "value": 0.900948387096774, + "timestamp": 1393632000000 + }, + { + "value": 1.9720633333333335, + "timestamp": 1396310400000 + }, + { + "value": 1.3286774193548385, + "timestamp": 1398902400000 + }, + { + "value": 0.8263266666666667, + "timestamp": 1401580800000 + }, + { + "value": 5.062932258064516, + "timestamp": 1404172800000 + }, + { + "value": 3.7404645161290317, + "timestamp": 1406851200000 + }, + { + "value": 2.73512, + "timestamp": 1409529600000 + }, + { + "value": 1.170358064516129, + "timestamp": 1412121600000 + }, + { + "value": 0.14135666666666666, + "timestamp": 1414800000000 + }, + { + "value": 0.08283548387096774, + "timestamp": 1417392000000 + }, + { + "value": 0.2841967741935483, + "timestamp": 1420070400000 + }, + { + "value": 0.030460714285714285, + "timestamp": 1422748800000 + }, + { + "value": 0.38081612903225803, + "timestamp": 1425168000000 + }, + { + "value": 0.02333666666666667, + "timestamp": 1427846400000 + }, + { + "value": 0.7997806451612904, + "timestamp": 1430438400000 + }, + { + "value": 1.5224566666666666, + "timestamp": 1433116800000 + }, + { + "value": 0.990932258064516, + "timestamp": 1435708800000 + }, + { + "value": 5.702148387096773, + "timestamp": 1438387200000 + }, + { + "value": 0.9648533333333336, + "timestamp": 1441065600000 + }, + { + "value": 0.1965032258064516, + "timestamp": 1443657600000 + }, + { + "value": 0.5751666666666665, + "timestamp": 1446336000000 + }, + { + "value": 0.8186806451612904, + "timestamp": 1448928000000 + }, + { + "value": 0.2591709677419355, + "timestamp": 1451606400000 + }, + { + "value": 0.318703448275862, + "timestamp": 1454284800000 + }, + { + "value": 0.8187290322580645, + "timestamp": 1456790400000 + }, + { + "value": 4.820703333333333, + "timestamp": 1459468800000 + }, + { + "value": 2.272238709677419, + "timestamp": 1462060800000 + }, + { + "value": 0.4943966666666667, + "timestamp": 1464739200000 + }, + { + "value": 5.14783870967742, + "timestamp": 1467331200000 + }, + { + "value": 4.638109677419355, + "timestamp": 1470009600000 + }, + { + "value": 1.6093666666666664, + "timestamp": 1472688000000 + }, + { + "value": 0.2956516129032259, + "timestamp": 1475280000000 + }, + { + "value": 0.16122333333333336, + "timestamp": 1477958400000 + }, + { + "value": 0.043764516129032247, + "timestamp": 1480550400000 + }, + { + "value": 0.0015129032258064516, + "timestamp": 1483228800000 + }, + { + "value": 1.7857428571428573, + "timestamp": 1485907200000 + }, + { + "value": 1.7253290322580646, + "timestamp": 1488326400000 + }, + { + "value": 1.3224433333333332, + "timestamp": 1491004800000 + }, + { + "value": 2.43228064516129, + "timestamp": 1493596800000 + }, + { + "value": 0.32378, + "timestamp": 1496275200000 + }, + { + "value": 2.0054193548387094, + "timestamp": 1498867200000 + }, + { + "value": 4.14855806451613, + "timestamp": 1501545600000 + }, + { + "value": 2.438363333333333, + "timestamp": 1504224000000 + }, + { + "value": 0.719467741935484, + "timestamp": 1506816000000 + }, + { + "value": 0.13373333333333332, + "timestamp": 1509494400000 + }, + { + "value": 0.00494516129032258, + "timestamp": 1512086400000 + }, + { + "value": 0.18523870967741934, + "timestamp": 1514764800000 + }, + { + "value": 0.6241428571428572, + "timestamp": 1517443200000 + }, + { + "value": 0.3953419354838708, + "timestamp": 1519862400000 + }, + { + "value": 2.6591999999999993, + "timestamp": 1522540800000 + }, + { + "value": 0.17660322580645163, + "timestamp": 1525132800000 + }, + { + "value": 0.47159666666666666, + "timestamp": 1527811200000 + }, + { + "value": 2.1962451612903227, + "timestamp": 1530403200000 + }, + { + "value": 3.4617064516129035, + "timestamp": 1533081600000 + }, + { + "value": 3.3733399999999993, + "timestamp": 1535760000000 + }, + { + "value": 0.9658967741935485, + "timestamp": 1538352000000 + }, + { + "value": 0.7850466666666666, + "timestamp": 1541030400000 + }, + { + "value": 0.029367741935483874, + "timestamp": 1543622400000 + }, + { + "value": 0.00004516129032258064, + "timestamp": 1546300800000 + }, + { + "value": 1.3573500000000003, + "timestamp": 1548979200000 + }, + { + "value": 0.9780967741935485, + "timestamp": 1551398400000 + }, + { + "value": 2.444236666666667, + "timestamp": 1554076800000 + }, + { + "value": 0.31139677419354833, + "timestamp": 1556668800000 + }, + { + "value": 1.1136799999999998, + "timestamp": 1559347200000 + }, + { + "value": 0.5978451612903224, + "timestamp": 1561939200000 + }, + { + "value": 2.9266354838709683, + "timestamp": 1564617600000 + }, + { + "value": 5.163923333333333, + "timestamp": 1567296000000 + }, + { + "value": 1.8762806451612908, + "timestamp": 1569888000000 + }, + { + "value": 0.98977, + "timestamp": 1572566400000 + }, + { + "value": 0.8167354838709676, + "timestamp": 1575158400000 + }, + { + "value": 0.3114774193548387, + "timestamp": 1577836800000 + }, + { + "value": 0.3238310344827586, + "timestamp": 1580515200000 + }, + { + "value": 1.214196774193548, + "timestamp": 1583020800000 + }, + { + "value": 3.587106666666666, + "timestamp": 1585699200000 + }, + { + "value": 2.2378451612903234, + "timestamp": 1588291200000 + }, + { + "value": 0.9830266666666667, + "timestamp": 1590969600000 + }, + { + "value": 3.9650741935483875, + "timestamp": 1593561600000 + }, + { + "value": 4.346283870967741, + "timestamp": 1596240000000 + }, + { + "value": 2.3164600000000006, + "timestamp": 1598918400000 + } + ], + "numLevels": 31 + } + } +} \ No newline at end of file diff --git a/tests/data/delphi/experiments_rain--temperature--yield.json b/tests/data/delphi/experiments_rain--temperature--yield.json new file mode 100644 index 000000000..b169ce721 --- /dev/null +++ b/tests/data/delphi/experiments_rain--temperature--yield.json @@ -0,0 +1,9 @@ +{ + "experimentType": "PROJECTION", + "experimentParam": { + "startTime": 1538352000000, + "endTime": 1598918400000, + "numTimesteps": 24, + "constraints": [] + } +} \ No newline at end of file