가족 ID 부여
생존 확률의 예측값을 가족 단위로 모으기 위해 어떤 탑승객이 누구와 가족인지를 알아보자. ticket이 이에 적당한 속성임을 앞서 확인했으므로 티켓 번호별로 가족 ID를 부여할 것이다. 이런 작업에는 plyr이 매우 유용하다.
family_idx <- 0 ticket_based_family_id <- ddply(all, .(ticket), function(rows) { family_idx <<- family_idx + 1 return(data.frame(family_id=paste0("TICKET_", family_idx))) })
이 코드에서 가장 핵심적인 부분은 ddply( )다. ddply( )에서 all(훈련 데이터와 검증 데이터를 모두 모은 데이터 프레임)은 .(ticket)에 의해 같은 ticket 값을 가지는 행끼리 그룹으로 묶이며, 같은 티켓 번호를 가지는 행들은 뒤에 따르는 함수에 rows란 이름으로 전달된다. ddply( )에 인자로 주어진 함수에서는 family_idx를 1 증가시킨 뒤3 이를 family_id라는 컬럼에 TICKET_family_id 형태로 저장한다. 문자열을 합치는 데는 인자로 주어진 문자열들을 공백 없이 합치는 paste0( )을 사용했다.
ddply( )에 인자로 넘어간 rows의 값을 보고 싶거나 인자로 주어진 함수의 동작을 한 행씩 확인해보고 싶다면, browser( )를 사용하거나 유닛 테스팅 testthat을 사용해 검증하면 코딩을 좀 더 쉽게 할 수 있으니 참고하기 바란다.
첫 번째 폴드에 대해 위 코드를 수행한 결과 ticket_based_family_id에는 다음과 같은 데이터 프레임이 저장된다.
> str(ticket_based_family_id) 'data.frame': 861 obs. of 2 variables: $ ticket : chr "110152" "110413" "110465" "110469" ... $ family_id: Factor w/ 861 levels "TICKET_1","TICKET_2",..: 1 2 3 4 5 6 7 8 9 10 ... > head(ticket_based_family_id) ticket family_id 1 110152 TICKET_1 2 110413 TICKET_2 3 110465 TICKET_3 4 110469 TICKET_4 5 110489 TICKET_5 6 110564 TICKET_6
이제 all 데이터 프레임에 ticket 값에 따라 family_id를 추가할 차례다. all$ticket을 보면서 ticket_based_family_id로부터 family_id를 찾아 all$family_id에 저장하면 된다.
all <- adply(all, 1, function(row) { family_id <- NA if (!is.na(row$ticket)) { family_id <- subset(ticket_based_family_id, ticket == row$ticket)$family_id } return(data.frame(family_id=family_id)) })
adply( )를 all 데이터에 .margins=1 인자와 함께 호출했다. .margins=1은 각 행마다 호출됨을 뜻하고 .margins=2는 각 컬럼마다 호출된다. 따라서 뒤따라 나온 함수의 인자 row에는 all의 각 행이 전달된다. adply( )에 인자로 주어진 함수는 ticket_based_family_id에서 row$ticket과 같은 ticket 값을 가지는 행을 찾고, 해당 행의 family_id를 family_id 변수에 저장한다. 최종적으로 family_id는 함수에서 데이터 프레임으로 반환된다. adply( )는 이 반환 값을 all 데이터 프레임에 새로운 컬럼으로 추가해 반환하므로 이를 all에 저장하면 family_id가 추가된 all을 얻을 수 있다.
다음은 첫 번째 폴드에 앞의 코드를 수행한 결과 구해진 all 데이터 프레임의 구조다.
> str(all)
'data.frame': 1178 obs. of 14 variables:
$ pclass : Factor w/ 3 levels "1","2","3": 1 1 1 1 1 1 1 1 1 1 ...
$ survived : Factor w/ 2 levels "dead","survived": 2 1 1 2 2 1 2 1 1 2 ...
$ name : chr "Allen, Miss. Elisabeth Walton" "Allison, Mr. Hudson Joshua Creighton" "Allison, Mrs. Hudson J C (Bessie Waldo Daniels)" "Anderson, Mr. Harry" ...
$ sex : Factor w/ 2 levels "female","male": 1 2 1 2 1 2 1 2 2 1 ...
$ age : num 29 30 25 48 63 39 53 71 47 18 ...
$ sibsp : int 0 1 1 0 1 0 2 0 1 1 ...
$ parch : int 0 2 2 0 0 0 0 0 0 0 ...
$ ticket : chr "24160" "113781" "113781" "19952" ...
$ fare : num 211.3 151.6 151.6 26.6 78 ...
$ cabin : chr "B5" "C22 C26" "C22 C26" "E12" ...
$ embarked : Factor w/ 3 levels "C","Q","S": 3 3 3 3 3 3 3 1 1 1 ...
$ type : chr "T" "T" "T" "T" ...
$ prob : num 0.0547 0.6857 0.0547 0.6857 0.0547 ...
$ family_id: Factor w/ 861 levels "TICKET_1","TICKET_2",..: 176 47 47 118 86 16 71 766 774 774 ...
3 family_idx가 함수 외부에 선언된 변수므로 <<-를 사용한 할당문을 사용했다.