いろいろ倉庫

KNIME、EXCEL、R、Pythonなどの備忘録

【R】valueからnameを釣ってきたい

・お題:ベクトルやリストの要素には、名前を付けることができる。名前から要素を釣ってくるのが通常だけれど、今回は要素から名前を釣ってきたい。

 

・例えば、名前付きのベクトルを作ってみる。

> vec1 <- c(1, 2, 3, 4)
> names(vec1) <- c("A", "B", "C", "D")

> vec1
A B C D
1 2 3 4

・名前が"A"の要素を取り出す。
> vec1["A"]

・では逆に、要素が1の名前をとって来るにはどうするか?which関数を使うと良いらしい。which関数は要素のインデックス番号を返す。例えば、valueが1の要素を探して、そのnameとインデックスを返してくれる(今回はvalueとインデックスがたまたま一致している)。

> which(vec1 == 1)

・ちなみに、vec1 == 1だけ実行すると、valueが1か否かのBoolが返ってくる。

> vec1 == 1
    A     B     C     D
 TRUE FALSE FALSE FALSE

・そのため、valueが1以外のものを釣ってくることもできる。

> which(vec1 != 1)
B C D 
2 3 4 

・今回はvalueが数字なので、不等号で釣ることもできる。

> which(vec1 > 2)
C D 
3 4 

> which(vec1 <= 2)
A B 
1 2 

・whichだとインデックスも返ってくるが、名前のところだけ釣ってきたいのであれば、names関数に渡せば良さそう。

> names(which(vec1 <= 2))
[1] "A" "B"

 

・同様に、リストも作成してみる。

> lis1 <- list("A" = 1,
+              "B" = 2,
+              "C" = 3,
+              "D" = 4,
+              "E" = 4)
> lis1
$A
[1] 1

$B
[1] 2

$C
[1] 3

$D
[1] 4

$E
[1] 4

> lis1$A
[1] 1

・これもwhichで釣ってくることができる。

> which(lis1 == 2)


> which(lis1 == 4)
D E 
4 5 

 

・では、Listの各要素がベクトルだった場合はどうなるか?とりあえずリストを作成する。

> lis2 <- list("A" = 1,
+              "B" = c(2,3),
+              "C" = c(4,5,6))
> lis2
$A
[1] 1

$B
[1] 2 3

$C
[1] 4 5 6

・例えば、このリストで要素が1のものを釣ってこようとする。

>  which(lis2 == 1)
Error in which(lis2 == 1) : 
  'list' object cannot be coerced to type 'double'

・エラーが出た。型があっていないらしい。。例えば今回のように、リストの要素が一つの数字などであれば、unlistしてベクトル化してしまうのも手かもしれない。

> which(unlist(lis2) == 1)

・では、(2, 3)というベクトルを含む要素をリストから釣ってきたい場合はどうするか?リストの各要素に対して、(2, 3)を含むか否か尋ねてBoolのベクトルを作ることを考えてみた。

> lis2 %in% list(c(2,3))
[1] FALSE  TRUE FALSE

> lis2[lis2 %in% list(c(2,3))]
$B
[1] 2 3

・一応目的の操作ができた。

・ちなみに、ベクトルの要素の一部だけでBoolを作成してもFALSEになるため、うまくいかない。ベクトルの要素がドンピシャで一致している場合にだけちゃんと返してくれるらしい。

> lis2 %in% list(c(5,6))
[1] FALSE FALSE FALSE

> lis2[lis2 %in% list(c(5,6))]
named list()

> lis2[lis2 %in% list(c(4,5,6))]
$C
[1] 4 5 6

 

・では、例えば2を含む要素を釣ってきたい場合はどうするか?この場合であれば、リストの要素が2を含む(ベクトル)か否かだけが重要で、ベクトル中の他の要素はなんでも良い。

・lis2の要素を一つずつ取り出し、その要素の中に2が含まれるのかを調べて、lis2の要素ごとにBoolで返せばよさそう。lis2の要素を一つずつ取り出して処理するので、sapply関数を使用して、functionで関数を定義してみる。

> sapply(lis2, function(n) 2 %in% n)
    A     B     C 
FALSE  TRUE FALSE 

・これをwhichに投げてみる。

> which(sapply(lis2, function(n) 2 %in% n))

・今回欲しいのはlis2の要素の名前なので、これにnames関数をくっつければBが返ってきて、目的の処理ができる。ちなみに、このやり方だと、c(4,5)というベクトルを含むlis2中の要素としてCを返してくれない。挙動を理解していないと妙なミスにつながりそうだし、もっと良いやり方がありそう。。

 

 

おわり