2

I am trying to split column name strings into separate columns but the issue I am facing is that the rows have logical values. There are a few posts that split columns with strings in the rows but I could not find any posts with logical values.

My data.frame looks something like this:

mydf <- data.frame (author = c("N1", "N2", "N3"),
Aa..Ab = c(T, T, F),
BB = c(T, F, T),
Ca...Cb = c(F, F, T))

The result should look something like this

mydfnew <- data.frame (author = c("N1", "N2", "N3"),
 Aa = c(T, T, F),
 Ab = c(T, T, F),
 BB = c(T, F, T),
 Ca = c(F, F, T),
 Cb = c(F, F, T))

I have tried to adjust code that splits columns and names (Split character in column and name) as follows:

splitCol <- function(dataframe, splitVars=names(dataframe)){
  split.DF <- dataframe[,splitVars]
  keep.DF <- dataframe[, !names(dataframe) %in% c(splitVars)]

  X <- function(x)matrix(unlist(rep(x)), byrow=TRUE)

  newdf <- as.data.frame(do.call(cbind, suppressWarnings(lapply(split.DF, X))) )
  names(newdf) <- paste(rep(names(split.DF), each=2), c(".a", ".b"), sep="") 
  data.frame(keep.DF,newdf)
}

When calling

splitCol(mydf) 

I get the error:

Error in names(newdf) <- paste(rep(names(split.DF), each = 2), c(".a", : 'names' attribute [8] must be the same length as the vector [4]

aynber
  • 22,380
  • 8
  • 50
  • 63
Rkook
  • 63
  • 1
  • 11

3 Answers3

2

Here is an approach using replicate and Map

as.data.frame(Map(x = strsplit(names(mydf), '[.]+'), 
                  DATA = mydf, 
                  f = function(x,DATA){
                    setNames(replicate(length(x), DATA, simplify = FALSE),x  )}
             ))
##    author    Aa    Ab    BB    Ca    Cb
##  1     N1  TRUE  TRUE  TRUE FALSE FALSE
##  2     N2  TRUE  TRUE FALSE FALSE FALSE
##  3     N3 FALSE FALSE  TRUE  TRUE  TRUE
mnel
  • 113,303
  • 27
  • 265
  • 254
  • Wow that was very quick! Thanks a lot. Tested it on my larger dataset and seems to work just as intended. I was not aware of and how to use it. Thanks for this learning opportunity. – Rkook Jun 12 '13 at 03:41
0

An answer which is essentially a two step variation on @mnel's version:

splnames <- strsplit(names(mydf),"\\.+")
setNames(data.frame(rep(mydf,sapply(splnames,length))),unlist(splnames))

Result:

  author    Aa    Ab    BB    Ca    Cb
1     N1  TRUE  TRUE  TRUE FALSE FALSE
2     N2  TRUE  TRUE FALSE FALSE FALSE
3     N3 FALSE FALSE  TRUE  TRUE  TRUE
thelatemail
  • 91,185
  • 12
  • 128
  • 188
0

Here is an alternative using the "reshape2" package and my "splitstackshape" package. The basic idea is to get a "long" dataset that is much easier to manipulate than a wide one--even if the end goal is to create a wide dataset :)

## Load required packages
library(reshape2)
library(splitstackshape)

## Create a "long" version of your dataset
A <- melt(mydf, id.vars="author")
B <- concat.split.multiple(A, "variable", ".", "long")

## Use `dcast` to get the desired wide form
## Use `na.omit(B)` to get rid of the rows that have 
##   NA before doing the transformation
dcast(na.omit(B), author ~ variable, value.var="value")
#   author    Aa    BB    Ca    Ab    Cb
# 1     N1  TRUE  TRUE FALSE  TRUE FALSE
# 2     N2  TRUE FALSE FALSE  TRUE FALSE
# 3     N3 FALSE  TRUE  TRUE FALSE  TRUE
A5C1D2H2I1M1N2O1R2T1
  • 190,393
  • 28
  • 405
  • 485