Comment ajouter une ligne à un bloc de données dans R?

129

Dans R, comment ajouter une nouvelle ligne à un bloc de données une fois que le bloc de données a déjà été initialisé?

Jusqu'à présent, j'ai ceci:

df <- data.frame("hi", "bye")
names(df) <- c("hello", "goodbye")

#I am trying to add "hola" and "ciao" as a new row
de <- data.frame("hola", "ciao")

merge(df, de) # Adds to the same row as new columns

# Unfortunately, I couldn't find an rbind() solution that wouldn't give me an error

Toute aide serait appréciée

Rilcon42
la source
1
attribuer des noms à deaussi. names(de) <- c("hello","goodbye")etrbind
Khashaa
3
Ou en une lignerbind(df, setNames(de, names(df)))
Rich Scriven
2
C'est vraiment un domaine dans lequel la base R échoue lamentablement, et ce depuis longtemps: stackoverflow.com/questions/13599197
...
1
@thelatemail n'est pas d'accord. les trames de données sont une structure spéciale dans r. une liste de listes avec des dimnames, des attributs et des méthodes communs. Je pense qu'il est très attendu que l'on ne puisse pas rbind(data.frame(a = 1), data.frame(b = 2)).. pourquoi voudriez-vous? J'espère que cela jetterait une erreur malgré tout. C'est comme mergeavec une byvariable aléatoire . Et c'est 2015, tout le monde n'est-il pas fixé options(stringsAsFactors = FALSE)?
rawr
1
@rawr - bien sûr, des noms différents ne doivent pas être liés, mais R ne peut pas gérer la liaison d'aucun nom à aucun nom, la liaison de noms à aucun nom avec les mêmes dimensions ou la liaison de nouvelles données pour incorporer de nouveaux niveaux de facteur. Je pense que c'est une faiblesse. Surtout quand il peut gérer la liaison des noms répétés et tous les noms NA. Et le réglage stringsAsFactors=FALSEpeut être une solution rapide, mais changer les paramètres par défaut que d'autres personnes vont définir différemment peut vraiment gâcher une journée.
thelatemail

Réponses:

131

Comme @Khashaa et @Richard Scriven le soulignent dans les commentaires, vous devez définir des noms de colonne cohérents pour tous les blocs de données que vous souhaitez ajouter.

Par conséquent, vous devez déclarer explicitement les noms de colonnes pour le deuxième bloc de données,, depuis utiliser rbind(). Vous définissez uniquement les noms de colonnes pour la première trame de données, df:

df<-data.frame("hi","bye")
names(df)<-c("hello","goodbye")

de<-data.frame("hola","ciao")
names(de)<-c("hello","goodbye")

newdf <- rbind(df, de)
Parfait
la source
Merci! Une idée de comment résoudre ce problème si je n'ai pas de deuxième dataframe déclaré, mais que chaque valeur que je veux ajouter à une nouvelle ligne est stockée en tant que variable?
Rilcon42
8
Essayez: newdf<-rbind(df, data.frame(hello="hola", goodbye="ciao"))OU avec variable:newdf<-rbind(df, data.frame(hello=var1, goodbye=var2))
Parfait
109

Faisons simple:

df[nrow(df) + 1,] = c("v1","v2")
Matheus Araujo
la source
10
Cela pose des problèmes lors de la tentative d'ajout d'une nouvelle ligne avec des types de données mixtes (certaines chaînes, certaines numériques). Dans un tel cas, même les valeurs numériques sont converties en chaîne. Une solution de contournement consiste à ajouter les valeurs séparément, quelque chose comme ce qui suit (en supposant qu'il y ait 3 colonnes): df[nrow(df) + 1, 1:2] = c("v1", "v2")et df[nrow(df), 3] = 100Mais c'est quand même un bon point sur l'ajout d'une nouvelle ligne. Donc, +1
The Student Soul
17
Ou utilisez "list" au lieu de "c".
Ytsen de Boer
belle idée, mais comment puis-je faire si je veux insérer ou ajouter une nouvelle ligne à la première position?
Darwin PC
1
J'ai essayé avec data.table mais dit avec nrow + 1 est hors de portée.
Herman Toothrot
1
@Arani il y a déjà une réponse avec list(). J'ai annulé votre modification.
M--
41

Ou, comme inspiré par @MatheusAraujo:

df[nrow(df) + 1,] = list("v1","v2")

Cela permettrait des types de données mixtes.

Ytsen de Boer
la source
24

Il y a maintenant add_row()des packages tibbleou tidyverse.

library(tidyverse)
df %>% add_row(hello = "hola", goodbye = "ciao")

Les colonnes non spécifiées obtiennent un NA.

Joe
la source
J'ai aimé cette approche si vous vous en tenez à la philosophie tidyverse. Sinon, la syntaxe R de base est une compétence de survie qui est utile lorsque vous êtes dans un environnement où vous n'avez pas les privilèges d'importer des packages. J'aime particulièrement la réponse utilisant la syntaxe R simple avec rbindet as.matrix ci
Pablo Adames
17

J'aime listplutôt cparce qu'il gère mieux les types de données mixtes. Ajout d'une colonne supplémentaire à la question de l'affiche originale:

#Create an empty data frame
df <- data.frame(hello=character(), goodbye=character(), volume=double())
de <- list(hello="hi", goodbye="bye", volume=3.0)
df = rbind(df,de, stringsAsFactors=FALSE)
de <- list(hello="hola", goodbye="ciao", volume=13.1)
df = rbind(df,de, stringsAsFactors=FALSE)

Notez qu'un contrôle supplémentaire est nécessaire si la conversion chaîne / facteur est importante.

Ou en utilisant les variables originales avec la solution de MatheusAraujo / Ytsen de Boer:

df[nrow(df) + 1,] = list(hello="hallo",goodbye="auf wiedersehen", volume=20.2)

Notez que cette solution ne fonctionne pas bien avec les chaînes sauf s'il existe des données dans le dataframe.

gsk9
la source
Si helloet goodbyesont dans le personnage df, vous pouvez faire ce qui suit. Vous n'utilisez pas nécessairement de noms dans une liste. df <- data.frame(hello = "hi", goodbye = "bye", volume = 1,stringsAsFactors = FALSE); rbind(df, list("hola", "ciao", 100)).
jazzurro
11

Pas très élégant, mais:

data.frame(rbind(as.matrix(df), as.matrix(de)))

De la documentation de la rbindfonction:

Pour les rbindnoms de colonne sont tirés du premier argument avec les noms appropriés: colnames pour une matrice ...

J. Win.
la source
Cette solution fonctionne sans avoir besoin de spécifier les colonnes à ajouter, ce qui est bien mieux pour les applications sur de grands ensembles de données
Phil_T
1

Je dois ajouter stringsAsFactors=FALSElors de la création du dataframe.

> df <- data.frame("hello"= character(0), "goodbye"=character(0))
> df
[1] hello   goodbye
<0 rows> (or 0-length row.names)
> df[nrow(df) + 1,] = list("hi","bye")
Warning messages:
1: In `[<-.factor`(`*tmp*`, iseq, value = "hi") :
  invalid factor level, NA generated
2: In `[<-.factor`(`*tmp*`, iseq, value = "bye") :
  invalid factor level, NA generated
> df
  hello goodbye
1  <NA>    <NA>
> 

.

> df <- data.frame("hello"= character(0), "goodbye"=character(0), stringsAsFactors=FALSE)
> df
[1] hello   goodbye
<0 rows> (or 0-length row.names)
> df[nrow(df) + 1,] = list("hi","bye")
> df[nrow(df) + 1,] = list("hola","ciao")
> df[nrow(df) + 1,] = list(hello="hallo",goodbye="auf wiedersehen")
> df
  hello         goodbye
1    hi             bye
2  hola            ciao
3 hallo auf wiedersehen
> 
nealei
la source
1

Assurez-vous de spécifier stringsAsFactors=FALSElors de la création du dataframe:

> rm(list=ls())
> trigonometry <- data.frame(character(0), numeric(0), stringsAsFactors=FALSE)
> colnames(trigonometry) <- c("theta", "sin.theta")
> trigonometry
[1] theta     sin.theta
<0 rows> (or 0-length row.names)
> trigonometry[nrow(trigonometry) + 1, ] <- c("0", sin(0))
> trigonometry[nrow(trigonometry) + 1, ] <- c("pi/2", sin(pi/2))
> trigonometry
  theta sin.theta
1     0         0
2  pi/2         1
> typeof(trigonometry)
[1] "list"
> class(trigonometry)
[1] "data.frame"

stringsAsFactors=FALSESi vous ne l' utilisez pas lors de la création du dataframe, l'erreur suivante se produira lors de la tentative d'ajout de la nouvelle ligne:

> trigonometry[nrow(trigonometry) + 1, ] <- c("0", sin(0))
Warning message:
In `[<-.factor`(`*tmp*`, iseq, value = "0") :
  invalid factor level, NA generated
OracleJavaNet
la source
0

Il existe un moyen plus simple d'ajouter un enregistrement d'un dataframe à un autre SI vous savez que les deux dataframes partagent les mêmes colonnes et types. Pour ajouter une ligne de xxà, yyprocédez comme suit: où se itrouve la i'ème ligne xx.

yy[nrow(yy)+1,] <- xx[i,]

Aussi simple que cela. Pas de liaisons désordonnées. Si vous devez tout ajouter xxà yy, appelez une boucle ou profitez des capacités de séquence de R et procédez comme suit:

zz[(nrow(zz)+1):(nrow(zz)+nrow(yy)),] <- yy[1:nrow(yy),]
Patrick Champion
la source
0

Si vous souhaitez créer un bloc de données vide et ajouter du contenu dans une boucle, les éléments suivants peuvent vous aider:

# Number of students in class
student.count <- 36

# Gather data about the students
student.age <- sample(14:17, size = student.count, replace = TRUE)
student.gender <- sample(c('male', 'female'), size = student.count, replace = TRUE)
student.marks <- sample(46:97, size = student.count, replace = TRUE)

# Create empty data frame
student.data <- data.frame()

# Populate the data frame using a for loop
for (i in 1 : student.count) {
    # Get the row data
    age <- student.age[i]
    gender <- student.gender[i]
    marks <- student.marks[i]

    # Populate the row
    new.row <- data.frame(age = age, gender = gender, marks = marks)

    # Add the row
    student.data <- rbind(student.data, new.row)
}

# Print the data frame
student.data

J'espère que ça aide :)

Edwin Pratt
la source