Como adicionar uma linha a um quadro de dados no R?

129

No R, como você adiciona uma nova linha a um quadro de dados depois que o quadro de dados já foi inicializado?

Até agora eu tenho o seguinte:

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

Qualquer ajuda seria apreciada

Rilcon42
fonte
1
atribuir nomes detambém. names(de) <- c("hello","goodbye")erbind
Khashaa 12/02/2015
3
Ou em uma linharbind(df, setNames(de, names(df)))
Rich Scriven
2
Esta é realmente uma área na qual a base R falha miseravelmente e há muito tempo: stackoverflow.com/questions/13599197/…
thelatemail
1
@thelatemail discorda. quadros de dados são uma estrutura especial em r. uma lista de listas com nomes de nomes e atributos e métodos comuns. Eu acho que é muito esperado que não se possa rbind(data.frame(a = 1), data.frame(b = 2)).. por que você quer? Eu espero que isso gere um erro independentemente. É como se estivesse mergecom uma byvariável aleatória . E isso é 2015, todo mundo não define options(stringsAsFactors = FALSE)?
rawr
1
@rawr - com certeza, nomes diferentes não devem ser vinculados, mas R não pode lidar com a vinculação de nenhum nome a nenhum nome, a vinculação de nomes a nenhum nome com as mesmas dimensões ou a vinculação de novos dados para incorporar novos níveis de fator. Eu acho que é uma fraqueza. Especialmente quando ele pode lidar com nomes repetidos e todos os nomes de NA. E a configuração stringsAsFactors=FALSEpode ser uma solução rápida, mas alterar os padrões que outras pessoas definirão de maneira diferente pode realmente arruinar um dia.
thelatemail

Respostas:

131

Como @Khashaa e @Richard Scriven apontam nos comentários, você deve definir nomes de colunas consistentes para todos os quadros de dados que deseja anexar.

Portanto, você precisa declarar explicitamente os nomes das colunas para o segundo quadro de dados dee depois usá-lo rbind(). Você define apenas os nomes das colunas para o primeiro quadro de dados 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
fonte
Obrigado! Alguma idéia de como corrigir isso se eu não tiver um segundo quadro de dados declarado, mas tiver cada valor que eu quero adicionar a uma nova linha armazenada como uma variável?
Rilcon42
8
Tente: newdf<-rbind(df, data.frame(hello="hola", goodbye="ciao"))OR com variável:newdf<-rbind(df, data.frame(hello=var1, goodbye=var2))
Parfait
108

Vamos simplificar:

df[nrow(df) + 1,] = c("v1","v2")
Matheus Araujo
fonte
9
Isso causa problemas ao tentar adicionar uma nova linha com tipos de dados mistos (algumas cadeias de caracteres, outras numéricas). Nesse caso, mesmo os valores numéricos são convertidos em sequência. Uma solução alternativa é adicionar os valores separadamente, algo como o seguinte (supondo que existam 3 colunas): df[nrow(df) + 1, 1:2] = c("v1", "v2")e df[nrow(df), 3] = 100Mas ainda assim, é um bom argumento sobre a adição de nova linha. Então, +1
The Student Soul
17
Ou use "lista" em vez de "c".
Ytsen de Boer
boa ideia, mas como posso fazer se quiser inserir ou adicionar uma nova linha na primeira posição?
Darwin PC
1
Tentei isso com data.table, mas diz com nrow + 1 está fora do intervalo.
Herman Toothrot
1
@Arani já existe uma resposta list(). Eu reverti sua edição.
M--
41

Ou, como inspirado em @MatheusAraujo:

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

Isso permitiria tipos de dados mistos.

Ytsen de Boer
fonte
24

Há agora add_row()a partir do tibbleou tidyversepacotes.

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

Colunas não especificadas recebem um NA.

Joe
fonte
Eu gostei dessa abordagem se você seguir a filosofia arrumada. Caso contrário, a sintaxe básica do R é uma habilidade de sobrevivência que é útil quando você está em um ambiente em que não tem privilégios para importar pacotes. Eu particularmente gosto da resposta usando a sintaxe R simples com rbinde as.matrix abaixo
Pablo Adames 21/03
17

Eu gosto, em listvez de, cporque ele lida melhor com tipos de dados mistos. Adicionando uma coluna adicional à pergunta do 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)

Observe que é necessário algum controle adicional se a conversão de string / fator for importante.

Ou usando as variáveis ​​originais com a solução de MatheusAraujo / Ytsen de Boer:

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

Observe que esta solução não funciona bem com as cadeias, a menos que haja dados existentes no quadro de dados.

gsk9
fonte
Se helloe goodbyeestiver no caractere df, você pode fazer o seguinte. Você não necessariamente usa nomes em uma lista. df <- data.frame(hello = "hi", goodbye = "bye", volume = 1,stringsAsFactors = FALSE); rbind(df, list("hola", "ciao", 100)).
jazzurro
11

Não muito elegante, mas:

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

Na documentação da rbindfunção:

Para rbindnomes de colunas são retirados do primeiro argumento com nomes apropriados: colnames para uma matriz ...

J. Win.
fonte
Esta solução funciona sem a necessidade de especificar as colunas a serem adicionadas, o que é muito melhor para aplicativos em grandes conjuntos de dados
Phil_T
1

Eu preciso adicionar stringsAsFactors=FALSEao criar o quadro de dados.

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

Certifique-se de especificar stringsAsFactors=FALSEao criar o quadro de dados:

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

Deixar de usar stringsAsFactors=FALSEao criar o quadro de dados resultará no seguinte erro ao tentar adicionar a nova linha:

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

Existe uma maneira mais simples de acrescentar um registro de um quadro de dados para outro, se você souber que os dois quadros de dados compartilham as mesmas colunas e tipos. Para acrescentar uma linha xxda yyapenas fazer o seguinte, onde ié o i'th linha na xx.

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

Simples assim. Sem vínculos confusos. Se você precisar anexar tudo xxa yy, chame um loop ou aproveite as habilidades de sequência de R e faça o seguinte:

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

Se você deseja criar um quadro de dados vazio e adicionar conteúdo em um loop, o seguinte pode ajudar:

# 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 que ajude :)

Edwin Pratt
fonte