3.3 Z점수화

Z점수(Z-Score) 정규화는 평점에서 평점의 평균을 뺀 후 표준편차로 나누어 평균이 0이고 표준편차가 1인 표준정규분포(Standard Normal Distribution)가 되도록 변환하는 것입니다. 이는 평점 데이터가 평균을 기준으로 표준편차의 몇 배만큼 떨어져 있는지를 나타내는 값으로 평균 중심화와 마찬가지로 정규화된 평점이 평균보다 작으면 음수, 평균보다 크면 양수, 평균이면 0이 됩니다. 평균 중심화와 다른 점은 표준편차에 의해 값의 크기가 결정되며 표준편차가 크면 클수록 정규화되는 값은 0에 가까워집니다.

3.3.1 수식 살펴보기

여기에서는 전체 평점을 대상으로 하는 전체 Z점수화와 사용자 또는 아이템 집단의 집단 평점을 대상으로 집단 Z점수화에 대한 수식을 살펴봅니다.

Tip:

표준 점수화(Z-Score) 정규화는 제로 평균(Zero Mean) 정규화라고도 합니다.

3.3.1.1 전체 Z점수화

전체 Z점수화는 평점을 전체 평점의 평균과 표준편차로 Z점수 값으로 변환하는 것입니다.

Z점수화는 다음과 같이 정의됩니다.

$$ \begin{flalign} \hat r_{ui} = \frac{{r_{ui} - \mu }}{\sigma } \end{flalign} $$

여기에서 $r_{ui}$은 사용자 $u$가 아이템 $i$에 매긴 평점, $\mu $와 $\sigma $는 평점 집합 $R$의 평균과 표준편차입니다.

표준편차 $\sigma $는 다음과 같이 정의됩니다.

$$ \begin{flalign} \sigma & = \sqrt {\frac{{\sum\nolimits_1^n {{{(r_{ui} - \mu )}^2}} }}{{\left| R \right| - 1}}} \end{flalign} $$

여기에서 $r_{ui}$은 사용자 $u$가 아이템 $i$에 매긴 평점, $\mu $와 $\left| R \right|$은 평점 집합 $R$의 평균과 원소 개수입니다.

Note:

여기에서는 표준편차 계산에서 n-1로 나눈 표본 분산을 사용한 이유인 불편 추정량(Unbiased Estimator)과 자유도(Degree of freedom)에 관해서는 다루지 않습니다. 자세한 개념은 필요하면 전문 서적이나 자료를 참고하세요.

정규화된 평점은 정규화 과정에서 사용된 전체 평점 집합 $R$의 평균과 표준편차를 알고 있다면 역정규화를 할 수 있습니다.

Z점수로 정규화된 평점의 역정규화는 다음과 같이 정의됩니다.

$$ \begin{flalign} r_{ui} = (\hat r_{ui} \times \sigma ) + \mu \end{flalign} $$

여기에서 $\hat r_{ui}$는 정규화된 평점, $\mu $와 $\sigma $는 평점 집합 $R$의 평균과 표준편차입니다.

3.3.1.2 사용자 Z점수화

사용자 Z점수화는 사용자의 평점을 사용자 그룹의 평점 평균과 표준편차로 Z점수 값으로 변환하는 것입니다.

사용자 Z점수화의 표준편차는 다음과 같이 정의됩니다.

$$\begin{flalign} {\sigma _u} & = \sqrt {\frac{{\sum\nolimits_{i \in {I_u}} {{{(r_{ui} - {\mu _u})}^2}} }}{{\left| {{I_u}} \right| - 1}}} \end{flalign}$$

여기에서 $r_{ui}$은 사용자 $u$가 아이템 $i$에 매긴 평점, ${\mu _u}$와 $\left| {{I_u}} \right|$는 사용자 $u$에게 평가된 아이템 집합 ${I_u}$의 평점 평균과 원소 개수입니다.

사용자 Z점수화는 다음과 같이 정의됩니다.

$$ \begin{flalign} \hat r_{ui} = \frac{r_{ui} - {\mu _u}}{{\sigma _u}} \end{flalign} $$

여기에서 $r_{ui}$은 사용자 $u$가 아이템 $i$에 매긴 평점, ${\mu _u}$와 ${\sigma _u}$는 아이템 집합 ${I_u}$의 평점 평균과 표준편차입니다.

정규화된 평점은 정규화 과정에서 사용된 아이템 집합 ${I_u}$의 평균과 표준편차를 알고 있다면 역정규화 할 수 있습니다.

사용자 Z점수으로 정규화된 평점의 역정규화는 다음과 같이 정의됩니다.

$$ \begin{flalign} r_{ui} = (\hat r_{ui} \times {\sigma _u}) + {\mu _u} \end{flalign} $$

여기에서 $\hat r_{ui}$는 정규화된 평점, ${\mu _u}$와 ${\sigma _u}$는 ${I_u}$의 평점 평균과 표준편차입니다.

3.3.1.3 아이템 Z점수화

아이템 Z점수화는 아이템 평점을 아이템 그룹의 평균과 표준편차로 Z점수 값으로 변환하는 것입니다.

아이템 Z점수화의 표준편차는 다음과 같이 정의됩니다.

$$\begin{flalign} {\sigma _i} = \sqrt {\frac{{\sum\nolimits_{u \in {U_i}} {{{(r_{ui} - {\mu _i})}^2}} }}{{\left| {{U_i}} \right| - 1}}} \end{flalign}$$

여기에서 $r_{ui}$은 사용자 $u$가 아이템 $i$에 매긴 평점, ${\mu _i}$와 $\left| {{U_i}} \right|$는 아이템 $i$를 평가한 사용자 집합 ${I_u}$의 평점 평균과 원소 개수입니다.

아이템 Z점수화는 다음과 같이 정의됩니다.

$$\begin{flalign} \hat r_{ui} = \frac{r_{ui} - {\mu _i}}{{\sigma _i}} \end{flalign}$$

여기에서 $r_{ui}$은 사용자 $u$가 아이템 $i$에 매긴 평점, ${\mu _i}$와 ${\sigma _i}$는 ${I_u}$의 평점 평균과 표준편차입니다.

정규화된 평점은 정규화 과정에서 사용된 사용자 집합 ${I_u}$의 평점 평균과 표준편차를 알고 있다면 역정규화 할 수 있습니다.

아이템 Z점수으로 정규화된 평점의 역정규화는 다음과 같이 정의됩니다.

$$\begin{flalign} r_{ui} = (\hat r_{ui} \times {\sigma _i}) + {\mu _i} \end{flalign}$$

여기에서 $\hat r_{ui}$는 정규화된 평점, ${\mu _i}$와 ${\sigma _i}$는 ${I_u}$의 평점 평균과 표준편차입니다.

3.3.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$에 매긴 평점을 정규화해 봅니다.

3.3.2.1 전체 Z점수화

예를 들어 사용자 $u_4$가 아이템 $i_1$에 매긴 평점을 Z점수로 정규화해 봅니다.

여기에서 전체 평점 평균은 평점 집합의 평점 평균으로 $3$입니다. 표본 분산은 $1.7931034$, 표준편차는 $1.3390681$입니다. Z점수로 정규화된 평점은 사용자 $u_4$가 아이템 $i_1$에 매긴 평점에서 사용자 $u_4$의 평점 평균을 뺀 값을 표준편차로 나눈 0이 됩니다.

$$\begin{flalign} {\hat r_{u_4,i_1}} = \frac{3 - 3}{1.3390681} = 0 \end{flalign}$$

이처럼 정규화된 평점은 정규화 과정에서 사용된 사용자 $u_4$가 평가한 아이템의 평점 평균과 표준편차를 알고 있다면 원본 평점인 $3$으로 역정규화 할 수 있습니다.

$$\begin{flalign} r_{u_4,i_1} = (0 \times 1.3390681) + 3 = 3 \end{flalign}$$

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

계산 결과

원본 평점 평점 평균 평점 표준편차 정규화된 평점 역정규화된 평점
3 3 1.3390681 0 3

같은 방법으로 Z점수화로 모두 정규화해 봅니다.

다음 표는 Z점수로 정규화된 평점 데이터를 나타낸 것입니다.

[전체 Z점수화 평점 데이터]

아이템 $i_1$ $i_2$ $i_3$ $i_4$ $i_5$ $i_6$ $i_7$ $i_8$ $i_9$ $i_{10}$
$u_1$ -1.86697 1.493576 -1.493576 0 0.373394 1.493576 -0.373394
$u_2$ 0 -0.746788 0.373394 -0.746788 0.746788 0.746788 -1.493576
$u_3$ 0.373394 -1.493576 0.373394 0.746788 -1.493576 0.373394
$u_4$ 0 1.493576 -1.86697 0.373394 0.373394 1.120182
$u_5$ 0 0.746788 -0.373394 0.746788

3.3.2.2 사용자 Z점수화

예를 들어 사용자 $u_4$가 아이템 $i_1$에 매긴 평점을 사용자 Z점수로 정규화해 봅니다.

여기에서 사용자 $u_4$가 평가한 아이템 {$i_1$, $i_2$, $i_4$, $i_6$, $i_8$, $i_9$}에 대한 평점은 {3, 5, 0.5, 3.5, 3.5, 4.5}입니다. 사용자 $u_4$의 평점 평균은 $3.3333333$, 표본 분산은 $2.4666666$, 표준편차는 $1.5705625$입니다. 사용자 Z점수로 정규화된 평점은 사용자 $u_4$가 아이템 $i_1$에 매긴 평점에서 사용자 $u_4$의 평점 평균을 뺀 값을 표준편차로 나눈 $-0.2122$이 됩니다.

$$\begin{flalign} {\hat r_{u_4,i_1}} = \frac{3 - 3.3333333}{1.5705625} \approx - 0.2122 \end{flalign}$$

이처럼 정규화된 평점은 정규화 과정에서 사용된 사용자 $u_4$가 평가한 아이템의 평점 평균과 표준편차를 알고 있다면 원본 평점인 $3$으로 역정규화 할 수 있습니다.

$$\begin{flalign} r_{u_4,i_1} = ( - 0.212 \times 1.5705625) + 3.3333333 \approx 3 \end{flalign}$$

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

계산 결과

원본 평점 평점 평균 평점 표준편차 정규화된 평점 역정규화된 평점
3 3.3333333 1.5705625 -0.2122 3

같은 방법으로 사용자 Z점수화로 모두 정규화해 봅니다.

다음 표는 사용자 Z점수로 정규화된 평점 데이터를 나타낸 것입니다.

[사용자 Z점수화 평점 데이터]

아이템 $i_1$ $i_2$ $i_3$ $i_4$ $i_5$ $i_6$ $i_7$ $i_8$ $i_9$ $i_{10}$
$u_1$ -1.3751177 1.1728945 -1.0920052 0.0404446 0.3235571 1.1728945 -0.2426678
$u_2$ 0.1864109 -0.6835067 0.6213698 -0.6835067 1.0563286 1.0563286 -1.5534244
$u_3$ 0.5477226 -1.2780193 0.5477226 0.9128709 -1.2780193 0.5477226
$u_4$ -0.2122382 1.0611909 -1.8040245 0.1061191 0.1061191 0.7428336
$u_5$ -0.5 0.8333333 -1.1666667 0.8333333

3.3.2.3 아이템 Z점수화

예를 들어 사용자 $u_4$가 아이템 $i_1$에 매긴 평점을 아이템 Z점수로 정규화해 봅니다.

여기에서 아이템 $i_1$을 평가한 사용자 {$u_1$, $u_2$, $u_4$}에 대한 평점은 {0.5, 3, 3}입니다. 아이템 $i_1$의 평점 평균은 $2.1666666$, 표본 분산은 $2.0833333$, 표준편차는 $1.4433757$입니다. 아이템 Z점수로 정규화된 평점은 사용자 $u_4$가 아이템 $i_1$에 매긴 평점에서 아이템 $i_1$의 평점 평균인 2.1666666을 뺀 값을 표준편차로 나눈 $0.5773$이 됩니다.

$$\begin{flalign} {\hat r_{u_4,i_1}} = \frac{3 - 2.1666666}{1.4433757} \approx 0.5773 \end{flalign}$$

정규화된 평점은 정규화 과정에서 사용된 아이템 $i_1$을 평가한 사용자의 평점 평균과 표준편차를 알고 있다면 원본 평점인 $3$으로 역정규화 할 수 있습니다.

$$\begin{flalign} r_{u_4,i_1} = (0.5773 \times 1.4433756) + 2.1666666 \approx 3 \end{flalign}$$

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

계산 결과

원본 평점 평점 평균 평점 표준편차 정규화된 평점 역정규화된 평점
3 2.1666666 1.4433756 0.5773 3

같은 방법으로 사용자 Z점수화로 모두 정규화해 봅니다.

다음 표는 아이템 Z점수로 정규화된 평점 데이터를 나타낸 것입니다.

[아이템 Z점수화 평점 데이터]

아이템 $i_1$ $i_2$ $i_3$ $i_4$ $i_5$ $i_6$ $i_7$ $i_8$ $i_9$ $i_{10}$
$u_1$ -1.1547005 0.9970545 -0.8589557 0.46291 -1.1547005 0.8728716 0.7071068
$u_2$ 0.5773503 -1.3038405 0.7027819 0 NaN 0.5773503 -0.7071068
$u_3$ -0.153393 -0.8589557 1 NaN -1.3887301 -1.0910895
$u_4$ 0.5773503 0.9970545 -1 0.9258201 NaN 0.2182179
$u_5$ -0.5368755 1.0151295 0 0.5773503

Tip:

NaN 설명이 필요함? NA는 데이터 없음 = null

3.3.3 예제 코드 실행해보기

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

"직접 계산하기"의 계산 결과

구분 사용자 아이템 원본 평점 정규화된 평점 설명
전체 Z점수화 $u_4$ $i_1$ 3 0 평점을 전체 평점의 평균과 표준편차로 Z점수화
사용자 Z점수화 -0.2122 각 사용자 그룹의 평점을 사용자 그룹의 평점 평균과 표준편차로 Z점수화
아이템 Z점수화 0.5773 각 아이템 그룹의 평점을 아이템 그룹의 평점 평균과 표준편차로 Z점수화

3.3.3.1 구현 클래스 살펴보기

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

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

Download

[UML 클래스 다이어그램]

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

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

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

주요 매개변수

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

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

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

3.3.3.2 예제 코드 살펴보기

여기에서는 "직접 계산하기"의 계산 결과를 확인하기 위해 JUnit으로 작성된 예제 클래스의 소스 코드를 살펴봅니다.

다음은 r4tings-recommender 라이브러리에 포함된 Z점수화를 위한 구현 클래스인 ZScoreNormalizer 클래스를 이용하여 "직접 계산하기"의 계산 결과를 확인하기 위한 ZScoreTest 클래스의 zScoreExamples는 테스트 메서드입니다.

ZScoreTest.java

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

3.3.3.3 실행 결과 확인하기

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

./gradlew :recommender-examples:test --tests com.r4tings.recommender.examples.ch03.ZScoreTest.zScoreExamples

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

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

테스트 인자 목록

구분 데이터 경로 그룹 상세출력 사용자 아이템 정규화된 평점
전체 Z점수화 dataset/r4tings/ratings.parquet true $u_4$ $i_1$ 0
사용자 Z점수화 dataset/r4tings/ratings.parquet USER true $u_4$ $i_1$ -0.2122382
아이템 Z점수화 dataset/r4tings/ratings.parquet ITEM true $u_4$ $i_1$ 0.5773503

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

예제 코드 실행 결과더보기

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

3.3.3.4 R 패키지로 확인해보기

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

ZScoreTest.R

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

Tip:

R 패키지 recommenderlab의 normalize 함수는 사용자 또는 아이템의 평점을 Z점수화 하는 정규화만 지원됩니다.

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

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

이 실행 결과에서 볼 수 있듯이 ❶ 사용자 Z점수화와 ❷ 아이템 Z점수화 결과를 확인할 수 있습니다. 또한, 실행 결과가 "직접 계산하기"의 계산 결과와 같음을 확인할 수 있습니다.

한글:3915 영어:4055 숫자:1622

추천 시스템: 워크북

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.