✔ 시계열 데이터

실습

  • 문자열을 시계열 데이터로 변환
df=pd.read_csv('./data/stock-data.csv')
print(df.head())
df.info()
# date는 날짜 데이터 같은데 object type으로 되어있다.
# 날짜 자료형을 변경해서 새로운 필드로 저장하기
df['NewDate']=pd.to_datetime(df['Date'])
df.info()
# 새로 만들어진 날짜 컬럼을 인덱스로 지정하고 기존의 날짜 컬럼 삭제
df.set_index(df['NewDate'], inplace=True)
df.drop('Date',axis=1, inplace=True)
df.head()
  • 여기에 샘플 데이터를 추가해보자.
# 첫 번째 데이터는 날짜로 변경 가능한 데이터
# 두 번째 데이터는 날짜로 변경 불가능한 데이터 (TM 오타)
date_strings=np.array([
    '03-04-2005 11:35 PM', '04-09-2005 09:09 TM'])
# 첫 번째 데이터는 날짜로 변경 가능한 데이터
# 두 번째 데이터는 날짜로 변경 불가능한 데이터 (TM 오타)
date_strings=np.array([
    '03-04-2005 11:35 PM', '04-09-2005 09:09 TM'])
# 예외 발생
# print([pd.to_datetime(date, format='%d-%m-%Y %I:%M %p') 
for date in date_strings])
# errors 관련 (예외) 옵션이 존재한다.
print([pd.to_datetime(date, format='%d-%m-%Y %I:%M %p',
errors='ignore') for date in date_strings])
  • [Timestamp('2005-04-03 23:35:00'), '04-09-2005 09:09 TM']
  • 두 개가 다르게 나옵니다.
  • list는 2개의 데이터 자료형이 달라도 상관없지만,
    array나 DF으로 변환해서 사용하는 경우에는 문제가 생길 수 있습니다.4
print([pd.to_datetime(date, format='%d-%m-%Y %I:%M %p',
errors='coerce') for date in date_strings])
# 변환이 되지 않는 경우에는 coerce는 NaT로 변환해버림
# 이러면 array나 df 변환 시 datatype은 보존할 수 있다.
print([pd.to_datetime(date, format='%d-%m-%Y %I:%M %p',
errors='raise') for date in date_strings])
# errors='raise'는 default로 처음과 같이
# 에러가 발생하면 예외발생처리하고 종료해버린다.
  • 일정한 기간을 의미하는 Period
    - 날짜 데이터를 일정한 간격 단위로 사용하고자 할 때 사용하는 자료형
    - pd의 to_period 함수를 이용하는데, freq 옵션에 주기를 설정함
D : 일
W : 주
M : 1개월(월말)
MS : 1개월(월초
Q : 분기말
QS : 분기초
A : 연말
AS : 연초
B : 월화수목금
H : 1시간
T : 1분
S : 1초
L : 1밀리초
U : 1마이크로초
N : 1나노초
date_strings=np.array([
    '2023-01-01', '2023-02-02','2023-02-20', '2023-04-05'])
pddates=pd.to_datetime(date_strings)
pr_months=pddates.to_period(freq='M')
pr_months 
# 이렇게 된다면 '일' 이 잘리고 '월' 까지만 남는다.
  • 주기를 갖는 날짜 생성
date_range 함수 이용합니다.
	- start : 시작 날짜
   	- end : 종료 날짜
    - periods : 생성할 날짜 개수
    - freq : 주기
    - tz : 시간대 설정('Asia/Seoul')
    - tz는 시간대역이고 중요한 정보이기에 거의 생략을 못함
  • 일정한 주기를 가지고 데이터가 생성되는데, 생성된 시간을 알지 못하는 경우 사용
  • 시작 시간만 알고 있는 경우
# 2023년 1월 1일부터 월 단위로 12개를 생성해보고 싶어
ts_ms=pd.date_range(start='2023-01-01',
                    periods=12,
                    freq='MS', # 월초
                    tz='Asia/Seoul')
print(ts_ms)
  • 년월일 분리
    - datetime64 타입에서 dt.단위에 해당하는 속서응ㄹ 호출
    - 년도를 추출하고자 하는 경우에는 dt.year
  • 날짜 차이
    - datetime64는 뺄셈을 연산자 오버로딩을 해놓았기 때문에 가능함
  • datetime64를 인덱스로 설정해서 사용하기
# 데이터를 가져와서 문자열을 날짜로 다시 변경해두자.
df=pd.read_csv('./data/stock-data.csv')
df['NewDate']=pd.to_datetime(df['Date'])
df.set_index('NewDate', inplace=True)
df.drop('Date',axis=1, inplace=True)
# df.head()
# 날짜 인덱스여서 일부분만 가지고도 인덱싱 가능합니다.
# 문자열은 죽었다 깨어나도 안됩니다.
df_y=df['2018']
print(df_y.head())
# 범위도 가능하다
# 어떤 컬럼을 할건지까지 할거면 loc 해주자.
df_y=df.loc['2018-06-25':'2018-06-30', 'Start':'Low']
print(df_y.head())
  • 시계열에서의 결측치 처리
    - 결측치를 제거
    - 대치법
  • 대치법(Imputation)
    - 누락된 데이터의 이전이나 이후 값으로 채워넣는 것
    - 이동 평균으로 데이터를 대입
    - 보간법
  • 보간법
    - 인접 데이터를 사용해 누락 데이터를 추정해서 대입
    - DF의 interplate 함수를 이용하며, 기본은 선형이다.
    - method 속성에서 quadratic을 설정하면 비선형으로도 추정할 수 있다.
    - time을 설정한다면 기산을 기준으로 보간합니다.
    - limit_direction 매개변수를 이용해서 보간 방향을 설정할 수 있다.
# 결측치 처리
time_index=pd.date_range('01-01-2023', periods=5, freq='M')
dataframe=pd.DataFrame(index=time_index)
dataframe['Sales']=[1.0,2.0,np.nan, np.nan, 5.0]
# print(dataframe)
# 앞의 데이터로 채우기
# print(datafram.ffill())
# 선형 보간 - 일차식
# print(dataframe.interpolate())
# 비선형 보간 - 다항식 
# print(dataframe.interpolate(method='quadratic'))
  • 이동시간 윈도우
    1. 단순이동 평균
    - 현 위치에서 일정한 개수만큼의 이전 데이터와의 통계를 계산
    - 이 때 사용되는 함수는 피보나치
    - rolling 함수를 이용함
    2. 지수 이동 평균(주가 이동 평균)
    - 최근의 데이터에 가중치를 두는 방식
    - 알파 값을 이용함
    - α:1-span(기간)
    - (현재값 + (1-α)*현재에서 하나 이전의 값+(1-α)(1-α)*현재에서 두개 이전의 값....)/(1+(1-α)+(1-α)(1-α)+..)
    - ewm 함수를 이용함
dataframe['Stock_Price']=[1,2,3,4,5]
# 단순 이동 평균
print(dataframe.rolling(window=2).mean())
# 지수 이동 평균
print(dataframe.ewm(span=2).mean())

  • resampling
    - 시계열의 빈도를 변환하는 과정입니다.
    - 시계열은 종종 downsampling을 합니다.
  • downsampling을 하는 상황
    - 원본 데이터의 시간 단위가 실용적이지 않은 경우(너무 자주 측정)
    - 계절 주기 특성을 파악하기 위한 경우
    - 한 데이터를 낮은 빈도로 측정된 다른 데이터와 맞춰주기 위한 경우
  • upsampling을 하는 상황(권장X)
    - 시계열이 불규칙적인 상황
    - 입력이 서로 다른 빈도로 샘플링된 상황
  • 계절성 데이터
    - 일정한 주기를 가지고 변화
    - 이를 계절성 시계열 이라고 한다.
    - 반복적인 동작을 하지만, 기간이 가변적인 경우는 순환성 시계열 : 주식

✔ 영상 처리와 컴퓨터 비전

✔ OpenCV

설치

  • pip install opencv-python

확인 (in jupyter)

  • import cv2 print(cv2.__vsrsion__)

윈도우 제어

윈도우 생성

  • cv2.namedWindow(윈도우이름:str[, flag:int]) -> None
  • flags에는 0(윈도우 크기 재조정 가능) 이나 1(크기가 자동 조절) 설정

영상을 윈도우에 표시하기

  • cv2.imshow(윈도우이름 :str, matrix:ndarray)->None

윈도우 제거

  • cv2.destroyAllWindows() -> None
# 모든 값을 200으로 채운 2차원 행렬 생성
image=np.zeros((200,400), np.uint8)
image[:]=200
cv2.namedWindow("윈도우 생성")
cv2.imshow("윈도우 생성", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

도형 그리기

직선 및 사각형 그리기

  • cv2.line(img, 좌표1, 좌표2, 색상 , 두께, 선모양)
  • cv2.rectangle(img, 좌표1,좌표2, 색상, 두께, 선모양)
  • cv2.clipLine(img, 좌표1,좌표2)

원 그리기

  • cv2.circle(img, center, radius, color, thickness, lineType)
  • thickness를 -1로 설정하면 color로 채운 원을 그립니다.
# 흰색 이미지 배열 생성
# 자료형을 np.uint8 로 설정
# 이미지는 0 - 255 사이의 숫자만 이용
# 이미지가 2차원이면 흑백, 3차원이면 컬러
image=np.zeros(shape=(512,512,3), dtype=np.uint8)+255
# 원 만들자
# 두께를 -1로 한다면 채워진 원이 나올 것이다.
cv2.circle(image,(image.shape[0]//2, image.shape[1]//2), radius=50,
color=(0,0,255), thickness=-1)
# RGB -> BGR 헤더쪽에서 거꾸로 되어있거든
# 윈도우에 이미지 출력
cv2.imshow("image",image)
#키보드 입력 대기
cv2.waitKey(0)
#윈도우 종류
cv2.destroyAllWindows()

다각형 그리기

  • polyline
  • fillPoly 등...

문자열 출력

  • putText

이미지 입출력

이미지 읽어오기

  • cv2.imread(이미지파일 경로, 이미지 옵션)
  • 옵션
    - -1 : ALPHA 채널 포함
    - 0 : 흑백
    - 1 : 컬러
    - 2 : 16이나 32비트 영상으로 변환 (기본은 8 비트)

이미지를 현재 뷰에 출력

  • plt.imshow(array-like or PIL image Data)

이미지 데이터

  • 흑백 : 0-255 사이의 정수 2차원 배열
  • 컬러 : 0-255 사이의 정수 3차원 배열
    BGR로 리턴하기에, cv2.cvtColor 함수를 이용해서 RGB로 변환해서 사용

OpenCV에서는 옵션을 정수로 설정합니다.

이미지 데이터 불러오기

image=cv2.imread('./data/plane.jpg', cv2.IMREAD_GRAYSCALE)
# 이미지 데이터 흑백으로 가져오기
print(image.shape)
# C나 C++, python에서는 상수를 정의할 때 이름을 사용한 경우면
# 상수 대신에 값을 직접 입력해도 됩니다.
# cv2.IMREAD_GRAYSCALE 대신 0 입력해도 된다.
# 하지만 상수 이름을 사용하는 것을 권장합니다.
plt.imshow(image, cmap='gray')
plt.axis('off')
plt.show()

컬러 이미지 출력

image=cv2.imread('./data/plane.jpg', cv2.IMREAD_COLOR)
# 이미지 데이터 흑백으로 가져오기
print(image.shape)
# opencv는 rgb로 가져오는게 아닌, bgr로 가져온다.
# color는 cmap을 안주면 됩니다.
img_rgb=cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
plt.axis('off')
plt.show()

이미지 저장

  • cv2.imwrite(파일경로, 이미지 데이터, params=옵션)
  • 옵션은 압축률
image=cv2.imread('./data/plane.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imwrite('./data/plane_new.jpg',image)

여러개 이미지를 한 영역에 표시하기

# 4개의 이미지를 2*2 로 출력
DATA_DIR='./data/'
imgBGRs=[]
imgBGRs.append(cv2.imread(DATA_DIR+'lena.jpg'))
imgBGRs.append(cv2.imread(DATA_DIR+'apple.jpg'))
imgBGRs.append(cv2.imread(DATA_DIR+'baboon.jpg'))
imgBGRs.append(cv2.imread(DATA_DIR+'orange.jpg'))
imgRGBs=[]
for i in imgBGRs:
    imgRGBs.append(cv2.cvtColor(i,cv2.COLOR_BGR2RGB))
# 여러 개의 영역 만들기
fig, ax=plt.subplots(2,2, figsize=(10,10), sharey=True)
length=len(imgRGBs)
# sharey는 축을 공유하는 것
for i in range(length):
    ax[i//2][i%2].axis('off')
    ax[i//2][i%2].imshow(imgRGBs[i],aspect='auto')
plt.show()
  • 같은 종류라면 리스트를 확인해보자.

비디오 캡쳐

비디오 캡쳐

  • cv2.VideoCapture()
    - 매개변수로 파일 경로나 device 대입 가능
    - device는 카메라 번호이다.
## 카메라 캡쳐
# 문자열 출력 함수
def put_string(frame, text, pt, value, color=(120,200,90)):
    text+=str(value)
    shade=(pt[0]+2,pt[1]+2) #좌우 상하 2정도 추가
    font=cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(frame, text,shade, font, 0.7, (0,0,0), 2) #그림자
    cv2.putText(frame, text,pt, font, 0.7, color, 2)
# 현재 디바이스의 첫번째 카메라 연결
capture=cv2.VideoCapture(0)
# 카메라 연결이 안된다면, 종료
if capture.isOpened()==False:
    raise Exception('카메라 연결 안됨')
while True:
    ret, frame=capture.read()
    if not ret:
        break
    if cv2.waitKey(30)>=0:
        break
    exposure=capture.get(cv2.CAP_PROP_EXPOSURE)
    put_string(frame, "EXPOS: ", (10,40), exposure)
    title="View Frame From Camera"
    cv2.imshow(title, frame)
capture.release()

wifi에 연결된 스마트폰 카메라 캡쳐

  • 모바일 디바이스에 droid cam 어플리케이션 설치
# wifi smartphone
cap=cv2.VideoCapture('http://IP:port/video') 
#iphone : video, android : mjpegfeed
# frame_size : 카메라 해상도 확인
frame_size=(int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),
           int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
print('frame_size= ' ,frame_size) #이거 값이 뭐라도 나와야 함
while True:
    # 실제 스마트폰 카메라가 촬영하고 있는 영상을 가져오기
    retval, frame=cap.read()
    if not retval:
        break
    # 영상을 화면에 출력하기
    cv2.imshow('frame',frame)
    # 키보드 대기하기
    key=cv2.waitKey(25)
    if key==27: #27이 esc이다.
        # esc를 누르면 종료한다.
        break
if cap.isOpened():
    cap.release()
cv2.destroyAllWindows()

비디오 파일 녹화도 가능하답니다.

  • videoWriter 함수를 이용합니다.

연산

영상 속성과 픽셀 접근

  • OpenCV 영상은 numpy.ndarray를 이용해서 표현
  • shape나 dtype 그리고 astype, reshape를 사용할 수 있습니다.
  • 이들을 확인해서 타입과 shape를 맞추는 작업매우 중요합니다.
    - 이미지를 가지고 수행하는 머신러닝은 모든 이미지의 데이터동일한 구조를 가져야 합니다.
    - 학습된 모델을 이용할 때도, 학습된 모델이 사용한 타입과 shape을 확인해서 데이터를 만들어서 사용해야 합니다.

크기 변경

  • resize라는 함수를 이용합니다.
  • 이미지 데이터와 이미지의 크기를 튜플로 대입해주면 됩니다.
  • 머신러닝에서 사용하는 사이즈는 대부분 (32x32), (64x64), (96x96), (128x128), (256x256)이다.
    - 정사각형 구조?
    - 데이터를 바라보는 시점이 대부분 "열" 방향으로 본다.
    - 이미지 딥러닝은 그러면 안된다. 열, 행 방향으로 일정한 비율로 보고 특징을 추출해나간다. 둘의 비율이 달라진다면 한쪽으로 편향된 결과를 얻게 되기에 결과를 믿을 수 없다.
  • 실습
img=cv2.imread('./data/lena.jpg',cv2.IMREAD_GRAYSCALE)
# print('img shape', img.shape)
# 2차원 이미지를 1차원으로 변경해주자. - flatten
img=img.flatten()
# 1차원으로 잘 변경되었다.
# print('img shape', img.shape)
# 이걸 또 3차원으로 바꿔?
# -1은 나머지를 "전부" 사용한다는 의미입니다.
# 262144/512/512가 첫 번째 차원입니다.
# 두개만 계산하고 나머지 그냥 넣어서 좀 더 편리하게 함
img=img.reshape(-1,512,512)
# 첫 번째 차원은 1이 됩니다.
print('img shape',img.shape)
img=cv2.imread('./data/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE)
img=cv2.resize(img, (64,64)) #좀 깨져보인다.
plt.imshow(img, cmap='gray')
plt.axis('off')
plt.show()

픽셀이나 영역 선택

  • ROI(Region of Interset - 관심 영역)
    - 이미지 내의 특정 부분을 선택
    - 분석 : Return On Investment, 투자 대비 수익률
    - 둘 다 알고 있자...
img=cv2.imread('./data/lena.jpg', cv2.IMREAD_GRAYSCALE)
img[100,200]=0
img[100:400, 200:300]=0
plt.imshow(img, cmap='gray')
plt.axis('off')
plt.show()
# 이미지의 특정 부분을 선택하는 것 : ROI
# 이미지 전처리의 핵심 중 하나가 
#ROI 부분을 다른 부분과 확연하게 구분되도록 하는 것

채널 접근

  • 컬러 이미지에서 특정한 색상에 접근하는 것
img=cv2.imread('./data/lena.jpg')
img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print(img.shape)
# shape : 가로, 세로, 색상 채널
# 색상채널 접근때리기
# 0, 1, 2 있는데 0 이 R인걸로 보아 RGB 형태네
img[100:400,200:300, 0]=0 
# R값이 빠지니까 CYAN으로 변한 것을 볼 수 있다.
plt.imshow(img)
plt.axis('off')
plt.show()

윈도우 영역 내에서 ROI 설정

  • selectROI(윈도우이름, 이미지[, showCrosshair[,fromCenter])->retval
  • 윈도우에서 마우스를 이용해서 선택 영역을 만드는 것
  • 선택을 종료하고자 할 때는, space bar / enter를 누르면 됩니다.
  • 선택을 취소하고자 할 때는 c키를 누릅니다.
  • 결과는 (x, y, width, height)의 튜플로 리턴됩니다.
img=cv2.imread('./data/lena.jpg')
img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
roi=cv2.selectROI(img)
print('roi : ', roi)
# 선택 영역만 추출
img=img[roi[1]:roi[1]+roi[3], roi[0]:roi[0]+roi[2]]
cv.imshow("IMG",img)
cv2.waitKey()
cv2.destroyAllWindows()

영상 복사

  • 영상을 복사할 때는 numpy의 copy함수나 zeros같은 함수를 이용해서 빈 배열을 만들고 데이터를 복사함

채널 분리

  • cv2.split(이미지데이터)

채널 병합

  • cv2.merge([채널 데이터 나열])
img=cv2.imread('./data/lena.jpg')
# img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 채널 분할
b, g, r=cv2.split(img)
# 채널 병합
img=cv2.merge([b,g,r])
cv2.imshow("IMG",img)
cv2.waitKey()
cv2.destroyAllWindows()

컬러 공간 변환

  • cvtColor(이미지, 변환코드[,dst])->dst
  • dst 자리에 배열을 설정하면, 배열에 결과가 저장
  • 컬러 영상 처리를 하다 보면, HSV나 YCrcb 포맷으로 처리해야 하는 경우가 발생
    - 이미지 머신러닝에서는 jpg나 png를 사용하는 경우가 많아서, 컬러 변환 출력 정도만 사용
  • 변환 코드
cv2.COLOR_BGR2GRAY
cv2.COLOR_GRAY2BGR
cv2.COLOR_BGR2HSV
cv2.COLOR_HSV2BGR
  • COLOR가 있는 데이터를 gray로 변환하는 경우가 종종 있는데, 이 경우는 특정 영역과 다른 영역의 구분을 뚜렷하게 하고자 하는 경우에 사용합니다.

회전

  • 입력된 2차원 배열을 수직, 수평 양축으로 뒤집기
  • cv2.flip(이미지, flipCode)->dst
  • flipCode = 0, 1, -1
    - 0 : x축 기준 위아래 뒤집기
    - 1 : y축 기준 위아래 뒤집기
    - -1 : 양 축을 기준으로 뒤집기
  • 전치 도 생각해보자.
    - 열과 행을 치환하는 것
    - cv2.transpose(src)->dst
img=cv2.imread('./data/flip_test.jpg')
# flip_img=cv2.flip(img,-1)
# plt.imshow(flip_img)
# transpose : 행 열 전치하기
# transpose_img=cv2.transpose(img)
# plt.imshow(transpose_img)
# 회전 : rotate
rotate_img=cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
rotate_img=cv2.rotate(img, cv2.ROTATE_180)
rotate_img=cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
plt.imshow(rotate_img)
plt.axis('off')
plt.show()

Affine 변환 - 또 다른 회전

  • 이미지 데이터를 행렬과 연산해서 변경
  • scale, angle, translate
    - 영상처리 분야에서는 translate는 잘 사용하지 않는다.
  • cv2.getRotationMatrix2D(center, angle, scale)->Matrix 함수를 이용함
    - 어디를 기준으로 돌릴거냐의 문제입니다.
  • 반환된 행렬을 가지고 Matrix[:,2]+=(tx,tx)를 이용하면, translate도 구현합니다.
  • 게임 분야에서 많이 쓰입니다.
    - 좌표 움직이게 하는거 등등...
src=cv2.imread('./data/lena.jpg')
src=cv2.cvtColor(src, cv2.COLOR_BGR2RGB)
rows,cols,channels=src.shape
# 중앙을 기준으로 45도 회전, 0.5배 축소 이미지
M1=cv2.getRotationMatrix2D((rows/2,cols/2), 45, 0.5)
src=cv2.warpAffine(src,M1,(rows,cols))
plt.imshow(src)
plt.axis('off')
plt.show()

  • 실제로 회전을 가장 많이 사용하긴 한다.

산술 연산, 비트 연산, 비교 연산 등 가능

  • 산술연산을 할 때, 주의해야 하는데, 덧셈이나 뺼셈을 직접 수행하는 경우, 255보다 크거나 0보다 작은 값이 만들어 질 수 있는데, 이 경우에 overflow underflow 발생할 수 있는 문제가 있다.
  • numpy는 결국 c언어라 256으로 나눈 값이 저장이 됩니다.
  • add 나 sub같은 함수를 제공하는데, 이 함수들은 255가 넘으면 255, 0보다 작으면 0 으로 설정함
    - 즉, 산술 연산을 직접 사용하면 안된다. 함수를 이용하자.
profile
밀가루 귀여워요

0개의 댓글