2009-09-21
水道屋がRubyを活用する(その4)
|ずいぶん久しぶりですが、私が仕事で使っているRubyプログラムの一部を紹介します。
その4となってますが、前のはここにあります。
http://d.hatena.ne.jp/miura1729/20090428/1240924372 その1
http://d.hatena.ne.jp/miura1729/20090430/1241083520 その2
http://d.hatena.ne.jp/miura1729/20090502/1241259378 その3
今回はその3のところで、ExcelのデータをRuby+Win32OLEを使って単価表を作ったわけですが、実際の見積でこれを使う話です。
水道屋が扱う部品はとても多くてサイズの違いなども別々に数えると数千にも及びます。それだけ種類が多くなると、それぞれを区別するために部品の名前が長くなってしまいます。さらに、使用頻度の高いものは略称をつい使ってしまいます。そんなこんなで、単価表に載っている部品は表記が揺れまくっています。
そのため、見積をしようとすると、通常の検索ではまともに部品が拾えないことになります。そこで、表記に揺れがあってもある程度適当に検索するfuzzy_compareというメソッドを作りました。これを使うと結構それらしい部品を探して提示してくれます。ただし、可能性が高いというだけで最終的な判断は人間がやる必要があります。それでも、数千もの候補から探すの事を考えると何10倍もスピードアップします。
fuzzy_compareはN-gramアルゴリズムを基本に、水道の部品の特有の特徴(φ[数字]+は口径で部品を特定するのに非常に重要であるとか)、を加味しています。かなり適当なつくりですが、結構重宝しています。
ソースコード兼使用例です。
# -*- coding: cp932 -*- def fuzzy_compare(s1, s2) score = 0 s1a = s1.each_char.to_a we = 50 s1a.each_cons(2) do |cp1| s = cp1.join if s2.include?(s) then score = score + we we = (we / 2 + 10) end end we = 40 s1a.each_cons(3) do |cp1| s = cp1.join if s2.include?(s) then score = score + we we = (we / 2 + we / 3 + 10) end end we = 100 s1.scan(/[0-9]+/).each do |cn1| if /([^0-9]#{cn1}[^0-9])|([^0-9]#{cn1}$)/ =~ s2 then we = (cn1.sub(/[0]+$/, "").size) * 100 score = score + we end end score end def search(list, s) l = [] list.each do |e| l.push [fuzzy_compare(s, e), e] end l.sort_by {|e0| -e0[0]} end list = [ "硬質塩化ビニル管 φ100 VP", "硬質塩化ビニル管 φ75 VP", "硬質塩化ビニル管 φ75 HI", "メカ式ベンド φ100", "メカ式ベンド φ50", "ダグタイル鋳鉄管 φ100 NS", "ダグタイル鋳鉄管 φ75 NS" ] ["塩ビ管 100", "ベンド 100", "鋳鉄管 100"].each do |s| print "#{s} \n" search(list, s).each do |e| print " #{e[1]} -> #{e[0]}\n" end print "\n" end
これで、
硬質塩化ビニル管 φ100 VP 硬質塩化ビニル管 φ75 VP 硬質塩化ビニル管 φ75 HI メカ式ベンド φ100 メカ式ベンド φ50 ダグタイル鋳鉄管 φ100 NS ダグタイル鋳鉄管 φ75 NS
という部品表から
塩ビ管 100 ベンド 100 鋳鉄管 100
を検索した場合の結果です。数が大きいほどより一致していると判断します。通常、数が大きい順にソートして表示します。
ruby fuzzy.rb 塩ビ管 100 硬質塩化ビニル管 φ100 VP -> 359 ダグタイル鋳鉄管 φ100 NS -> 318 メカ式ベンド φ100 -> 225 硬質塩化ビニル管 φ75 HI -> 175 硬質塩化ビニル管 φ75 VP -> 175 ダグタイル鋳鉄管 φ75 NS -> 125 メカ式ベンド φ50 -> 0 ベンド 100 メカ式ベンド φ100 -> 589 メカ式ベンド φ50 -> 399 硬質塩化ビニル管 φ100 VP -> 225 ダグタイル鋳鉄管 φ100 NS -> 225 硬質塩化ビニル管 φ75 HI -> 0 硬質塩化ビニル管 φ75 VP -> 0 ダグタイル鋳鉄管 φ75 NS -> 0 鋳鉄管 100 ダグタイル鋳鉄管 φ100 NS -> 589 ダグタイル鋳鉄管 φ75 NS -> 399 硬質塩化ビニル管 φ100 VP -> 318 メカ式ベンド φ100 -> 225 硬質塩化ビニル管 φ75 VP -> 125 硬質塩化ビニル管 φ75 HI -> 125 メカ式ベンド φ50 -> 0
- 14 http://www.rubyist.net/~kazu/samidare/
- 4 http://reader.livedoor.com/reader/
- 2 http://www.google.co.jp/hws/search?hl=ja&q=エスケープ解析&client=fenrir&adsafe=off&safe=off&lr=lang_ja
- 2 http://www.google.co.jp/reader/view/
- 1 http://74.125.153.132/search?q=cache:EK5gYgG0rxcJ:d.hatena.ne.jp/miura1729/20080403+jemalloc+spin&cd=1&hl=ja&ct=clnk&gl=jp&lr=lang_ja&client=firefox-a
- 1 http://a.hatena.ne.jp/fujita-y/
- 1 http://a.hatena.ne.jp/h_sakurai/
- 1 http://acquire-buy.info
- 1 http://d.hatena.ne.jp/
- 1 http://homepage3.nifty.com/HANI/index4.htm