COLOR(red){SIZE(25){リストに関する Tips 大全}}

リストに関する操作は、R をマスターする基本です。関連する
Tips を脈絡なくできるだけ集めたいと思います。お気づきの正統派・裏技テクニックを
お寄せください。一部重複はむしろ好ましいと思います。


#contents
~
// //////////////////////////////////////////////////////////////////
//リスト
// //////////////////////////////////////////////////////////////////

*リスト成分の成分名による操作に関する注意 (from r-help, 2005.02.11)
*リスト成分の成分名による操作に関する注意 (from r-help, 2005.02.11) [#scd4d0c2]
関数引数にリストとその成分名を与える際に起こりえるトラブル
 > x <- list(a=1:5, b=rnorm(5))
 > x$a           #  x[[1]] でも良い
 [1] 1 2 3 4 5
 > x$"a"         # 成分名の指定を「文字列」で行なう
 [1] 1 2 3 4 5
 > plot(x$a, x$b) # 問題なし。plot(x[[1]],x[[2]], plot(x$"a", x$"b") でも当然良い

 > test1 <- function(x ,c1, c2) plot(x$c1, x$c2)
 > test1(x,a,b)        # エラー
 Error in xy.coords(x, y, xlabel, ylabel, log) :
        x and y lengths differ
 > test1(x, "a", "b")  # エラー
 Error in xy.coords(x, y, xlabel, ylabel, log) :
        x and y lengths differ

 > test2 <- function(x ,c1, c2) plot(x[[c1]], x[[c2]])
 > test2(x,a,b)        # エラー 
 Error in plot(x[[c1]], x[[c2]]) : Object "a" not found
 > test2(x,"a","b") # 問題なし(成分名を文字列で指定している)
 > test2(x,1,2) # 問題なし

*複数回の同一試行の結果をリストに一括記録 lapply(), try()
*複数回の同一試行の結果をリストに一括記録 lapply(), try() [#v9335a77]
注:ある試行でエラーが起きても残りを続行するために try 関数を使用(help(try)参照)
 > doit <- function() {mean(rnorm(30))}      # 30個の正規乱数の平均値を求める関数
 > res <- lapply(1:3, function(i) try(doit()))
 > res
 [[1]]
 [1] -0.359225966054957
 [[2]]
 [1] 0.0249291122975083
 [[3]]
 [1] -0.0972657631255351

*(二重)リストの初期化 <- as.list()
*(二重)リストの初期化 <- as.list() [#ha6b47d4]

リストは属性の異なる任意のオブジェクトを一括保持でき、添字で操作できるため便利な
データタイプである。リスト成分は二重かぎ括弧演算子 [[,]] でアクセスする。名前付き
成分の場合には [["name"]] もしくは $ 演算子でアクセスする。Lst[[1]] がベクトル・配列
の時は Lst[[1]][1,2] 等でその要素にアクセスできる

一重リストの初期化は

 > Lst <- as.list(NA)  # リストオブジェクト Lst の初期化
 > Lst
 [[1]]
 [1] NA
 > Lst[[1]] <- c(1,2,3) # リストの第一成分(ベクトル)
 > Lst
 [[1]]
 [1] 1 2 3
 > Lst[[3]] <- matrix(1:4,ncol=2)  # リストの第3成分(行列)
 > Lst
 [[1]]
 [1] 1 2 3
 [[2]]                             # 自動的に途中の成分が生成される
 NULL
 [[3]]
      [,1] [,2]
 [1,]    1    3
 [2,]    2    4
 > Lst[[2]] <- "second character element" # 空の第二成分に文字列を代入
 > Lst
 [[1]]
 [1] 1 2 3
 [[2]]
 [1] "second character element"
 [[3]]
     [,1] [,2]
 [1,]    1    3
 [2,]    2    4

最初から要素数を指定して空のリストを作るには

 > Lst <- as.list(rep(NA,2))  # 要素数2
 > Lst
 [[1]]
 [1] NA
 [[2]]
 [1] NA

リストを具体的要素を与えて構成するには list 関数を使う。各要素には名前タグを
付けることが出来、要素番号以外に名前タグで操作(二重かぎ括弧以外に $ 演算子を
使える)できる

 > Lst <- list(sex=c(1,2),name=c("Tarou","Hanako"))
 > Lst
 $sex
 [1] 1 2
 $name
 [1] "Tarou"  "Hanako"
 > Lst[[1]]
 [1] 1 2
 > Lst[["sex"]]
 [1] 1 2
 > Lst$sex
 [1] 1 2

二重リスト(リストの各成分がまたリスト)を初期化するには

 > Lst <- as.list(c(NA,NA))
 > Lst[[1]] <- as.list(c(NA,NA))
 > Lst[[2]] <- as.list(c(NA,NA))
 > Lst
 [[1]]
 [[1]][[1]]
 [1] NA
 [[1]][[2]]
 [1] NA
 [[2]]
 [[2]][[1]]
 [1] NA
 [[2]][[2]]
 [1] NA
 > Lst[[1]][[2]] <- c(1,3)
 > Lst[[1]]
 [[1]]
 [1] NA
 [[2]]
 [1] 1 3
 > Lst[[1]][[2]]  # Lst[[1,2]] は不可
 [1] 1 3

*同じ範囲に対する多重ループをリストを範囲に取ることにより簡略化
*同じ範囲に対する多重ループをリストを範囲に取ることにより簡略化 [#f2d91e84]

for ループのループ範囲にはベクトル以外にリストを与えることが出来る
例えば2重ループ

 > for (i in 1:n) { for (j in 1:n) f(i,j)}

は

 > rangelist <- multiplerange(1:n)
 > for (i in rangelist) f(i[1],i[2])

と出来る(同じ多重範囲のループが瀕出する際は、コードが簡潔になり、実行時間も
多少早くなる)。ここで multiplerange(1:n) は全ての組合せ c(i,j), 1<=i,j<=n,
からなるリストを作る次の関数:

 multiplerange <- function(range) {
   mplerange <- as.list(rep(NA,length(range)^2))
   ct <- 0
   for (i1 in range) { for (i2 in range) {
     mplerange[[ct<-ct+1]] <- c(i1,i2)
   }}
   return(mplerange)
 }


*関数から複数の値を返す (リスト返り値)
*関数から複数の値を返す (リスト返り値) [#gdba6b85]

一つの関数から複数の値を返すにはそれらをリストとして返り値
とすれば良い。リストの各成分には元の変数名が名前タグとして自動的に付加される

 # この暗黙のリスト返り値機能は現在はエラーとされる!!!
 > test <- function(x){y=log(x);z=sin(x);return(x,y,z)} # 暗黙のリスト返り値
 > test(1:3)
 $x
 [1] 1 2 3
 
 $y
 [1] 0.0000000 0.6931472 1.0986123
 
 $z
 [1] 0.8414710 0.9092974 0.1411200

名前タグを自前で指定するには明示的に名前付きリストを返り値にする

 > test <- function(x){y=log(x);z=sin(x);return(list(value=x,log=y,sin=z))}
 > test(1:3)
 $value
 [1] 1 2 3
 
 $log
 [1] 0.0000000 0.6931472 1.0986123
 
 $sin
 [1] 0.8414710 0.9092974 0.1411200

*リストの要素を NULL にセット
*リストの要素を NULL にセット [#tf9226c2]

  x[i] <- list(NULL)

を用いると, リスト x の要素 i に NULL をセットすることができます. 名前付きの要素についても同様。x[i] あるいは x[ [i] ] に NULL をセットすると, リストから該当する要素を削除してしまう.

* リスト成分に後から名前タグを付ける、変更する、取り去る (names() 関数)
* リスト成分に後から名前タグを付ける、変更する、取り去る (names() 関数) [#s5721c19]

リスト x には成分名を表す名前タグ文字ベクトル names(x) が付随する。names(x) の該当成分が空の文字列 "" であることが、すなわち名前タグが無いということ。名前タグの追加、変更、除去はしたがって文字ベクトル names(x) を処理すれば良い。 

 > x=list(1:3,matrix(1:4,c(2,2))) # 名前タグの無いリスト
 > x <- list(1:3,matrix(1:4,c(2,2))) # 名前タグの無いリスト
 > x
 [[1]]
 [1] 1 2 3
 [[2]]
      [,1] [,2]
 [1,]    1    3
 [2,]    2    4
 > names(x)<-c("vector","matrix") # 名前タグを後から付ける
 > names(x) <- c("vector","matrix") # 名前タグを後から付ける
 > x
 $vector
 [1] 1 2 3
 $matrix
      [,1] [,2]
 [1,]    1    3
 [2,]    2    4
 > x$vector
 [1] 1 2 3
 > x$matrix
      [,1] [,2]
 [1,]    1    3
 [2,]    2    4
 > names(x)<-c("vector","")  # 第二成分の名前タグを取り除く
 > names(x) <- c("vector","")  # 第二成分の名前タグを取り除く
 > x
 $vector
 [1] 1 2 3
 [[2]]
      [,1] [,2]
 [1,]    1    3
 [2,]    2    4
 > names(x)<-c("","") # タグ無しのリストに戻す
 > x
 [[1]]
 [1] 1 2 3
 [[2]]
      [,1] [,2]
 [1,]    1    3
 [2,]    2    4
 > names(x)[[1]] <- "vector"  # 一部だけ指定する

* リストの中身全体を見やすく整形して出力 ( 関数 str() ) 
* リストの中身全体を見やすく整形して出力 ( 関数 str() ) [#m613ed32]
これはリスト以外にも使えますから、知っていると重宝します。

 > x=list(vec=1:3, mat=matrix(1:4,c(2,2)),char=c("a","b"))
 > str(x)
 List of 3
  $ vec : int [1:3] 1 2 3
  $ mat : int [1:2, 1:2] 1 2 3 4
  $ char: chr [1:2] "a" "b"

* 数値からなるリストをベクトルに変換  as.numeric()  (2003.12.22)
* 数値からなるリストをベクトルに変換  as.numeric()  (2003.12.22) [#u17165c3]
lapply() 関数を用いて複数回試行の結果をリストに記録したものを、ベクトルに変換する際便利。逆の操作は as.list()

 > x = list(1,2,3)
 > x <- list(1,2,3)
 > x
 [[1]]
 [1] 1
 [[2]]
 [1] 2
 [[3]]
 [1] 3
 > as.numeric(x)
 [1] 1 2 3


* ベクトルからなるリストを、1つのベクトルへ変換 unlist() (2007.1.10)
* ベクトルからなるリストを、1つのベクトルへ変換 unlist() (2007.1.10) [#pb7768d5]

 unlist(options())
 unlist(options(), use.names=FALSE)

 l.ex <- list(a = list(1:5, LETTERS[1:5]), b = "Z", c = NA)
 unlist(l.ex, recursive = FALSE)
 unlist(l.ex, recursive = TRUE)

 l1 <- list(a="a", b=2, c=pi+2i)
 unlist(l1) # a character vector
 l2 <- list(a="a", b=as.name("b"), c=pi+2i)
 unlist(l2) # remains a list



* 複数の行列、データフレームからなるリストの各成分から特定要素を抽出する (from r-help, 2004.09.17)
* 複数の行列、データフレームからなるリストの各成分から特定要素を抽出する (from r-help, 2004.09.17) [#pc843203]
 > data(iris)         # データフレーム iris
 > hiris = head(iris) # 長過ぎるので簡略化
 > L <- list(hiris, hiris) # 2つのデータフレームからなるリスト
 > lapply(L, "[", 1, 1) # 成分データフレームの第一行第一列をリストとして取り出し
 [[1]]
 [1] 5.1
 
 [[2]]
 [1] 5.1

 > lapply(L, "[[", 1) # 成分データフレームの第一列をリストとして取り出し
 [[1]]
 [1] 5.1 4.9 4.7 4.6 5.0 5.4 
 
 [[2]]
 [1] 5.1 4.9 4.7 4.6 5.0 5.4
 
 > lapply(L, "[", 1)  # 成分データフレームの第一行をデータフレームのリストとして取り出し
 [[1]]
   Sepal.Length
 1          5.1
 2          4.9
 3          4.7
 4          4.6
 5          5.0
 6          5.4 
 
 [[2]]
   Sepal.Length
 1          5.1
 2          4.9
 3          4.7
 4          4.6
 5          5.0
 6          5.4 

 > lapply(L, function(x) x[1,]) # 成分データフレームの第一行をリストとして取り出し
 [[1]]
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
 1          5.1         3.5          1.4         0.2  setosa 
 
 [[2]]
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
 1          5.1         3.5          1.4         0.2  setosa 
 
 # 成分データフレームの第一行と第一列をからなるリストを、リストとして取り出し
 > lapply(L, function(x) list(x[1,],x[,1]))  # 
 [[1]]
 [[1]][[1]]
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
 1          5.1         3.5          1.4         0.2  setosa 
 
 [[1]][[2]]
 [1] 5.1 4.9 4.7 4.6 5.0 5.4 
 
 [[2]]
 [[2]][[1]]
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
 1          5.1         3.5          1.4         0.2  setosa
 
 [[2]][[2]]
 [1] 5.1 4.9 4.7 4.6 5.0 5.4

* リストの成分を成分名で指定する (r-help, 2004.10.10)
* リストの成分を成分名で指定する (r-help, 2004.10.10) [#f9620d1d]
リストの何番目かを意識しないで新規成分を加えたり、取り出したりするのに便利。

 > lst <- list()
 > element <- "a"
 > lst[[element]] <- 1:5
 > element <- "b"
 > lst[[element]] <- letters[1:5]
 > lst
 $a
 [1] 1 2 3 4 5
 $b
 [1] "a" "b" "c" "d" "e"

 > lst <- list()
 > nm <- c("dude", "chick")
 > lst[[nm[1]]] <- 123
 > lst[[nm[2]]] <- 456 
 > lst
 $dude
 [1] 123
 $chick
 [1] 456

* リストの行列化 2005.01.25
* リストの行列化 2005.01.25 [#kd290b33]
リストも次元属性を与えれば行列として操作できる
 > x <- list(1,2,3,4)
 > x
 [[1]]
 [1] 1
 
 [[2]]
 [1] 2
 
 [[3]]
 [1] 3
 
 [[4]]
 [1] 4
 
 > dim(x) <- c(2,2) # 2x2 行列にする
 > x
      [,1] [,2]
 [1,] 1    3
 [2,] 2    4
 > x[1,2]           # 成分は添字操作で取り出せる
 [[1]]
 [1] 3
 
 > is.list(x[1,2])  # 結果はリスト
 [1] TRUE
 > x[[1,2]]         # 二重鈎括弧演算子でもOK
 [1] 3
 > is.list(x[[1,2]])  # ただし結果は成分そのものでリストではない
 [1] FALSE

または do.call を使う
 > L <- list(a=rnorm(5), b=runif(5)) 
 > do.call("rbind", L)     # 行列化
         [,1]      [,2]       [,3]       [,4]      [,5]
 a -0.2610772 0.5175920 -0.7930714 -0.5240486 -1.527911
 b  0.1986414 0.7121043  0.8124055  0.3421709  0.738326
 > do.call("cbind", L)   # 行列化
         a                   b
 [1,] -0.2610772 0.1986414
 [2,]  0.5175920 0.7121043
 [3,] -0.7930714 0.8124055
 [4,] -0.5240486 0.3421709
 [5,] -1.5279110 0.7383260

もっと,変な使い方
 > L <- list(a=rnorm(5), b=runif(5)) 
 > t(sapply(L, "+"))
         [,1]        [,2]        [,3]      [,4]         [,5]
 a -0.8160980 -0.04252811 -0.06028301 1.0007900 -0.712706536
 b  0.7652187  0.31091773  0.39100277 0.3420776  0.002987919
 > sapply(L, "+")
                a           b
 [1,] -0.81609801 0.765218671
 [2,] -0.04252811 0.310917726
 [3,] -0.06028301 0.391002772
 [4,]  1.00078997 0.342077593
 [5,] -0.71270654 0.002987919

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS