自然言語処理お勉強教室-word2vec-(1)

はじめに

言語処理の勉強しよーと思った次第で,始めた記事です.この記事で取り扱うのは,word2vecを扱おうと思っています.word2vecの記事は他にも大量にあるので,他の記事と対して差分はありませんので,これは私の勉強備忘録となります.今回はcbowを扱っていきます(skip-gramはやらないと思います.).

cbow

you say goodbye and I say hello 

というのがよく,例に出されますが,このうち例えば,

you [] goodbye and I say hello 

と来た時に,このを予測する問題がcbowとなります.基本となるのは,前後にどのような単語をとるかです.この前後となる単語を捉えることで,このの単語を推測するという流れです.よく,以下の図形を見かけます.

f:id:tatsuya_happy:20210228233838p:plain

これはsayを予測するものだと思ってください.この場合,入力層は以下のようになる(コンテクストサイズが1ね). f:id:tatsuya_happy:20210228234319p:plain なぜ,1or0かというと,前後の周りの単語がこいつ「you,goodbye」であるから,この単語があるよ!!というのをモデルに教えているからです.この時,入力層のベクトルの次元は(1,V)であると考えるとわかりやすいと思う.このVはvocaburaryの数です.この図表では,you say goodbye...の7文字しかありませんが,学習させた単語の数と同値になります.

さて,これを中間層に放り込みます.入力層と中間層の計算は以下のようになります. f:id:tatsuya_happy:20210228235453p:plain 中間層は画像のような感じになっており,計算すると1*3の行列が作成できます.入力層の1の部分だけが残り,中間層の上の部分だけが抽出された感じになります.このベクトルがよく「女王+男=王様」とかに利用される,ベクトル表現となります.この1*3のベクトル表現はyouに対してのベクトルであったので,goodbyeでも同様に作ります.こうすることで,二つの1*3のベクトル表現ができることになります.これを積とって割ることで,中間層を作ります(平均みたいなことをする). 出力層では,普通のLinear関数で計算をし,vocaburary分のwordを出力します.今回は7文字しか扱ってないので,7次元で出力していますが,100文字のvocaburaryを学習している場合,100次元が出力されます(一般的には,この時にnegative samplingをするが,省略).この100次元をsoftmaxにかけ,cross entropyでtargetとなる単語を推測するモデルを構築すれば,完成です.

数式を少し見よう.

cbowの数式は以下のような感じです.

f:id:tatsuya_happy:20210301000508p:plain

w_tは予測対象の単語であり,後ろの単語は前後の単語を表しています.Tはテキストの単語数です.条件付き確率ですね.ここを見るだけでも,前後から単語を予測していることは容易にわかると思います.次に,最適化です. f:id:tatsuya_happy:20210301000651p:plain logをとることで和としています(1/Tで割る必要があると思う).マイナスになっているのは,cross entropy 誤差です.ターゲットとなる単語をかけた後の数式となります.このP()うんたらの数式ですが,以下のようになります. f:id:tatsuya_happy:20210301001016p:plain この数式が少しややこしいのですが,分母から見ていきます.この数式はsoftmax関数です.このV_oが先ほどの中間層に当たる部分となります.u_iが出力層の一つとなるものです.分子のu_cがターゲットとなる単語の出力層です.以下,画像です(イメージ図です). f:id:tatsuya_happy:20210301001640p:plain 中間層と出力層の重みをかけると値が出力されるので,それをsoftmaxでやっているという感じです.

実装(PyTorch)

以下のサイトに実装を書きました.PyTorch tutorialを参考に書いてあります. www.kaggle.com

終わりに

word2vecって難しいですね.次は何を勉強しましょうかね...

コミック工学という研究分野が存在する

はじめに

かめはめ波!!」や「ゴムゴムー」や「諦めたらそこで試合終了ですよ」という言葉の数々を多くの人は一度以上,聞いたことがある言葉だと思います.この言葉は日常的にもしばしば使われ,たくさんの印象的な言葉たちを産み出してきました。今やこの漫画は日本だけでなく世界にも広がり、需要数は右肩を挙がるばかりです.実際に、漫画の新刊発行部数は1万以上にもおよぶと共に、電子書籍の方が2017年以降から紙媒体よりも読まれるようになりました(確かそうだったはず).このような膨大なコミックがあるなかで現状の検索はジャンルや初志情報などに限ります.もっと内容に沿うような,例えばワクワクするような漫画が読みたいとか,涙頂戴のような,そういうクエリで探せるようになることが求められています.また,漫画は今や娯楽のために読まれるだけでなく,教育や日本語表現(オノマトペとか)を表すことにも用いられています.教育では日本語初学者を対象に漫画を読ませて,母国の言葉と日本語の表現がどう違うかを学ばせるために,利用されます.以上のような,娯楽に捕らわれない多様性のある漫画の活用を行うためには,漫画の情報を分析したり,データを集めたり,漫画構造の仕組みについて知る必要があります.これらのことを遂行するために,コミック工学と呼ばれる分野があり,体系的にコミックを一つの研究分野として捉えて,知見を集めていく必要があります.その中で,現在では,深層学習の発展とともに,画像や言語処理や音声処理に至るまで,様々な部分で近代手法が用いらています.そこで,この記事ではそれらの研究分野について一部部分だけ紹介したいと思います.

【記事更新】私のブックマーク「コミック工学(Comic Computing)」 – 人工知能学会 (The Japanese Society for Artificial Intelligence)

データに関する研究

漫画を研究するにあたりどのようなデータセットが主に利用されるかを示して起きたいと思います.漫画のデータは著作権が関わるため,他のデータセットと比較しても収集が難しいものであります.しかし,現在は一定の範囲で,分析できるデータセットや作成方法について,報告されているので,その一部を少しかいつまんで紹介したいと思います.

Manga109

漫画を研究し始めたら必ずといっていいほど,このデータセットについてぶち当たります.

Manga109

このデータセットはこのデータセット(以下,Manga109と称する)は,日本漫画のメディア処理の学術研究使用のために,東京大学 大学院情報理工学系研究科 電子情報学専攻 相澤・山崎・松井研究室によりとりまとめられました.Manga109は,日本のプロの漫画家によって描かれた109冊の漫画で構成されています. それらは,1970年代から2010年代に公開された漫画であり, 対象読者層やジャンルも幅広く網羅しています.(詳細はExploreの表をご参照ください). 収録されている漫画のほとんどは,マンガ図書館Z(旧絶版漫画図書館)にて公開されています(サイトから引用). マンガ図書館Zは無料で様々な漫画を見ることができます.さて,このデータセットの構造ですが,「顔,テキスト,コマ,全身」の位置がxml形式で提供されています.このデータを用いれば,この1ページには「何が,どこに,誰が」,を機会が自動で判断することができるようになります.深層学習の物体検出の技術を用いて, https://repository.dl.itc.u-tokyo.ac.jp/?action=repository_action_common_download&item_id=51208&item_no=1&attribute_id=14&file_no=1 のような研究もされていたります.この研究の応用先は,電子書籍のページを見るときに,ユーザに視覚的に見やすいようにすることが期待されます.例えば,人物がぶつ切り状態でコマが下にいかないようにとかが考えられそうです.

f:id:tatsuya_happy:20210225204028p:plain

データセット構築と海外データセット

上記のものと同じようなデータセットは海外にも同じようなものがあります.例えば, [1611.05118] The Amazing Mysteries of the Gutter: Drawing Inferences Between Panels in Comic Book Narrativesのようなものがあります.データ数はこちらの方が圧倒的に多いですが,全てが手動でつけられていません.また,画風(書き方,絵を見てください)も日本のものとは圧倒的に異なっているので,使うときは注意が必要です.しかし,海外の漫画を実質無料でどんなものかなー,というのを確認することができます.

他のデータセットにはセリフ発話者データセット配布サイトのようなものがあります.これは「誰が,誰と話した?」というデータセットを作りたいときに作れるものとなっています.主にこの研究が問題視しているのは既存のデータセットに,「こま,テキスト,顔,人間」の場所の情報を取得することができるが,誰が誰に対して何を会話したか,という情報は取得することができません.この問題を解決することは,下の例の漫画の翻訳に必要不可欠な技術要素となっていくので,自動で「誰が誰に何を話したか」というのを付与することは重要となります.システムも公開されているので,利用してみるのは容易に思えます(使ったことないけど). f:id:tatsuya_happy:20210225205213p:plain

言語処理

言語処理でどんなことがされてきたかをちょっとだけ,紹介します.

情報集約

漫画は海外の人も読むため,日本語から英語に自動で要約してくれるようなシステムは必要そうです.その問題を解決するために,マントラと呼ばれるシステムが公開されています. https://arxiv.org/pdf/2012.14271.pdf 漫画の翻訳の難しさは,「登場人物の主語,誰が話しているか,誰に向けて話しているか,コマの不連続生」にあると思います.この中でも特に難しそうだと個人的に思うのは「コマの不連続生」だと感じてましたが,うまく取り扱っているようです.確か,githubにも上がっていたので確認しておきます.(私がNMTの分野に明るくないため,詳細な情報は?です.すみません) f:id:tatsuya_happy:20210225205852p:plainf:id:tatsuya_happy:20210225205857p:plain

漫画に登場するキャラクタをエゴグラムを用いることで定量的に,表現した研究があります. https://www.jstage.jst.go.jp/article/pjsai/JSAI2018/0/JSAI2018_1J302/_article/-char/ja/ この研究では,5次元で性格を定量的に表し,人間が思うキャラクタの性格とアルゴリズムにより表現した性格の精度を比較することで,有効かどうかを提示しています.この研究背景は,漫画の検索に対する問題を取り扱っています.現状の漫画検索は,ジャンルやレビューなどを対象としたざっくりとした,検索しかされていません.例えば,真面目で優しいキャラクタが登場する漫画を探したい,というようなユーザ欲求には答えることができません.この問題を解決するためには,キャラクタの持ち合わせている性格を把握する必要があります.この背景のもと,「優しい,真面目」というような性格を表す単語から,キャラクタの性格を推定しています.面白いですね.

コミック検索

コミックを探索的に探せることを目標にした研究があります. https://www.jstage.jst.go.jp/article/tjsai/32/1/32_WII-D/_article/-char/ja/ hldaとかtf-idfを駆使して,システム上で,表すことで探索的にコミックを探せるようにしています.hldaパラメータを手動で入れる必要がありますが,うまく取り扱っているようです.

f:id:tatsuya_happy:20210225210647p:plain

終わりに

今回はこんなところで終わろうかと思います.コミック工学はまだまだ発展途上中であり,学会も他のものと比べて新しいです.投稿してみては?

コミック工学研究会

Django Rest Framework(DRF)とVuetifyを使って,csvファイルを読み込ませる

はじめに

この記事ではDjango Rest Framework(DRF)とVuetifyを使って,csvファイルをバックエンド側で読み込ませる流れを記載します.これをやろうと思った時に少しつまづいたのでその備忘録です.

Vuetify側

<v-form type="submit">
<v-file-input  @change="onChange($event)"></v-file-input>
<v-btn @click="Submit()">
</v-form>
  • <v-file-input @change="onChange($event)"></v-file-input>でファイルを読み込むことができます.ファイルを挿入すると$eventの中身に格納されます.読み込んだら下の感じで見れます.

  • 通常のinput type="file"でやる方法で下の中身を出力するにはevent.target.files[0]を記載します.

f:id:tatsuya_happy:20210212152316p:plain

script側の記載方法は以下の通りです.

data(){
return {
  file:""
}}
methods:{

onChange(event){
console.log(event);
this.file = file;
},
 async Submit() {
      const formData = new FormData();
      formData.append("file", this.file);
  
        await this.$axios.post("test/", formData)
        .catch(error => {
          return error.response;
        });
     
    }
  }
  • onChangeでファイルが入力されたのを確認しています.this.fileでファイル情報を格納.

  • test.csvの中身を確認したいときはFileReaderのオブジェクトが必要となるので,別途作成する必要があります.

  • buttonがクリックされたらSubmitが発火.ファイル情報はFormDataで格納します.

DRF

import  pandas as pd
from rest_framework.decorators import api_view
from rest_framework.response import Response

@api_view(["POST"])
def api_view(request):
    if request.method == "POST":
        print(pd.read_csv(request.data["file"]))
        return Response(request.data,status=status.HTTP_200_OK)
  • バックエンド側でapi_viewのurlを作成し,そこにPOSTをします.その上でpd.read_csv()をするとcsvの中身をバックエンド側で読み込むことが容易にできます.

終わりに

今回はvuetifyの機能でファイルを読み込むことをしてみました.

とりあえず Django REST framework(DRF)を使って形態素解析をしてくれるAPIを作ってみませんか?

はじめに

この記事では Django REST framework(DRF)を使って形態素解析をサクッとしてくれるAPIを作ろうと思います.完成したものは以下のようなものです.

f:id:tatsuya_happy:20210126204457p:plainf:id:tatsuya_happy:20210126204452p:plain

この記事ではサクッとやるために,詳細なDRFの中身を説明しません.例えば,serializerが何者とかviewが何者とかを説明するつもりはないです.

DRFの環境設定

Djangoの環境設定は主にsettings.pyという場所で設定します.今回は以下のように設定します.

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    "rest_framework",#記載
    "apps",#記載
]
  • INSTALLED_APPSの一部に

modelsを作成

modelは送られてくるデータのテキストデータを保存するために利用します.

#apps/models.py
from django.db import models

class MorphologicalAnalysis(models.Model):

    text = models.CharField(max_length=30)

    def __str__(self):
        return self.text
  • 受け取るデータはtextフィールドにて受け取ります.max_lengthは受け取ることができる文字数となります.適宜好みの数値を入れてください.

serializersを作成

serializerの主な目的は受け取ったデータがフィールドに対して同じ型であるかを調べるために利用するものです.今回のケースでは,受け取ったテキストデータが文字列であり,文字数が30以下であるかを検証します.以下のように記載します.

#apps/serializers.py
from rest_framework import serializers
from apps.models import MorphologicalAnalysis


class MorphologicalAnalysisSerializer(serializers.ModelSerializer):

    class Meta:
        model = MorphologicalAnalysis
        fields = ( "text",)

viewを作成

この記事ではクラスビューを使わずに,関数ベースで記載したいと思います.関数ベースで書くことは自分がしたい事を詳細に記載する必要があり,クラスで記載するよりDjangoの内部動作を詳細にしる必要があります.そのため,この記事ではその内部動作を省略せずに関数ベースで書くことで,理解を促す意味で関数で記載していきます.

以下,形態素をして欲しい文章を送り,形態素分割後のデータを返却してくれるコードです.

# Create your views here.
from rest_framework.decorators import api_view
from rest_framework.views import  APIView
from rest_framework.response import Response
from rest_framework import status

from apps.models import MorphologicalAnalysis
from apps.serializers import MorphologicalAnalysisSerializer
from apps.keitaiso import Wakati

#function API View

@api_view(["GET","POST"])
def keitaiso_api_view(request):
    if request.method == "GET":
        queryset = MorphologicalAnalysis.objects.all()
        serializer = MorphologicalAnalysisSerializer(queryset,many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

    if request.method == "POST":
        serializer = MorphologicalAnalysisSerializer(data = request.data)
        #serializer.is_valid(raise_exception=True)でも良いです.
        if serializer.is_valid():
            serializer.save()

            #形態素コード
            wakati = Wakati()
            kaiseki = wakati.parse([serializer.data["text"]])

            return Response(kaiseki,status=status.HTTP_201_CREATED)
        return Response(serializer.error_messages,status=status.HTTP_400_BAD_REQUEST)


class MorphologicalAnalysisAPIView(APIView):
    def get(self, request):
        article = MorphologicalAnalysis.objects.all()
        serializer = MorphologicalAnalysisSerializer(article, many=True)  # manyは複数オブジェクトを返すときに必要
        return Response(serializer.data)

    def post(self, request):
        serializer = MorphologicalAnalysisSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()

            # 形態素コード
            wakati = Wakati()
            kaiseki = wakati.parse([serializer.data["text"]])
            
            # kaisekiしたデータを保存したい場合は以下のように,kaisekiというフィールドをモデルの方で作成して,保存する方法があります.
            # serializer.save(kaiseki = kaiseki)
            

            return Response(kaiseki, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

  • api_viewのデコレータは関数が「送られるURLをGETで受け取るのかPOSTで受け取るか」を記載することで,どのAPIに対応するかを判断してくれます.
  • 関数の引数のrequestは,「送られてくるAPIの種類(POSTとかGETとか),データ」が格納されいます.
  • データをserializerに渡すことでvalidationをすることができます.意図しないデータが渡された場合,エラーが出力されます.
  • validationに問題がない場合,渡されたテキストデータを形態素解析にかけます.
  • Responseは返すデータ,それに対してのstatusを記載します.

  • wakati()は形態素できるクラスを別で作成しております.

  • classで記載する方法も載せておきました.

形態素解析は以下のように実装しました.

#apps/keitaiso
import MeCab
class Wakati(object):
    def __init__(self, grammer=["名詞"]):
        self.mecab = MeCab.Tagger("-d  /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd")
        self.grammer = grammer

    def parse(self, sentence):
        '''
        sentence = [
            "hogehoge",
            "hogehoge",
        ]

        result = [
            ["hoge","hoge"],
            ["hoge","hoge"]
        ]
        '''
        result = []

        for text in sentence:
            lines = self.mecab.parse(text)
            lines = lines.split("\n")
            line_result = []

            for line in lines:
                feature = line.split("\t")
                if len(feature) == 2:
                    analyze = feature[1].split(",")
                    gram = analyze[0]
                    if gram in self.grammer:
                        line_result.append(analyze[6])

            result.append(line_result)

        return result

urlsを設定

urlsは以下のように設定します. セッティングの方は以下の通りです.

# setting
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path("apps/",include("apps.urls")),
]

アプリケーション側は以下の通りです.

from django.urls import path
from apps.views import keitaiso_api_view

urlpatterns = [
    path('keitaiso/', keitaiso_api_view,name="keitaiso"),
]

まとめ

簡単に形態素解析をしてくれるAPI実装をしました.フロントの方は実装しませんでしたが,別のアプリケーションを作った時にやってみようかと思います.

t検定を使わずにベイズアプローチ(BEST)で対象グループに平均値に差分があるか確認したいなー

はじめに

この記事では,t検定を使わずにベイズアプローチで平均値に差分があるかどうかの手法を紹介する記事です.平均値に差分があるかというのは,例えば1組は教えるのが上手い先生が授業を行うが,2組は教えるのが下手くそな先生が授業をした後,どちらの組もテスト受けた時,この1組と2組の平均値に差分があるかを調べることにあります.この例題では,当然のごとく1組の方が良さそうです.というように一般的に,1組には〇〇という効果を与え,2組には〇〇という効果を与えることを行い,どちらの方が効果が良かったのかを知る方法となります.この議論を行うために今までは,t 検定やu検定 などの古典的統計学の手法が採択されてしばしば論文の中に登場してきました.これらの違いはパラメトリックかノンパラメトリックかで使う手法が異なりますが,やりたい本質としては,対象グループの平均とか中央値に差分があるのかどうかを判断したいわけです.これらの手法は仮説検定と呼ばれ,これらには私が特に思うに3種類の共通点があり,以下に記します.

  • 得られたデータから対象グループが違うかどうかを判定する
    • 得られたデータ数が30個であるならば,その30個は平均値に差分があんの?を判定する手法が仮説検定となります.
  • 得られる分布はp値を判定するための正規化された分布
    • 0を平均値に1を分散にN(0,1)のような分布でプロットされるイメージです.
  • p値に従い棄却するかどうかを判定する
    • H_0:帰無仮説を設定し,p値(p<0.05とか)に従いh_0を棄却するかを判断.この時H_0は対象グループの平均が同じである(μ0 = μ1).

仮説検定でやっていることは主に上記の3種類がやりたいことだと思います.しかし,これらの情報が我々にとって重要なデータとなり得るのだろうか!!???ということで,上記の3種類に対してケチをつけてみましょう.

まず,1つめについてです.データ数が30個の場合はたまたま帰無仮説が棄却できたけど,データ数が50個の場合はどうなんだよ!!と言われた時に批判することはできません.なぜなら,今回用いているデータ数は一般性が十分にあるといえるほどのデータ数ではないためです.例えばデータ数が30個ではなく100,000個のデータでやっているならば100,200だろうが110,000であろうがケチを付ける人はそういないでしょう.しかし現実的にここまでのデータを直接集めることは非常に困難となります.システム実験でアンケートを使ってやるとナルト非常に多くの時間を必要とするためです.というように仮説検定はデータが少なければ少ないほどケチが付けることができてしまいます.

2種類目の分布の話はt検定の手法や u検定などの手法は直接平均値の差分の分布のようなグラフを生成するわけではありません.あくまで,正規分布の正規化系に当てはめてそれを元に分布関数を作成するため,平均値の差分がプロットされて分布関数は作成されていません.以下に図を記す.

f:id:tatsuya_happy:20210110195323p:plain

上記で記したように従来の分布は上で記されたzの分布の範囲のようなものです.一方で,本当に欲しい分布は下に記載されている平均値の差分の分布ではないでしょうか?これを見ることによって実際どれだけ離れているのかを数値的に判断することが可能です.

最後に3種類目ですが,P値の話となります.この議論はいくつもの論文でしばしば見られるかと思いますが,信頼区間が90%,95%99%のどれにするかということです.例えば,90%で棄却することができないが95%では棄却することができるとなると(信頼係数が低いほど信頼区間の幅は狭く,はずれの可能性は高くなる),研究者は95%で信頼区間を決めてやっぱり平均に差分はありました!と論文に記載するかもしれません.一方で,違う研究者は90%のままやり続けて,平均値に差分はありませんでした!と結論づけるかもしれません.このように,信頼区間を決める方法が1つ違えば結果は変わってしまい,研究者の各人にとって結論が異なるのは好ましくありません.この信頼区間を決める方法は先行研究に習うことや慣習的な95%を信頼してやる方法がありますが,実用的な議論をするならば各問題に対して最適な範囲を決めるのが妥当だと言えるのではないでしょうか?例えば,Aという問題には88%を設定し,Bという問題は93%を設定するような,95%である必要は特にないけど,慣習的にそれを定めてしまっています.

以上の問題を背景に,この記事ではt検定を使ってみた上で,上記の指定した問題を解決するベイズアプローチの手法の1つであるBEST(Bayesian Estimation Supersedes the t-Test)を紹介します.そこで,この記事ではBEST1 における注意点や解釈を含めて,t検定と比較しつつBEST アプローチの優位を提示することを目的とします.

馴染みのあるt検定

この章では馴染みのある,t検定(Welchのt 検定)を用いて対象グループ間に平均値の差分が確認できるかを検証します.対象とするデータは薬剤評価のための臨床試験の評価に関するデータを利用します.この試験では,治療群(薬を投与された人)と対照群(プラセボを投与された人)のIQスコアを比較することで,知能を向上させるとされる「スマートドラッグ」の有効性を評価することを目的とされたものです.治療群には47人、対照群には42人のデータが存在します(参考データ:https://docs.pymc.io/notebooks/BEST.html)以下のように,t検定の設定をします.

ここで, μ0は治療群の薬を投与された人, μ1はプラセボを投与された人の平均値をそれぞれ指します(μ0=101.91,μ1= 100.36).実験の結果,p_value=0.1098となりH_0(帰無仮説)は棄却されず(p < 0.05ではないため),このデータでは平均に差分があるかとかまではいえないという結論を得ることができます.しかし,もし帰無仮説を棄却することができれば,この議論はμ_0の方が良さそうなのでは,という結論に至ります. しかし,我々が本当に知りたい結論の情報は「数値的にどれだけ差分が本当にあるのか?」ということではないでしょうか?実際にどれだけの値が違うのだろうか,どれだけの範囲で平均の差分の分布が現れるのだろうか?ということが重要なのであり,「平均の差分が棄却できるかどうかは」平均値の差分の数値を具体的に見た上で初めて言えることです.しかし,仮説検定はこの情報を保管してくれず,出力はp値が5%有意水準より小さいか大きいかのみです.この問題を解決するために、ベイズを用いたアプローチのBESTという手法で平均の差分が棄却できるかどうかだけでなく,平均値の差分を出力することにより,どんだけ違うかを数値的に見てみましょう。

とりあえずBayse アプローチ

対象データは前述した異なる薬を投与してどちらがより大きな効果があるのかを調べたデータを利用します.ベイズのアプローチはP値を使わずにROPEという概念を使うことで棄却するかを判断します.このROPEは信頼区間とは異なり平均値の差分はこれだけなら許容できるという範囲を定めます。例えば異なる対象が[-0.1,0.1]の差分なら許容できるというように(平均の差分が実用的に-0.1~0.1の範囲ぐらいならとるだろうなーという区間を表す),具体的な数値を当てはめることをします.一方で,P値は信頼区間の元に決められており,これは慣習的な範囲で決められるものですがROPEの場合は直接平均の差分の数値を当てはめているため,解かなければならない問題に対して範囲を設定できます. 以下今回使うデータに関しては以下のように定めます。

ROPE:[-0.1,0.1] 信頼区間の分布:95%

ここでの信頼区間は今回用いているBESTが出力してくれる分布の事後分布の信頼区間です.詳しくは以下のサイトが参考になります.

qiita.com

f:id:tatsuya_happy:20210110221401p:plain

f:id:tatsuya_happy:20210110221417p:plain

また,ベイズを扱う手法は平均の差分分布を出力してくれるだけでなく,今回使うデータの分布,標準偏差の分布,自由度の分布,効果量の分布を出力します.difference of meanという分布を見ると,平均値の差分の分布がX軸にプロットされており,数値的にどれだけ差分があるのだろうか?が見ることができます.この例では95%信頼区間で[0.17,1.9]ぐらいの間で平均値の差分が出るだろうということがいえます.0より大きい値が98%以上分布が広がってることからも平均値には差分があることがいえるという結論が得られます.またROPEからも,全ての範囲から外にあるので実用的な範囲外となるので平均値の差はあるという結論となります(これは後述).この結果は前述したt検定との結果と異なります.t検定では棄却することができなかったものがベイズを用いたアプローチであると,棄却することができています.実際に数値的にみても少なくとも0.17ぐらいは差分があるといえます.中間の平均値をみても,1.0ぐらいは差分があるといえるので確かに,今回用いている対象の間では平均値に差分がありそうです.

以上がベイズを使った手法となります。次からは仮説検定と比較して何が嬉しいかを紹介していきたいと思います。

ベイズの嬉しさ

はじめに,の章で記載したように大きく異なる点個人的な主観では3種類存在します。仮説検定は「得られたデータから対象グループが違うかどうかを判定する,得られる分布はp値を判定するための正規化された分布,p値に従い棄却するかどうかを判定する」でしたがベイズの場合「MCMCを用いてパラメーターから事後分布を生成した分布で判断,得られる分布は平均値の差分分布,ROPEに従い平均値に差分があるかどうかを判定し,棄却または採択をする」の3種類です.大きく異なることはこの3種類なので以下それらについてどういうことか紹介していきます。

得られるサンプルデータ

MCMCでは確率モデルを用意しパラメータを推定することで事後分布からサンプルを生成できる手法です.それに従い沢山のパラメーターの組み合わせを作成することで、100,000個の組み合わせの事後分布を作成できます.ここで注意する必要があるのは論文で記載されているように( It is important to understand that these are histograms of parameter values; they are not simulated data.)であり,パラメータの分布でしかないということです.以下図を記す.

f:id:tatsuya_happy:20210110221951p:plain

得られる分布は平均値の差分分布

仮説検定から得られる分布は推定したいパラメーターではありません.あくまで,P値に沿ったような正規化された分布となります.一方,ベイスは図のように平均値の差分がどの範囲まで広がるかを出力します.そのため,我々が本当にみたいものである差分の数値を視覚的に把握することができます.実用的にこの範囲の差分ぐらいだったらなしかー,とかここまで差分が大きいのであれば効果があったーとか数値で判断することができます。これの良いところは各問題に対して個別にありかなしかを議論することができるので、P値の慣習的な値の議論を必要するところがないことです。

棄却または採択をする

仮説検定は平均値の差分があるかどうかを議論するが,平均値に差分はありませんでした( μ0 = μ1という結論),という結論に持っていくことはできません.帰無仮説を棄却するときの議論はこのデータでは棄却できるまでには至りませんでした,となります.しかし,ベイズのアプローチは棄却することも採択も可能となります.棄却というのは定めたROPEの範囲に信頼区間を完全に内包しないときや0以上の分布が95%以上広がるようなときです(もちろん、95%ではなく定めたい範囲で棄却することもできます).一方で採択というのはROPEの範囲を完全に内包するときです.ここでの棄却または採択の議論は後述する章で紹介します。

以上のようにベイズは仮説検定で行うことができないことをしてくれます.しかし,注意しなければいけないのはROPEの設定や棄却と採択の話を理解せずに使うことです.仮説検定とは違いアウトプットが複数存在するので多生なりとも知識が必要となります.

BESTの中身はどんなの??

数式的解釈はこの記事の本質ではないと考えたため,あまり詳細には説明しません.また,この手法だけが使いたいんだ!!という方はこの章をスキップしてください!!!!!(この手法の本質はベイズモデリングにあります.そのため,ベイズ統計学のお話を理解できる人のみを対象としてしまうため詳細に記載しません)統計モデリング2 がどういうものかを知りたいときはリンクの論文を参考にしてください.

BESTによりアウトプットされるデータはt分布に従って生成されます(先ほど上述で生成されていた).t分布は正規分布よりrobustな分布をするため外れ値に対応した分布となり,3種類のパラメータを必要とします.以下の定式に従い事後分布が作られます.

f:id:tatsuya_happy:20210106150736p:plain

ベイズの確率モデルは「階層性がある」モデルを容易に作成することができるため,パラメータに確率分布を与えることができます.ここで,xは今回求める平均値の事後分布となります.t分布に必要となるパラメータは,μは正規分布で表し,σは一様分布で表し,vはデータの外れ値を考慮するため指数分布が利用されております.そのためこれらのハイパーパラメータは,μはMμ, Sμとなり,σはLσとHσとなります. vは自由度のハイパーパラメータは1/29と設定されていますが,t分布はデータが30以上含まれると正規分布に近くなる性質を考慮して,1/29が設定されています.

数式的には上記の図のようなベイズモデルを構築することでパラメータを推定しています.この推定されたパラメータの組み合わせから,事後分布を生成しています.MCMCを用いることでこのパラメータの組み合わせを何十万個と組み合わせることができます.

ROPEの採択と棄却と設定とか諸々

ここではBESTの解釈を行うために必要となるROPEの概念について説明したのち,採択基準や設定について記載します.

ROPEは現実的にあり得る範囲を設定します.上述したように[-0.1,0.1]の範囲までの平均値の差分ぐらいなら許容できるな〜とかを記載することができます.もう少し具体的な例を出すと,とあるコインを考えた時,このコインは本当に裏と表が等価の確率であらわれるかを考える問題が挙げられます.実用的にこのコインが等価だと考えるならばROPEの範囲は[0.45,0.55]ぐらいの範囲に収まることが考えられます.単純に考えると,100回コインを投げた時,45回から55回は表が出るよ!!ということを表します.この時,N=10,000万回の回数を試行したとして,この確率分布が以下のように出力されたとします.

f:id:tatsuya_happy:20210106161911p:plain

すると信頼区間区間がROPE内に内包されることからもこのコインは実用的に表と裏は等価の確率であるといえます.何故なら,定めたROPEの範囲の[0.45,0.55]は信頼区間の[0.491,0.5]の範囲の外側にあるためです.

以上の事象のようにROPEの範囲を設定し,このコインは裏と表が等価というパラメータが実用的に見合っているか否かを判定することができます.この章では,このROPEがどんなパターンをとるのかについて紹介します.

ROPEの採択と棄却

ROPEの採択パターンは以下のようなものが見られます.上述したコインの例を題材に考えていきます.このコインの題材は求めたい情報である「表と裏は等価」であることが空値(空値とは求めたいパラメータ,この問題ではコインの表と裏が等価であること)となり,本当なのか本当ではないかを知りたいということになります.厳密にいうと,空値は棄却できるのか採択できるのかを判断します.

f:id:tatsuya_happy:20210106162634p:plain

aのパターンは,信頼区間の範囲が完全にROPEの範囲の外にあることから,空値は棄却されます.そのため,このコインは「表と裏が等価に出現しません」ということがいえます.具体的にはこのコインは表が100回投げた時70回出たりと不当なコインであることが予測されます.

bとcのパターンは.ROPEの範囲が完全に信頼区間の範囲の内側にあることから,空値は棄却されます.そのため,このコインは「表と裏が等価に出現する」ということがいえます.具体的にはこのコインは表が100回投げた時50回出たりと正当なコインであることが予測されます.

dとeとfのパターンはROPEの範囲が完全に信頼区間の範囲の内側または外側になく,一部内包していることから空値は棄却することも採択することもできません.具体的にはこのコインは表と裏が均一に出るかどうかわからない,ということになります.

以上のように,ROPEを設定することで,空値は「棄却,採択,どっちでもない」という3種類の決定を行うことができるようになります.

ROPEについてのまとめと決定

ROPEについて色々紹介してきましたが,少しだけ,上述でも利用してきたROPEについてどのように定めたら良いかについて紹介します.とはいっても,ROPEを決めることは何かしらの定められた決定規則があるわけでもありません.信頼区間95%のように慣習的に定められたもので決定するのではなく,とある問題に対して自分が定めたい範囲で設定するようにするのが我々の目的であるためです.少しだけ,基準点を話すと米国食品医薬品局(FDA)では2つのグループの平均の比について0.8および1.25のROPE限界を推奨しています(米国FDA、Center for Veterinary Medicine, 2016, p. 16).現代の業界基準では、中等度のリスクのある用途では±20%前後のROPE限界値を用いているが,リスクが高い場合にはROPEが狭く(すなわち±5%~±10%),リスクが低い場合にはROPEが広く(すなわち±26%~±50%)なることがある(Little, 2015, 表1)3

終わりに

この記事では,t検定を使わずにベイズアプローチの一つであるBESTを用いて対象グループに平均に差分があるかを確認するための手法について紹介しました.この手法にはROPEと呼ばれる概念やベイズの諸知識が必要であるため,急いで,BESTを使うんだ!!という必要性はないと思います.しかし,得られているデータ数が少ない場合や平均値の差分の分布が見てみたいときなどに利用すれば,t検定では得られない情報量を得ることができるのも事実です.そのため,こういう手法もあるんだなーという観点で調べたり納得していただけるといいのだと勝手ながら思っております.


  1. John K. Kruschke, Journal of Experimental Psychology: General, 2013, v.142(2), pp.573-603. (doi: 10.1037/a0029146)

  2. 清水 裕士 心理学におけるベイズ統計モデリング Japanese Psychological Review 2018, Vol. 61, No. 1, 22–41

  3. John K. Kruschke Rejecting or Accepting Parameter Values in Bayesian Estimation Advances in Methods and Practices in Psychological Science 2018, Vol. 1(2) 270–280