• 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
 
 

rubyで普通にinjectを使って合計を求めようとした場合、こんな感じになります。

   1  (1..10).inject(0){|sum, i| sum + i} #=> 55

しかし、以下のように書く事も出来ます。

   1  (1..10).inject(&:+) #=> 55

posted by Png genki on Sun 10 May 2009 at 04:55

ポジティブ/ネガティブ投票による正しいランキング方法が以下の記事で紹介されています。

How Not To Sort By Average Rating

この計算方法では、投票数が少ない場合には分散が大きく不正確な評価で、 投票数が多くなるにつれて分散が小さく正確な評価が得られているという事を考慮しています。以下数式


\frac{\hat{p}+\frac{z^2_{\alpha/2}}{2N}\pm{}z_{\alpha/2}\sqrt{
\frac{\hat{p}(1-\hat{p})+\frac{z^2_{\alpha/2}}{4N}}{N}
}}{1+\frac{z^2_{\alpha/2}}{N}}

これはScoreの{}_{1-\alpha/2}信頼区間を表しています。 この信頼区間の下界をランキングのスコアにすれば良い事になります。 ここで、{}_{\hat{p}}は、

です。全体に占めるポジティブ投票数の割合ですね。

{}_{z_{\alpha/2}}は標準正規分布上の {}_{1-\alpha/2}信頼区間の有意確率です。

さて、五段階評価によるRatingに同様のテクニックを適用する場合はどうしたらいいでしょうか。 単純に、1回の投票を4度のpositive/negative投票行為だと考えると (例えば星1つは[-,-,-,-], 星3つは[+,+,-,-])、以下のような {}_{\hat{p}'}を使えば良さそうです。


\hat{p}'=\frac{\sum_{i\in{[1,5]}}(i-1)N_{i}}{4N}

従って、最終的にこんな感じになります。


\frac{\hat{p}'+\frac{z^2_{\alpha/2}}{2N}\pm{}z_{\alpha/2}\sqrt{
\frac{\hat{p}'(1-\hat{p}')+\frac{z^2_{\alpha/2}}{4N}}{N}
}}{1+\frac{z^2_{\alpha/2}}{N}}

Rubyコードで表すとこんな感じですね。

   1  require 'statistics2'
   2  
   3  def score(ni, alpha)
   4    n = ni.inject(&:+)
   5    return 0 if n == 0
   6    m = ni.size
   7    z = Statistics2.pnormaldist(1-alpha/2)
   8    phat = m.times.zip(ni).inject(0){|s,(i,j)| s + i*j}/((m - 1.0)*n)
   9    (phat + z*z/(2*n) - z*Math.sqrt((phat*(1-phat)+z*z/(4*n))/n))/(1+z*z/n)
  10  end

posted by Png genki on Sun 10 May 2009 at 04:46

hamlでtext_areaヘルパメソッドを使う場合は、以下のように"~"を使うと良い。

   1  ~ text_area :foo

~ について (cheat hamlより)

Ruby expression preserving whitespace, e.g. %pre~ @content.body Works just like =, but calls the find_and_preserve helper to keep line breaks intact in the output.

posted by Png genki on Wed 6 May 2009 at 11:33

dm-is-remixable は、Commentなどの複数のリソースにまたがって共用されるがちなリソースをDRYにするためのDataMapperプラグインです。

しかし、Validationのためのコードを記述しても、正常に動作しないという問題がありました。これは、以下のようにすれば解決できます。

   1  module Commentable
   2    include DataMapper::Resource
   3    is :remixable, :suffix => "comment"
   4  
   5    (..snip..)
   6  
   7    def self.included(base)
   8      base.class_eval do
   9        validates_present :message
  10      end
  11    end
  12  end

See Also

posted by Png genki on Mon 4 May 2009 at 17:56

Enumerable#grepを使う事で、文字列の配列から、 所望のパターンにマッチするものだけを抜き出す事が出来ますが、 以下のようにブロックを指定する事で、 マッチした部分だけを取り出す事が出来ます。

   1  Dir["config/environments/*.rb"].grep(%r{(\w+)\.rb$}){$1}
   2  #=> ["development", "production", "rake", "staging", "test"]

痒いところに手が届く感じですね。

posted by Png genki on Thu 30 Apr 2009 at 14:32

Sassを使うようになって、属性とタグの区別がつきにくいなと感じていたので、シンタックスハイライトをする方法を探してみました。

これを使うと、こんな感じになります。

ss

だいぶ見やすくなりました。

posted by Png genki on Sun 26 Apr 2009 at 17:34

例えばJavaScriptだと"\u3000"と書けば良かったのですが、少なくともRuby-1.8系ではこれに相当する記法が無さそうだったので、いつも困ってました。 色々調べてみた結果、以下のようにすれば良さそうです。

   1  [0x3000].pack("U") == " "  #=> true

長い事迂回していた問題だったのでスッキリしました :-)

Special Thanks

  • @yukiko pack("U")が使えそうという情報をありがとうございます。
posted by Png genki on Fri 24 Apr 2009 at 06:28
posted by Png genki on Thu 23 Apr 2009 at 21:12

Rails勉強会#40のセッションでも言いましたが、 エラーが発生した時等に表示されるbacktraceの表示は、 コンソールのように上から下に流れる画面上では 通常の逆順のほうが追いやすいと思います。

ということで、ちょっと試しにそのような挙動にしてみました。 以下のようなコードを実行するとテストできます。

   1  class Exception
   2    def set_backtrace(bt)
   3      puts bt.reverse.map{|i|
   4        i.sub(/^([\/\.\w]+):(\d+)/,
   5          "\e[33m\\1\e[m:\e[32m\\2\e[m")
   6      }.join("\n")
   7    end
   8  end
   9  
  10  def foo
  11    raise StandardError
  12  end
  13  
  14  def bar
  15    foo
  16  end
  17  
  18  bar

こんな感じに、エラーが発生した場所に近い順に、 下から上にたどっていく感じに表示されます。

ss

上から下のbacktraceに目が慣れてしまっているので、最初は追いかけにくさを感じますが、一旦慣れてしまえば、スタックが深くて相当スクロールアップしなければエラーの発生源までたどり着けないという場合には良さそうな気がします。

stackという概念のイメージのせいで、新しいものが上の方に来るようになっているのだと思いますが、実用上は新しいものが下にくるこのスタイルの方が便利ではないでしょうか。

posted by Png genki on Thu 23 Apr 2009 at 14:27 with 2 comments

JRubyで相対パスを含む場合に、Jarファイルの中のファイルを読めるようにするためのモンキーパッチの最新版です。

   1  def cleanup_path(path)
   2    if path.to_s.match(/^file:/) && path.is_a?(String)
   3      jar_path, inner_path = path.split('!', 2)
   4      inner_path = File.expand_path(inner_path)
   5      path = [jar_path, inner_path].join('!')
   6    end
   7    path
   8  end
   9  
  10  alias :require_original :require
  11  def require(path)
  12    require_original cleanup_path(path)
  13  rescue Exception => e
  14    raise e unless path.to_s.match(/^file:/)
  15  end
  16  
  17  alias :load_original :load
  18  def load(path)
  19    load_original cleanup_path(path)
  20  rescue Exception => e
  21    raise e unless path.to_s.match(/^file:/)
  22  end
  23  
  24  class Dir
  25    class << self
  26      alias :aref_original :[]
  27      def [](*args)
  28        aref_original *(args.map{|path| cleanup_path(path)})
  29      end
  30    end
  31  end
  32  class File
  33    class << self
  34      alias :mtime_original :mtime
  35      def mtime(path)
  36        if path.match(/^file:/)
  37          jar_file, = path.split('!', 2)
  38          path = jar_file.sub(/^file:/, '')
  39        end
  40        mtime_original(path)
  41      end
  42    end
  43  end

posted by Png genki on Tue 21 Apr 2009 at 02:43