write.csv() a list of unequally sized data.frames
That's a warning, not an error. You can't change append=FALSE
with write.csv
. ?write.csv
says:
Attempts to change ‘append’, ‘col.names’, ‘sep’, ‘dec’ or ‘qmethod’
are ignored, with a warning.
Use write.table
with sep=","
instead.
Write different data frame in one .csv file with R
write.csv
just calls write.table
under the hood, with appropriate arguments. So you can achieve what you want with 3 calls to write.table
.
write.table(df1, "filename.csv", col.names=TRUE, sep=",")
write.table(df2, "filename.csv", col.names=FALSE, sep=",", append=TRUE)
write.table(df3, "filename.csv", col.names=FALSE, sep=",", append=TRUE)
Actually, you could avoid the whole issue by combining your data frames into a single df with rbind, then calling write.csv once.
write.csv(rbind(df1, d32, df3), "filename.csv")
Create a Data Frame of Unequal Lengths
Sorry this isn't exactly what you asked, but I think there may be another way to get what you want.
First, if the vectors are different lengths, the data isn't really tabular, is it? How about just save it to different CSV files? You might also try ascii formats that allow storing multiple objects (json, XML).
If you feel the data really is tabular, you could pad on NAs:
> x = 1:5
> y = 1:12
> max.len = max(length(x), length(y))
> x = c(x, rep(NA, max.len - length(x)))
> y = c(y, rep(NA, max.len - length(y)))
> x
[1] 1 2 3 4 5 NA NA NA NA NA NA NA
> y
[1] 1 2 3 4 5 6 7 8 9 10 11 12
If you absolutely must make a data.frame
with unequal columns you could subvert the check, at your own peril:
> x = 1:5
> y = 1:12
> df = list(x=x, y=y)
> attributes(df) = list(names = names(df),
row.names=1:max(length(x), length(y)), class='data.frame')
> df
x y
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 <NA> 6
7 <NA> 7
[ reached getOption("max.print") -- omitted 5 rows ]]
Warning message:
In format.data.frame(x, digits = digits, na.encode = FALSE) :
corrupt data frame: columns will be truncated or padded with NAs
Read CSV of list of dataframes and convert to list of dataframes
The first column issue while writing the dataframe can be avoided by setting row.names = FALSE
in write.table
.
lapply(my.list, function(x)
write.table(x,'mylist.csv',append = TRUE, sep=',', row.names = FALSE))
To recover the list of dataframes from mylist.csv
you can do :
#read the csv file
dat <- read.csv('mylist.csv')
#Create a group column to split the data
inds1 <- cumsum(dat[[1]] == names(dat)[1])
#Remove the rows where 1st column is equal to first column name.
inds2 <- dat[[1]] != names(dat)[1]
#split the data into list of dataframes
my.list <- split(dat[inds2, ], inds1[inds2])
my.list
#$`0`
# y1 y2
#1 1 4
#2 2 5
#$`1`
# y1 y2
#4 3 6
#5 2 5
#6 1 4
Saving multiple data-frames to single csv file using Shiny downloadHandler
Other options:
- Write an Excel workbook with one sheet per
dataframe - Zip together multiple csv
files
Here's a sample of both options using four dataframes from the R Datasets Package.
library(shiny)
library(xlsx)
shinyApp(
ui = fluidPage(
downloadButton("downloadExcelSheet", "Download Excel Workbook with Multiple Sheets"),
downloadButton("downloadZippedCSV", "Download zipped csv files")
),
server = function(input, output) {
#### Write an Excel workbook with one sheet per dataframe ####
output$downloadExcelSheet <- downloadHandler(
filename = function() {
"excelWorkbook.xlsx"
},
content = function(file) {
# write workbook and first sheet
write.xlsx(mtcars, file, sheetName = "mtcars", append = FALSE)
# add other sheets for each dataframe
listOtherFiles <- list(iris = iris,
airquality = airquality,
sleep = sleep)
for(i in 1:length(listOtherFiles)) {
write.xlsx(listOtherFiles[i], file,
sheetName = names(listOtherFiles)[i], append = TRUE)
}
}
)
#### Zip together multiple csv files ####
output$downloadZippedCSV <- downloadHandler(
filename = function() {
"zippedCSV.zip"
},
content = function(file) {
# go to temp dir to avoid permission issues
owd <- setwd(tempdir())
on.exit(setwd(owd))
# create list of dataframes and NULL value to store fileNames
listDataFrames <- list(mtcars = mtcars,
iris = iris,
airquality = airquality,
sleep = sleep)
allFileNames <- NULL
# loop through each dataframe
for(i in 1:length(listDataFrames)) {
# write each dataframe as csv and save fileName
fileName <- paste0(names(listDataFrames)[i], ".csv")
write.csv(listDataFrames[1], fileName)
allFileNames <- c(fileName, allFileNames)
}
# write the zip file
zip(file, allFileNames)
}
)
}
)
How to save a dataframe with list to csv file in R
Since it's not a data.frame , and more specifically cannot be coerced to one with as.data.frame which is where that message came from, you need to think of a different method of saving the data. Probably this simplest would be with dput
, which writes an ASCII representation of the list structure:
dput(operacions, file="out.txt")
To bring it back into R:
new <- source("out.txt")
Another method would be to convert to JSON format, which would also preserve the key-value information rather than just writing the values:
library(jsonlite)
toJSON(new)
# value---------
{"value":[{"Nom":["Victor"],"Bolis":["Negro","azul","verde"]},{"Nom":["Dani"],"Lapices":[1,2,3,4]}],"visible":[true]}
You can use the cat function to direct this to a text file:
cat( toJSON(new), file="test.3.txt")
Appending csv files of different dimension in R
There are a few ways I can think of. One would be to create a single data frame and then write it out to a CSV. This is kind of a pain. The other way(s) would be to either write out the body of the data into a file and then prepend your header info to that file or, conversely, write out the header info then append the csv body to that file.
I'd take an approach of creating the headers first and then appending the csv second. To get the ability to append, however, you have to switch from the write.csv()
to write.table()
Here's an example:
header <- "my first line"
body <- data.frame(a=rnorm(10), b=rnorm(10))
write.table(header, file="/tmp/myfile.txt", row.names=F, col.names=F, quote=F)
write.table(body, file="/tmp/myfile.txt", row.names=F, col.names=F, append=T, sep=",")
and, as you would expect, the resulting file looks like this:
$ cat myfile.txt
my first line
1.23874432711773,-2.2589990017634
0.231896206292307,1.17882048865978
-0.314437880898758,0.902090923407546
1.4997037042092,0.626724662264575
0.0695743692981956,0.250950969342156
1.33403372000003,0.552648907461989
0.182234972030415,0.950754253582309
-0.0960762881273546,-0.714485753494804
-0.850532439053779,1.89170555264949
0.269472111643762,1.39531731667127
Writing multiple lists of different lengths to same rows in Python
Once you establish the longest list in each input, you can pad the other lists with empty strings.
Name = ["Jon"]
Date = [1985]
Patcit = [1, 2, 3]
Npatcit = [4, 5, 6, 7, 8]
Class = [9, 10]
data = {"Name":Name, "Date":Date, "Patcit":Patcit, "Npatcit":Npatcit, "Class":Class}
max_n = max([len(x) for x in data.values()])
for field in data:
data[field] += [''] * (max_n - len(data[field]))
data
{'Class': [9, 10, '', '', ''],
'Date': [1985, '', '', '', ''],
'Name': ['Jon', '', '', '', ''],
'Npatcit': [4, 5, 6, 7, 8],
'Patcit': [1, 2, 3, '', '']}
Then write to CSV using your preferred method. I'd choose Pandas:
import pandas as pd
df = pd.DataFrame(data)
df.to_csv("output.csv", index=False)
df
Class Date Name Npatcit Patcit
0 9 1985 Jon 4 1
1 10 5 2
2 6 3
3 7
4 8
UPDATE
if you need to do this over multiple iterations (for example, over multiple cases of info
in grant
in your sample use case), you can use concat
.
I'd also recommend moving the padding operation into a function, like this:
import pandas as pd
def pad(data):
max_n = max([len(x) for x in data.values()])
for field in data:
data[field] += [''] * (max_n - len(data[field]))
return data
# CSV 1
Name = ["Jon"]
Date = [1985]
Patcit = [1, 2, 3]
Npatcit = [4, 5, 6, 7, 8]
Class = [9, 10]
data = {"Name":Name, "Date":Date, "Patcit":Patcit, "Npatcit":Npatcit, "Class":Class}
df = pd.DataFrame(pad(data))
# CSV 2
Name = ["Sally"]
Date = [19995]
Patcit = [9,8,7]
Npatcit = [1,3,5]
Class = [4, 10,15]
data = {"Name":Name, "Date":Date, "Patcit":Patcit, "Npatcit":Npatcit, "Class":Class}
df = pd.concat([df, pd.DataFrame(pad(data))])
df
Class Date Name Npatcit Patcit
0 9 1985 Jon 4 1
1 10 5 2
2 6 3
3 7
4 8
0 4 19995 Sally 1 9
1 10 3 8
2 15 5 7
Related Topics
Extracting Indices for Data Frame Rows That Have Max Value for Named Field
Installing Package from a Local .Tar.Gz File on Linux
Knitr: Opts_Chunk$Set() Not Working in Rscript Command
Create a New Variable Based on the First 7 Characters of Existing Variable
Row-Wise Sum of Values Grouped by Columns with Same Name
Get Dates of a Certain Weekday from a Year in R
How to Scrape Items Together So You Don't Lose the Index
R Shiny Widgetfunc() Warning Messages with Eventreactive(Warning 1) and Renderdatatable (Warning 2)
R Lpsolve Binary Find All Possible Solutions
Manipulating Files with Non-English Names in R
Sum Specific Columns Among Rows
R + Ggplot2: How to Hide Missing Dates from X-Axis
Repeat Vector to Fill Down Column in Data Frame