How do I make a list of data frames and how do I access each of those data frames from the list?
For example, how can I put these data frames in a list ?
d1 <- data.frame(y1 = c(1, 2, 3),
y2 = c(4, 5, 6))
d2 <- data.frame(y1 = c(3, 2, 1),
y2 = c(6, 5, 4))
Very simple ! Here is my suggestion :
If you want to select dataframes in your workspace, try this :
or
all these will give the same result.
You can change
is.data.frame
to check other types of variables likeis.function
You can also access specific columns and values in each list element with
[
and[[
. Here are a couple of examples. First, we can access only the first column of each data frame in the list withlapply(ldf, "[", 1)
, where1
signifies the column number.Similarly, we can access the first value in the second column with
Then we can also access the column values directly, as a vector, with
[[
Taking as a given you have a "large" number of data.frames with similar names (here d# where # is some positive integer), the following is a slight improvement of @mark-miller's method. It is more terse and returns a named list of data.frames, where each name in the list is the name of the corresponding original data.frame.
The key is using
mget
together withls
. If the data frames d1 and d2 provided in the question were the only objects with names d# in the environment, thenwhich would return
This method takes advantage of the pattern argument in
ls
, which allows us to use regular expressions to do a finer parsing of the names of objects in the environment. An alternative to the regex"^d[0-9]+$"
is"^d\\d+$"
.As @gregor points out, it is a better overall to set up your data construction process so that the data.frames are put into named lists at the start.
data
This isn't related to your question, but you want to use
=
and not<-
within the function call. If you use<-
, you'll end up creating variablesy1
andy2
in whatever environment you're working in:This won't have the seemingly desired effect of creating column names in the data frame:
The
=
operator, on the other hand, will associate your vectors with arguments todata.frame
.As for your question, making a list of data frames is easy:
You access the data frames just like you would access any other list element:
The other answers show you how to make a list of data.frames when you already have a bunch of data.frames, e.g.,
d1
,d2
, .... Having sequentially named data frames is a problem, and putting them in a list is a good fix, but best practice is to avoid having a bunch of data.frames not in a list in the first place.The other answers give plenty of detail of how to assign data frames to list elements, access them, etc. We'll cover that a little here too, but the Main Point is to say don't wait until you have a bunch of a
data.frames
to add them to a list. Start with the list.The rest of the this answer will cover some common cases where you might be tempted to create sequential variables, and show you how to go straight to lists. If you're new to lists in R, you might want to also read What's the difference between
[[
and[
in accessing elements of a list?.Lists from the start
Don't ever create
d1
d2
d3
, ..., in the first place. Create a listd
with 3 elements.Reading multiple files into a list of data frames
This is done pretty easily when reading in files. Maybe you've got files
data1.csv, data2.csv, ...
in a directory. Your goal is a list of data.frames calledmydata
. The first thing you need is a vector with all the file names. You can construct this with paste (e.g.,my_files = paste0("data", 1:5, ".csv")
), but it's probably easier to uselist.files
to grab all the appropriate files:my_files <- list.files(pattern = "\\.csv$")
. You can use regular expressions to match the files, read more about regular expressions in other questions if you need help there.At this point, most R beginners will use a
for
loop, and there's nothing wrong with that, it works just fine.A more R-like way to do it is with
lapply
, which is a shortcut for the aboveEither way, it's handy to name the list elements to match the files
Splitting a data frame into a list of data frames
This is super-easy, the base function
split()
does it for you. You can split by a column (or columns) of the data, or by anything else you wantThis is also a nice way to break a data frame into pieces for cross-validation. Maybe you want to split
mtcars
into training, test, and validation pieces.Simulating a list of data frames
Maybe you're simulating data, something like this:
But who does only one simulation? You want to do this 100 times, 1000 times, more! But you don't want 10,000 data frames in your workspace. Use
replicate
and put them in a list:In this case especially, you should also consider whether you really need separate data frames, or would a single data frame with a "group" column work just as well? Using
data.table
ordplyr
it's quite easy to do things "by group" to a data frame.I didn't put my data in a list :( I will next time, but what can I do now?
If they're an odd assortment (which is unusual), you can simply assign them:
If you have data frames named in a pattern, e.g.,
df1
,df2
,df3
, and you want them in a list, you canget
them if you can write a regular expression to match the names. Something likeGenerally,
mget
is used to get multiple objects and return them in a named list. Its counterpartget
is used to get a single object and return it (not in a list).Combining a list of data frames into a single data frame
A common task is combining a list of data frames into one big data frame. If you want to stack them on top of each other, you would use
rbind
for a pair of them, but for a list of data frames here are three good choices:(Similarly using
cbind
ordplyr::bind_cols
for columns.)To merge (join) a list of data frames, you can see these answers. Often, the idea is to use
Reduce
withmerge
(or some other joining function) to get them together.Why put the data in a list?
Put similar data in lists because you want to do similar things to each data frame, and functions like
lapply
,sapply
do.call
, thepurrr
package, and the oldplyr
l*ply
functions make it easy to do that. Examples of people easily doing things with lists are all over SO.Even if you use a lowly for loop, it's much easier to loop over the elements of a list than it is to construct variable names with
paste
and access the objects withget
. Easier to debug, too.Think of scalability. If you really only need three variables, it's fine to use
d1
,d2
,d3
. But then if it turns out you really need 6, that's a lot more typing. And next time, when you need 10 or 20, you find yourself copying and pasting lines of code, maybe using find/replace to changed14
tod15
, and you're thinking this isn't how programming should be. If you use a list, the difference between 3 cases, 30 cases, and 300 cases is at most one line of code---no change at all if your number of cases is automatically detected by, e.g., how many.csv
files are in your directory.You can name the elements of a list, in case you want to use something other than numeric indices to access your data frames (and you can use both, this isn't an XOR choice).
Overall, using lists will lead you to write cleaner, easier-to-read code, which will result in fewer bugs and less confusion.
This may be a little late but going back to your example I thought I would extend the answer just a tad.
Then you make your list easily:
Now you have a list but instead of accessing the list the old way such as
you can use this function to obtain & assign the dataframe of your choice.
Now get the one you want.
Hope that extra bit helps.
Cheers!