2.8 데이터 프레임(data frame)
학습목표: 데이터 프레임 클래스에 대해 알아보고, 데이터 프레임을 생성, 병합(merge), 연산에 대한 함수들에 대해 알아본다.
- Excel 스프레드시트와 같은 형태
이름 | 국적 | 나이 | 순위 |
---|---|---|---|
라파엘 나달 | 스페인 | 35 | 6 |
다닐 메드베데프 | 러시아 | 25 | 2 |
노박 조코비치 | 세르비아 | 34 | 1 |
권순우 | 대한민국 | 25 | 53 |
- 데이터 프레임은 데이터 유형에 상관없이 2차원 형태의 데이터 구조
- 행렬과 리스트를 혼합한 자료 형태 \(\rightarrow\) 동일한 길이의 벡터로 이루어진 리스트를 구성요소로 갖는 리스트
- 행렬과 유사한 구조를 갖고 있지만 각기 다른 유형의 자료형태로 자료행렬을 구성할 수 있다는 점에서 행렬과 차이를 갖음
- 행렬과 마찬가지로 변수(열)의 길이(행의 개수)는 모두 동일해야 함
- R에서 가장 빈번하게 활용되고 있는 데이터 클래스임
- 데이터 프레임의 각 열(컬럼)은 벡터로 간주
2.8.1 데이터 프레임 생성
- 데이터 프레임 생성 함수:
data.frame()
data.frame(
# 값 또는 이름(tag) = 값
..., # 논리값.
# 변수명(열 이름)이 구문 상 유효한 변수인지 또는 중복이 있는지 확인
check.names, # 논리값. 문자형 벡터의 factor 형 강제 변환 여부
stringsAsFactors, )
- 데이터 프레임 생성 예시: 모 병원에서 얻은 환자의 인구학적 정보
<- c(1:10)
id <- rep(c("Female", "Male"), each = 5)
sex <- c(34, 22, 54, 43, 44, 39, 38, 28, 31, 42)
age <- c(112, 118, 132, 128, 128, 124, 121, 119, 124, 109)
sbp <- c(165, 158, 161, 160, 168, 172, 175, 182, 168, 162)
height <- c(52, 48, 59, 60, 48, 72, 73, 82, 64, 60)
weight
<- data.frame(id, sex, age, sbp, height, weight,
df stringsAsFactors = FALSE)
df
attributes(df); str(df); summary(df)
$names
[1] "id" "sex" "age" "sbp" "height" "weight"
$class
[1] "data.frame"
$row.names
[1] 1 2 3 4 5 6 7 8 9 10
'data.frame': 10 obs. of 6 variables:
$ id : int 1 2 3 4 5 6 7 8 9 10
$ sex : chr "Female" "Female" "Female" "Female" ...
$ age : num 34 22 54 43 44 39 38 28 31 42
$ sbp : num 112 118 132 128 128 124 121 119 124 109
$ height: num 165 158 161 160 168 172 175 182 168 162
$ weight: num 52 48 59 60 48 72 73 82 64 60
id sex age sbp
Min. : 1.00 Length:10 Min. :22.00 Min. :109.0
1st Qu.: 3.25 Class :character 1st Qu.:31.75 1st Qu.:118.2
Median : 5.50 Mode :character Median :38.50 Median :122.5
Mean : 5.50 Mean :37.50 Mean :121.5
3rd Qu.: 7.75 3rd Qu.:42.75 3rd Qu.:127.0
Max. :10.00 Max. :54.00 Max. :132.0
height weight
Min. :158.0 Min. :48.00
1st Qu.:161.2 1st Qu.:53.75
Median :166.5 Median :60.00
Mean :167.1 Mean :61.80
3rd Qu.:171.0 3rd Qu.:70.00
Max. :182.0 Max. :82.00
# stringsAsFactors = TRUE 인 경우 sex의 summary() 결과
<- data.frame(id, sex, age, sbp, height, weight,
df stringsAsFactors = TRUE)
summary(df)
id sex age sbp height
Min. : 1.00 Female:5 Min. :22.00 Min. :109.0 Min. :158.0
1st Qu.: 3.25 Male :5 1st Qu.:31.75 1st Qu.:118.2 1st Qu.:161.2
Median : 5.50 Median :38.50 Median :122.5 Median :166.5
Mean : 5.50 Mean :37.50 Mean :121.5 Mean :167.1
3rd Qu.: 7.75 3rd Qu.:42.75 3rd Qu.:127.0 3rd Qu.:171.0
Max. :10.00 Max. :54.00 Max. :132.0 Max. :182.0
weight
Min. :48.00
1st Qu.:53.75
Median :60.00
Mean :61.80
3rd Qu.:70.00
Max. :82.00
summary()
함수는 객체의 클래스에 따라 요약 통계량을 출력해주는 함수- 데이터 프레임이 가지고 있는 변수들의 특징을 손쉽게 알아볼 수 있기 때문에 가장 많이 호출되는 함수 중 하나
- 숫자형 벡터: 최솟값(minimum), 1/4 분위수(1st quantile), 중앙값(median), 평균(mean), 3/4 분위수(3rd quantile), 최댓값을 출력
- 요인형 객체: 요인의 각 수준 별 빈도를 출력
- 2차원 이상
table()
객체에 적용 시 \(\chi^2\) 검정(독립성 검정) 결과값을 출력함.
- 이미 정의된 데이터 프레임에 데이터를 추가 가능
- 예를 들어
dbp
라는 벡터에 이완기 혈압(diastolic blood pressure) 데이터가 입력되어 있고df
에dbp
변수를 새롭게 추가 시df$dbp <- x
형태로 추가 - 위 형태로 이미 존재하고 있는 변수(열)에 새로운 값 재할당 가능
- 이러한 형태로 문자형 벡터 추가 시 문자형 벡터는 자동으로 factor로 형 변환 되지는 않음
- 예를 들어
<- 1:nrow(df)
x <- c(73, 70, 88, 82, 75, 77, 74, 81, 72, 64)
dbp
# df에 "dbp" 열을 생성하고 x 값 대입
$dbp <- x
df df
# df의 dbp에 dbp 벡터의 값을 재할당
$dbp <- dbp
df df
# df에 운동여부 exercyn 라는 변수 추가
# exercyn 는 "Y" 또는 "N" 두 값을 가짐
$exercyn <- c("Y", "Y", "N", "Y", "N",
df"N", "N", "Y", "N", "Y")
str(df)
'data.frame': 10 obs. of 8 variables:
$ id : int 1 2 3 4 5 6 7 8 9 10
$ sex : Factor w/ 2 levels "Female","Male": 1 1 1 1 1 2 2 2 2 2
$ age : num 34 22 54 43 44 39 38 28 31 42
$ sbp : num 112 118 132 128 128 124 121 119 124 109
$ height : num 165 158 161 160 168 172 175 182 168 162
$ weight : num 52 48 59 60 48 72 73 82 64 60
$ dbp : num 73 70 88 82 75 77 74 81 72 64
$ exercyn: chr "Y" "Y" "N" "Y" ...
- 행렬 및 벡터에서 언급 되었던
rownames()
,colnames()
,names()
,dim()
,ncol()/NCOL()
,nrow()/NROW()
함수 적용 가능
rownames(df); colnames(df); names(df)
[1] "1" "2" "3" "4" "5" "6" "7" "8" "9" "10"
[1] "id" "sex" "age" "sbp" "height" "weight" "dbp"
[8] "exercyn"
[1] "id" "sex" "age" "sbp" "height" "weight" "dbp"
[8] "exercyn"
dim(df); ncol(df); nrow(df)
[1] 10 8
[1] 8
[1] 10
# rownames() 함수를 통해 행이름 변경
rownames(df) <- letters[1:10]
df
#colnames() 함수를 통해 열 이름 변경
<- colnames(df)
varname_orig colnames(df) <- paste0("V", 1:ncol(df))
df
# names() 함수와 colnames()는 거의 동일한 기능 수행
# 두 함수의 차이점?
names(df)
[1] "V1" "V2" "V3" "V4" "V5" "V6" "V7" "V8"
names(df) <- varname_orig
df
참고: R Markdown에서 데이터 프레임의 데이터를 손쉽게 테이블로 출력하는 방법(html 문서)
- R Markdwon의 YAML 부분에 다음과 같이 옵션을 추가하면 별다른 함수 처리 없이 데이터 프레임을 표 형태로 html 문서에 붙일 수 있음.
아래 예시에서
output
이후df_print: paged
옵션을 추가 - 옵션 추가 시 들여쓰기(탭 구분)은 YAML 문서의 트리 구조를 표현한 것이기 때문에 꼭 들여쓰기를 정확히 일치시켜야 함
---
title: "문서 제목"
author: "이름"
date: "`r Sys.Date()`"
output:
html_document:
df_print: paged
---
2.8.2 데이터 프레임 접근 및 필터링
접근방법
- 리스트 데이터 접근 방식
# 추출(접근) 연산자(함수) `df$col_name` 형태로 접근
$height df
[1] 165 158 161 160 168 172 175 182 168 162
# df[[index]] 또는 df[["col_name"]] 형태로 접근
4]] df[[
[1] 112 118 132 128 128 124 121 119 124 109
"sex"]] df[[
[1] Female Female Female Female Female Male Male Male Male Male
Levels: Female Male
<- df[[4]]
w attributes(w); str(w)
NULL
num [1:10] 112 118 132 128 128 124 121 119 124 109
# df[index] 또는 df["col_name"] 형태로 접근
<- df["height"]
h attributes(h); str(h)
$names
[1] "height"
$row.names
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
$class
[1] "data.frame"
'data.frame': 10 obs. of 1 variable:
$ height: num 165 158 161 160 168 172 175 182 168 162
- 행렬 데이터 접근 방식
# df[idx_row, idx_col] 또는 df[row_name, col_name]
# 형태 데이터 접근
# 열 index 접근
3]; df[,
[1] 34 22 54 43 44 39 38 28 31 42
# 형 강제 변환 방지
3, drop = FALSE] df[,
# 행 index 접근
8, ] df[
# 행과 열 index 접근
1:4, 5:6] df[
# 열 이름으로 접근
c("sex", "sbp")] df[,
# 행 이름으로 접근
c("d", "e", "f"), ] df[
# 행과 열 이름으로 접근
c("a", "f"), c("sex", "height", "dbp")] df[
# 행 또는 열 제외
-c(2:6), ] df[
-c(1, 5:7), -c(1, 8)] df[
필터링
- 벡터, 행렬과 마찬가지로 비교 연산자를 이용해 조건에 맞는 부분 데이터 추출 가능
# %in% 연산자를 이용해 데이터 프레임의 부분 변수 추출
# id, age 열을 제외한 나머지 데이터 프레임 추출
<- names(df)
varname_df !varname_df %in% c("id", "age")] df[,
# 조건 연산자 사용
# sex 가 Female이고 나이가 40 이상인 데이터 추출
$sex == "Female" & df$age >= 40, ] df[df
# id가 3보다 작은 데이터 추출
1] < 3, ] df[df[,
# subset 함수 이용한 데이터 추출
# sbp 가 120 이상이고 dbp 가 80 이상인 데이터 추출
subset(df, sbp >= 120 & dbp >= 80)
# 성별, 수축기, 이완기 혈압 변수만 추출
subset(df, select = c(sex, sbp, dbp))
# id 변수 제거
subset(df, select = -c(id))
데이터 프레임 또는 리스트 접근 시 df$col_name
를 사용한다면 매번 데이터 프레임 이름과 $
을 반복하기 때문에 코드가 불필요하게 복잡해짐. R에서는 데이터 프레임 내부의 열 이름을 직접 접근할 수 있도록 도와주는 몇 가지 함수(예: with()
, attach()
등)가 있는데, with()
와 within()
활용법에 대해 간략히 알아봄.
- 위 예제에서 sex 가 Female이고 나이가 40 이상인 데이터 추출한다고
했을 때
with()
함수 사용
# with() 함수: 데이터 환경(객체 내)에서 주어진 표현식의 결과를 반환
with(
#리스트 또는 데이터 프레임
data, # 실제 명령을 수행할 표현식,
expr, )
with(df, df[sex == "Female" & age >= 40, ])
within()
함수는with()
와 유사하지만 코드블록({...}
)을 이용해 보다 자유롭게 데이터를 수정 및 추가할 수 있음
<- within(df, {
df2 <- c("A", "B", "B", "A", "C",
hospital "A", "A", "B", "C", "B")
<- mean(age)
mean_age })
2.8.3 데이터 프레임 관련 함수
유틸리티 함수
- 보통 데이터 분석은 외부에서 데이터를 읽은 후 특정 객체에 읽어온 데이터를 할당하는데, 이 경우 데이터가 저장된 객체는 대부분은 데이터 프레임 형태임.
- 읽어온 데이터는 보통 많은 행(표본)으로 구성되어 있기 때문에 데이터를 손쉽게 살펴보는 방법이 필요
데이터 프레임 결합 및 분리 함수
rbind()
/cbind()
함수
- 행렬에서 사용한
rbind()
/cbind()
를 데이터 프레임에도 적용 가능
= data.frame(x1 = rep(0,5), x2 = rep("x",5))
a = data.frame(x1 = rep(1,5), x2 = rep("d",5))
b = data.frame(x3 = rep(2,5), x4 = rep("z",5))
c <- list(1, "d")
d <- list(x5 = rep(4, 5), x6 = rep("y", 5))
e # rbind()를 이용해 두 데이터 프레임 a-b 합치기
<- rbind(a, b)
ab ab
# 변수명이 다른 경우
rbind(a, c) #변수명이 다르기때문에 행으로 묶을 수 없다.
Error in match.names(clabs, names(xi)): 이전에 사용된 이름들과 일치하지 않습니다.
# rbind()를 이용해 데이터 프레임-리스트 합치기
<- rbind(ab, d)
abd abd
# cbind()를 이용해 두 데이터 프레임 a-c 합치기
<- cbind(a, c)
ac ac
# 행 길이가 다르면 작은 길이의 데이터를 재사용
cbind(a, d)
# cbind()를 이용해 두 데이터 프레임-리스트 합치기
<- cbind(ac, e) ace
merge()
함수
- 두 데이터 프레임을 공통된 값을 기준으로 병합
- Excel의
vlookup()
함수 또는 데이터베이스 SQL 쿼리 중join
과 동일한 역할을 함 cbind()
의 경우는 단순히 열을 합치는 것이지만merge()
는 공통되는 열을 기준으로 두 데이터셋을 병합- 공통된 데이터가 있을 때만 데이터 병합 수행
# merge() 함수 인수
merge(
# 병합할 데이터 프레임
x, # 병합할 데이터 프레임
y, # 병합 기준으로 사용할 컬럼 (문자열 벡터)
by, # 병합에 사용할 x와 y의 열 이름이 다른 경우
by.x, # by.x와 by.y에 각각 공통 데이터에 해당하는 열 이름 지정
by.y, # 둘 다 문자형 스칼라 또는 벡터값 인수로 받음
# 논리값 이순
all, # TRUE인 경우 x, y 중 공통된 값을 갖는 행이 없을 때
# 해당 쪽을 NA를 채워 병합
# 결과적으로 x, y 전체 행이 결과에 포함
# x,y 중 특정 쪽에 공통된 값이 없더라도 항상
all.x, # 결과에 포함
all.y, )
merge()
함수 예시
= data.frame(Name = c("Park", "Hanzo", "Mercy", "Soldier76" ),
d1 country = c("Korea", "Japan", "Swiss", "USA"))
= data.frame(Age = c(19,38,37,56,31),
d2 Name = c("Park", "Hanzo", "Mercy", "Soldier76","Mei" ) )
d1; d2
dim(d1); dim(d2)
[1] 4 2
[1] 5 2
# 두 데이터 병합 01
merge(d1, d2, by = "Name")
# 두 데이터 병합 02
names(d2)[2] <- "Surname"
merge(d1, d2, by.x = "Name", by.y = "Surname")
# 두 데이터 병합 03
merge(d1, d2,
by.x = "Name", by.y = "Surname",
all = T)
split()
함수
- Factor 형에서 언급한
split()
함수를 통해 그룹 별로 데이터 분할 - 분할된 데이터는 리스트에 저장
split(df, df$sex)
$Female
id sex age sbp height weight dbp exercyn
a 1 Female 34 112 165 52 73 Y
b 2 Female 22 118 158 48 70 Y
c 3 Female 54 132 161 59 88 N
d 4 Female 43 128 160 60 82 Y
e 5 Female 44 128 168 48 75 N
$Male
id sex age sbp height weight dbp exercyn
f 6 Male 39 124 172 72 77 N
g 7 Male 38 121 175 73 74 N
h 8 Male 28 119 182 82 81 Y
i 9 Male 31 124 168 64 72 N
j 10 Male 42 109 162 60 64 Y
데이터 정렬 함수
sort()
함수
- 데이터(벡터)의 정렬(오름차순 또는 내림차순) 결과 반환
# sort() 함수 인수
sort(
# 정렬할 벡터
x, # 논리값, 내림차순 여부
decreasing, # default = FALSE
# 논리값. 결측 존재 시 NA 값 위치 지정
na.last # TRUE: 정렬 후 결측은 마지막에 위치
) # FALSE: 맨 처음 NA 위치
- 예시
# 오름차순 정렬
sort(df2$age)
[1] 22 28 31 34 38 39 42 43 44 54
# 내림차순 정렬
sort(df$height, decreasing = TRUE)
[1] 182 175 172 168 168 165 162 161 160 158