<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>func09 &#187; 集合知</title>
	<atom:link href="http://www.func09.com/wordpress/archives/tag/%e9%9b%86%e5%90%88%e7%9f%a5/feed" rel="self" type="application/rss+xml" />
	<link>http://www.func09.com/wordpress</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Mon, 06 Feb 2012 04:25:55 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>[Ruby] 集合知プログラミング 03</title>
		<link>http://www.func09.com/wordpress/archives/250</link>
		<comments>http://www.func09.com/wordpress/archives/250#comments</comments>
		<pubDate>Sun, 19 Oct 2008 14:44:11 +0000</pubDate>
		<dc:creator>haga</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[集合知]]></category>

		<guid isPermaLink="false">http://www.func09.com/wordpress/?p=250</guid>
		<description><![CDATA[オライリー「集合知プログラミング」のPythonサンプルコードをRubyに翻訳していく作業ログ。３回目。 2.3.4 評者をランキングするのサンプルコードをRuby化 def top_matches( prefs, pe [...]]]></description>
			<content:encoded><![CDATA[<p>オライリー「集合知プログラミング」のPythonサンプルコードをRubyに翻訳していく作業ログ。３回目。</p>

<p><span id="more-250"></span></p>

<p>2.3.4 評者をランキングするのサンプルコードをRuby化</p>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">def top_matches( prefs, person, n=5, similarity=:sim_pearson)<br />
&nbsp; scores = prefs.keys.select{|i| i != person}.map do |other|<br />
&nbsp; &nbsp; [ method(similarity).call(prefs,person,other), other ]<br />
&nbsp; end<br />
&nbsp; return scores.sort.reverse[0...n]<br />
end<br />
<br />
p top_matches( critics, 'Toby', 3 )<br />
# =&gt; [[0.99124070716193, &quot;Lisa Rose&quot;], [0.924473451641905, &quot;Mick LaSalle&quot;], [0.66284898035987, &quot;Claudia Puig&quot;]]</div></div>

<p>2.4 アイテムを推薦するのサンプルコードをRuby化</p>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">def get_recommendations( prefs, person, similarity=:sim_pearson )<br />
&nbsp; totals = {}<br />
&nbsp; sim_sums = {}<br />
&nbsp; prefs.keys.each do |other|<br />
<br />
&nbsp; &nbsp; # 自分自身とは比較しない<br />
&nbsp; &nbsp; next if other == person<br />
&nbsp; &nbsp; sim = method(similarity).call( prefs, person, other )<br />
&nbsp; &nbsp; # 0以下のスコアは無視<br />
&nbsp; &nbsp; next if sim &lt;= 0<br />
<br />
&nbsp; &nbsp; prefs[other].each do |item|<br />
&nbsp; &nbsp; &nbsp; item_name = item[0]<br />
&nbsp; &nbsp; &nbsp; # まだ見てない映画の得点のみ算出<br />
&nbsp; &nbsp; &nbsp; if !prefs[person].key?(item_name) or prefs[person][item_name] == 0<br />
&nbsp; &nbsp; &nbsp; &nbsp; # 類似度 * スコア<br />
&nbsp; &nbsp; &nbsp; &nbsp; totals[item_name] ||= 0<br />
&nbsp; &nbsp; &nbsp; &nbsp; totals[item_name] += prefs[other][item_name] * sim<br />
&nbsp; &nbsp; &nbsp; &nbsp; # 類似度を合計<br />
&nbsp; &nbsp; &nbsp; &nbsp; sim_sums[item_name] ||= 0<br />
&nbsp; &nbsp; &nbsp; &nbsp; sim_sums[item_name] += sim<br />
&nbsp; &nbsp; &nbsp; end<br />
&nbsp; &nbsp; end<br />
&nbsp; end<br />
<br />
&nbsp; # 正規化したリストを作る<br />
&nbsp; rankings = []<br />
&nbsp; totals.each do |item_name,total|<br />
&nbsp; &nbsp; rankings &lt;&lt; [ total / sim_sums[item_name], item_name ]<br />
&nbsp; end<br />
<br />
&nbsp; # ソート済みのリストを返す<br />
&nbsp; return rankings.sort.reverse<br />
<br />
end<br />
<br />
p get_recommendations( critics, 'Toby' )<br />
# =&gt; [[3.27445961524987, &quot;The Night Listener&quot;], [2.95467531335197, &quot;Lady in the Water&quot;], [2.34855517312818, &quot;Just My Luck&quot;]]</div></div>

<p>引数similarityで、使用する類似性関数を切り替える。Rubyでは</p>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">method(:method_name).call</div></div>

<p>というような形で、シンボルまたは文字列でメソッド名を指定することでメソッドをコールできます。
<a href="http://www.ruby-lang.org/ja/man/html/Object.html#method">http://www.ruby-lang.org/ja/man/html/Object.html#method</a></p>

<p>オリジナルのPythonのサンプルコードではタプルオブジェクトが多用されているが、Rubyでは配列に置き換えている。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.func09.com/wordpress/archives/250/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Ruby] 集合知プログラミング 02</title>
		<link>http://www.func09.com/wordpress/archives/247</link>
		<comments>http://www.func09.com/wordpress/archives/247#comments</comments>
		<pubDate>Wed, 15 Oct 2008 16:15:24 +0000</pubDate>
		<dc:creator>haga</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[集合知]]></category>

		<guid isPermaLink="false">http://www.func09.com/wordpress/?p=247</guid>
		<description><![CDATA[オライリー「集合知プログラミング」のピアソン相関によるスコア計算のサンプルプログラムをRubyに置き換えたもの def sim_pearson( prefs, person1, person2 ) &#160; # 両者 [...]]]></description>
			<content:encoded><![CDATA[<p>オライリー「集合知プログラミング」のピアソン相関によるスコア計算のサンプルプログラムをRubyに置き換えたもの</p>

<p><span id="more-247"></span></p>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">def sim_pearson( prefs, person1, person2 )<br />
<br />
&nbsp; # 両者が互いに評価しているアイテムのリストを取得<br />
&nbsp; si = prefs[person1].keys &amp; prefs[person2].keys<br />
<br />
&nbsp; # 要素の数を調べる<br />
&nbsp; n = si.size<br />
<br />
&nbsp; # 共に評価しているアイテムがなければ0を返す<br />
&nbsp; return 0 if n == 0<br />
<br />
&nbsp; # 配列をブロックで収集し、合計するメソッド<br />
&nbsp; def map_sum( list, &amp;block )<br />
&nbsp; &nbsp; list.map{|i| yield(i) }.inject(0.0){|res,item| res += item }<br />
&nbsp; end<br />
<br />
&nbsp; # すべての嗜好を合計する<br />
&nbsp; sum1 = map_sum( si ){|i| prefs[person1][i] }<br />
&nbsp; sum2 = map_sum( si ){|i| prefs[person2][i] }<br />
<br />
&nbsp; # 平方を合計する<br />
&nbsp; sum1_sq = map_sum( si ){|i| prefs[person1][i] ** 2 }<br />
&nbsp; sum2_sq = map_sum( si ){|i| prefs[person2][i] ** 2 }<br />
<br />
&nbsp; # 積を合計する<br />
&nbsp; p_sum = map_sum(si){|i| prefs[person1][i] * prefs[person2][i] }<br />
<br />
&nbsp; # ピアソンによるスコアを計算する<br />
&nbsp; num = p_sum - ( sum1 * sum2 / n)<br />
&nbsp; den = Math.sqrt(( sum1_sq - sum1 ** 2 / n ) * ( sum2_sq - sum2 ** 2 / n ))<br />
&nbsp; return 0 if den == 0<br />
<br />
&nbsp; return num / den<br />
<br />
end<br />
<br />
puts sim_pearson( critics, 'Lisa Rose', 'Gene Seymour' )</div></div>

<p>pythonでリスト内包を使っての合計は、Rubyで書くとmapとinjectを組み合わせたものになると思う。
これはPythonに比べ長くなってしまい、読みにくかった上に繰り返し出現するのでmap_sumというショートカット用のメソッドを用意した。</p>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"># 長ったらしい<br />
sum1 = si.map{|i| prefs[person1][i] }.inject(0.0){|res,item| res += item }</div></div>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"># python版<br />
sum1 = sum([prefs[p1][it] for it in si])</div></div>

<p>Ruby版は式を評価する順番が、単純に左から右へ読めばいいのに対し、Python版では式の評価箇所が飛び飛びなのが、Pythonがわからない人間には辛いが、慣れればリスト内包の方が奇麗な気がしてくるから不思議だ。</p>

<p>両者の評価しているアイテムを収集する場合は、Hash#keys同士を&amp;演算子で、集合の積を抽出するのがRubyらしいのかなと思う。</p>

<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"># 両者が互いに評価しているアイテムのリストを取得<br />
si = prefs[person1].keys &amp; prefs[person2].keys</div></div>
]]></content:encoded>
			<wfw:commentRss>http://www.func09.com/wordpress/archives/247/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

