2021-11-22 21:31 작성
자카드 유사도
정의
자카드 유사도는 집합 간의 유사도를 검사하는 방법 중 하나다. 두 집합 A
, B
사이의 자카드 유사도는 두 집합의 교집합 크기를 두 집합의 합집합 크기로 나눈 값이다. 이 때, A
, B
가 모두 공집합일 경우, 나눗셈이 정의되지 않으므로 1
로 정의한다.
예시
“FRANCE”와 “FRENCH”를 2글자씩 끊어 자카드 유사도를 구한다면,
- FRANCE: {FR, RA, AN, NC, CE}
- FRENCH: {FR, RE, EN, NC, CH}
- 교집합: {FR, NC}
- 합집합: {FR, RA, AN, NC, CE, RE, EN, CH}
- 유사도: 2 / 8 = 0.25
두 집합 간의 합집합은 서로 중복되는 값을 제거하고 계산한다. 예를 들어, {1, 1}과 {1, 2}의 합집합은 {1, 1, 2}다.
생각 1. 어디에 사용 가능할까?
- 정렬 기능에 있어서 비슷한 주제로 사용자에게 데이터를 제공할 필요가 있는 경우
- 고객 간 유사도
예를 들어, A 고객의 상품 결제 내역을 일렬로 나열한다고 하고,
- A: [샤넬가방, 구찌지갑, 구찌드레스, 태그호이어 시계]
B고객의 상품 결제 내역이 다음과 같다고 할 때,
- B: [샤넬가방, 구찌지갑, 구찌드레스, 에르메스 가방, 태그호이어 시계]
A 고객에게 비슷한 선호를 가진 B 고객의 상품을 추천한다면 A 고객도 만족할 확률이 높을 것이다(유사도: 4/5, 80%의 유사도를 가짐). 이와 같이 고객 간 데이터를 바탕으로 한 이런 추천 알고리즘을 짜는 것도 가능할 듯 하다.
function solution(str1, str2) {
var answer = clustering(str1, str2);
return answer;
}
const clustering = (str1, str2) => {
const constant = 65536;
let splited1 = str1.trim().toLowerCase().split("");
let splited2 = str2.trim().toLowerCase().split("");
// 두 개로 쪼갠 문자열 array
let set1 = [];
let set2 = [];
// 교집합
let intersection = [];
// 합집합
let union = [];
// splited1 문자열 두 개로 쪼개기
for (let e = 0; e < splited1.length; e++) {
// 각 element가 영문만 포함할 경우 저장
if (
splited1[e + 1] &&
/[a-z]/.test(splited1[e]) &&
/[a-z]/.test(splited1[e + 1])
)
set1.push(splited1[e] + splited1[e + 1]);
}
// splited2 문자열 두 개로 쪼개기
for (let e = 0; e < splited2.length; e++) {
if (
splited2[e + 1] &&
/[a-z]/.test(splited2[e]) &&
/[a-z]/.test(splited2[e + 1])
)
set2.push(splited2[e] + splited2[e + 1]);
}
// 교집합 변경 전 합집합 저장
union = set1.concat(set2);
// 교집합 구하기
set1.forEach((elem) => {
let i = set2.findIndex((e) => e === elem);
if (i >= 0) {
intersection.push(elem);
set2.splice(i, 1);
}
});
// 합집합 구하기 (집합 A) + (집합 B) - (교집합)
intersection.forEach((elem) => {
let i = union.findIndex((e) => e === elem);
union.splice(i, 1);
});
// 교집합의 분자, 분모가 0인 경우 constant를 반환하고 그 이외에는 모두 계산된 값으로 반환
return intersection.length === 0 && union.length === 0
? constant
: Math.trunc((intersection.length / union.length) * constant);
};