Examinei o StackOverflow, mas não consigo encontrar uma solução específica para o meu problema, que envolve anexar linhas a um quadro de dados R.
Estou inicializando um quadro de dados de 2 colunas vazio, da seguinte maneira.
df = data.frame(x = numeric(), y = character())
Então, meu objetivo é percorrer uma lista de valores e, em cada iteração, acrescentar um valor ao final da lista. Comecei com o seguinte código.
for (i in 1:10) {
df$x = rbind(df$x, i)
df$y = rbind(df$y, toString(i))
}
I também tentou as funções c
, append
e merge
sem sucesso. Por favor, deixe-me saber se você tem alguma sugestão.
Respostas:
Atualizar
Sem saber o que você está tentando fazer, compartilharei mais uma sugestão: Pré-aloque vetores do tipo que você deseja para cada coluna, insira valores nesses vetores e, no final, crie seu
data.frame
.Continuando com Julian's
f3
(um pré-alocadodata.frame
) como a opção mais rápida até agora, definida como:Aqui está uma abordagem semelhante, mas em que o
data.frame
é criado como a última etapa.microbenchmark
do pacote "microbenchmark" nos dará uma visão mais abrangente do quesystem.time
:f1()
(a abordagem abaixo) é incrivelmente ineficiente por causa da frequência com que chamadata.frame
e porque o crescimento de objetos dessa maneira geralmente é lento na R.f3()
é muito melhorado devido à pré-localização, mas adata.frame
estrutura em si pode ser parte do gargalo aqui.f4()
tenta contornar esse gargalo sem comprometer a abordagem que você deseja adotar.Resposta original
Isso realmente não é uma boa ideia, mas se você quiser fazer dessa maneira, acho que pode tentar:
Observe que no seu código, há outro problema:
stringsAsFactors
se quiser que os caracteres não sejam convertidos em fatores. Usar:df = data.frame(x = numeric(), y = character(), stringsAsFactors = FALSE)
fonte
data.frame
o tamanho máximo esperado e adicionar os valores com[
extração / substituição.Vamos comparar as três soluções propostas:
A melhor solução é pré-alocar espaço (conforme planejado em R). A próxima melhor solução é usar
list
, e a pior solução (pelo menos com base nesses resultados de tempo) parece serrbind
.fonte
df <- rbind(df, data.frame(x = i, y = toString(i)))
Suponha que você simplesmente não saiba o tamanho do data.frame com antecedência. Pode muito bem ser algumas linhas ou alguns milhões. Você precisa ter algum tipo de recipiente, que cresça dinamicamente. Levando em consideração minha experiência e todas as respostas relacionadas no SO, venho com 4 soluções distintas:
rbindlist
para o data.frameUse
data.table
aset
operação rápida e junte-a à duplicação manual da mesa, quando necessário.Use
RSQLite
e acrescente à tabela mantida na memória.data.frame
própria capacidade de crescer e usar o ambiente personalizado (que tem semântica de referência) para armazenar o data.frame, para que ele não seja copiado no retorno.Aqui está um teste de todos os métodos para o número pequeno e grande de linhas anexadas. Cada método possui 3 funções associadas:
create(first_element)
que retorna o objeto de suporte apropriado com afirst_element
inserção.append(object, element)
que anexaelement
ao final da tabela (representado porobject
).access(object)
obtém odata.frame
com todos os elementos inseridos.rbindlist
para o data.frameIsso é bastante fácil e direto:
data.table::set
+ dobrar manualmente a tabela quando necessário.Vou armazenar o comprimento verdadeiro da tabela em um
rowcount
atributo.O SQL deve ser otimizado para inserção rápida de registros, então eu inicialmente tinha grandes esperanças de
RSQLite
soluçãoIsso é basicamente copiar e colar a resposta de Karsten W. em tópicos semelhantes.
data.frame
próprio ambiente personalizado + com adição de linhas.A suíte de testes:
Por conveniência, usarei uma função de teste para cobrir todas elas com chamadas indiretas. (Eu verifiquei: usar em
do.call
vez de chamar diretamente as funções não torna o código mensurável por mais tempo).Vamos ver o desempenho de n = 10 inserções.
Também adicionei funções 'placebo' (com sufixo
0
) que não realizam nada - apenas para medir a sobrecarga da configuração do teste.Para linhas 1E5 (medições feitas na CPU Intel (R) Core (i) i7-4710HQ a 2,50 GHz):
Parece que a suluição baseada em SQLite, embora recupere alguma velocidade em dados grandes, não chega nem perto de data.table + crescimento exponencial manual. A diferença é quase duas ordens de magnitude!
Resumo
Se você souber que anexará um número bastante pequeno de linhas (n <= 100), vá em frente e use a solução mais simples possível: apenas atribua as linhas ao data.frame usando a notação entre colchetes e ignore o fato de que o data.frame é não pré-preenchido.
Para todo o resto, use
data.table::set
e aumente exponencialmente o data.table (por exemplo, usando meu código).fonte
Atualizar com purrr, tidyr e dplyr
Como a pergunta já está datada (6 anos), as respostas estão faltando uma solução com os pacotes mais recentes tidyr e purrr. Portanto, para as pessoas que trabalham com esses pacotes, quero adicionar uma solução às respostas anteriores - todas bastante interessantes, especialmente.
A maior vantagem do ronronar e do tidyr é a melhor legibilidade do IMHO. O purrr substitui o lapply pela família map () mais flexível, a tidyr oferece o método super intuitivo add_row - apenas faz o que diz :)
Esta solução é curta e intuitiva de ler, e é relativamente rápida:
Ele é dimensionado quase linearmente, portanto, para 1e5 linhas, o desempenho é:
que o colocaria em segundo lugar logo após data.table (se você ignorar o placebo) no benchmark de @Adam Ryczkowski:
fonte
add_row
. Por exemplo:map_dfr(1:1e5, function(x) { tibble(x = x, y = toString(x)) })
.bind_rows(df, map_dfr(1:1e5, function(x) { tibble(x = x, y = toString(x)) }))
vez de usá-loadd_row
.Vamos pegar um vetor 'point' com números de 1 a 5
point = c(1,2,3,4,5)
se quisermos adicionar um número 6 em qualquer lugar dentro do vetor, o comando abaixo pode ser útil
i) Vetores
new_var = append(point, 6 ,after = length(point))
ii) colunas de uma tabela
new_var = append(point, 6 ,after = length(mtcars$mpg))
O comando
append
usa três argumentos:simples...!! Desculpas em caso de qualquer ...!
fonte
Uma solução mais genérica para pode ser a seguinte.
A função extendDf () estende um quadro de dados com n linhas.
Como um exemplo:
fonte
Minha solução é quase a mesma que a resposta original, mas não funcionou para mim.
Então, eu dei nomes para as colunas e funciona:
fonte