简单求和 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]
不确定这样是否更有效率;这当然在某种程度上取决于数据。
这些是我的示例数据:
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]
不确定这样是否更有效率;这当然在某种程度上取决于数据。