Moje pytanie polega na zsumowaniu wartości w wielu kolumnach ramki danych i utworzeniu nowej kolumny odpowiadającej temu podsumowaniu za pomocą dplyr
. Wpisy danych w kolumnach są binarne (0,1). Myślę o wierszowym odpowiedniku funkcji summarise_each
lub mutate_each
funkcji dplyr
. Poniżej znajduje się minimalny przykład ramki danych:
library(dplyr)
df=data.frame(
x1=c(1,0,0,NA,0,1,1,NA,0,1),
x2=c(1,1,NA,1,1,0,NA,NA,0,1),
x3=c(0,1,0,1,1,0,NA,NA,0,1),
x4=c(1,0,NA,1,0,0,NA,0,0,1),
x5=c(1,1,NA,1,1,1,NA,1,0,1))
> df
x1 x2 x3 x4 x5
1 1 1 0 1 1
2 0 1 1 0 1
3 0 NA 0 NA NA
4 NA 1 1 1 1
5 0 1 1 0 1
6 1 0 0 0 1
7 1 NA NA NA NA
8 NA NA NA 0 1
9 0 0 0 0 0
10 1 1 1 1 1
Przydałoby się coś takiego:
df <- df %>% mutate(sumrow= x1 + x2 + x3 + x4 + x5)
ale wymagałoby to wypisania nazw każdej z kolumn. Mam jakieś 50 kolumn. Ponadto nazwy kolumn zmieniają się przy różnych iteracjach pętli, w której chcę zaimplementować tę operację, dlatego chciałbym spróbować uniknąć konieczności nadawania jakichkolwiek nazw kolumn.
Jak mogę to zrobić najskuteczniej? Każda pomoc byłaby bardzo mile widziana.
dplyr
? Dlaczego nie po prostu prostydf$sumrow <- rowSums(df, na.rm = TRUE)
z podstawy R? Lubdf$sumrow <- Reduce(`+`, df)
jeśli chcesz dokładnie odtworzyć to, co zrobiłeśdplyr
.dplyr
tak jak wdf %>% mutate(sumrow = Reduce(`+`, .))
lubdf %>% mutate(sumrow = rowSums(.))
dplyr
wersji i będzie działać.Odpowiedzi:
Co powiesz na
podsumuj każdą kolumnę
df %>% replace(is.na(.), 0) %>% summarise_all(funs(sum))
podsumuj każdy wiersz
df %>% replace(is.na(.), 0) %>% mutate(sum = rowSums(.[1:5]))
źródło
summarise_each
sumuje się wzdłuż każdej kolumny, podczas gdy wymagana jest suma w każdym wierszu(.[1:5])
część, ale niestety nie jestem zaznajomiony ze składnią ani nie wiem, jak szukać pomocy. Próbowałem,mutate(sum = rowSums(is.numeric(.)))
ale nie działało.df %>% replace(is.na(.), 0) %>% select_if(is.numeric) %>% summarise_each(funs(sum))
?summarise_all
zamiast,summarise_each
ponieważ zostało wycofane.mutate(sum = rowSums(.[,-1]))
może się przydać, jeśli nie wiesz, z iloma kolumnami masz do czynienia.Jeśli chcesz zsumować tylko niektóre kolumny, użyłbym czegoś takiego:
library(dplyr) df=data.frame( x1=c(1,0,0,NA,0,1,1,NA,0,1), x2=c(1,1,NA,1,1,0,NA,NA,0,1), x3=c(0,1,0,1,1,0,NA,NA,0,1), x4=c(1,0,NA,1,0,0,NA,0,0,1), x5=c(1,1,NA,1,1,1,NA,1,0,1)) df %>% select(x3:x5) %>% rowSums(na.rm=TRUE) -> df$x3x5.total head(df)
W ten sposób możesz użyć
dplyr::select
składni.źródło
Użyłbym dopasowywania wyrażeń regularnych, aby zsumować zmienne o określonych nazwach wzorców. Na przykład:
df <- df %>% mutate(sum1 = rowSums(.[grep("x[3-5]", names(.))], na.rm = TRUE), sum_all = rowSums(.[grep("x", names(.))], na.rm = TRUE))
W ten sposób można utworzyć więcej niż jedną zmienną jako sumę określonej grupy zmiennych w ramce danych.
źródło
-
znak:rowSums(.[-grep("x[3-5]", names(.))], na.rm = TRUE)
Używanie
reduce()
frompurrr
jest nieco szybszerowSums
i zdecydowanie szybsze niżapply
, ponieważ unikasz iteracji po wszystkich wierszach i po prostu korzystasz z operacji wektoryzowanych:library(purrr) library(dplyr) iris %>% mutate(Petal = reduce(select(., starts_with("Petal")), `+`))
Zobacz to dla czasów
źródło
na.rm = TRUE
rowSums(select(., matches("myregex")) , na.rm = TRUE))
że zrobiłem, ponieważ tego potrzebowałem, jeśli chodzi o ignorowanie NA. Więc jeśli liczby tosum(NA, 5)
wynik to 5. Ale powiedziałeś, że redukcja jest lepsza niżrowSums
tak, zastanawiałem się, czy jest sposób, aby to wykorzystać w tej sytuacji?rowSums
wersja jest prawdopodobnie najlepsza. Główną wadą jest to, że tylkorowSums
irowMeans
są dostępne (jest nieco wolniejsza niż redukcja, ale nie za dużo). Jeśli musisz wykonać inną operację (nie sumę),reduce
wersja jest prawdopodobnie jedyną opcją. Po prostu unikaj używaniaapply
w tym przypadku.Często spotykam się z tym problemem, a najłatwiejszym sposobem jest użycie
apply()
funkcji wmutate
poleceniu.library(tidyverse) df=data.frame( x1=c(1,0,0,NA,0,1,1,NA,0,1), x2=c(1,1,NA,1,1,0,NA,NA,0,1), x3=c(0,1,0,1,1,0,NA,NA,0,1), x4=c(1,0,NA,1,0,0,NA,0,0,1), x5=c(1,1,NA,1,1,1,NA,1,0,1)) df %>% mutate(sum = select(., x1:x5) %>% apply(1, sum, na.rm=TRUE))
Tutaj możesz użyć wszystkiego, co chcesz, aby wybrać kolumny za pomocą standardowych
dplyr
sztuczek (np.starts_with()
Lubcontains()
). Wykonując całą pracę w ramach jednegomutate
polecenia, ta akcja może wystąpić w dowolnym miejscudplyr
strumienia kroków przetwarzania. Wreszcie, korzystając z tejapply()
funkcji, masz elastyczność w używaniu dowolnego podsumowania, którego potrzebujesz, w tym własnej funkcji podsumowania zbudowanej specjalnie.Alternatywnie, jeśli pomysł użycia funkcji non-tidyverse jest nieatrakcyjny, możesz zebrać kolumny, podsumować je i ostatecznie połączyć wynik z powrotem z oryginalną ramką danych.
df <- df %>% mutate( id = 1:n() ) # Need some ID column for this to work df <- df %>% group_by(id) %>% gather('Key', 'value', starts_with('x')) %>% summarise( Key.Sum = sum(value) ) %>% left_join( df, . )
Tutaj użyłem
starts_with()
funkcji, aby wybrać kolumny i obliczyć sumę, i możesz zrobić, co chcesz zNA
wartościami. Wadą tego podejścia jest to, że chociaż jest dość elastyczne, tak naprawdę nie pasuje dodplyr
strumienia kroków czyszczenia danych.źródło
apply
kiedy to jest to, do czegorowSums
zostało zaprojektowane.rowSums
działa naprawdę dobrzerowMeans
, ale zawsze czułem się trochę dziwnie, zastanawiając się: „A jeśli to, co muszę obliczyć, nie jest sumą ani średnią?” Jednak w 99% przypadków muszę zrobić coś takiego, albo jest to suma, albo średnia, więc może dodatkowa elastyczność w korzystaniu zapply
funkcji ogólnej nie jest uzasadniona.W nowszych wersjach programu
dplyr
można używaćrowwise()
wraz zc_across
do wykonywania agregacji wierszowej dla funkcji, które nie mają określonych wariantów wierszowych, ale jeśli istnieje wariant wierszowy, powinno być szybsze.Ponieważ
rowwise()
jest to tylko specjalna forma grupowania i zmienia sposób działania czasowników, prawdopodobnie będziesz chciał to potokowaćungroup()
po wykonaniu operacji na wierszach.Aby wybrać zakres wierszy:
df %>% dplyr::rowwise() %>% dplyr::mutate(sumrange = sum(dplyr::c_across(x1:x5), na.rm = T)) # %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()
Aby wybrać wiersze według typu:
df %>% dplyr::rowwise() %>% dplyr::mutate(sumnumeric = sum(c_across(where(is.numeric)), na.rm = T)) # %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()
W twoim konkretnym przypadku istnieje wariant wierszowy, więc możesz wykonać następujące czynności (zwróć uwagę na użycie
across
zamiast):df %>% dplyr::mutate(sumrow = rowSums(dplyr::across(x1:x5), na.rm = T))
Więcej informacji można znaleźć na stronie w wierszach .
źródło