Archive | 8月, 2014

OracleのADD_MONTHSをMySQLのDATE_ADDに置き換えるとき気をつけること このエントリーをはてなブックマークに追加

25 8月

OracleのADD_MONTHSで月を加算する際、加算対象日がその月の最終日だったら、加算後の日も最終日になる。
だから、単純にMySQLに移行しDATE_ADDに置き換えるとき、最終日が意味を持つのか?ということはよく考えなくてはならない。

<Oracle>

ADD_MONTHS('2012-02-29', 1) => 2012-03-31

<MySQL>

DATE_ADD('2012-02-29', INTERVAL 1 MONTH) => 2012-03-29

MySQLのほうが素直な気がする。
なので、MySQLでも同様に最終日だったら1月加算しても最終日にする、という動きにしたい場合、ストアドファンクションなりプログラム側でうまいこと値を渡してやるなりしないと大変だね。というはなしです。

コサイン類似度を求める このエントリーをはてなブックマークに追加

25 8月

この記事は、前のブログから加筆修正して転載しています。

研究でコサイン類似度を求めなくてはならなくなりました。
コサイン類似度ってなんだ??どうやるんだ??まったく検討つかない!というレベルから、計算式はわかった!とりあえず値を出す関数まで作ろう!というレベルに達したのでメモしておきます。
あんまりコサイン類似度自体の本質はわかってないかもしれませんが、遅延評価勉強法というかんじです。

コサイン類似度とは

2つのデータが似ているかどうかを、文字列が似てるのを調べる分野では距離などで換算します。
ちょっとよくわからないかもしれませんが、ぴいことぴいたろう君の類似度は、なんらかの測定器を使うと60mくらいの距離です。ぴいこと弟の類似度は、その測定器では30mくらいの距離でした。弟とぴいこは近いので、ぴいたろう君より似ています。

みたいなかんじ。

コサイン類似度ではベクトルというものを使います。ベクトルってなんだ!!わけわかんねーこと言うな!!!と思っていましたが、先輩や同期の面々から教わって、なんとなくわかってきました。。。

2つのベクトルの類似度を測るには

ここに、2つのベクトルがあります。
ベクトルっていうとわかりづらいです。「配列」にします。
配列m1、m2には図のように、Apple Banana Orangeの項目が入っています。
これからやりたいのは、m1とm2がどれくらい似ているか(似ている要素を持っているか)です。

計算式を考えないで見てみると、m1とm2にはどちらもAppleが入っているので、それなりに似てそうです。

m1とm2にある要素を展開します。2つの配列には3種類の項目がありました。

各配列にある要素には1のフラグを立てて、ない要素には0を立てます。すると、m1はAppleとBanana、m2はAppleとOrangeにフラグが立ちます。

計算式は上記のような、分数の計算になります。

分子は二つの配列のANDを取ったときの1の個数です。今回でいうとm1とm2どちらにもAppleがあるので、ANDで1になる項目が1つです。

分母はm1の1の個数(AppleとBanana分の2)のルートかける、m2の個数(AppleとOrange分の2)です。

そうすると、1/(ルート2*ルート2) = 0.5となります。

どうなると似るのか

1に近づくと似ています。1だと全く同じ要素を持つものです。0だと全然違う要素のものです。このしきい値はそのシステムによって違うようですが、0.5〜0.7以上あればだいたい似てると思います。たぶん。

function cosSim($w1 = null, $w2 = null){
  $w = array_values(array_unique(array_merge($w1, $w2)));
  for($i=0; $i $m1[$i] = false;
    $m2[$i] = false;
  }

  //$wが$m1にあるか調べる
  foreach($w1 as $wi){
    $key = array_search($wi, $w);
    if($key !== FALSE)
      $m1[$key] = true;
  }

  //$wが$m2にあるか調べる
  foreach($w2 as $wi){
    $key = array_search($wi, $w);
    if($key !== FALSE)
      $m2[$key] = true;
  }

  //Cos類似度用計算
  //分子
  $and = 0;
  for($i=0; $i if($m1[$i] && $m2[$i]){
    $and++;
  }

  //分母
  $m1and = 0;
  foreach($m1 as $m){
    if($m)
      $m1and++;
  }
  $m2and = 0;
  foreach($m2 as $m){
    if($m)
      $m2and++;
  }

  $m1and = sqrt($m1and);
  $m2and = sqrt($m2and);

  if($and == 0 || $m1and == 0 || $m2and == 0){
    return 0;
  } else {
    return $and/($m1and * $m2and);
  }
}

$m1 = array('Apple', 'Banana'); //文章Aのベクトル
$m2 = array('Apple', 'Orange'); //文章Bのベクトル
echo cosSim($m1, $m2); //0.5

symfony1.4でCSV出力 このエントリーをはてなブックマークに追加

24 8月

symfony1.4でCSV出力がしたいとき、CakePHPのヘルパーをsymfony用に少し書き換えて使ったのでメモ。
CakePHPのヘルパはここで発見。
http://blog.asial.co.jp/721

(1) CSV Helper (PHP 5)のダウンロード

http://bakery.cakephp.org/articles/view/csv-helper-php5 からソースをコピーしてPROJECT/lib/helper/CsvHelper.phpとして保存。
lib/helper以下にあるヘルパは勝手に読み込まれる。べんりだなー。もしもhelperというディレクトリがなければ自分で作る。mkdir!

(2) Helperクラスのダウンロード

CSVHelperはそのままだと動かない。extendsしてるクラスがないから。
CakePHPをダウンロードしてきて、CAKEPHP/cake/libs/view/helper.php をCsvHelper.phpと同じディレクトリに保存。
また、26行目付近のApp::import(‘Core’, ‘Overloadable’); を削除。
それから、35行目付近のclass Helper exetnds…は、継承を削除して class Helper { だけにする。

要は、CsvHelperに必要な親クラスはincludeするけど、親クラスが継承しているOverloadableはいらないので削除、というかんじ。
ここまでで、lib/helperにはCsvHelper.phpとHelper.csvがあることになる。

(3) CsvHelperの修正

function render は、$this->outputをreturn しているけど、これを削除。
echo $outputとして、renderは出力をするメソッドにしてしまう。

(4) アクションにconfigを作る

通常だと、表示にlayoutが読み込まれるので余計なHTMLタグが入ってしまうので、CSVダウンロードの処理をするときだけはレイアウトを読み込まない設定にしたい。
apps/APPLICATION/module/MODULE/config に、view.ymlを作成。
configディレクトリがないときは作る。view.ymlでは以下のようにする。

downloadSuccess:
  has_layout: false
    http_metas:
      cache-control: public
      pragma: public

has_layoutでレイアウトを読み込まない設定。true/falseでの設定のよう。
metaはたぶん、キャッシュコントロール的なかんじ。CsvHelperのほうでヘッダを出力するので、あんまり考えなくていいと思う。

(5) actions.class.phpにメソッドを追加

ここでは、executeDownloadなどにしておく。

public function executeDownload(sfWebRequest $request)
{
  $this->csv = new CsvHelper();
  $this->headers = array('ユーザID', '名前', '性別', '誕生日', '作成日', '更新日');
  $this->fields = array('id', 'name', 'gender', 'birthday', 'created_at', 'updated_at');
  $this->filename = 'profile.csv';
  $this->profiles = Doctrine_Core::getTable('Profile')->findAll();
}

headers でCSVに表示するヘッダを作成。
fieldsでは、利用するモデルの項目名(なんていうか、$profile->get(‘id’)とかで使う、idっていうこと)。

(6) downloadSuccess.phpの作成

templateに先ほどのメソッドのビューを作成。

$csv->setFilename($filename);

foreach($headers as $h){
  $header[] = $h;
}
$csv->addRow($header);

foreach($profiles as $profile){
  $row = array();
  foreach($fields as $f){
    $row[] = $profile->get($f);
  }
  $csv->addRow($row);
}

$csv->render(true, 'sjis-win', 'utf-8');