Java – InfinityとNaN

Infinity

実数のオーバーフローはInfinity

実数演算で最大値を超えるような演算をすると、結果がInfinityになる。最小値を下回る演算の場合は-InfinityInfinityのリテラルはない。

Infinityに対する数値の演算結果は直感的

Infinityに対して数値を加減乗除しても結果はInfinity。で、数学の∞と同じ。

数値からInfinityを減じると-InfinityInfinityで割ると0.0。lim[x→∞]と考えると直感的。

Infinity同士の演算

Infinity同士の加算・乗算はInfinityInfinity同士の減算・除算はNaN

Infinityと最大値

Infinityは実数の最大値より大きく、これと等しくはない。

Infinity同士の大小比較

InfinityInfinityと等しい。

Infinityの定数定義

Infinitydouble型とfloat型で定義されていて、それらの定数定義も準備されている。

double型とfloat型で、Infinity-Infinityはそれぞれ等しい。

NaN

計算結果が不定→NaN

実数演算でゼロ同士やInfinity同士の除算結果はNaN (Not a Number)になる。NaNのリテラルはない。

NaNを含む演算はNaN

NaNを含む四則演算の結果は全てNaN

NaN != NaN

NaN同士は互いに等しくない。大小関係は特定できない(>でも<でもない)。

NaNの定数定義

NaNdouble型とfloat型で定義されていて、それらの定数定義も準備されている。double型のNaNfloat型のNaNは等しくない(double型同士やfloat型同士と同じように)。

InfinityとNaN

InfinityNaNの演算結果はNaN

InfinityNaNは互いに等しくない。大小関係は特定できない(>でも<でもない)。

 

Rails – 共通ヘルパーの置き場所

概要

複数のコントローラーやビューで共通に利用したいヘルパーの置き場所について。単純なヘルパーの場合、以下の場所が候補になる。

  • app/helpers下のビューに対応した***_helper.rbに記述
  • app/helpers/application_helper.rb内に記述
  • app/controllers/concerns下のモジュールファイルに記述(コントローラー

依存関係を持つような場合はconcernsに置くのがよいようだが、単純なヘルパーの場合はビューとの関連によってapplication_helper.rbに統一するのが簡明かもしれない。

コントローラーに対応したhelper

ヘルパーファイルにヘルパーを記述してapplication_controllerでインクルードすると、コントローラーやビューでこれを使うことができる。

以下はPagesコントローラーの例で、コントローラーとビューの両方でfoo_helperの実行が確認できる。

定義・設定

helpersディレクトリー内にあるコントローラー_helper.rbの中でヘルパーを定義する。

app/helpers/pages_helper.rb

application_controllerでモジュールをインクルード。

app/controllers/application_controller.rb

利用

コントローラーで利用可能。

app/controllers/pages_controller.rb

ビューでも利用可能。

app/views/pages/helper_test.html.erb

application_helper

application_helperもヘルパーファイルの1つで、Railsにより準備される。これを上と同じくapplication_controllerでインクルードして、アプリケーション共通のヘルパーとして使える。

定義・設定

helpersディレクトリー内にあるapplication_helper.rbの中でヘルパーを定義する。

app/helpers/application_helper.rb

application_controllerでモジュールをインクルード。

app/controllers/application_controller.rb

利用

コントローラーで利用可能。

app/controllers/pages_controller.rb

ビューでも利用可能。

app/views/pages/helper_test.html.erb

concerns

app/controllers/concernsにはコントローラー間で共通のモジュール、app/models/concernsはモデル間で共通のモジュールのファイルを配置する。

コントローラーなどでインクルードしてもビューではこれらのモジュールは使えない。

定義・設定

concernsディレクトリー下にモジュールファイルを作成して、その中にヘルパーを書く。

app/controller/concerns/common_module.rb

application_controllerでモジュールをインクルード。

app/controllers/application_controller.rb

利用

コントローラーで利用可能。

app/controllers/pages_controller.rb

しかしビューでは使えない。

 

 

 

Rails – レンダリングされない~form_with

概要

Rails事始めで、フォームから送信した内容を反映させるだけのことが「ページがレンダリングされない」という状態になった話。

結論はfome_withの機能とパラメーターに関するもので、オンラインレッスンの講師の方に教わるまで解決できなかった。

問題の内容

アプリケーション

フォームから受け取った値をインスタンス変数に入れて、それを他のアクションで参照してフォームがあるページを更新するという内容。

躓いてから、できるだけシンプルにしていったのが次のアプリケーションで、フォームのボタンを押すとトップページのテキストの内容を入れ替えるだけのもの。

コントローラー:app/controllers/pages_controller.rb

ビュー:app/views/pages/top.html.erb

ルーティング:config/rotes.rb

症状

以下のページが表示されるが、Submitボタンを押しても画面に変化がない。

よく見ると、inputにルーティングしているのにURLに/inputがついていない。

検証ツールで見ると、inputに対して通信はしていて、書き換えの処理はされているようだ。

コンソールの出力を見ると、POST時の変数の内容は”Hi”に変更されている。

解決

解決策は”form_withのパラメーターにlocal: trueを加える”というものだった。

<%= form_with(url: input_path, local: true) do %>

コントローラー:app/controllers/pages_controller.rb

Submitボタンを押すと表示が変更されるようになった。

理由

form_forでは送信時にページ全体がレンダリングされるが、form_withはデフォルトではajaxによる送信となっていて、そのままではページがレンダリングされない。

パラメーターにlocal: trueを指定するとHTMLとしてのフォーム送信として扱われ、ページがレンダリングされる。

form_tag/form_withがdeprecatedだというところだけを読んで気軽に使ったのが敗因。

 

Vagrant – MySQLのインストール – AmazonLinux2

概要

Vagrant + VirtualBoxのamazonlinux-2にMySQLをインストールした記録。

  • MySQLをローカルインストールする際、展開されたすべてのファイルをインストールする必要がある
  • Amazon Linux 2では標準でMariaDBがインストールされているのでアンインストール

インストール

概要

CentOS7へのインストールと同じ手順で完了した。ただしAmazon Linux 2にデフォルトでインストールされているMariaDBをアンインストール。

MariaDBのアンインストール

wgetの確認

Boxにwgetがインストールされていることを確認。

ダウンロード

ブラウザーで以下のページをたどる。

アーカイブページで以下を選択。

  • Product Version
    • 5.5.62
  • Operating Sysrem
    • Red Hat Enterprise Linux / Oracle Linux
  • OS Version
    • Red Hat Enterprise Linux 7 / Oracle Linux 7 (x86, 64-bit)

一覧の中のRPM Bundle、Downloadボタンを右クリックしてリンクのアドレスをコピー。

コンソールからwgetに上でコピーしたURLを適用してダウンロード。tarファイルがダウンロードされる。

ダウンロードされたtarファイルを確認し、展開。

展開されたファイルのインストール

1つずつsudo yum…でインストールしても、1行にまとめてインストールしても。

全ての展開ファイルのインストールが必要

当初、server、client、embeddedのみをインストールしたところ、不具合が出た。

  • Railsインストール後にプロジェクト生成でエラー
  • MySQLの文字コードセットがdatabaseとserverでlatin1
  • /etc/my.cnfが存在しない

後から残りのファイルをインストールしたところ、上の不具合は全て解消。ただしtestまで必要かどうかは確認していない。

サーバー稼働

サーバーの起動

オリジナルの環境ではservice mysqld startでサーバーを起動していたが、仮想環境ではsystemctlを使う。

ログイン

このバージョンのMySQLは、rootの初期パスワードは設定されていなかった。

文字コードセットの確認

MySQLコンソールからshow variablesで文字コードセットを確認。

 

JS/ES – DOM – textContent, innerText, innerHTML

概要

ブラウザーによる対応の有無もあるようだが、DOMの要素のテキストを扱う3つのプロパティー、textContent, innerText, innerHTMLの機能を確認する。

コード内容と結果

確認に使ったコードは以下の通りで、予め空のa要素を準備し、これに対して3つのプロパティーによってテキストを設定している。

テキストの種類は、プレーンテキスト、エスケープコード含み、HTMLタグ含みの3種類。

これに対して3つのプロパティーの挙動を確認しているので、計9個のリンクの結果を確認する。

HTML

結果

プレーンテキストに対しては、3つのプロパティーとも同じ結果になる。

エスケープコードを含むテキストについては、innerTextはエスケープを機能通りに表示、textContentとinnerHTMLはエスケープの機能は再現しないが、半角空白の文字として表現。

タグに関しては、innerHTMLは反映、他の2つはそのままプレーンテキストとして表示される。つまり、innerHTMLは<や>などの文字がそのまま送られ、innerTextとtextContentでは&lt;や&gt;などの特殊記号に変換されて送られる。

まとめ

textContent innerText innerHTML
プレーンテキスト テキスト表示 テキスト表示 テキスト表示
ESC含みテキスト テキスト表示(ESCは半角SP) ESC機能を反映 テキスト表示(ESCは半角SP)
タグ含みテキスト プレーンテキスト表示 プレーンテキスト表示 タグ機能を反映

Ruby – chomp/chomp!~末尾の改行文字の削除

chompは末尾の改行文字を削除する。ただし"\n\r"の場合は"\n"が削除されずに残る。

"\n\r"を削除したいときは引数に"\n\r"を指定するか、chompを2回実行する(chompは改行文字列だけを削除する)。

末尾以外にある改行文字は削除されない。

chopは非破壊的であり、元の文字列は変更されない。

chop!にすると破壊的メソッドになり、戻り値も変更後の文字列。

 

PCA – 次元削減と逆変換について

概要

主成分分析(PCA)において、次元削減により主成分の一部だけを残し、それを逆変換することを考える。

結論から言うと、以下の2つの操作は同じ結果をもたらす。

  • 全ての主成分を用いて変換し、削減する主成分に対応する元の特徴量を0とし、逆変換する
  • 削減する主成分より低次の主成分のみで変換し、それを逆変換する

簡単な例

全主成分を使った手順

概要

最初の例は、2次元のデータについて以下のような操作を行っている。

  1. 2つの主成分まで使ってデータを変換
  2. 第2主成分に対応する変換後のデータを0にする
  3. そのデータを逆変換する

元データの作成

まず元データを作成し、左上に散布図を描画。

元データは水平線にcosine状に正規分布するノイズを乗せ、それを45度回転させている。

また、適当な位置に特定の点を1つ定義している。

フィッティングと元データの変換

次に元データをPCAによって変換し、変換後の散布図を右上に描画。

斜めだった分布が、第1主成分がx軸と重るように変換されて水平になる。

第2主成分のデータの削除

変換後のデータにおいて、第2主成分に関する値を0とし、左下に散布図を描画。

第2成分に相当する垂直成分が0になる。

逆変換

第2主成分を0としたデータを逆変換して描画。

第1主成分に直角な第2主成分が0となり、全点が一直線上に並ぶ。

最初から主成分を限定する手順

概要

次の例は元の特徴量を操作せず、以下のような手順に寄っている。

  1. PCAのモデル生成時に、n_component=1とする
  2. そのPCAモデルで元データを変換する
  3. 変換したデータを逆変換する

まとめ

途中で表示させているXpのデータが、2つの手順で全く同じであることがわかる。

最初から主成分を限定することで、元の特徴量を意識せずに次元削減ができる。

 

LFW peopleデータセット

概要

Scikit-learnから入手できるLFW peopleデータセットは、世界の著名人の顔画像データを集めたものである。

1人につき1枚~最大530枚の画像データが、それぞれの人に対して紐づけされている。

LFWは”Labeled Faces in the Wild”の略で、”in the Wild”には「出回っている」というニュアンスがあるらしい。

IrisBostonなどのデータと異なり、Scikit-learnをインストールした状態ではデータはローカルに格納されず、最初の読み込み時にデータがダウンロードされてローカルに格納される。1度ダウンロードされた後は、ローカルのデータが使われる。

【注意】

  • fetch_lfw_people()resize引数を変更すると、そのたびにデータのダウンロードが実行されるようなので、実行ごとの時間を節約したい場合はresizeの値を決めておくとよい

データの取得

データの読み込みは以下の手順による。

  • sklearn.datasets.fetch_lfw_peopleをインポートする
  • fetch_lfw_poeple()関数でBunchオブジェクトのデータセットを読み込む
    • fetch_lfw_peple()関数を最初に実行したときに、ローカルにデータが読み込まれる(これには数分程度かかる)
    • 一度読み込まれた後は、ローカル上のデータが使われる
    • ローカル上のデータの場所は、ログインしたユーザーのホームディレクトリー下、schikit_learn_dataディレクトリー

データ構造

データセットはBunchオブジェクトで、辞書型のkeyvalueで内容を取得できる。

内容は以下の通りで、

  • dataimagesは顔画像データを異なる形状の配列で格納したもの
  • targetは各顔画像の人物id
  • target_namesは各idに対する人物の名前
  • DESCRはデータに関する説明。

データの内容

target_names~ターゲットの人物

ターゲットとなる人の名前はtarget_namesに格納されていて、その数は20201122時点で5,749人分のユニークなデータ。

名前に対するインデックスがターゲットのidになる。

target~ターゲット数

ターゲットのidはtargetに1次元配列で格納されている。

1人のターゲットに複数枚の異なる顔画像が格納されているものもあり、targetデータに格納されたターゲットデータ全体は13,233個。

これらのidがターゲットとなる人の名前と顔画像データに結びついている。

images~顔画像のピクセルデータ

imagesには各顔画像のデータが1次元のピクセル値として格納されている。

配列のインデックスとtargetのインデックスが紐づいていて、targetの要素から顔画像の人物が特定できる。

このデータの構造は以下のとおりで、13,233個の画像データが62×47のグレイスケールの配列として保存されている。

3次元データの構造は以下の通り。

data~1次元の顔画像データ

dataには顔画像のピクセルデータが各画像ごとに1次元で格納されている。

imagesと同じく、各画像データと人物が紐づけられる。

このデータの構造は以下の通りで、13,233行のデータがあり、各行が2次元の配列を1次元にフラット化した形で格納されている(62×47=2914)。

2次元のデータ構造は以下の通り。

データの概要

顔画像データの確認

顔画像データの内容を確認してみる。ここでは、書籍”Pythonではじめる機械学習”の例に沿って、最低20枚以上の画像がある人物から最初の10人分を取り出して表示している。

人物の並びは原著どおりだが、それぞれの顔画像が異なっている。著書執筆後にデータが追加/更新されたようだ。

データの俯瞰

全体の画像データを、1人あたりの枚数ごとに集計してみる。

多くの人について顔画像が1つだけで、George Bush元大統領の顔画像が飛びぬけて多いようだ。

画像枚数ごとに人数を整理してみる。

そこで、顔画像の個数ごとに見た時の人数を確認してみる。

上の配列は0~530の531個の要素の1次元配列で、インデックスが画像枚数、要素の値はそのインデックスの枚数の画像データがある人の数。

顔画像が1枚の人数が4千人以上と、ほとんどの人物については顔画像が1枚しかない。そして画像枚数2枚以降の人物の数が減っていっている。

読み込みパラメーター

resize~画像のサイズ変更(再読み込みされる)

fetch_lfw_people()resize引数で、画像データのサイズを指定できる。

デフォルトは0.5でこの時のサイズは62×47、書籍”Pythonではじめる機械学習”ではresize=0.7を指定していて、この時のサイズは87×65になる。

自分のマシンでは、resize=1.0とするとメモリーの制約なのかエラーになった。

min_faces_per_person~1人あたりの最低画像数

分析の目的によって、1人あたりの画像が複数必要な場合に、最低限登録されている画像数を指定する。

ここで指定した数以上の画像が登録されている人物とその画像データのみ抽出される。

 

numpy.where – インデックスの検索

概要

numpy.where()関数の主な使い方は以下の通り。

  • 配列の要素のうち条件に合う要素のインデックスを取り出す
  • 配列の要素の条件によって、2つの配列のいずれかの要素を割り当てる

基本的な挙動

条件に応じた値の取り出し

以下のように、3項演算子と同じように使える。

True/Falseの代わりに数値でも可。

bool配列によるインデックスの取り出し

bool配列を引数に渡すと、True要素のインデックスの配列を返す。True/Falseの代わりに数値でも可。

bool配列と同じ形の2つの配列を引数に加えると、bool配列の要素のTrue/Falseに応じて、1つ目の配列/2つ目の配列の要素が取り出されて並べられた配列が返される。

上の例では、True(1)が0番目と3番目、False(0)が1番目と2番目にあるので、戻り値の配列の0番目と3番目には2つ目の配列の対応する要素、1番目と2番目には3つ目の配列の対応する要素があてられている。

利用法~条件に合う要素のインデックス

条件に合う要素が1つの場合

where()関数の引数として、配列の要素に関する条件式を与えると、条件に合致する要素のインデックスが得ることができる。

ただし戻り値はタプルで、かつ2次元のタプルの第1要素にndarrayとして納められている点に注意。

そのndarrayは1つの要素を持ち、その値が"FRA"のインデックスになっている。

インデックスの数値を取り出したいときは、このndarrayの要素を取り出す。

条件に合う要素が複数の場合

先の配列には"JPN"が3つ含まれている。このように条件に合致する要素が複数ある場合は、インデックスが配列で返される。

ただしこの場合も戻り値は2次元のタプルで、その第1要素に目的の配列が格納されている。

インデックスの配列を利用する場合は、タプルの先頭要素を取り出す。

条件に応じた配列の要素の選択

配列に対する条件式と、その条件の真偽に応じて選択される配列を引数に与える。文章にするとややこしいので、以下例示。

xの各要素が基数の場合はxから、偶数の場合はyから、同じ位置にある要素が取り出されて結果の配列にセットされる。

以下はもう一つの例。

 

この例では条件、真の場合、偽の場合に同じ配列を使っている。条件の配列の要素が偶数の場合は、その要素の1/2、奇数の場合はその要素から1を引いて1/2にした数値を持つ配列が返される。その結果、同じ数が2つずつ並ぶ配列が得られる。

 

Ruby – クラスの継承について

標準的

親クラスのメソッドは子クラスから利用可能で、子クラス独自のメソッド定義が可能。

親クラスのメソッドの、子クラスでのオーバーライドも普通。

super

親クラスのメソッドの呼び出し

メソッドをオーバーライドするとき、superを使うと親クラスの同じ名前のメソッドを呼び出せる。

以下の例では、子クラスのメソッドが親クラスのメソッドをオーバーライドしつつ、その中で親クラスのメソッドをsuperで呼び出している。その結果、まず親クラスのメソッドが実行され、次に子クラスのメソッドで定義された処理が実行されている。

initialize内でのsuper

initialize()でもsuperを使える。以下の例での流れは次の通り。

  1. 子クラスBirdインスタンスbirdの生成時、Birdのコンストラクターが実行される
  2. Birdのコンストラクターはsuperで親クラスCreatureのコンストラクターを呼び出して実行し、親クラスのプロパティー@num_legsに2をセット
  3. その後子クラスBirdのコンストラクターで子クラスのプロパティー@num_wingsに2をセット
  4. bird.form()は子クラスのform()メソッドを呼び出し
  5. Birdform()メソッドはsuperで親クラスCreatureform()メソッドを呼び出し、@num_legsを表示
  6. その後Birdform()メソッドで@num_wingsを表示

public/protected/private

これらの挙動はC++やJavaにおける挙動と一部で異なる。詳しくはこちら