プログラミングを上達させたい

情報学専攻の大学院→放送局でCMの営業など@大阪→舞台俳優&IT営業@東京

KaggleのFacial Keypoints Detectionの入り口まで(R言語にて)

久々にKaggleをやりました。
やったとは言ってもガチのコンペではないやつをチュートリアルに基づきながら進めていっただけです。

やったのはこちらの問題。
www.kaggle.com

顔の画像データが入力して与えられるので、鼻の頭の位置や目の各ポイントの位置など特徴点の位置を推定しましょう、というものです。


注意点としては
・入力データにおいて、欠損値が結構ある
・変な画像もある(画像の端っこに人が写っているとか)
という感じでしょうか。

かなり久々だったので、R用のチュートリアルを見ながら進めました。
そして案の上、書いている通りにやっていても動かない部分があり・・・
しょぼい推定を提出するまで何とか進めていった結果を一旦まとめます。

上記チュートリアルのページで対話型でやっている部分&そのまま写して上手くいったところは省いていきます。

まず、データの取得について。
僕の場合はRのプログラムと同じフォルダにトレーニングデータやテストデータを入れたので、

train.file <- paste0('training.csv')
test.file <- paste0('test.csv')

でOKでした。

そして一旦途中の"data.Rd"を作成するまでのプログラムがこちらです。

# 並列処理パッケージ導入
# これを入れてるから、CRANサーバーの位置を入力必要(TOKYOでよいかと)
# reshape2パッケージが入れられない、使わないことにする
install.packages('doMC')
library(doMC)
registerDoMC()

# トレーニングデータ読み込み
train.file <- paste0('training.csv')
test.file <- paste0('test.csv')

# データフレームの作成
d.train <- read.csv(train.file, stringsAsFactors=F)

# 画像のデータはim.trainで管理
# d.trainの画像部分は消しとく
im.train      <- d.train$Image
d.train$Image <- NULL

# imのデータ形式が文字列になっているのをintの配列に変換
im.train <- foreach(im = im.train, .combine=rbind) %dopar% {
	as.integer(unlist(strsplit(im, " ")))
}

# ここまでトレーニングデータの処理、ここからテストデータの処理
# テストデータの読み込みと、画像データと位置データの切り分け(トレーニングと一緒)
d.test  <- read.csv(test.file, stringsAsFactors=F)
im.test <- foreach(im = d.test$Image, .combine=rbind) %dopar% {
    as.integer(unlist(strsplit(im, " ")))
}
d.test$Image <- NULL


# データを"data.Rd"というファイル名で出力
# 今後はload('data.Rd')というコマンドでデータ利用可能
save(d.train, im.train, d.test, im.test, file='data.Rd')

# 終了の合図
print("all up")


ここから、超簡単な推定をしていきます。
今回やる推定は「テストデータを見て、各特徴点の平均位置を割り出し、すべてそれで回答する」です。なんとざっくりした推定か。

出力形式があっているかなどを確かめる上でテスト提出はとても大切なので、とりあえず雑推定やってみます。
ただここからが結構つまずいてしまい・・・
詰まったポイントは
・melt関数が使えなかった(ライブラリーを上手く取得できず)
・チュートリアルの回答形式が今受け付けている回答形式と全く違った(困るよ)
の2点でした。
melt関数は回答形式をサンプル提出scvから取得して回答を作成するという関数っぽいです。どうやら。
これらが上手くいかないので、
・回答形式が何かを自分で見つけ
・melt関数の代わりに自分で(愚直に)回答を作るプログラムを作る
という流れでなんとか提出まで辿りつきました。

回答の形式について、チュートリアルでは'submissionFileFormat.csv'というファイルを参考にして

RowId,ImageId,FeatureName,Location
1,1,left_eye_center_x,数値
2,1,left_eye_center_y,数値
....

という形式だ、みたいなことが書いてあります。
ただ、そもそも'submissionFileFormat.csv'がダウンロードできません。困るよ。

色々やいやい考えた結果、今はこうではなく、数値を入れるだけの形式である

RowId,Location
1,37.651234191934
2,30.3061015140798
3,37.976942571727
4,59.1593394374039
5,37.9447523279677
6,73.3304779831461
.....

形のようです。チュートリアルが書き換わってないから、'SampleSubmission.csv'(←ダウンロードできる)を見ただけじゃそんなの分からないよ・・・

このような出力にするため、予測データのテーブルを全て巡回するようなプログラムを書きました。
そして、'SampleSubmission.csv'を上書きしていきます。

p           <- matrix(data=colMeans(d.train, na.rm=T), nrow=nrow(d.test), ncol=ncol(d.train), byrow=T)
colnames(p) <- names(d.train)
predictions <- data.frame(ImageId = 1:nrow(d.test), p)

# 入力例を参考に回答を作成
# predictions の全項目を巡回するようなプログラムを書けばよい?

simpleAns.file <- paste0('SampleSubmission.csv')
d.simpleAns <- read.csv(simpleAns.file, stringsAsFactors=F)

for(i in 1:nrow(d.simpleAns)){
	d.simpleAns[i,"Location"] <- predictions[[(i - 1) %/% 30 + 1, i %% 30 + 2]]
}

予測データが入っているデータフレーム"predictions"からデータを取り出すのがややこしかったです・・・
いつも書いてるJavaみたいにprediction[i][j]みたいな書き方ではなく、preditions[ [i,j] ]という書き方なんですね。
データフレームの形についてイマイチ想像ができていないので、色々触りながら輪郭をつかまないといけないですね。

最終的に雑推定の出力までするように書いたプログラムがこちら。

install.packages('doMC')
library(doMC)
registerDoMC()

# 今後はload('data.Rd')というコマンドでデータ利用可能
load('data.Rd')

# 簡単な予測の作成までやろう
# 各ポイントの平均を予測として提出(テストデータの入力画像に関係なく)
p           <- matrix(data=colMeans(d.train, na.rm=T), nrow=nrow(d.test), ncol=ncol(d.train), byrow=T)
colnames(p) <- names(d.train)
predictions <- data.frame(ImageId = 1:nrow(d.test), p)

# melt関数は使えなかった
# submission <- melt(predictions, id.vars="ImageId", variable.name="FeatureName", value.name="Location")

# 入力例を参考に回答を作成
# predictions の全項目を巡回するようなプログラムを書けばよい?

simpleAns.file <- paste0('SampleSubmission.csv')
d.simpleAns <- read.csv(simpleAns.file, stringsAsFactors=F)

for(i in 1:nrow(d.simpleAns)){
	d.simpleAns[i,"Location"] <- predictions[[(i - 1) %/% 30 + 1, i %% 30 + 2]]
}

# row.names = FALSE で行のナンバリングを出力しない
write.csv(d.simpleAns, "simpleAns.csv", quote = FALSE, row.names = FALSE)

# 終了の合図
print("all up")

やはりRはややこしい・・・
ただ、画像に点を打つなどRで出来ることもかなり広そうです。
何とかRである程度まともな推定を出力するところまでいきたいです。

終わり。