[팀플] 기초프로젝트 시각화

신운홍·2025년 6월 17일

팀플

목록 보기
5/7
!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}개")

0개의 댓글