1. ホーム
  2. r

dplyrで特定の値をNAに設定する

2023-10-13 22:06:40

質問

私はdplyr(データセット= dat、変数= x)でこのようなことを行う簡単な方法を考えています。

day$x[dat$x<0]=NA

簡単なはずなのですが、今のところこれが精一杯です。 もっと簡単な方法はないでしょうか?

dat =  dat %>% mutate(x=ifelse(x<0,NA,x))

どのように解決するのですか?

この場合 replace よりも少し速い ifelse :

dat <-  dat %>% mutate(x = replace(x, x<0, NA))

にインデックスを与えることで、もう少し高速化することができます。 replace を使って which :

dat <- dat %>% mutate(x = replace(x, which(x<0L), NA))

私のマシンでは、これで時間が3分の1に短縮されました。

以下は、異なる回答の小さな比較です。もちろん、これは単なる指標に過ぎません。

set.seed(24)
dat <- data.frame(x=rnorm(1e6))
system.time(dat %>% mutate(x = replace(x, x<0, NA)))
       User      System     elapsed
       0.03        0.00        0.03 
system.time(dat %>% mutate(x=ifelse(x<0,NA,x)))
       User      System     elapsed
       0.30        0.00        0.29 
system.time(setDT(dat)[x<0,x:=NA])
       User      System     elapsed
       0.01        0.00        0.02 
system.time(dat$x[dat$x<0] <- NA)
       User      System     elapsed
       0.03        0.00        0.03 
system.time(dat %>% mutate(x = "is.na<-"(x, x < 0)))
       User      System     elapsed
       0.05        0.00        0.05 
system.time(dat %>% mutate(x = NA ^ (x < 0) * x))
       User      System     elapsed
       0.01        0.00        0.02 
system.time(dat %>% mutate(x = replace(x, which(x<0), NA)))
       User      System     elapsed
       0.01        0.00        0.01 

(dplyr_0.3.0.2、data.table_1.9.4を使っています)


私たちは常にベンチマークに非常に興味があるので、特にdata.table-vs-dplyrの議論の過程で、私はmicrobenchmarkとakrunによるデータを使用して、答えの3つの別のベンチマークを提供します。私は dplyr1 を私の答えの更新版であるように修正したことに注意してください。

set.seed(285)
dat1 <- dat <- data.frame(x=sample(-5:5, 1e8, replace=TRUE), y=rnorm(1e8))
dtbl1 <- function() {setDT(dat)[x<0,x:=NA]}
dplr1 <- function() {dat1 %>% mutate(x = replace(x, which(x<0L), NA))}
dplr2 <- function() {dat1 %>% mutate(x = NA ^ (x < 0) * x)}
microbenchmark(dtbl1(), dplr1(), dplr2(), unit='relative', times=20L)
#Unit: relative
#    expr      min       lq   median       uq      max neval
# dtbl1() 1.091208 4.319863 4.194086 4.162326 4.252482    20
# dplr1() 1.000000 1.000000 1.000000 1.000000 1.000000    20
# dplr2() 6.251354 5.529948 5.344294 5.311595 5.190192    20