Skip to content
주제
Matplotlib
Matplotlib 히스토그램: Python에서 plt.hist()의 완전 가이드

Matplotlib 히스토그램: Python에서 plt.hist()의 완전 가이드

Updated on

수천 개의 숫자 값(나이, 시험 점수, 응답 시간, 센서 판독값)이 포함된 데이터셋이 있고, 이 값들이 어떻게 분포되어 있는지 이해해야 합니다. 중심점 주위에 모여 있나요? 한쪽으로 치우쳐 있나요? 정규 분포를 따르나요? 산점도는 도움이 되지 않습니다. 막대 차트는 범주형 데이터용이지 연속 데이터용이 아닙니다. 필요한 것은 히스토그램이며, Python에서 matplotlib.pyplot.hist()가 이를 만드는 표준 방법입니다.

문제는 plt.hist()에 12개 이상의 매개변수가 있고, 기본 출력이 종종 단조롭거나 오해의 소지가 있다는 것입니다. 잘못된 빈 수를 선택하면 데이터의 중요한 패턴이 숨겨질 수 있습니다. 하나의 차트에서 여러 분포를 비교하려면 올바른 옵션 조합을 알아야 합니다. 이 가이드는 중요한 모든 매개변수를 노트북이나 스크립트에 직접 복사할 수 있는 작동하는 코드 예제와 함께 다룹니다.

📚

히스토그램이란 무엇이며 언제 사용해야 하나요?

히스토그램은 숫자 값의 범위를 **빈(bin)**이라 불리는 동일 너비의 구간으로 나누고, 각 빈에 속하는 데이터 포인트의 수를 셉니다. x축은 값 범위를 나타내고, y축은 각 빈의 빈도(개수) 또는 밀도를 나타냅니다. 범주형 데이터를 표시하는 막대 차트와 달리, 히스토그램은 연속적인 수치 데이터의 분포를 나타냅니다.

히스토그램을 사용해야 하는 경우:

  • 분포의 형태 확인 (정규, 편향, 이봉, 균일)
  • 데이터의 이상값이나 공백 식별
  • 그룹 간 값의 퍼짐 비교
  • 모델링 전 데이터 변환 결정

기본 plt.hist() 구문

가장 간단한 히스토그램은 데이터 배열이라는 하나의 인수만 필요합니다.

import matplotlib.pyplot as plt
import numpy as np
 
# Generate 1000 normally distributed values
np.random.seed(42)
data = np.random.normal(loc=50, scale=15, size=1000)
 
plt.hist(data)
plt.title('Basic Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()

기본적으로 matplotlib는 데이터를 10개의 빈으로 나눕니다. 이 함수는 세 가지 객체를 반환합니다: 빈 카운트, 빈 가장자리, 패치 객체(그려진 직사각형). 이러한 반환 값에 대해서는 나중에 자세히 다루겠습니다.

전체 시그니처

plt.hist(x, bins=None, range=None, density=False, weights=None,
         cumulative=False, bottom=None, histtype='bar', align='mid',
         orientation='vertical', rwidth=None, log=False, color=None,
         label=None, stacked=False, edgecolor=None, alpha=None)

빈 제어

bins 매개변수는 히스토그램에서 가장 중요한 설정입니다. 빈이 너무 적으면 패턴이 숨겨집니다. 빈이 너무 많으면 노이즈가 생깁니다.

고정된 빈 수 설정

fig, axes = plt.subplots(1, 3, figsize=(14, 4))
 
axes[0].hist(data, bins=5, edgecolor='black')
axes[0].set_title('5 Bins')
 
axes[1].hist(data, bins=30, edgecolor='black')
axes[1].set_title('30 Bins')
 
axes[2].hist(data, bins=100, edgecolor='black')
axes[2].set_title('100 Bins')
 
plt.tight_layout()
plt.show()

5개의 빈에서는 대략적인 형태만 볼 수 있습니다. 100개의 빈에서는 빈당 작은 표본 크기가 시각적 노이즈를 만듭니다. 이 1,000개 포인트 데이터셋에서 30개의 빈은 정규 분포의 명확한 그림을 만들어냅니다.

사용자 정의 빈 가장자리

bins에 시퀀스를 전달하여 정확한 경계를 정의합니다:

custom_edges = [0, 20, 35, 50, 65, 80, 100]
plt.hist(data, bins=custom_edges, edgecolor='black', color='steelblue')
plt.title('Histogram with Custom Bin Edges')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()

이것은 데이터에 의미 있는 임계값이 있을 때 유용합니다 -- 문자 등급, 연령대 또는 성과 단계.

자동 빈 알고리즘

Matplotlib는 데이터 특성을 기반으로 최적의 빈 수를 계산하는 여러 알고리즘을 지원합니다:

알고리즘bins=방법적합한 용도
Sturges'sturges'1 + log2(n)작고 대략 정규 분포인 데이터셋
Scott'scott'표준편차와 n 기반정규 또는 거의 정규인 데이터
Freedman-Diaconis'fd'IQR과 n 기반이상값에 강건함
제곱근'sqrt'sqrt(n)빠른 대략적 추정
Auto'auto'Sturges와 FD의 최댓값범용 기본값
fig, axes = plt.subplots(1, 3, figsize=(14, 4))
 
for ax, method in zip(axes, ['sturges', 'scott', 'fd']):
    ax.hist(data, bins=method, edgecolor='black', color='#4C72B0')
    ax.set_title(f'bins="{method}"')
 
plt.tight_layout()
plt.show()

대부분의 경우, bins='auto'가 확실한 출발점입니다. 데이터에 이상값이 포함된 경우 'fd'로 전환하세요. 표준편차 대신 사분위 범위를 사용하기 때문입니다.

정규화 및 밀도 히스토그램

기본적으로 y축은 원시 카운트를 보여줍니다. density=True를 설정하면 막대 아래의 총 면적이 1이 되도록 히스토그램을 정규화합니다. 이것은 y축을 빈도에서 확률 밀도로 변환합니다.

fig, axes = plt.subplots(1, 2, figsize=(12, 4))
 
axes[0].hist(data, bins=30, edgecolor='black', color='#55A868')
axes[0].set_title('Frequency (default)')
axes[0].set_ylabel('Count')
 
axes[1].hist(data, bins=30, edgecolor='black', color='#C44E52', density=True)
axes[1].set_title('Density (density=True)')
axes[1].set_ylabel('Probability Density')
 
plt.tight_layout()
plt.show()

밀도 정규화는 이론적 분포 곡선을 오버레이하거나 크기가 다른 데이터셋을 비교할 때 필수적입니다:

from scipy import stats
 
plt.hist(data, bins=30, density=True, edgecolor='black', color='#55A868', alpha=0.7)
 
# Overlay the theoretical normal curve
x_range = np.linspace(data.min(), data.max(), 200)
plt.plot(x_range, stats.norm.pdf(x_range, loc=50, scale=15), 'r-', linewidth=2, label='Normal PDF')
plt.legend()
plt.title('Density Histogram with Normal Curve Overlay')
plt.show()

외관 사용자 정의

색상, 테두리 색상, 투명도

plt.hist(data, bins=30, color='#4C72B0', edgecolor='white', alpha=0.85)
plt.title('Styled Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()

히스토그램 유형

histtype 매개변수는 시각적 스타일을 변경합니다:

histtype설명
'bar'전통적인 채워진 막대 (기본값)
'barstacked'여러 데이터셋을 위한 누적 막대
'step'채우지 않은 선 윤곽
'stepfilled'계단형 윤곽이 있는 채워진 영역
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
types = ['bar', 'barstacked', 'step', 'stepfilled']
 
for ax, ht in zip(axes.flat, types):
    ax.hist(data, bins=30, histtype=ht, edgecolor='black', color='#4C72B0')
    ax.set_title(f'histtype="{ht}"')
 
plt.tight_layout()
plt.show()

'step' 유형은 여러 분포를 오버레이할 때 특히 유용합니다. 채우지 않은 윤곽은 서로를 가리지 않기 때문입니다.

하나의 플롯에 여러 히스토그램

겹치는 히스토그램

alpha(투명도)를 사용하여 두 개 이상의 분포를 겹칩니다:

np.random.seed(42)
group_a = np.random.normal(loc=50, scale=10, size=800)
group_b = np.random.normal(loc=65, scale=12, size=800)
 
plt.hist(group_a, bins=30, alpha=0.6, color='#4C72B0', edgecolor='black', label='Group A')
plt.hist(group_b, bins=30, alpha=0.6, color='#C44E52', edgecolor='black', label='Group B')
plt.legend()
plt.title('Overlapping Histograms')
plt.xlabel('Score')
plt.ylabel('Frequency')
plt.show()

나란히 놓은 히스토그램

배열의 리스트를 전달하여 그룹화된 막대로 표시합니다:

plt.hist([group_a, group_b], bins=20, color=['#4C72B0', '#C44E52'],
         edgecolor='black', label=['Group A', 'Group B'])
plt.legend()
plt.title('Side-by-Side Histograms')
plt.xlabel('Score')
plt.ylabel('Frequency')
plt.show()

배열의 리스트를 전달하면, matplotlib는 각 빈 내에서 각 데이터셋의 막대를 나란히 배치합니다.

누적 히스토그램

stacked=True를 설정하여 한 데이터셋을 다른 데이터셋 위에 쌓습니다. 이는 개별 분포와 결합된 총합을 모두 보여줍니다.

np.random.seed(42)
freshmen = np.random.normal(loc=68, scale=8, size=500)
sophomores = np.random.normal(loc=72, scale=7, size=400)
juniors = np.random.normal(loc=75, scale=6, size=300)
 
plt.hist([freshmen, sophomores, juniors], bins=25, stacked=True,
         color=['#4C72B0', '#55A868', '#C44E52'], edgecolor='black',
         label=['Freshmen', 'Sophomores', 'Juniors'])
plt.legend()
plt.title('Stacked Histogram: Exam Scores by Class Year')
plt.xlabel('Score')
plt.ylabel('Frequency')
plt.show()

누적 히스토그램은 하위 그룹이 전체 분포에 어떻게 기여하는지 보여주고 싶을 때 잘 작동합니다. 그러나 3~4개 이상의 그룹에서는 읽기 어려워집니다.

누적 히스토그램

cumulative=True를 설정하여 값이 왼쪽에서 오른쪽으로 어떻게 누적되는지 보여줍니다. 마지막 막대는 총 카운트(또는 density=True인 경우 1.0)에 도달합니다.

fig, axes = plt.subplots(1, 2, figsize=(12, 4))
 
axes[0].hist(data, bins=30, cumulative=True, edgecolor='black', color='#DD8452')
axes[0].set_title('Cumulative Histogram (Count)')
axes[0].set_ylabel('Cumulative Count')
 
axes[1].hist(data, bins=30, cumulative=True, density=True, edgecolor='black', color='#8172B3')
axes[1].set_title('Cumulative Histogram (Density)')
axes[1].set_ylabel('Cumulative Probability')
 
plt.tight_layout()
plt.show()

누적 히스토그램은 "값의 몇 퍼센트가 60 미만인가?"와 같은 질문에 y축에서 직접 읽어 답하는 데 유용합니다.

수평 히스토그램

orientation='horizontal'을 설정하여 축을 뒤집습니다. 이는 값 레이블이 긴 경우나 히스토그램을 다른 수직 차트 옆에 배치하고 싶을 때 유용합니다.

plt.hist(data, bins=30, orientation='horizontal', color='#64B5CD', edgecolor='black')
plt.title('Horizontal Histogram')
plt.xlabel('Frequency')
plt.ylabel('Value')
plt.show()

plt.hist() 반환 값

plt.hist()는 히스토그램 데이터에 프로그래밍 방식으로 접근할 수 있는 세 가지 값을 반환합니다:

n, bin_edges, patches = plt.hist(data, bins=20, edgecolor='black', color='#4C72B0')
plt.show()
 
print(f"Bin counts (n): shape = {n.shape}, first 5 = {n[:5]}")
print(f"Bin edges: shape = {bin_edges.shape}, first 5 = {bin_edges[:5]}")
print(f"Patches: {len(patches)} Rectangle objects")
반환 값타입설명
nndarray각 빈의 카운트(또는 밀도)
bin_edgesndarray각 빈의 가장자리 값 (길이 = len(n) + 1)
patchesRectangle 리스트각 막대의 matplotlib 패치 객체

patches를 사용하여 높이나 위치에 따라 개별 막대에 색을 입힐 수 있습니다:

n, bin_edges, patches = plt.hist(data, bins=30, edgecolor='black')
 
# Color bars based on height
for count, patch in zip(n, patches):
    if count > 50:
        patch.set_facecolor('#C44E52')
    else:
        patch.set_facecolor('#4C72B0')
 
plt.title('Conditional Bar Coloring')
plt.show()

plt.hist() 일반 매개변수 참조

매개변수타입설명기본값
xarray-like입력 데이터필수
binsint, 시퀀스 또는 str빈 수, 빈 가장자리 또는 알고리즘 이름10
rangetuple빈의 하한 및 상한 범위(x.min(), x.max())
densitybool면적이 1이 되도록 정규화False
weightsarray-like각 데이터 포인트의 가중치None
cumulativebool누적 히스토그램 계산False
histtypestr'bar', 'barstacked', 'step', 'stepfilled''bar'
orientationstr'vertical' 또는 'horizontal''vertical'
colorcolor 또는 리스트막대 색상None
edgecolorcolor막대 테두리 색상None
alphafloat투명도 (0~1)None
labelstr범례 레이블None
stackedbool여러 데이터셋 쌓기False
logbool로그 스케일 y축False
rwidthfloat막대의 상대적 너비 (0~1)None
bottomarray-like 또는 스칼라각 막대의 기준선0

plt.hist() vs sns.histplot(): 언제 무엇을 사용할까

matplotlib와 함께 seaborn을 사용한다면, 어떤 히스토그램 함수를 사용해야 할지 궁금할 수 있습니다. 직접 비교는 다음과 같습니다:

기능plt.hist()sns.histplot()
라이브러리matplotlibseaborn
입력 타입Array, 리스트, SeriesArray, Series, DataFrame 열
KDE 오버레이수동 (scipy 필요)내장 (kde=True)
기본 스타일최소한출판 품질
여러 그룹배열 리스트 전달hue 매개변수
통계 옵션카운트, 밀도카운트, 밀도, 빈도, 확률, 퍼센트
빈 알고리즘sturges, scott, fd, sqrt, autoauto, fd, doane, scott, stone, rice, sturges, sqrt
로그 스케일log=Truelog_scale=True
범주형 축미지원hue를 통해 지원
성능 (대용량 데이터)더 빠름약간 느림
사용자 정의 깊이전체 matplotlib APIseaborn + matplotlib API

plt.hist()를 사용하는 경우: 모든 시각적 요소를 완전히 제어해야 할 때, 서브플롯으로 작업할 때, 또는 seaborn을 사용할 수 없을 때. sns.histplot()를 사용하는 경우: KDE 오버레이, 더 깔끔한 기본 스타일이 필요하거나 최소한의 코드로 범주 변수별로 데이터를 분할해야 할 때.

PyGWalker로 인터랙티브 히스토그램 만들기

정적 히스토그램은 보고서와 스크립트에 적합하지만, 탐색적 데이터 분석 중에는 빈을 변경하고, 하위 집합을 필터링하고, 차트 유형 간에 빠르게 전환해야 하는 경우가 많습니다. PyGWalker (opens in a new tab)는 pandas 또는 polars DataFrame을 Jupyter Notebook 내에서 직접 인터랙티브한 드래그 앤 드롭 시각화 인터페이스로 변환하는 오픈소스 Python 라이브러리입니다 -- 프론트엔드 코드가 필요 없습니다.

pip install pygwalker
import pandas as pd
import pygwalker as pyg
 
# Load your dataset into a DataFrame
df = pd.DataFrame({
    'score': np.random.normal(70, 12, 2000),
    'group': np.random.choice(['A', 'B', 'C'], 2000)
})
 
# Launch the interactive UI
walker = pyg.walk(df)

인터페이스가 열리면 score를 x축으로 드래그하면 PyGWalker가 자동으로 히스토그램을 생성합니다. 빈 크기를 조정하고, 색상 인코딩을 사용하여 group별로 분할하고, 밀도 모드로 전환하고, 결과 차트를 내보낼 수 있습니다 -- 모두 추가 코드를 작성하지 않고도 가능합니다. 이것은 보고서를 위한 최종 matplotlib 코드를 작성하기 전에 여러 변수를 빠르게 탐색해야 할 때 특히 유용합니다.

자주 묻는 질문

matplotlib 히스토그램에 적합한 빈 수를 어떻게 선택하나요?

bins='auto'로 시작하세요. 이것은 Sturges와 Freedman-Diaconis 방법의 최댓값을 사용합니다. 이상값이 있는 데이터에는 bins='fd'를 사용하세요. 작은 데이터셋(200포인트 미만)에는 bins='sturges'가 잘 작동합니다. 정수를 전달하고 눈으로 조정할 수도 있습니다: 분포가 지나치게 매끄러워 보이면 수를 늘리고, 막대가 노이즈가 많아 보이면 줄이세요.

plt.hist()에서 density=True와 cumulative=True의 차이점은 무엇인가요?

density=True는 모든 막대 아래의 총 면적이 1이 되도록 히스토그램을 정규화하여, y축을 확률 밀도로 변환합니다. cumulative=True는 각 막대가 이전의 모든 막대 합계에 자신을 더한 것을 나타내게 합니다. 두 가지를 결합할 수 있습니다: density=True, cumulative=True는 마지막 막대가 1.0에 도달하는 누적 분포 함수를 생성합니다.

matplotlib에서 두 개의 히스토그램을 어떻게 오버레이하나요?

같은 bins 값으로 plt.hist()를 두 번 호출하고 alpha를 1 미만의 값(예: 0.5 또는 0.6)으로 설정하여 두 분포가 모두 보이게 합니다. 각 호출에 label을 추가하고 plt.legend()로 마무리합니다. 대안으로 histtype='step'을 사용하면 윤곽만 그리므로 투명도가 전혀 필요하지 않습니다.

plt.hist()는 pandas Series와 DataFrame 열을 직접 처리할 수 있나요?

네. plt.hist()는 pandas Series를 포함한 모든 array-like 입력을 받습니다. df['column_name']을 직접 전달할 수 있습니다. pandas의 내장 메서드를 사용하여 DataFrame에서 플롯하려면 df['column_name'].plot.hist(bins=30)을 사용하세요. 이것은 내부적으로 matplotlib를 사용합니다.

matplotlib 히스토그램을 이미지 파일로 어떻게 저장하나요?

plt.hist()를 호출한 후, plt.show() 전에 plt.savefig('histogram.png', dpi=150, bbox_inches='tight')를 사용합니다. bbox_inches='tight' 매개변수는 레이블이 잘리는 것을 방지합니다. 지원되는 형식에는 PNG, PDF, SVG, EPS가 있습니다.

📚