機略戦記

Maneuver warfare

[dplyr] group_byを行う時、集約に使うキーを変数で指定したい。

やりたい事

ここにirisがある。

> head(iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

これをPetal.Widthgroup_byしてnをカウントしたい時はこうする。

> iris %>% group_by(Petal.Width) %>% summarise(n = n())
Source: local data frame [22 x 2]

   Petal.Width  n
1          0.1  5
2          0.2 29
3          0.3  7
...

今回は、Petal.Widthを使ってgroup_byしたが、これを動的に指定したい。

結論

group_by_を使う + キーは変数に入れておく。

> group_by_key <- "Petal.Width"
> iris %>% group_by_(group_by_key) %>% summarise(n = n())
Source: local data frame [22 x 2]

   Petal.Width  n
1          0.1  5
2          0.2 29
3          0.3  7

このコードで言うところのgroup_by_keyに任意のカラム名を入れる事でgroup_byに使うキーを動的に指定できる。

プログラム実行中のある時点で処理を止め、止めた位置のコンテキストを維持したまま対話的にコードを実行したい(Rubyのbinding.pryみたいな事がしたい)

結論

止めたい位置でbrowser()を実行する。

例:

このようなスクリプトがあったとする。

a <- 1

止めたい位置にbrowser()を挿入する。

a <- 1
browser()

実行時にconsoleが起動し、対話的にコードを実行できる。

Browse[1]> a
[1] 1

説明

browser()が実行された箇所で参照できる変数や関数が自由にいじれる。

これはデバッグに大変便利。

[R] 文字列が複数格納されたvectorを結合して一つの文字列にしたい

結論

> string_vector <- c('abc', 'def', 'ghi')
> Reduce(function(x, y){ paste(x,  y) }, string_vector)
[1] "abc def ghi"

こうすれば行ける。
もっとシンプルな方法は無いものか…

背景

ある変数のclassをチェックして、想定外の値だったらstop()させるような処理が書きたい。

stop()させた時、エラーメッセージとしてチェックした変数のclassを表示したい。

この時、class()の戻り値は文字列のvectorである可能性がある。

これをいい感じに表示したかった。

  • classを複数持っている例:
> class(data.table())
[1] "data.table" "data.frame"

R あるdata.tableが指定したカラムを備えているか判定したい。ただし指定したカラム以外のカラムがくっついていてもTRUEを返させたい。

結論

# 期待するカラム(の名前)
expect_column_names <- c('V1', 'V2') 

# 判定したいテーブルが持っているカラム。
# 「V3は別にマストで存在していて欲しい訳ではないがあっても問題ない」という条件で判定したい。
column_names <- names(data.table(V1=1, V2=2, V3=3)) 

all(expect_column_names %in% column_names)
# TRUE

説明

あるdata.tableが指定したカラムを備えているか判定したい。ただし指定したカラム以外のカラムがくっついていてもTRUEを返させたい。

言い換えると、「期待するカラム名data.tableが持つカラム名の部分集合か判定したい」という事である。

上記でその判定ができる。

R で data.tableに変数で指定した名前の列を追加したい

結論

  • eval以外のいい方法が見つからなかった。
sample_data_table <- data.table(V1=1, V2=2)
new_column_name <- 'new_column'

expr <- parse(text = paste(new_column_name, ":= V1+V2"))
sample_data_table[, eval(expr)]

## Checking the result
print(sample_data_table)
#    V1 V2 new_column
# 1:  1  2          3

説明

  • new_column_nameで指定したカラム名のカラムを追加している。
  • 内容は、V1+V2
  • 静的に書いた場合こういうコードになる。
    • sample_data_table[, new_column := V1+V2]
    • new_columnの部分を変数で指定するためにevalしている。