[R] 최빈값을 구하는 사용자 정의 함수 뜯어보기
R 프로그램에는 벡터를 대입했을 때 평균(mean)과 중앙값(median)을 출력하는 기본 내장 함수가 들어있다.
> # 자료 생성
> set.seed(82)
> x = sample(c(1, 2, 3, 4), 15, replace=TRUE)
> x
[1] 4 1 3 3 3 2 2 1 1 3 3 4 4 4 2> # 평균 구하기
> mean(x)
[1] 2.666667> # 중앙값 구하기
> median(x)
[1] 3
하지만 최빈값(mode)의 경우 기본 내장함수가 제공되지 않는데, 이 경우 function
문을 이용하여 직접 최빈값을 구하는 사용자 정의 함수를 만들어야 한다. 결론부터 보자면 최빈값을 구하는 사용자 정의 함수는 다음과 같이 만들 수 있다.
> # 최빈값 사용자 정의 함수 만들기
> getmode = function(t){
+ u = unique(t)
+ u[which.max(tabulate(match(t, u)))]
+ }> # 최빈값 구하기
> getmode(x)
[1] 3
R의 기본 내장 함수인 mode
는 객체의 내부 타입을 출력하는 함수이므로 함수명이 겹치지 않게 getmode
로 이름 지었다.
최빈값 사용자 정의 함수를 구성하는 함수들(unique
, which.max
, tabulate
, match
)의 원리를 위주로 코드를 해석해보고자 한다.
unique 함수
unique
함수는 입력 받은 벡터(또는 데이터프레임 · 배열)에서 중복되는 원소(또는 행)을 제거하는 함수다.
> x
[1] 4 1 3 3 3 2 2 1 1 3 3 4 4 4 2> u = unique(x)
> u
[1] 4 1 3 2
match 함수
match
함수는 첫번째 벡터의 원소가 두번째 벡터의 몇번째 원소와 같은지를 출력하는 함수다.
> x
[1] 4 1 3 3 3 2 2 1 1 3 3 4 4 4 2> u
[1] 4 1 3 2> match(x, u)
[1] 1 2 3 3 3 4 4 2 2 3 3 1 1 1 4
위의 예에서 벡터 x
의 원소 4 1 3 3 3 …
가 벡터 u
의 몇번째 원소와 같은지를 보면 된다. (첫번째- 4
, 두번째- 1
, 세번째- 3
, 네번째- 2
)
예를 들어보자. 첫번째 벡터 x
의 첫번째 원소 4
는 두번째 벡터 u
의 첫번째 원소와 같다. 따라서 match
함수 값은 1
이다. 마찬가지로 x
의 네번째 원소 3
은 u
의 세번째 원소와 같다. 따라서 match
함수 값의 네번째 원소는 3
이다.
벡터 u
의 몇번째 원소와 같은지를 보는 것은 벡터 u
의 인덱스를 대응하는 것과 연관이 있다.
tabulate 함수
tabulate
함수는 입력한 벡터의 원소별 빈도를 출력해주는 함수다.
> match(x, u)
[1] 1 2 3 3 3 4 4 2 2 3 3 1 1 1 4> tabulate(match(x, u))
[1] 4 3 5 3
함수의 입력값이 벡터 x = c(4, 1, 3, 3, …)
가 아닌 match(x, u)
이므로 출력값의 원소 4 3 5 3
이 각각 1 2 3 4
의 개수를 나타내는 것임에 주의하자.
which.max 함수
which.max
함수는 입력된 벡터의 원소 중 최대값의 인덱스를 출력하는 함수다.
> tabulate(match(x, u))
[1] 4 3 5 3> which.max(tabulate(match(x, u)))
[1] 3
함수의 입력값 c(4, 3, 5, 3)
의 원소 중 최대값은 5
이고 해당하는 인덱스는 3이므로 출력값으로 3
을 출력한다.
종합 및 해석
> x
[1] 4 1 3 3 3 2 2 1 1 3 3 4 4 4 2> u = unique(x)
> u
[1] 4 1 3 2> match(x, u)
[1] 1 2 3 3 3 4 4 2 2 3 3 1 1 1 4> tabulate(match(x, u))
[1] 4 3 5 3> which.max(tabulate(match(x, u)))
[1] 3>u[which.max(tabulate(match(x, u)))]
[1] 3
tabulate(x)
를 하지 않은 이유는 tabulate
함수는 입력한 벡터의 원소 중에서 오름차순으로 빈도를 표시해주기 때문이다. tabulate(x)
를 실행하면 다음과 같다.
> x
[1] 4 1 3 3 3 2 2 1 1 3 3 4 4 4 2> tabulate(x)
[1] 3 3 5 4
출력값의 3 3 5 4
는 각각 x
의 원소 (1, 2, 3, 4)의 개수지, 벡터 x
의 원소 순서인 (4, 1, 3, 2 )의 개수가 아니다.
tabulate
함수의 출력값인 각 원소의 빈도수를 u = unique(x)
의 원소 4 1 3 2
의 순서로 출력되게 하기 위해 중간에 match(x, u)
함수를 추가함으로써 (4, 1, 3, 2)를 각각 (1, 2, 3, 4)에 대응하여 변환하였다.
tabulate(match(x, u))
의 출력값 4 3 5 3
은 u
의 값인 c(4, 1, 3, 2)
의 빈도수이므로( 4
4개, 1
3개, 3
5개, 2
3개), which.max
함수로 4 3 5 3
의 최대값의 인덱스를 구하고 다시 u
에 참조한 값( u[3] = 3
)은 x
의 원소 중 가장 많은 빈도수의 원소인 최빈값을 나타낸다.
다시 한 번 최빈값을 구하는 사용자 정의 함수 코드를 적으며 포스트를 마무리한다.
> # 자료
> x
[1] 4 1 3 3 3 2 2 1 1 3 3 4 4 4 2> # 최빈값 사용자 정의 함수 만들기
> getmode = function(t){
+ u = unique(t)
+ u[which.max(tabulate(match(t, u)))]
+ }> # 최빈값 구하기
> getmode(x)
[1] 3