2016年7月7日木曜日

R: read.table() EOFの警告

read.table()で以下のような警告が出る場合、read.table()に「quote = ""」を与えると、とりあえず警告が消える。
When you are using the function read.table() and encounter the warnings like below, just give 'quote = ""' to the read.talbe() to avoid the problem.

【日本語の警告】
 警告メッセージ:
 scan(file, what, nmax, sep, dec, quote, skip, nlines, na.strings,  で:
   クオートで囲まれた文字列中にEOFがあります

【Warning in English】
Warning message:In scan(file, what, nmax, sep, dec, quote, skip, nlines, na.strings,  :
EOF within quoted string

上は、「"」や「'」が悪さをしているときの解決法になります。

もともと "\"'" がデフォルトなので、 取り込み対象の書類に2カ所のダブルクォートあるいはシングルクォートがあると、警告なしに、一見問題なく取り込まれます。

異なる2つの行に個別に奇数のクォートがあると、その間の行はトリミングされます。しかも恐ろしいことに、警告がでません。

EOF のメッセージが出るのは、たまたま奇数のクォートが奇数行に存在するときだけらしいです。


2016年5月27日金曜日

R:文字列をつなぐ

Rで文字を繋ぐためにはpaste()を使う。
You can concatenate character strings with the function paste().

ひとつの文字列ベクターに含まれる各文字列を繋いで1つにしたいとき、collapseを使うと良い。
If you want to concatenate the strings in a character vector to obtain one string in which all the strings in the vector are linked together, use the argument collapse.

x <- "ABC"
y <- "DEF"
z <- c(x, y)

# zには2つの文字列が入っている。
# There are two strings in the character vector z.
# > z
# [1] "ABC" "DEF"

# collapseを使わないとき、文字列は2つのまま、文字列が繋がる。
# When you use paste() without the collapse argument, the resultant object will contain two strings.
# > paste(z, sep = "")
# [1] "ABC" "DEF"

# collapseを使うと、文字列が1つにまとまる。
# If you use the collapse, the strings will be linked together.
# > paste(z, sep = "", collapse = "")
# [1] "ABCDEF"

# つなぎを指定することもできる。
# You can add your favorite characters in between the strings.
# > paste(z, sep = "", collapse = "*")
# [1] "ABC*DEF"

2016年4月21日木曜日

Fortranにやってもらう

Rをある程度習熟すれば、考えたことをなんでも実行できる。塩基配列の取扱いはBiostringsパッケージが強力だし、parallelパッケージの並列処理で多くの作業を高速化できる。

だけれども、やりたい計算があまりにもマニアックでapply系が使えないとき、とても困る。for()を多用せざるをえないような計算だ。

一応、for()も高速化はできる。先に適切なオブジェクトをつくっておき、その中のある座標だけを入れ替えるようにfor()ループを組み立てておけば、それなりに速く計算が終わる。宣言する感じ。そのつどオブジェクトを作り直すように組み立ててしまうと極端に遅い。それに、巨大なデータを用いて計算すると、速いといっても大したことない。

そこでFortranの出番となる。

RとFortranをつなぐのは.Fortran()という関数。Fortranのコードはプログラムではなくサブルーチンとして用意する。RからFortranに変数を渡せるし、FortranからRに変数を返してもらえる。ただし、サブルーチンの記述通りの順番で変数を渡す必要があるし、渡した変数しか返してもらえない。

サブルーチンの最後まで行った時点で保持していた変数のうち、Rから受け取ったものと同じもののみが、Rに帰ってくる。リストとして束ねられている。Fortranサイドで得た計算結果を受け取るためには、あらかじめRから初期値を入れた変数を与えて、それをFortranサイドで上書きしてしまえば良い。

RからFortranに変数が渡されると、Fortranが計算する。Fortranから変数が戻ってくるとき、Rのオブジェクトの中身だけを入れ替える形で戻ってくるらしい。だから、Fortranサイドでの宣言の仕方によってはおかしなことになる。

たとえば character(3) x みたいな感じで3個しか文字を格納できないようにしていると、Rから「x = "ABCDE"」というふうに5文字を受け取ったとしても Fortranで使うのは最初の3文字だけとなる("ABC")。この3文字を仮に別の文字に入れ替えてみるとする。たとえば、「x(3:3) = 'a'」とすると"ABa"になるのだが、このxをRに返してやると、上書きで返すのでRが受け取る変数は最初の3文字だけが改変された5文字、つまり"ABaDE"ということになる。

2016年4月1日金曜日

数字の並びを部分的に置換したいとき

数字の並びを部分的に置換することを考える。

たとえば、あるinteger vectorの中に存在する「3, 4, 5」を「5, 4, 3」に置き換えたいとき。
ここでは、文字列用の関数であるpaste()とgsub()を使ったトリックを紹介する。

適当なinteger vectorを作る。
int <- 0:9
int.vec <- c(int, int, int)

> int.vec
 [1] 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9


【for()ループでやる場合】

int.vec.new <- int.vec
for(i in 1:length(int.vec)){
if(int.vec[i] == 3 & int.vec[i+1] == 4 & int.vec[i+2] == 5){
int.vec.new[i:(i+2)] <- c(5, 4, 3)
i <- i + 2
}

> int.vec.new
 [1] 0 1 2 5 4 3 6 7 8 9 0 1 2 5 4 3 6 7 8 9 0 1 2 5 4 3 6 7 8 9


int.vecの中の「3, 4, 5」を「5, 4, 3」に置き換える仕事をfor()ループでやろうとすると、
このように一応はできるのだけれども、for()ループは遅い。
とくにvectorが長いほど遅さを実感する。

そこで、paste()とgsub()を使ったトリックの登場。


【paste()とgsub()でやる場合】

chr.vec <- paste(int.vec, sep = "", collapse = "")
int.vec.new <- as.integer(strsplit(gsub("345", "543", chr.vec), split = "")[[1]])

> int.vec.new
 [1] 0 1 2 5 4 3 6 7 8 9 0 1 2 5 4 3 6 7 8 9 0 1 2 5 4 3 6 7 8 9


まず、int.vecの値を文字列として繋げてしまう。
paste() はintegerを与えられたとしても、それをcharacterとして扱う。
collapseをうまく使えばすべての文字が繋がって、値がひとつのcharacter vectorになる。

chr.vec <- paste(int.vec, sep = "", collapse = "")

> chr.vec
[1] "012345678901234567890123456789"

こうしてひとつなぎの文字列にしてしまえば、gsub()が使える。
sub()は1つ目のヒットだけを置換するが、gsub()はすべてのヒットを置換する。

gsub("345", "543", chr.vec)

> gsub("345", "543", chr.vec)
[1] "012543678901254367890125436789"

あとは、strsplit()で1文字ずつ切り出し、integerに戻す。
strsplit() はリストで返すので、その1つ目を採用する。

> strsplit(gsub("345", "543", chr.vec), split = "")
[[1]]
 [1] "0" "1" "2" "5" "4" "3" "6" "7" "8" "9" "0" "1" "2" "5" "4" "3" "6" "7" "8"
[20] "9" "0" "1" "2" "5" "4" "3" "6" "7" "8" "9"


回りくどい仕事のように見えるが、対象が大きくなるほど早さを実感する。

2016年3月22日火曜日

あるドメインをもつタンパク質をコードする遺伝子の数

興味のあるドメインがあるとして、そのドメインをもつタンパク質がヒトゲノムにどれだけコードされているかを調査する方法のメモ。

例えば、HMGというドメイン。このドメインの「SMART ID」は「SM00398」。
http://smart.embl.de/smart/do_annotation.pl?BLAST=DUMMY&DOMAIN=SM00398

ポイントは「SMART MODE」を「GENOMIC」にしておくこと。
SMARTのサイトのEvolutionという項目をたどればヒトにいくつのタンパク質があるかわかる。
「SMART MODE」が「NORMAL」だと147。
「SMART MODE」が「GENOMIC」だと37。

この37の数字をクリックして「Expand all nodes」をクリックするとすべての候補の名前を確認することができる。
でも、「ENSP...」というEnsemblのIDが付与されたものや、「..._HUMAN」という感じで遺伝子名が付与されたものや、UniprotのIDが付与されたものが混在している。だから、結局のところ現行ゲノムにどれだけ遺伝子が存在するのかよくわからない。そもそも「GENOMIC」での絞り込みが妥当かどうかがよくわからない。

この問題を回避するため、EnsemblのBiomartを使う。
http://www.ensembl.org/biomart/martview

セッティングは以下のとおり。
Dataset:
CHOOSE DATABASE: Ensembl Genes 84
CHOOSE DATASET: Homo sapience genes (GRCh38.p5)
Filters:
PROTEIN DOMAINS AND FAMILIES
Limit to genes with these family or domain IDs
SMART ID(s): SM00398
Attributes:
Features
GENE: Associated Gene Name, Description
PROTEIN DOMAINS AND FAMILIES: Domains: SMART ID

ポイントは、Ensemble Gene IDなどを呼び出さないこと。これをやっちゃうと変なものまで出てくる。
Countすると、52件のヒット。
Resultsの「Unique results only」で限定してダウンロードすると、52遺伝子の情報を得ることができる。

こうすれば、特定のSMART IDをもつ遺伝子が現行ゲノムにいくつあるかを知ることができる。
Transcript variantがやたらとあるので遺伝子単位で数を数えるのが妥当だと思う。

2013年8月28日水曜日

R: new.env() で環境をつくる

CRAN のポリシーのひとつに、大局的環境(.GlobalEnv)を操作してはならない、というのがある。自作パッケージの関数の中でオブジェクトを .GlobalEnv に assgin() したり、そこから get() していたので、このポリシーの存在には正直へこんだ。少なくとも、最終段階で気づくべきことではない。

google 先生に色々訊ねた結果、どうやらこの道の常識では .GlobalEnv は綺麗にしておくものらしい。

ポリシーに従ったパッケージにするためには、パッケージの環境に new.env() で小環境を作れば良い。たとえば、DATA という環境をつくる。そして、パッケージの中の assign(pos = .GlobalEnv) や get (pos = .GlobalEnv) を、assign(pos = DATA) や get(pos = DATA) に置換すればうまくいくはず。

以下のコードを R コンソールにコピペして、各関数を実行してみたら理解しやすいと思う。ls() で調べれば、.GlobalEnv の中に小環境 DATA が作られるのがわかる。ls(DATA) で 小環境 DATA の中のオブジェクトを確認できる。


# create an environment named DATA.
DATA <- new.env(parent = emptyenv())

# assign an object to DATA.
assignToDATA <- function (name = "unknown", value = "unknown"){
assign(name, value, pos = DATA)
}

# get an object from DATA.
getFromDATA <- function (name = "unknown"){
get(name, pos = DATA)
}

# remove an object from DATA.
rmFromDATA <- function (list = "unknown"){
rm(list = list, pos = DATA)
}


パッケージの「R」ディレクトリに入れる「.r」ファイルの1つに 「DATA <- 」の行を書き込んでおき、NAMESPACE に export("DATA") を加えておけば、パッケージをインストールして library() でロードしたときに、パッケージの環境中に小環境として DATA が作られる。これなら .GlobalEnv を操作しないで済む。DATA の中身は ls(DATA) で閲覧できる。

これはわかったけど、パッケージ中の至る所に get や assign があるので、これらを全部修正するのは非常に面倒。最初に知っておきたかった。

2013年8月26日月曜日

メモ:CRAN にパッケージを投稿する際の問題

メモです。

パッケージのチェックには「--as-cran」を使う。
R CMD check --as-cran test.package


Mac の Finder が自動生成する隠しファイル(.DS_Store)の存在が邪魔。これは rm で取り除くことができるから OK。

* checking for hidden files and directories ... NOTE
Found the following hidden files and directories:
  .DS_Store
These were most likely included in error. See section ‘Package
structure’ in the ‘Writing R Extensions’ manual.


assign で .GlobalEnv にオブジェクトを作ったらダメ。この解決法を知りたい。別の環境をつくってそこに放り込む?
* checking R code for possible problems ... NOTE
Found the following assignments to the global environment:
File ‘test.package/R/assign.obj.R’:
  assign(name, value, pos = .GlobalEnv)