This question already has answers here:
Use dynamic name for new column/variable in `dplyr`
(10 answers)
Closed 2 years ago.
I've used curly-curly with group_by and summarise as described in the rlang announcement. But I can't get it to work when mutating a variable in place. What's the best way to do this currently with dplyr?
Say I want to supply an unquoted column name and have it mutated, here's a toy example function that doesn't work:
my_fun <- function(dat, var_name){
dat %>%
mutate({{var_name}} = 1)
}
my_fun(mtcars, cyl)
What should that mutate line be to change any column in mtcars to be a constant?
You need to use the assignment operator (:=) if you want to use the curly-curly to specify a name on the left hand side of an assignment in mutate:
my_fun <- function(dat, var_name){
dat %>%
mutate({{var_name}} := 1)
}
Which allows:
my_fun(mtcars, cyl)
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> 1 21.0 1 160.0 110 3.90 2.620 16.46 0 1 4 4
#> 2 21.0 1 160.0 110 3.90 2.875 17.02 0 1 4 4
#> 3 22.8 1 108.0 93 3.85 2.320 18.61 1 1 4 1
#> 4 21.4 1 258.0 110 3.08 3.215 19.44 1 0 3 1
#> 5 18.7 1 360.0 175 3.15 3.440 17.02 0 0 3 2
#> 6 18.1 1 225.0 105 2.76 3.460 20.22 1 0 3 1
#> 7 14.3 1 360.0 245 3.21 3.570 15.84 0 0 3 4
#> 8 24.4 1 146.7 62 3.69 3.190 20.00 1 0 4 2
#> 9 22.8 1 140.8 95 3.92 3.150 22.90 1 0 4 2
#> 10 19.2 1 167.6 123 3.92 3.440 18.30 1 0 4 4
#> 11 17.8 1 167.6 123 3.92 3.440 18.90 1 0 4 4
#> 12 16.4 1 275.8 180 3.07 4.070 17.40 0 0 3 3
#> 13 17.3 1 275.8 180 3.07 3.730 17.60 0 0 3 3
#> 14 15.2 1 275.8 180 3.07 3.780 18.00 0 0 3 3
#> 15 10.4 1 472.0 205 2.93 5.250 17.98 0 0 3 4
#> 16 10.4 1 460.0 215 3.00 5.424 17.82 0 0 3 4
#> 17 14.7 1 440.0 230 3.23 5.345 17.42 0 0 3 4
#> 18 32.4 1 78.7 66 4.08 2.200 19.47 1 1 4 1
#> 19 30.4 1 75.7 52 4.93 1.615 18.52 1 1 4 2
#> 20 33.9 1 71.1 65 4.22 1.835 19.90 1 1 4 1
#> 21 21.5 1 120.1 97 3.70 2.465 20.01 1 0 3 1
#> 22 15.5 1 318.0 150 2.76 3.520 16.87 0 0 3 2
#> 23 15.2 1 304.0 150 3.15 3.435 17.30 0 0 3 2
#> 24 13.3 1 350.0 245 3.73 3.840 15.41 0 0 3 4
#> 25 19.2 1 400.0 175 3.08 3.845 17.05 0 0 3 2
#> 26 27.3 1 79.0 66 4.08 1.935 18.90 1 1 4 1
#> 27 26.0 1 120.3 91 4.43 2.140 16.70 0 1 5 2
#> 28 30.4 1 95.1 113 3.77 1.513 16.90 1 1 5 2
#> 29 15.8 1 351.0 264 4.22 3.170 14.50 0 1 5 4
#> 30 19.7 1 145.0 175 3.62 2.770 15.50 0 1 5 6
#> 31 15.0 1 301.0 335 3.54 3.570 14.60 0 1 5 8
#> 32 21.4 1 121.0 109 4.11 2.780 18.60 1 1 4 2
Related
My query is: May I use summarise after group_by like this:
mydataset %>%
arrange(grouping_variable,ordering_variable) %>%
group_by(grouping_variable) %>% summarise(answer = another_variable[j])
I expect to see the jth ranked row in each group when I do the above.
I think the above is correct but not mentioned in the documentation.
I ran the following experiment to determine this.
Here is the whole data set:
> mtcars %>% arrange(cyl,mpg) %>% group_by(cyl) %>% as.data.frame
mpg cyl disp hp drat wt qsec vs am gear carb
1 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
2 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
3 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
4 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
5 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
6 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
7 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
8 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
9 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
10 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
11 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
12 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
13 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
14 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
15 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
16 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
17 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
18 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
19 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
20 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
21 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
22 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
23 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
24 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
25 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
26 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
27 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
28 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
29 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
30 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
31 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
32 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
Here is the first row (j=1) in each group:
> mtcars %>% arrange(cyl,mpg) %>% group_by(cyl) %>% summarise(answer = mpg[1])
# A tibble: 3 × 2
cyl answer
<dbl> <dbl>
1 4 21.4
2 6 17.8
3 8 10.4
Here is the second row in each group (j=2):
> mtcars %>% arrange(cyl,mpg) %>% group_by(cyl) %>% summarise(answer = mpg[2])
# A tibble: 3 × 2
cyl answer
<dbl> <dbl>
1 4 21.5
2 6 18.1
3 8 10.4
>
On the help page, it says that way to do this is as follows:
> mtcars %>% arrange(cyl,mpg) %>% group_by(cyl) %>% summarise(answer = first(mpg))
# A tibble: 3 × 2
cyl answer
<dbl> <dbl>
1 4 21.4
2 6 17.8
3 8 10.4
>
> mtcars %>% arrange(cyl,mpg) %>% group_by(cyl) %>% summarise(answer = nth(mpg,2))
# A tibble: 3 × 2
cyl answer
<dbl> <dbl>
1 4 21.5
2 6 18.1
3 8 10.4
>
I don't remember which website I read this on. Since it was not mentioned on help page that I why I am asking here.
I would like to add new columns to an existing data frame. The column names are generated in a FOR loop so that they are numerically sequential. Here is the code:
NewColumn <- paste("return_date", as.character(i), sep = "_")
When I display NewColumn, this is what I want:
[1] "return_date_2"
When I execute:
mutate(Cima, NewColumn = "01-01-01")
The name of the column is: NewColumn
I can rename it, but is there a way to avoid this step?
Why does R not recognize that NewColumn holds a string?
Do you have to use mutate in your code?
If not, replace mutate(Cima, NewColumn = "01-01-01") with Cima[NewColumn] <- "01-01-01"
Because mutate consider the left part of the equal sign to be already the column name. U can get over it with the code below:
library(dplyr)
library(rlang)
i <- 1
NewColumn <- paste("return_date", as.character(i), sep = "_")
> mutate(mtcars, !!NewColumn := 5)
mpg cyl disp hp drat wt qsec vs am gear carb return_date_1
1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 5
2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 5
3 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 5
4 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 5
5 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2 5
6 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 5
7 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4 5
8 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2 5
9 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2 5
10 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4 5
11 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4 5
12 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3 5
13 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3 5
14 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3 5
15 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4 5
16 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4 5
17 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4 5
18 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1 5
19 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2 5
20 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1 5
21 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1 5
22 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2 5
23 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2 5
24 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4 5
25 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2 5
26 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1 5
27 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2 5
28 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2 5
29 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4 5
30 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6 5
31 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8 5
32 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2 5
Take a look into this one to understand it better:
Use dynamic variable names in `dplyr`
You can also check advanced R from Hadley Wickham and take a look at the bang bang operator and see what it does.
https://adv-r.hadley.nz/
I can not get my head around this. I have a dataset which contains a data.frame in per day for 3 years, so i have a list with 1000 dataframes.
I want to filter all dataframes like in the example below. I know I could easily filter (or use rbindlist), first and then do the split, but I desire a way to apply a filter function to multiple dataframes. Can you help me? The code below does not work, but hope it helps to make clear what I want to archieve.
dflist <- mtcars %>%
split(.$cyl)
lapply(dflist, function(x) dplyr::filter(x[["mpg"]] > 10))
The filter works on a data.frame/tbl_df. Instead, we are extracting a vector (x[["mpg"]])
library(tidyverse)
filter(mtcars$mpg > 10)
Error in UseMethod("filter_") : no applicable method for 'filter_'
applied to an object of class "logical"
and apply filter on it.
We need to apply filter on the data.frame itself
map(dflist, ~ .x %>%
filter(mpg > 10))
#$`4`
# mpg cyl disp hp drat wt qsec vs am gear carb
#1 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
#2 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
#3 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
#4 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
#5 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
#6 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
#7 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
#8 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
#9 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
#10 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
#11 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
#$`6`
# mpg cyl disp hp drat wt qsec vs am gear carb
#1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#3 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#4 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
#5 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
#6 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
#7 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
#$`8`
# mpg cyl disp hp drat wt qsec vs am gear carb
#1 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
#2 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
#3 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
#4 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
#5 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
#6 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
#7 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
#8 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
#9 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
#10 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
#11 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
#12 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
#13 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
#14 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
Or using lapply
lapply(dflist, function(x) x %>%
filter(mpg > 10))
I get an error when trying to call my function where dplyr is used inside the function. Does dplyr not work inside R functions?
all_df_yoy <- function(all_df, units) {
all_df_yoy <- all_df %>% mutate(
players_units_yoy = units)
}
us_players_all_df_yoy <- all_df_yoy(us_players_all_df, players_units_us)
I get the following error.
Error in compat_lazy_dots(.dots, caller_env(), ..., .named = TRUE) :
object 'players_units_us' not found
However, players_units_us does indeed exist inside the data frame.
Without a minimal reproducible example it's impossible to answer this question to your exact scope, but you need to utilize tidyeval to code functions in the same way that library(dplyr) does. Here is a brief example of what you have to do
library(tidyverse)
create_new_col <- function(df, units) {
units <- enquo(units)
df %>%
mutate(players_units_yoy = !!units)
}
mtcars %>%
create_new_col(cyl)
#> mpg cyl disp hp drat wt qsec vs am gear carb players_units_yoy
#> 1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 6
#> 2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 6
#> 3 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 4
#> 4 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 6
#> 5 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2 8
#> 6 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 6
#> 7 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4 8
#> 8 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2 4
#> 9 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2 4
#> 10 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4 6
#> 11 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4 6
#> 12 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3 8
#> 13 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3 8
#> 14 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3 8
#> 15 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4 8
#> 16 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4 8
#> 17 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4 8
#> 18 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1 4
#> 19 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2 4
#> 20 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1 4
#> 21 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1 4
#> 22 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2 8
#> 23 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2 8
#> 24 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4 8
#> 25 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2 8
#> 26 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1 4
#> 27 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2 4
#> 28 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2 4
#> 29 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4 8
#> 30 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6 6
#> 31 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8 8
#> 32 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2 4
Created on 2019-05-02 by the reprex package (v0.2.1)
You can read more on this here: https://cran.r-project.org/web/packages/dplyr/vignettes/programming.html
If you are new to programming in R, realize that this is a hurdle most users go through when beginning to develop their own packages. So don't worry if it doesn't click at first, become more familiar with R (try writing your functions using base R) and then come back to this topic.
I have a dataframe with a list-column which itself contains dataframes (see below). Essentially, I am trying to add values from another column in the parent dataframe into the smaller dataframe by creating another column.
This is a simplified example- my real application is more complex.
library(tidyverse)
# What I am trying to do: add column "a" to dataframe within the list column
add_column(mtcars, a = 1)
#> mpg cyl disp hp drat wt qsec vs am gear carb a
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 1
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 1
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 1
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 1
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2 1
#> Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 1
#> Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4 1
#> Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2 1
#> Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2 1
#> Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4 1
#> Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4 1
#> Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3 1
#> Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3 1
#> Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3 1
#> Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4 1
#> Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4 1
#> Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4 1
#> Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1 1
#> Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2 1
#> Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1 1
#> Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1 1
#> Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2 1
#> AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2 1
#> Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4 1
#> Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2 1
#> Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1 1
#> Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2 1
#> Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2 1
#> Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4 1
#> Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6 1
#> Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8 1
#> Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2 1
Then create list-column:
(df <- tibble(data = rep(list(mtcars), times = 3), a = 1:3))
#> # A tibble: 3 x 2
#> data a
#> <list> <int>
#> 1 <data.frame [32 x 11]> 1
#> 2 <data.frame [32 x 11]> 2
#> 3 <data.frame [32 x 11]> 3
But this doesn't work:
df %>%
rowwise() %>%
modify_at("data", ~ add_column(., a = a))
# Error in eval_tidy(xs[[i]], unique_output): object 'a' not found
We may use
df %>% mutate(data = data %>% map2(a, ~add_column(.x, a = .y)))
In this way we start by mutating a column as usual, but then recognising that it's a list we use map2 along with the a column.