Dplyr ile birden çok sütun boyunca toplama


98

Sorum, bir veri çerçevesinin birden çok sütunundaki değerleri toplamayı ve kullanarak bu toplama karşılık gelen yeni bir sütun oluşturmayı içerir dplyr. Sütunlardaki veri girişleri ikilidir (0,1). summarise_eachVeya mutate_eachişlevinin satır bazında bir analoğunu düşünüyorum dplyr. Aşağıda, veri çerçevesinin minimal bir örneği verilmiştir:

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

Şunun gibi bir şey kullanabilirim:

df <- df %>% mutate(sumrow= x1 + x2 + x3 + x4 + x5)

ancak bu, sütunların her birinin adının yazılmasını içerir. 50 tane sütunum var. Ek olarak, bu işlemi uygulamak istediğim döngünün farklı yinelemelerinde sütun adları değişir, bu nedenle herhangi bir sütun adı vermek zorunda kalmamaya çalışmak istiyorum.

Bunu en verimli şekilde nasıl yapabilirim? Herhangi bir yardım çok takdir edilecektir.


11
Neden dplyr? Neden basit bir df$sumrow <- rowSums(df, na.rm = TRUE)R tabanından değil ? Ya df$sumrow <- Reduce(`+`, df)da yaptığınız şeyi aynen kopyalamak istiyorsanız dplyr.
David Arenburg

7
dplyrdf %>% mutate(sumrow = Reduce(`+`, .))df %>% mutate(sumrow = rowSums(.))
İkisini

2
En son dplyrsürüme güncelleyin ve çalışacaktır.
David Arenburg

1
David Arenburg'un önerileri dplyr paketini güncelledikten sonra çalıştı @DavidArenburg
amo

1
@boern David Arenburgs yorumu en iyi cevap ve en doğrudan çözümdü. Cevabınız işe yarayabilir, ancak NA değerlerini sıfırla değiştirmek için fazladan bir adım içerir ve bu bazı durumlarda uygun olmayabilir.
amo

Yanıtlar:


112

Ne dersin

her sütunu topla

df %>%
   replace(is.na(.), 0) %>%
   summarise_all(funs(sum))

her satırı topla

df %>%
   replace(is.na(.), 0) %>%
   mutate(sum = rowSums(.[1:5]))

8
summarise_eachher bir sütun boyunca aşağı doğru toplar, gerekli olan ise her satırdaki toplamdır
amo

1
Ben de aynısını elde etmeye çalışıyorum ama benim DF'mde bir karakter olan bir sütun var, bu nedenle tüm sütunları toplayamıyorum. Sanırım (.[1:5])parçayı değiştirmem gerekiyor , ama ne yazık ki sözdizimine aşina değilim ve bu konuda nasıl yardım arayacağımı da bilmiyorum. Denedim mutate(sum = rowSums(is.numeric(.)))ama işe yaramadı.
ccamara

5
Anlıyorum. df %>% replace(is.na(.), 0) %>% select_if(is.numeric) %>% summarise_each(funs(sum))Bir şans vermek isteyebilir misin ?
Boern

2
Kullanımdan kaldırıldığı şekliyle summarise_allyerine kullanın summarise_each.
hmhensen

2
Sözdizimi mutate(sum = rowSums(.[,-1])), kaç sütunla uğraşmanız gerektiğini bilmiyorsanız kullanışlı olabilir.
Paulo S. Abreu

33

Yalnızca belirli sütunları toplamak istiyorsanız, bunun gibi bir şey kullanırım:

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)

Bu şekilde dplyr::select'ın sözdizimini kullanabilirsiniz .


NA'ları 0'a zorlamasını gerektirmediği için bu yaklaşımı diğerlerinden daha çok seviyorum
Michael Bellhouse

Ve grep'ten daha iyi çünkü x4: x11 gibi şeylerle uğraşmak daha kolay
Dov Rosenberg

32

Belirli desen adlarına sahip değişkenleri toplamak için normal ifade eşleştirmesini kullanırdım. Örneğin:

df <- df %>% mutate(sum1 = rowSums(.[grep("x[3-5]", names(.))], na.rm = TRUE),
                    sum_all = rowSums(.[grep("x", names(.))], na.rm = TRUE))

Bu şekilde, veri çerçevenizdeki belirli değişken grubunun toplamı olarak birden fazla değişken oluşturabilirsiniz.


harika çözüm! Son sürümlerde bunu yapan belirli bir dplyr işlevi arıyordum, ancak bulamadım
agenis

Bu çözüm harika. Dahil etmek istemediğiniz sütunlar varsa, belirli bir desenle eşleşen sütunları seçmek için grep () ifadesini tasarlamanız yeterlidir.
Trenton Hoffman

1
@TrentonHoffman burada belirli bir desen sütunlarının seçimini kaldıran bittir. sadece -işarete ihtiyacım var :rowSums(.[-grep("x[3-5]", names(.))], na.rm = TRUE)
alexb523

22

Bu sorunla sık sık karşılaşıyorum ve bunu yapmanın en kolay yolu, apply()işlevi bir mutatekomut içinde kullanmaktır .

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))

Burada, standart dplyrhileleri (örneğin starts_with()veya contains()) kullanarak sütunları seçmek istediğinizi kullanabilirsiniz . Tüm işi tek bir mutatekomut içinde yaparak , bu eylem, bir dplyrişleme adımları akışı içinde herhangi bir yerde gerçekleşebilir . Son olarak, apply()işlevi kullanarak, kendi amaca yönelik oluşturulmuş özetleme işlevi dahil olmak üzere ihtiyacınız olan özeti kullanma esnekliğine sahip olursunuz.

Alternatif olarak, tidyverse olmayan bir işlevi kullanma fikri çekici değilse, o zaman sütunları toplayabilir, özetleyebilir ve sonunda sonucu orijinal veri çerçevesine geri birleştirebilirsiniz.

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, . )

Burada starts_with()sütunları seçmek için işlevi kullandım ve toplamı hesapladım ve NAdeğerlerle istediğinizi yapabilirsiniz . Bu yaklaşımın dezavantajı, oldukça esnek olmasına rağmen, dplyrveri temizleme adımlarının akışına gerçekten uymamasıdır .


3
applyBunun için rowSumstasarlandığı zaman kullanmak aptalca görünüyor .
zacdav

6
Bu durumda rowSumsgerçekten işe yarıyor rowMeans, ama her zaman biraz garip hissettim, "Ya hesaplamam gereken şey bir toplam veya bir ortalama değilse?" Bununla birlikte, zamanın% 99'unda böyle bir şey yapmak zorunda kalıyorum, bu ya bir toplam ya da bir ortalamadır, bu yüzden belki de genel applyişlevi kullanmadaki ekstra esneklik garanti değildir.
Derek Sonderegger

22

reduce()From kullanmak , purrrbundan biraz daha hızlıdır rowSumsve kesinlikle daha hızlıdır apply, çünkü tüm satırlar üzerinde yinelemekten kaçınırsınız ve sadece vektörleştirilmiş işlemlerden yararlanabilirsiniz:

library(purrr)
library(dplyr)
iris %>% mutate(Petal = reduce(select(., starts_with("Petal")), `+`))

Bkz bu zamanlamaları


Bunu beğendim ama ihtiyacınız olduğunda bunu nasıl yapardınızna.rm = TRUE
bkz. 24

@ see24 Ne demek istediğini anladığımdan emin değilim. Bu, hepsi aynı uzunlukta olan a + b + c vektörlerini toplar. Her vektör farklı yerlerde NA'ya sahip olabileceği veya olmayabileceği için, onları göz ardı edemezsiniz. Bu, vektörleri hizasız hale getirir. Eğer NA değerleri kaldırmak isterseniz bunu yapmak zorunda sonradan örneğin ile, drop_na
SKD

Yapmaya son verdim rowSums(select(., matches("myregex")) , na.rm = TRUE))çünkü NA'ları görmezden gelmek için ihtiyacım olan şey buydu. Yani sum(NA, 5)sonuçlar 5 ise sayılar . Ama azaltmanın daha iyi olduğunu söylediniz rowSums, acaba bu durumda kullanmanın bir yolu var mı?
see24

Anlıyorum. Toplamı istiyorsanız ve NA değerlerini kesinlikle göz ardı etmek istiyorsanız, rowSumssürüm muhtemelen en iyisidir. Ana dezavantaj, yalnızca rowSumsve rowMeanskullanılabilir olmasıdır (azaltmaya göre biraz daha yavaştır, ancak çok fazla değil). Başka bir işlem yapmanız gerekiyorsa (toplamı değil), reducesürüm muhtemelen tek seçenektir. Sadece applybu durumda kullanmaktan kaçının .
skd

2

Yeni sürümlerinde, belirli satır bazlı varyantlara sahip olmayan fonksiyonlar için satır bazında toplama gerçekleştirmek dplyriçin rowwise()birlikte kullanabilirsiniz c_across, ancak satır bazlı varyant mevcutsa daha hızlı olmalıdır.

Yana rowwise()gruplama sadece özel bir şeklidir ve fiiller büyük olasılıkla boru bunu isteyeceksiniz çalışma biçimini değiştiren ungroup()sizin sıra sıra operasyon yaptıktan sonra.

Bir dizi satır seçmek için:

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()

Türe göre satır seçmek için:

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()

Özel durumunuzda satır bazlı bir varyant vardır, böylece aşağıdakileri yapabilirsiniz ( acrossbunun yerine kullanımına dikkat edin ):

df %>%
  dplyr::mutate(sumrow = rowSums(dplyr::across(x1:x5), na.rm = T))
# %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()

Daha fazla bilgi için satır bazında sayfaya bakın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.