Ian Hunter
Ian Hunter

Reputation: 35

Pass data frame and reference it for assignment inside function in R

I'm getting tripped up on assigning after passing a data frame through a function. The real function is much larger but below is an example. The goal: If the quarter column name is in the active_quarters vector, do nothing. If it isn't, assign blanks to all the values in that column of the data frame.

I understand it's trying to reference "some_data_frame" explicitly, but I'm blanking, pun intended, on how to properly assign the blanks given the iteration of the loop.

code:

library(dplyr)
active_quarters <- c("Q1", "Q2")

data_frame_dummy <- data.frame("Q1" = c(1:4),
                               "Q2" = c(5:8),
                               "Q3" = c(9:12),
                               "Q4" = c(13:16))

create_blanks<- function(quarters_list,some_data_frame){

  for(qcols in c("Q1", "Q2", "Q3", "Q4")){
    if(qcols %in% quarters_list){
      next
    }else{
      some_data_frame[,qcols] <<- ""
      
    }
  } # End of quarter if/else
} # End of function

create_blanks(active_quarters, data_frame_dummy)

result:

> create_blanks(active_quarters, data_frame_dummy)
Error in some_data_frame[, qcols] <<- "" : 
  object 'some_data_frame' not found

desired result:

> data_frame_dummy
  Q1 Q2 Q3 Q4
1  1  5      
2  2  6      
3  3  7      
4  4  8   

Upvotes: 1

Views: 717

Answers (2)

Brian Montgomery
Brian Montgomery

Reputation: 2414

Try not to use <<- unless absolutely necessary. Functions shouldn't change existing objects. So just have the function return some_data_frame and then assign it explicitly as needed.

create_blanks<- function(quarters_list,some_data_frame){
  
  for(qcols in c("Q1", "Q2", "Q3", "Q4")){
    if(qcols %in% quarters_list){
      next
    }else{
      some_data_frame[,qcols] <- ""
      
    }
  } # End of quarter if/else
  some_data_frame
} # End of function
data_frame_dummy <- create_blanks(active_quarters, data_frame_dummy)
data_frame_dummy
   Q1 Q2 Q3 Q4
1  1  5      
2  2  6      
3  3  7      
4  4  8      

Upvotes: 1

Bruno
Bruno

Reputation: 4151

Does this work for you? You can negate the selection if you want to assign 0 to the columns not in the .col parameters

library(tidyverse)

active_quarters <- c("Q1", "Q2")

data_frame_dummy <- data.frame("Q1" = c(1:4),
                               "Q2" = c(5:8),
                               "Q3" = c(9:12),
                               "Q4" = c(13:16))


data_frame_dummy |> 
  mutate(across(!active_quarters,.fns = ~ 0))
#> Note: Using an external vector in selections is ambiguous.
#> i Use `all_of(active_quarters)` instead of `active_quarters` to silence this message.
#> i See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
#> This message is displayed once per session.
#>   Q1 Q2 Q3 Q4
#> 1  1  5  0  0
#> 2  2  6  0  0
#> 3  3  7  0  0
#> 4  4  8  0  0

Created on 2022-01-23 by the reprex package (v2.0.1)

Upvotes: 0

Related Questions