패션 아이템의 특성 태그 기반 유사도 측정 #노드분류


현재 사용할 수 있는 데이터는 유저가 like, dislike 한 상품 번호, 구매한 상품 번호, 상품 디테일 페이지를 view 한 이력 이다.

그런데 이 데이터만 가지고는 상품마다 주어진 unique id 값을 단순 비교하는 작업 이외에는 도출할 수 있는 결과가 없다.

전형적인 사용자 유사도를 이용한 협력 필터링은
1. 유저 사이의 유사도를 뽑아내
2. A라는 유저와 비슷한 B 유저가 like 하거나, 구매하거나,열람한 상품 중 A유저가 구매하지 않은 상품의 리스트를 뽑고
3. 이 리스트를 유저간 유사도로 가중치를 주어 sorting 하는 것이다.

이 간단한 접근의 단점은 결과가 편향 된다는 점이다. 일부 상품이 계속 추천 리스트 안에 들어가게 되고 결국 추천의 질은 낮아지게 된다.

뿐만 아니라 패션 쪽의 특성 상 상품이 주기적으로(꽤 빠르게) 바뀐다. 그래서 3개월 이상 가입 시점이 차이나는 유저끼리는 상품의 단순 비교로는 유사도를 측정할 수가 없다.

그래서 상품별로 특성(설명)을 태그 기반으로 하고, 이를 비교하여 상품 별로 유사도를 측정하며, 유저간 유사도도 상품별 유사도를 토대로 도출하는 방식을 고려해본다.


이런 식으로 이 상품은 30대의 여자가 신기 좋은, 여성스럽고 우아한 분위기의 신발인 것이다.

각각의 상품에 대해 이러한 태그 tree 가 존재할 때 좋은 점은 유사도 비교를 하는데 쓰이는 연산 속도가 상대적으로 빠르고 다양한 상품, 태그에 적용할 수 있도록 확장성을 가질 수 있다는 점이다.

아래와 같은 두 상품이 존재할 때, 이 두 상품의 태그는 다음과 같이 표현할 수 있다.


상품 A

상품 B


상품 A의 경우 DB에 저장될때는 20대, 여, 우아한 의 키 값이 저장되고
상품 B의 경우 DB에 저장될 때 30대,  여성스러움, 우아한 이 저장된다.

먼저 각 leaf의 키값을 가지고 부모들을 이어 트리를 구성해준다.

상품 A 트리(총 노드 8개)
상품 B 트리 (총 노드 7개)

두 트리를 비교하여 유사도를 찾아내는 방법 중 가장 간단한 것은 n(교집합) / n(합집합) 일 것이다. 이 경우 5/15 이므로 33.3% 가 나오게 된다.

그러나 트리의 깊이가 깊어질 수록 상품의 '상세' 특성에 가까워진다고 가정할 때, 깊이에 따라 공통되는 태그의 가중치를 달리해야한다는 결론이 나온다(A,B 두 상품 모두 연령대 태그를 가지고 있기 때문에 연령대, 사용자 부모 태그가 겹친다.). 하지만 깊이가 깊은 leaf 노드가 겹친다고 해서 이 것이 상품의 전반적인 '느낌' 이나 유저의 전반적인 '취향' 을 대변한다고 볼 수는 없다.

따라서 깊이가 깊어진다고 해서 가중치가 커져서만도 안되며 깊이가 얕다고 가중치가 작아져서만도 안된다.

그렇다면 가중치는 어떻게 산정해야 하는가.

어떤 특정 노드가 '전반적인 느낌' 을 대표하는지 알 수 있을까.

이 부분에 대해 몇가지 가정을 세우고 진행해보려한다.

1. 지금은 두 상품만 놓고 비교를 하고 있지만, 상품의 개수가 많아진다면 전체 상품에서 유난히 많이 겹치는? 노드를 찾을 수 있을 것이다. 이 노드들은 사용자, 분위기 등, 하위 태그들을 묶어주는 '목차' 의 역할을 하는 노드들일 것이다. 즉 상품의 특성을 표현하지 않는다.
이 같은 태그들은 낮은 가중치를 받는 것이 옳다.

2. 위에서 찾은 많이 겹치는 노드들을 제외한 노드는 상품의 특성을 표현하고 있을 확률이 높은 것으로 판단할 수 있는데 이 노드들은 깊이가 깊어질 수록 상품의 상세 특성을 나타내며 깊이가 얕아질수록 상품의 전반적인 특성을 나타낸다고 볼 수 있다.

이를 통해 나온 결론은 다음과 같다.

1. 노드의 가중치 값은 상품마다 바뀌지 않고 전체 태그 트리에 귀속되어 고정된다.

2. 목차 노드를 제외한 노드들은 태그에 따라 그 절대 깊이가 각각 다를 테니 root부터의 깊이를 기준으로 가중치를 매긴다면 일부 태그는 가중치에 있어 손해를 입을 확률이 높다. 따라서 상대 깊이를 기준으로 가중치를 매겨야하는데, 그 기준은 parent node 중 가장 처음 나오는 '목차' 노드를 기준으로 하면 된다.


이제 새로 생긴 문제는 어떤 기준으로 '목차' 의 역할을 하는 노드를 가려낼 것인가 이다.
만약  겹치는 횟수가 전체 상품개수 대비 80% 이상 과 같은 특정 수치로 판단하게 된다면 몇가지 문제가 생긴다.

지금 슈가진의 경우 모든 신발이 여성화이기 때문에 위의 트리에서 사용자 => 성별 => 여 의 태그가 모든 상품에 들어가 있게 된다. 이 경우 '여' 노드가  목차의 역할을 하는 노드는 아니지만 가중치에 있어 낮은 가중치로 들어가야하는 점이 생긴다. 즉 위의 방법으로 겹치는 노드를 판단하게 되면 '목차' 이외에도 전체 상품에 공통적으로 적용되는 특성을 나타내는 노드가 섞이게 된다.

이는 매우 옳지 않은데, 추후 남성화가 들어올 경우 여자 성별 태그에 대한 노드가 '목차'화 되어 버리면 어찌보면 가장 중요한 특성이라고 볼 수 있는 성별이 낮은 가중치로 인해 무시될 것이기 때문이다.

따라서 '목차' 노드를 가려내는데는 다른 방법이 필요하다.

의외로 간단한 방법이 떠올랐는데

겹치는 횟수가 전체 상품개수 대비 80% 이상 과 같은 특정 수치로 판단 하되,

1. 여성, 남성과 같은 leaf 노드의 태그들의 경우에만 (children이 없을 경우에) 는 목차 태그에서 제외시키고
또는
2. 부모 노드가 '목차'노드가 아닐 경우에는 제외시킨다.

라는 예외 로직을 넣게 된다면 일단은 위의 문제가 해결될 수 있을 것 같다.
(이로서 '목차' 노드는 root 에서 부터 끊김 없이 아래로 연결된다. 트리의 중간에 '목차' 노드가 갑자기 끼어있게 되는 경우는 존재하지 않는다)

정리
1. 아이템 별로, 전체 태그 tree의 일부 leaf node 들을 특성으로 갖는다.
2. 태그 tree 안의 노드들은 '목차' 노드,  '특성' 노드로 나누어 진다.
3.  '목차' 노드는 최저 가중치를 갖거나, 가중치를 갖지 않는다.
4. '특성' 노드의 가중치는 lowest common ancestor 방식으로  '목차' 노드를 찾은 후, 그 높이를 기준으로 상대 높이에 비례한다. 


다음엔 태그의 가중치에 대해 썰을 풀어보고자 한다.

다음 글

댓글