[英]How to speed up nested for loop in R for large data, which currently uses append in it and outputs large lists? How to vectorise?
希望這次我能做到這一點,之前我發布過(盡管那是幾年前的事了),我記得我的問題中沒有太多好的例子/細節。
因此,我在 R 中使用了 quakes 數據集,希望這個示例更容易理解。
希望這個例子很清楚。
我有一個 function myfunc:
myfunc <- function(x,y){
z <- (x - y)^2
return(z)
}
所以我想要做的是,對 Quakes 數據集中的每一行都使用這個 function。 因此,例如使用數據集的頭部:
> library(datasets)
> data(quakes)
> head(quakes)
lat long depth mag stations
1 -20.42 181.62 562 4.8 41
2 -20.62 181.03 650 4.2 15
3 -26.00 184.10 42 5.4 43
4 -17.97 181.66 626 4.1 19
5 -20.42 181.96 649 4.0 11
6 -19.68 184.31 195 4.0 12
>
第一行將使用myfunc
function 和數據集中的每一行,然后第二行對於數據集中的每一行都會發生同樣的情況,等等。
我目前正在使用以下嵌套 for 循環並附加到向量。 然后我將它們全部cbind
在一起。
lat <- vector()
long <- vector()
depth <- vector()
mag <- vector()
stations <- vector()
for (i in 1:6){
for (j in 1:6){
lat <- append(lat,(myfunc(quakes$lat[i], quakes$lat[j])))
long <- append(long,(myfunc(quakes$long[i], quakes$long[j])))
depth <- append(depth,(myfunc(quakes$depth[i], quakes$depth[j])))
mag <- append(mag,(myfunc(quakes$mag[i], quakes$mag[j])))
stations <- append(stations,(myfunc(quakes$stations[i], quakes$stations[j])))
}
}
final <- as.data.frame(cbind(lat, long, depth, mag, stations))
我正在執行此操作的實際數據有 1244 行和 13 列,並且似乎沒有運行完整的代碼(或者需要太長時間,因為我通常會在接近 1 小時時停止)。 我已經在 191 行上嘗試了我的正常代碼,並且通常在 1 分鍾內運行良好。
我已經在網上閱讀了這方面的內容,很明顯 append 在 for 循環中不好做。 我遇到過sapply
、矢量化和一些例子。 但是,我真的很難讓這個工作和 output 與它目前的工作完全相同。
我想知道是否有人可以幫助我解決這個問題/有有用的建議?
謝謝你。
更新:只是補充一點,我將使用 cbind function 將兩列綁定到結果上。 例如,如果地震數據有一個分配給每一行的字母,即 A、B、C,我希望在 cbind 之后顯示最終的 output
ID lat long depth mag stations
1 A -20.42 181.62 562 4.8 41
2 B -20.62 181.03 650 4.2 15
3 C -26.00 184.10 42 5.4 43
4 D -17.97 181.66 626 4.1 19
5 E -20.42 181.96 649 4.0 11
6 F -19.68 184.31 195 4.0 12
至
ID1 ID2 long depth mag stations
1 A A (row from final)
2 A B (row from final)
3 A C (row from final)
4 B A (row from final)
5 B B (row from final)
6 B C (row from final)
等等
目前我正在使用類似的東西:
ID1 <- vector()
ID2 <- vector()
for (i in 1:1244){
for (j in 1:1244){
ID1 <- append(ID1,quakes$ID[i])
ID2 <- append(ID2,quakes$ID[j])
}
}
它當前返回大型字符列表。 您對如何改進有什么建議嗎?
很抱歉在我原來的帖子中沒有提到這一點。
這里有兩個功能。
第一個是我的原始答案是 function。根據評論,它已經比問題中的原始答案快,但第二個 function 的速度大約是原來的兩倍。 memory 效率也更高。
myfunc <- function(x, y){
z <- (x - y)^2
return(z)
}
slower <- function(X, fun = myfunc){
fun <- match.fun(fun)
res <- sapply(X, function(x) {
o <- outer(x, x, fun)
o[row(o) != col(o)]
})
as.data.frame(res)
}
faster <- function(X, fun){
f <- function(x, fun = myfunc){
y <- lapply(seq_along(x), function(i){
fun(x[i], x[-i])
})
unlist(y)
}
fun <- match.fun(fun)
res <- sapply(X, f, fun = fun)
as.data.frame(res)
}
測試兩者,結果是相同的。
res1 <- slower(quakes, myfunc)
res2 <- faster(quakes, myfunc)
identical(res1, res2)
#[1] TRUE
現在來看 package microbenchmark
的時序。
library(microbenchmark)
mb <- microbenchmark(
outer = slower(quakes, myfunc),
fastr = faster(quakes, myfunc),
times = 10
)
print(mb, unit = "relative", order = "median")
#Unit: relative
# expr min lq mean median uq max neval cld
# fastr 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 10 a
# outer 1.545283 1.650968 1.970562 2.159856 2.762724 1.332896 10 b
ggplot2::autoplot(mb)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.