3S
  • Portfolio Top
  • Categories
  • Tags
  • Archives

マイクロアレイ実習2

マイクロアレイデータ解析2¶

〜マイクロアレイを用いた網羅的遺伝子発現解析〜

  • 担当:程研究室
  • 実習のwiki:http://bit.ly/microarray-2019
  • 論文:Functional dissection of siRNA sequence by systematic DNA substitution: Modified siRNA with a DNA seed arm is a powerful tool for mammalian gene silencing with significantly reduced off-target effect

Index

  1. 全データを読み込む
  2. mRNAの配列を調べる
  3. AWSにインスタンスを立て並列処理
  4. NCBIの結果を統合する
  5. 相関関係を調べる
  6. seedmatchの結果と比べる
  7. モデルを作成する
  8. まとめ

【目的】¶

 「siRNAを導入した際にどのようなmRNAが発現抑制されるか」について様々な予測がされているが、確定的な理論は存在しない。

 そこで、どういった特徴を持ったmRNA(配列)が(この実験系では・マイクロアレイ解析の結果上は)抑制されるのか調べる。

In [1]:
! python --version
Python 3.6.8 :: Anaconda, Inc.
In [2]:
# 見栄えの問題
import warnings
warnings.filterwarnings('ignore')

1. 全データを読み込む

 マイクロアレイ解析1で行なった前処理後のデータを読み込む。

In [3]:
import pandas as pd
In [4]:
df = pd.read_excel("result.xlsx")
In [5]:
df.head(3)
Out[5]:
FeatureNum ControlType ProbeName GeneName SystematicName mock(1) RNA 2OMe3 2OMe5 mock(5) 2OMe7 LNA3 LNA7
3 4 0 A_23_P117082 HEBP1 NM_015987 12566.870 12356.960 12896.740 12860.240 12416.270 13869.810 14213.960 13553.84
8 9 0 A_21_P0000509 SNAR-G2 NR_024244 122723.700 117958.900 118623.000 128495.100 117447.400 124273.000 113802.500 107326.70
9 10 0 A_21_P0000744 LOC100506844 NR_038269 1234.146 1281.739 1128.132 1199.297 1251.119 1141.723 1302.718 1264.15
In [6]:
print("データ数: {}".format(len(df)))
データ数: 21511

2. mRNAの配列を調べる

 Home - Nucleotide - NCBI のデータベースにアクセスし、塩基配列データを取得する。こちらも、もちろん $21511$ の塩基配列を取得するのは骨が折れるので、プログラム化する。なお、GeneName(ex.`NM_015987`) から id(ex.`1519241814`) を取得し、そのidを用いて新たにクエリを投げないと(僕の頭では)塩基配列を取得できなかった ので、二回リクエストを送っている。(idの部分にGeneNameを入れてもうまく検索ができた。)

 また、リクエストを送った時にうまく try 内が処理できる場合と処理ができない場合(except)があるが、リクエストごとに決まっている訳ではなく、送るタイミングによってうまく処理できたりできなかったりしていた。

 が、ほとんどの場合 "No items found"と出ていたので、今回は深追いしない:(

In [7]:
import re
import requests
from tqdm import tqdm
In [8]:
guide_match_array = "gagttca"
In [9]:
front_patterns =r'<meta name="ncbi_uidlist" content="(.+)" /><meta name="ncbi_filter"'
In [10]:
back_request_format = "https://www.ncbi.nlm.nih.gov/sviewer/viewer.fcgi?id={}&db=nuccore&report=genbank&conwithfeat=on&hide-cdd=on&retmode=html&withmarkup=on&tool=portal&log$=seqview&maxdownloadsize=1000000"
In [11]:
back_patterns = ">([atgc ]*)</span>"
In [12]:
def gene2array(GeneName):
    try:
        #=== httpリクエストを飛ばしてプログラムで検索を行う ===
        front_response = requests.get('https://www.ncbi.nlm.nih.gov/nuccore/', params={'term': GeneName})
        genome_id = re.findall(front_patterns, front_response.text)[0]  # ex) 1519241814
        back_response = requests.get(back_request_format.format(genome_id))
        sequences = re.findall(back_patterns, back_response.text) # ex) ['atgcatgcat gcatgca...', 'at..', .., '..atgc']
        sequence = "".join(sequences).replace(" ","")
        
        #=== 配列の長さ ===
        length = len(sequence)
        
        #=== seed領域と一致するポジションの5'末端からの割合 ===
        position = re.search(guide_match_array, sequence)
        p = position.end()/length if position else 0
        
        return [sequence,length,p]
    except:
        return [None, None, None]
In [13]:
# GeneNameを全て調べる。
gene_names = df.SystematicName.values
In [14]:
sample_gene_name = gene_names[17]
In [15]:
print("sample gene name: {}".format(sample_gene_name))
sample gene name: NM_000147
In [16]:
gene2array(sample_gene_name)
Out[16]:
['cgggccaatcgttagtcagagtgggcggagccgcccgcgggcacctgcgcgttaagagtgggccgcgtcgctgaggggtagcgatgcgggctccggggatgaggtcgcggccggcgggtcccgcgctgttgctgctgctgctcttcctcggagcggccgagtcggtgcgtcgggcccagcctccgcgccgctacaccccagactggccgagcctggattctcggccgctgccggcctggttcgacgaagccaagttcggggtgttcatccactggggcgtgttctcggtgcccgcctggggcagcgagtggttctggtggcactggcagggcgaggggcggccgcagtaccagcgcttcatgcgcgacaactacccgcccggcttcagctacgccgacttcggaccgcagttcactgcgcgcttcttccacccggaggagtgggccgacctcttccaggccgcgggcgccaagtatgtagttttgacgacaaagcatcacgaaggcttcacaaactggccgagtcctgtgtcttggaactggaactccaaagacgtggggcctcatcgggatttggttggtgaattgggaacagctctccggaagaggaacatccgctatggactataccactcactcttagagtggttccatccactctatctacttgataagaaaaatggcttcaaaacacagcattttgtcagtgcaaaaacaatgccagagctgtacgaccttgttaacagctataaacctgatctgatctggtctgatggggagtgggaatgtcctgatacttactggaactccacaaattttctttcatggctctacaatgacagccctgtcaaggatgaggtggtagtaaatgaccgatggggtcagaactgttcctgtcaccatggaggatactataactgtgaagataaattcaagccacagagcttgccagatcacaagtgggagatgtgcaccagcattgacaagttttcctggggctatcgtcgtgacatggcattgtctgatgttacagaagaatctgaaatcatttcggaactggttcagacagtaagtttgggaggcaactatcttctgaacattggaccaactaaagatggactgattgttcccatcttccaagaaaggcttcttgctgttgggaaatggctgagcatcaatggggaggctatctatgcctccaaaccatggcgggtgcaatgggaaaagaacacaacatctgtatggtatacctcaaagggatcggctgtttatgccatttttctgcactggccagaaaatggagtcttaaaccttgaatcccccataactacctcaactacaaagataacaatgctgggaattcaaggagatctgaagtggtccacagatccagataaaggtctcttcatctctctaccccagttgccaccctctgctgtccccgcagagtttgcttggactataaagctgacaggagtgaagtaatcatttgagtgcaagaagaaagaggcgctgctcactgttttcctgcttcagtttttctcttatagtaccatcactataatcaacgaacttctcttctccacccagagatggcttttccaacacattttaattaaaggaactgagtacattaccctgatgtctaaatggaccaaagatctgagatccattgtgattatatctgtatcaggtcagcagaagaaggaactgagcagttgaactctgagttcatcaattgtaatatttggaaattatctacaatggaatcttccctctgttctctgataacctacttgcttactcaatgcctttaagccaagtcaccctgttgcctatgggaggaggtggaaggatttggcaagctcaaccacatgctatttagttagcatcagttgtcaccaacagtctttctgcaaagggcaggagagctttgggggaaaggaaaaggcttaccaggctgctatggtcaactcttcagaaattttcagagcaatctaaaagcgccaaaattcgctatgtttacagtgatactattaagaaaatgaatgtgattctgctctgtctttttaagtatgatcaaataaaaaatttgtacatcacaatcatttctaccaaaaaaaaaaaaaaaaaa',
 2133,
 0.8124706985466479]

「塩基配列・塩基配列長・シードマッチ領域の5'末端からの割合」が記録されていることがわかる。

 うまくプログラムが実行できていることがわかったので、以下を実行して $21511$ データ分の配列を入手する。

lst = []
for genome in tqdm(gene_names):
    lst.append(gene2array(genome))
df_output = pd.DataFrame(lst)
df_output.columns=['sequence','length','position']
df_output.to_csv('seeqences.csv')

 二時間ほど回したが、以下のような出力が出ていた…。(現在時刻 6/20 20:36)

9%|▉         | 1963/21511 [1:55:43<19:12:28,  3.54s/it]
9%|▉         | 1964/21511 [1:55:45<19:12:04,  3.54s/it]
9%|▉         | 1965/21511 [1:55:50<19:12:17,  3.54s/it]
9%|▉         | 1966/21511 [1:55:54<19:12:17,  3.54s/it]
9%|▉         | 1967/21511 [1:55:56<19:11:56,  3.54s/it]
9%|▉         | 1968/21511 [1:56:00<19:12:05,  3.54s/it]

明日のプレゼン開始時にデータ収集が終わるんだけど解析とは?? pic.twitter.com/0aOb3BVIDF

— しゅーと (@cabernet_rock) 2019年6月20日


3. AWSにインスタンスを立て並列処理

 6/21(金)のプレゼンテーションに間に合いそうにないので、急遽 [AWS](https://aws.amazon.com/jp/) でEC2インスタンスを複数台(計 $11$ 個)立てて並列処理を行うことにした。

 まず、以下の main.py ファイルと result.xlsx を格納した microarray というディレクトリを準備した。

main.py¶

#coding:utf-8
import argparse
import numpy as np
import pandas as pd
import re
import requests
from tqdm import tqdm

def gene2array(GeneName):
    try:
        #=== httpsリクエストを飛ばして検索を行う ===
        front_response = requests.get('https://www.ncbi.nlm.nih.gov/nuccore/', params={'term': GeneName})
        genome_id = re.findall(front_patterns, front_response.text)[0]
        back_response = requests.get(back_request_format.format(genome_id))
        sequences = re.findall(back_patterns, back_response.text)
        sequence = "".join(sequences).replace(" ","")

        #=== 配列の長さ ===
        length = len(sequence)

        #=== seed領域と一致するポジションを調べる ===
        position = re.search(guide_match_array, sequence)
        p = position.end()/length if position else 0

        return [sequence,length,p]
    except:
        return [None, None, None]

if __name__ == "__main__":
  parser = argparse.ArgumentParser()
  parser.add_argument('--begin', type=int)
  parser.add_argument('--end',   type=int)
  args = parser.parse_args()

  #=== パラメータ定義 ===
  guide_match_array = "gagttca"
  front_patterns =r'<meta name="ncbi_uidlist" content="(.+)" /><meta name="ncbi_filter"'
  back_request_format = "https://www.ncbi.nlm.nih.gov/sviewer/viewer.fcgi?id={}&db=nuccore&report=genbank&conwithfeat=on&hide-cdd=on&retmode=html&withmarkup=on&tool=portal&log$=seqview&maxdownloadsize=1000000"
  back_patterns = ">([atgc ]*)</span>"

  begin = args.begin
  end   = args.end
  df    = pd.read_excel("result.xlsx")[begin:end]

  print("{} ~ {}".format(begin, end))
  gene_names = df.SystematicName.values

  lst = []
  for genome in tqdm(gene_names): 
      lst.append(gene2array(genome))

  df_output = pd.DataFrame(lst)
  df_output.columns = ["sequence","length","p"]
  df_output.to_csv('sequence{:05}to{:05}.csv'.format(begin,end), index=False)
  print("finished.")
In [17]:
# 階層構造は以下の通り。
! tree microarray
microarray
├── main.py
├── main2.py
└── result.xlsx

0 directories, 3 files

データを送信する¶

 上記のディレクトリを scp コマンドでEC2インスタンスに転送し、プログラムが実行できる環境を構築する。諸々の準備が整い、後は実行するだけとなったらAmazon マシンイメージ (AMI) を取り、イメージを取得する。このイメージを元にEC2インスタンスを作成することで、かなりの作業を省略することができる。

# ローカルのデータをそれぞれのEC2インスタンスに送る。
$ scp -r -i ~/.ssh/ShutoBioinfo.pem microarray ubuntu@ec2-3-113-33-209.ap-northeast-1.compute.amazonaws.com:/home/ubuntu/
$ ssh -i "path/to/key.pem" ubuntu@ec2-3-113-33-209.ap-northeast-1.compute.amazonaws.com

----------------------------------------------------------------
Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-1041-aws x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

----------------------------------------------------------------

             環 境 構 築

----------------------------------------------------------------

             A M I 取 得

----------------------------------------------------------------

ubuntu@ip-172-31-45-117:~$ cd microarray/
ubuntu@ip-172-31-45-117:~/microarray$ nohup python main.py --begin 0 --end 2000 > Logger.log

インスタンス情報とコマンド作成プログラム¶

 以下のインスタンスを作成してプログラムを実行した。この時、一々コピーアンドペーストするのは面倒なので、スクレイピングをしている間にコマンドを準備しておく。

# パブリック DNS (IPv4) args
1 ec2-3-113-33-209.ap-northeast-1.compute.amazonaws.com --begin 0 --end 2000
2 ec2-3-112-149-206.ap-northeast-1.compute.amazonaws.com --begin 2000 --end 4000
3 ec2-3-112-213-203.ap-northeast-1.compute.amazonaws.com --begin 4000 --end 6000
4 ec2-13-113-177-99.ap-northeast-1.compute.amazonaws.com --begin 6000 --end 8000
5 ec2-54-249-50-45.ap-northeast-1.compute.amazonaws.com --begin 8000 --end 10000
6 ec2-13-231-179-134.ap-northeast-1.compute.amazonaws.com --begin 10000 --end 12000
7 ec2-13-115-166-8.ap-northeast-1.compute.amazonaws.com --begin 12000 --end 14000
8 ec2-3-112-73-40.ap-northeast-1.compute.amazonaws.com --begin 14000 --end 16000
9 ec2-52-198-222-27.ap-northeast-1.compute.amazonaws.com --begin 16000 --end 18000
10 ec2-13-115-220-149.ap-northeast-1.compute.amazonaws.com --begin 18000 --end 20000
11 ec2-18-182-16-178.ap-northeast-1.compute.amazonaws.com --begin 20000 --end 22000
In [18]:
publicDNSs = [
    "3-113-33-209","3-112-149-206","3-112-213-203",
    "13-113-177-99","54-249-50-45","13-231-179-134",
    "13-115-166-8","3-112-73-40","52-198-222-27",
    "13-115-220-149","18-182-16-178"
]
In [19]:
begins = [  i  * 2000 for i in range(11)]
ends   = [(i+1)* 2000 for i in range(11)]
# ssh接続からプログラム実行まで
for p,b,e in zip(publicDNSs, begins,ends):
    print(
        " ssh -i 'path/to/key.pem' ubuntu@ec2-{}.ap-northeast-1.compute.amazonaws.com\n".format(p),
        "cd microarray\n",
        "nohup python main.py --begin {} --end {} > Logger.log &\n".format(b,e),
        "exit"
    )

4. NCBIの結果を統合する

 無事それぞれがスクレイピングを完了したので、結果を統合する。なお、EC2インスタンスからデータを取得するのは、ローカルから以下のコマンドを実行するだけで可能である。

# 結果をEC2からリモートに送る
for p,b,e in zip(publicDNSs, begins,ends):
    print("scp -i 'path/to/key.pem' ubuntu@ec2-{}.ap-northeast-1.compute.amazonaws.com:/home/ubuntu/microarray/sequence{:05}to{:05}.csv .".format(p,b,e))

※ 本来ならうまくスクレイピングできなかったデータに関してはもう一度リクエストを飛ばすなりの作業を行ってデータを集める必要があるが、"No items found" とリスポンスが返ってきてしまっていたデータがかなりあったので今回は2回目だけ行い、それ以降は深追いしなかった:(

In [20]:
# 以下のファイルが作られた。
! tree AWS
AWS
├── sequence00000to02000.csv
├── sequence02000to04000.csv
├── sequence04000to06000.csv
├── sequence06000to08000.csv
├── sequence08000to10000.csv
├── sequence10000to12000.csv
├── sequence12000to14000.csv
├── sequence14000to16000.csv
├── sequence16000to18000.csv
├── sequence18000to20000.csv
└── sequence20000to22000.csv

0 directories, 11 files
In [21]:
import os
In [22]:
file_names = [name for name in sorted(os.listdir("AWS")) if name[-4:] == ".csv"]
In [23]:
# 確認
file_names
Out[23]:
['sequence00000to02000.csv',
 'sequence02000to04000.csv',
 'sequence04000to06000.csv',
 'sequence06000to08000.csv',
 'sequence08000to10000.csv',
 'sequence10000to12000.csv',
 'sequence12000to14000.csv',
 'sequence14000to16000.csv',
 'sequence16000to18000.csv',
 'sequence18000to20000.csv',
 'sequence20000to22000.csv']
In [24]:
df_all = pd.DataFrame()
for filename in file_names:
    tmp = pd.read_csv(os.path.join('AWS',filename))
    df_all = pd.concat([df_all,tmp])
In [25]:
# 結合
df_cocated = pd.concat([df_all[['sequence','length','p']].reset_index(drop=True),df.reset_index(drop=True)], axis=1)
In [26]:
df_cocated.head(3)
Out[26]:
sequence length p FeatureNum ControlType ProbeName GeneName SystematicName mock(1) RNA 2OMe3 2OMe5 mock(5) 2OMe7 LNA3 LNA7
0 NaN NaN NaN 4 0 A_23_P117082 HEBP1 NM_015987 12566.870 12356.960 12896.740 12860.240 12416.270 13869.810 14213.960 13553.84
1 NaN NaN NaN 9 0 A_21_P0000509 SNAR-G2 NR_024244 122723.700 117958.900 118623.000 128495.100 117447.400 124273.000 113802.500 107326.70
2 ggaggagttacgcaggcagggttgtggttgctggctgttaccagga... 711.0 0.0 10 0 A_21_P0000744 LOC100506844 NR_038269 1234.146 1281.739 1128.132 1199.297 1251.119 1141.723 1302.718 1264.15
In [27]:
# かなりNaN(配列データが取得できなかったもの)が多い
df_cocated.isnull().sum()
Out[27]:
sequence          13890
length            13888
p                 13888
FeatureNum            0
ControlType           0
ProbeName             0
GeneName              0
SystematicName        0
mock(1)               0
RNA                   0
2OMe3                 0
2OMe5                 0
mock(5)               0
2OMe7                 0
LNA3                  0
LNA7                  0
dtype: int64

5. 相関関係を調べる

 ここまでで集めたデータの特徴量と log2(siRNA/mock) の相関関係を調べる。

In [28]:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
In [29]:
df_cocated["mock"] = df_cocated[["mock(1)","mock(5)"]].mean(axis=1)
In [30]:
df_cocated["log2(siRNA/mock)"] = np.log2(df_cocated["RNA"]/df_cocated["mock"])
In [31]:
# 正しく配列データが取得できたものだけを利用する。
df_used = df_cocated[df_cocated.length>0].reset_index(drop=True)
In [32]:
print("取得できたmRNA: {}".format(len(df_used)))
取得できたmRNA: 7621
In [33]:
# 取得したmRNAの配列の長さの分布
plt.hist(df_used.length)
plt.title("The histgram of the length of mRNA")
plt.xlabel("length")
plt.ylabel("N")
plt.show()
In [34]:
print("7merマッチ出現量の期待値: {}".format(df_used.length.sum()/(4**7)))
7merマッチ出現量の期待値: 1662.5132446289062
In [35]:
# 取得した配列の発現量の分布
plt.hist(df_used["log2(siRNA/mock)"], bins=20)
plt.title("The histgram of the expression level of mRNA")
plt.xlabel("expression level")
plt.ylabel("N")
plt.show()
In [36]:
# シード領域とマッチする領域の出てくる場所の割合
def match_rate(match_array, array, length, rate=False):
    position = re.search(match_array, array)
    if position:
        p = position.end()/length if rate else position.end()
    else:
        p = 0
    return p
In [37]:
# うまく取得できていなかったので、これらのデータを利用
df_used["position"] = df_used.apply(lambda x: match_rate('gagttca', x.sequence, x.length), axis=1)
In [38]:
df_used["position_rate"] = df_used.apply(lambda x: match_rate('gagttca', x.sequence, x.length, rate=True), axis=1)
In [39]:
df_used[["length","log2(siRNA/mock)"]].corr()
Out[39]:
length log2(siRNA/mock)
length 1.000000 -0.084781
log2(siRNA/mock) -0.084781 1.000000
In [40]:
df_used_with_seed = df_used[df_used.position>0]
In [41]:
print("取得できたマッチ領域を含むmRNA: {}".format(len(df_used_with_seed)))
取得できたマッチ領域を含むmRNA: 1930

↑seedmatchで調べた時と数が異なっている…。こんなに多いはずがない??

In [42]:
df_used_with_seed[["length","position","position_rate","log2(siRNA/mock)"]].corr()
Out[42]:
length position position_rate log2(siRNA/mock)
length 1.000000 0.616134 -0.064294 0.061601
position 0.616134 1.000000 0.615967 0.040860
position_rate -0.064294 0.615967 1.000000 -0.056128
log2(siRNA/mock) 0.061601 0.040860 -0.056128 1.000000
In [43]:
sns.heatmap(
    df_used_with_seed[["length","position","position_rate","log2(siRNA/mock)"]].corr(),
    vmin=-1.0,
    vmax=1.0,
    center=0,
    annot=True, # True:格子の中に値を表示
    fmt='.3f',
)
plt.show()

 長さ・マッチ領域の割合はほとんど関係がない😱😱😱

6. seedmatchの結果と比べる

 シード領域とマッチする領域の数が異なっていたので、seedmatchの結果をもう一度参照し、比較する。

 ※なお、取得できたデータに対してのみ行なっていることに注意!!

seedmatch¶

In [44]:
def seedmatchNmer(df, N, match_array, arrayname="", return_data=False):
    """
    関数の概要:色々な領域のNmerの発現量を調べる。
    @param df         :元となるデータフレーム 
    @param N          :領域の長さ
    @param match_array:ガイド鎖やパッセンジャー鎖のシード領域と相補的なmRNAの配列(5'-3')
    """
    PATTERNS = r'\n(.+)\t([0-9]+)'
    GMEANS = []
    COLNAMES = []
    LENGTH = len(match_array)
    df_Nmer = df.sort_values(by="log2(siRNA/mock)")
    plt.figure(figsize=(12,8))
    
    for p in reversed(range(len(match_array)+1)):
        colname = "{}-{}mer({}-{})".format(arrayname, N,LENGTH-p+1,LENGTH-p+N)
        COLNAMES.append(colname)

        # "seedmatch"にリクエスト飛ばしてseed領域に対応する配列を検索
        array = match_array[p-N:p]
        r = requests.post('http://atlas.rnai.jp/seedmatch/seedmatch.cgi', data={"seedseq": array})
        df_mRNA = pd.DataFrame(re.findall(PATTERNS, r.text))
        df_mRNA.columns=["SystematicName", colname]

        # マージ
        df_Nmer = pd.merge(df_Nmer, df_mRNA, on="SystematicName", how="left").fillna(0)
        # マッチする配列を持っているものを抜き出して
        signal_7mer = df_Nmer[df_Nmer[colname]!=0]["log2(siRNA/mock)"].values
        GMEANS.append(np.mean(signal_7mer))
        length = len(signal_7mer)
        # 累積密度をプロット
        plt.plot(signal_7mer,[(i+1)/length for i in range(length)], label=colname + ": {}".format(length))

        if p-N==0: break
    
    #=== プロット後処理 ===
    plt.title('The difference between\n"seed match resions" and "Expression levels"')
    plt.xlabel("$\log_{2}(siRNA/mock)$")
    plt.ylabel("Cumulative frequency")
    plt.grid()
    plt.vlines(x=0, ymin=0, ymax=1, colors='black', linewidths=2)
    plt.legend()
    plt.xlim(-1,1)
    plt.show()
    
    #===  ===
    X = [i for i in range(len(GMEANS))]
    label_before = [i for i in range(len(GMEANS)) if i %2 == 0]
    label_after  = ["{}-{}".format(p+1,p+N) for p in range(len(GMEANS)) if p %2 == 0]

    plt.barh(X,GMEANS)
    plt.title('The difference between\n"seed match resions" and "Expression levels"')
    plt.xlabel("7mer position")
    plt.ylabel("average $\log_{2}(siRNA/mock)$")
    plt.yticks(label_before,label_after)
    plt.show()
    
    if return_data: 
        return (df_Nmer, COLNAMES)
In [45]:
guide_array   = "UUGAACUCGGUGUUGAUGGCG" # 5'-3'
g_match_array = "CGCCATCAACACCGAGTTCAA" # 5'-3'
In [46]:
seedmatchNmer(df_used_with_seed, 7, g_match_array, arrayname="guide", return_data=False)

 どの7merにも抑制傾向がある…。

NCBI¶

In [47]:
def seedNCBINmer(df, N, match_array, arrayname="", return_data=False):
    """
    関数の概要:色々な領域のNmerの発現量を調べる。
    @param df         :元となるデータフレーム 
    @param N          :領域の長さ
    @param match_array:ガイド鎖やパッセンジャー鎖のシード領域と相補的なmRNAの配列(5'-3')
    """
    GMEANS = []
    COLNAMES = []
    LENGTH = len(match_array)
    df_Nmer = df.sort_values(by="log2(siRNA/mock)")
    plt.figure(figsize=(12,8))
    
    for p in reversed(range(len(match_array)+1)):
        array = match_array[p-N:p]
        colname = "{}-{}mer({}-{})".format(arrayname, N,LENGTH-p+1,LENGTH-p+N)
        COLNAMES.append(colname)
        
        df_Nmer[colname] = df_Nmer.apply(lambda x: match_rate(array, x.sequence, x.length), axis=1)

        # マッチする配列を持っているものを抜き出して
        signal_7mer = df_Nmer[df_Nmer[colname]>0]["log2(siRNA/mock)"].values
        GMEANS.append(np.mean(signal_7mer))
        length = len(signal_7mer)
        # 累積密度をプロット
        plt.plot(signal_7mer,[(i+1)/length for i in range(length)], label=colname + ": {}".format(length))

        if p-N==0: break
    
    #=== プロット後処理 ===
    plt.title('The difference between\n"seed match resions" and "Expression levels"')
    plt.xlabel("$\log_{2}(siRNA/mock)$")
    plt.ylabel("Cumulative frequency")
    plt.grid()
    plt.vlines(x=0, ymin=0, ymax=1, colors='black', linewidths=2)
    plt.legend()
    plt.xlim(-1,1)
    plt.show()
    
    #===  ===
    X = [i for i in range(len(GMEANS))]
    label_before = [i for i in range(len(GMEANS)) if i %2 == 0]
    label_after  = ["{}-{}".format(p+1,p+N) for p in range(len(GMEANS)) if p %2 == 0]

    plt.barh(X,GMEANS)
    plt.title('The difference between\n"seed match resions" and "Expression levels"')
    plt.xlabel("7mer position")
    plt.ylabel("average $\log_{2}(siRNA/mock)$")
    plt.yticks(label_before,label_after)
    plt.show()
    
    if return_data: 
        return (df_Nmer, COLNAMES)
In [48]:
df_guide_7mer, guide_7mer_colnames = seedNCBINmer(df_used, 7, g_match_array.lower(), "guide", return_data=True)

7. モデルを作成する

 モデルに予測させてみて、「どの特徴量を参考にした??」って聞けば、変数の重要度がわかるという流れ。今回は解釈のしやすい決定木を用いてパラメータも適当に決めてサクッと学習させてみた。

In [49]:
feature_columns = guide_7mer_colnames+["length","position","position_rate"]
In [50]:
# 相関関係を調べる。
sns.heatmap(
    df_guide_7mer[feature_columns].corr(),
    vmin=-1.0,
    vmax=1.0,
    center=0,
    fmt='.3f',
)
plt.show()
In [51]:
from sklearn.ensemble import RandomForestRegressor
from sklearn import preprocessing

tree = RandomForestRegressor(random_state=0, max_depth=15)

X = df_guide_7mer[feature_columns].values.astype(float)
y = df_guide_7mer["log2(siRNA/mock)"].values.reshape(-1,1).astype(float)
/Users/iwasakishuto/.pyenv/versions/anaconda3-5.0.1/lib/python3.6/site-packages/sklearn/ensemble/weight_boosting.py:29: DeprecationWarning: numpy.core.umath_tests is an internal NumPy module and should not be imported. It will be removed in a future NumPy release.
  from numpy.core.umath_tests import inner1d
# 標準化
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
X_std = ss.fit_transform(X)
y_std = ss.fit_transform(y)
In [52]:
tree.fit(X, y)
Out[52]:
RandomForestRegressor(bootstrap=True, criterion='mse', max_depth=15,
           max_features='auto', max_leaf_nodes=None,
           min_impurity_decrease=0.0, min_impurity_split=None,
           min_samples_leaf=1, min_samples_split=2,
           min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1,
           oob_score=False, random_state=0, verbose=0, warm_start=False)
In [53]:
plt.scatter(y,tree.predict(X), s=0.3)
plt.title('predicted "$\log_2(siRNA/mock)$" and answer "$\log_2(siRNA/mock)$"')
plt.ylabel("answer")
plt.xlabel("predict")
plt.show()
In [54]:
n_features = len(feature_columns)
plt.figure(figsize=(12, 8))
plt.barh(range(n_features), tree.feature_importances_ , align='center')
plt.yticks(np.arange(n_features), feature_columns)
plt.title("importances for predict the Expression levels")
plt.show()

 どちらにせよ2-8の7merが重要そうだが、mRNAの長さにも依存関係がありそう。

 かなり深い木を使っていることもあり、その結果比較的プロットがうまくいっているので、一つのパラメータで語るのが難しい分野であると考えられる、


8. まとめ

 今回はほとんど考察をせずに必要そうな特徴量を

  • 「mRNAの長さ」
  • 「シード配列のポジション(割合/絶対値)」

に限って考えてしまった。もっと他の特徴量も考察したかった。

 また、「mRNAに対する抑制度合い」を予測するのであれば、もちろんデータを分割して汎化性能を求める必要がある。

※NCBIのプログラムに関しては目検でデータを確認していないので、それも確認が必要かと思います。

In [ ]:
 

  • « 分子進化学 第7回
  • 生体物質化学Ⅱ 第9回 »
hidden
Table of Contents
Published
Jun 21, 2019
Last Updated
Jun 21, 2019
Category
生命科学基礎実験
Tags
  • 3S 95
  • 生命科学基礎実験 14
Contact
Other contents
  • Home
  • Blog
  • Front-End
  • Kerasy
  • Python-Charmers
  • Translation-Gummy
    • 3S - Shuto's Notes
    • MIT
    • Powered by Pelican. Theme: Elegant