Loading the catalog…
Loading the catalog…
[플레이데이터 SK네트웍스 Family AI 캠프 36기] 2nd 프로젝트 - 2일차 (2026.09.29) 팀 프로젝트 2일차 📖 오늘 학습 내용 Riot Games API와 PUUID 경기 데이터 수집 (경기 시간, 모드, 승패, 전투 지표, 챔피언, 포지션 등) 경기 단위 데이터를 사용자 단위로 집계하기 중복 제거와 수집 실패/실제 무경기 구분 분석 기준일과 Data Leakage 방지 활동 사용자 Cohort 선정 Churn Label 생성과 Class Imbalance Feature Engineering (33개 Feature) 결측치 처리 시 주의할 점 1일차에 "30일 무경기 사용자를 예측하자"는 문제를 정했다. 2일차에는 실제로 모델에게 넣을 데이터를 만드는 작업을 진행했다. Riot API → 사용자 식별 → 경기 기록 수집 → 중복 제거 → 시간 정보 정리 → 활동 사용자 선정 → Churn Label 생성 → Feature Engineering → 최종 학습 Dataset 1. Riot Games API와 PUUID Riot Games에서는 League of Legends 데이터를 조회할 수 있는 API를 제공한다. 이번 프로젝트에서는 사용자 정보와 경기 정보가 필요하다. Riot 사용자 식별에 중요한 값이 PUUID 다. PUUID는 Riot에서 플레이어를 구분하기 위해 사용하는 암호화된 사용자 식별자다. Riot ID(gameName + tagLine) → ACCOUNT-V1 → PUUID → 경기 API 조회 ACCOUNT-V1 은 Riot 계정 정보를 가져오는 API다. Column 의미 puuid 암호화된 사용자 ID gameName Riot ID 이름 tagLine Riot ID의 Tag 예를 들어 Riot ID가 ABC#KR1 이면 gameName=ABC, tagLine=KR1로 PUUID를 조회한다. 2. 경기 데이터 수집 사용자의 PUUID를 얻은 후 Match 데이터를 수집한다. 사용자와 경기 식별 정보 : puuid (사용자 식별), matchId (경기 식별). 이 두 값은 "누가 어떤 경기를 했는가"를 연결하는 데 중요하다. 경기 시간 : gameStartTimestamp , gameEndTimestamp 로 언제 게임했는지, 마지막 게임이 언제였는지, 게임 사이 간격은 얼마인지를 계산할 수 있다. 다만 gameEndTimestamp 는 경기가 끝난 시간이지 마지막 로그인 시간이 아니라서, 이 데이터만으로 사용자가 클라이언트에 접속했는지는 알 수 없다. 게임 플레이 시간 : gameDuration 으로 평균/전체 플레이 시간을 만들 수 있다. 게임 모드 : queueId 로 솔로랭크, 자유랭크, 일반게임, ARAM, Arena 등을 구분할 수 있다. 승패 : win 값으로 승률, 연승, 연패, 최근 승률 변화를 계산할 수 있다. 전투 지표 : kills , deaths , assists 로 KDA 개념을 종합해 경기력을 표현한다. 챔피언 : championId , championName 으로 사용 챔피언 수, 주력 챔피언, 챔피언 집중도를 계산할 수 있다. 포지션 : teamPosition 으로 TOP/JUNGLE/MIDDLE/BOTTOM/UTILITY 정보를 확인할 수 있다. 추가 경기 지표 : goldEarned , totalMinionsKilled , neutralMinionsKilled , totalDamageDealtToChampions , visionScore , wardsPlaced , wardsKilled 등도 사용했다. 이 값을 그대로 쓰기보다는 분당 Gold, 분당 CS, 분당 Damage, 분당 Vision 등으로 변환해서 사용할 수 있다. 3. Raw Data가 바로 학습 데이터는 아니다 API에서 데이터를 가져왔다고 바로 Model에 넣을 수 있는 건 아니다. 원본은 경기 단위다(User A Game1, User A Game2, User B Game1...). 하지만 우리가 원하는 건 사용자별 이탈 예측이라, 여러 경기를 한 사용자의 상태를 대표하는 Feature로 집계 해야 한다. 분석 단위 : 최종 Model에서는 "사용자 1명 = DataFrame 한 Row"로 만들었다. user games_7d games_30d winrate days_since_last_game churn A 12 30 0.55 1 0 B 1 5 0.40 15 1 전처리 전체 흐름 : 여러 수집 Batch → 사용자 데이터 통합 → 경기 데이터 통합 → 중복 제거 → 경기 시간 정리 → 기준일 T 설정 → (T 이전=Feature, T 이후 30일=Label) → 활동 사용자 Filtering → 사용자 단위 집계 → Model Dataset 4. 중복 제거와 수집 실패/실제 무경기 구분 API를 여러 번 호출하다 보면 같은 경기나 사용자가 중복 저장될 수 있어서, 사용자는 team_id+player_id, 경기는 matchId를 기준으로 중복을 확인했다. 매우 중요한 부분 : API 결과가 비어 있을 때, 그 이유는 여러 가지일 수 있다 — 진짜 경기가 없는 경우, API 호출 실패, 요청 Error, 저장 실패. 이걸 전부 "경기 없음"으로 처리하면 잘못된 Label이 만들어질 수 있다. 그래서 실제 무경기와 API Error/빈 응답/수집 실패를 가능한 범위에서 구분 했다. 5. 분석 기준일과 Data Leakage 방지 최종 분석 기준일은 2026-08-01 로 설정했다(T라고 표기). 과거 ─────────────┬──────────────── 미래 T (2026-08-01) Data Leakage : 이번 프로젝트에서 매우 중요한 개념이다. 8월 1일에 앞으로 이탈할 사람을 예측한다고 할 때, Feature를 만들면서 8월 15일 경기 수를 사용하면 미래 정보를 미리 본 셈이 된다. 이게 Data Leakage(데이터 누수) 다. 그래서 기준일 이전 → Feature 생성, 기준일 이후 30일 → Label 생성을 철저히 분리했다. T │ Feature │ Label 구간 │ 구간 ◀─────────●─────────▶ 과거 데이터 미래 30일 Model Input Churn 판정 6. 활동 사용자 Cohort 처음 수집된 모든 사용자를 바로 사용하지는 않았다. 전체 수집 사용자는 9,879명 이었다. 왜 사용자를 줄였는가 : 어떤 사용자가 과거에도 거의 게임하지 않고 최근에도 1판만 했다면, "활동하다가 이탈했다"고 보기 어렵다. 그래서 실제로 어느 정도 게임을 하던 사용자를 분석 대상으로 선정했다. 진성 활동 고객 조건 : games_prev30d >= 4 그리고 games_30d > 0 . 즉 직전 기간에도 어느 정도 게임했으면서, 최근 30일에도 실제 게임한 사용자만 사용한다. Cohort 결과 : 전체 수집 사용자 9,879명 → 활동 조건 적용 → 최종 학습 대상 2,381명 . 7. Churn Label과 Class Imbalance 최종 Label : 기준일 이후 30일 경기 0개 → churn=1, 경기 1개 이상 → churn=0. Label 분포 : 최종 학습 대상 2,381명 중 이탈 사용자 363명, 비이탈 사용자 2,018명으로 이탈 비율은 15.25% 였다. 비이탈 █████████████████████ 이탈 ████ 이탈 363명 vs 비이탈 2,018명으로 Class 비율이 같지 않은 Class Imbalance 상태다. 왜 Accuracy만 보면 안 될까 : 100명 중 이탈 10명, 비이탈 90명인 데이터에서 모델이 전부 "비이탈"이라고 예측하면 90명을 맞혀서 Accuracy=90%가 나온다. 하지만 실제 이탈자 10명은 0명 찾은 셈이라 실제 목적에는 쓸모가 없다. 그래서 이후 모델에서는 Precision, Recall, PR-AUC 등을 중요하게 본다. 8. Feature Engineering 원본 경기 데이터를 그대로 쓰지 않고, 사용자의 행동을 대표하는 숫자로 만들었다. 최종 Feature Set은 33개 다( aggregate33 ). 활동량 Feature : games_7d : 최근 7일 경기 수 games_30d : 최근 30일 경기 수 games_90d : 최근 90일 경기 수 games_prev30d : 그 이전 비교 기간의 경기 수 activity_change_30d : 최근 활동량 변화 active_days_30d : 최근 30일 실제 게임한 날짜 수 최근성 Feature : days_since_last_game : 마지막 경기 이후 경과일(어제 마지막 경기면 1, 20일 전이면 20) avg_gap_30d : 최근 30일 평균 경기 간격 max_gap_30d : 최근 30일 최대 경기 간격 last_gap : 가장 최근 경기 사이 간격 경기력 Feature : winrate_20 : 최근 20경기 승률 avg_kda_20 , avg_kills_20 , avg_deaths_20 , avg_assists_20 : 최근 20경기의 평균 경기력 losing_streak : 현재 연속 패배 수 winrate_change_10 : 최근 승률 변화 게임 행동 Feature : avg_game_duration_20 , avg_gold_per_min_20 , avg_cs_per_min_20 , avg_damage_per_min_20 , avg_vision_per_min_20 챔피언 Feature : unique_champions_20 : 최근 20경기 사용 챔피언 수 top_champion_ratio_20 : 가장 많이 사용한 챔피언의 비율 게임 모드 Feature : unique_modes_30d , mode_switch_rate_20 , ranked_solo_ratio_30d , ranked_flex_ratio_30d , normal_ratio_30d , aram_ratio_30d , arena_ratio_30d , rotating_ratio_30d , other_ratio_30d 사용자 ID는 Feature가 아니다 : player_id , team_id 는 사용자 조회에는 필요하지만 Model Input에서는 제외했다. 모델이 "이 ID의 사람이 이탈한다"를 외워버리면 안 되기 때문이다. 우리가 원하는 건 "이런 행동 패턴의 사용자가 이탈 위험이 높다"를 학습하는 것이다. Tier Feature 제외 : Tier 정보도 검토했지만, 전체 사용자에게 존재하지 않고 수집 시점이 명확하지 않다는 문제가 있어 최종 Feature에서는 제외했다. 9. 결측치 처리 시 주의할 점 결측치를 전체 데이터 기준으로 미리 채우지 않았다. Cross Validation을 할 때 Train Fold → Median 계산 → Train 결측 대체 → Validation도 Train Median 적용하는 방식으로 진행했다. 왜 Validation Median을 쓰면 안 될까 : Validation은 시험 문제와 비슷해서, Validation 데이터의 정보로 전처리 기준을 만들면 시험 문제를 미리 본 것과 비슷해진다. 그래서 Train에서 기준을 학습하고, Validation에는 그 기준을 적용만 한다. 최종 데이터 구조 한 사용자 = 한 Row User → 33 Features + Churn Label 2일차 최종 Pipeline : Riot API → PUUID → Match Data → 사용자/경기 중복 제거 → Timestamp 정리 → 기준일 설정 ┌─ 기준일 이전: Feature 생성 ─┐ └─ 기준일 이후 30일: Churn Label 생성 ─┘ → 전체 사용자 9,879명 → 활동 Cohort 2,381명 → 33 Features → Churn 363명(15.25%) → Machine Learning Dataset 완성 핵심 정리 Raw Match Data 자체가 Machine Learning Data는 아니다. 경기 단위 데이터를 사용자 단위로 집계하고, 기준일 이전 행동만 Feature로 만들며, 미래 30일 기록은 Label에만 사용해야 한다. 그 결과 2,381명 × 33개 Feature 형태의 최종 학습 데이터를 만들었다.
What RADAR observed and classified to build this opportunity. It is what the source published, not a verification that the offer is still active.
[플레이데이터 SK네트웍스 Family AI 캠프 36기] 2nd 프로젝트 - 2일차(2026.09.29). [플레이데이터 SK네트웍스 Family AI 캠프 36기] 2nd 프로젝트 - 2일차 (2026.09.29) 팀 프로젝트 2일차 📖 오늘 학습 내용 Riot Games API와 PUUID 경기 데이터 수집 (경기 시간, 모드, 승패, 전투 지표, 챔피언, 포지션 등) 경기 단위 데이터를 사용자 단위로 집계하기 중복 제거와 수집 실패/실제 무경기 구분 분석 기준일과 Data Leakage 방지 활동 사용자 Cohort 선정 Churn Label 생성과 Class Imbalance Feature Engineering (33개 Feature) 결측치 처리 시 주의할 점 1일차에 "30일 무경기 사용자를…
Open source