r - R:更改单元格中的值,如果其上方和下方的值相互匹配,则不使用 for 循环
问题描述
我正在尝试用它们上方或下方的列中的值替换我的数据框中的 Us(或 NA,很容易将 Us 作为 NA)。IE
0 1 0 1
U U U U
0 1 1 0
会成为
0 1 0 1
0 1 U U
0 1 1 0
我有一个 for 循环来执行此操作,它适用于数据的子集
for(i in 2:((NROW(Sample_table))-1)) {
for(j in 3:NCOL(Sample_table)) {
if((Sample_table[i,j]=="U")&(Sample_table[(i-1),j]==Sample_table[(i+1),j])){
Sample_table[i,j] <- Sample_table[(i+1),j]
}
}
}
(不是从 1:1 开始,因为前几行/列包含位置/名称)。但是,我的最终数据集是 152 列和约 600 万行,因此 for 循环不是一个好的解决方案(尝试这样做,运行了一周没有完成)。我试过使用apply,但不知道如何让它引用其他行,我试过使用ifelse,但只能让它在for循环中工作。有什么帮助或建议吗?
编辑 ###我认为 Maurits 已经在下面解决了它,但是当我将它应用于更大的数据帧时,它并没有给出预期的输出:
df <- read.table(text =
"0 1 0 1 0 1 1 0
U U U U 1 0 1 1
0 1 1 0 0 1 0 1
0 1 0 1 0 1 1 0
U U U U 1 0 1 1
0 1 1 0 0 1 0 1
", header = F)
> df
V1 V2 V3 V4 V5 V6 V7 V8
1 0 1 0 1 0 1 1 0
2 U U U U 1 0 1 1
3 0 1 1 0 0 1 0 1
4 0 1 0 1 0 1 1 0
5 U U U U 1 0 1 1
6 0 1 1 0 0 1 0 1
> df2 <- as.data.frame(sapply(df, function(x) replace(x, x[1] == x[3] & x[2]
== "U", x[1])))
> df2
V1 V2 V3 V4 V5 V6 V7 V8
1 1 1 1 2 0 1 1 0
2 1 1 3 3 1 0 1 1
3 1 1 2 1 0 1 0 1
4 1 1 1 2 0 1 1 0
5 1 1 3 3 1 0 1 1
6 1 1 2 1 0 1 0 1
编辑 2
比较方法:应用最快(得到正确答案):
devtools::install_github("olafmersmann/microbenchmarkCore")
devtools::install_github("olafmersmann/microbenchmark")
library(microbenchmark)
mbm <- microbenchmark("apply_wrong_version" = {df <- read.table(text =
"0 1 0 1 0 1 1 0
U U U U 1 0 1 1
0 1 1 0 0 1 0 1
0 1 0 1 0 1 1 0
U U U U 1 0 1 1
0 1 1 0 0 1 0 1
", header = F)
df2 <- as.data.frame(sapply(df, function(x) replace(x, x[1] == x[3] & x[2]
== "U", x[1])))
df2},"forloop" = {df <- read.table(text =
"0 1 0 1 0 1 1 0
U U U U 1 0 1 1
0 1 1 0 0 1 0 1
0 1 0 1 0 1 1 0
U U U U 1 0 1 1
0 1 1 0 0 1 0 1
", header = F)
for(i in 2:((NROW(df))-1)) {
for(j in 1:NCOL(df)) {
if((df[i,j]=="U")&(df[(i-1),j]==df[(i+1),j])){
df[i,j] <- df[(i+1),j]
}
}
}
},"na.locf_version" = {mat=read.table(text =
"0 1 0 1 0 1 1 0
U U U U 1 0 1 1
0 1 1 0 0 1 0 1
0 1 0 1 0 1 1 0
U U U U 1 0 1 1
0 1 1 0 0 1 0 1
", header = F)
mat1=mat
mat1[mat1=='U']=NA
mask=zoo::na.locf(mat1)==zoo::na.locf(mat1,fromLast=T)
mat[mask]=zoo::na.locf(mat1,fromLast=T)[mask]
mat},"apply_version"= {df <- read.table(text =
"0 1 0 1 0 1 1 0
U U U U 1 0 1 1
0 1 1 0 0 1 0 1
0 1 0 1 0 1 1 0
U U U U 1 0 1 1
0 1 1 0 0 1 0 1
", header = F)
df[]<-apply(df, 2, function(x){
#find rows with U
us<-which(x=="U" )
#replace U with value above (if above=below)
x[us]<-ifelse(x[us-1]==x[us+1], x[us-1], "U")
return(x)
})
})
mbm
expr min lq mean median uq max neval cld
apply_wrong_version 671.605 821.334 979.1732 910.816 1020.840 4364.250 100 a
forloop 11809.985 13516.258 14523.5789 14059.863 15238.531 22556.858 100 d
na.locf_version 3754.275 4380.448 5042.3309 4631.510 5314.573 9295.415 100 c
apply_version 986.470 1209.878 1476.4378 1321.878 1492.742 8167.513 100 b
解决方案
我假设您只想在第一行和第三行中的条目匹配时替换第二行中的条目。
也许像这样使用replace
?
# Sample data (as matrix)
mat <- as.matrix(read.table(text =
"0 1 0 1
U U U U
0 1 1 0", header = F))
apply(mat, 2, function(x) replace(x, x[1] == x[3] & x[2] == "U", x[1]))
# V1 V2 V3 V4
#[1,] "0" "1" "0" "1"
#[2,] "0" "1" "U" "U"
#[3,] "0" "1" "1" "0"
或者如果你有一个data.frame
(而不是一个matrix
):
# Sample data (as data.frame)
df <- read.table(text =
"0 1 0 1
U U U U
0 1 1 0", header = F)
as.data.frame(sapply(df, function(x) replace(x, x[1] == x[3] & x[2] == "U", x[1])))
# V1 V2 V3 V4
#1 0 1 0 1
#2 0 1 U U
#3 0 1 1 0
推荐阅读
- math - 使用 ThreeJS 转换向量以遵循互补向量
- python - 如何用给定的索引多次对称地覆盖二维 numpy?
- c - 在 C 中获取 mod 10 的最快方法
- python - 如何通过使用多个文件在 Python 中正确使用多处理?
- python - Python CSV 删除表示为的新行
- php - 转换成十进制后的密码比较
- python - 使用 Pycharm 安装 Pillow 失败
- javascript - 如何从firebase数据库中获取密钥
- python - 将字典传递给函数而不更改先前处理的值
- reactjs - 我的 API laravel 在我的 reactjs 上运行时不起作用