这是一个类似于更大数据集的示例数据框:
Day <- c(1, 2, NA, 3, 4, NA, NA, NA, NA, NA, 1, 2, 3, NA, NA, NA, NA, 1, 2, NA, NA, 3, 4, 5)
y <- rpois(length(Day), 2)
z <- seq(1:length(Day)) + 500
df <- data.frame(z, Day, y)
Run Code Online (Sandbox Code Playgroud)
如果Day列中存在4个或更多缺失值(NAs)的序列,则该序列表示研究中的群组之间的差距.如果序列中少于4个NA,则缺失值仍被视为群组的一部分(例如,行3是群组1的一部分,但行8不是).在样本数据框中,有3个群组(群组1:行1-5,群组2:行11-13,群组3:行18-24).我想添加一个列出队列号的列和另一个列出队列研究日的列.这是我使用的代码:
require(dplyr)
CheckNA <- rle(is.na(df$Day))
CheckNA$values <- CheckNA$lengths >= 4 & CheckNA$values == 1
ListNA <- rep(CheckNA$values, CheckNA$lengths)
df$Co <- rep(c(1, NA, 2, NA, 3), rle(ListNA)$lengths) %>% as.factor()
df <- df %>%
group_by (Co) %>%
mutate(CoDay = seq(Co)) %>%
as.data.frame()
df$CoDay <- ifelse(is.na(df$Co), NA, df$CoDay)
Run Code Online (Sandbox Code Playgroud)
有没有更有效的方法来完成这项任务?我特意寻找代码以避免列出同类群号,因为我的实际数据集将有超过10个同类群组.我目前只列出应该重复的序列:c(1,NA,2,NA,3).
谢谢!
我在这里做一个改变
CheckNA <- rle(is.na(df$Day))
CheckNA$values <- CheckNA$lengths >= 4 & CheckNA$values == 1
CheckNA$values <- ifelse(!CheckNA$values, cumsum(CheckNA$values)+1, NA)
df$Co <- inverse.rle(CheckNA)
Run Code Online (Sandbox Code Playgroud)
我保持前两行相同,然后我习惯cumsum()在每次休息时分配新的ID.这意味着您不必对任何值进行硬编码.使用新值,您可以使用inverse.rle与用于rep()将新ID扩展到每个行的方式相同的方式.
如果将其转换为函数,则可以清理这些dplyr位
id_NA_break <- function(x) {
CheckNA <- rle(is.na(x))
CheckNA$values <- CheckNA$lengths >= 4 & CheckNA$values == 1
CheckNA$values <- ifelse(!CheckNA$values, cumsum(CheckNA$values)+1, NA)
inverse.rle(CheckNA)
}
df <- data.frame(z, Day, y)
df %>%
mutate(Co=id_NA_break(Day)) %>%
group_by(Co) %>%
mutate(CoDay = ifelse(is.na(Co), NA, seq(Co)))
Run Code Online (Sandbox Code Playgroud)