2.3 벡터(vector)
2.3.1 벡터의 특징
- 타 프로그래밍 언어의 배열(array)의 개념으로 동일한 유형의 데이터 원소가 하나 이상(\(n \times 1\), \(n \geq 1\)) 으로 구성된 자료 형태
- R 언어의 가장 기본적인 데이터 형태로 R에서 행해지는 모든 연산의 기본 단위임
- 벡터 연산 시 반복구문(예:for loop)이 필요 없음. 이러한 형태의 연산을 벡터화 연산(vectorization)이라고 함.
- 2.2 절에서 기술한 스칼라(scalar)는 사실 \(1 \times 1\) 벡터임
- 수학적으로 벡터는 아래와 같이 정의할 수 있음.
\[\mathrm{\mathbf x} = [x_1, x_2, x_3, \ldots, x_n]^T \]
- 벡터는 앞의 예시에서 본 바와 같이 c()함수를 사용해 생성
# 숫자형 벡터 
x <- c(2, 0, 2, 0, 0, 3, 2, 4)
x[1] 2 0 2 0 0 3 2 4# 문자형 벡터
y <- c("Boncho Ku", "R programming", "Male", "sophomore", "2020-03-24")
y[1] "Boncho Ku"     "R programming" "Male"          "sophomore"    
[5] "2020-03-24"   - 두 개 이상의 벡터는 c()함수를 통해 결합 가능- 함수 내 ,구분자를 통해 결합
 
- 함수 내 
# 두 벡터의 결합 (1)
x <- 1:5
y <- 10:6
z <- c(x, y)
x[1] 1 2 3 4 5y[1] 10  9  8  7  6z [1]  1  2  3  4  5 10  9  8  7  6x <- 5:10
x1 <- x[1:3] # x 벡터에서 1에서 4번째 원소 추출
x2 <- c(x1, 15, x[4])
x2[1]  5  6  7 15  8- 서로 다른 자료형으로 벡터를 구성한 경우 표현력이 높은 자료형으로
변환한 값 반환
- 예: 문자열 + 숫자로 구성된 벡터 \(\rightarrow\) 문자형 벡터
- 변환규칙:
NULL < raw < logical < integer < double < complex < character < list < expression
 
# 숫자형 벡터와 문자열 벡터 혼용
k <- c(1, 2, "3", "4")
k[1] "1" "2" "3" "4"is.numeric(k) # 벡터가 숫자형인지 판단하는 함수[1] FALSEis.character(k) # 벡터가 문자열인지 판단하는 함수[1] TRUE# 숫자형 벡터와 문자열 벡터 결합
x <- 1:3
y <- c("a", "b", "c")
z <- c(x, y)
z[1] "1" "2" "3" "a" "b" "c"is.numeric(z)[1] FALSEis.character(z)[1] TRUE# 숫자형 벡터와 논리형 벡터 결합
x <- 9:4
y <- c(TRUE, TRUE, FALSE)
z <- c(x, y)
z # TRUE/FALSE 가 1과 0으로 변환[1] 9 8 7 6 5 4 1 1 0is.numeric(z)[1] TRUEis.logical(z)[1] FALSE- 두 벡터는 중첩이 불가능 \(\rightarrow\) 동일한 벡터 2개를 결합 시 단일 차원 벡터 생성
x <- y <- 1:3 # x와 y 동시에 [1, 2, 3] 할당
x [1] 1 2 3y[1] 1 2 3z <- c(x, y)
z[1] 1 2 3 1 2 3- 벡터 각 원소에 이름 부여 가능
- names()함수를 이용해 원소 이름 지정
- 사용 프로토타입: names(x) <- 문자열 벡터, 단x와 이름에 입력할 문자열 벡터의 길이는 같아야 함.
- c()함수에서 직접 이름 지정 \(\rightarrow\)- c(atom_name1 = value, atom_name2 = value, ...)
 
x <- c("Boncho Ku", "R programming", "Male", "sophomore", "2020-03-24")
# 벡터 원소 이름 지정
names(x) <- c("name", "course", "gender", "grade", "date") 
x           name          course          gender           grade            date 
    "Boncho Ku" "R programming"          "Male"     "sophomore"    "2020-03-24" y <- c(a = 10, b = 6, c = 9)
names(y)[1] "a" "b" "c"- 벡터의 길이(차원) 확인
- length()또는- NROW()사용
 
x <- 1:50
# 객체의 길이 반환
# length(): 벡터, 행렬인 경우 원소의 개수, 데이터프레임인 경우 열의 개수 반환
length(x) [1] 50# NROW(): 벡터인 경우 원소의 개수, 행렬, 데이터 프레임인 경우 행의 개수 반환
NROW(x)[1] 502.3.2 벡터의 연산
- 원소 단위 사칙연산 및 비교연산 수행 \(\rightarrow\) 벡터화
연산(vectorized operation)
- 예를 들어 \(\mathrm{\mathbf x} = [1, 2, 3]^T\) 이고, \(\mathrm{\mathbf y} = [2, 3, 4]^T\) 라고 할 때 \(\mathrm{\mathbf x} + \mathrm{\mathbf y}\)의 연산은 아래와 같음
 
\[\begin{bmatrix} 1 \\ 2\\ 3 \end{bmatrix} + \begin{bmatrix} 2 \\ 3\\ 4 \end{bmatrix} = \begin{bmatrix} 3 \\ 5 \\ 7 \end{bmatrix} \]
- *연산 시 행렬 대수학에서 벡터의 곱(product)과 다름을 주의
\[\begin{bmatrix} 1 \\ 2\\ 3 \end{bmatrix} * \begin{bmatrix} 2 \\ 3\\ 4 \end{bmatrix} = \begin{bmatrix} 2 \\ 6 \\ 12 \end{bmatrix} \]
x <- 1:3; y <- 2:4
length(x); length(y)[1] 3[1] 3x; y[1] 1 2 3[1] 2 3 4# 사칙연산(+, -, *, /)
# 백터 vs. 백터
x + y[1] 3 5 7x - y[1] -1 -1 -1x * y[1]  2  6 12x / y[1] 0.5000000 0.6666667 0.7500000# 그외 연산
# 나머지(remainder)
y %% x[1] 0 1 1# 몫(quotient)
y %/% x[1] 2 1 1# 멱승(exponent)
y ^ x[1]  2  9 64- 차원이 서로 맞지 않는 경우 작은 차원(짧은 쪽)의 백터를 재사용함
\[\begin{bmatrix} 1 \\ 2\\ 3 \end{bmatrix} + [5] = \begin{bmatrix} 1 \\ 2\\ 3 \end{bmatrix} + \begin{bmatrix} 5 \\ 5\\ 5 \end{bmatrix} = \begin{bmatrix} 6 \\ 7 \\ 8 \end{bmatrix} \]
# 벡터(n by 1) vs. 스칼라(1 by 1)
x * 5 # 5을 x의 길이 만큼 재사용(반복) 후 곱 연산 수행[1]  5 10 15x <- c(2, 1, 3, 5, 4); y <- c(2, 3, 4)
x[1] 2 1 3 5 4y[1] 2 3 4length(x); length(y)[1] 5[1] 3# x의 길이가 5이고 y의 길이가 3이기 때문에 5를 맞추기 위헤
# y의 원소 중 1-2 번째 원소를 재사용
x + yWarning in x + y: 두 객체의 길이가 서로 배수관계에 있지 않습니다[1] 4 4 7 7 7x / yWarning in x/y: 두 객체의 길이가 서로 배수관계에 있지 않습니다[1] 1.0000000 0.3333333 0.7500000 2.5000000 1.3333333- 연산 순서는 일반적인 사칙연산의 순서를 준용
- 단 1단위 수열을 생성하는 :연산자가 사칙연산을 우선함
 
- 단 1단위 수열을 생성하는 
# 연산 우선 순위
1:5 * 3[1]  3  6  9 12 151:(5 * 3) [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15- 논리형 값으로 구성된 벡터의 기본 연산 시 수치형으로 변환된 연산 결과를 반환
# 논리형 벡터
b1 <- c(TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE)
b2 <- c(FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE)
is.numeric(b1); is.numeric(b2)[1] FALSE[1] FALSEis.logical(b1); is.logical(b2)[1] TRUE[1] TRUE# 논리형 벡터 연산
b3 <- b1 + b2
is.numeric(b3)[1] TRUEb3[1] 1 2 1 2 2 2 0 1b1 - b2[1]  1  0 -1  0  0  0  0 -1b1 * b2[1] 0 1 0 1 1 1 0 0b1/b2[1] Inf   1   0   1   1   1 NaN   0- 두 벡터 간 비교 연산은 사칙연산과 마찬가지로 각 원소단위 연산을
수행하고 논리형 벡터 반환
- 재사용 규칙은 그대로 적용됨
 
# 두 벡터의 비교 연산
x <- c(2, 4, 3, 10, 5, 9)
y <- c(3, 4, 6, 2, 10, 7)
x == y[1] FALSE  TRUE FALSE FALSE FALSE FALSEx != y[1]  TRUE FALSE  TRUE  TRUE  TRUE  TRUEx > y[1] FALSE FALSE FALSE  TRUE FALSE  TRUEx < y[1]  TRUE FALSE  TRUE FALSE  TRUE FALSEx >= y[1] FALSE  TRUE FALSE  TRUE FALSE  TRUEx <= y[1]  TRUE  TRUE  TRUE FALSE  TRUE FALSE# 비교 연산 시 두 벡터의 길이가 다른 경우
x <- 1:5; y <- 2:4
x == yWarning in x == y: 두 객체의 길이가 서로 배수관계에 있지 않습니다[1] FALSE FALSE FALSE FALSE FALSEx != yWarning in x != y: 두 객체의 길이가 서로 배수관계에 있지 않습니다[1] TRUE TRUE TRUE TRUE TRUEx > yWarning in x > y: 두 객체의 길이가 서로 배수관계에 있지 않습니다[1] FALSE FALSE FALSE  TRUE  TRUEx < yWarning in x < y: 두 객체의 길이가 서로 배수관계에 있지 않습니다[1]  TRUE  TRUE  TRUE FALSE FALSEx >= yWarning in x >= y: 두 객체의 길이가 서로 배수관계에 있지 않습니다[1] FALSE FALSE FALSE  TRUE  TRUEx <= yWarning in x <= y: 두 객체의 길이가 서로 배수관계에 있지 않습니다[1]  TRUE  TRUE  TRUE FALSE FALSE- 문자열 벡터의 연산은 ==또는!=만 가능(사칙연산 불가능)
# 문자열 벡터 연산 (==, !=)
c1 <- letters[1:5]
# a-z로 구성된 벡터에서 1-2, 6-8 번째 원소 추출
c2 <- letters[c(1:2, 6:8)] 
c1[1] "a" "b" "c" "d" "e"c2[1] "a" "b" "f" "g" "h"c1 == c2[1]  TRUE  TRUE FALSE FALSE FALSEc1 != c2[1] FALSE FALSE  TRUE  TRUE  TRUE- NA를 포함한 두 벡터 연산 시 동일 위치에- NA가 존재하면 어떤 연산이든- NA값을 반환
# 결측을 포함한 벡터
x <- c(1:10, c(NA, NA))
y <- c(NA, NA, 1:10)
x [1]  1  2  3  4  5  6  7  8  9 10 NA NAy [1] NA NA  1  2  3  4  5  6  7  8  9 10is.na(x); is.na(y) [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE [1]  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE# 결측을 포함한 벡터의 연산 
x + y [1] NA NA  4  6  8 10 12 14 16 18 NA NAx / y [1]       NA       NA 3.000000 2.000000 1.666667 1.500000 1.400000 1.333333
 [9] 1.285714 1.250000       NA       NAx < y [1]    NA    NA FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE    NA    NAx > y [1]   NA   NA TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE   NA   NA- NULL이 벡터에 포함되더라도 벡터의 길이에는 변동이 없음
# NULL을 포함한 벡터 
x <- c(1, 2, 3, NULL, NULL, NULL) # 길이가 6?
length(x)[1] 3x[1] 1 2 32.3.3 벡터의 색인(indexing)
- 벡터의 특정 위치에 있는 원소를 추출
 
- 색인(indexing)을 통해 벡터의 원소에 접근 가능
- 타 언어는 대체로 첫 번째 색인이 0에서 시작하지만, R은 1부터 시작
- x[i]: 벡터- x의- i번 째 요소
- x[start:end]:- x의- start부터- end까지 값 반환
x <- c(1.2, 3.1, 4.2, 2.8, 3.3)
x[3] # x 원소 중 3 번째 원소 추출[1] 4.2# x 원소 중 2-3번째 원소 추출
x[2:3][1] 3.1 4.2- x[-i]: 벡터- x에서- i번 째 요소를 제외한 나머지 값 반환
# x의 3 번째 원소 제거
x[-3][1] 1.2 3.1 2.8 3.3# 맨 마지막 원소(5 번째) 제거
# 아래 script는 동일한 결과 출력
x[1:(length(x) - 1)][1] 1.2 3.1 4.2 2.8x[-length(x)][1] 1.2 3.1 4.2 2.8- x[idx_vec]:- idx_vec가 인덱싱 벡터라고 할 때- idx_vec에 지정된 요소를 얻어옴. 일반적으로- idx_vec는 백터의 행 순서 번호 또는 각 벡터 원소의 이름에 대응하는 문자열 벡터를 인덱싱 벡터로 사용할 수 있음.
# 벡터를 이용한 인덱싱
# x 원소 중 1, 5번째 원소 추출
x[c(1, 5)] # c(1,5)는 벡터[1] 1.2 3.3v <- c(1, 4)
x[v][1] 1.2 2.8# 인덱스 번호 중복 가능
x[c(1, 2, 2, 4)][1] 1.2 3.1 3.1 2.8# 원소 이름으로 인덱싱
# 원소 이름 지정
names(x) <- paste0("x", 1:length(x)) # 문자열 "x"와 숫자 1:5(벡터 길이)를 결합한 문자열 반환
x["x3"] x3 
4.2 x[c("x2", "x4")] x2  x4 
3.1 2.8 - 필터링(filtering): 특정한 조건을 만족하는 원소 추출
- 비교 연산자를 이용한 조건 생성 \(\rightarrow\) 논리값을 이용한 원소 추출
 
z <- c(5, 2, -3, 8)
# z의 원소 중 z의 제곱이 8보다 큰 원소 추출
w <- z[z^2 > 8]
w[1]  5 -3  8- 작동 원리
- z^2 > 8은 벡터- z의 모든 원소 제곱값이 8 보다 큰 케이스를 논리형 값으로 반환
 
z^2[1] 25  4  9 64idx <- z^2 > 8
idx[1]  TRUE FALSE  TRUE  TRUEz[idx][1]  5 -3  8- 특정 조건을 만족하는 벡터의 위치에 임의의 값을 치환할 수 있음
# 위 벡터 z 의 원소 중 z^2 > 8 인 원소의 값을 0으로 치환
z[idx] <- 02.3.4 벡터 관련 함수
- c()함수 외에 R은 벡터 생성을 위해 몇 가지 유용한 함수를 제공함
seq 계열 함수
보다 자세한 사용 설명은
help(seq)참고
seq(): 등차 수열 생성하는 함수로 from에서 end 까지 숫자 내에서
공차(간격)가 by 인 수열 생성
# seq(): 수열 생성 함수
seq(
  from, # 시작값
  to,   # 끝값
  by    # 공차(증가치)
)
# 기타 인수
# length.out = n
#   - 생성하고자 하는 벡터의 길이가 n인 수열 생성
# along.with = 1:n 
#   - index가 1에서 n 까지 길이를 갖는 수열 생성- 사용 예시
x <- seq(from = 2, to = 30, by = 2)
x  [1]  2  4  6  8 10 12 14 16 18 20 22 24 26 28 30# 간격이 꼭 정수가 아니어도 사용 가능
x <- seq(from = 0, to = 3, by = 0.2)
# by 대신 length.out 으로 생성된 수열의 길이 조정
x <- seq(from = -3, to = 3, length.out = 10)
x [1] -3.0000000 -2.3333333 -1.6666667 -1.0000000 -0.3333333  0.3333333
 [7]  1.0000000  1.6666667  2.3333333  3.0000000# from, to 인수 없이 length.out=10 인 경우
seq(length.out = 10) [1]  1  2  3  4  5  6  7  8  9 10# by 대신 along.width 
seq(along.with=1:10) [1]  1  2  3  4  5  6  7  8  9 10seq(1, 5, along.with=1:10) [1] 1.000000 1.444444 1.888889 2.333333 2.777778 3.222222 3.666667 4.111111
 [9] 4.555556 5.000000# 벡터 x에 seq() 함수 적용 시 1:length(x) 값 반환
seq(x) [1]  1  2  3  4  5  6  7  8  9 10seq_along(): 주어진 객체의 길이 만큼 1부터 1 간격의 수열 생성
- seq()함수와 매우 유사하나, 무조건 1부터 시작해서 인수로- seq()의- along.with값을 이용한 함수
- seq()함수보다 조금 빠름
- 사용 예시
# 1부터 x 벡터의 길이 까지 1 단위 수열 값 반환
seq_along(x) [1]  1  2  3  4  5  6  7  8  9 10seq_len(): 인수로 받은 값 만큼 1부터 해당 값 까지 1 간격의 수열
생성
- seq()함수의 인수 중- length.out값을 이용한 함수
- 사용 예시
# 1부터 n 까지 1 단위 수열 값 반환
seq_len(10) [1]  1  2  3  4  5  6  7  8  9 10rep 계열 함수
help(rep)을 통해 상세 내용 참고
rep(): 주어진 벡터의 원소를 반복
# rep(): 벡터 또는 벡터의 개별 원소를 반복한 값 반환
rep(
  x, # 반복할 값이 저장된 벡터
  times, # 전체 벡터의 반복 횟수
  each # 개별 원소의 반복 횟수
)- 사용 예시
x <- rep(4, 5) # 4를 5번 반복
x[1] 4 4 4 4 4# x <- c(1:3) 전체를 3번 반복한 벡터 반환
x <- c(1:3)
xr1 <- rep(x, times = 3)
xr1[1] 1 2 3 1 2 3 1 2 3# 벡터 x 의 각 원소를 4번씩 반복한 벡터 반환
xr2 <- rep(x, each = 4)
xr2 [1] 1 1 1 1 2 2 2 2 3 3 3 3# 벡터 x 의 각 원소를 3번 반복하고 해당 벡터를 2회 반복
xr3 <- rep(x, each = 3, times = 2)
xr3 [1] 1 1 1 2 2 2 3 3 3 1 1 1 2 2 2 3 3 3# 문자형 벡터의 반복
# 아래 sex 벡터의 각 원소를 2 번 반복하고 해당 벡터를 4회 반복
sex <- c("Male", "Female")
sexr <- rep(sex, each = 2, times = 4)
sexr [1] "Male"   "Male"   "Female" "Female" "Male"   "Male"   "Female" "Female"
 [9] "Male"   "Male"   "Female" "Female" "Male"   "Male"   "Female" "Female"rep.int() & rep_len(): rep() 함수의 simple 버전으로
속도(performance)가 요구되는 프로그래밍 시 사용
- 사용 예시
# 1:5 벡터를 3 번 반복
rep.int(1:5, 3) [1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5# 불완전한 사이클로 벡터 반복
rep_len(1:5, length.out = 7)[1] 1 2 3 4 5 1 2Filtering 관련 함수
help(subset)참고
subset(): 기존 필터링 방식과 비교할 때 NA를 처리하는 방식에서
차이를 보임
- 벡터 뿐 아니라 앞으로 배울 행렬 및 데이터프레임 객체에도 적용 가능
x <- c(6, 1:3, NA, NA, 12)
x[1]  6  1  2  3 NA NA 12# 일반적 필터링 적용 
x[x > 5][1]  6 NA NA 12# subset() 함수 적용
subset(x, x > 5)[1]  6 12which(): 한 벡터에서 특정 조건에 맞는 위치(인덱스)를 반환
# which(): 논리형 벡터를 인수로 받고 해당 논리형 벡터가 참인 index 반환
which(
  logical_vec # 논리형 벡터
)- 사용 예시
x <- c(3, 8, 3, 1, 7)
# x의 원소값이 3인 index 반환
which(x == 3)[1] 1 3# x의 원소가 4보다 큰 원소의 index 반환
which(x > 4)[1] 2 5# 9월(Sep)과 12월(Dec)와 같은 원소 index
# month.abb: R 내장 벡터로 월 약어(Jan ~ Dec)를 저장한 문자열 벡터
which(month.abb == c("Sep", "Dec"))[1]  9 12# 조건을 만족하는 원소가 존재하지 않는다면?
x <- which(x > 9)
xinteger(0)length(x) # 길이가 0인 벡터 반환 is.null(x) == TRUE ??[1] 0is.null(x)[1] FALSE# 특정 조건 만족 여부를 확인 
# any(condition) -> 하나라도 condition을 만족하는 원소가 존재하는지 판단
# TRUE 또는 FALSE 값 반환
any(x > 9)[1] FALSE집합 관련 함수
- 벡터는 숫자, 문자열의 묶음, 즉 원소들의 집합(set)으로 볼 수 있기 때문에 집합 연산이 가능
- 두 집합을 \(X\)와 \(Y\)로 정의 했을 때 아래와 같은 집합 연산 가능
- setequal(X, Y):- X와- Y가 동일한지 판단 (\(X = Y\)) \(\rightarrow\) 논리값- TRUE또는- FALSE반환
x <- y <- c(1, 9, 7, 3, 6)
setequal(x, y)[1] TRUE- union(X, Y):- X와- Y의 합집합 (\(X \cup Y\))
y <- c(1, 9, 8, 2, 0, 3)
union(x, y)[1] 1 9 7 3 6 8 2 0- intersect(X, Y):- X와- Y의 교집합 (\(X \cap Y\))
intersect(x, y)[1] 1 9 3- setdiff(X, Y):- X와- Y의 차집합 (\(X - Y\))
setdiff(x, y)[1] 7 6setdiff(y, x)[1] 8 2 0- X %in% Y:- X(기준)가 집합- Y의 원소인지 논리값 반환
x <- c("apple", "banana", "strawberry", "mango", "peach", "orange")
y <- c("strawberry", "orange", "mango")
x %in% y[1] FALSE FALSE  TRUE  TRUE FALSE  TRUEy %in% x[1] TRUE TRUE TRUE두 벡터의 동일성 테스트
- 두 벡터가 동일한지 테스트 하기 위해 x == y연산의 반환 값은 위의 예제에서 확인한 것 처럼 각 원소에 대한 논리값을 반환(아래 예제 확인)
x <- 1:3
y <- c(1, 3, 4)
x == y[1]  TRUE FALSE FALSE- 단지 두 벡터가 동일한지 아닌지를 확인하기 위해서는 하나의 논리값만
필요한 경우 all()사용
all(x == y)[1] FALSE- 보다 나은 방법으로 identical()함수 적용
# 두 객체의 동일성 여부 테스트
identical(x, y)[1] FALSE- identical()함수는 벡터가 갖는 데이터 타입의 동일성 까지 체크함
x <- 1:5; y <- c(1, 2, 3, 4, 5)
x[1] 1 2 3 4 5y[1] 1 2 3 4 5# all() 함수로 동일성 확인
all(x == y)[1] TRUE# identical 함수로 동일성 확인
identical(x, y)[1] FALSE# x, y 데이터 타입 확인
typeof(x)[1] "integer"typeof(y)[1] "double"