(特定の列値の値に応じて)突然変異が条件付きであるときに突然変異を使用できますか?
この例は私が何を意味するのかを示すのに役立ちます。
structure(list(a = c(1, 3, 4, 6, 3, 2, 5, 1), b = c(1, 3, 4,
2, 6, 7, 2, 6), c = c(6, 3, 6, 5, 3, 6, 5, 3), d = c(6, 2, 4,
5, 3, 7, 2, 6), e = c(1, 2, 4, 5, 6, 7, 6, 3), f = c(2, 3, 4,
2, 2, 7, 5, 2)), .Names = c("a", "b", "c", "d", "e", "f"), row.names = c(NA,
8L), class = "data.frame")
a b c d e f
1 1 1 6 6 1 2
2 3 3 3 2 2 3
3 4 4 6 4 4 4
4 6 2 5 5 5 2
5 3 6 3 3 6 2
6 2 7 6 7 7 7
7 5 2 5 2 6 5
8 1 6 3 6 3 2
新しいコラムgを作成するためにdplyrパッケージを使って問題の解決策を見つけることを望んでいました(そしてこれはうまくいくはずのコードではありませんが、目的が明確になると思います)。
library(dplyr)
df <- mutate(df,
if (a == 2 | a == 5 | a == 7 | (a == 1 & b == 4)){g = 2},
if (a == 0 | a == 1 | a == 4 | a == 3 | c == 4) {g = 3})
私が探しているコードの結果は、この特定の例ではこの結果になるはずです。
a b c d e f g
1 1 1 6 6 1 2 3
2 3 3 3 2 2 3 3
3 4 4 6 4 4 4 3
4 6 2 5 5 5 2 NA
5 3 6 3 3 6 2 NA
6 2 7 6 7 7 7 2
7 5 2 5 2 6 5 2
8 1 6 3 6 3 2 3
誰もがdplyrでこれを行う方法についての考えを持っていますか?このデータフレームはほんの一例です、私が扱っているデータフレームははるかに大きいです。その速度のために私はdplyrを使おうとしました、しかしおそらくこの問題を扱うための他のより良い方法がありますか?
ifelse
を使用
df %>%
mutate(g = ifelse(a == 2 | a == 5 | a == 7 | (a == 1 & b == 4), 2,
ifelse(a == 0 | a == 1 | a == 4 | a == 3 | c == 4, 3, NA)))
追加 - if_else : dplyr 0.5ではif_else
関数が定義されているので、代わりにifelse
をif_else
に置き換えることができます。ただし、if_else
はifelse
よりも厳密であるため(条件の両方のレッグは同じ型でなければなりません)、その場合のNA
はNA_real_
に置き換える必要があります。
df %>%
mutate(g = if_else(a == 2 | a == 5 | a == 7 | (a == 1 & b == 4), 2,
if_else(a == 0 | a == 1 | a == 4 | a == 3 | c == 4, 3, NA_real_)))
追加 - case_whenこの質問が投稿されてから、dplyrはcase_when
を追加しました。
df %>% mutate(g = case_when(a == 2 | a == 5 | a == 7 | (a == 1 & b == 4) ~ 2,
a == 0 | a == 1 | a == 4 | a == 3 | c == 4 ~ 3,
TRUE ~ NA_real_))
この問題に対処するための他のより良い方法を求めているので、data.table
を使った別の方法があります。
require(data.table) ## 1.9.2+
setDT(df)
df[a %in% c(0,1,3,4) | c == 4, g := 3L]
df[a %in% c(2,5,7) | (a==1 & b==4), g := 2L]
g
を正しく取得するために、条件文の順序が逆になっていることに注意してください。 2番目の代入の間でさえ、作られたg
のコピーはありません - 代わりに置き換えられます.
大きなデータでは、ネストされたif-else
を使用するよりもパフォーマンスが向上します。 それは 'yes'と 'no'の両方を評価できます。場合 、そして入れ子にすることは私見を読み/維持することを難しくすることができます。
これは比較的大きいデータのベンチマークです。
# R version 3.1.0
require(data.table) ## 1.9.2
require(dplyr)
DT <- setDT(lapply(1:6, function(x) sample(7, 1e7, TRUE)))
setnames(DT, letters[1:6])
# > dim(DT)
# [1] 10000000 6
DF <- as.data.frame(DT)
DT_fun <- function(DT) {
DT[(a %in% c(0,1,3,4) | c == 4), g := 3L]
DT[a %in% c(2,5,7) | (a==1 & b==4), g := 2L]
}
DPLYR_fun <- function(DF) {
mutate(DF, g = ifelse(a %in% c(2,5,7) | (a==1 & b==4), 2L,
ifelse(a %in% c(0,1,3,4) | c==4, 3L, NA_integer_)))
}
BASE_fun <- function(DF) { # R v3.1.0
transform(DF, g = ifelse(a %in% c(2,5,7) | (a==1 & b==4), 2L,
ifelse(a %in% c(0,1,3,4) | c==4, 3L, NA_integer_)))
}
system.time(ans1 <- DT_fun(DT))
# user system elapsed
# 2.659 0.420 3.107
system.time(ans2 <- DPLYR_fun(DF))
# user system elapsed
# 11.822 1.075 12.976
system.time(ans3 <- BASE_fun(DF))
# user system elapsed
# 11.676 1.530 13.319
identical(as.data.frame(ans1), as.data.frame(ans2))
# [1] TRUE
identical(as.data.frame(ans1), as.data.frame(ans3))
# [1] TRUE
これがあなたが求めていた代替手段であるかどうかわからないが、私はそれが役立つことを願っています。
dplyrは、ベクトル化されたifを提供する関数case_when
を持っています。標準のdplyrの方法で変数にアクセスすることはできず、NAのモードを宣言する必要があるため、構文はmosaic:::derivedFactor
と比較すると少し変わっていますが、mosaic:::derivedFactor
よりかなり高速です。
df %>%
mutate(g = case_when(a %in% c(2,5,7) | (a==1 & b==4) ~ 2L,
a %in% c(0,1,3,4) | c == 4 ~ 3L,
TRUE~as.integer(NA)))
EDIT:パッケージのバージョン0.7.0以前からdplyr::case_when()
を使用している場合は、変数名の前に '.$
'を付ける必要があります(例:.$a == 1
の内側にcase_when
を書く)。
ベンチマーク:ベンチマーク(Arunの記事の関数を再利用)とサンプルサイズの縮小
require(data.table)
require(mosaic)
require(dplyr)
require(microbenchmark)
DT <- setDT(lapply(1:6, function(x) sample(7, 10000, TRUE)))
setnames(DT, letters[1:6])
DF <- as.data.frame(DT)
DPLYR_case_when <- function(DF) {
DF %>%
mutate(g = case_when(a %in% c(2,5,7) | (a==1 & b==4) ~ 2L,
a %in% c(0,1,3,4) | c==4 ~ 3L,
TRUE~as.integer(NA)))
}
DT_fun <- function(DT) {
DT[(a %in% c(0,1,3,4) | c == 4), g := 3L]
DT[a %in% c(2,5,7) | (a==1 & b==4), g := 2L]
}
DPLYR_fun <- function(DF) {
mutate(DF, g = ifelse(a %in% c(2,5,7) | (a==1 & b==4), 2L,
ifelse(a %in% c(0,1,3,4) | c==4, 3L, NA_integer_)))
}
mosa_fun <- function(DF) {
mutate(DF, g = derivedFactor(
"2" = (a == 2 | a == 5 | a == 7 | (a == 1 & b == 4)),
"3" = (a == 0 | a == 1 | a == 4 | a == 3 | c == 4),
.method = "first",
.default = NA
))
}
microbenchmark(
DT_fun(DT),
DPLYR_fun(DF),
DPLYR_case_when(DF),
mosa_fun(DF),
times=20
)
これは与える:
expr min lq mean median uq max neval
DT_fun(DT) 1.503589 1.626971 2.054825 1.755860 2.292157 3.426192 20
DPLYR_fun(DF) 2.420798 2.596476 3.617092 3.484567 4.184260 6.235367 20
DPLYR_case_when(DF) 2.153481 2.252134 6.124249 2.365763 3.119575 72.344114 20
mosa_fun(DF) 396.344113 407.649356 413.743179 412.412634 416.515742 459.974969 20
derivedFactor
パッケージのmosaic
関数はこれを処理するように設計されているようです。この例を使用すると、次のようになります。
library(dplyr)
library(mosaic)
df <- mutate(df, g = derivedFactor(
"2" = (a == 2 | a == 5 | a == 7 | (a == 1 & b == 4)),
"3" = (a == 0 | a == 1 | a == 4 | a == 3 | c == 4),
.method = "first",
.default = NA
))
(結果を因数ではなく数値にしたい場合は、derivedFactor
をas.numeric
呼び出しでラップすることができます。)
derivedFactor
は、任意の数の条件にも使用できます。
case_when
は、次の場合にSQLスタイルのケースをかなりきれいに実装したものになりました。
structure(list(a = c(1, 3, 4, 6, 3, 2, 5, 1), b = c(1, 3, 4,
2, 6, 7, 2, 6), c = c(6, 3, 6, 5, 3, 6, 5, 3), d = c(6, 2, 4,
5, 3, 7, 2, 6), e = c(1, 2, 4, 5, 6, 7, 6, 3), f = c(2, 3, 4,
2, 2, 7, 5, 2)), .Names = c("a", "b", "c", "d", "e", "f"), row.names = c(NA,
8L), class = "data.frame") -> df
df %>%
mutate( g = case_when(
a == 2 | a == 5 | a == 7 | (a == 1 & b == 4 ) ~ 2,
a == 0 | a == 1 | a == 4 | a == 3 | c == 4 ~ 3
))
Dplyrを使う0.7.4