R dplyr:在一列中查找特定值,然后用该值替换右侧后续列中的相邻单元格

R dplyr: Find a specific value in a column, then replace the adjacent cell in the subsequent columns to the right with that value

我正在尝试创建一个站点和事件时间矩阵。在我的例子中,一旦事件发生(“1”),它就是永久的,不能回到“0”。一旦列中的单元格为“1”,我将尝试用“1”填充右侧后续列中的相邻单元格(请参见下面的示例)。

site <- c('A','B','C','D','E','F','G') #site
time <- c(0,1,4,0,3,2,0) # time in which even occured
event <- c(0,1,1,0,1,1,0) # did a event occur
data <- data.frame(site, time, event)

site.time.matrix <- cast(data, site~time)

# This is the output      # This is the desired output
#site   0  1  2  3  4     #site   0  1  2  3  4
#    A  0 NA NA NA NA     #    A  0  0  0  0  0
#    B NA  1 NA NA NA     #    B  0  1  1  1  1
#    C NA NA NA NA  1     #    C  0  0  0  0  1
#    D  0 NA NA NA NA     #    D  0  0  0  0  0
#    E NA NA NA  1 NA     #    E  0  0  0  1  1
#    F NA NA  1 NA NA     #    F  0  0  1  1  1
#    G  0 NA NA NA NA     #    G  0  0  0  0  0

我发现了一些使用 dplyr 的有前途的代码,例如( or Apply function to each column in a data frame observing each columns existing data type) 替换值,尽管我不确定如何在后续列参数中指定相邻单元格。

如果这个问题不清楚,我很抱歉,这是我在 Whosebug 上的第一个 post。

谢谢。

第一个用户 post 对细节、可重现性和有趣性感到惊喜,+1!

使用 zoo 包中的 na.locf 你可以做:

library(reshape) # for cast function
library(zoo)    #for na.locf function short for if NA, last observation carrried forward, ?na.locf

site <- c('A','B','C','D','E','F','G') #site
time <- c(0,1,4,0,3,2,0) # time in which even occured
event <- c(0,1,1,0,1,1,0) # did a event occur
data <- data.frame(site, time, event)

site.time.matrix <- reshape::cast(data, site~time)

site.time.matrix.fill <- site.time.matrix


# Transpose the matrix excluding first column, carry forward last observation and 
# transpose again to return to original matrix structure

site.time.matrix.fill[,-1] <- t(na.locf(t(site.time.matrix.fill[,-1])))

site.time.matrix.fill[is.na( site.time.matrix.fill)] <- 0

site.time.matrix.fill

#  site 0 1 2 3 4
#1    A 0 0 0 0 0
#2    B 0 1 1 1 1
#3    C 0 0 0 0 1
#4    D 0 0 0 0 0
#5    E 0 0 0 1 1
#6    F 0 0 1 1 1
#7    G 0 0 0 0 0

使用 applybase R 方法。

基本上,对于每一行,我们都试图找到其中包含 1 的任何元素,并将 0 分配给左侧的每个元素,并为右侧的每个元素分配 1。

t(apply(site.time.matrix, 1, function(x) {
       temp = if(any(x == 1, na.rm = T)) which(x==1)-1 else length(x)
       x[temp:length(x)] <- 1
       x[0:temp] <- 0
       x
}))


#  0 1 2 3 4
#A 0 0 0 0 0
#B 0 1 1 1 1
#C 0 0 0 0 1
#D 0 0 0 0 0
#E 0 0 0 1 1
#F 0 0 1 1 1
#G 0 0 0 0 0

这是第二个基本的 R 方法(不包括重塑)。这使用 applycummax(累计最大值)。如果每个站点只发生一个事件,则将 cummax 替换为 cumsum 会 return 相同的结果。

# reshape the data
temp <- cast(data, site~time)

# construct matrix of 0s and 1s
myMat <- as.matrix(temp[-1])
myMat[is.na(myMat)] <- 0

# expand 1s to the right when they appear
myMat <- t(apply(myMat, 1, cummax))

# add row and column names
dimnames(myMat) <- list(levels(temp$site), seq_len(ncol(myMat))-1)

这个returns

myMat
  0 1 2 3 4
A 0 0 0 0 0
B 0 1 1 1 1
C 0 0 0 0 1
D 0 0 0 0 0
E 0 0 0 1 1
F 0 0 1 1 1
G 0 0 0 0 0

注: 重塑(使用 cast)也可以使用基本 R reshape 函数执行,但之后您还必须重新排序变量。例如,

# reshape data
temp <- reshape(data, direction="wide", idvar="site")
# reorder variables
temp <- temp[c("site", sort(names(temp)[-1]))]

会产生预期的数据帧。

  site event.0 event.1 event.2 event.3 event.4
1    A       0      NA      NA      NA      NA
2    B      NA       1      NA      NA      NA
3    C      NA      NA      NA      NA       1
4    D       0      NA      NA      NA      NA
5    E      NA      NA      NA       1      NA
6    F      NA      NA       1      NA      NA
7    G       0      NA      NA      NA      NA