3.5 소수 스케일링화

소수 스케일링(Decimal Scaling) 정규화는 평점을 1보다 작고 -1보다 큰 소수로 변환하여 평점의 소수점을 이동시키는 것입니다. 소수점을 얼마나 이동시킬지는 전체 평점의 최대 절대값에 의해 정해집니다.

소수/declmal fraction

小는 '작다'를 의미하므로, 小數에는 '작은 수'의 뜻이 있다. '小數'는 중국에서 만들어진 것으로 보인다. 중국에서는 1보다 작고 0보다 큰 수를 나타내기 위해 소수를 만들었다.
중국의 <算學啓蒙(산학계몽)>(1299년)에 소수의 이름으로 分(분), 釐(리), 毫(호), 絲(사), 忽(홀), 微(미), ... 등이 소개되고 있다. 한편, 서양에서 현재의 소수와 유사한 것을 고안한 사람은 벨기에의 시몬 스테빈(Simon Stevin, 1548-1620)으로 알려져 있다. 그는 (1585)에서 소수를 다루고 있었다. Disme에는 '십분의 일'이라는 뜻이 있다.
소수를 영어로는 decimal fraction이라고 한다. decimal에서, deci에는 '십분의 일'이라는 뜻이 있다. 오늘날 decimal이라고 할 때, 그것은 '십진법(의)'라고 해석된다. 十進(십진)이란 문자 그대로 10배씩 커진다는 의미이기도 하지만, 다른 한 편으로는 '10분의 1배'씩 작아진다는 의미이기도 하다.
이런 이유에서 decimal이 또한 '소수(의)'라고 해석되는 것으로 보인다. 본래, 십진법이란 한 자리가 올라갈 때마다 10배씩 커지는 기수법을 의미한다. fraction에는 '분수'라는 뜻이 있다.
그래서 서양의 decimal fraction은 '십진분수' 다시 말해, 서양의 소수는 분수의 특별한 형태 즉, 분모가 10씩 커지는 분수에서 비롯된 것으로, '분모가 10의 거듭제곱꼴로 된 분수'를 의미한다. 이렇게 보면, 중국의 소수와 스테빈에 의해 고안된 서양의 소수는 그 발상이 근본적으로 다르다는 것을 알 수 있다. 중국에 서양 수학이 소개되면서 이 decimal fraction이라는 용어도 도입되었을 것이다.
그러나 중국에서는 이미 소수라는 용어가 오랫동안 사용되어 왔으므로, 그것을 십진분수로 번역하는 대신 소수를 그대로 사용했던 것이다. 소수는 본래는 1보다 작고 0보다 큰 수를 의미했지만, 지금은 이를테면 0.3, 4.56, -2.34 등도 모두 소수라고 한다.
'소수점'은 한자 小數點의 음역이다. 이를테면, 소수 0.3, 4.56 등에서 0과 3 사이, 또 4와 56 사이의 점 ' .'이 소수점이다. 또, -3.7에서 -3과 7 사이의 점 ' .'도 소수점이다.
즉, 소수점을 기준으로, 소수점의 왼쪽은 정수이며, 오른쪽은 그 절대값이 0보다 크고 1보다 작은 수이다.
소수점을 영어로는 decimal point라고 한다. decimal은 '소수'를, point는 '점'을 의미한다.

3.5.1 수식 살펴보기

여기에서는 전체 평점을 대상으로 하는 소수 스케일링화를 위한 수식을 살펴봅니다. 소수 스케일링화는 전체 평점만 대상으로 사용자 또는 아이템 집단의 집단 평점을 대상으로 변환은 하지 않습니다.

소수 스케일링화는 다음과 같이 정의됩니다.

$$ \begin{flalign} \hat r_{ui} & =\frac{r_{ui}} {10^j} \end{flalign} $$

여기에서 $r_{ui}$은 사용자 $u$가 아이템 $i$에 매긴 평점, $j$는 새로운 평점 집합 $R'$에서 $\max \left| {R'} \right| < 1$ 이 성립되는 가장 가까운 정수입니다.

정규화된 평점은 정규화 과정에서 사용된 지수 $j$을 알고 있다면 역정규화 할 수 있습니다.

소수 스케일링로 정규화된 평점의 역정규화는 다음과 같이 정의됩니다.

$$ \begin{flalign} r_{ui} & =\hat r_{ui} \times {10^j} \end{flalign} $$

여기에서 $\hat r_{ui}$는 정규화된 평점, $j$는 정규화에 사용된 지수입니다.

3.5.2 직접 계산해보기

이제부터 예제 데이터셋을 사용하여 앞서 살펴본 수식으로 직접 계산해 볼 것입니다. 다음 표는 평점 데이터를 사용자는 행, 아이템은 열로 나타낸 것입니다.

예제 데이터셋의 평점 데이터

사용자/아이템 $i_1$ $i_2$ $i_3$ $i_4$ $i_5$ $i_6$ $i_7$ $i_8$ $i_9$ $i_{10}$
$u_1$ 0.5 5 1 3 3.5 5 2.5
$u_2$ 3 2 3.5 2 4 4 1
$u_3$ 3.5 1 3.5 4 1 3.5
$u_4$ 3 5 0.5 3.5 3.5 4.5
$u_5$ 3 4 2.5 4

예를 들어 사용자 $u_4$가 아이템 $i_1$에 매긴 평점을 소수 스케일링로 정규화해 봅니다. 여기에서 평점 데이터의 최대 절댓값은 5이고 이를 ${10^j}$로 나누었을 때 항상 1보다 작음을 만족하는 지수 $j$는 5의 상용로그 값인 $0.69897$과 가장 가까운 정수인 1입니다. 소수 스케일링로 정규화된 평점은 사용자 $u_4$가 아이템 $i_1$에 매긴 평점을 ${10^1}$으로 나눈 0.3이 됩니다.

$$ \begin{flalign} {\hat {\hat r_{u_4,i_1}} & =\frac{3}{10^1} \\ & = 0.3 \end{flalign} $$

Tip:

log5는 로그의 성질에 따라 log2+log5=log(2×5)=log10=1이므로 log2만 알면 됩니다.

정규화된 평점은 정규화 과정에서 사용된 지수 $j$를 알고 있다면 원본 평점인 $3$으로 역정규화 할 수 있습니다.

$$ \begin{flalign} r_{u_4,i_1} & =0.3 \times{10^1} \\ & = 3 \end{flalign} $$

다음 표는 직접 계산한 결괏값을 나타낸 것입니다.

계산 결과

원본 평점 평점 최대 절댓값 평점 최대 절댓값의 상용로그 지수 정규화된 평점 역정규화된 평점
3 5 0.69897 1 0.3 3

같은 방법으로 소수 스케일링로 모두 정규화해 봅니다.

다음 표는 소수 스케일링로 정규화된 평점 데이터를 나타낸 것입니다.

소수 스케일링 평점 데이터

아이템 $i_1$ $i_2$ $i_3$ $i_4$ $i_5$ $i_6$ $i_7$ $i_8$ $i_9$ $i_{10}$
$u_1$ 0.05 0.5 0.1 0.3 0.35 0.5 0.25
$u_2$ 0.3 0.2 0.35 0.2 0.4 0.4 0.1
$u_3$ 0.35 0.1 0.35 0.4 0.1 0.35
$u_4$ 0.3 0.5 0.05 0.35 0.35 0.45
$u_5$ 0.3 0.4 0.25 0.4

3.5.3 예제 코드 실행해보기

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

“직접 계산하기” 계산 결과

구분 사용자 아이템 원본 평점 정규화된 평점 설명
소수 스케일링화 $u_4$ $i_1$ 3 0.3 평점을 전체 평점의 최대 절대값으로 평점의 소수점을 이동시켜 변환
사용자 소수 스케일링화 소수 스케일링화는 전체 평점만 대상으로 지원하지 않음
아이템 소수 스케일링화 소수 스케일링화는 전체 평점만 대상으로 지원하지 않음

3.5.3.1 구현 클래스 살펴보기

먼저 예제 코드에서 사용하는 소수 스케일링화가 구현된 DecimalScalingNormalizer 클래스를 살펴봅니다. DecimalScalingNormalizer 클래스는 Apache Spark ML 패키지의 추상 클래스인 Transformer 클래스를 상속받아 평점 데이터를 소수 스케일링화된 평점 데이터로 변환하는 transform 메서드를 구현한 클래스입니다.

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

Download

[UML 클래스 다이어그램]

DecimalScalingNormalizer 클래스는 소수 스케일링화를 위해 필요한 매개변수의 설정이나 기본값 변경이 필요한 경우에는 필요에 따라 다음 코드와 같이 빌더 패턴을 사용하여 인스턴스를 생성할 수 있습니다.

DecimalScalingNormalizer normalizer =
                new DecimalScalingNormalizer()
                        .setGroup(Group.USER)
                        .setGroupCol("user")
                        .setVerbose(true)
                        .setOutputCol("rating")
                        .setUserCol("user")
                        .setItemCol("item")
                        .setRatingCol("rating");

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

주요 매개변수

매개변수 유형 필수여부 기본값 설명
group Enum - 소수 스케일링화 기준을 Enum 유형으로 설정(기본값/null: 전체, Group.USER: 사용자, Group.ITEM: 아이템)
groupCol String - 소수 스케일링화 기준을 문자열로 설정(기본값/null: 전체, user: 사용자, item:아이템).
verbose boolean false 처리과정에 대한 정보를 출력할 것인지 여부 체크(기본값: false).
userCol String user 평점 데이터의 사용자 칼럼명(기본값: user)
itemCol String item 평점 데이터의 아이템 칼럼명(기본값: item)
ratingCol String rating 평점 데이터의 평점 칼럼명(기본값: rating)
outputCol String ratingCol 출력 칼럼명(기본값: ratingCol)으로 정규화된 평점

생성된 DecimalScalingNormalizer 인스턴스는 RatingNormalizer 클래스에 구현된 transform 메서드를 사용하여 평점 데이터를 입력받아 평점을 소수 스케일링화된 평점으로 변환할 수 있습니다.

Dataset<Row> normalizedRatingDS = normalizer.transform(ratingDS);

3.5.3.2 예제 코드 살펴보기

여기에서는 "직접 계산하기"의 계산 결과를 확인하기 위해 JUnit으로 작성된 예제 클래스의 소스 코드를 살펴봅니다. 다음은 r4tings-recommender 라이브러리에 포함된 소수 스케일링화를 위한 구현 클래스인 DecimalScalingNormalizer 클래스를 이용하여 "직접 계산하기"의 계산 결과를 확인하기 위한 DecimalScalingTest 클래스의 decimalScalingExamples는 테스트 메서드입니다.

DecimalScalingTest.java

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

3.5.3.3 실행 결과 확인하기

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

./gradlew :recommender-examples:test --tests com.r4tings.recommender.examples.ch03.DecimalScalingTest.decimalScalingExamples

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

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

테스트 인자 목록

구분 데이터 경로 그룹 상세출력 사용자 아이템 정규화된 평점
전체 소수 스케일링화 dataset/r4tings/ratings.parquet true $u_4$ $i_1$ 0
사용자 소수 스케일링화 dataset/r4tings/ratings.parquet USER The requested operation is not supported. - user
아이템 소수 스케일링화 dataset/r4tings/ratings.parquet ITEM The requested operation is not supported. – item

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

예제 코드 실행 결과더보기

이 실행 결과에서 볼 수 있듯이 설정한 테스트 인자 목록에 따라 예상대로 실제 값이 반환되어 ❶ 소수 스케일링화 ❷ 사용자 소수 스케일링화 ❸ 아이템 소수 스케일링화에 대한 테스트 케이스가 성공적으로 종료(PASSED) 되었음을 확인할 수 있습니다. 또한, 실행 결과는 "직접 계산하기"에서 계산해 본 내용을 쉽게 확인하기 위해 처리 과정에서 파생된 상세 출력 정보도 함께 보여주고 있습니다.

3.5.3.4 R 패키지로 확인해보기

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

DecimalScalingTest.R

이 R 스크립트는 소수 스케일링화를 위한 rknn 패키지의 normalize.decscale 함수를 실행하고 결과를 확인하기 위한 방법을 설명합니다. 소스 코드에서 볼 수 있듯이 기본 흐름은 매우 단순합니다. 먼저 ❶ data.table 패키지의 fread 함수를 이용하여 CSV 유형의 평점 데이터를 읽어 들이고 (15행) ❷ recommenderlab 패키지에서 사용하는 realRatingMatrix 유형으로 변환하여 읽어 들인 평점 데이터를 출력합니다((32행~36행). 다음으로 ❸ 사용자 소수 스케일링화를 하고 정규화한 평점 데이터를 matrix 유형으로 변환하여 출력합니다(38행~42행).

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

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

이 실행 결과에서 볼 수 있듯이 ❶ 소수 스케일링화 결과를 확인할 수 있습니다. 또한, 실행 결과가 "직접 계산하기"의 계산 결과와 같음을 확인할 수 있습니다.

한글:3126 영어:3234 숫자:483

추천 시스템: 워크북

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.