如何编写dplyr :: filter函数

时间:2019-12-27 02:57:12

标签: r dplyr

dplyr过滤器功能源代码,当我单击filter()时,我无法获得, 源代码是UseMethod(),当我进行调试时。什么都没出现;

我的测试代码:

  

filter(irirs,Sepal.Length> 7.1)

所以我尝试编写自己的函数

第一版:

   filter<-function(data,condition){
attach(data)
r<- data[which(condition,)]
detach(data)
return (r)
}

当我使用system.time()来比较dplyr:filter和mine:filter时,它很有效,比dplyr花费更多的时间;

第二版:

   filter<-function(data,condition){
r<-with(data,data[which(condition),])
return (r)
}

它报告错误,找不到Sepal.Length。

我知道条件参数问题,
如果我直接使用with(irirs,irirs [which(Sepal.Length> 7.1),]),它可以工作,但是我需要一个自己的过滤器功能

我有两个问题:

  • a。如何编写有效的过滤器或解决第二版代码的问题。
  • b。如何读取函数源代码,如usemethod(“ func”)

非常感谢!

4 个答案:

答案 0 :(得分:5)

有一些可能性:

myfilter1 <- function(data, condition) {
  do.call(subset, list(data, substitute(condition)), envir = parent.frame())
}
myfilter1(iris, Sepal.Length > 7.1)

myfilter2 <- function(data, condition) {
  eval.parent(substitute(with(data, data[condition, ])))
}
myfilter2(iris, Sepal.Length > 7.1)

library(gtools)
myfilter3 <- defmacro(data, condition, expr = {
  with(data, data[condition, ])
})
myfilter3(iris, Sepal.Length > 7.1)

读取与S3泛型关联的R源代码

要阅读S3泛型f的方法的源R代码,请首先列出方法:

methods(f)

,然后如果f.x是列出的方法之一,请在R中输入不带括号的名称:

f.x

还是不起作用(在methods输出中的名称后面有*的情况就是这种情况)

getAnywhere("f.x")

如果代码在CRAN上的程序包p中,那么我们可以在 cran p 中进行谷歌搜索,然后从程序包的CRAN主页下载其源代码,或者在github上通过搜索 cran github p来找到它。 并查看github网站上的源代码。

性能

关于性能,这是我在PC上获得的:

library(dplyr)
library(gtools)
library(microbenchmark)

f1 <- function() {
  len <- 7.1
  myfilter1(iris, Sepal.Length > len)
}
f2 <- function() {
  len <- 7.1
  myfilter2(iris, Sepal.Length > len)
}
f3 <- function() {
  len <- 7.1
  myfilter3(iris, Sepal.Length > len)
}
fd <- function() {
  len <- 7.1
  filter(iris, Sepal.Length > len)
}

microbenchmark(f1(), f2(), f3(), fd())

给出以下内容。

Unit: microseconds
 expr    min      lq     mean  median      uq    max neval cld
 f1()  399.2  433.70  497.133  482.00  518.85 1362.6   100  b 
 f2()  301.4  326.15  374.078  364.50  407.65  579.1   100 a  
 f3()  302.4  330.65  375.650  352.25  397.15  623.0   100 a  
 fd() 1791.5 1948.60 2166.466 2117.35 2262.65 3443.7   100   c

myfilter2myfilter3的平均时间大约相同,并且都快于其他两个。

答案 1 :(得分:1)

一种方法是在eval中使用parse textsubset来编写自己的filter方法

my_filter <- function(data, condition) {
    subset(data, eval(parse(text = condition)))
}

my_filter(iris, "Sepal.Length > 7.1")
#    Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
#106          7.6         3.0          6.6         2.1 virginica
#108          7.3         2.9          6.3         1.8 virginica
#110          7.2         3.6          6.1         2.5 virginica
#118          7.7         3.8          6.7         2.2 virginica
#119          7.7         2.6          6.9         2.3 virginica
#123          7.7         2.8          6.7         2.0 virginica
#126          7.2         3.2          6.0         1.8 virginica
#130          7.2         3.0          5.8         1.6 virginica
#131          7.4         2.8          6.1         1.9 virginica
#132          7.9         3.8          6.4         2.0 virginica
#136          7.7         3.0          6.1         2.3 virginica

my_filter(mtcars, "cyl == 6")

#                mpg cyl  disp  hp drat    wt  qsec vs am gear carb
#Mazda RX4      21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
#Mazda RX4 Wag  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
#Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
#Valiant        18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
#Merc 280       19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
#Merc 280C      17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
#Ferrari Dino   19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6

关于您的第二个问题,请在此处回答:

How can I view the source code for a function?

答案 2 :(得分:0)

@G表示感谢。格洛腾迪克答案,

我比较了我的版本1过滤器,以及@G. Grothendieck的{​​{1}}和myfilter2和dplyr :: filter,

我使用system.time()进行比较,我的版本1效率最低,而“ myfilter2”最好,

每个函数执行myfilter1次,使用10000 这是时间花费表:

func(irirs,Sepal.Length>7.1)

time_spend是system.time()的时间

我没有测试myfilter3是因为我只想使用基本包来实现我的目标

答案 3 :(得分:0)

我们可以使用const A1 = ["text", "test"] const A2 = ["onetest", "two", "threetext", "fourtext"] // I need to get the result as ["onetest", "threetext", "fourtext"] console.log(A2.filter(r => r !== null && A1.some(s => r.indexOf(s) > -1)))选项

tidyverse

或者,如果我们要传递不带引号的表达式,请使用library(dplyr) my_filter <- function(data, condition) { data %>% filter(!! rlang::parse_expr(condition)) } my_filter(mtcars, "cyl == 6") # mpg cyl disp hp drat wt qsec vs am gear carb #1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 #2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 #3 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 #4 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 #5 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4 #6 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4 #7 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6

enexpr