R로 데이터 다루기

R에서 dplyr을 이용해 데이터를 추출, 가공하는 방법을 알아봅니다


수강중

17. dplyr 함수들을 조합한 실전 데이터 다루기 3

데이터 불러오기

변수명도 변경하기 데이터를 불러오고 변수명을 변경하는 법은 앞의 강의들을 참조해주기바란다. 대신 코드는 올린다. 판매 데이터, 업종 코드 데이터, 강수량이 들어있는 기후 데이터를 다 불러오고 변수명을 영문으로 변경하였다.

sales <- read.csv('sales.csv', stringsAsFactors = F,
                  fileEncoding = 'UTF-8')
colnames(sales) <- c('city', 'district', 'gender', 'sales.nm', 'sales.cd', 'ymd', 'sales.num')

products <- read.csv("productcode.csv", stringsAsFactors = F,
                     fileEncoding = "UTF-8")
colnames(products) <- c('products.cd', 'products.nm')

climates <- read.csv('seoul_climate.csv', stringsAsFactors = F,
                     fileEncoding = 'UTF-8')
colnames(climates) <- c('city', 'district', 'ym', 'lat', 'lon', 'rainfall')

판매 데이터에 업종 데이터와 join

mutate

판매 데이터에 업종 데이터와 join 하기 위해 변수를 생성한다. 두 데이터를 합치려면 동일한 업종코드products.cd가 판매 데이터에 있으면 키로 두 데이터를 합칠 수 있다. 그런데 판매 데이터에는 업종코드가 없다. 그래서 mutate를 이용하여 products.cd를 생성하여 join을 해주자.

sales <- sales %>%
    mutate(products.cd = substr(sales.cd, 1, 4))

판매 데이터에 업종 데이터와 join

그 이후에 left join을 해 판매 데이터를 확인하면 업종 코드가 있는 것을 알 수 있다.

sales <- sales %>%
    mutate(products.cd = substr(sales.cd, 1, 4))
sales <- left_join(sales, products)
sales %>% head
Joining, by = "products.cd"
  city       district gender sales.nm sales.cd ymd      sales.num products.cd
1 서울특별시 강남구   남     스탑버스 12AA02   20140101 103       12AA       
2 서울특별시 강남구   여     키즈랜드 100101   20140101 309       1001       
3 서울특별시 강남구   여     키즈랜드 100101   20140101 365       1001       
4 서울특별시 강남구   남     스탑버스 12AA02   20140101 421       12AA       
5 서울특별시 강남구   여     스탑버스 12AA02   20140101 413       12AA       
6 서울특별시 강남구   남     키즈랜드 100101   20140101 428       1001       
  products.nm
1 카페       
2 유아용품   
3 유아용품   
4 카페       
5 카페       
6 유아용품   

mutate

판매 데이터에 기후 데이터와 join 하기 위해 변수를 생성한다. 마찬가지로 기후 데이터에 연월 이라는 변수를 추가해주자.

sales <- sales %>%
    mutate(ym = substr(ymd, 1, 6))

as.character

기후 데이터에서는 연월 변수가 숫자로 되어있어서 as.character로 변환하자.

climates$ym <- as.character(climates$ym)

판매 데이터에 기후 데이터와 join

sales <- sales %>%
    mutate(products.cd = substr(sales.cd, 1, 4))
sales <- left_join(sales, products)
sales %>% head

sales <- sales %>%
    mutate(ym = substr(ymd, 1, 6))
climates$ym <- as.character(climates$ym)
sales <- left_join(sales, climates)
sales %>% head
Joining, by = c("products.cd", "products.nm")
  city       district gender sales.nm sales.cd ymd      sales.num products.cd
1 서울특별시 강남구   남     스탑버스 12AA02   20140101 103       12AA       
2 서울특별시 강남구   여     키즈랜드 100101   20140101 309       1001       
3 서울특별시 강남구   여     키즈랜드 100101   20140101 365       1001       
4 서울특별시 강남구   남     스탑버스 12AA02   20140101 421       12AA       
5 서울특별시 강남구   여     스탑버스 12AA02   20140101 413       12AA       
6 서울특별시 강남구   남     키즈랜드 100101   20140101 428       1001       
  products.nm ym    
1 카페        201401
2 유아용품    201401
3 유아용품    201401
4 카페        201401
5 카페        201401
6 유아용품    201401
Joining, by = c("city", "district", "ym")
  city       district gender sales.nm sales.cd ymd      sales.num products.cd
1 서울특별시 강남구   남     스탑버스 12AA02   20140101 103       12AA       
2 서울특별시 강남구   여     키즈랜드 100101   20140101 309       1001       
3 서울특별시 강남구   여     키즈랜드 100101   20140101 365       1001       
4 서울특별시 강남구   남     스탑버스 12AA02   20140101 421       12AA       
5 서울특별시 강남구   여     스탑버스 12AA02   20140101 413       12AA       
6 서울특별시 강남구   남     키즈랜드 100101   20140101 428       1001       
  products.nm ym     lat      lon     rainfall
1 카페        201401 37.49666 127.063 NA      
2 유아용품    201401 37.49666 127.063 NA      
3 유아용품    201401 37.49666 127.063 NA      
4 카페        201401 37.49666 127.063 NA      
5 카페        201401 37.49666 127.063 NA      
6 유아용품    201401 37.49666 127.063 NA      

1번 문제

업종별(products.nm) 평균 판매건수를 구하세요. 단, NA 업종은 제외하세요.

group_by, filter, summarise

group_by를 하고, NA를 제외하기 위해 filter를 한다. filter를 뒤에 하든 앞에 하든 상관없는데 보통 앞에 하는게 좋다. 그리고 summarise를 하여 평균 판매건수를 구한다.

sales %>%
    filter(!is.na(products.nm)) %>%
    group_by(products.nm) %>%
    summarise(mean.sales.num = mean(sales.num, na.rm = T))
  products.nm mean.sales.num
1 완구        250.7495      
2 유아용품    249.8582      
3 카페        250.0636      
4 한식        250.7960      

2번 문제

한식 업종의 월별 평균 판매건수를 구하고, 내림차순으로 정렬을 하세요.

filter

위와 다른 것은 월별로 구하는 것이 필요하고 한식업종만 구하면 된다.

sales %>%
    filter(products.nm == '한식')
      city       district gender sales.nm sales.cd ymd      sales.num
1     서울특별시 강남구   남     원조한식 100201   20140101 363      
2     서울특별시 강남구   남     원조백반 100202   20140101 480      
3     서울특별시 강남구   여     원조백반 100202   20140101  25      
4     서울특별시 강남구   여     전주비빔 100203   20140101 415      

mutate

그 다음에 월별이라 했는데 월 변수가 없기 때문에 mutate로 월 변수를 구한다.

sales %>%
    filter(products.nm == '한식') %>%
    mutate(m = substr(ymd, 5, 6))
      city       district gender sales.nm sales.cd ymd      sales.num
1     서울특별시 강남구   남     원조한식 100201   20140101 363      
2     서울특별시 강남구   남     원조백반 100202   20140101 480      
3     서울특별시 강남구   여     원조백반 100202   20140101  25      
4     서울특별시 강남구   여     전주비빔 100203   20140101 415      

group_by, summarise

월별 판매 건수이니 group_by가 들어가고 summarise 평균이 들어간다.

sales %>%
    filter(products.nm == '한식') %>%
    mutate(m = substr(ymd, 5, 6)) %>%
    group_by(products.nm, m) %>%
    summarise(mean.sales.num = mean(sales.num, na.rm = T))
   products.nm m  mean.sales.num
1  한식        01 253.7554      
2  한식        02 252.7710      
3  한식        03 250.3631      
4  한식        04 249.7209      
5  한식        05 251.9256      
6  한식        06 250.1250      
7  한식        07 249.2496      
8  한식        08 249.2152      
9  한식        09 253.0379      
10 한식        10 246.7699      
11 한식        11 252.1547      
12 한식        12 250.6891      

arrange

그 다음에 내림차순 정렬이니 desc를 쓴 arrange를 해주면 된다. 월별 평균 판매건수를 정렬해주면 된다.

sales %>%
    filter(products.nm == '한식') %>%
    mutate(m = substr(ymd, 5, 6)) %>%
    group_by(products.nm, m) %>%
    summarise(mean.sales.num = mean(sales.num, na.rm = T)) %>%
    arrange(desc(mean.sales.num))
   products.nm m  mean.sales.num
1  한식        01 253.7554      
2  한식        09 253.0379      
3  한식        02 252.7710      
4  한식        11 252.1547      
5  한식        05 251.9256      
6  한식        12 250.6891      
7  한식        03 250.3631      
8  한식        06 250.1250      
9  한식        04 249.7209      
10 한식        07 249.2496      
11 한식        08 249.2152      
12 한식        10 246.7699      

3번 문제

매출데이터에서 월별 & 구별 & 업종(products.nm)별 평균 판매 건수와 평균 강수량을 구하세요. 단, 평균 판매 건수와 평균 강수량이 NA인 것은 제외하세요.

판매 데이터에 월 변수가 없기 때문에 mutate을 사용해 월 변수를 만들고, group_by를 사용하여 월별 구별 업종별이 다 들어가기 때문에 넣어준다.

그리고 summarise를 하여 평균 판매건수, 평균 강수량을 구한다.

sales %>%
    mutate(m = substr(ymd, 5, 6)) %>%
    group_by(m, district, products.nm) %>%
    summarise(mean.sales.num = mean(sales.num, na.rm = T),
              mean.rainfall = mean(rainfall, na.rm = T))
     m   district products.nm mean.sales.num mean.rainfall
1    01  강남구   NA          275.4787       NaN          
2    01  강남구   완구        239.6862       NaN          
3    01  강남구   유아용품    266.5385       NaN          
4    01  강남구   카페        249.7489       NaN          

NA 처리

코드 뒤에 filter를 하여 is.na로 평균 판매건수와 평균 강수량에서 NA값을 제외한다.

sales %>%
    mutate(m = substr(ymd, 5, 6)) %>%
    group_by(m, district, products.nm) %>%
    summarise(mean.sales.num = mean(sales.num, na.rm = T),
              mean.rainfall = mean(rainfall, na.rm = T)) %>%
    filter(!is.na(mean.sales.num) & !is.na(mean.rainfall))
     m   district products.nm mean.sales.num mean.rainfall
1    01  강북구   NA          254.6341         0          
2    01  강북구   완구        250.7737         0          
3    01  강북구   유아용품    230.0101         0          
4    01  강북구   카페        271.1531         0          

4번 문제

3번의 결과에서 평균 강수량mean.rainfall을 250 이상은 '상', 50 ~ 250은 '중', 50미만은 '하'로 바꾸어 새로운 변수에 저장하세요.

mutate, ifelse

위의 코드를 붙여놓고 mutate로 새로운 변수를 만들어준다. 조건이 들어가기 때문에 ifelse를 사용한다. 250보다 크면 '상', 그게 아닐 때는 조건을 하나 더 줄 수 있다. 250보다 작은 경우에 한해서 50보다 크면 '중' 아니면 '하'로 한다.

sales %>%
    mutate(m = substr(ymd, 5, 6)) %>%
    group_by(m, district, products.nm) %>%
    summarise(mean.sales.num = mean(sales.num, na.rm = T),
              mean.rainfall = mean(rainfall, na.rm = T)) %>%
    filter(!is.na(mean.sales.num) & !is.na(mean.rainfall)) %>%
    mutate(rainfall.grade = ifelse(mean.rainfall >= 250, '상',
                                   ifelse(mean.rainfall >= 50, '중', '하')))
     m   district products.nm mean.sales.num mean.rainfall rainfall.grade
1    01  강북구   NA          254.6341         0           하            
2    01  강북구   완구        250.7737         0           하            
3    01  강북구   유아용품    230.0101         0           하            
4    01  강북구   카페        271.1531         0           하            

5번 문제

4번 결과에서 평균 강수량 등급(rainfall.grade) 별 평균 판매건수(mean.sales.num)의 평균을 다시 구해보세요.

group_by, summarise

강수량 등급rainfall.gradegroup_by로 묶어주고 summarise로 평균 판매건수와 강수량을 구한다.

sales %>%
    mutate(m = substr(ymd, 5, 6)) %>%
    group_by(m, district, products.nm) %>%
    summarise(mean.sales.num = mean(sales.num, na.rm = T),
              mean.rainfall = mean(rainfall, na.rm = T)) %>%
    filter(!is.na(mean.sales.num) & !is.na(mean.rainfall)) %>%
    mutate(rainfall.grade = ifelse(mean.rainfall >= 250, '상',
                                   ifelse(mean.rainfall >= 50, '중', '하'))) %>%
    group_by(rainfall.grade) %>%
    summarise(mean.mean.sales.num = mean(mean.sales.num, na.rm = T))
  rainfall.grade mean.mean.sales.num
1 상             248.6016           
2 중             250.7814           
3 하             250.9025           

코드를 효과적으로 짜기

3번을 mean.sales변수에 저장하고 거기에 chain을 하여 뒷 단계를 할 수 있다.

mean.sales <- sales %>%
    mutate(m = substr(ymd, 5, 6)) %>%
    group_by(m, district, products.nm) %>%
    summarise(mean.sales.num = mean(sales.num, na.rm = T),
              mean.rainfall = mean(rainfall, na.rm = T)) %>%
    filter(!is.na(mean.sales.num) & !is.na(mean.rainfall))

변수를 만들고 다시한번 밑에서 작업을 해도 큰 무리가 없다.

mean.sales %>%
    mutate(rainfall.grade = ifelse(mean.rainfall >= 250, '상',
                                   ifelse(mean.rainfall >= 50, '중', '하'))) %>%
    group_by(rainfall.grade) %>%
    summarise(mean.mean.sales.num = mean(mean.sales.num, na.rm = T))
  rainfall.grade mean.mean.sales.num
1 상             248.6016           
2 중             250.7814           
3 하             250.9025