我试图用R
中的数据框解决一点困境。我有下一个具有此结构的数据框DF
(我在最后部分添加dput()
版本):
Key M1 M2 M3 M4 M5 M6 M7
001 1 NA NA 1 NA NA 1
002 NA NA 1 NA NA 1 NA
003 NA NA NA 1 1 NA 1
004 NA NA 1 NA NA NA 1
005 NA NA NA 1 NA NA 1
006 1 NA NA NA NA NA NA
007 NA NA 1 NA NA NA 1
此数据框包含ID列(Key
)以及包含NA
和1
的多个列。我希望在下一个模式中填充包含NA
的每一行:在两个NA
之后有两个1
和之前的1
以及最后一个NA
},然后NA
必须填充1
。如果未找到模式,则行中的元素必须保持其原始形式。例如,在第一行中有两种模式:1 NA NA 1
和1 NA NA 1
,然后NA
必须填充1
。我想得到这样的结果:
Key M1 M2 M3 M4 M5 M6 M7
001 1 1 1 1 1 1 1
002 NA NA 1 1 1 1 NA
003 NA NA NA 1 1 NA 1
004 NA NA 1 NA NA NA 1
005 NA NA NA 1 1 1 1
006 1 NA NA NA NA NA NA
007 NA NA 1 NA NA NA 1
模式已填充1
。我尝试使用na.locf()
包中的zoo
,但它会更改NAs
中DF
的其余内容。 dput()
的{{1}}版本是下一个:
DF
非常感谢你的帮助!
答案 0 :(得分:4)
我会使用行程编码为每行找到两个NA:
i <- t(apply(is.na(df[-1]), 1, function(x){
r <- rle(x)
# 2 NAs in a row => lengths = 2 & value is is.na true
r$values = r$lengths == 2 & r$values
# don't modify first / last run of the series
r$values[1] <- r$values[length(r$lengths)] <- FALSE
inverse.rle(r)
}))
df[-1][i] <- 1
df
# Key M1 M2 M3 M4 M5 M6 M7
# 1 001 1 1 1 1 1 1 1
# 2 002 NA NA 1 1 1 1 NA
# 3 003 NA NA NA 1 1 NA 1
# 4 004 NA NA 1 NA NA NA 1
# 5 005 NA NA NA 1 1 1 1
# 6 006 1 NA NA NA NA NA NA
# 7 007 NA NA 1 NA NA NA 1
这样,您就不需要转换为角色并返回。
答案 1 :(得分:2)
mat <- as.matrix(df[-1])
mat[is.na(mat)] <- 0L
strings <- apply(mat, 1, function(x) paste(x, collapse=""))
pattern_matches <- str_locate_all(strings, "(?=(1001))")
strloc <- sapply(pattern_matches, function(x) c(x[,"start"]))
for(i in seq(nrow(mat))) mat[i,strloc[[i]]+rep(1:2,each=length(strloc[[i]]))] <- 1
is.na(mat) <- mat==0
as.data.frame(cbind(df[1],mat))
# Key M1 M2 M3 M4 M5 M6 M7
# 1 001 1 1 1 1 1 1 1
# 2 002 NA NA 1 1 1 1 NA
# 3 003 NA NA NA 1 1 NA 1
# 4 004 NA NA 1 NA NA NA 1
# 5 005 NA NA NA 1 1 1 1
# 6 006 1 NA NA NA NA NA NA
# 7 007 NA NA 1 NA NA NA 1
我采用了与@ColonelBeauvel类似的方法,但使用了矩阵结构。首先将0
分配给所有NA值。然后将每一行粘贴在一起。匹配模式&#34; 1001&#34;来自str_locate_all
包的stringr
。对于任何想知道,完整模式"(?=(1001))"
的优点是,它允许在下一场比赛中使用一个匹配的一部分,称为&#34;非消费正则表达式&#34;。
然后我们找到每场比赛的开始并分配&#39; 1&#39;与它相邻的两个零。
答案 2 :(得分:1)
这是一种完成工作的方法,当然可以在不将NA
转换为0
的情况下进行改进,并使用gsub进行环视(但我不是正则表达式杀手!)。
m
是您原来的data.frame
:
x = do.call(paste, c(data.frame(1*!is.na(m[-1])), sep=''))
y = gregexpr('(?=1001)', x, perl=T)
func = function(u,v)
{
if(any(u!=-1))
sapply(u, function(i) substr(v, start=i, stop=i+2) <<- '111')
as.numeric(strsplit(v,'')[[1]])
}
df = cbind(list('key'=m[,1]), data.frame(do.call(rbind, Map(func, y, x))))
df[df==0] = NA
# key X1 X2 X3 X4 X5 X6 X7
#1 001 1 1 1 1 1 1 1
#2 002 NA NA 1 1 1 1 NA
#3 003 NA NA NA 1 1 NA 1
#4 004 NA NA 1 NA NA NA 1
#5 005 NA NA NA 1 1 1 1
#6 006 1 NA NA NA NA NA NA
#7 007 NA NA 1 NA NA NA 1