Korzystanie z dplyr do liczenia częstotliwości interakcji, musi zawierać zerowe liczby

Moje pytanie dotyczy pisania kodu za pomocą pakietu dplyr W R

Mam stosunkowo dużą ramkę danych (około 5 milionów wierszy) z 2 kolumnami: pierwsza z indywidualnym identyfikatorem (id), a druga z datą (date). Obecnie każdy wiersz wskazuje wystąpienie akcji (wykonanej przez osobę w kolumnie id) w dniu w kolumnie Data. Istnieje około 300 000 unikalnych osób i około 2600 unikalnych dat. Na przykład początek dane wyglądają tak:

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

Chciałbym przekształcić dane tak, aby mieć wiersz dla każdej możliwej pary id x date, z dodatkową kolumną, która liczy całkowitą liczbę zdarzeń, które miały miejsce (być może przyjmując wartość 0) dla wymienionej osoby w podanej dacie.

Odniosłem sukces z pakietem dplyr , którego użyłem do tabulacji dat id x, które są obserwowane w danych.

Oto kod, którego użyłem do tabulacji id x date liczy się do tej pory: (mój dataframe nazywa się df )

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

Mój problem polega na tym, że (jak powiedziałem powyżej) chciałbym mieć zestaw danych, który zawiera również 0s dla par dat id X, które nie mają żadnych powiązanych działań. Na przykład, jeśli nie ma zaobserwowanej akcji dla John12 w dniu 2007-10-10, chciałbym, aby wyjście zwróciło wiersz dla pary id x date, z liczbą 0.

Rozważałem utworzenie powyższej ramki, a następnie połączenie z pustą ramką, ale jestem przekonany musi być prostsze rozwiązanie. Wszelkie sugestie bardzo mile widziane!

Author: Community, 2014-05-21

2 answers

Oto prosta opcja, używając zamiast tego 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

W wersji 1.9.2 lub przed wyrażeniem równoważnym pomija jawne by:

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

Chodzi o to, aby utworzyć wszystkie możliwe pary id i date (co robi CJ część), a następnie połączyć je z powrotem, licząc zdarzenia.

 6
Author: eddi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-21 15:25:38

W ten sposób możesz to zrobić, chociaż używamdplyr tylko częściowo do obliczania częstotliwości w Twoim oryginalnym df i dla left_join. Jak już zasugerowałeś w swoim pytaniu, stworzyłem nowe dane.ramki i połączył go z istniejącym. Myślę, że jeśli chcesz robić to wyłącznie w dplyr, to wymagałoby to od Ciebie w jakiś sposób rbind wielu wierszy w procesie i zakładam, że ten sposób może być szybszy niż drugi.

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          
 3
Author: docendo discimus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-31 05:28:24