機略戦記

Maneuver warfare

R : POSIXctをas.Date() する時にtzを指定しない場合、POSIXctのタイムゾーンに何が設定されていてもUTCとみなして処理されているのでは?

POSIXctはタイムゾーンを伴った日時型であり、これをas.Date()という組み込み関数に渡すと、Dateという日時型に変換できる。

この関数の挙動にどうにも違和感がある。
どうもこの関数、POSIXctをas.Date() する時にtzを指定しない場合、POSIXctのタイムゾーンに何が設定されていてもUTCとみなして処理されているようなのだ。

> as.POSIXct('2015-01-01 00:00:00')
[1] "2015-01-01 JST"
> as.Date(as.POSIXct('2015-01-01 00:00:00'))
[1] "2014-12-31"
> as.Date(as.POSIXct('2015-01-01 00:00:00', tz="UTC"))
[1] "2015-01-01"

実装を読んでみた

as.DateはRにおいて、総称関数と呼ばれるタイプの関数である。
これは、与えられた引数の型を判定して、型に応じて異なる処理を行う仕組みである。
この総称関数の実装を読むには以下のようにする。

> methods(as.Date)
[1] as.Date.IDate*    as.Date.POSIXct   as.Date.POSIXlt   as.Date.character as.Date.date      as.Date.dates     as.Date.default  
[8] as.Date.factor    as.Date.numeric  
see '?methods' for accessing help and source code

> as.Date.POSIXct
function (x, tz = "UTC", ...) 
{
    if (tz == "UTC") {
        z <- floor(unclass(x)/86400)
        attr(z, "tzone") <- NULL
        structure(z, class = "Date")
    }
    else as.Date(as.POSIXlt(x, tz = tz))
}
<bytecode: 0x5d0f708>
<environment: namespace:base>

as.Date.POSIXcttzにデフォルト引数として"UTC"が指定されている。

function (x, tz = "UTC", ...) 

これでは、引数のPOSIXcttzがなんであれ、(as.Date()tzが明示的に指定されない限り)"UTC"として処理されてしまう。

(…と、読み取ったんですが合ってますかね? 何か見落としがあったら教えて下さい。)

現状のas.Dateのインターフェースデザインの課題

このようなAPIのデザインはフールプルーフの原則にのっとっていないと感じる。
この関数は、「as.Date()を使う時はtzを明示的に指定する必要がある」という認識を欠いた人に対して手痛い打撃を与えることになる。

もし自分が実装者だったら?

  • tzを明示的に指定しない場合に例外を出すか、引数となったPOSIXcttzを使用するようにする。
    • 今から変えたら後方互換性が凄い事になるので無理だろうけど…

自分もこういうデザインをしないように気をつけます…

R 「エラー: 関数 "grid.newpage" を見つけることができませんでした」と言われる

結論

library(grid)する。

> # エラーになる
> grid.newpage()
 エラー:  関数 "grid.newpage" を見つけることができませんでした 
>
> # gridを読み込めば大丈夫
> library(grid)
> grid.newpage() 

説明

grid.newpage()ggplot2に含まれていない。

[R] キーワード付き引数みたいな事がしたい

  • rubyで言うところのキーワード付き引数みたいな事がしたい。

結論

  • 普通に引数を定義するだけで、キーワード付き引数のように振る舞う。
function_argument_biheibia_test <- function(argument1, argument2) {
  print(argument2)
}
function_argument_biheibia_test(argument2='test_message')

# => "test_message"

[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に使うキーを動的に指定できる。