【问题标题】:Create New Column Based on Previous Row and Multiple Conditions in R基于R中的前一行和多个条件创建新列
【发布时间】:2015-03-31 16:20:40
【问题描述】:

我有以下示例数据框:

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 

我想遍历每一行并根据 从发布到现在已经有多少天了。

要记住的几件事:
- 新产品发布 = 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 - 如果上面的行 > 0 ,则使用上面的行的值 + 1
- 所有这些都是产品独有的。

提前谢谢你!

更新/澄清:

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

例如:

    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的旗帜

【问题讨论】:

    标签: r row conditional plyr


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      我的一条评论是,您要求'逐行迭代'的解决方案。这不是R 做事方式。 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】:

        您可以尝试使用base R中的ave

         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
        

        【讨论】:

        • 这适用于 OP 中提供的示例。但是,如果每个产品有多个版本会怎样?
        • @DMC 我没有检查每个产品的多个版本。感谢您的评论
        • @DMC 感谢您的提问。在我的 df 中,相同的产品可以多次发布,但只能在不同的日子发布。例如,产品 A 可以在 2012-01-04 和 2012-05-01 再次发布。我只需要能够列出自最新发布以来已经过了多少天。因此,如果我们查看日期 2012-05-02,我想要 2,而不是 120(基于第一个发布日期)。
        • @lelgohary 你能否用一个模仿数据集和预期输出的例子来更新你的帖子。
        • @lelgohary 我认为该解决方案在新条件下仍然有效。比如x$release[7] &lt;-1然后试试上面的代码
        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-04-20
          • 1970-01-01
          • 2020-07-26
          • 1970-01-01
          • 2021-11-05
          • 2016-04-22
          • 1970-01-01
          相关资源
          最近更新 更多