NA Significa "Desconhecido" - e Ele Se Espalha
Conjuntos de dados reais têm buracos: a pergunta da pesquisa deixada em branco, o sensor que perdeu uma leitura. O R representa cada buraco com NA - not available. O modelo mental crucial: NA não é zero, não é string vazia, não é um número especial. Significa "existe um valor aqui, mas não sabemos qual é."
Leve isso a sério e o comportamento do R fica lógico. Quanto é um número desconhecido mais um? Desconhecido. Qual é a média de 4, 8 e algo desconhecido? Desconhecida - o valor ausente pode ser qualquer coisa, então a média pode ser qualquer coisa:
Os três imprimem NA. Esse contágio é um recurso, não um bug: o R se recusa a fingir silenciosamente que sabe uma resposta que não sabe. Uma planilha que ignora células em branco silenciosamente pode esconder o fato de que metade de uma coluna está faltando; o R faz você notar e decidir o que os valores ausentes devem significar para a sua análise. O resto deste artigo é sobre tomar essa decisão deliberadamente.
Testando por NA: is.na(), Nunca ==
Aqui está a primeira armadilha em que todo mundo cai. Você quer encontrar os valores ausentes, então escreve uma comparação - e ela não funciona:
x == NA retorna NA NA NA - nem um único TRUE. Por quê? Siga a lógica do "desconhecido": 4 é igual a algum valor desconhecido? Não dá para dizer - o desconhecido pode ser 4. Até a posição NA compara como NA: um desconhecido é igual a outro? Desconhecido. A comparação com NA nunca pode retornar TRUE ou FALSE, então como teste ela é inútil - e pior, uma máscara toda de NA dentro de [ ] não seleciona o que você espera.
A ferramenta correta é is.na(), construída para responder exatamente essa pergunta e que retorna lógicos honestos: FALSE TRUE FALSE. A partir daí, dois idiomas que você vai usar o tempo todo:
sum(is.na(x)) conta os valores ausentes (TRUE soma como 1) - rode isso em cada coluna de um conjunto de dados novo antes de qualquer outra coisa. which(is.na(x)) os localiza. E x[!is.na(x)] mantém apenas os valores observados - remoção manual via máscara lógica, o mesmo padrão de filtragem de vetores de sempre.
Ignorando NA em Resumos: na.rm = TRUE
Você normalmente não precisa remover NAs à mão, porque as funções de resumo do R têm uma saída de emergência embutida - o argumento na.rm (NA remove):
Com na.rm = TRUE, a função descarta os valores ausentes e calcula sobre o que restou: a média de 4 e 8 é 6. sum(), sd(), median(), min(), max(), var() - toda a família de estatística descritiva o aceita.
Repare que o padrão é FALSE. É o R sendo opinativo a seu favor: ele quer que ignorar dados ausentes seja uma escolha explícita que você escreve, não um padrão silencioso. Quando você digita na.rm = TRUE, está afirmando "os valores ausentes podem ser ignorados com segurança aqui" - o que é verdade quando um sensor perdeu algumas leituras aleatoriamente, e perigosamente falso quando, digamos, quem ganha menos pulou a pergunta sobre renda. O argumento faz você assumir essa decisão.
Descartando Linhas Incompletas: na.omit() e complete.cases()
Em um data frame, a ausência mora em células, mas a análise costuma trabalhar linha por linha - então a operação comum é descartar linhas que tenham qualquer NA:
na.omit(df) retorna o data frame menos toda linha contendo ao menos um NA - aqui, só Rosa sobrevive. complete.cases(df) retorna a máscara lógica de linhas (TRUE FALSE FALSE) por trás da mesma ideia, e indexar com ela dá resultados idênticos com duas vantagens: você pode contar antes o que está prestes a perder (sum(!complete.cases(df))) e pode restringir quais colunas importam - df[complete.cases(df[, "age"]), ] descarta apenas as linhas sem age, mantendo Mia mesmo com a nota desconhecida.
Essa forma restrita a colunas importa mais do que parece: na.omit() em um data frame largo pode descartar silenciosamente a maior parte das suas linhas por causa de NAs em colunas que você nunca planejou analisar. Saiba quantas linhas está descartando, e por quê, antes de descartá-las.
Substituindo NA
Às vezes o movimento certo é preencher os buracos em vez de apagar linhas. O idioma combina is.na() com atribuição:
Leia como: "nas posições em que visits está ausente, coloque 0." Isso é legítimo exatamente quando NA codifica um valor conhecido - um cliente sem registro de visitas genuinamente teve zero visitas.
Mas seja honesto sobre quando isso é verdade. Se NA significa "falhamos em medir", substituir por 0 fabrica dados: trocar notas de prova ausentes por 0 puxa a média para baixo como se aqueles alunos tivessem tirado zero, quando na verdade você não sabe quanto tiraram. Compare a média acima (2.4) com a média com na.rm do original (4): mesmos dados, afirmações diferentes. Substituir pela média ou mediana distorce menos, mas ainda subestima a variabilidade. A regra: impute um valor apenas quando você conseguir dizer, em palavras simples, por que aquele valor é o que a entrada ausente realmente era. Caso contrário, mantenha o NA e use na.rm - "desconhecido" é muitas vezes o valor mais verdadeiro do conjunto de dados.
NA vs NULL vs NaN vs Inf
O R tem quatro valores especiais parecidos que significam coisas genuinamente diferentes:
| Valor | Significado | Comprimento | Origem típica |
|---|---|---|---|
NA | Um valor existe mas é desconhecido | 1 (ocupa uma posição) | Dado ausente |
NULL | Nenhum objeto | 0 (sem posição) | Elemento de lista apagado, resultado vazio |
NaN | Conta com resposta indefinida | 1 | 0 / 0, log(-1) |
Inf | Número além do representável | 1 | 1 / 0, overflow |
As distinções que importam na prática: NULL desaparece dentro de vetores (c(1, NULL, 3) tem dois elementos - ele não consegue representar uma observação ausente), enquanto NA mantém seu lugar. NaN conta como ausente (is.na(NaN) é TRUE, então na.rm também o remove), mas o inverso é falso - is.nan(NA) é FALSE. E Inf não é ausente - é um número real e comparável (Inf > 1e300 é TRUE), então na.rm não vai removê-lo; use is.finite() para filtrar até os números comuns.
Para completar: NA vem discretamente em variantes tipadas (NA_integer_, NA_real_, NA_character_) para poder ficar em qualquer vetor sem quebrar a regra do tipo único. Você raramente vai digitá-las, mas vai vê-las em código de pacotes e em mensagens de erro do dplyr.
O Que Você Leva Daqui
NAsignifica "desconhecido", e desconhecidos são contagiosos: qualquer cálculo que toque NA retorna NA - por design.- Teste com
is.na(), nunca== NA; conte os buracos comsum(is.na(x)). na.rm = TRUEfaz funções de resumo ignorarem NAs - uma decisão explícita, por chamada, de que os valores ausentes são ignoráveis.na.omit()descarta linhas incompletas em bloco;complete.cases()te dá a máscara, contável e restringível às colunas que importam.- Substitua NA (
x[is.na(x)] <- valor) apenas quando você puder justificar o que o valor ausente realmente era. - NA ≠ NULL ≠ NaN ≠ Inf: valor ausente, objeto inexistente, matemática indefinida, número ilimitado.
A seguir: funções - empacotando sua lógica em pedaços nomeados e reutilizáveis.
Perguntas frequentes
Por que mean() retorna NA no R?
Porque pelo menos um valor do vetor é NA, e NA é contagioso: se qualquer entrada é desconhecida, o R diz que a resposta também é desconhecida. Passe na.rm = TRUE - mean(x, na.rm = TRUE) - para calcular a média dos valores presentes. A maioria das funções de resumo (sum, sd, median, min, max) aceita o mesmo argumento.
Como checar por NA no R?
Com is.na(x), que retorna TRUE onde houver um valor ausente. Nunca teste com x == NA - comparar qualquer coisa com um desconhecido resulta em NA, não TRUE ou FALSE, então o teste falha silenciosamente. sum(is.na(x)) conta os valores ausentes; which(is.na(x)) encontra suas posições.
Como remover linhas com NA de um data frame no R?
na.omit(df) descarta toda linha que contenha ao menos um NA. Para mais controle, complete.cases(df) retorna um vetor lógico marcando as linhas totalmente observadas, então df[complete.cases(df), ] faz a mesma coisa de forma explícita - e você pode aplicá-lo só às colunas que importam, por exemplo df[complete.cases(df[, c("age", "score")]), ].
Qual é a diferença entre NA e NULL no R?
NA é um valor ausente - ele ocupa uma posição em um vetor e tem comprimento 1. NULL é a ausência de um objeto - tem comprimento 0 e desaparece quando colocado em um vetor: c(1, NULL, 3) tem apenas dois elementos. Use NA para um dado ausente; NULL aparece ao remover elementos de listas ou como um retorno vazio.