Menu

R의 벡터: c(), seq(), 인덱싱, 벡터화 연산

벡터는 R의 기본 단위입니다. 숫자 하나조차 벡터입니다. c()로 만들고, (1부터!) 인덱싱하고, 논리 마스크로 걸러 내고, 벡터 전체에 한 번에 계산하는 방법을 다룹니다.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

R의 모든 것은 벡터입니다

대부분의 언어에는 단일 값인 스칼라가 있고, 그것들을 여러 개 담는 컨테이너 타입이 따로 있습니다. R은 스칼라를 건너뜁니다. 벡터는 모두 같은 타입을 공유하는 값들의 순서 있는 모음이며, 다른 모든 것이 그 위에 세워집니다. 홀로 있는 숫자처럼 보이는 것조차 길이 1의 벡터입니다.

combine의 줄임말인 c()는 벡터를 손으로 만드는 방법입니다. length()는 원소가 몇 개인지 알려 줍니다. 그리고 5 하나만으로도 is.vectorTRUE, 길이는 1로 보고됩니다. R은 벡터로 일하기를 멈추지 않고, 다만 가끔 아주 짧은 벡터를 다룰 뿐입니다.

이 설계 때문에 R 코드는 Python이나 JavaScript와 달라 보입니다. 다른 곳에서는 반복문을 써야 할 연산이 R에서는 표현식 하나로 벡터 전체에 적용됩니다. 아래에서 다루겠습니다.

지금 몸에 새길 규칙이 하나 있습니다. 벡터의 모든 원소는 같은 타입입니다. c()에 섞인 값을 넘겨도 불평하지 않습니다. 존재하는 것 중 가장 유연한 타입으로 조용히 전부 변환합니다.

문자열이 섞이면 모든 것이 문자열이 됩니다("1", "TRUE"). 숫자들 사이의 논리값은 10이 됩니다. 이 강제 변환은 logical → integer → double → character라는 고정된 서열을 따르며 경고 없이 일어납니다. 숫자 열에 끼어든 "7" 하나가 데이터셋 전체를 조용히 텍스트로 바꿔 놓을 수 있는 이유입니다. 전체 위계는 데이터 타입에서 다룹니다. 진짜로 섞인 값을 담아야 한다면 그것이 리스트의 역할입니다.

수열 만들기: :, seq(), rep()

c()에 모든 원소를 입력하는 일은 금방 지겨워집니다. R에는 규칙적인 패턴을 위한 세 가지 지름길이 있습니다.

  • 1:10은 일상적인 것입니다. 한 경계에서 다른 경계까지 1씩 증가하는 정수입니다.
  • seq()는 그것을 일반화합니다. by =로 간격을 정하거나, length.out =으로 원하는 원소 개수를 말하고 간격은 R이 계산하게 합니다.
  • seq_len(n)1부터 n까지를 만들며 반복문 인덱스를 만드는 안전한 방법입니다. 1:n과 달리 n이 0일 때 1 0처럼 거꾸로 세지 않고 올바르게 빈 벡터를 줍니다.
  • rep()는 반복합니다. times =는 벡터 전체를 끝에서 끝으로 반복하고(1 2 1 2 1 2), each =는 각 원소를 제자리에서 반복합니다(1 1 1 2 2 2). 둘은 헷갈리기 쉽습니다. 코드를 실행해 비교해 보세요.

인덱싱: R은 1부터 셉니다

대괄호로 원소를 꺼냅니다. 첫 원소는 [0]이 아니라 [1]입니다. Python이나 JavaScript에서 왔다면 초반에 가장 흔히 걸려 넘어지는 지점입니다.

여기서 멈춰 볼 만한 세 가지가 있습니다.

  • 위치들의 벡터로 인덱싱할 수 있습니다. fruits[c(2, 4)]는 두 번째와 네 번째를 한 번에 가져옵니다.
  • 음수 인덱스는 "그것만 빼고 전부"를 뜻합니다. fruits[-1]은 첫 원소가 빠진 벡터입니다. -1이 마지막 원소를 뜻하는 Python과는 완전히 다릅니다. 한 호출에서 양수와 음수 인덱스를 섞을 수는 없습니다.
  • fruits[0]은 오류가 아니라 빈 character(0)을 돌려줍니다. R에서 오프바이원 버그는 충돌 대신 조용한 빈 결과를 만들 때가 많으므로, 뒤쪽에서 무언가가 알 수 없이 비어 보이면 length()를 확인하는 것이 좋습니다.

원소는 이름을 가질 수도 있으며, 이는 라벨로 인덱싱하는 세 번째 방법을 제공합니다.

이름 있는 벡터는 가벼운 조회 표처럼 동작하며 코드를 읽기 쉽게 유지합니다. prices["tea"]는 의미를 말해 주지만 prices[2]는 그렇지 않습니다.

논리 마스크와 which()

가장 강력한 인덱싱 방법은 논리 벡터, 즉 데이터와 길이가 같은 TRUE/FALSE 마스크를 쓰는 것입니다. 벡터에 대한 모든 비교가 정확히 그것을 만들어 냅니다.

temps > 24는 하나의 답이 아니라 원소마다 하나씩 다섯 개의 답을 줍니다. 그 마스크를 [ ] 안에 넣으면 마스크가 TRUE인 원소만 남습니다. 조건은 &(그리고)와 |(또는)로 결합하며, 나머지는 연산자에서 다룹니다.

which()는 마스크를 위치로 번역합니다. 여기서는 더운 관측값의 인덱스인 2 3 5입니다. 일치가 어디에 있는지 알아야 할 때, 즉 그것을 보고하거나 같은 위치로 다른 벡터를 인덱싱할 때 쓰세요. 단순한 필터링에는 temps[which(temps > 24)]보다 temps[temps > 24]가 더 직접적입니다.

마스크로 필터링하는 이 패턴은 R에서 이루어지는 사실상 모든 데이터 작업의 척추입니다. 데이터 프레임의 행을 걸러 낼 때 그대로 다시 등장합니다.

벡터화 연산과 재활용 규칙

R의 산술은 벡터 전체에 원소 단위로 적용됩니다. 반복문이 필요 없습니다.

첫 줄이 대표 기능입니다. prices * 2는 모든 원소를 두 배로 만듭니다. 다른 언어가 for 반복문을 필요로 하는 곳에서 R은 연산자 하나면 됩니다. 게다가 벡터화된 형태가 더 짧고 더 빠릅니다. 반복이 아래쪽의 최적화된 C에서 일어나기 때문입니다. 각 단계가 이전 단계에 의존한다면 for 반복문을 쓰고, 원소 단위 계산이라면 벡터화하세요.

세 번째 줄은 재활용 규칙을 보여 줍니다. 벡터의 길이가 다르면 R은 짧은 쪽을 반복해 맞춥니다. c(10, 20)10 20 10 20으로 재활용되어 11 22 13 24가 됩니다. 길이 3인 벡터에 2가 재활용되는 것이 바로 prices * 2가 동작하는 원리입니다. 스칼라는 그저 재활용되는 길이 1의 벡터입니다.

긴 길이가 짧은 길이의 정확한 배수일 때 재활용은 깔끔합니다. 그렇지 않으면 R은 여전히 답을 계산하되 경고를 냅니다.

11 22 13과 함께 긴 객체의 길이가 짧은 객체 길이의 배수가 아니라는 경고가 나옵니다. 그 경고는 버그 보고서로 취급하세요. 부분 재활용은 의도한 것인 경우가 거의 없으며, 대개 같은 길이여야 할 두 벡터가 그렇지 않다는 뜻입니다.

정렬, 뒤집기, 중복 제거

끊임없이 쓰게 될 작은 도구 세 가지입니다.

sort()는 값을 순서대로 정렬하고, rev()는 정렬 없이 기존 순서를 뒤집으며, unique()는 처음 등장한 것을 남기고 중복을 버립니다. 어느 것도 x를 수정하지 않습니다. R의 거의 모든 것과 마찬가지로 새 벡터를 돌려주고 원본은 그대로 둡니다.

핵심 정리

  • 벡터는 R의 기본 단위입니다. 순서가 있고, 전체가 한 타입이며, 단일 값조차 길이 1의 벡터입니다.
  • c()로 만들고 :, seq(), rep()으로 패턴을 생성합니다. c()가 섞인 타입을 조용히 강제 변환한다는 점을 기억하세요.
  • 인덱싱은 1부터 시작하고, 음수 인덱스는 원소를 제거하며, 이름을 쓰면 라벨로 인덱싱할 수 있습니다.
  • 논리 마스크(x[x > 5])는 언어 전체의 필터링 관용구이고, which()는 마스크를 위치로 바꿔 줍니다.
  • 연산은 벡터화되어 있고 짧은 벡터는 재활용되며, 부분 재활용 경고는 버그가 있다는 뜻입니다.

다음 순서는 리스트입니다. 값들이 하나의 타입을 공유하지 않을 때를 위한 컨테이너입니다.

자주 묻는 질문

R에서 벡터는 어떻게 만드나요?

c() 함수(combine의 줄임말)를 사용합니다. 예: x <- c(10, 20, 30). 규칙적인 수열에는 1:10, seq(0, 1, by = 0.25), rep(0, 5)을 쓰세요. 모든 원소는 결국 같은 타입이 되어야 하며, 타입을 섞으면 R이 조용히 가장 유연한 타입으로 전부 변환합니다.

R의 인덱싱은 0부터 시작하나요, 1부터 시작하나요?

1부터입니다. x[1]이 첫 원소이고 x[length(x)]가 마지막입니다. Python, JavaScript, C에서 온 사람이라면 모두 여기서 걸려 넘어집니다. x[0]이라는 원소는 없으며, 요청하면 오류가 아니라 빈 벡터가 돌아오기 때문에 버그가 조용해집니다.

R의 재활용 규칙은 무엇을 하나요?

길이가 다른 두 벡터로 산술 연산을 하면 R은 짧은 쪽을 긴 쪽 길이에 맞을 때까지 반복합니다. c(1, 2, 3, 4) + c(10, 20)11 22 13 24를 줍니다. 긴 길이가 짧은 길이의 배수가 아니면 R은 답을 계산하되 경고를 냅니다. 그 경고는 버그로 취급하세요.

R에서 which()는 무슨 일을 하나요?

논리 벡터를 TRUE인 위치들로 바꿔 줍니다. x > 5FALSE TRUE TRUE라면 which(x > 5)2 3을 줍니다. 위치 자체가 필요할 때 쓰세요. 단순한 필터링에는 논리 벡터로 직접 인덱싱하는 것(x[x > 5])이 더 간단합니다.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기