読者です 読者をやめる 読者になる 読者になる

$yuzu->log();

技術ネタなど。

【機械学習】サポートベクターマシン(SVM)を使用して、乳癌かどうか調べてみる

機械学習 SVM PHP

サポートベクターマシン(SVM)について

サポートベクターマシン(以下SVM)とは、教師ありの機械学習の一手法です。 SVMは、現在知られている機械学習の手法の中で、認識性能が優れた学習モデルの一つです。 その理由は、未学習データに対して高い識別性能を得るための工夫があるためです。 学習サンプルから「マージン最大化」という基準で線形入力素子を利用して 2 クラスのパターン識別器を構成します。

SVMの具体的な例

○と●という2種類のデータがあるとして、そのデータをどのように分けるかを考えたとき、境界線を引くことが考えられます。

下記のグラフを見てみましょう。

  • H3は二つのクラスのいくつかの点を正しく分類していません。
  • H1とH2は二つのクラスのいくつかの点を正しく分類しています。
  • H2がH1よりもっと大きいマージンを持って分類することを確認することができます。

f:id:yuzurus:20161010221723p:plain

wikipediaより。

この識別平面からもっとも近い既知パターンとの距離(マージン)を最大になるように決定するのが最良の結果となります。 これがSVMの「マージン最大化」という方針です。 SVMを使えば未知のパターンに対しても正しく分類できる確率が高いと言われてます。

PHPSVMを使えるようにする

CentOSでインストールする場合はこんな感じです。

sudo yum install libsvm libsvm-devel
sudo pecl install svm-0.1.9

php.iniに下記を加える

extension=svm.so

これで準備ができました。

SVMを使って乳がんかどうかを調べる

スタンフォード大学機械学習コースでも同じような例があったので試してみます。

www.coursera.org

乳がんであることは色んな要因があると考えられます。

今回はSVMのテストなので、2次元ベクトルとして、年齢としこりの大きさで考えてみましょう。

イメージが下記のグラフです。

X軸がしこりの大きさ、Y軸が年齢、赤が悪性、青が良性です。 f:id:yuzurus:20161010225737p:plain

実際のサンプルデータがないので便宜的に右上が悪性、左下が良性としてプログラムで作成してしまいます。

<?php
$data = [];
for ($i = 0;$i < 100;$i++) {
  // 良性
  $size = mt_rand(0,4);
  $age = mt_rand(0,40);
  $data[] = [0,$size,$age];

  // 悪性
  $size = mt_rand(5, 10);
  $age = mt_rand(50, 80);
  $data[] = [1,$size,$age];
}

// データを学習してモデルを生成
$svm = new SVM();
$model = $svm->train($data);

// 良性テスト
$pre = $model->predict([1,30]);
echo $pre. "\n";

// 悪性テスト
$pre = $model->predict([8,70]);
echo $pre. "\n";

実行してみます。

$ php svm-test.php
0
1

うまくいきましたね!実際は乳房の腫瘍の塊の厚み、腫瘍の細胞のサイズの均一性、腫瘍の細胞の形状の均一性などなど、様々な要素が絡み合いますが、基本的な考え方は一緒です。 実際のデータを元に算出してみたいですね。

【機械学習】ニューラルネットワークを利用して自分の好みの女性を学習させる

PHP アルゴリズム 機械学習

ニューラルネットワークとは?

脳内には多数のニューロンと呼ばれる神経細胞があります。それぞれのニューロンは、他のニューロンから信号を受け付け,他のニューロンへ信号を受け渡しています。脳は、この信号の流れによって、様々な情報処理を行っています。 この仕組みをコンピュータ内に実現しようとしたものがニューラルネットワークです。

たとえば、入力層に学習させたいデータの特徴を入力します。 すると、入力層、中間層、出力層を通って、結果が出力されます。

http://cdn-ak.f.st-hatena.com/images/fotolife/u/ura_ra/20111026/20111026235506.png

ニューロンのモデル化

ニューロンの基本的な働きは信号の入力と出力だけです。 ここで重要になるのが、入力された信号をそのまま出力するのではなく一定の閾値を超えたときのみ出力(発火)されます。

ニューロンにはそれぞれ信号伝達の効率がバラバラです。そこでそれぞれの入力に対し結合荷重を設定します。 そしてその重み付きの入力の総和が各ニューロンに設定されている閾値を超えたとき、発火したとして、他ニューロンに信号を送ります。 コンピュータ上での実現のため、簡単化のため0を信号が無い、1を信号がある状態とします。

数式で表してみます。

 \displaystyle

\( i \)番目のニューロンからの入力信号を\( x_i \)、それぞれの荷重を\( w_i \)とすると他ニューロンからの入力信号の総和は、

{ \displaystyle
 \sum_{i=1}^{n} X_iW_i
}

となります。 入力信号を受けっとったニューロンは、その入力値が一定の閾値\( θ \)を超えたときに発火するので、次のように表せます。

{ \displaystyle
 y = f_k(\sum_{i=1}^{n} X_iW_i - θ)
}

ここで関数 \( f_k \)は入力値に対し発火するかしないかなので1か0を返却する関数です。このような関数は、ステップ関数またはヘビサイド関数と呼ばれています。関数は次のようになります。

{ \displaystyle
 y = f_k(x) = 1 or 0
}       

これがニューロンモデルです。

FANNについて

PHPニューラルネットワークを扱うためにはFANNを使う必要があります。

Fast Artificial Neural Network Library (FANN)

FANNはC言語で書かれていて主に次の特徴があります。

  • 誤差逆伝播法(BackProp)による学習を主にサポート
  • 動作がかなり高速
  • 最短3ステップで簡単に機械学習(リソース作成、学習、実行)
  • 英語ドキュメントは豊富である

MacOSXへFANNをインストール

$ brew install homebrew/science/fann
$ pecl install fann

php.iniに下記を追記

extension=fann.so

確認

php -i |grep fann

では次にFANNを使って自分の好みの女性を学習させてみましょう

自分の好みの女性かそうでないかを分類する

学習データを集める

まず教師データとして、大量の女性の画像が必要になります。 集め方はここでは触れませんが、僕は某ユニコーン企業のサイトから拝借させていただきました。

それぞれlikeとnopeというフォルダを用意し、手動で分類してください。それぞれ200枚ぐらい用意してみると良いかも。 更にテスト用にlike-testとnope-testというフォルダも用意しテスト用の画像としてそこにも20枚ぐらいいれておいてください。

学習データの作成

画像の分類はカラーヒストグラムを作成し、ニューラルネットワークで判定したいと思います。 カラーヒストグラムについては下記の記事を参照してください。

yuzurus.hatenablog.jp

カラーヒストグラムを作成するプログラム(histogram-ib.inc.php)

<?php
function make_histogram($path, $debug = true) {
  if ($debug) {
    echo "histogram: $path\n";
  }
  $im_big = imagecreatefromjpeg($path);
  $sx_big = imagesx($im_big);
  $sy_big = imagesy($im_big);
  $sx = 256;
  $sy = 192;
  $im = imagecreatetruecolor($sx, $sy);
  imagecopyresampled($im, $im_big, 0, 0, 0, 0, $sx, $sy, $sx_big, $sy_big);
  $his = array_fill(0, 64, 0);
  for ($y = 0;$y < $sy;$y++) {
    for ($x = 0;$x < $sx;$x++) {
      $rgb = imagecolorat($im, $x, $y);
      $no = rgb2no($rgb);
      $his[$no]++;
    }
  }

  $pixels = $sx * $sy;
  for ($i = 0; $i < 64; $i++) {
    $his[$i] = $his[$i] / $pixels;
  }
  imagedestroy($im_big);
  imagedestroy($im);
  return $his;
}

function rgb2no($rgb) {
  $r = ($rgb >> 16) & 0xFF;
  $g = ($rgb >> 8) & 0xFF;
  $b = $rgb & 0xFF;
  $rn = floor($r / 64);
  $gn = floor($g / 64);
  $bn = floor($b / 64);
  return 16 * $rn + 4 * $gn + $bn;
}

ヒストグラムデータからFANNの学習用データを生成するプログラム(gen-data.php)

<?php
require_once 'histogram-lib.inc.php';

$favorite_type = [
  "like" => "1 0",
  "nope" => "0 1",
];

gen_data("", 40);
gen_data("-test", 14);

echo "ok\n";

function gen_data($dir_type, $count) {
  $data = '';
  $types = ['like', 'nope'];
  $cnt = 0;
  foreach ($types as $type) {
    $type_list = glob("{$type}{$dir_type}/*jpg");
    shuffle($type_list);
    $type_list = array_slice($type_list, 0, $count);
    $cnt += count($type_list);
    $data .= gen_fann_data($type_list, $type);
  }
  $data = "$cnt 64 2\n" . $data;
  file_put_contents("type{$dir_type}.dat", $data);
}

function gen_fann_data($list, $type) {
  global $favorite_type;
  $out = $favorite_type[$type];
  $data = '';
  foreach ($list as $f) {
    $his = make_histogram($f);
    $data .= implode(' ', $his) . "\n";
    $data .= $out . "\n";
  }
  return $data;
}

これを実行するとtype.datとtype-test.datというデータが生成されます。

$ php gen-data.php
histogram: like/0228.jpg
histogram: like/0060.jpg
histogram: like/0295.jpg
*
*
*
ok

生成された学習用データを実際にFANNで学習して、テストデータで判定してみます(train.php)

<?php
$num_layers = 3;
$num_input = 64;
$num_neuros_hidden = 3;
$num_output = 2;
$ann = fann_create_standard(
  $num_layers, $num_input,
  $num_neuros_hidden, $num_output
);

if (!$ann) {
  die("FANNの初期化に失敗");
}

fann_set_activation_function_hidden($ann, FANN_SIGMOID_SYMMETRIC);
fann_set_activation_function_output($ann, FANN_SIGMOID_SYMMETRIC);

echo "学習します\n";
$desired_error = 0.0001;
$max_epochs = 500000;
$epochs_between_reports = 1000;
fann_train_on_file($ann, "type.dat", $max_epochs, $epochs_between_reports, $desired_error);
fann_save($ann, 'type.net');

echo "テストします\n";
$favorite_data = [
  "1 0" => 'like',
  "0 1" => 'nope',
];
$favorite_index = ["like", "nope"];
$testdata = explode("\n", file_get_contents("type-test.dat"));
array_shift($testdata);
$total = $ok = 0;
while ($testdata) {
  $s = array_shift($testdata);
  if ($s == "") continue;
  $data = explode(" ", $s);
  $label = array_shift($testdata);
  $label_desc = $favorite_data[$label];
  $r = fann_run($ann, $data);
  $v = $favorite_index[array_max_index($r)];
  echo "- $label_desc = $v\n";
  if ($label_desc == $v) $ok++;
  $total++;
}

$pre = floor($ok / $total * 100);
echo "結果: $ok/$total = $pre%\n";

function array_max_index($a) {
  $mv = -1;
  $mi = -1;
  foreach ($a as $i => $v) {
    if ($mv < $v) {
      $mv = $v;
      $mi = $i;
    }
  }
  return $mi;
}

実行してみましょう

$ php train.php
学習します
テストします
- like = like
- like = like
- like = like
- like = like
*
*
*
結果: 21/28 = 75%

ってことでわりとまずまずな数値が出たのではないでしょうか?

簡単にWEBのインターフェイスも作ってみました。

f:id:yuzurus:20161006004626p:plain

f:id:yuzurus:20161006004638p:plain

なるほどな結果になりましたね!

カラーヒストグラムを利用した類似画像検索システムの作り方

類似画像検索 アルゴリズム

最近Machine Learning(機械学習)を勉強することが多いのですが、そこに引きづられて類似画像検索について勉強する機会があったので、その内容についてまとめます。

画像検索ではクエリにテキストを入れてテキストに関連した画像を検索します。 一方、類似画像検索ではクエリに画像を与えて似た画像を検索します。 検索クエリに画像をアップロードすることが特徴です。

この分野をCBIR(Content-based image retrieval)と呼び1992年から研究されているそうです。

検索手法は沢山ありますが、今回は、画像の色に着目して、類似画像検索システムを作ってみたいと思います。

カラーヒストグラムとは

色は色の三原色である、赤緑青、所謂RGBで表せます。 そのRGBを使って、画像中にRGBの各色が何ピクセルあるか数えて作成した棒グラフです。 たとえば、

f:id:yuzurus:20161001172211j:plain

のカラーヒストグラムを作成すると

f:id:yuzurus:20161001172228p:plain

このように描写できます。

 \displaystyle

画像を減色して計算する

上記のグラフを見て気づいた方がいるかもしれませんが、減色して計算しています。

通常色はRGBの各8ビット、つまり256通りですので、表示できる色数は\( 256^{3} \) で約17,000,000通りあります。 これはあまりにも多すぎて計算量が膨大になってしまいます。 ですので、RGBを各2ビット、つまり4通り、\( 4^{3}=64 \) 通りまで減色。64次元のベクトルで計算できるようにしています。

画像の類似度の算出

画像Aのカラー値\( i \) のピクセルの個数を\( AH_i \)、2枚目の画像のカラー値\( i \) のピクセルの個数を\( BH_i \)とします。各カラー値\( min(AH_i,BH_i) \) についてを求めます。 \( min(A,B) \) とは\( A \)と\( B \)で小さい方を返す関数です。 これを全部のカラー値で足すと

{ \displaystyle
D = \sum_{i=0}^{63} min(AH_i,BH_i)
}

となり\( D \) をヒストグラムインタセクションいいます。

この値が大きくなればなるほど、2つの画像は類似しているということになります。

PHPによるサンプルプログラム

RGBから64色に減色するプログラム

<?php 
/**
 * ヒストグラムのビンを計算
 * @param $rgb
 * @return int
 */
function rgb2no($rgb) {
  $r = ($rgb >> 16) & 0xFF;
  $g = ($rgb >> 8) & 0xFF;
  $b = $rgb & 0xFF;
  $rn = floor($r / 64);
  $gn = floor($g / 64);
  $bn = floor($b / 64);
  return 16 * $rn + 4 * $gn + $bn;
}

カラーヒストグラム作成プログラム

/**
 * 画像からカラーヒストグラムを作成(csv形式)
 * @param $path 画像保存先
 * @param bool $cache
 * @return array
 */
function makeHistogram($path, $cache = TRUE) {
  // 結果を保存するファイル
  $csvfile = preg_replace('/\.(jpg|jpeg)$/', '-his.csv', $path);
  if ($cache) { // ヒストグラムのキャッシュを使うか
    if (file_exists($csvfile)) {
      $s = file_get_contents($csvfile);
      return explode(",", $s);
    }
  }
  $im = imagecreatefromjpeg($path);
  $sx = imagesx($im);
  $sy = imagesy($im);
  // ピクセルを数える
  $his = array_fill(0, 64, 0);
  for ($y = 0; $y < $sy; $y++) {
    for ($x = 0; $x < $sx; $x++) {
      $rgb = imagecolorat($im, $x, $y);
      $no = rgb2no($rgb);
      $his[$no]++;
    }
  }
  // 8bitに正規化
  $pixels = $sx * $sy;
  for ($i = 0; $i < 64; $i++) {
    $his[$i] = floor(256 * $his[$i] / $pixels);
  }
  file_put_contents($csvfile, implode(",", $his));
  return $his;
}

2つの画像から類似度を調べる

// $AHは画像Aのカラーヒストグラム、$BHは画像Bのカラーヒストグラム
$sum = 0;
for ($i = 0;$i < 64;$i++) {
  $sum += $min($AH[$i], $BH[$i]);
}

これらのロジックに基いて、予め用意しておいた画像を検索対象にして、検索してみましょう。 すると下記のような結果が得られます。 左上から順に類似度が高いものになります。

f:id:yuzurus:20161001183900p:plain

類似画像が検索できましたね!

参考文献

類似画像検索システムを作ろう - 人工知能に関する断創録
http://web.tuat.ac.jp/~s-hotta/gke/ch4/index.html

【機械学習】ナイーブベイズ分類アルゴリズムを利用した迷惑メールフィルタ実装例

PHP ベイジアンフィルタ ナイーブベイズ分類 Composer 機械学習 アルゴリズム

ナイーブベイズ分類器とは?

ベイズの定理を利用した分類手法です。 ベイズの定理について知りたい方は下記の参照下さい。

yuzurus.hatenablog.jp

 \displaystyle

ナイーブベイズ分類は文章をカテゴリ分けする際に、テキスト中の単語の出現率を調べます。 その際、その文章をどのカテゴリに分類するのが相応しいか調べるのです。

判定の際に \( P(B|A) \) は1つの確率ではなく、複数のカテゴリ中で、どのカテゴリになる確率が一番高いかを表す情報になります。 この時 \( P(A) \) は入力テキストが与えられる確率となります。

しかし、どのカテゴリを判定するにしても同じ入力になるため、同じ値と考えて良いこととします。するとナイーブベイズ分類は次のように表せます。

\( P(B|A) = P(B)P(A|B) \)

この時の \( P(B) \) は事前確率で、各カテゴリに分類される確率を表しています。

これは単なるベイズ分類器です。ナイーブベイズ分類器は確率分布 \(P(A|B) \) をシンプルな分布に限定します。

入力テキストAに関して、単語の集合と考えて、多次元変数と考えると

\( A={a1,a2,a3,…,aN} \)

と表せます。すると \(P(A|B) \) は

{ \displaystyle
P(A|B) = \prod_{i=1}^{N} P(a_i|B)
}

となります。

ナイーブベイズ分類を利用して迷惑メールフィルタを作ってみる

ナイーブベイズ分類アルゴリズムを内包したライブラリ「fieg/bayes」を利用して迷惑メールフィルタを作ってみましょう!
単語分類のためにMecabのインストールとphp-mecabのインストールが必要になります。

composerを利用してfieg/bayesというライブラリをインストールします

composer require fieg/bayes

単語分類器 MecabTokenizer.php

<?php
require_once 'vendor/autoload.php';
require_once 'mecab.inc.php';

use Fieg\Bayes\TokenizerInterface;

class MecabTokenizer implements TokenizerInterface {
  public function tokenize($str) {
    return mecab_parse_simple($str);
  }
}

単語分類器を利用したプログラムbayes-filter.php

<?php
require_once 'vendor/autoload.php';
require_once 'MecabTokenizer.php';

use Fieg\Bayes\Classifier;

// 単語分類器と分類器の生成
$tokenizer = new MecabTokenizer();
$classifier = new Classifier($tokenizer);

// 学習
$classifier->train('迷惑メール', '年収1000万を確実に稼ぐ方法');
$classifier->train('迷惑メール', '【FX】1年で資産120倍!このスゴイ講義が無料。ちょっと信じられません・・・');
$classifier->train('迷惑メール', '月利40%のモニター募集');
$classifier->train('迷惑メール', '【年利174%】99.9%の確率で含み損が利益になるプロ技');
$classifier->train('迷惑メール', '【2日で1億1800万円】英国EU離脱騒動で稼いだオトコの正体');
$classifier->train('迷惑メールでない', '暮らしを便利にするマストアイテムを65%OFF');
$classifier->train('迷惑メールでない', 'アンケートにご回答いただくと30ポイントプレゼント【楽天】(2016/09/17)');
$classifier->train('迷惑メールでない', '【お急ぎください!】9月連休出発高速バス予約ラストチャンス!');
$classifier->train('迷惑メールでない', 'Amazon.co.jpからポイント付与についてお知らせ');
$classifier->train('迷惑メールでない', '【住信SBIネット銀行】定額自動振込サービス振込受付のお知らせ  ');

$s = '【衝撃映像】『日給1100万円確定』の瞬間を捉えた!';
$r1 = $classifier->classify($s);
echo "--- $s\n";
print_r($r1);

$s = '【早割】特大和洋中おせち♪国産南高梅の木箱ギフトなど【楽天】(2016/09/18)';
$r2 = $classifier->classify($s);
echo "--- $s\n";
print_r($r2);

これを実行してみると

php bayes-filter.php
--- 【衝撃映像】『日給1100万円確定』の瞬間を捉えた!
Array
(
    [迷惑メール] => 0.9
    [迷惑メールでない] => 0.1
)
--- 【早割】特大和洋中おせち♪国産南高梅の木箱ギフトなど【楽天】(2016/09/18)
Array
(
    [迷惑メールでない] => 0.99980407523511
    [迷惑メール] => 0.00019592476489028
)

簡単なテストですが、ちゃんと分類されてますね!

ソースはここにおいておきます。

github.com

【機械学習】ベイジアンフィルタ

機械学習 ベイジアンフィルタ アルゴリズム

ベイジアンフィルタとは

ベイジアンフィルタ (Bayesian Filter)とはナイーブベイズ分類を応用したもので、対象となるデータを解析・学習し分類する為のフィルタです。 現状では迷惑メールフィルタやスパム投稿などの判定で利用されています。

ベイズの定理

ベイズの定理(Bayes' theorem)とは条件付き確率に関して成り立つ定理で、トーマス・ベイズによって示されたものです。

 \displaystyle
  P(B|A) = \frac{P(A|B)P(B)}{P(A)}
  • \( (A) \)とは\( A \)が起きる確率
  • \( P(B) \)とは、\( B \)が起きる確率(事前確率)
  • \( P(A|B) \)とは、\( B \)のあとで\( A \)が起きる確率(条件付き確率、尤度)
  • \( P(B|A) \)とは、\( A \)のあとで\( B \)が起きる確率(条件付き確率、事後確率)

条件付き確率とは

条件付き確率とは、ある事象Aが起こる条件下で、別の事象Bが起こる確率のことです。これを

\( P(B|A) \)

と表します。 たとえば

  • \( P(雨) \) = 雨の降る確率
  • \( P(事故) \) = 交通事故の発生確率

とすると雨が降っていて、交通事故が発生する確率は

\( P(事故|雨) \)

と表せます。

次はベイズの定理を使って実践的な問題を解いてみましょう。

ベイズの定理から見る膵臓ガン発見の検査方法

www.huffingtonpost.jp

15歳の少年が膵臓がん発見の画期的な方法を開発したことがについて、この検査方法が統計的にどのような意味をもつのかをベイズの定理を使って計算してみます。

  • \( p1 \) = 被験者が陽性になる確率
  • \( p2 \) = 被験者が陰性になる確率
  • \( p3 \) = 被験者ががん患者である確率
  • \( X \) = 被検査者はガンであるという事象
  • \( Y\) = 検査の結果、被検査者はガンであると示す事象

とすると

  • \( p1 = P(X|Y) \)
  • \( p2 = P(X^{c}|Y^{c}) \)
  • \( p3 = P(Y) \)

と表せる。 \( X^{c} \) や \( Y^{c} \) はそれぞれの補事象。

ここで \( P(X) \) は検査結果が真陽性となる確率と偽の陰性となる確率を足したものなので、

\( P(X) = P(Y)P(X|Y) + P(Y^{c})P(X|Y^{c}) \)

さらに、

\( P(X|Y^{c}) = 1-P(X^{c}|Y^{c}) \)

のため、

ベイズの定理より

 {
\begin{align} 
  P(Y|X) &= \frac{P(X|Y)P(Y)}{P(X)} \\
&=  \frac{P(X|Y)P(Y)}{P(Y)P(X|Y) + P(Y^{c})P(X|Y^{c})} \\
&=  \frac{P(X|Y)P(Y)}{P(Y)P(X|Y) + P(Y^{c})(1-P(X^{c}|Y^{c}))} \\
&= \frac{p1p3}{p1p3+(1-p3)(1-p2)} 
      \end{align}
}

となります。

実際の数値を当てはめてみましょう。 2008年の膵臓がんの患者数は29,584人、総人口は1億2769万2000人なので

\( p3 = 0.23168 * 10^{-3} \)

また簡単のために p1, p2をひとまとめに誤検出の確率と仮定してp1=p2=qおくと、\( P(Y|X) \) が70%となるようなqは

\( q=0.99990 \)

となります。 このことから、99.99%の精度をもつ検出方法でも実際には30%も見逃してしまうということがわかります。

さらに、「400倍の精度で検査できる」という部分を誤検出の確率が400分の1になったという意味だと解釈して、

\( q' = 1- \frac{(1-q)}{400} \)

とおいてがん患者が検査の結果実際に陽性だと判定される確率を再度計算すると

\( P(Y|X) = 0.99892 \)

となります。これは30%見逃していたのが1%まで減ったということです。 実に素晴らしい結果ですね。

次回はベイズの定理を使ったナイーブベイズ分類器のお話です。

yuzurus.hatenablog.jp

ベイズ統計学入門

ベイズ統計学入門

SEOの初心者にはおすすめな本「10年使えるSEOの基本」を読んだ感想

SEO 読んだ本

SEOの専門家におすすめされて、読んだ本。とても良かったので紹介します。

「10年使えるSEOの基本」の感想

SEOの専門家である土居くんと、SEOに詳しくないすずちゃんが対話形式で例を交えながらSEOの話をする本です。
特にSEOのテクニック的なところは出てこず、「検索エンジンとは何か」、「Googleが目指す世界」から、SEOを紐解く至極真っ当な本です。
陳腐化する小手先なテクニックよりは、本質的なところにフォーカスをあてているため、「10年つかえる」の看板に偽りはないと思いました。
フルカラーで優しい言葉でかけあいしてるので、初心者にはすごく読みやすい本なんじゃないかと思います。 以下メモ。

検索にヒットするようになるには?

  • どういう言葉で検索されているのかを知る
  • 検索エンジンが正しく理解できるようにサイトを作る
  • みんなが検索を通じて知りたいことをコンテンツ化してサイトに掲載しておく
  • 継続的にサイトにリンクを集めていく

検索キーワードの見つけ方

  • どんなキーワードで検索しているのか?
  • キーワードボリュームは感覚ではなく必ず調べるようにする

検索キーワードをサイトに反映させる

  • titleタグにキーワードを含める
  • meta descriptionにキーワードを含める
  • 最初の見出しにはキーワードを含める
  • ページ内のテキスト要素にキーワードを含め、なるべくページ上部に出現させる
  • 「見てほしい人が使いそうな言葉」をなるべく選んで使う
  • 自然な文章で表記し、不自然な繰り返しを用いない

良いタイトル付け

  • 大事なキーワードを含めて、なんのページなのかが具体的にわかるように
  • 異なる内容のページに、同じタイトルを複数つけない ← プログラムで書いた場合はやりがち
  • 文字数は30文字以内
  • 重要なキーワードはなるべく前半に

meta descriptionの重要さ

  • 検索エンジンのランキングには関係ない
  • クリック率には関わってくる
  • 大事なキーワードを含めて、なんのページなのか具体的にわかるように
  • 異なる内容のページに、同じdescriptionを書かない
  • 50〜100文字以内

SEOとは

  • 検索エンジンで上位表示」ではなく「検索を通じて知りたい情報を見つけられるようにする」技術
  • 「自分が言いたいこと」ではなく「みんなが知りたいこと」を書く
  • コンテンツは量よりも品質を重視。

コンテンツ・マーケティングの正のスパイラル

  1. 良いコンテンツを作る
  2. 多くの人に見てもらえ、一定のリンクを獲得
  3. リンクを通じて更に見てもらえる機会が増える
  4. SEOも強くなって検索での露出が増える
  5. さらにリンクが増える
  6. 2に戻る

10年つかえるSEOの基本

10年つかえるSEOの基本

ポケモンGo!のアンテナサイトを作った。技術仕様やアプリケーション仕様などなど

Vagrant PHP Nginx Composer CentOS CakePHP 作ったもの

酔った勢いで、ポケモンGo!のアンテナサイトを作ってみました。

pokemongo-mtm.xyz

こういうのって、スピードが大事ですよね。検索ボリュームが多い時にリリースできたのでよかったです。 1時間ぐらいでさくっと。

使用した技術

サーバーはGMOクラウドのVPSのメモリ2GB、月額1,280円のプラン。

composer.json

 "require": {
        "cakephp/cakephp": "2.*",
        "cakephp/debug_kit": "*",
        "intervention/image": "dev-master",
        "intervention/imagecache" : "*",
        "cakedc/migrations": "*",
        "nanapi/cakephp-redis": "*"
    },

アプリケーションの仕様

  • hourlyで指定したRSSをクロール。
  • サムネイルの取得は対象サイトのog:image、なかったら、RSSのdescriptionに含まれている、imgタグから取得。
  • PVのカウントはRedisで貯めてって、デイリーバッチで、MariaDBに貯めこむ。

悲しかった事。

CakeDCのマイグレーションプラグインを使ったのですが、マイグレーションプラグインがStringクラスを使っていて、PHP7から「型と同じクラス名」を作れないという制約があるため、exception error が発生するという悲しみ。
なので手動でDB作りました。

今後やりたいこと

広告周りは適当にimobileのクリック広告しか貼ってないですが、ユーザの志向にあったものを採用していきたいです。

ポケモンGo!をやってみて。

電池の減り早い! モバイルバッテリー必須ですね。
軽くて大容量なおすすめモバイルバッテリー↓