4

I'm trying to filter a data.frame with filter() function from the package dplyr. The main problem here is that I want to use a vector for the conditions.

For example

library(dplyr)
conditions <- c("Sepal.Width<3.2","Species==setosa")
DATA <- iris %>%
  filter(conditions) #This doesnt work, of course.

Is there any function that would take

conditions <- c("Sepal.Width<3.2","Species==setosa")

as an input and give me

Sepal.Width<3.2 & Species==setosa

as an output? I though about using eval(parse...) with sapplyand maybe paste0() to add the &, but can't make it work.

Any help would be aprecciated.

kowa
  • 89
  • 6

3 Answers3

4

There are multiple issues. First, you need to quote inside quotation for the second condition:

conditions <- c("Sepal.Width < 3.2", "Species == 'setosa'")

Then, you need to specify the association between the two conditions. Here, I assumed an &. Then you can use eval(parse(...)):

iris %>%
 filter(eval(parse(text = paste(conditions, sep = "&"))))

   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
5           5.0         3.6          1.4         0.2  setosa
6           5.4         3.9          1.7         0.4  setosa
7           4.6         3.4          1.4         0.3  setosa
8           5.0         3.4          1.5         0.2  setosa
9           4.4         2.9          1.4         0.2  setosa
10          4.9         3.1          1.5         0.1  setosa

On the other hand, I think it is always important to quote @Martin Mächler to warn about the potential problems associated with this approach:

The (possibly) only connection is via parse(text = ....) and all good R programmers should know that this is rarely an efficient or safe means to construct expressions (or calls). Rather learn more about substitute(), quote(), and possibly the power of using do.call(substitute, ......).

tmfmnk
  • 38,881
  • 4
  • 47
  • 67
  • Thanks for the answer. Didnt notice the quotation in setosa, it worked for me! As I asked to @sindri_baldur, do you know any other way to do it without the Eval(parse)? – kowa Oct 31 '19 at 09:43
3

Here is a way:

conditions <- c("Sepal.Width<3.2","Species=='setosa'")
# note the small change here:               ↑      ↑
DATA <- iris %>%
  filter(eval(parse(text = paste(conditions, collapse = "&"))))

> DATA
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1           4.9         3.0          1.4         0.2  setosa
2           4.6         3.1          1.5         0.2  setosa
3           4.4         2.9          1.4         0.2  setosa
4           4.9         3.1          1.5         0.1  setosa
5           4.8         3.0          1.4         0.1  setosa
6           4.3         3.0          1.1         0.1  setosa
7           5.0         3.0          1.6         0.2  setosa
8           4.8         3.1          1.6         0.2  setosa
9           4.9         3.1          1.5         0.2  setosa
10          4.4         3.0          1.3         0.2  setosa
11          4.5         2.3          1.3         0.3  setosa
12          4.8         3.0          1.4         0.3  setosa
s_baldur
  • 29,441
  • 4
  • 36
  • 69
  • I see, I don't know why It didnt work in first instance for me. Thanks, do you know if there's a way to do it without the eval(parse..)? – kowa Oct 31 '19 at 09:42
  • @kowa we might have an XY problem. What is your application? – s_baldur Oct 31 '19 at 09:44
  • I will use to to classify data, so I would be the only one with acces to the code, thats why I'm not affraid of XSS attack, but wouldnt mind to be safer. – kowa Oct 31 '19 at 09:47
2

A tidyeval way would be to use rlang::parse_exprs().

library(dplyr)

conditions <- c("Sepal.Width < 3.2", "Species == 'setosa'")

iris %>%
  filter( !!! rlang::parse_exprs(conditions))

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1           4.9         3.0          1.4         0.2  setosa
2           4.6         3.1          1.5         0.2  setosa
3           4.4         2.9          1.4         0.2  setosa
4           4.9         3.1          1.5         0.1  setosa
5           4.8         3.0          1.4         0.1  setosa
6           4.3         3.0          1.1         0.1  setosa
7           5.0         3.0          1.6         0.2  setosa
8           4.8         3.1          1.6         0.2  setosa
9           4.9         3.1          1.5         0.2  setosa
10          4.4         3.0          1.3         0.2  setosa
11          4.5         2.3          1.3         0.3  setosa
12          4.8         3.0          1.4         0.3  setosa
Ritchie Sacramento
  • 29,890
  • 4
  • 48
  • 56