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

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

Kaggle Titanic で、まだまだランダムフォレストをやっていない話

今日は少し時間があったのでTitanicの例題をやりました。
pythonでのやり方のページを見て、Anacondaのセッティングをしてみたりしました。
pythonのコードがある程度動くことを確認した上で、どうしてもランダムフォレストをやるのが面倒で、別のコードをRで書くことにしました。

もともと僕は要領の悪い、全探索みたいなコードを書くのが好きなので、前回の記事でやった、『"Fare"を10ごとに区切ってランク分けして、そのランクを元に推定する』方法の改良版をRで書いてみました。


やり方は、『ランクを4つに区切る、その区切の整数3つについて、一番良い組み合わせを全探索で探す』というものです。
『一番良い組み合わせ』の基準は、色々あると思うんですが、自分の中で一番自然に思えるような計算式にしました。

コードは以下のような感じです。ゴリゴリ書いて、まったくまとまっていない。
学生の時と全く変わっていません。後日見たら読解に時間かかるだろうな・・・

traindata <- read.table("train.csv", header=T, sep=",")
testdata <- read.table("test.csv", header=T, sep=",")

traindata$Fare <- ifelse(is.na(traindata$Fare), 33.3, traindata$Fare)
testdata$Fare <- ifelse(is.na(testdata$Fare), 33.3, testdata$Fare)

t<-proc.time()

maletraindata <- traindata[traindata$Sex == "male", ]
femaletraindata <- traindata[traindata$Sex == "female", ]
maletestdata <- testdata[testdata$Sex == "male", ]
femaletestdata <- testdata[testdata$Sex == "female", ]

bestsmaller <- 0
bestmiddle <- 0
bestlarger <- 0
bestscore <- 0
bestmalematrix <- matrix(nrow=3, ncol=4)
bestfemalematrix <- matrix(nrow=3, ncol=4)

devs <- c(-1,100,100,100,100000)

for(dev1 in 1:40){
  for(dev2 in dev1+1:40){
    for(dev3 in dev2+1:40){
      devs[2] <- dev1
      devs[3] <- dev2
      devs[4] <- dev3

      malematrix <- matrix(0,nrow=3, ncol=4) # class = row, farerand = col
      femalematrix <- matrix(0,nrow=3, ncol=4)

      for(classind in 1:3){
        for(devind in 1:4){
          nowdata <- maletraindata[maletraindata$Pclass == classind & maletraindata$Fare > devs[devind] & maletraindata$Fare <= devs[devind+1], ]

          nowsurviveddata <- nowdata["Survived"]

          if(nrow(nowsurviveddata) == 0){
            malematrix[classind, devind] <- 0
          }else{
            malematrix[classind, devind] <- (sum(nowsurviveddata) / nrow(nowsurviveddata))
          }
        }
      }

      for(classind in 1:3){
        for(devind in 1:4){
          nowdata <- femaletraindata[femaletraindata$Pclass == classind & femaletraindata$Fare > devs[devind] & femaletraindata$Fare <= devs[devind+1], ]
          nowsurviveddata <- nowdata["Survived"]
          if(nrow(nowsurviveddata) == 0){
            femalematrix[classind, devind] <- 0
          }else{
            femalematrix[classind, devind] <- (sum(nowsurviveddata) / nrow(nowsurviveddata))
          }
        }
      }
      # ここまでで、traindataからの集計は終わり。testdataへ適用した時のスコア(勝手に自分で決めた基準)を計算する

      nowscore <- 0
      for(classind in 1:3){
        for(devind in 1:4){
          nowcount <- nrow(maletestdata[maletestdata$Pclass == classind & maletraindata$Fare > devs[devind] & maletraindata$Fare <= devs[devind+1], ])
          nowscore <- nowscore + nowcount * abs(0.5 - malematrix[classind, devind])
        }
      }
      for(classind in 1:3){
        for(devind in 1:4){
          nowcount <- nrow(femaletestdata[femaletestdata$Pclass == classind & femaletraindata$Fare > devs[devind] & femaletraindata$Fare <= devs[devind+1], ])
          nowscore <- nowscore + nowcount * abs(0.5 - femalematrix[classind, devind])
        }
      }

      if(nowscore > bestscore){
        bestsmaller <- dev1
        bestmiddle <- dev2
        bestlarger <- dev3
        bestscore <- nowscore
        bestmalematrix <- malematrix
        bestfemalematrix <- femalematrix
      }
      print(sprintf("finish -> dev1,2,3 %2d , %2d , %2d", dev1, dev2, dev3))
    }
  }
}

devs[2] <- bestsmaller
devs[3] <- bestmiddle
devs[4] <- bestlarger

out <- file("./bestDevAns.csv", "w") # 書き込みモードで開く
writeLines("PassengerId,Survived", out) # ヘッダーを記入

for(i in 1:nrow(testdata)){
  writeLines(paste(testdata[i, "PassengerId"]), out, sep = ",")
  nowdata <- testdata[i,]
  nowfare <- nowdata$Fare
  nowfarerank <- 0
  for(rankind in 1:4){
    if(devs[rankind] < nowfare & nowfare <= devs[rankind + 1]){
      nowfarerank <- rankind
    }
  }
  if(nowdata$Sex == "male"){
    if(bestmalematrix[nowdata$Pclass, nowfarerank] < 0.5){
      writeLines(paste(0), out, sep = "\n")
    }else{
      writeLines(paste(1), out, sep = "\n")
    }
  }else{
    if(bestfemalematrix[nowdata$Pclass, nowfarerank] < 0.5){
      writeLines(paste(0), out, sep = "\n")
    }else{
      writeLines(paste(1), out, sep = "\n")
    }    
  }
}

close(out)                        # ファイルを閉じる

print(sprintf("smaller: %3d , middle: %3d , larger: %3d are bests!", bestsmaller, bestmiddle, bestlarger))
print(proc.time()-t)

これによって、今回の基準で一番良い区切は
x<24, 24 <= x < 56, 56 <= x < 58, 58 <= x
という区切でした。(4つに区切る前提のコードです)

これで提出した回答は・・・
ちゃんとスコアが上がっていました!

スコア:0.78469 (0.00478アップ!)
2014位/3760(全体) ( 約300位アップ!)

上がってホッとしました。
まぁ今回はデータ数が少ないので、このやり方ができましたが、データ量がもっと大きい問題では確実にできないやり方ですね。
その場合は、区切候補の中を少しずつ変えていくやり方ですかね。シュミレーテッドアニーリング。大学のときに少しだけ勉強したので、いつか実装したいです。

そろそろランダムフォレストもやらねば!面倒だー。以上です!