web-dev-qa-db-ja.com

Rの数値の範囲をフィルタリングするにはどうすればよいですか?

次のようなデータフレームMydataがあるとします。

Mydata <- data.frame(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
                     y = c(20, 30, 45, 54, 65, 78, 97, 102, 123, 156))

このデータフレームをフィルター処理して別のデータフレームを作成し、37の間のxの値と、それらに対応するy値のみが表示されるようにします。私は次を試みました:

new_frame <- Mydata %>% filter(x == (3:7))

これはうまくいきませんでした。指定した範囲でどのようにフィルタリングしますか?

すべての助けてくれてありがとう

9
Paul Ibrahim

つかいます %in%

library(dplyr)
new_frame<- Mydata%>% filter(x %in% (3:7))
new_frame
#   x  y
# 1 3 45
# 2 4 54
# 3 5 65
# 4 6 78
# 5 7 97
7
MHammer

いくつかの答えに既に存在する上限と下限のフィルタリングやハードコーディングなど、多数の優れたdplyrソリューション:

MydataTable%>% filter(between(x, 3, 70))
Mydata %>% filter(x %in% 3:7)
Mydata %>% filter(x>=3&x<=7)

Data.tableを使用することもできます。これは、大規模なデータセットに対して非常に高速です。 inrangebetweenは、この目的で同じように機能します

library(data.table)
MydataTable <- data.table(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
                          y = c(20, 30, 45, 54, 65, 78, 97, 102, 123, 156))
MydataTable[x %inrange% c(3,7)]
MydataTable[x %between% c(3,7)]

この方法の利点(data.tableの速度に加えて)は、最小範囲と最大範囲を指定するだけでよいことです。フィルターをサブセット化するための配列を作成する必要はありません。

これらの方法の時間比較:

> df <- data.frame(x = sample(1:10, 10000000, replace = T),
+                      y = sample(1:10, 10000000, replace = T))
> system.time({ df %>% filter(between(x, 3, 7)) })
   user  system elapsed 
   0.18    0.05    0.14 
> system.time({ df %>% filter(x %in% 3:7) })
       user  system elapsed 
       0.19    0.06    0.29 
> system.time({ df %>% filter(x>=3&x<=7)  })
   user  system elapsed 
   0.17    0.09    0.26 

> dt <- data.table(df)
> system.time( {dt[x %inrange% c(3,7)] })
   user  system elapsed 
   0.13    0.07    0.21 
> system.time( {dt[x %between% c(3,7)] })
   user  system elapsed 
   0.18    0.05    0.13
4
Anna

@Annaの答えに便乗して、私はいくつかのオプションを実行して、問題の大規模なデータセットでどれが速いかを確認しました。ここからセットアップを使用しました( Rのデータフレームの行のサブセットを高速化する方法 )10億行(16GB)のデータセットで確認しました。 data.tableがdplyrを少し削ったように見えます。ただし、data.tableを使用し始めたばかりなので、最も効率的なコードを使用していない可能性があります。また、1億行のデータセットの時間に基づいて、これらの4つに絞り込みました。下記参照:

set.seed(42)  
# 1 billion rows
df <- data.frame(age=sample(1:65,1e9,replace=TRUE),x=rnorm(1e9),y=rpois(1e9,25))



microbenchmark(df1 <- df %>% filter(age >= 5 & age <= 25),
               df2 <- df %>% filter(dplyr::between(df$age, 5, 25)),
               times=10)


Unit: seconds
                                      expr      min     lq   mean median     uq    max  neval
df %>% filter(age >= 5 & age <= 25)          15.327 15.796 16.526 16.601 17.086 17.996    10
df %>% filter(dplyr::between(df$age, 5, 25)) 14.214 14.752 15.413 15.487 16.121 16.447    10


DT <- as.data.table(df)
microbenchmark(dt1 <- DT[age %inrange% c(5, 25)],
               dt2 <- DT[age %between% c(5, 25)],
               times = 10)


Unit: seconds
                              expr    min     lq   mean median     uq    max neval
 dt1 <- DT[age %inrange% c(5, 25)] 15.122 16.042 17.180 16.969 17.310 22.138    10
 dt2 <- DT[age %between% c(5, 25)] 10.212 11.121 11.675 11.436 12.132 13.913    10
2
Andrew

上記の答えはおそらくよりユーザーフレンドリーですが、ここにさらにいくつかあります...

インデックスに関する賛成票の編集:

Mydata[Mydata$x >= 3 & Mydata$x <= 7, ]

  x  y
3 3 45
4 4 54
5 5 65
6 6 78
7 7 97

Yが必要な場合など、他の列を返すように拡張できます。

Mydata[Mydata$x >= 3 & Mydata$x <= 7, 'y']

[1] 45 54 65 78 97

また、複数の列を返すこともできます。例:

Mydata <- data.frame(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
                     y = c(20, 30, 45, 54, 65, 78, 97, 102, 123, 156),
                     z = c(5, 4, 3, 2, 1, 0, -1, -2, -3, -4))   

Mydata[Mydata$x >= 3 & Mydata$x <= 7, c('y','z')]

   y  z
3 45  3
4 54  2
5 65  1
6 78  0
7 97 -1
0
antimuon

ベースRソリューション:

df <- Mydata[Mydata$x >= 3 & Mydata$x <= 7, ]

df
  x  y
3 3 45
4 4 54
5 5 65
6 6 78
7 7 97
0
samadhi

そして、古き良きbase::subset

subset(Mydata, x >= 3 & x <= 7)
subset(Mydata, x %in% 3:7)
0