아래의 예제와 같이 콤마로 구분되어 있는 문자형 변수(caracter variable with comma seperator delimiter)를 가진 데이터 프레임이 있다고 합시다.
두번째의 item 변수에 콤마로 구분되어 들어있는 다수의 항목들을 구분자 콤마(',')를 기준으로 분리(split)한 후에 => 이를 동일한 name을 key로 해서 세로로 주욱~ 늘여서 재구조화하여야 할 필요가 생겼다고 합시다.
데이터 구조변환의 전/후 모습을 말로 설명하려니 좀 어려운데요, 아래의 'Before (original dataset) => After (transformation)' 의 그림을 참고하시기 바랍니다.
이걸 R로 하는 방법을 소개합니다.
먼저 위의 Before 모양으로 간단한 데이터 프레임을 만들어보았습니다.
# (1) creating sample dataframe name_2 <- c("Jane") name_3 <- c("Tom") tr_1 <- cbind(name_1, item_1)
# rename
#------------- > mart name item 1 John Apple,Banana,Mango 2 Jane Banana,Kiwi,Tomato,Mango 3 Tom Apple,Tomato,Cherry,Milk,IceCream |
위의 mart 라는 이름의 'Before' 데이터프레임을 'After' 모양의 데이터 프레임으로 구조 변환시키는 절차 및 R script는 아래와 같습니다.
[ 문자형 분리(split) 및 데이터 재구조화(reshape) 절차 ]
(1) mart_new <- data.table() : mart_new 라는 비어있는 데이터 테이블, 데이터 프레임을 생성 (<= 여기에 차곡차곡 loop돌린 결과를 rbind()로 쌓아가게 됨)
(2) n <- nrow(mart) : original dataset인 mart 의 총 행의 개수(nrow(mart))를 n 이라는 벡터로 할당 (<= 이 개수만큼 loop를 돌릴겁니다. 위 예제는 총 3개군요. John, Jane, Tom 이렇게요)
(3) for (i in 1:n) : 1부터 n (즉, 3)까지 반복 수행 <= 매 행별로 아래의 문자열을 구분자를 기준으로 분리 후 세로로 재구조화하는 작업을 반복할 겁니다
(4) print(i) : 반복수행 loop 문이 어디쯤 돌고 있나 콘솔 창에서 확인하려고 집어넣었습니다. 굳이 없어도 됩니다.
(5) name_index <- as.character(mart[i, 1]) : i번째 행(row)의 1번째 열("name")을 indexing 해옵니다. 즉, i의 순서 1, 2, 3 별로 "John", "Jane", "Tom", 이렇게 순서대로 indexing 해옵니다.
(6) item_index <- as.character(mart[i, 2]) : i번째 행(row)의 2번째 열("item")을 indexing 해옵니다.
(7) item_index_split_temp <- data.frame(strsplit(item_index, split = ',')) : (6)번에서 i번째 행별로 indexing해 온 item을 구분자 'comma (',')'를 기준으로 문자열을 분리(split)한 후에, 이것을 데이터 프레임으로 생성합니다.
(8) mart_temp <- data.frame(cbind(name_index, item_index_split_temp)) : (5)번과 (7)번 결과물을 cbind()로 묶은 후에, 이것을 데이터 프레임으로 생성합니다. cbind()로 결합할 때 name은 1개인데 item이 2개 이상일 경우에는 1개밖에 없는 name이 자동으로 반복으로 item의 개수만큼 재할당이 됩니다.
(9) names(mart_temp) <- c("name", "item") : mart_temp의 변수 이름을 첫번째 변수는 "name", 두번째 변수는 "item"으로 지정해줍니다.
(10) mart_new <- rbind(mart_new, mart_temp) : (1)번에서 생성한 (처음에는 비어있는) 데이터프레임에 loop를 돌 때마다 생성이되는 (8, 9)번 데이터프레임을 차곡 차곡 rbind()로 반복적으로 쌓아줍니다.
(11) rm(name_index, item_index, item_index_split_temp, mart_temp) : 중간 임시 데이터셋 삭제
끝.
[ R script ]
# (2) splitting charater by delimeter, reshaping data structure by loop programming install.packages("data.table") mart_new <- data.table() # blank data.table
n <- nrow(mart) # total number of rows
for (i in 1:n){ print(i) # to check progress rm(name_index, item_index, item_index_split_temp, mart_temp) # delete temp dataset
# ---------------- > mart_new name item 1: John Apple 2: John Banana 3: John Mango 4: Jane Banana 5: Jane Kiwi 6: Jane Tomato 7: Jane Mango 8: Tom Apple 9: Tom Tomato 10: Tom Cherry 11: Tom Milk 12: Tom IceCream |
Ashtray 님께서 댓글로 남겨주신 R script를 여러 사람이 좀더 쉽게 널리 공유할 수 있도록 아래에 공유합니다 (Ashtray님, R script 공유해주셔서 감사합니다. ^^).
구분자가 "\\^"를 기준으로 문자열을 분리하고, for loop 문을 사용해서 세로로 세워서 재구조화하는 절차는 같습니다. 대신 변수 개수가 다르다보니 for loop문이 조금 다르구요, data table이 아니라 list()를 사용했다는점도 다릅니다.
R script 짜다보면, 그리고 다른 분께서 R script 짜놓은것을 보면 "동일한 input과 동일한 output이지만 가운데 process는 방법이 단 한가지만 있는게 아니구나" 하고 저도 배우게 됩니다.
names(data) <- c("number", "PK", "Call_ID", "Keyword_Count")
|
혹시 Spark을 사용하는 분이라면 (key, value) pair RDD로 구성된 데이터셋에 대해 flatMapValues() 라는 pair operation 을 사용하면 쉽게 key를 기준으로 세로로 재구성한 RDD를 만들 수 있습니다. 참고하세요.
많은 도움이 되었기를 바랍니다.
이번 포스팅이 도움이 되었다면 아래의 '공감 ~ ♡'를 꾸욱 눌러주세요.
[Reference]
1. R 문자함수 : http://rfriend.tistory.com/37
2. R 반복 연산 loop 프로그래밍 : http://rfriend.tistory.com/90
'R 분석과 프로그래밍 > R 프로그래밍' 카테고리의 다른 글
[R] 웹사이트에서 텍스트를 가져다가 최저가 Top 10 리스트를 엑셀로 내보내기 (3) | 2018.08.06 |
---|---|
[R 프로그래밍] 반복문과 조건문을 써서 벡터에서 0이 연속 3번 나오면 구간 나누기 (6) | 2018.02.02 |
[R] 여러개의 데이터프레임을 한꺼번에 하나의 데이터프레임으로 묶기, data.table package : rbindlist(data) (8) | 2016.07.10 |
[R] 폴더 내 여러개 파일들을 Loop 돌려서 자동으로 불러오기 (154) | 2016.07.02 |
R "target of assignment expands to non-language object" error : assign() (2) | 2015.09.22 |