<jupyter_start><jupyter_text>12 시계열 데이터시계열 데이터는 데이터 분석 분야에서 중요하게 다루는 데이터 중 하나입니다. 우리가 지금까지 다룬 날씨 관측 데이터, 에볼라 전염병으로 인한 사망자 수 관측 데이터, 빌보드 차트 데이터에는 모두 시계열 데이터가 포함되어 있었죠. 즉, 일정 시간 간격으로 어떤 값을 기록한 데이터에서는 시계열 데이터가 매우 중요합니다. 따라서 데이터를 자유자재로 다룰 줄 알아야 유능한 데이터 분석가라고 할 수 있습니다. 그러면 시계열 데이터란 무엇인지 알아볼까요? 12-1 datetime 오브젝트 12-2 사례별 시계열 데이터 계산하기 12-1 datetime 오브젝트datetime 라이브러리는 날짜와 시간을 처리하는 등의 다양한 기능을 제공하는 파이썬 라이브러리입니다. datetime 라이브러리에는 날자를 처리하는 date 오브젝트, 시간을 처리하는 time 오브젝트, 날짜와 시간을 모두 처리하는 datetime 오브젝트가 포함되어 있습니다. 앞으로 3개의 오브젝트를 명확히 구분하기 위해 영무을 그대로 살려 date, time, datetime 오브젝트라고 부르겠습니다. datetime 오브젝트 사용하기 1. datetime 오브젝트를 사용하기 위해 datetime 라이브러리를 불러옵니다.<jupyter_code>from datetime import datetime<jupyter_output><empty_output><jupyter_text>2.now, today 메서드를 사용하면 다음과 같이 현재 시간을 출력할 수 있습니다.<jupyter_code>now1 = datetime.now()
print(now1)
now2 = datetime.today()
print(now2)<jupyter_output>2021-03-31 23:18:45.503513<jupyter_text>3. 다음은 datetime 오브젝트를 생성할 때 시간을 직접 입력하여 인자로 전달한 것입니다. 각 변수를 출력하여 확인해 보면 입력한 시간을 바탕으로 datetime 오브젝트가 생성괸 것을 알 수 있습니다<jupyter_code>t1 = datetime.now()
t2 = datetime(1970, 1, 1)
t3 = datetime(1970, 12, 12, 13, 24, 34)

print(t1)
print(t2)
print(t3)<jupyter_output>2021-03-31 23:18:46.172945
1970-01-01 00:00:00
1970-12-12 13:24:34<jupyter_text>4.datetime 오브젝트를 사용하는 이유 중 하나는 시간 계산을 할 수 있다는 점입니다. 다음은 두 datetime 오브젝트의 차이를 구한 것입니다.<jupyter_code>diff1 = t1 - t2

print(diff1)
print(type(diff1))
diff2 = t2 - t1

print(diff2)
print(type(diff2))<jupyter_output>-18718 days, 0:41:13.827055
<class 'datetime.timedelta'><jupyter_text>datetime 오브젝트로 변환하기 - to_datetime 메서드경우에 따라서는 시계열 데이터를 문자열로 저장해야 할 때도 있습니다. 하지만 문자열은 시간 계산을 할 수 없기 때문에 datetime 오브젝트로 변환해 주어야 합니다. 이번에는 to_datetime 메서드를 사용하여 문자열을 datetime 오브젝트로 변환하는 방법에 대해 알아보겠습니다.  문자열을 datetime 오브젝트로 변환하기 1.먼저  ebola 데이터 집합을 불러옵니다.<jupyter_code>import pandas as pd
import os

ebola = pd.read_csv('./data/country_timeseries.csv')<jupyter_output><empty_output><jupyter_text>2.ebola 데이터프레임을 보면 문자열로 저장된 Date 열이 있는 것을 알 수 있습니다.<jupyter_code>print(ebola.info())<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 122 entries, 0 to 121
Data columns (total 18 columns):
 #   Column               Non-Null Count  Dtype  
---  ------               --------------  -----  
 0   Date                 122 non-null    object 
 1   Day                  122 non-null    int64  
 2   Cases_Guinea         93 non-null     float64
 3   Cases_Liberia        83 non-null     float64
 4   Cases_SierraLeone    87 non-null     float64
 5   Cases_Nigeria        38 non-null     float64
 6   Cases_Senegal        25 non-null     float64
 7   Cases_UnitedStates   18 non-null     float64
 8   Cases_Spain          16 non-null     float64
 9   Cases_Mali           12 non-null     float64
 10  Deaths_Guinea        92 non-null     float64
 11  Deaths_Liberia       81 non-null     float64
 12  Deaths_SierraLeone   87 non-null     float64
 13  Deaths_Nigeria       38 non-null     float64
 14  Deaths_Senegal       22 non-null     float64
 15  Deaths_UnitedStates  18 non-null     flo[...]<jupyter_text>3.to_datetime 메서드를 사용하면 Date 열의 자료형을 datetime 오브젝트로 변환할 수 있습니다. 다음과 같이 to_datetime 메서드를 사용하여 Date열의 자료형을 datetime 오브젝트로 변환한 다음 ebola 데이터프레임에 새로운 열로 추가합니다.<jupyter_code>ebola['date_dt'] = pd.to_datetime(ebola['Date'])
print(ebola.info())<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 122 entries, 0 to 121
Data columns (total 19 columns):
 #   Column               Non-Null Count  Dtype         
---  ------               --------------  -----         
 0   Date                 122 non-null    object        
 1   Day                  122 non-null    int64         
 2   Cases_Guinea         93 non-null     float64       
 3   Cases_Liberia        83 non-null     float64       
 4   Cases_SierraLeone    87 non-null     float64       
 5   Cases_Nigeria        38 non-null     float64       
 6   Cases_Senegal        25 non-null     float64       
 7   Cases_UnitedStates   18 non-null     float64       
 8   Cases_Spain          16 non-null     float64       
 9   Cases_Mali           12 non-null     float64       
 10  Deaths_Guinea        92 non-null     float64       
 11  Deaths_Liberia       81 non-null     float64       
 12  Deaths_SierraLeone   87 non-null     float64       
 13  Deaths_Nigeria       38 non-null   [...]<jupyter_text>4.to_datetime 메서드를 좀 더 자세히 알아볼까요? 시간 형식 지정자(%d, %m, %y)와 기호(|,-)를 적절히 조합하여 format 인자에 전달하면 그 형식에 맞게 정리된 datetime 오브젝트를 얻을 수 있습니다. 다음 실습을 참고하여 format 인자의 사용법을 꼭 익혀두세요.<jupyter_code>test_df1 = pd.DataFrame({'order_day':['01/01/15', '02/01/15', '03/01/15']})

test_df1['date_dt1'] = pd.to_datetime(test_df1['order_day'], format = '%d/%m/%y')
test_df1['date_dt2'] = pd.to_datetime(test_df1['order_day'], format = '%m/%d/%y')
test_df1['date_dt3'] = pd.to_datetime(test_df1['order_day'], format = '%y/%m/%d')

print(test_df1)
test_df2 = pd.DataFrame({'order_day':['01-01-15', '02-01-15', '03-01-15']})
test_df2['date_dt'] = pd.to_datetime(test_df2['order_day'], format='%d-%m-%y')
                                      
print(test_df2)<jupyter_output>order_day    date_dt
0  01-01-15 2015-01-01
1  02-01-15 2015-01-02
2  03-01-15 2015-01-03<jupyter_text>시간 형식 지정자다음은 시간 형식 지정자를 정리한 표입니다. 이 장의 실습에서 종종 사용하므로 한 번 읽고 넘어가기 바랍니다.- %a : 요일출력- %A : 요일출력(긴 이름)- %w : 요일 출력(숫자, 0부터 일요일)- %d : 날짜 출력 (2자리표시)- %b : 월 출력- %B : 월 출력 (긴 이름)- %m : 월 출력 (숫자)- %y : 년 출력(2자리로 표시)- %Y : 년 출력(4자리로 표시)- %H : 시간출력(24시간)- %l : 시간출력(12시간)- %p : AM 또는 PM 출력- %M : 분 출력(2자리로 표시)- %S : 초 출력(2자리로 표시)- %f : 마이크로초 출력- %z : UTC 차이 출력- %Z : 기준 지역 이름 출력- %j : 올해의 지난 일 수 출력- %U : 올해의 지난 주 수 출력- %c : 날짜와 시간 출력- %x : 날자 출력- %X : 시간 출력- %G : 년 출력- %u : 요일 출력- %V : 올해의 지난 주 수 출력(ISO 8601 형식)  datetime 오브젝트로 변환하기 - read_csv 메서드앞에서는 to_datetime 메서드를 사용하여 문자열로 저장되어 있는 Date 열을 datetime 오브젝트로 변환했습니다. 하지만 datetime 오브젝트로 변환하려는 열을 지정하여 데이터 집합을 불러오는 것이 더 간단합니다. 다음 실습을 통해 알아보겠습니다. datetime 오브젝트로 변환하려는 열을 지정하여 데이터 집합 불러오기 1.다음은 read_csv 메서드의 parse_dates 인자에 datetime 오브젝트로 변환하고자 하는 열의 이름을 전달하여 데이터 집합을 불러온 것입니다. 결과를 보면 Date 열이 문자열이 아니라 datetime 오브젝트라는 것을 확인할 수 있습니다.<jupyter_code>ebola1 = pd.read_csv('./data/country_timeseries.csv', parse_dates = ['Date'])
                     
print(ebola1.info())<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 122 entries, 0 to 121
Data columns (total 18 columns):
 #   Column               Non-Null Count  Dtype         
---  ------               --------------  -----         
 0   Date                 122 non-null    datetime64[ns]
 1   Day                  122 non-null    int64         
 2   Cases_Guinea         93 non-null     float64       
 3   Cases_Liberia        83 non-null     float64       
 4   Cases_SierraLeone    87 non-null     float64       
 5   Cases_Nigeria        38 non-null     float64       
 6   Cases_Senegal        25 non-null     float64       
 7   Cases_UnitedStates   18 non-null     float64       
 8   Cases_Spain          16 non-null     float64       
 9   Cases_Mali           12 non-null     float64       
 10  Deaths_Guinea        92 non-null     float64       
 11  Deaths_Liberia       81 non-null     float64       
 12  Deaths_SierraLeone   87 non-null     float64       
 13  Deaths_Nigeria       38 non-null   [...]<jupyter_text>datetime 오브젝트에서 날짜 정보 추출하기datetime 오브젝트에는 년,월,일과 같은 날짜 정보를 따로 저장하고 있는 속성이 이미 준비되어 있습니다. 다음 실습을 통해 datetime 오브젝트에서 날짜 정보를 하나씩 추출해 보겠습니다.  datetime 오브젝트에서 날짜 정보 추출하기 1. 다음은 문자열로 저장된 날짜를 시리즈에 담아 datetime 오브젝트로 변환한 것입니다.<jupyter_code>date_series = pd.Series(['2018-05-16', '2018-05-17', '2018-05-18'])
d1 = pd.to_datetime(date_series)
print(d1)<jupyter_output>0   2018-05-16
1   2018-05-17
2   2018-05-18
dtype: datetime64[ns]<jupyter_text>2.datetime 오브젝트(d1)의 year,month,day 속성을 이용하면 년,월,일 정보를 바로 추출할 수 있습니다.<jupyter_code>print(d1[0].year)
print(d1[0].month)
print(d1[0].day)<jupyter_output>16<jupyter_text>dt 접근자 사용하기문자열을 처리하려면 str 접근자를 사용한 다음 문자열 속성이나 메서드를 사용해야 했습니다. datetime 오브젝트도 마찬가지로 dt 접근자를 사용하면 datetime 속성이나 메서드를 사용하여 시계열 데이터를 처리할 수 있습니다. dt 접근자로 시계열 데이터 정리하기 1. 먼저 ebola 데이터 집합을 불러온 다음 Date 열을 datetime 오브젝트로 변환하여 새로운 열 (date_dt)로 추가합니다.<jupyter_code>ebola = pd.read_csv('./data/country_timeseries.csv')
ebola['date_dt'] = pd.to_datetime(ebola['Date'])<jupyter_output><empty_output><jupyter_text>2.다음은 dt 접근자를 사용하지 않고 인덱스가 3인 데이터의 년,월,일 데이터를 추출한 것입니다.<jupyter_code>print(ebola[['Date', 'date_dt']].head())
print(ebola['date_dt'][3].year)
print(ebola['date_dt'][3].month)
print(ebola['date_dt'][3].day)<jupyter_output>2<jupyter_text>3.과정 2와 같은 방법은 date_dt 열의 특정 데이터를 인덱스로 접근해야 하기 때문에 불편합니다. 다음은 dt 접근자로 date_dt 열에 한번에 접근한 다음 year 속성을 이용하여 연도값을 추출한 것입니다. 추출한 연도값은 ebola 데이터프레임의 새로운 열 (year)로 추가 했습니다.<jupyter_code>ebola['year'] = ebola['date_dt'].dt.year

print(ebola[['Date', 'date_dt', 'year']].head())<jupyter_output>Date    date_dt  year
0    1/5/2015 2015-01-05  2015
1    1/4/2015 2015-01-04  2015
2    1/3/2015 2015-01-03  2015
3    1/2/2015 2015-01-02  2015
4  12/31/2014 2014-12-31  2014<jupyter_text>4.다음은 과정 3을 응용하여 월,일 데이터를 한 번에 추출해서 새로운 열(month, day)로 추가한 것입니다.<jupyter_code>ebola['month'], ebola['day'] = (ebola['date_dt'].dt.month, ebola['date_dt'].dt.day)

print(ebola[['Date', 'date_dt', 'year', 'month', 'day']].head())<jupyter_output>Date    date_dt  year  month  day
0    1/5/2015 2015-01-05  2015      1    5
1    1/4/2015 2015-01-04  2015      1    4
2    1/3/2015 2015-01-03  2015      1    3
3    1/2/2015 2015-01-02  2015      1    2
4  12/31/2014 2014-12-31  2014     12   31<jupyter_text>5.ebola 데이터프레임에 새로 추가한 date_dt, year, month, day 열의 자료형을 출력한 것입니다. date_dt 열은 datetime 오브젝트이고 나머지는 정수형이라는 것을 알 수 있습니다.<jupyter_code>print(ebola.info())<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 122 entries, 0 to 121
Data columns (total 22 columns):
 #   Column               Non-Null Count  Dtype         
---  ------               --------------  -----         
 0   Date                 122 non-null    object        
 1   Day                  122 non-null    int64         
 2   Cases_Guinea         93 non-null     float64       
 3   Cases_Liberia        83 non-null     float64       
 4   Cases_SierraLeone    87 non-null     float64       
 5   Cases_Nigeria        38 non-null     float64       
 6   Cases_Senegal        25 non-null     float64       
 7   Cases_UnitedStates   18 non-null     float64       
 8   Cases_Spain          16 non-null     float64       
 9   Cases_Mali           12 non-null     float64       
 10  Deaths_Guinea        92 non-null     float64       
 11  Deaths_Liberia       81 non-null     float64       
 12  Deaths_SierraLeone   87 non-null     float64       
 13  Deaths_Nigeria       38 non-null   [...]<jupyter_text>12-2 사례별 시계열 데이터 계산하기 에볼라 최초 발병일 계산하기 1.ebola 데이터프레임의 마지막 행과 열을 5개씩만 살펴보겠습니다. ebola 데이터프레임은 데이터가 시간 역순으로 정렬되어 있습니다. 즉, 시간 순으로 데이터를 살펴보려면 데이터프레임의 마지막부터 살펴봐야 합니다.<jupyter_code>print(ebola.iloc[-5:,:5])<jupyter_output>Date  Day  Cases_Guinea  Cases_Liberia  Cases_SierraLeone
117  3/27/2014    5         103.0            8.0                6.0
118  3/26/2014    4          86.0            NaN                NaN
119  3/25/2014    3          86.0            NaN                NaN
120  3/24/2014    2          86.0            NaN                NaN
121  3/22/2014    0          49.0            NaN                NaN<jupyter_text>2.121행에서 볼 수 있듯이 에볼라가 발행하기 시작한 날은 2014년 3월 22일 입니다. 다으은 min 메서드를 사용하여 에볼라의 최초 발병일을 찾은 것입니다.<jupyter_code>print(ebola['date_dt'].min())
print(type(ebola['date_dt'].min()))<jupyter_output>2014-03-22 00:00:00
<class 'pandas._libs.tslibs.timestamps.Timestamp'><jupyter_text>3.에볼라의 최초 발병일을 알아냈으니 Date 열에서 에볼라의 최초 발병일을 빼면 에볼라의 진행 정도를 알 수 있습니다.<jupyter_code>ebola['outbreak_d'] = ebola['date_dt'] - ebola['date_dt'].min()

print(ebola[['Date', 'Day', 'outbreak_d']].head())<jupyter_output>Date  Day outbreak_d
0    1/5/2015  289   289 days
1    1/4/2015  288   288 days
2    1/3/2015  287   287 days
3    1/2/2015  286   286 days
4  12/31/2014  284   284 days<jupyter_text>파산한 은행의 개수 계산하기 1.다음은 파산한 은행 데이터 집합을 불러온 것입니다. banks 데이터프레임의 앞부분울 살펴보면 Closing Date, Updated Date 열의 데이터 자료형이 시계열 데이터라는 것을 알 수 있습니다.<jupyter_code>banks = pd.read_csv('./data/banklist.csv')
print(banks.head())<jupyter_output>Bank Name         City  ST   CERT  \
0                Washington Federal Bank for Savings      Chicago  IL  30570   
1    The Farmers and Merchants State Bank of Argonia      Argonia  KS  17719   
2                                Fayette County Bank   Saint Elmo  IL   1802   
3  Guaranty Bank, (d/b/a BestBank in Georgia & Mi...    Milwaukee  WI  30003   
4                                     First NBC Bank  New Orleans  LA  58302   

                 Acquiring Institution Closing Date Updated Date  
0                   Royal Savings Bank    15-Dec-17    20-Dec-17  
1                          Conway Bank    13-Oct-17    20-Oct-17  
2            United Fidelity Bank, fsb    26-May-17    26-Jul-17  
3  First-Citizens Bank & Trust Company     5-May-17    26-Jul-17  
4                         Whitney Bank    28-Apr-17     5-Dec-17<jupyter_text>2.Closing Date, Updated Date 열의 데이터 자료형은 문자열입니다. 다음은 read_csv 메서드의 parse_dates 속성을 이용하여 문자열로 저장된 두 열을 datetime 오브젝트로 변환하여 불러온 것입니다.<jupyter_code>banks_no_dates = pd.read_csv('./data/banklist.csv')
print(banks_no_dates.info())
banks = pd.read_csv('./data/banklist.csv', parse_dates=[5,6])
print(banks.info())<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 555 entries, 0 to 554
Data columns (total 7 columns):
 #   Column                 Non-Null Count  Dtype         
---  ------                 --------------  -----         
 0   Bank Name              555 non-null    object        
 1   City                   555 non-null    object        
 2   ST                     555 non-null    object        
 3   CERT                   555 non-null    int64         
 4   Acquiring Institution  555 non-null    object        
 5   Closing Date           555 non-null    datetime64[ns]
 6   Updated Date           555 non-null    datetime64[ns]
dtypes: datetime64[ns](2), int64(1), object(4)
memory usage: 30.5+ KB
None<jupyter_text>3.dt접근자와 quarter 속성을 이용하면 은행이 파산한 분기를 알 수 있습니다. 다음은 dt접근자와 year,quarter 속성을 이용하여 은행이 파산한 연도, 분기를 새로운 열로 추가한 것입니다.<jupyter_code>banks['closing_quarter'], banks['closing_year'] = (banks['Closing Date'].dt.quarter, banks['Closing Date'].dt.year)

print(banks.head())<jupyter_output>Bank Name         City  ST   CERT  \
0                Washington Federal Bank for Savings      Chicago  IL  30570   
1    The Farmers and Merchants State Bank of Argonia      Argonia  KS  17719   
2                                Fayette County Bank   Saint Elmo  IL   1802   
3  Guaranty Bank, (d/b/a BestBank in Georgia & Mi...    Milwaukee  WI  30003   
4                                     First NBC Bank  New Orleans  LA  58302   

                 Acquiring Institution Closing Date Updated Date  \
0                   Royal Savings Bank   2017-12-15   2017-12-20   
1                          Conway Bank   2017-10-13   2017-10-20   
2            United Fidelity Bank, fsb   2017-05-26   2017-07-26   
3  First-Citizens Bank & Trust Company   2017-05-05   2017-07-26   
4                         Whitney Bank   2017-04-28   2017-12-05   

   closing_quarter  closing_year  
0                4          2017  
1                4          2017  
2    [...]<jupyter_text>4.이제 연도별로 파산한 은행이 얼마나 되는지 알아볼까요? grouby 메서드를 사용하면 연도별로 파산한 은행의 개수를 구할 수 있습니다.<jupyter_code>closing_year = banks.groupby(['closing_year']).size()
print(closing_year)<jupyter_output>closing_year
2000      2
2001      4
2002     11
2003      3
2004      4
2007      3
2008     25
2009    140
2010    157
2011     92
2012     51
2013     24
2014     18
2015      8
2016      5
2017      8
dtype: int64<jupyter_text>5.각 연도별, 분기별로 파산한 은행의 개수도 알아보겠습니다. 다음은 banks 데이터프레임을 연도별로 그룹화한 다음 다시 분기별로 그룹화하여 출력한 것입니다.<jupyter_code>closing_year_q = banks.groupby(['closing_year', 'closing_quarter']).size()

print(closing_year_q)<jupyter_output>closing_year  closing_quarter
2000          4                   2
2001          1                   1
              2                   1
              3                   2
2002          1                   6
              2                   2
              3                   1
              4                   2
2003          1                   1
              2                   1
              4                   1
2004          1                   3
              2                   1
2007          1                   1
              3                   1
              4                   1
2008          1                   2
              2                   2
              3                   9
              4                  12
2009          1                  21
              2                  24
              3                  50
              4                  45
2010          1                  41
              2                  45
              3                  4[...]<jupyter_text>6.다음은 과정5에서 얻은 값으로 그래프를 그린 것입니다.<jupyter_code>import matplotlib.pyplot as plt

fig, ax = plt.subplots()

ax = closing_year.plot()

plt.show()

fig, ax = plt.subplots()
ax = closing_year_q.plot()
plt.show()<jupyter_output><empty_output><jupyter_text>테슬라 주식 데이터로 시간 계산하기이번에는 pandas-datareader 라이브러리를 이용하여 주식 데이터를 불러오겠습니다. 이 라이브러리는 지금까지 설치한 적이 없는 라이브러리입니다. 다음을 아나콘다 프롬프트에 입력하여 pandas-datareader 라이브러리를 설치하세요.<jupyter_code>!pip install pandas-datareader<jupyter_output>Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: pandas-datareader in /home/goldang/.local/lib/python3.6/site-packages (0.9.0)
Requirement already satisfied: requests>=2.19.0 in /home/goldang/.local/lib/python3.6/site-packages (from pandas-datareader) (2.25.1)
Requirement already satisfied: lxml in /home/goldang/.local/lib/python3.6/site-packages (from pandas-datareader) (4.6.3)
Requirement already satisfied: pandas>=0.23 in /home/goldang/.local/lib/python3.6/site-packages (from pandas-datareader) (1.1.5)
Requirement already satisfied: numpy>=1.15.4 in /home/goldang/.local/lib/python3.6/site-packages (from pandas>=0.23->pandas-datareader) (1.19.5)
Requirement already satisfied: pytz>=2017.2 in /home/goldang/.local/lib/python3.6/site-packages (from pandas>=0.23->pandas-datareader) (2021.1)
Requirement already satisfied: python-dateutil>=2.7.3 in /home/goldang/.local/lib/python3.6/site-packages (from pandas>=0.23->pandas-datarea[...]<jupyter_text>1. 다음은 get_data_quanal 메서드에 TSLA라는 문자열을 전달하여 테슬라의 주식 데이터를 내려받은 다음 to_csv 메서드를 사용하여 data 폴더 안에 'tesla_stock_quandl.csv'라는 이름으로 저장한 것입니다.<jupyter_code>pd.core.common.is_list_like = pd.api.types.is_list_like
import pandas_datareader as pdr

tesla = pdr.get_data_quandl('TSLA', api_key = '<KEY>')

tesla.to_csv('./data/tesla_stock_quandl.csv')<jupyter_output><empty_output><jupyter_text>2.tesla 데이터프레임의 Date 열은 문자열로 저장되어 있습니다. 즉, datetime 오브젝트로 자료형을 변환해야 시간 계산을 할 수 있습니다.<jupyter_code>print(tesla.head())<jupyter_output>Open    High     Low   Close      Volume  ExDividend  \
Date                                                                 
2018-03-27  304.00  304.27  277.18  279.18  13696168.0         0.0   
2018-03-26  307.34  307.59  291.36  304.18   8324639.0         0.0   
2018-03-23  311.25  311.61  300.45  301.54   6600538.0         0.0   
2018-03-22  313.89  318.82  308.18  309.10   4914307.0         0.0   
2018-03-21  310.25  322.44  310.19  316.53   5927881.0         0.0   

            SplitRatio  AdjOpen  AdjHigh  AdjLow  AdjClose   AdjVolume  
Date                                                                    
2018-03-27         1.0   304.00   304.27  277.18    279.18  13696168.0  
2018-03-26         1.0   307.34   307.59  291.36    304.18   8324639.0  
2018-03-23         1.0   311.25   311.61  300.45    301.54   6600538.0  
2018-03-22         1.0   313.89   318.82  308.18    309.10   4914307.0  
2018-03-21         1.0   310.25   322.44  310.19    316.53   5927881.0 [...]<jupyter_text>3.Date 열을 Datetime 형으로 변환하려면 read_csv 메서드로 데이터 집합(tesla_stock_quandl.csv)을 불러올 때 parse_dates 인자에 Date 열을 전달하면 됩니다.<jupyter_code>tesla = pd.read_csv('./data/tesla_stock_quandl.csv', parse_dates=[0])
print(tesla.info())<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 500 entries, 0 to 499
Data columns (total 13 columns):
 #   Column      Non-Null Count  Dtype         
---  ------      --------------  -----         
 0   Date        500 non-null    datetime64[ns]
 1   Open        500 non-null    float64       
 2   High        500 non-null    float64       
 3   Low         500 non-null    float64       
 4   Close       500 non-null    float64       
 5   Volume      500 non-null    float64       
 6   ExDividend  500 non-null    float64       
 7   SplitRatio  500 non-null    float64       
 8   AdjOpen     500 non-null    float64       
 9   AdjHigh     500 non-null    float64       
 10  AdjLow      500 non-null    float64       
 11  AdjClose    500 non-null    float64       
 12  AdjVolume   500 non-null    float64       
dtypes: datetime64[ns](1), float64(12)
memory usage: 50.9 KB
None<jupyter_text>4.Date 열의 자료형이 datetime 오브젝트로 변환되었습니다. 이제 dt 접근자를 사용할 수 있습니다. 다음은 불린 추출로 2010년 6월의 데이터만 추출한 것입니다.<jupyter_code>print(tesla.loc[(tesla.Date.dt.year == 2010) & (tesla.Date.dt.month == 6)])<jupyter_output>Empty DataFrame
Columns: [Date, Open, High, Low, Close, Volume, ExDividend, SplitRatio, AdjOpen, AdjHigh, AdjLow, AdjClose, AdjVolume]
Index: []<jupyter_text>datetime 오브젝트와 인덱스 - datetimelndexdatetime 오브젝트를 데이터프레임의 인덱스로 설정하면 원하는 시간의 데이터를 바로 추출할 수 있어 편리합니다. 이번에는 datetime 오브젝트를 인덱스로 지정하는 방법에 대해 알아보겠습니다. datetime 오브젝트를 인덱스로 설정해 데이터 추출하기 1.계속해서 테슬라 주식 데이터를 사용하여 실습을 진행하겠습니다. 다음은 Date 열을 tesla 데이터프레임의 인덱스로 지정한 것입니다.<jupyter_code>tesla.index = tesla['Date']
print(tesla.index)<jupyter_output>DatetimeIndex(['2018-03-27', '2018-03-26', '2018-03-23', '2018-03-22',
               '2018-03-21', '2018-03-20', '2018-03-19', '2018-03-16',
               '2018-03-15', '2018-03-14',
               ...
               '2016-04-14', '2016-04-13', '2016-04-12', '2016-04-11',
               '2016-04-08', '2016-04-07', '2016-04-06', '2016-04-05',
               '2016-04-04', '2016-04-01'],
              dtype='datetime64[ns]', name='Date', length=500, freq=None)<jupyter_text>2. datetime 오브젝트를 인덱스로 지정하면 다음과 같은 방법으로 원하는 시간의 데이터를 바로 추출할 수 있습니다. 다음은 2015년의 데이터를 추출한 것입니다.<jupyter_code>print(tesla['2015'].iloc[:5, :5])<jupyter_output>Empty DataFrame
Columns: [Date, Open, High, Low, Close]
Index: []<jupyter_text>3.다음은 2010년 6월의 데이터를 추출한 것입니다.<jupyter_code>print(tesla['2010-06'].iloc[:, :5])<jupyter_output>Empty DataFrame
Columns: [Date, Open, High, Low, Close]
Index: []<jupyter_text>시간 간격과 인덱스 - Timedeltalndex예를 들어 주식 데이터에서 최초 5일간 수집된 데이터만 살펴보고 싶다면 어떻게 해야 할까요? 이런 경우에는 시간 간격을 인덱스로 지정하여 데이터를 추출하면 됩니다. 이번에는 datetime 오브젝트를 인덱스로 지정하는 것이 아니라 시간 간격을 인덱스로 지정하여 진행하겠습니다. 시간 간격을 인덱스로 지정해 데이터 추출하기 1.Date 열에서 Date 열의 최솟값(2010-06-29)을 빼면 데이터를 수집한 이후에 시간이 얼마나 흘렀는지 알 수 있습니다. 다음은 Date 열에서 Date 열의 최솟값을 뺀 다음 ref_date열로 추하한 것입니다.<jupyter_code>tesla['ref_date'] = tesla['Date'] - tesla['Date'].min()
print(tesla.head())<jupyter_output>Date    Open    High     Low   Close      Volume  ExDividend  \
Date                                                                            
2018-03-27 2018-03-27  304.00  304.27  277.18  279.18  13696168.0         0.0   
2018-03-26 2018-03-26  307.34  307.59  291.36  304.18   8324639.0         0.0   
2018-03-23 2018-03-23  311.25  311.61  300.45  301.54   6600538.0         0.0   
2018-03-22 2018-03-22  313.89  318.82  308.18  309.10   4914307.0         0.0   
2018-03-21 2018-03-21  310.25  322.44  310.19  316.53   5927881.0         0.0   

            SplitRatio  AdjOpen  AdjHigh  AdjLow  AdjClose   AdjVolume  \
Date                                                                     
2018-03-27         1.0   304.00   304.27  277.18    279.18  13696168.0   
2018-03-26         1.0   307.34   307.59  291.36    304.18   8324639.0   
2018-03-23         1.0   311.25   311.61  300.45    301.54   6600538.0   
2018-03-22         1.0   313.89   318.82  308.18    309.10   4[...]<jupyter_text>2.다음과 같이 ref_date 열을 인덱스로 지정했습니다. 이제 시간 간격(ref_date)을 이용하여 데이터를 추출할 수 있습니다.<jupyter_code>tesla.index = tesla['ref_date']
print(tesla.iloc[:5, :5])<jupyter_output>Date    Open    High     Low   Close
ref_date                                           
725 days 2018-03-27  304.00  304.27  277.18  279.18
724 days 2018-03-26  307.34  307.59  291.36  304.18
721 days 2018-03-23  311.25  311.61  300.45  301.54
720 days 2018-03-22  313.89  318.82  308.18  309.10
719 days 2018-03-21  310.25  322.44  310.19  316.53<jupyter_text>3.다음은 데이터를 수집한 이후 최초 5일의 데이터를 추출한 것입니다.<jupyter_code>print(tesla['5day':].iloc[:5, :5])<jupyter_output>Date     Open    High     Low   Close
ref_date                                            
5 days   2016-04-06  253.970  267.74  253.45  265.42
4 days   2016-04-05  240.500  256.56  240.00  255.47
3 days   2016-04-04  249.120  252.12  243.64  246.99
0 days   2016-04-01  244.825  247.90  233.25  237.59<jupyter_text>시간 범위와 인덱스앞에서 사용한 주식 데이터는 특정 일에 누락된 데이터가 없었습니다. 하지만 가끔은 데이터를 수집하지 못한 날도 있을 수 있겠죠. 만약 특정 일에 누락된 데이터도 포함시켜 데이터를 살펴보려면 어떻게 해야 할까요? 이런 경우에는 임의로 시간 범위를 생성하여 인덱스로 지정해야 합니다. 시간 범위 생성해 인덱스로 지정하기 1.테슬라 주식 데이터는 특정 일에 누락된 데이터가 없습니다. 그래서 이번에는 에볼라 데이터 집합을 사용하겠습니다. 가장 앞쪽의 데이터를 살펴보면 2015년 01월 01일의 데이터가 누락된 것을 알 수 있습니다.<jupyter_code>ebola = pd.read_csv('./data/country_timeseries.csv', parse_dates=[0])
print(ebola.iloc[:5, :5])<jupyter_output>Date  Day  Cases_Guinea  Cases_Liberia  Cases_SierraLeone
0 2015-01-05  289        2776.0            NaN            10030.0
1 2015-01-04  288        2775.0            NaN             9780.0
2 2015-01-03  287        2769.0         8166.0             9722.0
3 2015-01-02  286           NaN         8157.0                NaN
4 2014-12-31  284        2730.0         8115.0             9633.0<jupyter_text>2.뒤쪽의 데이터도 마찬가지입니다. 2014년 03월 23일의 데이터가 누락되었습니다.<jupyter_code>print(ebola.iloc[-5:, :5])<jupyter_output>Date  Day  Cases_Guinea  Cases_Liberia  Cases_SierraLeone
117 2014-03-27    5         103.0            8.0                6.0
118 2014-03-26    4          86.0            NaN                NaN
119 2014-03-25    3          86.0            NaN                NaN
120 2014-03-24    2          86.0            NaN                NaN
121 2014-03-22    0          49.0            NaN                NaN<jupyter_text>3.다음은 date_range 메서드를 사용하여 2014년 12월 31일부터 2015년 01월 05일 사이의 시간 인덱스(DatetimeIndex)를 생성한 것입니다.<jupyter_code>head_range = pd.date_range(start='2014-12-31', end='2015-01-05')
print(head_range)<jupyter_output>DatetimeIndex(['2014-12-31', '2015-01-01', '2015-01-02', '2015-01-03',
               '2015-01-04', '2015-01-05'],
              dtype='datetime64[ns]', freq='D')<jupyter_text>4.다음은 원본 데이터를 손상시키는 것을 방지하기 위해 ebola 데이터프레임의 앞쪽 5개의 데이터를 추출하여 새로운 데이터프레임을 만든 것입니다. 이때 Date 열을 인덱스로 먼저 지정하지 않으면 오류가 발생합니다. 반드시 Date 열을 인덱스로 지정한 다음 과정3에서 생성한 시간 범위를 인덱스로 지정해야 합니다.<jupyter_code>ebola_5 = ebola.head()
ebola_5.index = ebola_5['Date']
ebola_5.reindex(head_range)
print(ebola_5.iloc[:5, :5])<jupyter_output>Date  Day  Cases_Guinea  Cases_Liberia  Cases_SierraLeone
Date                                                                      
2015-01-05 2015-01-05  289        2776.0            NaN            10030.0
2015-01-04 2015-01-04  288        2775.0            NaN             9780.0
2015-01-03 2015-01-03  287        2769.0         8166.0             9722.0
2015-01-02 2015-01-02  286           NaN         8157.0                NaN
2014-12-31 2014-12-31  284        2730.0         8115.0             9633.0<jupyter_text>시간 범위의 주기 설정하기시간 범위를 인덱스로 지정하면 DatetimeIndex 자료형이 만들어집니다. 그리고 DatetimeIndex에는 freq 속성이 포함되어 있죠. freq 속상값을 지정하면 시간 간격을 조절하여 DatetimeIndex를 만들 수 있습니다. 아래에 freq 속성값으로 사용할 수 있는 시간 주기를 표로 정리했습니다. freq 속성값으로 사용할 수 있는 시간 주기- B : 평일만 포함- C : 사용자가 정의한 평일만 포함- D : 달력 일자 단위- W : 주간 단위- M : 월 마지막 날만 포함- SM : 15일과 월 마지막 날만 포함- BM : M주기의 값이 휴일이면 제외하고 평일만 포함- CBM : BM에 사용자 정의 평일을 적용- MS : 월 시작일만 포함- SMS : 월 시작일과 15일만 포함- BMS : MS 주기의 값이 휴일이면 제외하고 평일만 포함- CBMS : BMS에 사용자 정의 평일을 적용- Q : 3,6,9,12월 마지막 날만 포함- BQ : 3,6,9,12월 분기 마지막 나이 휴일이면 제외하고 평일만 포함-  BQS : 3,6,9,12월 분기 시작일이 휴일이면 제외하고 평일만 포함-  A : 년의 마지막 날만 포함- BA : 년의 마지막 날이 휴일이면 제외하고 평일만 포함-  AS : 년의 시작일만 포함- BAS : 년의 시작일이 휴일이면 제외하고 평일만 포함- BH : 평일을 시간 단위로 포함 (09:00 ~ 16:00)- H : 시간 단위로 포함 (00:00~00:00)- T : 분 단위 포함-  S : 초 단위 포함- L : 밀리초 단위 포함- U : 마이크로초 단위 포함- N : 나노초 단위 포함다음은 date_range 메서드의 greq 인잣값을 B로 설정하여 평일만 포함시킨 DatetimeIndex를 만든 것입니다.<jupyter_code>print(pd.date_range('2017-01-01', '2017-01-07', freq='B'))<jupyter_output>DatetimeIndex(['2017-01-02', '2017-01-03', '2017-01-04', '2017-01-05',
               '2017-01-06'],
              dtype='datetime64[ns]', freq='B')<jupyter_text>시간 범위 수정하고 데이터 밀어내기 - shift 메서드만약 나라별로 에볼라의 확산 속도를 비교하려면 발생하기 시작한 날짜를 옮기는 것이 좋습니다. 왜 그럴까요? 일단 ebola 데이터프레임으로 그래프를 그려보고 에볼라의 확산 속도를 비교하는 데 어떤 문제가 있는지 그리고 해결 방법응 무엇인지 알아보겠습니다. 에볼라의 확산 속도 비교하기 1.다음은 ebola 데이터프레임의 Date 열을 인덱스로 지정한 다음 x축을 Date 열로, y축을 사망자 수로 지정하여 그린 그래프입니다.<jupyter_code>import matplotlib.pyplot as plt

ebola.index = ebola['Date']

fig, ax = plt.subplots( )
ax = ebola.iloc[0:, 1:].plot(ax=ax)
ax.legend(fontsize=7, loc=2, borderaxespad=0.)
plt.show()<jupyter_output><empty_output><jupyter_text>2.그런데 과정 1의 그래프는 각 나라의 에볼라 발병일이 달라 그래프가 그려지기 시작한 지점도 다릅니다. 달리기 속도를 비교하려면 같은 출발선에서 출발하여 시간을 측정해야겠죠? 에볼라의 확산 속도도 같은 방법으로 측정해야 합니다. 즉, 각 나라의 발병일을 가장 처음 에볼라가 발병한 Guinea와 동일한 위치로 옮겨야 나라별 에볼라의 확산 속도를 제대로 비교할 수 있습니다.<jupyter_code>ebola_sub = ebola[['Day', 'Cases_Guinea', 'Cases_Liberia']]
print(ebola_sub.tail(10))<jupyter_output>Day  Cases_Guinea  Cases_Liberia
Date                                        
2014-04-04   13         143.0           18.0
2014-04-01   10         127.0            8.0
2014-03-31    9         122.0            8.0
2014-03-29    7         112.0            7.0
2014-03-28    6         112.0            3.0
2014-03-27    5         103.0            8.0
2014-03-26    4          86.0            NaN
2014-03-25    3          86.0            NaN
2014-03-24    2          86.0            NaN
2014-03-22    0          49.0            NaN<jupyter_text>. 그래프를 그리기 위한 데이터프레임 준비하기다음은 Date 열의 자료형을 datetime 오브젝트로 변환하여 ebola 데이터프레임을 다시 생성한 것입니다. 그런데 중간에 아예 날짜가 없는 데이터(2015년 01월 01일)도 있습니다. 이 데이터도 포함시켜야 확산 속도를 제대로 비교할 수 있습니다.<jupyter_code>ebola = pd.read_csv('./data/country_timeseries.csv', parse_dates= ['Date'])

print(ebola.head().iloc[:, :5])
print(ebola.tail().iloc[:, :5])<jupyter_output>Date  Day  Cases_Guinea  Cases_Liberia  Cases_SierraLeone
117 2014-03-27    5         103.0            8.0                6.0
118 2014-03-26    4          86.0            NaN                NaN
119 2014-03-25    3          86.0            NaN                NaN
120 2014-03-24    2          86.0            NaN                NaN
121 2014-03-22    0          49.0            NaN                NaN<jupyter_text>4.다음은 Date 열을 인덱스로 지정한 다음 ebola 데이터프레임의 Date 열의 최댓값과 최솟값으로 시간 범위를 생성하여 new_idx에 저장한 것입니다.이렇게 하면 날자가 아예 없었던 데이터의 인덱스를 생성할 수 있습니다.<jupyter_code>ebola.index = ebola['Date']
new_idx = pd.date_range(ebola.index.min(), ebola.index.max())<jupyter_output><empty_output><jupyter_text>5.그런데 new_idx를 살펴보면 ebola 데이터 집합에 있는 시간순서와 반대로 생성되어 있습니다. 다음은 시간 순서를 맞추기 위해 reversed 메서드를 사용하여 인덱스를 반대로 뒤집은 것입니다.<jupyter_code>print(new_idx)
new_idx = reversed(new_idx)<jupyter_output><empty_output><jupyter_text>6.다음은 reindex 메서드를 사용하여 새로 생성한 인덱스(new_idx)를 새로운 인덱스로 지정한 것입니다. 그러면 2015년 01월 01일 데이터와 같은 ebola 데이터프레임에 아예 없었던 날짜가 추가됩니다. 이제 그래프를 그리기 위한 데이터프레임이 준비되었습니다.<jupyter_code>ebola = ebola.reindex(new_idx)
print(ebola.head().iloc[:, :5])
print(ebola.tail().iloc[:, :5])<jupyter_output>Date  Day  Cases_Guinea  Cases_Liberia  Cases_SierraLeone
Date                                                                      
2014-03-26 2014-03-26  4.0          86.0            NaN                NaN
2014-03-25 2014-03-25  3.0          86.0            NaN                NaN
2014-03-24 2014-03-24  2.0          86.0            NaN                NaN
2014-03-23        NaT  NaN           NaN            NaN                NaN
2014-03-22 2014-03-22  0.0          49.0            NaN                NaN<jupyter_text>7. 각 나라의 에볼라 발병일 옮기기다음은 last_valid_index, first_valid_index 메서드를 사용하여 각 나라의 에볼라 발병일을 구한 것입니다. 각각의 메서드는 유효한 값이 있는 첫 번째와 마지막 인덱스를 반환합니다. 다음을 입력하고 결과를 확인해 보세요.<jupyter_code>last_valid = ebola.apply(pd.Series.last_valid_index)
print(last_valid)
first_valid = ebola.apply (pd.Series.first_valid_index)
print(first_valid)<jupyter_output>Date                  2015-01-05
Day                   2015-01-05
Cases_Guinea          2015-01-05
Cases_Liberia         2015-01-03
Cases_SierraLeone     2015-01-05
Cases_Nigeria         2014-12-07
Cases_Senegal         2014-12-07
Cases_UnitedStates    2014-12-07
Cases_Spain           2014-12-07
Cases_Mali            2014-12-07
Deaths_Guinea         2015-01-05
Deaths_Liberia        2015-01-03
Deaths_SierraLeone    2015-01-05
Deaths_Nigeria        2014-12-07
Deaths_Senegal        2014-12-07
Deaths_UnitedStates   2014-12-07
Deaths_Spain          2014-12-07
Deaths_Mali           2014-12-07
dtype: datetime64[ns]<jupyter_text>8. 각 나라의 에볼라 발병일을 동일한 출발선으로 옮기려면 에볼라가 가장 처음 발병한 날(earliest_date)에서 각 나라의 에볼라 발병일을 뺀 만큼(shift_values)만 옮기면 됩니다.<jupyter_code>earliest_date = ebola.index.min()
print(earliest_date)
shift_values = last_valid - earliest_date
print(shift_values)<jupyter_output>Date                    0 days
Day                     0 days
Cases_Guinea            0 days
Cases_Liberia           5 days
Cases_SierraLeone       5 days
Cases_Nigeria         123 days
Cases_Senegal         162 days
Cases_UnitedStates    193 days
Cases_Spain           200 days
Cases_Mali            214 days
Deaths_Guinea           0 days
Deaths_Liberia          5 days
Deaths_SierraLeone      5 days
Deaths_Nigeria        123 days
Deaths_Senegal        169 days
Deaths_UnitedStates   193 days
Deaths_Spain          200 days
Deaths_Mali           214 days
dtype: timedelta64[ns]<jupyter_text>9.이제 각 나라의 에볼라 발병일을 옮기면 됩니다. 다음은 shift 메서드를 사용하여 모든 열의 값을 shift_values 값만큼 옮긴 것입니다. shift 메서드는 인잣값만큼 데이터를 밀어내는 메서드입니다.<jupyter_code>ebola_dict = {}
for idx, col in enumerate(ebola):
    d = shift_values[idx].days
    shifted = ebola[col].shift(d)
    ebola_dict[col] =shifted<jupyter_output><empty_output><jupyter_text>10.ebola_dict에는 시간을 다시 설정한 데이터가 딕셔너리 형태로 저장되어 있습니다 다음은 DataFrame 메서드를 사용하여 ebola_dict의 값을 데이터프레임으로 변환한 것입니다.<jupyter_code>ebola_shift = pd.DataFrame(ebola_dict)<jupyter_output><empty_output><jupyter_text>11.이제 에볼라의 최초 발병일(2014-03-22)을 기준으로 모든 열의 데이터가 옮겨졌습니다.<jupyter_code>print(ebola_shift.tail())<jupyter_output>Date  Day  Cases_Guinea  Cases_Liberia  Cases_SierraLeone  \
Date                                                                         
2014-03-26 2014-03-26  4.0          86.0            8.0                2.0   
2014-03-25 2014-03-25  3.0          86.0            NaN                NaN   
2014-03-24 2014-03-24  2.0          86.0            7.0                NaN   
2014-03-23        NaT  NaN           NaN            3.0                2.0   
2014-03-22 2014-03-22  0.0          49.0            8.0                6.0   

            Cases_Nigeria  Cases_Senegal  Cases_UnitedStates  Cases_Spain  \
Date                                                                        
2014-03-26            1.0            NaN                 1.0          1.0   
2014-03-25            NaN            NaN                 NaN          NaN   
2014-03-24            NaN            NaN                 NaN          NaN   
2014-03-23            NaN            NaN                 NaN        [...]<jupyter_text>12.마지막으로 인덱스를 Day 열로 지정하고 그래프에 필요 없는 Date, Day열은 삭제하면 그래프를 그리기 위한 데이터프레임이 완성됩니다.<jupyter_code>ebola_shift.index = ebola_shift['Day']
ebola_shift = ebola_shift.drop(['Date', 'Day'], axis = 1)

print(ebola_shift.tail())<jupyter_output>Cases_Guinea  Cases_Liberia  Cases_SierraLeone  Cases_Nigeria  \
Day                                                                  
4.0          86.0            8.0                2.0            1.0   
3.0          86.0            NaN                NaN            NaN   
2.0          86.0            7.0                NaN            NaN   
NaN           NaN            3.0                2.0            NaN   
0.0          49.0            8.0                6.0            0.0   

     Cases_Senegal  Cases_UnitedStates  Cases_Spain  Cases_Mali  \
Day                                                               
4.0            NaN                 1.0          1.0         NaN   
3.0            NaN                 NaN          NaN         NaN   
2.0            NaN                 NaN          NaN         NaN   
NaN            NaN                 NaN          NaN         NaN   
0.0            1.0                 1.0          1.0         1.0   

     Deaths_Guinea  Deaths_Liberia  Dea[...]<jupyter_text>13.다음은 지금까지 만든 데이터프레임으로 다시 그린 그래프입니다.<jupyter_code>fig, ax = plt.subplots()
ax = ebola_shift.iloc[:, :].plot(ax=ax)
ax.legend(fontsize=7, loc=2, borderaxespad=0.)
plt.show()<jupyter_output><empty_output>
StarcoderdataJupyterStructuredCleanDedup