2

I want to create a function that takes the arguments as column names in my dataset.

However when I pass this function with my desired column names as arguments the mutated columns use the literal argument name instead of the passed column names (parameter instead of "cpp").

vehicle <- c("airplane", "bus", "car")
people <- c(300, 40, 5)
cost <- c(50, 5, 2)

small_dataset <- data.frame(vehicle, people, cost)

func <- function(data, parameter) {
  data <- data %>%
    mutate(parameter = cost/people)
  return(data)
}

func(small_dataset, "cpp")
WHAT I WANT:
##    vehicle people cost cpp
## 1 airplane    300   50 0.1666667
## 2      bus     40    5 0.1250000
## 3      car      5    2 0.4000000

WHAT I GET:
##    vehicle people cost parameter
## 1 airplane    300   50 0.1666667
## 2      bus     40    5 0.1250000
## 3      car      5    2 0.4000000

How do I get the function to use the arguments as column names?

user438383
  • 5,716
  • 8
  • 28
  • 43
  • You should include a small dataset for testing, and describe what you want the output to look like, ideally by creating it manually. – user2554330 Jan 03 '22 at 13:25
  • @user2554330 thanks for pointing that out. Now I have made my own small dataset which is easier to follow – Max Brehmer Jan 03 '22 at 13:44
  • Does this answer your question? [Passing argument from custom function to group\_by doesn't work](https://stackoverflow.com/questions/67382081/passing-argument-from-custom-function-to-group-by-doesnt-work) – user438383 Jan 03 '22 at 13:48
  • @user438383 that won't quite do it—part of what they want is to programmatically set the name of the new column as well, which requires its own syntax. Covered [here](https://stackoverflow.com/q/26003574/5325862) – camille Jan 03 '22 at 17:38
  • You are looking for glue syntax. Try `mutate({'parameter'} := cost/people)`. – jpdugo17 Jan 04 '22 at 05:08

3 Answers3

2

Perhaps cleaner here to use base R (instead of dplyr):

func <- function(data, parameter) {
  data[[parameter]] <- with(data, cost/people)
  data
}
func(small_dataset, "cpp")
#    vehicle people cost       cpp
# 1 airplane    300   50 0.1666667
# 2      bus     40    5 0.1250000
# 3      car      5    2 0.4000000
s_baldur
  • 29,441
  • 4
  • 36
  • 69
1

There are at least two options. Either use {} syntax:

library(glue)
func <- function(data, parameter) {
  data %>%
    mutate({{parameter}} := cost/people)
}
> func(small_dataset, "cpp")
   vehicle people cost       cpp
1 airplane    300   50 0.1666667
2      bus     40    5 0.1250000
3      car      5    2 0.4000000

Or the bang-bang operator !!

func <- function(data, parameter) {
  data %>%
    mutate(!!parameter := cost/people)
}
> func(small_dataset, "cpp")
   vehicle people cost       cpp
1 airplane    300   50 0.1666667
2      bus     40    5 0.1250000
3      car      5    2 0.4000000
Gerhard
  • 22,678
  • 7
  • 27
  • 43
user438383
  • 5,716
  • 8
  • 28
  • 43
  • I think there is (at least) one more which is the `glue` syntax (the first one is not from `glue`): `mutate("{parameter}" := cost/people)` – s_baldur Jan 04 '22 at 10:53
0

Because a data.frame is a special kind of list, we can use the purrr::set_names functions like this. Although is not very clean.

library(purrr)
library(dplyr)

func <- function(data, parameter) {
  data <- data %>%
    mutate(parameter = cost / people) %>%
    {
      set_names(., c(names(.[-ncol(.)]), parameter))
    }
  return(data)
}

func(small_dataset, "cpp")
#>    vehicle people cost       cpp
#> 1 airplane    300   50 0.1666667
#> 2      bus     40    5 0.1250000
#> 3      car      5    2 0.4000000

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

jpdugo17
  • 6,816
  • 2
  • 11
  • 23