scikit-learnを使ってMovieLensの映画評価データをクラスタリングしてみた

2014-11-07
このエントリーをはてなブックマークに追加

使ったのはMovieLens 100k
「100,000 ratings from 1000 users on 1700 movies.」
だそうです。

from sklearn.cluster import KMeans


def main():

    _items = []
    _f = open('./rating.csv' )
    _lines = _f.readlines()

    for _line in _lines:
        _items.append(_line.split(','))

    _f.close()

    km = KMeans(init='k-means++')
    km.fit(_items)

    print(km.labels_)


if __name__ == '__main__':
    main()

すげえ簡単。。。

CSVは1行が1人分で全部の映画のレーティング情報(0が観てない、評価は1から5)が入っています。1000ユーザーが1700本の映画を評価(未鑑賞含む)してます。

だいたいこんな感じ。

5,3,4,3,3,5,4,1,5,3,2,5,5,5,5,5,3,4,,,,,,,,
4,0,0,0,0,0,0,0,0,2,0,0,4,4,0,0,0,0,,,,,,,,

得られる結果は

[0 1 4 4 3 2 6 3 4 6 3 7 6 2 1 5 1 6 4 7 1 3 3 7,,,,,,,

インデックス2番のユーザーさんと3番のユーザーさんは好きな映画が似る傾向にありそうですね。

Python 3.4.2、scikit-learn 0.15.2 で試しました。

scikit-learnを使ってテキスト文書をクラスタリングしてみた

2014-11-05
このエントリーをはてなブックマークに追加

Clustering text documents using k-means (K平均法を使ってテキスト文書をクラスタリングする)というそのまんまのサンプルがあったので写経して最低限だけ削りだしてみた。

K平均法とかTF-IDFとか潜在意味解析の説明は割愛。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
from sklearn.decomposition import TruncatedSVD
from sklearn.preprocessing import Normalizer


def main():

    _items = [
        'わたし まけ まし た わ',
        'わたし まけ まし た わ',
        'わたし まけ まし た わ',
        'わたし まけ まし た わ',
        'となり の きゃく は よく かき くう きゃく だ',
        'にわ には にわ なかにわ には にわ にわとり が いる',
        'バカ と テスト と 召喚獣',
        '俺 の 妹 が こんな に 可愛い わけ が ない'
    ]

    vectorizer = TfidfVectorizer(
        use_idf=True
    )
    X = vectorizer.fit_transform(_items)

    lsa = TruncatedSVD(10)
    X = lsa.fit_transform(X)
    X = Normalizer(copy=False).fit_transform(X)

    km = KMeans(
        init='k-means++',
    )
    km.fit(X)

    print(km.labels_)


if __name__ == '__main__':
    main()

テキストは分かち書きされてる状態(空白区切りになってます)でドキュメント単位でリストにいれておく。これを元データとしてTfidfVectorizerに突っ込みます。ここでドキュメントがベクトル化されます。

で、潜在意味解析を通した上でK平均法でクラスタリング。至って単純。
km.labels_を出力すると

[1 1 1 1 0 2 4 3]

こんな感じで出力されるのですが、これは「データセットのインデックス0,1,2,3は1番クラスタ、インデックス4は0番クラスタ、、、」ということです。これを使って元データをグルーピングしておきます。

すっごい簡単。使い方はこれであってる、と思う。たぶん。あ、ドキュメント数は少なくても1,000以上ないときれいにクラスタリングされなそうだし、テキストももっと長くないと納得のいく結果は出力されにくいんじゃないかと。

自分のツイートを使ったり青空文庫を使ったりで気軽に試せそうです。

Python 3.4.2、scikit-learn==0.15.2 で動かしました。

昨日Mahoutの記事書いたばっかりなのにね。

PythonでS3にファイルを保存する

2014-09-30
このエントリーをはてなブックマークに追加

ユーザーがアップロードした画像とかをS3に保存したいときに使うメモ。

AWSのAccessKeyとSecretAccessKeyはAWSコンソールにログインして、「右上のアカウント名 > Security Credentials」 で生成しておきます。

pip install boto

S3に投げ込むのはboto(読みはボートー、でいいんだろうか。。。)だけあればOK。Python2.7でもPython3.4でもpipでインストールできました。

$ pip freeze
boto==2.32.1

投げ込むコードは以下

from boto.s3.connection import S3Connection
from boto.s3.key import Key


def main():
    print('start')
    _s3 = S3Connection(
        'AccessKey',
        'SecretAccessKey',
    )
    _bucket = _s3.get_bucket('バケット名称')
    _key = Key(_bucket)
    _key.set_metadata('Content-Type', 'image/jpeg')
    _key.key = 'img.jpg'
    _key.set_contents_from_filename('./img.jpg')

if __name__=='__main__':
        main()

非常に簡単。

set_metadataは無くてもJpegファイルの場合は問題ないっぽいけど、Content-Typeによっては問題が出たりするのかもしれない。

バケット側のパーミッションとかポリシーとかはまた別の話ということで。

PythonでYAMLを読んでみた

2014-09-19
このエントリーをはてなブックマークに追加

今更感満載なんですけど、最近何度か続いてyaml触ったもんでメモとして。

使うのはPyYAMLです。

pip install pyyaml

Python2でもPython3でも上記で入るはずです。2.7と3.4で試しました。

host: HOSTNAME
port: PORT
dbname: DBNAME
user: USERNAME
passwd: PASSWD

こんなYAMLをDBの接続情報として用意しておいたとして、

import yaml

def main():
    _var = open('./settings.yaml').read()
    _yaml = yaml.load(_var)

    print(_yaml['host'])


if __name__ == "__main__":
    main()

読んだYAMLは辞書になってますので、_yaml[キー]で触れます。
ちょっとした設定ファイルとかには便利ですね。

Python3.4でMySQLに接続してDjangoでも使ってみる

2014-09-18
このエントリーをはてなブックマークに追加

MySQLドライバはどれを使えばいいのかはっきりわからない、というのがPython3に本格的に踏み込めないでいた一番の理由がだったわけですが、MySQL Connector/PythonがPython3をサポートしててDjangoでも使えてマルチバイト文字もちゃんと通るっぽかったので試してみました。

unzip mysql-connector-python-1.2.3.zip
cd mysql-connector-python-1.2.3
python setup.py install
pip freeze

インストールはこれだけ。
DB-API 2.0準拠らしいので触り方も変わらずに安心。こういうのがPythonのいいところじゃないかと。

import mysql.connector


def main():

    _conn = mysql.connector.connect(
            user='USERNAME',
            password='PASSWD',
            host='127.0.0.1',
            database='DBNAME')

    _cur = _conn.cursor()
    _cur.execute("select * from app_comment;")
    for _row in _cur.fetchall():
        print(_row[0])

    _cur.close()
    _conn.close()

if __name__ == '__main__':
    main()

DjangoからMySQLを使うときはこれで。

DATABASES = {
    'default': {
        'NAME': 'DBNAME',
        'ENGINE': 'mysql.connector.django',
        'USER': 'USERNAME',
        'PASSWORD': 'PASSWD',
    }
}

マルチバイト文字使ってもinsert,update、selectひと通り問題なさ気だったので試しになんか書いてみようと思いました。

あ、Djangoは1.7で試してます。

CentOSにPython3.4をインストールして仮想環境を作るところまでやってみた

2014-09-17
このエントリーをはてなブックマークに追加

「Python3やんなきゃね」が季節の挨拶じみてきたので久々に重い腰をあげてみました。もう3.4かいな。
Djangoも1.7とか。

sudo wget https://www.python.org/ftp/python/3.4.1/Python-3.4.1.tgz
sudo tar zxfv Python-3.4.1.tgz
cd Python-3.4.1
sudo ./configure --enable-shared
sudo make & make install

sudo vi /etc/ld.so.conf
/usr/local/lib
ldconfig

ここまででPython3.4が起動するようになりました。
試しに

# /usr/local/bin/python3.4

Python 3.4.1 (default, Sep 16 2014, 12:43:31)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

おぉ、できたできた。
ついでに仮想環境も。
mkvirtualenvじゃなくてPython3っぽくvenvを使ってみます。

/usr/local/bin/python3.4 -m venv demo34
source demo34/bin/activate
pip freeze
deactivate

easy_installとの決別です。
気になるのはMySQLのドライバかなー。

MeCabのPythonバインディングをインストールする

2014-08-17
このエントリーをはてなブックマークに追加

CentOSにMeCabをインストールする方法の続きなんですけど、MeCab入れたらPythonから叩くよね、ってことでバインディングもインストールしておきます。

wget https://mecab.googlecode.com/files/mecab-python-0.996.tar.gz
tar zxfv mecab-python-0.996.tar.gz
cd mecab-python-0.996
python setup.py build
python setup.py install

これだけだとimportしたときにエラーが出ます。

ImportError: libmecab.so.2: cannot open shared object file: No such file or directory

そこで、

sudo vi /etc/ld.so.conf

/usr/local/lib #この行を追加

sudo ldconfig

やっとimportできるようになります。

$ python
Python 2.7.7 (default, Jun 4 2014, 17:11:14)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type “help”, “copyright”, “credits” or “license” for more information.
>>> import MeCab

Tags: ,

PythonでRedisに書き出して有効期限も設定する

2014-07-26
このエントリーをはてなブックマークに追加

Redisは頻繁に使ってます。データベースとして使うって言うよりテンポラリキャッシュとして使うケースのほうが多いです。

import redis

_redis = redis.Redis(
    host=REDIS_HOST,
    port=REDIS_PORT,
    db=REDIS_DB)

_redis.set('key', 'value')
_redis.expire('key', 90)

有効期限の設定方法がわかりにくいというかピンとこなくて悩んだのでメモ。「キーに対してバリューと有効期限を設定する」っていうよりも「キーにバリューを設定、キーに有効期限を設定」っていう2段階、ってイメージでしょうか。

expireで指定する値は秒数。上記で90秒間有効です。

Python 2.7.5、redis 2.9.1(本体じゃなくてパッケージのほう)

Tags: ,

Pythonのsetter、getter

2014-07-10
このエントリーをはてなブックマークに追加

ハセテツはこう書いてますよというメモ。

# -*- encoding: utf-8 -*-


class SampleClass(object):

    def __init__(self):
        self._params = None

    @property
    def params(self):
        return self._params

    @params.setter
    def params(self, v):
        self._params = v


if __name__ == '__main__':
    _obj = SampleClass()
    _obj.params = {'foo': 'bar'}
    print _obj.params
Tags:

PythonのフレームワークBottleでcookieの読み書き

2014-05-17
このエントリーをはてなブックマークに追加

Pythonの軽量フレームワークBottleを試してみた」の続き。
せっかく調べたので忘れないようにやったことを書いておこう。

# -*- encoding: utf-8 -*-

from bottle import (
    run,
    default_app,
    route,
    request,
    response
)


@route('/cookie_test')
def cookie_test():

    # cookie取得
    _stamp = request.get_cookie("_stamp")
    if _stamp is None:
        response.set_cookie(
            "_stamp",
            "some value",
            max_age=3888000)

    return 'Hello.'

if __name__ == "__main__":
    run(host="localhost", port=8080, debug=True, reloader=True)
else:
    application = default_app()

get_cookieで読み込み、set_cookieで書き込みます。

max_ageは秒数で、上記の例だとcookieの有効期限は45日後です。指定しないとブラウザを閉じた時にcookieは消えます。

Tags: ,