这个 R 语法是如何工作的?通过 [apply() with match()] 在 for 循环中选择性地使用 gsub()
How does this R syntax work? Selective use of gsub() by [apply() with match()] inside a for loop
前段时间我从Whosebug改编了一些代码,但我一直无法找到原来的post。该代码适用于我的应用程序,但我并没有真正 'get' 语法。 (代码通过将数值数据值与 'new_labels' 向量中的相应值进行匹配,用特定字符串覆盖数据中的数值。匹配是特定于列的。)
参考下面的代码,有人可以解释一下 [apply] 子句是如何被用来指定 gsub() 在哪里进行替换的吗?或者换句话说,这种语法是如何工作的?为什么 apply 在这里影响 gsub() ?更好的是,是否有更简单的方法来执行此操作?
# reproducible example
# fake data
dat <- tibble(var1 = c(1,NA, 1,1,1,2,1,NA,1,1),
var2 = c(NA,1,NA,NA,NA,NA,NA,1,NA,NA),
var3 = c(2,2,NA,2,NA,1,2,NA,NA,NA),
var4 = c(NA,NA,2,NA,2,NA,NA,2,2,2))
# names of columns in fake data
variables <- names(dat)
# names of new labels to replace the numeric values
new_labels <- c("elf", "hobbit", "wizard", "ranger")
# empty list
llist <- list(ones = data.frame(matrix(ncol=4,nrow=10)),
twos = data.frame(matrix(ncol=4,nrow=10)))
names(llist[[1]]) <- letters[1:length(new_labels)]
names(llist[[2]]) <- letters[1:length(new_labels)]
# for loops
for(j in 1:2){
for(i in 1:length(new_labels)){
llist[[j]][, letters[i]] <- gsub(variables[i], new_labels[i], names(dat[,variables[i]]))[apply(dat[,variables[i]], 1, match, x= j)]
}
llist[[j]][is.na(llist[[j]])] <- ""
}
让我们把它从循环中拉出来,看看到底发生了什么。
gsub(variables[1], new_labels[1], names(dat[,variables[1]]))[apply(dat[,variables[1]], 1, match, x = 1)]
[1] "elf" NA "elf" "elf" "elf" NA "elf" NA "elf" "elf"
查看 ?apply
的帮助:apply(X, MARGIN, FUN, ...)
,其中 x
是我们首先循环到的 dat
的列,1
是边距,?match
是它应用的函数,x = j
是 match
循环的一部分,在 1
和 2
之间(来自 for(j in 1:2)
).例如,如果它找到 1
的匹配项,则替换为 1
.
apply(dat[,variables[1]], 1, match, x = 1)
[1] 1 NA 1 1 1 NA 1 NA 1 1
并且 gsub
将第一个 new_labels
名称 (elf)
替换为第一个 variables
名称 (var1)
,并将其写入匹配元素letters[i]
(letters[1]
是 a
)。因此它在匹配 a
.
的列中找到 llist
的第一个 list
元素(名为 ones
)
它为每个标签的所有 1
值重复此操作,然后为每个列表元素重复此操作,然后为所有 2
值重复此操作。第一行变成第二行。
[1] 1 NA 1 1 1 NA 1 NA 1 1
[1] "elf" NA "elf" "elf" "elf" NA "elf" NA "elf" "elf"
这是一个相当优雅的过程。
这是一个没有循环的分步说明,因此您可以从本质上了解循环的作用。
dat2 <- as.data.frame(dat)
names(dat2) <- new_labels
dat2 <- list(dat2, dat2)
dat2[[1]][dat2[[1]] == 2] <- NA
dat2[[2]][dat2[[2]] == 1] <- NA
w1 <- which(dat2[[1]] == TRUE, arr.ind = TRUE)
w2 <- which(dat2[[2]] == 2, arr.ind = TRUE)
dat2[[1]][w1] <- colnames(dat2[[1]])[w1[,"col"]]
dat2[[2]][w2] <- colnames(dat2[[2]])[w2[,"col"]]
dat2 <- lapply(dat2, function(x) { x[is.na(x)] <- "" ; x})
[[1]]
elf hobbit wizard ranger
1 elf
2 hobbit
3 elf
4 elf
5 elf
6 wizard
7 elf
8 hobbit
9 elf
10 elf
[[2]]
elf hobbit wizard ranger
1 wizard
2 wizard
3 ranger
4 wizard
5 ranger
6 elf
7 wizard
8 ranger
9 ranger
10 ranger
这里有很多嵌套,但是要理解功能,最好的方法是运行控制台中嵌套最多的部分并向外工作。
假设 i = 1 且 j = 1
apply(dat[,variables[i]], 1, match, x= j)
apply 正在输入数据的子集,即 "var1" 列。然后将匹配应用于该列的每个索引,return如果索引中的值与 x 参数匹配则为 1,否则 returns NA。
这个向量,我们称之为 vec
,然后传递给 names(dat[,variables[i]]))[vec]
。
names(dat[,variables[i]])
似乎只是 return variable[i]
所以在这个例子中看起来有点毫无意义。
names(dat[,variables[i]]))[vec]
用 variables[i]
中的值替换 vec
中的每个值 1
最后,在gsub(pattern = variables[i], new_labels[i], new.vec)
其中 new.vec
是 names(dat[,variables[i]]))[vec]
前段时间我从Whosebug改编了一些代码,但我一直无法找到原来的post。该代码适用于我的应用程序,但我并没有真正 'get' 语法。 (代码通过将数值数据值与 'new_labels' 向量中的相应值进行匹配,用特定字符串覆盖数据中的数值。匹配是特定于列的。)
参考下面的代码,有人可以解释一下 [apply] 子句是如何被用来指定 gsub() 在哪里进行替换的吗?或者换句话说,这种语法是如何工作的?为什么 apply 在这里影响 gsub() ?更好的是,是否有更简单的方法来执行此操作?
# reproducible example
# fake data
dat <- tibble(var1 = c(1,NA, 1,1,1,2,1,NA,1,1),
var2 = c(NA,1,NA,NA,NA,NA,NA,1,NA,NA),
var3 = c(2,2,NA,2,NA,1,2,NA,NA,NA),
var4 = c(NA,NA,2,NA,2,NA,NA,2,2,2))
# names of columns in fake data
variables <- names(dat)
# names of new labels to replace the numeric values
new_labels <- c("elf", "hobbit", "wizard", "ranger")
# empty list
llist <- list(ones = data.frame(matrix(ncol=4,nrow=10)),
twos = data.frame(matrix(ncol=4,nrow=10)))
names(llist[[1]]) <- letters[1:length(new_labels)]
names(llist[[2]]) <- letters[1:length(new_labels)]
# for loops
for(j in 1:2){
for(i in 1:length(new_labels)){
llist[[j]][, letters[i]] <- gsub(variables[i], new_labels[i], names(dat[,variables[i]]))[apply(dat[,variables[i]], 1, match, x= j)]
}
llist[[j]][is.na(llist[[j]])] <- ""
}
让我们把它从循环中拉出来,看看到底发生了什么。
gsub(variables[1], new_labels[1], names(dat[,variables[1]]))[apply(dat[,variables[1]], 1, match, x = 1)]
[1] "elf" NA "elf" "elf" "elf" NA "elf" NA "elf" "elf"
查看 ?apply
的帮助:apply(X, MARGIN, FUN, ...)
,其中 x
是我们首先循环到的 dat
的列,1
是边距,?match
是它应用的函数,x = j
是 match
循环的一部分,在 1
和 2
之间(来自 for(j in 1:2)
).例如,如果它找到 1
的匹配项,则替换为 1
.
apply(dat[,variables[1]], 1, match, x = 1)
[1] 1 NA 1 1 1 NA 1 NA 1 1
并且 gsub
将第一个 new_labels
名称 (elf)
替换为第一个 variables
名称 (var1)
,并将其写入匹配元素letters[i]
(letters[1]
是 a
)。因此它在匹配 a
.
llist
的第一个 list
元素(名为 ones
)
它为每个标签的所有 1
值重复此操作,然后为每个列表元素重复此操作,然后为所有 2
值重复此操作。第一行变成第二行。
[1] 1 NA 1 1 1 NA 1 NA 1 1
[1] "elf" NA "elf" "elf" "elf" NA "elf" NA "elf" "elf"
这是一个相当优雅的过程。
这是一个没有循环的分步说明,因此您可以从本质上了解循环的作用。
dat2 <- as.data.frame(dat)
names(dat2) <- new_labels
dat2 <- list(dat2, dat2)
dat2[[1]][dat2[[1]] == 2] <- NA
dat2[[2]][dat2[[2]] == 1] <- NA
w1 <- which(dat2[[1]] == TRUE, arr.ind = TRUE)
w2 <- which(dat2[[2]] == 2, arr.ind = TRUE)
dat2[[1]][w1] <- colnames(dat2[[1]])[w1[,"col"]]
dat2[[2]][w2] <- colnames(dat2[[2]])[w2[,"col"]]
dat2 <- lapply(dat2, function(x) { x[is.na(x)] <- "" ; x})
[[1]]
elf hobbit wizard ranger
1 elf
2 hobbit
3 elf
4 elf
5 elf
6 wizard
7 elf
8 hobbit
9 elf
10 elf
[[2]]
elf hobbit wizard ranger
1 wizard
2 wizard
3 ranger
4 wizard
5 ranger
6 elf
7 wizard
8 ranger
9 ranger
10 ranger
这里有很多嵌套,但是要理解功能,最好的方法是运行控制台中嵌套最多的部分并向外工作。
假设 i = 1 且 j = 1
apply(dat[,variables[i]], 1, match, x= j)
apply 正在输入数据的子集,即 "var1" 列。然后将匹配应用于该列的每个索引,return如果索引中的值与 x 参数匹配则为 1,否则 returns NA。
这个向量,我们称之为 vec
,然后传递给 names(dat[,variables[i]]))[vec]
。
names(dat[,variables[i]])
似乎只是 return variable[i]
所以在这个例子中看起来有点毫无意义。
names(dat[,variables[i]]))[vec]
用 variables[i]
vec
中的每个值 1
最后,在gsub(pattern = variables[i], new_labels[i], new.vec)
其中 new.vec
是 names(dat[,variables[i]]))[vec]