이미지 로딩 중...
AI Generated
2025. 11. 21. · 4 Views
Matplotlib 기초부터 커스터마이징까지 완벽 가이드
Python의 대표 시각화 라이브러리 Matplotlib을 처음 접하는 분들을 위한 완벽 가이드입니다. 기본 그래프 그리기부터 스타일 커스터마이징, 여러 그래프 배치까지 실무에서 바로 쓸 수 있는 모든 것을 담았습니다. 데이터를 효과적으로 시각화하는 방법을 배워보세요.
목차
- 첫 번째 그래프 그리기 - 기본 선 그래프로 시작하기
- 여러 선 겹쳐 그리기 - 데이터 비교의 기술
- 막대 그래프 만들기 - 카테고리별 비교의 정석
- 산점도 그리기 - 두 변수의 관계 발견하기
- 여러 그래프 배치하기 - 서브플롯으로 대시보드 만들기
- 스타일과 색상 커스터마이징 - 그래프를 내 스타일로
- 히스토그램 만들기 - 데이터 분포를 한눈에
- 파이 차트로 비율 표현하기 - 전체 중 일부를 보여주기
- 박스플롯으로 분포 요약하기 - 통계적 관점에서 데이터 보기
- 히트맵으로 2차원 데이터 표현하기 - 색으로 값의 크기 보여주기
1. 첫 번째 그래프 그리기 - 기본 선 그래프로 시작하기
시작하며
여러분이 데이터 분석을 하면서 숫자로만 가득한 표를 보고 있을 때, 이게 대체 무슨 의미인지 한눈에 파악하기 어려웠던 경험 있으시죠? 100개, 1000개의 숫자를 일일이 읽으면서 패턴을 찾는 건 정말 힘든 일입니다.
바로 이럴 때 필요한 것이 데이터 시각화입니다. 숫자를 그래프로 바꾸면 복잡한 데이터의 패턴이 한눈에 보입니다.
Python에서 가장 많이 사용되는 시각화 도구가 바로 Matplotlib입니다. 오늘은 Matplotlib로 여러분의 첫 번째 그래프를 그려보겠습니다.
생각보다 훨씬 간단해서 놀라실 거예요.
개요
간단히 말해서, Matplotlib는 Python에서 그래프를 그리는 도구입니다. 마치 도화지에 그림을 그리듯이, 코드로 그래프를 그릴 수 있게 해주는 라이브러리죠.
왜 Matplotlib가 필요할까요? 실무에서는 데이터를 분석한 결과를 다른 사람에게 보여줘야 할 때가 많습니다.
예를 들어, 최근 3개월간 매출 추이를 보고해야 한다면, 숫자 나열보다는 선 그래프 하나가 훨씬 명확하게 전달됩니다. 전통적으로는 Excel 같은 프로그램에서 수동으로 그래프를 만들었다면, Matplotlib를 사용하면 코드 몇 줄로 자동화할 수 있습니다.
데이터가 바뀌어도 코드만 다시 실행하면 그래프가 자동으로 업데이트되죠. Matplotlib의 핵심은 pyplot이라는 모듈입니다.
이것만 있으면 선 그래프, 막대 그래프, 원 그래프 등 거의 모든 종류의 그래프를 그릴 수 있습니다. 게다가 전 세계 수백만 개발자가 사용하고 있어서 문제가 생겨도 해결 방법을 쉽게 찾을 수 있습니다.
코드 예제
import matplotlib.pyplot as plt
# 시간대별 온도 데이터 (시간, 온도)
hours = [0, 3, 6, 9, 12, 15, 18, 21, 24]
temperature = [15, 13, 12, 16, 22, 25, 23, 19, 16]
# 선 그래프 그리기
plt.plot(hours, temperature)
# 그래프에 제목과 라벨 추가
plt.title('Daily Temperature Change')
plt.xlabel('Hour')
plt.ylabel('Temperature (°C)')
# 그래프 화면에 표시
plt.show()
설명
이것이 하는 일: 24시간 동안의 온도 변화를 선 그래프로 시각화합니다. 몇 줄의 코드만으로 데이터의 추세를 한눈에 볼 수 있게 만들죠.
첫 번째로, matplotlib.pyplot을 plt라는 짧은 이름으로 불러옵니다. 마치 긴 이름을 가진 친구에게 별명을 지어주는 것과 같아요.
그 다음 시간과 온도 데이터를 리스트로 준비합니다. hours는 0시부터 24시까지의 시간, temperature는 각 시간대의 온도를 나타냅니다.
두 번째로, plt.plot() 함수가 실행되면서 실제 그래프가 그려집니다. 이 함수는 첫 번째 인자를 x축으로, 두 번째 인자를 y축으로 사용해서 점들을 선으로 연결합니다.
마치 점 찍기 놀이에서 점들을 순서대로 이어 그림을 완성하는 것처럼요. 세 번째로, title(), xlabel(), ylabel() 함수들이 그래프에 설명을 추가합니다.
제목은 "일일 온도 변화", x축은 "시간", y축은 "온도"라고 적어줍니다. 이렇게 라벨을 붙이면 그래프를 보는 사람이 무엇을 의미하는지 바로 이해할 수 있습니다.
마지막으로, plt.show()가 실행되면 여러분의 화면에 그래프가 나타납니다. 새 창이 열리면서 아름다운 선 그래프를 볼 수 있죠.
온도가 낮 12시경에 가장 높고, 새벽에 가장 낮다는 것을 한눈에 알 수 있습니다. 여러분이 이 코드를 사용하면 어떤 데이터든 빠르게 시각화할 수 있습니다.
주식 가격 추이, 웹사이트 방문자 수, 학습 진도율 등 시간에 따라 변하는 모든 데이터에 적용 가능합니다. 숫자 100개를 눈으로 읽는 대신 그래프 하나로 전체 패턴을 파악할 수 있다는 게 가장 큰 장점이죠.
실전 팁
💡 plt.plot() 뒤에 color='red' 옵션을 추가하면 선 색깔을 빨간색으로 바꿀 수 있습니다. 여러 그래프를 겹쳐 그릴 때 색으로 구분하면 훨씬 보기 좋아요.
💡 데이터가 많을 때는 plt.figure(figsize=(12, 6))을 맨 위에 추가해서 그래프 크기를 키우세요. 기본 크기는 작아서 데이터가 겹쳐 보일 수 있습니다.
💡 plt.grid(True)를 추가하면 격자 무늬가 생겨서 값을 더 정확히 읽을 수 있습니다. 프레젠테이션용 그래프에는 필수죠.
💡 plt.show() 대신 plt.savefig('graph.png')를 쓰면 그래프를 이미지 파일로 저장할 수 있습니다. 보고서에 첨부하거나 이메일로 보낼 때 유용합니다.
2. 여러 선 겹쳐 그리기 - 데이터 비교의 기술
시작하며
여러분이 두 지역의 온도를 비교하고 싶다면 어떻게 해야 할까요? 그래프를 두 개 그리면 왔다갔다 보느라 비교가 어렵습니다.
서울과 부산의 온도 변화를 동시에 보고 싶은데 말이죠. 이런 문제는 데이터 분석에서 정말 자주 발생합니다.
실제와 예측을 비교하거나, 올해와 작년을 비교하거나, A안과 B안을 비교할 때 말이에요. 바로 이럴 때 필요한 것이 여러 선을 한 그래프에 겹쳐 그리는 기술입니다.
Matplotlib에서는 plot() 함수를 여러 번 호출하면 자동으로 겹쳐집니다.
개요
간단히 말해서, 같은 그래프에 plot()을 여러 번 사용하면 선들이 자동으로 겹쳐져서 표시됩니다. 마치 투명한 종이에 그림을 그려서 겹쳐 놓는 것과 같아요.
왜 이 기능이 필요할까요? 실무에서는 단순히 하나의 데이터만 보는 경우가 거의 없습니다.
예를 들어, 제품 A와 제품 B의 판매량을 동시에 보면서 어느 것이 더 잘 팔리는지 비교해야 하죠. 각각 따로 그래프를 그리면 비교가 어렵지만, 하나에 겹쳐 그리면 차이가 명확히 보입니다.
기존에는 그래프를 두 개 그려서 눈으로 비교했다면, 이제는 하나의 그래프에서 직접 비교할 수 있습니다. 어느 시점에서 교차하는지, 차이가 얼마나 나는지 즉시 알 수 있죠.
Matplotlib는 자동으로 각 선에 다른 색상을 부여합니다. 첫 번째는 파란색, 두 번째는 주황색, 세 번째는 초록색 이런 식으로요.
또한 legend() 함수를 사용하면 각 선이 무엇을 나타내는지 범례를 표시할 수 있습니다. 이 두 가지 특징 덕분에 여러 데이터를 깔끔하게 비교할 수 있습니다.
코드 예제
import matplotlib.pyplot as plt
# 두 도시의 시간대별 온도 데이터
hours = [0, 3, 6, 9, 12, 15, 18, 21, 24]
seoul_temp = [15, 13, 12, 16, 22, 25, 23, 19, 16]
busan_temp = [18, 17, 16, 19, 24, 26, 24, 21, 19]
# 두 개의 선 그래프 그리기
plt.plot(hours, seoul_temp, label='Seoul', marker='o')
plt.plot(hours, busan_temp, label='Busan', marker='s')
# 그래프 꾸미기
plt.title('Temperature Comparison: Seoul vs Busan')
plt.xlabel('Hour')
plt.ylabel('Temperature (°C)')
plt.legend() # 범례 표시
plt.grid(True) # 격자 표시
plt.show()
설명
이것이 하는 일: 서울과 부산 두 도시의 온도 변화를 하나의 그래프에 표시해서 쉽게 비교할 수 있게 만듭니다. 두 도시의 온도 차이와 변화 패턴이 한눈에 보이죠.
첫 번째로, 데이터 준비 단계에서 두 도시의 온도 데이터를 각각 리스트로 만듭니다. seoul_temp와 busan_temp라는 이름으로 구분해서 저장하죠.
같은 시간대(hours)를 공유하지만 온도는 다릅니다. 두 번째로, plt.plot()을 두 번 연속으로 호출합니다.
첫 번째 호출은 서울 데이터를, 두 번째 호출은 부산 데이터를 그립니다. 여기서 중요한 것은 label 옵션입니다.
label='Seoul'과 label='Busan'을 지정하면 나중에 범례에 이 이름이 표시됩니다. marker 옵션은 데이터 포인트에 동그라미(o)나 네모(s) 표시를 추가해서 더 보기 좋게 만들어줍니다.
세 번째로, plt.legend()가 실행되면 그래프 한쪽 구석에 범례가 나타납니다. 파란 선은 Seoul, 주황 선은 Busan이라고 알려주는 작은 상자죠.
plt.grid(True)는 격자 무늬를 추가해서 특정 시간대의 정확한 온도를 읽기 쉽게 만듭니다. 마지막으로, 완성된 그래프를 보면 부산이 서울보다 전반적으로 2-3도 높다는 것을 즉시 알 수 있습니다.
낮 12시부터 18시 사이에 두 도시 모두 온도가 높고, 새벽에는 낮다는 공통 패턴도 보이죠. 여러분이 이 코드를 사용하면 2개든 10개든 원하는 만큼의 데이터를 겹쳐서 비교할 수 있습니다.
여러 주식 종목의 가격 비교, 여러 제품의 판매량 추이, 실제 값과 예측 값의 비교 등 실무에서 정말 자주 사용하는 패턴입니다. 색상과 마커 스타일을 달리하면 10개 이상의 선도 깔끔하게 구분할 수 있습니다.
실전 팁
💡 선이 3개 이상이면 색상과 함께 선 스타일도 바꾸세요. linestyle='--' (점선), linestyle=':' (점선), linestyle='-.' (일점쇄선) 등을 사용하면 흑백 인쇄에서도 구분 가능합니다.
💡 plt.legend(loc='upper left')처럼 loc 옵션으로 범례 위치를 조정하세요. 그래프와 겹치지 않는 곳에 배치하는 게 중요합니다.
💡 선의 투명도를 조절하려면 alpha=0.7 옵션을 추가하세요. 여러 선이 겹칠 때 모든 선을 동시에 볼 수 있어 유용합니다.
💡 linewidth=2 옵션으로 선 굵기를 조절할 수 있습니다. 중요한 선은 굵게, 참고용 선은 얇게 표시하면 시각적 계층이 생깁니다.
3. 막대 그래프 만들기 - 카테고리별 비교의 정석
시작하며
여러분이 과일 판매량을 분석한다고 생각해보세요. 사과 50개, 바나나 80개, 오렌지 65개...
이렇게 숫자로만 보면 어느 과일이 가장 인기 있는지 한눈에 안 들어오죠? 이런 카테고리형 데이터는 선 그래프보다 막대 그래프가 훨씬 효과적입니다.
막대의 높이로 크기를 비교할 수 있어서 시각적으로 즉시 이해되거든요. 바로 이럴 때 필요한 것이 Matplotlib의 bar() 함수입니다.
카테고리별 수치를 막대로 표현해서 비교를 쉽게 만들어줍니다.
개요
간단히 말해서, 막대 그래프는 여러 카테고리의 값을 막대 높이로 비교하는 그래프입니다. 마치 키 재기할 때 사람들을 나란히 세워서 비교하는 것과 같아요.
왜 막대 그래프가 필요할까요? 실무에서는 카테고리를 비교해야 할 때가 정말 많습니다.
예를 들어, 부서별 매출, 제품별 판매량, 지역별 인구, 언어별 사용자 수 등을 보여줄 때 막대 그래프만한 게 없습니다. 한눈에 1등부터 꼴등까지 순위가 보이니까요.
전통적으로 선 그래프는 시간의 흐름을 보여주는 데 좋지만, 카테고리 비교에는 막대 그래프가 압도적으로 우수합니다. 5개 항목의 판매량을 선으로 연결하면 이상하지만, 막대로 나란히 세우면 완벽하게 비교됩니다.
막대 그래프의 핵심 특징은 명확한 비교와 직관적인 이해입니다. 막대가 두 배 높으면 값도 두 배라는 것을 누구나 즉시 이해합니다.
또한 가로 막대 그래프(barh)도 지원해서 카테고리 이름이 길 때 유용하죠.
코드 예제
import matplotlib.pyplot as plt
# 과일별 판매량 데이터
fruits = ['Apple', 'Banana', 'Orange', 'Grape', 'Melon']
sales = [50, 80, 65, 45, 70]
# 막대 그래프 그리기
plt.bar(fruits, sales, color=['red', 'yellow', 'orange', 'purple', 'green'])
# 막대 위에 정확한 값 표시
for i, v in enumerate(sales):
plt.text(i, v + 2, str(v), ha='center', fontweight='bold')
# 그래프 꾸미기
plt.title('Fruit Sales Comparison')
plt.xlabel('Fruits')
plt.ylabel('Sales (units)')
plt.ylim(0, 100) # y축 범위 설정
plt.show()
설명
이것이 하는 일: 다섯 가지 과일의 판매량을 막대 그래프로 시각화해서 어느 과일이 가장 많이 팔렸는지 한눈에 보여줍니다. 바나나가 80개로 1등이라는 것이 즉시 파악되죠.
첫 번째로, 과일 이름과 판매량 데이터를 각각 리스트로 준비합니다. fruits는 카테고리(x축), sales는 값(y축)이 됩니다.
이 두 리스트의 순서가 중요한데, 첫 번째 과일은 첫 번째 판매량과 매칭됩니다. 두 번째로, plt.bar() 함수가 실행되면서 막대들이 그려집니다.
color 옵션에 리스트를 전달하면 각 막대마다 다른 색상을 지정할 수 있습니다. 사과는 빨강, 바나나는 노랑처럼 실제 과일 색과 맞추면 더 직관적이죠.
세 번째로, for 반복문을 사용해서 각 막대 위에 정확한 숫자를 표시합니다. enumerate()는 인덱스와 값을 동시에 가져오고, plt.text()로 텍스트를 배치합니다.
ha='center'는 텍스트를 가운데 정렬, fontweight='bold'는 글씨를 굵게 만듭니다. v + 2는 막대 위에서 약간 떨어진 위치를 의미하죠.
마지막으로, plt.ylim(0, 100)으로 y축 범위를 0부터 100까지로 고정합니다. 이렇게 하면 막대들의 상대적 크기가 더 명확해집니다.
만약 범위를 자동으로 맞추면 45부터 시작할 수 있는데, 그러면 차이가 과장되어 보일 수 있거든요. 여러분이 이 코드를 사용하면 모든 종류의 카테고리 데이터를 효과적으로 비교할 수 있습니다.
설문조사 결과, 나라별 통계, 월별 실적 등 어디든 활용 가능합니다. 특히 프레젠테이션에서 막대 그래프는 청중이 가장 쉽게 이해하는 차트 유형입니다.
실전 팁
💡 plt.barh()를 사용하면 가로 막대 그래프가 됩니다. 카테고리 이름이 길 때(예: 부서명, 제품명) 가로가 훨씬 읽기 편합니다.
💡 width=0.6 옵션으로 막대 폭을 조절하세요. 좁게 하면 여백이 많아져 세련되고, 넓게 하면 강조 효과가 있습니다.
💡 여러 그룹을 비교할 때는 x축 위치를 계산해서 막대를 나란히 배치하세요. numpy의 arange()를 사용하면 간편합니다.
💡 plt.xticks(rotation=45)로 x축 라벨을 45도 기울이면 긴 이름도 겹치지 않게 표시할 수 있습니다.
4. 산점도 그리기 - 두 변수의 관계 발견하기
시작하며
여러분이 공부 시간과 시험 점수의 관계를 알아보고 싶다면 어떻게 해야 할까요? 공부를 많이 하면 정말 점수가 오를까요?
막연히 그럴 것 같지만 확실하지 않습니다. 이런 두 변수 사이의 관계를 파악할 때는 산점도(scatter plot)가 최고입니다.
각 데이터 포인트를 점으로 찍어서 전체 패턴을 보면 관계가 보이거든요. 바로 이럴 때 필요한 것이 scatter() 함수입니다.
상관관계가 있는지, 어떤 패턴이 있는지 시각적으로 발견할 수 있게 해줍니다.
개요
간단히 말해서, 산점도는 두 개의 연속형 변수를 x축과 y축에 놓고 데이터를 점으로 표시하는 그래프입니다. 마치 별자리 찾기처럼 점들이 이루는 패턴을 관찰하는 거죠.
왜 산점도가 필요할까요? 실무에서는 두 가지가 서로 관련이 있는지 확인해야 할 때가 많습니다.
예를 들어, 광고비와 매출의 관계, 나이와 소득의 관계, 운동량과 체중의 관계 등을 분석할 때 산점도만큼 명확한 게 없습니다. 점들이 우상향하면 양의 상관관계, 우하향하면 음의 상관관계가 있다는 것을 바로 알 수 있죠.
전통적으로 표로만 보면 100개의 데이터 쌍을 일일이 비교해야 하지만, 산점도로 그리면 0.1초 만에 관계를 파악할 수 있습니다. 이상치(outlier)도 즉시 눈에 띄어서 데이터 품질 검사에도 유용합니다.
산점도의 특징은 점의 크기와 색상으로 추가 정보를 표현할 수 있다는 것입니다. 3차원, 4차원 데이터도 2차원 그래프에 표현 가능하죠.
또한 점의 분포를 보고 선형 관계인지, 비선형 관계인지도 판단할 수 있습니다.
코드 예제
import matplotlib.pyplot as plt
import numpy as np
# 학생들의 공부 시간과 시험 점수 (실제로는 데이터베이스에서 가져옴)
study_hours = [1, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7]
test_scores = [45, 52, 55, 60, 65, 68, 72, 75, 80, 85, 88, 92]
# 산점도 그리기
plt.scatter(study_hours, test_scores, s=100, c='blue', alpha=0.6, edgecolors='black')
# 추세선 추가 (선형 회귀)
z = np.polyfit(study_hours, test_scores, 1)
p = np.poly1d(z)
plt.plot(study_hours, p(study_hours), "r--", alpha=0.8, label='Trend Line')
# 그래프 꾸미기
plt.title('Study Hours vs Test Scores')
plt.xlabel('Study Hours')
plt.ylabel('Test Score')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
설명
이것이 하는 일: 12명 학생의 공부 시간과 시험 점수를 산점도로 그려서 둘 사이의 관계를 시각화합니다. 공부를 많이 할수록 점수가 높아지는 패턴이 명확히 보이죠.
첫 번째로, 데이터를 준비합니다. study_hours는 각 학생이 공부한 시간, test_scores는 받은 점수입니다.
실무에서는 이런 데이터를 데이터베이스나 CSV 파일에서 읽어옵니다. numpy를 import하는 이유는 나중에 추세선을 그리기 위해서입니다.
두 번째로, plt.scatter()가 실행되면서 각 학생이 점 하나로 표시됩니다. s=100은 점의 크기, c='blue'는 색상, alpha=0.6은 투명도(겹칠 때 보이게), edgecolors='black'은 점 테두리 색을 지정합니다.
이렇게 스타일을 주면 단순한 점이 아니라 보기 좋은 버블처럼 보입니다. 세 번째로, 추세선을 추가합니다.
np.polyfit()은 데이터에 가장 잘 맞는 직선의 방정식을 계산하고, np.poly1d()는 그 방정식을 함수로 만들어줍니다. 그 다음 plt.plot()으로 빨간 점선("r--")을 그리면 전체적인 경향이 한눈에 보입니다.
점들이 이 선 주변에 모여있다는 것은 공부 시간과 점수가 선형 관계라는 뜻이죠. 마지막으로, 완성된 그래프를 보면 공부를 1시간 할 때는 45점, 7시간 하면 92점으로 약 2배가 됩니다.
모든 점이 추세선 근처에 있어서 관계가 강하다는 것도 알 수 있습니다. 만약 점들이 사방에 흩어져 있다면 관계가 약하거나 없는 거죠.
여러분이 이 코드를 사용하면 어떤 두 변수든 관계를 분석할 수 있습니다. 키와 몸무게, 온도와 아이스크림 판매량, 광고 클릭과 구매 전환율 등 실무에서 정말 자주 사용합니다.
머신러닝에서 특성(feature) 간 관계를 파악할 때도 산점도는 첫 번째 도구입니다.
실전 팁
💡 점의 크기를 데이터에 연동하려면 s 옵션에 리스트를 전달하세요. s=population처럼 하면 인구가 많을수록 점이 커져서 3차원 정보를 표현할 수 있습니다.
💡 cmap='viridis' 옵션과 함께 c에 숫자 리스트를 전달하면 점 색상이 그라데이션으로 변합니다. 시간 순서나 추가 변수를 색으로 표현할 때 유용하죠.
💡 plt.colorbar()를 추가하면 색상이 의미하는 값의 범례가 나타납니다. 온도, 밀도, 시간 등을 색으로 표현했을 때 필수입니다.
💡 데이터가 많을 때는 alpha 값을 0.3~0.5로 낮추세요. 점들이 겹쳐도 밀도를 파악할 수 있어서 히트맵 효과가 납니다.
5. 여러 그래프 배치하기 - 서브플롯으로 대시보드 만들기
시작하며
여러분이 데이터 분석 결과를 한 번에 보여주고 싶을 때가 있죠? 온도 그래프, 습도 그래프, 풍속 그래프를 따로따로 보여주면 창을 3개나 열어야 해서 불편합니다.
이런 문제는 보고서나 대시보드를 만들 때 항상 발생합니다. 여러 그래프를 한 화면에 깔끔하게 배치하고 싶은데, 어떻게 해야 할까요?
바로 이럴 때 필요한 것이 서브플롯(subplot)입니다. 하나의 창을 격자로 나눠서 여러 그래프를 배치할 수 있게 해줍니다.
개요
간단히 말해서, 서브플롯은 하나의 큰 그림을 여러 칸으로 나눠서 각 칸에 다른 그래프를 그리는 기능입니다. 마치 아파트 평면도처럼 공간을 나누는 거죠.
왜 서브플롯이 필요할까요? 실무에서는 하나의 데이터셋에서 여러 관점의 분석을 동시에 보여줘야 할 때가 많습니다.
예를 들어, 주식 데이터를 분석한다면 가격 추이, 거래량, 이동평균선을 세로로 나란히 배치해서 보는 게 훨씬 유용합니다. 하나의 화면에 모든 정보가 있으니까요.
전통적으로는 그래프를 3개 그려서 파워포인트에 배치했다면, 이제는 코드로 자동화할 수 있습니다. 데이터가 업데이트되면 전체 대시보드가 자동으로 재생성되죠.
서브플롯의 핵심은 plt.subplot()이나 plt.subplots() 함수입니다. 전자는 그래프를 하나씩 추가하는 방식, 후자는 한 번에 격자를 만드는 방식입니다.
subplots()가 더 현대적이고 강력해서 요즘은 주로 이것을 사용합니다.
코드 예제
import matplotlib.pyplot as plt
import numpy as np
# 시간 데이터
time = np.linspace(0, 24, 100)
# 2x2 격자의 서브플롯 생성
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
# 좌상: 온도 그래프
axes[0, 0].plot(time, 20 + 5 * np.sin(time * np.pi / 12), 'r-')
axes[0, 0].set_title('Temperature')
axes[0, 0].set_ylabel('°C')
axes[0, 0].grid(True)
# 우상: 습도 그래프
axes[0, 1].plot(time, 60 + 10 * np.cos(time * np.pi / 12), 'b-')
axes[0, 1].set_title('Humidity')
axes[0, 1].set_ylabel('%')
axes[0, 1].grid(True)
# 좌하: 풍속 그래프
axes[1, 0].plot(time, 3 + 2 * np.random.randn(100).cumsum() / 10, 'g-')
axes[1, 0].set_title('Wind Speed')
axes[1, 0].set_xlabel('Hour')
axes[1, 0].set_ylabel('m/s')
axes[1, 0].grid(True)
# 우하: 기압 그래프
axes[1, 1].plot(time, 1013 + 5 * np.sin(time * np.pi / 6), 'purple')
axes[1, 1].set_title('Pressure')
axes[1, 1].set_xlabel('Hour')
axes[1, 1].set_ylabel('hPa')
axes[1, 1].grid(True)
# 전체 제목
fig.suptitle('Weather Dashboard - 24 Hours', fontsize=16, fontweight='bold')
# 그래프 간격 자동 조정
plt.tight_layout()
plt.show()
설명
이것이 하는 일: 날씨 데이터의 4가지 지표(온도, 습도, 풍속, 기압)를 2x2 격자로 배치해서 한눈에 볼 수 있는 대시보드를 만듭니다. 각 그래프가 독립적이면서도 하나의 주제로 통합되어 있죠.
첫 번째로, plt.subplots(2, 2, figsize=(12, 8))을 호출해서 2행 2열의 격자를 생성합니다. fig는 전체 figure 객체, axes는 4개의 서브플롯에 접근할 수 있는 2차원 배열입니다.
figsize로 전체 크기를 12x8인치로 지정해서 충분히 크게 만듭니다. 두 번째로, axes[0, 0], axes[0, 1], axes[1, 0], axes[1, 1]로 각 칸에 접근합니다.
이것은 numpy 배열처럼 [행, 열] 인덱스를 사용합니다. 각 칸에서 plot(), set_title(), set_ylabel() 등을 호출해서 독립적인 그래프를 그립니다.
온도는 빨강, 습도는 파랑처럼 색상을 다르게 해서 구분을 명확히 합니다. 세 번째로, 각 그래프에 적절한 데이터를 시뮬레이션합니다.
온도는 sin 함수로 낮에 높고 밤에 낮은 패턴, 습도는 cos 함수로 반대 패턴, 풍속은 랜덤한 변화, 기압은 완만한 주기를 가지도록 만듭니다. 실무에서는 여기에 실제 센서 데이터나 API 데이터를 넣겠죠.
마지막으로, fig.suptitle()로 전체 대시보드의 제목을 추가하고, plt.tight_layout()으로 그래프 간 간격을 자동 조정합니다. tight_layout()은 제목이나 라벨이 겹치지 않도록 여백을 최적화해주는 마법 같은 함수입니다.
여러분이 이 코드를 사용하면 원하는 만큼의 그래프를 깔끔하게 배치한 대시보드를 만들 수 있습니다. 3x3으로 9개 그래프를 보여줘도 되고, 1x3으로 가로로 길게 배치해도 됩니다.
데이터 분석 보고서, 모니터링 시스템, 연구 논문 등에서 필수적인 기술입니다.
실전 팁
💡 서브플롯의 크기를 다르게 하려면 plt.subplot2grid()나 GridSpec을 사용하세요. 중요한 그래프는 크게, 보조 그래프는 작게 배치할 수 있습니다.
💡 axes를 1차원으로 사용하려면 subplots(2, 2).flatten()으로 평탄화하세요. for문으로 반복하기 편해집니다.
💡 모든 서브플롯이 같은 x축을 공유한다면 sharex=True 옵션을 추가하세요. 축 라벨이 중복 표시되지 않아 깔끔합니다.
💡 fig.savefig('dashboard.png', dpi=300, bbox_inches='tight')로 저장하면 고해상도 이미지를 얻을 수 있습니다. 논문이나 보고서용으로 완벽합니다.
6. 스타일과 색상 커스터마이징 - 그래프를 내 스타일로
시작하며
여러분이 만든 그래프가 기본 스타일이라 좀 밋밋해 보인 적 있나요? 파란색 선만 계속 나오고, 배경은 하얀색이고, 뭔가 2000년대 느낌이 나는 것 같죠.
프레젠테이션이나 논문에서는 그래프의 시각적 완성도도 중요합니다. 같은 데이터라도 어떻게 꾸미느냐에 따라 전문성이 크게 달라 보이거든요.
바로 이럴 때 필요한 것이 Matplotlib의 스타일과 색상 커스터마이징 기능입니다. 수십 가지 내장 스타일과 무한한 색상 조합으로 그래프를 멋지게 만들 수 있습니다.
개요
간단히 말해서, Matplotlib는 그래프의 모든 시각적 요소를 세밀하게 조정할 수 있는 도구들을 제공합니다. 선 색상, 굵기, 스타일부터 배경색, 폰트, 격자까지 모든 것을 여러분이 원하는 대로 바꿀 수 있죠.
왜 커스터마이징이 필요할까요? 실무에서는 회사 CI에 맞춰야 하거나, 학술지 규정을 따라야 하거나, 단순히 더 보기 좋게 만들어야 할 때가 있습니다.
예를 들어, 다크 모드 프레젠테이션이라면 검은 배경에 밝은 색 선이 필요하고, 흑백 인쇄용이라면 색상 대신 선 스타일로 구분해야 합니다. 전통적으로는 모든 옵션을 일일이 지정해야 했다면, 이제는 plt.style.use()로 미리 만들어진 스타일을 한 줄로 적용할 수 있습니다.
'ggplot', 'seaborn', 'dark_background' 같은 스타일들이 내장되어 있죠. 커스터마이징의 핵심은 일관성입니다.
모든 그래프에 같은 스타일을 적용하면 전체 보고서나 프레젠테이션의 통일감이 생깁니다. 또한 색맹을 고려한 색상 팔레트를 사용하면 접근성도 향상됩니다.
코드 예제
import matplotlib.pyplot as plt
import numpy as np
# 스타일 적용 (여러 스타일 중 선택 가능)
plt.style.use('seaborn-v0_8-darkgrid')
# 데이터 생성
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
# 그림과 축 생성
fig, ax = plt.subplots(figsize=(10, 6))
# 커스텀 색상과 스타일로 그래프 그리기
ax.plot(x, y1, color='#FF6B6B', linewidth=2.5, linestyle='-',
label='sin(x)', marker='o', markevery=10, markersize=8)
ax.plot(x, y2, color='#4ECDC4', linewidth=2.5, linestyle='--',
label='cos(x)', marker='s', markevery=10, markersize=8)
# 축과 제목 커스터마이징
ax.set_title('Trigonometric Functions', fontsize=18, fontweight='bold', pad=20)
ax.set_xlabel('X axis', fontsize=14, fontweight='bold')
ax.set_ylabel('Y axis', fontsize=14, fontweight='bold')
# 범례 커스터마이징
ax.legend(loc='upper right', fontsize=12, frameon=True,
shadow=True, fancybox=True)
# 격자 스타일
ax.grid(True, linestyle=':', alpha=0.6)
# 배경색 (선택사항)
ax.set_facecolor('#F8F9FA')
plt.tight_layout()
plt.show()
설명
이것이 하는 일: sin과 cos 함수 그래프를 전문가 수준의 비주얼로 꾸밉니다. 색상, 선 굵기, 마커, 폰트 등 모든 요소를 세밀하게 조정해서 세련된 느낌을 만듭니다.
첫 번째로, plt.style.use('seaborn-v0_8-darkgrid')로 전체 스타일을 변경합니다. 이것은 Seaborn 라이브러리의 스타일을 가져오는데, 기본 Matplotlib보다 훨씬 현대적이고 깔끔합니다.
다른 옵션으로는 'ggplot'(R 스타일), 'dark_background'(다크 모드), 'bmh'(Bayesian Methods for Hackers) 등이 있습니다. 두 번째로, plot() 함수에 다양한 스타일 옵션을 전달합니다.
color='#FF6B6B'는 hex 코드로 정확한 색상을 지정(산호색), linewidth=2.5는 선을 굵게, linestyle='-'는 실선(cos는 '--'로 점선)을 의미합니다. marker='o'와 markevery=10은 10개마다 동그라미 마커를 표시해서 데이터 포인트를 강조합니다.
세 번째로, 텍스트 요소들을 커스터마이징합니다. set_title()에서 fontsize=18로 제목을 크게, fontweight='bold'로 굵게, pad=20으로 위쪽 여백을 줍니다.
축 라벨도 비슷하게 설정해서 가독성을 높입니다. 마지막으로, 범례와 격자를 꾸밉니다.
legend()의 shadow=True는 그림자 효과, fancybox=True는 둥근 모서리를 추가합니다. grid()의 linestyle=':'은 점선, alpha=0.6은 투명도를 줘서 너무 튀지 않게 만듭니다.
set_facecolor()로 배경을 연한 회색으로 바꾸면 선이 더 돋보입니다. 여러분이 이 코드를 사용하면 기본 그래프를 프로페셔널한 수준으로 업그레이드할 수 있습니다.
학술 논문, 비즈니스 보고서, 데이터 사이언스 포트폴리오 어디든 자신 있게 사용할 수 있는 퀄리티가 됩니다. 색상 선택만 잘해도 완성도가 2배는 높아 보입니다.
실전 팁
💡 plt.style.available로 사용 가능한 모든 스타일 목록을 확인하세요. 하나씩 적용해보면서 마음에 드는 것을 고르면 됩니다.
💡 색상 선택이 어렵다면 colorbrewer2.org나 coolors.co 같은 사이트에서 조화로운 색상 팔레트를 가져오세요. 전문 디자이너가 만든 조합입니다.
💡 plt.rcParams를 사용하면 폰트, 크기, 색상 등을 프로젝트 전체에 일괄 적용할 수 있습니다. 설정 파일처럼 사용하세요.
💡 색맹 친화적인 색상을 원한다면 'tab10' colormap이나 '#1f77b4', '#ff7f0e' 같은 구별 가능한 색상을 사용하세요.
7. 히스토그램 만들기 - 데이터 분포를 한눈에
시작하며
여러분이 100명의 시험 점수를 분석한다고 생각해보세요. 각 점수를 나열하면 너무 길고, 평균만 보면 분포를 알 수 없습니다.
대부분이 70점대인지, 골고루 퍼져있는지 알 수가 없죠. 이런 데이터 분포를 파악할 때는 히스토그램이 최고입니다.
점수 구간별로 몇 명이 있는지 막대로 보여줘서 전체 분포가 한눈에 들어옵니다. 바로 이럴 때 필요한 것이 hist() 함수입니다.
연속형 데이터의 분포를 구간별 빈도로 시각화해서 패턴을 즉시 파악할 수 있게 해줍니다.
개요
간단히 말해서, 히스토그램은 연속형 데이터를 여러 구간(bin)으로 나누고 각 구간에 속하는 데이터 개수를 막대로 표현하는 그래프입니다. 마치 키를 10cm 단위로 묶어서 사람 수를 세는 것과 같아요.
왜 히스토그램이 필요할까요? 실무에서는 데이터가 정규분포인지, 치우쳐 있는지, 이상치가 있는지 빠르게 확인해야 할 때가 많습니다.
예를 들어, 고객 나이 분포를 보면 타겟 고객층이 어디인지, 웹사이트 로딩 시간 분포를 보면 최적화가 필요한지 알 수 있습니다. 전통적인 막대 그래프는 카테고리를 비교하지만, 히스토그램은 연속된 숫자의 분포를 보여줍니다.
점수, 나이, 키, 시간, 금액 같은 연속형 데이터에 완벽하죠. 히스토그램의 핵심은 bin(구간) 개수입니다.
너무 많으면 너무 세밀해서 패턴이 안 보이고, 너무 적으면 너무 뭉뚱그려져서 디테일을 잃습니다. 보통 데이터 개수의 제곱근 정도가 적당하다고 알려져 있습니다.
코드 예제
import matplotlib.pyplot as plt
import numpy as np
# 100명 학생의 시험 점수 (정규분포로 시뮬레이션)
np.random.seed(42) # 재현 가능성을 위해
scores = np.random.normal(75, 10, 100) # 평균 75, 표준편차 10
scores = np.clip(scores, 0, 100) # 0-100 범위로 제한
# 히스토그램 그리기
fig, ax = plt.subplots(figsize=(10, 6))
n, bins, patches = ax.hist(scores, bins=20, color='skyblue',
edgecolor='black', alpha=0.7)
# 색상 그라데이션 (점수가 높을수록 진한 색)
for i, patch in enumerate(patches):
patch.set_facecolor(plt.cm.viridis(i / len(patches)))
# 평균선 추가
mean_score = scores.mean()
ax.axvline(mean_score, color='red', linestyle='--', linewidth=2,
label=f'Mean: {mean_score:.1f}')
# 그래프 꾸미기
ax.set_title('Test Score Distribution (100 Students)', fontsize=16, fontweight='bold')
ax.set_xlabel('Score', fontsize=12)
ax.set_ylabel('Number of Students', fontsize=12)
ax.legend()
ax.grid(axis='y', alpha=0.3)
# 통계 정보 텍스트 박스
textstr = f'Mean: {mean_score:.1f}\nStd: {scores.std():.1f}\nMin: {scores.min():.1f}\nMax: {scores.max():.1f}'
ax.text(0.02, 0.98, textstr, transform=ax.transAxes, fontsize=10,
verticalalignment='top', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
plt.tight_layout()
plt.show()
설명
이것이 하는 일: 100명 학생의 시험 점수 분포를 히스토그램으로 시각화합니다. 대부분이 70-80점대에 몰려있고, 평균이 75점이라는 것을 한눈에 알 수 있죠.
첫 번째로, 테스트 데이터를 생성합니다. np.random.normal(75, 10, 100)은 평균 75, 표준편차 10인 정규분포에서 100개 값을 뽑습니다.
실제 시험 점수는 보통 정규분포를 따르거든요. np.clip()으로 0-100 범위를 벗어나는 값을 잘라냅니다.
두 번째로, ax.hist()가 실행되면서 히스토그램이 그려집니다. bins=20은 점수를 20개 구간으로 나눈다는 뜻입니다(0-5점, 5-10점, ...
95-100점). 반환값 n은 각 구간의 개수, bins는 구간 경계값, patches는 막대 객체들입니다.
세 번째로, for 반복문으로 각 막대에 색상 그라데이션을 적용합니다. plt.cm.viridis는 과학적으로 인지하기 좋은 colormap인데, 왼쪽(낮은 점수)은 보라색, 오른쪽(높은 점수)은 노란색으로 변합니다.
이렇게 하면 점수 범위가 시각적으로 명확해집니다. 네 번째로, ax.axvline()으로 평균값에 빨간 점선을 그어줍니다.
이 선을 기준으로 왼쪽은 평균 이하, 오른쪽은 평균 이상이라는 것을 쉽게 파악할 수 있죠. 중앙값이나 목표 점수 같은 다른 기준선도 같은 방법으로 추가할 수 있습니다.
마지막으로, ax.text()로 통계 정보를 텍스트 박스에 표시합니다. 평균, 표준편차, 최소값, 최대값을 한눈에 볼 수 있게 하죠.
bbox 옵션으로 배경을 밀색으로 주고 둥근 모서리를 만들어서 보기 좋게 합니다. 여러분이 이 코드를 사용하면 어떤 연속형 데이터든 분포를 즉시 파악할 수 있습니다.
고객 구매 금액, 웹페이지 로딩 시간, 직원 연봉, 제품 무게 등 실무에서 정말 자주 사용합니다. 특히 머신러닝 전에 데이터 분포를 확인하는 것은 필수 과정입니다.
실전 팁
💡 bins 옵션에 숫자 대신 'auto', 'sturges', 'scott' 같은 문자열을 전달하면 자동으로 최적 구간 개수를 계산합니다. 어떻게 나눌지 고민될 때 유용해요.
💡 cumulative=True 옵션을 추가하면 누적 히스토그램이 됩니다. "80점 이하가 몇 명인가" 같은 질문에 답할 때 좋습니다.
💡 density=True를 설정하면 y축이 빈도가 아닌 확률 밀도가 됩니다. 확률 분포를 정규화된 형태로 보고 싶을 때 사용하세요.
💡 여러 데이터셋을 비교하려면 alpha=0.5로 투명도를 주고 겹쳐 그리세요. 남녀 점수 분포 비교 같은 경우에 효과적입니다.
8. 파이 차트로 비율 표현하기 - 전체 중 일부를 보여주기
시작하며
여러분이 회사 예산 배분을 보고한다고 생각해보세요. 마케팅 30%, 개발 40%, 운영 20%, 기타 10%...
숫자로만 보면 와닿지 않습니다. 전체 중에서 얼마나 차지하는지 시각적으로 보고 싶죠.
이런 비율이나 구성비를 보여줄 때는 파이 차트(원 그래프)가 직관적입니다. 원을 조각으로 나눠서 각 부분이 전체의 몇 퍼센트인지 한눈에 보여주거든요.
바로 이럴 때 필요한 것이 pie() 함수입니다. 전체를 100%로 보고 각 항목의 비율을 원 조각으로 표현해서 구성을 명확히 전달합니다.
개요
간단히 말해서, 파이 차트는 전체를 원으로 표현하고, 각 카테고리를 조각으로 나눠서 비율을 보여주는 그래프입니다. 마치 피자를 여러 조각으로 나누는 것과 같아요.
왜 파이 차트가 필요할까요? 실무에서는 부분이 전체의 몇 퍼센트를 차지하는지 보여줘야 할 때가 많습니다.
예를 들어, 시장 점유율, 예산 배분, 트래픽 소스, 설문조사 응답 비율 등을 보여줄 때 파이 차트만큼 직관적인 게 없습니다. 전통적으로 숫자와 퍼센트를 나열했다면, 파이 차트는 큰 조각과 작은 조각의 차이를 시각적으로 즉시 비교할 수 있게 해줍니다.
"A가 B보다 2배 크다"는 것을 조각 크기로 바로 느낄 수 있죠. 파이 차트의 핵심은 전체의 합이 100%라는 것입니다.
각 값의 비율을 자동으로 계산해서 원을 나눕니다. explode 옵션으로 특정 조각을 바깥으로 빼서 강조할 수도 있습니다.
코드 예제
import matplotlib.pyplot as plt
# 회사 예산 데이터
categories = ['Development', 'Marketing', 'Operations', 'HR', 'Others']
budgets = [40, 30, 20, 7, 3] # 비율 (합이 100일 필요는 없음)
# 색상 지정 (부서별 고유 색상)
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8']
# 가장 큰 항목 강조 (Development)
explode = (0.1, 0, 0, 0, 0) # 첫 번째 조각만 분리
# 파이 차트 생성
fig, ax = plt.subplots(figsize=(10, 8))
wedges, texts, autotexts = ax.pie(budgets, labels=categories, autopct='%1.1f%%',
startangle=90, colors=colors, explode=explode,
shadow=True, textprops={'fontsize': 11})
# 퍼센트 텍스트 스타일 (흰색, 굵게)
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontweight('bold')
# 제목
ax.set_title('Company Budget Allocation 2024', fontsize=16, fontweight='bold', pad=20)
# 범례 (금액 추가)
total = sum(budgets)
legend_labels = [f'{cat}: ${bud}M ({bud/total*100:.1f}%)'
for cat, bud in zip(categories, budgets)]
ax.legend(legend_labels, loc='center left', bbox_to_anchor=(1, 0, 0.5, 1))
plt.tight_layout()
plt.show()
설명
이것이 하는 일: 회사 예산을 5개 부서로 나눠서 각 부서가 전체 예산의 몇 퍼센트를 사용하는지 파이 차트로 보여줍니다. 개발팀이 40%로 가장 크고, 기타가 3%로 가장 작다는 것이 즉시 보이죠.
첫 번째로, 카테고리 이름과 값을 리스트로 준비합니다. budgets의 값들은 절대값이어도 되고 비율이어도 됩니다.
Matplotlib가 자동으로 전체 합에서 각각이 차지하는 비율을 계산해주거든요. 색상도 리스트로 지정해서 각 부서마다 고유한 색을 부여합니다.
두 번째로, explode 튜플을 만들어서 강조하고 싶은 조각을 지정합니다. (0.1, 0, 0, 0, 0)은 첫 번째 조각(Development)만 0.1만큼 바깥으로 빼라는 뜻입니다.
가장 중요한 항목을 강조하는 효과적인 방법이죠. 세 번째로, ax.pie()가 실행되면서 파이 차트가 그려집니다.
autopct='%1.1f%%'는 각 조각에 퍼센트를 자동으로 표시하라는 뜻입니다(%1.1f는 소수점 첫째 자리까지). startangle=90은 12시 방향부터 시작하게 만들고, shadow=True는 그림자 효과를 추가해서 입체감을 줍니다.
네 번째로, 반환된 autotexts(퍼센트 텍스트들)의 색상을 흰색으로, 굵게 만들어서 가독성을 높입니다. 기본 색상은 검은색인데, 어두운 조각에서는 안 보일 수 있거든요.
마지막으로, 범례를 만들 때 단순히 카테고리 이름만이 아니라 실제 금액과 퍼센트를 함께 표시합니다. 이렇게 하면 조각 크기(시각적)와 정확한 값(숫자)을 동시에 제공할 수 있습니다.
bbox_to_anchor로 범례를 차트 오른쪽에 배치해서 깔끔하게 만듭니다. 여러분이 이 코드를 사용하면 모든 종류의 구성비 데이터를 효과적으로 전달할 수 있습니다.
시장 점유율, 트래픽 출처, 매출 구성, 인구 분포 등 "전체 중 일부"를 보여줘야 할 때마다 유용합니다. 다만 조각이 7개 이상이면 너무 복잡해 보이니 주요 항목만 표시하고 나머지는 "기타"로 묶는 게 좋습니다.
실전 팁
💡 파이 차트는 조각이 5-6개 이하일 때 가장 효과적입니다. 너무 많으면 막대 그래프로 바꾸는 것을 고려하세요.
💡 startangle을 조정해서 가장 중요한 조각이 12시 방향에 오도록 배치하세요. 시선이 가장 먼저 가는 위치입니다.
💡 색상을 선택할 때는 인접한 조각이 비슷한 색이 되지 않도록 주의하세요. 구분이 어려워집니다.
💡 도넛 차트를 만들려면 wedgeprops={'width': 0.3} 옵션을 추가하세요. 중앙이 비어서 현대적인 느낌이 납니다.
9. 박스플롯으로 분포 요약하기 - 통계적 관점에서 데이터 보기
시작하며
여러분이 3개 지점의 판매 실적을 비교한다고 생각해보세요. 각 지점마다 30일치 데이터가 있는데, 30개 숫자를 일일이 비교할 수는 없죠.
평균만 보면 중요한 정보를 놓칠 수 있고요. 이럴 때는 데이터의 중심, 퍼짐, 이상치를 한 번에 보여주는 도구가 필요합니다.
통계 전문가들이 가장 선호하는 방법이 바로 박스플롯입니다. 바로 이럴 때 필요한 것이 boxplot() 함수입니다.
데이터를 5가지 숫자(최소, 1사분위, 중앙값, 3사분위, 최대)로 요약해서 상자로 표현하고, 이상치까지 찾아줍니다.
개요
간단히 말해서, 박스플롯은 데이터의 분포를 상자와 선으로 요약해서 보여주는 그래프입니다. 상자의 중간선은 중앙값, 상자의 크기는 데이터의 퍼짐 정도, 상자 밖의 점은 이상치를 나타내죠.
왜 박스플롯이 필요할까요? 실무에서는 여러 그룹의 데이터를 한눈에 비교하면서 동시에 각 그룹의 분포 특성도 파악해야 할 때가 많습니다.
예를 들어, A/B 테스트 결과를 비교하거나, 여러 제품의 품질을 비교하거나, 지역별 소득 분포를 비교할 때 박스플롯이 최적입니다. 전통적으로 평균과 표준편차만 보고했다면, 박스플롯은 중앙값, 사분위수, 범위, 이상치까지 한 번에 보여줍니다.
데이터가 치우쳐 있는지(skewed), 극단값이 있는지 즉시 알 수 있죠. 박스플롯의 핵심 구성 요소는 5가지입니다: 최소값(수염 하단), 1사분위수(상자 하단), 중앙값(상자 중간선), 3사분위수(상자 상단), 최대값(수염 상단).
이 5개 숫자만으로도 분포의 핵심을 전부 파악할 수 있습니다.
코드 예제
import matplotlib.pyplot as plt
import numpy as np
# 3개 지점의 30일간 판매 실적 (시뮬레이션)
np.random.seed(42)
branch_a = np.random.normal(100, 15, 30) # 평균 100, 표준편차 15
branch_b = np.random.normal(120, 20, 30) # 평균 120, 표준편차 20
branch_c = np.random.normal(95, 10, 30) # 평균 95, 표준편차 10
# 이상치 추가 (B지점에 특별 이벤트)
branch_b = np.append(branch_b, [180, 190])
data = [branch_a, branch_b, branch_c]
# 박스플롯 생성
fig, ax = plt.subplots(figsize=(10, 7))
bp = ax.boxplot(data, labels=['Branch A', 'Branch B', 'Branch C'],
patch_artist=True, # 색상 채우기 가능
notch=True, # 노치(신뢰구간) 표시
showmeans=True) # 평균값도 표시
# 각 박스에 다른 색상 적용
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1']
for patch, color in zip(bp['boxes'], colors):
patch.set_facecolor(color)
patch.set_alpha(0.6)
# 중앙값 선을 굵고 진하게
for median in bp['medians']:
median.set_color('darkred')
median.set_linewidth(2)
# 그래프 꾸미기
ax.set_title('Sales Performance Comparison (30 Days)', fontsize=16, fontweight='bold')
ax.set_ylabel('Sales (units)', fontsize=12)
ax.set_xlabel('Branch', fontsize=12)
ax.grid(axis='y', alpha=0.3)
# 통계 정보 추가
stats_text = f"Branch A: median={np.median(branch_a):.1f}\n"
stats_text += f"Branch B: median={np.median(branch_b):.1f}\n"
stats_text += f"Branch C: median={np.median(branch_c):.1f}"
ax.text(0.02, 0.98, stats_text, transform=ax.transAxes, fontsize=10,
verticalalignment='top', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
plt.tight_layout()
plt.show()
설명
이것이 하는 일: 3개 지점의 30일간 판매 실적을 박스플롯으로 비교합니다. B지점이 중앙값은 높지만 변동성도 크고, C지점은 안정적이고, A지점은 중간 정도라는 것을 한눈에 파악할 수 있죠.
첫 번째로, 각 지점의 데이터를 정규분포로 시뮬레이션합니다. branch_a는 평균 100에 표준편차 15, branch_b는 평균 120에 표준편차 20으로 설정해서 B지점이 실적은 좋지만 불안정하다는 상황을 만듭니다.
branch_b에 180, 190 같은 극단값을 추가해서 특별 이벤트가 있었다는 시나리오를 만들죠. 두 번째로, data 리스트에 3개 지점 데이터를 담고 ax.boxplot()에 전달합니다.
patch_artist=True는 상자에 색을 칠할 수 있게, notch=True는 상자 중간에 오목한 부분을 만들어 신뢰구간을 표시, showmeans=True는 평균값도 함께 표시하라는 뜻입니다. 세 번째로, 반환된 bp 딕셔너리를 사용해서 스타일을 커스터마이징합니다.
bp['boxes']는 3개 상자 객체, bp['medians']는 3개 중앙값 선입니다. for 반복문으로 각 상자에 다른 색상을 적용하고, 중앙값 선을 진한 빨강으로 굵게 만들어서 눈에 띄게 합니다.
네 번째로, 그래프를 해석하는 방법을 알아봅니다. 상자의 높이가 크면 데이터가 퍼져 있다는(분산이 크다는) 뜻입니다.
B지점의 상자가 가장 큰 것을 보세요. 상자 밖의 동그라미 점들은 이상치인데, B지점에만 있습니다.
이것은 대부분의 날은 120 정도지만, 특별히 잘 팔린 날(180, 190)이 있었다는 뜻이죠. 마지막으로, 통계 정보를 텍스트 박스에 표시해서 정확한 중앙값을 제공합니다.
시각적 비교와 정확한 숫자를 동시에 제공하는 거죠. 박스플롯만 보면 C지점이 가장 안정적(상자가 작음)이고, B지점이 변동성이 크다(상자가 큼)는 것을 알 수 있습니다.
여러분이 이 코드를 사용하면 데이터 과학과 통계 분석에서 필수적인 비교 분석을 수행할 수 있습니다. A/B 테스트, 품질 관리, 실험 결과 비교, 시계열 비교 등에서 정말 자주 사용됩니다.
특히 이상치가 중요한 금융, 의료, 품질 관리 분야에서는 필수 도구입니다.
실전 팁
💡 vert=False 옵션을 추가하면 가로 박스플롯이 됩니다. 카테고리 이름이 길 때 유용합니다.
💡 여러 그룹의 박스플롯을 나란히 배치하려면 데이터를 리스트의 리스트로 구성하세요. [[group1_a, group1_b], [group2_a, group2_b]] 형식입니다.
💡 widths=[0.5, 0.5, 0.5] 옵션으로 상자 폭을 조절할 수 있습니다. 중요도에 따라 다르게 하면 시각적 계층이 생깁니다.
💡 violin plot(violinplot)을 대안으로 고려하세요. 박스플롯과 비슷하지만 분포의 모양까지 보여줘서 더 풍부한 정보를 제공합니다.
10. 히트맵으로 2차원 데이터 표현하기 - 색으로 값의 크기 보여주기
시작하며
여러분이 1주일간 시간대별 웹사이트 트래픽을 분석한다고 생각해보세요. 7일 x 24시간 = 168개의 숫자를 표로 보면 머리가 아픕니다.
어느 요일 어느 시간대가 바쁜지 한눈에 파악하고 싶죠. 이런 2차원 데이터(행과 열이 모두 의미가 있는)를 표현할 때는 히트맵이 최고입니다.
숫자를 색의 진하기로 바꿔서 패턴이 즉시 보이게 만들거든요. 바로 이럴 때 필요한 것이 imshow()나 pcolormesh() 함수입니다.
2차원 배열을 색상 그라데이션으로 표현해서 큰 값과 작은 값을 시각적으로 구분합니다.
개요
간단히 말해서, 히트맵은 2차원 데이터를 색상으로 표현하는 그래프입니다. 마치 온도를 측정할 때 열화상 카메라로 보면 뜨거운 곳은 빨강, 차가운 곳은 파랑으로 보이는 것과 같아요.
왜 히트맵이 필요할까요? 실무에서는 행렬 형태의 데이터를 다룰 때가 정말 많습니다.
예를 들어, 시간대별 판매량, 지역별 매출, 상관관계 행렬, 사용자-제품 매트릭스 등을 분석할 때 히트맵만큼 직관적인 게 없습니다. 색이 진한 곳이 핫스팟이라는 것을 누구나 즉시 이해하죠.
전통적으로 2차원 데이터는 표로 표시했지만, 100개 이상의 셀은 눈으로 비교하기 불가능합니다. 히트맵은 1000개 셀도 색으로 한눈에 비교할 수 있게 해줍니다.
히트맵의 핵심은 colormap(색상표)입니다. 'viridis'는 낮은 값은 보라, 높은 값은 노랑으로, 'coolwarm'은 낮은 값은 파랑, 높은 값은 빨강으로 표현합니다.
목적에 맞는 colormap을 선택하는 것이 중요하죠.
코드 예제
import matplotlib.pyplot as plt
import numpy as np
# 7일 x 24시간 웹사이트 트래픽 데이터 (시뮬레이션)
days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
hours = [f'{h:02d}:00' for h in range(24)]
# 기본 트래픽 패턴 생성
np.random.seed(42)
traffic = np.random.randint(50, 150, (7, 24))
# 현실적인 패턴 추가 (주말, 저녁 시간대 트래픽 증가)
traffic[5:7, :] += 50 # 토요일, 일요일 증가
traffic[:, 18:23] += 80 # 저녁 6시~10시 증가
traffic[:, 0:6] -= 30 # 새벽 감소
# 히트맵 생성
fig, ax = plt.subplots(figsize=(14, 7))
im = ax.imshow(traffic, cmap='YlOrRd', aspect='auto')
# 축 설정
ax.set_xticks(np.arange(len(hours)))
ax.set_yticks(np.arange(len(days)))
ax.set_xticklabels(hours, rotation=45, ha='right')
ax.set_yticklabels(days)
# 각 셀에 숫자 표시
for i in range(len(days)):
for j in range(len(hours)):
text = ax.text(j, i, traffic[i, j],
ha='center', va='center', color='black', fontsize=8)
# 컬러바 추가
cbar = plt.colorbar(im, ax=ax)
cbar.set_label('Traffic (users/hour)', rotation=270, labelpad=20)
# 제목과 라벨
ax.set_title('Website Traffic Heatmap (7 Days x 24 Hours)',
fontsize=16, fontweight='bold', pad=20)
ax.set_xlabel('Hour of Day', fontsize=12)
ax.set_ylabel('Day of Week', fontsize=12)
plt.tight_layout()
plt.show()
설명
이것이 하는 일: 1주일간 시간대별 웹사이트 트래픽을 7x24 히트맵으로 시각화합니다. 주말 저녁 시간대가 진한 빨강으로 표시되어 트래픽이 가장 많다는 것을 즉시 알 수 있죠.
첫 번째로, 데이터를 2차원 numpy 배열로 준비합니다. (7, 24) 모양의 배열은 7개 행(요일)과 24개 열(시간)을 의미합니다.
현실적인 패턴을 만들기 위해 주말(5, 6번째 행)과 저녁(18-22번째 열)의 값을 높이고, 새벽(0-5번째 열)의 값을 낮춥니다. 두 번째로, ax.imshow()가 배열을 이미지처럼 표시합니다.
cmap='YlOrRd'는 노랑-주황-빨강 색상표를 사용하라는 뜻인데, 낮은 값은 연한 노랑, 높은 값은 진한 빨강으로 나타냅니다. aspect='auto'는 셀의 가로세로 비율을 자동 조정해서 화면에 꽉 차게 만듭니다.
세 번째로, 축을 설정합니다. set_xticks()와 set_xticklabels()로 x축에 00:00부터 23:00까지 시간을 표시하고, rotation=45로 45도 기울여서 겹치지 않게 합니다.
y축에는 월요일부터 일요일까지 요일을 표시하죠. 네 번째로, 이중 for 반복문으로 각 셀에 정확한 숫자를 표시합니다.
색만으로는 정확한 값을 알기 어려우니까 텍스트를 추가하는 거죠. 다만 셀이 너무 많으면(100개 이상) 텍스트는 생략하는 게 좋습니다.
마지막으로, plt.colorbar()로 오른쪽에 색상 범례를 추가합니다. 이것은 색상이 어떤 값을 의미하는지 알려주는 눈금자 역할을 합니다.
연한 노랑은 50명 정도, 진한 빨강은 200명 이상이라는 것을 한눈에 파악할 수 있죠. 여러분이 이 코드를 사용하면 복잡한 2차원 패턴을 즉시 발견할 수 있습니다.
사용자 행동 분석, 센서 데이터, 상관관계 분석, 게임 맵, 딥러닝의 가중치 시각화 등 정말 다양한 분야에서 활용됩니다. 특히 데이터 사이언스에서는 상관관계 행렬을 히트맵으로 보는 것이 표준입니다.
실전 팁
💡 상관관계 행렬을 표시할 때는 cmap='coolwarm', vmin=-1, vmax=1을 사용하세요. 음의 상관은 파랑, 양의 상관은 빨강으로 명확히 구분됩니다.
💡 셀이 많아서 숫자를 표시하기 어려우면 텍스트를 생략하고 colorbar만 사용하세요. 대신 colorbar의 눈금을 세밀하게 설정합니다.
💡 plt.pcolormesh()는 imshow()보다 불규칙한 격자에 적합합니다. 데이터 포인트가 균일하지 않을 때 사용하세요.
💡 annot=True 같은 기능을 원한다면 seaborn 라이브러리의 sns.heatmap()을 고려하세요. Matplotlib보다 히트맵 전용 기능이 더 많습니다.
댓글 (0)
함께 보면 좋은 카드 뉴스
데이터 증강과 정규화 완벽 가이드
머신러닝 모델의 성능을 극대화하는 핵심 기법인 데이터 증강과 정규화에 대해 알아봅니다. 실무에서 바로 활용할 수 있는 다양한 기법과 실전 예제를 통해 과적합을 방지하고 모델 성능을 향상시키는 방법을 배웁니다.
ResNet과 Skip Connection 완벽 가이드
딥러닝 모델이 깊어질수록 성능이 떨어지는 문제를 해결한 혁신적인 기법, ResNet과 Skip Connection을 초급자도 이해할 수 있도록 쉽게 설명합니다. 실제 구현 코드와 함께 배워보세요.
CNN 아키텍처 완벽 가이드 LeNet AlexNet VGGNet
컴퓨터 비전의 기초가 되는 세 가지 핵심 CNN 아키텍처를 배웁니다. 손글씨 인식부터 이미지 분류까지, 딥러닝의 발전 과정을 따라가며 각 모델의 구조와 특징을 실습 코드와 함께 이해합니다.
CNN 기초 Convolution과 Pooling 완벽 가이드
CNN의 핵심인 Convolution과 Pooling을 초급자도 쉽게 이해할 수 있도록 설명합니다. 이미지 인식의 원리부터 실제 코드 구현까지, 실무에서 바로 활용 가능한 내용을 담았습니다.
TensorFlow와 Keras 완벽 입문 가이드
머신러닝과 딥러닝의 세계로 들어가는 첫걸음! TensorFlow와 Keras 프레임워크를 처음 접하는 분들을 위한 친절한 가이드입니다. 실무에서 바로 활용할 수 있는 핵심 개념과 예제를 통해 AI 모델 개발의 기초를 탄탄히 다져보세요.