Bootstrap4のナビバーを用いたサイトの多言語化

 Webサイトを開発する際に、多言語対応することが必要となることがある。 今回は、Bootstrap4のナビバーによって各言語に対応したサイトに飛ぶようにする。

言語選択用のDropdownをつける


f:id:farma_11:20180213000251p:plain
言語選択用Dropdownつきナビバー

各言語用のindex.htmlを用意

 以下のようなディレクトリ構造を構築することで、多言語対応を試みる。

言語 ディレクトリ構造
日本語 example.com/jp/index.html
英語 example.com/en/index.html

言語選択用のナビバーを作る

 以下のBootstrap4移行ガイドに基づいて、navbarを用いる。

cccabinet.jpn.org

 また、言語選択用のナビバーだけ右寄せにすることとする。 右寄せにするには、右寄せにはナビバーにおけるメニューに .mr-auto か、言語選択用のDropdownに .ml-auto を追加

<div class="collapse navbar-collapse" id="navbarsExampleDefault">
  <!-- ナビバーにおけるメニュー -->
  <ul class="navbar-nav mr-auto">
    <li class="nav-item active">
      <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
    </li>
    <!-- 必要なぶんだけ繰り返す -->
  </ul>

  <!-- 言語対応用のDropdown -->
  <ul class="nav navbar-nav">
    <li class="nav-item dropdown">
      <a class="nav-link dropdown-toggle" href="http://example.com" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
        Language
      </a>

      <!-- Dropdownのメニュー -->
      <div class="dropdown-menu" aria-labelledby="dropdown01">
        <a class="dropdown-item" href="../jp/index.html">
          <img src="../img/flags/jp.gif"> 日本語
        </a>
        <a class="dropdown-item active" href="../en/index.html">
          <img src="../img/flags/gb.gif"> English
        </a>
      </div>
    </li>
  </ul>
</div>

 また、<a class="dropdown-item active" href=...>のように、現在選択している言語をactiveにすることで、 現時点選択している言語が何かをわかりやすくしている。

画面にはみ出したDropdownを修正する

 このままでは以下のように、ドロップダウンが画面からはみ出てしまう。 f:id:farma_11:20180213001441p:plain

 以下のようにメニューの出現位置を右端に固定することで、画面内に全て表示させることができる。 具体的には、<div class="dropdown-menu dropdown-menu-right"...>とすることで右側に固定することができる。

<!-- Dropdownのメニュー -->
<ul class="nav navbar-nav">
  <li class="nav-item dropdown">
    <a class="nav-link dropdown-toggle" href="http://example.com" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Language</a>
    <div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdown01">
      <a class="dropdown-item" href="../jp/index.html">
        <img src="../img/flags/jp.gif"> 日本語
      </a>
      <a class="dropdown-item active" href="../en/index.html">
        <img src="../img/flags/gb.gif"> English
      </a>
    </div>
  </li>
</ul>

 以上のようにすると、次のような表示となる。

f:id:farma_11:20180213001741p:plain

言語選択用のナビバーの全容

参考サイト一覧


ロジステック回帰 まとめ

scikit-learnを用いたirisの分類


1. scikit-learn の準備

from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

※クロスバリデーションの使い方の変更
scikit-learn 0.20からクロスバリデーション関係のモジュール(sklearn.cross_vlidation)は廃止されている。
scikit-learn 0.18でも既にDeprecationWarningが表示される。

- from sklearn.model_cross_varidation import train_test_split
+ from sklearn.model_selection import train_test_split

詳しくは以下を参照

segafreder.hatenablog.com

2. scikit-learnからirisデータを取得

  • iris.data: 説明変数(特徴量)の行列
  • iris.target: 目的変数
iris = datasets.load_iris()

x = iris.data[:100]   # 説明変数(1 - 100)
y = iris.target[:100] # 目的変数(1 - 100)

3. 教師データとテストデータの分割

  • 第1引数に入力データ, 第2引数に正解ラベルの配列を渡す。
  • test_size: テストデータのサイズ(割合)。0.0~1.0の実数で指定。
  • random_state: データを分割する際の乱数のシード値
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.20, random_state=25)

 順番がシャッフルされデータが分割されている。シャッフルを防ぐためには、shuffle=Falseとすると良い。 詳しくは以下の記事を参照。

www.madopro.net

4. ロジスティック回帰を用いた学習

# 学習する
model = LogisticRegression()
model.fit(X_train, y_train)
results = model.predict(X_test)

# 予測結果
print("予測結果 : " + str(results))
print("正解データ: " + str(y_test))
予測結果 : [0 0 0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0]
正解データ: [0 0 0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 1 0]

4. 分類結果の精度を評価

# 精度評価の計算
tp = 0
tn = 0
fn = 0
fp = 0

for result, answer in zip(results, y_test):
    if result == 1:
        if answer == 1:
            tp += 1
        else:
            fp += 1
    else:
        if answer == 1:
            fn += 1
        else:
            tn += 1
            
accuracy  = float(tp + tn)/(tp + tn + fn + fp)
precision = float(tp)/(tp + fp)
recall    = float(tp)/(tp + fn)
f_measure = 2*precision*recall/(precision + recall)

print("accuracy is {}".format(accuracy))
print("precision is {}".format(precision))
print("recall is {}".format(recall))
print("f_measure is {}".format(f_measure))
accuracy is 1.0
precision is 1.0
recall is 1.0
f_measure is 1.0

ロジステック回帰について


(標準)シグモイド関数を用いた線形分類

 (標準)シグモイド関数(Sigmoid function)はロジステック回帰に用いられたり、NN(Neural Network)における活性化関数といてよく用いられる。

 \sigma(x) = \frac{1}{1 + \exp(-x)} = \frac{1}{2} \bigl( \tanh\bigl(\frac{x}{2} \bigr) + 1 \bigr)

 シグモイド関数は以下のような性質を持つ。

  1.  \lim_{x \to -\infty} \sigma(x) = 0, \lim_{x \to \infty} \sigma(x) = 1となり、値を確率としてみることも多い。
  2.  \sigma(0) = 0.5であり、点 (0, 0.5) に対して点対称となる。
  3. 微分可能である。( \sigma'(x) = (1 - \sigma(x)) \sigma(x)

 シグモイド関数を用いた2値分類をする際は、基本的には以下のようになる。

 y = 
  \begin{cases}
   1, (\sigma(x) \geq 0.5 \Leftrightarrow x \geq 0) \\
   0, (\sigma(x) < 0.5 \Leftrightarrow x < 0) 
  \end{cases}

f:id:farma_11:20171228005931p:plain
シグモイド関数を用いた2値分類

 以下は、シグモイド関数の描画のためのPythonソースコードである。

機械学習の評価

正解データ: 1 正解データ: 0
予測結果: 1 真陽性
TP: True Positive
偽陽性
FP: False Positive
予測結果: 0 真陰性
TN: True Negative
偽陰性
FN: False Negative

以下のような指標を用いて,予測結果を評価することができる。

  • 正解率 (Accuracy):
    予測結果全体と、答えがどれぐらい一致しているかを判断
    $$Accuracy = \frac{TP + TN}{TP + FP + TN + FN}$$
  • 適合率 (Precision):
    偽陽性を低く抑えることを目的とする場合には適合率が高いモデルを採用
    $$Precision = \frac{TP}{TP + FP}$$
  • 再現率 (Recall): 偽陰性を低く抑えたい場合に採用
    $$Accuracy = \frac{TP}{TP + FN}$$
  • F値 (F-measure, F-score): 適合率と再現率の調和平均
    $$F_measure = \frac{2 \times Precision \times Recall}{Precision + Recall}$$

ABC #085 C - Otoshidama

問題の概要


問題: AtCoder Beginner Contest #085 C - Otoshidama

 お年玉を N (1 \leq N \leq 2000) のお札で合計 Y (1000 \leq Y \leq 2 \times 10^{7}) いただいた。 このとき、10000円札・5000円札・1000円札の枚数を求める。

 但し、複数の可能性がある場合はそのうちの1組を出力する。 また、お札の組み合わせが存在しない場合は-1 -1 -1と出力。

解答例


10000円札 5000円札 1000円札
枚数  X_{10}  X_{5}  X_{1}

10000円札・5000円札の全探索:  O(N^{2})

f:id:farma_11:20180124160631p:plain

 式(1)より、1000円札の枚数 X_{1}を計算によって求めることができる。 したがって、3種類のお札を全探索した場合の計算量 O(N^{3})から O(N^{2})へ削減できる。

 また、AtCoder上の環境では、平均実行時間7 msとなった。

10000円札の全探索:  O(N)

f:id:farma_11:20180124160843p:plain

 式(1)及び(2)より、10000万円札の枚数 X_{10}を固定すると、二元一次連立方程式となる。 したがって、3種類のお札を全探索した場合の計算量 O(N^{3})から O(N)へ削減できる。

  また、AtCoder上の環境では、平均実行時間1 msとなった。

C++における文字列操作

目次


 C++を使っていて、文字列の処理についてのTipsです。 追記及び修正等を気付き次第行なっていきます。

文字列の操作


文字(列)の挿入・削除

文字列の挿入: std::vector::insert

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string str = "Farma_11";

    str.insert(2,  "***");
    cout << str << endl; // Fa***rma_11
}

参考: vector::insert - cpprefjp C++日本語リファレンス

文字列の末尾に挿入: std::basic_string::append

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string str = "Farma_11";

    str.append(3, '!');
    cout << str << endl; // Farma_11!!!
}

参考: basic_string::append - cpprefjp C++日本語リファレンス

文字列内の一部の削除: std::basic_string::erase

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Farma_11";

    str.erase(str.end()-1); //end()は最後の次を指す
    cout << "末尾削除:  " << str << endl; // 末尾削除:  Farma_1

    str.erase(str.begin()+3); //begin()は先頭を指す
    cout << "4文字目削除:  " << str << endl; // 4文字目削除:  Fara_1
}

参考: basic_string::erase - cpprefjp C++日本語リファレンス

文字(列)の検索・置換

特定の文字(列)の検索: std::findなど

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string str = "Farma_11";

    cout << "最初の ma: " << str.find("ma")+1 << "文字目から" << endl;
    // 最初の ma: 4文字目から
    cout << "最後の  a: " << str.find_last_of('a')+1 << "文字目" << endl;
    // 最後の  a: 5文字目
    cout << "存在しない: " << str.find("e")+1 << endl; //string::npos
    // 存在しない: 0
}

アスキーコードの変更

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Farma_11";

    char plus = 5; // C++ではアスキーコードがchar型
    str[1] += plus;
    cout << str << endl; // Ffrma_11
}

文字(列)のカウント

文字のカウント

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Farma_11";

    int cnt = 0;
    for(unsigned int i = 0; i < str.size(); i++){
        if(str[i] == 'a') cnt++;
    }
    cout << "カウント: a " << cnt << "個" << endl; // カウント: a 2個
}

文字列のカウント

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Farma_11";

    int cnt = 0;
    string s = "ma";
    for(unsigned int i = 0; i < str.size() - s.size() + 1; i++){
        if(str.substr(i, s.size()) == s) cnt++; //添え字iからs.size()分
    }
    cout << "カウント: " << s << " " << cnt << "個" << endl; // カウント: ma 1個
}

文字列内の文字の並びを変更する

文字列内の文字の交換: std::swap

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Farma_11";

    swap(str[0], str[str.size()-1]); // size()は文字数
    cout << "先頭と末尾の交換: " << str << endl; // 先頭と末尾の交換: 1arma_1F
}

参考: swap (非メンバ関数) - cpprefjp C++日本語リファレンス

文字列の反転: std::reverse

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string str = "Farma_11";

    reverse(str.begin(), str.end()); // イテレータを用いて範囲指定
    cout << str << endl; // 出力: 11_amraF
}

参考: reverse - cpprefjp C++日本語リファレンス

文字列内の文字のソート: std::sort

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string str = "Farma_11";

    sort(str.begin(), str.end());
    cout << "昇順: " << str << endl; // 昇順: 11F_aamr
    sort(str.begin(), str.end(), greater<char>());
    cout << "降順: " << str << endl; // 降順: rmaa_F11
}

参考: sort - cpprefjp C++日本語リファレンス

文字列と数値の変換

文字列から整数へ変換

#include <iostream>
#include <string>
using namespace std;

int main() {
    string num = "12345";
    int n = atoi((const char*)num.c_str());
    
    num += "-5"; n += -5; //共に-5を足す
    cout << "整数へ変換: " << num << " = " << n << endl;
}

文字列から1桁ずつ整数へ変換

 一桁の数値への変換では、'[0-9]の文字' - '0'にて数値へ変換可能。

#include <iostream>
#include <string>
#include <cstring>
using namespace std;

int main() {
    string num = "12345";
    
    char number[10];
    int sum = 0;
    strcpy(number, num.c_str());
    for(unsigned int i = 0; i < num.size(); i++){
        sum += number[i] - '0';
    }
    cout << "1〜5の和: " << sum << endl;
}

HRI2017: "Marionette: Enabling On-Road Wizard-of-Oz Autonomous Driving Studies"

本記事・論文について


 本記事では以下の論文の概略を示しつつ、論文読解のための知識をまとめる。

論文: Wang, Peter, et al. "Marionette: Enabling On-Road Wizard-of-Oz Autonomous Driving Studies." Proceedings of the 2017 ACM/IEEE International Conference on Human-Robot Interaction. ACM, 2017.
HRI2017: Regular Session #5 - HRI2017

HRI(International Conference on Human-Robot Interaction): 人間とロボットの相互作用に関する研究成果を発表する国際会議

論文の内容


論文の概要

 本研究において、オンロード模擬自律走行研究のための相互作用研究システムMarionetteを開発した。 Marionetteは以下のような利点がある。

  • 低コスト、ポータブル、かつ多目的であるという特徴がある。
  • 部分的自律運転の錯覚を促進し、オンロード研究のための車両運転の安全性を維持する。
  • 運転手と部分的自律車両間のオンロードでの相互作用をシミュレートする研究のためのプラットフォームとして役立つ。

f:id:farma_11:20180106203252p:plain
Marionette インターフェース(当該論文から引用)

自律運転シミュレーション

 既存研究では、完全自動運転のシミュレーションが可能であるとされる。 しかし、自動運転におけるレベル2・3のシミュレーションには、ドライバーと車両間の相互作用部分が必要となる。

 単に多くの自動化をすることで解決するわけではなく、自動化分野の主な課題の多くは人間と機械の相互作用の部分にある。 特に自律運転技術に関して、運転者と部分的自動化機能の相互作用が十分に理解されていないという問題がある。

 実験室における運転シミュレータの研究と、路上実験の双方が重要である。

研究デザイン

研究デザインの概要

 路上実験で、自動運転レベル2・3の将来の自律運転シナリオにおける運転者の行動を理解する必要がある。 そのため、実験参加者に自動運転に対する経験を与えるためのWizard-of-Ozプロトコルを設計している。

 研究では、実際に運転するための運転席に取り付けられたハンドルと、助手席に取り付けられた偽ハンドルの2つを用意する。 助手席のハンドルを操作すると、運転席のハンドルへ伝わる。

Marionetteシステムの概要

 Marionetteは低コストで簡単に複製できるオンロード研究のための、自律運転シミュレートインタフェースシステム。

 Wizardは参加者の存在を容認し、参加者の制御操作をWizardが任意で取捨選択する。 また、参加者の車両制御の情報を制御、調整するソフトウェア構築をしている。 さらに、研究者の数を増やすため、安価であり設置の容易性を重視した部品の利用している。

 実装に関する詳細な事項は、当該論文を参照ください。

システムに対する評価実験

評価実験の概要

 システムのユースケースとして、以下のものがある。

  • Wizardによる通常とは逸脱した運転(不正な運転:車線を蛇行等)に対して、被験者がどう反応するかについての路上実験
  • 被験者がどのようにハンドルをオーバライド*1 できるかの実験

 具体的には、以下の手順で実験を行なっている。

  1. 被験者をWIzard Operatorが見えないように車に誘導する。
  2. 被験者には、レベル3の自律走行車両と同様の機能を備えた自律運転システムで運転することを指示する。
  3. 自律運転システムが「不正な運転をした時」「自律運転が停止した時」に、被験者が運転をオーバライドする。
  4. 実験後の被験者への質問と運転のビデオ映像から分析を行う。

評価実験の結果と考察

 被験者は、このデバイスが自走車へのナビゲーション入力として使用できることをすぐに認識することができた。 自動運転開始後5-10分経過した段階で、心配そうな身振り手振りが大きく減ることが判った。

 また、被験者から得たフィードバックから以下のことがわかった。

  • Marionette上の多くの入力モードがシステムへの意図の伝達に有用
  • Marionetteには車両情報を示す計器類がない

 今後の展望としては、ハードウェア面では特にシステム上の制約を解消することが挙げられる。 また、ソフトウェア面としてコードのオープンソース化や、他の研究者が使えるようにプラットフォーム化することも挙げられた。

論文読解の参考となる知識


WOZ(Wizard-of-Oz)法*2

 システムに扮した人間(Wizard)がシステムの代わりをする対話シミュレーション手法。 音声対話システムの領域や、HCI(Human-Computer Interaction)の領域などで、開発中の効果的なシミュレーション手法として用いられている。

 人間同士の対話ではあるものの、ユーザは実際にシステムを相手にしていると思いながら対話を行うため、実際のシステムに近い状態での対話データとなる。 Wizardが未開発の部分を補完することで、開発中にシミュレーションが可能となる。 設計・開発者は実験結果を踏まえて実際のシステムを開発する必要がある。

 名前は、オズの魔法使い(The Wonderful Wizard of Oz)から由来している。 オズの魔法使いにおけるドロシーがユーザであり、願いを叶えてくれるはずのオズの魔法使いがWizardに対応している。

自動運転レベルの分類

 2016年9月にNHTSA(米運輸省道路交通安全局)*3の発表に伴い、 自動運転レベルが以下に示すSAE J3016(2016)*4のように見直されている。

  • レベル5: 完全運転自動化(Full Driving Automation)
    システムが全ての運転タスクを実施する。

  • レベル4: 高度運転自動化(High Driving Automation)
    限定領域内で、システムが全ての運転タスクを実施する。

  • レベル3: 条件付き運転自動化(Conditioned Driving Automation)
    限定領域内で、システムが全ての運転タスクを実施する。作動継続が困難な場合は運転者が適切に対応する必要がある。

  • レベル2: 部分的運転自動化(Partial Driving Automation)
    前後・左右方向の両方の 車両制御に係る運転タスク(DDT)のサブタスクを実施する運転支援システムが搭載されている。

  • レベル1: 運転者支援(Driver Assistance)
    前後・左右方向のいずれかの 車両制御に係る運転タスク(DDT)のサブタスクを実施する運転支援システムが搭載されている。

  • レベル0: 運転自動化なし(No Driving Automation)
    人間の運転者が全ての運転タスクを実行する。

 ただし、当該論文ではレベル4までの旧分類に従って執筆されている模様。 SAE J3016(2016)のレベル5・4が、旧分類ではレベル4として分類されている。

論文を読んだ感想


Many of the key challenges to automation lie in the area of human-machine interaction. [...] these questions [...] cannot be resolved simply with more automation. (自動化の重要な課題の多くは、人と機械の間の相互作用の領域にある。(中略) これらの問題は単純により自動化することによって解決することはできない。)

 人工知能が盛んに議論されている中、問題解決のために何でも自動化すべきというわけでないことを改めて感じた。 人と機械が共存しながら、人の生活を豊かにする機械であるために、その相互作用について知る必要がある。

*1:オーバライド: 伝わった操作を別の操作上書きすること

*2:Fraser, Norman M., and G. Nigel Gilbert. "Simulating speech systems." Computer Speech & Language 5.1 (1991): 81-99.

*3:NHTSA : The National Highway Traffic Safety Administration

*4:SAE : Society of Automoitve Engineers, inc., アメリカ自動車技術会