Блок 2, практикум 6, сигналы и мотивы.¶

1. Краткое описание одного интересного сигнала, закодированного в геноме.¶

Сигнал - последовательность PAM (Protospacer Adjacent Motif).¶

Короткая последовательность из 2-6 нуклеотидов (например, 5'-NGG-3' у Streptococcus pyogenes) [1], прилегающая к сайту разрезания ДНК комплексом из белка Cas9 и crRNA (или sgRNA в случае использования Cas9 в генетической инженерии). Таким образом, сигнал адресован белку Cas9, который сначала связывает ДНК (может связывать ДНК и без РНК), на которой есть PAM и только потом проверяет, комплементарна ли последовательность за ним последовательностм crRNA. В случае наличия PAM и комплементарности Cas9 разрезает ДНК. Сигнал высокоэффективен, что хорошо для бактерии, защищающейся от вирусов (вся ДНК с PAM будет проверена как потенциально опасная), но плохо для создания генетических сетей, где важно постоянное наличие мутантной версии Cas9 (отсутствует эндонуклеазная активность - dCas9) в клетке, т.к. тогда dCas9 неспецифично связывается с геномом во всех местах, где есть PAM (а таких мест много - 5.4e4 у E.Coli), при этом активно раскрывая двойную спираль ДНК, что делает Cas9 токсичным для клетки, поэтому количество молекул белка в клетке ниже, чем могло бы быть, и этого не всегда хватает для построения генетических схем. Утеря способности распознавать PAM сильно понижает токсичность Cas9 для клетки [2]. В то же время, согласно некоторым работам, неспецифичное связывание PAM важно для построения мультистабильных генетических схем (системы, имеющие два и более равновесных состояния) [3].

P.S. Сталкивался с этим сигналом и продолжаю с ним работать в курсовых (за прошлый и этот год), интересует меня в первую очередь из-за своей важности в дизайне генетических схем.

2. Построение и проверка позиционной весовой матрицы (PWM) для последовательности Козак человека.¶

Код для выполнения этого задания я взял у своего однокурсника, Дмитрия Звездина (изменен GC-состав). Авторские комментарии сохранены. Ссылка на код.¶

In [11]:
import numpy as np
import requests
import pandas as pd
from scipy.stats import mannwhitneyu
In [12]:
genes_table = pd.read_csv("human-genes.tsv", sep="\t")
sequences = []
i = 0
req_count = 0
while req_count < 100:
    chromosome = genes_table.loc[i, "#chrom"]
    start = genes_table.loc[i, "thickStart"]
    strand = genes_table.loc[i, "strand"]
    i += 1
    if str(strand) == "+":
        link = f"https://rest.ensembl.org/sequence/region/human/{chromosome}:{start-6}..{start+400}:1?expand_3prime=0;expand_5prime=0"
        request = requests.get(link, headers={ "Content-Type" : "text/x-fasta"})
    else:
        continue
    if "error" in request.text:
        continue
    else:
        req_count += 1
        sequence = "".join(request.text.split("\n")[1:])
        sequences.append(sequence)
        
with open("sequences.txt", "w") as file:
    print(*sequences, sep="\n", file=file)

С использованием кода выше было отобрано 100 генов человека на "+"-цепи; для простоты, были взяты участки от -7 нуклеотида от координаты старт-кодона до +400 нуклеотида после.

In [13]:
sequences_clear=[]
sequences_test_negative=[]
with open("sequences.txt", "r") as file:
    sequences = file.readlines()
    for sequence in sequences:
        sequence_ = sequence[:13]
        if sequence_[7:10] == "ATG":
            sequences_clear.append(sequence_)
        ATG_coord_fake = sequence[200:].find("ATG")
        sequences_test_negative.append(sequence[200:][ATG_coord_fake-7:ATG_coord_fake+6])
sequences_train = sequences_clear[:40]
sequences_test = sequences_clear[40:]
sequences_test_negative = [seq for seq in sequences_test_negative if len(seq) == 13]
sequences_test_negative = sequences_test_negative[:36]

Далее были вырезаны участки размером 13 нуклеотидов в начале генов, из них были отобраны участки, содержащие старт-кодон. Полученные последовательности были разделены на 40 для построения PWM, и 36 для теста. Негативный котроль был сформирован из участков вокруг кодонов AUG, удаленных минимум на 200 нуклеотидов от начала гена, таким образом не являющихся старт-кодонами.

In [14]:
class PWM():
    def __init__(self, e=1, freq=[0.295, 0.295, 0.205, 0.205]):
        self.e = e
        self.positions = {"A": 0, "T": 1, "G": 2, "C": 3}
        self.frequencies = np.array(freq).reshape((4, 1))
        
    def fit(self, seq_list):
        self.seq_arr = np.array(list(map(list, seq_list)), dtype="str")
        self.n_pos = len(seq_list[0])
        self.n_seq = len(seq_list)
        A_n = np.count_nonzero(self.seq_arr == "A", axis=0)
        T_n = np.count_nonzero(self.seq_arr == "T", axis=0)
        G_n = np.count_nonzero(self.seq_arr == "G", axis=0)
        C_n = np.count_nonzero(self.seq_arr == "C", axis=0)
        self.matrix = np.stack([A_n, T_n, G_n, C_n], axis=0).astype("float")
        pseudocount = self.e / 4
        self.matrix += pseudocount
        self.matrix = self.matrix / (self.n_seq+self.e)
        self.pwm_matrix = np.log(self.matrix / self.frequencies)
        
    def test(self, seq):
        weight = 0
        for i, nuc in enumerate(list(seq)):
            weight += self.pwm_matrix[self.positions[nuc], i]
        return weight
    
    def ic_calculate(self):
        self.ic_matrix = self.matrix * np.log2(self.matrix / self.frequencies)
        
    def return_pwm(self):
        return pd.DataFrame(self.pwm_matrix, columns = np.arange(1, self.n_pos + 1), index = ["A", "T", "G", "C"])
    
    def return_ic(self):
        return pd.DataFrame(self.ic_matrix, columns = np.arange(1, self.n_pos + 1), index = ["A", "T", "G", "C"])

PWM была реализована в виде класса с методами для построения PWM, вычисления весов тестовых последовательностей, вычисления матрицы информационного содержания и вывода матриц. Для вычисления базовых частот нуклеотидов был взят GC-состав 41 [4]

In [15]:
pwm = PWM()
pwm.fit(sequences_train)
real_scores = []
fake_scores = []
for seq, fake_seq in zip(sequences_test, sequences_test_negative):
    real_scores.append(pwm.test(seq))
    fake_scores.append(pwm.test(fake_seq))
pwm.return_pwm()
Out[15]:
1 2 3 4 5 6 7 8 9 10 11 12 13
A -2.269649 -0.268169 -0.834564 -0.660211 -0.165514 -0.382579 -0.511791 1.202318 -3.879087 -3.879087 -0.660211 -0.268169 -1.681862
T -0.382579 -0.511791 -1.314137 -1.314137 -1.681862 -0.834564 -1.045873 -3.879087 1.202318 -3.879087 -0.382579 -0.268169 -0.165514
G 0.718985 0.198451 0.595753 0.595753 0.879328 0.095797 -0.470599 -3.515121 -3.515121 1.566283 0.595753 0.198451 0.718985
C 0.527930 0.527930 0.718985 0.659266 -0.018614 0.775338 1.059590 -3.515121 -3.515121 -3.515121 0.291541 0.376699 0.291541

Матрица была построена на основании полученных ранее последовательностей и протестирована на положительном и отрицательном контроле, оба по 36 последовательностей. Ниже представлен результат непараметрического теста Манна-Уитни наборов полученных весов. Видно, что при уровне значимости 0.05, вес положительного контроля выше веса отрицательного.

In [16]:
print(f"Средний вес положительного контроля: {np.mean(real_scores)}, средний вес отрицательного контроля: {np.mean(fake_scores)}.")
print(mannwhitneyu(real_scores, fake_scores))
Средний вес положительного контроля: 5.649725552268244, средний вес отрицательного контроля: 4.693530936295868.
MannwhitneyuResult(statistic=483.0, pvalue=0.031966510996488576)

3. Вычисление информационного содержания сигнала старта трансляции - последовательности Козак из задания 2. и построение Logo¶

In [17]:
pwm.ic_calculate()
pwm.return_ic()
Out[17]:
1 2 3 4 5 6 7 8 9 10 11 12 13
A -0.099830 -0.087285 -0.154173 -0.145196 -0.059697 -0.111062 -0.130563 1.702848 -0.034124 -0.034124 -0.145196 -0.087285 -0.133157
T -0.111062 -0.130563 -0.150285 -0.150285 -0.133157 -0.154173 -0.156408 -0.034124 1.702848 -0.034124 -0.111062 -0.087285 -0.059697
G 0.436415 0.071576 0.319688 0.319688 0.626566 0.031181 -0.086936 -0.030922 -0.030922 2.218334 0.319688 0.071576 0.436415
C 0.264717 0.264717 0.436415 0.376968 -0.005403 0.497903 0.904149 -0.030922 -0.030922 -0.030922 0.115410 0.162376 0.115410

Выше представлена матрица информационного содержания для последовательностей, использованных для построения PWM. На рисунке ниже представлено LOGO для этих последовательностей (построено с учетом GC-состава в 41%)

In [24]:
Image(filename="logo.png") 
Out[24]:

Источники информации¶

  1. Importance of the PAM Sequence in CRISPR Experiments
  2. S. Zhang, C. Voigt. Engineered dCas9 with reduced toxicity in bacteria: implications for genetic circuit design. Nucleic Acids Research, 2018.
  3. J. Santos-Moreno et al. Multistable and dynamic CRISPRi-based synthetic circuits. Nature Communications, 2020.
  4. International Human Genome Sequencing Consortium. Initial sequencing and analysis of the human genome. Nature 2001, 409, 860–921.