2013-10-31 8 views
12

मुझे एमएस-एसक्यूएल सर्वर से एक टेबल डाउनलोड करना है।rbind कैसे गति करें?

पंक्ति की संख्या 6 मिलियन से बड़ी है। सर्वर एक ही समय में पूरा डेटा वापस नहीं कर सकता है।

तो, मैंने एक कोड लिखा जो एक समय में 10,000 पंक्तियों को डाउनलोड करता है। और, यह लूप में पंक्तियों को बांधता है।

मान लें कि getData() फ़ंक्शन एक डेटा फ्रेम में एक समय में 10000 पंक्तियां देता है। (छद्म कोड)

for(i in 1:600) 
{ 
    tempValue <- getData() 
    wannagetValue <- rbind(wannagetValue,tempValue) 
    print(i) 
} 

समस्या यह है कि समय धीमा हो जाता है क्योंकि यह धीमा हो जाता है।

मुझे लगता है कि इस तरह rbind का उपयोग करना एक अच्छा विचार नहीं है।

कोई सलाह बहुत उपयोगी होगी। पहले ही, आपका बहुत धन्यवाद।

+3

यदि आप जानते हैं कि आपका अंतिम डेटा फ्रेम कितना बड़ा होगा, तो यह पूर्व-आवंटित करने के लिए बहुत तेज़ होगा और जब आप जाते हैं तो मानों को भरें। यद्यपि कोई भी पोस्ट करेगा जो विभिन्न डेटा संरचनाओं का उपयोग कर एक तेज समाधान की संभावना है। – David

+0

wannagetValue <- rbind (wannagetValue, getData()); । यह आपके कोड को थोड़ा बढ़ा सकता है ... लेकिन मुख्य सवाल यह है कि, इतने सारे डेटा क्यों? – Hackerman

+0

धन्यवाद डेविड! आपने मुझे बचाया .. रॉबर्ट // मुझे कोई जानकारी नहीं है ~~ मुझे पता है कि 500 ​​जीबी आकार से अधिक डेटा है। –

उत्तर

26

यहां कुछ विकल्प दिए कि मुझे यकीन है कि बेहतर हो सकता है कर रहा हूँ कर रहे हैं:

library(data.table) 
library(microbenchmark) 

#function to generate your data 
getData <- function(){ 
    data.frame(x=rnorm(10000),y=rnorm(10000),z=rnorm(10000)) 
} 

#using data table's rbindlist each iteration 
fDT1 <- function(n){ 
    dat <- getData() 
    for(i in 1:n){ 
    dat <- rbindlist(list(dat,getData())) 
    } 
    return(data.frame(dat)) 
} 

#using data table's rbindlist all at once 
fDT2 <- function(n){ 
    return(data.frame(rbindlist(lapply(1:n,function(x) getData())))) 
} 

#pre-allocating a data frame 
fPre <- function(n){ 
    dat <- data.frame(x=rep(0,n*10000),y=rep(0,n*10000),z=rep(0,n*10000)) 
    j <- 1 
    for(i in 1:n){ 
    dat[j:(j+10000-1),] <- getData() 
    j <- j + 10000 
    } 
    return(dat) 
} 

#standard do.call rbind 
f2 <- function(n){ 
    return(do.call(rbind,lapply(1:n,function(x) getData()))) 
} 

#current approach 
f <- function(n){ 
    dat <- getData() 
    for(i in 1:n){ 
    dat <- rbind(dat,getData()) 
    } 
    return(dat) 
} 

आप उपयोग कर data.table के rbindlist() आधार आर के rbind() पर एक बड़ा सुधार है देख सकते हैं और वहाँ जोड़कर में एक बड़ा लाभ यह है बातचीत के बजाय सभी बार पंक्तियां होती हैं, हालांकि स्मृति समस्याएं होने पर संभव नहीं हो सकता है। आप यह भी ध्यान दे सकते हैं कि डेटा में वृद्धि के आकार के रूप में गति सुधार कहीं भी रैखिक के करीब नहीं हैं।

> microbenchmark(fDT2(5),fDT1(5),fPre(5),f2(5),f(5), 
+    fDT2(25),fDT1(25),fPre(25),f2(25),f(25), 
+    fDT2(75),fDT1(75),fPre(75),f2(75),f(75), 
+    times=10) 
Unit: milliseconds 
    expr  min   lq  median   uq   max neval 
    fDT2(5) 18.31207 18.63969 24.09943 25.45590 72.01725 10 
    fDT1(5) 27.65459 29.25147 36.34158 77.79446 88.82556 10 
    fPre(5) 34.96257 39.39723 41.24445 43.30319 68.75897 10 
    f2(5) 30.85883 33.00292 36.29100 43.53619 93.15869 10 
    f(5) 87.40869 97.97500 134.50600 138.65354 147.67676 10 
fDT2(25) 89.42274 99.39819 103.90944 146.44160 156.01653 10 
fDT1(25) 224.65745 229.78129 261.52388 280.85499 300.93488 10 
fPre(25) 371.12569 412.79876 431.80571 485.37727 1046.96923 10 
    f2(25) 221.03669 252.08998 265.17357 271.82414 281.47096 10 
    f(25) 1446.32145 1481.01998 1491.59203 1634.99936 1849.00590 10 
fDT2(75) 326.66743 334.15669 367.83848 467.85480 520.27142 10 
fDT1(75) 1749.83842 1882.27091 2066.95241 2278.55589 2419.07205 10 
fPre(75) 3701.16220 3968.64643 4162.70585 4234.39716 4356.09462 10 
    f2(75) 1174.47546 1183.98860 1314.64585 1421.09483 1537.42903 10 
    f(75) 9139.36935 9349.24412 9510.90888 9977.24621 10861.51206 10 
+0

+1 - कृपया 'do.call जोड़ें (rbind, lapply (1: 25, फ़ंक्शन (...) getData()) ' – flodel

+0

अच्छा विचार, धन्यवाद। – David

+0

विस्तार से जानकारी के लिए बहुत बहुत धन्यवाद। ~ यह मुझे बहुत मदद करता है। –

4

यह कि ऊपर बताया गया है के रूप में, आर भंडार सभी डिफ़ॉल्ट रूप से रैम में अपनी वस्तुओं, डेटा की है कि राशि के साथ ऐसा है तो आप कुछ समस्याओं में चलाने के लिए जा रहे हैं।

दो बातें मैं जोड़ना चाहते हैं: 1) आम तौर पर, आप data.table का उपयोग नहीं करना चाहते हैं तो आपको हैडली के plyr पैकेज है, जो काफी तेज है में rbind.fill समारोह का भी उपयोग कर सकते हैं। कभी भीrbind का उपयोग करें, जिस तरह से आपने ऊपर किया था, 'फॉर' लूप में, प्रत्येक पंक्ति को अलग से जोड़ना। जब भी आप एक पंक्ति जोड़ते हैं, तो यह डेटा फ्रेम ऑब्जेक्ट की प्रतिलिपि बनाने के लिए आर को मजबूर करता है, और यह धीमा है।

2) आर के साथ बड़े से भी राम डेटा के साथ काम करने के लिए, अनुभाग बड़े स्मृति में और बाहर के स्मृति डेटाhttp://cran.r-project.org/web/views/HighPerformanceComputing.html पर एक नजर है, हो सकता है bigmemory पैकेज तुम क्या जरूरत है।

+1

संपूर्ण कच्चा डेटा 500GB से अधिक होगा, लेकिन यह 5 ~ 10GB कुल होगा यदि यह बाइनरी डेटा के रूप में संग्रहीत करता है। इसके अलावा, प्रत्येक तालिका में 1 ~ 2 जीबी होता है। मैं इसे अलग से सौदा कर सकता हूं। सौभाग्य से, मेरे कंप्यूटर में 64 जीबी डीडीआर 3 ईसीसी रैम है। मुझे नहीं लगता कि यह पर्याप्त नहीं है। वैसे, सलाह के लिए धन्यवाद। –

+0

यह प्रश्न थोड़ा पुराना है, लेकिन आज भी मुझे समाधान खोजने के दौरान यह मिला, इसलिए मैं यह जोड़ना चाहता हूं कि हैडली के नए 'dplyr' पैकेज में' bind_rows' फ़ंक्शन है जो 'rbind.fill' के समान है। मैंने इसे बेंचमार्क किया और यह मेरी मशीन पर 'do.call ('rbind', ...) 'से 1000x तेज है। [यह प्रश्न] देखें (https://stackoverflow.com/questions/44464441/r-is-there-a-good-replacement-for-plyrrbind-fill-in-dplyr)। – qdread

0

शायद आप SELECT COUNT(*) FROM table_name WHERE ... कर सकते हैं और फिर अपने डेटा फ्रेम के लिए स्थान आवंटित कर सकते हैं।

असल में, मुझे नहीं लगता कि प्रति 10k पंक्तियों में आपके डेटाबेस से पूछताछ करना एक अच्छा विचार है। डेटा को स्थानीय डिस्क पर निर्यात करके और वहां से पढ़ने से बचने का प्रयास करें। यह गति में भी सुधार करेगा। भंडारण सस्ता है, नेटवर्क बैंडविड्थ और स्मृति नहीं हैं।

संबंधित मुद्दे