자연어처리 입문 - 1. numpy, matplotlib 2. 텍스트 전처리(1)

Sunghee Park·2023년 2월 12일

자연어

목록 보기
1/1

NLTK(엔엘티케이)

  • 자연어 처리를 위한 파이썬 패키지

KoNLPy(코엔엘파이)

  • 한국어 자연어 처리를 위한 형태소 분석기 패키지

numpy

  1. np.array() 배열 생성
    numpy의 핵심은 ndarray
  • 1차원 배열
    vec=np.array([1,2,3,4,5])

  • 2차원 배열
    mat=np.array([[10,20,30],[60,70,80]])

  • 타입 확인
    print(type(vec))
    #<class 'numpy.ndarray'>

  • 축의 개수, 크기
    print(vec.ndim) #축의 개수
    print(vec.shape) #크기 출력
    #1
    #(5,)

print(mat.ndim)
print(mat.shape)
#2
#(2,3)

  1. ndarray 초기화
  • np.zeros()
    배열의 모든 원소에 0 삽입
    zero_mat=np.zeros((2,3))
    print(zero_mat)
    #[[0 0 0][0 0 0]]

  • np.ones()
    배열의 모든 원소에 1 삽입
    one_mat=np.ones((2,3))
    print(one_mat)
    #[[1 1 1][1 1 1]]

  • np.full((2,2), 7)
    배열에 사용자가 지정한 값을 삽입, 모든 값이 특정 상수인 배열 생성
    same_value_mat=np.full((2,2),7)
    print(same_value_mat)
    #[[7 7][7 7]]

  • np.eye()
    대각선이 1, 나머지는 0인 2차원 배열을 생성
    eye_mat=np.eye(3)
    print(eye_mat)
    #[[1 0 0][0 1 0]
    [0 0 1]]

  • np.random.random()
    임의의 값으로 채워진 배열 생성ㅇ
    random_mat=np.random.random((2,2))
    print(random_mat)
    #[[0.3111881 0.72996102][0.65667734 0.40758328]]

  1. np.arange()
  • np.arange(n) : 0부터 n-1까지의 값을 가지는 배열을 생성
    #0부터 9까지
    range_vec = np.arange(10)
    print(range_vec)
    #[0 1 2 3 4 5 6 7 8 9]

  • np.arange(i, j, k) : i부터 j-1까지 k씩 증가하는 배열을 생성
    #1부터 9까지 +2씩 적용되는 범위
    n = 2
    range_n_step_vec = np.arange(1, 10, n)
    print(range_n_step_vec)
    #[1 3 5 7 9]

  1. np.reshape()
  • np.reshape()은 내부 데이터는 변경하지 않으면서 배열의 구조를 바꿈
    0부터 29까지의 숫자를 생성하는 arange(30)을 수행한 후, 원소의 개수가 30개이므로 5행 6열의 행렬로 변경

reshape_mat = np.array(np.arange(30)).reshape((5,6))
print(reshape_mat)
#[[ 0 1 2 3 4 5][ 6 7 8 9 10 11]
[12 13 14 15 16 17][18 19 20 21 22 23]
[24 25 26 27 28 29]]

  1. Numpy 슬라이싱
  • 슬라이싱 기능을 사용하여 특정 행이나 열들의 원소들을 접근

mat=np.array([[1, 2, 3], [4, 5, 6]])
print(mat)
#[[1 2 3][4 5 6]]

#첫번째 행 출력
slicing_mat = mat[0, :]
print(slicing_mat)
#[1 2 3]

#두번째 열 출력
slicing_mat = mat[:, 1]
print(slicing_mat)
#[2 5]

  1. Numpy 정수 인덱싱
    #원소 하나 뽑기
    mat=np.array([[1 2], [4 5], [7 8]])
    print(mat[1,0])
    #4

#2행2열의 원소와 5행5열의 원소 뽑기
indexing_mat=mat[[2, 1],[0,1]]
print(indexing_mat)
#[7 5]

  1. Numpy 연산
    x=np.array([1,2,3])
    y=np.array([4,5,6])
  • +
    #np.add(x,y)와 동일
    result=x+y
    print(result)
    #[5 7 9]
  • -
    #np.subtract(x,y)와 동일
    result=x-y
    print(result)
    #[-3 -3 -3]

  • *
    result=result*x
    #np.multiply(result,x)와 동일
    print(result)
    #[-3 -6 -9]

  • /
    #np.divide(result,x)와 동일
    result=result/x
    print(result)
    #[-3 -3 -3]

  • 행렬곱 dot()
    벡터의 행렬곱
    at2 = np.array([[5,6],[7,8]])
    mat3 = np.dot(mat1, mat2)
    print(mat3)
    #[[19 22][43 50]]

Matplotlib 맷플롯립

import matplotlib as mpl
import matplotlib.pyplot as plt

1) 라인 플롯 그리기

  • plot()에 x축과 y축의 값을 기재
  • title('제목')
  • show()
    plt.title('test')
    plt.plot([1,2,3,4],[2,4,8,6])
    plt.show()

2) 축 레이블 삽입

  • xlabel('넣고 싶은 축이름')

  • ylabel('넣고 싶은 축이름')
    plt.title('test')
    plt.plot([1,2,3,4],[2,4,8,6])
    plt.xlabel('hours')
    plt.ylabel('score')
    plt.show()

3) 라인 추가와 범례 삽입

  • plot.([1,2,3],[3,5,8]) #라인 새로 추가
  • .legend(['첫번째 라인 범례 이름','두번째 라인 범례 이름'])
    plt.title('students')
    plt.plot([1,2,3,4],[2,4,8,6])
    plt.plot([1.5,2.5,3.5,4.5],[3,5,8,10]) # 라인 새로 추가
    plt.xlabel('hours')
    plt.ylabel('score')
    plt.legend(['A student', 'B student']) # 범례 삽입
    plt.show()

텍스트 전처리

자연어 처리에서 크롤링 등으로 얻어낸 코퍼스 데이터가 필요에 맞게 전처리되지 않은 상태일때,
해당 데이터를 사용하고자하는 용도에 맞게 토큰화(tokenization) & 정제(cleaning) & 정규화(normalization) 진행

  • 토큰화
    주어진 코퍼스(corpus)에서 토큰(token)이라 불리는 단위로 나누는 작업

토큰화

1. 단어 토큰화

토큰의 기준을 단어(word)로 하는 경우=> 단어 토큰화(word tokenization)

ex)
입력: Time is an illusion. Lunchtime double so!
=> 구두점 제외시킨 토큰화 작업 =>
출력 : "Time", "is", "an", "illustion", "Lunchtime", "double", "so"

NLTK - word_tokenize와 WordPunctTokenizer => 토큰화 처리 도구에 따라 토큰화 방법 조금씩 다름

2. 문장 토큰화

여러 개의 문장들로부터 문장을 구분
문장 중간에 마침표가 다수 등장하는 경우에 대해서도 tokenizer에 따라 다르게 구분
from nltk.tokenize import sent_tokenize : 영어 문장 토큰화 도구
import kss : 한국어 문장 토큰화 도구

3. 한국어 토큰화의 어려움

  • 형태소
    자립형태소(체언(명사, 대명사, 수사), 수식언(관형사, 부사), 감탄사 등)
    의존 형태소(접사, 어미, 조사, 어간)
    ex)
    문장 : 에디가 책을 읽었다
    자립 형태소 : 에디, 책
    의존 형태소 : -가, -을, 읽-, -었, -다

  • 잘 지켜지지 않는 띄어쓰기

4. 품사 태깅

  • 품사에 따라 단어 의미가 달라짐
    - fly : 날다 / 파리
    • 못 : 부사 못~ / 명사 못

      => 단어 파악하기 위해서는 해당 단어가 어떤 품사로 쓰였는지 보는 것이 주요 지표
      => 단어 토큰화 과정에서 각 단어가 어떤 품사로 쓰였는지를 구분해놓기도 함 : 품사 태깅 과정
      => NLTK와 KoNLPy를 통해 품사 태깅 (아래 실습)

5. NLTK, KoNLPy 이용한 영어, 한국어 토큰화

  • 영어 토큰화
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag

text = "I am actively looking for Ph.D. students. and you are a Ph.D. student."
tokenized_sentence = word_tokenize(text)

print('단어 토큰화 :',tokenized_sentence)
print('품사 태깅 :',pos_tag(tokenized_sentence))
단어 토큰화 : ['I', 'am', 'actively', 'looking', 'for', 'Ph.D.', 'students', '.', 'and', 'you', 'are', 'a', 'Ph.D.', 'student', '.']
품사 태깅 : [('I', 'PRP'), ('am', 'VBP'), ('actively', 'RB'), ('looking', 'VBG'), ('for', 'IN'), ('Ph.D.', 'NNP'), ('students', 'NNS'), ('.', '.'), ('and', 'CC'), ('you', 'PRP'), ('are', 'VBP'), ('a', 'DT'), ('Ph.D.', 'NNP'), ('student', 'NN'), ('.', '.')]
  • 한국어 토큰화
  1. Okt 형태소 분석기
from konlpy.tag import Okt
from konlpy.tag import Kkma

okt = Okt()
kkma = Kkma()

print('OKT 형태소 분석 :',okt.morphs("열심히 코딩한 당신, 연휴에는 여행을 가봐요"))
print('OKT 품사 태깅 :',okt.pos("열심히 코딩한 당신, 연휴에는 여행을 가봐요"))
print('OKT 명사 추출 :',okt.nouns("열심히 코딩한 당신, 연휴에는 여행을 가봐요")) 

1) morphs : 형태소 추출
2) pos : 품사 태깅(Part-of-speech tagging)
3) nouns : 명사 추출

OKT 형태소 분석 : ['열심히', '코딩', '한', '당신', ',', '연휴', '에는', '여행', '을', '가봐요']
OKT 품사 태깅 : [('열심히', 'Adverb'), ('코딩', 'Noun'), ('한', 'Josa'), ('당신', 'Noun'), (',', 'Punctuation'), ('연휴', 'Noun'), ('에는', 'Josa'), ('여행', 'Noun'), ('을', 'Josa'), ('가봐요', 'Verb')]
OKT 명사 추출 : ['코딩', '당신', '연휴', '여행']
  1. kkma (꼬꼬마 형태소 분석기)
print('꼬꼬마 형태소 분석 :',kkma.morphs("열심히 코딩한 당신, 연휴에는 여행을 가봐요"))
print('꼬꼬마 품사 태깅 :',kkma.pos("열심히 코딩한 당신, 연휴에는 여행을 가봐요"))
print('꼬꼬마 명사 추출 :',kkma.nouns("열심히 코딩한 당신, 연휴에는 여행을 가봐요")) 
꼬꼬마 형태소 분석 : ['열심히', '코딩', '하', 'ㄴ', '당신', ',', '연휴', '에', '는', '여행', '을', '가보', '아요']
꼬꼬마 품사 태깅 : [('열심히', 'MAG'), ('코딩', 'NNG'), ('하', 'XSV'), ('ㄴ', 'ETD'), ('당신', 'NP'), (',', 'SP'), ('연휴', 'NNG'), ('에', 'JKM'), ('는', 'JX'), ('여행', 'NNG'), ('을', 'JKO'), ('가보', 'VV'), ('아요', 'EFN')]
꼬꼬마 명사 추출 : ['코딩', '당신', '연휴', '여행']

정제 및 정규화

  • 코퍼스 용도에 맞는 토큰 분류 작업 : 토큰화

  • 토큰화 작업 전, 후에 텍스트 데이터를 용도에 맞게 정제 및 정규화 하는 일 진행

    	- 정제 : 갖고 있는 코퍼스로부터 노이즈 데이터 제거
    • 정규화 : 표현 방법이 다른 단어들을 통합시켜 같은 단어로 만듦
  • 정제 작업 : 토큰화 작업에 방해가 되는 부분들을 배제시키고 토큰화 작업을 수행하기 위해서 토큰화 작업보다 앞서 이루어지거나, 토큰화 작업 이후에도 여전히 남아있는 노이즈들을 제거하기 위해 진행

1. 표기가 다른 단어들 통합

  • uh-huh와 uhhuh
  • US와 USA
    => 같은 의미를 가지므로 하나의 단어로 정규화

2. 대,소문자 통합

  • 대, 소문자를 통합하는 것은 단어의 개수를 줄일 수 있는 또 다른 정규화 방법
  • 장의 맨 앞에서 나오는 단어의 대문자만 소문자로 바꾸고, 다른 단어들은 전부 대문자인 상태로 놔두는 다른 대안도 있음 => 머신 러닝 시퀀스 모델로 더 정확하게 진행

3. 불필요한 단어 제거

  • 노이즈 데이터(noise data)
    자연어가 아니면서 아무 의미도 갖지 않는 글자들(특수 문자 등)을 의미 or 분석하고자 하는 목적에 맞지 않는 불필요 단어들
  • 불필요 단어들을 제거하는 방법
    불용어 제거와 등장 빈도가 적은 단어, 길이가 짧은 단어들을 제거하는 방법
    • 등장 빈도가 적은 단어
      텍스트 데이터에서 너무 적게 등장해서 자연어 처리에 도움이 되지 않는 단어들
    • 길이가 짧은 단어
      길이가 짧은 단어를 삭제하는 것만으로도 어느정도 자연어 처리에서 크게 의미가 없는 단어들을 제거하는 효과
      영어권 언어에서 길이가 짧은 단어들은 대부분 불용어에 해당
      • 길이가 1인 단어를 제거 : 의미를 갖지 못하는 단어인 관사 'a'와 주어로 쓰이는 'I'가 제거
      • 길이가 2인 단어를 제거 : it, at, to, on, in, by 등 제거
import re
text = "I was wondering if anyone out there could enlighten me on this car."
#길이가 1~2인 단어들을 정규 표현식을 이용하여 삭제
shortword = re.compile(r'\W*\b\w{1,2}\b')
print(shortword.sub('', text))
=> was wondering anyone out there could enlighten this car.    

4. 정규 표현식

코퍼스에서 노이즈 데이터의 특징을 잡아낼 수 있다면, 정규 표현식을 통해서 이를 제거할 수 있는 경우가 많음

  • 정규 표현식 => 코퍼스 내에 계속해서 등장하는 글자들을 규칙에 기반하여 한 번에 제거하는 방식으로 사용됨

어간 추출

불용어

정규 표현식

정수 인코딩

패딩

원-핫 인코딩

데이터의 분리

한국어 전처리 패키지

ref

wikidocs-딥러닝을 이용한 자연어 처리 입문

0개의 댓글