📋 요약 한 줄 요약 내적은 두 벡터의 대응하는 항목을 곱해 모두 더한 숫자 하나를 구하는 연산이다. 수량과 단가로 합계 금액을 구하거나, 관심도와 주제 점수로 추천 점수를 구하는 데 사용할 수 있다.
2026-09-30 수학 공부 대화에서 배운 내용을 정리한 개인 학습 노트. 먼저 내적 자체의 계산과 추천 예시를 이해하고, 정규화와 유사도는 그다음에 연결한다.
1. 내적(Dot Product)이란 무엇인가
내적은 두 벡터(vector)를 입력받아, 같은 자리의 값들을 곱해서 모두 더한 숫자 하나를 만드는 연산이다. 이처럼 숫자 하나로 나타내는 값을 수학에서는 스칼라(scalar)라고 부른다.
입력: 두 벡터
계산: 같은 자리끼리 곱하기 → 전부 더하기
출력: 숫자 하나
그 숫자가 무엇을 뜻하는지는 입력한 벡터의 의미에 따라 달라진다. 구매 수량과 상품 단가를 넣으면 총금액이 되고, 사용자 관심도와 글의 주제 점수를 넣으면 정한 규칙에 따른 추천 점수가 될 수 있다.
왜 같은 자리끼리 곱해서 더하는가
장바구니에 상품 두 종류가 있다고 해보자. 두 벡터의 순서는 모두 [상품 A, 상품 B]이다.
구매 수량 = [2,3]
상품 단가 = [1000,2000]원
상품 A 금액 = 2*1000 = 2000원
상품 B 금액 = 3*2000 = 6000원
총금액 = 2000 + 6000 = 8000원
이 계산이 바로 두 벡터의 내적이다. 같은 자리끼리 곱하면 각 상품의 금액이 나오고, 이를 더하면 전체 금액이 나온다. 서로 대응하는 두 정보를 항목별로 결합한 뒤 하나의 결과로 합산하는 것이다.
추천 점수(Recommendation Score)도 내적으로 계산할 수 있다
개발 글 추천 서비스를 만든다고 가정한다. 숫자 순서는 항상 [Java, AI]이다. 아래 값은 직접 정한 설명용 관심도와 주제 점수이다.
사용자 관심도 = [2,1]
→ Java 주제 점수에 2배, AI 주제 점수에 1배의 비중을 준다.
글 A의 주제 점수 = [3,0]
글 B의 주제 점수 = [1,3]
장바구니에서는 수량 * 단가를 더했다. 추천에서는 각 주제의 관심도 * 주제 점수를 더한다.
글 A 추천 점수 = 2*3 + 1*0
= 6 + 0
= 6
글 B 추천 점수 = 2*1 + 1*3
= 2 + 3
= 5
추천 점수를 수식으로 표현하면 다음과 같다. 첫 줄은 글 A, 둘째 줄은 글 B의 점수이다.
점수가 높은 순서로 정렬하면 글 A → 글 B 순서로 추천한다. Java에 높은 비중을 두었기 때문에 Java 주제 점수가 큰 글 A가 우선한다.
이 예시에서 내적은 여러 항목의 중요도를 반영해 점수 하나를 만드는 도구이다. 이를 가중합(weighted sum), 즉 각 항목에 중요도를 곱해서 더한 값으로 이해할 수 있다.
추천 알고리즘에는 점수 계산 외에도 관심도를 정하는 방법, 글의 주제 점수를 정하는 방법, 이미 읽은 글을 제외하는 규칙 등이 들어간다. 내적은 그중 점수 계산에 사용할 수 있는 방법이다.
같은 자리는 같은 항목을 나타내야 한다. 사용자 벡터는 [Java, AI]인데 글 벡터는 [AI, Java]라면 의도한 추천 점수를 계산할 수 없다.
숫자만으로 계산해보기
두 벡터의 같은 자리끼리 곱한 다음, 그 결과를 모두 더한다. 두 벡터는 숫자의 개수가 같아야 한다.
A = [2,3]
B = [4,5]
첫 번째끼리 곱하기: 2*4 = 8
두 번째끼리 곱하기: 3*5 = 15
내적 = 8 + 15
= 23
숫자가 두 개인 벡터에서는 다음처럼 쓴다.
내적 = A의 첫 번째 값 * B의 첫 번째 값
+ A의 두 번째 값 * B의 두 번째 값
수식으로 표현한 내적 공식
두 벡터가 다음과 같을 때:
숫자가 두 개인 벡터의 내적 공식은 다음과 같다.
위에서 계산한 예시에 적용하면:
💡 TIP 내적의 결과는 숫자 하나
[2,3]과[4,5]를 내적한 결과는23이다. 결과가[8,15]인 것은 아니다. 자리별 곱셈 결과를 마지막에 더한다.
2. 변화량과 거리 계산에서 달라지는 부분
| 계산 | 하는 일 | 결과 |
|---|---|---|
변화량 B-A | 같은 자리끼리 뺀다 | 벡터 |
| 두 점 사이 거리 | 차이를 각각 제곱해 더하고 루트를 구한다 | 길이를 나타내는 숫자 하나 |
내적 A·B | 두 벡터의 같은 자리끼리 곱해서 더한다 | 숫자 하나 |
내적에는 거리 공식처럼 뺄셈이나 루트를 넣지 않는다. 내적 결과가 곧 두 점 사이 거리인 것도 아니다.
3. 내적과 정규화(Normalization)는 각각 무엇인가
내적은 두 벡터에서 숫자 하나를 계산하는 연산이고, 정규화는 벡터의 길이를 맞추는 작업이다.
| 개념 | 계산 방법 | 결과 |
|---|---|---|
| 내적 | 같은 자리끼리 곱해서 모두 더한다 | 숫자 하나 |
| 지금 배우는 정규화 | 벡터의 각 값을 그 벡터 자체의 길이로 나눈다 | 길이가 1인 벡터 |
정규화 예시:
벡터 = [3,4]
길이 = sqrt(3^2 + 4^2) = 5
정규화 = [3/5, 4/5]
= [0.6,0.8]
벡터의 길이는 원점 [0,0]에서 그 벡터의 끝점까지의 거리이다. 정규화할 때는 다른 벡터와의 거리가 아니라 자기 자신의 길이를 사용한다. 길이가 0인 벡터는 이 방식으로 정규화할 수 없다.
다음에 연결할 주제: 방향의 유사도
내적 결과는 벡터의 방향과 길이에 모두 영향을 받는다. 길이의 영향을 없애고 방향의 유사도를 비교하려면, 두 벡터를 각각 길이 1로 정규화한 뒤 내적한다. 그 결과가 코사인 유사도(cosine similarity)이다.
내적 자체는 계산 방법이고, 그 결과를 무엇으로 해석할지는 사용하는 상황에 따라 정한다. 앞의 추천 예시에서는 정한 관심도를 반영한 점수로 사용했다. 정규화와 코사인 유사도는 별도로 복습할 후속 주제이며, 이 노트에서는 계산과 추천 점수에 집중한다.
RAG에서도 임베딩(embedding) 모델과 검색 방식에 맞게 내적이나 코사인 유사도를 활용할 수 있다. 실제 임베딩의 각 자리가 위 추천 예시처럼 Java나 AI라는 특정 주제를 직접 뜻한다고 가정하지 않는다.
4. Kotlin으로 내적 계산하기
다음 Kotlin 함수는 같은 자리끼리 곱한 값을 누적해서 내적을 계산한다.
fun dot(a: DoubleArray, b: DoubleArray): Double {
require(a.size == b.size) {
"두 벡터의 숫자 개수가 같아야 합니다."
}
var result = 0.0
for (i in a.indices) {
result += a[i] * b[i]
}
return result
}
fun main() {
val user = doubleArrayOf(2.0, 1.0)
val articleA = doubleArrayOf(3.0, 0.0)
val articleB = doubleArrayOf(1.0, 3.0)
println(dot(user, articleA)) // 6.0
println(dot(user, articleB)) // 5.0
}
a.indices는 배열의 인덱스 범위이다. result += 값은 기존 결과에 값을 더해 저장한다는 뜻이다.
참고 자료
- Unity 공식 문서 — Vector3.Dot: 내적과 벡터의 길이·방향 관계, 정규화된 벡터의 내적.
- pgvector 공식 문서 — Querying: 내적 및 코사인 거리를 사용한 검색 예시.