데이터 프레임은 열들의 리스트입니다
데이터 프레임은 R의 표입니다. 행은 관측값이고 열은 변수입니다. R의 스프레드시트이며, 실제 데이터가 도착하는 사실상 모든 형태입니다. 사람마다, 측정마다, 거래마다 한 행씩이고 속성마다 한 열씩입니다.
구조적으로 데이터 프레임은 길이가 같은 벡터들의 리스트 위에 행/열 동작이 얹힌 것입니다. 이 한 가지 사실이 규칙 대부분을 설명합니다. 각 열은 벡터이므로 단일 타입을 갖고, 리스트이므로 열마다 다른 타입을 가질 수 있으며, 모든 열의 길이가 같아야 합니다. 그 부분이 "프레임"입니다.
이름이 붙은 벡터들을 data.frame()에 건네 만듭니다.
텍스트, 숫자, 논리값이 나란히 놓여 있습니다. 행렬은 담을 수 없는 조합입니다. 실제로는 이렇게 손으로 입력할 일이 드뭅니다. 표는 보통 read.csv나 데이터베이스를 통해 들어옵니다. 하지만 데이터 프레임이 어디서 왔든 아래 내용은 똑같이 적용됩니다.
데이터 프레임 파악하기
들여다보지 않은 데이터셋으로 계산하지 마세요. R의 점검 도구는 짧고 반사적으로 쓸 만합니다.
str()은 새로 불러온 데이터에 가장 먼저 실행할 것입니다. 열마다 한 줄씩 타입과 첫 값들을 보여 줍니다. 값 하나가 잘못 섞여 실제로는 문자로 읽힌 "숫자" 열을 잡아내는 곳입니다.nrow()/ncol()은 차원을 주고,names()는 열 이름을 나열합니다.summary()는 열별 통계를 줍니다. 숫자에는 최솟값/중앙값/평균/최댓값을, 논리값과 팩터에는 개수를 보여 줍니다.head(df)와tail(df)는 처음과 마지막 여섯 행을 출력합니다. 실제 데이터셋이 통째로 출력하기엔 너무 커지면 없어서는 안 됩니다. 아래에서 내장 데이터셋에head()를 적용해 보겠습니다.
열을 가져오는 세 가지 방법
열 접근은 가장 기본적인 작업이며, R은 세 가지 표기를 제공합니다.
people$age- 일상적인 형태입니다. 짧고 읽기 쉬우며 대부분의 편집기에서 자동 완성됩니다.people[["age"]]- 결과는 같지만 이름을 변수에서 가져올 수 있습니다(col <- "age"; people[[col]]).$는 그럴 수 없습니다. 함수 안에서는 이쪽을 택하세요.people[, "age"]- 행렬 스타일입니다. 쉼표 앞이 행(비우면 전부), 뒤가 열입니다.
셋 다 열을 평범한 벡터로 돌려주므로 mean(people$age)에 바로 쓸 수 있습니다. 코드의 네 번째 표기가 함정입니다. 대괄호 하나를 쓰는 people["age"]는 벡터가 아니라 열이 하나인 데이터 프레임을 돌려줍니다. 리스트에서 보았던 [와 [[의 구분과 같은데, 데이터 프레임이 곧 리스트이기 때문입니다. 수학 함수가 입력이 수치형이 아니라고 불평한다면 대괄호를 확인하세요.
행과 셀
[행, 열] 표기로 표의 어떤 조각에도 닿을 수 있습니다.
people[2, ]는 두 번째 행 전체입니다(행은 타입이 섞이므로 1행짜리 데이터 프레임으로 프레임을 유지합니다). people[2, "name"]은 셀 하나입니다. 행 번호 벡터를 주면 여러 행을 가져옵니다.
마지막 줄이 중요합니다. 열에 대한 논리 조건이 행을 선택합니다. 여기서는 28살보다 많은 모두입니다. 행을 마스킹하는 이 패턴은 R의 모든 데이터 필터링의 토대이며 별도의 글을 가질 자격이 있습니다. subset()과 다중 조건 필터를 포함한 전체 설명은 필터링과 부분 선택을 참고하세요.
열 추가와 제거
데이터 프레임은 열들의 리스트이므로 열은 평범한 대입으로 생기고 사라집니다.
새 이름에 대입하면 열이 추가됩니다. 벡터의 길이는 nrow()와 같아야 합니다(또는 길이 1이면 재활용되어 모든 행을 채웁니다). 두 번째 추가는 관용적인 방식을 보여 줍니다. 기존 열에서 계산한 새 열을, 열 전체에 대한 벡터화 연산으로 한 번에 만드는 것이죠. NULL을 대입하면 열이 완전히 삭제됩니다.
열의 값도 같은 방식으로 덮어쓸 수 있습니다. people$age <- people$age + 1은 모두를 한 살 더 먹게 합니다.
내장 데이터셋, 그리고 tibble에 대한 한마디
R에는 연습용 데이터셋이 미리 실려 있어 아무것도 불러오지 않고 위의 모든 것을 시험해 볼 수 있습니다. 모든 튜토리얼에서 만나게 될 두 가지는 mtcars(자동차 32대, 수치 변수 11개)와 iris(꽃 150송이, 측정값 4개와 종 팩터)입니다.
head()가 제 몫을 합니다. 여섯 행만으로 화면을 채우지 않고 대상의 모양을 알려 주죠. 이 데이터셋들은 이상적인 놀이터입니다. 어떤 함수의 동작이 확실하지 않다면 자기 데이터에 들이대기 전에 mtcars로 시험해 보세요.
tidyverse를 건드리는 순간 만나게 될 용어가 하나 있습니다. tidyverse가 데이터 프레임을 재해석한 tibble입니다. 개념은 같고 동작은 더 예의 바릅니다. 출력할 때 열 타입과 함께 처음 열 행만 보여 주고, 부분 이름 매칭이 없습니다. tibble()로 만들거나 readr/dplyr 함수가 돌려줍니다.
library(tibble)
tibble(name = c("Rosa", "Ken"), age = c(30, 41))
#> # A tibble: 2 x 2
#> name age
#> <chr> <dbl>
#> 1 Rosa 30
#> 2 Ken 41
이 글의 모든 것($, str(), 열 추가, 논리 행 마스크)이 tibble에서도 그대로 동작합니다. tibble은 광택을 더한 데이터 프레임입니다. 데이터 프레임을 배우면 둘 다 배운 셈입니다.
핵심 정리
- 데이터 프레임은 길이가 같은 열들의 리스트입니다. 열마다 한 타입, 표 전체로는 섞인 타입을 갖는 R의 스프레드시트입니다.
- 계산하기 전에 살펴보세요.
str()을 먼저, 그다음head(),summary(),nrow()/ncol()/names()입니다. df$col,df[["col"]],df[, "col"]은 모두 열을 벡터로 돌려주고, 대괄호 하나인df["col"]은 데이터 프레임을 돌려줍니다.df[행, 열]로 무엇이든 잘라 낼 수 있고, 쉼표 앞의 논리 마스크가 행을 걸러 냅니다.- 대입으로 열을 추가하고(종종 다른 열에서 계산합니다),
NULL로 제거하며,mtcars로 연습하세요.
다음 순서는 결측값입니다. NA가 무엇을 뜻하는지, 왜 계산 전체로 퍼지는지, 어떻게 다뤄야 하는지를 살펴봅니다.
자주 묻는 질문
R에서 데이터 프레임은 어떻게 만드나요?
이름이 붙고 길이가 같은 벡터들을 data.frame()에 전달하세요. 예: df <- data.frame(name = c("Rosa", "Ken"), age = c(30, 41)). 각 벡터가 하나의 열이 됩니다. 실무에서는 대부분의 데이터 프레임을 손으로 입력하지 않고 read.csv()나 데이터베이스에서 받아 오지만 구조는 같습니다.
R의 데이터 프레임에서 열에 어떻게 접근하나요?
세 가지 방법이 있습니다. df$age(빠르고 읽기 쉬움), df[["age"]](같은 결과이며 열 이름이 변수에 담겨 있을 때도 동작), df[, "age"](행렬 스타일)입니다. 셋 다 열을 평범한 벡터로 돌려줍니다. 대괄호 하나를 쓰는 df["age"]는 대신 열이 하나인 데이터 프레임을 돌려주며, 흔한 혼란의 원인입니다.
데이터 프레임에 str()을 쓰면 무엇이 보이나요?
열마다 한 줄씩 이름, 타입, 처음 몇 개의 값이 보이고 맨 위에 행과 열의 개수가 나옵니다. 어떤 열이 수치형으로 읽혔는지 텍스트로 읽혔는지 확인하는 가장 빠른 방법이며, 그래서 새로 불러온 데이터셋에 가장 먼저 실행해야 할 것이 str()입니다.
R에서 데이터 프레임에 열을 어떻게 추가하나요?
아직 없는 이름에 대입하세요. df$score <- c(88, 75, 93)처럼 합니다. 벡터의 길이가 행 개수와 같아야 합니다(또는 길이 1이면 모든 행으로 재활용됩니다). 열을 제거하려면 NULL을 대입하세요. df$score <- NULL입니다.