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
使用 apply
的 base 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 方法(不包括重塑)。这使用 apply
和 cummax
(累计最大值)。如果每个站点只发生一个事件,则将 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
我正在尝试创建一个站点和事件时间矩阵。在我的例子中,一旦事件发生(“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 的有前途的代码,例如(
如果这个问题不清楚,我很抱歉,这是我在 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
使用 apply
的 base 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 方法(不包括重塑)。这使用 apply
和 cummax
(累计最大值)。如果每个站点只发生一个事件,则将 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