Apache Airflow Installation

강의 홍보

개요

  • NiFi와 같은 용도의 소프트웨어이며, 현재 가장 인기 있는 오픈소스 데이터 파이프라인 도구라고 할 수 있다.
  • 보통은 시스템에 경로를 설정한다. 그런데, 본 장에서는 가상환경 설정 후 진행하는 것으로 했다.
  • 가상 환경은 virtualenv 를 통해서 진행한다.
  • 그 후에 가상 환경에 접속한다.
$ source venv/bin/activate
(venv) $

Step 01. 환경변수 설정

  • 우선 pip 으로 설치 하기에 앞서서 환경 변수를 임시로 설정한다.
  • 해당 환경 변수가 설정된 곳으로 airflow 설치 관련 폴더 및 파일들이 다운로드 될 것이다.
(venv) $ export AIRFLOW_HOME="$(pwd)"
(venv) $ echo $AIRFLOW_HOME
/Users/evan/Desktop/data_engineering_python/install_files/airflow

Step 02. 라이브러리 설치

  • 이제 airflow 설치를 진행한다.
  • 이때, 설치 명령어에 따른 옵션은 아래 그림에서 살펴보기를 바란다.

airflow_01.png

Apache NiFi Installation

강의 홍보

개요

  • 데이터 엔지니어링에 필요한 기본적인 인프라를 설치 진행하는 튜토리얼을 만들었다.
  • 기본적으로 교재에 충실하지만, 약 1년전에 쓰인 책이라, 최신 버전으로 업그레이드 하였다.

Apache NiFi 설치과정

  • 먼저 웹사이트에 방문하여 필요한 파일을 다운로드 받는다.
  1. wget을 이용해서 NiFi를 현재 디렉터리에 내려받는다.
$ wget https://downloads.apache.org/nifi/1.14.0/nifi-1.14.0-bin.tar.gz
--2021-09-06 13:10:55--  https://downloads.apache.org/nifi/1.14.0/nifi-1.14.0-bin.tar.gz
Resolving downloads.apache.org (downloads.apache.org)... 135.181.214.104, 135.181.209.10, 88.99.95.219
Connecting to downloads.apache.org (downloads.apache.org)|135.181.214.104|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1417663663 (1.3G) [application/x-gzip]
Saving to: ‘nifi-1.14.0-bin.tar.gz’

nifi-1.14.0-bin.tar.gz                      100%[==========================================================================================>]   1.32G  5.27MB/s    in 4m 13s
  1. .tar.gz 파일의 압축을 푼다.
$ tar -xvf nifi-1.14.0-bin.tar.gz
$ ls
nifi-1.14.0             nifi-1.14.0-bin.tar.gz
  1. nifi-1.14.0 의 디렉터리가 생겼을 것이며, 해당 디렉터리로 가서 다음 명령어를 실행한다.
$ cd nifi-1.14.0
$ bin/nifi.sh start
nifi.sh: JAVA_HOME not set; results may vary

Java home: 
NiFi home: /Users/evan/Desktop/data_engineering_python/install_files/nifi-1.14.0

Bootstrap Config File: /Users/evan/Desktop/data_engineering_python/install_files/nifi-1.14.0/conf/bootstrap.conf

The operation couldn’t be completed. Unable to locate a Java Runtime.
Please visit http://www.java.com for information on installing Java.
  • 자바가 이미 설치가 되어 있다면 정상적으로 실행이 된다.
  • 그러나, 자바가 설치가 되어 있지 않다면 위 에러와 같이 별도로 자바 환경 설치를 해야 한다.

3.1 자바 설치 및 환경변수 지정

LSTM을 활용한 주식가격 예측

강의 홍보

LSTM과 RNN의 개요

  • RNN은 자연어처리에서 사용되는 대표적인 알고리즘
    • 순환신경망으로 표현됨
    • 활용범위: 음성 인식, 언어 모델링, 번역, 이미지 주석 생성

기업 요청 샘플 (수강생) - Python Dash를 활용한 대시보드

강의 홍보

개요

  • 보안 로그 파일을 업로드한 뒤, 점검 결과를 자동으로 출력해주도록 한다.
  • (수강생의 도전) 보안 로그 파일을 업로드 한 뒤, CPU 사용률이 70%가 넘으면 경고 메시지를 뛰우도록 한다.

Chapter 1. 로그데이터 분석 및 확인

  • 먼저 CPU가 들어있는 로그데이터를 확인한다.
    • 골든시스에서 제공한 Sample 데이터를 근거로 랜덤하게 데이터를 생성했다. 파일명: (cpu_test.txt)
Dorm_E_116.95#
Dorm_E_116.95#sh logg
Dorm_E_116.95#sh logging 
Syslog logging: enabled (0 messages dropped, 1 messages rate-limited, 0 flushes, 0 overruns, xml disabled, filtering disabled)

No Active Message Discriminator.

No Inactive Message Discriminator.

    Console logging: level debugging, 2178 messages logged, xml disabled,
                     filtering disabled
    Monitor logging: level debugging, 244 messages logged, xml disabled,
                     filtering disabled
    Buffer logging:  level debugging, 2178 messages logged, xml disabled,
                    filtering disabled
    Exception Logging: size (4096 bytes)
    Count and timestamp logging messages: disabled
    File logging: disabled
    Persistent logging: disabled

No active filter modules.

    Trap logging: level informational, 2176 message lines logged
        Logging Source-Interface:       VRF Name:
          
Log Buffer (100000 bytes):
17:19:23: %PM-4-ERR_DISABLE: storm-control error detected on Gi1/0/36, putting Gi1/0/36 in err-disable state
Jul  7 17:19:23: %STORM_CONTROL-3-SHUTDOWN: A packet storm was detected on Gi1/0/36. The interface has been disabled.
Jul  7 17:19:25: %LINK-3-UPDOWN: Interface GigabitEthernet1/0/36, changed state to down
Jul  7 17:19:53: %PM-4-ERR_RECOVER: Attempting to recover from storm-control err-disable state on Gi1/0/36
Switch#show processor cpu
CPU utilization for five seconds: 4%/1%; one minute: 3%; five minutes: 3%
.
.
.
  • 업무 수행 시, 위와 같은 데이터를 생성한다. 그 후에, 점검일지 파일을 작성한다.
    • 점검일지 파일 Sample /img/programming/2021/08/dash_cpu_logdata/log_01.png log_01.png

(1) 문제점 진단

  • 통상적으로 위와 같이 명령어를 입력한 뒤 결괏값을 찾아 수기로 입력하여 작성하도록 함
  • 일일이 확인해야 하는 번거로움이 있다보니, 이를 자동으로 처리할 수 있는 툴 제작 의뢰를 받음

(2) 해결방안

  • 명령어 및 결괏값이 일정한 패턴이 있기 때문에, 문자열 매칭을 통해 전처리가 가능한 것을 확인
  • 또한, Dash 프레임워크를 통해 비교적 간단하게 대시보드를 만들 수 있음에 착안하였다.

(3) 배경지식

Chapter 2. 문자열 전처리 함수 만들기

  • 우선 Jupyter Lab에서 간단한 테스트 함수를 만들어 보았다.
  • 전체 코드는 아래와 같다.
    • 파일을 불러온 뒤 우선 각 코드 라인 중에서 CPU utilization 가 있는 텍스트만 남기고 그 외에는 모두 삭제한다.
    • 여기에서 다른 명령어의 결괏값을 확인하다면, if else 구문으로 계속적으로 확장할 수 있을 것이다.
    • 그 후에, 각 re.sub 함수를 활용하여 수치만 뽑아낸다.
    • 이를 각 데이터 프레임에 추가한 것이다.
import pandas as pd
import re

def text_cleanser(FILE_PATH):
    with open(FILE_PATH, 'r') as f:
        logLines = f.read().splitlines()
    cleaned_lines = [x for x in logLines if "CPU utilization" in x]
    clean_text = re.sub('/[0-9]%', '', cleaned_lines[0])
    print("temp:", clean_text)
    result_list = re.findall("\d+", clean_text)
    return result_list
        
FILE_PATH = "data/cpu_test.txt"
result_list = text_cleanser(FILE_PATH)
result_list
  • 위 파일을 Jupyter lab에서 실행하면 아래와 같은 결괏값이 출력될 것이다.
temp: CPU utilization for five seconds: 4%; one minute: 3%; five minutes: 3%
['4', '3', '3']
  • 출력한 결과물을 pandas 데이터 프레임에 적용한 결과는 아래와 같다.
data = pd.DataFrame({"분류":["cpu"],
                     "점검내용": ["CPU 사용률 점검 및 불필요한 프로세스 확인"],
                     "점검기준": ["MEM 임계치: 70% (MAX)"],
                     "점검방법": ["show processes cpu | in five"],
                     "5초 동안 CPU 사용률": [result_list[0]], 
                     "1분 동안 CPU 사용률": [result_list[1]], 
                     "5분 동안 CPU 사용률": [result_list[2]], 
                    })
data

log_02.png

네이버 뉴스 댓글 크롤링 대시보드 만들기 with Heroku

강의 홍보

1. 개요

  • 기존 웹크롤링은 주로 코드에 기반한 소개가 주를 이루었음
  • 본 장에서는 가급적 사용자 기준에 맞춰서 뉴스 URL만 입력하면 댓글 수집할 수 있는 기능 소개함

2. 라이브러리

  • 크롤링 및 대시보드 작업을 위한 필수 라이브러리는 다음과 같음 (requirements.txt)
colorama==0.4.4
dash==1.21.0
gunicorn==20.1.0
numpy==1.19.4
pandas==1.2.0
beautifulsoup4==4.9.3
openpyxl==3.0.7
requests==2.26.0
  • 위 파일을 프로젝트의 가장 최상단에 위치시켜 놓는다.
  • 설치 진행 시에는 pip install -r requirements.txt 해도 좋고, 아니면 개별적으로 설치를 해도 좋다.

3. 코드 설명

  • 본장에서는 디테일한 코드 설명은 넘어가도록 한다.

(1) 크롤링 코드

  • 먼저 크롤링 코드는 다음과 같다.
# 크롤링 라이브러리
from bs4 import BeautifulSoup
import requests
import re

# 데이터프레임
import pandas as pd

# 샘플 URL을 적용한다. 
url = "https://news.naver.com/main/read.naver?mode=LSD&mid=shm&sid1=100&oid=022&aid=0003609357" 

def get_df(url):
    # 댓글을 달 빈 리스트를 생성합니다.
    List = []
    url = url
    oid = url.split("oid=")[1].split("&")[0]
    aid = url.split("aid=")[1]
    page = 1
    header = {
        "User-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
        "referer": url,

    }
    while True:
        c_url = "https://apis.naver.com/commentBox/cbox/web_neo_list_jsonp.json?ticket=news&templateId=default_society&pool=cbox5&_callback=jQuery1707138182064460843_1523512042464&lang=ko&country=&objectId=news" + oid + "%2C" + aid + "&categoryId=&pageSize=20&indexSize=10&groupId=&listType=OBJECT&pageType=more&page=" + str(
            page) + "&refresh=false&sort=FAVORITE"
    # 파싱하는 단계입니다.
        r = requests.get(c_url, headers=header)
        cont = BeautifulSoup(r.content, "html.parser")
        total_comm = str(cont).split('comment":')[1].split(",")[0]

        match = re.findall('"contents":([^\*]*),"userIdNo"', str(cont))
        # 댓글을 리스트에 중첩합니다.
        List.append(match)

        # 한번에 댓글이 20개씩 보이기 때문에 한 페이지씩 몽땅 댓글을 긁어 옵니다.
        if int(total_comm) <= ((page) * 20):
            break
        else:
            page += 1

		# 
    def flatten(l):
        flatList = []
        for elem in l:
        # if an element of a list is a list
        # iterate over this list and add elements to flatList
            if type(elem) == list:
                for e in elem:
                    flatList.append(e)
            else:
               flatList.append(elem)
        return flatList

    # 리스트 결과입니다.
    # print(flatten(List))

    # convert dataframe
    data = pd.DataFrame(flatten(List), columns=["기사댓글"])
    data = data.rename_axis("index").reset_index()

    # write_excel
    # data.to_excel("news_comments.xlsx", sheet_name="Sheet1")
    return data

# data = get_df(url) # URL 테스트 시, 실행 
data = pd.DataFrame({"index": [0], "기사댓글": ["댓글"]}) # 앱 배포시 실행
# print(data.head())
  • 중간에 주석처리 한 것을 풀면 된다.
  • 해당 코드는 app.py 또는 일반적인 주피터 노트북, 구글 코랩에서 실행해도 된다.
  • 수집된 댓글을 확인해보니, 중간에 삭제된 글은 댓글 수집 시, 제외되는 것을 확인할 수 있다.

dash-crawling-04.png

Python Dash를 활용한 대시보드에서 엑셀 데이터로 다운로드 받기

강의 홍보

[대시보드] Dash Project - Excel 다운로드

개요

  • 각 레벨에 따라 달라지는 데이터를 시각화로 표현하고 결과치를 엑셀로 다운로드 받는 기능을 구현한다.

데이터 다운로드

import pandas as pd
train_df = pd.read_csv("train.csv")

id  level                                           full_log
0   0      0  Sep 24 10:02:22 localhost kibana: {"type":"err...
1   1      0  Feb  8 16:21:00 localhost logstash: [2021-02-0...
2   2      0  Jan 13 01:50:40 localhost kibana: {"type":"err...
3   3      0  Jan  4 10:18:31 localhost kibana: {"type":"err...
4   4      1  type=SYSCALL msg=audit(1603094402.016:52981): ...

함수 작성

  • 각 레벨에 따른 첫번째 글자수의 빈도를 구하는 데이터를 구하도록 한다.
  • 예를 들면, level 1에 대한 첫번째 글자 수를 집계한 결과는 아래와 같다.
    • 아래와 같은 결과값이 나오는 함수를 작성할 것이다.
index     cnt
0  type=SYSCALL  116496
1           Jan    3019
2           Oct    2904
3           Nov    2646
4           Feb    2381
  • 먼저 함수를 작성해본다.
def get_df(data, level=0):

    # pandas dataframe
    lvl_df = data.loc[data.level == level].full_log.apply(lambda x: x.split(' ')[0]).value_counts().rename(
        'cnt').to_frame().reset_index()

    return lvl_df

data = get_df(train_df, level = 1)
print(data.head())
index     cnt
0  type=SYSCALL  116496
1           Jan    3019
2           Oct    2904
3           Nov    2646
4           Feb    2381
  • 위 데이터를 토대로 시각화를 작성하고, 그 후에는 엑셀로 된 데이터로 변환하는 것이 목표이다.
  • 이 때, 각 레벨의 값에 따라 데이터 결괏값과 시각화의 그림도 달라지게 된다.

프로젝트 폴더 정리

  • 최종적인 프로젝트 폴더 및 파일은 아래와 같다.
C:.
  .gitignore
  app.py
  README.md


├─assets
      style.css

├─data
      train.csv

(1) 데이터 불러오기

  • 이제 app.py를 작성하도록 한다.
  • 먼저 데이터를 불러오는 코드 사용자 정의 함수는 다음과 같다.
import dash
import dash_table
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
from dash.dependencies import Input, Output

# 함수 정의
def get_df(data, level=0):
    # pandas dataframe
    lvl_df = data.loc[data.level == level].full_log.apply(lambda x: x.split(' ')[0]).value_counts().rename(
        'cnt').to_frame().reset_index()

    return lvl_df

DATA_PATH = "data/"
train_df = pd.read_csv(DATA_PATH + "train.csv")
print(train_df.head())

data = get_df(train_df, level=1)
print(data.head()) # 결과치가 잘 나오는지 확인하다. 
  • level=1 에서, 숫자를 변경하여 결괏값이 서로 다르게 나타나는지 반드시 확인하도록 한다.

(2) Dash 객체 생성

  • dash 클래스를 호출화여 app 인스턴스화를 진행한다.
  • 또한, app.titleapp.layout 작성한다.
.
.
external_stylesheets = [
    {
        "href": "https://fonts.googleapis.com/css2?"
                "family=Lato:wght@400;700&display=swap",
        "rel": "stylesheet",
    },
]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.title = "Temp Analytics: Understand Your Data!"

app.layout = html.Div(
    html.P("Hello World")
)

if __name__ == "__main__":
	app.run_server(debug=True)
  • 앱을 실행하면 아래와 같이 결괏값이 나타날 것이다.
id  level                                           full_log
0   0      0  Sep 24 10:02:22 localhost kibana: {"type":"err...
1   1      0  Feb  8 16:21:00 localhost logstash: [2021-02-0...
2   2      0  Jan 13 01:50:40 localhost kibana: {"type":"err...
3   3      0  Jan  4 10:18:31 localhost kibana: {"type":"err...
4   4      1  type=SYSCALL msg=audit(1603094402.016:52981): ...
          index     cnt
0  type=SYSCALL  116496
1           Jan    3019
2           Oct    2904
3           Nov    2646
4           Feb    2381
Dash is running on http://127.0.0.1:8050/
  • [http://127.0.0.1:8050/](http://127.0.0.1:8050/) 을 클릭하면 Hello World 만 나타날 것이다.

(3) HTML 상단 머리글 입력

  • 이제 HTML 코드를 추가로 입력한다.
  • 이제 app.layout 을 입력 하는 코드를 작성해보도록 한다.
  • HTML 코드는 DIV 태그가 기준이 된다. 따라서, DIV 태그가 완성될 때마다 화면을 공유하도록 했다.
  • 먼저, 화면의 상단 DIV 태그를 작업한다.
.
.
app.layout = html.Div(
	children=[
        html.Div(
            children=[
                html.P(children="📈", className="header_emoji"),
                html.H1(children="Temp Analytics", className="header_title", ),
                html.P(children="Temp", className="header_description", ),
            ],
            className='header',
        ),
	]
)
.
.
  • 아직 style.css을 입히기 전의 화면을 보면 다음과 같이 출력될 것이다.

dash_01.png

Python Dash를 활용한 대시보드 만들기 with Heroku

강의 소개

  • 필자의 강의를 소개합니다.

개요

  • 대시보드 프로젝트를 진행한다.
  • Heroku에 배포까지 진행하는 것을 목적으로 한다.
  • 참조: https://realpython.com/python-dash/
    • 여기에 있는 내용을 최대한 간결하게 한글로 재 작성하였다. 중간에 없는 코드들도 있으니, 가급적 본 소스코드를 활용한다.

1. 데이터 수집

C:\Users\1\Desktop\dashboard-project21>tree /f
폴더 PATH의 목록입니다.
볼륨 일련 번호는 E657-CFA3입니다.
C:.
  README.md

└─data
        avocado.csv
  • 파일 경로를 주의해서 보도록 합니다.

2. 가상환경 및 라이브러리 설치

  • conda를 활용하여 가상환경 설정을 합니다.
  • (dashboard-project21) 형태로 터미널 명령어가 바뀌어 있어야 합니다.
$ conda create --name dashboard-project21 python=3.8
.
.
$ conda activate dashboard-project21
(dashboard-project21) C:\Users\1\Desktop\dashboard-project21>
  • 이번에는 dash 라이브러리를 설치한다.
$ conda install dash
$ conda install pandas
$ conda install colorama

3. 대시 보드 코드 작성

(1) 데이터 수집 및 Dash 클래스 정의

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd

# step 1. Data Import
data = pd.read_csv("avocado.csv", index_col=0)
data = data.query("type == 'conventional' and region == 'Albany'")
data["Date"] = pd.to_datetime(data["Date"], format="%Y-%m-%d")
data.sort_values("Date", inplace=True)

# step 2. Dash Class
app = dash.Dash(__name__)
  • dash 라이브러리는 대시보드 어플리케이션 초기화를 담당한다.
  • dash_core_components 동적 구성요소들(예: 그래프, 드롭다운 메뉴, 날짜 기간 등) 작성할 수 있도록 도와주는 기능을 제공한다.
  • dash_html_components 은 html 태그에 접근하도록 한다.
  • pandas 데이터 수집 및 가공을 제공할 수 있는 함수들을 지원한다.
  • 코드 설명
    • step 1
      • 데이터를 avocado.csv 데이터를 수집한 후, type = conventional 과, region = Albany 만 추출하는 행을 추출한다.
      • 그 이후 날짜의 오름차순으로 정렬하는 코드를 작성한다.
    • step 2
      • Dash 클래스를 정의하여 app이라는 객체를 별도 생성한 것을 의미한다.

(2) 대시보드 HTML Layout 정의

  • 이전 코드에 이어서 작성을 하도록 한다.
# step 3. HTML
app.layout = html.Div(
	  # Header Message
    children=[
        html.H1(children="Temp Analytics",),
        html.P(
            children="Temp",
        ),
        # 그래프		
        dcc.Graph(
            figure={
                "data": [
                    {
                        "x": data["Date"],
                        "y": data["AveragePrice"],
                        "type": "lines",
                    },
                ],
                "layout": {"title": "Title_1"},
            },
        ),
        dcc.Graph(
            figure={
                "data": [
                    {
                        "x": data["Date"],
                        "y": data["Total Volume"],
                        "type": "lines",
                    },
                ],
                "layout": {"title": "Title_2"},
            },
        ),
    ]
)
  • Dash는 크게 2가지로 구성이 된다.

Python과 Oracle 연동

개요

  • 파이참에서 가상환경을 만들어 오라클 연동 예제를 작성한다.
  • 아나콘다, 파이참, 그리고 오라클 설치는 생략한다.

1. 가상환경 활성화

  • cmd 창에서 가상 환경을 세팅 하도록 한다. (권장: 관리자 실행)
  • 바탕화면에 필자는 python_oracle 폴더를 생성했다.
  • 현재 경로는 아래와 같다.
C:\Users\1\Desktop\python_oracle> 
  • 먼저 가상환경을 만든다.
conda create --name your_env_name python=3.8
.
.
done
#
# To activate this environment, use
#
#     $ conda activate python_oracle
#
# To deactivate an active environment, use
#
#     $ conda deactivate
  • your_env_name 대신 다른 이름으로 설정해도 된다.
  • 가상 환경에 접속한다.

C:\Users\1\Desktop\python_oracle>conda activate python_oracle
(python_oracle) C:\Users\1\Desktop\python_oracle>

2. 필수 라이브러리 설치

  • ML을 위한 필수 라이브러리를 설치한다.
  • pycaret & oracle
(python_oracle) C:\Users\1\Desktop\python_oracle>pip install pycaret
.
.
.
... wordcloud-1.8.1 yellowbrick-1.3.post1
(python_oracle) C:\Users\1\Desktop\python_oracle>pip install cx_Oracle
Collecting cx_Oracle
  Downloading cx_Oracle-8.2.1-cp38-cp38-win_amd64.whl (219 kB)
     |████████████████████████████████| 219 kB 2.2 MB/s
Installing collected packages: cx-Oracle
Successfully installed cx-Oracle-8.2.1
(python_oracle) C:\Users\1\Desktop\python_oracle> deactivate
  • deactivate 한 뒤, lsnrctl status 명령어를 통해 확인한다.
C:\Users\1\Desktop\python_oracle>lsnrctl status
LSNRCTL for 64-bit Windows: Version 19.0.0.0.0 - Production on 16-7월 -2021 10:28:24

Copyright (c) 1991, 2019, Oracle.  All rights reserved.

(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))에 연결되었습니다
리스너의 상태
------------------------
별칭                     LISTENER
버전                     TNSLSNR for 64-bit Windows: Version 19.0.0.0.0 - Production
시작 날짜                 13-7월 -2021 17:21:03
업타임                   217 시간. 7 분. 25트레이스 수준            off
보안                     ON: Local OS Authentication
SNMP                     OFF리스너 매개변수 파일   C:\ORACLE\WINDOWS.X64_193000_db_home\network\admin\listener.ora
리스너 로그 파일         C:\ORACLE\diag\tnslsnr\DESKTOP-F7LRGM5\listener\alert\log.xml
끝점 요약 청취 중...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=127.0.0.1)(PORT=1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(PIPENAME=\\.\pipe\EXTPROC1521ipc)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=DESKTOP-F7LRGM5)(PORT=5500))(Security=(my_wallet_directory=C:\ORACLE\admin\orcl\xdb_wallet))(Presentation=HTTP)(Session=RAW))
서비스 요약...
"CLRExtProc" 서비스는 1개의 인스턴스를 가집니다.
  "CLRExtProc" 인스턴스(UNKNOWN 상태)는 이 서비스에 대해 1 처리기를 가집니다.
"orcl" 서비스는 1개의 인스턴스를 가집니다.
  "orcl" 인스턴스(READY 상태)는 이 서비스에 대해 1 처리기를 가집니다.
"orclXDB" 서비스는 1개의 인스턴스를 가집니다.
  "orcl" 인스턴스(READY 상태)는 이 서비스에 대해 1 처리기를 가집니다.
명령이 성공적으로 수행되었습니다
  • (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))에 연결되었습니다

3. 연동코드 작성

  • 필수 정보를 확인한다.
    • IP주소: localhost
    • Port번호: 1521
    • 서비스이름: orcl
  • JupyterLab을 연 후 코드를 작성한다. (관리자 살행)
    • 가상환경 python_oracle 으로 연결이 되어 있는지 확인한다.

In ML, Data Leakage - 2

머신러닝 전처리 자주하는 안 좋은 습관들 모음

Sample 데이터

  • 먼저 가상의 데이터를 하나 생성합니다.
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split

random_state = 42
X, y = make_regression(random_state = random_state, n_features = 1, noise = 1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.4, random_state = random_state)

Inconsistent preprocessing

  • 모델을 학습시킬 때 이러한 데이터 변환을 사용하는 경우 테스트 데이터든 프로덕션 시스템의 데이터든 후속 데이터셋에도 사용해야 합니다. 그렇지 않으면 피쳐 공간이 변경되고 모델이 효과적으로 수행되지 않습니다.

Wrong

  • 먼저, 잘못된 방식을 소개합니다.
  • train 데이터에는 scaler가 적용되었지만, 테스트 데이터에는 적용되지 않았습니다. 따라서, 이러한 경우 모델 성능이 예상보다 떨어질 수 있습니다.
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train_transformed = scaler.fit_transform(X_train)
model = LinearRegression().fit(X_train_transformed, y_train)
mean_squared_error(y_test, model.predict(X_test))
62.80867119249524
  • Non-Transformed X_test 데이터를 예측값으로 넣으려면 X_train과 마찬가지로 동일하게 transform을 적용해야 한다.
scaler = StandardScaler()
X_train_transformed = scaler.fit_transform(X_train)
X_test_transformed = scaler.transform(X_test)
model = LinearRegression().fit(X_train_transformed, y_train)
mean_squared_error(y_test, model.predict(X_test_transformed))
0.9027975466369481
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline

random_state = 42
X, y = make_regression(random_state = random_state, n_features = 1, noise = 1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.4, random_state = random_state)

model = make_pipeline(StandardScaler(), LinearRegression())
model.fit(X_train, y_train)
mean_squared_error(y_test, model.predict(X_test))
0.9027975466369481

Data Leakage

  • 모델을 구축할 때 예측 시점에 사용할 수 없는 정보가 사용될 때 데이터 누출이 발생함.
  • 이로 인해 교차 검증 시, 매우 낙관적인 성능 추정치가 발생하기도 하며, 실제 새로운 데이터와 만날 때는 성능이 매우 크게 저하 되기도 함.
  • 훈련 및 테스트 데이터 하위 집합 모두 이전 섹션에서 설명한 것과 동일한 전처리 변환을 받아야 하지만,
  • 이러한 변환은 훈련 데이터에서만 학습되는 것이 중요하다. 예를 들어 평균값으로 나누는 정규화 단계가 있는 경우 평균은 모든 데이터의 평균이 아니라 훈련 데이터 하위 집합의 평균이어야 합니다. 테스트 하위 집합이 평균 계산에 포함되는 경우 테스트 하위 집합의 정보가 모델에 영향을 줍니다.
  • Data Leakage가 발생하는 몇가지 상황을 살펴본다.

Data Leakage During Pre-Processing

  • 우선 가상의 데이터를 만듭니다.
import numpy as np 
n_samples, n_features, n_classes = 200, 100000, 2
rng = np.random.RandomState(42)
X = rng.standard_normal((n_samples, n_features))
y = rng.choice(n_classes, n_samples)

print(X.shape, y.shape)
(200, 100000) (200,)

Wrong

  • 이제 transformation부터 머신러닝 학습, 그리고 평가까지 진행한다.
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score

# 여기 부분이 잘못 되었다. 
X_selected = SelectKBest(k=25).fit_transform(X, y)

X_train, X_test, y_train, y_test = train_test_split(X_selected, y, random_state=42)
gbc = GradientBoostingClassifier(random_state=1)
gbc.fit(X_train, y_train)

y_pred = gbc.predict(X_test)
accuracy_score(y_test, y_pred)
0.72

Right

  • Data Leakage를 예방하기 위해 먼저 train 데이터와 test 데이터를 분리한다.
  • fit이나 fit_transform은 train 데이터에만 적용한다.
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 42)
select = SelectKBest(k=25)

X_train_selected = select.fit_transform(X_train, y_train)
gbc = GradientBoostingClassifier(random_state = 1)
gbc.fit(X_train_selected, y_train)
GradientBoostingClassifier(ccp_alpha=0.0, criterion='friedman_mse', init=None,
                           learning_rate=0.1, loss='deviance', max_depth=3,
                           max_features=None, max_leaf_nodes=None,
                           min_impurity_decrease=0.0, min_impurity_split=None,
                           min_samples_leaf=1, min_samples_split=2,
                           min_weight_fraction_leaf=0.0, n_estimators=100,
                           n_iter_no_change=None, presort='deprecated',
                           random_state=1, subsample=1.0, tol=0.0001,
                           validation_fraction=0.1, verbose=0,
                           warm_start=False)
X_test_selected = select.transform(X_test)
y_pred = gbc.predict(X_test_selected)
accuracy_score(y_test, y_pred)
0.5
  • 이번에는 Pipeline을 통해 구성하도록 한다.
from sklearn.pipeline import make_pipeline

X_train, X_test, y_train, y_test = train_test_split(
    X, y, random_state=42)

pipeline = make_pipeline(SelectKBest(k=25), 
                         GradientBoostingClassifier(random_state=1))

pipeline.fit(X_train, y_train)
Pipeline(memory=None,
         steps=[('selectkbest',
                 SelectKBest(k=25,
                             score_func=<function f_classif at 0x7f56a7c7f5f0>)),
                ('gradientboostingclassifier',
                 GradientBoostingClassifier(ccp_alpha=0.0,
                                            criterion='friedman_mse', init=None,
                                            learning_rate=0.1, loss='deviance',
                                            max_depth=3, max_features=None,
                                            max_leaf_nodes=None,
                                            min_impurity_decrease=0.0,
                                            min_impurity_split=None,
                                            min_samples_leaf=1,
                                            min_samples_split=2,
                                            min_weight_fraction_leaf=0.0,
                                            n_estimators=100,
                                            n_iter_no_change=None,
                                            presort='deprecated',
                                            random_state=1, subsample=1.0,
                                            tol=0.0001, validation_fraction=0.1,
                                            verbose=0, warm_start=False))],
         verbose=False)
  • 테스트 데이터는 예측을 할 때만 사용하도록 한다.
y_pred = pipeline.predict(X_test)
accuracy_score(y_test, y_pred)
0.5
  • Pipeline은 cross_val_score에 직접 사용할 수도 있다.
from sklearn.model_selection import cross_val_score
scores = cross_val_score(pipeline, X, y)
print(f"Mean accuracy: {scores.mean():.2f}+/-{scores.std():.2f}")
Mean accuracy: 0.52+/-0.04

In ML, Data Leakage - 1

Data Leakage

  • 모형 평가를 하기 전에 전체 데이터셋을 가공 및 변환함.
  • 이를 평가에 반영하면 새로운 데이터를 예측할 때 부정확한 결과를 도출 할 수 있음.
  • 이를 방지 하기 위해서는 training 데이터만 데이터 전처리를 수행하는 것이 바람직함.
  • Data Leakage를 피하기 위해서는 scikit-learn modeling pipeline을 설계해햐 함.

데이터 준비

  • 가상의 데이터를 준비한다.
  • 데이터는 모두 수치형 데이터로 준비했다.
from sklearn.datasets import make_classification
X, y = make_classification(n_samples = 1000, n_features = 20, n_informative = 15, n_redundant = 5, random_state = 7)

# summarize the dataset
print(X.shape, y.shape)
(1000, 20) (1000,)

일반적인 방법의 데이터 전처리

  • 수치형 데이터이기 때문에, MinMaxScaler 클래스를 활용한다.
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()
X = scaler.fit_transform(X)
  • 이번에는 데이터셋을 분리하도록 한다.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state = 7)
  • 이번에는 로지스틱 회귀분석을 시행한다.
from sklearn.linear_model import LogisticRegression

model = LogisticRegression()
model.fit(X_train, y_train)
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                   intercept_scaling=1, l1_ratio=None, max_iter=100,
                   multi_class='auto', n_jobs=None, penalty='l2',
                   random_state=None, solver='lbfgs', tol=0.0001, verbose=0,
                   warm_start=False)
  • 이제 모형을 평가하도록 합니다.
from sklearn.metrics import accuracy_score

yhat = model.predict(X_test)
accuracy = accuracy_score(y_test, yhat)

print('Accuracy: %.3f' % (accuracy * 100))
Accuracy: 84.848
  • 이것이 일반적인 방법론이다. 그러나 엄밀히 말하면 Data Leakage 현상이 나타났다고 볼 수 있다.

Data Leakage 피하는 방법

  • 이번에는 먼저 데이터 셋을 분리하도록 합니다.
  • Train 데이터에만 scaler를 적용하도록 합니다.
from sklearn.utils.validation import check_random_state

X, y = make_classification(n_samples = 2000, n_features = 20, n_informative = 15, n_redundant = 5, random_state = 7)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state = 1)
  • 그 후, X_train과 X_test에만 scaler를 적용한다.
scaler = MinMaxScaler()
scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)
  • 이제 모형을 만든 후, 결괏값을 적용합니다.
model = LogisticRegression()
model.fit(X_train, y_train)
yhat = model.predict(X_test)
accuracy = accuracy_score(y_test, yhat)

print('Accuracy: %.3f' % (accuracy * 100))
Accuracy: 88.333
  • 결과를 보면 알겠지만, 모형의 성능에도 좋지 않음을 올 수 있다.

Reference

Jason Brownlee. 2020. How to Avoid Data Leakage When Performing Data Preparation. Retrieved from https://machinelearningmastery.com/data-preparation-without-data-leakage/