एक कॉल में समूह द्वारा कई चर पर कई सारांश कार्य लागू करें


91

मेरे पास निम्न डेटा फ़्रेम है

x <- read.table(text = "  id1 id2 val1 val2
1   a   x    1    9
2   a   x    2    4
3   a   y    3    5
4   a   y    4    9
5   b   x    1    7
6   b   y    4    4
7   b   x    3    9
8   b   y    2    8", header = TRUE)

मैं id1 और id2 द्वारा समूहीकृत val1 और val2 के माध्य की गणना करना चाहता हूं, और साथ ही साथ प्रत्येक id1-id2 संयोजन के लिए पंक्तियों की संख्या गिनता हूं। मैं प्रत्येक गणना अलग-अलग कर सकता हूं:

# calculate mean
aggregate(. ~ id1 + id2, data = x, FUN = mean)

# count rows
aggregate(. ~ id1 + id2, data = x, FUN = length)

एक कॉल में दोनों गणना करने के लिए, मैंने कोशिश की

do.call("rbind", aggregate(. ~ id1 + id2, data = x, FUN = function(x) data.frame(m = mean(x), n = length(x))))

हालाँकि, मुझे चेतावनी के साथ एक आउटपुट मिला है:

#     m   n
# id1 1   2
# id2 1   1
#     1.5 2
#     2   2
#     3.5 2
#     3   2
#     6.5 2
#     8   2
#     7   2
#     6   2
# Warning message:
#   In rbind(id1 = c(1L, 2L, 1L, 2L), id2 = c(1L, 1L, 2L, 2L), val1 = list( :
#   number of columns of result is not a multiple of vector length (arg 1)

मैं plyr पैकेज का उपयोग कर सकता हूं, लेकिन डेटासेट बड़ा होने पर मेरा डेटा सेट काफी बड़ा है और प्लाई बहुत धीमा (लगभग अनुपयोगी) है।

मैं aggregateएक कॉल में कई गणना करने के लिए अन्य कार्यों का उपयोग कैसे कर सकता हूं ?


इसके aggregateजवाब में उल्लेखित भी हैं byऔर tapply
रोमन लुसट्रिक

जवाबों:


152

आप इसे एक चरण में कर सकते हैं और उचित लेबलिंग प्राप्त कर सकते हैं:

> aggregate(. ~ id1+id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) )
#   id1 id2 val1.mn val1.n val2.mn val2.n
# 1   a   x     1.5    2.0     6.5    2.0
# 2   b   x     2.0    2.0     8.0    2.0
# 3   a   y     3.5    2.0     7.0    2.0
# 4   b   y     3.0    2.0     6.0    2.0

यह दो आईडी कॉलम और दो मैट्रिक्स कॉलम के साथ एक डेटाफ्रेम बनाता है:

str( aggregate(. ~ id1+id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) ) )
'data.frame':   4 obs. of  4 variables:
 $ id1 : Factor w/ 2 levels "a","b": 1 2 1 2
 $ id2 : Factor w/ 2 levels "x","y": 1 1 2 2
 $ val1: num [1:4, 1:2] 1.5 2 3.5 3 2 2 2 2
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr  "mn" "n"
 $ val2: num [1:4, 1:2] 6.5 8 7 6 2 2 2 2
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr  "mn" "n"

जैसा कि नीचे @ lord.garbage द्वारा बताया गया है, इसका उपयोग करके "सरल" कॉलम के साथ डेटाफ़्रेम में परिवर्तित किया जा सकता है do.call(data.frame, ...)

str( do.call(data.frame, aggregate(. ~ id1+id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) ) ) 
    )
'data.frame':   4 obs. of  6 variables:
 $ id1    : Factor w/ 2 levels "a","b": 1 2 1 2
 $ id2    : Factor w/ 2 levels "x","y": 1 1 2 2
 $ val1.mn: num  1.5 2 3.5 3
 $ val1.n : num  2 2 2 2
 $ val2.mn: num  6.5 8 7 6
 $ val2.n : num  2 2 2 2

यह LHS पर कई चरों के लिए वाक्य रचना है:

aggregate(cbind(val1, val2) ~ id1 + id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) )

1
बहुत धन्यवाद। एक साइड नोट के रूप में, मैं केवल एक कॉलम को योग करने के लिए कैसे एकत्रित हो सकता हूं। यदि मेरे पास कई संख्यात्मक कॉलम हैं, तो मैं यह नहीं चाहता कि मैं उन कॉलमों को जोड़ूं जो मैं नहीं चाहता। मैं निश्चित रूप से एकत्रीकरण के बाद स्तंभों को फेंक सकता हूं, लेकिन सीपीयू चक्र पहले ही खर्च हो जाएंगे।
ब्रोकली

आप इसे केवल उन कारकों पर देते हैं जिन्हें समूहबद्ध किया जाना है और स्तंभों को एकत्र किया जाना है। संभवतः डेटा में नकारात्मक स्तंभ अनुक्रमण का उपयोग करें या सूत्र के LHS पर इच्छित कॉलम डालें। (देखें संपादित करें।)
IRTFM

2
मैं बग का सामना करना पड़ा जो कि उपयोगकर्ता 2659402 ने अपने अपडेट में उल्लेख किया था, जबकि विंडोज़ 7 मशीन पर RStudio 0.98.1014 का उपयोग किया गया था। यदि आप डेटा फ़्रेम को कंसोल में आउटपुट करते हैं जैसा कि दिखाया गया है तो यह सामान्य प्रतीत होता है, हालांकि यदि आप इसे डी में सहेजते हैं, और फिर d $ val1.mn तक पहुंचने का प्रयास करते हैं, तो यह NULL देता है। यदि आप दृश्य (d) चलाते हैं तो d भी विकृत दिखाई देता है। अपडेट में कोड का उपयोग करके इसे ठीक किया।
JHowIX

4
जिस कारण से आपको कठिनाई हो रही है वह यह है कि "वैल्स" को साधारण कॉलम के बजाय दो कॉलम प्रत्येक के साथ मैट्रेस के रूप में लौटाया जा रहा है। कोशिश करो d$val1[ , ""mn"]और संरचना के साथ देखो str
IRTFM

5
आप उन स्तंभों को बांध सकते हैं जिनमें डेटा फ़्रेम में वापस मैट्रिसेस हैं: agg <- aggregate(cbind(val1, val2) ~ id1 + id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x)))उपयोग करके agg_df <- do.call(data.frame, agg)। यह भी देखें यहाँ
lord.garbage

30

इस प्रश्न में यह देखते हुए:

मैं plyr पैकेज का उपयोग कर सकता हूं, लेकिन डेटासेट बड़ा होने पर मेरा डेटा सेट काफी बड़ा है और प्लाई बहुत धीमा (लगभग अनुपयोगी) है।

तब data.table( 1.9.4+) में आप कोशिश कर सकते हैं:

> DT
   id1 id2 val1 val2
1:   a   x    1    9
2:   a   x    2    4
3:   a   y    3    5
4:   a   y    4    9
5:   b   x    1    7
6:   b   y    4    4
7:   b   x    3    9
8:   b   y    2    8

> DT[ , .(mean(val1), mean(val2), .N), by = .(id1, id2)]   # simplest
   id1 id2  V1  V2 N
1:   a   x 1.5 6.5 2
2:   a   y 3.5 7.0 2
3:   b   x 2.0 8.0 2
4:   b   y 3.0 6.0 2

> DT[ , .(val1.m = mean(val1), val2.m = mean(val2), count = .N), by = .(id1, id2)]  # named
   id1 id2 val1.m val2.m count
1:   a   x    1.5    6.5     2
2:   a   y    3.5    7.0     2
3:   b   x    2.0    8.0     2
4:   b   y    3.0    6.0     2

> DT[ , c(lapply(.SD, mean), count = .N), by = .(id1, id2)]   # mean over all columns
   id1 id2 val1 val2 count
1:   a   x  1.5  6.5     2
2:   a   y  3.5  7.0     2
3:   b   x  2.0  8.0     2
4:   b   y  3.0  6.0     2

इस बेंचमार्क ( और मामलों) aggregateको data.tableदेखने के लिए समय की तुलना (प्रश्न और सभी 3 अन्य उत्तरों में प्रयुक्त) के लिए ।aggagg.x


12

आप एक जोड़ सकता है countस्तंभ, के साथ कुल sum, फिर वापस पैमाने पर प्राप्त करने के लिए mean:

x$count <- 1
agg <- aggregate(. ~ id1 + id2, data = x,FUN = sum)
agg
#   id1 id2 val1 val2 count
# 1   a   x    3   13     2
# 2   b   x    4   16     2
# 3   a   y    7   14     2
# 4   b   y    6   12     2

agg[c("val1", "val2")] <- agg[c("val1", "val2")] / agg$count
agg
#   id1 id2 val1 val2 count
# 1   a   x  1.5  6.5     2
# 2   b   x  2.0  8.0     2
# 3   a   y  3.5  7.0     2
# 4   b   y  3.0  6.0     2

इसमें आपके कॉलम नामों को संरक्षित करने और एकल countकॉलम बनाने का लाभ है ।


12

dplyrपैकेज का उपयोग करके आप इसे प्राप्त कर सकते हैं summarise_all। इसे संक्षेप में-समारोह के साथ आप अन्य कार्यों (इस मामले में आवेदन कर सकते हैं meanऔर n()गैर-समूहीकरण स्तंभों में से प्रत्येक के लिए):

x %>%
  group_by(id1, id2) %>%
  summarise_all(funs(mean, n()))

जो देता है:

     id1    id2 val1_mean val2_mean val1_n val2_n
1      a      x       1.5       6.5      2      2
2      a      y       3.5       7.0      2      2
3      b      x       2.0       8.0      2      2
4      b      y       3.0       6.0      2      2

यदि आप फ़ंक्शन को सभी गैर-समूहीकरण स्तंभों पर लागू नहीं करना चाहते हैं, तो आप उन स्तंभों को निर्दिष्ट करते हैं जिन्हें उन्हें लागू किया जाना चाहिए या summarise_at()फ़ंक्शन का उपयोग करके माइनस के साथ गैर-वांछित को छोड़कर :

# inclusion
x %>%
  group_by(id1, id2) %>%
  summarise_at(vars(val1, val2), funs(mean, n()))

# exclusion
x %>%
  group_by(id1, id2) %>%
  summarise_at(vars(-val2), funs(mean, n()))

10

शायद आप विलय करना चाहते हैं ?

x.mean <- aggregate(. ~ id1+id2, p, mean)
x.len  <- aggregate(. ~ id1+id2, p, length)

merge(x.mean, x.len, by = c("id1", "id2"))

  id1 id2 val1.x val2.x val1.y val2.y
1   a   x    1.5    6.5      2      2
2   a   y    3.5    7.0      2      2
3   b   x    2.0    8.0      2      2
4   b   y    3.0    6.0      2      2

4

आप plyr::each()कई कार्यों को शुरू करने के लिए भी उपयोग कर सकते हैं :

aggregate(cbind(val1, val2) ~ id1 + id2, data = x, FUN = plyr::each(avg = mean, n = length))

1

एक अन्य dplyrविकल्प acrossवर्तमान देव संस्करण का हिस्सा है

#devtools::install_github("tidyverse/dplyr")
library(dplyr)

x %>% 
  group_by(id1, id2) %>% 
  summarise(across(starts_with("val"), list(mean = mean, n = length)))

परिणाम

# A tibble: 4 x 4
# Groups:   id1 [2]
  id1   id2   mean$val1 $val2 n$val1 $val2
  <fct> <fct>     <dbl> <dbl>  <int> <int>
1 a     x           1.5   6.5      2     2
2 a     y           3.5   7        2     2
3 b     x           2     8        2     2
4 b     y           3     6        2     2

packageVersion("dplyr")
[1]0.8.99.9000
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.