人工知能に関する断創録

このブログでは人工知能のさまざまな分野について調査したことをまとめています(更新停止: 2019年12月31日)

クモの巣図法

指数的成長モデルとロジスティックモデル(2011/2/19)のつづき。

ロジスティックモデルはどの初期値から始めてもフィードバックループをまわすと最終的に0.5に引き込まれることがわかる。この引き込まれる軌道を視覚的にグラフ化したのがクモの巣図法。まず、指数モデルでクモの巣図法を描いてみた。

#coding:utf-8
import numpy as np
from pylab import *
import matplotlib.lines as lines

"""クモの巣図法を描画"""

def drawGraph(func):
    """関数funcを描画"""
    xList = []
    yList = []
    for x in np.arange(-1.0, 1.0, 0.01):
        xList.append(x)
        yList.append(func(x))
    plot(xList, yList)

def drawCobweb(func, initial):
    """funcの軌道に対するクモの巣図法を描画"""
    vertices = []
    # 初期座標
    x = initial
    y = 0
    vertices.append([x, y])
    for n in range(1, 13):
        # 垂直方向
        y = func(x)
        vertices.append([x, y])
        # 水平方向
        x = y
        vertices.append([x, y])
    vertices = np.array(vertices)
    plot(vertices[:,0], vertices[:,1], '--')

if __name__ == "__main__":
    # y = xを描画
    drawGraph(lambda x: x)
    # y = 2xを描画
    drawGraph(lambda x: 2 * x)
    # 初期値を変えてクモの巣図法を描画
    drawCobweb(lambda x: 2 * x, 0.01)
    axis([-0.2, 1.0, -1.0, 1.0])
    grid(True)
    show()

f:id:aidiary:20110220094843p:plain

クモの巣図法では、対象の関数fを y = x とともに描く。任意の初期値 x = 0.01 から初めてまず上に垂直線をひく、fと接したら y = x にぶつかるまで水平に線を引く(これは、出力値f(x)をフィードバックさせて新たなxにすることを意味する)。これをずっと繰り返すだけ。指数モデルでは、どこにも引き込まれず発散してしまう様子がわかる。次にロジスティックモデル。

f:id:aidiary:20110219222441p:plain

前回、書いたようにフィードバックループを繰り返すと0.0から1.0のどの初期値から初めても最終的に0.5に引き込まれる。これをクモの巣図法で描くと、

#coding:utf-8
import numpy as np
from pylab import *
import matplotlib.lines as lines

"""クモの巣図法を描画"""

def drawGraph(func):
    """関数funcを描画"""
    xList = []
    yList = []
    for x in np.arange(-0.1, 1.0, 0.01):
        xList.append(x)
        yList.append(func(x))
    plot(xList, yList)

def drawCobweb(func, initial):
    """funcの軌道に対するクモの巣図法を描画"""
    vertices = []
    # 初期座標
    x = initial
    y = 0
    vertices.append([x, y])
    for n in range(1, 13):
        # 垂直方向
        y = func(x)
        vertices.append([x, y])
        # 水平方向
        x = y
        vertices.append([x, y])
    vertices = np.array(vertices)
    plot(vertices[:,0], vertices[:,1], '--')

if __name__ == "__main__":
    # y = xを描画
    drawGraph(lambda x: x)
    # y = 2x(1-x)を描画
    drawGraph(lambda x: 2 * x * (1 - x))
    # 初期値を変えてクモの巣図法を描画
    for initial in np.arange(0.0, 1.0, 0.2):
        drawCobweb(lambda x: 2 * x * (1 - x), initial)
    axis([0.0, 1.0, 0.0, 0.6])
    show()

f:id:aidiary:20110220094844p:plain

どのxから初めても最終的に座標 (0.5, 0.5) に引き込まれることがわかる。この軌道には経験則があり、グラフが対角線 y = x の上にあれば軌道は右に動き、対角線の下にあれば軌道は左に動く。f(p) = pのとき、点pは不動点と呼ばれる。不動点は、y = f(x) と y = xの連立方程式を解くことで求められる(つまり、関数f(x)と直線の交点)。上の場合、x = 0とx = 0.5が不動点(yの値はxと同じなので無視)。例1.3の  f(x) = (3x - x^3) / 2 も描いてみた。

#coding:utf-8
import numpy as np
from pylab import *
import matplotlib.lines as lines

"""クモの巣図法を描画"""

def drawGraph(func):
    """関数funcを描画"""
    xList = []
    yList = []
    for x in np.arange(-2.0, 2.0, 0.01):
        xList.append(x)
        yList.append(func(x))
    plot(xList, yList)

def drawCobweb(func, initial):
    """funcの軌道に対するクモの巣図法を描画"""
    vertices = []
    # 初期座標
    x = initial
    y = 0
    vertices.append([x, y])
    for n in range(1, 13):
        # 垂直方向
        y = func(x)
        vertices.append([x, y])
        # 水平方向
        x = y
        vertices.append([x, y])
    vertices = np.array(vertices)
    plot(vertices[:,0], vertices[:,1], '--')

if __name__ == "__main__":
    # y = xを描画
    drawGraph(lambda x: x)
    # y = (3x-x^3)/2を描画
    f = lambda x: (3 * x - x ** 3) / 2
    drawGraph(f)
    # 初期値を変えてクモの巣図法を描画
    drawCobweb(f, 1.6)
    drawCobweb(f, 1.8)
    axis([-2.0, 2.0, -2.0, 2.0])
    grid(True)
    show()

f:id:aidiary:20110220094845p:plain

不動点には、沈点(吸引的不動点)と源点(反発的不動点)の2種類がある。下の図では不動点は、-1.0, 0.0, 1.0の3個ある。-1.0と1.0に近い点(例では-1.2と0.9)は-1.0、1.0に吸引されるのに対し、0.0に近い点(例では-0.2と0.2)は0.0から離れていく。そんなわけで-1.0と1.0は沈点で0.0は源点と呼ばれる。沈点はボールが安定する谷底で源点はボールが不安定な山頂をイメージすればいい。

f:id:aidiary:20110225152302p:plain