이번 포스팅에서는 시간의 흐름에 따른 관측값의 변화, 추세를 시각화하는데 유용한 선 그래프 (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()



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


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


728x90
반응형
Posted by Rfriend
,

변수의 개수 및 데이터의 형태에 따라서 그래프, 시각화 방법이 달라지는데요,

 

지난번 포스팅에서는 한 변수의 연속형 데이터의 시각화 방법으로

 

 - 히스토그램(Histogram)
    : geom_histogram()

- 커널 밀도 곡선(Kernel Density Curve)
    : geom_density()

 - 박스 그래프(Box Plot)
    : geom_boxplot()

 - 바이올린 그래프(Violin Plot)
    : geom_violin()

 

범주형 데이터에 대한 시각화 방법으로

 

 - 막대그림(Bar Chart): geom_bar()

 - 원그림(Pie Chart): geom_bar() + coord_polar()

 - 모자이크 그림(Mosaic Chart): vcd 패키지 mosaic()

 

알아보았습니다.

 

 

이번에는 두 개 이상의 연속형 변수를 시각화하는 방법으로

 

 - 산점도 (Scatter Plot): geom_point()

 - 선 그래프(Line Plot): geom_line()

 - 시계열 그래프(Time Series Plot): geom_line()  

 

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

 

 

[ 변수 개수 및 형태에 따른 그래프 종류 ]

 

 

 

 

 

선 그래프(Line Graph)는 x축의 연속형 변수(또는 (순서나 크기가 있는 이산형 변수, ordered factor)의 변화에 따른 y축의 변화를 선으로 이어서 보여주는 그래프입니다.  x축이 시간의 순서이면 시계열 그래프(Time Series Graph) 이구요.

 

 

Base 패키지에 들어있는 airquality 데이터 프레임을 가지고 시계열 그래프를 그려보도록 하겠습니다.

airquality 데이터 프레임은 1973년 5월부터 9월달까지 뉴욕의 공기의 Ozone, Solar, Wind, Temp를 Daily 로 측정한 데이터 셋입니다.  결측값이 없는 Wind와 Temp를 가지고 시계열 그래프를 그려보겠습니다.

 

> str(airquality)
'data.frame':	153 obs. of  6 variables:
 $ Ozone  : int  41 36 12 18 NA 28 23 19 8 NA ...
 $ Solar.R: int  190 118 149 313 NA NA 299 99 19 194 ...
 $ Wind   : num  7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ...
 $ Temp   : int  67 72 74 62 56 66 65 59 61 69 ...
 $ Month  : int  5 5 5 5 5 5 5 5 5 5 ...
 $ Day    : int  1 2 3 4 5 6 7 8 9 10 ...
 
> head(airquality)
  Ozone Solar.R Wind Temp Month Day
1    41     190  7.4   67     5   1
2    36     118  8.0   72     5   2
3    12     149 12.6   74     5   3
4    18     313 11.5   62     5   4
5    NA      NA 14.3   56     5   5
6    28      NA 14.9   66     5   6

 

> # 결측값 여부 확인
> sum(is.na(airquality$Ozone))
[1] 37
> sum(is.na(airquality$Solar.R))
[1] 7
> sum(is.na(airquality$Wind))
[1] 0
> sum(is.na(airquality$Temp))
[1] 0

 

 

보기에 좋도록 Month 변수와 Day 변수를 합쳐서 Time이라는 새로운 변수를 만들어보겠습니다.

 

> # Time 변수 생성
> airquality <- transform(airquality, 
+                         Month.ch_temp = as.character(Month), 
+                         Day.ch_temp = as.character(Day))
> 
> airquality <- transform(airquality, 
+                         Month.ch = paste("0", Month.ch_temp, sep=""), 
+                         Day.ch = ifelse(Day.ch_temp == "1", "01", 
+                                  ifelse(Day.ch_temp == "2", "02", 
+                                  ifelse(Day.ch_temp == "3", "03", 
+                                  ifelse(Day.ch_temp == "4", "04", 
+                                  ifelse(Day.ch_temp == "5", "05", 
+                                  ifelse(Day.ch_temp == "6", "06", 
+                                  ifelse(Day.ch_temp == "7", "07", 
+                                  ifelse(Day.ch_temp == "8", "08", 
+                                  ifelse(Day.ch_temp == "9", "09", 
+                                                  Day))))))))))
> 
> airquality <- transform(airquality, 
+                         Time = paste(Month.ch, Day.ch, sep=""))
> 
> airquality_May <- airquality[c(1:31), c(1:6, 11)]
> 
> head(airquality_May)
  Ozone Solar.R Wind Temp Month Day Time
1    41     190  7.4   67     5   1 0501
2    36     118  8.0   72     5   2 0502
3    12     149 12.6   74     5   3 0503
4    18     313 11.5   62     5   4 0504
5    NA      NA 14.3   56     5   5 0505
6    28      NA 14.9   66     5   6 0506

 

 

 

선그래프를 그릴 때 group 지정을 안해주면 아래처럼 경고메시지가 뜨고, 선그래프가 텅 비게 나옵니다.

 

* 경고메시지: geom_path: Each group consist of only one observation. Do you need to adjust the group aesthetic?

 

> # 선그래프
> library(ggplot2)
> 
> # warning: geom_path: Each group consist of only one observation. Do you need to adjust the group aesthetic?
>
> ggplot(airquality_May, aes(x=Time, y=Wind)) + 
+   geom_line() + 
+   ggtitle("Line Graph, Wind from May.01 to May.31")
geom_path: Each group consist of only one observation. Do you need to adjust the group aesthetic?

 

 

 

 

 

이 문제를 해결하기 위해 gruop=1 을 지정해줍니다.

 

> # group=1
> ggplot(airquality_May, aes(x=Time, y=Wind, group=1)) + 
+   geom_line() + 
+   ggtitle("Time Series Graph, Wind from May.01 to May.31")

 

 

 

 

 


> ggplot(airquality_May, aes(x=Time, y=Temp, group=1)) + 
+   geom_line() + 
+   ggtitle("Time Series Graph, Temp from May.01 to May.31")

 

 

 

 

 

 

위의 두 개의 시계열 그래프를 보면 y축을 ggplot2 가 자동으로 계산해서 적정 범위를 설정해주었습니다만, 경우에 따라서는 사용자가 강제로 특정 범위를 설정해주고 싶을 때가 있습니다.  아래는 ylim()을 이용해서 0~max(y) 값 까지 y축 범위를 설정한 예시입니다.

 

> # y축 범위 설정 0~max
> ggplot(airquality_May, aes(x=Time, y=Temp, group=1)) + 
+   geom_line() + 
+   ylim(0, max(airquality_May$Temp)) +
+   ggtitle("Time Series Graph, Temp from May.01 to May.31, y axis from 0 to max")

 

 

 

 

 

 

 

선그래프의 선 모양도 바꿔보고 싶고, 점도 덮입혀 보고 싶다면 아래 예제를 참고하세요.

 

> # 점선으로 변경, 점 추가
> ggplot(airquality_May, aes(x=Time, y=Temp, group=1)) + 
+   geom_line(linetype="dotted", size=1, colour="blue") + 
+   geom_point(size=3, shape=19, colour="blue") +
+   ggtitle("Time Series Graph, Temp from May.01 to May.31, with dotted line, dot")

 

 

 

 

 

참고로 R Line Type과 Shape 은 아래와 같습니다.

 

[ R Line Type ]

 

 

 

[ R Symbol Shape ]

 

 

 

다음은 aes() 내 group과 colour 를 사용하여 그룹별로 선그래프, 시계열그래프 그리는 방법입니다. 

 

> # 집단별 시계열 그래프 : 월별(5월~9월) Temp 시계열 그래프
> ggplot(data=airquality, aes(x=Day, y=Temp, colour=Month, group=Month)) + 
+   geom_line() + 
+   geom_point(size=3) +
+   ggtitle("Time Seires Graph, Temp from May to Sep.")

 

 

 

 

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

 

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

 

728x90
반응형
Posted by Rfriend
,