091
[R] 데이터 전처리 본문
1. 결측값과 특이값
- 결측값이란 데이터를 수집하고 저장하는 과정에서 저장할 값을 얻지 못하는 경우에 발생하는 값으로, R에서는 NA(Not Available)로 표현합니다. 결측값을 제거, 제외하거나 적당한 값으로 치환하는 방식으로 데이터를 전처리합니다.
z <- c(1,2,3,NA,5,NA,8)
sum(z) #[1] NA
is.na(z) #[1] FALSE FALSE FALSE TRUE FALSE TRUE FALSE
z[is.na(z)] <- 0
sum(z) #[1] 19
z2 <- c(5,8,1,NA,3,NA,7)
sum(is.na(z2)) #[1] 2(NA의 개수)
-> 결측값이 있는 상태로, 백터의 연산을 시도하면 NA가 출력됩니다. NA를 0으로 치환하여 준 뒤에 다시 합을 해줘야 원하는 값을 받을 수 있습니다.
-> 결측값을 찾을 때는 is.na() 함수를 통해 개수를 해당 백터의 요소가 NA인지에 대한 참/거짓을 출력하고 이를 sum() 함수를 통해 개수를 받을 수 있습니다.
x <- c(1,2,3)
y <- c(4,5,6)
y[3] <- NA
xy1 <- data.frame(x,y)
xy1
# x y
# 1 1 4
# 2 2 5
# 3 3 NA
col_na <- function(y) {
return(sum(is.na(y)))
}
na_count <- apply(xy1,1,FUN=col_na)
na_count #[1] 0 0 1
-> 직접 만든 함수인 NA의 개수를 반환하는 함수인 col_na를 사용하여 na_count의 개수를 반환하는 로직으로 apply의 방향이 1이기 때문에 같은 행 중에서 NA의 개수를 반환합니다.(3번째 행에 NA가 있으니까 3번째 요소에서만 1이 반환됩니다.)
name <- c("Alice","Bob",NA,"Diana","Eve")
score <- c(85,NA,90,NA,78)
grade <- c("A","B","A",NA,"C")
student_df <- data.frame(name,score,grade)
student_df
# name score grade
# 1 Alice 85 A
# 2 Bob NA B
# 3 <NA> 90 A
# 4 Diana 11 <NA>
# 5 Eve 78 C
check_na <- function(z){
return(which(is.na(z)))
}
na_pos <- apply(student_df,2,FUN=check_na)
na_pos
# $name
# [1] 3
#
# $score
# [1] 2 4
#
# $grade
# [1] 4
# name score grade
# 3 2 4
-> 각 열마다 NA의 개수가 다르다면 apply는 결과물들의 길이가 달라서 맞춰 출력할 수 없기 때문에 list로 반환합니다. 만약 score의 NA를 숫자로 치환하여 재출력을 해보면 다시 벡터처럼 출력됩니다.
head(xy1)
# x y
# 1 1 4
# 2 2 5
# 3 3 NA
xy1[!complete.cases(xy1),]
# x y
# 3 3 NA
y_c <- xy1[complete.cases(xy1),]
y_c
# x y
# 1 1 4
# 2 2 5
-> complete.cases()는 NA를 행 단위로 검사하는 함수입니다. is.na()와의 가장 큰 차이는 아래처럼 행 단위/셀 단위입니다.
complete.cases(xy1) #[1] TRUE TRUE FALSE
is.na(xy1)
# x y
# [1,] FALSE FALSE
# [2,] FALSE FALSE
# [3,] FALSE TRUE
- 특이값은 정상적이라고 생각되는 데이터 분포 범위 밖에 위치한 값들로, 이상치라고도 합니다.
region_data <- data.frame(
Region=c("A","B","C","D","E"),
Area=c(120,350,200,180,1500),
Population=c(80,120,75,95,300)
)
region_data
# Region Area Population
# 1 A 120 80
# 2 B 350 120
# 3 C 200 75
# 4 D 180 95
# 5 E 1500 300
boxplot(region_data$Area)
boxplot.stats(region_data$Area)$out #[1] 1500
out.val <- boxplot.stats(region_data$Area)$out
region_data$Area[region_data$Area %in% out.val] <- NA
head(region_data)
# Region Area Population
# 1 A 120 80
# 2 B 350 120
# 3 C 200 75
# 4 D 180 95
# 5 E NA 300
newdata <- region_data$Area[!is.na(region_data$Area)]
head(newdata) #[1] 120 350 200 180
-> 이상치를 구하여 NA 값으로 변환 후 newdata에다가 NA가 아닌 값만 담아주는 코드로 이상치를 제거해주는 로직입니다.
-> boxplot.stats에는 아래처럼 $stats, $n, $conf, $out 4가지 결과값이 있습니다. 위에서 접근한대로 $out에 접근하면 이상치값이며, 나머지 세개는 순서대로 각각 핵심지점(아래쪽 수염의 끝, Q1, Q2, Q3, 위쪽 수염의 끝), 데이터의 총 개수, 신뢰구간을 나타냅니다.
-> %in%는 포함 여부 확인용 연산자로, region_data$Area가 out.val에 포함된 값을 찾아내는 함수입니다. ==는 단 하나의 값을 비교할 때만 사용하기 때문에 여러 개의 후보 중 해당되는지를 볼 때는 %in%을 사용해야합니다.
boxplot.stats(region_data$Area)
# $stats
# [1] 120 180 200 350 350
#
# $n
# [1] 5
#
# $conf
# [1] 79.87843 320.12157
#
# $out
# [1] 1500
2. 데이터 분리 및 샘플링
- 데이터를 분리할 때는 split()이라는 함수를 사용합니다. split()은 데이터를 그룹별로 쪼개어 리스트 형태로 반환합니다.
student_data <- data.frame(
Name = c("Alex","Brian","Cindy","David","Emma","Frank"),
Gender = c("M","M","F","M","F","M"),
Score = c(85,92,78,64,91,75)
)
student_data
# Name Gender Score
# 1 Alex M 85
# 2 Brian M 92
# 3 Cindy F 78
# 4 David M 64
# 5 Emma F 91
# 6 Frank M 75
sp <- split(student_data,student_data$Gender)#Gender를 기준으로 쪼개기
sp
# $F
# Name Gender Score
# 3 Cindy F 78
# 5 Emma F 91
#
# $M
# Name Gender Score
# 1 Alex M 85
# 2 Brian M 92
# 4 David M 64
# 6 Frank M 75
head(sp$F)
# Name Gender Score
# 3 Cindy F 78
# 5 Emma F 91
head(sp$M)
# Name Gender Score
# 1 Alex M 85
# 2 Brian M 92
# 4 David M 64
# 6 Frank M 75
-> 리스트로 반환하기 때문에 아래처럼 클래스가 반환합니다.
x <- data.frame(tel=c('02','031','032','031'),local1=c(3,3,3,4))
x
sp <- split(x,x$tel)
sp$`031`
-> 리스트의 이름은 변수처럼 이용됩니다. 이때 변수는 숫자로 시작할 수가 없기 때문에 백틱으로 감싸서 사용합니다.
class(sp) #[1] "list"
class(sp$M) #[1] "data.frame"
- 샘플링한다는 것은 주어진 값들이 있을 때, 그 중에서 임의의 개수의 값들을 추출하는 작업을 말합니다. sample()함수를 통해 원하는 샘플 추출할 수 있습니다. replace가 TRUE일 때는 중복값을 허용하는 것입니다. 그러기 때문에 size가 자유로울 수 있지만, replace=FALSE인 경우에는 size가 주어진 값보다 같거나 작아야합니다.
x <- c(1:100)
y <- sample(x,size=10,replace=F)
y #[1] 28 1 19 20 5 58 77 8 29 66
sample(1:20,size=5,replace=F) #[1] 8 4 9 11 6
sample(1:20,size=5,replace=T) #[1] 4 16 6 8 10
sample(1:20,size=5,replace=T) #[1] 10 16 16 12 13
3. 데이터 집계와 병합
- 2차원 데이터는 데이터 그룹에 대해서 합계나 평균을 계산해야하는 일이 많고 이와 같은 작업을 집계라고 합니다. aggregate() 함수를 통해 구현합니다.
aggregate(계산할값 ~ 기준값, data = 데이터셋, FUN = 함수)
simple_data <- data.frame(
Group = c("A","A","B","B"),
Val1 = c(5,7,10,14)
)
simple_data
# Group Val1
# 1 A 5
# 2 A 7
# 3 B 10
# 4 B 14
agg <- aggregate(Val1 ~ Group, data=simple_data, FUN=sd)
agg
# Group Val1
# 1 A 1.414214
# 2 B 2.828427
-> sd()함수를 넣어 표준편차를 구해줍니다.
- 병합이란 분리된 데이터 파일을 공동 열을 기준으로 하나로 합치는 작업을 말합니다. merge() 함수를 통해 구현합니다.
x <- data.frame(name=c("a","b","c"),math=c(90,80,40))
y <- data.frame(name=c("a","b","d"),korean=c(75,60,90))
x
# name math
# 1 a 90
# 2 b 80
# 3 c 40
y
# name korean
# 1 a 75
# 2 b 60
# 3 d 90
z <- merge(x,y,by=c("name"))
z
# name math korean
# 1 a 90 75
# 2 b 80 60
-> merge() 함수는 기본적으로 inner join이기 때문에, 양쪽 표에 모두 존재하는 이름만 합쳐서 c,d에 대한 값은 소실됩니다.
'Programming Language > R' 카테고리의 다른 글
| [R] 머신러닝(1): 연관규칙분석-아프리오리 알고리즘 (0) | 2026.05.23 |
|---|---|
| [R] 데이터 시각화(treemap, ggplot2) (0) | 2026.04.26 |
| [R] 단일&다중변수자료의 탐색 (0) | 2026.04.25 |
| [R] 기초문법(조건문, 반복문, 함수) (0) | 2026.04.06 |
| [R] 파일 데이터 읽기/쓰기 (0) | 2026.04.06 |
