!apt-get -qq install -y fonts-nanum
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
# 시스템에 설치된 나눔고딕 경로 확인
font_paths = fm.findSystemFonts(fontpaths=['/usr/share/fonts/truetype/nanum'])
nanumgothic_path = [f for f in font_paths if 'NanumGothic.ttf' in f][0]
# 해당 경로를 matplotlib에 수동 지정
fontprop = fm.FontProperties(fname=nanumgothic_path)
plt.rcParams['axes.unicode_minus'] = False
from collections import Counter
from google.colab import drive
drive.mount('/content/drive')
# 데이터 불러오기
df = pd.read_csv('/content/drive/MyDrive/h&m_dataset/data.csv')
# 상품별 판매량 집계
product_counts = df['prod_name'].value_counts()
# 상위 10개 상품 선택
top10 = product_counts.head(10).index.tolist()
top10_print = product_counts.head(10)
# top 10 출력
for product, count in top10_print.items():
print(f"{product} : {count}개")
# 추천 세트 저장할 리스트
bundle_sets = []
# 함수: 연관 상품 찾기
def find_bundle(base_product):
# 해당 상품 구매자 ID 목록
buyers = df[df['prod_name'] == base_product]['customer_id'].unique()
# 그 사람들이 산 다른 상품
other = df[
(df['customer_id'].isin(buyers)) &
(df['prod_name'] != base_product)
]
counter = Counter(other['prod_name'])
if counter:
best_match, match_count = counter.most_common(1)[0]
else:
best_match, match_count = None, 0
return best_match, match_count
# 루프 돌면서 base 상품과 연관 상품 + 판매량 함께 저장
used_products = set() # 이미 세트에 사용된 상품 추적용
for base in top10:
base_count = product_counts[base]
if base in used_products:
continue # 이미 세트에 포함된 상품은 스킵
# base 상품을 산 고객들
buyers = df[df['prod_name'] == base]['customer_id'].unique()
# 그 고객들이 산 다른 상품 (base 제외, used 제외)
other = df[
(df['customer_id'].isin(buyers)) &
(df['prod_name'] != base) &
(~df['prod_name'].isin(used_products))
]
counter = Counter(other['prod_name'])
if counter:
bundle_product, bundle_count = counter.most_common(1)[0]
else:
bundle_product, bundle_count = None, 0
bundle_sets.append({
'base_product': base,
'base_count': base_count,
'bundle_product': bundle_product,
'bundle_count': bundle_count
})
# 사용된 상품 등록
used_products.add(base)
if bundle_product:
used_products.add(bundle_product)
# 출력
for row in bundle_sets:
print(f"{row['base_product']} ({row['base_count']}개 팔림) → {row['bundle_product']} ({row['bundle_count']}개 팔림)")
# FN + Active 모두 동의한 유저만 추출
df_agree = df[(df['FN'] == 1) & (df['Active'] == 1)].copy()
# 나이대 생성
df_agree['age_group'] = (df_agree['age'] // 10 * 10).astype(int)
df_agree = df_agree[df_agree['age_group'].between(10, 90)]
# 날짜 변환 + 계절 생성
df_agree['t_dat'] = pd.to_datetime(df_agree['t_dat'])
def get_season(month):
if month in [3, 4, 5]: return '봄'
elif month in [6, 7, 8]: return '여름'
elif month in [9, 10, 11]: return '가을'
else: return '겨울'
df_agree['season'] = df_agree['t_dat'].dt.month.apply(get_season)
# 결과 저장
results = []
# 나이대, 계절 조합별 Top5 상품코드 + 판매량
for age in range(10, 100, 10):
for season in ['봄', '여름', '가을', '겨울']:
subset = df_agree[(df_agree['age_group'] == age) & (df_agree['season'] == season)]
vc = subset['product_code'].value_counts().head(5)
top5 = list(zip(vc.index.tolist(), vc.values.tolist())) # (코드, 수량)
results.append({
'나이대': f"{age}대",
'계절': season,
'Top5': top5
})
# 출력
for row in results:
print(f"{row['나이대']} {row['계절']} Top5 상품코드:")
for code, count in row['Top5']:
print(f"- {code} ({count}개)")
print()
# 상품코드 -> 상품명으로 변경
# 상품명 매핑 딕셔너리 만들기 중복 제거
code_to_name = df[['product_code', 'prod_name']].drop_duplicates().set_index('product_code')['prod_name'].to_dict()
# 결과 저장
results_name = []
# 나이대, 계절 조합별 Top1 상품코드 추출
for age in range(10, 100, 10):
for season in ['봄', '여름', '가을', '겨울']:
subset = df_agree[(df_agree['age_group'] == age) & (df_agree['season'] == season)]
vc = subset['product_code'].value_counts().head(1)
top1 = list(zip(vc.index.tolist(), vc.values.tolist())) # (상품코드, 판매량)
results_name.append({
'나이대': f"{age}대",
'계절': season,
'Top1': top1
})
# 출력
for row in results_name:
print(f"{row['나이대']} {row['계절']} best 상품:")
for code, count in row['Top1']:
name = code_to_name.get(code, "(상품명 없음)")
print(f"- {name} ({code}) : {count}개")
print()
plot_data = []
for row in results_name:
age = row['나이대']
season = row['계절']
for code, count in row['Top1']:
name = code_to_name.get(code, "(상품명 없음)")
label = f"{age} {season}"
plot_data.append({
'label': label,
'count': count,
'product_name': name
})
plot_df = pd.DataFrame(plot_data)
# 시각화
plt.figure(figsize=(12, 18))
bars = plt.barh(plot_df['label'], plot_df['count'], color='cornflowerblue')
for bar, name, count in zip(bars, plot_df['product_name'], plot_df['count']):
width = bar.get_width()
label = f"{name} ({count}개)"
plt.text(width + 3, bar.get_y() + bar.get_height()/2, label,
va='center', ha='left', fontsize=8, fontproperties=fontprop)
plt.title('연령대, 계절별 best 상품명 (판매량 포함)', fontproperties=fontprop)
plt.xlabel('판매량', fontproperties=fontprop)
plt.ylabel('연령대 + 계절', fontproperties=fontprop)
plt.yticks(fontproperties=fontprop)
plt.tight_layout()
plt.show()
vc2 = df_agree['product_code'].value_counts().head(10) # top10 기준, 숫자 조정 가능
# 결과 출력
print("열혈유저 기준 Top10 인기 상품:")
for code, count in vc2.items():
name = code_to_name.get(code, "(상품명 없음)")
print(f"- {name} ({code}) : {count}개")