![](/img/trans.png)
[英]R Dplyr; calculating difference between two columns from previous row but putting result in next row without for loop
[英]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.