이번 포스팅에서는 두개 이상의 다변량 범주형 자료 시각화(visualization with multiple categorical data)의 하나로서 모자이크 그래프 (mosaic chart)를 그리는 방법을 소개하겠습니다. 




statsmodels 라이브러리의 statsmodels.graphics.mosaicplot 내 mosaic 클래스를 사용하면 매우 간단한 코드로 그릴 수 있습니다. 



import numpy as np

import pandas as pd


from statsmodels.graphics.mosaicplot import mosaic

import matplotlib.pyplot as plt

import seaborn as sns

plt.rcParams['figure.figsize'] = [12, 8]

 



예제로 사용할 데이터는 Titanic 침몰로 부터 생존/사망자 데이터셋입니다. 몇 년 전에 Kaggle에서 생존 vs. 사망 분류 모델 만들기 competition을 했었던 데이터입니다. 



# Getting Titanic dataset

url = "https://raw.github.com/mattdelhey/kaggle-titanic/master/Data/train.csv"

titanic = pd.read_csv(url)

titanic.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 11 columns):
survived    891 non-null int64
pclass      891 non-null int64
name        891 non-null object
sex         891 non-null object
age         714 non-null float64
sibsp       891 non-null int64
parch       891 non-null int64
ticket      891 non-null object
fare        891 non-null float64
cabin       204 non-null object
embarked    889 non-null object
dtypes: float64(2), int64(4), object(5)
memory usage: 76.6+ KB

 



모자이크 그래프 시각화에 사용할 3개의 범주형 변수만 남겨놓았으며, 변수 이름과 코드값을 map() 함수를 사용하여 바꾸어보았습니다. 



titanic = titanic[['survived', 'pclass', 'sex']]


# make new variables of 'survived' and 'pclass' with the different class name

titanic["SURVIVE"] = titanic.survived.map({0: "DEAD", 1: "ALIVE"})

titanic["CLASS"] = titanic.pclass.map({1: "1ST", 2: "2ND", 3: "3RD"})

titanic["GENDER"] = titanic.sex.map({'male': 'MAN', 'female': "WOMAN"})


titanic.head()

survivedpclasssexSURVIVECLASSGENDER
003maleDEAD3RDMAN
111femaleALIVE1STWOMAN
213femaleALIVE3RDWOMAN
311femaleALIVE1STWOMAN
403maleDEAD3RDMAN

 




mosaic() 함수를 사용하여 생존여부('SURVIVE')와 티켓 등급('CLASS') 간의 관계를 알아볼 수 있는 모자이크 그래프를 그려보았습니다. 'CLASS' 변수의 코드값을 titanic.sort_values() 로 먼저 정렬을 한 후에 모자이크 그림을 그렸습니다. 1등석('1ST') > 3등석('3RD) > 2등석('2ND')의 순서로 생존율이 높게 나왔군요. 



from statsmodels.graphics.mosaicplot import mosaic

 

mosaic(titanic.sort_values('CLASS'), ['SURVIVE', 'CLASS'], 

      title='Mosaic Chart of Titanic Survivor')

plt.show()




이번에는 생존 여부('SURVIVE')와 성별('GENDER')와의 관계를 알아볼 수 있는 모자이크 그래프를 그려보았습니다. '여성('WOMEN')'의 생존자 비율이 높게 나왔습니다. 



mosaic(titanic, ['SURVIVE', 'GENDER'])

plt.title('Mosaic Chart of Titanic', fontsize=20)

plt.show()




생존 여부('SURVIVE'), 티켓 등급('CLASS'), 성별('GENDER') 3개 범주형 변수를 모두 한꺼번에 사용해서 모자이크 그림을 그릴 수도 있습니다. 



mosaic(titanic.sort_values('CLASS'), ['CLASS', 'SURVIVE', 'GENDER'])

plt.title('Mosaic Chart of Titanic', fontsize=20)

plt.show()

 





조금 더 가독성을 높이기 위해서 gap argument를 사용하여 변수 내 계급 간에 간극(gap)을 좀더 벌려서 모자이크 그림을 그릴 수 있습니다. 



mosaic(titanic.sort_values('CLASS'), ['CLASS', 'SURVIVE', 'GENDER'], 

      gap=0.02)

plt.title('Survivor of Titanic', fontsize=20)

plt.show()

 



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. ;-)



Posted by R Friend R_Friend

이번 포스팅에서는 시간의 흐름에 따른 관측값의 변화, 추세를 시각화하는데 유용한 선 그래프 (Line Graph)matplotlib, seaborn, pandas 라이브러리로 그리는 방법을 차례대로 소개하겠습니다. 


선 그래프를 그리려면 X좌표와 Y좌표별 값을 순서대로 선으로 이어주면 되는데요, X좌표, Y좌표, 값의 데이터 형태는 리스트, Series, 데이터프레임 등 여러가지가 가능합니다. 이번 포스팅에서는 이중에서도 (1) 옆으로 긴 데이터프레임(Wide-form DataFrame)과, (2) 아래로 긴 데이터프레임(Long-form DataFrame)을 사용하여 선 그래프 (Line Graph) 그리는 방법을 소개하겠습니다. 



[ 선 그래프를 그리는 두 가지 형태의 DataFrame: Wide-form, Long-form DataFrame ]




먼저 난수를 사용하여 4개의 연속형 변수를 가지는 시계열(time-series) 데이터셋을 (1) Wide-form DataFrame 과 (2) Long-form DataFrame을 만들어보겠습니다. 



  (Data form 1) Wide-form DataFrame



import numpy as np

import pandas as pd


import matplotlib.pyplot as plt

import seaborn as sns

plt.rcParams['figure.figsize'] = [12, 8]

 



np.random.seed(123) # for reproducibility

index = pd.date_range("1 1 2010", 

                      periods=100, 

                      freq="m", 

                      name="Date")


data = np.random.randn(100, 4).cumsum(axis=0)


wide_df = pd.DataFrame(data, index, ['a', 'b', 'c', 'd'])

wide_df.shape

(100, 4)

 

wide_df.head()

abcd
Date
2010-01-31-1.0856310.9973450.282978-1.506295
2010-02-28-1.6642312.648782-2.143701-1.935207
2010-03-31-0.3982951.782042-2.822587-2.029916
2010-04-301.0930951.143140-3.266569-2.464268
2010-05-313.2990253.329926-2.262515-2.078081





  (Data form 2) Long-form DataFrame



# stack to reshape from wide to long

long = wide_df.stack()

 

long_df = pd.DataFrame(long).reset_index()


long_df.head()

Datelevel_10
02010-01-31a-1.085631
12010-01-31b0.997345
22010-01-31c0.282978
32010-01-31d-1.506295
42010-02-28a-1.664231


# change column nane

long_df.columns = ['Date', 'Group', 'CumVal']

long_df.head()

DateGroupCumVal
02010-01-31a-1.085631
12010-01-31b0.997345
22010-01-31c0.282978
32010-01-31d-1.506295
42010-02-28a-1.664231


long_df.shape

(400, 3)


# adding a 'Size' column based on 'Group'

long_df['Size'] = np.where(long_df['Group'] == 'a', 1, 

                           np.where(long_df['Group'] == 'b', 2, 

                                    np.where(long_df['Group'] == 'c', 3, 4)))


long_df.head(n=12)

DateGroupCumValSize
02010-01-31a-1.0856311
12010-01-31b0.9973452
22010-01-31c0.2829783
32010-01-31d-1.5062954
42010-02-28a-1.6642311
52010-02-28b2.6487822
62010-02-28c-2.1437013
72010-02-28d-1.9352074
82010-03-31a-0.3982951
92010-03-31b1.7820422
102010-03-31c-2.8225873
112010-03-31d-2.0299164






  1. matplotlib으로 선 그래프 그리기 (Line Graph by matplotlib)


1-1. Wide-form DataFrame


matplotlib 으로 선 그래프를 그릴 때 점의 모양(marker)와 색깔을 4개 변수별로 다르게 설정해보았습니다. 



# Line Graph by matplotlib with wide-form DataFrame

plt.plot(wide_df.index, wide_df.a, marker='s', color='r')

plt.plot(wide_df.index, wide_df.b, marker='o', color='g')

plt.plot(wide_df.index, wide_df.c, marker='*', color='b')

plt.plot(wide_df.index, wide_df.d, marker='+', color='y')


plt.title('Line Graph w/ different markers and colors', fontsize=20) 

plt.ylabel('Cummulative Num', fontsize=14)

plt.xlabel('Date', fontsize=14)

plt.legend(fontsize=12, loc='best')

plt.show()


 




아래는 선 모양(line style)과 선 두께(line width)을 4개 변수별로 다르게 설정해보았습니다. 



# Line Graph by matplotlib with different line style and line width

plt.plot(wide_df.index, wide_df.a, linestyle='--', linewidth=1) # 'dashed'

plt.plot(wide_df.index, wide_df.b, linestyle='-', linewidth=2) # solid

plt.plot(wide_df.index, wide_df.c, linestyle=':', linewidth=3) # dotted

plt.plot(wide_df.index, wide_df.d, linestyle='-.', linewidth=4) # dashdotted


plt.title('Line Graph w/ different linestyles and linewidths', fontsize=20) 

plt.ylabel('Cummulative Num', fontsize=14)

plt.xlabel('Date', fontsize=14)

plt.legend(fontsize=12, loc='best')

plt.show()




1-2. Long-form DataFrame


Long-form DataFrame으로 선 그래프를 그릴 때는 for loop 문을 사용해서 변수 별로 subsetting 을 해서 차례대로 선 그래프를 겹쳐서 그려줍니다. (matplotlib이 for loop 문으로 복잡하다면 다음의 seaborn은 상대적으로 매우 깔끔함)



long_df.head(n=8)

DateGroupCumValSize
02010-01-31a-1.0856311
12010-01-31b0.9973452
22010-01-31c0.2829783
32010-01-31d-1.5062954
42010-02-28a-1.6642311
52010-02-28b2.6487822
62010-02-28c-2.1437013
72010-02-28d-1.9352074


# Line graph with long-form DataFrame

groups = ['a', 'b', 'c', 'd']

linewidths = [1, 2, 3, 4]


for group_name, size in zip(groups, linewidths):

    # subsetting

    long_df_sub = long_df[long_df['Group'] == group_name]


    # plotting

    plt.plot(long_df_sub.Date, long_df_sub.CumVal, linewidth=size)


plt.legend(['a', 'b', 'c', 'd'], fontsize=12, loc='best')

plt.show()





  2. seaborn으로 선 그래프 그리기 (Line Graph by seaborn)


2-1. Wide-form DataFrame


데이터셋이 Wide-form DataFrame 형태이면 sns.lineplot(data=df_name) 딱 한줄이면 디폴트 세팅 만으로도 매우 보기에 좋은 선 그래프가 그려집니다. 



# Line graph by seaborn

ax = sns.lineplot(data=wide_df)


plt.title('Line Graph w/ Wide-form DataFrame by seaborn', fontsize=20)

plt.ylabel('Cummulative Num', fontsize=14)

plt.xlabel('Date', fontsize=14)

plt.legend(fontsize=12, loc='best')


plt.show()




2-2. Long-form DataFrame


seaborn 라이브러리의 묘미는 hue argument를 사용할 때입니다. ^^ hue='Group'변수별로 색깔을 다르게 하고, size='Size' 변수값에 따라 선 굵기(size)를 다르게 해보겠습니다. 



# Line graph with long-form DataFrame

long_df.head(n=8)

DateGroupCumValSize
02010-01-31a-1.0856311
12010-01-31b0.9973452
22010-01-31c0.2829783
32010-01-31d-1.5062954
42010-02-28a-1.6642311
52010-02-28b2.6487822
62010-02-28c-2.1437013
72010-02-28d-1.9352074


ax = sns.lineplot(x='Date', 

                  y='CumVal', 

                  hue='Group',

                  size='Size',

                  data=long_df)


plt.title('Line Graph of different size w/ Long-form df by seaborn', fontsize=20)

plt.ylabel('Cummulative Num', fontsize=14)

plt.xlabel('Date', fontsize=14)

plt.legend(fontsize=12, loc='best')


plt.show()

 



style argument를 사용하여 선의 형태(line style)을 다르게 설정해보겠습니다. 참고로 style에 설정하는1, 2, 3, 4 숫자별로 선의 형태가 solid, dashed, dotted, dash-dotted 입니다. 



ax = sns.lineplot(x='Date', 

                  y='CumVal', 

                  #hue='Group',

                  style='Size',

                  data=long_df)


plt.title('Line Graph of different style w/ Long-form df by seaborn', fontsize=20)

plt.ylabel('Cummulative Num', fontsize=14)

plt.xlabel('Date', fontsize=14)

plt.legend(fontsize=12, loc='best')


plt.show()

 





  3. pandas로 선 그래프 그리기 (Line Graph by pandas)


3-1. Wide-form DataFrame


pandas 의 DataFrame에 대해서 df.plot.line() 혹은 df.plot(kind='line') 의 format으로 선 그래프를 그릴 수 있습니다. 



wide_df.head()

abcd
Date
2010-01-31-1.0856310.9973450.282978-1.506295
2010-02-28-1.6642312.648782-2.143701-1.935207
2010-03-31-0.3982951.782042-2.822587-2.029916
2010-04-301.0930951.143140-3.266569-2.464268
2010-05-313.2990253.329926-2.262515-2.078081


 # Line Graph by pandas

wide_df.plot.line()


plt.title('Line Graph with Wide-form df by pandas', fontsize=20)

plt.xlabel('Date', fontsize=14)

plt.ylabel('Cummulative Value', fontsize=14)

plt.legend(fontsize=12, loc='best')

plt.show()




# accessed by calling the accessor as a method with the ``kind`` argument

wide_df.plot(kind='line')

plt.show()




3-2. Long-form DataFrame


세로로 긴 형태의 DataFrame은 plt.subplots() 에 groupby() operator 와 함께 for loop 문을 사용해서 df.plot(ax=ax, kind='line') syntax 로 선 그래프를 그립니다. 좀 복잡하지요? 



long_df.head(n=8)

DateGroupCumValSize
02010-01-31a-1.0856311
12010-01-31b0.9973452
22010-01-31c0.2829783
32010-01-31d-1.5062954
42010-02-28a-1.6642311
52010-02-28b2.6487822
62010-02-28c-2.1437013
72010-02-28d-1.9352074


# Line plot w/ Long-form df by pandas

fig, ax = plt.subplots()


for key, grp in long_df.groupby('Group'):

    ax = grp.plot(ax=ax, kind='line', x='Date', y='CumVal', label=key)


plt.title('Line Graph with Long-form df by pandas', fontsize=20)

plt.xlabel('Date', fontsize=14)

plt.ylabel('Cummulative Value', fontsize=14)

plt.legend(fontsize=12, loc='best')

plt.show()



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. ^^


Posted by R Friend R_Friend

이번 포스팅에서는 산점도(scatter plot)의 마지막으로서, 여러개의 연속형 변수에 대해서 각 각 쌍을 이루어서 산점도를 그려서 한꺼번에 변수 간 관계를 일목요연하게 볼 수 있는 산점도 행렬 (scatterplot matrix)에 대해서 알아보겠습니다. 



(1) 산점도 (Scatter Plot)

(2) 그룹별 산점도 (Scatter Plot by Groups)

(3) 4개 변수로 산점도 크기 및 색깔 다르게 그리기 (Scatterplot with 4 variables)

(4) 산점도 행렬 (Scatter Plot Matrix)

 



예제로 사용할 데이터는 iris 데이터셋에 들어있는 4개의 연속형변수들인 'petal_length', 'petal_width', 'sepal_length', 'sepal_width' 입니다. 


matplotlib 으로 산점도 행렬을 그리려면 코드가 너무 길어지고 가독성도 떨어지므로 추천하지 않으며, seaborn 과 pandas, plotly 를 사용한 산점도 행렬만 소개하겠습니다. 



import numpy as np

import pandas as pd


import matplotlib.pyplot as plt

import seaborn as sns

 



# iris data loading

iris = sns.load_dataset('iris')

iris.shape

(150, 5)


iris.head()

sepal_lengthsepal_widthpetal_lengthpetal_widthspecies
05.13.51.40.2setosa
14.93.01.40.2setosa
24.73.21.30.2setosa
34.63.11.50.2setosa
45.03.61.40.2setosa





  (1) seaborn을 이용한 산점도 행렬 (scatterplot matrix by seaborn)


default 설정을 사용하여 4개의 연속형 변수만을 가지고 그린 산점도 행렬입니다. ('species' 범주형 변수는 알아서 무시해주니 참 편리합니다!)  코드도 간결하고 그래프도 깔끔하니 이뻐서 정말 마음에 듭니다! 

대각원소 자리에는 diag_kind='hist' 를 설정하여 각 변수별 히스토그램을 볼 수 있게 하였습니다. 



# scatterplot matrix with histogram only for continuous variables

sns.pairplot(iris, diag_kind='hist')

plt.show()


 




아래의 산점도 행렬에는 diag_kind='kde' 를 사용하여 각 변수별 커널밀도추정곡선을 볼 수 있게 하였으며, hue='species'를 사용하여 'species' 종(setosa, versicolor, virginica) 별로 색깔을 다르게 표시하여 추가적인 정보를 알 수 있도록 하였습니다. 색깔은 palette 에 'bright', 'pastel', 'deep', 'muted', 'colorblind', 'dark' 중에서 가독성이 좋고 선호하는 색상으로 선택하면 됩니다. 


아래 그래프를 이처럼 간결한 코드로 아름답게 그릴 수 있다니 seaborn 참 매력적입니다!



# Scatterplot matrix with different color by group and kde

sns.pairplot(iris, 

             diag_kind='kde',

             hue="species", 

             palette='bright') # pastel, bright, deep, muted, colorblind, dark

plt.show()






  (2) pandas를 이용한 산점도 행렬 (scatterplot matrix by pandas)


아래는 pandas.plotting 의 scatter_matrix() 함수를 사용하여 산점도 행렬을 그려본 것인데요, 코드가 간결하긴 하지만 위의 seaborn 대비 그래프가 그리 아름답지는 않고 좀 투박합니다. 



# scatterplot matrix by pandas scatter_matrix()

from pandas.plotting import scatter_matrix

scatter_matrix(iris, 

               alpha=0.5, 

               figsize=(8, 8), 

               diagonal='kde')

plt.show()




  (3) plotly를 이용한 산점도 행렬 (interactive scatterplot matrix by plotly)


plotly를 이용하면 분석가와 상호작용할 수 있는 역동적인 산점도 행렬 (interactive scatterplot matrix)을 만들 수 있습니다. API 대신에 오프라인 모드(offline mode)에서 사용할 수 있도록 아래에 제시한 패키지들을 pip로 설치하고, import 해주어야 합니다. 



# import plotly standard

import plotly.plotly as py

import plotly.graph_objs as go

import plotly.figure_factory as ff


# Cufflinks wrapper on plotly

import cufflinks as cf


# Display all cell outputs

from IPython.core.interactiveshell import InteractiveShell


# plotly + cufflinks in offline mode

from plotly.offline import iplot

cf.go_offline()


# set the global theme

cf.set_config_file(world_readable=True, theme='pearl', offline=True)

 




plotly.offline의 iplot을 사용하여 오프라인 모드에서 산점도 행렬을 그린 결과입니다. iag='histogram'으로 대각 행렬 위치에는 각 변수의 히스토그램을 그렸으며, 'scatter' (점 그림)와 'box' (박스 그림) 을 설정할 수도 있습니다. 


아래는 화면 캡펴한 이미지를 넣었는데요, jupyter notebook에서 보면 커서를 가져다데는 곳에 x, y 좌표 값이 실시간으로 화면에 INTERACTIVE하게 나타납니다. hover 기능도 있어서 커서로 블록을 설정하면 블록에 해당하는 부분만 다시 산점도가 그려지기도 하며, file로 바로 다운로드도 가능합니다. 



fig = ff.create_scatterplotmatrix(

    iris[['petal_width', 'petal_length', 'sepal_width', 'sepal_length']],

    height=800,

    width=800, 

    diag='histogram') # scatter, histogram, box


iplot(fig) # offline mode

 





아래의 산점도 행렬에서는 대각행렬 위치에 '박스 그림 (diag='box')'을 제시하였고, 산점도와 대각원소의 박스 그림을 index='species'를 사용하여 3개 종(setosa, versicolor, virginica) 별로 색깔을 다르게 구분해서 그려본 것입니다. 


아래 그림은 화면 캡쳐한 것이어서 interactive 하지 않은데요 (-_-;;;), jupyter notebook에서 실행해보면 커서를 위로 올려놓으면 데이터 값이 나오구요, 줌 인/아웃, hover, 다운로드 등 interactive 한 시각화가 가능합니다. 



# scatterplot matrix by plotly with box plot at diagonal & different color by index(GROUP)

fig = ff.create_scatterplotmatrix(

    iris,

    height=800,

    width=800, 

    diag='box', # scatter, histogram, box

    index='species')


iplot(fig)

 



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. ^^


Posted by R Friend R_Friend

이번 포스팅은 두 개의 연속형 변수에 대한 관계를 파악하는데 유용하게 사용할 수 있는 산점도(Scatter Plot) 의 세번째 포스팅으로서 4개의 연속형 변수를 사용하여 X축, Y축, 점의 색깔(color)과 크기(size)을 다르게 하는 방법을 소개합니다. 


즉, 산점도를 사용하여 4차원의 데이터를 2차원에 시각화하는 방법입니다. 




(1) 산점도 (Scatter Plot)

(2) 그룹별 산점도 (Scatter Plot by Groups)

(3) 4개 변수로 점의 크기와 색을 다르게 산점도 그리기 (Scatter plot with different size, color)

(4) 산점도 행렬 (Scatter Plot Matrix)

 



예제로 활용할 데이터는 iris 의 4개의 연속형 변수들입니다. 



# importing libraries

import numpy as np

import pandas as pd


import matplotlib.pyplot as plt

import seaborn as sns

plt.rcParams['figure.figsize'] = [10, 8] # setting figure size

 


 

# loading 'iris' dataset from seaborn

iris = sns.load_dataset('iris')

iris.shape

(150, 5)


iris.head()

sepal_lengthsepal_widthpetal_lengthpetal_widthspecies
05.13.51.40.2setosa
14.93.01.40.2setosa
24.73.21.30.2setosa
34.63.11.50.2setosa
45.03.61.40.2setosa





  (1) matplotlib에 의한 4개 연속형 변수를 사용한 산점도 (X축, Y축, 색, 크기)


plt.scatter() 함수를 사용하며, 점의 크기는 s, 점의 색깔은 c 에 변수를 할당해주면 됩니다. 



# 4 dimensional scatter plot with different size & color

plt.scatter(iris.sepal_length, # x

           iris.sepal_width, # y

           alpha=0.2, 

           s=200*iris.petal_width, # marker size

           c=iris.petal_length, # marker color

           cmap='viridis')

plt.title('Scatter Plot with Size(Petal Width) & Color(Petal Length)', fontsize=14)

plt.xlabel('Sepal Length', fontsize=12)

plt.ylabel('Sepal Width', fontsize=12)

plt.colorbar()

plt.show()





점(marker)의 모양을 네모로 바꾸고 싶으면 marker='s' 로 설정해주면 됩니다. 



# 4 dimensional scatter plot with different size & color

plt.scatter(iris.sepal_length, # x

           iris.sepal_width, # y

           alpha=0.2, 

           s=200*iris.petal_width, # marker size

           c=iris.petal_length, # marker color

           cmap='viridis'

           marker = 's') # square shape

plt.title('Size(Petal Width) & Color(Petal Length) with Square Marker', fontsize=14)

plt.xlabel('Sepal Length', fontsize=12)

plt.ylabel('Sepal Width', fontsize=12)

plt.colorbar()

plt.show()

 





  (2) seaborn에 의한 4개 연속형 변수를 사용한 산점도 (X축, Y축, 색, 크기)


seaborn 의 산점도 코드는 깔끔하고 이해하기에 쉬으며, 범례도 잘 알아서 색깔과 크기를 표시해주는지라 무척 편리합니다. 



# 4 dimensional scatter plot by seaborn

sns.scatterplot(x='sepal_length', 

                y='sepal_width', 

                hue='petal_length',

                size='petal_width',

                data=iris)

plt.show()





  (3) pandas에 의한 4개 연속형 변수를 사용한 산점도 (X축, Y축, 색, 크기)


pandas의 DataFrame에 plot(kind='scatter') 로 해서 color=iris['petal_length']로 색깔을 설정, s=iris['petal_width'] 로 크기를 설정해주면 됩니다. pandas 산점도 코드도 깔끔하고 이해하기 쉽긴 한데요, 범례 추가하기가 쉽지가 않군요. ^^; 



iris.plot(kind='scatter'

          x='sepal_length', 

          y='sepal_width', 

          color=iris['petal_length'],

          s=iris['petal_width']*100)


plt.title('Size(Petal Width) & Color(Petal Length) with Square Marker', fontsize=14)

plt.show()




참고로, 산점도의 점(marker)의 모양(shape)을 설정하는 심벌들은 아래와 같으니 참고하시기 바랍니다. 



# set the size

plt.rcParams['figure.figsize'] = [10, 8]


# remove ticks and values of axis

plt.xticks([])

plt.yticks([])


# markers' shape

all_shape=['.','o','v','^','>','<','s','p','*','h','H','D', 'd', '', '', '']


num = 0

for x in range(1, 5):

    for y in range(1, 5):

        num += 1

        

        plt.plot(x, y, 

                 marker = all_shape[num-1], 

                 markerfacecolor='green', 

                 markersize=20, 

                 markeredgecolor='black')

        

        plt.text(x+0.1, y, 

                 all_shape[num-1], 

                 horizontalalignment='left', 

                 size='medium', 

                 color='black', 

                 weight='semibold')

        

plt.title('Markers', fontsize=20)        

plt.show()



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. ^^


다음번 포스팅에서는 산점도 행렬 (Scatter Plot Matrix) 에 대해서 소개하겠습니다. 



Posted by R Friend R_Friend

이번 포스팅부터는 두 개의 연속형 변수에 대한 관계를 파악하는데 유용하게 사용할 수 있는 산점도(Scatter Plot) 를 4번에 나누어서 소개를 하겠습니다. 


(1) 산점도 (Scatter Plot)

(2) 그룹별 산점도 (Scatter Plot by Groups)

(3) 산점도의 marker 크기 및 색깔, 모양 설정 (Setting Marker's size, color, shape)

(4) 산점도 행렬 (Scatter Plot Matrix)



기본적인 산점도를 matplotlib, seaborn, pandas 패키지를 사용하여 순서대로 그려보겠습니다. 


사용할 데이터는 iris 데이터셋의 'petal length'와 'petal width'의 두 개 연속형 변수입니다. 



# importing libraries

import numpy as np

import pandas as pd


import matplotlib.pyplot as plt

import seaborn as sns

plt.rcParams['figure.figsize'] = [12, 8] # setting figure size

 



# loading 'iris' dataset from seaborn

iris = sns.load_dataset('iris')

iris.shape

(150, 5) 


iris.head()

sepal_lengthsepal_widthpetal_lengthpetal_widthspecies
05.13.51.40.2setosa
14.93.01.40.2setosa
24.73.21.30.2setosa
34.63.11.50.2setosa
45.03.61.40.2setosa




  (1) matplotlib을 사용한 산점도 (scatter plot by matplotlib)


# Basic Scatter Plot

plt.plot('petal_length',  # x

         'petal_width',  # y

         data=iris, 

         linestyle='none', 

         marker='o', 

         markersize=10,

         color='blue', 

         alpha=0.5)

plt.title('Scatter Plot of iris by matplotlib', fontsize=20)

plt.xlabel('Petal Length', fontsize=14)

plt.ylabel('Petal Width', fontsize=14)

plt.show()




산점도에 X, Y 좌표를 사용하여 직사각형(rectangle), 원(circle), 직선(line)을 추가하여 보겠습니다. 먼저 matplotlib.patches 를 importing 해주어야 하고, 산점도를 그린 다음에, add_patch() 함수를 사용하여 직사각형, 원, 직선을 추가합니다. 



# adding a rectangle, a circle

import matplotlib.patches as patches

import matplotlib.pyplot as plt


fig1 = plt.figure()

ax1 = fig1.add_subplot(111)


# (0) scatter plot

ax1.plot('petal_length', 'petal_width', data=iris, linestyle='none', marker='o')


# (1) adding a rectangle

ax1.add_patch(

    patches.Rectangle(

        (3, 1), # (x, y)

        2, # width

        1, # height

        alpha=0.2, 

        facecolor="blue", 

        edgecolor="black", 

        linewidth=2, 

        linestyle="solid", 

        angle=-10))


# (2) adding a circle

ax1.add_patch(

    patches.Circle(

        (1.5, 0.25), # (x, y)

        0.5, # radius

        alpha=0.2, 

        facecolor="red", 

        edgecolor="black", 

        linewidth=2, 

        linestyle='solid'))


# (3) adding a line

plt.plot([4, 6], [2.2, 1.1], color="green", lw=4, linestyle='solid')


plt.title("Adding a Rectangle, a Circle and a Line", fontsize=20)

plt.xlabel('Petal Length', fontsize=14)

plt.ylabel('Petal Width', fontsize=14)

plt.show()

 






  (2) seaborn을 사용한 산점도 (scatter plot by seaborn)


seaborn 패키지의 (a) regplot() 함수와 (b) scatterplot() 함수를 사용해서 산점도를 그릴 수 있습니다. 순서대로 소개합니다. 


(a) regplot() 함수를 사용한 산점도


선형회귀 적합 선을 포함시키지 않으려면 fit_reg=False 를 설정해주면 됩니다. 



# Basic Scatter Plot by seaborn

sns.regplot(x=iris['petal_length'], 

           y=iris['petal_width'], 

           fit_reg=False) # no regression line

plt.title('Scatter Plot of iris by regplot()', fontsize=20)

plt.xlabel('Petal Length', fontsize=14)

plt.ylabel('Petal Width', fontsize=14)

plt.show()





두 연속형 변수 간의 선형회귀 적합선을 산점도에 포함시키려면 fit_reg=True 를 설정해주면 됩니다. (defalt 이므로 별도로 표기를 해주지 않아도 회귀적합선이 추가됩니다)



# Scatter Plot with regression line by seaborn regplot()

sns.regplot(x=iris['petal_length'], 

           y=iris['petal_width'], 

           fit_reg=True) # default

plt.title('Scatter Plot with Regression Line by regplot()', fontsize=20)

plt.show()




X축과 Y축의 특정 값의 조건을 기준으로 산점도 marker의 색깔을 다르게 해보겠습니다. 가령, 'petal length' > 2.5 & 'petal width' > 0.8 이면 '빨간색', 그 이외는 '파란색'으로 설정을 해보겠습니다. 조건에 맞게 'color'라는 새로운 변수를 생성한 후에, scatter_kws={'facecolors': iris_df['color']}) 로 조건별 색을 설정하는 방법을 사용하였습니다. 



# Control color of each marker based on X and Y values

iris_df = iris.copy()


# Adding a 'color' column based on x and y values

cutoff = (iris_df['petal_length']>2.5) & (iris_df['petal_width'] > 0.8)

iris_df['color'] = np.where(cutoff==True, "red", "blue")


# Scatter Plot with different colors based on X and Y values

sns.regplot(x=iris['petal_length'], 

           y=iris['petal_width'], 

           fit_reg=False

           scatter_kws={'facecolors': iris_df['color']}) # marker color

plt.title('Scatter Plot with different colors by X & Y values', fontsize=20)

plt.show()

 




(b) scatterplot() 함수를 사용한 산점도


# scatter plot by seaborn scatterplot()

ax = sns.scatterplot(x='petal_length', 

                     y='petal_width', 

                     alpha=0.5,

                     data=iris)

plt.title('Scatter Plot by seaborn', fontsize=20)

plt.show()




  (3) pandas를 사용한 산점도 (scatter plot by pandas)



iris.plot.scatter(x='petal_length', 

                  y='petal_width', 

                  s=50, # marker size

                  c='blue', 

                  alpha=0.5)

plt.title('Scatter Plot of iris by pandas', fontsize=20)

plt.xlabel('Petal Length', fontsize=14)

plt.ylabel('Petal Width', fontsize=14)

plt.show()




많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. ^^


다음번 포스팅에서는 그룹별 산점도 (Scatter Plot by Groups) 의 마커 모양, 색깔을 다르게 그리는 방법을 소개하겠습니다. 



Posted by R Friend R_Friend

이번 포스팅에서는 시장 점유율과 같이 구성비율을 시각화하는데 사용하는 (1) 원 그래프 (Pie Chart), (2) 하위 그룹을 포함한 도넛 그래프 (Donut Chart with Subgraphs) 그리는 방법을 소개하겠습니다. 


두 개 모두 matplotlib 의 pie() 함수를 사용합니다. 



  (1) 원 그래프 (Pie Chart)



# importing library and set figure size

import matplotlib.pyplot as plt

plt.rcParams['figure.figsize'] = [12, 8]

 



# information of groups

group_names = ['Group_A', 'Group_B', 'Group_C']

group_sizes = [95, 54, 25]

group_colors = ['yellowgreen', 'lightskyblue', 'lightcoral']

group_explodes = (0.1, 0, 0) # explode 1st slice

 



# Pie chart

plt.pie(group_sizes, 

        explode=group_explodes, 

        labels=group_names, 

        colors=group_colors, 

        autopct='%1.2f%%', # second decimal place

        shadow=True, 

        startangle=90,

        textprops={'fontsize': 14}) # text font size

plt.axis('equal') #  equal length of X and Y axis

plt.title('Pie Chart of Market Share', fontsize=20)

plt.show()




  (2) 하위 그룹을 포함한 도넛 그래프 (Donut Chart with Subgraphs)


상위 그룹 A, B, C가 있고, 각 상위 그룹에 딸린 하위 그룹으로 'A_1'~'A_4', 'B_1'~'B_3', 'C_1'~'C_2' 의 하위 그룹(subgroups)이 있는 경우 가운데가 뚫린 도넛 모양의 도넛 그래프로 표현해주면 효과적입니다. 


기본 원리는 간단합니다. matplotlib 으로 원 그래프를 그리되, radius 와 width 의 숫자를 적절히 조절하여 (a) 바깥쪽의 상위 그룹의 원 그래프를 반지름이 크고 폭은 작아서 가운데가 뚫린 도넛 그래프로 만들고, (b) 안쪽에는 하위 그룹의 원 그래프를 반지름이 상위 그룹의 것보다는 작고(즉, 상위 그룹 도넛 그래프의 폭 만큼을 빼줌) 폭은 상위 그룹과 같은 가운데가 뚫린 도넛 그래프를 만들여서, (a)와 (b)의 두개 도넛 그래프를 겹치게 그리는 것입니다. 



# importing library and set figure size

import matplotlib.pyplot as plt

plt.rcParams['figure.figsize'] = [12, 8]

 



 # info. of groups

group_names = ['Group_A', 'Group_B', 'Group_C']

group_sizes = [95, 54, 25]


# info. of subgroups

subgroup_names = ['A_1', 'A_2', 'A_3', 'A_4', 

                  'B_1', 'B_2', 'B_3', 

                  'C_1', 'C_2']

subgroup_sizes = [50, 30, 10, 5, 30, 20, 4, 20, 5]


# colors

a, b, c = [plt.cm.Reds, plt.cm.Greens, plt.cm.Blues]


# width

width_num = 0.4

 



# Outside Ring

fig, ax = plt.subplots()

ax.axis('equal')

pie_outside, _ = ax.pie(group_sizes, 

                        radius=1.3

                        labels=group_names, 

                        labeldistance=0.8,

                        colors=[a(0.6), b(0.6), c(0.6)])

plt.setp(pie_outside

         width=width_num

         edgecolor='white')


# Inside Ring

pie_inside, plt_labels, junk = \

    ax.pie(subgroup_sizes, 

           radius=(1.3 - width_num), 

           labels=subgroup_names, 

           labeldistance=0.75, 

           autopct='%1.1f%%', 

           colors=[a(0.5), a(0.4), a(0.3), a(0.2), 

                   b(0.5), b(0.4), b(0.3), 

                   c(0.5), c(0.4)])

plt.setp(pie_inside

         width=width_num

         edgecolor='white')

plt.title('Donut Plot with Subgroups', fontsize=20)

plt.show()

 



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)



Posted by R Friend R_Friend

지난 포스팅에서는 Python으로 연속형 자료에 대해 히스토그램박스 그래프를 그리는 방법을 소개하였습니다. 


이번 포스팅에서는 이산형 자료에 대해 범주(category), 계급(class)별로 빈도나 합계 등을 막대로 그려서 비교하는데 유용하게 사용하는 막대 그래프(bar chart)를 Python의 matplotlib, seaborn, pandas를 사용하여 그리는 방법을 소개하겠습니다. 


예제로 사용할 데이터셋은 seaborn에 내장되어 있는 tips 데이터셋입니다. 



# importing packages

import numpy as np

import pandas as pd


import matplotlib.pyplot as plt

import seaborn as sns

plt.rcParams['figure.figsize'] = [10, 6]

 



# Loading 'tips' dataset from seaborn

tips = sns.load_dataset('tips')

tips.shape

(244, 7)

 

tips.head()

total_billtipsexsmokerdaytimesize
016.991.01FemaleNoSunDinner2
110.341.66MaleNoSunDinner3
221.013.50MaleNoSunDinner3
323.683.31MaleNoSunDinner2
424.593.61FemaleNoSunDinner

4





  (1) matplotlib으로 막대 그리프 그리기 (bar chart by matplotlib)


tips DataFrame에서 요일(day)별로 tip 의 합계를 구해서 막대 그래프로 비교를 해보겠습니다. 



# Summary Statistics

tips_sum_by_day = tips.groupby('day').tip.sum()

tips_sum_by_day

day
Thur    171.83
Fri      51.96
Sat     260.40
Sun     247.39 

Name: tip, dtype: float64

 



label = ['Thur', 'Fri', 'Sat', 'Sun']

index = np.arange(len(label))

 



# Basic Bar Chart

plt.bar(index, tips_sum_by_day)

plt.title('Sum of Tips by Day', fontsize=20)

plt.xlabel('Day', fontsize=18)

plt.ylabel('Sum of Tips', fontsize=18)

plt.xticks(index, label, fontsize=15)

plt.show()

 




막대 그래프의 막대 색깔(bar color)과 투명도(transparency, alpha)를 조절해보겠습니다. 



# bar color, transparency

plt.bar(label, tips_sum_by_day, 

        color='red', # color

        alpha=0.5) # transparency

plt.show()

 





막대그래프의 막대 폭(width)을 좀더 좁게하고, 가운데 정렬 대신에 한쪽 끝으로 정렬(align)을 변경해보겠습니다. 



# bar width, align

plt.bar(label, tips_sum_by_day, 

        width=0.5, # default: 0.8

        align='edge') # default: 'center'

plt.show()

 




X축의 라벨이 갯수가 많거나 길이가 길 경우에는 X 축 라벨을 비스듬히 눕히거나 90도로 세우는 것이 보기에 더 효과적일 때가 있습니다. X축 라벨을 90도 회전시켜 보겠습니다.  



# X tick labels rotation

plt.bar(index, tips_sum_by_day)

plt.xlabel('Day', fontsize=18)

plt.xticks(index, label, fontsize=15, 

           rotation=90) # when X tick labels are long

plt.show()

 




X축의 라벨 개수가 많다면 막대그래프를 아예 가로로 눕혀서 그리는 것이(horizontal bar chart) 보기에 효과적일 때도 있습니다. 옆으로 누운 막대그래프는 plt.barh() 함수를 사용합니다. 



# Horizontal Bar Chart

plt.barh(index, tips_sum_by_day)

plt.title('Sum of Tips by Day', fontsize=18)

plt.ylabel('Day', fontsize=15)

plt.xlabel('Sum of Tips', fontsize=15)

plt.yticks(index, label, fontsize=13, rotation=0)

plt.show()




2개의 범주형 변수를 사용하여 각 클래스별로 빈도나 합계를 막대그래프로 비교하려면 (a) 위로 쌓은 막대그래프 (stacked bar chart)나, (b) 옆으로 나란히 놓은 막대그래프 (dodged bar chart)를 사용합니다. 


먼저, (a) 요일(day)과 성별(sex)의 두개 범주형 변수의 클래스별로 팁(tip)의 합계를 비교하기 위해 위로 쌓은 막대그래프 (stacked bar chart)를 그려보겠습니다. 



# summary by group

tips_sum_by_day_male = tips[tips['sex'] == 'Male'].groupby('day').tip.sum()

tips_sum_by_day_female = tips[tips['sex'] == 'Female'].groupby('day').tip.sum()


print('--Male--')

print(tips_sum_by_day_male);

print(' ')

print('--Female--')

print(tips_sum_by_day_female);

--Male--

day
Thur     89.41
Fri      26.93
Sat     181.95
Sun     186.78
Name: tip, dtype: float64
 
--Female--
day
Thur    82.42
Fri     25.03
Sat     78.45
Sun     60.61
Name: tip, dtype: float64




# Bar Chart by 2 categorical variables

# Stacked Bar Chart

label = ['Thur', 'Fri', 'Sat', 'Sun']

N = len(tips['day'].unique())

index = np.arange(N)

alpha = 0.5


p1 = plt.bar(index, tips_sum_by_day_male, color='b', alpha=alpha)

p2 = plt.bar(index, tips_sum_by_day_female, color='r', alpha=alpha,

             bottom=tips_sum_by_day_male) # stacked bar chart

plt.title('Stacked Bar Chart of Sum of Tips by Day & Sex', fontsize=20)

plt.ylabel('Sum of Tips', fontsize=18)

plt.xlabel('Day', fontsize=18)

plt.xticks(index, label, fontsize=15)

plt.legend((p1[0], p2[0]), ('Male', 'Female'), fontsize=15)

plt.show()

 




다음으로 (b) 요일(day)과 성별(sex)의 두개 범주형 변수의 클래스별로 팁(tip)의 합계를 비교하기 위해 옆으로 나란히 놓은 막대그래프를 그려보겠습니다. 두번째 막대 그래프에서 X축의 위치를 bar_width 만큼 오른쪽으로 바로 붙여서 그려지도록 index+bar_width 로 설정(빨간색 부분)해주면 됩니다. 



# Dodged Bar Chart (with same X coordinates side by side)

bar_width = 0.35

alpha = 0.5


p1 = plt.bar(index, tips_sum_by_day_male, 

             bar_width, 

             color='b', 

             alpha=alpha,

             label='Male')

p2 = plt.bar(index + bar_width, tips_sum_by_day_female, 

             bar_width, 

             color='r', 

             alpha=alpha,

             label='Female')


plt.title('Dodged Bar Chart of Sum of Tips by Day & Sex', fontsize=20)

plt.ylabel('Sum of Tips', fontsize=18)

plt.xlabel('Day', fontsize=18)

plt.xticks(index, label, fontsize=15)

plt.legend((p1[0], p2[0]), ('Male', 'Female'), fontsize=15)

plt.show()

 




  (2) seaborn 으로 막대 그래프 그리기 (bar chart by seaborn)


seaborn 패키지를 사용하여 위의 matplotlib 으로 그린 stacked bar chart를 그려보겠습니다. input 으로 사용하는 집계한 데이터프레임(aggregated DataFrame)을 먼저 만들고, sns.barplot() 함수에서 hue argument를 같이 사용하고 dodge=False를 설정해서 위로 쌓은 막대그래프를 그립니다. matplotlib 대비 코드가 한결 간결해졌습니다. 



tips_sum_by_day_sex = pd.DataFrame(tips.groupby(['day', 'sex']).tip.sum())

tips_sum_by_day_sex = tips_sum_by_day_sex.reset_index()

tips_sum_by_day_sex

daysextip
0ThurMale89.41
1ThurFemale82.42
2FriMale26.93
3FriFemale25.03
4SatMale181.95
5SatFemale78.45
6SunMale186.78
7SunFemale60.61

 



# Stacked Bar Chart

sns.barplot(x='day', y='tip', hue='sex', data=tips_sum_by_day_sex, 

           dodge=False) # stacked bar chart

plt.title('Stacked Bar Chart by Seaborn', fontsize='20')

plt.show()




seaborn으로 옆으로 나란히 두 개의 범주형 변수의 클래스별 막대그래프를 그려서 비교를 하려면 dodge=True (default setting) 을 해주면 됩니다. 



# Dodged Bar Chart

sns.barplot(x='day', y='tip', hue='sex', data=tips_sum_by_day_sex) # default : dodge=True

plt.title('Dodged Bar Chart by Seaborn', fontsize=20)

plt.legend(fontsize=12)

plt.show()





  (3) pandas 로 막대 그래프 그리기 (bar chart by pandas)


pandas로도 막대 그래프를 그릴 수 있는데요, 위의 matplotlib, seaborn으로 그릴 때 사용했던 데이터 집계 테이블 형태가 조금 다르므로 유심히 살펴보고 참고해서 사용하시기 바랍니다. 



# make a DataFrame

tips_sum_by_day = pd.DataFrame(tips.groupby('day').tip.sum())

tips_sum_by_day = tips_sum_by_day.reset_index()

daytip
0Thur171.83
1Fri51.96
2Sat260.40
3Sun247.39

 




pandas DataFrame에 df.plot.bar() 함수를 사용하거나 df.plot(kind='bar') 를 사용해서 막대그래프를 그립니다.  rot 는 X축 라벨의 회전(rotation) 각도를 설정하는데 사용합니다. 



# basic bar chart with a single column

tips_sum_by_day.plot.bar(x='day', y='tip', rot=0)

plt.show()





이번에는 pandas로 요일(day)과 성별(sex)의 두개 범주형 변수의 각 클래스별로 팁의 합계(summation of tip)를 집계하여 위로 쌓은 막대그래프(stacked bar chart)를 그려보겠습니다. 



# making a DataFrame with 'day' and 'sex' groups

tips_sum_by_day_sex = pd.DataFrame(tips.groupby(['day', 'sex']).tip.sum())

tips_sum_by_day_sex = tips_sum_by_day_sex.reset_index()


# pivot

tips_sum_by_day_sex_pivot = \

    tips_sum_by_day_sex.pivot(index='day', 

                              columns='sex', 

                              values='tip')

tips_sum_by_day_sex_pivot

sexMaleFemale
day
Thur89.4182.42
Fri26.9325.03
Sat181.9578.45
Sun186.7860.61




# Stacked Bar Chart by pandas

tips_sum_by_day_sex_pivot.plot.bar(stacked=True, rot=0)

plt.title('Stacked Bar Chart by Pandas', fontsize=20)

plt.show()




이번에는 pandas로 요일(day)별 성별(sex) 팁의 합계를 옆으로 나란히 막대그래프(dodged bar chart by pandas)로 그려서 비교를 해보겠습니다. 



# Dodged Bar Chart by pandas

tips_sum_by_day_sex_pivot.plot(kind='bar', rot=0)

plt.title('Dodged Bar Chart by Pandas', fontsize=20)

plt.legend(fontsize='12')

plt.show()

 



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. 



Posted by R Friend R_Friend

이번 포스팅에서는 하나의 연속형 변수에 대해서 분포 형태, 퍼짐정도, 이상치 여부 등을 시각화하고, 하나의 그룹 혹은 여러개의 그룹 간 비교하는데 유용한 상자 그림 (Box plot, Box-and-Whisker Plot)을 그리는 방법을 소개하겠습니다. 


상자 그림은 연속형 변수에 대해서 최소값(min), 제 1사분위수(Q1), 중앙값(Q2, median), 제 3사분위수(Q3), 최대값(max) 의 요약통계량을 계산하는 것에서 시작합니다. 



[상자 그림 그리는 순서 및 방법]


  1. 주어진 데이터에서 각 사분위수를 계산한다.
  2. 그래프에서 제1 사분위와 제3 사분위를 밑변으로 하는 직사각형을 그리고, 제 2사분위에 해당하는 위치에 선분을 긋는다.
  3. 사분위수 범위(IQR, Interquartile range, )를 계산한다.
  4. 과 차이가 1.5*IQR 이내인 값 중에서 최댓값을 과 직선으로 연결하고, 마찬가지로 과 차이가 1.5*IQR 이내인 값 중에서 최솟값을 과 연결한다.
  5. 보다 1.5*IQR 이상 초과하는 값과 보다 1.5*IQR 이상 미달하는 값은 점이나, 원, 별표등으로 따로 표시한다(이상치 점).

* source: https://ko.wikipedia.org/wiki/상자_수염_그림

 



위의 상자 그림 그리는 방법에 대한 내용은 아래의 표준정규분포 확률밀도함수 분포 곡선에 대한 상자 그림 매핑을 보면 좀더 이해가 쉬울 것입니다. 


[Boxplot and a probability density function (pdf) of a Normal N(0,1σ2) Population]


* source: https://en.wikipedia.org/wiki/Box_plot




상자 그림을 (1) matplotlib, (2) seaborn, (3) pandas 패키지를 이용해서 그리는 방법을 차례대로 소개하겠습니다. 



import numpy as np

import pandas as pd


import matplotlib.pyplot as plt

import seaborn as sns

plt.rcParams['figure.figsize'] = [10, 6]

%matplotlib inline




예제로 사용할 데이터셋은 seaborn 패키지에 내장되어 있는 tips 라는 DataFrame 을 사용하겠습니다. 



# loading 'tips' dataset

tips = sns.load_dataset('tips')


tips.shape

(244, 7)


tips.head()

total_billtipsexsmokerdaytimesize
016.991.01FemaleNoSunDinner2
110.341.66MaleNoSunDinner3
221.013.50MaleNoSunDinner3
323.683.31MaleNoSunDinner2
424.593.61FemaleNoSunDinner4


tips.groupby(['sex', 'day']).size()

sex     day 
Male    Thur    30
        Fri     10
        Sat     59
        Sun     58
Female  Thur    32
        Fri      9
        Sat     28
        Sun     18
dtype: int64




tips DataFrame의 tip 연속형 변수에 대해서 상자 그림을 그려보겠습니다. 


  (1) matplotlib 으로 상자 그림 그리기


boxplot() 함수를 사용해서 default 세팅으로 상자 그림을 그려보겠습니다. 


# Basic box plot

plt.boxplot(tips['tip'])

plt.show()



이번에는 상자 그림의 이상치(outlier) 모양과 색깔, 제목(title), X축 이름(X label)을 설정해보겠습니다. 



# setting outlier symbol, title, xlabel

plt.boxplot(tips['tip'], sym="bo")

plt.title('Box plot of tip')

plt.xticks([1], ['tip'])

plt.show()




다음으로 상자그림을 가로로 눕히고, 가운데 상자는 중앙값 부근에서 V자 형태로 골이 패이게(notch) 그려보겠습니다. 


 

# Horizontal Box plot with notched box & red color outliers

plt.boxplot(tips['tip'], 

            notch=1, # if 'True' then notched box plot

            sym='rs', # symbol: red square

            vert=0 # vertical : if 'False' then horizontal box plot

           )

plt.show()




한 개의 축에 여러 개의 연속형 변수(total_bill, tip)에 대한 여러 개의 상자 그림을 한꺼번에 그려보겠습니다. (다수 개의 연속형 변수, 한개의 그룹)



# Multiple box plots on one Axes

fig, ax = plt.subplots()

ax.boxplot([tips['total_bill'], tips['tip']], sym="b*")

plt.title('Multiple box plots of tips on one Axes')

plt.xticks([1, 2], 

           ['total_bill', 'tip'])

plt.show()

 




  (2) seaborn 으로 여러개 그룹에 대한 상자 그림 그리기 

      (Grouped box plots by seaborn)


요일(day) 그룹별러 팁(tip)에 대한 상자 그림을 같이 그려서 비교를 해보겠습니다. (한 개의 연속 형 변수, 다수 개의 그룹)



# Grouped boxplots by seaborn

import seaborn as sns


sns.boxplot(x="day"

            y="tip"

            data=tips)

plt.show()





위의 요일(day: Thur, Fri, Sat, Sun) 그룹에 더해 hue 옵션을 사용하여 성별(sex: Male, Female)에 따른 그룹을 추가하여 (총 4개 그룹 x 2개 그룹 = 8개 그룹) 별 팁(tip) 에 대한 상자 그림을 그려서 비교해보겠습니다. 



#  2 by 4 multi-Grouped boxplots by seaborn

sns.boxplot(x="day", 

            y="tip", 

            hue="sex",

            data=tips)


plt.show()

 





  (3) pandas 로 상자 그림 그리기


pandas의 DataFrame에 df.boxplot() 함수를 사용하여 상자 그림을 그릴 수 있습니다. (2)번에서 그렸던 그룹 별 상자 그림을 pandas 의 boxplot() 함수로 그려보면 아래와 같습니다. 



# Grouped boxplots by pandas

tips.boxplot(column=["tip"], by=["day", "sex"])

plt.show()


제 개인적인 생각으로는, 그래프의 가독성은 seaborn이 더 나아 보이고, 코드의 가독성은 pandas가 더 우수해보이네요. 


많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요.


다음번 포스팅에서는 막대 그래프 그리는 방법을 소개하겠습니다. 



Posted by R Friend R_Friend

지난번 포스팅에서는 하나의 그룹, 하나의 변수에 대한 히스토그램, 커널밀도곡선을 그리는 방법을 소개하였습니다. 


이번 포스팅에서는

(1) 여러개의 그룹에 대한 히스토그램, 커널밀도곡선 그리기

(2) 여러개의 변수에 대한 히스토그램, 커널밀도곡선 그리기

에 대해서 알아보겠습니다. 



먼저, matlplotlib.pyplot, seaborn 패키지를 importing하고, 예제로 사용할 iris 데이터셋을 불러오겠습니다. 



import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

import seaborn as sns


# loading 'iris' dataset

iris = sns.load_dataset('iris')

iris.shape

(150, 5)


iris.head()

sepal_lengthsepal_widthpetal_lengthpetal_widthspecies
05.13.51.40.2setosa
14.93.01.40.2setosa
24.73.21.30.2setosa
34.63.11.50.2setosa
45.03.61.40.2setosa

 

iris.groupby('species').size()

species
setosa        50
versicolor    50
virginica     50
dtype: int64




iris는 붓꽃인데요, 아래처럼 versicolor, setosa, virginica의 3개 종(species) 그룹별로 각 50개씩 꽃잎 길이와 넓이, 꽃받침 길이와 넓이의 4개 변수를 측정한 데이터셋입니다. 


* image source: https://www.datacamp.com/community/tutorials/machine-learning-in-r



  (1) 여러개 그룹의 히스토그램, 커널밀도곡선 그리기


petal_length 변수에 대해서 setosa, versicolor, virginica 종의 3개 그룹(groups)의 히스토그램과 커널밀도곡선을 그룹별로 색깔을 다르게 하여 그려보겠습니다. 



# 1-1. Multiple histograms on the same axis

sns.distplot(iris[iris.species == "setosa"]["petal_length"], 

             color="blue", label="setosa")


sns.distplot(iris[iris.species == "versicolor"]["petal_length"], 

             color="red", label="versicolor")


sns.distplot(iris[iris.species == "virginica"]["petal_length"], 

             color="green", label="virginica")


plt.legend(title="Species")

plt.show()


 




만약 그룹 개수가 많아서 위에서처럼 일일이 코딩하기가 시간이 오래걸리고 반복되는 코드가 길게 늘어서는게 싫다면 아래처럼 for loop 을 사용해주면 됩니다. 


그래프의 제목, X축 이름, Y축 이름, 범례 이름을 설정하는 방법도 같이 소개합니다. 



# 1-2. Via for loop

grp_col_dict = {'setosa': 'blue', 

                    'versicolor': 'red', 

                    'virginica': 'green'}


# for loop of species group

for group in grp_col_dict:

    

    # subset of group

    subset = iris[iris['species'] == group]

    

    # histogram and kernel density curve

    sns.distplot(subset['petal_length'], 

                    hist = True, # histogram

                    kde = True,  # density curve

                    kde_kws = {'linewidth': 2}, 

                    color = grp_col_dict[group],

                    label = group)


# setting plot format

plt.title('Histogram & Density Plot by Groups')

plt.xlabel('Petal Length(unit:cm)')

plt.ylabel('Density')

plt.legend(prop={'size': 12}, title = 'Group')

plt.show()




  (2) 여러개 변수의 히스토그램, 커널밀도곡선 그리기


이번에는 sepal_width, sepal_length, petal_width, petal_length 의 4개 변수(variable)에 대해서 히스토그램과 커널밀도곡선을 그려보겠습니다. (단, 종(species)의 구분없이 전체 사용)


for loop 을 사용하였는데요, 위의 그룹 indexing 과 이번의 변수 indexing 부분이 다르다는 점 유심히 살펴보시기 바랍니다. 



# 2-1. Multiple histograms on the same axis

var_color_dict = {'sepal_length': 'blue', 

                      'sepal_width': 'red', 

                      'petal_length': 'yellow', 

                      'petal_width': 'green'}


# for loop

for var in var_color_dict:

    sns.distplot(iris[var],                  

                    color = var_color_dict[var], 

                    hist_kws = {'edgecolor': 'gray'}, 

                    label = var)


plt.legend(title = 'Variables')

plt.show()





위의 (2-1) 그래프는 1개의 window에 동일한 축을 사용하여 4개 변수의 히스토그램과 밀도곡선을 그리다보니 중첩이 되면서 좀 헷갈리고 보기에 어려운 점이 있습니다. 


이런 경우에 그래프를 각 변수별로 분리해서 4개의 window subplots에 하나씩 그려서 비교하는 것도 좋은 방법입니다. ax=axes[0, 0] 은 좌상, ax=axes[0, 1]은 우상, ax=axes[1, 0]은 좌하, ax=axes[1, 1]은 우하 위치의 subplot 입니다. 



# 2-2. Multiple histograms at separate windows

f, axes = plt.subplots(2, 2, figsize=(8, 6), sharex=True)

sns.distplot(iris["sepal_length"], color="blue", ax=axes[0, 0])

sns.distplot(iris["sepal_width"], color="red", ax=axes[0, 1])

sns.distplot(iris["petal_length"], color="yellow", ax=axes[1, 0])

sns.distplot(iris["petal_width"], color="green", ax=axes[1, 1])

plt.show()





for loop을 사용해서 그리려면 아래 코드를 참고하세요. 



var_color_dict = {'sepal_length': 'blue', 

                      'sepal_width': 'red', 

                      'petal_length': 'yellow', 

                      'petal_width': 'green'}


i = [0, 0, 1, 1]

j = [0, 1, 0, 1]


# for loop

f, axes = plt.subplots(2, 2, figsize=(8, 6), sharex=True)

for var, i, j in zip(var_color_dict, i, j):

    sns.distplot(iris[var],                  

                    color = var_color_dict[var],

                    ax = axes[i, j])

    

plt.show()



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요.  :-)



Posted by R Friend R_Friend

탐색적 데이터 분석 단계에서 변수의 분포, 중심 경향, 퍼짐 정도, 치우침 정도 등을 한눈에 살펴볼 수 있는 시각화 종류로 히스토그램이 많이 사용됩니다. 


이번 포스팅에서는 Python의 matplotlib.pyplot, seaborn, pandas를 이용해서 하나의 변수, 하나의 그룹에 대한 히스토그램(Histogram)을 그리는 방법을 소개하겠습니다. 


그리고 다음번 포스팅에서는 여러개의 변수, 여러개의 그룹별 히스토그램을 그리는 방법을 다루어보겠습니다. 


필요한 패키지를 import하고 데이터셋을 loading하겠습니다. 

예제로 사용할 데이터는 seaborn 패키지에 들어있는 iris 데이터세입니다. setosa, versicolor, virginica 종별로 50개씩, 총 150개의 붖꽃 관측치에 대해서 꽃받침(sepal)과 꽃입(petal)의 길이와 넓이를 측정한 자료입니다. 기계학습 공부할 때 약방의 감초처럼 분류나 군집분석 예제로 사용되곤 하는 바로 그 데이터셋입니다. 



import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

import seaborn as sns


# Data Loading

iris = sns.load_dataset('iris')

iris.shape

(150, 5)

iris.head()
sepal_lengthsepal_widthpetal_lengthpetal_widthspecies
05.13.51.40.2setosa
14.93.01.40.2setosa
24.73.21.30.2setosa
34.63.11.50.2setosa
45.03.61.40.2setosa


iris.groupby('species').size()

species
setosa        50
versicolor    50
virginica     50
dtype: int64

 




  (1) matplotlib.pyplot 으로 히스토그램 그리기


plt.hist() 함수에 X변수의 데이터와 bin의 개수를 입력해주면 됩니다. 이렇 히스토그램을 그리면 그래프 뿐만 아니라 아래처럼 2개의 array와 <a list of Patch objects>가 같이 반환됩니다. 


히스토그램을 그릴 때는 bin의 개수를 적당히(?) 설정하는 것이 매우 중요합니다. bin 개수가 너무 적으면 분포가 뭉뚱그려지며, bin 개수가 너무 많으면 이빨빠지 빗처럼 보기에 이상해집니다. 대개의 경우 bins 값을 입력하지 않은채로 default 세팅으로 해서 그래프를 그려도 제법 보기에 좋게 나오는데요, 혹시 마음에 들지 않는다면 bins=x 값을 변경해가면서 여러번 시도를 해보시기 바랍니다. 



plt.hist(iris['sepal_width'], bins=10)



히스토그램만 보고 싶을 때는 아래처럼 n, bins, patches = plt.hist() 처럼 관측치 값, bin 개수, patch 객체를 n, bins, patches 에 별도로 할당해주면 됩니다. 



n, bins, patches = plt.hist(iris['sepal_width'], bins=10)

 


n, bins, patches

(array([ 4.,  7., 22., 24., 37., 31., 10., 11.,  2.,  2.]),
 array([2.  , 2.24, 2.48, 2.72, 2.96, 3.2 , 3.44, 3.68, 3.92, 4.16, 4.4 ]),
 <a list of 10 Patch objects>)





Y축을 빈도수(frequency)가 아니라 density로 하고 싶을 때는 density=True 를 설정해주면 됩니다. 



# Y axis as density

n, bins, patches = plt.hist(iris['sepal_width'], bins=10, density=True)





히스토그램의 색깔은 facecolor = 'blue' 식으로 설정해주며, alpha 는 투명도(0~1)를 조절할 때 사용합니다. alpha 가 0에 가까워질수록 투명해집니다. 



# facecolor, alpha

n, bins, patches = plt.hist(iris['sepal_width'], bins=10, 

                            density=True, 

                            facecolor='blue'

                            alpha=0.5)




X축과 Y축 이름은 plt.xlabel(), plt.ylabel() 함수로 지정하며, 제목은 plt.title()를 사용하여 추가할 수 있습니다. X축과 Y축의 범위를 강제로 지정해주고 싶으면 plt.axis(X축 시작, X축 끝, Y축 시작, Y축 끝)의 순서대로 값을 입력해줍니다. 



# Setting X, Y label and Title, axis

n, bins, patches = plt.hist(iris['sepal_width'], 

                            bins=10, 

                            density=True, 

                            facecolor='blue', 

                            alpha=0.5)

plt.xlabel('X bins')

plt.ylabel('Density')

plt.title('Histogram of Sepal Width')

plt.axis([1.5, 4.5, 0, 1.1])

plt.show()




  (2) seaborn 패키지로 히스토그램 그리기


seaborn 패키지의 distplot() 함수로 히스토그램을 그리니 density 기준의 히스토그램에 kernel density curve가 겹쳐져서 그래프가 그려졌습니다. 디폴트 세팅으로 그렸는데 bin 개수도 적당해보이고, 분포 곡선까지 겹쳐서 그려주니 편리하고 좋네요. (density curve와 겹쳐그려야 하므로 히스토그램은 frequency가 아니라 density 기준입니다.) 



sns.distplot(iris['sepal_width'])

plt.show()

 




물론 세부 옵션 설정을 통해서 그래프를 자유자재로 그릴 수 있습니다. 옵션 이름만 보면 무슨 기능인지 짐작할 수 있으므로 부연설명은 생략하겠습니다. 


kde=True 에서 kde는 Kernel Density Estimate 를 하여 커널 밀도 함수 곡선을 그리라는 뜻입니다. 


sns.distplot()에서 반환된 axis를 사용해서 seaborn histogram의 제목(title), X축 이름(X axis label), Y축 이름(Y axis label)을 설정할 수 있습니다. (ax.set_title(), ax.set_xlabel(), ax.set_ylabel())



# Kernel Density Curve with histogram

ax = sns.distplot(iris['sepal_width'], 

                      hist=True, 

                      kde=True, 

                      bins=10, 

                      color='blue', 

                      hist_kws={'edgecolor': 'gray'}, 

                      kde_kws={'linewidth': 2})

ax.set_title('Histogram of Sepal Width')

ax.set_xlabel('Sepal Width(cm)')

ax.set_ylabel('Density')

plt.show()




Kernel Density Curve만 그리고 싶다면 sns.distplot(x, hist=False) 라고 해서 그려도 되는데요, 좀더 많은 옵션을 사용하고 싶으면 아래처럼 sns.kdeplot() 함수를 사용하면 편리합니다. 



# Kernel Density Estimate Plot

sns.kdeplot(iris['sepal_width'],  

               shade=True, 

               bw=2, 

               label="Sepal Width")

plt.legend()

plt.show()





  (3) pandas.DataFrame.hist 를 이용한 히스토그램 그리기


pandas의 DataFrame에 아래처럼 바로 hist() 함수를 사용해서 히스토그램을 그릴 수 있습니다. matplotlib.pyplot.hist() 함수를 pandas가 가져다가 히스토그램을 그려주므로 (1)번의 plt.hist() 의 결과와 동일하게 나왔습니다. (디폴트 세팅은 grid=True 여서 격자로 그리드가 쳐져 있음)



# Histogram by pandas.DataFrame.hist

iris['sepal_width'].hist(bins=10, grid=False)

plt.show()



저는 개인적으로는 seaborn 의 그래프가 제일 이뻐보이기는 한데요, 여러 책의 예제 코드로 가장 많이 눈에 띄이는 것은 matplotlib.pyplot 이네요. 간단하게 쓰기에는 pandas.DataFrame.hist 가 손이 제일 덜 가구요. 


다음번 포스팅에서는 여러개의 변수/그룹에 대한 히스토그램 그리는 방법을 소개하겠습니다. 


많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요.  :-)



Posted by R Friend R_Friend