機械学習でマンガのレコメンド その１ まずは何も考えずに分けてみる

#はじめに
検索エンジンでElasticSearchになったおかげで、検索ワードからの作品情報の抽出は比較的容易になってきました。

読んでいる作品のジャンルやらタグの情報を絡めてキーワードからレコメンドなんて手法はElasticSearchでは簡単に実現できるわけです。

でも、うちの場合はマンガのサイトなので、絵の好みやら趣向という要素もあるわけで、私もお金があった頃は内容は二の次で、ジャケ買いなんて普通にやっていたわけです。

で、そういった変に趣向的な部分を何らかの方法で補完できないかという試みです。

試す方法としてはマンガを画像情報として取り込み、それを何らかの方法で分類（クラスタリング：clustering）してあげればいいのは分かります。ではどうすれば良いのか？

**あっているかどうかは全く分からないので、その辺のツッコミは無しにすると、**

とりあえず、興味で人工知能の歴史を勉強して少しかじったので、そちらを踏まえてみれば、
**画像をいわゆる特徴量と呼ばれるもので表現し、それを使ってクラスタリングできれば何とかなるのでは？**
という認識からまずはスタートしようかとおもいます。

#とっかかりをさがす
Google先生に聞いてみると、画像のパターン認識においては**SURF**という局所特徴量をよく利用するということ。これは、画像の輝度の変化や拡大縮小あるいは回転等の処理を行っても不変なポイントを取って特徴量を生成するという物。
それを複数取れることから**局所**特徴量。
一つの画像から一つというわけではないらしい。

ではまずはコレを使い、その特徴量をクラスタリングする際にはこれまたよく利用するらしいk-meansによる分類をさくっと入れてみます。

正直、意味不明なワードが盛りだくさんだけど、ここの方法については必要に応じて調べていけば良いと思う。

#環境構築

ますは環境
OS:Mac
言語：Python2.7
開発環境：PyCharm Community Editioin 2017.1
機械学習ライブラリ：scikit-learn
画像処理ライブラリ：mahotas
数値計算ライブラリ：NumPy

何でこの環境かというと、単純にオンラインカリキュラムで習った仕組みがコレだったからです。
多分、今後必要に応じて変えていくかもしれません。

MacつかっているとデフォルトでPython2.7は行っていたので、それはそのまま。

#流れ
### 学習フェーズ
1.テキストファイルに記載されているURLから画像を読み込む（100～2000件）
2.SURF(mahotas)による局所特徴量の算出
3.k-means(scikit-learn)によるクラスタリングを経てこれを教師無しのデータ(Base特徴量)として利用
### 分類フェーズ
4.別で100件データを読み込む
5.SURFを算出する
6.先に出したBase特徴量からクラスタリング(まずは10分類と25分類)を実行
7.結果を見てみる。

#Code
```ruby:学習フェーズ
# coding:utf-8
import numpy as np
from sklearn import cluster
from sklearn.externals import joblib
import mahotas as mh
from mahotas import surf
from datetime import datetime
import cStringIO
import urllib

datetime_format = "%Y/%m/%d %H:%M:%S"

# パラメータ
feature_category_num = 512


# テキストファイルから画像URLを持ってくる。
list = []

list_file = open("list.txt")

for l in list_file:
    list.append(l.rstrip())

list_file.close()

# 画像処理
base = []

j=0

for url in list:
    file = cStringIO.StringIO(urllib.urlopen(url).read())
    im = mh.imread(file, as_grey=True)
    im = im.astype(np.uint8)
    base.append(surf.surf(im))

concatenated = np.concatenate(base)

del base

# Base特徴量の算出

km = cluster.KMeans(feature_category_num)
km.fit(concatenated)

# Base特徴量の保存
joblib.dump(km, "km-cluster-surf-.pk1")

```

```rb:分類フェーズ
# coding:utf-8
import numpy as np
from sklearn import cluster
from sklearn.externals import joblib
import mahotas as mh
from mahotas import surf

import cStringIO
import urllib

# パラメータ
feature_category_num = 512
picture_category_num = 25

#学習済みのモデル読み込み

km = joblib.load("km-cluster-surf.pk1")


# テキストファイルから画像URLを持ってくる。
list = []

list_file = open("list2.txt")

for l in list_file:
    list.append(l.rstrip())

list_file.close()

# 画像処理
base = []

for url in list:

    title = file[1]
    file = cStringIO.StringIO(urllib.urlopen(url).read())

    im = mh.imread(file, as_grey=True)
    im = im.astype(np.uint8)

    base.append(surf.surf(im))

concatenated = np.concatenate(base)

features = []

# 基本特徴量から画像の分類分け開始

for d in base:
    c = km.predict(d)
    features.append(np.array([np.sum(c==ci) for ci in range(feature_category_num)]))

features=np.array(features)


km = cluster.KMeans(n_clusters=picture_category_num,verbose=1)
km.fit(features)

#結果をファイル吐き出し

list = np.array(list)

for i in range(picture_category_num):
    print('Image category{0}'.format(i))
    challenge = list[km.labels_ == i]
    for c in list:
        print(c)
```

# 結果
結論から書くと、分類は出来ました。

でも、パッと見だめでした。

理由は多分色々あるのでしょうが、その辺は次回考えてみたいと思います。