Совокупное (расширяющееся окно) среднее по группе с дубликатом проверки для каждого расчета - PullRequest
3 голосов
/ 20 марта 2019

Я пытаюсь вычислить среднее значение по расширяющемуся окну, однако структура данных делает так, чтобы в предыдущих ответах отсутствовала хотя бы небольшая часть того, что нужно (самое близкое здесь: ссылка ).

Мои данные выглядят примерно так:

  Company TimePeriod IndividualID Date.Indiv.Acted  Value 
1  1         2015          A           2015-01-01    400
2  1         2015          B           2015-02-01    200
3  1         2015          A           2015-06-15    400
4  1         2015          C           2015-07-12    300
5  1         2016          A           2016-07-15    400
6  1         2016          B           2016-08-09    100
7  1         2016          C           2016-09-10    400
8  1         2016          A           2016-10-11    100
9  2         2004          A           2004-07-12    200
10 2         2004          B           2004-08-12    300

И мне нужно взять кумулятивное среднее значение по Company-TimePeriod для каждого объекта Date.Indiv.Acted.Тем не менее, мне нужно удалить дубликаты, поскольку я сохраняю самую последнюю.Таким образом, для первых двух средних значений проблем не возникает - они включают строку 1, строку 1 и строку 2. Однако строки 1, 2 и 3 должны удалить строку 1, поскольку IndividualID является дубликатом.По сути, у меня есть информация о прогнозе, и я хочу использовать только самый последний прогноз для отдельного человека при каждом расчете среднего.

Поэтому мои окончательные данные будут выглядеть примерно так (строки добавлены для простоты интерпретации - ненужно это в данных),

  Company TimePeriod IndividualID Date.Indiv.Acted  Value CumMean 
1  1         2015          A           2015-01-01    400   400
2  1         2015          B           2015-02-01    200   300 (row 1 and 2)
3  1         2015          A           2015-06-15    400   300 (row 2 and 3)
4  1         2015          C           2015-07-12    300   300 (2,3,4)
5  1         2016          A           2016-07-15    400   400 (5)
6  1         2016          B           2016-08-09    100   250 (5,6)
7  1         2016          C           2016-09-10    400   300 (5,6,7)
8  1         2016          A           2016-10-11    100   200 (6,7,8)
9  2         2004          A           2004-07-12    200   200 (9)
10 2         2004          B           2004-08-12    300   250 (9,10)

Решение data.table было бы идеальным, но я не требователен, если оно может работать на довольно больших данных (20M строк или около того) и не приниматьдо тепловой смерти вселенной.

Любая помощь, которую вы, ребята, получите, будет принята с благодарностью.

Ответы [ 2 ]

3 голосов
/ 20 марта 2019
setDT(dt)
dt[, occ := 1:.N, by = .(Company, TimePeriod, IndividualID)]
dt[, n := cumsum(!duplicated(IndividualID)), by = .(Company, TimePeriod)]
dt[, Value1 := Value,]
dt[, x := c(0, diff(Value)), by = .(Company, TimePeriod, IndividualID)]
dt[occ>1, Value1 := x,]
dt[, Cummean := cumsum(Value1)/n, by = .(Company, TimePeriod)]
dt[, c("occ", "n", "Value1", "x") := NULL][]
#    Company TimePeriod IndividualID Date.Indiv.Acted Value Cummean
# 1:       1       2015            A       2015-01-01   400     400
# 2:       1       2015            B       2015-02-01   200     300
# 3:       1       2015            A       2015-06-15   400     300
# 4:       1       2015            C       2015-07-12   300     300
# 5:       1       2016            A       2016-07-15   400     400
# 6:       1       2016            B       2016-08-09   100     250
# 7:       1       2016            C       2016-09-10   400     300
# 8:       1       2016            A       2016-10-11   100     200
# 9:       2       2004            A       2004-07-12   200     200
#10:       2       2004            B       2004-08-12   300     250

dt <- structure(list(Company = c(1, 1, 1, 1, 1, 1, 1, 1, 2, 2), TimePeriod = c(2015, 
2015, 2015, 2015, 2016, 2016, 2016, 2016, 2004, 2004), IndividualID = c("A", 
"B", "A", "C", "A", "B", "C", "A", "A", "B"), Date.Indiv.Acted = c("2015-01-01", 
"2015-02-01", "2015-06-15", "2015-07-12", "2016-07-15", "2016-08-09", 
"2016-09-10", "2016-10-11", "2004-07-12", "2004-08-12"), Value = c(400, 
200, 400, 300, 400, 100, 400, 100, 200, 300)), row.names = c(NA, 
-10L), class = "data.frame")
1 голос
/ 20 марта 2019

Мне особенно не нравятся петли, но я думаю, что этот стал достаточно простым, чтобы понять шаг за шагом. Его можно легко изменить, чтобы использовать любую другую метрику вместо среднего (например, кумулятивная дисперсия)

# function that drops duplicates and calculates cumulative mean
fun.attempt <- function(dat, dup, value){
  #dat: data set
  #dup: string column to look for duplicates
  #value: string column to calculate the mean

  x <- dat[!duplicated(get(dup), fromLast = T), .(get(value))]

  y <- cumsum(x) / 1:nrow(x)

  y <- y[nrow(y)]
  return(y)
}

foo[, grp := .GRP, by = .(Company, TimePeriod)] # to create a more efficient loop
hl <- list() # as storage

for(k in unique(foo$grp)){

    got <- foo[grp == k] # running the cumulative mean for each grouping

    for(y in 1:nrow(got)){
      # applying customized function
      got[y, cummean2:= fun.attempt(got[1:y], 'IndividualID', 'Value')]

    }

    hl[[k]] <- got # storing the subsetted data.tables

}

Теперь просто скомпилируйте списки data.tables. CumMean столбец - ваш исходный расчет, cummean2 - мой.

rbindlist(hl)
    Company TimePeriod IndividualID Date.Indiv.Acted Value CumMean grp cummean2
 1:       1       2015            A       2015-01-01   400     400   1      400
 2:       1       2015            B       2015-02-01   200     300   1      300
 3:       1       2015            A       2015-06-15   400     300   1      300
 4:       1       2015            C       2015-07-12   300     300   1      300
 5:       1       2016            A       2016-07-15   400     400   2      400
 6:       1       2016            B       2016-08-09   100     250   2      250
 7:       1       2016            C       2016-09-10   400     300   2      300
 8:       1       2016            A       2016-10-11   100     200   2      200
 9:       2       2004            A       2004-07-12   200     200   3      200
10:       2       2004            B       2004-08-12   300     250   3      250
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...