---
title: "Identification of urinary bacterial genes as biomarkers for early diagnosis of renal lupus"
author: "Virginia Pérez Carrasco"
date: "2025-03-20"
output: html_document
---
# ##############################################################################
#
##  Figure 2d - OTU-based RF classification model 
#
# ##############################################################################

```{python}
# Import necessary libraries
import pandas as pd
from sklearn.model_selection import train_test_split, StratifiedKFold, cross_val_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_auc_score, accuracy_score, recall_score, confusion_matrix, roc_curve, auc
import matplotlib.pyplot as plt
import numpy as np
import warnings

# Ignore warnings
warnings.filterwarnings("ignore")

# Load dataset
file_path = 'path/to/input/file.txt'
data = pd.read_table(file_path)

# Define features and target variable
differential_maslin_otu = ['Otu000138','Otu000098','Otu000026','Otu000028','Otu000010','Otu000079','Otu000007','Otu000030','Otu000042','Otu000021']
X = data[differential_maslin_otu]
y = data['group']

# Set the seed for reproducibility
np.random.seed(42)

# Split data into 80% training and 20% testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)

# Initialize fivefold cross-validation
stratified_cv = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)

# Initialize Random Forest classifier with baseline parameters
rf_classifier = RandomForestClassifier(n_estimators=1000, random_state=42)

# Recursive feature elimination based on 'mean decrease accuracy'
selected_features = list(X.columns)
auc_scores = []

while len(selected_features) > 1:
    X_train_subset = X_train[selected_features]
    
    # Perform cross-validation and calculate AUC for current set of features
    auc_cv = cross_val_score(rf_classifier, X_train_subset, y_train, cv=stratified_cv, scoring='roc_auc')
    mean_auc_cv = auc_cv.mean()
    std_auc_cv = auc_cv.std()  # calculate standard deviation
    auc_scores.append((len(selected_features), mean_auc_cv, std_auc_cv, selected_features.copy()))
    
    # Fit model on current subset to get feature importances
    rf_classifier.fit(X_train_subset, y_train)
    importances = rf_classifier.feature_importances_
    
    # Find the least important feature
    least_important_feature = selected_features[np.argmin(importances)]
    selected_features.remove(least_important_feature)
    
# Find the optimal number of features based on the highest AUC
optimal_num_features, best_auc, best_std_auc, best_features = max(auc_scores, key=lambda x: x[1])

# Display best AUC, std deviation, and selected features
print(f'Optimal number of features: {optimal_num_features}')
print(f'Best AUC during feature selection: {best_auc}')
print(f'Standard deviation of AUC: {best_std_auc}')
print(f'Selected features: {best_features}')

# Hyperparameter optimization and final model training
rf_classifier_optimized = RandomForestClassifier(
    n_estimators=1000,
    max_features='sqrt',  # updated from 'auto' to 'sqrt'
    max_leaf_nodes=optimal_num_features,
    min_samples_leaf=2,
    random_state=42
)

# Calculate mean ROC curve with confidence interval
tprs = []
aucs = []
mean_fpr = np.linspace(0, 1, 100)

for train, test in stratified_cv.split(X_train[best_features], y_train):
    rf_classifier_optimized.fit(X_train[best_features].iloc[train], y_train.iloc[train])
    probas_ = rf_classifier_optimized.predict_proba(X_train[best_features].iloc[test])[:, 1]
    
    # Compute ROC curve and area under the curve
    fpr, tpr, _ = roc_curve(y_train.iloc[test], probas_)
    tprs.append(np.interp(mean_fpr, fpr, tpr))  # Interpolate tpr at mean fpr points
    tprs[-1][0] = 0.0  # Ensure the curve starts at (0,0)
    aucs.append(auc(fpr, tpr))

# Calculate mean and std deviation of TPR at each FPR
mean_tpr = np.mean(tprs, axis=0)
mean_tpr[-1] = 1.0  # Ensure the curve ends at (1,1)
mean_auc = auc(mean_fpr, mean_tpr)
std_auc = np.std(aucs)

# Calculate standard deviation of TPRs for confidence interval
std_tpr = np.std(tprs, axis=0)
tpr_upper = np.minimum(mean_tpr + std_tpr, 1)
tpr_lower = np.maximum(mean_tpr - std_tpr, 0)

# Plot ROC curve with shaded standard deviation area
plt.figure(figsize=(8, 6))
plt.plot(mean_fpr, mean_tpr, color='darkorange', label=f'Mean ROC (AUC = {mean_auc:.2f} ± {std_auc:.2f})', lw=2)
plt.fill_between(mean_fpr, tpr_lower, tpr_upper, color='orange', alpha=0.2, label='± 1 std. dev.')
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver Operating Characteristic (ROC) Curve with Standard Deviation Shading')
plt.legend(loc='lower right')
plt.savefig('roc_curve_optimized_model_shaded.svg', format='svg')
plt.show()
```

```{python}
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import StratifiedKFold
from sklearn.metrics import roc_curve, auc, accuracy_score, precision_score
import matplotlib.pyplot as plt
import warnings

# Suppress warnings
warnings.filterwarnings("ignore")

# Define file paths to the datasets
file_paths = [
    'path/to/input/file_dataset1.txt',
    'path/to/input/file_dataset2.txt',
    'path/to/input/file_dataset3.txt'
]

# Define features to use
best_gene_combination = ['Otu000098', 'Otu000026', 'Otu000010', 'Otu000079', 'Otu000007', 'Otu000030', 'Otu000042', 'Otu000021']
all_features = best_gene_combination

# Define labels for the datasets
labels = ['Control + Non-renal SLE vs Renal SLE', 'Control vs Renal SLE', 'Non-renal SLE vs Renal SLE']

# Initialize lists to store metrics for each dataset
roc_curves = []
auc_values = []
accuracy_values = []
precision_values = []

# Colors for plots
colors = ['green', 'purple', 'orange']

# Loop through each dataset
for i, file_path in enumerate(file_paths):
    try:
        # Load the data into a DataFrame
        data = pd.read_table(file_path)
        
        # Verify columns exist
        if not all(feature in data.columns for feature in all_features + ['group']):
            print(f"Dataset {labels[i]}: Missing columns. Skipping...")
            continue
        
        # Create feature matrix X and target variable y
        X = data[all_features]
        y = data['group']
        
        # Convert y to binary labels (0 and 1)
        class_mapping = {label: idx for idx, label in enumerate(np.unique(y))}
        y = y.map(class_mapping)
        pos_label = 1  # Set positive class for ROC and precision calculation
        
        # Set the seed for reproducibility
        np.random.seed(42)
        
        # Define stratified k-fold cross-validation
        stratified_cv = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)
        
        # Initialize Random Forest classifier
        rf_classifier = RandomForestClassifier(n_estimators=1000, max_features='sqrt', random_state=42)
        
        # Perform stratified k-fold cross-validation
        mean_fpr = np.linspace(0, 1, 100)
        tprs = []
        aucs = []
        accuracies = []
        precisions = []
        
        for train_index, test_index in stratified_cv.split(X, y):
            X_train_fold, X_test_fold = X.iloc[train_index], X.iloc[test_index]
            y_train_fold, y_test_fold = y.iloc[train_index], y.iloc[test_index]

            # Fit the Random Forest classifier on the training fold
            rf_classifier.fit(X_train_fold, y_train_fold)

            # Predict probabilities and classes for the test fold
            y_pred_fold = rf_classifier.predict(X_test_fold)
            probas_fold = rf_classifier.predict_proba(X_test_fold)[:, 1]

            # Calculate accuracy and precision for this fold
            accuracies.append(accuracy_score(y_test_fold, y_pred_fold))
            precisions.append(precision_score(y_test_fold, y_pred_fold, pos_label=pos_label))

            # Compute ROC curve and AUC for the fold
            fpr_fold, tpr_fold, _ = roc_curve(y_test_fold, probas_fold, pos_label=pos_label)
            tprs.append(np.interp(mean_fpr, fpr_fold, tpr_fold))  # Interpolate TPR
            tprs[-1][0] = 0.0  # Ensure the curve starts at (0,0)
            aucs.append(auc(fpr_fold, tpr_fold))

        # Calculate mean TPR, std deviation, and mean AUC
        mean_tpr = np.mean(tprs, axis=0)
        mean_tpr[-1] = 1.0  # Ensure the curve ends at (1,1)
        std_tpr = np.std(tprs, axis=0)
        mean_auc = np.mean(aucs)
        std_auc = np.std(aucs)
        
        # Store metrics for this dataset
        accuracy_values.append(np.mean(accuracies))
        precision_values.append(np.mean(precisions))
        roc_curves.append((mean_fpr, mean_tpr, std_tpr, mean_auc, std_auc))
        auc_values.append(mean_auc)
    
    except Exception as e:
        print(f"Error processing dataset {labels[i]}: {e}")
        continue

# Plot the ROC curves for all datasets
plt.figure(figsize=(10, 8))

for i, (mean_fpr, mean_tpr, std_tpr, mean_auc, std_auc) in enumerate(roc_curves):
    plt.plot(mean_fpr, mean_tpr, color=colors[i], label=f'{labels[i]} (AUC = {mean_auc:.2f} ± {std_auc:.2f})')
    plt.fill_between(mean_fpr, mean_tpr - std_tpr, mean_tpr + std_tpr, color=colors[i], alpha=0.2)

plt.plot([0, 1], [0, 1], color='gray', linestyle='--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curves with Confidence Intervals for Multiple Datasets')
plt.legend(loc='lower right')
plt.savefig('roc_curves_multiple_datasets_with_ci.svg', format='svg')
plt.show()

# Print out accuracy and precision for each dataset
for i, label in enumerate(labels):
    if i < len(accuracy_values):
        print(f"Dataset: {label}")
        print(f"  Accuracy: {accuracy_values[i]:.2f}")
        print(f"  Precision: {precision_values[i]:.2f}")
```

# ##############################################################################
#
##  Figure 3a - Representation of the LefSe results using volcano plots
#
# ##############################################################################

```{r}
#Load libraries
library("ggplot2")

#Import data
data <-read.table("C:/path/to/file/input_control_vs_non-renal.txt", stringsAsFactors = FALSE, row.names = 1, header = TRUE, check.names = FALSE, fill = TRUE)
#data <-read.table("C:/path/to/file/input_control_vs_renal.txt", stringsAsFactors = FALSE, row.names = 1, header = TRUE, check.names = FALSE, fill = TRUE)
#data <-read.table("C:/path/to/file/input_non-renal_vs_renal.txt", stringsAsFactors = FALSE, row.names = 1, header = TRUE, check.names = FALSE, fill = TRUE)

#Visualization
p <- ggplot(data, aes(x=LDA, y=-log10(pvalue))) + geom_point() + theme_minimal()
print(p)

#The differentially expressed genes are the ones found in the upper-left and upper-right corners
#Add a column to the data frame to specify if they are UP- or DOWN- regulated 

# add a column of NOs
data$diffexpressed <- "NON SIGNIFICANT"

# if log2Foldchange > 1 and pvalue < 0.05, set as "UP" 
data$diffexpressed[data$LDA > 1 & data$pvalue < 0.05] <- "UP"
# if log2Foldchange < -0.6 and pvalue < 0.05, set as "DOWN"
data$diffexpressed[data$LDA < -1 & data$pvalue < 0.05] <- "DOWN"

# Re-plot con tamaño de puntos reducido
p <- ggplot(data, aes(x=LDA, y=-log10(pvalue), col=diffexpressed)) + 
  geom_point(size=1) +  # Cambia el tamaño de los puntos aquí
  theme_minimal()
print(p)

#Change the colours
p5 <- p + scale_color_manual(values=c("cornflowerblue", "lightcyan4", "indianred"))
print(p5)

pdf("Volcanoplot_KOgenes.pdf",height=5,width=5)
p5
dev.off()
```

# ##############################################################################
#
##  Figure 3c - Differential gene-based RF Classification model 
#
# ##############################################################################

```{python}
# Part 1: Select the best combination of genes for model construction.

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, StratifiedKFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_auc_score, roc_curve, auc
import matplotlib.pyplot as plt
from itertools import combinations

# Load the data
file_path = 'C:/path/to/file/input.txt'
data = pd.read_table(file_path)

# Define the differential genes 
differential_ko_lefse=['K01496','K01523','K14335','K07152','K01042','K03833','K00860','K14061','K02279','K10007','K07267','K02300','K00507','K09857','K01113','K03196','K11717','K05845','K07127','K09476','K00697','K01207','K03823','K03185','K07270','K00529','K01304','K03195','K07132','K02297','K09960','K02073','K02526','K02003','K03719','K03200','K05577','K03225','K02575','K01738','K12262','K09888','K06147','K06966','K07246','K05800','K01541','K02485','K03926','K03227','K00831','K02004','K03676','K03785','K02348','K04041','K07506','K12511','K01194','K02759','K05839','K02488','K03229','K00510','K06192','K03487','K07032','K00832','K10006','K07147','K00226','K07393','K03226','K07483','K07013','K01147','K14058','K03222','K07229','K00252','K09005','K13541','K03457','K10008','K01755','K02478','K07657','K07140','K07019','K06213','K09019','K08590','K07733','K05816','K08310','K00018','K07222','K03228','K07150','K10001','K01854','K01130','K03825','K02345','K10005','K00782','K09961','K06445','K08160','K02298','K03224','K03199','K07046','K03320','K01911','K00140','K05365','K00836','K06883','K13745','K01661','K09017','K03281','K00023','K03230','K03414','K03219','K09712','K05875','K07008']
all_features = differential_ko_lefse

# Create feature matrix X and target variable y
X = data[all_features]
y = data['group']

# Set the seed for reproducibility
np.random.seed(42)

# Define the proportion of training data
train_proportion = 0.7

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1 - train_proportion, random_state=42, stratify=y)

# Initialize Random Forest classifier
n_estimators = 1000
max_features = 0.1  # 10% of total features
rf_classifier = RandomForestClassifier(n_estimators=n_estimators, max_features=max_features, random_state=42)

# Dictionary to store AUC values and ROC curve data for each combination
comb_auc_scores = {}
roc_data = {}

# Calculate AUC and ROC curve for each combination of features
for r in range(1, len(all_features) + 1):
    for comb in combinations(all_features, r):
        X_comb = X[list(comb)]
        
        # Split the data for this combination
        X_train_comb, X_test_comb, y_train_comb, y_test_comb = train_test_split(X_comb, y, test_size=1 - train_proportion, random_state=42, stratify=y)
        
        # Train the classifier on this combination
        rf_classifier.fit(X_train_comb, y_train_comb)
        
        # Predict probabilities
        predictions_comb = rf_classifier.predict_proba(X_test_comb)[:, 1]
        
        # Calculate AUC
        auc_comb = roc_auc_score(y_test_comb, predictions_comb)
        comb_auc_scores[comb] = auc_comb
        
        # Get ROC curve data
        fpr, tpr, _ = roc_curve(y_test_comb, predictions_comb)
        roc_data[comb] = (fpr, tpr, auc_comb)

# Identify the best combination based on the highest AUC score
best_combination = max(comb_auc_scores, key=comb_auc_scores.get)
best_auc_score = comb_auc_scores[best_combination]

# Print the best combination of genes and its AUC score
best_genes = ' + '.join(best_combination)
print(f'Best gene combination: {best_genes}')
print(f'Best AUC score: {best_auc_score}')

# Initialize lists to store ROC curve values for cross-validation folds
mean_fpr = np.linspace(0, 1, 100)
tpr_list = []

# Create the stratified k-fold cross-validator
stratified_cv = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)

# Perform stratified k-fold cross-validation
for train_index, test_index in stratified_cv.split(X_train, y_train):
    X_train_fold, X_test_fold = X_train.iloc[train_index], X_train.iloc[test_index]
    y_train_fold, y_test_fold = y_train.iloc[train_index], y_train.iloc[test_index]

    # Fit the Random Forest classifier on the training data
    rf_classifier.fit(X_train_fold, y_train_fold)

    # Perform predictions on the test set
    predictions_fold = rf_classifier.predict_proba(X_test_fold)[:, 1]

    # Get the ROC curve for the fold
    fpr_fold, tpr_fold, _ = roc_curve(y_test_fold, predictions_fold)

    # Interpolate the ROC curve to match mean_fpr
    tpr_fold_interp = np.interp(mean_fpr, fpr_fold, tpr_fold)
    
    # Append the interpolated TPR to the list
    tpr_list.append(tpr_fold_interp)

# Calculate the mean TPR across folds
mean_tpr = np.mean(tpr_list, axis=0)

# Calculate the standard deviation of TPR across folds
std_tpr = np.std(tpr_list, axis=0)

# Calculate the mean AUC from the mean TPR
mean_auc_cv = auc(mean_fpr, mean_tpr)

# Print AUC values for each combination
for comb, auc_score in comb_auc_scores.items():
    comb_label = ' + '.join(comb)
    print(f'AUC for {comb_label}: {auc_score}')
print(f'Mean AUC across folds: {mean_auc_cv}')

# Save AUC values for each combination and the mean AUC to a text file
with open('comb_auc_scores.txt', 'w') as file:
    for comb, auc_score in comb_auc_scores.items():
        comb_label = ' + '.join(comb)
        file.write(f'AUC for {comb_label}: {auc_score}\n')
    file.write(f'Mean AUC across folds: {mean_auc_cv}\n')

# Save the best combination of genes and its AUC score to a text file
with open('best_gene_combination.txt', 'w') as file:
    file.write(f'Best gene combination: {best_genes}\n')
    file.write(f'Best AUC score: {best_auc_score}\n')

# Part 2: Build the model with these genes and test it on different datasets to see its efficiency in the different comparisons.

# Import necessary libraries
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split, StratifiedKFold
from sklearn.feature_selection import SelectFromModel
from sklearn.metrics import roc_auc_score, accuracy_score, precision_score, recall_score, f1_score, roc_curve, auc
import matplotlib.pyplot as plt
import warnings
from sklearn.exceptions import UndefinedMetricWarning

# Suppress warnings
warnings.filterwarnings("ignore", category=UndefinedMetricWarning)

# Define file paths to the three datasets
file_paths = [
    'C:/path/to/file/general.txt',
    'C:/path/to/file/control_vs_renal.txt',
    'C:/path/to/file/non-renal_vs_renal.txt'
]

# Define features to use
best_gene_combination = ['K14335', 'K07152', 'K01042', 'K02003', 'K06147', 'K07483', 'K02004', 'K01738', 'K00782']
all_features = best_gene_combination

# Initialize lists to store ROC curve values for each dataset
roc_curves = []
auc_values = []

for file_path in file_paths:
    # Load the data into a DataFrame
    data = pd.read_table(file_path)
    
    # Create feature matrix X and target variable y
    X = data[all_features]
    y = data['group']
    
    # Set the seed for reproducibility
    np.random.seed(42)
    
    # Define the proportion of training data
    train_proportion = 0.7
    
    # Create the stratified k-fold cross-validator
    stratified_cv = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)
    
    # Split the data into training and testing sets
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1 - train_proportion, random_state=42, stratify=y)
    
    # Define Random Forest parameters
    n_estimators = 1000
    max_features = 0.1  # 10% of total features
    
    # Initialize Random Forest classifier
    rf_classifier = RandomForestClassifier(n_estimators=n_estimators, max_features=max_features, random_state=42)
    
    # Perform stratified k-fold cross-validation for ROC curve
    mean_fpr = np.linspace(0, 1, 100)
    tpr_list = []
    
    for train_index, test_index in stratified_cv.split(X_train, y_train):
        X_train_fold, X_test_fold = X_train.iloc[train_index], X_train.iloc[test_index]
        y_train_fold, y_test_fold = y_train.iloc[train_index], y_train.iloc[test_index]

        # Fit the Random Forest classifier on the training data
        rf_classifier.fit(X_train_fold, y_train_fold)

        # Perform predictions on the test set
        predictions_fold = rf_classifier.predict_proba(X_test_fold)[:, 1]

        # Get the ROC curve for the fold
        fpr_fold, tpr_fold, _ = roc_curve(y_test_fold, predictions_fold)

        # Interpolate the ROC curve to match mean_fpr
        tpr_fold_interp = np.interp(mean_fpr, fpr_fold, tpr_fold)
        tpr_list.append(tpr_fold_interp)

    # Calculate the mean TPR across folds
    mean_tpr = np.mean(tpr_list, axis=0)
    std_tpr = np.std(tpr_list, axis=0)
    mean_auc = auc(mean_fpr, mean_tpr)
    
    # Append ROC curve data and AUC values
    roc_curves.append((mean_fpr, mean_tpr, std_tpr, mean_auc))
    auc_values.append(mean_auc)

# Plot the ROC curves for all datasets
plt.figure(figsize=(10, 8))
colors = ['purple', 'green', 'orange']
labels = ['Control vs Renal SLE', 'Control + Non-renal SLE vs Renal SLE', 'Non-renal SLE vs Renal SLE']

for i, (mean_fpr, mean_tpr, std_tpr, mean_auc) in enumerate(roc_curves):
    plt.plot(mean_fpr, mean_tpr, color=colors[i], label=f'{labels[i]} (AUC = {mean_auc:.2f})')
    plt.fill_between(mean_fpr, mean_tpr - std_tpr, mean_tpr + std_tpr, color=colors[i], alpha=0.2)

plt.plot([0, 1], [0, 1], color='gray', linestyle='--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curves for Different Datasets')
plt.legend()
plt.savefig('roc_curves_multiple_datasets.svg', format='svg')
plt.show()
```

# ##############################################################################
#
##  Figure 4 - Maaslin2 at level 3 bacterial pathways
#
# ##############################################################################

```{r}
#Install and load necessary libraries
if(!requireNamespace("BiocManager", quietly = TRUE))
  install.packages("BiocManager")
BiocManager::install("Maaslin2")

library(Maaslin2)

library(ggplot2)
library(dplyr)
install.packages("tidyverse")
library(tidyverse)

library(pheatmap)
library(RColorBrewer)


#Import data
input_data <- read.table("C:/path/to/file/data.txt",  header=TRUE, sep="\t", na.strings="NA", dec=".", strip.white=TRUE, check.names=FALSE, fill = TRUE, quote = "", row.names ="sample")
input_metadata <- read.table("C:/path/to/file/metadata.txt",  header=TRUE, sep="\t", na.strings="NA", dec=".", strip.white=TRUE, check.names=FALSE, fill = TRUE, quote = "", row.names ="sample")

#Maaslin2 analysis
fit_data = Maaslin2(input_data     = input_data, 
                    input_metadata = input_metadata, 
                    min_prevalence = 0,
                    normalization  = "NONE",
                    transform = "NONE",
                    output         = "Maaslin2_output_level3_age_as_fixedeffect", 
                    fixed_effects  = c("group","age"),
                    reference      = c("group,Control"))


# Load the Maaslin2 results file
results <- read.table("C:/path/to/file/all_results.tsv", header = TRUE, sep = "\t")

# Step 1: Filter out associations with 'age' metadata
filtered_results <- results %>%
  filter(metadata == "group")  # Keep only rows where metadata is 'group'

# Step 1: Filter for significant pathways in at least one group
# Group by feature and identify significant pathways
significant_features <- filtered_results %>%
  filter(qval < 0.05) %>%
  pull(feature) %>%
  unique()  # Get unique significant features

# Step 2: Keep all rows for the significant features identified
significant_results <- filtered_results %>%
  filter(feature %in% significant_features)

# Calculate the association index (-log(qval) * sign(coef))
significant_results <- significant_results %>%
  mutate(association_index = -log10(qval) * sign(coef))  # Replace 'coef' with the correct column name

#Visualization
# Assuming significant_results is already loaded and contains 'feature', 'value', 'association_index', and 'qval'
# Create matrices for association data and p-values
association_data <- significant_results %>%
  select(feature, value, association_index) %>%
  pivot_wider(names_from = value, values_from = association_index) %>%
  column_to_rownames(var = "feature") %>%
  as.matrix()

pvalue_data <- significant_results %>%
  select(feature, value, qval) %>%
  pivot_wider(names_from = value, values_from = qval) %>%
  column_to_rownames(var = "feature") %>%
  as.matrix()

# Function to add significance stars based on p-values
add_significance_stars <- function(p_data) {
  stars <- ifelse(p_data < 0.05, "*", "")
  stars[p_data < 0.01] <- "**"
  stars[p_data < 0.001] <- "***"
  return(stars)
}

# Apply function to p-value data
stars_matrix <- add_significance_stars(pvalue_data)

# Specify the PDF output file
pdf("heatmap_with_significance_stars.pdf", width = 10, height = 20)

# Add annotation row to the heatmap
pheatmap(association_data, 
         color = colorRampPalette(c("blue", "white", "red"))(20),
         display_numbers = stars_matrix,
         cellwidth = 20,   
         cellheight = 5, 
         main = "Heatmap with Significance Stars", fontsize = 5, width = 10, height = 20 )

# Close the PDF device
dev.off()
```

# ##############################################################################
#
##  Figure 5a and S4a - Differential abundance of KO genes
#
# ##############################################################################

```{r}
#Install and load necessary libraries

if (!require("BiocManager", quietly = TRUE))
  install.packages("BiocManager")
BiocManager::install("clusterProfiler")

if (!require("BiocManager", quietly = TRUE))
  install.packages("BiocManager")
BiocManager::install("edgeR")

install.packages("vegan")

library(edgeR)
library(clusterProfiler)
library(vegan)

#Import data: We have two files depending on whether the comparison is control vs non-renal or control vs renal.
KO_orthologs <-read.table("C:/path/to/file/figure4a_data_control_vs_non-renal.txt", stringsAsFactors = FALSE, row.names = 1, header = TRUE, check.names = FALSE, fill = TRUE)
#KO_orthologs <-read.table("C:/path/to/file/figure4a_data_control_vs_renal.txt", stringsAsFactors = FALSE, row.names = 1, header = TRUE, check.names = FALSE, fill = TRUE)

# Obtain CPMs (counts-per-million; with this we normalize to the sequencing depth of each sample)
myCPM <- cpm(KO_orthologs)
write.table(myCPM, "MyCPM.txt", sep= "\t", quote = F, row.names = TRUE, col.names= T, na= "NA")

#Generate DGEobject
dgeObj <- DGEList(myCPM)
# have a look at dgeObj
dgeObj
# See what slots are stored in dgeObj
names(dgeObj)
# Library size information is stored in the samples slot. Not pay attention in this case!!
dgeObj$samples


#Differential abundance analysis
#We define the comparison groups (factor) as a vector, with as many levels as groups to compare. They must be in the same order as in the initial data table. Samples at the same level are considered replicates.
We have two files depending on whether the comparison is control vs non-renal or control vs renal.
ID_f <- read.table("C:/path/to/file/figure4a_factor_control_vs_non-renal.txt", stringsAsFactors = FALSE, row.names = NULL, header = FALSE, check.names = FALSE)
#ID_f <- read.table("C:/path/to/file/figure4a_factor_control_vs_renal.txt", stringsAsFactors = FALSE, row.names = NULL, header = FALSE, check.names = FALSE)
ID_f <- as.character(ID_f)
class(ID_f)
group <- as.factor(ID_f)

#Calculate the object dispersion with the data
dgeObj <- estimateGLMTrendedDisp(dgeObj)
dgeObj <- estimateCommonDisp(dgeObj)
dgeObj <- estimateTagwiseDisp(dgeObj)

#Build a design matrix with the vector previously defined with the comparison groups (group)
design <- model.matrix( ~0+group)

# Fit the linear model
fit <- glmFit(dgeObj, design)

#Conduct statistics for study groups. Makecontrast indicates the groups to compare. Second group  is considered as reference
Comparison <-  glmLRT( fit, contrast=makeContrasts( group2-group1, levels=design ) )
Comparison_table <- Comparison$table
pvalue <- Comparison_table[,4]

#Calculate padj
padj <- p.adjust(pvalue,"fdr")
Comparison_table[5] <- padj
colnames(Comparison_table)[5] <- "padj"
padj_cutoff <- padj < 0.05
any(padj_cutoff == TRUE)
sum(padj_cutoff == TRUE)

write.table(Comparison_table, "KO_genes.txt", sep= "\t", quote = F, row.names = TRUE, col.names= T, na= "NA")

#Keep genes with padj<0.05
DA_genes_1 <- Comparison_table[Comparison_table$padj < 0.05,]
DA_genes_1$KO_number <- row.names(DA_genes_1)
DA_genes_filtrada <- DA_genes_1[, c("KO_number", "logFC")]
write.table(DA_genes_filtrada, "KO_significant_genes.txt", sep= "\t", quote = F, row.names = TRUE, col.names= T, na= "NA") #This file is the one we are going to use as input for the second part of the analysis in Python
```

```{python}
import matplotlib as mpl
import matplotlib.cm as cm
import matplotlib.pyplot as plt

# Open the file and read the lines
with open("ko_significant_genes.txt", "r") as f:
    lines = f.readlines()

# Print the lines read (optional)
print(lines)

# Extract the second column from the file
result = [line.split('\t')[1] for line in lines[1:]] 

# Convert data to floats
result2 = [float(val) for val in result]

# Normalize the data and create the colormap
norm = mpl.colors.Normalize(vmin=-4.6, vmax=5.2)
cmap = cm.RdBu
m = cm.ScalarMappable(norm=norm, cmap=cmap)

# Create the figure and the axes
fig, ax = plt.subplots()

# Add color bar to the axes
fig.colorbar(m, ax=ax)

# Transform data into RGB colors
y = [m.to_rgba(val) for val in result2]

# Convert RGB to Hexadecimal
z = [mpl.colors.rgb2hex(color[:3]) for color in y]  
print(z)

# Create and write the results to a new file. This file is the input for coloring metabolic pathway maps in the KEGG Mapper Color tool.
with open("Results.txt", "w") as f2:
    for color_hex in z:
        f2.write(color_hex + '\n')

# Show figure (optional)
plt.show()
```

# ##############################################################################
#
##  Figure 5b and S4b  Mean AUC of differential genes in the pathway of interest
#
# ##############################################################################

```{python}
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, StratifiedKFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_auc_score, accuracy_score, precision_score, recall_score, f1_score, roc_curve, auc
from sklearn.feature_selection import SelectFromModel
import matplotlib.pyplot as plt

# Load the data
file_path = 'C:/path/to/file/input_5b.txt'
#file_path = 'C:/path/to/file/input_S4b.txt'
data = pd.read_table(file_path)

# Define the genes in the valine pathway
genes_figure5b = ['K01703','K01754','K01653','K00053','K01687','K00263']
#genes_supple_figure4b= ['K01735','K00891','K00800','K01736','K01657','K01658','K00766','K01695']
all_features = genes_figure4b

# Create feature matrix X and target variable y
X = data[all_features]
y = data['group']

# Set the seed for reproducibility
np.random.seed(42)

# Define the proportion of training data
train_proportion = 0.7

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1 - train_proportion, random_state=42, stratify=y)

# Initialize Random Forest classifier
n_estimators = 1000
max_features = 0.1  # 10% of total features
rf_classifier = RandomForestClassifier(n_estimators=n_estimators, max_features=max_features, random_state=42)

# List to store AUC values for each feature
feature_auc_scores = []

# Calculate AUC for each individual feature
for feature in all_features:
    X_feature = X[[feature]]
    
    # Split the data for this feature
    X_train_feat, X_test_feat, y_train_feat, y_test_feat = train_test_split(X_feature, y, test_size=1 - train_proportion, random_state=42, stratify=y)
    
    # Train the classifier on this feature
    rf_classifier.fit(X_train_feat, y_train_feat)
    
    # Predict probabilities
    predictions_feat = rf_classifier.predict_proba(X_test_feat)[:, 1]
    
    # Calculate AUC
    auc_feat = roc_auc_score(y_test_feat, predictions_feat)
    feature_auc_scores.append(auc_feat)

# Calculate mean AUC
mean_auc = np.mean(feature_auc_scores)

# Plot AUC for each feature and the mean
plt.figure(figsize=(10, 6))
plt.bar(all_features, feature_auc_scores, color='skyblue')
plt.axhline(y=mean_auc, color='red', linestyle='--', label=f'Mean AUC = {mean_auc:.2f}')
plt.xlabel('Feature')
plt.ylabel('AUC')
plt.title('AUC for each feature and Mean AUC')
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.savefig('feature_auc_and_mean_genes.svg', format='svg')
plt.show()

# Print AUC values for each feature
for feature, auc_score in zip(all_features, feature_auc_scores):
    print(f'AUC for {feature}: {auc_score}')
print(f'Mean AUC: {mean_auc}')

# Save AUC values for each feature and the mean AUC to a text file
with open('feature_auc_scores_genes.txt', 'w') as file:
    for feature, auc_score in zip(all_features, feature_auc_scores):
        file.write(f'AUC for {feature}: {auc_score}\n')
    file.write(f'Mean AUC: {mean_auc}\n')

# Verificar que las columnas necesarias estén presentes en los datos
if not set(all_features + ['group']).issubset(data.columns):
    raise ValueError("Faltan columnas requeridas en el dataset.")

# Crear la matriz de características X y la variable objetivo y
X = data[all_features]
y = data['group']

# Validar si hay datos faltantes y eliminar filas con NaN si es necesario
if X.isnull().any().any():
    print("Se encontraron valores faltantes. Eliminando filas con valores faltantes.")
    data = data.dropna(subset=all_features + ['group'])
    X = data[all_features]
    y = data['group']

# Configurar la semilla para reproducibilidad
np.random.seed(42)

# Proporción de datos para entrenamiento
train_proportion = 0.8

# Inicializar el clasificador Random Forest
n_estimators = 1000
max_features = 0.1  # 10% de las características totales
rf_classifier = RandomForestClassifier(n_estimators=n_estimators, max_features=max_features, random_state=42)

# Preparar el gráfico
plt.figure(figsize=(10, 8))
colors = plt.cm.tab10(np.linspace(0, 1, len(all_features)))  # Colores para las curvas

# Lista para almacenar los resultados del AUC
auc_results = []

# Generar las curvas ROC para cada gen
for feature, color in zip(all_features, colors):
    X_feature = X[[feature]]  # Usar solo una característica
    
    # Dividir los datos para este gen
    X_train_feat, X_test_feat, y_train_feat, y_test_feat = train_test_split(
        X_feature, y, test_size=1 - train_proportion, random_state=42, stratify=y
    )
    
    # Entrenar el clasificador
    rf_classifier.fit(X_train_feat, y_train_feat)
    
    # Predecir probabilidades
    predictions_feat = rf_classifier.predict_proba(X_test_feat)[:, 1]
    
    # Calcular la curva ROC y el AUC
    fpr, tpr, _ = roc_curve(y_test_feat, predictions_feat)
    auc_feat = auc(fpr, tpr)
    auc_results.append((feature, auc_feat))
    
    # Graficar la curva ROC
    plt.plot(fpr, tpr, label=f'{feature} (AUC = {auc_feat:.2f})', color=color)

# Línea diagonal para el clasificador aleatorio
plt.plot([0, 1], [0, 1], color='red', linestyle='--', label='Clasificador Aleatorio')

# Personalizar el gráfico
plt.title('Curvas ROC para Genes Individuales', fontsize=14)
plt.xlabel('Tasa de Falsos Positivos (FPR)', fontsize=12)
plt.ylabel('Tasa de Verdaderos Positivos (TPR)', fontsize=12)
plt.legend(loc='lower right', fontsize=10)
plt.grid(alpha=0.3)
plt.tight_layout()

# Guardar y mostrar el gráfico
output_path = 'roc_curves_individual_features.svg'
plt.savefig(output_path, format='svg')
plt.show()

# Guardar los resultados del AUC en un archivo CSV
auc_results_df = pd.DataFrame(auc_results, columns=['Gen', 'AUC'])
print(auc_results_df)
auc_results_df.to_csv('feature_auc_scores.csv', index=False)
```

