﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>博客园-Kuberski - 酷伯司机</title><link>http://www.cnblogs.com/kuber/</link><description>写在代码边上</description><language>zh-cn</language><lastBuildDate>Thu, 24 Jul 2008 21:57:40 GMT</lastBuildDate><pubDate>Thu, 24 Jul 2008 21:57:40 GMT</pubDate><ttl>60</ttl><item><title>转载:通过Google Ajax Libraries API加速你的js脚本的加载 </title><link>http://www.cnblogs.com/kuber/archive/2008/07/23/1249795.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Wed, 23 Jul 2008 08:40:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/07/23/1249795.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1249795.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/07/23/1249795.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1249795.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1249795.html</trackback:ping><description><![CDATA[<p>原来想介绍这个Google Ajax Library, 在网上搜到了这篇文章, 写的比我好多了, 就转到这里吧, 希望能对大家有用.</p><h2>通过Google Ajax Libraries API加速你的js脚本的加载</h2>

			
				<p>原文链接: http://xuming.net/2008/05/ajax-libraries-api.html</p><p><br></p><p>Google 的触角似乎是无所不在的。在互联网的各个角落，我们都可以看到他的身影。</p>
<p>Google 花费了大量的时间来使网络应用变得更快，调用js脚本是我们经常要用到的功能之一，过多的脚本调用经常会使网页变慢。</p>
<p>Google似乎试图来解决这个问题，使大家在使用Javascript框架的时候能够更快速和简单，为此，Google最新提供了一个名为 <a href="http://code.google.com/apis/ajaxlibs/">Ajax Libraries API</a>的东西。</p>
<p><span id="more-50"></span></p>
<p>Ajax Libraries API的理念很简单：把Javascript运行在Google的服务器上面, 通过Google快速分发服务器, 当有需要的时候进行Gzip压缩, 更重要的是，使用缓存机制来改善多人同时加载的情况.</p>
<p>使用<a href="http://code.google.com/apis/ajaxlibs/">AJAX Libraries API</a> 有以下优势：</p>
<ul><li>开发者不需要考虑如何设置缓存机制，Google会为你准备好一切 </li><li>如果另外一个应用程序使用了同一个Javascript框架，那么客户端不再需要重复去获取脚本，因为其已经被缓存在用户的机器里面了。 </li><li>不需要考虑网络环境和流量限制 </li></ul>
<p> <a href="http://code.google.com/apis/ajaxlibs/">AJAX Libraries API</a> 目前支持以下JS框架：
</p><ul><li><a href="http://code.google.com/apis/ajaxlibs/documentation/index.html#jquery">jQuery</a> </li><li><a href="http://code.google.com/apis/ajaxlibs/documentation/index.html#prototype">prototype</a> </li><li><a href="http://code.google.com/apis/ajaxlibs/documentation/index.html#script_aculo_us">script.aculo.us</a> </li><li><a href="http://code.google.com/apis/ajaxlibs/documentation/index.html#mootools">MooTools</a> </li><li><a href="http://code.google.com/apis/ajaxlibs/documentation/index.html#dojo">dojo</a> </li></ul>
<p>如果这个缓存机制能够大规模的得到应用，那么将是无比强大的。只不过，在中国目前的这种状况下，对于其调用速度始终是担心的。</p>
<h3>Ajax Libraries API调用方式1：</h3>
<p>例如：加载Prototype 1.6.0.2 </p>
<p><code>&lt;script src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.2/prototype.js"&gt;&lt;/script&gt;</code>     </p>
<h3>Ajax Libraries API调用方式2：</h3>
<p>使用<a href="http://code.google.com/apis/ajax/documentation/">Google AJAX API Loader’s google.load() 方法</a>.</p>
<p><code>&lt;script src="http://www.google.com/jsapi"&gt;&lt;/script&gt;      <br>&lt;script&gt;       <br>// Load jQuery       <br>google.load("jquery", "1");       <br>// on page load complete, fire off a jQuery json-p query       <br>// against Google web search       <br>google.setOnLoadCallback(function() {       <br>$.getJSON("http://ajax.googleapis.com/ajax/services/search/web?q=google&amp;;v=1.0&amp;;callback=?",       <br>// on search completion, process the results       <br>function (data) {       <br>if (data.responseDate.results &amp;&amp;       <br>data.responseDate.results.length&gt;0) {       <br>renderResults(data.responseDate.results);       <br>}       <br>});       <br>});       <br>&lt;/script&gt;</code></p>
<p>详细调用方法请 <a href="http://code.google.com/apis/ajaxlibs/documentation/#AjaxLibraries" target="_blank">查看相关文档</a></p><img src ="http://www.cnblogs.com/kuber/aggbug/1249795.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41284/" target="_blank">[新闻]奇虎回应:瑞星半年免费版像是一个恶意软件</a>]]></description></item><item><title>乔布斯的策略</title><link>http://www.cnblogs.com/kuber/archive/2008/07/23/1249771.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Wed, 23 Jul 2008 08:11:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/07/23/1249771.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1249771.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/07/23/1249771.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1249771.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1249771.html</trackback:ping><description><![CDATA[这篇文章讲了一个<a href="http://hbswk.hbs.edu/archive/3533.html">乔布斯的故事</a>. 乔布斯被风投邀请到另外一家公司看看他们新推出的产品. 乔布斯一如既往的酷. 详细请看<a href="http://apple4.us/2008/07/-scooter.html">apple4.us的翻译</a>. <br><br>我的摘要:<br><b>产品开发</b>: 集中全部精力用于做好一款产品, 没有退路. 孤注一掷才能激发小宇宙.<br><b>产品设计</b>: 三个设计标准：创新,优雅，人性化, 找到"things that would make you shit in your pants." (btw, Jobs好像很喜欢shit这个词啊)<br><b>竞争对手</b>: 技术不是壁垒.关键是用时间和资金去找到其他壁垒.&nbsp; They'll figure out a way around that. 科特勒好像也说过, 技术永远不是核心竞争力. <br><b>市场营销</b>: 高举高打,他自己的话说就是big-bang guy. 看看apple的产品发布就知道了. The risk&nbsp; is that it exposes you to
your enemies. You're going to need a lot of money to fight thieves.<img src ="http://www.cnblogs.com/kuber/aggbug/1249771.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41284/" target="_blank">[新闻]奇虎回应:瑞星半年免费版像是一个恶意软件</a>]]></description></item><item><title>Google App Engine 未公开的Search API</title><link>http://www.cnblogs.com/kuber/archive/2008/07/23/1249617.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Wed, 23 Jul 2008 07:14:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/07/23/1249617.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1249617.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/07/23/1249617.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1249617.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1249617.html</trackback:ping><description><![CDATA[Search API是<a href="http://code.google.com/appengine/">Google App Engine</a>被广泛要求的一个特性. 其实GAE SDK中已经提供了SearchAPI, 可能因为还没有成熟, 还没有被公开. 但是在GAE的文档中可以找到一些痕迹.<br><br><a href="http://code.google.com/appengine/articles/bulkload.html">Uploading Data with Bulk Data Uploader</a>中使用了google.appengine.ext.search:<br>首先把Entity设为Searchable:<br>&nbsp; def HandleEntity(self, entity):<br>&nbsp;&nbsp;&nbsp; ent = search.SearchableEntity(entity)<br>&nbsp;&nbsp;&nbsp; return ent<br><br>接下来你就可以对此entity做Search了:<br>&nbsp;&nbsp;&nbsp; query = search.SearchableQuery('Person')<br>&nbsp;&nbsp;&nbsp; query.Search(keyword)<br>&nbsp;&nbsp;&nbsp; for result in query.Run():<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.response.out.write('%s' % result['email'])<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>下载的SDK有GAE的源码, 我们可以带代码中去看个究竟: C:\Program Files\Google\google_appengine\google\appengine\ext\search\__init__.py (这是我机器上的路径, 你安装的路径可能会不同)<br>\search\__init__.py中有三个类:<br>SearchableEntity<br>SearchableQuery<br>SearchableModel<br><br>SearchableModel是db.Model的子类要使用SearchableModel, 你的model必须从SearchableModel继承, 而不是db.Model; 你可以使用query方法search:<br>&nbsp;&nbsp; query = Article.all().search("sausages cheese dogs")<br><a href="http://appengineguy.com">App Engine Guy</a>在blog中说明了<a href="http://appengineguy.com/2008/06/how-to-full-text-search-in-google-app.html">怎么使用SearchableModel</a><br><br>目前Search API还很简单, 只有精确匹配, 没有短语, 没有语法变化, 也不支持Stop words, 更没有文档. Google应该在接下来的release中逐步增强这个功能, 毕竟Search是google的强项, 不能想象gogole的web hosting平台没有search支持. 让我们拭目以待吧.<br><br>我的Google App Engine随笔:<br><a href="/kuber/archive/2008/07/23/1249617.html">Google App Engine 未公开的Search API</a><br><a href="/kuber/archive/2008/07/01/1232717.html">Google App Engine 中数据库(DataStore)的限制</a><br><h2><a id="AjaxHolder_ctl01_TitleUrl" class="singleposttitle" href="/kuber/archive/2008/07/01/1232717.html"><br></a></h2><br><img src ="http://www.cnblogs.com/kuber/aggbug/1249617.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41284/" target="_blank">[新闻]奇虎回应:瑞星半年免费版像是一个恶意软件</a>]]></description></item><item><title>Does Chinese deserve it?</title><link>http://www.cnblogs.com/kuber/archive/2008/07/02/1233911.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Wed, 02 Jul 2008 04:55:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/07/02/1233911.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1233911.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/07/02/1233911.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1233911.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1233911.html</trackback:ping><description><![CDATA[在<a href="http://freenetproject.org/">FreeNet</a>的首页上看到这样一句话:<i><br>
"I worry about my child and the Internet all the time, even though
she's too young to have logged on yet. Here's what I worry about. I
worry that 10 or 15 years from now, she will come to me and say 'Daddy,
where were you when they took freedom of the press away from the
Internet?'"<br>
<br>
</i>扪心自问, 我很惭愧. <i>I deserve it. We deserve it.<br>
</i><img src ="http://www.cnblogs.com/kuber/aggbug/1233911.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41283/" target="_blank">[新闻]鲍尔默致员工信：部署09年微软5大工作重心</a>]]></description></item><item><title>Google App Engine 中数据库(DataStore)的限制</title><link>http://www.cnblogs.com/kuber/archive/2008/07/01/1232717.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Tue, 01 Jul 2008 01:19:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/07/01/1232717.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1232717.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/07/01/1232717.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1232717.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1232717.html</trackback:ping><description><![CDATA[做了一个GAE的应用,&nbsp; 在使用Datastore时碰到很多问题. Datastore有很多限制, 和以前使用的关系型数据库不同.&nbsp; 自己总结了一下, 以免以后自己忘记了. :-)<br>本文不是介绍怎么使用Google App Engine Datastore API. <br><br>任何查询都只能返回Entity, 所以必须Select * From SomeEntity. 不能只返回某些字段<br><br>GQL.fetch()可以带limit和offset参数, 返回从指定位置开始的指定条数记录. 但是, 其实datastore返回了offset+limit条记录, 只是在fetch方法中跳过offset条记录, 只返回最后limit条记录; 这一点不像通常的RMDB. 分页时我们经常会用到类似功能, 因此使用fetch(limit, offset)的话效率会是问题. <br><br>GQL.fetch()最多只返回1000条记录, 不管你把limit值设多大. 应该是出于性能的考虑<br><br>痛苦的Count, 在Groups里面被说的最多的Count: 不象在RMDB里面, count()方法其实是把所有符合条件的记录都读出来再算, 因此性能是个大问题. 出于性能考虑Google文档不建议你多使用count, 不建议在可能数据量很大的查询上用count(). <br><br>count()最多也只能返回1000. 原因同fetch(). <br><br>关于count(), Group里面讨论了很多解决方法. 一般是建议你自己实现count(): 在数据库中创建几个计数器, 创建新entity时随机拿出一个计数器加一. 把几个计数器的值相加, 就是最终的count值;<br><br>事务中所有的entity必须在一个entity group中, 事务中不能有select 查询<br><br>非等式过滤条件只能在一个属性(或字段)上. 以下查询就不可以<br><font size="1" color="#a52a2a">SELECT * FROM Person WHERE birth_year &gt;= :min_year<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND height &gt;= :min_height</font><br>你只能对birth_year属性用不等式<br><font size="1" color="#a52a2a">SELECT * FROM Person WHERE birth_year &gt;= :min<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND birth_year &lt;= :max</font><br>&nbsp;&nbsp;&nbsp; &nbsp;<br>如果查询中有不等式,并且有Order By, 不等式查询的字段必须第一个被order by; 以下这两个查询都是错误的:<br><font color="#a52a2a"><font size="1">SELECT * FROM Person WHERE birth_year &gt;= :min_year<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ORDER BY last_name, birth_year"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>SELECT * FROM Person WHERE birth_year &gt;= :min_year<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ORDER BY last_name&nbsp;&nbsp;&nbsp;</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>这个才行: <font size="1" color="#a52a2a">SELECT * FROM Person WHERE birth_year &gt;= :min_year<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ORDER BY birth_year, last_name</font><br><br>看到这么多限制, 是不是觉得很奇怪. Google就拿这么个东西出来现眼吗? Google的解释是这是为了datastore的伸缩性(Scalability). 我的猜测是每个创建的entity会被随机的保存在成百上千的servers中的某个server node上, 使得数据库中aggregation计算代价非常高, 所以更多的计算会被推到app层. 同样的, 事务中所有的entity必须在一个entity group中也是要保证事务中的entity在一个node(或cluster)上. 这仅仅是我的猜想. 有谁知道得更多请留言;<img src ="http://www.cnblogs.com/kuber/aggbug/1232717.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41282/" target="_blank">[新闻]陈一舟:Facebook也抄袭过校内 不怕打官司</a>]]></description></item><item><title>Google新推出Google Media Server</title><link>http://www.cnblogs.com/kuber/archive/2008/06/30/GoogleMediaServer.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Mon, 30 Jun 2008 07:56:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/06/30/GoogleMediaServer.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1232516.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/06/30/GoogleMediaServer.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1232516.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1232516.html</trackback:ping><description><![CDATA[摘要: Google Desktop上个礼拜发布了一个新Gadget, Google Media Server. 这个软件能自动识别连接到PC上的UPnP媒体设备(PC, XBox, PSP), 播放这些设备上的影音文件. 而且如果你的电视机也支持 UPnP并连接到PC了, 你就可以电视机上观看这些东东. &nbsp;&nbsp;<a href='http://www.cnblogs.com/kuber/archive/2008/06/30/GoogleMediaServer.html'>阅读全文</a><img src ="http://www.cnblogs.com/kuber/aggbug/1232516.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41281/" target="_blank">[新闻]微软重组视窗与在线业务</a>]]></description></item><item><title>Slope One 之二: C#实现</title><link>http://www.cnblogs.com/kuber/archive/2008/06/18/1224725.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Wed, 18 Jun 2008 09:54:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/06/18/1224725.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1224725.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/06/18/1224725.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1224725.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1224725.html</trackback:ping><description><![CDATA[<a href="/kuber/archive/2008/06/10/1216846.html">上一篇</a>简单介绍了Slope One算法的概念, 这次介绍C#实现<br>使用基于Slope One算法的推荐需要以下数据: <br>
1. 有一组用户<br>
2. 有一组Items(文章, 商品等)<br>
3. 用户会对其中某些项目打分(Rating)表达他们的喜好<br>
Slope One算法要解决的问题是, 对某个用户, 已知道他对其中一些Item的Rating了, 向他推荐一些他还没有Rating的Items, 以增加销售机会. :-)<br>
<br>
一个推荐系统的实现包括以下三步:<br>
1. 计算出任意两个Item之间Rating的差值<br>
2. 输入某个用户的Rating记录, 推算出对其它Items的可能Rating值<br>
3. 根据Rating的值排序, 给出Top Items;<br>
<br>第一步:例如我们有三个用户和4个Items, 用户打分的情况如下表.<br>

 <table x:str="" style="border-collapse: collapse; width: 262pt;" width="349" border="1" cellpadding="0" cellspacing="0"><col style="width: 54pt;" width="72">
 <col style="width: 100pt;" width="133">
 <col style="width: 54pt;" span="2" width="72">
 <tbody><tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="height: 14.25pt; width: 54pt;" width="72" height="19">Ratings</td>
  <td class="xl24" style="border-left: medium none; width: 100pt;" width="133">User1</td>
  <td class="xl24" style="border-left: medium none; width: 54pt;" width="72">User2</td>
  <td class="xl24" style="border-left: medium none; width: 54pt;" width="72">User3</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">5</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">4</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">5</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">4</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">N/A</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">N/A</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">5</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">5</td>
 </tr>
</tbody></table><br>
在第一步中我们的工作就是计算出Item之间两两的打分之差, 也就是使说计算出以下矩阵:<br>
 <table x:str="" style="border-collapse: collapse; width: 316pt;" width="421" border="1" cellpadding="0" cellspacing="0"><col style="width: 54pt;" width="72">
 <col style="width: 100pt;" width="133">
 <col style="width: 54pt;" span="3" width="72">
 <tbody><tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="height: 14.25pt; width: 54pt;" width="72" height="19">　</td>
  <td class="xl24" style="border-left: medium none; width: 100pt;" width="133">Item1</td>
  <td class="xl24" style="border-left: medium none; width: 54pt;" width="72">Item2</td>
  <td class="xl24" style="border-left: medium none; width: 54pt;" width="72">Item3</td>
  <td class="xl24" style="border-left: medium none; width: 54pt;" width="72">Item4</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">N/A</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">0/3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">2/2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">-2/2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">0/3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">N/A</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">2/2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">-1/2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">-2/2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">-2/2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">N/A</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">-2/1</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">2/2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">1/2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">2/1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;">N/A</td>
 </tr>
</tbody></table><br>
<br>
考虑到加权算法, 还要记录有多少人对这两项打了分(Freq), 我们先定义一个结构来保存Rating:<br>
&nbsp;&nbsp;&nbsp; public class Rating<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public float Value { get; set; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int Freq { get; set; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public float AverageValue<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get {return Value / Freq;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
我决定用一个Dictionary来保存这个结果矩阵:<br>
&nbsp;&nbsp;&nbsp; public class RatingDifferenceCollection : Dictionary&lt;string, Rating&gt;<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private string GetKey(int Item1Id, int Item2Id)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Item1Id + "/" + Item2Id;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public bool Contains(int Item1Id, int Item2Id)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.Keys.Contains&lt;string&gt;(GetKey(Item1Id, Item2Id));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Rating this[int Item1Id, int Item2Id]<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this[this.GetKey(Item1Id, Item2Id)];<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set { this[this.GetKey(Item1Id, Item2Id)] = value; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>接下来我们来实现SlopeOne类. 首先创建一个RatingDifferenceCollection来保存矩阵, 还要创建HashSet来保持系统中总共有哪些Items:<br>&nbsp;&nbsp;&nbsp; public class SlopeOne<br>&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public RatingDifferenceCollection _DiffMarix = new RatingDifferenceCollection();&nbsp; // The dictionary to keep the diff matrix<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public HashSet&lt;int&gt; _Items = new HashSet&lt;int&gt;();&nbsp; // Tracking how many items totally<br><br>方法AddUserRatings接收一个用户的打分记录(Item-Rating): public void AddUserRatings(IDictionary&lt;int, float&gt; userRatings)<br>AddUserRatings中有两重循环, 外层循环遍历输入中的所有Item, 内层循环再遍历一次, 计算出一对Item之间Rating的差存入_DiffMarix, 记得Freq加1, 以记录我们又碰到这一对Items一次:<br>&nbsp;&nbsp;&nbsp; Rating ratingDiff = _DiffMarix[item1Id, item2Id];<br>&nbsp;&nbsp;&nbsp; ratingDiff.Value += item1Rating - item2Rating;<br>&nbsp;&nbsp;&nbsp; ratingDiff.Freq += 1;<br><br>对每个用户调用AddUserRatings后, 建立起矩阵. 但我们的矩阵是以表的形式保存:<br>
 <table x:str="" style="border-collapse: collapse; width: 208pt;" width="277" border="1" cellpadding="0" cellspacing="0"><col style="width: 54pt;" width="72">
 <col style="width: 100pt;" width="133">
 <col style="width: 54pt;" width="72">
 <tbody><tr style="height: 14.25pt;" height="19">
  <td class="xl26" style="height: 14.25pt; width: 54pt;" width="72" height="19">　</td>
  <td class="xl27" style="border-left: medium none; width: 100pt;" width="133">Rating Dif</td>
  <td class="xl27" style="border-left: medium none; width: 54pt;" width="72">Freq</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item1-2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">0</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">3</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item1-3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item2-1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">0</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">3</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item2-3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item3-1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">-1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item3-2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">-1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item1-4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">-1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item2-4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">-0.5</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item3-4</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">-2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">1</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item4-1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">1</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item4-2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">0.5</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
 </tr>
 <tr style="height: 14.25pt;" height="19">
  <td class="xl24" style="border-top: medium none; height: 14.25pt;" height="19">Item4-3</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">2</td>
  <td class="xl25" style="border-top: medium none; border-left: medium none;" x:num="" align="right">1</td>
 </tr>
</tbody></table><br><br>第二步:输入某个用户的Rating记录, 推算出对其它Items的可能Rating值:<br>public IDictionary&lt;int, float&gt; Predict(IDictionary&lt;int, float&gt; userRatings)<br>也是两重循环, 外层循环遍历_Items中所有的Items; 内层遍历userRatings, 用此用户的ratings结合第一步得到的矩阵, 推算此用户对系统中每个项目的Rating:<br>&nbsp;&nbsp;&nbsp; Rating itemRating = new Rating(); // Prediction of this user's rating <br>&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp; Rating diff = _DiffMarix[itemId, inputItemId]:<br>&nbsp;&nbsp;&nbsp; itemRating.Value += diff.Freq * (diff.AverageValue + userRating.Value);<br>&nbsp;&nbsp;&nbsp; itemRating.Freq += diff.Freq;<br><br>第三步:得到用户的Rating预测后,就可以按rating排序, 向用户推荐了. 测试一下:<br>&nbsp;&nbsp;&nbsp; Dictionary&lt;int, float&gt; userRating userRating = new Dictionary&lt;int, float&gt;();<br>&nbsp;&nbsp;&nbsp; userRating.Add(1, 5);<br>&nbsp;&nbsp;&nbsp; userRating.Add(3, 4);<br>&nbsp;&nbsp;&nbsp; IDictionary&lt;int, float&gt; Predictions = test.Predict(userRating);<br>&nbsp;&nbsp;&nbsp; foreach (var rating in Predictions)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("Item " + rating.Key + " Rating: " + rating.Value);<br>&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; <br>输出:<br>Item 2 Rating: 5<br>Item 4 Rating: 6<br><br>改进:<br>观察之前产生的矩阵可以发现, 其中有很多浪费的空间; 例如: 对角线上永远是不会有值的. 因为我们是用线性表保存矩阵值, 已经避免了这个问题;<br>对角线下方的值和对角线上方的值非常对称,下方的值等于上方的值乘以-1; 在数据量很大的时候是很大的浪费. 我们可以通过修改RatingDifferenceCollection来完善. 可以修改GetKey方法, 用Item Pair来作为Key:<br>&nbsp;&nbsp;&nbsp; private string GetKey(int Item1Id, int Item2Id) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (Item1Id &lt; Item2Id) ? Item1Id + "/" + Item2Id : Item2Id + "/" + Item1Id ;;<br>&nbsp;&nbsp;&nbsp; }<br>完整代码在<a href="/kuber/articles/SlopeOne_CSharp.html">这里</a>,在.net 3.5上调试通过;<br><strong>参考资料</strong><br> <a href="http://www.serpentine.com/blog/2006/12/12/collaborative-filtering-made-easy/">tutorial about how to implement Slope One in Python</a><br>
<img src ="http://www.cnblogs.com/kuber/aggbug/1224725.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41280/" target="_blank">[新闻]我国网民数达2.53亿超美国居世界首位</a>]]></description></item><item><title>C# Implement of Slope One </title><link>http://www.cnblogs.com/kuber/articles/SlopeOne_CSharp.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Wed, 18 Jun 2008 08:57:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/articles/SlopeOne_CSharp.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1224800.html</wfw:comment><comments>http://www.cnblogs.com/kuber/articles/SlopeOne_CSharp.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1224800.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1224800.html</trackback:ping><description><![CDATA[Here's the source code of my C# implementation of Weighted Slope One. Tested on .net 3.5; The instruction in Chinese can be find <a href="/kuber/archive/2008/06/10/1216846.html">here</a> and <a href="/kuber/archive/2008/06/18/1224725.html">here</a>.<br>Reference:<br><a href="http://www.serpentine.com/blog/2006/12/12/collaborative-filtering-made-easy/">Tutorial about how to implement Slope One in Python</a><br><a href="http://www.daniel-lemire.com/fr/abstracts/SDM2005.html">Slope One Predictors for Online Rating-Based Collaborative Filtering</a><br><a href="http://www.guwendong.cn/post/2007/slope_one_algorithm.html">Recommender
Systems: Slope One</a><br><br><br>using System;<br>using System.Collections.Generic;<br>using System.Linq;<br>using System.Text;<br><br>namespace SlopeOne<br>{<br>&nbsp;&nbsp;&nbsp; public class Rating<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public float Value { get; set; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int Freq { get; set; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public float AverageValue<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get { return Value / Freq; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; public class RatingDifferenceCollection : Dictionary&lt;string, Rating&gt;<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private string GetKey(int Item1Id, int Item2Id)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (Item1Id &lt; Item2Id) ? Item1Id + "/" + Item2Id : Item2Id + "/" + Item1Id ;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public bool Contains(int Item1Id, int Item2Id)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.Keys.Contains&lt;string&gt;(GetKey(Item1Id, Item2Id));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Rating this[int Item1Id, int Item2Id]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this[this.GetKey(Item1Id, Item2Id)];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set { this[this.GetKey(Item1Id, Item2Id)] = value; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp; public class SlopeOne<br>&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public RatingDifferenceCollection _DiffMarix = new RatingDifferenceCollection();&nbsp; // The dictionary to keep the diff matrix<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public HashSet&lt;int&gt; _Items = new HashSet&lt;int&gt;();&nbsp; // Tracking how many items totally<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void AddUserRatings(IDictionary&lt;int, float&gt; userRatings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (var item1 in userRatings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int item1Id = item1.Key;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float item1Rating = item1.Value;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _Items.Add(item1.Key);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (var item2 in userRatings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (item2.Key &lt;= item1Id) continue; // Eliminate redundancy<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int item2Id = item2.Key;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float item2Rating = item2.Value;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rating ratingDiff;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (_DiffMarix.Contains(item1Id, item2Id))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ratingDiff = _DiffMarix[item1Id, item2Id];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ratingDiff = new Rating();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _DiffMarix[item1Id, item2Id] = ratingDiff;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ratingDiff.Value += item1Rating - item2Rating;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ratingDiff.Freq += 1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Input ratings of all users<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void AddUerRatings(IList&lt;IDictionary&lt;int, float&gt;&gt; Ratings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach(var userRatings in Ratings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AddUserRatings(userRatings);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public IDictionary&lt;int, float&gt; Predict(IDictionary&lt;int, float&gt; userRatings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dictionary&lt;int, float&gt; Predictions = new Dictionary&lt;int, float&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (var itemId in this._Items)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (userRatings.Keys.Contains(itemId))&nbsp;&nbsp;&nbsp; continue; // User has rated this item, just skip it<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rating itemRating = new Rating();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (var userRating in userRatings)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (userRating.Key == itemId) continue;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int inputItemId = userRating.Key;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (_DiffMarix.Contains(itemId, inputItemId))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rating diff = _DiffMarix[itemId, inputItemId];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; itemRating.Value += diff.Freq * (userRating.Value + diff.AverageValue * ((itemId &lt; inputItemId) ? 1 : -1));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; itemRating.Freq += diff.Freq;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Predictions.Add(itemId, itemRating.AverageValue);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Predictions;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void Test()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SlopeOne test = new SlopeOne();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dictionary&lt;int, float&gt; userRating = new Dictionary&lt;int, float&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(1, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(2, 4);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(3, 4);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test.AddUserRatings(userRating);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating = new Dictionary&lt;int, float&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(1, 4);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(2, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(3, 3);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(4, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test.AddUserRatings(userRating);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating = new Dictionary&lt;int, float&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(1, 4);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(2, 4);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(4, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test.AddUserRatings(userRating);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating = new Dictionary&lt;int, float&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(1, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userRating.Add(3, 4);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IDictionary&lt;int, float&gt; Predictions = test.Predict(userRating);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (var rating in Predictions)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("Item " + rating.Key + " Rating: " + rating.Value);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br><br><img src ="http://www.cnblogs.com/kuber/aggbug/1224800.html?type=2" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41280/" target="_blank">[新闻]我国网民数达2.53亿超美国居世界首位</a>]]></description></item><item><title>TinyURL的API</title><link>http://www.cnblogs.com/kuber/archive/2008/06/16/1222970.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Mon, 16 Jun 2008 04:37:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/06/16/1222970.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1222970.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/06/16/1222970.html#Feedback</comments><slash:comments>16</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1222970.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1222970.html</trackback:ping><description><![CDATA[<a href="http://tinyurl.com/">
TinyURL</a>是一个很有用的Web服务, 把你冗长的URL缩短成简单的地址, 比如说这个地址: http://www.cnblogs.com/kuber/archive/2008/06/10/1216846.html, 可以变成http://tinyurl.com/3umgrz. 这个例子可能太短了, 如果你有这样一个地址, 并且想发给朋友呢: http://www.amazon.cn/mn/detailApp?qid=1213590566&amp;ref=SR&amp;sr=1-1&amp;uid=168-6604802-9891462&amp;prodid=bkbk831097? 相信博客园的朋友很多都用过这个东东. <br>
<br>
要创建你的tiny url,可以在它的主页去, 输入你的源url. 但是有时候希望在程序中能自动创建, 就需要调用它的接口了. 象Live Writer<a href="http://livesino.net/archives/972.live">这个插件</a>http://livesino.net/archives/972.live, 当发布了一篇日志之后，这个插件使用了 <a href="http://tinyurl.com/">
TinyURL</a> 的服务来缩短日志地址并发到 Twitter让关注你 Twitter 的好友了解最新的日志。<br>
<br>
网上有一些第三方的api, 但其实TinyURL自己开放了一个API, 不知道为什么在它的主页上没有链接. 有知道的同学吱个声.<br>
<br>
API很简单, 调用:http://tinyurl.com/api-create.php?url=http://myURL,&nbsp; 你可以发送一个request到这个地址, Response中只有一个字符串,就是你的tiny url; 很简单吧.<br>
<img src ="http://www.cnblogs.com/kuber/aggbug/1222970.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41278/" target="_blank">[新闻]瑞星炮轰奇虎用阉割版杀毒软件欺骗用户</a>]]></description></item><item><title>Slope One :简单高效的协同过滤算法(Collaborative Filtering) </title><link>http://www.cnblogs.com/kuber/archive/2008/06/10/1216846.html</link><dc:creator>kuber</dc:creator><author>kuber</author><pubDate>Tue, 10 Jun 2008 09:37:00 GMT</pubDate><guid>http://www.cnblogs.com/kuber/archive/2008/06/10/1216846.html</guid><wfw:comment>http://www.cnblogs.com/kuber/comments/1216846.html</wfw:comment><comments>http://www.cnblogs.com/kuber/archive/2008/06/10/1216846.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cnblogs.com/kuber/comments/commentRss/1216846.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/kuber/services/trackbacks/1216846.html</trackback:ping><description><![CDATA[现在做的一个项目中需要用到推荐算法, 在网上查了一下. <a href="http://www.guwendong.cn/catalog.asp?cate=1">Beyond Search介绍了一个协同过滤算法(Collaborative Filtering)</a> : Slope One;和其它类似算法相比, 它的最大优点在于算法很简单, 易于实现, 执行效率高, 同时推荐的准确性相对很高; <br>
<br>
<strong>基本概念</strong><br>
Slope One的基本概念很简单, 例子1, 用户X, Y和A都对Item1打了分. 同时用户X,Y还对Item2打了分, 用户A对Item2可能会打多少分呢?<br>
<table x:str="" style="border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0" height="130" width="452">
    <col style="width: 54pt;" width="72">
    <col style="width: 131pt;" width="174">
    <col style="width: 121pt;" width="161">
    <tbody>
        <tr style="height: 14.25pt;" height="19">
            <td class="xl24" style="height: 14.25pt; width: 54pt;" height="19" width="72">User</td>
            <td class="xl24" style="width: 131pt;" width="174">Rating to Item
            1</td>
            <td class="xl24" style="width: 121pt;" width="161">Rating to Item
            2</td>
        </tr>
        <tr style="height: 14.25pt;" height="19">
            <td class="xl22" style="height: 14.25pt;" height="19">X</td>
            <td class="xl23" x:num="">5</td>
            <td class="xl23" x:num="">3</td>
        </tr>
        <tr style="height: 14.25pt;" height="19">
            <td class="xl22" style="height: 14.25pt;" height="19">Y</td>
            <td class="xl23" x:num="">4</td>
            <td class="xl23" x:num="">3</td>
        </tr>
        <tr style="height: 14.25pt;" height="19">
            <td class="xl22" style="height: 14.25pt;" height="19">A</td>
            <td class="xl23" x:num="">4</td>
            <td class="xl23">?</td>
        </tr>
    </tbody>
</table>
<br>
根据SlopeOne算法, 应该是:4 - ((5-3) + (4-2))/2 = 2.5. <br>
解释一下. 用户X对Item1的rating是5, 对Item2的rating是3, 那么他可能认为Item2应该比Item1少两分. 同时用户Y认为Item2应该比Item1少1分. 据此我们知道所有对Item1和Item2都打了分的用户认为Item2会比Item1平均少1.5分. 所以我们有理由推荐用户A可能会对Item2打(4-1.5)=2.5分;<br>
<br>
很简单是不是? 找到对Item1和Item2都打过分的用户, 算出rating差的平均值, 这样我们就能推测出对Item1打过分的用户A对Item2的可能Rating, 并据此向A用户推荐新项目.<br>
这里我们能看出Slope One算法的一个很大的优点, 在只有很少的数据时候也能得到一个相对准确的推荐, 这一点可以解决Cold Start的问题.<br>
<br>
<strong>加权算法</strong><br>
接下来我们看看加权算法(Weighted Slope One). 如果有100个用户对Item1和Item2都打过分, 有1000个用户对Item3和Item2也打过分. 显然这两个rating差的权重是不一样的. 因此我们的计算方法是<br>
(100*(Rating 1 to 2) + 1000(Rating 3 to 2)) / (100 + 1000)<br>
<br>
上面讨论的是用户只对项目的喜好程度打分.还有一种情况下用户也可以对项目的厌恶程度打分. 这时可以使用双极SlopeOne算法(BI-Polar SlopeOne). 我还在研究这篇论文,搞懂了再写吧, 呵呵;<br>
<br>
<strong>参考资料</strong><br>
Slope One 算法是由 Daniel Lemire 教授在 2005 年提出. <a href="http://www.daniel-lemire.com/fr/abstracts/SDM2005.html">这里可以找到论文原文(PDF)</a>;上面也列出了几个参考实现. 现在有Python, Java和Erlang, 还没有C#.<br>
这篇: <a href="http://www.serpentine.com/blog/2006/12/12/collaborative-filtering-made-easy/">tutorial about how to implement Slope One in Python</a>是一个很好的怎么实现SlopeOne并使用它来推荐的例子. 但是现在好像不能访问了 :-(&nbsp; 参考这篇文章, 我会在下一篇用C#代码讲解怎么实现Weighted Slope One;<br>
<img src ="http://www.cnblogs.com/kuber/aggbug/1216846.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41277/" target="_blank">[新闻]阿里巴巴正式成立台湾分公司</a>]]></description></item></channel></rss>