我有一些已解码的数据,如下所示:
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,但似乎没有一个工作得很好,所以像上面这样的逻辑规则是最好的。循环速度很慢。
答案 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`))