web-dev-qa-db-ja.com

dplyr case_whenのdata.table代替

少し前に、彼らはifelse内のdplyrの代わりにNice SQLに似た方法、つまりcase_whenを導入しました。

追加のパッケージをロードせずに、1つのdata.tableステートメント内で異なる条件を指定できる同等の[]はありますか?

例:

library(dplyr)

df <- data.frame(a = c("a", "b", "a"), b = c("b", "a", "a"))

df <- df %>% mutate(
    new = case_when(
    a == "a" & b == "b" ~ "c",
    a == "b" & b == "a" ~ "d",
    TRUE ~ "e")
    )

  a b new
1 a b   c
2 b a   d
3 a a   e

それは確かに非常に役立ち、コードをはるかに読みやすくします(これらの場合にdplyrを使い続ける理由の1つ)。

9
arg0naut91

1)条件がデフォルトと相互に排他的で、すべての条件がfalseの場合、これは機能します。

library(data.table)
DT <- as.data.table(df) # df is from question

DT[, new := c("e", "c", "d")[1 +
                             1 * (a == "a" & b == "b") + 
                             2 * (a == "b" & b == "a")]
]

与える:

> DT
   a b new
1: a b   c
2: b a   d
3: a a   e

2)条件の結果が数値の場合、さらに簡単です。たとえば、cdの代わりに、デフォルトの3の10と17が必要だとします。

library(data.table)
DT <- as.data.table(df) # df is from question

DT[, new := 3 + 
            (10 - 3) * (a == "a" & b == "b") + 
            (17 - 3) * (a == "b" & b == "a")]

1ライナーを追加するだけでこれを実装できます。各行に少なくとも1つのTRUEレッグがあると想定しています。

when <- function(...) names(match.call()[-1])[apply(cbind(...), 1, which.max)]

# test
DT[, new := when(c = a == 'a' & b == 'b', 
                 d = a == 'b' & b == 'a', 
                 e = TRUE)]
17
G. Grothendieck

これは実際の答えではありませんが、コメントとしては長すぎます。不適切と思われる場合は、投稿を削除させていただきます。

通常のtidyverse依存関係なしに_dplyr::case_when_を使用するオプションについて説明する RStudioコミュニティの興味深い投稿 が存在します。

要約すると、3つの選択肢が存在するようです。

  1. Stefan Fleckdplyrから_case_when_を分離し、新しいパッケージをビルド lestbaseのみに依存。
  2. yonicd 開発 noplyr 、「基本的なdplyrおよびtidyr機能を整然とした依存関係なしに提供します」。
  3. Bob Rudis(hrbrmstr)freebase の作成者であり、「ベースRの「usethis」に似たパッケージで、「tidyverse」コードの擬似同等物です。 "、これもチェックする価値があるかもしれません。

あなたが望んでいるのが_case_when_だけの場合、lestは_data.table_と組み合わせると魅力的で最小限のオプションになると思います。


アップデート[2019年10月29日]

Tyson Barrett パッケージを最近作成 tidyfast GitHubで利用可能(現在はバージョン_0.1.0_として)、これは関数 "_dt_case_when_ dplyr::case_when()構文の場合、速度はdata.table::fifelse() "です。

16
Maurits Evers

これは、@ g-grothendieckの回答のバリエーションであり、非排他的な条件で機能します。

DT[, new := c("c", "d", "e")[
  apply(cbind(
    a == "a" & b == "b", 
    a == "b" & b == "a",
    TRUE), 1, which.max)]
  ]

DT
#    a b new
# 1: a b   c
# 2: b a   d
# 3: a a   e
2