按ID分组数据集,然后创建一个新列,从当前行和后续行中减去不同的列

时间:2017-02-27 15:43:23

标签: r

我发现了像this这样的类似问题,但不完全一样。这是我的问题,我有以下数据集:

SELECT 
  {} ON 0
 ,[Customer].[Customer Geography].[Country] ON 1
FROM 
(
  SELECT 
    Head
    (
      Order
      (
        NonEmpty
        (
            [Customer].[Customer Geography].[Country]
          * 
            [Date].[Calendar].[Calendar Year]
         ,[Measures].[Internet Sales Amount]
        )
       ,[Measures].[Internet Sales Amount]
       ,bdesc
      )
     ,50
    ) ON 0
  FROM [Adventure Works]
);

我想创建以下列:> ds id begin end 1 1 2017-01-15 2017-01-17 2 1 2017-01-01 2017-01-03 3 2 2017-02-01 2017-02-28 4 4 2017-04-11 2017-05-11 5 3 2017-02-05 2017-02-10 6 4 2017-03-10 2017-03-20 7 1 2017-01-30 2017-02-03 8 3 2017-02-28 2017-03-09 9 4 2017-02-26 2017-03-05 ,为具有相同check值的每一行验证以下条件:

id

否则为ds[i,]$begin - ds[i-1,]$end < 30 => 1 # for each row i 。当它是该组的第一个元素时,则没有先前的信息,因此在这种情况下,新列0的值也将始终为零。

与我看到的其他问题(通过:checkave解决)的区别在于,我需要进行涉及后续行但不是同一列的计算。

以下是代码:

定义数据集

dplyr

对信息进行排序(我们需要使用for循环来获取当前解决方案)

id <- c("1", "1", "2", "4", "3", "4", "1", "3")
begin <- c("20170115", "20170101", "20170201",
    "20170411",
    "20170205", "20170310",
    "20170130", "20170228"
    )

end <- c("20170117", "20170103", "20170228",
    "20170511",
    "20170210", "20170320",
    "20170203", "20170309"
    )

ds <- data.frame(id = id, begin = as.Date(begin, "%Y%m%d"), end = as.Date(end, "%Y%m%d"))

现在使用for循环来分配控制变量:idx = order(rank(ds$id), ds$begin, decreasing = FALSE) ds <- ds[idx,]

check

最后预期的输出:

ds$check <- numeric(nrow(ds))
ds$check <- NA_integer_

nrep <- -1
for (i in 1:nrow(ds)) {
    rowi <- ds[i,]
    if (nrep == -1) {# Setting the first element of ds
        end.prev <- rowi$end
        id.prev <- rowi$id
        ds[i,]$check <- 0
        nrep = 1
    } else {
        id.current <- rowi$id
        if(id.prev == id.current) {
            ds[i,]$check <- ifelse(rowi$begin - end.prev < 30, 1, 0)
        } else {
             ds[i,]$check <- 0
        }
        end.prev <- rowi$end
        id.prev <- id.current
    }
}

感谢任何提示。

2 个答案:

答案 0 :(得分:1)

使用dplyr,使用lag可以轻松实现:

ds %>% 
  group_by(id) %>% 
  arrange(id, begin) %>% 
  mutate(check = c(0, as.numeric(begin - lag(end) < 30)[-1]))

给出:

Source: local data frame [8 x 4]
Groups: id [4]

      id      begin        end check
  <fctr>     <date>     <date> <dbl>
1      1 2017-01-01 2017-01-03     0
2      1 2017-01-15 2017-01-17     1
3      1 2017-01-30 2017-02-03     1
4      2 2017-02-01 2017-02-28     0
5      3 2017-02-05 2017-02-10     0
6      3 2017-02-28 2017-03-09     1
7      4 2017-03-10 2017-03-20     0
8      4 2017-04-11 2017-05-11     1

说明:

  • 首先我们group_by,因此计算由id完成。
  • 我们arrange确保我们从最早的日期开始。
  • 对于所有check s,第一个值为0
  • ,其他值只是当前begin减去前一个end是否小于30.我们使用as.numeric将逻辑转换为数字。

另见:vignette('window-functions')

注意:我认为每组的第一个值可以简单地保留在NA,因为它确实是未知的或未定义的,这将简化为:

ds %>% 
  group_by(id) %>%
  mutate(check = as.numeric(begin - lag(end, order_by = begin) < 30))

答案 1 :(得分:1)

使用data.table:

setDT(ds)[,New:=as.numeric(begin-shift(end,fill=0)<30),id]

使用dplyr:

ds%>%group_by(id)%>%mutate(new=as.numeric(begin-lag(end,default=0)<30))%>%arrange(id)