← Investigating Products
실험 기록 · AI PM 부트캠프

마이데이터를 분석하기 전에,
‘소비’부터 다시 정의했다

내 카드 내역 3년치와 핀테크 앱 리뷰 9,548건으로 확인한 것

2,780건카드·계좌 내역 (2년 7개월)
9,548건핀테크 앱 리뷰 5종
2,725,318행공공 상가정보 대조

내 카드 내역 3년치에서 한국철도공사를 검색하면 3건이 나온다.

실제로 기차에 쓴 돈은 123건, 약 550만 원이다. 44개의 다른 이름으로 흩어져 있기 때문이다. 고속철도(KTX)포항-서울, 코레일유통주식회사(, 고속철도(SRT)동대구-S수서. 노선마다 다른 이름으로 찍힌다. 출발지와 도착지가 같은 포항-포항이라는 표기도 있다. 왕복 예매를 한 건으로 처리해서 그렇다.

그런데 이 숫자도 틀렸다.

550만 원 중 약 220만 원은 취소했다. 실제로 낸 돈은 320만 원이다. 금액 기준 41%를 무른 셈이다. 그리고 취소하느라 낸 수수료가 따로 2만 9천 원 있다.

이름을 못 찾으면 있는 소비의 대부분을 놓치고,
취소를 못 세면 나머지를 41% 부풀린다.
INFOGRAPHIC 01 · 실제 지출을 다시 계산해보니
3년간 기차비로 550만 원을 쓴 줄 알았다.
처음 계산한 금액
550만 원
→
취소 거래 반영 후 실제 지출
320만 원
230만 원의 차이. 소비 습관의 문제가 아니라 데이터를 어떻게 읽느냐의 문제였다.

이 글은 저 두 문장이 어디까지 문제가 되는지 확인해본 기록이다.

00 출발

AI로 ‘새는 돈’을 찾으려 했다

지금 AI PM 부트캠프에서 MOA라는 핀테크 서비스를 만들고 있다. 사용자의 소비를 분석해 “이번 달에는 이 돈을 한번 지켜보자”고 제안하는 서비스다.

MOA가 하려는 일

AI가 소비 기록을 보고 줄여볼 만한 항목을 찾는다. 사용자는 그중 자신에게 중요한 소비는 남기고, 줄여볼 항목과 목표 금액을 직접 정한다.

소비 기록 불러오기→어디에 썼는지 분류→줄여볼 소비 찾기→한 달 목표 정하기

이 흐름에서 가장 먼저 맞아야 하는 것은 의외로 AI의 판단이 아니다. “이 돈을 어디에 쓴 돈인지”를 제대로 알아보는 일이다. 넷플릭스를 배달비로 분류하고, 취소한 기차표를 실제 지출로 세면서 “여기서 돈이 새고 있어요”라고 말하면 그다음 판단이 아무리 정교해도 소용이 없다.

프로젝트 과제에는 이런 문장이 있었다.

마이데이터 기반의 소비 패턴 분석 기준과 맞춤형 금융 상품 추천 알고리즘 기준을 정의한다.
마이데이터는 여러 금융기관에 흩어진 내 금융 정보를 한곳으로 불러와 활용할 수 있게 한 데이터다. 카드 결제, 계좌 거래 같은 기록을 서비스가 사용자의 동의를 받아 분석하는 방식이라고 생각하면 된다.

처음에는 소비 패턴을 잘 읽으면 개인화된 조언을 만들 수 있을 거라고 생각했다. 하지만 곧 질문이 바뀌었다. 소비를 해석하기 전에, 이 데이터 자체를 얼마나 믿을 수 있을까?

그래서 AI가 사람의 소비를 얼마나 잘 판단하는지를 검증하기 전에, 소비 데이터가 실제 생활을 어디까지 정확하게 담고 있는지부터 확인하기 시작했다.

01 시장

개인화된 추천을 하려면, 먼저 사용자를 알아야 한다

개인화된 추천을 하려면 먼저 사용자가 무엇을 불편해하고, 어떤 정보를 필요로 하는지 알아야 했다. 그래서 국내 핀테크 앱 5종(토스·네이버페이·카카오페이·뱅크샐러드·하나핀크)의 스토어 리뷰 9,548건을 수집해 8개 토픽으로 코딩했다.

결론부터 말하면 이렇다. 사람들은 개인화를 싫어한 게 아니었다. 대부분 ‘광고’라는 이름으로 이야기하고 있었다.

2025–2026 리뷰 9,548건 · 전체 평균 별점 2.26
토픽언급률평균 별점1–2점 비율
성능·버그28.1%1.8672.7%
광고·마케팅12.3%1.6082.2%
혜택·포인트12.1%2.1665.5%
자산조회·연동5.8%2.5652.6%
알림·푸시4.0%1.7975.5%
소비분석·분류3.0%3.1635.1%
개인정보·보안2.1%1.7080.3%
개인화·추천0.2%2.5060.0%

개인화·추천 0.2%. 9,548건 중 20건이다.

처음엔 이게 결론인 줄 알았다. “사람들은 개인화를 원하지 않는다.” 그런데 사실 원하지 않는다고 말한 적은 없고 그저 언급을 안 했을 뿐이다. 언급이 없다는 건 세 가지 중 무엇이든 될 수 있다. 원하지 않거나, 눈에 안 띄거나, 불만이 없어서 말할 이유가 없거나.

그래서 20건을 하나씩 다 읽었다. 그러자 다른 게 보였다. 그 20건의 대부분은 개인화 추천 이야기가 아니었다. “이 앱 추천 안 함” 같은 추천사(推薦辭)이거나, 광고 불만이었다.

포인트 혜택은 좋은데 광고만 2주째 나오는데 너무 지겨워요. 광고는 사용자 맞춤인가요?5★ 토스
관심없음 기능이 없어 알고리즘에 자꾸 관심 없는 상품들이 추천으로 뜹니다. 알고리즘 초기화 같은 기능을 바랍니다3★ 토스

개인화는 언급되지 않은 게 아니다. ‘광고’라는 이름으로 언급되고 있다. 그리고 그 이름의 별점이 8개 토픽 중 꼴찌다. 12.3%가 말했고, 그중 82.2%가 1–2점을 줬다.

사용자는 개인화에 대해 아주 많이 말하고 있었다.
대부분 화가 나 있었을 뿐이다.

그런데 회사는 왜 멈추지 않는가

악의가 아니라 구조다.

사용자가 앱에 내는 돈은 사실상 0이다. 토스의 유일한 B2C 과금인 토스프라임(월 5,900원)조차 규모가 공시되지 않을 만큼 작다. 내가 수집한 리뷰에서 유료 지불 의향을 밝힌 문장은 전수 검토 기준 3건이었고, 자릿수는 연 1~2만 원이었다.

매출의 대부분은 추천과 무관한 곳에서 나온다. 결제대행(PG)과 증권 위탁매매다. 그런데 한국신용평가는 토스의 2024년 창사 첫 흑자 동인을 “마진율이 높은 플랫폼 광고수익의 성장”으로 진단했다. PG 수수료는 아무리 키워도 마진이 얇다. 적자에서 흑자로 넘어가려면 앱 안의 지면을 눌러야 한다.

그리고 하나 더. 토스는 중개 수수료와 광고 매출을 각각 얼마 버는지 공개하지 않는다. 공시는 ‘컨슈머/머천트’ 두 부문까지만 쪼개주고, 그 안에서 중개와 광고는 ‘플랫폼수익’으로 합산된다.

같은 자리

사용자가 리뷰에서 개인화와 광고를 구분하지 못하는 것과, 회사가 공시에서 중개와 광고를 구분하지 않는 것. 우연이겠지만 같은 자리다.

사용자가 실제로 요구한 것

반대편도 봤다. 소비분석·분류 토픽은 언급이 3.0%로 적지만 평균 3.16★로 8개 토픽 중 1위, baseline 대비 +0.89다. 사용자가 유일하게 후하게 평가한 영역이라 285건을 다 읽었다.

고정지출 제외하고 변동 지출만 볼 수 있었으면 좋겠습니다. 총 소비에서 직접 고정 빼야 변동 알 수 있어서 불편해요4★ 토스
고정지출 금액이 커서 그래프가 크게 출렁이니 오히려 줄일 수 있는 충동지출들을 확인하는 게 어렵네요4★ 뱅크샐러드
카테고리를 2개 이상 고를 수 있으면 좋겠습니다. 필요한 소비 / 좋은 소비 / 나쁜 소비 이런 식으로 나눠서 쓰고 있는데5★ 토스

불만도 한 방향이었다. 월 달력이 주간 스크롤로 바뀐 것, 카테고리별 합계가 없어진 것, 여러 달 비교가 사라진 것. ‘예전 버전으로 되돌려달라’는 요청은 약 100건, 평균 1.9★대로 광고 불만보다 별점이 낮았다.

사용자가 요구한 건 해석의 대행이 아니라 해석의 재료였다. 세 번째 리뷰의 사용자는 이미 자기 손으로 카테고리를 ‘필요/좋은/나쁜 소비’로 나누고 있었다.

02 데이터

실제 마이데이터를 쓸 수 없어서
1,120만 건의 더미 마이데이터를 직접 만들었다

여기서 첫 번째 현실적인 문제가 생겼다. 프로젝트에서는 실제 금융사의 마이데이터를 바로 연결해 쓸 수 없었다. 실서비스 사업자가 아닌 팀이 실제 이용자의 금융 데이터를 받아 테스트하기는 어렵기 때문이다.

그래서 우리 팀은 실제 마이데이터를 대신할 더미 마이데이터를 직접 만들었다. 여기서 더미 마이데이터는 실제 금융 데이터를 흉내 내 테스트용으로 만든 가상 거래 데이터다. 단순히 이름과 금액을 무작위로 찍은 데이터는 아니었다.

약 1,120만 건5개 페르소나의 더미 마이데이터
17,000개실제 상호
3,495개전국 행정동 실제 좌표

실제 브랜드 310개와 2026년 가격 자료 569개도 섞었다. 사람마다 사는 동네와 출퇴근 동선을 만들고, 그 하루의 이동 위에 결제를 얹었다. 시간이 지나면 새로운 결제가 들어오는 것처럼 보이도록 미래 거래도 미리 만들어 두었다.

우리는 허술한 가짜 데이터를 만든 게 아니었다.
나름 현실을 닮았다고 생각한 1,120만 건을 만들었다.

그런데 그 데이터로 소비 분석 로직을 만들다가, 비교를 위해 내 카드이용내역 3년치을 넣어봤다. 그때부터 문제가 보이기 시작했다.

AI로 1,120만 건을 만드는 것과 현실을 제대로 모델링하는 것은 전혀 다른 일이었다. 우리가 만든 데이터에는 실제 카드 데이터에서 흔하게 생기는 취소, 결제대행사, 이름의 뒤섞임 같은 문제가 애초에 거의 생길 수 없었다.

API는 서비스끼리 데이터를 주고받는 약속된 통로다. 우리는 실제 금융사 API 대신 공개된 마이데이터 표준 규격—어떤 항목을 어떤 형태로 주고받는지 정한 약속—을 참고해 테스트용 서버를 만들었다.

이 글에서 분석한 실제 데이터는 카드 소비내역으로 범위를 좁혔다. 신용카드 승인 1,726건과 체크카드·후불교통 1,054건, 총 2,780건이다.

1,726건신용카드 승인내역
1,054건체크카드 결제·후불교통
2년 7개월합계 2,780건
03 실제 지출액

내 카드이용내역 3년치를 넣어보니
결과는 달랐다

소비를 분석한다고 하면 보통 “이걸 어느 카테고리로 넣을까”를 떠올린다. 그런데 실제로 데이터를 열어보니 그 앞에 훨씬 큰 문제가 있었다. 금액 자체가 맞지 않는다.

취소를 안 빼면 41% 부풀려진다

앞에서 본 철도가 그렇다. 결제 550만 원, 취소 220만 원, 실제 320만 원. 금액 기준 41%를 무른다.

취소가 가장 많은 항목이 앞에서 본 포항-포항이다. 35건 중 결제가 12건, 취소가 23건. 결제 한 건에 취소가 두 건씩 붙는다.

날짜별로 보면 패턴이 선명하다. 하루에 20만 원대 결제 한 건이 찍히고, 같은 날 5만 원대 취소가 두세 건 붙는다. 여러 날짜의 왕복표를 한꺼번에 잡아두고 필요 없는 걸 나중에 무르는 것이다.

취소를 안 빼면 이 사람은 기차에 550만 원 쓰는 사람이 된다. 그러면 “교통비를 줄이세요”라는 조언이 나간다. 실제 문제는 총액이 아니라 예매-취소를 반복하며 낸 수수료 2만 9천 원인데도.

그런데 취소는 그나마 쉬운 축이다

취소는 명세서에 음수로 찍힌다. 빼면 된다. 진짜 문제는 음수로 안 찍히는 것들이다.

계좌의 거래 기록(원장)을 열어보고 놀랐다. 출금의 94%가 소비가 아니었다. 파킹통장으로 옮긴 돈, 내 다른 계좌로 보낸 돈, 이체. 실제 소비는 6%뿐이었다. 나갔던 돈이 거의 그대로 다시 들어온다.

이걸 전부 지출로 세면 실제 소비의 여섯 배를 쓰는 사람이 된다.

그리고 이건 내 특이한 습관이 아니다. 리뷰에서 사용자들이 정확히 같은 걸 말하고 있었다.

타인 계좌로 돈을 보내면 이체가 아니라 ‘송금’으로 분류돼서 출금으로 잡힙니다3★ 뱅크샐러드
1/n을 각각 송금받는 경우 실제 지출은 전체 금액이 나간 걸로 합산됩니다4★ 토스
카카오페이머니로 결제하면 페이머니 차감과 결제가 이중지출로 찍힙니다. 오래된 문젠데 해결이 안되는 것 같습니다4★ 뱅크샐러드
콘서트 티켓 같은 것도 거액인데 친구 것도 신청하니 제 소비만 불어난 것으로 표기돼 불편3★ 뱅크샐러드

한 번의 소비가 거래 기록에 몇 줄로 들어오는가. 이게 실체다. 간편결제 이중, 승인과 출금 이중, 1/n 정산, 계좌 간 이체, 할부 승계, 그리고 취소. 소비분석 토픽이 별점 1위인데 그 안의 불만 대부분이 카테고리가 아니라 이 문제였다.

그다음에야 “무슨 업종인가”가 온다

금액이 맞아도 다음 문제가 있다. 마이데이터 카드 표준 규격에는 “이 결제가 카페인지 병원인지”를 바로 알려주는 업종 항목이 없다. 오는 건 가맹점명과 사업자등록번호뿐이고, 그마저 별도 동의를 켠 사용자에게만 온다.

그래서 서비스가 가맹점 이름과 사업자등록번호를 보고 업종을 직접 추정해야 한다. 단서는 사실상 이름과 번호 둘뿐이다.

문자열은 이렇게 생겼다. 앞에서 본 철도 44종이 그렇고, 배달의민족으로 검색하면 0건이 나오는 것도 그렇다. 실제로는 39건이 있는데 법인명 ‘우아한형제들’로, 그것도 다섯 가지 표기로 흩어져 있다. 택시는 298건이 190개의 서로 다른 이름으로 기록돼 있다. 대부분이 카카오택시-경북15바7177 같은 차량번호판이라 사실상 전부 고유값이다.

가맹점명이 너무 다양하게 흩어지는 문제

고유 서로 다른 가맹점명 1,441개 중 1,090개(75.6%)가 딱 한 번만 등장하고, 그 1회성 이름들이 거래의 39.2%를 차지한다.

그럼 숫자는 어떤가. 나는 처음에 사업자번호면 확실할 거라고 생각했다. 이름은 제각각이어도 번호는 하나일 테니까.

택시에서는 그 생각이 맞았다. 188개 이름이 사업자번호 3개로 깔끔하게 정리된다.

그런데 배달의민족에서는 정반대였다. 한 회사가 사업자번호 5개로 흩어진다.

그리고 온라인 결제에서는 더 이상한 일이 생겼다. 넷플릭스도, 배달의민족도, 맥도날드도 데이터에서는 같은 회사처럼 보일 수 있었다.

INFOGRAPHIC 02 · 실제 데이터를 넣자 보인 세 가지 문제
거래 기록을 그대로 ‘소비’라고 부를 수 없었다.
01
같은 곳에서 썼는데 이름이 달랐다
카드에 찍힌 이름 ≠ 실제 소비처
‘한국철도공사’ 검색3건 → 실제 123건
02
돈이 빠져나갔다고 모두 소비는 아니었다
출금 ≠ 소비
내 계좌 출금 내역 중94%는 소비 아님
03
다른 곳에서 썼는데 같은 회사로 보였다
결제한 회사 ≠ 실제 소비처
넷플릭스 · 배달 · 외식 · 주차같은 PG 사업자번호
분석보다 먼저, 무엇을 ‘소비’로 볼 것인지 정의해야 했다.
실제 소비 vs 데이터에 기록된 소비

결제한 곳은 다른데, 데이터에 찍힌 회사는 같았다.

사용자는 서로 다른 서비스를 이용했지만, 결제대행사를 거치면서 여러 거래가 같은 사업자번호 아래 묶였다.

내가 실제로 쓴 곳
넷플릭스OTT · 콘텐츠
배달의민족배달 · 식비
맥도날드외식 · 식비
주차장 서비스교통 · 주차
→
데이터가 본 것
같은 결제대행사(PG) 사업자번호

서로 다른 소비가 하나의 회사 아래 묶여, 사업자번호만으로는 내가 무엇에 쓴 돈인지 알 수 없었다.

PG(Payment Gateway)는 온라인 카드 결제를 중간에서 대신 처리하는 결제대행사다. 가게가 카드사와 직접 연결되는 대신 PG사가 중간에서 결제를 처리하고, 명세서에는 실제 이용한 가게가 아니라 이 중간 회사의 사업자번호가 찍히기도 한다.

실제 데이터에서는 사업자번호 하나에 넷플릭스·배달의민족·맥도날드·주차장 서비스 등 27종의 가맹점명이 붙었고, 또 다른 번호에는 네이버페이·배달의민족·올리브영·영화관 등 22종이 묶였다.

사업자번호 486개 중 32개(6.6%)에 복수 가맹점명이 붙어 있고, 그 32개가 거래의 59.9%를 차지한다. 예외가 아니라 절반이다.

그래서 낭비 판정은 시작도 못 한다

MOA의 낭비 판정은 “술은 낭비, 병원은 필수”처럼 품목에 도덕적 낙인을 찍는 방식이 아니다. 설명 가능한 모델(EBM)이 소비 유형, 평소 대비 금액 배수, 심야 여부, 재량 소비 성향 등을 함께 보고 확률을 만든다. 최신 모델에서 영향력이 큰 순서도 이 네 항목이다. 절대 금액 자체의 영향은 상대적으로 작다.

예를 들어 평소 카페에서 5천 원을 쓰던 사람이 새벽 2시에 3만 원을 결제했다면 ‘카페라서’가 아니라 평소보다 6배 크고, 심야에 발생했다는 맥락이 함께 작동한다. 반대로 의료·주거처럼 생존에 가까운 소비는 큰 금액이어도 쉽게 낭비로 보지 않는다.

문제는 모델보다 앞단이었다. 이런 판단을 하려면 먼저 “무슨 소비인가”, “언제 썼나”, “평소보다 얼마나 큰가” 같은 입력이 믿을 만해야 한다. 그래서 모델을 돌리기 전에 확인할 게 있었다. 이 판단에 필요한 단서들이 실제로 손에 들어오는가.

모델이 틀린 게 아니다.
판단에 필요한 단서를 충분히 받지 못한다.
04 골격

소비 데이터는 어디까지 나를 알 수 있을까?

단서가 부족하다는 게 아무것도 못 본다는 뜻은 아니었다. 카테고리를 포기하고 시간·순서·반복·지역만으로 다시 봤더니 이런 게 나왔다.

두 개의 거점. KTX 서울–포항 노선이 반복되고, 택시 번호판 지역이 경북과 서울로 갈리고, 포항 소재 가맹점이 200건 넘게 찍힌다. 서로 다른 세 종류의 데이터가 같은 결론을 가리킨다.

그리고 번호판이 뜻밖의 역할을 했다. 처음에는 쓸모없는 정보처럼 보였던 차량번호가 사실은 지역을 알려주는 단서였다.

택시 — 번호판 지역별
지역건수건당 평균
경북1078,102원
서울7314,707원
경북
8,102원
서울
14,707원

같은 ‘택시’인데 두 도시에서 성격이 다르다. 서울 택시가 거의 두 배 비싸다. 하나는 도시 안 짧은 이동이고 하나는 더 긴 이동이다.

자차 없음. 주유 결제가 사실상 없고 택시·KTX·후불교통이 반복된다.

그리고 그 거점에는 시작과 끝이 있다.

연도별 출현
202420252026
경북 번호판 택시0건107건0건
포항 소재 가맹점3건167건0건
2024경북 택시 0건 · 포항 가맹점 3건
2025경북 택시 107건 · 포항 가맹점 167건
2026경북 택시 0건 · 포항 가맹점 0건

2025년 한 해에만 존재한다. 1분기에 솟아서 3분기에 정점을 찍고 연말에 꺼진다. 데이터는 이 사람의 다거점 생활이 언제 시작해서 언제 끝났는지를 정확히 안다.

실제로 나는 2025년에 포항에서 애플 디벨로퍼 아카데미를 다녔다. 데이터가 맞췄다.

다만 아카데미라는 건 못 맞췄다. 그건 카드 명세서 어디에도 없다.

구독 탐지는 세 번 시도해서 세 번 다르게 틀렸다

리서치 자료에는 “룰 기반 반복결제 탐지는 정밀도 90% 이상”이라고 적혀 있었다. 내 데이터에서는 그렇지 않았다.

1차 — 가맹점명 단위로 30일 주기를 찾았다. 넷플릭스는 정확히 잡혔다. 31건, 간격 31일, 22,000원 고정. 그런데 후불교통대금이 같이 걸렸다. 간격이 30일로 규칙적이라서다.

후불교통대금은 구독이 아니다. 지하철 요금 수십 건을 월말에 묶은 청구서다. 넷플릭스는 안 봐도 22,000원이 나가지만 후불교통은 안 타면 안 나간다. 주기가 같아도 성격이 다르다. 이걸 고정비로 분류하면 사용자가 줄일 수 있는 돈이 줄일 수 없는 돈으로 보인다. 리뷰에서 사용자들이 화냈던 바로 그 문제다.

반대로 Apple 43건은 놓쳤다. 금액이 14,000 / 2,500 / 3,300원으로 쪼개져 있어서다. 애플은 판매자가 아니라 결제 창구다. 한 이름 안에 iCloud 구독과 앱 결제와 하드웨어가 섞여 있다.

2차 — 묶는 단위를 ‘가맹점명’에서 ‘가맹점명 + 금액’으로 바꿨다. 그러자 Apple 안에 숨어 있던 iCloud 14,000원이 17건, 30일 간격으로 나왔다. 이름만으로는 절대 안 걸리던 게 금액을 붙이니 바로 잡혔다.

후불교통대금은 자동으로 빠졌다. 30건 중 금액 종류가 29개라, 이름+금액으로 묶는 순간 각 그룹이 1건이 되어 조건에 안 걸린다. 규칙을 따로 만든 게 아니라 단위를 바꾸니 저절로 풀렸다.

대신 새 오탐이 생겼다. 어떤 항목은 간격 중앙값만 33일이지 실제로는 들쭉날쭉했다. 3차 — 간격이 얼마나 일정한지를 조건에 추가했더니 그것만 떨어졌다.

시도넷플릭스후불교통대금Apple부동산 관련
1차 · 이름 단위잡힘오탐놓침—
2차 · 이름+금액잡힘자동 제외잡힘오탐
3차 · 간격 일정성 추가잡힘제외잡힘제외

세 번 시도해서 세 번 다르게 틀렸다. 하나는 성격을 착각했고(청구서를 구독으로), 하나는 단위를 잘못 잡았고(한 이름 안에 여러 구독), 하나는 새로 만든 규칙이 새 오탐을 낳았다.

05 경계

데이터로 읽히는 건 골격까지다

읽힌 것과 안 읽힌 것을 나란히 놓으면 경계가 뚜렷하다.

관찰 사실여기까지 읽힌다여기부터 안 읽힌다
두 도시 KTX·택시 반복두 도시를 오간다왜 오가는가
같은 미용실 3년 10건단골이다왜 단골인가
특정 대학 가맹점 30여 건이 학교와 관련 있다학생인가 교수인가 방문객인가
예매의 41%를 취소취소를 반복한다낭비인가, 불확실한 일정에 대한 보험료인가

패턴이 하나로 모인다. 데이터는 “무엇을 반복하는가”까지 주고, “그게 누구이며 왜인가”는 안 준다.

세 번째 줄이 특히 중요하다. 학생인지 교수인지 방문객인지에 따라 소득 구조 추정이 통째로 갈린다. 그런데 데이터는 그걸 안 준다. 알고 싶으면 방법은 하나뿐이다. 물어보는 것.

그리고 층마다 요구되는 정확도가 다르다

여기서 설계에 직접 쓸 수 있는 게 나왔다. 거래를 해석하는 일은 한 겹이 아니라 여러 겹이고, 겹마다 필요한 정확도가 다르다.

층판단 단위요구 정확도틀리면
실제 지출액 맞추기거래 1건매우 높음금액이 통째로 틀림
카테고리 분류거래 1건높음사용자에게 바로 들킴
생활 패턴 찾기기간 내 반복중간신호가 겹쳐 상쇄됨
사람의 이유까지 해석하기——정확해도 하면 안 됨

아래로 갈수록 요구 정확도는 낮아지는데 위험은 반대로 올라간다. 카테고리는 틀려도 사용자가 고치면 되지만, 해석은 정확할수록 불쾌해진다.

그리고 가장 아픈 건 맨 윗줄이다. 가장 정확해야 하는 층이 가장 못 푸는 층이다.

정산에는 원리적 한계가 있다. 취소는 음수로 찍히니 뺄 수 있고, 내 계좌 간 이체는 양쪽이 다 내 계좌라 알 수 있고, 간편결제 이중 기록은 같은 금액·같은 날이라 짝을 찾을 수 있다. 여기까지는 거래 기록 안에서 서로 짝을 찾을 수 있다.

그런데 친구들과 밥을 먹고 내 카드로 3인분을 결제한 뒤 2인분을 계좌로 돌려받으면? 카드 명세서에는 3인분이 찍히고, 계좌에는 친구 이름으로 입금이 찍히고, 둘을 잇는 정보는 어디에도 없다. 금액도 안 맞고 날짜도 안 맞는다.

이건 더 좋은 알고리즘으로 풀리는 문제가 아니다. 데이터에 정보가 없다. 결제되지 않은 것이 데이터가 아니듯, 결제됐다가 되돌아온 돈도 그 되돌아옴이 원장에 안 남으면 데이터가 아니다.

그리고 골격이 신뢰할 만한 이유는 여러 신호가 겹치는 지점에서만 만들어지기 때문이다. 거점은 KTX와 택시 번호판과 지역 가맹점 셋이 동시에 가리켰다. 해석은 하나의 신호를 늘여서 만든다. 그래서 골격은 정확하고 해석은 부정확하다. 우연이 아니라 구조적이다.

거래 데이터만으로 읽을 수 있는 건 생활의 골격까지다.
그 소비가 왜 중요한지는 데이터 밖에 있다.
06 다음 개인화

생활의 골격 다음에는,
사용자의 맥락이 필요하다

생활의 골격만으로도 가능한 추천은 있다. 두 도시를 정기적으로 오간다는 사실만 알면 철도 할인 상품을 제안할 수 있다. 왜 오가는지까지 몰라도 상품 조건은 달라지지 않는다.

하지만 MOA가 하려는 건 여기서 한 걸음 더 나아간다. 사용자에게 무엇을 줄여볼지 제안하려면, 그 사람이 무엇을 중요하게 생각하는지도 알아야 한다.

같은 카페 지출도 누군가에게는 줄이고 싶은 소비지만, 누군가에게는 하루를 버티게 해주는 작은 즐거움일 수 있다. 몇 달째 보지 않는 OTT는 새는 돈일 수 있지만, 매일 야구 중계를 보는 사람에게는 쉽게 포기할 수 없는 소비다.

거래 데이터만으로는 이 차이를 알기 어렵다. 그렇다고 AI가 그 이유까지 그럴듯하게 추측하게 하고 싶지는 않았다.

데이터가 말하는 것과 사용자가 알려줘야 하는 것
카페에 자주 쓴다거래 데이터로 확인 가능한 사실
평소보다 많이 쓴 날이 있다반복과 금액으로 계산 가능
카페를 줄이고 싶을 것이다데이터만으로는 알 수 없는 추정
커피는 포기할 수 없다사용자만 알고 있는 가치와 맥락
앞의 두 칸은 데이터가 알려준다. 뒤의 두 칸은 서비스가 추측할 게 아니라, 사용자가 자연스럽게 알려줄 수 있어야 한다.

개인화가 잘 된 서비스는 사용자가 매번 자신의 취향을 길게 설명하지 않아도 점점 나를 더 잘 이해한다. 음악 서비스가 내가 반복해서 듣는 곡과 직접 선택한 취향을 함께 쌓아 새로운 음악을 추천하듯, MOA도 거래 데이터와 사용자 인풋을 함께 보며 소비의 의미를 알아가는 방식을 고민하고 있다.

첫 번째 시도는 ‘성역 설정’이다

그렇다고 처음부터 “당신에게 가장 중요한 소비는 무엇인가요?”라고 긴 설문을 받고 싶지는 않았다. 서비스를 쓰는 과정에서 자신의 기준을 자연스럽게 알려줄 수 있어야 했다.

그래서 만든 첫 번째 장치가 성역 설정이다. MOA가 최근 소비를 분석해 줄여볼 만한 카테고리를 보여주면, 사용자는 그중 “이건 줄이고 싶지 않다”고 생각하는 소비를 성역으로 지정할 수 있다.

사용자 인풋이 개인화 정보가 되는 순간
절약 후보
카페 배달 쇼핑 취미
→
내가 지킬 소비
성역으로 지정한 소비
“카페는 줄이고 싶지 않아요”라는 한 번의 선택이, 이 사람의 가치 소비를 이해하는 명시적 인풋이 된다.

겉으로 보면 절약 대상에서 특정 카테고리를 제외하는 기능이다. 하지만 서비스 입장에서는 중요한 사용자 인풋이 하나 생긴다.

이 사람은 어디에 돈을 쓰는 것을
가치 있다고 생각하는가?

성역 설정은 단순한 예외 처리가 아니라, 사용자의 가치 소비가 어디에 방점이 찍혀 있는지 알아가기 위한 첫 번째 시도다.

그래서 지금 개인화의 단계를 이렇게 보고 있다.

  1. 카테고리 합산소비 현황
    카페·교통·쇼핑처럼 어디에 얼마를 썼는지 묶어 보여준다.
  2. 생활의 골격 찾기데이터가 잘하는 일
    반복되는 이동, 고정지출, 자주 쓰는 카테고리처럼 여러 거래가 함께 가리키는 생활 패턴을 읽는다.
  3. 사용자 맥락 이해하기다음 탐구
    왜 이 소비가 중요한지는 추측하지 않는다. 성역 설정처럼 UX 안에서 자연스럽게 받은 사용자 인풋으로 그 의미를 조금씩 알아간다.
07 자기 발견

1,120만 건으로도 발견하지 못한 이유

이 실험을 하면서 가장 뼈아픈 걸 발견했다. 데이터 양이 부족했던 게 아니었다.

약 1,120만 건을 만들었지만, 우리가 만든 더미 마이데이터에는 이 문제가 애초에 존재할 수 없었다.

더미 마이데이터를 만들 때는 먼저 “이 사람이 어떤 소비를 한다”는 상황을 정하고 → 업종을 정하고 → 그 업종의 가게를 고른 뒤 → 마지막에 사업자번호를 붙였다. 업종이 원인이고 사업자번호가 결과다. 그래서 한 번호에 여러 업종이 달리는 상태가 애초에 생기지 않는다. 시각도 100%, 업종코드도 100% 채워진다.

즉 우리는 문제가 생길 수 없는 세계에서 테스트하고 있었다. 실제 카드 내역을 넣어보고서야 알았다.

그리고 지금 실데이터를 넣으면 어떻게 되는지도 확인했다. 업종 칸이 비어 있으니 전부 미분류로 떨어지고 소비를 판단하는 프로그램이 조용히 멈춘다. 화면이 깨지거나 오류 메시지가 뜨는 것도 아니다. 그냥 아무 판단도 내리지 않는다.

반대로 업종이나 사업자번호를 채워 넣기 시작하면, 그 순간 그 60%가 잘못된 카테고리로 분류될 수 있다. PG 사업자번호 하나가 넷플릭스와 배민과 맥도날드를 한 가맹점으로 묶으면서, 사용자가 넷플릭스에 “이건 낭비 아니에요”를 한 번 누르면 같은 결제대행사를 거친 배달·외식 결제까지 “낭비가 아닐 가능성이 높다”고 잘못 배우게 된다. 사용자는 자기가 뭘 했는지 모른다.

눈에 띄는 오류는 없고 숫자만 조용히 틀린다.
이게 이 문제의 진짜 무서운 점이다.
08 설계

‘잘 맞히는 것’보다 ‘틀리지 않는 것’부터

금융 데이터가 주는 건 결국 가맹점 이름과 사업자번호 같은 원재료다. 그걸 “카페”, “교통”, “배달”처럼 사람이 이해할 수 있는 소비 카테고리로 바꾸는 건 서비스를 만드는 쪽의 일이다.

MOA의 15개 소비 유형은 식비 · 교통/자동차 · 의료 · 금융/보험 · 주거/통신 · 카페/간식 · 술/유흥 · 쇼핑 · 취미/여가 · 생활 · 미용 · 건강/피트니스 · 여행/숙박 · 대형마트 · 편의점/잡화다. 카테고리 미분류은 15개 중 하나가 아니라, 무엇에 쓴 돈인지 끝내 확신할 수 없을 때 남겨두는 별도 상태다.
INFOGRAPHIC 03 · 실제 데이터 검증 후 바뀐 소비 분석 구조
모델을 바꾼 게 아니라, 판단하기 전에 확인할 것을 늘렸다.
BEFORE
거래 발생
→
마이데이터 유입

1-1. 카테고리 분류

가맹점명·사업자정보
↓
LLM 분류
↓
15개 소비 유형 중 하나

1-2. 낭비 판정

사용자 통계 생성
↓
11개 특징 추출
↓
EBM 점수 합산
↓
기준선 0.274
→
AFTER
거래 발생
→
마이데이터 유입

1-1. 카테고리 분류 신뢰도 추가

가맹점명 우선 확인
↓
사업자번호는 검증 신호
↓
공공 상가정보 교차 확인
↓
근거가 약하면 ‘카테고리 미분류’

1-2. 낭비 판정 신뢰 우선

분류 가능한 거래만
↓
사용자 통계 + 11개 특징
↓
EBM 점수 + 이유 공개
↓
기준선 0.479
↓
사용자 정정·보호 우선
더 똑똑한 모델을 만드는 것보다, 믿을 수 있는 판단 구조를 만드는 쪽을 택했다.

왜 업종코드 하나만 봤나

처음부터 게을렀던 게 아니다. 이전 방식이 실제로 문제를 냈고, 그걸 고치다 나온 결과였다.

예전에는 데이터 제공자가 소비 카테고리를 직접 붙여서 넘겼다. 식비 · 카페/간식 · 편의점 · 쇼핑 · 생활 · 여가 · 온라인 일곱 가지였는데, 여기 이상한 게 섞여 있다. ‘온라인’은 결제 수단이고 나머지는 업종이다. 한 목록에 두 축이 들어가 있었다.

그래서 이런 일이 벌어졌다. 지하철 요금이 ‘온라인’으로 분류됐다. 그리고 배달을 줄이는 챌린지를 걸면 지하철 요금까지 한도에 잡혔다.

축을 갈라야 했다. 그래서 통계청의 표준산업분류(KSIC)를 가져왔다. 전국의 사업체가 어떤 업종인지 같은 기준으로 구분하기 위한 국가 표준이다. 제공자는 “이 가게가 무슨 업종인가”까지만 말하고, “이 소비가 사용자에게 무엇인가”는 앱이 정한다. 실제 마이데이터도 그렇게 동작한다.

판단은 옳았다. 부수 효과도 좋았다. KSIC는 국가 표준이라 공공 상가정보와 연결할 수 있다. 가맹점명이 제각각이라 한 번씩만 등장하는 가게가 많아도, 약 270만 건의 상가정보와 대조해 업종을 추정할 수 있었던 이유다.

그런데 축을 가르는 것과, 업종코드 하나만 보는 것은 다른 얘기였다.

그 뒤로 가맹점명과 사업자번호는 저장만 하고 판단에 쓰지 않게 됐다. 대조표도 더미 생성기가 쓰던 원천 열한 개에서 역으로 자라 47개에서 멈췄다. 그러다 실제 카드 명세서를 넣어보니 업종코드 칸 자체가 없었다.

옳은 결정이 한 걸음 더 갔을 뿐이다.
되돌릴 것도 한 걸음이다.

이름이 코드를 이겨야 하는 이유

GS25 울릉크루즈점이라는 결제가 있었다. 울릉도 가는 배 안의 편의점이다.

이 결제의 사업자번호는 배를 운영하는 회사 것이다. 업종코드만 보면 ‘운송’으로 간다. 배 안에서 산 컵라면이 교통비가 되는 것이다.

카드 가맹점 정보가 사업자번호 기준이라, 입점 매장은 모(母)사업자의 업태를 그대로 상속한다. 병원 안 편의점, 휴게소 매장, 백화점 입점 브랜드가 전부 같다. 예외가 아니라 구조적으로 계속 나온다.

그런데 이름을 보면 한 번에 풀린다. GS25는 편의점이다.

그리고 앞에서 본 배달의민족이 정확히 거울상이다.

울릉크루즈배달의민족
구조번호 1개 → 이름 2종이름 1종 → 번호 5개
원인입점 매장이 모사업자 업태 상속결제마다 다른 결제대행사(PG)를 거침
번호를 믿으면편의점이 운송이 된다배달앱이 다섯 조각으로 갈린다
이름을 보면편의점식비 한 덩어리

방향이 반대인데 해법이 같다. 그래서 “번호를 믿으면 안 되는” 그 59.9% 구간의 89%가 이름 한 축으로 풀린다. 결제대행사를 거쳐도 가맹점 이름에는 실제 브랜드가 남는 경우가 많기 때문이다.

가맹점명을 업종코드보다 먼저 보는 것. 이 순서 하나로 거래의 71.2%가 잡혔다.

사업자번호는 버리는 게 아니라 역할이 바뀐다

그럼 번호는 쓸모가 없나. 아니다.

GS25 울릉크루즈점이 이름으로 편의점이라고 풀리는 순간, 그 답은 같은 번호의 업종(운송)과 충돌한다. 이 번호가 여러 업태를 담고 있다는 증거다. 그러면 같은 번호를 쓰는 다른 결제들에 “근거가 얇다”고 표시한다.

주의할 게 있다. 같은 번호의 다른 이름을 따라가면 안 된다. 그러면 배를 운영하는 회사가 편의점이 된다. GS25가 하는 일은 답을 주는 게 아니라 번호를 검증하는 것이다.

즉 사업자번호는 “무슨 업종인가”가 아니라 “믿을 수 있는 번호인가”에 쓴다.

전부 막으면 과하기도 하다. 어느 교통카드 정산사업자 번호에는 이름이 75종 붙어 있는데 그중 74종이 택시와 버스다. 이런 번호는 믿어도 안전하다. 기준은 “이름이 여럿인가”가 아니라 “아는 이름이 번호의 업종과 충돌하는가”다.

우리 대조표가 정답을 지우고 있었다

이름을 모르면 공공 상가정보 270만 행에 상호로 대조하는 관문을 하나 더 붙였다.

그런데 여기서 이상한 걸 발견했다. 상가정보가 정확히 맞혔는데 우리가 받을 칸이 없어서 버린 경우가 있었다.

우리 대조표에는 약국 → 4781 → 의료라고 적혀 있었다. 만들 때는 참이다. 약국은 4781이 맞다. 그런데 쓸 때는 거짓이다. 4781의 정식 명칭이 “의약품·의료용 기구·화장품·방향제 소매업”이기 때문이다.

KSIC 4781 · 전국 58,640곳
26,274 47811 의약품 및 의료용품 소매업 ← 약국 26,215 47813 화장품; 비누 및 방향제 소매업 ← 여기가 통째로 ‘의료’로 6,151 47812 의료용 기구 소매업

거의 반반이다. 화장품 브랜드 매장이 통째로 ‘의료’로 간다. 한 건이 재수 없게 걸린 게 아니라 원래 절반이 틀리는 자리였다.

그리고 여기에 우리 실수가 하나 더 겹쳐 있었다. 업종코드를 앞 네 자리만 잘라 썼다. 그 정도면 우리 카테고리는 나오겠거니 했다.

그런데 잘린 자리에 답이 있었다. 앞 네 자리만 보면 셋이 하나가 되고, 화장품 가게가 약국과 같은 칸에 앉는다. 코드를 자르는 순간 절반이 자리를 잘못 찾는다.

같은 구조의 자리가 더 있다. 편의점과 슈퍼마켓이 한 앞자리에 있고, 헬스장과 당구장과 골프연습장이 한 앞자리에 있다. 그래서 코드를 자르지 않고 끝까지 받는 것으로 바꿨다.

더 근본적으로는, 우리 47개 코드가 덮는 점포가 전국의 59.3%다. 나머지 40.7%는 칸 자체가 없다.

그리고 모든 사용자에게 공통으로 적용하는 하나의 정답은 만들지 않기로 했다

펀엔펀이라는 가게가 있다. 작년에 포항에 있을 때 가끔 가던, 팝콘을 주는 술집이다.

그런데 상가정보에는 커피 전문점으로 등록돼 있다.

처음엔 “원천 데이터가 틀렸다”고 생각했다. 그런데 아니었다. KSIC는 통계 분류라 주된 활동 하나만 찍는다. 그리고 일반음식점으로 신고했다면 커피도 술도 밥도 다 합법이다. 낮엔 카페, 밤엔 바로 도는 가게는 흔하다.

그래서 사용자가 고친 답을 모두의 답으로 올리려던 계획을 접었다.

낮에 커피를 마신 사람에게 그곳은 카페다.
밤에 술을 마신 사람에게는 술집이고,
파스타를 먹은 사람에게는 식당이다. 셋 다 참이다.

모든 사용자에게 공통으로 적용하는 하나의 정답은 한 사람의 이용 맥락을 모두의 정답으로 못박는 일이 된다. 그래서 교정은 개인 것으로만 둔다.

결과

단계카테고리 미분류 (금액 비중)
시작 — 업종코드만46.0%
+ 브랜드 이름45.8%
+ 사용자 확인 13종43.3%
+ 상가정보, 근거 2곳 이상만40.4%

줄어든 폭보다 중요한 게 있다. 근거 1곳짜리를 다 믿으면 32.3%까지 떨어지는데, 그렇게 하지 않았다. 실제로 채점해보니 근거가 1곳뿐인 건은 절반이 틀렸고, 2곳 이상은 아직 틀린 적이 없다.

그래서 “확정”이라는 한 단어로 둘을 묶지 않기로 했다. 카테고리는 정석대로 채우되, 그 답이 어디서 왔고 근거가 얼마나 두꺼운지를 따로 기록한다. 그리고 낭비 판정과 절약 후보는 이 값을 본다.

78.3%믿을 만한 것
21.7%확인이 필요한 것 (금액 26.5%)
“모른다”를 숫자로 들고 있는 것이,
46%가 조용히 사라지는 것보다 낫다.
09 결론

결국, 질문이 한 번 더 바뀌었다

처음에는 “AI가 얼마나 정확하게 소비를 판단할 수 있을까?”를 고민했다.

실제 카드이용내역을 넣어본 뒤에는 “우리가 가진 데이터만으로 어디까지 판단해도 될까?”로 질문이 바뀌었다.

그리고 지금은 여기서 한 걸음 더 나아가고 있다.

데이터만으로 알 수 없는 사용자 맥락을
어떻게 자연스럽게 이해할 수 있을까?

취소한 결제를 제대로 빼고, 같은 소비를 찾아 묶고, 무엇에 쓴 돈인지 정확하게 분류하는 일은 여전히 중요하다. 그 기반이 흔들리면 개인화도 흔들린다.

하지만 거래를 제대로 읽는 것과 사람을 제대로 이해하는 것은 다른 문제였다.

소비 데이터는 반복되는 이동과 결제, 자주 찾는 장소와 카테고리를 통해 생활의 골격을 꽤 잘 보여준다. 반면 왜 그 소비를 포기할 수 없는지, 무엇에는 기꺼이 돈을 쓰고 싶은지까지 알려주지는 않는다.

그래서 그 빈칸을 AI의 추측으로 채우기보다, 사용자가 서비스를 쓰는 과정에서 자신의 맥락을 자연스럽게 알려줄 수 있는 UX를 고민하고 있다.

성역 설정은 그 첫 번째 시도다. 앞으로는 사용자의 정정, 반복되는 선택, 챌린지 결과처럼 서비스 안에서 자연스럽게 생기는 행동을 통해 소비의 맥락을 조금씩 이해할 수 있는 방법도 더 실험해보려 한다.

아직 답을 찾은 것은 아니다. 오히려 질문이 하나 더 생겼다.

마이데이터를 분석하기 전에,
‘소비’부터 다시 정의했다.

그리고 소비를 제대로 읽고 나니, 다음에는 그 소비가 사용자에게 어떤 의미인지 이해해야 했다.

사용자에게 계속 물어보지 않으면서도,
어떻게 하면 이 사람의 소비 맥락을 조금 더 잘 이해할 수 있을까?

이 글의 한계

마이데이터가 실제로 어떻게 생겼는지 너무 궁금하다. 알려주실 분은 안 계시겠죠?