write.table écrit une colonne vide de début indésirable dans l'en-tête lorsqu'il a des noms de rôle

90

vérifiez cet exemple:

> 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

le tableau s'affiche correctement. Il existe deux manières différentes de l'écrire dans un fichier ...

write.csv(a, 'a.csv') ce qui donne comme prévu:

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

et write.table(a, 'a.txt')qui bousille

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

en effet, il manque un onglet vide ... ce qui est pénible pour les choses en aval. Est-ce un bug ou une fonctionnalité? Y at-il un travail autour? (autre que write.table(cbind(rownames(a), a), 'a.txt', row.names=FALSE)

Salut, yannick

Yannick Wurm
la source

Réponses:

137

Citant ?write.table, section fichiers CSV :

Par défaut, il n'y a pas de nom de colonne pour une colonne de noms de ligne. Si col.names = NAet row.names = TRUEun nom de colonne vide est ajouté, qui est la convention utilisée pour les fichiers CSV à lire par des feuilles de calcul.

Alors tu dois faire

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

et vous obtenez

"" "A" "B" "C"
"A" 1 4 7
"B" 2 5 8
"C" 3 6 9
Marek
la source
4
@Marek, serait-il possible d'ajouter un nom à la colonne des noms de domaine? Ie, au lieu de "", ajoutez "ID" ou quelque chose de similaire?
Dnaiel
2
@Dnaiel D'après ce que je sais, vous ne pouvez pas. Vous pouvez lier les noms de lignes avec des données et leur donner des noms (comme en question).
Marek
1
@rusalkaguy Votre modification ne sert à rien. Cette "extension" est en question d'origine ("solution de contournement autre que")
Marek
Comment obtiendriez-vous le numéro dans chaque colonne pour s'aligner sous les noms de col?
rrs
@rrs Vous voulez dire un format à largeur fixe? Regardez write.fwf du package gdata . Et posez une nouvelle question au lieu de commenter. Et pourquoi avez-vous jamais besoin de ça?!
Marek
10

Une légère modification de la réponse très utile @Marek ajoutera un en-tête à la colonne rownames: ajoutez temporairement les rownames comme première colonne dans le data.frame, et écrivez cela, en ignorant les vrais 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)

et vous obtenez

"H" "A" "B" "C"
"A" 1 4 7
"B" 2 5 8
"C" 3 6 9
Rusalkaguy
la source
Vous devriez modifier la réponse de Marek pour inclure cela, je pense.
user8397947
3

Pour toute personne travaillant dans le tidyverse (dplyr, etc.), la rownames_to_column()fonction du paquet tibble peut être utilisée pour convertir facilement row.names en colonne, par exemple:

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

En combinant cela avec l' row.names=FALSEoption in, vous write.table()obtenez une sortie avec des noms d'en-tête pour toutes les colonnes.

Keith Hughitt
la source
1

Pour ceux qui rencontrent le même problème lors de l'enregistrement d'une matrice avec write.table()et souhaitent conserver la colonne row.names, il existe en fait une solution extrêmement simple:

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

En faisant cela, vous incitez la write.tablefonction à créer une étiquette d'en-tête pour la colonne row.names. Le fichier .csv résultant ressemblerait à ceci:

row_name_col;val1_col;val2_col
row1;1;4 
row2;2;5 
row3;3;6 
uribalb
la source
J'essaye col.names = c ("row_name", colnames (matrix)) et j'obtiens une erreur indiquant la spécification "col.names" invalide. Une idée de ce qui ne va pas? c ("nom_ligne", colnames (matrice)) donne le texte correct.
MichaelE
write.tableattendez un en-tête de longueur ncol(matrix)et vous lui en donnez un de plus. J'ai essayé la solution ci-dessus, cela ne fonctionne pas, le mieux est de déplacer les noms de rangs comme une colonne comme dans d'autres solutions
aurelien le
0

J'ai révisé une fonction simple de @mnel, qui ajoute de la flexibilité en utilisant des connexions. Voici la fonction:

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

Vous pouvez spécifier la fonction comme étant «write.table», «write.csv», «write.delim», etc.

À votre santé!

yuanhangliu1
la source