diff --git a/README.md b/README.md index 7ba1bae..ef436ba 100644 --- a/README.md +++ b/README.md @@ -159,51 +159,6 @@ $$ --> | **... (additional parameters)** |Read more in the [User Guide: Additional Parameters](https://github.com/SaniyaKhullar/NetREm/blob/main/user_guide/Additional_NetREm_Parameters.md) for more parameters after **model_type** | - - - - - - - - - - - - - - - - - - ### Details: We input an edge list of the prior graph network (constrains the model via network-based regularization) and a beta_net ($\beta_{net} \geq 0$, which scales the network-based regularization penalty). The user may specify the alpha_lasso ($\alpha_{lasso} \geq 0$) manually for the lasso regularization on the overall model (if `model_type = Lasso`) or NetREm may select an optimal $\alpha_{lasso}$ based on cross-validation (CV) on the training data (if `model_type = LasssoCV`). Then, **netrem** builds an estimator object from the class Netrem that can then take in input $X$ and $y$ data: transforms them to $\tilde{X}$ and $\tilde{y}$, respectively, and use them to fit a Lasso regression model with a regularization value of $\alpha_{lasso}$. Ultimately, the trained NetREm machine learning model is more reflective of an underlying network structure among predictors and may be more biologically meaningful and interpretable. Nonetheless, NetREm could be applied in various contexts where a network structure is present among the predictors. Input networks are typically weighted and undirected. We provide details, functions, and help with converting directed networks to undirected networks (of similarity values among nodes) [here](https://github.com/SaniyaKhullar/NetREm/blob/main/user_guide/directed_to_undirected_network_example.ipynb). @@ -301,9 +256,9 @@ $$MSE = \frac{1}{m} \sum_{i=1}^m (y_i - \hat{y_i})^2$$
## Demo (Toy Example) of NetREm: -The goal is to build a machine learning model to predict the gene expression levels of our target gene (TG) $y$ based on the gene expression levels of $N = 6$ Transcription Factors (TFs) [TF1, $TF_{2}$, $TF_{3}$, $TF_{4}$, $TF_{5}$, $TF_{6}$] in a particular cell-type. Assume the gene expression values for each TF are [X1, $X_{2}$, $X_{3}$, $X_{4}$, $X_{5}$, $X_{6}$], respectively. We generate $M = 100$ random samples (rows) of data where the Pearson correlations ($r$) between gene expression of each TF ($X$) with gene expression of TG $y$ as *corrVals*: [cor(TF1, $y$) = 0.9, cor(TF2, $y$) = 0.5, cor(TF3, $y$) = 0.1, cor(TF4, $y$) = -0.2, cor(TF5, $y$) = -0.8, cor(TF6, $y$) = -0.3]. +The goal is to build a machine learning model to predict the gene expression levels of our target gene (TG) $y$ based on the gene expression levels of $N = 5$ Transcription Factors (TFs) [TF1, $TF_{2}$, $TF_{3}$, $TF_{4}$, $TF_{5}$] in a particular cell-type. Assume the gene expression values for each TF are [X1, $X_{2}$, $X_{3}$, $X_{4}$, $X_{5}$], respectively. We generate $M = 100,000$ random samples (rows) of data where the Pearson correlations ($r$) between gene expression of each TF ($X$) with gene expression of TG $y$ as *corrVals*: [cor(TF1, $y$) = 0.9, cor(TF2, $y$) = 0.5, cor(TF3, $y$) = 0.4, cor(TF4, $y$) = -0.3, cor(TF5, $y$) = -0.8]. -The dimensions of $X$ are therefore 100 rows by 6 columns (predictors). More details about our *generate_dummy_data* function (and additional parameters we can adjust for) are in [Dummy_Data_Demo_Example.ipynb](https://github.com/SaniyaKhullar/NetREm/blob/main/user_guide/Dummy_Data_Demo_Example.ipynb). Our NetREm estimator also incorporates a constraint of an **undirected weighted prior graph network** of biological relationships among only 5 TFs based on a weighted Protein-Protein Interaction (PPI) network ([TF1, $TF_{2}$, $TF_{3}$, $TF_{4}$, $TF_{5}$]), where higher edge weights $w$ indicate stronger biological interactions at the protein-level. +The dimensions of $X$ are therefore 100,000 rows by 5 columns (predictors). More details about our *generate_dummy_data* function (and additional parameters we can adjust for) are in [Dummy_Data_Demo_Example.pdf](https://github.com/SaniyaKhullar/NetREm/blob/main/user_guide/Dummy_Data_Demo_Example.pdf). Our NetREm estimator also incorporates a constraint of an **undirected weighted prior graph network** of biological relationships among only 5 TFs based on a weighted Protein-Protein Interaction (PPI) network ([TF1, $TF_{2}$, $TF_{3}$, $TF_{4}$, $TF_{5}$]), where higher edge weights $w$ indicate stronger biological interactions at the protein-level. The code for this demo example is [demo_toy.py](https://github.com/SaniyaKhullar/NetREm/blob/main/demo/demo_toy.py) in the *demo* folder. @@ -315,20 +270,18 @@ import error_metrics as em import essential_functions as ef import netrem_evaluation_functions as nm_eval -dummy_data = generate_dummy_data(corrVals = [0.9, 0.5, 0.1, -0.2, -0.8, -0.3], # the # of elements in corrVals is the # of predictors (X) - num_samples_M = 100, # the number of samples M - standardize_X = False, - center_y = False, +dummy_data = generate_dummy_data(corrVals = [0.9, 0.5, 0.4, -0.3, -0.8], # the # of elements in corrVals is the # of predictors (X) + num_samples_M = 100000, # the number of samples M train_data_percent = 70) # the remainder out of 100 will be kept for testing. If 100, all data is used for training and testing. ``` The Python console or Jupyter notebook will print out the following: same_train_test_data = False - We hold out 30.0% of our 100 samples for testing, so that: - X_train = 70 rows (samples) and 6 columns (N = 6 predictors) for training. - X_test = 30 rows (samples) and 6 columns (N = 6 predictors) for testing. - y_train = 70 corresponding rows (samples) for training. - y_test = 30 corresponding rows (samples) for testing. + Please note that since we hold out 30.0% of our 100000 samples for testing, we have: + X_train = 70000 rows (samples) and 5 columns (N = 5 predictors) for training. + X_test = 30000 rows (samples) and 5 columns (N = 5 predictors) for testing. + y_train = 70000 corresponding rows (samples) for training. + y_test = 30000 corresponding rows (samples) for testing. The $X$ data should be in the form of a Pandas dataframe as below: @@ -339,61 +292,55 @@ X_df.head()
- + - - - - - - - + + + + + - - - - - - + + + + + - - - - - - + + + + + - - - - - - + + + + + - - - - - - + + + + +
TF1 TF2 TF3 TF4 TF5TF6
02.0208400.594445-1.443012-0.6887770.900770-2.6436710.0675111.1681620.500052-1.622116-0.827644
13.224776-0.270632-0.557771-0.3055740.054708-1.0541971.754397-1.5314720.0676300.857830-1.440013
2-2.7467211.5022362.0438131.2529752.0821591.227615-1.519240-0.7648290.823048-0.2061060.820908
3-0.5581301.290771-1.230527-0.6784100.630084-1.5087580.0097352.0279542.0927690.8868840.054337
4-2.181462-0.657229-2.880186-1.6294700.2680421.207254-0.3774060.905750-1.1677451.350194-0.131234
@@ -444,11 +391,11 @@ y_df.head()
```python -# 70 samples for training data (used to train and fit GRegulNet model) +# 70,000 samples for training data (used to train and fit NetREm model) X_train = dummy_data.view_X_train_df() y_train = dummy_data.view_y_train_df() -# 30 samples for testing data +# 30,000 samples for testing data X_test = dummy_data.view_X_test_df() y_test = dummy_data.view_y_test_df() ``` diff --git a/code/DemoDataBuilderXandY.py b/code/DemoDataBuilderXandY.py index a1a9fe5..bb12db7 100644 --- a/code/DemoDataBuilderXandY.py +++ b/code/DemoDataBuilderXandY.py @@ -884,13 +884,12 @@ def view_train_vs_test_data_for_predictor(self, predictor_name): def generate_dummy_data(corrVals, - num_samples_M = 100, + num_samples_M = 10000, train_data_percent = 70, mu = 0, std_dev = 1, iters_to_generate_X = 100, orthogonal_X = False, - ortho_scalar = 10, view_input_corrs_plot = False, verbose = True, rand_seed_x = 123, rand_seed_y = 2023): diff --git a/code/Netrem_model_builder.py b/code/Netrem_model_builder.py index 761023f..1e13f6d 100644 --- a/code/Netrem_model_builder.py +++ b/code/Netrem_model_builder.py @@ -178,9 +178,14 @@ def updating_network_and_X_during_fitting(self, X, y): self.old_y = y y = self.center_y_data(y) - gene_expression_nodes = X_df.columns.tolist() # these are already sorted - #gene_expression_nodes = sorted(X_df.columns.tolist()) # these will be sorted - ppi_net_nodes = set(self.network_nodes_list) + #gene_expression_nodes = X_df.columns.tolist() # these are already sorted + tg_name = y.columns.tolist()[0] + if tg_name in X_df.columns.tolist(): + X_df = X_df.drop(columns = [tg_name]) + + #gene_expression_nodes = list(set(X_df.columns.tolist()) - tg_name) # these are already sorted + gene_expression_nodes = sorted(X_df.columns.tolist()) # these will be sorted + ppi_net_nodes = set(self.network_nodes_list) # set(self.network_nodes_list) - tg_name common_nodes = list(ppi_net_nodes.intersection(gene_expression_nodes)) if not common_nodes: # may be possible that the X dataframe needs to be transposed if provided incorrectly @@ -191,6 +196,7 @@ def updating_network_and_X_during_fitting(self, X, y): self.gene_expression_nodes = gene_expression_nodes self.common_nodes = sorted(common_nodes) + gene_expression_nodes = sorted(gene_expression_nodes) # 10/22 self.final_nodes = gene_expression_nodes if self.overlapped_nodes_only: self.final_nodes = common_nodes @@ -198,7 +204,7 @@ def updating_network_and_X_during_fitting(self, X, y): self.final_nodes = self.prior_network.final_nodes else: self.final_nodes = gene_expression_nodes - + self.final_nodes = sorted(self.final_nodes) # 10/22 final_nodes_set = set(self.final_nodes) ppi_nodes_to_remove = list(ppi_net_nodes - final_nodes_set) self.gexpr_nodes_added = list(set(gene_expression_nodes) - final_nodes_set) @@ -231,6 +237,7 @@ def updating_network_and_X_during_fitting(self, X, y): self.y_train = self.preprocess_y_df(y) return self + def organize_B_interaction_list(self): # TF-TF interactions to output :) self.B_train = self.compute_B_matrix(self.X_train) self.B_interaction_df = pd.DataFrame(self.B_train, index = self.final_nodes, columns = self.final_nodes) @@ -370,6 +377,7 @@ def view_W_network(self): labels = {e: G.edges[e]['weight'] for e in G.edges} return nx.draw_networkx_edge_labels(G, pos, edge_labels=labels, ax=ax) + def compute_B_matrix_times_M(self, X): """ M is N_sample, because ||y - Xc||^2 need to be normalized by 1/n_sample, but not the 2 * beta_L2 * c'Ac term see https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html @@ -412,6 +420,7 @@ def compute_X_tilde_y_tilde(self, B, X, y): y_tilde *= scale return X_tilde, y_tilde + def predict_y_from_y_tilda(self, X, X_tilda, pred_y_tilda): X = self.preprocess_X_df(X) @@ -550,57 +559,6 @@ def score(self, X, y, zero_coef_penalty=10): else: return -nmse_ - - -# def score(self, X, y, zero_coef_penalty=10): -# print("Debug: Start of score function") - -# if isinstance(X, pd.DataFrame): -# X = self.preprocess_X_df(X) -# print(f"Debug: preprocessed X, nulls: {X.isnull().sum().sum()}") - -# if isinstance(y, pd.DataFrame): -# y = self.preprocess_y_df(y) -# print(f"Debug: preprocessed y, nulls: {y.isnull().sum().sum()}") - -# y_pred = self.predict(X) -# print(f"Debug: y_pred, nulls: {np.isnan(y_pred).sum()}, infs: {np.isinf(y_pred).sum()}") - -# y_pred[y_pred == 0] = 1e-10 -# nmse_ = (y - y_pred)**2 - -# nmse_[y_pred == 1e-10] *= zero_coef_penalty -# denominator = (y**2).mean() - -# print(f"Debug: Denominator: {denominator}") - -# if denominator == 0: -# print("Debug: Denominator is zero.") -# return -1e10 # Some large negative value - -# nmse_ = nmse_.mean() / denominator - -# if nmse_ == 0: -# print("Debug: nmse_ is zero.") -# return -1e10 # Some large negative value - -# print(f"Debug: Returning score: {-nmse_}") -# return -nmse_ - - -# def score(self, X, y, zero_coef_penalty=10): -# if isinstance(X, pd.DataFrame): -# X = self.preprocess_X_df(X) # X_test -# if isinstance(y, pd.DataFrame): -# y = self.preprocess_y_df(y) -# # Make predictions using the predict method of your custom estimator -# y_pred = self.predict(X) -# # Calculate the normalized mean squared error between the true and predicted values -# nmse_ = (y - y_pred)**2 -# nmse_[y_pred==0] *= zero_coef_penalty -# nmse_ = nmse_.mean() / (y**2).mean() -# return -nmse_ # Return the negative normalized mean squared error - def updating_network_A_matrix_given_X(self) -> np.ndarray: """ When we call the fit method, this function is used to help us update the network information. @@ -692,7 +650,6 @@ def updating_network_A_matrix_given_X(self) -> np.ndarray: self.tf_names_list = self.nodes return self - def preprocess_X_df(self, X): if isinstance(X, pd.DataFrame): X_df = X @@ -708,19 +665,7 @@ def preprocess_X_df(self, X): X_df = X_df.reindex(columns=gene_names_list)# Reorder columns of dataframe to match order in `column_order` X = np.array(X_df.values.tolist()) return X -# def preprocess_X_df(self, X): -# if isinstance(X, pd.DataFrame): -# column_names_list = X.columns.tolist() -# overlap_num = len(set(column_names_list).intersection(self.final_nodes)) - -# if overlap_num == 0: -# print("Please note: we are flipping X dataframe around so that the rows are samples and the columns are gene/TF names :)") -# X = X.transpose() - -# gene_names_list = self.final_nodes # so that this matches the order of columns in A matrix as well -# X = X[gene_names_list] - -# return X.values + def preprocess_y_df(self, y): if isinstance(y, pd.DataFrame): @@ -835,18 +780,51 @@ def netrem(edge_list, beta_net = 1, alpha_lasso = 0.01, default_edge_weight = 0. return greggy - - -def generate_beta_networks(X_train, y_train, standardize_X, prior_network, overlapped_nodes_only = False, num = 10, max_beta = 200): - """ - Generate a grid of beta_network values to transform X_train. - - Parameters: - X_train (numpy array): training input data - - Returns: - numpy array: grid of beta_network values - """ +def netremCV(edge_list, X, y, + num_beta: int = 10, + extra_beta_list = [0.25, 0.5, 0.75, 1], # additional beta to try out + num_alpha: int = 10, + max_beta: float = 200, # max_beta used to help prevent explosion of beta_net values + reduced_cv_search: bool = False, # should we do a reduced search (Randomized Search) or a GridSearch? + default_edge_weight: float = 0.1, + degree_threshold: float = 0.5, + gene_expression_nodes = [], + overlapped_nodes_only: bool = False, + standardize_X: bool = True, + center_y: bool = True, + y_intercept: bool = False, + model_type = "Lasso", + lasso_selection = "cyclic", + all_pos_coefs: bool = False, + tolerance: float = 1e-4, + maxit: int = 10000, + num_jobs: int = -1, + num_cv_folds: int = 5, + lassocv_eps: float = 1e-3, + lassocv_n_alphas: int = 100, # default in sklearn + lassocv_alphas = None, # default in sklearn + verbose = False, + searchVerbosity: int = 2, + show_warnings: bool = False): + + X_train = X + y_train = y + if show_warnings == False: + warnings.filterwarnings('ignore') + prior_graph_dict = {"edge_list": edge_list, + "gene_expression_nodes":gene_expression_nodes, + "edge_values_for_degree": False, + "consider_self_loops":False, + "pseudocount_for_degree":1e-3, + "default_edge_weight": default_edge_weight, + "w_transform_for_d":"none", + "threshold_for_degree": degree_threshold, + "verbose":verbose, + "view_network":False} + + prior_network = graph.PriorGraphNetwork(**prior_graph_dict) + + # generate the beta grid: if isinstance(X_train, pd.DataFrame): X_df = X_train gene_names_list = list(X_df.columns) @@ -860,267 +838,172 @@ def generate_beta_networks(X_train, y_train, standardize_X, prior_network, overl X_df = X_df.reindex(columns=common_nodes) else: X_df = X_df.reindex(columns=gene_names_list) - + + X_train_np = X_df.copy() + y_train_np = y_train.copy() if standardize_X: - print("standardizing X :)") + if verbose: + print("standardizing X :)") scaler = preprocessing.StandardScaler().fit(X_df) - X_train = scaler.transform(X_df) + X_train_np = scaler.transform(X_df) else: - X_train = np.array(X_df.values.tolist()) + X_train_np = np.array(X_df.values.tolist()) if isinstance(y_train, pd.DataFrame): - y_train = y_train.values.flatten() - beta_max = 0.5 * np.max(np.abs(X_train.T.dot(y_train))) + y_train_np = y_train_np.values.flatten() + beta_max = 0.5 * np.max(np.abs(X_train_np.T.dot(y_train_np))) beta_min = 0.01 * beta_max - - var_X = np.var(X_train) - var_y = np.var(y_train) + + var_X = np.var(X_train_np) + var_y = np.var(y_train_np) if beta_max > max_beta: # max_beta used to prevent explosion of beta_net values - print(":) using variance to define beta_net values") + if verbose: + print(":) using variance to define beta_net values") beta_max = 0.5 * np.max(np.abs(var_X * var_y)) * 100 beta_min = 0.01 * beta_max - print(f"beta_min = {beta_min} and beta_max = {beta_max}") - - return np.logspace(np.log10(beta_max), np.log10(beta_min), num=num) - - -def generate_alpha_beta_pairs(X_train, - y_train, - prior_network, - overlapped_nodes_only: bool = False, - standardize_X: bool = True, - center_y: bool = True, - num_beta: int = 50, - num_alpha: int = 10, - max_beta: float = 200, - y_intercept: bool = False, - maxit: int = 10000, - all_pos_coefs: bool = False, - tolerance = 1e-4, - lasso_selection = "cyclic", - num_cv_folds = 5, - num_jobs = -1, - lassocv_eps = 1e-3, - lassocv_n_alphas = 100, - lassocv_alphas = None) -> dict: - """ - Generate a pairwise set of alpha_lasso and beta_network values. - - Parameters: - X_train (numpy array): training input data - y_train (numpy array): training output data - prior_network: The prior network to be used. - overlapped_nodes_only (bool): Whether to use only overlapped nodes. Default is False. - num (int): The number of beta_network values to generate. Default is 100. - - Returns: - dict: Dictionary containing grid of alpha_lasso values and beta_network values. - """ - beta_grid = generate_beta_networks(X_train, y_train, standardize_X, prior_network, overlapped_nodes_only, num=num_beta, max_beta = max_beta) + if verbose: + print(f"beta_min = {beta_min} and beta_max = {beta_max}") + beta_grid = np.logspace(np.log10(beta_max), np.log10(beta_min), num=num_beta) + if extra_beta_list != None: + if len(extra_beta_list) > 0: + for add_beta in extra_beta_list: # we add additional beta based on user-defined list + beta_grid = np.append(add_beta, beta_grid) + + beta_alpha_grid_dict = {"beta_network_vals": [], "alpha_lasso_vals": []} - + # generating the alpha-values that are corresponding try: with tqdm(beta_grid, desc=":) Generating beta_net and alpha_lasso pairs") as pbar: for beta in pbar: + if verbose: + print("beta_network:", beta) # please fix it so it reflects what we want more... like the proper defaults - netremCV_demo = nm.NetREmModel(beta_network=beta, - model_type="LassoCV", - network=prior_network, - standardize_X = standardize_X, - center_y = center_y, - overlapped_nodes_only=overlapped_nodes_only) -# netremCV_demo = nm.NetREmModel(beta_network=beta, -# model_type="LassoCV", -# network=prior_network, -# overlapped_nodes_only=overlapped_nodes_only, -# standardize_X = standardize_X, -# y_intercept = y_intercept, -# max_lasso_iterations = maxit, -# all_pos_coefs = all_pos_coefs, -# tolerance = tolerance, -# lasso_selection = lasso_selection, -# num_cv_folds = num_cv_folds, -# #num_jobs = num_jobs, -# lassocv_eps = lassocv_eps, -# lassocv_n_alphas = lassocv_n_alphas, -# lassocv_alphas = lassocv_alphas) - + netremCV_demo = NetREmModel(beta_net=beta, + model_type="LassoCV", + network=prior_network, + overlapped_nodes_only=overlapped_nodes_only, + standardize_X = standardize_X, + center_y = center_y, + y_intercept = y_intercept, + max_lasso_iterations = maxit, + all_pos_coefs = all_pos_coefs, + tolerance = tolerance, + lasso_selection = lasso_selection, + num_cv_folds = num_cv_folds, + #num_jobs = num_jobs, + lassocv_eps = lassocv_eps, + lassocv_n_alphas = lassocv_n_alphas, + lassocv_alphas = lassocv_alphas) + if lassocv_alphas != None: + netremCV_demo.lassocv_alphas = lassocv_alphas + # Fit the model and compute alpha_max and alpha_min netremCV_demo.fit(X_train, y_train) X_tilda_train = netremCV_demo.X_tilda_train y_tilda_train = netremCV_demo.y_tilda_train alpha_max = 0.5 * np.max(np.abs(X_tilda_train.T.dot(y_tilda_train))) alpha_min = 0.01 * alpha_max - + if verbose: + print(f"alpha_min = {alpha_min} and alpha_max = {alpha_max}") + # Generate alpha_grid based on alpha_max and alpha_min optimal_alpha = netremCV_demo.regr.alpha_ - alpha_grid = np.append(optimal_alpha, np.logspace(np.log10(alpha_min), np.log10(alpha_max), num=num_alpha)) - + # take the cross-validation alpha and apply as the best alpha as well for this beta_net + beta_alpha_grid_dict["beta_network_vals"].append(beta) + beta_alpha_grid_dict["alpha_lasso_vals"].append(optimal_alpha) + # we also utilize the other alphas we have constructed dynamically and will find the best alpha among those + alpha_grid = np.logspace(np.log10(alpha_min), np.log10(alpha_max), num=num_alpha) + # Find the best alpha using cross-validation best_alpha = None best_score = float('-inf') for alpha in alpha_grid: - #netremCV_demo.regr.set_params(alpha=alpha) -# netremCV_demo = nm.NetREmModel(beta_network=beta, -# alpha_lasso = alpha, -# model_type="Lasso", -# network=prior_network, -# standardize_X = standardize_X, -# overlapped_nodes_only=overlapped_nodes_only, -# y_intercept = y_intercept, -# max_lasso_iterations = maxit, -# all_pos_coefs = all_pos_coefs, -# tolerance = tolerance, -# lasso_selection = lasso_selection, -# num_cv_folds = num_cv_folds, -# #num_jobs = num_jobs, -# lassocv_eps = lassocv_eps, -# lassocv_n_alphas = lassocv_n_alphas, -# lassocv_alphas = lassocv_alphas) - netremCV_demo = nm.NetREmModel(beta_network=beta, - alpha_lasso = alpha, - standardize_X = standardize_X, - center_y = center_y, - model_type="Lasso", - network=prior_network, - overlapped_nodes_only=overlapped_nodes_only) - scores = cross_val_score(netremCV_demo, X_train, y_train, cv=5) # You can change cv to your specific cross-validation strategy + netremCV_demo = NetREmModel(beta_net=beta, + alpha_lasso = alpha, + model_type="Lasso", + network=prior_network, + standardize_X = standardize_X, + center_y = center_y, + overlapped_nodes_only=overlapped_nodes_only, + y_intercept = y_intercept, + max_lasso_iterations = maxit, + all_pos_coefs = all_pos_coefs, + tolerance = tolerance, + lasso_selection = lasso_selection) + scores = cross_val_score(netremCV_demo, X_train, y_train, cv=num_cv_folds, scoring = "neg_mean_squared_error") # You can change cv to your specific cross-validation strategy mean_score = np.mean(scores) if mean_score > best_score: best_score = mean_score best_alpha = alpha - + # Append the beta and best_alpha to the dictionary beta_alpha_grid_dict["beta_network_vals"].append(beta) beta_alpha_grid_dict["alpha_lasso_vals"].append(best_alpha) - + except Exception as e: print(f"An error occurred: {e}") - print("finished generate_alpha_beta_pairs") - print(beta_alpha_grid_dict) - return beta_alpha_grid_dict - - -# Custom scoring function -def custom_mse(y_true, y_pred): - mse = mean_squared_error(y_true, y_pred) - pbar.update(1) # Update the progress bar - return -mse # Negate because GridSearchCV tries to maximize the score - - -def netremCV(edge_list, X, y, - num_beta: int = 50, - num_alpha: int = 10, - max_beta: float = 200, # max_beta used to help prevent explosion of beta_net values - reduced_cv_search: bool = False, # should we do a reduced search (Randomized Search) or a GridSearch? - default_edge_weight: float = 0.1, - degree_threshold: float = 0.5, - gene_expression_nodes = [], - overlapped_nodes_only: bool = False, - standardize_X: bool = True, - center_y: bool = True, - y_intercept: bool = False, - model_type = "Lasso", - lasso_selection = "cyclic", - all_pos_coefs: bool = False, - tolerance: float = 1e-4, - maxit: int = 10000, - num_jobs: int = -1, - num_cv_folds: int = 5, - lassocv_eps: float = 1e-3, - lassocv_n_alphas: int = 100, # default in sklearn - lassocv_alphas = None, # default in sklearn - verbose = False, - searchVerbosity: int = 2): - - prior_graph_dict = {"edge_list": edge_list, - "gene_expression_nodes":gene_expression_nodes, - "edge_values_for_degree": False, - "consider_self_loops":False, - "pseudocount_for_degree":1e-3, - "default_edge_weight": default_edge_weight, - "w_transform_for_d":"none", - "threshold_for_degree": degree_threshold, - "verbose":verbose, - "view_network":False} - - network_to_use = graph.PriorGraphNetwork(**prior_graph_dict) - X_train = X - y_train = y - beta_alpha_grid_dict = generate_alpha_beta_pairs(X_train, - y_train, network_to_use, - overlapped_nodes_only, standardize_X, center_y, - num_beta, num_alpha, - y_intercept, - maxit, - all_pos_coefs, - tolerance, - lasso_selection, - num_cv_folds, - num_jobs, - lassocv_eps, - lassocv_n_alphas, - lassocv_alphas) + if verbose: + print("finished generate_alpha_beta_pairs") + print(beta_alpha_grid_dict) print(f"Length of beta_alpha_grid_dict: {len(beta_alpha_grid_dict['beta_network_vals'])}") - param_grid = [{"alpha_lasso": [alpha_las], "beta_net": [beta_net]} - for alpha_las, beta_net in zip(beta_alpha_grid_dict["alpha_lasso_vals"], - beta_alpha_grid_dict["beta_network_vals"])] - - - + param_grid = [{"alpha_lasso": [alpha_las], "beta_net": [beta_net]} + for alpha_las, beta_net in zip(beta_alpha_grid_dict["alpha_lasso_vals"], + beta_alpha_grid_dict["beta_network_vals"])] + if verbose: print(":) Performing NetREmCV with both beta_network and alpha_lasso as UNKNOWN.") - - initial_greg = nm.NetREmModel(network=network_to_use, - y_intercept = y_intercept, - standardize_X = standardize_X, - center_y = center_y, - max_lasso_iterations=maxit, - all_pos_coefs=all_pos_coefs, - lasso_selection = lasso_selection, - tolerance = tolerance, - view_network=False, - overlapped_nodes_only=overlapped_nodes_only) - - pbar = tqdm(total=len(param_grid)) # Assuming we're trying 9 combinations of parameters - - if reduced_cv_search: - # Run RandomizedSearchCV + initial_greg = NetREmModel(network=prior_network, + y_intercept = y_intercept, + standardize_X = standardize_X, + center_y = center_y, + max_lasso_iterations=maxit, + all_pos_coefs=all_pos_coefs, + lasso_selection = lasso_selection, + tolerance = tolerance, + view_network=False, + overlapped_nodes_only=overlapped_nodes_only) + pbar = tqdm(total=len(param_grid)) # Assuming we're trying 9 combinations of parameters + + if reduced_cv_search: + # Run RandomizedSearchCV + if verbose: print(f":) since reduced_cv_search = {reduced_cv_search}, we perform RandomizedSearchCV on a reduced search space") - grid_search= RandomizedSearchCV(initial_greg, - param_grid, - n_iter=num_alpha, - cv=num_cv_folds, - #scoring=make_scorer(custom_mse, greater_is_better=False), - verbose=searchVerbosity) - else: - # Run GridSearchCV - grid_search = GridSearchCV(initial_greg, param_grid=param_grid, cv=num_cv_folds, - #scoring=make_scorer(custom_mse, greater_is_better=False), - verbose = searchVerbosity) - grid_search.fit(X_train, y_train) - - # Extract and display the best hyperparameters - best_params = grid_search.best_params_ - optimal_alpha = best_params["alpha_lasso"] - optimal_beta = best_params["beta_net"] - print(f":) NetREmCV found that the optimal alpha_lasso = {optimal_alpha} and optimal beta_net = {optimal_beta}") - - newest_netrem = nm.NetREmModel(alpha_lasso = optimal_alpha, - beta_net = optimal_beta, - network = network_to_use, - y_intercept = y_intercept, - standardize_X = standardize_X, - center_y = center_y, - max_lasso_iterations=maxit, - all_pos_coefs=all_pos_coefs, - lasso_selection = lasso_selection, - tolerance = tolerance, - view_network=False, - overlapped_nodes_only=overlapped_nodes_only) - newest_netrem.fit(X_train, y_train) - train_mse = newest_netrem.test_mse(X_train, y_train) - print(f":) Please note that the training Mean Square Error (MSE) from this fitted NetREm model is {train_mse}") - return newest_netrem + grid_search= RandomizedSearchCV(initial_greg, + param_grid, + n_iter=num_alpha, + cv=num_cv_folds, + scoring = "neg_mean_squared_error", + #scoring=make_scorer(custom_mse, greater_is_better=False), + verbose=searchVerbosity) + else: + # Run GridSearchCV + grid_search = GridSearchCV(initial_greg, param_grid=param_grid, cv=num_cv_folds, + scoring = "neg_mean_squared_error", + #scoring=make_scorer(custom_mse, greater_is_better=False), + verbose = searchVerbosity) + grid_search.fit(X_train, y_train) + + # Extract and display the best hyperparameters + best_params = grid_search.best_params_ + optimal_alpha = best_params["alpha_lasso"] + optimal_beta = best_params["beta_net"] + print(f":) NetREmCV found that the optimal alpha_lasso = {optimal_alpha} and optimal beta_net = {optimal_beta}") + + newest_netrem = NetREmModel(alpha_lasso = optimal_alpha, + beta_net = optimal_beta, + network = prior_network, + y_intercept = y_intercept, + standardize_X = standardize_X, + center_y = center_y, + max_lasso_iterations=maxit, + all_pos_coefs=all_pos_coefs, + lasso_selection = lasso_selection, + tolerance = tolerance, + view_network=False, + overlapped_nodes_only=overlapped_nodes_only) + newest_netrem.fit(X_train, y_train) + train_mse = newest_netrem.test_mse(X_train, y_train) + print(f":) Please note that the training Mean Square Error (MSE) from this fitted NetREm model is {train_mse}") + return newest_netrem def organize_B_interaction_network(netrem_model): @@ -1143,7 +1026,7 @@ def organize_B_interaction_network(netrem_model): B_interaction_df["X_standardized"] = netrem_model.standardize_X B_interaction_df["gene_data"] = "training gene expression data" - # Step 1: Sort the DataFrame + # Step 1: Please Sort the DataFrame B_interaction_df = B_interaction_df.sort_values('absVal_B', ascending=False) # Step 2: Get the rank diff --git a/code/__pycache__/DemoDataBuilderXandY.cpython-310.pyc b/code/__pycache__/DemoDataBuilderXandY.cpython-310.pyc index 2488c24..bfd02c9 100644 Binary files a/code/__pycache__/DemoDataBuilderXandY.cpython-310.pyc and b/code/__pycache__/DemoDataBuilderXandY.cpython-310.pyc differ diff --git a/code/__pycache__/Netrem_model_builder.cpython-310.pyc b/code/__pycache__/Netrem_model_builder.cpython-310.pyc index 884519f..2df8416 100644 Binary files a/code/__pycache__/Netrem_model_builder.cpython-310.pyc and b/code/__pycache__/Netrem_model_builder.cpython-310.pyc differ diff --git a/code/old_code/refresh/DemoDataBuilderXandY.py b/code/old_code/refresh/DemoDataBuilderXandY.py new file mode 100644 index 0000000..a1a9fe5 --- /dev/null +++ b/code/old_code/refresh/DemoDataBuilderXandY.py @@ -0,0 +1,919 @@ +# DemoDataBuilder Class: :) +from packages_needed import * +import pandas as pd +import numpy as np +from tqdm.auto import tqdm +import numpy as np +from sklearn.model_selection import train_test_split +import plotly.express as px +class DemoDataBuilderXandY: + """:) Please note that this class focuses on building Y data based on a normal distribution (specified mean + and standard deviation). M is the # of samples we want to generate. Thus, Y is a vector with M elements. + Then, this class returns X for a set of N predictors (each with M # of samples) based on a list of N correlation + values. For instance, if N = 5 predictors (the Transcription Factors (TFs)), we have [X1, X2, X3, X4, X5], + and a respective list of correlation values: [cor(X1, Y), cor(X2, Y), cor(X3, Y), cor(X4, Y), cor(X5, Y)]. + Then, this class will generate X, a matrix of those 5 predictors (based on similar distribution as Y) + with these respective correlations.""" + + _parameter_constraints = { + "test_data_percent": (0, 100), + "mu": (0, None), + "std_dev": (0, None), + "num_iters_to_generate_X": (1, None), + "same_train_test_data": [False, True], + "rng_seed": (0, None), + "randSeed": (0, None), + "ortho_scalar": (1, None), + "orthogonal_X_bool": [True, False], + "view_input_correlations_plot": [False, True], + "num_samples_M": (1, None), + "corrVals": list + } + + def __init__(self, **kwargs): + + # define default values for constants + self.same_train_test_data = False + self.test_data_percent = 30 + self.mu = 0 + self.verbose = True + self.std_dev = 1 + self.num_iters_to_generate_X = 100 + self.rng_seed = 2023 # for Y + self.randSeed = 123 # for X + self.orthogonal_X_bool = True # False adjustment made on 9/20 + self.ortho_scalar = 10 + self.tol = 1e-2 + self.view_input_correlations_plot = False + # reading in user inputs + self.__dict__.update(kwargs) + ##################### other user parameters being loaded and checked + self.same_train_and_test_data_bool = self.same_train_test_data + # check that all required keys are present: + required_keys = ["corrVals", "num_samples_M"] + missing_keys = [key for key in required_keys if key not in self.__dict__] + if missing_keys: + raise ValueError(f":( Please note ye are missing information for these keys: {missing_keys}") + self.M = self.num_samples_M + self.N = self.get_N() + self.y = self.generate_Y() + self.X = self.generate_X() + self.same_train_and_test_data_bool = self.same_train_test_data + if self.same_train_and_test_data_bool: + self.testing_size = 1 + else: + self.testing_size = (self.test_data_percent/100.0) + self.data_sets = self.generate_training_and_testing_data() # [X_train, X_test, y_train, y_test] + self.X_train = self.data_sets[0] + self.X_test = self.data_sets[1] + self.y_train = self.data_sets[2] + self.y_test = self.data_sets[3] + + self.tf_names_list = self.get_tf_names_list() + self.corr_df = self.return_correlations_dataframe() + self.combined_correlations_df = self.get_combined_correlations_df() + if self.view_input_correlations_plot: + self.view_input_correlations = self.view_input_correlations() + self._apply_parameter_constraints() + self.X_train_df = self.view_X_train_df() + self.y_train_df = self.view_y_train_df() + self.X_test_df = self.view_X_test_df() + self.y_test_df = self.view_y_test_df() + self.X_df = self.view_original_X_df() + self.y_df = self.view_original_y_df() + self.combined_train_test_x_and_y_df = self.combine_X_and_y_train_and_test_data() + + def _apply_parameter_constraints(self): + constraints = {**DemoDataBuilderXandY._parameter_constraints} + for key, value in self.__dict__.items(): + if key in constraints: + if isinstance(constraints[key], tuple): + if isinstance(constraints[key][0], type) and not isinstance(value, constraints[key][0]): + setattr(self, key, constraints[key][0]) + elif constraints[key][1] is not None and isinstance(constraints[key][1], type) and not isinstance(value, constraints[key][1]): + setattr(self, key, constraints[key][1]) + elif key == "corrVals": # special case for corrVals + if not isinstance(value, list): + setattr(self, key, constraints[key]) + elif value not in constraints[key]: + setattr(self, key, constraints[key][0]) + return self + + def get_tf_names_list(self): + tf_names_list = [] + for i in range(0, self.N): + term = "TF" + str(i+1) + tf_names_list.append(term) + return tf_names_list + + # getter method + def get_N(self): + N = len(self.corrVals) + return N + + def get_X_train(self): + return self.data_sets[0] #X_train + + def get_y_train(self): + return self.data_sets[2] # y_train + + def get_X_test(self): + return self.data_sets[1] + + def get_y_test(self): + return self.data_sets[3] + + def view_original_X_df(self): + import pandas as pd + X_df = pd.DataFrame(self.X, columns = self.tf_names_list) + return X_df + + def view_original_y_df(self): + import pandas as pd + y_df = pd.DataFrame(self.y, columns = ["y"]) + return y_df + + def view_X_train_df(self): + import pandas as pd + X_train_df = pd.DataFrame(self.X_train, columns = self.tf_names_list) + return X_train_df + + def view_y_train_df(self): + import pandas as pd + y_train_df = pd.DataFrame(self.y_train, columns = ["y"]) + return y_train_df + + def view_X_test_df(self): + X_test_df = pd.DataFrame(self.X_test, columns = self.tf_names_list) + return X_test_df + + def view_y_test_df(self): + y_test_df = pd.DataFrame(self.y_test, columns = ["y"]) + return y_test_df + + def combine_X_and_y_train_and_test_data(self): + X_p1 = self.X_train_df + X_p1["info"] = "training" + X_p2 = self.X_test_df + X_p2["info"] = "testing" + X_combined = pd.concat([X_p1, X_p2]).drop_duplicates() + y_p1 = self.y_train_df + y_p1["info"] = "training" + y_p2 = self.y_test_df + y_p2["info"] = "testing" + y_combined = pd.concat([y_p1, y_p2]).drop_duplicates() + combining_df = X_combined + combining_df["y"] = y_combined["y"] + return combining_df + + def return_correlations_dataframe(self): + corr_info = ["expected_correlations"] * self.N + corr_df = pd.DataFrame(corr_info, columns = ["info"]) + corr_df["TF"] = self.tf_names_list + corr_df["value"] = self.corrVals + corr_df["data"] = "correlations" + return corr_df + + def generate_Y(self): + seed_val = self.rng_seed + rng = np.random.default_rng(seed=seed_val) + y = rng.normal(self.mu, self.std_dev, self.M) + return y + + # Check if Q is orthogonal using the is_orthogonal function + def is_orthogonal(matrix): + """ + Checks if a given matrix is orthogonal. + Parameters: + matrix (numpy.ndarray): The matrix to check + Returns: + bool: True if the matrix is orthogonal, False otherwise. + """ + # Compute the transpose of the matrix + matrix_T = matrix.T + + # Compute the product of the matrix and its transpose + matrix_matrix_T = np.dot(matrix, matrix_T) + + # Check if the product is equal to the identity matrix + return np.allclose(matrix_matrix_T, np.eye(matrix.shape[0])) + +# # Define the modified generate_X function +# def generate_X(self): +# """Generates a design matrix X with the given correlations while introducing noise and dependencies. +# Parameters: +# orthogonal (bool): Whether to generate an orthogonal matrix (default=False). + +# Returns: +# numpy.ndarray: The design matrix X. +# """ +# orthogonal = self.orthogonal_X_bool +# scalar = self.ortho_scalar +# np.random.seed(self.randSeed) +# y = self.y +# n = len(y) +# numTFs = self.N # len(corrVals) +# numIterations = self.num_iters_to_generate_X +# correlations = self.corrVals +# corrVals = [correlations[0]] + correlations + +# # Step 1: Generate Initial X +# e = np.random.normal(0, 1, (n, numTFs + 1)) +# X = np.copy(e) +# X[:, 0] = y * np.sqrt(1.0 - corrVals[0]**2) / np.sqrt(1.0 - np.corrcoef(y, X[:,0])[0,1]**2) +# for j in range(numIterations): +# for i in range(1, numTFs + 1): +# corr = np.corrcoef(y, X[:, i])[0, 1] +# X[:, i] = X[:, i] + (corrVals[i] - corr) * y + +# # Step 2: Add Noise +# noise_scale = 0.1 # You can adjust this value +# X += np.random.normal(0, noise_scale, X.shape) + +# # Step 3: Introduce Inter-dependencies +# # Make the second predictor a combination of the first and third predictors +# X[:, 1] += 0.3 * X[:, 0] + 0.7 * X[:, 2] + +# # Step 4: Adjust for Correlations +# for j in range(numIterations): +# for i in range(1, numTFs + 1): +# corr = np.corrcoef(y, X[:, i])[0, 1] +# X[:, i] = X[:, i] + (corrVals[i] - corr) * y + +# if orthogonal: +# # Compute the QR decomposition of X and take only the Q matrix +# Q = np.linalg.qr(X)[0] +# Q = scalar * Q +# return Q[:, 1:] +# else: +# # Return the X matrix without orthogonalization +# return X[:, 1:] + +# # # Display the modified function to ensure it looks okay +# # print(generate_X_modified) + +# def generate_X(self): +# """Generates a design matrix X with the given correlations and introduces an interaction term. + +# Returns: +# numpy.ndarray: The design matrix X. +# """ +# np.random.seed(self.randSeed) +# y = self.y +# n = len(y) +# numTFs = self.N # Number of predictors +# numIterations = self.num_iters_to_generate_X +# corrVals = self.corrVals + +# # Step 1: Generate Initial X based on the specified correlations with Y +# e = np.random.normal(0, 1, (n, numTFs)) +# X = np.copy(e) +# for j in range(numIterations): +# for i in range(numTFs): +# corr = np.corrcoef(y, X[:, i])[0, 1] +# X[:, i] = X[:, i] + (corrVals[i] - corr) * y + +# # Step 2: Introduce Interaction Term into Y +# interaction_term = X[:, 3] * X[:, 4] +# self.y = y + 0.5 * interaction_term # Adjust the coefficient as needed + +# # Step 3: Re-adjust for specified correlations with Y +# for j in range(numIterations): +# for i in range(numTFs): +# corr = np.corrcoef(self.y, X[:, i])[0, 1] +# X[:, i] = X[:, i] + (corrVals[i] - corr) * self.y + +# return X + + + + # Define the modified generate_X function to highlight the benefits of network-regularized regression +# def generate_X(self): +# """Generates a design matrix X to highlight the benefits of network-regularized regression. + +# Returns: +# numpy.ndarray: The design matrix X. +# """ +# np.random.seed(self.randSeed) +# n = len(self.y) +# numTFs = self.N # Number of predictors +# numIterations = self.num_iters_to_generate_X +# corrVals = self.corrVals + +# # Step 1: Generate Initial X based on the specified correlations with Y +# e = np.random.normal(0, 1, (n, numTFs)) +# X = np.copy(e) +# for j in range(numIterations): +# for i in range(numTFs): +# corr = np.corrcoef(self.y, X[:, i])[0, 1] +# X[:, i] = X[:, i] + (corrVals[i] - corr) * self.y + +# # Step 2: Weaken X2 and X4 as predictors by introducing interactions in Y +# interaction_term = 0.3 * (X[:, 0] * X[:, 1]) + 0.3 * (X[:, 3] * X[:, 4]) # Interaction terms +# self.y = self.y + interaction_term # Update Y + +# # Step 3: Strengthen network edges by making X1 and X2, and X4 and X5 highly correlated +# X[:, 1] = 0.7 * X[:, 0] + 0.3 * X[:, 1] # X1 and X2 +# X[:, 3] = 0.7 * X[:, 4] + 0.3 * X[:, 3] # X4 and X5 + +# # Step 4: Re-adjust for specified correlations with Y +# for j in range(numIterations): +# for i in range(numTFs): +# corr = np.corrcoef(self.y, X[:, i])[0, 1] +# X[:, i] = X[:, i] + (corrVals[i] - corr) * self.y + +# return X +# def generate_X(self): +# """Generates a design matrix X with the given correlations and introduces specified network edges and interactions. + +# Returns: +# numpy.ndarray: The design matrix X. +# """ +# np.random.seed(self.randSeed) +# y = self.y +# n = len(y) +# numTFs = self.N # Number of predictors +# numIterations = self.num_iters_to_generate_X +# corrVals = self.corrVals + +# # Step 1: Generate Initial X based on the specified correlations with Y +# e = np.random.normal(0, 1, (n, numTFs)) +# X = np.copy(e) +# for j in range(numIterations): +# for i in range(numTFs): +# corr = np.corrcoef(y, X[:, i])[0, 1] +# X[:, i] = X[:, i] + (corrVals[i] - corr) * y + +# # Step 2: Weaken X2 and X4 as predictors by introducing interactions in Y +# self.y = y + 0.3 * (X[:, 1] * X[:, 0]) + 0.3 * (X[:, 3] * X[:, 4]) # Adjust the coefficients as needed + +# # Step 3: Strengthen network edges by making X1 and X2, and X4 and X5 highly correlated +# X[:, 1] = 0.7 * X[:, 0] + 0.3 * X[:, 1] # X1 and X2 +# X[:, 3] = 0.7 * X[:, 4] + 0.3 * X[:, 3] # X4 and X5 + +# # Step 4: Re-adjust for specified correlations with Y +# for j in range(numIterations): +# for i in range(numTFs): +# corr = np.corrcoef(self.y, X[:, i])[0, 1] +# X[:, i] = X[:, i] + (corrVals[i] - corr) * self.y + +# return X +# def generate_X(self): +# """Generates a design matrix X with given correlations and introduces inter-predictor correlations. + +# Returns: +# numpy.ndarray: The design matrix X. +# """ +# np.random.seed(self.randSeed) +# y = self.y +# n = len(y) +# numTFs = self.N # Number of predictors +# numIterations = self.num_iters_to_generate_X +# corrVals = self.corrVals + +# # Step 1: Generate Initial X based on the specified correlations with Y +# e = np.random.normal(0, 1, (n, numTFs)) +# X = np.copy(e) +# for j in range(numIterations): +# for i in range(numTFs): +# corr = np.corrcoef(y, X[:, i])[0, 1] +# X[:, i] = X[:, i] + (corrVals[i] - corr) * y + +# # Step 2: Introduce Inter-predictor Correlations +# # Make X1 and X2 highly correlated +# X[:, 0] = 0.5 * X[:, 0] + 0.5 * X[:, 1] +# # Make X4 and X5 highly correlated +# X[:, 3] = 0.525 * X[:, 3] + 0.475 * X[:, 4] + +# # Step 3: Re-adjust for specified correlations with Y +# for j in range(numIterations): +# for i in range(numTFs): +# corr = np.corrcoef(y, X[:, i])[0, 1] +# X[:, i] = X[:, i] + (corrVals[i] - corr) * y + +# return X + +# def generate_X(self, tol=1e-4): +# orthogonal = self.orthogonal_X_bool +# scalar = self.ortho_scalar +# np.random.seed(self.randSeed) +# y = self.y +# n = len(y) +# numTFs = self.N + +# # Initialize X with standard normal distribution +# X = np.random.normal(0, 1, (n, numTFs)) + +# for i in range(numTFs): +# desired_corr = self.corrVals[i] + +# while True: +# # Create a new predictor as a linear combination of original predictor and y +# X[:, i] = desired_corr * y + np.sqrt(1 - desired_corr ** 2) * X[:, i] + +# # Standardize the predictor to have mean 0 and variance 1 +# X[:, i] = (X[:, i] - np.mean(X[:, i])) / np.std(X[:, i]) + +# # Calculate the actual correlation +# actual_corr = np.corrcoef(y, X[:, i])[0, 1] + +# # Calculate the difference between the actual and desired correlations +# diff = abs(actual_corr - desired_corr) + +# if diff < tol: +# break + +# # Orthogonalize the predictors to make them independent of each other +# Q, _ = np.linalg.qr(X) + +# if orthogonal: +# # Scale the orthogonalized predictors +# Q = scalar * Q +# return Q +# else: +# # Return the orthogonalized predictors without scaling +# return Q + +# def generate_X(self): +# np.random.seed(self.randSeed) +# y = self.y +# n = len(y) +# numTFs = self.N +# tol = self.tol + +# # Initialize X with standard normal distribution (vectorized) +# X = np.random.normal(0, 1, (n, numTFs)) + +# # Standardize y for correlation calculation +# y_std = (y - np.mean(y)) / np.std(y) + +# for i in tqdm(range(numTFs), desc="Generating predictors"): +# desired_corr = self.corrVals[i] + +# while True: +# # Orthogonalize Xi against all previous predictors +# for j in range(i): +# coef = np.dot(X[:, i], X[:, j]) / np.dot(X[:, j], X[:, j]) +# X[:, i] -= coef * X[:, j] + +# # Create and standardize new predictor (vectorized) +# X[:, i] = desired_corr * y + np.sqrt(1 - desired_corr ** 2) * X[:, i] +# X[:, i] = (X[:, i] - np.mean(X[:, i])) / np.std(X[:, i]) + +# # Calculate actual correlation (vectorized) +# actual_corr = np.dot(y_std, X[:, i]) / n + +# # Check if actual correlation is close enough to desired correlation +# if abs(actual_corr - desired_corr) < tol: +# break + +# # Orthogonalize X to reduce inter-predictor correlation (if required) +# if self.orthogonal_X_bool: +# X, _ = np.linalg.qr(X) + +# return X + + def generate_X(self): + np.random.seed(self.randSeed) + y = self.y + n = len(y) + numTFs = self.N + tol = self.tol + + # Initialize X with standard normal distribution (vectorized) + X = np.random.normal(0, 1, (n, numTFs)) + + # Standardize y for correlation calculation + y_std = (y - np.mean(y)) / np.std(y) + + for i in tqdm(range(numTFs), desc="Generating predictors"): + desired_corr = self.corrVals[i] + + while True: + # Create and standardize new predictor (vectorized) + X[:, i] = desired_corr * y + np.sqrt(1 - desired_corr ** 2) * X[:, i] + X[:, i] = (X[:, i] - np.mean(X[:, i])) / np.std(X[:, i]) + + # Calculate actual correlation (vectorized) + actual_corr = np.dot(y_std, X[:, i]) / n + + # Check if actual correlation is close enough to desired correlation + if abs(actual_corr - desired_corr) < tol: + break + + # Orthogonalize X to reduce inter-predictor correlation (if required) + if self.orthogonal_X_bool: + X, _ = np.linalg.qr(X) + + return X + def generate_X7(self): + orthogonal = self.orthogonal_X_bool + scalar = self.ortho_scalar + np.random.seed(self.randSeed) + y = self.y + n = len(y) + numTFs = self.N + tol = self.tol + + # Initialize X with standard normal distribution + X = np.random.normal(0, 1, (n, numTFs)) + + desc_name = "Generating data for " + str(numTFs) + " Predictors with tolerance of " + str(tol) + " :) " + for i in tqdm(range(numTFs), desc=desc_name): + desired_corr = self.corrVals[i] + + while True: + # Create a new predictor as a linear combination of original predictor and y + X[:, i] = desired_corr * y + np.sqrt(1 - desired_corr ** 2) * X[:, i] + + # Standardize the predictor to have mean 0 and variance 1 + X[:, i] = (X[:, i] - np.mean(X[:, i])) / np.std(X[:, i]) + + # Calculate the actual correlation + actual_corr = np.corrcoef(y, X[:, i])[0, 1] + + # Calculate the difference between the actual and desired correlations + diff = abs(actual_corr - desired_corr) + + if diff < tol: + break + + # Step 2: Orthogonalize the predictors to remove inter-predictor correlation + X_ortho, _ = np.linalg.qr(X) + + # Step 3: Scale each orthogonalized predictor to match the desired correlation with y + for i in tqdm(range(numTFs), desc="Rescaling orthogonalized predictors"): + desired_corr = self.corrVals[i] + + while True: + # Scale the orthogonalized predictor + X_ortho[:, i] = desired_corr * y + np.sqrt(1 - desired_corr ** 2) * X_ortho[:, i] + + # Standardize the predictor + X_ortho[:, i] = (X_ortho[:, i] - np.mean(X_ortho[:, i])) / np.std(X_ortho[:, i]) + + # Calculate the actual correlation + actual_corr = np.corrcoef(y, X_ortho[:, i])[0, 1] + + # Calculate the difference between the actual and desired correlations + diff = abs(actual_corr - desired_corr) + + if diff < tol: + break + + if orthogonal: + # Compute the QR decomposition of X and take only the Q matrix + Q = np.linalg.qr(X_ortho)[0] + Q = scalar * Q + return Q + else: + # Return the X matrix without orthogonalization + return X_ortho + + + def generate_X5(self): + orthogonal = self.orthogonal_X_bool + scalar = self.ortho_scalar + np.random.seed(self.randSeed) + y = self.y + n = len(y) + numTFs = self.N + tol = self.tol + jitter = 0.05 # Noise level to reduce correlation between predictors + + # Initialize X with standard normal distribution + X = np.random.normal(0, 1, (n, numTFs)) + + desc_name = "Generating data for " + str(numTFs) + " Predictors with tolerance of " + str(tol) + " :) " + for i in tqdm(range(numTFs), desc=desc_name): + desired_corr = self.corrVals[i] + + while True: + # Create a new predictor as a linear combination of original predictor and y + X[:, i] = desired_corr * y + np.sqrt(1 - desired_corr ** 2) * X[:, i] + + # Add a small amount of noise to reduce correlation with other predictors + X[:, i] += jitter * np.random.normal(0, 1, n) + + # Standardize the predictor to have mean 0 and variance 1 + X[:, i] = (X[:, i] - np.mean(X[:, i])) / np.std(X[:, i]) + + # Calculate the actual correlation + actual_corr = np.corrcoef(y, X[:, i])[0, 1] + + # Calculate the difference between the actual and desired correlations + diff = abs(actual_corr - desired_corr) + + if diff < tol: + break + + if orthogonal: + # Compute the QR decomposition of X and take only the Q matrix + Q = np.linalg.qr(X)[0] + Q = scalar * Q + return Q + else: + # Return the X matrix without orthogonalization + return X + + def generate_X3(self): + orthogonal = self.orthogonal_X_bool + scalar = self.ortho_scalar + np.random.seed(self.randSeed) + y = self.y + n = len(y) + numTFs = self.N + tol = self.tol + # Initialize X with standard normal distribution + X = np.random.normal(0, 1, (n, numTFs)) + desc_name = "Generating data for " + str(numTFs) + " Predictors with tolerance of " + str(tol) + " :) " + for i in tqdm(range(numTFs), desc=desc_name): + desired_corr = self.corrVals[i] + + while True: + # Create a new predictor as a linear combination of original predictor and y + X[:, i] = desired_corr * y + np.sqrt(1 - desired_corr ** 2) * X[:, i] + + # Standardize the predictor to have mean 0 and variance 1 + X[:, i] = (X[:, i] - np.mean(X[:, i])) / np.std(X[:, i]) + + # Calculate the actual correlation + actual_corr = np.corrcoef(y, X[:, i])[0, 1] + + # Calculate the difference between the actual and desired correlations + diff = abs(actual_corr - desired_corr) + + if diff < tol: + break + + if orthogonal: + # Compute the QR decomposition of X and take only the Q matrix + Q = np.linalg.qr(X)[0] + Q = scalar * Q + return Q + else: + # Return the X matrix without orthogonalization + return X + + # Define the function for generating synthetic data with specific correlations and standard normal predictors + def generate_X1(self): + orthogonal = self.orthogonal_X_bool + scalar = self.ortho_scalar + np.random.seed(self.randSeed) + y = self.y + n = len(y) + numTFs = self.N + + # Initialize X with standard normal distribution + X = np.random.normal(0, 1, (n, numTFs)) + + # Adjust X to achieve the desired correlations with y + for i in range(numTFs): + corr = self.corrVals[i] + # Create a new predictor as a linear combination of original predictor and y + X[:, i] = corr * y + np.sqrt(1 - corr ** 2) * X[:, i] + + # Standardize the predictor to have mean 0 and variance 1 + X[:, i] = (X[:, i] - np.mean(X[:, i])) / np.std(X[:, i]) + + if orthogonal: + # Compute the QR decomposition of X and take only the Q matrix + Q = np.linalg.qr(X)[0] + Q = scalar * Q + return Q + else: + # Return the X matrix without orthogonalization + return X +# def generate_X(self): +# orthogonal = self.orthogonal_X_bool +# scalar = self.ortho_scalar +# np.random.seed(self.randSeed) +# y = self.y +# n = len(y) +# numTFs = self.N +# numIterations = self.num_iters_to_generate_X +# correlations = self.corrVals +# corrVals = [correlations[0]] + correlations + +# # Initialize X with standard normal distribution +# X = np.random.normal(0, 1, (n, numTFs)) + +# for j in range(numIterations): +# for i in range(numTFs): +# corr = np.corrcoef(y, X[:, i])[0, 1] +# X[:, i] = X[:, i] + (corrVals[i] - corr) * y +# # Standardize the predictor +# X[:, i] = (X[:, i] - np.mean(X[:, i])) / np.std(X[:, i]) + +# if orthogonal: +# # Compute the QR decomposition of X and take only the Q matrix +# Q = np.linalg.qr(X)[0] +# Q = scalar * Q +# return Q +# else: +# # Return the X matrix without orthogonalization +# return X + + +# def generate_X(self): +# orthogonal = self.orthogonal_X_bool +# scalar = self.ortho_scalar +# np.random.seed(self.randSeed) +# y = self.y +# n = len(y) +# numTFs = self.N +# tol=self.tol +# # Initialize X with standard normal distribution +# X = np.random.normal(0, 1, (n, numTFs)) +# numIterations = self.num_iters_to_generate_X +# for iter_count in range(numIterations): +# max_diff = 0 # Initialize maximum difference between actual and desired correlations for this iteration +# for i in range(numTFs): +# desired_corr = self.corrVals[i] + +# # Create a new predictor as a linear combination of original predictor and y +# X[:, i] = desired_corr * y + np.sqrt(1 - desired_corr ** 2) * X[:, i] + +# # Standardize the predictor to have mean 0 and variance 1 +# X[:, i] = (X[:, i] - np.mean(X[:, i])) / np.std(X[:, i]) + +# # Calculate the actual correlation +# actual_corr = np.corrcoef(y, X[:, i])[0, 1] + +# # Calculate the difference between the actual and desired correlations +# diff = abs(actual_corr - desired_corr) +# max_diff = max(max_diff, diff) + +# # If the maximum difference between actual and desired correlations is below the tolerance, break the loop +# if max_diff < tol: +# break + +# if orthogonal: +# # Compute the QR decomposition of X and take only the Q matrix +# Q = np.linalg.qr(X)[0] +# Q = scalar * Q +# return Q +# else: +# # Return the X matrix without orthogonalization +# return X + + def generate_X_old(self): + """Generates a design matrix X with the given correlations. + Parameters: + orthogonal (bool): Whether to generate an orthogonal matrix (default=False). + + Returns: + numpy.ndarray: The design matrix X. + """ + orthogonal = self.orthogonal_X_bool + scalar = self.ortho_scalar + np.random.seed(self.randSeed) + y = self.y + n = len(y) + numTFs = self.N # len(corrVals) + numIterations = self.num_iters_to_generate_X + correlations = self.corrVals + corrVals = [correlations[0]] + correlations + e = np.random.normal(0, 1, (n, numTFs + 1)) + X = np.copy(e) + X[:, 0] = y * np.sqrt(1.0 - corrVals[0]**2) / np.sqrt(1.0 - np.corrcoef(y, X[:,0])[0,1]**2) + for j in range(numIterations): + for i in range(1, numTFs + 1): + corr = np.corrcoef(y, X[:, i])[0, 1] + X[:, i] = X[:, i] + (corrVals[i] - corr) * y + + if orthogonal: + # Compute the QR decomposition of X and take only the Q matrix + Q = np.linalg.qr(X)[0] + Q = scalar * Q + return Q[:, 1:] + else: + # Return the X matrix without orthogonalization + return X[:, 1:] + + + def generate_training_and_testing_data(self): + same_train_and_test_data_bool = self.same_train_and_test_data_bool + X = self.X + y = self.y + if same_train_and_test_data_bool == False: # different training and testing datasets + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = self.testing_size) + if self.verbose: + print(f"Please note that since we hold out {self.testing_size * 100.0}% of our {self.M} samples for testing, we have:") + print(f"X_train = {X_train.shape[0]} rows (samples) and {X_train.shape[1]} columns (N = {self.N} predictors) for training.") + print(f"X_test = {X_test.shape[0]} rows (samples) and {X_test.shape[1]} columns (N = {self.N} predictors) for testing.") + print(f"y_train = {y_train.shape[0]} corresponding rows (samples) for training.") + print(f"y_test = {y_test.shape[0]} corresponding rows (samples) for testing.") + else: # training and testing datasets are the same :) + X_train, X_test, y_train, y_test = X, X, y, y + y_train = y + y_test = y_train + X_test = X_train + if self.verbose: + print(f"Please note that since we use the same data for training and for testing :) of our {self.M} samples. Thus, we have:") + print(f"X_train = X_test = {X_train.shape[0]} rows (samples) and {X_train.shape[1]} columns (N = {self.N} predictors) for training and for testing") + print(f"y_train = y_test = {y_train.shape[0]} corresponding rows (samples) for training and for testing.") + return [X_train, X_test, y_train, y_test] + + + def get_combined_correlations_df(self): + combined_correlations_df = self.actual_vs_expected_corrs_DefensiveProgramming_all_groups(self.X, self.y, + self.X_train, + self.y_train, + self.X_test, + self.y_test, + self.corrVals, + self.tf_names_list, + self.same_train_and_test_data_bool) + return combined_correlations_df + + def actual_vs_expected_corrs_DefensiveProgramming_all_groups(self, X, y, X_train, y_train, X_test, y_test, + corrVals, tf_names_list, + same_train_and_test_data_bool): + overall_corrs_df = self.compare_actual_and_expected_correlations_DefensiveProgramming_one_data_group(X, y, corrVals, + tf_names_list, same_train_and_test_data_bool, "Overall") + training_corrs_df = self.compare_actual_and_expected_correlations_DefensiveProgramming_one_data_group(X_train, y_train, corrVals, + tf_names_list, same_train_and_test_data_bool, "Training") + testing_corrs_df = self.compare_actual_and_expected_correlations_DefensiveProgramming_one_data_group(X_test, y_test, corrVals, + tf_names_list, same_train_and_test_data_bool, "Testing") + combined_correlations_df = pd.concat([overall_corrs_df, training_corrs_df, testing_corrs_df]).drop_duplicates() + return combined_correlations_df + + def compare_actual_and_expected_correlations_DefensiveProgramming_one_data_group(self, X_matrix, y, corrVals, + predictor_names_list, + same_train_and_test_data_boolean, + data_type): + # please note that this function by Saniya ensures that the actual and expected correlations are close + # so that the simulation has the x-y correlations we were hoping for in corrVals + updatedDF = pd.DataFrame(X_matrix)#.shape + actualCorrsList = [] + for i in tqdm(range(0, len(corrVals))): + expectedCor = corrVals[i] + actualCor = np.corrcoef(updatedDF[i], y)[0][1] + difference = abs(expectedCor - actualCor) + predictor_name = predictor_names_list[i] + actualCorrsList.append([i, predictor_name, expectedCor, actualCor, difference]) + comparisonDF = pd.DataFrame(actualCorrsList, columns = ["i", "predictor", "expected_corr_with_Y", "actual_corr", "difference"]) + comparisonDF["X_group"] = data_type + num_samples = X_matrix.shape[0] + if same_train_and_test_data_boolean: + comparisonDF["num_samples"] = "same " + str(num_samples) + else: + comparisonDF["num_samples"] = "unique " + str(num_samples) + return comparisonDF + + # Visualizing Functions :) + def view_input_correlations(self): + corr_val_df = pd.DataFrame(self.corrVals, columns = ["correlation"])#.transpose() + corr_val_df.index = self.tf_names_list + corr_val_df["TF"] = self.tf_names_list + fig = px.bar(corr_val_df, x='TF', y='correlation', title = "Input Correlations for Dummy Example", barmode='group') + fig.show() + return fig + + + def view_train_vs_test_data_for_predictor(self, predictor_name): + combined_train_test_x_and_y_df = self.combined_train_test_x_and_y_df + combined_correlations_df = self.combined_correlations_df + print(combined_correlations_df[combined_correlations_df["predictor"] == predictor_name][["predictor", "actual_corr", "X_group", "num_samples"]]) + title_name = title = "Training Versus Testing Data Points for Predictor: " + predictor_name + fig = px.scatter(combined_train_test_x_and_y_df, x=predictor_name, y="y", color = "info", + title = title_name) + #fig.show() + return fig + + +def generate_dummy_data(corrVals, + num_samples_M = 100, + train_data_percent = 70, + mu = 0, + std_dev = 1, + iters_to_generate_X = 100, + orthogonal_X = False, + + ortho_scalar = 10, + view_input_corrs_plot = False, + verbose = True, rand_seed_x = 123, rand_seed_y = 2023): + + # the defaults + same_train_test_data = False + test_data_percent = 100 - train_data_percent + if train_data_percent == 100: # since all of the data is used for training, + # then the training and testing data will be the same :) + same_train_test_data = True + test_data_percent = 100 + print(f":) same_train_test_data = {same_train_test_data}") + demo_dict = { + "test_data_percent": 100 - train_data_percent, + "mu": mu, "std_dev": std_dev, + "num_iters_to_generate_X": iters_to_generate_X, + "same_train_test_data": same_train_test_data, + "rng_seed": rand_seed_y, #2023, # for Y + "randSeed": rand_seed_x, #123, # for X + "ortho_scalar": ortho_scalar, + "orthogonal_X_bool": orthogonal_X, + "view_input_correlations_plot": view_input_corrs_plot, + "num_samples_M": num_samples_M, + "corrVals": corrVals, "verbose":verbose} + dummy_data = DemoDataBuilderXandY(**demo_dict) # + return dummy_data diff --git a/user_guide/Dummy_Data_Demo_Example.ipynb b/code/old_code/refresh/Dummy_Data_Demo_Example.ipynb similarity index 100% rename from user_guide/Dummy_Data_Demo_Example.ipynb rename to code/old_code/refresh/Dummy_Data_Demo_Example.ipynb diff --git a/code/old_code/refresh/NetREm Myelinating Schwann Cells Comprehensive Example.ipynb b/code/old_code/refresh/NetREm Myelinating Schwann Cells Comprehensive Example.ipynb new file mode 100644 index 0000000..df06d8c --- /dev/null +++ b/code/old_code/refresh/NetREm Myelinating Schwann Cells Comprehensive Example.ipynb @@ -0,0 +1,11785 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "bfbc1d90", + "metadata": {}, + "source": [ + "Please note that this example focuses on the raw data utilized for human Myelinating Schwann Cells (mSCs) in the Dorsal Root Ganglion. NetREm is applied for predicting Transcription Factor (TF) to Target Gene (TG) regulatory links (given by coefficient **c*** as well) as for potential TF-TF interactions (given by *B* matrix values).\n", + "😊🤓\n", + "\n", + "This is a Bioinformatics Application🧑‍🔬👩‍🔬👨‍🔬👩🏼‍🔬👨🏼‍🔬🧑🏼‍🔬🧑🏻‍🔬👨🏻‍🔬👩🏻‍🔬🧑🏽‍🔬👨🏽‍🔬👩🏽‍🔬🧑🏾‍🔬👨🏾‍🔬👩🏾‍🔬🧑🏿‍🔬👨🏿‍🔬🧬🧫🔬🧑🏿‍💻👨🏿‍💻👩🏿‍💻👩🏾‍💻👨🏾‍💻🧑🏾‍💻👩🏽‍💻👨🏽‍💻🧑🏽‍💻👩🏼‍💻👨🏼‍💻🧑🏼‍💻👩🏻‍💻👨🏻‍💻🧑🏻‍💻👩‍💻👨‍💻🧑‍💻\n", + "\n", + "#### By: Saniya Khullar, Xiang Huang, Raghu Ramesh, John Svaren, Daifeng Wang\n", + "##### University of Wisconsin - Madison" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "a22d2244", + "metadata": {}, + "outputs": [], + "source": [ + "printdf = lambda *args, **kwargs: print(pd.DataFrame(*args, **kwargs))\n", + "rng_seed = 2023 # random seed for reproducibility\n", + "randSeed = 123\n", + "from packages_needed import *\n", + "import error_metrics as em \n", + "from packages_needed import *\n", + "import Netrem_model_builder as nm\n", + "import DemoDataBuilderXandY as demo\n", + "import PriorGraphNetwork as graph\n", + "import netrem_evaluation_functions as nm_eval\n", + "import essential_functions as ef\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "1c001000", + "metadata": {}, + "source": [ + "![netrem_info.png](../user_guide/pics/netrem_info.png)" + ] + }, + { + "cell_type": "markdown", + "id": "cd4d3d50", + "metadata": {}, + "source": [ + "## Input Datasets for NetREm\n", + "To load in *parquet* files (more effiicnet than csv files) and write them out, please ensure ye have installed `pyarrow` by running `pip install pyarrow` in the *terminal* 🧑‍💻👩‍💻👨‍💻. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "b72f1d89", + "metadata": {}, + "outputs": [], + "source": [ + "# file names (FNs) of input data: 🥸\n", + "# Please note that Saniya deposited these data files here: \n", + "# https://github.com/SaniyaKhullar/NetREm/tree/main/data/myelin_Schwann_Cells \n", + "\n", + "tfs_for_tgs_FN = \"myelin_candidate_TFs_for_TGs.parquet\"\n", + "train_data_FN = \"myelin_training_gene_expression_data.parquet\"\n", + "test_data_FN = \"myelin_testing_gene_expression_data.parquet\"\n", + "ppi_FN = \"ppi_dataframe.parquet\"" + ] + }, + { + "cell_type": "markdown", + "id": "ab0bd6bc", + "metadata": {}, + "source": [ + "These raw data files for this tutorial are available here: https://github.com/SaniyaKhullar/NetREm/tree/main/data/myelin_Schwann_Cells" + ] + }, + { + "cell_type": "markdown", + "id": "df73cba1", + "metadata": {}, + "source": [ + "A list of potential candidate TFs for each given target gene (TG). Please note that we constructed this input list of candidate TFs for the respective TGs using various data sources such as motif binding analysis, colocalization of TFs, molecular function, etc." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2e455973", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TGTF
0A1BGCREB3L2
1A1BGCTCF
2A1BGELF2
3A1BGGTF3C2
4A1BGIRF3
.........
635390ZZZ3BACH1
635391ZZZ3TCF3
635392ZZZ3ERF
635393ZZZ3ZNF281
635394ZZZ3SMAD4
\n", + "

1784242 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " TG TF\n", + "0 A1BG CREB3L2\n", + "1 A1BG CTCF\n", + "2 A1BG ELF2\n", + "3 A1BG GTF3C2\n", + "4 A1BG IRF3\n", + "... ... ...\n", + "635390 ZZZ3 BACH1\n", + "635391 ZZZ3 TCF3\n", + "635392 ZZZ3 ERF\n", + "635393 ZZZ3 ZNF281\n", + "635394 ZZZ3 SMAD4\n", + "\n", + "[1784242 rows x 2 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# list of potential candidate TFs for each given target gene (TG)\n", + "tfs_for_tgs_final_df = pd.read_parquet(tfs_for_tgs_FN)\n", + "tfs_for_tgs_final_df" + ] + }, + { + "cell_type": "markdown", + "id": "dc117b82", + "metadata": {}, + "source": [ + "Single-cell gene expression data that is cell samples by genes:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "dc406d0c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Unnamed: 0SAMD11NOC2LKLHL17PLEKHN1PERM1HES4ISG15AGRNC1orf159...STK26RTL8BRTL8CRTL8ASMIM10L2BSMIM10L2AINTS6LADGRG4PNMA6ACCNQ
0ATCGCCTAGTAGATCA-1_10.00.00.0001.2325990.00.00.795283...000.0000000000.0000.0
1ATGAGGGCATGGGAAC-1_40.00.00.0000.0000000.00.00.000000...000.0000000000.0000.0
2GGGACCTCAGACAAAT-1_30.00.00.0000.0000000.00.00.000000...000.0000000000.0000.0
3CGATGGCCAGATCCTA-1_50.00.00.0000.0000000.00.00.000000...002.5178990000.0000.0
4AATCGACGTGGCACTC-1_50.00.00.0000.0000000.00.00.000000...000.0000000000.0000.0
..................................................................
218GGGAAGTAGCTTAAGA-1_20.00.00.0000.0000000.00.02.360130...000.0000000000.0000.0
219GGAACCCGTCACTTCC-1_40.00.00.0000.0000000.00.00.000000...000.0000000000.0000.0
220CGGGTCACAAACGGCA-1_20.00.00.0000.0000000.00.00.000000...000.0000000000.0000.0
221CACCAAACATAGAATG-1_10.00.00.0001.2676930.00.00.822562...000.0000000000.0000.0
222TGCAGGCCACAGTGAG-1_20.00.00.0000.0000000.00.00.000000...000.0000000000.0000.0
\n", + "

223 rows × 17049 columns

\n", + "
" + ], + "text/plain": [ + " Unnamed: 0 SAMD11 NOC2L KLHL17 PLEKHN1 PERM1 HES4 \\\n", + "0 ATCGCCTAGTAGATCA-1_1 0.0 0.0 0.0 0 0 1.232599 \n", + "1 ATGAGGGCATGGGAAC-1_4 0.0 0.0 0.0 0 0 0.000000 \n", + "2 GGGACCTCAGACAAAT-1_3 0.0 0.0 0.0 0 0 0.000000 \n", + "3 CGATGGCCAGATCCTA-1_5 0.0 0.0 0.0 0 0 0.000000 \n", + "4 AATCGACGTGGCACTC-1_5 0.0 0.0 0.0 0 0 0.000000 \n", + ".. ... ... ... ... ... ... ... \n", + "218 GGGAAGTAGCTTAAGA-1_2 0.0 0.0 0.0 0 0 0.000000 \n", + "219 GGAACCCGTCACTTCC-1_4 0.0 0.0 0.0 0 0 0.000000 \n", + "220 CGGGTCACAAACGGCA-1_2 0.0 0.0 0.0 0 0 0.000000 \n", + "221 CACCAAACATAGAATG-1_1 0.0 0.0 0.0 0 0 1.267693 \n", + "222 TGCAGGCCACAGTGAG-1_2 0.0 0.0 0.0 0 0 0.000000 \n", + "\n", + " ISG15 AGRN C1orf159 ... STK26 RTL8B RTL8C RTL8A SMIM10L2B \\\n", + "0 0.0 0.0 0.795283 ... 0 0 0.000000 0 0 \n", + "1 0.0 0.0 0.000000 ... 0 0 0.000000 0 0 \n", + "2 0.0 0.0 0.000000 ... 0 0 0.000000 0 0 \n", + "3 0.0 0.0 0.000000 ... 0 0 2.517899 0 0 \n", + "4 0.0 0.0 0.000000 ... 0 0 0.000000 0 0 \n", + ".. ... ... ... ... ... ... ... ... ... \n", + "218 0.0 0.0 2.360130 ... 0 0 0.000000 0 0 \n", + "219 0.0 0.0 0.000000 ... 0 0 0.000000 0 0 \n", + "220 0.0 0.0 0.000000 ... 0 0 0.000000 0 0 \n", + "221 0.0 0.0 0.822562 ... 0 0 0.000000 0 0 \n", + "222 0.0 0.0 0.000000 ... 0 0 0.000000 0 0 \n", + "\n", + " SMIM10L2A INTS6L ADGRG4 PNMA6A CCNQ \n", + "0 0 0.0 0 0 0.0 \n", + "1 0 0.0 0 0 0.0 \n", + "2 0 0.0 0 0 0.0 \n", + "3 0 0.0 0 0 0.0 \n", + "4 0 0.0 0 0 0.0 \n", + ".. ... ... ... ... ... \n", + "218 0 0.0 0 0 0.0 \n", + "219 0 0.0 0 0 0.0 \n", + "220 0 0.0 0 0 0.0 \n", + "221 0 0.0 0 0 0.0 \n", + "222 0 0.0 0 0 0.0 \n", + "\n", + "[223 rows x 17049 columns]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_gexpr = pd.read_parquet(train_data_FN) # 70% of the original gene expression data (random split)\n", + "train_gexpr" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "4a7e81bc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Unnamed: 0SAMD11NOC2LKLHL17PLEKHN1PERM1HES4ISG15AGRNC1orf159...STK26RTL8BRTL8CRTL8ASMIM10L2BSMIM10L2AINTS6LADGRG4PNMA6ACCNQ
0CCCAACTGTCGAATTC-1_50.0000000.00.0000.0000000.0000000.00.000000...000.00000.0000.0
1GTTCGCTGTACAGTTC-1_10.0000000.00.0000.0000000.0000000.00.000000...000.00000.0000.0
2AGGAGGTCATTGACTG-1_20.0000000.00.0000.8409490.8409490.00.000000...000.00000.0000.0
3TAAGTCGTCTTCGTGC-1_30.0000000.00.0000.0000000.0000000.00.000000...000.00000.0000.0
4GCCAGCATCAGAGCAG-1_20.0000000.00.0000.0000000.0000000.00.000000...000.00000.0000.0
..................................................................
91AAGGAATCACGGGCTT-1_30.0000000.00.0000.0000000.0000000.00.000000...000.00000.0000.0
92ATAGAGATCAAAGGTA-1_20.0000000.00.0000.0000000.0000000.01.048932...000.00000.0000.0
93TTTGTTGTCTACGCGG-1_20.0000000.00.0001.0014980.0000000.00.000000...000.00000.0000.0
94GCCATGGGTGGAACAC-1_10.0000000.00.0001.9737620.0000000.00.000000...000.00000.0000.0
95TTTGGAGCAGTAGATA-1_21.5480590.00.0000.0000000.0000000.01.548059...000.00000.0000.0
\n", + "

96 rows × 17049 columns

\n", + "
" + ], + "text/plain": [ + " Unnamed: 0 SAMD11 NOC2L KLHL17 PLEKHN1 PERM1 HES4 \\\n", + "0 CCCAACTGTCGAATTC-1_5 0.000000 0.0 0.0 0 0 0.000000 \n", + "1 GTTCGCTGTACAGTTC-1_1 0.000000 0.0 0.0 0 0 0.000000 \n", + "2 AGGAGGTCATTGACTG-1_2 0.000000 0.0 0.0 0 0 0.840949 \n", + "3 TAAGTCGTCTTCGTGC-1_3 0.000000 0.0 0.0 0 0 0.000000 \n", + "4 GCCAGCATCAGAGCAG-1_2 0.000000 0.0 0.0 0 0 0.000000 \n", + ".. ... ... ... ... ... ... ... \n", + "91 AAGGAATCACGGGCTT-1_3 0.000000 0.0 0.0 0 0 0.000000 \n", + "92 ATAGAGATCAAAGGTA-1_2 0.000000 0.0 0.0 0 0 0.000000 \n", + "93 TTTGTTGTCTACGCGG-1_2 0.000000 0.0 0.0 0 0 1.001498 \n", + "94 GCCATGGGTGGAACAC-1_1 0.000000 0.0 0.0 0 0 1.973762 \n", + "95 TTTGGAGCAGTAGATA-1_2 1.548059 0.0 0.0 0 0 0.000000 \n", + "\n", + " ISG15 AGRN C1orf159 ... STK26 RTL8B RTL8C RTL8A SMIM10L2B \\\n", + "0 0.000000 0.0 0.000000 ... 0 0 0.0 0 0 \n", + "1 0.000000 0.0 0.000000 ... 0 0 0.0 0 0 \n", + "2 0.840949 0.0 0.000000 ... 0 0 0.0 0 0 \n", + "3 0.000000 0.0 0.000000 ... 0 0 0.0 0 0 \n", + "4 0.000000 0.0 0.000000 ... 0 0 0.0 0 0 \n", + ".. ... ... ... ... ... ... ... ... ... \n", + "91 0.000000 0.0 0.000000 ... 0 0 0.0 0 0 \n", + "92 0.000000 0.0 1.048932 ... 0 0 0.0 0 0 \n", + "93 0.000000 0.0 0.000000 ... 0 0 0.0 0 0 \n", + "94 0.000000 0.0 0.000000 ... 0 0 0.0 0 0 \n", + "95 0.000000 0.0 1.548059 ... 0 0 0.0 0 0 \n", + "\n", + " SMIM10L2A INTS6L ADGRG4 PNMA6A CCNQ \n", + "0 0 0.0 0 0 0.0 \n", + "1 0 0.0 0 0 0.0 \n", + "2 0 0.0 0 0 0.0 \n", + "3 0 0.0 0 0 0.0 \n", + "4 0 0.0 0 0 0.0 \n", + ".. ... ... ... ... ... \n", + "91 0 0.0 0 0 0.0 \n", + "92 0 0.0 0 0 0.0 \n", + "93 0 0.0 0 0 0.0 \n", + "94 0 0.0 0 0 0.0 \n", + "95 0 0.0 0 0 0.0 \n", + "\n", + "[96 rows x 17049 columns]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_gexpr = pd.read_parquet(test_data_FN) # remaining 30% of the original gene expression data\n", + "test_gexpr" + ] + }, + { + "cell_type": "markdown", + "id": "0fbd7f77", + "metadata": {}, + "source": [ + "Input Protein-Protein Interaction (PPI) Network:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "4cd8d66d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TF1TF2score
323NR2C2NR2C11.000000
432NR2C1NR2C21.000000
545ATF7ATF21.000000
572CUX1ATF21.000000
573JUNDATF21.000000
............
23168702TEAD1TEAD40.922923
24614146NFIANFIB0.812813
28106670MEF2CMEF2B0.912209
28172345NFIBNFIA0.983943
28484180TEAD4TEAD10.998360
\n", + "

20926 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " TF1 TF2 score\n", + "323 NR2C2 NR2C1 1.000000\n", + "432 NR2C1 NR2C2 1.000000\n", + "545 ATF7 ATF2 1.000000\n", + "572 CUX1 ATF2 1.000000\n", + "573 JUND ATF2 1.000000\n", + "... ... ... ...\n", + "23168702 TEAD1 TEAD4 0.922923\n", + "24614146 NFIA NFIB 0.812813\n", + "28106670 MEF2C MEF2B 0.912209\n", + "28172345 NFIB NFIA 0.983943\n", + "28484180 TEAD4 TEAD1 0.998360\n", + "\n", + "[20926 rows x 3 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ppi_df = pd.read_parquet(ppi_FN)\n", + "ppi_df" + ] + }, + { + "cell_type": "markdown", + "id": "2081d440", + "metadata": {}, + "source": [ + "Next, please note that we will use NetREm (Network Regression Embeddings) to identify the optimal Transcription Factors (TFs) out of the N candidate TFs, which may regulate this TG.\n", + "NetREm is run 1 TG at a time, to eventually build out networks for the cell-type :)" + ] + }, + { + "cell_type": "markdown", + "id": "3d5f4a32", + "metadata": {}, + "source": [ + "## Integration of multimodal data and networks:" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "e581a231", + "metadata": {}, + "source": [ + "![netrem_step1.png](../user_guide/pics/netrem_step1.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "456225d8", + "metadata": {}, + "outputs": [], + "source": [ + "tg = \"ZZZ3\" # target gene of interest" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "66fb2bf8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ZZZ3
00.0
10.0
20.0
30.0
40.0
......
2180.0
2190.0
2200.0
2210.0
2220.0
\n", + "

223 rows × 1 columns

\n", + "
" + ], + "text/plain": [ + " ZZZ3\n", + "0 0.0\n", + "1 0.0\n", + "2 0.0\n", + "3 0.0\n", + "4 0.0\n", + ".. ...\n", + "218 0.0\n", + "219 0.0\n", + "220 0.0\n", + "221 0.0\n", + "222 0.0\n", + "\n", + "[223 rows x 1 columns]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# training gene expression data for target gene (TG) y\n", + "y_train = train_gexpr[[tg]]\n", + "y_train" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "07c5d661", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ZZZ3
00.000000
11.406272
20.000000
30.000000
40.000000
......
910.000000
920.000000
930.000000
940.000000
951.548059
\n", + "

96 rows × 1 columns

\n", + "
" + ], + "text/plain": [ + " ZZZ3\n", + "0 0.000000\n", + "1 1.406272\n", + "2 0.000000\n", + "3 0.000000\n", + "4 0.000000\n", + ".. ...\n", + "91 0.000000\n", + "92 0.000000\n", + "93 0.000000\n", + "94 0.000000\n", + "95 1.548059\n", + "\n", + "[96 rows x 1 columns]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# testing gene expression data for target gene (TG) y\n", + "y_test = test_gexpr[[tg]]\n", + "y_test" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "bc43ad2e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) Please note that we have N = 77 candidate TFs for our TG ZZZ3\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TGTF
635318ZZZ3CTCF
635319ZZZ3E2F3
635320ZZZ3EBF1
635321ZZZ3FOXP1
635322ZZZ3GTF3C2
.........
635390ZZZ3BACH1
635391ZZZ3TCF3
635392ZZZ3ERF
635393ZZZ3ZNF281
635394ZZZ3SMAD4
\n", + "

77 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " TG TF\n", + "635318 ZZZ3 CTCF\n", + "635319 ZZZ3 E2F3\n", + "635320 ZZZ3 EBF1\n", + "635321 ZZZ3 FOXP1\n", + "635322 ZZZ3 GTF3C2\n", + "... ... ...\n", + "635390 ZZZ3 BACH1\n", + "635391 ZZZ3 TCF3\n", + "635392 ZZZ3 ERF\n", + "635393 ZZZ3 ZNF281\n", + "635394 ZZZ3 SMAD4\n", + "\n", + "[77 rows x 2 columns]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "candidate_TFs_for_TG_df = tfs_for_tgs_final_df[tfs_for_tgs_final_df[\"TG\"] == tg]\n", + "num_candidate_TFs_for_TG = candidate_TFs_for_TG_df.shape[0]\n", + "print(f\":) Please note that we have N = {num_candidate_TFs_for_TG} candidate TFs for our TG {tg}\")\n", + "candidate_TFs_for_TG_df" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "a70f24c4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Some of the first few candidate TFs for the TG ZZZ3: ['BACH1', 'BCL6', 'CCNT2', 'CTCF', 'E2F3', 'E4F1']\n" + ] + } + ], + "source": [ + "candidate_TFs_for_TG = list(candidate_TFs_for_TG_df[\"TF\"]) \n", + "candidate_TFs_for_TG.sort() # Saniya sorts alphabetically for convenience :)\n", + "print(f\"Some of the first few candidate TFs for the TG {tg}: {candidate_TFs_for_TG[0:6]}\")" + ] + }, + { + "cell_type": "markdown", + "id": "c69b3eb8", + "metadata": {}, + "source": [ + "Please note that we will utilize this given data to fit our network regularized regression problem for our target gene (TG):\n", + "\n", + "**NetREm model training:**\n", + "* filtered_ppi_for_TG\n", + "* X_train\n", + "* y_train\n", + "\n", + "**NetREm model testing:**\n", + "* X_test\n", + "* y_test" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "00f41fe4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TF1TF2score
32314HCFC1SP11.000000
32369SMC3SP11.000000
32387HDAC2SP11.000000
32457GTF3C2SP11.000000
32619MGASP11.000000
............
14290770ZFP82TP530.219219
14292496ZNF136SMC30.157157
14293375ZNF274HDAC20.245245
14293598ZNF281SMAD40.183183
18525244MYEF2CTCF0.013724
\n", + "

2860 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " TF1 TF2 score\n", + "32314 HCFC1 SP1 1.000000\n", + "32369 SMC3 SP1 1.000000\n", + "32387 HDAC2 SP1 1.000000\n", + "32457 GTF3C2 SP1 1.000000\n", + "32619 MGA SP1 1.000000\n", + "... ... ... ...\n", + "14290770 ZFP82 TP53 0.219219\n", + "14292496 ZNF136 SMC3 0.157157\n", + "14293375 ZNF274 HDAC2 0.245245\n", + "14293598 ZNF281 SMAD4 0.183183\n", + "18525244 MYEF2 CTCF 0.013724\n", + "\n", + "[2860 rows x 3 columns]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# we filter the PPI to only include the candidate TFs for our TG\n", + "filtered_ppi_for_TG = ppi_df[ppi_df[\"TF1\"].isin(candidate_TFs_for_TG)]\n", + "filtered_ppi_for_TG = filtered_ppi_for_TG[filtered_ppi_for_TG[\"TF2\"].isin(candidate_TFs_for_TG)].drop_duplicates()\n", + "filtered_ppi_for_TG" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "1f5c6dd4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2860\n" + ] + }, + { + "data": { + "text/plain": [ + "[['HCFC1', 'SP1', 1.0],\n", + " ['SMC3', 'SP1', 1.0],\n", + " ['HDAC2', 'SP1', 1.0],\n", + " ['GTF3C2', 'SP1', 1.0],\n", + " ['MGA', 'SP1', 1.0]]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# # Then, we need to do this conversion for NetREm:\n", + "filtered_ppi_for_TG = filtered_ppi_for_TG.values.tolist()\n", + "print(len(filtered_ppi_for_TG))\n", + "filtered_ppi_for_TG[0:5] # first 5 entries" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "21bfd35c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BACH1BCL6CCNT2CTCFE2F3E4F1EBF1EGR1ELF1ERF...YY1ZBTB7AZFP28ZFP82ZNF136ZNF140ZNF274ZNF281ZNF682ZNF76
00.7952830.0000000.7952830.0000001.9566150.00.00.00.7952830.0...0.7952830.0000000.0000000.00.0000000.0000000.7952830.00.00.0
10.0000002.1672180.0000000.0000000.0000000.00.00.00.0000000.0...0.0000000.0000000.0000000.00.0000000.0000000.0000000.00.00.0
20.0000000.0000000.0000000.0000000.0000000.00.00.00.0000000.0...0.0000000.0000000.0000000.00.0000000.0000000.0000000.00.00.0
30.0000000.0000000.0000000.0000000.0000000.00.00.00.0000000.0...0.0000000.0000002.5178990.00.0000000.0000000.0000000.00.00.0
40.0000000.0000000.0000001.2979271.2979270.00.00.02.1955670.0...0.0000000.0000000.0000000.00.0000000.0000000.0000000.00.00.0
..................................................................
2180.0000000.0000000.0000000.0000000.0000000.00.00.01.7571960.0...0.0000000.0000000.0000000.00.0000000.0000000.0000000.00.00.0
2190.0000000.0000000.0000000.0000000.0000000.00.00.00.0000000.0...0.0000002.4789690.0000000.00.0000000.0000000.0000000.00.00.0
2200.0000000.0000000.0000000.0000000.0000000.00.00.00.0000000.0...0.0000000.0000000.0000000.00.0000001.7345460.0000000.00.00.0
2210.0000002.1584770.8225620.0000000.0000000.00.00.00.8225620.0...0.8225620.0000000.0000000.00.8225620.0000000.8225620.00.00.0
2221.7659821.7659820.0000000.0000000.0000000.00.00.00.0000000.0...0.0000000.0000000.0000000.00.0000000.0000000.0000000.00.00.0
\n", + "

223 rows × 77 columns

\n", + "
" + ], + "text/plain": [ + " BACH1 BCL6 CCNT2 CTCF E2F3 E4F1 EBF1 EGR1 \\\n", + "0 0.795283 0.000000 0.795283 0.000000 1.956615 0.0 0.0 0.0 \n", + "1 0.000000 2.167218 0.000000 0.000000 0.000000 0.0 0.0 0.0 \n", + "2 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 0.0 0.0 \n", + "3 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 0.0 0.0 \n", + "4 0.000000 0.000000 0.000000 1.297927 1.297927 0.0 0.0 0.0 \n", + ".. ... ... ... ... ... ... ... ... \n", + "218 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 0.0 0.0 \n", + "219 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 0.0 0.0 \n", + "220 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 0.0 0.0 \n", + "221 0.000000 2.158477 0.822562 0.000000 0.000000 0.0 0.0 0.0 \n", + "222 1.765982 1.765982 0.000000 0.000000 0.000000 0.0 0.0 0.0 \n", + "\n", + " ELF1 ERF ... YY1 ZBTB7A ZFP28 ZFP82 ZNF136 \\\n", + "0 0.795283 0.0 ... 0.795283 0.000000 0.000000 0.0 0.000000 \n", + "1 0.000000 0.0 ... 0.000000 0.000000 0.000000 0.0 0.000000 \n", + "2 0.000000 0.0 ... 0.000000 0.000000 0.000000 0.0 0.000000 \n", + "3 0.000000 0.0 ... 0.000000 0.000000 2.517899 0.0 0.000000 \n", + "4 2.195567 0.0 ... 0.000000 0.000000 0.000000 0.0 0.000000 \n", + ".. ... ... ... ... ... ... ... ... \n", + "218 1.757196 0.0 ... 0.000000 0.000000 0.000000 0.0 0.000000 \n", + "219 0.000000 0.0 ... 0.000000 2.478969 0.000000 0.0 0.000000 \n", + "220 0.000000 0.0 ... 0.000000 0.000000 0.000000 0.0 0.000000 \n", + "221 0.822562 0.0 ... 0.822562 0.000000 0.000000 0.0 0.822562 \n", + "222 0.000000 0.0 ... 0.000000 0.000000 0.000000 0.0 0.000000 \n", + "\n", + " ZNF140 ZNF274 ZNF281 ZNF682 ZNF76 \n", + "0 0.000000 0.795283 0.0 0.0 0.0 \n", + "1 0.000000 0.000000 0.0 0.0 0.0 \n", + "2 0.000000 0.000000 0.0 0.0 0.0 \n", + "3 0.000000 0.000000 0.0 0.0 0.0 \n", + "4 0.000000 0.000000 0.0 0.0 0.0 \n", + ".. ... ... ... ... ... \n", + "218 0.000000 0.000000 0.0 0.0 0.0 \n", + "219 0.000000 0.000000 0.0 0.0 0.0 \n", + "220 1.734546 0.000000 0.0 0.0 0.0 \n", + "221 0.000000 0.822562 0.0 0.0 0.0 \n", + "222 0.000000 0.000000 0.0 0.0 0.0 \n", + "\n", + "[223 rows x 77 columns]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X_train = train_gexpr[candidate_TFs_for_TG] \n", + "X_train" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "628beab0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BACH1BCL6CCNT2CTCFE2F3E4F1EBF1EGR1ELF1ERF...YY1ZBTB7AZFP28ZFP82ZNF136ZNF140ZNF274ZNF281ZNF682ZNF76
00.0000002.5369810.0000000.0000000.0000000.0000000.00.00.0000000.0...0.0000000.0000000.00.0000000.0000000.00.0000000.0000000.000000.000000
11.4062722.3265110.0000000.0000000.0000000.0000000.00.00.0000000.0...1.4062720.0000000.00.0000000.0000000.00.0000000.0000001.968710.000000
20.8409490.8409490.0000000.8409490.0000000.0000000.00.00.8409490.0...0.8409490.0000000.00.0000000.8409490.00.0000000.0000000.000000.000000
30.0000000.0000002.3260940.0000000.0000001.7261430.00.00.0000000.0...0.0000000.0000000.01.7261430.0000000.00.0000000.0000000.000000.000000
41.8931360.0000000.0000000.0000000.0000000.0000000.00.01.8931360.0...1.3402710.0000000.01.3402710.0000000.00.0000000.0000000.000000.000000
..................................................................
910.0000000.0000002.8891450.0000000.0000000.0000000.00.00.0000000.0...0.0000003.5540860.00.0000000.0000000.00.0000000.0000000.000000.000000
920.0000001.0489320.0000000.0000001.0489320.0000000.00.01.0489320.0...0.0000000.0000000.00.0000000.0000000.00.0000000.0000000.000000.000000
931.0014980.0000000.0000000.0000000.0000000.0000000.00.00.0000000.0...0.0000000.0000000.00.0000000.0000000.01.0014980.0000000.000001.001498
940.0000000.0000000.0000000.0000000.0000000.0000000.00.00.0000000.0...1.4107070.0000000.00.0000000.0000000.00.0000001.4107070.000000.000000
950.0000000.0000000.0000000.0000000.0000000.0000000.00.00.0000000.0...0.0000001.5480590.00.0000001.5480590.00.0000000.0000000.000000.000000
\n", + "

96 rows × 77 columns

\n", + "
" + ], + "text/plain": [ + " BACH1 BCL6 CCNT2 CTCF E2F3 E4F1 EBF1 EGR1 \\\n", + "0 0.000000 2.536981 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n", + "1 1.406272 2.326511 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n", + "2 0.840949 0.840949 0.000000 0.840949 0.000000 0.000000 0.0 0.0 \n", + "3 0.000000 0.000000 2.326094 0.000000 0.000000 1.726143 0.0 0.0 \n", + "4 1.893136 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n", + ".. ... ... ... ... ... ... ... ... \n", + "91 0.000000 0.000000 2.889145 0.000000 0.000000 0.000000 0.0 0.0 \n", + "92 0.000000 1.048932 0.000000 0.000000 1.048932 0.000000 0.0 0.0 \n", + "93 1.001498 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n", + "94 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n", + "95 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n", + "\n", + " ELF1 ERF ... YY1 ZBTB7A ZFP28 ZFP82 ZNF136 ZNF140 \\\n", + "0 0.000000 0.0 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.0 \n", + "1 0.000000 0.0 ... 1.406272 0.000000 0.0 0.000000 0.000000 0.0 \n", + "2 0.840949 0.0 ... 0.840949 0.000000 0.0 0.000000 0.840949 0.0 \n", + "3 0.000000 0.0 ... 0.000000 0.000000 0.0 1.726143 0.000000 0.0 \n", + "4 1.893136 0.0 ... 1.340271 0.000000 0.0 1.340271 0.000000 0.0 \n", + ".. ... ... ... ... ... ... ... ... ... \n", + "91 0.000000 0.0 ... 0.000000 3.554086 0.0 0.000000 0.000000 0.0 \n", + "92 1.048932 0.0 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.0 \n", + "93 0.000000 0.0 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.0 \n", + "94 0.000000 0.0 ... 1.410707 0.000000 0.0 0.000000 0.000000 0.0 \n", + "95 0.000000 0.0 ... 0.000000 1.548059 0.0 0.000000 1.548059 0.0 \n", + "\n", + " ZNF274 ZNF281 ZNF682 ZNF76 \n", + "0 0.000000 0.000000 0.00000 0.000000 \n", + "1 0.000000 0.000000 1.96871 0.000000 \n", + "2 0.000000 0.000000 0.00000 0.000000 \n", + "3 0.000000 0.000000 0.00000 0.000000 \n", + "4 0.000000 0.000000 0.00000 0.000000 \n", + ".. ... ... ... ... \n", + "91 0.000000 0.000000 0.00000 0.000000 \n", + "92 0.000000 0.000000 0.00000 0.000000 \n", + "93 1.001498 0.000000 0.00000 1.001498 \n", + "94 0.000000 1.410707 0.00000 0.000000 \n", + "95 0.000000 0.000000 0.00000 0.000000 \n", + "\n", + "[96 rows x 77 columns]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X_test = test_gexpr[candidate_TFs_for_TG]\n", + "X_test" + ] + }, + { + "cell_type": "markdown", + "id": "90a9d41a", + "metadata": {}, + "source": [ + "Below, Saniya first shows the performance of 4 Baseline models (all fit using Cross Validation (CV) except Linear Regression) and then presents many examples of how NetREm may be applied, via **netrem**, **netremCV**, and/or Bayesian hyperparamater optimization. We recommend trying out these examples for your specific needs. 😁\n", + "\n", + "Please note that video tutorials on NetREm will soon be available on [Saniya's YouTube channel](https://www.youtube.com/c/SaniyaKhullar)📽️👩‍🏫." + ] + }, + { + "cell_type": "markdown", + "id": "888e3c9d", + "metadata": {}, + "source": [ + "**Example 1: Mainly using defaults and/or Cross-Validation to determine best values (minimal input from user 😴)** \n", + "* 1a: *netrem*: defaults for beta and $\\alpha_{lasso}$ \n", + "* 1b: *netrem*: default beta_net and LassoCV to find $\\alpha_{lasso}$ \n", + "* 1c: *netremCV*: find the optimal beta and optimal $\\alpha_{lasso}$ via Cross Validation (CV) (3 examples)\n", + "* 1d: *netrem and netrem-based function*: bayesian optimization to determine the optimal $\\alpha_{lasso}$ and $\\beta_{net}$ in fixed default ranges\n", + "\n", + "**Example 2: User provides inputs for NetREm (more input needed from user🤓🤔)** \n", + "* 2a: *netrem*: using user-defined values for $\\beta_{net}$ and $\\alpha_{lasso}$ \n", + "* 2b. *netrem*: using user-defined value for $\\beta_{net}$ and using LassoCV to find optimal $\\alpha_{lasso}$ \n", + "* 2c: *netrem*: using GridSearchCV for comprehensive hyperparameter optimization\n", + "* 2d: *netrem*: using RandomizedSearchCV for comprehensive hyperparameter optimization\n", + "* 2e: *netrem and netrem-based function*: bayesian optimization to determine the optimal $\\alpha_{lasso}$ and $\\beta_{net}$ for ranges of values defined by the user. \n", + "\n", + "**Example 3: User provides more inputs for more comprehensive hyperparameter optimization (building on #2)**\n", + "* 3a: *netrem*: using GridSearchCV for comprehensive hyperparameter optimization" + ] + }, + { + "cell_type": "markdown", + "id": "e9007e89", + "metadata": {}, + "source": [ + "### Baseline Examples: We fit models using Scikit-Learn packages for LinearRegression, LassoCV, RidgeCV, and ElasticNetCV on the data.\n", + "\n", + "#### Baseline Example 1: Fitting model with y-intercept term" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "6c63ed0d", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\saniy\\anaconda3\\lib\\site-packages\\sklearn\\linear_model\\_coordinate_descent.py:1568: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "C:\\Users\\saniy\\anaconda3\\lib\\site-packages\\sklearn\\linear_model\\_coordinate_descent.py:1568: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "C:\\Users\\saniy\\anaconda3\\lib\\site-packages\\sklearn\\linear_model\\_coordinate_descent.py:1568: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n", + "C:\\Users\\saniy\\anaconda3\\lib\\site-packages\\sklearn\\linear_model\\_coordinate_descent.py:1568: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " y = column_or_1d(y, warn=True)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
AbsoluteVal_coefficientRankTFInfoy_interceptfinal_model_TFsTFs_input_to_modeloriginal_TFs_in_Xtrain_msetest_msetrain_nmsetest_nmsetrain_snrtest_snrtrain_psnrtest_psnrTG
00.0975861SETDB1ElasticNetCVTrue :)1477770.5321990.6443590.6138350.6658922.1194871.76596012.51716310.656326ZZZ3
10.0890082ELF1ElasticNetCVTrue :)1477770.5321990.6443590.6138350.6658922.1194871.76596012.51716310.656326ZZZ3
20.0765893BACH1ElasticNetCVTrue :)1477770.5321990.6443590.6138350.6658922.1194871.76596012.51716310.656326ZZZ3
30.0749914NFKB1ElasticNetCVTrue :)1477770.5321990.6443590.6138350.6658922.1194871.76596012.51716310.656326ZZZ3
40.0598675NFIBElasticNetCVTrue :)1477770.5321990.6443590.6138350.6658922.1194871.76596012.51716310.656326ZZZ3
......................................................
720.00844473NR1D2LinearRegressionFalse :(7777770.8756471.0942981.0099651.130868-0.043063-0.53411710.3546138.356249ZZZ3
730.00770774NR6A1LinearRegressionFalse :(7777770.8756471.0942981.0099651.130868-0.043063-0.53411710.3546138.356249ZZZ3
740.00253575RXRALinearRegressionFalse :(7777770.8756471.0942981.0099651.130868-0.043063-0.53411710.3546138.356249ZZZ3
750.00169576THRBLinearRegressionFalse :(7777770.8756471.0942981.0099651.130868-0.043063-0.53411710.3546138.356249ZZZ3
760.00005777NR2F1LinearRegressionFalse :(7777770.8756471.0942981.0099651.130868-0.043063-0.53411710.3546138.356249ZZZ3
\n", + "

364 rows × 17 columns

\n", + "
" + ], + "text/plain": [ + " AbsoluteVal_coefficient Rank TF Info y_intercept \\\n", + "0 0.097586 1 SETDB1 ElasticNetCV True :) \n", + "1 0.089008 2 ELF1 ElasticNetCV True :) \n", + "2 0.076589 3 BACH1 ElasticNetCV True :) \n", + "3 0.074991 4 NFKB1 ElasticNetCV True :) \n", + "4 0.059867 5 NFIB ElasticNetCV True :) \n", + ".. ... ... ... ... ... \n", + "72 0.008444 73 NR1D2 LinearRegression False :( \n", + "73 0.007707 74 NR6A1 LinearRegression False :( \n", + "74 0.002535 75 RXRA LinearRegression False :( \n", + "75 0.001695 76 THRB LinearRegression False :( \n", + "76 0.000057 77 NR2F1 LinearRegression False :( \n", + "\n", + " final_model_TFs TFs_input_to_model original_TFs_in_X train_mse \\\n", + "0 14 77 77 0.532199 \n", + "1 14 77 77 0.532199 \n", + "2 14 77 77 0.532199 \n", + "3 14 77 77 0.532199 \n", + "4 14 77 77 0.532199 \n", + ".. ... ... ... ... \n", + "72 77 77 77 0.875647 \n", + "73 77 77 77 0.875647 \n", + "74 77 77 77 0.875647 \n", + "75 77 77 77 0.875647 \n", + "76 77 77 77 0.875647 \n", + "\n", + " test_mse train_nmse test_nmse train_snr test_snr train_psnr \\\n", + "0 0.644359 0.613835 0.665892 2.119487 1.765960 12.517163 \n", + "1 0.644359 0.613835 0.665892 2.119487 1.765960 12.517163 \n", + "2 0.644359 0.613835 0.665892 2.119487 1.765960 12.517163 \n", + "3 0.644359 0.613835 0.665892 2.119487 1.765960 12.517163 \n", + "4 0.644359 0.613835 0.665892 2.119487 1.765960 12.517163 \n", + ".. ... ... ... ... ... ... \n", + "72 1.094298 1.009965 1.130868 -0.043063 -0.534117 10.354613 \n", + "73 1.094298 1.009965 1.130868 -0.043063 -0.534117 10.354613 \n", + "74 1.094298 1.009965 1.130868 -0.043063 -0.534117 10.354613 \n", + "75 1.094298 1.009965 1.130868 -0.043063 -0.534117 10.354613 \n", + "76 1.094298 1.009965 1.130868 -0.043063 -0.534117 10.354613 \n", + "\n", + " test_psnr TG \n", + "0 10.656326 ZZZ3 \n", + "1 10.656326 ZZZ3 \n", + "2 10.656326 ZZZ3 \n", + "3 10.656326 ZZZ3 \n", + "4 10.656326 ZZZ3 \n", + ".. ... ... \n", + "72 8.356249 ZZZ3 \n", + "73 8.356249 ZZZ3 \n", + "74 8.356249 ZZZ3 \n", + "75 8.356249 ZZZ3 \n", + "76 8.356249 ZZZ3 \n", + "\n", + "[364 rows x 17 columns]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Examples with and without the y-intercept term included:\n", + "baseline_model_names = [\"ElasticNetCV\", \"RidgeCV\", \"LassoCV\", \"LinearRegression\"]\n", + "baseline_df = pd.DataFrame()\n", + "for model in baseline_model_names:\n", + " df_to_add1 = nm_eval.baseline_metrics_function(X_train = X_train, y_train = y_train, \n", + " X_test = X_test, y_test = y_test, \n", + " tg = tg, model_name = model, y_intercept = True)\n", + " df_to_add2 = nm_eval.baseline_metrics_function(X_train = X_train, y_train = y_train, \n", + " X_test = X_test, y_test = y_test, \n", + " tg = tg, model_name = model, y_intercept = False)\n", + " baseline_df = pd.concat([baseline_df, df_to_add1, df_to_add2])\n", + "baseline_df" + ] + }, + { + "cell_type": "markdown", + "id": "3d8379ea", + "metadata": {}, + "source": [ + "😊 We can view some of the baseline metrics at-a-glance:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "0d1f0053", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TGInfoy_interceptfinal_model_TFstrain_msetest_msetrain_nmsetest_nmsetrain_snrtest_snrtrain_psnrtest_psnr
0ZZZ3ElasticNetCVTrue :)140.5321990.6443590.6138350.6658922.1194871.76596012.51716310.656326
0ZZZ3ElasticNetCVFalse :(160.5176260.6588630.5970260.6808812.2400651.66928612.63774110.559653
0ZZZ3RidgeCVTrue :)770.8053430.8975810.9288760.9275760.3204220.32650410.7180989.216870
0ZZZ3RidgeCVFalse :(770.8055210.8978830.9290820.9278880.3194590.32504310.7171359.215409
0ZZZ3LassoCVTrue :)130.5354770.6464870.6176160.6680922.0928181.75164012.49049410.642006
0ZZZ3LassoCVFalse :(130.5181130.6608720.5975870.6829572.2359861.65606512.63366210.546431
0ZZZ3LinearRegressionTrue :)770.8781131.0996531.0128091.136401-0.055274-0.55531710.3424028.335050
0ZZZ3LinearRegressionFalse :(770.8756471.0942981.0099651.130868-0.043063-0.53411710.3546138.356249
\n", + "
" + ], + "text/plain": [ + " TG Info y_intercept final_model_TFs train_mse test_mse \\\n", + "0 ZZZ3 ElasticNetCV True :) 14 0.532199 0.644359 \n", + "0 ZZZ3 ElasticNetCV False :( 16 0.517626 0.658863 \n", + "0 ZZZ3 RidgeCV True :) 77 0.805343 0.897581 \n", + "0 ZZZ3 RidgeCV False :( 77 0.805521 0.897883 \n", + "0 ZZZ3 LassoCV True :) 13 0.535477 0.646487 \n", + "0 ZZZ3 LassoCV False :( 13 0.518113 0.660872 \n", + "0 ZZZ3 LinearRegression True :) 77 0.878113 1.099653 \n", + "0 ZZZ3 LinearRegression False :( 77 0.875647 1.094298 \n", + "\n", + " train_nmse test_nmse train_snr test_snr train_psnr test_psnr \n", + "0 0.613835 0.665892 2.119487 1.765960 12.517163 10.656326 \n", + "0 0.597026 0.680881 2.240065 1.669286 12.637741 10.559653 \n", + "0 0.928876 0.927576 0.320422 0.326504 10.718098 9.216870 \n", + "0 0.929082 0.927888 0.319459 0.325043 10.717135 9.215409 \n", + "0 0.617616 0.668092 2.092818 1.751640 12.490494 10.642006 \n", + "0 0.597587 0.682957 2.235986 1.656065 12.633662 10.546431 \n", + "0 1.012809 1.136401 -0.055274 -0.555317 10.342402 8.335050 \n", + "0 1.009965 1.130868 -0.043063 -0.534117 10.354613 8.356249 " + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "comparison_df = baseline_df[[\"TG\", \"Info\", \"y_intercept\", \n", + " \"final_model_TFs\", \"train_mse\", \"test_mse\", \"train_nmse\", \n", + " \"test_nmse\", \"train_snr\", \"test_snr\", \"train_psnr\", \"test_psnr\"]].drop_duplicates()\n", + "comparison_df" + ] + }, + { + "cell_type": "markdown", + "id": "69b2f2a2", + "metadata": {}, + "source": [ + "Please note that:\n", + "* MSE is Mean Squared Error (smaller values are better 😀)\n", + "* NMSE is Normalized MSE (smaller values are better 😀)\n", + "* SNR is Signal to Noise Ratio (larger values are better 😀)\n", + "* PSNR is Peak SNR (larger values are better 😀)" + ] + }, + { + "cell_type": "markdown", + "id": "033fd384", + "metadata": {}, + "source": [ + "### Below, Saniya will show examples utilizing NetREm (Network Regression Embeddings) " + ] + }, + { + "cell_type": "markdown", + "id": "006d75b3", + "metadata": {}, + "source": [ + "## Example 1️⃣:\n", + "### using defaults when possible :) 😴" + ] + }, + { + "cell_type": "markdown", + "id": "ca867780", + "metadata": {}, + "source": [ + "### Example 1a: \n", + "#### Using the defaults for *beta_net* $\\beta_{net}$ and *alpha_lasso* $\\alpha_{lasso}$ ." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "14b59753", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2860\n" + ] + }, + { + "data": { + "text/plain": [ + "[['HCFC1', 'SP1', 1.0],\n", + " ['SMC3', 'SP1', 1.0],\n", + " ['HDAC2', 'SP1', 1.0],\n", + " ['GTF3C2', 'SP1', 1.0],\n", + " ['MGA', 'SP1', 1.0]]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(len(filtered_ppi_for_TG))\n", + "filtered_ppi_for_TG[0:5] # Saniya views the first few entries of the input edge list\n", + "# [[node1, node2, weight (if known)],...]" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "dfe27f59", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using beta_net default of 1\n", + "using alpha_lasso default of 0.01\n", + "# of TFs with non-zero coefficients: 55\n", + "Training MSE: 0.4028411980913493\n", + "Testing MSE: 0.7056823978412833\n", + "CPU times: total: 0 ns\n", + "Wall time: 79.3 ms\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_interceptBACH1BCL6CCNT2CTCFE2F3E4F1EBF1ELF1ERF...STAT5BTBX2TCF3TP53USF1YY1ZBTB7AZNF140ZNF682ZNF76
0None0.0916370.0005140.049703-0.05840.181601-0.206912-0.0342050.122034-0.089625...0.0784890.007029-0.127275-0.1031150.0413950.106009-0.035760.0929990.0026580.139763
\n", + "

1 rows × 56 columns

\n", + "
" + ], + "text/plain": [ + " y_intercept BACH1 BCL6 CCNT2 CTCF E2F3 E4F1 \\\n", + "0 None 0.091637 0.000514 0.049703 -0.0584 0.181601 -0.206912 \n", + "\n", + " EBF1 ELF1 ERF ... STAT5B TBX2 TCF3 TP53 \\\n", + "0 -0.034205 0.122034 -0.089625 ... 0.078489 0.007029 -0.127275 -0.103115 \n", + "\n", + " USF1 YY1 ZBTB7A ZNF140 ZNF682 ZNF76 \n", + "0 0.041395 0.106009 -0.03576 0.092999 0.002658 0.139763 \n", + "\n", + "[1 rows x 56 columns]" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time \n", + "# added %%time above time the amount of time to run the code in the cell block\n", + "\n", + "# Using defaults for beta and alpha:\n", + "netrem_1a = nm.netrem(edge_list = filtered_ppi_for_TG)\n", + "\n", + "# Fitting the gregulnet model on training data: X_train and y_train:\n", + "netrem_1a.fit(X_train, y_train)\n", + "\n", + "# Analyzing the NetREm Function\n", + "final_model_1a = netrem_1a.model_nonzero_coef_df\n", + "print(f\"# of TFs with non-zero coefficients: {netrem_1a.num_final_predictors}\")\n", + "mse_train = netrem_1a.test_mse(X_train, y_train)\n", + "mse_test = netrem_1a.test_mse(X_test, y_test)\n", + "print(f\"Training MSE: {mse_train}\")\n", + "print(f\"Testing MSE: {mse_test}\")\n", + "final_model_1a" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "2ef578e0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
NetREmModel(verbose=False, overlapped_nodes_only=False, all_pos_coefs=False, model_type=Lasso, use_network=True, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C467AB8E0>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(verbose=False, overlapped_nodes_only=False, all_pos_coefs=False, model_type=Lasso, use_network=True, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, network=)" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_1a" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "27687c20", + "metadata": {}, + "source": [ + "![netrem_1a.png](../user_guide/pics/netrem_1a.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "8c2c20ff", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "To view the TF-TG regulatory links for the optimal TFs, please note that we can access this:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
coefTFTGinfotrain_msebeta_netalpha_lassoAbsoluteVal_coefficientRankfinal_model_TFsTFs_input_to_modeloriginal_TFs_in_X
0Noney_interceptZZZ3netrem_no_intercept0.40284110.01NaN56557777
10.091637BACH1ZZZ3netrem_no_intercept0.40284110.010.09163717557777
20.000514BCL6ZZZ3netrem_no_intercept0.40284110.010.00051455557777
30.049703CCNT2ZZZ3netrem_no_intercept0.40284110.010.04970329557777
4-0.0584CTCFZZZ3netrem_no_intercept0.40284110.010.05840025557777
50.181601E2F3ZZZ3netrem_no_intercept0.40284110.010.1816013557777
6-0.206912E4F1ZZZ3netrem_no_intercept0.40284110.010.2069121557777
7-0.034205EBF1ZZZ3netrem_no_intercept0.40284110.010.03420536557777
80.122034ELF1ZZZ3netrem_no_intercept0.40284110.010.1220347557777
9-0.089625ERFZZZ3netrem_no_intercept0.40284110.010.08962519557777
10-0.043602ESR2ZZZ3netrem_no_intercept0.40284110.010.04360231557777
11-0.011249FOXO1ZZZ3netrem_no_intercept0.40284110.010.01124947557777
120.120234HCFC1ZZZ3netrem_no_intercept0.40284110.010.1202348557777
130.054667HDAC2ZZZ3netrem_no_intercept0.40284110.010.05466727557777
140.114946IRF3ZZZ3netrem_no_intercept0.40284110.010.1149469557777
150.006109IRF7ZZZ3netrem_no_intercept0.40284110.010.00610951557777
16-0.074701KLF12ZZZ3netrem_no_intercept0.40284110.010.07470122557777
170.012354KLF15ZZZ3netrem_no_intercept0.40284110.010.01235446557777
180.021167MAFZZZ3netrem_no_intercept0.40284110.010.02116743557777
190.005506MAXZZZ3netrem_no_intercept0.40284110.010.00550653557777
20-0.109458MXI1ZZZ3netrem_no_intercept0.40284110.010.10945811557777
210.027785MYEF2ZZZ3netrem_no_intercept0.40284110.010.02778540557777
220.099391NFIBZZZ3netrem_no_intercept0.40284110.010.09939115557777
230.033488NFICZZZ3netrem_no_intercept0.40284110.010.03348837557777
240.170866NFKB1ZZZ3netrem_no_intercept0.40284110.010.1708664557777
250.104805NR1H2ZZZ3netrem_no_intercept0.40284110.010.10480513557777
26-0.021396NR2F1ZZZ3netrem_no_intercept0.40284110.010.02139642557777
270.016633NR3C1ZZZ3netrem_no_intercept0.40284110.010.01663344557777
280.008364NR6A1ZZZ3netrem_no_intercept0.40284110.010.00836449557777
290.040354PLAG1ZZZ3netrem_no_intercept0.40284110.010.04035434557777
30-0.040854PMLZZZ3netrem_no_intercept0.40284110.010.04085433557777
31-0.005926POU2F1ZZZ3netrem_no_intercept0.40284110.010.00592652557777
320.009088PPARAZZZ3netrem_no_intercept0.40284110.010.00908848557777
330.114686RARBZZZ3netrem_no_intercept0.40284110.010.11468610557777
34-0.058719RARGZZZ3netrem_no_intercept0.40284110.010.05871924557777
350.050561RFX3ZZZ3netrem_no_intercept0.40284110.010.05056128557777
36-0.091143RORAZZZ3netrem_no_intercept0.40284110.010.09114318557777
370.054681RREB1ZZZ3netrem_no_intercept0.40284110.010.05468126557777
380.045125RUNX2ZZZ3netrem_no_intercept0.40284110.010.04512530557777
390.196592SETDB1ZZZ3netrem_no_intercept0.40284110.010.1965922557777
400.070867SIN3AZZZ3netrem_no_intercept0.40284110.010.07086723557777
41-0.030716SMAD4ZZZ3netrem_no_intercept0.40284110.010.03071639557777
420.07586SMC3ZZZ3netrem_no_intercept0.40284110.010.07586021557777
430.021915SP1ZZZ3netrem_no_intercept0.40284110.010.02191541557777
44-0.016183SREBF2ZZZ3netrem_no_intercept0.40284110.010.01618345557777
450.031441STAT1ZZZ3netrem_no_intercept0.40284110.010.03144138557777
460.078489STAT5BZZZ3netrem_no_intercept0.40284110.010.07848920557777
470.007029TBX2ZZZ3netrem_no_intercept0.40284110.010.00702950557777
48-0.127275TCF3ZZZ3netrem_no_intercept0.40284110.010.1272756557777
49-0.103115TP53ZZZ3netrem_no_intercept0.40284110.010.10311514557777
500.041395USF1ZZZ3netrem_no_intercept0.40284110.010.04139532557777
510.106009YY1ZZZ3netrem_no_intercept0.40284110.010.10600912557777
52-0.03576ZBTB7AZZZ3netrem_no_intercept0.40284110.010.03576035557777
530.092999ZNF140ZZZ3netrem_no_intercept0.40284110.010.09299916557777
540.002658ZNF682ZZZ3netrem_no_intercept0.40284110.010.00265854557777
550.139763ZNF76ZZZ3netrem_no_intercept0.40284110.010.1397635557777
\n", + "
" + ], + "text/plain": [ + " coef TF TG info train_mse beta_net \\\n", + "0 None y_intercept ZZZ3 netrem_no_intercept 0.402841 1 \n", + "1 0.091637 BACH1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "2 0.000514 BCL6 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "3 0.049703 CCNT2 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "4 -0.0584 CTCF ZZZ3 netrem_no_intercept 0.402841 1 \n", + "5 0.181601 E2F3 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "6 -0.206912 E4F1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "7 -0.034205 EBF1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "8 0.122034 ELF1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "9 -0.089625 ERF ZZZ3 netrem_no_intercept 0.402841 1 \n", + "10 -0.043602 ESR2 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "11 -0.011249 FOXO1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "12 0.120234 HCFC1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "13 0.054667 HDAC2 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "14 0.114946 IRF3 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "15 0.006109 IRF7 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "16 -0.074701 KLF12 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "17 0.012354 KLF15 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "18 0.021167 MAF ZZZ3 netrem_no_intercept 0.402841 1 \n", + "19 0.005506 MAX ZZZ3 netrem_no_intercept 0.402841 1 \n", + "20 -0.109458 MXI1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "21 0.027785 MYEF2 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "22 0.099391 NFIB ZZZ3 netrem_no_intercept 0.402841 1 \n", + "23 0.033488 NFIC ZZZ3 netrem_no_intercept 0.402841 1 \n", + "24 0.170866 NFKB1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "25 0.104805 NR1H2 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "26 -0.021396 NR2F1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "27 0.016633 NR3C1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "28 0.008364 NR6A1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "29 0.040354 PLAG1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "30 -0.040854 PML ZZZ3 netrem_no_intercept 0.402841 1 \n", + "31 -0.005926 POU2F1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "32 0.009088 PPARA ZZZ3 netrem_no_intercept 0.402841 1 \n", + "33 0.114686 RARB ZZZ3 netrem_no_intercept 0.402841 1 \n", + "34 -0.058719 RARG ZZZ3 netrem_no_intercept 0.402841 1 \n", + "35 0.050561 RFX3 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "36 -0.091143 RORA ZZZ3 netrem_no_intercept 0.402841 1 \n", + "37 0.054681 RREB1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "38 0.045125 RUNX2 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "39 0.196592 SETDB1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "40 0.070867 SIN3A ZZZ3 netrem_no_intercept 0.402841 1 \n", + "41 -0.030716 SMAD4 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "42 0.07586 SMC3 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "43 0.021915 SP1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "44 -0.016183 SREBF2 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "45 0.031441 STAT1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "46 0.078489 STAT5B ZZZ3 netrem_no_intercept 0.402841 1 \n", + "47 0.007029 TBX2 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "48 -0.127275 TCF3 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "49 -0.103115 TP53 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "50 0.041395 USF1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "51 0.106009 YY1 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "52 -0.03576 ZBTB7A ZZZ3 netrem_no_intercept 0.402841 1 \n", + "53 0.092999 ZNF140 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "54 0.002658 ZNF682 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "55 0.139763 ZNF76 ZZZ3 netrem_no_intercept 0.402841 1 \n", + "\n", + " alpha_lasso AbsoluteVal_coefficient Rank final_model_TFs \\\n", + "0 0.01 NaN 56 55 \n", + "1 0.01 0.091637 17 55 \n", + "2 0.01 0.000514 55 55 \n", + "3 0.01 0.049703 29 55 \n", + "4 0.01 0.058400 25 55 \n", + "5 0.01 0.181601 3 55 \n", + "6 0.01 0.206912 1 55 \n", + "7 0.01 0.034205 36 55 \n", + "8 0.01 0.122034 7 55 \n", + "9 0.01 0.089625 19 55 \n", + "10 0.01 0.043602 31 55 \n", + "11 0.01 0.011249 47 55 \n", + "12 0.01 0.120234 8 55 \n", + "13 0.01 0.054667 27 55 \n", + "14 0.01 0.114946 9 55 \n", + "15 0.01 0.006109 51 55 \n", + "16 0.01 0.074701 22 55 \n", + "17 0.01 0.012354 46 55 \n", + "18 0.01 0.021167 43 55 \n", + "19 0.01 0.005506 53 55 \n", + "20 0.01 0.109458 11 55 \n", + "21 0.01 0.027785 40 55 \n", + "22 0.01 0.099391 15 55 \n", + "23 0.01 0.033488 37 55 \n", + "24 0.01 0.170866 4 55 \n", + "25 0.01 0.104805 13 55 \n", + "26 0.01 0.021396 42 55 \n", + "27 0.01 0.016633 44 55 \n", + "28 0.01 0.008364 49 55 \n", + "29 0.01 0.040354 34 55 \n", + "30 0.01 0.040854 33 55 \n", + "31 0.01 0.005926 52 55 \n", + "32 0.01 0.009088 48 55 \n", + "33 0.01 0.114686 10 55 \n", + "34 0.01 0.058719 24 55 \n", + "35 0.01 0.050561 28 55 \n", + "36 0.01 0.091143 18 55 \n", + "37 0.01 0.054681 26 55 \n", + "38 0.01 0.045125 30 55 \n", + "39 0.01 0.196592 2 55 \n", + "40 0.01 0.070867 23 55 \n", + "41 0.01 0.030716 39 55 \n", + "42 0.01 0.075860 21 55 \n", + "43 0.01 0.021915 41 55 \n", + "44 0.01 0.016183 45 55 \n", + "45 0.01 0.031441 38 55 \n", + "46 0.01 0.078489 20 55 \n", + "47 0.01 0.007029 50 55 \n", + "48 0.01 0.127275 6 55 \n", + "49 0.01 0.103115 14 55 \n", + "50 0.01 0.041395 32 55 \n", + "51 0.01 0.106009 12 55 \n", + "52 0.01 0.035760 35 55 \n", + "53 0.01 0.092999 16 55 \n", + "54 0.01 0.002658 54 55 \n", + "55 0.01 0.139763 5 55 \n", + "\n", + " TFs_input_to_model original_TFs_in_X \n", + "0 77 77 \n", + "1 77 77 \n", + "2 77 77 \n", + "3 77 77 \n", + "4 77 77 \n", + "5 77 77 \n", + "6 77 77 \n", + "7 77 77 \n", + "8 77 77 \n", + "9 77 77 \n", + "10 77 77 \n", + "11 77 77 \n", + "12 77 77 \n", + "13 77 77 \n", + "14 77 77 \n", + "15 77 77 \n", + "16 77 77 \n", + "17 77 77 \n", + "18 77 77 \n", + "19 77 77 \n", + "20 77 77 \n", + "21 77 77 \n", + "22 77 77 \n", + "23 77 77 \n", + "24 77 77 \n", + "25 77 77 \n", + "26 77 77 \n", + "27 77 77 \n", + "28 77 77 \n", + "29 77 77 \n", + "30 77 77 \n", + "31 77 77 \n", + "32 77 77 \n", + "33 77 77 \n", + "34 77 77 \n", + "35 77 77 \n", + "36 77 77 \n", + "37 77 77 \n", + "38 77 77 \n", + "39 77 77 \n", + "40 77 77 \n", + "41 77 77 \n", + "42 77 77 \n", + "43 77 77 \n", + "44 77 77 \n", + "45 77 77 \n", + "46 77 77 \n", + "47 77 77 \n", + "48 77 77 \n", + "49 77 77 \n", + "50 77 77 \n", + "51 77 77 \n", + "52 77 77 \n", + "53 77 77 \n", + "54 77 77 \n", + "55 77 77 " + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(\"To view the TF-TG regulatory links for the optimal TFs, please note that we can access this:\")\n", + "netrem_1a.combined_df" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "2c4f3853", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'info': 'NetREm Model',\n", + " 'alpha_lasso': 0.01,\n", + " 'beta_net': 1,\n", + " 'y_intercept': False,\n", + " 'model_type': 'Lasso',\n", + " 'max_lasso_iterations': 10000,\n", + " 'network': ,\n", + " 'verbose': False,\n", + " 'all_pos_coefs': False,\n", + " 'model_info': 'fitted_model :)',\n", + " 'target_gene_y': 'ZZZ3',\n", + " 'tolerance': 0.0001,\n", + " 'lasso_selection': 'cyclic'}" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_1a.get_params()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "1146999b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['info', 'verbose', 'overlapped_nodes_only', 'num_cv_folds', 'num_jobs', 'all_pos_coefs', 'model_type', 'use_network', 'y_intercept', 'max_lasso_iterations', 'view_network', 'model_info', 'target_gene_y', 'tolerance', 'lasso_selection', 'lassocv_eps', 'lassocv_n_alphas', 'lassocv_alphas', 'beta_net', 'network', 'alpha_lasso', 'optimal_alpha', 'prior_network', 'preprocessed_network', 'network_params', 'network_nodes_list', 'kwargs', 'X_df', 'gene_expression_nodes', 'common_nodes', 'final_nodes', 'gexpr_nodes_added', 'gexpr_nodes_to_add_for_net', 'filter_network_bool', 'A_df', 'A', 'nodes', 'network_info', 'M', 'N', 'X_train', 'y_train', 'B_train', 'B_interaction_df', 'B_train_times_M', 'X_tilda_train', 'y_tilda_train', 'X_training_to_use', 'y_training_to_use', 'regr', 'final_alpha', 'coef', 'predY_tilda_train', 'mse_tilda_train', 'predY_train', 'mse_train', 'model_coef_df', 'model_nonzero_coef_df', 'sorted_coef_df', 'corr_vs_coef_df', 'final_corr_vs_coef_df', 'combined_df', 'num_final_predictors'])" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vars(netrem_1a).keys() # to view all of the keys we may call" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "bfdba727", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) We can view the sorted B-matrix of TF-TF interaction for N = 77 TFs for TG ZZZ3 where beta_net = 1.\n" + ] + } + ], + "source": [ + "print(f\":) We can view the sorted B-matrix of TF-TF interaction for N = {num_candidate_TFs_for_TG} TFs \", end=\"\")\n", + "print(f\"for TG {tg} where beta_net = {netrem_1a.beta_net}.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "180439d9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TF1TF2B_train_weightsignpotential_interactionabsVal_Binfocandidate_TFs_Ntarget_gene_ynum_final_predictorsmodel_typebeta_netgene_datarankpercentile
2092FOXO1NFIB1.119274e+00:):(1.119274e+00B matrix of TF-TF interactions77ZZZ355Lasso1training gene expression data1.099.982912
1028NFIBFOXO11.119274e+00:):(1.119274e+00B matrix of TF-TF interactions77ZZZ355Lasso1training gene expression data1.099.982912
4416NFIBSREBF29.570243e-01:):(9.570243e-01B matrix of TF-TF interactions77ZZZ355Lasso1training gene expression data3.099.948735
2136SREBF2NFIB9.570243e-01:):(9.570243e-01B matrix of TF-TF interactions77ZZZ355Lasso1training gene expression data3.099.948735
1046RORAFOXO19.287842e-01:):(9.287842e-01B matrix of TF-TF interactions77ZZZ355Lasso1training gene expression data5.099.914559
................................................
3834TCF3RXRB-1.163842e-06:(:( competitive (-)1.163842e-06B matrix of TF-TF interactions77ZZZ355Lasso1training gene expression data5847.00.085441
960PMLESRRA-9.827955e-07:(:( competitive (-)9.827955e-07B matrix of TF-TF interactions77ZZZ355Lasso1training gene expression data5849.00.051265
2784ESRRAPML-9.827955e-07:(:( competitive (-)9.827955e-07B matrix of TF-TF interactions77ZZZ355Lasso1training gene expression data5850.00.034176
4708ESR2TCF3-9.284305e-07:(:( competitive (-)9.284305e-07B matrix of TF-TF interactions77ZZZ355Lasso1training gene expression data5851.00.017088
908TCF3ESR2-9.284305e-07:(:( competitive (-)9.284305e-07B matrix of TF-TF interactions77ZZZ355Lasso1training gene expression data5851.00.017088
\n", + "

5852 rows × 15 columns

\n", + "
" + ], + "text/plain": [ + " TF1 TF2 B_train_weight sign potential_interaction absVal_B \\\n", + "2092 FOXO1 NFIB 1.119274e+00 :) :( 1.119274e+00 \n", + "1028 NFIB FOXO1 1.119274e+00 :) :( 1.119274e+00 \n", + "4416 NFIB SREBF2 9.570243e-01 :) :( 9.570243e-01 \n", + "2136 SREBF2 NFIB 9.570243e-01 :) :( 9.570243e-01 \n", + "1046 RORA FOXO1 9.287842e-01 :) :( 9.287842e-01 \n", + "... ... ... ... ... ... ... \n", + "3834 TCF3 RXRB -1.163842e-06 :( :( competitive (-) 1.163842e-06 \n", + "960 PML ESRRA -9.827955e-07 :( :( competitive (-) 9.827955e-07 \n", + "2784 ESRRA PML -9.827955e-07 :( :( competitive (-) 9.827955e-07 \n", + "4708 ESR2 TCF3 -9.284305e-07 :( :( competitive (-) 9.284305e-07 \n", + "908 TCF3 ESR2 -9.284305e-07 :( :( competitive (-) 9.284305e-07 \n", + "\n", + " info candidate_TFs_N target_gene_y \\\n", + "2092 B matrix of TF-TF interactions 77 ZZZ3 \n", + "1028 B matrix of TF-TF interactions 77 ZZZ3 \n", + "4416 B matrix of TF-TF interactions 77 ZZZ3 \n", + "2136 B matrix of TF-TF interactions 77 ZZZ3 \n", + "1046 B matrix of TF-TF interactions 77 ZZZ3 \n", + "... ... ... ... \n", + "3834 B matrix of TF-TF interactions 77 ZZZ3 \n", + "960 B matrix of TF-TF interactions 77 ZZZ3 \n", + "2784 B matrix of TF-TF interactions 77 ZZZ3 \n", + "4708 B matrix of TF-TF interactions 77 ZZZ3 \n", + "908 B matrix of TF-TF interactions 77 ZZZ3 \n", + "\n", + " num_final_predictors model_type beta_net \\\n", + "2092 55 Lasso 1 \n", + "1028 55 Lasso 1 \n", + "4416 55 Lasso 1 \n", + "2136 55 Lasso 1 \n", + "1046 55 Lasso 1 \n", + "... ... ... ... \n", + "3834 55 Lasso 1 \n", + "960 55 Lasso 1 \n", + "2784 55 Lasso 1 \n", + "4708 55 Lasso 1 \n", + "908 55 Lasso 1 \n", + "\n", + " gene_data rank percentile \n", + "2092 training gene expression data 1.0 99.982912 \n", + "1028 training gene expression data 1.0 99.982912 \n", + "4416 training gene expression data 3.0 99.948735 \n", + "2136 training gene expression data 3.0 99.948735 \n", + "1046 training gene expression data 5.0 99.914559 \n", + "... ... ... ... \n", + "3834 training gene expression data 5847.0 0.085441 \n", + "960 training gene expression data 5849.0 0.051265 \n", + "2784 training gene expression data 5850.0 0.034176 \n", + "4708 training gene expression data 5851.0 0.017088 \n", + "908 training gene expression data 5851.0 0.017088 \n", + "\n", + "[5852 rows x 15 columns]" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b_matrix_1a = nm.organize_B_interaction_network(netrem_1a)\n", + "b_matrix_1a" + ] + }, + { + "cell_type": "markdown", + "id": "c28a9769", + "metadata": {}, + "source": [ + "Please note that the original B matrix provided by NetREm for the above dataframe can be accessed as:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "09ec182e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BACH1BCL6CCNT2CTCFE2F3E4F1EBF1EGR1ELF1ERF...YY1ZBTB7AZFP28ZFP82ZNF136ZNF140ZNF274ZNF281ZNF682ZNF76
BACH11.0188400.2792520.1873540.1880820.1857290.0660600.100796-0.0000030.3823660.012201...0.2400040.1854090.0506250.0899650.0337970.0606430.1069280.0216570.1313550.167068
BCL60.2792520.9173200.1359900.2014100.1318810.0577130.1245610.0630450.3022830.014507...0.1517850.2559130.0078600.0466150.0680430.0815460.1089800.0335850.0537070.077397
CCNT20.1873540.1359900.4775740.0761860.0948890.0151510.1447700.0097090.236614-0.000004...0.1310200.0667540.0125590.0693820.0099760.0344340.0549540.0238420.0422020.053667
CTCF0.1880820.2014100.0761860.5121250.0683050.0142190.0724450.0097090.2277570.031582...0.1384760.1748570.0225170.0167930.0378150.0419240.0270670.0232470.0355240.041152
E2F30.1857290.1318810.0948890.0683050.3572570.0277380.034148-0.0000050.1644840.014507...0.1205950.112284-0.0000070.0440220.0145260.0311740.0497030.0022960.0552610.068752
..................................................................
ZNF1400.0606430.0815460.0344340.0419240.0311740.0156080.0284690.0097090.102075-0.000008...0.0674580.0461840.0023670.009461-0.0000870.1668080.0196450.0058630.0206850.021863
ZNF2740.1069280.1089800.0549540.0270670.0497030.0075710.050144-0.0000040.1184890.014658...0.0422320.1029100.0023720.0090220.0254510.0196450.3171430.0022990.0407010.043983
ZNF2810.0216570.0335850.0238420.0232470.002296-0.0000030.049474-0.0000020.044545-0.000004...0.0215280.031265-0.0000660.008675-0.0000040.0058630.0022990.0583550.0196060.015731
ZNF6820.1313550.0537070.0422020.0355240.0552610.0103700.026068-0.0002050.135911-0.000435...0.0916610.074324-0.0007540.0205400.0275980.0206850.0407010.0196062.8440380.035217
ZNF760.1670680.0773970.0536670.0411520.0687520.0193010.046529-0.0000060.060648-0.000014...0.0703760.0968650.0078270.0078790.0060810.0218630.0439830.0157310.0352170.227348
\n", + "

77 rows × 77 columns

\n", + "
" + ], + "text/plain": [ + " BACH1 BCL6 CCNT2 CTCF E2F3 E4F1 EBF1 \\\n", + "BACH1 1.018840 0.279252 0.187354 0.188082 0.185729 0.066060 0.100796 \n", + "BCL6 0.279252 0.917320 0.135990 0.201410 0.131881 0.057713 0.124561 \n", + "CCNT2 0.187354 0.135990 0.477574 0.076186 0.094889 0.015151 0.144770 \n", + "CTCF 0.188082 0.201410 0.076186 0.512125 0.068305 0.014219 0.072445 \n", + "E2F3 0.185729 0.131881 0.094889 0.068305 0.357257 0.027738 0.034148 \n", + "... ... ... ... ... ... ... ... \n", + "ZNF140 0.060643 0.081546 0.034434 0.041924 0.031174 0.015608 0.028469 \n", + "ZNF274 0.106928 0.108980 0.054954 0.027067 0.049703 0.007571 0.050144 \n", + "ZNF281 0.021657 0.033585 0.023842 0.023247 0.002296 -0.000003 0.049474 \n", + "ZNF682 0.131355 0.053707 0.042202 0.035524 0.055261 0.010370 0.026068 \n", + "ZNF76 0.167068 0.077397 0.053667 0.041152 0.068752 0.019301 0.046529 \n", + "\n", + " EGR1 ELF1 ERF ... YY1 ZBTB7A ZFP28 \\\n", + "BACH1 -0.000003 0.382366 0.012201 ... 0.240004 0.185409 0.050625 \n", + "BCL6 0.063045 0.302283 0.014507 ... 0.151785 0.255913 0.007860 \n", + "CCNT2 0.009709 0.236614 -0.000004 ... 0.131020 0.066754 0.012559 \n", + "CTCF 0.009709 0.227757 0.031582 ... 0.138476 0.174857 0.022517 \n", + "E2F3 -0.000005 0.164484 0.014507 ... 0.120595 0.112284 -0.000007 \n", + "... ... ... ... ... ... ... ... \n", + "ZNF140 0.009709 0.102075 -0.000008 ... 0.067458 0.046184 0.002367 \n", + "ZNF274 -0.000004 0.118489 0.014658 ... 0.042232 0.102910 0.002372 \n", + "ZNF281 -0.000002 0.044545 -0.000004 ... 0.021528 0.031265 -0.000066 \n", + "ZNF682 -0.000205 0.135911 -0.000435 ... 0.091661 0.074324 -0.000754 \n", + "ZNF76 -0.000006 0.060648 -0.000014 ... 0.070376 0.096865 0.007827 \n", + "\n", + " ZFP82 ZNF136 ZNF140 ZNF274 ZNF281 ZNF682 ZNF76 \n", + "BACH1 0.089965 0.033797 0.060643 0.106928 0.021657 0.131355 0.167068 \n", + "BCL6 0.046615 0.068043 0.081546 0.108980 0.033585 0.053707 0.077397 \n", + "CCNT2 0.069382 0.009976 0.034434 0.054954 0.023842 0.042202 0.053667 \n", + "CTCF 0.016793 0.037815 0.041924 0.027067 0.023247 0.035524 0.041152 \n", + "E2F3 0.044022 0.014526 0.031174 0.049703 0.002296 0.055261 0.068752 \n", + "... ... ... ... ... ... ... ... \n", + "ZNF140 0.009461 -0.000087 0.166808 0.019645 0.005863 0.020685 0.021863 \n", + "ZNF274 0.009022 0.025451 0.019645 0.317143 0.002299 0.040701 0.043983 \n", + "ZNF281 0.008675 -0.000004 0.005863 0.002299 0.058355 0.019606 0.015731 \n", + "ZNF682 0.020540 0.027598 0.020685 0.040701 0.019606 2.844038 0.035217 \n", + "ZNF76 0.007879 0.006081 0.021863 0.043983 0.015731 0.035217 0.227348 \n", + "\n", + "[77 rows x 77 columns]" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_1a.B_interaction_df" + ] + }, + { + "cell_type": "markdown", + "id": "b586e2e4", + "metadata": {}, + "source": [ + "### Example 1b: \n", + "#### Use the default *beta_net* $\\beta_{net}$ but use LassoCV to help find the optimal *alpha_lasso* $\\alpha_{lasso}$ via Cross-Validation." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "717c7c66", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using beta_net default of 1\n", + "# of TFs with non-zero coefficients: 56\n", + "Training MSE: 0.4005184771488405\n", + "Testing MSE: 0.7104270905888238\n", + "CPU times: total: 15.6 ms\n", + "Wall time: 169 ms\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_interceptBACH1CCNT2CTCFE2F3E4F1EBF1ELF1ERFESR2...TBX2TCF3TP53USF1USF2YY1ZBTB7AZNF140ZNF682ZNF76
0None0.0914530.050524-0.0593310.183201-0.21609-0.0355850.121124-0.09812-0.053123...0.009692-0.129406-0.1067560.0492-0.0017340.108942-0.0364160.0952090.0026290.143346
\n", + "

1 rows × 57 columns

\n", + "
" + ], + "text/plain": [ + " y_intercept BACH1 CCNT2 CTCF E2F3 E4F1 EBF1 \\\n", + "0 None 0.091453 0.050524 -0.059331 0.183201 -0.21609 -0.035585 \n", + "\n", + " ELF1 ERF ESR2 ... TBX2 TCF3 TP53 USF1 \\\n", + "0 0.121124 -0.09812 -0.053123 ... 0.009692 -0.129406 -0.106756 0.0492 \n", + "\n", + " USF2 YY1 ZBTB7A ZNF140 ZNF682 ZNF76 \n", + "0 -0.001734 0.108942 -0.036416 0.095209 0.002629 0.143346 \n", + "\n", + "[1 rows x 57 columns]" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time \n", + "# Using defaults for beta and alpha:\n", + "netrem_1b = nm.netrem(edge_list = filtered_ppi_for_TG,\n", + " model_type = \"LassoCV\")\n", + "\n", + "# Fitting the gregulnet model on training data: X_train and y_train:\n", + "netrem_1b.fit(X_train, y_train)\n", + "\n", + "# Analyzing the NetREm Function\n", + "final_model_1b = netrem_1b.model_nonzero_coef_df\n", + "print(f\"# of TFs with non-zero coefficients: {netrem_1b.num_final_predictors}\")\n", + "mse_train = netrem_1b.test_mse(X_train, y_train)\n", + "mse_test = netrem_1b.test_mse(X_test, y_test)\n", + "print(f\"Training MSE: {mse_train}\")\n", + "print(f\"Testing MSE: {mse_test}\")\n", + "final_model_1b\n" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "cb233f0c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'info': 'NetREm Model',\n", + " 'alpha_lasso': 'LassoCV finds optimal alpha',\n", + " 'beta_net': 1,\n", + " 'y_intercept': False,\n", + " 'model_type': 'LassoCV',\n", + " 'max_lasso_iterations': 10000,\n", + " 'network': ,\n", + " 'verbose': False,\n", + " 'all_pos_coefs': False,\n", + " 'model_info': 'fitted_model :)',\n", + " 'target_gene_y': 'ZZZ3',\n", + " 'num_cv_folds': 5,\n", + " 'num_jobs': -1,\n", + " 'lassocv_eps': 0.001,\n", + " 'lassocv_n_alphas': 100,\n", + " 'lassocv_alphas': None,\n", + " 'optimal_alpha': 'Cross-Validation optimal alpha lasso: 0.009564951400513843',\n", + " 'tolerance': 0.0001,\n", + " 'lasso_selection': 'cyclic'}" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_1b.get_params()" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "b5d9634e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
NetREmModel(verbose=False, overlapped_nodes_only=False, num_cv_folds=5, num_jobs=-1, all_pos_coefs=False, model_type=LassoCV, use_network=True, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, lassocv_eps=0.001, lassocv_n_alphas=100, lassocv_alphas=None, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C46C5CF40>, alpha_lasso=LassoCV finds optimal alpha)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(verbose=False, overlapped_nodes_only=False, num_cv_folds=5, num_jobs=-1, all_pos_coefs=False, model_type=LassoCV, use_network=True, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, lassocv_eps=0.001, lassocv_n_alphas=100, lassocv_alphas=None, network=, alpha_lasso=LassoCV finds optimal alpha)" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_1b" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "29f467d5", + "metadata": {}, + "source": [ + "![netrem_1b.png](../user_guide/pics/netrem_1b.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "0e675c2c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) We can view the sorted B-matrix of TF-TF interaction for N = 77 TFs for TG ZZZ3 where beta_net = 1.\n" + ] + } + ], + "source": [ + "print(f\":) We can view the sorted B-matrix of TF-TF interaction for N = {num_candidate_TFs_for_TG} TFs \", end=\"\")\n", + "print(f\"for TG {tg} where beta_net = {netrem_1a.beta_net}.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "74108fae", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TF1TF2B_train_weightsignpotential_interactionabsVal_Binfocandidate_TFs_Ntarget_gene_ynum_final_predictorsmodel_typebeta_netgene_datarankpercentile
2092FOXO1NFIB1.119274e+00:):(1.119274e+00B matrix of TF-TF interactions77ZZZ356LassoCV1training gene expression data1.099.982912
1028NFIBFOXO11.119274e+00:):(1.119274e+00B matrix of TF-TF interactions77ZZZ356LassoCV1training gene expression data1.099.982912
4416NFIBSREBF29.570243e-01:):(9.570243e-01B matrix of TF-TF interactions77ZZZ356LassoCV1training gene expression data3.099.948735
2136SREBF2NFIB9.570243e-01:):(9.570243e-01B matrix of TF-TF interactions77ZZZ356LassoCV1training gene expression data3.099.948735
1046RORAFOXO19.287842e-01:):(9.287842e-01B matrix of TF-TF interactions77ZZZ356LassoCV1training gene expression data5.099.914559
................................................
3834TCF3RXRB-1.163842e-06:(:( competitive (-)1.163842e-06B matrix of TF-TF interactions77ZZZ356LassoCV1training gene expression data5847.00.085441
960PMLESRRA-9.827955e-07:(:( competitive (-)9.827955e-07B matrix of TF-TF interactions77ZZZ356LassoCV1training gene expression data5849.00.051265
2784ESRRAPML-9.827955e-07:(:( competitive (-)9.827955e-07B matrix of TF-TF interactions77ZZZ356LassoCV1training gene expression data5850.00.034176
4708ESR2TCF3-9.284305e-07:(:( competitive (-)9.284305e-07B matrix of TF-TF interactions77ZZZ356LassoCV1training gene expression data5851.00.017088
908TCF3ESR2-9.284305e-07:(:( competitive (-)9.284305e-07B matrix of TF-TF interactions77ZZZ356LassoCV1training gene expression data5851.00.017088
\n", + "

5852 rows × 15 columns

\n", + "
" + ], + "text/plain": [ + " TF1 TF2 B_train_weight sign potential_interaction absVal_B \\\n", + "2092 FOXO1 NFIB 1.119274e+00 :) :( 1.119274e+00 \n", + "1028 NFIB FOXO1 1.119274e+00 :) :( 1.119274e+00 \n", + "4416 NFIB SREBF2 9.570243e-01 :) :( 9.570243e-01 \n", + "2136 SREBF2 NFIB 9.570243e-01 :) :( 9.570243e-01 \n", + "1046 RORA FOXO1 9.287842e-01 :) :( 9.287842e-01 \n", + "... ... ... ... ... ... ... \n", + "3834 TCF3 RXRB -1.163842e-06 :( :( competitive (-) 1.163842e-06 \n", + "960 PML ESRRA -9.827955e-07 :( :( competitive (-) 9.827955e-07 \n", + "2784 ESRRA PML -9.827955e-07 :( :( competitive (-) 9.827955e-07 \n", + "4708 ESR2 TCF3 -9.284305e-07 :( :( competitive (-) 9.284305e-07 \n", + "908 TCF3 ESR2 -9.284305e-07 :( :( competitive (-) 9.284305e-07 \n", + "\n", + " info candidate_TFs_N target_gene_y \\\n", + "2092 B matrix of TF-TF interactions 77 ZZZ3 \n", + "1028 B matrix of TF-TF interactions 77 ZZZ3 \n", + "4416 B matrix of TF-TF interactions 77 ZZZ3 \n", + "2136 B matrix of TF-TF interactions 77 ZZZ3 \n", + "1046 B matrix of TF-TF interactions 77 ZZZ3 \n", + "... ... ... ... \n", + "3834 B matrix of TF-TF interactions 77 ZZZ3 \n", + "960 B matrix of TF-TF interactions 77 ZZZ3 \n", + "2784 B matrix of TF-TF interactions 77 ZZZ3 \n", + "4708 B matrix of TF-TF interactions 77 ZZZ3 \n", + "908 B matrix of TF-TF interactions 77 ZZZ3 \n", + "\n", + " num_final_predictors model_type beta_net \\\n", + "2092 56 LassoCV 1 \n", + "1028 56 LassoCV 1 \n", + "4416 56 LassoCV 1 \n", + "2136 56 LassoCV 1 \n", + "1046 56 LassoCV 1 \n", + "... ... ... ... \n", + "3834 56 LassoCV 1 \n", + "960 56 LassoCV 1 \n", + "2784 56 LassoCV 1 \n", + "4708 56 LassoCV 1 \n", + "908 56 LassoCV 1 \n", + "\n", + " gene_data rank percentile \n", + "2092 training gene expression data 1.0 99.982912 \n", + "1028 training gene expression data 1.0 99.982912 \n", + "4416 training gene expression data 3.0 99.948735 \n", + "2136 training gene expression data 3.0 99.948735 \n", + "1046 training gene expression data 5.0 99.914559 \n", + "... ... ... ... \n", + "3834 training gene expression data 5847.0 0.085441 \n", + "960 training gene expression data 5849.0 0.051265 \n", + "2784 training gene expression data 5850.0 0.034176 \n", + "4708 training gene expression data 5851.0 0.017088 \n", + "908 training gene expression data 5851.0 0.017088 \n", + "\n", + "[5852 rows x 15 columns]" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b_matrix_1b = nm.organize_B_interaction_network(netrem_1b)\n", + "b_matrix_1b" + ] + }, + { + "cell_type": "markdown", + "id": "0bd40de1", + "metadata": {}, + "source": [ + "### Example 1c\n", + "#### Using *netremCV* to determine the optimal alpha and beta values via cross-validation approaches :). This function may be computationally and time-intensive:" + ] + }, + { + "cell_type": "markdown", + "id": "4b901ca1", + "metadata": {}, + "source": [ + "#### Option 1\n", + "Option 1 is RandomizedSearchCV, which is more efficient given time constraints" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "7bc702c4", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) using variance to define beta_net values\n", + "beta_min = 0.14322421928177426 and beta_max = 14.322421928177425\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "5d8107af6c6a42f6b5130718c2d95e98", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + ":) Generating beta_net and alpha_lasso pairs: 0%| | 0/50 [00:00#sk-container-id-3 {color: black;background-color: white;}#sk-container-id-3 pre{padding: 0;}#sk-container-id-3 div.sk-toggleable {background-color: white;}#sk-container-id-3 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-3 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-3 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-3 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-3 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-3 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-3 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-3 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-3 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-3 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-3 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-3 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-3 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-3 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-3 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-3 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-3 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-3 div.sk-item {position: relative;z-index: 1;}#sk-container-id-3 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-3 div.sk-item::before, #sk-container-id-3 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-3 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-3 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-3 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-3 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-3 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-3 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-3 div.sk-label-container {text-align: center;}#sk-container-id-3 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-3 div.sk-text-repr-fallback {display: none;}
NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=11.868171420559674, alpha_lasso=0.009564951400513843, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C46B2AEF0>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=11.868171420559674, alpha_lasso=0.009564951400513843, network=)" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netCV_ex1" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "0e42a122", + "metadata": {}, + "source": [ + "![netCV_ex1.png](../user_guide/pics/netCV_ex1.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "48738d8c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'info': 'NetREm Model',\n", + " 'alpha_lasso': 0.009564951400513843,\n", + " 'beta_net': 11.868171420559674,\n", + " 'y_intercept': False,\n", + " 'model_type': 'Lasso',\n", + " 'max_lasso_iterations': 10000,\n", + " 'network': ,\n", + " 'verbose': False,\n", + " 'all_pos_coefs': False,\n", + " 'model_info': 'fitted_model :)',\n", + " 'target_gene_y': 'ZZZ3',\n", + " 'tolerance': 0.0001,\n", + " 'lasso_selection': 'cyclic'}" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netCV_ex1.get_params()" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "967f1b96", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Training MSE: 0.40382941437204656\n", + "Testing MSE: 0.7021367157493694\n" + ] + } + ], + "source": [ + "mse_train = netCV_ex1.test_mse(X_train, y_train)\n", + "mse_test = netCV_ex1.test_mse(X_test, y_test)\n", + "print(f\"Training MSE: {mse_train}\")\n", + "print(f\"Testing MSE: {mse_test}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "0d32d652", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
infoinput_dataBACH1BCL6CCNT2CTCFE2F3E4F1EBF1ELF1...TBX2TCF3TP53USF1USF2YY1ZBTB7AZNF140ZNF682ZNF76
0network regression coeff. with y: ZZZ3X_train0.092490.0007280.050554-0.0594160.180268-0.197291-0.0332580.119244...0.006187-0.128818-0.1031560.04475-0.0001380.105222-0.0355820.0889970.0004260.119169
0corr (r) with y: ZZZ3X_train0.1910810.0283150.134249-0.0534870.160718-0.046865-0.047160.207914...0.026626-0.149349-0.0651730.085353-0.0254910.119843-0.1245850.1325370.1297380.124608
0Absolute Value NetREm Coefficient RankingX_train1654292531377...525143257113518568
\n", + "

3 rows × 59 columns

\n", + "
" + ], + "text/plain": [ + " info input_data BACH1 BCL6 \\\n", + "0 network regression coeff. with y: ZZZ3 X_train 0.09249 0.000728 \n", + "0 corr (r) with y: ZZZ3 X_train 0.191081 0.028315 \n", + "0 Absolute Value NetREm Coefficient Ranking X_train 16 54 \n", + "\n", + " CCNT2 CTCF E2F3 E4F1 EBF1 ELF1 ... TBX2 \\\n", + "0 0.050554 -0.059416 0.180268 -0.197291 -0.033258 0.119244 ... 0.006187 \n", + "0 0.134249 -0.053487 0.160718 -0.046865 -0.04716 0.207914 ... 0.026626 \n", + "0 29 25 3 1 37 7 ... 52 \n", + "\n", + " TCF3 TP53 USF1 USF2 YY1 ZBTB7A ZNF140 \\\n", + "0 -0.128818 -0.103156 0.04475 -0.000138 0.105222 -0.035582 0.088997 \n", + "0 -0.149349 -0.065173 0.085353 -0.025491 0.119843 -0.124585 0.132537 \n", + "0 5 14 32 57 11 35 18 \n", + "\n", + " ZNF682 ZNF76 \n", + "0 0.000426 0.119169 \n", + "0 0.129738 0.124608 \n", + "0 56 8 \n", + "\n", + "[3 rows x 59 columns]" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netCV_ex1.final_corr_vs_coef_df" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "647fee07", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TF1TF2B_train_weightsignpotential_interactionabsVal_Binfocandidate_TFs_Ntarget_gene_ynum_final_predictorsmodel_typebeta_netgene_datarankpercentile
2092FOXO1NFIB1.119190:):(1.119190B matrix of TF-TF interactions77ZZZ357Lasso11.868171training gene expression data1.099.982912
1028NFIBFOXO11.119190:):(1.119190B matrix of TF-TF interactions77ZZZ357Lasso11.868171training gene expression data1.099.982912
4416NFIBSREBF20.956982:):(0.956982B matrix of TF-TF interactions77ZZZ357Lasso11.868171training gene expression data3.099.948735
2136SREBF2NFIB0.956982:):(0.956982B matrix of TF-TF interactions77ZZZ357Lasso11.868171training gene expression data3.099.948735
1046RORAFOXO10.928712:):(0.928712B matrix of TF-TF interactions77ZZZ357Lasso11.868171training gene expression data5.099.914559
................................................
3834TCF3RXRB-0.000014:(:( competitive (-)0.000014B matrix of TF-TF interactions77ZZZ357Lasso11.868171training gene expression data5848.00.068353
960PMLESRRA-0.000012:(:( competitive (-)0.000012B matrix of TF-TF interactions77ZZZ357Lasso11.868171training gene expression data5849.00.051265
2784ESRRAPML-0.000012:(:( competitive (-)0.000012B matrix of TF-TF interactions77ZZZ357Lasso11.868171training gene expression data5850.00.034176
908TCF3ESR2-0.000011:(:( competitive (-)0.000011B matrix of TF-TF interactions77ZZZ357Lasso11.868171training gene expression data5851.00.017088
4708ESR2TCF3-0.000011:(:( competitive (-)0.000011B matrix of TF-TF interactions77ZZZ357Lasso11.868171training gene expression data5851.00.017088
\n", + "

5852 rows × 15 columns

\n", + "
" + ], + "text/plain": [ + " TF1 TF2 B_train_weight sign potential_interaction absVal_B \\\n", + "2092 FOXO1 NFIB 1.119190 :) :( 1.119190 \n", + "1028 NFIB FOXO1 1.119190 :) :( 1.119190 \n", + "4416 NFIB SREBF2 0.956982 :) :( 0.956982 \n", + "2136 SREBF2 NFIB 0.956982 :) :( 0.956982 \n", + "1046 RORA FOXO1 0.928712 :) :( 0.928712 \n", + "... ... ... ... ... ... ... \n", + "3834 TCF3 RXRB -0.000014 :( :( competitive (-) 0.000014 \n", + "960 PML ESRRA -0.000012 :( :( competitive (-) 0.000012 \n", + "2784 ESRRA PML -0.000012 :( :( competitive (-) 0.000012 \n", + "908 TCF3 ESR2 -0.000011 :( :( competitive (-) 0.000011 \n", + "4708 ESR2 TCF3 -0.000011 :( :( competitive (-) 0.000011 \n", + "\n", + " info candidate_TFs_N target_gene_y \\\n", + "2092 B matrix of TF-TF interactions 77 ZZZ3 \n", + "1028 B matrix of TF-TF interactions 77 ZZZ3 \n", + "4416 B matrix of TF-TF interactions 77 ZZZ3 \n", + "2136 B matrix of TF-TF interactions 77 ZZZ3 \n", + "1046 B matrix of TF-TF interactions 77 ZZZ3 \n", + "... ... ... ... \n", + "3834 B matrix of TF-TF interactions 77 ZZZ3 \n", + "960 B matrix of TF-TF interactions 77 ZZZ3 \n", + "2784 B matrix of TF-TF interactions 77 ZZZ3 \n", + "908 B matrix of TF-TF interactions 77 ZZZ3 \n", + "4708 B matrix of TF-TF interactions 77 ZZZ3 \n", + "\n", + " num_final_predictors model_type beta_net \\\n", + "2092 57 Lasso 11.868171 \n", + "1028 57 Lasso 11.868171 \n", + "4416 57 Lasso 11.868171 \n", + "2136 57 Lasso 11.868171 \n", + "1046 57 Lasso 11.868171 \n", + "... ... ... ... \n", + "3834 57 Lasso 11.868171 \n", + "960 57 Lasso 11.868171 \n", + "2784 57 Lasso 11.868171 \n", + "908 57 Lasso 11.868171 \n", + "4708 57 Lasso 11.868171 \n", + "\n", + " gene_data rank percentile \n", + "2092 training gene expression data 1.0 99.982912 \n", + "1028 training gene expression data 1.0 99.982912 \n", + "4416 training gene expression data 3.0 99.948735 \n", + "2136 training gene expression data 3.0 99.948735 \n", + "1046 training gene expression data 5.0 99.914559 \n", + "... ... ... ... \n", + "3834 training gene expression data 5848.0 0.068353 \n", + "960 training gene expression data 5849.0 0.051265 \n", + "2784 training gene expression data 5850.0 0.034176 \n", + "908 training gene expression data 5851.0 0.017088 \n", + "4708 training gene expression data 5851.0 0.017088 \n", + "\n", + "[5852 rows x 15 columns]" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b_matrix_netremcv = nm.organize_B_interaction_network(netCV_ex1)\n", + "b_matrix_netremcv" + ] + }, + { + "cell_type": "markdown", + "id": "3def87b3", + "metadata": {}, + "source": [ + "#### Option 2:\n", + "\n", + "Option 2 is GridSearchCV, which is less efficient but more comprehensive:" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "6e915b26", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) using variance to define beta_net values\n", + "beta_min = 0.14322421928177426 and beta_max = 14.322421928177425\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "7cdc161663654a1b838aeb5afc5c0fc5", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + ":) Generating beta_net and alpha_lasso pairs: 0%| | 0/50 [00:00#sk-container-id-4 {color: black;background-color: white;}#sk-container-id-4 pre{padding: 0;}#sk-container-id-4 div.sk-toggleable {background-color: white;}#sk-container-id-4 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-4 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-4 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-4 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-4 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-4 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-4 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-4 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-4 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-4 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-4 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-4 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-4 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-4 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-4 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-4 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-4 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-4 div.sk-item {position: relative;z-index: 1;}#sk-container-id-4 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-4 div.sk-item::before, #sk-container-id-4 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-4 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-4 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-4 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-4 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-4 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-4 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-4 div.sk-label-container {text-align: center;}#sk-container-id-4 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-4 div.sk-text-repr-fallback {display: none;}
NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=14.322421928177425, alpha_lasso=0.009564951400513843, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C46E874C0>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=14.322421928177425, alpha_lasso=0.009564951400513843, network=)" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time \n", + "\n", + "netCV_ex2 = nm.netremCV(edge_list = filtered_ppi_for_TG, X = X_train, y = y_train, searchVerbosity = 1)\n", + "netCV_ex2" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "958fba86", + "metadata": {}, + "source": [ + "![netCV_ex2.png](../user_guide/pics/netCV_ex2.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "c66c5f9a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) # of final TFs in the model for TG ZZZ3: 56\n", + "Training MSE: 0.40452577061665235\n", + "Testing MSE: 0.7004107017093232\n" + ] + } + ], + "source": [ + "print(f\":) # of final TFs in the model for TG {tg}: {netCV_ex2.num_final_predictors}\")\n", + "mse_train = netCV_ex2.test_mse(X_train, y_train)\n", + "mse_test = netCV_ex2.test_mse(X_test, y_test)\n", + "print(f\"Training MSE: {mse_train}\")\n", + "print(f\"Testing MSE: {mse_test}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "367d8aa0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
coefTFTGinfotrain_msebeta_netalpha_lassoAbsoluteVal_coefficientRankfinal_model_TFsTFs_input_to_modeloriginal_TFs_in_X
0Noney_interceptZZZ3netrem_no_intercept0.40452614.3224220.009565NaN57567777
10.092587BACH1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.09258716567777
20.00092BCL6ZZZ3netrem_no_intercept0.40452614.3224220.0095650.00092054567777
30.050598CCNT2ZZZ3netrem_no_intercept0.40452614.3224220.0095650.05059829567777
4-0.059361CTCFZZZ3netrem_no_intercept0.40452614.3224220.0095650.05936125567777
50.179477E2F3ZZZ3netrem_no_intercept0.40452614.3224220.0095650.1794773567777
6-0.193458E4F1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.1934582567777
7-0.032772EBF1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.03277237567777
80.118892ELF1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.1188926567777
9-0.079737ERFZZZ3netrem_no_intercept0.40452614.3224220.0095650.07973719567777
10-0.043963ESR2ZZZ3netrem_no_intercept0.40452614.3224220.0095650.04396332567777
11-0.009189FOXO1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.00918950567777
120.118487HCFC1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.1184877567777
130.057439HDAC2ZZZ3netrem_no_intercept0.40452614.3224220.0095650.05743926567777
140.109527IRF3ZZZ3netrem_no_intercept0.40452614.3224220.0095650.10952710567777
150.014876IRF7ZZZ3netrem_no_intercept0.40452614.3224220.0095650.01487646567777
16-0.068512KLF12ZZZ3netrem_no_intercept0.40452614.3224220.0095650.06851223567777
170.012554KLF15ZZZ3netrem_no_intercept0.40452614.3224220.0095650.01255447567777
180.021563MAFZZZ3netrem_no_intercept0.40452614.3224220.0095650.02156342567777
190.004856MAXZZZ3netrem_no_intercept0.40452614.3224220.0095650.00485653567777
20-0.103236MXI1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.10323612567777
210.028747MYEF2ZZZ3netrem_no_intercept0.40452614.3224220.0095650.02874740567777
220.099127NFIBZZZ3netrem_no_intercept0.40452614.3224220.0095650.09912715567777
230.033372NFICZZZ3netrem_no_intercept0.40452614.3224220.0095650.03337236567777
240.169403NFKB1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.1694034567777
250.10255NR1H2ZZZ3netrem_no_intercept0.40452614.3224220.0095650.10255013567777
26-0.021933NR2F1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.02193341567777
270.01755NR3C1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.01755044567777
280.009942NR6A1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.00994248567777
290.04056PLAG1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.04056034567777
30-0.040835PMLZZZ3netrem_no_intercept0.40452614.3224220.0095650.04083533567777
31-0.007102POU2F1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.00710251567777
320.009594PPARAZZZ3netrem_no_intercept0.40452614.3224220.0095650.00959449567777
330.000353PPARDZZZ3netrem_no_intercept0.40452614.3224220.0095650.00035356567777
340.115948RARBZZZ3netrem_no_intercept0.40452614.3224220.0095650.1159488567777
35-0.060035RARGZZZ3netrem_no_intercept0.40452614.3224220.0095650.06003524567777
360.051793RFX3ZZZ3netrem_no_intercept0.40452614.3224220.0095650.05179328567777
37-0.089946RORAZZZ3netrem_no_intercept0.40452614.3224220.0095650.08994617567777
380.053255RREB1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.05325527567777
390.044984RUNX2ZZZ3netrem_no_intercept0.40452614.3224220.0095650.04498430567777
400.194475SETDB1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.1944751567777
410.069117SIN3AZZZ3netrem_no_intercept0.40452614.3224220.0095650.06911722567777
42-0.031496SMAD4ZZZ3netrem_no_intercept0.40452614.3224220.0095650.03149639567777
430.074904SMC3ZZZ3netrem_no_intercept0.40452614.3224220.0095650.07490421567777
440.02126SP1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.02126043567777
45-0.01584SREBF2ZZZ3netrem_no_intercept0.40452614.3224220.0095650.01584045567777
460.03191STAT1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.03191038567777
470.076585STAT5BZZZ3netrem_no_intercept0.40452614.3224220.0095650.07658520567777
480.005611TBX2ZZZ3netrem_no_intercept0.40452614.3224220.0095650.00561152567777
49-0.128551TCF3ZZZ3netrem_no_intercept0.40452614.3224220.0095650.1285515567777
50-0.102327TP53ZZZ3netrem_no_intercept0.40452614.3224220.0095650.10232714567777
510.044001USF1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.04400131567777
520.104471YY1ZZZ3netrem_no_intercept0.40452614.3224220.0095650.10447111567777
53-0.035432ZBTB7AZZZ3netrem_no_intercept0.40452614.3224220.0095650.03543235567777
540.08773ZNF140ZZZ3netrem_no_intercept0.40452614.3224220.0095650.08773018567777
550.000388ZNF682ZZZ3netrem_no_intercept0.40452614.3224220.0095650.00038855567777
560.114872ZNF76ZZZ3netrem_no_intercept0.40452614.3224220.0095650.1148729567777
\n", + "
" + ], + "text/plain": [ + " coef TF TG info train_mse beta_net \\\n", + "0 None y_intercept ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "1 0.092587 BACH1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "2 0.00092 BCL6 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "3 0.050598 CCNT2 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "4 -0.059361 CTCF ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "5 0.179477 E2F3 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "6 -0.193458 E4F1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "7 -0.032772 EBF1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "8 0.118892 ELF1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "9 -0.079737 ERF ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "10 -0.043963 ESR2 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "11 -0.009189 FOXO1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "12 0.118487 HCFC1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "13 0.057439 HDAC2 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "14 0.109527 IRF3 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "15 0.014876 IRF7 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "16 -0.068512 KLF12 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "17 0.012554 KLF15 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "18 0.021563 MAF ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "19 0.004856 MAX ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "20 -0.103236 MXI1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "21 0.028747 MYEF2 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "22 0.099127 NFIB ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "23 0.033372 NFIC ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "24 0.169403 NFKB1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "25 0.10255 NR1H2 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "26 -0.021933 NR2F1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "27 0.01755 NR3C1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "28 0.009942 NR6A1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "29 0.04056 PLAG1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "30 -0.040835 PML ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "31 -0.007102 POU2F1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "32 0.009594 PPARA ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "33 0.000353 PPARD ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "34 0.115948 RARB ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "35 -0.060035 RARG ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "36 0.051793 RFX3 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "37 -0.089946 RORA ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "38 0.053255 RREB1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "39 0.044984 RUNX2 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "40 0.194475 SETDB1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "41 0.069117 SIN3A ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "42 -0.031496 SMAD4 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "43 0.074904 SMC3 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "44 0.02126 SP1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "45 -0.01584 SREBF2 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "46 0.03191 STAT1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "47 0.076585 STAT5B ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "48 0.005611 TBX2 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "49 -0.128551 TCF3 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "50 -0.102327 TP53 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "51 0.044001 USF1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "52 0.104471 YY1 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "53 -0.035432 ZBTB7A ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "54 0.08773 ZNF140 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "55 0.000388 ZNF682 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "56 0.114872 ZNF76 ZZZ3 netrem_no_intercept 0.404526 14.322422 \n", + "\n", + " alpha_lasso AbsoluteVal_coefficient Rank final_model_TFs \\\n", + "0 0.009565 NaN 57 56 \n", + "1 0.009565 0.092587 16 56 \n", + "2 0.009565 0.000920 54 56 \n", + "3 0.009565 0.050598 29 56 \n", + "4 0.009565 0.059361 25 56 \n", + "5 0.009565 0.179477 3 56 \n", + "6 0.009565 0.193458 2 56 \n", + "7 0.009565 0.032772 37 56 \n", + "8 0.009565 0.118892 6 56 \n", + "9 0.009565 0.079737 19 56 \n", + "10 0.009565 0.043963 32 56 \n", + "11 0.009565 0.009189 50 56 \n", + "12 0.009565 0.118487 7 56 \n", + "13 0.009565 0.057439 26 56 \n", + "14 0.009565 0.109527 10 56 \n", + "15 0.009565 0.014876 46 56 \n", + "16 0.009565 0.068512 23 56 \n", + "17 0.009565 0.012554 47 56 \n", + "18 0.009565 0.021563 42 56 \n", + "19 0.009565 0.004856 53 56 \n", + "20 0.009565 0.103236 12 56 \n", + "21 0.009565 0.028747 40 56 \n", + "22 0.009565 0.099127 15 56 \n", + "23 0.009565 0.033372 36 56 \n", + "24 0.009565 0.169403 4 56 \n", + "25 0.009565 0.102550 13 56 \n", + "26 0.009565 0.021933 41 56 \n", + "27 0.009565 0.017550 44 56 \n", + "28 0.009565 0.009942 48 56 \n", + "29 0.009565 0.040560 34 56 \n", + "30 0.009565 0.040835 33 56 \n", + "31 0.009565 0.007102 51 56 \n", + "32 0.009565 0.009594 49 56 \n", + "33 0.009565 0.000353 56 56 \n", + "34 0.009565 0.115948 8 56 \n", + "35 0.009565 0.060035 24 56 \n", + "36 0.009565 0.051793 28 56 \n", + "37 0.009565 0.089946 17 56 \n", + "38 0.009565 0.053255 27 56 \n", + "39 0.009565 0.044984 30 56 \n", + "40 0.009565 0.194475 1 56 \n", + "41 0.009565 0.069117 22 56 \n", + "42 0.009565 0.031496 39 56 \n", + "43 0.009565 0.074904 21 56 \n", + "44 0.009565 0.021260 43 56 \n", + "45 0.009565 0.015840 45 56 \n", + "46 0.009565 0.031910 38 56 \n", + "47 0.009565 0.076585 20 56 \n", + "48 0.009565 0.005611 52 56 \n", + "49 0.009565 0.128551 5 56 \n", + "50 0.009565 0.102327 14 56 \n", + "51 0.009565 0.044001 31 56 \n", + "52 0.009565 0.104471 11 56 \n", + "53 0.009565 0.035432 35 56 \n", + "54 0.009565 0.087730 18 56 \n", + "55 0.009565 0.000388 55 56 \n", + "56 0.009565 0.114872 9 56 \n", + "\n", + " TFs_input_to_model original_TFs_in_X \n", + "0 77 77 \n", + "1 77 77 \n", + "2 77 77 \n", + "3 77 77 \n", + "4 77 77 \n", + "5 77 77 \n", + "6 77 77 \n", + "7 77 77 \n", + "8 77 77 \n", + "9 77 77 \n", + "10 77 77 \n", + "11 77 77 \n", + "12 77 77 \n", + "13 77 77 \n", + "14 77 77 \n", + "15 77 77 \n", + "16 77 77 \n", + "17 77 77 \n", + "18 77 77 \n", + "19 77 77 \n", + "20 77 77 \n", + "21 77 77 \n", + "22 77 77 \n", + "23 77 77 \n", + "24 77 77 \n", + "25 77 77 \n", + "26 77 77 \n", + "27 77 77 \n", + "28 77 77 \n", + "29 77 77 \n", + "30 77 77 \n", + "31 77 77 \n", + "32 77 77 \n", + "33 77 77 \n", + "34 77 77 \n", + "35 77 77 \n", + "36 77 77 \n", + "37 77 77 \n", + "38 77 77 \n", + "39 77 77 \n", + "40 77 77 \n", + "41 77 77 \n", + "42 77 77 \n", + "43 77 77 \n", + "44 77 77 \n", + "45 77 77 \n", + "46 77 77 \n", + "47 77 77 \n", + "48 77 77 \n", + "49 77 77 \n", + "50 77 77 \n", + "51 77 77 \n", + "52 77 77 \n", + "53 77 77 \n", + "54 77 77 \n", + "55 77 77 \n", + "56 77 77 " + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netCV_ex2.combined_df" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "b99f60fa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "We input N = 77 candidate TFs as our predictors, X, for this prediction, of which 56 TFs were selected as optimal for our target gene (TG): ZZZ3.\n" + ] + } + ], + "source": [ + "print(f\"We input N = {num_candidate_TFs_for_TG} candidate TFs as our predictors, X, for this prediction\", end = \"\")\n", + "print(f\", of which {netCV_ex2.num_final_predictors} TFs were selected as optimal for our target gene (TG): {tg}.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "fd3deadd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_interceptBACH1BCL6CCNT2CTCFE2F3E4F1EBF1EGR1ELF1...YY1ZBTB7AZFP28ZFP82ZNF136ZNF140ZNF274ZNF281ZNF682ZNF76
0None0.0925870.000920.050598-0.0593610.179477-0.193458-0.0327720.00.118892...0.104471-0.0354320.00.00.00.087730.00.00.0003880.114872
\n", + "

1 rows × 78 columns

\n", + "
" + ], + "text/plain": [ + " y_intercept BACH1 BCL6 CCNT2 CTCF E2F3 E4F1 \\\n", + "0 None 0.092587 0.00092 0.050598 -0.059361 0.179477 -0.193458 \n", + "\n", + " EBF1 EGR1 ELF1 ... YY1 ZBTB7A ZFP28 ZFP82 ZNF136 \\\n", + "0 -0.032772 0.0 0.118892 ... 0.104471 -0.035432 0.0 0.0 0.0 \n", + "\n", + " ZNF140 ZNF274 ZNF281 ZNF682 ZNF76 \n", + "0 0.08773 0.0 0.0 0.000388 0.114872 \n", + "\n", + "[1 rows x 78 columns]" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netCV_ex2.model_coef_df # all of the N predictors. 1 column is added due to y_intercept term. " + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "4457b6fb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_interceptBACH1BCL6CCNT2CTCFE2F3E4F1EBF1ELF1ERF...STAT5BTBX2TCF3TP53USF1YY1ZBTB7AZNF140ZNF682ZNF76
0None0.0925870.000920.050598-0.0593610.179477-0.193458-0.0327720.118892-0.079737...0.0765850.005611-0.128551-0.1023270.0440010.104471-0.0354320.087730.0003880.114872
\n", + "

1 rows × 57 columns

\n", + "
" + ], + "text/plain": [ + " y_intercept BACH1 BCL6 CCNT2 CTCF E2F3 E4F1 \\\n", + "0 None 0.092587 0.00092 0.050598 -0.059361 0.179477 -0.193458 \n", + "\n", + " EBF1 ELF1 ERF ... STAT5B TBX2 TCF3 TP53 \\\n", + "0 -0.032772 0.118892 -0.079737 ... 0.076585 0.005611 -0.128551 -0.102327 \n", + "\n", + " USF1 YY1 ZBTB7A ZNF140 ZNF682 ZNF76 \n", + "0 0.044001 0.104471 -0.035432 0.08773 0.000388 0.114872 \n", + "\n", + "[1 rows x 57 columns]" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netCV_ex2.model_nonzero_coef_df # the final # of non-zero predictors. 1 column is added due to y_intercept term. " + ] + }, + { + "cell_type": "markdown", + "id": "2daa8e81", + "metadata": {}, + "source": [ + "#### Option 3:\n", + "Option 3 shows how the user may add additional paramters to netremCV to consider as it determines the optimal *beta_net* $\\beta_{net}$ and *alpha_lasso* $\\alpha_{lasso}$ values via cross-validation. We can set searchVerbosity = 1, if we want to avoid printing out the outputs of the searchCV. " + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "a191c8f6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) using variance to define beta_net values\n", + "beta_min = 0.14322421928177426 and beta_max = 14.322421928177425\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "32a26343987e497ab96d6a97a55e6529", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + ":) Generating beta_net and alpha_lasso pairs: 0%| | 0/50 [00:00#sk-container-id-5 {color: black;background-color: white;}#sk-container-id-5 pre{padding: 0;}#sk-container-id-5 div.sk-toggleable {background-color: white;}#sk-container-id-5 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-5 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-5 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-5 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-5 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-5 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-5 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-5 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-5 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-5 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-5 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-5 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-5 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-5 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-5 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-5 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-5 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-5 div.sk-item {position: relative;z-index: 1;}#sk-container-id-5 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-5 div.sk-item::before, #sk-container-id-5 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-5 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-5 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-5 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-5 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-5 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-5 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-5 div.sk-label-container {text-align: center;}#sk-container-id-5 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-5 div.sk-text-repr-fallback {display: none;}
NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=True, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=0.9383027608540463, alpha_lasso=0.009564951400513843, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C46E87400>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=True, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=0.9383027608540463, alpha_lasso=0.009564951400513843, network=)" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "\n", + "netCV_ex3 = nm.netremCV(edge_list = filtered_ppi_for_TG, X = X_train, y = y_train, reduced_cv_search = True,\n", + " y_intercept = True, searchVerbosity = 1)\n", + "netCV_ex3" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "15372a52", + "metadata": {}, + "source": [ + "![netCV_ex3.png](../user_guide/pics/netCV_ex3.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "187edd9d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) # of final TFs in the model for TG ZZZ3: 53\n", + "Training MSE: 0.44467536404146185\n", + "Testing MSE: 0.7517263006549427\n" + ] + } + ], + "source": [ + "print(f\":) # of final TFs in the model for TG {tg}: {netCV_ex3.num_final_predictors}\")\n", + "mse_train = netCV_ex3.test_mse(X_train, y_train)\n", + "mse_test = netCV_ex3.test_mse(X_test, y_test)\n", + "print(f\"Training MSE: {mse_train}\")\n", + "print(f\"Testing MSE: {mse_test}\")" + ] + }, + { + "cell_type": "markdown", + "id": "41a83fee", + "metadata": {}, + "source": [ + "### Example 1d: \n", + "#### Using Bayesian Optimization and Gaussian Processes to determine the optimal *beta_net* $\\beta_{net}$ and *alpha_lasso* $\\alpha_{lasso}$. Here, we can use the default range of values checked for $\\beta_{net}$ and $\\alpha_{lasso}$. \n", + "\n", + "In *Example 2c*, we will show how these values can be adjusted by the user based on intuition to improve performance. :)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "8159e12d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using beta_net default of 1\n", + "using alpha_lasso default of 0.01\n", + ":) Please note that we are running: optimal_netrem_model_via_bayesian_param_tuner\n", + "alpha_lasso = 0.05632616797779373 ; beta_network = 1000.0\n", + "{'info': 'NetREm Model', 'alpha_lasso': 0.05632616797779373, 'beta_net': 1, 'y_intercept': True, 'model_type': 'Lasso', 'max_lasso_iterations': 10000, 'network': , 'verbose': False, 'all_pos_coefs': False, 'model_info': 'fitted_model :)', 'target_gene_y': 'ZZZ3', 'tolerance': 0.0001, 'lasso_selection': 'cyclic'}\n", + "CPU times: total: 18.8 s\n", + "Wall time: 50.1 s\n" + ] + }, + { + "data": { + "text/html": [ + "
NetREmModel(info=NetREm Model, verbose=False, all_pos_coefs=False, model_type=Lasso, y_intercept=True, max_lasso_iterations=10000, model_info=fitted_model :), target_gene_y=ZZZ3, tolerance=0.0001, lasso_selection=cyclic, beta_net=1, alpha_lasso=0.05632616797779373, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C48522830>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(info=NetREm Model, verbose=False, all_pos_coefs=False, model_type=Lasso, y_intercept=True, max_lasso_iterations=10000, model_info=fitted_model :), target_gene_y=ZZZ3, tolerance=0.0001, lasso_selection=cyclic, beta_net=1, alpha_lasso=0.05632616797779373, network=)" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "\n", + "netrem_bayes_demo1 = nm.netrem(edge_list = filtered_ppi_for_TG, \n", + " y_intercept = True)\n", + "\n", + "bayesian_netty = nm_eval.optimal_netrem_model_via_bayesian_param_tuner(netrem_bayes_demo1, X_train, y_train)\n", + "bayesian_net_model = bayesian_netty[\"optimal_model\"]\n", + "bayesian_net_model" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "8efc388a", + "metadata": {}, + "source": [ + "![bayesian_net_model.png](../user_guide/pics/bayesian_net_model.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "68ea9665", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) # of final TFs in the model for TG ZZZ3: 17\n", + "Training MSE: 0.5442961386563945\n", + "Testing MSE: 0.6919347461250936\n" + ] + } + ], + "source": [ + "print(f\":) # of final TFs in the model for TG {tg}: {bayesian_net_model.num_final_predictors}\")\n", + "mse_train = bayesian_net_model.test_mse(X_train, y_train)\n", + "mse_test = bayesian_net_model.test_mse(X_test, y_test)\n", + "print(f\"Training MSE: {mse_train}\")\n", + "print(f\"Testing MSE: {mse_test}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "92b733b9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_interceptBACH1E2F3ELF1FOXO1FOXP1MAFMAXNFIBNFKB1NR3C1NR6A1RFX3RREB1SETDB1STAT5BYY1ZNF682
0-0.1074520.1109690.0119360.1084070.0051260.025120.0533240.0205180.108520.0806910.0317760.0000450.0376260.0192530.1107980.0305870.014130.005165
\n", + "
" + ], + "text/plain": [ + " y_intercept BACH1 E2F3 ELF1 FOXO1 FOXP1 MAF \\\n", + "0 -0.107452 0.110969 0.011936 0.108407 0.005126 0.02512 0.053324 \n", + "\n", + " MAX NFIB NFKB1 NR3C1 NR6A1 RFX3 RREB1 \\\n", + "0 0.020518 0.10852 0.080691 0.031776 0.000045 0.037626 0.019253 \n", + "\n", + " SETDB1 STAT5B YY1 ZNF682 \n", + "0 0.110798 0.030587 0.01413 0.005165 " + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bayesian_net_model.model_nonzero_coef_df # the final # of non-zero predictors. 1 column is added due to y_intercept term. " + ] + }, + { + "cell_type": "markdown", + "id": "ad672132", + "metadata": {}, + "source": [ + "## Example 2️⃣\n", + "### involves more input from the user🥈🥼🧪\n" + ] + }, + { + "cell_type": "markdown", + "id": "62315325", + "metadata": {}, + "source": [ + "### Example 2a: \n", + "#### using user-defined values for *beta_net* $\\beta_{net}$ and *alpha_lasso* $\\alpha_{lasso}$ ." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "5ba43fe5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) # of final TFs in the model for TG ZZZ3: 75\n", + "Training MSE: 0.36146345048829703\n", + "Testing MSE: 0.9005579183195876\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgMAAAGFCAYAAABg2vAPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy88F64QAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOyddVhU2RvHvzMMjWJig9gKBmJgrIGg2C26dqzd3d2uP3ttUVm7Vl07sHHFrrW7MEGkZ+b7++MylxkmGMJ1V+/nee4Dc+655557Z+4973nPGzKShISEhISEhMQPi/xbd0BCQkJCQkLi2yIJAxISEhISEj84kjAgISEhISHxgyMJAxISEhISEj84kjAgISEhISHxgyMJAxISEhISEj84kjAgISEhISHxgyMJAxISEhISEj84kjAgISEhISHxgyMJAxISEhISEj84kjAgISEhISHxgyMJAxISEhISEj84kjAgISEhISHxgyMJAxISEhISEj84kjAgISEhISHxgyMJAxISEhISEj84kjAgISEhISHxgyMJAxISEhISEj84kjAgISEhISHxgyMJAxISEhISEj84kjAgISEhISHxgyMJAxISEhISEj84kjAgISEhISHxgyMJAxISEhISEj84kjAgISEhISHxgyMJAxISEhISEj84kjAgISEhISHxg6P41h2QkJCQSOQLgAcAYgFYAygEwOGb9khC4kdAEgYkJCS+MbcBLAOwH8AjANTaJwNQAEA9AD0BlPjHeych8SMgI8nkq0lISEikN48B9ABwBMK8RGmirma/L4DlAFy/eu8kJH4kJGFA4gdGUkl/O1YB6AdhgDclBCRFkbAtAtDtK/RLQuLHRBIGJH4wJJX0t2cagLHp0M5UAGPSoR0JCQlJGJD4QZBU0v8OVgH4JZ3b65qO7UlI/JhIwoDED4Ckkv538BiCtiUmHdu0gaDtkQQ2CYm0IMUZkPjOmQZhJhqDlAkCSKgfk3D8tHTu138bmUyW7DZx4sQkdQtAJouBTAbIZEC2bIntTZwIsVwmA6ysAFdXYMAAICxM99xXrgBNmgC5cwN2djEoVswdkydPRlRUlFhHpVLhf//7H/z8/JA3b17Y2dmhePHiGDlyJMKSNighISG5Fkp8z6xC+qxNI6GdnPjWKmmVSoXY2FioVCpYWFjAzs7OaN3IyEjcu3cPb968gUql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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fixed_netrem_2a = nm.netrem(edge_list = filtered_ppi_for_TG, \n", + " beta_net = 3,\n", + " alpha_lasso = 0.001,\n", + " view_network = True) # recommended that view_network = False since this is sadly a hairball! ☹️\n", + "fixed_netrem_2a.fit(X_train, y_train)\n", + "mse_train = fixed_netrem_2a.test_mse(X_train, y_train)\n", + "mse_test = fixed_netrem_2a.test_mse(X_test, y_test)\n", + "print(f\":) # of final TFs in the model for TG {tg}: {fixed_netrem_2a.num_final_predictors}\")\n", + "print(f\"Training MSE: {mse_train}\")\n", + "print(f\"Testing MSE: {mse_test}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "c70725de", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
NetREmModel(verbose=False, overlapped_nodes_only=False, all_pos_coefs=False, model_type=Lasso, use_network=True, y_intercept=False, max_lasso_iterations=10000, view_network=True, tolerance=0.0001, lasso_selection=cyclic, beta_net=3, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C46E946A0>, alpha_lasso=0.001)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(verbose=False, overlapped_nodes_only=False, all_pos_coefs=False, model_type=Lasso, use_network=True, y_intercept=False, max_lasso_iterations=10000, view_network=True, tolerance=0.0001, lasso_selection=cyclic, beta_net=3, network=, alpha_lasso=0.001)" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fixed_netrem_2a" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "0c3c702a", + "metadata": {}, + "source": [ + "![fixed_netrem_2a.png](../user_guide/pics/fixed_netrem_2a.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "00e7a6ec", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_interceptBACH1BCL6CCNT2CTCFE2F3E4F1EBF1EGR1ELF1...USF2YY1ZBTB7AZFP28ZNF136ZNF140ZNF274ZNF281ZNF682ZNF76
0None0.096596-0.0092370.085396-0.0832710.225887-0.42595-0.07387-0.0768010.112941...-0.1198740.165508-0.054092-0.1270780.1177170.14481-0.0759690.0534240.0000310.220575
\n", + "

1 rows × 76 columns

\n", + "
" + ], + "text/plain": [ + " y_intercept BACH1 BCL6 CCNT2 CTCF E2F3 E4F1 \\\n", + "0 None 0.096596 -0.009237 0.085396 -0.083271 0.225887 -0.42595 \n", + "\n", + " EBF1 EGR1 ELF1 ... USF2 YY1 ZBTB7A ZFP28 \\\n", + "0 -0.07387 -0.076801 0.112941 ... -0.119874 0.165508 -0.054092 -0.127078 \n", + "\n", + " ZNF136 ZNF140 ZNF274 ZNF281 ZNF682 ZNF76 \n", + "0 0.117717 0.14481 -0.075969 0.053424 0.000031 0.220575 \n", + "\n", + "[1 rows x 76 columns]" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fixed_netrem_2a.model_nonzero_coef_df # the final # of non-zero predictors. 1 column is added due to y_intercept term. " + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "93f93b49", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
coefTFTGinfotrain_msebeta_netalpha_lassoAbsoluteVal_coefficientRankfinal_model_TFsTFs_input_to_modeloriginal_TFs_in_X
0Noney_interceptZZZ3netrem_no_intercept0.36146330.001NaN76757777
10.096596BACH1ZZZ3netrem_no_intercept0.36146330.0010.09659634757777
2-0.009237BCL6ZZZ3netrem_no_intercept0.36146330.0010.00923768757777
30.085396CCNT2ZZZ3netrem_no_intercept0.36146330.0010.08539638757777
4-0.083271CTCFZZZ3netrem_no_intercept0.36146330.0010.08327140757777
.......................................
710.14481ZNF140ZZZ3netrem_no_intercept0.36146330.0010.14481019757777
72-0.075969ZNF274ZZZ3netrem_no_intercept0.36146330.0010.07596943757777
730.053424ZNF281ZZZ3netrem_no_intercept0.36146330.0010.05342456757777
740.000031ZNF682ZZZ3netrem_no_intercept0.36146330.0010.00003175757777
750.220575ZNF76ZZZ3netrem_no_intercept0.36146330.0010.2205756757777
\n", + "

76 rows × 12 columns

\n", + "
" + ], + "text/plain": [ + " coef TF TG info train_mse beta_net \\\n", + "0 None y_intercept ZZZ3 netrem_no_intercept 0.361463 3 \n", + "1 0.096596 BACH1 ZZZ3 netrem_no_intercept 0.361463 3 \n", + "2 -0.009237 BCL6 ZZZ3 netrem_no_intercept 0.361463 3 \n", + "3 0.085396 CCNT2 ZZZ3 netrem_no_intercept 0.361463 3 \n", + "4 -0.083271 CTCF ZZZ3 netrem_no_intercept 0.361463 3 \n", + ".. ... ... ... ... ... ... \n", + "71 0.14481 ZNF140 ZZZ3 netrem_no_intercept 0.361463 3 \n", + "72 -0.075969 ZNF274 ZZZ3 netrem_no_intercept 0.361463 3 \n", + "73 0.053424 ZNF281 ZZZ3 netrem_no_intercept 0.361463 3 \n", + "74 0.000031 ZNF682 ZZZ3 netrem_no_intercept 0.361463 3 \n", + "75 0.220575 ZNF76 ZZZ3 netrem_no_intercept 0.361463 3 \n", + "\n", + " alpha_lasso AbsoluteVal_coefficient Rank final_model_TFs \\\n", + "0 0.001 NaN 76 75 \n", + "1 0.001 0.096596 34 75 \n", + "2 0.001 0.009237 68 75 \n", + "3 0.001 0.085396 38 75 \n", + "4 0.001 0.083271 40 75 \n", + ".. ... ... ... ... \n", + "71 0.001 0.144810 19 75 \n", + "72 0.001 0.075969 43 75 \n", + "73 0.001 0.053424 56 75 \n", + "74 0.001 0.000031 75 75 \n", + "75 0.001 0.220575 6 75 \n", + "\n", + " TFs_input_to_model original_TFs_in_X \n", + "0 77 77 \n", + "1 77 77 \n", + "2 77 77 \n", + "3 77 77 \n", + "4 77 77 \n", + ".. ... ... \n", + "71 77 77 \n", + "72 77 77 \n", + "73 77 77 \n", + "74 77 77 \n", + "75 77 77 \n", + "\n", + "[76 rows x 12 columns]" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fixed_netrem_2a.combined_df" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "110ae80f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
NetREmModel(verbose=False, overlapped_nodes_only=False, all_pos_coefs=False, model_type=Lasso, use_network=True, y_intercept=False, max_lasso_iterations=10000, view_network=True, tolerance=0.0001, lasso_selection=cyclic, beta_net=3, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C46E946A0>, alpha_lasso=0.001)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(verbose=False, overlapped_nodes_only=False, all_pos_coefs=False, model_type=Lasso, use_network=True, y_intercept=False, max_lasso_iterations=10000, view_network=True, tolerance=0.0001, lasso_selection=cyclic, beta_net=3, network=, alpha_lasso=0.001)" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fixed_netrem_2a" + ] + }, + { + "cell_type": "markdown", + "id": "4d6bb46d", + "metadata": {}, + "source": [ + "### Example 2b:\n", + "#### using user-defined values for *beta_net* $\\beta_{net}$ and LassoCV to find the optimal *alpha_lasso* .\n", + "This is the approach that Saniya utilized for NetREm for the paper :)📜👩‍🏫" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "02d053b4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) # of final TFs in the model for TG ZZZ3: 67\n", + "Training MSE: 0.40284765315234555\n", + "Testing MSE: 0.6833977664046426\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fixed_netrem_2b = nm.netrem(edge_list = filtered_ppi_for_TG, \n", + " beta_net = 100,\n", + " y_intercept = True,\n", + " default_edge_weight = 0.01,\n", + " degree_threshold = 0.5,\n", + " model_type = \"LassoCV\",\n", + " view_network = True)\n", + "fixed_netrem_2b.fit(X_train, y_train)\n", + "mse_train = fixed_netrem_2b.test_mse(X_train, y_train)\n", + "mse_test = fixed_netrem_2b.test_mse(X_test, y_test)\n", + "print(f\":) # of final TFs in the model for TG {tg}: {fixed_netrem_2b.num_final_predictors}\")\n", + "\n", + "print(f\"Training MSE: {mse_train}\")\n", + "print(f\"Testing MSE: {mse_test}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "ac2520c4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_interceptBACH1CCNT2CTCFE2F3E4F1EBF1ELF1ERFESR1...TP53USF1USF2YY1ZBTB7AZNF136ZNF140ZNF274ZNF682ZNF76
00.068770.0731280.060351-0.086670.174759-0.170537-0.0456440.130413-0.0824570.007668...-0.0898060.069805-0.0151880.113233-0.0225050.0560880.076585-0.0019090.001840.109638
\n", + "

1 rows × 68 columns

\n", + "
" + ], + "text/plain": [ + " y_intercept BACH1 CCNT2 CTCF E2F3 E4F1 EBF1 \\\n", + "0 0.06877 0.073128 0.060351 -0.08667 0.174759 -0.170537 -0.045644 \n", + "\n", + " ELF1 ERF ESR1 ... TP53 USF1 USF2 YY1 \\\n", + "0 0.130413 -0.082457 0.007668 ... -0.089806 0.069805 -0.015188 0.113233 \n", + "\n", + " ZBTB7A ZNF136 ZNF140 ZNF274 ZNF682 ZNF76 \n", + "0 -0.022505 0.056088 0.076585 -0.001909 0.00184 0.109638 \n", + "\n", + "[1 rows x 68 columns]" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fixed_netrem_2b.model_nonzero_coef_df # the final # of non-zero predictors. 1 column is added due to y_intercept term. " + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "00c53c75", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
coefTFTGinfotrain_msebeta_netalpha_lassoCVAbsoluteVal_coefficientRankfinal_model_TFsTFs_input_to_modeloriginal_TFs_in_X
00.068770y_interceptZZZ3netrem_with_intercept0.402848100Cross-Validation optimal alpha lasso: 0.004425...0.06877029677777
10.073128BACH1ZZZ3netrem_with_intercept0.402848100Cross-Validation optimal alpha lasso: 0.004425...0.07312827677777
20.060351CCNT2ZZZ3netrem_with_intercept0.402848100Cross-Validation optimal alpha lasso: 0.004425...0.06035134677777
3-0.086670CTCFZZZ3netrem_with_intercept0.402848100Cross-Validation optimal alpha lasso: 0.004425...0.08667019677777
40.174759E2F3ZZZ3netrem_with_intercept0.402848100Cross-Validation optimal alpha lasso: 0.004425...0.1747591677777
.......................................
630.056088ZNF136ZZZ3netrem_with_intercept0.402848100Cross-Validation optimal alpha lasso: 0.004425...0.05608835677777
640.076585ZNF140ZZZ3netrem_with_intercept0.402848100Cross-Validation optimal alpha lasso: 0.004425...0.07658525677777
65-0.001909ZNF274ZZZ3netrem_with_intercept0.402848100Cross-Validation optimal alpha lasso: 0.004425...0.00190966677777
660.001840ZNF682ZZZ3netrem_with_intercept0.402848100Cross-Validation optimal alpha lasso: 0.004425...0.00184067677777
670.109638ZNF76ZZZ3netrem_with_intercept0.402848100Cross-Validation optimal alpha lasso: 0.004425...0.10963810677777
\n", + "

68 rows × 12 columns

\n", + "
" + ], + "text/plain": [ + " coef TF TG info train_mse beta_net \\\n", + "0 0.068770 y_intercept ZZZ3 netrem_with_intercept 0.402848 100 \n", + "1 0.073128 BACH1 ZZZ3 netrem_with_intercept 0.402848 100 \n", + "2 0.060351 CCNT2 ZZZ3 netrem_with_intercept 0.402848 100 \n", + "3 -0.086670 CTCF ZZZ3 netrem_with_intercept 0.402848 100 \n", + "4 0.174759 E2F3 ZZZ3 netrem_with_intercept 0.402848 100 \n", + ".. ... ... ... ... ... ... \n", + "63 0.056088 ZNF136 ZZZ3 netrem_with_intercept 0.402848 100 \n", + "64 0.076585 ZNF140 ZZZ3 netrem_with_intercept 0.402848 100 \n", + "65 -0.001909 ZNF274 ZZZ3 netrem_with_intercept 0.402848 100 \n", + "66 0.001840 ZNF682 ZZZ3 netrem_with_intercept 0.402848 100 \n", + "67 0.109638 ZNF76 ZZZ3 netrem_with_intercept 0.402848 100 \n", + "\n", + " alpha_lassoCV \\\n", + "0 Cross-Validation optimal alpha lasso: 0.004425... \n", + "1 Cross-Validation optimal alpha lasso: 0.004425... \n", + "2 Cross-Validation optimal alpha lasso: 0.004425... \n", + "3 Cross-Validation optimal alpha lasso: 0.004425... \n", + "4 Cross-Validation optimal alpha lasso: 0.004425... \n", + ".. ... \n", + "63 Cross-Validation optimal alpha lasso: 0.004425... \n", + "64 Cross-Validation optimal alpha lasso: 0.004425... \n", + "65 Cross-Validation optimal alpha lasso: 0.004425... \n", + "66 Cross-Validation optimal alpha lasso: 0.004425... \n", + "67 Cross-Validation optimal alpha lasso: 0.004425... \n", + "\n", + " AbsoluteVal_coefficient Rank final_model_TFs TFs_input_to_model \\\n", + "0 0.068770 29 67 77 \n", + "1 0.073128 27 67 77 \n", + "2 0.060351 34 67 77 \n", + "3 0.086670 19 67 77 \n", + "4 0.174759 1 67 77 \n", + ".. ... ... ... ... \n", + "63 0.056088 35 67 77 \n", + "64 0.076585 25 67 77 \n", + "65 0.001909 66 67 77 \n", + "66 0.001840 67 67 77 \n", + "67 0.109638 10 67 77 \n", + "\n", + " original_TFs_in_X \n", + "0 77 \n", + "1 77 \n", + "2 77 \n", + "3 77 \n", + "4 77 \n", + ".. ... \n", + "63 77 \n", + "64 77 \n", + "65 77 \n", + "66 77 \n", + "67 77 \n", + "\n", + "[68 rows x 12 columns]" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fixed_netrem_2b.combined_df" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "84ae10b3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
NetREmModel(verbose=False, overlapped_nodes_only=False, num_cv_folds=5, num_jobs=-1, all_pos_coefs=False, model_type=LassoCV, use_network=True, y_intercept=True, max_lasso_iterations=10000, view_network=True, tolerance=0.0001, lasso_selection=cyclic, lassocv_eps=0.001, lassocv_n_alphas=100, lassocv_alphas=None, beta_net=100, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C6A39A6B0>, alpha_lasso=LassoCV finds optimal alpha)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(verbose=False, overlapped_nodes_only=False, num_cv_folds=5, num_jobs=-1, all_pos_coefs=False, model_type=LassoCV, use_network=True, y_intercept=True, max_lasso_iterations=10000, view_network=True, tolerance=0.0001, lasso_selection=cyclic, lassocv_eps=0.001, lassocv_n_alphas=100, lassocv_alphas=None, beta_net=100, network=, alpha_lasso=LassoCV finds optimal alpha)" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fixed_netrem_2b" + ] + }, + { + "attachments": { + "netrem_1b.png": { + "image/png": "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r1RGNm1Yp/8i0qptRwZEEBEREREREYXDpYtfy5ABfeSnH39U5XIVKknDJs3lueeeU2UiIiIiIiIiIiIiIiKiYMtfsLBj8UfAiQcJY8dyLEREFLP8+eef0rldK0kS73nJ9FZq6dG5vZz/6pz628svvyyDh4+W1u07MSCCiIiIiIiIyE93bt+WIf17y/GjR1Q5Tdq00r5zd0mWPLkqExEREREREREREREREUUlnPGAiIj8li9/AVm8co2079xNXnzxRb2WKLSQCPPLvXshWx4+fKg/iYiIiIiIKLT++OMPGTNiiGNGQST39x88gjMKEhERERERERERERERUciVL1nYsfiDiQdEROTTK4kSSbESpaTPgCFy8MQ52bh1txQuWlyeeYbdCEWcDWvXyBspk4RsmT55gv4kIiIiIiKi0EFS9bBB/WTurOmqjKSDEWMnSOVqNSRWLM4qS0RERERERERERERERKG1f+8ex+KPgCNG7z/+n2MhIqKYJU6cODJh6ky5/sM9Wb1hi/To01/ezZSZCQdERERERERE4RQ7dmwpU66CpEmbViUddO/dX2rXayjPPfecfgcRERERERERERERERFR1MPIUSIiIiIiIiIiIqIIglkNChQqIh9PmSlDRo6VNh06M+mAiIiIiIiIiIiIiIiIIszGrbsciz9i/c9Gvw6XB3/pF0REREREREREREREREREREREREREREREFC0keFG/sCDgxAOM0GW4/9j3pvDu//T/ExERERERERERERERERERERERERERERFRYBDJ/4z+f6uidOIBERERERERERERERERERERERERERERERFFvPIlC+tXIvv27NavfIu0xAN8qumfEhERERERERERERERERERERERERERERGRn/yJzU8YO+yN/qQSBJx48OAv/cJf2N//9P8TEREREREREREREREREREREREREREREZFfVNLBM3hhL/sS/RIPbJBV8R++qC4TEREREREREREREREREREREREREREREZFvSAR4JpY9+cCq/Xt361ci5UoU1q98i9TEAwVZBwHtARERERERERERERERERERERERERERERHR0wMh+JgIIJBY/AQv6hcWBJx4EEvtrd39xwFmEOgvbmwlbMtERERERERERERERERERERERERERERERE8fp/h62/+osPsAQ/ch+iYeEBERERERERERERERERERERERERERERFRSJQvWVi/Etm3Z7d+5VvAiQcvvviixE+QQF5+Ob6cunBFryUiIiIiIiIiIiIiIiIiIiIiIiIiIiIioqgkYWz7xAMvvPCC/PXXX+q1FQEnHvxm+yzOc0BEREREREREREREREREREREREREREREFLWlTZ5QHjx4IGnSpJHvvvtOr/Ut4MSDP/5P5J//dIGIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiKKsry+cl/t3f5LSJYrpNb49o/8/3J6zbeH7776T/r276zVERERERERERERERERERERERERERERERBQVZXw3kxQtaj3pAAKe8eDhw4eSMmVK+e233+T+44A2RUREREREREREREREREREREREREREREREIfLg/n1JkDChxH9BJFYsvdKCgGc8iBcvnvTq1UuXiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIgoKnov01vyzVen/Eo6gIATD6Br165SpmxZXSIiIiIiIiIiIiIiIiIiIiIiIiIiIiIioqgmY4YMki1LJl2yLtb/bPTrgPzfP//Ko3+f1SUiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIopK/npwR5IlS6ZL1gVlxgN4/rln5eUXbBuMJTJ7xlRJGDuWWmpXrajfIdKwTnXH+vWfr9Zrud7A9XZcb8f1dlxv97Stb1C7ml/v53q7p2H9hrVr9NrgbT8U9e1p3s/IWs/zaBfIdszrY9J++vu5Vt7v7/EJxX4G63P9XR+T9jMqnMeotp/m9ebt+Pt+T/sTyPv9/dxg7ad5O0/zfnraTiD76Wk73E/r74+s/eTxseN+2lnZfrD208r6mLSfoT6P5vd72h8r7+d6rud6u1Cs5/UYvvWhOG6e2ttgbT8q7E9UO26e9ieQ/bTSbwZrP/3dTqj3x8p++nt8zOv9/Vzzek/biaz9sbKfgexPsPbTyvYjcj/93U6o94fHzY7r7bjejuvtuN6O6+243o7r7bjejuvtuN6O6+2i+/oMr6dQ69K9lkivscf5P/N/D8OVdABBSzwA7EzcZ/+Tm9cv6zUiRYqX1K+IiIiIiIiIiIiIiIiIiIiIiIiIiIiIiCiU0qRNp/7//q+/yoJ5s+WFZ0Veel7k5Xjx1PrwCGriATz77DMyadIkuXr1qowfP14qV66sEhKIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiCi08ubNJ5UqVVLx/FUrlpU4z9knGQhErP/Z6NdEREREREREREREREREREREREREREREREROgj7jARERERERERERERERERERERERERERERERxRxMPCAiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIo+YeEBERERERERERERERERERERERERERERERB4x8YCIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiDxi4gEREREREREREREREREREREREREREREREXnExAMiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIvKIiQdEREREREREREREREREREREREREREREROQREw+IiIiIiIiIiIiIiIiIiIiIiIiIiIiIiMgjJh4QEREREREREREREREREREREREREREREZFHTDwgIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiKPmHhAREREREREREREREREREREREREREREREQeMfGAiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIg8YuIBERERERERERERERERERERERERERERERF5IPL/SuZojLg4YF4AAAAASUVORK5CYII=" + } + }, + "cell_type": "markdown", + "id": "ea2faab5", + "metadata": {}, + "source": [ + "![netrem_1b.png](attachment:netrem_1b.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "dc687e29", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['info', 'verbose', 'overlapped_nodes_only', 'num_cv_folds', 'num_jobs', 'all_pos_coefs', 'model_type', 'use_network', 'y_intercept', 'max_lasso_iterations', 'view_network', 'model_info', 'target_gene_y', 'tolerance', 'lasso_selection', 'lassocv_eps', 'lassocv_n_alphas', 'lassocv_alphas', 'beta_net', 'network', 'alpha_lasso', 'optimal_alpha', 'prior_network', 'preprocessed_network', 'network_params', 'network_nodes_list', 'kwargs', 'X_df', 'gene_expression_nodes', 'common_nodes', 'final_nodes', 'gexpr_nodes_added', 'gexpr_nodes_to_add_for_net', 'filter_network_bool', 'A_df', 'A', 'nodes', 'network_info', 'M', 'N', 'X_train', 'y_train', 'B_train', 'B_interaction_df', 'B_train_times_M', 'X_tilda_train', 'y_tilda_train', 'X_training_to_use', 'y_training_to_use', 'regr', 'final_alpha', 'coef', 'intercept', 'predY_tilda_train', 'mse_tilda_train', 'predY_train', 'mse_train', 'model_coef_df', 'model_nonzero_coef_df', 'sorted_coef_df', 'corr_vs_coef_df', 'final_corr_vs_coef_df', 'combined_df', 'num_final_predictors'])" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vars(fixed_netrem_2b).keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "6d1f1c81", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'info': 'NetREm Model',\n", + " 'alpha_lasso': 'LassoCV finds optimal alpha',\n", + " 'beta_net': 100,\n", + " 'y_intercept': True,\n", + " 'model_type': 'LassoCV',\n", + " 'max_lasso_iterations': 10000,\n", + " 'network': ,\n", + " 'verbose': False,\n", + " 'all_pos_coefs': False,\n", + " 'model_info': 'fitted_model :)',\n", + " 'target_gene_y': 'ZZZ3',\n", + " 'num_cv_folds': 5,\n", + " 'num_jobs': -1,\n", + " 'lassocv_eps': 0.001,\n", + " 'lassocv_n_alphas': 100,\n", + " 'lassocv_alphas': None,\n", + " 'optimal_alpha': 'Cross-Validation optimal alpha lasso: 0.004425278133386773',\n", + " 'tolerance': 0.0001,\n", + " 'lasso_selection': 'cyclic'}" + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fixed_netrem_2b.get_params()" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "id": "668bfe5a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
infoinput_dataBACH1CCNT2CTCFE2F3E4F1EBF1ELF1ERF...TP53USF1USF2YY1ZBTB7AZNF136ZNF140ZNF274ZNF682ZNF76
0network regression coeff. with y: ZZZ3X_train0.0731280.060351-0.0866700.174759-0.170537-0.0456440.130413-0.082457...-0.0898060.069805-0.0151880.113233-0.0225050.0560880.076585-0.0019090.0018400.109638
0corr (r) with y: ZZZ3X_train0.1910810.134249-0.0534870.160718-0.046865-0.0471600.207914-0.091996...-0.0651730.085353-0.0254910.119843-0.124585-0.0124450.132537-0.0000890.1297380.124608
0Absolute Value NetREm Coefficient RankingX_train27.00000034.00000019.0000001.0000003.00000041.0000007.00000021.000000...18.00000028.00000058.0000009.00000050.00000035.00000025.00000066.00000067.00000010.000000
\n", + "

3 rows × 69 columns

\n", + "
" + ], + "text/plain": [ + " info input_data BACH1 CCNT2 \\\n", + "0 network regression coeff. with y: ZZZ3 X_train 0.073128 0.060351 \n", + "0 corr (r) with y: ZZZ3 X_train 0.191081 0.134249 \n", + "0 Absolute Value NetREm Coefficient Ranking X_train 27.000000 34.000000 \n", + "\n", + " CTCF E2F3 E4F1 EBF1 ELF1 ERF ... \\\n", + "0 -0.086670 0.174759 -0.170537 -0.045644 0.130413 -0.082457 ... \n", + "0 -0.053487 0.160718 -0.046865 -0.047160 0.207914 -0.091996 ... \n", + "0 19.000000 1.000000 3.000000 41.000000 7.000000 21.000000 ... \n", + "\n", + " TP53 USF1 USF2 YY1 ZBTB7A ZNF136 ZNF140 \\\n", + "0 -0.089806 0.069805 -0.015188 0.113233 -0.022505 0.056088 0.076585 \n", + "0 -0.065173 0.085353 -0.025491 0.119843 -0.124585 -0.012445 0.132537 \n", + "0 18.000000 28.000000 58.000000 9.000000 50.000000 35.000000 25.000000 \n", + "\n", + " ZNF274 ZNF682 ZNF76 \n", + "0 -0.001909 0.001840 0.109638 \n", + "0 -0.000089 0.129738 0.124608 \n", + "0 66.000000 67.000000 10.000000 \n", + "\n", + "[3 rows x 69 columns]" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fixed_netrem_2b.final_corr_vs_coef_df" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "id": "8cdcad59", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TF1TF2B_train_weightsignpotential_interactionabsVal_Binfocandidate_TFs_Ntarget_gene_ynum_final_predictorsmodel_typebeta_netgene_datarankpercentile
1028NFIBFOXO11.118503:):(1.118503B matrix of TF-TF interactions77ZZZ367LassoCV100training gene expression data1.099.982912
2092FOXO1NFIB1.118503:):(1.118503B matrix of TF-TF interactions77ZZZ367LassoCV100training gene expression data1.099.982912
4416NFIBSREBF20.956989:):(0.956989B matrix of TF-TF interactions77ZZZ367LassoCV100training gene expression data3.099.948735
2136SREBF2NFIB0.956989:):(0.956989B matrix of TF-TF interactions77ZZZ367LassoCV100training gene expression data3.099.948735
1046RORAFOXO10.928125:):(0.928125B matrix of TF-TF interactions77ZZZ367LassoCV100training gene expression data5.099.914559
................................................
3834TCF3RXRB-0.000012:(:( competitive (-)0.000012B matrix of TF-TF interactions77ZZZ367LassoCV100training gene expression data5848.00.068353
2784ESRRAPML-0.000010:(:( competitive (-)0.000010B matrix of TF-TF interactions77ZZZ367LassoCV100training gene expression data5849.00.051265
960PMLESRRA-0.000010:(:( competitive (-)0.000010B matrix of TF-TF interactions77ZZZ367LassoCV100training gene expression data5849.00.051265
4708ESR2TCF3-0.000009:(:( competitive (-)0.000009B matrix of TF-TF interactions77ZZZ367LassoCV100training gene expression data5851.00.017088
908TCF3ESR2-0.000009:(:( competitive (-)0.000009B matrix of TF-TF interactions77ZZZ367LassoCV100training gene expression data5852.00.000000
\n", + "

5852 rows × 15 columns

\n", + "
" + ], + "text/plain": [ + " TF1 TF2 B_train_weight sign potential_interaction absVal_B \\\n", + "1028 NFIB FOXO1 1.118503 :) :( 1.118503 \n", + "2092 FOXO1 NFIB 1.118503 :) :( 1.118503 \n", + "4416 NFIB SREBF2 0.956989 :) :( 0.956989 \n", + "2136 SREBF2 NFIB 0.956989 :) :( 0.956989 \n", + "1046 RORA FOXO1 0.928125 :) :( 0.928125 \n", + "... ... ... ... ... ... ... \n", + "3834 TCF3 RXRB -0.000012 :( :( competitive (-) 0.000012 \n", + "2784 ESRRA PML -0.000010 :( :( competitive (-) 0.000010 \n", + "960 PML ESRRA -0.000010 :( :( competitive (-) 0.000010 \n", + "4708 ESR2 TCF3 -0.000009 :( :( competitive (-) 0.000009 \n", + "908 TCF3 ESR2 -0.000009 :( :( competitive (-) 0.000009 \n", + "\n", + " info candidate_TFs_N target_gene_y \\\n", + "1028 B matrix of TF-TF interactions 77 ZZZ3 \n", + "2092 B matrix of TF-TF interactions 77 ZZZ3 \n", + "4416 B matrix of TF-TF interactions 77 ZZZ3 \n", + "2136 B matrix of TF-TF interactions 77 ZZZ3 \n", + "1046 B matrix of TF-TF interactions 77 ZZZ3 \n", + "... ... ... ... \n", + "3834 B matrix of TF-TF interactions 77 ZZZ3 \n", + "2784 B matrix of TF-TF interactions 77 ZZZ3 \n", + "960 B matrix of TF-TF interactions 77 ZZZ3 \n", + "4708 B matrix of TF-TF interactions 77 ZZZ3 \n", + "908 B matrix of TF-TF interactions 77 ZZZ3 \n", + "\n", + " num_final_predictors model_type beta_net \\\n", + "1028 67 LassoCV 100 \n", + "2092 67 LassoCV 100 \n", + "4416 67 LassoCV 100 \n", + "2136 67 LassoCV 100 \n", + "1046 67 LassoCV 100 \n", + "... ... ... ... \n", + "3834 67 LassoCV 100 \n", + "2784 67 LassoCV 100 \n", + "960 67 LassoCV 100 \n", + "4708 67 LassoCV 100 \n", + "908 67 LassoCV 100 \n", + "\n", + " gene_data rank percentile \n", + "1028 training gene expression data 1.0 99.982912 \n", + "2092 training gene expression data 1.0 99.982912 \n", + "4416 training gene expression data 3.0 99.948735 \n", + "2136 training gene expression data 3.0 99.948735 \n", + "1046 training gene expression data 5.0 99.914559 \n", + "... ... ... ... \n", + "3834 training gene expression data 5848.0 0.068353 \n", + "2784 training gene expression data 5849.0 0.051265 \n", + "960 training gene expression data 5849.0 0.051265 \n", + "4708 training gene expression data 5851.0 0.017088 \n", + "908 training gene expression data 5852.0 0.000000 \n", + "\n", + "[5852 rows x 15 columns]" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b_matrix_2b = nm.organize_B_interaction_network(fixed_netrem_2b)\n", + "b_matrix_2b" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "6e31ad77", + "metadata": {}, + "source": [ + "### Example 2c: \n", + "#### using GridSearchCV for comprehensive hyperparameter optimization🧮 for *beta_net* $\\beta_{net}$ and *alpha_lasso* $\\alpha_{lasso}$ ." + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "id": "1c6d089c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using beta_net default of 1\n", + "using alpha_lasso default of 0.01\n", + "Fitting 5 folds for each of 208 candidates, totalling 1040 fits\n", + "CPU times: total: 10.6 s\n", + "Wall time: 26.6 s\n" + ] + }, + { + "data": { + "text/html": [ + "
GridSearchCV(cv=5,\n",
+       "             estimator=NetREmModel(all_pos_coefs=False, alpha_lasso=0.01, beta_net=1, info='NetREm Model', lasso_selection='cyclic', max_lasso_iterations=10000, model_info='unfitted_model :(', model_type='Lasso', network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C71577C10>, target_gene_y='Unknown :(', tolerance=0.0001, verbose=False, y_intercept=False),\n",
+       "             n_jobs=-1,\n",
+       "             param_grid={'alpha_lasso': [1e-05, 1e-05, 1e-08, 0.0001, 0.005,\n",
+       "                                         0.001, 1e-09, 0.002, 0.1, 0.0023559,\n",
+       "                                         0.003, 0.005, 0.01],\n",
+       "                         'beta_net': [1e-06, 3, 0.1, 0.05, 1e-07, 5e-06, 0.01,\n",
+       "                                      0.001, 0.2, 0.4, 0.5, 0.6, 0.8, 5, 1,\n",
+       "                                      2]},\n",
+       "             verbose=10)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "GridSearchCV(cv=5,\n", + " estimator=NetREmModel(all_pos_coefs=False, alpha_lasso=0.01, beta_net=1, info='NetREm Model', lasso_selection='cyclic', max_lasso_iterations=10000, model_info='unfitted_model :(', model_type='Lasso', network=, target_gene_y='Unknown :(', tolerance=0.0001, verbose=False, y_intercept=False),\n", + " n_jobs=-1,\n", + " param_grid={'alpha_lasso': [1e-05, 1e-05, 1e-08, 0.0001, 0.005,\n", + " 0.001, 1e-09, 0.002, 0.1, 0.0023559,\n", + " 0.003, 0.005, 0.01],\n", + " 'beta_net': [1e-06, 3, 0.1, 0.05, 1e-07, 5e-06, 0.01,\n", + " 0.001, 0.2, 0.4, 0.5, 0.6, 0.8, 5, 1,\n", + " 2]},\n", + " verbose=10)" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "\n", + "demo1 = nm.netrem(edge_list = filtered_ppi_for_TG, \n", + " view_network = False)\n", + "\n", + "param_grid = {\n", + " 'beta_net': [1e-6,3, 0.1, 0.05, 1e-7, 5e-6, 0.01,1e-3, 0.2, 0.4, 0.5, 0.6, 0.8, 5, 1, 2],\n", + " 'alpha_lasso': [1e-5, 0.00001, 1e-8, 0.0001, 0.005, 0.001, 1e-9, 0.002, 0.1, 0.0023559, 0.003, 0.005, 0.01]}\n", + "\n", + "griddy_demo1 = GridSearchCV(demo1, param_grid=param_grid, cv=5, n_jobs = -1, verbose = 10)\n", + "griddy_demo1.fit(X_train, y_train)" + ] + }, + { + "cell_type": "markdown", + "id": "aff7d3cb", + "metadata": {}, + "source": [ + "![gridster_0.png](../user_guide/pics/gridster_0.png)\n", + "![gridster_1.png](../user_guide/pics/gridster_1.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "0ebaf4e7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'alpha_lasso': 0.1, 'beta_net': 5}" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "griddy_demo1.best_params_ # these are the parameters selected by the gridSearchCV" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "id": "eccef2a8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
NetREmModel(info=NetREm Model, verbose=False, all_pos_coefs=False, model_type=Lasso, y_intercept=False, max_lasso_iterations=10000, model_info=fitted_model :), target_gene_y=ZZZ3, tolerance=0.0001, lasso_selection=cyclic, beta_net=5, alpha_lasso=0.1, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C6E41B430>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(info=NetREm Model, verbose=False, all_pos_coefs=False, model_type=Lasso, y_intercept=False, max_lasso_iterations=10000, model_info=fitted_model :), target_gene_y=ZZZ3, tolerance=0.0001, lasso_selection=cyclic, beta_net=5, alpha_lasso=0.1, network=)" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gridsearch_netrem_model = griddy_demo1.best_estimator_\n", + "gridsearch_netrem_model" + ] + }, + { + "cell_type": "markdown", + "id": "8a2b1046", + "metadata": {}, + "source": [ + "![griddy_1.png](../user_guide/pics/griddy_1.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "41c9af6e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'info': 'NetREm Model',\n", + " 'alpha_lasso': 0.1,\n", + " 'beta_net': 5,\n", + " 'y_intercept': False,\n", + " 'model_type': 'Lasso',\n", + " 'max_lasso_iterations': 10000,\n", + " 'network': ,\n", + " 'verbose': False,\n", + " 'all_pos_coefs': False,\n", + " 'model_info': 'fitted_model :)',\n", + " 'target_gene_y': 'ZZZ3',\n", + " 'tolerance': 0.0001,\n", + " 'lasso_selection': 'cyclic'}" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gridsearch_netrem_model.get_params()" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "id": "0c4e7aca", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) # of final TFs in the model for TG ZZZ3: 12\n", + "Training MSE: 0.5480934127420958\n", + "Testing MSE: 0.6610817578852232\n" + ] + } + ], + "source": [ + "print(f\":) # of final TFs in the model for TG {tg}: {gridsearch_netrem_model.num_final_predictors}\")\n", + "mse_train = gridsearch_netrem_model.test_mse(X_train, y_train)\n", + "mse_test = gridsearch_netrem_model.test_mse(X_test, y_test)\n", + "print(f\"Training MSE: {mse_train}\")\n", + "print(f\"Testing MSE: {mse_test}\")" + ] + }, + { + "cell_type": "markdown", + "id": "24427c81", + "metadata": {}, + "source": [ + "### Example 2d: \n", + "#### using RandomizedSearchCV for more efficient (but less comprehensive) optimization for *beta_net* $\\beta_{net}$ and *alpha_lasso* $\\alpha_{lasso}$ ." + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "id": "20fcc68d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using beta_net default of 1\n", + "using alpha_lasso default of 0.01\n", + "Fitting 5 folds for each of 10 candidates, totalling 50 fits\n" + ] + }, + { + "data": { + "text/html": [ + "
RandomizedSearchCV(cv=5,\n",
+       "                   estimator=NetREmModel(all_pos_coefs=False, alpha_lasso=0.01, beta_net=1, info='NetREm Model', lasso_selection='cyclic', max_lasso_iterations=10000, model_info='unfitted_model :(', model_type='Lasso', network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C71576AA0>, target_gene_y='Unknown :(', tolerance=0.0001, verbose=False, y_intercept=False),\n",
+       "                   n_jobs=-1,\n",
+       "                   param_distributions={'alpha_lasso': [1e-05, 1e-05, 1e-08,\n",
+       "                                                        0.0001, 0.005, 0.001,\n",
+       "                                                        1e-09, 0.002, 0.1,\n",
+       "                                                        0.0023559, 0.003, 0.005,\n",
+       "                                                        0.01],\n",
+       "                                        'beta_net': [1e-06, 3, 0.1, 0.05, 1e-07,\n",
+       "                                                     5e-06, 0.01, 0.001, 0.2,\n",
+       "                                                     0.4, 0.5, 0.6, 0.8, 5, 1,\n",
+       "                                                     2]},\n",
+       "                   verbose=10)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "RandomizedSearchCV(cv=5,\n", + " estimator=NetREmModel(all_pos_coefs=False, alpha_lasso=0.01, beta_net=1, info='NetREm Model', lasso_selection='cyclic', max_lasso_iterations=10000, model_info='unfitted_model :(', model_type='Lasso', network=, target_gene_y='Unknown :(', tolerance=0.0001, verbose=False, y_intercept=False),\n", + " n_jobs=-1,\n", + " param_distributions={'alpha_lasso': [1e-05, 1e-05, 1e-08,\n", + " 0.0001, 0.005, 0.001,\n", + " 1e-09, 0.002, 0.1,\n", + " 0.0023559, 0.003, 0.005,\n", + " 0.01],\n", + " 'beta_net': [1e-06, 3, 0.1, 0.05, 1e-07,\n", + " 5e-06, 0.01, 0.001, 0.2,\n", + " 0.4, 0.5, 0.6, 0.8, 5, 1,\n", + " 2]},\n", + " verbose=10)" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from sklearn.model_selection import RandomizedSearchCV\n", + "demo2 = nm.netrem(edge_list = filtered_ppi_for_TG, \n", + " view_network = False)\n", + "\n", + "griddy_demo2 = RandomizedSearchCV(demo2, param_distributions=param_grid, cv=5, n_jobs = -1, verbose = 10)\n", + "griddy_demo2.fit(X_train, y_train)" + ] + }, + { + "cell_type": "markdown", + "id": "6c703cb5", + "metadata": {}, + "source": [ + "![rand_Search1.png](../user_guide/pics/rand_SearchA.png)\n", + "![rand_Search2.png](../user_guide/pics/rand_SearchB.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "id": "b34567b1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'beta_net': 5e-06, 'alpha_lasso': 0.1}" + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "griddy_demo2.best_params_" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "b48fa832", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
NetREmModel(info=NetREm Model, verbose=False, all_pos_coefs=False, model_type=Lasso, y_intercept=False, max_lasso_iterations=10000, model_info=fitted_model :), target_gene_y=ZZZ3, tolerance=0.0001, lasso_selection=cyclic, beta_net=5e-06, alpha_lasso=0.1, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C6E77F610>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(info=NetREm Model, verbose=False, all_pos_coefs=False, model_type=Lasso, y_intercept=False, max_lasso_iterations=10000, model_info=fitted_model :), target_gene_y=ZZZ3, tolerance=0.0001, lasso_selection=cyclic, beta_net=5e-06, alpha_lasso=0.1, network=)" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "randsearch_netrem_model = griddy_demo2.best_estimator_\n", + "randsearch_netrem_model" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "ab8f577e", + "metadata": {}, + "source": [ + "![rand_Search1.png](../user_guide/pics/rand_Search1.png)\n", + "![rand_Search2.png](../user_guide/pics/rand_Search2.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "id": "3dc7233b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) # of final TFs in the model for TG ZZZ3: 12\n", + "Training MSE: 0.5480195513484795\n", + "Testing MSE: 0.661036024697951\n" + ] + } + ], + "source": [ + "print(f\":) # of final TFs in the model for TG {tg}: {randsearch_netrem_model.num_final_predictors}\")\n", + "mse_train = randsearch_netrem_model.test_mse(X_train, y_train)\n", + "mse_test = randsearch_netrem_model.test_mse(X_test, y_test)\n", + "print(f\"Training MSE: {mse_train}\")\n", + "print(f\"Testing MSE: {mse_test}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "id": "39723bbe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_interceptBACH1ELF1FOXO1FOXP1MAFMAXNFIBNFKB1NR3C1RREB1SETDB1YY1
0None0.0854960.1189280.0127870.0103830.0264450.0247010.1171320.0520720.0512380.0063380.0830560.005714
\n", + "
" + ], + "text/plain": [ + " y_intercept BACH1 ELF1 FOXO1 FOXP1 MAF MAX \\\n", + "0 None 0.085496 0.118928 0.012787 0.010383 0.026445 0.024701 \n", + "\n", + " NFIB NFKB1 NR3C1 RREB1 SETDB1 YY1 \n", + "0 0.117132 0.052072 0.051238 0.006338 0.083056 0.005714 " + ] + }, + "execution_count": 71, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "randsearch_netrem_model.model_nonzero_coef_df" + ] + }, + { + "cell_type": "markdown", + "id": "41ee9e46", + "metadata": {}, + "source": [ + "### Example 2e: \n", + "#### using Bayesian Optimization and Gaussian Processes to determine the optimal *beta_net* $\\beta_{net}$ and *alpha_lasso* $\\alpha_{lasso}$ given a potential range of values.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "id": "f5d9e64a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using beta_net default of 1\n", + "using alpha_lasso default of 0.01\n", + ":) Please note that we are running: optimal_netrem_model_via_bayesian_param_tuner\n", + "alpha_lasso = 0.01 ; beta_network = 100.0\n", + "{'info': 'NetREm Model', 'alpha_lasso': 0.01, 'beta_net': 1, 'y_intercept': True, 'model_type': 'Lasso', 'max_lasso_iterations': 10000, 'network': , 'verbose': False, 'all_pos_coefs': False, 'model_info': 'fitted_model :)', 'target_gene_y': 'ZZZ3', 'tolerance': 0.0001, 'lasso_selection': 'cyclic'}\n", + "CPU times: total: 7.47 s\n", + "Wall time: 19.5 s\n" + ] + }, + { + "data": { + "text/html": [ + "
NetREmModel(info=NetREm Model, verbose=False, all_pos_coefs=False, model_type=Lasso, y_intercept=True, max_lasso_iterations=10000, model_info=fitted_model :), target_gene_y=ZZZ3, tolerance=0.0001, lasso_selection=cyclic, beta_net=1, alpha_lasso=0.01, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C6C6F8130>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(info=NetREm Model, verbose=False, all_pos_coefs=False, model_type=Lasso, y_intercept=True, max_lasso_iterations=10000, model_info=fitted_model :), target_gene_y=ZZZ3, tolerance=0.0001, lasso_selection=cyclic, beta_net=1, alpha_lasso=0.01, network=)" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "netrem_bayes_demo2 = nm.netrem(edge_list = filtered_ppi_for_TG, \n", + " y_intercept = True)\n", + "\n", + "bayesian_netty2 = nm_eval.optimal_netrem_model_via_bayesian_param_tuner(netrem_bayes_demo2,\n", + " X_train, y_train,\n", + " beta_net_min = 1, \n", + " beta_net_max = 100, \n", + " alpha_lasso_min = 0.0001,\n", + " alpha_lasso_max = 0.01, \n", + " num_grid_values = 50)\n", + "bayesian_net_model2 = bayesian_netty2[\"optimal_model\"]\n", + "bayesian_net_model2" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f0a94e1f", + "metadata": {}, + "source": [ + "![bayesian_net_model2.png](../user_guide/pics/bayesian_net_model2.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "id": "f85feba4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'info': 'NetREm Model',\n", + " 'alpha_lasso': 0.01,\n", + " 'beta_net': 1,\n", + " 'y_intercept': True,\n", + " 'model_type': 'Lasso',\n", + " 'max_lasso_iterations': 10000,\n", + " 'network': ,\n", + " 'verbose': False,\n", + " 'all_pos_coefs': False,\n", + " 'model_info': 'fitted_model :)',\n", + " 'target_gene_y': 'ZZZ3',\n", + " 'tolerance': 0.0001,\n", + " 'lasso_selection': 'cyclic'}" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bayesian_net_model2.get_params()" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "f40dfe15", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) # of final TFs in the model for TG ZZZ3: 53\n", + "Training MSE: 0.44677196830719673\n", + "Testing MSE: 0.7485799905085805\n" + ] + } + ], + "source": [ + "print(f\":) # of final TFs in the model for TG {tg}: {bayesian_net_model2.num_final_predictors}\")\n", + "mse_train = bayesian_net_model2.test_mse(X_train, y_train)\n", + "mse_test = bayesian_net_model2.test_mse(X_test, y_test)\n", + "print(f\"Training MSE: {mse_train}\")\n", + "print(f\"Testing MSE: {mse_test}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "d36243be", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_interceptBACH1BCL6CCNT2CTCFE2F3E4F1EBF1ELF1ERF...TCF3TP53USF2YY1ZBTB7AZFP28ZNF140ZNF274ZNF682ZNF76
0-0.156670.1118070.0023050.02496-0.0314190.135078-0.187243-0.0239860.091143-0.013846...-0.137879-0.154464-0.0391460.056958-0.064111-0.0837640.118554-0.0198790.0151350.151874
\n", + "

1 rows × 54 columns

\n", + "
" + ], + "text/plain": [ + " y_intercept BACH1 BCL6 CCNT2 CTCF E2F3 E4F1 \\\n", + "0 -0.15667 0.111807 0.002305 0.02496 -0.031419 0.135078 -0.187243 \n", + "\n", + " EBF1 ELF1 ERF ... TCF3 TP53 USF2 YY1 \\\n", + "0 -0.023986 0.091143 -0.013846 ... -0.137879 -0.154464 -0.039146 0.056958 \n", + "\n", + " ZBTB7A ZFP28 ZNF140 ZNF274 ZNF682 ZNF76 \n", + "0 -0.064111 -0.083764 0.118554 -0.019879 0.015135 0.151874 \n", + "\n", + "[1 rows x 54 columns]" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bayesian_net_model2.model_nonzero_coef_df" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "id": "f8222c0e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
coefTFTGinfotrain_msebeta_netalpha_lassoAbsoluteVal_coefficientRankfinal_model_TFsTFs_input_to_modeloriginal_TFs_in_X
0-0.156670y_interceptZZZ3netrem_with_intercept0.44677210.010.1566703537777
10.111807BACH1ZZZ3netrem_with_intercept0.44677210.010.11180712537777
20.002305BCL6ZZZ3netrem_with_intercept0.44677210.010.00230553537777
30.024960CCNT2ZZZ3netrem_with_intercept0.44677210.010.02496041537777
4-0.031419CTCFZZZ3netrem_with_intercept0.44677210.010.03141937537777
50.135078E2F3ZZZ3netrem_with_intercept0.44677210.010.1350787537777
6-0.187243E4F1ZZZ3netrem_with_intercept0.44677210.010.1872431537777
7-0.023986EBF1ZZZ3netrem_with_intercept0.44677210.010.02398642537777
80.091143ELF1ZZZ3netrem_with_intercept0.44677210.010.09114317537777
9-0.013846ERFZZZ3netrem_with_intercept0.44677210.010.01384647537777
10-0.112157ESR2ZZZ3netrem_with_intercept0.44677210.010.11215711537777
11-0.010902FOXO1ZZZ3netrem_with_intercept0.44677210.010.01090248537777
120.030213FOXP1ZZZ3netrem_with_intercept0.44677210.010.03021339537777
130.045014HCFC1ZZZ3netrem_with_intercept0.44677210.010.04501432537777
140.057533HDAC2ZZZ3netrem_with_intercept0.44677210.010.05753325537777
150.121722IRF3ZZZ3netrem_with_intercept0.44677210.010.1217229537777
16-0.051893KLF12ZZZ3netrem_with_intercept0.44677210.010.05189330537777
170.019619KLF15ZZZ3netrem_with_intercept0.44677210.010.01961944537777
180.051233MAFZZZ3netrem_with_intercept0.44677210.010.05123331537777
190.007074MAXZZZ3netrem_with_intercept0.44677210.010.00707450537777
20-0.060859MXI1ZZZ3netrem_with_intercept0.44677210.010.06085924537777
210.055780MYEF2ZZZ3netrem_with_intercept0.44677210.010.05578028537777
220.109876NFIBZZZ3netrem_with_intercept0.44677210.010.10987613537777
230.052258NFICZZZ3netrem_with_intercept0.44677210.010.05225829537777
240.133596NFKB1ZZZ3netrem_with_intercept0.44677210.010.1335968537777
250.039664NR1D2ZZZ3netrem_with_intercept0.44677210.010.03966435537777
260.056687NR1H2ZZZ3netrem_with_intercept0.44677210.010.05668727537777
27-0.030452NR2F1ZZZ3netrem_with_intercept0.44677210.010.03045238537777
280.005572NR3C1ZZZ3netrem_with_intercept0.44677210.010.00557251537777
290.000801NR6A1ZZZ3netrem_with_intercept0.44677210.010.00080154537777
300.043955PPARAZZZ3netrem_with_intercept0.44677210.010.04395533537777
310.100120RARBZZZ3netrem_with_intercept0.44677210.010.10012016537777
32-0.027042RARGZZZ3netrem_with_intercept0.44677210.010.02704240537777
330.004707RESTZZZ3netrem_with_intercept0.44677210.010.00470752537777
340.061880RFX3ZZZ3netrem_with_intercept0.44677210.010.06188023537777
35-0.086117RORAZZZ3netrem_with_intercept0.44677210.010.08611718537777
360.042622RREB1ZZZ3netrem_with_intercept0.44677210.010.04262234537777
370.076264RUNX2ZZZ3netrem_with_intercept0.44677210.010.07626421537777
380.170890SETDB1ZZZ3netrem_with_intercept0.44677210.010.1708902537777
39-0.100338SMAD4ZZZ3netrem_with_intercept0.44677210.010.10033815537777
400.077066SMC3ZZZ3netrem_with_intercept0.44677210.010.07706620537777
410.015308STAT1ZZZ3netrem_with_intercept0.44677210.010.01530845537777
420.100428STAT5BZZZ3netrem_with_intercept0.44677210.010.10042814537777
430.007686TBX2ZZZ3netrem_with_intercept0.44677210.010.00768649537777
44-0.137879TCF3ZZZ3netrem_with_intercept0.44677210.010.1378796537777
45-0.154464TP53ZZZ3netrem_with_intercept0.44677210.010.1544644537777
46-0.039146USF2ZZZ3netrem_with_intercept0.44677210.010.03914636537777
470.056958YY1ZZZ3netrem_with_intercept0.44677210.010.05695826537777
48-0.064111ZBTB7AZZZ3netrem_with_intercept0.44677210.010.06411122537777
49-0.083764ZFP28ZZZ3netrem_with_intercept0.44677210.010.08376419537777
500.118554ZNF140ZZZ3netrem_with_intercept0.44677210.010.11855410537777
51-0.019879ZNF274ZZZ3netrem_with_intercept0.44677210.010.01987943537777
520.015135ZNF682ZZZ3netrem_with_intercept0.44677210.010.01513546537777
530.151874ZNF76ZZZ3netrem_with_intercept0.44677210.010.1518745537777
\n", + "
" + ], + "text/plain": [ + " coef TF TG info train_mse beta_net \\\n", + "0 -0.156670 y_intercept ZZZ3 netrem_with_intercept 0.446772 1 \n", + "1 0.111807 BACH1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "2 0.002305 BCL6 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "3 0.024960 CCNT2 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "4 -0.031419 CTCF ZZZ3 netrem_with_intercept 0.446772 1 \n", + "5 0.135078 E2F3 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "6 -0.187243 E4F1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "7 -0.023986 EBF1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "8 0.091143 ELF1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "9 -0.013846 ERF ZZZ3 netrem_with_intercept 0.446772 1 \n", + "10 -0.112157 ESR2 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "11 -0.010902 FOXO1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "12 0.030213 FOXP1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "13 0.045014 HCFC1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "14 0.057533 HDAC2 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "15 0.121722 IRF3 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "16 -0.051893 KLF12 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "17 0.019619 KLF15 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "18 0.051233 MAF ZZZ3 netrem_with_intercept 0.446772 1 \n", + "19 0.007074 MAX ZZZ3 netrem_with_intercept 0.446772 1 \n", + "20 -0.060859 MXI1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "21 0.055780 MYEF2 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "22 0.109876 NFIB ZZZ3 netrem_with_intercept 0.446772 1 \n", + "23 0.052258 NFIC ZZZ3 netrem_with_intercept 0.446772 1 \n", + "24 0.133596 NFKB1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "25 0.039664 NR1D2 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "26 0.056687 NR1H2 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "27 -0.030452 NR2F1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "28 0.005572 NR3C1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "29 0.000801 NR6A1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "30 0.043955 PPARA ZZZ3 netrem_with_intercept 0.446772 1 \n", + "31 0.100120 RARB ZZZ3 netrem_with_intercept 0.446772 1 \n", + "32 -0.027042 RARG ZZZ3 netrem_with_intercept 0.446772 1 \n", + "33 0.004707 REST ZZZ3 netrem_with_intercept 0.446772 1 \n", + "34 0.061880 RFX3 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "35 -0.086117 RORA ZZZ3 netrem_with_intercept 0.446772 1 \n", + "36 0.042622 RREB1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "37 0.076264 RUNX2 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "38 0.170890 SETDB1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "39 -0.100338 SMAD4 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "40 0.077066 SMC3 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "41 0.015308 STAT1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "42 0.100428 STAT5B ZZZ3 netrem_with_intercept 0.446772 1 \n", + "43 0.007686 TBX2 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "44 -0.137879 TCF3 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "45 -0.154464 TP53 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "46 -0.039146 USF2 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "47 0.056958 YY1 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "48 -0.064111 ZBTB7A ZZZ3 netrem_with_intercept 0.446772 1 \n", + "49 -0.083764 ZFP28 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "50 0.118554 ZNF140 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "51 -0.019879 ZNF274 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "52 0.015135 ZNF682 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "53 0.151874 ZNF76 ZZZ3 netrem_with_intercept 0.446772 1 \n", + "\n", + " alpha_lasso AbsoluteVal_coefficient Rank final_model_TFs \\\n", + "0 0.01 0.156670 3 53 \n", + "1 0.01 0.111807 12 53 \n", + "2 0.01 0.002305 53 53 \n", + "3 0.01 0.024960 41 53 \n", + "4 0.01 0.031419 37 53 \n", + "5 0.01 0.135078 7 53 \n", + "6 0.01 0.187243 1 53 \n", + "7 0.01 0.023986 42 53 \n", + "8 0.01 0.091143 17 53 \n", + "9 0.01 0.013846 47 53 \n", + "10 0.01 0.112157 11 53 \n", + "11 0.01 0.010902 48 53 \n", + "12 0.01 0.030213 39 53 \n", + "13 0.01 0.045014 32 53 \n", + "14 0.01 0.057533 25 53 \n", + "15 0.01 0.121722 9 53 \n", + "16 0.01 0.051893 30 53 \n", + "17 0.01 0.019619 44 53 \n", + "18 0.01 0.051233 31 53 \n", + "19 0.01 0.007074 50 53 \n", + "20 0.01 0.060859 24 53 \n", + "21 0.01 0.055780 28 53 \n", + "22 0.01 0.109876 13 53 \n", + "23 0.01 0.052258 29 53 \n", + "24 0.01 0.133596 8 53 \n", + "25 0.01 0.039664 35 53 \n", + "26 0.01 0.056687 27 53 \n", + "27 0.01 0.030452 38 53 \n", + "28 0.01 0.005572 51 53 \n", + "29 0.01 0.000801 54 53 \n", + "30 0.01 0.043955 33 53 \n", + "31 0.01 0.100120 16 53 \n", + "32 0.01 0.027042 40 53 \n", + "33 0.01 0.004707 52 53 \n", + "34 0.01 0.061880 23 53 \n", + "35 0.01 0.086117 18 53 \n", + "36 0.01 0.042622 34 53 \n", + "37 0.01 0.076264 21 53 \n", + "38 0.01 0.170890 2 53 \n", + "39 0.01 0.100338 15 53 \n", + "40 0.01 0.077066 20 53 \n", + "41 0.01 0.015308 45 53 \n", + "42 0.01 0.100428 14 53 \n", + "43 0.01 0.007686 49 53 \n", + "44 0.01 0.137879 6 53 \n", + "45 0.01 0.154464 4 53 \n", + "46 0.01 0.039146 36 53 \n", + "47 0.01 0.056958 26 53 \n", + "48 0.01 0.064111 22 53 \n", + "49 0.01 0.083764 19 53 \n", + "50 0.01 0.118554 10 53 \n", + "51 0.01 0.019879 43 53 \n", + "52 0.01 0.015135 46 53 \n", + "53 0.01 0.151874 5 53 \n", + "\n", + " TFs_input_to_model original_TFs_in_X \n", + "0 77 77 \n", + "1 77 77 \n", + "2 77 77 \n", + "3 77 77 \n", + "4 77 77 \n", + "5 77 77 \n", + "6 77 77 \n", + "7 77 77 \n", + "8 77 77 \n", + "9 77 77 \n", + "10 77 77 \n", + "11 77 77 \n", + "12 77 77 \n", + "13 77 77 \n", + "14 77 77 \n", + "15 77 77 \n", + "16 77 77 \n", + "17 77 77 \n", + "18 77 77 \n", + "19 77 77 \n", + "20 77 77 \n", + "21 77 77 \n", + "22 77 77 \n", + "23 77 77 \n", + "24 77 77 \n", + "25 77 77 \n", + "26 77 77 \n", + "27 77 77 \n", + "28 77 77 \n", + "29 77 77 \n", + "30 77 77 \n", + "31 77 77 \n", + "32 77 77 \n", + "33 77 77 \n", + "34 77 77 \n", + "35 77 77 \n", + "36 77 77 \n", + "37 77 77 \n", + "38 77 77 \n", + "39 77 77 \n", + "40 77 77 \n", + "41 77 77 \n", + "42 77 77 \n", + "43 77 77 \n", + "44 77 77 \n", + "45 77 77 \n", + "46 77 77 \n", + "47 77 77 \n", + "48 77 77 \n", + "49 77 77 \n", + "50 77 77 \n", + "51 77 77 \n", + "52 77 77 \n", + "53 77 77 " + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bayesian_net_model2.combined_df" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "id": "92f8557b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['info', 'verbose', 'overlapped_nodes_only', 'num_cv_folds', 'num_jobs', 'all_pos_coefs', 'model_type', 'use_network', 'y_intercept', 'max_lasso_iterations', 'view_network', 'model_info', 'target_gene_y', 'tolerance', 'lasso_selection', 'lassocv_eps', 'lassocv_n_alphas', 'lassocv_alphas', 'beta_net', 'alpha_lasso', 'network', 'optimal_alpha', 'prior_network', 'preprocessed_network', 'network_params', 'network_nodes_list', 'kwargs', 'X_df', 'gene_expression_nodes', 'common_nodes', 'final_nodes', 'gexpr_nodes_added', 'gexpr_nodes_to_add_for_net', 'filter_network_bool', 'A_df', 'A', 'nodes', 'network_info', 'M', 'N', 'X_train', 'y_train', 'B_train', 'B_interaction_df', 'B_train_times_M', 'X_tilda_train', 'y_tilda_train', 'X_training_to_use', 'y_training_to_use', 'regr', 'final_alpha', 'coef', 'intercept', 'predY_tilda_train', 'mse_tilda_train', 'predY_train', 'mse_train', 'model_coef_df', 'model_nonzero_coef_df', 'sorted_coef_df', 'corr_vs_coef_df', 'final_corr_vs_coef_df', 'combined_df', 'num_final_predictors'])" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vars(bayesian_net_model2).keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "id": "d537c8cc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TF1TF2B_train_weightsignpotential_interactionabsVal_Binfocandidate_TFs_Ntarget_gene_ynum_final_predictorsmodel_typebeta_netgene_datarankpercentile
2092FOXO1NFIB1.119274e+00:):(1.119274e+00B matrix of TF-TF interactions77ZZZ353Lasso1training gene expression data1.099.982912
1028NFIBFOXO11.119274e+00:):(1.119274e+00B matrix of TF-TF interactions77ZZZ353Lasso1training gene expression data1.099.982912
4416NFIBSREBF29.570243e-01:):(9.570243e-01B matrix of TF-TF interactions77ZZZ353Lasso1training gene expression data3.099.948735
2136SREBF2NFIB9.570243e-01:):(9.570243e-01B matrix of TF-TF interactions77ZZZ353Lasso1training gene expression data3.099.948735
1046RORAFOXO19.287842e-01:):(9.287842e-01B matrix of TF-TF interactions77ZZZ353Lasso1training gene expression data5.099.914559
................................................
3834TCF3RXRB-1.163842e-06:(:( competitive (-)1.163842e-06B matrix of TF-TF interactions77ZZZ353Lasso1training gene expression data5847.00.085441
960PMLESRRA-9.827955e-07:(:( competitive (-)9.827955e-07B matrix of TF-TF interactions77ZZZ353Lasso1training gene expression data5849.00.051265
2784ESRRAPML-9.827955e-07:(:( competitive (-)9.827955e-07B matrix of TF-TF interactions77ZZZ353Lasso1training gene expression data5850.00.034176
4708ESR2TCF3-9.284305e-07:(:( competitive (-)9.284305e-07B matrix of TF-TF interactions77ZZZ353Lasso1training gene expression data5851.00.017088
908TCF3ESR2-9.284305e-07:(:( competitive (-)9.284305e-07B matrix of TF-TF interactions77ZZZ353Lasso1training gene expression data5851.00.017088
\n", + "

5852 rows × 15 columns

\n", + "
" + ], + "text/plain": [ + " TF1 TF2 B_train_weight sign potential_interaction absVal_B \\\n", + "2092 FOXO1 NFIB 1.119274e+00 :) :( 1.119274e+00 \n", + "1028 NFIB FOXO1 1.119274e+00 :) :( 1.119274e+00 \n", + "4416 NFIB SREBF2 9.570243e-01 :) :( 9.570243e-01 \n", + "2136 SREBF2 NFIB 9.570243e-01 :) :( 9.570243e-01 \n", + "1046 RORA FOXO1 9.287842e-01 :) :( 9.287842e-01 \n", + "... ... ... ... ... ... ... \n", + "3834 TCF3 RXRB -1.163842e-06 :( :( competitive (-) 1.163842e-06 \n", + "960 PML ESRRA -9.827955e-07 :( :( competitive (-) 9.827955e-07 \n", + "2784 ESRRA PML -9.827955e-07 :( :( competitive (-) 9.827955e-07 \n", + "4708 ESR2 TCF3 -9.284305e-07 :( :( competitive (-) 9.284305e-07 \n", + "908 TCF3 ESR2 -9.284305e-07 :( :( competitive (-) 9.284305e-07 \n", + "\n", + " info candidate_TFs_N target_gene_y \\\n", + "2092 B matrix of TF-TF interactions 77 ZZZ3 \n", + "1028 B matrix of TF-TF interactions 77 ZZZ3 \n", + "4416 B matrix of TF-TF interactions 77 ZZZ3 \n", + "2136 B matrix of TF-TF interactions 77 ZZZ3 \n", + "1046 B matrix of TF-TF interactions 77 ZZZ3 \n", + "... ... ... ... \n", + "3834 B matrix of TF-TF interactions 77 ZZZ3 \n", + "960 B matrix of TF-TF interactions 77 ZZZ3 \n", + "2784 B matrix of TF-TF interactions 77 ZZZ3 \n", + "4708 B matrix of TF-TF interactions 77 ZZZ3 \n", + "908 B matrix of TF-TF interactions 77 ZZZ3 \n", + "\n", + " num_final_predictors model_type beta_net \\\n", + "2092 53 Lasso 1 \n", + "1028 53 Lasso 1 \n", + "4416 53 Lasso 1 \n", + "2136 53 Lasso 1 \n", + "1046 53 Lasso 1 \n", + "... ... ... ... \n", + "3834 53 Lasso 1 \n", + "960 53 Lasso 1 \n", + "2784 53 Lasso 1 \n", + "4708 53 Lasso 1 \n", + "908 53 Lasso 1 \n", + "\n", + " gene_data rank percentile \n", + "2092 training gene expression data 1.0 99.982912 \n", + "1028 training gene expression data 1.0 99.982912 \n", + "4416 training gene expression data 3.0 99.948735 \n", + "2136 training gene expression data 3.0 99.948735 \n", + "1046 training gene expression data 5.0 99.914559 \n", + "... ... ... ... \n", + "3834 training gene expression data 5847.0 0.085441 \n", + "960 training gene expression data 5849.0 0.051265 \n", + "2784 training gene expression data 5850.0 0.034176 \n", + "4708 training gene expression data 5851.0 0.017088 \n", + "908 training gene expression data 5851.0 0.017088 \n", + "\n", + "[5852 rows x 15 columns]" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b_matrix_2e = nm.organize_B_interaction_network(bayesian_net_model2)\n", + "b_matrix_2e" + ] + }, + { + "cell_type": "markdown", + "id": "62b29bc5", + "metadata": {}, + "source": [ + "## Example 3️⃣: \n", + "### More intensive hyperparameter tuning\n", + "Here, please note that we focus on more hyperparameters that we may tune on, such as including the y-intercept term (or not?), or using Lasso versus LassoCV (and when LassoCV is being tested, we ignore the input alpha_lasso in the param_grid values). 😊\n", + "\n", + "### Example 3a:\n", + "#### User optimizes over several hyperparameters using GridSearchCV (comprehensive):\n" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "id": "e37b79f9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using beta_net default of 1\n", + "using alpha_lasso default of 0.01\n", + "Fitting 5 folds for each of 480 candidates, totalling 2400 fits\n", + "CPU times: total: 34 s\n", + "Wall time: 1min 9s\n" + ] + }, + { + "data": { + "text/html": [ + "
GridSearchCV(cv=5,\n",
+       "             estimator=NetREmModel(all_pos_coefs=False, alpha_lasso=0.01, beta_net=1, info='NetREm Model', lasso_selection='cyclic', max_lasso_iterations=10000, model_info='unfitted_model :(', model_type='Lasso', network=<PriorGraphNetwork.PriorGraphNetwork object at 0x0000016C6F1F74C0>, target_gene_y='Unknown :(', tolerance=0.0001, verbose=False, y_intercept=False),\n",
+       "             n_jobs=-1,\n",
+       "             param_grid={'alpha_lasso': [1e-05, 1e-05, 0.0001, 0.005, 0.001,\n",
+       "                                         0.002, 0.1, 0.003, 0.005, 0.01],\n",
+       "                         'beta_net': [0.1, 0.05, 0.01, 0.2, 0.4, 0.5, 0.6, 0.8,\n",
+       "                                      5, 1, 2, 10],\n",
+       "                         'model_type': ['Lasso', 'LassoCV'],\n",
+       "                         'y_intercept': [True, False]},\n",
+       "             verbose=10)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "GridSearchCV(cv=5,\n", + " estimator=NetREmModel(all_pos_coefs=False, alpha_lasso=0.01, beta_net=1, info='NetREm Model', lasso_selection='cyclic', max_lasso_iterations=10000, model_info='unfitted_model :(', model_type='Lasso', network=, target_gene_y='Unknown :(', tolerance=0.0001, verbose=False, y_intercept=False),\n", + " n_jobs=-1,\n", + " param_grid={'alpha_lasso': [1e-05, 1e-05, 0.0001, 0.005, 0.001,\n", + " 0.002, 0.1, 0.003, 0.005, 0.01],\n", + " 'beta_net': [0.1, 0.05, 0.01, 0.2, 0.4, 0.5, 0.6, 0.8,\n", + " 5, 1, 2, 10],\n", + " 'model_type': ['Lasso', 'LassoCV'],\n", + " 'y_intercept': [True, False]},\n", + " verbose=10)" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "\n", + "demo3 = nm.netrem(edge_list = filtered_ppi_for_TG, \n", + " view_network = False)\n", + "\n", + "larger_param_grid = {\n", + " 'beta_net': [0.1, 0.05,0.01, 0.2, 0.4, 0.5, 0.6, 0.8, 5, 1, 2, 10],\n", + " 'alpha_lasso': [1e-5, 0.00001, 0.0001, 0.005, 0.001, 0.002, 0.1, 0.003, 0.005, 0.01],\n", + " 'y_intercept': [True, False],\n", + " 'model_type': [\"Lasso\", \"LassoCV\"]}\n", + "\n", + "griddy_demo3 = GridSearchCV(demo3, param_grid=larger_param_grid, cv=5, n_jobs = -1, verbose = 10)\n", + "griddy_demo3.fit(X_train, y_train)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "b73d131d", + "metadata": {}, + "source": [ + "![gridster_0.png](../user_guide/pics/gridster_0.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "id": "cc34a859", + "metadata": {}, + "outputs": [], + "source": [ + "# griddy_demo3.cv_results_ # to view the results from GridSearchCV\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0351384", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/code/old_code/refresh/Netrem_model_builder.py b/code/old_code/refresh/Netrem_model_builder.py new file mode 100644 index 0000000..761023f --- /dev/null +++ b/code/old_code/refresh/Netrem_model_builder.py @@ -0,0 +1,1154 @@ +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +import random +import copy +from tqdm import tqdm +import os +import sys # https://www.dev2qa.com/how-to-run-python-script-py-file-in-jupyter-notebook-ipynb-file-and-ipython/#:~:text=How%20To%20Run%20Python%20Script%20.py%20File%20In,2.%20Invoke%20Python%20Script%20File%20From%20Ipython%20Command-Line. +import networkx as nx +import scipy +from scipy.linalg import svd as robust_svd +from sklearn.model_selection import KFold, train_test_split, GridSearchCV, RandomizedSearchCV, cross_val_score +from sklearn.decomposition import TruncatedSVD +from sklearn import linear_model, preprocessing # 9/19 +from sklearn.linear_model import Lasso, LassoCV, LinearRegression, ElasticNetCV, Ridge +from numpy.typing import ArrayLike +from typing import Optional, List, Tuple +from sklearn.metrics import make_scorer +import plotly.express as px +from sklearn.base import RegressorMixin, ClassifierMixin, BaseEstimator +from numpy.typing import ArrayLike +from skopt import gp_minimize, space +from scipy.sparse.linalg.interface import LinearOperator +import warnings +from sklearn.exceptions import ConvergenceWarning +printdf = lambda *args, **kwargs: print(pd.DataFrame(*args, **kwargs)) +rng_seed = 2023 # random seed for reproducibility +randSeed = 123 +# from packages_needed import * +import essential_functions as ef +import error_metrics as em # why to do import +#import Netrem_model_builder as nm +import DemoDataBuilderXandY as demo +import PriorGraphNetwork as graph +import netrem_evaluation_functions as nm_eval +import matplotlib.pyplot as plt +import pandas as pd +import numpy as np +import networkx as nx +from sklearn.linear_model import LinearRegression, Lasso, LassoCV +from tqdm.auto import tqdm +import copy +""" +Optimization for +(1 / (2 * M)) * ||y - Xc||^2_2 + (beta / (2 * N^2)) * c'Ac + alpha * ||c||_1 +Which is converted to lasso +(1 / (2 * M)) * ||y_tilde - X_tilde @ c||^2_2 + alpha * ||c||_1 +where M = n_samples and N is the dimension of c. +Check compute_X_tilde_y_tilde() to see how we make sure above normalization is applied using Lasso of sklearn +""" + +class NetREmModel(BaseEstimator, RegressorMixin): + """ :) Please note that this class focuses on building a Gene Regulatory Network (GRN) from gene expression data for Transcription Factors (TFs), gene expression data for the target gene (TG), and a prior biological network (W). This class performs Network-penalized regression :) """ + _parameter_constraints = { + "alpha_lasso": (0, None), + "beta_net": (0, None), + "num_cv_folds": (0, None), + "y_intercept": [False, True], + "use_network": [True, False], + "max_lasso_iterations": (1, None), + "model_type": ["Lasso", "LassoCV", "Linear"], + "tolerance": (0, None), + "num_jobs": (1, 1e10), + "lasso_selection": ["cyclic", "random"], + "lassocv_eps": (0, None), + "lassocv_n_alphas": (1, None), + "standardize_X": [True, False], + "center_y": [True, False] + } + + def __init__(self, **kwargs): + self.info = "NetREm Model" + self.verbose = False + self.overlapped_nodes_only = False # restrict the nodes to only being those found in the network? overlapped_nodes_only + self.num_cv_folds = 5 # for cross-validation models + self.num_jobs = -1 # for LassoCV or LinearRegression (here, -1 is the max possible for CPU) + self.all_pos_coefs = False # for coefficients + self.model_type = "Lasso" + self.standardize_X = True + self.center_y = True + self.use_network = True + self.y_intercept = False + self.max_lasso_iterations = 10000 + self.view_network = False + self.model_info = "unfitted_model :(" + self.target_gene_y = "Unknown :(" + self.tolerance = 1e-4 + self.lasso_selection = "cyclic" # default in sklearn + self.lassocv_eps = 1e-3 # default in sklearn + self.lassocv_n_alphas = 100 # default in sklearn + self.lassocv_alphas = None # default in sklearn + self.beta_net = kwargs.get('beta_net', 1) + self.__dict__.update(kwargs) + required_keys = ["network", "beta_net"] + if self.model_type == "Lasso": + self.alpha_lasso = kwargs.get('alpha_lasso', 0.01) + self.optimal_alpha = "User-specified optimal alpha lasso: " + str(self.alpha_lasso) + required_keys += ["alpha_lasso"] + elif self.model_type == "LassoCV": + self.alpha_lasso = "LassoCV finds optimal alpha" + self.optimal_alpha = "Since LassoCV is model_type, please fit model using X and y data to find optimal_alpha." + else: # model_type == "Linear": + self.alpha_lasso = "No alpha needed" + self.optimal_alpha = "No alpha needed" # + missing_keys = [key for key in required_keys if key not in self.__dict__] # check that all required keys are present: + if missing_keys: + raise ValueError(f":( Please note ye are missing information for these keys: {missing_keys}") + if self.use_network: + prior_network = self.network + self.prior_network = prior_network + self.preprocessed_network = prior_network.preprocessed_network + self.network_params = prior_network.param_lists + self.network_nodes_list = prior_network.final_nodes # tf_names_list + self.kwargs = kwargs + self._apply_parameter_constraints() # ensuring that the parameter constraints are met + + + def __repr__(self): + args = [f"{k}={v}" for k, v in self.__dict__.items() if k != 'param_grid' and k in self.kwargs] + return f"{self.__class__.__name__}({', '.join(args)})" + + + def check_overlaps_work(self): + final_set = set(self.final_nodes) + network_set = set(self.network_nodes_list) + return network_set != final_set + + + def standardize_X_data(self, X_df): # if the user opts to + """ :) If the user opts to standardize the X data (so that predictors have a mean of 0 + and a standard deviation of 1), then this method will be run, which uses the preprocessing + package StandardScalar() functionality. """ + if self.standardize_X: + # Transform both the training and test data + X_scaled = self.scaler.transform(X_df) + X_scaled_df = pd.DataFrame(X_scaled, columns=X_df.columns) + return X_scaled_df + else: + return X_df + + def center_y_data(self, y_df): # if the user opts to + """ :) If the user opts to center the response y data: + subtracting its mean from each observation.""" + if self.center_y: + # Center the response + y_train_centered = y_df - self.mean_y_train + return y_train_centered + else: + return y_df + + def updating_network_and_X_during_fitting(self, X, y): + # updated one :) + """ Update the prior network information and the + X input data (training) during the fitting of the model. It determines if the common predictors + should be used (based on if overlapped_nodes_only is True) or if all of the X input data should be used. """ + X_df = X.sort_index(axis=1) # sorting the X dataframe by columns. (rows are samples) + + #X_df = X.sort_index(axis=0).sort_index(axis=1) # sorting the X dataframe by rows and columns. + #self.X_df = X_df + self.target_gene_y = y.columns[0] + + if self.standardize_X: # we will standardize X then + if self.verbose: + print(":) Standardizing the X data") + self.old_X_df = X_df + self.scaler = preprocessing.StandardScaler().fit(X_df) # Fit the scaler to the training data only + # this self.scalar will be utilized for the testing data to prevent data leakage and to ensure generalization :) + self.X_df = self.standardize_X_data(X_df) + X = self.X_df # overwriting and updating the X df + else: + self.X_df = X_df + + self.mean_y_train = np.mean(y) # the average y value + if self.center_y: # we will center y then + if self.verbose: + print(":) centering the y data") + # Assuming y_train and y_test are your training and test labels + self.old_y = y + y = self.center_y_data(y) + + gene_expression_nodes = X_df.columns.tolist() # these are already sorted + #gene_expression_nodes = sorted(X_df.columns.tolist()) # these will be sorted + ppi_net_nodes = set(self.network_nodes_list) + common_nodes = list(ppi_net_nodes.intersection(gene_expression_nodes)) + + if not common_nodes: # may be possible that the X dataframe needs to be transposed if provided incorrectly + print("Please note: we are flipping X dataframe around so that the rows are samples and the columns are gene/TF names :)") + X_df = X_df.transpose() + gene_expression_nodes = sorted(X_df.columns.tolist()) + common_nodes = list(ppi_net_nodes.intersection(gene_expression_nodes)) + + self.gene_expression_nodes = gene_expression_nodes + self.common_nodes = sorted(common_nodes) + self.final_nodes = gene_expression_nodes + if self.overlapped_nodes_only: + self.final_nodes = common_nodes + elif self.preprocessed_network: + self.final_nodes = self.prior_network.final_nodes + else: + self.final_nodes = gene_expression_nodes + + final_nodes_set = set(self.final_nodes) + ppi_nodes_to_remove = list(ppi_net_nodes - final_nodes_set) + self.gexpr_nodes_added = list(set(gene_expression_nodes) - final_nodes_set) + self.gexpr_nodes_to_add_for_net = list(set(gene_expression_nodes) - set(common_nodes)) + + if self.verbose: + if ppi_nodes_to_remove: + print(f"Please note that we remove {len(ppi_nodes_to_remove)} nodes found in the input network that are not found in the input gene expression data (X) :)") + print(ppi_nodes_to_remove) + else: + print(f":) Please note that all {len(common_nodes)} nodes found in the network are also found in the input gene expression data (X) :)") + + filter_network_bool = self.filter_network_bool = self.check_overlaps_work() #self.check_overlaps_work(X_df) + if filter_network_bool: + print("Please note that we need to update the network information") + self.updating_network_A_matrix_given_X() # updating the A matrix given the gene expression data X + if self.view_network: + ef.draw_arrow() + self.view_W_network = self.view_W_network() + else: + self.A_df = self.network.A_df + self.A = self.network.A + self.nodes = self.A_df.columns.tolist() + + self.network_params = self.prior_network.param_lists + self.network_info = "fitted_network" + self.M = y.shape[0] + self.N = len(self.final_nodes) # pre-processing: + self.X_train = self.preprocess_X_df(X) + self.y_train = self.preprocess_y_df(y) + return self + + def organize_B_interaction_list(self): # TF-TF interactions to output :) + self.B_train = self.compute_B_matrix(self.X_train) + self.B_interaction_df = pd.DataFrame(self.B_train, index = self.final_nodes, columns = self.final_nodes) + return self + + + def fit(self, X, y): # fits a model Function used for model training + self.updating_network_and_X_during_fitting(X, y) + self.organize_B_interaction_list() + self.B_train_times_M = self.compute_B_matrix_times_M(self.X_train) + self.X_tilda_train, self.y_tilda_train = self.compute_X_tilde_y_tilde(self.B_train_times_M, self.X_train, + self.y_train) + self.X_training_to_use, self.y_training_to_use = self.X_tilda_train, self.y_tilda_train + self.regr = self.return_fit_ml_model(self.X_training_to_use, self.y_training_to_use) + ml_model = self.regr + self.final_alpha = self.alpha_lasso + if self.model_type == "LassoCV": + self.final_alpha = ml_model.alpha_ + self.optimal_alpha = "Cross-Validation optimal alpha lasso: " + str(self.final_alpha) + if self.verbose: + print(self.optimal_alpha) + self.coef = ml_model.coef_ # Please Get the coefficients + self.coef[self.coef == -0.0] = 0 + if self.y_intercept: + self.intercept = ml_model.intercept_ + self.predY_tilda_train = ml_model.predict(self.X_training_to_use) # training data + self.mse_tilda_train = self.calculate_mean_square_error(self.y_training_to_use, self.predY_tilda_train) # Calculate MSE + self.predY_train = ml_model.predict(self.X_train) # training data + self.mse_train = self.calculate_mean_square_error(self.y_train, self.predY_train) # Calculate MSE + if self.y_intercept: + coeff_terms = [self.intercept] + list(self.coef) + index_names = ["y_intercept"] + self.nodes + self.model_coef_df = pd.DataFrame(coeff_terms, index = index_names).transpose() + else: + coeff_terms = ["None"] + list(self.coef) + index_names = ["y_intercept"] + self.nodes + self.model_coef_df = pd.DataFrame(coeff_terms, index = index_names).transpose() + self.model_info = "fitted_model :)" + selected_row = self.model_coef_df.iloc[0] + selected_cols = selected_row[selected_row != 0].index # Filter out the columns with value 0 + if len(selected_cols) == 0: + self.model_nonzero_coef_df = None + self.num_final_predictors = 0 + else: + self.model_nonzero_coef_df = self.model_coef_df[selected_cols] + if len(selected_cols) > 1: # and self.model_type != "Linear": + self.netrem_model_predictor_results(y) + self.num_final_predictors = len(selected_cols) + if "y_intercept" in selected_cols: + self.num_final_predictors = self.num_final_predictors - 1 + return self + + + def netrem_model_predictor_results(self, y): # olders + """ :) Please note that this function by Saniya works on a netrem model and returns information about the predictors + such as their Pearson correlations with y, their rankings as well. + It returns: sorted_df, final_corr_vs_coef_df, combined_df """ + abs_df = self.model_nonzero_coef_df.replace("None", np.nan).apply(pd.to_numeric, errors='coerce').abs() + if abs_df.shape[0] == 1: + abs_df = pd.DataFrame([abs_df.squeeze()]) + sorted_series = abs_df.squeeze().sort_values(ascending=False) + sorted_df = pd.DataFrame(sorted_series) # convert the sorted series back to a DataFrame + sorted_df['Rank'] = range(1, len(sorted_df) + 1) # add a column for the rank + sorted_df['TF'] = sorted_df.index + sorted_df = sorted_df.rename(columns = {0:"AbsoluteVal_coefficient"}) + self.sorted_coef_df = sorted_df # print the sorted DataFrame + tg = y.columns.tolist()[0] + corr = pd.DataFrame(self.X_df.corrwith(y[tg])).transpose() + corr["info"] = "corr (r) with y: " + tg + all_df = self.model_coef_df + all_df = all_df.iloc[:, 1:] + all_df["info"] = "network regression coeff. with y: " + tg + all_df = pd.concat([all_df, corr]) + all_df["input_data"] = "X_train" + sorting = self.sorted_coef_df[["Rank"]].transpose().drop(columns = ["y_intercept"]) + sorting = sorting.reset_index().drop(columns = ["index"]) + sorting["info"] = "Absolute Value NetREm Coefficient Ranking" + sorting["input_data"] = "X_train" + all_df = pd.concat([all_df, sorting]) + self.corr_vs_coef_df = all_df + self.final_corr_vs_coef_df = self.corr_vs_coef_df[["info", "input_data"] + self.model_nonzero_coef_df.columns.tolist()[1:]] + + netrem_model_df = self.model_nonzero_coef_df.transpose() + netrem_model_df.columns = ["coef"] + netrem_model_df["TF"] = netrem_model_df.index.tolist() + netrem_model_df["TG"] = tg + if self.y_intercept: + netrem_model_df["info"] = "netrem_with_intercept" + else: + netrem_model_df["info"] = "netrem_no_intercept" + netrem_model_df["train_mse"] = self.mse_train + if self.model_type != "Linear": + netrem_model_df["beta_net"] = self.beta_net + if self.model_type == "LassoCV": + netrem_model_df["alpha_lassoCV"] = self.optimal_alpha + else: + netrem_model_df["alpha_lasso"] = self.alpha_lasso + if netrem_model_df.shape[0] > 1: + self.combined_df = pd.merge(netrem_model_df, self.sorted_coef_df) + self.combined_df["final_model_TFs"] = max(self.sorted_coef_df["Rank"]) - 1 + else: + self.combined_df = netrem_model_df + self.combined_df["TFs_input_to_model"] = len(self.final_nodes) + self.combined_df["original_TFs_in_X"] = len(self.gene_expression_nodes) + self.combined_df["standardized_X"] = self.standardize_X + self.combined_df["centered_y"] = self.center_y + return self + + def view_W_network(self): + roundedW = np.round(self.W, decimals=4) + wMat = ef.view_matrix_as_dataframe(roundedW, column_names_list=self.final_nodes, row_names_list=self.final_nodes) + w_edgeList = wMat.stack().reset_index() + w_edgeList = w_edgeList[w_edgeList["level_0"] != w_edgeList["level_1"]] + w_edgeList = w_edgeList.rename(columns={"level_0": "source", "level_1": "target", 0: "weight"}) + w_edgeList = w_edgeList[w_edgeList["weight"] != 0] + + G = nx.from_pandas_edgelist(w_edgeList, source="source", target="target", edge_attr="weight") + pos = nx.spring_layout(G) + weights_list = [G.edges[e]['weight'] * self.prior_network.edge_weight_scaling for e in G.edges] + + fig, ax = plt.subplots() + + if not self.overlapped_nodes_only: + nodes_to_add = list(set(self.gene_expression_nodes) - set(self.common_nodes)) + if nodes_to_add: + print(f":) {len(nodes_to_add)} new nodes added to network based on gene expression data {nodes_to_add}") + node_color_map = { + node: self.prior_network.added_node_color_name if node in nodes_to_add else self.prior_network.node_color_name + for node in G.nodes + } + nx.draw(G, pos, node_color=node_color_map.values(), edge_color=self.prior_network.edge_color_name, with_labels=True, width=weights_list, ax=ax) + else: + nx.draw(G, pos, node_color=self.prior_network.node_color_name, edge_color=self.prior_network.edge_color_name, with_labels=True, width=weights_list, ax=ax) + else: + nx.draw(G, pos, node_color=self.prior_network.node_color_name, edge_color=self.prior_network.edge_color_name, with_labels=True, width=weights_list, ax=ax) + + labels = {e: G.edges[e]['weight'] for e in G.edges} + return nx.draw_networkx_edge_labels(G, pos, edge_labels=labels, ax=ax) + + def compute_B_matrix_times_M(self, X): + """ M is N_sample, because ||y - Xc||^2 need to be normalized by 1/n_sample, but not the 2 * beta_L2 * c'Ac term + see https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html + The optimization objective for Lasso is: + (1 / (2 * n_samples)) * ||y - Xw||^2_2 + alpha * ||w||_1 where M = n_sample + Calculations""" + XtX = X.T @ X + beta_L2 = self.beta_net + N_squared = self.N * self.N + part_2 = 2.0 * float(beta_L2) * self.M / (N_squared) * self.A + B = XtX + part_2 + return B + + + def compute_B_matrix(self, X): + """ M is N_sample, because ||y - Xc||^2 need to be normalized by 1/n_sample, but not the 2 * beta_L2 * c'Ac term + see https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html + The optimization objective for Lasso is: + (1 / (2 * n_samples)) * ||y - Xw||^2_2 + alpha * ||w||_1 + where M = n_sample + Outputting for user """ + return self.compute_B_matrix_times_M(X) / self.M + + + def compute_X_tilde_y_tilde(self, B, X, y): + """Compute X_tilde, y_tilde such that X_tilde.T @ X_tilde = B, y_tilde.T @ X_tilde = y.T @ X """ + U, s, _Vh = np.linalg.svd(B, hermitian=True) # B = U @ np.diag(s) @ _Vh + if (cond := s[0] / s[-1]) > 1e10: + print(f'Large conditional number of B matrix: {cond: .2f}') + S_sqrt = ef.DiagonalLinearOperator(np.sqrt(s)) + S_inv_sqrt = ef.DiagonalLinearOperator(1 / np.sqrt(s)) + X_tilde = S_sqrt @ U.T + y_tilde = (y @ X @ U @ S_inv_sqrt).T + # assert(np.allclose(y.T @ X, y_tilde.T @ X_tilde)) + # assert(np.allclose(B, X_tilde.T @ X_tilde)) + # scale: we normalize by 1/M, but sklearn.linear_model.Lasso normalize by 1/N because X_tilde is N*N matrix, + # so Lasso thinks the number of sample is N instead of M, to use lasso solve our desired problem, correct the scale + scale = np.sqrt(self.N / self.M) + X_tilde *= scale + y_tilde *= scale + return X_tilde, y_tilde + + def predict_y_from_y_tilda(self, X, X_tilda, pred_y_tilda): + + X = self.preprocess_X_df(X) + # Transposing the matrix before inverting + X_transpose_inv = np.linalg.inv(X.T) + + # Efficiently compute pred_y by considering the dimensions of matrices + pred_y = np.dot(np.dot(X_transpose_inv, X_tilda.T), pred_y_tilda) + + return pred_y + + + def _apply_parameter_constraints(self): + constraints = {**NetREmModel._parameter_constraints} + for key, value in self.__dict__.items(): + if key in constraints: + if isinstance(constraints[key], tuple): + if isinstance(constraints[key][0], type) and not isinstance(value, constraints[key][0]): + setattr(self, key, constraints[key][0]) + elif constraints[key][1] is not None and isinstance(constraints[key][1], type) and not isinstance(value, constraints[key][1]): + setattr(self, key, constraints[key][1]) + elif value not in constraints[key]: + setattr(self, key, constraints[key][0]) + return self + + + def calculate_mean_square_error(self, actual_values, predicted_values): + difference = (actual_values - predicted_values)# Please note that this function by Saniya calculates the Mean Square Error (MSE) + squared_diff = difference ** 2 # square of the difference + mean_squared_diff = np.mean(squared_diff) + return mean_squared_diff + + + def predict(self, X_test): + if self.standardize_X: + self.X_test_standardized = self.standardize_X_data(X_test) + X_test = self.preprocess_X_df(self.X_test_standardized) + else: + X_test = self.preprocess_X_df(X_test) # X_test + return self.regr.predict(X_test) + + + def test_mse(self, X_test, y_test): + X_test = X_test.sort_index(axis=1) # 9/20 + if self.standardize_X: + self.X_test_standardized = self.standardize_X_data(X_test) + X_test = self.preprocess_X_df(self.X_test_standardized) + else: + X_test = self.preprocess_X_df(X_test) # X_test + if self.center_y: + y_test = self.center_y_data(y_test) + #X_test = self.preprocess_X_df(X_test) # X_test + y_test = self.preprocess_y_df(y_test) + predY_test = self.regr.predict(X_test) # training data + mse_test = self.calculate_mean_square_error(y_test, predY_test) # Calculate MSE + return mse_test #mse_test + + + def get_params(self, deep=True): + params_dict = {"info":self.info, "alpha_lasso": self.alpha_lasso, "beta_net": self.beta_net, + "y_intercept": self.y_intercept, "model_type":self.model_type, + "standardize_X":self.standardize_X, + "center_y":self.center_y, + "max_lasso_iterations":self.max_lasso_iterations, + "network":self.network, "verbose":self.verbose, + "all_pos_coefs":self.all_pos_coefs, "model_info":self.model_info, + "target_gene_y":self.target_gene_y} + if self.model_type == "LassoCV": + params_dict["num_cv_folds"] = self.num_cv_folds + params_dict["num_jobs"] = self.num_jobs + params_dict["alpha_lasso"] = "LassoCV finds optimal alpha" + params_dict["lassocv_eps"] = self.lassocv_eps + params_dict["lassocv_n_alphas"] = self.lassocv_n_alphas + params_dict["lassocv_alphas"] = self.lassocv_alphas + params_dict["optimal_alpha"] = self.optimal_alpha + elif self.model_type == "Linear": + params_dict["alpha_lasso"] = "No alpha needed" + params_dict["num_jobs"] = self.num_jobs + if self.model_type != "Linear": + params_dict["tolerance"] = self.tolerance + params_dict["lasso_selection"] = self.lasso_selection + if not deep: + return params_dict + else: + return copy.deepcopy(params_dict) + + + def set_params(self, **params): + """ Sets the value of any parameters in this estimator + Parameters: **params: Dictionary of parameter names mapped to their values + Returns: self: Returns an instance of self """ + if not params: + return self + for key, value in params.items(): + if key not in self.get_params(): + raise ValueError(f'Invalid parameter {key} for estimator {self.__class__.__name__}') + setattr(self, key, value) + return self + + + def __deepcopy__(self, memo): + cls = self.__class__ + result = cls.__new__(cls) + memo[id(self)] = result + for k, v in self.__dict__.items(): + setattr(result, k, deepcopy(v, memo)) + result.optimal_alpha = self.optimal_alpha + return result + + + def clone(self): + return deepcopy(self) + + + def score(self, X, y, zero_coef_penalty=10): + if isinstance(X, pd.DataFrame): + X = self.preprocess_X_df(X) # X_test + if isinstance(y, pd.DataFrame): + y = self.preprocess_y_df(y) + + # Make predictions using the predict method of your custom estimator + y_pred = self.predict(X) + + # Handle cases where predictions are exactly zero + y_pred[y_pred == 0] = 1e-10 + + # Calculate the normalized mean squared error between the true and predicted values + nmse_ = (y - y_pred)**2 + nmse_[y_pred == 1e-10] *= zero_coef_penalty + nmse_ = nmse_.mean() / (y**2).mean() + + if nmse_ == 0: + #return float(1e1000) # Return positive infinity if nmse_ is zero + + return float("inf") # Return positive infinity if nmse_ is zero + else: + return -nmse_ + + + +# def score(self, X, y, zero_coef_penalty=10): +# print("Debug: Start of score function") + +# if isinstance(X, pd.DataFrame): +# X = self.preprocess_X_df(X) +# print(f"Debug: preprocessed X, nulls: {X.isnull().sum().sum()}") + +# if isinstance(y, pd.DataFrame): +# y = self.preprocess_y_df(y) +# print(f"Debug: preprocessed y, nulls: {y.isnull().sum().sum()}") + +# y_pred = self.predict(X) +# print(f"Debug: y_pred, nulls: {np.isnan(y_pred).sum()}, infs: {np.isinf(y_pred).sum()}") + +# y_pred[y_pred == 0] = 1e-10 +# nmse_ = (y - y_pred)**2 + +# nmse_[y_pred == 1e-10] *= zero_coef_penalty +# denominator = (y**2).mean() + +# print(f"Debug: Denominator: {denominator}") + +# if denominator == 0: +# print("Debug: Denominator is zero.") +# return -1e10 # Some large negative value + +# nmse_ = nmse_.mean() / denominator + +# if nmse_ == 0: +# print("Debug: nmse_ is zero.") +# return -1e10 # Some large negative value + +# print(f"Debug: Returning score: {-nmse_}") +# return -nmse_ + + +# def score(self, X, y, zero_coef_penalty=10): +# if isinstance(X, pd.DataFrame): +# X = self.preprocess_X_df(X) # X_test +# if isinstance(y, pd.DataFrame): +# y = self.preprocess_y_df(y) +# # Make predictions using the predict method of your custom estimator +# y_pred = self.predict(X) +# # Calculate the normalized mean squared error between the true and predicted values +# nmse_ = (y - y_pred)**2 +# nmse_[y_pred==0] *= zero_coef_penalty +# nmse_ = nmse_.mean() / (y**2).mean() +# return -nmse_ # Return the negative normalized mean squared error + + + def updating_network_A_matrix_given_X(self) -> np.ndarray: + """ When we call the fit method, this function is used to help us update the network information. + Here, we can generate updated W matrix, updated D matrix, and updated V matrix. + Then, those updated derived matrices are used to calculate the A matrix. + """ + network = self.network + final_nodes = self.final_nodes + W_df = network.W_df.copy() # updating the W matrix + + # Simplified addition of new nodes + if self.gexpr_nodes_added: + for node in self.gexpr_nodes_added: + W_df[node] = np.nan + W_df.loc[node] = np.nan + + # Consolidated indexing and reindexing operations + W_df = W_df.reindex(index=final_nodes, columns=final_nodes) + + # Handle missing values + W_df.fillna(value=self.prior_network.default_edge_weight, inplace=True) + np.fill_diagonal(W_df.values, 0) + + N = len(final_nodes) + self.N = N + W = W_df.values + np.fill_diagonal(W, (W.sum(axis=0) - W.diagonal()) / (N - 1)) + + self.W = W + self.W_df = W_df + + # Check for symmetric matrix + if not ef.check_symmetric(W): + print(":( W matrix is NOT symmetric") + + # Update V matrix + self.V = N * np.eye(N) - np.ones(N) + + # Update D matrix + if not network.edge_values_for_degree: + W_bool = (W > network.threshold_for_degree) + d = np.float64(W_bool.sum(axis=0) - W_bool.diagonal()) + else: + if network.w_transform_for_d == "sqrt": + W_to_use = np.sqrt(W) + elif network.w_transform_for_d == "square": + W_to_use = W ** 2 + else: + W_to_use = W + d = W_to_use.diagonal() * (self.N - 1) + + # Handle pseudocount and self loops + d += network.pseudocount_for_degree + if network.consider_self_loops: + d += 1 + + d_inv_sqrt = 1 / np.sqrt(d) + self.D = ef.DiagonalLinearOperator(d_inv_sqrt) + + # Update inv_sqrt_degree_df + self.inv_sqrt_degree_df = pd.DataFrame({ + "TF": self.final_nodes, + "degree_D": self.D * np.ones(self.N) + }) + + Amat = self.D @ (self.V * W) @ self.D + A_df = pd.DataFrame(Amat, columns=final_nodes, index=final_nodes, dtype=np.float64) + + # Handle nodes based on `overlapped_nodes_only` + gene_expression_nodes = self.gene_expression_nodes + nodes_to_add = list(set(gene_expression_nodes) - set(final_nodes)) + self.nodes_to_add = nodes_to_add + if not self.overlapped_nodes_only: + for name in nodes_to_add: + A_df[name] = 0 + A_df.loc[name] = 0 + A_df = A_df.reindex(columns=sorted(gene_expression_nodes), index=sorted(gene_expression_nodes)) + else: + if len(nodes_to_add) == 1: + print(f"Please note that we remove 1 node {nodes_to_add[0]} found in the input gene expression data (X) that is not found in the input network :)") + elif len(nodes_to_add) > 1: + print(f":) Since overlapped_nodes_only = True, please note that we remove {len(nodes_to_add)} gene expression nodes that are not found in the input network.") + print(nodes_to_add) + A_df = A_df.sort_index(axis=0).sort_index(axis=1) + + self.A_df = A_df + self.A = A_df.values + self.nodes = A_df.columns.tolist() + self.tf_names_list = self.nodes + return self + + + def preprocess_X_df(self, X): + if isinstance(X, pd.DataFrame): + X_df = X + column_names_list = list(X_df.columns) + overlap_num = len(ef.intersection(column_names_list, self.final_nodes)) + if overlap_num == 0: + print("Please note: we are flipping X dataframe around so that the rows are samples and the columns are gene/TF names :)") + X_df = X_df.transpose() + column_names_list = list(X_df.columns) + overlap_num = len(ef.intersection(column_names_list, self.common_nodes)) + gene_names_list = self.final_nodes # so that this matches the order of columns in A matrix as well + X_df = X_df.loc[:, X_df.columns.isin(gene_names_list)] # filtering the X_df as needed based on the columns + X_df = X_df.reindex(columns=gene_names_list)# Reorder columns of dataframe to match order in `column_order` + X = np.array(X_df.values.tolist()) + return X +# def preprocess_X_df(self, X): +# if isinstance(X, pd.DataFrame): +# column_names_list = X.columns.tolist() +# overlap_num = len(set(column_names_list).intersection(self.final_nodes)) + +# if overlap_num == 0: +# print("Please note: we are flipping X dataframe around so that the rows are samples and the columns are gene/TF names :)") +# X = X.transpose() + +# gene_names_list = self.final_nodes # so that this matches the order of columns in A matrix as well +# X = X[gene_names_list] + +# return X.values + + def preprocess_y_df(self, y): + if isinstance(y, pd.DataFrame): + y = y.values.flatten() + return y + + + def return_Linear_ML_model(self, X, y): + regr = LinearRegression(fit_intercept = self.y_intercept, + positive = self.all_pos_coefs, + n_jobs = self.num_jobs) + regr.fit(X, y) + return regr + + + def return_Lasso_ML_model(self, X, y): + regr = Lasso(alpha = self.alpha_lasso, fit_intercept = self.y_intercept, + max_iter = self.max_lasso_iterations, tol = self.tolerance, + selection = self.lasso_selection, + positive = self.all_pos_coefs) + regr.fit(X, y) + return regr + + + def return_LassoCV_ML_model(self, X, y): + regr = LassoCV(cv = self.num_cv_folds, random_state = 0, + fit_intercept = self.y_intercept, + max_iter = self.max_lasso_iterations, + n_jobs = self.num_jobs, + tol = self.tolerance, + selection = self.lasso_selection, + positive = self.all_pos_coefs, + eps = self.lassocv_eps, + n_alphas = self.lassocv_n_alphas, + alphas = self.lassocv_alphas) + regr.fit(X, y) + return regr + + + def return_fit_ml_model(self, X, y): + if self.model_type == "Linear": + model_to_return = self.return_Linear_ML_model(X, y) + elif self.model_type == "Lasso": + model_to_return = self.return_Lasso_ML_model(X, y) + elif self.model_type == "LassoCV": + model_to_return = self.return_LassoCV_ML_model(X, y) + return model_to_return + + +def netrem(edge_list, beta_net = 1, alpha_lasso = 0.01, default_edge_weight = 0.1, + degree_threshold = 0.5, gene_expression_nodes = [], overlapped_nodes_only = False, + y_intercept = False, standardize_X = True, center_y = True, view_network = False, + model_type = "Lasso", lasso_selection = "cyclic", all_pos_coefs = False, tolerance = 1e-4, maxit = 10000, + num_jobs = -1, num_cv_folds = 5, lassocv_eps = 1e-3, + lassocv_n_alphas = 100, # default in sklearn + lassocv_alphas = None, # default in sklearn + verbose = False, + hide_warnings = True): + degree_pseudocount = 1e-3 + if hide_warnings: + warnings.filterwarnings("ignore") + default_beta = False + default_alpha = False + if beta_net == 1: + print("using beta_net default of", 1) + default_beta = True + if alpha_lasso == 0.01: + if model_type != "LassoCV": + print("using alpha_lasso default of", 0.01) + default_alpha = True + edge_vals_for_d = False + self_loops = False + w_transform_for_d = "none" + + prior_graph_dict = {"edge_list": edge_list, + "gene_expression_nodes":gene_expression_nodes, + "edge_values_for_degree": edge_vals_for_d, + "consider_self_loops":self_loops, + "pseudocount_for_degree":degree_pseudocount, + "default_edge_weight": default_edge_weight, + "w_transform_for_d":w_transform_for_d, + "threshold_for_degree": degree_threshold, + "verbose":verbose, + "view_network":view_network} + netty = graph.PriorGraphNetwork(**prior_graph_dict) # uses the network to get features like the A matrix. + greg_dict = {"network": netty, + "model_type": model_type, + "use_network":True, + "standardize_X":standardize_X, + "center_y":center_y, + "y_intercept":y_intercept, + "overlapped_nodes_only":overlapped_nodes_only, + "max_lasso_iterations":maxit, + "all_pos_coefs":all_pos_coefs, + "view_network":view_network, + "verbose":verbose} + if default_alpha == False: + greg_dict["alpha_lasso"] = alpha_lasso + if default_beta == False: + greg_dict["beta_net"] = beta_net + if model_type != "Linear": + greg_dict["tolerance"] = tolerance + greg_dict["lasso_selection"] = lasso_selection + if model_type != "Lasso": + greg_dict["num_jobs"] = num_jobs + if model_type == "LassoCV": + greg_dict["num_cv_folds"] = num_cv_folds + greg_dict["lassocv_eps"] = lassocv_eps + greg_dict["lassocv_n_alphas"] = lassocv_n_alphas + greg_dict["lassocv_alphas"] = lassocv_alphas + greggy = NetREmModel(**greg_dict) + return greggy + + + + +def generate_beta_networks(X_train, y_train, standardize_X, prior_network, overlapped_nodes_only = False, num = 10, max_beta = 200): + """ + Generate a grid of beta_network values to transform X_train. + + Parameters: + X_train (numpy array): training input data + + Returns: + numpy array: grid of beta_network values + """ + if isinstance(X_train, pd.DataFrame): + X_df = X_train + gene_names_list = list(X_df.columns) + if overlapped_nodes_only: + nodes_list = prior_network.nodes#self.nodes + common_nodes = ef.intersection(gene_names_list, nodes_list) + common_nodes.sort() + + X_df = X_df.loc[:, X_df.columns.isin(common_nodes)] + # Reorder columns of dataframe to match order in `column_order` + X_df = X_df.reindex(columns=common_nodes) + else: + X_df = X_df.reindex(columns=gene_names_list) + + if standardize_X: + print("standardizing X :)") + scaler = preprocessing.StandardScaler().fit(X_df) + X_train = scaler.transform(X_df) + else: + X_train = np.array(X_df.values.tolist()) + if isinstance(y_train, pd.DataFrame): + y_train = y_train.values.flatten() + beta_max = 0.5 * np.max(np.abs(X_train.T.dot(y_train))) + beta_min = 0.01 * beta_max + + var_X = np.var(X_train) + var_y = np.var(y_train) + if beta_max > max_beta: # max_beta used to prevent explosion of beta_net values + print(":) using variance to define beta_net values") + beta_max = 0.5 * np.max(np.abs(var_X * var_y)) * 100 + beta_min = 0.01 * beta_max + print(f"beta_min = {beta_min} and beta_max = {beta_max}") + + return np.logspace(np.log10(beta_max), np.log10(beta_min), num=num) + + +def generate_alpha_beta_pairs(X_train, + y_train, + prior_network, + overlapped_nodes_only: bool = False, + standardize_X: bool = True, + center_y: bool = True, + num_beta: int = 50, + num_alpha: int = 10, + max_beta: float = 200, + y_intercept: bool = False, + maxit: int = 10000, + all_pos_coefs: bool = False, + tolerance = 1e-4, + lasso_selection = "cyclic", + num_cv_folds = 5, + num_jobs = -1, + lassocv_eps = 1e-3, + lassocv_n_alphas = 100, + lassocv_alphas = None) -> dict: + """ + Generate a pairwise set of alpha_lasso and beta_network values. + + Parameters: + X_train (numpy array): training input data + y_train (numpy array): training output data + prior_network: The prior network to be used. + overlapped_nodes_only (bool): Whether to use only overlapped nodes. Default is False. + num (int): The number of beta_network values to generate. Default is 100. + + Returns: + dict: Dictionary containing grid of alpha_lasso values and beta_network values. + """ + beta_grid = generate_beta_networks(X_train, y_train, standardize_X, prior_network, overlapped_nodes_only, num=num_beta, max_beta = max_beta) + beta_alpha_grid_dict = {"beta_network_vals": [], "alpha_lasso_vals": []} + + try: + with tqdm(beta_grid, desc=":) Generating beta_net and alpha_lasso pairs") as pbar: + for beta in pbar: + # please fix it so it reflects what we want more... like the proper defaults + netremCV_demo = nm.NetREmModel(beta_network=beta, + model_type="LassoCV", + network=prior_network, + standardize_X = standardize_X, + center_y = center_y, + overlapped_nodes_only=overlapped_nodes_only) +# netremCV_demo = nm.NetREmModel(beta_network=beta, +# model_type="LassoCV", +# network=prior_network, +# overlapped_nodes_only=overlapped_nodes_only, +# standardize_X = standardize_X, +# y_intercept = y_intercept, +# max_lasso_iterations = maxit, +# all_pos_coefs = all_pos_coefs, +# tolerance = tolerance, +# lasso_selection = lasso_selection, +# num_cv_folds = num_cv_folds, +# #num_jobs = num_jobs, +# lassocv_eps = lassocv_eps, +# lassocv_n_alphas = lassocv_n_alphas, +# lassocv_alphas = lassocv_alphas) + + # Fit the model and compute alpha_max and alpha_min + netremCV_demo.fit(X_train, y_train) + X_tilda_train = netremCV_demo.X_tilda_train + y_tilda_train = netremCV_demo.y_tilda_train + alpha_max = 0.5 * np.max(np.abs(X_tilda_train.T.dot(y_tilda_train))) + alpha_min = 0.01 * alpha_max + + # Generate alpha_grid based on alpha_max and alpha_min + optimal_alpha = netremCV_demo.regr.alpha_ + alpha_grid = np.append(optimal_alpha, np.logspace(np.log10(alpha_min), np.log10(alpha_max), num=num_alpha)) + + # Find the best alpha using cross-validation + best_alpha = None + best_score = float('-inf') + for alpha in alpha_grid: + #netremCV_demo.regr.set_params(alpha=alpha) +# netremCV_demo = nm.NetREmModel(beta_network=beta, +# alpha_lasso = alpha, +# model_type="Lasso", +# network=prior_network, +# standardize_X = standardize_X, +# overlapped_nodes_only=overlapped_nodes_only, +# y_intercept = y_intercept, +# max_lasso_iterations = maxit, +# all_pos_coefs = all_pos_coefs, +# tolerance = tolerance, +# lasso_selection = lasso_selection, +# num_cv_folds = num_cv_folds, +# #num_jobs = num_jobs, +# lassocv_eps = lassocv_eps, +# lassocv_n_alphas = lassocv_n_alphas, +# lassocv_alphas = lassocv_alphas) + netremCV_demo = nm.NetREmModel(beta_network=beta, + alpha_lasso = alpha, + standardize_X = standardize_X, + center_y = center_y, + model_type="Lasso", + network=prior_network, + overlapped_nodes_only=overlapped_nodes_only) + scores = cross_val_score(netremCV_demo, X_train, y_train, cv=5) # You can change cv to your specific cross-validation strategy + mean_score = np.mean(scores) + if mean_score > best_score: + best_score = mean_score + best_alpha = alpha + + # Append the beta and best_alpha to the dictionary + beta_alpha_grid_dict["beta_network_vals"].append(beta) + beta_alpha_grid_dict["alpha_lasso_vals"].append(best_alpha) + + except Exception as e: + print(f"An error occurred: {e}") + print("finished generate_alpha_beta_pairs") + print(beta_alpha_grid_dict) + return beta_alpha_grid_dict + + +# Custom scoring function +def custom_mse(y_true, y_pred): + mse = mean_squared_error(y_true, y_pred) + pbar.update(1) # Update the progress bar + return -mse # Negate because GridSearchCV tries to maximize the score + + +def netremCV(edge_list, X, y, + num_beta: int = 50, + num_alpha: int = 10, + max_beta: float = 200, # max_beta used to help prevent explosion of beta_net values + reduced_cv_search: bool = False, # should we do a reduced search (Randomized Search) or a GridSearch? + default_edge_weight: float = 0.1, + degree_threshold: float = 0.5, + gene_expression_nodes = [], + overlapped_nodes_only: bool = False, + standardize_X: bool = True, + center_y: bool = True, + y_intercept: bool = False, + model_type = "Lasso", + lasso_selection = "cyclic", + all_pos_coefs: bool = False, + tolerance: float = 1e-4, + maxit: int = 10000, + num_jobs: int = -1, + num_cv_folds: int = 5, + lassocv_eps: float = 1e-3, + lassocv_n_alphas: int = 100, # default in sklearn + lassocv_alphas = None, # default in sklearn + verbose = False, + searchVerbosity: int = 2): + + prior_graph_dict = {"edge_list": edge_list, + "gene_expression_nodes":gene_expression_nodes, + "edge_values_for_degree": False, + "consider_self_loops":False, + "pseudocount_for_degree":1e-3, + "default_edge_weight": default_edge_weight, + "w_transform_for_d":"none", + "threshold_for_degree": degree_threshold, + "verbose":verbose, + "view_network":False} + + network_to_use = graph.PriorGraphNetwork(**prior_graph_dict) + X_train = X + y_train = y + beta_alpha_grid_dict = generate_alpha_beta_pairs(X_train, + y_train, network_to_use, + overlapped_nodes_only, standardize_X, center_y, + num_beta, num_alpha, + y_intercept, + maxit, + all_pos_coefs, + tolerance, + lasso_selection, + num_cv_folds, + num_jobs, + lassocv_eps, + lassocv_n_alphas, + lassocv_alphas) + print(f"Length of beta_alpha_grid_dict: {len(beta_alpha_grid_dict['beta_network_vals'])}") + + param_grid = [{"alpha_lasso": [alpha_las], "beta_net": [beta_net]} + for alpha_las, beta_net in zip(beta_alpha_grid_dict["alpha_lasso_vals"], + beta_alpha_grid_dict["beta_network_vals"])] + + + + print(":) Performing NetREmCV with both beta_network and alpha_lasso as UNKNOWN.") + + initial_greg = nm.NetREmModel(network=network_to_use, + y_intercept = y_intercept, + standardize_X = standardize_X, + center_y = center_y, + max_lasso_iterations=maxit, + all_pos_coefs=all_pos_coefs, + lasso_selection = lasso_selection, + tolerance = tolerance, + view_network=False, + overlapped_nodes_only=overlapped_nodes_only) + + pbar = tqdm(total=len(param_grid)) # Assuming we're trying 9 combinations of parameters + + if reduced_cv_search: + # Run RandomizedSearchCV + print(f":) since reduced_cv_search = {reduced_cv_search}, we perform RandomizedSearchCV on a reduced search space") + grid_search= RandomizedSearchCV(initial_greg, + param_grid, + n_iter=num_alpha, + cv=num_cv_folds, + #scoring=make_scorer(custom_mse, greater_is_better=False), + verbose=searchVerbosity) + else: + # Run GridSearchCV + grid_search = GridSearchCV(initial_greg, param_grid=param_grid, cv=num_cv_folds, + #scoring=make_scorer(custom_mse, greater_is_better=False), + verbose = searchVerbosity) + grid_search.fit(X_train, y_train) + + # Extract and display the best hyperparameters + best_params = grid_search.best_params_ + optimal_alpha = best_params["alpha_lasso"] + optimal_beta = best_params["beta_net"] + print(f":) NetREmCV found that the optimal alpha_lasso = {optimal_alpha} and optimal beta_net = {optimal_beta}") + + newest_netrem = nm.NetREmModel(alpha_lasso = optimal_alpha, + beta_net = optimal_beta, + network = network_to_use, + y_intercept = y_intercept, + standardize_X = standardize_X, + center_y = center_y, + max_lasso_iterations=maxit, + all_pos_coefs=all_pos_coefs, + lasso_selection = lasso_selection, + tolerance = tolerance, + view_network=False, + overlapped_nodes_only=overlapped_nodes_only) + newest_netrem.fit(X_train, y_train) + train_mse = newest_netrem.test_mse(X_train, y_train) + print(f":) Please note that the training Mean Square Error (MSE) from this fitted NetREm model is {train_mse}") + return newest_netrem + + +def organize_B_interaction_network(netrem_model): + B_interaction_df = netrem_model.B_interaction_df + num_TFs = B_interaction_df.shape[0] + B_interaction_df = B_interaction_df.reset_index().melt(id_vars='index', var_name='TF2', value_name='B_train_weight') + B_interaction_df = B_interaction_df.rename(columns = {"index":"TF1"}) + B_interaction_df = B_interaction_df[B_interaction_df["TF1"] != B_interaction_df["TF2"]] + B_interaction_df = B_interaction_df.sort_values(by = ['B_train_weight'], ascending = False) + B_interaction_df["sign"] = np.where((B_interaction_df.B_train_weight > 0), ":)", ":(") + B_interaction_df["potential_interaction"] = np.where((B_interaction_df.B_train_weight > 0), ":(", + ":( competitive (-)") + B_interaction_df["absVal_B"] = abs(B_interaction_df["B_train_weight"]) + B_interaction_df["info"] = "B matrix of TF-TF interactions" + B_interaction_df["candidate_TFs_N"] = num_TFs + B_interaction_df["target_gene_y"] = netrem_model.target_gene_y + B_interaction_df["num_final_predictors"] = netrem_model.num_final_predictors + B_interaction_df["model_type"] = netrem_model.model_type + B_interaction_df["beta_net"] = netrem_model.beta_net + B_interaction_df["X_standardized"] = netrem_model.standardize_X + B_interaction_df["gene_data"] = "training gene expression data" + + # Step 1: Sort the DataFrame + B_interaction_df = B_interaction_df.sort_values('absVal_B', ascending=False) + + # Step 2: Get the rank + B_interaction_df['rank'] = B_interaction_df['absVal_B'].rank(method='min', ascending=False) + + # Step 3: Calculate the percentile + B_interaction_df['percentile'] = (1 - (B_interaction_df['rank'] / B_interaction_df['absVal_B'].count())) * 100 + return B_interaction_df \ No newline at end of file diff --git a/code/old_code/refresh/PriorGraphNetwork.py b/code/old_code/refresh/PriorGraphNetwork.py new file mode 100644 index 0000000..29d474d --- /dev/null +++ b/code/old_code/refresh/PriorGraphNetwork.py @@ -0,0 +1,547 @@ +# PriorGraphNetwork Class: :) +# Standard libraries +import os +import sys +import random +import copy +import warnings + +# Third-party libraries +import pandas as pd +import numpy as np +import networkx as nx +import scipy +import matplotlib.pyplot as plt +import plotly.express as px +from tqdm import tqdm +import jinja2 + +# Scikit-learn imports +from sklearn import linear_model +from sklearn.metrics import make_scorer +from sklearn.exceptions import ConvergenceWarning +from sklearn.base import RegressorMixin, ClassifierMixin, BaseEstimator +from sklearn.model_selection import KFold, train_test_split, GridSearchCV, cross_val_score +from sklearn.decomposition import TruncatedSVD +from sklearn.linear_model import Lasso, LassoCV, LinearRegression, ElasticNetCV, Ridge + +# Scipy imports +from scipy.linalg import svd as robust_svd +from scipy.sparse.linalg.interface import LinearOperator + +# Type hinting +from typing import Optional, List, Tuple +from numpy.typing import ArrayLike + +# Custom module imports +import essential_functions as ef +import error_metrics as em +import DemoDataBuilderXandY as demo + + +import math +from sklearn.metrics.pairwise import cosine_similarity +from node2vec import Node2Vec + + +# Constants +rng_seed = 2023 # random seed for reproducibility +randSeed = 123 + +# Utility functions +printdf = lambda *args, **kwargs: print(pd.DataFrame(*args, **kwargs)) + + +class PriorGraphNetwork: + """:) Please note that this class focuses on incorporating information from a prior network (in our case, + a biological network of some sort). The input would be an edge list with: source, target, weight. If no + weights are given then a weight of 1 will be automatically assumed. + If the prior network is NOT symmetric (most likely directed): + please note we can use graph embedding techniques like weighted node2vec (on the directed graph) to generate + an embedding, find the cosine similarity, and then use the node-node similarity values for our network. + Ultimately, this class builds the W matrix (for the prior network weights to be used for our network + regularization penalty), the D matrix (of degrees), and the V matrix (custom for our approach).""" + + _parameter_constraints = { + "w_transform_for_d": ["none", "sqrt", "square"], + "degree_pseudocount": (0, None), + "default_edge_weight": (0, None), + "threshold_for_degree": (0, None), + "view_network":[True, False], + "verbose":[True, False]} + + def __init__(self, **kwargs): # define default values for constants + + self.edge_values_for_degree = False # we instead consider a threshold by default (for counting edges into our degrees) + self.consider_self_loops = False # no self loops considered + self.verbose = True # printing out statements + self.pseudocount_for_degree = 1e-3 # to ensure that we do not have any 0 degrees for any node in our matrix. + self.undirected_graph_bool = True # by default we assume the input network is undirected and symmetric :) + self.default_edge_weight = 0.1 # if an edge is missing weight information + # these are the nodes we may wish to include. If these are provided, then we may utilize these in our model. + self.gene_expression_nodes = [] # default if we use edge weights for degree: + # if edge_values_for_degree is True: we can use the edge weight values to get the degrees. + self.w_transform_for_d = "none" + #self.square_root_weights_for_degree = False # take the square root of the edge weights for the degree calculations + #self.squaring_weights_for_degree = False # square the edge weights for the degree calculations + # default if we use a threshold for the degree: + self.threshold_for_degree = 0.5 + self.view_network = False + #################### +# self.dimensions = 64 +# self.walk_length = 30 +# self.num_walks = 200 +# self.p = 1 +# self.q = 0.5 +# self.workers = 4 +# self.window = 10 +# self.min_count = 1 +# self.batch_words = 4 + self.node_color_name = "yellow" + self.added_node_color_name = "lightblue" + self.edge_color_name = "red" + self.edge_weight_scaling = 5 + self.debug = False + #################### + self.preprocessed_network = False # is the network preprocessed with the final gene expression nodes + self.__dict__.update(kwargs) # overwrite with any user arguments :) + required_keys = ["edge_list"] # if consider_self_loops is true, we add 1 to degree value for each node, + # check that all required keys are present: + missing_keys = [key for key in required_keys if key not in self.__dict__] + if missing_keys: + raise ValueError(f":( Please note since edge_values_for_degree = {self.edge_values_for_degree} ye are missing information for these keys: {missing_keys}") + self.network_nodes = self.network_nodes_from_edge_list() + # other defined results: + # added Aug 30th: + if isinstance(self.edge_list, pd.DataFrame): + print(":( Please input edgelist as a list of lists instead of a dataframe. For your edge_df, try: edge_df.values.tolist()") + #self.edge_list = self.edge_list.values.tolist() + self.original_edge_list = self.edge_list + if len(self.gene_expression_nodes) > 0: # is not None: + self.preprocessed_network = True + self.gene_expression_nodes.sort() + gene_expression_nodes = self.gene_expression_nodes + self.final_nodes = gene_expression_nodes + common_nodes = ef.intersection(self.network_nodes, self.gene_expression_nodes) + common_nodes.sort() + self.common_nodes = common_nodes + self.gex_nodes_to_add = list(set(self.gene_expression_nodes) - set(self.common_nodes)) + self.network_nodes_to_remove = list(set(self.network_nodes) - set(self.common_nodes)) + # filtering the edge_list: + self.edge_list = [edge for edge in self.original_edge_list if edge[0] in gene_expression_nodes and edge[1] in gene_expression_nodes] + else: + self.final_nodes = self.network_nodes + if self.verbose: + print(self.final_nodes) + self.tf_names_list = self.final_nodes + self.nodes = self.final_nodes + self.N = len(self.tf_names_list) + self.V = self.create_V_matrix() + if self.undirected_graph_bool: + self.directed=False + self.undirected_edge_list_to_matrix() + self.W_original = self.W + #self.edge_df = self.undirected_edge_list_updated().drop_duplicates() + else: + self.directed=True + self.W_original = self.directed_node2vec_similarity(self.edge_list, self.dimensions, + self.walk_length, self.num_walks, + self.p, self.q, self.workers, + self.window, self.min_count, self.batch_words) + self.W = self.generate_symmetric_weight_matrix() + self.W_df = pd.DataFrame(self.W, columns = self.nodes, index = self.nodes) + if self.view_network: + self.view_W_network = self.view_W_network() + else: + self.view_W_network = None + self.degree_vector = self.generate_degree_vector_from_weight_matrix() + self.D = self.generate_degree_matrix_from_weight_matrix() + # added on April 26, 2023 + degree_df = pd.DataFrame(self.final_nodes, columns = ["TF"]) + degree_df["degree_D"] = self.D * np.ones(self.N) + self.inv_sqrt_degree_df = degree_df ######## + self.edge_list_from_W = self.return_W_edge_list() + self.A = self.create_A_matrix() + self.A_df = pd.DataFrame(self.A, columns = self.nodes, index = self.nodes, dtype=np.float64) + self.param_lists = self.full_lists() + self.param_df = pd.DataFrame(self.full_lists(), columns = ["parameter", "data type", "description", "value", "class"]) + self.node_status_df = self.find_node_status_df() + self._apply_parameter_constraints() + + + def find_node_status_df(self): + """ Returns the node status """ + preprocessed_result = "No :(" + if self.preprocessed_network: + preprocessed_result = "Yes :)" + if self.preprocessed_network: + common_df = pd.DataFrame(self.common_nodes, columns = ["node"]) + common_df["preprocessed"] = preprocessed_result + common_df["status"] = "keep :)" + common_df["info"] = "Common Node (Network and Gene Expression)" + full_df = common_df + if len(self.gex_nodes_to_add) > 0: + gex_add_df = pd.DataFrame(self.gex_nodes_to_add, columns = ["node"]) + gex_add_df["preprocessed"] = preprocessed_result + gex_add_df["status"] = "keep :)" + gex_add_df["info"] = "Gene Expression Node Only" + full_df = pd.concat([common_df, gex_add_df]) + if len(self.network_nodes_to_remove) > 0: + net_remove_df = pd.DataFrame(self.network_nodes_to_remove, columns = ["node"]) + net_remove_df["preprocessed"] = preprocessed_result + net_remove_df["status"] = "remove :(" + net_remove_df["info"] = "Network Node Only" + full_df = pd.concat([full_df, net_remove_df]) + else: + full_df = pd.DataFrame(self.network_nodes, columns = ["node"]) + full_df["preprocessed"] = preprocessed_result + full_df["status"] = 'unknown :|' + full_df["info"] = "Original Network Node" + return full_df + + + def network_nodes_from_edge_list(self): + edge_list = self.edge_list + network_nodes = list({node for edge in edge_list for node in edge[:2]}) + network_nodes.sort() + return network_nodes + + + def _apply_parameter_constraints(self): + constraints = {**PriorGraphNetwork._parameter_constraints} + for key, value in self.__dict__.items(): + if key in constraints: + if isinstance(constraints[key], tuple): + if isinstance(constraints[key][0], type) and not isinstance(value, constraints[key][0]): + setattr(self, key, constraints[key][0]) + elif constraints[key][1] is not None and isinstance(constraints[key][1], type) and not isinstance(value, constraints[key][1]): + setattr(self, key, constraints[key][1]) + elif value not in constraints[key]: + setattr(self, key, constraints[key][0]) + return self + + + def create_V_matrix(self): + V = self.N * np.eye(self.N) - np.ones(self.N) + return V + + + + # Optimized functions + def preprocess_edge_list(self): + processed_edge_list = [] + default_edge_weight = self.default_edge_weight + + for sublst in self.edge_list: + if len(sublst) == 2: + processed_edge_list.append(sublst + [default_edge_weight]) + else: + processed_edge_list.append(sublst) + + return processed_edge_list + + def undirected_edge_list_to_matrix(self): + all_nodes = self.final_nodes + edge_list = self.preprocess_edge_list() + default_edge_weight = self.default_edge_weight + N = len(all_nodes) + self.N = N + weight_df = np.full((N, N), default_edge_weight) + + # Create a mapping from node to index + node_to_idx = {node: idx for idx, node in enumerate(all_nodes)} + + for edge in tqdm(edge_list) if self.verbose else edge_list: + try: + source, target, *weight = edge + weight = weight[0] if weight else default_edge_weight + weight = np.nan_to_num(weight, nan=default_edge_weight) + source_idx, target_idx = node_to_idx[source], node_to_idx[target] + weight_df[source_idx, target_idx] = weight + weight_df[target_idx, source_idx] = weight + except ValueError as e: + print(f"An error occurred: {e}") + continue + + np.fill_diagonal(weight_df, 0) + W = weight_df + np.fill_diagonal(W, (W.sum(axis=0) - W.diagonal()) / (N - 1)) + + if not ef.check_symmetric(W): + print(":( W matrix is NOT symmetric") + + self.W = W + self.W_df = pd.DataFrame(W, columns=all_nodes, index=self.final_nodes, dtype=np.float64) + return self + + + def generate_symmetric_weight_matrix(self) -> np.ndarray: + """generate symmetric W matrix. W matrix (Symmetric --> W = W_Transpose). + Note: each diagonal element is the summation of other non-diagonal elements in the same row divided by (N-1) + 2023.02.14_Xiang. TODO: add parameter descriptions""" + W = self.W_original + np.fill_diagonal(W, (W.sum(axis=0) - W.diagonal()) / (self.N - 1)) + symmetric_W = ef.check_symmetric(W) + if symmetric_W == False: + print(":( W matrix is NOT symmetric") + return None + return W + + + def return_W_edge_list(self): + wMat = ef.view_matrix_as_dataframe(self.W, column_names_list = self.tf_names_list, row_names_list = self.tf_names_list) + w_edgeList = wMat.stack().reset_index() + w_edgeList = w_edgeList[w_edgeList["level_0"] != w_edgeList["level_1"]] + w_edgeList = w_edgeList.rename(columns = {"level_0":"source", "level_1":"target", 0:"weight"}) + w_edgeList = w_edgeList.sort_values(by = ["weight"], ascending = False) + return w_edgeList + + + def view_W_network(self): + roundedW = np.round(self.W, decimals=4) + wMat = ef.view_matrix_as_dataframe(roundedW, column_names_list=self.nodes, row_names_list=self.nodes) + w_edgeList = wMat.stack().reset_index() + # https://stackoverflow.com/questions/48218455/how-to-create-an-edge-list-dataframe-from-a-adjacency-matrix-in-python + w_edgeList = w_edgeList[w_edgeList["level_0"] != w_edgeList["level_1"]] + w_edgeList = w_edgeList.rename(columns={"level_0": "source", "level_1": "target", 0: "weight"}) + w_edgeList = w_edgeList[w_edgeList["weight"] != 0] + + G = nx.from_pandas_edgelist(w_edgeList, source="source", target="target", edge_attr="weight") + pos = nx.spring_layout(G) + weights_list = [G.edges[e]['weight'] * self.edge_weight_scaling for e in G.edges] + fig, ax = plt.subplots() + if self.preprocessed_network and len(self.gex_nodes_to_add) > 0: + new_nodes = self.gex_nodes_to_add + print("new nodes:", new_nodes) + node_color_map = {node: self.added_node_color_name if node in new_nodes else self.node_color_name for node in G.nodes} + nx.draw(G, pos, node_color=node_color_map.values(), edge_color=self.edge_color_name, with_labels=True, width=weights_list, ax=ax) + else: + nx.draw(G, pos, node_color=self.node_color_name, edge_color=self.edge_color_name, with_labels=True, width=weights_list, ax=ax) + + labels = {e: G.edges[e]['weight'] for e in G.edges} + return nx.draw_networkx_edge_labels(G, pos, edge_labels=labels, ax=ax) + + + def generate_degree_vector_from_weight_matrix(self) -> np.ndarray: + """generate d degree vector. 2023.02.14_Xiang TODO: add parameter descriptions + """ + if self.edge_values_for_degree == False: + W_bool = (self.W > self.threshold_for_degree) + d = np.float64(W_bool.sum(axis=0) - W_bool.diagonal()) + else: + if self.w_transform_for_d == "sqrt": #self.square_root_weights_for_degree: # taking the square root of the weights for the edges + W_to_use = np.sqrt(self.W) + elif self.w_transform_for_d == "square": # self.squaring_weights_for_degree: + W_to_use = self.W ** 2 + else: + W_to_use = self.W + d = W_to_use.diagonal() * (self.N - 1) # summing the edge weights + d += self.pseudocount_for_degree + if self.consider_self_loops: + d += 1 # we also add in a self-loop :) + # otherwise, we can just use this threshold for the degree + if self.verbose: + print(":) Please note: we are generating the prior network:") + if self.edge_values_for_degree: + print(":) Please note that we use the sum of the edge weight values to get the degree for a given node.") + else: + print(f":) Please note that we count the number of edges with weight > {self.threshold_for_degree} to get the degree for a given node.") + if self.consider_self_loops: + print(f":) Please note that since consider_self_loops = {self.consider_self_loops} we also add 1 to the degree for each node (as a self-loop).") + print(f":) We also add {self.pseudocount_for_degree} as a pseudocount to our degree value for each node.") + print() # + return d + + + def generate_degree_matrix_from_weight_matrix(self): # D matrix + """:) Please note that this function returns the D matrix as a diagonal matrix + where the entries are 1/sqrt(d). Here, d is a vector corresponding to the degree of each matrix""" + # we see that the D matrix is higher for nodes that are singletons, a much higher value because it is not connected + d = self.degree_vector + d_inv_sqrt = 1 / np.sqrt(d) + # D = np.diag(d_inv_sqrt) # full matrix D, only suitable for small scale. Use DiagonalLinearOperator instead. + D = ef.DiagonalLinearOperator(d_inv_sqrt) + return D + + + def create_A_matrix(self): # A matrix + """ Please note that this function by Saniya creates the A matrix, which is: + :) here: %*% refers to matrix multiplication + and * refers to element-wise multiplication (for 2 dataframes with same exact dimensions, + component-wise multiplication) + # Please note that this function by Saniya creates the A matrix, which is: + # (D_transpose) %*% (V*W) %*% (D) + """ + A = self.D @ (self.V * self.W) @ self.D + approxSame = ef.check_symmetric(A) # please see if A is symmetric + if approxSame: + return A + else: + print(f":( False. A is NOT a symmetric matrix.") + print(A) + return False + + + def full_lists(self): + # network arguments used: + # argument, description, our value + full_lists = [] + term_to_add_last = "PriorGraphNetwork" + row1 = ["default_edge_w", ">= 0", "edge weight for any edge with missing weight info", self.default_edge_weight, term_to_add_last] + row2 = ["self_loops", "boolean", "add 1 to the degree for each node (based on self-loops)?", self.consider_self_loops, term_to_add_last] + + full_lists.append(row1) + full_lists.append(row2) + if self.pseudocount_for_degree != 0: + row3 = ["d_pseudocount", ">= 0", + "to ensure that no nodes have 0 degree value in D matrix", + self.pseudocount_for_degree, term_to_add_last] + full_lists.append(row3) + if self.edge_values_for_degree: + row_to_add = ["edge_vals_for_d", "boolean", + "if True, we use the edge weight values to derive our degrees for matrix D", True, term_to_add_last] + full_lists.append(row_to_add)# arguments to add in: + if self.w_transform_for_d == "sqrt": # take the square root of the edge weights for the degree calculations + row_to_add = ["w_transform_for_d: sqrt", "string", + "for each edge, we use the square root of the edge weight values to derive our degrees for matrix D", self.w_transform_for_d, term_to_add_last] + full_lists.append(row_to_add) + if self.w_transform_for_d == "square": # square the edge weights for the degree calculations + row_to_add = ["w_transform_for_d: square", "string", + "for each edge, we square the edge weight values to derive our degrees for matrix D", self.w_transform_for_d, term_to_add_last] + full_lists.append(row_to_add) + else: # default if we use a threshold for the degree: + row_to_add = ["edge_vals_for_d", "boolean", + "if False, we use a threshold instead to derive our degrees for matrix D", False, term_to_add_last] + full_lists.append(row_to_add) + self.threshold_for_degree = 0.5 # edge weights > this threshold are counted as 1 for the degree + to_add_text = "edge weights > " + str(self.threshold_for_degree) + " are counted as 1 for the degree" + row_to_add = ["thresh_for_d", ">= 0", + to_add_text, self.threshold_for_degree, term_to_add_last] + full_lists.append(row_to_add) + return full_lists + + +def build_prior_network(edge_list, gene_expression_nodes = [], default_edge_weight = 0.1, + degree_threshold = 0.5, + degree_pseudocount = 1e-3, + view_network = True, + verbose = True): + edge_vals_for_d = False + self_loops = False + w_transform_for_d = "none" + prior_graph_dict = {"edge_list": edge_list, + "gene_expression_nodes":gene_expression_nodes, + "edge_values_for_degree": edge_vals_for_d, + "consider_self_loops":self_loops, + "pseudocount_for_degree":degree_pseudocount, + "default_edge_weight": default_edge_weight, + "w_transform_for_d":w_transform_for_d, + "threshold_for_degree": degree_threshold, + "view_network": view_network, + "verbose":verbose} + if verbose: + print("building prior network:") + print("prior graph network used") + netty = PriorGraphNetwork(**prior_graph_dict) # uses the network to get features like the A matrix. #################### + return netty + + +def directed_node2vec_similarity(edge_list: List[Tuple[int, int, float]], + dimensions: int = 64, + walk_length: int = 30, + num_walks: int = 200, + p: float = 1, q: float = 0.5, + workers: int = 4, window: int = 10, + min_count: int = 1, + batch_words: int = 4) -> np.ndarray: + print("directed_node2vec_similarity") + """ Given an edge list and node2vec parameters, returns a scaled similarity matrix for the node embeddings generated + by training a node2vec model on the directed graph defined by the edge list. + + Parameters: + ----------- + edge_list: List[List[int, int, float]] + A list of lists representing the edges of a directed graph. Each edge should be a list of three values: + [source_node, target_node, edge_weight]. If no edge weight is specified, it is assumed to be 1.0. + + dimensions: int, optional (default=64) + The dimensionality of the node embeddings. + + walk_length: int, optional (default=30) + The length of each random walk during the node2vec training process. + + num_walks: int, optional (default=200) + The number of random walks to generate for each node during the node2vec training process. + + p: float, optional (default=1) + The return parameter for the node2vec algorithm. + + q: float, optional (default=0.5) + The in-out parameter for the node2vec algorithm. + + workers: int, optional (default=4) + The number of worker threads to use during the node2vec training process. + + window: int, optional (default=10) + The size of the window for the skip-gram model during training. + + min_count: int, optional (default=1) + The minimum count for a word in the training data to be included in the model. + + batch_words: int, optional (default=4) + The number of words in each batch during training. + + Returns: + -------- + scaled_similarity_matrix: np.ndarray + A scaled (0-1 range) cosine similarity matrix for the node embeddings generated by training a node2vec model + on the directed graph defined by the edge list. + """ + print("Creating directed graph from edge list") + directed_graph = nx.DiGraph() + for edge in edge_list: + source, target = edge[:2] + weight = edge[2] if len(edge) == 3 else 1.0 + directed_graph.add_edge(source, target, weight=weight) + + # Extract unique node names from the graph + node_names = list(directed_graph.nodes) + + print("Initializing the Node2Vec model") + model = Node2Vec(directed_graph, dimensions=dimensions, walk_length=walk_length, + num_walks=num_walks, p=p, q=q, workers=workers) + + print("Training the model") + model = model.fit(window=window, min_count=min_count, batch_words=batch_words) + + print("Getting node embeddings") + node_embeddings = np.array([model.wv[node] for node in node_names]) + + print("Calculating cosine similarity matrix") + similarity_matrix = cosine_similarity(node_embeddings) + + print("Scaling similarity matrix to 0-1 range") + scaled_similarity_matrix = (similarity_matrix + 1) / 2 + + # Create a DataFrame with rows and columns labeled as node names + similarity_matrix = pd.DataFrame(scaled_similarity_matrix, index=node_names, columns=node_names) + print(f":) First 5 entries of the symmetric similarity matrix for {similarity_matrix.shape[0]} nodes.") + print(similarity_matrix.iloc[0:5, 0:5]) + + similarity_df = similarity_matrix.reset_index().melt(id_vars='index', var_name='TF2', value_name='cosine_similarity') + #similarity_df = similarity_df[similarity_df['index'] < similarity_df['TF2']] + similarity_df = similarity_df.rename(columns = {"index":"node_1", "TF2":"node_2"}) + similarity_df = similarity_df[similarity_df["node_1"] != similarity_df["node_2"]] + results_dict = {} + print("\n :) ######################################################## \n") + print(":) Please note that we return a dictionary with 3 keys based on Node2Vec and cosine similarity computations:") + print("1. similarity_matrix: the cosine similarity matrix for the nodes in the original directed graph") + results_dict["similarity_matrix"] = similarity_matrix + print("2. similarity_df: simplified dataframe of the cosine similarity values from the similarity_matrix.") + + results_dict["similarity_df"] = similarity_df + print("3. NetREm_edgelist: an edge_list that is based on similarity_df that is ready to be input for NetREm.") + + results_dict["NetREm_edgelist"] = similarity_df.values.tolist() + print(results_dict.keys()) + return results_dict \ No newline at end of file diff --git a/code/old_code/refresh/directed_to_undirected_network_example.ipynb b/code/old_code/refresh/directed_to_undirected_network_example.ipynb new file mode 100644 index 0000000..121c8ac --- /dev/null +++ b/code/old_code/refresh/directed_to_undirected_network_example.ipynb @@ -0,0 +1,951 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c912f6d3", + "metadata": {}, + "source": [ + "# Working with Weighted Directed Input Networks in NetREm\n", + "## Converting Weighted Directed Networks to Undirected Similarity Networks :)\n", + "### By: Saniya Khullar, Xiang Huang, Raghu Ramesh, John Svaren, Daifeng Wang\n", + "\n", + "The code for NetREm is optimized for undirected, weighted, networks.\n", + "\n", + "\n", + "Please note that in this Jupyter notebook, we will go through how to work with directed prior network graphs in NetREm (Network Regression Embeddings).\n", + "\n", + "There are many ways to do this. 1 of the ways is via the popular graph embedding method of weighted node2vec, where we learn embeddings for each of the nodes based on a random walk followed by a Skipgram model. Hopefully these embeddings capture as much information about the original directed graph network. \n", + "\n", + "This is similar to the word2vec approach in Natural Language Processing (NLP) tasks.\n", + "Then, we will calculate the similarity among nodes based on the cosine similarity values of their embeddings. Ultimately, we will build out an undirected, weighted network among the predictors, which is a similarity network. \n", + "\n", + "This similarity network may be our input network for NetREm as it is undirected and weighted :)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "a7271420", + "metadata": {}, + "outputs": [], + "source": [ + "printdf = lambda *args, **kwargs: print(pd.DataFrame(*args, **kwargs))\n", + "rng_seed = 2023 # random seed for reproducibility\n", + "randSeed = 123\n", + "from packages_needed import *\n", + "import error_metrics as em \n", + "from packages_needed import *\n", + "import Netrem_model_builder as nm\n", + "import DemoDataBuilderXandY as demo\n", + "import PriorGraphNetwork as graph\n", + "import netrem_evaluation_functions as nm_eval\n", + "import essential_functions as ef" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "1d304b66", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[['TF1', 'TF2', 0.4],\n", + " ['TF2', 'TF3', 0.7],\n", + " ['TF3', 'TF4', 0.2],\n", + " ['TF3', 'TF5', 0.8],\n", + " ['TF4', 'TF6', 0.5],\n", + " ['TF5', 'TF7', 0.6],\n", + " ['TF6', 'TF8', 0.3],\n", + " ['TF7', 'TF9', 0.9],\n", + " ['TF8', 'TF10', 0.1],\n", + " ['TF9', 'TF1', 0.7]]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Create a small fake weighted directed network of 10 nodes \"TF1 to TF10\"\n", + "# Given by a DataFrame of [source, target, weight]\n", + "data = {\n", + " 'source': [\"TF1\", \"TF2\", \"TF3\", \"TF3\", \"TF4\", \n", + " \"TF5\", \"TF6\", \"TF7\", \"TF8\", \"TF9\"],\n", + " 'target': [\"TF2\", \"TF3\", \"TF4\", \"TF5\", \"TF6\",\n", + " \"TF7\", \"TF8\", \"TF9\", \"TF10\", \"TF1\"],\n", + " 'weight': [0.4, 0.7, 0.2, 0.8, 0.5, \n", + " 0.6, 0.3, 0.9, 0.1, 0.7]\n", + "}\n", + "\n", + "df = pd.DataFrame(data)\n", + "# Convert the DataFrame to a list of edge tuples\n", + "edge_list = [list(x) for x in df.to_records(index=False)]\n", + "edge_list" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9dc946f1", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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Ip9++ilz586levXqgG6+B3jyySf5+uuv+d///kefPn2IiYlh7NixrFq1iu3bt1/zd1dYFoslz/t0dXUtdGCV3ZeiSZMmubabTCbq16+fq6+FKAOUKDOmTp2qALV169ar7lO1alXVoEED68/jxo1TV94mderUUa6ururgwYO5tj/++OPK19dXHT16NNf29957TwFq7969SimlfvzxRwWob7755pr59fHxUUOGDMmzvaDpfPnllwpQf/zxR679Hn30UQWoqVOnXjP9yMhIBahff/1VKaVUp06dVK1atVRqaqpSSqkhQ4YoHx8f6/6xsbHKzc1NjRw5Mtd5Ll68qKpVq6buvfde67YRI0bk+b0qpdShQ4cUoH788UellFLr1q1TgHrxxRdVUFCQdb/u3burDh06WH8eOHCg8vDwULGxsbnO17NnT+Xt7a3Onz+f6z2FhYXlSfvy+2PZsmWqfPny6p577rG+32spaPpKKQWoESNGXPecl7vyWlypc+fOCsjzPXjw4Kue82r319W8++67ClBHjhzJtX3//v0KUE899VSu7Zs3b1aAevXVVwucxpX31OWOHDmS73sE1LJly/I95tdff1WAioyMzPPaG2+8oQB16tSpPK/16NFD1a1bt8D5FiWfPCYQuSilCrRfkyZNqFu3bq5tCxcuJDw8nBo1apCVlWX9zn7uuHr1agD+/PNPPD09r/kJ+1oKmk5kZCTlypWjb9++uY6/svNVQb399tscP36cjz/+ON/XlyxZQlZWFg899FCufHl6etK5c+dr9ujOFhISQmBgIMuXLwdg2bJl3HLLLTzwwAMcOXKEw4cPk56ezrp163J19Fy5ciVdu3blpptuynW+oUOHkpKSkqej2t13333VPEybNo1evXoxfPhwZs+ejaen53XzXdj0i0NISAhbt27N9T1p0qRiTzcyMhIgz8iENm3a0KBBA1asWGHT9J555pk877Nt27Y3fL6rtSg4ahSRcAx5TCCskpOTSUhI4JZbbrnuvtnNpJc7c+YMCxYswGQy5XtMfHw8AHFxcdSoUeOGm28Lmk5CQoK1I+TlqlWrdkPpdujQgTvvvJO33nqLxx57LN98AbRu3Trf4wv6frt27cpff/0F6McB3bt355ZbbqFq1aosX76c0NBQ6yOQbAkJCflekxo1alhfv1x++2abNWsWXl5eDB8+vMAVQmHTLw6enp65OsbaS/Z7u9r7P3r0qE3Tq1Wrlk3ep5+fH5D/30liYiKVK1cuchqi5JBgQFgtWrQIs9mcq6Pe1eRXSVSpUoUmTZrwxhtv5HtMdsXg7+/PunXrsFgsNxQQFDQdPz8/tmzZkuf1wnYgvNybb75J48aNmTx5cr75At2Du06dOjecRteuXfnuu+/YsmULmzdvZsyYMQBERESwbNkyjh49iq+vb64e5X5+fpw6dSrPuU6ePJkrb9muVcnPmDGDsWPH0rlzZ5YuXUqzZs2um+fCpl+aZFeqp06dyjPy5uTJk0773rOD/n/++cfa9wF0v4sDBw4waNAgR2VNOIA8JhAAxMbG8vzzz1OhQgUef/zxGzpHnz592LNnDyEhIbRq1SrPd3Yl3bNnT9LS0q476Y+Hhwepqak3nE54eDgXL15k/vz5uY6fOXPmDb0/gPr16/Pwww/z6aefEhsbm+u12267DTc3Nw4fPpxvvi7/NOfh4QGQ7/vr2rUrhmEwduxYXFxcCAsLA6Bbt25ERkaybNkywsLCcrWMdO3alZUrV1or32w//vgj3t7e1x1yd7nKlSuzfPlyGjRoQHh4OJs2bbruMbZM31ld7ZpFREQA8NNPP+XavnXrVvbv30/Xrl3tk8FCatu2LdWrV8/zdzhnzhwuXbpE//79HZMx4RDSMlAG7dmzx/o8++zZs6xdu5apU6fi6urKvHnzck3kUhgTJ05k2bJldOjQgaeffpp69eqRlpZGTEwMixcvZsqUKdSqVYtBgwYxdepUnnjiCQ4ePEh4eDgWi4XNmzfToEEDBg4cCOhPLqtWrWLBggVUr16dcuXKUa9evQKn89BDD/Hhhx/y0EMP8cYbbxAaGsrixYtZsmRJkX5/48ePZ8aMGURGRuLj42PdHhgYyMSJExk9ejTR0dHcfvvtVKpUiTNnzrBlyxZ8fHysQzCzP5W9/fbb9OzZE1dXV5o0aYK7uzsBAQE0btyYpUuXEh4ejre3N6CDgcTERBITE/nggw9y5WncuHHWvhSvvfYalStXZsaMGSxatIh33nmHChUqFOo9litXjr/++ov+/fvTvXt35s+fn2uynyvZOv3isnr1auLi4gA9zv7o0aPMmTMHgM6dO1/z3s++Zh9//DFDhgzBZDJRr1496tWrx2OPPcann36Ki4sLPXv2tI4muOmmmxg1alTxv7HLpKSksHjxYgBrILd69Wri4+Px8fGx9q1xdXXlnXfe4cEHH+Txxx9n0KBBREVF8eKLL9K9e3eHTTYmHMTRPRiF/WT3Fs/+dnd3VwEBAapz585q8uTJ6uzZs3mOudpogt69e+ebRlxcnHr66adVUFCQMplMqnLlyqply5Zq9OjR6tKlS9b9UlNT1WuvvaZCQ0OVu7u78vPzUxEREWrDhg3WfXbu3Kk6duyovL29FaA6d+5c6HSOHz+u7r77buXr66vKlSun7r77brVhw4YbGk1wuVdffVUB+fb8/v3331V4eLgqX7688vDwUHXq1FH33HOPWr58uXWf9PR0NXz4cOXv768Mw8jTS33UqFEKUG+88Uauc4eGhipA7d69O0+6//zzj7rjjjtUhQoVlLu7u2ratGme93it95TfaJP09HR19913K09PT7Vo0aKr/q4Kmr5SxTeaoFGjRtc9z9VGHXCVHvdXeuWVV1SNGjWUi4tLrmPMZrN6++23Vd26dZXJZFJVqlRRDzzwgDp27Fhh3maBRhO8++671zzHtUYd1KlTJ8/+M2fOVE2aNFHu7u6qWrVq6umnn1YXL14sVL5FyWcoVcDu40IIIYQolaTPgBBCCFHGSTAghBBClHESDAghhBBlnAQDQgghRBknwYAQQghRxkkwIIQQQpRxEgwIIYQQZZwEA0IIIUQZJ8GAEEIIUcZJMCCEEEKUcRIMCCGEEGWcBANCCCFEGSfBgBBCCFHGSTAghBBClHESDAghhBBlnAQDQgghRBknwYAQQghRxkkwIIQQQpRxEgwIIYQQZZybozMghKMkW5I5az5LfFY86SodM2ZcccXD8KCKWxUCXAPwcfFxdDaFjcl1FyIvCQZEmRKXFcfu9N0czjxMqkoFwPjvK5v67wvAy/AixBRCE48m+Lv5OyTPoujkugtxbYZSSjk6E0IUJ6UUhzMPsy1tG6fNpzEwrIV+QWTvX821Gi09WxJiCsEwjOsfKBxKrrsQBSfBgCjVki3JrExZSXRmdKErgytlHx9sCibCO0Kakp2YXHchCkeCAVFqRWVEsTx5OZlkFqkyuJKBgQkT3Xy6EeoearPzCtuQ6y5E4UkwIEql7WnbWZu6ttjTCfMKo7ln82JPRxSMXHchbowMLRSljr0qBIA1qWvYkbbDLmmJa5PrLsSNk2BAlCpRGVF2qxCyrUldQ1RGlF3TFLnJdReiaCQYEKVGsiWZ5cnLHZL28uTlJFuSHZJ2WSfXXYiik2BAlApKKVamrCSTTIekn0kmK1NWIl1w7EuuuxC2IcGAKBUOZx4mOjPapr3HC0OhiM6M5nDmYYekX1bJdRfCNiQYEKXCtrRtuWaTcwQDg+1p22/8BErB+fM2y09ZUCquuxBOQKYjFiVWYGAgR48eLdQxI+aPYOaImZw7du66+36U+NFVX4vdHstHt32ExWzJdW7VSRFvjqeKa5WCZ0opWLkSxo+HTZsgIQHKly/48fnYunUr48aNY9OmTWRkZNCoUSOeffZZBg0aVKDj169fz9y5c1m9ejUxMTEkJycTGBhIv379eOWVV6hQoUKR8lcU9rzusTti2fjjRo7vOk7SqSSSzyXj4uKCr78vNzW9iTaD2tC4Z2NOmU8V/roL4USkZUCIQspKz2LmiJm5AoFsBga70nYV7ERKwYoVEBYG3bpBWhosWFDkQGDVqlXceuutrF+/ngEDBvDUU0+RkJDA4MGDeeuttwp0jnvuuYdPP/2U8uXLM2TIEEaMGIGPjw/vvPMOrVu3Jj4+vkh5LCkOrTvExmkbObbzGBfOXMCcYSYzLZNzx86xe+Fuvh38LX+89kfhrrsQTkhaBkSJNXr0aJKSktiUuolMlUlqUirLPlhmfb1el3rUC6+X65gqgbk/ufkF+tFxWMdCpbv4zcWcPng639eynyF3pevVT3B5S8C6ddCqFSxcCL16QRHnvjebzQwfPhwXFxfWrl1LkyZNABg3bhzt2rVj3LhxDBgwgJCQkGue5//+7/8YMmQIAQEBubaPGDGCKVOmMGHCBD799NMi5fVG2fO6u7i5UKtJLW5qdhPlAsrh5u7G2UNn2TFvB+ZMMwCrvlhFl6e6EF39OtddCCcmwYAosR599FGSLcmYkkwAJMQm5KoUAtsEEjEy4prnqFiz4nX3uVzM3zGs+nwVALf0voV/Fv2TZ58UlUKKJQVvF+/cLxRjEJBt5cqVREdH88gjj1gDAQAfHx/Gjh3LwIEDmTp1Kq+//vo1z/PCCy/ku33s2LF8+eWXrF692ib5vRH2vO5dnuxClye75NletW5VFr2+CABlUZw7fo4K1Srkf92FKAHkMYEo0c6az9otrcy0TOvjgZCOIYQ9FlawfOX3OGDhQtiyBXr3tlkgAPoRgWEYdO/ePc9rPXr0AChSRW4y6QrYzc2xnyPsed0vl5GawfF/jrN3yV7rNld3V/yD/R2aLyGKSloGRIkWnxVfpFXpzp84z8pPV+bZXr1BdRp0a5Br2+LJizkbdRZ3H3cGfTqIc8fz74xmYBCXFUegW51ibwm4UlSUnhEvNDTvQjoVK1akSpUq1n1uxHfffQfAbbfddsPnsAV7XneAGSNmsPXnrXm2Gy4G/Sb2w6eyT851NwXeUJ6EcCQJBkSJlq7Si1QpJMQkMH/c/DzbWw9qnatSOLLlCKu+WAVA3/F9qRJY5ZrBQPreHTD8Udi1C+rXh3ffhQ4ddBCwadMN5RXDgHbtrrlLUlISwFV7+5cvX54TJ07cUPI7d+5k4sSJVKtW7aqPEfLYtEm3jNhYuv8xDL/iv+7X4u7jzoD3BtD6vtbAf9ddpd9QfoRwNAkGRIlmxlzsaWSkZjDzfzNRFkVoWCgdH75+xzPz0j91IABw4AAUtPK8Fnd3SHdMZXPkyBH69OmDxWJh1qxZVK5cuWAHdu4MGRk2z4/5jTvhsc7gap85Blrc1YLq9auTeiGVE7tPsH/FfjKSM5jx5AxitsYw4L0BOl92uB+FKA4SDIgSzRXXIh0f0jGEkQtGXnOf1VNWE3coDg9fDwZ9OgijAE38rv36w5JEWLMGgoLgySfhttvAtQj5LUC62S0C2S0EV7pw4UKh5wg4evQo4eHhJCQkMHfuXMLCrt5XIo8dO4qlZcC1XBS4HgPyDu8siIJc98s16NYgV4vB1l+2MuPJGQCs/3499SPq07RX0yLfj0I4igQDokTzMDyKfSrai2cvApB+KZ2JTSdedb/P+34OwP/m/4923R6C1ath61aYMAFefBG+/x5eew3uvbdoQcE1ZPcViIqKonnz5rleO3/+PPHx8XTsWPChlDExMYSHh3P69GnmzJlDz549C5ehhg0Lt38BeaSmoNJii+XcBXFLz1ty/Xxo3SGa9GqCh+HhoBwJUTQymkCUaFXcqjhsXvqrUSj83XTvclq3zhk5EBIC998PjRvDzz+D2fZNyp07d0YpxdKlS/O8tmTJEgC6dOlSoHPFxMTQpUsXTp06xezZs+nTp48ts1ok9rjumWmZ7PlzT76TS+1dtjf3BuOK6y5ECSMtA6JEC3ANuP5ORVTzlpo0vaNpnu2XEi5xeEPOAjUhHULw9fPF1883b76yg4LsloL774eJE23eUtC1a1eCg4OZOXMmI0eOpGlTne+LFy8yadIkTCYTQ4YMse6fkJBAfHw8VapUwc/Pz7r9ykCgb9++NslfkZnNsHMnARsjYbCpWJPKTM/k28HfUqF6BepH1Mcv0A9zpplT+06x5689ufZtdFsjwD73oxDFQYIBUaL5uPjgZXiRqlKLLY2297el7f1t82yPWhdlfTQAcPvLtxPaKRRvw/vqE88Uc1Dg6urKt99+y+23386tt97KoEGDKF++PHPnziUmJoY33niDm2++2br/p59+ysSJExk/fjyvvfaadXuXLl2IjY2lffv27Ny5k507d+ZJa9y4cUXKa4FYLLBnjx6iGRmp+2CcP4+PlxdefcaTWqH4m+WTTiWxecbmq77e/f+6Uzes7rWvuxBOToIBUeKFmELYm7H3+jvagYFBsCn4+jteLSiYOBEGDChSHrp06cK6desYN24cv/76q3WhojfeeIOBAwfmzq9hWL8vd+zYMQzDYNOmTWzKZyikYRjFEwwoBfv364o/MhJWrdILN7m766GZo0ZBeDi0aUNI1rpive4e3h70m9SP6E3RnNp/ikvxl8hIzsDkZaJy7coEtQmi3QPtqN2idsGvuxBOylCqGLr6CmFHcVlxzLw409HZsBpcfnDhV6/LDgqWLoX4+CIvVlRiKAWHDuVU/pGRcOYMuLlB27a64g8Ph/btwcsr16Gl4roL4SSkZUCUeP5u/lRzrcYZ8xmHdiY0MKjmWu3GKoTsloKsLF0RlmYxMTnN/pGRcOIEuLjoGRqHDoWICOjYEXx8rnmaUnHdhXAS0jIgSoVDGYdYlLzI0dmgt09vbna/+fo7liXHj+f+5B8To+dMaNZMV/zh4XDrrTfUGuI01329Ozcn+kD16vp9XP7t46ODHSGcWCn/CCLKihBTCMGmYI5kHnHIp0QDgyBTECGmay8NXKZYLHoq5uy1EG65Bfr21ZV/WBgUdBbDa3CK6+4WREi/O/X7zXcnA3x9cwcI5crl/rlbN7jjDrvmXYjLSTAgSgXDMIjwjuDHpB/JwPbT316PCRMR3hEFmp2wzDh3TldykyfraYn9bT8G3ymuu08Exptvwksv6Y3BwTBiBDRoABcu6O+LF3P+f/m206f1/00mCQaEQ8ljAlGqRGVEsTh5sd3T7eXTi1D3vCsFlllKFdvKjPlx+HVXCnr00MMgQ0Jg/Xro2RPef18HBUI4OXmQJUqVUPdQwv4t3Nz7RRXmFSaBwJXs3EIS6h5KmFch1kywgVzX3TDg228hOVk/GvntN71A1S23wNNP6+GRQjgxCQZE6fLHHzTvOJywZeftklyYVxjNPZtff0dR7Jp7NrdbQJDvda9TB957D777Dry99XwJb74JP/wAoaHw8ceQmWmX/AlRWPKYQJQeq1bB7bfrTmo//0yUOZrlycvJJNOmncsMDEyY6ObTrXS0CCiV822x5F5l0MVFf+rN7g1fAvpERGVEOe66K6VXp9y/Xz8yqFBBz5vw2mu65SA0VD866NWrRPwuRdkhwYAoHf7+Ww9Ta9cOFiwADz1NbbIlmZUpK4nOjMbAKFLlkH18sCmYCO8IfFyuPQ7eaZnNemz/kSN6mN+xY3p+Ay8vCAzUSy4HBuoOfyW0wnLodY+N1YtRDRigWwmy7d4N//d/sGIFdO8OH3yg9xPCCUgwIEq+Awf0OPWbb4Zly/QwrssopTiceZhtads4bT5d6Mohe//qrtVp4dmCEFNIyRo1kJUF27blTPSzfj2kpOhPrWFhObP8NWlSqsbDO/S6f/stPPooLFqkWwFyMqWD1eeeg+hoePxxPfNkIUdaJCQkcOHCBdLS0mggHRSFDUgwIEq22Fg9W13FirB69XXHrsdlxbE7fTfRmdGkqBRAF/oGOYW8+u8LwNvwJtgUTBOPJiVnedr/VvazTvKzdq0exubjk7vyb97cZqslOju7X3el9GiCf/6BvXv1/Xm5jAz4/HMdCDz+OLz1VoFaYcxmM6+88gqzZ8/mzJkzeHl50bZtWz766CPq1atX+HwK8R8JBkTJdfasbhHIzIR166BGjUIdnmJJ4az5LHFZcaSrdMyYccUVD8MDfzd/AlwDbLIKnVKqeFsSslf2y678V6+G8+d1s3/HjjmVf6tWejx7GWev686xY/oxQP/+MHVq/vskJOjOhp6e1w0GTp48yfPPP8+sWbNo2LAh/fr14/z586xYsYLz58/z008/0a1bt+K/30SpJMGAKJkuXNAV3MmTOhAIcY6Z//bu3cumTZtITk6mQ4cONGjQAB8fHywWCy62aoJXSj8aiYzUTf+rV+vFjdzd9YI+2ZV/27bWvhPCQb7/Hh55RK870bv3DZ8mKyuLoUOHMnPmTIYOHcorr7xCaGgomZmZLFu2jIEDB9KnTx9mznSehZtEySLBgCh5UlN1E+yuXboibNLE0Tni22+/5ZNPPmH//v34+Phw6dIlPD09ad++PX/88Qfe3kX4pHnlyn6rVumZ6wqwsp9wMKV0ELBzp35cUKnSDZ1m5syZPPDAA/Tu3ZtPP/2UwMBAzGYzrv895hkwYAArVqxg/fr10odA3BCZjliULJmZcN99sGULLF/uFIHA119/zZgxY6hevTrvvPMOoaGhuLu7M3HiRFasWMF3333HE088gakwTfQxMbkX9zl+PGdlvyFDdOXfsWOezpLCyRgGfP21flwwapSec6CQLly4wJgxY/Dy8mLixIkEBgYC4OrqisViwWw2U7FiRc6fP4+np6dt8y/KDAkGRMlhsegm17/+gvnzoUOHYkuqoM9d09LSmDhxIl5eXvzyyy/Ur1/f+prZbOb+++9n586dBQsEMjLgySd10//lK/vde2/Oyn4V7Du7orCBWrV0QPDTTzd0+Ndff01MTAwvv/wyzZvnnujIMAxMJhOHDh0iKCgIaegVN0qCAVEyKKU/Wf30E/z8s55cqBicO3cOpRSVC7ii3ubNm8nMzKRjx47UqVMn12tVqlQhKSkJPz8/oAABhru77vhn45X9hBO49179XUhJSUnMnTuXqlWrMmzYsFyvZT8m2Lp1K6tXr6ZLly5UrVrVVjkWZUzpGVQsSrdJk+CTT+DLL/VjAhvas2cPI0eOJCgoiAYNGjBw4EC++eYbEhMTAfL9tJW9zd/fn2rVqrFlyxa2bNkC6F7fK1eu5OWXXyY0NJRRo0YBXL+lQSk9p/3HH8Odd0ogIDh16hT79u2je/fueSr67P4C7777LqD7DWR3Vr2a7du3c+uttzJ79uziy7QokSQYEM7vs89g3Dh44w09JtuGYmNjGTFiBD/88APt27enR48eHDp0iMcff5yxY8de9dN89rbQ0FCeffZZjh49yh133EHnzp0ZPHgw9913H5GRkbRv355du3aRnJx8/czIcDBxhX379nHhwgVq165N+fLlrdvNZjMACxcuZM6cOQQGBvLkk08C1w46MzIy8PLyYuDAgXTo0IHt27cX7xsQJYcSwpn99JOeNf+555SyWGx6aovFop599lllGIaaMmWKOnfunFJKqXPnzqlevXopNzc39eGHHxboXKtXr1YjRoxQPj4+6uabb1YjRoxQb731lmrfvr0yDEM99thj6tSpU9Z0hSiI9evXK8Mw1GeffaaUUiozM9N6/2RkZKjGjRsrwzDU7Nmzra9fT1RUlPrwww9Vo0aNlGEYavDgwSouLq743oQoESQYEM5rwQKlXF2VGjbM5oGAUkolJCSocuXKqWbNmuXabrFY1JEjR1S5cuVU3bp1VXx8/HXPdeLECdWpUyf12GOPqaysLOv22NhY9dhjjynDMKyBhdlstun7EKXXyZMnVe3atVWrVq3Uv//+a91+4sQJ6301cODAQp/XYrGorVu3qhdffFFVq1ZNmUwm9fbbb9sy66KEkWBAOKfVq5Xy9FTqrruUKsCnnRsRHR2tfH191QMPPKBSU1Ot27Mr88GDByvDMNSvv/6aa3t+XnzxRVW1alV1+vRppVTuT2ibN29WhmGoe+65pzjehijl3n77bWUymdRdd92lPv74Y/X999+rFi1aKMMwVL9+/VR0dLRS6tr35+Uub5lKTU1Vy5YtU02aNFGGYaiOHTuq48ePF8v7EM5N+gwI57NjB9xxhx46OHOmnlynGCQnJ2MymXB3d8+3k+Bdd90FwB9//AHk35Ew+zy///47SilrJy8XFxcsFgtKKdzd3a0duy5cuFAs70WUXi+++CKffvopGzZs4Pnnn+eRRx4hJiaGF198kSlTphAUFATkdCi8HsMwyMrKAuDixYv8/fff7Nu3D4AhQ4bgK3NXlEkytFA4l3//1evB16sHv/+u52wvJv7+/ri5uREdHZ1rHoDsaYPbtWuHt7c3a9euBcAtn6BEKYWPjw8eHh7ExcWxb98+GjZsmGvq4UWLFpGcnEzDhg0pX768bacmFmXC448/zrBhw1i6dCm+vr7UqFGDunXrFvo86r8OsW5ubpw7d46HHnqIJUuW0LRpU5599lmGDBlSDLkXJYEEA8J5HD+u13mvUgUWL4Zy5Yo1OT8/P6pWrcru3bs5f/48VapUAXJ6Y9esWZOgoCAOHDjAqVOnqF69ep7RBWazGTc3N+644w727NnDqFGjePXVVwkMDOTo0aMsWrSIzz77jEaNGtGvXz8ACQTEDXF3d6dPnz7Wn7ODygsXLrBjxw4aNWpkvYevZ+HChXz88cesWLGCZs2aMXv2bIKDgwE7LKwlnJPjnlAIcZm4OKUaNFCqdm2ljh2zW7JPPPGEMgxDLVmyJNf27Oevd955p3JxcVHr1q1TSuUdCZD98+HDh619DLy9vVW1atWUn5+f9TnslecXwlamT5+uXFxcVP/+/a19Vq6UfT9funRJLVq0SFWoUEEZhqGeeeYZtXfvXqWUdGwt66RlQDjexYt64aH4eL0CYa1aRT/n5Sv7hYVBgwaQzzPV/v3789VXX7FgwQI6deqEt7d3rk9G1apVo3LlyrnmfI+NjWXNmjWEhITQvn17AIKDg/niiy/o378/f/31F0lJSTRo0ICePXvStm3bor8fIa6iTp06+Pv7U6FCBXx8fPLdJ7s/wcSJE5k6dSrp6em8+uqrvP7669Z9pMWqjHN0NCLKuNRUpSIilCpfXqnt22/8PBaLUlFRSn39tVKDBilVrZqen8DNTamvvlLqKp96EhMTVbt27VTt2rXV8uXLlVI5n5CysrJUw4YNVc2aNXONNhg3bpwyDEM9+OCDKiMj48bzLISNZGVlWUcBXN56lX0v79u3T/3f//2fMgxD1axZU82ePVulp6fn2V+UXdIyIBwnKwsGDYING2DpUrhiEZbrOno0Z1W/lStvaGW/SpUqMWLECB566CEmTZpE27Zt8fX1JS4ujl9++YX9+/fz7LPP5upg2KBBA7p06UL37t1v9J0LYVOurq7UrFkT0H1esvsTuLi4cOTIEYYMGcLff/9N27ZtefvttwkLC7MeK/0DBIChlCxzJRxAKb0C4fTpetRA797XP+bEidzL+h45krOyX3h4kVb2e/jhh/nhhx+oWbMmnTp1Ij09ncWLFxMeHs53331HjRo1ZBSAKHG++uor3nnnHY4cOcKgQYN4/fXXrUMRhbictAwI+1MKXngBpk7VqxBeLRA4cwZWrcqp/P/9V29v3Bj69NGVf+fONlnQ58svv6RTp078+uuvrFmzhnLlyvHMM88wfPhwatSoAcgzVVHyVKtWDaUUzzzzDK+//vpV+xQIIS0Dwv7efBNefRU+/RT+97+c7QkJsHp1TuW/d6/eXr9+zif/zp0hIKDYsnbp0iUMw5BCU5Qqly5dwtfXt/CtW2Zzvh1vRekjwUAxS7Ykc9Z8lviseNJVOmbMuOKKh+FBFbcqBLgG4ONShiqeKVPgySdhwgR45hlYs0Y/74+MhN27datBSEhO5d+lC/z3yVwIYSdmM6xdC6NGwYcf6r9DO5Dy0nEkGCgGcVlx7E7fzeHMw6SqVACM/76yqf++ALwML0JMITTxaIK/m79D8mwXP/wADz+sOwoahp522GKB2rVzKv/wcP2zEMKxdu+Gxx6DzZvhrrvg3Xd1oG5jUl46BwkGbEQpxeHMw2xL28Zp82kMDOvNWxDZ+1dzrUZLz5aEmEJKfi/flBQ9UiAyEubO1eP+AapVg65dcyr/oCAdHAghnItS8PPP8NJLcPasbs0bPfqGOunmPq2Ul85GggEbSLYkszJlJdGZ0YW+qa+UfXywKZgI7wjbNIlZLPoZ/cGDMG9e0c93NenpsGlTzlC/zZshIwMqVtQTCzVsqBceatRIKn8hSpKUFHj/fXjrLfDxgUmTYPjwG+pP4PTlZRklwUARRWVEsTx5OZlkFummvpKBgQkT3Xy6EeoeeuMnSkmBBx/UQcCXX8Ljj9ssj2RmwtatOc/8N2yAtDTdu79zZ/2pv2ZNPYSwSRP46y/w8rJd+kII+zpxQn+w+PFHuOUW3Z+ga9cCH+705WUZJsFAEWxP287a1LXFnk6YVxjNPQs5IQ/oZr2+feGff3RTX9++RctIVhZs357T23/dOkhOhvLlcyr/8HBd8bu4wOHDetKfmjV1wFDEpkUhhJPYulV3Lly/Xi83/t57cJ1VFJ2+vCzjJBi4Qfa6sbMV+gY/cAB69dItAwsX6ln5CstigV27cir/NWvgwgXdTHjrrTmVf/PmcOXyvidPQqdOYDLpXsnFOBxQCOEASsGvv8KLL+oWg5EjYexYqFQpz65OX14KCQZuRFRGFIuTF9s93V4+vQrWBLZ6Ndx5p/5EvmgR1KlTsASU0mP7s5/5r14N586Bp6f+hB8eDhEROrC4bHrePBIT9eJASUn6k4OMDhCi9EpNhY8+gsmTwcMDJk7UoxD++4Dg9OWlACQYKLRkSzI/Jv1IBhl2T9sddx6q8NC1O8n89JMevhcWBnPm6M57V6OU7lSY/cl/1SqIiwN3d2jXTlf84eHQtq3+Iy+I5GTo1g0OHdItAvXrF+YtCiFKqlOnYMwYPbNogwbwwQckd+/k3OWlsJJgoBCUUixMXsiRzCM27fxSUAYGQaYg+vj0yTuMRikdkY8fD8OG6cl93N3z7hMdnXt+/1OndATfpk1Os3+HDjfW0S89XT8/3LhRn/tGHk0IIUq2HTtg1CjU6tUs3Pc5R6plOV95KfKQYKAQDmUcYlHyIkdng94+vbnZ/eacDRkZ8Oijuofv66/r3r7ZN39sbO6V/Y4d0537WrbMafa/zsp+BWI26xUI58+HP//U5xZClE1KcWjHfBYFxTg6J3nLS5EvWajoOgIDAzl69GihjhkxfwQzR8zk3LFz1933o8SPrP/fPHMzP//v52vuX7dzXarPr55zc587B3ffrZ/Nz5ihpw2dOTMnAIiO1oFB06YwYECRVva7KqX0FMNz58Jvv0kgIEQZZc/yMnpTNAdWHiB6UzTnjp/j4tmLKIuiYs2KhIaFEj4inIDgALanbZdgoAAkGCiBTplPEW+Op0rsRbjtNt1z//bb9WOCwYP1To0b69UAbbiy31W98gp8842ebrhfv+JLRwgh/jPrmVmcjTqbZ3vc4TjiDsexddZWHv35UVSY0uWlaxUH5LLkkGDgOkaPHk1SUhJRGVGcyTpDSlIKyz5YZn29Xpd61Auvl+uYKoG5bzq/QD86DutYqHTzOy9A5ZsqY2CwK3EjXev212P/Qc8jftttOiDo0sV+Q/nefRfefltPPjJkiH3SFEI4JUeUl4GtAwnpEIKbuxv7V+wndnssAJmpmcwcMZNxu8axK20XXX0KPjlSWSTBwHU8+uijAHx9/mtSVSoJsQm5bu7ANoFEjIy45jkq1qx43X2udK3zKhTRbqfo2qqVHt97/DjExOiJhQ4f1pMMtWunRwFUKcZo+Ntv9RjjMWPg2WeLLx0hRIlgz/Ky0W2NGPbDMKo3qG7ddvvLt/Nl/y/5d/W/AJw/cZ5TB07h08iHrkgwcC0SDBRAsiXZupqWvWz4YQOrp6wmMzWTcv7lCGobROcnOhPYOhCAFFJJWb8CbxdvPe//33/rdQE2bYKvv9YdCUGvMvbww3qhERcX260J8Ntvemrjp57SrRFCCIH9yst+E/M+kjQMg1t63WINBgDMGWZSVAoplhRdXop8STBQAGfNeZ9LFcb5E+dZ+enKPNurN6hOg24N8j3m4tmLOcefPM+OeTvY+cdO7pp8F2GPhVnzFegSCOXK5QwLBN2hLyZGLxR04gSMGKG32yoQWLYM7r8f7rsPPv1UFh0SQlg5orzMlf6hnPQ9fD0ICA2w5ivQJbBIeSvNJBgogPis+CKtrpUQk8D8cfPzbG89qHWem9vNw426YXUJCA3As5wnx3YdY+9fewFQFsW8V+cR2imUGg1rEJcVR6ApMG+ChqGXBQ4KuqH8XlP22uZdu8K0abq1QQgh/mPP8vJK0Zui2TBtg/XnLk92wcPHAwPj6uWlACQYKJB0lV7kpTYLon5EfSYdnIRX+dwT/myctpFfRv0C6IBgy6wt3DXxLtJVerHmJ4+9e6FnT2jWTM9ueK0piYUQZZK9yssr7Vu2j2mPTMOcYQagad+m3PbSbYCegMju5WUJI8FAAZgxF+n4kI4hjFww8rr7VaiW/9j/tg+2Zd7oeWSk6Ck9zxw8Y5N8FcqRI9Cjh15nYOFC8JZnb0KIvOxVXl5u47SN/PrCr1iyLAC0vKcl939xPy6XtVzatbwsgSQYKABXXB2dhVwMF/2M3q752rZN901YsuTa6x0IIco0e5ZLSikWvb6I5R8ut26LeDqCO8bdkWcKYmcrx52NPPAtAA/Dwy5NXnNfnkvC0YQ82zdP32xtFQCo1qAaCoWHUcDFg2yhf38dEFStar80hRAljr3Ky6yMLKY/Nt0aCLi4uXDvB/fSd3zfPIGA3cvLEkhaBgqgilsVu9zcW2ZtYe23awnpEEJg60DcPNw4vus4e/7cY93H1d2Vdg+0Q6Hwd/Mv9jxZubiAj6z+JYS4NnuVl98/9D37lu6z/lw3rC5pF9PyjERo0K0B1RtUt295WQJJMFAAAa52ms0P3UHw0LpDHFp3KM9rJk8T939+P/7B/nbPlxBCFIS9yqVT+0/l+vnAygMcWHkgz34+fj5Ub1BdysvrkGCgAHxcfPAyvIp9Io2n5j3Fnj/3ELUmivMnz3Mx7iKGi0HlmyoTGhZK58c74x+iAwFvw/uGJ9A4ceIErq6uVKtWzZbZF0IIu5WXhVGU8rKskCWMC2hF8gr2Zux1yLrcVzIwaOTe6Ibm2o6OjqZu3bqMHj2aV199FQ8PeY4mhLCt0lJeliXSgbCAmng0cYobG3RnmKaeTQt9XFxcHF26dCE4OJiWLVtKICCEKBalobwsayQYKCB/N3+quVbDwLFT7xoYVHetXujlONPS0ujUqROGYfDWW2/Rt2/fYsqhEKKsK+nlZVkkwUAhtPRs6fBoV6Fo4dmi0MeFh4eTlJTE5MmTueOOO6zbL1y4wI4dO9i9ezfHjh2zZVaFEGVYSS4vyyIJBgohxBRCsCnYYdGugUGwKZgQU0ihjuvatSubN2/mf//7H4MHD8ZkMnHq1Clmz55N27ZtadOmDa1ataJp06Z88cUXpKSkFNM7EEKUFSW1vCyrJBgoBMMwiPCOwIRj5uQ3YSLCOyLPhBrXEh8fT0CAHlKza9cu/v33Xy5dusT333/PkCFDMAyD/v37c99995GSksL//vc/Jk2aVFxvQQhRRpTE8rIsk6GFheTj4kM3n24sTl5s97S7+XTDx6VwE/9UqVKFDz74gICAAD799FMyMjJo27Ytr7/+OnfddReffvoplSpVwsXFhfvuu48xY8bw9ttvExISwvDhw4vpnQghyoKSVl6WZTK08AbtSNvBmtQ1dksvzCuM5p7Nb/j4hIQEPvjgA9566y2UUtxxxx388ccfefZbsGAB/fr1o2/fvvz+++9FyLEQQmglrbwsiyQYKAJ73eC2urGTkpL48ssvmTZtGlOmTKFz585YLBZcXFzIvg0uXLhA48aNcXNzY8+ePXh7e0szmxCiyEpaeVnWSDBQRFEZUSxPXk4mmTbtOWtgYMJEN59uhLqH2uy8SUlJ7N69m8aNG1OpUiXrdqUUhmFw+vRpbrnlFm677TZ++uknm6UrhBAlrbwsS6TPQBGFuodSw60GK1NWEp0ZjYFRpJs8+/ggUxAR3hE2f+ZVoUIFOnbsmGud7+zWgfT0dD7//HPOnTtHixYyHEcIYVslrbwsS6RlwEaUUhzOPMy2tG2cNp8u9E2evX911+q08GxBiCnELs3z2YGAxWLhxx9/5OWXXyY0NJRVq1bh6irrfwshbM9m5aURQAvv1nYrL0szCQaKQVxWHLvTdxOdGU2K0mP2DQwMswUsFjCZUP99gV5EI9gUTBOPJjZbZjO72b8gLl68yMSJE/n5558pX748GzdupEKFCjbJhxBCXMtVy8vL5ifIU17GmGkyeCL+lgqwbh34+Tkk76WJBAPFLMWSwlnzWeKy4khfuwLzwX24PvIYHoYH/m7+BLgGFGk1rYSEBPbs2cORI0fw8vKiS5cuVKhQAU9PT+un/ms5f/48AwcOZOnSpdx2221MnTpVVjMUQjhErvJSpWPGjCuuecvLWbNg0CAwmSAwEBYvhptvdnT2SzQJBuzptddg2jQ4etQmpzt+/DgDBgxgx44dZGRkABAcHEyPHj146aWXqFOnToECgp07d/L333/Tr18//P1t0zIhhBDF5osv4OmnwWyGoCC4cAHmz4cOHRydsxJLZiAsoS5evEj37t2Ji4vj5ZdfZtmyZbz11ltUrFiRKVOm0K1bN/7++2/rsMErYz6LxWL9f7NmzXjkkUckEBBClAyJifrRQJUqcNtt0KgRRETAr786OmcllgQDJdRHH33E0aNHee211xg3bhxdu3blxRdfZOPGjQwfPpzDhw/TqVMnli9fjmEYGIZhDQiSk5OZNm0aa9bkjPmVzjdCiBIjMREqV4ZHHoGff4Z58+Duu+Hee+Gdd0AavAtNgoES6uDBg/j6+nLnnXdiGAZmsxmLxYLJZOLrr79m4sSJZGRk0K9fP1asWAHoCt9isTBr1iweeeQRJkyYQEJCgoPfiRBCFFJ2MPD44/oRwdy58NNPMGYMvPQSPPUUZGU5OpcligQDJZRSipSUFBITEwFwdXXFxcUFs9kMwJgxY3jzzTdJTU3lxRdfZN++fQC4uLhw00030aFDB4YOHYqf9MIVQpQ02cFAUBD07g2ff663T5oE330H334LL78MmZmOzWcJIsFACXXzzTeTkpLCjBkzSEtLs253dXW1BgQvvfQSzz33HDt27GD9+vXWfXr06MGcOXN48MEH7Z5vIYQosuxgAHQrwM6dsHmz/vnhh+HcOXjvPZDHnwUmwUAJNWLECBo0aMB3333Htm3bcr3m6upq7SD41FNP4e/vz1dffcXFixet/QZk+KAQosS6PBi47Tbo3h0uXsx53ddX/+smk+wWlAQDJZS/vz+jRo3i5MmTPP744+zZsyfX69nDCYOCgmjatCmJiYlkZmZKR0EhRMmXmKhHEgC4uMDSpdCli0OzVNJJMFBCGYbBww8/zEsvvcS+ffu46667WLt2LVlXdJpJTk4mMTGRmjVryvTCQoiSTykYMQJGjcq93WRyTH5KCQkGSjAXFxfGjx/PG2+8QXR0NP379+eTTz7hn3/+AXQgMH36dPbv30/btm1limEhROnw6qvgfeMzt4q8ZAZCe7LxDISXmzFjBm+88QYHDhygZs2atG/fntjYWPbu3UuzZs1Yu3atzdMUQghROkjLQCkxePBg5s6dy7hx4zAMg6VLl5KWlsbQoUOt8wwIIYQQ+ZGWAXuyRcuAUtcdLnPu3DnMZjM+Pj54eHhcd20CIYQoC8xms3W0lZSLucm4i5JEKdi0Cdq1u2ZAUKlSJTtmSgghnJfFYmH//v38/vvvHDp0iKNHj1KhQgX69u3Lvffei4+Pj6Oz6BQkGCgplILnn4cPP4R9+6B+fUfnSAghnFZqaip//fUX7777Llu3bsVsNluXd09MTOSPP/5g3rx5fPLJJwQGBjo6uw4n7SQlxZtvwgcfwCefSCAghBDXsHXrVu6++27uvvtuNm3aRPfu3fn+++9ZsmQJS5cu5dixY0yYMIFVq1bx+uuvOzq7TkFaBkqCKVNg9GiYMAH+9z9H50YIIZzW0qVLeeKJJzh9+jQPPfQQTz31FG3atMmz36hRo4iPj+f777/n448/LvOPC6RlwNnNmqXn3n7mGRg71tG5EUIIp3Xu3DlefPFFYmJimDx5Mu+//36+gYDZbMbX15c6deqQkZHB5ux1DcowaRlwZn/9BQ8+CA88oB8RyFTCQghxVevXr2f37t28//77PPvss/nuo5SyTst++PBhPD09qVq1qh1z6ZykZcBZrV8P/ftDz556SU4ZBiOEENe0Y8cO3NzcCAsLAyDzsiWMLRYLFosFwzBwcXHht99+48svv6Rdu3aEhIQ4KstOQ2oYZ7R7N/TpA23awC+/yJzbQghRAH5+fnh4eHDq1CkATCaTdQVXFxcXXFxcOHv2LK+88grDhg2jVq1ajB49Gk9PT8r6lDsSDDibQ4egRw8IDob588HLy9E5EkKIEmHw4MFYLBa+/vprLly4AOSs4LplyxaeeeYZGjVqxNtvv02NGjX4+OOPra0IZX1FV+kz4ExOntTrcleoAH/+CeXLOzpHQghRYlSoUIEXXniBd955h4YNG9KqVSv8/f2JjIwkOjoa0K0FI0aM4OmnnyY0NNTBOXYeEgw4i8RE3SKQlQWrV0NAgKNzJIQQJc7zzz9P/fr1+eSTT1i0aBGVKlXC1dWV9u3bM2DAAIYNG5ZrBdfLOxSWZRIMOINLl6B3bzhzBtauhdq1HZ0jIYQokXx9fRk4cCDdunUjMzOTxMRETCYTdevWte5jNputHQklENAkGHC09HQ9amDvXoiMlNkFhRDCBqpUqQJA9erVrdvMZjMuLi64uro6KltOS4IBRzKb9TwCa9boOQVatnR0joQQolS5fIVCCQKuToIBR1EKnnwS5s6F336DLl0cnSMhhCg1Ll68yMKFC8nKyuL++++XQOA6JBhwlFdegW++gR9+gH79HJ0bIYQoVdLS0njsscdIT0+nRYsWNGrUyNFZcmoSDDjCO+/A22/r5YiHDHF0boQQotTx9/fnwQcf5MKFC5iuMnGb2WzG1dVVRhQAhirr0y7Z02uvweef62GEY8fCxImOzpEQQpRaFy5cwNXVNdeKhHFxcZjNZtzc3KydDC93eR+DskRaBuxp/34dCIwYoZcjFkIIUWzK/zdxW/Yn/xMnTvDll1/y448/4u7uTnBwMLfccgtdu3alatWqtGzZskwGAiAtA/azbBncfjt4esLFi7LwkBBC2NnJkycZPHgwq1evZty4cWzZsoX9+/dz7Ngxypcvj4uLCx06dKBWrVr07t2bmjVr0rRpU0dn2y6kZcAeNm+Gu+7S6w1kZEggIIQQDlCjRg169+7N6tWrqVu3LuPGjSMuLo6MjAxWr17NmTNn2LBhA6dOneLee+8lIyODEydO4O/v7+isFzuplYrb3r16GeLmzeGeexydGyGEKJOyVy/s1q0bQUFBfPTRRwBUqlSJmjVrcv/99zNq1CimTZtGnTp1UEqRlZXFV1995cBc248EA8XpyBG93kDt2rBggSxFLIQQDpLdF6Bp06b07NmTrVu3cujQIdzcdAP5ypUr6d27N76+vnz88cd4eHjQs2dPWrVq5chs2408Jigup0/rFQi9vWHJEqhY0dE5EkKIMi09PR0PDw/uvfdepk2bxqRJk4iIiGDixIkcOXIEgJtvvpmBAwcyaNAgGjRo4OAc248EA8Xh/Hm47TZITYX166FqVUfnSAghyjwPDw/r/ytXrsxPP/3E9OnTAejevTsPPvggd955J76+vtb9suciKO0kGLC1lBTo0weOH9drDgQGOjpHQgghgJ9//pm3336b3bt3W7eFhYXx/fffExwcbN2W3b+gLC1qJMGALWVk6E6CO3fCypUg018KIYTTmD9/Prt37+bWW2+lc+fOzJs3j6NHj1oDgexVDcviXAMSDNiK2aynFl6xAhYtgjZtHJ0jIYQQl/nwww958MEH6dWrF6BbAH755ReOHTvGTTfdVGZaAfIjkw7ZglJ6VsGvvoJff4X+/fPf77XXYNo0OHrUvvkTQgiRx7lz56hUqZKjs+EUyl5bSHF47TX48kv4+uurBwJCCCGcSnYgYDabHZwTx5NgoKg+/BBef12vRPjII47OjRBCiEIqy48HskkwcDUPPaQr+GuZNg3+7//g5ZfhhRfsky8hhBDCxiQYyM+lSzBrFnh5XX2f33/XLQGPPQaTJ9sta0IIIYStSTCQn+XLITMTevfO//XISLjvPt0/4IsvwDDsmz8hhBC2o5QeEVaG+9NLMJCfRYugXj29yuCV/v4b+vaFLl3gp59AnjUJIUTJ9/HHMHKko3PhMBIMXEkpWLw4/1aB/fvh9tuhcWOYOxfc3e2fPyGEELZlGGCxwDffQFyco3PjEBIMXGnXLjh5Mm8wEBurVyCsXl23HPj4OCZ/QgghbG/YMHBxge+/d3ROHEKCgSstWgTlykGnTjnbzp7VKxCaTLB0KVSu7Lj8CSGEsD0/Pxg4EKZM0f0HyhgJBq60aJGu+LMfASQl6UcDFy7AsmW6ZUAIIUTp89RTEBMDf/3l6JzYnUxHfLn4eAgIgG+/hYcf1ksQ33477N6tVyC85Zain//Chfw7JgohhHC81q3B31/3HStDpGXgckuW6A6EPXvqoYX33Qdbt+rWgqsFAhZLwYejVKkigYAQQjizp57SLQOHDzs6J3YlwcDlFi2CFi2galXdMvDXXzBvHnTokLOPxQJnzuh/QXc4kXkGhBCidLjvPqhYUS88V4aUiscEyZZkzprPEp8VT7pKx4wZV1zxMDyo4laFANcAfFyu0/s/K0s/IhgxQvcT+Owz+PlnfWMAREfr6Yc3by6Tz5OEEKLMeO45+OEHOH7cOhOtTeoZJ+bm6AzcqLisOHan7+Zw5mFSVSoAxn9f2dR/XwBehhchphCaeDTB380/7wk3bYJz5+D0ad1nYMoUPbzwhx9g6lTdZ6BcOR0gKCWtAUIIUVo9+SR88AFxf/3M7h51bFfPOLES1TKglOJw5mG2pW3jtPk0Bob1IhRE9v7VXKvR0rMlIaYQjOxK/dVX4ZNPIDkZhg/XfQbmzIGUFOjaFYYOhbvuAm/v4nlzQgghHM5az+yfw+naXratZ5xYiQkGki3JrExZSXRmdKEvzpWyjw82BRPhHaGbdurU0RMLVaigHxOEhOgA4KGHoHZt270RIYQQTqnY6xknViKCgaiMKJYnLyeTzCJdnCsZGJgw0c3tVkLL3wJubrryHzYMOnaURwFCCFFGFHs949ONUPdQm53X1pw+GNietp21qWuLPZ2wowE0D+4N5csXe1pCCCGch93qGa8wmns2L/Z0boRTBwP2ukDZivtCmc1mVqxYwerVq4mKiiIpKQmAChUqEBoaSpcuXYiIiMBVVkIUQgi7KG31zI1y2mAgKiOKxcn2nwGql0+vYmnKWbVqFcOHDyc6OvqqnUmUUgQHB/Ptt9/SpUsXm+dBCCFEjtJWzxSFUwYDyZZkfkz6kQwy7J62O+48VOEhm3b2+Pvvv+nUqRMuLi7cf//99OjRg9DQUCpUqABAUlISUVFRLFu2jBkzZmCxWFi7di2tW7e2WR6EEELkKG31TFE5XTCglGJh8kKOZB6xaSeOgjIwCDIF0cenj82Gg/Tu3Zu1a9eydu1amjZtes19d+/eza233krHjh1ZXMbmxhZCCHsojfVMUTnddMSHMw8TnRntkAsEegKJ6MxoDmfabl7qjRs3MmjQoOsGAgBNmjRh4MCBbNq0yWbpCyGEyFEa65micrpgYFvatlyzOzmCgcH2tO02O19GRgblCzFKoUKFCmRk2L/pSgghyoLSWM8UlVM8JggMDOTo0aOFOmbE/BHMHDGTc8fOXXffjxI/yrPNYraw9ZetbP9tOyf+OUFqUipeFbyoWKMiwe2D6fZsN54MfZIqrlUKla/8tG3blvj4eHbu3Em5cuWuuW9ycjJNmzbFz8+PzZs3FzltIYQQ9q1nUpJS2PDDBo7tOEbsjthcx7ce1JrBnw+2/jy4/GCb1DNF5XQtA/ZwKf4SH/f8mJ//9zMHIw9yKf4S5kwzl+IvcXz3cdZ8tYb4I/HsSttlk/RGjRpFTEwM7du355dffuH8+fN59jl//jyzZ8+mXbt2REdH8+yzz9okbSGEEPaVGJvIwgkL2TV/1zUDCQPDZvVMUTnFQkWjR48mKSmJTambyFSZpCalsuyDZdbX63WpR73wermOqRKYO5LyC/Sj47CO103LnGXmuwe+4+jfOkI0eZq4pfct+If4YxgGF85e4Piu47iaXInOjKYrXYv8/gYOHEhMTAzjxo1j0KBBOv9VqlgfHVy4cIH4+HidH5OJyZMnW/cTQghRdPasZ0DXLdUbVqd289ps/207KedT8uyT3XfAFvVMUTlFMPDoo4+SbEnGlGQCICE2IddFCmwTSMTIiGueo2LNitfdB+Dv2X9zZMsRACpUr8DTi5/Gr45fvvumqBRSLCl4uxR9caKXX36Ze+65h2nTprFq1SqioqI4ceKEzkeFCnTs2JHOnTszbNgwQkJCipyeEEKIHPasZ6rXr85bsW/h6qYnkNu7dG++wQDYtp4pCqcIBgDOms/aJZ0tM7dY/9+gawP+evsvDq0/xMWzF6lYoyK39L6F7v/XHe+K3tZ8BboE2iTtm2++mUmTJtnkXEIIIQrHXvWMq6lws8jasp65UU4TDMRnxRdplajzJ86z8tOVebZXb1CdBt0aALrTYOz2WOtrm37KPXwv/kg8kZ9F8s/if3jmz2co71+euKw4Ak2BN5QnIYQQzsMe9UxhGRhOUc84TTCQrtKLdJESYhKYP25+nu2tB7W2XqSU8ylkpmXmej0gNIBm/Zpx5uAZdi3QHTnio+OZ9+o8hn4zlHSVfkP5udyECRNQSjFy5Ej8/PJ/JCGEEKJ42aOeKSwDwyb1TFE5TTBgxlz8aWTkTsPkaWLkwpGU89fD/b5/6Ht2L9wNwO6Fu8lIzcDsUfR8TZw4EaUUgwYNkmBACCEcxB71zI1whnw5TTDgStFW6gvpGMLIBSOvuY9XBa9cP1etV9UaCGSfIzsYyErPIulUEq4Vi76C4Pjx41FKUaWK48eSCiFEWWWPeuZGFDVftuA0wYCH4VHsU0O6e7vjV8ePhKMJ+b5+5RzRbh5ueBgeRU537NixRT6HEEKIorFHPVNYCmWTeqaonGbSoSpuVexykRre1tD6/zP/nuFS/CXrz4fX58wTXb5qecrXKI+/m3+x50kIIUTxs1c9UxgK5RT1jNO0DAS4BtglnS5PdmHzjM1kJGeQmZrJZ3d8RtO+TTnzb04HQoBbH70VwzDsli8hhBDFy17lecr5FJa9nzOHQer5VOv/j+04xh9j/wDAL8iPTg93cop6xmmCAR8XH7wML1JV6vV3LgK/On4M/mIwPz76I+YMM6cPnub0u6dz7dOkTxMino7A2/C26UQQMTExTJ06lZUrV3Lw4EGSkpJwcXEhICCAli1bct999zFgwABcXJymwUYIIUoNe9UzqRdSifw8Mt/XTh84zekDus4J6RhCj0d6OHzCIXCiYAAgxBTC3oy9xZ5O0zua8nzk86z8dCVRa6K4GHcRk5eJmo1r0nZwW1oPbI2L4UKwKdhmaX722We88MILpKen5+mbcPz4cY4fP87vv//O+++/z2+//cZNN91ks7SFEEJo9qpnCsLAsGk9UxROsWphtrisOGZenOnobFjZajWpRYsW0bdvXwICAhg5ciQNGzbk/PnzLFiwgAULFvDJJ59w6623MmfOHN59912qVavGzp078fX1tcG7EEIIka201jNF5VTBAMAvF37hjPmMQzt5GBhUc63GveXvtcn5unTpwt69e9m1axc1atTI9dro0aP54IMPiIqKolatWqxZs4aIiAhGjx7NhAkTbJK+EEKIHKWxnikqp3s43dKzpcN7eyoULTxb2Ox8O3bs4K677soTCACMGDGCjIwMFi5cCEBYWBjdunVj7ty5NktfCCFEjtJYzxSV0wUDIaYQgk3BGBjX37kYZD/DCTHZbuXArKwsPDzyH0fq6ekJQFJSknVb8+bNiY6Otln6QgghcpTGeqaonC4YMAyDCO8ITJgckr4JExHeEXk6+RVFo0aNWLRoERcvXszz2s8//4xSKteyxenp6bi7u9ssfSGEEDlKYz1TVE4XDIAe/tHNp5tD0u7m0w0fFx+bnvOJJ57g6NGjhIWF8euvv7Jv3z42bNjAK6+8wnPPPYe/vz89e/a07n/o0CGCg52jh6kQQpRGpa2eKSqnGlp4uVD3UMIsYaxJXWO3NMO8wgh1D7X5eR9++GH+/vtvvvrqK+677z7rdsMwqFChArNnz8bHR98YFouF2NhY+vfvb/N8CCGEyFGa6pmicrrRBFfakbbDLhcqbMwfNO/7Etx2W7GlERkZyezZs4mJicHLy4tWrVrxyCOPULVq1WJLUwghxBWUgi1bYNIk2LCBHbFLWJO5odiTDfMKo7ln82JP50Y4fTAAEJURxfLk5WSSadMeoAYGJkx08+xC6IAXIDISli+H9u1tloYQQggncfIk/PQT/PAD7N+vt7m7Q0oKUebo4q1nfLo5ZYtAthIRDAAkW5JZmbKS6MxoDIwiXazs44NNwUR4R+hnNykpulVg715YvRpuucWGuRdCCOEQaWkwf74OAJYs0ZV/RIQu5wH69oWZehKiYq9nnFiJCQYAlFIczjzMtrRtnDafLvTFyt6/umt1Wni2IMQUkrs35/nzEB4Op0/D+vUgnfiEEKLkUQr+/lsHAD//DOfOQYcOMHQotG4NPXuCn5/+8DdzJgwadNmhxVzPOKkSFQxcLi4rjt3pu4nOjCZFpQD6Ilw+blT99wXgbXgTbAqmiUeTay8XeeYMdOoEFgusWwfVqxfr+xBCCGEjp07lPAbYtw9q1oSHHoIhQ6BePf2YoFMncHODxx+HF1+EuDioXDnf0xVbPeOESmwwcLkUSwpnzWeJy4ojXaVjxowrrngYHvi7+RPgGlC4VaFiYvQNU6kSrFmj/xVCCOGcNmyAN96Av/4Ckwnuuku3AnTrBq6uep/EROjcWbcSrF8PzzwDCQmwdm2BkrB5PeNkSkUwUCz27YNbb9XR5LJl4OPcz3uEEKLMevxx2L1bBwD33QcVK+Z+PTkZuneHf//VlX9wsH5MMGYMvPyyI3LsdCQYuJYtW3RHk06ddAcUmRVQCCFKlvR03UlwwwZYuVL3GVi2DHr0gF27oEkTR+fQKTjlDIROo00b+OMPPeTwwQfBbC7a+b75BmQyISGEsA+zWZfdq1bpsrx1a7190SKoVUtGjV1GgoHr6doVZs2COXNgxAjdS/VGHTsG27bZLm9CCCHypxQ89RT89hv88otu5c22aBH07g0loJe/vUgwUBB33aU/1X/1FYwe7ejcCCGEuJ5XX4Wvv4Zvv4U778zZ/u+/cOiQDgaEldOuTeB0Hn5Y90J9/nnd8eS55xydIyGEEPl57z146y14/30YNiz3a4sXg4dH7pYCIcFAoTz3nB6K8vzzerjhww87OkdCCCEu99138MILuhX3//4v7+uLFkGXLjJC7AoSDBTWG2/o8aqPPqqHr0iHQCGEcA5z58Jjj8ETT+hFiK508aKehvj99+2fNycnfQYKyzDg889hwAA9heWKFY7OkRBCiOXLdZk8YAB89ln+nQNXrIDMTOjVy/75c3ISDNwIV1f48Ue9jkG/fno+AiGEEI6xebPuJBgRocvm7FkHr7R+vZ5ILiTErtkrCSQYuFHu7nrISpMmetGLffscnSMhhCh79u7Vn/SbNtVl8rUmhxsxQj9KEHlIMFAUPj66M0rNmno2q5gYR+dICCHKjpgYXfbWqgULF4L3ddYGCAyEhg3tkbMSR4KBoqpUSa+R7eGh574+c8bRORJCiNLvzBld5np56TJYFpQrEgkGbKF6dT3XdXIy3H47JCU5OkdCCFF6nT8Pt92my9xly6BaNUfnqMSTYMBWgoN1dBoTA3fcASkpjs6REEKUPikpuoyNjYWlSyEoyNE5KhUkGLClW27Rs1tt2wb33quHsAghhLCNzEw9dHDHDl3WNm7s6ByVGhIM2Fr79jBvno5Yhw4Fi8XRORJCiJLPYoEhQ/RjgXnzoF07R+eoVJFgoDj06AEzZsDPP8PTTxdtpUMhhCjrlIKRI/XqgzNn6o6DwqZkOuLiMmCA7uTy2GN6YaMJExydIyGEKJnGjYMvvtCrEN5zj6NzUypJMFCcHn1UL2z0yitQubKjcyOEECXPRx/pdQbefluXqaJYSDBQ3F56SS9s9Oyz0Levo3MjhBAlx48/wqhR8OKL+lsUG0MpeaBd7JTSEe333+tHBnFxjs6REEI4tz/+gLvvhmHD9OOB/BYeEjYjwYC9mM16GMyBAxAZqdfTFkIIkdeqVXoCtzvugFmzrr7wkLAZGU1gL66ucNdd4OmpHxds2+boHAkhhPPZtk2XkWFh8NNPEgjYiQQD9uTmBlWqQIMGOuo9cMDRORJCCOdx4IAuGxs21KsLeng4OkdlhgQD9ubiomfOCgjQ8xHExjo6R0II4XixsXr+gKpVdRnp6+voHJUpEgw4gp+fnqHQ1VUHBNKhUAhRlsXF6bLQzU2XjTIU2+4kGHCUmjX1TX/unG4Wu3DB0TkSQgj7u3BBl4Hnz+uphmvUcHSOyiQJBhwpNFSvdHj4MPTrB2lpjs6REELYT2qq7ix4+LD+cHTzzY7OUZklwYCjNWsGCxfC5s1w332QleXoHAkhRPHLzNRl3pYtsGgRNGni6ByVaRIMOINOnWDOHN1p5pFHZKVDIUTpZrHosu7PP/WogY4dHZ2jMk+CAWfRq5eeenP6dHjuOVnpUAhROikF//d/eg6B6dN1fwHhcLI2gTMZNEh3KBwxQo84GDPG0TkSQgjbev11+Phj+PJLGDjQ0bkR/5FgwNk89ZRe2GjsWD285qmnHJ0jIYSwjc8+g9de0wHBE084OjfiMhIMOKPRo/XSx//7H1SsCPff7+gcCSFE0cycCSNH6kcEr77q6NyIK0gw4IwMA95/Xz8yGDJEBwS9ejk6V0IIcWMWLdJl2dCh8N57sgKhE5IOhM7KxQW+/RZ699bLeK5b5+gcCSFE4a1dC/fcA336wDffSCDgpCQYcGZubnr5znbt9B/Szp2OzpEQQhTcjh267OrQAX7+WZdpwilJMODsPD3hjz/0zFy33QZRUY7OkRBCXF9UlB42WLcu/P67LsuE05JgoCQoX15PzlGpkl7V6+xZR+dICCGu7uxZXVZVrqzLrnLlHJ0jcR0SDNjaqlU6Gs7MLNxxn38Ozz579df9/fUiHh07QoUKMimREMI5KaU/wHTsqMusKlUcnSNRABIM2Jqfn1586KefCn5MYiK88gq4u197v5tu0ud1c5NOOEII52QYYDLpsqpWLUfnRhSQBAO2dsstuvf/668XvHXgww/BbIbnn7/+voYBrq6FylJqairJycmFOkYIIW6Yq6t8YClhJBgoDq+9BtHRBWsdSEzUU3OOGAEBATbNxoEDB3jttde49dZbad68OQ888AA/FabFQgghgFOnTnHu3DlHZ0MUIwkGikOTJgVvHShMq0ABWSwWPvnkE/r27cvrr7/O0aNH8ff3Z/ny5TzyyCO89957NktLCFG6/fPPP3Tp0oW///4b0OWLKH0kGCguBWkdKIZWgczMTJ555hmeffZZsrKy+Oijj1i1ahXr16/nr7/+4oEHHmDMmDEsW7bMJukJIUqvI0eO0KNHD6Kiopg8eTIXL17ExUWqjdJIrmpxKUjrgI1bBdLT03nsscf4/PPPadu2LXPnzuXJJ5+kUaNGADRr1ozHHnsMFxcXIiMjAVAyKkEIkY/4+Hg6duxIxYoVqVu3LuvXr2flypUAmM1mB+dO2JoEA8XpWq0DNm4VyMrKYvz48UybNo3w8HDmzJlDs2bNMJlMQE7TXsuWLfHw8CA2NhYAQzr5CCGukJaWRseOHXFzc+Pdd99lwoQJANY+R66F7MQsnJ8EA8WpSRPo3z//1gEbtwps3ryZb775hnbt2jFlyhRq1qyZ6/XsFoAVK1aQlJRExYoVbZKuEKL0CQsL4/z587z11lv06dOH8PBwgoOD+e233/jll18cnT1RDCQYKG75tQ7YuFXAYrHw+uuvc+7cOZ5++mmCg4NzvW42m62R/Ndff423tzcPPvhgkdMVQpQ+4eHhHDx4kMmTJ3P33XcDEBAQwJtvvombmxsrVqxwcA5FcZBgoLg1bZrTOpD9nM3GrQLJycns37+fVq1acccdd+Rqwrs8EBgxYgTz5s3j9ttvJyQkxCZpCyFKj++++44DBw4wadIkBg0ahIeHh/URY/Pmzalbty7ffvstixYtcnBOha1JMGAP2a0D//yjgwAbjyDIysoiNTWV2rVr4+Pjg1IKpVSuQGDkyJF8+eWXBAYGMmHCBKrIFKFCiCs8/PDD/PLLLwwdOhRvb2+UUtbRA4GBgYwcORKA2bNnk5mZKcMMSxFDSXdy+7j7boiM1MFAVhYcOWKzYCA5OZl+/fpx/Phxfv75Z5o3b2597cKFCwwbNox58+ZRvXp1li1bRsOGDVFKSedBIYTV5R8erpRdXiQmJtKvXz927tzJmjVrcpU1omSTlgF7ee01OHcOLlyw+WyDPj4+jBw5kqioKCZOnMjixYvZvHkzU6ZMoWXLlsybN4/mzZuzceNGGjZsiNlslkBACJHLtUYIZJcXlStX5rbbbiM5OZk333yTCxcu2Ct7ophJy4A9NW4M+/bB6dM2n3oYdOfAV199lcTEROu2wMBA+vbty/jx46lYseI1o/9sJ0+eJDU1VfoVCCGsslsHsrKyuPXWWzl27BjLly+nfv36WCwWmYyohJNgwJ5iY2HXLrjjjmJLYuvWrezdu5ejR48SFBREhw4dCAoKwtXVtUCBQEpKCmPHjmXTpk0MGDCAZ6+1rLIQokyxWCwopXjjjTcYP348gwYNYvr06RIIlAISDBSzZEsyZ81nic+KJ12lY8aMK654GB5UcatCgGsAPi4+xZ6PwkTu27Zt4/HHHycmJobhw4fz1ltvFXPuhBAlSVxcHJ07dyY6Opr169fTsmVLm5zXWcrLssjN0RkojeKy4tidvpvDmYdJVakAGP99ZVP/fQF4GV6EmEJo4tEEfzd/m+Th8so/OTkZH5+C/QFZLBZatmzJrFmzeO+993j33XcpX748r776qk3yJYRwPoXpUGw2m/H396d///7MmTOHBg0aFCltZygvhbQM2IxSisOZh9mWto3T5tMYGNabtyCy96/mWo2Wni0JMYXYpJPf9u3bmTFjBj179qRbt25XzXt+aR05coRx48axZMkSfvrpJ7p3717k/AghHCchIYE9e/Zw5MgRvLy86NKlCxUqVMDT07PQz/2joqLw8/OjcuXKhc6Hs5aXZZm0DNhAsiWZlSkric6MtkazhbmxL9//jPkMi5IXEWwKJsI7oshNYmvWrOHDDz9k//79NG/eHD8/vzz7ZP8Rbd26lSpVqhAUFARAUFAQQ4YMYc6cOaxfv16CASFKsOPHjzNgwAB27NhBRkYGAMHBwfTo0YOXXnqJOnXqFCogCA0NvaF8OHN5WZZJy0ARRWVEsTx5OZlkFvqGvhYDAxMmuvl0I9T9xv7oso0cOZK2bdvywAMPXHWfEydOcP/99xMQEMC4ceNo3LgxoJsEq1WrRrNmzViyZIl0FBKiBLp48SJt2rQhMzOTBx54gFtvvZVt27Yxe/Zstm/fTkhICD///DOtWrWyrmNy+Sfty4OEosxRUhLKy7JKSvYi2J62ncXJi8kgw6Y3NujIN4MMFicvZkfajiKd65NPPskVCFgsljxLkNasWZOBAwfy22+/MW7cOFatWgXAW2+9RUJCAjfffLM0wwlRQn300UccPXqU1157jXHjxtG1a1defPFFNm7cyPDhwzl8+DCdOnVi+fLlGIaBYRjWoCA5OZlp06axZs0a4MZXOi0p5WVZJcHADdqetp21qWvtktaa1DVFusEv/+M9d+4c9957L8ePHwdyhgoBPPnkk4wZM4Z58+bRo0cPatasydixY/H09OTuu++WYECIEurgwYP4+vpy5513YhgGZrMZi8WCyWTi66+/ZuLEiWRkZNCvXz/rQkSGYWCxWJg1axaPPPIIEyZMICEh4YbSL0nlZVklwcANiMqIstuNnW1N6hqiMqKKfJ7169czd+5cvv/+e4BcTX8Wi4UBAwbQpEkTxo4dS/v27Xn00UdZunTpVTsfCiGcn1KKlJQU64Rkrq6uuLi4WFsIx4wZw5tvvklqaiovvvgi+/btA3T5cNNNN9GhQweGDh2ab5+j6ynJ5WVZIsFAISVbklmevNwhaS9PXk6yJblI52jbti1du3Zl1qxZLF26FNCfADIzM3FxcaF27drs3buXZs2aMWfOHKZMmUKnTp2six8JIUqem2++mZSUFGbMmEFaWpp1e/ZkZAAvvfQSzz33HDt27GD9+vXWfXr06MGcOXNuaNnzkl5eliUSDBSCUoqVKSvJJNMh6WeSycqUlUWqlP39/XnjjTc4deoU77zzDqtXrwbA3d2dzMxMpk+fjtlsts45nv1oIPs5ohCi5BkxYgQNGjTgu+++Y9u2bblec3V1ta4++NRTT+Hv789XX33FxYsXrWVNtWrVCp1maSgvyxIJBgrhcOZhojOjbd75paAUiujMaA5nHi7Sedq0acP06dNZs2YNI0aM4KOPPmLLli1MmDCBDz/8kAoVKtCmTRsb5VoI4Wj+/v6MGjWKkydP8vjjj7Nnz55cr2c/LgwKCqJp06YkJiaSmZlZpA8ApaW8LCtkaOF1BAYGcvTo0UIdM2L+CGaOmMm5Y+euu+9HiR8BkBCbwKRmkwp0/ntevodf3/y1UHnKzx9//MHYsWNzFQw1a9Zk0qRJDB06VJY5FqIUsVgsTJgwgUmTJhESEsL3339P+/btcXPLmW4mOTmZzp074+XlxcKFC6lQoUKe89irTARISUphww8bOLbjGLE7YnMd33pQawZ/Pviq50k6ncSKj1bw7/J/OX/yPJ6enjRq1IiHHnqIRx555LrrtJQ1MulQCXRJXSLeHE8V1ypFOk+/fv1o0KAB+/btY+PGjbi5uTF06FBuuukm4MaHEAkhnI+Liwvjx4/H09OTMWPG0L9/f1555RW6d+/OLbfcQnJyMtOnT2f//v08+eST+QYC9pYYm8jCCQsLfVzsjlim3DOFlHMp1m1paWmsX7/e2on6999/x9PT05bZLdEkGLiO0aNHk5SURFRGFGeyzpCSlMKyD5ZZX6/XpR71wuvlOqZKYO5K2i/Qj47DOl4zHZ+KPvSd0Dff1w5vOMzeJXutPzfo2oBdabvo6tO1sG8nj7p161K3bl3uvPPOIp9LCOHcDMPglVdeoXbt2rzxxhs8//zz1KxZk/bt2xMbG8vevXtp0aIF77333lXPkV0mZjt37hyTJ0+2/ty9e3eCugRxJuuM9RHBjZSJ2UyeJqo3rE7t5rXZ/tt2Us6nXHP/9OR0pg6dag0EKtasyB0P3oFXohffffcdZrOZJUuWMHbsWN59990C5aEskGDgOh599FEAvj7/NakqlYTYhFzBQGCbQCJGRlzzHBVrVrzuPp7lPa+6z455OWNmg9sFU6dVHaIzo+lK0YMBIUTZM3jwYFq2bMkvv/zCd999x9KlSwkMDGTo0KG8//771zw2u0zMFhMTkysY6NChAzWeqmFddCg/BSkTAarXr85bsW/h6qab9Pcu3XvdYGDrL1utjxMMw+DJuU8SVDeIRys+SpUqVax5/eyzz3j11VepVKnSdfNRFkgHwgJItiRf88YuTlHroji285j15/D/hQOQolJIsVz7j8KmzGaQ7iVClCxK6b/dfNSvX59x48axa9cuDh06xMaNG/n4449xd3cvUpIZKsNm5aWrydUaCBTUnj9z+kBVa1CNqqFVreXl3XffbX0tLS2NZcuW5XeKMklaBgrgrPlskY4/f+I8Kz9dmWd79QbVadDt2st/Rn4Waf1/QGgAjXs2zpWvQJfAIuWtQCwWiI+Hb76B0aNB+hII4fyUgjfegMcegypV4Crritj6k3FBxvYXpUy8nlP7Tln/7xeYM0nSWfNZgoODc+27e/du7r333iKlV1pIMFAA8VnxhV5i83IJMQnMHzc/z/bWg1pf88Y/8+8Z9i/bb/25y5Ndcsb9YxCXFUegKfCG8lQoLi4QGQljx0JmJkyYUPxpCiGKZtw4mDQJbr4ZBg60W7IplpTrlpc3WiYWRHJiTjDiWU53EMwuL28qd1OufePj44uUVmkiwUABpKv0IgUDN2rVF6usE2b4+vvSemBr62sGBukq3X6ZGTgQjh6Fl1+GypXhmWfsl7YQonA++kgHAu+8Y9dAAMCM2SHlZb7+y0J2eXnlSHoZMZVDgoECMJP/M7eCCukYwsgFIwt1zMW4i/w9+2/rz50e6YTJ02TTfBXaSy9BQgI8+yxUqgQPPWTf9IUQ1/fjjzBqlP57feEFuydvwXLdfW6kTCwo70reXDitZ1BNu5Qz9bKZnJlVs1WuXLlY8lASSTBQAK7Yf3KKdd+uIzNNT+Np8jLR6ZFOefZxRL54+21ITISHH4aKFaFv/sMhhRAOMH++/tt89FF4803bnjsuDvz8rtr3IJuLg/ul12hYwxoMJBzJWWXRFVcOH849G2GTJk3smjdnJqMJCsDD8LBrk1dGagbrvl9n/bnNoDb4+vnm2keh8DA87JYnK8OAr76CO++Ee++FVavsnwchRF6rVum/yf794csvbdfRVymYMgUCAnSLYPfuMGYMLFyoA4QruOLq0EcEjW5vZP3/6QOnOfPvGWt5OXv2bOtrnp6edO/e3RFZdErSMlAAVdyq2PXm3jprK8kJuhOM4WLQ5akuefZRKPwPJ0L9LHCz82V0dYUZM6BPH90yEBkJLVvaNw9CiBzbtum/xbAwmD5d/43aimHA/fdD3bqwaRNs3qxHFr3xhn69du1cu3u7eNusvEw5n8Ky93OG/6WezxmyeGzHMf4Y+wcAfkF+dHpYt562GdiGFR+v4PyJ8yil+PLuL2k7uC0bEzYye2pOMPDkk0/KY4LLSDBQAAGuAXZLSynFqi9XWX++pdct+Af757tvQPg9kOGiC4DwcP3dtOl1m/FswsMD5s2Dbt3g9tth7VqoX7/40xVC5HbggP4bbNQI5s7Vf5u2Vr48RETob9CtBYcPw6+/6nIgNta6q0+S7VYpTL2QSuTnkfm+dvrAaU4fOA3oPgjZwYCHrwfDfhjGlHumkJqUyvkT51nyzpJcx3br1o03soMZAUgwUCA+Lj54GV52mXho7197iTuU0/QWPiI83/28DS+85y+FlSv1J/PRoyEtTTfjde6sA4OICF1AFFePWV9fWLRIByM9esC6dXk+JQghilFsrG62r1ZN/y36+l7/mBtlscDevTllzurVcP48XDFJkXvlALuVl1dTp2UdXlr/Eis+XsH+5fs5f/I83h7e1oWKhg8fnmuBJiGrFhbYiuQV7M3Y6xTDZQwMGrk3yr02QXq6br6LjNR/rJs2QUYG+PtDly45LQf16tk+ODhxAjp10p9I1q7VaQohildcHNx6q/47X7cOatSw7fmV0q0OkZH6e9UqPfmYuzu0b6/Lk2bNYPJk2LMHfv7Z2qHY6ctLkYcEAwUUlxXHzIszHZ0Nq8HlB1971cLUVNiwIecPecsWyMqC6tVzAoPwcAgOtk1wcOiQDghq1tTplS9f9HMKIfJ34YL++z15UgcCISFFP2d20392mREZCadP6z5JbdrklBkdOoCXlw4UevWClBTdmbBVK+upSlx5KSQYKIxfLvzCGfMZh0a7BgbVXKtxb/lCTqF56RKsX5/TxLdtm272u+mm3MFBnTo3nrldu/QjimbN4M8/dYEhhLCt1FTo2VP/va1eDUUZHnf0aE5rYmQkHD+u+xy1bKkfM4aHQ8eOeR8/rF6tRxTVrKkfT+RTbpTo8rIMkmCgEA5lHGJR8iJHZ4PePr252f3mop0kKUk36WcXBLt26U8GwcG5g4PCNj2uX6+fYXbvDr/9Zv+RDkKUZllZcPfdsGyZ/u5YsGWArU6cyP3J/8gR3TLYrFnO3/ytt0KFClc/x/Tp8MgjOvCfM+eq+5aq8rIMkGCgEJRSLExeyJHMIw6Jdg0MgkxB9PHpY/tpNBMTdbSfXUjs+W/lr3r1cgqJLl30WOPr+fNP/ezw/vth6lT7jG4QorSzWGDYMP1sfv58PYLges6c0c/6s/+u//1Xb2/cOOfvunNnPcX49SgFEyfC+PF6YqMpU8Bkusbupbi8LIUkGCikZEsyPyb9SAYZdk/bHXceqvAQPi4+xZ/Y2bO5C5GDB/X2Ro1yRipcqxD5+WcYPBiefho+/FBWOhSiKJTSUwx/8on+27rvvvz3S0jQQX12s/++fXp7dlCf/XdbkKD+chkZelbDH3+E11+HV18t0N90mSkvSwEJBm5AVEYUi5MX2z3dXj69CHUPtXu6gO6olB0crFwJ0dG6MGjaNOcTRlhY7ibDL7+Ep57SnybGjnVMvoUoDSZNgtde039TTzyRs/38eVizJido371bBw4hIblb9Ioy0uDcOf1oYv16+OEHGDSoUIeXyfKyBJJg4AbtSNvBmtQ1dksvzCuM5p7N7ZbedcXG5n72GBub0/EouxDq1Ak+/lhPXfr55zowEEIUzmefwciResa/kSP16IHsv7vt2/Xjg9q1c/f1sdV8H0eO6BEDZ8/C77/r/gQ3oMyXlyWABANFYK8b3OlvbKV0S8HlwcGpU7rzYOvWYDbroY1Tp8LQoY7OrRAlx9Sp+vl8mza6Je7vv/XfU/YQ4ewe/0FBxfMork0b3Z9o8WI9HXERSHnp3CQYKKKojCiWJy8nk0ybdpIxMDBhoptPt5LX1KWU7qh0eXCQvaBJ48a6yTE8HNq1K56pU4UoqdLS9IRhkZF6NM7evXp7lSo5FX94uK6Y7dEP559/oFYtPbOpDUh56bwkGLCBZEsyK1NWEp0ZjYFRpJs8+/hgUzAR3hGlo/OLUnro4kMP6cLNxwcuXgRPTz00KruAa936mr2ThSh1MjJg69acoHnDBh0Q+PrqyXwaN4Zp03TfnFLSCVfKS+ckwYCNKKU4nHmYbWnbOG0+XeibPHv/6q7VaeHZghBTSOkbDpOWpp8//v03fP217pQYGak7QF24oIOETp1ymj+bN5d5CkTpkpWln/Nn9/Zft05X+uXL6w64ERG6s99jj+kZ/RYt0kFzKSPlpfORYKAYxGXFsTt9N9GZ0aSoFEDfvAY5N6v67wvA2/Am2BRME48m+LuV8nn9L17UBV5srC4IQ0N1AbljR85IhXXrIDk5p4C084qM8fHxrF27lr1799K0aVPCw8PxLc4FYETpZTbrVrHsT/5r1ui/AR8f3Rkv+97ODnyjonRAXKcOrFgB5co5+h0UOykvnYMEA8UsxZLCWfNZ4rLiSFfpmDHjiisehgf+bv4EuAbg7eLt6GzaV3y8LghTU/VwpZo1c7+emZm76XT9+pwVGS9fdKkYVmRctmwZTz/9NAcPHqR8+fKkpaVRsWJFJk6cyGOPPWbTtIR97d69mwsXLtCpUyeysrKKZ9W67JX9su/d1av10LyCPBI7flwHAt7eOmioUvbm0pfy0nEkGBCOceyYLhzLldMFn5/f1fdNT8/pVBUZmXdFxuyOVUXsVHXgwAFatWqF2Wzms88+IyQkhDNnzvD2229z+PBhZs2aRc+ePW/4/MK+zGYzBw4cYMGCBUydOpWoqCiqVq3KqVOnsFgsuNiilUkpPSFXdrP/5Sv7tWuX88irbdtrd5aNj9etYMnJOvitVavoeROiECQYEI5z8KBuIQgKguXLC94kmpICGzfmPFbYurXIKzKmpaXx+OOPM2vWLN566y1GjRplfS02Npabb76ZLl26sHTp0gKdTyklzzAd7MCBAwwaNIhdu3YREBBAVlYW586d4+LFi3h73+Cny4Ku7Ne+vf6EXxAXL0LXrhATox+RFXEInxA3QiaNF45Trx789Rfs3w933aVbAArC21sXnq+/rntfnzun10N48EH9zPXxx+Hmm/Vz16FD9Set68S8Bw8e5I8//uD222/nvv+mes3MzASgYsWKdOnShYMHD5KQkFCgLBqGwcaNG9m1a1fB3pMosIJ+fsnKysLPz4833niDY8eO0b9/f5RSrF27FtAtBwVMUFfSQ4boeyo0VM8CeOiQHiHz55/6Hly/Xt+TXbsWPBBIT9f3/sGDsGSJBALCYSQYEI7VogUsWKAL0vvv15/wC8vXVy/a8vbbenKjxES9kMs99+jOW9HR1z3vggULuHDhAnfffTc1/pu61WQyYTabKV++PJUqVeLChQtERUUBV6+QlFL89ddftGjRgjvuuIM2bdrg7e3NPffcw/r16wv/3oTVuXPnSExMLHCLS2hoKLNmzeKVV17BZDLRtm1bAP7880+g4EEFWVn6Htq9W99TCxboe2zLFn3P3X573iV+C3re++/X9/7ChboToRAOIo8JhHNYsEB/QhoyBL791rYdAy2Wa45CUErRvn17du7cycGDB6lz2drs2c39LVq0YP/+/ezdu5fg4OA8jwHMZjOurq5MmzaNZ599FqUU99xzDzfffDNHjx5l9uzZ1KlTh19++YXQUJkUpaD27NnDV199xcKFC0lNTaVJkyYMGDCAu+++m8qVKxfocUz2Pvv376dx48bUr1+fvXv3Fq7fwHXuoUJTCoYP13MI/P479Olju3MLcSOUEM5i+nSlQKnnn1fKYrFbsufOnVMBAQGqVatWKjMzM8/rSUlJqnLlyqpq1arXPVerVq2UYRhq7ty51m1ms1n9+OOPyjAMNXz4cKWUUhY7vr+S6ujRoyosLEz5+vqqQYMGqQcffFAFBgYqwzDUU089dUO/w1tuuUUZhqGSkpKKIccFZLHoexyU+uknx+VDiMtIMCCcy8cf60LyzTftluSePXuUr6+vGjZsmMrKyrJuN5vNSimlVq5cqQzDULfffrtSSuXa53JHjx5VhmGoli1bWiuqyyusNm3aqMqVK6uYmJjieiulhsViUc8++6wyDENNmTJFnTt3TimlVGJiourVq5dyc3NTH330UYHPl30thw8frgzDUAsWLFBKXf1aFqs339T3+Kef2j9tIa5C+gwI5/L00zBuHLzyip6l8Hqio/UwwyJISUlBKUX58uWtnQYh55ly9giC3r1759qezWKxABATEwNAUFAQhmGQmZlpbcLOysrC3d2dc+fO4erqWqT8lgXnzp3ju+++o2nTpjz++ONUrFgR0J05P//8c7y8vPjiiy8K3KEz+5rd+t+qe4XuN2ArX32l7+3x4+F//7Nv2kJcgwQDwvmMG6eXan3iCZg9+9r79u4Nb75ZpOQCAgJISUkhNjYWT09PlFK5nifPnj0bd3d3br/9doA8lXn2fhaLBXd3d2tAYbpsUpmDBw9y8uRJqlevzsmTJ4uU37IgKSkJpRSNGzcmLS3Nut1isRAYGEjfvn2JiooiMjISuP7IgOxr1K5dO1xdXVm+fLl1u90Cgl9+gSef1AHva6/ZJ00hCkiCAeF8DAM++ggGD4YHHtBDrq6mRQv4448iJVeuXDmaNGnC1q1buXjxIoZh4OLigmEYfP755xw5coRBgwZx8803/5e9/Dus3XrrrbRq1Yr58+fz3nvvcfbsWUBXYF9++SVHjhyhSpUq1srH7p9KS5Dk5GRMJhPu7u75/p7uuusuAObPnw9c/3eZfc3q1q1L48aNiYqKIiEhwXqdi92SJXro6+DB8OGHpWbRIVGKOObphBAFkJGhVJ8+Snl7K7V+ff77zJihn7+eOFGkpL7//ntlGIbq3r27mj9/vtq0aZN65513lGEYqkmTJmrv3r1Kqet3/Dtw4IBq1qyZMplMqmvXrmrw4MEqKChIVa5c2Xr+o0ePFimvZcHp06eVv7+/6tKlS65Ondm//+PHjysfHx9Vp06dAp3PYrGojIwMpZRSTz/9tDIMQy1cuFAppdTu3bvV/v37bfsGLrd+vb6H77hD39NCOCEJBoRzS0lRKixMqYoVldq9O+/r8fFKubgo9e23RUrGbDariRMnqvLlyysvLy/l7e2tDMNQHTt2VKtXr7bul5GRke+Ig8vt27dPjRkzRjVt2lS1bt1ajRw5Ug0bNky5uLjccC/4siYzM1M1btxYVa5cWcXFxeW7T+PGjZWbm5s6efKkUqrgIzQ+/PBDZRiGatu2rRoyZIgKCAhQYWFhxXNddu3S925YmL6XhXBSEgwI53f+vFLNmytVrZpShw/nfb1DB6XuussmSZ05c0bNmDFDTZgwQc2bNy/PELT58+er/v37qxkzZqi0tLQCnfPff/9V/fv3V+XLl1ezZs1SSsnQwoJ44oknlGEYasmSJbm2Z48AuPPOO5WLi4tat26dUurav9O4uDg1evRoNWTIEOvwRMMwlIeHh2rbtq168803rxvkFdqhQ/qebd5c38NCODFZLF44vwoV9LTFt94K3bvrqWGrV895PbsTYXr6tReDKYCAgADuv//+q76+ceNG5s2bh5eXF/fcc491e2JiIsnJydx00015jlm4cCHz5s1j0KBBREREXDsD8+frNRWKYUVGp6GUXtnv8GHo1++qu/Xv35+vvvqKBQsW0KlTJ7y9vXNNMlStWjUqV66Mp6en9ZjY2FjWrFlDSEgI7du3t+7v7e3N5MmTcXV1pUWLFjz88MP07NmTVq1aFc97PHUKevTQy3D/9Ze+h4VwZo6ORoQosJgYpWrVUqpxY6USEnK279yp+w0sW1bsWYiPj1czZsxQq1atyrU9MjJSeXt7q1GjRqmlS5eq/fv3q4SEBPX6668rDw8PVaNGDWu/g6vKylKqcmX9Xvz9lbr3XqW+/FKpAwfsOgmTzVksSu3fr9QXXyg1YIB+b6Df6zXG+ScmJqp27dqp2rVrq+XLlyulcuYLyMrKUg0bNlQ1a9ZUqamp1mPGjRunDMNQDz74oLWPQPYx27Zts0+LTEKCvkdr1VJK+oeIEkKCAVGy7NunlJ+fUu3bK3Xpkt5msShVs6ZSo0Y5LFv//vuv6tu3r/L19VXly5dXdevWVb6+vsowDNWpUye1devWgp0oOVkHNa++qt+jm5uuOKtXV+r++3XfiMOHnTs4sFh0E/k33+g8V6+u34Obm35Pr76q1PLl+r1ex/Tp05VhGKpz587q4sWLSimlzp49qz799FNlGIYaNWpUromDZs2apcLDw9WPP/5oDQZ0luz0+7p0Sb/HKlV0ACRECSFrE4iSZ+tWvUZ8hw56TQN3d3jsMVi9Wq/+5kAHDx7kzz//ZOfOnVStWpXOnTvTokULqlWrVri58LNduqQfi2Qv17x9u54nv3bt3Ms1165dPG+ooGJjc/IYGQnHjum5/Fu2zMljp043tKDPww8/zA8//EDNmjXp1KkT6enpLF68mPDwcL777jtq1KhxY79bW0tPh7599UqakZFQXI8ghCgGEgwI55OZqQvVRo1g2DD975VWroSePeHOO2HmTL3q25136iWM/5sPwJnYrLI6fx7WrtWVTWSkXpVRKQgJyR0cXN6nojicPJmTh8hIPROkYUDTpjl5CAuzybPy9PR0ZsyYwa+//sru3bspV64c/fr1Y/jw4c6z6JPZDIMG6T4ff/6p378QJYgEA8L5KAVjxujpiOPj9SesoUN1YVu5cs5+v/8Od9+tV3977z2oUgXeeQeeecZRObe/hATdIpJdKe/dq7fXq6crpIgI6NIF/P2Lls7Zs7BqVU462S0wjRrlVP6dO4OfX9HSuYZLly5hGAY+Pj7FlsYNUUrPlvndd/Dbb9fsFCmEs5JgQDivjAxYtAh++EH/6+qqWwyGDdM9td3c9GvDhun53v/+W386vdaMhZdJtiRz1nyW+Kx40lU6Zsy44oqH4UEVtyoEuAbg4+JkFc/1XF5pr1wJ//6rtzdunLvSvjyoyk9iYk6QsXJl3iAjPFwHGQEBxfluioXNr/urr+rRLD/8oJfgFqIEkmBAlAxnzsCMGTB1KuzZA9Wq6eldhw7VQ7eee04HCn/9pT8tX+XZdFxWHLvTd3M48zCpKhUA47+vbOq/LwAvw4sQUwhNPJrg71bET9eOcOJE7k/02c35zZrlVOr/Ld7DmjV5Hz8EB+d+/FCjhiPfzQ0rtuv+3nvwwgt6iuFnny3OtyBEsZJgQJQsSsGOHfpT2IwZ+hNsmzb6k+5ff+l9fv89V1OtUorDmYfZlraN0+bTGBjWQr8gsvev5lqNlp4tCTGF2Gc+++Jw9Kiu7JcuhWXL9GOYy/n7Q7duuuUlPBzq1HFMPm2g2K/799/DI4/oR1qTJhXDOxDCfiQYECVXerp+fDB1qu60pZTuad+jh/VRQbIlmZUpK4nOjC50ZXCl7OODTcFEeEeUrEcIqak5vdwjI2HLFsjK0pV/UJDeJzpaBwdubjrAym4N6NABvLyKL287dujHGJet8lhUxX7d586FAQN0X4HPPiu9E0SJMkOCAVE6nD4N06frZ7f+/nDwIFEZUSxPXk4mmUWqDK5kYGDCRDefboS6O0lv9iulp8PmzTnP/Ddt0n0w/P31s/7sir5evZyKTCndMTA7YFi1CuLi9NDN9u1zjmnbtsgzPeZy4gTExEC7drpfSBEV+3WPrkpoh0G68+pPP+khlEKUcBIMiFJpe9p21qauLfZ0wrzCaO7ZvNjTua7MTD3/QnZFvmGDbg2oVEl3GMweWdCwYcErL4sF9u3LmTtg9Wo4d063EnTokHPOVq2K/qk+KQnKlStyxWq36z79AM2f+FgHSkKUAhIMiFLHXhVCNocEBGaznoAou/JfuxaSk3WFGhamK+nwcGjSxCaftq1p7t6d09qwZg1cvAg+ProTYnbLQYsWN5amxaJbJ24wv2XiugtRTCQYEKVKVEYUi5MX2z3dXj69iveRgcWStyK+cEFXxJ065a6I3ey0/lhWVt6AJCVFTzQUFpaTpyZNCveJ32wudEBQaq+7EHYiwYAoNZItyfyY9CMZZNg9bXfceajCQ7brVKhU3ib6xETw9MzdRN+6tU073hVJRkbeRxVpaXqkR+fOOa0VDRvatMNdqbruQjiIBAOiVFBKsTB5IUcyj9i001hBGRgEmYLo49PnxoYdKqUnCLq8897Zs7qib9cupyJt21YHBCVBWlreToyZmXqioss7Mdatm39wsGULfPONblWYNCnfCY5K/HUXwklIMCBKhUMZh1iUvMjR2aC3T29udi/A2ghKwZEjuef3P3lSN49fOazP27v4M24PKSl5hzeazXoio8snNgoKygkOtm2DPn10ALR4MTRokOuUJe66C+GkJBgQJVZgYCBHjx4t1DEj5o9g5oiZnDt27rr7fpT4Ua6fT+47yZopazi86TBJJ5PISs/Cw9cD/xB/GnRtQOcnOhNSJYR7y9+b/wmPHcu9sl9srP7U26JF7pX9ypUr1HsqsS5ezFmRMTIy74qM2a0hSkGvXnoI4ty5BA4bZtfrnpyYzKovVrHnzz0kHE1AKUXlmyrTuGdjIkZG4FvZl2qu1a5+3YUoAezU00iIkm3vkr18/9D3mDPNubanJqUSuz2W2O2xbPl5C/+3/P+I94mnimsVOHUq9yf/w4f1QU2b6jHq2VMBV6xo/zfkDMqV0ytP9uypf85ekTE7WJo2TW8PCYGOHXVrwW232WQlxII6ffA0X9z1BRdOX8i1/cy/Zzjz7xn+nv03T/3+FCpUEW/+77oLUQJJMCBKrNGjR5OUlERURhRnss6QkpTCsg+WWV+v16Ue9cLr5TqmSmDuwtov0I+OwzpeN60F4xdYAwFXd1faDm5LxeoVObDyANGbogE4d/wcG6aup324ma7PzoIDB/TBjRrpCs8OK/uVaBUrwh136G/IvSLjypW6QyUwOj6epLZtierbtFivu8ViYdrD06yBgIevB+0ebIe7lzubZ27mwukLJJ1KYtrD03g+8nl2pe2iq0/XIv4ShHAMCQZEifXoo48C8PX5r0lVqSTEJuSqFALbBBIxMuKa56hYs+J19wGIj8mZw7/9Q+255517AIh4OoKXar+EOUMHCpcSk4kOcadr584wfrzuKFe1aiHfmSAxUY9M2L0bDh3SrSz/ebRSJWjblq+falSs1z12eyyn9uek2//N/rQd3BaARrc34qMeHwFwcu9J9vy1B987fOmKBAOiZJJgQJRoyZZk6yp0xalavWoc330cgJgtMSQcTaBCtQr8s/gfayAAUD+iPil+3qR88QHeLqWk419xy8qCf/7Row02bdIjEA4e1K9VrqxHU4wapf9t3RoqVtTXPenbYs1WwtGEXD9Xb1jd+v8ajXKv3rh3yV6a9GlCiiVFrrsokSQYECXaWfPZIh1//sR5Vn66Ms/26g2q06BbTs/1uybfxdcDvyb9UjrHdx9nUvPcq9T5+PnQ8+WeNLqtkTVfgS6BRcpbqbZjB/z8s678t23TIw3c3PTSyt266ZUA27XT/QXyGbJnj+vuVT734kyn9p2idvPagG4NuNzpA6et+ZLrLkoiCQZEiRafFV+kVekSYhKYP25+nu2tB7XOFQyEdAhh1LJRfPfgd8Qdisuzf8PuDa37GxjEZcURaAq8oTyVCe++q0cStGun5xBo21aPqijg6oj2uO4h7UPwquBFapJueZr7ylxO7juJu5c7W37ekuu4lKQUue6iRJNgQJRo6Sq9yEvUFsSh9Yf4/qHvSTmXgourCy3vbYlfbT8OrDxAzNYYts7ayr6l+3jmr2eodnM10lV6seanxJs5s0iH2+O6e/h6cN+H9/HjYz9iybKQfimd1V+uzndfN5MbBoZcd1FiSTAgSjQz5uvvdA0hHUMYuWDkNffJSs9i+mPTSTmXAkCP53tw+0u3A9D9ue681f4t4g7HkZyYzJJ3lzDkqyFFzpe4Nntcd4Bmdzajcu3KLP9oOdGbokm7mIZfHT+a9m3Kkc1HiFobBUD5auVtki8hHEWCAVGiuWKjFfmu4UzUGZJOJVl/rt2idk76bq7UbFyTuMP60cGJf07YLV9lmT1/v7Vb1ObhHx/OtS0jNYMJTSZYfw5qE2T3fAlhS0VbPFwIB/MwPIr9EYHFbMn187Gdx6z/N2eZObH3hPVnk5cJhcLD8CjWPJV19rjuACnnU7BYcl9/i9nC76N/JzkhGQAXVxdaD2wt112UaNIyIEq0Km5Vir1SqN6gOt6VvK2PCZa+t5TE2EQq3VSJg5EHc3UorB9eH4XC382/WPNU1tnjugNs+3Ubyz9aTv2I+lS6qRKpSan8u+rfXPMPhI8Mx6+On1x3UaJJMCBKtADXvCvZ2Zqbuxv3vHsPPz3+ExazBXOmmc0zNufZr0bjGkQ8HWG3fJVl9vz9Jp1Kyvd6A7R7sB29Xu1l/VmuuyipJBgQJZqPiw9ehlexTzzUon8LAkIDWPfNulwLFXmW86Rqvao06d2ETsM7YfI04W14y8Qzxcxe1z2oXRCtB7bm6LajXDhzgcy0THz9fAlqE0SHYR2oG1bXuq9cd1GSyaqFosRbkbyCvRl7HbKe/ZUMDBq5N5I56u1ArrsQtiMdCEWJ18SjiVNUCAAKRVPPpo7ORpkg110I25FgQJR4/m7+VHOthkHeaWvtycCgumt1WcbWTuS6C2E7EgyIUqGlZ0uHf0pUKFp4tnBoHsoaue5C2IYEA6JUCDGFEGwKdtinRAODYFMwIaYQh6RfVsl1F8I2JBgQpYJhGER4R2DC5JD0TZiI8I7AyGeFPVF85LoLYRsSDIhSw8fFh24+3RySdjefbvi4+Dgk7bJOrrsQRSfBgChVQt1DCfMKs2uaYV5hhLqH2jVNkZtcdyGKRoIBUeo092xut4ohzCuM5p7N7ZKWuDa57kLcOJl0SJRaURlRLE9eTiaZNu1xbmBgwkQ3n27yydAJyXUXovAkGBClWrIlmZUpK4nOjMbAKFLlkH18sCmYCO8IeVbsxOS6C1E4EgyIUk8pxeHMw2xL28Zp8+lCVw7Z+1d3rU4LzxaEmEKk93gJINddiIKTYECUKXFZcexO3010ZjQpSi9JbPz3lU399wV68ZlgUzBNPJrI8rQlmFx3Ia5NggFRZqVYUjhrPktcVhzpKh0zZlxxxcPwwN/NnwDXAFmFrhSS6y5EXhIMCCGEEGWcDC0UQgghyjgJBoQQQogyToIBIYQQooyTYEAIIYQo4yQYEEIIIco4CQaEEEKIMk6CASGEEKKMk2BACCGEKOMkGBBCCCHKOAkGhBBCiDJOggEhhBCijJNgQAghhCjjJBgQQgghyjgJBoQQQogyToIBIYQQooyTYEAIIYQo4yQYEEIIIco4CQaEEEKIMk6CASGEEKKMk2BACCGEKOMkGBBCCCHKuP8H5VNLGg9T3swAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Create a directed graph\n", + "G = nx.from_pandas_edgelist(df, 'source', 'target', ['weight'], \n", + " create_using=nx.DiGraph())\n", + "\n", + "# Generate layout\n", + "#pos = nx.spring_layout(G, seed=42)\n", + "pos = nx.circular_layout(G)\n", + "\n", + "# Explicitly create a new figure\n", + "fig, ax = plt.subplots()\n", + "\n", + "# Draw nodes, edges, and labels\n", + "nx.draw(G, pos, with_labels=True, node_color='lightgreen', node_size=700, font_size=14,\n", + " font_color='black', font_weight='bold', edge_color='red', ax=ax,\n", + " arrowstyle='->', arrowsize=25)\n", + "\n", + "# Draw edge weights\n", + "labels = nx.get_edge_attributes(G, 'weight')\n", + "nx.draw_networkx_edge_labels(G, pos, edge_labels=labels, font_size=14)\n", + "\n", + "# Show plot\n", + "plt.title(\"Directed Network of TF1 to TF10\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "fbad0b53", + "metadata": {}, + "source": [ + " Given an edge list and node2vec parameters, the directed_node2vec_similarity function in the PriorGraphNetwork class (imported as *graph*) returns a scaled similarity matrix for the node embeddings generated by training a node2vec model on the directed graph defined by the edge list.\n", + "\n", + "**directed_node2vec_similarity**(edge_list: List[Tuple[int, int, float]],\n", + " dimensions: int = 64,\n", + " walk_length: int = 30,\n", + " num_walks: int = 200,\n", + " p: float = 1, q: float = 0.5,\n", + " workers: int = 4, window: int = 10,\n", + " min_count: int = 1,\n", + " batch_words: int = 4) -> np.ndarray:\n", + " \n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "86badb4b", + "metadata": {}, + "source": [ + "Parameters:\n", + "-----------\n", + " edge_list: List[List[int, int, float]]\n", + " A list of lists representing the edges of a directed graph. Each edge should be a list of three values:\n", + " [source_node, target_node, edge_weight]. If no edge weight is specified, it is assumed to be 1.0.\n", + "\n", + " dimensions: int, optional (default=64)\n", + " The dimensionality of the node embeddings.\n", + "\n", + " walk_length: int, optional (default=30)\n", + " The length of each random walk during the node2vec training process.\n", + "\n", + " num_walks: int, optional (default=200)\n", + " The number of random walks to generate for each node during the node2vec training process.\n", + "\n", + " p: float, optional (default=1)\n", + " The return parameter for the node2vec algorithm.\n", + "\n", + " q: float, optional (default=0.5)\n", + " The in-out parameter for the node2vec algorithm.\n", + "\n", + " workers: int, optional (default=4)\n", + " The number of worker threads to use during the node2vec training process.\n", + "\n", + " window: int, optional (default=10)\n", + " The size of the window for the skip-gram model during training.\n", + "\n", + " min_count: int, optional (default=1)\n", + " The minimum count for a word in the training data to be included in the model.\n", + "\n", + " batch_words: int, optional (default=4)\n", + " The number of words in each batch during training." + ] + }, + { + "cell_type": "markdown", + "id": "d90f5a0a", + "metadata": {}, + "source": [ + "We run this function below to retrieve the similarity matrix values for our nodes. " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f6448c8f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "directed_node2vec_similarity\n", + "Creating directed graph from edge list\n", + "Initializing the Node2Vec model\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "609bc0c933cf4164828857683b308cd4", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Computing transition probabilities: 0%| | 0/10 [00:00\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TF1TF2TF3TF4TF5TF6TF7TF8TF9TF10
TF11.0000000.9775650.9828390.7919590.9778990.7756400.9671700.7353920.9481570.751666
TF20.9775651.0000000.9792040.8075410.9817140.7892270.9582440.7656840.9749400.767854
TF30.9828390.9792041.0000000.8127720.9826370.7854010.9846940.7564410.9761560.772716
TF40.7919590.8075410.8127721.0000000.7295630.9842060.7597970.9879390.7614820.987777
TF50.9778990.9817140.9826370.7295631.0000000.6994160.9822360.6723450.9832000.681467
TF60.7756400.7892270.7854010.9842060.6994161.0000000.7265840.9838130.7273400.989362
TF70.9671700.9582440.9846940.7597970.9822360.7265841.0000000.6986950.9789320.712766
TF80.7353920.7656840.7564410.9879390.6723450.9838130.6986951.0000000.7145800.984900
TF90.9481570.9749400.9761560.7614820.9832000.7273400.9789320.7145801.0000000.712718
TF100.7516660.7678540.7727160.9877770.6814670.9893620.7127660.9849000.7127181.000000
\n", + "" + ], + "text/plain": [ + " TF1 TF2 TF3 TF4 TF5 TF6 TF7 \\\n", + "TF1 1.000000 0.977565 0.982839 0.791959 0.977899 0.775640 0.967170 \n", + "TF2 0.977565 1.000000 0.979204 0.807541 0.981714 0.789227 0.958244 \n", + "TF3 0.982839 0.979204 1.000000 0.812772 0.982637 0.785401 0.984694 \n", + "TF4 0.791959 0.807541 0.812772 1.000000 0.729563 0.984206 0.759797 \n", + "TF5 0.977899 0.981714 0.982637 0.729563 1.000000 0.699416 0.982236 \n", + "TF6 0.775640 0.789227 0.785401 0.984206 0.699416 1.000000 0.726584 \n", + "TF7 0.967170 0.958244 0.984694 0.759797 0.982236 0.726584 1.000000 \n", + "TF8 0.735392 0.765684 0.756441 0.987939 0.672345 0.983813 0.698695 \n", + "TF9 0.948157 0.974940 0.976156 0.761482 0.983200 0.727340 0.978932 \n", + "TF10 0.751666 0.767854 0.772716 0.987777 0.681467 0.989362 0.712766 \n", + "\n", + " TF8 TF9 TF10 \n", + "TF1 0.735392 0.948157 0.751666 \n", + "TF2 0.765684 0.974940 0.767854 \n", + "TF3 0.756441 0.976156 0.772716 \n", + "TF4 0.987939 0.761482 0.987777 \n", + "TF5 0.672345 0.983200 0.681467 \n", + "TF6 0.983813 0.727340 0.989362 \n", + "TF7 0.698695 0.978932 0.712766 \n", + "TF8 1.000000 0.714580 0.984900 \n", + "TF9 0.714580 1.000000 0.712718 \n", + "TF10 0.984900 0.712718 1.000000 " + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "results_dict[\"similarity_matrix\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "240fbff8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
node_1node_2cosine_similarity
1TF2TF10.977565
2TF3TF10.982839
3TF4TF10.791959
4TF5TF10.977899
5TF6TF10.775640
............
94TF5TF100.681467
95TF6TF100.989362
96TF7TF100.712766
97TF8TF100.984900
98TF9TF100.712718
\n", + "

90 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " node_1 node_2 cosine_similarity\n", + "1 TF2 TF1 0.977565\n", + "2 TF3 TF1 0.982839\n", + "3 TF4 TF1 0.791959\n", + "4 TF5 TF1 0.977899\n", + "5 TF6 TF1 0.775640\n", + ".. ... ... ...\n", + "94 TF5 TF10 0.681467\n", + "95 TF6 TF10 0.989362\n", + "96 TF7 TF10 0.712766\n", + "97 TF8 TF10 0.984900\n", + "98 TF9 TF10 0.712718\n", + "\n", + "[90 rows x 3 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "similarity_df = results_dict[\"similarity_df\"]\n", + "similarity_df" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "cbe9d663", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[['TF2', 'TF1', 0.9775652289390564],\n", + " ['TF3', 'TF1', 0.9828392863273621],\n", + " ['TF4', 'TF1', 0.791959285736084],\n", + " ['TF5', 'TF1', 0.9778987169265747],\n", + " ['TF6', 'TF1', 0.7756398320198059],\n", + " ['TF7', 'TF1', 0.9671704173088074],\n", + " ['TF8', 'TF1', 0.7353924512863159],\n", + " ['TF9', 'TF1', 0.9481567144393921],\n", + " ['TF10', 'TF1', 0.7516655921936035],\n", + " ['TF1', 'TF2', 0.9775652289390564],\n", + " ['TF3', 'TF2', 0.9792038202285767],\n", + " ['TF4', 'TF2', 0.807540774345398],\n", + " ['TF5', 'TF2', 0.9817137718200684],\n", + " ['TF6', 'TF2', 0.7892271280288696],\n", + " ['TF7', 'TF2', 0.9582439661026001],\n", + " ['TF8', 'TF2', 0.7656841278076172],\n", + " ['TF9', 'TF2', 0.9749403595924377],\n", + " ['TF10', 'TF2', 0.7678544521331787],\n", + " ['TF1', 'TF3', 0.9828392863273621],\n", + " ['TF2', 'TF3', 0.9792038202285767],\n", + " ['TF4', 'TF3', 0.8127720355987549],\n", + " ['TF5', 'TF3', 0.9826374053955078],\n", + " ['TF6', 'TF3', 0.7854012846946716],\n", + " ['TF7', 'TF3', 0.9846940636634827],\n", + " ['TF8', 'TF3', 0.7564405202865601],\n", + " ['TF9', 'TF3', 0.9761558771133423],\n", + " ['TF10', 'TF3', 0.7727159261703491],\n", + " ['TF1', 'TF4', 0.791959285736084],\n", + " ['TF2', 'TF4', 0.807540774345398],\n", + " ['TF3', 'TF4', 0.8127720355987549],\n", + " ['TF5', 'TF4', 0.7295628190040588],\n", + " ['TF6', 'TF4', 0.9842056632041931],\n", + " ['TF7', 'TF4', 0.7597967982292175],\n", + " ['TF8', 'TF4', 0.9879385828971863],\n", + " ['TF9', 'TF4', 0.761481523513794],\n", + " ['TF10', 'TF4', 0.987776517868042],\n", + " ['TF1', 'TF5', 0.9778987169265747],\n", + " ['TF2', 'TF5', 0.9817137718200684],\n", + " ['TF3', 'TF5', 0.9826374053955078],\n", + " ['TF4', 'TF5', 0.7295628190040588],\n", + " ['TF6', 'TF5', 0.6994156837463379],\n", + " ['TF7', 'TF5', 0.9822356104850769],\n", + " ['TF8', 'TF5', 0.6723446846008301],\n", + " ['TF9', 'TF5', 0.983199954032898],\n", + " ['TF10', 'TF5', 0.6814671158790588],\n", + " ['TF1', 'TF6', 0.7756398320198059],\n", + " ['TF2', 'TF6', 0.7892271280288696],\n", + " ['TF3', 'TF6', 0.7854012846946716],\n", + " ['TF4', 'TF6', 0.9842056632041931],\n", + " ['TF5', 'TF6', 0.6994156837463379],\n", + " ['TF7', 'TF6', 0.7265838980674744],\n", + " ['TF8', 'TF6', 0.9838127493858337],\n", + " ['TF9', 'TF6', 0.7273401021957397],\n", + " ['TF10', 'TF6', 0.989362359046936],\n", + " ['TF1', 'TF7', 0.9671704173088074],\n", + " ['TF2', 'TF7', 0.9582439661026001],\n", + " ['TF3', 'TF7', 0.9846940636634827],\n", + " ['TF4', 'TF7', 0.7597967982292175],\n", + " ['TF5', 'TF7', 0.9822356104850769],\n", + " ['TF6', 'TF7', 0.7265838980674744],\n", + " ['TF8', 'TF7', 0.6986950635910034],\n", + " ['TF9', 'TF7', 0.9789323806762695],\n", + " ['TF10', 'TF7', 0.7127657532691956],\n", + " ['TF1', 'TF8', 0.7353924512863159],\n", + " ['TF2', 'TF8', 0.7656841278076172],\n", + " ['TF3', 'TF8', 0.7564405202865601],\n", + " ['TF4', 'TF8', 0.9879385828971863],\n", + " ['TF5', 'TF8', 0.6723446846008301],\n", + " ['TF6', 'TF8', 0.9838127493858337],\n", + " ['TF7', 'TF8', 0.6986950635910034],\n", + " ['TF9', 'TF8', 0.7145799398422241],\n", + " ['TF10', 'TF8', 0.9848997592926025],\n", + " ['TF1', 'TF9', 0.9481567144393921],\n", + " ['TF2', 'TF9', 0.9749403595924377],\n", + " ['TF3', 'TF9', 0.9761558771133423],\n", + " ['TF4', 'TF9', 0.761481523513794],\n", + " ['TF5', 'TF9', 0.983199954032898],\n", + " ['TF6', 'TF9', 0.7273401021957397],\n", + " ['TF7', 'TF9', 0.9789323806762695],\n", + " ['TF8', 'TF9', 0.7145799398422241],\n", + " ['TF10', 'TF9', 0.7127178311347961],\n", + " ['TF1', 'TF10', 0.7516655921936035],\n", + " ['TF2', 'TF10', 0.7678544521331787],\n", + " ['TF3', 'TF10', 0.7727159261703491],\n", + " ['TF4', 'TF10', 0.987776517868042],\n", + " ['TF5', 'TF10', 0.6814671158790588],\n", + " ['TF6', 'TF10', 0.989362359046936],\n", + " ['TF7', 'TF10', 0.7127657532691956],\n", + " ['TF8', 'TF10', 0.9848997592926025],\n", + " ['TF9', 'TF10', 0.7127178311347961]]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "undirected_edge_list = results_dict[\"NetREm_edgelist\"]\n", + "undirected_edge_list" + ] + }, + { + "cell_type": "markdown", + "id": "bad6c517", + "metadata": {}, + "source": [ + "We can visualize this updated undirected network of cosine similarities, which we can input to NetREm. :)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "54c46f82", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Create an undirected graph\n", + "G = nx.Graph()\n", + "\n", + "# Add edges to the graph\n", + "for _, row in similarity_df.iterrows():\n", + " G.add_edge(row['node_1'], row['node_2'], weight=row['cosine_similarity'])\n", + "\n", + "# Generate layout\n", + "pos = nx.circular_layout(G)\n", + "# Get edge weights and normalize for better visualization\n", + "edge_weights = [G[u][v]['weight'] for u, v in G.edges()]\n", + "max_weight = max(edge_weights)\n", + "normalized_weights = [5 * (weight / max_weight) \n", + " for weight in edge_weights] # multiplied by 5 for better visibility\n", + "\n", + "# Explicitly create a new figure and axes\n", + "fig, ax = plt.subplots()\n", + "\n", + "# Draw nodes, edges, and labels\n", + "nx.draw(G, pos, with_labels=True, node_color='yellow',\n", + " node_size=700, font_size=18,\n", + " font_color='black', font_weight='bold', \n", + " edge_color='red', width=normalized_weights, ax=ax)\n", + "\n", + "# Draw edge weights\n", + "labels = nx.get_edge_attributes(G, 'weight')\n", + "for label in labels:\n", + " labels[label] = round(labels[label], 2)\n", + "nx.draw_networkx_edge_labels(G, pos, edge_labels=labels, \n", + " font_size=6, ax=ax)\n", + "\n", + "# Show plot\n", + "plt.title(\"Undirected Weighted Network of Cosine Similarity Values\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "d7c46371", + "metadata": {}, + "source": [ + "We can compare the original directed network weights (*directed_weight* values) with the updated cosine similarity undirected values (*cosine_similarity*) as we do below:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "a0d62a2f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
node_1node_2cosine_similaritydirected_weight
78TF7TF90.9789320.9
38TF3TF50.9826370.8
7TF9TF10.9481570.7
19TF2TF30.9792040.7
58TF5TF70.9822360.6
...............
31TF6TF40.9842060.0
30TF5TF40.7295630.0
28TF2TF40.8075410.0
27TF1TF40.7919590.0
89TF9TF100.7127180.0
\n", + "

90 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " node_1 node_2 cosine_similarity directed_weight\n", + "78 TF7 TF9 0.978932 0.9\n", + "38 TF3 TF5 0.982637 0.8\n", + "7 TF9 TF1 0.948157 0.7\n", + "19 TF2 TF3 0.979204 0.7\n", + "58 TF5 TF7 0.982236 0.6\n", + ".. ... ... ... ...\n", + "31 TF6 TF4 0.984206 0.0\n", + "30 TF5 TF4 0.729563 0.0\n", + "28 TF2 TF4 0.807541 0.0\n", + "27 TF1 TF4 0.791959 0.0\n", + "89 TF9 TF10 0.712718 0.0\n", + "\n", + "[90 rows x 4 columns]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "directed_wieghts_df = df\n", + "directed_wieghts_df = directed_wieghts_df.rename(columns = {\"source\":\"node_1\", \"target\":\"node_2\",\n", + " \"weight\":\"directed_weight\"})\n", + "directed_wieghts_df\n", + "comparison_df = pd.merge(similarity_df, directed_wieghts_df, how = \"left\", on = [\"node_1\", \"node_2\"])\n", + "comparison_df = comparison_df.fillna(0)\n", + "comparison_df = comparison_df.sort_values(by = [\"directed_weight\"], ascending = False)\n", + "comparison_df" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/code/old_code/refresh/error_metrics.py b/code/old_code/refresh/error_metrics.py new file mode 100644 index 0000000..d4ca876 --- /dev/null +++ b/code/old_code/refresh/error_metrics.py @@ -0,0 +1,474 @@ +# Error_Metrics.py :) +import pandas as pd +import numpy as np +import random +import copy +from tqdm import tqdm +import os +import sys # https://www.dev2qa.com/how-to-run-python-script-py-file-in-jupyter-notebook-ipynb-file-and-ipython/#:~:text=How%20To%20Run%20Python%20Script%20.py%20File%20In,2.%20Invoke%20Python%20Script%20File%20From%20Ipython%20Command-Line. +import networkx as nx +import scipy +from scipy.linalg import svd as robust_svd +from sklearn.model_selection import KFold, train_test_split, GridSearchCV, cross_val_score +from sklearn.decomposition import TruncatedSVD +from sklearn import linear_model +from sklearn.linear_model import Lasso, LassoCV, LinearRegression, ElasticNetCV, Ridge +from numpy.typing import ArrayLike +# from skopt import gp_minimize, space +from typing import Optional, List, Tuple +from sklearn.metrics import make_scorer +import plotly.express as px +from sklearn.base import RegressorMixin, ClassifierMixin, BaseEstimator +import matplotlib.pyplot as plt +from numpy.typing import ArrayLike +from scipy.sparse.linalg.interface import LinearOperator +import warnings +from sklearn.exceptions import ConvergenceWarning +printdf = lambda *args, **kwargs: print(pd.DataFrame(*args, **kwargs)) +rng_seed = 2023 # random seed for reproducibility +randSeed = 123 + +def calculate_mean_square_error(actual_values, predicted_values): + # Please note that this function by Saniya calculates the Mean Square Error (MSE) + difference = (actual_values - predicted_values) + squared_diff = difference ** 2 # square of the difference + mean_squared_diff = np.mean(squared_diff) + return mean_squared_diff + + +def mse(REF: np.ndarray, X: np.ndarray, axis: Optional[int] = None) -> np.float: + """Compute mean square error between array with a reference array - + If REF or X is complex, compute mse(REF.real, X.real) + 1j * mse(REF.imag, X.imag) + + Parameters + ---------- + REF: + ground truth, or reference array, e.g. shape=(n_sample, n_target) for machine learning + X: + result array to compare with reference, e.g. shape=(n_sample, n_target) for machine learning + axis: + Axis along which the comparison is computed. Default to None to compute the comparison + of the flattened array. + + Returns + ------- + mse_: + normalized mean square error + + Examples + ------- + mse(REF, X, axis=0) compute the comparision along n_sample dimension for machine learning + regression application where shape=(n_sample, n_target) + """ + + if (not np.iscomplexobj(REF)) and (not np.iscomplexobj(X)): + return ((X - REF)**2).mean(axis=axis) + else: + return mse(REF.real, X.real, axis) + 1j * mse(REF.imag, X.imag, axis) + + +def nmse(REF: np.ndarray, X: np.ndarray, axis: Optional[int] = None) -> np.float: + """Compute normalized mean square error between array with a reference array - + If REF or X is complex, compute nmse(REF.real, X.real) + 1j * nmse(REF.imag, X.imag) + + Parameters + ---------- + REF: + ground truth, or reference array, e.g. shape=(n_sample, n_target) for machine learning + X: + result array to compare with reference, e.g. shape=(n_sample, n_target) for machine learning + axis: + Axis along which the comparison is computed. Default to None to compute the comparison + of the flattened array. + + Returns + ------- + nmse_: + normalized mean square error + + Examples + ------- + nmse(REF, X, axis=0) compute the comparision along n_sample dimension for machine learning + regression application where shape=(n_sample, n_target) + """ + if (not np.iscomplexobj(REF)) and (not np.iscomplexobj(X)): + return ((X - REF)**2).mean(axis=axis) / (REF**2).mean(axis=axis) + else: + return nmse(REF.real, X.real, axis) + 1j * nmse(REF.imag, X.imag, axis) + + +def snr(REF: np.ndarray, X: np.ndarray, axis: Optional[int] = None) -> np.float64: + """Compare an array with a reference array - compute signal to noise ration in dB. + If REF or X is complex, compute snr(REF.real, X.real) + 1j * snr(REF.imag, X.imag) + + Parameters + ---------- + REF: + ground truth, or reference array, e.g. shape=(n_sample, n_target) for machine learning + X: + result array to compare with reference, e.g. shape=(n_sample, n_target) for machine learning + axis: + Axis along which the comparison is computed. The default is to compute the comparison + of the flattened array. + + Returns + ------- + snr_: + signal to noise ration in dB + + Examples + ------- + snr(REF, X, axis=0) compute the comparision along n_sample dimension for machine learning + regression application where shape=(n_sample, n_target) + """ + if (not np.iscomplexobj(REF)) and (not np.iscomplexobj(X)): + return 10 * np.log10((REF**2).mean(axis=axis) / ((X - REF)**2).mean(axis=axis)) + else: + return snr(REF.real, X.real, axis) + 1j * snr(REF.imag, X.imag, axis) + + +def psnr(REF: np.ndarray, X: np.ndarray, axis: Optional[int] = None, max_: Optional[np.float64] = None) -> np.float64: + """See snr, TODO: copy and modify docstring from snr + """ + if (not np.iscomplexobj(REF)) and (not np.iscomplexobj(X)): + if max_ is None: + max_ = REF.max() + return 10 * np.log10(max_**2 / ((X - REF)**2).mean(axis=axis)) # change from REF.max() to 255 + else: + return psnr(REF.real, X.real, axis, max_) + 1j * psnr(REF.imag, X.imag, axis, max_) + + +def nmse_custom_score(y_true, y_pred): + """ + Calculates the negative normalized mean squared error (MSE) between the true and predicted values. + """ + import numpy as np + if isinstance(y_true, pd.DataFrame): + y_true = y_true.values.flatten() + if isinstance(y_pred, pd.DataFrame): + y_pred = y_pred.values.flatten() + if not any(y_pred): # if all predicted coefficients are 0 + return -np.inf # return a high negative score + nmseVal = nmse(y_true, y_pred) + return -nmseVal + + +def mse_custom_score(y_true, y_pred): + """ + Calculates the negative normalized mean squared error (MSE) between the true and predicted values. + default: greater_is_better, so we set negative mseVal to find the smallest mse + """ + import numpy as np + if isinstance(y_true, pd.DataFrame): + y_true = y_true.values.flatten() + if isinstance(y_pred, pd.DataFrame): + y_pred = y_pred.values.flatten() + if not any(y_pred): # if all predicted coefficients are 0 + return -np.inf # return a high negative score + mseVal = mse(y_true, y_pred) + return -mseVal + + +def snr_custom_score(y_true, y_pred): + """ + Higher the SNR the better + """ + if isinstance(y_true, pd.DataFrame): + y_true = y_true.values.flatten() + if isinstance(y_pred, pd.DataFrame): + y_pred = y_pred.values.flatten() + if not any(y_pred): # if all predicted coefficients are 0 + return -np.inf # return a high negative score + snrVal = snr(y_true, y_pred) + return snrVal + + +def psnr_custom_score(y_true, y_pred): + """ + Higher the psnr, the better + """ + if isinstance(y_true, pd.DataFrame): + y_true = y_true.values.flatten() + if isinstance(y_pred, pd.DataFrame): + y_pred = y_pred.values.flatten() + if not any(y_pred): # if all predicted coefficients are 0 + return -np.inf # return a high negative score + psnrVal = psnr(y_true, y_pred) + return psnrVal + +# Create a custom scorer object using make_scorer +mse_custom_scorer = make_scorer(mse_custom_score) +nmse_custom_scorer = make_scorer(nmse_custom_score) +snr_custom_scorer = make_scorer(snr_custom_score) +psnr_custom_scorer = make_scorer(psnr_custom_score) + + +def generate_model_metrics_for_baselines_df(X_train, y_train, X_test, y_test, model_name = "ElasticNetCV", y_intercept = False, tf_name = "SOX10"): + from sklearn.linear_model import ElasticNetCV, LinearRegression, LassoCV, RidgeCV + print(f"{model_name} results :) for fitting y_intercept = {y_intercept}") + if model_name == "ElasticNetCV": + regr = ElasticNetCV(cv=5, random_state=0, fit_intercept = y_intercept) + elif model_name == "LinearRegression": + regr = LinearRegression(fit_intercept = y_intercept) + elif model_name == "LassoCV": + regr = LassoCV(cv=5, fit_intercept = y_intercept) + elif model_name == "RidgeCV": + regr = RidgeCV(cv=5, fit_intercept = y_intercept) + regr.fit(X_train, y_train) + if model_name in ["RidgeCV", "LinearRegression"]: + model_df = pd.DataFrame(regr.coef_) + else: + model_df = pd.DataFrame(regr.coef_).transpose() + model_df.columns = X_train.columns.tolist() + selected_row = model_df.iloc[0] + selected_cols = selected_row[selected_row != 0].index # Filter out the columns with value 0 + model_df = model_df[selected_cols] + df = model_df.replace("None", np.nan).apply(pd.to_numeric, errors='coerce') + sorted_series = df.abs().squeeze().sort_values(ascending=False) + # convert the sorted series back to a DataFrame + sorted_df = pd.DataFrame(sorted_series) + # add a column for the rank + sorted_df['Rank'] = range(1, len(sorted_df) + 1) + sorted_df['TF'] = sorted_df.index + sorted_df = sorted_df.rename(columns = {0:"AbsoluteVal_coefficient"}) + tfs = sorted_df["TF"].tolist() + if tf_name not in tfs: + sorted_df = pd.DataFrame(["N/A", tf_name]).transpose() + sorted_df.columns = ["Rank", "TF"] + sorted_df["Info"] = model_name + if y_intercept: + sorted_df["y_intercept"] = "True :)" + else: + sorted_df["y_intercept"] = "False :(" + sorted_df["num_TFs"] = model_df.shape[1] + predY_train = regr.predict(X_train) + predY_test = regr.predict(X_test) + train_mse = mse(y_train.values.flatten(), predY_train) + test_mse = mse(y_test.values.flatten(), predY_test) + train_nmse = nmse(y_train.values.flatten(), predY_train) + test_nmse = nmse(y_test.values.flatten(), predY_test) + sorted_df["train_mse"] = train_mse + sorted_df["test_mse"] = test_mse + sorted_df["train_nmse"] = train_nmse + sorted_df["test_nmse"] = test_nmse + predY_train = regr.predict(X_train) + predY_test = regr.predict(X_test) + sorted_df["train_nmse"] = nmse(y_train.values.flatten(), predY_train) + sorted_df["test_nmse"] = nmse(y_test.values.flatten(), predY_test) + sorted_df["train_snr"] = snr(y_train.values.flatten(), predY_train) + sorted_df["test_snr"] = snr(y_test.values.flatten(), predY_test) + sorted_df["train_psnr"] = psnr(y_train.values.flatten(), predY_train) + sorted_df["test_psnr"] = psnr(y_test.values.flatten(), predY_test) + return sorted_df + + +def generate_model_metrics_for_netrem_model_object(netrem_model, y_intercept_fit, X_train, y_train, X_test, y_test, filtered_results = False, tf_name = "SOX10", focus_gene = "y"): + if netrem_model.model_nonzero_coef_df.shape[1] == 1: + sorted_df = pd.DataFrame(["N/A", tf_name]).transpose() + sorted_df.columns = ["Rank", "TF"] + tf_netrem_found = False + if netrem_model.model_type == "LassoCV": + sorted_df["Info"] = "NetREm (b = " + str(netrem_model.beta_network) + "; LassoCV)" #+ netrem_info# + str(netrem_model.optimal_alpha) + ")" + else: + sorted_df["Info"] = "NetREm (b = " + str(netrem_model.beta_network) + "; a = " + netrem_model.alpha_lasso + ")"# : " + netrem_info# + str(netrem_model.optimal_alpha) + ")" + + if y_intercept_fit: + sorted_df["y_intercept"] = "True :)" + else: + sorted_df["y_intercept"] = "False :(" + sorted_df["num_TFs"] = 0 + else: + sorted_df = netrem_model.sorted_coef_df[netrem_model.sorted_coef_df["TF"] == tf_name] + tfs = sorted_df["TF"].tolist() + tf_netrem_found = True + if tf_name not in tfs: + sorted_df = pd.DataFrame(["N/A", tf_name]).transpose() + sorted_df.columns = ["Rank", "TF"] + tf_netrem_found = False + sorted_df["Info"] = "NetREm (b = " + str(netrem_model.beta_network) + "; LassoCV)"# + str(netrem_model.optimal_alpha) + ")" + sorted_df["num_TFs"] = netrem_model.model_nonzero_coef_df.drop(columns = ["y_intercept"]).shape[1] + predY_train = netrem_model.predict(X_train) + predY_test = netrem_model.predict(X_test) + sorted_df["train_mse"] = mse(y_train.values.flatten(), predY_train) + sorted_df["test_mse"] = mse(y_test.values.flatten(), predY_test) + sorted_df["train_nmse"] = nmse(y_train.values.flatten(), predY_train) + sorted_df["test_nmse"] = nmse(y_test.values.flatten(), predY_test) + sorted_df["train_snr"] = snr(y_train.values.flatten(), predY_train) + sorted_df["test_snr"] = snr(y_test.values.flatten(), predY_test) + sorted_df["train_psnr"] = psnr(y_train.values.flatten(), predY_train) + sorted_df["test_psnr"] = psnr(y_test.values.flatten(), predY_test) + sorted_df_netrem = sorted_df + netrem_dict = {"sorted_df_netrem":sorted_df_netrem, "tf_netrem_found":tf_netrem_found} + return netrem_dict + + +def metrics_for_netrem_models_versus_other_models(netrem_with_intercept, netrem_no_intercept, X_train, y_train, X_test, y_test, filtered_results = False, tf_name = "SOX10", target_gene = "y"): + """ :) This is similar to function metrics_for_netrem_versus_other_models() except it focuses on 2 types of NetREm models: + 1. with y-intercept fitted + 2. with no y-intercept fitted + :) Please note: + MSE (Mean Squared Error) and NMSE (Normalized Mean Squared Error) are both measures of the average difference between the predicted and actual values, where lower values indicate better performance. + + PSNR (Peak Signal-to-Noise Ratio) and SNR (Signal-to-Noise Ratio) are both measures of the ratio between the maximum possible signal power and the power of the noise, where higher values indicate better performance. + + However, the specific metrics that are most relevant to a particular machine learning problem can vary depending on the application and the specific goals of the model. So, it's important to consider the context and objectives of each project when selecting evaluation metrics. + """ + focus_gene = target_gene + netrem_intercept_bool = True + netrem_no_intercept_bool = True + if netrem_with_intercept is None: + netrem_intercept_bool = False + tf_netrem_found_with_intercept = False + if netrem_no_intercept is None: + netrem_no_intercept_bool = False + tf_netrem_found_no_intercept = False + + if netrem_with_intercept: + netrem_with_intercept_sorted_dict = generate_model_metrics_for_netrem_model_object(netrem_with_intercept, True, X_train, y_train, X_test, y_test, filtered_results, tf_name, focus_gene) + netrem_with_intercept_sorted_df = netrem_with_intercept_sorted_dict["sorted_df_netrem"] + netrem_with_intercept_sorted_df["y_intercept"] = "True :)" + tf_netrem_found_with_intercept = netrem_with_intercept_sorted_dict["tf_netrem_found"] + + if netrem_no_intercept_bool: + netrem_no_intercept_sorted_dict = generate_model_metrics_for_netrem_model_object(netrem_no_intercept, False, X_train, y_train, X_test, y_test, filtered_results, tf_name, focus_gene) + netrem_no_intercept_sorted_df = netrem_no_intercept_sorted_dict["sorted_df_netrem"] + netrem_no_intercept_sorted_df["y_intercept"] = "False :(" + tf_netrem_found_no_intercept = netrem_no_intercept_sorted_dict["tf_netrem_found"] + + + sorted_df_elasticcv = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "ElasticNetCV", y_intercept = False, tf_name = tf_name) + sorted_df_lassocv = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "LassoCV", y_intercept = False, tf_name = tf_name) + sorted_df_ridgecv = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "RidgeCV", y_intercept = False, tf_name = tf_name) + sorted_df_linear = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "LinearRegression", y_intercept = False, tf_name = tf_name) + sorted_df_elasticcv2 = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "ElasticNetCV", y_intercept = True, tf_name = tf_name) + sorted_df_lassocv2 = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "LassoCV", y_intercept = True, tf_name = tf_name) + sorted_df_ridgecv2 = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "RidgeCV", y_intercept = True, tf_name = tf_name) + sorted_df_linear2 = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "LinearRegression", y_intercept = True, tf_name = tf_name) + + if netrem_no_intercept_bool: + sorty_combo = pd.concat([netrem_no_intercept_sorted_df, sorted_df_elasticcv, sorted_df_ridgecv, sorted_df_lassocv, sorted_df_linear]) + else: + sorty_combo = pd.concat([sorted_df_elasticcv, sorted_df_ridgecv, sorted_df_lassocv, sorted_df_linear]) + if netrem_intercept_bool: + sorty_combo = pd.concat([sorty_combo, netrem_with_intercept_sorted_df, sorted_df_elasticcv2, sorted_df_ridgecv2, sorted_df_lassocv2, sorted_df_linear2]) + else: + sorty_combo = pd.concat([sorty_combo, sorted_df_elasticcv2, sorted_df_ridgecv2, sorted_df_lassocv2, sorted_df_linear2]) + sorty_combo = sorty_combo[sorty_combo["TF"] == tf_name] + sorty_combo["TG"] = focus_gene + sorty_combo = sorty_combo.reset_index().drop(columns = ["index"]) + if 'AbsoluteVal_coefficient' not in sorty_combo.columns.tolist(): + sorty_combo['AbsoluteVal_coefficient'] = pd.Series([float('nan')]*len(sorty_combo)) + + sorty_combo = sorty_combo[['AbsoluteVal_coefficient', 'Rank', 'TF', 'Info', 'y_intercept', 'num_TFs', 'TG', 'train_mse', + 'test_mse', 'train_nmse', 'test_nmse', 'train_snr', 'test_snr', + 'train_psnr', 'test_psnr']] + aaa = sorty_combo + aaa['rank_mse_train'] = aaa['train_mse'].rank(ascending=True).astype(int) + aaa['rank_mse_test'] = aaa['test_mse'].rank(ascending=True).astype(int) + aaa['rank_nmse_train'] = aaa['train_nmse'].rank(ascending=True).astype(int) + aaa['rank_nmse_test'] = aaa['test_nmse'].rank(ascending=True).astype(int) + + aaa['rank_snr_train'] = aaa['train_snr'].rank(ascending=False).astype(int) + aaa['rank_snr_test'] = aaa['test_snr'].rank(ascending=False).astype(int) + aaa['rank_psnr_train'] = aaa['train_psnr'].rank(ascending=False).astype(int) + aaa['rank_psnr_test'] = aaa['test_psnr'].rank(ascending=False).astype(int) + aaa["total_metrics_rank"] = aaa['rank_mse_train'] + aaa['rank_mse_test'] + aaa['rank_nmse_train'] + aaa['rank_nmse_test'] + aaa["total_metrics_rank"] += aaa['rank_snr_train'] + aaa['rank_snr_test'] + aaa['rank_psnr_train'] + aaa['rank_psnr_test'] + sorty_combo = aaa + + reduced_results_df = sorty_combo[sorty_combo["Rank"] != "N/A"] + reduced_results_df = reduced_results_df.sort_values(by = ["Rank"]) + + + if tf_netrem_found_with_intercept: + print(netrem_with_intercept.final_corr_vs_coef_df[["info"] + [tf_name]]) + elif tf_netrem_found_no_intercept: + print(netrem_no_intercept.final_corr_vs_coef_df[["info"] + [tf_name]]) + if filtered_results: + return reduced_results_df + else: + return sorty_combo + + +def metrics_for_netrem_versus_other_models(netrem_model, X_train, y_train, X_test, y_test, filtered_results = False, tf_name = "SOX10", target_gene = "y"): + """ :) Please note: + MSE (Mean Squared Error) and NMSE (Normalized Mean Squared Error) are both measures of the average difference between the predicted and actual values, where lower values indicate better performance. + + PSNR (Peak Signal-to-Noise Ratio) and SNR (Signal-to-Noise Ratio) are both measures of the ratio between the maximum possible signal power and the power of the noise, where higher values indicate better performance. + + However, the specific metrics that are most relevant to a particular machine learning problem can vary depending on the application and the specific goals of the model. So, it's important to consider the context and objectives of each project when selecting evaluation metrics. + """ + focus_gene = target_gene + if netrem_model.model_nonzero_coef_df.shape[1] == 1: + sorted_df = pd.DataFrame(["N/A", tf_name]).transpose() + sorted_df.columns = ["Rank", "TF"] + tf_netrem_found = False + sorted_df["Info"] = "NetREm (b = " + str(netrem_model.beta_network) + "; LassoCV)"# + str(netrem_model.optimal_alpha) + ")" + sorted_df["y_intercept"] = "False :(" + sorted_df["num_TFs"] = 0 + else: + sorted_df = netrem_model.sorted_coef_df[netrem_model.sorted_coef_df["TF"] == tf_name] + tfs = sorted_df["TF"].tolist() + tf_netrem_found = True + if tf_name not in tfs: + sorted_df = pd.DataFrame(["N/A", tf_name]).transpose() + sorted_df.columns = ["Rank", "TF"] + tf_netrem_found = False + sorted_df["Info"] = "NetREm (b = " + str(netrem_model.beta_network) + "; LassoCV)"# + str(netrem_model.optimal_alpha) + ")" + sorted_df["y_intercept"] = "False :(" + sorted_df["num_TFs"] = netrem_model.model_nonzero_coef_df.drop(columns = ["y_intercept"]).shape[1] + predY_train = netrem_model.predict(X_train) + predY_test = netrem_model.predict(X_test) + sorted_df["train_mse"] = mse(y_train.values.flatten(), predY_train) + sorted_df["test_mse"] = mse(y_test.values.flatten(), predY_test) + sorted_df["train_nmse"] = nmse(y_train.values.flatten(), predY_train) + sorted_df["test_nmse"] = nmse(y_test.values.flatten(), predY_test) + sorted_df["train_snr"] = snr(y_train.values.flatten(), predY_train) + sorted_df["test_snr"] = snr(y_test.values.flatten(), predY_test) + sorted_df["train_psnr"] = psnr(y_train.values.flatten(), predY_train) + sorted_df["test_psnr"] = psnr(y_test.values.flatten(), predY_test) + sorted_df_netrem = sorted_df + + sorted_df_elasticcv = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "ElasticNetCV", y_intercept = False, tf_name = tf_name) + sorted_df_lassocv = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "LassoCV", y_intercept = False, tf_name = tf_name) + sorted_df_ridgecv = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "RidgeCV", y_intercept = False, tf_name = tf_name) + sorted_df_linear = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "LinearRegression", y_intercept = False, tf_name = tf_name) + sorted_df_elasticcv2 = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "ElasticNetCV", y_intercept = True, tf_name = tf_name) + sorted_df_lassocv2 = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "LassoCV", y_intercept = True, tf_name = tf_name) + sorted_df_ridgecv2 = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "RidgeCV", y_intercept = True, tf_name = tf_name) + sorted_df_linear2 = generate_model_metrics_for_baselines_df(X_train = X_train, y_train = y_train, X_test = X_test, y_test = y_test, model_name = "LinearRegression", y_intercept = True, tf_name = tf_name) + + sorty_combo = pd.concat([sorted_df_netrem, sorted_df_elasticcv, sorted_df_ridgecv, sorted_df_lassocv, sorted_df_linear]) + sorty_combo = pd.concat([sorty_combo, sorted_df_elasticcv2, sorted_df_ridgecv2, sorted_df_lassocv2, sorted_df_linear2]) + sorty_combo = sorty_combo[sorty_combo["TF"] == tf_name] + sorty_combo["TG"] = focus_gene + sorty_combo = sorty_combo.reset_index().drop(columns = ["index"]) + if 'AbsoluteVal_coefficient' not in sorty_combo.columns.tolist(): + sorty_combo['AbsoluteVal_coefficient'] = pd.Series([float('nan')]*len(sorty_combo)) + + sorty_combo = sorty_combo[['AbsoluteVal_coefficient', 'Rank', 'TF', 'Info', 'y_intercept', 'num_TFs', 'TG', 'train_mse', + 'test_mse', 'train_nmse', 'test_nmse', 'train_snr', 'test_snr', + 'train_psnr', 'test_psnr']] + + aaa = sorty_combo + aaa['rank_mse_train'] = aaa['train_mse'].rank(ascending=True).astype(int) + aaa['rank_mse_test'] = aaa['test_mse'].rank(ascending=True).astype(int) + aaa['rank_nmse_train'] = aaa['train_nmse'].rank(ascending=True).astype(int) + aaa['rank_nmse_test'] = aaa['test_nmse'].rank(ascending=True).astype(int) + + aaa['rank_snr_train'] = aaa['train_snr'].rank(ascending=False).astype(int) + aaa['rank_snr_test'] = aaa['test_snr'].rank(ascending=False).astype(int) + aaa['rank_psnr_train'] = aaa['train_psnr'].rank(ascending=False).astype(int) + aaa['rank_psnr_test'] = aaa['test_psnr'].rank(ascending=False).astype(int) + aaa["total_metrics_rank"] = aaa['rank_mse_train'] + aaa['rank_mse_test'] + aaa['rank_nmse_train'] + aaa['rank_nmse_test'] + aaa["total_metrics_rank"] += aaa['rank_snr_train'] + aaa['rank_snr_test'] + aaa['rank_psnr_train'] + aaa['rank_psnr_test'] + sorty_combo = aaa + + reduced_results_df = sorty_combo[sorty_combo["Rank"] != "N/A"] + reduced_results_df = reduced_results_df.sort_values(by = ["Rank"]) + if tf_netrem_found: + print(netrem_model.final_corr_vs_coef_df[["info"] + [tf_name]]) + if filtered_results: + return reduced_results_df + else: + return sorty_combo \ No newline at end of file diff --git a/code/old_code/refresh/essential_functions.py b/code/old_code/refresh/essential_functions.py new file mode 100644 index 0000000..ebe7587 --- /dev/null +++ b/code/old_code/refresh/essential_functions.py @@ -0,0 +1,123 @@ +# Essential_functions.py: :) +import pandas as pd +import numpy as np +import random +import copy +from tqdm import tqdm +import os +import sys # https://www.dev2qa.com/how-to-run-python-script-py-file-in-jupyter-notebook-ipynb-file-and-ipython/#:~:text=How%20To%20Run%20Python%20Script%20.py%20File%20In,2.%20Invoke%20Python%20Script%20File%20From%20Ipython%20Command-Line. +import networkx as nx +import scipy +from scipy.linalg import svd as robust_svd +from sklearn.model_selection import KFold, train_test_split, GridSearchCV, cross_val_score +from sklearn.decomposition import TruncatedSVD +from sklearn import linear_model +from sklearn.linear_model import Lasso, LassoCV, LinearRegression, ElasticNetCV, Ridge +from numpy.typing import ArrayLike +# from skopt import gp_minimize, space +from typing import Optional, List, Tuple +from sklearn.metrics import make_scorer +import plotly.express as px +from sklearn.base import RegressorMixin, ClassifierMixin, BaseEstimator +import matplotlib.pyplot as plt +from numpy.typing import ArrayLike +from scipy.sparse.linalg.interface import LinearOperator +import warnings +from sklearn.exceptions import ConvergenceWarning +printdf = lambda *args, **kwargs: print(pd.DataFrame(*args, **kwargs)) +rng_seed = 2023 # random seed for reproducibility +randSeed = 123 + +# Python program to illustrate the intersection +# of two lists in most simple way +def intersection(lst1, lst2): + lst3 = [value for value in lst1 if value in lst2] + return lst3 + + +def view_matrix_as_dataframe(matrix, column_names_list = [], row_names_list = []): + # :) Please note this function by Saniya returns a dataframe representation of the numpy matrix + # optional are the names of the columns and names of the rows (indices) + matDF = pd.DataFrame(matrix) + if len(column_names_list) == matDF.shape[1]: + matDF.columns = column_names_list + if len(row_names_list) == matDF.shape[0]: + matDF.index = row_names_list + return matDF + + +def check_symmetric(a, rtol=1e-05, atol=1e-08): + # https://stackoverflow.com/questions/42908334/checking-if-a-matrix-is-symmetric-in-numpy + # Please note that this function checks if a matrix is symmetric in Python + # for square matrices (same # of rows and columns), there is a possiblity they may be symmetric + # returns True if the matrix is symmetric (matrix = matrix_tranpose) + # returns False if the matrix is NOT symmetric + return np.allclose(a, a.T, rtol=rtol, atol=atol) + + +class DiagonalLinearOperator(LinearOperator): + """Construct a diagonal matrix as a linear operator instead a full numerical matirx np.diag(d). + This saves memory and computation time which is especially useful when d is huge. + D.T = D + For 2d matrix A: + D @ A = d[:, np.newwaxis]* A # scales rows of A + A @ D = A * d[np.newaxis, :] # scales cols of A + For 1d vector v: + D @ v = d * v + v @ D = v * d + NOTE: Coding just for fun: using a numerical matrix or a sparse matrix maybe just fine for network regularization. + By Xiang Huang + """ + def __init__(self, d): + """d is a 1d vector of dimension N""" + N = len(d) + self.d = d + super().__init__(dtype=None, shape=(N, N)) + + def _transpose(self): + return self + + def _matvec(self, v): + return self.d * v + + def _matmat(self, A): + return self.d[:, np.newaxis] * A + + def __rmatmul__(self, x): + """Implmentation of A @ D, and x @ D + We could implment __matmul__ in a similar way without inheriting LinearOperator + Because we inherit from LinearOperator, we can implment _matvec, and _matmat instead. + """ + if x.ndim == 2: + return x * self.d[np.newaxis, :] + elif x.ndim == 1: + return x * self.d + else: + raise ValueError(f'Array should be 1d or 2d, but it is {x.ndim}d') + # Generally A @ D will call A.__matmul__(D) which raises a ValueError and not a NotImplemented + # We need to set __array_priority__ to high value higher than 0 (np.array) and 10.1 (scipy.sparse.csr_matrix) + # https://github.com/numpy/numpy/issues/8155 + # https://stackoverflow.com/questions/40252765/overriding-other-rmul-with-your-classs-mul + __array_priority__ = 1000 + + +def normalize_data_zero_to_one(data): + # https://stackoverflow.com/questions/18380419/normalization-to-bring-in-the-range-of-0-1 + return (data - np.min(data)) / (np.max(data) - np.min(data)) + + +def draw_arrow(direction = "down", color = "blue"): + x = [0.5, 0.5] + if direction == "down": + # Define the coordinates for the arrow + y = [0.9, 0.1] + else: # up-arrow + y = [0.1, 0.9] + fig, ax = plt.subplots(figsize=(2,2)) + # Plot the arrow using Matplotlib + plt.arrow(x[0], y[0], x[1]-x[0], y[1]-y[0], head_width=0.05, head_length=0.1, fc=color, ec=color) + # Set the x and y limits to adjust the plot size + plt.xlim(0, 1) + plt.ylim(0, 1) + plt.axis('off') # Hide the axis labels + plt.show() # Show the plot \ No newline at end of file diff --git a/user_guide/netremCV-old.ipynb b/code/old_code/refresh/netremCV-old.ipynb similarity index 100% rename from user_guide/netremCV-old.ipynb rename to code/old_code/refresh/netremCV-old.ipynb diff --git a/code/old_code/refresh/netremCV.ipynb b/code/old_code/refresh/netremCV.ipynb new file mode 100644 index 0000000..849d1cc --- /dev/null +++ b/code/old_code/refresh/netremCV.ipynb @@ -0,0 +1,1247 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ade59a66", + "metadata": {}, + "source": [ + "# netremCV\n", + "Cross-validation approach for estimating the optimal $\\beta_{net}$ and $\\alpha_{lasso}$.\n", + "\n", + "Selection for $\\beta_{net}$ can impact the optimal values for $\\alpha_{net}$" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "d801c820", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) same_train_test_data = False\n", + "Please note that since we hold out 30.0% of our 100000 samples for testing, we have:\n", + "X_train = 70000 rows (samples) and 5 columns (N = 5 predictors) for training.\n", + "X_test = 30000 rows (samples) and 5 columns (N = 5 predictors) for testing.\n", + "y_train = 70000 corresponding rows (samples) for training.\n", + "y_test = 30000 corresponding rows (samples) for testing.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|███████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 557.68it/s]\n", + "100%|███████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 994.05it/s]\n", + "100%|██████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 1684.73it/s]\n" + ] + } + ], + "source": [ + "import sys\n", + "sys.path.append(\"../code\") # assuming \"code\" is one directory up and then down into \"code\"\n", + "\n", + "from DemoDataBuilderXandY import generate_dummy_data\n", + "from Netrem_model_builder import netrem, netremCV\n", + "import PriorGraphNetwork as graph\n", + "import error_metrics as em \n", + "import essential_functions as ef\n", + "import netrem_evaluation_functions as nm_eval\n", + "import Netrem_model_builder as nm\n", + "\n", + "dummy_data = generate_dummy_data(corrVals = [0.9, 0.5, 0.3, -0.2, -0.8],\n", + " num_samples_M = 100000,\n", + " train_data_percent = 70)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2b97750a", + "metadata": {}, + "outputs": [], + "source": [ + "# 70 samples for training data (used to train and fit GRegulNet model)\n", + "X_train = dummy_data.view_X_train_df()\n", + "y_train = dummy_data.view_y_train_df()\n", + "\n", + "# 30 samples for testing data\n", + "X_test = dummy_data.view_X_test_df()\n", + "y_test = dummy_data.view_y_test_df()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "69496222", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[['TF1', 'TF2', 0.9],\n", + " ['TF4', 'TF5', 0.75],\n", + " ['TF1', 'TF3'],\n", + " ['TF1', 'TF4'],\n", + " ['TF1', 'TF5'],\n", + " ['TF2', 'TF3'],\n", + " ['TF2', 'TF4'],\n", + " ['TF2', 'TF5'],\n", + " ['TF3', 'TF4'],\n", + " ['TF3', 'TF5']]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# prior network edge_list:\n", + "edge_list = [[\"TF1\", \"TF2\", 0.9], [\"TF4\", \"TF5\", 0.75], [\"TF1\", \"TF3\"], [\"TF1\", \"TF4\"], [\"TF1\", \"TF5\"], \n", + " [\"TF2\", \"TF3\"], [\"TF2\", \"TF4\"], [\"TF2\", \"TF5\"], [\"TF3\", \"TF4\"], [\"TF3\", \"TF5\"]]\n", + "edge_list" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "094a7227", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ":) using variance to define beta_net values\n", + "beta_min = 1.1506396943803596 and beta_max = 115.06396943803597\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "ac3bddb5c58846a68761633cf7b46850", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + ":) Generating beta_net and alpha_lasso pairs: 0%| | 0/50 [00:00#sk-container-id-1 {color: black;background-color: white;}#sk-container-id-1 pre{padding: 0;}#sk-container-id-1 div.sk-toggleable {background-color: white;}#sk-container-id-1 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-1 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-1 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-1 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-1 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-1 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-1 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-1 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-1 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-1 div.sk-item {position: relative;z-index: 1;}#sk-container-id-1 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-1 div.sk-item::before, #sk-container-id-1 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-1 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-1 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-1 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-1 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-1 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-1 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-1 div.sk-label-container {text-align: center;}#sk-container-id-1 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-1 div.sk-text-repr-fallback {display: none;}
NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=1.1506396943803596, alpha_lasso=0.051694590434151706, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x00000202249230A0>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=1.1506396943803596, alpha_lasso=0.051694590434151706, network=)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time \n", + "\n", + "netrem_demoCV = netremCV(edge_list = edge_list, X = X_train, y = y_train) \n", + "netrem_demoCV" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "15723a95", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=1.1506396943803596, alpha_lasso=0.051694590434151706, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x00000202249230A0>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=1.1506396943803596, alpha_lasso=0.051694590434151706, network=)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_demoCV" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "c599f58e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'info': 'NetREm Model',\n", + " 'alpha_lasso': 0.051694590434151706,\n", + " 'beta_net': 1.1506396943803596,\n", + " 'y_intercept': False,\n", + " 'model_type': 'Lasso',\n", + " 'max_lasso_iterations': 10000,\n", + " 'network': ,\n", + " 'verbose': False,\n", + " 'all_pos_coefs': False,\n", + " 'model_info': 'fitted_model :)',\n", + " 'target_gene_y': 'y',\n", + " 'tolerance': 0.0001,\n", + " 'lasso_selection': 'cyclic'}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_demoCV.get_params()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "7ba65d39", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.13727397681026726" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_demoCV.test_mse(X_train, y_train)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "1a9f2f60", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.13781162327050317" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_demoCV.test_mse(X_test, y_test)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "758b4684", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y_interceptTF1TF2TF3TF5
0None0.2777520.0633780.00145-0.159248
\n", + "
" + ], + "text/plain": [ + " y_intercept TF1 TF2 TF3 TF5\n", + "0 None 0.277752 0.063378 0.00145 -0.159248" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_demoCV.model_nonzero_coef_df" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "7afe0c3f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TF1TF2TF3TF4TF5
TF15.4140751.1132610.361368-0.429737-2.771125
TF21.1132611.439763-0.107738-0.125070-0.773506
TF30.361368-0.10773837.921695-0.359079-0.715906
TF4-0.429737-0.125070-0.3590791.1392720.197285
TF5-2.771125-0.773506-0.7159060.1972852.877027
\n", + "
" + ], + "text/plain": [ + " TF1 TF2 TF3 TF4 TF5\n", + "TF1 5.414075 1.113261 0.361368 -0.429737 -2.771125\n", + "TF2 1.113261 1.439763 -0.107738 -0.125070 -0.773506\n", + "TF3 0.361368 -0.107738 37.921695 -0.359079 -0.715906\n", + "TF4 -0.429737 -0.125070 -0.359079 1.139272 0.197285\n", + "TF5 -2.771125 -0.773506 -0.715906 0.197285 2.877027" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_demoCV.B_interaction_df" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "64bd24b1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TF1TF2B_train_weightsignpotential_interactionabsVal_Binfocandidate_TFs_Ntarget_gene_ynum_final_predictorsmodel_typebeta_netgene_datarankpercentile
20TF1TF5-2.771125:(:( competitive (-)2.771125B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data1.095.0
4TF5TF1-2.771125:(:( competitive (-)2.771125B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data1.095.0
5TF1TF21.113261:):(1.113261B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data3.085.0
1TF2TF11.113261:):(1.113261B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data3.085.0
9TF5TF2-0.773506:(:( competitive (-)0.773506B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data5.075.0
21TF2TF5-0.773506:(:( competitive (-)0.773506B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data5.075.0
14TF5TF3-0.715906:(:( competitive (-)0.715906B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data7.065.0
22TF3TF5-0.715906:(:( competitive (-)0.715906B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data7.065.0
15TF1TF4-0.429737:(:( competitive (-)0.429737B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data9.055.0
3TF4TF1-0.429737:(:( competitive (-)0.429737B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data9.055.0
2TF3TF10.361368:):(0.361368B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data11.045.0
10TF1TF30.361368:):(0.361368B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data11.045.0
13TF4TF3-0.359079:(:( competitive (-)0.359079B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data13.035.0
17TF3TF4-0.359079:(:( competitive (-)0.359079B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data13.035.0
19TF5TF40.197285:):(0.197285B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data15.025.0
23TF4TF50.197285:):(0.197285B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data15.025.0
8TF4TF2-0.125070:(:( competitive (-)0.125070B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data17.015.0
16TF2TF4-0.125070:(:( competitive (-)0.125070B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data17.015.0
7TF3TF2-0.107738:(:( competitive (-)0.107738B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data19.05.0
11TF2TF3-0.107738:(:( competitive (-)0.107738B matrix of TF-TF interactions5y4Lasso1.15064training gene expression data19.05.0
\n", + "
" + ], + "text/plain": [ + " TF1 TF2 B_train_weight sign potential_interaction absVal_B \\\n", + "20 TF1 TF5 -2.771125 :( :( competitive (-) 2.771125 \n", + "4 TF5 TF1 -2.771125 :( :( competitive (-) 2.771125 \n", + "5 TF1 TF2 1.113261 :) :( 1.113261 \n", + "1 TF2 TF1 1.113261 :) :( 1.113261 \n", + "9 TF5 TF2 -0.773506 :( :( competitive (-) 0.773506 \n", + "21 TF2 TF5 -0.773506 :( :( competitive (-) 0.773506 \n", + "14 TF5 TF3 -0.715906 :( :( competitive (-) 0.715906 \n", + "22 TF3 TF5 -0.715906 :( :( competitive (-) 0.715906 \n", + "15 TF1 TF4 -0.429737 :( :( competitive (-) 0.429737 \n", + "3 TF4 TF1 -0.429737 :( :( competitive (-) 0.429737 \n", + "2 TF3 TF1 0.361368 :) :( 0.361368 \n", + "10 TF1 TF3 0.361368 :) :( 0.361368 \n", + "13 TF4 TF3 -0.359079 :( :( competitive (-) 0.359079 \n", + "17 TF3 TF4 -0.359079 :( :( competitive (-) 0.359079 \n", + "19 TF5 TF4 0.197285 :) :( 0.197285 \n", + "23 TF4 TF5 0.197285 :) :( 0.197285 \n", + "8 TF4 TF2 -0.125070 :( :( competitive (-) 0.125070 \n", + "16 TF2 TF4 -0.125070 :( :( competitive (-) 0.125070 \n", + "7 TF3 TF2 -0.107738 :( :( competitive (-) 0.107738 \n", + "11 TF2 TF3 -0.107738 :( :( competitive (-) 0.107738 \n", + "\n", + " info candidate_TFs_N target_gene_y \\\n", + "20 B matrix of TF-TF interactions 5 y \n", + "4 B matrix of TF-TF interactions 5 y \n", + "5 B matrix of TF-TF interactions 5 y \n", + "1 B matrix of TF-TF interactions 5 y \n", + "9 B matrix of TF-TF interactions 5 y \n", + "21 B matrix of TF-TF interactions 5 y \n", + "14 B matrix of TF-TF interactions 5 y \n", + "22 B matrix of TF-TF interactions 5 y \n", + "15 B matrix of TF-TF interactions 5 y \n", + "3 B matrix of TF-TF interactions 5 y \n", + "2 B matrix of TF-TF interactions 5 y \n", + "10 B matrix of TF-TF interactions 5 y \n", + "13 B matrix of TF-TF interactions 5 y \n", + "17 B matrix of TF-TF interactions 5 y \n", + "19 B matrix of TF-TF interactions 5 y \n", + "23 B matrix of TF-TF interactions 5 y \n", + "8 B matrix of TF-TF interactions 5 y \n", + "16 B matrix of TF-TF interactions 5 y \n", + "7 B matrix of TF-TF interactions 5 y \n", + "11 B matrix of TF-TF interactions 5 y \n", + "\n", + " num_final_predictors model_type beta_net gene_data \\\n", + "20 4 Lasso 1.15064 training gene expression data \n", + "4 4 Lasso 1.15064 training gene expression data \n", + "5 4 Lasso 1.15064 training gene expression data \n", + "1 4 Lasso 1.15064 training gene expression data \n", + "9 4 Lasso 1.15064 training gene expression data \n", + "21 4 Lasso 1.15064 training gene expression data \n", + "14 4 Lasso 1.15064 training gene expression data \n", + "22 4 Lasso 1.15064 training gene expression data \n", + "15 4 Lasso 1.15064 training gene expression data \n", + "3 4 Lasso 1.15064 training gene expression data \n", + "2 4 Lasso 1.15064 training gene expression data \n", + "10 4 Lasso 1.15064 training gene expression data \n", + "13 4 Lasso 1.15064 training gene expression data \n", + "17 4 Lasso 1.15064 training gene expression data \n", + "19 4 Lasso 1.15064 training gene expression data \n", + "23 4 Lasso 1.15064 training gene expression data \n", + "8 4 Lasso 1.15064 training gene expression data \n", + "16 4 Lasso 1.15064 training gene expression data \n", + "7 4 Lasso 1.15064 training gene expression data \n", + "11 4 Lasso 1.15064 training gene expression data \n", + "\n", + " rank percentile \n", + "20 1.0 95.0 \n", + "4 1.0 95.0 \n", + "5 3.0 85.0 \n", + "1 3.0 85.0 \n", + "9 5.0 75.0 \n", + "21 5.0 75.0 \n", + "14 7.0 65.0 \n", + "22 7.0 65.0 \n", + "15 9.0 55.0 \n", + "3 9.0 55.0 \n", + "2 11.0 45.0 \n", + "10 11.0 45.0 \n", + "13 13.0 35.0 \n", + "17 13.0 35.0 \n", + "19 15.0 25.0 \n", + "23 15.0 25.0 \n", + "8 17.0 15.0 \n", + "16 17.0 15.0 \n", + "7 19.0 5.0 \n", + "11 19.0 5.0 " + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b_matrix = nm.organize_B_interaction_network(netrem_demoCV)\n", + "b_matrix" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "b5ca8aca", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/code/old_code/refresh/netrem_evaluation_functions.py b/code/old_code/refresh/netrem_evaluation_functions.py new file mode 100644 index 0000000..b99b41d --- /dev/null +++ b/code/old_code/refresh/netrem_evaluation_functions.py @@ -0,0 +1,594 @@ +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +import random +import copy +from tqdm import tqdm +import os +import sys # https://www.dev2qa.com/how-to-run-python-script-py-file-in-jupyter-notebook-ipynb-file-and-ipython/#:~:text=How%20To%20Run%20Python%20Script%20.py%20File%20In,2.%20Invoke%20Python%20Script%20File%20From%20Ipython%20Command-Line. +import networkx as nx +import scipy +from scipy.linalg import svd as robust_svd +from sklearn.model_selection import KFold, train_test_split, GridSearchCV, RandomizedSearchCV, cross_val_score +from sklearn.decomposition import TruncatedSVD +from sklearn import linear_model +from sklearn.linear_model import Lasso, LassoCV, LinearRegression, ElasticNetCV, Ridge +from numpy.typing import ArrayLike +from typing import Optional, List, Tuple +from sklearn.metrics import make_scorer +import plotly.express as px +from sklearn.base import RegressorMixin, ClassifierMixin, BaseEstimator +from numpy.typing import ArrayLike +from skopt import gp_minimize, space +from scipy.sparse.linalg.interface import LinearOperator +import warnings +from sklearn.exceptions import ConvergenceWarning +printdf = lambda *args, **kwargs: print(pd.DataFrame(*args, **kwargs)) +rng_seed = 2023 # random seed for reproducibility +randSeed = 123 +# from packages_needed import * +from error_metrics import * +from DemoDataBuilderXandY import * +from PriorGraphNetwork import * +from Netrem_model_builder import * +from sklearn.linear_model import ElasticNetCV, LinearRegression, LassoCV, RidgeCV +from skopt import gp_minimize, space +from skopt.utils import use_named_args + +class BayesianObjective_Lasso: + def __init__(self, X, y, cv_folds, model, scorer="mse", print_network=False): + self.X = X + self.y = y + self.cv_folds = cv_folds + model.view_network = print_network + self.model = model + self.scorer_obj = 'neg_mean_squared_error' # the default + if scorer == "mse": + self.scorer_obj = em.mse_custom_scorer + elif scorer == "nmse": + self.scorer_obj = em.nmse_custom_scorer + elif scorer == "snr": + self.scorer_obj = em.snr_custom_scorer + elif scorer == "psnr": + self.scorer_obj = em.psnr_custom_scorer + + def __call__(self, params): + try: + alpha_lasso, beta_network = params + # print(f"Testing with alpha_lasso = {alpha_lasso}, beta_network = {beta_network}") + + netrem_model = self.model + #print(netrem_model.get_params()) + netrem_model.alpha_lasso = alpha_lasso + netrem_model.beta_network = beta_network + + cv_scores = cross_val_score(netrem_model, self.X, self.y, cv=self.cv_folds, scoring=self.scorer_obj) + + # Check for infinite values + if np.any(np.isinf(cv_scores)): + # print("Cross-validation scores contain infinite values.") + #return np.inf + return 1e100 # Replace infinite score with large finite value + + # Debugging: Print the individual cross-validation scores + # print(f"Individual cross-validation scores: {cv_scores}") + + score = -cv_scores.mean() + # print(f"Score with alpha_lasso = {alpha_lasso}, beta_network = {beta_network} is {score}") + + #if np.isinf(score): + #print("Score is infinite!") + + return score + + except Exception as e: + #print(f"An exception occurred: {e}") + #return np.inf # Return a high "bad" value to indicate failure + return 1e100 # Replace infinite score with large finite value + + +# Define a callback function to update the progress bar +def progress_bar_callback(res): + progress_bar.update(1) + +def optimal_netrem_model_via_bayesian_param_tuner(netrem_model, X_train, y_train, + beta_net_min = 0.5, + beta_net_max = 1000, + alpha_lasso_min = 0.0001, + alpha_lasso_max = 0.1, + num_grid_values = 100, + cv_folds = 5, + scorer = "mse", + verbose = False): + + print(":) Please note that we are running: optimal_netrem_model_via_bayesian_param_tuner") + if verbose: + print(f":) Please note we are running Bayesian optimization (via skopt Python package) for parameter hunting for beta_network and alpha_lasso with model evaluation scorer: {scorer} :)") + print("we use gp_minimize here for hyperparameter tuning") + print(f":) Please note this is a start-to-finish optimizer for NetREm (Network regression embeddings reveal cell-type protein-protein interactions for gene regulation)") + + + model_type = netrem_model.model_type + if model_type == "LassoCV": + print("please note that we can only do this for Lasso model not for LassoCV :(") + print("Thus, we will alter the model_type to make it Lasso") + netrem_model.model_type = "Lasso" + + param_space = [space.Real(alpha_lasso_min, alpha_lasso_max, name='alpha_lasso', prior='log-uniform'), + space.Real(beta_net_min, beta_net_max, name='beta_network', prior='log-uniform')] + objective = BayesianObjective_Lasso(X_train, y_train, cv_folds = cv_folds, model = netrem_model, scorer = scorer) + + + # Perform Bayesian optimization + result = gp_minimize(objective, param_space, n_calls=num_grid_values, random_state=123) + + results_dict = {} + optimal_model = netrem_model + if verbose: + print(":) ######################################################################\n") + print(f":) Please note the optimal model based on Bayesian optimization found: ") + + bayesian_alpha = result.x[0] + bayesian_beta = result.x[1] + optimal_model.alpha_lasso = bayesian_alpha + optimal_model.beta_network = bayesian_beta + results_dict["bayesian_alpha"] = bayesian_alpha + print(f"alpha_lasso = {bayesian_alpha} ; beta_network = {bayesian_beta}") + if verbose: + print(":) ######################################################################\n") + print("Fitting the model using these optimal hyperparameters for beta_net and alpha_lasso...") + dict_ex = optimal_model.get_params() + optimal_model = nm.NetREmModel(**dict_ex) + optimal_model.fit(X_train, y_train) + print(optimal_model.get_params()) + results_dict["optimal_model"] = optimal_model + results_dict["bayesian_beta"] = bayesian_beta + results_dict["bayesian_alpha"] = bayesian_alpha + results_dict["result"] = result + return results_dict + +# class BayesianObjective_Lasso: +# def __init__(self, X, y, cv_folds, model, scorer = "mse", print_network = False): +# self.X = X +# self.y = y +# self.cv_folds = cv_folds +# model.view_network = print_network +# self.model = model +# self.scorer_obj = 'neg_mean_squared_error' # the default +# if scorer == "mse": +# self.scorer_obj = mse_custom_scorer +# elif scorer == "nmse": +# self.scorer_obj = nmse_custom_scorer +# elif scorer == "snr": +# self.scorer_obj = snr_custom_scorer +# elif scorer == "psnr": +# self.scorer_obj = psnr_custom_scorer + + +# def __call__(self, params): + +# alpha_lasso, beta_network = params +# #network = PriorGraphNetwork(edge_list = edge_list) +# netrem_model = self.model +# #print(netrem_model.get_params()) +# netrem_model.alpha_lasso = alpha_lasso +# netrem_model.beta_network = beta_network +# #netrem_model.view_network = self.view_network +# score = -cross_val_score(netrem_model, self.X, self.y, cv=self.cv_folds, scoring=self.scorer_obj).mean() +# return score + + +# def optimal_netrem_model_via_bayesian_param_tuner(netrem_model, X_train, y_train, +# beta_net_min = 0.001, +# beta_net_max = 10, +# alpha_lasso_min = 0.0001, +# alpha_lasso_max = 0.1, +# num_grid_values = 100, +# gridSearchCV_folds = 5, +# scorer = "mse", +# verbose = False): +# if verbose: +# print(f":) Please note we are running Bayesian optimization (via skopt Python package) for parameter hunting for beta_network and alpha_lasso with model evaluation scorer: {scorer} :)") +# print("we use gp_minimize here for hyperparameter tuning") +# print(f":) Please note this is a start-to-finish optimizer for NetREm (Network regression embeddings reveal cell-type protein-protein interactions for gene regulation)") +# from skopt import gp_minimize, space +# model_type = netrem_model.model_type +# # param_space = [space.Real(alpha_lasso_min, alpha_lasso_max, name='alpha_lasso', prior='log-uniform'), +# # space.Real(beta_net_min, beta_net_max, name='beta_network', prior='log-uniform')] + +# if model_type == "LassoCV": +# print("please note that we can only do this for Lasso model not for LassoCV :(") +# print("Thus, we will alter the model_type to make it Lasso") +# netrem_model.model_type = "Lasso" + +# param_space = [space.Real(alpha_lasso_min, alpha_lasso_max, name='alpha_lasso', prior='log-uniform'), +# space.Real(beta_net_min, beta_net_max, name='beta_network', prior='log-uniform')] +# objective = BayesianObjective_Lasso(X_train, y_train, cv_folds = gridSearchCV_folds, model = netrem_model, scorer = scorer) + +# # Perform Bayesian optimization +# result = gp_minimize(objective, param_space, n_calls=num_grid_values, random_state=123) +# results_dict = {} +# optimal_model = netrem_model +# if verbose: +# print(":) ######################################################################\n") +# print(f":) Please note the optimal model based on Bayesian optimization found: ") + +# bayesian_alpha = result.x[0] +# bayesian_beta = result.x[1] +# optimal_model.alpha_lasso = bayesian_alpha +# optimal_model.beta_network = bayesian_beta +# results_dict["bayesian_alpha"] = bayesian_alpha +# print(f"alpha_lasso = {bayesian_alpha} ; beta_network = {bayesian_beta}") +# if verbose: +# print(":) ######################################################################\n") +# print("Fitting the model using these optimal hyperparameters for beta_net and alpha_lasso...") +# dict_ex = optimal_model.get_params() +# optimal_model = NetREmModel(**dict_ex) +# optimal_model.fit(X_train, y_train) +# print(optimal_model.get_params()) +# results_dict["optimal_model"] = optimal_model +# results_dict["bayesian_beta"] = bayesian_beta +# results_dict["result"] = result +# return results_dict + + +def optimal_netrem_model_via_gridsearchCV_param_tuner(netrem_model, X_train, y_train, num_grid_values, num_cv_jobs = -1): + beta_max = 0.5 * np.max(np.abs(X_train.T.dot(y_train))) + beta_min = 0.01 * beta_max + beta_grid = np.logspace(np.log10(beta_max), np.log10(beta_min), num=num_grid_values) + import copy + alpha_grid = [] + initial_gregCV = netrem_model + original_dict = copy.deepcopy(netrem_model.get_params()) + original_model = NetREmModel(**netrem_model.get_params()) + initial_gregCV.model_type = "LassoCV" + #print(initial_gregCV.get_params()) + for beta in beta_grid: + gregCV_demo = initial_gregCV + gregCV_demo.beta_network = beta + gregCV_demo.fit(X_train, y_train) + optimal_alpha = gregCV_demo.regr.alpha_ + alpha_grid.append(optimal_alpha) + + beta_alpha_grid_dict = {} + beta_alpha_grid_dict["beta_network_vals"] = beta_grid + beta_alpha_grid_dict["alpha_lasso_vals"] = alpha_grid #np.array(alpha_grid) + param_grid = [] + for i in tqdm(range(0, len(beta_alpha_grid_dict["beta_network_vals"]))): + beta_net = beta_alpha_grid_dict["beta_network_vals"][i] + alpha_las = beta_alpha_grid_dict["alpha_lasso_vals"][i] + param_grid.append({"alpha_lasso": [alpha_las], "beta_network": [beta_net]}) + grid_search = GridSearchCV(original_model, param_grid = param_grid, cv=gridSearchCV_folds, + n_jobs = num_cv_jobs, scoring='neg_mean_squared_error') + grid_search.fit(X_train, y_train) + # Get the best hyperparameters + best_params = grid_search.best_params_ + optimal_alpha = best_params["alpha_lasso"] + optimal_beta = best_params["beta_network"] + if isinstance(optimal_alpha, np.ndarray): + optimal_alpha = optimal_alpha[0] + if isinstance(optimal_beta, np.ndarray): + optimal_beta = optimal_beta[0] + print(f":) NetREmModelCV found that the optimal alpha_lasso = {optimal_alpha} and optimal beta_network = {optimal_beta}") + update_NetREmModel = NetREmModel(**original_dict) + update_NetREmModel.beta_network = optimal_beta + update_NetREmModel.alpha_lasso = optimal_alpha + update_NetREmModel = NetREmModel(**update_NetREmModel.get_params()) + update_NetREmModel.fit(X_train, y_train) + return update_NetREmModel + + +def model_comparison_metrics_for_target_gene_with_BayesianOpt_andOr_GridSearchCV_ForNetREm(gene_num, target_genes_list, + X_train_all, X_test_all, y_train_all, y_test_all, + scgrnom_step2_df, tfs, expression_percentile, tf_df, + js_mini, ppi_edge_list, num_tfs_family, gene_expression_genes, tf_name = "SOX10", + beta_net_min = 0.001, + beta_net_max = 10, + alpha_lasso_min = 0.0001, + alpha_lasso_max = 0.1, + num_grid_values = 100, + gridSearchCV_folds = 5, + scorer = "mse", view_network = False, verbose = False, num_cv_jobs = -1): + + focus_gene = target_genes_list[gene_num] # here, this is tough 9, 10 + print(f"Please note that our focus gene (Target gene (TG) y) is: {focus_gene}") + + y_train = y_train_all[[focus_gene]] + y_test = y_test_all[[focus_gene]] + + tfs_for_tg = scgrnom_step2_df[scgrnom_step2_df["TG"] == focus_gene]["TF"].tolist() + tfs_for_tg.sort() + + tfs_for_tg = intersection(tfs_for_tg, tfs) + len(tfs_for_tg) + + low_TFs_bool = False + if len(tfs_for_tg) < 5: + print(":( uh-oh!") + low_TFs_bool = True + if verbose: + print(len(tfs_for_use)) + # adding genes from the same family to the set of TFs (based on co-binding from Step 2) + tf_families_to_add = list(set(tf_df[tf_df["gene"].isin(tfs_for_tg)]["TF_Family"])) + gene_expression_avg = np.mean(X_train_all, axis=0) + + expression_threshold = np.percentile(gene_expression_avg, expression_percentile) + if verbose: + print(f":) Please note that based on the training X data, we find that the {expression_percentile}%ile average gene expression level is: {expression_threshold}") #expression_threshold + gene_expression_avg_df = pd.DataFrame(gene_expression_avg, columns = ["avg_expression"]) + gene_expression_avg_df["gene"] = gene_expression_avg_df.index + genes_above_threshold_df = gene_expression_avg_df[gene_expression_avg_df["avg_expression"] >= expression_threshold] + info_tf_family_expression_df = pd.merge(tf_df, gene_expression_avg_df, how = "inner") + info_tf_family_expression_df = info_tf_family_expression_df.sort_values(by = ["avg_expression"], ascending = False) + info_tf_family_expression_df = info_tf_family_expression_df.sort_values(by = ["TF_Family"]) + mini_info_tf_family_express_df = info_tf_family_expression_df[info_tf_family_expression_df["TF_Family"].isin(tf_families_to_add)] + # sort dataframe by 'TF_Family' and 'avg_expression' in descending order + df_sorted = mini_info_tf_family_express_df.sort_values(['TF_Family', 'avg_expression'], ascending=False) + # select the row with the highest 'avg_expression' for each 'TF_Family' + df_result = df_sorted.groupby('TF_Family').first().reset_index() + + ######################################################################## + df_sorty = info_tf_family_expression_df[info_tf_family_expression_df["gene"].isin(genes_above_threshold_df["gene"].tolist())] + # sort dataframe by 'TF_Family' and 'avg_expression' in descending order + df_sorted1 = df_sorty.sort_values(['TF_Family', 'avg_expression'], ascending=False) + # select the top 2 rows for each 'TF_Family' + if low_TFs_bool: + num_to_use_TFs = num_tfs_family + 1 + df_result1 = df_sorted1.groupby('TF_Family').head(n=num_to_use_TFs).reset_index(drop=True) + else: + df_result1 = df_sorted1.groupby('TF_Family').head(n=num_tfs_family).reset_index(drop=True) + if verbose: + print(df_result1) + tfs_to_use_list = df_result["gene"].tolist() + tfs_to_use_list.sort() + if verbose: + print(f" :) tfs_to_use_list = {tfs_to_use_list}") + + tfs_for_use = list(set(tfs_to_use_list + df_result1["gene"].tolist())) + tfs_for_use.sort() + + ########################################################################## + js_minier = js_mini[js_mini["TF1"].isin(tfs_for_use)] + js_minier = js_minier[js_minier["TF2"].isin(tfs_for_use)] + + # for each tf from scgrnom step 2, we add the top 3 TFs based on the cobind matrix + tfs_added_list = [] + for i in tqdm(range(0, len(tfs_to_use_list))): + tf_num = i#in tfs_for_tg: + if low_TFs_bool: + tfs_added_list += js_minier[js_minier["TF1"] == tfs_to_use_list[tf_num]].head(9)["TF2"].tolist() + else: + tfs_added_list += js_minier[js_minier["TF1"] == tfs_to_use_list[tf_num]].head(3)["TF2"].tolist() + + tfs_added_list.sort() + + + #################################### + if verbose: + print(len(tfs_added_list)) + print(tfs_added_list) + combo_tfs = list(set(tfs_to_use_list+tfs_added_list)) + if verbose: + print(len(combo_tfs)) + print(combo_tfs) + tf_columns = intersection(combo_tfs, gene_expression_genes) + tf_columns = list(set(tf_columns)) + tf_columns.sort() + if verbose: + print(":) # of TFs: ", len(tf_columns)) + print(tf_columns) + + if focus_gene in tf_columns: + tf_columns.remove(focus_gene) + key_genes = tf_columns + + ######################### :) We are filtering the input PPI matrix based on the + # final TFs (key_genes) to help us save time: + filtered_ppi_edge_list = [] + for edge in ppi_edge_list: + if edge[0] in key_genes and edge[1] in key_genes: + filtered_ppi_edge_list.append(edge) + + if verbose: + print(filtered_ppi_edge_list) + + X_train = X_train_all[tf_columns] + X_test = X_test_all[tf_columns] + if verbose: + print("X_train dimensions: ", X_train.shape) + print("X_test dimensions: ", X_test.shape) + + netrem_no_intercept = netrem(edge_list = filtered_ppi_edge_list, + gene_expression_nodes = key_genes, + verbose = verbose, + view_network = view_network) + + netrem_with_intercept = netrem(edge_list = filtered_ppi_edge_list, + y_intercept = True, + verbose = verbose, + gene_expression_nodes = key_genes, + view_network = view_network) + + model_comparison_df1 = pd.DataFrame() + model_comparison_df2 = pd.DataFrame() + bayes_optimizer_bool = False + griddy_optimizer_bool = False + + ##################################################################################### + no_intercept = False + with_intercept = False + try: + optimal_netrem_no_intercept = optimal_netrem_model_via_bayesian_param_tuner(netrem_no_intercept, X_train, y_train, + beta_net_min, + beta_net_max, + alpha_lasso_min, + alpha_lasso_max, + num_grid_values, + gridSearchCV_folds, + scorer, + verbose) + #optimal_netrem_no_intercept = optimal_netrem_model_via_bayesian_param_tuner(netrem_no_intercept, X_train, y_train, verbose = verbose) + optimal_netrem_no_intercept = optimal_netrem_no_intercept["optimal_model"] + no_intercept = True + except: + print(":( Bayesian optimizer is not working for no y-intercept") + optimal_netrem_no_intercept = None + + try: + optimal_netrem_with_intercept = optimal_netrem_model_via_bayesian_param_tuner(netrem_with_intercept, X_train, y_train, + beta_net_min, + beta_net_max, + alpha_lasso_min, + alpha_lasso_max, + num_grid_values, + gridSearchCV_folds, + scorer, + verbose) + + optimal_netrem_with_intercept = optimal_netrem_with_intercept["optimal_model"] + with_intercept = True + + except: + print(":( Bayesian optimizer is not working for y-intercept") + optimal_netrem_with_intercept = None + + if no_intercept or with_intercept: + model_comparison_df1 = metrics_for_netrem_models_versus_other_models(netrem_with_intercept = optimal_netrem_with_intercept, netrem_no_intercept = optimal_netrem_no_intercept, + X_train = X_train, y_train = y_train, + X_test = X_test, y_test = y_test, filtered_results = False, + tf_name = tf_name, target_gene = focus_gene) + model_comparison_df1["approach"] = "bayes_optimizer" + bayes_optimizer_bool = True + + ##################################################################################### + no_intercept = False + with_intercept = False + try: + griddy_netrem_no_intercept = optimal_netrem_model_via_gridsearchCV_param_tuner(netrem_no_intercept, X_train, y_train, + num_grid_values, num_cv_jobs) + + no_intercept = True + except: + print(":( gridsearchCV is not working for no y-intercept") + griddy_netrem_no_intercept = None + + try: + griddy_netrem_with_intercept = optimal_netrem_model_via_gridsearchCV_param_tuner(netrem_with_intercept, X_train, y_train, + num_grid_values, num_cv_jobs) + with_intercept = True + except: + print(":( gridsearchCV is not working for y-intercept") + griddy_netrem_with_intercept = None + + if no_intercept or with_intercept: + model_comparison_df2 = metrics_for_netrem_models_versus_other_models(netrem_with_intercept = griddy_netrem_with_intercept, netrem_no_intercept = griddy_netrem_no_intercept, + X_train = X_train, y_train = y_train, + X_test = X_test, y_test = y_test, filtered_results = False, + tf_name = tf_name, target_gene = focus_gene) + + model_comparison_df2["approach"] = "gridSearchCV" + griddy_optimizer_bool = True + # except: + # print(":( gridsearchCV optimizer is not working") + both_approaches_bool = False + if bayes_optimizer_bool and griddy_optimizer_bool: + combined_model_compare_df = pd.concat([model_comparison_df1, model_comparison_df2]) + both_approaches_bool = True + elif bayes_optimizer_bool: + combined_model_compare_df = pd.concat([model_comparison_df1]) + else: + combined_model_compare_df = pd.concat([model_comparison_df2]) + + if both_approaches_bool: + res3 = combined_model_compare_df + res3["combo_key"] = res3["Info"] + "_" + res3["y_intercept"] + "_" + res3["Rank"].astype(str) + "_" + res3["num_TFs"].astype(str) + # Count the number of occurrences of each combo_key + combo_key_counts = res3.groupby('combo_key').size() + + # Create a boolean mask for the combo_keys that appear more than once + combo_key_mask = combo_key_counts > 1 + + # Update the approach column for the combo_keys that appear more than once + res3.loc[res3['combo_key'].isin(combo_key_counts[combo_key_mask].index), 'approach'] = 'both' + aaa = res3 + + aaa['rank_mse_train'] = aaa['train_mse'].rank(ascending=True).astype(int) + aaa['rank_mse_test'] = aaa['test_mse'].rank(ascending=True).astype(int) + aaa['rank_nmse_train'] = aaa['train_nmse'].rank(ascending=True).astype(int) + aaa['rank_nmse_test'] = aaa['test_nmse'].rank(ascending=True).astype(int) + + aaa['rank_snr_train'] = aaa['train_snr'].rank(ascending=False).astype(int) + aaa['rank_snr_test'] = aaa['test_snr'].rank(ascending=False).astype(int) + aaa['rank_psnr_train'] = aaa['train_psnr'].rank(ascending=False).astype(int) + aaa['rank_psnr_test'] = aaa['test_psnr'].rank(ascending=False).astype(int) + aaa["total_metrics_rank"] = aaa['rank_mse_train'] + aaa['rank_mse_test'] + aaa['rank_nmse_train'] + aaa['rank_nmse_test'] + aaa["total_metrics_rank"] += aaa['rank_snr_train'] + aaa['rank_snr_test'] + aaa['rank_psnr_train'] + aaa['rank_psnr_test'] + aaa = aaa.drop_duplicates() + combined_model_compare_df = aaa + combined_model_compare_df = combined_model_compare_df.drop(columns = ["combo_key"]) + return combined_model_compare_df + + +def baseline_metrics_function(X_train, y_train, X_test, y_test, tg, model_name, y_intercept, verbose = False): + + if verbose: + print(f"{model_name} results :) for fitting y_intercept = {y_intercept}") + try: + if model_name == "ElasticNetCV": + regr = ElasticNetCV(cv=5, random_state=0, fit_intercept = y_intercept) + elif model_name == "LinearRegression": + regr = LinearRegression(fit_intercept = y_intercept) + elif model_name == "LassoCV": + regr = LassoCV(cv=5, fit_intercept = y_intercept) + elif model_name == "RidgeCV": + regr = RidgeCV(cv=5, fit_intercept = y_intercept) + regr.fit(X_train, y_train) + if model_name in ["RidgeCV", "LinearRegression"]: + model_df = pd.DataFrame(regr.coef_) + else: + model_df = pd.DataFrame(regr.coef_).transpose() + if verbose: + print(model_df) + model_df.columns = X_train.columns.tolist() + selected_row = model_df.iloc[0] + selected_cols = selected_row[selected_row != 0].index # Filter out the columns with value 0 + model_df = model_df[selected_cols] + df = model_df.replace("None", np.nan).apply(pd.to_numeric, errors='coerce') + sorted_series = df.abs().squeeze().sort_values(ascending=False) + # convert the sorted series back to a DataFrame + sorted_df = pd.DataFrame(sorted_series) + # add a column for the rank + sorted_df['Rank'] = range(1, len(sorted_df) + 1) + sorted_df['TF'] = sorted_df.index + sorted_df = sorted_df.rename(columns = {0:"AbsoluteVal_coefficient"}) + # tfs = sorted_df["TF"].tolist() + # if tf_name not in tfs: + # sorted_df = pd.DataFrame(["N/A", tf_name]).transpose() + # sorted_df.columns = ["Rank", "TF"] + sorted_df["Info"] = model_name + if y_intercept: + sorted_df["y_intercept"] = "True :)" + else: + sorted_df["y_intercept"] = "False :(" + sorted_df["final_model_TFs"] = model_df.shape[1] + sorted_df["TFs_input_to_model"] = X_train.shape[1] + sorted_df["original_TFs_in_X"] = X_train.shape[1] + + predY_train = regr.predict(X_train) + predY_test = regr.predict(X_test) + train_mse = em.mse(y_train.values.flatten(), predY_train) + test_mse = em.mse(y_test.values.flatten(), predY_test) + sorted_df["train_mse"] = train_mse + sorted_df["test_mse"] = test_mse + sorted_df["train_nmse"] = em.nmse(y_train.values.flatten(), predY_train) + sorted_df["test_nmse"] = em.nmse(y_test.values.flatten(), predY_test) + sorted_df["train_snr"] = em.snr(y_train.values.flatten(), predY_train) + sorted_df["test_snr"] = em.snr(y_test.values.flatten(), predY_test) + sorted_df["train_psnr"] = em.psnr(y_train.values.flatten(), predY_train) + sorted_df["test_psnr"] = em.psnr(y_test.values.flatten(), predY_test) + sorted_df["TG"] = tg + sorted_df = sorted_df.reset_index().drop(columns = ["index"]) + sorted_df + except: + return pd.DataFrame() + return sorted_df \ No newline at end of file diff --git a/code/old_code/refresh/packages_needed.py b/code/old_code/refresh/packages_needed.py new file mode 100644 index 0000000..b4d319e --- /dev/null +++ b/code/old_code/refresh/packages_needed.py @@ -0,0 +1,38 @@ +import pandas as pd +import numpy as np +import random +import copy +from tqdm import tqdm +import os +import sys # https://www.dev2qa.com/how-to-run-python-script-py-file-in-jupyter-notebook-ipynb-file-and-ipython/#:~:text=How%20To%20Run%20Python%20Script%20.py%20File%20In,2.%20Invoke%20Python%20Script%20File%20From%20Ipython%20Command-Line. +import networkx as nx +import scipy +from scipy.linalg import svd as robust_svd +from sklearn.model_selection import KFold, train_test_split, GridSearchCV, cross_val_score +from sklearn.decomposition import TruncatedSVD +from sklearn import linear_model +from sklearn.linear_model import Lasso, LassoCV, LinearRegression, ElasticNetCV, Ridge +from numpy.typing import ArrayLike +from skopt import gp_minimize, space +from typing import Optional, List, Tuple +from sklearn.metrics import make_scorer +import plotly.express as px +from sklearn.base import RegressorMixin, ClassifierMixin, BaseEstimator +import matplotlib.pyplot as plt +from numpy.typing import ArrayLike +from scipy.sparse.linalg.interface import LinearOperator +import warnings +from sklearn.exceptions import ConvergenceWarning +printdf = lambda *args, **kwargs: print(pd.DataFrame(*args, **kwargs)) +rng_seed = 2023 # random seed for reproducibility +randSeed = 123 + + +""" +Optimization for +(1 / (2 * M)) * ||y - Xc||^2_2 + (beta / (2 * N^2)) * c'Ac + alpha * ||c||_1 +Which is converted to lasso +(1 / (2 * M)) * ||y_tilde - X_tilde @ c||^2_2 + alpha * ||c||_1 +where M = n_samples and N is the dimension of c. +Check compute_X_tilde_y_tilde() to see how we make sure above normalization is applied using Lasso of sklearn +""" \ No newline at end of file diff --git a/netrem_final_demo.png b/netrem_final_demo.png index 68f5136..2466627 100644 Binary files a/netrem_final_demo.png and b/netrem_final_demo.png differ diff --git a/netrem_gexpr_demo.png b/netrem_gexpr_demo.png index cbf20f4..b00c556 100644 Binary files a/netrem_gexpr_demo.png and b/netrem_gexpr_demo.png differ diff --git a/netrem_pipeline.PNG b/netrem_pipeline.PNG index dbb4328..add34f4 100644 Binary files a/netrem_pipeline.PNG and b/netrem_pipeline.PNG differ diff --git a/output_3_1.png b/output_3_1.png index e3be997..d92f453 100644 Binary files a/output_3_1.png and b/output_3_1.png differ diff --git a/output_3_2.png b/output_3_2.png deleted file mode 100644 index 19c0da7..0000000 Binary files a/output_3_2.png and /dev/null differ diff --git a/output_3_5.png b/output_3_5.png deleted file mode 100644 index 8bb31f1..0000000 Binary files a/output_3_5.png and /dev/null differ diff --git a/user_guide/Dummy_Data_Demo_Example.pdf b/user_guide/Dummy_Data_Demo_Example.pdf new file mode 100644 index 0000000..46a2e57 Binary files /dev/null and b/user_guide/Dummy_Data_Demo_Example.pdf differ diff --git a/user_guide/netremCV.ipynb b/user_guide/netremCV.ipynb index 849d1cc..434c3c9 100644 --- a/user_guide/netremCV.ipynb +++ b/user_guide/netremCV.ipynb @@ -6,11 +6,46 @@ "metadata": {}, "source": [ "# netremCV\n", - "Cross-validation approach for estimating the optimal $\\beta_{net}$ and $\\alpha_{lasso}$.\n", + "## By: Saniya Khullar\n", + "Cross-validation approach for estimating the optimal $\\beta_{net}$ and $\\alpha_{lasso}$ for NetREm models.\n", "\n", "Selection for $\\beta_{net}$ can impact the optimal values for $\\alpha_{net}$" ] }, + { + "cell_type": "markdown", + "id": "bc3c1688", + "metadata": {}, + "source": [ + "netremCV(`edge_list`,
`X`, # *gene expression data for the predictors (e.g. Transcription Factors (TFs))*
\n", + "`y`, # *gene expression data for the response variable (e.g. target gene (TG))*
\n", + " `num_beta`: int = 10,
\n", + " `extra_beta_list` = [0.25, 0.5, 0.75, 1], # *additional beta to try out*
\n", + " `num_alpha`: int = 10,
\n", + " `max_beta`: float = 200, # *max_beta used to help prevent explosion of beta_net values*
\n", + " `reduced_cv_search`: bool = False, # *should we do a reduced search (Randomized Search) or a GridSearch?*
\n", + " `default_edge_weight`: float = 0.1,
\n", + " `degree_threshold`: float = 0.5,
\n", + " `gene_expression_nodes` = [],
\n", + " `overlapped_nodes_only`: bool = False,
\n", + " `standardize_X`: bool = True,
\n", + " `center_y`: bool = True,
\n", + " `y_intercept`: bool = False,
\n", + " `model_type` = \"Lasso\",
\n", + " `lasso_selection` = \"cyclic\", # *default in sklearn*
\n", + " `all_pos_coefs`: bool = False,
\n", + " `tolerance`: float = 1e-4,
\n", + " `maxit`: int = 10000,
\n", + " `num_jobs`: int = -1,
\n", + " `num_cv_folds`: int = 5,
\n", + " `lassocv_eps`: float = 1e-3, # *default in sklearn*
\n", + " `lassocv_n_alphas`: int = 100, # *default in sklearn*
\n", + " `lassocv_alphas` = None, # *default in sklearn*
\n", + " `verbose` = False,
\n", + " `searchVerbosity`: int = 2,
\n", + " `show_warnings`: bool = False
):" + ] + }, { "cell_type": "code", "execution_count": 1, @@ -21,7 +56,27 @@ "name": "stdout", "output_type": "stream", "text": [ - ":) same_train_test_data = False\n", + ":) same_train_test_data = False\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c12fe758096c4becb7fb41acb546021a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Generating predictors: 0%| | 0/5 [00:00\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
TF1TF2TF3TF4TF5
0-0.1331900.590034-0.5371130.0855020.360832
10.4413820.845980-1.3441820.3289250.311403
20.6712581.1714991.013758-0.9520910.265659
3-0.5652900.7190510.3447981.276574-0.349368
4-1.4108210.522239-0.6798171.1011291.755733
..................
699950.639805-0.7273370.8952200.266462-0.287123
699960.4912231.649460-1.260947-0.452498-0.300503
69997-0.688052-0.428763-1.080820-0.9335080.795700
69998-2.117304-1.1956601.4094432.0827791.809950
699992.0241601.523225-0.026287-0.107088-1.912545
\n", + "

70000 rows × 5 columns

\n", + "" + ], + "text/plain": [ + " TF1 TF2 TF3 TF4 TF5\n", + "0 -0.133190 0.590034 -0.537113 0.085502 0.360832\n", + "1 0.441382 0.845980 -1.344182 0.328925 0.311403\n", + "2 0.671258 1.171499 1.013758 -0.952091 0.265659\n", + "3 -0.565290 0.719051 0.344798 1.276574 -0.349368\n", + "4 -1.410821 0.522239 -0.679817 1.101129 1.755733\n", + "... ... ... ... ... ...\n", + "69995 0.639805 -0.727337 0.895220 0.266462 -0.287123\n", + "69996 0.491223 1.649460 -1.260947 -0.452498 -0.300503\n", + "69997 -0.688052 -0.428763 -1.080820 -0.933508 0.795700\n", + "69998 -2.117304 -1.195660 1.409443 2.082779 1.809950\n", + "69999 2.024160 1.523225 -0.026287 -0.107088 -1.912545\n", + "\n", + "[70000 rows x 5 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X_train" + ] + }, + { + "cell_type": "markdown", + "id": "8d994c65", + "metadata": {}, + "source": [ + "Input Protein-Protein Interaction (PPI) network relating TF predictors to each other:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, "id": "69496222", "metadata": {}, "outputs": [ @@ -93,7 +347,7 @@ " ['TF3', 'TF5']]" ] }, - "execution_count": 3, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -107,48 +361,33 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "094a7227", "metadata": {}, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - ":) using variance to define beta_net values\n", - "beta_min = 1.1506396943803596 and beta_max = 115.06396943803597\n" - ] - }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "ac3bddb5c58846a68761633cf7b46850", + "model_id": "8e1be7ac5c6241e49f0c9bfe72aa7300", "version_major": 2, "version_minor": 0 }, "text/plain": [ - ":) Generating beta_net and alpha_lasso pairs: 0%| | 0/50 [00:00#sk-container-id-1 {color: black;background-color: white;}#sk-container-id-1 pre{padding: 0;}#sk-container-id-1 div.sk-toggleable {background-color: white;}#sk-container-id-1 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-1 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-1 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-1 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-1 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-1 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-1 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-1 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-1 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-1 div.sk-item {position: relative;z-index: 1;}#sk-container-id-1 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-1 div.sk-item::before, #sk-container-id-1 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-1 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-1 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-1 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-1 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-1 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-1 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-1 div.sk-label-container {text-align: center;}#sk-container-id-1 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-1 div.sk-text-repr-fallback {display: none;}
NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=1.1506396943803596, alpha_lasso=0.051694590434151706, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x00000202249230A0>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + "
NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, standardize_X=True, center_y=True, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=0.25, alpha_lasso=0.0008985897297578544, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x00000234F23167A0>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" ], "text/plain": [ - "NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=1.1506396943803596, alpha_lasso=0.051694590434151706, network=)" + "NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, standardize_X=True, center_y=True, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=0.25, alpha_lasso=0.0008985897297578544, network=)" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -450,20 +573,20 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "15723a95", "metadata": {}, "outputs": [ { "data": { "text/html": [ - "
NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=1.1506396943803596, alpha_lasso=0.051694590434151706, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x00000202249230A0>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + "
NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, standardize_X=True, center_y=True, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=0.25, alpha_lasso=0.0008985897297578544, network=<PriorGraphNetwork.PriorGraphNetwork object at 0x00000234F23167A0>)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" ], "text/plain": [ - "NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=1.1506396943803596, alpha_lasso=0.051694590434151706, network=)" + "NetREmModel(overlapped_nodes_only=False, all_pos_coefs=False, standardize_X=True, center_y=True, y_intercept=False, max_lasso_iterations=10000, view_network=False, tolerance=0.0001, lasso_selection=cyclic, beta_net=0.25, alpha_lasso=0.0008985897297578544, network=)" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -474,7 +597,99 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, + "id": "928aa851", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
infoinput_dataTF1TF2TF3TF4TF5
0network regression coeff. with y: yX_train0.6145360.1060680.007784-0.030845-0.298912
0corr (r) with y: yX_train0.9001780.4962340.302551-0.203738-0.800527
0Absolute Value NetREm Coefficient RankingX_train13542
\n", + "
" + ], + "text/plain": [ + " info input_data TF1 TF2 \\\n", + "0 network regression coeff. with y: y X_train 0.614536 0.106068 \n", + "0 corr (r) with y: y X_train 0.900178 0.496234 \n", + "0 Absolute Value NetREm Coefficient Ranking X_train 1 3 \n", + "\n", + " TF3 TF4 TF5 \n", + "0 0.007784 -0.030845 -0.298912 \n", + "0 0.302551 -0.203738 -0.800527 \n", + "0 5 4 2 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_demoCV.final_corr_vs_coef_df" + ] + }, + { + "cell_type": "code", + "execution_count": 8, "id": "c599f58e", "metadata": {}, "outputs": [ @@ -482,12 +697,14 @@ "data": { "text/plain": [ "{'info': 'NetREm Model',\n", - " 'alpha_lasso': 0.051694590434151706,\n", - " 'beta_net': 1.1506396943803596,\n", + " 'alpha_lasso': 0.0008985897297578544,\n", + " 'beta_net': 0.25,\n", " 'y_intercept': False,\n", " 'model_type': 'Lasso',\n", + " 'standardize_X': True,\n", + " 'center_y': True,\n", " 'max_lasso_iterations': 10000,\n", - " 'network': ,\n", + " 'network': ,\n", " 'verbose': False,\n", " 'all_pos_coefs': False,\n", " 'model_info': 'fitted_model :)',\n", @@ -496,7 +713,7 @@ " 'lasso_selection': 'cyclic'}" ] }, - "execution_count": 6, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -507,17 +724,17 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "id": "7ba65d39", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0.13727397681026726" + "0.13363812169073666" ] }, - "execution_count": 7, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -528,17 +745,17 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "id": "1a9f2f60", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0.13781162327050317" + "0.13487280608906413" ] }, - "execution_count": 8, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -549,7 +766,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, "id": "758b4684", "metadata": {}, "outputs": [ @@ -578,6 +795,7 @@ " TF1\n", " TF2\n", " TF3\n", + " TF4\n", " TF5\n", " \n", " \n", @@ -585,21 +803,22 @@ " \n", " 0\n", " None\n", - " 0.277752\n", - " 0.063378\n", - " 0.00145\n", - " -0.159248\n", + " 0.614536\n", + " 0.106068\n", + " 0.007784\n", + " -0.030845\n", + " -0.298912\n", " \n", " \n", "\n", "" ], "text/plain": [ - " y_intercept TF1 TF2 TF3 TF5\n", - "0 None 0.277752 0.063378 0.00145 -0.159248" + " y_intercept TF1 TF2 TF3 TF4 TF5\n", + "0 None 0.614536 0.106068 0.007784 -0.030845 -0.298912" ] }, - "execution_count": 9, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -610,8 +829,193 @@ }, { "cell_type": "code", - "execution_count": 10, - "id": "7afe0c3f", + "execution_count": 12, + "id": "6ed7493d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
coefTFTGinfotrain_msebeta_netalpha_lassoAbsoluteVal_coefficientRankfinal_model_TFsTFs_input_to_modeloriginal_TFs_in_Xstandardized_Xcentered_y
0Noney_interceptynetrem_no_intercept0.1336380.250.000899NaN6555TrueTrue
10.614536TF1ynetrem_no_intercept0.1336380.250.0008990.6145361555TrueTrue
20.106068TF2ynetrem_no_intercept0.1336380.250.0008990.1060683555TrueTrue
30.007784TF3ynetrem_no_intercept0.1336380.250.0008990.0077845555TrueTrue
4-0.030845TF4ynetrem_no_intercept0.1336380.250.0008990.0308454555TrueTrue
5-0.298912TF5ynetrem_no_intercept0.1336380.250.0008990.2989122555TrueTrue
\n", + "
" + ], + "text/plain": [ + " coef TF TG info train_mse beta_net \\\n", + "0 None y_intercept y netrem_no_intercept 0.133638 0.25 \n", + "1 0.614536 TF1 y netrem_no_intercept 0.133638 0.25 \n", + "2 0.106068 TF2 y netrem_no_intercept 0.133638 0.25 \n", + "3 0.007784 TF3 y netrem_no_intercept 0.133638 0.25 \n", + "4 -0.030845 TF4 y netrem_no_intercept 0.133638 0.25 \n", + "5 -0.298912 TF5 y netrem_no_intercept 0.133638 0.25 \n", + "\n", + " alpha_lasso AbsoluteVal_coefficient Rank final_model_TFs \\\n", + "0 0.000899 NaN 6 5 \n", + "1 0.000899 0.614536 1 5 \n", + "2 0.000899 0.106068 3 5 \n", + "3 0.000899 0.007784 5 5 \n", + "4 0.000899 0.030845 4 5 \n", + "5 0.000899 0.298912 2 5 \n", + "\n", + " TFs_input_to_model original_TFs_in_X standardized_X centered_y \n", + "0 5 5 True True \n", + "1 5 5 True True \n", + "2 5 5 True True \n", + "3 5 5 True True \n", + "4 5 5 True True \n", + "5 5 5 True True " + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "netrem_demoCV.combined_df" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "a2e8cd9f", "metadata": {}, "outputs": [ { @@ -645,58 +1049,58 @@ " \n", " \n", " TF1\n", - " 5.414075\n", - " 1.113261\n", - " 0.361368\n", - " -0.429737\n", - " -2.771125\n", + " 1.023976\n", + " 0.426869\n", + " 0.207654\n", + " -0.186497\n", + " -0.721913\n", " \n", " \n", " TF2\n", - " 1.113261\n", - " 1.439763\n", - " -0.107738\n", - " -0.125070\n", - " -0.773506\n", + " 0.426869\n", + " 1.023976\n", + " 0.082365\n", + " -0.104892\n", + " -0.400304\n", " \n", " \n", " TF3\n", - " 0.361368\n", - " -0.107738\n", - " 37.921695\n", - " -0.359079\n", - " -0.715906\n", + " 0.207654\n", + " 0.082365\n", + " 9.000000\n", + " -0.128178\n", + " -0.303677\n", " \n", " \n", " TF4\n", - " -0.429737\n", - " -0.125070\n", - " -0.359079\n", - " 1.139272\n", - " 0.197285\n", + " -0.186497\n", + " -0.104892\n", + " -0.128178\n", + " 1.020979\n", + " 0.148067\n", " \n", " \n", " TF5\n", - " -2.771125\n", - " -0.773506\n", - " -0.715906\n", - " 0.197285\n", - " 2.877027\n", + " -0.721913\n", + " -0.400304\n", + " -0.303677\n", + " 0.148067\n", + " 1.020979\n", " \n", " \n", "\n", "" ], "text/plain": [ - " TF1 TF2 TF3 TF4 TF5\n", - "TF1 5.414075 1.113261 0.361368 -0.429737 -2.771125\n", - "TF2 1.113261 1.439763 -0.107738 -0.125070 -0.773506\n", - "TF3 0.361368 -0.107738 37.921695 -0.359079 -0.715906\n", - "TF4 -0.429737 -0.125070 -0.359079 1.139272 0.197285\n", - "TF5 -2.771125 -0.773506 -0.715906 0.197285 2.877027" + " TF1 TF2 TF3 TF4 TF5\n", + "TF1 1.023976 0.426869 0.207654 -0.186497 -0.721913\n", + "TF2 0.426869 1.023976 0.082365 -0.104892 -0.400304\n", + "TF3 0.207654 0.082365 9.000000 -0.128178 -0.303677\n", + "TF4 -0.186497 -0.104892 -0.128178 1.020979 0.148067\n", + "TF5 -0.721913 -0.400304 -0.303677 0.148067 1.020979" ] }, - "execution_count": 10, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -708,7 +1112,7 @@ { "cell_type": "code", "execution_count": 14, - "id": "64bd24b1", + "id": "6bb4d465", "metadata": {}, "outputs": [ { @@ -744,6 +1148,7 @@ " num_final_predictors\n", " model_type\n", " beta_net\n", + " X_standardized\n", " gene_data\n", " rank\n", " percentile\n", @@ -754,16 +1159,17 @@ " 20\n", " TF1\n", " TF5\n", - " -2.771125\n", + " -0.721913\n", " :(\n", " :( competitive (-)\n", - " 2.771125\n", + " 0.721913\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 1.0\n", " 95.0\n", @@ -772,16 +1178,17 @@ " 4\n", " TF5\n", " TF1\n", - " -2.771125\n", + " -0.721913\n", " :(\n", " :( competitive (-)\n", - " 2.771125\n", + " 0.721913\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 1.0\n", " 95.0\n", @@ -790,16 +1197,17 @@ " 5\n", " TF1\n", " TF2\n", - " 1.113261\n", + " 0.426869\n", " :)\n", " :(\n", - " 1.113261\n", + " 0.426869\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 3.0\n", " 85.0\n", @@ -808,16 +1216,17 @@ " 1\n", " TF2\n", " TF1\n", - " 1.113261\n", + " 0.426869\n", " :)\n", " :(\n", - " 1.113261\n", + " 0.426869\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 3.0\n", " 85.0\n", @@ -826,16 +1235,17 @@ " 9\n", " TF5\n", " TF2\n", - " -0.773506\n", + " -0.400304\n", " :(\n", " :( competitive (-)\n", - " 0.773506\n", + " 0.400304\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 5.0\n", " 75.0\n", @@ -844,16 +1254,17 @@ " 21\n", " TF2\n", " TF5\n", - " -0.773506\n", + " -0.400304\n", " :(\n", " :( competitive (-)\n", - " 0.773506\n", + " 0.400304\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 5.0\n", " 75.0\n", @@ -862,16 +1273,17 @@ " 14\n", " TF5\n", " TF3\n", - " -0.715906\n", + " -0.303677\n", " :(\n", " :( competitive (-)\n", - " 0.715906\n", + " 0.303677\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 7.0\n", " 65.0\n", @@ -880,160 +1292,169 @@ " 22\n", " TF3\n", " TF5\n", - " -0.715906\n", + " -0.303677\n", " :(\n", " :( competitive (-)\n", - " 0.715906\n", + " 0.303677\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 7.0\n", " 65.0\n", " \n", " \n", - " 15\n", + " 2\n", + " TF3\n", " TF1\n", - " TF4\n", - " -0.429737\n", + " 0.207654\n", + " :)\n", " :(\n", - " :( competitive (-)\n", - " 0.429737\n", + " 0.207654\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 9.0\n", " 55.0\n", " \n", " \n", - " 3\n", - " TF4\n", + " 10\n", " TF1\n", - " -0.429737\n", + " TF3\n", + " 0.207654\n", + " :)\n", " :(\n", - " :( competitive (-)\n", - " 0.429737\n", + " 0.207654\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 9.0\n", " 55.0\n", " \n", " \n", - " 2\n", - " TF3\n", + " 15\n", " TF1\n", - " 0.361368\n", - " :)\n", + " TF4\n", + " -0.186497\n", " :(\n", - " 0.361368\n", + " :( competitive (-)\n", + " 0.186497\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 11.0\n", " 45.0\n", " \n", " \n", - " 10\n", + " 3\n", + " TF4\n", " TF1\n", - " TF3\n", - " 0.361368\n", - " :)\n", + " -0.186497\n", " :(\n", - " 0.361368\n", + " :( competitive (-)\n", + " 0.186497\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 11.0\n", " 45.0\n", " \n", " \n", - " 13\n", + " 19\n", + " TF5\n", " TF4\n", - " TF3\n", - " -0.359079\n", + " 0.148067\n", + " :)\n", " :(\n", - " :( competitive (-)\n", - " 0.359079\n", + " 0.148067\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 13.0\n", " 35.0\n", " \n", " \n", - " 17\n", - " TF3\n", + " 23\n", " TF4\n", - " -0.359079\n", + " TF5\n", + " 0.148067\n", + " :)\n", " :(\n", - " :( competitive (-)\n", - " 0.359079\n", + " 0.148067\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 13.0\n", " 35.0\n", " \n", " \n", - " 19\n", - " TF5\n", + " 13\n", " TF4\n", - " 0.197285\n", - " :)\n", + " TF3\n", + " -0.128178\n", " :(\n", - " 0.197285\n", + " :( competitive (-)\n", + " 0.128178\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 15.0\n", " 25.0\n", " \n", " \n", - " 23\n", + " 17\n", + " TF3\n", " TF4\n", - " TF5\n", - " 0.197285\n", - " :)\n", + " -0.128178\n", " :(\n", - " 0.197285\n", + " :( competitive (-)\n", + " 0.128178\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 15.0\n", " 25.0\n", @@ -1042,16 +1463,17 @@ " 8\n", " TF4\n", " TF2\n", - " -0.125070\n", + " -0.104892\n", " :(\n", " :( competitive (-)\n", - " 0.125070\n", + " 0.104892\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 17.0\n", " 15.0\n", @@ -1060,16 +1482,17 @@ " 16\n", " TF2\n", " TF4\n", - " -0.125070\n", + " -0.104892\n", " :(\n", " :( competitive (-)\n", - " 0.125070\n", + " 0.104892\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 17.0\n", " 15.0\n", @@ -1078,16 +1501,17 @@ " 7\n", " TF3\n", " TF2\n", - " -0.107738\n", + " 0.082365\n", + " :)\n", " :(\n", - " :( competitive (-)\n", - " 0.107738\n", + " 0.082365\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 19.0\n", " 5.0\n", @@ -1096,16 +1520,17 @@ " 11\n", " TF2\n", " TF3\n", - " -0.107738\n", + " 0.082365\n", + " :)\n", " :(\n", - " :( competitive (-)\n", - " 0.107738\n", + " 0.082365\n", " B matrix of TF-TF interactions\n", " 5\n", " y\n", - " 4\n", + " 5\n", " Lasso\n", - " 1.15064\n", + " 0.25\n", + " True\n", " training gene expression data\n", " 19.0\n", " 5.0\n", @@ -1116,26 +1541,26 @@ ], "text/plain": [ " TF1 TF2 B_train_weight sign potential_interaction absVal_B \\\n", - "20 TF1 TF5 -2.771125 :( :( competitive (-) 2.771125 \n", - "4 TF5 TF1 -2.771125 :( :( competitive (-) 2.771125 \n", - "5 TF1 TF2 1.113261 :) :( 1.113261 \n", - "1 TF2 TF1 1.113261 :) :( 1.113261 \n", - "9 TF5 TF2 -0.773506 :( :( competitive (-) 0.773506 \n", - "21 TF2 TF5 -0.773506 :( :( competitive (-) 0.773506 \n", - "14 TF5 TF3 -0.715906 :( :( competitive (-) 0.715906 \n", - "22 TF3 TF5 -0.715906 :( :( competitive (-) 0.715906 \n", - "15 TF1 TF4 -0.429737 :( :( competitive (-) 0.429737 \n", - "3 TF4 TF1 -0.429737 :( :( competitive (-) 0.429737 \n", - "2 TF3 TF1 0.361368 :) :( 0.361368 \n", - "10 TF1 TF3 0.361368 :) :( 0.361368 \n", - "13 TF4 TF3 -0.359079 :( :( competitive (-) 0.359079 \n", - "17 TF3 TF4 -0.359079 :( :( competitive (-) 0.359079 \n", - "19 TF5 TF4 0.197285 :) :( 0.197285 \n", - "23 TF4 TF5 0.197285 :) :( 0.197285 \n", - "8 TF4 TF2 -0.125070 :( :( competitive (-) 0.125070 \n", - "16 TF2 TF4 -0.125070 :( :( competitive (-) 0.125070 \n", - "7 TF3 TF2 -0.107738 :( :( competitive (-) 0.107738 \n", - "11 TF2 TF3 -0.107738 :( :( competitive (-) 0.107738 \n", + "20 TF1 TF5 -0.721913 :( :( competitive (-) 0.721913 \n", + "4 TF5 TF1 -0.721913 :( :( competitive (-) 0.721913 \n", + "5 TF1 TF2 0.426869 :) :( 0.426869 \n", + "1 TF2 TF1 0.426869 :) :( 0.426869 \n", + "9 TF5 TF2 -0.400304 :( :( competitive (-) 0.400304 \n", + "21 TF2 TF5 -0.400304 :( :( competitive (-) 0.400304 \n", + "14 TF5 TF3 -0.303677 :( :( competitive (-) 0.303677 \n", + "22 TF3 TF5 -0.303677 :( :( competitive (-) 0.303677 \n", + "2 TF3 TF1 0.207654 :) :( 0.207654 \n", + "10 TF1 TF3 0.207654 :) :( 0.207654 \n", + "15 TF1 TF4 -0.186497 :( :( competitive (-) 0.186497 \n", + "3 TF4 TF1 -0.186497 :( :( competitive (-) 0.186497 \n", + "19 TF5 TF4 0.148067 :) :( 0.148067 \n", + "23 TF4 TF5 0.148067 :) :( 0.148067 \n", + "13 TF4 TF3 -0.128178 :( :( competitive (-) 0.128178 \n", + "17 TF3 TF4 -0.128178 :( :( competitive (-) 0.128178 \n", + "8 TF4 TF2 -0.104892 :( :( competitive (-) 0.104892 \n", + "16 TF2 TF4 -0.104892 :( :( competitive (-) 0.104892 \n", + "7 TF3 TF2 0.082365 :) :( 0.082365 \n", + "11 TF2 TF3 0.082365 :) :( 0.082365 \n", "\n", " info candidate_TFs_N target_gene_y \\\n", "20 B matrix of TF-TF interactions 5 y \n", @@ -1146,62 +1571,62 @@ "21 B matrix of TF-TF interactions 5 y \n", "14 B matrix of TF-TF interactions 5 y \n", "22 B matrix of TF-TF interactions 5 y \n", - "15 B matrix of TF-TF interactions 5 y \n", - "3 B matrix of TF-TF interactions 5 y \n", "2 B matrix of TF-TF interactions 5 y \n", "10 B matrix of TF-TF interactions 5 y \n", - "13 B matrix of TF-TF interactions 5 y \n", - "17 B matrix of TF-TF interactions 5 y \n", + "15 B matrix of TF-TF interactions 5 y \n", + "3 B matrix of TF-TF interactions 5 y \n", "19 B matrix of TF-TF interactions 5 y \n", "23 B matrix of TF-TF interactions 5 y \n", + "13 B matrix of TF-TF interactions 5 y \n", + "17 B matrix of TF-TF interactions 5 y \n", "8 B matrix of TF-TF interactions 5 y \n", "16 B matrix of TF-TF interactions 5 y \n", "7 B matrix of TF-TF interactions 5 y \n", "11 B matrix of TF-TF interactions 5 y \n", "\n", - " num_final_predictors model_type beta_net gene_data \\\n", - "20 4 Lasso 1.15064 training gene expression data \n", - "4 4 Lasso 1.15064 training gene expression data \n", - "5 4 Lasso 1.15064 training gene expression data \n", - "1 4 Lasso 1.15064 training gene expression data \n", - "9 4 Lasso 1.15064 training gene expression data \n", - "21 4 Lasso 1.15064 training gene expression data \n", - "14 4 Lasso 1.15064 training gene expression data \n", - "22 4 Lasso 1.15064 training gene expression data \n", - "15 4 Lasso 1.15064 training gene expression data \n", - "3 4 Lasso 1.15064 training gene expression data \n", - "2 4 Lasso 1.15064 training gene expression data \n", - "10 4 Lasso 1.15064 training gene expression data \n", - "13 4 Lasso 1.15064 training gene expression data \n", - "17 4 Lasso 1.15064 training gene expression data \n", - "19 4 Lasso 1.15064 training gene expression data \n", - "23 4 Lasso 1.15064 training gene expression data \n", - "8 4 Lasso 1.15064 training gene expression data \n", - "16 4 Lasso 1.15064 training gene expression data \n", - "7 4 Lasso 1.15064 training gene expression data \n", - "11 4 Lasso 1.15064 training gene expression data \n", + " num_final_predictors model_type beta_net X_standardized \\\n", + "20 5 Lasso 0.25 True \n", + "4 5 Lasso 0.25 True \n", + "5 5 Lasso 0.25 True \n", + "1 5 Lasso 0.25 True \n", + "9 5 Lasso 0.25 True \n", + "21 5 Lasso 0.25 True \n", + "14 5 Lasso 0.25 True \n", + "22 5 Lasso 0.25 True \n", + "2 5 Lasso 0.25 True \n", + "10 5 Lasso 0.25 True \n", + "15 5 Lasso 0.25 True \n", + "3 5 Lasso 0.25 True \n", + "19 5 Lasso 0.25 True \n", + "23 5 Lasso 0.25 True \n", + "13 5 Lasso 0.25 True \n", + "17 5 Lasso 0.25 True \n", + "8 5 Lasso 0.25 True \n", + "16 5 Lasso 0.25 True \n", + "7 5 Lasso 0.25 True \n", + "11 5 Lasso 0.25 True \n", "\n", - " rank percentile \n", - "20 1.0 95.0 \n", - "4 1.0 95.0 \n", - "5 3.0 85.0 \n", - "1 3.0 85.0 \n", - "9 5.0 75.0 \n", - "21 5.0 75.0 \n", - "14 7.0 65.0 \n", - "22 7.0 65.0 \n", - "15 9.0 55.0 \n", - "3 9.0 55.0 \n", - "2 11.0 45.0 \n", - "10 11.0 45.0 \n", - "13 13.0 35.0 \n", - "17 13.0 35.0 \n", - "19 15.0 25.0 \n", - "23 15.0 25.0 \n", - "8 17.0 15.0 \n", - "16 17.0 15.0 \n", - "7 19.0 5.0 \n", - "11 19.0 5.0 " + " gene_data rank percentile \n", + "20 training gene expression data 1.0 95.0 \n", + "4 training gene expression data 1.0 95.0 \n", + "5 training gene expression data 3.0 85.0 \n", + "1 training gene expression data 3.0 85.0 \n", + "9 training gene expression data 5.0 75.0 \n", + "21 training gene expression data 5.0 75.0 \n", + "14 training gene expression data 7.0 65.0 \n", + "22 training gene expression data 7.0 65.0 \n", + "2 training gene expression data 9.0 55.0 \n", + "10 training gene expression data 9.0 55.0 \n", + "15 training gene expression data 11.0 45.0 \n", + "3 training gene expression data 11.0 45.0 \n", + "19 training gene expression data 13.0 35.0 \n", + "23 training gene expression data 13.0 35.0 \n", + "13 training gene expression data 15.0 25.0 \n", + "17 training gene expression data 15.0 25.0 \n", + "8 training gene expression data 17.0 15.0 \n", + "16 training gene expression data 17.0 15.0 \n", + "7 training gene expression data 19.0 5.0 \n", + "11 training gene expression data 19.0 5.0 " ] }, "execution_count": 14, @@ -1210,17 +1635,8 @@ } ], "source": [ - "b_matrix = nm.organize_B_interaction_network(netrem_demoCV)\n", - "b_matrix" + "organize_B_interaction_network(netrem_demoCV)" ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "b5ca8aca", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -1239,7 +1655,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.6" + "version": "3.10.9" } }, "nbformat": 4, diff --git a/user_guide/overlapped_nodes_only.pdf b/user_guide/overlapped_nodes_only.pdf new file mode 100644 index 0000000..2323b61 Binary files /dev/null and b/user_guide/overlapped_nodes_only.pdf differ