デザイナーである佐藤可士和の仕事術を,「整理」というキーワードを軸にまとめあげた1冊.整理といっても,ただ単純に部屋や机の上の小綺麗に整理するということだけではない.そういった空間の整理方法を,情報や思考といった考え方にも当てはめることで,仕事における問題解決や効率化を目指すという形となっている.この話の流れからすると,部屋の整理術を無理矢理当てはめているんだろうと感じるかもしれないが,佐藤可士和の考える整理というものは,実は空間・情報・思考が互いに深く関係したものであることが読み進めるうちに判明してくる.机の整理をするには情報の整理が必要であり,情報の整理をするには思考の整理をする必要があるといったように,それぞれのレイヤーで何をすべきか,そしてどういった整理法がポイントになってくるかが,佐藤可士和の代表的な仕事を例に挙げながら詳しく語られる.

本書の内容は,デザイナーや整理という単語から連想するイメージとは全く違ったものになっている.それは自分の性格や審美眼のような右脳的な能力に頼るのではなく,突き詰めて合理的に考えて細かな部分にもきちっと論理的な解釈を加えるという左脳的な能力を重視している点にある.奇抜なアイデアや突拍子もない行動の裏にある,徹底的に言語化された理論武装があることを知ると,佐藤可士和のデザインがなぜ広告の消費者である私たちに驚きや深い印象を与えたり,デザイナーが意図したイメージをそのままに伝えることができるのかが分かるだろう.デザインの制作過程で語られる試行錯誤の跡であったり情報の整理方法は,最終的に出来上がったものと見比べながら解釈することができて,非常に興味深いものになっている.

最近では工業デザインやUI/UXが注目されるようになり,外側の形を製品の機能とは別に考えるのではなく設計に組み込んでしまうというデザイン思考という総合的な言葉も出てきているが,本書はまさにその流れを整理という言葉で言い換えているだけで,主張することはほとんど変わらない.実際の手法に関してはそれぞれのスタイルで異なっているが,デザインと機能を両立して製品なりロゴなりを作り上げるという点では同じアプローチだと言える.

少し前の本だと思って軽い気持ちで読み始めたが,中身を開けてみると意外としっかりして現在のデザイン思考と比べても遜色ない内容となっていて驚いた.整理本という括りがもったいないと思えるほど,プロダクトデザインの教科書としても良書だと思う.



10年近く前に大ヒットとなった,自己啓発ブームのさきがけのような1冊.2匹のネズミと2人と小人がチーズを探すという寓話を通して,成功を追求することや変化を恐れずに行動を起こすことの重要性が語られる.

本書は寓話を使った切り口でありながら,回りくどい方法で読者に主張したいことを伝えるのではなく,冒頭の文章でまずはじめに私たち自身の単純さと複雑さの象徴が寓話に登場するネズミと小人であることが語られる.そして,元クラスメートだった数人が大人になって久しぶりに会って食事しているというシチュエーションのもとで,そのうちの一人がこの寓話の話をし始める.実際にネズミと小人の寓話が語られた後に,話を聞いた他の参加者が,その寓話をどう読み解くかを議論したり感想を述べたりするという構成となっている.

寓話の内容はとても簡単だ.ネズミと小人はそれぞれチーズを探して迷路をさまよう毎日を過ごしている.チーズはどこにあるかわからない.ひとたび大きなチーズが見つかればしばらくは食いつなぐことができるのだが,それも時間が経つとともに食べてなくなってしまうし,その場所にまたチーズが置かれるかどうかもわからない.そうした環境のなか,ネズミは何も考えずにチーズを探すことに専念し,環境の変化に敏感で常に新しい行動を起こすことに抵抗がない.一方で,小人の方は物事を複雑に考えがちで,単にチーズが無くなることに筋の通らない理屈を結び付けたがったり,今までの成功に囚われて生活を変えることができない.その両者が,それまで同じような生活をしていた中で,ある場所で好みのチーズを発見するところから物語は始まる.そして,その好みのチーズを見つけた後に,ネズミと小人それぞれのチーズ探しに対する態度はがらりと変わってしまうことで話は進んでいく.

古本屋で見つけたので,買って読んでみたという感じ.この本を今更読むのはどうなのと思うけれども,まあ話が陳腐になってるといったわけでもないので,気になる人は読んでみるといいかもしれない.はまる人にとっては教訓を得られるだろうし,はまらない人でも教養程度にはなるだろう.物語が終わった後の解釈の部分も含めて上手くまとまっているし,何よりページ数が少ないので空いた時間にでも読みきれる程度のものだ.自己啓発の本としては,長々と意味不明な理論展開されて読後感が悪いのもあるけれども,この本に関しては物語をどう捉えるにしろ,こんな素晴らしい本を読めてよかったとか意味なかったけどこれくらいの時間の浪費なら別に…といったように,キッパリ割り切れるところがいいのかもしれない.個人的には好きな類の本ではある.



内容:確率的勾配法(Stochastic Gradient Methods)で関数の最大値を求める

目的関数からの直接的なシミュレーションが難しい場合,関数の表面をローカルになぞって最大値を探索するという手法が使える.探索に用いる系列は以下のように表す事ができる.

\theta_{j+1} = \theta_j +  \varepsilon_j

これは現在のステップに摂動項\varepsilon_j を加えて次のステップとすることを表している.つまりこれはマルコフ連鎖となるのだが,今回はそれほどマルコフ性は重要にはならない.

概念的に目的関数の分布を山の斜面と考えるならば,現在の位置からちょっと動いて…を繰り返して山を登っていくような動きをする.ただし,単純に傾斜の上の方に登っていくのではなく,どちらかに進むかはランダムなので,たまに斜面を下ったりもする.その試行を繰り返していくことで,山の頂上を目指すような方法となっている.

有限差分法

有限差分法では,関数の勾配は

\nabla h(\theta_j) \approx \frac{h(\theta_j+\beta_j\zeta_j)-h(\theta_j-\beta_j\zeta_j)}{2\beta_j}\zeta_j = \frac{\Delta h(\theta_j,\beta_j\zeta_j)}{2\beta_j}\zeta_j

とし,摂動項\varepsilon_j を組み込んだ系列の更新は以のようになる.

\theta_{j+1} = \theta_j +  \frac{\alpha_j}{2\beta_j}\Delta h(\theta_j,\beta_j\zeta_j)\zeta_j

例 5.7 有限差分法による関数の最大化において,複数の勾配パラメータがどのように収束に影響するかを調べる

例5.6の続き.有限差分法を用いて以下の式を最小化することを目的とする.

h(x,y)=(x\sin(20y)+y\sin(20x))^2\cosh(\sin(10x)x)+ (x\cos(10y)-y\sin(10x))^2\cosh(\cos(20y)y)

今回は最大化ではなく最小化することが目的なので,この関数をマイナスにする必要がある.

1
2
3
4
h <- function(x){
  -(x[1]*sin(20*x[2]) + x[2]*sin(20*x[1]))^2 * cosh(sin(10*x[1])*x[1]) -
    (x[1]*cos(10*x[2]) - x[2]*sin(10*x[1]))^2 * cosh(cos(20*x[2])*x[2])
}

アルゴリズム

  • 勾配の値が10-5 になるまで以下を繰り返す
    1. \zeta_j を生成する
    2. \theta_{j} を使って勾配\frac{\alpha_j}{2\beta_j}\Delta h(\theta_j,\beta_j\zeta_j)\zeta_j を生成する
    3. \theta_{j}+\varepsilon_j \theta_{j+1} とする
    4. \alpha_j \beta_j を更新する

なお,実際のソースコードでは勾配の値が発散しないように,scaleが1以上になった場合には内部でループをして値を再計算するようにしている.


\zeta_j の生成方法と有限差分法における役割

さて,ここで有限差分法のポイントとなる\zeta_j に関して,実際にどうやって値を生成するのか,そしてこの値がどういう意味を持っているかについて考えてみる.

まずは\zeta_j の生成方法について.本文中では\zeta_j は単位球\| \zeta_j \| = 1 上に一様に分布しています」とあるだけで,コードの方を参照してみてもzeta / sqrt(t(zeta) %*% zeta)としか書かれていない.ではこれは一体何をしているのかというと,一言で言うと「球面上の一様分布から乱数を生成する」,つまり今回の場合は単位円の円周の上からある一点を取ってきて\zeta_j の値にするということをしている.

このような球面上の一様分布に関しては「Rによる計算機統計学」のP.96に詳しく書かれており,この本ではD次元の球面上の一様乱数を生成する方法についてrunif.sphere()関数を定義している.今回の場合はxとyの2次元について考えているので,「Rによる計算機統計学」に倣ってrunif.sphere(1,2)とすれば,\zeta_j と同様の値が得られる.

1
2
3
4
5
6
7
8
9
10
11
12
# Rによる計算機統計学 P.87より
# http://personal.bgsu.edu/~mrizzo/SCR/SCRch3.R
runif.sphere <- function(n, d) {
    # return a random sample uniformly distributed
    # on the unit sphere in R ^d
    M <- matrix(rnorm(n*d), nrow = n, ncol = d)
    L <- apply(M, MARGIN = 1,
               FUN = function(x){sqrt(sum(x*x))})
    D <- diag(1 / L)
    U <- D %*% M
    U
}

次に,有限差分法における\zeta_j の役割について考えてみる.

そもそも,確率的勾配法はローカルに関数の表面をなぞるように探索して,値の大きいポイントを探す確率的なアプローチだった.概念的には,前回3Dプロットをしたような山みたいになっている関数の上をあちこち動いて頂上を探し出すということだが,あちこち動きまわるためには,歩く「方向」と「距離」を考えなければならない.今回の有限差分法における勾配は\varepsilon_j = \frac{\alpha_j}{2\beta_j}\Delta h(\theta_j,\beta_j\zeta_j)\zeta_j で表されていたが,その「方向」が\zeta_j ,「距離」が\frac{\alpha_j}{2\beta_j}\Delta h(\theta_j,\beta_j\zeta_j) に対応している.

では実際に\zeta_j と勾配\varepsilon_j を図示して,「方向」と「距離」の意味を確かめてみよう.以下の図は,\zeta_j の取りうる単位円と,赤い矢印\zeta_j ,黒い矢印\varepsilon_j を示した図になっている(j=1 ).この図を見ると,赤い矢印で方向が示され,黒い矢印でどれくらいの距離を進むかが見て取れる.\zeta_j は乱数で生成された値なので,本書の「そのつど方向をランダムに選択する」という勾配の説明の通り,単位円の円周上からどこか一点を選択して進む方向を決めている.

といったように,この有限差分法では関数の山の傾斜を考えて進む方向を決めるのではなく,何も考えずに動いてみるといったアプローチとなっている.ただし,距離に関しては別で,関数を使って傾斜を見つつ調整しているので,その点は注意.

1
2
3
plot(runif.sphere(1000,2), xlim=c(-2,2), ylim=c(-2,2), cex=0.1)
arrows(0,0,grad[1],grad[2], lwd=2)             # 黒の矢印が勾配
arrows(0,0,zeta[1],zeta[2], lwd=2, col="red")  # 赤の矢印がゼータ

今回実験を行う4つのシナリオ

この有限差分法において,\alpha_j \beta_j の系列の更新式は任意に設定できる.今回は4つのシナリオを用意して実験を行った.それぞれのシナリオの更新式は以下の通り.

  • シナリオ1:1/\log(j+1) 1/\log(j+1)^{0.1}
  • シナリオ2:1/100\log(j+1) 1/\log(j+1)^{0.1}
  • シナリオ3:1/(j+1) 1/(j+1)^{0.5}
  • シナリオ4:1/(j+1) 1/(j+1)^{0.1}

(※シナリオ1と2に関しては後述の「本問題の疑問点」を参考)

例 5.7のソースコード

前置きがだいぶ長くなってしまったが,本題のソースコードおよび4つのシナリオにおける確率的勾配法の探索過程を示した図は以下のようになる.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
h <- function(x){
  -(x[1]*sin(20*x[2]) + x[2]*sin(20*x[1]))^2 * cosh(sin(10*x[1])*x[1]) -
    (x[1]*cos(10*x[2]) - x[2]*sin(10*x[1]))^2 * cosh(cos(20*x[2])*x[2])
}

start <- c(0.65, 0.8)
theta <- matrix(start, ncol=2)
dif <- 1
iter <- 1
alpha <- 1
beta <- 1

while(dif > 10^-5){
  zeta <- rnorm(2)
  zeta <- zeta / sqrt(t(zeta) %*% zeta)
  grad <- alpha[iter]*zeta * (h(theta[iter,]+beta[iter]*zeta) -
    h(theta[iter,]-beta[iter]*zeta)) / 2*beta[iter]
  scale <- sqrt(t(grad) %*% grad)
  while(scale > 1){
    zeta <- rnorm(2)
    zeta <- zeta / sqrt(t(zeta) %*% zeta)
    grad <- alpha[iter]*zeta * (h(theta[iter,]+beta[iter]*zeta) -
      h(theta[iter,]-beta[iter]*zeta)) / 2*beta[iter]
    scale <- sqrt(t(grad) %*% grad)
  }
  theta <- rbind(theta, theta[iter,]+grad)
  dif <- scale
  iter <- iter + 1

# scenario1
  alpha <- cbind(alpha, 1/log(iter+1))
  beta <- cbind(beta, 1/(log(iter+1))^(0.1))
}

hcur <- h(start)
hval <- h(start)
x <- seq(-1,1,le=435)
y <- seq(-1,1,le=435)
z <- matrix(0, nrow=435, ncol=435)
for (i in 1:435){
  for (j in 1:435){
    z[i,j] <- h(c(x[i], y[j]))
  }
}

image(x, y, z, col=terrain.colors(150))
lines(theta, lwd=2)
points(theta[1,1], theta[1,2], col="gold", pch=19)
title(main="scenario 1")

シナリオ2,3,4の場合は,whileループの最後の\alpha_j \beta_j の更新式を以下の通りにする.

1
2
3
4
5
6
7
8
9
# scenario2
  alpha <- cbind(alpha, 1/(100*log(iter+1)))
  beta <- cbind(beta, 1/(log(iter+1))^(0.1))
# scenario3
  alpha <- cbind(alpha, 1/(iter+1))
  beta <- cbind(beta, 1/sqrt(iter+1))
# scenario4
  alpha <- cbind(alpha, 1/(iter+1))
  beta <- cbind(beta, 1/(iter+1)^(0.1))

上の図の解釈だが,この4つのシナリオの場合において

  • シナリオ1では,動きまわる距離が大きすぎて(\alpha_j が収束するのに時間がかかって)なかなかアルゴリズムが停止しない
  • シナリオ2では,動きまわる距離が小さすぎて(\alpha_j がすぐ収束してしまって)ローカルミニマムにはまっている
  • シナリオ3では,動きまわる距離はシナリオ2より改善しているが,最大値を見つけられていない
  • シナリオ4では,上手い具合に最大値を見つけることができている

ことが分かる.

なお,この解釈は本書(P.156)に書かれているものとは多少異なっているということを注意していただきたい.それに関しては次の疑問点のところで述べる.

本問題の疑問点

さて,この問題を素直に解いてもP.157の図5.7のようにはいかない.色々と試してみた結果,どうやら本書におけるシナリオ1と2の\beta_j において,分母にかかっている0.1乗の表記がおかしい気がする.この0.1乗がlogの中の括弧にかかっていると考えて0.1*log()としてコードを組むと,値が発散しすぎてなかなか収束しなくなる.ということで,ここでは以下のように式を解釈して問題を解いた.正直なところ,これが正しいのかよくわかっていない.

  • シナリオ1と2の\beta_j \frac{1}{\log(j+1)^{0.1}} \frac{1}{(\log(j+1))^{0.1}}

これにともなって,シナリオの図示や解釈にも少し違いが出てきている.そのため,今回は本書の解説(P.156)からは少し外れることになったが,自分がスクリプトを回して得た結果を解釈に用いた.



このタイミングで読まなければ意味が無いと思って購入した1冊.この分野には馴染みがありiPS細胞に関して大体のところは把握していたのだが,それでも色々と面白い部分があり,自分の理解を再確認する意味でもなかなかに読み応えがある内容だった.

本書は2012年のノーベル生理学・医学賞を受賞された京都大学の山中伸弥教授の研究遍歴などについて書かれた自伝的作品である.前半部では主に,山中先生が研究を目指されたきっかけであったり学生時代や研究時代の様々な逸話を通して,その研究観であったり興味の移り変わりが語られる.そして,グラッドストーン研究所への留学や奈良先端科学技術大学院大学の助教授就任,京都大学への再生医科学研究所への転属といった研究の道を歩まれる中で,ノーベル賞受賞へと導いたiPS細胞の研究の話へとつながっていく.また,後半には対談形式で現在の研究に関する話も収められている.

題材としては研究人生であったりiPS細胞であったりと専門性があり難しい内容でありながら,語り口は非常に軽く,欄外の注釈や写真も充実しているなど,中学生・高校生から一般の人にとっても問題なく読める書き方をされている.例えばiPS細胞の遺伝子と転写因子の関係を本としおりに喩えて説明されているなど,その生物学的な特徴や細胞をリプログラミングする仕組みのみならず,研究する動機となったES細胞の倫理的側面や今後の医療への応用の展望などもあわせて紹介されている.

ノーベル賞受賞を受けて出版というだけあって,ニュースだけの情報に物足なさを感じる人向けの気軽に読める1冊となっている.iPS細胞というトピックに関して,現状としては取り敢えず今は本書を読んでおけば問題ないんじゃないだろうか.ただし,これから問題になるであろう倫理問題や研究を促進するための法的整備などの詳しい話はあまり触れられていないので,そっちが読みたい人はむしろ少し前のES細胞周りの文献を当たった方が良さそうな気がする.個人的な要望としては,もう少し世間が落ち着いてiPS細胞に対する評価がまとまった頃に,今度はもっと詳しい内容で研究競争などの専門的な話を盛り込んだ本を出していただきたいところ.



一言で言うと

「データ解析のための統計モデリング入門」P.157 図7.8とP.158 図7.9の分布を混ぜる過程をアニメーションにした.無限混合分布に関して手元の資料であまり情報が無かったことがあり,検算のためにと計算したときに作ったものだが,意外とうまく作れたんじゃないかと思う.

GLMMの最尤推定と積分

個体差r_i を考慮に入れた今回のGLMMでは,尤度L_i を以下の式のように積分をしてr_i を消す.

L_i = \int_{-\infty}^{\infty}p(y_i|\beta_1,\beta_2,r_i)p(r_i|s)dr_i

これはすなわち,p(y_i|\beta_1,\beta_2,r_i)p(r_i|s) を混ぜあわせた無限混合分布となっている.

アニメーション作成過程

今回は,P.157 図7.8とP.158 図7.9の2つの図をアニメーションとして表現してみた.それぞれの実験のパラメータは以下の通り.

  • 二項分布と正規分布

    • \beta = 0
    • q = \frac{1}{1+\exp(-(\beta + r))}
  • ポアソン分布と正規分布

    • \beta = 0.5
    • \lambda = \exp(\beta + r)

ただし,無限混合分布に関しては,きちんと積分をして値を求めているわけではなく,rを細かく分割してそれぞれ計算した後に足しあわせているだけなので,あくまでも模式図ということで.

結果

gifアニメーションは少し容量が大きいので,以下のリンク先で公開している.

以下のプロットは,その中から1枚だけ抜き出した例となっている.左の図は二項分布/ポアソン分布の変化,中央の図は正規分布とr の値,右の図は混合分布の変化を示している.rを小さい値から大きい値にかけて変化させていったときの,二項分布/ポアソン分布の変化と混合分布の形の変化がわかる.

以下ソースコード.