基于R中的上一行和多个条件创建新列

时间:2015-02-01 17:29:12

标签: r row conditional plyr

我有以下示例数据框:

x
date          product   release    
2012-01-01    A         0                   
2012-01-02    A         0                   
2012-01-03    A         0                   
2012-01-04    A         1 
2012-01-05    A         0     
2012-01-06    A         0   
2012-01-07    A         0   
2012-01-08    A         0   
2012-01-09    A         0   
2012-01-10    A         0   
2012-01-11    A         0   
2012-01-12    A         0 
2012-01-01    Z         0                   
2012-01-02    Z         1                   
2012-01-03    Z         0                   
2012-01-04    Z         0   
2012-01-05    Z         0     
2012-01-06    Z         0   
2012-01-07    Z         0 

我希望遍历每一行并生成基于的dayssince列 自发布以来已经过了多少天。

要记住的几件事:
  - 新产品发布= 1没有产品发布= 0
  - 输出需要对日期产品

是唯一的

所需的输出是:

   x
    date      product   release    dayssince  
    2012-01-01    A         0          0         
    2012-01-02    A         0          0        
    2012-01-03    A         0          0        
    2012-01-04    A         1          1
    2012-01-05    A         0          2
    2012-01-06    A         0          3
    2012-01-07    A         0          4
    2012-01-08    A         0          5
    2012-01-09    A         0          6
    2012-01-10    A         0          7
    2012-01-11    A         0          8
    2012-01-12    A         0          9
    2012-01-01    Z         0          0        
    2012-01-02    Z         1          1        
    2012-01-03    Z         0          2        
    2012-01-04    Z         0          3
    2012-01-05    Z         0          4
    2012-01-06    Z         0          5
    2012-01-07    Z         0          6

我已经尝试了从ifelse语句和for循环到ddply的所有想法。

我能够解决问题的最简单方法是从概念上做到以下几点:

x$dayssince <- ifelse(x$release > 0, 1, 0)

- 然后检查每一天的每一行   - 如果dayssince == 1,那么1   - 如果是dayssince&lt; 1,然后检查上面的行   - 如果上面的行是&gt; 0,然后使用上面的行+ 1的值   - 这一切对产品而言都是独一无二的。

提前谢谢!

UPDATE /澄清:

对于每年多次发布的相同产品,我希望获得自上次发布以来的天数

例如:

    x
    date      product   release    dayssince  
    2012-01-01    A         0          0         
    2012-01-02    A         0          0        
    2012-01-03    A         0          0        
    2012-01-04    A         1          1
    2012-01-05    A         0          2
    2012-01-06    A         0          3
    2012-01-07    A         0          4
    2012-01-08    A         0          5
    2012-01-09    A         0          6
    2012-01-10    A         1          1
    2012-01-11    A         0          2
    2012-01-12    A         0          3
    2012-01-13    A         0          4
    2012-01-14    A         0          5

...等 感谢国旗@DMC

4 个答案:

答案 0 :(得分:2)

您可以尝试使用ave

中的base R
 x$dayssince <-  with(x, ave(release, cumsum(release), product, 
                          FUN=function(y) cumsum(cumsum(y))))

或使用data.table

library(data.table)
setDT(x)[,dayssince:=cumsum(cumsum(release)) ,
                   .(product,cumsum(release))][]
 #  1: 2012-01-01       A       0         0
 #  2: 2012-01-02       A       0         0
 #  3: 2012-01-03       A       0         0
 #  4: 2012-01-04       A       1         1
 #  5: 2012-01-05       A       0         2
 #  6: 2012-01-06       A       0         3
 #  7: 2012-01-07       A       0         4
 #  8: 2012-01-08       A       0         5
 #  9: 2012-01-09       A       0         6
 # 10: 2012-01-10       A       1         1
 # 11: 2012-01-11       A       0         2
 # 12: 2012-01-12       A       0         3
 # 13: 2012-01-01       Z       0         0
 # 14: 2012-01-02       Z       1         1
 # 15: 2012-01-03       Z       0         2
 # 16: 2012-01-04       Z       0         3
 # 17: 2012-01-05       Z       0         4
 # 18: 2012-01-06       Z       0         5
 # 19: 2012-01-07       Z       0         6

答案 1 :(得分:1)

解决方案使用dplyr并创建一个中间变量release_num

library(dplyr)

x %>%
  group_by(product) %>%
  mutate(release_num = cumsum(release)) %>%
  group_by(product, release_num) %>%
  mutate(dayssince = cumsum(cumsum(release)))

答案 2 :(得分:0)

我的一个评论是,您要求一个逐行迭代的解决方案。&#39; 这不是 R < / strong>做事的方式。 R 适用于矢量 - 通常是列矢量。因此,任何解决方案都需要一些解决方法。您可以切换到 SAS 之类的内容,它可以明确地按行进行操作。

我的解决方案使用plyr库,但它没有矢量化。因此它可能比某些替代品慢。

# given vector of release dates and output vector, produce "dayssince"
ds <- function(rel.dts, x) {
  n <- length(rel.dts)
  x[1:rel.dts[1]] <- 0
  for (i in 2:n) {
    x[(rel.dts[i-1]):(rel.dts[i]-1)] <- 0:(rel.dts[i]-rel.dts[i-1]-1)
  }
  x[rel.dts[n]:length(x)] <- 0:(length(x)-rel.dts[n])
  return(x)
}

# use ds() on a given product
ds.prod <- function(dat) {
  dat <- dat[order(dat$date, decreasing=FALSE),]
  rel.dts <- which(dat$release ==1)
  ds <- get("ds")
  dat$daysince <- ds(rel.dts, x=vector("integer", length= nrow(dat)))
  return(dat)
}

# split by product and run
require(plyr)
dat <- ddply(dat, .var="product", .fun= ds.prod)

答案 3 :(得分:0)

如果您的数据来自数据库,则可能更容易创建一个带有计算列的视图,用于计算自发布以来的天数。

我目前太累了,无法发布任何SQL代码,但如果这是一种你会考虑的方法,我明天可以提供一些示例代码。