ऐसा प्रतीत होता है कि [.data.table
के साथ डेटा.table से स्तंभ (ओं) का चयन अंतर्निहित वेक्टर की एक प्रति में होता है। मैं नाम से बहुत सरल कॉलम चयन के बारे में बात कर रहा हूं, j
में गणना करने के लिए कोई अभिव्यक्ति नहीं है और i
में सबसेट करने के लिए कोई पंक्ति नहीं है। और भी अजीब बात यह है कि डेटा.फ्रेम में कॉलम सबसेटिंग कोई प्रतिलिपि नहीं दिखती है। मैं डेटा.table संस्करण डेटाटेबल 1.10.4 का उपयोग कर रहा हूँ। विवरण और बेंचमार्क के साथ एक सरल उदाहरण नीचे प्रदान किया गया है। मेरे प्रश्न हैं:डेटाटेबल परिणामों से कॉलम (ओं) का चयन प्रतिलिपि में क्यों करता है?
- क्या मैं कुछ गलत कर रहा हूं?
- क्या यह एक बग है या यह इरादा व्यवहार है?
- यदि इसका इरादा है, तो कॉलम द्वारा डेटाटेबल को सबसेट करने और अतिरिक्त प्रति से बचने का सबसे अच्छा तरीका क्या है?
इच्छित उपयोग-मामले में बड़े डेटासेट शामिल हैं, इसलिए अतिरिक्त प्रतियों से परहेज करना आवश्यक है (विशेष रूप से बेस आर पहले से ही इसका समर्थन करता है)।
library(data.table)
set.seed(12345)
cpp_dt <- data.table(a = runif(1e6), b = rnorm(1e6), c = runif(1e6))
cols=c("a","c")
## naive/data.frame style of column selection
## leads to a copy of the column vectors in cols
subset_cols_1=function(dt,cols){
return(dt[,cols,with=F])
}
## alternative syntax, still results in a copy
subset_cols_2=function(dt,cols){
return(dt[,..cols])
}
## work-around that uses data.frame column selection,
## appears to avoid the copy
subset_cols_3=function(dt,cols){
setDF(dt)
subset=dt[,cols]
setDT(subset)
setDT(dt)
return(subset)
}
## another approach that makes a "shallow" copy of the data.table
## then NULLs the not needed columns by reference
## appears to also avoid the copy
subset_cols_4=function(dt,cols){
subset=dt[TRUE]
other_cols=setdiff(names(subset),cols)
set(subset,j=other_cols,value=NULL)
return(subset)
}
subset_1=subset_cols_1(cpp_dt,cols)
subset_2=subset_cols_2(cpp_dt,cols)
subset_3=subset_cols_3(cpp_dt,cols)
subset_4=subset_cols_4(cpp_dt,cols)
अब स्मृति आवंटन को देखें और मूल डेटा की तुलना करें।
.Internal(inspect(cpp_dt)) # original data, keep an eye on 1st and 3d vector
# @7fe8ba278800 19 VECSXP g1c7 [OBJ,MARK,NAM(2),ATT] (len=3, tl=1027)
# @10e2ce000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.720904,0.875773,0.760982,0.886125,0.456481,...
# @10f1a3000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) -0.947317,-0.636669,0.167872,-0.206986,0.411445,...
# @10f945000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.717611,0.95416,0.191546,0.48525,0.539878,...
# ATTRIB: [removed]
[.data.table
पद्धति का उपयोग करना कॉलम सबसेट तक:
.Internal(inspect(subset_2)) # same, still copy
# @7fe8b6402600 19 VECSXP g0c7 [OBJ,NAM(1),ATT] (len=2, tl=1026)
# @115452000 14 REALSXP g0c7 [NAM(2)] (len=1000000, tl=0) 0.720904,0.875773,0.760982,0.886125,0.456481,...
# @1100e7000 14 REALSXP g0c7 [NAM(2)] (len=1000000, tl=0) 0.717611,0.95416,0.191546,0.48525,0.539878,...
# ATTRIB: [removed]
setDF
के अनुक्रम का उपयोग करना, के बाद: कि अभी भी [.data.table
उपयोग करता है और अभी भी एक प्रतिलिपि बनाने
.Internal(inspect(subset_1)) # looks like data.table is making a copy
# @7fe8b9f3b800 19 VECSXP g0c7 [OBJ,NAM(1),ATT] (len=2, tl=1026)
# @114cb0000 14 REALSXP g0c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.720904,0.875773,0.760982,0.886125,0.456481,...
# @1121ca000 14 REALSXP g0c7 [NAM(2)] (len=1000000, tl=0) 0.717611,0.95416,0.191546,0.48525,0.539878,...
# ATTRIB: [removed]
एक और वाक्य रचना संस्करण [.data.frame
और setDT
। देखो, वेक्टर a
और c
अब कॉपी नहीं किए गए हैं! ऐसा प्रतीत होता है कि आधार आर विधि अधिक कुशल/छोटी स्मृति पदचिह्न है?
.Internal(inspect(subset_3)) # "[.data.frame" is not making a copy!!
# @7fe8b633f400 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=1026)
# @10e2ce000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.720904,0.875773,0.760982,0.886125,0.456481,...
# @10f945000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.717611,0.95416,0.191546,0.48525,0.539878,...
# ATTRIB: [removed]
एक और दृष्टिकोण data.table की एक उथले प्रतिलिपि बनाने के लिए, तो नए data.table में संदर्भ द्वारा सभी अतिरिक्त कॉलम रिक्त है। फिर कोई प्रतियां नहीं बनाई जाती हैं।
.Internal(inspect(subset_4)) # 4th approach seems to also avoid the copy
# @7fe8b924d800 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=1027)
# @10e2ce000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.720904,0.875773,0.760982,0.886125,0.456481,...
# @10f945000 14 REALSXP g1c7 [MARK,NAM(2)] (len=1000000, tl=0) 0.717611,0.95416,0.191546,0.48525,0.539878,...
# ATTRIB: [removed]
अब इन चार दृष्टिकोणों के बेंचमार्क देखें। ऐसा लगता है कि "[.data.frame" (subset_cols_3
) एक स्पष्ट विजेता है।
microbenchmark({subset_cols_1(cpp_dt,cols)},
{subset_cols_2(cpp_dt,cols)},
{subset_cols_3(cpp_dt,cols)},
{subset_cols_4(cpp_dt,cols)},
times=100)
# Unit: microseconds
# expr min lq mean median uq max neval
# { subset_cols_1(cpp_dt, cols) } 4772.092 5128.7395 8956.7398 7149.447 10189.397 53117.358 100
# { subset_cols_2(cpp_dt, cols) } 4705.383 5107.1690 8977.1816 6680.666 9206.164 53523.191 100
# { subset_cols_3(cpp_dt, cols) } 148.659 177.9595 285.4926 250.620 283.414 4422.968 100
# { subset_cols_4(cpp_dt, cols) } 193.912 241.9010 531.8308 336.467 384.844 20061.864 100
शायद यहां अपडेट के लिए प्रतीक्षा करें: https://stackoverflow.com/a/26481429/ 'उथला 'फ़ंक्शन अभी तक निर्यात नहीं किया गया है, लेकिन शायद इसके साथ मदद करेगा। – Frank