我正在尝试使用数据框上方或下方的列中的值替换数据框中的“我们”(或NA,容易将我们称为NA)。即
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
答案 0 :(得分:1)
我假设您只希望在第一行和第三行中的条目匹配时替换第二行中的条目。
也许使用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
答案 1 :(得分:1)
这是仅使用基数R和libOpenCL.so
函数的简单解决方案。此解决方案还假定“ U”不在第一行或最后一行。同样,这也假设数据存储在数据帧中。
apply
答案 2 :(得分:0)
在zoo
包中,有一个称为na.approx
的方法将在两个值之间插值。还有na.locf
会采用先前的值。两者一起可以为您提供帮助。
一个相关的问题可以在这里找到:Interpolation of NAs
答案 3 :(得分:0)
如拉尔所说,您可以将zoo
与na.locf
一起使用
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
V1 V2 V3 V4
[1,] "0" "1" "0" "1"
[2,] "0" "1" "U" "U"
[3,] "0" "1" "1" "0"
答案 4 :(得分:0)
使用 dplyr lead()
和lag()
myfunc <- function(my_list) {
mlead <- lead(my_list, default = 'U')
mlag <- lag(my_list, default = 'U')
valuetocopy <- (my_list == 'U') & ((mlead == mlag))
my_list[valuetocopy] <- mlead[valuetocopy]
return(my_list)
}