Суммируйте набор столбцов numeri c и сверните столбец строки по группе - PullRequest
1 голос
/ 06 августа 2020

Предположим, у меня есть такой фрейм данных (df):

    Names ID Thing1 Thing2 Thing3 Thing4 Thing5
1:  Gen1 id1    10     5    10     5      10
2:  Gen2 id2     1     2     3     4       5
3:  Gen1 id3    10     5    10     5      10
4:  Gen2 id4     1     2     3     4       5
5:  Gen3 id5     7     7     7     7       7

Для каждого «Names» я хотел бы суммировать столбцы «Thing» и свернуть строки в «ID»:

   Names   ID     Thing1  Thing2 Thing3 Thing4 Thing5
1:  Gen1 id1|id3    20      10     20     10    20
2:  Gen2 id2|id4     2       4      6      8    10
3:  Gen3 id5         7       7      7      7     7

Я могу добиться этого с помощью dplyr:

df1 <- df %>%
        group_by(Names)%>%
        summarise_each(funs(paste(unique(.), collapse='|')),matches('^\\D+$'))


df2 <- df %>%
         group_by(Names)%>%
           summarise_each(funs(sum = sum(., na.rm=TRUE)), starts_with('Thing' )) 

bind_cols(df1, df2[-1]) 

Однако это решение занимает очень много времени, поскольку у меня есть фрейм данных с более чем 10 тыс. Строк и более чем 10 тыс. Столбцов!

Есть ли какое-либо возможное решение с data.table?

Ближайшее, что я получил, это здесь:

> setDT(df)[, c(paste(df$ID,collapse = "-", sep = ""), lapply(.SD, sum, na.rm = TRUE)), 
            by = Names, .SDcols = !"ID"]

   Names                     Thing1 Thing2 Thing3 Thing4 Thing5
1:  Gen1 id1-id2-id3-id4-id5     20     10     20     10     20
2:  Gen2 id1-id2-id3-id4-id5      2      4      6      8     10
3:  Gen3 id1-id2-id3-id4-id5      7      7      7      7      7

Очевидно, это не то, что я собираюсь, так как он свернет все идентификаторы, а не только те, которые были объединены путем суммирования через «Имена».

Я был бы очень признателен за вашу помощь!

Вот пример данных:

df <- structure(list(Names = c("Gen1", "Gen2", "Gen1", "Gen2","Gen3"),
                      ID=c("id1","id2","id3","id4","id5"),
                      Thing1 = c(10L, 1L, 10L, 1L, 7L), 
                      Thing2 = c(5L, 2L, 5L, 2L,7L), 
                      Thing3 = c(10L, 3L, 10L, 3L, 7L), 
                      Thing4 = c(5L, 4L, 5L,4L, 7L), 
                      Thing5 = c(10L, 5L, 10L, 5L, 7L)), 
                      .Names = c("Names","ID","Thing1", "Thing2", "Thing3", "Thing4", "Thing5"),
                      class = "data.frame", row.names = c(1:5L))

Ответы [ 2 ]

0 голосов
/ 06 августа 2020

попробуйте так

используйте tidyverse

library(tidyverse) 
df %>% 
  group_by(Names) %>% 
  summarise(across(where(is.character), str_c, collapse = "|"),
            across(where(is.numeric), sum, na.rm = T))

# A tibble: 3 x 7
  Names ID      Thing1 Thing2 Thing3 Thing4 Thing5
  <chr> <chr>    <int>  <int>  <int>  <int>  <int>
1 Gen1  id1|id3     20     10     20     10     20
2 Gen2  id2|id4      2      4      6      8     10
3 Gen3  id5 

используйте data.table

library(data.table)
dt <- copy(df)
setDT(dt)
  
out_sum <- dt[, lapply(.SD, sum), by = Names, .SDcols=!"ID"] 
out_id <- dt[, list(id = sapply(list(ID), paste0, collapse = "|")), by = Names]  
merge(out_id, out_sum)

   Names      id Thing1 Thing2 Thing3 Thing4 Thing5
1:  Gen1 id1|id3     20     10     20     10     20
2:  Gen2 id2|id4      2      4      6      8     10
3:  Gen3     id5      7      7      7      7      7
0 голосов
/ 06 августа 2020

Если вы не сильно полагаетесь на data.table, вы можете использовать aggregate два раза и merge результаты.

merge(aggregate(.~Names, df[-2], sum), aggregate(ID ~ Names, df, paste, collapse="|"))
#   Names Thing1 Thing2 Thing3 Thing4 Thing5      ID
# 1  Gen1     20     10     20     10     20 id1|id3
# 2  Gen2      2      4      6      8     10 id2|id4
# 3  Gen3      7      7      7      7      7     id5
...