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")