이 글은 누구를 위한 것인가
- 서비스 메뉴 구조가 "우리 논리"가 아닌 "사용자 논리"로 설계됐는지 의심하는 팀
- 카드 소팅을 처음 해보고 싶은 UX 리서처
- 사이트 리뉴얼 시 정보 구조를 재설계해야 하는 팀
들어가며
"이 메뉴가 어디 있는지 도저히 못 찾겠어요" — 이것은 정보 구조(IA) 실패다. 우리 팀의 논리로 메뉴를 만들면 사용자가 찾을 수 없다. 카드 소팅은 사용자가 정보를 어떻게 분류하는지 직접 데이터로 확인하는 방법이다.
이 글은 bluefoxdev.kr의 UX 리서치 방법론 를 참고하여 작성했습니다.
1. 정보 구조 설계 프로세스
[IA 설계 단계]
1단계 - 콘텐츠 인벤토리:
현재 서비스의 모든 페이지·기능 목록화
스프레드시트에 URL + 제목 + 카테고리 정리
2단계 - 카드 소팅 (사용자 리서치):
오픈 카드 소팅: 사용자가 자유롭게 그룹화
클로즈드 카드 소팅: 미리 정의된 카테고리로 분류
하이브리드: 기존 카테고리 + 새 카테고리 추가 가능
참여자: 최소 15-20명 (유사도 매트릭스 의미 있음)
도구: Maze, Optimal Workshop, Miro
3단계 - 유사도 매트릭스 분석:
같은 그룹에 넣은 빈도 → 함께 배치
다른 그룹에 넣은 항목 → 분리 또는 중복 배치
4단계 - 사이트맵 초안:
리서치 결과 기반 계층 구조 설계
5단계 - 트리 테스트:
"이 작업을 수행하려면 어디로 가시겠습니까?"
실제 찾기 성공률 측정
6단계 - 반복:
성공률 낮은 항목 재배치
2. 카드 소팅 분석
import pandas as pd
import numpy as np
from scipy.cluster.hierarchy import linkage, fcluster
import matplotlib.pyplot as plt
def analyze_card_sorting(sorting_data: list[dict]) -> dict:
"""
카드 소팅 데이터 분석
sorting_data: [{"participant": "P1", "card": "주문 내역", "group": "마이페이지"}]
"""
df = pd.DataFrame(sorting_data)
# 카드별 공동 분류 빈도 매트릭스
cards = df["card"].unique()
n = len(cards)
card_to_idx = {card: i for i, card in enumerate(cards)}
co_occurrence = np.zeros((n, n))
# 같은 참여자가 같은 그룹에 넣은 카드 쌍 카운트
for participant, group_df in df.groupby("participant"):
for group, cards_in_group in group_df.groupby("group")["card"]:
cards_list = cards_in_group.tolist()
for i in range(len(cards_list)):
for j in range(i + 1, len(cards_list)):
idx_i = card_to_idx[cards_list[i]]
idx_j = card_to_idx[cards_list[j]]
co_occurrence[idx_i][idx_j] += 1
co_occurrence[idx_j][idx_i] += 1
# 총 참여자 수로 정규화 (0-100%)
n_participants = df["participant"].nunique()
similarity_matrix = (co_occurrence / n_participants * 100).round(1)
# 군집 분석
distance_matrix = 100 - similarity_matrix
Z = linkage(distance_matrix, method="ward")
clusters = fcluster(Z, t=3, criterion="maxclust") # 3개 그룹으로
# 결과 정리
card_clusters = {}
for i, card in enumerate(cards):
cluster_id = clusters[i]
if cluster_id not in card_clusters:
card_clusters[cluster_id] = []
card_clusters[cluster_id].append(card)
return {
"similarity_matrix": similarity_matrix,
"suggested_groups": card_clusters,
"n_participants": n_participants,
}
def find_problematic_labels(tree_test_results: list[dict]) -> list[dict]:
"""트리 테스트에서 실패율 높은 경로 찾기"""
df = pd.DataFrame(tree_test_results)
# 각 태스크별 성공률
task_success = df.groupby("task_id").agg(
success_rate=("success", "mean"),
avg_time=("time_seconds", "mean"),
first_click_correct=("first_click_correct", "mean"),
).reset_index()
# 성공률 50% 미만인 태스크
problematic = task_success[task_success["success_rate"] < 0.5]
return problematic.to_dict("records")
마무리
카드 소팅에서 가장 가치 있는 인사이트는 "이것과 저것이 같은 그룹에 있어야 하는지"다. 주문 내역이 마이페이지 하위인지, 주문 하위인지 — 사용자 15명의 데이터가 어떤 주장보다 강력하다. 트리 테스트로 IA 초안을 검증하면 출시 후 "찾기 어렵다" 피드백을 크게 줄일 수 있다.