본문 바로가기
AI

자연어 처리 개요

by 코낄2 2024. 1. 16.

1. 자연어(Natural Language)

자연어는 인간이 일상적으로 사용하는 언어를 의미합니다. 언어의 형태와 의미를 가지며, 일반적으로 의사소통의 수단으로 사용됩니다. 예를 들면, 한국어, 영어, 중국어 등이 자연어에 해당합니다. 자연어는 문법, 어휘, 문맥 등 다양한 측면에서 다양한 특징을 가지고 있습니다.

1-1. 자연어 처리(Natural Language Processing)

자연어 처리는 기계가 인간의 언어를 이해하고 해석하는 분야를 가리킵니다. NLP는 자연어에서 의미있는 정보를 추출하여 활용함으로써 인간의 언어적 능력을 기계적으로 모델링하고, 기계가 텍스트나 음성을 처리하고 분석하는 기술을 포함합니다. 이를 통해 기계는 자연어의 의미를 이해하고, 번역하며, 질문에 답하고, 감정을 분석하고, 요약을 생성할 수 있게 됩니다.

1-2. 자연어 처리의 활용

  • 문서 분류, 스팸 처리와 같은 분류 문제
  • 검색어 추천
  • 음성 인식, 질의 응답, 번역
  • 소셜 미디어 분석

1-3. 자연어 처리의 용어

🔷 자연어 이해 (Natural Language Understanding, NLU)

자연어 이해는 자연어 처리의 하위 집합으로, 기계가 자연어의 실제 의미, 의도, 감정, 질문 등을 사람처럼 이해하도록 돕는 기술입니다. 기계가 다양한 텍스트의 숨겨진 의미를 해석하기 위해서는 사전 처리 작업과 추가적인 학습이 필요합니다. 비 언어적인 신호인 표정, 손짓, 몸짓도 힌트로 활용될 수 있습니다. 또한, 텍스트에서 의미있는 정보를 추출하는 기술과 통계적으로 학습시킬 수 있는 다량의 데이터가 필요합니다.

🔷 자연어 생성 (Natural Language Generation, NLG)

자연어 생성은 기계가 사람의 언어를 직접 생성하는 기술을 의미합니다. 이는 기계가 일련의 계산 결과를 사람의 언어로 표현하도록 돕는 역할을 합니다. NLG는 자연어 처리의 중요한 부분 중 하나로, 기계가 특정 작업에 대한 결과를 이해하기 쉬운 언어로 표현하거나, 요약을 생성하거나, 대화형 인터페이스에서 응답을 생성하는 등 다양하게 활용됩니다.

2. 토그나이징(Tokenization)

토크나이징은 문장을 의미가 있는 가장 작은 단위인 '토큰'으로 나누는 과정을 말합니다. 이 작업은 문장 형태의 데이터를 처리하기 위한 기본적이고 중요한 단계로, 토크나이징을 어떻게 수행하느냐에 따라 자연어 처리 시스템의 성능에 큰 영향을 미칠 수 있습니다. 토큰은 일반적으로 단어로 사용되며, 문장을 이해하고 분석하기 위한 기본 단위로 활용됩니다.

3. 형태소 분석(Morphological Analysis)

형태소 분석은 자연어의 문장을 형태소라는 최소 의미 단위로 분할하고, 각 형태소의 품사를 판별하는 작업입니다. 영어의 경우 형태소 간에 띄어쓰기가 있어 비교적 간단하지만, 아시아 계열의 언어, 특히 한국어는 형태소 분석이 더 복잡하며 많은 노력이 필요합니다.

- 한국어 형태소 분석: 한국어 형태소 분석 라이브러리 중 하나인 KoNLPy를 활용할 수 있습니다.

설치 : !pip install KoNLPy

# KoNLPy에는 kolaw(대한민국 헌법 텍스트 파일)를 제공
from konlpy.corpus import kolaw

kolaw.fileids() // ['constitution.txt']

코퍼스는 텍스트 데이터의 집합으로, 주로 자연어 처리 작업을 위한 학습 데이터나 테스트 데이터로 사용됩니다. KoNLPy의 kolaw 코퍼스는 대한민국의 법률 문서를 포함하고 있습니다. fileids() 메서드를 호출하면 해당 코퍼스에 포함된 파일들의 목록을 얻을 수 있습니다.

law = kolaw.open('constitution.txt').read()

'대한민국헌법

유구한 역사와 전통에 빛나는 우리 대한국민은 3·1운동으로 건립된 대한민국임시정부의 법통과 불의에 항거한 4·19민주이념을 계승하고, 조국의 민주개혁과 평화적 통일의 사명에 입각하여 정의·인도와 동포애로써 민족의 단결을 공고히 하고, 모든 사회적 폐습과 불의를 타파하며, 자율과 조화를 바탕으로 자유민주적 기본질서를 더욱 확고히 하여 정치·경제·사회·문화의 모든 영역에 있어서 각인의 기회를 균등히 하고, 능력을 최고도로 발휘하게 하며, 자유와 권리에 따르는 책임과 의무를 완수하게 하여, 안으로는 국민생활의 균등한 향상을 기하고 밖으로는 항구적인 세계평화와 인류공영에 이바지함으로써 우리들과 우리들의 자손의 안전과 자유와 행복을 영원히 확보할 것을 다짐하면서 1948년 7월 12일에 제정되고 8차에 걸쳐 개정된 헌법을 이제 국회의 의결을 거쳐 국민투표에 의하여 개정한다.....'

# KoNLPy에는 kobill(국회법안 파일)을 제공
from konlpy.corpus import kobill

kobill.fileids()
['1809896.txt',
 '1809895.txt',
 '1809894.txt',
 '1809892.txt',
 '1809897.txt',
 '1809898.txt',
 '1809899.txt',
 '1809893.txt',
 '1809891.txt',
 '1809890.txt']
bill = kobill.open('1809895.txt').read()

'하도급거래 공정화에 관한 법률 일부개정법률안\n\n(유선호의원 대표발의 )\n\n 의 안\n 번 호\n\n9895\n\n발의연월일 : 2010.  11.  15.\n\n발  의  자 : 유선호․강기갑․김효석  \n\n조승수ㆍ최문순ㆍ조영택  \n\n문학진ㆍ백재현ㆍ송민순  \n\n박은수ㆍ정동영ㆍ김춘진  \n\n김재윤ㆍ우윤근ㆍ이성남  \n\n이종걸 의원(16인)\n\n제안이유 및 주요내용\n\n  원․수급사업자 사이의 하도급거래는 외형적으로 공정한 계약을 체\n\n결할지라도 교섭력에서 절대 우위에 있는 원사업자에 의한 불공정한 \n\n행위의 가능성은 여전히 상존하고 있음. 또한 수급사업자는 원사업자\n\n의 부당행위에 의하여 손해를 입게 된 경우에도 입증의 부담을 안기 \n\n때문에 민사소송에 의한 피해구제도 쉽지 않은 실정임.  \n\n  이에 서면에 의한 계약을 따르지 않을 경우 벌금에 처하도록 하고, \n\n손해배상에 있어서 입증책임을 원사업자에게 전환시키며, 법원이 추정\n\n에 의한 손해액의 인정을 할 수 있게 하여 수급사업자가 소송을 용의\n\n- 1 -\n\n\x0c- 2 -\n\n하게 진행할 수 있도록 함으로써 비대칭적인 교섭력과 정보력의 차이\n\n를 보완하고, 나아가 공정한 하도급거래 질서가 유지․발전 되도록 하\n\n려는 것임(안 제35조 및 제36조 신설). \n\n\x0c법률  제        호\n\n하도급거래 공정화에 관한 법률 일부개정법률안\n\n하도급거래 공정화에 관한 법률 일부를 다음과 같이 개정한다.\n\n제30조제2항제1호 및 제2호를 각각 제2호 및 제3호로 하고, 같은 항에 \n\n제1호를 다음과 같이 신설한다.'

4. 분석기 종류

분석기들은 한국어 텍스트의 형태소(명사, 대명사, 수사, 동사, 형용사, 관형사, 부사, 조사, 감탄사)를 분석하여 의미 단위로 나누어주는 역할을 하며, 자연어 처리 작업에서 중요한 선행 단계로 활용됩니다.

  1. Hannanum (한나눔): KAIST Semantic Web Research Center에서 개발했습니다.
  2. Kkma (꼬꼬마): 서울대학교 IDS 연구실에서 개발했습니다. Kkma는 형태소 분석 뿐만 아니라 구문 분석과 의미 분석에도 중점을 둔다는 특징이 있습니다. 따라서 문장의 구조와 의미를 더 깊게 이해하고자 하는 경우에 활용될 수 있습니다.
  3. Komoran (코모란): Shineware에서 개발되었습니다. Komoran은 빠른 속도와 높은 정확도를 가진 형태소 분석기로 알려져 있습니다. 주로 대용량 텍스트 데이터를 처리하는 데에 적합합니다.
  4. Okt (Open Korean Text): Okt는 과거에는 트위터에서 사용되던 형태소 분석기로, 현재는 Open Korean Text로 불립니다. 오픈소스로 공개되어 있어 사용자들이 자유롭게 활용할 수 있으며, 상대적으로 가벼운 분석기로 알려져 있습니다.
from konlpy.tag import *

hannanum = Hannanum()
kkma = Kkma()
komoran = Komoran()
okt = Okt()

law[:50]
// 대한민국헌법 유구한 역사와 전통에 빛나는 우리 대한국민은 3·1운동으로 건립된 대한민국임
  • .nouns() : 명사만 추출해준다.
hannanum.nouns(law[:50])

// ['대한민국헌법', '유구', '역사', '전통', '빛', '우리', '대한국민', '3·1운동', '건립', '대한민국임']

kkma.nouns(law[:50])

// ['대한', '대한민국', '대한민국헌법', '민국', '헌법', '유구', '역사', '전통', '우리', '국민', '3', '1', '1운동', '운동', '건립', '대한민국임', '임']

komoran.nouns(law[:50])

// ['대한민국', '헌법', '역사', '전통', '국민', '운동', '건립', '대한민국', '임']

okt.nouns(law[:50])

// ['대한민국', '헌법', '유구', '역사', '전통', '우리', '국민', '운동', '건립', '대한민국', '임']

  • morphs(): 한국어 문장을 형태소 단위로 분리하여 모든 형태소들을 리스트로 반환
# 예시는 한나눔만
hannanum.morphs(law[:50])

// ['대한민국헌법', '유구', '하', 'ㄴ', '역사', '와', '전통', '에', '빛', '나는', '우리', '대한국민', '은', '3·1운동', '으로', '건립', '되', 'ㄴ', '대한민국임']

  • pos(): 주어진 한국어 문장을 형태소 단위로 분리하고, 각 형태소의 품사를 함께 반환
hannanum.pos(law[:50])

[('대한민국헌법', 'N'),
 ('유구', 'N'),
 ('하', 'X'),
 ('ㄴ', 'E'),
 ('역사', 'N'),
 ('와', 'J'),
 ('전통', 'N'),
 ('에', 'J'),
 ('빛', 'N'),
 ('나는', 'J'),
 ('우리', 'N'),
 ('대한국민', 'N'),
 ('은', 'J'),
 ('3·1운동', 'N'),
 ('으로', 'J'),
 ('건립', 'N'),
 ('되', 'X'),
 ('ㄴ', 'E'),
 ('대한민국임', 'N')]

okt.pos(law[:50])

[('대한민국', 'Noun'),
 ('헌법', 'Noun'),
 ('\n\n', 'Foreign'),
 ('유구', 'Noun'),
 ('한', 'Josa'),
 ('역사', 'Noun'),
 ('와', 'Josa'),
 ('전통', 'Noun'),
 ('에', 'Josa'),
 ('빛나는', 'Verb'),
 ('우리', 'Noun'),
 ('대', 'Modifier'),
 ('한', 'Modifier'),
 ('국민', 'Noun'),
 ('은', 'Josa'),
 ('3', 'Number'),
 ('·', 'Punctuation'),
 ('1', 'Number'),
 ('운동', 'Noun'),
 ('으로', 'Josa'),
 ('건립', 'Noun'),
 ('된', 'Verb'),
 ('대한민국', 'Noun'),
 ('임', 'Noun')]

  • Okt에서는 tagset으로 분석기에서 사용되는 품사 태그를 확인 가능
okt.tagset

{'Adjective': '형용사',
 'Adverb': '부사',
 'Alpha': '알파벳',
 'Conjunction': '접속사',
 'Determiner': '관형사',
 'Eomi': '어미',
 'Exclamation': '감탄사',
 'Foreign': '외국어, 한자 및 기타기호',
 'Hashtag': '트위터 해쉬태그',
 'Josa': '조사',
 'KoreanParticle': '(ex: ㅋㅋ)',
 'Noun': '명사',
 'Number': '숫자',
 'PreEomi': '선어말어미',
 'Punctuation': '구두점',
 'ScreenName': '트위터 아이디',
 'Suffix': '접미사',
 'Unknown': '미등록어',
 'Verb': '동사'}

text = '아버지가방에들어가신다'
okt.pos(text)
// [('아버지', 'Noun'), ('가방', 'Noun'), ('에', 'Josa'), ('들어가신다', 'Verb')]

text = '아버지가 방에 들어가신다'
okt.pos(text)
// [('아버지', 'Noun'), ('가', 'Josa'), ('방', 'Noun'), ('에', 'Josa'), ('들어가신다', 'Verb')]
  • norm = True : 각 형태소에 대한 원형으로 처리
  • stem = True: 원형 글자로 변경
okt.pos('오늘 날씨가 참 춥네욬ㅋㅋㅋㅋ')
[('오늘', 'Noun'),
 ('날씨', 'Noun'),
 ('가', 'Josa'),
 ('참', 'Verb'),
 ('춥네욬', 'Noun'),
 ('ㅋㅋㅋㅋ', 'KoreanParticle')]

okt.pos('오늘 날씨가 참 춥네욬ㅋㅋㅋㅋ', norm=True)
[('오늘', 'Noun'),
 ('날씨', 'Noun'),
 ('가', 'Josa'),
 ('참', 'Verb'),
 ('춥네요', 'Verb'),
 ('ㅋㅋㅋ', 'KoreanParticle')]
 
 okt.pos('오늘 날씨가 참 춥네욬ㅋㅋㅋㅋ',norm=True, stem=True)
 [('오늘', 'Noun'),
 ('날씨', 'Noun'),
 ('가', 'Josa'),
 ('차다', 'Verb'),
 ('추다', 'Verb'),
 ('ㅋㅋㅋ', 'KoreanParticle')]

4. 워드 클라우드(Word Cloud)

워드 클라우드(Word Cloud)는 문서 내에서 핵심 단어를 시각적으로 표현하는 기법입니다. 이 기법은 문서의 키워드나 주요 개념을 한눈에 파악할 수 있도록 핵심 단어들을 시각적으로 돋보이게 합니다. 일반적으로 빈도수가 높은 단어일수록 크게 표현되며, 이를 통해 문서의 주요 주제나 내용을 직관적으로 이해할 수 있습니다.

!pip install wordcloud

from wordcloud import WordCloud
# generate(): 단어별 출현 빈도수를 비율로 반환하는 객체를 생성
wordcloud = WordCloud().generate(text)
wordcloud // <wordcloud.wordcloud.WordCloud at 0x7ada540fd060>
wordcloud.words_
{'said': 1.0,
 'Alice': 0.7225433526011561,
 'said Alice': 0.3352601156069364,
 'little': 0.31213872832369943,
 .
 .
 .
 'name': 0.03468208092485549,
 'Dinah': 0.03468208092485549,
 'afraid': 0.03468208092485549}
import matplotlib.pyplot as plt

plt.figure(figsize=(15,10))
plt.imshow(wordcloud)
plt.axis('off')
plt.show()

# max_words: 워드 클라우드에 표시되는 단어의 개수를 설정
wordcloud = WordCloud(max_words=100).generate(text)
plt.figure(figsize=(15,10))
plt.imshow(wordcloud)
plt.axis('off')
plt.show()

# 폰트 다운받기(nanum으로 시작하는 모든 글씨체 다운)

!apt-get update -qq
!apt-get install fonts-nanum* -qq

import matplotlib.font_manager as fm
sys_font = fm.findSystemFonts()
[f for f in sys_font if 'Nanum' in f]

['/usr/share/fonts/truetype/nanum/NanumSquareR.ttf',
 '/usr/share/fonts/truetype/nanum/NanumGothicCodingBold.ttf',
 '/usr/share/fonts/truetype/nanum/NanumBarunGothicBold.ttf',
 '/usr/share/fonts/truetype/nanum/NanumMyeongjoEcoR.ttf',
 '/usr/share/fonts/truetype/nanum/NanumGothicEco.ttf',
 '/usr/share/fonts/truetype/nanum/NanumSquareRoundL.ttf',
 '/usr/share/fonts/truetype/nanum/NanumSquareRoundEB.ttf',
 '/usr/share/fonts/truetype/nanum/NanumGothic.ttf',
 '/usr/share/fonts/truetype/nanum/NanumSquareRoundB.ttf',
 '/usr/share/fonts/truetype/nanum/NanumGothicCoding.ttf',
 '/usr/share/fonts/truetype/nanum/NanumSquare_acEB.ttf',
 '/usr/share/fonts/truetype/nanum/NanumSquareRoundR.ttf',
 '/usr/share/fonts/truetype/nanum/NanumBarunGothicLight.ttf',
 '/usr/share/fonts/truetype/nanum/NanumGothicLight.ttf',
 '/usr/share/fonts/truetype/nanum/NanumBarunGothic-YetHangul.ttf',
 '/usr/share/fonts/truetype/nanum/NanumMyeongjo-YetHangul.ttf',
 '/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf',
 '/usr/share/fonts/truetype/nanum/NanumGothicEcoBold.ttf',
 '/usr/share/fonts/truetype/nanum/NanumPen.ttf',
 '/usr/share/fonts/truetype/nanum/NanumSquare_acB.ttf',
 '/usr/share/fonts/truetype/nanum/NanumGothicExtraBold.ttf',
 '/usr/share/fonts/truetype/nanum/NanumMyeongjoEco.ttf',
 '/usr/share/fonts/truetype/nanum/NanumMyeongjoEcoExtraBold.ttf',
 '/usr/share/fonts/truetype/nanum/NanumSquareEB.ttf',
 '/usr/share/fonts/truetype/nanum/NanumGothicEcoExtraBold.ttf',
 '/usr/share/fonts/truetype/nanum/NanumGothicEcoR.ttf',
 '/usr/share/fonts/truetype/nanum/NanumSquare_acL.ttf',
 '/usr/share/fonts/truetype/nanum/NanumMyeongjoExtraBold.ttf',
 '/usr/share/fonts/truetype/nanum/NanumBarunGothicUltraLight.ttf',
 '/usr/share/fonts/truetype/nanum/NanumGothicBold.ttf',
 '/usr/share/fonts/truetype/nanum/NanumSquare_acR.ttf',
 '/usr/share/fonts/truetype/nanum/NanumSquareB.ttf',
 '/usr/share/fonts/truetype/nanum/NanumBrush.ttf',
 '/usr/share/fonts/truetype/nanum/NanumSquareL.ttf',
 '/usr/share/fonts/truetype/nanum/NanumBarunpenR.ttf',
 '/usr/share/fonts/truetype/nanum/NanumMyeongjo.ttf',
 '/usr/share/fonts/truetype/nanum/NanumBarunpenB.ttf',
 '/usr/share/fonts/truetype/nanum/NanumMyeongjoEcoBold.ttf',
 '/usr/share/fonts/truetype/nanum/NanumMyeongjoBold.ttf']
wordcloud = WordCloud(max_words=100,
                      font_path = '/usr/share/fonts/truetype/nanum/NanumPen.ttf').generate(text)
plt.figure(figsize=(15,10))
plt.imshow(wordcloud)
plt.axis('off')
plt.show()

  • mask : 특정한 모양이나 이미지를 사용하여 워드 클라우드를 해당 모양으로 제한하는 기법. 코랩에서는 어두운 부분에 워드가 표출되도록 기본값이 설정되어 있음
from PIL import Image
import numpy as np

alice_mask = np.array(Image.open('/content/drive/MyDrive/KDT/자연어 처리/data/alice_mask.png'))
wordcloud = WordCloud(max_words=150,
                      font_path = '/usr/share/fonts/truetype/nanum/NanumPen.ttf',
                      mask=alice_mask,
                      background_color='ivory').generate(text)
plt.figure(figsize=(15,10))
plt.imshow(wordcloud)
plt.axis('off')
plt.show()

(왼) 미리 준비한 mask 이미지 (오) 마스크를 씌운 워드 클라우드


# kolaw에서 constitution.txt 파일을 읽어오기
text = kolaw.open('constitution.txt').read()
text

'대한민국헌법\n\n유구한 역사와 전통에 빛나는 우리 대한국민은 3·1운동으로 건립된 대한민국임시정부의 법통과 불의에 항거한 4·19민주이념을 계승하고, 조국의 민주개혁과 평화적 통일의 사명에 입각하여 정의·인도와 동포애로써 민족의 단결을 공고히 하고, 모든 사회적 폐습과 불의를 타파하며, 자율과 조화를 바탕으로.....'

# Okt를 분석기를 이용하여 해당 파일의 내용 중 명사만 추출하기
nouns = okt.nouns(text)

# 단어의 길이를 기준으로 오름차순 저장
nouns.sort(key=lambda x: len(x))
# 불용어를 제외한 단어만 저장
# set을 통해 중복을 없앤 리스트에서 불용어 찾기
nouns_set = list(set(nouns)) 
print(sorted(nouns_set, key=lambda x: len(x)))

# 찾은 불용어 없애기
exclude_words = ['이내', '날로','범한', '일로', '그때', '다만', '또한', '로써', '붙이',
		'로서', '거나', '로부터','내지','얻지']
nouns = [word for word in nouns if word not in exclude_words]
# 2자 이상만 저장
nouns = [word for word in nouns if len(word) >= 2]
# 빈도수가 많은 단어 top100을 저장

from collections import Counter

word_counts = Counter(nouns)
print(word_counts)
// Counter({'법률': 127, '대통령': 83, '국가': 73, '국회': 68, '국민': 61....})

top_words = word_counts.most_common(100)
top_words = dict(top_words)
print(top_words)
// {'법률': 127, '대통령': 83, '국가': 73, '국회': 68, '국민': 61, '헌법': 53, ...}
# 워드 클라우드 생성
korea_mask = np.array(Image.open('/content/drive/MyDrive/KDT/자연어 처리/data/korea_mask.jpg'))

wordcloud = WordCloud(max_words=150,
                      font_path = '/usr/share/fonts/truetype/nanum/NanumPen.ttf',
                      mask=korea_mask,
                      background_color='ivory').generate_from_frequencies(top_words)
plt.figure(figsize=(15,10))
plt.imshow(wordcloud)
plt.axis('off')
plt.show()

'AI' 카테고리의 다른 글

데이터 전처리 실습  (0) 2024.01.19
자연어 처리 진행 순서  (0) 2024.01.19
포켓몬 분류 해보기  (1) 2024.01.14
전이 학습  (0) 2024.01.12
간단한 CNN모델 만들기 실습  (1) 2024.01.11