재현가능한 과학적 분석을 위한 R
데이터 부분집합
학습 목표
- 벡터, 요인, 행렬, 리스트, 데이터프레임 부분집합을 뽑아낼 수 있다.
- 개별, 다수 요소를 다음 기준으로 뽑아낼 수 있다:
- 색인
- 명칭
- 비교 연산을 사용
- 다양한 자료구조로부터 요소를 건너뛰거나 제거할 수 있다.
R에는 강력한 부분집합 연산자를 다수 구비되어 있다. 이를 완전히 익히게 되면 어떤 유형의 데이터셋에 대해서도 복잡한 연산을 수월하게 수행할 수 있게 된다.
어떤 유형의 객체에서 부분집합을 뽑아낼 수 있는 방식은 6가지가 있다. 다른 자료구조에 대한 부분집합을 뽑아내는 연산자는 3가지가 있다.
R의 핵심으로 가장 많은 일은 하는 것부터 시작해본다: 원자 벡터(atomic vector)
x <- c(5.4, 6.2, 7.1, 4.8, 7.5)
names(x) <- c('a', 'b', 'c', 'd', 'e')
x
a b c d e
5.4 6.2 7.1 4.8 7.5
이제 작업할 준비가 마루타 벡터를 생성했다. 해당 벡터 내용물을 손에 넣는 방식은 무엇인가?
색인을 사용한 요소 접근
벡터 요소를 추출하는데, 대응되는 색인을 부여하는데, 1부터 시작된다:
x[1]
a
5.4
x[4]
d
4.8
꺾쇠 괄호 연산자는 다른 어떤 함수와 비슷한다. 원자 벡터(그리과 행렬)에 대해, “n번째 요소를 뽑아낸다”라는 의미다.
한번에 다수 요소를 뽑아낼 수도 있다:
x[c(1, 3)]
a c
5.4 7.1
혹은, 벡터 슬라이스로 뽑아낼 수도 있다:
x[1:4]
a b c d
5.4 6.2 7.1 4.8
:
연산자는 왼쪽 요소부터 우측 요소까지 연속된 숫자를 생성한다. 예를 들어, x[1:4]
은 x[c(1,2,3,4)]
와 동등하다:
x[c(1,1,3)]
a a c
5.4 5.4 7.1
벡터를 벗어난 숫자를 뽑아내려고 하면, R은 결측값을 반환한다:
x[6]
<NA>
NA
길이 1을 갖는 벡터로 NA
가 담겨있고, 명칭도 NA
다.
0번째 요소를 뽑아내려고 하면, 공벡터가 반환된다:
x[0]
named numeric(0)
요소 건너뛰고 제거하기
벡터 색인으로 음수를 사용하면, R은 명세된 숫자를 제외한 모든 요소를 반환한다:
x[-2]
a c d e
5.4 7.1 4.8 7.5
다수 요소를 건너뛸 수도 있다:
x[c(-1, -5)] # 혹은 x[-c(1,5)]
b c d
6.2 7.1 4.8
벡터에서 요소를 제거하려면, 결과를 다시 벡터에 대입할 필요가 있다:
x <- x[-4]
x
a b c e
5.4 6.2 7.1 7.5
도전 과제 1
다음과 같이 코드가 주어졌다:
x <- c(5.4, 6.2, 7.1, 4.8, 7.5)
names(x) <- c('a', 'b', 'c', 'd', 'e')
print(x)
a b c d e
5.4 6.2 7.1 4.8 7.5
- 다음 출력결과를 산출하는 적어도 서로 다른 명령어 3개 제시한다:
b c d
6.2 7.1 4.8
- 작업결과를 옆 사람과 비교한다. 서로 다른 전략을 취했나요?
명칭으로 부분집합 뽑아내기
색인 대신에 명칭을 사용해서, 요소를 뽑아낼 수 있다:
x[c("a", "c")]
a c
5.4 7.1
명칭을 사용한 것이 객체에 대한 부분집합을 뽑아내는 훨씬 더 신뢰성 있는 방식이다: 다양한 요소 위치는 부분집합을 뽑아내는 연산자를 연결해서 적용할 때 종종 변경되지만, 명칭은 항상 동일하게 남게 마련이다!
불행하게도, 그다지 수월하게 요소를 건너뛰거나 제거할 수는 없다.
요소 하나를 건너뛰거나 제거하려면:
x[-which(names(x) == "a")]
b c d e
6.2 7.1 4.8 7.5
which
함수는 함수 인자의 모든 TRUE
요소에 대한 색인을 반환한다. 함수에 전달되기 전에 표현식이 평가됨을 기억한다. 내부를 파고들어, 어떤 일이 진행되는지 명확히 알아보자.
다음이 가장 먼저 진행된다:
names(x) == "a"
[1] TRUE FALSE FALSE FALSE FALSE
조건 연산자는 x
벡터에 대한 모든 명칭에 적용된다. 첫번째 명칭만 “a” 라서, 해당 요소만 참(TRUE)이 된다.
그리고 나면, which
가 이를 색인으로 변환한다:
which(names(x) == "a")
[1] 1
첫번째 요소만 참(TRUE)
이라서, which
는 1을 반환한다. 이제 색인을 갖게 되서, 건너뛰는 연산이 동작한다. 왜냐하면 음수 색인이기 때문이다!
명칭을 갖는 다수 색인을 건너뛰는 것도 유사하다. 하지만, 다른 비교 연산자를 사용한다:
x[-which(names(x) %in% c("a", "c"))]
b d e
6.2 4.8 7.5
%in%
비교연산자는 좌측 인자(이번 경우에, x
명칭)에 대한 각 요소를 훑는다. 그리고 나서, “해당 요소가 두번째 인자에 나타나는가?”라고 질의한다.
도전과제 2
다음 코드를 실행해서 x
벡터를 정의한다.
x <- c(5.4, 6.2, 7.1, 4.8, 7.5)
names(x) <- c('a', 'b', 'c', 'd', 'e')
print(x)
a b c d e
5.4 6.2 7.1 4.8 7.5
x
벡터가 주어지면, 다음 명령어는 어떤 작업을 수행할 것으로 예상되는가?
x[-which(names(x) == "g")]
상기 명령어를 시도해보고, 실행결과를 살펴본다. 여러분의 예상과 일치하는가? 왜 이런 결과가 나왔을까? (Tip: 여러분이 직접 작성한 것처럼 한땀한땀 명령어 각각을 테스트한다 - 매우 유용한 디버깅 전략이다.)
다음 중 어떤 것이 사실인가:
which
에 전달되는TRUE
값이 없다면, 공벡터가 반환된다.
which
에 전달되는TRUE
값이 없다면, 오류 메시지가 나타난다.
integer()
는 공벡터다.
- 공벡터를 부정하면 “모든” 벡터를 만들어낸다.
x[]
은x[integer()]
와 동일한 결과를 산출한다.
x <- 1:3 x
[1] 1 2 3
names(x) <- c('a', 'a', 'a') x
a a a 1 2 3
x['a'] # 첫번째 값만 반환한다.
a 1
x[which(names(x) == 'a')] # 세가지 값 모두 반환한다.
a a a 1 2 3
그러면, 이전처럼 ==
연산자는 왜 사용할 수 없을까? 매우 좋은 질문이다.
비교에 해당되는 항목만 살펴보자:
names(x) == c('a', 'c')
Warning in names(x) == c("a", "c"): 두 객체의 길이가 서로 배수관계에 있지
않습니다
[1] TRUE FALSE TRUE
분명히, “c”는 x
요소명칭 중에 존재한다. 그런데, 왜 동작을 하지 않을까? ==
은 %in%
과는 다소 다른방식으로 동작한다. ==
은 좌측 인자 요소 각각을 대응되는 우측 요소 각각과 비교한다.
==
연산자를 모사한 것이 다음에 나와 있다:
c("a", "b", "c", "e") # x 명칭
| | | | # ==으로 요소들을 비교한다.
c("a", "c")
한 벡터가 다른 벡터보다 작은 경우, 해당 벡터는 재사용된다:
c("a", "b", "c", "e") # x 명칭
| | | | # ==으로 요소들을 비교한다.
c("a", "c", "a", "c")
이런 경우, R이 단순히 c("a", "c")
을 두번 반복한다. 더 긴 벡터가 더 짧은 벡터의 배수가 아닌 경우, R은 경고 메시지도 출력한다:
names(x) == c('a', 'c', 'e')
[1] TRUE FALSE FALSE
==
와 %in%
차이점을 숙지하는 것이 중요한데, 이유는 탐지가 어렵고 미묘한 버그가 스며들 수 있기 때문이다!
논리 연산자를 통한 부분집합 뽑아내기
더 단순하게는 논리 연산자로 부분집합을 뽑아낼 수도 있다:
x[c(TRUE, TRUE, FALSE, FALSE)]
a a
1 2
이번 경우, 논리 벡터는 부분집합을 뽑아내는 벡터 길이만큼 재사용됨에 주목한다!
x[c(TRUE, FALSE)]
a a
1 3
비교 연산자는 논리벡터로 평가되기 때문에, 간결하게 벡터 부분집합을 뽑아내는데 사용할 수도 있다:
x[x > 7]
named integer(0)
도전과제 3
다음 코드가 주어졌다:
x <- c(5.4, 6.2, 7.1, 4.8, 7.5)
names(x) <- c('a', 'b', 'c', 'd', 'e')
print(x)
a b c d e
5.4 6.2 7.1 4.8 7.5
x
벡터에서 4보다 크고 7보다 적은 값을 부분집합으로 뽑아내는 명령어를 작성한다.
특수값 처리하기
어느 지점에 다다르면, R 함수에 처리할 수 없는 결측값, 무한값, 정의되지 않는 값을 갖는 데이터와 마주하게 된다.
이런 유형의 데이터를 필터링하는데 사용되는 특수 함수가 있다:
is.na
는 벡터, 행렬, 데이터프레임에 포함된NA
위치를 반환한다.- 마찬가지로,
is.nan
와is.infinite
함수도NaN
와Inf
값에 대한 동일한 작업을 수행한다. is.finite
함수는NA
,NaN
,Inf
값을 포함하지 않는 벡터, 행렬, 데이터프레임에 대한 모든 위치정보를 반환한다.na.omit
는 벡터에서 모든 결측값을 필터링해서 제외시키다.
요인 부분집합으로 뽑아내기
지금까지 벡터 부분집합을 뽑아내는 다양한 방식을 탐색했다. 다른 자료구조에 대한 부분집합은 어떻게 뽑아낼 수 있을까?
요인 부분집합 뽑아내기는 벡터 부분집합 뽑아내기와 동일한 방식으로 동작한다.
f <- factor(c("a", "a", "b", "c", "c", "d"))
f[f == "a"]
[1] a a
Levels: a b c d
f[f %in% c("b", "c")]
[1] b c c
Levels: a b c d
f[1:3]
[1] a a b
Levels: a b c d
중요한 주의점 하나는 건너뛰는 요소가 설사 해당 범주가 요인으로 존재하지 않더라도, 수준(level)을 제거하지 않는다는 점이다:
f[-3]
[1] a a c c d
Levels: a b c d
행렬 부분집합 뽑아내기
행렬의 경우도 [
함수를 사용해서 부분집합을 뽑아낸다. 이번 경우에는 인자를 두개 사용한다: 첫번째 인자는 행에 적용되고, 두번째 인자는 칼럼에 적용된다:
set.seed(1)
m <- matrix(rnorm(6*4), ncol=4, nrow=6)
m[3:4, c(3,1)]
[,1] [,2]
[1,] 1.12493092 -0.8356286
[2,] -0.04493361 1.5952808
첫번째 혹은 두번째 인자를 공백으로 남겨놓을 수도 있는데, 모든 행 혹은 칼럼을 각각 불러올 경우 사용한다:
m[, c(3,4)]
[,1] [,2]
[1,] -0.62124058 0.82122120
[2,] -2.21469989 0.59390132
[3,] 1.12493092 0.91897737
[4,] -0.04493361 0.78213630
[5,] -0.01619026 0.07456498
[6,] 0.94383621 -1.98935170
행 혹은 칼럼 하나만 접근하고자 하면, R이 자동으로 결과값을 벡터로 전환시킨다:
m[3,]
[1] -0.8356286 0.5757814 1.1249309 0.9189774
결과값을 행렬로 그대로 유지하고자 한다면, 세번째 인자를 명세할 필요가 있다; drop = FALSE
:
m[3, , drop=FALSE]
[,1] [,2] [,3] [,4]
[1,] -0.8356286 0.5757814 1.124931 0.9189774
벡터와 달리, 행렬 외부 행과 칼럼을 접근하고자 하면, R이 오류를 던진다:
m[, c(3,6)]
Error in m[, c(3, 6)]: 첨자의 허용 범위를 벗어났습니다
행렬을 까면 정말 자료형이 벡터라서, 단지 인자 하나로만 부분집합을 추출할 수도 있다:
m[5]
[1] 0.3295078
보통 유용하지는 않다. 하지만, 행렬이 열우선형식(column-major format)으로 기본디폴트 설정으로 되어있음에 주목한다. 즉, 벡터 요소가 칼럼방향으로 배열된다는 것을 의미한다:
matrix(1:6, nrow=2, ncol=3)
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
행렬을 행우선으로 쭉 펼치고자 한다면, byrow=TRUE
를 사용한다:
matrix(1:6, nrow=2, ncol=3, byrow=TRUE)
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
행과 칼럼 색인 대신에 행명칭(rownames)과 열명칭(column names)을 사용해서 배열 부분집합을 뽑아낼 수 있다.
도전과제 4
다음과 같은 코드가 주어졌다:
m <- matrix(1:18, nrow=3, ncol=6)
print(m)
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 4 7 10 13 16
[2,] 2 5 8 11 14 17
[3,] 3 6 9 12 15 18
- 다음 중 어떤 명령어가 값 11과 14를 추출하는 하는가?
A. m[2,4,2,5]
B. m[2:5]
C. m[4:5,2]
D. m[2,c(4,5)]
리스트 부분집합 뽑아내기
이제 몇가지 새로운 부분집합을 뽑아내는 연산자를 소개한다. 리스트 부분집합을 뽑아내는데 사용되는 함수가 세가지 있다; 원자벡터와 행렬에서 살펴본 [
, 그리고 [[
, $
이 있다.
[
을 사용하면, 항상 리스트만 반환한다. 리스트 부분집합을 뽑아내고자 하지만, 요소는 뽑아내고 싶지 않다면, 아마도 [
연산자를 사용할 것이다.
xlist <- list(a = "Software Carpentry", b = 1:10, data = head(iris))
xlist[1]
$a
[1] "Software Carpentry"
상기 명령어는 요소 하나만 갖는 리스트를 반환한다.
[
연산자를 사용해서 원자벡터에 적용한 그대로 리스트 요소를 부분집합으로 뽑아낼 수 있다. 하지만, 리스트가 재귀적으로 되어 있지 않다면, 비교 연산자는 동작하지 않는다. 이유는 비교 연산자가 데이터 구조 내부 개별 요소가 아닌, 리스트 각 요소에 내재한 자료구조로 되어있기 때문이다.
xlist[1:2]
$a
[1] "Software Carpentry"
$b
[1] 1 2 3 4 5 6 7 8 9 10
리스트 개별 요소를 추출하려면, 이중 꺾쇠 함수를 사용한다: [[
.
xlist[[1]]
[1] "Software Carpentry"
이제 결과값이 리스트가 아닌 벡터에 주목한다.
한번에 요소 하나이상을 추출할 수는 없다:
xlist[[1:2]]
Error in xlist[[1:2]]: 첨자의 허용 범위를 벗어났습니다
요소를 건너뛰는 것도 사용할 수 없다:
xlist[[-1]]
Error in xlist[[-1]]: 한 개 이상의 구성요소 선택을 시도합니다
하지만, 명칭을 사용해서 요소에 대한 부분집합으로 뽑아내거나, 요소를 추출할 때 사용할 수 있다:
xlist[["a"]]
[1] "Software Carpentry"
$
함수는 명칭으로 요소를 뽑아내는데 사용되는 초간편 방법이다:
xlist$data
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
도전 과제 5
다음 리스트가 주어졌다:
xlist <- list(a = "Software Carpentry", b = 1:10, data = head(iris))
리스트와 벡터 부분집합을 추출하는 지식을 활용해서, xlist
에서 숫자 2를 추출한다. 힌트: 숫자 2는 리스트 “b” 항목 내부에 담겨있다.
도전 과제 6
선형 모형이 다음과 같이 주어졌다:
mod <- aov(pop ~ lifeExp, data=gapminder)
잔차 자유도를 추출하라. 힌트: attributes()
함수가 도움을 줄 것이다.
데이터프레임
데이터프레임을 까면 내부는 리스트로 구성된 것을 기억한다. 그래서 유사한 규칙이 적용된다. 하지만, 데이터프레임도 2차원 객체다:
[
함수에 인자를 하나만 넣으면 리스트와 동일하게 동작한다. 즉, 각 리스트 요소는 칼럼에 대응된다. 작업결과 나오는 객체는 데이터프레임이다:
head(gapminder[3])
pop
1 8425333
2 9240934
3 10267083
4 11537966
5 13079460
6 14880372
유사하게, [[
함수는 칼럼 한개만 추출하는데 동작된다:
head(gapminder[["lifeExp"]])
[1] 28.801 30.332 31.997 34.020 36.088 38.438
명칭으로 칼럼을 추출하는데 사용되는 편리한 단축어가 $
이다:
head(gapminder$year)
[1] 1952 1957 1962 1967 1972 1977
인자가 두개 있는 경우, [
함수는 행렬에 대해서와 마찬가지로 동작한다:
gapminder[1:3,]
country year pop continent lifeExp gdpPercap
1 Afghanistan 1952 8425333 Asia 28.801 779.4453
2 Afghanistan 1957 9240934 Asia 30.332 820.8530
3 Afghanistan 1962 10267083 Asia 31.997 853.1007
행 하나만 부분집합으로 뽑아내면, 결과는 데이터프레임이 되는데 이유는 각 요소가 혼합된 자료형으로 구성되었기 때문이다:
gapminder[3,]
country year pop continent lifeExp gdpPercap
3 Afghanistan 1962 10267083 Asia 31.997 853.1007
하지만, 단일 칼럼에 대해서 결과는 벡터다. drop = FALSE
를 세번째 인자로 넣으면 바꿀 수 있다.
도전과제 7
데이터프레임 부분집합을 뽑아내는 오류가 다음에 나와 있는데 이를 버그없이 수정하라:
- 1957년에 수집된 관측점을 뽑아내라.
gapminder[gapminder$year = 1957,]
- 1에서 4를 제외한 모든 칼럼을 뽑아내라.
gapminder[,-1:4]
- 기대수명이 80세 이상 되는 행을 추출하라.
gapminder[gapminder$lifeExp > 80]
- 첫번째 행과 4번째 5번째 칼럼(
lifeExp
,gdpPercap
)을 뽑아내라. .
gapminder[1, 4, 5]
- 고급: 2002년과 2007년에 대한 정보를 담고 있는 행을 추출하라.
gapminder[gapminder$year == 2002 | 2007,]
도전과제 8
gapminder[1:20]
명령어는 왜 오류를 반환하는가?gapminder[1:20,]
와 어떻게 다른가?gapminder_small
이라는 데이터프레임을 생성하는데 1에서 9까지 행과 19에서 23까지 행만 포함한다. 이 작업을 하나 혹은 두 단계로 작성한다.
도전과제 해답
도전과제 1에 대한 해답
다음과 같은 코드가 주어졌다:
x <- c(5.4, 6.2, 7.1, 4.8, 7.5)
names(x) <- c('a', 'b', 'c', 'd', 'e')
print(x)
a b c d e
5.4 6.2 7.1 4.8 7.5
- 다음 출력결과를 산출하는 적어도 서로 다른 명령어 3개를 제시한다:
b c d
6.2 7.1 4.8
x[2:4]
x[-c(1,5)]
x[c("b", "c", "d")]
x[c(2,3,4)]
도전과제 2에 대한 해답
다음 코드를 실행해서 x
벡터를 정의한다.
x <- c(5.4, 6.2, 7.1, 4.8, 7.5)
names(x) <- c('a', 'b', 'c', 'd', 'e')
print(x)
a b c d e
5.4 6.2 7.1 4.8 7.5
x
벡터가 주어지면, 다음 명령어는 어떤 작업을 수행할 것으로 예상되는가?
x[-which(names(x) == "g")]
상기 명령어를 시도해보고, 실행결과를 살펴본다. 여러분의 예상과 일치하는가? 왜 이런 결과가 나왔을까? (Tip: 여러분이 직접 작성한 것처럼 한땀한땀 명령어 각각을 테스트한다 - 매우 유용한 디버깅 전략이다.)
다음 중 어떤 것이 사실인가:
which
에 전달되는TRUE
값이 없다면, 공벡터가 반환된다.
which
에 전달되는TRUE
값이 없다면, 오류 메시지가 나타난다.
integer()
는 공벡터다.
- 공벡터를 부정하면 “모든” 벡터를 만들어낸다.
x[]
은x[integer()]
와 동일한 결과를 산출한다.
정답: A 와 C 가 맞다.
which
명령어는 입력값에 대한 모든 TRUE
값에 대한 색인을 반환한다. names(x) == "g"
은 어떤 TRUE
값도 반환하지 않는다. which
명령어에 전달되는 어떤 TRUE
값도 없기 때문에, 공벡터를 반환했다. 음수 부호로 벡터를 부정한다고 의미가 변경되지는 않는다. x
벡터에서 값을 가져오는데 공벡터를 사용했기 때문에, 빈 숫자벡터를 만들어 낸다. 결과는 named numeric
공벡터다. 이유는 x
벡터 자료형이 “named numeric”인데, 명칭을 값에 대입했기 때문이다(str(x)
을 시도해 보라).
도전과제 4에 대한 해답
다음과 같은 코드가 주어졌다:
m <- matrix(1:18, nrow=3, ncol=6)
print(m)
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 4 7 10 13 16
[2,] 2 5 8 11 14 17
[3,] 3 6 9 12 15 18
- 다음 중 어떤 명령어가 값 11과 14를 추출하는 하는가?
A. m[2,4,2,5]
B. m[2:5]
C. m[4:5,2]
D. m[2,c(4,5)]
정답: D
도전과제 5에 대한 해답
다음 리스트가 주어졌다:
xlist <- list(a = "Software Carpentry", b = 1:10, data = head(iris))
리스트와 벡터 부분집합을 추출하는 지식을 활용해서, xlist
에서 숫자 2를 추출한다. 힌트: 숫자 2는 리스트 “b” 항목 내부에 담겨있다.
xlist$b[2]
xlist[[2]][2]
xlist[["b"]][2]
도전과제 6에 대한 해답
선형 모형이 다음과 같이 주어졌다:
mod <- aov(pop ~ lifeExp, data=gapminder)
잔차 자유도를 추출하라. 힌트: attributes()
함수가 도움을 줄 것이다.
attributes(mod) ## `df.residual` is one of the names of `mod`
mod$df.residual
도전과제 7에 대한 해답
데이터프레임 부분집합을 뽑아내는 오류가 다음에 나와 있는데 이를 버그없이 수정하라:
- 1957년에 수집된 관측점을 뽑아내라.
# gapminder[gapminder$year = 1957,]
gapminder[gapminder$year == 1957,]
- 1에서 4를 제외한 모든 칼럼을 뽑아내라.
# gapminder[,-1:4]
gapminder[,-c(1:4)]
- 기대수명이 80세 이상 되는 행을 추출하라.
# gapminder[gapminder$lifeExp > 80]
gapminder[gapminder$lifeExp > 80,]
- 첫번째 행과 4번째 5번째 칼럼(
lifeExp
,gdpPercap
)을 뽑아내라. .
# gapminder[1, 4, 5]
gapminder[1, c(4, 5)]
- 고급: 2002년과 2007년에 대한 정보를 담고 있는 행을 추출하라.
# gapminder[gapminder$year == 2002 | 2007,]
gapminder[gapminder$year == 2002 | gapminder$year == 2007,]
gapminder[gapminder$year %in% c(2002, 2007),]
도전과제 8에 대한 해답
gapminder[1:20]
명령어는 왜 오류를 반환하는가?gapminder[1:20,]
와 어떻게 다른가?
정답: gapminder
는 데이터프레임이다. 그래서 차원 2개로 부분집합을 뽑아낼 필요가 있다. gapminder[1:20, ]
는 첫번째부터 20번째 모든 행과 모든 칼럼을 부분집합으로 뽑아낸다.
gapminder_small
이라는 데이터프레임을 생성하는데 1에서 9까지 행과 19에서 23까지 행만 포함한다. 이 작업을 하나 혹은 두 단계로 작성한다.
gapminder_small <- gapminder[c(1:9, 19:23),]