R 按属性分组行
我有一个数据框,其中包含关于学生上课迟到的数据。每行包含有关迟到学生及其班级的数据:班级日期和时间、班级名称、班级规模、迟到分钟数以及学生性别。为了得到所有班级迟到学生的总百分比,我需要计算行数(迟到学生),并将其与上课的学生总数进行比较 我不能简单地计算所有行的班级人数;这将对给定班级的学生进行多次统计,每班迟到一名学生统计一次。相反,我只需要为班级的每次会议计算一次班级人数 例子 关键:迟到分钟数、班级名称、出席人数、迟到学生性别、迟到分钟数R 按属性分组行,r,filter,dataframe,R,Filter,Dataframe,我有一个数据框,其中包含关于学生上课迟到的数据。每行包含有关迟到学生及其班级的数据:班级日期和时间、班级名称、班级规模、迟到分钟数以及学生性别。为了得到所有班级迟到学生的总百分比,我需要计算行数(迟到学生),并将其与上课的学生总数进行比较 我不能简单地计算所有行的班级人数;这将对给定班级的学生进行多次统计,每班迟到一名学生统计一次。相反,我只需要为班级的每次会议计算一次班级人数 例子 关键:迟到分钟数、班级名称、出席人数、迟到学生性别、迟到分钟数 11/12/10 Stats 30 M 1 11
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个迟到的学生。如何确保每次班会的班级人数只计算一次?对于迟到总数和班级人数有不同的函数。需要使用“粘贴”策略创建数据和类名的唯一组合:
> 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
>sum\u late csize pct\u late pct\u late
11/12/10_统计11/15/10_统计11/16/10_雷达
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
>dfcount dfcount$pct dfcount
第1组,第2组
1 2010年11月16日雷达5 22.72727
2010年11月12日统计数据310.00000
2010年11月15日统计数据37.50000
如果我正确理解了您的需求,那么使用plyr软件包比使用tapply或by更容易做到这一点,因为它了解多变量分组的含义。例如:
ddply(df,.(日期,类别),转换,延迟百分比=长度(延迟分钟数)/类别大小)
此处length的参数可以是任何列名。ddply将为日期和类别因子级别的每个组合拆分数据帧。每个迷你数据框中的行数应与迟到学生的数量相对应(因为每个迟到学生都有一个条目)。这就是长度(任何变量)的作用。将其除以分数的“类大小”列。编辑:我的解决方案可以简单得多,方法是首先计算每行延迟的微小百分比,然后使用
聚合()
按日期和类对这些百分比求和:
> 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
这给了我们这个起点
> 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)
然后计算延迟的百分比:
summ <- within(summ, pcLate <- 100 * (nLate / Size))
如果您需要经常这样做,请将其包装到函数中
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
}
要继续@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
df.out df.out
日期类NLATE大小PCLATE
2010年11月12日统计数据33010.00
2010年11月15日统计数据3407.50
2010年11月16日雷达5 22.73
注意,第5列(tst$V5
在您的示例中)是每个学生迟到的分钟数,而不是迟到的学生数。因此,您希望在tapply
调用中使用length
而不是sum
。请注意,有11名迟到的学生,您的结果显示有22名迟到的学生。回答不错(+1)。我对plyr套餐不熟悉。是否有一种方法可以使用plyr(即修改您的答案)根据我的答案提供聚合到类/日期级别的输出?我的回答涉及几个步骤,但给出了(IHMO;-)更简洁的输出。您的回答简明扼要,但输出包含冗余的数据复制。[这不是挖苦-如果plyr能做得比我的答案更简单,我真的很感兴趣。]@Gavin-功能摘要可能就是您在这里寻找的。从帮助页面“Summary以一种分析的方式进行转换,除了不向现有数据框添加列之外,它会创建一个新的数据框。”感谢Chase在下面的评论和回答。当我从桌子下面出来时,我必须仔细看看plyr。@Gavin-另一个可能更清楚的选择是在@frannkc的答案周围加上一个unique()
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
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