Clojureで「言語処理100本ノック 2015」(その1)

最後まで達成できるか分かりませんが、言語処理100ノックをClojureで解いていきたいと思います。

目次

言語処理100本ノック 2015とは

www.cl.ecei.tohoku.ac.jp

言語処理100本ノックは,実践的な課題に取り組みながら,プログラミング,データ分析,研究のスキルを楽しく習得することを目指した問題集です

つまり、プログラミング言語の習得だけではなく、データ分析のスキルも得ることが出来るというわけです。

第1章: 準備運動

00. 文字列の逆順

文字列"stressed"の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ.

(apply str (reverse "stressed"))

01. 「パタトクカシーー」

「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.

(apply str 
  (map-indexed 
    (fn [idx, item] 
      (when (even? idx) item)) 
    "パタトクカシーー"))

一度解いた後、もっと簡潔な書き方を思いついた。

(apply str (take-nth 2 "パタトクカシーー"))

02. 「パトカー」+「タクシー」=「パタトクカシーー」

「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ.

(apply str (interleave (seq "パトカー") (seq "タクシー")))

interleave は、2つ以上のリストの項目を交互に返します。

03. 円周率

"Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.

(require '[clojure.string :as str])

(defn word-list [str]
  (remove (fn [x] (= x "")) 
    (str/split str #"\W")))

(map count (word-list "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."))

結果は、 (3 1 4 1 5 9 2 6 5 3 5 8 9 7 9) のように円周率になります。

04. 元素記号

"Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."という文を単語に分解し,1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字,それ以外の単語は先頭に2文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

(require '[clojure.string :as str])

(defn word-list [input]
  (remove #(= % "") 
    (str/split input #"\W")))


(defn word-slice [idx input]
  (if (some #(= (+ idx 1) %) '(1 5 6 7 8 9 15 16 19))
    (hash-map (str (first input)) idx)
    (hash-map (apply str (take 2 input)) idx)))


(reduce merge 
  (map #(word-slice (first %) (second %)) 
    (map-indexed vector
      (word-list "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."))))
))

結果

{"Si" 13, "K" 18, "He" 1, "Ca" 19, "Al" 12, "S" 15, "H" 0, "Be" 3, "C" 5, "F" 8, "B" 4, "Cl" 16, "P" 14, "O" 7, "Na" 10, "N" 6, "Ar" 17, "Li" 2, "Mi" 11, "Ne" 9}

05. n-gram

与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ.この関数を用い,"I am an NLPer"という文から単語bi-gram,文字bi-gramを得よ.

(require '[clojure.string :as str])

(defn n-gram [n target & cond]
  (if (= (first cond) "word")
      (map #(apply str %) (partition n 1 (str/split target #"\W+")))
      (map #(apply str %) (partition n 1 (seq target)))))

(n-gram 3 "I am an NLPer")
; => ("I a" " am" "am " "m a" " an" "an " "n N" " NL" "NLP" "LPe" "Per")

(n-gram 2 "I am an NLPer")
; => ("I " " a" "am" "m " " a" "an" "n " " N" "NL" "LP" "Pe" "er")

(n-gram 2 "I am an NLPer" "word")
; => ("Iam" "aman" "anNLPer")

ifの後がダサい。