Input size issue when using lapply to mutate with R

Viewed 101

I have mylist which contains 2 lists, with sample data below.
Using class(mylist[[1]]) gives "grouped_df" "tbl_df" "tbl" "data.frame"

[[1]]
# A tibble: 2 x 5
# Groups:   Year, Commodity [2]
   Year Commodity Commodity.Code value1_k value2_k
  <int> <chr>     <int>          <dbl>    <dbl>
1  2010 A         721            100      100
2  2010 B         792            200      200

[[2]]
# A tibble: 2 x 5
# Groups:   Year, Commodity [2]
   Year Commodity Commodity.Code value1_m value2_m
  <int> <chr>     <int>          <dbl>    <dbl>
1  2010 A         721            100      100
2  2010 B         792            200      200

I tried using mutate() to add a new column div to both tibbles, with the value derived by dividing the 4th by the 5th column, using the code below:

mylist2 <- lapply(1:2, function(i){
  mylist[[i]] %>% mutate(div=.[[4]] /.[[5]])
})

This brings up the error below:

 Error: Problem with `mutate()` input `div`.
x Input `div` can't be recycled to size 1.
i Input `div` is `.[[4]]/.[[5]]`.
i Input `div` must be size 1, not 2.
i The error occurred in group 1: Year = 2010, Commodity = "A".

Trying to reproduce the problem

I tried to reproduce the problem with dataset cars, but the code worked this time.

cars1 <- cars +1
cars2 <- cars +2 
cars_all <- list(cars1,cars2)

lapply(1:2, function(i){
  cars_all[[i]] %>% mutate(div = .[[1]] / .[[2]])
})

Comparing both list of lists, I take note that the classes are different, i.e.

  • class(cars_all[[1]]) gives "data.frame"
  • class(mylist[[1]]) gives "grouped_df" "tbl_df" "tbl" "data.frame"

However, I tried using as.data.frame before applying lapply, but the problem persists.

I use lapply because the actual mylist contains more lists;
I use index form to perform division instead of column names because the column names are different (and important, to be preserved) across lists.

My goal is to add the extra column with its value derived through division as mentioned.
If there are better methods out there to achieve this please let me know.

Your help is much appreciated.

1 Answers

It looks like the grouping is what's causing the issue. Here is a reproducible example:

library(tidyverse)

df1 <- tibble::tribble(
  ~Year, ~Commodity, ~Commodity.Code, ~value1_k, ~value2_k,
  2010,        "A",             721,       100,       100,
  2010,        "B",             792,       200,       200
) %>% 
  group_by(Year, Commodity)

df2 <- tibble::tribble(
  ~Year, ~Commodity, ~Commodity.Code, ~value1_k, ~value2_k,
  2011,        "C",            7242,       111,       123,
  2011,        "D",            7421,       222,       234
) %>% 
  group_by(Year, Commodity)

str(df1)
#>grouped_df[,5] [2 × 5] (S3: grouped_df/tbl_df/tbl/data.frame)
str(df2)
#>grouped_df[,5] [2 × 5] (S3: grouped_df/tbl_df/tbl/data.frame)

mylist <- list(df1, df2)

mylist2 <- lapply(1:2, function(i){
  mylist[[i]] %>% mutate(div=.[[4]] /.[[5]])
})
#>Error: Problem with `mutate()` input `div`.
#>x Input `div` can't be recycled to size 1.
#>ℹ Input `div` is `.[[4]]/.[[5]]`.
#>ℹ Input `div` must be size 1, not 2.
#>ℹ The error occurred in group 1: Year = 2010, Commodity = "A".

mylist2 <- lapply(1:2, function(i){
  mylist[[i]] %>% ungroup() %>% mutate(div=.[[4]] /.[[5]])
})
mylist2
#>[[1]]
#> A tibble: 2 x 6
#>   Year Commodity Commodity.Code value1_k value2_k   div
#>  <dbl> <chr>              <dbl>    <dbl>    <dbl> <dbl>
#>1  2010 A                    721      100      100     1
#>2  2010 B                    792      200      200     1

#>[[2]]
#> A tibble: 2 x 6
#>   Year Commodity Commodity.Code value1_k value2_k   div
#>  <dbl> <chr>              <dbl>    <dbl>    <dbl> <dbl>
#>1  2011 C                   7242      111      123 0.902
#>2  2011 D                   7421      222      234 0.949

Does this work on your 'real' data?

Related