¿Cómo se puede agregar una fila a un marco de datos en R?

129

En R, ¿cómo agrega una nueva fila a un marco de datos una vez que el marco de datos ya se ha inicializado?

Hasta ahora tengo esto:

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

Cualquier ayuda sería apreciada

Rilcon42
fuente
1
asignar nombres a detambién. names(de) <- c("hello","goodbye")yrbind
Khashaa
3
O en una línearbind(df, setNames(de, names(df)))
Rich Scriven
2
Esta realmente es un área en la que la base R falla miserablemente, y lo ha hecho durante mucho tiempo: stackoverflow.com/questions/13599197/…
thelatemail
1
@thelatemail no está de acuerdo. Los marcos de datos son una estructura especial en r. Una lista de listas con nombres y atributos y métodos comunes. Creo que es muy esperado que uno no pueda rbind(data.frame(a = 1), data.frame(b = 2))... ¿por qué quieres hacerlo? Espero que arroje un error independientemente. Es como estar mergecon una byvariable aleatoria . Y esto es 2015, ¿no están todos listos options(stringsAsFactors = FALSE)?
rawr
1
@rawr: claro, no se deben vincular nombres diferentes, pero R no puede manejar la vinculación de nombres sin nombres, la vinculación de nombres sin nombres con las mismas dimensiones o la vinculación de datos nuevos para incorporar nuevos niveles de factores. Creo que es una debilidad. Particularmente cuando puede manejar vinculantes nombres repetidos y todos los nombres de NA. Y la configuración stringsAsFactors=FALSEpuede ser una solución rápida, pero cambiar los valores predeterminados que otras personas establecerán de manera diferente realmente puede arruinar un día.
thelatemail

Respuestas:

131

Como @Khashaa y @Richard Scriven señalan en los comentarios, debe establecer nombres de columna consistentes para todos los marcos de datos que desea agregar.

Por lo tanto, debe declarar explícitamente los nombres de las columnas para el segundo marco de datos dey luego usarlos rbind(). Solo establece los nombres de columna para el primer marco de datos 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
fuente
¡Gracias! ¿Alguna idea de cómo solucionar esto si no tengo un segundo marco de datos declarado, sino que tengo cada valor que quiero agregar a una nueva fila almacenado como una variable?
Rilcon42
8
Prueba: newdf<-rbind(df, data.frame(hello="hola", goodbye="ciao"))O con variable:newdf<-rbind(df, data.frame(hello=var1, goodbye=var2))
Parfait
109

Hagámoslo simple:

df[nrow(df) + 1,] = c("v1","v2")
Matheus Araujo
fuente
10
Esto causa problemas al intentar agregar una nueva fila con tipos de datos mixtos (algunas cadenas, algunas numéricas). En tal caso, incluso los valores numéricos se convierten en cadenas. Una solución alternativa es agregar los valores por separado, algo como lo siguiente (suponiendo que haya 3 columnas): df[nrow(df) + 1, 1:2] = c("v1", "v2")y df[nrow(df), 3] = 100aún así es un buen punto sobre agregar una nueva fila. Entonces, +1
The Student Soul
17
O use "lista" en lugar de "c".
Ytsen de Boer
Buena idea, pero ¿cómo puedo hacer si quiero insertar o agregar una nueva fila en la primera posición?
Darwin PC
1
Intenté esto con data.table pero dice que con nrow + 1 está fuera de rango.
Herman Toothrot
1
@Arani ya hay una respuesta con list(). Revertí tu edición.
M--
41

O, inspirado por @MatheusAraujo:

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

Esto permitiría tipos de datos mixtos.

Ytsen de Boer
fuente
24

Ahora hay add_row()de los paquetes tibbleo tidyverse.

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

Las columnas no especificadas obtienen un NA.

Joe
fuente
Me gustó este enfoque si te apegas a la filosofía tidyverse. De lo contrario, la sintaxis básica de R es una habilidad de supervivencia que resulta útil cuando se encuentra en un entorno en el que no tiene privilegios para importar paquetes. Particularmente me gusta la respuesta usando sintaxis R simple con rbindy as.matrix debajo
Pablo Adames
17

Me gusta en listlugar de cporque maneja mejor los tipos de datos mixtos. Agregar una columna adicional a la pregunta del póster original:

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

Tenga en cuenta que se requiere algún control adicional si la conversión de cadena / factor es importante.

O usando las variables originales con la solución de MatheusAraujo / Ytsen de Boer:

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

Tenga en cuenta que esta solución no funciona bien con las cadenas a menos que haya datos existentes en el marco de datos.

gsk9
fuente
Si helloy goodbyeestán en el personaje df, puede hacer lo siguiente. No necesariamente usa nombres en una lista. df <- data.frame(hello = "hi", goodbye = "bye", volume = 1,stringsAsFactors = FALSE); rbind(df, list("hola", "ciao", 100)).
jazzurro
11

No es terriblemente elegante, pero:

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

De la documentación de la rbindfunción:

Para los rbindnombres de columna se toman del primer argumento con nombres apropiados: colnames para una matriz ...

J. Win.
fuente
Esta solución funciona sin necesidad de especificar las columnas para agregar, lo cual es mucho mejor para aplicaciones en grandes conjuntos de datos
Phil_T
1

Necesito agregar stringsAsFactors=FALSEal crear el marco de datos.

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

Asegúrese de especificar stringsAsFactors=FALSEal crear el marco de datos:

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

Si no se usa stringsAsFactors=FALSEal crear el marco de datos, se producirá el siguiente error al intentar agregar la nueva fila:

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

Hay una manera más simple de agregar un registro de un marco de datos a otro SI sabe que los dos marcos de datos comparten las mismas columnas y tipos. Para añadir una fila a partir xxde yysimplemente hacer lo siguiente donde ies la i'th en fila xx.

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

Simple como eso. Sin ataduras desordenadas. Si necesita agregar todo xxa yy, entonces llame a un bucle o aproveche las habilidades de secuencia de R y haga esto:

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

Si desea crear un marco de datos vacío y agregar contenido en un bucle, lo siguiente puede ayudar:

# 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

Espero eso ayude :)

Edwin Pratt
fuente