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の後がダサい。

Clojureのインストール Using Brew

2011年にプログラミング言語の1つであるClojure入門しようとしたけど、時間だけが過ぎていた。こんどこそは入門しようと思い、Mac(high sirrera)にClojureをインストールした。

Javaのインストール

$ brew cask install java

Clojureのインストール

$ brew install clojure

Clojureの起動

$ clj
user=> (reverse "Hello World!")
(\! \d \l \r \o \W \space \o \l \l \e \H)

artisan.hatenablog.com

Day One ClassicでDropboxと同期できなくなった

最強の日記アプリと誉れ高いDay One。これまで日記のデータをDropboxに保存し、複数デバイスで同期して利用していたが、気づいたら同期出来なくなっていた。なんでろうと思ったら、サポートに記載あった。

Syncing with Dropbox in Day One Classic | Day One Help

  • 2017年9月28日に、DropboxがDay Oneとデータを同期できるAPIを廃止
  • Day One Classicは2016年3月でサポート終了したため、対応せず

とりあえず、暫定対策としてiCloudで同期して利用している。そろそろDay One 2へ移行する必要があるかもしれない。

apt-get installでインストールしたパッケージに含まれるファイル一覧を表示させる

dpkg-query -L <package_name> を利用する。 UbuntuなどのDebian系のディストリビューションで利用可能。

# dpkg-query -L mecab    
/.
/usr
/usr/bin
/usr/bin/mecab
/usr/share
/usr/share/man
/usr/share/man/man1
/usr/share/man/man1/mecab.1.gz
/usr/share/doc
/usr/share/doc/mecab
/usr/share/doc/mecab/mecab.html
/usr/share/doc/mecab/changelog.Debian.gz
/usr/share/doc/mecab/copyright
/usr/share/doc/mecab/partial.html
/usr/share/doc/mecab/unk.html
/usr/share/doc/mecab/dic.html
/usr/share/doc/mecab/flow.png
/usr/share/doc/mecab/feature.png
/usr/share/doc/mecab/soft.html
/usr/share/doc/mecab/dic-detail.html
/usr/share/doc/mecab/libmecab.html
/usr/share/doc/mecab/learn.html
/usr/share/doc/mecab/result.png
/usr/share/doc/mecab/posid.html
/usr/share/doc/mecab/README.Debian
/usr/share/doc/mecab/README
/usr/share/doc/mecab/AUTHORS
/usr/share/doc/mecab/index.html
/usr/share/doc/mecab/bindings.html
/usr/share/doc/mecab/format.html
/usr/share/doc/mecab/feature.html
/usr/share/doc/mecab/mecab.css

参考

askubuntu.com

データがあればUPDATE。なければINSERTの「INSERT ... ON DUPLICATE KEY UPDATE 構文」

MySQLで、データが存在する場合は更新を行い、存在しない場合にのみ登録を行いたい場合には、「INSERT ... ON DUPLICATE KEY UPDATE 構文」を利用する。

今回は、サンプルとして複数データを一度に登録する場合である所謂Bulk Insertのサンプルを掲載しておく。

流れとしては、

  • UNIQUE インデックスまたは PRIMARY KEYの指定を行う(以下の例では、fruit_nameに対し、UNIQUEインデックスを指定している)
  • 以下のような「INSERT ... ON DUPLICATE KEY UPDATE 構文」を含んだSQL文を実行させる
  • INSERT文の部分が実行され、重複データと判断された場合には、 ON DUPLICATE KEY UPDATE 以下の更新処理が実行される
INSERT INTO
  fruit_count(fruit_name, total_count, updated_at)
VALUES
  ('apple', total_count, NOW()),  ('banana', total_count, NOW())
ON DUPLICATE KEY UPDATE
  fruit_name = VALUES(fruit_name),
  total_count = total_count + 1

テーブルに AUTO_INCREMENT カラムが含まれているとき

上記のままだと、AUTO_INCREMENT カラムの値が激増する。そのため、下記のようにする必要があるようだ。当方未確認。

INSERT INTO
  fruit_count(fruit_name, total_count, updated_at)
VALUES
  ('apple', total_count, NOW()),  ('banana', total_count, NOW())
ON DUPLICATE KEY UPDATE
  fruit_name = VALUES(fruit_name),
  total_count = total_count + 1,
  id=LAST_INSERT_ID(id)

参考

MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.2.5.3 INSERT ... ON DUPLICATE KEY UPDATE 構文