首页 > 解决方案 > 如何将 for 循环转换为在 r 中应用

问题描述

我有以下循环。我正在尝试将其转换为使用apply函数而不是循环,但我不知道如何重写代码。

for (i in 1:dim(Y)[2]) {
     K = K_origin
     print(i)

     e = lmmlite::eigen_rotation(K, t(Y)[i,], use_cpp = T)
     VC = lmmlite::fitLMM(
       e$Kva,
       e$y,
       e$X,
       reml = T,
       use_cpp = T,
       tol = 1e-6,
       check_boundary = T
     )

     write.table(
       VC$sigmasq_g,
       "Vg_temp.txt",
       row.names = F,
       col.names = F,
       append = T,
       quote = F,
       sep = "\n"
     )
     write.table(
       VC$sigmasq_e,
       "Ve_temp.txt",
       row.names = F,
       col.names = F,
       append = T,
       quote = F,
       sep = "\n"
     )
}

我想要这样的结果

Vg                  Ve
1.15521325512487    0.755118863386436
0.579039221720728   1.21733212837417
0.372439354137817   0.296327744338075
0.0668396114713355  0.300417453013007
0.00771158861391208 0.100176380868691
0.210174870097273   0.141907482831872

标签: rfor-loopapply

解决方案


R 的apply函数必须表述为 1)要迭代的东西,以及 2)应用于 (1) 中每个元素的函数。

但!您是否会从将特定循环转换为应用程序中获得任何好处,这是值得怀疑的。如果您的循环很慢,我猜这是由于执行的操作,而不是“R 在循环上很慢”。如果在 中只有 6 行Y,则将循环重新制定为应用程序将一无所获!

对于您的循环,每个i都是独立的(与循环相反i,当结果取决于 的计算时i-1)。所以这使得重新制定非常容易。一般来说,

for (i in some_sequence) {
  do something with i
}

可以重新表述为

my_do_something <- function(i) {
  do something
}

for (i in some_sequence) {
  my_do_something(i)
}

可以再次直接重新表述为

sapply(some_sequence, my_do_something)

在你的情况下,这将是

my_rotate <- function(i) {
  e = lmmlite::eigen_rotation(K, t(Y)[i,], use_cpp = T)
  VC = lmmlite::fitLMM( ... )
  write.table(...)
  write.table(...)
  NULL
}

sapply(seq_len(dim(Y)[2]), my_rotate)

请注意我是如何NULL在函数底部添加的?那是因为apply将从迭代函数中收集返回值;write.table返回不可见的写入数据。试试没有最后一个的函数NULL,看看apply返回什么。

但是等等,还有更多!

由于您正在迭代特定的行(并特别询问apply),所以让我们删除这些i东西并将该行提供给函数:

my_rotate_row <- function(x) {
  # you might or might not need to either use x as is, transpose it as t(x) or double transpose it, t(t(x)), to get the correct orientation. 
  # x is most likely an atomic vector, whereas `eigen_rotation` might be requiring either a row-vector or a column vector.

  e = lmmlite::eigen_rotation(K, x, use_cpp = T)
  VC = lmmlite::fitLMM( ... )
  # lets collect data directly into a data.frame or matrix, instead of using files:
  c(VC$sigmasq_g, VC$sigmasq_e)
}

现在您可以使用apply

apply(Y, 2, my_rotate_row)

推荐阅读