6.5 필터링 조인

필터링 조인(Filtering join)은 변환 조인과 같은 방식으로 관측값을 매칭하지만 변수가 아닌 관측값에 영향을 준다. 두 가지 유형이 있다.

  • semi_join(x, y)y 와 매치되는 x 의 모든 관측값을 보존한다 .
  • anti_join(x, y)y 와 매치되는 x 의 모든 관측값을 삭제한다 .

세미 조인(Semi-joins)필터링된 요약 테이블을 다시 원래 행과 매치시키는 데 유용하다. 예를 들어 가장 인기 있는 상위 10개 도착지(dest)를 구했다고 가정해보자.

top_dest <- flights %>%
  count(dest, sort = TRUE) %>%
  head(10)
top_dest
## # A tibble: 10 x 2
##   dest      n
##   <chr> <int>
## 1 ORD   17283
## 2 ATL   17215
## 3 LAX   16174
## # ... with 7 more rows

이제 그 목적지 중 한 곳(dest %in% top_dest$dest)으로 운행한 항공편(flihts)을 찾고 싶다면 직접 필터를 만들 수 있다.

flights %>% 
  filter(dest %in% top_dest$dest)
## # A tibble: 141,145 x 19
##    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
## 1  2013     1     1      542            540         2      923            850
## 2  2013     1     1      554            600        -6      812            837
## 3  2013     1     1      554            558        -4      740            728
## # ... with 141,142 more rows, and 11 more variables: arr_delay <dbl>,
## #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

그러나 이러한 접근 방식을 여러 변수로 확장하는 것은 어렵다. 예를 들어 평균 연착시간(average arr_delay)이 가장 길었던 날 10일을 골라냈다고 상상해보라. year, month, day 를 사용하여 다시 항공편(flights)과 일치시키는 필터 구문을 어떻게 작성할 수 있는가?

한편 변환 조인과 같이 두 테이블을 연결하는 세미 조인을 사용할 수 있지만, 새 열을 추가하는 대신 y 에서 일치하는 x 의 행만 보존한다.

flights %>% 
  semi_join(top_dest)
## Joining, by = "dest"
## # A tibble: 141,145 x 19
##    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
## 1  2013     1     1      542            540         2      923            850
## 2  2013     1     1      554            600        -6      812            837
## 3  2013     1     1      554            558        -4      740            728
## # ... with 141,142 more rows, and 11 more variables: arr_delay <dbl>,
## #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

세미 조인(semi-join)은 그래픽으로 다음과 같이 표현된다.

img

x <- tribble(
  ~key, ~val_x,
  1, "x1",
  2, "x2",
  3, "x3"
)

y <- tribble(
  ~key, ~val_y,
  1, "y1",
  2, "y2",
  4, "y3"
)

x %>%  semi_join(y, by="key")
## # A tibble: 2 x 2
##     key val_x
##   <dbl> <chr>
## 1     1 x1   
## 2     2 x2
  • 매칭되었는지 여부만이 중요하다. 즉, 어떤 관측값이 매칭되는지는 중요하지 않다. 이는 필터링 조인은 뮤테이팅 조인처럼 행을 복제하지는 않는다는 것을 의미한다.

img

x <- tribble(
  ~key, ~val_x,
  1, "x1",
  2, "x2",
  2, "x3",
  3, "x4"
)
y <- tribble(
  ~key, ~val_y,
  1, "y1",
  2, "y2",
  2, "y3",
  3, "y4"
)
x %>% semi_join(y, by="key")
## # A tibble: 4 x 2
##     key val_x
##   <dbl> <chr>
## 1     1 x1   
## 2     2 x2   
## 3     2 x3   
## 4     3 x4

세미 조인의 반대는 안티 조인(Anti-join)이다. 안티 조인은 매칭되지 않는 행을 보존한다.

img

x <- tribble(
  ~key, ~val_x,
  1, "x1",
  2, "x2",
  3, "x3"
)
x
## # A tibble: 3 x 2
##     key val_x
##   <dbl> <chr>
## 1     1 x1   
## 2     2 x2   
## 3     3 x3
y <- tribble(
  ~key, ~val_y,
  1, "y1",
  2, "y2",
  4, "y3"
)
y
## # A tibble: 3 x 2
##     key val_y
##   <dbl> <chr>
## 1     1 y1   
## 2     2 y2   
## 3     4 y3
x %>%  anti_join(y, by="key")
## # A tibble: 1 x 2
##     key val_x
##   <dbl> <chr>
## 1     3 x3

안티 조인(Anti-join)조인 불일치를 진단하는 데 유용하다. 예를 들어 flightsplanes 를 연결하는 경우, planes 에 매치되지 않는 flights 이 많다는 것을 알고 싶을 수 있다.

flights %>%
  anti_join(planes, by = "tailnum") %>%
  count(tailnum, sort = TRUE)
## # A tibble: 722 x 2
##   tailnum     n
##   <chr>   <int>
## 1 <NA>     2512
## 2 N725MQ    575
## 3 N722MQ    513
## # ... with 719 more rows

6.5.1 연습문제

  1. 항공편에 tailnum 이 없는 것은 무엇을 의미하는가? planes 에 매치되는 관측값이 없는 tailnum 관측값의 공통점은 무엇인가? (힌트: 한 변수가 문제의 약 90%를 설명한다.)
  2. flights 를 필터링하여 최소 100 편의 운행을 한 여객기의 항공편만 표시하라.
  3. fueleconomy::vehiclesfueleconomy::common 을 결합하여 가장 많은 차량 모델의 레코드만 찾아라.
  4. 최악의 연착 시간을 가진 (1년 중) 48시간을 찾아라. 날씨 데이터와 교차 참조하라. 어떤 패턴을 볼 수 있는가?
  5. anti_join(flights, airports, by = c("dest" = "faa")) 을 보고 무엇을 알 수 있는가? anti_join(airports, flights, by = c("faa" = "dest")) 은 어떤가?
  6. 각 항공기는 단일 항공사에 의해 운항되므로 항공기와 항공사 간에 암묵적인 관계가 있을 것으로 예상할 수 있다. 이전 절에서 배운 도구를 사용하여 이 가설을 확인하거나 기각하라.