Haskell에서 자연언어 처리 100개 노크의 제1장을 풀어본다. 【중편~bi-gram이란】

Haskell에서 자연 언어 처리 100개의 1장을 풀어보세요!



Haskell에서 자연언어 처리 100개 노크의 제1장을 풀어본다. 【전편】 계속
뭐 1장만이라면 대단히 고생하지 않을 것이라고 누구나가 츳코미를 넣고 있겠지만. .

05문제의 내용이 상당히 풍부해져 버렸다



그래서 하나의 기사로했습니다.

문제와 해답에 이르기까지의 과정



05. n-gram



주어진 시퀀스 (문자열, 목록 등)에서 n-gram을 만드는 함수를 만듭니다. 이 함수를 사용하여 "I am an NLPer"라는 문장에서 단어 bi-gram, 문자 bi-gram을 얻습니다.

우선, n-gram 이란 무엇인가로부터 시작되어 버린다.
우선 위키로 조사한다.

「N문자 인덱스법」 「N그램법」 등이라고도 한다. 검색 대상을 단어 단위가 아닌 문자 단위로 분해하고 후속 N-1 문자를 포함한 상태에서 출현 빈도를 구하는 방법.

분명히 ↑만으로는 모르겠다. (영어판 wiki에는 다소 자세하고 있다.)
그 밖에도 조사해 가면,

이웃 (연속) n 개

등으로 쓰여져 드디어 다가온다.
조사를 진행하면 아무래도
単語n-gram 는 연속 n개의 단어文字n-gram 는 연속 n개의 문자

라는 인식인것 같다.
n이 2일 때 n-gram은 bi-gram이라고도 할 수 있는 것 같다.
구체적으로 보면,

↑ 출처

위는 "This is a sentence"에 대하여 単語n-gram이다.文字n-gram 는 최소 단위를 단어가 아닌 문자로 한 버전이라고 봐도 좋을 것이다.

그렇다면 Haskell에서는 어떻게 n-gram 함수를 사용합니까?
리스트의 선두의 n개를 취해, 다음은 리스트의 선두를 들여다 본 리스트로부터 선두의 n개를 취해,....
라고 할 수 있으므로 再帰 에 의한 정의를 할 수 있는 것 같다.
실제로 takedrop를 사용하여,

ngram
ngram :: Int -> [a] -> [[a]]
ngram n xs  | n <= length xs = take n xs : ngram n (drop 1 xs)
            | otherwise      = []

같이 재귀로 기술할 수 있다.

다만, 구그하면 다른 것에도 여러 가지 방법은 있는 것 같다.
본 것에 공통적으로 보이는 것은

꼬리와 맵과 take
map (take n) . tails

사용하는 방법입니다.tails 함수는 부분 목록 목록을 생성하는 함수로, 예를 들어 "sentence"tails를 적용하면

꼬리
Prelude Data.List> tails "sentence"
["sentence","entence","ntence","tence","ence","nce","ce","e",""]

와 같이, 가장 큰 요소가 리스트의 선두가 된다.
그러므로 map (take n) 를 계속 적용하면

꼬리와 맵과 take
Prelude Data.List> map (take 2) . tails $ "sentence"
["se","en","nt","te","en","nc","ce","e",""]

같은 결과가 된다.
그리고는 take 되어, filter 나름을 쓰면 기대하는 결과를 얻을 수 있다.
그래서 해답은 다음과 같습니다.

05.hs
module Main where

import qualified Data.List as List
import qualified System.IO as IO

-- 解答その1
ngram :: Int -> [a] -> [[a]]
ngram n xs  | n <= List.length xs = List.take n xs : ngram n (List.drop 1 xs)
            | otherwise           = []
-- 解答その2
ngram' :: Int -> [a] -> [[a]]
ngram' n = List.filter (\xs -> List.length xs == n) . List.map (List.take n) . List.tails

main :: IO()
main = do
    let sentence = "I am an NLPer"
        wbigram = Main.ngram 2 $ List.words sentence  -- 単語bi-gram
        cbigram = Main.ngram 2 sentence               -- 文字bi-gram
    IO.print wbigram
    IO.print cbigram

출력
[["I","am"],["am","an"],["an","NLPer"]]
["I "," a","am","m "," a","an","n "," N","NL","LP","Pe","er"]

좋은 웹페이지 즐겨찾기