我有一个数据框,其中有2718个观察值,其中一列感兴趣。这是使用diff()
创建的第一个差异系列。为了方便起见,让我们创建一个类似于数据的虚假向量,假装v
是第一个差异系列。引入NA
以使其与原始数据类似。
# Create fake first difference series vector v
v <- runif(2718, -0.05, 0.05)
v <- append(NA, diff(v))
# Insert NAs at the beginning and end
v[c(1:8, 2712:2718)] <- NA
# Insert some NAs at random places in v
ind <- which(v %in% sample(v, 7))
v[ind] <- NA
我对显示增加和减少行为的v
序列感兴趣。具体来说,我想分别提取连续增加和减少的v
序列。在递增的序列中,v
的每个元素不能小于其前一个元素,并且在递减的序列中,v
的每个元素不能大于其前一个元素。在绘制v
时尝试画出这一点:每当曲线没有减少(即上升或保持水平)时,它是一个递增的序列,每当曲线没有增加(即下降或保持水平)时,它是一个递减的序列。
澄清一下,程序可以解释为:
i
中的给定值v
,并将其与前一个值i-1
进行比较i
大于或等于i-1
,则序列符合增加条件;如果i
小于或等于i-1
,则序列符合减少条件。i
元素i-1
到i
没有变化(即i-1
和i
相等),则序列会继续,就像{NA
时一样1}}发生由于v
是第一个差异系列,因此提取的元素i
(第3个项目符号点)已经表示增加/减少。目前,我不想限制序列的长度,因此序列可能已经由两个元素给出。
我想将i
v
元素存储在一个新的向量中(例如inc.v
和dec.v
),然后找到序列的最大值和平均值增加/减少量,以及这些序列的最大和平均长度。元素应存储在inc.v
或dec.v
中,与v
中的原始位置相关联,因此我可以追溯它们。 inc.v
和dec.v
中的每个序列在被NA
元素分隔时应该很容易区分。
我尝试用for循环和条件语句写这个但是没有做得太远:
inc.v <- NULL
dec.v <- NULL
for (i in 2:length(v)) {
if(!v[i] < v[i-1] | is.na(v[i])) {
inc.v[i] <- v[i]
} else if (!v[i] > v[i-1] | is.na(v[i])) {
dec.v[i] <- v[i]
} else {
next
}
}
if
和else if
语句代表第五个要点。我知道当i
等于i-1
时,它可以同时作为递增和递减序列,并且应该添加到先前存储的任何序列中。我只是不知道如何实现它。我认为序列将非常短,因为数据是嘈杂的,没有减少/没有增加的时期不会长期存在。因此,也可以尝试使用例如此操作。 50/100点移动平均值:
# A symmetric 50 points moving average for v
f50 <- rep(1/51,51)
v_smooth <- filter(v, f50, sides = 2)
从现在开始运行循环时,对第一个条件的评估会产生NA
,从而给出错误:
Error in if (!v[i] < v[i - 1] | is.na(v[i])) { :
missing value where TRUE/FALSE needed
我不太明白这里发生了什么,因为is.na()
语句应该保护TRUE
或FALSE
参数?!
很高兴听到你的想法!
答案 0 :(得分:2)
您应该进行矢量化而不是循环,并在差异向量上使用直接条件来创建包含inc和dec的新列。当你想要平滑时它的工作原理是一样的。这是一个例子:
library(data.table)
plouf <- setDT(list( v = v, diff = c(NA,diff(v))))
plouf[diff > 0,inc := v]
plouf[diff < 0, dec := v]
f50 <- rep(1/51,51)
plouf[,v_smooth := filter(v, f50, sides = 2)]
plouf[,diff_smooth :=c(NA,diff(v_smooth))]
plouf[diff_smooth > 0,inc_smooth := v_smooth]
plouf[diff_smooth < 0, dec_smooth := v_smooth]
要提取减小值,您需要创建一个分组变量,该变量在每次更改diff时都会增加,因此我们可以使用by
plouf[,grouptmp := abs(c(NA,diff(ifelse(diff>0,1,0))))]
plouf[is.na(grouptmp),grouptmp:= 0]
plouf[,group := cumsum(grouptmp)]
plouf[,decvalue := dec[.N] - dec[1], by = group]
plouf[,incvalue := inc[.N]-inc[1], by = group]
v diff inc dec group decvalue grouptmp
1: NA NA NA NA 0 NA 0
2: NA NA NA NA 0 NA 0
3: NA NA NA NA 0 NA 0
4: NA NA NA NA 0 NA 0
5: NA NA NA NA 0 NA 0
6: NA NA NA NA 0 NA 0
7: NA NA NA NA 0 NA 0
8: NA NA NA NA 0 NA 0
9: -0.0344851657 NA NA NA 0 NA 0
10: 0.0788633499 0.1133485156 0.0788633499 NA 0 NA 0
11: -0.0415118591 -0.1203752090 NA -0.0415118591 1 0.000000000 1
12: 0.0557818390 0.0972936981 0.0557818390 NA 2 NA 1
13: -0.0314433977 -0.0872252367 NA -0.0314433977 3 0.000000000 1
14: 0.0098391432 0.0412825409 0.0098391432 NA 4 NA 1
15: -0.0147885296 -0.0246276728 NA -0.0147885296 5 0.000000000 1
16: -0.0009157661 0.0138727635 -0.0009157661 NA 6 NA 1
17: 0.0303060166 0.0312217827 0.0303060166 NA 6 NA 0
18: -0.0384165912 -0.0687226078 NA -0.0384165912 7 -0.005185349 1
19: -0.0436019399 -0.0051853487 NA -0.0436019399 7 -0.005185349 0
20: 0.0821260908 0.1257280307 0.0821260908 NA 8 NA 1
21: -0.0172987636 -0.0994248545 NA -0.0172987636 9 -0.003255037 1
22: -0.0205538005 -0.0032550369 NA -0.0205538005 9 -0.003255037 0
23: -0.0114417208 0.0091120797 -0.0114417208 NA 10 NA 1
24: 0.0524503477 0.0638920686 0.0524503477 NA 10 NA 0
25: -0.0105871856 -0.0630375333 NA -0.0105871856 11 -0.047042624 1
26: -0.0576298093 -0.0470426237 NA -0.0576298093 11 -0.047042624 0
27: 0.0031608195 0.0607906288 0.0031608195 NA 12 NA 1
28: -0.0009828784 -0.0041436979 NA -0.0009828784 13 0.000000000 1
29: 0.0167153471 0.0176982255 0.0167153471 NA 14 NA 1
30: 0.0088964230 -0.0078189241 NA 0.0088964230 15 -0.033234568 1
31: 0.0065035882 -0.0023928348 NA 0.0065035882 15 -0.033234568 0
32: -0.0243381450 -0.0308417332 NA -0.0243381450 15 -0.033234568 0
然后,您可以轻松找到最好的或做任何你想做的事。
答案 1 :(得分:1)
你应该尝试使用矢量化方法,这可能是一种更清晰的方法来查找增加或减少序列的运行:
library(data.table)
data <- as.data.table(v)
data[, vl := shift(v, 1)]
data[, runs := rleid(vl > v)]
使用data.table库