현재 진행 중인 프로젝트의 이름은 '글눈'으로, 기초 문해력 강화를 위한 자기주도형 학습 웹 서비스입니다.
사용자가 학습을 원하는 지문을 입력하면, 문해력 강화를 위한 요약 문제와 어휘 문제를 생성하여 제공합니다.
제가 맡은 부분은 어휘 파트로, 어휘 문제 유형은 총 4가지입니다.
1. 용례의 빈칸에 들어갈 단어 찾기
2. 동음이의어의 의미와 용례 연결하기
3. 사전적 의미에 부합하는 단어 찾기
4. 단어의 용례를 보고 해당 단어의 유의어 찾기
위의 어휘 문제를 구현하기 위해서 아래와 같은 과정으로 구현하였습니다.
저희가 사용한 모델은 KoNLPy의 Kkma, bs4의 BeautifulSoup, gensim, Word2Vec(ko.bin) 입니다.
1. 사용자가 학습할 텍스트를 입력받기
2. 텍스트 토큰화, 불용어 제거 후 출제 기준에 맞춰 출제 어휘 선정
#불용어제거 리스트
ko_model = Word2Vec.load('./ko/ko_new.bin')
module_dir = os.path.dirname(__file__)
with open(os.path.join(module_dir, 'stop_word.txt'), encoding = 'cp949') as f:
stop_word = f.readlines()
f.close()
# 출제기준1 (A,B,C)
with open(os.path.join(module_dir, 'WORD_A_01.txt'),encoding = 'cp949') as f:
WORD_A_01 = f.readlines()
f.close()
# 불용어 제거_리스트파일로 바꾸기
stopwords = list(itertools.chain(*stop_word))
no_contain = [',']
stopword = [i for i in stopwords if i not in no_contain]
# 지문에서 불용어 제거한 명사만 있는 리스트
kkma = Kkma()
text_word_list = []
def TEXT_WORD(temp, stopword):
for i in temp:
nouns = kkma.nouns(i)
for noun in nouns:
if noun not in stopword:
text_word_list.append(noun)
return text_word_list
WORD = TEXT_WORD(temp,stopword)
# 출제기준 어휘 데이터 처리
# (리스트 안에 한개의 문자열로 되어 있어 분리하는 작업)
def TOList_A1(WORD_A_01):
# 문자열 한개 -> 여러개로 쪼개기
stringA1 = ''.join(WORD_A_01)
# ,를 기준으로 분리
A01 = stringA1.split(',')
return A01
# 출제기준1&2 - 상(A) 리스트
def EXAM_A1(A01):
exam_A_01 = []
for i in WORD:
if i in A01:
if i not in exam_A_01:
exam_A_01.append(i)
return exam_A_01
word_A_01 = EXAM_A1(TOList_A1(WORD_A_01))
def SAMEWORD(word_A_01):
def target_parse():
try:
TGT = item.find("target_code").get_text()
return {
TGT,
}
except AttributeError as e:
return {
None,
}
url = "https://krdict.korean.go.kr/api/search?"
serviceKey = "certkey_no=3349&key=EAE8B2C9214D808997D177C50333BBFA"
typeOfSearch="&type_search=search"
part = "&part=word"
sort = "&sort=popular"
ex_word = []
for i in word_A_01:
word = i
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
result = requests.get(url+serviceKey+typeOfSearch+part+"&q="+word+sort,verify=False)
soup = BeautifulSoup(result.text,'lxml-xml')
items = soup.find_all("item")
target_row = []
for item in items:
WORD = item.find("word").get_text()
if WORD == word:
target_row.append(str(target_parse())[2:7])
if len(target_row) > 1:
ex_word.append(word)
sameword_list = []
for i in ex_word:
if i not in result:
if len(i) > 1:
sameword_list.append(i)
return sameword_list
#동음이의어 제외한 어휘리스트
def WORD(word_A_01):
sameword = SAMEWORD(word_A_01)
word_list = []
for word in word_A_01:
if word not in sameword:
if len(word)>1:
word_list.append(word)
return word_list
#리스트내에서 중복된 어휘 제거
test_sameword = list(set(SAMEWORD(word_A_01)))
test_word = list(set(WORD(word_A_01)))
여기서 사용된 ko.bin 파일은 아래의 링크를 참고하여 저희가 직접 생성한 뉴스기사 데이터셋으로 추가학습 시킨 모델입니다.
https://www.infoking.site/16?category=899784
워드투벡 단어 추가 및 학습시키는 방법은?!
이전 포스팅에서 워드투벡의 의미와 한글 워드투벡에 대해서 알아보았다. 오늘은 이어서 새로운 단어들을 추가로 학습시켜보고자 한다. 워드투벡을 추가학습하는 방법은 아래 포스팅에 잘 설
www.infoking.site
출제 어휘 선정
#출제 어휘 선정
#2번 문제 어휘 선정
word02 = []
similar_list = []
for i in test_sameword:
t = TEST(i)
result_example = t[1]
ex_example = EXAMPLE(result_example)
if ex_example:
word02.append(i)
similar = t[2]
if similar:
similar_list.append(i)
print(word02)
print(similar_list)
if not word02:
word.append("전면")
else:
word = random.sample(word02,1)
if not similar_list:
word.append("반박")
else:
word.append(random.choice(similar_list))
#1,3번 유형 어휘 선정
word0103 = []
for i in test_word:
w = ko_model.wv.most_similar(i)
if w :
word0103.append(i)
if len(word0103) == 0:
word0103.append("신규")
word0103.append("유입")
elif len(word0103) == 1:
word0103.append("신규")
word_0103 = random.sample(word0103, 2)
word.insert(0,word_0103[0])
word.append(word_0103[1])
return word
3. 보기 어휘 선정
ko.bin 파일로 Word2Vec을 진행하여 출제할 어휘와 유사한 단어를 선정하여 보기 어휘로 사용합니다.
from konlpy.tag import Kkma
import matplotlib.pyplot as plt
from collections import Counter
from gensim.models import Word2Vec
import random
def W2V(word):
ko_model = Word2Vec.load("././ko/ko_new.bin")
example = ko_model.wv.most_similar(word)
print(example)
word_list = []
try:
for i in range(3, len(example)):
if len(example[i][0]) > 1 :
word_list.append(example[i][0])
except:
word_list = example
w2v_word = []
w2v_word = random.sample(word_list, 4)
return w2v_word
4. 한국어 기초 사전 API를 활용하여 필요한 정보 불러오기
저희 유형의 경우 단어의 사전적 의미, 동음이의어 여부, 용례가 필요했습니다.
한국어 기초 사전 API의 key를 발행받은 후, parsing을 위해 bs4의 BeautifulSoup를 사용했습니다.
import requests
from bs4 import BeautifulSoup
word = ""
urls = "https://krdict.korean.go.kr/api/search?"
urlv = "https://krdict.korean.go.kr/api/view?"
serviceKey = "certkey_no=****&key=EAE8B2C9214D808997D177C50333BBFA"
typeOfSearch_s="&type_search=search"
typeOfSearch_v = "&type_search=view"
part = "&part=word"
sort = "&sort=popular"
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
method = "&method=TARGET_CODE"
def TEST(word):
def parse():
try:
TGT = item.find("target_code").get_text()
WORD = item.find("word").get_text()
DEF = item.find("definition").get_text()
return {
"코드":TGT,
"단어":WORD,
"뜻":DEF,
}
except AttributeError as e:
return {
"코드":None,
"단어":None,
"뜻":None,
}
def target_parse():
try:
TGT = item.find("target_code").get_text()
return {
TGT,
}
except AttributeError as e:
return {
None,
}
#parsing 하기
result = requests.get(urls+serviceKey+typeOfSearch_s+part+"&q="+word+sort, verify=False)
soup = BeautifulSoup(result.text,'lxml-xml')
items = soup.find_all("item")
parsing_result = []
for item in items:
WORD = item.find("word").get_text()
if WORD == word:
parsing_result.append(parse())
target_row = []
for item in items:
WORD = item.find("word").get_text()
if WORD == word:
target_row.append(str(target_parse())[2:7])
#용례 가져오기
def parse2():
try:
CODE = item.find("target_code").get_text()
EX = item.find("example").get_text()
return {
"코드":CODE,
"용례":EX,
}
except AttributeError as e:
return {
"코드":None,
"용례":None,
}
def parse3(ex):
try:
CODE = item.find("link_target_code").get_text()
SIMILAR = item.find("word").get_text()
p3 = dict()
p3["예시"]= ex
p3["코드"]=CODE
p3["유의어"] = SIMILAR
return p3
except AttributeError as e:
return 0
example_result = []
similar_result = []
for code in target_row:
word2 = code
result2 = requests.get(urlv+serviceKey+typeOfSearch_v+method+part+"&q="+word2+sort, verify=False)
soup = BeautifulSoup(result2.text,'lxml-xml')
items2 = soup.find_all("item")
items3 = soup.find_all("rel_info")
parse2_result = {}
for item in items2:
parse2_result = parse2()
example_result.append(parse2_result)
for item in items3:
parse3_result = parse3(parse2_result['용례'])
if parse3_result != 0:
similar_result.append(parse3_result)
#유의어 가져오기
return parsing_result, example_result, similar_result
# st = parsing_result
# 뜻
def MEAN(st):
mean = []
for item in st:
mean.append(str(item)[34:])
return mean
# st = example_result
# 예문
def EXAMPLE(st):
example = []
for item in st:
example.append(str(item)[22:])
return example
# st = EXAMPLE의 결과
# 예문빈칸
def EXAMPLE_test(st, targetword):
example = []
for item in st:
val = item.find(targetword
string = item[:val] + "____" + item[val+len(targetword):]
example.append(string)
return example
def SIMILAR(st):
s_word = []
for item in st:
s_word.append(str(item)[24:])
return s_word
위와 같이 파싱 과정을 거쳐
단어의 뜻, 예문, 유의어를 불러오는 MEAN, EXAMPLE, SIMILAR 함수를 작성하였습니다.
그 다음 불러온 정보를 활용하여 문제의 형태로 만들어줍니다.
※
보기 어휘의 경우
Word2Vec을 활용하여 선정하는 W2V_word.py를 import 하여 불러왔고,
보기 단어들의 뜻을 불러오기 위해서 W2V_mean 함수를 작성하여 사용하였습니다.
1. 용례의 빈칸에 들어갈 단어 찾기
상단의 EXAMPLE_test를 호출하여 출제 어휘의 용례에 빈칸을 뚫어줍니다.
출제 어휘와 보기 어휘의 사전적 의미를 추출하여 해설로 제공합니다.
문제를 생성한 후 JSON파일로 return 하도록 하였습니다.
#W2V 어휘들(1번 문제의 보기 단어들의 뜻을 불러오는 함수)
def W2V_MEAN(w2v_word):
n = len(w2v_word)
w2v_mean = []
for i in range(0,n):
t = TEST(w2v_word[i])
result_parse = t[0]
row1 = MEAN(result_parse)
row2 = REMOVE(row1)
w2v_mean.append(row2)
return w2v_mean
#exam_word에서 뽑아온 1번문제 어휘
def t01(word):
#W2V_word에서 뽑아온 보기 어휘
w2v_word = W2V(word)
#parsing에서 코드 추출
t = TEST(word)
result_parse = t[0]
result_example = t[1]
# 뜻 추출
ex_mean = MEAN(result_parse)
# 용례 추출
ex_example = EXAMPLE(result_example)
# 빈칸 문제 생성
ex_test = EXAMPLE_test(ex_example, word)
mean = REMOVE(ex_mean)
test = REMOVE(ex_test)
w2v_mean = W2V_MEAN(w2v_word)
choice = { name:value for name, value in zip(w2v_word, w2v_mean) }
choice[word] = mean
file_exam1 = OrderedDict()
file_exam1["TYPE1"] = "다음 단어 중 빈칸에 들어갈 수 있는 단어를 고르시오."
file_exam1["TEST1"] = test #문제
file_exam1["ANSWER"] = word #단어
file_exam1["CHOICE"] = choice
EXAM1 = json.dumps(file_exam1, ensure_ascii=False, indent="\t")
return EXAM1
2. 동음이의어의 의미와 용례 연결하기
동음이의어 문제로 출제할 단어의 뜻과 용례를 추출하고,
출제 단어가 포함되어있는 문장과 그 앞, 뒷 문장을 추출합니다.
그 후 문제의 형태로 만들어 JSON 파일로 반환합니다.
def t02(word, temp):
#parsing에서 코드 추출
t = TEST(word)
result_parse = t[0]
result_example = t[1]
# 뜻 추출
ex_mean = MEAN(result_parse)
# 용례 추출
ex_example = EXAMPLE(result_example)
# 출제 어휘가 있는 문장과 문장 전후 추출
def Sentence(temp):
sentence_list = []
for i in range(len(temp)):
if word in temp[i]:
if i==0:
sentence_list.append(temp[i])
sentence_list.append(temp[i+1])
elif i==len(temp)-1:
sentence_list.append(temp[i-1])
sentence_list.append(temp[i])
else:
sentence_list.append(temp[i-1])
sentence_list.append(temp[i])
sentence_list.append(temp[i+1])
if len(sentence_list) > 3:
break
return sentence_list
# 뜻
mean = REMOVE(ex_mean)
# 용례
example = REMOVE(ex_example)
# 문장
sentence = Sentence(temp)
choice = { name:value for name, value in zip(mean, example) }
# json파일
file_exam2 = OrderedDict()
file_exam2["TYPE2"] = "위 지문의 '{}'은(는) 동음이의어이다. 각 문장에 사용된 '{}'의 의미로 알맞은 것을 고르시오.".format(word,word)
file_exam2["WORD"] = word #단어
file_exam2["SENTENCE"] = sentence #단어가 있는 문장과 그 전후 문장
file_exam2["CHOICE"] = choice
EXAM2 = json.dumps(file_exam2, ensure_ascii=False, indent="\t")
return EXAM2
3. 사전적 의미에 부합하는 단어 찾기
출제할 어휘의 뜻을 추출한 후 문제의 형태로 만들어 JSON 파일을 반환합니다.
#exam_word에서 뽑아온 3번문제 어휘
def t03(word):
#W2V_word에서 뽑아온 보기 어휘
w2v_word = W2V(word)
#parsing에서 코드 추출
t = TEST(word)
result_parse = t[0]
result_example = t[1]
# 뜻 추출
ex_mean = MEAN(result_parse)
mean = REMOVE(ex_mean)
w2v_mean = W2V_MEAN(w2v_word)
choice = { name:value for name, value in zip(w2v_word, w2v_mean) }
choice[word] = mean
#json파일
#문제 3번은 MEAN 문제, WORD 정답
file_exam3 = OrderedDict()
file_exam3["TYPE3"] = "다음 단어 중 주어진 사전적 의미에 부합하는 단어를 고르시오."
file_exam3["ANSWER"] = word #단어
file_exam3["MEAN"] = mean #뜻
file_exam3["CHOICE"] = choice
EXAM3 = json.dumps(file_exam3, ensure_ascii=False, indent="\t")
return EXAM3
4. 단어의 용례를 보고 해당 단어의 유의어 찾기
출제 어휘의 용례와, 유의어를 불러와 문제의 형태로 만든 후 JSON 파일로 반환합니다.
def t04(word):
#W2V_word 파일의 W2V 함수 사용하여 보기 단어 추출
w2v_word = W2V(word)
t = TEST(word)
result_parse = t[0]
result_similar = t[2]
result_similar = random.choice(result_similar)
mean = result_similar['예시']
similar = result_similar['유의어']
similar_list = []
similar_list.append(similar)
#출제 어휘와 보기 어휘
w2v_mean = W2V_MEAN(w2v_word) + W2V_MEAN(similar_list)
#출제 어휘와 보기 어휘의 뜻
w2v_word = w2v_word + similar_list
choice = { name:value for name, value in zip(w2v_word, w2v_mean) }
#JSON 파일
file_exam4 = OrderedDict()
file_exam4["TYPE4"] = "다음 단어 "+word+"와(과) 의미가 비슷한 어휘(유의어)를 고르시오."
file_exam4["ANSWER"] = similar #유의어
file_exam4["MEAN"] = mean #뜻
file_exam4["CHOICE"] = choice #보기
EXAM4 = json.dumps(file_exam4, ensure_ascii=False, indent="\t")
print(EXAM4)
return EXAM4
구현 결과
![](https://blog.kakaocdn.net/dn/bDIMeR/btrCqo4WglL/2lH6BZjXWHeSV7gpLKAwK1/img.png)
![](https://blog.kakaocdn.net/dn/X6dSS/btrCqoRlSuQ/zMFcei4NL8VNRiEbSurT0K/img.png)