山椒 Tips 集
初心者の悩みを解決する、小粒だけれどピリリと効く Tips 集。自分はこれにハマッタという方は、後進のために、追加お願いします。
ファイル入出力時などに必要かも
getwd() #作業ディレクトリの確認 setwd("指定する作業ディレクトリ") #作業ディレクトリの変更
表示される有効桁数を変える。内部演算桁数は変更されず。最大22桁まで指定できるが、意味のある最大桁数はせいぜい15,16桁
options(digits=10) # 表示桁数を10桁に変える
> options(scipen=10) > p <- 0.0001 > p [1] 0.0001
>formatC(p) [1] "0.0001"
関数 foo の説明と参考例コードを見る
help(foor) ?foo # 簡略形
予め help.start() を一度実行すると、それ以降の説明はブラウザーに表示される
help() で表示される、各関数の説明の最後には参考例がついている。これを見ると使い方のヒントになることが多い。予め par(ask=TRUE) を実行しておくと、グラフィックス出力を一つずつ眺められる。
example(lm) # 関数 lm の参考デモを見る
> sum(1,2,3,4) [1] 10 #よしよし > mean(1,2,3,4) [1] 1 #あれ? > mean(c(1,2,3,4)) [1] 2.5 #これが正解
Rの関数はコンマのあとは引数。 sum() などは、引数はベクトル要素と見なしてくれるので、上記の手抜き入力ができる。 でも、mean() など、ベクトル演算の関数を使うときは、手抜きせず c() を入力するように。
次のグラフィックス出力の前に確認プロンプトがでる。特に example() 関数を使用した時、複数のグラフィックスが一瞬に流れさるのを防ぐのに効果。
par(ask=TRUE) par(ask=FALSE) # 元に戻す
グラフィックスのオプションパラメータを一時変更した後で、元に戻す。オプション変更を伴う関数に入れておくと便利。
oldpar <- par(no.readonly = TRUE) # 現在の変更可能パラメータの値を退避 (パラメータオプションの変更を伴う作業) par(oldpar) # 作業前のパラメータ値に戻す
foo <- function ( ) { oldpar <- par(no.readonly = TRUE) (パラメータオプションの変更を伴う作業) on.exit(par(oldpar)) # 関数がエラー中断してもパラメータ復帰 }
オプション horizontal=FALSE を使う。
postscript("foo.eps", horizontal=FALSE, height=9, width=14, pointsize=15) (ポストスクリトへの出力) dev.off() # デバイスを閉じる
出力が全部終ったら、すかさず dev.off() でデバイスを閉じるのがコツ。
postscript("foo.eps", horizontal=FALSE, height=9, width=14, pointsize=15) (ポストスクリトへの出力) dev.off() # デバイスを閉じる
R の組み込み関数、オブジェクトは自由に再定義可能である。同じ名前の組み込み関数・オブジェクトがあることに気づかず、うかつに再定義すると、悩むことになる。しかも、作業スペースを保存で終了すると、次回もその定義が生き返るので危険。
> "+" <- function (x) x # 過激な例 > +(1) # これが正しく意味を持つ [1] 1 > 2+3 # + は二項演算子の意味を失っている Error in 2 + 3 : unused argument(s) ( ...)
このような事態になったときの対処法は,再定義したオブジェクトを取り除くことである。組み込み関数自体は rm() 関数で消去できないので元の定義が復活する。
> ls() 今定義されているオブジェクトのリストを見る [1] "+" その他いろいろのオブジェクト > rm("+") "+" オブジェクトを取り除く! > 3+4 [1] 7 なおった!
コード中に # を置くと、それ以降行末までコメントとして無視される。複数行をまとめてコメントとするには if(0){........} で囲む。本来のコメントでも良いし、デバッグ中に一時的にコードを変更する際に、古いコードを残しておくにも便利。
foo <- function (x) { x <- 0 # 変数 x に値 1 を代入する (本来のコメント) # x <- 2 # コメントアウトされた一行 if(0){ # 複数行一括コメント化 (コメントアウトされた複数行) } )
> for(i in 1:3){2^i} >
ブロック{ }内の結果を表示するには、print() や cat() が必要です。
> for(i in 1:3){print(2^i)} [1] 2 [1] 4 [1] 8
何かキー入力があるまでプログラムの実行を停止
> foo <- function(x) { cat("sum of x is -->", sum(x), "?n") readline("Can I proceed? ") cat("prod of x is -->", prod(x),"?n") } > temp(1:4) sum of x is --> 10 Can I proceed? #ここで何かをキー入力すると次を実行 prod of x is --> 24
readline() は入力した値を取り込むのにも使える
> foo <- function () { x <- readline("Input some number ---> ") # 入力値(文字列とされる)を x に付値 cat(" Inputted number = ", x, "?n") return(as.numeric(x))} # 入力された文字列化された数字を、本来の数字に変換 > foo() Input some number ---> 2.3 Inputted number = 2.3 [1] 2.3
普通の if 文 (条件についてベクトル化されていない)
if (x) A if (x==0) A else B if (x==0) A else if (x==1) B else C
二者択一 (条件についてベクトル化されている)
ifelse(x==0, A, B) ifelse(x==0, A, ifelse(x==1, B, C) )
R の付値演算子 <-, ->, <<-, ->> は実は関数で、暗黙のうちに値(付値された値自身)を返す。実際 x <- 10 はよりめんどくさい書き方の assign(x, 10) と同値。したがって、次のような一見奇妙な(なれると病み付きになる)コードが書ける。
lm.D9 <- lm(weight ~ group) # 線形回帰の結果をオブジェクト lm.D9 に付値 anova(lm.D9) # オブジェクトを anova 関数で処理
これを一行で書くと
anova(lm.D9 <- lm(weight ~ group)) # 線形回帰の結果をオブジェクト lm.D9 に付値し、それを anova 関数で処理
こんなこともできる
x <- y <- 10 # x <- (y <- 10) つまり assign(x, assign(y, 10)) ということ
R のすべての関数・演算子は原則として何らかの値を返すように設計されている。それを意識してコードを書けば、幸せになれる(幸せと不幸せは紙一重だから注意)
関数(データ)の効率的な編集をするには、
sr <- function() source("bar.R")
オプションをフルに書かなくてもいいケースがあります。イーコールの前はユニークになるところまでスペルすれば OK.TRUE/FALSEに関してはT/Fと略すことができます。R の関数のオプション名は意味が分かりやすいことを最優先して長ったらしいことが多いので、この省略可能性は魅力的。ただし、F や T は付値が可能で,F値をFとして付値してしまっていたりすると、おかしなことになるので、プログラムなどではTRUE,FALSE とちゃんと略さないで書く癖をつけておいたほうが無難。
mean(c(1, NA, 3), na.rm =TRUE) # NA を取り除いて平均を求める mean(c(1, NA, 3), na.rm =T) mean(c(1, NA, 3), n=T) mean(c(1, NA, 3), na.r=TRUE) [1] 2
いずれも同じ結果を返します。
pb <- winProgressBar(title="プログレスバーの例", label="0% done", min=0, max=100, initial=0) for(i in 1:100) { Sys.sleep(0.1) # slow down the code for illustration purposes info <- sprintf("%d%% 完了", round((i/100)*100)) setWinProgressBar(pb, i/(100)*100, label=info) }
> x <- c(1,2,3,4,5,6,7,8,9) # x <- 1:9 でも良い > x[2:5] # x[2], x[3], ..., x[5] を取り出す、x[c(2,3,4,5)] でも良い [1] 2 3 4 5 > x[-2:5] # x[2], x[3], ..., x[5] 以外を取り出す [1] 1 6 7 8 9 > y <- x%%3==0 > y [1] FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE TRUE > x[y] # 論理値ベクトル指定、x[x%%3==0] でもよい [1] 3 6 9
> x <- runif(10) > y <- which(x < 0.5) # 0.5 未満以の値を持つ要素の添字を取り出す > y [1] 3 5 6 10 > x[y] # 0.5 未満以の値を持つ要素を取り出す、x[x < 0.5] と同じ [1] 0.40643515 0.26432576 0.35265039 0.08640936 > (1:length(x))[x < 0.5] # 同じことを少し複雑に行なう [1] 3 5 6 10
> x <- runif(100) # 一様疑似乱数 100 個からなるベクトル(テスト用に便利) > 1:10 [1] 1 2 3 4 5 6 7 8 9 10 > 10:1 [1] 10 9 8 7 6 5 4 3 2 1 > (-1):5 [1] -1 0 1 2 3 4 5 > (-1):(-5) [1] -1 -2 -3 -4 -5 > 1.3:10 [1] 1.3 2.3 3.3 4.3 5.3 6.3 7.3 8.3 9.3 > (-1.3):10 [1] -1.3 -0.3 0.7 1.7 2.7 3.7 4.7 5.7 6.7 7.7 8.7 9.7 > (1:10)/10 [1] 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
> seq(0, 1, length = 11) # 0 と 1 の間を 11等分する等差数列 [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
> seq(1, 9, by = 2) 公差 2 の等差数列 [1] 1 3 5 7 9 > seq(1, 9, by = pi) [1] 1.000000 4.141593 7.283185 > seq(1, 6, by = 3) [1] 1 4 > seq(17) # 1:17 と同じ [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 > x= c("a", "b", "c", "d", "e", "f") > seq(along = x) # 1:length(x) [1] 1 2 3 4 5 6
> rep(0,10) [1] 0 0 0 0 0 0 0 0 0 0 > rep(1:2,10) [1] 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2
> x <- numeric(10) > x [1] 0 0 0 0 0 0 0 0 0 0
度数分布表のようなものから元のデータを再現するときなどに
x <- c(rep(100, 5), rep(101,8), rep(102,13), ..., rep(180,3))
とするのは大変。
x <- rep(100:180, c(5,8,13, ..., 3))
のようにすると簡単。
繰り返される数値が等差数列なら,
x <- rep(n:m*k+i, c(5, 8, 13, ..., 3))
とか,特に規則性がないときでも,
x <- rep(c(a,b,c,d,...), c(x,y,z,u, ...))
とか。
繰り返しも二通りある。どちらでもいい場合もあるし,どちらかでなくてはならない場合もある。
> rep(1:3, 4) [1] 1 2 3 1 2 3 1 2 3 1 2 3 > rep(1:3, each=4) [1] 1 1 1 1 2 2 2 2 3 3 3 3
> x <- factor(c("s","t","a","t","i","s","t","i","c","s"), levels=letters) # 因子オブジェクトを作る > x [1] s t a t i s t i c s Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z
> x [1] s t a t i s t i c s Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z > factor(x) # x[, drop=TRUE] でも同じ [1] s t a t i s t i c s Levels: a c i s t
> data(iris) > sp <- unique(iris$Species) > nested.list <- list() > for(i in 1:length(sp)){ > nested.list[i] <- list(subset(iris, Species==sp[i])) > } > summary( nested.list[[1]]) Sepal.Length Sepal.Width Petal.Length Petal.Width Species Min. :4.300 Min. :2.300 Min. :1.000 Min. :0.100 setosa :50 1st Qu.:4.800 1st Qu.:3.200 1st Qu.:1.400 1st Qu.:0.200 versicolor: 0 Median :5.000 Median :3.400 Median :1.500 Median :0.200 virginica : 0 Mean :5.006 Mean :3.428 Mean :1.462 Mean :0.246 3rd Qu.:5.200 3rd Qu.:3.675 3rd Qu.:1.575 3rd Qu.:0.300 Max. :5.800 Max. :4.400 Max. :1.900 Max. :0.600
> data(warpbreaks) > wl <- unique(warpbreaks$wool) > tn <- unique(warpbreaks$tension) > nested.list <- list() > for(i in 1:length(wl)){ > nested.tmp <- list() > for(j in 1:length(tn)){ > nested.tmp[j] <- list(subset(warpbreaks, wool==wl[i] & tension==tn[j])) > } > nested.list[i] <- list(nested.tmp) > } > nested.list[[1]][[2]] breaks wool tension 10 18 A M 11 21 A M 12 29 A M 13 17 A M 14 12 A M 15 18 A M 16 35 A M 17 30 A M 18 36 A M
> diag(1, ncol=3, nrow=3) # 値 1 がリサイクル使用される [,1] [,2] [,3] [1,] 1 0 0 [2,] 0 1 0 [3,] 0 0 1 > diag(rep(1, 3)) # diag(c(1,1,1)) と同じ [,1] [,2] [,3] [1,] 1 0 0 [2,] 0 1 0 [3,] 0 0 1 > x <- matrix(0, ncol=3, nrow=3) # 全成分が 0 の行列 > diag(x) <- 1 # 対角成分を 1 にする > x [,1] [,2] [,3] [1,] 1 0 0 [2,] 0 1 0 [3,] 0 0 1 > diag(x) <- c(1, 2, 3) # 対角成分を 1, 2, 3 にする > x # diag(1:3) で直接作れる [,1] [,2] [,3] [1,] 1 0 0 [2,] 0 2 0 [3,] 0 0 3
> x <- matrix(runif(9), ncol=3, nrow=3) > x [,1] [,2] [,3] [1,] 0.8296189 0.9144157 0.60020004 [2,] 0.9440765 0.5413652 0.03560994 [3,] 0.0623679 0.6051179 0.57717385 > x[1, 3] # (1,3)成分 [1] 0.6002 > x[, 3] # 第3列 (ベクトルになる) [1] 0.60020004 0.03560994 0.57717385 > x[1,] # 第1列 (ベクトルになる) [1] 0.8296189 0.9144157 0.6002000 > x[, 3, drop=FALSE] #第3列 (3x1 行列になる) [,1] [1,] 0.60020004 [2,] 0.03560994 [3,] 0.57717385 > x[1, , drop=FALSE] # 第1行 (1x3行列になる) [,1] [,2] [,3] [1,] 0.8296189 0.9144157 0.6002 > x[c(1,2), c(3,2)] # 2x2副行列の取り出し、c(3,2)の順序に注意 [,1] [,2] [1,] 0.60020004 0.9144157 [2,] 0.03560994 0.5413652 > x[-1,] # 第2,3行からなる2x3行列 [,1] [,2] [,3] [1,] 0.9440765 0.5413652 0.03560994 [2,] 0.0623679 0.6051179 0.57717385
> x[x >= 0.5] # 0.5より大きな成分は? [1] 0.8296189 0.9440765 0.9144157 0.5413652 0.6051179 0.6002000 0.5771739 > x[x >= 0.5] <- 0 # 0.5より大きな成分を0に置き換え > x [,1] [,2] [,3] [1,] 0.0000000 0 0.00000000 [2,] 0.0000000 0 0.03560994 [3,] 0.0623679 0 0.00000000
> i <- which(x != 0) # 0でない成分の添字 > i # xをベクトルと考えた時の添字 [1] 3 8 > x[i] # x[x != 0] と同じ [1] 0.06236790 0.03560994 > which(x != 0, arr.ind=T) # 0でない添字を行列として取り出す row col [1,] 3 1 # つまり x[3,1]=0.06236790 [2,] 2 3
注意! ベクトルや行列にNAが入っている場合は、which を使わない添字取り出し(NAが入る!)と、whichを使った添字取り出しで結果が異なるので注意が必要です。
入力
x<-c(1,2,NA) x[x==1] x[which(x==1)]
結果
> x<-c(1,2,NA) > x[x==1] [1] 1 NA > x[which(x==1)] [1] 1
スカラー、ベクトル、リストオブジェクトを初期化するさい、適当な初期値を入れておいてもよいが、空のオブジェクトとして初期化しておくと、変更がされたかどうか確認しやすく、間違いがおきないこともある。
> x <- numeric(0) > x numeric(0) > x*0 numeric(0) > x <- pi > x [1] 3.141593
> y <- NULL > y[3] <- 3 > y [1] NA NA 3
> z <- NULL > z[[1]] <- 1:10 Error: more elements supplied than there are to replace > z <- as.list(NULL) > z[[1]] <- 1:10 > z [[1]] [1] 1 2 3 4 5 6 7 8 9 10
> as.list(rep(NA,5)) [[1]] [1] NA [[2]] [1] NA [[3]] [1] NA [[4]] [1] NA [[5]] [1] NA
ls()
rm(object.name)
全てのオブジェクトを削除
rm(list=ls(all=TRUE))
(詳しくは Tips データフレーム を参照)
> data(swiss) # 組み込みデータ swiss を読み込み > swiss # swiss データは5成分からなるデータフレーム Fertility Agriculture Examination Education Catholic Courtelary 80.2 17.0 15 12 9.96 Delemont 83.1 45.1 6 9 84.84 ...... (以下略) .............................. > swiss$Fertility # 成分 Fertility の表示 [1] 80.2 83.1 92.5 85.8 76.9 76.1 83.8 92.4 82.4 82.9 87.1 64.1 66.9 68.9 61.7 [16] 68.3 71.7 55.7 54.3 65.1 65.5 65.0 56.6 57.4 72.5 74.2 72.0 60.5 58.3 65.4 [31] 75.5 69.3 77.3 70.5 79.4 65.0 92.2 79.3 70.4 65.7 72.7 64.4 77.6 67.6 35.0 [46] 44.7 42.8 > FertilityError: Object "Fertility" not found # Fertility という変数は無いのでエラー > attach(swiss) # swiss データの各成分を成分ラベルで参照できるようにする > Fertility # Fertility という変数ができた [1] 80.2 83.1 92.5 85.8 76.9 76.1 83.8 92.4 82.4 82.9 87.1 64.1 66.9 68.9 61.7 [16] 68.3 71.7 55.7 54.3 65.1 65.5 65.0 56.6 57.4 72.5 74.2 72.0 60.5 58.3 65.4 [31] 75.5 69.3 77.3 70.5 79.4 65.0 92.2 79.3 70.4 65.7 72.7 64.4 77.6 67.6 35.0 [46] 44.7 42.8 > detach(swiss) # もし不要で邪魔なら成分名で参照できないようにする
次のような関数を定義しておくと便利。lapply + factor ではすべての成分が要素になってしまうので、要素のものだけを変換している。
rm.level <- function(x){ sub.fun <- function(sub.df){ if (is.factor(sub.df)) factor(sub.df) else sub.df } data.frame(lapply(x, sub.fun)) }
> x <- data.frame(a=c("a","b","c"), b=1:3) > y <- subset(x, a!="c") > summary(y) a b a:1 Min. :1.00 b:1 1st Qu.:1.25 c:0 Median :1.50 Mean :1.50 3rd Qu.:1.75 Max. :2.00 > y <- data.frame(lapply(x, factor)) > summary(y) a b a:1 1:1 b:1 2:1 c:1 3:1 > z <- subset(x, a!="c") > z <- rm.level(z) > summary(z) a b a:1 Min. :1.00 b:1 1st Qu.:1.25 Median :1.50 Mean :1.50 3rd Qu.:1.75 Max. :2.00
R のあるセッション中に入力した命令はすべて記録されており、
PDF作成命令の中に、フォント指定 family="" が必要です。 (Windowsなどのフォントが自動的に流用されればいいのですが..)
1.
> names(pdfFonts())
で、使えるフォント名を確認。いろいろ出るので、どれを使うか決める。
2-1.PDFファイルを作る古典的方法でfamily指定。
> pdf("なんとか.pdf", family="フォント名") > plot(あれこれ) > .... > dev.off()
2-2. PDFファイルを作る別法。スクリプトの最後に以下の一行を入れる。こちらは作図経過を視認でき、おすすめ。
> dev.copy2pdf(file="なんとか.pdf", family="フォント名")
注1.EPSファイルも、PDFと同様にできるかと思いきや、だめでした。EPSは過去の遺物だと、あきらめるしかなさそうです?
注2.非標準かもしれないフォントを使って人にファイルを渡す場合が問題。相手の日本語環境が不明なら、PDF内に「フォント埋めこみ」をすべき。Ghostscript があるならこう、そうでなければ cairo_pdf を使うとか、初心者向けでないので説明は省略。
既にインストールしているパッケージについて、その作成者などの概要と利用可能な関数 (とその説明)を表示します。以下は、パッケージ MASS の場合。
> library( help = MASS )
標準で配布されるパッケージ以外にどんなパッケージがあるかは CRAN の Packages Srouces に一覧(現在210余り)と、簡単な解説がある。更に詳しい説明と含まれる関数・データの一覧表も得られる。
例えば vegan と呼ばれる、生態学用のパッケージをインストールするには
下向き矢印キーを一回押すと一番下までスクロールします。
もちろんコントロール+Cでコピー、コントロール+Vでペーストできるのですが、コピーペーストしたいときはコントロール+Xでコピーしてペーストしてくれます。コンソール窓内でしかコピーペーストできませんが、覚えておくと便利です。
MSWindows標準のAlt+F4でも終了できますが、コントロール+Zでも終了できます。
quit("yes") q("yes") q() # 作業スペースを保存するかどうか問い合わせがあるから yes と答える
とすると終了時に残っているオブジェクトは次回使えます(作業内容はバイナリファイル ".Rdata" に、入力命令の履歴は ".Rhistory" に記録される。Unix の場合)。 save()で分かりやすい場所に分かりやすい名前で保存して次々回以降に使うことも出来ます。 また .Rhistory と .Rdata を別のディレクトリにコピーすれば、そのディレクトリで再開できます。
> x=-3 > if (x<-2) cat(x,"?n") # x<-2 は x に 2 を代入する、そして if (2) は真! 2 > x=-3 > if (x < -2) cat(x,"?n") # x と -2 の大小比較 -3
> x = 2 > if (3.1) cat(x,"?n") # if (3.1) は真になる 2
# case1 x <- 1 # xに1を代入 y <-2 # yに2を代入 x+y #これはエラー #.case2 x <- 1 # xに1を代入 y <-2 # yに2を代入 x+y #これは 大丈夫 #コメントには全角スペースは使えるが、それ以外では使えない!
超初心者Tipsですが、ハマったので追加しました。分かりにくいですが# case1では1の後に全角スペースが入っています。
訳の分からないエラーが出る時にチェックすべき点をここに追加して頂ければ、勉強になります。-のの