10

I have used lapply to apply a function to a number of data frames:

data.cleaned <- lapply(data.list, shooter_cleaning)

And then labeled each of the resulting data frames in the list according to their subject number (e.g., 100):

names(data.cleaned) <- subject.names

What I want to do is to save each new data frame as an individual .csv file based on its subject number. For example, for subject 100 I'd like the .csv file to be labeled as "100.csv" Normally to do this (for a single data frame) I would just write (where x is the data frame):

write.csv(x, "100.csv", row.names = F)

But, obviously using lapply to do this for my list of data frames will just produce many copies of "100.csv" when instead I would like the files to be unique, based on their subject number. How can I (use apply to?) save each of these data frames to their own unique .csv file?

3
  • Maybe something like lapply(seq_along(list), function(i) { write.csv(list[[i]], sprintf("%d.csv", i), row.names = FALSE) }) And if you want the file names to all be the same uniform character length you can use sprintf("%03d.csv", i) Commented Nov 3, 2014 at 4:24
  • This works! However, the exported files are simply named numerically (e.g., 1 - 100). Is there a way to preserve the original subject numbers in the exported file name? Commented Nov 3, 2014 at 4:47
  • Yes, use names() instead of seq_along(). Commented Dec 28, 2017 at 16:47

4 Answers 4

20

Here's a self-contained example along the lines of Richard's comment, but uses the names of the dataframes in the list as filenames for the CSV files:

# Create a list of n data frames

n <- 10

my_list <- lapply(1:n, function(i)  data.frame(x = rnorm(10), y = rnorm(10)) )

# name the data frames

names(my_list) <- letters[1:n]

# save each new data frame as an individual .csv file based on its name

lapply(1:length(my_list), function(i) write.csv(my_list[[i]], 
                                      file = paste0(names(my_list[i]), ".csv"),
                                      row.names = FALSE))
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! This individually exports the data frames like Richard's code above and also preserves the subject number associated with each data frame.
How can I type the whole save path in paste0?
Can you do paste0("/path", names(my_list[i]), ".csv")?
6

This is a common operation. You need to split the dataframe into a list of dataframes then write them to many separate csvs. I will demonstrate 2 approaches with base R, and 2 approaches with tidyverse.

base R

A for loop makes the iteration very explicit.

# example data.frame
df  <- data.frame(x = 1:4, y = c("a", "a", "b", "b"))

# split the dataframe into a list by the y column
l  <- split(df, df$y)

# make filepaths from list names, which are unique values of the y column
file_out <- paste0(names(l), ".csv")

# iterate over the list and the vector of list names to write csvs
for(i in 1:length(l)) {
  write_csv(l[[i]], file_out[i])
}

Or using mapply():

mapply(
  function(x, y) write_csv(x, y), 
  l, 
  file_out
)

tidyverse approach

library(tidyverse)

# we pass walk2 two inputs: a list of dataframes (.x) and filepaths (.y)
# `walk` is a silent `map` that doesn't print output to the console
walk2(l, file_out, ~write_csv(.x, .y))

Or, avoiding intermediate variables:

df %>% 
  group_split(y) %>% 
  walk(~write_csv(.x, paste0(.x$y[1], ".csv")))

Comments

2

In case this helps: I had an environment with multiple data frames, and only those data frames, and I wanted to output each data frame as a separate CSV file. With the help of Ben's answer, and discovering mget, I was able to do that with the following code:

for(i in 1:length(ls())) {
  write.table(
  mget(ls()[[i]]),
  file = paste0(ls()[[i]], ".csv"),
  sep = ";",
  qmethod = "double",
  row.names = FALSE)
}

Comments

1

Here is a reprex to write multiple data frames inside a tibble using purrr:

# use functions from the 
# tidyr, stringr and purrr packages
library(tidyverse)
# create fake dataset
expand_grid(cat = c("a","b"),
            lev = "c",
            num = 1:2) %>% 
  # group and nest by `cat`
  group_by(cat) %>% 
  nest() %>% 
  ungroup() %>% 
  # create different file names with
  # the `cat` variable as reference
  # (you can also specify folder paths)
  mutate(file = map_chr(.x = cat,
                        .f = str_replace, 
                        "(.+)","\\1.csv")) %>% 
  # write each nested dataset 
  # in a separate file
  mutate(write = pmap(.l = select(.,x = data, file),
                      .f = write_csv))
#> # A tibble: 2 x 4
#>   cat   data             file  write           
#>   <chr> <list>           <chr> <list>          
#> 1 a     <tibble [2 x 2]> a.csv <tibble [2 x 2]>
#> 2 b     <tibble [2 x 2]> b.csv <tibble [2 x 2]>

Created on 2022-02-02 by the reprex package (v2.0.1)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.