【问题标题】:Find indexes where vector crosses boundaries查找向量跨越边界的索引
【发布时间】:2023-03-03 02:26:01
【问题描述】:

我正在编写一些代码来绘制 CUSUM 图。我不能使用 R 必须绘制这些图的(少数)包,因为我的边界会随着时间的推移定期更新(即在 1 个图中边界会发生变化)。我目前遇到的问题是如何提取向量第一次跨越边界的时间点。边界是数据框中的变量。

此外,当向量移向零(最佳)线时,我对何时越界不感兴趣。所以我猜有两个步骤,找到向量穿过每个边界的所有点,然后选择我最感兴趣的那些。

以下是一个边界发生变化的虚构示例:

set.seed(1235)
df <- data.frame(Run=c(1:21), y = cumsum(c(0, rnorm(20, 0, 5))))
df$zero <- 0
df$LL1  <- -3
df$LL2  <- -8
df$UL1  <-  6
df$UL2  <- 14

df[c("zero","LL1", "LL2", "UL1", "UL2")][c(11:21),] <- df[c("zero","LL1", "LL2", "UL1", "UL2")][c(11:21),]+14

数据如下:

> df
   Run         y zero LL1 LL2 UL1 UL2
1    1  0.000000    0  -3  -8   6  14
2    2 -3.489940    0  -3  -8   6  14
3    3 -9.914209    0  -3  -8   6  14
4    4 -4.964414    0  -3  -8   6  14
5    5 -4.405535    0  -3  -8   6  14
6    6 -3.834496    0  -3  -8   6  14
7    7  4.656486    0  -3  -8   6  14
8    8  4.895714    0  -3  -8   6  14
9    9  8.170026    0  -3  -8   6  14
10  10 14.996445    0  -3  -8   6  14
11  11 17.009310   14  11   6  20  28
12  12 12.307479   14  11   6  20  28
13  13 17.732298   14  11   6  20  28
14  14 13.981514   14  11   6  20  28
15  15 11.873050   14  11   6  20  28
16  16  7.757170   14  11   6  20  28
17  17  9.820672   14  11   6  20  28
18  18 12.887160   14  11   6  20  28
19  19 10.617464   14  11   6  20  28
20  20  7.286322   14  11   6  20  28
21  21  8.869055   14  11   6  20  28

并且可以通过下面的代码来绘制。上图是实际数据。第二张图突出显示了我要提取的点。

par(mfrow=c(2,1))
par(mar=c(3,3,2,3))

plot(df$Run, df$y, type="b", ylim=c(-10, 30), pch=19, cex=2, lwd=2)
abline(v=c(1:21), lty=3, col="grey")

points(df$Run, df$zero, lwd=2, col="darkgreen", type="l")
points(df$Run, df$LL1, type="l", col="orange")
points(df$Run, df$LL2, type="l", col="red")
points(df$Run, df$UL1, type="l", col="orange")
points(df$Run, df$UL2, type="l", col="red")

par(xpd=T)
text(rep(22, 5), c(14,11,6,20,28), c("zero", "LL1", "LL2", "UL1", "UL2"), pos=4, col=c("darkgreen", "orange", "red", "orange", "red"))
par(xpd=F)


plot(df$Run, df$y, type="b", ylim=c(-10, 30), pch=19, cex=2, lwd=2)
abline(v=c(1:21), lty=3, col="grey")

points(df$Run, df$zero, lwd=2, col="darkgreen", type="l")
points(df$Run, df$LL1, type="l", col="orange")
points(df$Run, df$LL2, type="l", col="red")
points(df$Run, df$UL1, type="l", col="orange")
points(df$Run, df$UL2, type="l", col="red")

flags <- data.frame(boundary.crossed=c("LL1", "LL2", "UL1", "UL2", "LL1", "LL1"),col=c("orange", "red", "orange", "red", "orange", "orange"), Run=c(2,3,9,10, 16, 19))
points(df$Run[flags$Run], df$y[flags$Run], cex=2,  col=as.character(flags$col), pch=19)

par(xpd=T)
text(rep(22, 5), c(14,11,6,20,28), c("zero", "LL1", "LL2", "UL1", "UL2"), pos=4, col=c("darkgreen", "orange", "red", "orange", "red"))
par(xpd=F)

【问题讨论】:

  • “我不能使用 R 必须的(少数)包来绘制这些图......”这是否意味着您想要一个基本的 R 解决方案?

标签: r data-manipulation


【解决方案1】:

这是一个基本的 R 解决方案:

BoundaryCross <- function(myDf, keepSeparate=TRUE) {
    y <- myDf$y
    L2 <- myDf$LL2
    U2 <- myDf$UL2
    L1 <- myDf$LL1
    U1 <- myDf$UL1
    LimitTwo <- c(which(diff(y > L2)==-1L), which(diff(y > U2)==1L))+1L
    LimitOne <- c(which(diff(y > L1)==-1L), which(diff(y > U1)==1L))+1L

    ## do you won't to differentiate between the boundary crosses???
    if (keepSeparate) {
        list(YellowIndices=sort(LimitOne), RedIndices=sort(LimitTwo))
    } else {
        sort(c(LimitOne, LimitTwo))
    }
}

调用它,我们得到:

BoundaryCross(df)
$YellowIndices
[1]  2  9 16 19

$RedIndices
[1]  3 10

如果您只是想集体识别索引,我们有:

BoundaryCross(df, FALSE)
[1]  2  3  9 10 16 19

【讨论】:

  • 非常整洁!正是我所追求的!我会玩一下 -1L 来了解它是什么!谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 1970-01-01
  • 1970-01-01
  • 2018-09-11
  • 1970-01-01
  • 2021-07-13
相关资源
最近更新 更多