簡體   English   中英

如何為大數據加速 R 中的嵌套 for 循環,目前在其中使用 append 並輸出大列表? 如何矢量化?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM