ホーム | 統計 Top | Rを便利に使うための個人的メモ
目次
- 現在パソコンで開いているフォルダを作業ディレクトリとしてRを起動する(2014年12月28日)
- ガベージこれくしょん(2014年12月29日)
- save()関数によるデータオブジェクト保存の落とし穴(2015年10月8日)
- お使いのコンピュータのプラットフォームをR環境内で取得する方法(2015年12月20日)
- リストの結合(既存リスト末尾への要素追加)時にラベル名を動的に生成する(2016年2月20日)
- 添付ファイルの置き場としての属性情報attribute(2017年9月17日)
- 文字コードのこと(2019年11月29日)
- ソースファイルを読み込むときの文字コードのこと(2019年11月29日)
- MacOS X で imager package が使えません(2019年11月29日)
- ベクトルの[1], [1:2], [1:3], ... の和を求める(2019年12月10日)
- 度数分布の数値ベクトルから累積相対度数を求める(2019年12月10日)
- 数値ベクトルにおいて最初に/最後にゼロより大となる要素の位置を返す(2019年12月11日)
- 何もしてないのに R GUI 上で文字を打ってもコンソールに表示されなくなりました(2020年4月13日)
現在パソコンで開いているフォルダを作業ディレクトリとしてRを起動する
OSのスタートメニューやデスクトップから通常の手続きでRのGUIを起動すると、インストール時に指定した場所が作業ディレクトリとなる。一方、研究テーマや解析ごとに異なる環境を設け、Rのデータやコマンド履歴をそのディレクトリから読込、保存させたい場合もある。できればWindowsのエクスプローラーや Mac OS X の Finder など、コンピュータのファイラーで現在開いているフォルダから一発でRを起動して、その場にあるデータを読み込ませたい。
CUIからシコシコ指定したい場合はsetwd()コマンドを使って作業フォルダを変更できるのだけど、ボタン一発でやる方法も無くはない。ただしOS依存なので注意。
Windowsの場合
起動しているRコンソール上で、
> save.image("./hoge.RData")
と打ち込む。これで現在の作業ディレクトリに、"hoge.RData"という名前のファイル(Rのワークスペースを格納したデータ)が作成される。いったんRを閉じて、このファイルを、次にRを起動したい任意のフォルダにコピーないし移動。然る後にダブルクリックすれば、それが置かれているフォルダを作業ディレクトリとしてRを起動できる。
なお、"hoge.RData"を作成した元のR環境に含まれていたデータオブジェクトは、移植先の環境にも持ち越される。これが邪魔な場合は、移植先環境で
> rm(list=ls())
と打ち込んでワークスペースを全消去してから再度RDataを保存してやれば、バニラ状態からRを始めるための種が得られる。なお下手に移植元のR環境でrm()をやると、ユーザーがこれまでに作ったデータを断捨離してしまうので注意。
Mac OS Xの場合
上記のWindowsと同様にRDataファイルのダブルクリックからRを起動しても、「データオブジェクトは再現されるが作業ディレクトリは切り替わらない」ので、この方法では実現できない。正解は、「開きたいフォルダを、Finderで掴んでDock上のRのアイコンへドラッグ&ドロップする」。こちらのページも参照のこと。
ガベージこれくしょん
ゴミが溜まったメモリ領域を解放し、暁の水平線に勝利を刻む方法。
通常の環境では > gc();gc() library(parallel)のマルチスレッド環境で作業をした後に(clの部分には、自分が作ったクラスターの名前を入れる) > invisible(clusterEvalQ(cl,gc()));invisible(clusterEvalQ(cl,gc()))
gcコマンド1回ではゴミを見つけても消去までしてくれないことがあるらしく、2回打つのがコツ。
save()関数によるデータオブジェクト保存の落とし穴
Rで計算して得られるデータオブジェクトを、テキストとしての書き出しではなくR内の構造(クラス)を保ったバイナリファイルとして保存したい場合、save() という関数を使うのが通例であろう。だがオブジェクトの名前を指定する際に、若干の癖があるので注意。
たとえば幾つかの分析を自動で行なって、R環境内に以下のような名前の結果オブジェクトがあるとする。
> ls() [1] "A.fly.result" "A.moth.result" [3] "B.fly.result" "B.moth.result"
このうち A.fly.result を、ローカル環境にRバイナリ形式のファイルとして保存したい。
# 目的のオブジェクトを "A.fly.dat" というファイル名でローカル保存。 chemical <- "A" insect <- "fly" # これは想定通りに動く。 save( A.fly, file=paste(chemical, insect, "dat", sep=".")) # 一見正しく動きそうだが、これはダメ。 save( paste(chemical, insect, "result", sep="."), file=paste(chemical, insect, "dat", sep=".") )
保存対象のRオブジェクト名を、paste()で生成した任意の文字列ベクトルで指定したいならば、save関数の第一引数にそのままベクトルを指定してもダメ。正しくは以下のように、listで括る必要がある。
# 保存対象オブジェクト名を character vector で指定するときは、list = とする必要。 save( list=paste(chemical, insect, "result", sep="."), file=paste(chemical, insect, "dat", sep=".") )
これを読み込む際は、save() に対応する関数として load() を素直に使えばいい。
chemical <- "A" insect <- "fly" load( paste(chemical, insect, "dat", sep=".") ) > ls() [1] "A.fly.result" # R内でのオブジェクト名は、保存前のR環境で付いていた名前が復元される。
どうして保存時にlistで括らせる仕様なのか。あくまで推測だが、これは一回のsaveで保存対象とするオブジェクトが、複数ある場合に備えてである。たとえばR環境内の全てのオブジェクトを保存する操作は save( list=ls(), file="all.dat" ) となる。
参考
R help > assigning and saving datasets in a loop, with names changing with "i"
R Documentation > Save R Objects
お使いのコンピュータのプラットフォームをR環境内で取得する方法
こちらのページより。
WINDOWS <- .Platform$OS.type == "windows" if (WINDOWS) { print("Hello, world.") } else { print("Hello, world.") }
リストの結合(既存リスト末尾への要素追加)時にラベル名を動的に生成する
こちらのページより。
# リスト生成。 example <- list( a=1, b=c(2, 3, 4) ) # まずは単純に、名前を手動で指定してのリスト要素の追加方法。 example1 <- c( example, aa=list(c(5, 6, 7)) ) # 追加したいデータ自体をlistで括る必要がある。 # 動的に名を与える。以下が正しく動作する記法。 example2 <- c( example1, setNames(list(c(9, 10)), paste("name", "auto", sep="_")) ) > example2 $a [1] 1 $b [1] 2 3 4 $aa [1] 5 6 7 $name_auto [1] 9 10
SetNames() は日本のR界隈ではあまり知られていないものの、この手の問題をあっさり解決してくれるお助けマン的な関数である。下の記法が可能であれば必要ないのだが、どうやらRの実装的にマズいらしく通らないので、奴の出番となる。
# 以下は一見動きそうだが、ダメ。 example2 <- c( example1, paste("name", "auto", sep="_") = list( c(9, 10) ) ) エラー: 予想外の '=' です in "example2 <- c( example1, paste("name", "auto", sep="_") ="
添付ファイルの置き場としての属性情報attribute
R言語には予め、ベクトルやリストといったオブジェクトの種類が定義されている。こうした各オブジェクトは「属性」という文字列を、データ本体に付随して持つことができる。普段は意識せずに使っているが、属性を知る者はRを制すと言っても過言ではないほど重要な機能を担っている。
属性をハックすることで、基本オブジェクトを新たに定義することすら可能である。たとえば一般に「行列」と呼ばれるオブジェクトは、内部的には「次元という属性情報(dim属性)を持つベクトル」として保持されている。
hoge <- c(1:6) # [1, 2, 3, 4, 5, 6] というベクトルを作る。 hoge_matrix <- matrix(hoge, byrow=FALSE, nrow=2, ncol=3) # 行列に変換する dim(hoge_matrix) # dim 属性を調べる [1] 2 3
実は変法として、matrix() 関数を経由せずに行列を作ることができる。
hogehoge <- hoge # ベクトルをコピーした新規オブジェクトを作る is.matrix(hogehoge) [1] FALSE # もちろんこれは行列ではない # が、属性情報を直接操作するattr() 関数により強引にdim属性を与えることができる attr(hogehoge, "dim") <- c(2, 3) > hogehoge [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 # いつのまにか行列になってるゥ
さらに、attr() 関数により任意の属性情報を与えることができる。
attr(hoge, "himistu_message") <- c("今日の夕食", "カレーにしよう") > hoge [1] 1 2 3 4 5 6 attr(,"himistu_message") [1] "今日の夕食" "カレーにしよう"
上の例ではただのジョーク機能になってしまっているが、自作関数の戻り値に用いる場合など、これが威力を発揮する。
関数から複数データをアウトプットさせる方便としての属性埋め込み
基本的に関数の戻り値は「1つのオブジェクト」でなければならないので、複雑な情報を返したり計算の途中過程を保持しておきたい場合には、リストで括るのが一般的だ。だがリストだと個々のデータを取り出す時に、名称のラベルかアドレスを指定する必要がある。これが嫌ならば、return(x) されるオブジェクト x を最も主要な値1つにして、他の情報は x の属性情報として添付するのである。
# n個の一様乱数を発生させて、その平均値を返す関数。 corefunc <- function (n) { temp <- runif(n) result <- mean(temp) attr(result, "data.all") <- temp return(result) } corefunc(10) # 主な戻り値は平均値だが、関数内部で発生させた乱数データも属性として保持させている。 [1] 0.2157421 attr(,"data.all") [1] 0.646423804 0.118985521 0.426636328 0.273777440 0.004623513 0.183439193 0.026485985 0.416269893 0.014716725 0.046062869 hoge <- corefunc(10) # とりあえずオブジェクトに渡しておいて str(hoge) # str() 関数を使うと、どんな属性を含むオブジェクトであるか概略を示せる atomic [1:1] 0.396 - attr(*, "data.all")= num [1:10] 0.6865 0.6451 0.0785 0.8199 0.1201 ...
文字コードのこと
https://stat.ethz.ch/R-manual/R-devel/library/base/html/Encoding.html の内容を中心に。とりあえず調べてみよう。
# 現在のOS環境と、R環境内のデフォルト文字エンコーディングを調べる
.Platform$OS.type
options()$encoding
> .Platform$OS.type
[1] "windows"
> options()$encoding
[1] "native.enc"
この "native.enc" とは現在の R 環境において、特定の文字コードを標準で用いるようなユーザー設定が存在せず、OS標準に従うことを示す。MacOS X ならば "UTF-8" であり、Windows ならば "shift-jis" (正確には Microsoft が shift jis を独自拡張した CP932 という文字コードだが) になる。
# 何らかのデータ文字列が与えられたときに、そのエンコーディングを調べる
hogestring <- c("あいうえお")
Encoding(hogestring)
> Encoding(hogestring)
[1] "unknown"
エンコーディングが unknown というのは、hogestring という文字列を R のデフォルトエンコーディングに従うように与えており、特定のエンコーディングに従うようには宣言されていないことを表す。
こうした文字コードが "unknown" な文字列(R 内部で paste() や直接入力を用いて作った文字列は、大体そうなる)を、特定の文字コードたとえば UTF-8 に変換したい。候補となる方法を幾つか試してみよう。
# 以下、Windows での動作
iconv("あいうえお", from="shift-jis", to="UTF-8") # これは動く
iconv("あいうえお", from="native.enc", to="UTF-8")
iconv("あいうえお", from=Encoding("あいうえおえ"), to="UTF-8")
> iconv("あいうえお", from="shift-jis", to="UTF-8") # これは動く
[1] "あいうえお"
> iconv("あいうえお", from="native.enc", to="UTF-8")
iconv("あいうえお", from = "native.enc", to = "UTF-8") でエラー:
'native.enc' から 'UTF-8' へのサポートされていない変換がコードページ 932 中にあります
> iconv("あいうえお", from=Encoding("あいうえおえ"), to="UTF-8")
iconv("あいうえお", from = Encoding("あいうえおえ"), to = "UTF-8") でエラー:
'unknown' から 'UTF-8' へのサポートされていない変換がコードページ 932 中にあります
Windows 環境であれば "unknown" の実態は shift-jis なので、 iconv(from="shift-jis") という決め打ちでも一応動く。一方、iconv(from="native.enc") や iconv(from=Encoding("あいうえお")) は、実際に指し示す文字コードが不明なためエラーになる。
より一般性のある方法として、 enc2utf8() という関数を使うと、元の環境に関わらず文字列を UTF-8 に変換できる。
enc2utf8("あいうえおか")
> enc2utf8("あいうえおか")
[1] "あいうえおか"
enc2native(enc2utf8("あいうえおか")) # Win標準の shift-jis に戻す。
逆に enc2native() という関数を使うと元の文字列が何であれ、R環境の現在のデフォルト文字コードに変換できる。更に詳しい内容が必要であれば Maurício Collaça による解説 Encoding character strings in R を読むと良い。
ソースファイルを読み込むときの文字コードのこと
外部からダウンロードした(パッケージ化されていない)ソースコード、たとえば自分や知り合いが自作した関数定義ファイルを、現在のR環境へ読み込む処理は source() 関数で行える。問題は日本語やその他言語の文字列が含まれているときで、しばしば「構文解析中に不正なマルチバイト文字列がありました」というメッセージが出る。落ち着いてソースファイルの文字コードを(テキストエディタ等で)確認し、encoding を明示して source() しよう。
source("hoge.R", encoding="utf-8") # 文字コードを明示してソースファイルを読み込む
# そもそも自分のR環境でどんな文字コードが使われうるかを知るために、一度以下のコマンドを実行してみると良い。
iconvlist()
MacOS X で imager package が使えません(2019年11月29日)
R環境でラスター画像の取り込み・加工に使うパッケージの1つが imager である。色々便利だが、もともとシステムにインストールされている画像コーデックに依存するため、環境によっては正常にインストール・動作しないことがある。特に問題となりやすいのが、MacOS X の近頃のバージョンで出る、以下のエラーだ。
> library(imager)
エラー: package or namespace load failed for ‘imager’ in dyn.load(file, DLLpath = DLLpath, ...):
共有ライブラリ '/Library/Frameworks/R.framework/Versions/3.4/Resources/library/imager/libs/imager.so' を読み込めません:
dlopen(/Library/Frameworks/R.framework/Versions/3.4/Resources/library/imager/libs/imager.so, 6): Library not loaded: /opt/X11/lib/libX11.6.dylib
Referenced from: /Library/Frameworks/R.framework/Versions/3.4/Resources/library/imager/libs/imager.so
Reason: image not found
追加情報: 警告メッセージ:
パッケージ ‘imager’ はバージョン 3.4.4 の R の下で造られました
この原因は大別すると2つあって、1つは libX11.6.dylib がシステムのパスから探せない 場合である。
Actually, X11 is not erased but moved to /opt/X11. So, the simplest solution would probably be to manually add the symbolic link from /usr/X11 to /opt/X11:
解決法としては、ターミナルを開いてシンボリックリンクを作る(要再起動)。
sudo ln -s /opt/X11 /usr/X11
ただし、うちの環境(macOS 10.12.6)では上記を行なって再起動してもダメだった。この場合は原因 2「そもそも XQuartz が入っていない」可能性が疑われる。プロジェクト公式 (www.xquartz.org) から XQuartz をインストール。https://support.apple.com/ja-jp/HT201341 辺りも参照。その後、imager package も再インストールするとようやく正常に起動した。
ベクトルの [1], [1:2], [1:3], ... の和を求める(2019年12月10日)
数値ベクトルの最初の要素、最初と2番めの要素、最初と2番めと3番目の要素、みたいな足し合わせを順番に計算したいときは、cumsum() 使うべし。
cumsum(rep(1, 10))
cumsum(1:10)
> cumsum(rep(1, 10))
[1] 1 2 3 4 5 6 7 8 9 10
> cumsum(1:10)
[1] 1 3 6 10 15 21 28 36 45 55
度数分布の数値ベクトルから累積相対度数を求める(2019年12月10日)
度数分布がデータとして与えられているとき、cumsum() と総和(sum() を使う)の併せ技で、累積相対度数が計算できるゾ。
sampl <- rnorm(150, mean=1, sd=1)
sampl.hist <- hist(sampl)
###############################################################################
> sampl.hist
$breaks
[1] -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0
$counts
[1] 1 3 9 16 25 22 27 20 22 4 0 1
$density
[1] 0.01333333 0.04000000 0.12000000 0.21333333 0.33333333 0.29333333 0.36000000 0.26666667 0.29333333
[10] 0.05333333 0.00000000 0.01333333
$mids
[1] -1.75 -1.25 -0.75 -0.25 0.25 0.75 1.25 1.75 2.25 2.75 3.25 3.75
$xname
[1] "sampl"
$equidist
[1] TRUE
attr(,"class")
[1] "histogram"
このとき counts に階級別の度数が記録されている。 cumsum(counts) / sum(counts) が累積相対度数を与える。
counts <- sampl.hist$counts
print(counts)
cumsum(counts)
cum.dist <- cumsum(counts)/sum(counts)
print(cum.dist)
> print(counts)
[1] 1 3 9 16 25 22 27 20 22 4 0 1
> cumsum(counts)
[1] 1 4 13 29 54 76 103 123 145 149 149 150
> print(cum.dist)
[1] 0.006666667 0.026666667 0.086666667 0.193333333 0.360000000 0.506666667 0.686666667 0.820000000
[9] 0.966666667 0.993333333 0.993333333 1.000000000
数値ベクトルにおいて最初に/最後にゼロより大となる要素の位置を返す(2019年12月11日)
R で「ベクトルにおいて何らかの条件に合致する要素の位置」を返す関数が which() であり、「ベクトルにおいて最大となる要素の位置」を返す関数が which.max() である。
hoge <- c(0, 0, 3, 4, 5, 6, 7, 0, 0, 0)
which(hoge>0)
which.max(hoge)
> which(hoge>0)
[1] 3 4 5 6 7
> which.max(hoge)
[1] 7
この which.max() を cumsum() との併せ技で用いて、「最初にゼロより大となる要素」の位置を返す。
hoge <- c(0, 0, 3, 4, 5, 6, 7, 0, 0, 0)
dayFirstCap <- which.max(cumsum(hoge)>0)
dayLastCap <- length(hoge) - which.max(cumsum(rev(hoge))>0) + 1
> dayFirstCap
[1] 3
> dayLastCap
[1] 7
なぜ which.max() が「条件を満たす最初の要素」にマッチするのか一瞬分かりにくいが、 これは関数の仕様である。 which.max() の引数が真偽値ベクトルの場合、「最初のTRUE要素の位置」を返す。ちなみに which.min() だと最初のFALSE要素にマッチする。
> cumsum(c(0, 0, 0, 1, 0))>0
[1] FALSE FALSE FALSE TRUE TRUE
> which.max(cumsum(c(0, 0, 0, 1, 0))>0)
[1] 4
> which.min(cumsum(c(0, 0, 0, 1, 0))>0)
[1] 1
何もしてないのに R GUI 上で文字を打ってもコンソールに表示されなくなりました
嘘つけぜったい sink() で遊んでるゾ。stackoverflow の先達によれば以下の操作で治る。
sink.reset <- function() {
for(i in seq_len(sink.number())) {
sink(NULL)
}
}
sink.reset()