繁体   English   中英

将Excel转换为R,从上一行开始计算,缓慢循环

[英]Convert excel to R, calculating from previous row, slow loop

我有一些已解码的数据,看起来如下:

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之间的格林尼治标准时间变化所示。 我想用正确的日期替换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中的数据表中,并编写了以下等效代码(不介绍max部分,但在失败后添加了此代码):

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(yes,length.out = length(ans))[test&ok]中的错误:替换的长度为零另外:警告消息:In 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,但似乎都无法正常工作,因此最好使用上述逻辑规则。 循环很慢。

您可以尝试这样。 我将所有辅助列添加到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))

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM