2016-02-16 3 views
0

Это вопрос по Cumulative Mean with Grouping and Lag и Grouped moving average in r.Совокупное среднее с условиями

Я ищу, чтобы создать кумулятивное среднее поле с отставанием от единицы, которая группируется по нескольким переменным, но вычисляет только среднее значение по определенным критериям. Итак, для примера ниже, S-AVG дает только совокупное среднее значение для S и наоборот для O-AVG и J-AVG. Я уверен, что это возможно с помощью ave и cumsum, но я не уверен, как это сделать.

Здесь требуемый выход:

Player Goals **S-AVG** **O-AVG** **J-AVG** 
S  5       
S  2  5 
S  7  3.5   
O  3      
O  9      3 
O  6      6  
O  3      3 
S  7  4.66   
O  1      5.25 
S  7  5.25   
S  3  5.6   
Q  8      4.4    
S  3  5.16     
O  4      5   
P  1      4.857 
S  9  4.857   
S  4  5.375   
Z  6      4.375   
S  3  5.22   
O  8      4.55    
S  3  5     
O  4      4.9  
O  1      4.81  
S  9  4.81     
S  4  5.16     
O  6      4.5  
J  6      

Здесь входные данные для г

Player <- c('S','S','S','O','O','O','O','S','O','S','S','O','S','O','O','S','S','O','S','O','S','O','O','S','S','O','J') 
Goals <- c(5,2,7,3,9,6,3,7,1,7,3,8,3,4,1,9,4,6,3,8,3,4,1,9,4,6,6) 
data.frame(Player, Goals) 

Любая помощь оценена.

+0

Я думаю, что это может быть более простым, если вы просто подмножаетесь на 3 кадра данных, вычисляете совокупное среднее, а затем рекомбинируете. – giraffehere

+0

Не можете ли вы изменить данные в этом формате от предыдущего anwser? – mtoto

+0

Кроме того, может помочь таяние и литье. Может быть, хорошо смотреть. – giraffehere

ответ

3

DF2 Пусть это кадр данных, рассчитанный в my answer к prior post ссылается на вопрос, т.е. фрейма данных, имеющий AVG столбца. Он также воспроизводится в примечании в конце этого ответа.

Если мы только что один или небольшое фиксированное число игроков, которых мы могли бы сделать это, выписав в AVG.* столбец для каждого игрока (показан для одного игрока):

transform(DF2, AVG.S = ifelse(Player == "S", AVG, NA)) 

но более общий подход следующим образом. Установите levs на уровень фактора Player или если вы не хотите, чтобы все игроки, то levs должен быть установлен в вектор символа только тех игроков, которых вы хотите. Затем используйте sapply для конструирования логической матрицы и преобразования ее в матрицу из 1s и NA, которая затем скаляр умножается на AVG.

Решение имеет ряд желательных функций - оно не перезаписывает его вход (который был бы подвержен ошибкам), и он избегает ненужной повторной квалификации (оба благодаря transform), он использует весь объектный подход, а не циклы и subscriptip, он использует существующий код, избегая дублирования (используя результат предыдущего решения, что этот вопрос является продолжением) и является кратким - две строки кода. Он не использует пакеты.

(Также отметим, что в качестве альтернативы sapply(...) можно заменить model.matrix(~ Player + 0) в этом случае имена столбцов будет немного отличаться.)

levs <- levels(DF2$Player) 
transform(DF2, Avg = ifelse(sapply(levs, `==`, Player), 1, NA) * AVG) 

дает:

Player Goals  AVG Avg.J Avg.O Avg.S 
1  S  5  NA NA  NA  NA 
2  S  2 5.000000 NA  NA 5.000000 
3  S  7 3.500000 NA  NA 3.500000 
4  O  3  NA NA  NA  NA 
5  O  9 3.000000 NA 3.000000  NA 
6  O  6 6.000000 NA 6.000000  NA 
7  O  3 6.000000 NA 6.000000  NA 
8  S  7 4.666667 NA  NA 4.666667 
9  O  1 5.250000 NA 5.250000  NA 
10  S  7 5.250000 NA  NA 5.250000 
11  S  3 5.600000 NA  NA 5.600000 
12  O  8 4.400000 NA 4.400000  NA 
13  S  3 5.166667 NA  NA 5.166667 
14  O  4 5.000000 NA 5.000000  NA 
15  O  1 4.857143 NA 4.857143  NA 
16  S  9 4.857143 NA  NA 4.857143 
17  S  4 5.375000 NA  NA 5.375000 
18  O  6 4.375000 NA 4.375000  NA 
19  S  3 5.222222 NA  NA 5.222222 
20  O  8 4.555556 NA 4.555556  NA 
21  S  3 5.000000 NA  NA 5.000000 
22  O  4 4.900000 NA 4.900000  NA 
23  O  1 4.818182 NA 4.818182  NA 
24  S  9 4.818182 NA  NA 4.818182 
25  S  4 5.166667 NA  NA 5.166667 
26  O  6 4.500000 NA 4.500000  NA 
27  J  6  NA NA  NA  NA 

Примечание: Эта использовался как ввод выше:

DF2 <- structure(list(Player = structure(c(3L, 3L, 3L, 2L, 2L, 2L, 2L, 
3L, 2L, 3L, 3L, 2L, 3L, 2L, 2L, 3L, 3L, 2L, 3L, 2L, 3L, 2L, 2L, 
3L, 3L, 2L, 1L), .Label = c("J", "O", "S"), class = "factor"), 
    Goals = c(5, 2, 7, 3, 9, 6, 3, 7, 1, 7, 3, 8, 3, 4, 1, 9, 
    4, 6, 3, 8, 3, 4, 1, 9, 4, 6, 6), AVG = c(NA, 5, 3.5, NA, 
    3, 6, 6, 4.66666666666667, 5.25, 5.25, 5.6, 4.4, 5.16666666666667, 
    5, 4.85714285714286, 4.85714285714286, 5.375, 4.375, 5.22222222222222, 
    4.55555555555556, 5, 4.9, 4.81818181818182, 4.81818181818182, 
    5.16666666666667, 4.5, NA)), .Names = c("Player", "Goals", 
"AVG"), row.names = c(NA, -27L), class = "data.frame") 
+0

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

+0

Что касается трансформации, это не «личный стиль». Это почти буквально предупреждение на странице справки. То же самое для подмножества. Они могут облегчить чтение кода при использовании в интерактивном режиме. Если вы обертываете функцию вокруг нее, я имею в виду '? Transform' для рекомендации основной группы R. –

+0

Вы когда-нибудь задавались вопросом, почему существует 'mutate' и почему Хэдли не просто использует' transform', что делает то же самое? И почему он предоставил аргумент '.dots' -quote- для работы с нестандартной оценкой -unquote-? Вы можете назвать это мнением, но я не единственный, у кого это есть. Собственно, это мнение является одной из причин существования пакета 'dplyr'. –

0

Другой подход - просто использовать индексы. Сначала сделайте функцию cummean (что тривиально ...):

cummean <- function(x){ 
    cumsum(x)/seq_along(x) 
} 

Затем рассчитать кумулятивные средства и сохранить ее в списке (simplify = FALSE):

avgs <- with(mydf, 
      tapply(Goals,Player,cummean, 
        simplify = FALSE)) 

Наконец, создать переменные, основанные на именах игроков, удобно добавлены в качестве имен в списке, возвращаемой tapply. Я специально использую цикл for, чтобы избежать необходимости перестраивать полный кадр данных каждый раз. Используя индексы, я могу пополнить кадр данных более эффективным способом и все еще иметь такое отставание. :

for(i in names(avgs)){ 
    theavg <- avgs[[i]] 
    mydf[[i]][mydf$Player == i] <- c(NA, theavg[-length(theavg)]) 
} 
Смежные вопросы