Machine-Learning
머신러닝이란?
머신러닝(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
-
학습전용 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
-
value view: http://paulcuth.me.uk/netpbm-viewer/
-
image view: https://www.xnview.com/
-
image make: https://oneday0012.tistory.com/8
이미지 데이터 학습하기
-
손글씨 숫자 데이터를 벡터로 변환
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 (파일형식 : 모든파일)로 저장