【发布时间】:2020-07-08 12:25:56
【问题描述】:
我想加快创建成对矩阵的函数,该矩阵描述了在一组位置中,在所有其他对象之前和之后选择对象的次数。
这是一个例子df:
df <- data.frame(Shop = c("A","A","A","B","B","C","C","D","D","D","E","E","E"),
Fruit = c("apple", "orange", "pear",
"orange", "pear",
"pear", "apple",
"pear", "apple", "orange",
"pear", "apple", "orange"),
Order = c(1, 2, 3,
1, 2,
1, 2,
1, 2, 3,
1, 1, 1))
在每个Shop 中,Fruit 由给定Order 中的客户选择。
以下函数创建一个m x n 成对矩阵:
loop.function <- function(df){
fruits <- unique(df$Fruit)
nt <- length(fruits)
mat <- array(dim=c(nt,nt))
for(m in 1:nt){
for(n in 1:nt){
## filter df for each pair of fruit
xm <- df[df$Fruit == fruits[m],]
xn <- df[df$Fruit == fruits[n],]
## index instances when a pair of fruit are picked in same shop
mm <- match(xm$Shop, xn$Shop)
## filter xm and xn based on mm
xm <- xm[! is.na(mm),]
xn <- xn[mm[! is.na(mm)],]
## assign number of times fruit[m] is picked after fruit[n] to mat[m,n]
mat[m,n] <- sum(xn$Order < xm$Order)
}
}
row.names(mat) <- fruits
colnames(mat) <- fruits
return(mat)
}
其中mat[m,n] 是fruits[m] 被选中的次数 fruits[n]。 mat[n,m] 是fruits[m] 在之前 fruits[n] 被选中的次数。如果同时采摘成对水果(例如在ShopE),则不会记录。
查看预期输出:
>loop.function(df)
apple orange pear
apple 0 0 2
orange 2 0 1
pear 1 2 0
您可以在这里看到pear 在apple 之前被选择了两次(在Shop C 和D 中),apple 在pear 之前被选择了一次(在Shop @987654346 @)。
我正在努力提高我对矢量化的了解,尤其是在循环的地方,所以我想知道如何对这个循环进行矢量化。
(我感觉可能有使用outer()的解决方案,但我对矢量化函数的了解仍然非常有限。)
更新
查看times = 10000loop.function()、tidyverse.function()、loop.function2()、datatable.function() 和 loop.function.TMS() 的真实数据基准测试:
Unit: milliseconds
expr min lq mean median uq max neval cld
loop.function(dat) 186.588600 202.78350 225.724249 215.56575 234.035750 999.8234 10000 e
tidyverse.function(dat) 21.523400 22.93695 26.795815 23.67290 26.862700 295.7456 10000 c
loop.function2(dat) 119.695400 126.48825 142.568758 135.23555 148.876100 929.0066 10000 d
datatable.function(dat) 8.517600 9.28085 10.644163 9.97835 10.766749 215.3245 10000 b
loop.function.TMS(dat) 4.482001 5.08030 5.916408 5.38215 5.833699 77.1935 10000 a
对我来说最有趣的结果可能是tidyverse.function() 在真实数据上的表现。稍后我将不得不尝试添加 Rccp 解决方案 - 我无法让它们处理真实数据。
感谢大家对这篇文章的兴趣和回答 - 我的目的是学习和提高性能,从给出的所有 cmets 和解决方案中肯定有很多东西可以学习。谢谢!
【问题讨论】:
-
嗨,您的实际数据集的维度是多少?您将调用此函数多少次?
-
对于 Shop E,Order 也应该是 1,2,3 而不是 1,1,1?
-
关于尺寸:通常,df 可能包含在约 100 家商店订购的约 15 种水果。它在单次运行中被调用约 1K 次,但是,使用引导程序有 10k 次运行。在 E 店:不,这不是一个错误,我希望该示例包含同时采摘所有水果的情况,因为函数忽略这些情况很重要
-
@chinsoon12 这个问题有一些相似之处,但我的问题中的排序增加了一层额外的复杂性:stackoverflow.com/questions/19891278/…>
-
@jayb 感谢您发布一个小型玩具数据集,供人们试用他们的代码。但是,由于您的问题是关于速度和性能的,您能否在您的问题中提供与基准测试相关的大小和复杂性的数据集。如果没有这些数据,就很难/不可能评估答案。还要描述您期望的改进。谢谢。
标签: r performance loops matrix vectorization