대충벌레 블로그
article thumbnail
Published 2021. 1. 21. 18:00
R언어 공부 정리 [5] IT 기술/R
728x90
반응형

R언어 이전 포스트 참고

2021/01/20 - [IT/R] - R언어 공부 정리 [4]

2021/01/19 - [IT/R] - R 언어 공부 정리 [3]

2021/01/18 - [IT/R] - R 언어 공부정리 [2]

2021/01/15 - [IT/R] - 분석 , 통계시 유용한 R 언어 설치와 기본 공부 정리

 

 

 

데이터를 합치는 방법 에는 left_join() 과 bind_rows() 가 있습니다.

우선 left_join() 과 bind_rows()는 dplyr라는 라이브러리를 로드해주어야합니다.

library(dplyr)

left_join() : 데이터 열 합치기 

bind_rows() : 데이터 행 합치기 

 

열 컬럼을 합치기 위해서 데이터 프레임을 두개 생성해줍니다.

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))                    

두 데이터 프레임은 반드시 통합적으로 기준이 되는 공통된 컬럼 변수가 있어야합니다.

위의 프레임에는 id가 공통 컬럼 변수입니다.

 

두 프레임을 합쳐보도록 하겠습니다.

total <- left_join(test1,test2, by="id")
total

# 실행 결과 
#   id midterm final
# 1  1      60    70
# 2  2      80    83
# 3  3      70    65
# 4  4      90    95
# 5  5      85    80

이번에는 기존 exam 데이터프레임에 선생님을 left_join으로 추가해보도록 하겟습니다.

name <- data.frame(class=c(1,2,3,4,5),
                   teacher=c('kim','lee','park','choi','jung'))

name이라는 프레임에 class와 선생님 데이터를 추가하고 exam과 name을 컬럼병합을 해봅시다.

exam_new <- left_join(exam,name,by='class')
exam_new

# 실행 결과 
   id class math english science teacher
1   1     1   50      98      50     kim
2   2     1   60      97      60     kim
3   3     1   45      86      78     kim
4   4     1   30      98      58     kim
5   5     2   25      80      65     lee
6   6     2   50      89      98     lee
7   7     2   80      90      45     lee
8   8     2   90      78      25     lee
9   9     3   20      98      15    park
10 10     3   50      98      45    park
11 11     3   65      65      65    park
12 12     3   45      85      32    park
13 13     4   46      98      65    choi
14 14     4   48      87      12    choi
15 15     4   75      56      78    choi
16 16     4   58      98      65    choi
17 17     5   65      68      98    jung
18 18     5   80      78      90    jung
19 19     5   89      68      87    jung
20 20     5   78      83      58    jung

이번에는 행을 합치는 bind_rows 입니다.

group_a <- data.frame(id=c(1,2,3,4,5),
                      test=c(60,80,70,90,85))
group_a


group_b <- data.frame(id=c(6,7,8,9,10),
                      test=c(70,83,65,95,80))
group_b

 

group_a  에는 id가 1부터5인 사람의 점수  group_b 에는 id가 6부터 10인 사람의 점수가 있습니다.

bind_rows() 함수는 컬럼이 동일하면 합칠수 있습니다.

group_all <- bind_rows(group_a,group_b)
group_all

# 실행결과 
   id test
1   1   60
2   2   80
3   3   70
4   4   90
5   5   85
6   6   70
7   7   83
8   8   65
9   9   95
10 10   80

 

문제로 mpg와 병합할 데이터를 만들어보겠습니다.

fuel <- data.frame(fl=c('c','d','e','p','r'),
                   price_fl=c(2.35,2.36,2.11,2.76,2.22),
                   stringsAsFactors = F)

이 f1을 기준으로 mpg에 가격컬럼을 추가해보겟습니다,

mpg_1 <- left_join(mpg,fuel,by="fl")

새로 생성한 mpg_1 에서 model, fl , price_fl만 추출해서 상위 6개를 확인해보겠습니다.

mpg_1 %>% select(model,fl,price_fl) %>% head()

 

예제 문제입니다. 

midwest 데이터에서 popadults는 해당지역의 성인인구 , poptotal은 전체인구입니다.

midwest 데이터에서 전체인구 대비 미성년 인구 백분율을 변수 popchild로 추가하시오.

midwest_b <- midwest %>% mutate(popchild=(total-popadults)/total*100)

# 제대로 들어갔는지 확인하기 위해 select 해보겠습니다.
# midwest는 dim(midwest) 시 437행 31열 이라서 눈으로 직접 확인할수도 있지만
# 열 컬럼이 많은 빅데이터시에는 힘들수도 있습니다.
midwest_b %>% select(popchild)
# 실행결과 
   popchild
      <dbl>
 1     34.5
 2     36.7
 3     35.5
 4     37.4
 5     31.8
 6     34.3
 7     32.7
 8     32.6
 9     34.3
10     44.5
# ... with 427 more rows

이번엔 미성년 인구 비율이 가장 높은 상위 5개 지역(country)의 미성년 인구 백분율을 출력해봅시다.

midwest_b %>% arrange(desc(popchild)) %>% # 내림차순
  select(county,popchild) %>% # country와 popchild 컬럼 확인
  head(5) # 상위 5개
  
  # 실행 결과
 # A tibble: 5 x 2
  county    popchild
  <chr>        <dbl>
1 ISABELLA      51.5
2 MENOMINEE     50.6
3 ATHENS        49.3
4 MECOSTA       49.1
5 MONROE        47.4

 

분류하는 기준에 따라서 미성년 비율 등급변수를 추가하고, 각 등급에 몇개의 지역이 해당되는지 출력해봅시다.

기준은 40% 이상이면 large , 30~40% 사이면 middle , 30% 미만이면 small 

midwest_c <- midwest_b %>% mutate(grade=ifelse(popchild>= 40,'large',ifelse(popchild>=30,'middle','small')))
# mutate 새로운 컬럼을 추가합니다. ifelse로 popchild가 40% 이상일시 large 
# 이중조건문으로 popchild가 30% 이상일시 middle
# 그외에는 small 입니다 

table로 출력시 수치로 바로 확인이 가능합니다.

table(midwest_c$grade)

# 실행 결과 
 large middle  small 
    32    396      9 

qplot 확인시 그래프로 확인할수 있습니다 .

qplot(midwest_c$grade)

popasian은 해당 지역의 아시아인 인구를 나타냅니다. 전체인구 대비 아시아인구 백분율 asianrate를 추가하고

하위 10개 지역의 state, country , asianrate을 출력해봅시다.

 

 midwest_c %>%   # midwest_c 데이터프레임에서
  mutate(asian_rate=(asain/total)*100) %>% # 새로운 컬럼을 추가합니다 전체인구분의 아시아인구 백분율
  arrange(asian_rate) %>% # 오름차순으로 정렬
  select(state,county,asian_rate) %>% # state, country , asian_rate 컬럼만 선택
  head(10) # 10개만 출력

데이터 정제하기  : 이상치 혹은 결측치가 있으면 데이터 분석이 어려울수 있음

결측치 : 데이터가 없는 경우  [ ex) NA ] 

이상치 : 데이터가 이상한 데이터 [ 있을수가 없는 데이터 ex) 나이가 999살 , 100점만점인 시험에서 115점이다 ]

 

결측치가 있는 데이터 생성

df <- data.frame(sex=c('M','F',NA,'M','F'),
                 score=c(5,4,3,4,NA))
                 
df

# 실행결과 
   sex score
1    M     5
2    F     4
3 <NA>     3
4    M     4
5    F    NA

성별의 <NA>는 결측치 score의 NA는 결측치이다.

 

결측치를 감별하는 함수는 is.na 인데 정상이 False로 출력되고 비정상은 True로 출력됨

만약 정상이 True 비정상이 False로 하고싶으면 !is.na( ) 로 하면 된다.

is.na(df)
# 실행결과
       sex score
[1,] FALSE FALSE
[2,] FALSE FALSE
[3,]  TRUE FALSE
[4,] FALSE FALSE
[5,] FALSE  TRUE
# 정상이 False # 비정상이 True

table(is.na(df))  # table() 빈도 테이블로 출력
# 실행결과
FALSE  TRUE 
    8     2 
 

# 성별에 결측치가 있는지 확인
table(is.na(df$sex))

#실행결과
FALSE  TRUE 
    4     1 

 

결측치가 있는 데이터는 연산이 불가능하다 .

sum(df$score)

[1] NA

결측치를 제거하는 방법은 filter를 사용하면 된다.

df %>% filter(!is.na(df$score)) # score에 있는 결측 데이터를 제거함

non_all <- df %>% filter(!is.na(df$score) & !is.na(df$sex))
# is.na 결측결과 score의 False sex에 False를 빼고 non_all에 넣는다

한번에 모든 결측치를 제거할려면 na.omit() 함수를 사용하면 된다.

df_omit <- na.omit(df) # 모든 결측치 제거
df_omit

# 실행결과 
  sex score
1   M     5
2   F     4
3   M     4

 

일반적인 함수사용시에는 na.rm = T 를 추가해서 사용이 가능하다.

mean(df$score, na.rm = T)   
# [1] 4
sum(df$score,na.rm=T)
# [1] 16

csv_exam.csv 파일에서 수학점수 3행 8행 15행을 결측치로 NA를 삽입해보자

exam[c(3,8,15),'math'] <- NA

#결측치 확인을 위해 is.na 사용
table(is.na(exam$math))

exam의 결측치를 제거하고 수학점수의 총점 , 평균,중앙값을 구해봅시다.

exam %>% na.omit() %>% summarise(tot=sum(math),avg=mean(math),median=median(math))
# 실행결과 
  tot      avg median
1 939 55.23529     50

na.omit() 방식 대신에 각각에 na.rm = T 를 넣는 방식으로 쓸수도 있다

 exam %>% summarise(tot=sum(math,na.rm = T),avg=mean(math,na.rm=T),medi=median(math,na.rm = T))

 

결측치를 대처하는 방법으로 imputation이 있다 

예를 들어 수학점수가 결측치가 있다면 0으로 대체하는 방법이다.

exam$math <- ifelse(is.na(exam$math),0,exam$math)
# is.na는 정상값이 False이므로 결측치가 있으면 0으로하고 아니면 그대로 둔다

 

mpg 데이터에 hwy 컬럼이 65,124,131,153,212 행에 NA를 할당하고 결측치가 있는지 확인해봅시다.

mpg_4 <- mpg
mpg_4[c(65,124,131,153,212),'hwy'] <- NA
table(is.na(mpg_4$hwy))

FALSE  TRUE 
  229     5 

 

filter()를 이용해서 hwy 변수의 결측치를 제거하고 어떤 구동방식의 hwy가 높은지 알아봅시다

단 하나의 dplyr 구문으로 작성하시오

mpg_4 %>% filter(!is.na(hwy)) %>%  # 결측치를 제거한다
  group_by(drv)  %>%# 구동방식별
  summarise(mean_hwy=mean(hwy)) # hwy 평균
  
 # 실행결과

  drv   mean_hwy
  <chr>    <dbl>
1 4         19.2
2 f         28.2
3 r         21  

이상치 

이상치가 있는 데이터를 새로 생성해봅시다.

outlier <- data.frame(sex=c(1,2,1,3,2,1), 
                      score=c(5,4,3,4,2,6)) 
                      
# 성별은 1 ,2 로만 구성되어야 하고 
# 점수는 1~5 사이에서 구성되어야 한다

즉 성별에서 3은 이상치이고 점수에서 6은 이상치 입니다.

빈도테이블을 이용해서 값을 확인해봅시다.

table(outlier$sex)

# 결과
1 2 3 
3 2 1

성별의 1이 3개 2가 2개 3이 1개 입니다 여기서 3은 이상치!

마찬가지로 점수의 값을 확인해봅시다.

table(outlier$score) 

2 3 4 5 6 
1 1 2 1 1 

6이 1개 발견되었습니다.

결측치의 경우 제외를 하거나 다른 연산이 가능한 값으로 변경처리했고

이상치의 경우는 NA로 처리하여 제외시키거나 아니면 다른 연산이 가능한 값으로 변경처리를 합니다.

outlier$sex <- ifelse(outlier$sex ==3,NA,outlier$sex)
outlier

# 결과 
  sex score
1   1     5
2   2     4
3   1     3
4  NA     4
5   2     2
6   1     6

outlier$score <- ifelse(outlier$score ==6,NA,outlier$score)
outlier

# 결과
  sex score
1   1     5
2   2     4
3   1     3
4  NA     4
5   2     2
6   1    NA

 

성별 평균을 구해봅시다 . 

outlier %>% filter(!is.na(sex) & !is.na(score) ) %>% 
  group_by(sex) %>% summarise(score_avg=mean(score))
  
# filter로 sex가 결측치가 아닌값 즉 !is.na True인값과 score가 정상인값을 추린후
sex별 점수의 평균을 구한다

    sex score_avg
  <dbl>     <dbl>
1     1         4
2     2         3

 

만약 확실한 범위가 아닌경우 이상치 판단을 할때는 boxplot을 주로 이용하는데

boxplot은 표준편차로 +-3을 벗어나면 (이상치)극단치로 간주합니다.

 

mpg의 hwy의 이상치를 그림으로 확인해보면

boxplot(mpg$hwy)  # 그림으로 확인

위와같이 확인할수 있고 통계치로 확인을 하려면 

boxplot(mpg$hwy)$stats

#결과 
     [,1]
[1,]   12
[2,]   18
[3,]   24
[4,]   27
[5,]   37
attr(,"class")
        1 
"integer" 

12보다 작거나 37 보다 큰경우에는 이상치,극단치로 간주한다.

 

고속도로 연비 극단치를 처리해 봅시다.

12보다 작거나 37보다 크면 NA 그외에는 그대로 사용합니다.

mpg$hwy <- ifelse(mpg$hwy < 12 | mpg$hwy > 37 , NA , mpg$hwy)

극단치가 몇개 있는지 NA를 확인해 봅시다 .

table(is.na(mpg$hwy)) 

FALSE  TRUE 
  231     3 
  
  # 극단치가 3개인것을 확인할수 있음

 

drv별 고속도로 연비 평균을 산출해 봅시다.

mpg %>% group_by(drv) %>% summarise(drv_hwy_avg=mean(hwy,na.rm = T)) 

  drv   drv_hwy_avg
  <chr>       <dbl>
1 4            19.2
2 f            27.7
3 r            21 

이번엔 임의의 이상치를 할당해서 테스트 해봅시다.

mpg[c(10,14,58,93),"drv"] <- "k"
mpg[c(29,43,129,203),"cty"] <- c(3,4,39,42)

10행 14행 58행 93행의 drv에 k의 값
29행 43행 129행 203행의 cty에는 3 4 39 42 가 들어갑니다

 

drv에 이상치가 있는지 확인해서 이상치를 결측치로 처리후 사라져는지 확인해봅시다 %in% 연산자를 활용!

table(mpg$drv) # drv의 이상치를 확인합니다 

  4   f   k   r 
100 106   4  24 

즉 k는 이상치 NA로 치환해줍니다

mpg$drv <- ifelse(mpg$drv %in% c('4','f','r'), mpg$drv,NA)

후에 다시 이상치를 확인합니다.

table(mpg$drv) 

  4   f   r 
100 106  24 

 

이상치를 결측치로 변경했으므로 이상치는 없으나 NA 결측치가 4개가 존재합니다.

결측치를 확인하는 방법은 

table(is.na(mpg$drv))  

FALSE  TRUE 
  230     4 

즉 결측치 4개 존재

 

boxplot을 이용해서 이상치가 있는지 확인하고 상자그림의 통계치를 이용해

정상범위를 벗어난 값을 결측제거 처리한후 다시 상자그림을 이용해 이상치가 없는지 확인하시오.

boxplot(mpg$cty)$stats

    [,1]
[1,]    9
[2,]   14
[3,]   17
[4,]   19
[5,]   26

# 9~26 이외는 NA로 처리
mpg$cty <- ifelse(mpg$cty < 9 | mpg$cty > 26 ,NA,mpg$cty)
9미만 26초과는 NA로 처리 그외에는 그대로

boxplot(mpg$cty)

극단치가 사라진것을 확인할수 있음 

하지만 이제 NA가 9개 존재함

table(is.na(mpg$cty))

FALSE  TRUE 
  225     9 

이상치를 제외한 다음 drv별로 cty 평균이 어떻게 다른지 알아보시오

mpg %>% 
  filter(!is.na(drv) & !is.na(cty)) %>%  # 결측치 제외
  group_by(drv) %>% # drv별로 
  summarise(mean_hwy = mean(cty)) # cty의 평균을 구한다.
  
  # A tibble: 3 x 2
  drv   mean_hwy
  <chr>    <dbl>
1 4         14.2
2 f         19.5
3 r         14.0

 

반응형

'IT 기술 > R' 카테고리의 다른 글

R언어 공부정리 [7]  (0) 2021.01.25
R언어 공부 정리 [6]  (0) 2021.01.22
R언어 공부 정리 [4]  (2) 2021.01.20
R 언어 공부 정리 [3]  (1) 2021.01.19
R 언어 공부정리 [2]  (2) 2021.01.18
profile

대충벌레 블로그

@대충벌레

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!