简体   繁体   中英

r extend data.table columns by filling row values

I have a data.table:

library(data.table)
p1 = data.table(a = c(10.34,25.87,53.2), b=c(15.3,183.2,34.8))
print(p1)

       a     b
1: 10.34  15.3
2: 25.87 183.2
3: 53.20  34.8

What I would like to get is a new data.table with the following structure:

       a     b     a1    b1     a2    b2     a3    b3     
1: 10.34  15.3  10.34  15.3  25.87 183.2   53.2  34.8
2: 25.87 183.2  10.34  15.3  25.87 183.2   53.2  34.8
3: 53.20  34.8  10.34  15.3  25.87 183.2   53.2  34.8

My current solution is:

p2 = cbind(p,p[1,],p[2,],p[3,])

How do I create a similar (other than using for loops) data.table p2 with 10001 columns when I have input data.table p with 10000 rows?

Any help is appreciated.

Here is another option using rbindlist and cbind on rep for transposed data frame.

library(data.table)

cbind(p1, rbindlist(rep(list(data.table(t(unlist(p1)))), times = nrow(p1))))
#        a     b    a1    a2   a3   b1    b2   b3
# 1: 10.34  15.3 10.34 25.87 53.2 15.3 183.2 34.8
# 2: 25.87 183.2 10.34 25.87 53.2 15.3 183.2 34.8
# 3: 53.20  34.8 10.34 25.87 53.2 15.3 183.2 34.8

Update

@Frank pointed out in the comments that cbind can take unequal row numbers of two data frames. In this case, the data frame with less row numbers would be "recycled". So we don't need rep or rbindlist and below is the updated code.

cbind(p1, data.table(t(unlist(p1))))
#        a     b    a1    a2   a3   b1    b2   b3
# 1: 10.34  15.3 10.34 25.87 53.2 15.3 183.2 34.8
# 2: 25.87 183.2 10.34 25.87 53.2 15.3 183.2 34.8
# 3: 53.20  34.8 10.34 25.87 53.2 15.3 183.2 34.8

To get the col order as desired by OP, one option is setcolorder :

cbind(p1, setcolorder(data.table(t(unlist(p1))), order(row(p1))) )    
#        a     b    a1   b1    a2    b2   a3   b3
# 1: 10.34  15.3 10.34 15.3 25.87 183.2 53.2 34.8
# 2: 25.87 183.2 10.34 15.3 25.87 183.2 53.2 34.8
# 3: 53.20  34.8 10.34 15.3 25.87 183.2 53.2 34.8

We can use shift

out <- cbind(p1, p1[, shift(.SD, type = 'lead',
             n = c(0, seq_len(.N-1)))][rep(1, nrow(p1))])
setnames(out, make.unique(c(names(p1), rep(names(p1), each = nrow(p1)))))

or with tidyverse

library(tidyverse)
pmap_dfc(p1, list) %>% 
             uncount(nrow(p1))

If we need the original data as well

pmap_dfc(p1, list) %>%
   rowr::cbind.fill(p1, .)
#     a     b     a    b    a1    b1   a2   b2
#1 10.34  15.3 10.34 15.3 25.87 183.2 53.2 34.8
#2 25.87 183.2 10.34 15.3 25.87 183.2 53.2 34.8
#3 53.20  34.8 10.34 15.3 25.87 183.2 53.2 34.8

Or with transpose and bind_cols

purrr::transpose(p1) %>% 
    bind_cols %>% 
    rowr::cbind.fill(p1, .)

Here's another option, similar to www 's:

> cbind(p1, matrix(rep(unlist(p1), nrow(p1)), nrow = nrow(p1), byrow=T))
       a     b    V1    V2   V3   V4    V5   V6
1: 10.34  15.3 10.34 25.87 53.2 15.3 183.2 34.8
2: 25.87 183.2 10.34 25.87 53.2 15.3 183.2 34.8
3: 53.20  34.8 10.34 25.87 53.2 15.3 183.2 34.8
cbind(p1, do.call(cbind, split(p1, 1:nrow(p1))))

#        a     b   1.a  1.b   2.a   2.b  3.a  3.b
# 1: 10.34  15.3 10.34 15.3 25.87 183.2 53.2 34.8
# 2: 25.87 183.2 10.34 15.3 25.87 183.2 53.2 34.8
# 3: 53.20  34.8 10.34 15.3 25.87 183.2 53.2 34.8

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