создание новой переменной, которая учитывает предшествующую информацию из более ранних записей - PullRequest
0 голосов
/ 18 сентября 2018

У меня есть следующие данные, и я хочу создать новую переменную, которая учитывает предыдущую информацию за предыдущий период.Например,

moviewatched<- c('Comedy', 'Horror', 'Comedy', 'Horror', 'Drama', 'Comedy', 'Drama')
name<- c('john', 'john', 'john', 'john', 'john','kate','kate')
time<- c('1-2018', '1-2018', '1-2018', '2-2018', '2-2018','1-2018' ,'2-2018')


df<- data.frame(moviewatched, name, time)

Теперь мне нужно создать переменную, которая будет сообщать, какой новый тип жанровых фильмов он / она смотрел в этом месяце.Например, в приведенном выше случае Джон просмотрел 2 жанровых типа в первый месяц 2018 года и 1 новый дополнительный тип во втором месяце (поскольку он уже смотрел комедии и фильмы ужасов в первый месяц). Есть ли способ, которым я могу создатьсчетчик новых типов, которые человек начал смотреть?Я хочу создать переменную с именем movietypewatched, которая содержит общее количество жанров, которые этот человек просматривал до этого месяца.Ожидаемый результат будет следующим:

     name time   movietypewatched 
     john 1-2018       2
     john 2-2018       3
     kate 1-2018       1
     kate 2-2018       2

Спасибо

Ответы [ 5 ]

0 голосов
/ 18 сентября 2018

Здесь вы можете сделать промежуточные шаги, если хотите получить уникальные значения в genre_all и счет в genre_count.

Обратите внимание:

  • Вам нужно расположить фрейм данных по name, date для накопления значений.
  • Вы можете использовать lag(), чтобы получить предыдущее значение.Поскольку первая запись для каждого name не имеет предыдущего значения, она даст NA.
  • . Вам нужно будет удалить NA, когда вы подсчитываете уникальные жанры, используя n_distinct().
0 голосов
/ 18 сентября 2018

Составить таблицу первых просмотренных дат;считать по месяцам;и возьмите накопленную сумму:

library(data.table)
setDT(df)

# fix bad date
df[, d := as.IDate(paste(time, "01", sep="-"), "%m-%Y-%d")]

# identify month first watched
fw = df[, .(d = min(d)), by=.(name, moviewatched)]

# count new movies per month
nm = fw[, .N, keyby=.(name, d)]

# take cumulative count
nm[, cN := cumsum(N), by=name]

   name          d N cN
1: john 2018-01-01 2  2
2: john 2018-02-01 1  3
3: kate 2018-01-01 1  1
4: kate 2018-02-01 1  2

Вам необходимо преобразовать дату;в противном случае min () будет неправильным и / или сломанным.

Здесь есть два этапа агрегации, но код должен быть быстрым благодаря оптимизации в data.table (см. ?GForce).

0 голосов
/ 18 сентября 2018

Сначала преобразуйте данные времени в класс, чтобы установить порядок, например, с помощью lubridate::myd и truncated = 1.Отсюда установите расположение строк, чтобы убедиться, что они в порядке, затем, сгруппированные по name, используйте purrr::accumulate, чтобы сгенерировать список уникальных значений, видимых до сих пор в moviewatched, при вызове которого lengths будетверните количество фильмов, просмотренных к этому моменту.Суммируйте по месяцам max, чтобы получить общее количество типов за каждый месяц.

library(tidyverse)

df <- data_frame(
    moviewatched =  c('Comedy', 'Horror', 'Comedy', 'Horror', 'Drama', 'Comedy', 'Drama'),
    name =  c('john', 'john', 'john', 'john', 'john','kate','kate'),
    time =  lubridate::myd(c('1-2018', '1-2018', '1-2018', '2-2018', '2-2018','1-2018' ,'2-2018'), truncated = 1)
)

df %>% 
    group_by(name) %>% 
    arrange(name, time) %>%
    mutate(n_types = lengths(accumulate(moviewatched, ~unique(c(...))))) %>% 
    group_by(name, time) %>% 
    summarise(n_types = max(n_types))
#> # A tibble: 4 x 3
#> # Groups:   name [2]
#>   name  time       n_types
#>   <chr> <date>       <dbl>
#> 1 john  2018-01-01       2
#> 2 john  2018-02-01       3
#> 3 kate  2018-01-01       1
#> 4 kate  2018-02-01       2
0 голосов
/ 18 сентября 2018

Использование data.table:

library(data.table)
df <- unique(df) 
setDT(df)[, movietypewatched := 1:.N, by = c("moviewatched", "name")] 
df <- df[!(movietypewatched == 2), ]
df[, movietypewatched := .N, by = c("name", "time")][, moviewatched := NULL]
df <- unique(df)
df[, movietypewatched := cumsum(movietypewatched), by = name]

   name   time movietypewatched
1: john 1-2018                2
2: john 2-2018                3
3: kate 1-2018                1
4: kate 2-2018                2
0 голосов
/ 18 сентября 2018

Решение с использованием dplyr.Мы можем удалить дублирующиеся строки на основе moviewatched и name, считать уникальные moviewatched, а затем использовать cumsum для расчета промежуточного итога.df2 - это конечный результат.

library(dplyr)

df2 <- df %>%
  distinct(moviewatched, name, .keep_all = TRUE) %>%
  group_by(name, time) %>%
  summarise(movietypewatched = n_distinct(moviewatched)) %>%
  mutate(movietypewatched = cumsum(movietypewatched)) %>%
  ungroup()
df2
# # A tibble: 4 x 3
#   name  time   movietypewatched
#   <fct> <fct>             <int>
# 1 john  1-2018                2
# 2 john  2-2018                3
# 3 kate  1-2018                1
# 4 kate  2-2018                2

А вот решение data.table по той же логике.

library(data.table)

setDT(df)
df2 <- df[!duplicated(df[, .(moviewatched, name)])][
  , .(movietypewatched = uniqueN(moviewatched)), by = .(name, time)][
    , movietypewatched := cumsum(movietypewatched), by = name]
df2[]
#    name   time movietypewatched
# 1: john 1-2018                2
# 2: john 2-2018                3
# 3: kate 1-2018                1
# 4: kate 2-2018                2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...