티스토리 뷰
교차 테이블로 데이터 구조 변경
1. stack()과 unstack() : 비교적 간단한 구조의 변경
stack() 함수와 unstack() 함수를 사용하여 데이터 구조를 변경해보았었습니다.
> m1 <- read.csv('melt_ex.csv')
> d1 <- read.csv('dcast_ex1.csv')
> d2 <- read.csv('dcast_ex2.csv')
> head(m1)
year mon latte americano mocha
1 2000 1 400 482 298
2 2000 2 401 483 299
3 2000 3 402 484 300
...
> head(d1)
year name info value
1 2000 latte qty 100
2 2000 mocha qty 80
3 2000 latte price 2200
...
> head(d2)
year name qty price
1 2000 latte 100 1200
2 2000 mocha 80 2200
3 2000 americano 200 1000
...
# stack()함수는 모든 컬럼을 동일하게 두 개의 컬럼으로 만들어 줍니다.
> stack(m1) # 이미 쌓여진(stacked) 컬럼(year, mon)까지 모두 stack 처리해버립니다.
values ind 컬럼 고정 불가. (스택 처리를 하지 않아도 되는 컬럼 제외 불가)
1 2000 year
2 2000 year
...
25 1 mon
26 2 mon
...
49 400 latte
50 401 latte
...
73 482 americano
...
97 298 mocha
98 299 mocha
...
2. reshape2::melt()와 reshape2::dcast() : (다양한 옵션을 사용하여)교차 테이블 만들기 중요@@@
# 데이터의 모양을 바꾸거나 그룹별 요약 값을 계산하는 함수들을 담고 있는 패키지
> install.packages('reshape2')
> library(reshape2)
2-1) melt : stack()함수처럼 동일 관측치의 값이 각 컬럼으로 분리되어 있는 경우 차곡차곡 쌓는 형식입니다.
melt()함수는 stack()함수와 달리 일부 컬럼 고정(제외) 나머지 컬럼을 stack 처리할 수 있는 것이 melt 함수의 특징입니다.
주로 Join, group by에서 그룹 연산을 위해 주로 사용합니다.
melt(data, # 원본 데이터
id, # 고정 컬럼
measure.var) # stack처리 할 컬럼(생략 시 id컬럼 제외 모든 컬럼)
> library(reshape2)
> head(m1)
year mon latte americano mocha
1 2000 1 400 482 298
2 2000 2 401 483 299
3 2000 3 402 484 300
...
> melt_d1 <- melt(m1, id=c('year','mon')) # year, mon 컬럼을 제외하고 stack 처리
> melt_d1[order(melt_d1$year, melt_d1$mon),] # 함수 결과를 year, mon 순으로 정렬
year mon variable value
1 2000 1 latte 400
25 2000 1 americano 482
...
4 2000 4 latte 403
28 2000 4 americano 485
...
10 2000 10 latte 409
34 2000 10 americano 491
...
36 2000 12 americano 493
60 2000 12 mocha 309
...
37 2001 1 americano 494
61 2001 1 mocha 310
...
22 2001 10 latte 421
46 2001 10 americano 503
...
47 2001 11 americano 504
71 2001 11 mocha 320
...
> head(m1)
year mon latte americano mocha
1 2000 1 400 482 298
2 2000 2 401 483 299
3 2000 3 402 484 300
...
> melt(m1, id=c('year','mon'), measure.vars = 'latte') # latte 데이터만 stack 처리
year mon variable value
1 2000 1 latte 400
2 2000 2 latte 401
...
11 2000 11 latte 410
12 2000 12 latte 411
13 2001 1 latte 412
14 2001 2 latte 413
15 2001 3 latte 414
...
23 2001 11 latte 422
24 2001 12 latte 423
2-2) dcast : unstack 함수처럼 이미 쌓여진(stacked) 컬럼을 각 항목별로 분리하기 위해 사용합니다.
그래프 작성, 분석, 시각화에 필요한 교차 테이블 작성이 가능합니다. 각 row와 column을 지정 가능하고, 품목별 가격, 품목별 수량 과 같이 표현할 수 있습니다.
dcast(data, # 원본 데이터
formula, # 행 고정 ~ unstack 처리 컬럼
fun.aggregate = NULL, # 데이터 축약 시 사용 (그룹,결합)함수(default:length)
margins = NULL, # 부분합 출력 시 TRUE
value.var = guess_value(data)) # value 컬럼 지정(분리 할 컬럼), 생략 가능, 생략 시 마지막 컬럼 지정
# 의미없이 쌓여진 컬럼을 서로 다른 각 컬럼으로 분리합니다.
> head(d1)
year name info value
1 2000 latte qty 100
2 2000 mocha qty 80
3 2000 latte price 2200
...
# 품목별 price와 qty 교차 테이블
# 고정시키고자하는 컬럼(name), 분리 컬럼(info), 값을 담고자하는 대상(value)
> dcast(d1, name ~ info) # 맨 마지막 컬럼(value)을 자동으로 지정
name price qty
1 latte 2200 100
2 mocha 2500 80
# d1 데이터로 년도별 price와 qty의 총 합을 나타내는 교차 테이블 (하나의 쉘에 다수에 값이 포함될 경우 그룹 함수가 필요)
> dcast(d1, year ~ info) # 데이터 축약 발생 시 default로 데이터의 수 출력
Aggregation function missing: defaulting to length
year price qty
1 2000 2 2
> dcast(d1, year ~ info, fun.aggregate = sum)
year price qty
1 2000 4700 180
# d2 데이터로 년도별, 품목별 교차 테이블 작성
> head(d2)
year name qty price
1 2000 latte 100 1200
2 2000 mocha 80 2200
3 2000 americano 200 1000
> dcast(d2, year ~ name) # value.var 생략 시 자동으로 마지막 컬럼 선택
Using price as value column: use value.var to override.
year americano latte mocha
1 2000 1000 1200 2200
2 2001 1100 1250 2300
> dcast(d2, year ~ name, value.var = 'qty') # 단점: 종종 컬럼 지정 시 '따움표가 필요할 떄가 있음..
year americano latte mocha
1 2000 200 100 80
2 2001 210 120 70
# 행별, 열별 부분합 출력
> dcast(d2, year ~ name, margins = TRUE) # margins 사용 시 그룹 함수 지정 필요, 생략 시 데이터의 수 출력
Using price as value column: use value.var to override.
Aggregation function missing: defaulting to length
year americano latte mocha (all)
1 2000 1 1 1 3
2 2001 1 1 1 3
3 (all) 2 2 2 6
> dcast(d2, year ~ name, margins = TRUE, fun.aggregate = sum) # 부분합으로 주로 sum 사용
Using price as value column: use value.var to override.
year americano latte mocha (all)
1 2000 1000 1200 2200 4400
2 2001 1100 1250 2300 4650
3 (all) 2100 2450 4500 9050
# 참고 : dcast의 포뮬러에 컬러 추가
# dcast의 formula에 고정 대상을 + 로 추가 가능
> sales <- read.csv("sales.csv", stringsAsFactors = F)
> sales
날짜 지점 품목 판매량
1 2018-01-01 c1 냉장고 899
2 2018-01-01 c1 TV 859
...
15 2018-01-02 c1 세탁기 234
16 2018-01-02 c1 에어컨 645
...
28 2018-01-03 c1 에어컨 493
29 2018-01-03 c2 냉장고 457
...
35 2018-01-03 c2 세탁기 453
36 2018-01-03 c2 에어컨 234
> library(reshape2)
> dcast(sales, 날짜 ~ 품목, fun.aggregate = sum) # 날짜별, 품목 판매량 교차 테이블
Using 판매량 as value column: use value.var to override.
날짜 TV 냉장고 세탁기 에어컨
1 2018-01-01 2236 2588 1189 2114
2 2018-01-02 1144 1642 1733 1556
3 2018-01-03 1554 1536 1142 1362
> dcast(sales, 날짜 + 지점 ~ 품목, fun.aggregate = sum) # 날짜+지점별, 품목 판매량 교차 테이블
Using 판매량 as value column: use value.var to override.
날짜 지점 TV 냉장고 세탁기 에어컨
1 2018-01-01 c1 859 899 453 400
2 2018-01-01 c2 1377 1689 736 1714
3 2018-01-02 c1 345 565 234 645
4 2018-01-02 c2 799 1077 1499 911
5 2018-01-03 c1 454 845 545 493
6 2018-01-03 c2 1100 691 597 869
> dcast(sales, 날짜 ~ 지점 + 품목, fun.aggregate = sum) # 날짜별, 지점+품목 판매량 교차 테이블
Using 판매량 as value column: use value.var to override.
날짜 c1_TV c1_냉장고 c1_세탁기 c1_에어컨 c2_TV c2_냉장고 c2_세탁기 c2_에어컨
1 2018-01-01 859 899 453 400 1377 1689 736 1714
2 2018-01-02 345 565 234 645 799 1077 1499 911
3 2018-01-03 454 845 545 493 1100 691 597 869
# 파이썬에서는 멀티컬럼으로 출력 가능하지만 R에서는 멀티컬럼이 불가하여 컬럼을 자동으로 결합하여 컬럼화합니다.
고로, R에서는 잘 사용되지 않음 (파이썬은 상하위 레벨 정리가 가능)
Q. deep
# melt, dcast 심화 문제
# 1. 상반기사원별월별실적현황_new.csv 파일을 읽고
> emp_result <- read.csv("상반기사원별월별실적현황_new.csv", stringsAsFactors = F)
> str(emp_result)
> head(emp_result)
이름 월 실적금액 목표금액 성취도
1 박동주 1 100 100 1.00
2 박동주 2 85 100 0.85
3 박동주 3 75 100 0.75
4 박동주 4 98 100 0.98
5 박동주 5 92 100 0.92
6 박동주 6 97 100 0.97
# 각 사원별 월별 성취율의 비교하기위해 아래와 같은 교차테이블 형태로 변경
# 1 2 3 4 5 6
#박동주 1 0.85 0.75 0.98 0.92 0.97
#최경우 0.90 0.92 0.68 0.87 0.89 0.89
> library(reshape2)
> res1 <- dcast(emp_result, 이름 ~ 월)
Using 성취도 as value column: use value.var to override.
> rownames(res1) <- res1$이름 # 이름을 행 번호로
> res1 <- res1[,-1]
> res1
1 2 3 4 5 6
김지수 0.78 0.86 1.00 0.91 0.95 0.91
박동주 1.00 0.85 0.75 0.98 0.92 0.97
박지영 0.70 0.97 1.10 0.86 0.90 0.79
윤정웅 0.95 1.01 0.89 0.85 0.79 0.89
이동근 0.92 0.83 0.79 0.96 0.79 0.95
주시현 0.85 0.91 0.97 0.69 0.87 0.86
최경우 0.90 0.92 0.68 0.87 0.89 0.89
############################################################
#2. sales.csv 파일을 읽고
> sales <- read.csv("sales.csv", stringsAsFactors = F)
> str(sales)
> head(sales)
날짜 지점 품목 판매량
1 2018-01-01 c1 냉장고 899
2 2018-01-01 c1 TV 859
3 2018-01-01 c1 세탁기 453
4 2018-01-01 c1 에어컨 400
5 2018-01-01 c2 냉장고 695
6 2018-01-01 c2 TV 920
#1) 지점별 품목별 판매량의 요약 정보 출력
> dcast(sales, 지점 ~ 품목, fun.aggregate = sum) # 그룹함수의 결과를 표현하기 위해 fun.aggregate 옵션 필요
Using 판매량 as value column: use value.var to override.
지점 TV 냉장고 세탁기 에어컨
1 c1 1658 2309 1232 1538
2 c2 3276 3457 2832 3494
#2) 날짜별 각 품목별 판매량의 총합 출력
> dcast(sales, 날짜 ~ 품목, fun.aggregate = sum)
Using 판매량 as value column: use value.var to override.
날짜 TV 냉장고 세탁기 에어컨
1 2018-01-01 2236 2588 1189 2114
2 2018-01-02 1144 1642 1733 1556
3 2018-01-03 1554 1536 1142 1362
###########################################################
#3. 연령별실업률_40~49세.csv 파일을 읽고
> unemp <- read.csv("연령별실업율_40-49세.csv", stringsAsFactors = F)
> str(unemp)
> unemp
월 X2014년 X2015년 X2016년 X2017년 X2018년
1 1 4.0 4.3 2.4 2.0 2.2
2 2 4.5 4.5 2.5 2.1 2.6
3 3 3.9 4.1 2.5 2.2 2.8
4 4 3.6 3.3 2.1 2.1 2.3
5 5 3.4 2.7 2.0 2.2 2.2
6 6 3.3 2.4 1.8 2.2 2.0
...
> popul <- read.csv("data.csv", stringsAsFactors = F)
> str(popul)
> popul
년도 월 총구직자수
1 2014 1 7228
2 2014 2 8888
...
22 2015 10 9412
23 2015 11 7708
...
33 2016 9 8434
34 2016 10 5171
...
46 2017 10 6464
47 2017 11 5106
...
59 2018 11 6791
60 2018 12 7534
#1) 각 년도별 실업자 수의 총 합 출력
#(실업자/총구직인구 * 100 = 실업률)
#(단, 각 날짜별 총구직인구는 data.csv파일에 있다)
> library(stringr)
> colnames(unemp)[-1] <- substr(colnames(unemp)[-1],2,5) # 컬럼명 먼저 변경 ('x2018' -> '2008')
> library(reshape2)
> unemp2 <- melt(unemp, '월') # 월 기준으로 stack
> unemp2
월 variable value
1 1 2014 4.0
2 2 2014 4.5
...
15 3 2015 4.1
...
27 3 2016 2.5
...
39 3 2017 2.2
...
53 5 2018 2.2
...
> result <- merge(popul, unemp2, by.x = c('년도','월'), by.y = c('variable','월')) # 데이터 조인
> result
년도 월 총구직자수 value
1 2014 1 7228 4.0
...
13 2015 1 8051 4.3
...
30 2016 3 9623 2.5
...
41 2017 2 5637 2.1
...
54 2018 3 6732 2.8
...
> result$실업자수 <- round(result$총구직자수 * result$value / 100) # 실업자 수 연산 후 컬럼에 추가
> aggregate(실업자수 ~ 년도, result, sum) # 연도별 실업자 수의 합 (aggregate 사용)
년도 실업자수
1 2014 3161
2 2015 2796
3 2016 1844
4 2017 1874
5 2018 1965
> library(plyr)
> ddply(result, .(년도), summarise, sum=sum(실업자수)) # 연도별 실업자 수의 합 (ddply 사용)
년도 sum
1 2014 3161
2 2015 2796
3 2016 1844
4 2017 1874
5 2018 1965
참고: KIC 캠퍼스 머신러닝기반의 빅데이터분석 양성과정
'R > Process' 카테고리의 다른 글
[R] n번째 이전(이후) 행의 값 가져오기 - data.table::shift() (0) | 2019.01.12 |
---|---|
[R] 데이터 내 NA를 이전 행의 값으로 치환하기 (0) | 2019.01.09 |
[R] R에서 SQL문법으로 데이터 조작하기 - sqldf 패키지 (0) | 2019.01.08 |
[R] plyr 패키지로 그룹(join) 연산 하기 - adply(), ddply() 함수 (0) | 2019.01.08 |
[R] 그룹 연산 - tapply, aggregate 함수 (0) | 2019.01.08 |