본문 바로가기
Study/혼자 공부하는 판다스

혼자 공부하는 판다스 - 데이터 사전처리(정규화, 시계열 데이터)

by Wanooky 2022. 4. 22.

정규화

 

각 변수에 들어 있는 숫자 데이터의 상대적 크기 차이 때문에 분석 결과가 달라질 수 있다.

 

그렇기 때문에 숫자 데이터의 상대적 크기 차이를 제거할 필요가 있는데, 각 열에 속하는 데이터 값을

 

동일한 크기 기준으로 나눈 비율로 나타내는 것을 정규화라고 한다.

 

정규화 과정을 거치게 되면, 데이터의 범위는 0~1 또는 -1 ~ 1이 된다.

 

df = pd.read_csv('/content/drive/MyDrive/part5/auto-mpg.csv', header=None)
df.columns = ['mpg','cylinders','displacement','horsepower','weight',
              'acceleration', 'model_year','origin','name']

df['horsepower'].replace('?', np.nan, inplace=True)
df.dropna(subset=['horsepower'], axis=0, inplace=True)
df['horsepower'] = df['horsepower'].astype('float')

print(df.horsepower.describe())
print('\n')

df.horsepower = df.horsepower/abs(df.horsepower.max())

print(df.horsepower.head())
print('\n')
print(df.horsepower.describe())

count    392.000000
mean     104.469388
std       38.491160
min       46.000000
25%       75.000000
50%       93.500000
75%      126.000000
max      230.000000
Name: horsepower, dtype: float64


0    0.565217
1    0.717391
2    0.652174
3    0.652174
4    0.608696
Name: horsepower, dtype: float64


count    392.000000
mean       0.454215
std        0.167353
min        0.200000
25%        0.326087
50%        0.406522
75%        0.547826
max        1.000000
Name: horsepower, dtype: float64

또 다른 정규화 방법으로는 최대값과 최소값의 차를 이용한 방법이 있는데,

 

이를 이용하여 정규화하면 0~1 사이의 범위로 변환된다.

 

print(df.horsepower.describe())
print('\n')

min_x = df.horsepower - df.horsepower.min()
min_max = df.horsepower.max() - df.horsepower.min()
df.horsepower = min_x / min_max
print(df.horsepower.head())
print('\n')
print(df.horsepower.describe())

count    392.000000
mean       0.454215
std        0.167353
min        0.200000
25%        0.326087
50%        0.406522
75%        0.547826
max        1.000000
Name: horsepower, dtype: float64


0    0.456522
1    0.646739
2    0.565217
3    0.565217
4    0.510870
Name: horsepower, dtype: float64


count    392.000000
mean       0.317768
std        0.209191
min        0.000000
25%        0.157609
50%        0.258152
75%        0.434783
max        1.000000
Name: horsepower, dtype: float64

시계열 데이터

 

판다스는 시계열 데이터를 다루는 여러 가지 유용한 기능을 제공한다.

 

판다스의 시간 표시 방법에는 두가지가 있는데,

 

특정한 시점을 기록하는 Timestamp와 두 시점 사이의 일정한 기간을 나타내는 Period가 존재한다.

 

먼저, 다른 자료형을 시계열 객체로 변환해보자.

 

문자열을 Timestamp로 변환하기 위해서, to_datetime() 함수를 사용하면 문자열 등의 다른 자료형을

 

판다스의 Timestamp로 나타내는 datetime64 자료형으로 변환할 수 있다.

 

import pandas as pd
df = pd.read_csv('/content/drive/MyDrive/part5/stock-data.csv')

print(df.head())
print('\n')
print(df.info())

         Date  Close  Start   High    Low  Volume
0  2018-07-02  10100  10850  10900  10000  137977
1  2018-06-29  10700  10550  10900   9990  170253
2  2018-06-28  10400  10900  10950  10150  155769
3  2018-06-27  10900  10800  11050  10500  133548
4  2018-06-26  10800  10900  11000  10700   63039


<class 'pandas.core.frame.DataFrame'>
RangeIndex: 20 entries, 0 to 19
Data columns (total 6 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   Date    20 non-null     object
 1   Close   20 non-null     int64 
 2   Start   20 non-null     int64 
 3   High    20 non-null     int64 
 4   Low     20 non-null     int64 
 5   Volume  20 non-null     int64 
dtypes: int64(5), object(1)
memory usage: 1.1+ KB
None



df['new_Date'] = pd.to_datetime(df['Date'])

print(df.head())
print('\n')
print(df.info())
print('\n')
print(type(df['new_Date'][0]))


         Date  Close  Start   High    Low  Volume   new_Date
0  2018-07-02  10100  10850  10900  10000  137977 2018-07-02
1  2018-06-29  10700  10550  10900   9990  170253 2018-06-29
2  2018-06-28  10400  10900  10950  10150  155769 2018-06-28
3  2018-06-27  10900  10800  11050  10500  133548 2018-06-27
4  2018-06-26  10800  10900  11000  10700   63039 2018-06-26


<class 'pandas.core.frame.DataFrame'>
RangeIndex: 20 entries, 0 to 19
Data columns (total 7 columns):
 #   Column    Non-Null Count  Dtype         
---  ------    --------------  -----         
 0   Date      20 non-null     object        
 1   Close     20 non-null     int64         
 2   Start     20 non-null     int64         
 3   High      20 non-null     int64         
 4   Low       20 non-null     int64         
 5   Volume    20 non-null     int64         
 6   new_Date  20 non-null     datetime64[ns]
dtypes: datetime64[ns](1), int64(5), object(1)
memory usage: 1.2+ KB
None


<class 'pandas._libs.tslibs.timestamps.Timestamp'>

new_Date 열을 행 인덱스로 지정하고, Date 열을 제거하자. 시계열 값을 행 인덱스로 지정하면 

 

판다스는 DatetimeIndex로 저장한다.

 

df.set_index('new_Date', inplace=True)
df.drop('Date', axis=1, inplace=True)

print(df.head())
print('\n')
print(df.info())


            Close  Start   High    Low  Volume
new_Date                                      
2018-07-02  10100  10850  10900  10000  137977
2018-06-29  10700  10550  10900   9990  170253
2018-06-28  10400  10900  10950  10150  155769
2018-06-27  10900  10800  11050  10500  133548
2018-06-26  10800  10900  11000  10700   63039


<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 20 entries, 2018-07-02 to 2018-06-01
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype
---  ------  --------------  -----
 0   Close   20 non-null     int64
 1   Start   20 non-null     int64
 2   High    20 non-null     int64
 3   Low     20 non-null     int64
 4   Volume  20 non-null     int64
dtypes: int64(5)
memory usage: 960.0 bytes
None

 

to_period() 함수를 이용하면 일정한 기간을 나타내는 Period 객체로 Timestamp 객체를 변환할 수 있다.

 

freq 옵션에 기준이 되는 기간을 설정하는데,

 

'D'로 지정할 경우 1일의 기간을 나타내고, 'M'은 1개월의 기간, 'A'는 1년의 기간을 나타내는데, 1년이 끝나는 12월을

 

기준으로 삼는다.

 

dates = ['2019-01-01', '2020-03-01', '2021-06-01']

ts_dates = pd.to_datetime(dates)
print(ts_dates)
print('\n')

pr_day = ts_dates.to_period(freq='D')
print(pr_day)
pr_month = ts_dates.to_period(freq='M')
print(pr_month)
pr_year = ts_dates.to_period(freq='A')
print(pr_year)


DatetimeIndex(['2019-01-01', '2020-03-01', '2021-06-01'], dtype='datetime64[ns]', freq=None)


PeriodIndex(['2019-01-01', '2020-03-01', '2021-06-01'], dtype='period[D]')
PeriodIndex(['2019-01', '2020-03', '2021-06'], dtype='period[M]')
PeriodIndex(['2019', '2020', '2021'], dtype='period[A-DEC]')

 

date_range() 함수를 사용하면 여러 개의 날짜가 들어있는 배열 형태의 시계열 데이터를 만들 수 있다.

 

ts_ms = pd.date_range(start='2019-01-01', #날짜범위시작
                      end=None,  #날짜 범위 끝
                      periods=6,  #생성할 timestamp 갯수
                      freq='MS',  #시간 간격(MS : 월의 시작일)
                      tz='Asia/Seoul' #시간대(timezone)
                      )
print(ts_ms)


DatetimeIndex(['2019-01-01 00:00:00+09:00', '2019-02-01 00:00:00+09:00',
               '2019-03-01 00:00:00+09:00', '2019-04-01 00:00:00+09:00',
               '2019-05-01 00:00:00+09:00', '2019-06-01 00:00:00+09:00'],
              dtype='datetime64[ns, Asia/Seoul]', freq='MS')

 

시간 간격을 다르게 설정할 수 있는데, freq='M'으로 설정하면 월의 마지막 날짜를 생성한다.

 

3M으로 설정하면 3개월 간격의 마지막 날짜를 나타낸다.

 

ts_me = pd.date_range('2019-01-01', periods=6,
                      freq='M', #시간 간격 (M: 월의 마지막날)
                      tz='Asia/Seoul')
print(ts_me)
print('\n')

ts_3m = pd.date_range('2019-01-01', periods=6,
                      freq='3M',  #시간 간격 3개월
                      tz='Asia/Seoul')
print(ts_3m)


DatetimeIndex(['2019-01-31 00:00:00+09:00', '2019-02-28 00:00:00+09:00',
               '2019-03-31 00:00:00+09:00', '2019-04-30 00:00:00+09:00',
               '2019-05-31 00:00:00+09:00', '2019-06-30 00:00:00+09:00'],
              dtype='datetime64[ns, Asia/Seoul]', freq='M')


DatetimeIndex(['2019-01-31 00:00:00+09:00', '2019-04-30 00:00:00+09:00',
               '2019-07-31 00:00:00+09:00', '2019-10-31 00:00:00+09:00',
               '2020-01-31 00:00:00+09:00', '2020-04-30 00:00:00+09:00'],
              dtype='datetime64[ns, Asia/Seoul]', freq='3M')

period_range() 함수는 여러 개의 기간이 들어 있는 시계열 데이터를 만든다.

 

pr_m = pd.period_range(start='2019-01-01',  #날짜 범위 시작
                       end=None,  #날짜 범위 끝
                       periods=3, #생성할 periods 수
                       freq = 'M')  #기간의 길

print(pr_m)

PeriodIndex(['2019-01', '2019-02', '2019-03'], dtype='period[M]')


pr_h = pd.period_range(start='2019-01-01',
                       end=None,
                       periods=3,
                       freq='H' #기간의 길이 H는 시간
                       )
print(pr_h)
print('\n')

pr_2h = pd.period_range(start='2019-01-01',
                       end=None,
                       periods=3,
                       freq='2H' #기간의 길이 H는 시간
                        )
print(pr_2h)

PeriodIndex(['2019-01-01 00:00', '2019-01-01 01:00', '2019-01-01 02:00'], dtype='period[H]')


PeriodIndex(['2019-01-01 00:00', '2019-01-01 02:00', '2019-01-01 04:00'], dtype='period[2H]')

 

날짜 데이터를 분리하는 방법도 있다.

 

df = pd.read_csv('/content/drive/MyDrive/part5/stock-data.csv')

df['new_Date'] = pd.to_datetime(df['Date'])
print(df.head())
print('\n')

df['Year'] = df['new_Date'].dt.year
df['Month'] = df['new_Date'].dt.month
df['Day'] = df['new_Date'].dt.day
print(df.head())


         Date  Close  Start   High    Low  Volume   new_Date
0  2018-07-02  10100  10850  10900  10000  137977 2018-07-02
1  2018-06-29  10700  10550  10900   9990  170253 2018-06-29
2  2018-06-28  10400  10900  10950  10150  155769 2018-06-28
3  2018-06-27  10900  10800  11050  10500  133548 2018-06-27
4  2018-06-26  10800  10900  11000  10700   63039 2018-06-26


         Date  Close  Start   High    Low  Volume   new_Date  Year  Month  Day
0  2018-07-02  10100  10850  10900  10000  137977 2018-07-02  2018      7    2
1  2018-06-29  10700  10550  10900   9990  170253 2018-06-29  2018      6   29
2  2018-06-28  10400  10900  10950  10150  155769 2018-06-28  2018      6   28
3  2018-06-27  10900  10800  11050  10500  133548 2018-06-27  2018      6   27
4  2018-06-26  10800  10900  11000  10700   63039 2018-06-26  2018      6   26

 

to_period() 메서드를 이용하여 연-월-일 중 연-월 또는 연도를 추출할 수 있다.

 

df['Date_yr'] = df['new_Date'].dt.to_period(freq='A')
df['Date_m'] = df['new_Date'].dt.to_period(freq='M')
print(df.head())

         Date  Close  Start   High    Low  Volume   new_Date  Year  Month  \
0  2018-07-02  10100  10850  10900  10000  137977 2018-07-02  2018      7   
1  2018-06-29  10700  10550  10900   9990  170253 2018-06-29  2018      6   
2  2018-06-28  10400  10900  10950  10150  155769 2018-06-28  2018      6   
3  2018-06-27  10900  10800  11050  10500  133548 2018-06-27  2018      6   
4  2018-06-26  10800  10900  11000  10700   63039 2018-06-26  2018      6   

   Day Date_yr   Date_m  
0    2    2018  2018-07  
1   29    2018  2018-06  
2   28    2018  2018-06  
3   27    2018  2018-06  
4   26    2018  2018-06

추출한 날짜 정보를 행 인덱스로 지정할 수도 있다.

 

df.set_index('Date_m', inplace=True)
print(df.head())

               Date  Close  Start   High    Low  Volume   new_Date  Year  \
Date_m                                                                     
2018-07  2018-07-02  10100  10850  10900  10000  137977 2018-07-02  2018   
2018-06  2018-06-29  10700  10550  10900   9990  170253 2018-06-29  2018   
2018-06  2018-06-28  10400  10900  10950  10150  155769 2018-06-28  2018   
2018-06  2018-06-27  10900  10800  11050  10500  133548 2018-06-27  2018   
2018-06  2018-06-26  10800  10900  11000  10700   63039 2018-06-26  2018   

         Month  Day Date_yr  
Date_m                       
2018-07      7    2    2018  
2018-06      6   29    2018  
2018-06      6   28    2018  
2018-06      6   27    2018  
2018-06      6   26    2018