전처리에 대한 끝없는 회의와 조인/머지를 어떻게 해야할지에 대한 논의 그리고 관점에 따라 조인을 달리하여 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 패턴 연구에서도 이런 텍스트/메타는 사용 안 하는 경우가 많아서 드랍해도 무방
- id
- 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.
- id
- 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.
- id, fund_id
- investments 테이블
- id
- 인덱스라면 드랍 OK
- 단, 나중에 레코드 추적하고 싶다면 보존 옵션 (특정 행의 값을 보고 싶다)
- funding_round_id
- FK로 유지 funded_object_id
- funded_object_id -> c_funded_object_id + int
- investments가 투자를 받은 회사와 투자자들을 연결한다고 되어 있어서, 실제로는 대부분 c:일 가능성이 큼
- 다만, 혹시 다른 타입(p:, f:)이 섞여 있지 않은지 한 번 확인 추천.
- int 변환 시 공통 규칙 적용 필수.
- FK로 유지 funded_object_id
- investor_object_id
- c/f/p_investor_object_id 세 컬럼으로 분리 + dtype int -> 구조적으로 매우 좋은 아이디어
- 추가로 원본 문자열 investor_object_id_raw는 한 컬럼에 그대로 남겨두면, 나중에 유연하게 조인/디버깅할 때 편함.
- created_at, updated_at
- Crunchbase 크롤링/수정 시점이라, 이벤트 시점으로 사용하기 어렵다는 판단 -> 드랍
- 동의!
- id
- ipos 테이블
- id
- 고유식별 컬럼 삭제 OK.
- ipo_id
- PK로 유지 object_id
- object_id → c_object_id + int
- 결측 5개 row 드랍 (어차피 금액/날짜도 전부 결측)
- 중복 object_id는 최신 updated_at만 남기는 건 다중 상장(해외/국내 동시 상장) 정보가 필요 없다면 OK.
- 그런 정보까지 보고 싶다면, 별도 로직으로 관리 필요
- PK로 유지 object_id
- 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.
- id
- 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.
- id
- objects 테이블
- 이 테이블은 전체 분석의 허리라서, 여기 설계가 가장 중요해요 !
- 1. 식별 관련
- id
- object_id로 rename → OK.
- 위에서 말한 것처럼 문자열+prefix를 보존하는 형태 추천.
- entity_type
- Company / FinancialOrg / Person / Product 구분
- 절대 드랍하지 말고 주요 feature로 활용하세요.
- entity_id
- 이건 보통 id의 numeric 버전이라 중복 정보일 가능성이 큼
- 실제로 id에서 숫자만 떼어낸 것과 동일한지 확인 후, 동일하면 드랍 추천.
- id
- 2. 계열/지배구조
- parent_id (결측 94%)
- 계획처럼 has_parent 플래그 만드는 건 아주 좋습니다.
- 다만 결측값 자체를 'independent'라는 문자열로 대체하는 건 -> 모델링용(분석용이면 good) 테이블에선 비추.
- 추천한다면, parent_id는 그대로 NaN 유지, has_parent = parent_id.notnull().astype(int) 따로 생성.
- parent_id (결측 94%)
- 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에 맞는 구분이 필요합니다.
- name, normalized_name
- 4. 날짜/생존 관련
- founded_at (결측 78%)
- 최솟값으로 대치는 강하게 비추천.
- founded_at은 NaT 그대로 두고, is_founded_missing 플래그만 추가.
- 필요하면 first_funding_at 등으로 "최초 관측 시점"을 따로 쓰는 편이 더 안전.
- closed_at (결측 99%)
- 비결측이면 폐업/휴면으로 보는 건 OK.
- is_closed = closed_at.notnull().astype(int) 플래그 생성 추천.
- founded_at (결측 78%)
- 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 같은 플래그가 더 정보량이 명확함.
- domain, homepage_url
- 6. 위치 정보
- country_code / state_code / city / region
- 위치 컬럼 간 상관관계 분석 잘 해놓음.
- region 정제 (오타/unknown/이상값 통합) -> 상위 카테고리로 재코딩은 매우 좋은 아이디어 US/CA에 대해서만 state_code 보정하는 것도 현실적인 접근.
- 결측을 ‘Unknown’으로 치환하기보다는, NaN 유지 + country_missing 같은 플래그가 더 나음.
- country_code / state_code / city / region
- 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로 쓰면 충분.
- 플래그+카운트 feature로 쓰기 딱 좋음. 현재 계획대로 진행 relationships
- created_by, created_at, updated_at
- created_by에 "Anonymous" 채우는 것보단 아예 드랍해도 무방해 보입니다.
- created_at, updated_at은 데이터 최신성/스냅샷 시점을 보고 싶을 때만 사용.
- first_investment_at, last_investment_at, investment_rounds, invested_companies
- 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.
- id, office_id
- 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이 안 되는 케이스에서 보조 정보 정도로 쓰는 걸 추천.
- id, object_id
- 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개 이내 카테고리로 매핑 -> 좋은 전략.
- 결측 플래그도 추가 추천.
- 이상값(20,000 이상) 처리는 필요해 보이고, sequence ==1 vs >1 구분해서 대표 관계 여부 보는 아이디어 좋음. title
- created_at, updated_at
- 드랍 OK.
- id vs relationship_id
- 예상 질문
- 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으로 수천 차원 되는 것에 비하면 아주 양호)
회고
오늘은 하루 종일 회의하고 결정하고 회의하고 결정하고를 계속 반복한 날이었다. 그래도 천천히 하나씩 결정이 되어가는 것 같아서 앞으로 나아가고 있는 느낌을 받았다. 사실은 이해가 안되는 부분도 있고 집중이 안될 때도 있었지만 주말동안 스스로 이해도를 디벨롭 시켜야겠다 반드시!
'프로젝트' 카테고리의 다른 글
| [프로젝트 #4] 12월 08일 (월) - TIL (0) | 2025.12.08 |
|---|---|
| [프로젝트 #4] 12월 04일 (목) - TIL (0) | 2025.12.04 |
| [프로젝트 #4] 12월 03일 (수) - TIL (0) | 2025.12.03 |