ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • KoNLP(자연어처리)
    Python 2020. 7. 22. 17:25

    자연어 처리 시작하기

    한글 자연어 처리 기초 - KoNLPy 및 필요 모듈의 설치

    • 콘다 콘솔에서 설치

    • KoNLPy : pip install konlpy

    • JPype1 : conda install -c conda-forge jpype1 - console에서 실행

    • JPype1는 KoNLPy 0.5.x 버전 설치시 자동 설치됨(0.4.x 버전에서 필요)

      • 이후 Jupyter Notebook 재실행 필요

    • JDK 설치 : Java JDK로 검색해서 OS에 맞춰 설치

    • pip install nltk

    • pip install wordcloud

    # 학습을 위한 패키지 설치
    # All Packages Download
    import nltk
    nltk.download()
    showing info https://raw.githubusercontent.com/nltk/nltk_data/gh-pages/index.xml
    
    
    
    
    
    True
    #jpype 설치 확인 konlpy 오류시 확인 
    #import jpype
    #pype.startJVM(jpype.getDefaultJVMPath())

    한글 자연어 처리 기초

    # 꼬꼬마 모듈
    from konlpy.tag import Kkma
    kkma = Kkma()
    # 문장 분석 : 마침표가 없어도 구분
    kkma.sentences('한국어 분석을 시작합니다 재미있어요~~')
    ['한국어 분석을 시작합니다', '재미있어요~~']
    # 명사 분석
    kkma.nouns('한국어 분석을 시작합니다 재미있어요~~')
    ['한국어', '분석']
    # 형태소 분석 : 형태소(최소한의 의미 단어)
    kkma.pos('한국어 분석을 시작합니다 재미있어요~~')
    [('한국어', 'NNG'),
     ('분석', 'NNG'),
     ('을', 'JKO'),
     ('시작하', 'VV'),
     ('ㅂ니다', 'EFN'),
     ('재미있', 'VA'),
     ('어요', 'EFN'),
     ('~~', 'SW')]
    txt = '한국어 분석을 시작합니다 재미있어요~~'
    # 한나눔 사용
    from konlpy.tag import Hannanum
    hannanum = Hannanum()
    # 명사 분석
    hannanum.nouns(txt)
    ['한국어', '분석', '시작']
    # 형태소 분석(설명 안나옴)
    hannanum.morphs(txt)
    ['한국어', '분석', '을', '시작', '하', 'ㅂ니다', '재미있', '어요', '~~']
    # 형태소 분석
    hannanum.pos(txt)
    [('한국어', 'N'),
     ('분석', 'N'),
     ('을', 'J'),
     ('시작', 'N'),
     ('하', 'X'),
     ('ㅂ니다', 'E'),
     ('재미있', 'P'),
     ('어요', 'E'),
     ('~~', 'S')]
    #from konlpy.tag import Twitter
    from konlpy.tag import Okt
    #t = Twitter()
    t = Okt()
    # 명사 분석
    t.nouns(txt)
    ['한국어', '분석', '시작']
    t.morphs(txt)
    ['한국어', '분석', '을', '시작', '합니다', '재미있어요', '~~']
    t.pos(txt)
    [('한국어', 'Noun'),
     ('분석', 'Noun'),
     ('을', 'Josa'),
     ('시작', 'Noun'),
     ('합니다', 'Verb'),
     ('재미있어요', 'Adjective'),
     ('~~', 'Punctuation')]

    워드 클라우드

    from wordcloud import WordCloud, STOPWORDS
    
    import numpy as np
    from PIL import Image
    # 이상한 나라의 엘리스
    text = open('DataScience_Ing/data/09. alice.txt').read()
    alice_mask = np.array(Image.open('DataScience_Ing/data/09. alice_mask.png'))
    
    # 카운트 하지 않게 하기 - said란 단어가 많이 나오나??
    stopwords = set(STOPWORDS)
    stopwords.add('said')
    import matplotlib.pyplot as plt
    import platform
    
    #폰트 설정
    path = "c:/Windows/Fonts/malgun.ttf"
    from matplotlib import font_manager, rc
    if platform.system() == 'Darwin':
        rc('font', family='AppleGothic')
    elif platform.system() == 'Windows':
        font_name = font_manager.FontProperties(fname=path).get_name()
        rc('font', family=font_name)
    else:
        print('Unknown system... sorry~~~~') 
    
    %matplotlib inline
    plt.figure(figsize=(8,8))
    plt.imshow(alice_mask, cmap=plt.cm.gray, interpolation='bilinear')
    plt.axis('off')
    plt.show()

    # Alice 1등
    wc = WordCloud(background_color='white', max_words=2000, mask=alice_mask,
                  stopwords=stopwords)
    wc = wc.generate(text)
    #wc.words_
    # 그림에 겹처 보이게 
    # interpolation='bilinear'(선형 보간법) : https://blog.naver.com/aorigin/220947541918
    plt.figure(figsize=(12,12))
    plt.imshow(wc, interpolation='bilinear')
    plt.axis('off')
    plt.show()

    앨리스 그림처럼 word로 채워짐

    # 스타워즈 A New Hope
    text = open('DataScience_Ing/data/09. a_new_hope.txt').read()
    
    text = text.replace('HAN', 'Han')
    text = text.replace("LUKE'S", 'Luke')
    
    mask = np.array(Image.open('DataScience_Ing/data/09. stormtrooper_mask.png'))
    stopwords = set(STOPWORDS)
    stopwords.add("int")
    stopwords.add("ext")
    wc = WordCloud(max_words=1000, mask=mask, stopwords=stopwords,
                  margin=10, random_state=1).generate(text)
    default_colors = wc.to_array()
    import random
    def grey_color_func(word, font_size, position, orientation,
                       random_state=None, **kwargs):
        return 'hsl(0, 0%%, %d%%)' % random.randint(60, 100)
    plt.figure(figsize=(12,12))
    plt.imshow(wc.recolor(color_func=grey_color_func, random_state=3),
              interpolation='bilinear')
    plt.axis('off')
    plt.show()

    육아휴직관련 법안 대한민국 국회 제 1809890호 의한

    from konlpy.corpus import kobill
    files_ko = kobill.fileids()
    doc_ko = kobill.open('1809890.txt').read()
    doc_ko
    '지방공무원법 일부개정법률안\n\n(정의화의원 대표발의 )\n\n 의 안\n 번 호\n\n9890\n\n발의연월일 : 2010.  11.  12.  \n\n발  의  자 : 정의화․이명수․김을동 \n\n이사철․여상규․안규백\n\n황영철․박영아․김정훈\n\n김학송 의원(10인)\n\n제안이유 및 주요내용\n\n  초등학교 저학년의 경우에도 부모의 따뜻한 사랑과 보살핌이 필요\n\n한 나이이나, 현재 공무원이 자녀를 양육하기 위하여 육아휴직을 할 \n\n수 있는 자녀의 나이는 만 6세 이하로 되어 있어 초등학교 저학년인 \n\n자녀를 돌보기 위해서는 해당 부모님은 일자리를 그만 두어야 하고 \n\n이는 곧 출산의욕을 저하시키는 문제로 이어질 수 있을 것임.\n\n  따라서 육아휴직이 가능한 자녀의 연령을 만 8세 이하로 개정하려\n\n는 것임(안 제63조제2항제4호).\n\n- 1 -\n\n\x0c법률  제        호\n\n지방공무원법 일부개정법률안\n\n지방공무원법 일부를 다음과 같이 개정한다.\n\n제63조제2항제4호 중 “만 6세 이하의 초등학교 취학 전 자녀를”을 “만 \n\n8세 이하(취학 중인 경우에는 초등학교 2학년 이하를 말한다)의 자녀를”\n\n로 한다.\n\n부      칙\n\n이 법은 공포한 날부터 시행한다.\n\n- 3 -\n\n\x0c신 ·구조문대비표\n\n현      행\n\n개   정   안\n\n제63조(휴직) ① (생  략)\n\n제63조(휴직) ① (현행과 같음)\n\n  ② 공무원이 다음 각 호의 어\n\n  ② -------------------------\n\n느 하나에 해당하는 사유로 휴\n\n----------------------------\n\n직을 원하면 임용권자는 휴직\n\n----------------------------\n\n을 명할 수 있다. 다만, 제4호\n\n-------------.---------------\n\n의 경우에는 대통령령으로 정\n\n----------------------------\n\n하는 특별한 사정이 없으면 휴\n\n----------------------------\n\n직을 명하여야 한다.\n\n--------------.\n\n  1. ∼ 3. (생  략)\n\n  1. ∼ 3. (현행과 같음)\n\n  4. 만 6세 이하의 초등학교 취\n\n  4. 만 8세 이하(취학 중인 경우\n\n학 전 자녀를 양육하기 위하\n\n에는 초등학교 2학년 이하를 \n\n여 필요하거나 여자공무원이 \n\n말한다)의 자녀를 ----------\n\n임신 또는 출산하게 되었을 \n\n---------------------------\n\n때\n\n---------------------------\n\n  5.⋅6. (생  략)\n\n  ③⋅④ (생  략)\n\n--------\n\n  5.⋅6. (현행과 같음)\n\n  ③⋅④ (현행과 같음)\n\n- 5 -\n\n\x0c지방공무원법 일부개정법률안 등 비용추계서 미첨부사유서\n1.  재정수반요인\n\n개정안에서 「국가공무원법」  제71조제2항제4호 중 국가공무원의 육아\n\n휴직 가능 자녀의 연령을 만6세 이하에서 만8세 이하로 하고, 「지방공\n\n무원법」 제63조제2항제4호 중 지방공무원의 육아휴직 가능 자녀의 연\n\n령을 만6세 이하에서 만8세 이하로 하고, 「교육공무원법」 제44조제1항\n\n제7조 중 교육공무원의 육아휴직 가능 자녀의 연령을 만6세 이하에서 \n\n만8세 이하로 하고, 「남녀고용평등과 일․가정 양립지원에 관한 법률」 \n\n제19조제1항 중 근로자 육아휴직 가능 자녀연령을 만6세 이하에서 만\n\n8세 이하로 조정함에 따라 추가 재정소요가 예상됨.\n\n2.  미첨부  근거  규정\n「의안의 비용추계에 관한 규칙」 제3조제1항 단서 중 제1호(예상되는 비용이 연평균  10억원 미만\n이거나  한시적인  경비로서  총  30억원  미만인  경우)에  해당함.\n\n3.  미첨부  사유\n\n개정안에서 국가․지방․교육공무원 및 근로자가 육아휴직을 신청할 \n\n수 있는 자녀의 연령을 만6세 이하에서 만8세 이하로 상향조정함에 \n\n따라 추가 재정소요가 예상된다. 동 법률 개정안이 2011년에 시행된다\n\n고 가정한 경우, 2010년 현재 자녀의 연령이 7세이고 육아휴직을 신청\n\n- 7 -\n\n\x0c- 8 -\n\n하지 않은 국가․지방․교육공무원 및 근로자가 대상이 된다.\n\n대상연령의 확대됨에 따라 육아휴직신청자의 수가 어느 정도 늘어날 \n\n것으로 예상된다. 이 경우 발생하는 비용은 현행법에 따르면 월50만원\n\n이나 현재 관련법령 개정이 추진되고 있으며, 이에 따라 2011년에는 \n\n육아휴직자가 지급받는 월급여액에 비례하여 육아휴직급여가 지급되\n\n기 때문에 법령개정을 가정하고 추계한다. 이러한 경우 육아휴직급여\n\n액은 육아휴직자가 지급받는 월급여의 40%에 해당한다. 육아휴직자가 \n\n발생한 경우 발생하는 비용은 대체인력 고용인건비와 육아휴직자가 \n\n받는 월급여액의 40%이다. 이와 대비하여 육아휴직자에게 지급하던 \n\n임금은 더 이상 발생하지 않는다. 따라서 실제 발생하는 순비용은 육\n\n아휴직자에게 지급하던 월 급여액과 연령 확대에 따라 발생하는 비용\n\n인 육아휴직자가 받던 월급여액의 40%와 대체인력 고용인건비의 차\n\n액인데 이 값이 0보다 크면 추가 재정소요는 발생하지 않는다고 볼 \n\n수 있다.\n\n추가비용 발생여부를 정확하게 알아보기 위하여 비용에 대한 수리모\n\n델을 만들고 이에 따라 비용발생 여부를 알아보기로 하자. 모델에 사\n\n용되는 변수를 다음과 같이 정의한다.\n\n발생비용 : N×p×X + N×육아휴직급여액 - N×P\n\nN\n\nP\n\n: 육아휴직대상자의 수\n\n: 육아휴직대상자의 월급여액\n\n\x0cp\n\nX\n\n: 육아휴직자가 발생한 경우 대체 고용할 확률\n\n: 대체 고용한 인력에게 지급하는 월급여액\n\n위의 수식에서 육아휴직급여액은 육아휴직자 월급여액의 40%까지 지\n\n급할 예정이므로 육아휴직급여액은 P×40%이다. 육아휴직자가 발생한 \n\n경우 대체 고용할 확률 p는 고용노동부의 육아휴직 관련 자료를 이용\n\n한다. 고용노동부에 따르면 2011년의 경우 육아휴직급여 대상자는 \n\n40,923명이며, 육아휴직에 따른 대체인력 고용 예상인원은 2,836명이\n\n다. 2007년부터 2011년까지의 현황을 정리하면 다음의 [표]와 같다.\n\n[표]  육아휴직급여  수급자의  수  및  대체인력  고용  현황:  2007~2011년\n\n(단위:  명,  % )\n\n2007\n\n2008\n\n2009\n\n2010\n\n2011\n\n평균\n\n육아휴직급여  수급자(A)\n\n21,185\n\n29,145\n\n35,400\n\n41,291\n\n43,899\n\n34,184\n\n대체인력  채용(B)\n\n796\n\n1,658\n\n1,957\n\n2,396\n\n2,836\n\n1,929\n\n비  율(B/A)\n\n3.8\n\n5.7\n\n5.5\n\n5.8\n\n6.5\n\n5.6\n\n자료: 고용노동부  자료를  바탕으로  국회예산정책처  작성\n\n위의 [표]의 자료에 따라 육아휴직자가 발생한 경우 대체 고용할 확률 \n\np의 값은 5.6%라고 가정한다. 그리고 비용이 발생한다고 가정하여 위\n\n의 수식을 다시 작성하면 다음의 수식과 같다.\n\nN×p×X + N×육아휴직급여액 - N×P > 0\n\n(1)\n\n- 9 -\n\n\x0c- 10 -\n\nN×5.6%×X + N×P×40% - N×P > 0\n\n0.056×X > 0.6P\n\nX > 10.7×P\n\n(2)\n\n(3)\n\n(5)\n\n위의 수식에 육아휴직자가 받는 월 급여액을 대입하여 대체고용인력\n\n자에게 지급하는 월 급여액을 추정하여 보자. 육아휴직자가 월 200만\n\n원을 받는다고 가정하면, 대체고용인력자에게 육아휴직자가 받는 월 \n\n급여액의 10.7배에 달하는 월 21,428,571원 이상을 지급해야 추가 비용\n\n이 발생한다. 대체고용인력자에게 육아휴직자보다 더 많은 월급여액을 \n\n주지는 않을 것이고 그리고 10여배 이상 월급을 주지도 않을 것이기 \n\n때문에 추가 비용이 발생한다고 보기 힘들다. 위의 수식에서 대체인력 \n\n고용확률 p를 20%로 가정하더라도(이 경우 X > 3×P) 200만원 받는 \n\n육아휴직자 대체인력에게 월 600만원 이상을 지급해야 추가 비용이 \n\n발생한다.\n\n행정안전부의 통계자료(행정안전부 통계연감)에서는 지방공무원의 육\n\n아휴직 현황자료를 보여주고 있다. 여기서 육아휴직자가 발생한 경우 \n\n대체인력을 주로 임용대기자 또는 일용직을 활용하는 것으로 보인다. \n\n따라서 공무원의 경우에도 [표]에서 보여주는 일반기업체의 대체인력 \n\n고용확률과 차이는 크지 않을 것으로 보인다.\n\n이상의 논의를 바탕으로 육아휴직기간을 만6에서 만8세로 연장하더라\n\n도 법률 개정에 따른 추가 비용은 발생하지 않을 것으로 예상된다.\n\n\x0c4.  작성자\n\n국회예산정책처 법안비용추계1팀\n\n팀      장   정 문 종\n\n예산분석관   김 태 완\n\n(02-788-4649, tanzania@assembly.go.kr)\n\n- 11 -\n\n\x0c'
    #from konlpy.tag import Twitter
    from konlpy.tag import Okt
    #t = Twitter()
    t = Okt()
    tokens_ko = t.nouns(doc_ko)
    #tokens_ko
    # 빈도수 처리
    ko = nltk.Text(tokens_ko, name='대한민국 국회 의안 제 1809890호')
    print(len(ko.tokens)) # returns number of tokens (document length)
    print(len(set(ko.tokens))) # returns number of unique tokens
    # 빈도수로 정리
    ko.vocab() # returns frequency distribution
    735
    250
    
    
    
    
    
    FreqDist({'육아휴직': 38, '발생': 19, '만': 18, '이하': 18, '비용': 17, '액': 17, '경우': 16, '세': 16, '자녀': 14, '고용': 14, ...})
    plt.figure(figsize=(12, 6))
    ko.plot(50)
    plt.show()

    # 제외 문자 처리
    stop_words = ['.', '(', ')', ',', "'", '%', '-', 'X', ').', '×','의','자','에','안','번',
                          '호','을','이','다','만','로','가','를']
    ko = [each_word for each_word in ko if each_word not in stop_words]
    #ko
    ko = nltk.Text(ko, name='대한민국 국회 의안 제 1809890호')
    
    plt.figure(figsize=(12, 6))
    ko.plot(50) # Plot sorted frequency of top 50 tokens
    plt.show()

    ko.count('초등학교')
    6
    plt.figure(figsize=(12, 6))
    ko.dispersion_plot(['육아휴직', '초등학교', '공무원'])

    # 단어 주변부 확인
    ko.concordance('초등학교')
    Displaying 6 of 6 matches:
     안규백 황영철 박영아 김정훈 김학송 의원 인 제안 이유 및 내용 초등학교 저학년 경우 부모 사랑 필요 나이 현재 공무원 자녀 양육 위 육아
     나이 현재 공무원 자녀 양육 위 육아휴직 수 자녀 나이 세 이하 초등학교 저학년 자녀 위 해당 부모님 일자리 곧 출산 의욕 저하 문제 수 
    일부 개정 법률 지방공무원법 일부 다음 개정 제 항제 중 세 이하 초등학교 취학 전 자녀 세 이하 취학 중인 경우 초등학교 학년 이하 말 자
    항제 중 세 이하 초등학교 취학 전 자녀 세 이하 취학 중인 경우 초등학교 학년 이하 말 자녀 부 칙 법 공포 날 시행 신 구조 문대비 표 
     수 다만 제 경우 대통령령 정 사정 직 명 생 략 현행 세 이하 초등학교 취 세 이하 취학 중인 경우 학 전 자녀 양육 위 초등학교 학년 
     이하 초등학교 취 세 이하 취학 중인 경우 학 전 자녀 양육 위 초등학교 학년 이하 여 여자 공무원 말 자녀 임신 출산 때 생 략 생 략 
    # 연이어 사용된 단어 확인
    ko.collocations()
    초등학교 저학년; 근로자 육아휴직; 육아휴직 대상자; 공무원 육아휴직
    data = ko.vocab().most_common(150)
    
    # for window : font_path='c:/Windows/Fonts/malgun.ttf'
    # for mac : font_path='/Library/Fonts/AppleGothic.ttf'
    wordcloud = WordCloud(font_path='c:/Windows/Fonts/malgun.ttf',
                         relative_scaling = 0.2,
                         background_color = 'white',
                         ).generate_from_frequencies(dict(data))
    plt.figure(figsize=(12, 8))
    plt.imshow(wordcloud)
    plt.axis('off')
    plt.show()

    Naive Bayes Classifier의 이해 - 영문

    • 지도학습의 한 종류 (지도학습은 항상 답이 정해져있음)

    • 두 사건을 독립이라고 사정하고 각각의 조건부 확률을 가지고 분류

    from nltk.tokenize import word_tokenize
    import nltk
    # pos 긍정, neg 부정의 태그가 있는 지도학습용 Data
    train = [('i like you', 'pos'), 
             ('i hate you', 'neg'), 
             ('you like me', 'neg'),
             ('i like her', 'pos')]
    # 말뭉치
    all_words = set(word.lower() for sentence in train 
                                    for word in word_tokenize(sentence[0]))
    all_words
    {'hate', 'her', 'i', 'like', 'me', 'you'}
    # 벡터화 한다
    # 말뭉치를 기준으로 train 정보 존재 확인
    t = [({word: (word in word_tokenize(x[0])) for word in all_words}, x[1]) for x in train]
    t
    [({'you': True,
       'like': True,
       'i': True,
       'me': False,
       'her': False,
       'hate': False},
      'pos'),
     ({'you': True,
       'like': False,
       'i': True,
       'me': False,
       'her': False,
       'hate': True},
      'neg'),
     ({'you': True,
       'like': True,
       'i': False,
       'me': True,
       'her': False,
       'hate': False},
      'neg'),
     ({'you': False,
       'like': True,
       'i': True,
       'me': False,
       'her': True,
       'hate': False},
      'pos')]
    classifier = nltk.NaiveBayesClassifier.train(t)
    classifier.show_most_informative_features()
    # hate = False   pos : neg  =  1.7 : 1.0 => hate가 없을 때 
    # 긍정과 부정의 비율 1.7:1 이라는 의미
    Most Informative Features
                        hate = False             pos : neg    =      1.7 : 1.0
                         her = False             neg : pos    =      1.7 : 1.0
                           i = True              pos : neg    =      1.7 : 1.0
                        like = True              pos : neg    =      1.7 : 1.0
                          me = False             pos : neg    =      1.7 : 1.0
                         you = True              neg : pos    =      1.7 : 1.0
    test_sentence = 'i like MeRui'
    test_sent_features = {word.lower(): 
                            (word in word_tokenize(test_sentence.lower()))
                               for word in all_words}
    test_sent_features
    {'you': False,
     'like': True,
     'i': True,
     'me': False,
     'her': False,
     'hate': False}
    classifier.classify(test_sent_features)
    'pos'

    Naive Bayes Classifier의 이해 - 한글

    #from konlpy.tag import Twitter
    from konlpy.tag import Okt
    #pos_tagger = Twitter()
    pos_tagger = Okt()
    train = [('메리가 좋아', 'pos'), 
             ('고양이도 좋아', 'pos'),
             ('난 수업이 지루해', 'neg'),
             ('메리는 이쁜 고양이야', 'pos'),
             ('난 마치고 메리랑 놀거야', 'pos')]
    # 말뭉치 만들기
    all_words = set(word.lower() for sentence in train
                   for word in word_tokenize(sentence[0]))
    all_words # 메리가 와 메리는 메리랑 별도 구분
    {'고양이도',
     '고양이야',
     '난',
     '놀거야',
     '마치고',
     '메리가',
     '메리는',
     '메리랑',
     '수업이',
     '이쁜',
     '좋아',
     '지루해'}
    t = [({word: (word in word_tokenize(x[0])) for word in all_words}, x[1]) for x in train]
    t
    [({'메리가': True,
       '좋아': True,
       '이쁜': False,
       '난': False,
       '마치고': False,
       '수업이': False,
       '고양이도': False,
       '지루해': False,
       '메리랑': False,
       '고양이야': False,
       '놀거야': False,
       '메리는': False},
      'pos'),
     ({'메리가': False,
       '좋아': True,
       '이쁜': False,
       '난': False,
       '마치고': False,
       '수업이': False,
       '고양이도': True,
       '지루해': False,
       '메리랑': False,
       '고양이야': False,
       '놀거야': False,
       '메리는': False},
      'pos'),
     ({'메리가': False,
       '좋아': False,
       '이쁜': False,
       '난': True,
       '마치고': False,
       '수업이': True,
       '고양이도': False,
       '지루해': True,
       '메리랑': False,
       '고양이야': False,
       '놀거야': False,
       '메리는': False},
      'neg'),
     ({'메리가': False,
       '좋아': False,
       '이쁜': True,
       '난': False,
       '마치고': False,
       '수업이': False,
       '고양이도': False,
       '지루해': False,
       '메리랑': False,
       '고양이야': True,
       '놀거야': False,
       '메리는': True},
      'pos'),
     ({'메리가': False,
       '좋아': False,
       '이쁜': False,
       '난': True,
       '마치고': True,
       '수업이': False,
       '고양이도': False,
       '지루해': False,
       '메리랑': True,
       '고양이야': False,
       '놀거야': True,
       '메리는': False},
      'pos')]
    classifier = nltk.NaiveBayesClassifier.train(t) # 공부시킴
    classifier.show_most_informative_features()
    Most Informative Features
                           난 = True              neg : pos    =      2.5 : 1.0
                          좋아 = False             neg : pos    =      1.5 : 1.0
                        고양이도 = False             neg : pos    =      1.1 : 1.0
                        고양이야 = False             neg : pos    =      1.1 : 1.0
                         놀거야 = False             neg : pos    =      1.1 : 1.0
                         마치고 = False             neg : pos    =      1.1 : 1.0
                         메리가 = False             neg : pos    =      1.1 : 1.0
                         메리는 = False             neg : pos    =      1.1 : 1.0
                         메리랑 = False             neg : pos    =      1.1 : 1.0
                          이쁜 = False             neg : pos    =      1.1 : 1.0
    test_sentence = '난 수업이 마치면 메리랑 놀거야'
    test_sent_features = {word: 
                            (word in word_tokenize(test_sentence))
                                for word in all_words}
    test_sent_features
    {'메리가': False,
     '좋아': False,
     '이쁜': False,
     '난': True,
     '마치고': False,
     '수업이': True,
     '고양이도': False,
     '지루해': False,
     '메리랑': True,
     '고양이야': False,
     '놀거야': True,
     '메리는': False}
    # neg => 한글을 다룰 때는 형태소 분석이 필요해짐
    classifier.classify(test_sent_features)
    'neg'
    # https://datascienceschool.net/view-notebook/70ce46db4ced4a999c6ec349df0f4eb0/
    # pos() 품사 부착
    def tokenize(doc):
        return ['/'.join(t) for t in pos_tagger.pos(doc, norm=True, stem=True)]
    # 태그부착
    train_docs = [(tokenize(row[0]), row[1]) for row in train]
    train_docs
    [(['메리/Noun', '가/Josa', '좋다/Adjective'], 'pos'),
     (['고양이/Noun', '도/Josa', '좋다/Adjective'], 'pos'),
     (['난/Noun', '수업/Noun', '이/Josa', '지루하다/Adjective'], 'neg'),
     (['메리/Noun', '는/Josa', '이쁘다/Adjective', '고양이/Noun', '야/Josa'], 'pos'),
     (['난/Noun', '마치/Noun', '고/Josa', '메리/Noun', '랑/Josa', '놀다/Verb'], 'pos')]
    # 말뭉치 재작업
    tokens = [t for d in train_docs for t in d[0]]
    tokens
    ['메리/Noun',
     '가/Josa',
     '좋다/Adjective',
     '고양이/Noun',
     '도/Josa',
     '좋다/Adjective',
     '난/Noun',
     '수업/Noun',
     '이/Josa',
     '지루하다/Adjective',
     '메리/Noun',
     '는/Josa',
     '이쁘다/Adjective',
     '고양이/Noun',
     '야/Josa',
     '난/Noun',
     '마치/Noun',
     '고/Josa',
     '메리/Noun',
     '랑/Josa',
     '놀다/Verb']
    # 말뭉치에 단어 존재 여부 확인 함수
    def term_exists(doc):
        return {word: (word in set(doc)) for word in tokens}
    # 훈련데이터에 적용
    train_xy = [(term_exists(d), c) for d,c in train_docs]
    train_xy
    [({'메리/Noun': True,
       '가/Josa': True,
       '좋다/Adjective': True,
       '고양이/Noun': False,
       '도/Josa': False,
       '난/Noun': False,
       '수업/Noun': False,
       '이/Josa': False,
       '지루하다/Adjective': False,
       '는/Josa': False,
       '이쁘다/Adjective': False,
       '야/Josa': False,
       '마치/Noun': False,
       '고/Josa': False,
       '랑/Josa': False,
       '놀다/Verb': False},
      'pos'),
     ({'메리/Noun': False,
       '가/Josa': False,
       '좋다/Adjective': True,
       '고양이/Noun': True,
       '도/Josa': True,
       '난/Noun': False,
       '수업/Noun': False,
       '이/Josa': False,
       '지루하다/Adjective': False,
       '는/Josa': False,
       '이쁘다/Adjective': False,
       '야/Josa': False,
       '마치/Noun': False,
       '고/Josa': False,
       '랑/Josa': False,
       '놀다/Verb': False},
      'pos'),
     ({'메리/Noun': False,
       '가/Josa': False,
       '좋다/Adjective': False,
       '고양이/Noun': False,
       '도/Josa': False,
       '난/Noun': True,
       '수업/Noun': True,
       '이/Josa': True,
       '지루하다/Adjective': True,
       '는/Josa': False,
       '이쁘다/Adjective': False,
       '야/Josa': False,
       '마치/Noun': False,
       '고/Josa': False,
       '랑/Josa': False,
       '놀다/Verb': False},
      'neg'),
     ({'메리/Noun': True,
       '가/Josa': False,
       '좋다/Adjective': False,
       '고양이/Noun': True,
       '도/Josa': False,
       '난/Noun': False,
       '수업/Noun': False,
       '이/Josa': False,
       '지루하다/Adjective': False,
       '는/Josa': True,
       '이쁘다/Adjective': True,
       '야/Josa': True,
       '마치/Noun': False,
       '고/Josa': False,
       '랑/Josa': False,
       '놀다/Verb': False},
      'pos'),
     ({'메리/Noun': True,
       '가/Josa': False,
       '좋다/Adjective': False,
       '고양이/Noun': False,
       '도/Josa': False,
       '난/Noun': True,
       '수업/Noun': False,
       '이/Josa': False,
       '지루하다/Adjective': False,
       '는/Josa': False,
       '이쁘다/Adjective': False,
       '야/Josa': False,
       '마치/Noun': True,
       '고/Josa': True,
       '랑/Josa': True,
       '놀다/Verb': True},
      'pos')]
    # 분류기 동작
    classifier = nltk.NaiveBayesClassifier.train(train_xy)
    # 형태소 분석 전  neg 
    test_sentence = [("난 수업이 마치면 메리랑 놀거야")]
    test_docs = pos_tagger.pos(test_sentence[0])
    test_docs
    [('난', 'Noun'),
     ('수업', 'Noun'),
     ('이', 'Josa'),
     ('마치', 'Noun'),
     ('면', 'Josa'),
     ('메리', 'Noun'),
     ('랑', 'Josa'),
     ('놀거야', 'Verb')]
    classifier.show_most_informative_features()
    Most Informative Features
                      난/Noun = True              neg : pos    =      2.5 : 1.0
                     메리/Noun = False             neg : pos    =      2.5 : 1.0
                    고양이/Noun = False             neg : pos    =      1.5 : 1.0
                좋다/Adjective = False             neg : pos    =      1.5 : 1.0
                      가/Josa = False             neg : pos    =      1.1 : 1.0
                      고/Josa = False             neg : pos    =      1.1 : 1.0
                     놀다/Verb = False             neg : pos    =      1.1 : 1.0
                      는/Josa = False             neg : pos    =      1.1 : 1.0
                      도/Josa = False             neg : pos    =      1.1 : 1.0
                      랑/Josa = False             neg : pos    =      1.1 : 1.0
    test_sent_features = {word: (word in tokens) for word in test_docs}
    test_sent_features
    {('난', 'Noun'): False,
     ('수업', 'Noun'): False,
     ('이', 'Josa'): False,
     ('마치', 'Noun'): False,
     ('면', 'Josa'): False,
     ('메리', 'Noun'): False,
     ('랑', 'Josa'): False,
     ('놀거야', 'Verb'): False}
    # pos 로 분류
    classifier.classify(test_sent_features)
    'pos'

    문장의 유사도 측정

    • 어떤 문장을 벡터로 표현할 수 있다면 벡터간 거리를 구하는 방법으로 해결 가능

    from sklearn.feature_extraction.text import  CountVectorizer
    # scikit-learn 텍스트 특징(feature) 추출 모듈
    # CountVectorizer 글자를 벡터로 만들어줌
    vectorizer = CountVectorizer(min_df = 1)
    contents = ['메리랑 놀러가고 싶지만 바쁜데 어떻하죠?',
                       '메리는 공원에서 산책하고 노는 것을 싫어해요',
                       '메리는 공원에서 노는 것도 싫어해요. 이상해요.',
                       '먼 곳으로 여행을 떠나고 싶은데 너무 바빠서 그러질 못하고 있어요']
    # 추출
    X = vectorizer.fit_transform(contents)
    vectorizer.get_feature_names()
    ['것도',
     '것을',
     '곳으로',
     '공원에서',
     '그러질',
     '너무',
     '노는',
     '놀러가고',
     '떠나고',
     '메리는',
     '메리랑',
     '못하고',
     '바빠서',
     '바쁜데',
     '산책하고',
     '싫어해요',
     '싶은데',
     '싶지만',
     '어떻하죠',
     '여행을',
     '이상해요',
     '있어요']
    # 4개문장 == 4개열로 표현 각 단어 위치가 1의 값을 가짐 메리랑은 첫번째 열 11번째가 1임
    X.toarray().transpose()
    array([[0, 0, 1, 0],
           [0, 1, 0, 0],
           [0, 0, 0, 1],
           [0, 1, 1, 0],
           [0, 0, 0, 1],
           [0, 0, 0, 1],
           [0, 1, 1, 0],
           [1, 0, 0, 0],
           [0, 0, 0, 1],
           [0, 1, 1, 0],
           [1, 0, 0, 0],
           [0, 0, 0, 1],
           [0, 0, 0, 1],
           [1, 0, 0, 0],
           [0, 1, 0, 0],
           [0, 1, 1, 0],
           [0, 0, 0, 1],
           [1, 0, 0, 0],
           [1, 0, 0, 0],
           [0, 0, 0, 1],
           [0, 0, 1, 0],
           [0, 0, 0, 1]], dtype=int64)
    X = vectorizer.fit_transform(contents)
    num_samples, num_features = X.shape
    num_samples, num_features
    (4, 22)
    new_post = ['메리랑 공원에서 산책하고 놀고 싶어요']
    new_post_vec = vectorizer.transform(new_post)
    new_post_vec.toarray()
    array([[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]],
          dtype=int64)
    # 거리 계산을 위한 함수 호출
    # new_post 와 contents의 거리 구하기
    # norm 의 의미: https://leebaro.tistory.com/entry/norm%EB%85%B8%EB%A6%84%EC%9D%98-%EC%A0%95%EC%9D%98
    import scipy as sp
    
    def dist_raw(v1, v2):
        delta = v1 - v2
        return sp.linalg.norm(delta.toarray())
    # new_post 와 contents의 거리 확인
    #best_doc = None
    best_dist = 65535
    best_i = None
    
    for i in range(0, num_samples):
        post_vec = X.getrow(i)
        d = dist_raw(post_vec, new_post_vec)
    
        print('== Post %i with dist = %.2f     :  %s' %(i, d, contents[i]))
        if d<best_dist:
            best_dist = d
            best_i = i
    == Post 0 with dist = 2.45     :  메리랑 놀러가고 싶지만 바쁜데 어떻하죠?
    == Post 1 with dist = 2.24     :  메리는 공원에서 산책하고 노는 것을 싫어해요
    == Post 2 with dist = 2.65     :  메리는 공원에서 노는 것도 싫어해요. 이상해요.
    == Post 3 with dist = 3.46     :  먼 곳으로 여행을 떠나고 싶은데 너무 바빠서 그러질 못하고 있어요
    # 좀더 한글 문장에 맞게 벡터화 진행
    # from konlpy.tag import Twitter
    # t = Twitter()
    from konlpy.tag import Okt
    t = Okt()
    # morphs() 형태소 추출
    contents_tokens = [t.morphs(row) for row in contents]
    contents_tokens
    [['메리', '랑', '놀러', '가고', '싶지만', '바쁜데', '어떻하죠', '?'],
     ['메리', '는', '공원', '에서', '산책', '하고', '노', '는', '것', '을', '싫어해요'],
     ['메리', '는', '공원', '에서', '노', '는', '것', '도', '싫어해요', '.', '이상해요', '.'],
     ['먼',
      '곳',
      '으로',
      '여행',
      '을',
      '떠나고',
      '싶은데',
      '너무',
      '바빠서',
      '그러질',
      '못',
      '하고',
      '있어요']]
    # 형태소 분석 후 띄어쓰기로 구분하고 하나의 문장(sentence)으로 만들기
    contents_for_vectorize = []
    
    for content in contents_tokens:
        sentence = ''
        for word in content:
            sentence = sentence + ' ' + word
    
        contents_for_vectorize.append(sentence)
    
    contents_for_vectorize
    [' 메리 랑 놀러 가고 싶지만 바쁜데 어떻하죠 ?',
     ' 메리 는 공원 에서 산책 하고 노 는 것 을 싫어해요',
     ' 메리 는 공원 에서 노 는 것 도 싫어해요 . 이상해요 .',
     ' 먼 곳 으로 여행 을 떠나고 싶은데 너무 바빠서 그러질 못 하고 있어요']
    X = vectorizer.fit_transform(contents_for_vectorize)
    num_samples, num_features = X.shape
    num_samples, num_features
    (4, 20)
    vectorizer.get_feature_names()
    ['가고',
     '공원',
     '그러질',
     '너무',
     '놀러',
     '떠나고',
     '메리',
     '바빠서',
     '바쁜데',
     '산책',
     '싫어해요',
     '싶은데',
     '싶지만',
     '어떻하죠',
     '에서',
     '여행',
     '으로',
     '이상해요',
     '있어요',
     '하고']
    X.toarray().transpose()
    array([[1, 0, 0, 0],
           [0, 1, 1, 0],
           [0, 0, 0, 1],
           [0, 0, 0, 1],
           [1, 0, 0, 0],
           [0, 0, 0, 1],
           [1, 1, 1, 0],
           [0, 0, 0, 1],
           [1, 0, 0, 0],
           [0, 1, 0, 0],
           [0, 1, 1, 0],
           [0, 0, 0, 1],
           [1, 0, 0, 0],
           [1, 0, 0, 0],
           [0, 1, 1, 0],
           [0, 0, 0, 1],
           [0, 0, 0, 1],
           [0, 0, 1, 0],
           [0, 0, 0, 1],
           [0, 1, 0, 1]], dtype=int64)
    new_post = ['메리랑 공원에서 산책하고 놀고 싶어요']
    new_post_tokens = [t.morphs(row) for row in new_post]
    
    new_post_for_vectorize = []
    
    for content in new_post_tokens:
        sentence = ''
        for word in content:
            sentence = sentence + ' ' + word
    
        new_post_for_vectorize.append(sentence)
    
    new_post_for_vectorize
    [' 메리 랑 공원 에서 산책 하고 놀고 싶어요']
    new_post_vec = vectorizer.transform(new_post_for_vectorize)
    new_post_vec.toarray()
    array([[0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]],
          dtype=int64)
    import scipy as sp
    
    def dist_raw(v1, v2):
        delta = v1 - v2
        return sp.linalg.norm(delta.toarray())
    best_doc = None
    best_dist = 65535
    best_i = None
    
    for i in range(0, num_samples):
        post_vec = X.getrow(i)
        d = dist_raw(post_vec, new_post_vec)
    
        print("== Post %i with dist=%.2f   : %s" %(i,d,contents[i]))
    
        if d<best_dist:
            best_dist = d
            best_i = i
    == Post 0 with dist=3.00   : 메리랑 놀러가고 싶지만 바쁜데 어떻하죠?
    == Post 1 with dist=1.00   : 메리는 공원에서 산책하고 노는 것을 싫어해요
    == Post 2 with dist=2.00   : 메리는 공원에서 노는 것도 싫어해요. 이상해요.
    == Post 3 with dist=3.46   : 먼 곳으로 여행을 떠나고 싶은데 너무 바빠서 그러질 못하고 있어요
    print("Best post is %i, dist = %.2f" % (best_i, best_dist))
    print('-->', new_post)
    print('---->', contents[best_i])
    Best post is 1, dist = 1.00
    --> ['메리랑 공원에서 산책하고 놀고 싶어요']
    ----> 메리는 공원에서 산책하고 노는 것을 싫어해요
    for i in range(0,len(contents)):
        print(X.getrow(i).toarray())
    
    print('---------------------')
    print(new_post_vec.toarray())
    [[1 0 0 0 1 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0]]
    [[0 1 0 0 0 0 1 0 0 1 1 0 0 0 1 0 0 0 0 1]]
    [[0 1 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0]]
    [[0 0 1 1 0 1 0 1 0 0 0 1 0 0 0 1 1 0 1 1]]
    ---------------------
    [[0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 1]]
    # sp.linalg.norm - https://datascienceschool.net/view-notebook/dd1680bfbaab414a8d54dc978c6e883a/
    def dist_norm(v1, v2):
        v1_normalized = v1 / sp.linalg.norm(v1.toarray())
        v2_normalized = v2 / sp.linalg.norm(v2.toarray())
    
        delta = v1_normalized - v2_normalized
    
        return sp.linalg.norm(delta.toarray())
    best_doc = None
    best_dist = 65535
    best_i = None
    
    for i in range(0, num_samples):
        post_vec = X.getrow(i)
        d = dist_norm(post_vec, new_post_vec)
    
        print("== Post %i with dist=%.2f   : %s" %(i,d,contents[i]))
    
        if d<best_dist:
            best_dist = d
            best_i = i
    == Post 0 with dist=1.28   : 메리랑 놀러가고 싶지만 바쁜데 어떻하죠?
    == Post 1 with dist=0.42   : 메리는 공원에서 산책하고 노는 것을 싫어해요
    == Post 2 with dist=0.89   : 메리는 공원에서 노는 것도 싫어해요. 이상해요.
    == Post 3 with dist=1.30   : 먼 곳으로 여행을 떠나고 싶은데 너무 바빠서 그러질 못하고 있어요
    # 결과는 조금 변했으나 유사 문장은 변하지 않음
    print("Best post is %i, dist = %.2f" % (best_i, best_dist))
    print('-->', new_post)
    print('---->', contents[best_i])
    Best post is 1, dist = 0.42
    --> ['메리랑 공원에서 산책하고 놀고 싶어요']
    ----> 메리는 공원에서 산책하고 노는 것을 싫어해요

    tf / idf 개념

     

    tf(term frequency) idf(inverse document frequency)

    • 텍스트 마이닝에서 사용하는 일종의 단어별로 부과하는 가중치

     

    tf(term frequency)

    • 어떤 단어가 문장내에서 자주 등장할 수록 중요도가 높을 것으로 보는 것

     

    idf(inverse document frequency)

    • 문서군의 성격에 따라 중요 단어 여부 결정

     

    TF-IDF는 TF와 IDF를 곱한 값을 의미

    • TF-IDF는 모든 문서에서 자주 등장하는 단어는 중요도가 낮다고 판단하며, 특정 문서에서만 자주 등장하는 단어는 중요도가 높다고 판단

    • TF-IDF 값이 낮으면 중요도가 낮은 것이며, TF-IDF 값이 크면 중요도가 큰 것

    • the나 a와 같이 불용어의 경우에는 모든 문서에 자주 등장하기 마련이기 때문에 자연스럽게 불용어의 TF-IDF의 값은 다른 단어의 TF-IDF에 비해서 낮아지게 됨

    # tfidf 함수 작성
    # idf : log() 문서 n이 너무 커지질 수 있기 때문
    
    def tfidf(t, d, D):
        tf  = float(d.count(t)) / sum(d.count(w) for w in set(d)) 
        idf = sp.log(float(len(D)) / (len([doc for doc in D if t in doc])))
        return tf, idf
    sp.log(3/3)
    C:\ProgramData\Anaconda3\envs\r_study\lib\site-packages\ipykernel_launcher.py:1: DeprecationWarning: scipy.log is deprecated and will be removed in SciPy 2.0.0, use numpy.lib.scimath.log instead
      """Entry point for launching an IPython kernel.
    
    
    
    
    
    0.0
    sp.log(3/2)
    C:\ProgramData\Anaconda3\envs\r_study\lib\site-packages\ipykernel_launcher.py:1: DeprecationWarning: scipy.log is deprecated and will be removed in SciPy 2.0.0, use numpy.lib.scimath.log instead
      """Entry point for launching an IPython kernel.
    
    
    
    
    
    0.4054651081081644
    sp.log(3/1)
    C:\ProgramData\Anaconda3\envs\r_study\lib\site-packages\ipykernel_launcher.py:1: DeprecationWarning: scipy.log is deprecated and will be removed in SciPy 2.0.0, use numpy.lib.scimath.log instead
      """Entry point for launching an IPython kernel.
    
    
    
    
    
    1.0986122886681098
    a, abb, abc = ['a'], ['a','b','b'], ['a','b','c']
    D = [a, abb, abc]
    
    print(tfidf('a', a, D)) # 'a'는  a에 1/1번 == tf=1, idf == log(3/3) = 0
    print(tfidf('b', abb, D)) # 'b'는  abb에 2/3번 == tf=0.666, log(3/2) = 0.4054651081081644
    print(tfidf('a', abc, D))
    print(tfidf('b', abc, D))
    print(tfidf('c', abc, D)) # 'c'는  abc에 1/3번 == tf=0.333, log(3/1) = 1.0986122886681098
    (1.0, 0.0)
    (0.6666666666666666, 0.4054651081081644)
    (0.3333333333333333, 0.0)
    (0.3333333333333333, 0.4054651081081644)
    (0.3333333333333333, 1.0986122886681098)
    
    
    C:\ProgramData\Anaconda3\envs\r_study\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: scipy.log is deprecated and will be removed in SciPy 2.0.0, use numpy.lib.scimath.log instead
    # TF-IDF는 TF와 IDF를 곱한 값을 의미
    def tfidf(t, d, D):
        tf = float(d.count(t)) / sum(d.count(w) for w in set(d))
        idf = sp.log( float(len(D))/(len([doc for doc in D if t in doc])) )
        return tf * idf
    # scikit-learn 의 TfidfVectorizer import
    from sklearn.feature_extraction.text import TfidfVectorizer
    vectorizer = TfidfVectorizer(min_df = 1, decode_error='ignore')
    contents_tokens = [t.morphs(row) for row in contents]
    
    contents_for_vectorize = []
    
    for content in contents_tokens:
        sentence = ''
        for word in content:
            sentence = sentence + ' ' + word
    
        contents_for_vectorize.append(sentence)
    
    X = vectorizer.fit_transform(contents_for_vectorize)
    num_samples, num_features = X.shape
    num_samples, num_features
    (4, 20)
    # 말뭉치 확인
    vectorizer.get_feature_names()
    ['가고',
     '공원',
     '그러질',
     '너무',
     '놀러',
     '떠나고',
     '메리',
     '바빠서',
     '바쁜데',
     '산책',
     '싫어해요',
     '싶은데',
     '싶지만',
     '어떻하죠',
     '에서',
     '여행',
     '으로',
     '이상해요',
     '있어요',
     '하고']
    new_post = ['근처 공원에 메리랑 놀러가고 싶네요.']
    new_post_tokens = [t.morphs(row) for row in new_post]
    
    new_post_for_vectorize = []
    
    for content in new_post_tokens:
        sentence = ''
        for word in content:
            sentence = sentence + ' ' + word
    
        new_post_for_vectorize.append(sentence)
    
    new_post_for_vectorize
    [' 근처 공원 에 메리 랑 놀러 가고 싶네요 .']
    new_post_vec = vectorizer.transform(new_post_for_vectorize)
    # 다른 결과를 얻을 수 있음
    best_doc = None
    best_dist = 65535
    best_i = None
    
    for i in range(0, num_samples):
        post_vec = X.getrow(i)
        d = dist_norm(post_vec, new_post_vec)
    
        print("== Post %i with dist=%.2f   : %s" %(i,d,contents[i]))
    
        if d<best_dist:
            best_dist = d
            best_i = i
    
    print("Best post is %i, dist = %.2f" % (best_i, best_dist))
    print('-->', new_post)
    print('---->', contents[best_i])
    == Post 0 with dist=0.90   : 메리랑 놀러가고 싶지만 바쁜데 어떻하죠?
    == Post 1 with dist=1.18   : 메리는 공원에서 산책하고 노는 것을 싫어해요
    == Post 2 with dist=1.16   : 메리는 공원에서 노는 것도 싫어해요. 이상해요.
    == Post 3 with dist=1.41   : 먼 곳으로 여행을 떠나고 싶은데 너무 바빠서 그러질 못하고 있어요
    Best post is 0, dist = 0.90
    --> ['근처 공원에 메리랑 놀러가고 싶네요.']
    ----> 메리랑 놀러가고 싶지만 바쁜데 어떻하죠?

    KoNLP(자연어처리).html
    1.17MB

    'Python' 카테고리의 다른 글

    자연어 처리 예제  (0) 2020.07.22
    Pandas - pivot_table, Seaborn  (0) 2020.07.20
    Pandas 기초  (0) 2020.07.16
    Numpy 기본  (0) 2020.07.16
    OPEN_API를 사용하여 데이터 수집하기  (0) 2020.06.15
Designed by Tistory.