2011-11-15 12 views
7

द्वारा बड़े मैट्रिक्स में कुल पंक्तियां मैं पंक्तियों में मान जोड़कर एक मैट्रिक्स की पंक्तियों को जोड़ना चाहूंगा जिसमें समान राउननाम है। मेरे वर्तमान दृष्टिकोण इस प्रकार है:rowname

> M 
    a b c d 
1 1 1 2 0 
1 2 3 4 2 
2 3 0 1 2 
3 4 2 5 2 
> index <- as.numeric(rownames(M)) 
> M <- cbind(M,index) 
> Dfmat <- data.frame(M) 
> Dfmat <- aggregate(. ~ index, data = Dfmat, sum) 
> M <- as.matrix(Dfmat) 
> rownames(M) <- M[,"index"] 
> M <- subset(M, select= -index) 
> M 
    a b c d 
1 3 4 6 2 
2 3 0 1 2 
3 4 2 5 2 

इस appraoch की समस्या यह है कि मैं (1.000 पंक्तियों और 30.000 कॉलम तक) बहुत बड़ी मैट्रिक्स के एक नंबर करने के लिए इसे लागू करने की आवश्यकता है। इन मामलों में गणना समय बहुत अधिक है (ddply का उपयोग करते समय वही समस्या)। क्या समाधान के साथ आने के लिए और अधिक सार्थक है? क्या यह मदद करता है कि मूल इनपुट मैट्रिक्स tm पैकेज से DocumentTermMatrix हैं? जहां तक ​​मुझे पता है कि वे एक स्पैर मैट्रिक्स प्रारूप में संग्रहीत हैं।

+0

आपको पूरी तरह से स्पष्ट करने की आवश्यकता नहीं है, लेकिन मैं 'reshape' पैकेज (पिघल() और कास्ट()) के साथ थोड़ा सा खेलूँगा। लेकिन अधिक महत्वपूर्ण: आपने पहली जगह डुप्लिकेट पंक्ति नामों को कैसे अनुमति दी? यह आमतौर पर एक बुरा विचार है। –

+0

मेरे डेटा में rownames तिथियां हैं। जब भी मेरे पास एक ही तारीख पर कई अवलोकन होते हैं तो वे डुप्लीकेट होते हैं। – Christian

+0

@ क्रिस्टियन यह ठीक है। मुझे लगता है कि कार्ल डेटा फ्रेम के बारे में सोच रहा है, जहां डुप्लिकेट की सख्ती से अनुमति नहीं है। –

उत्तर

6

यहां by और colSums का उपयोग करके एक समाधान है, लेकिन by के डिफ़ॉल्ट आउटपुट के कारण कुछ फिडलिंग की आवश्यकता है।

M <- matrix(1:9,3) 
rownames(M) <- c(1,1,2) 
t(sapply(by(M,rownames(M),colSums),identity)) 
    V1 V2 V3 
1 3 9 15 
2 3 6 9 
1

जेम्स द्वारा उत्तर की अपेक्षा की जाती है, लेकिन बड़ी मैट्रिक्स के लिए काफी धीमी है।

combineByRow <- function(m) { 
    m <- m[ order(rownames(m)), ] 

    ## keep track of previous row name 
    prev <- rownames(m)[1] 
    i.start <- 1 
    i.end <- 1 

    ## cache the rownames -- profiling shows that it takes 
    ## forever to look at them 
    m.rownames <- rownames(m) 
    stopifnot(all(!is.na(m.rownames))) 


    ## go through matrix in a loop, as we need to combine some unknown 
    ## set of rows 
    for (i in 2:(1+nrow(m))) { 

     curr <- m.rownames[i] 

     ## if we found a new row name (or are at the end of the matrix), 
     ## combine all rows and mark invalid rows 
     if (prev != curr || is.na(curr)) { 

      if (i.start < i.end) { 
       m[i.start,] <- apply(m[i.start:i.end,], 2, max) 
       m.rownames[(1+i.start):i.end] <- NA 
      } 

      prev <- curr 
      i.start <- i 
     } else { 
      i.end <- i 
     } 
    } 

    m[ which(!is.na(m.rownames)),]  
} 

परीक्षण यह पता चलता है कि है का उपयोग कर by (2 बनाम इस उदाहरण में 20 सेकंड) जवाब से अधिक तेजी से 10x के बारे में:

N <- 10000 

m <- matrix(runif(N*100), nrow=N) 
rownames(m) <- sample(1:(N/2),N,replace=T) 

start <- proc.time() 
m1 <- combineByRow(m) 
print(proc.time()-start) 

start <- proc.time() 
m2 <- t(sapply(by(m,rownames(m),function(x) apply(x, 2, max)),identity)) 
print(proc.time()-start) 

all(m1 == m2) 
1

वहाँ है अब एक समग्र यहाँ एक संस्करण avoids creating of new objects कि है Matrix.utils में कार्य करें। यह पूरा कर सकते हैं क्या आप कोड की एक लाइन के साथ चाहते हैं और by समाधान की तुलना में combineByRow समाधान की तुलना में 10x के बारे में तेजी से और 100x तेजी से होता है:

N <- 10000 

m <- matrix(runif(N*100), nrow=N) 
rownames(m) <- sample(1:(N/2),N,replace=T) 

> microbenchmark(a<-t(sapply(by(m,rownames(m),colSums),identity)),b<-combineByRow(m),c<-aggregate.Matrix(m,row.names(m)),times = 10) 
Unit: milliseconds 
                expr  min   lq  mean  median   uq  max neval 
a <- t(sapply(by(m, rownames(m), colSums), identity)) 6000.26552 6173.70391 6660.19820 6419.07778 7093.25002 7723.61642 10 
            b <- combineByRow(m) 634.96542 689.54724 759.87833 732.37424 866.22673 923.15491 10 
       c <- aggregate.Matrix(m, row.names(m)) 42.26674 44.60195 53.62292 48.59943 67.40071 70.40842 10 

> identical(as.vector(a),as.vector(c)) 
[1] TRUE 

संपादित करें: फ्रैंक सही है, rowsum कुछ हद तक तेजी से इनमें से किसी भी तुलना में है समाधान की। आप इन अन्य कार्यों में से किसी एक का उपयोग केवल तभी करना चाहेंगे जब आप Matrix का उपयोग कर रहे थे, विशेष रूप से एक स्पैस, या यदि आप sum के अलावा एकत्रीकरण कर रहे थे।

+2

शायद आप 'रोससम (एम, राउनम्स (एम))' जोड़ सकते हैं, जो आधार समाधान है (अजीब तरह से यहां जवाबों में दिखाई नहीं दे रहा है)। – Frank

+0

इस फ़ंक्शन का उपयोग न करें। यह "मजेदार" तर्क के लिए लगभग सभी संभावनाओं पर चुपचाप विफल रहता है। https://github.com/cran/Matrix.utils/issues/1 –

+0

@eric_kernfeld 'aggregate.Matrix' 'गिनती', 'माध्य', या 'योग' की एक स्ट्रिंग तर्क स्वीकार करता है। यह वर्तमान संस्करण में बेहतर दस्तावेज है। – Craig