2012-08-08 15 views
8

में समूह को अपने मूल क्रम (डेटा फ्रेम में पहली उपस्थिति के आधार पर क्रम में रखते हुए) को डेटा फ्रेम को एकत्रित करने में कुछ परेशानी हो रही है। मैंने इसे सही करने में कामयाब रहा है, लेकिन उम्मीद कर रहा था कि इसके बारे में जाने का एक आसान तरीका है।मूल क्रम रखते हुए कुल डेटा फ्रेम,

यहाँ पर काम करने के लिए सेट एक नमूना डेटा है:

set.seed(7) 
sel.1 <- sample(1:5, 20, replace = TRUE)  # selection vector 1 
sel.2 <- sample(1:5, 20, replace = TRUE) 
add.1 <- sample(81:100)      # additional vector 1 
add.2 <- sample(81:100) 
orig.df <- data.frame(sel.1, sel.2, add.1, add.2) 

कुछ बिंदुओं को नोट करने के लिए: यह तय करने के लिए कैसे डेटा एक साथ समूहीकृत है दो चयन स्तंभ हैं। वे वही होंगे, और उनके नाम ज्ञात हैं। मैंने केवल इस डेटा में दो अतिरिक्त कॉलम डाले हैं, लेकिन और भी कुछ हो सकता है। मैंने कॉलम नामों को 'सेल' और 'एड' से शुरू करना आसान बनाने के लिए दिया है, लेकिन वास्तविक डेटा के अलग-अलग नाम हैं (इसलिए grep चालें शांत हैं, वे यहां उपयोगी नहीं होंगे)।

जो मैं करने की कोशिश कर रहा हूं वह 'सेल' कॉलम के आधार पर समूहों में डेटा फ्रेम को समेकित करता है, और सभी 'एड' कॉलम को एक साथ जोड़ता है। यह काफी सरल aggregate का उपयोग कर इस प्रकार है:

# Get the names of all the additional columns 
all.add <- names(orig.df)[!(names(orig.df)) %in% c("sel.1", "sel.2")] 
aggr.df <- aggregate(orig.df[,all.add], 
        by=list(sel.1 = orig.df$sel.1, sel.2 = orig.df$sel.2), sum) 

समस्या यह है कि परिणाम 'sel' कॉलम द्वारा आदेश दिया जाता है; मैं चाहता हूं कि यह मूल डेटा में प्रत्येक समूह की पहली उपस्थिति के आधार पर आदेश दिया जाए।

## Attempt 1 
# create indices for each row (x) and find the minimum index for each range 
index.df <- aggregate(x = 1:nrow(orig.df), 
         by=list(sel.1 = orig.df$sel.1, sel.2 = orig.df$sel.2), min) 
# Make sure the x vector (indices) are in the right range for aggr.df 
index.order <- (1:nrow(index.df))[order(index.df$x)] 
aggr.df[index.order,] 

## Attempt 2 
# get the unique groups. These are in the right order. 
unique.sel <- unique(orig.df[,c("sel.1", "sel.2")]) 
# use sapply to effectively loop over data and sum additional columns. 
sums <- t(sapply(1:nrow(unique.sel), function (x) { 
    sapply(all.add, function (y) { 
     sum(aggr.df[which(aggr.df$sel.1 == unique.sel$sel.1[x] & 
          aggr.df$sel.2 == unique.sel$sel.2[x]), y]) 
     }) 
})) 
data.frame(unique.sel, sums) 

इन मुझे सही परिणाम दे, वहीं मुझे उम्मीद थी कि किसी को एक सरल समाधान का कहना है हो सकता है:

यहाँ यह काम कर रही है पर मेरे सबसे अच्छे प्रयास कर रहे हैं। यह समाधान बेहतर होगा यदि समाधान मानक आर स्थापना के साथ आने वाले संकुल के साथ काम करता है।

मैं aggregate और match के लिए दस्तावेज़ को देखा है, लेकिन मैं एक जवाब (मुझे लगता है मैं aggregate के लिए एक "keep.original.order" पैरामीटर की तरह कुछ के लिए उम्मीद कर रहा था) नहीं पा सके।

किसी भी मदद की बहुत सराहना की जाएगी!


अपडेट: (मामले में किसी को भी इस पार ठोकर)

यहाँ स्पष्ट तरीका है कि मैं कुछ और दिन के लिए प्रयास करने के बाद मिल सकता है है:

unique(data.frame(sapply(names(orig.df), function(x){ 
    if(x %in% c("sel.1", "sel.2")) orig.df[,x] else 
    ave(orig.df[,x], orig.df$sel.1, orig.df$sel.2, FUN=sum)}, 
simplify=FALSE))) 
+1

अद्यतन के लिए धन्यवाद, यह शायद data.table का उपयोग करने का सबसे अच्छा समाधान कम है। कुल मिलाकर 'keep.original.order' पैरामीटर को लागू करने के लिए आर विकास टीम को कैसे बैजर करता है? यह एक स्पष्ट निरीक्षण की तरह लगता है .. –

उत्तर

1

थोड़ा कठिन पढ़ने के लिए , लेकिन यह आपको वही देता है जो आप चाहते हैं और मैंने स्पष्ट करने के लिए कुछ टिप्पणियां जोड़ दीं।

# Define the columns you want to combine into the grouping variable 
sel.col <- grepl("^sel", names(orig.df)) 
# Create the grouping variable 
lev <- apply(orig.df[sel.col], 1, paste, collapse=" ") 
# Split and sum up 
data.frame(unique(orig.df[sel.col]), 
      t(sapply(split(orig.df[!sel.col], factor(lev, levels=unique(lev))), 
        apply, 2, sum))) 

उत्पादन इस

sel.1 sel.2 add.1 add.2 
1  5  4 96 84 
2  2  2 175 176 
3  1  5 384 366 
5  2  5 95 89 
6  4  1 174 192 
7  2  4 82 87 
8  5  3 91 98 
10  3  2 189 178 
11  1  4 170 183 
14  1  1 100 91 
17  3  3 81 82 
19  5  5 83 88 
20  2  3 90 96 
5

यह छोटी और data.table में आसान है की तरह लग रहा है। यह समूह को डिफ़ॉल्ट रूप से पहले उपस्थिति क्रम में लौटाता है।

require(data.table) 
DT = as.data.table(orig.df) 
DT[, list(sum(add.1),sum(add.2)), by=list(sel.1,sel.2)] 

    sel.1 sel.2 V1 V2 
1:  5  4 96 84 
2:  2  2 175 176 
3:  1  5 384 366 
4:  2  5 95 89 
5:  4  1 174 192 
6:  2  4 82 87 
7:  5  3 91 98 
8:  3  2 189 178 
9:  1  4 170 183 
10:  1  1 100 91 
11:  3  3 81 82 
12:  5  5 83 88 
13:  2  3 90 96 

और यह बड़े डेटा के लिए तेज़ होगा, इसलिए यदि आपको गति के मुद्दे मिलते हैं तो बाद में अपना कोड बदलने की आवश्यकता नहीं है। निम्न वैकल्पिक वाक्यविन्यास किस कॉलम को समूहबद्ध करने का सबसे आसान तरीका है।

DT[, lapply(.SD,sum), by=c("sel.1","sel.2")] 

    sel.1 sel.2 add.1 add.2 
1:  5  4 96 84 
2:  2  2 175 176 
3:  1  5 384 366 
4:  2  5 95 89 
5:  4  1 174 192 
6:  2  4 82 87 
7:  5  3 91 98 
8:  3  2 189 178 
9:  1  4 170 183 
10:  1  1 100 91 
11:  3  3 81 82 
12:  5  5 83 88 
13:  2  3 90 96 

या, by भी, किसी भी कॉमा स्तंभ नाम के अलग स्ट्रिंग हो सकता है बहुत:

DT[, lapply(.SD,sum), by="sel.1,sel.2"] 
संबंधित मुद्दे