do.call(rbind, ) 換成 dplyr::bind_rows( ) 竟然提速千倍,R讓人如此無語。
個人理解:
R給人的感覺是一切操作賦值都是“傳值”。
list 是R的基本數(shù)據(jù)類型,本身是 C struct, 定義操作等使用了指針,傳地址操作,list的函數(shù),很多也是primitive函數(shù),這些應(yīng)該也是C 代碼. 對list類型,mylist <- myfucntion(mylist)這種情況下,系統(tǒng)可以實現(xiàn)內(nèi)存上原地修改數(shù)據(jù),沒必要先復(fù)制。list實際上存儲的是每一個vector的地址,各個vector相互獨立,而且vector和list支持越界賦值,一個length為5的vector x, 你可以直接給x[6]賦值,可以更改x[3]。
而data.frame也是list,并不是R的原生類型,而是list的擴展。data.frame的各個組件間存在制約關(guān)系,必須等長,相互并不獨立,猜測這些制約關(guān)系相當(dāng)于增加了引用次數(shù),所以不能原地(in place)修改,其次data.frame不能越界賦值,也表明data.frame不支持原地修改。
R代碼的默認傳遞方式是傳值,這樣的好處是安全,適合非計算機專業(yè)同學(xué)使用。
如果是函數(shù)是C代碼(區(qū)別于純R代碼的函數(shù)),那么是可以支持傳地址的,這取決于C代碼怎么寫的。
data.frame也并非那么不堪,如果只是更改data.frame里的某一列,實際上是只copy某一列。而rbind行操作相當(dāng)于更改所有列**,每rbind一次就會在內(nèi)存復(fù)制完全一次data.frame,所以真的會很慢。
大數(shù)據(jù)的do.call(rbind, )相當(dāng)于不斷復(fù)制合并后的data.frame,真的可以慢到無以復(fù)加。