TIL (Today I Learn)

TIL [내배캠] 78일차

dataguard 2025. 6. 11. 21:45
최종 프로젝트 : 결측치 보완 2
다른 결측치들도 무난하게 잘 채워 가는 듯 했다.
하지만, 지금까지 계속 발목을 잡았던 카테고리가 이번에도 문제였다.

 

leafCategoryIds 결측치

eaf_category 가 각 row마다 쪼개서 나온 (depth 기준) 최하위 category_id 를
leaf_category로 가져오는 바람에 L2, L3, L6 등 다 혼재되어 있음

df['leafCategoryId_1'].value_counts() >>> 11,086

 

  • 해결 시도
    • leafCategoryId_1 탐색 시작
      • 같은 id (100979)인데도 이름이 다 다르게 나와서 의문을 가짐 → 이름 추출했던 코드 다시 뜯어보기 시작
      • # 리프 카테고리 이름 추출 def get_leaf_names(categories, leaf_ids): return [ cat["categoryName"] for cat in categories if cat.get("categoryId") in leaf_ids ] df["leaf_category_names"] = df.apply( lambda row: get_leaf_names(row["categories"], row["leafCategoryIds"]), axis=1 )
      • df[['leafCategoryId_1','leaf_category_names']].value_counts()
  • 이유 & 해결 방안
    • leafCategoryIds 에서 이름을 추출할 때, leafCategoryIds리스트에 있는 모든 이름을 가져옴
      • Gifts만 나오게 하는 것을 목표로 코드 제작
        • 이름 추출할 코드를 leafCategoryIds가 아닌 분리한 leafCategoryId_1에서 추출
        • categories컬럼에서 이름을 추출해야 하기 때문에, categories 컬럼을 복원
        import ast
        
        df1['categories'] = df1['categories'].apply(lambda x: ast.literal_eval(x) if isinstance(x, str) else x)
        
        def extract_leaf_category_name(row):
            try:
                if isinstance(row['categories'], list):
                    for cat in row['categories']:
                        if str(cat.get('categoryId')) == str(row['leafCategoryId_1']):
                            return cat.get('categoryName')
            except:
                pass
            return None
        
        df1['leafCategoryName'] = df1.apply(extract_leaf_category_name, axis=1)
        
    • Ex) Gifts, [Gifts, Baby Jewellery] , [Gifts, Baby Showers], ….
  • 새로운 문제 발생
    • leafCategoryId_1 는 같지만, leafCategoryName 이 다름
    • 국가별로 다르게 정의 되어있는 카테고리 이름 때문인 것으로 추측
    • US의 leafCategoryId 를 기반으로 다시 정리 해보자!
      • 1차 시도
        • leafCategoryId의 최빈값을 기준으로 이름 선택하기
        • 최빈값이 US가 아닐 확률이 있어, 위험성 존재
        # 1. ID 기준으로 가장 많이 쓰인 이름만 남김
        id_to_name = (
            df.groupby(["leafCategoryId_1", "leafCategoryName"])
            .size()
            .reset_index(name="count")
            .sort_values(["leafCategoryId_1", "count"], ascending=[True, False])
            .drop_duplicates("leafCategoryId_1")  # ID 기준으로 대표 name 하나만
        )
        
        # 2. 대표 이름 기준으로 df에 다시 붙이기
        df = df.drop(columns=["leafCategoryName"], errors='ignore')  # 혹시 기존 컬럼 있으면 삭제
        df = df.merge(id_to_name[["leafCategoryId_1", "leafCategoryName"]], on="leafCategoryId_1", how="left")
        
      • 2차 시도
        • US 데이터를 기준으로 최빈값의 이름 선택하기
        • leafCategoryId의 고유값도 같이 감소해서 원인파악 필요
        # 먼저 US 데이터만 필터링
        df_us = df[df['listingMarketplaceId'] == 'EBAY_US'].copy()
        # US 데이터 기준으로 ID별 최빈 이름 구하기
        id_to_name_us = (
            df_us.groupby(["leafCategoryId_1", "leafCategoryName"])
            .size()
            .reset_index(name="count")
            .sort_values(["leafCategoryId_1", "count"], ascending=[True, False])
            .drop_duplicates("leafCategoryId_1")  # ID 기준으로 대표 name 하나만
        )
        # 기존 컬럼 삭제 후 merge (전체 df 기준으로 merge → US 기준 대표 name 사용)
        df = df.drop(columns=["leafCategoryName"], errors='ignore')
        df = df.merge(id_to_name_us[["leafCategoryId_1", "leafCategoryName"]], on="leafCategoryId_1", how="left")
        

 

 

'TIL (Today I Learn)' 카테고리의 다른 글

TIL [내배캠] 80일차  (0) 2025.06.13
TIL [내배캠] 79일차  (1) 2025.06.12
TIL [내배캠] 77일차  (0) 2025.06.10
TIL [내배캠] 76일차  (0) 2025.06.09
TIL [내배캠] 75일차  (1) 2025.06.05