У меня есть список наблюдений на пользователя; Каждый пользователь может иметь несколько наблюдений foo
в день. Для каждого отдельного дня я хотел бы получить совокупное количество значений foo
. Вот что я получил до сих пор:
library(tidyverse)
library(lubridate)
df = tribble(
~user_id, ~foo, ~bar, ~created_at,
1, "a", "b", "2018-07-30",
1, "a", "c", "2018-07-31",
1, "a", "c", "2018-07-31",
1, "b", "a", "2018-08-01",
1, "b", "c", "2018-08-02",
1, "b", "a", "2018-08-03",
1, "a", "a", "2018-08-03",
2, "b", "b", "2018-07-30",
2, "b", "c", "2018-07-31",
2, "a", "a", "2018-08-01",
2, "a", "a", "2018-08-01",
2, "a", "c", "2018-08-02",
2, "a", "c", "2018-08-02",
2, "a", "a", "2018-08-03"
) %>% mutate_at("created_at", as_datetime)
df %>%
mutate(cutoff_date = created_at %>% date) %>%
group_by(user_id, foo, cutoff_date) %>%
tally %>%
mutate(foo_cnt = cumsum(n)) %>%
select(-n) %>%
arrange(user_id, cutoff_date, foo)
Это дает мне:
user_id foo cutoff_date foo_cnt
<dbl> <chr> <date> <int>
1 1. a 2018-07-30 1
2 1. a 2018-07-31 3
3 1. b 2018-08-01 1
4 1. b 2018-08-02 2
5 1. a 2018-08-03 4
6 1. b 2018-08-03 3
7 2. b 2018-07-30 1
8 2. b 2018-07-31 2
9 2. a 2018-08-01 2
10 2. a 2018-08-02 4
11 2. a 2018-08-03 5
Отлично, я знаю, что до 3 августа пользователь 1 видел a
четыре раза и b
три раза. Теперь я хотел бы знать, для каждой даты, которая встречается в моих данных (меня не волнуют пропущенные даты):
- Общее количество конкретных
foo
наблюдений до даты
- Относительный объем наблюдения по сравнению с другими
То есть вывод должен быть:
user_id cutoff_date foo foo_cnt foo_cnt_total foo_pct
1 1. 2018-07-30 a 1 1 100
2 1. 2018-07-30 b 0 0 0
3 1. 2018-07-31 a 3 4 100
4 1. 2018-07-31 b 0 0 0
5 1. 2018-08-01 a 3 7 87.5
6 1. 2018-08-01 b 1 1 12.5
...
В строке 5 это 87,5%, потому что пользователь видел a
семь раз и b
один раз до этой точки.
У меня есть идея, как туда добраться, но я борюсь с включением других значений foo
для даты, которая присутствует в данных, но где нет наблюдения foo
. Я изучил complete()
, но не могу понять, как использовать его для заполнения оставшихся значений.
Например, когда я добавляю один из них, я не получаю дополнительных столбцов:
complete(nesting(user_id, foo), cutoff_date)
complete(user_id, cutoff_date, foo)
Чего мне не хватает?
Обновление: я добавил ungroup
как предложено, и теперь я также получаю общее количество за день. Я использовал fill
, чтобы заполнить предыдущие значения для того же значения foo
:
df %>%
mutate(cutoff_date = created_at %>% date) %>%
group_by(user_id, foo, cutoff_date) %>%
tally %>%
mutate(foo_cnt = cumsum(n)) %>%
select(-n) %>%
ungroup() %>%
complete(nesting(user_id, foo), cutoff_date) %>%
arrange(user_id, cutoff_date, foo) %>%
group_by(user_id, foo) %>%
fill(foo_cnt) %>%
ungroup() %>%
group_by(user_id, cutoff_date) %>%
mutate(foo_cnt_total = sum(foo_cnt, na.rm = TRUE))
user_id foo cutoff_date foo_cnt foo_cnt_total
<dbl> <chr> <date> <int> <int>
1 1. a 2018-07-30 1 1
2 1. a 2018-07-31 3 3
3 1. a 2018-08-01 3 4
4 1. a 2018-08-02 3 5
5 1. a 2018-08-03 4 7
6 1. b 2018-07-30 NA 1
7 1. b 2018-07-31 NA 3
8 1. b 2018-08-01 1 4
9 1. b 2018-08-02 2 5
10 1. b 2018-08-03 3 7
Однако значение b
не должно начинаться с NA
. Что здесь понадобится?