벡터
R의 데이터 컬렉션
`데이터 컬렉션`은 앞에서 배운 변수들의 보관함이라고 생각하면 됩니다. R에서의 데이터 컬렉션에는 대표적으로 `벡터`, `리스트`, `행렬`, `배열`, `데이터 프레임`등이 있는데요. 참고로 데이터 컬렉션도 변수가 될 수 있습니다. 예를들어 벡터들도 어떤 통에 담겨 보관될 수 있는데요. 이에 대해서는 후에 다루겠습니다.
이번 게시글에서는 R에서 가장 간단한 데이터 컬렉션의 `벡터`에 대해 알아보겠습니다.
벡터란?
`벡터`는 동일한 데이터 타입을 가지는 원소들의 배열입니다.이는 마치 C 언어에서의 배열과 비슷한데요. 보통 배열은 이미 크기가 정해져 있습니다.
참고로 R의 배열(데이터 컬렉션)이랑 지금 말하는 배열은 다릅니다!
R의 `벡터`도 크기가 이미 결정되어 있어, 원소(데이터)를 삽입하거나 삭제할 수 없습니다.
따라서, 원소를 추가하거나 삭제하려면 벡터를 다시 할당해줘야합니다.
벡터 생성
1) c()
아마 앞선 R기초(변수, 데이터 타입, 연산자)편을 읽으신 분들은 벡터를 어떻게 생성하는지 봤을텐데요.
바로 코드를 통해 확인해보겠습니다.
벡터는 `c()` 를 통해 생성할 수 있습니다. 참고로 c 는 combine의 약자입니다. 앞에서 배운 기본 데이터 타입의 변수들을 잘 출력하는 것을 확인할 수 있네요.
그럼 이번에는 아래 코드처럼 벡터 원소로 다른 데이터 타입의 변수들을 넣어보겠습니다.
a <- c(1,2,"3")
분명 `벡터`의 정의에서 벡터는 동일한 타입의 원소를 가진다고 했습니다.
그렇다면 '1, 2 는 숫자형이고 3은 문자형이니 에러가 나겠구나!'라고 생각하실 수 있는데요.
하지만 해당 코드를 실행할때 R은 자동으로 동일한 타입의 원소로 변환을 합니다.
그래서 출력 결과를 확인하면 모든 원소가 문자열로 출력된 것을 확인할 수 있습니다.
여기서 왜 숫자형이 아닌 문자형으로 변환되었는지 궁금하시지 않나요?
R에서는 데이터 타입에 따라 순위(Rank)가 존재하는데요.
리스트 > 문자형 > 복소수형 > 수치형 > 논리형 순입니다.
만약 벡터를 생성할 때 수치형(정수, 실수), 논리형이 있으면 수치형으로 변환하게 됩니다.
2) seq()
c()만으로는 인자들을 직접 입력해야하는 번거로움이 있습니다. 그래서 만일 규칙이 있는 벡터(등차 수열)를 만들고 싶으면 `seq()`를 이용하면 됩니다. 예제를 통해 알아보겠습니다.
- `from`, `to`: 시작, 종료 값
- `by`: 특정 간격으로 벡터 생성 시 사용
- `length`: 특정 길이의 벡터 생성시 사용
`seq()`에는 백터 생성 말고도 다른 기능이 있는데요. 만약 seq()의 인자로 벡터를 주게 되면 어떻게 될까요?
1:length(x)와 동일한 결과를 출력하는 것을 확인할 수 있습니다.
단, x가 NULL (빈 벡터)인 경우에는 두 결과과 다릅니다. 1:length(x)의 경우 1 0 벡터를 반환하지만 seq(x)의 경우는 0을 반환합니다.
주로 1:length(x)을 for문에 사용하는 경우가 많은데요. 대신 seq(x)를 이용하여 x가 빈 경우일 때 대응할 수 있습니다.
3) rep()
`rep()` 를 통해 반복적인 벡터를 만들 때 사용할 수 있습니다.
벡터의 특징
원소에 이름 지어주기
`names()`를 통해 벡터의 각 원소에 이름을 지어줄 수 있습니다. 예제 코드는 아래와 같은데요.
벡터를 출력해보면 이름과 같이 출력되는 것을 확인할 수 있습니다. 추가적으로 names()를 통해 이름만 따로 추출할 수 있습니다.
이는 뒤에서 다룰 데이터의 접근 방법으로 사용할 수 있습니다.
벡터는 중첩할 수 없다.
벡터의 특징 중 하나는 벡터는 중첩할 수 없다는 것입니다.즉, 벡터 안에 벡터를 넣어도 하나의 벡터로 변환된다는 것을 의미합니다.
코드를 통해 알아보겠습니다.
분명 벡터 안에 벡터를 넣었는데 c(1,2,3,4,1,2)와 동일한 결과가 나오네요. 이를 통해 벡터는 단일 차원이라는 것을 알 수 있습니다.
벡터 데이터접근 (Indexing)
벡터의 데이터에 접근하는 방법(Indexing)은 색인을 이용한 방법과 특정 원소를 제외하는 방법 (+ 이름을 이용한 방법) 이 있습니다.
R의 색인(index)는 0이 아닌 1부터 시작합니다.
1) 색인을 이용한 방법
위 코드처럼 `[색인]` 을 통해 단일 데이터에 접근할 수 있습니다.
또한, `:` 연산자를 통해 특정 범위의 데이터를 가져올 수 있습니다.
그렇다면 첫번째와 세번째 데이터를 가져오려면 어떻게 해야할까요?
색인에 정수뿐만 아니라 벡터를 이용하여 특정 원소를 추출할 수 있습니다.
2) 특정 원소를 제외하는 방법
위 예시의 다룬 첫번째와 세번째의 데이터를 가져오는 방법을 다른 관점에서 보면 'a 벡터에서 2번째 원소를 빼고 가져오면 되겠네?'라고 생각할 수 있는데요. 이번에는 해당 방법으로 데이터를 추출해보겠습니다.
`-`와 색인을 이용하면 특정 원소를 제외할 수 있습니다.
동일하게 `-` 와 `색인 벡터`를 이용할 수 있습니다.
Python 의 Numpy 혹은 Pandas 를 사용해보신분들은 a[-2] 를 뒤에서 두번째 원소를 가져오는 것이라고 오해하실 수 있는데요. R에서의 '-'는 Python과 다르게 작동한다는 사실을 주의해주세요!
3) 이름을 이용한 방법
위에서 `names()`를 이용하여 벡터의 원소에 이름을 붙이는 방법을 알아봤는데요. 색인 대신 이름을 이용하여 데이터에 접근할 수도 있습니다.
여기서 재밌는 사실은 이름에 중복된 `num1`이 있을 때, 앞에 있는 원소만을 가져온다는 점입니다.
벡터 필터링
그렇다면 중복된 이름의 원소를 모두 가져오는 방법은 없을까요? 특정 조건의 필요한 벡터의 값만을 추출하는 것을 `필터링`이라고 합니다.
벡터에서 필터링을 하는 방법에 대해 알아보겠습니다.
1) 비교 연산자 이용
위 코드처럼 `==` 연산자를 이용해 인덱싱하는 방법으로 이름이 `num1`인 원소들을 모두 가져올 수 있습니다.
비교 연산자를 통해 값과 벡터를 비교하면 위와 같이 Boolean 형으로 반환되는 것을 알 수 있습니다.
즉, `a[names(a) == "num1"]`은 위와 동일합니다.
2) subset() 이용
`subset()` 을 이용해서도 특정 조건을 검색할 수 있습니다.
cf) 특정 조건의 index 가져오기
`which()`를 이용해 특정 조건을 만족하는 index를 가져올 수 있습니다.
벡터 연산
벡터 산술 연산
위 예시처럼 앞선 게시글에서 수치형 변수의 산술 연산자에 다뤘었는데요. 이를 벡터에도 동일하게 적용할 수 있습니다.
벡터 집합 연산
벡터에서 집합 연산도 가능합니다. 코드는 다음과 같습니다.
R의 Recycling
R의 특징 중 하나는 같은 길이를 요구하는 벡터 계산의 경우 자동으로 더 짧은 벡터의 원소들을 반복하여 계산을 수행합니다. 코드를 통해 확인해보겠습니다.
위 예시를 통해 5, 6 에 1, 2가 더해진 것을 확인할 수 있습니다. 추가적으로 두 벡터간의 길이가 다르다는 경고문이 뜨는데요. 이로 인해 우리가 예상치 못했던 결과들이 나올 수 있으니 주의를 해야합니다.
벡터 사용법
특정 값 찾기 (%in%)
`%in%`을 통하여 특정 값이 벡터에 포함되어 있는지 확인할 수 있습니다.
만약 벡터를 앞에 쓰면, 각 원소별로 비교할 수 있습니다.
중복된 값 제거하기 (unique)
`unique()`를 이용하여 벡터에서 반복되는 값을 제거할 수 있습니다.
길이 확인하기 (length)
`length()`을 이용하여 벡터의 길이를 얻을 수 있습니다.
벡터화
R에서는 인자로 벡터를 사용할 수 있습니다. 이를 `벡터화`라 하고 for문으로 각 인자에 접근할 필요가 없어 계산 속도가 빠릅니다.
다음 R의 기초문법을 먼저 참고하면 이해하는데 도움이 됩니다.
함수 인자의 벡터화
x 인자에 벡터가 들어가 벡터를 반환하는 것을 확인할 수 있습니다.
추가적으로 R에서 제공하는 초월 함수(ex.로그 함수, 삼각 함수 등)도 벡터화되어있습니다.
ifelse
if 조건문도 벡터화되어 있어 다음과 같이 사용가능합니다.
정리
벡터에 대한 전반적인 내용에 대해 알아보았는데요. 벡터는 R에서 매우 중요한 개념이기 때문에 자세히 설명하다보니 글이 길어졌습니다 ㅠㅠ..
그럼에도 불구하고 벡터에 대해 아직 다루진 못한 내용들도 있는데요. 이후에 배울 데이터 컬렉션이나 함수에서 부족한 부분은 추가적으로 설명하겠습니다! 긴 글 읽어주셔서 감사합니다.