머신러닝

Machine-Learning

2020. 7. 23. 17:19

머신러닝이란?

머신러닝(machine learning) 개요

  • 머신러닝이란 인공지능 연구 과제 중 하나

  • 인간의 뇌가 학습하는 것처럼 학습의 능력을 컴퓨터로 구현하는 방법

  • 샘플 데이터 입력 => 분석 => 특징과 규칙 발견 => 데이터분류 또는 예측

어떻게 특징과 규칙을 찾을까?

  • 특징량을 기반으로 구분선 그리기

  • 머신러닝 계산을 통해 구분선을 찾아 내는 것

  • 많은 경우 거리가 가까우면 비슷한 데이터라고 판정

특징 추출

  • Raw Data => 데이터가 어떤 특징을 가지고 있는 지 확인 => 벡터(vector)

  • 벡터란 공간에서 크기와 방향을 가지는 것을 의미

  • 어떤 특징을 추출할지가 포인트

회귀 분석 regression analysis

  • Y가 연속된 값일 때 Y = f(x) 모델로 나타 내는 것

  • Y = aX + b 인 경우를 선형 회귀

  • Y: 종복변수(목표변수), X(독립변수,설명변수)

  • X가 1차원 단순회귀, 2차원이상 다중 회귀

머신러닝의 종류

지도학습(교사학습) Supervised learning

  • 데이터와 함께 답도 입력

  • 다른 데이터의 답 예측

  • 답을 특별히 레이블 이라고 함

  • 글자를 나타내는 이미지와 답을 학습 => 새로운 이미지의 글자 예측

비지도학습(비교사학습) Unsupervised learning

  • 데이터만 입력

  • 데이터에서 규칙성을 찾음

  • 일반적으로 사람도 알 수없는 본질적은 구조 찾기등에 사용

  • 클러스트 분석(Cluster analysis), 주성분 분석(Pricipal component analysis) 등

강화학습 Reinforcement learning

  • 부분 적인 답 입력

  • 데이터를 기반으로 최적의 답 찾기

  • 행동의 주체 <==> 환경(상황, 상태)

  • 행동의 주체는 환경을 관찰 => 의사결정(행동) => 보상

  • 더 많은 보상을 얻을 수 있는 방향으로 행동을 학습

머신러닝의 흐름

  • 데이터 수집 => 가공 => 학습 => 모델 평가 => 정밀도 확인 => 성공

  • 학습 => 학습 방법 선택 => 매개변수 조정 => 모델 학습

  • 정밀도가 낮으면 매개변수 조정 => 모델 학습 = > 모델 평가 => 정밀도 확인 반복

데이터 수집

  • 가장 어려운 부분

  • 충분한 양의 데이터 확보 필요

데이터 가공

  • 프로그램이 다루기 쉬운 형태로 가공 => 벡터화

  • 머신러닝의 어떤 특징을 활용 및 그에 따른 데이터 가공 방법 고민

학습

  • 알고리즘 선택 : SVM, 랜덤포레스트, k-menas등

  • 데이터와 알고리즘에 맞게 매개변수 지정

평가

  • 테스트 데이터를 활용 해 정밀도 확인

머신러닝 응용 분야

클래스 분류(Classification)

  • 특정 데이터에 레이블을 붙여 분류

  • 스팸 메일 분류, 필기 인식, 증권 사기 등에 사용

클러스터링 - 그룹 나누기(Clustering)

  • 값의 유사성 기반으로 데이터를 여러 그룹으로 나누기

  • 사용자 취향 별 타겟 광고 제공

추천(Recomendation)

  • 특정 데이터를 기반으로 다른 데이터를 추천 하는 것

  • 사용자가 인터넷 서점에서 구매한 책을 기반으로 다른 책 추천

회귀(Regression)

  • 과거의 데이터를 기반으로 미래의 데이터를 예측 하는 것

  • 판매 예측, 주가 변동 등 예측

차원 축소(Dimensionality Reduction)

  • 데이터의 특성을 유지하면서 데이터의 양을 줄이는 것

  • 양을 줄인다는 것 보다는 고차원을 저차원 데이터로 변환 하는 것

  • 데이터를 시각화 하거나 구조를 추출해서 용량을 줄여 계산을 빠르게 하거나 메모리 절약에 사용

  • 사람은 얼굴 이미지는 용량이 큰 고차원 데이터 => 이미지에서 눈의 크기, 굴곡, 코의 위치, 입의 위치등을 분석해 숫자로 추출

초과 학습(초과 적합) Overfitting

  • 훈련 전용 데이터가 학습돼 있지만 학습되지 않은 데이터에 대해 제대로 된 예측을 못하는 상태

  • 데이터가 너무 적은 경우

  • 모델에 비해 문제가 너무 복잡한 경우

머신러닝 프레임워크 scikit-learn

# !pip install scikit-learn
# !pip install scipy

XOR 연산 학습하기

from sklearn import svm
# XOR의 계산 결과 데이터 --- (1)
xor_data = [
    #P, Q, result
    [0, 0, 0],
    [0, 1, 1],
    [1, 0, 1],
    [1, 1, 0]
]
# 학습을 위해 데이터와 레이블 분리하기 --- (2)
# 학습시키기 fit() 매개변수에 필요
data = [] # 훈련데이터 / 테스트데이터
label = [] # 답
for row in xor_data:
    p = row[0]
    q = row[1]
    r = row[2]
    data.append([p, q])
    label.append(r)
# 데이터 학습시키기 fit() --- (3)
# SVC 알고리즘 사용
clf = svm.SVC()
clf.fit(data, label)
# 데이터 예측하기 predict() --- (4)
pre = clf.predict(data)
print('예측 결과 :', pre)
# 결과 확인하기 --- (5)
ok = 0; total = 0
for idx, answer in enumerate(label):
    p = pre[idx]
    if p == answer: ok += 1
    total += 1
print("정답률:", ok, "/", total, "=", ok/total)
예측 결과 : [0 1 1 0]
정답률: 4 / 4 = 1.0
data
[[0, 0], [0, 1], [1, 0], [1, 1]]
label
[0, 1, 1, 0]
pre
array([0, 1, 1, 0])

프레임워크로 작성하기

  • 판다스로 데이터와 레이블 나누기

  • scikit-learn 정답률 계산 기능 등 내장

import pandas as pd
from sklearn import svm, metrics
# XOR 연산
xor_input = [
    [0, 0, 0],
    [0, 1, 1],
    [1, 0, 1],
    [1, 1, 0]
]
# 입력을 학습 전용 데이터와 테스트 전용 데이터로 분류하기 --- (1)
xor_df = pd.DataFrame(xor_input)
xor_data  = xor_df.loc[:,0:1] # 데이터
xor_label = xor_df.loc[:,2]   # 레이블

# 데이터 학습과 예측하기 -- (2)
clf = svm.SVC()
clf.fit(xor_data, xor_label) # 훈련, 학습, 모델만들기 같은말임
pre = clf.predict(xor_data)

# 정답률 구하기 --- (3)
ac_score = metrics.accuracy_score(xor_label, pre)
print('정답률 =', ac_score)
정답률 = 1.0
xor_label
0    0
1    1
2    1
3    0
Name: 2, dtype: int64
pre
array([0, 1, 1, 0], dtype=int64)

붓꽃의 품종 분류하기

  • 외떡잎식물 백합목 붓꽃과의 여러해살이풀 '붓꽃' 분류

  • 머신러닝을 사용해 꽃입과 꽃받치의 크기 기반 분류

붓꽃 데이터 구하기

  • https://wikibook.co.kr/pyml-rev/ 예제코드 다운로드

  • Fisher의 붓꽃 데이터 internet에 공개되 있음

  • iris.csv 검색 (ch4)

  • 판다스의 데이터로도 포함되 있음

데이터 설명

  • 붓꽃 종류 3가지 Iris-setosa, Iris-versicolor, Iris-virginica

  • SepalLength : 꽃받침의 길이

  • SepalWidth : 꽃받침의 폭

  • PetalLength : 꽃잎의 길이

  • PetalWidth : 꽃잎의 너비

머신러닝으로 붓꽃 품종 분류하기

  • 150개의 데이터 / 100개 훈련용 / 50개 테스트용

from sklearn import svm, metrics
import random, re
# 붓꽃의 CSV 데이터 읽어 들이기 --- (1)
csv = []
with open('pyml_rev_examples/ch4/iris.csv', 'r', encoding='utf-8') as fp:
    # 한 줄씩 읽어 들이기
    for line in fp:
        line = line.strip() # 줄바꿈 제거
        cols = line.split(',') # 쉼표로 자르기
        # 문자열 데이터를 숫자로 변환하기
        fn = lambda n : float(n) if re.match(r'^[0-9\.]+$', n) else n
        cols = list(map(fn, cols))
        csv.append(cols)
# 가장 앞 줄의 헤더 제거
del csv[0]
csv[:3]
[[5.1, 3.5, 1.4, 0.2, 'Iris-setosa'],
 [4.9, 3.0, 1.4, 0.2, 'Iris-setosa'],
 [4.7, 3.2, 1.3, 0.2, 'Iris-setosa']]
data = pd.read_csv('pyml_rev_examples/ch4/iris.csv')
data.head()
  SepalLength SepalWidth PetalLength PetalWidth Name
0 5.1 3.5 1.4 0.2 Iris-setosa
1 4.9 3.0 1.4 0.2 Iris-setosa
2 4.7 3.2 1.3 0.2 Iris-setosa
3 4.6 3.1 1.5 0.2 Iris-setosa
4 5.0 3.6 1.4 0.2 Iris-setosa
# 데이터 셔플하기(섞기) -- (2)
random.shuffle(csv)
# 학습 전용 데이터와 테스트 전용 데이터 분할하기(2:1 비율) --- (3)
total_len = len(csv)
train_len = int(total_len * 2 / 3)
train_data = []
train_label = []
test_data = []
test_label = []
for i in range(total_len):
    data = csv[i][0:4]
    label = csv[i][4]
    if i < train_len:
        train_data.append(data)
        train_label.append(label)
    else:
        test_data.append(data)
        test_label.append(label)
train_data[:3]
[[4.4, 3.0, 1.3, 0.2], [5.2, 3.5, 1.5, 0.2], [5.8, 2.7, 3.9, 1.2]]
train_label[:3]
['Iris-setosa', 'Iris-setosa', 'Iris-versicolor']
test_data[:3]
[[5.7, 2.9, 4.2, 1.3], [6.4, 3.2, 5.3, 2.3], [6.3, 2.7, 4.9, 1.8]]
test_label[:3]
['Iris-versicolor', 'Iris-virginica', 'Iris-virginica']
# 데이터를 학습시키고 예측하기 --- (4)
clf = svm.SVC()
clf.fit(train_data, train_label)
pre = clf.predict(test_data)
# 정답률 구하기 --- (5)
ac_score = metrics.accuracy_score(test_label, pre)
print('정답률 =', ac_score)
정답률 = 0.86

훈련용 / 테스트 데이터 분할 메서드

  • model_selection 모듈의 train_test_split()

import pandas as pd
from sklearn import svm, metrics
from sklearn.model_selection import train_test_split
# 붓꽃의 CSV 데이터 읽어 들이기 --- (※1)
csv = pd.read_csv('pyml_rev_examples/ch4/iris.csv')
# 필요한 열 추출하기 --- (2)
csv_data = csv[["SepalLength","SepalWidth","PetalLength","PetalWidth"]]
csv_label = csv['Name']
# 학습 전용 데이터와 테스트 전용 데이터로 나누기 --- (3)
train_data, test_data, train_label, test_label = train_test_split(csv_data, csv_label)
train_data[:3]
len(train_data)
112
test_data[:3]
len(test_data)
38
train_label[:3]
23         Iris-setosa
51     Iris-versicolor
122     Iris-virginica
Name: Name, dtype: object
test_label[:3]
54    Iris-versicolor
35        Iris-setosa
15        Iris-setosa
Name: Name, dtype: object
# 데이터 학습시키고 예측하기 --- (4)
clf = svm.SVC()
clf.fit(train_data, train_label)
pre = clf.predict(test_data)
# 정답률 구하기 --- (5)
ac_score = metrics.accuracy_score(test_label, pre)
print('정답률 = ', ac_score)
정답률 =  0.9736842105263158

이미지 내부의 문자 인식

손글씨 숫자 인식

데이터 수집 MNIST : THE MINIST DATABASE

  • THE MINIST DATABASE of handwritten digits

  • http://yann.lecun.com/exdb/mnist

  • 학습전용 6만개 / 테스트 전용 1만개

  • MNIST 자체 데이터베이스 형식

  • train-images-idx3-ubyte.gz: training set images (9912422 bytes)

  • train-labels-idx1-ubyte.gz: training set labels (28881 bytes)

  • t10k-images-idx3-ubyte.gz: test set images (1648877 bytes)

  • t10k-labels-idx1-ubyte.gz: test set labels (4542 bytes)

 

데이터 구조

  • 사이트 확인: FILE FORMATS FOR THE MNIST DATABASE

  • 이미지데이터는 각 픽셀을 그레이스케일 256단계

  • 왼쪽 위부터 오른쪽 아래로 차례차례 픽셀이 나열된 형태

  • 0:흰색, 1~255 숫자가 클수록 짙은 부분

  • 바이너리 데이터 => CSV로 변환

  • <레이블>, <28x28의 픽셀 데이터>

  • 각파일은 32bit(매빅넘버)+32bit(이미지갯수)+이미지(8byte씩)

 

데이터 변환

# binary 파일 변환위한 모듈
import struct
def to_csv(name, maxdata):
    # 레이블 파일과 이미지 열기
    lbl_f = open("mnist/"+name+"-labels.idx1-ubyte", "rb")
    img_f = open("mnist/"+name+"-images.idx3-ubyte", "rb")
    csv_f = open("mnist/"+name+".csv", "w", encoding="utf-8")
    # 헤더 정보 읽기 --- (1)
    # unpack() 원하는 바이너리수 많큼 읽고 정수로 변환
    # > 리틀 엔디안 II 4byte4byter
    # https://suspected.tistory.com/155
    # PGM : 글자파일로 이미지 생성 가능
    mag, lbl_count = struct.unpack(">II", lbl_f.read(8))
    mag, img_count = struct.unpack(">II", img_f.read(8))
    rows, cols = struct.unpack(">II", img_f.read(8))
    pixels = rows * cols
    # 이미지 데이터를 읽고 CSV로 저장하기 --- (2)
    res = []
    for idx in range(lbl_count):
        if idx > maxdata : break
        label = struct.unpack("B", lbl_f.read(1))[0]
        bdata = img_f.read(pixels)
        sdata = list(map(lambda n: str(n), bdata))
        csv_f.write(str(label)+",")
        csv_f.write(",".join(sdata)+"\r\n")
        # 잘 저장됐는지 이미지 파일로 저장해서 테스트 하기 --- (3)
        if idx < 10:
            s = "P2 28 28 255\n"
            s += " ".join(sdata)
            iname = "./mnist/{0}-{1}-{2}.pgm".format(name, idx, label)
            with open(iname, "w", encoding="utf-8") as f:
                f.write(s)
    csv_f.close()
    lbl_f.close()
    img_f.close()
# 결과를 파일로 출력하기 --- (4)
# 6만개 처리 시간이 많이 걸려 학습 1000개 / 테스트 500개
to_csv('train', 1000)
to_csv('t10k', 500)

pgm view

 

이미지 데이터 학습하기

  • 손글씨 숫자 데이터를 벡터로 변환

from sklearn import model_selection, svm, metrics
# CSV 파일을 읽어 들이고 가공하기 --- (1)
def load_csv(fname):
    labels = []
    images = []
    with open(fname, 'r') as f:
        for line in f:
            cols = line.split(',')
            if len(cols) < 2 :continue
            labels.append(int(cols.pop(0)))
            # 0<= vals < 1
            vals = list(map(lambda n: int(n) / 256, cols))
            images.append(vals)
    return {'labels':labels, 'images':images}
data = load_csv('./mnist/train.csv')
test = load_csv('./mnist/t10k.csv')
# 학습하기 --- (2)
clf = svm.SVC()
clf.fit(data['images'], data['labels'])
SVC()
# 예측하기 --- (3)
predict = clf.predict(test['images'])
# 결과 확인하기 --- (4)
ac_score = metrics.accuracy_score(test['labels'], predict)
cl_report = metrics.classification_report(test["labels"], predict)
print("정답률 =", ac_score)
print("리포트 =")
print(cl_report)
정답률 = 0.8842315369261478
리포트 =
              precision    recall  f1-score   support

           0       0.87      0.98      0.92        42
           1       0.99      1.00      0.99        67
           2       0.91      0.89      0.90        55
           3       0.94      0.72      0.81        46
           4       0.86      0.93      0.89        55
           5       0.75      0.82      0.78        50
           6       0.95      0.81      0.88        43
           7       0.79      0.94      0.86        49
           8       0.94      0.82      0.88        40
           9       0.89      0.87      0.88        54

    accuracy                           0.88       501
   macro avg       0.89      0.88      0.88       501
weighted avg       0.89      0.88      0.88       501

외국어 문장 판별하기

  • 외국어 글자를 읽어 들이고 어떤 언어인지 판정하는 프로그램 만들기

  • 알파벳을 사용하는 언어라도 프랑스어, 타갈로어(필리핀), 인도네시아어 등

 

판정 방법

  • 글자를 곧바로 학습기에 넣을 수 없음

  • 글자를 나타내는 백터로 변경

  • 언어가 다르면 알파벳 출현 빈도가 다름(언어학)

  • a 부터 z 까지의 출현 빈도를 확인해서 이를 특징으로 사용

샘플 데이터 수집

  • 각 언여별로 풍부한 데이터가 있는 위키피디아 글자 사용

  • 영어(en), 프랑스어(fr), 인도네시아(id), 타갈로어(tl) 테스트

  • 학습데이터 20개 / 테스트 8개

언어 판별

from sklearn import svm, metrics
import glob, os.path, re, json
# 텍스트를 읽어 들이고 출현 빈도 조사하기 --- (※1)
def check_freq(fname):
    name = os.path.basename(fname)

    # 파일이름 앞의 두 문자가 언어 코드
    lang = re.match(r'^[a-z]{2,}', name).group()
    # print(name)
    # print(lang)
    with open(fname, 'r', encoding='utf-8') as f:
        text = f.read()
    text = text.lower() # 소문자 변환

    # 숫자 세기 변수(cnt) 초기화 하기
    cnt = [0 for n in range(0, 26)]

    # ord() 함수 : 특정한 한 문자를 아스키 코드 값으로 변환해 주는 함수
    code_a = ord('a') # 97
    code_z = ord('z') # 122
    # print(code_a)

    # 알파벳 출현 횟수 구하기 --- (2)
    for ch in text:
        n = ord(ch)
        # print(n)
        if code_a <= n <= code_z: # a~z 사이에 있을 때, 알파벳만 처리
            cnt[n - code_a] += 1
    # 정규화 하기 --- (3) 하는 이유 : 각 텍스트 파일에 글자수가 다르므로
    total = sum(cnt)
    freq = list(map(lambda n: n / total, cnt))
    return (freq, lang)
# 각 파일 처리하기
def load_files(path):
    freqs = []
    labels = []
    # glob - 특정 파일만 출력하기
    # https://wikidocs.net/3746
    file_list = glob.glob(path)
    for fname in file_list:
        r = check_freq(fname)
        freqs.append(r[0]) # 빈도수
        labels.append(r[1]) # 국가명
    return {'freqs':freqs, 'labels':labels}
data = load_files("pyml_rev_examples/ch4/lang/train/*.txt")
test = load_files("pyml_rev_examples/ch4/lang/test/*.txt")
# 이후를 대비해서 JSON으로 결과 저장하기 - 이미지 출력용
# JSON 으로 결과 저장했지만 피클로 저장해도 상관없음
with open('pyml_rev_examples/ch4/lang/freq.json', 'w', encoding='utf-8') as fp:
    json.dump([data, test], fp)
# 학습하기 --- (4)
clf = svm.SVC()
clf.fit(data["freqs"], data["labels"])
SVC()
# 예측하기 --- (5)
predict = clf.predict(test['freqs'])
# 결과 테스트하기 --- (6)
ac_score = metrics.accuracy_score(test['labels'], predict)
cl_report = metrics.classification_report(test['labels'], predict)
print("정답률 =", ac_score)
print("리포트 =")
print(cl_report)
정답률 = 1.0
리포트 =
              precision    recall  f1-score   support

          en       1.00      1.00      1.00         2
          fr       1.00      1.00      1.00         2
          id       1.00      1.00      1.00         2
          tl       1.00      1.00      1.00         2

    accuracy                           1.00         8
   macro avg       1.00      1.00      1.00         8
weighted avg       1.00      1.00      1.00         8

데이터마다의 분포를 그래프로 확인

  • 알파벳의 빈도가 어떻게 다른지 시각적으로 확인

import matplotlib.pyplot as plt
import pandas as pd
import json
# 알파벳 출현 빈도 데이터 읽어 들이기 --- (※1)
with open("pyml_rev_examples/ch4/lang/freq.json", "r", encoding="utf-8") as fp:
    freq = json.load(fp)
# 언어마다 계산하기 --- (2)
lang_dic = {}
for i, lbl in enumerate(freq[0]['labels']):
    fq = freq[0]['freqs'][i]
    if not (lbl in lang_dic):
        lang_dic[lbl] = fq
        continue
    for idx, v in enumerate(fq):
        lang_dic[lbl][idx] = (lang_dic[lbl][idx] + v) / 2
# Pandas의 DataFrame에 데이터 넣기 --- (3)
asclist = [[chr(n) for n in range(97, 97+26)]]
df = pd.DataFrame(lang_dic, index=asclist)
df.head()
  en fr id tl
a 0.073919 0.076504 0.171599 0.201979
b 0.020681 0.012910 0.025640 0.022360
c 0.033506 0.036590 0.007429 0.015670
d 0.039112 0.050464 0.040608 0.027269
e 0.131043 0.148523 0.081552 0.055009
# 그래프 그리기 --- (4)
df.plot(kind='bar', subplots=True, ylim=(0, 0.15)) # subplots=True =>각각
plt.savefig('lang-plot.png')

# 다른 그래프로 확인
df.plot(kind='line')

Web 인터페이스 추가

  • 언어판정 모델을 활용해서 언어 판정 웹 서비스 개발

!pip install joblib
Requirement already satisfied: joblib in c:\programdata\anaconda3\envs\r_study\lib\site-packages (0.16.0)
# 언어 판정 마다 데이터 학습은 필요 없으니 학습 모델 저장
from sklearn import svm 
import joblib
# 각 언어의 출현 빈도 데이터(JSON) 읽어 들이기
with open("pyml_rev_examples/ch4/lang/freq.json", "r", encoding="utf-8") as fp:
    d = json.load(fp)
    data = d[0]
# 데이터 학습하기
clf = svm.SVC()
clf.fit(data['freqs'], data['labels'])
# 학습 데이터 저장하기
# 학습한 모델을 저장할 수 있는 joblib
# https://minwook-shin.github.io/python-disk-caching-parallel-computing-using-joblib/
joblib.dump(clf, 'pyml_rev_examples/ch4/lang/freq.pkl')
print('ok')
ok

cgi program 구성

  • 파이썬 내장 웹서버 구성

  • cgi-bin 폴더 내부에 프로그램 배치, 폴더 상위가 root 가 됨

  • root/cgi-bin/웹프로그램.py

  • root 에서 명령어 실행(anaconda 콘솔에서 실행)

    • python -m http.server --cgi 포트

  • 웹프로그램 실행

#!/usr/bin/env python3
import cgi, os.path
from sklearn.externals import joblib

# 학습 데이터 읽어 들이기 ★
pklfile = os.path.dirname(__file__) + '/freq.pkl'
clf = joblib.load(pklfile)

# 텍스트 입력 양식 출력하기
def show_form(text, msg=""):
    print("Content-Type: text/html; charset=utf-8")
    print("")
    print("""
        <html><body><form>
        <textarea name="text" rows="8" cols="40">{0}</textarea>
        <p><input type="submit" value="판정"></p>
        <p>{1}</p>
        </form></body></html>
    """.format(cgi.escape(text), msg))

# 판정하기
def detect_lang(text):
    # 알파벳 출현 빈도 구하기
    text = text.lower() 
    code_a, code_z = (ord("a"), ord("z"))
    cnt = [0 for i in range(26)]
    for ch in text:
        n = ord(ch) - code_a
        if 0 <= n < 26: cnt[n] += 1
    total = sum(cnt)
    if total == 0: return "입력이 없습니다"
    freq = list(map(lambda n: n/total, cnt))
    # 언어 예측하기 ★
    res = clf.predict([freq])
    # 언어 코드를 한국어로 변환하기
    lang_dic = {"en":"영어","fr":"프랑스어",
        "id":"인도네시아어", "tl":"타갈로그어"}
    return lang_dic[res[0]]

# 입력 양식의 값 읽어 들이기
form = cgi.FieldStorage()
text = form.getvalue("text", default="")
msg = ""
if text != "":
    lang = detect_lang(text)
    msg = "판정 결과:" + lang

# 입력 양식 출력
show_form(text, msg)
  • 위 코드 메모장에 붙여넣기 후 lang-Webapp.py (파일형식 : 모든파일)로 저장