티스토리 뷰
함수의 정의
사용자 정의 함수 : 코드의 반복을 줄이기 위한 사용자 정의 함수
function(함수) 생성 시 반환되는 하나의 return 값이 꼭 있어야 합니다.
# 함수의 인자는 위치에 맞게 순서대로 작성하거나 이름으로 작성할 수 있습니다.
> func <- function(x,y){
print(c(x,y))
}
> func(1,2)
[1] 1 2
> func(y=2, x=1)
[1] 1 2
가변 길이 인자를 가진 함수 : 함수의 인자 개수가 정해지지 않은 경우
> func <- function(...){
list <- list(...) # 인자를 list 형식으로 저장합니다.
for(i in list) {
print(i)
}
}
> func(1,2,3,4,5)
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
가변 함수
> func <- function(x,y){
print(c(x,y))
}
> func2 <- function(a, ...){
print(a)
func(...)
}
> func2(1,2,3)
[1] 1
[1] 2 3
중첩 함수 : 함수 안에 또 다른 함수를 정의
> func <- function(x,y){
print(x)
func2 <- function(y){
print(y)
}
func2(y)
}
> func(1,2)
[1] 1
[1] 2
함수 인자의 default 값 설정
> f3 <- function(x, y=3) { # default 값 설정 (두 번째 인자 생략 시 3)
return(x + y)
}
> f3(1,1)
[1] 2
> f3(1) # 1 + 3(y=3)
[1] 4
Q.
# 연습문제
# abs함수와 동일한 사용자 정의함수를 f_abs이름으로 생성
> abs(-3) # 절대값 함수
[1] 3
> f_abs <- function(x){
if(x >0){
return(x)
} else{
return(-1 * x)
}
}
> f_abs(-3)
[1] 3
# sign함수와 동일한 사용자 정의함수를 f_sign이름으로 생성
> sign(9) # 양수면 1, 음수면 -1, 0이면 0 리턴
[1] 1
> f_sign <- function(x){
if(x >0){
return(1)
} else if(x<0){
return(-1)
} else {
return(0)
}
}
> f_sign(9)
[1] 1
Q.1
#Q1. 사용자에게 정수 n을 입력 받은 후 1 부터 n 까지의 합 출력
# if문 사용
> Nsum <- function(n){
if(n == 1){
return(1)
} else {
return(n + Nsum(n-1))
}
}
> Nsum(10)
[1] 55
# 위 함수는 재귀 함수로 동작은 다음과 같습니다.
# Nsum(10) = 10 + Nsum(9)
# = 10 + 9 + Nsum(8)
# = 10 + 9 + 8 + Nsum(7)
# = 10 + 9 + 8 + 7 ... 2 + Nsum(1)
# for문 사용
> Nsum2 <- function(n) {
+ sum <- 0
+ for(i in 1:n) {
+ sum <- sum + i
+ }
+ return(sum)
+ }
> Nsum2(10)
[1] 55
# sum() 함수 사용
> Nsum3 <- function(n){
+ return(sum(1:n))
+ }
> Nsum3(10)
[1] 55
Q.2
#Q2. 팩토리얼 계산하기
# if문 사용
> fac <- function(n){
if(n == 1){
return(1)
} else{
return(n * fac(n-1))
}
}
> fac(10)
[1] 3628800
# 위 함수는 재귀 함수로 동작은 다음과 같습니다.
# fac(10) = 10 * fac(9)
# = 10 * 9 * fac(8)
# = 10 * 9 * 8 * fac(7)
# = 10 * 9 * 8 * 7 ... 2 * fac(1)
> factorial(10) # 내장 함수 factorial과 결과값과 비교
[1] 3628800
# for문 사용
> fac2 <- function(n) {
mul <- 1
for(i in 1:n) {
mul <- mul * i
}
return(mul)
}
> fac2(10)
[1] 3628800
Q.3
# Q3. 사용자가 Y or y 를 입력하면 화면에 'Yes'를 출력하고, 그 외의 문자를 입력하면 'Not Yes'를 출력하는 사용자 정의 함수
> answer <- function(x){
if(tolower(x) == 'y'){ # if(x=='Y' | x =='y') 또는 if(x %in% c('Y','y')) 로 사용 가능
return('Yes')
} else {
return('Not Yes')
}
}
> answer('y')
[1] "Yes"
> answer('Y')
[1] "Yes"
> answer('n')
[1] "Not Yes"
Q.4
# emp 데이터를 사용, 사번을 입력하면 해당 사원의 상위관리자를 출력하는 사용자 정의함수 생성
(단, 상위관리자가 없을 경우 본인이름 출력)
> emp <- read.csv("emp.csv", stringsAsFactors = F)
> emp
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
1 7369 SMITH CLERK 7902 1980-12-17 0:00 800 NA 20
2 7499 ALLEN SALESMAN 7698 1981-02-20 0:00 1600 300 30
...
13 7902 FORD ANALYST 7566 1981-12-03 0:00 3000 NA 20
14 7934 MILLER CLERK 7782 1982-01-23 0:00 1300 NA 10
> MGR <- function(x){
+ if(is.na(emp[emp$EMPNO==x,"MGR"])){
+ return(emp[emp$EMPNO==x,"ENAME"])
+ } else {
+ return(emp[emp$EMPNO==emp[emp$EMPNO==x,"MGR"],"ENAME"])
+ }
+ }
> MGR(7369)
[1] "FORD"
> MGR(7839)
[1] "KING"
Q.5
# card_history.csv 파일을 읽고
> card <- read.csv('card_history.csv', stringsAsFactors = F)
> str(card)
> card
NUM 식료품 의복 외식비 책값 온라인소액결제 의료비
1 1 19,400 143,000 8,600 29,000 5,600 19,200
2 2 22,200 120,400 7,000 26,000 3,300 13,000
3 3 24,600 88,500 7,500 22,000 7,500 16,600
4 4 22,300 124,800 7,700 78,000 3,900 28,100
...
# num 컬럼이 지출 "일" 이라고 할 때,
# 각 일자별 각 소비품목의 지출 비율을 아래와 같이 출력
# NUM 식료품 의복 외식비 책값 온라인소액결제 의료비
# 1 8.63 63.61 3.83 12.9 2.49 8.54
# 천 단위의 문자를 숫자로 치환
> f <- function(data, c1=',', c2='') {
as.data.frame(sapply(data, str_replace_all,c1,c2))
}
> card <- f(card,',','')
> card <- data.frame(apply(card, 2, as.numeric))
> str(card) # 컬럼별로 타입을 변경시켜주는 apply함수를 사용하는 것이 바람직합니다. sapply는 행으로 전달
# 비율을 구하기 위한 사용자 정의 함수
* 사실상 apply함수는 각 원소를 기억하여 전달하므로 for문을 사용하지 않아도 연산이 가능합니다.
> f5 <- function(x) {
x / sum(x) * 100
}
> data.frame(t(apply(card[,-1], 1, f5))) # apply 함수 자체가 행별 반복 뿐만 아니라, 행 원소별 반복 가능
식료품 의복 외식비 책값 온라인소액결제 의료비
1 8.629893 63.61210 3.825623 12.900356 2.491103 8.540925
2 11.568525 62.74101 3.647733 13.548723 1.719646 6.774362
3 14.757049 53.08938 4.499100 13.197361 4.499100 9.958008
...
# for문을 사용한 경우
> f2 <- function(x) { # apply를 적용해야하므로 인자는 하나
v1 <- c()
for(i in 1:length(x)){
v1 <- c(v1, (x[i] / sum(x)) * 100)
}
return(v1)
}
> data.frame(t(apply(card[,-1], 1, f2))) # 행별 반복 수행
Q. 특정 문자 이전의 데이터를 추출하는 함수
# 1) mapply를 사용하는 방법
> f1 <- function(x, c) {
strsplit(x, c)[[1]][1]
}
> mapply(f1, prof$EMAIL,'@')
> sapply(prof$EMAIL, f1, '@')
# 2) 함수만으로 사용하는 방법
> f2 <- function(x, c) {
v1 <- c()
for(i in 1:length(x)){
v1 <- c(v1, strsplit(x, c)[[i]][1])
}
return(v1)
}
> f2(prof$EMAIL,'@')
Q. 특정 컬럼 기준 큰 순서대로 n개의 행을 출력하는 함수
top <- function(data, column, n=5) {
data[order(data[,column], decreasing = T)[1:n],] # data$column 와 같은 문법은 function에서 전달 불가
}
top(prof,'PAY',3)
Q. 데이터 프레임 전체에 적용할 수 있는 치환 함수
f3 <- function(data, c1=',', c2='') {
as.data.frame(sapply(data, str_replace_all,c1,c2))
}
f3(card,',','')
참고: KIC 캠퍼스 머신러닝기반의 빅데이터분석 양성과정
'R > Process' 카테고리의 다른 글
[R] apply 계열 함수 - 적용 함수(원소별 연산, 그룹별 연산) (0) | 2019.01.07 |
---|---|
[R] 데이터 포맷 변경 함수 - sprintf(), gettextf() 함수 (0) | 2019.01.04 |
[R] 연산 (0) | 2019.01.02 |
[R] 정규 표현식 - 정규 표현식을 사용한 데이터 추출 (0) | 2019.01.02 |
[R] 문자열 관련 함수 - stringr 패키지, 정규식 (1) | 2019.01.01 |