61

I have a dataframe, df, with a a number of columns of data already. I have a vector, namevector, full of strings. I need empty columns added to df with the names of the columns from namevector.

I am trying to add columns with this for loop, iterating over each string in namevector.

for (i in length(namevector)) {
  df[, i] <- NA
}

but am left with this error:

Error in [<-.data.frame(*tmp*, , i, value = NA) : new columns would leave holes after existing columns

Alternatively, I have thought of creating an empty dataframe with the correct names, then cbind-ing the two dataframes together but am not sure how to go about coding this.

How would I go about resolving this?

UseR10085
  • 7,120
  • 3
  • 24
  • 54
user2631296
  • 863
  • 2
  • 8
  • 16

6 Answers6

85

The problem with your code is in the line:

for(i in length(namevector))

You need to ask yourself: what is length(namevector)? It's one number. So essentially you're saying:

for(i in 11)
df[,i] <- NA

Or more simply:

df[,11] <- NA

That's why you're getting an error. What you want is:

for(i in namevector)
    df[,i] <- NA

Or more simply:

df[,namevector] <- NA
Señor O
  • 17,049
  • 2
  • 45
  • 47
  • 9
    Please consider moving `df[,namevector] <- NA` to the top of your answer, since that is the general solution – stevec Feb 12 '21 at 00:13
31
set.seed(1)
example <- data.frame(col1 = rnorm(10, 0, 1), col2 = rnorm(10, 2, 3))
namevector <- c("col3", "col4")
example[ , namevector] <- NA

example
#          col1       col2 col3 col4
# 1  -0.6264538  6.5353435   NA   NA
# 2   0.1836433  3.1695297   NA   NA
# 3  -0.8356286  0.1362783   NA   NA
# 4   1.5952808 -4.6440997   NA   NA
# 5   0.3295078  5.3747928   NA   NA
# 6  -0.8204684  1.8651992   NA   NA
# 7   0.4874291  1.9514292   NA   NA
# 8   0.7383247  4.8315086   NA   NA
# 9   0.5757814  4.4636636   NA   NA
# 10 -0.3053884  3.7817040   NA   NA
dayne
  • 7,504
  • 6
  • 38
  • 56
16

The below works for me

dataframe[,"newName"] <- NA

Make sure to add "" for new name string.

David Arenburg
  • 91,361
  • 17
  • 137
  • 196
Shubham
  • 434
  • 6
  • 12
  • The OP has requested to *Add empty columns to a dataframe with specified names **from a vector***. So, he wants to add *many* columns. Your answer does only add *one* column and the name is *not* taken from the variable `namevector` as requested. Therefore, please review your post or consider to delete it. Thank you. – Uwe Oct 09 '18 at 05:35
  • you can always run a loop for list of columns – Shubham Jan 28 '19 at 23:38
  • Right but then your answer is identical to the [accepted answer](https://stackoverflow.com/a/18215216/3817004) which suggests `for(i in namevector) df[,i] <- NA` – Uwe Jan 28 '19 at 23:43
4

I prefer the base R solution, but here is a tidyverse solution. Below uses mutate, but the syntax is the same if you were to use tibble::add_column:

library(dplyr)

new_columns <- c("A", "B", "C")

iris %>% 
  mutate(!!!setNames(rep(NA, length(new_columns)), new_columns))

The splice operator uses the name-value pair from setNames to create the columns.

If you had name-value pairs in a list already then you can simply do:

new_columns <- list(A = NA, B = 1, C = "c")

iris %>% 
  mutate(!!!new_columns)

If the length of each list element is 1 then its value is recycled. Otherwise, it needs to have the same length as the data frame (e.g. list(A = 1:150).

LMc
  • 12,577
  • 3
  • 31
  • 43
0

A different way to add empty columns to a dataframe.

df <- data.frame(name0 = c(1,2,3))
namevector <- c("name1", "name2", "name3")

sapply(namevector, function(x){df[x] <<- numeric()})
  • The for loop is eliminated with the <<- operator.
  • In many of these examples, the type associated with the new empty column will be a logical; however, by specifying numeric() the type will be numeric. Other types, like double() or character(), could be specified.
Agriculturist
  • 521
  • 9
  • 20
-2

Maybe

df <- do.call("cbind", list(df, rep(list(NA),length(namevector))))
colnames(df)[-1*(1:(ncol(df) - length(namevector)))] <- namevector
James Pringle
  • 1,079
  • 6
  • 15