Is it possible to create a new column in a dataframe that is the output of a function using mutate in R?

Viewed 92

I need to run a self-made function across rows and create an output column in the same data frame (column name tt_daily). This is some made up example.

#data
data1 <- read.csv(text = "
doy,tmx,tmn,relHum,srad
148,31.3,13.8,68.3,30.4
149,31.1,17.2,62.2,30
150,30.1,16.1,69.7,20.9
151,27.3,16.2,77.1,26.1
152,33.4,18.4,65.9,27.4
153,27.2,18,70.3,26.6
154,30.3,13,71.5,28.4
155,36.2,22,62.2,28.8
156,32.9,22.2,61.1,24.9
157,30.5,16.2,63.2,27.9
158,25.7,19.3,71,18.3
159,29.1,18.3,87.2,12.7
160,28.5,20.3,70.2,24.8
")

This is the function:

# function to run row wise
tb<- 11
topt<- 30
tmax<- 42

tt<-function(tmx, tmn, tb, topt, tmax){
  
  tmean<- (tmx + tmn) / 2
  
  if(tmean <= tb) {t1 = 0}
  if(tmean >tb & tmean <=topt) {t1 = tmean - tb}
  if(tmean>topt & tmean<max) {t1 = (topt - tb) / (topt - tmax) * (tmean - tmax)}
  if(tmean >= tmax) {t1 <- 0}
  return(t1)
  
}

This is two options of what I did:

#Option 1
library(dplyr)

tt.example <- data1 %>%
  mutate(tt_daily = purrr::pmap(function(tmx, tmn, tb, topt, tmax) tt))

and this is the error:

Error: Problem with mutate() column tt_daily. i tt_daily = purrr::pmap(function(tmx, tmn, tb, topt, tmax) tt). x argument ".f" is missing, with no default

This is the option 2:

#Option 2
tt.example <- data1 %>%
  rowwise() %>%
  mutate(tt_daily = tt(tmx, tmn, tb, topt, tmax))

This is the error I got:

Error: Problem with mutate() column tt_daily. i tt_daily = tt(tmx, tmn, tb, topt, tmax). x comparison (3) is possible only for atomic and list types i The error occurred in row 1.

Thanks for any advice.

1 Answers

There is a typo in the function which should be tmax instead of max

tt<-function(tmx, tmn, tb, topt, tmax){
  
  tmean<- (tmx + tmn) / 2
  
  
  if(tmean <= tb) {t1 = 0}
  if(tmean >tb & tmean <=topt) {t1 = tmean - tb}
  if(tmean>topt & tmean<tmax) {t1 = (topt - tb) / (topt - tmax) * (tmean - tmax)}
  if(tmean >= tmax) {t1 <- 0}
  return(t1)
  
}

Now, we apply the function within mutate after appending the other arguments as a named list within pmap

library(dplyr)
library(purrr)
data1 %>% 
    mutate(tt_daily = pmap_dbl(c(across(tmx:tmn), 
             dplyr::lst(tb, topt, tmax)), tt))

-output

doy  tmx  tmn relHum srad tt_daily
1  148 31.3 13.8   68.3 30.4    11.55
2  149 31.1 17.2   62.2 30.0    13.15
3  150 30.1 16.1   69.7 20.9    12.10
4  151 27.3 16.2   77.1 26.1    10.75
5  152 33.4 18.4   65.9 27.4    14.90
6  153 27.2 18.0   70.3 26.6    11.60
7  154 30.3 13.0   71.5 28.4    10.65
8  155 36.2 22.0   62.2 28.8    18.10
9  156 32.9 22.2   61.1 24.9    16.55
10 157 30.5 16.2   63.2 27.9    12.35
11 158 25.7 19.3   71.0 18.3    11.50
12 159 29.1 18.3   87.2 12.7    12.70
13 160 28.5 20.3   70.2 24.8    13.40

Or using rowwise

data1 %>% 
   rowwise %>% 
   mutate(tt_daily = tt(tmx, tmn, tb, topt, tmax)) %>%
   ungroup

-output

# A tibble: 13 x 6
     doy   tmx   tmn relHum  srad tt_daily
   <int> <dbl> <dbl>  <dbl> <dbl>    <dbl>
 1   148  31.3  13.8   68.3  30.4     11.6
 2   149  31.1  17.2   62.2  30       13.2
 3   150  30.1  16.1   69.7  20.9     12.1
 4   151  27.3  16.2   77.1  26.1     10.8
 5   152  33.4  18.4   65.9  27.4     14.9
 6   153  27.2  18     70.3  26.6     11.6
 7   154  30.3  13     71.5  28.4     10.6
 8   155  36.2  22     62.2  28.8     18.1
 9   156  32.9  22.2   61.1  24.9     16.5
10   157  30.5  16.2   63.2  27.9     12.4
11   158  25.7  19.3   71    18.3     11.5
12   159  29.1  18.3   87.2  12.7     12.7
13   160  28.5  20.3   70.2  24.8     13.4

If we want to add a new column, then it may be better to either return a list or tibble in 'tt' function

tt<-function(tmx, tmn, tb, topt, tmax){
   
   tmean<- (tmx + tmn) / 2
   
   
   if(tmean <= tb) {t1 = 0}
   if(tmean >tb & tmean <=topt) {t1 = tmean - tb}
   if(tmean>topt & tmean<tmax) {t1 = (topt - tb) / (topt - tmax) * (tmean - tmax)}
   if(tmean >= tmax) {t1 <- 0}
   return(tibble(tt_daily = t1, tmean = tmean))
   
 }

Now, we wrap the contents in a list and unnest the output column

library(tidyr)
data1 %>% 
    rowwise %>% 
    mutate(out = list(tt(tmx, tmn, tb, topt, tmax))) %>%
    ungroup %>% 
    unnest_wider(c(out))
# A tibble: 13 x 7
     doy   tmx   tmn relHum  srad tt_daily tmean
   <int> <dbl> <dbl>  <dbl> <dbl>    <dbl> <dbl>
 1   148  31.3  13.8   68.3  30.4     11.6  22.6
 2   149  31.1  17.2   62.2  30       13.2  24.2
 3   150  30.1  16.1   69.7  20.9     12.1  23.1
 4   151  27.3  16.2   77.1  26.1     10.8  21.8
 5   152  33.4  18.4   65.9  27.4     14.9  25.9
 6   153  27.2  18     70.3  26.6     11.6  22.6
 7   154  30.3  13     71.5  28.4     10.6  21.6
 8   155  36.2  22     62.2  28.8     18.1  29.1
 9   156  32.9  22.2   61.1  24.9     16.5  27.6
10   157  30.5  16.2   63.2  27.9     12.4  23.4
11   158  25.7  19.3   71    18.3     11.5  22.5
12   159  29.1  18.3   87.2  12.7     12.7  23.7
13   160  28.5  20.3   70.2  24.8     13.4  24.4
Related