在我看来,子集和过滤器(来自dplyr)具有相同的结果.但我的问题是:在某些方面存在潜在的差异,例如.速度,它可以处理的数据大小等?是否有时候使用其中一种更好?
例:
library(dplyr)
df1<-subset(airquality, Temp>80 & Month > 5)
df2<-filter(airquality, Temp>80 & Month > 5)
summary(df1$Ozone)
# Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
# 9.00 39.00 64.00 64.51 84.00 168.00 14
summary(df2$Ozone)
# Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
# 9.00 39.00 64.00 64.51 84.00 168.00 14
Run Code Online (Sandbox Code Playgroud)
Ben*_*min 47
它们确实产生了相同的结果,它们在概念上非常相似.
它的优点subset是它是基础R的一部分,不需要任何额外的包.样本量较小,似乎比filter您的示例快一点(在您的示例中快6倍,但以微秒为单位).
随着数据集的增长,filter似乎在效率方面占据上风.在15,000条记录中,filter超过subset了大约300微秒.在153,000条记录中,filter速度提高了三倍(以毫秒为单位).
所以就人的时间而言,我认为两者之间并没有太大区别.
另一个优点(这是一个利基优势)是filter可以在SQL数据库上运行而无需将数据拉入内存. subset根本不这样做.
就个人而言,我倾向于使用filter,但仅仅因为我已经在使用dplyr框架.如果您不使用内存不足的数据,则不会产生太大影响.
library(dplyr)
library(microbenchmark)
# Original example
microbenchmark(
df1<-subset(airquality, Temp>80 & Month > 5),
df2<-filter(airquality, Temp>80 & Month > 5)
)
Unit: microseconds
expr min lq mean median uq max neval cld
subset 95.598 107.7670 118.5236 119.9370 125.949 167.443 100 a
filter 551.886 564.7885 599.4972 571.5335 594.993 2074.997 100 b
# 15,300 rows
air <- lapply(1:100, function(x) airquality) %>% bind_rows
microbenchmark(
df1<-subset(air, Temp>80 & Month > 5),
df2<-filter(air, Temp>80 & Month > 5)
)
Unit: microseconds
expr min lq mean median uq max neval cld
subset 1187.054 1207.5800 1293.718 1216.671 1257.725 2574.392 100 b
filter 968.586 985.4475 1056.686 1023.862 1036.765 2489.644 100 a
# 153,000 rows
air <- lapply(1:1000, function(x) airquality) %>% bind_rows
microbenchmark(
df1<-subset(air, Temp>80 & Month > 5),
df2<-filter(air, Temp>80 & Month > 5)
)
Unit: milliseconds
expr min lq mean median uq max neval cld
subset 11.841792 13.292618 16.21771 13.521935 13.867083 68.59659 100 b
filter 5.046148 5.169164 10.27829 5.387484 6.738167 65.38937 100 a
Run Code Online (Sandbox Code Playgroud)
rsm*_*h54 26
还没有提到的一个额外差异是过滤器丢弃了rownames,而子集则没有:
filter(mtcars, gear == 5)
mpg cyl disp hp drat wt qsec vs am gear carb
1 26.0 4 120.3 91 4.43 2.140 16.7 0 1 5 2
2 30.4 4 95.1 113 3.77 1.513 16.9 1 1 5 2
3 15.8 4 351.0 264 4.22 3.170 14.5 0 1 5 4
4 19.7 4 145.0 175 3.62 2.770 15.5 0 1 5 6
5 15.0 4 301.0 335 3.54 3.570 14.6 0 1 5 8
subset(mtcars, gear == 5)
mpg cyl disp hp drat wt qsec vs am gear carb
Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.7 0 1 5 2
Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.9 1 1 5 2
Ford Pantera L 15.8 4 351.0 264 4.22 3.170 14.5 0 1 5 4
Ferrari Dino 19.7 4 145.0 175 3.62 2.770 15.5 0 1 5 6
Maserati Bora 15.0 4 301.0 335 3.54 3.570 14.6 0 1 5 8
Run Code Online (Sandbox Code Playgroud)
在主要用例中,它们的行为相同:
library(dplyr)
identical(
filter(starwars, species == "Wookiee"),
subset(starwars, species == "Wookiee"))
# [1] TRUE
Run Code Online (Sandbox Code Playgroud)
但是它们有很多差异,包括(我尽可能详尽,但可能会漏掉一些):
subset 可以在矩阵上使用filter 可以在数据库上使用filter 删除行名subset有select争论subset 回收其条件参数filter 支持条件作为单独的参数filter支持.data代词filter支持一些rlang功能filter 支持分组filter支持n()和row_number()filter 更严格filter 算是比较快一点subset 在其他包中有方法subset 可以在矩阵上使用subset(state.x77, state.x77[,"Population"] < 400)
# Population Income Illiteracy Life Exp Murder HS Grad Frost Area
# Alaska 365 6315 1.5 69.31 11.3 66.7 152 566432
# Wyoming 376 4566 0.6 70.29 6.9 62.9 173 97203
Run Code Online (Sandbox Code Playgroud)
虽然列不能直接用作参数中的subset变量
subset(state.x77, Population < 400)
Run Code Online (Sandbox Code Playgroud)
subset.matrix(state.x77,人口<400)中的错误:找不到对象'人口'
两者都不起作用 filter
filter(state.x77, state.x77[,"Population"] < 400)
Run Code Online (Sandbox Code Playgroud)
UseMethod(“ filter_”)中的错误:没有将适用于'filter_'的适用方法应用于类“ c('matrix','double','numeric')”的对象
filter(state.x77, Population < 400)
Run Code Online (Sandbox Code Playgroud)
UseMethod(“ filter_”)中的错误:没有将适用于'filter_'的适用方法应用于类“ c('matrix','double','numeric')”的对象
filter 可以在数据库上使用library(DBI)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con, "mtcars", mtcars)
tbl(con,"mtcars") %>%
filter(hp < 65)
# # Source: lazy query [?? x 11]
# # Database: sqlite 3.19.3 [:memory:]
# mpg cyl disp hp drat wt qsec vs am gear carb
# <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
# 2 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
Run Code Online (Sandbox Code Playgroud)
subset 不能
tbl(con,"mtcars") %>%
subset(hp < 65)
Run Code Online (Sandbox Code Playgroud)
subset.default(。,hp <65)中的错误:找不到对象'hp'
filter 删除行名filter(mtcars, hp < 65)
# mpg cyl disp hp drat wt qsec vs am gear carb
# 1 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
# 2 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
Run Code Online (Sandbox Code Playgroud)
subset 不
subset(mtcars, hp < 65)
# mpg cyl disp hp drat wt qsec vs am gear carb
# Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
# Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
Run Code Online (Sandbox Code Playgroud)
subset有select争论虽然dplyr遵循tidyverse旨在使每个功能都做一件事情的原理,但是select是一个单独的功能。
identical(
subset(starwars, species == "Wookiee", select = c("name", "height")),
filter(starwars, species == "Wookiee") %>% select(name, height)
)
# [1] TRUE
Run Code Online (Sandbox Code Playgroud)
它还具有一个drop参数,这在使用select参数的上下文中最有意义。
subset 回收其条件参数half_iris <- subset(iris,c(TRUE,FALSE))
dim(iris) # [1] 150 5
dim(half_iris) # [1] 75 5
Run Code Online (Sandbox Code Playgroud)
filter 不
half_iris <- filter(iris,c(TRUE,FALSE))
Run Code Online (Sandbox Code Playgroud)
filter_impl(.data,quo)中的错误:结果的长度必须为150,而不是2
filter 支持条件作为单独的参数满足条件,...所以我们可以将几个条件作为不同的参数,这与使用相同,&但有时由于逻辑运算符优先级和自动标识而更具可读性。
identical(
subset(starwars,
(species == "Wookiee" | eye_color == "blue") &
mass > 120),
filter(starwars,
species == "Wookiee" | eye_color == "blue",
mass > 120)
)
Run Code Online (Sandbox Code Playgroud)
filter支持.data代词的使用mtcars %>% filter(.data[["hp"]] < 65)
# mpg cyl disp hp drat wt qsec vs am gear carb
# 1 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
# 2 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
Run Code Online (Sandbox Code Playgroud)
filter支持一些rlang功能x <- "hp"
library(rlang)
mtcars %>% filter(!!sym(x) < 65)
# m pg cyl disp hp drat wt qsec vs am gear carb
# 1 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
# 2 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
filter65 <- function(data,var){
data %>% filter(!!enquo(var) < 65)
}
mtcars %>% filter65(hp)
# mpg cyl disp hp drat wt qsec vs am gear carb
# 1 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
# 2 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
Run Code Online (Sandbox Code Playgroud)
filter 支持分组iris %>%
group_by(Species) %>%
filter(Petal.Length < quantile(Petal.Length,0.01))
# # A tibble: 3 x 5
# # Groups: Species [3]
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# <dbl> <dbl> <dbl> <dbl> <fctr>
# 1 4.6 3.6 1.0 0.2 setosa
# 2 5.1 2.5 3.0 1.1 versicolor
# 3 4.9 2.5 4.5 1.7 virginica
iris %>%
group_by(Species) %>%
subset(Petal.Length < quantile(Petal.Length,0.01))
# # A tibble: 2 x 5
# # Groups: Species [1]
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# <dbl> <dbl> <dbl> <dbl> <fctr>
# 1 4.3 3.0 1.1 0.1 setosa
# 2 4.6 3.6 1.0 0.2 setosa
Run Code Online (Sandbox Code Playgroud)
filter支持n()和row_number()filter(iris, row_number() < n()/30)
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 5.1 3.5 1.4 0.2 setosa
# 2 4.9 3.0 1.4 0.2 setosa
# 3 4.7 3.2 1.3 0.2 setosa
# 4 4.6 3.1 1.5 0.2 setosa
Run Code Online (Sandbox Code Playgroud)
filter 更严格如果输入可疑,则会触发错误。
filter(iris, Species = "setosa")
# Error: `Species` (`Species = "setosa"`) must not be named, do you need `==`?
identical(subset(iris, Species = "setosa"), iris)
# [1] TRUE
df1 <- setNames(data.frame(a = 1:3, b=5:7),c("a","a"))
# df1
# a a
# 1 1 5
# 2 2 6
# 3 3 7
filter(df1, a > 2)
#Error: Column `a` must have a unique name
subset(df1, a > 2)
# a a.1
# 3 3 7
Run Code Online (Sandbox Code Playgroud)
filter 算是比较快一点借用本杰明在他的答案中构建的数据集(15.3万行),它的速度快两倍,尽管它很少会成为瓶颈。
air <- lapply(1:1000, function(x) airquality) %>% bind_rows
microbenchmark::microbenchmark(
subset = subset(air, Temp>80 & Month > 5),
filter = filter(air, Temp>80 & Month > 5)
)
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# subset 8.771962 11.551255 19.942501 12.576245 13.933290 108.0552 100 b
# filter 4.144336 4.686189 8.024461 6.424492 7.499894 101.7827 100 a
Run Code Online (Sandbox Code Playgroud)
subset 在其他包中有方法subset和S3一样,它也是S3泛型,dplyr::filter但是subset由于基本功能很可能在其他软件包中开发了方法,因此一个著名的例子是zoo:::subset.zoo。
| 归档时间: |
|
| 查看次数: |
23189 次 |
| 最近记录: |