dec_latitude, dec_longitude)speed)temperatura)consumo)PONTUACAOEste relatório descreve, de forma objetiva e transparente, a metodologia adotada para o tratamento de valores ausentes (NAs) na base operacional utilizada no projeto de modelagem de bioincrustação em navios.
O foco é demonstrar que:
pontuacao (indicador de fouling de inspeção)
foi preservada, sem imputação direta, e complementada
por um índice físico de fouling.A base original foi fornecida no arquivo df.xlsx, com as
seguintes características principais:
startGMTDate);shipName (ex.:
DANIEL PEREIRA);TRIM,
displacement, speed,
CONSUMO;beaufort,
sea condition, Temperatura;decLatitude,
decLongitude;PONTUACAO (quase
totalmente ausente).A primeira etapa consiste em carregar e padronizar a base:
df_bruto <- read_excel("data/df.xlsx") %>%
clean_names() %>% # padroniza nomes: decLatitude -> dec_latitude
arrange(start_gmt_date) # garante ordenação temporal
glimpse(df_bruto)
## Rows: 3,056
## Columns: 15
## $ session_id <dbl> 3.98e+10, 3.98e+10, 3.98e+10, 3.98e+10, 3.98e+10, 3.98e…
## $ ship_name <chr> "DANIEL PEREIRA", "DANIEL PEREIRA", "DANIEL PEREIRA", "…
## $ class <chr> "Aframax", "Aframax", "Aframax", "Aframax", "Aframax", …
## $ event_name <chr> "NAVEGACAO", "NAVEGACAO", "NAVEGACAO", "NAVEGACAO", "NA…
## $ start_gmt_date <dttm> 2021-05-25 11:00:00, 2021-05-26 11:00:00, 2021-05-27 1…
## $ trim <dbl> 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, …
## $ displacement <dbl> 128703.7, 128703.7, 128703.7, 128703.7, 128703.7, 12870…
## $ beaufort <dbl> 3, 3, 3, 1, 1, 1, 3, 3, 2, 2, 3, 2, NA, NA, NA, NA, 3, …
## $ sea_condition <dbl> 2, 3, 2, 2, 5, 3, 3, 2, 1, 2, 2, 2, NA, NA, NA, NA, 2, …
## $ speed <dbl> 10.58, 11.80, 11.83, 11.72, 11.75, 11.84, 12.00, 11.63,…
## $ dec_latitude <dbl> -30.3800, -28.5568, -27.1400, -25.2800, -23.4545, -22.0…
## $ dec_longitude <dbl> 1.02500e+01, 5.20180e+00, 2.10000e-08, -4.42730e+00, -9…
## $ consumo <dbl> 47, 48, 46, 47, 46, 48, 45, 41, 40, 40, 40, 20, 2, 0, 0…
## $ pontuacao <dbl> 4.8, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ temperatura <dbl> 298.9, 301.6, 307.3, 299.9, 301.6, 302.0, 300.3, 300.1,…
Antes de qualquer tratamento, foi feito um diagnóstico da quantidade e do percentual de NAs em cada coluna.
na_info_inicial <- tibble(
coluna = names(df_bruto),
n_na = sapply(df_bruto, function(x) sum(is.na(x))),
pct_na = round(colMeans(is.na(df_bruto)) * 100, 2)
)
na_info_inicial %>%
arrange(desc(pct_na))
## # A tibble: 15 × 3
## coluna n_na pct_na
## <chr> <int> <dbl>
## 1 pontuacao 3053 99.9
## 2 temperatura 1396 45.7
## 3 dec_latitude 884 28.9
## 4 dec_longitude 884 28.9
## 5 displacement 854 28.0
## 6 beaufort 854 28.0
## 7 sea_condition 854 28.0
## 8 trim 853 27.9
## 9 speed 837 27.4
## 10 session_id 0 0
## 11 ship_name 0 0
## 12 class 0 0
## 13 event_name 0 0
## 14 start_gmt_date 0 0
## 15 consumo 0 0
Os principais pontos observados foram:
PONTUACAO: ~99,9% de NAs (praticamente toda a
coluna);temperatura: ~45% de NAs;dec_latitude e dec_longitude: ~29% de
NAs;displacement, beaufort, trim,
sea_condition: ~28% de NAs;speed: ~27% de NAs;CONSUMO, datas e identificação do navio: sem
NAs.Dado esse cenário, decidiu-se por um tratamento variável a variável, levando em conta a natureza física de cada campo.
A estratégia adotada combinou:
pontuacao sem
imputação direta, devido à baixa cobertura e natureza subjetiva.Além disso, foi construído um índice físico de
fouling, utilizado como base para uma
pontuacao_estimada.
dec_latitude,
dec_longitude)Justificativa: falhas de GPS são comuns, mas o movimento do navio é contínuo. É fisicamente coerente interpolar a posição entre dois pontos conhecidos.
Passos:
na.approx);na.locf).df <- df_bruto %>%
mutate(
dec_latitude = as.numeric(dec_latitude),
dec_longitude = as.numeric(dec_longitude)
)
df$dec_latitude <- na.approx(df$dec_latitude, na.rm = FALSE)
df$dec_longitude <- na.approx(df$dec_longitude, na.rm = FALSE)
df$dec_latitude <- na.locf(df$dec_latitude, na.rm = FALSE)
df$dec_latitude <- na.locf(df$dec_latitude, fromLast = TRUE)
df$dec_longitude <- na.locf(df$dec_longitude, na.rm = FALSE)
df$dec_longitude <- na.locf(df$dec_longitude, fromLast = TRUE)
Justificativa: essas variáveis apresentam variação relativamente suave:
trim e displacement mudam com o
carregamento, mas não de forma caótica;beaufort e sea_condition refletem
condições de mar e vento, que evoluem gradualmente.Abordagem:
sea_condition, uso de beaufort
como proxy quando disponível.df <- df %>%
mutate(
trim = as.numeric(trim),
displacement = as.numeric(displacement),
beaufort = as.numeric(beaufort),
sea_condition = as.numeric(sea_condition)
)
# TRIM
df$trim <- na.approx(df$trim, na.rm = FALSE)
df$trim[is.na(df$trim)] <- median(df$trim, na.rm = TRUE)
# DISPLACEMENT por navio
df <- df %>%
group_by(ship_name) %>%
arrange(start_gmt_date, .by_group = TRUE) %>%
mutate(displacement = na.approx(displacement, na.rm = FALSE)) %>%
mutate(displacement = ifelse(is.na(displacement),
median(displacement, na.rm = TRUE),
displacement)) %>%
ungroup()
# BEAUFORT
df$beaufort <- na.approx(df$beaufort, na.rm = FALSE)
df$beaufort[is.na(df$beaufort)] <- median(df$beaufort, na.rm = TRUE)
# SEA_CONDITION
df$sea_condition <- na.approx(df$sea_condition, na.rm = FALSE)
idx_sc_na <- is.na(df$sea_condition) & !is.na(df$beaufort)
df$sea_condition[idx_sc_na] <- df$beaufort[idx_sc_na]
df$sea_condition[is.na(df$sea_condition)] <- median(df$sea_condition, na.rm = TRUE)
df$sea_condition <- round(df$sea_condition)
speed)Justificativa operacional:
Regra aplicada:
lat/lon iguais ao registro
anterior) → speed = 0;consumo == 0 → speed = 0;df <- df %>%
mutate(
speed = as.numeric(speed),
pos_igual = lag(dec_latitude) == dec_latitude &
lag(dec_longitude) == dec_longitude
) %>%
mutate(
speed = case_when(
!is.na(speed) ~ speed,
pos_igual == TRUE ~ 0,
consumo == 0 ~ 0,
TRUE ~ NA_real_
)
)
df$speed <- na.approx(df$speed, na.rm = FALSE)
df$speed[is.na(df$speed)] <- median(df$speed, na.rm = TRUE)
temperatura)Justificativa:
Abordagem:
temperatura ~ dec_latitude;df <- df %>%
mutate(temperatura = as.numeric(temperatura))
df$temperatura <- na.approx(df$temperatura, na.rm = FALSE)
mod_temp <- lm(temperatura ~ dec_latitude, data = df)
df$temperatura[is.na(df$temperatura)] <-
predict(mod_temp, df)[is.na(df$temperatura)]
df$temperatura[is.na(df$temperatura)] <- median(df$temperatura, na.rm = TRUE)
consumo)Problema identificado:
consumo = 0 ao mesmo tempo em que
speed > 3 nósSolução:
consumo_erro);consumo ~ speed + displacement + beaufort usando apenas
consumos > 0;df <- df %>%
mutate(consumo = as.numeric(consumo)) %>%
mutate(consumo_erro = ifelse(consumo == 0 & speed > 3, 1, 0))
table(df$consumo_erro)
##
## 0 1
## 1855 1201
mod_c <- lm(consumo ~ speed + displacement + beaufort,
data = df %>% filter(consumo > 0))
df$consumo[df$consumo_erro == 1] <-
predict(mod_c, df[df$consumo_erro == 1, ])
df$consumo[df$consumo < 0] <- 0
PONTUACAOA coluna pontuacao é um indicador de fouling baseado em
inspeção, porém:
Por isso:
pontuacao não foi imputada;pontuacao_original, e a partir das variáveis
físicas foi construída um índice de fouling e uma
pontuacao_estimada.df <- df %>%
mutate(pontuacao_original = pontuacao)
fouling_indexFoi criado um índice físico (fouling_index) a partir
de:
consumo relativo à velocidade
(consumo/speed);speed < 5 nós);df <- df %>%
mutate(
fuel_per_speed = consumo / pmax(speed, 1),
low_speed_flag = ifelse(speed < 5, 1, 0),
temp_norm = rescale(temperatura, to = c(0, 1)),
calm_sea_flag = ifelse(beaufort <= 2, 1, 0),
fouling_index_raw =
fuel_per_speed +
0.7 * low_speed_flag +
0.5 * temp_norm +
0.3 * calm_sea_flag,
fouling_index = rescale(fouling_index_raw, to = c(0, 4))
)
pontuacao_estimadaNos poucos pontos em que pontuacao_original existe:
pontuacao_original ~ fouling_index;pontuacao_estimada em todos os registros;pontuacao_estimada =
fouling_index.dados_ancora <- df %>%
filter(!is.na(pontuacao_original), !is.na(fouling_index))
if (nrow(dados_ancora) >= 2) {
mod_p <- lm(pontuacao_original ~ fouling_index, data = dados_ancora)
df$pontuacao_estimada <- as.numeric(predict(mod_p, newdata = df))
} else if (nrow(dados_ancora) == 1) {
ref_p <- dados_ancora$pontuacao_original[1]
media_fi <- mean(df$fouling_index, na.rm = TRUE)
df$pontuacao_estimada <- df$fouling_index - media_fi + ref_p
} else {
df$pontuacao_estimada <- df$fouling_index
}
df$pontuacao_estimada <- pmax(pmin(df$pontuacao_estimada, 24), 0)
Essa abordagem permite:
pontuacao_original;Após todo o tratamento, foi feita uma nova verificação de NAs.
na_final <- tibble(
coluna = names(df),
n_na = sapply(df, function(x) sum(is.na(x))),
pct_na = round(colMeans(is.na(df)) * 100, 2)
)
na_final %>%
arrange(desc(pct_na))
## # A tibble: 25 × 3
## coluna n_na pct_na
## <chr> <int> <dbl>
## 1 pontuacao 3053 99.9
## 2 pontuacao_original 3053 99.9
## 3 pos_igual 1 0.03
## 4 session_id 0 0
## 5 ship_name 0 0
## 6 class 0 0
## 7 event_name 0 0
## 8 start_gmt_date 0 0
## 9 trim 0 0
## 10 displacement 0 0
## # ℹ 15 more rows
O resultado esperado é:
speed,
trim, displacement, beaufort,
sea_condition, dec_latitude,
dec_longitude, temperatura,
consumo) sem NAs;pontuacao_original permanece com NAs (por escolha
metodológica);pontuacao_estimada e fouling_index
completamente preenchidas.Por fim, a base tratada é salva tanto em RDS quanto em Excel para uso posterior (modelagem, dashboards, relatórios).
saveRDS(df, "data/df_tratado_fouling.rds")
writexl::write_xlsx(df, "data/df_tratado_fouling.xlsx")
O tratamento de NAs foi conduzido de forma:
pontuacao, evitando imputação arbitrária onde não
há base para isso, mas criando um índice físico de fouling e uma
pontuacao_estimada alinhada com os poucos registros de
inspeção disponíveis.Esta base tratada constitui o ponto de partida confiável para as
etapas seguintes de:
modelagem preditiva de bioincrustação, análise de cenários de limpeza e
avaliação do impacto em consumo e emissões.