2015-12-11 26 views
-1

sapplyreplicate(等)中的函數運行指定的次數。放sapply(1:N, function(n){expr})將執行N次的expr。假設我想讓sapply在m運行後停止。這可能沒有發生錯誤? break不起作用,並且forwhile循環在我的上下文中會太慢。退出* apply

一種近乎:

sapply(1:N, function(n){ 
    #some expression 
    if(identical(n, m)) break 
}) 

除了休息不工作。

我想要做的事:

創建功能在很大程度上定義的結構,但未知長度(二進制)數據文件的讀取。使用replicatearray(readBin(...), ...)是我發現的最好的方法,但是當NA開始返回(即文件結束)時,我希望它停止。

+4

據我所知,'for'迴路中的R支持和_can_使用,儘管名聲不好。認爲'sapply'比'for for'循環更快是一種常見的誤解。 – nicola

+0

我的經驗是'for'比'apply'家族慢得多,我試着用'for'來完成這個任務(在我真正瞭解'* apply'之前)。是否有一些技巧可以讓工作更快? – Bazz

+1

'for'的速度並不比'* apply'慢很多。它通常(稍微)比'lapply'和'vapply'慢。根據情況,可能比'sapply'更慢或更快。它通常比'申請'快。這提供了你正確地編寫循環和(比其他更多的事情)避免增長對象和正確預分配。對你的嘗試更詳細,你可能會有幫助。 – nicola

回答

1

的部分解決辦法可以是在全局控制的形式可變

i<-TRUE 
unlist(sapply(1:10, function(x){if(i){ if(x>=4)(i<<-FALSE); 2*x;}})) 

使用盡管它仍然運行N次,至少它不執行該操作每次和備用資源。 我不能確切地說明爲什麼簡化不能一直工作,我不得不使用unlist。

+0

謝謝 - 這是一個好主意。我認爲它不會在'sapply'內簡化,因爲它想保留'NULL'值。 – Bazz

+0

試過這個,比使用'for' /'while' /'repeat'循環快得多。 0.25秒,而4.8秒。當我輸入較大的文件時會有很大的不同。我仍然堅信'for'可以與'* apply'競爭。 – Bazz

+0

很高興能有所幫助。 –

1

除了從for VS *apply戰鬥中,如果你的問題是使用readBin直至達到文件的末尾,請記住:

  • 你可以使用一個(小)高估n(中要閱讀的元素數量);
  • 你可以通過file.info(filename)$size知道文件的大小;那麼你可以自己估計文件中包含了多少個元素。

例如,假設您正在讀取整數(四個字節)的值。只需嘗試:

readBin(con,"int",n=file.info(filename)$size/4+10) 

一次性讀取所有文件。 +10是有點高估。

+0

謝謝。這很有幫助。另外一個複雜的情況是文件中有16字節的字符串,也就是每個數組代表的內容以及文件中的4字節整數以及元數據。有兩個整數(4),一個字符串(16),三個整數(4)給出數組的維數,然後是一個雙精度數組,重複未指定的次數。確實,你可以粗略地知道有多少個數組,所以我現在可以進步了。有關更多詳細信息,請參閱http://water.usgs.gov/ogw/modflow/MODFLOW-2005-Guide/ - > FAQ - > L。 – Bazz

0

想到我會張貼我想出來的。 cbb是正在構建的陣列。在這個糟糕的例子中,cbb逐漸建立爲一個數組,使用abind。在每個步驟中,cbb都必須重新評估,因此每個連續步驟都會變慢 - 這是一個成長中的對象。在這個很好的例子中,cbb被構建爲一個列表,並且每個步驟都會聲明一個新的列表條目。 R不需要每次重新評估現有列表。陣列在末尾與do.call(abind, c(cbb, list(along = 4)))綁定在一起。

我發現有幫助的一件事是把cat(".")放在循環中。如果點打印速度變慢,那可能表明物體在不斷增長。舉個很好的例子,點或多或少以恆定的速率打印。這個好例子比糟糕快十倍。

BAD:

cbb <- array(NA, c(N1, N2, N3, 0)) 
repeat{ 
    sptsnew <- readBin(to.read, "integer", 2L, 4L) 
    if(identical(sptsnew, integer(0))){cat("\nend of file\n"); break} 
    ... #reading array metadata 
    cbb <- abind(cbb, array(readBin(to.read, "double", N1*N2*N3, 4L), c(N1, N2, N3, 1)), along = 4) 
    cat(".") 
} 

GOOD:

i <- 1 
cbb <- list() 
repeat{ 
    sptsnew <- readBin(to.read, "integer", 2L, 4L) 
    if(identical(sptsnew, integer(0))){cat("\nend of file\n"); break} 
    ... #reading array metadata 
    cbb[[i]] <- array(readBin(to.read, "double", N1*N2*N3, 4L), c(N1, N2, N3, 1)) 
    i <- i + 1 
    cat(".") 
} 
cbb <- do.call(abind, c(cbb, list(along = 4)))