2016年8月3日水曜日

R: pdflatex is not available

Rで「pdflatex is not available」というエラーに遭遇したときの対処方法。
こちらのサイトを参考にした。

まず、ターミナルで「pdflatex」の場所を確かめる。whichを使う。

$ which pdflatex
/usr/texbin/pdflatex

ちなみに「R」の場所はこちら。

$ which r
/usr/bin/r

「pdflatex」が入っていることを確認した。mac側ではなくR側の問題ということになる。

Rがソフトウェアを認識するかどうかは、Sys.which()で知ることができる。
たとえば「R」を探すなら、

> Sys.which("r")
           r 
"/usr/bin/r"

という具合。ターミナルでみたときと同じ。

上のエラーが出ている状態で「pdflatex」を探してみると、

> Sys.which("pdflatex")
pdflatex 
      "" 

どうやら認識していないことがわかる。

これはPATHの問題。RのPATHを調べるには、Sys.getenv()を使う。

> Sys.getenv("PATH")
[1] "/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin"

いくつかPATHがあるが、「/usr/texbin」がない。
これがエラーの元凶。

PATHを通す作業を行う。そのためには、Sys.setenv()を使う。
既存のPATHと「/usr/texbin」をpaste()で繋げるところがRっぽい。

Sys.setenv(PATH = paste(Sys.getenv("PATH"), "/usr/texbin", sep=":"))

これで、PATHが追加された。

> Sys.getenv("PATH")
[1] "/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/texbin"

Rが「pdflatex」の場所を知ることができるようになった。

> Sys.which("pdflatex")
              pdflatex 
"/usr/texbin/pdflatex" 

これで、「pdflatex is not available」というエラーが出なくなる。

2016年7月22日金曜日

R: オブジェクトのサイズを考える

関数object.size()を使えば、オブジェクトのサイズを知ることができる。大きなデータを扱う場合、サイズは意識しておいた方が良いと思う。

とりあえず、character vectorをつくってサイズを眺めてみる。

# > x <- ""
# > nchar(x)
# [1] 0
# > object.size(x)
# 96 bytes

# > object.size("1")
# 96 bytes

# > object.size("1234567")
# 96 bytes

# > object.size("12345678")
# 104 bytes

# > object.size("123456789012345")
# 104 bytes

# > object.size("1234567890123456")
# 120 bytes

# > object.size("1234567890123456789012345678901")
# 120 bytes

# > object.size("12345678901234567890123456789012")
# 136 bytes

文字が長くなると表示しづらいので、for()で伸ばしてnchar()で文字数を確認し、object.size()で調査する。

# > x <- ""
# > for(i in 1:47) x <- paste(x, "a", sep = "")
# > nchar(x)
# [1] 47
# > object.size(x)
# 136 bytes

# > x <- ""
# > for(i in 1:48) x <- paste(x, "a", sep = "")
# > nchar(x)
# [1] 48
# > object.size(x)
# 152 bytes

# > x <- ""
# > for(i in 1:63) x <- paste(x, "a", sep = "")
# > nchar(x)
# [1] 63
# > object.size(x)
# 152 bytes

# > x <- ""
# > for(i in 1:64) x <- paste(x, "a", sep = "")
# > nchar(x)
# [1] 64
# > object.size(x)
# 216 bytes


文字の数とサイズは、どうやら以下の関係になっている。
0~7:   96 bytes
8~15:  104 bytes (+8)
16~31: 120 bytes (+16)
32~47: 136 bytes (+16)
48~63: 152 bytes (+16)
64~?:  216 bytes (+64)


一見すると秩序がありそう。
ということで、以下のコマンドでプロットしてみる。

main <- "Relationship between nchar and object.size"
sub <- c("64(blue), 128(green), 136(red), 144(orange)")
y <- ""
plot(x = nchar(y), y = object.size(y), 
   sub = sub, main = main, 
   xlim = c(0,550), ylim = c(0,700), pch = 20)
for(i in 1:550){
   y <- paste(y, "y", sep = "")
   points(x = nchar(y), y = object.size(y), pch = 20)
}
abline(v = c(64, 128, 136, 144), 
   col = c("blue", "green", "red", "orange"))



これはもう、本当に変なプロットになった。
どうやら、127文字を越えると取扱い方が変わるらしい。

# > x <- ""
# > for(i in 1:127) x <- paste(x, "a", sep = "")
# > nchar(x)
# [1] 127
# > object.size(x)
# 216 bytes

# > x <- ""
# > for(i in 1:128) x <- paste(x, "a", sep = "")
# > nchar(x)
# [1] 128
# > object.size(x)
# 224 bytes

# > x <- ""
# > for(i in 1:135) x <- paste(x, "a", sep = "")
# > nchar(x)
# [1] 135
# > object.size(x)
# 224 bytes

# > x <- ""
# > for(i in 1:136) x <- paste(x, "a", sep = "")
# > nchar(x)
# [1] 136
# > object.size(x)
# 232 bytes

# > x <- ""
# > for(i in 1:143) x <- paste(x, "a", sep = "")
# > nchar(x)
# [1] 143
# > object.size(x)
# 232 bytes

# > x <- ""
# > for(i in 1:144) x <- paste(x, "a", sep = "")
# > nchar(x)
# [1] 144
# > object.size(x)
# 240 bytes


まとめると、文字の数とサイズは以下の関係になっている。
0~7:      96 bytes
8~15:     104 bytes (+8)
16~31:    120 bytes (+16)
32~47:    136 bytes (+16)
48~63:    152 bytes (+16)
64~127:   216 bytes (+64)
128~135:  224 bytes (+8)
136~143:  232 bytes (+8)
144~152:  240 bytes (+8)
153~xxx:  8文字毎に8バイト増える。

基本的に1バイトに1文字が格納される計算になるのだが、そのオブジェクトの占有メモリは1文字毎に増えるのではない。あらかじめ決められた規則に則って、時には16文字分、あるいは64文字分のメモリが割り当てられる。しかも、どうやら128文字目以降は8文字単位でメモリの割り当てが増やされるらしい。

もうひとつの奇妙な現象を見つけた。
以下のコマンドを実行してもらうとわかるのだが、ひとつのベクターが2つの文字列をもち、しかもそれらの文字列が同一であれば、オブジェクトサイズは期待値よりも小さい。もしかしてfactorとして管理してるのかなぁ。

x <- ""
for(i in 1:10) x <- paste(x, "a", sep = "")
y <- c(x, x)
z <- c(x, paste(x, "b", sep = ""))
w <- c(paste(x, "b", sep = ""), paste(x, "b", sep = ""))
x
y
z
w
nchar(x)
nchar(y)
nchar(z)
nchar(w)
object.size(x)
object.size(y)
object.size(z)
object.size(w)

2016年7月20日水曜日

R: latticeのlevelplot()で枠を消す

表に入っているデータを俯瞰したいとき、レベルプロットが役に立つ。レベルプロットはlatticeパッケージのlevelplot()で実現できる。

しかし通常のやり方だと関数内で縦と横がスケーリングされてしまうので、ピクセル単位で期待通りのサイズの絵を出力するのが難しい。

マージンをゼロにしてプロット領域のみにし、プロットの外枠を消し、カラーキーを消すと、1ピクセルに1つの値を配置することができる。

R: lattice levelplot(), Remove the border line.

When you would like to see the information in a table or matrix at a glance, draw a level plot. It can be done with the function levelplot() in the lattice package.

It seems that the function automatically scales the plot, making it difficult to get a plot with defined scales.

By removing the margins, border lines and colorkey, you can get a plot in which a square of 1 x 1 pixel is filled with a value-related color.

# テスト用のマトリックスを作る。乱数の絶対値。
# Make a matrix with randomly produced values for a test.
x <- rnorm(20, mean = 0.5, sd = 0.3)
x <- abs(x)
m <- matrix(x, nrow = 4)

# パッケージをロードする。
# Load the package.
library(lattice)

# マージンゼロのテーマを定義する。参考サイトはこちら
# Define the theme.
theme.x <- list(
      layout.heights = list(  # マージンをゼロに
         top.padding = 0, 
         main.key.padding = 0, 
         key.axis.padding = 0, 
         axis.xlab.padding = 0, 
         xlab.key.padding = 0, 
         key.sub.padding = 0, 
         bottom.padding = 0), 
         layout.widths = list(
            left.padding = 0, 
            key.ylab.padding = 0, 
            ylab.axis.padding = 0, 
            axis.key.padding = 0, 
            right.padding = 0
         ), 
      axis.line = list(lwd = 0)  # 外枠を消す
      ) 

# 保存先に移動する。
# Change the working directory.
setwd("test")

# レベルプロットをPNGとして保存する。
# Draw a level plot and save it as a PNG.
width <- nrow(m)
height <- ncol(m)
filename <- "m.png"
png(filename = filename, width = width, height = height)
levelplot(m, par.settings = theme.x, xlab = NULL, ylab = NULL, 
scales = list(draw = FALSE), colorkey = FALSE)
dev.off()






こうして得たPNGファイルは、X軸とY軸の表示もなく、色と値の関係も分からないが、1ピクセルに1つの値が入っているので取扱いやすい。
# The resulting PNG file does not have the XY-axises or colorkey. However, as it is completely in a pixel-based format, it may be good for some purposes.

と、思いきや、Keynote ver. 6 以降に張り付けようとすると、PNGの画質が劣化する問題が生じる。この問題を回避するには、png()ではなくpdf()を使用するのが良さそう。pdf()は細い外枠が加えられるが、おそらく支障のないレベル。

# レベルプロットをPDFとして保存する。
# pdf()のサイズはピクセルではなくインチなので注意。
width <- nrow(m) / 72
height <- ncol(m) / 72
filename <- "m.png"
pdf(filename = filename, width = width, height = height)
levelplot(m, par.settings = theme.x, xlab = NULL, ylab = NULL, 
scales = list(draw = FALSE), colorkey = FALSE, useRaster = FALSE)
dev.off()

pdf()を使うとき、levelplot()useRaster=TRUEを与えると、keynoteに載せたときに絵が変になる。





2016年7月12日火曜日

R: strsplit() で、ピリオドを区切りとして文字列を分ける

strsplit()は、指定した文字を区切りとして文字列を分割する関数。
splitというArgumentで区切り文字を指定する。

ピリオド「.」はワイルドカードとして認識されてしまう、というのが今回の問題。手元にピリオドを含む文字列があり、ピリオドを区切りとして2つの文字列に分割したいとき、エスケープする必要がある。


# たとえば「ABC.01」という文字列を考える。
x <- "ABC.01"

# ピリオドをそのまま与えると、ワイルドカードになる。
strsplit(x, split = ".")[[1]]

# 「\\」でエスケープすると、ピリオドが区切りとみなされる。
strsplit(x, split = "\\.")[[1]]

R: Map() でマップする

Map the values with Map().

Map()はapply系の関数。mapply()のラッパー。

Map()は沢山のArgumentsを受け付けてくれるのでとても便利。
マルチコア版のmcMap()もある。

Map() is a wrapper function to mapply. Map() is useful as it takes lots of arguments. You can also use mcMap(), the multicore version of it.

#######################################################
たとえば、以下のようなデータフレームがあるとする。
Assume that there is a data frame like this.

x <- data.frame(strA = c("A", "B", "C", "D", "E", "F"),
strB = c("a", "b", "c", "d", "e", "f"),
strC = c("1", "2", "3", "4", "5", "6"))

> x
  strA strB strC
1    A    a    1
2    B    b    2
3    C    c    3
4    D    d    4
5    E    e    5
6    F    f    6


各row毎に、strAとstrBとstrCを繋げた文字列を得たいとする。
ついでに任意の文字(ここでは「-」)を加える。
And, you would like to concatenate character strings in the columns strA, strB and strC. Here, you may want the characters to be linked with '-'.

当然ながら、for()ループで実現できる。
You can do it with the for().

x$strABC <- ""
for(i in 1:nrow(x)){
strABC <- paste(x$strA[i], x$strB[i], x$strC[i], sep = "-")
x$strABC[i] <- strABC
}

for()ループの結果。
The result of the for loop.

> x
  strA strB strC strABC
1    A    a    1  A-a-1
2    B    b    2  B-b-2
3    C    c    3  C-c-3
4    D    d    4  D-d-4
5    E    e    5  E-e-5
6    F    f    6  F-f-6

しかし、rowの数が増えるほど計算が遅くなってしまう。Map()だと速い。
However, the more row numbers you have, the more time it takes. Map() does this more rapidly.

Map()を使うには、まず関数をつくる必要がある。
In order to use Map(), you need to make a function to be used by the function Map().

get.strABC <- function(strA, strB, strC){
return(paste(strA, strB, strC, sep = "-"))
}

この関数を使ってみるとこんな結果が帰ってくる。
This function acts like this.

> get.strABC("A", "a", "1")
[1] "A-a-1"

上のfor()ループの中でこの関数を使うと同じ結果を得ることができる。
Of course, you can use this function in a for loop.

x$strABC <- ""
for(i in 1:nrow(x)){
x$strABC[i] <- get.strABC(x$strA[i], x$strB[i], x$strC[i])
}

Map()でget.strABC()を実行する。Map()はリストで結果を返すので、unlist()で結果をシンプルにする必要がある。
Let's use Map(). You need to unlist the output of Map() to map the values in a preexisting container.

x$strABC <- unlist(Map(f = get.strABC,
strA = x$strA,
strB = x$strB,
strC = x$strC))

> x
  strA strB strC strABC
1    A    a    1  A-a-1
2    B    b    2  B-b-2
3    C    c    3  C-c-3
4    D    d    4  D-d-4
5    E    e    5  E-e-5
6    F    f    6  F-f-6

Map()のマルチコア版であるmcMap()も使える。この場合、parallelパッケージをロードする必要がある。
You can also use mcMap(), which is the multicore version of Map().
You need load the parallel package to do it.

library(parallel)
x$strABC <- unlist(mcMap(f = get.strABC,
strA = x$strA,
strB = x$strB,
strC = x$strC))

mcMap()のArgumentであるmc.coresで、使うコアの数を制御できる。
The number of cores can be regulated with the argument mc.cores.

#######################################################
rowの数を増やしてfor()とMap()を比べる。

x <- data.frame(strA = c("A", "B", "C", "D", "E", "F"),
strB = c("a", "b", "c", "d", "e", "f"),
strC = c("1", "2", "3", "4", "5", "6"))

for(i in 1:12) x <- rbind(x, x)

> nrow(x)
[1] 24576

for()ループでやると、4.286秒かかる。

x$strABC <- ""
system.time(
for(i in 1:nrow(x)){
x$strABC[i] <- get.strABC(x$strA[i], x$strB[i], x$strC[i])
}
)

   ユーザ   システム       経過
     4.169      0.137      4.286


Map()でやると、0.940秒。for()より速い。

system.time(
x$strABC <- unlist(Map(f = get.strABC,
strA = x$strA,
strB = x$strB,
strC = x$strC))
)

   ユーザ   システム       経過
     0.892      0.009      0.940


mcMap()でやると、0.711秒。Map()との差は小さい。

system.time(
x$strABC <- unlist(mcMap(f = get.strABC,
strA = x$strA,
strB = x$strB,
strC = x$strC, mc.cores = 4))
)

   ユーザ   システム       経過
     1.697      0.155      0.711


#######################################################
rowの数を増やしてMap()とmcMap()を比べる。

x <- data.frame(strA = c("A", "B", "C", "D", "E", "F"),
strB = c("a", "b", "c", "d", "e", "f"),
strC = c("1", "2", "3", "4", "5", "6"))

for(i in 1:16) x <- rbind(x, x)

> nrow(x)
[1] 393216


Map()でやると、16.926秒かかる。for()は怖くて試せない。

system.time(
x$strABC <- unlist(Map(f = get.strABC,
strA = x$strA,
strB = x$strB,
strC = x$strC))
)

   ユーザ   システム       経過
    16.596      0.107     16.926


mcMap(mc.cores = 4)でやると、8.939秒。Map()の半分の時間。

system.time(
x$strABC <- unlist(mcMap(f = get.strABC,
strA = x$strA,
strB = x$strB,
strC = x$strC, mc.cores = 4))
)

   ユーザ   システム       経過
     1.104      0.172      8.939


mcMap(mc.cores = 20)でやると、3.412秒。かなり速い。

system.time(
x$strABC <- unlist(mcMap(f = get.strABC,
strA = x$strA,
strB = x$strB,
strC = x$strC, mc.cores = 20))
)

   ユーザ   システム       経過
    80.537      3.933      3.412


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がやたらとあるので遺伝子単位で数を数えるのが妥当だと思う。