めも

これはメモ。

リーダブルコードの要約のメモ(後半)

このメモは「リーダブルコード」を読んだ際のものです。 自分用のメモなので、本の構成の順番を守っておらず、例も本のものではなく自分の理解で置き換えたものになっているので注意してください。

大原則: 優れたコード = 人が最短の時間で理解できるコード

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

  • 作者: Dustin Boswell,Trevor Foucher,須藤功平,角征典
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2012/06/23
  • メディア: 単行本(ソフトカバー)
  • 購入: 68人 クリック: 1,802回
  • この商品を含むブログ (140件) を見る

前半

paper.hatenadiary.jp

ロジックの構造化

6. 制御フローを見やすく

  • コードの並び順と書き方を明確に
    • 比較:左辺を調査対象、右辺を比較対象
    • if/else: 否定の比較を使わない、重要な条件を先に
    • 三項演算子: 単純な二変数の比較・代入以外で無理に使わない、理解のしやすさが最優先
  • do-while文を避ける
    • continueのわかりにくさ
    • 条件(重要な箇所)を先に記述する
  • return
    • 理解しやすさが優先
    • returnを関数末端に持ってくるためだけにコードを複雑にしてはいけない
  • go-to文を避ける
  • ネストをむやみに深くしない

7. 巨大な式を分割する

  • 説明変数と要約変数を作る
    • 変数に何の値が入っているか、それが何を示しているかの見やすさが優先
    • 逆に、複雑な式を分割したり変数に含まれる値を要約できていない変数は削除するべき(次の章)
  • ドモルガンの法則を使う
    • not(!)が一番外側の括弧についていると条件が分かりにくくなる
    • 条件分岐のわかりにくさはエラーや取りこぼしの原因になる
    • 短絡評価の悪用
      • 範囲指定の条件や複雑な入れ子など場合分けが複雑な条件分岐を避ける
      • 複雑になる場合は”反対”(例:[1, 2] の範囲の反対は 1),(2 を一旦考えてみる)

この後長い処理をマクロでまとめるなどの例が出てくるが、総じて複雑な条件分岐のパターンを見やすくすることでバグや見落としを回避する。

8. 変数と読みやすさ

  • 余分・不要なコードの削除
    • 手前の章にあるような、複雑な式の要約や分割を行わない変数
    • 中間結果を一時的に持つ変数の削除したい
    • 制御フローのための変数を削除する
      • complete_vgg16_train = False などの変数を用意して分岐を制御する変数
      • 制御の入れ子が重なる場合は他の関数として切り出す
  • 変数のスコープを少なくする
    • 大域変数を使用しない
    • スコープ内部だけでしか使用しない変数を用意
    • 変数宣言の位置を下げる
      • 使用する直前で宣言をする
    • 変数は一度だけしか代入されないようにする
      • const等を使える場所でしっかり宣言する

コードの再構成

9.無関係の下位問題を抽出する

  • 下位問題の抽出
    • コードブロックごとの高レベルでの目的は何かを定める
    • コードブロック内部で、高レベルの問題とは関係ない↓位問題をどれくらい含んでいるかを俯瞰して
    • 無関係な問題を解決するためのコードが多数含まれる場合はその箇所をくくりだす
  • 汎用コードを作る
    • プリントのフォーマット化など、高レベルでの目的にならないがどこでも利用できるコードは関数としてくくりだす
    • 入力と出力がはっきりしていればデバッグもテストも楽になる
  • 簡潔なインターフェースを作る
    • 複雑な処理は外部に切り出し、ラッパー関数を作る
    • 例: 指定したウェブページの <article>...</article>部分の文字列だけを抽出する
      • get_article_str(http_adress)などとして内部に細かいテキストのフィルタリングを記述する

10. 一度に一つの事を実行する

  • 複数のタスクを並列で実行しない
    • 一つのコードブロックで一つのタスク
    • ”デフラグ”されているタスクを直列にまとめる

11.〜

省略。

How to Win a Data Science Competition: Learn from Top Kagglers(三週目)のメモ

コーセラの以下のコースを受講した際の聴講した内容を部分的にメモ。あくまで自分の理解で講義の中身そのものではないです。

coursera

Week2の聴講メモは以下。

Week3

コンペティションの評価指標(metric)について、それらの最適化について。 問題が異なれば最適化すべき損失は異なる。

回帰

回帰問題の指標

  • MAE(Mean Absolute Error)
  • MSE(Mean Squared Error)
  • RMSE(Root Mean Square Error)

MSEとRMSEは勾配ベースのモデルだと学習率が異なる場合と見ることができる。外れ値がある場合はMAEの方がロバストなので(MAEは誤差の絶対値なので外れ値を過大評価しない)外れ値があるかもしれない場合はMAEでいいとして一つ目の講義は締めている。

  • RMSPE(Root Mean Square Percentage Error)
  • MAPE(Mean Absolute Percentage Error)
  • RMSLE(Root Mean Squared Logarithmic Error)

上記は予測の誤差と正解の値との比率が重要になる時に利用する。 RMSLE(Root Mean Squared Logarithmic Error)は

import numpy as np
import math

def rmsle(y, y_pred):
    # Σの箇所を計算
    diffs = [(math.log(ypi + 1) - math.log(yi + 1)) ** 2.0 for yi,ypi in zip(y, y_pred)]
    # サンプル数で割ってルート
    return np.sqrt(np.sum(diffs) * (1.0/len(y)))

となり、MSPE,MAPEはMSE,MAEの重み付けバージョン、RMSLEはMSEのlog-spaceバージョンと見ることができる。

決定係数 (R-squared)

R-squaredを最適化すること = MSEを最適化することと式の形からわかる。 R-squaredは説明変数を増やせば増やすほど(それが重要な説明変数で無いにもかかわらず)高くなるケースがある場合に注意する。

回帰モデルの最適化

評価指標が最適化したい関数であり、損失関数がモデルの最適化する関数。 実際に最適化したい関数は微分不可能だったりの理由からモデルを使って最適化することができない時がある。そのため代替する損失関数を最適化する。

XGBoostではモデルの損失関数を簡単に変えることができる。

XGBoostは損失関数でヘッセ行列が出てくることから二階微分できない MAEなどを目的関数に利用することはできないが、LightGBMは使うことができる(なぜだろう?)。なので二階微分できない関数で勾配ブースティングするときはLightBGMを使えばいいい。

MSPEはサンプルごとの重みを変えてMAEを行えば良い。 XGBoostとLightGBMはsample_weights を変えればok。 それ以外のモデルを使う場合はdf.sampleを使えば良い。

ロバストな損失関数

  • Huber-loss
  • Quantile-loss(MAEはquantileの特別なケースですね)

その他のロバストな損失関数

講義からはそれますが。

A More General Robust Loss Function

BARRON, Jonathan T. A more general robust loss function. arXiv preprint arXiv:1701.03077, 2017.

[1701.03077] A More General Robust Loss Function

Charbonnier損失, pseudo-Huber損失, L2損失, L1損失などパラメータを一つ持つ損失関数を一般化したパラメータを二つ持つ関数を提案。

分類問題の指標

  • accuracy

accuracyは(正解数)/Nなので頻度が高いクラスを当てると高くなる点に注意する。

  • logloss

ylog(y)+(1-y)log(1-y)の箇所は実際には10**-5などの小さい値でクリッピングした値で損失を計算する(講義参照)。

  • AUC-ROC

AUCは予測したクラスが特定の閾値(0~1)で完全に二分できる時に1になる。ベースラインは完全にランダムに予測した場合で、0.5になる。

  • Kohen's Kappa

1 - (1-accuracy)/(1-baseline)

偏りのあるデータ、例えば全部クラス1で予測したらaccuracy=0.9となるデータではaccuracyは高くなる。なのでベースラインとして「予測値をランダムに並び替えたもの」を用意してそのaccuracyとの比率を見る。

他ランキング推定などの指標も sk-learn/metric以下で実装されている。重要なのは、ときたい問題に沿って正しい指標を選ぶこと。

追記予定

リーダブルコードの要約のメモ(前半)

このメモは「リーダブルコード」を読んだ際のものです。 自分用のメモなので、本の構成の順番を守っておらず、例も本のものではなく自分の理解で置き換えたものになっているので注意してください。

大原則: 優れたコード = 人が最短の時間で理解できるコード

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

  • 作者: Dustin Boswell,Trevor Foucher,須藤功平,角征典
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2012/06/23
  • メディア: 単行本(ソフトカバー)
  • 購入: 68人 クリック: 1,802回
  • この商品を含むブログ (140件) を見る

表面上の改善

1. 名前に情報を詰め込む

  • 複数の意味を持つ単語や動作の目的がわからない動詞・名詞だけの名前を回避する
  • piyo, hogeなどの汎用的な名前を回避して、変数の値を表現する名前を使う
    • ループイテレータを i, j, k ではなく意味を持たせる (iepoch_i, ei, etc...)
    • 状況に応じて必要な形容詞を考えて加える
      • 大きさをそろえるべき画像データなのにまだ処理前: imageunscaled_imageとしてデータがまだ生のままであることを伝える
      • 本来のデータに処理を加えた: texttext_tfidf(tfidf法を適用したテキストデータ)
    • ミリ秒などの単位を持つ変数に単位を付ける
      • inference_timeinference_time_ms
      • sizememory_size_gb
  • 具体的に何をするか明確な名前を付ける
    • 少なくともVOは明確にする
      • --stop--stop-all-gpu
      • add_noise(X, noise_param1, noise_param2)add_gaussian_noise(image, mean, var)
  • 新しく開発を行う人がそれを理解できるか考える
    • 明らかでない省略形は使わない
    • 不要な単語を除去する
    • エンティティごとに変数名・関数名のフォーマットを区別する
      • DBから取得したデータを持つ変数にDBの頭文字を付けるフォーマットがあれば、すぐにDBの値と分かる
      • jqueryでライブラリ関数($)から呼び出した値を持つ変数は $を接頭辞とする

2. 誤解されない名前

  • 関数の取る値と比較して何をするか曖昧な名前を避ける
    • filter(data, classname)select_class(data, classname)
    • 範囲指定の名前を明確にする
      • first~last, min~max, begin~end
      • 単位を持つ値なら min_ms~max_msなどとしたい
  • 開発者が気にしていることを理解してそれを伝えるように記述する
    • get_inference_time(model)では予測モデルのインファレンス時間を実際にモデルを100回して計算しているとは伝わらないので evaluate_inference_time_ms(model, simulate_num=100)などとする
  • 複数の名前候補を挙げて誤解の無い名前を絞り込む

3. 美しさ

  • 読み手が慣れているパターンと一貫性があるコードに
  • 関連するコードブロックをひとまとめに
    • 改行の位置、インデント、コメントの位置を規則正しく
  • 規則正しく並べる
    • 似ているコードは似ている組み立て
    • 変数をどの様な順番に並べるか
      • どんな規則を使ってもいい、しかし同じコード内では同じルールを一貫して使うこと
        • アルファベット順
        • 変数の重要度順
        • 使用位置順、変数の持つ値の型順...

4. コメントすべきこと

  • コードを見て理解できることはコメントしない
  • コードを見てもわからない変数名・関数名はまずその名前を変えられないかを検討する
  • なぜこのような構成・選択にしたのかを記録する
  • コードの欠陥や例外の恐れがある箇所を指摘する
    • TODO, FIXME, HACK, XXX, ...
    • todo, mabe-latter, ...
  • 新しく見た人が知らない可能性が高い・ミスをする可能性が高い箇所にコメントする
    • # adaptive thresholding のカーネルサイズは~だからXXにする
    • # keras のバックエンドが tensorflow の場合XXXのため以下でエラーになる etc..
  • 比較的大きなコードブロックの要約を記述する

5. 正確かつ簡潔にコメントする

  • 代名詞は使わない
  • 関数の入出力を具体例で示す
  • 名前付き引数で引数の内容を説明する

ロジックの構造化

6. 制御フローを見やすく

  • コードの並び順と書き方を明確に
    • 比較:左辺を調査対象、右辺を比較対象
    • if/else: 否定の比較を使わない、重要な条件を先に
    • 三項演算子: 単純な二変数の比較・代入以外で無理に使わない、理解のしやすさが最優先
  • do-while文を避ける
    • continueのわかりにくさ
    • 条件(重要な箇所)を先に記述する
  • return
    • 理解しやすさが優先
    • returnを関数末端に持ってくるためだけにコードを複雑にしてはいけない
  • go-to文を避ける
  • ネストをむやみに深くしない このメモは「リーダブルコード」を読んだ際のものです。 自分用のメモなので、本の構成の順番を守っておらず、例も本のものではなく自分の理解で置き換えたものになっているので注意してください。

大原則: 優れたコード = 人が最短の時間で理解できるコード

表面上の改善

1. 名前に情報を詰め込む

  • 複数の意味を持つ単語や動作の目的がわからない動詞・名詞だけの名前を回避する
  • piyo, hogeなどの汎用的な名前を回避して、変数の値を表現する名前を使う
    • ループイテレータを i, j, k ではなく意味を持たせる (iepoch_i, ei, etc...)
    • 状況に応じて必要な形容詞を考えて加える
      • 大きさをそろえるべき画像データなのにまだ処理前: imageunscaled_imageとしてデータがまだ生のままであることを伝える
      • 本来のデータに処理を加えた: texttext_tfidf(tfidf法を適用したテキストデータ)
    • ミリ秒などの単位を持つ変数に単位を付ける
      • inference_timeinference_time_ms
      • sizememory_size_gb
  • 具体的に何をするか明確な名前を付ける
    • 少なくともVOは明確にする
      • --stop--stop-all-gpu
      • add_noise(X, noise_param1, noise_param2)add_gaussian_noise(image, mean, var)
  • 新しく開発を行う人がそれを理解できるか考える
    • 明らかでない省略形は使わない
    • 不要な単語を除去する
    • エンティティごとに変数名・関数名のフォーマットを区別する
      • DBから取得したデータを持つ変数にDBの頭文字を付けるフォーマットがあれば、すぐにDBの値と分かる
      • jqueryでライブラリ関数($)から呼び出した値を持つ変数は $を接頭辞とする

2. 誤解されない名前

  • 関数の取る値と比較して何をするか曖昧な名前を避ける
    • filter(data, classname)select_class(data, classname)
    • 範囲指定の名前を明確にする
      • first~last, min~max, begin~end
      • 単位を持つ値なら min_ms~max_msなどとしたい
  • 開発者が気にしていることを理解してそれを伝えるように記述する
    • get_inference_time(model)では予測モデルのインファレンス時間を実際にモデルを100回して計算しているとは伝わらないので evaluate_inference_time_ms(model, simulate_num=100)などとする
  • 複数の名前候補を挙げて誤解の無い名前を絞り込む

3. 美しさ

  • 読み手が慣れているパターンと一貫性があるコードに
  • 関連するコードブロックをひとまとめに
    • 改行の位置、インデント、コメントの位置を規則正しく
  • 規則正しく並べる
    • 似ているコードは似ている組み立て
    • 変数をどの様な順番に並べるか
      • どんな規則を使ってもいい、しかし同じコード内では同じルールを一貫して使うこと
        • アルファベット順
        • 変数の重要度順
        • 使用位置順、変数の持つ値の型順...

4. コメントすべきこと

  • コードを見て理解できることはコメントしない
  • コードを見てもわからない変数名・関数名はまずその名前を変えられないかを検討する
  • なぜこのような構成・選択にしたのかを記録する
  • コードの欠陥や例外の恐れがある箇所を指摘する
    • TODO, FIXME, HACK, XXX, ...
    • todo, mabe-latter, ...
  • 新しく見た人が知らない可能性が高い・ミスをする可能性が高い箇所にコメントする
    • # adaptive thresholding のカーネルサイズは~だからXXにする
    • # keras のバックエンドが tensorflow の場合XXXのため以下でエラーになる etc..
  • 比較的大きなコードブロックの要約を記述する

5. 正確かつ簡潔にコメントする

  • 代名詞は使わない
  • 関数の入出力を具体例で示す
  • 名前付き引数で引数の内容を説明する

ロジックの構造化

6. 制御フローを見やすく

  • コードの並び順と書き方を明確に
    • 比較:左辺を調査対象、右辺を比較対象
    • if/else: 否定の比較を使わない、重要な条件を先に
    • 三項演算子: 単純な二変数の比較・代入以外で無理に使わない、理解のしやすさが最優先
  • do-while文を避ける
    • continueのわかりにくさ
    • 条件(重要な箇所)を先に記述する
  • return
    • 理解しやすさが優先
    • returnを関数末端に持ってくるためだけにコードを複雑にしてはいけない
  • go-to文を避ける
  • ネストをむやみに深くしない

MK8DXの(3v3v3v3)トリプルスの即時集計

3v3v3v3(トリプルス)

MK8DX3v3v3v3(トリプルス)即時集計

マリオカート8DXにおいて4チーム(3v3v3v3、トリプルス)で12レースする際の即時集計をするページです。ボタンが押しにくい+小さいスマホからだと使いにくいですね、ごめんなさい。

4v4v4(フォーマンセル)

6v6(交流戦用)

MK8DXの(4v4v4)フォーマンセルの即時集計

マリオカート8DXにおいて3チーム(4v4v4)で12レースする際の即時集計をするページです。

MK8DX4v4v4(フォーマンセル)即時集計

チェックボックスが小さくて押しにくいかも知れません、UIの難しさを実感します。Android3.1とChromeでのみ動作確認してます。計算などにバグがあった場合や要望(チェックボックスが小さい、等)はコメント欄などに連絡いただけると嬉しいです。ただ、時間的な関係ですぐには修正できないと思います、すいません。

6v6、いわゆる交流戦の即時集計は以下を参照してください。