【问题标题】:Better ways to combine Year and Month into Date object using mapply and lubridate使用 mapply 和 lubridate 将年和月组合成日期对象的更好方法
【发布时间】:2021-04-09 09:24:26
【问题描述】:

(我实际上想出了一个解决方案,但这并不能满足我对简单性和直观性的渴望,因此我在这里陈述我的问题和解决方案,同时等待一个漂亮而简洁的解决方案。)

我有一个数据,其中一列是Year,另一列是Month,而月份是字符串格式:

  Country   Month      Year Type    
  <fct>     <chr>     <dbl> <fct>   
1 Argentina June       1975 Currency
2 Argentina February   1981 Currency
3 Argentina July       1982 Currency

我正在尝试将“月”和“年”列合并为单个列 Date,其格式为 date

第一次尝试

我的第一次尝试是使用mapply,借助lubridate 和我的一个小函数,将month 从字符串转换为整数。

months = c("January", "February", "March", "April", 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
month_num = c(1:12)
names(month_num) = months


crisis$Date = mapply(function(y, m){
  m = month_num[m]
  d = make_date(y,m) 
  return(d)
},crisis$Year, crisis$Month)

然而这并不是我想要的:

  Country   Month      Year Type     Date      
  <fct>     <chr>     <dbl> <fct>    <list>    
1 Argentina June       1975 Currency <date [1]>
2 Argentina February   1981 Currency <date [1]>
3 Argentina July       1982 Currency <date [1]>
4 Argentina September  1986 Currency <date [1]>

,因为Date列是列表格式。

一些谷歌搜索

this post 的帮助下,以及一些取消列出并将其转回日期对象的操作,我设法得到了我想要的结果:

crisis$Date = as_date(unlist(mapply(function(y, m){
  m = month_num[m]
  d = make_date(y,m) 
  return(d)
},crisis$Year, crisis$Month, SIMPLIFY = FALSE)))

结果是

  Country   Month      Year Type     Date      
  <fct>     <chr>     <dbl> <fct>    <date>    
1 Argentina June       1975 Currency 1975-06-01
2 Argentina February   1981 Currency 1981-02-01
3 Argentina July       1982 Currency 1982-07-01
4 Argentina September  1986 Currency 1986-09-01

到目前为止,这很好处理,但我相信有更好的解决方案。

【问题讨论】:

    标签: r lubridate mapply


    【解决方案1】:

    您可以将月份转换为数字,然后从那里转换为日期:

    df %>% 
      mutate(
        Month = base::match(Month, base::month.name),
        Date = as.Date(paste(Year, '-', Month, '-01', sep=''))
      ) %>% 
      select(-c(Month, Year))
    
    # A tibble: 3 x 3
    #   Country   Type     Date      
    #   <chr>     <chr>    <date>    
    # 1 Argentina Currency 1975-06-01
    # 2 Argentina Currency 1981-02-01
    # 3 Argentina Currency 1982-07-01
    

    这有帮助吗?

    我在下面提供了数据框:

    library(tibble)
    
    df <- tibble(
      Country = 'Argentina',
      Month = c('June', 'February', 'July'),
      Year = c(1975, 1981, 1982),
      Type = 'Currency'
    )
    

    【讨论】:

    • 是的!它通过提供一种使用 mutate 函数的好方法来帮助我,使它看起来语法上很舒服。我曾尝试将 mutate 与我的自定义函数一起使用,但出现了类似的问题。您使用match 的解决方案效果很好!
    【解决方案2】:
    df$Date <- lubridate::myd(paste(df$Month, df$Year, "1"))
    

    【讨论】:

    • 不知道 myd 函数可以识别月份的字母表示。非常感谢!
    【解决方案3】:

    所以在@Gram@det的帮助下,我想出了我的解决方案。

    我是 R 的新手,所以我没有意识到处理数据的一些 R-ish 风格,因此我尝试在一行代码中完成所有事情。感谢 Gram 的回答中的一些提示,我不知何故学会了通过添加辅助列来清除我的代码(类似于 excel)。

    考虑到将来可能会出现通信可能不仅仅是从 1:12 到几个月的情况,为了使事情更通用以供将来使用,我创建了一个新的 data.frame 只是为了存储有关的所有信息月:

    month_ref = data.frame(num = 1:12, Month = c("January", "February", "March", "April", 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'))
    
      num    Month
    1   1  January
    2   2 February
    3   3    March
    4   4    April
    

    现在的想法是“组合”两个数据框,将Month 列与数字相匹配。这与 excel 中的 VLOOKUP 函数完全一样,在 this post 的帮助下,我现在有了一个包含一列数字的数据框

    crisis  = crisis %>% 
      inner_join(month_ref, by=c("Month")) 
    
      Country   Month      Year Type       num
      <fct>     <chr>     <dbl> <fct>    <int>
    1 Argentina June       1975 Currency     6
    2 Argentina February   1981 Currency     2
    3 Argentina July       1982 Currency     7
    4 Argentina September  1986 Currency     9
    

    然后我可以用一个整齐的月份列来处理我的数据框,这比在mutate() 中的自定义函数中处理解析更容易和可读。

    crisis  = crisis %>% 
      inner_join(month_ref, by="Month") %>%
      mutate(
        Date = lubridate::ymd(paste(Year, num, "01", sep="-"))
      ) %>%
      select(-c(num, Month, Year))
    
      Country   Type     Date      
      <fct>     <fct>    <date>    
    1 Argentina Currency 1975-06-01
    2 Argentina Currency 1981-02-01
    3 Argentina Currency 1982-07-01
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-03
      • 1970-01-01
      • 2018-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多