/sbin/mount.vboxsf: mounting failed with the error

Vagrantでvbguestを使って、VirtualBoxのアドオンを更新していて、VagrantとVirutalBoxを更新したら以下のように怒られるようになった…。

Failed to mount folders in Linux guest. This is usually because
the "vboxsf" file system is not available. Please verify that
the guest additions are properly installed in the guest and
can work properly. The command attempted was:
mount -t vboxsf -o uid=`id -u vagrant`,gid=`getent group vagrant | cut -d: -f3` vagrant /vagrant
mount -t vboxsf -o uid=`id -u vagrant`,gid=`id -g vagrant` vagrant /vagrant
The error output from the last command was:
/sbin/mount.vboxsf: mounting failed with the error: No such device

こんなときは、~/.vagrant.d/Vagrantfileを以下のように更新して、auto_updateを無効にする必要があるらしい。

Vagrant.configure("2") do |config|
  config.vbguest.auto_update = false
end

として、vagrant upしたら解決した。

WikipediaをElasticsearchに取り込む

どこまで継続できるかというのはあるけど、Elasticsearchを使って機械学習的なことをちょっとまとめていこうかと。
まず、いろいろとやるためには適用するデータが必要になるけど、ここではWikipediaのデータを使ってあれこれしてみようかな。
MovieLensとか、IRISとか、定番データは世の中に存在していると思うけど、あれはあれできれいな感じだからHelloWorld的なことをしたければ、それらを使ってみるのが良いかと思う。
Elasticsearchをここからダウンロードして、展開した後にkuromojiをインストールしておく。

$ wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.4.2.tar.gz
$ tar zxvf elasticsearch-1.4.2.tar.gz
$ cd elasticsearch-1.4.2/
$ bin/plugin -install elasticsearch/elasticsearch-analysis-kuromoji/2.4.1

今回は、WikipediaのデータをElasticsearchに入れるところまでを試してみる。
Wikipediaのデータを投入するのには、WikipediaのRiverを利用する。
WikipediaのRiverは

$ bin/plugin -install elasticsearch/elasticsearch-river-wikipedia/2.4.1

でElasticsearch 1.4系のものをインストールできる。
インストール後、Elasticsearchを起動する。

$ ./bin/elasticsearch &

次にWikipediaのデータをアーカイブされているところから取得する(ダウンロードしたものを置くところはどこでも良いです)。

$ mkdir wikipedia
$ cd wikipedia/
$ wget http://dumps.wikimedia.org/jawiki/latest/jawiki-latest-pages-articles.xml.bz2

ここまで準備できれば、あとはRiverを実行するだけだが、事前に登録先のインデックスを作成しておく。

$ curl -XPUT 'http://localhost:9200/jawiki-pages-articles/' -d '
{
  "settings": {
    "index":{
      "refresh_interval": "60s",
      "number_of_replicas":"0",
      "number_of_shards":"5"
    },
    "analysis":{
      "tokenizer":{
        "ja_tokenizer":{
          "type":"kuromoji_tokenizer",
          "mode":"normal",
          "discard_punctuation":"false",
          "user_dictionary":"userdict_ja.txt"
        }
      },
      "analyzer":{
        "ja_analyzer":{
          "type":"custom",
          "tokenizer":"ja_tokenizer"
        }
      }
    }
  },
  "mappings":{
    "page":{
      "_all": {
        "enabled": false
      },
      "properties":{
        "category":{
          "type":"string",
          "index":"not_analyzed"
        },
        "disambiguation":{
          "type":"boolean"
        },
        "link":{
          "type":"string",
          "index":"not_analyzed"
        },
        "redirect":{
          "type":"boolean"
        },
        "redirect_page":{
          "type":"string",
          "index":"not_analyzed",
          "copy_to":"redirect_page_text"
        },
        "redirect_page_text":{
          "type":"string",
          "analyzer":"ja_analyzer"
        },
        "special":{
          "type":"boolean"
        },
        "stub":{
          "type":"boolean"
        },
        "text":{
          "type":"string",
          "analyzer":"ja_analyzer"
        },
        "title":{
          "type":"string",
          "index":"not_analyzed",
          "copy_to":"title_text"
        },
        "title_text":{
          "type":"string",
          "analyzer":"ja_analyzer"
        }
      }
    }
  }
}'

$ES_HOME/config/userdict_ja.txtは空ではだめなので、kuromojiの辞書を適当に作成してください。
kuromojiの設定は後日変えるかもしれませんが、とりあえず、そんな感じにしておきます。
titleプロパティとかはanalyzeしない方が良さそうな場合もありそうなので、形態素解析用にはcopy_toで別プロパティを作成しておくことにします。
あとは、

$ curl -XPUT localhost:9200/_river/jawiki-pages-articles/_meta -d '
{
    "type":"wikipedia",
    "wikipedia":{
        "url":"file:$ES_HOME/wikipedia/jawiki-latest-pages-articles.xml.bz2"
    },
    "index":{
        "bulk_size":1000
    }
}'

を実行してしばらく待つとデータができあがりです($ES_HOMEを適当に置き換えてください)。
latestを持ってきているので、実行したときによって違うかと思いますが、190万ドキュメントで7Gくらいの量のようです。
次回以降でこれをつかっていろいろと試せれば良いかな。

sklearnのVectorizer

sklearnのVectorizerは文を渡して、それをベクトル化してくれるものですが、sklearnに含まれているCountVectorizerとTfidfVectorizer試してみる。
まずは、適当な文の配列を用意する。

$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> corpus = [
... 'aaa bbb ccc ddd eee',
... 'aaa bbb ccc ddd',
... 'aaa bbb ccc',
... 'aaa bbb ddd eee',
... 'aaa ddd eee'
... ]

まずは、単語数を数えて、それをベクトルに変換する。

>>> from sklearn.feature_extraction.text import CountVectorizer
>>> count_vect = CountVectorizer(min_df=1)

という感じで、CountVectorizerを生成する。
そして、先ほど作った文の配列をまるっと渡す。

>>> X_count = count_vect.fit_transform(corpus)

X_countとして結果が返ってきますが、中身を確認すると、

>>> print X_count.todense()
[[1 1 1 1 1]
 [1 1 1 1 0]
 [1 1 1 0 0]
 [1 1 0 1 1]
 [1 0 0 1 1]]

という感じで、単語数を数えて配列のベクトルが得られる。
ベクトルがどの単語に対応しているかは、get_feature_namesで得られる。

>>> count_vect.get_feature_names()
[u'aaa', u'bbb', u'ccc', u'ddd', u'eee']
>>> count_vect.vocabulary_.get('ddd')
3
>>> count_vect.vocabulary_.get('bbb')
1

新規の文をベクトルにする場合は

>>> count_vect.transform(['aaa ccc eee']).toarray()
array([[1, 0, 1, 0, 1]])

とすればOK。
TFIDFを用いて、同じようにベクトルを生成するためにはTfidfVectorizerを利用する。

>>> from sklearn.feature_extraction.text import TfidfVectorizer
>>> tfidf_vect = TfidfVectorizer()
>>> X_tfidf = tfidf_vect.fit_transform(corpus)
>>> print X_tfidf.todense()
[[ 0.3592933   0.42480021  0.5049742   0.42480021  0.5049742 ]
 [ 0.41626575  0.49215996  0.58504698  0.49215996  0.        ]
 [ 0.47818893  0.56537308  0.67207785  0.          0.        ]
 [ 0.41626575  0.49215996  0.          0.49215996  0.58504698]
 [ 0.47818893  0.          0.          0.56537308  0.67207785]]
>>> tfidf_vect.get_feature_names()
[u'aaa', u'bbb', u'ccc', u'ddd', u'eee']
>>> tfidf_vect.vocabulary_.get('ddd')
3
>>> tfidf_vect.vocabulary_.get('bbb')
1
>>> tfidf_vect.transform(['aaa ccc eee']).toarray()
array([[ 0.44943642,  0.        ,  0.6316672 ,  0.        ,  0.6316672 ]])