본문 바로가기
공부/IT-R프로그래밍

R데이터배우기 - [05] 데이터 가공(데이터 전처리),데이터 정제

by 썸볼 2017. 10. 24.

무작정 따라하는 공부법 ! 무따공입니다~


벌써 다섯번째 포스팅이네요 ㅎㅎ 

패키지 함수를 몇가지 다루는데, 잘 따라오세요!


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



1. 데이터 전처리기
- 분석에 적합한 데이터로 가공하는 작업을 데이터 전처리(Data Preprocessing)라고 한다.
- dplyr패키지는 데이터 전처리 작업에 가장 많이 사용된다.




(1) 조건에 맞는 데이터 추출

- filter(조건식)를 이용하여 원하는 데이터를 추출할 수 있다.


library(dplyr)

exam <- read.csv("csv_exam.csv")
exam
 
# exam에서 class가 1인 경우만 추출하여 출력
exam %>% filter(class == 1)  
 
# 2반인 경우만 추출
exam %>% filter(class == 2)  
 
# 1반이 아닌 경우
exam %>% filter(class != 1)
 
# 3반이 아닌 경우
exam %>% filter(class != 3)
 
 
## -------------------------------------------------------------------- ##
# 수학 점수가 50점을 초과한 경우
exam %>% filter(math > 50)
 
# 수학 점수가 50점 미만인 경우
exam %>% filter(math < 50)
 
# 영어 점수가 80점 이상인 경우
exam %>% filter(english >= 80)
 
# 영어 점수가 80점 이하인 경우
exam %>% filter(english <= 80)
 
 
## -------------------------------------------------------------------- ##
# 1반이면서 수학 점수가 50점 이상인 경우
exam %>% filter(class == 1 & math >= 50)
 
# 2반이면서 영어 점수가 80점 이상인 경우
exam %>% filter(class == 2 & english >= 80)
 
 
## -------------------------------------------------------------------- ##
# 수학 점수가 90점 이상이거나 영어 점수가 90점 이상인 경우
exam %>% filter(math >= 90 | english >= 90)
 
# 영어 점수가 90점 미만이거나 과학점수가 50점 미만인 경우
exam %>% filter(english < 90 | science < 50)
 
 
## -------------------------------------------------------------------- ##
# 1, 3, 5 반에 해당되면 추출
exam %>% filter(class == 1 | class == 3 | class == 5)
 
exam %>% filter(class %in% c(1,3,5))
 
 
## -------------------------------------------------------------------- ##
class1 <- exam %>% filter(class == 1)  # class가 1인 행 추출, class1에 할당
class2 <- exam %>% filter(class == 2)  # class가 2인 행 추출, class2에 할당
 
mean(class1$math)                      # 1반 수학 점수 평균 구하기
mean(class2$math)                      # 2반 수학 점수 평균 구하기
 


(3) 필요한 변수만 추출

- select()는 데이터에 들어 있는 수 많은 변수 중 일부 변수만 추출해 활용하고자 할 때 사용한다.


exam %>% select(math)                  # math 추출
 
exam %>% select(english)               # english 추출
 
exam %>% select(class, math, english)  # class, math, english 변수 추출
 
exam %>% select(-math)                 # math 제외
 
exam %>% select(-math, -english)       # math, english 제외
 


- filter()와 select() 조합

# class가 1인 행만 추출한 다음 english 추출
exam %>% filter(class == 1) %>% select(english)
 
exam %>%
  filter(class == 1) %>%  # class가 1인 행 추출
  select(english)         # english 추출
 
exam %>% 
  select(id, math) %>%    # id, math 추출
  head                    # 앞부분 6행까지 추출
 
exam %>% 
  select(id, math) %>%  # id, math 추출
  head(10)              # 앞부분 10행까지 추출
 


(4) 순서대로 정렬
- arrange()를 이용하여 데이터를 원하는 순서로 정렬할 수 있다.
- default가 오름차순이며 desc()를 사용하여 내림차순을 지정할 수 있다.


exam %>% arrange(math)         # math 오름차순 정렬
exam %>% arrange(desc(math))   # math 내림차순 정렬
exam %>% arrange(class, math)  # class 및 math 오름차순 정렬




(5) 파생변수 추가
- mutate()를 사용하여 기존 데이터에 파생변수를 추가할 수 있다.


exam %>%

  mutate(total = math + english + science) %>%  # 총합 변수 추가
  head                                          # 일부 추출
 
exam %>%
  mutate(total = math + english + science,         # 총합 변수 추가
         mean = (math + english + science)/3) %>%  # 총평균 변수 추가
  head                                             # 일부 추출
 
exam %>%
  mutate(test = ifelse(science >= 60, "pass", "fail")) %>%
  head
 
exam %>%
  mutate(total = math + english + science) %>%  # 총합 변수 추가
  arrange(total) %>%                            # 총합 변수 기준 정렬
  head                                          # 일부 추출
 


(6) 집단별로 요약
- 집단별 평균이나 집단별 빈도처럼 각 집단을 요약한 값을 group_by()와
  summarise()를 사용한다.


exam %>% summarise(mean_math = mean(math))  # math 평균 산출

 
exam %>% 
  group_by(class) %>%                   # class별로 분리
  summarise(mean_math = mean(math))     # math 평균 산출


- 여러 요약 통계량을 한번에 산출할 수 있다.

exam %>% 
  group_by(class) %>%                   # class별로 분리
  summarise(mean_math = mean(math),     # math 평균
            sum_math = sum(math),       # math 합계
            median_math = median(math), # math 중앙값
            n = n())                    # 학생 수
 
 



 ※ summarise()에 자주사용 하는 요약 통계랑 함수




- group_by()에 여러 변수를 지정하면 집단을 나눈 후 다시 하위 집단으로 나눌 수 있다.
- mpg(자동차 정보)데이터를 이용하여 하위집단별 평균을 구한다., 회사별로 집단을 나눈 후
  다시 구동 방식별로 나눠 도시 연비 평균을 구한다.

  
mpg %>%
  group_by(manufacturer, drv) %>%       # 회사별, 구동방식별 분리
  summarise(mean_cty = mean(cty)) %>%   # cty 평균 산출
  head(10)                              # 일부 출력
 
   manufacturer   drv mean_cty
          <chr> <chr>    <dbl>
 1         audi     4 16.81818
 2         audi     f 18.85714
 3    chevrolet     4 12.50000
 4    chevrolet     f 18.80000
 5    chevrolet     r 14.10000
 6        dodge     4 12.00000
 7        dodge     f 15.81818
 8         ford     4 13.30769
 9         ford     r 14.75000
10        honda     f 24.44444

 

drv 변수: 4->사륜구동,  f->전륜구동, r ->후륜구동

- dplyr패키지의 함수들을 하나의 구문으로 조합하여 아래의 분석 문제를 해결하자.

회사별 'suv' 자동차의 도시 및 고속도로 통합 연비 평균을 구해 내림차순으로 정렬하고,
1~5위까지 출력하기


※ 작성 절차에 따른 기능별 함수
1. 회사별로  분리   -> group_by()
2. SUV
추출          -> filter()
3. 통합 연비 변수 생성   -> mutate()
4. 통합 연비 평균 산출   -> summarise()
5. 내림차순 정렬  -> arrange()
6. 1~5까지 출력  -> head()



mpg %>%
  group_by(manufacturer) %>%           # 회사별로 분리
  filter(class == "suv") %>%           # suv 추출
  mutate(tot = (cty+hwy)/2) %>%        # 통합 연비 변수 생성
  summarise(mean_tot = mean(tot)) %>%  # 통합 연비 평균 산출
  arrange(desc(mean_tot)) %>%          # 내림차순 정렬
  head(5)                              # 1~5위까지 출력
 



(7) 데이터 합치기
1) 가로로 합치기
 - 두개의 데이터 프레임을 만들고 dplyr패키지의 left_join()을 이용하여 데이터를 
   가로로 합친다.
 - 기준변수명은 by에 지정한다.


# 중간고사 데이터 생성
test1 <- data.frame(id = c(1, 2, 3, 4, 5),           
                    midterm = c(60, 80, 70, 90, 85))
 
# 기말고사 데이터 생성
test2 <- data.frame(id = c(1, 2, 3, 4, 5),           
                    final = c(70, 83, 65, 95, 80))
 
test1  # test1 출력
test2  # test2 출력
 
total <- left_join(test1, test2, by = "id")  # id 기준으로 합쳐서 total에 할당
total                                        # total 출력
 


- 각반학생 명단에 담임교사 명단 추가하기

name <- data.frame(class = c(1, 2, 3, 4, 5),
                   teacher = c("kim", "lee", "park", "choi", "jung"))
name
 
exam_new <- left_join(exam, name, by = "class")
exam_new




2) 세로로 합치기
- bind_rows()함수를 이용하여 데이터를 세로로 합친다.
- 우선 다섯명이 시험을 보고 나중에 다섯명이 따로 시험본결과를 
  세로로 합친다.


# 학생 1~5번 시험 데이터 생성

group_a <- data.frame(id = c(1, 2, 3, 4, 5),
                      test = c(60, 80, 70, 90, 85))
 
# 학생 6~10번 시험 데이터 생성
group_b <- data.frame(id = c(6, 7, 8, 9, 10),
                      test = c(70, 83, 65, 95, 80))
 
group_a  # group_a 출력
group_b  # group_b 출력
 
group_all <- bind_rows(group_a, group_b)  # 데이터 합쳐서 group_all에 할당
group_all                                 # group_all 출력
 




2. 데이터 정제
(1) 결측치 정제하기
- 결측치(Missing Value)는 누락된 값, 비어 있는 값의미
- 결측치로 이인해 함수가 적용이 안되거나 분석결과가 왜곡되는 문제가 발생할 수 있다.
- 결측치를 없애는 정제과정이 필요하다.
- R에서 결측치는 NA로 표시된다. 결측지를 확인하기 위해서는 is.na()로 확인한다.
- 결측치를 제거하기위해 is.na()를 filter()적용하면 결측치 행을 제거할 수 있다.

#결측치가 포함된 데이터 생성

df <- data.frame(gender = c("M", "F", NA, "M", "F"),
                       score = c(5, 4, 3, 4, NA))
df
 
is.na(df)               # 결측치 확인
table(is.na(df))        # 결측치 빈도 출력
table(is.na(df$gender))    # gender 결측치 빈도 출력
table(is.na(df$score))      # score 결측치 빈도 출력

#결측치가 포함된 데이터는 함수 적용시 연산되지 못하고 NA값 출력한다.
mean(df$score)  # 평균 산출
sum(df$score)   # 합계 산출

#결측치 제거
library(dplyr)                # dplyr 패키지 로드
df %>% filter(is.na(score))   # score가 NA인 데이터만 출력
df %>% filter(!is.na(score))  # score 결측치 제거

#결측치가 제거되면 함수가 적용된다.
df_nomiss <- df %>% filter(!is.na(score))  # score 결측치 제거
mean(df_nomiss$score)                      # score 평균 산출
sum(df_nomiss$score)                       # score 합계 산출

#성별및 점수의 결측치 제거
df_nomiss <- df %>% filter(!is.na(score) & !is.na(gender))  # score, gender 결측치 제거
df_nomiss                                                # 출력


#na.omit()를 이용하면 결측치가 있는행을 한번에 제거할 수 있다.
df_nomiss2 <- na.omit(df)  # 모든 변수에 결측치 없는 데이터 추출
df_nomiss2                     # 출력


- 함수 자체에 결측치 제외 기능(na.rm)이 있는경우는 그기능을 사용하여 함수를 적용한다.
  결측치 제외 기능이 없을시에는 fillter()로 결측지를 제거한다.

df

mean(df$score, na.rm = T)  # 결측치 제외하고 평균 산출
sum(df$score, na.rm = T)   # 결측치 제외하고 합계 산출
 
exam <- read.csv("csv_exam.csv")  # 데이터 불러오기
exam[c(3, 8, 15), "math"] <- NA   # 3, 8, 15행의 math에 NA 할당
exam
 
exam %>% summarise(mean_math = mean(math))  # math 평균 산출
 
# math 결측치 제외하고 평균 산출
exam %>% summarise(mean_math = mean(math, na.rm = T))  
 
exam %>% summarise(mean_math = mean(math, na.rm = T),      # 평균 산출
                   sum_math = sum(math, na.rm = T),        # 합계 산출
                   median_math = median(math, na.rm = T))  # 중앙값 산출



- 결측치를 제거 하는 대신 다른 값으로 대체할 수 있다.

mean(exam$math, na.rm = T) # 결측치 제외하고 math 평균 산출
 
exam$math <- ifelse(is.na(exam$math), 55, exam$math)  # math가 NA면 55로 대체
table(is.na(exam$math))                               # 결측치 빈도표 생성
exam                                                  # 출력
mean(exam$math)                                       # math 평균 산출
 




(2) 이상치 정제하기
- 정상범주에서 크게 벗어난 값을 이상치(Outlier)라고 한다.
- 오류는 아니지만 굉장히 드물게 극단적인 값이 있을 수도 있다.
- 분석적 이런 이상치를 제거 해야 한다.
- 이상치를 결측치로 변화하여 결측치를 제거한다.

성별은 1과 2 ,  점수는 1~5

# 이상치값을 성별에 3, 점수에 6을 넣어서 생성한다.


outlier <- data.frame(gender = c(1, 2, 1, 3, 2, 1),
                         score = c(5, 4, 3, 4, 2, 6))
outlier
 
table(outlier$gender)
table(outlier$score)
 
# gender가 3이면 NA 할당
outlier$gender <- ifelse(outlier$gender == 3, NA, outlier$gender)
outlier
 
# score가 5보다 크면 NA 할당
outlier$score <- ifelse(outlier$score > 5, NA, outlier$score)
outlier
 
outlier %>% 
  filter(!is.na(gender) & !is.na(score)) %>%
  group_by(gender) %>%
  summarise(mean_score = mean(score))
 


- 극단적으로 크거나 작은 값을 극단치라 하는데 몸무게가 200kg 이상의 값은
  존재가능성은 있지만 굉장히 드문경우이다. 데이터에 극단치가 있으면 분석결과가
  왜곡 될 수 있으므로 제거 해야 한다.

- 아래의 상자 그림은 데이터의 분포를 직사각형의 상자 모양으로 표현한다.
  데이터 분포를 한눈에 볼수 있는데 그림에서 극단치를 확인할 수 있다.





   ※상자그림의 값과 설명

    
 
   *  1.5 IQR 값은 사분위 범위(Q1~Q3간 거리)의 1.5배를 위미한다.


boxplot(mpg$hwy) #위 상자그림과 같다.

- 위 상자 그림의 윗수염과 아랫수염 위와 아래의 가로선의 값을 보면 12~37을 벗어났다.

 
# 상자 그림 통계치 출력
boxplot(mpg$hwy)$stats 

> boxplot(mpg$hwy)$stats
     [,1]
[1,]   12
[2,]   18
[3,]   24
[4,]   27
[5,]   37
attr(,"class")
        1 
"integer" 
           

# 12~37 벗어나면 NA 할당
mpg$hwy <- ifelse(mpg$hwy < 12 | mpg$hwy > 37, NA, mpg$hwy)
 
# 결측치 확인
table(is.na(mpg$hwy))  

#결측치 제외하고  drv그룹별 평균값출력
mpg %>%
  group_by(drv) %>%
  summarise(mean_hwy = mean(hwy, na.rm = T))


댓글