즐겁게!! 자신있게!! 살아보세!!

재밌는 인생을 위하여! 영촤!

Language_Study/Python

[Python] 10-2.데이터전처리

Godwony 2021. 1. 19. 21:26
728x90
반응형

불균형한 데이터 다루기

  • 실무에서는 특정한 값을 갖는 데이터가 많은 경우가 있음
  • 쇼핑몰에서 웹사이트 방문자는 구매 버튼을 거의 클릭하지 않으며 암 환자의 경우 암의 종류가 다양하지만 실제로는 상당수가 희귀한 경우
  • 이 데이터를 가지고 데이터 분석을 수행하는 경우 잘못된 예측을 할 가능성이 있음
  • 해결책
    • 소수의 값을 갖는 데이터를 더 많이 모아야 함
    • 불균형한 클래스에 잘맞는 모델 평가 지표를 사용
      (정확도 -> 오차 행렬, 정밀도, 재현율, F1 점수, ROC 곡선 등)
    • 데이터에 가중치를 적용
      사이킷런의 대부분의 분류기들은 class_weight 라는 매개변수를 이용해서 가중치를 부여
    • 다운 샘플링
      적은 값을 갖는 데이터의 크기와 동일하게 다수 값을 갖는 데이터의 랜덤한 부분집합을 생성
    • 업 샘플링
      다수 값을 갖는 데이터의 크기와 동일하게 적은 값을 갖는 데이터의 중복을 허용

앙상블 - 두가지 이상을 같이 적용 (같은것, 다른것을 적용해도 앙상블이라고 함.)

불균형한(개수가 다른 경우) 클래스의 데이터를 가지고 분석을 해야 하는 겨우

  • 샘플 자체의 개수가 작을 때는 자료를 더 수집하는 것이 가장 좋은 방법
  • 데이터를 수집하는 것이 가능하지 않을 때는 데이터에 가중치를 적용해서 사용 - 분류 알고리즘의 매개변수 중에서 weight가 있으면 이 매개변수가 데이터에 가중치를 적용할 수 있는 매개변수이다
  • 개수가 작은 데이터의 개수를 강제로 늘리거나 개수가 많은 데이터의 개수를 줄이는 업샘플링이나 다운 샘플링을 해서 알고리즘에 적용
  • 평가지표를 다양하게 선택 - 정확도 대신에 재현율이나 F1 통계량 등을 이용
import numpy as np 
import pandas as pd 


# %%
# 0이 10개 이고 1이 90개인 ndarray 생성
list1 = []
for i in range(0, 10, 1) :
    list1.append(0)

list2 = []
for i in range(0, 90, 1) : 
    list2.append(1)


# %%
# 2개의 list를 가지고 하나의 array 생성
target = np.array(list1 + list2) 
print(target)


# %%
# 분류 알고리즘에 위의 데이터를 이용하는 경우 
# 0:10%, 1:90% 

# 분류 알고리즘
from sklearn.ensemble import RandomForestClassifier
# 데이터의 비율이 현저하게 다르기 때문에 가중치 설정 
weights = { 0:0.9, 1:.1 }
rfc = RandomForestClassifier(class_weight=weights)
print(rfc)


# %%
# 가중치를 직접 설정하지 않고 분류기에게 판단하도록 해주는 옵션 
rfc = RandomForestClassifier(class_weight='balanced')
print(rfc)


# 샘플링 비율 조정
# np.where 는 array에서 조건에 맞는 데이터만 추출
# np.where(target==0)
# taget 행렬에서 값이 0인 데이터의 행번호를 리턴
#(행번호행렬, 자료형) 으로 결과를 리턴
# 행번호행렬만 가져오기 위해서 [0]을 추가 
class0 = np.where(target==0)[0]
class1 = np.where(target==1)[0]
print(len(class0))
print(len(class1))
# 데이터의 개수 확인 



# target이 1인 데이터에서 target이 0인 데이터만큼 다운 샘플링을 해서 새로운 데이터셋을 생성
# 다운샘플링에서는 비복원추출 해야됨
# class1 에서 class0의 데이터 개수만큼 비복원추출(replace) 
# 비복원추출 - 나온것은 제거 , True로 설정하면 나온게 또 나옴.
downsample = np.random.choice(class1, size=len(class0), replace=False)
result = np.hstack((target[class0], target[downsample]))  # hstack은 매개변수 1개라 묶어
print(result)


# 업샘플링 
upsample = np.random.choice(class0, size=len(class1), replace=True)
result = np.hstack((target[class1], target[upsample]))  # hstack은 매개변수 1개라 묶어
print(result)

다변량 분석에서 데이터의 상대적 크기 문제

  • 다변량 분석 - 2개이상의 컬럼의 데이터를 가지고 분석
  • 하나의 컬럼의 데이터는 값의 범위가 0-100 이고 다른 컬럼의 데이터는 값의 범위가 0-1 이라면 이 경우 2개의 데이터를 가지고 다변량 분석을 하게 되면 첫번째 컬럼의 영향을 받게 될 수 있다.
    • 이런 경우에는 값의 범위를 일치시켜 주는것이 좋다.
  • 값의 범위는 같은데 분포가 다른 경우에도 분포를 기준으로 해서 값을 조정할 필요가 있다.
    • 최대값으로 나누거나 최대값-최소값을 분포모로하고 해당값-최소값을 분자로해서 값을 조정
  • 이러한 값의 조정을 scailing 이라고 합니다.
    • 01 사이나 -11 사이로 조정한다.
    • 더 큰값으로 가능하지만 머신러니 모델에서는 값의 크기가 커지면 정확도가 떨어진다.

1. 표준화

  • 모든 값들의 표준 값을 정해서 그 값을 기준으로 차이를 구해서 비교하는 방법

1) 표준값

  • (데이터-평균)/표준편차 : 표준값의 평균은 50

2) 편차값

  • 표준값 * 10 + 50 : 위의 숫자보다 큰 숫자로 변환
# To add a new cell, type '# %%'
# To add a new markdown cell, type '# %% [markdown]'
# %%
import numpy as np 
import pandas as pd

# 표준화
# student.csv 파일의 내용을 가져오기 
# index 로 이름 설정 
df = pd.read_csv('../data/student.csv', encoding='cp949', index_col='이름')
print(df)


# %%
import platform
from matplotlib import font_manager, rc

# 그래프의 한글 깨짐
if platform.system() == 'Darwin':
    rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
    font_name = font_manager.FontProperties(
        fname="c:/Windows/Fonts/malgun.ttf").get_name()
    rc('font', family=font_name)


# %%
# 인덱스를 기준으로 해서 막대 그래프 그리기
df.plot(kind='bar')


# %%
# 표준값 작업 
# 각 과목의 평균과 표준편차 구하기 
kormean, korstd = df['국어'].mean(), df['국어'].std()
engmean, engstd = df['영어'].mean(), df['영어'].std()
matmean, matstd = df['수학'].mean(), df['수학'].std()


# %%
# 표준값 구하기 - (자신의값-평균)/표준편차
# 0.0이면 중간
# 1.0이면 상하위 15%
# 2.0이면 상하위 1.1%
df['국어표준값'] = (df['국어'] - kormean)/korstd
df['영어표준값'] = (df['영어'] - engmean)/engstd
df['수학표준값'] = (df['수학'] - matmean)/matstd
print(df[['국어표준값','영어표준값','수학표준값']])


# %%
# 표준값은 비교가 가능하기는 하지만 사람이 알아보기 힘들다. 
# 표준값 * 10 + 50 을 해서 편차값을 만들어서 보고서 작성 
df['국어편차값'] = (df['국어표준값']*10)+50
df['영어편차값'] = (df['영어표준값']*10)+50
df['수학편차값'] = (df['수학표준값']*10)+50
print(df[['국어편차값', '영어편차값', '수학편차값']].plot(kind='bar'))


# %%
# 최대값으로 나누어서 값을 저장 - 정규화
# (자신의값-최소값)/(최대값-최소값)으로 하기도함 
df['국어정규화1'] = df['국어'] / df['국어'].max()
df['국어정규화2'] = (df['국어']-df['국어'].min()) / (df['국어'].max()-df['국어'].min())
print(df[['국어정규화1', '국어정규화2']])

2. sklearn 의 정규화

1) StandardScaler

  • 평균이 0이 되고 표준편차가 1이 되도록 변환
  • (벡터-평균)/표준편차
  • 주로 주성분분석에서 많이 이용
  • 음수가 발생함.

2) MinMaxScaler

  • 최대값이 1 최소값이 0이 되도록 변환
  • (벡터-최소값)/(최대값-최소값)
  • 신경망에서 주로 이용

3) RobustScaler

  • 중앙값이 0 IQR(4분위수)를 이용하는 방식
  • (벡터-중관값)/(75%-25%)
  • 앞의 방식들은 이상치에 영향을 많이 받는다.
  • 데이터의 분포가 불균형이거나 이상치(outlier)가 존재하는 경우에 주로이용

4) QuantileTransformer

  • 데이터를 1000개의 분위로 나눈 후 0-1 사이에 고르게 분포시키는 방식
  • outlier의 영향을 적데 받기 위해서 사용

데이터의 분포 - 한쪽에 완전히 쏠려있을 때는 정규화를 하지 않는다.
outlier 확인

import platform
from matplotlib import font_manager, rc
import numpy as np 
import pandas as pd

df = pd.read_csv('../data/student.csv', encoding='cp949', index_col='이름')

# 그래프의 한글 깨짐
if platform.system() == 'Darwin':
    rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
    font_name = font_manager.FontProperties(
        fname="c:/Windows/Fonts/malgun.ttf").get_name()
    rc('font', family=font_name)

# sklearn 을 이용한 scailing
from sklearn import preprocessing

# StandardScaler - 평균은 0 표준편차는 1이 되도록 scailing
scaler = preprocessing.StandardScaler()

# 국어 점수만 이용하는 경우 df['국어'] 가 아니고 df[['국어']]
# 머신러닝의 데이터들은 행렬을 이용하는데 data['국어'] 로 하게 되면
# 컬럼이름이 1개라서 하나의 열로 리턴되서 1차원 데이터가 된다. 
# df[['국어']] 하게되면 list를 대입했기 때문에 DataFrame 으로 리턴 
result = scaler.fit_transform(df[['국어']].values)
print(result) # 표준값
print(np.mean(result)) # 평균은 0에 가까워짐 
print(np.std(result)) # 표준편차는 1.0에 가까워짐


scaler = preprocessing.MinMaxScaler()
result = scaler.fit_transform(df[['국어']].values)
print(result) # 표준값
print(np.mean(result)) 
print(np.std(result)) 


scaler = preprocessing.RobustScaler()
result = scaler.fit_transform(df[['국어']].values)
print(result) # 표준값
print(np.mean(result))
print(np.std(result)) 


scaler = preprocessing.QuantileTransformer()
result = scaler.fit_transform(df[['국어']].values)
print(result) # 표준값
print(np.mean(result)) 
print(np.std(result)) 

정규화

  • 값의 범위를 0-1 사이의 데이터로 변환
  • 표준화는 일정한 범위 내로 데이터를 변환하는 것이고 정규화는 0-1 사이로 해야한다.
  • Nomalizer 클래스를 이용해서 transdorm 메소드에 데이터를 대입하면 된다.
    • 이 때 norm 매개변수에 옵션을 설정할 수 잇는데 l1, l2, max 등의 값을 설정할수 있다.
    • max는 최대값으로 나누는 방식
    • max를 이용할 때는 하나의 부호형태의 데이터야 한다 (음수일때 안됨)
    • l1과 l2는 거리 계산 방식
    • l1 - 맨하턴 거리를 이용하고, l2는 유클리드 거리를 이용

유클리드 거리 (알고리즘에서는 기본값으로 쓰는 경우가 많다.)
A <-> B 의 가장 짧은 거리
맨한턴 거리
중간에 장애물이 있다 하여 돌아가는 거리를 계산

image-20200311120838987
# To add a new cell, type '# %%'
# To add a new markdown cell, type '# %% [markdown]'
# %%
import platform
from matplotlib import font_manager, rc
import numpy as np 
import pandas as pd

df = pd.read_csv('../data/student.csv', encoding='cp949', index_col='이름')

# 그래프의 한글 깨짐
if platform.system() == 'Darwin':
    rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
    font_name = font_manager.FontProperties(
        fname="c:/Windows/Fonts/malgun.ttf").get_name()
    rc('font', family=font_name)


# %%
# 2차원 행렬을 생성
matrix = df[['국어', '영어']].values
print(matrix)
print()
matrix = np.array([[30,20], [10, 30], [30,40]])
print(matrix)


# %%
from sklearn import preprocessing

# 정규화 객체 생성 - 유클리디안 거리를 사용
norm = preprocessing.Normalizer(norm='l2')
print(norm.transform(matrix))


# %%
# 맨하턴 거리 (결과는 합치면 1)
norm = preprocessing.Normalizer(norm='l1')
print(norm.transform(matrix))


# %%
# max
norm = preprocessing.Normalizer(norm='max')
print(norm.transform(matrix))

다항과 교차항 특성

  • 기존 데이터에 데이터들을 곱하고 제곱을 해서 데이터를 추가하는 것

  • 특성과 타겟 사이에 비선형 관계와 존재할 때 사용하는 방식

  • 비선형 관계는 2개의 관계가 직선의 형태가 아니고 곡선의 형태인 것

  • 각 특성이 다른 특성에 영향을 줄 때 각 특성을 곱합 교차항을 가지고 인코딩

  • 다변량 분석(2개 이상의 컬럼을 가지고 분석)을 할 때 2개의 컬럼사이에 상관관계가 있는 경우가 있는데 이런 경우 2개의 컬럼 모두를 가지고 분석을 하게 되며 다중공선성 문제가 발생할 수 있다.

    • 어떤 컬럼의 값을 알면 다른 컬럼의 값을 예측할 수 있는 경우 발생할 수 있는 문제이다.
    • 이런 경우에는 2개의 컬럼을 1개의 컬럼으로 변환하는 작업을 해야 하는데(차원축소) 이런 경우 더하거나 곱하거나 제곱해서 새로운 값을 만들어 낸다.
  • PloynomialFeatures 클래스를 이용하는데 몇 차항까지 생성할 것인지 degree에 설정

    • 첫번째 데이터로 1을 추가할지 여부를 inclued_bias에 설정 (상수항 하나를 넣을것인가)
  • 연산식의 순서는 get_feature_names 메소드를 이용해서 확인 가능

degree=2
[1,2] -> [1,2,1,2,4]
[4,7] -> [4,7,16,27,49]
[값, 값, 제곱, 값*값, 제곱]

# 위 코드 이어서 
# %%
# 다항과 교차항을 만들어주는 객체를 생성
# degree=2 : 제곱한 것 까지 생성 
ploynomial = preprocessing.PolynomialFeatures(degree=2, include_bias=False)
result = ploynomial.fit_transform(matrix)
print(result)


# %%
# degree=3 : 세제곱
ploynomial = preprocessing.PolynomialFeatures(degree=3, include_bias=False)
result = ploynomial.fit_transform(matrix)
print(result)

표준화나 정규화는 직접 하는 경우가 많지만 다항식을 만드는 것은 머신러닝 알고리즘에서 자체적으로 처리하는 경우가 많다.

특성 변환

  • 데이터에 동일한 함수를 적용해서 다른 데이터로 직접 변환하는 것

  • pandas에서는 apply 메소드를 이용하고 sklearn에서는 preprocessing.FunctionTransformer 나 ColumnTransformer 클래스를 이용

  • FunctionTransformer 는 모든 열에 동일한 함수를 적용하고 ColumnTransformer 는 서로 다른 함수를 적용할 수 있다.

    • 객체를 생성할 때 적용할 함수를 설정해서 만들고 transform 메소드에 데이터를 대입하면 된다.
# 위 코드 이어서 
# 함수 적용하기 
matrix = np.array([[100, 200],[300, 150]])
print(matrix)

# 100을 결합하기  
def intconvert(x) : 
    return x +100

transformer = preprocessing.FunctionTransformer(intconvert)
result = transformer.transform(matrix)
print(result)


print(df['국어'])
print(df['국어'].apply(intconvert))

Outlier 감지

  • Outlier : 이상치나 극단치, 일반적인 데이터의 범위를 넘어선 값

1. z 점수를 이용하는 방법

  • 중앙값을 기준으로 표준편차가 3 또는 -3 범위의 바깥쪽에 있는 데이터를 Outlier로 간주

2. z 점수의 보정

  • z 점수는 데이터가 12개 이하이면 감지를 못함
    • 편차의 범위를 3.5로 늘리고 0.6745를 곱한 값

3. IQR(3사분위수 - 1사분위수) 이용

  • 1사분위수(25%)보다 1.5 IQR 작은 값이나 3사분위수(75%) qhek 1.5 IQR 큰 데이터를 Outlier로 간주
import numpy as np 
import pandas as pd

# array를 입력받아서 z 점수(평균의 표준편차3범위) 밖에 있는 데이터를 리턴해주는 함수
def z_score_outlier(ar) : 
    threshold = 3
    # 평균가져오기
    meandata = np.mean(ar)
    stdevdata =  np.std(ar)
    # ar의 요소를 y에 하나씩 대입하고 앞에 수식을 적용해서 결과를 가지고 다시 list를 만드는것 
    z_scores = [(y-meandata) / stdevdata for y in ar]
    return np.where(np.abs(z_scores) > threshold)

# 샘플 데이터 생성
featrues = np.array([
                    [10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 2330, 
                    5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 
                    20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 
                    13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4], 
                    [10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 
                    4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -3440, 4,10, 13, 20, 5, -30, 
                    4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 4,10, 13, 20, 5, -30, 
                    4,10, 13, 20, 5, -30, 4]])
result = z_score_outlier(featrues)
print(result)
# 데이터가 적으면 출력값(참고) : (array([1]), array([5])) # 2행 6열이 이상치이다.
# 데이터가 많을때 출력값(참고) : (array([0, 1]), array([32, 64]))


# %%
# z score 보정 - 범위를 3.5배로 늘리고 표준편차 0.6875를 곱해준다. 
def modify_z_score_outlier(ar) : 
    threshold = 3.5
    # 평균가져오기
    meandata = np.mean(ar)
    stdevdata =  np.std(ar) 
    z_scores = [0.6875 * (y-meandata) / stdevdata for y in ar]
    return np.where(np.abs(z_scores) > threshold)

result = modify_z_score_outlier(featrues)
print(result)


# %%
# IQR 이용 : 3사분위수 - 1사분위수의 +- 1.5 배 이상 차이나면 이상치로 간주
def iqr_outlier(ar) : 
    # 25% 와 75% 값 찾기 
    q1, q3 = np.percentile(ar,[25,75])
    print(q1, q3)
    # IQR 값 찾기 
    iqr = q3 - q1 
    # 25% 값과 1.5 iqr 보다 작은 값 찾기 
    lower = q1 - iqr * 1.5
    upper = q3 + iqr * 1.5
    return np.where((ar > upper) | (ar < lower))

result = iqr_outlier(featrues)
print(result)

Outlier 처리

1. 제거

  • 설문조사를 했는데 이상한 데이터가 입력된 것 같은 경우
  • 분석 목적에 맞지 않는 데이터인 경우
    • 내가 쓸려는 값하고 맞지 않는 값
    • 설문조사를 했는데 100세가 있어서 제외

2. 이상한 데이터로 표현해두고 특성의 하나로 간주

  • 따로 분석을 수행

3. outlier의 영향이 줄어들도록 특성을 변환

  • 값의 범위를 줄임(표준화, 정규화등)
  • 표준화할 때는 RobustScaler를 이용하는 것이 좋음
# To add a new cell, type '# %%'
# To add a new markdown cell, type '# %% [markdown]'
# %%
import numpy as np 
import pandas as pd

house = pd.DataFrame()
house['price'] = [100000, 200000, 150000, 100000000]
house['rooms'] = [1,2,3,100]
house['square'] = [11,23,16,3000]
print(house)


# %%
# 이상한 데이터 제거 : 방이 5개 이상 제거 
print(house[house['rooms']<6])


# %%
# 이상한 데이터를 별도로 표시
# 6보다 작으면 0 아니면 1을 대입 
house['outlier'] = np.where(house['rooms']<6, 0, 1)
print(house)


# %%
# 값의 범위 줄이기 - np.log는 자연로그를 계산 
house['log'] = [np.log(x) for x in house['rooms']]
print(house)

시계열 데이터

  • 날짜 및 시간에 관련된 데이터

1. pandas의 시계열 자료형

  • datatime64 : 부등호를 이용해서 크기비교를 할 수 있고 -를 이용해서 뺄셈을 할 수 있음
  • Period : 두 개의 날짜 사이의 간격을 나타내기 위한 자료형
  • 시계열 자료형을 별도로 구성하는 이유는 일정한 패턴을 만들기 쉽도록 하기 위해서

2. datetime64 생성

  • 문자열 데이터를 시계열로 변경 : pandas.to_datetiem() 이용
    • 날짜 형식의 문자열과 format 매개변수에 날짜 형식을 대입
import pandas as pd
import numpy as np 

df = pd.read_csv('../data/stock-data.csv')
print(df)

# 자료형 확인
print(df.info())

# Date 컬럼의 값을 시계열로 변경해서 추가 
df['newDate'] = pd.to_datetime(df['Date'])
print(df.info())

# 위와 같은 데이터프레임에서는
# 날짜를 index로 설정하는 경우가 많다
df.set_index('newDate', inplace=True)
print(df.head())
df.drop('Date', axis=1, inplace=True)
print(df.head())

3. Period

  • pandas.to_period 함수를 이용해서 datetime을 Period로 생성
    • freq 옵션에 기준이 되는 기간을 설정
  • freq 옵션
    • D : 1일 B 휴일 제외
    • W : 1주 H 1시간
    • M : 1개월(월말) T 1분
    • MS : 1개월(월초) S 1초
    • Q : 1분기말 L 1밀리초
    • QS : 1분기초 U 1마이크로초
    • A : 연말 N 1나노초
    • AS : 연초
    • B : 휴일 제외
    • H, T, S, L, U, N : 시간, 분, 초, 밀리초, 마이크로초, 나노초
import pandas as pd 

# 일정한 간격을 갖는 날짜 만들기
dates = ['2017-03-01', '2017-06-01', '2019-12-02']
# 날짜로 변경
pddates = pd.to_datetime(dates)
print(pddates)


# Period로 변환
pdperiod = pddates.to_period(freq='D')
print(pdperiod,'\n')

pdperiod = pddates.to_period(freq='M')
print(pdperiod,'\n')

pdperiod = pddates.to_period(freq='Q')
print(pdperiod,'\n')

pdperiod = pddates.to_period(freq='A')
print(pdperiod,'\n')

4. date_range()

  • 일정한 간격을 소유한 날짜 데이터의 집합을 생성

  • 매개변수

    • start : 시작 날짜
    • end : 종료 날짜
    • periods : 생성할 날짜 개수
    • freq : 이전의 freq와 동일
    • tz : 시간대 설정(‘Europe/London’, ‘Asia/Seoul’, ‘Africa/Abidjan’…)

5. 날짜 데이터에서 필요한 부분 추출하기

  • dt.year, dt.month, dt.day ...
  • 요일은 dt.weekday_name은 문자열로 dt.weekday 하면 숫자로 리턴(월요일이 0)
    • 화면에 출력할 때는 문자열로 하고 머신러닝에서 사용할 때는 숫자로 리턴 받습니다.
import pandas as pd
import numpy as np 

df = pd.read_csv('../data/stock-data.csv')

# Date 컬럼의 값을 시계열로 변경해서 추가 
df['newDate'] = pd.to_datetime(df['Date'])

df['year'] = df['newDate'].dt.year
print(df['year'])

6. python에서는 날짜는 datetime 패키지의 datetime 으로 제공

  • 날짜 형식의 문자열을 가지고 날짜 형식의 데이터를 생성

7. shift 함수를 이용하면 기존 날짜를 이동시키는 것이 가능

# To add a new cell, type '# %%'
# To add a new markdown cell, type '# %% [markdown]'
# %%
import pandas as pd 
import numpy as np 
from datetime import datetime

dates = [datetime(2017,1,1),
         datetime(2017,1,4),
         datetime(2017,1,7)]

ts = pd.Series(np.random.randn(3), index=dates)
print(ts)

print(ts.shift(-1))

8. resampling

  • 시계열의 빈도를 변환하는 것
  • 상위 빈도의 데이터를 하위 빈도의 데이터로 변환하는 것을 다운샘플링이라고 하고 반대의 과정을 업샘플링이라고 한다.
  • resampling(freq, how, fill_method, closed, label, kind)
    • freq : 리샘플링 빈도(M, Q, A등)
    • how : 집계함수를 지정하는 것으로 기본은 mean이고 first, last, max, median, min 등
    • fill_method : 업 샘플링할 때 데이터를 채우는 옵션으로 기본은 None 인데 ffill 이나 bfill을 설정해서 이전값이나 이후값으로 채울 수 있음
    • closed : 다운 샘플링을 할 때 왼쪽과 오른쪽 어느쪽을 포함시킬지 설정
    • label : 다운 샘플링을 할 때 레이블을 왼쪽 또는 오른쪽을 사용할것인지 여부
import pandas as pd 
import numpy as np 

# 일정한 간격ㅇ로 집계
ran = pd.date_range('11/3/2020', periods=20, freq='T')
print(ran)


ts = pd.Series(np.arange(20), index=ran)
print(ts)

# 5분 단위로 합계
print(ts.resample('5T').sum())

9. 날짜 데이터가 데이터프레임에 존재하는 경우 날짜 데이터를 인덱스로 설정하면 특정 시간단위로 집계를 하는 것이 쉬워진다.

시계열 이동 시간 윈도우

  • 통계적 수치를 계산 할 때 최근의 데이터에 가중치를 부여해야 한다는 개념
    • 평균을 구할 때 데이터 전체의 평균을 구하는 거 보다는 최근의 데이터 몇 개의 평균을 구하는 것이 미래를 예측할 때는 더 잘 맞을 가능성이 높다.
    • 이전 데이터와 최근의 데이터를 같이 사용할 거라면 최근의 데이터에 가중치를 부여하는 것이 미래를 예측할 때는 더 잘 맞을 가능성이 높다.

1. rolling 함수

  • 단순 이동 평균을 계산해주는 함수
  • window 매개변수에 데이터 개수를 설정하면 데이터 개수 단위로 연산을 수행

2. ewm 함수

  • 지수 이동 평균을 계산해주는 함수

  • 지수 이동 평균은 최근의 데이터에 가중치를 부여하는 방식의 평균

    • 주식 데이터는 이 평균을 사용한다.
  • 기간(span)을 설정하면 아래 수식으로 평균

    데이터가 3개인경우
    x1, x2, x3(가장최근데이터)
    (1-span)을 알파라고 한다. 알파를 계산할 때는 1/span 이 span 자리에 대입

    x3 + (1-(1-span))*x2 + (1-(1-span))^x3 / 1+(1-알파) + (1-알파)^

에이징커브
시간에 따라 변경되는 데이터를 가지고 예측할 때는 최근의 데이터에 가중치를 부여해야 한다.

x3 : 2500 (가장최근데이터)
x2 : 2000
x1 : 2200
^ : 제곱 

기간이 지날수록 반영율을 줄여나간다 
x3 : 2500  # 그대로 반영
x2 : (1- 1/3) * 2000
x1 : (1- 1/3)^ * 2200

지수 이동 평균
2500 + ((1 - 1/3) * 2000) + ((1 - 1/3)^ * 2200) /  1 + (1 - 1/3) + (1 - 1/3)^

지수 이동 평균

  • DataFram.ewm(span=가중치를 부여할 데이터 개수).mean()

알파 = 1/span

최근의 데이터 + (1-알파)이전데이터 + (1-알파)제곱 * 그 이전 데이터

  • 최근의 데이터 반영 비율을 높이고 이전 데이터의 반영 비율을 줄여서 계산하는 방식
  • 주가 데이터에 많이 사용
    • 주가는 최근의 데이터의 추세를 반영하는 것이 예측의 정확성을 높여주기 때문이다.
import numpy as np 
import pandas as pd 

#2020년 1월 1일 부터 월 단위로 5개의 데이터를 생성
timeindex = pd.date_range('01/01/2020', periods=5, freq="M")
df=pd.DataFrame(index=timeindex)
df['price'] = [10, 20, 30, 40, 50 ]
print(df)

#span을 2로 설정해서 지수이동평균 구하기
print(df.ewm(span=2).mean())

시계열 데이터에서의 누락된 값

  • 시간의 간격이 일정한 상태에서 데이터가 누락된 경우라면 제거를 하는 것보다는 패턴을 확인해서 데이터를 대입하는 것이 좋다.
  • DataFrame 의 interpolate 함수를 호출하면 누락된 값을 채워줍니다.

    • 매개변수가 없으면 선형으로 관계를 파악해서 채줘주고 method에 quadratic 을 설정하면 비선형으로 채워줍니다.
  • ax + b : 일차 방정식

    • 선형 : 데이터의 분포가 직선에 가까워집니다.
    • spearman
  • ax^ + bx + c : 이차 방정식 이상

    • 비선형 : 데이터의 분포가 곡선에 가까워집니다.
    • fearson, kendall
  • 머신러닝을 할 때도 회귀나 분류하기 전에 데이터의 분포를 확인해야 합니다.

  • 데이터의 분포를 확인 할 때는 산포도(scatter)를 많이 이용합니다.

# To add a new cell, type '# %%'
# To add a new markdown cell, type '# %% [markdown]'
# %%
import numpy as np 
import pandas as pd 

#2020년 1월 1일 부터 월 단위로 12개의 데이터를 생성
timeindex = pd.date_range('01/01/2020', periods=12, freq="M")
df=pd.DataFrame(index=timeindex)

# 누락된 데이터( 결측치 - None, null, np.nan) 만들기
df['price'] = [10, 20, np.NaN,30, 40, 50,np.NaN, 60, 70, 90, np.NaN, 110 ]

# 선형으로 누락된 값 채우기
print(df.interpolate())


# %%
df['price'] = [10, 20, np.NaN,303, 404, 506,np.NaN, 3033, 705, 2000, np.NaN, 1310 ]

# 비선형으로 누락된 값 채우기
# method 를 주지 않았을 때는 부자연스러운 값들이 생성됨
print(df.interpolate())

# 비선형으로 누락된 값 채우기
# method='quadratic' 를 입력하니 그렇지 않을때보다 조금은 자연스러워졌다.
print(df.interpolate(method='quadratic'))
728x90
반응형

'Language_Study > Python' 카테고리의 다른 글

[Python] 11-2.Dataframe응용과 시각화  (0) 2021.01.19
[Python] 11-1.DataFrame응용과 시각화  (0) 2021.01.19
[Python] 10-1.데이터전처리  (4) 2021.01.19
[Python] 9.시각화  (0) 2021.01.19
[Python] 8.pandas  (0) 2021.01.19