dplyr सारांश: आउटपुट में शून्य लंबाई वाले समूहों को रखने के लिए ".drop = FALSE" के बराबर


97

का उपयोग करते समय summariseके साथ plyrके ddplyसमारोह, खाली श्रेणियों डिफ़ॉल्ट रूप से नहीं किया जाता। आप इस व्यवहार को जोड़कर बदल सकते हैं .drop = FALSE। हालाँकि, जब यह उपयोग के summariseसाथ काम नहीं करता है dplyr। क्या परिणाम में खाली श्रेणियों को रखने का एक और तरीका है?

यहां नकली डेटा के साथ एक उदाहरण दिया गया है।

library(dplyr)

df = data.frame(a=rep(1:3,4), b=rep(1:2,6))

# Now add an extra level to df$b that has no corresponding value in df$a
df$b = factor(df$b, levels=1:3)

# Summarise with plyr, keeping categories with a count of zero
plyr::ddply(df, "b", summarise, count_a=length(a), .drop=FALSE)

  b    count_a
1 1    6
2 2    6
3 3    0

# Now try it with dplyr
df %.%
  group_by(b) %.%
  summarise(count_a=length(a), .drop=FALSE)

  b     count_a .drop
1 1     6       FALSE
2 2     6       FALSE

बिल्कुल वैसा नहीं जैसा मैं उम्मीद कर रहा था। वहाँ के dplyrरूप .drop=FALSEमें एक ही परिणाम प्राप्त करने के लिए एक विधि है plyr?


जवाबों:


26

चूंकि dplyr 0.8 group_by ने वह .dropतर्क प्राप्त किया, जो आपने पूछा था:

df = data.frame(a=rep(1:3,4), b=rep(1:2,6))
df$b = factor(df$b, levels=1:3)

df %>%
  group_by(b, .drop=FALSE) %>%
  summarise(count_a=length(a))

#> # A tibble: 3 x 2
#>   b     count_a
#>   <fct>   <int>
#> 1 1           6
#> 2 2           6
#> 3 3           0

@ Moody_Mudskipper के उत्तर के साथ जाने के लिए एक अतिरिक्त नोट: .drop=FALSEसंभावित रूप से अप्रत्याशित परिणाम दे सकते हैं जब एक या अधिक समूह चर को कारकों के रूप में कोडित नहीं किया जाता है। नीचे दिए गए उदाहरण देखें:

library(dplyr)
data(iris)

# Add an additional level to Species
iris$Species = factor(iris$Species, levels=c(levels(iris$Species), "empty_level"))

# Species is a factor and empty groups are included in the output
iris %>% group_by(Species, .drop=FALSE) %>% tally

#>   Species         n
#> 1 setosa         50
#> 2 versicolor     50
#> 3 virginica      50
#> 4 empty_level     0

# Add character column
iris$group2 = c(rep(c("A","B"), 50), rep(c("B","C"), each=25))

# Empty groups involving combinations of Species and group2 are not included in output
iris %>% group_by(Species, group2, .drop=FALSE) %>% tally

#>   Species     group2     n
#> 1 setosa      A         25
#> 2 setosa      B         25
#> 3 versicolor  A         25
#> 4 versicolor  B         25
#> 5 virginica   B         25
#> 6 virginica   C         25
#> 7 empty_level <NA>       0

# Turn group2 into a factor
iris$group2 = factor(iris$group2)

# Now all possible combinations of Species and group2 are included in the output, 
#  whether present in the data or not
iris %>% group_by(Species, group2, .drop=FALSE) %>% tally

#>    Species     group2     n
#>  1 setosa      A         25
#>  2 setosa      B         25
#>  3 setosa      C          0
#>  4 versicolor  A         25
#>  5 versicolor  B         25
#>  6 versicolor  C          0
#>  7 virginica   A          0
#>  8 virginica   B         25
#>  9 virginica   C         25
#> 10 empty_level A          0
#> 11 empty_level B          0
#> 12 empty_level C          0

Created on 2019-03-13 by the reprex package (v0.2.1)

मैंने आपके उत्तर में एक अतिरिक्त नोट जोड़ा है। अगर आपको एडिट पसंद नहीं है तो कृपया डिलीट करने के लिए स्वतंत्र महसूस करें।
eipi10

मैंने इस बारे में एक मुद्दा जीथब पर दर्ज किया है ताकि पता लगाया जा सके कि यह बग है या इच्छित व्यवहार।
eipi10

@ eipi10 थोड़ा छोटा है count:iris %>% count(Species, group2, .drop=FALSE)
Tjebo

59

यह मुद्दा अभी भी खुला है, लेकिन इस बीच, खासकर जब से आपके डेटा को पहले से ही पता चल गया है, आप complete"tidyr" से उपयोग कर सकते हैं, जिसे आप ढूंढ रहे हैं:

library(tidyr)
df %>%
  group_by(b) %>%
  summarise(count_a=length(a)) %>%
  complete(b)
# Source: local data frame [3 x 2]
# 
#        b count_a
#   (fctr)   (int)
# 1      1       6
# 2      2       6
# 3      3      NA

यदि आप प्रतिस्थापन मूल्य शून्य चाहते थे, तो आपको यह निर्दिष्ट करना होगा fill:

df %>%
  group_by(b) %>%
  summarise(count_a=length(a)) %>%
  complete(b, fill = list(count_a = 0))
# Source: local data frame [3 x 2]
# 
#        b count_a
#   (fctr)   (dbl)
# 1      1       6
# 2      2       6
# 3      3       0

11
यह मुझे पता लगाने के लिए दीवार के खिलाफ बहुत सिर पीटने लगा, इसलिए मैं यहां इसका उल्लेख करूंगा ... यदि आप 2 चर द्वारा समूह बनाते हैं, और वे कारकों के बजाय वर्ण हैं, तो ungroup()आपको पूरा करने से पहले उपयोग करने की आवश्यकता होगी । यदि आप कभी नोटिस completeवास्तव में पूरा नहीं कर रहे हैं, ungroupशायद जरूरत है।
विलियमसल्स

क्या होगा यदि आपके पास और भी अधिक समूह चर हैं? यदि मुझे मेरे Group_by से सभी समूहीकरण वर्जन का उपयोग करने पर भारी संख्या में पंक्तियाँ (मेरे मूल डेटाफ़्रेम से बहुत अधिक) मिलती हैं
तोबीओ

1
मैं यह समझ से बाहर: आप घोंसला बनाने से उपयोग करने के लिए :-) इसलिए में आपस में सभी चर कि भी नहीं जोड़ा जाना चाहिए डाल complete(variablewithdroppedlevels, nesting(var1,var2,var3))(यह वास्तव में मदद में है के लिए completeअभी भी मुझे थोड़ी देर आंकड़ा करने के लिए बाहर ले
TobiO

20

dplyr समाधान:

पहले ग्रुप डीएफ बनाएं

by_b <- tbl_df(df) %>% group_by(b)

फिर हम उन स्तरों को संक्षेप में प्रस्तुत करते हैं जो गिनती के साथ घटित होते हैं n()

res <- by_b %>% summarise( count_a = n() )

फिर हम अपने परिणामों को एक डेटा फ्रेम में मिला देते हैं जिसमें सभी कारक स्तर होते हैं:

expanded_res <- left_join(expand.grid(b = levels(df$b)),res)

अंत में, इस मामले में चूंकि हम देख रहे हैं कि NAमान 0 में बदल गए हैं।

final_counts <- expanded_res[is.na(expanded_res)] <- 0

इसे कार्यात्मक रूप से भी लागू किया जा सकता है, उत्तर देखें: dplyr के साथ समूहीकृत डेटा में पंक्तियाँ जोड़ें?

एक हैक:

मैंने सोचा कि मैं एक भयानक हैक पोस्ट करूंगा जो इस मामले में ब्याज के लिए काम करता है। मुझे गंभीरता से संदेह है कि आपको वास्तव में ऐसा करना चाहिए, लेकिन यह दिखाता है कि group_by()अत्याचार कैसे उत्पन्न होते हैं जैसे कि df$bएक चरित्र वेक्टर स्तरों के साथ एक कारक नहीं था। इसके अलावा, मैं इसे ठीक से समझने का दिखावा नहीं करता - लेकिन मुझे उम्मीद है कि इससे मुझे सीखने में मदद मिलेगी - यही एकमात्र कारण है जो मैं इसे पोस्ट कर रहा हूँ!

by_b <- tbl_df(df) %>% group_by(b)

"आउट-ऑफ-बाउंड्स" मान परिभाषित करें जो डेटासेट में मौजूद नहीं हो सकता है।

oob_val <- nrow(by_b)+1

"ट्रिक" में विशेषताओं को संशोधित करें summarise():

attr(by_b, "indices")[[3]] <- rep(NA,oob_val)
attr(by_b, "group_sizes")[3] <- 0
attr(by_b, "labels")[3,] <- 3

सारांश करें:

res <- by_b %>% summarise(count_a = n())

सूचकांक और oob_val की सभी घटनाओं को प्रतिस्थापित करता है

res[res == oob_val] <- 0

जो इरादा देता है:

> res
Source: local data frame [3 x 2]

b count_a
1 1       6
2 2       6
3 3       0

11

यह ठीक वैसा नहीं है जैसा प्रश्न में पूछा गया था, लेकिन कम से कम इस सरल उदाहरण के लिए, आप xtabs का उपयोग करके एक ही परिणाम प्राप्त कर सकते हैं, उदाहरण के लिए:

dplyr का उपयोग कर:

df %>%
  xtabs(formula = ~ b) %>%
  as.data.frame()

या इससे कम:

as.data.frame(xtabs( ~ b, df))

परिणाम (दोनों मामलों में बराबर):

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