Table 在具有行名时将不需要的前导空列写入 Header

看看这个例子:

> 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

有两种不同的方式将其写入文件..。

write.csv(a, 'a.csv')的结果与预期一致:

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

write.table(a, 'a.txt')会搞砸

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

事实上,一个空标签丢失了... ... 这对于下游的东西来说是一个痛苦的屁股。 这是一个 bug 还是一个特性? 有变通方法吗? (除了 write.table(cbind(rownames(a), a), 'a.txt', row.names=FALSE)

干杯, Yannick

84493 次浏览

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

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!

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

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.

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