Come si può aggiungere una riga a un frame di dati in R?


129

In R, come si aggiunge una nuova riga a un frame di dati una volta che il frame di dati è già stato inizializzato?

Finora ho questo:

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

Qualsiasi aiuto sarebbe apprezzato


1
assegnare nomi deanche a. names(de) <- c("hello","goodbye")erbind
Khashaa,

3
O in una rigarbind(df, setNames(de, names(df)))
Rich Scriven,

2
Questa è davvero una zona che di base R fallisce miseramente a, ed ha per lungo tempo: stackoverflow.com/questions/13599197/...
thelatemail

1
@thelatemail non è d'accordo. i frame di dati sono una struttura speciale in r. un elenco di elenchi con nomi, attributi e metodi comuni. Penso che ci si possa aspettare che non si possa rbind(data.frame(a = 1), data.frame(b = 2))... perché dovresti farlo? Spero che ciò provocherebbe un errore a prescindere. È come merge'ing con una byvariabile casuale . E questo è il 2015, non sono tutti pronti options(stringsAsFactors = FALSE)?
Rawr,

1
@rawr - certo, i nomi diversi non dovrebbero essere associati, ma R non può gestire l'associazione di nessun nome a nessun nome, l'associazione di nomi a nessun nome con le stesse dimensioni o l'associazione di nuovi dati per incorporare nuovi livelli di fattore. Penso che sia un punto debole. In particolare quando è in grado di gestire nomi ripetuti e tutti i nomi NA associati. E l'impostazione stringsAsFactors=FALSEpuò essere una soluzione rapida, ma cambiare le impostazioni predefinite che altre persone hanno impostato in modo diverso può davvero rovinare un giorno.
thelatemail,

Risposte:


131

Come sottolineato da @Khashaa e @Richard Scriven nei commenti, è necessario impostare nomi di colonna coerenti per tutti i frame di dati che si desidera aggiungere.

Pertanto, è necessario dichiarare esplicitamente i nomi delle colonne per il secondo frame di dati de, quindi utilizzare rbind(). È possibile impostare solo i nomi di colonna per il primo frame di dati 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)

Grazie! Qualche idea su come risolvere questo problema se non ho dichiarato un secondo frame di dati, ma invece ho ogni valore che voglio aggiungere a una nuova riga memorizzata come variabile?
Rilcon42,

8
Prova: newdf<-rbind(df, data.frame(hello="hola", goodbye="ciao"))OPPURE con variabile:newdf<-rbind(df, data.frame(hello=var1, goodbye=var2))
Parfait,

109

Rendiamolo semplice:

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

10
Ciò causa problemi quando si tenta di aggiungere una nuova riga con tipi di dati misti (alcune stringhe, altre numeriche). In tal caso, anche i valori numerici vengono convertiti in stringa. Una soluzione alternativa consiste nell'aggiungere i valori separatamente, in modo simile al seguente (supponendo che siano presenti 3 colonne): df[nrow(df) + 1, 1:2] = c("v1", "v2")e df[nrow(df), 3] = 100tuttavia è comunque utile aggiungere una nuova riga. Quindi, +1
The Student Soul

17
Oppure usa "list" invece di "c".
Ytsen de Boer,

bella idea, ma come posso fare se voglio inserire o aggiungere una nuova riga alla prima posizione?
Darwin PC

1
Ho provato questo con data.table ma dice con nrow + 1 è fuori portata.
Herman Toothrot,

1
@Arani c'è già una risposta con list(). Ho ripristinato la tua modifica.
M--

41

Oppure, come ispirato da @MatheusAraujo:

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

Ciò consentirebbe tipi di dati misti.


24

C'è ora add_row()dai pacchetti tibbleo tidyverse.

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

Le colonne non specificate ottengono un NA.


Mi è piaciuto questo approccio se ti attieni alla filosofia ordinata. Altrimenti la sintassi R di base è un'abilità di sopravvivenza che è utile quando ti trovi in ​​un ambiente in cui non hai i privilegi per importare i pacchetti. Mi piace particolarmente la risposta usando la sintassi R semplice con rbinde as.matrix sotto
Pablo Adames il

17

Mi piace listinvece cperché gestisce meglio i tipi di dati misti. Aggiunta di una colonna aggiuntiva alla domanda del poster 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)

Si noti che è necessario un controllo aggiuntivo se la conversione stringa / fattore è importante.

O usando le variabili originali con la soluzione di MatheusAraujo / Ytsen de Boer:

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

Nota che questa soluzione non funziona bene con le stringhe a meno che non ci siano dati esistenti nel frame di dati.


Se helloe hai goodbyecarattere df, puoi fare quanto segue. Non usi necessariamente i nomi in un elenco. df <- data.frame(hello = "hi", goodbye = "bye", volume = 1,stringsAsFactors = FALSE); rbind(df, list("hola", "ciao", 100)).
jazzurro,

11

Non terribilmente elegante, ma:

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

Dalla documentazione della rbindfunzione:

Per i rbindnomi delle colonne sono presi dal primo argomento con nomi appropriati: nomi di colonna per una matrice ...


Questa soluzione funziona senza la necessità di specificare le colonne da aggiungere, il che è molto meglio per le applicazioni su set di dati di grandi dimensioni
Phil_T

1

Devo aggiungere stringsAsFactors=FALSEquando creo il frame di dati.

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

1

Assicurati di specificare stringsAsFactors=FALSEquando crei il frame di dati:

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

Se non si utilizza stringsAsFactors=FALSEdurante la creazione del frame di dati, si verificherà il seguente errore quando si tenta di aggiungere la nuova riga:

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

0

Esiste un modo più semplice per aggiungere un record da un frame di dati a un altro SE sai che i due frame di dati condividono le stesse colonne e tipi. Per aggiungere una riga da xxal yysolo fare il seguente, dove iè la i'esima riga in xx.

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

Semplice come quella. Nessun vincolo disordinato. Se devi aggiungere tutto xxa yy, allora chiama un loop o sfrutta le abilità di sequenza di R e fai questo:

zz[(nrow(zz)+1):(nrow(zz)+nrow(yy)),] <- yy[1:nrow(yy),]

0

Se si desidera creare un frame di dati vuoto e aggiungere contenuti in un ciclo, potrebbero essere utili:

# 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

Spero che sia d'aiuto :)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.