jnobuyukiのブログ

JavaScriptとR言語を中心に研究活動に役立つwebアプリケーション技術について考えていきます。twitter ID: @j_nobuyuki

研究方法を学ぶ重要性とそこで終わらない重要性

今回は具体的な方法論ではなく、研究方法のとらえ方について書いてみます。

研究方法を学ぶ重要性

研究をしてみたいと思ったら、まずは過去の研究を読んでみたり、関連する話題を研究している研究者に質問したりして、研究方法を学びましょう。研究方法を覚えることは、言わば「研究の型」を覚えるようなものだと思います。この研究の型は多くの研究で使用されており、その中で型として洗練されてきたので、これを使うメリットがあります。これに加えて、その型を示すだけで、どんなことが行われたのかを他の研究者に教えられます。つまり、研究の型を覚えることは、一見何をして良いのかわからない研究の道を照らし出す案内役であると同時に、科学的なコミュニケーションをスムーズにする役割も持つと言えるでしょう。

研究方法の「意味」を考える

上記のような便利さと重要性を持つ研究方法ですが、ただ覚えてそれを使うだけでは研究を先に進められません。なぜなら研究では常に新しい問題を探し検討するため、学んだ研究方法ては対処できないかもしれないからです。ではそれをどうやって見極めれば良いのか?まず学んだ研究方法が「なぜその方法になったのか」を考えてみましょう。おそらく方法として確立されるための暗黙の仮定や前提が思いついてくるでしょう。そしてその仮定や前提が新たな問題に適用可能かを考えることで、方法の限界や改善につながると思うのです*1

まとめ

今回は研究方法を学ぶ重要性とその意味についてしっかり考えることの重要性について書きました。私も含めて皆でよく考えながら、科学を進めていきましょう。

*1:レアケースだと思いますが、研究の勘所がはじめから分かっているなら特定の方法論に縛られる必要がないかもしれません。

評価という手段を目的にしてしまうと教育に何が起きるか

今回は,とても抽象的なことを書きます。自分としてもまだ問題の整理が完全に済んでいないので,これを書きながら少しでも整理できたものが残せればいいなと祈りながら書き始めます。

教育における評価の機能

様々な教育場面において,しばしば評価が行われます。最も一般的なのは,学習後の成果を調べるための評価でしょう。これは,事後評価または総括的評価と呼ばれます。しかし,教育評価はこれだけではありません。例えば,学習前に学習者の知識や能力を測定することがあります。これは事前評価または診断的評価です。また,教育評価は学習中にも行われます。学習者が,予め定められた目標に近づいているかどうかを探るための評価で,形成的評価と呼ばれています。総括的評価が,成績や科目単位の付与,資格の認定など,学習者個人に対する評価になっているのに対し,診断的評価や形成的評価は,学習する内容の調整に使われます。

評価はあくまでも手段

最近の教育評価では,評価基準の透明性を高めること(言い換えれば,先生の気まぐれで評価基準がぶれないこと)が求められています。これ自体は,評価の公平性や妥当性を考える上で大変重要です。しかし,評価は学習目標を達成することを確認するための手段に過ぎません。教育の目的・目標は学習者の学びを最大化することであって,高い評価を得ることではないことに注意が必要です。

評価を目的にすると何が起きるのか

上記のような,手段としての評価についての議論は,当たり前のことです。しかし,最近の教育評価の透明化は,学習者そして教員にも評価そのものを強く意識させるという効果も持っており,「以下に良い評価を得るか」「以下に良い評価を与えるか」に意識が向いてしまいがちであると感じます。つまり,当たり前が当たり前でなくなってきているとうことです。高評価を作りたいだけなら,自分に学んだ内容があるように感じられなくても,相手が好印象・高評価をつけやすい文言で学習内容を報告すればよいわけです*1。高評価を得られたとしても,その評価に値するような学びが生じにくい可能性が出てきたと思います。これは私自身もそうであって,ときどき何のために評価をしているのかを見直す必要性を感じています。

ではどうすればよいのか

まず,なぜこれが可能になるのかを考えてみたいと思います。私自身はこれをコミュニケーションの問題だと捉えています。どういうことかというと,本来主観が大事な学びにおいて,評価者の考えそうなことを学習者が予測していると感じられるのです。それは日常のコミュニケーションで頻繁に生じており,話し手は,聞き手の気持ちや考えを予想しながら自らの発言を調整することがあります。仮に,学習者が話し手,評価者が聞き手と考えてみましょう。話し手である学習者は,自分の思ったことを思ったとおりに報告するのではなく,学習という状況と評価者の考えそうなことを予測しながら報告内容の調整をしているかもしれない。それによって高評価が得られると信じれば,これは当然です。さらに言えば,評価者は,学習者の報告を文字通りに受け取らずに,報告内容から学習者が何を考えているのかを予測しなければならない事態となります。このような考えが正しければ,ある種の先の読み合いには果てがないので,学習者と評価者のコミュニケーションは非常に複雑なものになっていっていくでしょう。ではどうすればよいか。これを回避する一手段として,評価と学びの内容を分離が考えられます。例えば,評価の対象とはなっていないことを確認した上で,自らの正直な学びに関する意識を教員に報告してもらう。そこには,「面倒くさい」とか「学ぶ意味がわからない」とか「ありきたりでつまらない」といった教員をがっかりさせるような言葉があるかもしれません。しかし,それはそれとして互いに認めた上で,学びの最大化に挑戦する。そんな過程の築くことがこの問題の自体改善につながるのでないかと思います。

*1:もちろんそれすら難しい場合もあります。

検定力(検出力)の求め方

今回は,当たり前に思っていたことが実はそんなことなかったという話です。

検定力とは何か?

私達が,観察したデータについて,そのデータを取得した大元の集団について考えたいときがあります。そのようなときには統計的仮説検定の手続きにのっとって,推論を行います。統計的仮説検定では,自らが主張したい内容を対立仮説として設定し,それの逆の内容を帰無仮説とします。計算過程では,あえて帰無仮説が正しいと想定した上で,手持ちのデータが帰無仮説の内容に合致するかどうかを確率的に判断します。この確率的に判断するところが,大事であり,難しいところです。典型的には5%が基準になっており,得られたデータが帰無仮説を基準に観察される確率がこの基準未満ならば「あり得ないことがおきた」と考え,ありえないのはなぜかというと帰無仮説に無理があったからだと判断します。5%というのは,100回同じような検定をすれば,その100回の中に帰無仮説を否定できるような真実が一切なかったとしても,5回位は誤って,帰無仮説を否定する危険性があります。これを第一種の誤りと呼ぶことがあります。これと全く逆の話として,実際には帰無仮説を棄却することが正しいにもかかわらず,それをしないという判断になることもあります。いわゆる効果や差異の見落としです。先程の第一種の誤りと対比されて,第二種の誤りと呼ばれます。研究をしていれば,できるだけ,真実に近いことを明らかにしていきたいわけですが,確率を基準に判断している以上,実際には帰無仮説が正しいのに,否定してしまったり,帰無仮説を否定すべきなのに見落とすことがあるわけです。ここまでを表にまとめると次のようになります。

帰無仮説が正しい 帰無仮説は誤り
帰無仮説を否定しない 正しい判断 見落とし(第二種の誤り)
帰無仮説を否定する 誤った否定(第一種の誤り) 正しい判断

正しい判断というのが2つあります。このうち,右下の場合になる確率が,検定力です。

どのように検定力を求めるのか?

検定力は,帰無仮説を棄却すべきときに,正しく棄却している確率です。つまり,帰無仮説を棄却するということを前提に話を進める必要があります。帰無仮説を棄却するには,検定統計量の帰無分布や棄却域を考えます。サンプルをもとに推定した帰無分布の標準偏差を考えると信頼上限や信頼下限を計算可能で,それよりも検定統計量が大きくなると帰無仮説が棄却されるわけです。以下の図は,帰無仮説が正しい場合の検定統計量の分布で,ピンクの領域が棄却域になる確率(つまり有意水準)になっています。

f:id:jnobuyuki:20190114054452j:plain
帰無仮説から考えた検定統計量の分布と有意水準


つぎに,サンプルから推定した検定統計量もとに検定統計量の分布を構成してみます。そして,帰無分布上の信頼区間の限界との関係を見てみましょう。すると,検定統計量は,それ以上低くなると,その分布が正しいにもかかわらず,帰無仮説を棄却できない状態が
表現できます。

以下の図の右側の分布が,サンプルから推定した検定統計量の分布です。その分布の左側の水色部分が帰無仮説を棄却できない確率を示しています。

f:id:jnobuyuki:20190114054638j:plain
帰無仮説から考えた分布とサンプルから推定した分布

この裏を返せば,その検討統計量よりも高い値がある場合には,その分布が正しく,帰無仮説を正しく棄却した場合になります。よってこれが検定力といえます。

以下の図の右側の分布の緑色の部分が検定力に相当します。

f:id:jnobuyuki:20190114054738j:plain
有意水準と第二種の謝りと検定力

ここで大事なのは,検定力を求めるために,帰無仮説の棄却という過程を経ていることです。棄却には当然,有意水準が関わります。そしてそれは,第一種の誤りの確率を示しています。つまり,第二種の誤りとその裏返しとしての検定力を考える際に,第一種の誤りを切離して考えることはできないのです。統計学の教科書に,第一種の誤りと第二種の誤りはトレードオフ(つまりどちらかを低くしようとすると,他方が高くなる)ので,両者を同時に低くすることはできないと説明されていることがありますが,その理由がここにあります。

実は真逆の表現がある

今回,この記事を書くにあたって,いくつかの統計学やデータ分析に関する書籍をあたってみています。その中で発見した驚きを報告します。それは,検定力を1−とβと表現する本βと表現する本の二種類があることです。さらにいろいろな人に話を聞く中でわかってきたのは,どうも数理統計学の領域では検定力をβと表現することがあるようです。この場合,第二種の誤りが1−βとなります。先程の統計的帰無仮説をベースにする説明では,2種類の誤りについて考えましたが,検定力をベータとするのは,有意差有りと判断した上で,それが誤りの場合と正しい場合という方針で考えられています。ここで大事なのは,どちらが正しい・適切かを考えるのではなく,人によっては真逆の表現をとっている可能性があるということです。学問領域をまたいだ共同研究を行うときには,この点を慎重に確認した上で議論すると良いと思います。

論文を書く予定がある人は,まずはできるだけ論文を読みましょう

今回は,最近考えていることを共有したいと思って書きます。タイトルが言いたいことそのままなのですが。

論文には構造がある

論文には,構造があります。研究領域や学術雑誌によって,その構造自体は異なることもあります。最も典型的な形式としてIMRAD (Introduction, Method, Result, and Discussion)があります。私が専門としている心理学の学術雑誌では,ほとんどこの順序で出てきます。しかし,例えば神経科学分野では,結果が最初に述べられることになっているものもあります。このような構造があることで,研究者(とそうでない人)は,論文を短い時間で読めます。

論文には数多くの専門用語がある

論文は,原則として「掲載スペースが狭いので奪い合う」ことになっています。よって,冗長な表現や長い表現が避けられる傾向にあり,それを補うための数多くの専門用語が出てきます。例えば心理学の領域で出てくる「態度」,「制約」のような表現は,一般的にも使用できるものですが,それが指す内容は一般的な意味からだいぶ離れています。*1

論文には特有の言い回しがある

論文には,専門用語以外にも特有の言い回しがあります。例えば「傾向」。この言葉は,統計的仮説検定において,後少しで効果が有意になりそうなときに使います。心理学だったら,確率(p値)が5%以上10%未満で出てくる表現です。また,統計的仮説検定では,帰無仮説が棄却できないときに,「〜でないとは言えない」といったまわりくどい表現が使われます。この表現は「〜である」と言い切ることと明確に区別されます。

読みながら自然に学ぶ論文のルール

上記のように,論文には,特有の構造,用語,言い回しが多数使われています。これらをマニュアル的に理解するのは,論文を書く上で非常に重要です。それに加えて,たくさんの論文を読んで,その特有の言い回しを早く身につけることが大事だと思います。なぜ,身につけたほうが良いかというと,それはもちろんそれがその世界のルールだからです。しかし実際にはそれ以上の意味があると思います。こういった書き方に沿った文章を読むと読み手に安心感が生まれると思います。論文の構造や言い回しが適切に使われている論文と,そういった言い回しがあり得ない表現になっている論文を比べたら,どちらをより信頼するでしょうか?せっかく自分の論文を読んでくれた読者にはぜひ内容を信頼してもらいたい。論文特有の構造や言い回しを適切に表現することが,それに貢献すると思います。

*1:一般的に態度とは,内面の状態を指すものだと思いますが,心理学的態度は,表面に表れている行動を含んでいます。また,認知的制約という用語は,制限という意味ではなく,偏りのような意味です

R言語でデータを分割してから,それぞれに同じ操作を繰り返す

今回はR言語の使い方のヒントを皆様と共有します。

データの分割はsplit関数

データを分割するには,split関数が便利です。split関数では2つの引数をとり,1つ目がデータオブジェクト,2つ目が分割するための基準となる変数を設定します。
以下の例を見てください。

sampleData <- data.frame(ID = c(1,1,1,2,2,2,3,3,3), performance = c(2,3,4, 3,4,5,4,5,6))

splitData <- split(sampleData, sampleData$ID)

このとき,splitDataの内容を見ると,分割されたデータのそれぞれがリスト内に保存されていることがわかります。

splitした後のデータへの操作

リストの中身を見るときには通常の でインデックスをつかうのではなく,[]二重にカッコを使ってインデックスで指定します。
例えば分割したデータの最初の部分(IDが1の場合)だけを見るなら以下のようにします。

splitData[[1]]

for関数の引数のインデックスをこのリスト内の要素呼び出しに使えば,分割されたデータのそれぞれに,同じ操作を繰り返し使えます。例として,IDごとの平均値を計算して,偏差の変数を作ってみます。

for (i in 1: length(splitData)){
    #平均を計算
    averagePerformance <- mean(splitData[[i]]$performance)
    splitData[[i]]$deviation <- splitData[[i]]$performance - averagePerformance 
}

このようにすると,IDごとに異なる平均値で偏差が計算できます。

分割したデータをもとに戻す

分割したデータに操作を加えたら,最後はもとのデータに戻しましょう。このときunsplit関数を用います。
分割の基準の変数をそのままもう一度使うのがコツです。

unsplitData <- unsplit(splitData, sampleData$ID)

このようにすると,subset関数で部分データを作らなくても,分割データに対して次々に操作を加えられます。

数式は(そんなに)怖くない(3)

本日は,数式怖くないシリーズ3つめの話題です。共分散を取り上げます。

共分散とは

共分散とは2つの変数の変動(または連動)する様子を1つの値に要約したものです。ある変数の値が高くなるときに,他の変数も同じように値が高くなるのか,逆に低くなるのか,それとも連動しないのかを知ることができます。

共分散を求める式

共分散の計算式を眺めてみましょう。

 cov_{xy} = \frac{\sum_i^n{(x_i - \overline{x})(y_i - \overline{y})}}{n}

全体として眺めてみると,分数になっていて,1番目からn番目までについて何かを計算したら,すべて足し合わせて,要素数のnで割るという式になっています。要素を全部足して,要素数で割るのは平均ですね。これもなにかの全体的な傾向を真ん中あたりの値で示すという意味がありそうです。

分子を眺めてみると,2つの計算結果の掛け算になっています。カッコの中を見ると,各要素の値から全体の平均が引かれていることがわかります。個々までの計算を表す言葉をまとめれば,割り算,足し算,掛け算,引き算しか出てきていません。つまり,やろうと思えば紙とペンで手計算もできそうです*1

次に,分子の部分に注目してみます。分子は2つの式の掛け算でできていて,それぞれは,各要素から平均値を引いた値です。ここで大事なのは,この値が正負両方の可能性があることです。要素の値が平均値より大きければ,引き算の結果が正になり,平均値より小さければ引き算の結果は負になります。それで,この結果を掛けているので,考えられるのは次の4つのパターンです。

  • 正の値 x  正の値 = 正の値
  • 正の値 x 負の値 = 負の値
  • 負の値 x 正の値 = 負の値
  • 負の値 x 負の値 = 正の値

つまり,両者の正負が一致していれば,掛け算の結果が正,不一致なら掛け算の結果が負になります。共分散は全体として,この傾向を要約したものと考えられるので,全体的に平均からの差の方向性が一致している要素が多いか,差の方向が逆になっている要素が多いかを示していることになります。

最後に,この式は,各要素の値をどんな単位で扱うかによって,共分散自体の大きさが変化してしまうことを指摘しておきます。

グラフから考える共分散の意味

今度は,グラフを使って考えてみます。先程から,平均値を引いた引き算の結果と読んでいるものは,もう少し難しい言葉でいうと偏差と言います。2つの変数の偏差の正負組み合わせをグラフで考えると以下のようになります。このグラフは,各変数の平均値の位置で線が引かれて,4つの領域が作られています。まず,偏差の正負が同じ場合は,グラフ上,データの値が,右上の領域または左下の領域にあることになります。

f:id:jnobuyuki:20181203153650p:plain
偏差(要素と平均の差)の正負が2つの変数で同じ場合のデータプロット位置
一方,2つの変数の偏差の正負が異なるなら,グラフ上,データの値が左上か右下の領域にあります。
f:id:jnobuyuki:20181203153758p:plain
偏差(要素と平均値の差)の正負が2つの変数で異なる場合のデータプロット位置

つまり全体的な傾向として,偏差の正負が同じことが多いなら,共分散は正の値になり,グラフ上右肩上がりの傾向を持ちます。逆に,偏差の正負が異なることが多いなら,共分散は負の値になり,グラフ上右肩下がりの傾向を持ちます。このように考えると,共分散を計算することによって,グラフ上でのデータの直線的な傾向の様子を推論することができるようになります。

まとめ

今回は共分散を計算する式を取り上げました。基本的には四則演算しかしていないですし,値の取る意味がわかれば,グラフにデータをプロットするときの様子との対応関係もよく分かると思います。

*1:もちろん要素数が手計算でもなんとかなりそうな範囲に限ります

サンプル平均の期待値はサンプルサイズがいくつでも同じです

本日は,久々の投稿な上に,ちょっと込み入った話です。込み入っているけど,推測統計を理解するためにぜひ抑えておきたいポイントについて書きたいと思います。

サンプルの平均を母平均の推定に使う

推測統計学では,実際に持っているデータをデータを取った集団*1から持ってきた「サンプル」であるとみなします。だから,毎回毎回取ったデータが変わる可能性があります。大事なのは,今,手持ちのデータを利用して,もともとの集団全体の特徴を推定するところです。例えば,集団全体の平均(母平均)は,今持っているサンプルデータの平均として推定します*2。今あるデータから計算するしかないんだから仕方ないよね,という理解でも良いのかもしれません。でも,この方法はそんな妥協の産物というものでもなく,サンプルデータの平均値の期待値が母集団に一致することを根拠にできます*3。「サンプルデータの平均の期待値」というのが直感的ではないと思うので,これをちょっと掘り下げてみましょう*4

数式で考える

 \overline{x} = \frac{\sum_i^n{x_i}}{n}
これが平均を求める式ですね。要素数がn個のときに,そのすべての要素を足し合わせて,要素数で割れば良いです。この値の期待値を考えてみます。期待値とは,取りうる値とその確率をかけたものをすべて足し合わせたものです。

 E(\overline{x}) = E( \frac{\sum_i^n{x_i}}{n})
この式の分母は,要素数が決まれば定数になるので,確率を考える必要がありません。なので,E()の外に出してみましょう。

 E(\sum_i^n{x_i}) / n

ここでE()に入っている部分は,それぞれの要素を足し合わせたものです。それがわかりやすいように書き直します。

 E(x_1 + x_2 + x_3 + ... + x_n)  /  n

各要素の和の期待値は,各要素の期待値の和と考えても同じことなので,式を少し変えます。

 (E(x_1) + E(x_2) + E(x_3) + ... + E(X_n)) / n

ここで E(x_1),ある要素の期待値を考えてみます。ある要素の期待値は,集団の中のすべての要素が等しい確率で出ると考えると,集団全体の平均値に等しくなります。これは E(x_2)でも E(x_3)でも同じです。これを考えると式が以下のようになります。

 (\overline{x} + \overline{x} + \overline{x} + ... + \overline{x}) / n

平均値がn個あって,それをnで割っているので,結局は \overline{x}というのが,平均の期待値になるわけです。
ここで大事なポイントは,要素数nが何個であっても結局式の上で数値が変動する要素がないことです。

シミュレーションしてみる

一回一回のサンプルの値は必ずしも集団全体の平均に一致するとは限りません。でも,どんどんサンプルをとっていって,それまでのサンプルの平均をまとめて,その平均をとったらどうなるでしょうか?
まずは,10万個の全体集団を作りましょう。rnorm関数を使うと自分で決めた平均と標準偏差を持つ正規分布からランダムに値を生成してくれます。

populationData <- rnorm(100000,0,1)

今回たまたま生成した10万個のデータの平均値は0.001270158でした。では,この中から2個のデータをとってきて,サンプルを作ります。その平均値を次のように計算できます。

sampleData <- sample(populationData,2)
mean(sampleData)

これを1000回ほど繰り返します。さらに,毎回,それまでの平均値のデータを利用して,「平均値の平均」を計算します。

SampleRes <- NULL
Res <- NULL
for ( i in 1:1000){
  
  sampleData <- sample(populationData,2)
  SampleRes <- append(SampleRes, values = mean(sampleData))
  Res <- append(Res, mean(SampleRes))
  
  
}

この結果を見てみましょう。まずは,サンプルを毎回取るごとの平均値はこのようになりました。

f:id:jnobuyuki:20181125174758j:plain

横軸は1回目から1000回めまでの回数を表していて,縦軸がサンプルの平均値です。おおよそ−2から2の範囲で値がばらついているのがわかります。さらに,毎回平均を計算するごとに平均の平均を計算したら次のようになりました。

f:id:jnobuyuki:20181125174848j:plain
このグラフも横軸は1回目から1000回目までの回数を表しています。これを見ると,徐々に0付近に値がよっていく様子がわかります。ちなみに1000回めの平均の平均は0.0003681900でした。

では,1回のサンプルの要素数を10にしてみたらどうなるでしょうか?各回のサンプル平均は以下のようになりました。

f:id:jnobuyuki:20181125175303j:plain

値が-1から1の間でばらついています。要素数2のときよりもばらつきが小さいように見えます。平均の平均を計算した結果は以下のようになりました。

f:id:jnobuyuki:20181125175448j:plain

やはり計算を重ねていくと0付近に値が寄っていきます。ちなみに1000回目の「平均の平均」の値は-0.006140395でした。
このように,サンプルに含まれる要素数がいくつであろうと,もともとの集団全体の平均値に次第に近づいていくことがわかります。

まとめ

今回は,数式とシミュレーションという異なる方法を用いながら,サンプル平均の期待値が集団全体の平均になることを見てきました。

*1:母集団と言います。

*2:この場合,データを1点の値で推定するので点推定と言います。

*3:このような性質を普遍性を持つといいます

*4:ここまで書いた時点で掘り下げたからといってそれほどわかりやすくなるかと言えばそうでもない気がしています。