티스토리 뷰

R/Process

[R] 함수의 정의

Aaron 2019. 1. 2. 23:07
반응형

함수의 정의



사용자 정의 함수 : 코드의 반복을 줄이기 위한 사용자 정의 함수


 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 캠퍼스 머신러닝기반의 빅데이터분석 양성과정

반응형
댓글
최근에 올라온 글
최근에 달린 댓글
링크
Total
Today
Yesterday