9

I would like to create an empty data frame where the column names are coming from a character vector.

for example, if this was my vector:

 vec <- letters[1:3]

I would like create an empty data frame like the following:

 df <- tibble('a' = character(), 'b' = character(), 'c' = character())

however, I would like to iterate through the items in the vector to populate the dataframe names and not have to manually specify each one. In reality my vector has 40+ names.

I've tried the following by they don't work:

 df <- tibble(vec[1:3])
 df <- tibble(vec)
 df <- tibble(for (i in 1:3){
   vec[i]
 })

Any help on this would be greatly appreciated!

user438383
  • 5,716
  • 8
  • 28
  • 43
pd441
  • 2,644
  • 9
  • 30
  • 41
  • For a refrence: https://stackoverflow.com/questions/10689055/create-an-empty-data-frame – Marek Jun 21 '22 at 14:37

5 Answers5

4

You can create a named vector, vec, where the first argument sets the type of column you want. The rep("", 3) line says I want three character columns. Then the second argument is the vector of column names.

Use dplyr::bind_rows to convert this into tibble with one row. Then [0, ] selects zero rows, leaving it empty.

With this method, you can control the data type for each column easily.

library(dplyr)

vec <- setNames(rep("", 3), letters[1:3])
bind_rows(vec)[0, ]

# A tibble: 0 x 3
# ... with 3 variables: a <chr>, b <chr>, c <chr>

You can also use as_tibble if you transpose the named vector. I guess I use bind_rows because I usually have dplyr loaded but not tibble.

library(tibble)

vec <- setNames(rep("", 3), letters[1:3])
as_tibble(t(vec))[0, ]

# A tibble: 0 x 3
# ... with 3 variables: a <chr>, b <chr>, c <chr>

If you know all of the columns are of a single type (e.g., character), you can do something like this.

vec <- letters[1:3]
df <- bind_rows(setNames(rep("", length(vec)), vec))[0, ]
3

Another variant of Adam's idea:

as_tibble(sapply(vec, \(x) character()))

# A tibble: 0 x 3
# ... with 3 variables: a <chr>, b <chr>, c <chr>
s_baldur
  • 29,441
  • 4
  • 36
  • 69
2

You can do

library(tibble)

tb <- as_tibble(matrix(nrow = 0, ncol = length(vec), dimnames = list(NULL, vec)))

tb
# A tibble: 0 x 3
# ... with 3 variables: a <lgl>, b <lgl>, c <lgl>

Humpelstielzchen
  • 6,126
  • 3
  • 14
  • 34
  • Provide a first argument to matrix, e.g., `matrix(character(), 0, length(vec), ...)` to create a data.frame (`as.data.frame()`) or tibble with appropriate column type... If the column types really are homogeneous, maybe a matrix is the correct data structure? – Martin Morgan Oct 17 '19 at 12:33
  • I don't know, maybe.. OP asks for a tibble. the default for `matrix` is logical, but column type is adjusted upon assigning anyway. – Humpelstielzchen Oct 17 '19 at 12:40
1

A variant on Adam's solution is to create a named list of appropriate types, e.g.,

n = length(vec)
tmpl = setNames(rep(list(character()), n), head(letters, n))

This reflects the underlying structure of a data.frame or tibble -- a named list of equal-length vectors. Then

as.data.frame(tmpl, stringsAsFactors = FALSE)
tibble::as_tibble(tmpl)
Martin Morgan
  • 45,935
  • 7
  • 84
  • 112
0

You could use read_csv from readr package, which could read from text vector.

First you need to paste your vector and then read it:

readr::read_csv(I(paste(vec, collapse=",")), col_types = "c")

In pipeline:

vec %>%
    paste(collapse = ",") %>% # makes "a,b,c"
    I() %>% # needed for read_ to treat as string not a file
    readr::read_csv(col_types = "c") # columns types as characters
Marek
  • 49,472
  • 15
  • 99
  • 121