从向量

时间:2018-02-23 16:47:11

标签: r sequence na difference

我有一个数据框,其中有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-1i没有变化(即i-1i相等),则序列会继续,就像{NA时一样1}}发生

由于v是第一个差异系列,因此提取的元素i(第3个项目符号点)已经表示增加/减少。目前,我不想限制序列的长度,因此序列可能已经由两个元素给出。

我想将i v元素存储在一个新的向量中(例如inc.vdec.v),然后找到序列的最大值和平均值增加/减少量,以及这些序列的最大和平均长度。元素应存储在inc.vdec.v中,与v中的原始位置相关联,因此我可以追溯它们。 inc.vdec.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
  }
}

ifelse 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()语句应该保护TRUEFALSE参数?!

很高兴听到你的想法!

2 个答案:

答案 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库

相关问题