Как сложить несколько столбцов, используя Tidyverse

У меня есть такой фрейм данных в широком формате

setseed(1)
df = data.frame(item=letters[1:6], field1a=sample(6,6),field1b=sample(60,6),
                field1c=sample(200,6),field2a=sample(6,6),field2b=sample(60,6),
                field2c=sample(200,6))

что было бы лучшим способом сложить все столбцы вместе и все б вместе и все с вместе, как это

items fielda fieldb fieldc
    a     2      52    121
    a     1      44     57

2 ответа

Решение

Если мы используем tidyverse, затем gather в "длинный" формат, сделайте некоторые перестановки с именем столбца и spread

library(tidyverse)
out <- df %>% 
         gather(key, val, -item) %>%
         mutate(key1 = gsub("\\d+", "", key), 
                key2 = gsub("\\D+", "", key)) %>% 
         select(-key) %>%
         spread(key1, val) %>%
         select(-key2)
head(out, 2)
#   item fielda fieldb fieldc
#1    a      2     57    138
#2    a      3     17     97

Или похожий вариант melt/dcast от data.table, где мы melt в "длинный" формат, подстрока "переменная", а затем dcast в "широкий" формат

library(data.table)
dcast(melt(setDT(df),  id.var = "item")[, variable := sub("\\d+", "", variable)
      ], item  + rowid(variable) ~ variable, value.var = 'value')[
        , variable := NULL][]
#     item fielda fieldb fieldc
# 1:    a      2     57    138
# 2:    a      3     17     97
# 3:    b      6     39     77
# 4:    b      4     23    120
# 5:    c      3     37    153
# 6:    c      5      1     98
# 7:    d      4      4     99
# 8:    d      1     22     37
# 9:    e      1     12    141
#10:    e      2     49    163
#11:    f      5     10    194
#12:    f      6     19    131

ПРИМЕЧАНИЕ: должно также работать, когда длины не сбалансированы для каждого случая

данные

set.seed(1)
df = data.frame(item = letters[1:6], 
                field1a=sample(6,6),
                field1b=sample(60,6),
                field1c=sample(200,6),
                field2a=sample(6,6),
                field2b=sample(60,6),
                field2c=sample(200,6))

Используя базу R:

cbind(item=df$item,unstack(transform(stack(df,-1),ind=sub("\\d+","",ind))))
      item fielda fieldb fieldc
1        a      2     57    138
2        b      6     39     77
3        c      3     37    153
4        d      4      4     99
5        e      1     12    141
6        f      5     10    194
7        a      3     17     97
8        b      4     23    120
9        c      5      1     98
10       d      1     22     37
11       e      2     49    163
12       f      6     19    131

Или вы можете использовать reshape функция в базе R:

reshape(df,varying = split(names(df)[-1],rep(1:3,2)),idvar = "item",direction = "long")
    item time field1a field1b field1c
a.1    a    1       2      57     138
b.1    b    1       6      39      77
c.1    c    1       3      37     153
d.1    d    1       4       4      99
e.1    e    1       1      12     141
f.1    f    1       5      10     194
a.2    a    2       3      17      97
b.2    b    2       4      23     120
c.2    c    2       5       1      98
d.2    d    2       1      22      37
e.2    e    2       2      49     163
f.2    f    2       6      19     131

Вы можете также решить разделить имя информационного кадра самостоятельно, а затем отформатировать его:

names(df)=sub("(\\d)(.)","\\2.\\1",names(df))
reshape(df,varying= -1,idvar = "item",direction = "long")
Другие вопросы по тегам