특성 벡터
고친 사람 github-actions[bot]
특성 벡터는 대상 하나를 숫자 몇 개의 줄로 옮겨 적어 머신러닝 모델이 다룰 수 있게 해 줍니다. 칸마다 무엇을 적을지 미리 정해 두기 때문에 모든 대상이 같은 길이의 줄이 됩니다. 이 줄은 공간 위의 점 하나로 볼 수 있습니다. 그래서 두 대상이 얼마나 닮았는지를 점 사이의 거리로 잴 수 있습니다.
쉽고 빠른 이해
무슨 일을 하는 물건인가 — 고객이나 글 같은 대상 하나를 숫자 몇 개로 옮겨 적은 줄입니다. 한 달에 4번 방문해 10만 원을 쓴 고객은 (4, 10) 이 됩니다.
왜 이렇게 하나 — 모델은 고객을 직접 보지 못하고 숫자만 계산합니다. 모든 대상을 같은 칸에 같은 순서로 적어 두어야 둘을 칸끼리 맞대어 견줄 수 있습니다.
어떻게 도나
- 칸마다 무엇을 적을지 정합니다. 앞 칸은 방문 횟수, 뒤 칸은 구매액입니다
- 대상마다 그 순서대로 값을 채웁니다
- 줄을 점으로 보고 점 사이가 가까우면 닮았다고 봅니다
대가
- 칸에 안 적은 정보는 모델이 끝내 모릅니다. 낱말 순서처럼 칸에 담기 어려운 정보도 있습니다
- 칸마다 값이 오가는 범위가 다르면 미리 맞춰야 합니다. 안 맞추면 범위가 큰 칸이 거리를 혼자 정합니다
- 답과 상관없는 칸이 많아지면 거리가 닮음을 잘 못 가려냅니다
상세
건강검진 결과표를 떠올려 봅시다. 누구의 결과표든 키, 몸무게, 혈압이 같은 순서로 적혀 있습니다. 그래서 두 사람의 결과표를 나란히 놓고 칸끼리 맞대 보면 얼마나 비슷한지 금방 보입니다.
머신러닝 모델도 대상을 숫자 몇 개로 옮겨 적고 나서야 다룹니다. 고객이라면 한 달 방문 횟수와 한 달 구매액을 적을 수 있습니다. 이렇게 대상을 묘사하는 값 하나하나를 특성이라고 부릅니다.
특성 벡터는 특성들을 정해 둔 순서로 늘어놓은 줄입니다. 방문 4번에 구매액 10만 원인 고객은 (4, 10) 입니다. 앞 칸에는 늘 방문 횟수를, 뒤 칸에는 늘 구매액을 적습니다.
벡터는 수학에서 숫자를 순서대로 늘어놓은 묶음입니다. 벡터끼리는 더하거나 곱하는 계산이 정해져 있습니다. 특성을 벡터로 적어 두면 이 계산을 빌려 대상끼리 견줄 수 있습니다.
같은 것을 분야에 따라 특징 벡터라고도 합니다. 영어로는 feature vector 라서 실무에서는 「피처 벡터」라고도 합니다. 이 편은 특성 벡터로 통일합니다.
이 절은 먼저 고객 예로 칸을 정하는 법과 벡터를 점으로 보는 법을 봅니다. 그다음 닮음을 재는 두 방법과 칸이 많을 때 생기는 일을 봅니다. 끝에는 벡터라는 이름이 겹치는 다른 개념을 가릅니다.
칸의 순서와 길이
이 소절은 칸 순서와 칸 개수를 왜 고정해 두는지 봅니다. 예는 방문 4번에 10만 원을 쓴 고객 (4, 10) 입니다.
모델은 값을 이름으로 알아보지 않습니다. 몇 번째 칸에 있는지로 알아봅니다. 두 칸을 바꿔 (10, 4) 로 넣으면 모델은 방문 10번에 4만 원인 고객으로 읽습니다. 오류는 나지 않습니다. 틀린 답이 조용히 나올 뿐입니다.
모델은 먼저 과거 고객 데이터를 보고 규칙을 세웁니다. 이 단계를 훈련이라고 합니다. 훈련에 쓴 벡터가 모두 「앞 칸은 방문 횟수」였다면 규칙도 그 순서에 맞춰 세워집니다.
훈련을 마친 모델은 새 고객을 받아 답을 냅니다. 이 단계는 예측입니다. 예측 때 넣는 벡터도 훈련 때와 같은 순서여야 합니다. 순서가 바뀌면 앞에서 본 것처럼 틀린 답이 조용히 나옵니다.
백엔드 개발자에게 익숙한 말로 하면 칸 정의는 스키마입니다. 테이블의 컬럼 순서를 정해 두고 모든 행을 거기에 맞추는 것과 닮았습니다. 다른 점은 컬럼 이름이 벡터에 실려 다니지 않는다는 것입니다. 이름은 코드나 설정에만 남습니다. 벡터에는 숫자만 남습니다.
길이도 모두 같아야 합니다. 어떤 고객은 칸이 둘이고 어떤 고객은 셋이면 칸끼리 맞댈 수가 없습니다. 값을 모르는 칸이 있어도 칸을 빼지 않고 무언가로 채웁니다.
이렇게 비어 있는 값을 결측값이라고 합니다. 흔히 그 칸의 평균 같은 값으로 메웁니다.
칸의 개수는 차원입니다. 특성 두 개로 적은 벡터는 2차원 벡터입니다. 특성이 백 개면 100차원 벡터입니다.
공간 위의 점
벡터를 점으로 보면 「닮았다」를 거리로 바꿀 수 있습니다. 고객 세 명을 평면에 찍어 보겠습니다.
| 고객 | 방문 횟수 | 구매액(만 원) | 특성 벡터 |
|---|---|---|---|
| 가 | 4 | 10 | (4, 10) |
| 나 | 7 | 6 | (7, 6) |
| 다 | 5 | 11 | (5, 11) |
특성이 둘이면 가로축을 방문 횟수로, 세로축을 구매액으로 둔 평면을 그릴 수 있습니다. 고객 가는 가로 4, 세로 10 에 찍힌 점입니다. 고객 셋이 점 셋이 됩니다.
점 사이가 가까우면 두 고객이 닮았다는 뜻입니다. 표에서 가와 다는 두 칸 모두 1 씩만 다릅니다. 가와 나는 두 칸 모두 차이가 큽니다.
이 생각으로 닮은 대상을 묶는 방법이 군집화입니다. 가까운 점끼리 한 무리로 묶어 닮은 고객 집단을 찾습니다. 답을 미리 알려 주지 않아도 묶을 수 있다는 것이 쓸모입니다.
최근접 이웃도 같은 생각에서 나왔습니다. 새 고객이 오면 가장 가까운 과거 고객을 찾습니다. 그 고객의 답을 새 고객의 답으로 빌려 옵니다.
특성이 셋이면 점은 입체 공간에 놓입니다. 넷부터는 그림으로 그릴 수 없습니다. 그래도 점과 거리라는 생각은 칸이 몇 개든 똑같이 씁니다.
거리로 재는 닮음
두 벡터를 받아 얼마나 떨어져 있는지를 숫자 하나로 돌려주는 계산을 거리 함수라고 합니다. 어떤 거리 함수를 고르느냐에 따라 「닮았다」의 뜻이 달라집니다.
가장 흔한 것은 유클리드 거리입니다. 평면에 자를 대고 두 점 사이를 잰 직선 거리입니다. 칸마다 차이를 제곱해 모두 더한 뒤 제곱근을 씌워 구합니다.
가와 나는 방문 횟수에서 3, 구매액에서 4가 차이 납니다. 제곱해 더하면 9 + 16 = 25 입니다. 제곱근을 씌우면 5 입니다.
가와 다는 두 칸 모두 1 씩 차이 납니다. 제곱해 더하면 2 입니다. 거리는 약 1.41 입니다. 숫자로도 가와 다가 더 닮았습니다.
칸이 셋 이상이어도 계산은 같습니다. 칸마다 차이를 제곱한 값이 칸 수만큼 늘어날 뿐입니다. 그것을 모두 더해 제곱근을 씌웁니다.
칸마다 단위가 다를 때
구매액을 만 원이 아니라 원 단위로 적었다고 해 봅시다. 가는 (4, 100000), 나는 (7, 60000) 이 됩니다. 구매액 차이 40000 앞에서 방문 횟수 차이 3 은 거리에 거의 안 드러납니다.
칸의 단위가 거리 계산을 휘두르는 셈입니다. 그래서 거리를 재기 전에 칸마다 값이 오가는 범위를 비슷하게 맞춥니다. 이 손질을 특성 스케일링이라고 합니다.
대표적인 방법은 표준화입니다. 칸마다 값에서 평균을 뺍니다. 그 값을 값들이 평균에서 흩어진 정도로 나눕니다. 그러면 모든 칸이 「평균에서 얼마나 벗어났나」라는 같은 눈금을 갖게 됩니다.
모든 모델이 이 손질을 원하지는 않습니다. 「방문 횟수가 5보다 큰가」처럼 크고 작음만 묻는 결정 트리는 범위를 맞춰도 결과가 같습니다. 문제가 되는 것은 거리로 닮음을 재는 방법들입니다.
방향으로 재는 닮음
거리만으로는 닮음을 잘못 잴 때가 있습니다. 글을 벡터로 적을 때가 대표적입니다. 이 소절은 짧은 글 세 편으로 거리와 방향을 견줘 봅니다.
글을 벡터로 적는 흔한 방법은 낱말마다 칸을 하나 두고 그 낱말이 나온 횟수를 적는 것입니다. 칸이 「캐시」와 「서버」 둘뿐이라고 해 봅시다. 「캐시」가 2번, 「서버」가 1번 나온 글 A 는 (2, 1) 입니다.
글 B 는 글 A 와 같은 이야기를 세 배 길이로 썼습니다. 그래서 (6, 3) 입니다. 글 C 는 서버 이야기가 중심인 짧은 글이라 (1, 3) 입니다.
유클리드 거리로 재면 A 는 B 보다 C 에 가깝습니다. 길이 차이가 거리를 키웠기 때문입니다. 그런데 주제로 보면 A 와 B 가 같은 글입니다.
이럴 때는 점 사이의 거리 대신 방향을 견줍니다. 모든 칸이 0 인 점을 원점이라고 합니다. 원점에서 A 와 B 를 향해 선을 그으면 길이만 다르고 같은 방향을 가리킵니다.
방향을 견주려면 먼저 내적이 필요합니다. 내적은 두 벡터의 같은 칸끼리 곱해 모두 더한 값입니다. A 와 B 의 내적은 2×6 + 1×3 = 15 입니다.
벡터의 길이는 원점에서 그 점까지의 유클리드 거리입니다. A 의 길이는 약 2.24 입니다. B 의 길이는 약 6.71 입니다.
코사인 유사도는 내적을 두 벡터 길이의 곱으로 나눈 값입니다. 길이로 나누었으니 글이 길고 짧음은 빠지고 방향만 남습니다. A 와 B 는 15 ÷ (2.24 × 6.71) 이라서 1 이 됩니다.
값은 -1 에서 1 사이입니다. 1 이면 같은 방향입니다. 0 이면 서로 직각입니다. -1 이면 정반대 방향입니다. 낱말 횟수처럼 음수가 없는 칸만 있으면 0 에서 1 사이에 놓입니다.
아래 코드는 세 글의 거리와 코사인 유사도를 계산합니다. 오른쪽 주석은 그 줄이 내는 값을 소수 둘째 자리까지 반올림한 것입니다.
import math
def cos(u, v):
dot = sum(x * y for x, y in zip(u, v))
return dot / (math.hypot(*u) * math.hypot(*v))
a, b, c = [2, 1], [6, 3], [1, 3]
math.dist(a, b) # 4.47
math.dist(a, c) # 2.24
cos(a, b) # 1.0
cos(a, c) # 0.71
math.dist 는 유클리드 거리를, math.hypot 은 벡터의 길이를 구합니다. 거리로는 A 가 C 에 더 가깝습니다. 코사인 유사도로는 A 와 B 가 1 로 같은 방향입니다. A 와 C 는 0.71 입니다.
유클리드 거리와 코사인 유사도처럼 두 벡터의 닮음을 숫자 하나로 재는 계산을 이 편에서는 잣대라고 묶어 부릅니다. 같은 세 벡터라도 잣대에 따라 닮은 짝이 바뀝니다. 그래서 잣대는 데이터의 성격을 보고 고릅니다.
| 잣대 | 무엇을 보나 | 어울리는 데이터 |
|---|---|---|
| 유클리드 거리 | 점 사이의 직선 거리 | 값의 크기 자체에 뜻이 있다. 방문 횟수, 구매액 |
| 코사인 유사도 | 원점에서 본 방향 | 크기보다 비율에 뜻이 있다. 글의 낱말 횟수 |
길이가 1 인 벡터를 단위 벡터라고 합니다. 어떤 벡터든 각 칸을 자기 길이로 나누면 단위 벡터가 됩니다. A (2, 1) 을 길이 약 2.24 로 나누면 약 (0.89, 0.45) 입니다.
두 벡터가 모두 단위 벡터면 코사인 유사도는 내적과 같아집니다. 나눌 길이의 곱이 1 이기 때문입니다. 그래서 길이를 미리 1 로 맞춰 두면 내적만으로 방향을 견줄 수 있습니다.
희소 벡터와 밀집 벡터
낱말마다 칸을 두는 방식은 낱말 수만큼 칸이 생깁니다. 다루는 낱말이 수만 개면 칸도 수만 개입니다. 글 한 편에 나오는 낱말은 그중 얼마 안 되니 나머지 칸은 모두 0 입니다.
희소 벡터는 이렇게 대부분의 칸이 0 인 벡터입니다. 칸이 많아도 0 이 아닌 칸은 몇 개 안 됩니다.
원-핫 인코딩도 희소 벡터를 만듭니다. 값의 종류마다 칸을 하나씩 두고 해당하는 칸에만 1 을 적는 방법입니다. 색깔 칸이 빨강, 초록, 파랑 셋이면 초록 옷은 (0, 1, 0) 이 됩니다.
희소 벡터는 0 을 일일이 적지 않습니다. 0 이 아닌 칸의 번호와 값만 짝지어 적습니다. 아래 그림의 칸 번호는 0 부터 셉니다.
block-beta columns 8 t1["모든 칸을 적는 방식 · 여덟 칸"]:8 a0["0번 · 0"] a1["1번 · 0"] a2["2번 · 1"] a3["3번 · 0"] a4["4번 · 0"] a5["5번 · 0"] a6["6번 · 2"] a7["7번 · 0"] t2["0 아닌 칸만 적는 방식 · 두 짝"]:8 s1["2번 칸 · 1"]:4 s2["6번 칸 · 2"]:4
위 그림의 여덟 칸 가운데 0 이 아닌 칸은 2번과 6번 둘입니다. 아래 줄은 이 두 짝만 적습니다. 칸이 수만 개여도 적을 짝은 글에 나온 낱말 수만큼입니다.
코드로 옮기면 배열 대신 칸 번호를 키로 둔 맵을 쓰는 셈입니다. 내적도 0 이 아닌 칸끼리만 곱하면 되니 계산이 빨라집니다.
반대로 거의 모든 칸에 0 아닌 값이 찬 벡터를 밀집 벡터라고 합니다. 고객의 방문 횟수와 구매액처럼 칸이 적고 값이 다 차 있으면 밀집 벡터입니다. 밀집 벡터는 배열 하나에 모든 칸을 순서대로 적습니다.
사람이 고른 칸과 모델이 만든 칸
지금까지의 칸은 사람이 이름을 붙여 골랐습니다. 앞 칸은 방문 횟수, 뒤 칸은 구매액이었습니다. 원본 기록에서 이런 칸을 골라 계산해 내는 일을 특성 공학이라고 부릅니다.
사진이나 문장처럼 사람이 칸을 고르기 어려운 데이터도 있습니다. 이럴 때는 신경망이 데이터를 보고 벡터를 직접 만들어 냅니다. 신경망은 입력을 여러 단계의 계산에 차례로 통과시키며 바꿔 나가는 모델입니다.
신경망이 이렇게 만들어 낸 밀집 벡터를 임베딩이라고 부릅니다. 비슷한 문장은 가까운 점이 되도록 훈련합니다.
임베딩도 특성 벡터의 한 가지입니다. 대상 하나가 같은 길이의 숫자 줄이 됩니다. 닮음도 점 사이의 거리나 방향으로 잽니다. 다른 점은 칸에 이름이 없다는 것입니다. 37번 칸이 무엇을 뜻하는지는 사람이 읽어 낼 수 없습니다.
닮은 벡터 찾기
최근접 이웃은 새 대상과 가장 가까운 과거 사례를 찾는다고 했습니다. 쌓아 둔 사례가 수백만 개로 늘면 이 찾기 자체가 따로 다룰 일이 됩니다. 이 소절은 문장을 임베딩으로 바꿔 둔 경우로 봅니다.
먼저 찾고 싶은 문장도 같은 방식으로 벡터로 바꿉니다. 그다음 쌓아 둔 벡터들 가운데서 이 벡터와 가까운 것을 찾습니다. 이 일을 벡터 검색이라고 합니다.
쌓아 둔 벡터를 하나하나 모두 견주면 사례가 늘수록 느려집니다. 그래서 벡터를 저장하고 가까운 것을 빨리 찾도록 따로 만든 저장소를 씁니다. 이런 저장소가 벡터 데이터베이스입니다.
칸이 너무 많을 때
칸을 늘리면 대상을 더 자세히 적을 수 있을 것 같습니다. 그런데 답과 상관없는 칸이 많아지면 거리가 닮음을 잘 못 가려냅니다. 이 소절은 앞의 고객 가, 나, 다에 상관없는 칸을 덧붙여 봅니다.
가와 다는 방문 횟수와 구매액에서 1 씩만 달랐습니다. 여기에 회원 번호 끝자리나 태어난 날짜처럼 구매와 아무 관계없는 칸을 98개 더 붙인다고 해 봅시다. 이제 고객마다 100차원 벡터가 됩니다.
유클리드 거리는 모든 칸의 차이를 제곱해 더합니다. 가와 다 사이에서 쓸모 있는 두 칸이 보태는 몫은 1 + 1 = 2 입니다. 상관없는 칸 98개도 저마다 차이를 보태므로 그 몫이 훨씬 커집니다.
그러면 거리를 정하는 것이 대부분 상관없는 칸이 됩니다. 가에서 다까지의 거리와 가에서 나까지의 거리가 비슷해집니다. 거리로는 「가장 닮은 고객」을 골라내기 어려워집니다.
칸이 많아지면서 거리가 이렇게 잘 듣지 않게 되는 일을 차원의 저주라고 합니다.
그래서 답에 쓸모 있는 칸만 남기고 나머지를 버리기도 합니다. 이 일은 특성 선택입니다.
버리는 대신 함께 움직이는 칸들을 섞어 더 적은 칸으로 줄이는 방법도 있습니다. 이 방법은 차원 축소라고 합니다.
한 줄로 적기 어려운 대상
특성 벡터는 대상 하나를 정해 둔 칸에 나눠 적습니다. 그래서 칸으로 나누는 순간 핵심이 빠지는 대상에는 쓰기 어렵습니다. 이 소절은 그런 경우 둘을 봅니다.
첫째는 순서가 뜻을 지는 데이터입니다. 낱말 횟수로 글을 적는 방식을 단어 주머니라고 합니다. 영어 문장 dog bites man 과 man bites dog 는 낱말과 횟수가 같고 순서만 다릅니다. 단어 주머니로 적으면 두 문장이 같은 벡터가 됩니다.
둘째는 대상끼리의 연결이 핵심인 데이터입니다. 친구가 몇 명인지는 한 사람의 칸 하나에 적을 수 있습니다. 그 친구들이 서로 어떻게 이어져 있는지는 한 사람의 줄에 담기지 않습니다.
이럴 때는 순서나 연결이 드러나도록 칸을 새로 궁리합니다. 아니면 순서나 연결을 받아들이는 모델을 따로 고릅니다.
벡터라는 이름의 다른 쓰임
벡터라는 낱말은 개발 현장 곳곳에 나옵니다. 대부분은 이 편의 뜻과 이름만 같습니다.
| 쓰임 | 무엇인가 | 특성 벡터와 견주면 |
|---|---|---|
| 수학의 벡터 | 숫자를 순서대로 늘어놓은 묶음. 덧셈과 내적이 정해져 있다 | 특성 벡터가 이 이름과 계산을 빌려 왔다 |
| 프로그래밍 언어의 벡터 | 원소를 붙이면 길이가 늘어나는 배열 | 이름만 같다. 특성 벡터는 길이가 고정이다 |
| 벡터 시계 | 분산 시스템에서 사건의 앞뒤를 따지는 카운터 묶음 | 이름만 같다 |
| 벡터 테이블 | 인터럽트가 오면 뛰어갈 주소를 모은 표 | 이름만 같다 |
백엔드 개발자에게는 둘째 줄이 가장 헷갈립니다. 자바의 Vector 나 C++ 의 std::vector 는 원소를 붙이면 길이가 늘어납니다. 특성 벡터는 칸 정의가 정한 길이에서 한 칸도 늘거나 줄지 않습니다.
관련 항목
특성 벡터를 이루는 칸과 값
특성 · 차원 · 벡터 · 결측값 · 범주형 변수 · 수치형 변수
특성 벡터의 하위 종류
희소 벡터 · 밀집 벡터 · 임베딩 · 단어 주머니 · 원-핫 벡터
특성 벡터 사이의 닮음을 재는 잣대
거리 함수 · 유클리드 거리 · 맨해튼 거리 · 코사인 유사도 · 내적 · 단위 벡터
특성 벡터를 만들고 다듬는 전처리
특성 공학 · 특성 스케일링 · 표준화 · 최소-최대 스케일링 · 원-핫 인코딩 · 특성 선택 · 차원 축소 · 주성분 분석 · 표현 학습
특성 벡터를 받아 답을 내는 학습 방법
머신러닝 · 지도학습 · 비지도학습 · 최근접 이웃 · 군집화 · 분류 · 결정 트리 · 신경망 · 훈련 · 예측
특성 벡터를 쌓아 두고 찾는 검색과 저장소
벡터 검색 · 벡터 데이터베이스 · 최근접 이웃 검색 · 근사 최근접 이웃 · 벡터 공간 모델
특성 벡터를 잘못 만들 때 터지는 문제
차원의 저주 · 과적합 · 데이터 누수 · 훈련-서빙 불일치 · 분포 이동
벡터라는 이름이 겹치는 다른 개념
다른 이름: feature vector · 특징 벡터 · 피처 벡터