0

I have a vector like this:

dput(xv)
c("Users", "Transactions", "Workload")

I need to be able to create an empty data frame based on entries in vector xv using a function.

For example, it should be like this:

new_df <- data.frame(
    Users = character(), 
    Transactions = character(), 
    Workload = character()
)

since the values in xv could change and number of entries in xv could also change, I need to be able to do this using a function?

Any ideas how I could do this?

nrussell
  • 18,382
  • 4
  • 47
  • 60
user1471980
  • 10,127
  • 48
  • 136
  • 235
  • 1
    If the column types vary and the number of columns vary, why do you need a function. You can use `setNames(data.frame(....), xv)` – akrun Jun 23 '16 at 13:38

3 Answers3

4

I think this does what you want:

do.call(data.frame,setNames(lapply(xv,function(e) vector(typeof(e))),xv));
## [1] Users        Transactions Workload
## <0 rows> (or 0-length row.names)

Edit: Thanks to @Zheyuan for making me think a little more about my solution. Since the input (as specified by the OP) is an atomic vector, it cannot contain heterogeneous data types, so my lapply() call that generates a separate zero-length vector according to each input element's type offers no benefit. It would offer a benefit if xv was a list, which can contain heterogeneous data types, but since xv is also being used to set the names of the resulting data.frame, it would be very questionable if it contained non-character elements. So my solution is actually not as sensible as I thought it was.

Here's a more sensible solution using the do.call(data.frame,...) pattern, which replaces the lapply() call with rep():

do.call(data.frame,setNames(rep(list(character()),length(xv)),xv));
## [1] Users        Transactions Workload
## <0 rows> (or 0-length row.names)
bgoldst
  • 34,190
  • 6
  • 38
  • 64
3

As the OP wanted a function and because I commented setNames first

f1 <- function(nm1){
       len <- length(nm1)
       setNames(as.data.frame(matrix(typeof(nm1), 0, len), 
                      stringsAsFactors=FALSE), nm1) 
     }

f1(xv)
#[1] Users        Transactions Workload    
#<0 rows> (or 0-length row.names)

str(f1(xv))
#'data.frame':   0 obs. of  3 variables:
#$ Users       : chr 
#$ Transactions: chr 
#$ Workload    : chr 

The matrix(.. part is stolen from @ZheyuanLi's comment.

akrun
  • 874,273
  • 37
  • 540
  • 662
2

I would do something like this:

MakeDF.R <- function(CustomVector){
  NewDF <- data.frame(matrix(nrow=0,ncol=length(CustomVector)))
  #Matrixes can be easier to make, and wrapping in data.frame() quickly converts them
  colnames(NewDF) <- CustomVector
  #give the New dataframe columns names based on the vector you fed in
  return(NewDF)
}

So calling the function like below

CusVec<-c('a','b','c')
CustomDF <- MakeDF.R(CusVec)

Returns

> CustomDF
[1] a b c
<0 rows> (or 0-length row.names)

Or to get a data frame with a set number of rows (more efficient to slot data in, than to create a new row every time, if you know how many rows you want, before hand)

CusVec<-c('a','b','c')

MakeDF.R <- function(CustomVector,n){
  NewDF <- data.frame(matrix(nrow=n,ncol=length(CusVec)))
  colnames(NewDF) <- CustomVector
  return(NewDF)
}

CustomDF <- MakeDF.R(CusVec,3)
ChristyCasey
  • 426
  • 5
  • 9