Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write loops "for" loops in R using dplyr syntax

Tags:

loops

r

dplyr

I have an extensive block of code that I've written using dplyr syntax in R. However, I am trying to put that code in a loop, so that I can ultimately create multiple output files as opposed to just one. Unfortunately, I appear unable to do so.

For illustration purposes regarding my problem, let's refer to the commonly used "iris" dataset in R:

      > data("iris")
      > str(iris)
      'data.frame': 150 obs. of  5 variables:
      $ Sepal.Length: num  
      $ Sepal.Width : num  
      $ Petal.Length: num  
      $ Petal.Width : num  
      $ Species     : Factor w/ 3 levels "setosa","versicolor","virginica"

Let's say that I want to save the average Petal.Length of the species "versicolor". The dplyr code could look like the following:

    MeanLength2 <- iris %>% filter(Species=="versicolor")
                       %>% summarize(mean(Petal.Length)) %>% print()

Which would give the following value:

      mean(Petal.Length)
    1               4.26

Lets attempt to create a loop to get the average petal length for all of the species.

From what little I know of loops, I would want to do something like this:

     for (i in unique(iris$Species))
      {
       iris %>% filter(iris$Species==unique(iris$Species)[i]) %>%
        summarize(mean(iris$Petal.Length)) %>% print()
        print(i) 
       }

For some reason, I had to specify the data frame and the column inside the loop, which is generally not the case while using the piping functionality of dplyr. I'm assuming that this is indicative of the problem.

Anyways, the above code gives the following output:

          mean(iris$Petal.Length)
     1                   3.758
     [1] "setosa"
          mean(iris$Petal.Length)
     1                   3.758
     [1] "versicolor"
          mean(iris$Petal.Length)
     1                   3.758
     [1] "virginica"  

So the code is outputting 3.758 three times, which is the average petal length across all species in the dataset. This indicates that the "filter" code did not work as expected. From what I can tell, it appears that the loop itself functioned as intended, as all three unique species names were printed in the eventual output.

How can one go about doing something like this with the use of for loops? I understand that this particular exercise does not require the use of fancy loops as one can easily get the average petal length of all the species by using, for example, the "group_by" function in dplyr, but I am looking to output close to a 100 unique table and PDF files with the dataset that I am working with and knowing how to use for loops would really help for that purpose.

like image 489
Naj S Avatar asked Sep 01 '16 20:09

Naj S


People also ask

Can you put a for loop in a for loop R?

Nested For-loop in R R programming language allows using one loop inside another loop. In loop nesting, we can put any type of loop inside of any other type of loop.

HOW DO FOR loops work R?

For Loop in R It is an entry controlled loop, in this loop the test condition is tested first, then the body of the loop is executed, the loop body would not be executed if the test condition is false.

How do you make a loop in a Dataframe in R?

A data frame can also be created row by row, using repeated rbind() operations on the data frame in the for loop, with number of iterations equivalent to the number of rows to insert. Example: R.


1 Answers

It is unfortunate that your code didn't raise any errors. If you run your code line by line you'll understand what I'm saying. For this example I will choose the first iteration of your loop, let's replace i for "setosa":

> iris  %>% filter(iris$Species == unique(iris$Species)["setosa"])
[1] Sepal.Length Sepal.Width  Petal.Length Petal.Width  Species     
<0 rows> (or 0-length row.names)

Your filter yields a data frame with no observations, so no point in going ahead, but for this example, let's run the rest of the code:

> iris  %>% filter(iris$Species == unique(iris$Species)["setosa"]) %>%  
+ summarize(mean(iris$Petal.Length))
  mean(iris$Petal.Length)
1                   3.758

What happened is that you're calling the iris dataset from within your code, a more obvious example would be:

> filter(iris, iris$Species == unique(iris$Species)["setosa"]) %>% 
+ summarize(mean(mtcars$cyl))
  mean(mtcars$cyl)
1           6.1875

That's why you don't get the answer you expected, your filter didn't work and you got a summary statistic from another dataset.

As TJ Mahr mentioned, your code without specifying the dataset runs fine:

> for (i in unique(iris$Species))
+ {
+     iris %>% filter(Species==i) %>%
+         summarize(mean(Petal.Length)) %>% print()
+     print(i) 
+ }
  mean(Petal.Length)
1              1.462
[1] "setosa"
  mean(Petal.Length)
1               4.26
[1] "versicolor"
  mean(Petal.Length)
1              5.552
[1] "virginica"

I hope this helps

like image 186
donlelek Avatar answered Oct 18 '22 17:10

donlelek