無駄と文化

実用的ブログ

八耐 in 東京 に参加してきました。

福岡で働いていた頃からの友人である 岩本くん(@grem_ito) に声を掛けてもらったので 八時間耐久作品制作会(仮) in 東京 に参加してきました。
ふり返りつつレポートしてみます。


会場

会場は株式会社ドリコムのカフェスペースです。地上17回!高い!広い!

f:id:todays_mitsui:20170830150610p:plain

参加者は全員で13名ほど。
エンジニアが多いですが、デザイナーやプランナーの方も参加していました。


題材を決める

名前の通り8時間で何か作るイベントなので、題材を決めなければいけません。

この題材決めが難しいんですよね。
「作るものは何でも良いし、一つのものが完成しなくてもいいし、作りかけの物の続きでもいい」と言われてはいるものの、やっぱり何か成果物を出したいという下心は湧いてくるんで。

最初は手製本で布張りのハードカバー本を作ろうかと思ってたんですが、ちょっと 作業すぎる かなと思ってやめました。


結局、昨年作った Lazy_K のトランスレーターを引っ張り出して、

qiita.com

これをベースにλ式とコンビネータのステップ簡約ができるインタプリタを作ることにしました。


成果物

というわけで、いきなり完成品をお見せします。
イベント中にコミットしたところまでのリアルな状態で GitHub に公開しています。

github.com

デモ

SKI-Mogul というツールを作りました。
gif をご覧ください。

f:id:todays_mitsui:20170830232523g:plain


何をするものなのか

Lazy_K または Unlambda 初学者に捧げるコンビネータインタプリタです。

Lazy_K にしても Unlambda にしても、一般的な実行環境ではコードを実行してみても標準出力しか表示してくれない事が往々にしてあります。
しかし初学者にとっては、標準出力を見せられるよりもλ式が簡約されていく様をステップ毎に見られる方がプログラムの動作を理解する助けになると思うのです。

というか、私の場合がそうでした。
λ式の簡約に慣れるために、紙の上で手書きで運算しながら簡約のステップを追ったものです。

f:id:todays_mitsui:20170830150617p:plain

※写真は Image です

今回作った SKI-Mogul はλ式が簡約されていく様をステップ毎に表示してくれます。
Lazy_K や Unlambda の初学者は、ぜひ手元でλ式の変化を確かめながら学びを深めてください。


今後の展望

本当は今回のツールをもとに API を作って → UI を作って → web アプリにしたかったんですが、全く時間が足りませんでしたね。


発表

てな感じの事をもっと手短に、もっと雑に発表してきました。 理解されなくてもいい、少しでも風を感じてもらえればそれでいい、そんな事を思いながら。

f:id:todays_mitsui:20170830150549p:plain

まぁちょいちょい笑いも起こりつつ、周囲のみなさんにも少しは楽しんでいただけたようなのでオッケィです。


他の方の発表も楽しく拝見しました。

f:id:todays_mitsui:20170830150604p:plain

絵を描いたり、IoT をやったり、暗号化技術をモチーフにしたカードゲームのルールブックを作ったり、本当にテーマにも技術にも制限がない懐の深いイベントでした。

次回は10月7日8日に行われる 大八耐 で、2日がかりの大きいイベントになるそうです。
テーマは自由だし、部分参加も可能だそうなので参加してみてはいかがでしょうか。


私からは以上です。

Python3 で言語処理100本ノック 2015 - 第3章

乾・岡崎研究室が公開している 言語処理100本ノック 2015 に取り組んで行きます。
使用する言語は Python3 です。

第3章です。一部の方が大好きな 正規表現 の章です。
私は…、あんまり好きじゃないですね。


第3章: 正規表現

Wikipediaの記事を以下のフォーマットで書き出したファイルjawiki-country.json.gzがある.

  • 1行に1記事の情報がJSON形式で格納される
  • 各行には記事名が"title"キーに,記事本文が"text"キーの辞書オブジェクトに格納され,そのオブジェクトがJSON形式で書き出される
  • ファイル全体はgzipで圧縮される

以下の処理を行うプログラムを作成せよ.


20. JSONデータの読み込み

Wikipedia記事のJSONファイルを読み込み,「イギリス」に関する記事本文を表示せよ.
問題21-29では,ここで抽出した記事本文に対して実行せよ.

import codecs
import json


for row in codecs.open("./src/jawiki-country.json", "r", "utf-8"):
    article = json.loads(row)
    if u"イギリス" == article["title"]:
        print(article["text"])
# =>
# {{redirect|UK}}
# {{基礎情報 国
# |略名 = イギリス
# |日本語国名 = グレートブリテン及び北アイルランド連合王国
# ...
# [[Category:島国|くれいとふりてん]]
# [[Category:1801年に設立された州・地域]]

Python3 で UTF-8 エンコードの JSON をうまく読み込むために codecs モジュールを使っています。
読み込んだ各行が JSON 形式になっているようなので(いわゆる JSON Lines 形式 ですね)、1行ずつ処理して json.loads() で JSON をパースします。


21. カテゴリ名を含む行を抽出

記事中でカテゴリ名を宣言している行を抽出せよ.

import codecs
import json
import re


def extract_text(title):
    for row in codecs.open("./src/jawiki-country.json", "r", "utf-8"):
        article = json.loads(row)
        if title == article["title"]:
            return article["text"]


text = extract_text(u"イギリス")
for line in text.split("\n"):
    if re.search(r"Category:", line):
        print(line)
# =>
# [[Category:イギリス|*]]
# [[Category:英連邦王国|*]]
# [[Category:G8加盟国]]
# [[Category:欧州連合加盟国]]
# [[Category:海洋国家]]
# [[Category:君主国]]
# [[Category:島国|くれいとふりてん]]
# [[Category:1801年に設立された州・地域]]

今後、「ファイルからタイトルが『イギリス』の記事を取り出す」という処理は頻繁に登場するので extract_text() という関数にまとめました。

JSON のパースまで終わったら各行毎に処理して "Category:" というテキストを含む行だけを抽出します。
このあたりはまだ正規表現を持ち出すまでもない処理ですね。


22. カテゴリ名の抽出

記事のカテゴリ名を(行単位ではなく名前で)抽出せよ.

import codecs
import json
import re


def extract_text(title):
    for row in codecs.open("./src/jawiki-country.json", "r", "utf-8"):
        article = json.loads(row)
        if title == article["title"]:
            return article["text"]


text = extract_text(u"イギリス")
for line in text.split("\n"):
    m = re.search(r"Category:(?P<category>.+?)(\||])", line)
    if m:
        print(m.group("category"))
# =>
# イギリス
# 英連邦王国
# G8加盟国
# 欧州連合加盟国
# 海洋国家
# 君主国
# 島国
# 1801年に設立された州・地域

正規表現の キャプチャ を使います。
個人的に 名前付きキャプチャ が大好きです。正規表現は書けるけど読めないという地獄のようなものでっすが、名前付きキャプチャを使う事でいくらか可読性を向上させることができます。


23. セクション構造

記事中に含まれるセクション名とそのレベル(例えば"== セクション名 ==“なら1)を表示せよ.

ここから先はまず MediaWiki のマークアップ記法 について知っておいたほうがよさそうです。

セクション名は == セクション名 == のようにマークアップされます。先頭と末尾の == は Level1(==) から Level5(======) まであります。
Level0(=) も許容されるけどページのタイトルをマークアップするのに使うから本文中では使わないようにという注釈がどこかにあったような。

ともかく連続する = によって行頭と行末が囲まれている行を抽出して = の数を数えれば良さそうです。

import codecs
import json
import re


def extract_text(title):
    for row in codecs.open("./src/jawiki-country.json", "r", "utf-8"):
        article = json.loads(row)
        if title == article["title"]:
            return article["text"]


text = extract_text(u"イギリス")
for line in text.split("\n"):
    m = re.search(r"^(?P<level>=+)(?P<header>.+)\1$", line)
    if m:
        header = m.group("header")
        level = m.group("level").count("=") - 1

        print("{0}: {1}".format(level, header))
# =>
# 1: 国名
# 1: 歴史
# 1: 地理
# 2: 気候
# ...
# 1: 外部リンク

セクション名をキャプチャしている正規表現に着目してください。

^(?P<level>=+)(?P<header>.+)\1$

行頭の = と行末の = が対になっていることを確認するために 後方参照 を使っています。
行が == から始まったときは == で終わらなければマッチしませんし、 ===== から始まったときは ===== で終わらなければマッチしないという具合です。

後方参照は可読性が低くなりがちなのでなるべく使いたくなかったのですが、セクション名に = を含む場合を許容したかったことと、始まりの = の数と終わりの = の数が不一致になる場合を弾きたかったので使いました。


24. ファイル参照の抽出

記事から参照されているメディアファイルをすべて抜き出せ.

記事中に埋め込まれたメディアファイルは [[ファイル:Wiki.png|thumb|説明文]] というような形をしているそうです。

import codecs
import json
import re


def extract_text(title):
    for row in codecs.open("./src/jawiki-country.json", "r", "utf-8"):
        article = json.loads(row)
        if title == article["title"]:
            return article["text"]


text = extract_text(u"イギリス")
for line in text.split("\n"):
    m = re.search("ファイル:(?P<filename>[^|]+)\|", line)
    if m:
        print(m.group("filename"))
# =>
# Royal Coat of Arms of the United Kingdom.svg
# CHANDOS3.jpg
# The Fabs.JPG
# PalaceOfWestminsterAtNight.jpg
# ...
# Wembley Stadium, illuminated.jpg

やるだけですね。


25. テンプレートの抽出

記事中に含まれる「基礎情報」テンプレートのフィールド名と値を抽出し,辞書オブジェクトとして格納せよ.

生の「基礎情報」は以下のような形式になっています。

{{基礎情報 国
|略名 = イギリス
|日本語国名 = グレートブリテン及び北アイルランド連合王国
|公式国名 = {{lang|en|United Kingdom of Great Britain and Northern Ireland}}<ref>英語以外での正式国名:<br/>
*{{lang|gd|An Rìoghachd Aonaichte na Breatainn Mhòr agus Eirinn mu Thuath}}([[スコットランド・ゲール語]])<br/>
*{{lang|cy|Teyrnas Gyfunol Prydain Fawr a Gogledd Iwerddon}}([[ウェールズ語]])<br/>
*{{lang|ga|Ríocht Aontaithe na Breataine Móire agus Tuaisceart na hÉireann}}([[アイルランド語]])<br/>
*{{lang|kw|An Rywvaneth Unys a Vreten Veur hag Iwerdhon Glédh}}([[コーンウォール語]])<br/>
*{{lang|sco|Unitit Kinrick o Great Breetain an Northren Ireland}}([[スコットランド語]])<br/>
**{{lang|sco|Claught Kängrick o Docht Brätain an Norlin Airlann}}、{{lang|sco|Unitet Kängdom o Great Brittain an Norlin Airlann}}(アルスター・スコットランド語)</ref>
|国旗画像 = Flag of the United Kingdom.svg
|国章画像 = [[ファイル:Royal Coat of Arms of the United Kingdom.svg|85px|イギリスの国章]]
|国章リンク = ([[イギリスの国章|国章]])
...
|国際電話番号 = 44
|注記 = <references />
}}

一見、 | 区切りで key = value が並んでいるように見えますが、区切り文字の | が value の中にエスケープ無しで現れるのが曲者です。
ちょっと考えて、 \n| を区切り文字と見なして split() することにしてみました。

import codecs
import json
import re
from pprint import pprint


def extract_text(title):
    for row in codecs.open("./src/jawiki-country.json", "r", "utf-8"):
        article = json.loads(row)
        if title == article["title"]:
            return article["text"]

def extract_base_info(text):
    m = re.search("{{基礎情報[^|]+\|(?P<info_body>.+?)\n}}", text, re.DOTALL)
    if not m:
        return {}

    info_body = m.group("info_body")

    info_dict = {}

    for item in info_body.split("\n|"):
        key, val = re.split(r"\s+=\s+", item, maxsplit=1)
        info_dict[key] = val

    return info_dict

text = extract_text(u"イギリス")
base_info = extract_base_info(text)

pprint(base_info, indent=4)
# =>
# {
#     '公式国名': '{{lang|en|United Kingdom of Great Britain and Northern Ireland}}<ref>英語以外での...コットランド語)</ref>',
#     '国旗画像': 'Flag of the United Kingdom.svg',
#     '日本語国名': 'グレー トブリテン及び北アイルランド連合王国',
#     '国章リンク': '([[イギリスの国章|国章]])',
#     ...
#     '首都': '[[ロンドン]]'
# }

最終的に dict に格納してあげます。


26. 強調マークアップの除去

25の処理時に,テンプレートの値からMediaWikiの強調マークアップ(弱い強調,強調,強い強調のすべて)を除去してテキストに変換せよ
(参考: マークアップ早見表).

前節で作った dict に加工を加えます。
強調マークアップは ''他との区別'', '''強調''', '''''斜体と強調''''' のいずれかです。ここでは単純に2回以上連続する ' を除去すれば充分でしょう。

import codecs
import json
import re
from pprint import pprint


def extract_text(title):
    for row in codecs.open("./src/jawiki-country.json", "r", "utf-8"):
        article = json.loads(row)
        if title == article["title"]:
            return article["text"]

def extract_base_info(text):
    m = re.search("{{基礎情報[^|]+\|(?P<info_body>.+?)\n}}", text, re.DOTALL)
    if not m:
        return {}

    info_body = m.group("info_body")

    info_dict = {}

    for item in info_body.split("\n|"):
        key, val = re.split(r"\s*=\s*", item, maxsplit=1)
        info_dict[key] = val

    return info_dict

def remove_emphasis(text):
    """強調マークアップを除去"""
    return re.sub(r"'{2,}", "", text)

text = extract_text(u"イギリス")
base_info = extract_base_info(text)


sanitized_base_info = {}
for k, v in base_info.items():
    v = remove_emphasis(v)
    sanitized_base_info[k] = v


pprint(sanitized_base_info, indent=4)

「基礎情報」を抜き出して dict 型に変換する処理を extract_base_info() にまとめました。

強調マークアップの除去は re.sub() を用いて正規表現にマッチする部分を空文字列 "" に置換することで処理しています。
'{2,} と書くことで2回以上連続する ' にのみマッチさせることができます。


27. 内部リンクの除去

26の処理に加えて,テンプレートの値からMediaWikiの内部リンクマークアップを除去し,テキストに変換せよ(参考: マークアップ早見表).

先ほどに引き続き。
内部リンクは [[記事名]], [[記事名|表示文字]], [[記事名#節名|表示文字]] のいずれかの形をしています。

import codecs
import json
import re
from pprint import pprint


def extract_text(title):
    for row in codecs.open("./src/jawiki-country.json", "r", "utf-8"):
        article = json.loads(row)
        if title == article["title"]:
            return article["text"]

def extract_base_info(text):
    m = re.search("{{基礎情報[^|]+\|(?P<info_body>.+?)\n}}", text, re.DOTALL)
    if not m:
        return {}

    info_body = m.group("info_body")

    info_dict = {}

    for item in info_body.split("\n|"):
        words = re.split(r"\s+=\s+", item, maxsplit=1)
        info_dict[words[0]] = words[1]

    return info_dict

def remove_emphasis(text):
    """強調マークアップを除去"""
    return re.sub(r"'{2,}", "", text)

def remove_internal_links(text):
    """内部リンクのマークアップを除去"""
    return re.sub(r"\[\[([^]]+)\]\]", lambda m: m.group(1).split("|")[-1], text)


text = extract_text(u"イギリス")
base_info = extract_base_info(text)

sanitized_base_info = {}
for k, v in base_info.items():
    v = remove_emphasis(v)
    v = remove_internal_links(v)
    sanitized_base_info[k] = v


pprint(sanitized_base_info, indent=4)

さきほどと同様に re.sub()で。
置換処理に無名関数を使用しています。| を区切り文字としてリストに分解して末尾の要素を取り出していますが…、これはちょっと魔術的かも知れませんね。半年後とかに読み返したとき後悔しそう。


28. MediaWikiマークアップの除去

27の処理に加えて,テンプレートの値からMediaWikiマークアップを可能な限り除去し,国の基本情報を整形せよ.

やるだけです!

import codecs
import json
import re
from pprint import pprint


def extract_text(title):
    for row in codecs.open("./src/jawiki-country.json", "r", "utf-8"):
        article = json.loads(row)
        if title == article["title"]:
            return article["text"]

def extract_base_info(text):
    m = re.search("{{基礎情報[^|]+\|(?P<info_body>.+?)\n}}", text, re.DOTALL)
    if not m:
        return {}

    info_body = m.group("info_body")

    info_dict = {}

    for item in info_body.split("\n|"):
        [key, word] = re.split(r"\s+=\s+", item, maxsplit=1)

        word = remove_section_header(word)
        word = remove_emphasis(word)
        word = remove_category_links(word)
        word = remove_internal_links(word)
        word = remove_external_links(word)
        word = remove_template(word)
        word = remove_unordered_list(word)
        word = remove_define_list(word)
        word = remove_redirect(word)
        word = remove_comment(word)

        info_dict[key] = word

    return info_dict

def remove_section_header(text):
    """見出しのマークアップを除去"""
    return re.sub(r"(=+)(.+?)\1", lambda m: m.group(2), text)

def remove_emphasis(text):
    """強調マークアップを除去"""
    return re.sub(r"'{2,}", "", text)

def remove_category_links(text):
    """カテゴリリンクのマークアップを除去"""
    return re.sub(r"\[\[Category:(.+?)\]\]", lambda m: m.group(1).split("|")[0], text)

def remove_internal_links(text):
    """内部リンクのマークアップを除去"""
    return re.sub(r"\[\[([^]]+)\]\]", lambda m: m.group(1).split("|")[-1], text)

def remove_external_links(text):
    """外部リンクのマークアップを除去"""
    return re.sub(r"\[([^]]+)\]", lambda m: m.group(1).split(" ")[-1], text)

def remove_template(text):
    """スタブのマークアップを除去"""
    return re.sub(r"\{\{(.+?)\}\}", lambda m: m.group(1).split("|")[-1], text)

def remove_unordered_list(text):
    """箇条書きのマークアップを除去"""
    return re.sub(r"^\*+\s*", "", text, flags=re.MULTILINE)

def remove_ordered_list(text):
    """番号付箇条書きのマークアップを除去"""
    return re.sub(r"^#+\s*", "", text, flags=re.MULTILINE)

def remove_define_list(text):
    """定義の箇条書きのマークアップを除去"""
    return re.sub(r"^(:|;)\s*", "", text, flags=re.MULTILINE)

def remove_redirect(text):
    """リダイレクトのマークアップを除去"""
    return re.sub(r"#REDIRECT \[\[(.+?)\]\]", lambda m: m.group(1), text)

def remove_comment(text):
    """コメントアウトのマークアップを除去"""
    return re.sub(r"<!--.*?-->", "", text)


text = extract_text(u"イギリス")
base_info = extract_base_info(text)

pprint(base_info, indent=4)

やるだけ!


29. 国旗画像のURLを取得する

テンプレートの内容を利用し,国旗画像のURLを取得せよ.
(ヒント: MediaWiki APIのimageinfoを呼び出して,ファイル参照をURLに変換すればよい)

import codecs
import json
import re
from pprint import pprint


def extract_text(title):
    for row in codecs.open("./src/jawiki-country.json", "r", "utf-8"):
        article = json.loads(row)
        if title == article["title"]:
            return article["text"]

def extract_base_info(text):
    m = re.search("{{基礎情報[^|]+\|(?P<info_body>.+?)\n}}", text, re.DOTALL)
    if not m:
        return {}

    info_body = m.group("info_body")

    info_dict = {}

    for item in info_body.split("\n|"):
        [key, word] = re.split(r"\s+=\s+", item, maxsplit=1)

        word = remove_section_header(word)
        word = remove_emphasis(word)
        word = remove_category_links(word)
        word = remove_internal_links(word)
        word = remove_external_links(word)
        word = remove_template(word)
        word = remove_unordered_list(word)
        word = remove_define_list(word)
        word = remove_redirect(word)
        word = remove_comment(word)

        info_dict[key] = word

    return info_dict

def remove_section_header(text):
    """見出しのマークアップを除去"""
    return re.sub(r"(=+)(.+?)\1", lambda m: m.group(2), text)

def remove_emphasis(text):
    """強調マークアップを除去"""
    return re.sub(r"'{2,}", "", text)

def remove_category_links(text):
    """カテゴリリンクのマークアップを除去"""
    return re.sub(r"\[\[Category:(.+?)\]\]", lambda m: m.group(1).split("|")[0], text)

def remove_internal_links(text):
    """内部リンクのマークアップを除去"""
    return re.sub(r"\[\[([^]]+)\]\]", lambda m: m.group(1).split("|")[-1], text)

def remove_external_links(text):
    """外部リンクのマークアップを除去"""
    return re.sub(r"\[([^]]+)\]", lambda m: m.group(1).split(" ")[-1], text)

def remove_template(text):
    """スタブのマークアップを除去"""
    return re.sub(r"\{\{(.+?)\}\}", lambda m: m.group(1).split("|")[-1], text)

def remove_unordered_list(text):
    """箇条書きのマークアップを除去"""
    return re.sub(r"^\*+\s*", "", text, flags=re.MULTILINE)

def remove_ordered_list(text):
    """番号付箇条書きのマークアップを除去"""
    return re.sub(r"^#+\s*", "", text, flags=re.MULTILINE)

def remove_define_list(text):
    """定義の箇条書きのマークアップを除去"""
    return re.sub(r"^(:|;)\s*", "", text, flags=re.MULTILINE)

def remove_redirect(text):
    """リダイレクトのマークアップを除去"""
    return re.sub(r"#REDIRECT \[\[(.+?)\]\]", lambda m: m.group(1), text)

def remove_comment(text):
    """コメントアウトのマークアップを除去"""
    return re.sub(r"<!--.*?-->", "", text)


text = extract_text(u"イギリス")
base_info = extract_base_info(text)


from urllib.parse import urlencode
from urllib import request

flag_image_name = base_info["国旗画像"]
query = urlencode({
    "action": "query",
    "titles": "File:{0}".format(flag_image_name),
    "prop": "imageinfo",
    "iiprop": "url",
    "format": "json",
})
url = "https://commons.wikimedia.org/w/api.php?{0}".format(query)

with request.urlopen(url) as response:
    body = response.read()
    data = json.loads(body.decode("utf-8"))

    pprint(data, indent=4)
    # =>
    # {
    #     'continue': {'continue': '||', 'iistart': '2007-09-03T09:51:34Z'},
    #     'query': {
    #         'pages': {
    #             '347935': {
    #                 'imageinfo': [{
    #                     'descriptionshorturl': 'https://commons.wikimedia.org/w/index.php?curid=347935',
    #                     'descriptionurl': 'https://commons.wikimedia.org/wiki/File:Flag_of_the_United_Kingdom.svg',
    #                     'url': 'https://upload.wikimedia.org/wikipedia/commons/a/ae/Flag_of_the_United_Kingdom.svg'
    #                 }],
    #                 'imagerepository': 'local',
    #                 'ns': 6,
    #                 'pageid': 347935,
    #                 'title': 'File:Flag of the United ''Kingdom.svg'
    #             }
    #         }
    #     }
    # }

    flag_image_url = list(data["query"]["pages"].values())[0]["imageinfo"][0]["url"]

    print(flag_image_url)
    # => https://upload.wikimedia.org/wikipedia/commons/a/ae/Flag_of_the_United_Kingdom.svg

ヒントの通りにやってます。

MediaWiki API という API があるようです。
エンドポイントは https://commons.wikimedia.org/w/api.php

URI のクエリ部分に action=queryprop=imageinfo を与えることで画像情報の問い合わせができます。
format=json を指定することでレスポンスが JSON 形式になり、iiprop=url を指定することでレスポンスに画像の URL を含めてくれるようになるので、レスポンスを JSON パースして国旗画像の URL を取得できます。

レスポンスのパース後のデータの取り出し部分がひたすら汚いことについては目を瞑ってください。


所感

正規表現あんまり好きじゃないんでひたすらツラかったです。

じゃあ、何ならツラくないのかというと 関数型パーサ ですね。


私からは以上です。


コード全部まとめ

回答 - 言語処理100本ノック 2015 - 第3章 · GitHub


その他の章の回答はこちらから

blog.mudatobunka.org

数学を教わってみて思うこと ~ ベイズ統計学入門レポート

先月から すうがくぶんかのベイズ統計学入門 に通っています。
もちろん無料講座とかではなく月謝が掛かるタイプのもので、自腹でお金を出してます。
(向上心があって素晴らしいと評価してくれる方は今度会ったときにコーヒーでも奢ってください。学びをフィードバックしますんで)

まだ2回しか受講していないけれど、きっかけや気づきなどを書き留めておこうと思います。


講座の内容

主題は文字通り「ベイズ統計学」です。 ベイズ統計学の考え方を元にモデルを組み立ててパラメーターを推定できるようになるのが目的、だと思います。
そのためのツールとして MCMC(マルコフ連鎖モンテカルロ法) についての解説が入っていくと思われます。

1回の授業は2時間で、レジュメを見ながらの座学で理論を学ぶ時間と実際のデータをいじりながら実践で学ぶ時間があります。
実践パートでは R言語 と Stan を使います。


なぜベイズ統計学か?

包み隠さずに正直に書くと、数学関係の講座を受講することが目的で 何の講座か という部分はまぁ、ある意味何でもよかったのでフィーリングで決めました。
まず すうがくぶんか という会社が社会人向けの講座をやっていることを知り、そのカリキュラムの中から現在でいちばん関心のあったベイズ統計学を選んだという流れですね。

とは言え一応の狙いはあって、いま流行りの 機械学習 分野に自分の歩みを進めたいという思いがありました。
どちらかというと応用よりも基礎理論が好きな自分にとって、既存のフレームワークを触ることでは入門していけず、理論を教えてもらえる講座を探していました。


それともう一つ、
久しぶりに 人に教わる という体験をしたいと言うのもありましたね。
自分にとって、教わること独学 とどちらが効率がいいのか、ここらでテストしてみたいという事も思っていました。


授業を経て思うこと

そんなわけで、2回ほど授業を受けての感想です。

暗黙知を垣間見る

授業を受けての一番のメリットは、講師が暗黙に知っていることを 雰囲気で 感じられることです。

例えば、書籍などでは「代表的な方法は A, B, C の3種類がある」と形式的に書かれている事でも、講師が読み上げるときに「とはいえ、実際には C だけ押さえられとけば事足りますけどね」などと付け足すわけです。
この付け足しの一言みたいなものがものすごく貴重で、実は情報量の多い発言だなと感じます。書籍ほどに整理されていない形式だからこそ枝葉末節に多くの情報を持たせることができるのでしょうね。


それに加えて、こちらから積極的に質問できるのもポイントです。
これまで2回の授業とも、講師が「A は B ですので~」と言ったのに対して『それは 意図的に B にする というニュアンスですか?それとも B になってしまう という意味でしょうか?』と質問しました。
このようにニュアンスを聞き出せるのも対面での授業ならではだと感じます。


関心の範囲が広がり、有意注意が鍛えられる

授業を受けると、スッと理解できる部分もある一方で、なかなか呑み込めない部分もあります。
かるく導入だけされた後で「この部分は後半で詳しくやります」とか言われるとなおさらですね。

そういった、自分の中に飛び込んではきたけれど消化できていないキーワードを持っておくことで、日常生活の中でもそれらに関連した物事が目に入りやすくなります。
ベイジアンフィルタや MCMC というワード、それらが実際に応用されている事例などがハッと目に飛び込んできます。
『ああ、俺がいままさに学んでいるやつだな』という気持ちで身の回りの物事に気づきやすくなるわけです。


誰だって、普段から身の回りで接していても見逃しているものが多くあります。
そういうものをしっかりとキャッチしていくには、やはり意図的に 注意 を向けるしかないわけで、新しい物事を学ぶのはそういった 有意注意 を促してくれるものなんだなと感じます。


自分の背中を押す強制力

時間と枠が決められた 授業 というものを中心に据えて学習が進んでいくスタイルはやはり心地よい強制力があります。
授業中は集中して理解に努めますし、次回の授業までに用意しておくべきことや予習しておくべきことはケツをたたかれている気分できっちりと進められます。

社会に出てからというものもっぱら独学でまなんできた自分にとって、目的・期限が決められて強制的に学習が進んでいく環境は刺激的で、学習を加速させるいい要素だと感じています。


「人に教わる」ということ

最後に、人に教わりながらあらためて「人に教える」ことについても考えています。
専門領域においてほとんど独学で知識を獲得してきたために、職場では教わるよりも教える割合が多くなっています。

人を教えるというのは難しいもので、すぐに『教えるより自分がやったほうが早い』というダメな思考に取りつかれます。
今回気づいたのは、人を教える自分自身が「教わる」という体験をしばらくしていなかったことです。
今回あらためて教わる側にまわることで、今後人を教えるためににも多くの学びがあると期待しています。


私からは以上です。