r - 按周期对数据帧中的数据进行分组

标签 r dataframe

我已经创建了我的数据的简化版本:

a <- data.frame(a = c(0,1,2,3,2,1,0,-1,-2,-3,-2,-1,
                        0,1,2,3,4,3,2,1,0,-1,-2,-3,-2,-1,
                        0,1,2,1,0,-1,-2,-3,-2,-1,0,1,2,3,2,1,
                        0,-1,-2,-3,-2,-1,0,1,2,3,2,1,
                        0,-1,-2,-3,-4,-3,-2,-1,0))
a$b <- seq(1,length(a$a),1)
我尝试检测数据中的周期如下(对更好的建议开放):
library(quantmod)
max <- findPeaks(a$a)
min <- findValleys(a$a)
这实际上给出了最大值和最小值之后的点。我想找到每个周期的跨度和设定点。
周期: - 第一个周期定义为第一个数据点到第一个设定点之前的数据点。例如,考虑到第一个设定点是 -1.0,第一个循环定义在第 1 行到第 12 行。第 12 行被选为循环结束,因为它出现在第一个峰值和谷值之后,并且也等于或小于 - 1.0.第二个循环从第 13 行开始到第 27 行,因为第 27 行的振幅为 0,小于或等于 0.5,并且发生在第二个峰值和谷值点之后:
span <- a[max-1,]$a-a[min-1,]$a
set <-  a[max,]$a - span/2
我想对原始数据框中的数据进行分组 a并将每个循环(组)的循环编号、跨度和设定点分配给相应的行组。
所需的输出是:
> print(a)
    a  b cycles span   set
1   0  1      1    6 -1.0
2   1  2      1    6 -1.0
3   2  3      1    6 -1.0
4   3  4      1    6 -1.0
5   2  5      1    6 -1.0
6   1  6      1    6 -1.0
7   0  7      1    6 -1.0
8  -1  8      1    6 -1.0
9  -2  9      1    6 -1.0
10 -3 10      1    6 -1.0
11 -2 11      1    6 -1.0
12 -1 12      1    6 -1.0
13  0 13      2    7  0.5
14  1 14      2    7  0.5
15  2 15      2    7  0.5
16  3 16      2    7  0.5
17  4 17      2    7  0.5
18  3 18      2    7  0.5
19  2 19      2    7  0.5
20  1 20      2    7  0.5
21  0 21      2    7  0.5
22 -1 22      2    7  0.5
23 -2 23      2    7  0.5
24 -3 24      2    7  0.5
25 -2 25      2    7  0.5
26 -1 26      2    7  0.5
27  0 27      2    7  0.5
28  1 28      3    5 -1.5
29  2 29      3    5 -1.5
30  1 30      3    5 -1.5
31  0 31      3    5 -1.5
32 -1 32      3    5 -1.5
33 -2 33      3    5 -1.5
34 -3 34      3    5 -1.5
35 -2 35      3    5 -1.5
36 -1 36      4    6 -1.0
37  0 37      4    6 -1.0
38  1 38      4    6 -1.0
39  2 39      4    6 -1.0
40  3 40      4    6 -1.0
41  2 41      4    6 -1.0
42  1 42      4    6 -1.0
43  0 43      4    6 -1.0
44 -1 44      4    6 -1.0
45 -2 45      4    6 -1.0
46 -3 46      4    6 -1.0
47 -2 47      4    6 -1.0
48 -1 48      4    6 -1.0
49  0 49      5    7 -1.5
50  1 50      5    7 -1.5
51  2 51      5    7 -1.5
52  3 52      5    7 -1.5
53  2 53      5    7 -1.5
54  1 54      5    7 -1.5
55  0 55      5    7 -1.5
56 -1 56      5    7 -1.5
57 -2 57      5    7 -1.5
58 -3 58      5    7 -1.5
59 -4 59      5    7 -1.5
60 -3 60      5    7 -1.5
61 -2 61      5    7 -1.5
62 -1 62      5    7 -1.5
63  0 63      5    7 -1.5

最佳答案

鉴于循环的定义,我认为您的循环应该在第 12、27、36、48 和 62 行结束,因此总共是 6 个循环而不是 5 个。实际上只有 5 个完整的循环。
为了简单和区分,一些数据/对象的名称已更改-
给定的对象

df_a <- data.frame(a = c(0,1,2,3,2,1,0,-1,-2,-3,-2,-1,
                      0,1,2,3,4,3,2,1,0,-1,-2,-3,-2,-1,
                      0,1,2,1,0,-1,-2,-3,-2,-1,0,1,2,3,2,1,
                      0,-1,-2,-3,-2,-1,0,1,2,3,2,1,
                      0,-1,-2,-3,-4,-3,-2,-1,0))
df_a$b <- seq(1,length(df_a$a),1)
df_a
my_max <- findPeaks(df_a$a)
my_min <- findValleys(df_a$a)


span <- df_a[my_max-1,]$a-df_a[my_min-1,]$a
set <-  df_a[my_max,]$a - span/2
建议用于循环的代码
# generate a for loop to calculate end of cycle

my_vec <- NULL # create a null vector

#create a my_vec through for loop
for(i in seq_along(my_max)){
  my_vec[i] <- which(df_a$b > max(my_max[i], my_min[i]) & df_a$a >= set[i])[1]
  }

library(tidyverse) # for cumsum function
#create cycle column
df_a$cycle <- rev(cumsum(rev(df_a$b %in% my_vec)))
#check
> df_a
    a  b cycle
1   0  1     5
2   1  2     5
3   2  3     5
4   3  4     5
5   2  5     5
6   1  6     5
7   0  7     5
8  -1  8     5
9  -2  9     5
10 -3 10     5
11 -2 11     5
12 -1 12     5
13  0 13     4
14  1 14     4
15  2 15     4
16  3 16     4
17  4 17     4
18  3 18     4
19  2 19     4
20  1 20     4
21  0 21     4
22 -1 22     4
23 -2 23     4
24 -3 24     4
25 -2 25     4
26 -1 26     4
27  0 27     4
28  1 28     3
29  2 29     3
30  1 30     3
31  0 31     3
32 -1 32     3
33 -2 33     3
34 -3 34     3
35 -2 35     3
36 -1 36     3
37  0 37     2
38  1 38     2
39  2 39     2
40  3 40     2
41  2 41     2
42  1 42     2
43  0 43     2
44 -1 44     2
45 -2 45     2
46 -3 46     2
47 -2 47     2
48 -1 48     2
49  0 49     1
50  1 50     1
51  2 51     1
52  3 52     1
53  2 53     1
54  1 54     1
55  0 55     1
56 -1 56     1
57 -2 57     1
58 -3 58     1
59 -4 59     1
60 -3 60     1
61 -2 61     1
62 -1 62     1
63  0 63     0
上面的代码将反向生成循环数。但是,如果您需要按顺序使用它们,请执行此操作
df_a$cycle <- max(rev(cumsum(rev(df_a$b %in% my_vec))))+1-rev(cumsum(rev(df_a$b %in% my_vec)))

df_a

> df_a
    a  b cycle
1   0  1     1
2   1  2     1
3   2  3     1
4   3  4     1
5   2  5     1
6   1  6     1
7   0  7     1
8  -1  8     1
9  -2  9     1
10 -3 10     1
11 -2 11     1
12 -1 12     1
13  0 13     2
14  1 14     2
15  2 15     2
16  3 16     2
17  4 17     2
18  3 18     2
19  2 19     2
20  1 20     2
21  0 21     2
22 -1 22     2
23 -2 23     2
24 -3 24     2
25 -2 25     2
26 -1 26     2
27  0 27     2
28  1 28     3
29  2 29     3
30  1 30     3
31  0 31     3
32 -1 32     3
33 -2 33     3
34 -3 34     3
35 -2 35     3
36 -1 36     3
37  0 37     4
38  1 38     4
39  2 39     4
40  3 40     4
41  2 41     4
42  1 42     4
43  0 43     4
44 -1 44     4
45 -2 45     4
46 -3 46     4
47 -2 47     4
48 -1 48     4
49  0 49     5
50  1 50     5
51  2 51     5
52  3 52     5
53  2 53     5
54  1 54     5
55  0 55     5
56 -1 56     5
57 -2 57     5
58 -3 58     5
59 -4 59     5
60 -3 60     5
61 -2 61     5
62 -1 62     5
63  0 63     6
旧代码
my_vec <- NULL

for(i in seq_along(my_max)){
  my_vec[1] <- 0
  my_vec[i+1] <- which(df_a$b > max(my_max[i], my_min[i]) & df_a$a >= set[i])[1]
  }
# generate column cycle as intended

df_a$cycle <- c(rep(1:length(my_max), diff(my_vec)), rep(length(my_max)+1, length(df_a$a)-length(rep(1:length(my_max), diff(my_vec)))))

    a  b cycle
1   0  1     1
2   1  2     1
3   2  3     1
4   3  4     1
5   2  5     1
6   1  6     1
7   0  7     1
8  -1  8     1
9  -2  9     1
10 -3 10     1
11 -2 11     1
12 -1 12     1
13  0 13     2
14  1 14     2
15  2 15     2
16  3 16     2
17  4 17     2
18  3 18     2
19  2 19     2
20  1 20     2
21  0 21     2
22 -1 22     2
23 -2 23     2
24 -3 24     2
25 -2 25     2
26 -1 26     2
27  0 27     2
28  1 28     3
29  2 29     3
30  1 30     3
31  0 31     3
32 -1 32     3
33 -2 33     3
34 -3 34     3
35 -2 35     3
36 -1 36     3
37  0 37     4
38  1 38     4
39  2 39     4
40  3 40     4
41  2 41     4
42  1 42     4
43  0 43     4
44 -1 44     4
45 -2 45     4
46 -3 46     4
47 -2 47     4
48 -1 48     4
49  0 49     5
50  1 50     5
51  2 51     5
52  3 52     5
53  2 53     5
54  1 54     5
55  0 55     5
56 -1 56     5
57 -2 57     5
58 -3 58     5
59 -4 59     5
60 -3 60     5
61 -2 61     5
62 -1 62     5
63  0 63     6
逻辑解释
  • 为了创建每个循环的终点,我从一个空向量开始。
  • 该向量的第一个元素被视为 0
  • 使用循环定义创建的另一个元素(具有相同的计数),从而使 my_vec 中的元素比需要的多
  • my_vec将有每个周期的终点
  • diff(my_vec) 将再次产生相同数量的元素,但每个都代表每个循环的终点
  • rep(1:number of complete cycle, diff(my_vec) 将导致生成所需的向量
  • 该向量将导致仅生成完整循环。此后需要添加不完整的循环数。

  • 此后您可以加入已生成的列。
    完整输出
    df_b <- data.frame(cycle = 1:length(my_max))
    df_b$span <- df_a[my_max-1,]$a-df_a[my_min-1,]$a
    df_b$set <-  df_a[my_max,]$a - span/2
    
    merge(df_a, df_b, by.x = "cycle", by.y = "cycle", all = T)
       cycle  a  b span  set
    1      1  0  1    6 -1.0
    2      1  1  2    6 -1.0
    3      1  3  4    6 -1.0
    4      1  2  5    6 -1.0
    5      1  1  6    6 -1.0
    6      1  2  3    6 -1.0
    7      1 -1  8    6 -1.0
    8      1 -2  9    6 -1.0
    9      1 -3 10    6 -1.0
    10     1  0  7    6 -1.0
    11     1 -1 12    6 -1.0
    12     1 -2 11    6 -1.0
    13     2  0 13    7 -0.5
    14     2  1 14    7 -0.5
    15     2  2 15    7 -0.5
    16     2  4 17    7 -0.5
    17     2  3 18    7 -0.5
    18     2  2 19    7 -0.5
    19     2  3 16    7 -0.5
    20     2  0 21    7 -0.5
    21     2 -1 22    7 -0.5
    22     2 -2 23    7 -0.5
    23     2  1 20    7 -0.5
    24     2 -2 25    7 -0.5
    25     2 -1 26    7 -0.5
    26     2  0 27    7 -0.5
    27     2 -3 24    7 -0.5
    28     3  1 28    5 -1.5
    29     3  1 30    5 -1.5
    30     3  0 31    5 -1.5
    31     3 -1 32    5 -1.5
    32     3  2 29    5 -1.5
    33     3 -3 34    5 -1.5
    34     3 -2 35    5 -1.5
    35     3 -1 36    5 -1.5
    36     3 -2 33    5 -1.5
    37     4  1 38    6 -1.0
    38     4  2 39    6 -1.0
    39     4  3 40    6 -1.0
    40     4  2 41    6 -1.0
    41     4  1 42    6 -1.0
    42     4  0 43    6 -1.0
    43     4 -1 44    6 -1.0
    44     4 -2 45    6 -1.0
    45     4 -3 46    6 -1.0
    46     4 -2 47    6 -1.0
    47     4 -1 48    6 -1.0
    48     4  0 37    6 -1.0
    49     5  0 49    7 -1.5
    50     5  2 51    7 -1.5
    51     5  3 52    7 -1.5
    52     5  2 53    7 -1.5
    53     5  1 54    7 -1.5
    54     5  0 55    7 -1.5
    55     5 -1 56    7 -1.5
    56     5 -2 57    7 -1.5
    57     5 -3 58    7 -1.5
    58     5 -4 59    7 -1.5
    59     5 -3 60    7 -1.5
    60     5 -2 61    7 -1.5
    61     5 -1 62    7 -1.5
    62     5  1 50    7 -1.5
    63     6  0 63   NA   NA
    
    我们可以检查一下
    library(tidyverse)
    
    df_a %>% ggplot() +
      geom_line(aes(x=b, y=a, linetype = as.character(cycle)))
    
    enter image description here

    关于r - 按周期对数据帧中的数据进行分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65801769/

    相关文章:

    r - 在 R 中找到使最大值的值

    python - 剥离数据框单元格然后创建列

    r - 使用 knitr 时 stargazer latex 表的新字体样式

    r - R e1071 朴素贝叶斯中的错误?

    r - 通过使用另一列索引到列表中来在数据框中创建一个新列?

    python - 存储在字典中的多个数据帧 - Python/Pandas

    python - 创建一个数据透视表,其中我的值是我列的计数

    Python-通过从另一列中选择第一个值来按列分组,但如果已经选择了值则不会

    html - 使用 rvest 包提取两条 html 水平线之间的文本

    r - 在绘图中的点 0 处添加 3d 曲面