좋아요 예측: 간단한 추천 엔진의 알고리즘 내부
게시 됨: 2022-03-11추천 엔진(때로는 추천 시스템이라고도 함)은 알고리즘 개발자가 주어진 항목 목록 중에서 사용자가 무엇을 좋아하거나 좋아하지 않을지 예측할 수 있도록 하는 도구입니다. 추천 엔진은 사용자가 다른 방법으로는 볼 수 없는 제품이나 콘텐츠를 발견하는 데 도움을 주기 때문에 검색 필드에 대한 매우 흥미로운 대안입니다. 따라서 추천 엔진은 Facebook, YouTube, Amazon 등과 같은 웹 사이트 및 서비스의 큰 부분을 차지합니다.
추천 엔진은 두 가지 방법 중 하나로 이상적으로 작동합니다. 사용자가 좋아하는 항목의 속성에 의존할 수 있으며, 이를 분석하여 사용자가 좋아할 수 있는 다른 항목을 결정할 수 있습니다. 또는 추천 엔진이 사용자 간의 유사도 지수를 계산하고 그에 따라 항목을 추천하는 데 사용하는 다른 사용자의 좋아요 및 싫어요에 의존할 수 있습니다. 이 두 가지 방법을 결합하여 훨씬 더 강력한 추천 엔진을 구축하는 것도 가능합니다. 그러나 다른 모든 정보 관련 문제와 마찬가지로 해결하려는 문제에 적합한 알고리즘을 선택하는 것이 중요합니다.
이 튜토리얼에서는 협업 및 메모리 기반 추천 엔진을 구축하는 과정을 안내합니다. 이 추천 엔진은 사용자가 좋아하는 것과 싫어하는 것을 기반으로 영화를 추천하고 앞서 언급한 두 번째 예와 같이 작동합니다. 이 프로젝트에서는 기본 집합 연산, 약간의 수학 및 Node.js/CoffeeScript를 사용할 것입니다. 이 튜토리얼과 관련된 모든 소스 코드는 여기에서 찾을 수 있습니다.
집합과 방정식
협업 메모리 기반 추천 엔진을 구현하기 전에 먼저 이러한 시스템의 핵심 아이디어를 이해해야 합니다. 이 엔진에서 각 항목과 각 사용자는 식별자일 뿐입니다. 따라서 추천을 생성할 때 영화의 다른 속성(예: 출연진, 감독, 장르 등)을 고려하지 않습니다. 두 사용자 간의 유사성은 -1.0에서 1.0 사이의 십진수를 사용하여 표시됩니다. 우리는 이 숫자를 유사도 지수라고 부를 것입니다. 마지막으로 사용자가 영화를 좋아할 가능성은 -1.0에서 1.0 사이의 다른 십진수로 표시됩니다. 이제 간단한 용어를 사용하여 이 시스템 주변의 세계를 모델링했으므로 소수의 우아한 수학 방정식을 풀어서 이러한 식별자와 숫자 간의 관계를 정의할 수 있습니다.
우리의 추천 알고리즘에서 우리는 많은 세트를 유지할 것입니다. 각 사용자는 사용자가 좋아하는 영화 세트와 사용자가 싫어하는 영화 세트의 두 가지 세트를 갖게 됩니다. 각 영화에는 영화를 좋아한 사용자 세트와 영화를 싫어한 사용자 세트라는 두 개의 세트가 연관되어 있습니다. 권장 사항이 생성되는 단계에서 많은 집합이 생성됩니다. 대부분은 다른 집합의 합집합 또는 교집합입니다. 우리는 또한 각 사용자에 대한 제안 목록과 유사한 사용자 목록을 정렬할 것입니다.
유사성 지수를 계산하기 위해 Jaccard 지수 공식의 변형을 사용할 것입니다. 원래 "coefficient de communaute"(Paul Jaccard가 작성)로 알려진 이 공식은 두 세트를 비교하여 0과 1.0 사이의 간단한 십진법 통계를 생성합니다.
공식은 한 세트의 공통 요소 수를 두 세트의 모든 요소(한 번만 계산됨)의 수로 나누는 것을 포함합니다. 두 개의 동일한 집합의 Jaccard 인덱스는 항상 1이 되는 반면 공통 요소가 없는 두 집합의 Jaccard 인덱스는 항상 0을 생성합니다. 이제 두 집합을 비교하는 방법을 알았으므로 두 집합을 비교하는 데 사용할 수 있는 전략을 생각해 보겠습니다. 사용자. 앞서 논의한 바와 같이, 시스템의 관점에서 사용자는 식별자, 좋아하는 영화 세트 및 싫어요 영화 세트의 세 가지입니다. 사용자가 좋아하는 영화 세트만을 기반으로 사용자의 유사성 지수를 정의한다면 Jaccard 지수 공식을 직접 사용할 수 있습니다.
여기서 U1과 U2는 우리가 비교하는 두 사용자이고 L1과 L2는 U1과 U2가 각각 좋아한 영화 세트입니다. 자, 생각해보면 같은 영화를 좋아하는 두 명의 유저가 비슷하면 같은 영화를 싫어하는 두 명의 유저도 비슷해야 한다. 여기에서 방정식을 약간 수정합니다.
공식의 분자에서 일반적인 좋아요를 고려하는 대신 이제 일반적인 싫어함의 수도 추가합니다. 분모에서는 사용자가 좋아하거나 싫어한 모든 항목의 수를 취합니다. 이제 우리는 독립적인 방식으로 좋아함과 싫어함을 모두 고려했으므로 두 사용자가 선호도가 정반대인 경우도 생각해야 합니다. 한 사람은 영화를 좋아하고 다른 한 사람은 싫어하는 두 사용자의 유사성 지수는 0이 아니어야 합니다.
그것은 하나의 긴 공식입니다! 하지만 간단합니다. 약속합니다. 분자에 약간의 차이가 있는 이전 공식과 유사합니다. 이제 두 사용자의 공통 좋아요 및 싫어요 수에서 충돌하는 좋아요 및 싫어요 수를 뺍니다. 이로 인해 유사성 지수 공식은 -1.0에서 1.0 사이의 값 범위를 갖게 됩니다. 취향이 같은 두 사용자의 유사도 지수는 1.0이고 영화에서 완전히 상충되는 취향을 가진 두 사용자의 유사도 지수는 -1.0입니다.
이제 영화 취향에 따라 두 사용자를 비교하는 방법을 알았으므로 자체 추천 엔진 알고리즘 구현을 시작하기 전에 공식을 하나 더 탐색해야 합니다.
이 방정식을 조금 분해해 보겠습니다. P(U,M)
이 의미하는 것은 사용자 U
가 영화 M
을 좋아할 가능성입니다. ZL
과 ZD
는 각각 영화 M
을 좋아하거나 싫어한 모든 사용자와 사용자 U
의 유사도 지수의 합이다. |ML|+|MD|
영화 M
을 좋아하거나 싫어한 총 사용자 수를 나타냅니다. 결과 P(U,M)
은 -1.0에서 1.0 사이의 숫자를 생성합니다.
그게 다야. 다음 섹션에서는 이러한 공식을 사용하여 협업 메모리 기반 추천 엔진 구현을 시작할 수 있습니다.
추천 엔진 구축
우리는 이 추천 엔진을 매우 간단한 Node.js 애플리케이션으로 구축할 것입니다. 또한 프론트 엔드, 대부분 HTML 페이지 및 양식에 대한 작업이 거의 없습니다(페이지를 깔끔하게 보이게 하기 위해 부트스트랩을 사용할 것입니다). 서버 측에서는 CoffeeScript를 사용할 것입니다. 애플리케이션에는 몇 가지 GET 및 POST 경로가 있습니다. 응용 프로그램에 사용자 개념이 있더라도 정교한 등록/로그인 메커니즘은 없습니다. 지속성을 위해 애플리케이션이 일반 JSON 파일에 데이터를 저장하고 기본 데이터베이스 쿼리를 수행할 수 있도록 하는 NPM을 통해 사용할 수 있는 Bourne 패키지를 사용합니다. Express.js를 사용하여 경로 및 핸들러를 쉽게 관리할 수 있습니다.
이 시점에서 Node.js 개발이 처음이라면 이 튜토리얼을 더 쉽게 따라할 수 있도록 GitHub 리포지토리를 복제할 수 있습니다. 다른 Node.js 프로젝트와 마찬가지로 먼저 package.json 파일을 만들고 이 프로젝트에 필요한 종속성 패키지 세트를 설치합니다. 복제된 리포지토리를 사용하는 경우 package.json 파일이 이미 있어야 하며 여기서 종속성을 설치하려면 "$ npm install"을 실행해야 합니다. 그러면 package.json 파일 안에 나열된 모든 패키지가 설치됩니다.
이 프로젝트에 필요한 Node.js 패키지는 다음과 같습니다.
- 비동기
- 시내
- 커피 스크립트
- 표현하다
- 옥
- 밑줄
우리는 모든 관련 메소드를 4개의 개별 CoffeeScript 클래스로 분할하여 추천 엔진을 구축할 것입니다. Engine 클래스는 추천 엔진에 대한 간단한 API를 제공하는 역할을 하며 다른 세 클래스를 함께 바인딩합니다. 평가자는 좋아요와 싫어요를 추적할 책임이 있습니다(평가자 클래스의 두 개의 개별 인스턴스). 유사 및 제안은 각각 유사 사용자 및 사용자에 대한 추천 항목을 결정하고 추적하는 책임이 있습니다.
좋아요 및 싫어요 추적
먼저 평가자 클래스부터 시작하겠습니다. 이것은 간단한 것입니다:
class Rater constructor: (@engine, @kind) -> add: (user, item, done) -> remove: (user, item, done) -> itemsByUser: (user, done) -> usersByItem: (item, done) ->
이 튜토리얼의 앞부분에서 설명한 대로, 좋아요에 대한 평가자 인스턴스와 싫어요에 대한 다른 하나의 인스턴스가 있습니다. 사용자가 항목을 좋아하는지 기록하기 위해 "Rater#add()"에 전달합니다. 마찬가지로 평가를 제거하기 위해 "Rater#remove()"에 전달합니다.
Bourne을 서버리스 데이터베이스 솔루션으로 사용하고 있기 때문에 이러한 평가를 "./db-#{@kind}.json"이라는 파일에 저장합니다. 여기서 종류는 "좋아요" 또는 "싫어요"입니다. 평가자 인스턴스의 생성자 내부에서 데이터베이스를 엽니다.
constructor: (@engine, @kind) -> @db = new Bourne "./db-#{@kind}.json"
이렇게 하면 "Rater#add()" 메서드 내에서 Bourne 데이터베이스 메서드를 호출하는 것처럼 간단하게 평가 레코드를 추가할 수 있습니다.
@db.insert user: user, item: item, (err) =>
그리고 그것들을 제거하는 것과 비슷합니다("db.insert" 대신 "db.delete"). 그러나 무언가를 추가하거나 제거하기 전에 데이터베이스에 이미 존재하지 않는지 확인해야 합니다. 이상적으로는 실제 데이터베이스를 사용하여 단일 작업으로 수행할 수 있었습니다. Bourne에서는 먼저 수동 검사를 수행해야 합니다. 삽입 또는 삭제가 완료되면 이 사용자에 대한 유사성 지수를 다시 계산한 다음 새로운 제안 세트를 생성해야 합니다. "Rater#add()" 및 "Rater#remove()" 메서드는 다음과 같습니다.
add: (user, item, done) -> @db.find user: user, item: item, (err, res) => if res.length > 0 return done() @db.insert user: user, item: item, (err) => async.series [ (done) => @engine.similars.update user, done (done) => @engine.suggestions.update user, done ], done remove: (user, item, done) -> @db.delete user: user, item: item, (err) => async.series [ (done) => @engine.similars.update user, done (done) => @engine.suggestions.update user, done ], done
간결함을 위해 오류를 확인하는 부분은 건너뜁니다. 이것은 기사에서 할 수 있는 합리적인 일이지만 실제 코드의 오류를 무시하는 것에 대한 변명은 아닙니다.
이 클래스의 다른 두 가지 방법인 "Rater#itemsByUser()" 및 "Rater#usersByItem()"은 이름이 의미하는 대로 수행하는 것입니다. 즉, 사용자가 평가한 항목과 항목을 평가한 사용자가 각각 조회합니다. 예를 들어, 평가자 kind = “likes”
로 인스턴스화되면 "Rater#itemsByUser()"는 사용자가 평가한 모든 항목을 찾습니다.
유사한 사용자 찾기
다음 수업으로 이동: 유사. 이 클래스는 사용자 간의 유사성 지수를 계산하고 추적하는 데 도움이 됩니다. 앞서 논의한 바와 같이 두 사용자 간의 유사도를 계산하려면 그들이 좋아하는 항목과 싫어하는 항목 집합을 분석해야 합니다. 이를 위해 평가자 인스턴스에 의존하여 관련 항목 세트를 가져온 다음 유사성 지수 공식을 사용하여 특정 사용자 쌍에 대한 유사성 지수를 결정합니다.
이전 클래스인 Rater와 마찬가지로 "./db-similars.json"이라는 Bourne 데이터베이스에 모든 것을 저장합니다. 클래스에는 "Similars#byUser()" 메서드가 있어 간단한 데이터베이스 조회를 통해 주어진 사용자와 유사한 사용자를 찾을 수 있습니다.
@db.findOne user: user, (err, {others}) =>
그러나 이 클래스의 가장 중요한 메소드는 "Similars#update()"로 사용자를 취하여 유사한 다른 사용자의 목록을 계산하고 해당 목록을 유사도 지수와 함께 데이터베이스에 저장합니다. 사용자의 좋아요와 싫어요를 찾는 것으로 시작됩니다.
async.auto userLikes: (done) => @engine.likes.itemsByUser user, done userDislikes: (done) => @engine.dislikes.itemsByUser user, done , (err, {userLikes, userDislikes}) => items = _.flatten([userLikes, userDislikes])
또한 다음 항목을 평가한 모든 사용자를 찾습니다.
async.map items, (item, done) => async.map [ @engine.likes @engine.dislikes ], (rater, done) => rater.usersByItem item, done , done , (err, others) =>
다음으로 이러한 다른 사용자 각각에 대해 유사성 인덱스를 계산하고 모두 데이터베이스에 저장합니다.
async.map others, (other, done) => async.auto otherLikes: (done) => @engine.likes.itemsByUser other, done otherDislikes: (done) => @engine.dislikes.itemsByUser other, done , (err, {otherLikes, otherDislikes}) => done null, user: other similarity: (_.intersection(userLikes, otherLikes).length+_.intersection(userDislikes, otherDislikes).length-_.intersection(userLikes, otherDislikes).length-_.intersection(userDislikes, otherLikes).length) / _.union(userLikes, otherLikes, userDislikes, otherDislikes).length , (err, others) => @db.insert user: user others: others , done
위의 스니펫에서 Jaccard 지수 공식의 변형인 유사성 지수 공식과 본질적으로 동일한 표현식이 있음을 알 수 있습니다.

권장 사항 생성
다음 수업인 제안은 모든 예측이 이루어지는 곳입니다. 유사 클래스와 마찬가지로 우리는 생성자 내부에서 열리는 "./db-suggestions.json"이라는 또 다른 Bourne 데이터베이스에 의존합니다.
클래스에는 주어진 사용자에 대해 계산된 제안을 조회하는 "Suggestions#forUser()" 메서드가 있습니다.
forUser: (user, done) -> @db.findOne user: user, (err, {suggestions}={suggestion: []}) -> done null, suggestions
이 결과를 계산하는 방법은 "Suggestions#update()"입니다. "Similars#update()"와 같은 이 메서드는 사용자를 인수로 사용합니다. 이 방법은 주어진 사용자와 유사한 모든 사용자를 나열하고 해당 사용자가 평가하지 않은 모든 항목을 나열하는 것으로 시작됩니다.
@engine.similars.byUser user, (err, others) => async.auto likes: (done) => @engine.likes.itemsByUser user, done dislikes: (done) => @engine.dislikes.itemsByUser user, done items: (done) => async.map others, (other, done) => async.map [ @engine.likes @engine.dislikes ], (rater, done) => rater.itemsByUser other.user, done , done , done , (err, {likes, dislikes, items}) => items = _.difference _.unique(_.flatten items), likes, dislikes
다른 모든 사용자와 평가되지 않은 항목이 나열되면 이전 권장 사항 세트를 제거하고 각 항목을 반복하며 사용 가능한 정보를 기반으로 사용자가 좋아할 가능성을 계산하여 새로운 권장 사항 세트 계산을 시작할 수 있습니다.
@db.delete user: user, (err) => async.map items, (item, done) => async.auto likers: (done) => @engine.likes.usersByItem item, done dislikers: (done) => @engine.dislikes.usersByItem item, done , (err, {likers, dislikers}) => numerator = 0 for other in _.without _.flatten([likers, dislikers]), user other = _.findWhere(others, user: other) if other? numerator += other.similarity done null, item: item weight: numerator / _.union(likers, dislikers).length , (err, suggestions) =>
완료되면 데이터베이스에 다시 저장합니다.
@db.insert user: user suggestions: suggestions , done
라이브러리 API 노출
Engine 클래스 내에서 외부 세계에서 쉽게 액세스할 수 있도록 모든 것을 API와 같은 깔끔한 구조로 묶습니다.
class Engine constructor: -> @likes = new Rater @, 'likes' @dislikes = new Rater @, 'dislikes' @similars = new Similars @ @suggestions = new Suggestions @
일단 Engine 객체를 인스턴스화하면:
e = new Engine
좋아요와 싫어요를 쉽게 추가하거나 제거할 수 있습니다.
e.likes.add user, item, (err) -> e.dislikes.add user, item, (err) ->
또한 사용자 유사성 지수 및 제안 업데이트를 시작할 수 있습니다.
e.similars.update user, (err) -> e.suggestions.update user, (err) ->
마지막으로 이 Engine 클래스(및 다른 모든 클래스)를 해당 ".coffee" 파일에서 내보내는 것이 중요합니다.
module.exports = Engine
그런 다음 한 줄로 "index.coffee" 파일을 만들어 패키지에서 엔진을 내보냅니다.
module.exports = require './engine'
사용자 인터페이스 만들기
이 튜토리얼에서 추천 엔진 알고리즘을 사용할 수 있도록 웹을 통해 간단한 사용자 인터페이스를 제공하고자 합니다. 이를 위해 "web.iced" 파일 내에 Express 앱을 생성하고 몇 가지 경로를 처리합니다.
movies = require './data/movies.json' Engine = require './lib/engine' e = new Eengine app = express() app.set 'views', "#{__dirname}/views" app.set 'view engine', 'jade' app.route('/refresh') .post(({query}, res, next) -> async.series [ (done) => e.similars.update query.user, done (done) => e.suggestions.update query.user, done ], (err) => res.redirect "/?user=#{query.user}" ) app.route('/like') .post(({query}, res, next) -> if query.unset is 'yes' e.likes.remove query.user, query.movie, (err) => res.redirect "/?user=#{query.user}" else e.dislikes.remove query.user, query.movie, (err) => e.likes.add query.user, query.movie, (err) => if err? return next err res.redirect "/?user=#{query.user}" ) app.route('/dislike') .post(({query}, res, next) -> if query.unset is 'yes' e.dislikes.remove query.user, query.movie, (err) => res.redirect "/?user=#{query.user}" else e.likes.remove query.user, query.movie, (err) => e.dislikes.add query.user, query.movie, (err) => res.redirect "/?user=#{query.user}" ) app.route('/') .get(({query}, res, next) -> async.auto likes: (done) => e.likes.itemsByUser query.user, done dislikes: (done) => e.dislikes.itemsByUser query.user, done suggestions: (done) => e.suggestions.forUser query.user, (err, suggestions) => done null, _.map _.sortBy(suggestions, (suggestion) -> -suggestion.weight), (suggestion) => _.findWhere movies, id: suggestion.item , (err, {likes, dislikes, suggestions}) => res.render 'index', movies: movies user: query.user likes: likes dislikes: dislikes suggestions: suggestions[...4] )
앱 내에서 4개의 경로를 처리합니다. 인덱스 경로 "/"는 Jade 템플릿을 렌더링하여 프런트 엔드 HTML을 제공하는 곳입니다. 템플릿을 생성하려면 영화 목록, 현재 사용자의 사용자 이름, 사용자의 좋아요 및 싫어요, 사용자에 대한 상위 4개 제안이 필요합니다. Jade 템플릿의 소스 코드는 기사에서 제외되지만 GitHub 리포지토리에서 사용할 수 있습니다.
"/like" 및 "/dislike" 경로는 사용자의 좋아요 및 싫어요를 기록하기 위해 POST 요청을 수락하는 곳입니다. 두 경로 모두 필요한 경우 충돌하는 등급을 먼저 제거하여 등급을 추가합니다. 예를 들어 사용자가 이전에 싫어했던 것을 좋아하면 핸들러가 "싫어요" 등급을 먼저 제거하게 됩니다. 이러한 경로를 통해 사용자는 원하는 경우 항목을 "싫어요" 또는 "싫어요"할 수도 있습니다.
마지막으로 "/refresh" 경로를 통해 사용자는 요청 시 권장 사항 집합을 다시 생성할 수 있습니다. 그러나 이 작업은 사용자가 항목에 등급을 매길 때마다 자동으로 수행됩니다.
테스트 드라이브
이 문서를 따라 처음부터 이 애플리케이션을 구현하려고 시도했다면 테스트하기 전에 마지막 단계를 수행해야 합니다. "data/movies.json"에 ".json" 파일을 생성하고 다음과 같은 영화 데이터로 채워야 합니다.
[ { "id": "1", "name": "Transformers: Age of Extinction", "thumb": { "url": "//upload.wikimedia.org/wikipedia/en/7/7f/Inception_ver3.jpg" } }, // … ]
몇 가지 영화 이름과 썸네일 URL이 미리 채워져 있는 GitHub 리포지토리에서 사용 가능한 것을 복사할 수 있습니다.
모든 소스 코드가 준비되고 함께 연결되면 서버 프로세스를 시작하려면 다음 명령을 호출해야 합니다.
$ npm start
모든 것이 순조롭게 진행되었다고 가정하면 터미널에 다음 텍스트가 표시되어야 합니다.
Listening on 5000
실제 사용자 인증 시스템을 구현하지 않았기 때문에 프로토타입 애플리케이션은 "http://localhost:5000"을 방문한 후 선택한 사용자 이름에만 의존합니다. 사용자 이름을 입력하고 양식을 제출하면 "추천 영화" 및 "모든 영화" 섹션이 있는 다른 페이지로 이동해야 합니다. 협업 메모리 기반 추천 엔진(데이터)의 가장 중요한 요소가 없기 때문에 이 새로운 사용자에게 어떤 영화도 추천할 수 없습니다.
이 시점에서 다른 브라우저 창을 "http://localhost:5000"으로 열고 거기에서 다른 사용자로 로그인해야 합니다. 이 두 번째 사용자로 일부 영화를 좋아하거나 싫어합니다. 첫 번째 사용자의 브라우저 창으로 돌아가서 일부 영화도 평가하십시오. 두 사용자 모두에 대해 최소한 몇 편의 일반적인 영화를 평가해야 합니다. 즉시 추천을 보기 시작해야 합니다.
개량
이 알고리즘 튜토리얼에서 우리가 구축한 것은 프로토타입 추천 엔진입니다. 확실히 이 엔진을 개선할 수 있는 방법이 있습니다. 이 섹션에서는 대규모로 사용하기 위해 개선이 필수적인 일부 영역에 대해 간략하게 설명합니다. 그러나 확장성, 안정성 및 기타 속성이 필요한 경우 항상 오랜 시간 동안 테스트를 거친 솔루션을 사용해야 합니다. 기사의 나머지 부분과 마찬가지로 여기의 아이디어는 추천 엔진이 작동하는 방식에 대한 통찰력을 제공하는 것입니다. 현재 방법의 명백한 결함(예: 우리가 구현한 일부 방법의 경쟁 조건)에 대해 논의하는 대신 개선 사항에 대해 더 높은 수준에서 논의할 것입니다.
여기서 매우 분명한 개선 사항 중 하나는 파일 기반 솔루션 대신 실제 데이터베이스를 사용하는 것입니다. 파일 기반 솔루션은 소규모 프로토타입에서는 잘 작동할 수 있지만 실제 사용에는 전혀 합리적인 선택이 아닙니다. 많은 옵션 중 하나는 Redis입니다. Redis는 빠르며 집합과 같은 데이터 구조를 처리할 때 유용한 특수 기능이 있습니다.
간단히 해결할 수 있는 또 다른 문제는 사용자가 영화에 대한 등급을 지정하거나 변경할 때마다 새로운 권장 사항을 계산한다는 사실입니다. 실시간으로 즉석에서 재계산을 수행하는 대신 사용자에 대한 이러한 권장 업데이트 요청을 대기열에 넣고 장면 뒤에서 수행해야 합니다.
이러한 "기술적" 선택 외에도 권장 사항을 개선하기 위해 할 수 있는 몇 가지 전략적 선택도 있습니다. 항목과 사용자의 수가 증가함에 따라 권장 사항을 생성하는 데 점점 더 많은 비용이 들게 됩니다(시간 및 시스템 리소스 측면에서). 매번 전체 데이터베이스를 처리하는 대신 추천을 생성할 사용자의 하위 집합만 선택하여 이 작업을 더 빠르게 수행할 수 있습니다. 예를 들어, 이것이 레스토랑을 위한 추천 엔진이라면 같은 도시나 주에 거주하는 사용자만 포함하도록 유사한 사용자 집합을 제한할 수 있습니다.
다른 개선 사항에는 협업 필터링 및 콘텐츠 기반 필터링을 기반으로 권장 사항이 생성되는 하이브리드 접근 방식이 포함될 수 있습니다. 이것은 콘텐츠의 속성이 잘 정의된 영화와 같은 콘텐츠에서 특히 좋습니다. 예를 들어 Netflix는 이 경로를 사용하여 다른 사용자의 활동과 영화의 속성을 기반으로 영화를 추천합니다.
결론
메모리 기반 협업 추천 엔진 알고리즘은 매우 강력한 기능을 제공할 수 있습니다. 이 기사에서 실험한 것은 원시적일 수도 있지만 단순하기도 합니다. 이해하기 쉽고 구축하기 쉽습니다. 완벽하지는 않지만 Recommendable과 같은 추천 엔진의 강력한 구현은 유사한 기본 아이디어를 기반으로 합니다.
많은 데이터를 포함하는 대부분의 다른 컴퓨터 과학 문제와 마찬가지로 올바른 권장 사항을 얻는 것은 작업할 콘텐츠의 올바른 알고리즘과 적절한 속성을 선택하는 것과 관련이 있습니다. 이 기사를 통해 협업 메모리 기반 추천 엔진을 사용할 때 내부에서 어떤 일이 발생하는지 엿볼 수 있기를 바랍니다.