使用嵌套的应用函数而不是嵌套的for循环
我的目标是在使用嵌套的应用函数而不是嵌套的for循环,r,apply,nested-loops,R,Apply,Nested Loops,我的目标是在df中遍历每一列,然后针对每一列遍历每一行并执行一个函数。本例中的特定函数将最后一列中的NA值替换为相应的值,但所需函数的详细信息与此处的问题无关。我使用两个嵌套for循环得到了所需的结果,如下所示: for (j in 1:ncol(df.i)) { for (i in 1:nrow(df.i)) { df.i[i,j] <- ifelse(is.na(df.i[i,j]), df.i[i,39], df.i[i,j]) } } for(1中的j:ncol(
df
中遍历每一列,然后针对每一列遍历每一行并执行一个函数。本例中的特定函数将最后一列中的NA
值替换为相应的值,但所需函数的详细信息与此处的问题无关。我使用两个嵌套for循环得到了所需的结果,如下所示:
for (j in 1:ncol(df.i)) {
for (i in 1:nrow(df.i)) {
df.i[i,j] <- ifelse(is.na(df.i[i,j]), df.i[i,39], df.i[i,j])
}
}
for(1中的j:ncol(df.i)){
用于(1:nrow中的i(df.i)){
这里有四种方法可以实现内部指令的功能
首先是一个数据集示例
set.seed(5345) # Make the results reproducible
df.i <- matrix(1:400, ncol = 40)
is.na(df.i) <- sample(400, 50)
然后,矢量化,完全没有循环
df.i2 <- ifelse(is.na(df.i), df.i[, 39], df.i)
以及你的解决方案,如问题中所述
for (j in 1:ncol(df.i)) {
for (i in 1:nrow(df.i)) {
df.i[i,j] <- ifelse(is.na(df.i[i,j]), df.i[i,39], df.i[i,j])
}
}
基准。
在@Gregor发表评论后,我决定对这4个解决方案进行基准测试。正如预期的那样,每个优化都会产生显著的影响,他的完全矢量化解决方案是最快的
f <- function(df.i){
for (j in 1:ncol(df.i)) {
for (i in 1:nrow(df.i)) {
df.i[i,j] <- ifelse(is.na(df.i[i,j]), df.i[i,39], df.i[i,j])
}
}
df.i
}
f1 <- function(df.i1){
for (j in 1:ncol(df.i1)) {
df.i1[,j] <- ifelse(is.na(df.i1[, j]), df.i1[, 39], df.i1[, j])
}
df.i1
}
f2 <- function(df.i2){
df.i2 <- ifelse(is.na(df.i2), df.i2[, 39], df.i2)
df.i2
}
f3 <- function(df.i3){
df.i3[is.na(df.i3)] <- df.i3[row(df.i3)[is.na(df.i3)], 39]
df.i3
}
microbenchmark::microbenchmark(
two_loops = f(df.i),
one_loop = f1(df.i1),
ifelse = f2(df.i2),
vectorized = f3(df.i3)
)
#Unit: microseconds
# expr min lq mean median uq max neval
# two_loops 1125.017 1143.4995 1226.93089 1152.5665 1190.599 5209.431 100
# one_loop 492.945 500.7045 518.73060 504.9435 516.638 678.951 100
# ifelse 42.269 45.7770 50.55519 48.4140 50.470 198.533 100
#vectorized 12.626 14.5520 16.21975 15.6380 17.663 27.525 100
f这里有四种方法可以实现内部指令的功能
首先是一个数据集示例
set.seed(5345) # Make the results reproducible
df.i <- matrix(1:400, ncol = 40)
is.na(df.i) <- sample(400, 50)
然后,矢量化,完全没有循环
df.i2 <- ifelse(is.na(df.i), df.i[, 39], df.i)
以及你的解决方案,如问题中所述
for (j in 1:ncol(df.i)) {
for (i in 1:nrow(df.i)) {
df.i[i,j] <- ifelse(is.na(df.i[i,j]), df.i[i,39], df.i[i,j])
}
}
基准。
在@Gregor发表评论后,我决定对这4个解决方案进行基准测试。正如预期的那样,每个优化都会产生显著的影响,他的完全矢量化解决方案是最快的
f <- function(df.i){
for (j in 1:ncol(df.i)) {
for (i in 1:nrow(df.i)) {
df.i[i,j] <- ifelse(is.na(df.i[i,j]), df.i[i,39], df.i[i,j])
}
}
df.i
}
f1 <- function(df.i1){
for (j in 1:ncol(df.i1)) {
df.i1[,j] <- ifelse(is.na(df.i1[, j]), df.i1[, 39], df.i1[, j])
}
df.i1
}
f2 <- function(df.i2){
df.i2 <- ifelse(is.na(df.i2), df.i2[, 39], df.i2)
df.i2
}
f3 <- function(df.i3){
df.i3[is.na(df.i3)] <- df.i3[row(df.i3)[is.na(df.i3)], 39]
df.i3
}
microbenchmark::microbenchmark(
two_loops = f(df.i),
one_loop = f1(df.i1),
ifelse = f2(df.i2),
vectorized = f3(df.i3)
)
#Unit: microseconds
# expr min lq mean median uq max neval
# two_loops 1125.017 1143.4995 1226.93089 1152.5665 1190.599 5209.431 100
# one_loop 492.945 500.7045 518.73060 504.9435 516.638 678.951 100
# ifelse 42.269 45.7770 50.55519 48.4140 50.470 198.533 100
#vectorized 12.626 14.5520 16.21975 15.6380 17.663 27.525 100
fifelse
是一个矢量化函数,因此您的内部循环可以替换为:df.i[,j]在对data.frames使用apply()
时要小心。apply()
将data.frame强制转换为矩阵,其中所有列都是相同的数据类型。在您的特定情况下,这似乎不是一个问题,但通常使用lappy()
更安全,如果else
是一个向量化函数,那么您的内部循环可以替换为:df.i[,j]使用apply()时要小心
使用data.frames.apply()
将data.frames强制到所有列都是相同数据类型的矩阵中。在您的特定情况下,这似乎不是问题,但通常使用lappy()
。完全矢量化,无ifelse
:df.i3[is.na(df.i3)]=df.i3[行(df.i3)[is.na(df.i3)],39]
(对于循环,无ifelse
,将内行替换为df.i1[is.na(df.i1[,j])@Gregor谢谢,我使用了第一条注释,请参见编辑。完全矢量化,无ifelse
:df.i3[is.na(df.i3)]=df.i3[row(df.i3)[is.na(df.i3)],39]
(对于循环,没有ifelse
,将内行替换为df.i1[is.na(df.i1[,j]),j]@Gregor谢谢,我使用了第一条注释,请参见编辑。