使用dplyr进行交互的频率计数,必须包括零计数

时间:2014-05-20 22:01:54

标签: r dplyr frequency interaction large-data

我的问题涉及使用R

中的 dplyr 包编写代码

我有一个相对较大的数据框(大约500万行),有2列:第一列有个人标识符(id),第二列有日期(date)。目前,每行表示日期列中日期上发生的操作(由id列中的个人采取)。大约有300,000个独特个体,大约2600个独特日期。例如,数据的开头如下所示:

    id         date
    John12     2006-08-03
    Tom2993    2008-10-11
    Lisa825    2009-07-03
    Tom2993    2008-06-12
    Andrew13   2007-09-11

我想重新整形数据,以便为每个可能的id x date对添加一行,并附加一列来计算发生的事件总数(可能是在给定日期列出的个人的价值为0)。

我在 dplyr 包中取得了一些成功,我曾用它来列出数据中观察到的id x日期计数。

以下是到目前为止用于制表id x date计数的代码:(我的数据框称为 df

reduced = df %.% 
  group_by(id, date) %.%
  summarize(length(date))

我的问题是(正如我上面所说)我想要一个数据集,其中包含0个没有任何相关操作的id x日期对。例如,如果在2007-10-10没有观察到John12的操作,我希望输出为id x date对返回一行,计数为0.

我考虑过创建上面的框架,然后使用空框架进行合并,但我确信必须有一个更简单的解决方案。任何建议非常感谢!

2 个答案:

答案 0 :(得分:6)

这是一个简单的选项,改为使用data.table

library(data.table)

dt = as.data.table(your_df)

setkey(dt, id, date)

# in versions 1.9.3+
dt[CJ(unique(id), unique(date)), .N, by = .EACHI]
#          id       date N
# 1: Andrew13 2006-08-03 0
# 2: Andrew13 2007-09-11 1
# 3: Andrew13 2008-06-12 0
# 4: Andrew13 2008-10-11 0
# 5: Andrew13 2009-07-03 0
# 6:   John12 2006-08-03 1
# 7:   John12 2007-09-11 0
# 8:   John12 2008-06-12 0
# 9:   John12 2008-10-11 0
#10:   John12 2009-07-03 0
#11:  Lisa825 2006-08-03 0
#12:  Lisa825 2007-09-11 0
#13:  Lisa825 2008-06-12 0
#14:  Lisa825 2008-10-11 0
#15:  Lisa825 2009-07-03 1
#16:  Tom2993 2006-08-03 0
#17:  Tom2993 2007-09-11 0
#18:  Tom2993 2008-06-12 1
#19:  Tom2993 2008-10-11 1
#20:  Tom2993 2009-07-03 0

在1.9.2版本中或等效表达式之前省略了显式by

dt[CJ(unique(id), unique(date)), .N]

我们的想法是创建所有可能的iddate对(这是CJ部分所做的),然后将其合并,计算出现次数。

答案 1 :(得分:3)

这就是你可以做到的方式,虽然我只使用dplyr来计算原始df和left_join的频率。正如您在问题中已经建议的那样,我创建了一个新的data.frame并将其与现有数据合并。我想如果你想在dplyr专门做这件事,那就要求你在过程中以某种方式rbind许多行,我认为这种方式可能比另一方更快。

require(dplyr)

original <- read.table(header=T,text="    id         date
John12     2006-08-03
Tom2993    2008-10-11
Lisa825    2009-07-03
Tom2993    2008-06-12
Andrew13   2007-09-11", stringsAsFactors=F)

original$date <- as.Date(original$date) #convert to date

#get the frequency in original data in new column and summarize in a single row per group
original <- original %>%
  group_by(id, date) %>%
  summarize(count = n())            

#create a sequence of date as you need it
dates <- seq(as.Date("2006-01-01"), as.Date("2009-12-31"), 1)    

#create a new df with expand.grid to get all combinations of date/id
newdf <- expand.grid(id = original$id, date = dates)     

#remove dates
rm(dates)

#join original and newdf to have the frequency counts from original df
newdf <- left_join(newdf, original, by=c("id","date"))   

#replace all NA with 0 for rows which were not in original df
newdf$count[is.na(newdf$count)] <- 0