카테고리 없음

인기를 정의하면 공식이 보인다

kimong 2026. 4. 9. 23:58

 

이번 과제 요구사항에 인기 상품 랭킹 만들기 라는 요구사항이 있었다
 
처음에는 공식부터 고르면 되는 줄 알았다. 그래서 주문된 상품 갯수를 기준으로 사용할지, 매출을 사용할지 , 합쳐서 사용할지 정하기만 하면 끝이라고 생각했다.

그런데 같은 데이터를 넣어보니 공식마다 1위가 달랐다.
볼펜이 1위가 되기도 했고, 명품백이 1위가 되기도 했다.
 
멘토링 시간에도 인기라는 정의를 우선하고 코드를 구현하는 것이다 라는 멘토님의 조언처럼
랭킹 공식은 먼저 고르는 것이 아니었다. 우리 서비스에서 인기를 무엇으로 볼지 정해야 공식도 정할 수 있었다.

 

1. 세 가지 인기의 정의

 
공식을 고르기 전에 먼저 정의부터 나누고, 실험을 했다.

실제 내 프로젝트에서는 세 가지 이벤트가 랭킹 점수에 기여하는데, 주문 이벤트의 weight는 0.7로 설정하였기 때문에 실험도 동일하게 0.7로 하였다   

 

정의 A) 많은 사람이 선택한 상품이 인기 상품이다

100명이 각자 1개씩 구매한 상품이, 1명이 100개를 한 번에 구매한 상품보다 더 인기 있다고 본다.
중요한 것은 구매 금액이 아니라 독립적인 선택의 수다.

double f1(int quantity) {
    return 0.7 * Math.log1p(quantity);
}

 
여기서 log1p를 쓴 이유가 있다. 수량에 단순 선형 가중치를 쓰면 대량 구매 1건이 랭킹을 독점할 수 있다. log1p는 수량이 늘어날수록 점수 증가폭을 줄여준다.
 

수량점수직전 대비 증가율
10.49-
101.683.46x
1003.231.92.x
1,0004.841.50x
100,0008.061.25x

 
수량이 100,000배 늘어나도 점수는 16.6배 정도만 오른다. 대량 주문의 영향은 인정하되, 과도하게 반영되지는 않는다. 덕분에 F1은 "다수의 독립적인 선택"을 더 강한 신호로 보려는 정의 A의 의도를 유지할 수 있다.
 

정의 B) 매출이 높은 상품이 인기 상품이다

비즈니스 기여도가 곧 인기다.
1개에 200만원짜리나 1,000개에 2천원짜리나 총 매출이 같으면 같은 인기다.

double f2(int quantity, int price) {
    return 0.7 * Math.log1p((long) quantity * price);
}

 

정의 C) 고가 상품도 공정하게 경쟁해야 한다

명품백 1개를 판 것과 볼펜 1,000개를 판 것은 다르다.
가격대가 높은 상품에도 별도의 존재감을 인정해줘야 한다.

double f3(int quantity, int price) {
    return 0.7 * (Math.log1p(quantity) + Math.log1p(price));
}

 

세 정의 모두 논리적이다.
문제는 같은 데이터에서도 결과가 달라진다는 점이다.

 

 


 
 

2. 실험

실험 1 : 같은 매출인데 1위가 바뀐다

세 공식이 얼마나 다른 결과를 내는지 먼저 확인했다.
 
이번에는 총 매출이 같은 조건을 골랐다. 매출이 같으면 비즈니스 기여도가 동등한 상품들이다. 이 상품들을 세 공식에 넣었을 때 1위가 달라진다면, 그건 "공식은 중립적이지 않다"는 증거가 된다.

상품수량단가총 매출
명품백1개2,000,000원2,000,000원
노트북2개1,000,000원2,000,000원
운동화10개200,000원2,000,000원
100개20,000원2,000,000원
볼펜1,000개2,000원2,000,000원

 

상품F1 (수량)F2 (매출)F3 (혼합)
명품백0.4910.1610.64
노트북0.7710.1610.44
운동화1.6810.1610.22
3.2310.1610.16
볼펜4.8410.1610.16

 
랭킹은 이렇게 갈렸다.

  • F1 : 볼펜 > 책 > 운동화 > 노트북 > 명품백
  • F2 : 전부 동점
  • F3 : 명품백 > 노트북 > 운동화 > 책 > 볼펜

같은 200만원 매출인데, 공식 하나 바꿨더니 꼴찌가 1위가 됐다.
F2가 전부 동점인 이유는 수식을 보면 바로 보인다.
log1p(quantity × price)는 quantity × price가 모두 200만으로 같으니 결과도 같다.
즉, F2는 "총 매출이 같으면 같은 인기"라는 정의를 그대로 구현한 것이고, 얼마짜리를 몇 개 팔았는지는 관심이 없다. 
 
공식은 중립적이지 않다. 각 공식은 각기 다른 인기의 정의를 반영한다
 
 
 

실험 2 : F1은 정의 A의 의도대로 동작하는가?

실험1에서 공식마다 결과가 다르다는 걸 확인했다. 그렇다면 우리가 선택하려는 F1이 실제로 정의 A의 의도대로 동작하는지 확인해야한다. 
정의 A는 "많은 사람이 독립적으로 선택한 상품이 인기 상품"이라 봤다. 총 판매량은 같지만 주문 패턴이 다른 세 상품을 F1에 넣어봤다.

  • 상품 A: 1명이 100개를 한 번에 주문
  • 상품 B: 10명이 10개씩 주문
  • 상품 C: 100명이 1개씩 주문

총 판매량은 모두 100개로 같다. F1에 넣으면 점수는 이렇게 나온다.

double scoreA = f1(100);       // 1건 × 100개
double scoreB = 10 * f1(10);   // 10건 × 10개
double scoreC = 100 * f1(1);   // 100건 × 1개

 

상품점수
A (1건 x 100개)3.2점
B (10건 x 10개)16.8점
C (100건 x 1개)48.5점

 
같은 100개인데도, C가 A보다 15배 높다.
 
100명이 각자 선택한 상품이 1명이 대량 구매한 상품보다 훨씬 높은 점수를 받는다. F1은 정의 A의 의도대로 동작한다.
 
단, B2B처럼 대량 구매 자체가 핵심인 서비스라면 이야기가 달라진다. 그 경우에는 F1이 아니라 선형 수량 공식이 더 맞을 수도 있다.
 
 
 

실험 3: 현실 데이터에서도 공식마다 순위가 갈리는가?

앞의 실험들은 "매출만 같게" 같은 통제된 조건을 썼다. 하지만 현실에서는 상품마다 주문 건수도 다르고, 건당 수량도 다르고, 가격도 다르다. 
 
아래는 하루 주문 패턴을 가정해서 직접 구성한 가상 데이터다.

상품주문건수건당 수량단가F1F2F3
명품시계2건1개5,000,000원0.9721.5922.56
노트북4건1개1,500,000원1.9439.8241.76
커피머신6건1개500,000원2.9155.1158.03
운동화8건1개150,000원3.8866.7470.62
사무용품박스5건50개3,000원13.7641.7141.78
티셔츠20건2개50,000원15.38161.18166.86
30건1개20,000원14.55208.17222.53

 
랭킹 결과 

  • F1 : 티셔츠 > 책 > 사무용품박스 > 운동화 > 커피머신 > 노트북 > 명품시계
  • F2 : 책 > 티셔츠 > 운동화 > 커피머신 > 사무용품박스 > 노트북 > 명품시계
  • F3 : 책 > 티셔츠 > 운동화 > 커피머신 > 사무용품박스 > 노트북 > 명품시계

이 표에서 보인 건 세 가지다.

1) 티셔츠와 책은 공식에 따라 1위가 바뀐다

책은 주문 30건, 티셔츠는 주문 20건이다. 이벤트 수만 보면 책이 더 강하다.
그런데 F1에서는 티셔츠가 1위다. 건당 2개라는 수량이 반영되기 때문이다.
반대로 F2와 F3에서는 책이 다시 1위가 된다.

2) 사무용품박스는 수량 중심 공식의 성격을 보여준다

사무용품박스는 F1에서 3위지만, F2와 F3에서는 5위로 내려간다.
1건에 50개씩 팔리기 때문에 수량 기반 공식에서는 강하지만, 매출과 가격을 함께 보기 시작하면 힘이 빠진다.
즉, F1은 “많이 담긴 주문”에 반응하고, F2/F3는 “얼마의 가치가 팔렸는가”에 더 민감하다.

3) 명품시계는 공식보다 비교 기준의 한계를 드러낸다

명품시계는 단가가 가장 높지만 세 공식 모두에서 꼴찌다.
이건 공식이 틀렸다기보다, 카테고리 맥락 없이 상품을 같은 기준으로 비교한 한계에 가깝다.
책 30건과 명품시계 2건은 숫자로는 비교되지만, 실제 비즈니스 의미는 같지 않을 수 있다.
 
 


 
 

3. 그래서 어떤 정의를 골랐나

정의를 다시 표로 정리하면 이렇다.

목표공식이유
많은 사람이 선택한 상품F1: log1p(quantity)주문 횟수 누적 = 다수 고객 신호
매출 기여도 기준F2: log1p(quantity × price)총 매출이 같으면 동등하게 취급
가격대 다양성 보장F3: log1p(q) + log1p(p)고가 소량 상품도 경쟁 가능
B2B 대량 구매선형 quantity단일 대량 주문에 충분한 가중치 필요

 
나는 F1을 골랐다.
이 서비스는 일반 소비자가 대상인 커머스라고 가정하고 개발 했기 때문이다.
여기서 인기 상품이란 "많은 사람이 독립적으로 선택한 상품" 이어야한다. 1명이 대량 구매한 상품보다, 여러 사람이 각자 골라간 상품이 더 많은 사람에게 의미있는 추천이 된다. 
 
정의를 먼저 택했고, 공식은 그 정의를 구현한 결과였다.
그리고 log1p는 그 정의가 대량 구매에 의해 왜곡되지 않도록 지켜주는 장치였다.
 
 


 
 

4. 마치며

이번에 얻은 결론은 단순하다.
랭킹 공식은 수학 문제가 아니었다. 정의를 먼저 정하고, 공식은 그 정의를 구현하는 것이다. log1p 조차도 수학적 선택이 아니라, "대량 구매가 랭킹을 왜곡하지 않아야한다"는 정의를 지키기 위한 장치였다.
 
공식 선택 전에 먼저 해야할 질문은 이것이다.

우리 서비스에서 인기란 무엇인가?

 
정의가 바뀌면 공식도 바뀌어야 한다.
그리고 바꾸기 전에, 실제 데이터에 넣어보고 어떤 결과가 나오는지 먼저 확인해야 한다.