latexのソースからMeCabを用いて名詞だけ抜き出す

■記事の概要:latexのソースから形態素解析器を用いて名詞だけ抜き出したリストを作る.
■環境:MinGW または MSYS2 (Cygwin でも多分大丈夫だろうな~と思うが試していない)
■主な道具:MeCab, python3, make

■動機と背景:latexで作成しているPDFファイルのページ数が増えてきたので,索引を付けようと考えた.(索引はlatex の\indexという命令で作れるが,この記事ではこれ以上触れない).最初は索引の項目を手で付けていたが,思いついたものを十個ぐらい挙げたら飽きてしまった.そこで,《latexソースファイルの中から名詞だけ抜き出す》ことを考えた.

■環境整備
1.MinGW または MSYS2 については環境整備が済んでいるものとする.
2.MeCabのインストール:Windows用に配布されているバイナリを使う.公式からリンクされているダウンロードページ(http://taku910.github.io/mecab/#download)からBinary package for MS-Windowsという項目の直下の mecab-0.996.exe をダウンロードし,インストールした.インストール時にエンコーディングを指定するように言われる.今回の目的はlatexのソース処理なので utf-8 を選ぶ.(デフォルトだとShift-JPだったように記憶している).
3.Pythonのインストール:Windows用に配布されているバイナリを使う.公式ページ(https://www.python.org/)からDownload/latestに飛び,そこから「Windows x86-64 executable installer」と題されたファイルをダウンロードし,インストールした.この記事が書かれた時点での最新版は3.6.4であった.
4.パスを通す.MecabとPythonがMinGWシェルから見えるようにパスを通す必要がある.(MinGW なら
C:\MinGW\msys\1.0\home\YourUserName, MSYS2 なら C:\msys64\home\YourUserName などに置いてある).bashrc の下の方に次のような行を加える:

export MECABPATH=/c/MeCab
export PATH=$PATH:$MECABPATH/bin

export PYTHONPATH=/c/Python3.6.4
export PATH=$PATH:$PYTHONPATH
export PYTHONIOENCODING=UTF-8

※《/c/MeCab》や《/c/Python3.6.4》は各自のインストールの実態に合わせて適宜変更してほしい.
※最後の《export PYTHONIOENCODING=UTF-8》という行はパスを通しているのではなく,ユニコード文字(utf-8)をpython3で扱うときに必須らしい設定である.

■MeCab用のユーザー辞書作成
MeCab には「微分」や「積分」のような一般的な用語は(Windowsバイナリに同梱の)辞書ファイルに登録されている.しかし,それほど一般的でない用語は登録されておらず,バラバラの言葉や文字として認識されてしまう.そこでユーザ辞書を作成する.ユーザ辞書の元になるデータは次のような形式のcsvファイルである:

無限小,,,10,名詞,一般,*,*,*,*,個別名,アアアア,REGISTERED
無限大,,,10,名詞,一般,*,*,*,*,個別名,アアアア,REGISTERED
無限小量,,,10,名詞,一般,*,*,*,*,個別名,アアアア,REGISTERED
無限大量,,,10,名詞,一般,*,*,*,*,個別名,アアアア,REGISTERED

「アアアア」などとなっている箇所は本来きちんとした読みを登録するのだが面倒であり,今回の業務と無関係なのでこのようにしてある.(今回は説明を省略するが,一行に一つ単語を書いたファイルからこのようなファイルを自動生成している.)「REGISTERED」は後で解析結果を加工するためのヒントとするための追加タグである.

■Makefileの作成
次のようなMakefileを用意する.

help:
	@grep -E '^[0-9a-zA-Z_-]+[[:blank:]]*:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[1;32m%-30s\033[0m %s\n", $$1, $$2}'

dict : mecab.csv ## add user dictionary for mecab by mecab.csv
	mecab-dict-index -d$(MECABPATH)/dic/ipadic -u ./mecab.dic -f utf8 -t utf8 mecab.csv

mecab : hoge.tex ## analyze hoge.tex by mecab
	$(eval MECAB_OUT := $(strip $(basename .tex $ $(UNIQ)
	python extractNoun.py  $(UNIQ) > $(RESULT)
	rm  $(MECAB_OUT) $(UNIQ)

make dict としてやると mecab.csv が処理され mecab.dic というMeCab用ユーザー辞書が作成される.(helpターゲットのルールについては以前の記事を参考にしてほしい).

make mecab としてやるとまずターゲットの hoge.tex が MeCab で処理され,hoge-out.txt が生成される.このファイルはhoge.texのすべての内容を品詞分解して一行に一つずつ並べたものになっているので重複が多い.そこでhoge-out.txt sort し uniq して重複を除去して hoge-out-u.txtを生成する.(前段の sed については以前の記事を参考にされたい.)今回は「名詞」とタグ付けされたものだけ欲しいので,hoge-out-u.txt を自作のpythonスクリプト extractNoun.py で処理して最終結果の hoge-nouns.txt を得る.

★Makeルールの中で変数を定義する方法については『makefile 動的に変数に代入 共通して使う』を参考にさせて頂いた.

■pythonスクリプト extractNoun.py

# -*- coding: utf-8 -*-
import sys
import re #正規表現
import codecs
import copy

reNegIgnoreFlag = re.compile('REGISTERED')
reNeg = re.compile('接頭詞')
rePos = re.compile('(.+?)名詞')
reNum = re.compile('(\d+)')
reSymbols = re.compile('[!\$%\#&\(\){}\+,\-@\.\\\\=\"\'\*:;\?–\[\]|_`\^,]+')

def main():
    f = open(sys.argv[1], 'r', encoding="utf-8_sig")
    input = f.readlines()

    for line in input:
        myFilter(line)

def myFilter(line):
    pos = rePos.search(line)
    neg1 = reNeg.search(line)
    neg2 = reNegIgnoreFlag.search(line)

    if pos and (not neg1) and (not neg2):
        result = pos.group(1).strip()
        isnumber = reNum.search(result)
        containsSymbols = reSymbols.search(result)
        if (not isnumber) and (not containsSymbols):
            sys.stdout.write(result)
            sys.stdout.write('\n')

if __name__ == '__main__' : main()

解説:関数 main() では,一番目の引数 sys.argv[1] として与えられたファイル名を持つファイルを開き,readlines で行の集まりに分解し,各行を関数 myFilter() で処理している.
関数 myFilter() では,事前にコンパイルされた5つの正規表現 reNegIgnoreFlag,reNeg,rePos,reNum,reSymbols を使って「欲しそうなものを抜き出し,要らないものを弾く」ことをやっている.それぞれの正規表現の目的は次の通り:

・reNegIgnoreFlag:MeCabのユーザー辞書に登録済みの単語を検出するため.(MeCabのユーザー辞書のcsvファイルは索引づくりのヒントファイルを兼ねており,そこにまだ登録されていない単語を探すのが今回の目的なので).
・reNeg:「名詞」タグが付いているもののうち,さらに「接頭詞」というタグが付いたものを排除するため.このタグがつくものは「不」「無」「第」「最」などの一文字単語(?)であり,今回の目的にはノイズなので弾く.
・rePos:「名詞」タグを検出するため.
・reNum:年号などの数字列を弾くため.
・reSymbols:latexソースを自然言語解析器にかけた結果として大量の無意味記号列が(MeCabによって,仕方なく)「名詞」に分類されてしまうためそれらを弾くため.

広告

export PYTHONIOENCODING=UTF-8

pythonでユニコードを扱いたいときは .bashrc にこう書いておくといいみたい.とりあえず,これで sys.stdout.write にまつわる UnicodeEncodeError が解消してくれた.

(latex)mdframed 環境の外に脚注を置く方法(tablefootnote)

mdframed 環境中で\footnoteを使うと,mdframed 環境の「内側に」脚注が作られてしまう.これを回避するためには次のようにすればよい:

% !TEX TS-program = platex
% !TEX encoding = UTF-8 Unicode
\documentclass[16pt]{jsarticle}
\usepackage{minitoc}
\usepackage[dvipdfmx]{graphicx}
\usepackage{textgreek}
\usepackage{tikz}
\usepackage[framemethod=tikz]{mdframed}
\usepackage{tablefootnote}

\makeatletter
\AfterEndEnvironment{mdframed}{%
\tfn@tablefootnoteprintout%
\gdef\tfn@fnt{0}%
}
\makeatother

\newcommand{\textgreek}[1]{\begingroup\fontencoding{LGR}\selectfont#1\endgroup}

\title{金について}
\date{}
\begin{document}
\maketitle

金\footnote{ギリシャ語では{\textgreek{qrus\'os}}と呼びます}は(1)希少な鉱物資源であり(2)加工が容易であり、特に伸展性に富む(3)美しい;といった性質により、世界中で珍重されています。

\begin{mdframed}
銀\tablefootnote{ギリシャ語では{\textgreek{ashm\'enio}}と呼びます}は大和言葉では「しろがね」と呼ばれていました。室温における可視光線の反射率は、金属中で最大の98\%です。
\end{mdframed}
\end{document}

つまり上のようにプリアンブルを整備した上で\tablefootnoteを使えば良い.

vacuous truth

たまにこの言葉を思い出せなくてググってるので自分用メモ.

(ここに来た他人用の説明):条件式(A⇒B)のAを「前件」と,そしてBを「後件」と言うのであった.前件が偽ならば後件に何を置いても条件式全体は真と評価される.このような場合に条件式が真になることを特に “vacuous truth” と呼ぶことがある.(決まった訳語はないらしい).古典論理のなかで,入門者を少しばかり悩ませる話題として有名である.

古典論理における条件式は時相のような微妙なニュアンスを含んでいないので日常言語における条件文とそのまま同一視することはできないが,日常言語でも前件として「絶対に起こらない(であろうと思われる)」ことを置いて何かを言うことがある.少し前の話題だがマスコミ各社が「トランプが大統領になるはずがない」と報じていたときに,「トランプが大統領になったら全裸で街を歩く」といった類のツイートしている人たちがいた.前件が絶対に偽だ(とそのときには思われていた)から後件にどんなヤバいことを書いても平気というわけである.

もう一つの「納得方法」として,条件式(A⇒B)を「(Aであって(Bではない))ということはありえない」と言い換えるというものがある.これを論理式で置き換えれば(¬(A∧(¬B)))ということになる.さらに de Morgan を使えばこれは((¬A)∨B) と書き換えられる.この言い換えと置き換えに納得が行くならば,「Aが成り立たない」場合の(A⇒B)の真理表を書いたとき,BがTであってもFであっても
     ((¬F)∨B) = (T ∨ B) = T
となるからvacuous truth も受け入れるべきだということになる.

集合論においても vacuous truth が活躍する場面がある.空集合にはいかなる集合も含まれない.よって,
    {a \in \varnothing}
と書いただけで({a}がなんであれ)偽になる.よって,
    {\forall a \enskip (a \in \varnothing \Rightarrow P(a)).}
という文は任意の述語{P()}について正しい.任意の述語を入れて良いのだから{P()}の代わりにその否定{\neg P()}を入れても良いわけである.よって
    {\forall a \enskip (a \in \varnothing \Rightarrow \neg P(a)).}
つまり,「空集合の任意の要素はいかなる性質をも持ち得る」ということになる.少し騙されたような気持ちになるが,帰納的に構成された集合の列についての命題を証明しようとするときの最初のステップなどでこのような vacuous truth が有効に活用されることもある.

(latex) epigraph と boxnote

よく忘れて困るので自分用メモ.

・章の最初に気の利いた引用を置いてカッコつけるやつをエピグラフ(epigraph)と言う.latex ではそのものズバリの epigraph.sty を使う.
・ノートパッドをちぎったような罫線は boxnote 環境で作る.ascmac.sty を使う.
epi

pdf : epigraph_boxnote

% !TEX TS-program = platex
% !TEX encoding = UTF-8 Unicode
\documentclass{jsarticle}
\usepackage{minitoc}
\usepackage{textgreek}
\usepackage{ascmac} %for boxnote
\usepackage{epigraph}
\usepackage[utf8x]{inputenc}

\setlength\epigraphwidth{.8\textwidth}

\newcommand{\textgreek}[1]{\begingroup\fontencoding{LGR}\selectfont#1\endgroup}
\title{金について}
\date{}
\begin{document}
\maketitle

\epigraph{<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>
All that glisters is not gold—\\
Often have you heard that told.\\
Many a man his life hath sold\\
But my outside to behold.}{William Shakespeare, \textit{The Merchant of Venice}}

\epigraph{
Fort von hier sei sie entf\"uhrt!\\
Bis Abend, achtet's wohl,\\
pflegen wir sie als Pfand:\\
wir kehren wieder; doch kommen wir,\\
und bereit liegt nicht als L\"osung\\
das Rheingold licht und rot —}{Richard Wagner, \textit{Das Rheingold}}

\section{金の基本的性質}
金(ギリシャ語では {\textchi}{\textrho}{\textupsilon}{\textsigma}\textgreek{ό}{\textvarsigma} と呼びます)は(1)希少な鉱物資源であり(2)加工が容易であり、特に伸展性に富む(3)美しい;といった性質により、世界中で珍重されています。

原子番号は79であり、貴金属としては最も大きいです。 金は単体では金色と呼ばれる光沢のある黄色い金属ですが、非常に細かい粒子状(金コロイド)にすると黒やルビー色に見える場合があり、時には紫色になります。これらの色は金のプラズモン周波数によるもので、主に黄色と赤を反射し青を吸収します。このため、薄い金箔を光にかざすと、反射と吸収の谷間にあたる緑色に見えるのです。

\begin{boxnote}
金が持つ独特の金属色は日本語では「金色」と呼ばれます。英語でもずばり``gold'' です。しかしながら、冒頭に引用したワーグナー『ラインの黄金』では「輝く赤い」と形容されています。このように,金が常に「金色」と形容されるわけではないことには注意が必要です。
\end{boxnote}

\end{document}

千円を崩す方法(Haskell)

次のような問題を考えてみましょう:

千円を両替して崩す方法は何通りあるだろうか.ただし,一円玉,五円玉,十円玉,五十円玉,百円玉,五百円玉を自由に(好きなだけ)使って良いものとする.

まず問題を一般化し,つぎのように考えます.{A_n}によって「{n}円を一円玉で崩す方法の数」を表すことにします.(と言っても{n\ge 0}ならば常に{A_n = 1}なのですが).

また,{B_n}によって「{n}円を一円玉と五円玉で崩す方法の数」を,

{C_n}によって「{n}円を一円玉と五円玉と十円玉で崩す方法の数」を,

{D_n}によって「{n}円を一円玉と五円玉と十円玉と五十円玉で崩す方法の数」を,

{E_n}によって「{n}円を一円玉と五円玉と十円玉と五十円玉と百円玉で崩す方法の数」を,

最後に{F_n}によって「{n}円を一円玉と五円玉と十円玉と五十円玉と百円玉と五百円玉で崩す方法の数」を表すことにします.

このように定式化すると,クイズの答えは{F_{1000}}と表されます.あとはこの具体的な数値を求めれば良いわけです.

さて,{F_n}はを「n円を五百円玉を一枚も使わないで表した場合の数」と「(n-500)円をすべてのコインを好きなだけ使って表した場合の数」の和だと考えられます.よって

{F_n = E_n + F_{n-500}}

となります.よって,{F_n}の計算を{E_{n},\,F_{n-500}}の計算に還元できます.

同様に考えれば
{E_n = D_n + E_{n-100}}などの式が得られます.ただし,負のインデックスに対しては{A_n, B_n, C_n, D_n, E_n, F_n}はいずれもゼロとします.この考えをそのままHaskellコードにすれば次のようになります:

fA n | (n < 0) = 0
     | otherwise = 1

fB n | (n < 0) = 0
     | otherwise = fA n + fB (n-5)

fC n | (n < 0) = 0
     | otherwise = fB n + fC (n-10)

fD n | (n < 0) = 0
     | otherwise = fC n + fD (n-50)

fE n | (n < 0) = 0
     | otherwise = fD n + fE (n-100)

fF n | (n < 0) = 0
     | otherwise = fE n + fF (n-500)

これらの定義を書いてGHCiで:l 1000yen.hs してやってから fF 1000 を計算させると248908という答えが得られます.

したがって,一円玉,五円玉,十円玉,五十円玉,百円玉,五百円玉を自由に(好きなだけ)使って千円を両替する方法は全部で248908通りあることになります.

この問題はポリア他『組合せ論入門』p.11(近代科学社)で扱われている問題を改変したものです.(元の問題は1ドルを1セント,5セント,10セント,25セント,50セントで崩す問題です.)この問題はポリアのお気に入りだったのか,Pólya & Szegö “Problems and Theorems in Analysis I” にも収録されています.)

この記事では漸化式を組み合わせ論的な考えで導きましたが,ポリアの本では母関数を利用して漸化式を導いています.興味のある方は是非ポリアの『組合せ論入門』を読んでみてください.

無限小を用いた記述を標準的な記述に還元することについて

これはMath Advent Calendar 2017の12/8の記事です: mathAdventCalendar2017  (←リンク先PDF)

改訂情報

  • 2017/12/09: 式(24), 式(26)の脱字と誤字を訂正しました.(@waidotto 様,ありがとうございました.)
  • 2017/12/20: ISTの公理図式などの記述において,「FV」のような用語を使わないようにしました.

 

cos(x)+sin(x√2)の「周期っぽい長さ」を作る方法

{f(x) := \cos(x)+\sin(\sqrt{2}x)}とすると,これは明らかに周期関数ではないが,「周期っぽい長さ」が存在する.ある{l_\varepsilon}{f(x)}の「{\varepsilon}精度で周期っぽい長さ」であるということを次の条件で定義しよう:

\displaystyle{\sup_{x\in\Bbb{R}}\lvert f(x) - f(x+l_\varepsilon) \rvert < \varepsilon.}

このような「周期っぽい長さ」を機械的に作ってみよう.{\cos(x)}は周期{2\pi}で,{\sin(\sqrt{2}x)}は周期{\sqrt{2}\pi}なので
{\cos(x+l_\varepsilon) \fallingdotseq \cos(x),}
{\sin(\sqrt{2}x + \sqrt{2}l_\varepsilon) \fallingdotseq \sin(\sqrt{2}x).}
であればよい.よって
{l_\varepsilon \fallingdotseq 0\enskip(\mod 2\pi),\enskip l_\varepsilon \fallingdotseq 0\enskip(\mod \sqrt{2}\pi).}
そこである{a,b\in\Bbb{Z}}があって
{l_\varepsilon \fallingdotseq 2a\pi \fallingdotseq \sqrt{2}b\pi}
となっていれば良いことになる.

補足:近似({\fallingdotseq})による「アバウトな」議論がうまく行く事は,{\cos(x)}{\sin(\sqrt{2}x)}{\Bbb{R}}上一様連続であることを使えばうまく説明できる.

このような整数{a,b}を上手く見つけるために{\Bbb{Z}[\sqrt{2}]}が積について閉じていることに注目する.また,{0 < \sqrt{2}-1 < 1}という不等式にも注目する.よく知られているように,絶対値が{1}より小さい数のべき乗はゼロに収束する.そこで例えば
{(\sqrt{2}-1)^{2n} = b_n - \sqrt{2}a_n}
としてやれば,{2a_n \fallingdotseq \sqrt{2}b_n}となるような整数{a_n,\,b_n}を作り出すことができるはずである.{(\sqrt{2}-1)^{2n}}の二項展開を利用して具体形を求めれば

\displaystyle{a_n = \sum_{k=1}^n \binom{2n}{2k-1}2^{k-1},}

\displaystyle{b_n = \sum_{k=1}^n \binom{2n}{2k} 2^k.}

となる.

C92:「簡約!?λカ娘(10)」が出ます

C92の一日目(2017/08/11(金))に、サークル「参照透明な海を守る会」から『簡約!? λカ娘 10』が出ます.場所は「東7た11b」です.

<簡約!? λカ娘 10> 内容紹介
第 1 章 モナドとひも @myuon_myon
第 2 章 矢澤にこ先輩と一緒にモナドモナド! @public_ai000ya
第 3 章 Coqダンジョン:底抜けの壺の夢 @master_q
第 4 章 IST(Internal Set Theory)入門(後編) @dif_engine
第 5 章 静的コード解析はいいぞ! @master_q
第 6 章 VeriFast チュートリアル(Bart Jacobs / 翻訳: @eldesh, @master_q)

第 4 章の『 IST(Internal Set Theory)入門(後編) 』が私の記事です.
前編から一年もあればさぞかしゆったりと充実した記事が書けるだろうと思っていましたが,調べる範囲を広げたり絞ったりして試行錯誤しているうちにわりと初歩的なところに内容がとどまった感じです.

表紙
去年に続いて表紙絵を描きました.Goのとき以来の両面表紙になりました.表が『けものフレンズ』のフルルの衣装を着たあずにゃんで,裏が『シンフォギア』の立花響のアームドギアをまとったイカ娘です.

イカ娘(10)表紙

【自分用メモ】ラテン語でiの上の点がなくて棒になってるやつ(伝われ)

■要約: \={\i}

■ラテン語なんかを(まったく知りませんが)latex の文書で引用しようとするとき,i の上の点が棒になってる文字が使いたくなりました.
最初は \={i} かと思ったのですがこれではiの上の点が消えてくれません.調べたら \={\i}を使えば良いようです.(終わり)

■参考:

% !TEX TS-program = platex
% !TEX encoding = UTF-8 Unicode
\documentclass{jsarticle}
\usepackage{verbatim}
\usepackage{minitoc}
\usepackage[utf8x]{inputenc}
\title{有限性について}
\date{}
\begin{document}
\maketitle
finite という言葉はラテン語の\textit{f\={\i}nis}から来てるそうです.
\end{document}