我是新的实证研究法律教授和R.我正在研究法官的工作量(如他/她在30天内完成的案件数量)或他/她的案件积压(因为案件开放与案件在同一范围内关闭的比例)影响案件结果。一些样本数据:
# first generate a vector of dates and repeat it 4 times
beg.date <- rep(seq.Date(as.Date("2008-01-01"),as.Date("2013-12-31"),by="day"),4)
length(beg.date) # 8768
length(beg.date)/4 # 2192 dates (6 years)
# generate a vector of judges of same length
x <- factor(LETTERS[1:4]); judge <- rep(x, each=2192)
# cbind them as df
data <- cbind.data.frame(judge, beg.date)
# create end date exactly 30 days later for each case
data$end.date <- as.Date(data$beg.date + 30)
#sort by beg.date and add caseid variable
data <- data[order(data$beg.date),]; data$caseid <- 1:8768
#reorder columns
data <- data[c(4,1,2,3)]
# reorder rows by judge and by end dates
data <- data[order(data$judge, data$end.date),]
这是数据的样子:
caseid judge beg.date end.date
1 1 A 2008-01-01 2008-01-31
2 5 A 2008-01-02 2008-02-01
3 9 A 2008-01-03 2008-02-02
4 13 A 2008-01-04 2008-02-03
5 17 A 2008-01-05 2008-02-04
6 21 A 2008-01-06 2008-02-05
所以我想计算一下裁判判决当天法官的30天积压和完成率。我已经弄清楚如何创建日期间隔(窗口)并确定在该窗口内开始或结束的案例数。并且我能够在法官使用笨重for loop.
a <- data
comprate <- numeric()
ratio <- numeric()
for (j in c("A","B","C","D")){
x=a[a$judge==j,]
for(i in 1:nrow(x)){
y <- new_interval((x$end.date[i]-ddays(30)),x$end.date[i])
x$comprate[i] <- length(x$end.date[x$end.date %within% y==T])
x$ratio[i] <- length(x$beg.date[x$beg.date %within% y==T])/x$comprate[i]
}
comprate <- append(comprate, x$comprate, after=length(comprate))
ratio <- append(ratio, x$ratio, after=length(ratio))
}
a$comprate <- comprate
a$ratio <- ratio
这适用于小样本数据集,但我的项目数据有超过600万个观察(案例)。我知道有一种方法可以通过ddply
或dplyr
执行此操作,但它只是超出我的范围。有人可以帮助我吗?
非常感谢。肯
一些跟进问题:
感谢@MrFlick提供了有用的答案。 让我看看我是否理解(或请帮助我理解)解决方案的工作原理:
dt[, comprate:=sapply(end.date, function(i)
sum(between(as.numeric(i)-as.numeric(end.date),0,30))), by=judge]
在此代码块中:
1 comprate变量是通过应用sapply(etc.)
表达式by=judge
创建的
2 sapply
将function(i)
应用于end.date
的每个元素,并返回简化结果
3 function(i)
将end.date
的第一个元素作为输入,sum
返回逻辑向量between(etc.)
的逻辑真值的总和。
我好,我想到这里,但在此之后,我对between
如何运作以及确切地包含和评估哪些值感到困惑。那么as.numeric(i)-as.numeric(end.date)
到底在做什么呢?我得到as.numeric
部分 - 它只是提取表示哨兵日期之后天数的整数。
所以&#39; as.numeric(i)&#39;正在提取i-th
的{{1}}元素的整数值?
那么end.date
在做什么?
答案 0 :(得分:4)
我不会感觉太糟糕,这些移动的窗口问题有点棘手。
考虑到数据的大小,我建议您使用data.table
库。此库允许您索引数据,以便查找更快。我们在这里
library(data.table)
dt<-setDT(data)
setkey(dt, judge, end.date)
dt[, comprate:=sapply(end.date, function(i)
sum(between(as.numeric(i)-as.numeric(end.date),0,30))), by=judge]
setkey(dt, judge, beg.date)
dt[, newcase:=sapply(end.date, function(i)
sum(between(as.numeric(i)-as.numeric(beg.date),0,30))), by=judge]
dt[, ratio:= newcase/comprate]
a<-as.data.frame(dt)
因此我们使用setDT()
将data
转换为data.table对象。然后我们设置键,为表添加索引。接下来,我们使用特殊的data.table语法添加新列。在这里,对于每个法官,我们计算过去30天内的结束日数。您似乎之前使用过lubridate
。这里,由于Date值存储为自哨兵日期以来的天数,我只需转换为数字并自行进行减法。然后我重新排序并计算新案件的数量。我做了一个额外的步骤来计算比率。然后我将东西转换回data.frame(但您也可以将它们保存为data.table)。
因此,在此示例数据上,它运行得更快,并提供相同的结果。这确实意味着可能会为新包提供新的语法,但您应该获得更快的结果。
进一步解释
因此,让我们使用简单的向量
x<-c(1,3,6,9,10,15)
我们可以将这些作为数字形式的日期。当我们做的时候
sapply(x, function(i) i-x)
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] 0 2 5 8 9 14
# [2,] -2 0 3 6 7 12
# [3,] -5 -3 0 3 4 9
# [4,] -8 -6 -3 0 1 6
# [5,] -9 -7 -4 -1 0 5
# [6,] -14 -12 -9 -6 -5 0
我们正在做的是一次获取x
的每个值(i
)并找到x
中每个其他值的差异。每个x
值都会生成上面的一列。现在我可以添加两者之间以查看差异是否介于0和10之间。
sapply(x, function(i) between(i-x, 1, 10))
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] TRUE TRUE TRUE TRUE TRUE FALSE
# [2,] FALSE TRUE TRUE TRUE TRUE FALSE
# [3,] FALSE FALSE TRUE TRUE TRUE TRUE
# [4,] FALSE FALSE FALSE TRUE TRUE TRUE
# [5,] FALSE FALSE FALSE FALSE TRUE TRUE
# [6,] FALSE FALSE FALSE FALSE FALSE TRUE
因此我们使用between
(来自data.table
包)将结果限制为过去的特定窗口。现在,我们不是为每个x
值返回一列,而是取两个值之间的sum()
,这会将所有TRUE值变为1,将FALSE变为0
sapply(x, function(i) sum(between(i-x, 0, 10)))
# [1] 1 2 3 4 5 4