Skip to Content
0
Jan 06, 2020 at 09:03 AM

Python3.6 Machine Learning Code transform SAP DataHub Modeling

163 Views

Python3.6 Machine Learning Code

#!/usr/bin/python
#coding=utf-8
from konlpy.tag import Okt
import json
import os
from pprint import pprint
import nltk
import numpy as np
from tensorflow.keras import models
from tensorflow.keras import layers
from tensorflow.keras import optimizers
from tensorflow.keras import losses
from tensorflow.keras import metrics
# nsmc 데이터 불러오기
def read_data(filename):
        with open(filename, 'r', encoding='utf8') as f:
                data = [line.split('\t') for line in f.read().splitlines()]
                # txt 파일의 헤더(id document label)는 제외하기
                data = data[1:]
        return data
train_data = read_data('ratings_train.txt')
test_data  = read_data('ratings_test.txt')
#print(len(train_data))
#print(len(train_data[0]))
#print(len(test_data))
#print(len(test_data[0]))
# 데이터 전처리
# KoNLPy 라이브러리를 이용해 형태소 분석 및 품사 태깅
# imdb 리뷰 분석 예제처럼 주어진 빈도만을 사용해서 처리해도 되지만 한국어는 영어와는 달리 띄어쓰기로 의미를 구분짓기에는 한계가 있고
# 네이버 영화 데이터에는 맞춤법이나 띄어쓰기가 제대로 되어있지 않은 경우가 있기 때문에 정확한 분류를 위해서 KoNLPy를 이용
# KoNLPy는 띄어쓰기 알고리즘과 정규화를 이용해서 맞춤법이 틀린 문장도 어느 정도 고쳐주면서 형태소 분석과 품사를 태깅해주는 여러 클래스를 제공
# 그 중에서 Okt(Open Korean Text) 클래스를 이용
# 먼저 Okt를 이용해서 간단한 문장을 분석
okt = Okt()
#print(okt.pos('이 밤 그날의 반딧불을 당신의 창 가까이 보낼게요'))
# 이제 아까 불러온 데이터에 형태소 분석을 통해서 품사를 태깅해주는 작업
# 데이터의 양이 큰 만큼 시간이 오래 걸리기 때문에 이 작업을 반복하지 않도록 한 번 태깅을 마친 후에는 json 파일로 저장하는 것을 추천
# 여기에서는 이미 태깅이 완료된 train_docs.json 파일이 존재하면 반복하지 않도록 만듦
def tokenize(doc):
        # norm은 정규화, stem은 근어로 표시하기를 나타냄
        return ['/'.join(t) for t in okt.pos(doc, norm=True, stem=True)]
if os.path.isfile('train_docs.json'):
        with open('train_docs.json') as f:
                train_docs = json.load(f)
        with open('test_docs.json') as f:
                test_docs = json.load(f)
else:
        train_docs = [(tokenize(row[1]), row[2]) for row in train_data]
        test_docs = [(tokenize(row[1]), row[2]) for row in test_data]
        # JSON 파일로 저장
        with open('train_docs.json', 'w', encoding="utf-8") as make_file:
                json.dump(train_docs, make_file, ensure_ascii=False, indent="\t")
        with open('test_docs.json', 'w', encoding="utf-8") as make_file:
                json.dump(test_docs, make_file, ensure_ascii=False, indent="\t")
# 예쁘게(?) 출력하기 위해서 pprint 라이브러리 사용
#pprint(train_docs[0])
# 분석한 데이터의 토큰(문자열을 분석을 위한 작은 단위)의 갯수를 확인
tokens = [t for d in train_docs for t in d[0]]
#print(len(tokens))
# 이제 이 데이터를 nltk 라이브러리를 통해서 전처리
# Text 클래스는 문서를 편리하게 탐색할 수 있는 다양한 기능을 제공
# 여기에서는 vocab().most_common 메서드를 이용해서 데이터에서 가장 자주 사용되는 단어를 가져올 때 사용
text = nltk.Text(tokens, name='NMSC')
# 전체 토큰의 개수
#print('전체 토근 개수: {}'.format(len(text.tokens)))
# 중복을 제외한 토큰의 개수
#print('중복 제외 토근 수: {}'.format(len(set(text.tokens))))
# 출현 빈도가 높은 상위 토큰 10개
#pprint('출현 빈도가 높은 상위 10개 토큰: {}'.format(text.vocab().most_common(10)))
# 자주 사용되는 토큰 10000개를 사용해서 데이터를 벡터화
# 여기서는 원 핫 인코딩 대신에 CountVectorization을 사용
# 이는 문서 집합에서 단어 토큰을 생성하고 각 단어의 수를 세어 BOW(Bag of Words) 인코딩한 벡터를 만드는 역할을 함
# 시간이 꽤 걸립니다! 시간을 절약하고 싶으면 most_common의 매개변수를 줄여보세요.
selected_words = [f[0] for f in text.vocab().most_common(200)]
def term_frequency(doc):
        return [doc.count(word) for word in selected_words]
train_x = [term_frequency(d) for d, _ in train_docs]
test_x  = [term_frequency(d) for d, _ in test_docs]
train_y = [c for _, c in train_docs]
test_y  = [c for _, c in test_docs]
# 이제 데이터를 float로 형 변환 시켜주면 데이터 전처리 과정은 끝남
x_train = np.asarray(train_x).astype('float32')
x_test  = np.asarray(test_x).astype('float32')
y_train = np.asarray(train_y).astype('float32')
y_test  = np.asarray(test_y).astype('float32')
# 두 개의 Dense 층은 64개의 유닛을 가지고 활성화 함수로는 relu를 사용했으며, 마지막 층은 sigmoid 활성화 함수를 사용해서 긍정의 리뷰일 확률을 출력
# 손실 함수로는 binary_crossentropy를 사용했고 RMSProp 옵티마이저를 통해서 경사하강법을 진행
# 또한 배치 사이즈를 512로, 에포크를 10번으로 학습
model = models.Sequential()
model.add(layers.Dense(64, activation='relu', input_shape=(200,)))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(optimizer=optimizers.RMSprop(lr=0.001),
        loss=losses.binary_crossentropy,
        metrics=[metrics.binary_accuracy])
model.fit(x_train, y_train, epochs=10, batch_size=512)
#results = model.evaluate(x_test, y_test)
# 테스트 데이터로 확인해본 결과를 출력해보면 80%의 성능을 보여주는 것을 알 수 있음
#print(results)
# 이제 문자열 형태의 새로운 데이터를 받아와서 바로 결과를 예측하는 함수
# 데이터의 형태를 맞춰주기 위해서 np.expand_dims 메서드를 이용해 array의 축을 확장
# 최종 확률이 0.5 보다 크면 긍정이고, 그렇지 않으면 부정이라고 예측
def predict_pos_neg(review):
        token = tokenize(review)
        tf    = term_frequency(token)
        data  = np.expand_dims(np.asarray(tf).astype('float32'), axis=0)
        score = float(model.predict(data))
        if(score > 0.5):
                print("[{}]는 {:.2f}% 확률로 긍정 리뷰이지 않을까 추측해봅니다.^^\n".format(review, score * 100))
        else:
                print("[{}]는 {:.2f}% 확률로 부정 리뷰이지 않을까 추측해봅니다.^^;\n".format(review, (1 - score) * 100))
predict_pos_neg("올해 최고의 영화! 세 번 넘게 봐도 질리지가 않네요.")
predict_pos_neg("배경 음악이 영화의 분위기랑 너무 안 맞았습니다. 몰입에 방해가 됩니다.")
predict_pos_neg("주연 배우가 신인인데 연기를 진짜 잘 하네요. 몰입감 ㅎㄷㄷ")
predict_pos_neg("믿고 보는 감독이지만 이번에는 아니네요")
predict_pos_neg("주연배우 때문에 봤어요")

- Result

2020-01-06 17:43:15.713229: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
2020-01-06 17:43:15.727035: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2094870000 Hz
2020-01-06 17:43:15.727626: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x1b4ad8c0 executing computations on platform Host. Devices:
2020-01-06 17:43:15.727682: I tensorflow/compiler/xla/service/service.cc:175]   StreamExecutor device (0): Host, Default Version
Train on 150000 samples
Epoch 1/10
150000/150000 [==============================] - 5s 33us/sample - loss: 0.5173 - binary_accuracy: 0.7374
Epoch 2/10
150000/150000 [==============================] - 3s 23us/sample - loss: 0.4790 - binary_accuracy: 0.7559
Epoch 3/10
150000/150000 [==============================] - 5s 30us/sample - loss: 0.4684 - binary_accuracy: 0.7630
Epoch 4/10
150000/150000 [==============================] - 3s 19us/sample - loss: 0.4601 - binary_accuracy: 0.7666
Epoch 5/10
150000/150000 [==============================] - 3s 20us/sample - loss: 0.4534 - binary_accuracy: 0.7719
Epoch 6/10
150000/150000 [==============================] - 3s 23us/sample - loss: 0.4473 - binary_accuracy: 0.7752
Epoch 7/10
150000/150000 [==============================] - 3s 19us/sample - loss: 0.4423 - binary_accuracy: 0.7784
Epoch 8/10
150000/150000 [==============================] - 3s 23us/sample - loss: 0.4377 - binary_accuracy: 0.7816
Epoch 9/10
150000/150000 [==============================] - 4s 29us/sample - loss: 0.4339 - binary_accuracy: 0.7830
Epoch 10/10
150000/150000 [==============================] - 3s 23us/sample - loss: 0.4304 - binary_accuracy: 0.7853
[올해 최고의 영화! 세 번 넘게 봐도 질리지가 않네요.]는 99.14% 확률로 긍정 리뷰이지 않을까 추측해봅니다.^^
[배경 음악이 영화의 분위기랑 너무 안 맞았습니다. 몰입에 방해가 됩니다.]는 90.31% 확률로 부정 리뷰이지 않을까 추측해봅니다.^^;
[주연 배우가 신인인데 연기를 진짜 잘 하네요. 몰입감 ㅎㄷㄷ]는 59.12% 확률로 긍정 리뷰이지 않을까 추측해봅니다.^^
[믿고 보는 감독이지만 이번에는 아니네요]는 89.76% 확률로 부정 리뷰이지 않을까 추측해봅니다.^^;
[주연배우 때문에 봤어요]는 68.33% 확률로 부정 리뷰이지 않을까 추측해봅니다.^^;

- Datahub modeling below

1. Create Dockerfile

FROM ubuntu:18.04
MAINTAINER Jiho Jung <jjung@dataworks.co.kr>
USER root
# OS 패키지 설치
RUN apt-get update
RUN apt-get install -y curl apt-utils git make build-essential
RUN apt-get install -y gcc openjdk-8-jdk diffutils
RUN apt-get install -y libssl-dev libffi-dev zlib1g-dev libbz2-dev libreadline-dev
RUN apt-get install -y libsqlite3-dev python3.6 python-pip python3-pip libjpeg8-dev python-dev
RUN apt-get install -y language-pack-ko python3-dev libxml2 libxml2-dev libxslt1-dev
RUN apt-get install -y fonts-nanum fonts-nanum-coding fonts-nanum-extra
RUN apt-get install -y cmake git wget unzip yasm pkg-config libswscale-dev
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/*
# 머신 러닝 관련 파이썬 라이브러리 설치
RUN pip3 install --upgrade pip
RUN pip3 install requests
RUN pip3 install beautifulsoup4
RUN pip3 install html5lib
RUN pip3 install JPype1
RUN pip3 install konlpy
RUN pip3 install nltk
RUN pip3 install steem
RUN pip3 install tensorflow
RUN pip3 install pandas
CMD bash <(curl -s https://raw.githubusercontent.com/konlpy/konlpy/master/scripts/mecab.sh)
CMD echo '/usr/local/lib' >> /etc/ld.so.conf
CMD ldconfig
CMD ldconfig -p | grep libmecab

2. Create Operator - ongoing

#coding=utf-8
import requests
import os
import sys
import json
import nltk
import numpy as np
import pandas as pd
import io
from konlpy.tag import Okt
from pprint import pprint
from tensorflow.keras import models
from tensorflow.keras import layers
from tensorflow.keras import optimizers
from tensorflow.keras import losses
from tensorflow.keras import metrics
def inputtrain(data):
    t = "{}".format(data)
    data = [line.split('\t') for line in t.splitlines()]
    data = data[1:]
    #train_data = len(data)
    #stringout = str(train_data)
    #api.send("outtrain", stringout)
    okt = Okt()
    train_docs = [(['/'.join(t) for t in okt.pos(row[1], norm=True, stem=True)], row[2]) for row in data]
    train_docs = train_docs[0]
    stringout = str(train_docs)
    api.send("outtrain", stringout)
api.set_port_callback("inputtrain", inputtrain)
def inputtest(data):
    t = "{}".format(data)
    data = [line.split('\t') for line in t.splitlines()]
    data = data[1:]
    #test_data = len(data)
    #stringout = str(test_data)
    #api.send("outtest", stringout)
    okt = Okt()
    test_docs = [(['/'.join(t) for t in okt.pos(row[1], norm=True, stem=True)], row[2]) for row in data]
    test_docs = test_docs[0]
    stringout = str(test_docs)
    api.send("outtest", stringout)
api.set_port_callback("inputtest", inputtest)

3. Create Pipeline - ongoing

- Question

How do I change the machine running Python code to the DataHub modeling pipeline?

Attachments