R:如果前一行包含某个值,则更新该行



我有一组来自RFID阅读器的数据,该阅读器记录了个别鸟类何时造访巢穴。然而,木板的错误意味着它们经常会停止扫描一整天,所以我不知道这只鸟是否去过鸟巢。数据集包含最近一次检测的时间以及上次检测的日期和时间的记录。我想在上次已知访问前的任何一天董事会休息时,将"上次访问"栏更新为"未知"。

我的最小数据集如下:

date <- seq.POSIXt(ISOdate(2018, 7, 6), ISOdate(2018,7,16), by = "day")
status <- c("ON","ON","OFF","ON","ON", "ON", "ON", "ON", "ON","ON", "ON")
firstdet <- c("2018-07-07 03:34:58 BST", NA, NA , NA ,               
NA  , "2018-07-12 01:30:37 BST","2018-07-13 03:15:55 BST", "2018-07-14 00:01:39 BST",
"2018-07-14 23:46:47 BST" ,"2018-07-15 23:28:16 BST" ,"2018-07-16 23:57:00 BST")
prevVisit <- c(NA, NA, NA,  NA, NA ,"2018-07-07 03:34:58 BST", "2018-07-12 01:30:37 BST",
"2018-07-13 03:15:55 BST", "2018-07-14 00:01:39 BST",
"2018-07-14 23:46:47 BST" ,"2018-07-15 23:28:16 BST")
mydf <- data.frame(cbind(as.character(date), status, firstdet, prevVisit))
colnames(mydf)[1] <- "date"

看起来像这样:

date       status                firstdet               prevVisit
1  2018-07-06 12:00:00     ON 2018-07-07 03:34:58 BST                    <NA>
2  2018-07-07 12:00:00     ON                    <NA>                    <NA>
3  2018-07-08 12:00:00    OFF                    <NA>                    <NA>
4  2018-07-09 12:00:00     ON                    <NA>                    <NA>
5  2018-07-10 12:00:00     ON                    <NA>                    <NA>
6  2018-07-11 12:00:00     ON 2018-07-12 01:30:37 BST 2018-07-07 03:34:58 BST
7  2018-07-12 12:00:00     ON 2018-07-13 03:15:55 BST 2018-07-12 01:30:37 BST
8  2018-07-13 12:00:00     ON 2018-07-14 00:01:39 BST 2018-07-13 03:15:55 BST
9  2018-07-14 12:00:00     ON 2018-07-14 23:46:47 BST 2018-07-14 00:01:39 BST
10 2018-07-15 12:00:00     ON 2018-07-15 23:28:16 BST 2018-07-14 23:46:47 BST
11 2018-07-16 12:00:00     ON 2018-07-16 23:57:00 BST 2018-07-15 23:28:16 BST

N.B.鸟类在晚上22:00到03:00之间造访,因此日期栏指的是夜晚开始的那一天;这就是为什么firstdet列的日期并不总是与日期匹配的原因

我希望"prevVisit"列更新为"unknown",只要当前检测和最后一个已知检测之间的任何一行包含状态"OFF",因为我不确定这只鸟最后一次访问是什么时候。例如:

date     status                firstdet               prevVisit
1  2018-07-06 12:00:00     ON 2018-07-07 03:34:58 BST                    <NA>
2  2018-07-07 12:00:00     ON                    <NA>                    <NA>
3  2018-07-08 12:00:00    OFF                    <NA>                    <NA>
4  2018-07-09 12:00:00     ON                    <NA>                    <NA>
5  2018-07-10 12:00:00     ON                    <NA>                    <NA>
6  2018-07-11 12:00:00     ON 2018-07-12 01:30:37 BST UNKNOWN
7  2018-07-12 12:00:00     ON 2018-07-13 03:15:55 BST 2018-07-12 01:30:37 BST
8  2018-07-13 12:00:00     ON 2018-07-14 00:01:39 BST 2018-07-13 03:15:55 BST
9  2018-07-14 12:00:00     ON 2018-07-14 23:46:47 BST 2018-07-14 00:01:39 BST
10 2018-07-15 12:00:00     ON 2018-07-15 23:28:16 BST 2018-07-14 23:46:47 BST
11 2018-07-16 12:00:00     ON 2018-07-16 23:57:00 BST 2018-07-15 23:28:16 BST

我遇到了很多问题,问如何根据前几行更改行值,但这些问题似乎都不以前几行的可变范围为条件,所以它们并没有解决我的问题。

我得到的最接近的是一个ifelse语句,我希望它能在状态列的前几行搜索"OFF",但这不起作用:

mydf$prevVisit <- ifelse("OFF" %in% mydf$status[which(mydf$date > mydf$prevVisit & mydf$date < mydf$firstdet)], "unknown", mydf$prevVisit)

我认为没有一种优雅/可向量化的方法来实现这一点,ifelse肯定不会做你想做的事。这里有一个可能对你有用的快速破解方法。

我稍微修改了你的数据,以进行另一次测试(我不会在间隙中错误地指定"未知"(:

x <- read.table(stringsAsFactors=FALSE, header=TRUE, text="
date status                firstdet               prevVisit
2018-07-06_12:00:00     ON 2018-07-07_03:34:58_BST                      NA
2018-07-07_12:00:00     ON                      NA                      NA
2018-07-08_12:00:00    OFF                      NA                      NA
2018-07-09_12:00:00     ON                      NA                      NA
2018-07-10_12:00:00     ON                      NA                      NA
2018-07-11_12:00:00     ON 2018-07-12_01:30:37_BST 2018-07-07_03:34:58_BST
2018-07-12_12:00:00     ON 2018-07-13_03:15:55_BST 2018-07-12_01:30:37_BST
2018-07-13_12:00:00     ON 2018-07-14_00:01:39_BST 2018-07-13_03:15:55_BST
2018-07-14_12:00:00     ON                      NA 2018-07-14_00:01:39_BST
2018-07-15_12:00:00     ON 2018-07-15_23:28:16_BST 2018-07-14_00:01:39_BST
2018-07-16_12:00:00     ON 2018-07-16_23:57:00_BST 2018-07-15_23:28:16_BST")
x[] <- lapply(x, function(a) gsub("_", " ", a))
x$unknown <- c(FALSE, sapply(seq_len(nrow(x))[-1], function(i) {
prev <- tail(which(!is.na(x$firstdet[seq_len(i-1)])), n = 1)
!is.na(x$firstdet[i]) && (!length(prev) || any(x$status[prev:i] == "OFF"))
}))
x$prevVisit <- ifelse(is.na(x$firstdet) | x$unknown, NA, lag(zoo::na.locf(x$firstdet)))
x
#                   date status                firstdet               prevVisit unknown
# 1  2018-07-06 12:00:00     ON 2018-07-07 03:34:58 BST                    <NA>   FALSE
# 2  2018-07-07 12:00:00     ON                    <NA>                    <NA>   FALSE
# 3  2018-07-08 12:00:00    OFF                    <NA>                    <NA>   FALSE
# 4  2018-07-09 12:00:00     ON                    <NA>                    <NA>   FALSE
# 5  2018-07-10 12:00:00     ON                    <NA>                    <NA>   FALSE
# 6  2018-07-11 12:00:00     ON 2018-07-12 01:30:37 BST                    <NA>    TRUE
# 7  2018-07-12 12:00:00     ON 2018-07-13 03:15:55 BST 2018-07-12 01:30:37 BST   FALSE
# 8  2018-07-13 12:00:00     ON 2018-07-14 00:01:39 BST 2018-07-13 03:15:55 BST   FALSE
# 9  2018-07-14 12:00:00     ON                    <NA>                    <NA>   FALSE
# 10 2018-07-15 12:00:00     ON 2018-07-15 23:28:16 BST 2018-07-14 00:01:39 BST   FALSE
# 11 2018-07-16 12:00:00     ON 2018-07-16 23:57:00 BST 2018-07-15 23:28:16 BST   FALSE

(修改后的数据显示,行10显示了行8的firstdet,尽管行9中存在间隙。(

我假设您打算在某一点上确定这些实际日期,所以我将其保存在一个单独的列中(因为"UNKNOWN"不能包含在POSIXt列中(。如果你真的想把它放在那里,你也可以做

x$prevVisit <- ifelse(x$unknown, "UNKNOWN", x$prevVisit)

最新更新