计算行之间的时差(以天为单位)

时间:2018-03-21 13:14:31

标签: r dplyr data.table zoo lubridate

我试图计算行数创建间隔的天数差异。

我的名为SELECT extract(xmlval,'/EMP/EMPNO/text()').getNumberVal() as empno FROM Xml_tab WHERE existsnode(xmlval,'/EMP/EMPNO') = 1 ; 的数据集如下所示,

temp

所以我的问题是如何通过ID计算日期之间的差异?所以ID 31933是2天,31750 6,20和1天。 我尝试了其他几个例子,例如

ID  Event
31933   11/12/2016
31933   11/14/2016
31750   09/04/2016
31750   09/10/2016
31750   09/30/2016
31750   10/01/2016
30995   09/04/2016
30995   09/09/2016
30995   09/10/2016
30995   9/24/2016

此处的错误是library(zoo) setDT(temp) Interval<- function(x) difftime(x[3], x[1],units = "days") temp[, INTERVAL := rollapply(Event, 3, diff, align = "left", fill = NA), by= ID] 。对于最快的情况,检查和强制会对性能产生太大影响。要么更改目标列的类型,要么强制{= 1} :(例如,使用1L而不是1)&#34;

还尝试了一些data.table函数,但它们没有用。

我对R很陌生,所以我想有一个简单的解决方案。

4 个答案:

答案 0 :(得分:2)

data.tablelubridate

library(lubridate)
library(data.table)

setDT(df)[, Days := c(NA, diff(mdy(Event))), by=ID]

或:

setDT(df)[, Days := mdy(Event)-lag(mdy(Event)), by=ID]

<强>结果:

       ID      Event    Days
 1: 31933 11/12/2016 NA days
 2: 31933 11/14/2016  2 days
 3: 31750 09/04/2016 NA days
 4: 31750 09/10/2016  6 days
 5: 31750 09/30/2016 20 days
 6: 31750 10/01/2016  1 days
 7: 30995 09/04/2016 NA days
 8: 30995 09/09/2016  5 days
 9: 30995 09/10/2016  1 days
10: 30995  9/24/2016 14 days

您还可以使用dplyrlubridate

尝试以下操作
library(lubridate)
library(dplyr)

df %>%
  group_by(ID) %>%
  mutate(Event = mdy(Event),
         Days = Event - lag(Event))

<强>结果:

# A tibble: 10 x 3
# Groups:   ID [3]
      ID      Event    Days
   <int>     <date>  <time>
 1 31933 2016-11-12 NA days
 2 31933 2016-11-14  2 days
 3 31750 2016-09-04 NA days
 4 31750 2016-09-10  6 days
 5 31750 2016-09-30 20 days
 6 31750 2016-10-01  1 days
 7 30995 2016-09-04 NA days
 8 30995 2016-09-09  5 days
 9 30995 2016-09-10  1 days
10 30995 2016-09-24 14 days

或者如果您想删除NA行:

df %>%
  group_by(ID) %>%
  mutate(Event = mdy(Event),
         Days = Event - lag(Event)) %>%
  filter(Days > 0)

<强>结果:

# A tibble: 7 x 3
# Groups:   ID [3]
     ID      Event    Days
  <int>     <date>  <time>
1 31933 2016-11-14  2 days
2 31750 2016-09-10  6 days
3 31750 2016-09-30 20 days
4 31750 2016-10-01  1 days
5 30995 2016-09-09  5 days
6 30995 2016-09-10  1 days
7 30995 2016-09-24 14 days

数据:

df = structure(list(ID = c(31933L, 31933L, 31750L, 31750L, 31750L, 
31750L, 30995L, 30995L, 30995L, 30995L), Event = structure(c(6L, 
7L, 1L, 3L, 4L, 5L, 1L, 2L, 3L, 8L), .Label = c("09/04/2016", 
"09/09/2016", "09/10/2016", "09/30/2016", "10/01/2016", "11/12/2016", 
"11/14/2016", "9/24/2016"), class = "factor")), .Names = c("ID", 
"Event"), class = "data.frame", row.names = c(NA, -10L))

答案 1 :(得分:1)

有几个问题:

  • 日期应该是"Date"课程,而不是"character"课程

  • 在R中
  • NA是合乎逻辑的。写入NA类型为NA_real_通常没关系,但在这种情况下,由于data.table的工作方式,它很重要。

  • 如果您将代码缩进4个空格,那么SO会为您格式化

  • 问题中没有显示所需的输出,但是从代码中询问每隔一行之间的差异。我们显示了每个其他行的解决方案,但是如果您想要连续的行,则在每个解决方案中将2替换为1。

使用上面我们这样写:

library(data.table)
library(zoo) 

setDT(temp) 
temp$Event <- as.Date(temp$Event, "%m/%d/%Y")

roll <- function(x, k) rollapply(x, k+1, diff, lag = k, align = "left", fill = NA_real_)
temp[, INTERVAL := roll(as.numeric(Event), 2), by = ID]

给出所有其他行案例:

> temp
       ID      Event INTERVAL
 1: 31933 2016-11-12       NA
 2: 31933 2016-11-14       NA
 3: 31750 2016-09-04       26
 4: 31750 2016-09-10       21
 5: 31750 2016-09-30       NA
 6: 31750 2016-10-01       NA
 7: 30995 2016-09-04        6
 8: 30995 2016-09-09       15
 9: 30995 2016-09-10       NA
10: 30995 2016-09-24       NA

这个使用data.table的shift的替代方法也可以使用,只需要data.table:

temp[, INTERVAL := as.numeric(shift(Event, 2, type = "lead") - Event), by = ID]

如果您打算连续的行而不是每隔一行,则使用1替换上述任一解决方案中的2。

注意

可重复形式的输入是:

Lines <- "ID Event 
31933 11/12/2016 
31933 11/14/2016 
31750 09/04/2016 
31750 09/10/2016 
31750 09/30/2016 
31750 10/01/2016 
30995 09/04/2016 
30995 09/09/2016 
30995 09/10/2016 
30995 09/24/2016"
temp <- read.table(text = Lines, header = TRUE)

答案 2 :(得分:0)

日期类以按天测量日期的格式存储,因此您可以使用它们执行简单的关节模拟,as per this SO thread.

它使用YYYY / MM / DD格式。例如

abs(as.Date("2016/11/12") - as.Date("2016/11/14"))
Time difference of 2 days

如果您将日期重新格式化为YYYY / MM / DD,您应该可以使用,例如, abs(temp[1, 2] - temp[2, 2])确定前两行中日期之间的差异。

答案 3 :(得分:0)

非常感谢你的所有建议。我想通了。

temp<- data.table(ID,Event, key = c("ID", "Event"))
temp[,INTER := c(0,'units<-'(diff(Event), "days")),by= ID]

然后将其与我的数据集合并。假设它不是很优雅,但它有效。