【问题标题】:While loop with conditions using data.table使用 data.table 进行条件循环
【发布时间】:2018-06-18 12:11:10
【问题描述】:

我不熟悉 R 中的循环,并且有一个相对简单的数据集要处理。我的示例数据集包含时间戳 - time,手机 ID:id,以及手机电池电量:level 我的目标是产生一个输出,该输出采用电池随时间下降的速度,同时考虑到充电周期。可以识别循环的开始,其中下一个记录的级别高于前一个。换句话说,虽然level lag(level),循环应该继续,但只要level > lag(level),循环应该重新开始

> test
                   time id level
 1: 2017-12-25 14:10:03  1    81
 2: 2017-12-25 14:20:03  1    81
 3: 2017-12-25 14:30:04  1    81
 4: 2017-12-25 14:40:04  1    73
 5: 2017-12-25 14:50:04  1    70
 6: 2017-12-25 15:00:03  1    70
 7: 2017-12-25 15:10:04  1    65
 8: 2017-12-25 15:20:04  1    62
 9: 2017-12-25 15:30:04  1    61
10: 2017-12-25 15:40:04  1    60
11: 2017-12-25 15:50:03  1    60
12: 2017-12-25 16:00:04  1    60
13: 2017-12-25 16:10:04  1    95
14: 2017-12-25 16:20:03  1    95
15: 2017-12-25 16:30:04  1    95
16: 2017-12-25 16:40:04  1    94
17: 2017-12-25 16:50:04  1    92
18: 2017-12-25 17:00:03  1    90
19: 2017-12-25 17:10:04  1    81
20: 2017-12-25 17:20:03  1    79
21: 2017-12-25 17:30:03  2   100
22: 2017-12-25 17:40:03  2   100
23: 2017-12-25 17:50:03  2   100
24: 2017-12-25 18:00:03  2    90
25: 2017-12-25 18:10:03  2    85
26: 2017-12-25 18:20:03  2    75
27: 2017-12-25 18:30:04  2    65
28: 2017-12-25 18:40:03  2    54
29: 2017-12-25 18:50:03  2    32
30: 2017-12-25 19:00:03  2    11
31: 2017-12-25 19:10:04  2    92
32: 2017-12-25 19:20:04  2    92
33: 2017-12-25 19:30:03  2    91
34: 2017-12-25 19:40:04  2    90
35: 2017-12-25 19:50:04  2    90
36: 2017-12-25 20:00:03  2    81
37: 2017-12-25 20:10:03  2    79
38: 2017-12-25 20:20:04  2    99
39: 2017-12-25 20:30:04  2    96
40: 2017-12-25 20:40:03  2    96

在上面的示例数据集中,预期输出如下所示,其中difftime = 循环开始和停止的时间差,diffcharge = 循环开始和停止的电池电量差, 和 rate = diffcharge/difftime

> outcome
  id               start            recharge difftime diffcharge      rate
1  1 2017-12-25 14:10:03 2017-12-25 16:00:04  110.0167          21 0.1908801
2  1 2017-12-25 16:10:04 2017-12-25 17:20:03  69.98333          16 0.2286259
3  2 2017-12-25 17:30:03 2017-12-25 19:00:03        90          89 0.9888889
4  2 2017-12-25 19:10:04 2017-12-25 20:10:03  59.98333          13 0.2167269
5  2 2017-12-25 20:20:04 2017-12-25 20:40:03  19.98333           3 0.1501251

到目前为止,我只是尝试创建一个连接每个循环的级别的 while 循环,之后我可以使用以下代码获取最小值、最大值等,但这不会产生预期的输出。

raw_data <- test
unique_id = unique(test$id)

for (id in unique_id)
{
  onePhone <- raw_data[ which(raw_data$id == id), ]
  onePhone <- onePhone[order(onePhone$time, decreasing = FALSE),]
  cycle <- NULL

  if(nrow(onePhone) >=2 ){
    for(i in 2:nrow(onePhone)) {
      while(onePhone[i-1,"level"] >= onePhone[i,"level"])
      { 
        i = i+1
        cycle <- c(z, onePhone[i,"level"])
      } 
      print(cycle)
    }
  }
}

任何关于如何使用 data.tabledplyr 或简单的 while 循环的建议将不胜感激。这是示例数据:

> dput(test)
structure(list(time = structure(c(1514229003.91212, 1514229603.61297, 
1514230204.14629, 1514230804.81938, 1514231404.36784, 1514232003.73393, 
1514232604.17933, 1514233204.00143, 1514233804.68755, 1514234404.15599, 
1514235003.99419, 1514235604.68204, 1514236204.18828, 1514236803.66526, 
1514237404.0434, 1514238004.40609, 1514238604.02003, 1514239203.42238, 
1514239804.19495, 1514240403.15927, 1514241003.87092, 1514241603.93167, 
1514242203.77223, 1514242803.66758, 1514243403.33705, 1514244003.25017, 
1514244604.05367, 1514245203.7921, 1514245803.2651, 1514246403.63888, 
1514247004.02684, 1514247604.04009, 1514248203.99929, 1514248804.07401, 
1514249404.11004, 1514250003.74613, 1514250603.88962, 1514251204.19115, 
1514251804.06932, 1514252403.94181), class = c("POSIXct", "POSIXt"
), tzone = "EST"), id = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
2, 2, 2, 2, 2, 2, 2), level = c(81, 81, 81, 73, 70, 70, 65, 62, 
61, 60, 60, 60, 95, 95, 95, 94, 92, 90, 81, 79, 100, 100, 100, 
90, 85, 75, 65, 54, 32, 11, 92, 92, 91, 90, 90, 81, 79, 99, 96, 
96)), .Names = c("time", "id", "level"), class = c("data.table", 
"data.frame"), row.names = c(NA, -40L), .internal.selfref = <pointer: 0x102010778>)

【问题讨论】:

    标签: r while-loop dplyr data.table


    【解决方案1】:

    假设您从 csv 文件中读取测试:

    test<-read.csv("test.csv",stringsAsFactors = F)
    test$DateTime<-paste(test$Date,test$time,by=" ")
    test$Charge<-FALSE
    test$Charge[1:((nrow(test)-1))]<-diff(test$level)>0
    
    start=test[which(test$Charge)+1,]$DateTime
    start<-c(test$DateTime[1],start)
    start<-dmy_hms(start)
    
    recharge<-filter(test,Charge)$DateTime
    recharge<-c(recharge,tail(test$DateTime,1))
    recharge<-dmy_hms(recharge)
    
    difftime=recharge-start
    
    startLevel=test[which(test$Charge)+1,]$level
    startLevel=c(test$level[1],startLevel)
    endLevel=filter(test,Charge)$level
    endLevel=c(endLevel,tail(test$level,1))
    
    diffcharge=startLevel-endLevel
    
    rate=diffcharge/as.numeric(difftime)
    
    id=filter(test,Charge)$id
    id=c(id,tail(test$id,1))
    
    outcome=data.frame(id=id,start=start,recharge=recharge,difftime=difftime,diffcharge=diffcharge,rate=rate)
    

    【讨论】:

      【解决方案2】:

      第一步使用@Hugh方法,然后得到最终结果:

      test[, cycle := cumsum(level > shift(level, fill = first(level))), by = "id"]
      x <- test[, .(start = min(time),
                    recharge = max(time),
                    diffcharge = max(level) - min(level)),
                by = .(id, cycle)]
      x[, difftime := as.numeric(recharge - start)]
      x[, rate :=  diffcharge / difftime]
      x
      #    id cycle               start            recharge diffcharge  difftime      rate
      # 1:  1     0 2017-12-25 14:10:03 2017-12-25 16:00:04         21 110.01283 0.1908868
      # 2:  1     1 2017-12-25 16:10:04 2017-12-25 17:20:03         16  69.98285 0.2286274
      # 3:  2     0 2017-12-25 17:30:03 2017-12-25 19:00:03         89  89.99613 0.9889314
      # 4:  2     1 2017-12-25 19:10:04 2017-12-25 20:10:03         13  59.99771 0.2166749
      # 5:  2     2 2017-12-25 20:20:04 2017-12-25 20:40:03          3  19.99584 0.1500312
      

      【讨论】:

        【解决方案3】:

        如果testdata.table,您可以使用cumsumshift。 (shift 是来自data.table 的函数;它与lag 相同。)

        test[, cycle := cumsum(level > shift(level, fill = first(level))), by = "id"]
        

        【讨论】:

        • 谢谢,但是这如何考虑到手机的id?例如,一个id 有可能在第 80 级结束,然后下一个id 可能从第 79 级开始,但这仍然会被视为同一个循环,即使这是不正确的,这是否会使感觉?
        • 是的。 fill = first(level) 在这种情况下如何发挥作用?
        • 尝试省略 fill 参数; cycle 列将是 NAs 的列。所以你需要为每个组提供一个合理的第一个值。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-20
        • 2014-03-02
        • 1970-01-01
        • 1970-01-01
        • 2021-06-25
        • 2020-07-01
        • 1970-01-01
        相关资源
        最近更新 更多