2017-07-25 65 views
2

我有一个ID和一个事件发生日期列表的时间序列。我想知道在我的时间序列中某个特定日期发生了多少次事件。在列表中作为R中的数据框的元素进行操作

下面是一个示例数据框:

ID <- c(1,1,1,2,2,2,3,3,3) 
date <- c(2000,2001,2002) 
df <- data.frame(ID,date) 

rand1 <- c(runif(5)*4+1999) 
rand2 <- c(runif(6)*4+1999) 
rand3 <- c(runif(100)*4+1999) 

df$events <- list(rand1, rand1, rand1, rand2, rand2, rand2,rand3, rand3, rand3) 

此代码正确地解决我的问题:

for (i in c(1:9)){ 
    print(i) 
    df[i,]$past <- sum(df[i,]$events[[1]] < df[i,]$date) 
} 

但似乎疯狂低效通过数据帧去一行行。我的真实数据集有400万行,所以我需要一些更明智的东西。

这是我第一次尝试:我不确定它到底在做什么,但它最终创建了df $ past2的所有元素作为某个整数。

df$past2 <- sum(df$events[[1]] < df$date) 

得到的DF:

ID date  events past past2 
<dbl> <dbl>  <list> <dbl> <int> 
1 2000  <dbl [5]> 3  6 
1 2001  <dbl [5]> 3  6 
1 2002  <dbl [5]> 4  6 
2 2000  <dbl [6]> 0  6 
2 2001  <dbl [6]> 3  6 
2 2002  <dbl [6]> 5  6 
3 2000 <dbl [100]> 26  6 
3 2001 <dbl [100]> 55  6 
3 2002 <dbl [100]> 74  6 

所以,

1)什么是我的计算真正在做什么?

2)有没有办法对列表中的数据框的元素进行这种操作,而不是逐行进行?

谢谢。

回答

1

您的df $ past2的问题是df$events[[1]]总是返回df[1,]$df$events[[1]]

一个解决问题的方法是将您的数据帧中的每一行分成列表,并lapply使用:

df$past2 = unlist(lapply(split(df,seq(nrow(df))),function(x) sum(x$events[[1]]< x$date))) 

然而,因为有一些数据操纵,我不知道,这是非常有效的与一个400万行的数据帧。您可能需要查看data.tabledplyr以查找更有效的解决方案。

0

您可以使用tidyr::unnest()为每个事件创建一行,然后使用dplyr::filter()来处理发生在感兴趣日期之后的事件。

2

1)您的计算返回事件列表的FIRST值小于日期列中的值的行数,然后将整个列设置为此值。括号中的表达式返回TRUEFALSE,当您拨打sum()时,表达式将被解释为 10。例如sum(TRUE, TRUE, FALSE)返回2

2)使用tidyr::unnest()功能以及从dplyr包的功能,你可以做到以下几点:

df2 <- df %>% 
    unnest(events) %>% 
    group_by(ID, date) %>% 
    mutate(past = if_else(events < date, 1, 0)) %>% 
    summarize(past2 = sum(past)) 
+0

无论这个答案,并在我的例子问题@ xraynaud的回答工作,但是基于微基准两种方法的结果,这一个是100倍快。编辑添加我的单位为相同的代码是不一样的...重新检查和病态更新,当我有单位正确。 – Chris

+0

好的,在得到我的单位正确之后:unlist的平均时间为732微秒,而unnest的平均时间为4060微秒。这种方法的代码更容易阅读和理解,所以我认为这可能是很多情况下的正确选择。 – Chris