2017-07-25 41 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

相關問題