समूह द्वारा चर का योग कैसे करें


357

मेरे पास दो कॉलम वाला एक डेटा फ्रेम है। पहले कॉलम में "प्रथम", "दूसरा", "तीसरा" जैसी श्रेणियां हैं, और दूसरे कॉलम में संख्याएं हैं जो "श्रेणी" से मैंने विशिष्ट समूहों को देखे जाने की संख्या का प्रतिनिधित्व करती हैं।

उदाहरण के लिए:

Category     Frequency
First        10
First        15
First        5
Second       2
Third        14
Third        20
Second       3

मैं श्रेणी के आधार पर डेटा को सॉर्ट करना चाहता हूं और सभी आवृत्तियों को योग करना चाहता हूं:

Category     Frequency
First        30
Second       5
Third        34

मैं आर में यह कैसे करूंगा?


1
बेस आर में सबसे तेज तरीका है rowsum
माइकल एम

जवाबों:


387

का उपयोग कर aggregate:

aggregate(x$Frequency, by=list(Category=x$Category), FUN=sum)
  Category  x
1    First 30
2   Second  5
3    Third 34

उपरोक्त उदाहरण में, कई आयामों को निर्दिष्ट किया जा सकता है list। एक ही डेटा प्रकार के कई एग्रीगेटेड मेट्रिक्स को इसके माध्यम से शामिल किया जा सकता है cbind:

aggregate(cbind(x$Frequency, x$Metric2, x$Metric3) ...

(एम्बेडिंग @thelatemail टिप्पणी), aggregateएक सूत्र इंटरफ़ेस भी है

aggregate(Frequency ~ Category, x, sum)

या यदि आप कई कॉलमों को एकत्र करना चाहते हैं, तो आप इसका उपयोग कर सकते हैं . नोटेशन का (एक कॉलम के लिए भी काम करता है)

aggregate(. ~ Category, x, sum)

या tapply :

tapply(x$Frequency, x$Category, FUN=sum)
 First Second  Third 
    30      5     34 

इस डेटा का उपयोग करना:

x <- data.frame(Category=factor(c("First", "First", "First", "Second",
                                      "Third", "Third", "Second")), 
                    Frequency=c(10,15,5,2,14,20,3))

4
@AndrewMcKinlay, R आँकड़ों और अन्य कार्यों के लिए प्रतीकात्मक सूत्रों को परिभाषित करने के लिए टिल्ड का उपयोग करता है। इसे "श्रेणी द्वारा मॉडल आवृत्ति" या "श्रेणी के आधार पर आवृत्ति " के रूप में व्याख्या की जा सकती है । सभी भाषाएं प्रतीकात्मक फ़ंक्शन को परिभाषित करने के लिए एक विशेष ऑपरेटर का उपयोग नहीं करती हैं, जैसा कि आर में यहां किया गया है। शायद टिल्ड ऑपरेटर की "प्राकृतिक-भाषा की व्याख्या" के साथ, यह अधिक सार्थक (और यहां तक ​​कि सहज) हो जाता है। मैं व्यक्तिगत रूप से इस प्रतीकात्मक सूत्र प्रतिनिधित्व को कुछ अधिक क्रियाशील विकल्पों से बेहतर मानता हूं।
r2evans

1
आर के लिए नया होने के नाते (और ओपी के रूप में उसी तरह के सवाल पूछते हुए), मैं प्रत्येक विकल्प के पीछे सिंटैक्स के कुछ और विवरण से लाभान्वित होगा। उदाहरण के लिए, यदि मेरे पास एक बड़ी स्रोत तालिका है और मैं केवल दो आयामों को सममित करना चाहता हूं, तो मैं इन विधियों में से किसी को भी अनुकूलित कर सकता हूं? बताना मुश्किल है।
डोडेकाफोन

236

आप उस उद्देश्य के लिए dplyr पैकेज का उपयोग भी कर सकते हैं :

library(dplyr)
x %>% 
  group_by(Category) %>% 
  summarise(Frequency = sum(Frequency))

#Source: local data frame [3 x 2]
#
#  Category Frequency
#1    First        30
#2   Second         5
#3    Third        34

या, कई सारांश कॉलमों के लिए (एक कॉलम के साथ भी काम करता है):

x %>% 
  group_by(Category) %>% 
  summarise_all(funs(sum))

अंतर्निहित डेटासेट का उपयोग करके dplyr फ़ंक्शन का उपयोग करके समूह द्वारा डेटा को सारांशित करने के कुछ और उदाहरण इस प्रकार हैं mtcars:

# several summary columns with arbitrary names
mtcars %>% 
  group_by(cyl, gear) %>%                            # multiple group columns
  summarise(max_hp = max(hp), mean_mpg = mean(mpg))  # multiple summary columns

# summarise all columns except grouping columns using "sum" 
mtcars %>% 
  group_by(cyl) %>% 
  summarise_all(sum)

# summarise all columns except grouping columns using "sum" and "mean"
mtcars %>% 
  group_by(cyl) %>% 
  summarise_all(funs(sum, mean))

# multiple grouping columns
mtcars %>% 
  group_by(cyl, gear) %>% 
  summarise_all(funs(sum, mean))

# summarise specific variables, not all
mtcars %>% 
  group_by(cyl, gear) %>% 
  summarise_at(vars(qsec, mpg, wt), funs(sum, mean))

# summarise specific variables (numeric columns except grouping columns)
mtcars %>% 
  group_by(gear) %>% 
  summarise_if(is.numeric, funs(mean))

%>%ऑपरेटर सहित अधिक जानकारी के लिए, परिचय को देखें


1
अन्य उत्तरों में प्रस्तुत डेटाटेबल और एग्रीगेट विकल्पों की तुलना में यह कितना तेज है?
असीरा

5
@ असीरा, जो सबसे तेज़ है और कितना बड़ा अंतर (या यदि अंतर ध्यान देने योग्य है) हमेशा आपके डेटा आकार पर निर्भर करेगा। आमतौर पर, बड़े डेटा सेट के लिए, उदाहरण के लिए कुछ GB, data.table सबसे अधिक संभावना होगी। छोटे डेटा आकार पर, डेटाटैब और डैप्लर अक्सर बंद होते हैं, यह भी समूहों की संख्या पर निर्भर करता है। बेस फंक्शन्स की तुलना में दोनों डेटा, टेबल और ड्रिप काफी तेज होगी, हालाँकि (कुछ ऑपरेशनों के लिए यह अच्छी तरह से 100-1000 गुना तेज़ हो सकती है)। यहां
तात

1
दूसरे उदाहरण में "फ़न" का क्या अर्थ है?
lauren.marietta 19

@ lauren.marietta आप उस फ़ंक्शन को निर्दिष्ट कर सकते हैं जिसे आप उसके funs()तर्क summarise_allऔर उसके संबंधित कार्यों ( summarise_at, summarise_if) के तालमेल के रूप में लागू करना चाहते हैं
ताल

76

जवाब rcs द्वारा प्रदान किया गया काम करता है और सरल है। हालाँकि, यदि आप बड़े डेटासेट को संभाल रहे हैं और एक प्रदर्शन को बढ़ावा देने की आवश्यकता है तो एक तेज़ विकल्प है:

library(data.table)
data = data.table(Category=c("First","First","First","Second","Third", "Third", "Second"), 
                  Frequency=c(10,15,5,2,14,20,3))
data[, sum(Frequency), by = Category]
#    Category V1
# 1:    First 30
# 2:   Second  5
# 3:    Third 34
system.time(data[, sum(Frequency), by = Category] )
# user    system   elapsed 
# 0.008     0.001     0.009 

चलिए तुलना करते हैं कि डेटा.फ्रेम और इसके बाद के संस्करण का उपयोग करके एक ही चीज़ से:

data = data.frame(Category=c("First","First","First","Second","Third", "Third", "Second"),
                  Frequency=c(10,15,5,2,14,20,3))
system.time(aggregate(data$Frequency, by=list(Category=data$Category), FUN=sum))
# user    system   elapsed 
# 0.008     0.000     0.015 

और यदि आप कॉलम रखना चाहते हैं तो यह सिंटैक्स है:

data[,list(Frequency=sum(Frequency)),by=Category]
#    Category Frequency
# 1:    First        30
# 2:   Second         5
# 3:    Third        34

अंतर बड़े डेटासेट के साथ अधिक ध्यान देने योग्य हो जाएगा, क्योंकि नीचे दिए गए कोड प्रदर्शित होते हैं:

data = data.table(Category=rep(c("First", "Second", "Third"), 100000),
                  Frequency=rnorm(100000))
system.time( data[,sum(Frequency),by=Category] )
# user    system   elapsed 
# 0.055     0.004     0.059 
data = data.frame(Category=rep(c("First", "Second", "Third"), 100000), 
                  Frequency=rnorm(100000))
system.time( aggregate(data$Frequency, by=list(Category=data$Category), FUN=sum) )
# user    system   elapsed 
# 0.287     0.010     0.296 

कई एकत्रीकरण के लिए, आप संयोजन कर सकते हैं lapplyऔर .SDनिम्नानुसार

data[, lapply(.SD, sum), by = Category]
#    Category Frequency
# 1:    First        30
# 2:   Second         5
# 3:    Third        34

13
+1 लेकिन 0.296 बनाम 0.059 विशेष रूप से प्रभावशाली नहीं है। डेटा का आकार 300k पंक्तियों से बड़ा होना चाहिए, और 3 से अधिक समूहों के साथ, डेटाटेबल को चमकने के लिए। हम उदाहरण के लिए जल्द ही 2 बिलियन से अधिक पंक्तियों का प्रयास करेंगे और उनका समर्थन करेंगे, क्योंकि कुछ डेटाटैब उपयोगकर्ताओं के पास 250GB RAM और GNU R है, जो अब लंबाई> 2 ^ 31 का समर्थन करता है।
मैट डोले

2
सच। यह पता चलता है कि मेरे पास वह सब रैम नहीं है, और केवल डेटाटेबल के बेहतर प्रदर्शन के कुछ सबूत देने की कोशिश कर रहा था। मुझे यकीन है कि अंतर अधिक डेटा के साथ और भी बड़ा होगा।
असीरा

1
मेरे पास 7 सैन्य अवलोकन थे। dplyr ने 3 सेकंड और एग्रीगेट () ने ऑपरेशन को पूरा करने में 22 सेकंड का समय लिया। मैं इसे इस विषय पर पोस्ट करने जा रहा था और आपने मुझे इसे हरा दिया!
zazu

3
इसे लिखने का एक और भी छोटा तरीका है data[, sum(Frequency), by = Category]। आप उपयोग कर सकते हैं .Nजो sum()फ़ंक्शन को प्रतिस्थापित करता है। data[, .N, by = Category]। यहाँ एक उपयोगी चीटशीट है
स्टोफ़फेस

3
.N का उपयोग करना। सम (फ़्रिक्वेंसी) के समतुल्य होगा यदि फ़्रीक्वेंसी कॉलम में सभी मान 1 के बराबर थे, क्योंकि .N प्रत्येक एग्रीगेटेड सेट (.SD) में पंक्तियों की संख्या की गणना करता है। और यहाँ ऐसा नहीं है।
असीरा

41

आप भी () फ़ंक्शन का उपयोग कर सकते हैं :

x2 <- by(x$Frequency, x$Category, sum)
do.call(rbind,as.list(x2))

उन अन्य पैकेज (plyr, reshape) में डेटा.फ्रेम वापस करने का लाभ होता है, लेकिन यह आधार फ़ंक्शन के बाद से () से परिचित होने के लायक है।


28

कई सालों बाद, बस एक और सरल आधार आर समाधान जोड़ना है जो किसी कारण से यहां मौजूद नहीं है- xtabs

xtabs(Frequency ~ Category, df)
# Category
# First Second  Third 
#    30      5     34 

या यदि आप एक data.frameपीठ चाहते हैं

as.data.frame(xtabs(Frequency ~ Category, df))
#   Category Freq
# 1    First   30
# 2   Second    5
# 3    Third   34


23

यदि xआपके डेटा के साथ एक डेटाफ़्रेम है, तो निम्नलिखित वह करेगा जो आप चाहते हैं:

require(reshape)
recast(x, Category ~ ., fun.aggregate=sum)

19

जबकि मैं हाल ही dplyrमें इन प्रकार के अधिकांश कार्यों के लिए एक रूपांतरित हो गया हूंsqldf कुछ चीजों के लिए पैकेज अभी भी वास्तव में अच्छा है (और IMHO अधिक पठनीय)।

इस सवाल का जवाब कैसे दिया जा सकता है, इसका एक उदाहरण इस प्रकार है sqldf

x <- data.frame(Category=factor(c("First", "First", "First", "Second",
                                  "Third", "Third", "Second")), 
                Frequency=c(10,15,5,2,14,20,3))

sqldf("select 
          Category
          ,sum(Frequency) as Frequency 
       from x 
       group by 
          Category")

##   Category Frequency
## 1    First        30
## 2   Second         5
## 3    Third        34

18

बस एक तीसरा विकल्प जोड़ने के लिए:

require(doBy)
summaryBy(Frequency~Category, data=yourdataframe, FUN=sum)

EDIT: यह एक बहुत पुराना उत्तर है। अब मैं के उपयोग की सिफारिश करेंगे group_byऔर summariseसे dplyr, @docendo जवाब में के रूप में।


7

मुझे लगता है aveजब आप विभिन्न कॉलमों पर अलग-अलग एकत्रीकरण कार्यों को लागू करने की आवश्यकता होती है, तो बहुत उपयोगी (और कुशल) लगता है (और आपको आरटीआई पर चिपकना चाहिए):

जैसे

इस इनपुट को देखते हुए:

DF <-                
data.frame(Categ1=factor(c('A','A','B','B','A','B','A')),
           Categ2=factor(c('X','Y','X','X','X','Y','Y')),
           Samples=c(1,2,4,3,5,6,7),
           Freq=c(10,30,45,55,80,65,50))

> DF
  Categ1 Categ2 Samples Freq
1      A      X       1   10
2      A      Y       2   30
3      B      X       4   45
4      B      X       3   55
5      A      X       5   80
6      B      Y       6   65
7      A      Y       7   50

हमने समूह में से चाहते हैं Categ1और Categ2और की राशि की गणना Samplesऔर का मतलब है Freq
यहां एक संभावित समाधान का उपयोग किया गया है ave:

# create a copy of DF (only the grouping columns)
DF2 <- DF[,c('Categ1','Categ2')]

# add sum of Samples by Categ1,Categ2 to DF2 
# (ave repeats the sum of the group for each row in the same group)
DF2$GroupTotSamples <- ave(DF$Samples,DF2,FUN=sum)

# add mean of Freq by Categ1,Categ2 to DF2 
# (ave repeats the mean of the group for each row in the same group)
DF2$GroupAvgFreq <- ave(DF$Freq,DF2,FUN=mean)

# remove the duplicates (keep only one row for each group)
DF2 <- DF2[!duplicated(DF2),]

परिणाम :

> DF2
  Categ1 Categ2 GroupTotSamples GroupAvgFreq
1      A      X               6           45
2      A      Y               9           40
3      B      X               7           50
6      B      Y               6           65

6

हाल ही में जोड़ा गया dplyr::tally()यह पहले से कहीं अधिक आसान बनाता है:

tally(x, Category)

Category     n
First        30
Second       5
Third        34

6

आप पैकेज रिफ़्टgroup.sum से फ़ंक्शन का उपयोग कर सकते हैं ।

Category <- Rfast::as_integer(Category,result.sort=FALSE) # convert character to numeric. R's as.numeric produce NAs.
result <- Rfast::group.sum(Frequency,Category)
names(result) <- Rfast::Sort(unique(Category)
# 30 5 34

RIFT के कई समूह कार्य हैं औरgroup.sumउनमें से एक है।


4

के castबजाय का उपयोग कर recast(नोट 'Frequency'अब है 'value')

df  <- data.frame(Category = c("First","First","First","Second","Third","Third","Second")
                  , value = c(10,15,5,2,14,20,3))

install.packages("reshape")

result<-cast(df, Category ~ . ,fun.aggregate=sum)

लेना:

Category (all)
First     30
Second    5
Third     34

2

एक अन्य समाधान जो एक मैट्रिक्स या डेटा फ़्रेम में समूहों द्वारा रकम लौटाता है और यह छोटा और तेज़ है:

rowsum(x$Frequency, x$Category)

अच्छी तरह से, और वास्तव में तेजी से।
jay.sf
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.