ひらめの日常

日常のメモをつらつらと

『レガシーコードからの脱却』を読んだ

はじめに

ITエンジニア本大賞を受賞していて、気になっていた本です。

「レガシーコードを作らないようにするためのプラクティス」が紹介されている。テストやリファクタリングではなく、「よい開発者は机をきれいにしている」といったマインドセットが解説されているのが特徴だ。

codezine.jp

学びが多かったので印象に残ったところを残しておきます。

まとめ&感想

レガシーコードはなぜ生まれてしまうのか、そしてどのようにしたらレガシーコードやいわゆる技術的負債に陥らないのかについて書かれていました。アジャイル開発とテスト駆動開発の関連性、そしてそれらから得られるコード保守性に関する説明が非常にわかりやすかったです...!

開発者として非常に共感する内容が書かれていたり、

開発者がほとんどの時間を費やしているのはコーディングではない。仕様書を読み、ドキュメントを書き、会議に出席するのに時間を費やす。そして、デバッグに一番多くの時間を消費しているのだ。

少し捻ったかっこいい表現があったりと、読んでいて楽しかったです。

私たちは言葉を通じて世界を体験し理解する。ソフトウェアを作るのも、結局言語的な活動なのだ。

個人的には、もっとペアプログラミングをして、知識を伝達しあう営みを行うと、エンジニアとしても満足度が上がるし、プロダクトとしてもより保守性の高いものに出来上がっていきそうだと感じました。

特に印象に残ったところ

レガシーとは

毎日実行され、過去の意思決定をもとに逃れようのない影響を及ぼし続けるが、なんの活力もないコードがある。このコードを丁寧な言葉で「レガシー」と呼ぶ。

第一原理

以下のものが例として挙げられている。

  • 単一責務の原則。「クラスを変更する理由は1つでなければならない」
  • オープン・クローズドの原則。「ソフトウェアのエンティティは、拡張に対して開いており、変更に対して閉じてなければならない」

この辺の原則は SOLID原則 から取ってきているような気がする。

開発者が知っておくべきSOLIDの原則 | POSTD

なぜよいソフトウェア開発のためのプラクティスを知る必要があるか(抜粋)

  • 使われるソフトウェアは、必ず変更が必要になる。なので、変更可能であるように書かれる必要がある。
  • 何かを正確にモデリングするためには、まずはその対象を理解しなければならない。

良いストーリーを書くための戦略

アジャイルの文脈でいう)ストーリーとは、「誰のため」に「何を作る」のかに集中しやすくするためのもの。

  • プレースホルダーとしてみる
    • ストーリーはプロダクトオーナーと開発者の間の会話を取り持つものとして捉える。
  • 目的に注目する
    • ストーリーは How ではなく What に焦点を当てる。
  • 「誰」を擬人化する
    • ユーザーを理解する助けとなる。
  • なぜ機能が必要とされたかを知る
    • ストーリーの「〇〇のために」という部分に注目し、機能開発のためのより良い選択肢を探す助けとなる。
  • シンプルに始めて追加は後で行う
  • エッジケースを考える
  • 受入基準を利用する

実装の詳細ではなく、目的や制約を説明するために、「目的、理由、誰のためか」を明文化する。

ソフトウェア開発を計測するための戦略

  • 価値実現までの時間を計測する
  • コーディングに使った時間を計測する
  • 欠陥密度を計測する
  • 機能ごとの顧客価値を計測する
  • 機能を提供しない場合のコストを計測する
  • フィードバックループの効率を計測する

ペアプログラミング

参考:ペアプロを極めて最強の開発チームをつくる(1/4)ペアの組み方(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社

エクストリームプログラミングのうち、もっとも価値がありながら、もっとも誤解され過小評価されているものである。ペアの組み方には二つの方法がある。

  1. 開発者の強みと弱みを踏まえて組み合わせる方法。ペアはお互いの得意なところを活かし、苦手なところを補うために協力し合う。これは、性格面でも適用できる。
  2. 一番経験を積んだ開発者と、一番経験の少ない開発者を組み合わせる方法。これは、経験を積んだ開発者側も教えることによって、新たな学びを得ることができる。

ペアプログラミングを適切にやれば、チーム内で知識を広げて全員のスキルを伸ばし、仕事の満足度を上げられる。

コードレビューとレトロスペクティブのスケジュールを立てる

  • ペアプログラミングとは、本質的には「書きながらおこなうコードレビュー」である。
  • 設計レビューはコードレビューでは、設計とその設計を選択した理由について議論するべき。
  • 設計のトレードオフを理解し、拡張がどれだけ簡単かを議論することがコードレビューの良い議論。
  • イテレーションやリリースの終わりごとのレトロスペクティブ(振り返り)も非常に需要。チームの改善を促し、新たな課題の発見を促すことができる。

明日のベロシティのために今日品質を上げる

  • 明日のベロシティを上げるためには今日コード品質を上げることが大事。
  • 高品質のソフトウェアはデバッグも簡単で、早くデリバリーできるようになるし、コードの保守も簡単になる。結果として、総所有コストが下がり、すばやい改修が可能になる。
  • コード品質の向上は変更のコストを下げ、見積もりを予測可能なものにしてくれる。
  • 品質のためのプラクティスを共有する。

保守しやすいコードを書く戦略(抜粋)

  • コードの共同所有を取り入れる
    • チームメンバーの誰もが、コードのどの部分でも変更して良いことを意味する
  • リファクタリングを熱心に行う
  • 常時ペアで進める
    • ペアプログラミングは知識を伝える上でいちばん早い方法である。
    • 毎日いろんな人とペアを組んでみて、学習し続けることが必要。
  • 頻繁にコードレビューする
  • 他の開発者のやり方を学ぶ

良いテストを書く

テストの観点(外部からの観察)と、コードの観点(内部からの観察)を行き来することで、フィードバックをもらいながら堅実に進めることができる。テスト可能なコードを最初に作成しておくのが楽である。

  • 呼び出し側の視点に立つ
  • テストを使って振る舞いを表す
  • 新しい違いを生み出すテストだけを書く
  • 失敗したテストにパスするためのコードのみを書く
  • テストを使って振る舞いを作る
  • コードをリファクタリングする
  • テストをリファクタリングする

『教育効果を可視化する学習科学』を読んだ ー 第3部 自身を知ろう

はじめに

この投稿は、基本的に和訳の本を読みつつ、わかりづらい章や箇所を原著に戻って確認した内容をまとめています。自分が興味を持ったところしか取り上げていないので、網羅性を求めている方は本を手に取って是非読んでみてください!

今回は最後の第3部になります。第1部と第2部分はこちら。

hiramekun.hatenablog.com

hiramekun.hatenablog.com

読書会を開いて週に2章読むペースでも、4ヶ月かかって読み終わりました。網羅的に学習心理学に関わる内容を知ることができるので、より掘り下げたいテーマに関して参考文献などもあたりながら深めていくと良さそうに思いました。

8/1 追記

スライドも作りました

www.slideshare.net

第24章 自信 ー 表にでてこないその3つの水準

自信は以下のように、異なる3つの水準がある。

  1. 自尊感情(全体的に包括した感情)
  2. 有能感(領域単位で感じる)
  3. 自己効力感(具体的な課題単位で感じる)

自尊感情

自尊感情は、自分自身の価値をどのように信じているかを表す。

自尊感情を測った際に高得点を示す人は、自分は幸福で生産的だと感じている。さらに、自尊感情が学業成績や社交性、安定した精神的健康などの肯定的な性質と相関していることも示されている。

しかしながら、自尊感情の高揚は、成功した結果によってもたらされる帰結であって、それらの原因では無いことがわかった。例えば "Psychological Science in the Public Interest" の中で以下のように言及されている。

ほとんどのエビデンスは、自尊感情が後続の学業成績に何ら影響も与えないことを示している。

驚くべきことに、身勝手な行動、攻撃、自己陶酔、抑制の欠如といった多くの負の側面が、高い自尊感情と結びつきやすいことまで明らかになっている。

有能感

有能感は、「得意である」と感じていることで、分野ごとに自分がどれくらい上手くできると感じているかを表す。

有能感はその能力に基づく実際の成果と対応しない。他者よりも自分をよく評価してしまうことなどが原因となる。また、全体的な自尊感情が、必ずしも領域固有の有能感をもたらすわけでは無い。しかし逆は起こり得る。例えば、生徒が学校で成功すると、自尊感情の一つとして学業に関する自己概念を発達させる。

自己効力感

自己効力感は、人生で出くわす眼前の課題を上手くこなせるという自信の高さを表す。自己効力感は、自尊感情や有能感のような汎用的なものではなく、目の前にある課題に対して成功する自信のみ

自己効力感が実際の能力に照らし合わせて妥当な評価になっているかというと、そうでは無いことがわかっている。同じくらいの能力を持つ個人の間でも、自己効力感の評価において大きな差異が見られる。挑戦し続ける人もいれば、挑戦を避け続ける人もいる。

自己効力感を左右する重要な要素は「記憶」である。次に出会う課題に対して自己効力感を感じるためには、過去に「成功」したことのあるよく似た課題に関する知識を活性化する必要がある。ここでいう「成功」した「記憶」とは、「過去によくできた」ことではなく、「この課題では自分の知識を素早く取り出せて使えた」という記憶のことを指す。知識へのアクセスのしやすさは自己効力感の鍵となる要素。

なので、「励ます」という行為は自己効力感を高めることが可能だが、過去に成功したことのある記憶を呼び起こしてあげることでより効果的になる

自己効力感は常に現実の実力や能力と一致する必要はない。少し誇張された能力評価や自信過剰な状態は、自分に対する理想状態に一致する水準にまで技能を向上させるように人を動機づける。

教育的観点から

教育的観点から考えると、以下のことは重要である。

  • 自尊感情のような、自分に対する肯定的な見方や自信は、学習における成功によってもたらされる。
  • 自尊感情の基礎となる決定的な要素は自己効力感であり、自己効力感は人生で出会う課題は本質的に対処可能であるという感覚に依存する。
  • 教師は、生徒が学校のカリキュラムに対処する能力に関して自信を得ることを助けるという、極めて重要な役割を担っている

上記を達成するための教授法については原著24章末のコラム参照。

第25章 自己高揚と「バカなやつともっとバカなやつ」の効果

題名が意味わからないと思ったが英語版も「Self-enhancement and the dumb-and-dumber effect」なので大体意味があってそう。

自己高揚

自己高揚とは人が自分の個人属性を肯定的に見なす傾向のこと。自信のあることを表に出す人は、他者から好意的に評価される。これは 自己呈示 と呼ばれる。自己呈示は人生において重要な役割を担っているので、自己高揚という現象が見られていると考えられる。

自分のことが優れていると虚栄をはっているのではなく、本当に自分は他者よりも優れていると信じているのである。このような感情は、ポジティブな出来事の記憶にアクセスしやすいことから正当化されている。具体的には、良い特性について考えたとき、それに合致するような出来事の記憶を引き出すことは容易であるということだ。

自己評価の持つ意味とは

多数の研究で得られたデータから、自己評価は客観的な指標に比べて以下のようであると示されている。

  • 不十分である。
  • 他者による評価よりも不正確な結果となることが多い。

例として、人は他者のIQやテスト結果を予測する方が、自分のものを予測するよりも正確であることが示されている

このようなことにも自己高揚が関係している。人間は自分の評価をする際は自己高揚を基準として評価する。それに対して他人の場合は誇張された状態がないため、おおよそ正しい評価ができる。

自己評価の正確さは、技能領域における正確なフィードバックが利用可能かどうかに関連している。性格で客観的なフィードバックが容易に利用可能な領域においてのみ、自己評価は客観的なデータに収束し始める。

バカなやつともっとバカなやつ効果

能力を欠いた人は、自分がいかに能力を持たないかを知るための基盤を持たない。例えば、クラスの下位に位置する学生たちは、自分が平均よりも成績が悪いことに気づかず、成績を20%も過大評価した。

この効果は有能でない人に限ったことではない。課題が取り組む人にとって非常に難しい場合には、認知負荷が高まり判断力が失われるので、より一般的に起こりうる。例えばテストの時に上手く回答できなかった場合、「正解したかはわからないが、努力した上で頑張って回答した」という感覚が反映される。

自己イメージを正しく持つための教師の役割

人生において自分の立ち位置を正解に知ることは、生徒全員が取り組まなければならない重要な課題の一つである。確かなフィードバック情報が非常に重要だと生徒に理解してもらうことは、以下の理由から重要である。

  • 誰もが引き起こしている自己高揚の効果を抑制するために。
  • 個人が感じる自己価値を傲慢なものにしな`いために。

適切なフィードバックがなければ、個人の自我の構築は利己主義に委ねられてしまうだろう。

第26章 自己制御の獲得

満足遅延耐性と自己制御

幼い時に強い我慢能力を発達することに失敗した人は、のちの人生において自己制御の問題に直面することになりやすい。ここでは、目先の報酬を我慢することでより将来の報酬を得る能力のことを 満足遅延耐性 と呼ぶ。

マシュマロの実験では、高満足遅延耐性を持つ子供たちは目の前の報酬から自分自身の注意を逸らす方法を工夫していた。また、低満足遅延耐性を持つ子供たちは、年を経るごとにしばしば行動上に問題があると報告された。

他にも、自己制御の能力が高い人々は、一般的に社会的に成功していることが報告されている。自己制御できる人は、他者を理解するために努力するという適応のプロセスを通して、対人関係を改善していくことが見出された。

自我消耗

自己制御に関連の深い概念として、自我消耗 がある。自我消耗は、要求された課題に最大限注意を向けることによって引き起こされ、消耗後の課題に対するエネルギーや自己制御を著しく低下させる(例:美味しそうな食べ物を食べないように言われると、些細な批判を受けただけでより攻撃的になる)。衝動を抑えるために必要なエネルギーが、もう残っていないためだ。

自己制御能力の活用と発達

  • 自己制御ができる人ほど、衝動をコントロールする必要がありそうな状況を避けようとしている。
  • 衝動を制御するのに関係するスキルと方略は、社会モデリングを通して子供たちに教えることができる
    • 逆に捉えるならば、家族間の経験を通してモデル化され、伝達されることも多い。それにより、ギャンブルの習慣や薬物乱用などといった行為も伝達していくことが多くの研究によって意示されている。
  • 気晴らしや注意を逸らすことによって、自分の衝動に満ちた思考を落ち着けることができる
  • If-then 方略も有効である。これは、誘惑にさらされた際にどのように行動するか事前に考えておくこと。誘惑に抵抗できる効果が非常に高い。

備考

スタンフォードの自分を変える教室』で言及されている「意志力」について知っていると、より理解がしやすいと感じた。

hiramekun.hatenablog.com

第27章 笑顔の神経科学ー教えることの基本ツール

対面授業において、笑顔は最も強力なツールの一つである。

笑顔は他者といる時に生じる社会的なシグナルである。人は単独ではほとんど笑っていない。笑顔は伝染効果が強力であるということもわかっている。笑いは個人的な反応ではなく、社会的なつながりを確立したり確認したりすることを意図した表現なのである

また、無意識に発生したわずかな笑顔を、見た人は知覚することができる。教師はこれを手がかりとして、生徒からのフィードバック情報として笑顔を用いている。生徒の顔は彼らの理解レベルについて重要な手がかりを与えてくれるのだ。生徒もまた、教師の笑顔を必ず読み取る。生徒に笑いかけることによって、教師がその生徒を一人の人間として尊重していることを示すことができる。笑顔を抑制することが適切な場合もあり、例えば生徒の悪行について笑顔になったりすることは避けなければならない。

第28章 社会的カメレオンであることの驚くべきメリット

姿勢のマッチング とは、動作や姿勢などの多くの面で集団参加者間で一貫していることを指す。集団がうまく行っている時、そのメンバーの行動が伝染していく。逆に、無意識の姿勢マッチングが生じた後に、好意や信頼感といったものが続いているかもしれないと明らかになっている。

カメレオン効果 とは姿勢マッチングの一種で、人々が近くにいる時、当事者が誰もそのことに気づかずに、ある程度の模倣が生じるという事実を指す。良い関係性であればあるほど模倣がより行われるし、友人を作ろうとしている際は相手を熱心に模倣している。このようなカメレオン効果に代表されるような自動的な模倣に関する研究により、人間は「他者と交わり、うまくやっていこうとする、暗黙的な目標」を持っているということが示唆される。

カメレオン効果のようなものは、ミラーニューロンによって行われていると考えられる。ミラーニューロン理論とは、人間を観察している時、その人を神経学的に鏡映していることを表す。このメカニズムが、人間における協力的な社会スキルの発達を可能にさせたと推測されている。

教授場面においては、前の章でも述べたように、教師の個人的なジェスチャーが生徒の脳にとって非常に重要であると示されている。ミラーニューロン理論を踏まえると、ジェスチャーは単に情報の流れを助けているだけではなく、伝達されるべき情報そのものを伝達していると捉えることができる

第29章 「見えないゴリラ」、非注意性盲目、そして注目

非注意性盲目(inattentional blindness, IB) は、知覚失明の概念の一つで、実際に目の前で起こっているにも関わらず、一過性の失明であるかのような状態に陥ることである。一つの中心課題に向けば向くほど、別の側面に対して注意が散漫になる。昔の研究では、ストレスのかかる課題に集中している時、0.5秒ほど、実験参加者は正面に誰が座っているか一瞬見えなくなってしまうことがわかっている。

IBを有名にしたのが、「見えないゴリラ」の実験である。この実験の概要は以下の通りである。

  • 被験者は、映像を見て、バスケットボールが何回パスされるかを数えることを命じられる。
  • 映像の途中で、ゴリラの格好をした人が入ってきて、胸を叩いたりする。
  • 30秒の映像のうち9秒間もゴリラが画面に現れていたが、実験参加者の42%しかそのことに気づかなかった。

このIBは、聴覚にも適用されることがわかっている。従って、誰かが明瞭に話していても、他のことで心がいっぱいになっていると、何もインプットされてこないのである。授業の時も、生徒が他のことで心に負荷がかかっていると、聞いているように見えても、教師の伝えたいことを全く伝えられていないことが発生する。

第30章 すばやい思考とゆっくりとした思考ーあなたの中にいるロボットへの負債

  • すばやい思考とは「システム1」とも呼ばれ、実際の行動基準を通して、どのような処理が相応しいか瞬時に判断するシステムのこと。
  • ゆっくりとした思考とは「システム2」とも呼ばれ、言語と明確な意図を持って整理された思考システムのこと。

人生の発達途上にある時、衝動性を押さえたり、システム2を起動させて用いたり、懸命に自制心をはっきしたりする能力は、非常に重要な素養である。教育は、個々の生徒に合うレベルで機能するシステム2を作り直すことを伴う営みである。

備考

これも、『スタンフォードの自分を変える教室』で言及されている。

第31章 IKEA効果、努力、価値づけ

IKEA効果 とは、人は自分の作ったものに愛情を抱くということである。自分でモノを作ることに伴う隠された効果とは、その成果物に対して行われる客観的で正当な評価以上に、作り手は価値があると信じてしまうのである。努力は自動的に価値付与の構成要素となる

生徒が宿題を完成させ、それを提出した時はいつでも、同じような効果が発生していることを心に留めとくべきである。生徒が宿題に対して投入している努力を理解することは、教師にとっても重要で、生徒は教師からのフィードバックで自分の努力が認められることを求めている。

似て非なるものに 授かり効果 というものがある。これは、所有しているものに対して、客観的に妥当とされる以上の価値づけがなされることに起因する。

IKEA効果は、価値ある目標を達成したり、成果物を完成させたりすることに対する努力に由来する。授かり効果は、成果物に対する所有権に由来する。教室内でこうした努力を理解するには、何がどのように達成されているのかを、時間をかけてじっくり観察し、真摯に正しく評価することが大事である。

『効果検証入門』用語まとめ

はじめに

効果検証入門を読みました。「概念の説明→具体例での実践」が繰り返されることで、実際に使う様子がイメージしやすく、取り組みやすい本だなと思いました。少し誤植があって、そこで引っかかってしまったので、そこだけもったいないとは思いました(とても分かりやすかったので、次の版に期待...!)。

知らない単語や概念がたくさんあったので、用語集的にまとめ直しました。内容は本を読んだ方が分かりやすいと思うので、是非そちらをお読みください。

1章

セレクションバイアス

そもそも比較しているグループの潜在的な傾向が違うことによって発生するバイアスのこと。

例えば、クーポンを発行した効果を検証したいとする。クーポンを配信したグループと、配信されなかったグループに元々購買量の差があった場合、その差分が効果に上乗せされてしまう。

介入をどのようにして行うかが、セレクションバイアスの有無を決めることになる。

ポテンシャルアウトカムフレームワーク

まず Z_{i} を以下のように定義する。

{ \displaystyle
Z_{i}=\left\{\begin{array}{ll}
1 & \text { (介入が行われた場合) } \\
0 & \text { (介入が行われなかった場合) }
\end{array}\right.
}

売り上げである Y は次のように2種類が存在する。

{ \displaystyle
Y_{i}=\left\{\begin{array}{ll}
Y_{i}^{(1)} & \left(Z_{i}=1\right) \\
Y_{i}^{(0)} & \left(Z_{i}=0\right)
\end{array}\right.
}

上記の売り上げは、場合わけを取り除いて以下のように表現することもできる。

{ \displaystyle
Y_{i}=Y_{i}^{(0)}\left(1-Z_{i}\right)+Y_{i}^{(1)} Z_{i}
}

介入が行われた場合の結果 Y^{(1)} と、介入が行われなかった場合の Y^{(0)} があると考え、その差に介入の本当の効果があると考えることをポテンシャルアウトカムフレームワークと呼ぶ。

実際の実験では、Y^{(1)}Y^{(0)} のどちらかしか観測されないので、この差は計算ができない。観測されない側の結果をポテンシャルアウトカムと呼ぶ。

差が計算できないので、平均的な効果の差を計算する。この平均的な効果を、平均処置効果(ATE) と呼ぶ。

{ \displaystyle
\tau=E[Y^{(1)}] - E[Y^{(0)}]
}

t検定のプロセス

有意差検定におけるt検定のプロセスをここでおさらいする

標準誤差の算出

グループ間の平均の差が、母集団におけるグループ間の期待値の差からどの程度ずれているのかを示す。 グループ間の差の分散を以下で計算し、

{ \displaystyle
V=\frac{\sum_{i=1}^{n}(Y_{i}^{(0)} - \bar{Y^{(0)}})^2 + \sum_{i=1}^{m}(Y_{i}^{(1)} - \bar{Y^{(1)}})^2}{n+m-2}
}

その分散を用いて標準誤差を計算する。

{ \displaystyle
SE=\sqrt{\frac{V}{m} + \frac{V}{n}}
}

効果の推定値と標準誤差を使ってt値を算出

グループ間の平均の差が、標準誤差の何倍であるかを算出する。

{ \displaystyle
t = \frac{\bar{Y^{(1)}} - \bar{Y^{(0)}}}{SE}
}

t値を使ってp値を算出

p値は得られた推定結果がたまたま得られてしまう確率を表す。

p値を有意水準と比較する

p値が有意水準よりも低い場合は、推定結果がたまたま得られてしまった可能性は十分に低いと判断し、統計的に優位な値であると評価する。

2章

共変量

共変量は、介入・施策の有無で傾向が異なっていると想定される変数。セレクションバイアスを発生させていると分析者が想定している変数でもある。共変量と介入変数を合わせて、説明変数と呼ばれる。

回帰分析では、共変量で条件づけた被説明変数の条件付き期待値を推定する。

脱落変数バイアス

二つの回帰分析モデルAとBを考える。

{ \displaystyle
\begin{aligned}
Y_{i}&=\alpha_{0} + \alpha_{1}Z_{i} + u_{i} &\text{モデルA}\\
Y_{i}&=\beta_{0} + \beta_{1}Z_{i} + \beta_{2}X_{omit, i} + e_{i} &\text{モデルB}
\end{aligned}
}

この二つのモデルの差は、共変量 X_{omit, i} が追加されているか否かにある。\alpha_{1}, \beta_{1} はそれぞれ介入変数 Z_{i} にかかるパラメータ。介入変数の効果が、この2つのモデル間でどのような差を生じているかを考える。

モデルAの誤差項 u_{i} のなかに、\beta_{2}X_{omit, i} とモデルBの誤差項 e_{i} が含まれていることになる。

{ \displaystyle
u_{i} = \beta_{2}X_{omit, i}+e_{i}
}

モデルBはセレクションバイアスの影響がより小さい分析結果を得られるため、X_{omit,i} は必要な共変量。
このように、本来必要だがモデルから抜け落ちている変数を 脱落変数 と呼ぶ。

このとき、X_{omit, i} を無視した時のパラメータ \alpha_{1} は、以下のようになることが知られている。(TODO: 導出する)

{ \displaystyle
\alpha_{1} = \beta_{1} + \gamma_{1}\beta_{2}
}

つまり、\alpha_{1} は、本来推定されるはずの \beta_{1} に何らかの値を付け加えたものとなる。この \gamma_{1}\beta_{2}脱落変数バイアス (Omitted Variable Bias : OVB) と呼ぶ。

このように、

  • 必要な共変量がモデルに含まれない場合は、推定される結果に OVB が含まれる。
  • 必要な共変量をモデルに加えることで、回帰分析では OVB の影響を取り除くことが可能。

ということがわかる。

{ \displaystyle
\alpha_{1} = \beta_{1} + \gamma_{1}\beta_{2}
}

この式に戻って、\gamma_{1}\beta_{2} の意味について考える。

  • \gamma_{1} は、X_{omit, i} に対して Z_{i} を回帰させた時に得られる回帰係数であり、Z_{i}X_{omit, i} の相関と捉えることができる。
  • \beta_{2} はモデルBにおいて推定される X_{omit, i}Y_{i} の相関に当たるもの。

よって \gamma_{1}\beta_{2} は、省略された共変量 X_{omit, i}Y_{i} に対して与える影響が、X_{omit, i}Z_{i} との相関を通して Z の効果として現れているように見えているということになる。

f:id:thescript1210:20210519104750p:plain:w500
イメージ図

OVB は、統計的に有意でない共変量をモデルから除外しても発生する可能性がある。なので、興味あるパラメータ以外の有意差検定の結果を考慮して共変量を選択することは避けた方が良い。

またこれを逆に考えると、介入変数 Z の決定に何らかの関連を持っていて、さらに目的変数 Y との相関もあるような変数を新たにモデルに加えると、バイアスを減らすことができる。

Conditional Independence Assumption

モデルに含めた共変量で条件づけた時に、介入変数が Y^{(1)}Y^{(0)} とは独立になることを、CIA (Conditional Independence Assumption) と呼ぶ。

共変量の値が同じサンプルにおいては、介入 Z はランダムに割り振られているの等しい状態。

Sensitivity Analysis

手持ちのデータには含まれない変数が、セレクションバイアスを起こしているか評価するための方法が Sensitivity Analysis

分析者が重要だと認識している共変量以外の共変量をモデルから抜くことで、効果の推定値が大きく変動しないかを確認する。

Post Treatment Bias

介入によって影響を受けた変数を分析に入れることによって生じるバイアスのことを、Post Treatment Bias と呼ぶ。

これを避けるために、介入よりも後のタイミングで値が決まるような変数は、分析から除外する必要がある。

多重共線性

回帰モデルに含まれている変数のうち、2つが強い相関を持つ状況ことを 多重共線性 と呼ぶ。

回帰分析で得られる推定値の分散の式は次のようになる。(TODO: 導出する)

{ \displaystyle
\bar{x}_{k} = \frac{1}{N}\sum^{N}_{i=1}x_{k,i} \\
Var(\hat{\beta}_{k}) = \frac{\sigma^{2}}{(1-R_{k})\sum^{N}_{i=1}(x_{k, i} - \bar{x}_{k})^{2}}
}

R_{k} は変数 k と多重共線性を起こしていると考えられる変数の相関をを表した値。つまり、相関が強いと分子が0に近づき、推定値の分散が非常に大きくなってしまう。

しかし、多重共線性は関連の強い変数以外の変数には特に影響を与えていないため、介入変数以外の変数においては仮に起きていたとしても問題にはならない。

3章

傾向スコア

傾向スコア とは、各サンプルにおいて介入が行われる確率のこと。傾向スコアを用いた分析は、介入が行われた仕組みに注目し、介入グループと非介入グループのデータの性質を近くするする操作を行う。

CIA のように共変量で条件づけるのではなく、共変量から算出した介入の割り振り確率で条件づけ たサンプルの中で、介入の割り振りが独立だと考える。つまり、傾向スコアが同一のユーザーの中ではランダムに介入が決められているに等しいと考える。

割り当て結果 Z を用いて、傾向スコア P(X) を推定できる。多くの場合はロジスティック回帰が用いられる。具体的な回帰式は以下の通り。

{ \displaystyle
Z_{i} = \sigma(\beta X_{i}+u_{i}) \\
\sigma(x) = \frac{1}{(1+e^{-x})} \\
\hat{P}(X_{i}) = \hat{Z}_{i} = \sigma(\hat{\beta}X_{i})
}

u は誤差項であり、 \beta は推定されるパラメータ。

傾向スコアマッチング

傾向スコアマッチング では、介入が行われているグループと傾向スコアが近いサンプルを、介入が行われていないグループからマッチングしてペアにする。そしてそのペアの中で目的変数の差を算出し、平均をとったものを効果の推定値とする。つまり、介入が行われているサンプルにのみ注目して、そのサンプルと傾向スコアが近いものとの差をとって平均をとるので、母集団における以下のような効果を推定しているということになる。

{ \displaystyle
\hat{\tau}_{match} = E\{E[Y|P(X),Z=1] - E[Y|P(X), Z=0]|Z=1\}
}

これを、ATT (Average Treatment effect on Treated) と呼ぶ。

逆確率重み付き推定

逆確率重み付き推定 (Inveres Probability Weighting: IPW) は傾向スコアをサンプルの重みとして利用する。与えられたデータ全体での介入を受けた場合の結果の期待値 E[Y^{(1)}] と、介入を受けなかった場合の結果の期待値 E[Y^{(0)}] を推定する。そしてこれらの期待値の差分を取ることで効果を推定する。

Z=1 となったサンプルはデータセット全体の中で P(X) が高い値のサンプルばかりとなり、Z=0 となったサンプルはその逆になる。よって、Z=1 となったサンプルで E[Y^{(1)}] を推定するために Y^{(1)} の平均を計算すると、\hat{P}(X_{i}) が小さいサンプルはデータとしてほとんど含まれないということになってしまう。

f:id:thescript1210:20210522165121p:plain:w500
イメージ図

欠損しているところは、P(X) が低いので、その分観測されていない。そこで IPW では、P(X) が低いところに大きな重みをつけて「重み付きの平均」を取ることで、この偏りを解消する。

{ \displaystyle
\bar{Y}^{(1)} = \sum_{i=1}^{N} \frac{Z_{i}Y_{i}}{\hat{P}(X_{i})} / \sum_{i=1}^{N} \frac{Z_{i}}{\hat{P}(X_{i})}
}

平均をとる際に確率の逆数を重みにしている。これにより、サンプルが含まれない分重みを増していることになる。

逆に Y^{(0)} は、確率 1-\hat{P}(X) の逆数を重みに利用する。

{ \displaystyle
\bar{Y}^{(0)} = \sum_{i=1}^{N} \frac{Z_{i}Y_{i}}{1 - \hat{P}(X_{i})} / \sum_{i=1}^{N} \frac{Z_{i}}{1 - \hat{P}(X_{i})}
}

2022/04/09追記 期待値を出すときに、 Z=1 に相当するサンプルを数える分母部分に対して、傾向スコアで標準化する必要はないのではないか?逆確率重み付け推定は、得られた確率を傾向スコアで重み付けするだけのはず。

{ \displaystyle
\bar{Y}^{(1)} = \sum_{i=1}^{N} \frac{Z_{i}Y_{i}}{\hat{P}(X_{i})} / \sum_{i=1}^{N} Z_{i}
}

4章

DID (差分の差分法)

回帰分析と傾向スコアは、介入グループと非介入グループの両方に同じような特徴を持つサンプルが含まれている状況を利用して比較するという方法。

しかし実際には同質なサンプルが存在しない時がある。そのような際に DID (Difference in Difference: 差分の差分法) を使うと、介入が行われた地域における介入の前後データに加えて、他の地域の介入の前後のデータを利用することで問題を解決するという方法。

方法としては大まかに以下の2ステップ。

  1. 介入前後の差分を介入されたグループと介入されなったグループでそれぞれ算出し、
  2. さらにグループ間でその差を取る。

DID における標準誤差

  • 自己相関 とは、ある時点で取得された変数の値がその近辺の時間で取得される同じ変数の値と相関するような状態。
  • クラスター標準誤差 とは、指定した観測対象ごとに誤差を観測していると考えて誤差項を扱う(TODO:詳細を調べる)。

平行トレンド仮定 (Common Trend Assumption)

介入グループと非介入グループの目的変数の時間を通した変化(これをトレンドと呼ぶ)が同一であるという仮定を、平行トレンド仮定 (Common Trend Assumption) と呼ぶ。DID の分析結果が正しいと考えるために必要な重要な仮定。

CausalImpact

DID の欠点は以下の2点。

  • 効果の影響を調べたい変数が複数の場所や時期で得られている必要がある。
  • どのデータを分析に用いるのかが分析者の仮説に依存している。

そこで、介入が発生した前の期間で、目的変数 Y をうまく予測できるモデルを作成し、それとの差分を取ろうというのが CausalImpact のアイデア。さらに、介入前のデータを利用してどの変数のデータが予測に役立つのか判別し、自動的に利用するデータを決定しつつモデルを学習してくれる。

なお、CausalImpact においても平行トレンド仮説は重要で、介入に影響を受ける変数は予測に用いると問題になる。

5章

回帰不連続デザイン

介入が確率的に定まると考えるのが傾向スコアを用いた手法だが、実際には「条件を満たす人全員に介入する」というような、介入の割り当てがルールによって行われている場合もある。このような場合には 回帰不連続デザイン (Regression Discontinuity Design: RDD) を用いることができる。

介入を決定する変数のことを running variable とよび、介入の有無の閾値のことを カットオフ と呼ぶ。

回帰不連続デザインでは、カットオフ付近のデータに注目することで効果を検証できる手法。カットオフ付近のデータは似たような値になっているので、同質なユーザが集まっていると考えられる。

running variable を共変量として線形回帰を行うと、バイアスがある程度取り除かれた効果が推定される。これはカットオフ付近のデータのみが効果として利用されており、Local Average Treatment Effect (LATE) と呼ばれている。

nonparametric RDD

介入を決定する変数と目的変数の関係が非線型の場合に使用できるのが nonparametric RDD。利用するデータを閾値の前後に限定することでセレクションバイアスを小さくするというアイデア

しかし、同時にデータを絞り過ぎると、集計に含まれるデータ量が少なくなることから、標準誤差は大きくなってしまう。

Continuity of Conditional Regression Functions

Continuity of Conditional Regression Functions とは、介入を受けた場合と受けなかった場合における条件付き期待値である E[Y^{(1)}|X] と E[Y^{(0)}|X] が X に対して連続であることを仮定していること。これは RDD で推定された効果が正しいと考えるために満たされるべき仮定。

例えば、介入したグループに対して他の施策も行っていた場合は、その他の施策も効果に含んでしまう。

non-manipulation

RDD においては、分析の対象が自身の介入に関するステータスを調整できないという non-manipulation という重要な仮説がある。例えば、介入される人が、一定の購入額を超えるとクーポンをもらえると知っている場合は、意図的に追加購入をしてしまうような状態だと、カットオフ付近でのデータの分布が大きく変化する。

LATE の妥当性

カットオフ近辺のみではなくデータ全体における平均的な効果と考えるためには、行われた介入の効果が running variable の値によっては変化しないという仮説を置く必要がある。

一方で、カットオフ付近の効果を知る方が価値がある場合は、LATE を得ることで閾値における効果を比較できるため、非常に重要。

はてなブログのtex記法では記号を余分にescapeすること

うまく表示されなくて困ることが多いので自分用にメモします(随時更新)。

大括弧

tex記法自体が大括弧 [] を使用するのでうまくparseできないようです。自分用にメモします。

<div align="center">[tex:{ \displaystyle
\tau=E\[Y^{(1)}\] - E\[Y^{(0)}\]
}]</div>
{ \displaystyle
\tau=E[Y^{(1)}] - E[Y^{(0)}]
}

ちなみにescapeしないと表示が壊れます😇

<div align="center">[tex:{ \displaystyle
\tau=E[Y^{(1)}] - E[Y^{(0)}]
}]</div>
{ \displaystyle
\tau=E[Y^{(1)} - E[Y^{(0)}] }]

アンダースコア

texのインライン記法においても _ が同じ行に複数回現れると、Markdownで使用する _ と混ざってしまってparseに失敗しているようです。なので、アンダースコア _ の前でescapeが必要になるようです。

  • この変数は [tex: A\_{i}]  A_{i} で、こっちは [tex: B\_{i}]  B_{i} です。

こっちはesapeしていないので表示が壊れます。

  • この変数は [tex: A_{i}] [tex: A{i}] で、こっちは [tex: B_{i}] [tex: B{i}] です。

『教育効果を可視化する学習科学』を読んだ ー 第2部 学びの基礎

はじめに

この投稿は、基本的に和訳の本を読みつつ、わかりづらい章や箇所を原著に戻って確認した内容をまとめています。自分が興味を持ったところしか取り上げていないので、網羅性を求めている方は本を手に取って是非読んでみてください!

前回分はこちら。

hiramekun.hatenablog.com

個人的に面白いと思った内容が多いので、今回の前半は特に分量が多めになっています。

勉強会を開催して読んでいます。参加したい方は是非一緒に読破しましょう!

connpass.com

※2021/05/21追記 第1部に引き続きまとめスライドを作りましたので、こちらもご参照ください。

www.slideshare.net

第13章 いかにして知識は獲得されるのか?

知識獲得の6つの原理

  1. 学習には時間と努力と動機が必要である。
    • 具体的には、時間、目標の設定、支援的なフィードバック、成功体験の蓄積、頻繁に復習することが必要になる。
  2. 集中できる時間は短い。
    • おおよそ15分-20分しか集中力は保てない。誰かに新しい情報を教える必要があるなら、15分以内に行う必要がある。
  3. . 分散型の練習は、集中型の練習や詰め込みよりも効果がある
  4. 先行知識の影響は強固である。
    • 先行知識の影響は、IQなどよりもはっきりと優っている。
    • 優れた教師は、私たちが何を学ぶべきかについて、最初に見通しを示してくれる。これにより、先行知識を活発化させ、新しい情報を効率的に獲得することができる。
  5. 知性はマルチメディアのインプットによく反応する。
    • 人間はより多くのメディアを用いて伝えられると、より学習できる
    • 全ての生徒は、言葉とともに関連するイメージを通して最も良く学習する。
  6. . 学ぶ時には知性を「能動的な状態」にしなければならない。
    • 有意義な経験に対して、有意義な反応を示すことによって、学習は効果的に表れる。

記憶保持の6つの原理

  1. 識別するのは簡単だが、想起するのは大変である。
    • (イメージ)選択式問題は簡単だが、記述式問題は難しい。
  2. 最初と最後に与えられた情報は想起しやすい。
    • 初頭効果親近効果
  3. 時間が経つにつれた忘却の程度はまちまちである。
    • 何をどのように学習したかによって、忘却の程度は異なっている。
  4. 記憶とは高次の構成的過程である。
    • 部分的な手がかりや曖昧な情報であっても、脳が意味が通るようにしてくれている。
    • 人間の脳による解釈が、記憶に影響を与えている
  5. 保存の原理:忘れられたことはまだ役立つ。
    • 完全に忘れた内容でも、また学ぶ時、無意識に素早く学ぶことができることが研究によって示されている。
  6. 記憶は干渉に左右される。
    • 逆向干渉順向干渉
    • 先行知識は一般的には学習を助けてくれるが、先行知識が誤りであった場合などは、順向干渉の原因となってしまう。

情報過多に対処する5つの側面

  1. 学習者の視点からすると学習は常に楽しい経験とは限らない。
    • 一般的には、学習は個人に満足感をもたらす。しかし、その満足感は、(1)最初に計画と目標を設定する(2)計画された目標に到達している、時に抱く感情である。大部分において、今行っている学習は楽しいものではない。
    • 生徒の多くは、この満足感に引っ張られて、「実際よりもよく技能を習得できる」「習得するのにより短い時間と努力でできる」と自信過剰に陥ってしまう
    • こうした自信過剰の状態は、適切なフィードバックによって修正することができる。
  2. 学習は精神的に大きなストレスを引き起こす。
  3. どの学習者も過負荷に対応する方略を編み出すことが重要。
  4. 過負荷の要因は特定することができる。
  5. 誰もが過負荷によって支配されている。

多重貯蔵理論

  • 感覚の認識入力を一瞬だけ保持している記憶の種類である、映像的記憶。
  • 一度に保持できる量が限定されており、すぐにシステムから消失してしまう、短期記憶 あるいは 作業記憶。
  • 永続的に情報を保持するが、このシステムに移すのが困難であり、記憶へアクセスする方略が必要になる、長期記憶。

第14章 どのようにして知識は定着しているのか

今までの章で見てきたように、前提知識は、次にどのような知識を習得できるかや、どのようにして思考するかを決定する。ここでは知識というものがどのようにして貯蔵されているかを見ていく。

大きく分けて、知識には二つの種類がある。(詳しくは原著のp127参照。)

  • 宣言的知識:単語や文章で表される知識で、細かく次の5つに分類される。
    • 知覚的認識:知覚したものの区別ができること。一回区別ができるようになると、その知覚をやめることはできなくなる。
    • 文字列:シーケンシャルに並んだ簡単な文字や情報を意味づけること。集中した状態での反復練習によって獲得できる。
    • 着想:主語と述語からなる、複数の文章(命題と呼ばれる)を通して、それらをまとめて一つの実体に結びつけること。前提知識に対して新しい知識が関連づくと、着想を獲得できる。
    • スキーマ:分断している知識を当てはめて、既存の自分の思考しうる範囲を超えて思考することができるフレームワークのようなもの。このスキーマは洗練されていく必要があり、簡単に取得できるものではなく、全く同じではない事柄について、どのようにして統一したフレームワークを作るか試行錯誤を重ねて獲得される。
    • メンタルモデル:獲得したスキーマたちを用いて、問題を解決すること。メンタルモデルは仮説思考を可能にする。しかし、これは各々が活用できるスキーマと着想に依存している。さらには、(a) 正しい知識と、(b) その知識がワーキングメモリで簡単に扱えるかどうかにも非常に強く依存している。メンタルモデルは、抽象的な概念を説明できる優秀な個々とのやりとりによって獲得につながることが判明している。
  • 手続き知識:動作を通して指標づけられる知識。どの状態でどの知識を用いるか、これを条件反射的に判断している。この知識を身につけるのに言葉は必須ではない。

第15章 学習は意識的に行われる必要があるのか。そしてジェスチャーに隠されたその役割とは。

(まとめとしては原著p143を読めば良い)

暗黙的な学習とは

学習は、必ずしも意識的に行われるわけではない。脳は私たちが自覚しているよりも多くの情報を実際に受容している。このような情報による学習のことを暗黙的学習 と呼ぶ。

暗黙的学習は、どんな時でも行われている。例えば、条件反射は意識しないで条件付けが学習された結果のものである。より一般的には、言葉や考えで簡単には説明できない学習体系のことは暗黙的学習となる。具体的には以下のような実験がある。

  • あるルールに従った文字列を提示したところ、そのルールを明確には説明できないが、なんとなく次に来る文字を当てられるようになった。
  • 被験者がアバターとジャンケンをする際、アバターは各手を出す前に微妙な態度の変化を表すようにした。被験者は明確な理由は説明できないのに、ジャンケンで44%の確率で勝てるようになった(全くランダムなら33%)。

重要なことは、学習結果は(学習者が明示的に表現できる)言語的な形で表現されるのではないという点である。

ジェスチャーの役割

ジェスチャーを通じて、暗黙的学習によって得た知識を用いることができる。ジェスチャーは暗黙的知識を評価し、それを向上させ、さらに新しい場面で用いることに効果を発揮する。生徒たちがジェスチャーを用いている時、彼らは自身の話している内容をより深いレベルで捉えようとしており、さらに学業のパフォーマンスも向上する可能性がある

さらにジェスチャーは、私たちの思考過程に対して良い影響を及ぼすことが確実である。考えている時にジェスチャーを用いることは認知負荷を軽減させ、思考能力や問題解決能力を向上させることができる。

重要なことは、知識は単語として明示的に表現される前に、ジェスチャーを用いて表現することができるという事実である。

このようにジェスチャーは重要な役割を果たしているが、子供も大人のジェスチャーに強く影響を受けている。実際の教室でも、生徒は教師のジェスチャーから知識を得ようとしているのである。

第16章 認知負荷の影響

認知負荷の研究は、教育者にとっては非常に重要な分野である。それはなぜなら、認知負荷の研究は以下のような二つの側面があるから。

  1. なぜ人間にとって学習が難しいのかという問題を扱っていること
  2. 生徒が比較的容易に新しい情報を学習し覚えることができるようになるために、教師がどのようなことをしているかを明確に説明していること

人間の認知構造

まず認知負荷理論は、人間の認知構造を明らかにするところから始まる。その中で特に自分が興味深かったものをいくつか取りあげる。

  • 長期記憶から取り出された情報を処理するとき、作業記憶に限界はない。
  • したがって、長期記憶は作業記憶内での出来事の内容や質の両方に大きな影響を与える
  • 専門的知識は、学習者が簡単なアイデアをより複雑なスキーマに注意深く組み合わせることで発達する。
  • 発達する複雑なスキーマによって知識は整理されていき、作業記憶の負荷が劇的に軽減されるスキーマは作業記憶内の単一の要素として簡単に処理できるからである。

長期記憶や知識の再構成が作業記憶に対して大きな影響を与えていることがわかる。このように知識が自動化され、実質的な労力をかけないで素早く知識にアクセスできるようになると、作業記憶システムは自発運動化の段階に達する。

認知負荷の原因

作業記憶は、新しい情報や整理されていない情報が、特に複数与えられると摩耗してしまう。与えられた情報は相互作用し、干渉し合う。さらにその干渉は与えられた情報に対して組み合わせ爆発的に増加していくため、少しの個数の増加が大きな認知負荷を生み出す。

認知負荷の原因には、「内在的な認知負荷」と「外来的な認知負荷」の2種類が存在している。

  1. 内在的な認知負荷は、与えられた課題自体の性質によって定まる。この認知負荷の主な決定要因は、個人の先行知識である。先行知識があれば、与えられた課題に対する認知負荷は軽減される。
  2. 外来的な認知負荷は、学習条件や教育的文脈によって課せられる負荷のこと。これは学習に集中することを阻害する要因のため、取り除かれることが望ましい。具体的には、必要のない情報を過剰に与えたり、生徒に不必要な要求を同時に課したりすること。特に学習が難しくなるにつれて、外来的な認知負荷の影響が大きくなる。

どのようにして認知負荷を減らすか

生徒の学びを助けるためにどのようにすれば認知負荷を減らすことができるか研究がなされてきた。結論の一つとして、未熟な学習者にとって、事前指導を受けることは価値がある。まさに反転授業が成功する理由の一つとされている。

しかし、これは知識のある人々を教える際には全く効果的ではなく時間の浪費となることには注意が必要。

問題を解くことによる学習の問題点

知識スキーマを教えようとする場合、問題を解くことは効果的な方法として成功しそうにないということが明らかになっている。問題を解くことによって学習することは、状況が単純化されているか、情報間の相互作用のレベルが低い場合、もしくは概念が十分に理解されている場合に実行可能になる。これはつまり、問題を解くことによる学習は、学習する教材が極めて単純な場合にのみ有効だということ。

一方で、グループで問題を解く活動を行わせた場合、効果的な指導ツールになることも示唆されている。一般的に一人だと負荷が高くなりがちだが、グループメンバー間で作業記憶の機能を共有することにより、認知負荷を分け合うことができる可能性があるとされている。

第17章 記憶力はどのように伸ばせるか?

人生の最初の頃を思い出すのはめったいないことで、これは 幼児期健忘 と呼ばれている。この時点では多くのことを学習しているが、のちの人生では本当に少しだけしか記憶することはできない。3歳頃から、特定の記憶を思い出すことができる言語と記憶のシステムが発達する。この頃から、豊かな会話が子供の記憶システムの発達において劇的な役割を果たすことがわかっている。共に出来事を思い出すように話しかけるようなスタイルを 回想スタイル と呼ぶ。質の高い言語を利用して子供が過去の出来事を理解できるように支援することができる。

学校に通う子供たちは、通わない子供たちと比べて認知スキルにおける様々な面で大きく異なることがわかっている。特に学校に通うと、生徒の認識、言語スキル、知識を蓄えるシステムを組織する方法が劇的に変わる。例として、年齢が上がるにつれて子供たちは新しい情報を覚えようとするとき、長期記憶のシステムを効果的に使用し、知識を体制化する。

さて、学校では教師は記憶スキルを教えているのだろうかというと、先生によりまちまちであるということが、以下のようないくつかの研究結果から分かっている。

  • 記憶方略の指示は、時間の2%で発生していた。
  • 教師の10%は、その方略について直接的な指示を全くしていなかった。
  • 記憶方略を直接指示した教師は5%だったが、50%がある程度の記憶作業を要するものだった。

そのほかにも、記憶術を教えることに長けた教師と、そうでない教師がいることも分かっている。

  • 記憶術を高いレベルで教える教師(high mnemonic teachers: HMT)は、学習に適した方法を直接指示したり、特定の方法がなぜ効果的なのかを尋ねたりした。
    • HMTからの学習の効果は、基本スキルのテストが低い得点で学校に登校し始めた生徒の場合に特に顕著であった
  • 記憶術を低いレベルで教える教師(low mnemonic teachers: LMT)は、知的方略に焦点を当てることが少なく、学習プロセス自体より、基本的な質問をする傾向があった。

第18章 スポーツであり、技術であり、教育的ツールでもある記憶術

記憶術には様々な側面があり、この章ではスポーツとして取り上げられるような「記憶のアスリート」について取り上げている。より多くのスキルを習得するにつれて、作業記憶内により多くを保存する能力が生まれる。しかしこのような人たちは、記憶すること自体を目標としているため、高度なスキルを習得する助けになるわけではない。

このような記憶術が教育の観点に持ってきたときに一番問題になるのは、本質的には役に立たない記憶術に対して時間を費やす点だ。優れた記憶のコツを使うことは、記憶している内容自体への理解を増やすわけではない。暗記のための明確で便利なテクニックは、積極的に教えるべきではある。ただし過信は厳禁だ。あくまでも低いレベルの表面的な知識を学ぶことに対してのみであり、深い側面の知識を高めることには役立たないことに留意しておこなう必要があるだろう。

第19章 生徒の学習スタイルの分析

俗に VAKモデル というものが存在している。これは、人は生まれながらにして持っている情報処理のためのシステムによって、3つのうちいずれかに分類されるという主張である。

  • 視覚学習者(visual learners)
  • 聴覚学習者(auditory learners)
  • 運動感覚学習者(kinaesthetic learners)

しかし、研究結果を見ていくと、「生徒たちの学習スタイルを知ってそれを分析して教える方が、知らずに教えるよりうまくいく」ことを示唆するエビデンスは何も見つかっていない。これは、人には得意とする情報入力方法があるはずだという主張が背景にあるが、神経学的に見ても、行動を見ても、こうした分類の妥当性を示す結果は得られていない。強いていうのならば、学習スタイルのようなものは自己申告によるものであり、表面的に観察される好みのようなもの以外に判断の妥当性は示されていない。

第20章 大きく誤解されている複数タスクの同時進行

人間は往々にして複数タスク(俗にいうマルチタスク)を同時進行できると考えている。しかし、これまでの研究結果を見るとそれは否定される

複数タスクの同時進行という言葉自体は、以下のいずれかを表している。

  1. 頭の中で2つ以上の仕事を同時にこなすこと
  2. 複数の仕事を切り替えて行いながら一定時間内に複数の目標を達成すること
  3. 1つの重要な目標を目指しながら、時々他の仕事をやること
  4. メールチェックなどをしながら、大したことのない用事に意識的に時間を使って取り組むこと

2つの信号が同時に入ってきた場合、人間の注意はどちらか一方に引き付けられるため、二つ以上の仕事を同時にこなすことはできないことがわかっている。また、複数タスクを効果的に同時進行する際、1つ目の目標や課題を遂行するには学習と思考が必要となるのに対し、もう一つはすでに学習済みの活動であるということが重要となる。同時に異なるものを学ぼうとすると、干渉が起きてしまい、学習が阻害される。

さらには以下のような厳しい言葉で複数タスクをこなせると主張する人を批判している。

複数のタスクをこなせると主張する人は現実を見ておらず自分の実力を過信している。未完成の仕事を次々に切り替えて取り組んでいる人たちは、全体的に効率が下がっていることにも気づけないほど低いレベルのメタ認知判断力とともに、自分の軽率さを露呈している。

その一方で、退屈だが注意力の必要な仕事にずっと取り組んでいると、疲労が出てきて仕事の効率は下がる。これはヴィジランスの低下と呼ばれている。なので、このような状況では、時々他の仕事に切り替えることで注意力低下の影響を軽減することができる。

第21章 学習者は本当に情報機器を使いこなしているのか?

デジタルネイティブという言葉が出てきて久しいが、デジタルネイティブというのはいささか誇張されがちである。

デジタルネイティブであろうと、それはただ単に生徒たちが最新の技術や機器に慣れているだけであり、人間が本来持っている能力が変わっているわけではない。

コンピュータを利用すること自体は、現代社会で生徒の役に立っていることがわかっている。しかし、あくまでもコンピュータは教師ではなく、コンピュータが可能にするのは、人間の教師が異なる媒体を使い、異なるやり方で指導案を立案し人間を指導することを可能にすることだけである。

第22章 インターネットは私たちを浅薄な思考の持ち主にしているか?

インターネットが普及してきて、生徒が教科の内容を正しく理解できていないのに、それを誤魔化すかのようにインターネットを使用するかもしれない問題がある。

「インターネットは私たちに数分の検索で得た情報の寄せ集めという形で知識を獲得させようとしているのだ」という主張まで出てきている。しかし、インターネットの使用そのものが認知能力の劣化を起こすことを裏付けた研究は存在しない。情報のインプット方法は人間の理解を決定するのに特に重要ではないことに気づくべきだ。考えたり学んだりするやり方は、近年開発されたテクノロジーよりも、幼少期から出会った言語や人間関係、本質的な文化に負うところがずっと大きい。教師は、現代のコンピュータの能力と上手に付き合うことで、教材を今の生徒たちにとってより意味のあるものにできる。

第23章 音楽はどのように学習に作用するのか?

音楽は、人間の生活の中に最も浸透している側面の一つである。昔からモーツァルト効果のように音楽と学習の関係性は議論に上がってきた。ここでは3つの観点について見解を述べる。

  • BGMの効果はなんだろう
    • 音楽以外の作業を行なっているときに、BGMのあるとなしとでは学習との間になんの関係性も見られない。
    • 一方で、音楽は場の雰囲気を変えるのに利用される。音楽を聴くことでやる気を起こさせることができる。
  • 音楽を聴くことは脳に影響するのか。音楽を聴くことで学習や成績は上がるのか
    • モーツァルト効果のようなものは、調査されているがいまだに証明されていない。クラシック音楽を聴くことは注意を喚起し覚醒させることに役立つが、知能を高めること自体はないと証明されている。
    • コーヒーを飲むことで同様の効果が得られることが示唆されている。
  • 音楽指導は音楽以外の分野を学ぶ場合にも効果があるのか
    • 音楽の練習が他の分野の学習を助ける側面があるのは心理学的に理にかなっている。(努力、自己制御、メタ認知的観察、知的方略といった観点。)
    • 音楽に関するプログラムに参加した子供たちは、他の子供達に比べて語彙テストと抑制制御テスト(将来得られる利益のために我慢するテスト)の二つでかなり高い得点を達成した。
    • 音楽の練習は生徒にとって認知的効果があるというエビデンスが集まってきている

第3部に続く

hiramekun.hatenablog.com

Scalaで競技プログラミング: 標準入力周りで調べたこと

複数変数の初期化

例えば、1 2 3のように空白区切りで3つの標準入力を受け取るために、次のようなコードをよく書きます。

val sc = new Scanner(System.in)
val v, e, r = sc.nextInt()

これは左辺の変数の個数分、右辺の式が評価されているようです。(公式ドキュメントが見当たらないので、探しています...)

scala> val a, b, c = 1
val a: Int = 1
val b: Int = 1
val c: Int = 1

scala> val a, b, c = util.Random.nextInt()
val a: Int = 2127446030
val b: Int = 1199584050
val c: Int = 638157382

これは ScannernextInt() を使うことによって実現できるのですが、Scalascala.io.StdIn.readInt() ではできません。

Scanner (Java Platform SE 8)

Scala Standard Library 2.13.3 - scala.io.StdIn

なぜかというと、ScalareadInt() は「readLine() した結果に対して toInt を呼び出している」だけだからです。なので空白区切りの入力に対しては readLine().split(" ").map(_.toInt) のように文字列を分割する処理を入れなければいけません。readInt() の内部実装は以下の通りです。

/** Reads an int value from an entire line of the default input.
 *
 *  @return the Int that was read
 *  @throws java.io.EOFException if the end of the
 *  input stream has been reached.
 *  @throws java.lang.NumberFormatException if the value couldn't be converted to an Int
 */
def readInt(): Int = {
  val s = readLine()
  if (s == null)
    throw new java.io.EOFException("Console has reached end of input")
  else
    s.toInt
}

複数行の読み込み

この記事を参考にしました。

qiita.com

AOJなどでは、行数が与えられずに、「与えられた行数分処理しなさい」という問題があります。行数が与えられればその数だけループ回せば良いのですが、そうではないので困ってしまいますね。(例えばこの問題などです:Aizu Online Judge

その際はio.Source.stdin.getLines() を呼び出すことで、次の入力がある限りは読み込み続けてくれます。

Scala Standard Library 2.13.3 - scala.io.Source

for (l <- io.Source.stdin.getLines()) {
  val arr = l.split(" ").map(_.toInt)
  ...
}

Array.fill

サイズnの入力を受け取り、配列として初期化する際に、次のようなコードをよく書きます。

val a = Array.fill(n)(sc.nextInt())

これでn回の入力を受け取っているのですが、これは Array.fill の第二引数が名前渡し引数(call-by-name)になっているからです。そのおかげで、第二引数がn回呼び出されることになり、意図した挙動になります。

Scala Standard Library 2.12.4 - scala.Array

By-name Parameters | Tour of Scala | Scala Documentation

By-name parameters are evaluated every time they are used. They won’t be evaluated at all if they are unused. This is similar to replacing the by-name parameters with the passed expressions.

Array.fill の内部実装は以下の通りです。

  /** Returns an array that contains the results of some element computation a number
   *  of times.
   *
   *  Note that this means that `elem` is computed a total of n times:
   *  {{{
   * scala> Array.fill(3){ math.random }
   * res3: Array[Double] = Array(0.365461167592537, 1.550395944913685E-4, 0.7907242137333306)
   *  }}}
   *
   *  @param   n  the number of elements desired
   *  @param   elem the element computation
   *  @return an Array of size n, where each element contains the result of computing
   *  `elem`.
   */
  def fill[T: ClassTag](n: Int)(elem: => T): Array[T] = {
    if (n <= 0) {
      empty[T]
    } else {
      val array = new Array[T](n)
      var i = 0
      while (i < n) {
        array(i) = elem
        i += 1
      }
      array
    }
  }

コメントや例が書いてあり、丁寧だと感じました。

Note that this means that elem is computed a total of n times

Scalaで競技プログラミング: ダイクストラ法

C++で書いたライブラリをScalaで書き直しています。ダイクストラ法全体として以下のようなコードになりました。

case class Edge(to: Int, w: Long)

case class Graph(n: Int) {
  val g: Array[Array[Edge]] = Array.fill(n)(Array.empty)

  def push(from: Int, edge: Edge): Unit = {
    g(from) :+= edge
  }

  def dijkstra(start: Int, Inf: Long = 1e18.toLong): Array[Long] = {
    val d = Array.fill(n)(Inf)
    d(start) = 0
    val queue = mutable.PriorityQueue.empty[(Long, Int)](Ordering.Tuple2[Long, Int].reverse)
    queue.enqueue((0, start))

    while (queue.nonEmpty) {
      val (minCost, minV) = queue.dequeue()
      if (d(minV) >= minCost) {
        g(minV).foreach { e =>
          if (d(e.to) > d(minV) + e.w) {
            d(e.to) = d(minV) + e.w
            queue.enqueue((d(e.to), e.to))
          }
        }
      }
    }
    d
  }
}

今回の主な新情報は PriorityQueue についての以下の行です。

 val queue = mutable.PriorityQueue.empty[(Long, Int)](Ordering.Tuple2[Long, Int].reverse)

Scala Standard Library 2.12.0 - scala.collection.mutable.PriorityQueue

元々ScalaPriorityQueue は降順で管理されています。今回は、(コスト: Long, 頂点id: Int) というタプルを PriorityQueue で管理します。その際は以下のように順序が規定されています。最初に第一要素を比べ、同じだったら第二要素を比べます。

def compare(x: (T1, T2), y: (T1, T2)): Int = {
  val compare1 = ord1.compare(x._1, y._1)
  if (compare1 != 0) return compare1
  ord2.compare(x._2, y._2)
}

ダイクストラで用いる際には、ある頂点までのコストが軽い順に並べ替えられていた方が嬉しいので、昇順になっている必要があります。そこで、 Ordering を引数に与えることで、並べ替えの順序を指定してあげます。降順の逆の昇順に並べたいので、Ordering.Tuple2[Long, Int].reverse を指定することになります。

他にも dequeue がpopするだけでなく要素も返すところは C++ と異なりますね。(むしろ返す方が自然だとは思いますが...)

AOJの問題でverifyしました。入出力含めた全てのコードはこちらをご覧ください。

github.com