探索推荐引擎内部的秘密”系列将带领读者从浅入深的学习探索推荐引擎的机制,实现方法,其中还涉及一些基本的优化方法,例如聚类和分类的应用。同时在理论讲解的基础上,还会结合 Apache Mahout 介绍如何在大规模数据上实现各种推荐策略,进行策略优化,构建高效的推荐引擎的方法。本文作为这个系列的第一篇文章,将深入介绍推荐引擎的工作原理,和其中涉及的各种推荐机制,以及它们各自的优缺点和适用场景,帮助用户清楚的了解和快速构建适合自己的推荐引擎。
信息发现
如今已经进入了一个数据爆炸的时代,随着 Web 2.0 的发展, Web 已经变成数据分享的平台,那么,如何让人们在海量的数据中想要找到他们需要的信息将变得越来越难。
在这样的情形下,搜索引擎(Google,Bing,百度等等)成为大家快速找到目标信息的最好途径。在用户对自己需求相对明确的时候,用搜索引擎很方便的通过关键字搜索很快的找到自己需要的信息。但搜索引擎并不能完全满足用户对信息发现的需求,那是因为在很多情况下,用户其实并不明确自己的需要,或者他们的需求很难用简单的关键字来表述。又或者他们需要更加符合他们个人口味和喜好的结果,因此出现了推荐系统,与搜索引擎对应,大家也习惯称它为推荐引擎。
随着推荐引擎的出现,用户获取信息的方式从简单的目标明确的数据的搜索转换到更高级更符合人们使用习惯的信息发现。
如今,随着推荐技术的不断发展,推荐引擎已经在电子商务 (E-commerce,例如 Amazon,当当网 ) 和一些基于 social 的社会化站点 ( 包括音乐,电影和图书分享,例如豆瓣,Mtime 等 ) 都取得很大的成功。这也进一步的说明了,Web2.0 环境下,在面对海量的数据,用户需要这种更加智能的,更加了解他们需求,口味和喜好的信息发现机制。
回页首
推荐引擎
前面介绍了推荐引擎对于现在的 Web2.0 站点的重要意义,这一章我们将讲讲推荐引擎到底是怎么工作的。推荐引擎利用特殊的信息过滤技术,将不同的物品或内容推荐给可能对它们感兴趣的用户。
图 1. 推荐引擎工作原理图
图 1 给出了推荐引擎的工作原理图,这里先将推荐引擎看作黑盒,它接受的输入是推荐的数据源,一般情况下,推荐引擎所需要的数据源包括:
- 要推荐物品或内容的元数据,例如关键字,基因描述等;
- 系统用户的基本信息,例如性别,年龄等
- 用户对物品或者信息的偏好,根据应用本身的不同,可能包括用户对物品的评分,用户查看物品的记录,用户的购买记录等。其实这些用户的偏好信息可以分为两类:
- 显式的用户反馈:这类是用户在网站上自然浏览或者使用网站以外,显式的提供反馈信息,例如用户对物品的评分,或者对物品的评论。
- 隐式的用户反馈:这类是用户在使用网站是产生的数据,隐式的反应了用户对物品的喜好,例如用户购买了某物品,用户查看了某物品的信息等等。
显式的用户反馈能准确的反应用户对物品的真实喜好,但需要用户付出额外的代价,而隐式的用户行为,通过一些分析和处理,也能反映用户的喜好,只是数据不是很精确,有些行为的分析存在较大的噪音。但只要选择正确的行为特征,隐式的用户反馈也能得到很好的效果,只是行为特征的选择可能在不同的应用中有很大的不同,例如在电子商务的网站上,购买行为其实就是一个能很好表现用户喜好的隐式反馈。
推荐引擎根据不同的推荐机制可能用到数据源中的一部分,然后根据这些数据,分析出一定的规则或者直接对用户对其他物品的喜好进行预测计算。这样推荐引擎可以在用户进入的时候给他推荐他可能感兴趣的物品。
推荐引擎的分类
推荐引擎的分类可以根据很多指标,下面我们一一介绍一下:
根据这个指标,推荐引擎可以分为基于大众行为的推荐引擎和个性化推荐引擎
C4.5决策树在ID3决策树的基础之上稍作改进,请先阅读ID3决策树。
C4.5克服了ID3的2个缺点:
1.用信息增益选择属性时偏向于选择分枝比较多的属性值,即取值多的属性
2.不能处理连贯属性
Outlook Temperature Humidity Windy PlayGolf? sunny 85 85 FALSE no sunny 80 90 TRUE no overcast 83 86 FALSE yes注册表实现,只需要修改几个关键的注册表项就可以了。
第一项:启用代理的注册表项。
第二项:代理的IP和端口。
第三项:连接的方式。
第四项:让注册表项立即生效。严格来说,这一步并没有修改注册表项,而是调用API通知注册表项生效。
下面是相关代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.Diagnostics; using Microsoft.Win32; namespace UtilSp.ClassLib { public class ProxySp { [DllImport("wininet.dll", SetLastError = true)] private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int lpdwBufferLength); private const int INTERNET_OPTION_REFRESH = 37; private const int INTERNET_OPTION_PROXY = 38; private const int INTERNET_OPTION_SETTINGS_CHANGED = 39; private const int INTERNET_OPEN_TYPE_PROXY = 3; private const int INTERNET_OPEN_TYPE_DIRECT = 1; #region changeUserAgent Function public static void changeUserAgent() { var appName = Process.GetCurrentProcess().MainModule.ModuleName; RegeditSp.write(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION", appName, 9999, RegistryValueKind.DWord); } #endregion #region setProxyEnabled Function /// <summary> /// Set proxy. /// </summary> /// <param name="isProxyEnabled">true:is enabled.false:is not enabled.</param> /// <param name="proxyIP">Proxy ip and port.Format:192.168.100.162:8080</param> /// <returns></returns> public static bool setProxy(bool isProxyEnabled, string proxyIP = "") { string regPath = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";//Enabled proxy option. bool isSetProxyEnabledOk = RegeditSp.write(RegeditSp.REGEDIT_ROOT_SET.HKEY_CURRENT_USER, regPath, "ProxyEnable", isProxyEnabled ? 1 : 0, true); bool isSetProxyIP = true; if (!string.IsNullOrEmpty(proxyIP)) { isSetProxyIP = RegeditSp.write(RegeditSp.REGEDIT_ROOT_SET.HKEY_CURRENT_USER, regPath, "ProxyServer", proxyIP, true); } bool isConnectionOK=setConnection(isProxyEnabled, proxyIP); bool isNotifyOk = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);//Notify proxy in the regedit has changed.Lanuch proxy when connect next. bool isReadOK = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);//Read proxy from regedit. return isSetProxyEnabledOk && isSetProxyIP && isNotifyOk && isReadOK && isConnectionOK; } #endregion #region setConnection Function private static bool setConnection(bool isProxyEnabled, string proxyIP) { string regPath = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Connections";//Connection register option. byte[] szBuf = new byte[80]; szBuf[0] = 0x3c; szBuf[4] = 0x09; szBuf[8] = (byte)(isProxyEnabled ? 0x03 : 0x01); szBuf[12] = (byte)proxyIP.Length; for (int i = 0; i < proxyIP.Length; i++) { szBuf[i + 16] =(byte)Convert.ToInt32(proxyIP[i]); } string local = "<local>"; for (int j = 0; j < 7; j++) { szBuf[20 + proxyIP.Length + j] = (byte)Convert.ToInt32(local[j]); } return RegeditSp.write(RegeditSp.REGEDIT_ROOT_SET.HKEY_CURRENT_USER, regPath, "宽带连接", szBuf, true); } #endregion } }