简体   繁体   中英

How to stack multiple columns using tidyverse

I have a data frame like this in wide format

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))

what would be the best way to stack all a columns together and all b together and all c together like this

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

using base 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

Or you can use the reshape function in Base 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

You can also decide to separate the name of the dataframe by yourself then format it:

names(df)=sub("(\\d)(.)","\\2.\\1",names(df))
reshape(df,varying= -1,idvar = "item",direction = "long")

If we are using tidyverse , then gather into 'long' format, do some rearrangements with the column name and 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

Or a similar option is melt/dcast from data.table , where we melt into 'long' format, substring the 'variable' and then dcast to 'wide' format

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

NOTE: Should also work when the lengths are not balanced for each cases

data

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))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM