ためすう

How to Win a Data Science Competition (Week3-1 part1)

2019-06-16

Metrics optimization

学習目標

  • Describe the role of correct metric optimization method in a competition
  • Analyze new metrics
  • Create constant baselines
  • Recall the most important classification and regression metrics
  • Describe what libraries can be used to optimize a particular metric

Motivation

Metrics

  • 提出物の評価で使われるもの
  • コンペによって異なるのは、何に対して最適化するのかが決まっているからである
  • バリデーションデータのメトリクスを改善しても、テストデータのメトリクスが改善しないことがある

Regression metrics review I

Regression

  • MSE, RMSE, R-squared
  • MAE
  • ®MSPE, MAPE
  • ®MSLE

平均二乗誤差: MSE (Mean Square Error)

$$ MSE = 1/N * \sum_{i=1}^N (y_i - \hat{y_i})^2 $$

$$ RMSE = \sqrt{MSE} $$

R-squared

$$ R^2 = 1 - \frac{MSE}{\frac{1}{N}\sum_{i=1}^N (y_i - \bar{y_i})^2} $$

MSEが0のとき、R-squared は1

MSEが定数と等しいとき、R-squared は0

MAE: Mean Absolute Error

$$ MAE = \frac{1}{N}\sum_{i=1}^N|y_i - \hat{y_i}| $$

  • MSE ほどには外れ値にペナルティを与えない
  • 最適な定数は中央値

MAE vs MSE

  • 外れ値があるなら、MAE
  • ただし、外れ値があるのが正常なら、MSE
  • 異常値であるなら、MAE

参考

アジャイルソフトウェア開発の奥義 第5章 リファクタリング

2019-06-15

「アジャイルソフトウェア開発の奥義」の読書メモです。

時々、個人の見解入りです。

書き上げるモジュールと保守するモジュールのすべてを必ずリファクタリングすることを強く勧める。リファクタリングに費やす時間は、それをしなかったことで自分自身を含む関係者が将来費やすことになる労力に比べれば微々たるものだからだ。

ソフトウェアモジュールの3つの機能

  • 特定の処理を実行する機能
  • 変化を許容する機能
  • 読み手にそのモジュールの意図を伝える機能

この章で書かれていないが、リファクタリングをするには、自動テストが書かれている必要があると思います。

自動テストされていれば、自動テストが用意されている分については挙動が変わっていないと保証できます。

Rails5 で sidekiq を使う

2019-06-15

やったこと

Rails5 で sidekiq を使います。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

インストールからやっていきます。

redis のインストール

$ brew install redis
$ redis-server --version
Redis server v=5.0.5 sha=00000000:0 malloc=libc bits=64 build=272e5301ea2dcb73

redisサーバーを起動します

$ redis-server /usr/local/etc/redis.conF

sidekiq のインストール

Gemfile

gem 'sidekiq', '~> 5.2', '>= 5.2.7'
$ bundle install

もしかしたら、エラーが出るかもしれないのでこちら見てみてください

Rails5 で bundle install が失敗する件 – ためすう

sidekiq の設定

config/initializers/sidekiq.rb

Sidekiq.configure_server do |config|
  config.redis = { url: 'redis://localhost:6379'}
end

config/sidekiq.yml

:pidfile: ./tmp/pids/sidekiq.pid
:logfile: ./log/sidekiq.log
:queues:
  - task
$ bundle exec sidekiq -C config/sidekiq.yml

sidekiq の ワーカー作成

app/workers/task_worker.rb

class TaskWorker
  include Sidekiq::Worker
  sidekiq_options queue: :task

  def perform(id)
    logger.debug('id 出力')
    logger.debug(id)
  end
end

※ ログを出力するには、設定する必要があるのですが、また今度。

Queue を登録

app/controllers/tasks_controller.rb

class TasksController < ApplicationController

  def new
    TaskWorker.perform_async 333
  end
end

参考

Rails5 で bundle install が失敗する件

2019-06-15

やったこと

Rails5 で sidekiq をインストールしようとしたところ、bundle install が失敗してしまいました。

今回、そのエラーを解消したいと思います。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

問題の再現

Gemfile

gem 'sidekiq', '~> 5.2', '>= 5.2.7'

bundle install で失敗します

$ bundle install
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
Fetching source index from https://rubygems.org/

Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from https://rubygems.org/
Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from https://rubygems.org/
Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from https://rubygems.org/
Could not fetch specs from https://rubygems.org/

解決までの過程

bundle update してみます

$ gem update --system
ERROR:  While executing gem ... (Gem::RemoteFetcher::UnknownHostError)
    timed out (https://rubygems.org/specs.4.8.gz)

失敗したので、次は、wget できるかやってみます

$ wget https://api.rubygems.org/specs.4.8.gz
--2019-06-15 11:30:11--  https://api.rubygems.org/specs.4.8.gz
Resolving api.rubygems.org... 2a04:4e42::70, 151.101.0.70, 151.101.192.70, ...
Connecting to api.rubygems.org|2a04:4e42::70|:443... failed: Operation timed out.
Connecting to api.rubygems.org|151.101.0.70|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3886510 (3.7M) [application/octet-stream]
Saving to: 'specs.4.8.gz'

specs.4.8.gz                        100%[=====================================================================>]   3.71M  1.91MB/s   in 1.9s

2019-06-15 11:31:29 (1.91 MB/s) - 'specs.4.8.gz' saved [3886510/3886510]

wget は出来ました。IPv6 での通信に失敗しているようです。

IPv4 を使うようにします。

該当ドメインの IP アドレスを調べます。

$ host api.rubygems.org
api.rubygems.org is an alias for rubygems.org.
rubygems.org has address 151.101.128.70
rubygems.org has address 151.101.0.70
rubygems.org has address 151.101.64.70
rubygems.org has address 151.101.192.70
rubygems.org has IPv6 address 2a04:4e42::70
rubygems.org mail is handled by 10 mxa.mailgun.org.
rubygems.org mail is handled by 10 mxb.mailgun.org.

hosts を書き換えてみます。

$ sudo vim /etc/hosts

151.101.128.70 api.rubygems.org
151.101.0.70 api.rubygems.org
151.101.64.70 api.rubygems.org
151.101.192.70 api.rubygems.org
$ bundle install

sidekiq がインストールできました。

参考

Rails5 で validate の on オプションを使う

2019-06-13

やったこと

Rails5 で validate の on オプションを使います。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

app/models/task.rb

class Task < ApplicationRecord
  validates :name , uniqueness: true, on: :task_setup
end

task.name に “name1” で1件登録します。

$ rails c
Running via Spring preloader in process 23605
Loading development environment (Rails 5.2.3)
irb(main):001:0> a1 = Task.new
=> #<Task id: nil, created_at: nil, updated_at: nil, name: nil>
irb(main):002:0> a1.name = "name1"
=> "name1"
irb(main):003:0> a1.save
   (0.1ms)  begin transaction
  Task Create (0.5ms)  INSERT INTO "tasks" ("created_at", "updated_at", "name") VALUES (?, ?, ?)  [["created_at", "2019-06-12 12:50:53.647258"], ["updated_at", "2019-06-12 12:50:53.647258"], ["name", "name1"]]
   (0.8ms)  commit transaction
=> true

save メソッドに context で指定すると、保存に失敗します。

irb(main):005:0> a2 = Task.new
=> #<Task id: nil, created_at: nil, updated_at: nil, name: nil>
irb(main):006:0> a2.name = "name1"
irb(main):007:0> a2.save(context: :task_setup)
   (0.1ms)  begin transaction
  Task Exists (0.2ms)  SELECT  1 AS one FROM "tasks" WHERE "tasks"."name" = ? LIMIT ?  [["name", "name1"], ["LIMIT", 1]]
   (0.1ms)  rollback transaction
=> false

context を指定せずに save すると、保存できました。

irb(main):008:0> a2.save()
   (0.1ms)  begin transaction
  Task Create (0.4ms)  INSERT INTO "tasks" ("created_at", "updated_at", "name") VALUES (?, ?, ?)  [["created_at", "2019-06-12 12:52:31.539434"], ["updated_at", "2019-06-12 12:52:31.539434"], ["name", "name1"]]
   (0.8ms)  commit transaction
=> true

参考

rspec の let と let!

2019-06-13

やったこと

rspec の let と let! の違いについて調べてみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

$ gem list | grep rspec-rails
rspec-rails (3.8.2)

調査

  • let は遅延評価
  • let! はテスト前に実行される

let を使う

spec/models/task6_spec.rb

require 'rails_helper'

RSpec.describe Task, type: :model do
  let(:user) { create(:user) }
  let(:task) { create(:task) }

  it 'test1' do
  end
end

出力結果

$ rspec spec/models/task6_spec.rb
.

Finished in 0.01818 seconds (files took 1.66 seconds to load)
1 example, 0 failures

let! を使う

spec/models/task6_spec.rb

require 'rails_helper'

RSpec.describe Task, type: :model do
  let!(:user) { create(:user) }
  let!(:task) { create(:task) }

  it 'test1' do
  end
end

出力結果

$ rspec spec/models/task6_spec.rb
F

Failures:

  1) Task test1
     Failure/Error: let!(:user) { create(:user) }

     KeyError:
       Factory not registered: "user"
     # ./spec/models/task6_spec.rb:7:in `block (2 levels) in <top (required)>'
     # ------------------
     # --- Caused by: ---
     # KeyError:
     #   key not found: "user"
     #   ./spec/models/task6_spec.rb:7:in `block (2 levels) in <top (required)>'

Finished in 0.00288 seconds (files took 1.65 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/models/task6_spec.rb:10 # Task test1

参考

Ruby で each_with_object を使う

2019-06-12

やったこと

Ruby で each_with_object を使ってみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

調査

test.rb

scores = { 'Carol' => 90, 'Alice' => 50, 'David' => 40, 'Bob' => 60 }
names = scores.each_with_object([]) do |(key, val), arr|
  arr << val * 2 if val >= 60
end

p names

arr に値を入れていくイメージです。

出力結果

$ ruby test.rb
[180, 120]

参考

Rails5 で escape_javascript を使う

2019-06-12

やったこと

Rails5 で escape_javascript を使ってみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

例えば、下記の view ファイルに書いてみます。

app/views/tasks/new.html.erb

<span>
<%= escape_javascript("111
222") %>
</span>
<span>
  <%= escape_javascript("<script>alert(1111);</script>") %>
</span>
<span>
<%= "333
222" %>
</span>

出力結果

<span>
111\n222
</span>
<span>
  &lt;script&gt;alert(1111);&lt;\/script&gt;
</span>
<span>
333
222
</span>

改行もエスケープされてます。

参考

Rails5 の css で画像を設定する

2019-06-11

やったこと

Rails5 の css で画像を設定します。

今回 production 環境で試します。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

画像を下記に配置します

app/assets/images/sample.png

app/views/tasks/new.html.erb

<div id="main">
  dddd
</div>

app/assets/stylesheets/tasks.scss

#main {
  background-image: image-url('sample.png')
}

config/environments/production.rb

# config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.public_file_server.enabled = true

↑ Webサーバから静的ファイルを読み込むことができるようにします。

$ RAILS_ENV=production bin/rails assets:precompile

↑ プリコンパイルして、ファイルを作成します。

参考

Rails5 で自作ミドルウェアを作ってみる

2019-06-11

やったこと

Rails5 で自作したミドルウェアを読み込んで使ってみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

現在のミドルウェア

$ bin/rails middleware
use Rack::Sendfile
use ActionDispatch::Static
use ActionDispatch::Executor
use ActiveSupport::Cache::Strategy::LocalCache::Middleware
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use ActionDispatch::RemoteIp
use Sprockets::Rails::QuietAssets
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use WebConsole::Middleware
use ActionDispatch::DebugExceptions
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ContentSecurityPolicy::Middleware
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Rack::TempfileReaper
run Sample2::Application.routes

lib/middlewares/my_middleware.rb

class MyMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)

    if env['PATH_INFO'] == '/tasks/new'
      Rails.logger.debug('path is /tasks/new')
      res = @app.call(env)
    else
      Rails.logger.debug('path is other')
      res = @app.call(env)
    end

    res
  end
end

config/application.rb

require './lib/middlewares/my_middleware'
...
module Sample2
  class Application < Rails::Application
    ...
    config.middleware.use ::MyMiddleware
  end
end
$ bin/rails middleware | grep My
use MyMiddleware

参考