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)은 그래픽으로 다음과 같이 표현된다.

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
- 매칭되었는지 여부만이 중요하다. 즉, 어떤 관측값이 매칭되는지는 중요하지 않다. 이는 필터링 조인은 뮤테이팅 조인처럼 행을 복제하지는 않는다는 것을 의미한다.

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)이다. 안티 조인은 매칭되지 않는 행을 보존한다.

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