Использование dplyr для подсчета частоты взаимодействий должно включать нулевые отсчеты
Мой вопрос заключается в написании кода с помощью пакета dplyr в R
У меня относительно большой размер данных (около 5 миллионов строк) с двумя столбцами: первый с отдельным идентификатором (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))
Моя проблема в том, что (как я сказал выше) я бы хотел иметь набор данных, который также включает 0s для пар id x date, которые не имеют связанных действий. Например, если не было обнаруженного действия для John12 в 2007-10-10, я бы хотел, чтобы результат возвращал строку для этой пары id
x date
с числом 0.
Я подумал о создании фрейма выше, а затем слияния с пустым фреймом, но я убежден, что должно быть более простое решение. Любые предложения очень ценятся!
Ответы
Ответ 1
Вот простой вариант, вместо 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]
Идея состоит в том, чтобы создать все возможные пары id
и date
(это то, что делает часть CJ
), а затем объединить ее, подсчитывая вхождения.
Ответ 2
Вот как вы могли это сделать, хотя я использую 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