본문 바로가기
R 과 데이터분석/기초 문법 ~ 머신러닝

[R 데이터분석] 7장. EDA & 데이터 전처리

by JoyfulS 2019. 9. 13.

1.  EDA란?

 - 탐색적 데이터 분석 (Exploratory Data Analysis)

 - 수집 데이터를 다양한 각도에서 관찰하고 이해하는 과정

 - 그래프나 통계적 방법으로 자료를 직관적으로 파악하는 과정

 

2. EDA의 필요성

 - 데이터의 분포와 통계를 파악하여 데이터가 가지고 있는 특성을 이해하고 잠재적인 문제 발견

 - 분석 전에 다양한 문제점을 발견하고, 이를 바탕으로 기존 가설 수정 또는 새로운 가설 수립

 

3. EDA 과정

 - 분석의 목적과 변수 특징 확인 -> 데이터셋 확인 및 전처리 -> 데이터 개별 변수 값 관찰 -> 변수 간의 관계에 초점을 맞춰 변수 패턴 발견

 

-------------------------------------------------------------------------------------------------------------------------

 

# chap07_EDA_Preprocessing

 

# 데이터 전처리

# 1. 데이터 탐색(조회) 

# 2. 결측치(NA) 처리

# 3. 이상치(outlier) 발견과 처리 

# 4. 코딩변경  

# 5. 탐색적 분석을 위한 시각화  

# 6. 파생변수  

 

### 사용된 파일은 https://joyfuls.tistory.com/4 에서 다운 받으실 수 있습니다.

# 1. 데이터 탐색(조회)
setwd("c:/2_Rwork/Part-II")
dataset <- read.csv("dataset.csv", header = T)

# 1) 데이터 조회 
names(dataset) # 변수 확인 
attributes(dataset)
# $names $class $row.names
str(dataset)
# 'data.frame': 300 obs. of  7 variables:
# $variables type

nrow(dataset) # 행 수 반환 
ncol(dataset) # 열 수 반환 
length(dataset) # 열 수 반환 
dim(dataset) # 300   7

# 2) 데이터셋 내용 보기 
dataset
print(dataset)
View(dataset)

head(dataset, 10)
tail(dataset)


# 2. 결측치(NA) 처리 

# 1) 결측치 확인
names(dataset)

summary(dataset$price) # NA's
table(is.na(dataset$price)) # TRUE
# FALSE  TRUE 
#   270    30

table(is.na(dataset)) # 118 
300 * 7 # 2100

# 2) 결측치 처리
# - 제거, 0, 평균, 통계적 방법

# (1) 결측치 제거
dataset2 <- na.omit(dataset) # 전체 변수 대상 
dim(dataset) # 300   7
dim(dataset2) # 209   7
table(is.na(dataset2))

stock <- read.csv(file.choose()) # stock.csv
str(stock)
dim(stock) # 6706   69
# $ Sector # 분야 
# $ Market.Cap : 시가총액 
# $ P.E : 주가수익 
# $ Forward.P.E : 예상주가수익 

library(dplyr)
# 형식) df %>% filter(필터조건) -> 행선택 
stock_df <- stock %>% filter(!is.na(Market.Cap)) # 특정 변수 대상 
dim(stock_df) # 5028   69


# 2) 0, 평균 대체 
x <- dataset$price
x[1:30]

# 0 대체 
dataset$price2 <- ifelse(is.na(x), 0, x)
head(dataset,30)

# 평균 대체 
dataset$price3 <- ifelse(is.na(x), 
                         mean(x, na.rm = T), x)

head(dataset, 30)
dim(dataset) # 300   9

dataset[c("price", "price2", "price3")]


# 3) 통계적 방법 : 고객 유형별 NA 처리 
# type : 1.우수, 2.보통, 3.저조 
# 1. 우수 : mean(8.75)*1.5
# 2. 보통 : mean(8.75)
# 3. 저조 : mean(8.75)*0.5

dim(dataset) # 300   9
type <- rep(1:3, 100)
dataset$type <- type
head(dataset,30)

price4 <- numeric() # 통계적 방법
# 구매금액 평균 
avg <- mean(dataset$price, na.rm = T)

for(i in 1:nrow(dataset)){ # 300회 반복 
  if(is.na(dataset$price[i])){ # NA
    if(dataset$type[i] == 1){ # 1. 우수 
       price4[i] = avg * 1.5
    }else if(dataset$type[i] == 2){ # 2. 보통
      price4[i] = avg 
    }else{ # 3. 저조
      price4[i] = avg * 0.5
    }
  }else{ # NOT NA
    price4[i] <- dataset$price[i]
  }
}
length(price4) # 300

# 칼럼 추가 
dataset$price4 <- price4
dataset[c("price", "price2", "price3", "price4", "type")]


# 3. 이상치(outlier) 발견과 처리 

# 1) 범주형(집단) 변수 이상치 처리 
dim(dataset) # 300  11

gender <- dataset$gender
gender

# 이상치 발견 
table(gender)
#   0   1   2   5 
#   2 173 124   1

pie(table(gender))

# 이상치 처리(제거)
dataset <- subset(dataset, gender == 1 | gender == 2)
pie(table(dataset$gender))


# 2) 연속형 변수 이상치 처리 
price <- dataset$price
length(price) # 297

# 이상치 발견 
plot(price) # plot(y) : 상하위 3%
summary(price)


# 이상치 제거 : 2~10
dataset2 <- subset(dataset, price >= 2 & price <= 10)
dim(dataset2) # 248  11
297 - 248 # 49

plot(dataset2$price)

# age 변수 이상치 발견 
plot(dataset2$age)
range(dataset2$age, na.rm = T) # 20 69


# 3) boxplot & 통계 이용  
install.packages("ggplot2")
library(ggplot2) # 시각화 도구, dataset 제공 
mpg # ggplot2 제공 dataset
str(mpg)
# Classes ‘tbl_df’ 234 obs. of  11 variables:

# 이상치 발견 
boxplot(mpg$hwy)
boxplot(mpg$hwy)$stats
# 12 ~ 37
range(mpg$hwy) # 12 44

# 이상치 제거 
mpg_sub <- subset(mpg, hwy >= 12 & hwy <= 37)
boxplot(mpg_sub$hwy)


# 4. 코딩변경 
# - 데이터의 가독성, 척도변경(연속형 -> 범주형), 역코딩 

# 1) 데이터의 가독성
# 형식) data$새칼러명[조건식] <- 추가할 값 

table(dataset2$resident)

dataset2$resident2[dataset2$resident==1] <- "1.서울특별시"
dataset2$resident2[dataset2$resident==2] <- "2.인천광역시"
dataset2$resident2[dataset2$resident==3] <- "3.대전광역시"
dataset2$resident2[dataset2$resident==4] <- "4.대구광역시"
dataset2$resident2[dataset2$resident==5] <- "5.시구군"

head(dataset2)

table(dataset2$job)
#  1  2  3  ->  1.공무원, 2.회사원, 3.개인사업 (job2 변수 추가)
# 61 87 88

dataset2$job2[dataset2$job==1] <- "1.공무원"
dataset2$job2[dataset2$job==2] <- "2.회사원"
dataset2$job2[dataset2$job==3] <- "3.개인사업"

head(dataset2)


# 2) 척도변경(연속형 -> 범주형)
range(dataset2$age, na.rm = T) # 20 ~ 69

# 20~35 : 청년층 
# 36~55 : 중년층 
# 56이상 : 장년층 
dataset2$age2[dataset2$age <= 35] <- "1.청년층"
dataset2$age2[dataset2$age > 35 & dataset2$age <= 55] <- "2.중년층"
dataset2$age2[dataset2$age > 55] <- "3.장년층"

dataset2[c("age", "age2")]
table(dataset2$age2)
#1.청년층 2.중년층 3.장년층
#   79       97       56 


# 3) 역코딩 : 반대로 코딩 
#  1   2 3 4     5
# 매우만족(1) ~ 매우불만족(5)  
#    1 -> 5        5 -> 1

x <- dataset2$survey
csurver <- 6 - x
x[1:5]
csurver[1:5]

# 변수 수정 
dataset2$survey <- csurver


# 5. 탐색적 분석을 위한 시각화 
# - 변수와 변수의 데이터 분포 분석 

setwd("c:/2_Rwork/Part-II")

new_data <- read.csv("new_data.csv")
str(new_data)
# 'data.frame': 231 obs. of  15 variables:

# 1) 범주형(명목/서열) vs 범주형(명목/서열) 
# - 방법 : table(), barplot, mosaicplot

# 거주지역, 성별 변수 
resident_gender <- table(new_data$resident2, 
                         new_data$gender2) 
resident_gender # 행,열 -> 교차분할표 

barplot(resident_gender, col=rainbow(5),
        beside = T, horiz = T,
        legend = row.names(resident_gender))
# beside = F : 누적형 막대차트 
# legend : 범례 
# row.names(resident_gender) : 행 이름 추출 

# 정사각형 -> 해당 빈도수 직사각형 
mosaicplot(resident_gender, col=rainbow(2))

# 고급시각화 : 직업유형 vs 나이(범주형) 
library(ggplot2)
ggplot(data = new_data, aes(x=job2, fill=age2)) + geom_bar(position = "fill")


# 2) 숫자형(비율/등간) vs 범주형(명목/서열)
# - 방법 : boxplot, 카테고리별 통계 

boxplot(new_data$age)

# 카테고리별 통계 시각화 
install.packages("lattice") # 격자 
library(lattice)

# 나이(비율), 직업유형(범주형:3개)
densityplot(~age, groups = job2, data=new_data,
            auto.key = T) # ~ x축 
# auto.key = T : 범례 

# 나이(비율), 직업유형(범주형:3개)
ggplot(data = new_data, aes(x=age, fill=job2)) + geom_bar(position = "fill")


# 3) 숫자형 vs 범주형 vs 범주형 

# (1) 구매금액, 성별(1,2), 직급(1,2,3,4,5)  
densityplot(~price | gender2, groups = position2,
            data = new_data, auto.key = T)

# | gender2 -> 남자/여자 
densityplot(~price | position2 , groups = gender2,
            data = new_data, auto.key = T)


# 4) 숫자형 vs 숫자형 vs 범주형 
# - 방법 : 상관계수, 산점도, 산점도 matrix

# 나이, 구매금액 
x <- new_data$age
y <- new_data$price

new_data2 <- na.omit(new_data)
x <- new_data2$age
y <- new_data2$price

cor(x, y) # 0.0881251
# 3~4 이상 
# 5~7 : 보통 
# 7~ : 높다 

plot(x, y) # 기본 함수 

# 숫자형, 숫자형, 범주형 
xyplot(price ~ age | gender2, data = new_data) # lattice 제공 


# 6. 파생변수 
# - 기존변수를 이용해서 새로운 변수 생성 

# 1) 1:1 : 기존칼럼 -> 새로운 칼럼(1) 
# 2) 1:n : 기존변수 ->  새로운 칼럼(n)

# 3) 사칙연산


setwd("c:/2_Rwork/Part-II")

# 고객 기본 정보 table
user_data <- read.csv("user_data.csv")
str(user_data)
# 'data.frame': 400 obs. of  5 variables:
table(user_data$house_type)
#   1   2 -> 1   3   4 -> 2
#  32  47       21 300

# 1) 1:1 : 기존칼럼 -> 새로운 칼럼(1)
user_data$house_type2 <- ifelse(user_data$house_type==1 | user_data$house_type==2, 1, 2)
head(user_data)


# 2) 1:n : 기존변수 ->  새로운 칼럼(n)
# 지불정보 table
pay_data <- read.csv("pay_data.csv")
str(pay_data)
head(pay_data)

library(reshape2)

# 고객별 구매상품 유형 파생변수 
pay_price <- dcast(pay_data, user_id~product_type,sum,na.rm=T)
pay_price
head(pay_price) 
#  user_id      1      2      3      4     5
#1    1001 153000      0      0      0     0
#2    1002      0 120000      0      0     0
#3    1003 125000      0 780000 123000 79000
#4    1007      0 150000  78879  81980 71773

names(pay_price) <- c("user_id","식료품","생필품","의료","잡화","기타")

head(pay_price)

library(dplyr)  

# table join
user_pay_data <- left_join(user_data, pay_price, by="user_id")
head(user_pay_data)  
  
# 3) 사칙연산  
user_pay_data$tot_price <- user_pay_data$'식료품'+ user_pay_data$'생필품' + user_pay_data$'의료' + user_pay_data$'잡화' + user_pay_data$'기타'
head(user_pay_data)


댓글