디큐 NLP를 파이썬에서 써보기-1

deeq NLP란? / 설치하기 / 기본 사용법

Posted by 윤기현 on February 27, 2021 · 12 mins read

새로운 시작

드디어 바이칼에이아이 기술 블로그를 시작합니다. 마음 맞는 사람들끼리 시작한 걸음이었습니다. 여러 사람들에게 도움이 되는 글쓰기를 지속적으로 해보자고 뜻을 모았습니다. 우리가 의미있는 기술 중심의 회사로 서 가는 과정을 기록하고 그려내는 글쓰기를 하려고 합니다. 회사의 성장에 대한 기록이겠지만, 글을 읽는 사람들에게도 최소한의 도움을 줄 수 있기를 기대합니다.

디큐 NLP는

막상 새로운 기술과 제품을 선보인다는 것은 쉽지 않은 일입니다. 누군가에게 의미 있게 활용될 수 있는 물건을 만든다는 것 또한 인생을 걸고 해볼만한 즐거운 일입니다. 수많은 의미있는 일이 있겠지만, 자연어 처리 엔진을 가진다는 것은 매우 설레는 일입니다.

수많은 거인들의 어깨 위에서 그냥 빼꼼히 한뼘 정도의 높이를 더하는 수준이겠지만, 그래도 들인 노력이 의미있게 쓰일 수 있기를 기대해봅니다.

상용 수준의 NLP를 만드는 과정에서 다뤄볼 만한 많은 주제들은 차츰 꺼내기로 하겠습니다. 일단 오늘은 “디큐엔엘피”라는 새로운 제품을 사용하는 방법을 소개하려고 합니다. “deeq NLP”라고 씁니다.

시작하기

이 글은 인문과학이나 사회과학을 전공하는 대학 학부생 또는 고등학교 학생 수준에서 자연어 처리 엔진을 처음 접하는 사람들이 따라할 수 있는 수준에서 설명을 해볼까 합니다. 최소한 파이썬을 설치해보고 만져봤다면 시작할 수 있습니다.

설치하기

가상환경 만들기

글쓴이가 윈도우즈를 안쓴지 20년이 넘어가서 모두 다 터미널 위주로 설명을 해야 합니다. 윈도우즈에서 리눅스를 설치해서 터미널을 사용하는 방법에 대해서는 44bits.io의 글을 참조하면 좋겠습니다.

늘 그렇듯이 파이썬에서는 새로운 가상환경을 만들어서 작업을 해봐야죠! 늘 그렇듯이 가상환경은 빈 작업 폴더를 만들어서 작업하는 것이 좋습니다.

# mydeeq라는 폴더 만들기
mkdir mydeeq
# 폴더로 이동하기
cd mydeeq
# 새로운 deeqnlpy-test라는 파이썬 가상환경을 만듭니다.
# deeqnlpy-test라는 폴더를 만들고 새로운 파이썬 환경을 꾸밉니다.
python3 -m venv deeqnlpy-test
# 새 가상환경 deeqnlpy-test를 실행합니다.
source deeqnlpy-test/bin/activate

바로 위 명령줄에서 source 대신에 .을 쓰셔도 됩니다. 뒤에 온 파일을 불러들여서 실행하고 그 결과를 현재 상태에 반영하는 방법입니다.

아마도 프롬프트가 바뀌어 있을 것입니다. 쉘 설정에 따라 다양하겠지만 대략 다음과 같습니다.

(deeqnlpy-test) ➜  mydeeq _   # 여기에 보이는 _ 는 프롬프트입니다.

PIP 최신 버전으로 업그레이드하기

늘 그렇듯이 pip는 최신으로 업데이트 해주는 게 좋습니다. pip는 파이썬용 패키지를 설치하는 도구입니다. 아래 명령을 사용하면 됩니다.

pip3 install --upgrade pip

아래와 비슷한 결과물들이 보일 것입니다. 각 환경마다 차이가 있을 수 있습니다.

Collecting pip
  Using cached pip-21.0.1-py3-none-any.whl (1.5 MB)
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 20.2.3
    Uninstalling pip-20.2.3:
      Successfully uninstalled pip-20.2.3
Successfully installed pip-21.0.1

설치하기

마지막 단계입니다.

먼저 명령줄에서 간단하게 deeqnlpy라는 패키지를 설치하는 것으로 모든 것이 준비가 끝납니다.

(deeqnlpy-test) $ pip install deeqnlpy

위 명령을 실행하면, deeqnlpy 뿐 아니라 grpcio, protobuf, six 와 같은 추가적인 패키지들이 자동으로 설치됩니다.

Collecting deeqnlpy
  Downloading deeqnlpy-0.9.2-py3-none-any.whl (24 kB)
Collecting protobuf==3.14.0
  Using cached protobuf-3.14.0-py2.py3-none-any.whl (173 kB)
Collecting grpcio==1.35.0
  Using cached grpcio-1.35.0-cp39-cp39-macosx_10_10_x86_64.whl (3.8 MB)
Collecting six>=1.5.2
  Using cached six-1.15.0-py2.py3-none-any.whl (10 kB)
Installing collected packages: six, protobuf, grpcio, deeqnlpy
Successfully installed deeqnlpy-0.9.2 grpcio-1.35.0 protobuf-3.14.0 six-1.15.0```

뭐하는 녀석이지?

파이썬에서 새로운 녀석을 접할 때에는 help 하는 강략한 도구도 있습니다. 더 쉬운 도구는 . <TAB>을 이용해서 자동완성을 시키는 방법입니다. 이제 그 도구를 이용해서 안쪽을 파보도록 하죠.

다운로드를 마쳤으면 이제 콘솔을 통해서 새로 설치한 deeqnlpy를 사용해 보겠습니다.

먼저 터미널에서 python3 명령어를 칩니다. 다음에 import deeqnlpy 문장으로 패키지를 가져옵니다. help(deeqnlpy)를 입력하면 도움알믈 보실 수 있습니다.

(deeqnlpy-test) $ python3
Python 3.9.1 (default, Dec 10 2020, 11:11:14)
[Clang 12.0.0 (clang-1200.0.32.27)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import deeqnlpy
>>> help(deeqnlpy)

help() 함수를 이용해서 도움말 보기

아래와 같은 메시지를 보실 수 있습니다.

Help on package deeqnlpy:

NAME
    deeqnlpy

DESCRIPTION
    DeeqNLPy
    =====
    Provides
      1. a Korean Part-Of-Speech Tagger as deeq NLP client
      2. Multiple custom dictionaries which is kept in the your deeq NLP server.


    How to use the documentation
    ----------------------------
    Full documentation for deeq NLP is available in
    installable tarball or docker images.
    - see `docs/intro.html` at installable tarball.
    - or `http://localhost:5757/intro.html` after running docker.
    
    The docstring examples assume that `deeqnlpy` has been imported as `dn`::
      >>> import deeqnlpy as dn
    
    Use the built-in ``help`` function to view a class's docstring::
      >>> help(dn.Tagger)

    Classes
    -------
    Tagger
        the deeq NLP POS tagger for Korean
        `from deeqnlpy import Tagger`
    Tagged
        Wrapper for tagged output
        `from deeqnlpy import Tagged`
    CustomDict
        Custom dictionary for Korean.
        `from deeqnlpy import CustomDict`
    Tagger
        the deeq NLP POS tagger for Korean
        `from deeqnlpy import Tagger`
    CustomDict
        Custom dictionary for Korean.
        `from deeqnlpy import CustomDict`
    DeeqTaggerCall
        Wrapper for single tagging function.
        `from deeqnlpy import DeeqTaggerCall`
    DeeqNlp
        Most available library.
        `from deeqnlpy import DeeqNlp`

    Version
    -------
    ```
    import deeqnlpy as dn
    print(dn.version)
    ```
    ## 이하 생략

다른 도움말을 얻어 볼 수도 있습니다.

>>> help(deeqnlpy.Tagger)
>>> help(deeqnlpy.Tagged)
>>> help(deeqnlpy.CustomDict)

<TAB>을 이용해서 구조 파악해보기

프로그래밍 또는 개발은 무릇 공간지각능력이 많이 필요한 분야입니다. 마치 새로운 전자기기나 물건을 볼 때, 요리조리 조심스레 뜯어보게 됩니다. 만저보기도 하고, 두드리기도 하면서 말입니다.

파이썬에서 새로운 라이브러리나 모듈을 요리조리 뜯어볼 때 톡톡 건드릴 때는 ‘.’을 찍고 <TAB>을 쳐주면 됩니다.

<TAB>으로 deeqnlpy의 구조를 한눈에 볼 수 있습니다.

>>> deeqnlpy.<TAB>

탭키를 누르면, 아래와 같은 결과물을 나옵니다.

>>> deeqnlpy.<TAB>
deeqnlpy.CustomDict(                     deeqnlpy.Tagged(                         deeqnlpy.os
deeqnlpy.CustomDictionaryServiceClient(  deeqnlpy.Tagger(                         deeqnlpy.sys
deeqnlpy.DeeqLanguageServiceClient(      deeqnlpy.deeq_nlp_version                deeqnlpy.version

여기에서 2가지 서로 다른 모습을 볼 수 있습니다. 먼저 deeqnlpy는 불러들인(import) 패키지의 이름입니다. 이중에서 ‘(‘, 즉 여는 괄호가 있는 것들은 클래스나 함수입니다. 여는 괄호가 없는 것들은 상수이거나 다른 서브 패키지 입니다.

여기서 deeq_nlp_version 을 입력해보면, 1.4.2를 출력하고 끝납니다.

>>> deeqnlpy.deeq_nlp_version
'1.4.2'

눈치채셨을지 모르지만, deeqnlpy.versiondeeqnlpy.deeq_nlp_version은 서로 다릅니다. deeqnlpy.version은 이 파이썬 패키지의 버전입니다. deeq_nlp_version은 이 파이썬 패키지와 연결되어 있는 디큐 NLP의 버전입니다. 이 파이썬 패키지는 디큐 NLP를 사용하는 클라이언트 라이브러리입니다. 이 라이브러리는 반드시 서버에 연결해서 응답을 얻어오게 됩니다. 이 서버는 nlp.deeq.ai 라는 주소에 늘 존재하고 있습니다. 누구나 쓸 수 있습니다. 대신 직접 윈도우즈 PC에 설치할 수도 있습니다. 이것에 대해서는 다시 설명하겠습니다.

다른 도움말을 볼까요?

>>> deeqnlpy.Tagger.<TAB>

이번에는 또 다른 새로운 함수들이 나오는데, Tagger 클래스의 함수들이 잔뜩 나타납니다.

>>> deeqnlpy.Tagger.
deeqnlpy.Tagger.custom_dict(  deeqnlpy.Tagger.pos(
deeqnlpy.Tagger.domain        deeqnlpy.Tagger.post
deeqnlpy.Tagger.host          deeqnlpy.Tagger.set_domain(
deeqnlpy.Tagger.morphs(       deeqnlpy.Tagger.tag(
deeqnlpy.Tagger.mro(          deeqnlpy.Tagger.tags(
deeqnlpy.Tagger.nouns(        deeqnlpy.Tagger.verbs(

이중에서 tags 함수에 대한 도움말을 얻고 싶으시다면, help() 명령을 이용해서 결과를 얻을 수 있습니다.

>>> help(deeqnlpy.Tagger.tags)
Help on function tags in module deeqnlpy._tagger:

tags(self, phrase: [<class 'str'>]) -> deeqnlpy._tagger.Tagged
    tag string array.
    :param phrase: array of string
    :return: Tagged result instance

쓰임새 알아보기

deeqnlpy는 한국어 형태소를 분석해줍니다. 내부적으로는 디큐 NLP의 서버에 접속하여 형태소 분석을 요청하고 그 결과를 받아오는 방식입니다.

실제로 분석해보기

Tagger 클래스가 그런 역할을 수행합니다. 여러가지 메소드들이 있는데, 그 쓰임새가 조금씩 다릅니다.

  • tag: 문장 또는 여러 문장을 분석한 결과를 줍니다.
  • tags: 여러 문장, 즉 문장의 배열을 분석하고 결과를 줍니다. 이 함수를 쓰는 것을 권장합니다.
  • pos: 형태소 분석 결과를 꺼내옵니다. 여러 문장일 때, 문장 구분이 없는 조금 곤란한 결과를 가져옵니다.
  • morphs: 형태소만 꺼내옵니다.
  • nouns: 명사류만 꺼내옵니다. 고유명사, 일반명사, 대명사까지 꺼내옵니다.
  • verbs: 동사만 꺼내옵니다.

자, 그럼 실제로 실행을 해볼까요?

from deeqnlpy import Tagger
t = Tagger()
pos_tuples = t.pos("그 가수는 밍기뉸데.")
print(pos_tuples)

실행을 해보면 다음과 같은 결과물을 얻을 수 있습니다.

[('그', 'MMD'), ('가수', 'NNG'), ('는', 'JX'), ('밍기뉴', 'NNP'), ('이', 'VCP'), ('ㄴ데', 'EF'), ('.', 'SF')]

여기에 사용한 어절은 모두 3개입니다.

['그', '가수는', '밍기뉸데.']

실제로 분석해보기(II)

pos() 함수의 결과물은 그런 구분없이 수평적으로 형태 분석한 결과물을 보여주고 있습니다.

이것을 어절 단위로 묶어서 결과를 가져올 수도 있습니다.

여기에서 help(t.pos)를 이용해서 도움말을 볼까요?

Help on method pos in module deeqnlpy._tagger:

pos(phrase: str, flatten: bool = True, join: bool  = False, detail: bool = False) -> [] method of deeqnlpy._tagger.Tagger instance
    POS tagger.
    :param phrase  : string to analyse
    :param flatten : If False, returns original morphs.
    :param join    : If True, returns joined sets of morph and tag.
    :param detail  : if True, returns every things of morph result

pos() 함수는 크게 4가지 파라미터를 받을 수 있습니다. flatten은 어절단위로 배열을 풀어서 1차원으로 만듭니다. join은 출력형식을 “문자열/태그” 바꿔줍니다. detail 파라미터는 숨겨진 정보들도 모두 보여줍니다. 가본값은 flattenTrue이고, joinFalse, detailFalse입니다. 먼저 flatten 값을 False로 넘겨보도록 하죠. joinTrue를 넘겨보겠습니다.

from deeqnlpy import Tagger
t = Tagger()
# 이번에는 문장의 끝에 [요]를 덧붙였습니다.
pos_tuples = t.pos("그 가수는 밍기뉸데요.", flatten=False, join=True)
print(*pos_tuples, sep="\n") 

결과가 조금 바뀌었습니다.

>>> print(*aa, sep="\n")
['그/MMD']
['가수/NNG', '는/JX']
['밍기뉴/NNP', '이/VCP', 'ㄴ데/EC', '요/JX', './SF']

flatten값으로 False를 주자 어절 단위로 쪼개주고, 모두 3개의 배열로 나뉘어진 결과물을 얻을 수 있습니다. “밍기뉸데요.”의 경계를 확인하기 쉽지 않았을 텐데, 모두 5개로 쪼개진 것을 알 수 있습니다.

NNP: 밍기뉴는 고유명사입니다. 밍기뉴라는 노래하는 팀 이름이니까요. 근데, 어떻게 알았을까요?

VCP: 는 생략된 것인데, 복원을 해주었습니다. 이런 형태를 지정사라고 합니다. 서술격조사라고도 했습니다. 쉽게 생각하면 명사 다음에 바로 어미가 올 수 없으니까, 어미가 올 수 있도록 어간화 해주는 것으로 이해하면 좋겠습니다. 근데 모음으로 끝나는 체언이나 부사 뒤에서 가 생략될 수 있습니다. 구어에서는 흔하게 일어나는 일입니다.

EF: 종결어미입니다. ㄴ데로 문장이 끝나고 있습니다.

JX: 보조사입니다. 종결어미로 ㄴ데로도 충분히 의미를 전달할 수 있는데, -요가 붙어서 존대의 뜻을 나타냅니다.

내용이 길어서 다음편에 이어서 계속됩니다.