Write.Csv() a List of Unequally Sized Data.Frames

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:

  1. Write an Excel workbook with one sheet per
    dataframe
  2. 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



Leave a reply



Submit