Получить все возможные комбинации из n элементов заданного размера k и применить функцию sum к другому столбцу. - PullRequest
0 голосов
/ 26 сентября 2018

У меня есть df, похожий на:

  item value
1    a     1
2    b     4
3    c     3
4    d     2
5    e     6
6    f     8
7    g    11

df <- data.frame(stringsAsFactors=FALSE,
        item = c("a", "b", "c", "d", "e", "f", "g"),
       value = c(1L, 4L, 3L, 2L, 6L, 8L, 11L))

Я хочу сгенерировать все возможные комбинации элементов размером = 3, например:

size <- 3

combo_3 <- combn(df$item, size, simplify = F)

Теперь я хочу обобщить эторезультат.

Я хотел бы получить кадр данных, содержащий:

  • Индекс комбинации
  • Элементы в комбинации
  • Суммазначение столбца для этой конкретной комбинации

Вот пример кадра данных для вхождений первой комбинации:

combo_index    item    sum_total
1                 a        8
1                 b        8
1                 c        8
2                 a        7
2                 b        7
2                 d        7
3                 a        11
3                 b        11
3                 e        11 
             ...
             ...
             ...

Ответы [ 3 ]

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

Та же идея, что и у @akrun, но с map_dfr вместо rbindlist и lapply

library(tidyverse)

map_dfr(
  combo_3, 
  ~ data.frame(item = .x, sum_total = sum(df$value[df$item %in% .x])),
  .id = 'combo_index')

#     combo_index item sum_total
# 1             1    a         8
# 2             1    b         8
# 3             1    c         8
# 4             2    a         7
# 5             2    b         7
# 6             2    d         7
# 7             3    a        11
# 8             3    b        11
# 9             3    e        11
# 10            4    a        13
# ...
0 голосов
/ 26 сентября 2018

С помощью data.table (плюс косвенно reshape2) вы можете «растопить» комбинацию и присоединиться:

library(data.table)
setDT(df)

res = df[melt(combn(item, 3, simplify=FALSE)), on=.(item = value)]
res[, sum_total := sum(value), by=L1][]

     item value L1 sum_total
  1:    a     1  1         8
  2:    b     4  1         8
  3:    c     3  1         8
  4:    a     1  2         7
  5:    b     4  2         7
 ---                        
101:    f     8 34        21
102:    g    11 34        21
103:    e     6 35        25
104:    f     8 35        25
105:    g    11 35        25

melt назначает имя L1 по умолчанию, но это может быть установлено на другоезначение с setnames.

Этот способ хранения данных с повторяющимися значениями в sum_total не является "аккуратным";и было бы более целесообразно использовать две таблицы (одну, индексированную с помощью L1 / комбинированный индекс, с общим итогом, а другую, индексированную с помощью L1 + item).См. аккуратный справочник , если интересно.

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

Этого можно достичь с помощью циклического перебора list, получения соответствующего «значения» на основе сопоставления с «item» из «df», создания элементов data.frame и rbind list

library(data.table)
rbindlist(lapply(combo_3, function(x) data.frame(item = x, 
  sum_total = sum(setNames(df$value, df$item)[x])) ), 
            idcol = 'combo_index')
#     combo_index item sum_total
#  1:           1    a         8
#  2:           1    b         8
#  3:           1    c         8
#  4:           2    a         7
#  5:           2    b         7
# ---                           
#101:          34    f        21
#102:          34    g        21
#103:          35    e        25
#104:          35    f        25
#105:          35    g        25

Или лучше было бы stack list с двумя столбцами data.frame, left_join с исходным набором данных, сгруппированных по 'ind', получить sum из'значение'

library(tidyverse)
setNames(combo_3, seq_along(combo_3)) %>% 
    stack %>%
    left_join(df, by = c("values" = "item")) %>%
    group_by(ind) %>%
    mutate(value = sum(value)) %>%
    ungroup %>%
    select(combo_index = ind, item = values, sum_total = value)
# A tibble: 105 x 3
#   combo_index item  sum_total
#   <fct>       <chr>     <int>
# 1 1           a             8
# 2 1           b             8
# 3 1           c             8
# 4 2           a             7
# 5 2           b             7
# 6 2           d             7
# 7 3           a            11
# 8 3           b            11
# 9 3           e            11
#10 4           a            13
# ... with 95 more rows
...