13

I have a date frame similar to the following toy data:

df <- structure(list(year = c(2014, 2014, 2014, 2014, 2014, 2015, 2015, 
    2015, 2015, 2015, 2016, 2016, 2016, 2016, 2016), date = structure(c(16229, 
    16236, 16243, 16250, 16257, 16600, 16607, 16614, 16621, 16628, 
    16964, 16971, 16978, 16985, 16992), class = "Date"), value = c(0.27, 
    0.37, 0.57, 0.91, 0.2, 0.9, 0.94, 0.66, 0.63, 0.06, 0.21, 0.18, 
    0.69, 0.38, 0.77)), .Names = c("year", "date", "value"), row.names = c(NA, 
    -15L), class = c("tbl_df", "tbl", "data.frame"))

Where value is some value of interest and year and date are self-explanatory. If I want to visually compare value across years, having the different years in date makes the graph not very helpful

library(tidyverse)    
ggplot(df, aes(date, value, color = as.factor(year))) +
  geom_line()

enter image description here

I can change the year in date using lubridate as follows, and this works

# This works
library(lubridate)
df2 <- df

year(df2$date) <- 2014

ggplot(df2, aes(date, value, color = as.factor(year))) +
  geom_line() 

enter image description here

But it would be helpful to change this as part of a dplyr chain, something along the lines of

df3 <- df %>%
  mutate(year(date) = 2014)

But that code returns an error

Error: unexpected '=' in: "df3 <- df %>% mutate(year(date) ="

Is there a way to make this work within a dplyr chain, or do I just need to do this edit outside of the chain?

MeetMrMet
  • 1,349
  • 8
  • 14

2 Answers2

24

The assignment is just another function call, so you can do:

mutate(df, date = `year<-`(date, 2014))

Gives:

# A tibble: 15 x 3
    year       date value
   <dbl>     <date> <dbl>
 1  2014 2014-06-08  0.27
 2  2014 2014-06-15  0.37
 3  2014 2014-06-22  0.57
 4  2014 2014-06-29  0.91
 5  2014 2014-07-06  0.20
 6  2015 2014-06-14  0.90
 7  2015 2014-06-21  0.94
 8  2015 2014-06-28  0.66
 9  2015 2014-07-05  0.63
10  2015 2014-07-12  0.06
11  2016 2014-06-12  0.21
12  2016 2014-06-19  0.18
13  2016 2014-06-26  0.69
14  2016 2014-07-03  0.38
15  2016 2014-07-10  0.77
Axeman
  • 32,068
  • 8
  • 81
  • 94
  • 2
    This is imho much more elegant and should be the accepted solution. – grssnbchr Jul 29 '19 at 13:39
  • And it seems the library must be loaded first (i.e. can't use ::). For example, `mutate(df, date = \`lubridate::year<-\`(date, 2014)) ` gives error. – MCornejo Jul 03 '22 at 03:05
  • 1
    @MCornejo, the backticks go around the function name excluding the package. `lubridate::\`year<-\`` – Axeman Jul 04 '22 at 16:32
6
df3 <- df %>%
  mutate(date=ymd(format(df$date, "2014-%m-%d")))
df3

# # A tibble: 15 x 3
#     year       date value
#    <dbl>     <date> <dbl>
#  1  2014 2014-06-08  0.27
#  2  2014 2014-06-15  0.37
#  3  2014 2014-06-22  0.57
#  4  2014 2014-06-29  0.91
#  5  2014 2014-07-06  0.20
#  6  2015 2014-06-14  0.90
#  7  2015 2014-06-21  0.94
#  8  2015 2014-06-28  0.66
#  9  2015 2014-07-05  0.63
# 10  2015 2014-07-12  0.06
# 11  2016 2014-06-12  0.21
# 12  2016 2014-06-19  0.18
# 13  2016 2014-06-26  0.69
# 14  2016 2014-07-03  0.38
# 15  2016 2014-07-10  0.77

all.equal(df2, df3)
# [1] TRUE

Or use do:

df4 <- df %>%
  do({year(.$date)<-2014; .})
df4
# same results as df3

all.equal(df2, df4)
# [1] TRUE
JasonWang
  • 2,414
  • 11
  • 12