Pandas 시계열 다루기

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


시계열 데이터

일정 시간 간격으로 어떤 값을 기록한 데이터

시계열 데이터 만들어보기

data = {
    'Date1': ['2024-02-17', '2024-02-18', '2024-02-19', '2024-02-20'],
    'Date2': ['2024:02:17', '2024:02:18', '2024:02:19', '2024:02:20'],
    'Date3': ['24/02/17', '24/02/18', '24/02/19', '24/02/20'],
    'Date4': ['02/17/2024', '02/18/2024', '02/19/2024', '02/20/2024'],
    'Date5': ['17-Feb-2024', '18-Feb-2024', '19-Feb-2024', '20-Feb-2024'],
    'DateTime1': ['24-02-17 13:45:30', '24-02-18 14:55:45', '24-02-19 15:30:15', '24-02-20 16:10:50'],
    'DateTime2': ['2024-02-17 13-45-30', '2024-02-18 14-55-45', '2024-02-19 15-30-15', '2024-02-20 16-10-50'],
    'DateTime3': ['02/17/2024 01:45:30 PM', '02/18/2024 02:55:45 PM', '02/19/2024 03:30:15 AM', '02/20/2024 04:10:50 AM'],
    'DateTime4': ['17 Feb 2024 13:45:30', '18 Feb 2024 14:55:45', '19 Feb 2024 15:30:15', '20 Feb 2024 16:10:50']
}

df = df.DataFrame(data)
df
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 9 columns):
 #   Column     Non-Null Count  Dtype 
---  ------     --------------  ----- 
 0   Date1      4 non-null      object
 1   Date2      4 non-null      object
 2   Date3      4 non-null      object
 3   Date4      4 non-null      object
 4   Date5      4 non-null      object
 5   DateTime1  4 non-null      object
 6   DateTime2  4 non-null      object
 7   DateTime3  4 non-null      object
 8   DateTime4  4 non-null      object
dtypes: object(9)
memory usage: 420.0+ bytes

모든 데이터가 object형인것을 볼 수 있다. 우선 Date1을 datetime형으로 변환해보자.

df['Date1'] = pd.to_datetime(['Date1'])

그런데 이때, Date2, Date3, DateTime1, DateTime2도 위와 같이 변환이 가능할까?

아니다. 오류가 뜬다.

DateParseError: hour must be in 0..23: 2024:02:17, at position 0

pd.to_datetime으로 인식할 수 있는 포맷이 아니기 때문이다. 이런때에는 format함수를 통해 형식에 맞게 포맷팅해주는 것이 중요하다. 이때는 파이썬에서 지원하는 %y, %m, %d등을 사용해 변환해주면 된다.

df['Date2'] = pd.to_datetime(df['Date2'], format = '%Y:%m:%d')
df['Date3'] = pd.to_datetime(df['Date3'] ,format = '%y/%m/%d' ) 
df['Date4'] = pd.to_datetime(df['Date4'] )
df['Date5'] = pd.to_datetime(df['Date5'] )

df['DateTime1'] = pd.to_datetime(df['DateTime1'], format = '%y-%m-%d %H:%M:%S')
df['DateTime2'] = pd.to_datetime(df['DateTime2'], format = '%Y-%m-%d %H-%M-%S')
df['DateTime3'] = pd.to_datetime(df['DateTime3'])
df['DateTime4'] = pd.to_datetime(df['DateTime4'])

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 9 columns):
 #   Column     Non-Null Count  Dtype         
---  ------     --------------  -----         
 0   Date1      4 non-null      datetime64[ns]
 1   Date2      4 non-null      datetime64[ns]
 2   Date3      4 non-null      datetime64[ns]
 3   Date4      4 non-null      datetime64[ns]
 4   Date5      4 non-null      datetime64[ns]
 5   DateTime1  4 non-null      datetime64[ns]
 6   DateTime2  4 non-null      datetime64[ns]
 7   DateTime3  4 non-null      datetime64[ns]
 8   DateTime4  4 non-null      datetime64[ns]
dtypes: datetime64[ns](9)
memory usage: 420.0 bytes

완변하게 모든 데이터가 datetime으로 형변환이 되었다.

df = df[['Date1','Date2','Date3','Date4','Date5','DateTime1','DateTime2','DateTime3','DateTime4']]

위 데이터 중 Date1의 년,월,일,시,분,초,분기,요일을 나타내는 방법은 아래와 같다.

df['year'] = df['Date1'].dt.year
df['month'] = df['Date1'].dt.month
df['day'] = df['Date1'].dt.day
df['hour'] = df['Date1'].dt.hour
df['minute'] = df['Date1'].dt.minute
df['second'] = df['Date1'].dt.second
df['quarter'] = df['Date1'].dt.quarter
or
df['quarter'] = df['Date1'].dt.to_period('Q')
df['week'] = df['Date1'].dt.dayofweek

시계열 연산

datetime으로 변환한 데이터는 연산이 가능하다.

# 예상 도착시간보다 늦게 도착한 경우
df_time_diff = df['예상도착시간'] - df['실제도착시간']

Pandas astype과 to_numeric의 차이

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


to_numeric & astype

데이터 분석에서 수치형 데이터는 중요한 역학을 차지한다. 비수치형 데이터를 수치형 데이터로 변환하는 작업은 데이터 전처리 과정에서 자주 요구 된다. 이때 판다스는 이러한 변환을 위해 두가지 함수를 제공한다. 그게 바로 astype과 to_numeric이다.

astype

대부분의 자료형으로 변환을 지원하는 범용성을 갖추고 있어 수치형으로도 변환이 가능한 것으로 이때 astype을 사용하기 위해서는 모든 데이터가 해당 형식으로 변환할 수 있어야만 올바르게 작동된다.

즉 모든 데이터를 한꺼번에 수치형, 혹은 모든 자료를 어떠한 자료형으로 변환시킬 떄 사용할 수 있다는 것을 의미한다.

to_numeric

astype보다 좀 더 유연하게 작동되어 변환할 수 없는 데이터를 자동으로 NaN처리하면서 변환할 수 있는 데이터만 수치형으로 변환해준다. 대규모 데이터 셋을 처리할 때 매우 유용하다.

변환을 요구하는 데이터 셋 안에 ‘안녕’과 같은 오브젝트(문자형) 데이터가 있다면 이때는 astype을 통해 정수형 데이터로 변환시키지 못할 것이다. 이때 사용하는 것이 to_numeric함수이다. to_numeric을 사용하면서 errors='coerce를 입력하면 변환할 수 있는 데이터는 수치형으로 변환되고 변환할 수 없는 데이터는 NaN으로 처리된다.

이떄 주의할 점은 두가지 있는데

  1. to_numeric은 메서드로 사용할 수 없고 pd.to_numeric함수로 호출해야함
  2. 데이터 프레임 전체에 사용불가능하며 시리즈에만 함수를 적용할 수 있음

만약 데이터프레임 전체에 사용하고 싶다면 apply를 사용해 해결해야한다.

# df라는 데이터프레임이 있다고 가정하고 
df = pd.dataFrame(data)

# 이런식으로 apply를 사용해 적용해야한다
df.apply(pd.to_numeric, errors='coerce')

따라서 두 함수를 상황에 맞게 잘 선택해 사용하는 것이 중요하다!

Pandas missingno 라이브러리

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


missingno

결측치(null)값만 빠르게 확인하기 위한 시각화 라이브러리

결측치가 있는지 알아야 결측치를 없애든, 임의의 값을 넣든 할 수 있기 때문에 이를 위해 빠르게 시각화 하는 툴이다. 실무에서 반드시 사용해야하는 것은 아니지만, 업무를 더 잘하기 위해 사용하는 라이브러리 정도로 이해하고 넘어가면 좋을 듯 하다.

import missingno as msno

msno.matrix(df)
import missingno as msno

msno.bar(df)

Pandas 박스플랏과 이상치

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


box plot으로 이상치 확인하기

데이터 분석을 할 때 데이터 전처리에 많은 시간을 할애하게 된다. 데이터 전처리 단계에서 해야하는 것은 여러가지가 있겠지만 그중 하나가 데이터 이상치 처리이다. 데이터에 이상치가 많이 포함되어 있을 경우, 모델의 성능을 저하시킬 수 있기 때문에 이를 처리해주는 것이 필요하다. 이때 이상치라고 해서 무조건 제거해야하는 것은 아니고 해당 도메인에 맞게 판단하는 것이 중요하다. 하여튼, 이러한 이상치를 잘 볼수 있는 방법중에 하나가 boxplot을 그려보는 방법이다.

이상치: 관측된 데이터의 일반적인 범위에서 많이 벗어난 값, 너무 작거나 너무 큰 값

위 그림과 같이 상자 수염 도표를 이용해 데이터의 분포와 패턴을 파악하거나 해당 데이터셋에 이상치가 있는지 시작적으로 나타낸 것을 박스플롯(box plot)이라고 한다.

박스플롯의 사분위 범위(IQR)을 이용해 이상치 포함여부를 확인할 수 있는데, 이때의 사분위 범위란 Q3-Q1값을 의미한다. (위 이미지에서 분홍색 박스를 의미함) 그리고 이상치 판단 기준은 Q1 - 1.5*IQR 미만에 해당하는 값 또는 Q3 + 1.5*IQR초과에 해당되는 값이면 이상치로 볼 수 있다. (위 이미지에서 초록색 점을 의미함)

그러나 해당부분에 위치해 있어도 이상치가 아닐 가능성도 있기 때문에 도메인 지식을 통해 해당 데이터의 특성을 파악해야 조금 더 정확하게 처리할 수 있다.

q3 = df['views'].quatile(.75)  # 3분위 수 > 75%
q1 = df['views'].quatile(.25)  # 1분위 수 > 25%

iqr = q3 - q1

min_outlier = q1 - (iqr*1.5)
max_outlier = q3 + (iqr*1.5)

df_outlier = df[(df['views'] < min_outlier) | df['views'] > max_outlier)]

Pandas 데이터 전처리 다양한 실습

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


데이터 전처리

where

특정 조건을 만족하는 행들의 값만 필터링하고 나머지 행은 Nan값으로 대치

혹은 Nan 대신 대치될 값을 적어줄 수도 있음 (각 열들의 값을 기준으로 더 복잡한 조건을 지정할 수 있음)

# 나이를 0~100범위를 두고 나머지에 대해서는 NaN처리
df['age'] = df['age'].where(df['age'].between(0,100), np.nan)

descibe

기술통계량(평균, 표준편차, 최대, 최소값 등)을 보여주는 메소드

df.describe()

value_counts

각 값의 개수(등장 횟수)를 카운팅

  • 가장 많은 빈도수부터 내림차순 정렬
  • 리턴값은 시리즈
  • 기본적으로는 Nan값은 제외하지만 dropna=False를 적용하면 Nan값이 포함
# A열에서 가장 많이 등장한 값 추출
df.value_counts('A').idxmax()[0]
# A열의 최빈값 등장 횟수
df.value_counts('A').max()

# 그반대는 아래와 같다
df.value_counts('A').idxmin()[0]
df.value_counts('A').min()

match

특정 단어와 완전 일치하는 데이터 필터링 (contains로는 겹쳐버리는 문자가 있으면 걸러내지 못하는 데이터를 match를 통해 걸러낼 수 있다)

정규표현식을 전달해, 해당 정규식에 해당하는 인덱스 반환

reg = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$'
df['email'] = df['email'].where(df['email'].str.match(reg, na=False))

rename

컬럼의 이름을 바꾸는 함수

  1. 전체 컬럼 이름 한꺼번에 바꾸기
  2. 개별적으로 바꾸기 > 이떄 사용하는 것이 rename

우선 전체 컬럼을 한꺼번에 바꾸는 방법은 아래와 같다.

# 전체 컬럼명을 확인 
df.columns  # Index(['a', 'b', 'c'])

# 바꿀 컬럼명 대입
df.columns = ['에이', '비', '씨']
df.columns  # Index(['에이', '비', '씨'])

위 경우는 전체 컬럼을 한번에 바꿀때에만 가능하다.

이제 rename을 사용해 개별 컬럼명을 변경해보자.

# 전체 컬럼명을 확인 
df.columns  # Index(['a', 'b', 'c'])

df.rename(columns = {'a':'에이', 'b':'비'}, inplace=True)
df.columns  # Index(['에이', '비', 'c'])

mode

행/열의 최빈값을 구하는 함수(최빈값이 여러개일 경우 모두 표시)

최빈값: 가장 많이 등장한 값

  • df.mode(axis=0, numeric_only=False, dropna=True)
# 최빈값 찾기 
df['A'].mode()[0]

select_dtypes

데이터프레임 내 포함 혹은 제외할 데이터 타입을 지정할 수 있는 함수

# 포함할 데이터타입 
df = df.select_dtypes(include='object')
# 제외할 데이터타입
df = df.select_dtypes(exclude=['int64', 'object'])