FrontPage / Learning Programming
概要 †
- Unix環境でのプログラミング方法,研究室の実験環境を学ぶ
- 自然言語処理で頻繁に使われる処理を題材としてプログラミング演習を行うことで,スムースに研究に取り組める力を養います
内容 †
- 言語処理100本ノック 2015
- 自然言語処理に関するプログラムを実際に作ってもらい,互いにコードレビューを行います。
- 問題に対する答えは一つではありません。どんな方法でも,無理矢理でも解いてみてください。
- ほか「研究に伴うプログラミング/実装」の周辺知識
2018年度 †
- 日時
- TBA
- 参加者
- 大竹、今野、佐藤(志)、佐藤(拓)、藤井、北山
- 書いたコード
- https://github.com/cl-tohoku/100knock-2018
TA †
研究室の実験環境など †
- 🔒内部資料 (2016年版)
Pythonプログラミングのチュートリアル †
100本ノックコーチ割り当て †
場所 | 担当者 |
第1章: 準備運動 | 清野 |
第2章: UNIXコマンドの基礎 | 横井 |
第3章: 正規表現 | 阿部,白井 |
第4章: 形態素解析 | 伊藤,田上 |
第5章: 係り受け解析 | 浅野,高橋 |
第6章: 英語テキストの処理 | 栗林 |
第7章: データベース | 佐々木 |
第8章: 機械学習 | 鈴木,赤間 |
第9章: ベクトル空間法 (I) | 塙 |
第10章: ベクトル空間法 (II) | 吉成,中村 |
代打 | 水本,横井,松林,O |
このページの記録 †
- やったことだけ書く
- 以前の記録と同じことを書いても良い
- 何度も書かれているということは,それだけ重要だということを意味する
予定・記録 †
- 2/13(水)
- with_iter
- with を iterable でwrapしたもの
- https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.with_iter
- コードゴルフ
- どれだけ短く書けるかを競う
- コードゴルフをやるサイトの例 http://golf.shinh.org/
- (90)
- Mikolovの実装(Skip-gram,CBOW)
- (91)
- 解き方が色々ある
- groupby
- split_before
- pcregrep
- 複数行のgrep
- takewhile,dropwhileの組み合わせ
- (93)
- sklearn.metrics.accuracy_score でも正解率が計算できる
- with_iter
- 1/30(水)
- Counter.most_common()で出現回数でソートしたリストが返る
- 疎行列データ
- https://docs.scipy.org/doc/scipy/reference/sparse.html
- scipy.sparse.[coo, lil, dok]_matrix : 1つづつ要素を入力するのに便利、算術演算は不可or遅い
- scipy.sparse.[csc, csr]_matrix : 算術演算は早い、要素挿入などは遅い
- 12/18(火)
- (80)
- ファイルに保存するときは行ごとに処理をしておいた方が良い
- 文をまたいで複合語を作ってしまう可能性も0ではないため
- 全ての文をメモリに保持しないよう,逐一ファイルに書き込む
- (81)
- 国名が取れる pycountry というものもある
- 使用する国名リストによっては,ある国名が他の国名の部分文字列になっているケースがあり得る
- United States と United States Virgin Island
- replace するアプローチと,単語を一つずつ見ていくアプローチがあった
- (82)
- random.randintとnumpy.random.randintで仕様が違う
- random.randint(1, 5)は 1-5 が返る
- numpy.random.randint(1, 5) は 1-4 が返る
- 以下の書き方でwithのネストを減らせる
- with open('hoge') as f1, open('foo') as f2 :
- (83)
- defaultdict(int)に+=1するほうがcounterへのupdateより速い?
- メモリを節約するための工夫の一つ
- 82のファイルを単語でソート
- ソートするときにはファイルを分割してマージソート
- 12/4(火)
- (75-79)
- 関数アノテーション
- pycharm等のIDEでは関数アノテーションに基づいたエラーを吐いてくれる
- 関数名 (引数名 : 引数の型=default) -> returnの型:
- ex)def get_hoge(x:str, y:int=3)->str:
- マシューズ相関係数
- 正解ラベルが正が多数の場合はF1ではなく、マシューズ相関係数で評価した方が良い
- https://blog.datarobot.com/jp/matthews-correlation-coefficient
- scikit-learn
- LogisticRegression
- CountVectorizer
- metrics
- train_test_split
- cross_validate
- precision_recall_curve
- 11/27(火)
- (70-74)
- nkfのエンコード変換はオプションの設定次第で1行消えることがあるらしい
- iconvの方が簡単
- nkfでもオプション指定すればできるかも…?
- stop words の数
- nltk 318
- sklearn 179
- pytest
- test〜.pyの test〜という名前の関数を全部実行してくれるモジュール
- 11/13(火)
- (清野)実験のやり方 🔒slide (PDF)
- 資料外の関連情報を中心に
- p6. 積極的にassertionを使おう
- 行列のshapeの確認にも使える
- p6. プログラミング用のフォントを使おう(lと1の区別)
- p9. サーバですべて書く& github にこまめにcommit派もいる
- p12. SSH configによるサーバ名の省略
- p14. pyenvのインストール
- p16 実験ログを残そう
- Chainer使いのためのtensorboard的なもの
- chainerui
- https://github.com/chainer/chainerui
- 11/06(火)
- (69)
- フロントエンド周りのまとめ:🔒https://io-lab.esa.io/posts/1828
- 各自のWebアプリの紹介
- Webフレームワーク:Flask, Bottle, Django
- CSSフレームワーク:Bootstrap
- 10/30(火)
- (64-68)
- インデックスの作成 collection.create_index
- 検索が早くなる
- 挿入が遅くなる
- MongoDBのClientは、hostとportを指定する方法とURIで指定する方法がある
- Connection String URI Format:https://docs.mongodb.com/manual/reference/connection-string/
- 重複させたくない場合は insert 時にunique_idで存在をチェックする
- インタラクティブコマンド実行時は %%bash を先頭に書く
- db.collection.distinct(field, query)
- fieldに指定した列が一致するエントリの重複を省いてqueryの条件で検索
- mongoDBはcase-sensitive(DB的には普通)
- 10/23(火)
- (60-63)
- 1行単位がjsonになっているファイルは読み込む時にstrip()推奨
- ifconfigコマンド, topコマンド, killコマンド
- more_itertools.ilen(iterable)
- iteratorの長さが分かる(iteratorは消費される)
- https://more-itertools.readthedocs.io/en/latest/api.html
- pickleはデータ(parse結果など)を保存したいときによく使う
- Redis強い
- pipeline, valueの型, 揮発性
- Pelican
- Markdownがhtml、cssに!
- 10/16(火)
- (57-59)
- 57
- グラフ化する際は表層形の重複を防ぐ工夫が必要
- 依存構造は係り元から係り先への向きにする流儀と逆にする流儀がある
- 59
- 再帰構造は停止/再帰部分をコメント書くなどして明示しておくと見やすい
- S式のParserもある
- https://www.nltk.org/_modules/nltk/tokenize/sexpr.html(NLTK)
- http://inforno.net/articles/2008/09/19/sexp-library-for-python
- 10/09(火)
- (54-56)
- ElementTree
- Elementオブジェクトのchildにアクセスする場合、elem[i]とするよりもelem.find('word')のようにした方が可読性が良い
- findallはリストに一度格納するので(メモリ消費量が)怖い
- XPathで .//tag で指定する場合、すべての子要素から選択されるため、想定外のタグの重複に注意
- POS-taggingなどの前処理の方法は記録して統一したほうがいい(複数人で共同で作業する場合は特に)
- POS taggingに関しては、Standard Core NLPとspaCyで nlp.txt の解析結果が異なる箇所が15%位あった
- (55) 固有表現抽出の注意点
- NERが連続してた場合につなげる
- 1)Alan / Turing → Alan Turing
- 2)Joseph / Weizenbaum → Joseph Weizenbaum
- (56) 共参照解析の注意点
- 参照の入れ子に注意
- ある参照表現の中に別の代表参照表現があるケースがある
- 例)sentence 41 代表参照表現 -> the advantage
- sentence 25 参照表現 -> advantage of existing multilingual textual...
- sentence 25 代表参照表現 -> existing multilingual textual...
- sentence 36 参照表現 -> `` corpora ''
- 10/02(火)
- (50-53)
- wget
- オプション -nc / --no-clobber で上書きしない設定にできる
- 正規表現
- 文区切りのスペースは一つとは限らないケースがあるので、\s よりも \s+ としておいた方が良い
- 正規表現のパターンはキャッシュされる。パターン数が少なければ re.compile(pattern) をした場合とre.match(pattern, string) で速度差はほとんどない
- ルールベースで文区切りをすると、以下の場合にe.g.と人名で区切られてしまったりするので気を付ける
- 例) e.g. 人名(大文字スタート)
- 文区切りするなら、NLTKやspaCyを使ったほうがいい
- stripは区切り文字を文字集合として捉える
- hohogege.rstrip('ge') の結果は hoho
- assertで自分の想定通りの動作になっているか確認
- if文
- できるだけ、not表現よりも==表現を使う
- if x != y vs. if not x == y であれば前者推奨(https://stackoverflow.com/questions/31026754/python-if-not-vs-if/)
- readlinesはメモリ消費が激しい
- ElementTreeのiterparse
- Standard Core NLPのオプション
- ssplit.eolonly:行末のみを文区切りと見なす
- もともと各行に1文が書かれているようなファイルに便利
- RISE
- JupyterでプレゼンができるCoolなTool
- http://codecrafthouse.jp/p/2017/05/jupyter-rise-live-presentation/
- 命名に悩んだとき
- 07/24(火)
- (49)
- itertoolsのpermutations, combinations, product
- 真偽値を返す関数の名前はis_〜、has_〜等、わかりやすいものにする
- 関数のデフォルト引数はimutableにすべし
- デフォルト引数をリストにしたいときは、一度Noneとしてから関数内でリストを作る
- 研究室の実験サーバの使い方
- 07/17(火)
- (46-48)
- Broke pipe error
- 標準出力をパイプでheadに渡すと、Broke pipeのエラーが出る
- エラーを消したいようであれば、sort 2>/dev/null | head 等とすることで、標準エラー出力を破棄できる
- あるインデックスの値でソートをしたい場合、以下のどちらでもできる
- sorted(hoge, key=lambda x: x[n])
- sorted(hoge, key=operator.itemgetter(n))
- list.sort()は破壊的、sorted(list)は非破壊的
- 関数化は重要。可読性に大きな影響が出る
- 文字列の初期化はNoneよりも空文字
- メモ化
- @lru_cache(maxsize=int, typed=Boolean)
- 上のデコレータを付けるだけで、関数のメモ化してくれる https://docs.python.jp/3/library/functools.html
- 同じ引数で関数が何回か呼び出されるようなケースの計算時間を減らすことができる
- LRU (least recently used) キャッシュ:最も使われていないデータから捨てられる。Memory Leak を防げる
- 07/10(火)
- (44-45)
- 依存構造木の矢印の向き
- 係り元から係り先への向き(係り受け構造と同じ方向)にする流儀と逆にする流儀がある
- pydot
- 表層系の重複を防ぐ工夫が必要
- 独自にユニークな番号を割り振る、Cabochaが文節に振るIDを使うなど
- 関数の引数やtuple定義などの括弧 (){}[]の内側では改行や空白は許容される
- 文字列の結合
- listにappendか内包表記してjoinする方が良いらしい (strはimmutable)
- pythonからの外部プロセス起動
- 外部プロセスを起動するときはsubprocessを使う
- 3.5以降は subprocess.run が追加されている
- 引数 check=True にするとエラー時に例外が発生する
- 引数 shell=True は非推奨(外部入力をそのまま指定した場合にコマンドインジェクションされる危険性があるため)
- X in Y の判定をする場合、Yにsetを使うと高速
- 辞書順
- 文字列のリストをソートすると文字コードに基づく辞書式順序になる
- 国語辞書の見出し順とは必ずしも一致しないことに注意
- 07/3(火)
- (41-43)
- groupby()が返すgroupのcopy
- わかりやすい命名
- なるべくメソッド化
- メンバ変数の取得・変更等
- for文・if文が深くなるのを回避
- re.split()
- 関数のキーワード引数
- __str__と__repr__
- if 条件式:
- "", [], 0, None
- A and BとA or Bの評価戦略
- Spacy
- 06/26(火)
- (40)
- クラスについて
- なぜ使うのか
- クラス変数、インスタンス変数、初期化、インスタンスメソッド
- メソッドの定義が不要なときはcollections.namedtupleを使っても良い
- has-a関係には「包含」を利用
- __slots__
- インスタンス変数を予め列挙して外から追加不能にする。メモリの節約になる。
- インスタンス変数が少量・固定で何度もインスタンス化をする時は利用して良いかも
- @classmethod
- __str__と__repr__
- ___str__はユーザ向け、__repr__は開発者向けの文字列を返すようにする
- __str__はprint()等、__repr__はrepr()等で呼び出される
- print([instance1, instance2])等とすると__repr__が呼び出されてしまう
- "プライベート"変数
- __spam (先頭に二個以上の下線文字、末尾に一個以下の下線文字) という形式で定義
- @propertyをつけてspamという名前のgetterを定義すると、self.spamは外から変更不能のままアクセス可能になる
- cytoolz.nth
- cytoolz.nth(3, iterable)
- itertools.islice(iterable, 3, 4)
- more_itertools.nth(iterable, 3)
- PEP8を守ろう
- キーワード引数や、デフォルトパラメータであることを示すために使う = の両側にスペースを入れてはいけません
- argparseは重要
- stringクラスには便利な文字列定数が定義されている
- Docstring
- fstring
- str.format()より簡単
- Python3.6の新機能なので、後方互換性注意
- 06/12(火)
- (35-39)
- 数え上げ方いろいろ
- Counter, defaultdict, setdefaultなどなど
- Counter()を呼び出しまくると遅い
- %%timeitで時間測ると楽しい
- AppleGothicはダメ。ゼッタイ。
- 別にmatplotlibはオワコンではない
- pandas使えるようになりたい
- カーネル密度推定
- xkcd()で心にゆとりを
- 06/8(火)
- (29)
- Requests, urllibを用いてGETリクエストを送る
- エンドポイント・クエリパラメータ
- (30-34)
- 形態素解析はなぜ必要なのか
- 様々な形態素解析器
- Mecab, JUMAN, JUMAN++, knp※, KyTea, sudachi…
- ※knpは格解析器
- Python wrapperがある解析器:Mecab, JUMAN, knp
- 基本的には形態素解析後の出力をpythonで処理
- wgetコマンド
- `-O` output_documentの名前を指定
- 元データはdataディレクトリへ
- `itertools.groupby(iterable, key)`
- key(lambda式など)のTrue/Falseに従いiterableをグルーピング
- `itertools.islice()`(復習)
- リストじゃないけどiterableをスライスしたいな〜
- そこでislice
- 正規表現は遅い
- generatorの定義
- コードの可読性と速さの両立を意識して内包表記を使おう
- (%%heatでIPythonのスクリプト中において時間がかかる箇所を表示できる)
- ‘’組み込みの名前を上書きしない’’(復習)
- `tqdm(.notebook)` モジュール
- 処理時間・進捗をいい感じに可視化してくれる
- toolz.itertoolz.sliding_window(復習)
- ★try_except(例外処理)
- 組み込み例外
- 自分で例外を定義することも可能
- 05/22(火)
- (22)-(25)
- 正規表現の後読みアサーション(と先読みアサーション)とは
- 否定もあるよ
- 後方参照で前側でマッチした内容を参照できるよ
- グループに名前を付けられるよ(付けなかった場合が`1`とか`2`)
- takewhile, dropwhile でイテレータの前部分をスキップしたり、後ろ部分を読まずに終わったりすることができる
- 05/15(火)
- (19)-(21)
- `pprint.pprint`: オブジェクトを整形して出力する
- sort コマンド
- `-r`: 降順にソート
- `-n`: 数値としてソート
- `collections.Counter(iterable)`: `iterable` をイテレートして値をカウントした dictionary を生成する
- 安定ソートとは
- 正規表現テスター https://regex101.com
- 正規表現の可視化 https://regexper.com
- JSON とは
- `gzip` モジュール
- `json` モジュール
- `json.load()` と `json.loads()` の違い
- wget コマンド
- gunzip コマンド
- zcat コマンド
- コマンドラインで完結する作業では Python を使わなくてもよい
- `re.MULTILINE` flag
- 正規表現の特殊文字
- 貪欲マッチ
- `str.startswith()`
- 05/08(火)
- (16)-(18)
- for x in iterable 内で list.append(f(x)) を繰り返すよりも内包表記 [f(x) for x in iterable] の方が(一般に)高速 & Pythonic
- `deque.popleft()` は $O(1)$
- `$*1` ≒ `expr 算術式`
- split コマンド: ファイル分割
- `split -n l/N`: 行を分断せずに N 個のファイルに分割
- `diff -s`: 比較するファイルが同じであることを出力
- iterator に対して `itertools.islice()` を繰り返すと中身を次々消費する
- `math.floor(N / M)` = `N // M`
- `divmod()`
- `more_itertools.divide()`
- `sort | uniq`: ソートして重複行をつぶす
- `sort -u` でも同じ
- 集合内包表記 `{f(x) for x in iterable}`
- `set(f(x) for x in iterable)` も結果は同じ.これはジェネレータ式(iterable)を `set()` コンストラクタに代入したもの
- `set()` コンストラクタは引数をイテレートして集合を作る
- `set('abc')` -> `{'a', 'b', 'c'}`
- `sort(iterable, key)`: `key` 関数で `iterable` をソート
- `operator.itemgetter`, `operator.attrgetter`
- sort コマンド
- `-s` 安定ソート
- ソートの安定性
- `var = !command`: シェルコマンドの実行結果を Python の変数に代入 (Jupyter)
- `!... $var ...`: Python の変数をシェルコマンドの引数として利用 (Jupyter)
- 04/24(火)
- (12)-(15)
- `cut` コマンド
- `-f` で切り出すフィールド指定
- デリミタはデフォルトでタブ文字
- コマンドによってデリミタとされる文字が異なるので注意
- `*` でイテラブルをバラす
- `print(*'abc')` は `print('a', 'b', 'c')` と等価
- `*変数` に「残りの値」を代入する (extended iterable unpacking)
- `x, y = 'ab' # x == 'a', y == 'b'`
- `x, *rest = 'abc' # x == 'a', rest == ['b', 'c']`
- 以上詳細: https://qiita.com/eumesy/items/dda85b70d28da61663cb
- `file.seek()`
- `paste` コマンド
- `cat` コマンド
- `zip()` は引数にイテラブルをとる
- Python スクリプトファイルの作り方
- `chmod` コマンド
- shebang
- スクリプトファイルとしてコマンドラインから呼び出されたときだけ実行したい部分は `if __name__ == '__main__':` ブロックに書く
- `sys.argv`
- `argparse` モジュール
- ★`itertools` モジュール
- イテレータを便利に扱うためのモジュール
- レシピ集を含め必読
- さらなる追加関数群: `more_itertools` モジュール
- `file.readlines()` には気を付けましょう
- `collections.deque([iterable, maxlen])`
- 双方向キュー / double ended queue
- 04/17(火)
- (08)-(11)
- map, filter, lambda
- filter + map より内包表記が好まれる
- ★iterable (list, str など) の要素を for で iterate したい場合は range() で index を iterate するのでは なく, 要素を直接 iterate する
- 変数名を capitalize するとクラス名に見える
- random.random(population, k) seq or set からの非復元抽出
- random.shuffle(list) list を破壊的に shuffle
- ★ipython: [tab] による補完(e.g., クラスメンバ名)
- ★ipython: `?` による docstring 閲覧
- ipython: `??` による(より詳しい) docstring(?)閲覧
- file から line を iterate する場合はとりあえず rstrip()
- UNIX コマンドの使い方を確認するオプション: `--help`
- `wc -l`
- ショートオプション (e.g., `-l`) とロングオプション (e.g., `--lines`)
- 頻繁に入力するコマンドはショートオプションを覚える
- 稀にしか入力しないコマンドはロングオプションで書くと可読性が高い
- 改行の数をカウントするアプローチ
- ファイル末尾に改行を
- `file.read()`, `file.readlines()` の使い方に注意
- ファイルサイズが非常に大きいとメモリに載り切らない
- tldr http://tldr.sh
- man ページの簡易版
- 新しいデータを処理する前にやること:ファイルの中身を確認する: `head`, `less`
- `with` 文: `file.close()` を自動的にやってくれる
- 使わないことを明示したい場合,変数名に `_` を使うことが多い
- `for i, _ in enumerate(file):`
- `diff` コマンド
- 標準入出力
- IPython でセルの中身をファイルに書き出す: `%%file filename`
- `tr`, `sed`, `expand`
- `sed` の典型的な使い方: `sed 's/old/new/g' file`
- Python でのファイル処理では行を処理する前に `str.strip()` で改行を消すことが多い
- `itertools.islice()`: スライスのイテレータ版
- 04/04(水) 14:40-16:10
- (03)-(07)
- ★スライス
- `x in s` は set が速い (O(1))
- 時間計算量
- set の要素や dict の key はハッシュ化される
- 三項演算子 (的な表記): `true_value if cond else false_value`
- 命名規則: PEP 8
- 組み込みの名前を上書きしない
- フォーマット文字列
- % (printf 形式の文字列書式化)
- ★str.format() (推奨), 仮引数に名前をつけられる
- f'' (フォーマット済み文字列リテラル) (Python 3.6-)
- toolz.itertoolz.sliding_window
- `%timeit` on Jupyter で時間計測できる
- 高度な話題
- escape sequence for shell
- 03/30(金) 10:30-12:00
- (00)-(03)
- ★スライス
- 文字列の連結
- `reversed()`
- `str.join()`
- `list.reverse()`
- `enumerate()`
- 0以外の数値は True になる
- リスト内包表記
- 高度な話題
- ジェネレータ
- イテレータ
- 遅延評価
- ★`zip()`
- 短いほうに合わせる
- ★関数名に ? を付けると仕様を表示できる
- `min()`
- ★`str.format()`
- ★`str.replace()`
- ★`str.split()`
- ★`str.strip()`
- ファイルを読み込むときによく使う
- `str.lstrip()`
- `str.rstrip()`
- lambda 式
- `map()`
- 03/26(月)
- (準備)
- 🔒100本ノック初回(esa)
- jupyterlab インストール: conda install -c conda-forge jupyterlab
- git 周りの設定: ~/.ssh/config に ssh 公開鍵 path, git config --global 系
- GitHub 当該ディレクトリに個人用ブランチ&ディレクトリ作成
- 03/??
- (課題図書)
- Python
- Shell
- 『新しいLinuxの教科書』
参考書 †
- TBA
過去の記録 †
© Inui Laboratory 2010-2018 All rights reserved.