1. ํ์ฉ ๋ฐ์ดํฐ
1-1. ๋ฐ์ดํฐ : Olist ๋ฐ์ดํฐ(์ถ์ฒ : kaggle)

Olist(์ฌ๋ฆฌ์คํธ)๋ ๋ธ๋ผ์ง์ ์ด์ปค๋จธ์ค ํ๋ซํผ์ผ๋ก, ํ๋งค์(๋ธ๋๋)๊ฐ ์ํ์ ์จ๋ผ์ธ ๋ง์ผํ๋ ์ด์ค์ ํ๋งคํ ์ ์๋๋ก ์ ํต ์๋ฃจ์ (์ํ ๋ฑ๋ก, ๋ฌผ๋ฅ, ๊ณ ๊ฐ ์๋ ๋ฑ)์ ์ ๊ณตํ๋ค.
1-2. ๋ฐ์ดํฐ ์คํค๋ง

๊ฐ ๋ฐ์ดํฐ ํน์ฑ์ ๋ฐ๋ผ ์ฃผ๋ฌธ ์์ด๋(order_id), ๊ณ ๊ฐ ์์ด๋(customer_id) ๋ฑ์ ์ด์ฉํด ์ฐธ์กฐ๊ฐ ๊ฐ๋ฅํ๋ค.
1-3. ๋ฐ์ดํฐ ์ปฌ๋ผ ์ ๋ณด

* ์ด ์ด๋ฆ ์คํ ์์
- products ๋ฐ์ดํฐ์ product_name_leng'ht' -> product_name_leng'th'
- products ๋ฐ์ดํฐ์ product_description_leng'ht' -> product_description_leng'th'
2. ๋์๋ณด๋ ์ค๊ณ
2-1. ์ฃผ์ ์ ์
๋ถ์์ ์ํํ๊ธฐ ์ ๋์๋ณด๋๋ฅผ ์ค๊ณํ์ฌ ์ด๋ค ๋ถ๋ถ์ ์ค์ ์ผ๋ก ๋ถ์ํ ์ง ๋ฐฉํฅ์ ์ ํ๋ค.

์ฐ์ ๋ฐ์ดํฐ๊ฐ ์ฃผ๋ก ํ๋งค ํํฉ์ ๋ค๋ฃจ๊ณ ์๊ธฐ์ ๋งค์ถ ๋ถ์์ด๋ผ๋ ํฐ ์ฃผ์ ๋ฅผ ์ก๊ณ , ์ธ๋ถ ์ฃผ์ ๋ฅผ ์๋์ ๊ฐ์ด ์ ์ ํ๋ค.
- ์ ํ ์นดํ ๊ณ ๋ฆฌ๋ณ ๋งค์ถ
- ์๋ณ ๋งค์ถ
- ๊ณ ๊ฐ ๋ฑ๊ธ๋ณ ๋งค์ถ
- ์ง์ญ๋ณ ๋งค์ถ(๋ํ, ๋งต)
2-2. ์์
๋์๋ณด๋์ ํฌ์ธํธ ์ปฌ๋ฌ๋ olist์ ๋ก๊ณ ์์์ ํ์ฉํ์๋ค.

3. ๋ฐ์ดํฐ ๋ถ์
์ค์ ๊ณ ๊ฐ ์ ํ์ธ

customers ๋ฐ์ดํฐ ์ค customer_id๋ ์ฃผ๋ฌธ ๋น์ ๊ตฌ๋งค์์๊ฒ ๋ฐ๊ธ๋๋ id๋ก, ๊ฐ์ customer_unique_id๋ฅผ ๊ฐ์ง ๊ณ ๊ฐ์ด๋ผ ํด๋ customer_id๋ฅผ ์ฌ๋ฌ ๊ฐ๋ฅผ ๊ฐ์ง ์ ์๋ค.

์ค์ ๊ณ ๊ฐ์ ์๋ 96,096๋ช ์ผ๋ก ์ถ์ ํ ์ ์๋ค.
์ฃผ(state) ๋งคํ

๋ธ๋ผ์ง์ 27๊ฐ ์ฃผ(state)๊ฐ ์ฝ์ด๋ก ๋์ด ์์ด ๋์๋ณด๋ ์์์ ๊ตฌ๋ถ์ด ์ด๋ ค์ธ ๊ฒ ๊ฐ์ ์ฝ์ด๋ฅผ ํ์ด ์ ์ฉํ๋ค.
state_mapping = {
'SP': 'Sao Paulo',
'SC': 'Santa Catarina',
'MG': 'Minas Gerais',
'PR': 'Parana',
'RJ': 'Rio de Janeiro',
'RS': 'Rio Grande do Sul',
'PA': 'Para',
'GO': 'Goias',
'ES': 'Espirito Santo',
'BA': 'Bahia',
'MA': 'Maranhao',
'MS': 'Mato Grosso do Sul',
'CE': 'Ceara',
'DF': 'Distrito Federal',
'RN': 'Rio Grande do Norte',
'PE': 'Pernambuco',
'MT': 'Mato Grosso',
'AM': 'Amazonas',
'AP': 'Amapa',
'AL': 'Alagoas',
'RO': 'Rondonia',
'PB': 'Paraiba',
'TO': 'Tocantins',
'PI': 'Piaui',
'AC': 'Acre',
'SE': 'Sergipe',
'RR': 'Roraima'
}
customers['customer_state'] = customers['customer_state'].map(state_mapping)
product_category_name ์๋ฌธ ๋ณํ

๊ธฐ์กด products ๋ฐ์ดํฐ์๋ product_category_name์ด ํฌ๋ฅดํฌ๊ฐ์ด๋ก ๋์ด ์๋ค.

product_category_name_translation ๋ฐ์ดํฐ๋ product_category_name์ด ํฌ๋ฅดํฌ๊ฐ์ด์ ์์ด๊ฐ ๋งคํ๋์ด ์์ด ์ด๋ฅผ ํ์ฉํ์ฌ ํฌ๋ฅดํฌ๊ฐ์ด๋ฅผ ์์ด๋ก ๋ณํํ๋ค.
# ๋์
๋๋ฆฌ๋ก ๋งคํ
category_dict = product_translation.set_index('product_category_name')['product_category_name_english']
# 2๋ฒ์งธ ์ธ๋ฑ์ค์ ์ถ๊ฐ
products.insert(2, 'product_category_name_english', products['product_category_name'].map(category_dict))

RFM
RFM์ด๋ ๊ณ ๊ฐ์ ์ต๊ทผ ๊ตฌ๋งค ์์ (Recency), ๊ตฌ๋งค ๋น๋(Frequency), ๊ตฌ๋งค ๊ธ์ก(Monetary)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ณ ๊ฐ์ ๋ถ๋ฅํ๊ณ ๋ถ์ํ๋ ๊ณ ๊ฐ ๊ฐ์น ๋ถ์ ๊ธฐ๋ฒ์ด๋ค.
- ๊ตฌ๋งค ์์ (Recency) : ๋ชจ๋ ์ฃผ๋ฌธ ์ผ์ ์ค ์ต๋๊ฐ - ํด๋น ๊ณ ๊ฐ์ ๋ง์ง๋ง ์ฃผ๋ฌธ ์ผ์(Day)
- ๊ตฌ๋งค ๋น๋(Frequency) : ๊ณ ๊ฐ๋ณ ๋์ ์ฃผ๋ฌธ ํ์
- ๊ตฌ๋งค ๊ธ์ก(Monetary) : ๊ณ ๊ฐ๋ณ ์ฃผ๋ฌธ ์ด์ก
์ฌ์ฉํ ๋ฐ์ดํฐ๋ ์๋์ ๊ฐ๋ค.
- orders : ์ฃผ๋ฌธ ID(order_id), ์ฃผ๋ฌธ ์ํ(order_status) ํฌํจ
- order_payments : ์ฃผ๋ฌธ๋ณ ๊ฒฐ์ ๋ด์ญ
- customers : ๊ณ ๊ฐ ๊ณ ์ ID(customer_unique_id), ์ฃผ๋ฌธ ๋น์ ๋ฐ๊ธ๋๋ ID(customer_id) ํฌํจ
๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ

orders์ order_payments ๋ฐ์ดํฐ๋ฅผ order_id๋ฅผ ๊ธฐ์ค์ผ๋ก ๋น๊ตํ ๊ฒฐ๊ณผ, orders์๋ ์์ง๋ง order_payments์๋ ์๋ order_id๊ฐ ์กด์ฌํ์ฌ ํด๋น ํ์ ์ ์ธํ์๋ค.

์ฃผ๋ฌธ ์ํ๊ฐ '๋ฐฐ์ก ์๋ฃ(order_status='delivered')'์ธ ์ฃผ๋ฌธ๋ง ๋์์ ํฌํจํ์๋ค.

๊ธฐ์กด orders ๋ฐ์ดํฐ์๋ ์ฃผ๋ฌธ ์ ๋ฐ๊ธ๋ customer_id๋ง ์กด์ฌํ๋ฏ๋ก, ๊ณ ๊ฐ๋ณ ์ฃผ๋ฌธ ๋ด์ญ์ ์ทจํฉํ๊ธฐ ์ํด customers์ orders๋ฅผ ์กฐ์ธํ์ฌ ๊ฐ ์ฃผ๋ฌธ์ ๊ณ ๊ฐ์ ๊ณ ์ ์๋ณ์(customer_unique_id) ๊ธฐ์ค์ผ๋ก ์ฌ๊ตฌ์ฑํ์๋ค.
RFM

Recency๋ ๋ชจ๋ ๊ณ ๊ฐ์ ๋ง์ง๋ง ๊ตฌ๋งค ์๊ฐ์์ ๊ณ ๊ฐ๋ณ ๋ง์ง๋ง ๊ตฌ๋งค ์๊ฐ์ ๋บ ์ผ์๋ก ๊ณ์ฐํ์๋ค.

Frequency๋ ๊ณ ๊ฐ๋ณ ๋์ ์ฃผ๋ฌธ ํ์๋ก ๊ณ์ฐํ์๋ค.

Monetary๋ ๊ณ ๊ฐ๋ณ ๋์ ์ฃผ๋ฌธ์ ๋ํ ์ด ๊ธ์ก์ผ๋ก ๊ณ์ฐํ์๋ค.
ํ ๋ฒ๋ ์ฃผ๋ฌธํ์ง ์์ ๊ณ ๊ฐ์ RFM ๋ถ์ ๋์์์ ์ ์ธํ์์ผ๋ฉฐ, 5์ ๋ง์ ๊ธฐ์ค์ผ๋ก ์์๋ณ ์ ์๋ฅผ ํ ๋นํ๊ธฐ ์ํด ๋ฐ์ดํฐ์ ๋ถํฌ๋ฅผ ํ์ธํ์๋ค.

1. Recency(๊ตฌ๋งค ์์ )
Recency์ ๊ฒฝ์ฐ ์๋์ ์ผ๋ก ๊ณ ๋ฅด๊ฒ ๋ถํฌ๋์ด ์ ์ ํ ๋น์ ๋ฐ๋ก ์งํํ์๋ค.
rfm_score = rfm.copy()
rfm_score['R_score'] = pd.qcut(rfm['Recency'], 5, labels=[5, 4, 3, 2, 1])
๊ฐ์ด ๋ฎ์์๋ก ์ต์ ์ฑ์ด๋ฏ๋ก ์ ์๋ฅผ ์ญ์์ผ๋ก ํ ๋นํ์๋ค.
2. Frequency(๊ตฌ๋งค ๋น๋)

Frequency์ ๊ฒฝ์ฐ 1ํ ๊ตฌ๋งค ๊ณ ๊ฐ์ด ๊ฐ์ฅ ๋ง์๊ณ , ์ฃผ๋ฌธ ํ์๊ฐ ๋ง์์๋ก ๊ณ ๊ฐ ์๋ ๊ฐ์ํ๋ ํจํด์ ํ์ธํ ์ ์์๋ค.
def score_frequency(freq):
if freq == 1:
return 1
elif freq == 2:
return 2
elif freq == 3:
return 3
elif freq == 4:
return 4
else:
return 5
rfm_score['F_score'] = rfm['Frequency'].apply(score_frequency)
1, 2, 3, 4, 5๋ฒ ์ด์์ผ๋ก ๊ตฌ๋ถํ์ฌ ์ ์๋ฅผ ํ ๋นํ์๋ค.
3. Monetary(๊ตฌ๋งค ๊ธ์ก)

Monetary์ ๊ฒฝ์ฐ ์ ์๋ณ ๊ธฐ์ค๊ฐ์ ์ ํ๊ธฐ ์ํด ์ฌ๋ถ์์๋ฅผ ํ์ธํ์๋ค.
def score_monetary(mone):
if mone < 20:
return 1
elif mone < 50:
return 2
elif mone < 100:
return 3
elif mone < 500:
return 4
else:
return 5
rfm_score['M_score'] = rfm['Monetary'].apply(score_monetary)
20 ๋ฏธ๋ง, 50 ๋ฏธ๋ง, 100 ๋ฏธ๋ง, 500 ๋ฏธ๋ง, 500 ์ด์์ผ๋ก ๊ตฌ๋ถํ์ฌ ์ ์๋ฅผ ํ ๋นํ์๋ค.
๊ณ ๊ฐ ๋ฑ๊ธ์ ์ ์ ์กฐํฉ์ ๋ฐ๋ผ ์ด 6๊ฐ๋ก ๋ถ๋ฅํ์๋ค.
- VIP ๊ณ ๊ฐ
- ์ถฉ์ฑ ๊ณ ๊ฐ
- ์ ์ฌ ์ถฉ์ฑ ๊ณ ๊ฐ
- ์ ๊ท ๊ณ ๊ฐ
- ์ ์ฌ ์ดํ ๊ณ ๊ฐ
- ์ดํ ๊ณ ๊ฐ

4. ๊ฒฐ๊ณผ

ํน์ ์ง์ญ์ ํด๋ฆญํ๋ฉด ํด๋น ์ง์ญ์ ๋ํ ๋ฐ์ดํฐ๋ง ๋์ค๋๋ก ์ง์ญ๋ณ ๋งค์ถ(๋งต)์ ํํฐ๋ก ์ค์ ํ์๋ค.
'๐ก ๋ฐ์ดํฐ ๋ถ์ ํ๋ก์ ํธ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| ๋ฐ์ดํฐ ๋ถ์ ํฌํธํด๋ฆฌ์ค (0) | 2025.12.21 |
|---|---|
| olist ๋์๋ณด๋ ์ ์ ํ๋ก์ ํธ โ (BigQuery / Looker Studio / Tableau) (0) | 2025.10.28 |
| [2024 ๋น ์ฝํ ์คํธ] ์์ธ์ธ๊ณ๋ถ๊ฝ์ถ์ ๋ฐฉ๋ฌธ๊ฐ ๋ถ์ (0) | 2024.10.22 |