Применение функций к нескольким спискам

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

Вот небольшое случайное подмножество данных: (Обратите внимание, что это базовое представление - фактический фрейм данных имеет 38 столбцов - я просто удалил большинство неприменимых)

    structure(list(dayofweek = structure(c(4L, 7L, 3L, 7L, 3L, 2L, 
2L, 7L, 3L, 3L, 2L, 7L, 5L, 5L, 2L, 5L, 1L, 3L, 7L, 3L, 4L, 1L, 
3L, 5L, 7L), .Label = c("Friday", "Monday", "Saturday", "Sunday", 
    "Thursday", "Tuesday", "Wednesday"), class = "factor"), timeofday = structure(c(6L, 
4L, 5L, 5L, 2L, 6L, 6L, 5L, 6L, 3L, 6L, 3L, 5L, 4L, 1L, 3L, 5L, 
6L, 5L, 4L, 6L, 6L, 3L, 2L, 5L), .Label = c("After Work", "Early AM", 
     "Evening", "Late AM", "Lunch", "MidAfternoon", "Overnight"), class = "factor"), 
 area = c(6L, 4L, 4L, 5L, 5L, 1L, 4L, 2L, 3L, 2L, 7L, 3L, 
 7L, 5L, 7L, 4L, 1L, 4L, 1L, 4L, 5L, 7L, 1L, 3L, 7L), totsales = c(40, 
 6, 5, 10, 1, 0, 0, 3, 5, 3, 10, 30, 2, 1, 2, 22, 8, 1, 1, 
 5, 11, 20, 0, 1, 5)), .Names = c("dayofweek", "timeofday", 
     "area", "totsales"), class = "data.frame", row.names = c(192278L, 
     140773L, 121051L, 157984L, 154299L, 258034L, 108031L, 43760L, 
     78005L, 42103L, 95603L, 98431L, 30252L, 165303L, 40713L, 108252L, 
     304549L, 137041L, 268473L, 124599L, 161253L, 12897L, 240815L, 
     89439L, 21032L))

Первое, что я делаю, — это пытаюсь получить средние и медианные продажи в каждой области и в каждое время дня. Я хотел бы, чтобы R прошел список каждого и вернул все значения. Я пробовал это:

vallist<-list(a= c("Early AM", "Late AM", "Lunch", "MidAfternoon", "After Work", 
         "Evening", "Overnight"),
          b= c(1,2,3,4,5,6,7))

sapply(vallist[['b']], function(x)
    mapply(function(a,b) mean(data$totsales[which(data$timeofday==a & data$area==b)]),
          vallist[['a']], vallist[['b']])
 )

Но он применяет среднее значение только к каждому сегменту времени дня в области 1, а не к каждому сегменту времени дня в областях 1-7. Итак, мои результаты выглядят так:

                  [,1]      [,2]      [,3]      [,4]      [,5]      [,6]      [,7]
Early AM      9.192847  9.192847  9.192847  9.192847  9.192847  9.192847  9.192847
Late AM       8.020678  8.020678  8.020678  8.020678  8.020678  8.020678  8.020678
Lunch        10.096277 10.096277 10.096277 10.096277 10.096277 10.096277 10.096277
MidAfternoon 11.503961 11.503961 11.503961 11.503961 11.503961 11.503961 11.503961
After Work    8.206124  8.206124  8.206124  8.206124  8.206124  8.206124  8.206124
Evening      11.457599 11.457599 11.457599 11.457599 11.457599 11.457599 11.457599
Overnight    11.415667 11.415667 11.415667 11.415667 11.415667 11.415667 11.415667

которые являются правильными ответами для области 1, но вы можете видеть, что они являются одинаковыми значениями для каждой области. Как заставить R применить функцию к нескольким спискам и вернуть все комбинации значений?

Следующими шагами будет применение медианы и оценка на районном уровне и в разные дни недели, но я предполагаю, что одна и та же идея применима ко всем различным комбинациям.


person datahappy    schedule 03.03.2014    source источник
comment
Вы просто ищете aggregate? Может что-то вроде aggregate(totsales ~ timeofday + area, data, mean)?   -  person A5C1D2H2I1M1N2O1R2T1    schedule 03.03.2014
comment
Да, это определенно работает. У меня есть тенденция делать вещи намного сложнее, чем нужно в R ... Я думаю, это приходит, когда я новичок в этом. Спасибо! Однако для дальнейшего использования мне все же было бы интересно узнать, почему приведенный выше код не будет читать список.   -  person datahappy    schedule 03.03.2014
comment
@AnandaMahto, если вы правильно рассчитаете время, вы должны получить 50 тысяч представителей по 50-тысячному [r] вопросу на SO. Это должно стоить как минимум 10 тысяч бонусных репутаций.   -  person BrodieG    schedule 03.03.2014
comment
@datahappy, измените vallist[['b']] на x в своем mapply, и тогда вы получите примерно тот же результат, что и я (примерно потому, что вам также нужен na.rm).   -  person BrodieG    schedule 03.03.2014


Ответы (2)


Преобразование моего комментария в ответ....

Похоже, вас может заинтересовать aggregate (хотя в R существует много способов агрегирования данных).

out <- aggregate(totsales ~ timeofday + area, data, mean)
out
#       timeofday area totsales
# 1       Evening    1      0.0
# 2         Lunch    1      4.5
# 3  MidAfternoon    1      0.0
# 4       Evening    2      3.0
# 5         Lunch    2      3.0
# 6      Early AM    3      1.0
# 7       Evening    3     30.0
# 8  MidAfternoon    3      5.0
# 9       Evening    4     22.0
# 10      Late AM    4      5.5
# 11        Lunch    4      5.0
# 12 MidAfternoon    4      0.5
# 13     Early AM    5      1.0
# 14      Late AM    5      1.0
# 15        Lunch    5     10.0
# 16 MidAfternoon    5     11.0
# 17 MidAfternoon    6     40.0
# 18   After Work    7      2.0
# 19        Lunch    7      3.5
# 20 MidAfternoon    7     15.0

Если вы хотите перейти оттуда к широкому формату, вы можете использовать reshape (например: reshape(out, direction = "wide", idvar="timeofday", timevar="area")).

person A5C1D2H2I1M1N2O1R2T1    schedule 03.03.2014

В этом конкретном случае вы можете воспроизвести свой результат с помощью:

library(reshape2)
dcast(data[-1], timeofday ~ area, fun.aggregate=mean, fill=0)

который производит:

     timeofday   1 2  3    4  5  6    7
1   After Work 0.0 0  0  0.0  0  0  2.0
2     Early AM 0.0 0  1  0.0  1  0  0.0
3      Evening 0.0 3 30 22.0  0  0  0.0
4      Late AM 0.0 0  0  5.5  1  0  0.0
5        Lunch 4.5 3  0  5.0 10  0  3.5
6 MidAfternoon 0.0 0  5  0.5 11 40 15.0

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

person BrodieG    schedule 03.03.2014
comment
Это так, спасибо. Я знаю, что для этого это не нужно, но есть идеи, почему приведенный выше код применил только первое значение в списке «b»? Что нужно изменить, чтобы он циклически проходил через значения 1-7 в списке «b», как это было со списком «a»? - person datahappy; 03.03.2014
comment
@datahappy, см. мой свежий комментарий к вашему вопросу. - person BrodieG; 03.03.2014
comment
+1. Был ли мой другой план, если бы они ответили утвердительно о aggregate. - person A5C1D2H2I1M1N2O1R2T1; 03.03.2014