Spaces:
Running on Zero
Running on Zero
Download CodonTransformer/CodonEvaluation.py from calvinmoody1/codontransformerstuff: direct link, hf CLI and curl.
- Browser
- Download file 8.51 kB
-
https://huggingface.co/spaces/calvinmoody1/codontransformerstuff/resolve/main/CodonTransformer/CodonEvaluation.py
- Command line
-
hf download hf://spaces/calvinmoody1/codontransformerstuff/CodonTransformer/CodonEvaluation.py
-
curl -L -o CodonEvaluation.py https://huggingface.co/spaces/calvinmoody1/codontransformerstuff/resolve/main/CodonTransformer/CodonEvaluation.py
8.51 kB
| """ | |
| File: CodonEvaluation.py | |
| --------------------------- | |
| Includes functions to calculate various evaluation metrics along with helper | |
| functions. | |
| """ | |
| from typing import Dict, List, Tuple | |
| import pandas as pd | |
| from CAI import CAI, relative_adaptiveness | |
| from tqdm import tqdm | |
| def get_CSI_weights(sequences: List[str]) -> Dict[str, float]: | |
| """ | |
| Calculate the Codon Similarity Index (CSI) weights for a list of DNA sequences. | |
| Args: | |
| sequences (List[str]): List of DNA sequences. | |
| Returns: | |
| dict: The CSI weights. | |
| """ | |
| return relative_adaptiveness(sequences=sequences) | |
| def get_CSI_value(dna: str, weights: Dict[str, float]) -> float: | |
| """ | |
| Calculate the Codon Similarity Index (CSI) for a DNA sequence. | |
| Args: | |
| dna (str): The DNA sequence. | |
| weights (dict): The CSI weights from get_CSI_weights. | |
| Returns: | |
| float: The CSI value. | |
| """ | |
| return CAI(dna, weights) | |
| def get_organism_to_CSI_weights( | |
| dataset: pd.DataFrame, organisms: List[str] | |
| ) -> Dict[str, dict]: | |
| """ | |
| Calculate the Codon Similarity Index (CSI) weights for a list of organisms. | |
| Args: | |
| dataset (pd.DataFrame): Dataset containing organism and DNA sequence info. | |
| organisms (List[str]): List of organism names. | |
| Returns: | |
| Dict[str, dict]: A dictionary mapping each organism to its CSI weights. | |
| """ | |
| organism2weights = {} | |
| # Iterate through each organism to calculate its CSI weights | |
| for organism in tqdm(organisms, desc="Calculating CSI Weights: ", unit="Organism"): | |
| organism_data = dataset.loc[dataset["organism"] == organism] | |
| sequences = organism_data["dna"].to_list() | |
| weights = get_CSI_weights(sequences) | |
| organism2weights[organism] = weights | |
| return organism2weights | |
| def get_GC_content(dna: str, lower: bool = False) -> float: | |
| """ | |
| Calculate the GC content of a DNA sequence. | |
| Args: | |
| dna (str): The DNA sequence. | |
| lower (bool): If True, converts DNA sequence to lowercase before calculation. | |
| Returns: | |
| float: The GC content as a percentage. | |
| """ | |
| if lower: | |
| dna = dna.lower() | |
| return (dna.count("G") + dna.count("C")) / len(dna) * 100 | |
| def get_cfd( | |
| dna: str, | |
| codon_frequencies: Dict[str, Tuple[List[str], List[float]]], | |
| threshold: float = 0.3, | |
| ) -> float: | |
| """ | |
| Calculate the codon frequency distribution (CFD) metric for a DNA sequence. | |
| Args: | |
| dna (str): The DNA sequence. | |
| codon_frequencies (Dict[str, Tuple[List[str], List[float]]]): Codon | |
| frequency distribution per amino acid. | |
| threshold (float): Frequency threshold for counting rare codons. | |
| Returns: | |
| float: The CFD metric as a percentage. | |
| """ | |
| # Get a dictionary mapping each codon to its normalized frequency | |
| codon2frequency = { | |
| codon: freq / max(frequencies) | |
| for amino, (codons, frequencies) in codon_frequencies.items() | |
| for codon, freq in zip(codons, frequencies) | |
| } | |
| cfd = 0 | |
| # Iterate through the DNA sequence in steps of 3 to process each codon | |
| for i in range(0, len(dna), 3): | |
| codon = dna[i : i + 3] | |
| codon_frequency = codon2frequency[codon] | |
| if codon_frequency < threshold: | |
| cfd += 1 | |
| return cfd / (len(dna) / 3) * 100 | |
| def get_min_max_percentage( | |
| dna: str, | |
| codon_frequencies: Dict[str, Tuple[List[str], List[float]]], | |
| window_size: int = 18, | |
| ) -> List[float]: | |
| """ | |
| Calculate the %MinMax metric for a DNA sequence. | |
| Args: | |
| dna (str): The DNA sequence. | |
| codon_frequencies (Dict[str, Tuple[List[str], List[float]]]): Codon | |
| frequency distribution per amino acid. | |
| window_size (int): Size of the window to calculate %MinMax. | |
| Returns: | |
| List[float]: List of %MinMax values for the sequence. | |
| Credit: https://github.com/chowington/minmax | |
| """ | |
| # Get a dictionary mapping each codon to its respective amino acid | |
| codon2amino = { | |
| codon: amino | |
| for amino, (codons, frequencies) in codon_frequencies.items() | |
| for codon in codons | |
| } | |
| min_max_values = [] | |
| codons = [dna[i : i + 3] for i in range(0, len(dna), 3)] # Split DNA into codons | |
| # Iterate through the DNA sequence using the specified window size | |
| for i in range(len(codons) - window_size + 1): | |
| codon_window = codons[i : i + window_size] # Codons in the current window | |
| Actual = 0.0 # Average of the actual codon frequencies | |
| Max = 0.0 # Average of the min codon frequencies | |
| Min = 0.0 # Average of the max codon frequencies | |
| Avg = 0.0 # Average of the averages of all frequencies for each amino acid | |
| # Sum the frequencies for codons in the current window | |
| for codon in codon_window: | |
| aminoacid = codon2amino[codon] | |
| frequencies = codon_frequencies[aminoacid][1] | |
| codon_index = codon_frequencies[aminoacid][0].index(codon) | |
| codon_frequency = codon_frequencies[aminoacid][1][codon_index] | |
| Actual += codon_frequency | |
| Max += max(frequencies) | |
| Min += min(frequencies) | |
| Avg += sum(frequencies) / len(frequencies) | |
| # Divide by the window size to get the averages | |
| Actual = Actual / window_size | |
| Max = Max / window_size | |
| Min = Min / window_size | |
| Avg = Avg / window_size | |
| # Calculate %MinMax | |
| percentMax = ((Actual - Avg) / (Max - Avg)) * 100 | |
| percentMin = ((Avg - Actual) / (Avg - Min)) * 100 | |
| # Append the appropriate %MinMax value | |
| if percentMax >= 0: | |
| min_max_values.append(percentMax) | |
| else: | |
| min_max_values.append(-percentMin) | |
| # Populate the last floor(window_size / 2) entries of min_max_values with None | |
| for i in range(int(window_size / 2)): | |
| min_max_values.append(None) | |
| return min_max_values | |
| def get_sequence_complexity(dna: str) -> float: | |
| """ | |
| Calculate the sequence complexity score of a DNA sequence. | |
| Args: | |
| dna (str): The DNA sequence. | |
| Returns: | |
| float: The sequence complexity score. | |
| """ | |
| def sum_up_to(x): | |
| """Recursive function to calculate the sum of integers from 1 to x.""" | |
| if x <= 1: | |
| return 1 | |
| else: | |
| return x + sum_up_to(x - 1) | |
| def f(x): | |
| """Returns 4 if x is greater than or equal to 4, else returns x.""" | |
| if x >= 4: | |
| return 4 | |
| elif x < 4: | |
| return x | |
| unique_subseq_length = [] | |
| # Calculate unique subsequences lengths | |
| for i in range(1, len(dna) + 1): | |
| unique_subseq = set() | |
| for j in range(len(dna) - (i - 1)): | |
| unique_subseq.add(dna[j : (j + i)]) | |
| unique_subseq_length.append(len(unique_subseq)) | |
| # Calculate complexity score | |
| complexity_score = ( | |
| sum(unique_subseq_length) / (sum_up_to(len(dna) - 1) + f(len(dna))) | |
| ) * 100 | |
| return complexity_score | |
| def get_sequence_similarity( | |
| original: str, predicted: str, truncate: bool = True, window_length: int = 1 | |
| ) -> float: | |
| """ | |
| Calculate the sequence similarity between two sequences. | |
| Args: | |
| original (str): The original sequence. | |
| predicted (str): The predicted sequence. | |
| truncate (bool): If True, truncate the original sequence to match the length | |
| of the predicted sequence. | |
| window_length (int): Length of the window for comparison (1 for amino acids, | |
| 3 for codons). | |
| Returns: | |
| float: The sequence similarity as a percentage. | |
| Preconditions: | |
| len(predicted) <= len(original). | |
| """ | |
| if not truncate and len(original) != len(predicted): | |
| raise ValueError( | |
| "Set truncate to True if the length of sequences do not match." | |
| ) | |
| identity = 0.0 | |
| original = original.strip() | |
| predicted = predicted.strip() | |
| if truncate: | |
| original = original[: len(predicted)] | |
| if window_length == 1: | |
| # Simple comparison for amino acid | |
| for i in range(len(predicted)): | |
| if original[i] == predicted[i]: | |
| identity += 1 | |
| else: | |
| # Comparison for substrings based on window_length | |
| for i in range(0, len(original) - window_length + 1, window_length): | |
| if original[i : i + window_length] == predicted[i : i + window_length]: | |
| identity += 1 | |
| return (identity / (len(predicted) / window_length)) * 100 | |