◎ apply 계열 함수
함수 | 적용 | 반환 |
apply() | 행렬, 배열, 데이터프레임 | 벡터, 리스트, 행렬, 배열 |
lapply() | 벡터, 리스트, 데이터프레임 | 리스트 |
sapply() | 벡터, 리스트, 데이터프레임 | 벡터, 행렬, 배열 |
tapply() | 리스트, 행렬 | |
mapply() | 벡터, 리스트, 행렬 |
- apply()
apply(X, MARGIN, FUN, ...) |
<인수설명>
MARGIN | 함수를 적용하는 방향 1은 행, 2는 열, c(1,2)는 행과 열 모두를 의미 |
FUN | 적용할 함수 |
apply() 함수는 배열 or 행렬의 행/열 방향으로 동일한 특정 함수가 적용되도록 한다. 실행결과가 어떤 형태로 반환될 것인지는 데이터의 타입과 적용함수의 반환 값에 따라 바뀌며, 예상이 가능하다.
> mat = matrix(1:12, 3, 4)
> mat
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
> apply(mat, 1, sum)
[1] 22 26 30
> apply(mat, 2, sum)
[1] 6 15 24 33
sum() 함수를 적용하여 MARGIN이 1이었을 때는 행렬의 행 방향으로, MARGIN이 2이었을 때는 행렬의 열 방향으로 데이터의 합을 계산한다.
만약 데이터에 결측치(NA)가 포함되어 있다면 na.rm=TRUE 를 apply() 함수 안에 넣어주면 된다.
apply(mat, 1, sum, na.rm=TRUE)
함수정의에서 FUN 인수 뒤에 ... 이 FUN에 대한 옵션을 넣는 자리이기 때문에 sum() 함수 안에 넣는 인수인 na.rm=TRUE 를 apply() 함수에서는 ... 자리에 넣는 것이다. 이는 다른 apply 계열 함수들도 마찬가지다.
> arr = array(1:12, c(2,3,2))
> arr
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
> apply(arr, 1, mean)
[1] 6 7
> apply(arr, 2, mean)
[1] 4.5 6.5 8.5
배열에 적용하였을 경우 3차원, 4차원 상관없이 행렬처럼 계산이 된다. 행 방향의 결과값을 예로 들어보면
(1+3+5+7+9+11) / 6 = 6
(2+4+6+8+10+12) / 6 = 7
이처럼 배열의 첫번째 면과 두번째 면의 행들이 합쳐져서 계산되었음을 알 수 있다.
> df = data.frame(NO=1:3,
+ NAME=c('홍길동','이순신','유관순'),
+ PAY=c(250,350,200))
> df
NO NAME PAY
1 1 홍길동 250
2 2 이순신 350
3 3 유관순 200
> apply(df[,c(1,3)], 2, sum)
NO PAY
6 800
sum() 함수는 숫자를 데이터로 받기때문에 문자타입인 2번째 열을 제외하고 계산한 결과이다.
- lapply()
lapply(X, FUN, ...) |
> lst = list(name=c("Kim", "Lee", "Han"),
+ age=c(20, 21, 23),
+ height=c(169.7, 177.4, 182.4))
> lst
$name
[1] "Kim" "Lee" "Han"
$age
[1] 20 21 23
$height
[1] 169.7 177.4 182.4
> lapply(lst, class)
$name
[1] "character"
$age
[1] "numeric"
$height
[1] "numeric"
lapply() 함수는 결과를 리스트로 반환한다.
class() 함수를 통해 리스트 각 멤버(key)의 자료구조를 알아보았다. class() 함수는 행렬, 배열, 데이터프레임 같은 자료구조를 반환하는데 리스트의 각 멤버가 벡터로 이루어져 있으므로 벡터가 문자형인지 숫자형인지를 반환하였다.
※ 자료형과 자료구조 더 알아보기
> result = lapply(lst[2:3], max)
> result
$age
[1] 23
$height
[1] 182.4
> unlist(result)
age height
23.0 182.4
위의 리스트에서 name 멤버의 경우 문자열이므로 max() 함수에서는 값이 계산되지 않기에 제외를 하였다.
리스트보다는 벡터 or 데이터프레임이 다루기에 편하고 직관적이므로 unlist() 함수를 이용해 리스트를 벡터타입으로 변환해주었다.
> lapply(df[,c(1,3)], sum)
$NO
[1] 6
$PAY
[1] 800
데이터프레임을 lapply() 함수에 적용시켜도 결과는 역시 리스트로 반환된다.
- sapply()
sapply(X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE) |
<인수설명>
simplify | 기본값으로 벡터를 반환 |
USE.NAMES | TRUE이면 객체의 성분 이름을 사용 |
> result = sapply(df[,c(1,3)], sum)
> result
NO PAY
6 800
> class(result)
[1] "numeric"
sapply() 함수는 lapply() 함수와 유사하나 실행결과를 리스트가 아닌 벡터나 행렬 등으로 반환한다. 결과를 class() 함수에 넣었을 때 "numeric"이 나왔으니 실행결과가 벡터로 반환되었음을 알 수 있다.
> as.data.frame(result)
result
NO 6
PAY 800
> as.data.frame(t(result))
NO PAY
1 6 800
벡터를 데이터프레임으로 변환하고 싶어서 as.data.frame() 함수를 사용할 때 그냥 실행결과를 집어넣게되면 행과 열이 바뀌어 저장되는데 이는 간단하게 전치행렬을 만들어주는 t() 함수를 사용하면 원하는 모양의 데이터를 얻을 수 있다.
- tapply()
tapply(X, INDEX, FUN = NULL, ..., default = NA, simplify = TRUE) |
<인수설명>
INDEX | 데이터를 그룹으로 묶을 색인 |
simplify | 기본값으로 행렬 반환, FALSE이면 리스트 반환 |
tapply() 함수는 그룹별로 지정한 함수를 적용시킨다.
INDEX 인수는 객체 X와 같은 길이의 요인(factor)형 데이터를 지정해야하고, 요인형이 아닌 타입을 지정해도 요인형으로 변환되어 함수가 실행된다.
> x = c(169, 177, 182, 179, 167, 192, 162)
> grp = c('A', 'B', 'C', 'B', 'C', 'A', 'B')
> tapply(x, grp, mean)
A B C
180.5000 172.6667 174.5000
3개의 그룹(A, B, C)으로 분류된 데이터 키(cm)에 대해 각 그룹별 평균을 구하는 예이다.
> 1:10 %% 2 == 1
[1] TRUE FALSE TRUE FALSE TRUE
[6] FALSE TRUE FALSE TRUE FALSE
> tapply(1:10, 1:10 %% 2 == 1, sum)
FALSE TRUE
30 25
1에서 10까지의 숫자를 홀수와 짝수별로 합을 계산하는 예로 FALSE 는 짝수의 합이고, TRUE는 홀수의 합이다.
INDEX 인수를 조건식으로 채웠다. 조건식 말고도 함수, 리스트 등으로 INDEX 인수를 채울 수 있다.
- mapply()
mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE) |
<인수설명>
SIMPLIFY | 기본값으로 행렬을 반환, FALSE이면 리스트 반환 |
USE.NAMES | TRUE이면 객체의 성분 이름을 사용 |
mapply() 함수는 지정한 함수에 여러 값을 대입하여 실행된다.
... 자리에 여러 데이터가 있을 경우 FUN에 이들 데이터 각각의 첫번째 원소들을 인자로 전달해 실행하고, 다음 두번째 원소들을 인자로 전달해 실행하고를 반복해 결과를 반환한다.
> mapply(rep, c('a','b','c'), c(2,2,2))
a b c
[1,] "a" "b" "c"
[2,] "a" "b" "c"
> mapply(rep, c('a','b','c'), c(2,3,5))
$a
[1] "a" "a"
$b
[1] "b" "b" "b"
$c
[1] "c" "c" "c" "c" "c"
rep() 함수를 사용해 서로 다른 길이의 멤버(key)를 가진 리스트를 결과로 얻었고, 이는 아래 코드를 실행한 결과들과 같다.
> rep('a', 2)
[1] "a" "a"
> rep('b', 3)
[1] "b" "b" "b"
> rep('c', 5)
[1] "c" "c" "c" "c" "c"
◎ replicate()
replicate(n, expr, simplify = "array") |
<인수설명>
n | 반복 횟수 |
expr | 반복할 식 |
simplify | 기본값으로 배열을 반환 |
replicate() 함수는 지정한 식을 n 회 반복하여 실행하고, 결과를 벡터, 행렬, 배열 등으로 반환한다.
> replicate(5, sample(0:2, 3, replace=T))
[,1] [,2] [,3] [,4] [,5]
[1,] 2 2 1 0 0
[2,] 1 1 0 1 2
[3,] 1 2 2 0 0
0에서 2까지의 범위를 가지는 난수를 3개씩 5회 추출하는 코딩이고, 실행결과로 행렬이 반환되었다.
> star = function() return('*')
> star()
[1] "*"
> n = 7
> for(i in 1:n) {
+ a = replicate(n, star())
+ cat(a, '\n')
+ }
* * * * * * *
* * * * * * *
* * * * * * *
* * * * * * *
* * * * * * *
* * * * * * *
* * * * * * *
> for(i in 1:n) {
+ a = replicate(i, star())
+ cat(a, '\n')
+ }
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
'*'를 출력하는 star() 함수를 정의하고, 이를 이용하여 양의 정수 n의 값에 따라 출력되는 '*'의 갯수를 달리하는 코드를 작성하였다.
◎ sweep()
sweep(x, MARGIN, STATS, FUN = "-", check.margin = TRUE, ...) |
<인수설명>
MARGIN | 벡터의 차원, 1은 행, 2는 열 |
STATS | 계산할 값 or 벡터 |
FUN | 계산할 연산, 기본값은 뺄셈 |
sweep() 함수는 배열 객체의 지정한 행 or 열에 연산을 적용하여 계산하고, 그 결과를 벡터, 행렬 등으로 반환한다.
> arr = array(1:12, dim=3:4)
> arr
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
> sweep(arr, 1, c(1,0,2))
[,1] [,2] [,3] [,4]
[1,] 0 3 6 9
[2,] 2 5 8 11
[3,] 1 4 7 10
데이터 행의 방향으로 1, 0, 2의 값이 빼진 결과를 얻을 수 있고, 연산의 기본값은 뺄셈이다.
> colsum = apply(arr, 2, sum)
> colsum
[1] 6 15 24 33
> sweep(arr, 2, colsum, FUN="/")
[,1] [,2] [,3] [,4]
[1,] 0.1666667 0.2666667 0.2916667 0.3030303
[2,] 0.3333333 0.3333333 0.3333333 0.3333333
[3,] 0.5000000 0.4000000 0.3750000 0.3636364
각 열의 합을 구하였고, 이를 데이터의 열 방향으로 나누는 연산을 실행하였다.
◎ aggregate()
aggregate(x, by, FUN, ..., simplify = TRUE, drop = TRUE) |
<인수설명>
by | 그룹화할 요소들의 리스트, 객체의 크기와 같아야함 |
FUN | 계산할 함수 |
drop | 사용되지 않는 그룹화 요소들은 제외 |
aggregate() 함수는 데이터를 부분 집합으로 분할한 후, 각 부분집합에 요약 통계를 계산한 다음 실행결과를 벡터, 행렬 등으로 반환한다.
by 인수에 들어가는 그룹화 리스트의 데이터타입은 반드시 리스트 객체여야 한다.
> df = data.frame(height=c(169, 177, 182, 179, 167, 192, 162),
+ weight=c(71, 83, 85, 79, 66, 95, 69))
> df
height weight
1 169 71
2 177 83
3 182 85
4 179 79
5 167 66
6 192 95
7 162 69
> grp = c('A', 'B', 'C', 'B', 'C', 'A', 'B')
> aggregate(df, list(grp), mean)
Group.1 height weight
1 A 180.5000 83.0
2 B 172.6667 77.0
3 C 174.5000 75.5
aggregate(formula, data, FUN, ... ) |
<인수설명>
formula | y ~ x 형태로 y는 계산에 사용될 값, x는 그룹화할 값 |
data | furmula를 적용할 데이터 |
FUN | 계산할 함수 |
aggregate() 함수의 또다른 식으로 포뮬라를 사용하는 방식이 있다.
> aggregate(height ~ grp , df, mean)
grp height
1 A 180.5000
2 B 172.6667
3 C 174.5000
<R apply 계열 함수/replicate/sweep/aggregate>
'R > Data Operation' 카테고리의 다른 글
R 데이터 분리, 병합, 정렬 - split/subset/merge/sort/order (0) | 2020.12.05 |
---|---|
R table 계열 함수 - 집계함수 (0) | 2020.11.26 |
R 벡터 Vector 관련 내장함수 (0) | 2020.11.10 |
R 산술/관계/비교/논리연산자와 벡터연산 (0) | 2020.11.05 |
R 함수 Function - 함수정의/함수인자/재귀중첩함수 (0) | 2020.11.03 |
댓글