Menu

R에서 데이터 필터링과 부분집합 추출 (subset, [ ], dplyr filter)

원하는 행과 열만 남기는 모든 방법: 대괄호와 논리 마스크, subset() 한 줄 표현, %in%, NA 함정, 그리고 dplyr의 filter()와 select().

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

행 필터링: 논리 마스크

R에서 데이터 프레임을 필터링하려면 대괄호의 행 위치에 조건을 넣습니다: df[조건, ]. 조건은 행마다 하나씩 TRUE/FALSE 벡터로 평가되고, R은 TRUE인 행을 남깁니다:

scores[scores$score > 80, ]은 안쪽에서 바깥으로 읽습니다: scores$score > 80TRUE FALSE TRUE TRUE FALSE를 만들고, 대괄호가 1, 3, 4행을 남깁니다. 끝의 쉼표는 선택 사항이 아닙니다. 데이터 프레임의 대괄호는 [행, 열]을 받으며, 열 자리를 비워 두면 "모든 열"을 뜻합니다. 쉼표를 빠뜨리면 행이 아니라 열을 인덱싱하게 됩니다 - R 초보자가 가장 흔히 저지르는 실수 중 하나입니다.

출력된 행 번호가 1 2 3이 아니라 1 3 4인 점에 주목하세요 - 필터링은 원래의 행 라벨을 유지합니다. 문제가 되지는 않지만 처음 보면 당황스럽습니다.

다중 조건: & 와 | (&&가 아닙니다)

&(AND)와 |(OR)로 조건을 결합합니다. 각 조건은 완전한 비교식을 따로 갖습니다:

함정: R에는 &&||도 있는데, 여기서는 &, |호환되지 않습니다. 두 개짜리 형태는 단일 값에 대해 동작합니다(if 조건을 위해 존재합니다). 열 전체를 넘기면 최신 R(4.3+)은 'length = 5' in coercion to 'logical(1)' 같은 오류로 중단하고, 예전 R은 조용히 첫 행만 비교했습니다 - 어떤 면에서는 더 나쁩니다. 대괄호 안에서는 언제나 홑 &|를 씁니다. 연산자 문서에서 이 차이를 자세히 다룹니다.

%in%: 값의 집합과 매칭하기

어떤 열이 여러 값 중 하나와 일치해야 한다면 ==|로 이어 붙이지 말고 %in%을 쓰세요:

x %in% setxset의 값 중 하나인 위치마다 TRUE를 반환합니다. status == "pending" | status == "shipped"보다 읽기 좋고, 값의 개수가 늘어나도 잘 확장되며, 부정도 깔끔합니다: !(orders$status %in% c("refunded")).

열 선택하기

대괄호의 열 자리에는 이름이나 위치를 넣을 수 있습니다:

두 가지를 유의하세요. 이름으로 선택하면 열 순서가 바뀌어도 안전하지만, 위치로 선택하면(scores[, c(1, 3)]) 누군가 열을 하나 끼워 넣는 순간 깨집니다. 그리고 단일 열을 요청하면 데이터 프레임이 아니라 평범한 벡터가 반환됩니다 - 두 번째 print()가 표 없이 91 88만 보여 주는 이유입니다. 데이터 프레임 형태를 유지하려면 drop = FALSE를 추가하세요: scores[, "score", drop = FALSE].

subset(): 친절한 base R 한 줄 표현

base R에는 행과 열을 한 번의 읽기 쉬운 호출로 처리하는 래퍼가 있습니다 - $도, 쉼표 관리도 필요 없습니다:

subset() 안에서는 열 이름을 그대로 씁니다(scores$score가 아니라 score) - 데이터 프레임을 기준으로 이름을 평가하기 때문입니다. 이를 비표준 평가(non-standard evaluation) 라고 하며, 문서화된 주의 사항이 따라옵니다: 실행 시점에 이름을 해석하기 때문에 직접 만든 함수 안에서는 오작동할 수 있습니다(함수 안의 score 변수가 score라는 열에 가려질 수 있습니다). ?subset이 직접 제시하는 경험칙은 이렇습니다: 대화형 작업에는 훌륭하지만 프로그래밍에서는 피하고 대괄호 인덱싱을 쓰세요.

NA 함정

NA와의 비교는 FALSE가 아니라 NA를 만들고, 대괄호 필터링은 NA 마스크 행을 NA로 가득 찬 행으로 남깁니다:

첫 번째 결과에는 NA로 채워진 쓸모없는 행이 들어 있습니다. 2행의 조건이 TRUEFALSE도 아니었기 때문입니다. 해결책은 !is.na()를 명시적으로 요구하는 것입니다. subset()과 dplyr의 filter()는 둘 다 조건이 NA인 행을 조용히 제거합니다 - 편리하지만 그런 일이 벌어지고 있다는 사실은 알고 있어야 합니다. 결측값 문서에서 NA가 왜 이렇게 번져 나가는지 설명합니다.

dplyr 방식: filter()와 select()

dplyr 패키지는 이 작업을 두 개의 동사로 나눕니다 - 행에는 filter(), 열에는 select() - 열 이름을 그대로 쓰고 df$를 반복할 필요가 없습니다(정적 예제입니다. 샌드박스는 base R만 실행합니다):

library(dplyr)

scores |> filter(score > 80)
scores |> filter(score > 80, team == "red")     # comma = AND
scores |> filter(status %in% c("pending", "shipped"))
scores |> select(name, score)
scores |> filter(team == "red") |> select(name, score)

filter()는 조건이 NA인 행을 자동으로 제거하고 항상 데이터 프레임을 반환하므로(벡터로 떨어지지 않습니다) 위의 base R 함정 두 가지를 모두 없애 줍니다. 대신 패키지 의존성이 생기고 subset()과 동일한 비표준 평가 주의 사항이 따라옵니다 - 전체 동사 투어는 dplyr 입문을 참고하세요.

핵심 정리

  • df[조건, ]이 가장 기본이 되는 관용구이며, 쉼표는 필수입니다.
  • 조건은 홑 &|로 결합하세요. &&는 벡터에서 오류를 냅니다.
  • 값의 집합과 매칭할 때는 ==를 연달아 쓰는 것보다 %in%이 낫습니다.
  • 열은 이름으로 선택하고, drop = FALSE가 없으면 단일 열은 벡터로 떨어진다는 점을 기억하세요.
  • subset()은 대화형 작업에 쾌적한 한 줄 표현이고, 대괄호는 프로그래밍 가능한 방식입니다.
  • NA와의 비교는 대괄호에서 유령 행을 만듭니다 - !is.na()로 방어하세요.

다음 주제: 열을 추가하고 변형하기 - df$new <- ..., ifelse(), 그리고 dplyr의 mutate().

자주 묻는 질문

R에서 데이터 프레임의 행을 어떻게 필터링하나요?

대괄호의 행 위치에 논리 조건을 넣습니다: df[df$score > 80, ]. 조건은 TRUE/FALSE 벡터를 만들고, R은 TRUE인 행만 남깁니다. 쉼표가 중요합니다 - 행 필터와 (비어 있는) 열 필터를 구분해 주기 때문입니다. subset(df, score > 80)은 더 적은 타이핑으로 같은 일을 합니다.

R에서 여러 조건으로 필터링하려면 어떻게 하나요?

&(AND)와 |(OR)로 조건을 결합합니다: df[df$score > 80 & df$team == "red", ]. &&가 아니라 홑 &를 사용하세요 - 두 개짜리 형태는 단일 값에만 동작하며 최신 R에서는 벡터에 대해 오류를 냅니다.

R에서 subset()과 대괄호 필터링의 차이는 무엇인가요?

남기는 행은 같지만 두 가지가 다릅니다: subset()은 조건이 NA인 행을 조용히 제거하지만(대괄호는 NA로 채워진 행으로 남깁니다), subset()은 비표준 평가를 사용해 열 이름을 그대로 적을 수 있습니다. 대화형 작업에서는 편리하지만 직접 만든 함수 안에서는 신뢰하기 어렵습니다.

열 값이 여러 값 중 하나와 일치하는 행만 필터링하려면 어떻게 하나요?

%in%을 사용합니다: df[df$team %in% c("red", "blue"), ]는 team이 나열된 값 중 하나인 행을 남깁니다. |로 이어 붙인 == 비교의 연쇄를 대체하며, ==와 달리 절대 NA를 반환하지 않습니다.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기