JS에서 컨텐츠 기반 권장 엔진 구축

기계 학습은 이미 나의 레이더에 오랫동안 등장했지만, 나는 지금까지 진정으로 그것을 배우기 시작한 적이 없다.최근까지나는 연속적인 학습자로서 아무것도 없는 상황에서 기계 학습 문제를 해결하기로 결정했다.나는 자신에게 추천 엔진을 만드는 임무를 설정했다.우리는 매일 소셜 미디어, 온라인 쇼핑 및 기타 많은 곳을 통해 이 사람들과 소통한다.네트워크에서 가져온 간단한 데이터 집합을 사용했는데 20폭의 이미지로 구성되었고 결과는 Google Vision API 요청에서 나온 것입니다.하나의 그림을 선택할 때 이 집합의 다른 그림을 추천하는 것이 목표입니다.
나는 Python이 이 임무를 완성하는 더 좋은 언어 선택일 수 있다는 것을 깨달았지만, 나는 자바스크립트에 대해 매우 익숙해서 내가 완전히 익숙하지 않은 언어로 엔진을 조립하는 추가 부담을 지고 싶지 않다.
위키백과에 따르면 내용 기반 추천 엔진은 다음과 같다.

“Recommender systems or recommendation systems (sometimes replacing “system” with a synonym such as a platform or engine) are a subclass of information filtering system that seeks to predict the ‘rating’ or ‘preference’ that user would give to an item.”


추천 엔진은 주동적인 필터 시스템으로 사용자가 알고 있는 정보에 따라 사용자에게 제공하는 정보를 개성화시킨다.이 정보는 Google Vision에서 처음 선택한 이미지와 반환된 데이터입니다.
가장 좋은 것은 본고가 끝날 때, 우리는 사용자의 초기 이미지 선택에 따라 사용자에게 더 많은 이미지를 추천할 수 있을 것이다.

이해득실


우리가 토론하기 전에우리 원인을 이야기합시다.이런 종류의 엔진이 이렇게 환영받는 데는 이유가 있지만, 그것을 사용하지 않을 이유도 있다.

찬성 의견

  • 다른 방법과 달리 내용 기반 필터는 다른 사용자의 데이터가 필요하지 않습니다. 사용자를 위한 것이기 때문입니다.이로 인해 데이터가 제한된 경우 콜드 부팅 문제가 발생하지 않음
  • 이 모델은 사용자의 특정한 흥미를 포착하여 다른 사용자에게 인기가 없을 수 있는 리키 프로젝트를 추천할 수 있다
  • 속이다

  • 이 모델은 기존의 흥미를 바탕으로 건의만 할 수 있다.이것은 이미 알고 있는 취미에 대한 추천을 제한하고 사용자의 흥미 확대를 막았다
  • 레이블의 정확성에 의존
  • 사용자의 괴벽을 고려하지 않았다.그들은 어떤 것을 좋아하지만, 매우 특정한 상황에서만 좋아한다.
  • 내용 기반 추천 엔진이 어떻게 작동하는지


    내용 기반 추천 엔진은 사용자가 제공한 데이터를 처리합니다. (이 예에서 그림을 선택하십시오.)이러한 데이터를 바탕으로 우리는 사용자에게 건의를 제기할 수 있다.
    우리의 예에서 우리의 스크립트는 다음과 같은 절차를 통해 진행될 것이다.
  • 교육
  • 데이터를 사용 가능한 상태로 포맷
  • TF-IDF를 계산하고 포맷된 문서에서 벡터 생성
  • 유사한 파일 계산
  • 훈련된 데이터를 사용하여 사용자의 이미지 선택에 따라 추천합니다.
  • 추천 엔진을 작성하기 전에 우리는 몇 가지 관건적인 개념을 토론해야 한다.즉, 우리는 어떤 데이터를 추천할지 어떻게 결정할 것인가?
    용어 빈도(TF) 및 역문서 빈도(IDF) 개념은 용어의 상대적 중요성을 결정하는 데 사용됩니다.이렇게 하면 우리는 여현의 유사성 개념을 이용하여 무엇을 추천할지 확정할 수 있다.우리는 전체 문장에서 이 문제들을 토론할 것이다.
    TF는 문서에 단어가 나타나는 빈도일 뿐입니다.IDF는 전체 문서 라이브러리에서 용어의 빈도수입니다.그것은 한 단어의 희귀성을 의미하며, 희귀어의 점수를 높이는 데 도움이 된다.TD-IDF를 사용하는 이유는 고립된 항목뿐만 아니라 전체 문서 자료 라이브러리의 용어도 고려하기 때문이다.이 모델은 문서에서 단어의 중요성(국부적 중요성)과 전체 자료 라이브러리에서의 단어의 중요성(전체적 중요성)을 결합시켰다
    여현 유사성은 문서의 유사성을 확정하는 데 쓰이는 도량으로 크기와 무관하다.수학적으로 말하자면, 그것은 두 벡터 사이의 여현각을 측정하는 것이다.컨텍스트에서 벡터는 키 및 TF-IDF를 값으로 포함하는 객체입니다.이 값은 벡터의 폭값이라고도 부른다.

    1. 교육



    훈련 엔진의 첫 번째 단계는 데이터를 사용할 수 있고 관리하기 쉬운 구조로 포맷하는 것이다.Google Cloud Vision에서 반환된 레이블 데이터는 다음과 같습니다.
    {
      "1.jpg": [
        {
          "locations": [],
          "properties": [],
          "mid": "/m/0c9ph5",
          "locale": "",
          "description": "Flower",
          "score": 0.9955990314483643,
          "confidence": 0,
          "topicality": 0.9955990314483643,
          "boundingPoly": null
        },
        {
          "locations": [],
          "properties": [],
          "mid": "/m/04sjm",
          "locale": "",
          "description": "Flowering plant",
          "score": 0.9854584336280823,
          "confidence": 0,
          "topicality": 0.9854584336280823,
          "boundingPoly": null
        },
        [...]
      ]
    }
    

    1.a 형식


    이 연습에서 우리는 대상의 최고급 키(1.jpg와 그룹의 각 대상description만 주목한다.그러나 우리는 모든 설명이 하나의 문자열에 있기를 바란다.이것은 우리로 하여금 앞으로 그것들을 더욱 쉽게 처리하게 할 것이다.
    우리는 데이터가 다음과 같은 개체 그룹에 있기를 바란다.
    const formattedData = [
      {
        id: '1.jpg',
        content: 'flower flowering plant plant petal geraniaceae melastome family geranium wildflower geraniales perennial plant' 
      }
    ]
    
    데이터를 포맷하기 위해서 우리는 다음 함수를 통해 그것을 실행할 것이다.이것은 우리가 엔진을 계속 훈련하는 데 필요한 모든 데이터 그룹을 되돌려 줄 것이다.우리는 교체를 더욱 쉽게 하기 위해 Object.entries 를 사용한다.DN 선언:

    The Object.entries() method returns an array of a given object's own enumerable string-keyed property [key, value] pairs...


    그리고 우리는 btObject.entries가 만든 그룹을 순환하여 필요한 속성을 추출하고 desc 그룹에 추가합니다.마지막으로, 우리는 desc 그룹의 내용을 연결하고 content 속성에 기록합니다.이 formatted 수조는 우리의 어료 라이브러리다.
    const formatData = data => {
      let formatted = [];
    
      for (const [key, labels] of Object.entries(data)) {
        let tmpObj = {};
        const desc = labels.map(l => {
          return l.description.toLowerCase();
        });
    
        tmpObj = {
          id: key,
          content: desc.join(" ")
        };
    
        formatted.push(tmpObj);
      }
    
      return formatted;
    };
    

    1.b TF-IDF 및 벡터


    위에서 설명한 바와 같이 TF는 단지 하나의 용어가 문서에 나타난 횟수일 뿐이다.
    예:
    // In the data set below the TF of plant is 3
    { 
      id: '1.jpg',
      content: 'flower flowering plant plant petal geraniaceae melastome family geranium wildflower geraniales perennial plant' 
    }
    
    IDF의 계산은 좀 복잡합니다.공식:

    javascript에서는 다음과 같은 방식으로 이루어집니다.
    var idf = Math.log((this.documents.length) / docsWithTerm );
    
    위의 값(TF 및 IDF)만 있으면 TF-IDF를 계산할 수 있습니다.그것은 단지 TF 곱하기 IDF일 뿐이다.
    const tdidf = tf * idf;
    
    다음 단계에서는 문서의 TF-IDF를 계산하고 키의 항목과 TF-IDF의 값(벡터)을 포함하는 벡터를 만듭니다.우리는 naturalvector-objectnpm 패키지에 의존하여 이 점을 쉽게 실현할 수 있다.tfidf.addDocument는 우리의 재산을 표시할 것이다.content 메서드는 TD, IDF 및 TD-IDF를 포함하는 객체 배열을 반환하는 새로운 처리 문서를 나열합니다.하지만 우리는 TF-IDF에만 관심을 갖는다.
    /**
    * Generates the TF-IDF of each term in the document
    * Create a Vector with the term as the key and the TF-IDF as the value
    * @example - example vector
    * {
    *   flowers: 1.2345
    * }
    */
    const createVectorsFromDocs = processedDocs => {
      const tfidf = new TfIdf();
    
      processedDocs.forEach(processedDocument => {
        tfidf.addDocument(processedDocument.content);
      });
    
      const documentVectors = [];
    
      for (let i = 0; i < processedDocs.length; i += 1) {
        const processedDocument = processedDocs[i];
        const obj = {};
    
        const items = tfidf.listTerms(i);
    
        for (let j = 0; j < items.length; j += 1) {
          const item = items[j];
          obj[item.term] = item.tfidf;
        }
    
        const documentVector = {
          id: processedDocument.id,
          vector: new Vector(obj)
        };
    
        documentVectors.push(documentVector);
      }
    
    현재 이미지의 id tfidf.listTerms 를 id와 벡터로 포함하는 대상 그룹이 있습니다.우리의 다음 단계는 문서 간의 유사성을 계산하는 것이다.

    1.c 여현 유사도와 점적 계산 유사도 사용


    교육 단계의 마지막 단계는 파일 간의 유사성을 계산하는 것이다.우리는 다시 1.jpg 가방을 사용하여 여현의 유사성을 계산한다.계산이 끝난 후, 우리는 그것을 하나의 그룹에 넣습니다. 이 그룹은 이미지 id와 훈련에서 추천한 모든 이미지를 포함합니다.마지막으로, 우리는 그것들을 정렬하여, 가장 높은 여현의 유사성을 가진 항목이 수조에서 첫 번째로 위치하도록 한다.
    /**
    * Calculates the similarities between 2 vectors
    * getCosineSimilarity creates the dotproduct and the 
    * length of the 2 vectors to calculate the cosine 
    * similarity
    */
    const calcSimilarities = docVectors => {
      // number of results that you want to return.
      const MAX_SIMILAR = 20; 
      // min cosine similarity score that should be returned.
      const MIN_SCORE = 0.2;
      const data = {};
    
      for (let i = 0; i < docVectors.length; i += 1) {
        const documentVector = docVectors[i];
        const { id } = documentVector;
    
        data[id] = [];
      }
    
      for (let i = 0; i < docVectors.length; i += 1) {
        for (let j = 0; j < i; j += 1) {
          const idi = docVectors[i].id;
          const vi = docVectors[i].vector;
          const idj = docVectors[j].id;
          const vj = docVectors[j].vector;
          const similarity = vi.getCosineSimilarity(vj);
    
          if (similarity > MIN_SCORE) {
            data[idi].push({ id: idj, score: similarity });
            data[idj].push({ id: idi, score: similarity });
          }
        }
      }
    
      // finally sort the similar documents by descending order
      Object.keys(data).forEach(id => {
        data[id].sort((a, b) => b.score - a.score);
    
        if (data[id].length > MAX_SIMILAR) {
          data[id] = data[id].slice(0, MAX_SIMILAR);
        }
      });
    
      return data;
    
    무대 뒤에서 vector-object 방법은 많은 일을 할 수 있다.
    이것은 두 개의 벡터를 취하고 단일 (표량) 수를 되돌려주는 점적을 생성합니다.그것은 두 벡터 중 각 분량을 더하는 간단한 곱셈입니다.
    a = [1.7836, 3]
    b = [4, 0.5945]
    
    a.b = 1.7836 * 4 + 3 *0.5945 = 8.9176
    
    점적을 계산한 후, 우리는 모든 문서의 벡터 값을 표량 값으로 줄일 수 있을 뿐이다.이것은 모든 값의 제곱근을 자신에게 곱하여 실현한 것이다.다음 getCosineSimilarity 방법은 이 계산을 진행하고 있습니다.
    const getLength = () => {
      let l = 0;
    
      this.getComponents().forEach(k => {
        l += this.vector[k] * this.vector[k];
      });
    
      return Math.sqrt(l);
    }
    
    실제 여현 유사성 공식은 다음과 같습니다.

    javascript에서는 다음과 같습니다.
    const getCosineSimilarity = (vector) => {
      return this.getDotProduct(vector) / (this.getLength() * vector.getLength());
    }
    
    교육 완료!!

    2. 우리의 건의를 얻는다


    현재 우리는 이미 훈련 단계를 마쳤기 때문에 우리는 간단하게 훈련 데이터에서 추천하는 이미지를 요청할 수 있다.
    const getSimilarDocuments = (id, trainedData) => {
      let similarDocuments = trainedData[id];
    
      if (similarDocuments === undefined) {
        return [];
      }
    
      return similarDocuments;
    };
    
    이것은 추천 이미지와 여현의 유사성 점수를 포함하는 대상 그룹을 되돌려줍니다.
    // e.g
    [ { id: '14.jpg', score: 0.341705472305971 },
      { id: '9.jpg', score: 0.3092133517794513 },
      { id: '1.jpg', score: 0.3075994367748345 } ]
    

    총결산


    나는 네가 따라갈 수 있기를 바란다.나는 이 연습에서 많은 것을 배웠는데, 그것은 확실히 내가 기계 학습에 대한 흥미를 불러일으켰다.

    좋은 웹페이지 즐겨찾기