人工知能してみる

人工知能の中の人が機械学習とか統計とかAI的なことを書き連ねます

Redshiftで条件ごとに集計する

こんにちは。Grahamianです

↓みたいなデータのときに

category | number
1 | 3
1 | 4
1 | 10
2 | 5
2 | 6
2 | 1
3 | 2
3 | 11

categoryごとにnumberを集計したいときがあると思います。あるはずです。私はありました。

普通にやるとcategoryをgroup byしてsumするので↓みたいな結果になります

category | sum(number)
1 | 17
2 | 21
3 | 14

普段はこれで良いのですが、たまに条件ごとに横持ちにしたいときがあります。

cate1 | cate2 | cate3
17 | 21 | 14

こんなときにどうしたら良いのかいろいろと探し回ってしまったのでメモ。

具体的にはsumとcaseメソッドを使います。caseはif文みたいなやつです。こんな風に書きます。

sum(case when category = 1 then number else 0 end) as cate1
sum(case when category = 2 then number else 0 end) as cate2
sum(case when category = 3 then number else 0 end) as cate3

これは何をしているかというと when category = 1 then number else 0 のように指定してやることで category = 1 のときだけ number の値を得ることができます。他のときは else 0 とすることで返り値を0にしています。この結果をsumするので最終的には category = 1 のときのsumが得られるというわけです。
ただし、categoryそれぞれについて横持ちに計算したい場合はそれぞれのcategoryの数だけカラムを作ってやる必要があるのでselect文が長くなってしまう点は注意かもしれません。最も、そのようになってしまう場合はそもそも抽出元や作りたいデータの構造に問題がある可能性もありそうですが...

SQLは簡単だと思ったことが意外と難しかったりしてツライときもありますが、やはり大規模データを高速に処理するためには必須の技術なので頑張って身につけていきたいですね。

複数のnumpy1次元ベクトルの平均を得る

機械学習をしているとベクトル演算をする機会は多いと思うのですが慣れていないとハマる(ハマった)のでメモ。

前に書いたfastTextを使って遊んでいたのですが、文書ベクトルとして単語ごとのベクトルを相加平均したものを得ようと思ったら手間取りました。
fastTextで得られる単語ベクトルは1次元のnumpyベクトルです。何次元になっているかは学習させたときに指定していると思います。で、これを単語の数だけ計算して、それらの相加平均を得る、というのが目標です。つまり複数のベクトルから相加平均ベクトルを得るのが目標です。
調べてみたんですが要素ごとの平均を得るメソッドは無さそうなので順番に足していって最後に割り算します。

import numpy as np

vec_a = np.array([1, 2, 3])
vec_b = np.array([4, 5, 6])
vec_stack = np.vstack((vec_a, vec_b))
# array([[1, 2, 3],
#        [4, 5, 6]])
vec_sum = np.sum(vec_sum, axis=0)  # 列の和
vec_mean = vec_sum / 2  # vstackしたベクトルの数で割る

最後の割り算ですがスカラーで割ることで全要素に演算することができます。全体を倍にするとかでも同じようにできますね。
今回の方法は1次元ベクトルだったので簡単にできましたが2次元以上の高次元ベクトルだとどうやるのがよいのか分からないので調べたいところ。

PythonでMeCabを使って形態素解析する

こんにちは、Grahamianです。
すっごい今更なんですけど Python を使ったときの分かち書きの仕方を書いておこうと思います。日本語の記事もたくさんあるので困ることは無いと思うんですが備忘録ということで。

前準備

Python 自体は3系推奨です。私は3.6を使っています。
PythonMeCab を使うには MeCab 本体のインストールと Python のライブラリのインストールが必要です。
MeCabのインストールはbrewを使うのが一番早いです。いちいちサイトから DL して make install する必要はありません。 brew install mecab

Pythonのライブラリは pip で簡単に入ります。 pip install mecab-python3

これだけで使えるようになっているはずなので確認してみましょう。コンソールから python を起動して import mecab できたら成功です。 気になる人は Neologd(ねおろぐでぃーって読むらしいです) の追加もしてみましょう。 qiita.com

Python分かち書きしてみよう

インストールしたらあとは簡単です。MeCabを初期化してあげて分かち書きしたい文字列を入れてやるだけです。このときPythonライブラリのバグで初期化時に一回空打ちしてやる必要があります。

def init_mecab(dic_path=''):
    arg = ''
    if dic_path:
        arg = '-d ' + dic_path
    m = MeCab.Tagger(arg)
    m.parseToNode('')  # バグ対策で空打ちする
    return m


def tokenize_mecab(text, m):
    mecab_nodes = m.parseToNode(text)
    surfaces = []
    while mecab_nodes:
        surfaces.append(mecab_nodes.surface)  # surfaceで表層形、featureで形態素情報
        mecab_nodes = mecab_nodes.next  # nextを忘れない
    return surfaces

text = 'これはテストです'
m = init_mecab(dic_path)
token = tokenized_mecab(text, m)

処理の流れとしてはこんな感じ

  • 引数を与えてMeCabを初期化する
  • Neologdなど辞書がある場合は dic_path に指定する(無しだと標準を使う)
  • 分かち書きしたい文字列を引数にしてparseToNode()に入れて mecab_nodes を得る
  • nodes を回してmecab_nodes.surfaceで表層形を得る

このときmecab_nodes.nextを忘れると無限ループします(やらかした)
ちなみに単純に分かち書きするだけなら MeCab を初期化するときに-Owakatiにしてm.parseとすると分かち書きが得られます。
形態素特徴量はカンマ "," で分解してやればいろんな情報を得られます。順番は固定なので、例えば名詞だけ使いたいならばカンマでリストに分解して品詞が入っている要素を見てif文で分ければOKです。

MeCab便利なのでみんなも使おう。

Facebook社の自然言語処理ライブラリfastTextを使ってみる

こんには、Grahamianです。
今日は Facebook が公開している自然言語処理ライブラリである fastText を使ってみます。

fastText はこちら!
github.com

インストールは readme に書いてあるとおりなので省略するとして。fastText は何ができるかというとCPUでも高速に自然言語処理を行うことができるのが特徴です。 実際かなり早くて既存のものにくらべると「コレ本当に大丈夫?」と心配になるほど早いです。なぜなのかは実装見ないと分からないのでちょいと不明ですがテストしてみた感じでは使えそうです。

さて、fastText の使い方ですが、大きく分けて2つのことができます。
1つ目は単語のベクトル表現の獲得、2つ目は文書の分類です。

単語のベクトル表現の獲得

自然言語処理をするときは単語の Bag-of-Words(BoW) を使うのが古典的に一般でした。BoW は one hot vector で何かの単語が出現するとその要素が1つ増える、みたいなベクトルのことです。詳しくはググってください。 で、fastText は BoW よりも表現力が豊かな C-BoW と skip-gram を採用しています。Word2Vec でも採用されているアルゴリズムですね。それぞれの詳細はここでは書きませんが現代では一般的な手法で、単語周辺の文脈を盛り込むことができるので単純な BoW に比べるとかなり強力です。
似たようなライブラリとして Word2Vec があります。実はアルゴリズムが少し違い、fastText は subword分割 という手法を採用しているので同じテキストを学習させても結果が異なります。詳しくは検証してくださっている方がいるのでそちらを参照してください。

catindog.hatenablog.com

実際の使い方ですが、readme にあるように簡単で、学習用データを用意してそれをインプットするだけです。学習データは事前に単語を半角スペースで分かち書きしておいてください。

./fasttext skipgram -input data.txt -output model

分かち書きMeCab や JUMAN を使えばよいです。追記: 分かち書きのやり方を簡単にまとめました

grahamian.hatenablog.com

  • skipgram は学習アルゴリズムを指定します。cbow で C-BoW に切り替えられます。
  • -input は学習データのパスを与えます。
  • -output は学習したモデルの出力先を指定します。

文書の分類

自然言語処理をするときは一般にこっちが目的だと思います。文書を自然言語処理してラベリングする、というタスクです。
古典的な手法としては BoW を作って SVM で分けたりトピックモデルを使ったり、最近だと文字列を RNN や LSTM にインプットする方法が一般的です。fastTextは skipgram で得た単語のベクトル表現を使ってニューラルネットワークで処理します。ニューラルネットワークは1層です。シンプルですね。速さの源泉はここかな?
学習のさせ方は簡単で事前に用意した訓練データ train.txt をインプットするだけです。

./fasttext supervised -input train.txt -output model

このとき、訓練データの形式は下記のようになっている必要があります。

# __label__番号, 分かち書き した 文字列
__label__0, hoge hoge hoge
__label__1, huge huge huge
__label__2, hege hege hege

ラベル番号を指定するときに __label__◯ と書く必要があるので注意です。ちなみに header はあってもなくても大丈夫そうです。多分 __label__ が無い行は無視されるんだと思います。 学習結果で得られた model.bin に文書を与えることで文書分類が可能になります。

./fasttext predict-prob model.bin test.txt

このとき k を末尾に指定することで文書から複数のラベルを得られます。デフォルトは k=1 です。predict と predict-prob がありますが predict-prob は確率も表示してくれるだけなので内容に差はないはずです。
ちなみに精度を評価したいときは引数に test を使うことで precision と recall を表示してくれます。

./fasttext test model.bin test.txt

学習するときはいくつか引数からパラメータを設定することができます。詳細はreadmeの最後の載っていますが、ここでは使いそうなものだけ抜粋します。

  • -wordngram: N-gram の長さ
  • -dim: ベクトルの次元
  • -lr: 学習率
  • -epoch: epoch数

とりあえず学習するときは epoch を増やしたいと思うので epoch だけ覚えておけばいいんじゃないですかね?学習データサイズにもよりますが epoch=500 くらいなら数分で終わります。

まとめ

fastText は CPU でも軽快に動作する良い自然言語処理ライブラリです。中身のアルゴリズムも skipgram や C-BoW のように今っぽいものを使っているためかなり精度よく文書分類もできます。
今回は書きませんでしたが Python のラッパーも公式に用意されているので使い勝手良いです。 下手に自然言語処理で文書分類するくらいなら fastText を使ったほうが良いのではないでしょうか?あんまり使われている例が無いですが非常に便利なライブラリだと思います。皆さんも是非使ってみては?

PyCharmでanacondaの仮想環境を使う

こんにちはGrahamianです。
みなさんはPython書くときに何使ってますか?
私はPyCharm使ってます。
www.jetbrains.com

PyCharmはNetBrains社のPythonIDEで見た目もクールですが機能も劣らずクールなイケてるヤツです。
コードは補完されるしコードエラーは警告がでるしPEP8に違反してたらwarningを出してくれます。
最高ですね。

そんな最高なヤツなんですがanacondaなどの仮想環境を使っていたらPyCharm上でも仮想環境が反映して欲しいですよね
例えばPython2系と3系を同時進行で作っているときなんかは環境を反映してくれないとエラーだらけになります。
PyCharmはエラーをコード上で警告してくれるので反映して欲しいですね。
またPyCharm上でRunやDebugしたときに仮想環境で走ってくれると楽です。

さて、そんな機能どこかにあるだろうと思って探したらPyCharmはイケてるヤツなのでその機能がありました。
使い方は簡単です。

Preferences
> Project: hogehoge
> Project Interpreter
> 歯車から"Create Conda env"をクリック

f:id:Grahamian:20171225224402p:plain

あとは適当な名前と欲しいpythonバージョンを指定してやればOKです。
必要なパッケージなんかはpipなりcondaなりでinstallしてやれば勝手に反映されていきます
(反映されなかったらfiles -> Synchronizedで同期します)
これで仮想環境がコードチェックに反映されるしRunやDebugでも仮想環境が走るようになります。

PyCharm最高に便利なのでみんなも使おう。

Go言語でMeCabを使う

こんにちは。 機械学習系はPythonにライブラリが偏っていることもあり圧倒的にPython一択ではあるのですが処理が遅いのが問題です。 Cythonって手もありますがビジネスで使うってなるとRubyとかGoで使えた方がいいよなーと思ってます。 そこでGoの勉強も兼ねて自然言語処理の基本MeCab分かち書きをしてみました。 結構苦労したので書いておきます。

使ったラッパー

Goで使えるMeCabのラッパーはいくつかあるのですが一番簡単に動かせたのが下記のレポジトリのラッパーです。 github.com

インストール

使い方はGitHubのREADMEに書いてあるとおりなのですが、事前にMeCabが入っていれば下記で終わりです。

$ export CGO_LDFLAGS="`mecab-config --libs`"
$ export CGO_CFLAGS="-I`mecab-config --inc-dir`"
$ go get github.com/bluele/mecab-golang

使い方

READMEそのままだと面白くないのでちょいと関数を小分けにしました。 あとNEologdをインストールしてあるので、それも使ってみました。

package main

import (
    "C"
    "strings"
    "github.com/bluele/mecab-golang"
    "fmt"
)

func main(){
    text := "NEologdが入っているのでDMM.comがディーエムエムドットコムって読めます"
    m := generateMeCab()
    defer m.Destroy()
    node := parseToNode(text, m)
    extractSurface(node)
}


func generateMeCab() *mecab.MeCab {
    m, err := mecab.New("-d /usr/local/lib/mecab/dic/mecab-ipadic-neologd")
    if err != nil {
        panic(err)
    }
    return m
}

func parseToNode(text string, m *mecab.MeCab) *mecab.Node {
    tg, err := m.NewTagger()
    if err != nil {
        panic(err)
    }
    lt, err := m.NewLattice(text)
    if err != nil {
        panic(err)
    }
    node := tg.ParseToNode(lt)
    return node
}

func extractSurface(node *mecab.Node){
    for {
        features := strings.Split(node.Feature(), ",")
        if features[0] == "名詞" {
            fmt.Println(fmt.Sprintf("%s %s", node.Surface(), node.Feature()))
        }
        if node.Next() != nil {
            break
        }
    }
}

結果は↓

NEologd 名詞,固有名詞,一般,*,*,*,NEologd,ネオログディー,ネオログディー
DMM.com 名詞,固有名詞,一般,*,*,*,DMM.com,ディーエムエムドットコム,ディーエムエムドットコム
ディーエムエムドットコム 名詞,固有名詞,一般,*,*,*,DMM.com,ディーエムエムドットコム,ディーエムエムドットコム

感想

始めてGo書いたんですが中々仕様に慣れなくて苦労しました。特に型はPythonだと意識しないので大変でしたね。でも型があるとエラーがスグ分かって良いです。
Pythonのゆるさもいいですが、ちゃんと開発するならGoのシッカリした感じはとても良さそうです。 サーバーサイドなんかはGoの方が楽だと思うのでGoでも機械学習できるパッケージ出てほしい。

メルカリがKaggleでコンペ始めたみたい

こんにちはGrahamianです。

昨日からメルカリがKaggleで機械学習コンペティションを始めたみたいです。
mercan.mercari.com

テーマ課題は Mercari SuggestPrice ということでメルカリのプライシング(価格査定)です。
データを見ると説明文、タグ、ブランド、商品状態なんかが説明変数にありました。
自然言語処理も必要で結構難易度高く楽しみがいがありそうです。

いままで謎に包まれていたメルカリのデータが見られるのはとてもたのしいですね。
世界中のデータサイエンティストが挑戦していると思いますが、私も挑戦してみようと思います。