概要
- スマートフォン片手にカイ二乗検定できるアプリをreactで書きました
- create-react-app自体にPWAの準備が整っていますので何もしなくてもPWAとしてうごきます
- Androidならホーム画面から起動できるアプリとして動作させられます
動作画像
- 解析結果をテキストデータとしてコピー
赤矢印の箇所を押すと解析結果をテキスト形式でコピーできます。
* 入力データ
treat non-treat
case 5 2
control 12 8
* 検定結果
χ2 0.290
p値 0.590 (有意差なし)
* 解析日時
Wed Feb 28 2018 18:52:18 GMT+0900 (JST)
* Powered by
https://case-control-test.firebaseapp.com
すぐ使いたい人
サイトで使いたい
Firebaseのhostingで公開しています。
PWAとしてホーム画面に追加したい
現在は、iOSでは不可。Androidのみです。
でも、このような情報があるのでiOSでPWAでアプリっぽく使える日も近いです。
とりあえず、現状可能なAndroid(chrome)での追加方法の説明をします。
- Andoridのchromeブラウザでサイトを開き、右上からブラウザのメニューを呼び出し、ホーム画面に追加を押す
- ホーム画面に追加されます。ホーム画面上のアイコンをクリックすればアプリの様にスプラッシュ画面が出て起動できます!
localで動かしたい
- https://github.com/junara/two-by-two-table-stat からコードをクローン後、クローンしたフォルダ内へ移動して下記コマンドを打てば localhost:3000で起動します。
> yarn install
> npm run build
環境
- 前回のQiitaの記事の続きなので、それに準じてください
手順
コード概要
-
componentsとcontainersフォルダ
reactのcomponentをこちらに保存する -
modulesフォルダ
- 関数とか(今回であればカイ二乗検定を計算する所とか)
- Graph: グラフを描画するためのデータを用意する
- Stat: カイ二乗検定の計算する
- サービス
- LocationHref: mailtoなどのリンクを出力
- 定数
- MyProfile: 自己紹介の用のURL
- Site: サイトのURL
- 関数とか(今回であればカイ二乗検定を計算する所とか)
コンポーネントの紹介
-
<TwoByTwoTable/>
: stateはここだけで管理。あとはバケツリレー。-
<StatHeader/>
: ロゴ -
<StatBody/>
: 結果の表示(統計量、表、グラフ)-
<CopyToClipboardButton/>
: 結果をコピーするためのコンポーネント -
<SendMailButton/>
: 結果をメールで送信するためのコンポーネント
-
-
<StatForm/>
: データを入力するコンポーネント。stateの変更はthis.props.handleChangeでおこなう。 -
<StatFooter/>
-
<AboutMe/>
: 自己紹介 -
<AboutThis/>
: アプリ紹介
-
-
TwoByTwoTable
いつもは、reduxを使うのだけど、今回のアプリには過剰なので素直にバケツリレーで作りました。久しぶりにバケツリレーで書いた。階層が2階層で、非同期のタスクを書く必要がなければ、バケツリレーのほうが書いていて楽しいですね。
handleChange = name => event => {
const value = event.target.value ? parseInt(event.target.value, 10) : ''
this.setState({[name]: value})
}
formで使うメソッド。子コンポーネントでonChange={this.props.handleChange('caseTreatment')}
として使うと、state.caseTreatmentを変更することができます。すごい便利。
StatHeader
そんなに説明するところないな。
StatBody
const chiSq = Stat.chiSq({a: caseTreatment, b: caseNonTreatment, c: controlTreatment, d: controlNonTreatment})
const chiP = Stat.chiP(chiSq)
今回χ2検定を行うための関数を呼び出しています。
- χ2値を計算する(Stat.chiSq)
- chiSq値を累積分布関数にわたしてあげる(Stat.chiSq)とp値を出力してくれる
StatForm
<TextField
id={'number'}
autoFocus
type={'number'}
margin={'normal'}
onChange={this.props.handleChange('caseTreatment')}
value={this.props['caseTreatment']}
/>
onChangeのhandleChangeでstateを変化させ、propsとして受け取った値をvalueに入れる。
PWA用のカスタマイズ
create-react-appで作ると、最初からPWAの準備はできています。
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
なので、デフォルトで作られているサイト名やアイコン(logo.svgとfavicon.icoとlogo.png)を若干カスタマイズすればOKです。
"short_name": "2x2 STAT",
"name": "Case control data analysis by chi squared test",
統計解析
Stat.js
χ2値の計算。適当に教科書から取ってきました。ごく一般的な数式。このサイトとおなじです。
export const chiSq = ({a, b, c, d}) => {
if (!isValid({a, b, c, d})) return 'error'
const n = a + b + c + d
const calc = ((a * d - b * c) ** 2) * (n / ((a + b) * (c + d) * (a + c) * (b + d)))
return (calc.toFixed(3))
}
p値の計算。自由度1のχ2の累積分布関数から計算する。累積分布関数はchi-squaredをつかいました。
export const chiP = (chiSq) => {
if (!(chiSq > 0)) return 'error'
const df = 1 // dfは自由度
const calc = 1 - chi.cdf(chiSq, df) // cdfは累積分布関数
return calc.toFixed(3)
}
その他ライブラリの紹介
fontawesome
- twitterとgithubとfacebookのアイコン画像が欲しいので導入。fontawesomeってここ半年でバージョンが5になったのですね。svgになったので、表現力が向上したっぽい。
import FontAwesomeIcon from '@fortawesome/react-fontawesome'
import { faGithub } from '@fortawesome/fontawesome-free-brands/index'
省略
<FontAwesomeIcon icon={faGithub} size="lg" fixedWidth/>
react-chartjs-2
グラフを作成するためのライブラリ。chart.jsをreact用のコンポーネントとして使えるされたラッパー。
dataをobjectで渡せば描画できます。
import { Doughnut } from 'react-chartjs-2'
省略
<Doughnut data={Graph.data(controlTreatment, controlNonTreatment)} options={Graph.options}/>
export const data = (t = 10, nt = 10) => {
return {
labels: [
'Non Treat',
'Treat',
],
datasets: [{
data: [nt, t],
backgroundColor: [
color.nonTreat,
color.treat,
],
hoverBackgroundColor: [
color.nonTreat,
color.treat,
],
}],
}
}
list-it
- 表をテキストで出力する時に、ずれないようにうまい具合に空白を入れてくれる。すごい便利。
export const tableString = ({a, b, c, d}) => {
if (!isValid({a, b, c, d})) return 'no result'
const arr = [
['', 'treat', 'non-treat'],
['case', a, b],
['control', c, d],
]
let buf = listIt.buffer({'autoAlign': true})
buf.d(arr)
return (buf.toString())
}
react-scroll-to-component
任意の場所に移動するためのメソッド。
移動したい所にrefを定義して**scrollToComponent(ref, option)**を実行すると、refの場所にスクロールします。
componentDidMount () {
this.scrollToForm()
}
scrollToForm = () => {
scrollToComponent(this['form'], {
align: 'bottom',
duration: 1000,
})
}
省略
<StatForm {...this.state}
handleChange={this.handleChange}
ref={(section) => {this['form'] = section}}
/>
react-share
有名どころのシェアボタンを作成出来るreact component。ボタンと画像を別々にimpportして、画像(TwitterIcon)をボタン(TwitterShareButton)囲むところがミソ。
import {
TwitterShareButton,
TwitterIcon,
} from 'react-share'
省略
<TwitterShareButton
title={Site.title}
url={Site.rootUrl}
hashtags={[Site.title]}
style={styles.buttonMarginRight}
>
<TwitterIcon
size={32}
round/>
</TwitterShareButton>
発展
- 統計量を増やすかも(オッズ比とか陽性的中率とか検出力とか)
- 分散データの解析(t検定は作るつもり)。ただし、ノンパラはライブラリがあれば実装します。自分で計算書くのはつらいので。
備考
もっと色々やりたい場合は、PCの目の前に腰を据えて、RとかSASとSPSSとかSとか使ってください。
以上。
Happy Statistics.