我有一个具有三个日期列x, y和z的数据表,我正在尝试创建一个新列(new_col),这是每一行中三个日期的中间日期,从最早到最晚,即,我想要最小和最大日期之间的日期-请参见下表:
下面的方法
- 将字符日期字符串强制转换为数字类型
Date
,因为字符日期没有算术, - 查找"中间"的位置。日期每行
- 并返回相应的字符串
- 最终变成
new_col
这可以使用apply()
在每一行上使用适当的函数来实现:
df$new_col <- apply(df, 1L, function(x) x[order(lubridate::dmy(x))][2L])
df
x y z new_col 1 1st Jan 2005 4th May 1998 2nd Mar 2009 1st Jan 2005 2 9th May 2010 14th Feb 2003 9th Jan 2008 9th Jan 2008 3 7th Sept 2002 8th Dec 2010 23rd May 2012 8th Dec 2010
注意
返回预期的结果。new_col
为字符日期字符串。
然而,如果OP打算继续使用Date
类型,例如做更多的算术,我建议遵循Ben的例子,将整个data.frame强制为Date
类型,并坚持使用它。
首先确保你所有的日期都是"日期";类型,您可以使用lubridate
中的dmy
(假设您的数据帧称为df
):
library(lubridate)
df[] <- lapply(df, dmy)
接下来,按时间顺序对每一行进行排序,并将中间一列(第2列)作为new_col
:
df$new_col <- as.Date(t(apply(df, 1, sort))[,2])
最后,如果您希望结果以相同的文本格式显示(例如,"1st Jan 2005"而不是"2005-01-01"),那么您可以使用基于以下答案的自定义函数:
library(dplyr)
date_to_text <- function(dates){
dayy <- day(dates)
suff <- case_when(dayy %in% c(11,12,13) ~ "th",
dayy %% 10 == 1 ~ 'st',
dayy %% 10 == 2 ~ 'nd',
dayy %% 10 == 3 ~'rd',
TRUE ~ "th")
paste0(dayy, suff, " ", format(dates, "%b %Y"))
}
df[] <- lapply(df, date_to_text)
x y z new_col
1 1st Jan 2005 4th May 1998 2nd Mar 2009 1st Jan 2005
2 9th May 2010 14th Feb 2003 9th Jan 2008 9th Jan 2008
3 7th Sep 2002 8th Dec 2010 23rd May 2012 8th Dec 2010
df <- structure(list(x = c("1st Jan 2005", "9th May 2010", "7th Sept 2002"
), y = c("4th May 1998", "14th Feb 2003", "8th Dec 2010"), z = c("2nd Mar 2009",
"9th Jan 2008", "23rd May 2012")), class = "data.frame", row.names = c(NA,
-3L))