web-dev-qa-db-fra.com

Moyen le plus simple pour que rbind ignore les noms de colonne

Cela est venu juste en réponse à une autre question ici. Lorsque vous rbind deux blocs de données, il fait correspondre les colonnes par nom plutôt que par index, ce qui peut entraîner un comportement inattendu:

> df<-data.frame(x=1:2,y=3:4)
> df
  x y
1 1 3
2 2 4
> rbind(df,df[,2:1])
  x y
1 1 3
2 2 4
3 1 3
4 2 4

Bien sûr, il existe des solutions de contournement. Par exemple:

rbind(df,rename(df[,2:1],names(df)))
data.frame(rbind(as.matrix(df),as.matrix(df[,2:1])))

Lors de l'édition: rename du package plyr ne fonctionne pas vraiment de cette façon (même si je pensais que je le faisais quand j'ai écrit cela à l'origine ...). La façon de le faire en renommant est d'utiliser la solution de SimonO101:

rbind(df,setNames(df[,2:1],names(df)))

Aussi, peut-être étonnamment,

data.frame(rbindlist(list(df,df[,2:1])))

fonctionne par index (et si cela ne nous dérange pas une table de données, alors c'est assez concis), c'est donc une différence entre do.call(rbind).

La question est, quelle est la manière la plus concise de rbind deux trames de données où les noms ne correspondent pas? Je sais que cela semble trivial, mais ce genre de chose peut finir par encombrer le code. Et je ne veux pas avoir à écrire une nouvelle fonction appelée rbindByIndex. Idéalement, ce serait quelque chose comme rbind(df,df[,2:1],byIndex=T).

40
mrip

Vous trouverez peut-être setNames à portée de main ici ...

rbind(df, setNames(rev(df), names(df)))
#  x y
#1 1 3
#2 2 4
#3 3 1
#4 4 2

Je soupçonne que votre cas d'utilisation réel est un peu plus complexe. Vous pouvez bien sûr réorganiser les colonnes dans le premier argument de setNames comme vous le souhaitez, utilisez simplement names(df) dans le deuxième argument, de sorte que les noms des colonnes réorganisées correspondent à l'original.

45
Simon O'Hanlon

Cela semble assez simple:

mapply(c,df,df[,2:1])
     x y
[1,] 1 3
[2,] 2 4
[3,] 3 1
[4,] 4 2

Pour ce cas simple, cependant, vous devez le reconvertir en cadre de données (car mapply le simplifie en matrice):

as.data.frame(mapply(c,df,df[,2:1]))
  x y
1 1 3
2 2 4
3 3 1
4 4 2

Note importante 1: Il semble y avoir un inconvénient à la coercition de type lorsque votre trame de données contient des vecteurs de différents types:

df<-data.frame(x=1:2,y=3:4,z=c('a','b'))
mapply(c,df,df[,c(2:1,3)])
     x y z
[1,] 1 3 2
[2,] 2 4 1
[3,] 3 1 2
[4,] 4 2 1

Note importante 2: C'est aussi terrible si vous avez des facteurs.

df<-data.frame(x=factor(1:2),y=factor(3:4))
mapply(c,df[,1:2],df[,2:1])
     x y
[1,] 1 1
[2,] 2 2
[3,] 1 1
[4,] 2 2

Donc, tant que vous avez toutes les données numériques, ça va.

8
Thomas