स्ट्रिंग वेक्टर इनपुट का उपयोग करके, dplyr में कई कॉलम द्वारा समूह


157

मैं plyr की अपनी समझ को dplyr में स्थानांतरित करने की कोशिश कर रहा हूं, लेकिन मैं यह पता नहीं लगा सकता कि कैसे कई कॉलम द्वारा समूह बनाया जाए।

# make data with weird column names that can't be hard coded
data = data.frame(
  asihckhdoydkhxiydfgfTgdsx = sample(LETTERS[1:3], 100, replace=TRUE),
  a30mvxigxkghc5cdsvxvyv0ja = sample(LETTERS[1:3], 100, replace=TRUE),
  value = rnorm(100)
)

# get the columns we want to average within
columns = names(data)[-3]

# plyr - works
ddply(data, columns, summarize, value=mean(value))

# dplyr - raises error
data %.%
  group_by(columns) %.%
  summarise(Value = mean(value))
#> Error in eval(expr, envir, enclos) : index out of bounds

मैं एक dplyr-esque वाक्यविन्यास में plyr उदाहरण का अनुवाद करने के लिए क्या याद कर रहा हूँ?

संपादित करें 2017 : Dplyr अपडेट किया गया है, इसलिए एक सरल समाधान उपलब्ध है। वर्तमान में चयनित उत्तर देखें।


3
बस यहाँ आ गया क्योंकि यह शीर्ष गूगल था। group_by_अब आप समझाया जा सकता हैvignette("nse")
जेम्स ओनर्स

3
@ कुंगफुजम: यह केवल स्तंभ के समूह द्वारा प्रतीत होता है, स्तंभों की जोड़ी से नहीं
शारो जनाब

1
आपको उपयोग करने की आवश्यकता है .dots। यहाँ समाधान नीचे @hadley के उत्तर से अनुकूलित किया गया है:df %>% group_by_(.dots=list(quote(asihckhdoydk), quote(a30mvxigxkgh))) %>% summarise(n = n())
जेम्स ओनर्स

1
नीचे एक उत्तर में पूर्ण कोड डाल दिया है
जेम्स ओनर्स

1
जैसा कि किसी ने टिप्पणी पर एक जवाब में बताया है, इसका उद्देश्य हार्डकोडेड कॉलम नामों की आवश्यकता नहीं है।
शारोज

जवाबों:


52

चूँकि यह प्रश्न पोस्ट किया गया था, इसलिए dplyr ने group_by( यहाँ प्रलेखन ) के स्कोप किए गए संस्करण जोड़े । इससे आप उन्हीं कार्यों का उपयोग कर सकते हैं, जिनका आप उपयोग करेंगे select, जैसे:

data = data.frame(
    asihckhdoydkhxiydfgfTgdsx = sample(LETTERS[1:3], 100, replace=TRUE),
    a30mvxigxkghc5cdsvxvyv0ja = sample(LETTERS[1:3], 100, replace=TRUE),
    value = rnorm(100)
)

# get the columns we want to average within
columns = names(data)[-3]

library(dplyr)
df1 <- data %>%
  group_by_at(vars(one_of(columns))) %>%
  summarize(Value = mean(value))

#compare plyr for reference
df2 <- plyr::ddply(data, columns, plyr::summarize, value=mean(value))
table(df1 == df2, useNA = 'ifany')
## TRUE 
##  27 

आपके उदाहरण प्रश्न से आउटपुट अपेक्षित है (ऊपर plyr की तुलना देखें और नीचे आउटपुट):

# A tibble: 9 x 3
# Groups:   asihckhdoydkhxiydfgfTgdsx [?]
  asihckhdoydkhxiydfgfTgdsx a30mvxigxkghc5cdsvxvyv0ja       Value
                     <fctr>                    <fctr>       <dbl>
1                         A                         A  0.04095002
2                         A                         B  0.24943935
3                         A                         C -0.25783892
4                         B                         A  0.15161805
5                         B                         B  0.27189974
6                         B                         C  0.20858897
7                         C                         A  0.19502221
8                         C                         B  0.56837548
9                         C                         C -0.22682998

ध्यान दें कि dplyr::summarizeएक समय में समूहीकरण की केवल एक परत के बंद होने के बाद , आपको अभी भी परिणामी टिबल में कुछ समूहन चल रहा है (जो कुछ समय बाद लाइन के नीचे से लोगों को पकड़ सकते हैं)। यदि आप अप्रत्याशित समूह व्यवहार से पूरी तरह से सुरक्षित होना चाहते हैं, तो %>% ungroupआप संक्षेप में अपनी पाइपलाइन को हमेशा जोड़ सकते हैं ।


0.7.0कई स्तंभों के साथ उद्धरण-अयोग्य प्रणाली को उपलब्ध कराने के लिए अद्यतन भी करता है?
जेलिना atक्लिना

4
तुम भी उपयोग कर सकते हैं .dotsकरने के लिए तर्क group_by()जैसे: data %>% group_by(.dots = columns) %>% summarize(value = mean(value))
पॉल रौजीक्स

क्या one_of()यहाँ कुछ करने के लिए कॉल आता है? मुझे लगता है कि यह इस संदर्भ में बेमानी है, क्योंकि अभिव्यक्ति को एक कॉल में लपेटा गया है vars()
पताह

@Khashir हाँ, इस सवाल का जवाब अभी भी आप @knowah काम करता रहे हों तो सही, करने के लिए कॉल one_of()इस संदर्भ में अनावश्यक है
Empiromancer

1
@Sos selectवाक्यविन्यास का उपयोग करते हुए कई कॉलमों में एक फ़ंक्शन लागू करने के लिए , नया acrossफ़ंक्शन देखें : dplyr.tidyverse.org/reference/across.html आपके मामले में, यह कुछ ऐसा दिखाई देगाsummarize(across(all_of(c(''value_A", "value_B")), mean))
Empiromancer

102

बस इतना है कि पूरी तरह से कोड लिखने के लिए, नए सिंटैक्स के साथ हैडली के जवाब पर एक अपडेट है:

library(dplyr)

df <-  data.frame(
    asihckhdoydk = sample(LETTERS[1:3], 100, replace=TRUE),
    a30mvxigxkgh = sample(LETTERS[1:3], 100, replace=TRUE),
    value = rnorm(100)
)

# Columns you want to group by
grp_cols <- names(df)[-3]

# Convert character vector to list of symbols
dots <- lapply(grp_cols, as.symbol)

# Perform frequency counts
df %>%
    group_by_(.dots=dots) %>%
    summarise(n = n())

उत्पादन:

Source: local data frame [9 x 3]
Groups: asihckhdoydk

  asihckhdoydk a30mvxigxkgh  n
1            A            A 10
2            A            B 10
3            A            C 13
4            B            A 14
5            B            B 10
6            B            C 12
7            C            A  9
8            C            B 12
9            C            C 10

1
ऐसा लगता है कि स्तंभ के नामों को अभी भी हार्डकोड किया जा रहा है, केवल एक सूत्र में। सवाल का मुद्दा यह है कि तार का उपयोग कैसे किया जाए ताकि टाइप न करें asihckhdoydk...
ग्रेगर थॉमस

1
अद्यतन dots <- lapply(names(df)[-3], function(x) as.symbol(x))बनाने के लिए .dotsतर्क का उपयोग करके अद्यतन किया है
जेम्स ओनर्स

4
इन उत्तरों के माध्यम से छाँटने की कोशिश करना, .dots=महत्वपूर्ण कदम था। अगर किसी के पास group_byकॉल में आवश्यक क्यों है , तो क्या आप इस उत्तर को संपादित कर सकते हैं? अभी यह थोड़ा असंवेदनशील है।
एंड्रयू

12
vignette("nse")इंगित करता है कि बोली के तीन तरीके स्वीकार्य हैं: सूत्र, उद्धरण और चरित्र। जब तक आप इस बात से चिंतित नहीं होंगे कि यह किस वातावरण से खींचेगा, आप शायद इससे दूर हो सकते हैंgroup_by_(.dots=grp_cols)
अरी बी। फ्रीडमैन

58

वर्तमान में इसके लिए समर्थन बहुत कमजोर है, अंततः मुझे लगता है कि वाक्यविन्यास कुछ इस तरह होगा:

df %.% group_by(.groups = c("asdfgfTgdsx", "asdfk30v0ja"))

लेकिन यह शायद वहाँ थोड़ी देर के लिए नहीं होगा (क्योंकि मुझे सभी परिणामों के माध्यम से सोचने की आवश्यकता है)।

इस बीच, आप उपयोग कर सकते हैं regroup(), जो प्रतीकों की एक सूची लेता है:

library(dplyr)

df <-  data.frame(
  asihckhdoydk = sample(LETTERS[1:3], 100, replace=TRUE),
  a30mvxigxkgh = sample(LETTERS[1:3], 100, replace=TRUE),
  value = rnorm(100)
)

df %.%
  regroup(list(quote(asihckhdoydk), quote(a30mvxigxkgh))) %.%
  summarise(n = n())

आप स्तंभ नाम की एक चरित्र वेक्टर है है, तो आप उन लोगों के साथ सही संरचना करने के लिए परिवर्तित कर सकते हैं lapply()और as.symbol():

vars <- setdiff(names(df), "value")
vars2 <- lapply(vars, as.symbol)

df %.% regroup(vars2) %.% summarise(n = n())

6
as.symbolइसे हल करता है। धन्यवाद! मामले में यह विकास में मदद करता है: यह परिदृश्य मेरे लिए वास्तव में सामान्य है। अन्य चर के हर संयोजन पर एक संख्यात्मक परिणाम एकत्र करें।
शारोज

जाहिरा तौर पर यह केवल इस विशेष उदाहरण के लिए काम करता है और कोई अन्य नहीं।
पाउलो ई। कार्डसो

3
मैंने मूल रूप से इसे उत्तर के रूप में चिह्नित किया है, लेकिन डंपलर को अपडेट करने से कुंगफूजम के जवाब को काम करने की अनुमति मिलती है।
शारोज

regroupकम से कम (संस्करण 0.4.3 के रूप में कम से कम) भी है।
बर्क यू।

27

स्तंभों के स्ट्रिंग विनिर्देश dplyrअब dplyrअंडरस्कोर में नाम के साथ फ़ंक्शंस के वेरिएंट के माध्यम से समर्थित हैं । उदाहरण के लिए, group_byफ़ंक्शन के अनुरूप एक group_by_फ़ंक्शन है जो स्ट्रिंग तर्क ले सकता है। यह विगनेट विस्तार से इन कार्यों के वाक्यविन्यास का वर्णन करता है।

निम्नलिखित स्निपेट स्पष्ट रूप से उस समस्या को हल करता है जो @sharoz ने मूल रूप से पेश की थी ( .dotsतर्क को लिखने की आवश्यकता पर ध्यान दें ):

# Given data and columns from the OP

data %>%
    group_by_(.dots = columns) %>%
    summarise(Value = mean(value))

(ध्यान दें कि अब dplyr %>%ऑपरेटर का उपयोग करता है , और %.%पदावनत किया जाता है)।


17

जब तक स्ट्रीप तर्कों के लिए dplyr को पूर्ण समर्थन नहीं मिलता, तब तक शायद यह संकेत उपयोगी है:

https://gist.github.com/skranz/9681509

इसमें s_group_by, s_mutate, s_filter आदि जैसे रैपर कार्यों का गुच्छा होता है, जो कड़े बदलावों का उपयोग करते हैं। आप उन्हें सामान्य dplyr कार्यों के साथ मिला सकते हैं। उदाहरण के लिए

cols = c("cyl","gear")
mtcars %.%
  s_group_by(cols) %.%  
  s_summarise("avdisp=mean(disp), max(disp)") %.%
  arrange(avdisp)

11

यह काम करता है यदि आप इसे वस्तुओं (अच्छी तरह से, आप नहीं हैं, लेकिन ...) के बजाय एक चरित्र वेक्टर के रूप में:

df %.%
    group_by(asdfgfTgdsx, asdfk30v0ja) %.%
    summarise(Value = mean(value))

> df %.%
+   group_by(asdfgfTgdsx, asdfk30v0ja) %.%
+   summarise(Value = mean(value))
Source: local data frame [9 x 3]
Groups: asdfgfTgdsx

  asdfgfTgdsx asdfk30v0ja        Value
1           A           C  0.046538002
2           C           B -0.286359899
3           B           A -0.305159419
4           C           A -0.004741504
5           B           B  0.520126476
6           C           C  0.086805492
7           B           C -0.052613078
8           A           A  0.368410146
9           A           B  0.088462212

जहां dfआपके था data

?group_by कहते हैं:

 ...: variables to group by. All tbls accept variable names, some
      will also accept functons of variables. Duplicated groups
      will be silently dropped.

जिसका अर्थ है कि मैं नामों के वर्ण संस्करणों का अर्थ नहीं करता, लेकिन आप उन्हें कैसे संदर्भित करेंगे foo$bar; barयहाँ उद्धृत नहीं किया गया है। या आप किसी सूत्र में चर को कैसे संदर्भित करेंगे foo ~ bar:।

@ अरुण का भी उल्लेख है कि आप कर सकते हैं:

df %.%
    group_by("asdfgfTgdsx", "asdfk30v0ja") %.%
    summarise(Value = mean(value))

लेकिन आप किसी ऐसी चीज़ में नहीं जा सकते हैं जो डेटा ऑब्जेक्ट में अनवैल्युएटेड वैरिएबल का नाम नहीं है।

मुझे लगता है कि यह आंतरिक तरीकों के कारण हैडली उन चीजों को देखने के लिए उपयोग कर रहा है जो आप ...तर्क से गुजरते हैं ।


1
@ अरुण इसके लिए धन्यवाद। मैंने उस पर ध्यान नहीं दिया था, लेकिन यह भी समझ में आता है। मैंने आपको और आपकी टिप्पणी का हवाला देते हुए इस संबंध में एक नोट जोड़ा।
गैविन सिम्पसन

4
दुर्भाग्य से, मैं स्तंभ नामों को हार्ड कोडिंग पर भरोसा नहीं कर सकता। मैं उन्हें निर्दिष्ट किए बिना ऐसा करने की कोशिश कर रहा हूं।
शारोज

4
data = data.frame(
  my.a = sample(LETTERS[1:3], 100, replace=TRUE),
  my.b = sample(LETTERS[1:3], 100, replace=TRUE),
  value = rnorm(100)
)

group_by(data,newcol=paste(my.a,my.b,sep="_")) %>% summarise(Value=mean(value))

4

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

library(wakefield)
df_foo = r_series(rnorm, 10, 1000)
df_foo %>% 
  # 1. create quantized versions of base variables
  mutate_each(
    funs(Quantized = . > 0)
  ) %>% 
  # 2. group_by the indicator variables
  group_by_(
    .dots = grep("Quantized", names(.), value = TRUE)
    ) %>% 
  # 3. summarize the base variables
  summarize_each(
    funs(sum(., na.rm = TRUE)), contains("X_")
  )

यह मूल रूप से दिखाता है कि इसे प्राप्त करने के लिए grepसंयोजन के साथ कैसे उपयोग किया जाए group_by_(.dots = ...)


3

फ़ंक्शन पर .dotsवर्ण वेक्टर इनपुट के रूप में तर्क का उपयोग करने पर सामान्य उदाहरण dplyr::group_by:

iris %>% 
    group_by(.dots ="Species") %>% 
    summarise(meanpetallength = mean(Petal.Length))

या समूहीकरण चर के लिए एक हार्ड कोड नाम के बिना (ओपी द्वारा पूछा गया):

iris %>% 
    group_by(.dots = names(iris)[5]) %>% 
    summarise_at("Petal.Length", mean)

ओपी के उदाहरण के साथ:

data %>% 
    group_by(.dots =names(data)[-3]) %>% 
    summarise_at("value", mean)

सर्वनाम, quasiquotation, quosures, और tidyeval की व्याख्या करने वाले प्रोग्रामिंग पर dplyr विगनेट भी देखें ।

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