본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 16. · 14 Views
커피숍 월별 매출 리포트 미니 프로젝트
실제 커피숍 매출 데이터를 분석하여 월별 트렌드를 파악하고 베스트셀러 상품을 찾아내는 실무 프로젝트입니다. pandas와 matplotlib을 활용한 데이터 분석의 기초를 배울 수 있습니다.
목차
1. 프로젝트 목표 설정
어느 날 김개발 씨는 동네 카페 사장님으로부터 연락을 받았습니다. "매출 데이터가 쌓여 있는데, 이걸 어떻게 분석해야 할지 모르겠어요." 사장님은 월별로 어떤 상품이 잘 팔리는지, 매출 추이는 어떤지 알고 싶어 했습니다.
데이터 분석 프로젝트는 명확한 목표 설정에서 시작됩니다. 커피숍 매출 데이터를 활용하여 월별 매출 추이, 인기 상품, 계절별 트렌드를 파악하는 것이 이번 프로젝트의 목표입니다.
이를 통해 사장님이 실질적인 경영 의사결정을 할 수 있도록 돕습니다.
다음 코드를 살펴봅시다.
# 프로젝트 목표 정의
project_goals = {
"primary": "월별 매출 트렌드 분석",
"secondary": [
"베스트셀러 상품 Top 5 선정",
"상품 카테고리별 매출 비교",
"계절별 판매 패턴 발견"
],
"output": "시각화 리포트 및 인사이트 문서"
}
# 필요한 라이브러리 임포트
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
# 한글 폰트 설정
plt.rcParams['font.family'] = 'NanumGothic'
plt.rcParams['axes.unicode_minus'] = False
김개발 씨는 대학에서 파이썬을 배웠지만, 실제 데이터 분석 프로젝트는 처음이었습니다. 카페 사장님이 보내준 엑셀 파일을 열어보니 날짜, 상품명, 수량, 금액이 빼곡히 적혀 있었습니다.
"이걸 어디서부터 시작해야 하지?" 선배 개발자 박시니어 씨에게 조언을 구했습니다. "데이터 분석은 목표 설정이 가장 중요해요.
무엇을 알아내고 싶은지부터 명확히 해야 합니다." 프로젝트 목표 설정이란 무엇을 분석할지, 어떤 결과를 도출할지 미리 정하는 것입니다. 마치 여행을 떠나기 전에 목적지를 정하는 것과 같습니다.
목적지 없이 무작정 출발하면 길을 잃기 쉽습니다. 데이터 분석도 마찬가지입니다.
명확한 목표가 있어야 어떤 데이터를 수집하고, 어떤 방법으로 분석할지 결정할 수 있습니다. 카페 사장님과 통화하며 김개발 씨는 구체적인 질문들을 받았습니다.
"어느 달에 매출이 가장 높았나요?", "겨울에는 뜨거운 음료가 더 잘 팔릴까요?", "메뉴를 줄이려고 하는데, 어떤 상품을 없애야 할까요?" 이런 질문들을 정리하니 프로젝트의 방향이 보였습니다. 주요 목표는 월별 매출 추이를 파악하는 것이고, 부수적인 목표로는 베스트셀러 상품 선정, 카테고리별 비교, 계절 패턴 분석이 있었습니다.
목표가 정해지자 필요한 도구도 명확해졌습니다. 데이터를 다루기 위해서는 pandas 라이브러리가 필수였습니다.
또한 결과를 시각화하기 위해 matplotlib을 사용하기로 했습니다. 김개발 씨는 노트에 프로젝트 목표를 하나씩 적어 내려갔습니다.
"1. 월별 매출 합계 계산하기, 2.
베스트셀러 상품 찾기, 3. 그래프로 시각화하기." 글로 적고 나니 막연했던 과제가 구체적인 단계로 나뉘어졌습니다.
한 가지 중요한 점은 결과물의 형태도 미리 정해두는 것입니다. 김개발 씨는 사장님께 PDF 리포트를 드리기로 했습니다.
그래프와 함께 "1월 매출이 전년 대비 15% 증가했습니다"와 같은 구체적인 인사이트를 담기로 했습니다. 코드를 작성하기 전에 김개발 씨는 한 가지 더 확인했습니다.
한글 폰트 설정입니다. matplotlib은 기본적으로 한글을 지원하지 않아서, 그래프에 한글을 사용하려면 폰트를 따로 지정해야 합니다.
"제대로 준비하고 시작하니까 훨씬 자신감이 생기네요." 김개발 씨는 이제 본격적으로 데이터를 불러올 준비가 되었습니다. 프로젝트 목표를 명확히 설정하면 세 가지 이점이 있습니다.
첫째, 방향성을 잃지 않습니다. 데이터가 많아질수록 무엇을 분석할지 헷갈리기 쉬운데, 목표가 있으면 집중할 수 있습니다.
둘째, 효율적으로 작업할 수 있습니다. 불필요한 분석에 시간을 낭비하지 않습니다.
셋째, 결과물의 완성도가 높아집니다. 처음부터 무엇을 보여줄지 알고 있으니까요.
박시니어 씨는 마지막으로 조언했습니다. "프로젝트 중간에 목표가 바뀔 수도 있어요.
그건 자연스러운 일이니 유연하게 대응하세요."
실전 팁
💡 - 프로젝트 시작 전 반드시 이해관계자(사장님 등)와 명확한 목표를 합의하세요
- 목표는 구체적이고 측정 가능해야 합니다 (예: "매출 증가 원인 파악" → "월별 매출 상위 3개 상품 선정")
- 한글 폰트 설정은 프로젝트 초반에 미리 해두면 나중에 그래프 깨짐 문제를 예방할 수 있습니다
2. 커피숍 매출 데이터 로드
김개발 씨는 사장님이 보내준 CSV 파일을 프로젝트 폴더에 저장했습니다. 파일명은 'coffee_sales.csv'였습니다.
"이제 이 데이터를 파이썬으로 불러오면 되겠네." 하지만 막상 코드를 작성하려니 어떤 함수를 사용해야 할지 막막했습니다.
pandas 라이브러리의 read_csv 함수를 사용하면 CSV 파일을 쉽게 불러올 수 있습니다. 불러온 데이터는 DataFrame이라는 표 형태로 저장되며, 이후 다양한 분석 작업을 수행할 수 있습니다.
데이터를 불러온 후에는 head 함수로 상위 몇 개 행을 확인하는 것이 좋습니다.
다음 코드를 살펴봅시다.
# CSV 파일 불러오기
df = pd.read_csv('coffee_sales.csv', encoding='utf-8')
# 상위 5개 행 확인
print(df.head())
# 데이터 기본 정보 확인
print("\n데이터 정보:")
print(df.info())
# 데이터 크기 확인 (행, 열)
print(f"\n총 {df.shape[0]}개의 판매 기록이 있습니다.")
print(f"컬럼 수: {df.shape[1]}개")
김개발 씨는 구글에서 "pandas csv 불러오기"를 검색했습니다. 첫 번째로 나온 결과가 read_csv 함수였습니다.
"생각보다 간단하네?" 데이터 로드란 외부 파일에 저장된 데이터를 프로그램 안으로 가져오는 작업입니다. 마치 도서관에서 책을 빌려오는 것과 같습니다.
책이 서가에만 꽂혀 있으면 읽을 수 없습니다. 책을 꺼내서 책상 위에 펼쳐놓아야 내용을 볼 수 있습니다.
데이터도 마찬가지입니다. 파일로 저장되어 있는 데이터를 메모리에 불러와야 분석할 수 있습니다.
pandas 라이브러리는 데이터 분석을 위한 파이썬의 핵심 도구입니다. 그중에서도 read_csv는 가장 자주 사용되는 함수 중 하나입니다.
CSV는 Comma-Separated Values의 약자로, 쉼표로 구분된 텍스트 파일 형식입니다. 김개발 씨가 작성한 첫 줄 코드를 살펴봅시다.
df라는 변수에 데이터를 담았습니다. df는 DataFrame의 약자로, 데이터 분석에서 관례적으로 사용하는 변수명입니다.
encoding 매개변수는 왜 필요할까요? 한글이 포함된 CSV 파일은 인코딩 방식이 맞지 않으면 깨져서 보입니다.
'utf-8'은 한글을 포함한 다국어를 지원하는 표준 인코딩 방식입니다. 만약 데이터가 깨진다면 'cp949'나 'euc-kr'을 시도해볼 수 있습니다.
데이터를 불러왔다면 제대로 불러와졌는지 확인해야 합니다. head 함수는 상위 5개 행을 보여줍니다.
김개발 씨는 화면에 출력된 결과를 보고 안도했습니다. 날짜, 상품명, 수량, 금액 컬럼이 모두 제대로 보였습니다.
하지만 박시니어 씨는 한 가지를 더 확인하라고 조언했습니다. "info 함수도 사용해 보세요.
데이터 타입과 결측치를 한눈에 볼 수 있어요." info 함수를 실행하자 더 자세한 정보가 나타났습니다. 총 몇 개의 행이 있는지, 각 컬럼의 데이터 타입은 무엇인지, 빈 값은 없는지 확인할 수 있었습니다.
날짜 컬럼이 object 타입으로 되어 있는 것을 발견했습니다. "이건 나중에 datetime으로 변환해야겠네." shape 속성은 데이터의 크기를 알려줍니다.
shape[0]은 행의 개수, shape[1]은 열의 개수입니다. 김개발 씨의 데이터에는 1,247개의 판매 기록이 있었습니다.
"생각보다 많네. 이 정도면 의미 있는 분석이 가능하겠어." 데이터를 불러올 때 주의할 점이 있습니다.
파일 경로를 정확히 지정해야 합니다. 만약 코드 파일과 CSV 파일이 같은 폴더에 있다면 파일명만 적어도 되지만, 다른 폴더에 있다면 전체 경로를 적어야 합니다.
또 하나 중요한 점은 메모리 관리입니다. 데이터가 매우 크다면 한 번에 불러오는 것보다 청크 단위로 나눠서 읽는 것이 효율적입니다.
하지만 커피숍 데이터는 1,247개 행으로 크기가 작아서 한 번에 불러와도 문제없습니다. 김개발 씨는 데이터를 성공적으로 불러왔습니다.
화면에 출력된 표를 보니 뿌듯했습니다. "드디어 첫 단계를 완료했네!" 이제 본격적인 분석을 시작할 차례입니다.
실전 팁
💡 - CSV 파일을 열었을 때 한글이 깨진다면 encoding 매개변수를 'cp949'나 'euc-kr'로 변경해 보세요
- 데이터를 불러온 직후에는 반드시 head와 info로 구조를 확인하는 습관을 들이세요
- 파일 경로 오류가 발생하면 os.getcwd()로 현재 작업 디렉토리를 확인해 보세요
3. 데이터 탐색 및 정제
데이터를 불러온 김개발 씨는 본격적인 분석에 들어가려 했지만, 박시니어 씨가 제지했습니다. "잠깐!
데이터를 먼저 깨끗하게 정제해야 해요. 지금 상태로 분석하면 잘못된 결과가 나올 수 있어요." 김개발 씨는 데이터가 깨끗해 보였는데 무엇이 문제인지 궁금했습니다.
데이터 정제는 결측치 제거, 중복 제거, 데이터 타입 변환 등을 포함하는 필수 과정입니다. 날짜 데이터를 datetime 형식으로 변환하고, 숫자 데이터의 이상치를 확인하며, 불필요한 공백을 제거합니다.
정제된 데이터만이 신뢰할 수 있는 분석 결과를 보장합니다.
다음 코드를 살펴봅시다.
# 결측치 확인
print("결측치 개수:")
print(df.isnull().sum())
# 날짜 컬럼을 datetime 타입으로 변환
df['날짜'] = pd.to_datetime(df['날짜'])
# 월 정보 추출하여 새로운 컬럼 생성
df['월'] = df['날짜'].dt.month
# 상품명 공백 제거
df['상품명'] = df['상품명'].str.strip()
# 중복 데이터 확인 및 제거
duplicates = df.duplicated().sum()
print(f"\n중복 데이터: {duplicates}개")
df = df.drop_duplicates()
# 정제 후 데이터 확인
print("\n정제 후 데이터:")
print(df.head())
김개발 씨는 고개를 갸우뚱했습니다. "데이터가 다 있는 것 같은데요?" 박시니어 씨는 모니터를 가리키며 설명했습니다.
"여기 날짜 컬럼 보세요. 지금은 문자열로 인식되고 있어요.
이 상태로는 월별 집계를 할 수 없습니다." 데이터 정제란 분석에 적합한 형태로 데이터를 가공하는 과정입니다. 마치 요리를 하기 전에 재료를 손질하는 것과 같습니다.
채소를 씻고, 껍질을 벗기고, 적당한 크기로 썰어야 제대로 된 요리를 만들 수 있습니다. 데이터도 마찬가지입니다.
결측치를 제거하고, 타입을 변환하고, 중복을 없애야 정확한 분석이 가능합니다. 실제 현장에서 수집된 데이터는 완벽하지 않습니다.
입력 실수로 빈 값이 있을 수 있고, 시스템 오류로 같은 데이터가 두 번 기록될 수도 있습니다. 김개발 씨의 커피숍 데이터도 예외는 아니었습니다.
첫 번째로 확인할 것은 결측치입니다. isnull 함수를 사용하면 각 컬럼별로 빈 값이 몇 개인지 알 수 있습니다.
다행히 김개발 씨의 데이터에는 결측치가 없었습니다. 만약 있었다면 dropna 함수로 해당 행을 삭제하거나, fillna 함수로 특정 값을 채워 넣을 수 있습니다.
두 번째는 데이터 타입 변환입니다. 날짜 컬럼이 문자열로 저장되어 있으면 월별 집계나 시계열 분석을 할 수 없습니다.
to_datetime 함수를 사용하면 문자열을 날짜 형식으로 변환할 수 있습니다. 날짜를 datetime으로 변환하면 놀라운 일이 일어납니다.
dt 접근자를 통해 연, 월, 일, 요일 등을 쉽게 추출할 수 있습니다. 김개발 씨는 월 정보를 새로운 컬럼으로 만들었습니다.
"나중에 월별 집계할 때 편하겠네." 세 번째는 문자열 정제입니다. 상품명 컬럼을 자세히 보니 일부 데이터 앞뒤로 공백이 있었습니다.
"아메리카노"와 " 아메리카노"는 다른 상품으로 인식됩니다. strip 함수로 앞뒤 공백을 제거했습니다.
네 번째는 중복 제거입니다. duplicated 함수는 완전히 동일한 행이 있는지 확인합니다.
김개발 씨의 데이터에서는 3개의 중복이 발견되었습니다. "어?
같은 날, 같은 상품, 같은 금액이 두 번 기록되어 있네요." drop_duplicates 함수로 중복을 제거했습니다. 데이터를 정제하면서 김개발 씨는 흥미로운 점을 발견했습니다.
수량이 음수인 데이터가 있었습니다. "이건 뭐지?
환불인가?" 사장님께 확인하니 맞았습니다. 환불 데이터는 별도로 처리해야 할지, 아니면 매출에서 차감해야 할지 고민이 되었습니다.
박시니어 씨는 비즈니스 로직을 이해하는 것이 중요하다고 강조했습니다. "단순히 코드만 작성하는 게 아니라, 데이터가 무엇을 의미하는지 알아야 합니다." 김개발 씨는 사장님과 상의한 끝에 환불 데이터는 그대로 포함하되, 분석할 때 순매출로 계산하기로 했습니다.
정제 과정에서 또 하나 중요한 것은 원본 데이터 보존입니다. 실수로 중요한 데이터를 삭제할 수도 있으니, 원본 파일은 따로 백업해 두는 것이 좋습니다.
김개발 씨는 df_original = df.copy()로 원본 데이터를 복사해 뒀습니다. 데이터 정제가 끝나고 나니 훨씬 깔끔해 보였습니다.
날짜는 datetime 형식으로 정렬되어 있고, 상품명에는 불필요한 공백이 없으며, 중복 데이터도 사라졌습니다. "이제야 분석할 준비가 됐네요!"
실전 팁
💡 - 데이터 정제 전에 반드시 원본을 복사해 두세요 (df_original = df.copy())
- 날짜 형식 변환 시 errors='coerce' 옵션을 사용하면 변환 불가능한 값을 NaT로 처리합니다
- 실제 비즈니스 로직을 이해하지 못한 채 데이터를 함부로 삭제하면 안 됩니다
4. 월별 상품별 매출 집계
깨끗하게 정제된 데이터를 보며 김개발 씨는 드디어 본격적인 분석을 시작할 수 있다는 생각에 들뜬 마음이었습니다. "이제 월별로 얼마나 팔렸는지 계산해야겠어." 하지만 1,000개가 넘는 데이터를 어떻게 월별로 묶어야 할까요?
groupby 함수는 특정 기준으로 데이터를 그룹화하여 집계할 수 있게 해줍니다. 월별 매출을 계산하려면 월 컬럼을 기준으로 그룹화하고, 금액 컬럼을 합산합니다.
상품별 집계도 같은 방식으로 수행할 수 있으며, 여러 기준을 동시에 사용할 수도 있습니다.
다음 코드를 살펴봅시다.
# 월별 총 매출 집계
monthly_sales = df.groupby('월')['금액'].sum()
print("월별 총 매출:")
print(monthly_sales)
# 상품별 총 매출 집계
product_sales = df.groupby('상품명')['금액'].sum().sort_values(ascending=False)
print("\n상품별 총 매출 (상위 10개):")
print(product_sales.head(10))
# 월별, 상품별 매출 집계 (2차원)
monthly_product_sales = df.groupby(['월', '상품명'])['금액'].sum()
print("\n월별, 상품별 매출:")
print(monthly_product_sales.head(15))
# 월별 거래 건수도 함께 확인
monthly_summary = df.groupby('월').agg({
'금액': 'sum',
'수량': 'sum',
'날짜': 'count'
})
monthly_summary.columns = ['총매출', '총수량', '거래건수']
print("\n월별 종합 집계:")
print(monthly_summary)
김개발 씨는 엑셀에서 피벗 테이블을 사용해 본 경험이 있었습니다. "pandas에도 비슷한 기능이 있을 텐데..." 검색해 보니 groupby라는 강력한 함수가 있었습니다.
groupby란 데이터를 특정 기준으로 묶어서 집계하는 함수입니다. 마치 학생들을 반별로 나누어 평균 점수를 계산하는 것과 같습니다.
1반 학생들의 점수를 모두 더해서 평균을 내고, 2반 학생들도 같은 방식으로 계산합니다. groupby도 이런 식으로 데이터를 그룹으로 나눈 뒤 각 그룹에 집계 함수를 적용합니다.
첫 번째 코드를 살펴봅시다. df.groupby('월')은 데이터를 월별로 그룹화합니다.
그다음 ['금액']을 선택하면 금액 컬럼만 대상으로 삼습니다. 마지막으로 sum()을 호출하면 각 월의 금액을 모두 더합니다.
실행 결과를 보니 1월부터 12월까지 매출이 깔끔하게 정리되어 있었습니다. "오, 7월 매출이 가장 높네!" 여름에 아이스 음료 판매가 많았던 것으로 추정됩니다.
상품별 집계도 같은 방식입니다. groupby('상품명')으로 그룹화한 뒤 금액을 합산합니다.
여기서 한 가지 팁은 sort_values를 사용하는 것입니다. ascending=False 옵션을 주면 내림차순으로 정렬되어 베스트셀러가 맨 위에 나타납니다.
김개발 씨는 결과를 보고 놀랐습니다. "아메리카노가 압도적 1위네요.
2위는 카페라떼고." 예상했던 대로였지만, 숫자로 확인하니 더 확실했습니다. 더 복잡한 집계도 가능합니다.
여러 기준으로 그룹화하려면 리스트로 컬럼명을 넘깁니다. groupby(['월', '상품명'])을 사용하면 월별로 나눈 뒤 다시 상품별로 나눕니다.
"1월 아메리카노", "1월 카페라떼", "2월 아메리카노" 이런 식으로 집계됩니다. 박시니어 씨는 agg 함수를 추천했습니다.
"여러 가지 통계를 한 번에 계산할 수 있어요." agg에 딕셔너리를 넘기면 컬럼별로 다른 집계 함수를 적용할 수 있습니다. 금액은 sum, 수량도 sum, 날짜는 count로 거래 건수를 셉니다.
실행 결과를 보니 월별로 총매출, 총수량, 거래건수가 한눈에 보였습니다. "12월은 매출이 높은데 거래건수는 적네?
고가 상품이 많이 팔렸나 봐요." 데이터에서 인사이트가 보이기 시작했습니다. 김개발 씨는 한 가지 궁금한 점이 생겼습니다.
"평균 매출도 알고 싶은데?" mean 함수를 사용하면 됩니다. df.groupby('월')['금액'].mean()을 실행하니 월별 평균 거래 금액이 나왔습니다.
집계 함수는 다양합니다. sum(합계), mean(평균), count(개수), max(최댓값), min(최솟값), std(표준편차) 등을 자유롭게 사용할 수 있습니다.
상황에 맞게 선택하면 됩니다. 한 가지 주의할 점은 NaN 처리입니다.
만약 어떤 월에 특정 상품이 팔리지 않았다면 해당 조합은 결과에 나타나지 않습니다. 이런 경우 fillna(0)을 사용해 0으로 채울 수 있습니다.
김개발 씨는 월별 집계 결과를 CSV로 저장했습니다. monthly_sales.to_csv('monthly_sales.csv')를 실행하니 새 파일이 생성되었습니다.
"나중에 엑셀로도 확인할 수 있겠네요." 데이터 집계는 생각보다 간단했지만, 그 안에 숨은 인사이트는 무궁무진했습니다. 김개발 씨는 점점 데이터 분석의 매력에 빠져들고 있었습니다.
실전 팁
💡 - groupby 후 여러 집계 함수를 동시에 적용하려면 agg 함수를 사용하세요
- sort_values(ascending=False)로 내림차순 정렬하면 상위 항목을 쉽게 찾을 수 있습니다
- 집계 결과를 reset_index()로 일반 DataFrame으로 변환하면 추가 작업이 편리합니다
5. 베스트셀러 상품 분석
월별 매출을 집계한 김개발 씨는 다음 단계로 넘어갔습니다. 사장님이 가장 궁금해하시던 질문, "어떤 상품이 가장 잘 팔리나요?" 전체 기간 동안 베스트셀러 상위 5개를 뽑아내면 메뉴 전략을 세우는 데 도움이 될 것입니다.
베스트셀러 분석은 매출액 기준뿐만 아니라 판매 수량, 거래 건수 등 다양한 관점에서 수행할 수 있습니다. nlargest 함수를 사용하면 상위 N개 항목을 쉽게 추출할 수 있으며, 여러 지표를 종합해 순위를 매길 수도 있습니다.
다음 코드를 살펴봅시다.
# 매출액 기준 베스트셀러 Top 5
top5_revenue = df.groupby('상품명')['금액'].sum().nlargest(5)
print("매출액 기준 베스트셀러 Top 5:")
print(top5_revenue)
# 판매 수량 기준 베스트셀러 Top 5
top5_quantity = df.groupby('상품명')['수량'].sum().nlargest(5)
print("\n판매 수량 기준 베스트셀러 Top 5:")
print(top5_quantity)
# 거래 건수 기준 베스트셀러 Top 5
top5_count = df.groupby('상품명')['날짜'].count().nlargest(5)
print("\n거래 건수 기준 베스트셀러 Top 5:")
print(top5_count)
# 종합 분석 (매출, 수량, 건수를 모두 포함)
product_analysis = df.groupby('상품명').agg({
'금액': 'sum',
'수량': 'sum',
'날짜': 'count'
})
product_analysis.columns = ['총매출', '총수량', '거래건수']
product_analysis['평균단가'] = product_analysis['총매출'] / product_analysis['총수량']
print("\n종합 상품 분석:")
print(product_analysis.sort_values('총매출', ascending=False).head(10))
김개발 씨는 이미 상품별 매출을 집계해 뒀기 때문에 베스트셀러를 찾는 것은 간단했습니다. "정렬해서 상위 5개만 뽑으면 되겠네." 하지만 박시니어 씨는 다른 관점을 제시했습니다.
"매출액만 보면 안 돼요. 비싼 상품 하나가 싼 상품 여러 개보다 매출이 높을 수 있으니까요." 베스트셀러 분석은 단순히 매출 순위를 매기는 것이 아닙니다.
다양한 각도에서 상품을 평가해야 합니다. 마치 학생을 평가할 때 시험 점수만 보는 것이 아니라 출석, 과제, 태도 등을 종합적으로 고려하는 것과 같습니다.
상품도 매출액, 판매 수량, 거래 건수, 평균 단가 등 여러 지표를 함께 봐야 정확한 평가가 가능합니다. nlargest 함수는 상위 N개를 추출하는 편리한 함수입니다.
sort_values를 사용해도 되지만, nlargest가 더 직관적이고 빠릅니다. nlargest(5)를 호출하면 상위 5개가 자동으로 정렬되어 나타납니다.
첫 번째 분석에서 매출액 기준 1위는 아메리카노였습니다. 총매출 450만 원으로 압도적이었습니다.
2위는 카페라떼 320만 원, 3위는 바닐라라떼 280만 원이었습니다. 하지만 판매 수량 기준으로 보니 결과가 달랐습니다.
1위는 여전히 아메리카노였지만, 3위에 에스프레소가 올라왔습니다. "에스프레소는 가격이 싸서 매출액은 낮지만 많이 팔렸구나." 거래 건수 기준도 흥미로웠습니다.
거래 건수는 얼마나 자주 주문되었는지를 보여줍니다. 아메리카노는 이 부문에서도 1위였습니다.
"사람들이 매일 찾는 상품이네요." 김개발 씨는 세 가지 기준의 순위를 비교하면서 패턴을 발견했습니다. 아메리카노와 카페라떼는 모든 기준에서 상위권이었습니다.
이런 상품은 핵심 상품으로 분류할 수 있습니다. 절대로 메뉴에서 빼면 안 됩니다.
반면 바닐라라떼는 매출액은 높지만 거래 건수는 상대적으로 적었습니다. "가격이 높아서 매출은 올라가지만, 자주 팔리지는 않는 상품이네요." 이런 상품은 고수익 상품으로 분류됩니다.
종합 분석을 위해 agg 함수로 여러 지표를 한 번에 계산했습니다. 총매출, 총수량, 거래건수를 모두 담은 테이블을 만들었습니다.
여기서 한 걸음 더 나아가 평균 단가도 계산했습니다. 평균 단가는 총매출을 총수량으로 나눈 값입니다.
이 값을 보면 상품의 가격대를 알 수 있습니다. 케이크류는 평균 단가가 6,000원이 넘었고, 에스프레소는 2,500원이었습니다.
박시니어 씨는 이런 분석을 상품 포트폴리오 분석이라고 불렀습니다. "상품을 네 가지 유형으로 나눌 수 있어요.
고매출-고빈도, 고매출-저빈도, 저매출-고빈도, 저매출-저빈도." 고매출-고빈도 상품은 핵심 상품으로 절대 빼면 안 됩니다. 고매출-저빈도 상품은 수익성은 좋지만 홍보가 필요합니다.
저매출-고빈도 상품은 가격을 올릴 여지가 있습니다. 저매출-저빈도 상품은 메뉴에서 제외를 고려해야 합니다.
김개발 씨는 분석 결과를 표로 정리했습니다. 사장님께 보여드릴 때 한눈에 이해하기 쉽도록 컬럼명도 한글로 바꿨습니다.
"이 정도면 사장님이 메뉴 전략을 세우는 데 큰 도움이 되겠어요." 데이터를 다각도로 분석하니 단순히 "아메리카노가 1위"라는 것 이상의 인사이트를 얻을 수 있었습니다. 각 상품의 특성을 파악하고, 전략을 수립할 수 있는 근거가 마련되었습니다.
실전 팁
💡 - nlargest 대신 nsmallest를 사용하면 하위 N개를 추출할 수 있습니다 (저조한 상품 찾기)
- 평균 단가를 계산할 때 수량이 0인 경우를 대비해 fillna(0)을 사용하세요
- 여러 기준을 종합한 점수를 만들어 순위를 매기는 방법도 유용합니다 (가중 평균 등)
6. 매출 트렌드 시각화
숫자로만 보던 매출 데이터를 김개발 씨는 이제 그래프로 만들고 싶었습니다. "사장님께서 그래프로 보시면 훨씬 이해하기 쉬우실 텐데." 하지만 파이썬으로 그래프를 그려본 적이 없었습니다.
박시니어 씨는 matplotlib 라이브러리를 추천했습니다.
matplotlib은 파이썬의 대표적인 시각화 라이브러리입니다. 선 그래프, 막대 그래프, 파이 차트 등 다양한 형태로 데이터를 표현할 수 있습니다.
월별 매출 트렌드는 선 그래프로, 상품별 비교는 막대 그래프로, 비율은 파이 차트로 시각화하면 효과적입니다.
다음 코드를 살펴봅시다.
import matplotlib.pyplot as plt
# 그래프 크기 설정
plt.figure(figsize=(12, 5))
# 1. 월별 매출 트렌드 선 그래프
plt.subplot(1, 2, 1)
monthly_sales.plot(kind='line', marker='o', color='#4CAF50', linewidth=2)
plt.title('월별 매출 트렌드', fontsize=14, fontweight='bold')
plt.xlabel('월', fontsize=12)
plt.ylabel('매출액 (원)', fontsize=12)
plt.grid(True, alpha=0.3)
# 2. 상품별 매출 막대 그래프 (Top 10)
plt.subplot(1, 2, 2)
top10_products = product_sales.head(10)
top10_products.plot(kind='barh', color='#2196F3')
plt.title('상품별 매출 Top 10', fontsize=14, fontweight='bold')
plt.xlabel('매출액 (원)', fontsize=12)
plt.ylabel('상품명', fontsize=12)
plt.tight_layout()
plt.savefig('sales_report.png', dpi=300, bbox_inches='tight')
plt.show()
print("그래프가 'sales_report.png'로 저장되었습니다.")
김개발 씨는 그래프를 그리기 전에 어떤 형태가 좋을지 고민했습니다. 박시니어 씨는 조언했습니다.
"시간의 흐름을 보여줄 땐 선 그래프, 항목 간 비교는 막대 그래프가 좋아요." 데이터 시각화란 숫자를 그림으로 표현하여 패턴과 인사이트를 쉽게 파악하게 하는 것입니다. 마치 지도가 복잡한 지리 정보를 한눈에 보여주는 것과 같습니다.
서울에서 부산까지 거리를 "400km"라고 글로 쓰는 것보다 지도에 표시하면 훨씬 직관적입니다. 데이터도 표보다 그래프로 보면 추세와 패턴이 명확하게 보입니다.
matplotlib에서 그래프를 그리려면 먼저 figure를 만들어야 합니다. figure는 그림판 같은 것입니다.
figsize=(12, 5)는 가로 12인치, 세로 5인치 크기를 의미합니다. 크기를 적절히 조정하면 가독성이 좋아집니다.
subplot은 하나의 figure 안에 여러 그래프를 배치하는 기능입니다. subplot(1, 2, 1)은 "1행 2열 레이아웃에서 첫 번째 위치"를 뜻합니다.
이렇게 하면 두 개의 그래프를 나란히 놓을 수 있습니다. 첫 번째 그래프는 월별 매출 트렌드입니다.
선 그래프(line)를 사용했습니다. marker='o' 옵션은 각 데이터 포인트에 동그라미 표시를 추가합니다.
색상은 녹색(#4CAF50)으로 지정했습니다. 색상 코드는 웹에서 쉽게 찾을 수 있습니다.
title 함수로 그래프 제목을 추가했습니다. fontsize와 fontweight로 글자 크기와 굵기를 조정할 수 있습니다.
xlabel과 ylabel은 축 이름을 지정합니다. 한글이 잘 보이는지 확인하세요.
grid는 격자 선을 추가하는 옵션입니다. alpha=0.3은 투명도를 의미하며, 0.3이면 흐릿하게 보여서 그래프를 방해하지 않습니다.
격자가 있으면 값을 읽기 쉬워집니다. 두 번째 그래프는 상품별 매출 비교입니다.
막대 그래프(bar)를 사용했는데, kind='barh'로 가로 막대를 선택했습니다. 상품명이 길 때는 세로 막대보다 가로 막대가 읽기 편합니다.
김개발 씨는 그래프를 실행해 보고 감탄했습니다. "와, 월별 매출이 7월에 급증했다가 9월에 떨어지는 게 한눈에 보이네요!" 숫자로만 봤을 때는 몰랐던 패턴이 그래프로는 명확했습니다.
tight_layout은 그래프 간 여백을 자동으로 조정해 줍니다. 이 함수를 호출하지 않으면 제목이나 축 이름이 잘릴 수 있습니다.
항상 사용하는 것을 추천합니다. savefig는 그래프를 이미지 파일로 저장합니다.
dpi=300은 해상도를 의미하며, 300이면 인쇄용으로도 충분합니다. bbox_inches='tight'는 여백을 최소화하는 옵션입니다.
파일 형식은 png, jpg, pdf 등을 선택할 수 있습니다. 박시니어 씨는 파이 차트도 추천했습니다.
"상위 5개 상품의 매출 비율을 파이 차트로 그려보세요." 김개발 씨는 top5_revenue.plot(kind='pie', autopct='%1.1f%%')를 실행했습니다. autopct 옵션은 각 조각에 퍼센트를 표시합니다.
그래프를 보니 아메리카노가 전체 매출의 28%를 차지했습니다. 상위 5개 상품이 전체 매출의 70%를 차지했습니다.
"파레토 법칙이네요. 20%의 상품이 80%의 매출을 만든다는." 이런 인사이트는 그래프가 아니면 발견하기 어렵습니다.
색상을 커스터마이징하고 싶다면 colors 매개변수를 사용합니다. colors=['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8']처럼 리스트로 색상 코드를 넘기면 됩니다.
김개발 씨는 여러 그래프를 만들어 본 뒤 가장 효과적인 것들을 선택해 리포트에 포함시켰습니다. "그래프 하나가 천 마디 말보다 낫네요." 시각화의 핵심은 명확성입니다.
화려한 그래프보다 간결하고 이해하기 쉬운 그래프가 좋습니다. 불필요한 장식은 오히려 메시지를 흐립니다.
실전 팁
💡 - 그래프 저장 전에 plt.show()를 호출하면 미리보기로 확인할 수 있습니다
- 색상은 colorbrewer2.org 같은 사이트에서 색상 조합을 참고하세요
- 여러 그래프를 비교할 땐 동일한 축 범위를 사용하면 비교가 쉬워집니다 (ylim 함수 사용)
7. 인사이트 도출 및 정리
모든 분석과 시각화를 마친 김개발 씨는 마지막 단계에 도달했습니다. "이제 사장님께 뭐라고 말씀드리지?" 단순히 그래프를 보여드리는 것만으로는 부족합니다.
데이터에서 발견한 인사이트를 명확한 메시지로 전달해야 합니다.
인사이트란 데이터 분석을 통해 얻은 실행 가능한 통찰입니다. 단순한 사실 나열이 아니라 "왜 그런지", "어떻게 해야 하는지"까지 포함해야 합니다.
분석 결과를 바탕으로 구체적인 액션 아이템을 제시하는 것이 데이터 분석의 최종 목표입니다.
다음 코드를 살펴봅시다.
# 핵심 인사이트 정리
insights = {
"매출 트렌드": "7월 매출이 연중 최고(450만원), 겨울 시즌 매출 하락 대비 필요",
"베스트셀러": "아메리카노, 카페라떼, 바닐라라떼가 전체 매출의 70% 차지",
"계절성": "여름 아이스 음료 매출 급증, 겨울 디저트 판매 증가",
"가격대": "평균 거래 금액 5,200원, 고가 디저트(7,000원+) 판매 비중 15%"
}
# 액션 아이템 도출
action_items = [
"1. 겨울 시즌 프로모션 기획 (따뜻한 음료 번들 할인)",
"2. 베스트셀러 3종 원두 품질 관리 강화",
"3. 저조한 판매 상품 5종 메뉴 제외 검토",
"4. 고가 디저트 홍보 강화로 객단가 상승 유도"
]
print("=== 커피숍 매출 분석 인사이트 ===\n")
for key, value in insights.items():
print(f"[{key}] {value}")
print("\n=== 권장 액션 아이템 ===")
for item in action_items:
print(item)
# 최종 리포트 요약
summary_report = f"""
분석 기간: 전체 데이터 ({df['날짜'].min().strftime('%Y-%m-%d')} ~ {df['날짜'].max().strftime('%Y-%m-%d')})
총 거래 건수: {len(df):,}건
총 매출: {df['금액'].sum():,}원
월 평균 매출: {df.groupby('월')['금액'].sum().mean():,.0f}원
"""
print(summary_report)
김개발 씨는 지난 일주일간의 분석 작업을 돌아봤습니다. 데이터를 불러오고, 정제하고, 집계하고, 시각화했습니다.
하지만 가장 중요한 마지막 단계가 남았습니다. "그래서 뭐?"라는 질문에 답하는 것입니다.
인사이트 도출이란 데이터 뒤에 숨은 의미를 찾아내는 것입니다. 마치 의사가 검사 결과를 보고 진단을 내리는 것과 같습니다.
혈압이 140이라는 숫자만 말하는 것이 아니라 "고혈압이므로 염분 섭취를 줄이세요"라고 조언합니다. 데이터 분석도 숫자를 넘어서 그것이 의미하는 바와 취해야 할 행동을 제시해야 합니다.
김개발 씨는 분석 결과를 다시 살펴봤습니다. 7월 매출이 가장 높았습니다.
왜일까요? 여름이라 아이스 음료가 많이 팔렸기 때문입니다.
그렇다면 겨울에는? 매출이 떨어집니다.
이것이 첫 번째 인사이트입니다. "계절성이 뚜렷하므로 비수기 대책이 필요하다." 두 번째 인사이트는 베스트셀러 분석에서 나왔습니다.
상위 3개 상품이 전체 매출의 70%를 차지합니다. 이것은 무엇을 의미할까요?
"핵심 상품의 품질과 재고 관리가 매우 중요하다." 만약 아메리카노 원두가 떨어지면 매출에 치명타를 입을 수 있습니다. 세 번째 인사이트는 저조한 상품에서 발견했습니다.
몇몇 디저트는 한 달에 5개도 안 팔렸습니다. "메뉴를 간소화하여 재고 부담을 줄이고 효율성을 높여야 한다." 박시니어 씨는 인사이트를 SMART 원칙으로 정리하라고 조언했습니다.
Specific(구체적), Measurable(측정 가능), Actionable(실행 가능), Relevant(관련성), Time-bound(기한). "7월 매출이 높다"보다 "7월 매출이 450만 원으로 연중 최고치를 기록했으며, 이는 아이스 음료 판매 급증에 기인한다"가 더 좋은 인사이트입니다.
액션 아이템은 인사이트를 실행으로 옮기는 구체적인 계획입니다. "겨울 매출이 낮다"는 인사이트에서 "11월부터 따뜻한 음료 2+1 프로모션 진행"이라는 액션 아이템이 나옵니다.
김개발 씨는 액션 아이템을 우선순위별로 정리했습니다. 1순위는 당장 다음 달부터 적용할 수 있는 것들입니다.
저조한 메뉴 제외, 프로모션 기획 등입니다. 2순위는 중장기 과제로, POS 시스템 개선이나 고객 로열티 프로그램 같은 것들입니다.
사장님께 보고서를 작성할 때 김개발 씨는 스토리텔링을 활용했습니다. "우리 카페의 매출은 여름에 정점을 찍고 겨울에 하락합니다.
이는 아이스 음료 의존도가 높기 때문입니다. 겨울 시즌 대비를 위해..."처럼 이야기를 풀어나갔습니다.
숫자는 객관적이지만, 사람은 이야기에 더 잘 반응합니다. 그래프와 표를 적절히 배치하되, 각 그래프마다 "이 그래프는 무엇을 말하는가"를 명확히 설명했습니다.
김개발 씨는 리포트 마지막에 제한사항도 언급했습니다. "이 분석은 1년치 데이터만 사용했으므로 장기 트렌드를 파악하기 어렵습니다.
또한 경쟁 카페나 날씨 같은 외부 요인은 고려하지 않았습니다." 정직하게 한계를 인정하는 것도 신뢰를 높이는 방법입니다. 사장님은 리포트를 보시고 매우 만족하셨습니다.
"이제 뭘 해야 할지 명확하네요. 다음 달부터 바로 적용해 보겠습니다." 김개발 씨는 뿌듯함을 느꼈습니다.
데이터 분석의 진정한 가치는 의사결정에 도움을 주는 것입니다. 아무리 멋진 그래프를 만들어도 실제 비즈니스 개선으로 이어지지 않으면 의미가 없습니다.
김개발 씨는 이번 프로젝트를 통해 데이터 분석가의 진정한 역할을 배웠습니다. 몇 달 후, 사장님은 김개발 씨에게 연락했습니다.
"겨울 프로모션 효과가 좋아요. 작년 대비 매출이 20% 올랐어요!" 데이터가 현실을 바꾼 순간이었습니다.
실전 팁
💡 - 인사이트는 "So What?"(그래서 뭐?) 질문에 답할 수 있어야 합니다
- 액션 아이템은 담당자와 기한을 명시하면 실행력이 높아집니다
- 리포트는 경영진용(요약본)과 실무자용(상세본)을 따로 준비하면 효과적입니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.