2015-09-28 12 views
11

In this blog post, Paul Hiemstra mostra come riassumere due colonne utilizzando dplyr::mutate_. Copia/incolla-ing parti rilevanti:Utilizzo di 'mutate_' per sommare un gruppo di colonne per riga

library(lazyeval) 
f = function(col1, col2, new_col_name) { 
    mutate_call = lazyeval::interp(~ a + b, a = as.name(col1), b = as.name(col2)) 
    mtcars %>% mutate_(.dots = setNames(list(mutate_call), new_col_name)) 
} 

permette di fare poi:

head(f('wt', 'mpg', 'hahaaa')) 

Grande!

Ho seguito una domanda (vedi commenti) su come estendere questo a 100 colonne, poiché non era chiaro (per me) come si potesse fare senza dover digitare tutti i nomi usando il metodo sopra. Paul è stato così gentile di indulgere me e ha fornito questa risposta (grazie!):

# data 
df = data.frame(matrix(1:100, 10, 10)) 
names(df) = LETTERS[1:10] 

# answer 
sum_all_rows = function(list_of_cols) { 
    summarise_calls = sapply(list_of_cols, function(col) { 
    lazyeval::interp(~col_name, col_name = as.name(col)) 
    }) 
    df %>% select_(.dots = summarise_calls) %>% mutate(ans1 = rowSums(.)) 
} 
sum_all_rows(LETTERS[sample(1:10, 5)]) 

Mi piacerebbe migliorare questa risposta su questi punti:

  1. Le altre colonne sono andati. Mi piacerebbe tenerli.

  2. Esso utilizza rowSums() che deve costringere il data.frame ad una matrice di che vorrei evitare.

    Anche io non sono sicuro se l'uso di . all'interno non do() verbi è incoraggiato? Perché . all'interno di mutate() non sembra adattarsi solo a quelle righe quando viene utilizzato con group_by().

  3. E, cosa più importante, come posso fare lo stesso utilizzando mutate_() anziché mutate()?

ho trovato this answer, che affronta il punto 1, ma purtroppo, entrambe le risposte dplyr utilizzare rowSums() con mutate().


PS: Ho appena letto Hadley's comment under that answer. IIUC, 'risagoma a forma lunga + gruppo per + somma + risagoma a forma estesa' è il modo consigliato per questo tipo di operazioni? dplyr?

+0

Non c'è bisogno di 'biblioteca (lazyeval)' quando si qualificano in modo esplicito il suo utilizzo in ogni caso. –

risposta

7

Ecco un approccio diverso:

library(dplyr); library(lazyeval) 
f <- function(df, list_of_cols, new_col) { 
    df %>% 
    mutate_(.dots = ~Reduce(`+`, .[list_of_cols])) %>% 
    setNames(c(names(df), new_col)) 
} 

head(f(mtcars, c("mpg", "cyl"), "x")) 
# mpg cyl disp hp drat wt qsec vs am gear carb x 
#1 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 27.0 
#2 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 27.0 
#3 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 26.8 
#4 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 27.4 
#5 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 26.7 
#6 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 24.1 

Per quanto riguarda i punti:

  • altre colonne vengono tenuti
  • Non usa rowSums
  • Stai specificamente chiedendo un'operazione di riga-saggio qui quindi non sono ancora sicuro (ancora) di come group_by potrebbe fare del male quando si utilizza . all'interno mutate/mutate_
  • Si avvale di mutate_
+0

Grande! Su '.' con' group_by() ', trovo che sia strano. Come esempio, calcola la somma delle righe e dividile per somma massima all'interno del gruppo. Immagino che prima calcolerai la somma delle righe e poi raggrupperai per ottenere il rapporto? Se è così, trovo strano (di non essere in grado di farlo in un solo passaggio usando mutate, ma usando 'do()'). Ma forse è di progettazione, non preoccuparti. Grazie. – Arun

+0

Ciao @docendo discimus. Bella risposta. Sai se nelle versioni recenti di dplyr c'è qualche funzione che aggiunge una colonna come somma di colonne che corrispondono ad alcune espressioni regolari? – agenis

Problemi correlati