2017-04-20 6 views
0

(Muster in einem Vektor enthalten) habe ich eine data.frame wie folgt:Mutate (gilt eine Operation an) mehrere unterschiedlich große Teilmengen von Spalten mit automatischer Namensgebung in dplyr

df = data.frame(a1 = c(1:6, rep(NA,6)), 
       a2 = c(rep(NA,6), 7:12), 
       b1 = rep(c(1,NA), 6), 
       b2 = rep(c(NA,2), 6), 
       c1 = rep(c(1,NA,NA), each=4), 
       c2 = rep(c(NA,2,NA), each=4), 
       c3 = rep(c(NA,NA,3), each=4)) 
# a1 a2 b1 b2 c1 c2 c3 
# 1 1 NA 1 NA 1 NA NA 
# 2 2 NA NA 2 1 NA NA 
# 3 3 NA 1 NA 1 NA NA 
# 4 4 NA NA 2 1 NA NA 
# 5 5 NA 1 NA NA 2 NA 
# 6 6 NA NA 2 NA 2 NA 
# 7 NA 7 1 NA NA 2 NA 
# 8 NA 8 NA 2 NA 2 NA 
# 9 NA 9 1 NA NA NA 3 
# 10 NA 10 NA 2 NA NA 3 
# 11 NA 11 1 NA NA NA 3 
# 12 NA 12 NA 2 NA NA 3 

Hier gibt es 3 Gruppen von Spalten, die jeweils ein Muster im Namen enthalten (2 Spalten mit a, 2 Spalten mit b und 3 Spalten mit c), und ich muss eine Operation auf diese Teilmengen anwenden, um sie alle in einer einzigen Spalte zusammenzufassen (benannt nach der allgemeines Muster) - hier einfach durch Zusammenführen, um die NAs zu entfernen.

ich es mit Base R zum Beispiel tun könnte wie folgt:

sapply(c('a', 'b', 'c'), function(x) rowSums(df[,grepl(x, names(df))], na.rm=T)) 
#  a b c 
# [1,] 1 1 1 
# [2,] 2 2 1 
# [3,] 3 1 1 
# [4,] 4 2 1 
# [5,] 5 1 2 
# [6,] 6 2 2 
# [7,] 7 1 2 
# [8,] 8 2 2 
# [9,] 9 1 3 
# [10,] 10 2 3 
# [11,] 11 1 3 
# [12,] 12 2 3 

Aber ich kann nicht herausfinden, wie es in dplyr zu tun? Ich nehme an, durch eine intelligente Kombination von mutate_each_ und select(contains()) etc, aber ich kann es nicht bekommen ... ??

Da es potenziell viele Untergruppen von Spalten gibt, brauche ich eine völlig automatische Lösung, wo ich einfach den Mustervektor (hier, c('a','b','c')) gebe (d. H. Ich möchte die Ausgabespalten nicht manuell benennen).

Antwort

3

Wir können dies aus tidyverse Paket mit map tun (purrr) nach split ting des Datensatzes durch die Spaltennamen ohne die Zahlen (sub(...))

library(tidyverse) 
split.default(df, sub("\\d+", "", names(df))) %>% 
         map_df(~rowSums(., na.rm = TRUE)) 
#  A tibble: 12 × 3 
#  a  b  c 
# <dbl> <dbl> <dbl> 
#1  1  1  1 
#2  2  2  1 
#3  3  1  1 
#4  4  2  1 
#5  5  1  2 
#6  6  2  2 
#7  7  1  2 
#8  8  2  2 
#9  9  1  3 
#10 10  2  3 
#11 11  1  3 
#12 12  2  3 
+2

So wird alles mit Base R durchgeführt, während 'sapply' mit' purrr ersetzt wurde :: map_df' (und ein ' %>% ') so wird es cooler aussehen? Ich verstehe nicht mehr, was jetzt los ist. –

+0

@DavidArenburg Die 'split' und' rowSums' stammen von 'base R'. Das ist keine Frage. Aber hier verwenden wir eine Methode, um mit Ketten zu verbinden. – akrun

2

Eine allgemeine tidyverse Lösung könnten Sie zuerst neu zu gestalten benötigen. Leider müssen wir während dieser Operation die Zeilen im Auge behalten, was den Code ein wenig verlängert.

patterns <- c('a', 'b', 'c') 

df %>% 
    mutate(i = row_number()) %>% 
    gather(key, value, -i) %>% 
    mutate(group = do.call(coalesce, purrr::map(patterns, ~stringr::str_match(tmp$key, .)))) %>% 
    group_by(group, i) %>% 
    summarise(value = sum(value, na.rm = TRUE)) %>% 
    spread(group, value) %>% 
    select(-i) 

Gibt:

# A tibble: 12 × 3 
     a  b  c 
* <dbl> <dbl> <dbl> 
1  1  1  1 
2  2  2  1 
3  3  1  1 
4  4  2  1 
5  5  1  2 
6  6  2  2 
7  7  1  2 
8  8  2  2 
9  9  1  3 
10 10  2  3 
11 11  1  3 
12 12  2  3 

Sie können jede beliebige Operation an den ursprünglichen Reihen durchführen, indem die epxression in der summarise Aussage zu ändern. Es verallgemeinert sich auch auf jedes beliebige Muster.

Sie könnten möglicherweise das SE-Paradigma verwenden, um direkt eine entsprechende transmute-Funktion zu codieren, aber ich kann nicht genau herausfinden, wie (mit dem kommenden dplyr0.6.0). Ein Start für ein einzelnes Muster:

patterns <- c('a', 'b', 'c') 
cols <- map(patterns, ~map(grep(., names(df), value = TRUE), rlang::as_symbol)) 

transmute(df, !!patterns[1] := coalesce(!!!cols[[1]])) 

Gibt:

a 
1 1 
2 2 
3 3 
4 4 
5 5 
6 6 
7 7 
8 8 
9 9 
10 10 
11 11 
12 12 
Verwandte Themen