Группировать строки по атрибутам - PullRequest
3 голосов
/ 01 декабря 2010

У меня есть фрейм данных, содержащий данные об опозданиях учеников в разные классы. В каждой строке содержатся данные об опоздавшем ученике и его классе: дата и время занятия, название класса, размер класса, количество опоздавших минут и пол ученика. Чтобы получить общий процент опоздавших учеников для всех классов, мне нужно посчитать количество рядов (поздних учеников) и сравнить его с общим количеством учеников, посещавших занятия.

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

Пример

Ключ: опоздание на минуты, имя класса, посещаемость студентов, пол опоздавшего студента, опоздание на минуты.

11/12/10 Stats 30 M 1
11/12/10 Stats 30 M 1
11/12/10 Stats 30 M 1
11/15/10 Stats 40 F 3
11/15/10 Stats 40 F 3
11/15/10 Stats 40 F 3
11/16/10 Radar 22 M 2
11/16/10 Radar 22 M 2
11/16/10 Radar 22 M 2
11/16/10 Radar 22 M 2
11/16/10 Radar 22 M 2

В этом случае есть три разных класса и 11 опоздавших учеников. Как я могу убедиться в том, что размер класса каждого собрания учитывается только один раз?

Ответы [ 4 ]

2 голосов
/ 01 декабря 2010

Если я правильно понимаю, что вы хотите, это проще сделать с пакетом plyr, чем с tapply или с помощью, потому что он понимает, что означает многомерную группировку.Например: <pre> ddply(df, .(DATE,CLASS), transform, PERCENT_LATE=length(MINUTES.LATE)/CLASS.SIZE)) Аргумент к длине здесь может быть любым из имен столбцов.ddply разделит ваш фрейм данных для каждой комбинации уровней фактора DATE и CLASS.Количество строк в каждом мини-фрейме данных должно соответствовать количеству опоздавших студентов (поскольку для каждого опоздавшего студента есть запись).Вот где приходит длина (любая переменная). Разделите ее на столбец размера класса для дроби.

1 голос
/ 01 декабря 2010

Подписаться на комментарий @ Гэвина по поводу избыточного вывода с использованием суммирования:

df.out <- ddply(x, .(DATE, CLASS), summarise    
    , NLATE = length(c(DATE, CLASS)) / 2
    , SIZE = unique(CLASS.SIZE)
    , PCLATE = 100 * (length(c(DATE, CLASS)) / 2 )/ unique(CLASS.SIZE)
    )
> df.out
      DATE CLASS NLATE SIZE PCLATE
1 11/12/10 Stats     3   30  10.00
2 11/15/10 Stats     3   40   7.50
3 11/16/10 Radar     5   22  22.73
1 голос
/ 01 декабря 2010

Редактировать: Мое решение может быть значительно упрощено, если сначала вычислить тривиальные% с опозданием на для строки , а затем использовать aggregate() для суммирования этих процентов по дате и Класс:

> df2 <- within(df, pcLate <- 100 * (1 / Size)) 
> df2
         Date Class Size Sex MinsLate   pcLate
1  2010-11-12 Stats   30   M        1 3.333333
2  2010-11-12 Stats   30   M        1 3.333333
3  2010-11-12 Stats   30   M        1 3.333333
4  2010-11-15 Stats   40   F        3 2.500000
5  2010-11-15 Stats   40   F        3 2.500000
6  2010-11-15 Stats   40   F        3 2.500000
7  2010-11-16 Radar   22   M        2 4.545455
8  2010-11-16 Radar   22   M        2 4.545455
9  2010-11-16 Radar   22   M        2 4.545455
10 2010-11-16 Radar   22   M        2 4.545455
11 2010-11-16 Radar   22   M        2 4.545455
> with(df2, aggregate(pcLate, by = list(Date = Date, Class = Class), sum))
        Date Class        x
1 2010-11-16 Radar 22.72727
2 2010-11-12 Stats 10.00000
3 2010-11-15 Stats  7.50000

Оригинальный ответ:

Предполагая, что df содержит примеры данных, которые вы предоставляете, мы можем сделать это за пару шагов, используя aggregate()

Во-первых, возьмите число опоздавших в классе:

summ <- with(df, aggregate(MinsLate, by = list(Date = Date, Class = Class),
                           FUN = length))
names(summ)[3] <- "nLate"

Что дает нам эту отправную точку

> head(summ)
        Date Class nLate
1 2010-11-16 Radar     5
2 2010-11-12 Stats     3
3 2010-11-15 Stats     3

Тогда сформируйте классы размеров:

summ$Size <- with(df, aggregate(Size, by = list(Date = Date, Class = Class),
                                FUN = unique)$x)

Что приводит нас сюда:

> head(summ)
        Date Class nLate Size
1 2010-11-16 Radar     5   22
2 2010-11-12 Stats     3   30
3 2010-11-15 Stats     3   40

Затем вычислите процент позднее:

summ <- within(summ, pcLate <- 100 * (nLate / Size))

Что приводит к:

> head(summ)
        Date Class nLate Size   pcLate
1 2010-11-16 Radar     5   22 22.72727
2 2010-11-12 Stats     3   30 10.00000
3 2010-11-15 Stats     3   40  7.50000

Если вам нужно сделать это много, оберните это в функцию

tardiness <- function(df) {
    out <- with(df, aggregate(MinsLate, by = list(Date = Date, Class = Class),
                              FUN = length))
    names(out)[3] <- "nLate"
    out$Size <- with(df, aggregate(Size, by = list(Date = Date, Class = Class),
                                   FUN = unique)$x)
    out <- within(out, pcLate <- 100 * (nLate / Size))
    out
}

это делает все шаги для нас:

> tardiness(df)
        Date Class nLate Size   pcLate
1 2010-11-16 Radar     5   22 22.72727
2 2010-11-12 Stats     3   30 10.00000
3 2010-11-15 Stats     3   40  7.50000
1 голос
/ 01 декабря 2010

Различные функции для суммы номера поздно и размера класса.Необходимо использовать стратегию «вставки» для создания уникальных комбинированных данных и имени класса:

>  sum_late <- tapply( tst$V5, paste(tst$V1, tst$V2, sep="_"), length)
>  csize <- tapply( tst$V3, paste(tst$V1, tst$V2, sep="_"), head,1)
> pct_late <- 100*sum_late/csize
> pct_late
11/12/10_Stats 11/15/10_Stats 11/16/10_Radar 
      10.00000        7.50000       22.72727 

Или с агрегатом:

>  dfcount <- aggregate( tst$V5, list(tst$V1, tst$V2), length)
> dfcount$pct <- 100*aggregate( tst$V5, list(tst$V1, tst$V2), length)$x/aggregate( tst$V3, list(tst$V1, tst$V2), head,1)$x
> dfcount
   Group.1 Group.2 x      pct
1 11/16/10   Radar 5 22.72727
2 11/12/10   Stats 3 10.00000
3 11/15/10   Stats 3  7.50000
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...