A Day In The Boy's Life -32ページ目

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

不透明な時代を見抜く「統計思考力」/ディスカヴァー・トゥエンティワン
¥1,680
Amazon.co.jp

 

自分、理系なわけですが高校のときに確率・統計という授業がありまして、これがまた苦手だったんですよ。

ただ、社会人になってから一番ちゃんと勉強しておけばよかったなと後悔したのがこの統計だったりするんですよね。

社会人になって色んな提案資料を書くときにその元データを整理して並べたりするわけですが、よく質問されたのが「これって実績ベースの数値?それとも君の感覚値?」とか言われたりして、やっぱり感覚値だと信憑性が無いわけですから提案が通らないわけです。

 

エンジニアとしてインフラの増強を提案しようとしても、システムの利用者が増えてきているとか、機能数の増加とかそういうことも実績データを分析した結果をきちんと示さないといけないわけで。

そういったときに数値のまとめ方とか効果的に相手にインプットできる図の作り方とかだけでなく、そもそもの原因の分析の仕方というところに着目できるように統計思考力って改めて大事だったんだなとこの本を読んで改めて思ったりしました。

 

ただ、やっぱり本格的な統計の勉強をしようとすると色んな数式や手法が出てきて敬遠しがちなんですが、この本はあまりそういったところに突っ込むというよりは、手法の概要は解説しつつも統計を使って世の中の問題を取り上げていて、副題に「小泉改革派格差を拡大したのか?」っていうことであったり、「若者の読書離れはほんとうか?」といったことが分析されていて、新聞やニュースで取り上げられる話題を鵜呑みにするのではなく、自分なりの分析や検証の大切さが説かれていたりもします。

 

実績ベースの数値を集めることも大事なのですが、それは始めの第一歩なわけで単純にそれを図示して納得しているだけでは場合によっては数値に自分自身がだまされることになったりもします。

その検証をするための手法を知ることで数字の裏にある事実を知ることができますし、逆に世の中にある数字や自分に持ちかけられた提案に対してだまされずに済むんだなと感じたりもします。

そして、統計結果というのは過去のデータを元に並べたものですが、その結果の規則性などから未来を予測するのにも役立ったりもするわけです。

不透明な時代を見抜くという本のタイトルは、統計というものが単に過去の事実を明らかにするだけでなく、その結果からこれからの未来予測に応用ができるんだなということを気づかされたりした本でもあります。

 

 

目次

 

第1章 基礎編 データを見る
 1. 生データを入手する
 2. データを図にする
 3. 専門外のデータはこう読もう

第2章 中級編 データを読む
 1. 基本をおさえる - 平均と分散
 2. 足したらでてくる正規分布
 3. 一を聞いて十を知る - 大数の法則
 4. 分けて考えるべき分布
 5. 因果関係と間違えるな - 相関

第3章 上級編 データを利用する
 1. 未来を予測する
 2. 思考を練磨する - オープンコラボレーション
 3. 自力で考えることの最大の敵

 

 

 

 

 

 

 

サニタイズ言うなーという議論はさておいて、CakePHPにはSanitizeというクラスが存在します。

その名の通り、CakePHPで扱うデータから不正な文字を消してくれたりエスケープしてくれたりSQLセーフなデータとして返してくれたりします。

CakePHPでユーザーから送られてくるリクエストデータなどは取りあえずこれ通しとけってものなので、ぜひ覚えて使いたいクラスとなっています。



Sanitizeクラスの概要と使いかた


使い方も非常にシンプルで以下のようにしてSanitizeクラスの呼び込みとcleanメソッドを使えばデータを綺麗にしてくれます。


<?php
App::uses('Sanitize', 'Utility');

class FooController extends AppController {
    public function index($param) {
        $param = Sanitize::clean($param);
    }
}

サニタイズしたいデータが入った変数をcleanメソッドの引数として渡すだけでその変数を浄化してくれます。

配列にも対応していますので、その場合は再帰的に処理をしてくれます。

cleanメソッドはデータを浄化する一連の処理をしてくれるもので、個別の処理を呼び出すことも可能です。


Sanitizeクラスは、CakePHPのユーティリティとして、以下のパスに定義されています。


/path/to/cakephp/lib/Cake/Utility/Sanitize.php

それほど難しい処理をしていないので、中身を見ればどのような処理をしてくれるか理解できるかと思いますが、clean以外にも下記のメソッドが定義されています。


メソッド 用途
paranoid 半角英数字以外の文字を除去する(第2引数であえて許可したい文字を指定することができる)
escape SQLセーフなデータとして返す(エスケープ処理をする)
html データに含まれるHTMLタグを変換する(htmlentitiesとほぼ同義)。第2引数にremoveオプションを付けるとHTMLタグそのものを削除する
stripWhitespace 不要な改行コードやスペースを削除する
stripImages データに含まれるIMGタグを削除する
stripScripts データに含まれるSCRIPTタグを削除する
stripAll stripWhitespace、stripImages、stripScripts全ての処理を通す
stripTags データから特定のHTMLタグを除去する
clean 一連のサニタイズ処理を行う(オプション指定に付いては後述)

それぞれ、Sanitize::html($param)のように単体で呼び出すこともできます。

cleanメソッドは第2引数のオプションによって細かくサニタイズの処理を指定することができます。
オプションの配列に指定できるキーとそのデフォルト値は、プログラム内で以下のように定義されています。


$options = array_merge(array(
    'connection' => 'default',
    'odd_spaces' => true,
    'remove_html' => false,
    'encode' => true,
    'dollar' => true,
    'carriage' => true,
    'unicode' => true,
    'escape' => true,
    'backslash' => true
), $options);


それぞれのキーの意味は下記の通りです。


オプション 用途
connection DB接続名(app/Config/database.phpで指定している変数名)
odd_spaces 「0xCA」を含むおかしなスペースを標準的な半角スペースに置換する
remove_html HTMLタグを除去するかどうか(encodeオプションをTRUEにしないと動作しない)
encode HTMLタグを変換するかどうか
dollar ドルマークをエスケープするかどうか
carriage キャリッジリターンを削除するかどうか
unicode HTMLエンティティ化してしまったUnicodeの数値文字参照を正しいものに置き換えるかどうか
escape 内部のescapeメソッドを通すかどうか
backslash ユーザが入力したバックスラッシュを信頼できるバックスラッシュに置き換えるかどうか

デフォルトのオプションと照らし合わせて見ればわかりますが、データからHTMLタグの除去(remove_html)以外は全て処理をしてくれます。

一旦、Sanitize::clean()を通してしまい、必要の応じてアプリケーションごとの独自処理としてその他のデータの加工等をしていくのがよさそうです。

仕様の詳細は、マニュアル の方も確認してみてください。


ただ、サニタイズできたからデータが安全になったというわけではなく、やはりロジックの作りによりますので注意は当然必要です。

例えば、clean()によってSQLセーフなデータになったからといって下記のように直接SQLにユーザーから送られてくるパラメータを閉じ込めていいわけではありません。


$id = Sanitize::clean($id);
$data = $this->Foo->query("select name from foo where id = $id");

escape()によって余計な\マークをエスケープ処理してはくれますが、当然それだけでは上記のSQLインジェクションの問題を解決するわけではありません。

バインド変数を使うなど、適切な処理が必要です。


CakePHP内のデータをクリーンな状態にしたいという場合は、不正なデータの除去やHTMLエンティティの変換を自動でやってくれたりもするので、便利に使えるのではないでしょうか。





Apache Solrにはクエリ内に使う際に注意が必要な特殊文字が幾つかあります。


Apache Lucene - Query Parser Syntax


上記マニュアルによれば、下記の文字列が特殊文字に該当するようです。


+ - && || ! ( ) { } [ ] ^ " ~ * ? : \

管理ツール上のQuery機能を使って特殊文字をそのまま入れて検索してみてもSolrがエラーを返してきます。


org.apache.solr.search.SyntaxError: Cannot parse '&&': Encountered " <AND> "&& "" at line 1, column 0.

ということで、この辺の特殊文字の意味とこれらをクエリに使いたい場合の回避方法のまとめです。



Apache Solrの特殊文字


・ 丸括弧()


Solrで丸括弧(小括弧)の文字はグルーピングを意味します。
例えば、「Apache Solrのデモ環境を作ってみる 」で使った郵便番号データの場合、下記のような検索が行えます。


(prefecture:東京) AND 杉並

東京都の中の杉並という地名を探すという検索です。

ちなみに、普通に杉並だけで探すと北海道に杉並町というのがあるらしくそのデータもヒットします。

都道府県に東京を指定するという条件のグルーピングを()で指定しているわけです。


・ 角括弧[]


Solrで角括弧(大括弧)の文字はレンジを意味します。
先ほどの郵便番号データの例で言えば下記のように書くことで郵便番号が指定の範囲にあるデータを検索できます。


zip:[0100000 TO 0200000]

郵便番号が「0100000」から「0200000」の範囲にあるデータを検索するというものです。
細かいところですが開始(0100000)と終了(0200000)の値も範囲に含まれます(以上、以下)。
後述しますが、アスタリスクを使って「zip:01*」というような検索でも似たようなことはできたりするのですが、きちんと範囲を指定したい場合は[]を使った範囲指定のほうがクエリもわかりやすいでしょう。


・ 波括弧{}


Solrで波括弧(中括弧)の文字は角括弧と同じレンジを意味しますが、若干角括弧と仕様が異なります。
角括弧は指定した開始と終了の値も含みますが、波括弧はその値を含みません(より大きい、未満)


zip:{0100000 TO 0200000}

この場合「0100000」と「0200000」の郵便番号を持つデータはヒットしません。


・ アンパサンド(&&)


これはプログラムでよくある構文と同じでAND条件を指定するものです。
先ほどの例の


(prefecture:東京) AND 杉並
(prefecture:東京) && 杉並

上記は同じ意味となります。


・ バーティカルバー(||)


こちらもプログラムの構文と同じでOR条件を指定するものです。


(prefecture:東京) OR 杉並
(prefecture:東京) || 杉並

上記は同じ意味となります。


・ 感嘆符(!)


感嘆符はNOTを意味し、その条件を含まないという動作をします。


(prefecture:東京) !杉並

上記は、東京都で「杉並」という言葉を含まない地名を検索します。


もちろんNOTの言葉のままでも使えます。


(prefecture:東京) NOT 杉並

・ プラス(+)


プラスはその言葉が必ず含まれるという条件になります。


(prefecture:東京) +杉並

上記の場合、必ず「杉並」ということが含まれる条件で検索します。


・ マイナス(-)


マイナスはプラスの逆でその言葉を含まないという条件になります。


(prefecture:東京) -杉並

どうもこの結果はNOTと同じみたいです。


In Solr, what is the difference between the NOT and - (minus) operators? @ stackoverflow


・ ワイルドカード(* ?)


Apache Solrの検索であいまい検索をしたい場合、ワイルドカードを指定することで柔軟な検索ができます。


town:*新宿*

アスタリスクを指定した場合、その文字が含まれる(前方一致や後方一致、中間一致)データを検索します。
例の場合、西新宿や新宿町などがヒットします。

アスタリスクはその間に0個以上の文字があるものにヒットしますが、特定の1文字に限定したければ疑問符を指定します。


town:?新宿

・ あいまい検索(~)


ワイルドカードの指定でもあいまい検索ができるのですが、Solrお任せのあいまい検索も可能です。
単語の最後にチルダを指定すると、その単語に近いキーワードを持つデータを検索してくれます。


town:杉並~

例えば、上記の検索だと「日並」や「杉津」といった地名もヒットします。
これが近いか、といわれると微妙なのですがその言葉に近い(1文字違いなど)言葉を検索してくれるようです。

どこまで使えるか不明なのですが、チルダの値の間に数字を指定してあいまいさの調整ができるようです。


town:杉並~0.8

数字は0から1の間で指定するようでデフォルトは0.5だそうです。


・ キャレット(^)


検索キーワードのあとにキャレットをつけるとその文字を重要性を強調させることができます。
こちらの例はマニュアルから参照しますが、


jakarta^4 apache

というクエリを投げた場合、Apacheよりjakartaという文字が含まれるデータのほうが重視されます。


・ ダブルコーテーション(")


ダブルコーテーションは文章を指定できます。
特にスペースで区切られた文字列を検索したい場合などに有効です。


"jakarta apache" OR "Apache Lucene"

といった感じで、単語単語ではなくその言葉で検索したい場合に指定します。


・ その他


「:」はそもそも条件の区切りに指定する特殊文字になります。
また、「\」は後述もしますが、これらの特殊文字をエスケープするために指定する文字です。



Apache Solrの特殊文字をエスケープする


マニュアルにも記載があるのですが、前述した特殊文字をクエリ内で使いたい場合はエスケープする必要があります。
エスケープは\マークをその特殊文字の前に指定します。


\(1\+1\)\:2

「(1+1):2」という文字を検索したい場合は、上記のようにエスケープしてクエリに投げます。

最後にPHPでこれらSolrの特殊文字をエスケープする処理が下記サイトにまとめられていました。


Escaping Characters in a Solr Query / Solr URL @ Mats Lindh


ただ、これだとstr_replace()使うんじゃなくてaddcslashes()を使ってもいいんじゃないかと思ったりして、そのパターンの例も載せておきます。


static public function escapeSolrValue($string)
{
    $string = addcslashes($string, "\\+-&|!(){}[]^~*?:\";");
    return $string;
}


検索機能を提供する場合、これら特殊文字をユーザーに指定させるというような使い方はさせないと思いますので、しっかりとこの辺の文字を処理しておかないとクエリがエラーとなって問題が起きることになりそうです。