假设我有如下所示的数据框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))
我要过滤此数据帧并创建另一个数据帧,以便仅显示x
和3
之间的7
的值及其对应的y
的值。我尝试了以下操作:
new_frame <- Mydata %>% filter(x == (3:7))
这没有用。然后如何过滤指定范围?
提前感谢所有帮助
答案 0 :(得分: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
答案 1 :(得分:4)
许多不错的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
答案 2 :(得分:2)
Pi带@Anna的答案,我只是运行了一些选项,以查看在较大的数据集上哪一个更快解决了问题。我从这里(Faster way to subset on rows of a data frame in 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
答案 3 :(得分:0)
Base 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
答案 4 :(得分:0)
以上答案可能对用户更友好,但这里还有更多...
编辑有关索引的否决票:
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
答案 5 :(得分:0)
还有老base::subset
:
subset(Mydata, x >= 3 & x <= 7)
subset(Mydata, x %in% 3:7)