ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 그래프와 시각화
    Python 2023. 11. 28. 17:19
    맷플롯립 API 간단하게 살펴보기

     

    주피터 노트북 환경에서 %matplotlib notebook 실행한 다음(IPYTHON인 경우 %matplotlib) 간단한 그래프 그리기

    In [3]: import matplotlib.pyplot as plt
    
    In [4]: %matplotlib
    Installed qt5 event loop hook.
    Shell is already running a gui event loop for qt5. Call with no arguments to disable the current loop.
    Using matplotlib backend: QtAgg
    
    In [5]: data = np.arange(10)
    
    In [6]: data
    Out[6]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    
    In [7]: plt.plot(data)
    Out[7]: [<matplotlib.lines.Line2D at 0x1ae351c8d50>]

    %matplotlib을 입력하지 않아 그래프를 보여주지 않는 경우 plt.show() 함수를 부르면 됨

     

    피겨와 서브플롯

    맷플롯립에서 그래프는 피겨(figure) 객체 내에 존재함

    새로운 피겨는 plt.figure로 생성

    In [8]: fig = plt.figure()

    plt.figure에 다양한 옵션이 있는데 그중 figsize로 파일로 저장할 피겨의 크기와 비율 지정 가능

    빈 피겨 객체로는 그래프를 만들 수 없으므로 add_subplot을 사용해 최소 하나 이상의 subplots를 생성해야 함

    In [9]: ax1 = fig.add_subplot(2, 2, 1)

    위 코드의 fig 객체는 2x2 크기이고 네 개(2x2)의 서브플롯 중 첫 번째를 선택하겠다는 의미, 서브플롯은 1부터 숫자가 매겨짐

     

    In [10]: ax2 = fig.add_subplot(2, 2, 2)
    
    In [11]: ax3 = fig.add_subplot(2, 2, 3)

     

    In [12]: ax3.plot(np.random.standard_normal(50).cumsum(), color='black',
        ...:          linestyle='dashed')
    Out[12]: [<matplotlib.lines.Line2D at 0x1ae3dc11250>]

     

    # 줄 끝에 세미콜론을 넣으면 <matplotlib.lines.Line2D at...> 출력 생략
    # alpha=0.3 스타일 옵션은 겹쳐서 그려진 그래프의 투명도 설정
    In [13]: ax1.hist(np.random.standard_normal(100), bins=20, color='black', alpha=0.3);
    
    In [14]: ax2.scatter(np.arange(30), np.arange(30) + 3 * np.random.standard_normal(30));

    fig.add_subplot에서 반환되는 객체는 AxesSubplot 객체이며 각 인스턴스 메서드를 호출해 다른 빈 서브플롯에 직접 그래프를 그릴 수 있음

    In [15]: figs, axes = plt.subplots(2, 3)
    
    In [16]: axes
    Out[16]:
    array([[<Axes: >, <Axes: >, <Axes: >],
           [<Axes: >, <Axes: >, <Axes: >]], dtype=object)

    axes 배열은 2차원 배열처럼 인덱싱 가능 ex) axes[0, 1]은 가장 상단 행의 중간에 있는 서브플롯 참조

    서브플롯이 동일한 x축이나 y축을 가져야 한다면 각각 sharex와 sharey를 사용해 지정

        > 지정하지 않을 경우 맷플롯립은 각 그래프의 범위를 독립적으로 조정

    인수 설명
    nrows 서브플롯의 행 수
    ncols 서브플롯의 열 수
    sharex 모든 서브플롯이 동일한 x축 눈금을 사용하도록(xlim 값을 조절하면 모든 서브플롯에 적용됨)
    sharey 모든 서브플롯이 동일한 y축 눈금을 사용하도록(ylim 값을 조절하면 모든 서브플롯에 적용됨)
    subplot_kw add_subplot을 사용해 각 서브플롯을 생성할 때 사용할 키워드를 담고 있는 딕셔너리
    **fig_kw 피겨를 생성할 때 사용할 추가적인 키워드 인수
    ex) plt.subplots(2, 2, figsize=(8, 6))와 같음

     

    서브플롯 간 간격 조절

    맷플롯립은 서브플롯 간의 적당한 간격(spacing)과 여백(padding)을 기본적으로 추가

    전체 그래프의 높이와 너비에 따라 상대적으로 결정됨

        > 프로그램을 이용하거나 GUI 윈도우 크기를 직접 조정하면 크기가 자동으로 조절됨

    서브플롯 간의 간격은 피겨 객체의 subplot_adjust 메서드로 쉽게 조정 가능

    subplots_adjust(left=None, bottom=None, right=None, top=None,
                    wspace=None, hspace=None)

     

    wspace(가로)와 hspace(세로)는 서브플롯 간의 간격을 위해 각 피겨의 너비와 높이에 대한 비율을 조절 

    # 서브플롯 간의 간격을 주지 않은 그래프 생성 코드
    In [20]: figs, axes = plt.subplots(2, 2, sharex=True, sharey=True)
    
    In [21]: for i in range(2):
        ...:     for j in range(2):
        ...:         axes[i, j].hist(np.random.standard_normal(500), bins=50, color='black', alpha=0.5)
        ...:
    
    In [22]: fig.subplots_adjust(wspace=0, hspace=0)
    
    In [23]: plt.show()

    In [8]: fig, axes = plt.subplots(2, 2, sharex=True, sharey=True)
    
    In [9]: for i in range(2):
       ...:     for j in range(2):
       ...:         axes[i, j].hist(np.random.standard_normal(500), bins=50,
       ...:                         color='red', alpha=0.1)
       ...:
    
    In [10]: fig.subplots_adjust(wspace=10, hspace=10)
    
    In [11]: plt.show()

     

     

    색상, 마커, 선 스타일

    색상에는 색상 문자열(green) 제공, 헥스 코드(hex code)(#CECECE)를 직접 지정하면 색상표에 있는 모든 색상 사용 가능

    선 그래프는 특정 지점의 실제 데이터를 강조하기 위해 마커(marker)를 추가하기도 함, 스타일 문자열로 지정 가능

    In [26]: fig = plt.figure()
    
    In [27]: ax = fig.add_subplot()
    
    In [28]: ax.plot(np.random.standard_normal(30).cumsum(), color='black',
        ...:         linestyle='dashed', marker='o')
    Out[28]: [<matplotlib.lines.Line2D at 0x1e273edde50>]
    
    In [29]: plt.show()

     

    선 그래프를 보면 일정한 간격으로 연속된 지점이 연결됨

        > drawstyle 옵션으로 바꿀 수 있음

    In [30]: fig = plt.figure()
    
    In [31]: ax = fig.add_subplot()
    
    In [32]: data = np.random.standard_normal(30).cumsum()
    
    In [33]: ax.plot(data, color='black', linestyle='dashed', label='Default')
    Out[33]: [<matplotlib.lines.Line2D at 0x1e273e95650>]
    
    In [34]: ax.plot(data, color='green', linestyle='dashed',
        ...:         drawstyle='steps-post', label='steps-post')
    Out[34]: [<matplotlib.lines.Line2D at 0x1e273e67090>]
    
    # ax.legend를 사용해 각 선을 구별하는 범례를 포함시켜 그래프 작성
    In [35]: ax.legend()
    Out[35]: <matplotlib.legend.Legend at 0x1e277a288d0>

     

    ipython 여러 줄 입력

    In [6]: # 여러 줄 입력
    
    In [7]: # ctrl + o 누르면
       ...: # 새로운 줄이 만들어짐

     

    눈금, 레이블, 범례

    그래프를 꾸미는 방법은 대부분 맷플롯립의 ax 객체 메서드로 접근 가능

    xlim, xticks, xticklabels와 같은 메서드를 이용해 그래프의 범위를 지정하거나 눈금 위치, 눈금 레이블 설정

        · 아무런 인수 없이 호출하면 현재 설정된 매개변숫값을 반환 ex) ax.xlim 메서드는 현재 x축의 범위 반환

        · 매개변수를 전달하면 매개변숫값 설정 ex) ax.xlim([0, 10])을 전달하면 x축의 범위가 0부터 10까지로 설정됨

    모든 메서드는 현재 활성화되거나 가장 최근에 생성된 AxesSubplot 객체에 대해 작동

    제목, 축 레이블, 눈금, 눈금 레이블 설정
    # fig, axes = plt.subplots()
    fig, ax = plt.subplots()
    ax.plot( np.random.standard_normal(1000).cumsum() );

     

    x축의 눈금을 변경하는 가장 쉬운 방법은 set_xticks와 set_sticklabels 메서드를 사용하는 것

    set_xticks 메서드는 전체 데이터 범위에 따라 눈금을 어디에 배치할지 지정, 기본적으로 이 위치에 눈금 레이블이 들어감

      > 다른 눈금 레이블을 지정하고 싶다면 set_xticklabels 사용

    fig, ax = plt.subplots()
    ax.plot(np.random.standard_normal(1000).cumsum())
    
    ticks = ax.set_xticks([0, 250, 500, 750, 1000])
    # rotation=30은 x축 눈금 레이블을 30도 회전
    labels = ax.set_xticklabels(['one', 'two', 'three', 'four', 'five'],
                              rotation=30, fontsize=8)

     

     

    # 서브플롯의 제목 지정
    ax.set_xlabel('Stages')
    ax.set_ylabel('ylabel')
    ax.set_title('My first matplotlib plot')

     

    타이틀, 축 레이블 추가하는 다른 방법

    fig, ax = plt.subplots()
    ax.plot(np.random.standard_normal(1000).cumsum())
    
    ticks = ax.set_xticks([0, 250, 500, 750, 1000])
    labels = ax.set_xticklabels(['one', 'two', 'three', 'four', 'five'],
                              rotation=30, fontsize=8)
    
    # ax.set_xlabel('Stages')
    # ax.set_title('My first matplotlib plot')
    ax.set(title='My first matplotlib plot', xlabel='Stages')

     

    범례 추가

    fig, ax = plt.subplots()
    ax.plot(np.random.randn(1000).cumsum(), color='red', label='one');
    ax.plot(np.random.randn(1000).cumsum(), color='green', linestyle='dashed',
            label='two');
    # dotted 대신 : 넣어도 됨
    ax.plot(np.random.randn(1000).cumsum(), color='blue', linestyle='dotted',
            label='three');
    # 위 label 인수를 넘기면 ax.legend() 호출했을 때 자동으로 범례 생성
    ax.legend()

    # 범례 설정
    fig, ax = plt.subplots()
    ax.plot(np.random.randn(1000).cumsum(), color='red');
    ax.plot(np.random.randn(1000).cumsum(), color='green', linestyle='dashed',
            label='_nolegend_');
    ax.plot(np.random.randn(1000).cumsum(), color='blue', linestyle='dotted',
            label='three');
    ax.legend()

     

    주석과 그림 추가

    기본 그래프에 글자나 화살표, 다른 도형으로 주석을 추가하고 싶은 경우 text, arrow, annotate 함수를 이용해 추가 가능

    text 함수는 그래프 내의 주어진 좌표(x, y)에 부가적인 스타일로 글자를 그림

    ax.text(x, y, 'Hello world!',
            family='monospace', fontsize=10)

     

    # 주석에는 글자와 화살표를 함께 사용 가능
    # 2007년 이후의 데이터로 그래프 생성, 2008-2009년 사이 있었던 금융위기 중 중요한 날짜를 주석으로 추가
    from datetime import datetime
    
    fig, ax = plt.subplots()
    
    data = pd.read_csv("spx.csv", index_col=0, parse_dates=True)
    spx = data['SPX']
    
    spx.plot(ax=ax, color='black')
    
    crisis_data = [
        (datetime(2007, 10, 11), 'Peak of bull market'),
        (datetime(2008, 3, 12), 'Bear Stearn Fails'),
        (datetime(2008, 9, 15), 'Lehman Bankruptcy')
    ]
    
    # ax.annotate 메서드를 이용해 x, y 좌표로 지정한 위치에 레이블 추가
    for date, label in crisis_data:
        ax.annotate(label, xy=(date, spx.asof(date) + 75),
                   xytext=(date, spx.asof(date) + 225),
                   arrowprops=dict(facecolor='black', headwidth=4, width=2,
                                  headlength=4),
                   horizontalalignment='left', verticalalignment='top')
    
    # 2007-2010 구간으로 확대(시작과 끝 경계 직접 지정)
    ax.set_xlim(['1/1/2007', '1/1/2011'])
    ax.set_ylim([600, 1800])
    
    ax.set_title('Important dates in the 2008-2009 financial crisis')

    spx.csv

     

    도형 그리기

    Rectangle과 Circle 같은 종류는 matplotlib.pyplot에서도 찾을 수 있지만 전체 모음은 matplotlib.patches에 있음

    그래프에 도형 추가: patch 객체를 만든 후 ax.add_patch 호출해 서브플롯 ax에 객체를 추가

    # 도형 그리기
    fig, ax = plt.subplots()
    
    rect = plt.Rectangle((0.2, 0.75), 0.4, 0.15, color='red', alpha=0.3)
    circ = plt.Circle((0.7, 0.2), 0.15, color='blue', alpha=0.3)
    pgon = plt.Polygon([[0.15, 0.15], [0.35, 0.4], [0.2, 0.6]],
                      color='green', alpha=0.5)
    
    ax.add_patch(rect)
    ax.add_patch(circ)
    ax.add_patch(pgon)

     

    다른 도형에 대해 더 자세히 알고 싶은 경우

    https://matplotlib.org/

     

    Matplotlib — Visualization with Python

    seaborn seaborn is a high level interface for drawing statistical graphics with Matplotlib. It aims to make visualization a central part of exploring and understanding complex datasets. statistical data visualization Cartopy Cartopy is a Python package des

    matplotlib.org

     

    그래프를 파일로 저장

    fig.savefig('figpath.png', dpi=400)

    .svg, .pdf 형식 저장 가능

     

    맷플롯립 설정

    # 전역으로 피겨의 크기 10x10 설정
    plt.rc('figure', figsize=(10, 10))
    
    plt.rc('font', family='monospace', weight='bold', size=8)

    더 많은 설정과 옵션 종류는 matplotlib/mpl-data 디렉터리에 있는 matplotlibrc 파일에 저장되어 있음

     

    판다스에서 시본으로 그래프 그리기

     

    판다스는 Series와 DataFrame 객체를 간단하게 시각화하는 내장 메서드를 제공

    다른 라이브러리로는 맷플롯립 기반의 고차원 통계 그래픽 라이브러리인 시본(sea born)이 있음

        > 시본은 흔히 사용하는 다양한 시각화 패턴을 쉽게 구현 가능

     

    선 그래프

    s = pd.Series(np.random.standard_normal(10).cumsum(), index=np.arange(0, 100, 10))
    s.plot()

    Series 객체의 인덱스는 맷플롯립에서 그래프를 생성할 때 x축으로 해석되는데

    인덱스를 그래프의 축으로 사용하길 원하지 않을 경우 use_index=False 옵션을 넘기면 축으로 사용하지 않음

     

    DataFrame의 plot 메서드는 하나의 서브플롯 안에 각 열별로 선 그래프를 그리고, 자동으로 범례 생성

    df = pd.DataFrame(np.random.standard_normal((10, 4)).cumsum(0),
                     columns=['A', 'B', 'C', 'D'],
                     index=np.arange(0, 100, 10))
    # 흑백 설정
    plt.style.use('grayscale')
    df.plot()

     

    막대그래프

    Series 또는 DataFrame의 인덱스는 수직 막대그래프인 경우 x(bar) 눈금, 수평 막대그래프의 경우 y(barh) 눈금으로 사용됨

    fig, axes = plt.subplots(2, 1)
    data = pd.Series(np.random.uniform(size=16), index=list('abcdefghijklmnop'))
    
    # 수직 막대그래프
    data.plot.bar(ax=axes[0], color='green', alpha=0.7)
    
    # 수평 막대그래프
    data.plot.barh(ax=axes[1], color='red', alpha=0.7)

    # 그리드 적용
    fig, axes = plt.subplots(2, 1)
    data = pd.Series(np.random.uniform(size=16),
                     index=list('abcdefghijklmnop'))
    data.plot.bar(ax=axes[0], color='green', alpha=0.7, grid=True)
    data.plot.barh(ax=axes[1], color='red', alpha=0.7, grid=True)

     

    Kernel restart - grayscale 적용 해제를 위해 커널 재실행

     

    DataFrame에서 막대그래프는 각 행의 값을 함께 묶어 하나의 그룹마다 각각의 막대를 보여줌

    df = pd.DataFrame(np.random.uniform(size=(6, 4)),
                     index=['one', 'two', 'three', 'four', 'five', 'six'],
                     columns=pd.Index(['A', 'B', 'C', 'D'], name='Genus'))
    print(df)
    df.plot.bar()

    # 누적 막대 그래프는 stacked=True 옵션을 사용해 생성
    df.plot.barh(stacked=True, alpha=0.5)

     

    레스토랑의 팁 데이터셋 예제 살펴보기

    이 데이터에서 요일별로 열린 파티 개수를 계산하고 파티 개수 대비 팁 비율을 보여주는 누적 막대그래프 그리기

    pandas.crosstab 함수를 이용하면 두 DataFrame 열에서 간단한 빈도표를 뽑을 수 있음

    tips.csv

    tips = pd.read_csv('tips.csv')
    tips.head()
    
    party_counts = pd.crosstab(tips['day'], tips['size'])
    party_counts = party_counts.reindex(index=['Thur', 'Fri', 'Sat', 'Sun'])
    
    print(party_counts)
    print()
    
    # 열 1과 6은 제외
    party_counts = party_counts.loc[:, 2:5]
    
    # 합이 1이 되도록 정규화
    party_pcts = party_counts.div(party_counts.sum(axis='columns'), axis='index')
    print(party_pcts)
    
    party_pcts.plot.bar(stacked=True)

    위 그래프를 통해 주말에 파티 규모가 커지는 경향이 있음을 파악 가능

     

    그래프를 그리기 전에 요약이 필요한 데이터에 시본 패키지를 이용하면 훨씬 간단하게 처리 가능

        · jupyter notebook에서 실행 시 conda install seaborn 명령으로 설치

        · ipython에서 실행 시 !pip install seaborn 명령으로 설치

     

    시본 패키지로 팁 데이터 다시 그리기

    import seaborn as sns
    
    tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip'])
    tips.head()
    
    sns.barplot(x='tip_pct', y='day', data=tips, orient='h')

    오차 막대가 있는 요일별 팁 비율 그래프

    막대그래프 위에 겹쳐서 그려진 검은 선은 95%의 신뢰 구간(confidence interval)을 나타냄 > 옵션 인수로 설정 가능

    # seaborn.barplot 메서드의 hue 옵션을 이용해 추가 분류에 따라 나눠 그릴 수 있음
    sns.barplot(x='tip_pct', y='day', hue='time', data=tips, orient='h')

    요일과 시간별 팁 비율

     

    'Python' 카테고리의 다른 글

    ipython 명령어  (0) 2024.01.04
    주피터 노트북 설정  (0) 2023.12.07
    데이터 준비: 조인, 병합, 변형  (0) 2023.11.27
    데이터 정제 및 준비  (0) 2023.11.21
    데이터 로딩과 저장, 파일 형식  (0) 2023.11.20
Designed by Tistory.