5.5 예제 코드 실행해보기

앞서 "직접 계산하기"에서는 예제 데이터셋의 평점 데이터를 사용하여 계산해 보았습니다. 이제부터는 평점 데이터 파일과 예제 코드를 사용하여 "직접 계산하기"의 계산 결과에 대해 한번 더 확인해 볼 것입니다.

"직접 계산하기"의 결과

구분 평점 예측 k값 최소이웃 사용자 아이템 랭크 예측평점
사용자 기반 추천 유사도 가중 평균 3 2 $i_3$ $i_3$ 3 2.825149
평점 평균과 유사도 평균 중심 가중 평균 3 1.960004
평점 평균과 유사도 Z점수 가중 평균 3 2.1836194
아이템 기반 추천 유사도 가중 평균 $u_4$ 3 3.6744673
평점 평균과 유사도 평균 중심 가중 평균 1 3.1968382
평점 평균과 유사도 Z점수 가중 평균 1 3.3887394

5.5.1 구현 클래스 살펴보기

먼저 예제 코드에서 사용하는 이웃 기반 협업 필터링이 구현된 KNearestNeighborsParams 클래스와 KNearestNeighbors 클래스를 살펴봅니다. KNearestNeighborsParams 클래스는 Apache Spark ML 패키지의 추상 클래스인 JavaParams 클래스를 상속받는 CommonParams 클래스를 구현하고 있는 클래스로 KNearestNeighbors 클래스의 생성자에 매개변수를 전달합니다. KNearestNeighbors 클래스는 AbstractRecommender 클래스를 상속받아 평점 데이터(사용자/아이템/평점)를 사용자 기반 또는 아이템 기반의 추천 결과로 변환하는 recommend 메서드를 구현하고 있는 협업 필터링 추천을 처리하는 추천기(Recommender)입니다.

다음 그림은 UML 클래스 다이어그램 표기법을 사용하여 KNearestNeighborsParams 클래스와 KNearestNeighbors 클래스를 클래스 다이어그램으로 나타낸 것입니다.

Download

[UML 클래스 다이어그램]

KNearestNeighborsParams 클래스는 이웃 기반 협업 필터링 추천을 위해 필요한 매개변수의 설정이나 기본값 변경이 필요한 경우에는 필요에 따라 다음 코드와 같이 빌더 패턴을 사용하여 인스턴스를 생성할 수 있습니다.

KNearestNeighborsParams params =
    new KNearestNeighborsParams()
        .setGroup(Group.USER)
        .setGroupCol("user")
        .setRatingNormalizer(new MeanCenteringNormalizer())
        .setSimilarityMeasurer(new CosineSimilarityMeasurer().setCriterion(Criterion.USER))
        .setWeightedAverage(WeightedAverage.SIMPLE)
        .setK(20)
        .setMinimumNeighbors(2)
        .setVerbose(false)
        .setUserCol("user")
        .setItemCol("item")
        .setRatingCol("rating")
        .setOutputCol("score");

KNearestNeighborsParams 클래스의 인스턴스에 설정 가능한 매개변수는 다음과 같습니다.

주요 매개변수

매개변수 유형 필수여부 기본값 설명
group Enum Group.USER 유사도 계산 기준을 Group 열거형 유형으로 설정(Group.USER: 사용자, Group.ITEM: 아이템)
groupCol String user 유사도 계산 기준을 문자열로 설정(“user”: 사용자, “item”:아이템).
ratingNormalizer RatingNormalizer - 평점 정규화를 처리하는 RatingNormalizer 객체
similarityMeasurer RatingSimilarityMeasurer O - 유사도 계산을 처리하는 RatingSimilarityMeasurer 객체
weightedAverage Enum WeightedAverage.SIMPLE 평점 예측을 위한 가중평균 계산 방법을 WeightedAverage 열거형 유형(WeightedAverage.SIMPLE: 단순 가중 평균, WeightedAverage.MEAN_CENTERING: 평균 중심 가중 평균, WeightedAverage.Z_SCORE: Z점수 가중평균)
k 20 최근접 이웃의 수(기본값: 20).
minimumNeighbors Integer 2 최소 이웃의 수(기본값: 2).
verbose boolean false 처리과정에 대한 정보를 출력할 것인지 여부 체크(기본값: false).
userCol String user 평점 데이터의 사용자 컬럼명(기본값: “user”)
itemCol String item 평점 데이터의 아이템 컬럼명(기본값: “item”)
ratingCol String rating 평점 데이터의 평점 컬럼명(기본값: “rating”)
outputCol String “score” 출력 컬럼명(기본값: “score”)으로 정규화된 평점

KNearestNeighbors 클래스는 다음 코드와 같이 생성된 KNearestNeighborsParams 클래스의 인스턴스를 생성자의 인자로 전달받아 인스턴스를 생성한 후 recommend 메서드를 사용하여 평점 데이터를 입력받아 예측 평점 높은 순의 Top-N 아이템 추천 데이터로 변환할 수 있습니다.

KNearestNeighborsParams params =
    new KNearestNeighborsParams()
        .setGroup(Group.USER)
        .setGroupCol("user")
        .setRatingNormalizer(new MeanCenteringNormalizer())
        .setSimilarityMeasurer(new CosineSimilarityMeasurer().setCriterion(Criterion.USER))
        .setWeightedAverage(WeightedAverage.SIMPLE)
        .setK(20)
        .setMinimumNeighbors(2)
        .setVerbose(false)
        .setUserCol("user")
        .setItemCol("item")
        .setRatingCol("rating")
        .setOutputCol("score");

KNearestNeighbors recommender = new KNearestNeighbors(params);

Dataset<Row> recommendedItemDS = recommender.recommend(ratingDS, 10, “$u_4$”);

KNearestNeighbors 클래스의 recommend 메서드에 설정 가능한 매개변수는 다음과 같습니다.

주요 매개변수

매개변수 유형 필수여부 기본값 설명
ratings Dataset O - Spark의 Dataset 유형인 평점 데이터셋
topN Integer O - 추천 아이템 수
userId Object O - 추천 받을 사용자 ID

5.5.2 예제 코드 살펴보기

여기에서는 "직접 계산하기"의 계산 결과를 확인하기 위해 JUnit으로 작성된 예제 클래스의 소스 코드를 살펴봅니다. 다음은 r4tings-recommender 라이브러리에 포함된 이웃 기반 협업 필터링 추천을 위한 구현 클래스인 KNearestNeighbors 클래스를 이용하여 "직접 계산하기"의 계산 결과를 확인하기 위한 KNearestNeighborsTest 클래스의 kNearestNeighborsExamples는 테스트 메서드입니다.

KNearestNeighborsTest.java

소스 코드에서 볼 수 있듯이 대부분 코드는 테스트를 처리하기 위한 것이지만 기본 흐름은 매우 단순합니다. 먼저 ❶ 매개변수를 바꿔가면서 실행하고 결과를 확인하기 위한 CSV 형식의 인자 목록을 설정합니다( 24~31행). 반복 실행되는 kNearestNeighborsExamples 메서드에서는 테스트 인자들을 매개변수로 받습니다. 다음으로 ❷ Parquet 유형의 평점 데이터를 읽어 들이고(44행) ❸ 이웃 기반 협업 필터링 추천을 위해 필요한 매개변수를 설정합니다(46행~54행). 다음으로 ❹ KNearestNeighbors 클래스의 인스턴스를 생성하고(56행) ❺ 평점 데이터와 추천 아이템 수, 추천받을 사용자 ID를 전달하여 아이템을 추천합니다(58행). 마지막으로 ❻ "직접 계산하기"에서 계산해 본 결과에 해당하는 기댓값(Expected)과 예제 코드의 실행 결과인 실제 값(Actual)의 소수 자릿수 7자리까지 비교합니다( 71행).

5.5.3 실행 결과 확인하기

여기에서는 앞서 살펴본 테스트 클래스인 KNearestNeighborsTest 클래스의 테스트 메서드인 kNearestNeighborsExamples의 실행 결과를 살펴봅니다. 다음과 같이 명령줄 인터페이스(CLI, Command line interface)에서 빌드 도구인 Gradle Wrapper로 KNearestNeighborsTest 클래스의 테스트 메서드인 kNearestNeighborsExamples를 실행해 봅니다.

./gradlew :recommender-examples:test --tests com.r4tings.recommender.examples.ch05.KNearestNeighborsTest.kNearestNeighborsExamples

테스트 메서드가 실행되면 직접 계산하기에서 다룬 결과를 확인하기 위해 설정한 테스트 인자 목록을 테스트 메서드의 매개변수에 대입해가며 반복 실행되어 결과가 출력됩니다.

다음은 반복 실행 테스트를 위한 테스트 인자 목록입니다

테스트 인자 목록

구분 데이터 경로 평점 정규화 유사도 계산 기준 평점 예측 k값 최소이웃 Top-N 사용자 아이템 랭크 예측평점

사용자 기반

추천

유사도 가중 평균 dataset/r4tings/ratings.parquet - COSINE USER SIMPLE 3 2 5 $u_4$ $i_3$ 3 2.825149
평점 평균과 유사도 평균 중심 가중 평균 MEAN_CENTERING MEAN_CENTERING 3 1.960004
평점 평균과 유사도 Z점수 가중 평균 Z_SCORE Z_SCORE 3 2.1836194

아이템

기반

추천

유사도 가중 평균 - ITEM SIMPLE 3 3.6744673
평점 평균과 유사도 평균 중심 가중 평균 MEAN_CENTERING MEAN_CENTERING 1 3.1968382
평점 평균과 유사도 Z점수 가중 평균 Z_SCORE Z_SCORE 1 3.3887394

예제 코드의 실행 결과는 다음과 같습니다.

예제 코드 실행 결과더보기

사용자 기반 추천의 ❶ 유사도 가중 평균, ❷ 평점 평균과 유사도 평균 중심 가중 평균, ❸ 평점 평균과 유사도 Z점수 가중 평균과 아이템 기반 추천의 ❹ 유사도 가중 평균, ❺ 평점 평균과 유사도 평균 중심 가중 평균, ❻ 평점 평균과 유사도 Z점수 가중 평균을 사용한 이웃 기반 협업 필터링 아이템 추천에 대한 테스트 케이스가 성공적으로 종료(PASSED)되었음을 확인할 수 있습니다. 또한, 실행 결과는 "직접 계산하기"에서 계산해 본 내용을 쉽게 확인하기 위해 처리 과정에서 파생된 상세 출력 정보도 함께 보여주고 있습니다.

5.5.4 R 패키지로 확인해보기

다음은 R 패키지를 이용하여 "직접 계산하기"의 계산 결과를 확인하기 위해 작성된 R 스크립트입니다.

KNearestNeighbors.R

이 R 스크립트는 사용자 기반 협업 필터링 추천을 위한 recommenderlab 패키지의 Recommender함수를 실행하고 결과를 확인하기 위한 방법을 설명합니다.

Note:

여기에서는 recommenderlab 패키지의 계산 방식이 여기에서 다루는 계산 방식과 동일한 사용자 기반 협업 필터링 추천 중 평점 평균과 유사도 평균 중심 가중 평균과 평점 평균과 유사도 Z점수 가중 평균 기반의 예측 평점 계산과 아이템 추천의 2가지 경우만 계산 결과를 확인합니다.

소스 코드에서 볼 수 있듯이 기본 흐름은 매우 단순합니다. 먼저 ❶ data.table 패키지의 fread 함수를 이용하여 CSV 유형의 평점 데이터를 읽어 들이고 (13행) ❷ recommenderlab 패키지에서 사용하는 realRatingMatrix 유형으로 변환하여 읽어 들인 평점 데이터를 출력합니다(25행~27행). 다음으로 ❸ 추천 대상을 사용자 $u_4$를 선정하고(33행~35행), ❹ 평점 평균과 유사도 평균 중심 가중 평균 기반의 사용자 기반 협업 필터링 추천 모델을 계산하고(41행~50행), ❺ 사용자 $u_4$의 추천 결과를 확인해봅니다(52행~53행). 같은 방법으로 ❻ 평점 평균과 유사도 Z점수 가중 평균 기반의 사용자 기반 협업 필터링 추천 모델을 계산하고(55행~65행), ❼ 사용자 $u_4$의 추천 결과를 확인해봅니다(67행~69행).

R 스크립트의 실행 결과는 다음과 같습니다.

R 스크립트 실행 결과더보기

이 실행 결과에서 볼 수 있듯이 ❶ 평점 평균과 유사도 평균 중심 가중 평균 기반과 ❷ 평점 평균과 유사도 Z점수 중심 가중 평균 기반의 사용자 기반 협업 필터링 추천 모델의 추천 결과를 확인할 수 있습니다. 또한, 실행 결과가 "직접 계산하기"의 계산 결과와 다른 점을 확인할 수 있습니다.

❶의 추천 결과에서 사용자 $u_4$가 평가하지 않은 아이템 {$i_3$, $i_5$, $i_7$, $i_{10}$}에 대한 예측 평점은 {1.960004, 4.547619, 4.039821, 2.619638}로 사용자 $u_4$에게 예측 평점이 높은 상위 $N$개($N = 3$)의 아이템을 추천하면, 추천된 아이템은 {$i_5$, $i_7$, $i_{10}$} 순이 되지만 "직접 계산하기"에서는 사용자 $u_4$가 평가하지 않은 아이템 {$i_3$, $i_5$, $i_7$, $i_{10}$}에 대한 예측 평점은 {1.9600039, NaN, 4.0398207, 2.6196375}으로 {$i_7$, $i_{10}$, $i_3$} 순이 됩니다. 이 중에서 $i_5$에 대한 예측 평점이 "직접 계산하기"와 상이한 이유는 "직접 계산하기에서는 최소 2이상의 근접 이웃을 기준으로 계산하였기 때문입니다.

"직접 계산하기"의 사용자 $u_4$가 평가하지 않은 아이템의 예측평점

아이템 평점 평균 합계(유사도와 평균중심화 평점의 곱) 합계(유사도 절대값) k-근접 이웃 예측 평점
$i_7$ 3.3333333 0.760188 1.0760106 {$i_1$, $i_2$} 4.0398207
$i_{10}$ 3.3333333 -0.7679442 1.0760106 {$i_1$, $i_2$} 2.6196375
$i_3$ 3.3333333 -1.4777169 1.0760106 {$i_1$, $i_2$} 1.9600039
$i_5$ 3.3333333 0.2745024 0.2260608 {$i_2$} NaN

NaN으로 처리된 사용자 $u_4$가 평가하지 않은 아이템 $i_5$에 대한 예측 평점을 계산해보면 4.547619로 ❶의 추천 결과와 같음을 확인할 수 있습니다.

$$ \begin{flalign} {\hat r_{u_4,i_5}} & = 3.3333333 + \frac{{0.2260608 \times (4 - 2.7857142)}}{{\left| {0.2260608} \right|}} \\ & = 4.547619 \end{flalign} $$

❷의 추천 결과도 마찬가지로 $i_5$에 대한 예측 평점이 4.992363로 "직접 계산하기"의 예측 평점인 NaN과 상이한 이유는, "직접 계산하기에서는 최소 2이상의 근접 이웃을 기준으로 계산하였기 때문입니다.

"직접 계산하기"의 사용자 $u_4$가 평가하지 않은 아이템의 예측평점

아이템 평점 평균 표준편차 합계(유사도와 Z점수의 곱) 합계(유사도 절대값) k-근접 이웃 예측 평점
$i_7$ 3.3333333 1.5705625 0.5138017 1.0760106 {$i_1$, $i_2$} 4.0832867
$i_{10}$ 3.3333333 1.5705625 -0.5574238 1.0760106 {$i_1$, $i_2$} 2.5197084
$i_3$ 3.3333333 1.5705625 -0.7876822 1.0760106 {$i_1$, $i_2$} 2.1836194
$i_5$ 3.3333333 1.5705625 0.2387944 0.2260608 {$i_2$} NaN

NaN으로 처리된 사용자 $u_4$가 평가하지 않은 아이템 $i_5$에 대한 예측 평점을 계산해보면 4.9923635로 ❷의 추천 결과와 같음을 확인할 수 있습니다.

$$ \begin{flalign} {\hat r_{u_4,i_5}} & = 3.3333333 + 1.5705625 \times \frac{{0.2260608 \times \frac{{4 - 2.7857142}}{{1.149534}}}}{{\left| {0.2260608} \right|}} \\ & = 4.9923635 \end{flalign} $$
한글:2876 영어:4814 숫자:822

추천 시스템: 워크북

Comments

Do you have a problem, want to share feedback, or discuss further ideas? Feel free to leave a comment here! Please follow Rust's code of conduct. This comment thread directly maps to a discussion on GitHub, so you can also comment there if you prefer.

Instead of authenticating the giscus application, you can also comment directly on GitHub.