使用 mapply 和 lubridate 将年和月组合成日期对象的更好方法 第一次尝试一些谷歌搜索

问题描述

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

我有一个数据,一列是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

我正在尝试将 Month 和 Year 列合并为单个列 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,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

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

解决方法

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

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'
)
,
df$Date <- lubridate::myd(paste(df$Month,df$Year,"1"))
,

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

我是 R 的新学习者,所以我没有意识到处理数据的一些 R 风格,因此试图在一行代码中完成所有事情。感谢 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,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