write.table escribe una columna vacía inicial no deseada en el encabezado cuando tiene nombres de fila

92

mira este ejemplo:

> 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

la tabla se muestra correctamente. Hay dos formas diferentes de escribirlo en un archivo ...

write.csv(a, 'a.csv') que da como se esperaba:

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

y write.table(a, 'a.txt')que arruina

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

de hecho, falta una pestaña vacía ... lo cual es un dolor de cabeza para las cosas posteriores. ¿Es esto un error o una característica? ¿Existe alguna solución? (que no sea write.table(cbind(rownames(a), a), 'a.txt', row.names=FALSE)

Saludos, Yannick

Yannick Wurm
fuente

Respuestas:

141

Citando ?write.table, sección archivos CSV :

De forma predeterminada, no hay un nombre de columna para una columna de nombres de fila. Si col.names = NAy row.names = TRUEse agrega un nombre de columna en blanco, que es la convención utilizada para que las hojas de cálculo lean los archivos CSV.

Así que debes hacer

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

y obtienes

"" "A" "B" "C"
"A" 1 4 7
"B" 2 5 8
"C" 3 6 9
Marek
fuente
4
@Marek, ¿sería posible agregar un nombre a la columna de nombres de filas? Es decir, en lugar de "", ¿agregar "ID" o algo parecido?
Dnaiel
2
@Dnaiel Por lo que sé, no puedes. Puede vincular nombres de filas con datos y darles nombres (como en la pregunta).
Marek
1
@rusalkaguy Tu edición no tiene sentido. Esta "extensión" está en cuestión original ("solución alternativa que no sea")
Marek
¿Cómo conseguiría que el número de cada columna se alineara con los nombres de las columnas?
2017
@rrs ¿Te refieres al formato de ancho fijo? Mire write.fwf del paquete gdata . Y haga una nueva pregunta en lugar de comentar. ¡¿Y por qué necesitas eso ?!
Marek
10

Una ligera modificación a @Marek, una respuesta muy útil, agregará un encabezado a la columna de nombres de fila: agregue temporalmente los nombres de fila como la primera columna en el data.frame, y escríbalo, ignorando los nombres de fila reales.

> 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)

y obtienes

"H" "A" "B" "C"
"A" 1 4 7
"B" 2 5 8
"C" 3 6 9
rusalkaguy
fuente
Deberías editar la respuesta de Marek para incluir esto, creo.
user8397947
3

Para cualquiera que trabaje en tidyverse (dplyr, etc.), la rownames_to_column()función del paquete tibble se puede usar para convertir fácilmente row.names en una columna, por ejemplo:

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

La combinación de esto con la row.names=FALSEopción en write.table()da como resultado una salida con nombres de encabezado para todas las columnas.

Keith Hughitt
fuente
1

Para aquellos que experimentan el mismo problema al guardar una matriz write.table()y desean mantener la columna row.names, en realidad existe una solución extremadamente simple:

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

Al hacer eso, básicamente está engañando a la write.tablefunción para que cree una etiqueta de encabezado para la columna row.names. El archivo .csv resultante se vería así:

row_name_col;val1_col;val2_col
row1;1;4 
row2;2;5 
row3;3;6 
uribalb
fuente
Estoy probando col.names = c ("row_name", colnames (matriz)) y obtengo un error que dice que la especificación 'col.names' no es válida. ¿Alguna idea de lo que está mal? c ("row_name", colnames (matriz)) da el texto correcto.
MichaelE
write.tableespere un encabezado de longitud ncol(matrix)y le está dando uno más. Probé la solución anterior, no funciona, lo mejor es mover los nombres de fila como una columna como en otras soluciones
aurelien
0

Revisé una función simple de @mnel, que agrega flexibilidad al usar conexiones. Aquí está la función:

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,...)
}

Puede especificar que la función sea 'write.table', 'write.csv', 'write.delim', etc.

¡Salud!

yuanhangliu1
fuente