Appending list to data frame in R

Nicole Goebel picture Nicole Goebel · Oct 5, 2012 · Viewed 17.2k times · Source

I have created an empty data frame in R with two columns:

d<-data.frame(id=c(), numobs=c())

I would like to append this data frame (in a loop) with a list, d1 that has output:

[1] 1  100

I tried using rbind:

d<-rbind(d, d2)

and merge:

d<-merge(d, d2)

And I even tried just making a list of lists and then converting it to a data frame, and then giving that data frame names:

d<-rbind(dlist1, dlist2)
dframe<-data.frame(d)
names(dframe)<-c("id","numobs")

But none of these seem to meet the standards of a routine checker (this is for a class), which gives the error:

Error: all(names(cc) %in% c("id", "nobs")) is not TRUE

Even though it works fine in my workspace.

This is frustrating since the error does not reveal where the error is occurring.

Can anyone help me to either merge 2 data frames or append a data frame with a list?

Answer

acylam picture acylam · Sep 5, 2017

I think you are confusing the purpose of rbind and merge. rbind appends data.frames or named lists, or both vertically. While merge combines data.frames horizontally.

You seem to be also confused by vector's and list's. In R, list can take different datatypes for each element, while vector has to have all elements the same type. Both list and vector are one-dimensional. When you use rbind you want to append a named list, not a named/unnamed vector.

Unnamed Vectors and Lists

The way you define a vector is with the c() function. The way you define an unnamed list is with the list() function, like so:

vec1 = c(1, 10)
# > vec1
# [1]  1 10

list1 = list(1, 10)
# > list1
# [[1]]
# [1] 1
# 
# [[2]]
# [1] 10

Notice that both vec1 and list1 have two elements, but list1 is storing the two numbers as two separate vectors (element [[1]] the vector c(1) and [[2]] the vector c(10))

Named Vectors and Lists

You can also create named vectors and lists. You do this by:

vec2 = c(id = 1, numobs = 10)
# > vec2
# id numobs 
# 1     10

list2 = list(id = 1, numobs = 10)
# > list2
# $id
# [1] 1
# 
# $numobs
# [1] 10

Same data structure for both, but the elements are named.

Dataframes as Lists

Notice that list2 has a $ in front of each element name. This might give you some clue that data.frame's are actually list's with each column an element of the list, since df$column is often used to extract a column from a dataframe. This makes sense since both list's and data.frame's can take different datatypes, unlike vectors's.

The rbind function

When your first element is a dataframe, rbind requires that what you are appending has the same names as the columns of the dataframe. Now, a named vector would not work, because the elements of a vector are not treated as columns of a dataframe, whereas a named list matches elements with columns if the names are the same:

To demonstrate:

d<-data.frame(id=c(), numobs=c())

rbind(d, c(1, 10))
#   X1 X10
# 1  1  10

rbind(d, c(id = 1, numobs = 10))
#   X1 X10
# 1  1  10

rbind(d, list(1, 10))
#   X1 X10
# 1  1  10

rbind(d, list(id = 1, numobs = 10))
#   id numobs
# 1  1     10

Knowing the above, it is obvious that you can most certainly also rbind two dataframes with column names that match:

df2 = data.frame(id = 1, numobs = 10)

rbind(d, df2)
#   id numobs
# 1  1     10