python
파이썬에서 히스토그램을 쉽게 그리기: 초보자를 위한 가이드

파이썬에서 히스토그램을 쉽게 그리기: 초보자를 위한 가이드

MoeNagy Dev

히스토그램이란?

히스토그램은 데이터 집합의 분포를 그래픽으로 나타낸 것입니다. 데이터 분석 및 시각화에서 핵심적인 도구로 사용되며, 데이터 집합의 기본 패턴과 특성을 명확하고 직관적인 방식으로 이해하는 데 도움이 됩니다.

히스토그램은 데이터 집합의 값 범위를 일련의 구간(또는 간격)으로 나눈 다음, 각 구간에 속하는 데이터 포인트의 개수를 계산하여 생성됩니다. 이렇게 생성된 플롯은 각 구간 내의 데이터 포인트의 빈도수 또는 개수를 표시하여 데이터 분포를 시각적으로 나타냅니다.

히스토그램은 데이터 집합의 모양, 중심 경향 및 분포의 퍼짐 정도 파악에 특히 유용합니다. 이를 통해 다중 피크(다중 모양 분포를 나타냄), 비대칭(분포의 비대칭성), 이상치(주 분포 외에 위치하는 데이터 포인트) 등의 패턴을 찾는 데 도움이 됩니다.

데이터 준비

파이썬에서 히스토그램을 생성하려면 필요한 라이브러리를 가져오고 작업할 샘플 데이터를 생성해야 합니다.

import numpy as np
import matplotlib.pyplot as plt
 
# 샘플 데이터 생성
data = np.random.normal(0, 1, 1000)

이 예시에서는 numpy.random.normal() 함수를 사용하여 표준 정규 분포(평균 = 0, 표준 편차 = 1)에서 1,000개의 데이터 포인트를 생성합니다. 이를 자신의 데이터 집합으로 바꾸거나 다른 분포를 사용하여 히스토그램 시각화를 탐색할 수 있습니다.

기본적인 히스토그램 그리기

파이썬에서 히스토그램을 생성하는 가장 기본적인 방법은 Matplotlib 라이브러리의 plt.hist() 함수를 사용하는 것입니다.

# 히스토그램 생성
plt.hist(data, bins=30, color='blue', alpha=0.5)
 
# 라벨 및 제목 추가
plt.xlabel('값')
plt.ylabel('빈도수')
plt.title('샘플 데이터의 히스토그램')
 
# 플롯 출력
plt.show()

이 예시에서는 30개의 구간(bins)을 사용하여 히스토그램을 생성하며, 파란색으로 표시하고 투명도(alpha)를 0.5로 설정합니다. 구간의 수, 구간의 폭, 색상 및 투명도를 조정하여 히스토그램을 사용자 정의할 수 있습니다.

히스토그램 사용자 정의

구간의 수 설정

히스토그램의 구간 수는 플롯의 모양과 해석에 중요한 매개변수입니다. plt.hist() 함수의 bins 매개변수를 사용하여 구간 수를 조정할 수 있습니다.

# 구간 수가 10인 히스토그램
plt.hist(data, bins=10, color='green', alpha=0.7)
plt.show()
 
# 구간 수가 50인 히스토그램
plt.hist(data, bins=50, color='red', alpha=0.7)
plt.show()

구간의 수를 늘리면 데이터 분포에 대한 더 많은 세부 정보를 제공할 수 있지만, 노이즈가 많거나 "칙칙한" 외관을 가져올 수도 있습니다. 구간의 수를 줄이면 히스토그램이 부드럽게 되지만, 미세한 세부 사항을 감출 수도 있습니다.

구간 폭 조정

구간의 수뿐만 아니라 구간의 폭도 조정하여 히스토그램에서 표시되는 세부 사항의 수준을 조절할 수 있습니다.

# 폭이 0.2인 히스토그램
plt.hist(data, bins=np.arange(-3, 3, 0.2), color='orange', alpha=0.7)
plt.show()
 
# 폭이 0.5인 히스토그램
plt.hist(data, bins=np.arange(-3, 3, 0.5), color='purple', alpha=0.7)
plt.show()

이 예시에서는 np.arange() 함수를 사용하여 구간의 경계를 생성하며, 시작, 종료 및 간격 값을 지정합니다.

히스토그램 색상과 투명도 변경

막대의 색상과 투명도(alpha)를 조정하여 히스토그램의 외관을 더욱 사용자 정의할 수 있습니다.

# 다른 색상과 투명도를 가진 히스토그램
plt.hist(data, bins=30, color='red', alpha=0.3)
plt.show()

다양한 색상과 투명도 설정을 실험해보면 데이터 분포를 시각적으로 표현하는 견고하고 매력적인 히스토그램을 만들 수 있습니다.

고급 히스토그램 사용자 정의

기본적인 히스토그램 플로팅 이외에도, 시각화를 더욱 정보성 있고 시각적으로 매력적으로 만들기 위해 추가적인 사용자 정의를 수행할 수 있습니다.

라벨 및 제목 추가

명확한 라벨과 설명적인 제목을 추가하면 독자가 히스토그램의 문맥과 목적을 이해하는 데 도움이 됩니다.

# 라벨 및 제목 추가
plt.hist(data, bins=30, color='blue', alpha=0.5)
plt.xlabel('값')
plt.ylabel('빈도수')
plt.title('샘플 데이터의 히스토그램')
plt.show()

축 범위 조정

데이터의 범위와 분포에 따라 x축과 y축의 스케일을 조정하여 데이터에 더욱 잘 맞도록 할 수 있습니다.

# x축과 y축 스케일 조정
plt.hist(data, bins=30, color='blue', alpha=0.5)
plt.xlim(-3, 3)
plt.ylim(0, 150)
plt.xlabel('값')
plt.ylabel('빈도수')
plt.title('샘플 데이터의 히스토그램')
plt.show()

이 예시에서는 x축 범위를 -3에서 3으로, y축 범위를 0에서 150으로 설정하여 데이터 분포에 더 잘 맞게 조정하였습니다.

그리드 라인 표시

그리드 라인을 추가하면 독자가 히스토그램을 더 잘 해석하고 특정 데이터 포인트 또는 빈도를 파악할 수 있습니다.

# 그리드 라인 추가
plt.hist(data, bins=30, color='blue', alpha=0.5)
plt.grid(True)
plt.xlabel('값')
plt.ylabel('빈도수')
plt.title('샘플 데이터의 히스토그램')
plt.show()

히스토그램을 이미지 파일로 저장

히스토그램이 마음에 들 경우 보고서, 프레젠테이션 또는 기타 응용 프로그램에서 사용하기 위해 이미지 파일로 저장할 수 있습니다.

# 히스토그램을 이미지 파일로 저장
plt.hist(data, bins=30, color='blue', alpha=0.5)
plt.xlabel('값')
plt.ylabel('빈도수')
plt.title('샘플 데이터의 히스토그램')
plt.savefig('histogram.png', dpi=300)

이 예시에서는 해상도가 300 도트 인치 (dpi) 인 PNG 파일로 히스토그램을 저장합니다.

히스토그램 정규화

히스토그램은 절대 빈도수 대신 데이터의 상대 빈도수 또는 확률 밀도를 나타내도록 정규화 될 수도 있습니다.

# 정규화된 히스토그램 생성
plt.hist(data, bins=30, density=True, color='blue', alpha=0.5)
plt.xlabel('값')
plt.ylabel('확률 밀도')
plt.title('샘플 데이터의 정규화된 히스토그램')
plt.show()

plt.hist() 함수의 density=True 매개변수를 설정하여 히스토그램의 y축이 빈도 대신 확률 밀도를 나타내도록 설정할 수 있습니다. 이는 서로 다른 스케일을 가진 데이터 세트의 히스토그램을 비교하거나 히스토그램에 확률 분포 곡선을 오버레이하는 경우에 유용할 수 있습니다.

동일한 그림에 여러 히스토그램 그리기

서로 다른 데이터 세트 또는 변수의 분포를 비교하기 위해 동일한 그림에 여러 히스토그램을 그릴 수 있습니다.

# 두 개의 샘플 데이터 세트 생성
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(1, 0.5, 1000)
 
# 두 개의 서브플롯이 있는 피규어 생성
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
 
# 첫 번째 히스토그램 그리기
ax1.hist(data1, bins=30, color='blue', alpha=0.5)
ax1.set_xlabel('값')
ax1.set_ylabel('빈도수')
ax1.set_title('데이터 세트 1의 히스토그램')
 
# 두 번째 히스토그램 그리기
ax2.hist(data2, bins=30, color='red', alpha=0.5)
ax2.set_xlabel('값')
ax2.set_ylabel('빈도수')
ax2.set_title('데이터 세트 2의 히스토그램')
 
# 서브플롯 간의 공간 조정
plt.subplots_adjust(wspace=0.4)
plt.show()

이 예시에서는 서로 다른 데이터셋에 대한 히스토그램이 있는 두 개의 서브플롯이 있는 그림을 생성합니다. plt.subplots_adjust() 함수를 사용하여 서브플롯 간의 간격을 조정합니다.

범주형 데이터와 히스토그램

히스토그램은 범주형 데이터의 분포를 시각화하는 데에도 사용할 수 있으나 해석은 약간 다릅니다.

# 샘플 범주형 데이터 생성
categories = ['A', 'B', 'C', 'D', 'E']
data = np.random.choice(categories, 1000)
 
# 범주형 데이터에 대한 히스토그램 생성
plt.hist(data, bins=len(categories), edgecolor='black')
plt.xticks(range(len(categories)), categories)
plt.xlabel('범주')
plt.ylabel('빈도수')
plt.title('범주형 데이터의 히스토그램')
plt.show()

이 예시에서는 1000개의 무작위 범주형 데이터 포인트를 생성하고 분포를 시각화하기 위해 히스토그램을 생성합니다. bins 매개변수는 고유한 범주의 수로 설정되고, plt.xticks()를 사용하여 x축에 범주 이름을 레이블로 표시합니다.

연속적인 데이터와 히스토그램

연속적인 데이터를 다룰 때, 빈의 수 선택은 시각화의 외형과 해석에 중요한 영향을 주므로 주의해야 합니다.

# 샘플 연속적인 데이터 생성
data = np.random.normal(0, 1, 1000)
 
# 다른 빈 크기의 히스토그램 생성
plt.figure(figsize=(12, 4))
 
plt.subplot(1, 2, 1)
plt.hist(data, bins=10, color='blue', alpha=0.5)
plt.xlabel('값')
plt.ylabel('빈도수')
plt.title('10개 빈으로 생성된 히스토그램')
 
plt.subplot(1, 2, 2)
plt.hist(data, bins=50, color='red', alpha=0.5)
plt.xlabel('값')
plt.ylabel('빈도수')
plt.title('50개 빈으로 생성된 히스토그램')
 
plt.subplots_adjust(wspace=0.4)
plt.show()

이 예시에서는 연속적인 데이터의 시각화에 빈 크기의 영향을 보여주기 위해 다른 빈 크기 (10개와 50개)로 옆에 두 개의 히스토그램을 생성합니다.

함수

함수는 특정 작업을 수행하는 재사용 가능한 코드 블록입니다. 논리를 캡슐화하여 코드를 더 모듈화하고 유지 관리하기 쉽게 만듭니다.

다음은 직사각형의 면적을 계산하는 함수 예시입니다.

def calculate_area(length, width):
    area = length * width
    return area
 
# 함수 호출
rect_area = calculate_area(5, 10)
print(rect_area)  # 출력: 50

이 예시에서 calculate_area() 함수는 lengthwidth 두 개의 매개변수를 받고 면적을 계산하여 반환합니다. 그런 다음 함수를 호출하고 결과를 rect_area 변수에 저장합니다.

함수는 기본 매개변수 값을 가지고 있거나 가변 개수의 인자를 받을 수도 있습니다.

def print_greeting(name, message="Hello"):
    print(f"{message}, {name}!")
 
print_greeting("Alice")  # 출력: Hello, Alice!
print_greeting("Bob", "Hi")  # 출력: Hi, Bob!
 
def calculate_sum(*numbers):
    total = 0
    for num in numbers:
        total += num
    return total
 
print(calculate_sum(1, 2, 3))  # 출력: 6
print(calculate_sum(4, 5, 6, 7, 8))  # 출력: 30

첫 번째 예시에서 print_greeting() 함수는 message 매개변수에 기본값을 가지고 있으며, 값이 제공되지 않으면 해당 값을 사용합니다. 두 번째 예시에서 calculate_sum() 함수는 임의의 개수의 인자를 받을 수 있으며, 이들은 numbers라는 튜플로 수집됩니다.

모듈과 패키지

Python의 표준 라이브러리는 프로그램에서 사용할 수 있는 다양한 내장 모듈을 제공합니다. 또한 코드를 구성하기 위해 자체 모듈과 패키지를 만들 수도 있습니다.

다음은 math 모듈을 사용하는 예시입니다.

import math
 
radius = 5
circle_area = math.pi * radius ** 2
print(circle_area)  # 출력: 78.53981633974483

이 예시에서는 math 모듈을 가져오고 pi 상수와 ** 연산자를 사용하여 원의 면적을 계산합니다.

특정 함수나 속성만 모듈에서 가져올 수도 있습니다.

from math import pi, sqrt
 
radius = 5
circle_area = pi * radius ** 2
diagonal = sqrt(radius ** 2 + radius ** 2)
print(circle_area)  # 출력: 78.53981633974483
print(diagonal)  # 출력: 7.0710678118654755

여기에서는 math 모듈에서 pisqrt 함수를 직접 가져오기 때문에 math. 접두사 없이 사용할 수 있습니다. 자신의 모듈을 만들려면, 단순히 확장자가 .py인 파일에 Python 코드를 저장하면 됩니다. 예를 들어, 다음 내용과 같은 my_module.py 파일을 만들 수 있습니다:

def greet(name):
    print(f"안녕, {name}!")
 
def calculate_area(length, width):
    return length * width

그런 다음 모듈에서 함수를 가져와 사용할 수 있습니다:

import my_module
 
my_module.greet("Alice")  # 출력: 안녕, Alice!
area = my_module.calculate_area(5, 10)
print(area)  # 출력: 50

패키지는 모듈을 계층 구조로 구성하는 방법입니다. 패키지를 만들려면, __init__.py 파일이 있는 디렉토리를 만들어야 합니다. 이 파일은 비어 있을 수 있지만, Python이 해당 디렉토리를 패키지로 인식하기 위해서는 필요합니다.

예를 들어, my_package 디렉토리를 만들고 그 안에 __init__.py 파일을 추가한 다음, 디렉토리 안에 my_module.py 파일을 추가할 수 있습니다:

my_package/
    __init__.py
    my_module.py

그런 다음 패키지 내부의 모듈에서 함수를 가져와 사용할 수 있습니다:

import my_package.my_module
 
my_package.my_module.greet("Alice")  # 출력: 안녕, Alice!
area = my_package.my_module.calculate_area(5, 10)
print(area)  # 출력: 50

또는 from 문을 사용하여 모듈에서 함수를 직접 가져올 수도 있습니다:

from my_package.my_module import greet, calculate_area
 
greet("Alice")  # 출력: 안녕, Alice!
area = calculate_area(5, 10)
print(area)  # 출력: 50

파일 입출력

Python은 파일 읽기와 쓰기를 위한 내장 함수를 제공합니다. 가장 흔히 사용되는 함수는 open(), read(), write(), close()입니다.

다음은 파일 내용을 읽는 방법의 예입니다:

# 읽기 모드로 파일 열기
with open("example.txt", "r") as file:
    contents = file.read()
    print(contents)

이 예제에서는 open() 함수를 사용하여 example.txt 파일을 읽기 모드 ("r")로 엽니다. with 문은 예외가 발생해도 코드 블록이 실행된 후에 파일이 제대로 닫히도록 보장합니다.

또한 파일을 한 줄씩 읽을 수도 있습니다:

with open("example.txt", "r") as file:
    for line in file:
        print(line.strip())

이렇게 하면 파일의 각 줄을 출력하며, strip() 메서드를 사용하여 앞뒤의 공백을 제거할 수 있습니다.

파일에 쓰기 위해서는 write() 함수를 사용할 수 있습니다:

with open("output.txt", "w") as file:
    file.write("안녕, 세상아!\n")
    file.write("이것은 새로운 줄입니다.\n")

이 예제에서는 "w"로 쓰기 모드로 output.txt 파일을 열고, write() 함수를 사용하여 파일에 두 줄의 텍스트를 추가합니다.

기존 파일에 데이터를 추가하기 위해 append 모드로 열 수도 있습니다 ("a"):

with open("output.txt", "a") as file:
    file.write("이것은 추가적인 줄입니다.\n")

이렇게 하면 output.txt 파일의 끝에 새 줄이 추가됩니다.

예외 처리

Python의 예외 처리 메커니즘을 사용하면 코드 내에서 오류와 예상치 못한 상황을 처리할 수 있습니다. try-except 블록은 예외를 잡고 처리하는 데 사용됩니다.

다음은 ZeroDivisionError를 처리하는 방법의 예입니다:

try:
    result = 10 / 0
except ZeroDivisionError:
    print("오류: 0으로 나눌 수 없음")

이 예제에서 try 블록은 10을 0으로 나누려고 시도하며, 이는 ZeroDivisionError를 발생시킵니다. except 블록은 예외를 잡아 오류 메시지를 출력합니다.

하나의 except 블록에서 여러 예외를 처리할 수도 있습니다:

try:
    num = int(input("숫자를 입력하세요: "))
    result = 10 / num
except (ValueError, ZeroDivisionError):
    print("오류: 잘못된 입력 또는 0으로 나눌 수 없음")

이 예제에서 try 블록은 사용자의 입력을 정수로 변환하고 그 결과로 10을 나누려고 시도합니다. 사용자가 숫자가 아닌 값을 입력하면 ValueError가 발생하고, 0을 입력하면 ZeroDivisionError가 발생합니다. except 블록은 이러한 예외를 모두 잡아 오류 메시지를 출력합니다.

try-except 블록에 elsefinally 절을 사용할 수도 있습니다:

try:
    num = int(input("숫자를 입력하세요: "))
    result = 10 / num
except ValueError:
    print("오류: 잘못된 입력")
except ZeroDivisionError:
    print("오류: 0으로 나눌 수 없음")
else:
    print(f"결과: {result}")
finally:
    print("'try-except' 블록이 완료되었습니다.")

이 예제에서는 try 블록에서 예외가 발생하지 않으면 else 절이 실행되고, finally 절은 예외가 발생했든 안 했든 항상 실행됩니다.

결론

이 튜토리얼에서는 함수, 모듈 및 패키지, 파일 입출력, 예외 처리를 포함한 다양한 Python 개념을 배웠습니다. 이는 모든 Python 프로그래머에게 필수적인 기술이며, 더 체계적이고 유지보수 가능하며 견고한 코드를 작성하는 데 도움이 될 것입니다.

기억하세요, Python 기술을 향상시키는 가장 좋은 방법은 연습입니다. 배운 개념을 자신의 프로젝트에 적용해 보고, Python 라이브러리와 도구의 방대한 생태계를 탐험하는 데 겁먹지 마세요. Python 프로그래밍 여정에서 행운을 빕니다!

MoeNagy Dev