[프로젝트 #4] 12월 05일(금) - TIL

전처리에 대한 끝없는 회의와 조인/머지를 어떻게 해야할지에 대한 논의 그리고 관점에 따라 조인을 달리하여 ERD를 그리는 작업 등등

 

오늘 진행 사항

  • 전처리에 대한 회의
  • 미사용 컬럼 선정 및 삭제
  • 결측치 있는 컬럼 처리 방법
  • 카테고리화 작업이 필요한 컬럼
  • 금액 컬럼 0 값의 의미에 대한 논의 
  • 조인키 컬럼명 알아보기 쉽도록 변경
  • 테이블 간 조인이나 머지에 대한 논의
  • 테이블 ERD 스케치 작업
  • 주말 동안 각자 해올 업무

▼ 튜터님 피드백

더보기
  • acquisitions 테이블
    • id
      • 내부 식별용이라 드랍
      • 그대로 진행해도 됨.
    • acquisition_id
      • 유지하는 거 좋음 (PK)
    • acquiring_object_id
      •  c_acquiring_object_id로 rename + int 변환
      • 다만, 이 값이 항상 c:(Company)인지 실제 데이터에서 한 번 꼭 확인 필요.
      • 혹시나 항상 c가 아니라면 프리픽스 정보는 다른 컬럼으로 보존 추천.
      • objects 테이블과 조인할 때 동일한 규칙으로 변환해야 함.
    • acquired_object_id
      • 위와 동일한 이슈. c_acquired_object_id 라고 이름 붙이는 건 실제로 모두 company일 때는 좋지만, 체크는 꼭 필요.
    • term_code (결측 80%)
      • 금액 분석 시엔 버리고, 건수 분석에는 유지
      • 합리적. 다만 완전히 드랍하기보단 EDA에서 “용어별 분포” 정도만 보는 용도로도 충분
    • price_amount (0이 73%)
      • float 유지 추천 (소수점 가능성 + 로그변환/단위 변환 유연성)
      • 0은 대부분 미공개/미제공으로 보는 게 자연스러우므로
        • price_amount == 0 -> NaN
        • is_price_disclosed 플래그 추가 추천
      • 굳이 직접 연도별 환율을 다시 계산할 필요까진..? 분석에 필요하다면 해야겠지만!
    • price_currency_code
      • price_amount_usd같은 통일된 컬럼을 하나 만들고 나면 drop 해도 무방
    • acquired_at
      •  datetime 변환, 연도 분석엔 결측 드랍, 그 외엔 유지
      • 추가로 acquired_year, acquired_quarter 파생변수 만드는 건 좋은 아이디어
    • source_url, source_description, created_at, updated_at
      • 보통 M&A 패턴 연구에서도 이런 텍스트/메타는 사용 안 하는 경우가 많아서 드랍해도 무방
 
  • degrees 테이블
    • id
      • 드랍 OK
    • object_id
      • object_id -> p_object_id + int 변환
      • 위에서 말한 object_id 공통 이슈 동일
      • relationships.person_object_id, people.object_id와 똑같은 방식으로 변환해야 함
      • Degrees는 사람이니까 무조건 p:다라고 가정하는 건 대체로 맞겠지만, 실제 데이터에서 prefix가 모두 p인지 한 번 확인하는 게 안전.
    • degree_type (결측 10.2%)
      • 전문 / 학사 / 석사 / 박사 / 기타 등으로 매핑, GPT로 분류 -> 좋은 아이디어
      • 다만, GPT로 분류한 후, 샘플링해서 수작업 검수를 추천 (완전 자동은 오분류 위험)
      • 모델용으로 쓸 땐 Degree_level(순서형) + is_degree_missing 플래그 정도로 단순화하면 좋음.
    • subject (전공, 결측 25.8%)
      • 창업 카테고리와 비교, GPT 활용 -> 흥미로운 feature
      • 다만 전처리 비용이 크니, 1차 분석에서는 상위 빈도 전공 몇 개만 카테고리화 후에 추가 작업을 해도 될 듯
    • institution (결측 거의 없음)
      • 아마 사용 안 할 듯 -> 1차 분석에서는 드랍해도 크게 아쉬울 것 없음
      • 향후 대학 랭킹/네트워크를 붙이고 싶다면 그때 보존해도 됨
    • graduated_at (결측 47%)
      • datetime 변환, 졸업연도가 중요할까 싶어서 그냥 냅두기 -> 동의
      • 다만, graduated_at이 null이면 degree_type도 null로 할까? -> 비추(정보 누락일 수도 있어서, 학위 없음으로 취급하면 오판 가능)
    • created_at, updated_at
      • 드랍 OK.
 
  • funding_rounds 테이블 
    • 이 테이블 전처리 계획이 제일 디테일하게 잘 되어있어요. 
    • id
      • 드랍 OK.
    • funding_round_id
      • PK로 유지
    • object_id
      • 투자받는 객체 ID (보통 company). FK로 유지하는 전략 OK.
      • 다만 앞서 말한 object_id 공통 처리 원칙 적용 필요.
    • funded_at
      • datetime 변환, 0.4% 결측은 NaT or 드랍
      • 일반 분석/모델용 테이블에서는 NaT로 두고, 연도/분기별 시계열 분석에서만 결측 라운드 제외하는 방식 추천
    • funding_round_type
      • 카테고리 변환 OK.
    • funding_round_code
      • type과 매핑 불일치가 있으니 사용 시 주의.
      • 코드가 깨끗이 정리되지 않는다면, 그냥 funding_round_type만 쓰고 이 컬럼은 드랍하는 것도 깔끔한 선택.
    • raised_amount_usd
      • 로그변환, 0값은 상황 따라 NaN으로 볼지 고민
      • 로그 변환 아이디어는 좋습니다.
      • 추천하는 룰
        • raised_amount_usd == 0 && 라운드 존재 → NaN + is_raised_disclosed=0
        • log_raised_amount = log1p(raised_amount_usd)로 처리
        • case 분류도 잘해놨으니, 그걸 이용해 비공개/진행중/에러 플래그 여러 개를 만드는 것도 좋아요.
    • raised_amount + raised_currency_code
      • dataset에 이미 raised_amount_usd가 있으니, USD 기준으로만 분석한다면 drop해도 OK.
    • pre_money_valuation_usd / post_money_valuation_usd
      • 99% 가까이 0 값이기 때문에, 0 -> NaN / is_valuation_disclosed 플래그 정도만 써도 충분할 수 있음.
      • 로그 변환은 NaN 아닌 값에만 적용.
      • raised_amount와 마찬가지로, 분석 단위를 USD로 통일한다면 드랍 추천.
    • participants
      • 이상치, 0값(투자자 정보 비공개/자기자본), 로그변환
      • 매우 좋음, 로그 변환 시 np.log1p(participants) 추천.
    • is_first_round, is_last_round
      • 그대로 사용, 특히 성공 예측 모델에서 중요 피처가 되곤 합니다.
    • source_url, source_description
      • 텍스트 정규화 + 결측 Unknown vs 드랍 고민
      • 텍스트 분석을 안 한다면 둘 다 드랍해도 괜찮음.
      • 사용하려면 Unknown 문자열보다는 NaN + has_source 플래그가 모델에는 더 낫습니다.
    • created_by, created_at, updated_at

드랍 계획 

 
  • funds 테이블
    • id, fund_id
      • id 드랍, fund_id PK 유지 OK.
    • object_id (펀드 객체 ID)
      • FK로 유지 + 공통 규칙 적용.
    • name
      • 텍스트 정규화 (strip, lower 등) OK.
    • funded_at
      • datetime 변환 + NaT 유지 OK.
      • 연도/분기 파생변수 만드는 것 좋음.
    • raised_amount
      • 로그변환 아이디어 OK.
      • 0 값 처리: 라운드 존재하면서 0이면 NaN + is_fund_size_disclosed 플래그.
    • raised_currency_code
      • 상위 top N 외 OTHERS로 묶는 건 합리적
      • 다만 USD로만 보면 drop해도 무방.
    • source_url, source_description
      • 텍스트 전처리 + Unknown 대체
      • 모델용으론 드랍 추천, EDA용에만 두는 걸 추천.
    • created_at, updated_at
      • 드랍 OK.
 
  • investments 테이블
    • id
      • 인덱스라면 드랍 OK
      • 단, 나중에 레코드 추적하고 싶다면 보존 옵션 (특정 행의 값을 보고 싶다)
    • funding_round_id
      • FK로 유지 funded_object_id
        • funded_object_id -> c_funded_object_id + int
        • investments가 투자를 받은 회사와 투자자들을 연결한다고 되어 있어서, 실제로는 대부분 c:일 가능성이 큼
        • 다만, 혹시 다른 타입(p:, f:)이 섞여 있지 않은지 한 번 확인 추천.
        • int 변환 시 공통 규칙 적용 필수.
    • investor_object_id
      • c/f/p_investor_object_id 세 컬럼으로 분리 + dtype int -> 구조적으로 매우 좋은 아이디어
      • 추가로 원본 문자열 investor_object_id_raw는 한 컬럼에 그대로 남겨두면, 나중에 유연하게 조인/디버깅할 때 편함.
    • created_at, updated_at
      • Crunchbase 크롤링/수정 시점이라, 이벤트 시점으로 사용하기 어렵다는 판단 -> 드랍
      • 동의!
 
  • ipos 테이블
    • id
      • 고유식별 컬럼 삭제 OK.
    • ipo_id
      • PK로 유지 object_id
        • object_id → c_object_id + int
        • 결측 5개 row 드랍 (어차피 금액/날짜도 전부 결측)
        • 중복 object_id는 최신 updated_at만 남기는 건 다중 상장(해외/국내 동시 상장) 정보가 필요 없다면 OK.
        • 그런 정보까지 보고 싶다면, 별도 로직으로 관리 필요
    • valuation_amount, raised_amount (0이 대부분)
      • 금액 0 → 비공개/미제공으로 간주 → NaN + is_ipo_valuation_disclosed, is_ipo_raised_disclosed 플래그 추천
      • int로 바꾸기보다는 float 유지.
    • valuation_currency_code, raised_currency_code
      • USD로만 분석한다면, USD 기준 값 하나 만들고 나머지는 드랍해도 OK.
    • public_at
      • datetime 변환 OK.
      • 상장 예정 실패 vs 날짜 누락”은 실제론 구분하기 어렵기 때문에, 그냥 NaT(Not a Time)로 두고 is_public_date_known 정도의 플래그만 두는 게 무난
    • stock_symbol
      • 여기서 국가를 유추해서 카테고리 만들 생각 GPT로 분류 후 샘플링 검수만 조금 해주면 충분.
    • source_url, source_description, created_at, updated_at
      • 드랍 OK.
 
  • milestones 테이블
    • id
      • 계획서에 "mixed_object_id로 열 이름 변경"이라고 적혀 있는데, 실제 스키마상 id는 milestone 자체의 PK이고, object_id가 "어떤 객체의 milestone인지"를 나타냅니다.
      • 그래서, id -> 그대로 milestone PK로 두거나, 안 쓰면 드랍.
      • object_id -> mixed_object_id로 rename 하는 게 더 자연스럽습니다.
    • object_id
      • 위와 같이 rename 추천 + 공통 규칙 적용.
    • milestone_at
      • datetime 변환 OK.
    • milestone_code
      • 전부 other라면 드랍 OK.
    • description
      • 키워드 기반으로 launch/release/beta/... 분류하는 아이디어  (누구 생각인지 참 좋네요~  )
      • 원본 텍스트는 그대로 보존하고, 새 요약/카테고리 컬럼을 추가하는 방식 추천.
    • source_url, source_description, created_at, updated_at
      • 드랍 OK.
 
  • objects 테이블 
    • 이 테이블은 전체 분석의 허리라서, 여기 설계가 가장 중요해요 ! 
    • 1. 식별 관련
      • id
        • object_id로 rename → OK.
        • 위에서 말한 것처럼 문자열+prefix를 보존하는 형태 추천.
      • entity_type
        • Company / FinancialOrg / Person / Product 구분
        • 절대 드랍하지 말고 주요 feature로 활용하세요.
      • entity_id
        • 이건 보통 id의 numeric 버전이라 중복 정보일 가능성이 큼
        • 실제로 id에서 숫자만 떼어낸 것과 동일한지 확인 후, 동일하면 드랍 추천.
    • 2. 계열/지배구조
      • parent_id (결측 94%)
        • 계획처럼 has_parent 플래그 만드는 건 아주 좋습니다.
        • 다만 결측값 자체를 'independent'라는 문자열로 대체하는 건 -> 모델링용(분석용이면 good) 테이블에선 비추.
        • 추천한다면, parent_id는 그대로 NaN 유지, has_parent = parent_id.notnull().astype(int) 따로 생성.
    • 3. 이름/텍스트
      • name, normalized_name
        • normalized_name만 쓰고, name은 거의 안 쓸 가능성이 큼.
        • 둘 중 하나만 남겨도 됨(검색/조인용이라면 둘 다 보존도 가능).
      • permalink
        • homepage_url 결측 채우기용으로 사용하는 아이디어 좋음.
      • category_code (결측 73%)
        • 단순히 'Unknown'으로 메꾸기보다, NaN 유지 + has_category_code 플래그 (물론, 모델링 <-> 분석용(EDA) 따라 다를수도..?)
        • 혹은 상위 몇 개 카테고리만 별도 one-hot 하는 방식 추천.
      • status
        • 운영/초기/성공(exit)/실패 구분 체계 아주 좋음.
        • live와 operating을 묶을지 여부만 정하면 됨 -> status에서 operating과 live는 둘 다 "현재 운영 중인 객체"로 봐도 되고, VC의 포트폴리오/Exit 분석에서는 같은 카테고리로 합치는 게 안전합니다.
        • 다만, 세밀한 제품 단계 분석을 할 때는 별도의 제품 lifecycle에 맞는 구분이 필요합니다.
    • 4. 날짜/생존 관련
      • founded_at (결측 78%)
        • 최솟값으로 대치는 강하게 비추천.
        • founded_at은 NaT 그대로 두고, is_founded_missing 플래그만 추가.
        • 필요하면 first_funding_at 등으로 "최초 관측 시점"을 따로 쓰는 편이 더 안전.
      • closed_at (결측 99%)
        • 비결측이면 폐업/휴면으로 보는 건 OK.
        • is_closed = closed_at.notnull().astype(int) 플래그 생성 추천.
    • 5. 웹/소셜/설명 텍스트
      • domain, homepage_url
        • 둘이 중복이 많으니, homepage_url만 남기고 domain은 거기서 파생해도 됨.
      • twitter_username, logo_url, short_description, description, overview, tag_list
        • EDA 차원에서 'Unknown', 'No info'로 채우는 건 괜찮지만,  모델링용에선 NaN + has_overview, has_tag_list 같은 플래그가 더 정보량이 명확함.
    • 6. 위치 정보
      • country_code / state_code / city / region
        • 위치 컬럼 간 상관관계 분석 잘 해놓음.
        • region 정제 (오타/unknown/이상값 통합) -> 상위 카테고리로 재코딩은 매우 좋은 아이디어 US/CA에 대해서만 state_code 보정하는 것도 현실적인 접근.
        • 결측을 ‘Unknown’으로 치환하기보다는, NaN 유지 + country_missing 같은 플래그가 더 나음.
    • 7. 투자/펀딩/마일스톤
      • first_investment_at, last_investment_at, investment_rounds, invested_companies
        • 결측 패턴 설명이 잘 되어 있고, 플래그 컬럼 생성 계획도 좋습니다.
        • datetime 변환 후 NaT 유지 + 플래그 생성 → OK.
      • first_funding_at, last_funding_at, funding_rounds, funding_total_usd
        • funding_rounds가 0인데 funding_total_usd > 0이면 데이터 이상치이므로 이 조합은 한번 체크해보고 필요시 정제.
        • funding_total_usd 0을 "투자 없음" vs "비공개"로 구분하려는 조건식은 좋은데, 실제로 깔끔하게 나뉘지 않을 가능성도 있어서 최소한 has_funding_rounds (round >0), has_disclosed_total_funding (funding_total_usd>0) 두 축으로 나누는 걸 기본으로 추천.
      • first_milestone_at, last_milestone_at, milestones
        • 플래그+카운트 feature로 쓰기 딱 좋음. 현재 계획대로 진행 relationships
          • entity_type/status와 강한 연관 있다는 메모 좋음. 그대로 카운트 feature로 쓰면 충분.
      • created_by, created_at, updated_at
        • created_by에 "Anonymous" 채우는 것보단 아예 드랍해도 무방해 보입니다.
        • created_at, updated_at은 데이터 최신성/스냅샷 시점을 보고 싶을 때만 사용.
 
  • offices 테이블
    • id, office_id
      • 한 회사에 여러 오피스가 있으니 office_id는 유지, id는 굳이 필요 없으면 드랍해도 OK.
    • object_id
      • object_id -> office_object_id
      • rename + 공통 규칙 적용 OK.
    • description
      • 텍스트 패턴으로 HQ/Branch/R&D/Sales 등 카테고리화 → 아주 좋은 아이디어 (누구 아이디어인지 찰떡이네  )
    • region
      • 기본 전처리 + 키워드 기반 분류(GPT 활용) 전략은 텍스트 EDA에 유용.
    • address1, address2, city, zip_code, state_code
      • 'Unknown' 채우기 + 결측 플래그 생성 계획.
      • 모델용에선 주소 텍스트는 high-cardinality라 직접 쓰기 어렵고, has_address, has_city 같은 플래그만 써도 충분할 가능성이 큼.
      • state_code는 city/description으로 보정하겠다는 계획 좋아요.
      • high-cardinality : 고유값 개수가 엄청 많은 범주형 컬럼(후에 모델링 관점에서 차원이 너무 커지거나, 희소값들에 대한 과적합 발생 가능성이 높음 -> one-hot 때려 넣기보단 드랍 or TOP N + "기타"로 묶기)
    • country_code, latitude, longitude
      • 특히 lat/lon은 나중에 군집/거리 기반 feature로 쓸 수 있으니, 남겨두면 좋습니다.
    • created_at, updated_at (전부 결측)
      • 드랍 OK.
 
  • people 테이블
    • id, object_id
      • object_id는 필수 FK이므로 유지, id는 드랍 OK.
    • first_name, last_name
      • 인물의 이름은 대부분 predictive power(예측 파워)가 낮으므로, PII(개인정보 식별자) 측면에서도 드랍 OK.
    • birthplace (결측 88%)
      • 'unknown'으로 채우는 것보다는, NaN + birthplace_missing 플래그 + 별도 카테고리(birthplace_region 정도)로 단순화하는 걸 추천.
    • affiliation_name
      • 1% 미만 결측이니, 드랍보다는 Unknown으로 두고, 나중에 relationships/objects와 join이 안 되는 케이스에서 보조 정보 정도로 쓰는 걸 추천.
 
  • relationships 테이블
    • id vs relationship_id
      • 동일하다고 되어 있는데, 실제로 값이 완전 동일한지 한 번 확인 후 하나만 남기고 나머지 드랍 추천. (relationship_id만 남기면 될 듯)
    • person_object_id
      • person_object_id -> p_object_id
      • rename + 공통 규칙 적용 OK.
    • relationship_object_id
      • relationship_object_id -> mixed_object_id
      • 회사/펀드/기타가 섞여 있으니 이름 잘 지은 것 같아요~
    • start_at, end_at
      • datetime 변환 + start_at > end_at 452행 드랍 -> 합리적.
      • 플래그(has_end_date) 추가해도 좋음.
    • is_past
      • 유지 OK.
    • sequence
      • 이상값(20,000 이상) 처리는 필요해 보이고, sequence ==1 vs >1 구분해서 대표 관계 여부 보는 아이디어 좋음. title
        • Unknown으로 채우고, 20개 이내 카테고리로 매핑 -> 좋은 전략.
        • 결측 플래그도 추가 추천.
    • created_at, updated_at
      • 드랍 OK.
 
  • 예상 질문
    • Q. 튜터님 단순 UNKNOWN으로 처리하는 것보다 NAN or NAT로 하고 별로 컬럼으로 두라고 한 조언들이 많습니다. 왜 그런건가요? 컬럼이 더 많아지는 단점이 생기지 않나요?
    • A. 모델링/통계 관점에서는 값이 "진짜 존재하는 값"인지, "아예 없어서 모르는(missing)" 건지를 분리해서 표현해 주는 게 훨씬 안전해서 입니다.
      • 컬럼 처리시에는 NaN/NaT로 "없음"을 남기고, 없었음 여부를 표시하는 이진 플래그 컬럼을 하나 더 만드는 패턴이 너무나도 빈번하게 사용됩니다.
      • 컬럼 수는 조금 늘어나지만, 그만큼 해석력/유연성/모델 성능에서 이득이 커서 trade-off로 보는 경우가 많습니다!
      • 이유 1. Unknown은 진짜 값처럼 보이지만, NaN은 값 없음이란 의미 자체를 보존함
      • 이유 2. 값이 비어있다는 사실 자체가 예측에 도움이 될 때가 많음
      • 이유 3. 라이브러리/툴들이 애초에 "NaN + indicator" 패턴을 공식 지원함(ex. scikit‑learn 문서의 missing 처리 권장 - 링크 )
      • 그러면 Unknown은 언제 쓰냐고 하면?
        • 모델용 / 통계 분석용에는 Unknown을 실제 값처럼 쓰는 걸 되도록 피하는 게 일반적인 경우
        • EDA / 대시보드 / 보고용에는 NaN은 안 보이니까 뷰/리포트 레이어에서만 Unknown을 붙이자는 느낌
      • 근데 컬럼 수 늘어나는 거 아닌가요?
        • 맞습니다. 실제로 결측 플래그 1개당 binary(이진) 컬럼이 늘어납니다..  그래서 보통 아래와 같은 경우에 사용합니다.
        • 1. 모든 컬럼에 무지성으로 플래그 붙이지는 않는다. -> 정말로 중요하거나, missing이 의미 있을 것 같다 위주로만 플래그
        • 2. high-cardinality 텍스트(주소, 상세 설명 등)는 애초에 모델 특성으로 잘 안 쓰고 존재 여부 플래그 몇 개만 써도 충분한 경우가 많음.
        • VC/스타트업 데이터처럼 컬럼 수가 수십~백여 개인 수준에서는 플래그 몇 개 늘어난다고 해서 차원 폭발이 일어날 정도는 아님 (one-hot으로 수천 차원 되는 것에 비하면 아주 양호)

 

 

회고

오늘은 하루 종일 회의하고 결정하고 회의하고 결정하고를 계속 반복한 날이었다. 그래도 천천히 하나씩 결정이 되어가는 것 같아서 앞으로 나아가고 있는 느낌을 받았다. 사실은 이해가 안되는 부분도 있고 집중이 안될 때도 있었지만 주말동안 스스로 이해도를 디벨롭 시켜야겠다 반드시!