M1996rg
M1996rg

Reputation: 65

Special reshape in R

Consider a 3x3 char dataframe:

example <- data.frame(one = c("a","b","c"),
             two = c("a","b","b"),
             three = c ("c","a","b"))

I want to resize these data to 6x2 and add the following content:

desired <- data.frame(one = c("a","a","b","b",
                              "c","b"),
                      two = c("a","c","b","a","b","b"))

For the original example dataframe, I want to rbind() the contents of example[,2:3] beneath each row index.

This can be achieved by:

ex <- as.matrix(example)

des <- as.data.frame(rbind(ex[,1:2], ex[,2:3]))

Maybe using library(tidyverse) for an arbitrary number of columns would be nicer?

Upvotes: 3

Views: 92

Answers (3)

Rui Barradas
Rui Barradas

Reputation: 76565

For each pair of columns, transpose the sub-data.frame defined by them and coerce to vector. Then coerce to data.frame and set the result's names.
The code that follows should be scalable, it does not hard code the number of columns.

desired2 <- as.data.frame(
  lapply(seq(names(example))[-1], \(k) c(t(example[(k-1):k])))
)
names(desired2) <- names(example)[-ncol(example)]

identical(desired, desired2)
#[1] TRUE

The code above rewritten as a function.

reformat <- function(x){
  y <- as.data.frame(
    lapply(seq(names(x))[-1], \(k) c(t(x[(k-1):k])))
  )
  names(y) <- names(x)[-ncol(x)]
  y
}

reformat(example)
example %>% reformat()

Another example, with 6 columns input.

ex1 <- example
ex2 <- example
names(ex2) <- c("fourth", "fifth", "sixth")
ex <- cbind(ex1, ex2)

reformat(ex)
ex %>% reformat()

Upvotes: 3

LyzandeR
LyzandeR

Reputation: 37879

A base-R solution with Map:

#iterate over example$one, example$two, and example$three at the same
#time, creating the output you need.
mylist <- Map(function(x ,y ,z ) {
 data.frame(one = c(x, y), two = c(y, z))
},
example$one #x,
example$two #y,
example$three #z)


do.call(rbind, mylist)
    one two
a.1   a   a
a.2   a   c
b.1   b   b
b.2   b   a
c.1   c   b
c.2   b   b

Upvotes: 1

stefan
stefan

Reputation: 125038

A tidyverse approach using tidyr::pivot_longer may look like so:

library(dplyr)
library(tidyr)

pivot_longer(example, -one, values_to = "two") %>% 
  select(-name)
#> # A tibble: 6 × 2
#>   one   two  
#>   <chr> <chr>
#> 1 a     a    
#> 2 a     c    
#> 3 b     b    
#> 4 b     a    
#> 5 c     b    
#> 6 c     b

Upvotes: 2

Related Questions