2017-09-09 1 views
1

Dies ist eine Nachfolge von this question. Ich kann die gewünschte Ausgabe nicht erreichen.Zusammenfassende Zeile jeder Faktorstufe mit dplyr in R

Reg <- rep(LETTERS[1:5], c(4, 6, 4, 4, 6)) 
City <- rep(letters[1:12], each = 2) 
Res <- rep(c("Urban", "Rural"), times = length(Reg)/2) 
set.seed(12345) 
Pop <- rpois(n = length(Reg), lambda = 500000) 
Pop1 <- rpois(n = length(Reg), lambda = 500) 
df <- data.frame(Reg, City, Res, Pop, Pop1) 

df3 <- 
df %>% 
    group_by(Reg) %>% 
    summarise(Pop = sum(Pop), Pop1 = sum(Pop1), Res = 'Total') %>% 
    bind_rows(df) %>% 
    arrange(Reg) %>% 
    select(Reg, Res, Pop, Pop1) %>% 
    distinct() 
df3 


# A tibble: 29 x 4 
     Reg Res  Pop Pop1 
    <fctr> <chr> <int> <int> 
1  A Total 2000853 2135 
2  A Urban 500414 549 
3  A Rural 500501 545 
4  A Urban 499922 536 
5  A Rural 500016 505 
6  B Total 3000844 2938 
7  B Urban 501638 510 
8  B Rural 499274 492 
9  B Urban 499804 506 
10  B Rural 499825 508 
# ... with 19 more rows 

Dann wird der folgende Code ist erforderlich, ländliche und städtische Summen innerhalb jeden Reg

df3 %>% group_by(Reg, Res) %>% summarise(sum(Pop), sum(Pop1)) 

# A tibble: 15 x 4 
# Groups: Reg [?] 
     Reg Res `sum(Pop)` `sum(Pop1)` 
    <fctr> <chr>  <int>  <int> 
1  A Rural 1000517  1050 
2  A Total 2000853  2135 
3  A Urban 1000336  1085 
4  B Rural 1499485  1446 
5  B Total 3000844  2938 
6  B Urban 1501359  1492 
7  C Rural  999234   987 
8  C Total 1997259  2007 
9  C Urban  998025  1020 
10  D Rural  998760  1058 
11  D Total 2000712  2052 
12  D Urban 1001952   994 
13  E Rural 1501848  1547 
14  E Total 2999304  3050 
15  E Urban 1497456  1503 

zu finden, die auch andere Reihenfolge für Res Spalte hat.

Ich möchte jedoch alle Berechnungen effizienter und kompakter durchführen.

Wunsch Ausgang

Reg Res  Pop Pop1 
1  A Total 2000853 2135 
2  A Urban 1000336 1085 
3  A Rural 1000517 1050 

4  B Total 3000844 2938 
5  B Urban 1501359 1492 
6  B Rural 1499485 1446 

Antwort

3

nicht sicher, dass es kompakter, aber durch die Reihenfolge der beiden Gruppe von Prozessen Umkehren können Sie mehrere Zeilen Code beseitigen:

df %>% 
    group_by(Reg, Res) %>%   # group by Reg and Res first 
    summarise(Pop = sum(Pop), Pop1 = sum(Pop1)) %>% 
    bind_rows(
     group_by(., Reg) %>%   # now group by Reg and bind_rows with previous result 
      summarise(Pop = sum(Pop), Pop1 = sum(Pop1), Res = 'Total'), 
     .  # <<<<<<    bind total above other Res by passing previous 
            # result as second argument in the bind_rows 
    ) %>% arrange(Reg) 

# A tibble: 15 x 4 
#  Reg  Pop Pop1 Res 
# <chr> <int> <int> <chr> 
# 1  A 2000853 2135 Total 
# 2  A 1000517 1050 Rural 
# 3  A 1000336 1085 Urban 
# 4  B 3000844 2938 Total 
# 5  B 1499485 1446 Rural 
# 6  B 1501359 1492 Urban 
# 7  C 1997259 2007 Total 
# 8  C 999234 987 Rural 
# 9  C 998025 1020 Urban 
# 10  D 2000712 2052 Total 
# 11  D 998760 1058 Rural 
# 12  D 1001952 994 Urban 
# 13  E 2999304 3050 Total 
# 14  E 1501848 1547 Rural 
# 15  E 1497456 1503 Urban 
+0

Dank @Psidom für nette Antwort. Würde mich freuen, wenn Sie das Problem der Show Total Zeile über Urban und Rural adressieren können. Danke – MYaseen208

+0

In 'bind_rows' können Sie die Reihenfolge der Summe und des ursprünglichen Datenrahmens, auf den Sie mit' .' zugreifen können, in die Pipe ('%>%') umschalten, und wenn 'total' als erstes Argument steht, dann' Total würde über * Urban * und * Rural * liegen. – Psidom

+0

Danke @Psidom für nette Lösung. Ich würde es sehr schätzen, wenn Sie mir helfen können, Total zu bekommen, selbst wenn Urban oder Rural NA ist. – MYaseen208

0

Hier eine Option unter Verwendung tidyverse

library(tidyverse) 
map(list(c("Reg", "Res"), "Reg"), ~df %>% group_by(!!! syms(.x)) %>% 
      summarise_at(vars("Pop", "Pop1"), sum)) %>% 
      bind_rows %>% 
      mutate(Res = replace(as.character(Res), is.na(Res), "Total")) %>% 
      arrange(Reg, Res != "Total") 
# A tibble: 15 x 4 
# Groups: Reg [5] 
#  Reg Res  Pop Pop1 
# <fctr> <chr> <int> <int> 
# 1  A Total 2000853 2135 
# 2  A Rural 1000517 1050 
# 3  A Urban 1000336 1085 
# 4  B Total 3000844 2938 
# 5  B Rural 1499485 1446 
# 6  B Urban 1501359 1492 
# 7  C Total 1997259 2007 
# 8  C Rural 999234 987 
# 9  C Urban 998025 1020 
#10  D Total 2000712 2052 
#11  D Rural 998760 1058 
#12  D Urban 1001952 994 
#13  E Total 2999304 3050 
#14  E Rural 1501848 1547 
#15  E Urban 1497456 1503 

oder eine ähnliche Option mit data.table

library(data.table) 
rbindlist(Map(function(grp) df[, lapply(.SD, sum), by = c(grp), .SDcols = Pop:Pop1], 
    list(c("Reg", "Res"), "Reg")), fill = TRUE)[ 
     is.na(Res), Res := "Total"][order(Reg, Res != "Total")] 
# Reg Res  Pop Pop1 
# 1: A Total 2000853 2135 
# 2: A Urban 1000336 1085 
# 3: A Rural 1000517 1050 
# 4: B Total 3000844 2938 
# 5: B Urban 1501359 1492 
# 6: B Rural 1499485 1446 
# 7: C Total 1997259 2007 
# 8: C Urban 998025 1020 
# 9: C Rural 999234 987 
#10: D Total 2000712 2052 
#11: D Urban 1001952 994 
#12: D Rural 998760 1058 
#13: E Total 2999304 3050 
#14: E Urban 1497456 1503 
#15: E Rural 1501848 1547