- 投稿日:2019-02-09T13:21:01+09:00
バレンタインデーにもらったチョコが本命かどうか判定するAIを実際に作って公開した
TL;DR
バレンタインデーが近いですね!
バレンタインでもらったチョコが、本命かどうかは、世の男性にとって、重大な問題です。
女性心理の機微に疎い男子中高生、理系男子学生、男性エンジニア(偏見)
を救うべく、実際にもらったチョコが本命かどうか判定するAIを開発しました。1. 男性エンジニアを悩ませるバレンタイン問題
1.1 バレンタインデー
世界中にあるイベントの一つに、2/14のバレンタインデー(Valentine’s Day)があります。
国や地域によって、その日の過ごし方などは異なるようですが、ここ日本では、女性から男性へチョコレートを贈る日、という お菓子会社の戦略によって定着した文化 があります(例えば[1]参照。諸説あり)。[1]によれば、1970年代後半頃に本命チョコを贈る習慣が定着したようです。ここから、さらにお菓子業界の商機ととらえた全国飴菓子工業協同組合は、義理チョコとホワイトデーという文化を創り出し、1984年をホワイトデー定着の年としました。
1.2 バレンタインデーの悲劇
しかし、このような文化は悲劇を起こしました。それは、女性から贈られたチョコが、本命なのか義理なのかがはっきりしないケースが登場したためです。はっきり口にせず、以心伝心や忖度を是 とする日本の文化が、多くの迷える男性を生み出して しまうことになりました。
このような背景から、贈られたチョコレートが、本命なのか義理なのかをはっきりさせる社会的ニーズが産まれました。図1に、この状況証拠を示します。世の中のどれだけの人が検索をすれば、Googleの検索サジェスチョンにこのような結果をもたらすのでしょうか。これは、もはや国民的課題といえるでしょう。
以降、これを バレンタイン問題 と呼ぶことにします。
図1:バレンタイン問題 – バレンタインのチョコレートが本命か義理かを判断する社会的ニーズ1.3 バレンタインデーの救世主
一方、最近の機械学習手法の発達は目覚ましい物があります。AIすなわち、機械学習がこの バレンタイン問題 を解決する手段になりえることが示されました[2]。これは画期的な観点であると思われましたが、開発したエンジニアのみが実行、評価できるものでした。これでは、迷える男子中高生、理系男子大学生、そして男性エンジニアを救う ことはできません(筆者の独断と偏見による)。
また、男性の立場からすると、ホワイトデーにお返しを行う義務が、暗黙のうちに発生します。ここで不適切な対応をとると、その後の長期間にわたり、生きづらい人生を歩むことになりかねません。
そのため、贈られたチョコレートに対して、どのくらいのお返しを行えばよいのか、その指針を示すことができれば、悩める男性に対して有効なサービスとなり得ると思われます。図2に、悩める男性像の一例を示します。1.4 バレンタイン問題の解決方法
以上のことから、本記事では[2]をさらに発展させ、バレンタイン問題の一助となることを目指すものです。
- 本命チョコと義理チョコを判別する学習モデルを開発する
- 二値分類と呼ばれる、機械学習における代表的な手法を用いたアプローチをとる
- これを本命・義理チョコ分類問題と呼ぶ
- 開発した、構築した学習モデルをサービス化して公開する
- PC、スマホのどちらからでも使えるように、Webサービス化を行う
- 義理チョコと本命チョコを分類する際の確率を算出する
- 定量的に判断指標を示すことで、悩める男性自身の判断を促す
- 確率を用いることで、ホワイトデーのお返し予算の提案も併せて行う
実際のイメージを、以下に示します。
なお、筆者が人生でチョコレートを貰った回数(個数)は、年齢のおよそ25%以下である。
チョコ欲しい。2. DNNでの学習
以降、以下URLに、随時加筆修正していきます。
https://boomin.yokohama/archives/13572.1 学習データ
2.2 学習モデル
2.3 学習の実行
2.4 学習モデルの評価
3. お返し予算の算出
- 投稿日:2019-02-09T12:45:41+09:00
JSXの基本
はじめに
JSXとは、JavaScriptの拡張構文です。
実行時、内部的にはJavaScriptにトランスパイルされます。具体的には、React.createElementメソッドに変換される
複数の要素を列挙することができない
複数の要素を列挙することができないため、以下のコードは不可です。
sample.jsReact.DOM.render( <h1>Hello, World</h1> <p>こんにちは、世界</p>, document.getElementById('root') );複数の要素全体を
<div>
などの要素で括るsample.jsReact.DOM.render( <div> <h1>Hello, World</h1> <p>こんにちは、世界</p>, </div> document.getElementById('root') );または、
<React.Fragment>
で、複数の子要素をまとめるsample.jsReact.DOM.render( <React.Fragment> <h1>Hello, World</h1> <p>こんにちは、世界</p>, </React.Fragment> document.getElementById('root') );空要素は<~ />で終える
JSXでは、XMLと同じように、空要素は
<~ />
で終えなければなりません。sample.js//ダメなコード const tag = <img src={logo}>; //正しいコード const tag = <img src={logo} />;JavaScriptの予約語は使えない
JSXはあくまでもJavaScriptの拡張構文なので、JavaScriptの予約語である
class
,for
などの属性は使えない。JavaScriptを使う場合は{}で埋め込む
JSX内でJavaScriptを使う場合は、
{}
で埋め込むことができる。sample.jsconst name = 'Tom'; ReactDOM.render( <p>Hello {name}.</p>, docunent.getElementById('root') ); #=> Hello Tom.
- 投稿日:2019-02-09T02:02:24+09:00
React.js の Context API で Private Route を作る
Reactでログイン機能があるSPAを開発する際に、特定のページ(ルート)を秘匿したい場合があると思います。
今回はReact v16から実装されたContext APIを使ってプライベートなルートを作成します。Context APIとは
Context APIはProviderとConsumerという機構を使い、異なるコンポーネント間でデータの共有を可能にするものです。大まかな概要は以下の通りです。
- createContextはProviderとConsumerというコンポーネントのペアを返す
- Providerはデータとコールバックを保有するコンポーネント
- ConsumerはProviderのデータを購読しコンポーネントにデータを渡す
環境
ライブラリのバージョン
Library version react 16.2.0 react-router-dom 4.3.1 ディレクトリ構成
Reactではディレクトリ構成やコンポーネントの分割に規制がなく、アプリケーションの要件に応じて設計することができます。
以下は今回、解説に使うアプリケーションのディレクトリ構成です。あくまで例ですので、実際の開発では適宜設計してください。index.js /contexts auth.js /routes home.js mypage.js1. Contextを作成する
/contexts
ディレクトリにauth.js
ファイルを作成しAuthContextを作成します。// contexts/auth.js import React, { Component } from 'react'; // Contextの生成 const AuthContext = React.createContext(); // ContextにはProviderとConsumerというコンポーネントが含まれる const AuthProvider = AuthContext.Provider; const AuthConsumer = AuthContext.Consumer; export { AuthProvider, AuthConsumer };AuthContextにログイン状態を表す
isAuth
というデータを管理させるため、Providerをカスタマイズします。// contexts/auth.js ... class AuthProvider extends Component { constructor(props) { super(props); this.state = { isAuth: false } } // Providerのvalueを設定する。Consumerはこのvalueを購読する。 render() { return ( <AuthContext.Provider value={{ isAuth: this.state.isAuth }} > {this.props.children} </AuthContext.Provider> ); } } ...2. Contextからデータを取り出す
AuthContextから
isAuth
を取り出しコンポーネントに反映させてみます。
Headerというコンポーネントを作成し、ログイン状態に応じてテキストを表示させます。ProviderでHeaderコンポーネントをラップし、コンポーネント側ではConsumerを使ってデータを取り出します。
// index.js import React from 'react'; import ReactDOM from 'react-dom'; import { AuthProvider, AuthConsumer } from './contexts/auth'; // ProviderでHeaderコンポーネントをラップ const App = () => ( <AuthProvider> <Header /> </AuthProvider> ); // Headerコンポーネント中でConsumerからデータを取り出す const Header = () => ( <AuthConsumer> {({ isAuth }) => ( <> <h1>Header</h1> {isAuth ? ( <p>ログインしているよ!</p> ) : ( <p>ログインしていないよ!</p> )} </> )} </AuthConsumer> ); ReactDOM.render(<App />, document.getElementById('root'));3. Providerに状態を変更するコールバックを作成
ログイン、ログアウトボタンを作成するために、AuthProviderにログイン状態を切り替えるためのコールバック関数を作成します。
今回はfetch等のAPI通信は割愛します。// contexts/auth.js ... class AuthProvider extends Component { constructor(props) { ... // thisをバインド this.login = this.login.bind(this); this.logout = this.logout.bind(this); } login() { // 実際にはここでAPI等を使ってログイン処理を行う setTimeout(() => this.setState({ isAuth: true }), 1000); } logout() { this.setState({ isAuth: false }); } render() { return ( <AuthContext.Provider value={{ isAuth: this.state.isAuth, login: this.login, logout: this.logout }} > {this.props.children} </AuthContext.Provider> ); } } ...続いてHeaderコンポーネントにログイン/ログアウトボタンを実装します。
// index.js ... const Header = () => ( <AuthConsumer> {({ isAuth, login, logout }) => ( <> <h1>Header</h1> {isAuth ? ( <p>ログインしているよ!</p> <button onClick={logout}>ログアウト</button> ) : ( <p>ログインしていないよ!</p> <button onClick={login}>ログイン</button> )} </> )} </AuthConsumer> ); ...4. プライベートなルートを作成
次はreact-routerを使ってプライベートなルートを作成していきます。
Headerコンポーネントに続いて、react-routerを使ってルーティングを設定します。// index.js ... import { BrowserRouter, Route, Redirect, Switch } from 'react-router-dom'; import Home from './routes/home'; import MyPage from './routes/mypage'; // Headerコンポーネントを取り除き、ルーティングを設定 const App = () => ( <BrowserRouter> <AuthProvider> <Header /> <Switch> <Route exact path="/" component={Home} /> <Route path="/mypage" component={MyPage} /> </Switch> </AuthProvider> </BrowserRouter> ); ...続いて、プライベートなルートを作成するための、PrivateRouteコンポーネントを作成します。
// index.js ... // プライベートなルートを設定するためのコンポーネント const PrivateRoute = ({ component: Component, ...rest }) => ( <AuthConsumer> {({ isAuth }) => ( <Route render={props => isAuth ? ( <Component {...props} /> ) : ( <Redirect to="/" /> ) } {...rest} /> )} </AuthConsumer> ); // 秘匿したいルートをPrivateRouteで置き換える const App = () => ( <BrowserRouter> <AuthProvider> <Header /> <Switch> <Route exact path="/" component={Home} /> <PrivateRoute path="/mypage" component={MyPage} /> </Switch> </AuthProvider> </BrowserRouter> ); ...未ログイン状態でmypageにアクセスすると、トップページにリダイレクトされることが確認できると思います。
大規模なアプリケーションなど厳格な状態管理が必要とされるケースでは、Redux等の状態管理フレームワークが引き続き有用に思いますが、中小規模のアプリケーションにおいてはContextを用いるのも良い選択肢ではないでしょうか。
参照サイト