Создать несколько сумм - PullRequest
       34

Создать несколько сумм

0 голосов
/ 18 сентября 2018

Ciao, вот реплицируемый пример.

   df <- data.frame("STUDENT"=c(1,2,3,4,5),
                     "TEST1A"=c(NA,5,5,6,7),
                     "TEST2A"=c(NA,8,4,6,9),
                     "TEST3A"=c(NA,10,5,4,6),
                     "TEST1B"=c(5,6,7,4,1),
                     "TEST2B"=c(10,10,9,3,1),
                     "TEST3B"=c(0,5,6,9,NA),
                     "TEST1TOTAL"=c(NA,23,14,16,22),
                     "TEST2TOTAL"=c(10,16,15,12,NA))

У меня есть столбцы STUDENT через TEST3B и я хочу создать TEST1TOTAL TEST2TOTAL.TEST1TOTAL = TEST1A + TEST2A + TEST3A и так далее для TEST2TOTAL.Если в TEST1A TEST2A TEST3A есть пропущенная оценка, тогда TEST1TOTAL - это NA.

Вот моя попытка, но есть ли решение с меньшим количеством строк кода?Потому что здесь мне нужно будет выписать эту строку много раз, так как там до ТЕСТА от А до О.

TEST1TOTAL=rowSums(df[,c('TEST1A', 'TEST2A', 'TEST3A')], na.rm=TRUE)

Ответы [ 3 ]

0 голосов
/ 18 сентября 2018

Использование только базовых функций R:

output <- data.frame(df1, do.call(cbind, lapply(c("A$", "B$"), function(x) rowSums(df1[, grep(x, names(df1))]))))

Настройка имен столбцов:

> colnames(output)[(ncol(output)-1):ncol(output)] <- c("TEST1TOTAL", "TEST2TOTAL")
> output
  STUDENT TEST1A TEST2A TEST3A TEST1B TEST2B TEST3B TEST1TOTAL TEST2TOTAL
1       1     NA     NA     NA      5     10      0         NA         15
2       2      5      8     10      6     10      5         23         21
3       3      5      4      5      7      9      6         14         22
4       4      6      6      4      4      3      9         16         16
5       5      7      9      6      1      1     NA         22         NA
0 голосов
/ 18 сентября 2018

Я думаю, что вы хотите, Решение Джилбера Урбины - это путь.Для полноты (и потому, что я узнал кое-что, выясняя это), вот простой способ получить итоговые оценки по номеру теста для любого количества тестов.

Преимущество заключается в том, что вам не нужно указывать идентификаторы длятесты (кроме того, они пронумерованы или имеют завершающую букву) и тот же код будет работать для любого количества тестов.

library(tidyverse)

df_totals <- df %>%
    gather(test, score, -STUDENT) %>%                    # Convert from wide to long format
    mutate(test_num = paste0('TEST', ('[^0-9]', '', test),
                             'TOTAL'),                   # Extract test_number from variable
           test_let = gsub('TEST[0-9]*', '', test)) %>%  # Extract test_letter (optional)
    group_by(STUDENT, test_num) %>%                      # group by student + test
    summarize(score_tot = sum(score)) %>%                # Sum score by student/test
    spread(test_num, score_tot)                          # Spread back to wide format

df_totals

# A tibble: 5 x 4
# Groups:   STUDENT [5]
  STUDENT TEST1TOTAL TEST2TOTAL TEST3TOTAL
    <dbl>      <dbl>      <dbl>      <dbl>
1       1         NA         NA         NA
2       2         11         18         15
3       3         12         13         11
4       4         10          9         13
5       5          8         10         NA

Если вы хотите, чтобы отдельные баллы тоже, просто объедините итоги вместе соригинал:

left_join(df, df_totals, by = 'STUDENT')
  STUDENT TEST1A TEST2A TEST3A TEST1B TEST2B TEST3B TEST1TOTAL TEST2TOTAL TEST3TOTAL
1       1     NA     NA     NA      5     10      0         NA         NA         NA
2       2      5      8     10      6     10      5         11         18         15
3       3      5      4      5      7      9      6         12         13         11
4       4      6      6      4      4      3      9         10          9         13
5       5      7      9      6      1      1     NA          8         10         NA
0 голосов
/ 18 сентября 2018

Попробуйте:

library(dplyr)
df %>%
        mutate(TEST1TOTAL = TEST1A+TEST2A+TEST3A,
               TEST2TOTAL = TEST1B+TEST2B+TEST3B)

или

df %>%
        mutate(TEST1TOTAL = rowSums(select(df, ends_with("A"))),
               TEST2TOTAL = rowSums(select(df, ends_with("B"))))
...