Django – テンプレートの基礎

概要

HTMLや埋め込まれたデータを含むテンプレートを使ったアプリケーションの基本。流れは以下の通り。

  • テンプレートを表示させるアプリケーションの作成と登録
  • テンプレートを保存するディレクトリーとテンプレートファイルの作成
  • テンプレートを呼び出すビュー関数の作成
  • ルーティング設定

ここでは以下のことを整理している。

  • テンプレートの配置場所
  • テンプレートの参照方法
  • テンプレート言語(DTL)の概要

関連記事

プロジェクトの準備

プロジェクトディレクトリーをtemplatebasicsとし、settings.pyなどを含むサブディレクトリーをconfigとする。

初期設定とサーバー起動で動作確認しておく。

アプリケーションの作成・登録

テンプレートを表示させるアプリケーションtemplatedemoを作成する。

そしてアプリケーションをsettings.pyINSTALLED_APPSに追加登録する。

テンプレート配置

初期設定

テンプレートの配置場所settings.pyTEMPLATESで設定する。

DIRSは任意の場所・ディレクトリー名のパスを設定する。またAPP_DIRTrueに設定すると、各アプリケーションディレクトリー下のtemplatesディレクトリーが探索される。

複数のテンプレートディレクトリーは一括して同列に扱われ、各ディレクトリーのサブディレクトリーも再帰的に探索される。

デフォルトの設定では、各アプリケーションディレクトリー下のtemplatesディレクトリーのみが対象となっている。

配置場所

ここでは、以下の場所にテンプレートディレクトリーを置いて設定していく。

  • 2か所にテンプレートディレクトリーを配置し、いずれのファイル名ともindex.htmlとしている
  • プロジェクト直下のディレクトリー名は任意だが、簡明のためtemplatesとする
  • 2つのテンプレートディレクトリーは併せて参照されるので、アプリケーション下の方は区別のためにサブディレクトリーを設けている

アプリケーション下

テンプレートディレクトリー作成

作成したアプリケーションディレクトリーtemplatedemoの下にtemplatesディレクトリーを作成し、その下に更にサブディレクトリーtemplatedemoを作成する。

テンプレートファイル作成

作成したサブディレクトリー下にindex.htmlファイルを作成して以下を記述。

プロジェクト直下

settings.py編集

TEMPLATESDIRSにプロジェクト直下のtemplatesディレクトリーを探索するよう追加。

os.pathを使う方法もありその場合はimport osが必要になるが、上記の記述でも同じ効果。

テンプレートディレクトリー作成

プロジェクトディレクトリー直下にtemplatesディレクトリーを作成する。サブディレクトリーは作成しない。

テンプレートファイル作成

作成したtemplatesディレクトリー下にindex.htmlファイルを作成して以下を記述。

view関数の作成とルーティング

view関数の作成

アプリケーションディレクトリーtemplatedemoviews.pyを編集して、view関数を定義する。

view関数でレンダリングするテンプレートを指定するため、プロジェクト直下とアプリケーションディレクトリー下2か所のテンプレートに対応する関数を記述している。要点は以下のとおり。

  • def 関数名(request):で定義
  • テンプレートを呼ぶ戻り値はrender関数
    • 第1引数は受け取ったrequest
    • 第2引数はテンプレートファイルのパス
  • テンプレートファイルのパスについて
    • TEMPLATESで設定したすべてのテンプレートディレクトリー下が一括して扱われる
    • テンプレートディレクトリー以下の相対パスとする

複数テンプレートディレクトリーが一括して扱われ、テンプレートの指定がテンプレートディレクトリーからの相対パスとなるため、サブディレクトリーを設定した意義が確認できる。

view関数のルーティング登録

これらのview関数をURLから呼び出すためurls.pyに記述を追加する。

確認

ここで開発用Webサーバーを起動して、ブラウザーで以下の入力に対応したページが表示されるのが確認できる。

  • localhost:8000/project
  • localhost:8000/application

DTL~テンプレート言語

概要

テンプレートにはHTMLのほかに、view関数から受け取った変数を埋め込んだり、繰り返しや条件分岐による出力の変更といった制御をさせることができる。そのための言語をDTL (Django Template Language)と言う。

  • {{ 変数 }}:変数の内容を展開してHTMLに埋め込む
  • {% 文 %}forendforによるループやifelifendifによる条件分岐で出力を制御する

変数の展開

たとえばtemplatedemoアプリケーションのviews.pyで、index_application関数を以下のように変更する。

ここでは、変数textを定義して、これを'text'をキーとする辞書の値としてrender関数の第3引数に渡している。

次に、templatedemoアプリケーション下のindex.htmlテンプレートを以下のように変更する。

表示結果は、ブラウザーの上部またはタブと見出しに同じ「アプリケーション下」が表示される。

このように、ビュー側で処理した結果を変数としてテンプレートに渡し、HTMLとして表示させることができる。

制御構造

先のindex_application関数を以下のように変更する。

ここでは第3引数をcontextとし、この変数に2つの要素を持つ辞書を入れている。1つ目の要素はタイトル、2つ目の要素は物語のシーンを収めた配列としている。

これを受け取るindex.htmlを以下のように変更する。

scenesで渡された配列の要素を、DTLのforendforでループしながら取り出し、li要素として並べている。この結果、出力されたHTMLでは5つのシーンがリストとして表示される。

同じテンプレートを使って、タイトルとシーンを桃太郎やかぐや姫などと変化させることができる。

 

Django – テンプレートの場所

概要

  • Djangoのテンプレートファイルは、テンプレートディレクトリーやそのサブディレクトリーに置かれることを想定している
  • 複数場所に配置されたテンプレートディレクトリー以下が一括して探索される
  • 探索場所と順序はsettings.pyファイルのTEMPLATESの設定に従う
    • DIRSでは任意の場所・名前でテンプレートディレクトリーを追加できる
    • APP_DIRSTrueに設定されている場合、各アプリケーションディレクトリー下のtemplatesディレクトリーが探索される
  • 探索されたテンプレートを参照する場合、テンプレートディレクトリーからの相対パスで指定する
  • テンプレートディレクトリーを分散配置しても一括して検索されるため、各テンプレートディレクトリーに適切なサブディレクトリーを置いて、その下にテンプレートファイルを置くのが一般的

確認用プロジェクト

確認のためtemplatetestプロジェクトを準備し、app1app2の2つのアプリケーションを作成する。templatesディレクトリーとそのサブディレクトリーを以下のように作成し、4つの場所に即した内容のindex.htmlファイルを置く。

各場所のindex.htmlは、title要素/bodyp要素で以下を表示させるようにした。

  • App1/Under the app1 directory
  • App2/Under the app2 directory
  • Subirectory/Under the subdirectory
  • Base Directory/Under the base directory

そしてapp1のビューファイルで指定するテンプレート名のディレクトリー名を変更しながら、各場所のindex.htmlが読み込まれたかどうか確認する。

プロジェクトの完成後、template変数に設定した文字列を以下のように変更して、それぞれに対応したページが表示されるかどうかを確認する。

  • 'base/index.html'
  • 'subdirectory/index.html'
  • 'app1/index.html'
  • 'app2/index.html'

TEMPLATESの初期設定

初期状態でのTEMPLATESは以下の通り。

このうちテンプレートの探索場所は'DIRS''APP_DIRS'で設定される。

なおディレクトリーの探索場所が設定されていれば、そのサブディレクトリー下も再帰的に探索される。

DIRSでの設定

プロジェクトディレクトリー直下

'DIRS'にはプロジェクト内任意の場所の、任意の名前のディレクトリーを設定できる。たとえばプロジェクトディレクトリー直下に置いたtemplatesを探索させるなら以下のように記述する。

または

後者の場合、settings.pyではimport osがないので追加が必要。

この設定により、'templatetest/templates/base/index.html'のレンダリングが可能になる。

サブディレクトリー下

プロジェクトの設定ファイル群があるサブディレクトリー下(この場合configディレクトリー)にあるディレクトリーを探索させるときは以下のように相対パスで設定する。

または

この場合もsettings.pyimport osが必要。

この設定により、templatetest/config/subdirectory/templates/index.htmlのレンダリングが可能になる。

APP_DIRSの設定

また、'APP_DIRS'Trueに設定されている場合は、各アプリケーションディレクトリー下にあるtemplatesディレクトリーが探索される。

デフォルトでTrueがセットされているので、アプリケーションディレクトリー下にtempratesディレクトリーがあれば全て探索される。

この例の場合、app1/templatesapp2/templatesは、デフォルトの設定)のままでそれぞれのサブディレクトリーも含めて探索される。

この結果templatetest/app1/templates/app1/index.htmltemplatetest/app2/templates/app2/index.htmlのレンダリングが可能になる。

全てを探索させるTEMPLATESの設定

これまでの4つの場所のすべてを探索対象とするには、settings.pyTEMPLATESを以下のように設定する。

この結果、以下の4つが探索可能になる。

  • templatetest/templates/base/index.html
  • templatetest/config/templates/subdirectory/index.html
  • templatetest/app1/templates/app1/index.html
  • templatetest/app2/templates/app2/index.html

templatesのサブディレクトリー

特にアプリケーションディレクトリー下にテンプレートを置く場合に、(index.htmlのように)同じ名前のファイルが重複しないよう、サブディレクトリーを設けるのが一般的。

通常、サブディレクトリー名はアプリケーションディレクトリー名と同じとする。冗長だが重複が防止され、可読性も保たれる。

 

 

Django – Hello! – 単純なアプリケーション

概要

特定のURLにアクセスするとブラウザーに”Hello!”とだけ表示させるプロジェクトを作成する。要点は以下の通り。

  • Djangoのプロジェクトは複数のアプリケーションを含むことができる
  • アプリケーション作成はmanage.pystartappオプションで実行
  • リクエストに対応した処理を行うview関数をviews.pyに定義
  • 特定のURLへのアクセスが対応するview関数にルーティングされるよう、urls.pyに設定

仕様

動作は以下の通り。

  • URLにhttp://localhost:8000/helloを指定してリクエスト
  • 文字列"Hello!"を返す(ブラウザーに表示される)

構造は以下の通り。

  • Hello表示のアプリケーションをhelloとする
  • リクエストに対応するview関数をsay_hello()とする
  • say_hello()はリクエストに対して文字列"Hello!"をレスポンスで返す

プロジェクトのスタート

まずgreetingsという名前でディレクトリーを作成し、そのディレクトリー下にプロジェクト作成。ここではサブディレクトリー名をconfigとしている。

プロジェクトの構成は以下の通り。

settings.py編集後にサーバーを起動してDjangoのwelcomeページが表示されることを確認しておく。

ここでのsettings.pyの編集内容は以下の通り。

  • ALLOWED_HOSTSへの追加
  • DATABASESのコメントアウト
  • 言語とタイムゾーンの設定

サーバー起動はVagrantのプライベート環境下なので以下の通り。

ブラウザーからのアクセスはhttp://localhost:8000で。

アプリケーションの作成

アプリケーション作成は、プロジェクトディレクトリー直下(manage.pyのある場所)で以下を実行。

ここでは、ブラウザーに”Hello!”を表示するためのhelloアプリケーションを作成する。greetingsディレクトリー下で以下を実行。

ディレクトリー構成は以下のようになる。新たにhelloディレクトリーが追加されている。

settings.pyにアプリケーションを追加

プロジェクトでhelloアプリケーションを認識するため、settings.pyINSTALLED_APPSにアプリケーション名'hello'を追加。

viewの作成~views.py

リクエストに対応した処理を、helloアプリケーションディレクトリー内のviews.pyファイルに記述。

  • 単純にHTTPレスポンスで文字列を返すため、HttpResponseをインポート
  • view関数としてsay_hello()を定義し、文字列を返すよう記述

ルーティング~urls.py

想定しているURLに対して定義したview関数が呼ばれるようにルーティング。プロジェクトサブディレクトリーのurls.pyファイルに記述を追加する。

  • say_hello()を使うためインポートが必要
  • urlpatterns/helloからsay_hello()へのルーティングを定義

ブラウザーから接続

以下のURLでブラウザーに”Hello!”と表示される。

なお、これ以降localhost:8000のルートに接続すると404エラーとなる。

ルーティングを記述したurls.pyにホストのルートへのルーティングを追加すると、http://localhost:8000のURLに対しても”Hello!”が表示されるようになる。

 

Django – プロジェクトの作成

概要

Djangoのプロジェクト作成はdjango-admin startprojectで行う。新規にプロジェクトディレクトリーを作成する方法と、既存のディレクトリーに作成する方法がある。

新規にプロジェクトディレクトリーを作成する方法では、プロジェクト名のみを指定する。

この場合プロジェクト名と同じディレクトリーが作成され、その下に同じ名前のサブディレクトリーとmanage.pyファイルが作成される。

既存のディレクトリーに作成する方法では、第1引数にサブディレクトリー、第2引数に既存のプロジェクトディレクトリーを指定する。

この場合、既存のプロジェクトディレクトリーの下にサブディレクトリーとmanage.pyファイルが作成される。

何れの場合もサブディレクトリーの内容は同じで、プロジェクト全体に関する設定ファイルなどが作成される。

manage.pyはコマンドラインで管理レベルの操作を行うためのファイル。

プロジェクト名だけを指定する場合

プロジェクト名だけを指定した場合は、その名前でディレクトリーが作成され、その下に同じ名前のサブディレクトリーとmanage.pyファイルが作成される。

もし同じ名前のディレクトリーが既に存在していた場合はエラーとなる。

以下は新規作成されたプロジェクトディレクトリーの内容

サブディレクトリーの下には、プロジェクト全体に関する設定ファイルが作成される。たとえばsettings.pyファイルは、プロジェクトの言語やタイムゾーン、データベースなどに関する設定を記述する。

既存のディレクトリーに作成する場合

空のプロジェクトディレクトリーを作成し、第1引数にサブディレクトリー、第2引数にプロジェクトディレクトリーを指定して実行する。

もし指定したプロジェクトディレクトリーが存在しない場合はエラーになる。

なお、以後の作業をプロジェクトディレクトリー内で行うことを想定して以下のように実行してもよい。

この場合のディレクトリー構成は以下のようになる。

 

 

Django – 初期設定とサーバー起動

概要

主な留意点は以下の通り。

  • DjangoのデフォルトDBMSはSQLite
  • 言語・タイムゾーン・DB設定などはsettings.pyで記述(Laravelの.envに相当)
  • Vagrantなどの仮想環境の場合はサーバー起動のIPに注意
    →ゲスト側でALLOW_HOSTSの設定も必要

当初に発生したエラーと対応についてはこちら

データベースクライアントのインストール

DjangoのデフォルトではSQLiteとなっている。SQLiteの場合は一定以上のバージョンが要求される模様。

他のDBMSを使う場合、クライアントをインストールしておく必要がある。以下はMySQLを使う場合にmysqlclientをインストールした例。

settings.py~各種設定

言語とタイムゾーン

言語を日本語に、タイムゾーンを日本のものに設定。

データベース設定

デフォルトのSQLiteではなくMySQLを使う例

ホスト許可

Vagrantなど仮想環境のプライベートネットワークで接続する場合、ここに設定が必要。

Vagrantの場合

Vagrantfileの設定

ポートマッピング設定。プライベートネットワークはデフォルト。

ゲスト側IP確認

ゲスト側の仮想環境でサーバーを起動する場合のIPを確認。ホスト側では127.0.0.1にセットされている。

開発用Webサーバー起動

ifconfigで確認したゲスト側のIPでサーバーを起動する。

ブラウザーで接続

ホスト側のブラウザーで、http://localhost:8000かhttp://127.0.0.1:8000で接続。

 

CwntOS7 – Djangoのインストール

概要

Vagrant上のCentOS7にDjangoをインストール。

virtualenvの仮想環境でインストールした場合、元のシステムには影響を与えない。

手順

Python3インストール済みの環境でDjangoをインストール。特に問題なくインストール完了。

バージョンチェック。

Python3からもチェック。

 

Vagrant – CentOS7 – Python3 – virtualenv

概要

Vagrant上のCentOS7で、virtualenvをインストールしてPython3の仮想環境をつくった手順の記録。

  • pipvirtualenvwrapperをインストールする
  • sudoでインストールすると警告が出てグローバルにインストールされる

許可がなくインストールできない

pip3virtualenvwrapperをインストールしようとしたところ、許可がないとエラーになった。

ディレクトリーに書き込み権限がない。

sudoで警告が出るがインストール

以下のような警告が出るが、インストールは実行される。

WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install –user` instead.

グローバルインストールするのに対して、--userオプションでユーザーディレクトリーへのインストールを促している。

確認

virtualenvのバージョン確認。

仮想環境構築の確認。

ディレクトリー確認。

仮想環境の有効化。

仮想環境の無効化と削除。

操作

基本操作

ディレクトリーを作成して仮想環境を作成。絶対パスでなければ現在のディレクトリー下に作成される。

$ virtualenv directory

仮想環境の有効化。

$ source directory/bin/activate
または
$ . directory/bin/activate

仮想環境の無効化。

(directory) $ deactivate

仮想環境の削除

$ rm -rf directory

応用

Pythonのバージョン指定

$ virtualenv -p python3.6 directory

システムのPythonパッケージ群を仮想環境からも参照

$ virtualenv --system-site-packages directory

virtualenvwrapperの利用

.bashrcの編集と再読み込み

virtualenvだけでも基本的な操作はできるが、virtualenvwrapperを利用すると便利なコマンドが使えるようになる。そのために~/.bashrcに以下の3行を加える。

.bashrcを実行して反映させる。

1行目のWORKON_HOMEで指定したディレクトリーが作成され、ここに仮想環境ごとのディレクトリーが作成される。

2行目を設定しないと以下のエラーが出る。エラーが出てもvirtualenvwrapperは利用できたが入れておく。

3行目はvirtualenvwrapper.shを実行させる。

.bashrcの実行後、~/.virtualenvsディレクトリーと必要なファイルが作成される。

確認

仮想環境を作ってみる。

python3の場所が仮想環境内になっていて、元のシステムの場所とは違う。

もう一つ仮想環境を作って、workonコマンドで見てみる。lsvirtualenvコマンドもあるが、workonコマンドとの違いがよくわからない。

仮想環境にモジュールをインストールしてもシステムに影響がないことを確認する。まずシステムにはNumpyモジュールがインストールされていないことを確認。

仮想環境でもNumpyはインストールされていない。

Python3をexit()で抜けて、仮想環境のコマンドラインでNumpyをインストール。

Python3でNumpyが使えるようになった。

Python3をexit()で抜けて、仮想環境からも抜ける。元の環境ではNumpyはインストールされていないことがわかる。

virtualenvwrapperのコマンド

仮想環境の作成・有効化。WORKON_HOMEで設定したディレクトリーに作成される。

$ mkvirtualenv envname

仮想環境の無効化。

(envname) $ deactivate

仮想環境の一覧。

$ workon
または
$ lsvirtyalenv -b/-l

仮想環境の有効化。

$ workon envname

仮想環境ディレクトリーへの移動。

$ cdvirtualenv envname

仮想環境の削除。

$ rmvirtualenvname envname

 

Vagrant – CentOS7 – Python3インストール

概要

Vagrant上のCentOS7にPython3をインストールした記録。

要点は以下の通り。

  • IUSのリポジトリーでインストール
  • --enablerepo=iusが必要

バージョン確認

まずPythonのバージョンを確認する。

一応Python2の動作確認。

Python3はインストールされていない。

IUSのリポジトリー追加

リポジトリー追加ができない。

リポジトリーは作成できている。

GitをインストールしたときにIUSのリポジトリーをインストールしていたのを忘れていた。

Python3がインストールできない

Python3.6をインストールしようとするができない。

/etc/yum.repos.d/ius.repoの設定でenabled = 0になっているため。Gitのインストールの時に書き換えているが、毎回元に戻るのか?

オプション設定でインストール成功

設定ファイルを書き換えてもよいが、yum実行時のオプションで--enablerepo=iusを追加して成功。

確認

バージョン確認。

動作確認。

Python2ではない。

python3の場所。

pipのバージョン確認。

 

PCA – 主成分分析

概要

主成分分析(principal component analysis: PCA)は教師なし学習の手法の一つでもあり、その考え方は、特徴量の線形組み合わせの中で、最もデータの情報を多く含む組み合わせを発見し、それを主成分として分析を行うものである。

具体的には、特徴量空間の中でベクトルを考え、そのベクトル沿いのデータの分散が最も大きくなるようにベクトルを定める。その考え方と定式化については、主成分分析の定式化にまとめた。

クラス分類データへの適用

Irisデータセット

Irisデータセットにscikit-learnのPCAを適用した例。

PCA – Irisデータセット

教師なし学習として、クラス分類のターゲットデータを用いることなく、特徴量の分析だけでクラスがうまく分離できるような主成分が得られる。

Breast cancerデータセット

Breast cancerデータセットにscikit-learnのPCAを適用した例。

PCA – Breast cancerデータセット

Irisデータの場合と同じく、教師なし学習として、クラス分類のターゲットデータを用いることなく、特徴量の分析だけでクラスがうまく分離できるような主成分が得られる。

ここでは、主成分を構成する各特徴量の寄与をヒートマップによって視覚化している。

LFW peopleデータセット

著名人の顔画像データを集めたLFW peopleデータセットにscikit-learnのPCAを適用した例。

PCA – LFWデータセット

主成分の可視化、次元圧縮後の画像の再現など、様々な角度でPCAの特性を見ている。

回帰データへの適用

Boston house pricesデータセット

Boston house pricesデータセットにPCAを適用して、ターゲットが連続量で与えられた回帰系の問題への適用性を確認する。

PCA – Boston house pricesデータセット

このデータセットに関する限り、PCAで明確な関係は見いだせなかった。

なお、このデータセットには属性データが含まれ、前処理としてone-hot encodingを行っている。

 

PCA – LFWデータセット

概要

Scikit-learnで提供されているLFW peopleデータセットを、主成分分析を使って分析する。

データの読み込みと確認

LFWデータセットは世界の著名人の顔画像を、その名前とそれに対応するクラスデータとともに格納したものである。

書籍”Pythonではじめる機械学習”に沿って、画像サイズを0.7にし、20枚以上の画像がある人物を抽出する。

画像の人物は書籍と同じだが顔画像は異なっている。書籍執筆後画像データが追加/変更されたものと思われる。

画像の枚数の絞り込み

元のコード

LFW peopleの画像データは、人物によって枚数にばらつきがある(特にGeorge Bushだけ500枚を超えている)。画像データの多寡によるばらつきを抑えるため、書籍では画像の数を50枚までとし、それ以上の画像は切り落としている。

このコードがちょっとわかり難かったので、別にこちらで整理している

k-近傍法との組み合わせによる精度の確認

書籍では、画像を50枚以下に制限したデータについて、k-近傍法(knn)を適用したときのスコア、元データを主成分分析によって変換した場合のknnのスコアを確認している。

その過程をトレースしてみた

  • 画像データを最近傍データ1つで判定する1-nnの実行結果は、スコアは0.23と低い
  • 元の画像データを100個の主成分で変換したデータに対しては、1-nnのスコアは0.31と若干向上
  • PCAインスタンス生成時にwhiten=Trueを指定しない場合、PCA変換後もスコアは向上しなかった

主成分の可視化

PCA.fit()を実行すると、PCA.components_に主成分が格納される。components_は2次元配列で、[主成分の数, 元の特徴量数]という形になっている。たとえば今回のデータの場合、主成分の数はn_componentsで指定した100、特徴量の数は画像のピクセル数87×65=5655となり、components_は100×5655の2次元配列になっている。

(1)    \begin{equation*} \tt{components_} = \left[ \begin{array}{ccc} (p_{0, 0} & \cdots & p_{0, 5654} ) \\ & \vdots &\\ (p_{99, 0} & \cdots & p_{99, 5654}) \end{array} \right] = \left[ \begin{array}{c} \boldsymbol{p}_0 \\ \vdots \\ \boldsymbol{p}_{99} \end{array} \right] \end{equation*}

components_に収められた主成分はそれぞれが画像データと同じサイズの配列なので、これらを画像として表示させてみる。

たとえばComponent-0は顔と背景のコントラスト、Component-2は顔の左右の明るさの差をコーディングしているように見える、と書籍では解説している。その他にも、Component-5は目の下の出っ張った部分、Component-11は鼻筋のあたりを表現しているかもしれないといった想像はできる。

上の画像は以下のコードで表示させたが、要点は以下の通り。

  • 最低20枚の画像を持つ人物のみ読み込んでいる
  • 画像の最大数を50枚以下に制限している
  • 訓練データとテストデータに分割し、訓練データを主成分分析にかけている
  • components_プロパティーの主成分配列のうち、15行分を取り出して表示させている
  • 表示にあたって、リニアな5655の要素を画像の形(87, 65)に変形している
  • components_の形状が、100行×5655の2次元配列であることを確認

次元圧縮された主成分からの復元

概要

主成分の意味の一つとして、元のデータは主成分の線形和で表せるという解釈がある。

(2)    \begin{equation*} \boldsymbol{x} = (x_0, ..., x_n) = a_0 \boldsymbol{p}_0 + a_1 \boldsymbol{p}_1 + a_2 \boldsymbol{p}_2 + \cdots \end{equation*}

LFWの顔画像データで考えると、components_に収められた主成分の重みによって、元のそれぞれの人物の画像を再現しようとすることになる。

そこで、限られた主成分だけを用いて元の顔画像を再現してみる。

顔画像の選定

まず、特に有名な人物の顔画像をいくつか表示させてみた。選んだ人物は、Arnold Schwarzenegger, Tiger Woods, Vladimir Putinの3人。

これらの画像から、一旦次元削減して復元する画像を選ぶ。Shwalzzeneggerは正面少し左向きの31番、Tiger Woodsは少し右側から撮った歯を出している683番、Putinは左を向いた顔をほぼ正面から撮った372番を選んだ。

次元削減後の逆変換

そして次元数を変化させながらPCAモデルに全データを学習させ、それらのモデルで3枚の画像を変形し、逆変換する。

10個の主成分では、3人とも似たような顔になっているが、30個になると顔の方向や葉を出しているかどうかといった特徴が表れ始めている。

70個から100個にかけて、ShwaltzeneggerとWoodsはかなり元の顔に近いが、Putinはあまり判然としない。前者2人が「濃い」顔立ちなのに比べると、Putinの顔立ちは平板だということだろうか。

この画像は、以下の手順で作成した。

  1. 20枚以上の画像を持つ人物を選び、画像の枚数を50枚以下に制限
  2. 3人の顔画像について、次元数を10、30、70、100と変化させて以下を実行
    1. 設定された次元数で全データを学習
    2. 学習済みモデルで各顔画像を変換(ここで次元が削減される)
    3. 設定された次元数で元の顔画像に逆変換

同一人物の画像

さらに、3人について1人ずつ、3枚の顔画像について同様のことを行った結果が以下の通り。

Shwalzeneggerの後半2枚は向きが逆だが口元などがよく似ていて、目元と口元の特徴が強調されている。1枚目の画像はこの2枚と特徴が違うが、主成分30個あたりではよく似た感じともいえる。

Tiger Woodsも、主成分30個のところで173と683の画像が似ている。だが、535については一貫して他の2つと異なっているように見える。個人の特徴よりも顔の表情に大きく引きずられているようだ。

Putinは60と372の画像が割に似ているが、239の画像はかなり異なり、コントラストが強調されているようだ。60や372では、そもそも顔画像が平板なせいなのか、主成分を増やしても明確な画像が得られていない(他の人物との区別も難しいのではないだろうか)。

第2主成分までによるクラスの分布

第1主成分と第2主成分だけを使って、各クラスの分布をみてみる。62人の人物の各画像データが1つの点に対応している。2つの主成分だけでは人物が明確なクラスターとしては認識し難い(というよりもクラスが多すぎて識別も難しい)。

試しに表示するクラスを5つに限定してみる。やはり2つの主成分では明確なクラスターは確認できない。先ほどの変換・逆変換の結果でも、主成分10個でも個々の顔の識別は困難だったので、2つの主成分では難しいのは自明だが。

以上の可視化のコードは以下の通り。