2010/12/18

画像をぼかす: いろんなボケ、リアルなボケ

画像をぼかす』と一口に言っても、その方法にはいろんなものがあります。一番有名なのはPhotoshopの『ガウスぼかし』に見られるようなGaussian Blurですが、残念ながらこれはカメラに見られるようなリアルなぼかしと比べるとどうしても見劣りします。原因はいくつか考えられて、一つはGaussian Blurに使われているガウス関数の勾配が穏やかなため、現実のレンズのシチュエーションを考慮していないという点があります。

それじゃあ勾配を急にした関数ー例えばフェルミ分布関数のようなーをカーネルに採用すれば良いのかというとそういうわけではありません。有名なLena画像で試してみましょう。

左が元画像、中央がカーネルにガウス関数を用いた画像、右がフェルミ分布関数を用いた画像。
確かに中央よりは綺麗だけど、それでもまだリアルとは言えない
それじゃあ他に何が違うのでしょう?端的に言うと、黒も白も等価に扱って平均してしまうのがマズい

画像をぼかすという行為は要は畳込み積分で、周囲のピクセル値を特定のウェイトで平均してやってることになります。で、普通にブラーしてしまうとピクセルの輝度に関わらず常に一定の割合で平均してしまいますので、なんか濁ったような画像が生成されてしまうと。

通常のブラー。カーネルにはよりリアルに見せるため正六角形を用いている
それではどのようなアプローチを用いればいいのでしょうか?レンズブラーを観察してみると、明るい箇所が強調されてぼかされていることが分かります。言い換えると、輝度の高いピクセルが優先的に混合されている、つまり予めRGBの全ピクセル値を適当な単調増加関数で写像してから畳込み積分を行って、その後対応する逆関数で戻してやればいい。要はhirax.netとやっていることは同じで、expしてからボカしてlogすると、こういうわけです。

結果の画像。比較的リアルにボカされていることが分かる

並べてみれば、違いがはっきり(クリックで拡大)
Lenaさんだけでは少し分かりづらいので、適当な背景写真に適用してみましょう。

森林画像
まず、通常の手法でぼかしてしまうとどうなるでしょう?
森林画像(通常のブラー)
お世辞にも綺麗なボケとは言えません。それじゃあ今回の手法でぼかしてみます。

森林画像(リアルブラー)
なんということでしょう…リアルなボケ画像ができました。
比較画像(クリックで拡大)
今回組んだOpenCVのソースコードを下記に示します。2.2でコンパイルしましたが、多分2.0以上だったら普通に通ると思います。

#include <algorithm>
#include <cmath>
#include <string>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/operations.hpp>

struct exp_each_element
{
public:
    exp_each_element(float factor): factor_(factor/256.0){};
    cv::Vec3f operator()(cv::Vec3b &color) {
        return cv::Vec3f(
                std::exp(static_cast<float>(color[0])*factor_),
                std::exp(static_cast<float>(color[1])*factor_),
                std::exp(static_cast<float>(color[2])*factor_));
    }
private:
    const float factor_;
};

struct log_each_element
{
public:
    log_each_element(float factor): factor_(factor/256.0){};
    cv::Vec3b operator()(cv::Vec3f &color) {
        return cv::Vec3b(
                cv::saturate_cast<uchar>(std::log(color[0])/factor_),
                cv::saturate_cast<uchar>(std::log(color[1])/factor_),
                cv::saturate_cast<uchar>(std::log(color[2])/factor_));
    }
private:
    const float factor_;
};

cv::Mat make_fermi_kernel(float radius, float range) {
    const int size = static_cast<int>(2.0*range + radius)*2 + 5;
    const float mu = static_cast<float>(size/2);
    const float range_inversed = 1.0 / range;
    cv::Mat dst(size, size, CV_32F);
    for(int i=0; i<size; ++i) {
        for(int j=0; j<size; ++j) {
            const float u = static_cast<float>(i - mu);
            const float v = static_cast<float>(j - mu);
            const float r = std::sqrt(u*u + v*v);
            dst.at<float>(i, j) =
                    1.0/(std::exp(range_inversed*(r - radius)) + 1.0);
        }
    }
    cv::normalize(dst, dst, 1.0, 0, CV_L1);
    return dst;
}

cv::Mat make_regular_polygon_kernel(int number, float radius) {
    const int size = static_cast<int>(2.0*radius) + 1;
    const float center = static_cast<float>(size)/2.0;
    std::vector<cv::Point> dst_vector;
    for(int i=0; i<number; ++i) {
        const float theta = 2.0*M_PI*i/number;
        const cv::Point point = cv::Point(
                center + radius*std::cos(theta),
                center + radius*std::sin(theta));
        dst_vector.push_back(point);
    }
    cv::Mat dst(size, size, CV_32F);
    const cv::Scalar color(1.0, 1.0, 1.0, 1.0);
    cv::fillConvexPoly(dst, &dst_vector[0], number, color);
    cv::normalize(dst, dst, 1.0, 0, CV_L1);
    return dst;
}

int main(int argc, char** argv) {
    const std::string source = argc >= 2 ? argv[1] : "lena_std.tif";
    const std::string destination = argc >= 3 ? argv[2] : "out.jpg";
    const float factor = 6.0;

    cv::Mat image = cv::imread(source);
    CV_Assert(image.type() == CV_8UC3);
    cv::Mat kernel = make_regular_polygon_kernel(6, 8.0);

    cv::Mat exp_image(image.size(), CV_32FC3);
    std::transform(image.begin<cv::Vec3b>(), image.end<cv::Vec3b>(),
            exp_image.begin<cv::Vec3f>(), exp_each_element(factor));

    cv::filter2D(exp_image, exp_image, -1, kernel);

    std::transform(exp_image.begin<cv::Vec3f>(), exp_image.end<cv::Vec3f>(),
            image.begin<cv::Vec3b>(), log_each_element(factor));

    cv::imwrite(destination, image);
    return 0;
}

余談
  • 実質80行くらいで完成したので嬉しいです。可読性も多分結構読みやすい部類だと思う
  • C++のコードが何やってるか分からない方は、まず関数オブジェクトとSTLについて調べてみましょう。あれはいいもんです
追記(11/03/23)
どんなデバイスであるか、たとえば、それが入力デバイスであるのか、出力でバイスであるのか、はたまた、計算処理デバイスであるのか次第で「輝度値の単位系」をどのように保持(処理)するべきかは違うことでしょう。
大切なことは、取り扱う「値」がどんな単位であるのかを見失わないことなのか、と思います。 
hirax.net::「コンピュータ画像処理」と「輝度値の単位系」 
自分がこのような『任意の単調増加関数で良い』という具合で筆を進めたのには2つ理由があります。

まず1つ目が、『全てのデジタルカメラにおいて、ピクセルは輝度の対数の次元を取っているのだろうか?』という単純な疑問です。

きちんと物理的/工学的な意味合いを持つ画像処理にするためには、格納されているピクセルデータの次元がきちんと揃えられている必要があります。自分自身も普通に考えて輝度の対数が格納されているんだろうということで、任意ではなく指数関数に制限された関数系を使いましょうと運びたかったのですが、そうするための証拠が不足していた。

もしかしたら自分の予想もつかない方法で処理されている可能性があるわけで、そういった証拠が十分にないことから、単調増加関数と少し曖昧とした意味合いを含ませたのです。

もう一つの理由は『今回の画像処理は物理的に正確である必要がない』という理由です。これが大きかった。

そもそも今回の画像処理はどういう目的があるのでしょうか?ぼけて普通よりもリアルに見えて面白い、それで終わりです。物理的に計測をするわけではなく、ざっくり『それっぽく』見えればそれでいいという類のものです。そのような目的の下では、下手に物理的正確さを求めて処理時間を長くするよりは、計算速度の早いフェイクのほうがより適しています。

だから何も指数関数に制限する理由はあまりないわけで、より早くてよりそれっぽく見えれば、そちらのほうが優れていると、そう言えるわけです(ただ、今回の計算量からすると最も大きなオーダーとなっているのは畳み込み積分の箇所で、単調増加関数自体のコストはそれに比べれば微々たるものでしょう)。

2010/10/27

OMakeマニュアル 日本語訳 PDFバージョンをリリースしました

"Aint they cute?" by Nicki Varkevisser

題名の通りで、以前から取り組んでおりました『OMakeマニュアル 日本語訳』の全ページを一つに纏めたPDFバージョンをリリースしました。

http://omake-japanese.sourceforge.jp/OMake.pdf

よりダウンロードできます。電子書籍でまとめてご覧になりたい方や、職場などの環境で使いたいけれどネットが使えないのでごりごり印刷したい…といった場合に便利です。

元々は渋川さんの『LaTeX経由でのPDF作成』という記事を拝見しまして、試験的にPDF版を作成してみたところ、思いのほか綺麗に製本されていることからきちんとリリースしてみようと思い立った次第です。殆ど素の状態から手を加えていないので暫定的ですが、後はきちんとスタイルを組んでいって、もうちょっと読みやすいレイアウトにしていけばいいかなって感じです。

思えば個人的な暇潰しから始まったこのプロジェクトも現在はPDFにして約200ページにもなり、きちんと一つの事柄に集中して取り組めたことは、学部時代のいい経験になったと考えています。まあ、これからも暇があればちょくちょくレイアウト、文章含めて修正していきますので、どうぞ今後ともよろしくお願いします。

2010/10/04

確率微分方程式を解くー幾何ブラウン運動、バシチェックモデルの場合

"New York Fashion Week Fall 2007: Doo Ri" by Art Comments

確率微分方程式という分野がある。どういうものかっていうと、要は確率過程を微分方程式によって表そうという試みであり、微分方程式の中に微小の確率変数が含まれている。具体的にはこんな感じ。

このdWはブラウン運動を表していて、時間がたつにつれてうねうねと確率的に動く。期待値と標準偏差はそれぞれ0と√tで、時間がたつにつれて動く場所もどんどん広がっていく。この運動はランダムウオークとか酔歩とも呼ばれていて、酔っ払ったおっさんがうねうねとあちこちに歩いているように見えることからこういう名前がついたそうな。上のような式で表すことができる確率過程を一般には『伊藤過程』と言って、他にもストラトノビッチ確率解析とかいうのもあるらしいけど、詳しくやっていないので分かりません。

これの何が便利かっていうと確率過程を通常の微分方程式のように扱えるところで、確率変数をまるで微分方程式を解くかのように求めることができる。とは言っても通常の微分方程式にはない規則がいくつかあって、初めはすごく奇妙に思えるかもしれない。

具体的には、以下のように確率変数x(t)とy(t)を定めた場合、


このy(t)もまた伊藤過程に従い、確率微分方程式dyは以下のルールに従う。


普通だったら消えるはずの2乗の項が残ってしまう。それじゃあ(dx)^2はどのようにして計算するのかというと、以下の公式に従う。


なんと、(dW)^2がdtに変化してしまう!これを『伊藤の公式』という。なんでそうなるのか?それを知りたい方は専門書を漁ればいくらでも載っているので、そこらへんを参照すればいいと思う。ここが通常の微分方程式と違うところで、逆を言えばそこさえ守ればきちんと積分によって求めることができる。専門書だとこの箇所がすごく分かり辛い表現で説明されているけど、詳細をはしょればこんな感じなはず。

それじゃあ、まず手始めに幾何ブラウン運動と呼ばれるモデル


を求めてみる。これは株価の変動を表す最も簡単なモデルなんだけど、何故これが株価の変動を表しているのかっていうのは、とりあえず解いてみれば判明するはず。

さて、普通の考えだったら『変数分離法を用いてxを分離させて、そのまま積分すればよくね?』って発想になるんだけど、何度も言っているようにこれは確率微分方程式なので、まずは伊藤の補題を用いて変数変換を行い、xを分離させてみることにする。y = ln(x)とおくと、伊藤の補題より


となる。(-1/2 σ^2)の項が出てくるところがミソで、普通に変数変換してしまうと出現しない。これで定数部分だけに分離できたので、そのまま愚直に積分を行うと、


となる。これは対数正規分布の形となっているため、株価の変動を表す簡単なモデルとなっていることは容易に理解できると思う。

それでは、次にVasicekモデルと呼ばれるモデル


について求めてみる。これは主に国債金利の利子率の時間的変動を表すモデルで、いったいこいつの何が重要なんじゃいっていうと、金融商品のリスクを推定する際に使われる。金融商品の価格は利子率によって変動するので、利子率の変動を推定することは金融商品のリスクを推定することに繋がる(*1)。つまり、今の自分のポートフォリオがどれくらいのリスクを持っているのか判断できる。そもそもこの記事を書くきっかけになったのはこいつが原因で、wikipediaさんにはただ『積分するとこれになりますよ』って書いてあるだけで、どうやって積分するのかについては書いていなかった。しょうがないので自分で手を動かして、ようやっと理解できたので公開してみようと。

さて、まずはu=b-rとおいて変数変換すると、


となる。ただ普通にChain Ruleやってるように見えるけど、たまたま結果が同じだっただけで、どんな変数変換でもきちんと伊藤の補題を使わなきゃいけない。そんで、物理やってる人はピンとくるかもしれないけど、これはランジュバン方程式の形となっているので、積分には同様の手法を利用できる。まぁ自分はピンとこなかったんですけど。それはさておき、v=e^(at)uとおいてさらに変数変換してやると、


となり、いい感じに余計な項が消えてブラウン運動だけになった。よってこれを積分してやると


あとはごちゃごちゃ整理してやると


これでwikipediaさんにあるのとおんなじ形になった。めでたしめでたし。

なんかブログに書くと導出するのは楽ちんなように思えるけど、結構悩んだし大変だった。どんなもんでも答えを見るとすぐ分かるし思いつきそうなんだけど、実際になにもない地点から思いつくかどうかっていうのはまた別な話で、それを考えると新しい学問を生み出すっていうのは凄まじいほどの労力が必要だ。実際、未だにどういう発想で量子力学を思いついたのか本気で理解できない。あんなのヒントがいくらあっても無理だ。そういうことを考えた一日でありましたとさ。

*1: もちろんこの説明は適当でないが、詳しく説明してもあんまり意味がないのでこう書くことにする

追記(2010/10/04)
1/2の項が抜けていたので修正。

2010/09/28

マルコフ連鎖モンテカルロ法を実装してみよう

"Chain Bridge, Budapest" by szeke

約2ヶ月ぶりということで、ご無沙汰しております。書きたいネタというのは結構あって書こう書こうとは思っているんですが、なにより書くとなるとあれもこれも伝えなきゃいけないみたいな思いになって、結局分量の多さから諦めてしまうというのが結構続いています。もう少し気を張らずに更新していきたいものです。

さて、最近の自分はマルコフ連鎖モンテカルロ法(Markov Chain Monte Carlo, MCMC)についておりました。何にも知らない方ににとってはよく分からないかもしれませんが、この手法はマルコフ連鎖が持つ簡明さとモンテカルロ法が持つ実用性が合わさった凄まじい手法なんです。そしてなによりとてもエレガント。

とりあえず知らない人のためにてきとーに解説しますと、与えられた適当な関数から確率変数をサンプリングするための公式です。べつにこれじゃなくても確率変数のサンプリングにはいろんなアルゴリズムがあるわけですが、これを使うと関数の計算コストがやけに高い場合だとか、ピーク部分を集中的にサンプリングしてくれたりとかで結構便利で、金融や工学、物理の分野でも非常に役立っております。計算物理をやる人にとっては必須に近い手法といっても過言ではありません。

そんなMCMCですが、実際に提案されている手法には様々なものがあります。不変分布から遷移確率を逆算するため、自由度が増えるから遷移確率は一意じゃなくなってしまうんです。今回は最も有名なMetropolis-Hastingsアルゴリズム(*1)を用いて、任意の関数に従って乱数のサンプリングを行うコードを練習がてらpythonで書いてみました。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
import math
import random

def main():
   f = lambda x: math.exp(-x*x / 10.0)
   for x, fx in metropolis(f):
       print x, fx

def metropolis(func, start=0.0, delta=2.0, burn_in=100, seed=1):
   metro_iter = _metropolis(func, start, delta, seed)
   for i, value in enumerate(metro_iter):
       if i > burn_in:
           yield value
           break
   for value in metro_iter:
       yield value

def _metropolis(func, start, delta, seed):
   random.seed(seed)
   initial_x = start
   initial_fx = func(initial_x)
   proposed_x, proposed_fx = 0.0, 0.0
   while True:
       proposed_x = initial_x + random.uniform(-delta, delta)
       proposed_fx = func(proposed_x)
       ratio = proposed_fx / initial_fx
       if ratio > 1.0 or ratio > random.random():
           initial_x, initial_fx = proposed_x, proposed_fx
           yield proposed_x, proposed_fx
       else:
           yield initial_x, initial_fx

if __name__ == '__main__':
   sys.exit(main())
うーん・・・きれいだ(*2)・・・

こいつのすごいところは、アルゴリズム自体は非常にシンプルで実装しやすいというところにあります。行数も上を見ると分かるのですがとっても少ないし、コア部分はたった25行くらいで構成されています。

なのに使っている学問は結構複雑で、定常分布から遷移行列を導出するために詳細釣り合いの条件からMetropolis的制約を用いて導出、サンプリングを行っております。このアルゴリズム自体は結構知ってる人が多いかもしれませんが、実際に理論方面で理解している人はどうなんでしょう。

んで、正規分布のガウス関数からサンプリングを行った結果がこれ。


赤線が元の確率分布。きちんとサンプリングが行われているようです。今回は正規分布で計算を行いましたが、非負の関数であればなんでも構いません。

あとはこれを研究テーマへと落とし込むことができれば、とりあえず一区切りつけるかなって感じです。

*1: 提案確率関数が対称であるという制約を持つのがMetropolis。それを非対称の場合にも拡張したのがHastings。個人的にはMetropolis-HastingよりMetropolisのほうが綺麗で好きです。というか提案確率密度関数が非対称じゃないといけないようなシチュエーションがよく分からない
*2: yieldとジェネレータって便利ですよね。計算速度も効率的だし、慣れてくるとすべて遅延評価で行わせたいくらい

2010/07/23

ドルコスト平均法は賢い投資方法と言えるのか? 補足

"Pyramid of Capitalism" by Warren Noronha


以前ブログの記事を読んでいただいた友人から感想を伺うと、「なんかよく分からない」といった感想が帰ってきました。基本的に説明が不足しているなぁと思った箇所は実際いくつもあって、金融の確率論を少しでもやると大体感覚的に理解できるのですが、普通の人はそんなのやらないのが当たり前ですので、基本的な概念について少し説明したいと思います。この分野に興味ない人でもちょこちょこと面白そうな話を挟んでいくので、暇つぶしに見てやってください。

1. 確率変数、期待値、分散

確率変数というのは試行によって出てくる値が確率的に異なってくる変数のことです。これは抽象的なので、もうすこし具体的にいきましょう。例えば、以下のコイントスゲームを考えます。最初あなたは1万円を所持していたとして、表であれば所持金が2倍となり、一方で裏であれば所持金が0.5倍、つまり半分になります。このような試行を3回行ったとして、最終的な資金額をXと表すと、このゲームは以下の式で表せます。


ここでのX1はそれぞれの試行の確率変数に相当し、50%の確率で0.5, 50%の確率で2.0の値をとります。
で、これだけではただ定式化しただけで、何にも面白いことは分かりません。ですがこいつの期待値と分散を求めてやることで、このゲームは得なのか損なのか、またどれくらいのリスクがあるゲームなのか調べてやることができるのです。

例えば、Xの期待値をE[X]としてやりましょう。ここで、期待値の性質として以下を確認しておきましょう。まず、XとYが確率変数とすると、その和の期待値は単純にそれぞれの期待値の和で表せます。


また、XとYが独立(それぞれの試行がもう一方の試行に影響を及ぼさない)であるとすると、その積も同じような性質を持ちます。


この性質を用いると、Xの期待値は以下のように表せます。


つまり、このゲームを行うことによってあなたは9500円くらいの利益を得ることが期待できます。もうこれはやるっきゃないと。

このゲームが得であることは理解できましたが、ただこのゲームにどれくらいリスクがあるのかは不透明です。期待値が10000円プラスになるからといって、40%の確率で全財産を失ってしまうみたいなゲームですと、普通は行いたくないですよね。このリスクについて求めるためには分散を計算してやればいいのですが、これはそれなりに面倒です(*1)。前回ごっちゃごっちゃやってたのはこの面倒さによるものが大半ですので、今回は説明しません。とりあえず分散がリスクに対応しているということが大事です。

世の中の投資行動には常にリスクとリターンが付きまといます。一般的にリスクとリターンは紙一重と言われており、リスクの高い行動はよりリターンも大きいというのが感覚的な理解です。ただ、このリスクとリターンを確率変数を用いて計算することによって、どの行動が一番リスクとリターンのバランスが取れている行動であるのか、判断することができます。

で、どの戦略を用いれば合理的に資産を増やすことができるのかという問題ですが、実はこの戦略は既に知られており、ある戦略を用いればリスクをリターンに変化させることで指数関数的に資産を増やすことができます。その戦略について興味がある方は適当に調べると出てくると思います。

2. なぜ乗法モデルを仮定しているのか?

まず、株価の変動は確率的であるから確率変数として表せるという話は納得できると思います。では、株価などの資産モデルには様々なものがあるのに、なぜそれぞれの確率変数が独立と仮定した乗法モデル


をわざわざ採用するのでしょうか?別に、例えば


のような加法モデルでも構わないわけです。何故なんでしょう?

まず独立と仮定した理由については、単に計算が楽だからです。正直独立と仮定しないと、ここまで綺麗な形がでるのか、そもそも解析的に解けるのかどうかすら分かりません。ただこれを仮定したことによって、ごちゃごちゃ計算できて結果的にそれなりに綺麗な数式へと展開することができたという次第です。

乗法モデルを仮定した理由については、金融業界の指数関数的な性格によるものです。例えば、ローンなんかは年利15%ーフリーローンですとこんくらいでしょうかーとありますが、これは1年間につきローンが15%増加していくので、ふるまいとしては指数的になります。同様に、国債についても年利で計算するので指数的な計算となります。金利が低いといってほいほい借金をすると危険だという理由もこれによるものです。逆に、金持ちがより金持ちになる理由の一つでもあります。

これは個人的な意見ですが、金融の世界で乗法モデルが成り立っている理由は、人間が金に対して貧欲であるからだと思っています。はっきりと言いますが、世の中の結構な割合の人間は指数的なふるまいを理解できません。ですからマイホームを数十年ローンでぽんと買ってしまったり、リボ払いで決済をしたりしてしまいます。

ちなみに、これらの金額はすべて年金公式と呼ばれる公式で算出できます。1期間後に支払いを始め、n期間にわたって金額Aを支払う場合、金利をrとおくと借入額Pは


もしくは


と表せます。これはすごく役立つ公式なので、店員の言葉に騙されないでおくこともできるかもしれません。ついでに、ローンを借りて全額返した場合に損をする差額はnA-Pで計算できて、


となります。こういう情報ってあんまり表沙汰にならないんですけれど。

追記(10/08/23)
上の式は正直汚いからどんな振る舞いをするのか感覚的に理解し辛いですけど、利率が少ない、つまりrが微小のときは (1+r)^n ~ 1 + nr で近似できますから損失額は


となります。ですから利率が低いときは、分割回数をちょっと多くしても線形的な負担にかならない。確かに損失額が増えることは確かですけど、一括払いで生活に支障がでるよりは、3, 4回くらいローンで払うっていう選択肢もありなのかもしれません(*2)。

*1: 1次元のising模型の解析解を求めたり、極座標のラプラシアン導出するのよりは面倒じゃない
*2: ただそこまでして本当に欲しいものかそれっていう疑問はありますし、30年ローンとかで家を購入するような場合には全く通用しません。そもそもこのご時勢に長期のローンを組むなんて狂気の沙汰です。狂っている。

2010/06/05

BLESS by Overture


BLESS from Overture on Vimeo.

KiraKiraというアイスランドのミュージシャンの音楽PV。作ったのはOvertureというアメリカのユニット。

これの何が凄いのかっていうと、たった2人の夫婦によって作られたっていうところです。やった人は分かると思うんですが、アニメーション制作というのは本当に大変です。それを夫婦の共同作業でやっちゃってるところが仲良さそうで素敵。しかもその作品もとても個性溢れていて、気持ちがいいなぁと思う作品でした。

ブログも良かったらごらんになってください。奥さんが日本人なので片方は日本語で書かれています。

2010/05/31

ドルコスト平均法ははたして賢い投資方法と言えるのか? part2

"Soviet poster of the transport sector during the Five Year Plan. 1930" by National Library of Scotland

3. 計算

前回の記事で株価が乗法モデル


に従った場合の一般投資戦略とドルコスト戦略の資産はそれぞれ



で与えられることが分かりました。

それではこれよりリスクの定量的評価を行います。私たちが知りたいのは、それぞれの資産のリスクとリターンの値です。この場合リターンは確率変数の期待値、リスクは確率変数の分散(より正確に言うと標準偏差)にそれぞれ対応していることが分かりますので、 XN の期待値と分散をそれぞれ求めてやればよさそうです。
3.1 期待値の計算
まず簡単な期待値から調べていきましょう。 Ri と Rj は i≠j の場合独立であり、さらに Ri の期待値を μ 、分散を σ2 と仮定しているため、 XN(1) の期待値は


XN(2) の期待値は


となります。
3.2 分散の計算
次に一番知りたい分散についてですが、正直これは期待値に比べて少々面倒くさい。これは分散が期待値のような線形的な関係を持たない上に、ドルコスト平均法の Ri の項が折りたたまっているために生じているのですが、そんなことを憂いていても仕方がないのでさっさと計算していきます。

まず比較的簡単な XN(1) の分散ですが、


ここで右式の V にのみ注目すると、分散の定義より


関係式


に注意すると、上式は


となりました。よって XN(1)


と表現できます。これは比較的何も悩まずに展開できました。

次にドルコスト戦略 XN(2) について同じように求めていきます。


2つの項が現れました。それぞれの項は結構面倒ですので、分けて考えることにします。まず第二項についてですが、


次に第一項について計算します。まず


ここで


についてそれぞれの Rk で乗算し、独立性から期待値を分割して求めるわけですが、きちんと注目してやると
  • Rk となっている変数は全部で |i-j| 個
  • Rk2 となっている変数は全部で min(N-i+1, N-j+1) 個
となっているため、上式は


と展開できます。

ここで対称性について考えます。当たり前ですが i と j を反転させても上式の値は不変であるため、反転対称性から上式は以下のように展開できます。


以上から、 XN(2) の分散の値は


となります。ここで、数式を見やすくするために


と定義しておくことにし、便宜的にこの変数を『修正バリアンス』とでも名づけておきます。この命名が正しいのかどうか、そもそも名前がつけられているのかについてはよく分かりません。

この分散、和の項が3つ並んできたり少々面倒くさい形になっていますが、よくよく注目してみると σ に関して単調増加の形をしており、 σ=0 を代入すると結果に0が帰ってきたりとちゃんとしたリスク関数になっているのが確認できます。ただこの関数が一般投資戦略に比べてリスクを分散する形になっているかどうかはちょっと判別しにくいですね。

まぁそんなこんなで XN(1) と XN(2) それぞれにおける期待値と分散を求めることができました。次回はこの関数を利用して定量的な調査を行っていきます。
Note. σに関して単調増加であることと0であることの説明
まず、式の形よりVN(2)はσに関して単調増加関数であることは自明。
次にσ=0を代入すると修正バリアンスはμ2になるので、次数を調整した後で合計のラベリングを変更してやると、


となる。