데이콘(생육 환경 최적화 경진대회) : Outlier2
최종결과 : 다른 청경채 샘플 같은 잎 넓이(무게)
무게 변화를 통한 이상치 탐색
#### 1. 분석 준비 ####
pacman::p_load(magick, tidyverse) # 데이터 전처리 관련 패키지
#### 2. 기본 데이터 로딩 ####
train_labels <- list.files(path="label", full.names = TRUE) %>%
lapply(read_csv, show_col_types = F) %>% bind_rows()
#### 3. 이상치 점검 ####
#### 나. 이미지 점검 ####
images1 <- function(case="CASE45", num=c("15", "16", "17")){
ggsave(filename = "data/temp.png", # 임시로 그래프를 이미지로 저장
train_labels %>%
mutate(num=as.integer(str_sub(img_name, 8, 9))) %>%
filter(grepl(case, img_name)) %>%
ggplot(aes(num, leaf_weight)) +
geom_line(size=0.4) + theme_bw()+
theme(text = element_text(size=3.5),
plot.margin = margin(0, 0, 0.1, 0.1, "cm"),
# top, right, bottom, left (사진과의 적당한 여백 유지)
panel.border = element_rect(size = 0.3),
panel.grid = element_line(size=0.2),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.ticks = element_line(size = 0.2),
axis.ticks.length = unit(.03, "cm")) +
labs(x=""),
width = 200, height = 150, dpi = 300, units = "px", device='png')
img1_name <- train_labels %>% mutate(img_name=paste0("train/", img_name)) %>%
filter(grepl(paste0(case, "_", num[1]), img_name))
img1 <- image_read(img1_name$img_name) %>% image_scale(200) %>%
image_annotate(paste0(str_sub(img1_name, 7, -1), ", ", round(img1_name$leaf_weight)),
size=12, color="blue", boxcolor="white", location="+40+135")
img2 <- image_read("data/temp.png")
img12 <- image_append(c(img1, img2))
img3_name <- train_labels %>% mutate(img_name=paste0("train/", img_name)) %>%
filter(grepl(paste0(case, "_", num[2]), img_name))
img3 <- image_read(img3_name$img_name) %>% image_scale(200) %>%
image_annotate(paste0(str_sub(img3_name, 7, -1), ", ", round(img3_name$leaf_weight)),
size=12, color="blue", boxcolor="white", location="+40+135")
img4_name <- train_labels %>% mutate(img_name=paste0("train/", img_name)) %>%
filter(grepl(paste0(case, "_", num[3]), img_name))
img4 <- image_read(img4_name$img_name) %>% image_scale(200) %>%
image_annotate(paste0(str_sub(img4_name, 7, -1), ", ", round(img4_name$leaf_weight)),
size=12, color="blue", boxcolor="white", location="+40+135")
img34 <- image_append(c(img3, img4))
image_append(c(img12, img34), stack=T)
}
images1()
오른쪽 위에 있는 그래프를 보면 16 부분에서 갑자기 무게가 감소한 것을 알 수 있습니다. 사진 밑에 해당 사진의 파일명과 소수 첫째자리에서 반올림한 무게를 표시해 두었습니다. 그래프와 비교하면서 보시면 됩니다. CASE45_06의 경우 24시간 후 무게가 감소한 이유를 다음과 같이 추론할 수 있습니다. CASE45_16은 CASE45_15의 24시간 후 모습입니다. 같은 맥락에서 CASE45_17은 CASE_16의 24시간 후의 모습이죠. 사진에서도 확인할 수 있듯이 CASE45_17을 보면 손이 같이 찍혔습니다. 무게를 측정(?)하는데 오류가 발생해서 CASE45_16의 경우 24시간 후 무게가 감소한 것으로 기록된 것입니다. 많은 분들이 CASE45_17의 경우 손이 찍혀서 자연스럽게 분석에서 제외했을텐데 CASE45_16도 제외하는 것이 타당합니다.
떨어져 나간 잎
images1(case="CASE72", num=c("05","06","07"))
CASE72의 경우도 06에서 무게가 감소한 것으로 나타납니다. 그 이유는 CASE72_06의 24시간 후 모습인 CASE72_07을 보면 일부 잎이 떨어져 나간 것을 확인할 수 있습니다. CASE72_06의 시진을 분석에 활용한다는 것은 이 사진을 보고 24시간 후 무게가 감소할 것을 학습시키는 것과 같습니다.
분무기 오류
images1(case="CASE05", num=c("21","22","23"))
CASE05에서도 21번째의 경우 24시간 후 무게가 감소한 것으로 나타났습니다. 앞 뒤 이미지를 살펴보면 CASE05_21과 CASE05_23은 정상적으로 보이는데 CASE05_22번 사진은 비정상적으로 말라 있는 것을 알 수 있습니다. 아마도 물 분무 기계 장치에 오류가 생겨서 물 분무가 안 된 것 같습니다. 그러다보니 CASE05_21 이미지의 경우 24시간 후 무게가 매우 많이 감소한 것으로 나타난 것입니다. 개인적으로 생각할 때 CASE05_21, 22, 23 모두 문제가 있는 이미지로 판단됩니다.
무게 측정 오류
images1(case="CASE07", num=c("06","07","08"))
CASE07_07과 CASE07_08의 경우 24시간 후 무게가 감소한 것으로 나타났습니다. 하지만 사진장으로 보면 멀쩡하게 잘 자라고 있는 모습을 확인할 수 있습니다. 이는 무게 측정 센서(?) 혹은 나름대로의 방법(?)에 문제가 생겨서 나타난 현상 같습니다. CASE07_07과 08 모두 빼야할 것 같습니다.
사진 비교를 통한 무게 추정
images2 <- function(files=c('train/CASE01_06.png', 'train/CASE04_05.png',
'train/CASE23_03.jpg', 'train/CASE16_03.jpg'),
value=c(123, 130, 123, 130)){
img1 <- image_read(files[1:2]) %>% image_scale(200) %>% image_append() %>%
image_annotate(str_sub(files[1], 7, -1) %>% paste0(", ", value[1]),
size = 12, color = "blue", boxcolor = "white", location = "+40+135") %>%
image_annotate(str_sub(files[2], 7, -1) %>% paste0(", ", value[2]),
size = 12, color = "blue", boxcolor = "white", location = "+240+135")
img2 <- image_read(files[3:4]) %>% image_scale(200) %>% image_append() %>%
image_annotate(str_sub(files[3], 7, -1) %>% paste0(", ", value[3]),
size = 12, color = "blue", boxcolor = "white", location = "+40+135") %>%
image_annotate(str_sub(files[4], 7, -1) %>% paste0(", ", value[4]),
size = 12, color = "blue", boxcolor = "white", location = "+240+135")
image_append(c(img1, img2), stack=T)
}
data <- train_labels %>% filter(leaf_weight>120 & leaf_weight<140) %>%
mutate(img_name=paste0("train/", img_name))
images2(file=c(data$img_name[c(1,2,5,6)]), value=c(round(data$leaf_weight[c(1,2,5,6)])))
잎 무게가 비슷한 데이터들을 선별해서 눈으로 잎 면적을 비교해 보았습니다. 다양한 형태의 잎이 보이는데 대략적으로 수긍이 갑니다.
무게 이상치
images2(file=c(data$img_name[c(10,1,3,4)]), value=c(round(data$leaf_weight[c(10,1,3,4)])))
많은 데이터가 수긍이 가지만 위와 같이 믿을 수 없는 경우도 있습니다. CASE41_20과 CASE16_03이 같다는 사실을 도저히 믿을 수 없습니다. 이 경우도 CASE16_03 무게를 측정할 때 오류가 발생했다고 판단하는 것이 타당합니다. 같은 맥락에서 CASE23_03도 마찬가지입니다. CASE01_06과 비교해보면 얼마나 터무니 없는 무게인지 알 수 있습니다.
위와 같은 사례들은 전체 이상치 중 일부에 해당됩니다. 꼼꼼하게 살펴보면서 이상치를 모두 제거해 주어야 25%의 public 데이터를 넘어 나머지 test 데이터들의 무게를 보다 정확하게 추론할 수 있습니다.
대회가 한참 진행중이었던 5월 6일 9위 달리고 있었으며 5월 7일 CNN 고수분과 팀을 이루면서 서로의 데이터를 합쳐서 5월 8일 현재 6위 중입니다. 100% 다 공개하지는 못해도 꾸준히 분석 과정 공유하고 1등을 향해 최선을 다할 예정입니다. 대회가 끝난 이후에는 성적에 관계없이 최소한 제가 분석한 결과는 모두 공개하도록 하겠습니다. ^^
댓글남기기