jnobuyukiのブログ

研究していて困ったことやその解決に関するメモ。同じように困ったあなたのために。twitter ID: @j_nobuyuki

学術雑誌で論文を出すとはどういうことなのか?(1)

今回は、論文が学術雑誌に掲載される*1ことのプロセスや意味などを考えてみたいと思います。世の大半の人にはどうでも良いことなのかもしれないのですが、中には「研究者が何かといえば論文、論文と騒いでいるが、論文が出るのがそんなに大事・大変なことなの?」という疑問をお持ちの方がいらっしゃるかもしれないので、そういう方に向けて、僕が知っていることを書きたいと思います。第1回の今回は、論文の著者という立場で書いてみたいと思います。
あくまでも個人的な経験に基づく個人の見解です。異なる考え方を持っている研究者もいるかもしれませんし、それはそれで良いと思います。

筆者の経験

これまでに論文が学術雑誌に掲載された経験が何回かあります。筆者の専門は心理学で、日本国内の心理学系学術雑誌に何回かと英語圏の学術雑誌にも何回か掲載されています。自分が責任著者(後で説明します)でないものも含めると合計で10回以上はあります。また、審査員として投稿された論文を査読した経験はその2〜3倍くらいあると思います。あとは国内または国際学会に応募された論文または論文要旨の審査や海外の研究助成金の審査の経験があります。なので、人から聞いた話も中にはありますが、基本的には自分で経験したことを元に説明したいと思います。


論文投稿のよくあるプロセス

論文著者から見ると...

1. 論文を書く*2。各学術雑誌には、受け付ける研究の種類や書き方に至るまで細かい指定があるので、それに合わせて書く。
2. 論文を投稿する。以前は印刷した原稿を郵送でしたが、最近はほぼ電子投稿です。投稿用のWEBページで原稿や図表のファイルをアップロードして投稿用原稿を完成させます。これ以降、全てこのwebページにプロセスのログが残っていきます。

(この間約3~6ヶ月)

3. 審査コメントを受け取る。編集者と2〜3人の審査員の審査結果とコメントを受け取ります。この時点で、掲載可となることはほぼないので、審査員のコメントを読みながら論文の修正を試みます。よく指摘されるポイントは、「この研究の意義や先行研究との差分が分かりにくい」「分析結果が分かりにくい。もっと良い分析方法がある」「結果の解釈に論理の飛躍がある」などです。

(この間3〜6ヶ月)

4. 修正原稿とコメントへの返答レターを書く。修正については、基本的に審査者のコメントに合わせます。どうしても修正したくない場合は、その理由を書いて編集者の意見を仰ぐことになります。修正した点とその意図をコメントごとに返答として記載したレターと呼ばれる文書も作成します。
5. 再度投稿する。

(この間3〜6ヶ月)

6. 審査結果を受け取る。そのままで掲載可となることもありますが、少し修正した上で掲載可となることもしばしばあります。また、修正した原稿では、コメントに答え切れていないと判断されれば掲載不可の結果になることもあります。掲載不可となった場合でも、他の学術雑誌に投稿することはできますし、大抵再投稿になります。

(この間約1ヶ月)

7. 出版に向けた原稿の確認と修正。ゲラ原稿と呼ばれる原稿が届くので、スペルミスや引用文献の抜けなどを確認します。

(この間約1ヶ月)

8. 掲載号が決定される。紙に印刷される雑誌よりも早いタイミングで電子的な出版物として世に出ることもよくあります。

論文の審査はコミュニケーション

上記を見て分かるように、最初に論文を学術雑誌に応募してから約1年はかかるというのが典型的なパターンです。論文の審査というのは、合格不合格が決定される単純なものではありません。編集者や審査員とのやりとりの中で研究そのものや論文がブラッシュアップされていくプロセスが含まれています。特に、著者が適切であると考えていた研究方法や分析方法について、審査員が第三者的観点からそれを検証する点が重要です。著者は自分たちのやり方を取れば、研究の結論にとって良い結果が得られると感じています。第三者的な立場から見て、それが妥当な判断であるとお墨付きをもらうことで著者は安心しますし、論文の読者も安心します。

審査員のコメントに全て従うわけではない

審査員のコメントによって研究の品質が向上すると書きましたが、審査員もまた人なので、100%そうなるわけではありません。なので、どうしても著者が自分の主張が正しい場合には、審査員コメントに反論することも可能です。その場合は担当編集の人がどちらの言い分をとるかを判断することが多いです。経験的には、審査員の方のコメントが著者の主張と大きくずれている場合、論文の表現が審査員にとって誤解を生むものであったということも多いです。なので、反論する際には、いつも以上に慎重に元の論文と審査員コメントを読み込む必要があります。

査読された論文に研究者がこだわる理由

以上見てきたように、論文の査読プロセスは、研究の品質向上にとって重要なプロセスとなり得ると思います。また、読者も一定の品質が著者以外の研究者によって担保された研究であると納得してその内容を読むことができるわけです。

*1:「出版される」「パブリケーション」と呼ばれたりします。

*2:もちろんこれがとても大変だし、後のプロセスを意識して書くべきですね。

Rのfactanal関数で因子分析した時に因子負荷行列を全て表示したい

今回はRを利用した分析に関する非常に細かい話です。

因子分析とは

因子分析は、ある個人・対象について、複数の指標で計測を行った場合に、それらの指標を上手に要約する方法の1つです。例えば、ある学校のある学年の生徒に国語・算数・理科・社会のテストを実施したとします。生徒一人ひとりに各教科の得点が記録されている状況です。もちろん各教科ごとにみていけば良いのですが、4つの科目の成績を因子分析によって1つに要約し、いわゆる「学力」のようなものを考えることができます。この「学力」のように、要約された変数(因子と呼びます)は、それを実際に測るわけではないところが、少しわかりにくいかもしれません。また、単純なテスト得点の合計であれば、強化ごとの重み付けを考える必要がありませんが、因子分析では、因子が各指標に対してどの程度影響を持っているか *1の重み付けを計算しています。これが因子負荷です。

Rのfactanal関数で因子分析

因子分析をR言語で行う場合は、factanal関数が利用できます。引数として複数の指標のデータテーブル、因子数、回転方法を指定します。以下の例ではdataset*2というデータテーブルに対して因子数2, 因子の回転方法としてpromax法を指定した書き方を示しています。

res.factanal <- factanal(dataset, factors = 2, rotation = "promax")

因子負荷行列の負荷量の値を全て表示したい

factanal関数の結果はprint関数で表示できます。ただしこの時、因子負荷量が0.1未満の値は非表示となるようにデフォルトが設定されています。実際に見てみると表示がない値が気になるだけでなく、非表示があることで見にくくなります。これを避けるには、結果を表示する際のprint関数にcutoffという引数を値0を代入して加えます。これで全ての因子負荷量が表示され、結果として、表全体も見やすくなります。

print(res.factanal, cutoff = 0)

*1:今回深く説明しないのですが、因果の方向的には因子がまずあって、測定可能な指標は、その因子の影響を受けていると考えます

*2:Rのベースパッケージで利用可能なirisというデータ

機械学習の精度指標

昨今、いわゆる機械学習の技術は、学術研究だけでなく、様々な産業応用がなされています。ユーザーとしては、実際に使ってみて、それが便利であるか否かで利用を判断すれば良いと思います。一方で、こういった技術がどの程度、客観性があったり、信用できるものなのかを理解できれば、技術の利用がさらに進むのではないかと考えました。そこで今回は、機械学習の精度、つまりどの程度うまくデータを予想できているかの指標を3つ考えてみたいと思います。

想定する問題

機械学習は計算方法も、利用方法も様々です。その中で今回は2値分類という問題を考えます。2値分類というのは何かの情報を使って2つの状態や行動(例えば「はい」か「いいえ」か)を予想すると考えると良いでしょう。これが当てはまれば、なんでも良いわけですが、より具体的な問題として、ある商品を宣伝・販売しているウェブページにおいて「カートにいれる」のボタンを押すか押さないかを予想するとします。

予想と実際の行動を第1種の過誤と第2種の過誤で考える

機械学習で色々な情報を元に、ボタンを押すか押さないかを予想します*1。すると予想(押すか押さない)と正解(実際に押すか押さない)の関係は以下のような4つの場合のいずれかになります。

正解:押す 正解:押さない
予想:押す 予想通り 予想外れ
予想:押さない 予想外れ 予想通り

予想通りの場合と予想外れの場合がそれぞれ2つあります。ここで最初に予想したものによって、これらの呼び方を変えてみます。

正解:押す 正解:押さない
予想:押す TP FP
予想:押さない FN TN

TP: True Positive, TN: True Negative, FP: False Positive, FN: False Negative

ここで押さないのが基本状態で押すのが特筆すべき行動という認識で見てみると、これは統計的仮説検定の第1種の過誤、第2種の過誤とも似たような状況であることがわかります。第1種の過誤、つまり実際には押さないのに押すと誤って予想してしまった場合です。第2種の過誤は、実際に押すのに押さないと予想してしまう、つまり押すの見逃しにあたります*2

正解:押す 正解:押さない
予想:押す 正しく予想 第1種の過誤
予想:押さない 第2種の過誤 正しく予想

このように考えてみると、正解率と言っても以下の2種類のような正解率が計算できることになります。

機械学習の精度指標1:Precision

 Precision = \frac{TP}{(TP + FP)}

TP+FPというのは「押すと予測した場合」の合計数です。つまりPrecisionは、「押すと予測した中で本当に押すが正解だった場合の割合」を示しています。

機械学習の精度指標2:Recall

 Recall = \frac{TP} {(TP + FN)}

TP+FNでFNが直感的には少しわかりにくいのですが、TPとFNはどちらも「押すが正解」の場合です。つまりRecallは「押すが正解の場合」のうち、正しく「押す」と予測できた場合の割合を示しています。

ここまでで2つの精度指標はどちらも大事そうです。しかし、2つあるとどちらにより頼ったほうが良いのかなどの考えが頭をよぎります。どうせなら1つの指標でPrecisionとRecallどちらの要素も考慮できないだろうか?そんな指標が以下のF値です。

機械学習の精度指標3:F値

 F値 = \frac{2 * Recall * Precision}{Recall + Precision}

上記の式で分母と分子のそれぞれにRecallとPrecisionが出てきます。よって、F値は、RecallとPrecisionの両者を考慮していることがわかります。しかし、Recallや Precision自体が複数の指標から計算するものになっている上に、分母と分子の両方に RecallとPrecisionが出てきます。なので、Recallと Precisionの値がどのように変化するとF値が大きくなったり小さくなったりするのか直感的に理解しにくいです。そこで上記のF値の式を変換させてみようと思います*3

F値を求める式の変換

 F値 = \frac{2 * Recall * Precision}{Recall + Precision}

Recallと Precisionの定義式をここに代入してみます。

 \frac{2 * \frac{TP}{(TP + FN)} * \frac{TP}{(TP + FP)}}{\frac{TP}{(TP + FP)} + \frac{TP}{(TP + FN)}}

だいぶややこしいので、いったん、(TP + FP)をXとし、(TP + FN)をYとおいて式をもう一度眺めてみます。

 \frac{2 * \frac{TP}{Y} * \frac{TP}{X}}{\frac{TP}{X} + \frac{TP}{Y}}

分子は掛け算なので、分子の中にある分数の分子と分母をそれぞれかければ良いですね。分母は足し算なので2つの分数を通分して足してみます。

 \frac{\frac{2*TP*TP}{X*Y} }{\frac{TP*Y + TP * X}{X*Y}}

分子と分母それぞれX*Yで割っているので、ここは約分しちゃいます。

 \frac{2*TP*TP }{TP*Y + TP * X}

分母はTPでくくりましょう。

 \frac{2*TP*TP }{TP*(X + Y)}

TPで約分できますね。

 \frac{2*TP }{X + Y}

ここでXとYをもとに戻します。

 \frac{2*TP }{(TP + FP)+ (TP + FN)}

これでだいぶ整理できました。まず分子はTPつまり正しく押すと予想した場合の数を2倍しています。次に分母は、分子同様にTPの2倍に加えて、FPとFNがあります。つまり正しく押すと予想した場合の2倍の数に間違って押すと予想した場合の数と誤って押さないと予想した場合の数が足されています。こうして見てみるとF値は2種類の予想外れに対する正解率になっていると理解できますね。最初の式だとよくわかりませんでしたが、式を変形して見たら案外単純な指標であるとわかりました。

まとめ

今回は、機械学習の精度を表す3つの指標Precision、Recall、F値を考えました。実際の分析では、3つとも計算する必要がありそうですが、それぞれの意味をきちんと把握した上で結果をみると分析結果の理解をより楽しめそうです。

*1:典型的な機械学習の話題なら、どんな情報を元に予測するか、どんな計算方法で予想するかが重要なのですが、今回はそのようなポイントにかかわらず問題となる評価に注目しているので、大変雑な説明になっています。

*2:ここでは2種類の予想外れの理解に役立つと思っての説明で、統計学的に2つが等価であると言いたいわけではありません

*3:結論だけ見たい人は途中式を飛ばしてください

心理学の構成概念について

本日は、心理学が扱う「構成概念」を取り上げます。独特な考え方をするのもポイントですが、一般的にも用いる単語が構成概念を指す用語として扱われるとどうなるかについて考えてみます。

そもそも構成概念とは

構成概念というのは実体を持たない説明のために有用な概念と考えると良さそうです。例えば、心理学で扱う構成概念の1つに「知能」があります。知能という概念について、環境により適応しながら行動を選べる能力と仮に定義してみます。このような能力があると、様々なテストで高得点を上げることができたり、特定の職業に寄らずに社会で活躍することをうまく説明できそうです。ここで、知能が脳の特定の部位やその活動に依存していないことが重要です。一般に心の働きは、脳の働きに結びついていると考えられますが、心理学で構成概念として定義している際には、必ずしも脳の特定の部位の活動にその実体を求めていません。

構成概念には定義が伴う

上記の例では、環境への適応という緩い定義を考えました。実際には、もっと厳密な定義を与えることもあります。例えば、上記の知能は、数字や場面の記憶、言葉の知識のようないわゆる知能テストによって測られるものと定義されます。

一般的に使われる言葉が構成概念を示す用語になる

知能という言葉は、心理学だけで用いられる言葉ではないですね。例えば情報学分野では、人工知能がしばしば取り上げられます。また、学術領域とは異なる一般的な言葉としては、知能が「頭の良さ」とか「地頭の良さ」などと考えられることもあります。同じ言葉であっても、学問領域が異なれば、定義が異なることがありますし、一般的に使われる意味とは異なることもあります。現代の心理学は、19世紀末頃から盛んになっており、物理学や数学に比べれば比較的新しい学問です。様々な心の働きを説明する際に、これまで一般で用いられた用語を使い回すことで心の働きを直感的に理解しやすくすることが考えられていたのかもしれません。一方で、これが混乱をうむもとにもなっており、厳密に定義を行った心理学の構成概念としての言葉が、そのまま別の意味として一般に用いられることで混乱や誤用が起きやすくなるでしょう。この問題への対処としては、構成概念として定義を設定した上で言葉を使っていることを伝えていくのが良さそうです。さらに、学問や学問で得られた知見が社会に浸透・普及するためには、学問領域ではしばしば言葉に定義が設定されていると理解することが重要であると思います。

Rで作成した度数分布表のラベルと値をすぐに使いたい

今回はRの使い方の話です。最初に考えた方法がうまくいかなかったので、意外に解決策を見つけるのに手間取ったので自分のためのメモ。でも同じ問題で行き詰まる方にも共有します。

Rで表を作るならtable関数

Rのbaseパッケージで度数分布表を作るときはtable関数を利用します。

data <- c("りんご", "りんご", "オレンジ", "オレンジ", "バナナ", "バナナ", "バナナ")

res <- table(data)
オレンジ バナナ りんご
2 3 2

これ自体は特に問題なく利用できます。

度数分布表のラベルはname関数で取得可能

度数分布表のラベルだけ使いたいことがあります。例えば、度数は関係なく、項目のバリエーションの数だけが気になっているような時です。これはname関数を使えば取得可能です。

names(res)

出力は以下のようになります。

[1] "オレンジ" "バナナ" "りんご"

度数分布の値を取得するにはどうすれば良いか?

table関数の出力は、table クラスという特殊な形式をとっています。リストオブジェクトではないのでunlist関数を使っても値とラベルの分離ができません。tableオプジェクトの値だけを取り出す際にはas.numeric関数が良さそうです。

as.numeric(res)

以下のような出力が得られます。

[1] 2 3 2

データフレームオブジェクトの利用

table関数で出力した度数分布表のラベルや値を別の計算で再利用するならdata.frame関数でデータフレームオブジェクトにしてしまうのが一番便利そうです。

new.data <- data.frame(res)

これを実行するとnew.dataの中身は以下のようにdataとFreqという変数を持つデータフレームオブジェクトになります。

data Freq
1 オレンジ 2
2 バナナ 3
3 りんご 2

インプットとアウトプット(1)

久しぶりに書きたいことが出てきたので、インプットとアウトプットについて考えていることを何回か書いてみたいと思います。ここで言っているインプットとアウトプットはプログラミングや統計で利用する関数の入力・出力のことではありません。読書やインターネット検索、勉強会参加など何らかの方法での知識や情報を集めることをインプット、自分で作った成果やまとめた知識を他の人に伝えることをアウトプットと考えています。

インプットがあってこそのアウトプット

何かをアウトプットするには、自分の中にある知識や情報を見直すことが大事です。では、その自分の中にある知識や情報はどこから来たのか。完全に自分の中から出てくる知識というのもあるにはありますが、周りの人、書籍、ブログなど自分の外側にあるものから得られることがほとんどです。そういう意味においては、まずインプットが重要で、どんどん自分の中に知識をため込みたい。インプットがあってこそのアウトプットとはそういう意味です。

アウトプットがあるからこそのインプット

では、何か目的があってアウトプットする際に、自分の中にたまたまあった知識や情報だけを使うのでしょうか。それでことが足りる場合は案外少ないです。では、足りない知識はどうすれば良いか。一生懸命考えるという方法もあります。ですが、周りの人、書籍、ブログなど自分の外側にあるものから得るのが手っ取り早いでしょう。先ほどと同じようなことを書いているように見えますが、実は、インプットとアウトプットの主従関係が逆転しています。今は、アウトプットが主体であり、それに必要な何かを能動的にインプットする必要があるのです。アウトプットがあるからこそのインプットとはそういう意味です。この方法には1つメリットがあります。アウトプットの枠組みの中に必要な知識なので、知識がどのように生かされるのか、どのように体系づけられるべきなのかが知識・情報を集める時点で決まっています。すると、その枠組みが手がかりとなって、次に同じような場面でその知識が必要になるときにもスムーズに思い出しやすくなると思います。

まとめ

今回はインプットとアウトプットの関係について考えて、アウトプットを先に定めてしまうことのメリットを紹介しました。

Rを利用したデータのまとめ方(1)

今回は、久しぶりにRの基本的な使い方について説明します。

データをまとめる方法

アンケート調査や実験などでデータを取得し、スプレッドシートなどになっているデータについて、色々な方法でまとめることができます。

変数の特徴を知る方法:summary関数で五数要約

五数要約とは最小、第一四分位、中央値、第三四分位、最大値のことで、この5つの数字をみることでおおよそのデータの位置と広がりを知ることができます。Rではこれに平均値を加えた6つの指標をsummary関数一つで計算可能です。

例えば以下のようなデータがあるときに

rawdata <-  c(1,2,3,4,5)

summary関数を使うと

summary(rawdata)

Min. 1st Qu. Median Mean 3rd Qu. Max.
1 2 3 3 4 5

という出力が得られます。左から順に最小値、第一四分位、中央値、平均値、第三四分位、最大値です。

ケースごとにまとめたいときにはapply関数

たくさんの人から取得したデータがあって項目ごとの得点があるとします。次のような場合です。


参加者 問題1 問題2 問題3
A 1 2 1
B 2 2 1
C 1 1 2

Rでこのデータを作るなら以下のように書けます。

rawdata2 <- data.frame(参加者= c("A", "B","C"), 問題1 = c(1,2,1), 問題2= c(2,2,1), 問題3= c(1,1,2))

ここで参加者全体の各問題の平均などを計算するのであれば上記で紹介しらsummary関数が役立ちます。では、個人ごとの合計得点を知りたい場合はどうすれば良いでしょうか。この場合はapply関数が役立ちそうです。

apply関数はケースごとに複数の変数のデータをまとめる計算をしてくれます。引数としてまとめたい変数とまとめ方を指定します。まとめ方については2つの要素があって、1つはまとめる方向です。MARGINという引数で1にすると行方向(ケース、参加者ごとでまとめる)、2にすると列方向(変数ごとでまとめる)に計算します。また、FUNという引数で計算方法を指定します。平均ならmean、標準偏差ならsd、合計ならsumです。
例として参加者ごとの合計得点をapply関数で計算してみましょう。

res <- apply(rawdata[,2:4], MARGIN = 1, FUN = sum)

resでは4,5,4
という出力結果が保存されています。これを元のデータフレームオブジェクトに含めることもできます。

rawdata2$total <- apply(rawdata[,2:4], MARGIN = 1, FUN = sum)

こうするとデータフレームにtotalという変数が増えて各参加者の合計得点がデータとして使用可能になります。まとめた後で、次の計算に使う場合には、このようなやり方が便利かもしれません。