人間だったら考えて

考えて考えて人間だったら考えて

卒論・修論tips

この記事は何?

卒論・修論を書き始めるときに知っておくと良い知識を研究室内でまとめていたのですが,恐らく研究室外の方々にも役に立つのではないかと思い公開してみます.
基本的にTeXを使った理系の卒論・修論を想定しています,分野毎に作法が異なる点もあるとは思いますが適宜対応してください.

TeXのお作法

このページが分かりやすくまとまっているので,こちらを参照してください.
ichiro-maruta.blogspot.jp

半角と全角

句読点

分野によります.
「,」「.」を使う場合はIMEの設定で変更しておくと簡単です.

括弧

日本語文のときは全角括弧を使います.

✕:新しい物質(成分)を発見する.
◯:新しい物質(成分)を発見する.

英文のときは半角括弧を使いますが,括弧の外側に半角スペースを置きます.

✕:Support Vector Machine(SVM)is a supervised machine learning algorithm.
◯:Support Vector Machine (SVM) is a supervised machine learning algorithm.

日本語文の中に英単語および括弧を用いる場合には宗派があると思いますが,半角括弧+半角スペースで良いと思います.

Support Vector Machine (SVM) を用いた.

引用

引用スタイル

引用スタイルを整えましょう.弊研究室では,引用スタイルが統一されているかどうかをかなり厳しくチェックされました.

また,松尾さんによると

論文の質は、参考文献を見るだけで、ほぼ言い当てることができます

とのことです.

bibitemに参考文献を書いていくときは,

  • 氏名表記(Myoji N.やN. Myojiといった書き方や,何人以上をet al.にするかなど)
  • 雑誌名(省略形にするかフルで書くか,イタリックにするか)
  • vol.issue
  • pages
  • 年号

を統一します.

BibTeXを使うときは,bstファイルを編集することで引用スタイルを統一させることができます.
しかし,bstファイルの編集は面倒なので既存のものを使う方が良いと思います.
こちらのページで紹介されているjecon.bstを編集すると簡単かもしれません.
jecon.bst: 経済学用BibTeXスタイルファイル

参考文献の順番(名前順?引用順?)は分野によって異なるため確認してください.
bibitemで参考文献を書いている場合は,文献を手動で並べる必要があるため注意が必要です.
BibTeXを使っている場合はbstファイルを編集することで名前順や引用順の指定が可能です.
(jplain.bstは名前順に,junsrt.bstは引用順に並びます.)

文献管理ソフト

私は文献管理にはMendeleyを使っています.
Mendeleyにはbibファイルを出力する機能があり,引用の際は非常に楽です.
一方で,Mendeleyが取得する文献情報は間違っていることが多いため注意が必要です(巻・号・ページや雑誌名が省略されていたりなど).
そのため,Mendeleyが出力したbibファイルを用いて引用する際には,必ず文献情報が正しいかチェックする必要があります.
間違っていた場合には,Mendeleyから手作業で文献情報を修正する作業が必要となります.

日本語

接続詞

ひらがなを使ってください.

✕:「~である.従って~」
◯:「~である.したがって~」

係り受け

係り受けの分かりにくい文は避けましょう.
下の引用は係り受けの厳しい文の一例です.


表記ゆれ

一週間くらい卒論・修論を書いていると,だいたい最初の方と最後の方で表記がゆれています.
「ユーザー」or「ユーザ」など注意してください.

参考になりそうな図書

古典としては理科系の作文技術でしょうか.私は結城さんの数学文章作法を参考にしていました.

数字・数式

桁数の大きい数字

「,」を入れてください.「10000000」とか書かれると混乱します.

単位

単位の前には半角スペースを置きます.
ただし,「℃」や「%」のときは半角スペースを置きません.

✕:長さが100mの~
◯:長さが100 mの~
✕:50 %の濃度の~
◯:50%の濃度の~

数式

sin関数やexp関数はTeXのコマンドを使います.

✕:sin(x)
◯:\sin(x)

sin(x)と書いてしまうとsinの部分が斜体となり,sとiとnの積のように見えてしまいます.

図・表

キャプション

図のキャプションは下,表のキャプションは上に書きます.
図表目次を入れているとき,キャプションが長くなってしまうと目次が大変なことになってしまいます.
その場合は,\caption[目次]{内容}を使うと回避できます.

なるべくベクター画像

図はなるべくベクター画像で作りましょう.
ラスター画像は印刷したときには気にならなくても,ディスプレイ上で拡大すると汚くなってしまいます.

PowerPointで図を作っているケースが多いと思いますが,MetafileToEPSConverterを使うとPowerPointの図をEPSに変換してくれます.

その他

なんだかとりとめのない記事になってしまいました.
卒論・修論を先生にチェックしてもらう前に,なるべく自分でチェックできるところはチェックしておくと良いと思います.

スケーリングは訓練データだけでやる?テストデータも混ぜてスケーリングする?

この記事は何?

機械学習における前処理として,特徴量のスケーリングがあります.
スケーリングの有無によって,予測器の性能が変化することがあります.
スケーリングにも様々な手法があります.代表的なものとして,「最小値を0,最大値を1とする0-1スケーリング」や,「平均を0,分散を1とするZスコア」があります.

訓練データとテストデータに対してZスコアによるスケーリングを行うとします.Zスコアによるスケーリングでは各特徴量の平均と分散を求める必要がありますが,次の2つの求め方が考えられます.

  1. 訓練データから各特徴量の平均と分散を求める.
  2. 訓練データとテストデータを合わせて,各特徴量の平均と分散を求める.

意識している人は意識しているでしょうが,どちらが正しい求め方なのでしょうか?この記事では2つの求め方の違いについて考えてみます.

予測精度の違いを確かめてみる

簡単な回帰問題で,2つの平均・分散の求め方による予測精度の違いを確かめてみます.
データセットにはsklearnが用意しているdiabetesデータセットを使いました.
予測器にはLassoを使い,評価にはR^2スコアを用いました.
評価は3-fold Cross Validationによって行いました.

ソースコード

import numpy as np
from sklearn import datasets, preprocessing, cross_validation, linear_model, metrics

np.random.seed(0)
dataset = datasets.load_diabetes()
X = dataset.data
ys = dataset.target
n_folds=3
N = X.shape[0]
kf = cross_validation.KFold(N, n_folds=n_folds, shuffle=True)
def scaling_test(X, ys, kf, scaling_all=False):
    scores = []
    for train_index, test_index in kf:
        X_train, ys_train = X[train_index], ys[train_index]
        X_test, ys_test = X[test_index], ys[test_index]
        
        scaler = preprocessing.StandardScaler()
        if scaling_all:
            scaler.fit(X)
        else:
            scaler.fit(X_train)
        X_train_scaled = scaler.transform(X_train)
        X_test_scaled = scaler.transform(X_test)
        
        model = linear_model.Lasso()
        model.fit(X_train_scaled, ys_train)
        ys_pred = model.predict(X_test_scaled)
        
        score = metrics.r2_score(ys_test, ys_pred)
        scores.append(score)
    mean_cv_score = np.mean(scores)
    print(mean_cv_score, scores)
# scaling with train data
scaling_test(X, ys, kf, scaling_all=False)
    0.48948448111 [0.40182607340355103, 0.51899710839470226, 0.54763026153277639]
# scaling with all data
scaling_test(X, ys, kf, scaling_all=True)
    0.489511363845 [0.4017844911712618, 0.51900200106422789, 0.54774759929815264]

訓練データだけで各特徴量の平均と分散を求めるよりも,訓練データとテストデータを合わせて各特徴量の平均と分散を求めた方が,予測精度がわずかに高いようです.

じゃあどっちを使って評価するべきなの?

予測対象の特徴によって,どちらを使って評価するべきかが変わってくると思います.

  • 予測対象が手元に無い未知データのときを想定するならば,スケーリングは訓練データのみを用いて行うべきです.予測対象となるデータを使ってスケーリングはできません.
  • 予測対象が手元にあるデータ(ラベルは未知)だけのときを想定するならば,スケーリングはテストデータも含めて行って良いと思います.これは,トランスダクティブ学習の考え方を根拠としています.

トランスダクティブ学習では,未知データの予測は行わず,手元のデータの予測のみ行います.予測対象のデータはもう分かっているのだから,そのデータだけを正しく当てられるように学習すれば良い…という考え方です.

その他

スケーリングをしたからといって,予測精度は必ずしも上がらないものです…つらいですね……

不均衡データに対する予測結果のAccuracyは簡単に上がってしまう

この記事は何?

機械学習における不均衡データの扱いは,学習時にも評価時にも注意する必要があります.
例えばSVMにおける学習では,クラス重みを事前に設定することで,不均衡データによるバイアスを軽減できます.
不均衡データに対する予測精度の評価について,Accuracyを用いて評価を行うと,不当に高い値が得られてしまいます.
この記事では不均衡データに対する予測結果をどのように評価すべきかについて紹介します.

不均衡データにおけるAccuracy評価を簡単に上げる

Accuracyは次式で定義されます.
 {\rm Accuracy}=\frac{{\rm TP}+{\rm TN}}{{\rm TP}+{\rm TN}+{\rm FP}+{\rm FN}}

ここで,正例数 n_{+}が負例数 n_{-}よりも多い不均衡データを考えます.
この不均衡データに対して全て正例と予測します.
すると,{\rm Accuracy}=\frac{n_{+} + 0}{n_{+} + 0 + n_{-} +0}=\frac{n_{+}}{n_{+}+n_{-}}となります.
 n_{+} \gg n_{-}より,Accuracyは1に近づいていきます.

実際に実験してみます.正例/負例の比率を0.5,0.99として,それぞれの予測結果におけるAccuracyを求めます.

import numpy as np
from sklearn.metrics import accuracy_score, confusion_matrix
def make_labels(N, positive_ratio=0.5):
    n_positive = int(N * positive_ratio)
    n_negative = N - n_positive
    labels = np.r_[np.ones(n_positive), np.zeros(n_negative)]
    return labels
N = 1000
positive_ratio = 0.5
y_true = make_labels(N, positive_ratio=positive_ratio)
y_pred = np.ones(N)
print("Accuracy:", accuracy_score(y_true, y_pred))
    Accuracy: 0.5
positive_ratio = 0.99
y_true = make_labels(N, positive_ratio=positive_ratio)
y_pred = np.ones(N)
print("Accuracy:", accuracy_score(y_true, y_pred))
    Accuracy: 0.99

というわけで,不均衡データでは簡単に高いAccuracyを出すことができます.
逆に言うと,Accuracyだけ見てすごい!と言うのは危険だということです.
Accuracyの評価の際には,ラベルの分布も一緒に見てすごいかどうか考えた方が良さそうです.

じゃあどうしたらいいの?

不均衡データに対する予測結果の評価において,Matthews correlation coefficient (MCC)が用いられています.
MCCは次式で定義されます.
 \frac{{\rm TP}\times {\rm TN} - {\rm FP} \times {\rm FN}}{\sqrt{ ({\rm TP}+{\rm FP}) ({\rm TP}+{\rm FN}) ({\rm TN}+{\rm FP}) ({\rm TN} + {\rm FN})}}
MCCは-1から1の値を取り,正しい予測のときに1・逆の予測のときに-1・ランダム予測のときに0となります.
正例に関する予測精度と負例に関する予測精度が共に考慮されているため,不均衡データに対する予測精度の評価に使えるということ…でしょうか.
MCCを使って先程の実験を行います.

positive_ratio = 0.5
y_true = make_labels(N, positive_ratio=positive_ratio)
y_pred = np.ones(N)
print(matthews_corrcoef(y_true, y_pred))
    0.0
positive_ratio = 0.99
y_true = make_labels(N, positive_ratio=positive_ratio)
y_pred = np.ones(N)
print(matthews_corrcoef(y_true, y_pred))
    0.0

 {\rm TN}=0かつ{\rm FN}=0なので,MCCは0となりました.

その他

評価指標はそれぞれ一長一短で特性も異なるので,出来る限り複数種類の評価指標で予測精度を検証した方が良いです.
もちろん,目的に応じた評価指標を使うべきなのですが…

【Python】組み込み関数のsumとnumpyのsumはどっちが速い?

この記事は何?

Pythonでリストやnumpy.array中の数値和を求めたい時は,組み込み関数のsumを使う方法とnumpy.sumを使う方法があります.
この記事では,どちらの方法がより高速に和を求められるのかを確認します.

結論は?

リスト中の数値和を求めるときは組み込み関数のsumが速く,numpy.array中の数値和を求めるときはnumpy.sumが速かったです.

実験

N = 10000000の要素のリストおよびnumpy.arrayを生成し,組み込み関数のsumおよびnumpy.sumの実行時間を計測します.
Pythonのバージョンはanaconda 2.5.0 (Python 3.5.1)です.

実行結果

import numpy as np
N = 10000000
python_list = [i for i in range(N)]
numpy_array = np.arange(N)
# python sum -> python list
%timeit sum(python_list)

    10 loops, best of 3: 82.6 ms per loop
# python sum -> numpy array
%timeit sum(numpy_array)

    1 loops, best of 3: 959 ms per loop
# numpy sum -> python list
%timeit np.sum(python_list)

    1 loops, best of 3: 588 ms per loop
# numpy sum -> numpy array
%timeit np.sum(numpy_array)

    100 loops, best of 3: 7.46 ms per loop

表にまとめます.

組み込みsum numpy.sum
python list 82.6 ms 588 ms
numpy array 959 ms 7.46 ms

その他

何でもかんでもnumpy.sumを使えば良いというわけでは無さそうです.numpy.arrayに変換してからnumpy関数を使って処理するのが一番良さそうですね.

CNNとRankNetを用いた画像の順序予測(ラブライブ!のキャラクター順序予測を例に)

(Chainer Advent Calendar 2016 5日目です.この記事はTokyoTechLTで発表したものと同内容のものです.)

この記事は何?

以前Chainer Advent Calendar 2015において,Chainerを用いたRankNet(ランク学習手法の1つ)の実装を紹介しました
本記事では,RankNetを応用した画像の順序予測を紹介します.

やりたいことの概要

RankNetを応用した画像順序予測の概要図を示します.
f:id:sz_dr:20161204133645p:plain


訓練データとして,既に順序付けされた画像集合を用います.
順序付けの例として,ユーザーの好みによるレイティングが考えられます.クリック率などを使う方法も可能だと思います.

得られた訓練データをCNNに入力し学習します.目的関数は,訓練データ中の画像対の順序が正しく識別できるように設定します(RankNet).

得られた予測器にレイティング未知の画像集合(テストデータ)を入力します.予測器の出力はレイティングを表しているため,これを用いて画像集合の順序付けを行います.

何に使えそう?

画像が好みの順番に並んでいると嬉しいケースは色々考えられます.

  • 漫画の表紙買い,アルバムのジャケット買い
  • pixivのようなイラストコミュニケーションサービスで,好みの画像検索
  • Amazonなどのショッピングサイトで,購買率が上がるような画像の表示

実装

まずはネットワークを書きます.CNNもRankNetも非常にシンプルに書けました(Chainer強い).
CNNのパラメータは決め打ちです,入力画像はRGBでサイズは80×80とします.

from chainer import Chain
import chainer.functions as F
import chainer.links as L


class CNN(Chain):

    def __init__(self):
        """
        picture size: 3 * 80 * 80
        Convolution2D parameter
        input_channels, output_channels, filter_size
        """
        super(CNN, self).__init__(
            conv1=F.Convolution2D(3, 20, 5),
            conv2=F.Convolution2D(20, 50, 5),
            l1=L.Linear(14450, 500),
            l2=L.Linear(500, 1)
        )

    def __call__(self, x):
        h1 = F.max_pooling_2d(F.relu(self.conv1(x)), 2)
        h2 = F.max_pooling_2d(F.relu(self.conv2(h1)), 2)
        h3 = F.relu(self.l1(h2))
        y = self.l2(h3)
        return y


class RankNet(Chain):

    def __init__(self, predictor):
        super(RankNet, self).__init__(predictor=predictor)

    def __call__(self, x_i, x_j, t_i, t_j):
        s_i = self.predictor(x_i)
        s_j = self.predictor(x_j)
        s_diff = s_i - s_j
        if t_i.data > t_j.data:
            S_ij = 1
        elif t_i.data < t_j.data:
            S_ij = -1
        else:
            S_ij = 0
        self.loss = (1 - S_ij) * s_diff / 2. + \
            F.math.exponential.Log()(1 + F.math.exponential.Exp()(-s_diff))
        return self.loss

次は訓練のスクリプトを書きます.
入力は訓練画像とレイティングファイルです.訓練画像はnumpyでシリアライズされたファイル(.npy)とし,レイティングファイルは各画像のレイティングがN行並んだテキストファイルとします.
出力は訓練画像のレイティング結果と,予測器をシリアライズしたファイル(.pkl)です.

# -*- coding: utf-8 -*-
import argparse
import pickle
import numpy as np
from chainer import Variable, optimizers
import net


def ndcg(y_true, y_score, k=None):
    y_true = y_true.ravel()
    y_score = y_score.ravel()
    if k is None:
        k = len(y_true)
    y_true_sorted = sorted(y_true, reverse=True)
    ideal_dcg = 0
    for i in range(k):
        ideal_dcg += (2 ** y_true_sorted[i] - 1.) / np.log2(i + 2)
    dcg = 0
    argsort_indices = np.argsort(y_score)[::-1]
    for i in range(k):
        dcg += (2 ** y_true[argsort_indices[i]] - 1.) / np.log2(i + 2)
    ndcg = dcg / ideal_dcg
    return ndcg

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("X_train_npy")
    parser.add_argument("rank_file")
    parser.add_argument("--output_pred", "-op", default="pred.txt")
    parser.add_argument("--output_model", "-om", default="model.pkl")
    parser.add_argument("--image_scale", type=float, default=1/255)
    parser.add_argument("--n_iter", type=int, default=1000)
    parser.add_argument("--monitor_step", type=int, default=100)
    parser.add_argument("--ndcg_k", type=int, default=100)
    args = parser.parse_args()

    np.random.seed(0)
    X_train = np.load(args.X_train_npy)
    X_train *= args.image_scale
    y_train = np.loadtxt(args.rank_file)
    N_train = np.shape(X_train)[0]

    model = net.RankNet(net.CNN())
    optimizer = optimizers.Adam()
    optimizer.setup(model)

    for step in range(1, args.n_iter + 1):
        i, j = np.random.randint(N_train, size=2)
        # X_train: (N, 3, 80, 80)
        x_i = X_train[i].reshape((1, ) + X_train[i].shape)
        x_j = X_train[j].reshape((1, ) + X_train[j].shape)
        y_i = Variable(np.array(y_train[i]))
        y_j = Variable(np.array(y_train[j]))
        model.zerograds()
        loss = model(x_i, x_j, y_i, y_j)
        loss.backward()
        optimizer.update()
        if step % args.monitor_step == 0:
            train_pred = model.predictor(X_train).data
            train_ndcg = ndcg(y_train, train_pred, args.ndcg_k)
            print("step: {} | NDCG@{} | train: {}".format(
                step, args.ndcg_k, train_ndcg))

    y_pred = model.predictor(X_train).data
    np.savetxt(args.output_pred, y_pred)
    out_model = args.output_model
    with open(out_model, "wb") as out_fp:
        pickle.dump(model, out_fp)

最後に予測のスクリプトを書きます,といってもテスト画像と予測器を読み込んで予測するだけですが…

# -*- coding: utf-8 -*-
import argparse
import pickle
import numpy as np

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("model_pkl")
    parser.add_argument("X_test_npy")
    parser.add_argument("--output", "-o", default="pred.txt")
    args = parser.parse_args()

    with open(args.model_pkl, "rb") as model_pkl_fp:
        model = pickle.load(model_pkl_fp)
    X_test = np.load(args.X_test_npy)
    y_pred = model.predictor(X_test).data
    np.savetxt(args.output, y_pred)

使用例

以上の実装を使って,「ラブライブ!サンシャイン!!」の画像順序予測をやってみたいと思います.
訓練データには「ラブライブ!」の画像を用いました.

学習の流れ

  1. Lantisちゃんねるから『TVアニメ「ラブライブ!」先行発表PV』を取得します.
  2. OpenCVを用いて顔部分をクリップします.277枚の顔画像を生成しました.顔画像認識はlbpcascade_animefaceを参考にしました.
  3. 各画像にレイティングを付けます(277枚の画像にレイティングを付けます,つらい作業).
  4. 上記で実装したCNN+RankNetで学習します.

訓練データに対する予測結果

まず,上記の実装が正しく動いていることを確認するために,訓練データに対して予測を行い正しく順序付けされているかを確認します.
f:id:sz_dr:20161204142340p:plain

レイティング値は好み度を表しています(左に行くほど好きです).
にこにーと希ちゃんが上位にたくさん来てます.花陽ちゃんは1枚だけ見当たります,レイティング下位のキャラクターと類似性が高いためでしょうか…
訓練データ内に非常に類似した画像が含まれていますが,これはクリッピング後にクラスタリング等を行っていないためです.冗長なデータは訓練データから取り除いた方が良いと思います.

テストデータに対する予測結果

学習の結果得られた予測器を使って,「ラブライブ!サンシャイン!!」の画像順序予測をします.
テスト画像はLantisちゃんねるからラブライブ!サンシャイン!! Aqoursメンバー紹介PVを取得し,先程と同様に顔画像をクリップします.各キャラ毎に2種類の画像を取り出して計18枚の画像をテストデータとしました.
f:id:sz_dr:20161204143225p:plain

上が私がランク付けした結果(左に行くほど好き)で,下がCNN+RankNetによる予測結果です.
なかなか私のランク付け結果とは一致しませんが,訓練データの傾向は反映しているように見えます.
また,同じキャラクターの画像は似たような順位に来ていることがわかります.

まとめ

この記事ではCNN+RankNetを使った画像の順序予測について,実装および使用例を紹介しました.
使用例で紹介したキャラクター順序予測は難しい問題です.ランク付けの際に,キャラクターへの思い入れが入ってしまうので…
キャラクター順序予測に本気で取り組む際には,キャラクターの性格を学習にどうにかして取り入れる必要がありそうです.
これについては,TokyoTechLTで発表後に以下のような意見をいただきました.



マルチモーダル学習になってきましたね,テキストで順位付けしている例はまさにwebページランキングですね.画像情報を組合せたランキング予測なんてやられているんでしょうか…??新しい研究ネタになりそうです.

レイティングを付ける作業は結構大変です,そのため学習データサイズが小さくなってしまうという問題点があります.これについては既存の学習済み予測器をfine tuningしたり,自動でレイティングを得る方法(画像クリック率)を考えると良さそうです.

あまりChainer自体の話はしていませんでしたが,Pylearn2 -> Caffe -> Chainerと移り変わってきた身からすると,Chainerはかなり楽にネットワークを書けるので好きです.Deep Learningフレームワークが溢れているご時世ですが,何でも良いので1つ使えるようにしておけば良いと思います…色々なフレームワークを平均的に知っているよりも,1つのフレームワークを極める方が良いんじゃないかなあ(・。・)

z-scoreに変換しても相関係数は変わらない

この記事は何?

機械学習の前処理として特徴量のスケーリングを行うことがありますが,スケーリング手法の1つとしてz-score変換があります.
z-scoreは平均が0,標準偏差が1となるようにスケーリングを行います,z-scoreを10倍して50を加えるとお馴染みの偏差値になります.

特徴量XYの相関係数を\rhoとします.このとき,Xをz-score化したX'Yの相関係数\rho'を考えます.
直感的には\rho\rho'は等しくなるんじゃないかなと思いますが,本当に等しくなるのか確かめてみたときのメモです

証明

結論から先に言うと,\rho\rho'は等しくなります.

z-score変換は,平均を引いて標準偏差で割って求めるため,線形変換です.
そこで,X'=aX+bとし,\rho=\rho'となることを示します.


\rho'= \frac{{\rm cov}[X', Y]}{\sqrt{ V[X' ]V[Y] }}\\
 = \frac{E[X'Y] - E[X']E[Y]}{\sqrt{ V[X' ]V[Y] }}\\
 = \frac{E[aXY+bY ] - E[aX+b]E[Y]}{\sqrt{ V[X' ]V[Y] }}\\
 = \frac{aE[XY] + bE[Y] - (aE[X]+b)E[Y]}{\sqrt{ V[X' ]V[Y] }}\\
 = \frac{a(E[XY]-E[X]E[Y])}{\sqrt{ V[X' ]V[Y] }} \\
 = \frac{a(E[XY]-E[X]E[Y])}{\sqrt{ V[aX+b ]V[Y] }} \\
 = \frac{a(E[XY]-E[X]E[Y])}{a\sqrt{ V[X ]V[Y] }} \\
 = \frac{E[XY]-E[X]E[Y]}{\sqrt{ V[X ]V[Y] }} \\
 = \rho

というわけで,\rho=\rho'となることが示されました.
これで安心して相関係数を計算できますヽ(^o^)丿

追記(2016/11/20)

上式では,aの正負によっては\rho=-\rho'になることがありますね…
z-scoreではaは正なので(標準偏差は正)問題は無いのですががが

Pythonのset演算は演算子使うとスマート

この記事は何?

Pythonでset演算をするには,union関数やintersection関数を用います.
最近,set演算は演算子を用いた方法もサポートされていることを知ったので(ドキュメントに書いてあるんですけどね),紹介したいと思います.

どのように書けるのか?

set演算は演算子を用いて,以下のように書けます.

>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s1 | s2
{1, 2, 3, 4}
>>> s1 & s2
{2, 3}
>>> s1 - s2
{1}
>>> s1 ^ s2
{1, 4}
>>> s3 = set([1, 2, 3])
>>> s4 = set([1, 2])
>>> s3 > s4
True
>>> s3 < s4
False

ビット演算と同じような気持ちで書けます,union関数やintersection関数を呼ぶよりもスマートな気がします.

どんな演算子がサポートされてるの?

これに関しては公式ドキュメント
http://docs.python.jp/3.5/library/stdtypes.html#set-types-set-frozenset
を参照です,たまに公式ドキュメントを読むと発見がありますね…