집합연산

R Analytics

R에서도 집합연산을 수행할 수 있는 여러 유용한 함수를 제공한다.

유충현
2005-06-22

일러두기

2005-06-22 네이버 블로그에 게시된 내용을 옮겨 온 글입니다. 지금의 R 환경과 다소 내용이 다를 수 있음을 밝여둡니다. R에서의 집합연산에 대해서 알아보자.

데이터 만들기

먼저 집합 x와 y를 만들어 보자. 두 개의 벡터는 이후에 집한 연산에서 계속 사용될 데이터다.

set.seed(3) 
x <- sort(sample(1:10, 5))
x
[1] 2 3 4 5 7
set.seed(5)
y <- sort(sample(1:10, 5))
y
[1] 1 2 3 7 9

합집합 (x ∪ y)

합집합은 union() 함수를 사용한다.

union(x, y)
[1] 2 3 4 5 7 1 9

그리고 unique() 함수를 응용해서 구할 수도 있다. unique() 함수는 벡터에 대해서 유일(unique)한 값을 구한다.

unique(c(x, y))
[1] 2 3 4 5 7 1 9

교집합 (x ∩ y)

교집합은 intersect() 함수를 사용한다.

intersect(x, y)
[1] 2 3 7

그리고 unique() 함수와 sort() 함수를 응용해서 구할 수도 있다. sort() 함수는 정렬함수다.

sort(unique(c(x, y)))[table(c(x, y)) == 2]
[1] 2 3 7

또한 다음과 같이 구할 수도 있다.

unique(y[match(x, y, 0)])
[1] 2 3 7

사실 R에서 intersect() 함수가 이와 같이 정의되어 있다.

intersect
function (x, y) 
{
    y <- as.vector(y)
    unique(y[match(as.vector(x), y, 0L)])
}
<bytecode: 0x7faa90cda870>
<environment: namespace:base>

차집합 (x - y)

차집합은 setdiff() 함수를 사용한다.

setdiff(x, y)  # x-y
[1] 4 5
setdiff(y, x)  # y-x
[1] 1 9

그리고 intersect() 함수를 응용해서 구할 수도 있다.

intersect(sort(unique(c(x, y)))[table(c(x, y)) == 1], x)  # x-y
[1] 4 5
intersect(sort(unique(c(x, y)))[table(c(x, y)) == 1], y)  # y-x
[1] 1 9

R의 setdiff() 함수는 다음과 같이 정의되어 있다.

setdiff
function (x, y) 
{
    x <- as.vector(x)
    y <- as.vector(y)
    unique(if (length(x) || length(y)) 
        x[match(x, y, 0L) == 0L]
    else x)
}
<bytecode: 0x7faa909ce240>
<environment: namespace:base>

원소의 집합 포함관계 (a ∈ x, a ∈ y)

is.element() 함수를 이용해서 특정 원소가 집합에 포함되는지를 검증할 수 있다. 단, 이 함수의 반환값은 논리 벡터인데 그 원소의 개수가 함수의 첫번째 인수의 개수와 동일하다.

a <- 9
is.element(a,x)  # a ∈ x
[1] FALSE
is.element(a,y)  # x ∈ y
[1] TRUE

그리고 as.logical() 함수와 sum() 함수를 응용해서 구할 수도 있다.

as.logical(sum(x == a))  # a ∈ x
[1] FALSE
as.logical(sum(y == a))  # a ∈ y
[1] TRUE

다음과 같은 방법을 사용할 수도 있다.

all(!is.na(match(a, x)))  # a ∈ x
[1] FALSE
all(!is.na(match(a, y)))  # a ∈ y
[1] TRUE
all(match(a, x, 0) > 0)   # a ∈ x
[1] FALSE
all(match(a, y, 0) > 0)   # a ∈ y
[1] TRUE

또한 다음처럼 구할 수도 있다.

match(a, x, 0) > 0
[1] FALSE
match(a, y, 0) > 0
[1] TRUE

R에서 is.element() 함수가 이와 같이 정의되어 있다.

is.element
function (el, set) 
match(el, set, 0L) > 0L
<bytecode: 0x7faa90e0cc90>
<environment: namespace:base>

집합의 포함관계 (z ⊂ x, z ⊂ y)

is.element() 함수를 이용해서 특정 집합이 집합에 포함되는지를 검증할 수 있다. 단, is.element() 함수의 반환값은 논리 벡터인데 그 원소의 개수가 함수의 첫번째 인수의 개수와 동일하기 때문에 prod() 함수를 이용하였다.

z <- c(2, 8)
as.logical(prod(is.element(z, x)))  # z ⊂ x
[1] FALSE
as.logical(prod(is.element(z, y)))  # z ⊂ y
[1] FALSE
as.logical(prod(is.element(x, z)))  # x ⊂ z
[1] FALSE

그리고 as.logical() 함수와 prod() 함수, intersect() 함수를 응용해서 구할 수도 있다.

as.logical(prod(intersect(x, z)==z))  # z⊂x
[1] FALSE
as.logical(prod(intersect(y, z)==z))  # z⊂y
[1] FALSE
# 원소의 개수가 배수가 아니면 경고가 발생한다.
as.logical(prod(intersect(x, z)==x)) 
[1] FALSE

다음을 응용할 수도 있다.

match(z, x, 0) > 0
[1]  TRUE FALSE
match(z, y, 0) > 0
[1]  TRUE FALSE
match(x, z, 0) > 0
[1]  TRUE FALSE FALSE FALSE FALSE
all(match(z, x, 0) > 0)  # z ⊂ x
[1] FALSE
all(match(z, y, 0) > 0)  # z ⊂ y
[1] FALSE
all(match(x, z, 0) > 0)  # x ⊂ z
[1] FALSE
all(is.element(z, x))    # z ⊂ x
[1] FALSE
all(is.element(z, y))    # z ⊂ y
[1] FALSE
all(is.element(x, z))    # x ⊂ z
[1] FALSE

all() 함수는 인수의 값이 모두 TRUE일 경우에만 TRUE를 반환하고 아니면 FALSE를 반환한다.

is.element() 함수를 응용한 교집합

is.element() 함수를 응용하면 sort(unique(c(x, y)))[table(c(x, y)) == 2]을 다음과 같이 간략화 시킬 수 있다.

x[is.element(x, y)]  # x ∩ y
[1] 2 3 7
y[is.element(y, x)]  # y ∩ x
[1] 2 3 7

is.element() 함수를 응용한 차집합

is.element() 함수를 응용하면 intersect(sort(unique(c(x, y)))[table(c(x, y)) == 1], x)을 다음과 같이 간략화 시킬 수 있다.

x[!is.element(x, y)]  # x - y
[1] 4 5
y[!is.element(y, x)]  # y - x
[1] 1 9

집합의 상등(x = y)

setequal() 함수를 이용하여 집합의 상등을 알아볼 수 있다.

setequal(x, y)
[1] FALSE
setequal(x, x)
[1] TRUE

setequal() 함수는 다음과 같이 정의되어 있다.

setequal
function (x, y) 
{
    x <- as.vector(x)
    y <- as.vector(y)
    !(anyNA(match(x, y)) || anyNA(match(y, x)))
}
<bytecode: 0x7faa6632af98>
<environment: namespace:base>

이 함수를 수식으로 표현하자면 다음과 같다.

if x ⊂ y and y ⊂ x then x = y othwise x ≠ y

다음처럼 구할 수도 있다.

all(sort(x) == sort(y))
[1] FALSE
all(sort(x) == sort(x))
[1] TRUE
# 원소의 개수가 배가 아니면 경고가 발생한다.
all(sort(x) == sort(z))  
Warning in sort(x) == sort(z): longer object length is not a multiple
of shorter object length
[1] FALSE

warning message가 번거롭다면 options() 함수의 warn 인수값을 음수로 바꾸면 출력되지 않는다. 그러나 이 방법은 권장하지 않는다. 차라리 다음과 같이 ifelse() 함수를 이용해서 예외처리를 해주면 된다.

ifelse(length(x) != length(z), FALSE, all(sort(x) == sort(z)))
[1] FALSE

앞서 집합 포함관계에서도 warning message가 출력되었는데 이와 같이 처리하면 된다.

Citation

For attribution, please cite this work as

유충현 (2005, June 22). Dataholic: 집합연산. Retrieved from https://choonghyunryu.github.io/posts/2005-06-22-operation-sets/

BibTeX citation

@misc{유충현2005집합연산,
  author = {유충현, },
  title = {Dataholic: 집합연산},
  url = {https://choonghyunryu.github.io/posts/2005-06-22-operation-sets/},
  year = {2005}
}