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

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

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只是解码的时间,所以不相关,我们看到date列中有很多NULL值。 你也可以看到,从29日到30日之间的时间变化,时间确实有差距。 我想用正确的datereplaceNULL。 在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&ok] < – rep(是,length.out =长度(ans))[test&ok]:replace长度为零另外:警告消息:在rep(是,length.out = length ans)):'x'是NULL,所以结果将是NULL

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

  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])) 

这个循环有效,但是速度很慢。 我的testingdataframe是80K行,循环花费了大约10分钟,但我将处理数百万行的dataframe。 我想知道是否有更快的方法来做到这一点在河。

希望这是有道理的,本质上代码是说,如果一天是空的(NA时,在R),如果时间跟随从行之前,然后使用上一行的最后一个date。 如果时间改变,请select下一个4行中的下一个date。

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

你可以尝试这样的事情。 我将所有帮助列添加到data.frame来说明发生了什么。 当然,你也可以使用base 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)) 

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

 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`))