2012年10月14日日曜日

R: wigもつくる

せっかく自動でgffをつくったので、wigもつくってみる。
まず、前回の「gff.gen()」に若干の修正を加えてgffを得る。


gffをつくる関数

gff.gen <- function(n=1000,chrnum=3,type="protein_coding"){
chrs <- paste("chr",1:chrnum,sep="")
source <- "R"
type <- type
dots <- rep(".",n)
chr <- sample(chrs,n,replace=T)
start <- sample(1:9990000,n)
end <- start+1500+(round(rnorm(n)/2*500))
strand <- sample(c("+","-"),n,replace=T,prob=c(0.5,0.5))
id <- paste("gene",1:n,sep="")
gff <- data.frame(chr,source,type,start,end,dots,strand,dots,id)
return(gff)
}

gffをつくってソート

gff <- gff.gen(1000,3,"protein_coding")
gff <- sort.left(gff)


このgffの中の一部の遺伝子の5'末端にふくらみのあるwigをつくる。

# wigをつくる関数(上のgffがあることが前提)
wig.gen <- function(chrnum=3){

# chrの名前をつくる
chrs <- paste("chr",1:chrnum,sep="")

# chr毎に作業する
for (i in 1:length(chrs)){
chr <- chrs[i]

# headerをつくる
wig.head1 <- paste("track type=wiggle_0 name=\"",chr,"\" description=\"generated by R\"",sep="")
wig.head2 <- paste("variableStep chrom=",chr," span=10",sep="")
wig.head <- c(wig.head1,wig.head2)
wig.head.file <- paste("head_",chr,".txt",sep="")
write(wig.head,file=wig.head.file)

# bodyをつくる
n <- 10000000
step <- 10
pos <- seq(1,n,step)
depth <- round(rnorm(1:length(pos),100,sd=2))
wig.body <- cbind(pos,depth)

# chr毎のgffをつくる
assign(paste("gff.",chr,".fw",sep=""),gff[gff$chr==chr&gff$strand=="+",])
assign(paste("gff.",chr,".rv",sep=""),gff[gff$chr==chr&gff$strand=="-",])

# bodyに変化を加える
y.rep <- nrow(get(paste("gff.",chr,".fw",sep="")))%/%5
for(y in 1:y.rep) {
tss <- sample(get(paste("gff.",chr,".fw",sep=""))[,4],1)%/%10
upst <- tss-19
dnst <- tss+20
hight <- sample(1:2000,1)
add.tag.upst <- round((cos(seq(1*pi,0,length=20))+1)*hight)
add.tag.dnst <- round((cos(seq(0,1*pi,length=20))+1)*hight)
wig.body[upst:tss,2] <- wig.body[upst:tss,2]+add.tag.upst
wig.body[(tss+1):dnst,2] <- wig.body[(tss+1):dnst,2]+add.tag.dnst
tss <- sample(get(paste("gff.",chr,".rv",sep=""))[,5],1)%/%10
upst <- tss-19
dnst <- tss+20
hight <- sample(1:2000,1)
add.tag.upst <- round((cos(seq(1*pi,0,length=20))+1)*hight)
add.tag.dnst <- round((cos(seq(0,1*pi,length=20))+1)*hight)
wig.body[upst:tss,2] <- wig.body[upst:tss,2]+add.tag.upst
wig.body[(tss+1):dnst,2] <- wig.body[(tss+1):dnst,2]+add.tag.dnst
}

# bodyを保存する
wig.body.file <- paste("body_",chr,".txt",sep="")
write.table(wig.body,file=wig.body.file,col.names=F,row.names=F,sep=" ")

# headerbodyをつなげる
wig.file <- paste(chr,".wig",sep="")
sys.command <- paste("cat",wig.head.file,wig.body.file,">",wig.file,sep=" ")
system(sys.command)

# headerとbodyを消す
system(paste("rm",wig.head.file,sep=" "))
system(paste("rm",wig.body.file,sep=" "))

} # chr毎のループはここまで
} # この関数はここまで


上の関数を使ってwigをつくる
wig.gen(3)




2012年10月12日金曜日

R: gffをつくる

いくつかの解析系のことを考えていると、gffフォーマットのファイルが欲しくなった。Rで自動生成してみる。


gffファイルをつくる関数
行数と染色体の数、それとタイプを指定してgffの中身をランダムに生成する。

# n: 行数
# chrnum: 染色体の数
# type: "protein_coding", etc.

gff.gen <- function(n,chrnum,type){
chrs <- paste("chr",1:chrnum,sep="")
source <- "R"
type <- type
dots <- rep(".",n)
chr <- sample(chrs,n,replace=T)
start <- abs(round(rnorm(n)*1000000))
end <- start+1500+(round(rnorm(n)/2*500))
strand <- sample(c("+","-"),n,replace=T,prob=c(0.5,0.5))
id <- paste("gene",1:n,sep="")
gff <- data.frame(chr,source,type,start,end,dots,strand,dots,id)
return(gff)
}

# usage
gff <- gff.gen(1000,3,"ncRNA")

# check
head(gff)

# min length
min(gff[,5]-gff[,4])

# distribution
hist(gff[,5]-gff[,4],main="gene length")

# sort.left
gff.s <- sort.left(gff)

# check
head(gff.s)

# number of each strand
nrow(gff.s[gff.s$strand=="+",])
nrow(gff.s[gff.s$strand=="-",])


関数「sort.left()」はこちらを参照。


上の「# usage」以下の実行結果。

> # usage
> gff <- gff.gen(1000,3,"ncRNA")

> # check
> head(gff)
   chr source  type   start     end dots strand dots.1    id
1 chr2      R ncRNA  272400  273456    .      -      . gene1
2 chr1      R ncRNA 1173705 1175235    .      +      . gene2
3 chr1      R ncRNA  726009  727790    .      +      . gene3
4 chr3      R ncRNA 2041368 2042869    .      -      . gene4
5 chr3      R ncRNA  607172  608515    .      +      . gene5
6 chr3      R ncRNA  556786  558183    .      +      . gene6

> # min length
> min(gff[,5]-gff[,4])
[1] 767

> # distribution
> hist(gff[,5]-gff[,4],main="gene length")


histの結果

> # sort.left
> gff.s <- sort.left(gff)

> # check
> head(gff.s)
     chr source  type start   end dots strand dots.1      id
150 chr1      R ncRNA  1017  2463    .      -      . gene150
378 chr1      R ncRNA  9260 11146    .      -      . gene378
164 chr1      R ncRNA  9922 10844    .      +      . gene164
93  chr1      R ncRNA 14776 15981    .      +      .  gene93
557 chr1      R ncRNA 17269 18323    .      +      . gene557
863 chr1      R ncRNA 21640 22834    .      -      . gene863

> # number of each strand
> nrow(gff.s[gff.s$strand=="+",])
[1] 495
> nrow(gff.s[gff.s$strand=="-",])
[1] 505








R: 左側のカラムを優先して全カラムをソートする

PeakAnnotatorを使ってみたら、順番に並んでないから無理と言われた。

こんな結果。

$ PeakAnnotator TSS peaks.bed genes.bed out/tss.txt
Starting...
Reading BED File
Files must be sorted by chromosomes,start position, end position



ということで、左のカラムを優先して全カラムをソートする関数を作った。
行列xに適用すれば並べ替えてくれる。普遍的に使える。列数の限界なし。


sort.left <- function(x,decreasing=FALSE){
n <- ncol(x)
colnum <- n
for (i in 1:n){
x <- x[order(x[,colnum],decreasing=decreasing),]
colnum <- colnum-1
}
return(x)
}


以下、挙動の確認
4列のマトリックスに1から8をランダムに入れた。

> x <- matrix(sample(1:8,4*16,replace=T),ncol=4)

xの中身を確認。

> x
      [,1] [,2] [,3] [,4]
 [1,]    2    5    5    2
 [2,]    3    4    8    2
 [3,]    5    6    8    1
 [4,]    2    6    2    4
 [5,]    2    2    2    4
 [6,]    5    6    4    7
 [7,]    7    1    6    1
 [8,]    7    1    8    7
 [9,]    4    2    8    8
[10,]    8    4    2    6
[11,]    5    2    4    4
[12,]    5    1    4    5
[13,]    8    7    4    7
[14,]    4    5    7    5
[15,]    6    5    3    7
[16,]    6    5    5    6

関数「sort.left()」を適用。
1列目が同じ場合には2列目(1行目と2行目を参照)が、2列目まで同じ場合には3列目(9行目から14行目参照)が、ちゃんと昇順になっているのがわかる。

> sort.left(x)
      [,1] [,2] [,3] [,4]
 [1,]    2    2    2    4
 [2,]    2    5    5    2
 [3,]    2    6    2    4
 [4,]    3    4    8    2
 [5,]    4    2    8    8
 [6,]    4    5    7    5
 [7,]    5    1    4    5
 [8,]    5    2    4    4
 [9,]    5    6    4    7
[10,]    5    6    8    1
[11,]    6    5    3    7
[12,]    6    5    5    6
[13,]    7    1    6    1
[14,]    7    1    8    7
[15,]    8    4    2    6
[16,]    8    7    4    7

引数の「decreasing」はデフォルトでFALSEだが、TRUEを与えると降順になる。

> sort.left(x,T)
      [,1] [,2] [,3] [,4]
 [1,]    8    7    4    7
 [2,]    8    4    2    6
 [3,]    7    1    8    7
 [4,]    7    1    6    1
 [5,]    6    5    5    6
 [6,]    6    5    3    7
 [7,]    5    6    8    1
 [8,]    5    6    4    7
 [9,]    5    2    4    4
[10,]    5    1    4    5
[11,]    4    5    7    5
[12,]    4    2    8    8
[13,]    3    4    8    2
[14,]    2    6    2    4
[15,]    2    5    5    2
[16,]    2    2    2    4


せっかくなので、右側優先の関数もつくった。

sort.right <- function(x,decreasing=FALSE){
n <- ncol(x)
colnum <- n
for (i in 1:n){
x <- x[order(x[,n-colnum+1],decreasing=decreasing),]
colnum <- colnum-1
}
return(x)
}



xに関数「sort.right()」を適用。
最右列から優先的にソートされる。

> sort.right(x)
      [,1] [,2] [,3] [,4]
 [1,]    7    1    6    1
 [2,]    5    6    8    1
 [3,]    2    5    5    2
 [4,]    3    4    8    2
 [5,]    2    2    2    4
 [6,]    2    6    2    4
 [7,]    5    2    4    4
 [8,]    5    1    4    5
 [9,]    4    5    7    5
[10,]    8    4    2    6
[11,]    6    5    5    6
[12,]    6    5    3    7
[13,]    5    6    4    7
[14,]    8    7    4    7
[15,]    7    1    8    7
[16,]    4    2    8    8

もちろん降順もできる。

> sort.right(x,T)
      [,1] [,2] [,3] [,4]
 [1,]    4    2    8    8
 [2,]    7    1    8    7
 [3,]    8    7    4    7
 [4,]    5    6    4    7
 [5,]    6    5    3    7
 [6,]    6    5    5    6
 [7,]    8    4    2    6
 [8,]    4    5    7    5
 [9,]    5    1    4    5
[10,]    5    2    4    4
[11,]    2    6    2    4
[12,]    2    2    2    4
[13,]    3    4    8    2
[14,]    2    5    5    2
[15,]    5    6    8    1
[16,]    7    1    6    1



列が増えても大丈夫。

> y <- matrix(sample(1:4,6*16,replace=T),ncol=6)
> sort.left(y)
      [,1] [,2] [,3] [,4] [,5] [,6]
 [1,]    1    1    1    3    4    3
 [2,]    1    2    3    3    1    4
 [3,]    1    3    1    1    1    2
 [4,]    1    3    3    3    2    3
 [5,]    1    4    1    3    4    1
 [6,]    1    4    3    4    1    3
 [7,]    2    1    3    4    2    3
 [8,]    2    1    4    1    2    4
 [9,]    2    1    4    2    4    4
[10,]    2    2    1    3    4    4
[11,]    2    3    1    4    3    3
[12,]    3    1    4    4    3    1
[13,]    4    3    1    1    4    3
[14,]    4    3    1    3    1    2
[15,]    4    4    3    2    1    3
[16,]    4    4    3    2    2    1

> sort.right(y,T)
      [,1] [,2] [,3] [,4] [,5] [,6]
 [1,]    2    2    1    3    4    4
 [2,]    2    1    4    2    4    4
 [3,]    2    1    4    1    2    4
 [4,]    1    2    3    3    1    4
 [5,]    1    1    1    3    4    3
 [6,]    4    3    1    1    4    3
 [7,]    2    3    1    4    3    3
 [8,]    2    1    3    4    2    3
 [9,]    1    3    3    3    2    3
[10,]    1    4    3    4    1    3
[11,]    4    4    3    2    1    3
[12,]    4    3    1    3    1    2
[13,]    1    3    1    1    1    2
[14,]    1    4    1    3    4    1
[15,]    3    1    4    4    3    1
[16,]    4    4    3    2    2    1




2012年6月19日火曜日

MEMEが見つけるモチーフの中身

たとえリピートをマスキングしてから実行したとしても、MEMEは沢山のモチーフを提示してくれる。

ランダムにサンプリングしたプロモーター配列をMEMEに渡すと、MEMEが発見するモチーフの傾向がつかめる。

転写開始点付近のGCに富む領域、Alu配列の下流にあるA-richな領域などが目立つ。A-richな領域はリピートマスキングでもマスクされないのでどうしてもMEMEが拾ってしまう。

ハズレらしきモチーフは極端に長い傾向にある。特にGCに富む領域の場合、ひとつの配列に類似のモチーフが複数見つかる。もちろん、ハズレと断定できるわけではないのだが、このような傾向があることを知っておくのは重要だと思う。

PowerPointの低い解像度について

macでKeynoteを使っていると、PowerPointが使い難くてたまらない。数ある問題のひとつ、「貼付けたPDFの画質が落ちる」という問題への対処法。せっかくPDFで貼付けているのに、どうしてガビガビにしてしまうのか。液晶プロジェクタで出力するなら高解像度は必要ないが、配布資料の画質が荒いのは困る。


使っているプレゼンソフト
Keynote'09
PowerPoint 2008


解決法
PowerPointの「環境設定」の「保存オプション」の「解像度の設定」で解像度を高める。「グラフィックファイルの圧縮」を解除する。


PDFをソースからコピーし、プレビューで「クリップボードから新規作成」し、PNGで保存する。このときのPNGの解像度が重要。解像度 300 ピクセル/インチ以上が望ましい。


.pngファイルをPowerPointに貼付ける。


Keynoteにはめ込んだPDFほどではないが、それなりにクリアになる。

2012年6月15日金曜日

for()ループを入れ子にして検索するより、Rならではの方法で


IDと数値をもつ表があり、それとは別にIDのリストがあるとする。そのとき、リスト中のIDに対応する数値を表から抽出するにはどうしたらいいだろうか。

Rを使う。

for()ループでIDリストを1つずつ取り出し、そのループの中で更にfor()ループを使って表を1行ずつ取り出し、対応するIDをif()で探すという方法が思い浮かぶ。for()ループを入れ子構造にするやり方だ。方法を下に示す。

この入れ子構造でやってみるとものすごく遅い。2つ目のfor()ループは表の行数マイナス1行分も無駄に動いているわけだから、遅いのも頷ける。でも、perlだったらもっと速くに結果がでるような気がする。どうやらRはループが苦手らしい。

作業効率がとても悪いので、for()ループをひとつ減らして同じ結果を得る方法を考えた。if()で条件検討をせず、セルが一致する行をそのままRっぽく拾う。方法を下に示す。

ここに示す小さなデータではスピードの違いを実感できないが、数千行の表の中から数百のリストに合致する行を得ようとすれば、その違いは雲泥の差。前者ならかけっぱなしで散歩にでも行きたくなるが、後者ならあくびをしている間に終了する。


とりあえず、説明用にデータを用意する。

データフレーム(df.1)を用意する。

id1 <- c("A","B","C","D","E","F")
value1 <- rnorm(6,mean=3,sd=1)
df1 <- data.frame(id1,value1)

> df1
  id1   value1
1   A 2.484163
2   B 1.539250
3   C 2.773143
4   D 1.041669
5   E 2.409677
6   F 2.532448


IDリスト(id2)を用意する。

id2 <- c("B","D","E")

> id2
[1] "B" "D" "E"


入れ子構造のやり方。
forループを2つ重ねて検索する。

found1 <- df1[0,]
for (i in 1:length(id2)){
for (j in 1:nrow(df1)){
if (id2[i]==df1[j,1]){
hit1 <- df1[j,]
found1 <- rbind(found1,hit1)
}
}
}

> found1
  id1   value1
2   B 1.539250
4   D 1.041669
5   E 2.409677



Rの強みを活かすやり方。
forループをひとつだけにする。

found2 <- df1[0,]
for(x in 1:length(id2)){
hit2 <- df1[df1[,1]==id2[x],]
found2 <- rbind(found2,hit2)
}


> found2
  id1   value1
2   B 1.539250
4   D 1.041669
5   E 2.409677


2012年6月11日月曜日

MEMEの前にリピートをマスク


MEMEを使ってプロモーター中のモチーフ探しをすると、意味がありそうな、なさそうな、保存性の高いエレメントが多数ヒットすることがある。これらは通常とても長い。ゲノムにはAluなどのリピート配列が多く、それらが解析対象のプロモーター配列セットの中に沢山含まれてしまっているためだ。

MEMEでDNAモチーフを探すときは、あらかじめリピートをマスクしたFASTAを用いるべきだろう。


リピートのマスキングには、giri(Genetic Information Research Institute)のRepeat Maskingツール「CENSOR」が使える。生物種(Sequence source)を指定し、Report simple repeatsをチェックし、FASTAを与えて実行すると、リピート部分の塩基を「X」に置き換えたFASTAを返してくれる。もちろん、どのようなリピートがどこにヒットするかも教えてくれる。

都合のいいことに、CENSORが返してくれたFASTA(「X」でリピートがマスクされたもの)は、そのままMEMEに与えることができる。