write.table writes unwanted leading empty column to header when has rownames

RExport to-Csvwrite.table

R Problem Overview


check this example:

> a = matrix(1:9, nrow = 3, ncol = 3, dimnames = list(LETTERS[1:3], LETTERS[1:3]))
> a
  A B C
A 1 4 7
B 2 5 8
C 3 6 9

the table displays correctly. There are two different ways of writing it to file...

write.csv(a, 'a.csv') which gives as expected:

"","A","B","C"
"A",1,4,7
"B",2,5,8
"C",3,6,9

and write.table(a, 'a.txt') which screws up

"A" "B" "C"
"A" 1 4 7
"B" 2 5 8
"C" 3 6 9

indeed, an empty tab is missing.... which is a pain in the butt for downstream things. Is this a bug or a feature? Is there a workaround? (other than write.table(cbind(rownames(a), a), 'a.txt', row.names=FALSE)

Cheers, yannick

R Solutions


Solution 1 - R

Citing ?write.table, section CSV files:

> By default there is no column name for > a column of row names. If col.names = > NA and row.names = TRUE a blank > column name is added, which is the > convention used for CSV files to be > read by spreadsheets.

So you must do

write.table(a, 'a.txt', col.names=NA)

and you get

"" "A" "B" "C"
"A" 1 4 7
"B" 2 5 8
"C" 3 6 9

Solution 2 - R

A slight modification to @Marek very helpful answer WILL add a header to the rownames column: temporarily add the rownames as the first column in the data.frame, and write that, ignoring the real rownames.

> a = matrix(1:9, nrow = 3, ncol = 3, dimnames = list(LETTERS[1:3], LETTERS[1:3]))
> write.table(data.frame("H"=rownames(a),a),"a.txt", row.names=FALSE)

and you get

"H" "A" "B" "C"
"A" 1 4 7
"B" 2 5 8
"C" 3 6 9

Solution 3 - R

For anyone working in the tidyverse (dplyr, etc.), the rownames_to_column() function from the tibble package can be used to easily convert row.names to a column, e.g.:

library('tibble')
a = as.data.frame(matrix(1:9, nrow=3, ncol=3, 
                  dimnames=list(LETTERS[1:3], LETTERS[1:3])))

a %>% rownames_to_column('my_id')

  my_id A B C
1     A 1 4 7
2     B 2 5 8
3     C 3 6 9

Combining this with the row.names=FALSE option in write.table() results in output with header names for all columns.

Solution 4 - R

For those who experience the same issue when saving a matrix with write.table() and want to keep the row.names column, there is actually an extremely simple solution:

 write.table(matrix,file="file.csv",quote=F,sep=";", row.names=T
             col.names=c("row_name_col;val1_col","val2_col"))

By doing that you're basically tricking the write.table function into creating a header label for the row.names column. The resulting .csv file would look like this:

row_name_col;val1_col;val2_col
row1;1;4 
row2;2;5 
row3;3;6 

Solution 5 - R

I revised a simple function from @mnel, which adds flexibility by using connections. Here is the function:

my.write <- function(x, file, header, f = write.csv, ...){
# create and open the file connection
datafile <- file(file, open = 'wt')
# close on exit 
on.exit(close(datafile))
# if a header is defined, write it to the file (@CarlWitthoft's suggestion)
if(!missing(header)) {
writeLines(header,con=datafile, sep='\t')
writeLines('', con=datafile, sep='\n')
}
# write the file using the defined function and required addition arguments  
f(x, datafile,...)
}

You can specify the function to be 'write.table', 'write.csv', 'write.delim' etc.

Cheers!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionYannick WurmView Question on Stackoverflow
Solution 1 - RMarekView Answer on Stackoverflow
Solution 2 - RrusalkaguyView Answer on Stackoverflow
Solution 3 - RKeith HughittView Answer on Stackoverflow
Solution 4 - RLeCodexView Answer on Stackoverflow
Solution 5 - Ryuanhangliu1View Answer on Stackoverflow