R 如何优化创建新数据帧的循环

R 如何优化创建新数据帧的循环,r,loops,R,Loops,我已经创建了一个可以工作的代码,但我相信它可以通过为循环重放,运行得更快 旧版本(可以跳过) 基本上,我有一个非常大的矩阵D和两个向量,pop和trainSetSongs。矩阵太大,在这里复制它变得毫无意义,因此让我们使用随机数据: D <- matrix(rnorm(44158666), ncol = 7199, nrow = 6134) pop <- rnorm(6134) trainSetSongs <- rnorm(7199) 基本上,record2在所使用的D中的每

我已经创建了一个可以工作的代码,但我相信它可以通过为循环重放
,运行得更快

旧版本(可以跳过)

基本上,我有一个非常大的矩阵
D
和两个向量,
pop
trainSetSongs
。矩阵太大,在这里复制它变得毫无意义,因此让我们使用随机数据:

D <- matrix(rnorm(44158666), ncol = 7199, nrow = 6134)
pop <- rnorm(6134)
trainSetSongs <- rnorm(7199)
基本上,
record2
在所使用的
D
中的每一列都有一个条目(并非所有条目都有,因为这太慢了)。第二列给出了一些复杂的东西,也许最好通过查看代码来理解。它是
pop
中的
i
th值(
i
标记
D
这一过程发生的行)和
trainSetSongs中的
j
值之间差值的绝对值的平均值。由于
trainSetSongs
的索引最初对应于
D
的列,因此所选
trainSetSongs
的值是矩阵中值最低的值。因此,
j
标记此过程发生的列数

我知道这很让人困惑(至少对我来说是这样;我经常发现自己在反复思考这一切意味着什么)。我的目标是让一段代码不使用
进行循环(或者不经常使用它们?),也许可以通过使用
apply
transmute
或其他类似函数来实现

编辑:新版本

在阅读了注释之后,我尽可能地改进了代码,但我不知道如何绕过
add_row()
,我还认为有很多方法可以改进我没有想到的代码

如注释所示,试验数据减少为:

set.seed(123)

D <- matrix(rnorm(50*20), ncol = 50, nrow = 20)
pop <- rnorm(20)
trainSetSongs <- rnorm(50)
代码的其余部分完全相同。我还决定对数据进行可视化:

record2 <- record %>%
  group_by(col) %>%
  summarise(r = mean(r))

ggplot(record2, aes(x = col, y = r))+
  geom_line(alpha = 0.5)+
  theme_minimal()+
  xlab("Number of Training Songs")+
  ylab("R")
record2%
分组依据(列)%>%
总结(r=平均值(r))
ggplot(记录2,aes(x=col,y=r))+
几何线(α=0.5)+
主题_极小值()+
xlab(“训练歌曲的数量”)+
ylab(“R”)
使用此种子和此代码,可视化绘图生成的内容以后可以更容易地进行比较


我花了一点时间分解您的代码,但首先,这里是更小(更快)的代码:

set.seed(123)

D向
数据帧
(和
tibble
)迭代添加行是一件坏事(
add_行
)应该非常谨慎地使用,对于重复添加东西来说,这是一个糟糕的设计选择)。这种反实践属于第二个循环(“成长对象”一章),因为每次添加任何行时,它都必须对所有行进行完整复制,而且这种扩展非常严重。这里还有其他低效之处。例如,
pop%>%n(i)
的速度大约是
pop[i]
的20倍,后者在我看来更具可读性;类似地,
DRow%>%head(j)
head(DRow[j,])
。您的内部
for
循环可能会减少(矢量化)。坦率地说,为了获得更多帮助,我建议您将此问题的大小从
44158666
减少到类似
40
的大小,使用
set.seed
控制随机性,显示输出,然后从那里开始。很明显,一个40号的例子很好地说明了需要做的事情是该尺寸的100万倍,因此效率是一件好事。但是44米的例子比40米的例子更难表达。好吧,我试着按照你的建议去做。但是,我不知道如何消除
add_row()
,也不知道如何消除
循环的任何
。这是我最需要帮助的地方(任何其他提高代码效率的方法也都会受到赞赏)。哇,太好了!我将深入研究你的代码,它是完美的!非常感谢。
record <- tibble(r = numeric(), row = numeric(), col = numeric())

for (i in 1:20) {
  r <- rep(0, 50)
  DRow <- order(D[i,])
  popi <- pop[i]
  for (j in 1:50) {
    r[j] <- mean(trainSetSongs[head(DRow,j)]) - popi
  }
  record <- record %>%
    add_row(r = abs(r), row = i, col = 1:50)
}
record2 <- record %>%
  group_by(col) %>%
  summarise(r = mean(r))

ggplot(record2, aes(x = col, y = r))+
  geom_line(alpha = 0.5)+
  theme_minimal()+
  xlab("Number of Training Songs")+
  ylab("R")