次のようなデータフレーム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))
このデータフレームをフィルター処理して別のデータフレームを作成し、3
と7
の間のx
の値と、それらに対応するy
値のみが表示されるようにします。私は次を試みました:
new_frame <- Mydata %>% filter(x == (3:7))
これはうまくいきませんでした。指定した範囲でどのようにフィルタリングしますか?
すべての助けてくれてありがとう
つかいます %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
いくつかの答えに既に存在する上限と下限のフィルタリングやハードコーディングなど、多数の優れたdplyrソリューション:
MydataTable%>% filter(between(x, 3, 70))
Mydata %>% filter(x %in% 3:7)
Mydata %>% filter(x>=3&x<=7)
Data.tableを使用することもできます。これは、大規模なデータセットに対して非常に高速です。 inrange
とbetween
は、この目的で同じように機能します
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
@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
上記の答えはおそらくよりユーザーフレンドリーですが、ここにさらにいくつかあります...
インデックスに関する賛成票の編集:
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
ベース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
そして、古き良きbase::subset
:
subset(Mydata, x >= 3 & x <= 7)
subset(Mydata, x %in% 3:7)