[R 프로그래밍] 9. 함수와 apply

Author : tmlab / Date : 2016. 10. 4. 01:01 / Category : Lecture/R 프로그래밍


PR8

함수와 apply

조혁준

2016-04-14

함수

  • 여러분들이 사용하셨던 모든 명령어는 함수라고 보시면 됩니다
  • 함수란 특정 목적을 위한 모든 프로그래밍적 과정을 하나로 묶은 것이라고 보시면 됩니다
  • 그렇다면 R에서 함수를 만드는 법을 알아보도록 하겠습니다
In [2]:
addone<-function(x){
    x+1
}
  • 상단의 코드는 addone이라는 함수를 만든 겁니다
    • addone이란 함수는 인수를 한개 받아서 1을 더해주는 함수입니다
  • 결과를 살펴보겠습니다
In [3]:
addone(1)
2
  • 1을 넣었더니 2가 출력되어 돌아왔습니다!
In [6]:
param <- 10
number <- addone(param)
number
11
  • 다른 프로그래밍 언어와는 다르게 return을 시키지 않아도 값이 할당 되는 것을 볼 수 있습니다

return

  • return은 함수가 종료될 때 값을 반환시키는 명령어로써 함수의 최종 출력값이라고 생각하시면 됩니다
  • 아래의 예제를 보시겠습니다
In [8]:
addtwo <- function(x){
    x+2
}
addtwo(1)
3
  • addone()과 같은 addtwo함수를 만들었습니다
  • return 값을 다른걸로 줘보겟습니다
In [12]:
addtwo <- function(x){
    x+2
    return (10)
}
addtwo(1)
addtwo(2)
addtwo(3)
10
10
10
  • 보시면 어떤 숫자를 사용해도 리턴값은 10으로 정해집니다
  • 이를 활용해보겠습니다
In [16]:
oddnum <- function(x){
    if(x%%2==1){
       return(T)
    }
    else{
        return(F)
    }
}

oddnum(1)
oddnum(2)
TRUE
FALSE
  • 상단의 함수는 홀수판별 함수입니다
  • 보시면 return을 사용하여 입력값은 numeric이지만 결과값은 logical인것을 확인 할 수 있습니다
  • 하지만 안타까운 것은 return을 사용하지 않아도 이 값이 반환된다는 것입니다
In [19]:
oddnum <- function(x){
    if(x%%2==1){
        T
    }
    else{
        F
    }
}

oddnum(1)
oddnum(2)
TRUE
FALSE
  • 하지만 return 명령어를 써서 값을 반환한다면 함수가 종료되니 상황에 맞춰서 사용하셔야 합니다

자 그럼 함수를 하나 작성해 봅시다

  • 다음과 같은 상황에서 짝수만 출력해보세요
In [22]:
num <- 1:10

evennum<-function(x){
    #내용
    #채우
    #세요
}

even <-evennum(num)
num[even]
  1. 2
  2.  
  3. 4
  4.  
  5. 6
  6.  
  7. 8
  8.  
  9. 10
  • 함수를 사용하시려면 scope of variable을 아셔야 합니다
    • 이는 교수님 자료를 보시면 자세히 설명이 되어 있습니다
    • 간단하게 말하면, 모든 함수 바깥에서 선언되거나 할당된 변수는 같은 파일 안에서는 어디서나 쓸 수 있습니다
    • 하지만 특정 함수 내에서 선언되거나 할당된 변수는 함수가 종료되는 순간 값을 반환해주지 않으면 그대로 사라집니다
    • 간단한 예시입니다
In [40]:
x<-10
printall <- function(y){
    print(y)
    print(x+1)
}
printall(9)
print(x)
[1] 9
[1] 11
[1] 10
  • 상단의 코드를 보시면 printall이라는 함수는 입력받은 값과 x라는 변수의 값을 출력하는 함수라는 것을 아실 수 있을 것입니다.
  • 그런데 x값을 넘겨주지 않았는데 print(x)가 정상적으로 출력이 되는 것을 확인 하실 수 있습니다
    • 이는 x가 전역변수여서 그렇습니다
In [45]:
printtest<-function(x){
    a<-10
    print(a)
    print(x)
}
printtest(9)
print(a)
[1] 10
[1] 9
Error in print(a): 객체 'a'를 찾을 수 없습니다
Traceback:

1. print(a)
  • 상단의 코드를 보시면 함수 내부에 a라는 변수를 선언하고 10이라는 값을 할당했는데 함수내에서는 출력이 되지만 함수 바깥에서는 a라는 변수를 찾을 수 없다고 에러메시지를 출력합니다
  • 이는 a가 함수내에서만 생성되고 사라지는 변수라는 의미입니다
  • 하지만 R에서는 internal 변수를 global 변수로 만들어주는 방법이 존재합니다
    • <<-로 할당해주시면 됩니다
In [23]:
printtest<-function(x){
    a<<-10
    print(a)
    print(x)
}
printtest(9)
print(a)
[1] 10
[1] 9
[1] 10

default 값 주기

  • 예전에 설명을 드렸는데 read.csv는 단지 read.table함수에 default값만 바꿔 준거라고 말씀드렸을 것입니다.
  • default 값은 어떻게 주는지 한번 실습해보겠습니다
In [47]:
add10 <- function(x=10){
    x+10
}
add10()
add10(20)
20
30
  • 상단의 코드를 보시면 add10이라는 함수에 어떠한 값을 주지 않았는데 10+10의 값이 나오는 것을 확인 하실 수 있습니다
  • 하지만 다른 값을 주자 해당 값에 10을 더하는 것을 확인하실 수 있습니다
  • 처음에 인수를 줄 때, 할당할 값을 적어둔다면 아무런 인수도 넘기시지 않으셨을 때 적어둔 값으로 결과값을 준다는 것을 알 수 있습니다
  • 만약 함수의 parameter를 설정했을 때 default값을 주지 않고 아무런 인수를 주지 않는다면 에러가 납니다
In [26]:
add10 <- function(x){
    x+10
}
add10(20)
add10()
30
Error in add10(): 기본값이 없는 인수 "x"가 누락되어 있습니다
Traceback:

1. add10()

그럼 default값을 줘서 함수를 작성해보겠습니다

  • 숫자를 두개 줘서 다(多)제곱 하는 함수를 작성해보겠습니다
  • 제곱할 parameter의 default값은 2입니다
  • 함수이름은 맘대로 쓰세요.....
  • 제곱 연산 수식은 ^입니다
In [27]:
powered <- function(  ,  ){
    ^
}
powered(num=2)
powered(num=2,power=3)
4
8

apply() 명령어

  • Data Frame에서 모든 열에 명령어를 적용시킬 수 있는 함수입니다
  • 그냥 data frame으로 바로 적용시키면 제대로 된 결과값이 반환되지 않습니다
  • base에서 제공하는 함수는 apply,lapply,sapply,vapply,tapply,mapply 등이 있습니다
In [29]:
test <- data.frame(a=1:3,b=2:4,c=3:5)
test
mean(test)
abc
1123
2234
3345
Warning message:
In mean.default(test): argument is not numeric or logical: returning NA
[1] NA

apply

  • matrix나 array, data frame처럼 이차원 이상의 데이터에 일괄적으로 함수를 적용할 수 있는 함수 입니다
  • 결과값은 vector로 반환합니다
  • 사용법은 apply(data,margin(dimension),function)입니다
    • dimension은 1이면 행, 2이면 열입니다
In [5]:
test.num<-matrix(1:25,nrow=5)
test.num
apply(test.num,1,mean)==rowMeans(test.num)
apply(test.num,2,mean)==colMeans(test.num)
16111621
27121722
38131823
49141924
510152025
  1. TRUE
  2.  
  3. TRUE
  4.  
  5. TRUE
  6.  
  7. TRUE
  8.  
  9. TRUE
  1. TRUE
  2.  
  3. TRUE
  4.  
  5. TRUE
  6.  
  7. TRUE
  8.  
  9. TRUE

lapply

  • l은 list를 의미합니다.
  • 입력으로 리스트를 받아 결과값도 리스트로 반환합니다
    • 기억하실런지 모르겠지만... data frame의 각 열은 리스트입니다
  • lapply를 써서 각 열의 평균값을 구해보겠습니다
    • 사용법은 lapply(data,function)입니다
In [31]:
a<-lapply(test,mean)
a
class(a)
$a
2
$b
3
$c
4
"list"

sapply

  • s는 simplification을 의미합니다
  • 결과 값을 vector나 matrix값으로 반환합니다...만 인수에 의해 조절될 수 있습니다
  • 역시 입력값은 리스트입니다
  • 함수 내용을 확인해보면 function(data,function,...,simplify=T,USE.NAMES=T)인 것을 확인 할 수 있습니다
In [33]:
sapply
function (X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE) 
{
    FUN <- match.fun(FUN)
    answer <- lapply(X = X, FUN = FUN, ...)
    if (USE.NAMES && is.character(X) && is.null(names(answer))) 
        names(answer) <- X
    if (!identical(simplify, FALSE) && length(answer)) 
        simplify2array(answer, higher = (simplify == "array"))
    else answer
}
  • 간단한 사용법은 sapply(data,function)입니다
In [35]:
a<-sapply(test,mean)
a
class(a)
a
2
b
3
c
4
"numeric"
  • 주요 인수를 간단하게 설명을 하겠습니다
    • simplify: 결과값을 리스트로 반환할지의 유무입니다. T면 vector나 matrix를, F면 list입니다
In [36]:
a<-sapply(test,mean,simplify=F)
a
class(a)
$a
2
$b
3
$c
4
"list"
  • 단, 각 리스트의 결과 값의 길이가 다르면 simplify는 자동적으로 F값으로 설정됩니다
    • 물론 data frame은 길이가 다를 수 없기 때문에 data frame에서는 이 경고 문구가 의미는 없습니다
In [41]:
test1 <- list(a=1:3,b=1:5)
test1
a<-sapply(test1,function(x){x+1})
a
class(a)
$a
  1. 1
  2.  
  3. 2
  4.  
  5. 3
$b
  1. 1
  2.  
  3. 2
  4.  
  5. 3
  6.  
  7. 4
  8.  
  9. 5
$a
  1. 2
  2.  
  3. 3
  4.  
  5. 4
$b
  1. 2
  2.  
  3. 3
  4.  
  5. 4
  6.  
  7. 5
  8.  
  9. 6
"list"

자 문제를 풀어보겠습니다

  • iris 데이터를 사용하여 숫자로 이루어진 데이터들을 apply,lapply,sapply를 사용하여 mean함수를 적용해보세요
In [1]:
#apply
Sepal.Length
5.84333333333333
Sepal.Width
3.05733333333333
Petal.Length
3.758
Petal.Width
1.19933333333333
In [61]:
#lapply
$Sepal.Length
5.84333333333333
$Sepal.Width
3.05733333333333
$Petal.Length
3.758
$Petal.Width
1.19933333333333
In [62]:
#sapply
Sepal.Length
5.84333333333333
Sepal.Width
3.05733333333333
Petal.Length
3.758
Petal.Width
1.19933333333333

과제

  • 함수를 하나 만들어보세요. 함수의 내용은 숫자 두개를 넣고 그 중 최대공약수를 찾는 것입니다
In [71]:
GCD <- function(x,y){
## 내용을 작성하세요
}

GCD(25,30)
5
  • demo.csv파일을 읽어서 전부 소문자로 바꿔보세요. 이 때, matrix로 바꿔서 하면 안됩니다.
    • 결과 값이 matrix인 것은 뭐라 하지 않겠지만, matrix로 변환해서 함수를 적용하면 감점입니다
    • apply함수 사용하면 됩니다
In [83]:
V1V2V3V4V5V6
1Black PantherDaredevilHawkeyeLokiPunisherStorm
2Black WidowDeadpoolHulkLuke CageRocket RaccoonTaskmaster
3CableDoctor StrangeHuman TorchMoon KnightScarlet WitchThing
4Captain AmericaEmma FrostInvisible WomanMs. MarvelSilver SurferThor
5ColossusGambitIron ManNightcrawlerSpider-ManWolverine
6CyclopsGhost RiderJean GreyPsylockeSquirrel GirlBarricade
V1V2V3V4V5V6
1black pantherdaredevilhawkeyelokipunisherstorm
2black widowdeadpoolhulkluke cagerocket raccoontaskmaster
3cabledoctor strangehuman torchmoon knightscarlet witchthing
4captain americaemma frostinvisible womanms. marvelsilver surferthor
5colossusgambitiron mannightcrawlerspider-manwolverine
6cyclopsghost riderjean greypsylockesquirrel girlbarricade


Archives

05-16 18:47

Contact Us

Address
경기도 수원시 영통구 원천동 산5번지 아주대학교 다산관 429호

E-mail
textminings@gmail.com

Phone
031-219-2910

Tags

Calendar

«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Copyright © All Rights Reserved
Designed by CMSFactory.NET