본문 바로가기
R/RSTAT101

[RSTAT101] 4강. 사용자 정의함수와 최빈값

by 슬통이 2023. 6. 10.
반응형

사용자 정의 함수

미국에서 생활을 하다보면 우리나라와 단위가 달라서 불편할 때가 많습니다. 그 중 하나가 바로 온도 단위입니다. 미국은 화씨(Fahrenheit, ºF)를 온도의 단위로 사용하고, 한국은 섭씨(Celsius, ºC)를 사용하기 때문입니다. 두 단위의 변환 공식은 다음과 같습니다.

(°F − 32) × 5/9 = °C

위 공식을 사용하면, 다음과 같이 화씨 89도는 섭씨로 31.7도 인 것을 알 수 있습니다.

(89 - 32) * 5/9
>> [1] 31.66667

만약 우리가 다음과 같은 화씨로 측정된 온도데이터가 5개 있다고 합니다. 이 숫자들을 섭씨로 바꾸려면, R에서는 어떻게 해야할까요?

67, 45, 92, 83, 70

가장 직관적인 방법은 다음과 같이 위의 코드를 다섯번 적용하는 것입니다.

(67 - 32) * 5/9
>> [1] 19.44444
(45 - 32) * 5/9
>> [1] 7.222222
(92 - 32) * 5/9
>> [1] 33.33333
(83 - 32) * 5/9
>> [1] 28.33333
(70 - 32) * 5/9
>> [1] 21.11111

아니면, 앞에서 배웠던 벡터형식의 코드를 쓰면 더 짧아질 수 있겠죠.

myF <- c(67, 45, 92, 83, 70)
(myF - 32) * 5/9
>> [1] 19.444444  7.222222 33.333333 28.333333 21.111111

하지만, 이러한 방법도 한계가 있습니다. 왜냐하면 매번 변환 공식을 외워야하기 때문입니다. 공식을 어디에 따로 저장하는 방법이 없을까요? 이런 경우 우리가 따로 convFtoC라는 함수를 만들어서 저장해두면 참 편리할 것입니다. 다음처럼 말이죠.

convFtoC(67)

위의 함수를 이용하면, 공식을 외울 필요도 없고, 함수가 하는 일도 명확하게 드러나게 됩니다. 이렇게 사용자가 직접 정의한 함수를 사용자 정의 함수라고 부르며, R에서는 함수를 정의할 때 다음과 같은 문법을 이용합니다.

함수명 <- function(입력값){
    결과 <- 계산 공식
    return(결과)
}

이에 따라서 convFtoC 함수를 작성해보면 다음과 같습니다.

convFtoC <- function(numF){
    result <- (numF - 32) * 5/9
    result
}

위에서 정의한 convFtoC 함수는 화씨로 측정된 온도를 입력값으로 받아 numf에 저장하고, 이를 계산 공식에 넣어서 결과를 반환합니다.

convFtoC(89)
>> [1] 31.66667
(89 - 32) * 5/9
>> [1] 31.66667

위의 두 결과를 비교해보면, 함수가 잘 작동하고 있다는 것을 알 수 있습니다.

최빈값 (Mode) 함수 만들기

최빈값은 데이터 셋에서 가장 빈도수가 높은, 즉 가장 많이 등장하는 수를 생각하면 됩니다. 최빈값을 찾기 위해서는 먼저 각 숫자별로 몇번이 등장하는지를 세어야 됩니다. 이러한 과정은 table 함수를 통하여 쉽게 할 수 있죠.

x <- c(1, 3, 9, 7, 1, 2, 2, 5, 3, 3, 3)
result <- table(x)
result
>> x
>> 1 2 3 5 7 9 
>> 2 2 4 1 1 1

위의 결과를 보면 벡터 x의 원소들 중에는 3이 네번 등장하여, 가장 많이 등장한 최빈값이 됩니다. R에서는 최빈값을 계사하는 기본 함수를 제공하기 않으므로, 사용자 정의함수를 연습하기 딱 좋은 예제가 됩니다. 한번 시도해보세요! 다음은 제가 생각하기에 가장 짧은 최빈값을 찾는 코드입니다!

statMode <- function(x){
  dataTable <- table(x)
  result <- names(sort(-dataTable)[1])
  result
}
statMode(x)
>> [1] "3"

카테고리컬 (categorical) 변수 만들기

숫자의 대소 비교

R에는 비교를 위한 유용한 연산자들이 있습니다. 예를 들어 ==를 이용하면 양 옆에 위치한 숫자들이 같은지를 물어볼 수 있죠.

1 == 2
>> [1] FALSE

>, < 를 사용해서 대소 비교도 할 수 있습니다.

1 < 2
>> [1] TRUE
3 > 2
>> [1] TRUE
5 <= 6
>> [1] TRUE
c(1, 2, 3) < 2
>> [1]  TRUE FALSE FALSE

마지막 코드는 이 연산자들을 벡터에서도 사용할 수 있다는 것을 보여주는 아주 좋은 코드일 것입니다. 이 사실을 이용해 여러가지 일들을 할 수 있죠.

a <- c(1:10)
a
>>  [1]  1  2  3  4  5  6  7  8  9 10

위에서 정의한 벡터 a의 원소들에 접근할 경우 []을 사용해야 한다는 것을 배웠습니다.

a[1:5] <- c(1, 5, 3, 2, 4)
a
>>  [1]  1  5  3  2  4  6  7  8  9 10

벡터 필터링 (filtering)

만약 특정 조건을 만족하는 원소들에 접근하고 싶을 경우에는 어떻게 해야할까요? 즉, a의 원소들에 필터 (filter)를 주고 싶은 것이죠. 예를 들어 4보다 큰 숫자들만 걸러서 접근하고 싶은 경우에 다음과 같은 코드를 쓸 수 있습니다.

a[a < 4]
>> [1] 1 3 2

왜 이런 일이 일어나는지는 a < 4 코드의 결과를 살펴봐야 합니다.

a < 4
>>  [1]  TRUE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE
>> [10] FALSE

결과를 보면 TRUE와 FALSE로 이루어진 벡터인 것을 알 수 있습니다. 즉, 이 벡터를 [] 안에 넣어주면 참에 대응하는 원소들만을 가져온 다는 것을 알 수 있습니다. 이 사실을 이용해서 특정 벡터의 값에 따른 카테고리컬 데이터를 만들어 낼 수 있습니다.

a
>>  [1]  1  5  3  2  4  6  7  8  9 10
b <- rep(0, 10) # repeat 0s 10 times
b[a < 4]  <- "low"
b[a >= 4] <- "high"
b
>>  [1] "low"  "high" "low"  "low"  "high" "high" "high"
>>  [8] "high" "high" "high"

a 벡터를 이용하여 카테고리컬 데이터인 b 벡터를 만들었습니다. 이것을 가지고 이전 시간에 배웠던 파이 차트를 그려봅시다.

mytable <- table(b)
pie(mytable, 
    labels = names(mytable),
    main="Pie Chart of categorical variable")

반응형

댓글