Как я могу создать скользящее среднее для каждого пользователя на основе предыдущих 7 дней активности? - PullRequest
0 голосов
/ 22 июня 2019

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

Я использовал dplyr для группировки по пользователю, но не могу понять, как брать каждую отметку времении запишите среднее значение всех действий до этой отметки времени, чтобы получить скользящее среднее для каждого человека.Это большой набор данных, поэтому он должен быть эффективным.Я уверен, что datatable может достичь этого, но я нахожу код трудным для интерпретации, даже если он намного быстрее.

User  Stamp          activity   Score    

1     2019-06-20     "Car"      4500
1     2019-06-18     "Car"      600
1     2019-06-15     "Walk"     650
1     2019-06-21     "Ride"     790
2     2019-06-21     "Car"      800    
2     2019-06-23     "Car"      500
3     2019-06-11     "Walk"     900
4     2019-06-15     "Walk"     200   
4     2019-06-12     "Walk"     900

Нужно стать чем-то вроде этого.У нас есть скользящие пропорции и скользящие средства для каждого пользователя, основанные на отметке времени, исключая это наблюдение отметок времени.

User  Stamp          activity   Score   proportion_walk   mean_score    

1     2019-06-20     "Car"      4500    .5                 625
1     2019-06-18     "Car"      600     1                  650
1     2019-06-15     "Walk"     650     0                   0
1     2019-06-21     "Ride"     790     .33                   1916.33
2     2019-06-21     "Car"      800     0                   0
2     2019-06-23     "Car"      500     0                   800
3     2019-06-11     "Walk"     900     0                   0
4     2019-06-15     "Walk"     200     1                   900
4     2019-06-12     "Walk"     900     1                   900

Ответы [ 3 ]

1 голос
/ 22 июня 2019

Можно попробовать:

library(data.table)

df <- setDT(df)[, Stamp := as.Date(Stamp)][
  , `:=` (mean_score = sapply(Stamp, 
                              function(x) 
                                mean(Score[between(Stamp, x - 7, x - 1)])
  ),
  proportion_walk = sapply(Stamp, 
                           function(x) 
                             round(mean(
                               activity[between(Stamp, x - 7, x - 1)] == 'Walk'
                               ),2)
  )
  ), by = User][
    is.nan(mean_score), `:=` (mean_score = 0, proportion_walk = 0)]

Выход:

   User      Stamp activity Score mean_score proportion_walk
1:    1 2019-06-20      Car  4500    625.000            0.50
2:    1 2019-06-18      Car   600    650.000            1.00
3:    1 2019-06-15     Walk   650      0.000            0.00
4:    1 2019-06-21     Ride   790   1916.667            0.33
5:    2 2019-06-21      Car   800      0.000            0.00
6:    2 2019-06-23      Car   500    800.000            0.00
7:    3 2019-06-11     Walk   900      0.000            0.00
8:    4 2019-06-15     Walk   200    900.000            1.00
9:    4 2019-06-12     Walk   900      0.000            0.00

Для proportion_walk, я полагаю, в вашем выводе есть опечатка, основанная на вашем описании. В противном случае, пожалуйста, перефразируйте; например, 2019-06-20 не может иметь 0,33, поскольку есть 2 дня позади, и один из них - Walk.

0 голосов
/ 22 июня 2019
library("dplyr")
library("purr")
DF %>%
  group_by(User) %>%
  mutate(mean_score = map_dbl(Stamp, 
                              ~mean(Score[(Stamp > . - 7) & (Stamp < .)]))) %>%
  mutate(mean_score =ifelse(is.nan(mean_score), 0, mean_score))

выход

  User Stamp      activity Score mean_score
  <int> <date>     <fct>    <int>      <dbl>
1     1 2019-06-20 Car       4500       625 
2     1 2019-06-18 Car        600       650 
3     1 2019-06-15 Walk       650         0 
4     1 2019-06-21 Ride       790      1917.
5     2 2019-06-21 Car        800         0 
6     2 2019-06-23 Car        500       800 
7     3 2019-06-11 Walk       900         0 
8     4 2019-06-15 Walk       200       900 
9     4 2019-06-12 Walk       900         0 
0 голосов
/ 22 июня 2019

Используя данные в примечании в конце, выполните левое самостоятельное соединение по указанным критериям, взяв среднее значение Score для всех совпадающих строк или 0, если его нет.

library(sqldf)

sqldf("select a.*, 
         coalesce(avg(b.Activity == 'Walk'), 0) as Proportion_Walk, 
         coalesce(avg(b.Score), 0) as Mean
  from DF as a 
  left join DF as b on a.User = b.User and 
                       b.Stamp < a.Stamp and b.Stamp >= a.Stamp - 7
  group by a.rowid")

давая:

  User      Stamp activity Score Proportion_Walk     Mean
1    1 2019-06-20      Car  4500       0.5000000  625.000
2    1 2019-06-18      Car   600       1.0000000  650.000
3    1 2019-06-15     Walk   650       0.0000000    0.000
4    1 2019-06-21     Ride   790       0.3333333 1916.667
5    2 2019-06-21      Car   800       0.0000000    0.000
6    2 2019-06-23      Car   500       0.0000000  800.000
7    3 2019-06-11     Walk   900       0.0000000    0.000
8    4 2019-06-15     Walk   200       1.0000000  900.000
9    4 2019-06-12     Walk   900       0.0000000    0.000

Примечание

Данные в воспроизводимом виде:

Lines <- 'User  Stamp          activity   Score    
1     2019-06-20     "Car"      4500
1     2019-06-18     "Car"      600
1     2019-06-15     "Walk"     650
1     2019-06-21     "Ride"     790
2     2019-06-21     "Car"      800    
2     2019-06-23     "Car"      500
3     2019-06-11     "Walk"     900
4     2019-06-15     "Walk"     200   
4     2019-06-12     "Walk"     900'

DF <- read.table(text = Lines, header = TRUE)
DF$Stamp <- as.Date(DF$Stamp)
...