как сложить на основе трех разных условий в R - PullRequest
1 голос
/ 23 декабря 2019

Ниже приведены мои данные.

gcode code year   P  Q
1      101  2000  1  3
1      101  2001  2  4
1      102  2000  1  1
1      102  2001  4  5
1      102  2002  2  6
1      102  2003  6  5
1      103  1999  6  1
1      103  2000  4  2
1      103  2001  2  1
2      104  2000  1  3
2      104  2001  2  4
2      105  2001  4  5
2      105  2002  2  6
2      105  2003  6  5
2      105  2004  6  1
2      106  2000  4  2
2      106  2001  2  1

gcode 1 имеет 3 разных кода 101, 102 и 103. Все они имеют один и тот же год (2000 и 2001). Я хочу подвести итоги P и Q за эти годы. В противном случае я хочу удалить ненужные данные. Я хочу сделать то же самое для gcode 2.

Как я могу получить такой результат?

gcode  year   P       Q
1      2000   1+1+4   3+1+2
1      2001   2+4+2   4+5+1
2      2001   2+4+2   4+5+1

Ответы [ 3 ]

4 голосов
/ 23 декабря 2019

Опция с использованием пакета data.table:

years <- DT[, {
    m <- min(year)
    ty <- tabulate(year-m)
    .(year=which(ty==uniqueN(code)) + m)
}, gcode]

DT[years, on=.(gcode, year),
    by=.EACHI, .(P=sum(P), Q=sum(Q))]

Вывод:

   gcode year P  Q
1:     1 2000 6  6
2:     1 2001 8 10
3:     2 2001 8 10

данные:

library(data.table)
DT <- fread("gcode code year   P  Q
1      101  2000  1  3
1      101  2001  2  4
1      102  2000  1  1
1      102  2001  4  5
1      102  2002  2  6
1      102  2003  6  5
1      103  1999  6  1
1      103  2000  4  2
1      103  2001  2  1
2      104  2000  1  3
2      104  2001  2  4
2      105  2001  4  5
2      105  2002  2  6
2      105  2003  6  5
2      105  2004  6  1
2      106  2000  4  2
2      106  2001  2  1")
4 голосов
/ 23 декабря 2019

Мы можем split данные, основанные на gcode, подгруппировать данные, основанные на общих year, которые присутствуют во всех code и aggregate данных, на gcode и year.

do.call(rbind, lapply(split(df, df$gcode), function(x) {
      aggregate(cbind(P, Q)~gcode+year, 
               subset(x, year %in% Reduce(intersect, split(x$year, x$code))), sum)
}))

#    gcode year P  Q
#1.1     1 2000 6  6
#1.2     1 2001 8 10
#2       2 2001 8 10

Используя dplyr с аналогичной логикой, мы можем сделать

library(dplyr)
df %>%
  group_split(gcode) %>%
  purrr::map_df(. %>% 
                 group_by(year) %>% 
                 filter(n_distinct(code) == n_distinct(.$code)) %>% 
                 group_by(gcode, year) %>%
                 summarise_at(vars(P:Q), sum))

data

df <- structure(list(gcode = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), code = c(101L, 101L, 102L, 102L, 
102L, 102L, 103L, 103L, 103L, 104L, 104L, 105L, 105L, 105L, 105L, 
106L, 106L), year = c(2000L, 2001L, 2000L, 2001L, 2002L, 2003L, 
1999L, 2000L, 2001L, 2000L, 2001L, 2001L, 2002L, 2003L, 2004L, 
2000L, 2001L), P = c(1L, 2L, 1L, 4L, 2L, 6L, 6L, 4L, 2L, 1L, 
2L, 4L, 2L, 6L, 6L, 4L, 2L), Q = c(3L, 4L, 1L, 5L, 6L, 5L, 1L, 
2L, 1L, 3L, 4L, 5L, 6L, 5L, 1L, 2L, 1L)), class = "data.frame", 
row.names = c(NA, -17L))
3 голосов
/ 23 декабря 2019

Я придумал следующее решение. Во-первых, я посчитал, сколько раз каждый год появляется для каждого gcode. Я также посчитал, сколько уникальных кодов существует для каждого gcode. Затем объедините два результата, используя left_join(). Затем я определил строки с одинаковыми значениями в n_year и n_code. Затем я присоединился к исходному фрейму данных, который называется mydf. Затем я определил группы по gcode и year и суммировал P и Q для каждой группы.

library(dplyr)

left_join(count(mydf, gcode, year, name = "n_year"),
          group_by(mydf, gcode) %>% summarize(n_code = n_distinct(code))) %>% 
filter(n_year == n_code) %>% 
left_join(mydf, by = c("gcode", "year")) %>% 
group_by(gcode, year) %>% 
summarize_at(vars(P:Q),
             .funs = list(~sum(.)))

#  gcode  year     P     Q
#  <int> <int> <int> <int>
#1     1  2000     6     6
#2     1  2001     8    10
#3     2  2001     8    10
...