按属性对行进行分组

时间:2010-12-01 03:40:13

标签: r filter dataframe

我有一个数据框,其中包含有关学生迟到各种课程的数据。每行包含有关已故学生及其班级的数据:班级的日期和时间,班级名称,班级人数,迟到的分钟数以及学生的性别。为了获得所有课程的迟到学生的总百分比,我需要计算行数(已故学生)并将其与上课的学生总数进行比较。

我不能简单地将所有行的类大小相加;这将计算一个特定班级的学生几次,每班一次为每个已故的学生。相反,我需要为每次班级会议计算每个班级大小一次。

实施例

重点:迟到的分钟,课堂名称,出勤的学生,迟到的学生的性别,迟到的分钟。

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 个答案:

答案 0 :(得分:2)

如果我理解你想要什么,这对于plyr包更容易,而不是tapply或因为它理解多变量分组的含义。例如:

ddply(df, .(DATE,CLASS), transform, PERCENT_LATE=length(MINUTES.LATE)/CLASS.SIZE))
这里的长度参数可以是任何列名。 ddply将为DATE和CLASS因子级别的每个组合拆分数据帧。然后,每个迷你数据帧中的行数应该对应于已有多少学生(因为每个已故学生都有一个条目)。这就是长度(任何变量)的来源。将它除以分数的类大小列。

答案 1 :(得分:1)

和数和晚期的不同函数。需要使用“粘贴”策略来创建数据和类名称的唯一组合:

>  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

答案 2 :(得分:1)

编辑:首先通过计算每行基础上的琐碎%%,然后使用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

答案 3 :(得分:1)

继续关注@Gavin的评论:冗余输出,使用摘要:

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