Por que a complexidade de tempo desse loop não é linear?

Por que a complexidade de tempo desse loop não é linear e por que é tão lenta? O loop leva~38s for N=50k, e~570s for N=200k. Existe uma maneira mais rápida de fazer isso?Rprof() parece indicar que a gravação na memória é muito lenta.

df <- data.frame(replicate(5, runif(200000)))
df[,1:3] <- round(df[,1:3])

Rprof(line.profiling = TRUE); timer <- proc.time()
x <- df; N <- nrow(df); i <- 1 
ind <- df[1:(N-1),1:3] == df[2:N,1:3]; 
rind <- which(apply(ind,1,all))
N <- length(rind)
while(i <= N)
{
    x$X4[rind[i]+1] <- x$X4[rind[i]+1] + x$X4[rind[i]]
    x$X5[rind[i]+1] <- x$X4[rind[i]+1] * x$X3[rind[i]+1]
    x$X5[rind[i]+1] <- trunc(x$X5[rind[i]+1]*10^8)/10^8
    x$X1[rind[i]] <- NA
    i <- i + 1
};x <- na.omit(x)
proc.time() - timer; Rprof(NULL)
summaryRprof(lines = "show")

O objetivo deste algoritmo é iterar sobre o quadro de dados e combinar linhas adjacentes que correspondem a determinados elementos. Ou seja, ele remove uma das linhas e adiciona alguns dos valores dessa linha à outra linha. O quadro de dados resultante deve ter n menos linhas, em que n é o número de linhas adjacentes correspondentes no quadro de dados original. Sempre que um par de linhas é combinado, o índice do quadro de dados de origem e o novo quadro de dados ficam fora de sincronia em 1, uma vez que uma linha é removida / omitida do novo quadro, portantoi controla a posição no quadro de dados de origem eq controla a posição no novo quadro de dados.

O código acima é atualizado graças ao comentário de @ joran. O desempenho é substancialmente aprimorado para~5.5s for N=50k e~88s for N=200k. No entanto, a complexidade do tempo ainda não é linear, o que não consigo entender. Eu preciso rodar isso em N = 1 milhão ou mais, então ainda não é uma grande velocidade.

questionAnswers(2)

yourAnswerToTheQuestion