함수 만들기
R에서 함수는 일급 객체입니다. 변수에 담을 수 있고, 다른 함수에 인자로 넘길 수 있습니다. 직접 함수를 만들 줄 알면 반복되는 분석 코드를 깔끔하게 정리할 수 있습니다.
function()으로 함수 만들기
# 파일: 04_functions.R
add <- function(x, y) {
x + y
}
add(3, 5) # 8
R에서 함수의 반환값은 마지막으로 평가된 표현식입니다. return()을 명시하지 않아도 됩니다. 물론 명시해도 됩니다.
add <- function(x, y) {
result <- x + y
return(result) # 명시적 반환
}
중간에 조건부로 반환할 때는 return()을 씁니다.
safe_divide <- function(x, y) {
if (y == 0) {
return(NA) # 0으로 나누면 NA 반환
}
x / y
}
safe_divide(10, 2) # 5
safe_divide(10, 0) # NA
기본값 설정
인자에 기본값을 주면 생략 가능한 인자가 됩니다.
greet <- function(name, greeting = "안녕하세요") {
cat(greeting, name, "\n")
}
greet("Alice") # 안녕하세요 Alice
greet("Bob", "반갑습니다") # 반갑습니다 Bob
기본값이 있는 인자는 없는 인자 뒤에 오는 것이 관례입니다.
# 좋은 패턴
describe <- function(x, digits = 2, na.rm = TRUE) {
round(mean(x, na.rm = na.rm), digits)
}
scores <- c(85.5, 92.3, NA, 78.8, 95.1)
describe(scores) # 87.93
describe(scores, digits = 0) # 88
describe(scores, na.rm = FALSE) # NA
인자 이름으로 호출
R에서는 인자 이름을 명시하면 순서와 상관없이 값을 넘길 수 있습니다.
power <- function(base, exponent) {
base ^ exponent
}
power(2, 10) # 1024
power(base = 2, exponent = 10) # 1024
power(exponent = 10, base = 2) # 1024 — 순서 달라도 됨
인자가 여러 개일 때 이름을 명시하면 코드가 읽기 쉬워집니다.
가변 인자 ...
인자 개수가 정해지지 않을 때 ...를 씁니다.
my_sum <- function(...) {
args <- c(...)
sum(args)
}
my_sum(1, 2, 3) # 6
my_sum(1, 2, 3, 4, 5) # 15
...는 내부 함수에 그대로 전달할 수도 있습니다. 래퍼 함수를 만들 때 유용합니다.
my_mean <- function(x, ...) {
mean(x, ...) # na.rm 같은 추가 인자를 그대로 전달
}
scores <- c(85, NA, 92, NA, 78)
my_mean(scores) # NA
my_mean(scores, na.rm = TRUE) # 85
...로 받은 인자를 리스트로 보려면 list(...)를 씁니다.
show_args <- function(...) {
args <- list(...)
for (i in seq_along(args)) {
cat(i, ":", args[[i]], "\n")
}
}
show_args(10, "hello", TRUE)
# 1 : 10
# 2 : hello
# 3 : TRUE
여러 값 반환
R 함수는 값 하나만 반환할 수 있습니다. 여러 값을 반환하려면 리스트에 담아 반환합니다.
stats <- function(x, na.rm = TRUE) {
list(
mean = mean(x, na.rm = na.rm),
sd = sd(x, na.rm = na.rm),
min = min(x, na.rm = na.rm),
max = max(x, na.rm = na.rm),
n = sum(!is.na(x))
)
}
scores <- c(85, 92, 78, 95, NA, 88)
result <- stats(scores)
result$mean # 87.6
result$n # 5
익명 함수
이름 없이 바로 쓰는 함수입니다. 다른 함수에 인자로 넘길 때 자주 씁니다.
# apply 계열과 함께
scores_list <- list(c(85, 92, 78), c(70, 65, 80))
sapply(scores_list, function(x) mean(x)) # 85.0 71.7
# 한 번만 쓸 때 바로 호출
(function(x, y) x + y)(3, 5) # 8
R 4.1부터는 \(x) 형태의 단축 문법을 씁니다.
sapply(scores_list, \(x) mean(x)) # R 4.1+ 단축 문법
함수를 인자로 넘기기
R에서 함수는 변수처럼 다룰 수 있습니다.
apply_fn <- function(x, fn) {
fn(x)
}
scores <- c(85, 92, 78, 95, 88)
apply_fn(scores, mean) # 87.6
apply_fn(scores, sum) # 438
apply_fn(scores, max) # 95
apply_fn(scores, \(x) round(mean(x), 1)) # 87.6
스코프 — 변수의 유효 범위
함수 안에서 만든 변수는 함수 밖에서 보이지 않습니다.
outer_val <- 10
my_func <- function() {
inner_val <- 20
cat(outer_val, "\n") # 10 — 외부 변수는 읽을 수 있음
}
my_func()
cat(inner_val, "\n") # 오류 — inner_val은 함수 밖에서 없음
<<-를 쓰면 상위 환경의 변수를 수정할 수 있습니다. 그러나 부작용이 생기기 쉬우므로 신중하게 씁니다.
counter <- 0
increment <- function() {
counter <<- counter + 1 # 전역 변수 수정
}
increment()
increment()
counter # 2
재귀 함수
함수가 자기 자신을 호출합니다.
factorial <- function(n) {
if (n <= 1) return(1)
n * factorial(n - 1)
}
factorial(5) # 120
R에서는 깊은 재귀가 느릴 수 있습니다. 반복문이나 내장 함수(factorial())가 있다면 그쪽을 쓰는 것이 좋습니다.
함수 문서화
함수를 만들 때 주석으로 설명을 남겨두면 나중에 다시 봤을 때 빠르게 이해할 수 있습니다.
# 성적 통계를 계산합니다.
#
# @param scores numeric 벡터 — 점수 데이터
# @param na.rm logical — NA 제거 여부 (기본값: TRUE)
# @return list — mean, sd, min, max, n 포함
#
summarize_scores <- function(scores, na.rm = TRUE) {
list(
mean = mean(scores, na.rm = na.rm),
sd = sd(scores, na.rm = na.rm),
min = min(scores, na.rm = na.rm),
max = max(scores, na.rm = na.rm),
n = sum(!is.na(scores))
)
}
패키지를 만들 계획이라면 roxygen2 스타일 주석(#')을 쓰면 자동으로 문서가 생성됩니다.