>假设我有以下数据和数据框:
sample_data <- c(1:14)
sample_data2 <- c(NA,NA,NA, "break", NA, NA, "break", NA,NA,NA,NA,NA,NA,"break")
sample_df <- as.data.frame(sample_data)
sample_df$sample_data2 <- sample_data2
当我打印此数据框时,结果如下:
sample_data sample_data2
1 1 <NA>
2 2 <NA>
3 3 <NA>
4 4 break
5 5 <NA>
6 6 <NA>
7 7 break
8 8 <NA>
9 9 <NA>
10 10 <NA>
11 11 <NA>
12 12 <NA>
13 13 <NA>
14 14 break
我将如何对其进行编程,以便在每次"休息"时,它都会输出该行的最大值?例如,我希望代码输出 (4,7,14) 集。此外,我希望它只找到下一个"中断"间隔之间的最大值。如果我使用了任何不正确的命名法,我提前道歉。
我构建了寻找单词"break"的组,然后将结果向上移动一行。然后dplyr
一些命令来获取每个组的最大值。
library(dplyr)
sample_df_new <- sample_df %>%
mutate(group = c(1, cumsum(grepl("break", sample_data2)) + 1)[1:length(sample_data2)]) %>%
group_by(group) %>%
summarise(group_max = max(sample_data))
> sample_df_new
# A tibble: 3 x 2
group group_max
<dbl> <dbl>
1 1 4
2 2 7
3 3 14
我有一个答案,使用data.table
:
library(data.table)
sample_df <- setDT(sample_df)
sample_df[,group := (rleid(sample_data2)-0.5)%/%2]
sample_df[,.(maxvalues = max(sample_data)),by = group]
group maxvalues
1: 0 4
2: 1 7
3: 2 14
棘手的部分是(rleid(sample_data2)-0.5)%/%2
:rleid
为每个更改创建一个递增索引:
sample_data sample_data2 rleid
1: 1 NA 1
2: 2 NA 1
3: 3 NA 1
4: 4 break 2
5: 5 NA 3
6: 6 NA 3
7: 7 break 4
8: 8 NA 5
9: 9 NA 5
10: 10 NA 5
11: 11 NA 5
12: 12 NA 5
13: 13 NA 5
14: 14 break 6
如果保留该索引的整个部分 - 0.5,则所需行具有常量索引,可用于分组操作:
sample_data sample_data2 group
1: 1 NA 0
2: 2 NA 0
3: 3 NA 0
4: 4 break 0
5: 5 NA 1
6: 6 NA 1
7: 7 break 1
8: 8 NA 2
9: 9 NA 2
10: 10 NA 2
11: 11 NA 2
12: 12 NA 2
13: 13 NA 2
14: 14 break 2
然后它只是为每个组取最大值。如果对您来说更容易,您可以轻松地将其转换为dplyr
<</p>
以下是使用 base R 的 2 种方法。诀窍是定义一个分组变量,grp
.
grp <- !is.na(sample_df$sample_data2) & sample_df$sample_data2 == "break"
grp <- rev(cumsum(rev(grp)))
grp <- -1*grp + max(grp)
tapply(sample_df$sample_data, grp, max, na.rm = TRUE)
aggregate(sample_data ~ grp, sample_df, max, na.rm = TRUE)
数据。
这是简化的数据创建代码。
sample_data <- 1:14
sample_data2 <- c(NA,NA,NA, "break", NA, NA, "break", NA,NA,NA,NA,NA,NA,"break")
sample_df <- data.frame(sample_data, sample_data2)
看起来有很多不同的方法可以做到这一点。我是这样做的:
rows <- which(sample_data2 == "break") #Get the row indices for where "break" appears
findmax <- function(maxrow) {
max(sample_data[1:maxrow])
} #Create a function that returns the max "up to" a given row
sapply(rows, findmax) #apply it for each of your rows
### [1] 4 7 14
请注意,这"最多"适用于给定行。使用其他解决方案之一来获得两个中断之间的最大值可能会更容易,但您也可以通过查看 rows
对象的 j-1 行到第 j 行来做到这一点。
根据您是否要评估所有"sample_data2"== 中断(例如第 1 行到第 4 行)或排除(例如第 1 行到第 3 行)给定的"sample_data2"== 中断行之间的最大"sample_data"数字,您可以使用 tidyverse
执行以下操作:
排除分隔行:
sample_df %>%
group_by(sample_data2) %>%
mutate(temp = ifelse(is.na(sample_data2), NA_character_, paste0(gl(length(sample_data2), 1)))) %>%
ungroup() %>%
fill(temp, .direction = "up") %>%
filter(is.na(sample_data2)) %>%
group_by(temp) %>%
summarise(res = max(sample_data))
temp res
<chr> <dbl>
1 1 3.
2 2 6.
3 3 13.
包括分隔行:
sample_df %>%
group_by(sample_data2) %>%
mutate(temp = ifelse(is.na(sample_data2), NA_character_, paste0(gl(length(sample_data2), 1)))) %>%
ungroup() %>%
fill(temp, .direction = "up") %>%
group_by(temp) %>%
summarise(res = max(sample_data))
temp res
<chr> <dbl>
1 1 4.
2 2 7.
3 3 14.
这两个代码都使用gl()
表示"sample_data2"==中断,然后使用该ID填充NA行,从而创建一个名为"temp"的ID变量。然后,第一个代码过滤掉"sample_data2"==中断行并评估每组的最大"sample_data"值,而第二个代码评估每组的最大"sample_data"值,包括"sample_data2"==中断行。