2013-04-04 10 views
7

मैं आर में एक बड़े डेटा तालिका है:धुरी एक बड़ी data.table

library(data.table) 
set.seed(1234) 
n <- 1e+07*2 
DT <- data.table(
    ID=sample(1:200000, n, replace=TRUE), 
    Month=sample(1:12, n, replace=TRUE), 
    Category=sample(1:1000, n, replace=TRUE), 
    Qty=runif(n)*500, 
    key=c('ID', 'Month') 
) 
dim(DT) 

मैं इस data.table पिवट करने के लिए, जैसे कि श्रेणी एक स्तंभ बन जाता है चाहते हैं। दुर्भाग्यवश, चूंकि श्रेणियों की संख्या समूहों के भीतर स्थिर नहीं है, इसलिए मैं this answer का उपयोग नहीं कर सकता।

कोई विचार मैं यह कैसे कर सकता हूं?

/संपादन: Joran की टिप्पणी और flodel के जवाब के आधार पर, हम वास्तव में देगी रहे हैं निम्नलिखित data.table:

agg <- DT[, list(Qty = sum(Qty)), by = c("ID", "Month", "Category")] 

यह आकृति बदलें तरीके का एक संख्या पूरा किया जा सकता (मैं कुछ अच्छा जवाब अब तक मिल गया है), लेकिन जो मैं वास्तव में खोज रहा हूं वह ऐसा कुछ है जो data.table पर लाखों पंक्तियों और सैकड़ों से हजारों श्रेणियों के साथ अच्छी तरह से स्केल करेगा।

+1

क्या आप तालिका के शरीर को 'मात्रा' से भरने का मतलब है? किसी भी डुप्लिकेट संयोजन को सारांशित करना? – joran

+0

@ जोरन: मेरे उदाहरण में डुप्लिकेट संयोजन हैं, लेकिन तर्क के लिए, मान लें कि वहां नहीं हैं। मैं चाहता हूं कि श्रेणी फ़ील्ड के प्रत्येक मान के लिए एक अलग कॉलम है, या तो एनए, या 0 गायब संयोजनों के लिए। – Zach

+0

@ जोरान मुझे लगता है कि आपके प्रश्न का सही उत्तर हां है: मैं चाहता हूं कि श्रेणी कॉलम बन जाए, प्रत्येक कॉलम में मात्रा, एनएएस या 0 गुम श्रेणियों के लिए 0, और डुप्लीकेट को सारांशित किया जाना चाहिए (लेकिन यह हमारे सामने संक्षेप करना उचित है नयी आकृति प्रदान)। – Zach

उत्तर

7

data.tablemelt/dcast data.table विशिष्ट विधियों (सी में) के तेजी से संस्करणों लागू करता है। यह एकाधिक कॉलम पिघलने और कास्टिंग के लिए अतिरिक्त सुविधाएं भी जोड़ता है। कृपया Efficient reshaping using data.tables विग्नेट देखें।

ध्यान दें कि हमें reshape2 पैकेज लोड करने की आवश्यकता नहीं है।

library(data.table) 
set.seed(1234) 
n <- 1e+07*2 
DT <- data.table(
    ID=sample(1:200000, n, replace=TRUE), 
    Month=sample(1:12, n, replace=TRUE), 
    Category=sample(1:800, n, replace=TRUE), ## to get to <= 2 billion limit 
    Qty=runif(n), 
    key=c('ID', 'Month') 
) 
dim(DT) 

> system.time(ans <- dcast(DT, ID + Month ~ Category, fun=sum)) 
# user system elapsed 
# 65.924 20.577 86.987 
> dim(ans) 
# [1] 2399401  802 
3

इसी तरह?

agg <- DT[, list(Qty = sum(Qty)), by = c("ID", "Month", "Category")] 

reshape(agg, v.names = "Qty", idvar = c("ID", "Month"), 
     timevar = "Category", direction = "wide") 
3

कोई विस्तृत data.table विशिष्ट विस्तृत रीशेपिंग विधि नहीं है।

यहां एक दृष्टिकोण है जो काम करेगा, लेकिन यह बल्कि समझा जाएगा।

इस सुविधा को और अधिक सरल बनाने में सहायता के लिए एक सुविधा अनुरोध #2619 Scoping for LHS in := है।

यहाँ एक सरल उदाहरण

# a data.table 
DD <- data.table(a= letters[4:6], b= rep(letters[1:2],c(4,2)), cc = as.double(1:6)) 
# with not all categories represented 
DDD <- DD[1:5] 
# trying to make `a` columns containing `cc`. retaining `b` as a column 
# the unique values of `a` (you may want to sort this...) 
nn <- unique(DDD[,a]) 
# create the correct wide data.table 
# with NA of the correct class in each created column 
rows <- max(DDD[, .N, by = list(a,b)][,N]) 
DDw <- DDD[, setattr(replicate(length(nn), { 
        # safe version of correct NA 
        z <- cc[1] 
         is.na(z) <-1 
        # using rows value calculated previously 
        # to ensure correct size 
         rep(z,rows)}, 
        simplify = FALSE), 'names', nn), 
      keyby = list(b)] 
# set key for binary search 
setkey(DDD, b, a) 
# The possible values of the b column 
ub <- unique(DDw[,b]) 
# nested loop doing things by reference, so should be 
# quick (the feature request would make this possible to 
# speed up using binary search joins. 
for(ii in ub){ 
    for(jj in nn){ 
    DDw[list(ii), {jj} := DDD[list(ii,jj)][['cc']]] 
    } 
} 

DDw 
# b d e f 
# 1: a 1 2 3 
# 2: a 4 2 3 
# 3: b NA 5 NA 
# 4: b NA 5 NA 
+0

मैं इसे अपने उदाहरण डेटा.table पर आज़माउंगा और आपको बताऊंगा कि क्या होता है। – Zach

2

संपादित

मैं इस SO post है, जो एक data.table में लापता पंक्तियों को सम्मिलित करने के लिए एक बेहतर तरीका भी शामिल पाया जाता है। फंक्शन fun_DT तदनुसार समायोजित । कोड अब क्लीनर है; मुझे हालांकि कोई गति सुधार नहीं दिख रहा है।

अन्य पोस्ट पर मेरा अपडेट देखें। अरुण का समाधान भी काम करता है, लेकिन आपको लापता संयोजनों को मैन्युअल रूप से डालना होगा। चूंकि आपके पास यहां अधिक पहचानकर्ता कॉलम हैं (आईडी, महीना), मैं केवल यहां एक गंदे समाधान के साथ आया हूं (पहले आईडी 2 बनाना, फिर सभी आईडी 2-श्रेणी संयोजन बनाना, फिर डेटाटेबल भरना, फिर रीशेपिंग करना)।

मुझे यकीन है कि यह सबसे अच्छा समाधान नहीं है, लेकिन यदि this FR बनाया गया है, तो ये चरण स्वचालित रूप से किए जा सकते हैं।

समाधान लगभग एक ही गति के अनुसार हैं, हालांकि यह देखना दिलचस्प होगा कि कैसे स्केल (मेरी मशीन बहुत धीमी है, इसलिए मैं आगे बढ़ाना नहीं चाहता ... कंप्यूटर अक्सर पहले से दुर्घटनाग्रस्त हो गया है ;-)

library(data.table) 
library(rbenchmark) 

fun_reshape <- function(n) { 

    DT <- data.table(
    ID=sample(1:100, n, replace=TRUE), 
    Month=sample(1:12, n, replace=TRUE), 
    Category=sample(1:10, n, replace=TRUE), 
    Qty=runif(n)*500, 
    key=c('ID', 'Month') 
) 
    agg <- DT[, list(Qty = sum(Qty)), by = c("ID", "Month", "Category")] 
    reshape(agg, v.names = "Qty", idvar = c("ID", "Month"), 
      timevar = "Category", direction = "wide") 
} 

#UPDATED! 
fun_DT <- function(n) { 

    DT <- data.table(
    ID=sample(1:100, n, replace=TRUE), 
    Month=sample(1:12, n, replace=TRUE), 
    Category=sample(1:10, n, replace=TRUE), 
    Qty=runif(n)*500, 
    key=c('ID', 'Month') 
) 

    agg <- DT[, list(Qty = sum(Qty)), by = c("ID", "Month", "Category")] 
    agg[, ID2 := paste(ID, Month, sep="_")] 

    setkey(agg, ID2, Category) 
    agg <- agg[CJ(unique(ID2), unique(Category))] 

    agg[, as.list(setattr(Qty, 'names', Category)), by=list(ID2)] 

} 

library(rbenchmark) 

n <- 1e+07 
benchmark(replications=10, 
      fun_reshape(n), 
      fun_DT(n)) 
      test replications elapsed relative user.self sys.self user.child sys.child 
2  fun_DT(n)   10 45.868  1 43.154 2.524   0   0 
1 fun_reshape(n)   10 45.874  1 42.783 2.896   0   0 
+0

मैं इन दोनों को 200,000 आईडी और 1,000 श्रेणियों के साथ आज़माउंगा और आपको बताऊंगा कि यह कैसा चल रहा है। मुझे संदेह है कि 'fun_DT' उड़ने जा रहा है, लेकिन' fun_reshape' काम कर सकता है। – Zach

+0

@Zach मुझे बताएं, यह दिलचस्प होगा। आप क्यों सोचते हैं कि 'run_DT' उड़ने जा रहा है? मुझे लगता है कि उन अतिरिक्त क्षेत्रों को वैसे भी बनाया जाना चाहिए, एक तरफ या दूसरा, इसलिए मैं इसकी अपेक्षा नहीं करूंगा। उम्मीद है कि मुझे यह सही मिला। इसके अलावा, मेरा अपडेट देखें। कोड अब क्लीनर है। –

+0

200,000 आईडी * 12 महीने * 1,000 श्रेणियां = 2,400,000,000 पंक्तियों का एक पूर्ण डेटा। फ्रेम, जो अधिकतम आकार डेटा से अधिक है। आर (2,147,483,648) में फ्रेम। – Zach