Home > database >  Special reshape in R
Special reshape in R

Time:12-06

Consider a 3x3 dataframe of characters:

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

I'm interested in reshaping these data to be 6x2 with the following contents:

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

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

This can be accomplished by the following:

ex <- as.matrix(example)

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

I'm wondering if there's a cleaner way to do this for an arbitrary number of columns, maybe by using library(tidyverse)??

CodePudding user response:

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

CodePudding user response:

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

CodePudding user response:

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
  • Related