【问题标题】:Calculating mean date by row按行计算平均日期
【发布时间】:2014-10-27 12:08:14
【问题描述】:

我希望逐行获取平均日期,其中每行包含两个日期。终于找到了办法,贴在下面。但是,我使用的方法似乎相当麻烦。有没有更好的办法?

my.data = read.table(text = "
     OBS  MONTH1  DAY1  YEAR1  MONTH2  DAY2  YEAR2   STATE
       1       3     6   2012       3    10   2012       1
       2       3    10   2012       3    20   2012       1
       3       3    16   2012       3    30   2012       1
       4       3    20   2012       4     8   2012       1
       5       3    20   2012       4     9   2012       1
       6       3    20   2012       4    10   2012       1
       7       3    20   2012       4    11   2012       1
       8       4     4   2012       4     5   2012       1
       9       4     6   2012       4     6   2012       1
      10       4     6   2012       4     7   2012       1
", header = TRUE, stringsAsFactors = FALSE)
my.data

my.data$MY.DATE1 <- do.call(paste, list(my.data$MONTH1, my.data$DAY1, my.data$YEAR1))
my.data$MY.DATE2 <- do.call(paste, list(my.data$MONTH2, my.data$DAY2, my.data$YEAR2))

my.data$MY.DATE1 <- as.Date(my.data$MY.DATE1, format=c("%m %d %Y"))
my.data$MY.DATE2 <- as.Date(my.data$MY.DATE2, format=c("%m %d %Y"))
my.data

desired.result = read.table(text = "
   OBS MONTH1 DAY1 YEAR1 MONTH2 DAY2 YEAR2 STATE   MY.DATE1   MY.DATE2    mean.date
    1      3     6  2012      3   10  2012     1 2012-03-06 2012-03-10   2012-03-08
    2      3    10  2012      3   20  2012     1 2012-03-10 2012-03-20   2012-03-15
    3      3    16  2012      3   30  2012     1 2012-03-16 2012-03-30   2012-03-23
    4      3    20  2012      4    8  2012     1 2012-03-20 2012-04-08   2012-03-29
    5      3    20  2012      4    9  2012     1 2012-03-20 2012-04-09   2012-03-30
    6      3    20  2012      4   10  2012     1 2012-03-20 2012-04-10   2012-03-30
    7      3    20  2012      4   11  2012     1 2012-03-20 2012-04-11   2012-03-31
    8      4     4  2012      4    5  2012     1 2012-04-04 2012-04-05   2012-04-04
    9      4     6  2012      4    6  2012     1 2012-04-06 2012-04-06   2012-04-06
   10      4     6  2012      4    7  2012     1 2012-04-06 2012-04-07   2012-04-06
", header = TRUE, stringsAsFactors = FALSE)

这是对我有用的方法:

my.data$mean.date <- (my.data$MY.DATE1 + ((my.data$MY.DATE2 - my.data$MY.DATE1) / 2))
my.data

这些方法不起作用:

my.data$mean.date <- mean(my.data$MY.DATE1, my.data$MY.DATE2)
my.data$mean.date <- mean(my.data$MY.DATE1, my.data$MY.DATE2, trim = 0)
my.data$mean.date <- mean(my.data$MY.DATE1, my.data$MY.DATE2, trim = 1)
my.data$mean.date <- mean(my.data$MY.DATE1, my.data$MY.DATE2, trim = 0.5)
my.data$mean.data <- apply(my.data, 1, function(x) {(x[9] + x[10]) / 2})

我想我应该使用Ops.Date 命令,但没有找到示例。

感谢您的任何建议。

【问题讨论】:

  • 在基础 R 中查看 mean.Datemean.Date(as.Date(c("01-01-2014", "01-07-2014"), format=c("%m-%d-%Y"))) [1] "2014-01-04"
  • @jaysunice3401 谢谢。如果您将其发布为答案,我可能会在一天左右的时间内接受它。
  • 我在下面发表了我的评论,欢迎采纳。

标签: r date mean


【解决方案1】:

保持简单并在基础R 中使用mean.Date

mean.Date(as.Date(c("01-01-2014", "01-07-2014"), format=c("%m-%d-%Y"))) 
[1] "2014-01-04"

【讨论】:

  • 很遗憾,这个函数好像没有向量化。
  • base::Vectorize一起玩怎么样?
【解决方案2】:

使用@jaysunice3401 的好建议,我想出了这个。如果要保留原始数据,可以在unite这两行加上remove = FALSE

library(dplyr)
library(tidyr)

my.data %>%
    unite(whatever1, matches("1"), sep = "-") %>%
    unite(whatever2, matches("2"), sep = "-") %>%
    mutate_each(funs(as.Date(., "%m-%d-%Y")), contains("whatever")) %>%
    rowwise %>%
    mutate(mean.date = mean.Date(c(whatever1, whatever2)))

#   OBS  whatever1  whatever2 STATE  mean.date
#1    1 2012-03-06 2012-03-10     1 2012-03-08
#2    2 2012-03-10 2012-03-20     1 2012-03-15
#3    3 2012-03-16 2012-03-30     1 2012-03-23
#4    4 2012-03-20 2012-04-08     1 2012-03-29
#5    5 2012-03-20 2012-04-09     1 2012-03-30
#6    6 2012-03-20 2012-04-10     1 2012-03-30
#7    7 2012-03-20 2012-04-11     1 2012-03-31
#8    8 2012-04-04 2012-04-05     1 2012-04-04
#9    9 2012-04-06 2012-04-06     1 2012-04-06
#10  10 2012-04-06 2012-04-07     1 2012-04-06

【讨论】:

    【解决方案3】:

    也许是这样的?

    library(data.table)
    setDT(my.data)[, `:=`(MY.DATE1 = as.Date(paste(DAY1 ,MONTH1, YEAR1), format = "%d %m %Y"),
                          MY.DATE2 = as.Date(paste(DAY2 ,MONTH2, YEAR2), format = "%d %m %Y"))][, 
                          mean.date := MY.DATE2 - ceiling((MY.DATE2 - MY.DATE1)/2)]
    
    my.data
    #     OBS MONTH1 DAY1 YEAR1 MONTH2 DAY2 YEAR2 STATE   MY.DATE1   MY.DATE2  mean.date
    #  1:   1      3    6  2012      3   10  2012     1 2012-03-06 2012-03-10 2012-03-08
    #  2:   2      3   10  2012      3   20  2012     1 2012-03-10 2012-03-20 2012-03-15
    #  3:   3      3   16  2012      3   30  2012     1 2012-03-16 2012-03-30 2012-03-23
    #  4:   4      3   20  2012      4    8  2012     1 2012-03-20 2012-04-08 2012-03-29
    #  5:   5      3   20  2012      4    9  2012     1 2012-03-20 2012-04-09 2012-03-30
    #  6:   6      3   20  2012      4   10  2012     1 2012-03-20 2012-04-10 2012-03-30
    #  7:   7      3   20  2012      4   11  2012     1 2012-03-20 2012-04-11 2012-03-31
    #  8:   8      4    4  2012      4    5  2012     1 2012-04-04 2012-04-05 2012-04-04
    #  9:   9      4    6  2012      4    6  2012     1 2012-04-06 2012-04-06 2012-04-06
    # 10:  10      4    6  2012      4    7  2012     1 2012-04-06 2012-04-07 2012-04-06
    

    或者如果你坚持使用mean.date,这里是替代解决方案:

    library(data.table)
    setDT(my.data)[, `:=`(MY.DATE1 = as.Date(paste(DAY1 ,MONTH1, YEAR1), format = "%d %m %Y"),
                          MY.DATE2 = as.Date(paste(DAY2 ,MONTH2, YEAR2), format = "%d %m %Y"))][, 
                          mean.date := mean.Date(c(MY.DATE1, MY.DATE2)), by = OBS]
    

    【讨论】:

    • @Spacedman,是的,你是对的,我一定是以前创建的。我已将其更改为 data.table 解决方案并克服了它。不确定最近是否值得为 pipomania 付出努力
    【解决方案4】:

    单线(为了便于阅读而拆分),使用 lubridate 和 dplyr 以及(当然)管道:

    > require(lubridate)
    > require(dplyr)
    > my.data =  my.data %>% 
        mutate(
          MY.DATE1=as.Date(mdy(paste(MONTH1,DAY1,YEAR1))),
          MY.DATE2=as.Date(mdy(paste(MONTH2,DAY2,YEAR2)))) %>% 
        rowwise %>%
        mutate(mean.data=mean.Date(c(MY.DATE1,MY.DATE2))) %>% data.frame()
    > head(my.data)
      OBS MONTH1 DAY1 YEAR1 MONTH2 DAY2 YEAR2 STATE   MY.DATE1   MY.DATE2
    1   1      3    6  2012      3   10  2012     1 2012-03-06 2012-03-10
    2   2      3   10  2012      3   20  2012     1 2012-03-10 2012-03-20
    3   3      3   16  2012      3   30  2012     1 2012-03-16 2012-03-30
    4   4      3   20  2012      4    8  2012     1 2012-03-20 2012-04-08
    5   5      3   20  2012      4    9  2012     1 2012-03-20 2012-04-09
    6   6      3   20  2012      4   10  2012     1 2012-03-20 2012-04-10
       mean.data
    1 2012-03-08
    2 2012-03-15
    3 2012-03-23
    4 2012-03-29
    5 2012-03-30
    6 2012-03-30
    

    作为事后的想法,如果您喜欢管道,您可以在管道中放置一个管道,这样您就可以在管道的同时进行管道 - 重写第一个 mutate 步骤:

    my.data %>% mutate(
      MY.DATE1 = paste(MONTH1,DAY1,YEAR1) %>% mdy %>% as.Date,
      MY.DATE2 = paste(MONTH2,DAY2,YEAR2) %>% mdy %>% as.Date)
    

    【讨论】:

    • 最后的解决方案太残忍了:)
    • 每次我在控制台上做的事情没有括号匹配,我必须计算右括号我才意识到它实际上更容易使用管道......
    【解决方案5】:

    1) 创建 Date 类列,然后很容易。没有使用外部包:

    asDate <- function(x) as.Date(x, "1970-01-01")
    
    my.data2 <- transform(my.data, 
       date1 = as.Date(ISOdate(YEAR1, MONTH1, DAY1)),
       date2 = as.Date(ISOdate(YEAR2, MONTH2, DAY2))
    )
    transform(my.data2, mean.date = asDate(rowMeans(cbind(date1, date2))))
    

    如果我们确实添加了一个library(zoo) 调用,那么我们可以在最后一行使用as.Date 而不是asDate 省略asDate 定义,因为zoo 为as.Date 添加了一个默认来源。

    1a) dplyr 版本如下所示(使用上面的 asDate):

    library(dplyr)
    
    my.data %>%
      mutate(
         date1 = ISOdate(YEAR1, MONTH1, DAY1) %>% as.Date,
         date2 = ISOdate(YEAR2, MONTH2, DAY2) %>% as.Date,
         mean.date = cbind(date1, date2) %>% rowMeans %>% asDate)
    

    2) 另一种方式是在chron包中使用julianjulian 将月/日/年转换为自纪元以来的天数。我们可以平均两个 julians 并转换回Date 类:

    library(zoo)
    library(chron)
    
    transform(my.data, 
      mean.date = as.Date( ( julian(MONTH1,DAY1,YEAR1) + julian(MONTH2,DAY2,YEAR2) )/2 ) 
    )
    

    如果我们使用 (1) 中的 asDate 代替 as.Date,我们可以省略 library(zoo)

    更新讨论了使用 zoo 来缩短解决方案并进一步减少解决方案 (1)。

    【讨论】:

    • 整洁的解决方案,但我不得不反对你不使用管道。 j/k
    • 抱歉,我添加了library(zoo),这是他们工作所必需的。否则,如果您将 origin = "1970-10-01" 添加到每个答案中的最后一个 as.Date 呼叫,它们仍然可以工作。
    【解决方案6】:

    怎么样:

    apply(my.data[,c("MY.DATE1","MY.DATE2")],1,function(date){substr(strptime(mean(c(strptime(date[1],"%y%y-%m-%d"),strptime(date[2],"%y%y-%m-%d"))),format="%y%y-%m-%d"),1,10)})
    

    ? (我只需要使用 substr 因为 CET 和 CEST 将我的输出作为列表...)

    【讨论】:

    • 这看起来类似于我上面发布的解决方案。
    【解决方案7】:

    这是 jaysunice3401 发布的答案的矢量化版本。这似乎相当简单,除了我必须使用反复试验来识别正确的origin。我不知道origin = "1970-01-01" 的通用性如何,也不知道每个数据集是否必须指定不同的来源。

    据本网站:http://www.ats.ucla.edu/stat/r/faq/dates.htm

    当 R 将日期视为整数时,它的起源是 1970 年 1 月 1 日。

    这似乎表明origin = "1970-01-01" 相当笼统。不过,如果我的数据集中有 "1970-01-01" 之前的日期,我肯定会在使用之前测试代码。

    my.data = read.table(text = "
         OBS  MONTH1  DAY1  YEAR1  MONTH2  DAY2  YEAR2   STATE
           1       3     6   2012       3    10   2012       1
           2       3    10   2012       3    20   2012       1
           3       3    16   2012       3    30   2012       1
           4       3    20   2012       4     8   2012       1
           5       3    20   2012       4     9   2012       1
           6       3    20   2012       4    10   2012       1
           7       3    20   2012       4    11   2012       1
           8       4     4   2012       4     5   2012       1
           9       4     6   2012       4     6   2012       1
          10       4     6   2012       4     7   2012       1
    ", header = TRUE, stringsAsFactors = FALSE)
    
    desired.result = read.table(text = "
       OBS MONTH1 DAY1 YEAR1 MONTH2 DAY2 YEAR2 STATE   MY.DATE1   MY.DATE2    mean.date
        1      3     6  2012      3   10  2012     1 2012-03-06 2012-03-10   2012-03-08
        2      3    10  2012      3   20  2012     1 2012-03-10 2012-03-20   2012-03-15
        3      3    16  2012      3   30  2012     1 2012-03-16 2012-03-30   2012-03-23
        4      3    20  2012      4    8  2012     1 2012-03-20 2012-04-08   2012-03-29
        5      3    20  2012      4    9  2012     1 2012-03-20 2012-04-09   2012-03-30
        6      3    20  2012      4   10  2012     1 2012-03-20 2012-04-10   2012-03-30
        7      3    20  2012      4   11  2012     1 2012-03-20 2012-04-11   2012-03-31
        8      4     4  2012      4    5  2012     1 2012-04-04 2012-04-05   2012-04-04
        9      4     6  2012      4    6  2012     1 2012-04-06 2012-04-06   2012-04-06
       10      4     6  2012      4    7  2012     1 2012-04-06 2012-04-07   2012-04-06
    ", header = TRUE, stringsAsFactors = FALSE)
    
    my.data$MY.DATE1 <- do.call(paste, list(my.data$MONTH1,my.data$DAY1,my.data$YEAR1))
    my.data$MY.DATE2 <- do.call(paste, list(my.data$MONTH2,my.data$DAY2,my.data$YEAR2))
    
    my.data$MY.DATE1 <- as.Date(my.data$MY.DATE1, format=c("%m %d %Y"))
    my.data$MY.DATE2 <- as.Date(my.data$MY.DATE2, format=c("%m %d %Y"))
    
    my.data$mean.date2 <- as.Date( apply(my.data, 1, function(x) {
    
                          mean.Date(c(as.Date(x['MY.DATE1']), as.Date(x['MY.DATE2'])))
    
                          }) , origin = "1970-01-01")
    my.data
    
    desired.result
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-04
      • 1970-01-01
      • 1970-01-01
      • 2016-06-06
      • 2020-07-24
      • 2020-07-04
      • 2023-01-19
      • 2017-11-26
      相关资源
      最近更新 更多