有没有一种更快的方式来运行嵌套在两个for循环中的sapply?
我有一个大数据框架,上面有超过100万行表示几个个体的时间序列数据(在不同的列中有不同的个体数据)。 此外,我还有一个3D数组,其中包含“遭遇”帧编号,指示我要从时间序列中的哪个帧提取数据 对于给定的个人和遭遇类型,我想提取一个时间序列,例如100帧。但是,由于我对每种会议类型和每一个人都有许多重复,所以我想直接计算每一个人和每一次会面类型的平均时间序列 我设法做到这一点,使用sapply嵌入在两个for循环中。然而,运行这些for循环非常慢,我现在想知道在R中是否有更快的方法来实现这个计算,或者我是否应该在C++中实现。下面是我的代码和我的一小部分数据:有没有一种更快的方式来运行嵌套在两个for循环中的sapply?,r,for-loop,sapply,R,For Loop,Sapply,我有一个大数据框架,上面有超过100万行表示几个个体的时间序列数据(在不同的列中有不同的个体数据)。 此外,我还有一个3D数组,其中包含“遭遇”帧编号,指示我要从时间序列中的哪个帧提取数据 对于给定的个人和遭遇类型,我想提取一个时间序列,例如100帧。但是,由于我对每种会议类型和每一个人都有许多重复,所以我想直接计算每一个人和每一次会面类型的平均时间序列 我设法做到这一点,使用sapply嵌入在两个for循环中。然而,运行这些for循环非常慢,我现在想知道在R中是否有更快的方法来实现这个计算,或
nb_ind = 3;
response_duration = 100;
nb_meeting_types = 2;
nb_variables = 2;
speed_offset = 2;
MEETING_START_OFFSET = 50;
replicate = 20;
# behavior_data is a data frame with columns: frame,speed1,head1,speed2,head2,speed3,head3
# there are about 1 million rows
dim(behavior_data)
[1] 1080000 7
head(behavior_data)
frame speed1 head1 speed2 headd2 speed3 head3
1 0 0 25 2.4 179 1.1 16
2 1 1.5 20 2.0 -175 1.6 27
3 2 1.6 28 2.0 -178 1.0 37
4 3 0.8 56 1.6 170 0.8 37
5 4 0.3 56 1.8 162 0 40
# encounters is an array with frame numbers of dimension [nb_ind,replicate,nb_meeting_types]
# these frame number correspond to starting points of meetings, for which I want to calculate the speed
dim(encounters)
[1] 3 20 2
head(encounters[,,1])
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16] [,17] [,18] [,19] [,20]
[1,] 12049 17693 23350 29018 34666 40327 68608 57293 74264 45980 113864 79922 119522 102552 51636 153462 91235 142151 159121 62948
[2,] 12036 17694 23352 29014 34674 40322 68606 57296 74268 45982 113865 79929 119521 102558 51639 153463 91242 142161 159168 62952
[3,] 12037 17694 23351 29011 34669 40329 68606 57298 74263 45985 NA 79921 NA 102550 51641 NA 91234 NA NA 62950
all_average_speeds = array(NaN, c(nb_ind, response_duration, nb_meeting_types))
for (j in 1:nb_ind){
#calculate the average speed response for each meeting type for a given individual
average_speed = numeric(0);
for (i in 1:nb_meeting_types){
# calculate the average speed response across all replicates of a given meeting type for a given individual
average_speed_type = sapply(1:response_duration, function(k){
mean(behavior_data[,(j-1)*nb_variables + speed_offset][which(behavior_data$frame == ((encounters[j,,i] + k-1) - MEETING_START_OFFSET)], na.rm=TRUE)
})
average_speed = rbind(average_speed, t(average_speed_type))
}
all_average_speeds[j,,] = average_speed;
}
从第一眼看,我无意中发现了内部循环中的rbind。这通常是个坏主意。尝试提前分配平均速度将拥有的所有内存和所有列和行(找到比
average\u speed=numeric(0);
)更好的内存和列,然后查看是否足够快。如果没有,请触摸工作回路。如果需要对循环进行一些尝试,请尝试外部循环的foreach
包中的foreach
循环。它使从循环到并行处理变得非常容易。请包含代码使用的数据集-更改数字使其匹配,或者在此处放置更大的部分。这可能是完全矢量化的,我能看到的Other快速加速如果“frame”列等于行号,你可以用位置子集替换sapply。@Bernhard。按照建议,我替换了平均速度=数值(0)
使用预分配数组填充NaN,但在执行时间方面没有差异。对于我的部分数据集(15个人,时间序列为1090504帧,响应持续时间为1200帧,5种会议类型),当我使用数字时,时间为23.91分钟,当我使用预分配数组时,时间为23.94分钟。@jeremycg。我不明白你关于使用子集的建议。你能提供更多的细节吗。对于info,帧编号并不总是等于行编号,但由于帧编号是连续的且不断增加,因此偏移应该能够解释差异。另外,我的数据集似乎太大(450MB),无法上传到这里。为了进一步增加性能问题,我测试了代码,在嵌套for循环中添加了另一个sappy,执行代码所需的时间增加了一倍,这表明是sappy本身消耗了时间。如果我自己运行sapply,即通过设置I=1和j=1,则需要大约4.28分钟。有没有比我选择的更有效的方法来编写sappy函数?