简单求和 if 表达式

Simple sum if expression

这些是我的示例数据:

dt <- data.table(id=c("a","a","a","a","b","b"), monthsinarrears=c(0,1,0,0,1,0), date=c(2013,2014,2015,2016,2014,2015))

table 看起来像这样:

> dt
   id monthsinarrears date
1:  a               0 2013
2:  a               1 2014
3:  a               0 2015
4:  a               0 2016
5:  b               1 2014
6:  b               0 2015

现在我想创建一个名为 "EverinArrears" 的附加列,如果 id 曾经拖欠过(历史上),则分配给“1”,否则分配给“0”。因此我想要获得的输出是:

   id monthsinarrears date EverinArrears
1:  a               0 2013             0
2:  a               1 2014             1
3:  a               0 2015             1
4:  a               0 2016             1
5:  b               1 2014             1
6:  b               0 2015             1

请注意,贷款 ID a 在 2013 年历史上并没有欠款(这发生在 2014 年),所以这就是 EverinArrears 在 2013 年也得到 0 的原因。

您可以使用 ave:

dt$EverinArrears = as.integer(!!ave(dt$monthsinarrears, dt$id, FUN=cumsum))

或者 data.table 的好方法:

dt[, EverinArrears := +(!!cumsum(monthsinarrears)), id][]

您可以执行以下操作(感谢@Roland 提示避免数字 > 1):

dt[, EverinArrears := as.integer(as.logical(cumsum(monthsinarrears))), by=id]

输出:

#   id monthsinarrears date EA
#1:  a               0 2013  0
#2:  a               1 2014  1
#3:  a               0 2015  1
#4:  a               0 2016  1
#5:  b               1 2014  1
#6:  b               0 2015  1

注意:如果你喜欢更短的代码,你也可以做

dt[, EverinArrears := +(!!(cumsum(monthsinarrears))), by=id]

虽然不像"good practice"那样as.integer(as.logical(...))

如@Jaap所述,您还可以这样做:

dt[, EverinArrears := +(cumsum(monthsinarrears) > 0), by = id]

或者,为了更好的练习:

dt[, EverinArrears := as.integer(cumsum(monthsinarrears) > 0), by = id]

正如@Arun 在评论中所建议的,另一种更简单的方式:

dt[, EverinArrears := cummax(monthsinarrears), by = id]

使用包 dplyr:

library(dplyr)

dt %>% 
  group_by(id) %>% 
  arrange(date) %>% 
  mutate(EverinArrears = +as.logical(cumsum(monthsinarrears))) %>% 
  data.table

   id monthsinarrears date EverinArrears
1:  a               0 2013             0
2:  a               1 2014             1
3:  a               0 2015             1
4:  a               0 2016             1
5:  b               1 2014             1
6:  b               0 2015             1

其他人的答案略有不同:

dt[, newcol := cummax(monthsinarrears > 0), by=id]

通过使用 cummax 而不是 cumsum,我们可能会节省一些计算量。


这里有一种方法可以比较第一个欠款月份为正数的条目的位置:

dt[, newcol := {
  z = which(monthsinarrears > 0)
  if (!length(z)) rep(0L,.N)
  else            replace(rep(1L,.N), 1:.N < z[1], 0L)
}, by=id]

不确定这样是否更有效率;这当然在某种程度上取决于数据。