如何在按行操作时应用能够“看到”前面结果的函数?
这出现了很多,但是我目前的问题需要学生运行总计,如果总数没有达到5则重置。
示例数据:
> df
row Student Absent Consecutive.Absences
1 A 0 0
2 A 1 1
3 A 1 2
4 A 0 0 <- resets to zero if under 5
5 A 0 0
6 A 1 1
7 A 1 2
8 A 1 3
9 B 1 1 <- starts over for new factor (Student)
10 B 1 2
11 B 0 0
12 B 1 1
13 B 1 2
14 B 1 3
15 B 1 4
16 B 0 0
17 B 1 1
18 B 1 2
19 B 1 3
20 B 1 4
21 B 1 5
22 B 0 5 <- gets locked at 5
23 B 0 5
24 B 1 6
25 B 1 7
我尝试用巨大的移位矢量矩阵来做这件事。
我尝试使用apply系列函数执行此操作,其中一半不执行任何操作,另一半执行16 GB内存并使计算机崩溃。
我尝试过直接循环,需要4个多小时(这是一个大数据集)
困扰我的是Excel中的这种容易程度。通常R在速度和可写性方面围绕Excel运行,这让我相信我在这里缺少一些基本的东西。
忘记这个更具挑战性(“5点锁定”)的功能,我甚至无法获得重置的cumsum。没有我能想到的因素组合这样的ave:
Consecutive.Absences = ave(Absent, ..., cumsum)
显然,对学生进行分组只会给出总累积缺席 - 它会“记住”孩子因缺席而导致缺席,因为大肆分裂和重组。
正如我所说,我不知道如何在R中做的核心是:
如何在按行操作时应用能够“看到”前面结果的函数?
在Excel中很容易:
C3 = IF($A3=$A2,$B3+$C2,$B3)*$B3
此excel功能在没有5-absence锁定的情况下显示,以便于阅读。
一旦我弄清楚如何应用一个查看R中相同函数的先前结果的函数,我将能够弄清楚其余部分。
提前感谢您的帮助 - 这对我的很多应用程序非常有用!
真正, 萨姆
更新:
感谢大家关于如何识别学生连续缺席5次的想法!
但是,在STUDENTS表的数据库中这很容易。我需要知道的是学生在考勤记录中连续缺席的次数,例如“我们在计算其他汇总统计时是否计算这个特定的出勤记录?”
答案 0 :(得分:7)
如果您希望在使用前一个元素的值时将一个函数应用于向量中的每个元素,您可能需要检出“Reduce”,并将accumulate参数设置为True
以下是一个例子:
##define your function that takes two parameters
##these are the 'previous' and the 'current' elements
runSum <- function(sum, x){
res = 0
if (x == 1){
res = sum + 1
}
else if (x == 0 & sum < 5){
res = 0
}
else{
res = sum
}
res
}
#lets look at the absent values from subject B
x = c(1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1)
Reduce(x=x, f=runSum, accumulate=T)
# [1] 1 2 0 1 2 3 4 0 1 2 3 4 5 5 5 6 7
答案 1 :(得分:1)
通过一次或多次5次运动来识别学生相当容易:
tapply(dfrm$Absent, dfrm$Student, function(x) rle(x)$value[rle(x)$length >=5] )
$A
integer(0)
$B
[1] 1
在结果中查找“1”的任何值:
tapply(dfrm$Absent, dfrm$Student, function(x) 1 %in% rle(x)$value[rle(x)$length >=5] )
A B
FALSE TRUE
我也努力通过Reduce解决方案(但是优先考虑@kithpradhan):
ave(dfrm$Absent, dfrm$Student,
FUN= function(XX)
Reduce(function(x,y) if( x[1] >= 5){ y+x[1]
} else{ x[1]*y+y } , #Resets to 0 if y=0
XX, accumulate=TRUE)
)
#[1] 0 1 2 0 0 1 2 3 1 2 0 1 2 3 4 0 1 2 3 4 5 5 5 6 7
答案 2 :(得分:0)
作为记录,您还可以创建自己的Reduce
派生类,该派生类接收f
和x
,并将f(x)
应用于其输出,直到x == f(x)
或达到maxiter
:
ireduce = function(f, x, maxiter = 50){
i = 1
while(!identical(f(x), x) & i <= maxiter) {x = f(x); i = i+1}; x
}