브랜드별 매출을 다 더했더니 전체보다 커졌습니다
외식 프랜차이즈 매출 분석 화면을 열어 브랜드별 매출을 뽑았습니다. 브랜드 A, 브랜드 B, 브랜드 C 각각의 숫자를 확인하고 마지막으로 셋을 더했습니다. 그런데 그 합이 전체 매출보다 컸습니다. 부분을 더했는데 전체보다 크다는 건, 어딘가에서 같은 매출이 두 번 세어지고 있다는 신호였습니다.
매출 리포트는 그대로 의사결정의 입력값이 됩니다. 어느 브랜드에 마케팅비를 더 태울지, 어느 브랜드를 접을지, 성과급을 어떻게 나눌지가 이 숫자 위에서 결정됩니다. 브랜드별 합이 부풀어 있다면, 그 위에 얹힌 판단도 같이 틀어집니다. 그래서 '합이 안 맞는다'는 사소해 보이는 위화감을 그냥 넘기지 않았습니다.
필터는 '포함'을 모읍니다
원인은 복합매장에 있었습니다. 한 자리, 한 매장에 여러 브랜드가 함께 들어간 경우입니다. 브랜드 A와 브랜드 B를 한 매장에서 같이 운영하는 형태를 떠올리면 됩니다.
브랜드 필터는 '이 브랜드를 포함하는 매장'을 모으는 방식으로 동작했습니다. 브랜드 A로 필터하면 A만 있는 매장뿐 아니라 A와 B가 함께 있는 복합매장도 걸립니다. 브랜드 B로 필터해도 같은 복합매장이 또 걸립니다. 결국 그 복합매장의 매출은 A 집계에도 한 번, B 집계에도 한 번, 두 번 계상됐습니다. 브랜드별로 각자 보면 아무 문제가 없어 보이지만, 셋을 합치는 순간 겹친 부분만큼 전체를 초과했습니다.

필터를 파티션으로 바꿨습니다
해결의 방향은 집계 축을 바꾸는 것이었습니다. '포함' 기준의 필터를 겹침 없는 코호트 파티션으로 바꿨습니다. 필터는 조건에 맞으면 여러 그룹에 동시에 넣지만, 파티션은 한 대상을 정확히 한 칸에만 넣습니다.
코호트를 이렇게 나눴습니다. 'A단독'은 순수하게 브랜드 A만 있는 매장, 'B단독'은 B만 있는 매장, '복합(A&B)'은 둘이 함께 있는 매장, 그리고 'C'입니다. 여기서 핵심은 귀속 규칙입니다. 복합매장에서 발생한 A 매출은 'A단독'에 얹지 않고 '복합' 코호트에 통째로 귀속시켰습니다. 'A단독'은 말 그대로 A만 있는 매장만 담고, 겹치는 것은 별도의 '복합' 칸으로 빼낸 것입니다. 그러면 어떤 매장도 두 칸에 동시에 들어가지 않습니다.
구분을 정리하면 다음과 같습니다. 같은 대상을 두고 '어떻게 모으는가'가 다릅니다.
구분 | 필터 (포함 기준) | 파티션 (구성 기준) |
|---|---|---|
기준 | 이 브랜드를 포함하면 담음 | 정확히 이 구성이면 담음 |
복합매장 | A·B 필터에 모두 걸림 | '복합' 칸에만 들어감 |
부분의 합 | 전체보다 큼 (겹침만큼 초과) | 전체와 일치 |

정합은 원 단위로 확인했습니다
파티션을 나눴다고 끝이 아니었습니다. 진짜로 겹침이 없는지는 눈으로 믿을 수 없었습니다. 각 코호트의 합계를 모두 더한 값이 전체 총계와 원 단위까지 일치하는지 대조했습니다. 백 원 단위, 천 원 단위로 반올림해서 '대충 맞네' 하고 넘어가면, 소수의 매장이 두 칸에 걸치는 미묘한 누수를 놓칩니다.
개별 코호트 합이 전체와 원 단위까지 맞아떨어질 때, 그때 비로소 진짜 상호배타 파티션이라고 말할 수 있었습니다. 이 대조는 한 번 하고 끝나는 검수가 아니라, 귀속 규칙이 바뀌거나 코호트가 추가될 때마다 돌리는 회귀 검증으로 남겼습니다.

정의는 한 곳에 뒀습니다
숫자를 맞춘 뒤에는 정의가 흩어져 있던 문제를 정리했습니다. 코호트 목록과 귀속 규칙이 화면마다 조금씩 다르게 박혀 있으면, 같은 '브랜드 A'가 매출 화면과 성장 화면에서 서로 다른 매장 집합을 가리키게 됩니다. 한 화면에서는 복합을 A에 포함하고 다른 화면에서는 빼는 식입니다.
그래서 코호트 정의를 공통 정의 한 곳으로 통일하고, 코호트를 고르는 선택 UI도 공통 프리미티브 하나로 맞췄습니다. 전년비(yoy) 비교도 같은 코호트 기준 위에서 돌게 했습니다. 작년의 'A단독'과 올해의 'A단독'이 같은 정의여야 비교가 성립하기 때문입니다. 정의가 한 곳에 있으면, 규칙을 바꿀 때도 한 곳만 바꾸면 모든 화면이 같이 따라옵니다.
다만 파티션이 만능은 아니었습니다. 세 가지 한계를 안고 갑니다. 첫째, 파티션은 '복합' 코호트를 하나 더 만듭니다. 그래서 사용자가 '복합 포함 브랜드 A 전체'를 보고 싶어 하면 'A단독'과 '복합'을 다시 합쳐야 하고, 이 목적에는 오히려 필터가 맞습니다. 둘째, 겹침 조합이 많아지면 코호트가 폭발합니다. 브랜드가 셋 넷씩 얽힌 복합까지 다 칸을 만들면 감당이 안 되므로, 의미 있는 조합만 골라 큐레이션했습니다. 셋째, '복합의 A 매출은 복합으로 귀속한다' 같은 규칙은 기술이 아니라 합의의 문제라, 현업과 먼저 맞춘 뒤에 코드로 옮겼습니다.
매출 데이터는 눈에 보이는 값만 함정이 아니었습니다. 겹쳐서 두 번 세어지는 값도, 아예 안 들어와서 조용히 비어 있는 값도 똑같이 판단을 흔듭니다. 같은 외식 ERP 매출 데이터에서 '안 들어온 값'을 오히려 신호로 삼은 사례도 함께 두면 그림이 완성됩니다.
겹치는 축은 언제나 이중계상을 부릅니다
이 문제는 브랜드에만 있는 게 아닙니다. 한 대상이 여러 그룹에 동시에 속할 수 있는 축이라면, 그 축으로 필터 집계하는 순간 이중계상이 생깁니다. 여러 태그가 달린 상품, 여러 카테고리에 걸친 고객, 여러 부서가 공유하는 비용이 모두 같은 구조입니다. 그룹별 합이 전체를 넘는 순간이 바로 그 신호입니다.
부분합이 전체와 맞기를 원한다면, '포함' 기준의 필터가 아니라 '정확히 이 구성' 기준의 파티션으로 나눠야 합니다. 겹치는 것은 별도 코호트로 빼고, 나눈 뒤에는 개별 합이 전체와 원 단위까지 맞는지 대조합니다. 그리고 그 분류 정의는 화면마다 흩어놓지 말고 한 곳에 둡니다.
의사결정 전에 짚어볼 체크리스트로 정리합니다.
브랜드(또는 그룹)별 합계가 전체 총계와 맞는지 먼저 대조한다. 합이 더 크면 이중계상 신호다.
집계 축이 '포함' 기준 필터인지, '정확히 이 구성' 기준 파티션인지 확인한다. 부분합=전체가 필요하면 파티션이다.
겹치는 대상은 '복합' 코호트로 따로 뺐는지, 귀속 규칙(복합의 매출은 어디로)이 현업과 합의됐는지 본다.
개별 코호트 합계 = 전체를 반올림 없이 원 단위로 검증한다.
코호트 정의와 전년비 기준이 화면마다 같은지, 정의가 한 곳에 모여 있는지 확인한다.