방법론
모든 통계를 어떻게 만드는가
BrawlVision은 Supercell 공식 API, 자체 PRO 플레이어 샘플링 레이어, 그리고 여러 통계 스무딩 단계를 결합하여 안정적이고 비교 가능하며 자체 불확실성에 솔직한 숫자를 제공합니다. 이 페이지는 정확한 공식과 갱신 주기와 함께 각 단계를 문서화합니다.
마지막 업데이트: 2026-04-30
데이터 출처
우리가 표시하는 모든 것은 감사 가능하게 유지하는 세 가지 출처에서 옵니다: Supercell 공개 API (developer.brawlstars.com), Brawlify CDN (cdn.brawlify.com), 그리고 공식 API가 플레이어당 최근 25경기 이후로는 노출하지 않는 전투와 집계를 보존하는 자체 Supabase 데이터베이스.
Supercell API는 구조 데이터(브롤러, 가젯, 스타파워, 하이퍼차지, 기어, 이벤트 로테이션)의 정식 출처이지만 브롤러 이미지, 등급, 긴 설명 같은 핵심 필드는 빠져 있습니다. 이 필드들은 독립적으로 운영되며 때때로 Supercell보다 1~3일 늦는 Brawlify CDN과 교차 참조합니다. 공식 API에 새 브롤러가 등장했지만 Brawlify에 아직 없을 때, 출시일에도 브롤러 페이지가 정확히 렌더되도록 로컬 등급 매핑(BRAWLER_RARITY_MAP)을 유지합니다.
데이터베이스는 meta_stats에 두 종류의 행을 저장합니다: source=user (동기화를 활성화한 프리미엄 사용자의 실제 전투)와 source=global (상위 PRO 랭킹의 자동 샘플링). 사이트의 모든 공개 통계는 source=global 필터로 계산되어 단일 사용자의 개인 데이터가 절대 공개 페이지로 새지 않습니다.
PRO 데이터 구성 방식
BrawlVision의 "PRO" 레이어는 세계 최고 플레이어들의 최근 전투에서 계산된 집계입니다. 6시간마다 cron 작업(meta-poll)이 경쟁 활동이 집중된 11개국의 Supercell 공식 랭킹을 조회하여 각 상위 200위에서 약 2,100명의 고유 플레이어로 구성된 중복 제거 풀을 만듭니다.
이 풀에 확률적 샘플러를 적용하여 인기 있는 (맵, 모드) 조합이 데이터셋을 지배하고 희귀 조합을 가리지 않도록 합니다. 개별 전투를 받아들일 확률은 p = min(1, (minLive + 1) / (current + 1))이며, minLive는 가장 적게 표현된 조합의 카운트, current는 후보 전투의 조합 카운트입니다. 과소 샘플링된 조합은 더 많은 가중치를 받고, 포화된 조합은 성장이 멈춥니다.
cron은 서버리스 함수의 300초 maxDuration 안에 머물기 위해 270초 소프트 예산으로 실행당 META_POLL_MAX_DEPTH = 1,000명의 플레이어까지 반복합니다. 각 응답은 반복 횟수, 조회된 플레이어 수, 모드별 카운트가 담긴 "adaptive" 진단 블록을 포함하여 비정상 샘플러 동작이 프로덕션에서 관찰 가능하도록 합니다.
베이지안 승률
소박한 승률(승리를 경기 수로 나눈 값)은 경기 수가 적을 때 오해를 부릅니다. 새 맵에서 3승 0패인 브롤러는 아무 의미도 없는 100%를 보여 줍니다. BrawlVision은 이 왜곡을 바로잡고 표본 크기가 크게 다른 브롤러끼리도 비교할 수 있는 숫자를 돌려주기 위해 베이지안 스무딩을 적용합니다.
식은 WR_bayesian = (승리 + α·μ) / (경기 + α)입니다. 매개변수 α는 가상의 경기를 얼마나 더할지에 대한 가중치이고 μ는 그 경기에 부여하는 결과입니다. α = 30을 사용하며, 이는 실제 자료를 보기 전에 30경기를 미리 더하는 것과 같습니다.
2026년 9월까지 이 가상의 경기는 50% 값을 가졌고, 그것은 잘못된 값이었습니다. 우리 테이블은 경기당 한 행, 조사 대상 플레이어의 행만 저장합니다. 이 플레이어는 자국 상위 200위에 들며 자기 경기의 71.4%를 이깁니다(14일 창에서 85,970경기 중 61,400승, 2026년 9월 7일 측정). 71.4%를 중심으로 모인 자료를 50%로 줄이면 경기 수가 적은 칸은 모두 아래로 끌려 내려갔고, 표본이 작을수록 더 세게 끌렸습니다. 오늘의 μ는 0.714이며 이는 우리가 측정한 기준값입니다.
사전분포의 무게는 표본이 커질수록 줄어듭니다. 1,000경기에 530승이면 결과는 (530 + 21.42) / 1,030 = 53.5%로 원자료의 53.0%에 아주 가깝습니다. 3경기에 3승이면 소박한 계산의 100% 대신 74.0%가 됩니다. 스무딩은 표본이 정말 작을 때만 무게를 가집니다.
보정 강도
우리가 공개하는 승률은 두 가지를 섞고 있습니다. 하나는 브롤러가 얼마나 좋은지이고, 다른 하나는 어떤 상대와 붙었는지입니다. 유리한 대결에 주로 등장하는 브롤러는 위로 올라오지만 그 사실이 성능에 대해 말해 주는 것은 많지 않습니다. 보정 강도는 이 둘을 나누고, 그 브롤러가 중간 수준의 상대에게 얼마나 자주 이길지를 추정합니다.
계산은 최근 14일간의 대결 표에 MM으로 적합한 Bradley-Terry 모형입니다. 적합에 들어가기 전에 브롤러 쌍마다 대칭화를 거칩니다. 우리 행은 항상 조사 대상 플레이어 쪽에서 기록되고 그쪽이 유리하기 때문입니다. 양방향 각각 30회 이상의 대결이 있는 쌍으로 측정하면 A의 B 상대 승률과 B의 A 상대 승률의 합이 중앙값 138%가 되고, 대칭인 자료라면 100%가 됩니다. 각 대결을 양쪽에서 한 번씩 세면 그 유리함이 양쪽 모두에 들어가 상쇄됩니다. 결과는 적합의 중앙값 브롤러를 상대로 한 기대 승률로 공개하므로 이 척도에서는 50%가 무승부입니다.
이 수치는 상대 구성과 표집의 평균적인 유리함을 덜어냅니다. 브롤러를 다루는 사람의 실력은 덜어내지 않습니다. meta_stats에도 meta_matchups에도 플레이어 식별자가 저장되지 않아 지금의 자료로는 조작자의 실력을 빼는 것이 불가능하며, 그러려면 수집 시점에 조사 대상 플레이어의 순위를 함께 기록해야 합니다. 그래서 사이트의 목록은 여전히 관측 승률로 정렬하고 강도는 그 옆에 둡니다. 관측 승률이 50%가 아니라 72% 안팎인 이유도 같습니다. 표본은 11개국 상위 200위 플레이어의 경기이고 이들은 자기 경기의 72% 가까이를 이기므로, 그 척도에서 72%는 평범한 브롤러를 나타냅니다. 강도는 서로 다른 상대 20명을 상대로 400회 이상 기록된 대결이 있는 브롤러에 대해서만 공개합니다. 그 아래에서는 근거가 약한 숫자를 보여 주는 대신 수치를 생략합니다.
Comfort Score
Comfort Score는 "어떤 브롤러로 평균보다 정말 잘하는가?"라는 질문에 답하는 BrawlVision 자체 메트릭입니다. 순수한 승률이 아닙니다: 개인 성과의 다양한 차원을 포괄하기 위해 60/30/10 가중치로 세 가지 구성 요소를 결합합니다.
주요 구성 요소(60%)는 그 브롤러로의 플레이어 승률이며, 글로벌 메타와 동일하게 베이지안 스무딩을 적용해 거의 사용하지 않은 브롤러가 랭킹을 왜곡하지 않게 합니다. 중간 구성 요소(30%)는 이 개인 승률과 브롤러의 전체 메타 승률 간의 차이입니다: 글로벌 메타가 48%일 때 SHELLY로 55%인 플레이어는 메타가 53%인 브롤러로 55%인 플레이어보다 더 많은 comfort를 얻는데, 상대적 향상이 더 크기 때문입니다.
마지막 구성 요소(10%)는 정규화된 사용 빈도입니다: 다른 모든 것이 같다면 브롤러를 100번 플레이하는 것이 10번보다 더 가치가 있습니다. 일관성이 보상받기 때문입니다. 정확한 공식과 가중치는 src/lib/analytics/compute.ts에 있으며 모든 엔드포인트 호출에서 동일하게 적용되어 랭킹이 재현 가능합니다.
7일 트렌드
모든 공개 브롤러에는 메타 승률이 지난 7일 동안 이전 7일에 비해 어떻게 변했는지(총 14일 창) 보여주는 "+X.Y%" 또는 "−X.Y%" 트렌드 표시기가 있습니다. 계산은 source=global에서 창의 각 절반에 최소 MIN_BATTLES_PER_TREND_WINDOW = 3 전투로 실행됩니다 — 절반 중 하나라도 임계값에 미치지 못하면 null을 반환하고 UI는 약한 신호의 숫자를 만들어내는 대신 화살표를 숨깁니다.
트렌드는 pg_cron 작업으로 6시간마다 작은 테이블(public.brawler_trends, 브롤러당 한 행)에 미리 계산됩니다. 엔드포인트 응답이 아닌 데이터베이스에서 이렇게 하는 것은 모든 ISR 새로고침에서 14일 슬라이스의 수만 행을 스캔하는 것을 피합니다. 미리 계산된 테이블이 12시간 이상 오래되었거나 비어 있으면 엔드포인트는 더 높은 비용으로 동일한 응답을 반환하는 meta_stats의 페이지화된 인라인 경로로 떨어집니다. 페이징은 PostgREST가 페이지화되지 않은 쿼리를 1,000행으로 조용히 자르기 때문에 필요하며, 이는 한때 대부분의 브롤러가 가짜 언더샘플링으로 null을 반환하게 했습니다.
논리는 의도적으로 중복 존재합니다: src/lib/brawler-detail/trend.ts의 TypeScript 버전(상세 경로)과 supabase/migrations/022_*.sql의 SQL 버전(대량 경로). 둘 다 동일한 임계값, 동일한 창, 동일한 source=global 필터를 사용합니다. 발산하면 브롤러별 상세 페이지와 집계 페이지가 같은 브롤러에 대해 다른 숫자를 보여주게 되므로 모든 변경은 둘 다에 적용됩니다.
갱신 주기
데이터가 얼마나 자주 새로 고쳐지는지는 해석 방식에 영향을 미치므로 명시적으로 문서화합니다. 정적 페이지(이 페이지 포함)는 24시간 재검증의 ISR(Incremental Static Regeneration)을 사용합니다. 동적 데이터가 있는 페이지는 관련 작업이 무효화할 때까지 API 응답을 캐시합니다.
브롤러, 가젯, 스타파워는 24시간 서버 캐시로 Supercell API에서 동기화됩니다. meta-poll(PRO 데이터)은 6시간마다 실행되어 새로운 meta_stats 행을 생성합니다. 7일 트렌드 사전 계산은 meta-poll과 충돌을 피하기 위해 pg_cron의 "17 */6 * * *"(매 6시간마다 17분)에서 실행됩니다. 게임 내 이벤트 로테이션은 30분마다 새로 고쳐집니다.
동기화를 활성화한 프리미엄 사용자의 개별 전투는 sync cron을 통해 슬라이딩 윈도우에서 각 매치 직후에 다운로드됩니다. 데이터베이스에 들어가면 source=user로 meta_stats를 채우고 프로필 섹션의 비공개 분석의 기반이 됩니다; 공개 집계에 절대 나타나지 않으며 source=global과 절대 섞이지 않습니다.
자주 묻는 질문
표본이 적은 브롤러의 승률이 0% 또는 100%가 아닌 이유는?+
50% 중심의 사전을 가진 베이지안 스무딩을 적용하기 때문입니다. 매치가 매우 적으면 표시되는 숫자는 50%에 가깝고; 표본이 커지면 실제 승률에 수렴합니다. 의도적입니다: 3매치에서 100%는 정보가 아니라 노이즈입니다.
공개 페이지가 실제 사용자 데이터를 사용하나요?+
아니요. 모든 공개 집계는 PRO 랭킹 자동 샘플링에서 가져온 전투만 포함하는 source=global로 필터링합니다. 프리미엄 사용자의 비공개 전투는 source=user로 저장되며 공개 페이지로 절대 넘어가지 않습니다.
Supercell이 새 브롤러를 출시하면 어떻게 되나요?+
브롤러 목록은 공식 API에서 가져오므로 출시 당일 사이트에 전체 로스터가 나타납니다. 등급과 이미지는 1~3일 지연될 수 있는 Brawlify에서 가져옵니다; 첫 며칠을 위한 폴백으로 로컬 등급 매핑(BRAWLER_RARITY_MAP)을 유지합니다.
일부 트렌드가 백분율 대신 대시를 보여주는 이유는?+
14일 창의 각 절반에 source=global에 최소 3개의 전투가 있을 때만 트렌드를 표시합니다. 브롤러를 거의 보지 못할 때는 약한 신호의 숫자보다 아무것도 표시하지 않는 것을 선호합니다.
사이트가 설명을 생성하는 데 AI를 사용하나요?+
설명은 자체 데이터(최고 맵, 최고 모드, 브롤러별 베이지안 승률)에서 동적으로 생성됩니다. Brawlify나 위키에서 텍스트를 복사하지 않으며 콘텐츠를 부풀리기 위해 언어 모델을 사용하지 않습니다.
질문이나 수정 사항?
방법론적 오류를 발견했거나 개선을 제안하고 싶으면 연락해 주세요. 데이터 계산 방식의 모든 관련 변경 사항으로 이 페이지를 동기화 상태로 유지합니다.
