如何根据 R 中的预定义阈值比较所有行的值后进行标记?
How to flag after comparing values over all rows based on a pre-defined threshold in R?
df <- cbind(c(1,1,1,1,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5), c(6,12,18,24,30,3,9,21,6,12,18,24,30,36,6,12,18,24,30,36,12,24,36,48), c(0.4,1.5,2.7,1.6,0.4,1.3,3.1,3.6,0.5,2.6,3.7,1.8,0.9,0.3,0.7,1.6,1.3,2.8,1.9,1.8,2.0,1.0,3.0,0.8))
colnames(df) <- c("ID","time","value")
我有上面代码给出的数据集。我想知道对于每个ID,从lowest/starting时间开始,该值是否与上涨前的最低值相比至少反弹了2,然后跌破或等于反弹前的最低值价值。我想将至少增加2的时间标记为反弹时间。
因此,例如,在上面的数据集中,对于 ID 1,在开始上升之前的时间 6 的最低值为 0.4。在时间 18,它达到了预定义的阈值 2,然后在时间 30,它下降到等于预反弹最低值的值。所以我想标记ID 1有反弹时间18作为反弹时间。
另一方面,对于 ID 2,虽然它至少上升了 2 个值 (1.3-->3.6),但从未回到低于或等于 1.3 的值
对于ID 3,它再次符合跳出标准(0.5-->2.6-->3.7-->1.8-->0.9-->0.3)。所以我想将 ID 2 标记为有反弹,并将第 18 个月标记为反弹时间。
对于 ID 4,虽然从 0.7-->1.6-->1.3-->2.8(在时间 24)至少上升了 2,但是,后来它从未下降到 0.7 以下反弹前的最低值。所以它不能被标记为有退回。
对于 ID 5,值为 2-->1-->3-->0.8,因此反弹至少 2 (1-->3),然后跌至以下值最低预反弹值 (0.8 <1.0)。所以这个ID应该被标记为有跳出并且跳出时间应该是时间36.
请帮助我进行动态计算,并尽可能解释代码,以便我理解这个概念。提前谢谢你。
考虑一下:
func <- function(tm, val, threshold = 2) {
mtx <- outer(val, val, `-`)
mtx[upper.tri(mtx)] <- NA
if (all(mtx < threshold, na.rm = TRUE)) return(tm[NA][1])
ij <- which.max(mtx) # counts through the matrix, along columns
i <- (ij-1) %/% length(val) + 1
j <- (ij-1) %% length(val) + 1
if (i < length(val) && any(val[-seq_len(i)] <= val[i])) {
return(tm[j])
} else {
return(tm[NA][i])
}
}
df <- data.frame(
ID = c(1,1,1,1,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5),
time = c(6,12,18,24,30,3,9,21,6,12,18,24,30,36,6,12,18,24,30,36,12,24,36,48),
value = c(0.4,1.5,2.7,1.6,0.4,1.3,3.1,3.6,0.5,2.6,3.7,1.8,0.9,0.3,0.7,1.6,1.3,2.8,1.9,1.8,2.0,1.0,3.0,0.8)
)
我使用 which.max
以及 %/%
和 %%
运算符,因为通常我不喜欢 which(val == max(val), arr.ind = TRUE)
;虽然后者有效,但它也依赖于浮点数的相等性测试,这对于极值可能会有问题。参见 Why are these numbers not equal?, Is floating point math broken?, and https://en.wikipedia.org/wiki/IEEE_754。如果您不喜欢这种安全防护,请随意调整函数以使用 which(.)
代替。
我经历 tm[NA][1]
麻烦的原因是 return 值与您输入的 time
变量完全相同 class
。例如,如果您在矢量中更改的值与 class 不同,dplyr
在许多情况下会发出警告或出错。 这个警告或错误很好,因为 R 的本机(和静默)值强制转换可能有问题。例如,Sys.time()
是 class POSIXt
但 NA
不是。但是Sys.time()[NA]
是classPOSIXt
。同样,integer
和 numeric
都有不同类型的 NA
。也许这有点过度防御,但使用 tm[NA][1]
可确保输出始终与输入 time
.
相同 class
dplyr
library(dplyr)
# # A tibble: 5 x 2
# ID time
# * <dbl> <dbl>
# 1 1 18
# 2 2 NA
# 3 3 18
# 4 4 NA
# 5 5 36
data.table
library(data.table)
DF <- as.data.table(df)
DF[, .(time = func(time, value)), by = .(ID)]
# ID time
# <num> <num>
# 1: 1 18
# 2: 2 NA
# 3: 3 18
# 4: 4 NA
# 5: 5 36
df <- cbind(c(1,1,1,1,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5), c(6,12,18,24,30,3,9,21,6,12,18,24,30,36,6,12,18,24,30,36,12,24,36,48), c(0.4,1.5,2.7,1.6,0.4,1.3,3.1,3.6,0.5,2.6,3.7,1.8,0.9,0.3,0.7,1.6,1.3,2.8,1.9,1.8,2.0,1.0,3.0,0.8))
colnames(df) <- c("ID","time","value")
我有上面代码给出的数据集。我想知道对于每个ID,从lowest/starting时间开始,该值是否与上涨前的最低值相比至少反弹了2,然后跌破或等于反弹前的最低值价值。我想将至少增加2的时间标记为反弹时间。
因此,例如,在上面的数据集中,对于 ID 1,在开始上升之前的时间 6 的最低值为 0.4。在时间 18,它达到了预定义的阈值 2,然后在时间 30,它下降到等于预反弹最低值的值。所以我想标记ID 1有反弹时间18作为反弹时间。
另一方面,对于 ID 2,虽然它至少上升了 2 个值 (1.3-->3.6),但从未回到低于或等于 1.3 的值
对于ID 3,它再次符合跳出标准(0.5-->2.6-->3.7-->1.8-->0.9-->0.3)。所以我想将 ID 2 标记为有反弹,并将第 18 个月标记为反弹时间。
对于 ID 4,虽然从 0.7-->1.6-->1.3-->2.8(在时间 24)至少上升了 2,但是,后来它从未下降到 0.7 以下反弹前的最低值。所以它不能被标记为有退回。
对于 ID 5,值为 2-->1-->3-->0.8,因此反弹至少 2 (1-->3),然后跌至以下值最低预反弹值 (0.8 <1.0)。所以这个ID应该被标记为有跳出并且跳出时间应该是时间36.
请帮助我进行动态计算,并尽可能解释代码,以便我理解这个概念。提前谢谢你。
考虑一下:
func <- function(tm, val, threshold = 2) {
mtx <- outer(val, val, `-`)
mtx[upper.tri(mtx)] <- NA
if (all(mtx < threshold, na.rm = TRUE)) return(tm[NA][1])
ij <- which.max(mtx) # counts through the matrix, along columns
i <- (ij-1) %/% length(val) + 1
j <- (ij-1) %% length(val) + 1
if (i < length(val) && any(val[-seq_len(i)] <= val[i])) {
return(tm[j])
} else {
return(tm[NA][i])
}
}
df <- data.frame(
ID = c(1,1,1,1,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5),
time = c(6,12,18,24,30,3,9,21,6,12,18,24,30,36,6,12,18,24,30,36,12,24,36,48),
value = c(0.4,1.5,2.7,1.6,0.4,1.3,3.1,3.6,0.5,2.6,3.7,1.8,0.9,0.3,0.7,1.6,1.3,2.8,1.9,1.8,2.0,1.0,3.0,0.8)
)
我使用 which.max
以及 %/%
和 %%
运算符,因为通常我不喜欢 which(val == max(val), arr.ind = TRUE)
;虽然后者有效,但它也依赖于浮点数的相等性测试,这对于极值可能会有问题。参见 Why are these numbers not equal?, Is floating point math broken?, and https://en.wikipedia.org/wiki/IEEE_754。如果您不喜欢这种安全防护,请随意调整函数以使用 which(.)
代替。
我经历 tm[NA][1]
麻烦的原因是 return 值与您输入的 time
变量完全相同 class
。例如,如果您在矢量中更改的值与 class 不同,dplyr
在许多情况下会发出警告或出错。 这个警告或错误很好,因为 R 的本机(和静默)值强制转换可能有问题。例如,Sys.time()
是 class POSIXt
但 NA
不是。但是Sys.time()[NA]
是classPOSIXt
。同样,integer
和 numeric
都有不同类型的 NA
。也许这有点过度防御,但使用 tm[NA][1]
可确保输出始终与输入 time
.
class
dplyr
library(dplyr)
# # A tibble: 5 x 2
# ID time
# * <dbl> <dbl>
# 1 1 18
# 2 2 NA
# 3 3 18
# 4 4 NA
# 5 5 36
data.table
library(data.table)
DF <- as.data.table(df)
DF[, .(time = func(time, value)), by = .(ID)]
# ID time
# <num> <num>
# 1: 1 18
# 2: 2 NA
# 3: 3 18
# 4: 4 NA
# 5: 5 36