機械学習とか全くわからないけどKaggleに初挑戦してみた

今日は#pyhack & Kaggleに初参加してみました。

Kaggleとは?

Kaggleは企業や研究者がデータを投稿し、世界中の統計家やデータ分析家がその最適モデルを競い合う、予測モデリング及び分析手法関連プラットフォーム及びその運営会社である。

bywikipedia

とりあえず今日の目標は、機械学習とか全くわからないけど、とりあえず何か提出してみよう、という感じです。

挑戦するのはDigit Recognizerという、手書きの数字の画像から数字を判別するチュートリアルコンテストです。

f:id:cocodrips:20150411182745p:plain:w400

データは実際には画像ではなくて、28*28の0~255の数字で用意されています。

まずは適当にやってみる

誰かの記事なんかに沿ってやってくのは難しいしよくわからないし、ワクワクしないので、とりあえず最初に自分で考えたしょぼい方法でどこまでできるかやってみます。

機械学習(教師あり)は一切知識がないので、何をしていいかさっぱりわかりません。

とりあえず小さいデータをつくる

データがでかすぎてテスト的に使うのに時間が掛かり過ぎるので、小さめのデータを作ってみました。

head -n 1000 data/train.csv > data/simple.csv

いろいろ試行するときは、こっちの小さいの使ったり使わなかったりします。

各々の数字の各々のピクセルの平均の値をとってみる

トレーニングデータをつかって、 各々の数字の各々のピクセルの平均の値をとるプログラムを書いてみました。

小さくする前のデータを使い、平均の値によって適当に文字を割り当てて、平均の画像がどんな感じになっているかアスキーアートで見てみます。

def chara(v):
    if v < 50:
        return ' '
    if 50 <= v < 100:
        return '.'
    if 100 <= v < 160:
        return 'o'
    return '@'

0はこんな感じ

                          . o o .                      
                    . . o o o o o o .                  
                  . . o o o o o @ @ @ o . .            
                . . . o o @ @ @ @ @ @ @ o o .          
                . . o o @ @ @ @ @ @ @ @ @ o . .        
              . . o o o o o o o . o o o o o o .        
              . . o o o o o o .   . o o o o o . .      
            . . o o o o o . .       . o o o @ o .      
            . o o o o o . .         . o o @ @ o        
            o o @ o . .               . o @ @ o        
          . o o @ o . .               . o @ @ .        
          o o @ @ o .               . . o @ o .        
          o o @ @ .                 . o o o o .        
          o @ @ o .               . . o o o . .        
          o @ @ @ . .         . o o o o . o .          
          . @ @ @ o o .     . o o o @ o o o .          
            o @ @ @ @ @ o o @ @ @ @ o o o .            
            . o @ @ @ @ @ @ @ @ @ o o . .              
              . o @ @ @ @ @ @ o o o .                  
                  . o o o o o .                        
                                                       
                                                     
                                                       

5とかちょっと微妙な感じですね。

                                                       
                      . . . . .   . . .                
                  . o o o o o o o o o o .              
                . o o o o o @ @ o o o o o .            
                . o o o o o o o o o o o o . .          
              . o o @ o o . . . . . . . . . . . .      
              . o @ o . . . . . . . . o o o o . .      
              o o @ o     . . . . . . . . . . . .      
            . o @ @ .     . . .                        
            . o @ o o . o o o o o o . .                
            . o @ @ o @ @ @ @ @ o o o o . .            
            . o @ @ @ @ @ @ o o o o o o o o            
              . o @ @ @ o . . . . . o o o o .          
                . . . . . . .   . . . . o o .          
                  . . . . . . . o . .   . o .          
                  . . . . . . o o o .   . o .          
              . . o o . . . . o o o . . . o o          
                . o o o o o . o o o . . o o .          
                    . o o o @ @ @ @ o o o .            
                      . o @ @ @ @ o . o . .            
                      . . o o o o .                    
                  . . . . .                            
                                                       
                                                       

他の数字もここで見れます。

とにかくまずは提出してみる

この平均のデータを使って、テストデータがどれくらい正解できるのか試してみます。

差の合計値が1番小さいやつにする

テストデータと平均データの差の合計値が1番小さいやつが答えなんじゃない?ってことでとりあえず初提出。

submitファイルはこんな感じのcsvファイル。

ImageId,Label
1,6
2,0
3,9
4,9
5,1
6,7
7,0

Score: 0.544 50%強です。なかなか微妙ですね。

テストデータと平均データの差の二乗の合計値が1番小さいやつにする

最小二乗法とかよく聞くしとりあえず差があるほうが悪いと判断されるよう二乗の値をとってみることに。

Score: 0.676

良いとは言えないけど10%以上精度が向上したっぽいです。

答えのあるデータを、トレーニング用とテスト用にわける

答えのわかっているデータをトレーニング用とテスト用にわけて、 トレーニング用の方で分類器を作り、テスト用のほうがどれだけ正解するか正答率をみてみます。

トレーニング:テスト = 3:7 で分けるとかどこかで聞いたことがあるんですけど、 まずは42000件あるデータのうち、各数字につき100件をトレーニングデータとして使うことにしました。(ただそれがプログラム的に書くのが簡単だったからです。)

プログラム: ここ

トレーニング用とテスト用にわけてみた結果、精度はこんな感じでした。

数 正答率
––––––––
0  85 %
1  96 %
2  75 %
3  76 %
4  68 %
5  63 %
6  83 %
7  84 %
8  72 %
9  71 %

4,5,8,9あたりの精度が特に悪いなーということがわかりました。

そろそろまじめに機械学習っぽいことを考える

だいたい満足したので、自己流はここまでにしてそろそろまじめに機械学習っぽいことしてみたいです。

今日はこの辺を参考にすることに。

とりあえず平均とか言わずにもっとおしゃれな特徴を学習していきたいです。

名前がカッコいいのでSVMを使ってみたいなーと思いました。 SVMが何なのかは未だによくわからないですが、とりあえず二値分類をしてくれるやつらしいです。

今回は使ったのことのあるscikit-learnの、LinearSVCというのを使ってみました。 sklearn.svm.LinearSVC

数字NをNだと判定した確率。 (数字N以外をNと判定してもok)

0 100%
1 90%
2 74%
3 71%
4 64%
5 53%
6 83%
7 80%
8 32%
9 72%

8が異常に低い!

コード:digit-recognizer/svm-traning.py

0~9を判別するには多クラスSVM分類?とかを使ったほうがいいのかなあという感じです。

今日はここまで。

まとめ

  • kaggleの提出するまでの過程を学んだ
  • 機械学習のすごさを実感するために、自分で考えた方法で正答率を出してみた
  • ランキング上位には100%判別している人とかいてすごい
  • 機械学習(教師あり)をまじめに勉強する意欲が湧いた