xtfrm(data.frame)でエラーが出るようになった

order()経由でエラーを見た人多数
R
公開

2024年4月27日

order()関数の引数にdata.frameを渡したことはあるでしょうか?order()の引数はvectorが想定されているので、普通に考えればdata.frameは渡せないように思えますね。(S3クラスで別途定義されていればその限りではありませんが)

実際、data.frameを渡すとこのようにエラーになります。

order(iris)
Error in xtfrm.data.frame(x) : cannot xtfrm data frames
Calls: order ... lapply -> FUN -> as.vector -> xtfrm -> xtfrm.data.frame

ところが、R4.2.3まではorder()関数にdata.frameを渡してもエラーにならずに値が返ってきていました。エラーが出るようになったのはR4.3.0からです。ただしorder()関数が変わったのではなく、その中で呼ばれているxtfrm()関数が変わっています。xtfrm()は並べ替えの基準を定義する関数ですが、この変更に関してインターネットで検索してもあまり情報がないのでソースコードを確認してみました。

R4.2.3ではこのような定義になっていて、特別な環境変数_R_STOP_ON_XTFRM_DATA_FRAME_がセットされている場合だけエラーとなり、そうでなければ別クラスのオブジェクトとしてxtfrm()を試みる動作になっていました。(その結果とりあえずうまく動いていたことになります)

xtfrm.data.frame <- function(x) {
    if(tolower(Sys.getenv("_R_STOP_ON_XTFRM_DATA_FRAME_")) %in%
       c("1", "yes", "true"))
        stop("cannot xtfrm data frames")
    else {
        warning("cannot xtfrm data frames")
        NextMethod("xtfrm")
    }
}

これがR4.3.0では、有無を言わさずエラーを出して処理が止まるように変わっています。

xtfrm.data.frame <- function(x) {
    stop("cannot xtfrm data frames")
}

xtfrm()関数は並べ替えのコアな処理だけを行うものなので、直接使うことはほとんどありません。なのでorder()などのよく使われる関数から呼び出されたときに初めて気が付くパターンが多いと思います。R4.2.3まではうまく動いていたのに、R4.3.0にバージョンアップしたら動かなくなったという場合の原因の1つになりそうですね。

不思議なのはこの変更がNew featuresに載っていないことです。Rはバージョンアップのたびに変更箇所を細かく出していてすごいなと思っているのですが、書き忘れとかもあるのでしょうかね。data.frameに変換するas.data.frame()に関する変更などは載っているのですがxtfrm()のdata.frameメソッドに関する変更は見当たりませんでした。

とは言え、そもそもorder()にdata.frameを渡すのが間違いなので、エラーになったならばコードを適切に修正するべきでしょう。ただ、Rは関数本来の仕様を守らなくても何となく動いてしまうことが多いので意図せずそうなっていたということも十分起こり得ますね。