2015-10-05 44 views
10

这些都是我的样本数据:简单总结,如果表达

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)) 

表看起来是这样的:

> 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年

+2

您的结果与您提供的数据不符! –

+0

为什么?我只是想根据我提供的第一个表格和我提供的条件来添加这个额外的列EverinArrears。 –

+0

看看你的初始dt,和你写的东西......这完全不同,即使你的问题是可以理解的) –

回答

14

你可以做以下的(感谢@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] 

虽然不是像“良好做法”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] 
+0

这不起作用是有超过1个月inininrerears每个ID ... –

+0

@ColonelBeauvel权利,良好的捕获... – Cath

+2

只需包裹'as.logical'。 – Roland

3
得到一个0零以及

您可以使用ave

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

或者与data.table的好办法:

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

不要在data.table中使用'ave'。这是不必要的缓慢。 – Roland

+0

因为'!! cumsum()+ 0L'不能用data.table首先使用''ave'解决方案:) –

+1

使用'as.logical'和'as.integer'是更好的做法(更清晰的代码和边缘更快)。 – Roland

2

使用包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 
5

下面是对别人的答案稍有不同:

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] 

不知道这可能是任何更有效;它在一定程度上肯定取决于数据。