Project/codestates-final-project

17일차 / n-Gram구현 및 개선, 리벤슈타인 거리 시간,공간 복잡도 개선

fullfish 2022. 5. 15. 18:56

n-Gram

n-gram에 대해 내가 쓴 글들

https://fullfish.tistory.com/109

 

n-Gram

n-Gram이란 문장의 유사도를 비교하는 방법중 하나로 문장을 쪼개서 비교한다 예를 들어 3-gram으로 '과자중에 제일 맛있는건 새우깡' '제일 맛있는 과자는 무엇일까' 이 두문장을 비교한다면 각 문

fullfish.tistory.com

https://fullfish.tistory.com/110

 

n-Gram 개선 및 고찰

자음 모음단위로 n-Gram 저번에 구현한 n-gram https://fullfish.tistory.com/109 n-Gram n-Gram이란 문장의 유사도를 비교하는 방법중 하나로 문장을 쪼개서 비교한다 예를 들어 3-gram으로 '과자중에 제일 맛있..

fullfish.tistory.com

위와 같은 고민을 거쳐서

최종적으로는 자음,모음단위로 쪼갠후 3-Gram을했다

그리고 여러 데이터를 넣어서 시뮬레이션 해본결과

0.27이상의 유사도만을 검색하기로 했다

 

또한 1-Gram이 1일 경우도 검색을 하게 했는데 1-Gram이 1인경우는 글자는 다 똑같은데

순서만 바뀐경우인 경우이다

'새우깡'과 '깡우새'인 경우

(그런데 현재는 자음 모음단위로 분해했기에 '새우깡'과 '꾸앗애'같은것도 검색이된다)

 

코드

// nGram.js
const chSplit = (ch) => {
  const rCho = [
    "ㄱ",
    "ㄲ",
    "ㄴ",
    "ㄷ",
    "ㄸ",
    "ㄹ",
    "ㅁ",
    "ㅂ",
    "ㅃ",
    "ㅅ",
    "ㅆ",
    "ㅇ",
    "ㅈ",
    "ㅉ",
    "ㅊ",
    "ㅋ",
    "ㅌ",
    "ㅍ",
    "ㅎ",
  ];
  const rJung = [
    "ㅏ",
    "ㅐ",
    "ㅑ",
    "ㅒ",
    "ㅓ",
    "ㅔ",
    "ㅕ",
    "ㅖ",
    "ㅗ",
    "ㅘ",
    "ㅙ",
    "ㅚ",
    "ㅛ",
    "ㅜ",
    "ㅝ",
    "ㅞ",
    "ㅟ",
    "ㅠ",
    "ㅡ",
    "ㅢ",
    "ㅣ",
  ];
  const rJong = [
    "",
    "ㄱ",
    "ㄲ",
    "ㄳ",
    "ㄴ",
    "ㄵ",
    "ㄶ",
    "ㄷ",
    "ㄹ",
    "ㄺ",
    "ㄻ",
    "ㄼ",
    "ㄽ",
    "ㄾ",
    "ㄿ",
    "ㅀ",
    "ㅁ",
    "ㅂ",
    "ㅄ",
    "ㅅ",
    "ㅆ",
    "ㅇ",
    "ㅈ",
    "ㅊ",
    "ㅋ",
    "ㅌ",
    "ㅍ",
    "ㅎ",
  ];
  let resultStr = "";
  for (let i = 0; i < ch.length; i++) {
    //만약 ch가 자음이 아닌 한글 문자일때만 이거 해당
    if (/[가-힣]/.test(ch[i])) {
      const nTmp = ch[i].charCodeAt(0) - 0xac00;
      const jong = nTmp % 28; // 종성
      const jung = ((nTmp - jong) / 28) % 21; // 중성
      const cho = ((nTmp - jong) / 28 - jung) / 21; // 초성

      resultStr += rCho[cho] + rJung[jung];
      if (rJong[jong] !== "") resultStr += rJong[jong];
    } else resultStr += ch[i];
  }
  return resultStr;
};

const ngram = (str, num) => {
  let arr = [];
  const repeat = str.length - num + 1;
  for (let i = 0; i < repeat; i++) {
    const split = str.slice(i, i + num);
    arr.push(split);
  }
  return arr;
};

exports.diff_ngram = (data, search, num) => {
  if (search === undefined) return 0;
  data = chSplit(data);
  search = chSplit(search);
  let splitArrA = ngram(data, num);
  let splitArrB = ngram(search, num);
  const splitArrBLength = splitArrB.length;
  let count = 0;
  for (let i = 0; i < splitArrA.length; i++) {
    for (let j = 0; j < splitArrB.length; j++) {
      if (splitArrA[i] === splitArrB[j]) {
        count++;
        splitArrB.splice(j, 1);
        break;
      }
    }
  }
  return count / (splitArrA.length + splitArrBLength - count);
};

실행 예시

let a = "오늘 강남에서 맛있는 스파게티를 먹었다.";
let b = "강남에서 먹었던 오늘의 스파게티는 맛있었다.";
let a2 = "과자는 새우깡이지";
let b2 = "새우깡은 과자지";
let a3 = "과자중에 제일 맛있는건 새우깡";
let b3 = "제일 맛있는 과자는 무엇일까";
let a4 = "새우깡";
let b4 = "깡우새";
let a5 = "새우깡임";
let b5 = "새우깡은 과자다";
let a6 = "나는 새우깡을 먹고 있는데 너는 어떤 과자를 좋아하니?";
let b6 = "나는 새우깡은 안좋아하고 다른 과자가 좋아";
let a7 = "고구마깡은 맛있나?";
let b7 = "저녁 뭐먹지?";
console.log("___________________1");
console.log(this.diff_ngram(a, b, 1));
console.log(this.diff_ngram(a, b, 2));
console.log(this.diff_ngram(a, b, 3));
console.log("___________________2");
console.log(this.diff_ngram(a2, b2, 1));
console.log(this.diff_ngram(a2, b2, 2));
console.log(this.diff_ngram(a2, b2, 3));
console.log("___________________3");
console.log(this.diff_ngram(a3, b3, 1));
console.log(this.diff_ngram(a3, b3, 2));
console.log(this.diff_ngram(a3, b3, 3));
console.log("___________________4");
console.log(this.diff_ngram(a4, b4, 1));
console.log(this.diff_ngram(a4, b4, 2));
console.log(this.diff_ngram(a4, b4, 3));
console.log("___________________5");
console.log(this.diff_ngram(a5, b5, 1));
console.log(this.diff_ngram(a5, b5, 2));
console.log(this.diff_ngram(a5, b5, 3));
console.log("___________________6");
console.log(this.diff_ngram(a6, b6, 1));
console.log(this.diff_ngram(a6, b6, 2));
console.log(this.diff_ngram(a6, b6, 3));
console.log("___________________7");
console.log(this.diff_ngram(a7, b7, 1));
console.log(this.diff_ngram(a7, b7, 2));
console.log(this.diff_ngram(a7, b7, 3));

___________________1
0.8035714285714286
0.6779661016949152
0.5645161290322581
___________________2
0.8947368421052632
0.6190476190476191
0.391304347826087
___________________3
0.7073170731707317
0.4166666666666667
0.29411764705882354
___________________4
1
0.5
0.1111111111111111
___________________5
0.42105263157894735
0.3888888888888889
0.35294117647058826
___________________6
0.5942028985507246
0.4794520547945205
0.34177215189873417
___________________7
0.2857142857142857
0.030303030303030304
0

 

리벤슈타인 시간 복잡도, 공간 복잡도 개선

https://fullfish.tistory.com/108

 

레벤슈타인 거리 시간복잡도와 공간복잡도 개선

기존 코드 //레벤슈타인 거리 코드 exports.levenshteinDistance = (str, search) => { if (search === undefined) return 0; if (str === search) return 0; let aLen = str.length; let bLen = search.length; i..

fullfish.tistory.com