我在列表中有data.frames,通常,当我想要居中数据时,我使用循环(如下例所示)。我想使用“apply”系列的一些功能,但我无法弄清楚如何编写代码。
我的数据示例:
env <- list (data.frame(a=c(-1.08, -1.07, -1.07),
b=c( 4.61, 4.59, 4.59),
c=c( 3.46, 3.56, 3.52)),
data.frame(a=c( 3.93, 3.94, 3.92),
b=c(-6.69, -6.72, -6.68),
c=c( 3.04, 3.08, 3.03)))
我将使用的值将它们置于中心位置:
d <- c(a=10.20, b=-10.91, c=11.89)
我常用的循环类型:
for(i in 1:length(env)) {
env[[i]][, 1] <- env[[i]][, 1] - d[1]
env[[i]][, 2] <- env[[i]][, 2] - d[2]
env[[i]][, 3] <- env[[i]][, 3] - d[3]
}
有没有办法使用“apply”系列的函数来完成我在上面循环中做的同样的事情?
答案 0 :(得分:8)
这里有两点可以简化:循环遍历列表元素并分别减去d
中的每个值。
要替换for循环,您可以使用lapply
(“l”,因为我们在列表上进行迭代)。
# Run function for every element i in list env
lapply(env, function(i))
为了简化减法,你可以:
t(i)
t(i) - d
t(t(i) - d)
所以最终的代码是:
lapply(env, function(i) t(t(i) - d))
答案 1 :(得分:3)
1)扫描使用sweep
生成数据框列表:
lapply(env, sweep, 2, d, "-")
,并提供:
[[1]]
a b c
1 -11.28 15.52 -8.43
2 -11.27 15.50 -8.33
3 -11.27 15.50 -8.37
[[2]]
a b c
1 -6.27 4.22 -8.85
2 -6.26 4.19 -8.81
3 -6.28 4.23 -8.86
另请参阅How to divide each row of a matrix by elements of a vector in R了解与sweep
等效或几乎等效的多个表达式。
2)缩放或像这样使用scale
;但是,它给出了一个数字矩阵列表而不是数据帧列表:
lapply(env, scale, d, FALSE)
,并提供:
[[1]]
a b c
[1,] -11.28 15.52 -8.43
[2,] -11.27 15.50 -8.33
[3,] -11.27 15.50 -8.37
attr(,"scaled:center")
a b c
10.20 -10.91 11.89
[[2]]
a b c
[1,] -6.27 4.22 -8.85
[2,] -6.26 4.19 -8.81
[3,] -6.28 4.23 -8.86
attr(,"scaled:center")
a b c
10.20 -10.91 11.89
答案 2 :(得分:1)
以下是使用lapply
nrows <- 3
lapply(env, function(x) x - matrix(rep(d, nrows), nrow = nrows, byrow = TRUE))
答案 3 :(得分:0)
我的PoGibas' answer(+1)版本:
lapply(lapply(lapply(env, t), "-", d), t)
它完全相同:
data.frame
个对象d
matrix
个对象,这不是OP想要的。我认为它更彻底地使用矢量化它会更快一点。但情况并非如此。
microbenchmark(
f1 = lapply(env, function(i) t(t(i) - d)),
f2 = lapply(lapply(lapply(env, t), "-", d), t), times = 1E5L)
#Unit: microseconds
# expr min lq mean median uq max neval cld
# f1 99.838 103.104 114.8280 104.970 108.702 106230.106 1e+05 a
# f2 103.570 107.303 118.9683 110.102 113.834 7765.414 1e+05 b
答案 4 :(得分:0)
非常感谢您快速而有趣的答案。
我在microbenchmark :: microbenchmark函数中运行了你发布的所有解决方案。
对于生成矩阵列表的解决方案,我(仅使用我当前的R知识)添加了一条额外的行,将它们转换为数据帧列表。
env1 <- env
env2 <- env
env3 <- env
env4 <- env
env5 <- env
env6 <- env
env7 <- env
## install.packages
library("microbenchmark")
microbenchmark(
## 1; the original.
for(i in 1:length(env1)) {
env1[[i]][, 1] <- env1[[i]][, 1] - d[1]
env1[[i]][, 2] <- env1[[i]][, 2] - d[2]
env1[[i]][, 3] <- env1[[i]][, 3] - d[3]}
,
## 2
for(i in 1:length(env2)) {
for (j in 1:length(env2[[i]])) {
env2[[i]][, j] <- env2[[i]][, j] - d[j]
}
}
,
## 3
{env3 <- lapply(env3, function(i) t(t(i) - d))
env3 <- lapply(env3, function(i) as.data.frame(i))}
,
## 4
{env4 <- lapply(env4, scale, center=d, scale=FALSE)
env4 <- lapply(env4, function(i) as.data.frame(i))}
,
## 5
{nrows <- 3
env5 <- lapply(env5, function(x) x - matrix(rep(d, nrows), nrow =
nrows, byrow = TRUE))}
,
## 6
env6 <- lapply(env6, sweep, 2, d, "-")
,
## 7
{env7 <- lapply(lapply(lapply(env7, t), "-", d), t)
env7 <- lapply(env7, function(i) as.data.frame(i))}
)
## install.packages("compare")
library("compare")
identical(env1, env2)
identical(env1, env3)
identical(env1, env4)
identical(env1, env5)
identical(env1, env6)
identical(env1, env7)
正如您将看到的,所有线条都会生成相同的对象。
执行“microbenchmark”功能5次后,上述代码中的## 7解决方案速度更快,但解决方案## 3只是稍慢一点。
我将详细研究您提出的每个解决方案,并再次非常感谢您!
为表示感谢,请欣赏我喜欢的这首歌! https://www.youtube.com/watch?v=QnguI5OrfZ4
问候!
答案 5 :(得分:0)
您还可以使用map
函数来完成相同的操作。具体来说,您可以使用map()
循环列表env
,然后map2()
循环(并发)d
以及各个数据框env[[1]]
和{ {1}}。 env[[2]]
是数据集中的地方。
j-k
屈服,
library('purrr')
map(env, function(i){
map2(i, d, function(j,k){
j-k
})
})