Fernanda,
Seu problema não é nada simples de resolver! Na verdade, ele é tão capcioso que eu achei a solução com purrr muito mais difícil de implementar e explicar do que a versão sem purrr.
Para entender a minha resposta, vamos começar repensando a sua pergunta. Quando você dá todos esses exemplos, qual é a regra subjacente? Ou seja, eu quero saber qual é o algoritmo que te levou a criar esses 6 cenários. Exemplos são ótimos para seres humanos, mas infelizmente os computadores só trabalham com procedimentos bem definidos.
O conjunto de regras que eu abstraí dos seus cenários foi o seguinte:
- Encontramos o primeiro
NA
da linha e o substituímos pela média entre o primeiro valor válido à esquerda e o primeiro valor válido à direita.
- Se não houver nenhum valor válido de um dos dois lados (por exemplo, se o
NA
em questão for o primeiro ou o último valor da linha), pegamos dois valores válidos do mesmo lado.
- Resolvido o primeiro
NA
da linha, repetimos os passos 1. e 2. para qualquer outro NA
subsequente.
Pode ser que eu tenha entendido errado, aí é só você me falar que eu tento reescrever o código. Mas, se for isso mesmo, podemos criar um código que nem dependa do número ou posição de NA
s! Na verdade, até o número de colunas não importa muito.
Minha sugestão de resposta faz um loop nas linhas da base e aplica um algoritmo baseado nos pontos acima. Ele pega o primeiro NA
da linha, encontra o primeiro não-NA
à esquerda e o primeiro à direita; se não tiver nada válido à esquerda, ele pega um segundo não-NA
à direita e vice-versa. Encontrados dois não-NA
s, tiramos a média e fazemos a substituição desejada. O procedimento é repetido até que não haja mais nenhum NA
na linha.
library(magrittr, include.only = "%>%")
banco_teste <- tibble::tribble(
~id, ~pixel1, ~pixel2, ~pixel3, ~pixel4,
1L, 0.25, 0.78, 0.82, NA,
2L, NA, 0.52, 0.43, 0.23,
3L, 0.68, 0.58, 0.63, NA,
4L, 0.68, 0.58, NA, 0.45,
5L, 0.68, 0.58, 0.63, 0.45,
6L, 0.68, NA, 0.63, 0.45,
7L, 0.25, 0.78, NA, NA,
8L, 0.25, NA, 0.82, NA,
9L, 0.68, NA, 0.63, 0.45,
10L, 0.65, 0.53, NA, 0.23,
11L, 0.25, NA, NA, 0.10
)
# Número de pixels na base
n_pix <- ncol(banco_teste) - 1
# Um loop nas linhas da base
for (id in seq_len(nrow(banco_teste))) {
# A linha da vez (sem a coluna `id`)
linha <- banco_teste[id, -1]
# Posição do primeiro NA
pos_na <- which(is.na(linha))[1]
# Enquanto tiver pelo menos um NA na linha
while (!is.na(pos_na)) {
# Nossos buscadores da esquerda e direita
i <- -1
j <- +1
# Diminuir i até que ele ache um não-NA (ou caia para fora da linha)
while (pos_na + i > 0 && is.na(linha[pos_na + i])) {
i <- i - 1
}
# Aumentar j até que ele ache um não-NA (ou caia para fora da linha)
while (pos_na + j <= n_pix && is.na(linha[pos_na + j])) {
j <- j + 1
}
# Se i tiver caido para fora do vetor, pegar um segundo valor à direita
if (pos_na + i == 0) {
i <- j + 1
}
# Se j tiver caido para fora do vetor, pegar um segundo valor à esquerda
if (pos_na + j == n_pix + 1) {
j <- i - 1
}
# Substituir o NA pela média dos dois valores encontrados
linha[pos_na] <- mean(c(linha[[pos_na + i]], linha[[pos_na + j]]))
# Se tiver mais um NA na linha, vamos passar para ele
pos_na <- which(is.na(linha))[1]
}
# Colocar a linha de volta na base (sem os NAs)
banco_teste[id, -1] <- linha
}
banco_teste
#> # A tibble: 11 × 5
#> id pixel1 pixel2 pixel3 pixel4
#> <int> <dbl> <dbl> <dbl> <dbl>
#> 1 1 0.25 0.78 0.82 0.8
#> 2 2 0.475 0.52 0.43 0.23
#> 3 3 0.68 0.58 0.63 0.605
#> 4 4 0.68 0.58 0.515 0.45
#> 5 5 0.68 0.58 0.63 0.45
#> 6 6 0.68 0.655 0.63 0.45
#> 7 7 0.25 0.78 0.515 0.648
#> 8 8 0.25 0.535 0.82 0.678
#> 9 9 0.68 0.655 0.63 0.45
#> 10 10 0.65 0.53 0.38 0.23
#> 11 11 0.25 0.175 0.138 0.1
Created on 2022-05-11 by the reprex package (v2.0.1)
Espero que o código não tenha ficado muito complicado Foi a melhor forma que eu encontrei de resolver o problema. Se der algum problema com a base real, manda aqui para eu tentar ajustar.