将excel转换为R,从前一行计算,慢速循环

时间:2017-07-03 11:15:47

标签: r excel performance loops

我有一些已解码的数据,如下所示:

datetime    date - day  date - month  date - year  gmt hrs  gmt minutes  gmt seconds  val1  val2  val3
37:00.9         NULL        NULL          15          0        30          54         1      1     0
37:01.9          29          9           NULL   0   30  55  1   1   0
37:02.9         NULL        NULL         NULL   0   30  56  1   1   0
37:03.9         NULL        NULL         NULL   0   30  57  1   1   0
37:04.9         NULL        NULL          15    0   30  58  1   1   0
37:05.9          29          9           NULL   0   30  59  1   1   0
37:06.9         NULL        NULL         NULL   0   31  0   1   1   0
37:07.9         NULL        NULL         NULL   0   31  1   1   1   0
37:08.9         NULL        NULL          15    0   31  2   1   1   0
37:09.9          29          9           NULL   0   31  3   1   1   0
37:10.9         NULL        NULL         NULL   0   31  4   1   1   0
37:11.9         NULL        NULL         NULL   0   31  5   1   1   0
37:12.9         NULL        NULL          15    6   7   40  1   1   0
37:13.9          30          9           NULL   6   7   41  1   1   0
37:14.9         NULL        NULL         NULL   6   7   42  1   1   0
37:15.9         NULL        NULL         NULL   6   7   43  1   1   0
37:16.9         NULL        NULL          15    6   7   44  1   1   0

datetime只是解码时的时间,因此不相关,我们看到日期列中有很多NULL值。您还可以看到时间确实存在间隙,如第29天和第30天之间的gmt更改所示。我想用正确的日期替换NULL。白天,在excel中我写了以下内容(在K3中):

=IF(AND(ISNUMBER(B3)=FALSE,OR(G3=G2+1,F3=F2+1,E3=E2+1,G3=G2,G3=G2+2)),K2,IF(ISNUMBER(B3)=FALSE,MAX(B4,B5,B6),B3))

注意有时秒等于之前的行,有时差异是2秒,这就是OR也涵盖这些的原因。

这很好用,但是文件太大而不能很好地处理excel。所以我将这些文件加载​​到R中的数据表中并编写了以下等效代码(不包括最大部分,但在此失败后添加了):

test2$day =ifelse(is.na(test2$`DATE - DAY`)==T &
 (test2$`GMT SECONDS`==shift(test2$`GMT SECONDS`)+1 |test2$`GMT SECONDS`== shift(test2$`GMT SECONDS`) | test2$`GMT SECONDS`==shift(test2$`GMT SECONDS`)+2
  | test2$`GMT MINUTES`== shift(test2$`GMT MINUTES`) +1 
   | test2$`GMT HRS`==shift(test2$`GMT HRS`) +1  ),
  shift(test2$day), ifelse(is.na(test2$`DATE - DAY`)==T, shift(test2$`DATE - DAY`, type = 'lead'),test2$`DATE - DAY`))
  

ans [test& amp; ok]< - rep(yes,length.out = length(ans))[test&好] :     替换的长度为零   另外:警告信息:   在rep(是的,length.out = length(ans)):     'x'为NULL,因此结果为NULL

上面的失败,所以我创建了以下循环:

 if(nrow(test3)>1) for(i in 2:nrow(test3)) test3$day[i]= ifelse(is.na(test3$`DATE - DAY`[i])==T &
          (test3$`GMT SECONDS`[i]==(test3$`GMT SECONDS`[i-1])+1 |test3$`GMT SECONDS`[i]== (test3$`GMT SECONDS`[i-1]) | test3$`GMT SECONDS`[i]==(test3$`GMT SECONDS`[i-1])+2
          | test3$`GMT MINUTES`[i]== (test3$`GMT MINUTES`[i-1]) +1 
           | test3$`GMT HRS`[i]==(test3$`GMT HRS`[i-1]) +1 ),
          test3$day[i-1], ifelse(is.na(test3$`DATE - DAY`[i])==T, max(test3$`DATE - DAY`[i+1],test3$`DATE - DAY`[i+2],test3$`DATE - DAY`[i+3], na.rm=T),test3$`DATE - DAY`[i]))

这个循环有效,但速度很慢。我的测试数据帧是80K行,循环大约需要10分钟,但我将处理几百万行的数据帧。我想知道在R中是否有更快的方法可以做到这一点。

希望这是有道理的,基本上代码是说如果日期为NULL(在R中为NA),如果时间从前一行开始,则使用上一行中的最后一个日期。如果时间发生变化,请从接下来的4行中选择下一个日期。

我无法改变解码器,我尝试了一些插补方法,包括使用平均值,回归和kNN,但似乎没有一个工作得很好,所以像上面这样的逻辑规则是最好的。循环速度很慢。

2 个答案:

答案 0 :(得分:1)

你可以尝试这样的事情。我在data.frame中添加了所有帮助列,以说明发生了什么。当然你也可以使用基数R而不是dplyr着作。我决定> 2分钟的差异定义了新的一天。 (V2=date - day; V6=gmt minutes

library(tidyverse)
library(zoo)

d %>% 
  mutate(V2=ifelse(V2=="NULL",NA, V2),
         day=na.locf(V2, na.rm=F)) %>% 
  mutate(diff=c(0,diff(V6)),
         day2=dplyr::lead(day),
         day_final=ifelse(abs(diff)>2, day2, day))

答案 1 :(得分:0)

想想我写了一些处理我遇到的所有问题的逻辑:

test2$time = strptime(sprintf("%s:%s:%s", test$`GMT HRS`, test$`GMT MINUTES`, test$`GMT SECONDS`), "%H:%M:%S")

test2$time = as.POSIXct(test2$time)

test2$day = ifelse(is.na(test2$`DATE - DAY`)==T & abs(test2$time - shift(test2$time)) < 3, 
                       ifelse(is.na(shift(test2$`DATE - DAY`))==F,shift(test2$`DATE - DAY`), ifelse(is.na(shift(test2$`DATE - DAY`, n=2))==F, shift(test2$`DATE - DAY`, n=2), shift(test2$`DATE - DAY`, n=3))),
                       ifelse(is.na(test2$`DATE - DAY`) == T, 
                      ifelse(is.na(shift(test2$`DATE - DAY`, type="lead"))==F,shift(test2$`DATE - DAY`, type="lead"), ifelse(is.na(shift(test2$`DATE - DAY`, n=2, type="lead"))==F, 
                    shift(test2$`DATE - DAY`, n=2, type="lead"), shift(test2$`DATE - DAY`, n=3, type="lead"))),
                              test2$`DATE - DAY`))