2014-05-19 5 views
6

अभी मेरे पास निम्न डेटा है। फ्रेम जो original.df %.% group_by(Category) %.% tally() %.% arrange(desc(n)) द्वारा बनाया गया था।एक "अन्य" फ़ील्ड बनाना

DF <- structure(list(Category = c("E", "K", "M", "L", "I", "A", 
"S", "G", "N", "Q"), n = c(163051, 127133, 106680, 64868, 49701, 
47387, 47096, 45601, 40056, 36882)), .Names = c("Category", 
"n"), row.names = c(NA, 10L), class = c("tbl_df", "tbl", "data.frame" 
)) 

     Category  n 
1    E 163051 
2    K 127133 
3    M 106680 
4    L 64868 
5    I 49701 
6    A 47387 
7    S 47096 
8    G 45601 
9    N 40056 
10    Q 36882 

मैं नीचे रैंक श्रेणियों से "अन्य" फ़ील्ड बनाना चाहता हूं। अर्थात

 Category  n 
1    E 163051 
2    K 127133 
3    M 106680 
4    L 64868 
5    I 49701 
6   Other 217022 

अभी, मैं

rbind(filter(DF, rank(rev(n)) <= 5), 
    summarise(filter(DF, rank(rev(n)) > 5), Category = "Other", n = sum(n))) 

जो अन्य श्रेणी में शीर्ष 5 में नहीं सभी श्रेणियों गिर कर रहा हूं।

लेकिन मुझे उत्सुकता है कि dplyr या किसी अन्य मौजूदा पैकेज में कोई बेहतर तरीका है या नहीं। "बेहतर" से मेरा मतलब अधिक संक्षिप्त/पठनीय है। मैं चुनने के लिए चतुर या अधिक लचीला तरीकों के तरीकों में भी रूचि रखता हूं।

उत्तर

5

अलग पैकेज/विभिन्न वाक्य रचना संस्करण:

library(data.table) 

dt = as.data.table(DF) 

dt[order(-n), # your data is already sorted, so this does nothing for it 
    if (.BY[[1]]) .SD else list("Other", sum(n)), 
    by = 1:nrow(dt) <= 5][, !"nrow", with = F] 
# Category  n 
#1:  E 163051 
#2:  K 127133 
#3:  M 106680 
#4:  L 64868 
#5:  I 49701 
#6: Other 217022 
6

यह एक और तरीका है यह सोचते हैं कि हर वर्ग के (शीर्ष 5 में कम से कम) केवल एक बार होता है:

df %.% 
    arrange(desc(n)) %.%  #you could skip this step since you arranged the input df already according to your question 
    mutate(Category = ifelse(1:n() > 5, "Other", Category)) %.% 
    group_by(Category) %.% 
    summarize(n = sum(n)) 

# Category  n 
#1  E 163051 
#2  I 49701 
#3  K 127133 
#4  L 64868 
#5  M 106680 
#6 Other 217022 

संपादित करें:

मैं सिर्फ n कम करके देखा है कि मेरी उत्पादन आदेश नहीं है और भी कोड को फिर से चलाने के बाद, मुझे पता चला कि आदेश group_by(Category) के बाद तक रखा गया है, लेकिन जब मैं summarize चलाता हूं, तो आदेश चला जाता है (या इसके बजाय, ऐसा लगता है कि Category द्वारा आदेश दिया गया है)। क्या ऐसा होना चाहिए?

m <- 5 #number of top results to show in final table (excl. "Other") 
n <- m+1 

#preserves the order (or better: reesatblishes it by index) 
df <- arrange(df, desc(n)) %.% #this could be skipped if data already ordered 
    mutate(idx = 1:n(), Category = ifelse(idx > m, "Other", Category)) %.% 
    group_by(Category) %.% 
    summarize(n = sum(n), idx = first(idx)) %.% 
    arrange(idx) %.% 
    select(-idx) 

#doesnt preserve the order (same result as in first dplyr solution, ordered by Category) 
df[order(df$n, decreasing=T),]  #this could be skipped if data already ordered 
df[n:nrow(df),1] <- "Other" 
df <- aggregate(n ~ Category, data = df, FUN = "sum") 

#preserves the order (without extra index) 
df[order(df$n, decreasing=T),]  #this could be skipped if data already ordered 
df[n:nrow(df),1] <- "Other" 
df[n,2] <- sum(df$n[df$Category == "Other"]) 
df <- df[1:n,] 
0

यह फ़ंक्शन एक स्तंभ संशोधित करता है, Other साथ निराला प्रविष्टियों की जगह, या तो कम से कम आवृत्ति को निर्दिष्ट करके

यहाँ तीन अधिक तरीके हैं , या इच्छित श्रेणियों की परिणामी संख्या निर्दिष्ट करके।

#' @title Group infrequent entries into 'Other category' 
#' @description Useful when you want to constrain the number of unique values in a column. 
#' @param .data Data containing variable. 
#' @param var Variable containing infrequent entries, to be collapsed into "Other". 
#' @param n Threshold for total number of categories above "Other". 
#' @param count Threshold for total count of observations before "Other". 
#' @param by Extra variables to group by when calculating \code{n} or \code{count}. 
#' @param copy Should \code{.data} be copied? Currently only \code{TRUE} is supported. 
#' @param other.category Value that infrequent entries are to be collapsed into. Defaults to \code{"Other"}. 
#' @return \code{.data} but with \code{var} changed to be grouped into smaller categories. 
#' @export 
mutate_other <- function(.data, var, n = 5, count, by = NULL, copy = TRUE, other.category = "Other"){ 
    stopifnot(is.data.table(.data), 
      is.character(other.category), 
      identical(length(other.category), 1L)) 

    had.key <- haskey(.data) 

    if (!isTRUE(copy)){ 
    stop("copy must be TRUE") 
    } 

    out <- copy(.data) 

    if (had.key){ 
    orig_key <- key(out) 
    } else { 
    orig_key <- "_order" 
    out[, "_order" := 1:.N] 
    setkeyv(out, "_order") 
    } 

    if (is.character(.data[[var]])){ 
    stopifnot(!("nvar" %in% names(.data)), 
       var %in% names(.data)) 

    N <- .rank <- NULL 
    n_by_var <- 
     out %>% 
     .[, .N, keyby = c(var, by)] %>% 
     .[, .rank := rank(-N)] 

    out <- merge(out, n_by_var, by = c(var, by)) 

    if (missing(count)){ 
     out[, (var) := dplyr::if_else(.rank <= n, out[[var]], other.category)] 
    } else { 
     out[, (var) := dplyr::if_else(N >= count, out[[var]], other.category)] 
    } 
    out <- 
     out %>% 
     .[, N := NULL] %>% 
     .[, .rank := NULL] 

    setkeyv(out, orig_key) 

    if (!had.key){ 
     out[, (orig_key) := NULL] 
     setkey(out, NULL) 
    } 
    out 

    } else { 
    warning("Attempted to use by = on a non-character vector. Aborting.") 
    return(.data) 
    } 
} 

https://github.com/HughParsonage/hutils/blob/master/R/mutate_other.R

संबंधित मुद्दे