Menu

R의 행렬: matrix(), cbind, rbind, 행렬 연산

matrix(), cbind(), rbind()로 행렬을 만들고, 행과 열을 인덱싱하고, 원소 단위 *와 진짜 행렬 곱셈 %*%를 구분하는 방법을 다룹니다.

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

행렬은 차원을 가진 벡터입니다

R의 행렬은 값들의 직사각형, 즉 행과 열이며 모든 칸이 같은 타입(보통 숫자)을 담습니다. 내부적으로는 말 그대로 dim 속성이 붙은 벡터이고, 이 사실이 행렬의 동작 대부분을 설명합니다. 전체가 한 타입이고 어디서나 벡터화 연산이 됩니다.

matrix()로 벡터를 재구성해 만듭니다.

값 여섯 개, 행 두 개이니 R이 열 세 개가 필요하다고 계산합니다. dim()은 두 차원을 한꺼번에 2 3으로 보고하고, nrow()ncol()은 따로 알려 줍니다.

출력된 행렬을 자세히 보세요. 값이 첫 열을 따라 1 2로 내려간 뒤 다음 열로 3 4가 내려갑니다. R은 기본적으로 행렬을 열 방향으로 채웁니다. 데이터가 행 방향으로 읽힌다면(사람은 보통 그렇게 씁니다) byrow = TRUE로 알려 주세요.

이제 첫 행이 1 2 3입니다. byrow = TRUE를 빠뜨려도 오류가 나지 않습니다. 같은 숫자들이 전치된 것처럼 배열된 결과가 조용히 나올 뿐이니, 원시 값으로 행렬을 만들 때는 출력된 배치를 확인하는 습관을 들이세요.

인덱싱: m[행, 열]

행렬 인덱싱은 한 쌍의 대괄호 안에 두 위치를 받으며, 쉼표 앞이 행이고 뒤가 열입니다. 둘 다 1부터 셉니다.

위치를 비워 두면 "전부"라는 뜻입니다. m[1, ]은 첫 행 전체이고 m[, 2]는 두 번째 열 전체입니다. 둘 다 평범한 벡터로 돌아온다는 점에 주목하세요. R이 크기 1로 줄어든 차원을 떨어뜨리기(drop) 때문입니다. 대화형에서는 편리하지만 코드에서는 함정입니다. 행렬을 기대하는 함수가 벡터에 걸려 넘어지기 때문이죠. drop = FALSE로 모양을 유지하도록 R에 요청하세요.

이제 dim()1 3을 보고합니다. 여전히 행렬입니다. 함수 안에서 단일 행이나 열을 잘라 낼 때는 언제나 drop = FALSE를 쓰세요. 이것이 막아 주는 버그(넓은 데이터에서는 동작하다가 열이 하나인 데이터에서 깨지는 코드)는 추적하기 아주 괴로운 종류입니다.

논리 마스크도 여기서 동작합니다. m[m > 3]은 3을 넘는 모든 칸을 벡터로 돌려줍니다.

cbind()와 rbind()로 만들기

긴 벡터 하나를 재구성하는 대신 조각들로 행렬을 조립할 수도 있습니다. cbind()는 벡터들을 열로, rbind()는 행으로 묶습니다. 같은 함수로 기존 행렬을 확장할 수도 있습니다.

이름은 벡터와 함께 따라옵니다. cbind()heightsweights를 자동으로 열 이름으로 사용해 출력된 행렬을 읽기 쉽게 유지합니다. 두 함수 모두 길이가 맞아야 한다고 요구합니다(길이 1인 값은 재활용됩니다). 길이 3인 벡터를 4행 행렬에 묶으면 경고가 납니다.

열 이름과 행 이름은 colnames(m) <- ...rownames(m) <- ...으로 직접 설정할 수도 있고, 그 후에는 이름으로 인덱싱할 수 있습니다. 예: people[, "weights"].

원소 단위 와 진짜 행렬 곱셈 %%

이 글 전체에서 가장 중요한 구분입니다. R에는 행렬을 위한 곱셈 연산자가 있고, 완전히 다른 것을 계산합니다.

  • a * a원소 단위입니다. 각 칸이 대응하는 칸과 곱해집니다. 1 2 3 4가 같은 모양으로 배열된 1 4 9 16이 됩니다. 벡터에 쓰는 것과 똑같은 *, 즉 그냥 벡터화 산술입니다.
  • a %*% a는 선형대수의 행렬 곱셈입니다. 결과의 각 칸은 첫 행렬의 한 행과 두 번째 행렬의 한 열을 곱해 합한 값입니다. 같은 입력이 7 10 15 22를 줍니다. 완전히 다른 숫자입니다.

코드를 실행해 두 출력을 나란히 비교해 보세요. 동일한 입력에서 다르게 나오는 것을 직접 보는 것이 이 구분을 각인시켜 줍니다. 수학적으로 %*%가 필요한 곳에 *를 쓰면 R은 경고하지 않습니다. 정사각 행렬이라면 어느 쪽이든 모양이 맞기 때문에, 그냥 잘못된 숫자를 얻게 됩니다. 통계 코드(공분산 행렬, 선형 모델 대수)에서 이것은 고전적인 조용한 버그 중 하나입니다.

t()는 전치, 즉 행과 열을 뒤바꿉니다. 행렬 곱셈은 안쪽 차원이 맞아야 하므로 %*% 옆에 끊임없이 등장합니다.

덧붙이자면 solve(m)은 행렬의 역행렬을 구하고, 벡터와 함께 쓰는 %*%는 그 벡터를 1열 행렬로 취급합니다. 대부분의 데이터 작업에는 이 정도 깊이면 충분합니다.

행과 열 요약

행과 열을 가로질러 합하거나 평균 내는 일은 너무 흔해서 R이 전용의 빠른 함수를 함께 제공합니다.

rowSums()는 각 행을 숫자 하나로 접고(여기서는 6 15), colSums()는 각 열을 접으며(5 7 9), Means 계열은 합 대신 평균을 냅니다. 손수 만든 반복문이나 심지어 apply(m, 1, sum)보다 이 함수들을 택하세요. 더 명확하고 더 빠릅니다. 이 넷이 다루지 못하는 요약(예: 열별 최댓값)이라면 apply 계열이 일반 도구입니다. apply(m, 2, max)처럼 쓰면 됩니다.

행렬인가 데이터 프레임인가?

둘 다 직사각형인데, 어느 쪽을 택해야 할까요?

  • 행렬: 모든 칸이 같은 타입이고 계산이 중요할 때입니다. 수치 계산, 선형대수, 거리 계산, 이미지 같은 격자에 씁니다. 한 타입이라는 보장 덕분에 행렬이 더 가볍고 연산도 더 빠릅니다.
  • 데이터 프레임: 열마다 타입이 다를 때입니다. 이름 옆에 나이, 그 옆에 논리 플래그 같은 식이죠. 현실의 표 형태 데이터이며, 거의 모든 데이터 분석 함수가 기대하는 것입니다.

좋은 기준이 있습니다. 이름이 붙고 타입이 섞인 열들과 함께 스프레드시트로 열어 볼 만한 것이라면 데이터 프레임입니다. 대수 연산을 하려는 숫자 격자라면 행렬입니다. 서로 변환하기는 쉽지만(as.matrix(), as.data.frame()), 텍스트 열이 하나라도 있는 데이터 프레임에 as.matrix()를 쓰면 모든 것이 문자로 강제 변환되므로 수치 열만 변환하세요.

핵심 정리

  • 행렬은 차원을 가진 벡터입니다. 전체가 한 타입이고 matrix(data, nrow, ncol)로 만들며, byrow = TRUE를 넘기지 않으면 열 방향으로 채웁니다.
  • m[행, 열]로 인덱싱하고, 빈 위치는 "전부"를 뜻하며, 코드 안에서 단일 행이나 열을 자를 때는 drop = FALSE를 추가하세요.
  • cbind()rbind()는 벡터로 행렬을 조립하거나 기존 행렬을 확장합니다.
  • *는 원소 단위이고 %*%는 진짜 행렬 곱셈입니다. 같은 입력에 다른 답이 나오며 경고는 없습니다.
  • rowSums() / colSums() / rowMeans() / colMeans()가 일상적인 요약을 처리합니다.

다음 순서는 팩터입니다. R이 범주형 데이터를 표현하는 방식과 그에 따르는 함정을 다룹니다.

자주 묻는 질문

R에서 행렬은 어떻게 만드나요?

matrix(1:6, nrow = 2)는 벡터를 2행 3열로 재구성하며 열 방향으로 채웁니다. 행 방향으로 채우려면 byrow = TRUE를 추가하세요. 벡터들로부터 조립할 수도 있습니다. cbind()는 열로, rbind()는 행으로 붙입니다.

R에서 *와 %*%의 차이는 무엇인가요?

*는 원소 단위로 곱합니다. 각 칸이 대응하는 칸과 곱해지며 모양이 맞아야 합니다. %*%는 선형대수의 진짜 행렬 곱셈으로(행과 열의 곱이므로 안쪽 차원이 일치해야 합니다), 같은 행렬에 대해 완전히 다른 결과를 줍니다. %*%를 의도한 곳에 *를 쓰는 것은 고전적인 조용한 버그입니다.

R에서 행렬의 한 행이나 한 열을 어떻게 가져오나요?

다른 위치를 비워 두세요. m[1, ]은 첫 행이고 m[, 2]는 두 번째 열입니다. 기본적으로 둘 다 평범한 벡터로 돌아옵니다. m[1, , drop = FALSE]처럼 drop = FALSE를 추가하면 결과가 1행 또는 1열 행렬로 유지되며, 이후 코드가 2차원을 기대할 때 중요합니다.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기