ARAN1218 / Statistics_learning

統計学の勉強も兼ねて、様々な統計量の計算や分析手法をPythonで実装していきます。
MIT License
1 stars 0 forks source link

フィッシャーの正確確率検定にて、p値が負の値を取ってしまう場合がある。 #2

Closed ARAN1218 closed 2 years ago

ARAN1218 commented 2 years ago

cross_tabulationfisher_exact_test.pyにて、以下の様にp値が負の値を取ってしまう場合があることを確認した。このエラーは検定を実行する上で機能不全を起こすエラーであり、どうにか対処しなくてはならない。

この例以外にも、より数値の大きいデータで実行したり、単純にマス数を増やした場合にも同様のエラーが見られたので、恐らく数値のオーバーフローだと思われる。詳細な検証は後に進めていく。

スクリーンショット 2022-03-17 22 57 25
ARAN1218 commented 2 years ago

原因と対策

pythonはC言語やJava等と違い、int型のデータに上限がない。その為、通常ならば非常に大きな数字の階乗等の計算もオーバーフローを心配せずに実行できる。しかし、今回はオーバーフローと思わしきエラーが発生してしまっている。今回はnumpyというライブラリを用いてリスト内の要素の総積を求めるメソッドであるnp.prodを使用している。その出力が以下である。

スクリーンショット 2022-03-18 23 12 27

これはnumpyがC言語で書かれたライブラリであり、C言語の制約を受けてしまうために起こる現象である。つまり、C言語と同様に約21億程度でオーバーフローを起こしてしまい、負の値を取ってしまうことがある。

これを防ぐためには、numpyを使わずに同様の処理を達成する事が求められる。現在numpyを使っている処理は

  1. 階乗(np.factorial)
  2. リストの総積(np.prod)

の2つである。

1つ目は簡単で、標準ライブラリであるmathライブラリのmath.factorialメソッドを用いれば良い。 問題は2つ目である。一応mathライブラリにmath.prodメソッドがあるのだが、これはPythonのバージョンが3.8以降でないと使えない。つまり、jupyter notebookのカーネルを更新する必要があると考えられ、非常に面倒である。

fisher_exact_test関数内にリスト内総積算出関数を作ってしまうのも手だが、こちらは関数のスペースを取ってしまい、美しくない。その為、最後の手段として考える。

ARAN1218 commented 2 years ago

解決法

調査の結果、functoolsライブラリとoperatorライブラリを用いることでスマートに処理できることが分かった。 pythonにてfunctoolsのreduceモジュールとoperatorのmulモジュールを用いてreduce(mul, target_list)と記述することで、リスト内要素の総積がpythonの処理として求められる。つまり、上記のバグが起きていた計算が以下のように修正される。

スクリーンショット 2022-03-29 23 28 45

これでコードの複雑性をあまり上げずにオーバーフローを起こす心配を解消できた。