<?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>超群.com的博客 &#187; Data Mining</title>
	<atom:link href="http://www.fuchaoqun.com/category/data-mining/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.fuchaoqun.com</link>
	<description></description>
	<lastBuildDate>Thu, 22 Jul 2010 23:31:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>一种比较省内存的稀疏矩阵Python存储方案</title>
		<link>http://www.fuchaoqun.com/2010/03/python-sparse-matrix/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=python-sparse-matrix</link>
		<comments>http://www.fuchaoqun.com/2010/03/python-sparse-matrix/#comments</comments>
		<pubDate>Sat, 13 Mar 2010 08:15:44 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[Data Mining]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[sparse matrix]]></category>

		<guid isPermaLink="false">http://www.fuchaoqun.com/?p=333</guid>
		<description><![CDATA[推荐系统中经常需要处理类似user_id, item_id, rating这样的数据，其实就是数学里面的稀疏矩阵，scipy中提供了sparse模块来解决这个问题，但scipy.sparse有很多问题不太合用：1、不能很好的同时支持data[i, ...]、data[..., j]、data[i, j]快速切片；2、由于数据保存在内存中，不能很好的支持海量数据处理。 要支持data[i, ...]、data[..., j]的快速切片，需要i或者j的数据集中存储；同时，为了保存海量的数据，也需要把数据的一部分放在硬盘上，用内存做buffer。这里的解决方案比较简单，用一个类Dict的东西来存储数据，对于某个i（比如9527），它的数据保存在dict['i9527']里面，同样的，对于某个j（比如3306），它的全部数据保存在dict['j3306']里面，需要取出data[9527, ...]的时候，只要取出dict['i9527']即可，dict['i9527']原本是一个dict对象，储存某个j对应的值，为了节省内存空间，我们把这个dict以二进制字符串形式存储，直接上代码： ''' Sparse Matrix ''' import struct import numpy as np import bsddb from cStringIO import StringIO &#160; class DictMatrix&#40;&#41;: def __init__&#40;self, container = &#123;&#125;, dft = 0.0&#41;: self._data = container self._dft = dft self._nums = 0 &#160; def __setitem__&#40;self, index, value&#41;: try: i, j = [...]]]></description>
			<content:encoded><![CDATA[<p>推荐系统中经常需要处理类似user_id, item_id, rating这样的数据，其实就是数学里面的稀疏矩阵，scipy中提供了sparse模块来解决这个问题，但scipy.sparse有很多问题不太合用：1、不能很好的同时支持data[i, ...]、data[..., j]、data[i, j]快速切片；2、由于数据保存在内存中，不能很好的支持海量数据处理。</p>
<p>要支持data[i, ...]、data[..., j]的快速切片，需要i或者j的数据集中存储；同时，为了保存海量的数据，也需要把数据的一部分放在硬盘上，用内存做buffer。这里的解决方案比较简单，用一个类Dict的东西来存储数据，对于某个i（比如9527），它的数据保存在dict['i9527']里面，同样的，对于某个j（比如3306），它的全部数据保存在dict['j3306']里面，需要取出data[9527, ...]的时候，只要取出dict['i9527']即可，dict['i9527']原本是一个dict对象，储存某个j对应的值，为了节省内存空间，我们把这个dict以二进制字符串形式存储，直接上代码：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
Sparse Matrix
'</span><span style="color: #483d8b;">''</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">struct</span>
<span style="color: #ff7700;font-weight:bold;">import</span> numpy <span style="color: #ff7700;font-weight:bold;">as</span> np
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">bsddb</span>
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">cStringIO</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">StringIO</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> DictMatrix<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, container = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>, dft = <span style="color: #ff4500;">0.0</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>._data  = container
        <span style="color: #008000;">self</span>._dft   = dft
        <span style="color: #008000;">self</span>._nums  = <span style="color: #ff4500;">0</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__setitem__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, index, value<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            i, j = index
        <span style="color: #ff7700;font-weight:bold;">except</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">IndexError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'invalid index'</span><span style="color: black;">&#41;</span>
&nbsp;
        ik = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'i%d'</span> <span style="color: #66cc66;">%</span> i<span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># 为了节省内存，我们把j, value打包成字二进制字符串</span>
        ib = <span style="color: #dc143c;">struct</span>.<span style="color: black;">pack</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'if'</span>, j, value<span style="color: black;">&#41;</span>
        jk = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'j%d'</span> <span style="color: #66cc66;">%</span> j<span style="color: black;">&#41;</span>
        jb = <span style="color: #dc143c;">struct</span>.<span style="color: black;">pack</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'if'</span>, i, value<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            <span style="color: #008000;">self</span>._data<span style="color: black;">&#91;</span>ik<span style="color: black;">&#93;</span> += ib
        <span style="color: #ff7700;font-weight:bold;">except</span>:
            <span style="color: #008000;">self</span>._data<span style="color: black;">&#91;</span>ik<span style="color: black;">&#93;</span> = ib
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            <span style="color: #008000;">self</span>._data<span style="color: black;">&#91;</span>jk<span style="color: black;">&#93;</span> += jb
        <span style="color: #ff7700;font-weight:bold;">except</span>:
            <span style="color: #008000;">self</span>._data<span style="color: black;">&#91;</span>jk<span style="color: black;">&#93;</span> = jb
        <span style="color: #008000;">self</span>._nums += <span style="color: #ff4500;">1</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__getitem__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, index<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            i, j = index
        <span style="color: #ff7700;font-weight:bold;">except</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">IndexError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'invalid index'</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: black;">&#40;</span><span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>i, <span style="color: #008000;">int</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
            ik = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'i%d'</span> <span style="color: #66cc66;">%</span> i<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">self</span>._data.<span style="color: black;">has_key</span><span style="color: black;">&#40;</span>ik<span style="color: black;">&#41;</span>: <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._dft
            ret = <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>np.<span style="color: black;">fromstring</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._data<span style="color: black;">&#91;</span>ik<span style="color: black;">&#93;</span>, dtype = <span style="color: #483d8b;">'i4,f4'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: black;">&#40;</span><span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>j, <span style="color: #008000;">int</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>: <span style="color: #ff7700;font-weight:bold;">return</span> ret.<span style="color: black;">get</span><span style="color: black;">&#40;</span>j, <span style="color: #008000;">self</span>._dft<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: black;">&#40;</span><span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>j, <span style="color: #008000;">int</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
            jk = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'j%d'</span> <span style="color: #66cc66;">%</span> j<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">self</span>._data.<span style="color: black;">has_key</span><span style="color: black;">&#40;</span>jk<span style="color: black;">&#41;</span>: <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._dft
            ret = <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>np.<span style="color: black;">fromstring</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._data<span style="color: black;">&#91;</span>jk<span style="color: black;">&#93;</span>, dtype = <span style="color: #483d8b;">'i4,f4'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">return</span> ret
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__len__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._nums
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__iter__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
    <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
    从文件中生成matrix
    考虑到dbm读写的性能不如内存，我们做了一些缓存，每1000W次批量写入一次
    考虑到字符串拼接性能不太好，我们直接用StringIO来做拼接
    '</span><span style="color: #483d8b;">''</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> from_file<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, fp, sep = <span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\t</span>'</span><span style="color: black;">&#41;</span>:
        cnt = <span style="color: #ff4500;">0</span>
        cache = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> l <span style="color: #ff7700;font-weight:bold;">in</span> fp:
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff4500;">10000000</span> == cnt:
                <span style="color: #008000;">self</span>._flush<span style="color: black;">&#40;</span>cache<span style="color: black;">&#41;</span>
                cnt = <span style="color: #ff4500;">0</span>
                cache = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
            i, j, v = <span style="color: black;">&#91;</span><span style="color: #008000;">float</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> l.<span style="color: black;">split</span><span style="color: black;">&#40;</span>sep<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
            ik = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'i%d'</span> <span style="color: #66cc66;">%</span> i<span style="color: black;">&#41;</span>
            ib = <span style="color: #dc143c;">struct</span>.<span style="color: black;">pack</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'if'</span>, j, v<span style="color: black;">&#41;</span>
            jk = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'j%d'</span> <span style="color: #66cc66;">%</span> j<span style="color: black;">&#41;</span>
            jb = <span style="color: #dc143c;">struct</span>.<span style="color: black;">pack</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'if'</span>, i, v<span style="color: black;">&#41;</span>
&nbsp;
            <span style="color: #ff7700;font-weight:bold;">try</span>:
                cache<span style="color: black;">&#91;</span>ik<span style="color: black;">&#93;</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span>ib<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">except</span>:
                cache<span style="color: black;">&#91;</span>ik<span style="color: black;">&#93;</span> = <span style="color: #dc143c;">StringIO</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
                cache<span style="color: black;">&#91;</span>ik<span style="color: black;">&#93;</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span>ib<span style="color: black;">&#41;</span>
&nbsp;
            <span style="color: #ff7700;font-weight:bold;">try</span>:
                cache<span style="color: black;">&#91;</span>jk<span style="color: black;">&#93;</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span>jb<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">except</span>:
                cache<span style="color: black;">&#91;</span>jk<span style="color: black;">&#93;</span> = <span style="color: #dc143c;">StringIO</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
                cache<span style="color: black;">&#91;</span>jk<span style="color: black;">&#93;</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span>jb<span style="color: black;">&#41;</span>
&nbsp;
            cnt += <span style="color: #ff4500;">1</span>
            <span style="color: #008000;">self</span>._nums += <span style="color: #ff4500;">1</span>
&nbsp;
        <span style="color: #008000;">self</span>._flush<span style="color: black;">&#40;</span>cache<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._nums
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _flush<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, cache<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> k,v <span style="color: #ff7700;font-weight:bold;">in</span> cache.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
            v.<span style="color: black;">seek</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
            s = v.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">try</span>:
                <span style="color: #008000;">self</span>._data<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span> += s
            <span style="color: #ff7700;font-weight:bold;">except</span>:
                <span style="color: #008000;">self</span>._data<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span> = s
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    db = <span style="color: #dc143c;">bsddb</span>.<span style="color: black;">btopen</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, cachesize = <span style="color: #ff4500;">268435456</span><span style="color: black;">&#41;</span>
    data = DictMatrix<span style="color: black;">&#40;</span>db<span style="color: black;">&#41;</span>
    data.<span style="color: black;">from_file</span><span style="color: black;">&#40;</span><span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/path/to/log.txt'</span>, <span style="color: #483d8b;">'r'</span><span style="color: black;">&#41;</span>, <span style="color: #483d8b;">','</span><span style="color: black;">&#41;</span></pre></div></div>

<p>测试4500W条rating数据（整形,整型,浮点格式），922MB文本文件导入，采用内存dict储存的话，12分钟构建完毕，消耗内存1.2G，采用示例代码中的bdb存储，20分钟构建完毕，占用内存300～400MB左右，比cachesize大不了多少，数据读取测试：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">timeit</span>
<span style="color: #dc143c;">timeit</span>.<span style="color: black;">Timer</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'foo = __main__.data[9527, ...]'</span>, <span style="color: #483d8b;">'import __main__'</span><span style="color: black;">&#41;</span>.<span style="color: #dc143c;">timeit</span><span style="color: black;">&#40;</span>number = <span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span></pre></div></div>

<p>消耗1.4788秒，大概读取一条数据1.5ms。</p>
<p>采用类Dict来存储数据的另一个好处是你可以随便用内存Dict或者其他任何形式的DBM，甚至传说中的Tokyo Cabinet&#8230;.</p>
<p>好的，码完收工。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2010/03/python-sparse-matrix/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>基于关联规则的推荐系统</title>
		<link>http://www.fuchaoqun.com/2010/02/recommendation-system-on-association-rules/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=recommendation-system-on-association-rules</link>
		<comments>http://www.fuchaoqun.com/2010/02/recommendation-system-on-association-rules/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 06:28:17 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[Data Mining]]></category>
		<category><![CDATA[association rules]]></category>
		<category><![CDATA[recommendation system]]></category>

		<guid isPermaLink="false">http://www.fuchaoqun.com/?p=305</guid>
		<description><![CDATA[首先，要了解关联规则的几个概念，定义N为总事务数，N(A)、N(B)分别为项集A、项集B出现的次数，N(AB)为项集A、项集B同时出现的次数，A、B为不相交项集A∩B=Ø，规则A→B表示由A推到B： 支持度（Support）： 支持度是一种重要度量，支持度低的规则很可能是偶然现象，对推荐意义不大，另外支持度是数据剪枝的一个重要依据。 置信度（Confidence）： 置信度，字面上的解释就是这个规则到底有多可信，对于给定的规则A→B，置信度越高，B出现在包含A的事务中的概率越高。 提升度（Lift）： Support(A→B)其实就是AB的联合概率P(AB)，Support(A) 、 Support(B)分别为A、B的概率估计P(A)、P(B)，如果A、B相互独立，则P(AB) = P(A) × P(B)，所以只有 Lift &#62; 1 才表示A、B正相关，且越大越好。 为什么要引入提升度的概念呢？还是拿歌曲来做例子，比如歌曲A、歌曲C为小众歌曲，歌曲B为口水歌，共有10万个用户，有200个人听过歌曲A，这200个人里面有60个听过口水歌B，有40个人听过歌曲C，同时听过歌曲C的人数是300，听过口水歌B的人为50000，那么Confidence(A→B) = 0.3，Confidence(A→C) = 0.2，从置信度来看貌似A和B更相关，但是10W人里面有5W听过歌曲B，说明有一半的用户都喜欢歌曲B，但听过歌曲A的人里面只有30%的人喜欢歌曲B，很明显歌曲A和歌曲B负相关，计算Lift(A→B) = 0.6，小于1，负相关，Lift(A→C) = 66.7，远大于1，正相关。 当然，还有一些其他的度量因子，可自行参阅其他文档。 可以进入正题了，我们要实验的是一个文学类的网站数据，数据格式如下： 用户ID 图书ID 表示此用户阅读过该图书，我们首先要解决的问题是：喜欢图书A的用户还喜欢其他哪些图书？（图书之间的相关性） 推荐流程： 数据清理：对用户和图书分别计数，过滤掉一些超不活跃的用户和超冷门的图书 计算两两图书之间的支持度、置信度、提升度，根据最低支持度、最低置信度、最低提升度剪枝，把低于最小值的规则扔掉 对图书A进行推荐：找出图书A的所有规则，按照置信度降序排序，Top-N即为和图书A最相关的前N本图书 非常简单，关键的就是数据清理以及规则剪枝设置，这需要对业务熟悉一些，提升度的话，如果不确认，大于1即可。 结果示例： 古龙:剑毒梅香(中) →古龙:剑毒梅香(上)&#124;古龙:剑毒梅香(下)&#124;武林第一少年:血欲江湖&#124;笑傲江湖之风清扬别传&#124;草根续写:天龙八部续 古龙:剑毒梅香(下) →古龙:剑毒梅香(中)&#124;古龙:剑毒梅香(上)&#124;武林第一少年:血欲江湖&#124;笑傲江湖之风清扬别传&#124;恐怖宿舍惊魂夜:女生寝室&#124;倚天屠龙记之复兴明教&#124;至尊武神:六脉神剑闹武林&#124;草根续写:天龙八部续 温瑞安：四大名捕猿猴月 → 四大名捕会京师:逆水寒&#124;温瑞安：四大名捕铁布衫&#124;四大名捕震关东－亡命&#124;四大名捕破神枪: 惨绿&#124;四大名捕破神枪－妖红&#124;四大名捕震关东－追杀&#124;温瑞安：四大名捕谈亭会&#124;温瑞安：四大名捕开谢花&#124;温瑞安：四大名捕碎梦刀&#124;四大名捕走龙蛇&#124;温瑞安：四大名捕猛鬼庙&#124;温瑞安神州奇侠:人世间 异界玄奇：尸池 → 荒村血鬼洞房:剥皮新娘&#124;真实恐怖:鬼宅小区&#124;丫鬟不好当:王爷,请自重&#124;人鬼恋:我的老婆不是人&#124;灵异事件全曝光:诡异档案&#124;恐怖的盗墓历险:荒村古墓&#124;校园僵尸&#124;古墓惊魂夜:坟岭村笔记&#124;阴阳眼之鬼瞳:荒道门&#124;极度恐怖乱坟头:墓地惊叫&#124;盗墓传说&#124;不解迷:殡仪馆里的化妆师&#124;凶尸宿舍惊魂声:猛鬼校园&#124;惊声尖叫:太平间美丽女尸&#124;生化疯狂撕杀之丧尸异形&#124;僵尸当街:遇上美女天师&#124;生化异族的入侵:吸血传说&#124;凶宅女尸:学院惊魂夜&#124;棺木里的眼球:古井沉尸&#124;校园恐怖女生寝室3:诡铃 变成有钱人并不难: 理财YS → 快速发财: 怎样做无本生意&#124;创业指南:三十六计&#124;成功三宝:习惯、心态、人脉&#124;掌控自己命运:读孙子兵法&#124;改变你一生的30个招术&#124;帮你成高手:口才决定成败&#124;左右逢源的做人心机术&#124;穷人与富人的差别&#124;最快的致富秘诀: 赢在观念&#124;做个聪明的老板: 经商要会说话&#124;把话说得滴水不漏全集&#124;职场:1分钟读懂对方心理&#124;恋人浪漫短信&#124;李嘉诚的谋局与处世&#124;股票入门:股票认知大全&#124;男人了解女人,女人了解男人&#124;教你理财:理财高手&#124;心机&#8211;做人的一种智慧&#124;必修课:这样做女孩最命好&#124;女人的身体·女人的智慧 [...]]]></description>
			<content:encoded><![CDATA[<p>首先，要了解<a href="http://en.wikipedia.org/wiki/Association_rule_learning" target="_blank">关联规则</a>的几个概念，定义<span style="color: #ff0000;">N</span>为总事务数，<span style="color: #ff0000;">N(A)</span>、<span style="color: #ff0000;">N(B)</span>分别为项集A、项集B出现的次数，<span style="color: #ff0000;">N(AB)</span>为项集A、项集B同时出现的次数，A、B为不相交项集A∩B=Ø，规则A→B表示由A推到B：</p>
<p><strong>支持度</strong>（Support）：</p>
<p style="padding-left: 30px;"><img class="alignnone" title="A、B同时出现的次数除以总事务数" src="http://www.fuchaoqun.com/wp-content/uploads/Support.png" alt="Support" width="203" height="38" /></p>
<p>支持度是一种重要度量，支持度低的规则很可能是偶然现象，对推荐意义不大，另外支持度是数据剪枝的一个重要依据。</p>
<p><strong>置信度</strong>（Confidence）：</p>
<p style="padding-left: 30px;"><img class="alignnone" title="A、B同时出现的次数除以A全部出现的次数" src="http://www.fuchaoqun.com/wp-content/uploads/Confidence.png" alt="Confidence" /></p>
<p>置信度，字面上的解释就是这个规则到底有多可信，对于给定的规则A→B，置信度越高，B出现在包含A的事务中的概率越高。</p>
<p><strong>提升度</strong>（Lift）：</p>
<p style="padding-left: 30px;"><img class="alignnone" title="A、B的支持度除以A的支持度和B的支持度" src="http://www.fuchaoqun.com/wp-content/uploads/Lift.png" alt="Lift" /></p>
<p>Support(A→B)其实就是AB的联合概率<em>P(AB)</em>，Support(A) 、 Support(B)分别为A、B的概率估计<em>P(A)</em>、<em>P(B)</em>，如果A、B相互独立，则<em>P(AB)</em> = <em>P(A)</em> × <em>P(B)</em>，所以只有 <span style="color: #ff0000;">Lift &gt; 1</span> 才表示A、B正相关，且越大越好。</p>
<p>为什么要引入提升度的概念呢？还是拿歌曲来做例子，比如歌曲A、歌曲C为小众歌曲，歌曲B为口水歌，共有10万个用户，有200个人听过歌曲A，这200个人里面有60个听过口水歌B，有40个人听过歌曲C，同时听过歌曲C的人数是300，听过口水歌B的人为50000，那么Confidence(A→B) = 0.3，Confidence(A→C) = 0.2，从置信度来看貌似A和B更相关，但是10W人里面有5W听过歌曲B，说明有一半的用户都喜欢歌曲B，但听过歌曲A的人里面只有30%的人喜欢歌曲B，很明显歌曲A和歌曲B负相关，计算Lift(A→B) = 0.6，小于1，负相关，Lift(A→C) = 66.7，远大于1，正相关。</p>
<p>当然，还有一些其他的度量因子，可自行参阅其他文档。</p>
<p>可以进入正题了，我们要实验的是一个文学类的网站数据，数据格式如下：</p>
<p style="padding-left: 30px;">用户ID    图书ID</p>
<p>表示此用户阅读过该图书，我们首先要解决的问题是：<strong>喜欢图书A的用户还喜欢其他哪些图书？</strong>（图书之间的相关性）</p>
<p><strong>推荐流程</strong>：</p>
<ul>
<li>数据清理：对用户和图书分别计数，过滤掉一些超不活跃的用户和超冷门的图书</li>
<li>计算<span style="color: #ff0000;">两两图书</span>之间的支持度、置信度、提升度，根据最低支持度、最低置信度、最低提升度剪枝，把低于最小值的规则扔掉</li>
<li>对图书A进行推荐：找出图书A的所有规则，按照置信度降序排序，Top-N即为和图书A最相关的前N本图书</li>
</ul>
<p>非常简单，关键的就是数据清理以及规则剪枝设置，这需要对业务熟悉一些，提升度的话，如果不确认，大于1即可。</p>
<p>结果示例：</p>
<p style="padding-left: 30px;">古龙:剑毒梅香(中) <span style="color: #ff0000;">→</span>古龙:剑毒梅香(上)|古龙:剑毒梅香(下)|武林第一少年:血欲江湖|笑傲江湖之风清扬别传|草根续写:天龙八部续<br />
古龙:剑毒梅香(下) <span style="color: #ff0000;">→</span>古龙:剑毒梅香(中)|古龙:剑毒梅香(上)|武林第一少年:血欲江湖|笑傲江湖之风清扬别传|恐怖宿舍惊魂夜:女生寝室|倚天屠龙记之复兴明教|至尊武神:六脉神剑闹武林|草根续写:天龙八部续<br />
温瑞安：四大名捕猿猴月 <span style="color: #ff0000;">→</span> 四大名捕会京师:逆水寒|温瑞安：四大名捕铁布衫|四大名捕震关东－亡命|四大名捕破神枪:  惨绿|四大名捕破神枪－妖红|四大名捕震关东－追杀|温瑞安：四大名捕谈亭会|温瑞安：四大名捕开谢花|温瑞安：四大名捕碎梦刀|四大名捕走龙蛇|温瑞安：四大名捕猛鬼庙|温瑞安神州奇侠:人世间<br />
异界玄奇：尸池 <span style="color: #ff0000;">→</span> 荒村血鬼洞房:剥皮新娘|真实恐怖:鬼宅小区|丫鬟不好当:王爷,请自重|人鬼恋:我的老婆不是人|灵异事件全曝光:诡异档案|恐怖的盗墓历险:荒村古墓|校园僵尸|古墓惊魂夜:坟岭村笔记|阴阳眼之鬼瞳:荒道门|极度恐怖乱坟头:墓地惊叫|盗墓传说|不解迷:殡仪馆里的化妆师|凶尸宿舍惊魂声:猛鬼校园|惊声尖叫:太平间美丽女尸|生化疯狂撕杀之丧尸异形|僵尸当街:遇上美女天师|生化异族的入侵:吸血传说|凶宅女尸:学院惊魂夜|棺木里的眼球:古井沉尸|校园恐怖女生寝室3:诡铃<br />
变成有钱人并不难:  理财YS <span style="color: #ff0000;">→</span> 快速发财:  怎样做无本生意|创业指南:三十六计|成功三宝:习惯、心态、人脉|掌控自己命运:读孙子兵法|改变你一生的30个招术|帮你成高手:口才决定成败|左右逢源的做人心机术|穷人与富人的差别|最快的致富秘诀:  赢在观念|做个聪明的老板: 经商要会说话|把话说得滴水不漏全集|职场:1分钟读懂对方心理|恋人浪漫短信|李嘉诚的谋局与处世|股票入门:股票认知大全|男人了解女人,女人了解男人|教你理财:理财高手|心机&#8211;做人的一种智慧|必修课:这样做女孩最命好|女人的身体·女人的智慧<br />
……</p>
<p>不再多举例子了，目测感觉大多比较靠谱。</p>
<p>Simpler could be better.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2010/02/recommendation-system-on-association-rules/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>[视频] Music Recommender Systems</title>
		<link>http://www.fuchaoqun.com/2009/11/music-recommender-systems-video/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=music-recommender-systems-video</link>
		<comments>http://www.fuchaoqun.com/2009/11/music-recommender-systems-video/#comments</comments>
		<pubDate>Sun, 29 Nov 2009 12:44:55 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[Data Mining]]></category>
		<category><![CDATA[Collaborative filtering]]></category>
		<category><![CDATA[KNN]]></category>
		<category><![CDATA[recommender system]]></category>
		<category><![CDATA[slope one]]></category>
		<category><![CDATA[SVD]]></category>

		<guid isPermaLink="false">http://www.fuchaoqun.com/?p=272</guid>
		<description><![CDATA[上次去beta沙龙的视频，希望没有浪费大家的时间，感谢beta沙龙的组织工作。]]></description>
			<content:encoded><![CDATA[<p><embed width="500" height="420" wmode="transparent" quality="high" name="fm_v" id="fm_v" src="http://player.youku.com/player.php/sid/XMTM0NjMzMTYw/v.swf" type="application/x-shockwave-flash"/></p>
<p>上次去beta沙龙的<a href="http://club.blogbeta.com/133.html" target="_blank">视频</a>，希望没有浪费大家的时间，感谢<a href="http://club.blogbeta.com/" target="_blank">beta沙龙</a>的组织工作。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2009/11/music-recommender-systems-video/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Music Recommender Systems</title>
		<link>http://www.fuchaoqun.com/2009/11/music-recommender-systems/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=music-recommender-systems</link>
		<comments>http://www.fuchaoqun.com/2009/11/music-recommender-systems/#comments</comments>
		<pubDate>Tue, 17 Nov 2009 04:18:29 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[Data Mining]]></category>
		<category><![CDATA[association rules]]></category>
		<category><![CDATA[Collaborative filtering]]></category>
		<category><![CDATA[KNN]]></category>
		<category><![CDATA[music recommender systems]]></category>
		<category><![CDATA[slope one]]></category>
		<category><![CDATA[SVD]]></category>

		<guid isPermaLink="false">http://www.fuchaoqun.com/?p=262</guid>
		<description><![CDATA[周末beta沙龙和大家分享的音乐智能推荐PPT，有些内容和上次的PPT差不多，这次主要和大家分享一个完整的数据挖掘流程，同样的，还是工程方面比较多，学术方面这里有很多大牛。]]></description>
			<content:encoded><![CDATA[<div style="width:425px;text-align:left" id="__ss_2561419"><embed width="510" height="415" flashvars="sessid=BAhDOh9BY3RpdmVTdXBwb3J0OjpPcmRlcmVkSGFzaFsKWwc6DWxhbmd1YWdl%250AIgcqKlsHOgl0ZXN0MFsHOgl1c2VyewYiCXVzZXJpA3XGb1sHOgppbmJveGkA%250AWwc6Em5vdGlmaWNfY291bnRpCg%253D%253D--56a5c08d98a103d6c1c79e7a3d9ca8f5331c745d&amp;pvt=0&amp;doc=musicrecommendersystems-091122193613-phpapp01&amp;version_no=1258940212&amp;presentationId=2561419&amp;totalSlides=27&amp;startSlide=1&amp;inContest=0&amp;preview=no&amp;stitle=music-recommender-systems-2561419&amp;userName=fuchaoqun&amp;has_form=null&amp;form_after_slide_number=null&amp;form_is_blocking=false&amp;hostedIn=slideshare&amp;useHttp=1&amp;autoplay=0" allowfullscreen="true" allowscriptaccess="always" quality="high" bgcolor="#FFFFFF" name="player" id="player" style="" src="http://static.slidesharecdn.com/swf/player.swf" type="application/x-shockwave-flash"/></div>
<p>周末<a href="http://club.blogbeta.com/127.html" target="_blank">beta沙龙</a>和大家分享的<a href="http://www.slideshare.net/fuchaoqun/music-recommender-systems-2515604" target="_blank">音乐智能推荐</a>PPT，有些内容和<a href="http://www.fuchaoqun.com/2009/05/recommender-system/" target="_blank">上次的PPT</a>差不多，这次主要和大家分享一个完整的数据挖掘流程，同样的，还是工程方面比较多，学术方面<a href="http://groups.google.com/group/resys?hl=zh-CN" target="_blank">这里</a>有很多大牛。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2009/11/music-recommender-systems/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>智能推荐系统</title>
		<link>http://www.fuchaoqun.com/2009/05/recommender-system/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=recommender-system</link>
		<comments>http://www.fuchaoqun.com/2009/05/recommender-system/#comments</comments>
		<pubDate>Mon, 18 May 2009 10:33:19 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[Data Mining]]></category>
		<category><![CDATA[KNN]]></category>
		<category><![CDATA[recommender system]]></category>
		<category><![CDATA[slope one]]></category>
		<category><![CDATA[SVD]]></category>

		<guid isPermaLink="false">http://www.fuchaoqun.com/?p=224</guid>
		<description><![CDATA[断断续续的做了大半年歌曲相关性方面的试验，有一些肤浅的体会，工程方面多些，学术上仍很不足，与大家分享，望后来之君少走弯路，抑或被我带入岐途，不当之处，请指正。 PS：前段时间申请了个独立域名：http://www.fuchaoqun.com，烦请订阅feed者更新：http://www.fuchaoqun.com/feed/，原http://chaoqun.17348.com作了301跳转，将来一段时间内亦能访问。]]></description>
			<content:encoded><![CDATA[<div id="__ss_1451423" style="width: 425px; text-align: left;"><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="425" height="355" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><param name="src" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-090518051254-phpapp01&amp;rel=0&amp;stripped_title=ss-1451423" /><embed type="application/x-shockwave-flash" width="425" height="355" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-090518051254-phpapp01&amp;rel=0&amp;stripped_title=ss-1451423" allowscriptaccess="always" allowfullscreen="true"></embed></object>
</div>
<p>断断续续的做了大半年歌曲相关性方面的试验，有一些肤浅的体会，工程方面多些，学术上仍很不足，与大家分享，望后来之君少走弯路，抑或被我带入岐途，不当之处，请指正。</p>
<p>PS：前段时间申请了个独立域名：<a href="http://www.fuchaoqun.com" target="_blank">http://www.fuchaoqun.com</a>，烦请订阅feed者更新：<a href="http://www.fuchaoqun.com/feed/" target="_blank">http://www.fuchaoqun.com/feed/</a>，原<a href="http://chaoqun.17348.com" target="_blank">http://chaoqun.17348.com</a>作了301跳转，将来一段时间内亦能访问。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2009/05/recommender-system/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>基于Slope One的相关歌曲推荐算法</title>
		<link>http://www.fuchaoqun.com/2009/02/slope-one-for-music-recommender-system/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=slope-one-for-music-recommender-system</link>
		<comments>http://www.fuchaoqun.com/2009/02/slope-one-for-music-recommender-system/#comments</comments>
		<pubDate>Tue, 03 Feb 2009 10:55:29 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[Data Mining]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[recommender system]]></category>
		<category><![CDATA[slope one]]></category>
		<category><![CDATA[数据挖掘]]></category>
		<category><![CDATA[歌曲推荐]]></category>

		<guid isPermaLink="false">http://chaoqun.17348.com/?p=142</guid>
		<description><![CDATA[本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享，转载请保留链接http://chaoqun.17348.com/2009/02/slope-one-for-music-recommender-system/ 不知不觉，研究歌曲相关推荐快半年了，第一篇文章利用orange进行关联规则挖掘完成于2008.08.26，到现在基本搞定基于矩阵奇异值分解(SVD)的协同过滤算法，期间得到了很多朋友的帮助，在此致谢。有些收获，将逐步的分享出来，有兴趣的可以参照研习。 对于Slope One算法，不熟悉的可以参照我之前的文章：Slope one:简单高效的推荐算法，已经被很多人证明有很好的推荐效果。 Slope one算法中有一个很重要的步骤是获取用户的打分数据，这个对很多网站都很费劲，很多用户都会听歌，但大多懒得去给歌曲打分，另外用户打分的时候会比较困惑，该打多少分呢？喜欢这首歌，是打4分还是5分呢？费劲。 我这里给出的是另外一种方法，做法是分析用户的听歌记录，一般网站都会记录这样的记录，统计一段时间内用户的听歌记录，我们得到下面格式的数据： 用户ID    歌曲ID    听歌次数 比如某个片段： 3389    9527    23 3389    9528    56 3306    1211    78 3306    9527    45 表示用户3389听歌曲9527的次数是23，听9528的次数是56，诸如此类。这样的数据当然不能直接用来做Slope one，需要把数据格式化到某个区间。我们分析一下用户听歌的行为，一般来说最喜欢的歌曲听的最多，越喜欢的歌曲听的越多，听的少的歌曲自然不那么喜欢。所以我们可以简单的模拟用户对歌曲的打分： 用户对歌曲的打分 ＝ 用户听此歌曲的次数 / 用户听单首歌曲的最大次数 这样就可以把打分数据规整到0～1之间，还是上面的数据： 3389    9527    23/56 3389    9528    56/56 3306    1211    78/78 3306    9527    45/78 用户听的最多的歌曲打分是1，其他歌曲的打分等于听歌次数除以最大次数，我们就获得了用户的打分数据了。剩下的工作就是按照标准的Slope One流程走了，程序代码可以参考：http://code.google.com/p/openslopeone/ 贴出几个实例大家看看，第一次做的结果，再去做的话应该比这个要好一些： 歌曲 推荐歌曲 南无大悲观世音菩萨   刘小茜 梵音大悲咒   齐豫 大悲咒   齐豫 [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享，转载请保留链接<a href="http://chaoqun.17348.com/2009/02/slope-one-for-music-recommender-system/" target="_blank">http://chaoqun.17348.com/2009/02/slope-one-for-music-recommender-system/</a></p></blockquote>
<p>不知不觉，研究歌曲相关推荐快半年了，第一篇文章<a href="http://chaoqun.17348.com/2008/08/data-mining-with-python-orange-association_rule/" target="_blank">利用orange进行关联规则挖掘</a>完成于2008.08.26，到现在基本搞定基于矩阵奇异值分解(SVD)的协同过滤算法，期间得到了很多朋友的帮助，在此致谢。有些收获，将逐步的分享出来，有兴趣的可以参照研习。</p>
<p>对于Slope One算法，不熟悉的可以参照我之前的文章：<a href="http://chaoqun.17348.com/2008/09/slope_one/" target="_blank">Slope one:简单高效的推荐算法</a>，已经被很多人证明有很好的推荐效果。</p>
<p>Slope one算法中有一个很重要的步骤是获取用户的打分数据，这个对很多网站都很费劲，很多用户都会听歌，但大多懒得去给歌曲打分，另外用户打分的时候会比较困惑，该打多少分呢？喜欢这首歌，是打4分还是5分呢？费劲。</p>
<p>我这里给出的是另外一种方法，做法是分析用户的听歌记录，一般网站都会记录这样的记录，统计一段时间内用户的听歌记录，我们得到下面格式的数据：</p>
<blockquote><p>用户ID    歌曲ID    听歌次数</p></blockquote>
<p>比如某个片段：</p>
<blockquote><p>3389    9527    23<br />
3389    9528    56<br />
3306    1211    78<br />
3306    9527    45</p></blockquote>
<p>表示用户3389听歌曲9527的次数是23，听9528的次数是56，诸如此类。这样的数据当然不能直接用来做Slope one，需要把数据格式化到某个区间。我们分析一下用户听歌的行为，一般来说<strong>最喜欢的歌曲听的最多，越喜欢的歌曲听的越多，听的少的歌曲自然不那么喜欢</strong>。所以我们可以简单的模拟用户对歌曲的打分：</p>
<blockquote><p><strong>用户对歌曲的打分 ＝ 用户听此歌曲的次数 / 用户听单首歌曲的最大次数</strong></p></blockquote>
<p>这样就可以把打分数据规整到0～1之间，还是上面的数据：</p>
<blockquote><p>3389    9527    23/56<br />
3389    9528    56/56<br />
3306    1211    78/78<br />
3306    9527    45/78</p></blockquote>
<p>用户听的最多的歌曲打分是1，其他歌曲的打分等于听歌次数除以最大次数，我们就获得了用户的打分数据了。剩下的工作就是按照标准的Slope One流程走了，程序代码可以参考：<a href="http://code.google.com/p/openslopeone/" target="_blank">http://code.google.com/p/openslopeone/</a></p>
<p>贴出几个实例大家看看，第一次做的结果，再去做的话应该比这个要好一些：</p>
<table style="border: 1px solid black; width: 400px;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border-right:1px solid #000;border-bottom:1px solid #000">歌曲</td>
<td style="border-bottom:1px solid #000">推荐歌曲</td>
</tr>
<tr>
<td style="border-right:1px solid #000;border-bottom:1px solid #000">南无大悲观世音菩萨   刘小茜</td>
<td style="border-bottom:1px solid #000">梵音大悲咒   齐豫<br />
大悲咒   齐豫<br />
观世音菩萨发愿偈.大悲咒   齐豫<br />
大悲咒   邝美云<br />
般若波罗蜜多心经   齐豫<br />
大悲咒   齐豫<br />
清净法身佛   齐豫<br />
阿弥陀佛在心间   小娟<br />
吉祥如意   凤凰传奇</td>
</tr>
<tr>
<td style="border-right:1px solid #000;border-bottom:1px solid #000">好一朵茉莉花   朱昌耀</td>
<td style="border-bottom:1px solid #000">理查德-克莱德曼《梦中的婚礼》   合辑（欧美）<br />
茉莉花（汉族民歌）   雷佳<br />
好一朵茉莉花-笛子   合辑（内地）<br />
最浪漫的事   赵咏华<br />
沧海一声笑   罗文<br />
how can i keep from singing   Enya<br />
生死不离   成龙<br />
羞答答的玫瑰静悄悄地开   孟庭苇</td>
</tr>
<tr>
<td style="border-right:1px solid #000">过三关   吴卓羲</td>
<td>别怪她   吴卓羲<br />
生命有一种绝对   五月天<br />
春日(电视剧&#8217;春日&#8217;主题曲)   吴卓羲<br />
爱玛仕小姐   吴卓羲<br />
别人问起   吴卓羲<br />
别怪她(Dance Remix)   吴卓羲<br />
别怪她 &#8211; 吴卓羲   合辑<br />
米老鼠   五月天<br />
One Last Dance   Craig David<br />
新不了情   薛凯琪</td>
</tr>
</tbody>
</table>
<p>Tips:</p>
<p>做Slope one之前最好过滤掉那些超热门的歌曲，因为很多人都听过了，会让这些歌曲经常出现在推荐结果里面，我的感觉是过滤掉Top100就可以了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2009/02/slope-one-for-music-recommender-system/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>slope one算法在Netflix Prize上的表现</title>
		<link>http://www.fuchaoqun.com/2009/01/slope-one-on-netflix-prize/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=slope-one-on-netflix-prize</link>
		<comments>http://www.fuchaoqun.com/2009/01/slope-one-on-netflix-prize/#comments</comments>
		<pubDate>Tue, 06 Jan 2009 09:40:58 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[Data Mining]]></category>
		<category><![CDATA[netflix prize]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[slope one]]></category>

		<guid isPermaLink="false">http://chaoqun.17348.com/?p=125</guid>
		<description><![CDATA[本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享，转载请保留链接http://chaoqun.17348.com/2009/01/slope-one-on-netflix-prize/ 前段时间做了个slope one算法在Netflix Pirze上的测试，关于slope one算法可以参考我之前写的文章:Slope one:简单高效的推荐算法，Netflix Prize是DVD在线租赁商Netflix于2006年10月2日发起一项竞赛：任何组织或个人只要能够提交比它现有电影推荐系统Cinematch效果好10%的新方法，就可以获得100万美元的奖金。竞赛最多持续到2011年10月2日。同时，NetflixPrize还提供每年5万美元的年度进步奖。为什么是五万美元的年度进步奖呢？因为100万美元大奖存银行，每年的利息是5万美元，看来老外是挺有意思的。 Netflix Pirze采用RMSE作为评测的标准，RMSE中文的意思是均方根误差，计算的公式：  其中Ot是原始数据，Ft是预测数据，n是样本数。 目前最好的成绩是有BellKor in BigChaos创造的0.8598（2009.01.05数据），比官方数据提高9.63％，这样可以推算出官方的数据应该是0.9492左右，BellKor in BigChaos也是2008年度进步奖的获得者，他们更新数据的频率很高，如不出意外，最后的大奖应该是他们的。 目前的方向大多是SVD奇异值分解，可以参见BellKor in BigChaos他们的文章http://www.netflixprize.com/community/viewtopic.php?id=1193，这里有一个开源的项目nprize，也是一个SVD处理Netflix Prize的模型，大部分代码是Python的（国外很多用Python做数据挖掘和自然语言处理的案例），成绩到了0.9046，折算比官方数据要高4.70％，如果你想拿SVD热热手，可以看看这个开源项目，过些日子我会写一些SVD应用在推荐系统方面的文章，着急的可以阅读吴军的文章数学之美 系列十八 － 矩阵运算和文本处理中的分类问题。 由于对slope one算法比较熟悉，决定看看slope one算法在netflix pirze上的表现如何，netflix prize训练数据太大，大概有1亿多条的打分记录，OpenSlopeOne在运行效率方面不是很好，OpenSlopeOne处理几百万上千万的打分数据还是非常不错的，更多的话需要更多的机器水平扩展，如果有好的Mysql DBA可以尝试优化一下mysql server的参数，估计效果会很好，当然也需要有好的机器配合，我这里是用Python写的一个程序，多进程＋多线程＋手工Map-Reduce，需要源代码的话可以找我拿。 跑出来的结果不是很好，我的得分是0.9829，比官方数据差0.0337，大概差3.55％，分析原因可能是用户打分的数据普遍偏高，人们大多给自己喜欢的电影打分，对于不喜欢的数据打分就少很多了，下面是打分数据的分布情况： mysql&#62; select rating,count(*) as times from nf_log group by rating; +--------+----------+ &#124; rating &#124; times    &#124; +--------+----------+ &#124;      1 &#124;  4617904 &#124; &#124;      2 &#124; [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>本博客所有原创文章采用<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" target="_blank"><span style="color: #356aa0;">知识共享署名-非商业性使用-相同方式共享</span></a>，转载请保留链接<a href="http://chaoqun.17348.com/2009/01/slope-one-on-netflix-prize/">http://chaoqun.17348.com/2009/01/slope-one-on-netflix-prize/</a></p></blockquote>
<p>前段时间做了个slope one算法在<a href="http://www.netflixprize.com/" target="_blank">Netflix Pirze</a>上的测试，关于slope one算法可以参考我之前写的文章:<a href="http://chaoqun.17348.com/2008/09/slope_one/" target="_blank">Slope one:简单高效的推荐算法</a>，Netflix Prize是DVD在线租赁商<a href="https://www.netflix.com" target="_blank">Netflix</a>于2006年10月2日发起一项竞赛：任何组织或个人只要能够提交比它现有电影推荐系统Cinematch效果好10%的新方法，就可以获得100万美元的奖金。竞赛最多持续到2011年10月2日。同时，NetflixPrize还提供每年5万美元的年度进步奖。为什么是五万美元的年度进步奖呢？因为100万美元大奖存银行，每年的利息是5万美元，看来老外是挺有意思的。</p>
<p>Netflix Pirze采用RMSE作为评测的标准，RMSE中文的意思是均方根误差，计算的公式： </p>
<p><img class="alignnone" src="http://farm2.static.flickr.com/1194/3171843795_1251bcff35.jpg" alt="" /></p>
<p>其中O<sup>t</sup>是原始数据，F<sup>t</sup>是预测数据，n是样本数。</p>
<p>目前最好的成绩是有<a href="http://www.commendo.at/prize08/team.html" target="_blank">BellKor in BigChaos</a>创造的0.8598（2009.01.05数据），比官方数据提高9.63％，这样可以推算出官方的数据应该是0.9492左右，BellKor in BigChaos也是2008年度进步奖的获得者，他们更新数据的频率很高，如不出意外，最后的大奖应该是他们的。</p>
<p>目前的方向大多是SVD奇异值分解，可以参见BellKor in BigChaos他们的文章<a href="http://www.netflixprize.com/community/viewtopic.php?id=1193" target="_blank">http://www.netflixprize.com/community/viewtopic.php?id=1193</a>，这里有一个开源的项目<a href="http://code.google.com/p/nprize/" target="_blank">nprize</a>，也是一个SVD处理Netflix Prize的模型，大部分代码是Python的（国外很多用Python做数据挖掘和自然语言处理的案例），成绩到了0.9046，折算比官方数据要高4.70％，如果你想拿SVD热热手，可以看看这个开源项目，过些日子我会写一些SVD应用在推荐系统方面的文章，着急的可以阅读吴军的文章<a href="http://www.googlechinablog.com/2007/01/blog-post.html" target="_blank">数学之美 系列十八 － 矩阵运算和文本处理中的分类问题</a>。</p>
<p>由于对slope one算法比较熟悉，决定看看slope one算法在netflix pirze上的表现如何，netflix prize训练数据太大，大概有1亿多条的打分记录，<a href="http://code.google.com/p/openslopeone/" target="_blank">OpenSlopeOne</a>在运行效率方面不是很好，OpenSlopeOne处理几百万上千万的打分数据还是非常不错的，更多的话需要更多的机器水平扩展，如果有好的Mysql DBA可以尝试优化一下mysql server的参数，估计效果会很好，当然也需要有好的机器配合，我这里是用Python写的一个程序，多进程＋多线程＋手工Map-Reduce，需要源代码的话可以找我拿。</p>
<p>跑出来的结果不是很好，我的得分是0.9829，比官方数据差0.0337，大概差3.55％，分析原因可能是用户打分的数据普遍偏高，人们大多给自己喜欢的电影打分，对于不喜欢的数据打分就少很多了，下面是打分数据的分布情况：</p>
<blockquote>
<pre>mysql&gt; select rating,count(*) as times from nf_log group by rating;
+--------+----------+
| rating | times    |
+--------+----------+
|      1 |  4617904 |
|      2 | 10131945 |
|      3 | 28810978 |
|      4 | 33750581 |
|      5 | 23167830 |
+--------+----------+</pre>
</blockquote>
<p>一目了然，用户对不喜欢的电影打分甚少，而且用户的平均打分达到了3.6043，所以最后算出来的打分值普遍偏高，RMSE的表现当然差了，<a href="http://www.daniel-lemire.com/fr/documents/publications/lemiremaclachlan_sdm05.pdf" target="_blank">Slope one算法</a>里面有个BI-POLAR SLOPE ONE来应对这种问题，有兴趣的可以尝试一下。</p>
<p>尽管得分情况不是很好，我用probe的数据测试看，slope one算法对用户喜欢的电影预测还是很好的，不擅长的是对用户不喜欢的电影的预测，对用户打分为1的预测普遍在3以上，拖累了它的表现。</p>
<p>我们一般要做的是对用户喜欢的东西进行推荐，slope one还是一个很不错的选择。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2009/01/slope-one-on-netflix-prize/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>OpenSlopeOne: An Open Source Project implementing Slope One in PHP&amp;MySQL</title>
		<link>http://www.fuchaoqun.com/2008/09/openslopeone-open-source-php-mysql/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=openslopeone-open-source-php-mysql</link>
		<comments>http://www.fuchaoqun.com/2008/09/openslopeone-open-source-php-mysql/#comments</comments>
		<pubDate>Fri, 12 Sep 2008 15:37:34 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[Data Mining]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Collaborative filtering]]></category>
		<category><![CDATA[openslopeone]]></category>
		<category><![CDATA[slope one]]></category>

		<guid isPermaLink="false">http://chaoqun.17348.com/?p=68</guid>
		<description><![CDATA[About OpenSlopeOne OpenSlopeOne is an implementation of Slope One based on PHP&#38;MySQL, it&#8217;s an open source project under GPL V3. It aims to a fast way to use Slope One with PHP&#38;MySQL, and it can handle tons of data. It&#8217;s localed on Google Code:     http://code.google.com/p/openslopeone/ You can get the latest code here:     svn [...]]]></description>
			<content:encoded><![CDATA[<p><strong>About OpenSlopeOne</strong></p>
<p>OpenSlopeOne is an implementation of Slope One based on PHP&amp;MySQL, it&#8217;s an open source project under GPL V3.</p>
<p>It aims to a fast way to use Slope One with PHP&amp;MySQL, and it can handle tons of data.</p>
<p>It&#8217;s localed on Google Code:</p>
<p>    <a href="http://code.google.com/p/openslopeone/" target="_blank">http://code.google.com/p/openslopeone/</a></p>
<p>You can get the latest code here:</p>
<p>    svn checkout https://openslopeone.googlecode.com/svn/trunk/openslopeone</p>
<p>it uses Zend_Db as its database layer.PHP5&amp;MySQL5 or higher.</p>
<p><strong>About Slope One</strong></p>
<p>Slope One is a family of algorithms used for <a href="http://en.wikipedia.org/wiki/Collaborative_filtering" target="_blank">Collaborative filtering</a> introduced in Slope One Predictors for Online Rating-Based Collaborative Filtering by <a href="http://www.daniel-lemire.com/fr/abstracts/SDM2005.html" target="_blank">Daniel Lemire</a> and Anna Maclachlan.</p>
<p>You can check <a href="http://en.wikipedia.org/wiki/Slope_One" target="_blank">http://en.wikipedia.org/wiki/Slope_One</a> to know more about Slope One.</p>
<p><strong>What&#8217;s the difference between OpenSlopeOne and Vogoo?</strong></p>
<p>As you know,there is also another implementation of Slope One based on PHP&amp;MySQL:<a href="http://sourceforge.net/projects/vogoo" target="_blank">Vogoo</a></p>
<p>What&#8217;s the difference?</p>
<p>OpenSlopeOne aims to a fast way to use Slope One with PHP&amp;MySQL, so it cares more about performance.</p>
<p>OpenSlopeOne has two modes to init the slope one table, one is based on pure PHP, the other is based on MySQL procedure, as you know, it will be much faster, and you can use it with any other programming language.</p>
<p>the bottleneck of Vogoo(read the source code of cronslope.php Line 70~Line 150, version 2.2) is to check whether the record exits or not. If there is tons of data, the performance is very bad.</p>
<p>In OpenSlopeOne, first I get distinct item ids, then foreach item id, i calculate the slope one of it. I do not have to check whether if it exits, and i am faster.</p>
<p><strong>Installation</strong></p>
<p>1. Modify the config ini file: config.ini.php</p>
<p>   ; &lt;?php exit; ?&gt; DO NOT REMOVE THIS LINE<br />
   [database]<br />
   host                 = localhost ; database host name or ip<br />
   username             = root      ; database user name<br />
   password             =           ; user password<br />
   dbname               =           ; database name<br />
   port                 = 3306      ; database host port,3306 as default<br />
   adapter              = PDO_MYSQL ; PDO_MYSQL or MYSQLI</p>
<p>2. Create user&#8217;s rating table:</p>
<p>    CREATE TABLE IF NOT EXISTS `oso_user_ratings` (<br />
      `user_id` int(11) NOT NULL,<br />
      `item_id` int(11) NOT NULL,<br />
      `rating` decimal(14,4) NOT NULL default &#8217;0.0000&#8242;,<br />
      KEY `item_id` (`item_id`),<br />
      KEY `user_id` (`user_id`,`item_id`)<br />
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;</p>
<p>there is a sample data file:sample.data, you can load it into the table</p>
<p>    load data infile &#8216;sample.data&#8217; into table oso_user_ratings;</p>
<p>3. Create slope one table:</p>
<p>    CREATE TABLE IF NOT EXISTS `oso_slope_one` (<br />
      `item_id1` int(11) NOT NULL,<br />
      `item_id2` int(11) NOT NULL,<br />
      `times` int(11) NOT NULL,<br />
      `rating` decimal(14,4) NOT NULL<br />
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;</p>
<p><strong>Usage<br />
</strong><br />
The main also the only PHP file is OpenSlopeOne.php, you must include it in your own PHP file:</p>
<p>    require &#8216;./OpenSlopeOne.php&#8217;;</p>
<p>    $openslopeone = new OpenSlopeOne();</p>
<p>1. Init the slope one table:</p>
<p>before you get the recommendtion, you must pre-computation the slope one table.</p>
<p>    $openslopeone-&gt;initSlopeOneTable($factory);</p>
<p>you can specify the mode use &#8216;PHP&#8217; or &#8216;MySQL&#8217;,If you user &#8216;PHP&#8217; mode, it&#8217;s a pure php implementation, and it might be very slow when there is tons of data.You can also use &#8216;MySQL&#8217; mode, it&#8217;s based on mysql procedure, and it will be mutch faster.</p>
<p>If you have tons of data to pre-computation, a good advice is that you do not index any colum on oso_slope_one before it done.</p>
<p>2. Get recommended items by item&#8217;s id</p>
<p>    $recommendedItems = $openslopeone-&gt;getRecommendedItemsById(9527);</p>
<p>3. Get recommended items by user&#8217;s id</p>
<p>    $recommendedItems = $openslopeone-&gt;getRecommendedItemsByUser(30002);<br />
<strong>About Author</strong></p>
<p>I am a PHP programmer in China, my blog:http://chaoqun.17348.com, mostly written in Chinese.</p>
<p>You can contack me with gtalk or mail:fuchaoqun@gmail.com</p>
<p>Welcom to any bug and advice.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2008/09/openslopeone-open-source-php-mysql/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Slope one:简单高效的推荐算法</title>
		<link>http://www.fuchaoqun.com/2008/09/slope_one/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=slope_one</link>
		<comments>http://www.fuchaoqun.com/2008/09/slope_one/#comments</comments>
		<pubDate>Tue, 02 Sep 2008 16:05:10 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[Data Mining]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Collaborative]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[filtering]]></category>
		<category><![CDATA[mining]]></category>
		<category><![CDATA[one]]></category>
		<category><![CDATA[slope]]></category>

		<guid isPermaLink="false">http://chaoqun.17348.com/?p=57</guid>
		<description><![CDATA[本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享，转载请保留链接http://chaoqun.17348.com/2008/09/slope_one/ 推荐系统最早在亚马逊的网站上应用，根据以往用户的购买行为，推荐出购买某种产品同时可能购买的其他产品，国内做的不错的当当网,有时候买书，它总能给我推荐出我感兴趣的其他书来，也算是技术极大的促进了销售。 一般的协同过滤算法，首先是收集用户对事物（产品）的评分情况，一种直接对某本书，或者某个歌曲打分，另种是隐性的打分，比如商务系统中，购买了表示打2分，浏览了打1分，其他的0分。我比较看好隐性打分，因为直接打分需要用户的参与程度比较高，很多网站都在内容页中留一个打分的按钮，从1～5选一个，我可能喜欢这篇文章，可我哪里知道我喜欢的程度是几分啊，还要我去思考，而网站设计中一条很重要的原则是:Do not let me think!，于是我就胡打一个分数或者不打，而隐性的打分则不同，只有你喜欢的图书你才会购买，只有你喜欢的歌曲才会听多次。 收集好用户的打分之后，通过最近邻搜索到和某个事物或者某个人特征或者兴趣相近的其他事物或者人，最近邻搜索算法一般是皮尔森相关系数（Person Correlation Coefficient）、余弦相似性（Cosine-based Similarity）以及调整余弦相似性（Adjusted Cosine Similarity）。关于余弦定理在数据挖掘中的应用，google黑白报有过介绍，可以参考数学之美 系列 12 &#8211; 余弦定理和新闻的分类。 剩下的工作就是根据最近邻集进行推荐了。 最近邻集的运算相对来说成本比较高，尤其是大量数据的时候，今天和大家分享的是一种简单高效的协同过滤算法：Slope one 基本原理 用户          对事物A打分 对事物B打分 X 3 4 Y 2 4 Z 4 ? 用户Z对事物B的打分可能是多少呢？股票上有个说法是平均值可以掩盖一切异常波动，所以股票上的各个技术指标收拾不同时间段的平均值的曲线图或者柱状图等。同样的，Slope one算法也认为：平均值也可以代替某两个未知个体之间的打分差异，事物A对事物B的平均很差是：((3 &#8211; 4) + (2 &#8211; 4)) / 2 = -1.5，也就是说人们对事物B的打分一般比事物A的打分要高1.5，于是Slope one算法就猜测Z对事物B的打分是4 + 1.5 = 5.5 是不是非常的简单？ 加权算法 有n个人对事物A和事物B打分了，R(A-&#62;B)表示这n个人对A和对B打分的平均差（A-B）,有m个人对事物B和事物C打分了，R（C-&#62;B）表示这m个人对C和对B打分的平均差（C-B），注意都是平均差而不是平方差，现在某个用户对A的打分是ra，对C的打分是rc，那么A对B的打分可能是： rb = [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>本博客所有原创文章采用<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" target="_blank"><span style="color: #356aa0;">知识共享署名-非商业性使用-相同方式共享</span></a>，转载请保留链接<a href="http://chaoqun.17348.com/2008/09/slope_one/"><span style="color: #356aa0;">http://chaoqun.17348.com/2008/09/slope_one/</span></a></p></blockquote>
<p>推荐系统最早在<a href="http://www.amazon.com/" target="_blank">亚马逊</a>的网站上应用，根据以往用户的购买行为，推荐出购买某种产品同时可能购买的其他产品，国内做的不错的<a href="http://www.dangdang.com" target="_blank">当当网</a>,有时候买书，它总能给我推荐出我感兴趣的其他书来，也算是技术极大的促进了销售。</p>
<p>一般的协同过滤算法，首先是收集用户对事物（产品）的评分情况，一种直接对某本书，或者某个歌曲打分，另种是隐性的打分，比如商务系统中，购买了表示打2分，浏览了打1分，其他的0分。我比较看好隐性打分，因为直接打分需要用户的参与程度比较高，很多网站都在内容页中留一个打分的按钮，从1～5选一个，我可能喜欢这篇文章，可我哪里知道我喜欢的程度是几分啊，还要我去思考，而网站设计中一条很重要的原则是:Do not let me think!，于是我就胡打一个分数或者不打，而隐性的打分则不同，只有你喜欢的图书你才会购买，只有你喜欢的歌曲才会听多次。</p>
<p>收集好用户的打分之后，通过最近邻搜索到和某个事物或者某个人特征或者兴趣相近的其他事物或者人，最近邻搜索算法一般是皮尔森相关系数（<a href="http://en.wikipedia.org/wiki/Correlation" target="_blank">Person Correlation Coefficient</a>）、余弦相似性（<a href="http://www10.org/cdrom/papers/519/node12.html" target="_blank">Cosine-based Similarity</a>）以及调整余弦相似性（<a href="http://www10.org/cdrom/papers/519/node14.html" target="_blank">Adjusted Cosine Similarity</a>）。关于余弦定理在数据挖掘中的应用，google黑白报有过介绍，可以参考<a href="http://www.googlechinablog.com/2006/07/12.html" target="_blank">数学之美 系列 12 &#8211; 余弦定理和新闻的分类</a>。</p>
<p>剩下的工作就是根据最近邻集进行推荐了。</p>
<p>最近邻集的运算相对来说成本比较高，尤其是大量数据的时候，今天和大家分享的是一种简单高效的协同过滤算法：<a href="http://en.wikipedia.org/wiki/Slope_One" target="_blank">Slope one</a></p>
<p><strong>基本原理</strong></p>
<blockquote>
<table style="width: 300px; height: 184px;" border="0">
<tbody>
<tr>
<td><strong>用户          </strong></td>
<td><strong>对事物A打分</strong></td>
<td><strong>对事物B打分</strong></td>
</tr>
<tr>
<td><strong>X</strong></td>
<td><strong>3</strong></td>
<td><strong>4</strong></td>
</tr>
<tr>
<td><strong>Y</strong></td>
<td><strong>2</strong></td>
<td><strong>4</strong></td>
</tr>
<tr>
<td><strong>Z</strong></td>
<td><strong>4</strong></td>
<td><strong>?</strong></td>
</tr>
</tbody>
</table>
</blockquote>
<p>用户Z对事物B的打分可能是多少呢？股票上有个说法是平均值可以掩盖一切异常波动，所以股票上的各个技术指标收拾不同时间段的平均值的曲线图或者柱状图等。同样的，Slope one算法也认为：平均值也可以代替某两个未知个体之间的打分差异，事物A对事物B的平均很差是：((3 &#8211; 4) + (2 &#8211; 4)) / 2 = -1.5，也就是说人们对事物B的打分一般比事物A的打分要高1.5，于是Slope one算法就猜测Z对事物B的打分是4 + 1.5 = 5.5</p>
<p>是不是非常的简单？</p>
<p><strong>加权算法</strong></p>
<p>有n个人对事物A和事物B打分了，R(A-&gt;B)表示这n个人对A和对B打分的平均差（A-B）,有m个人对事物B和事物C打分了，R（C-&gt;B）表示这m个人对C和对B打分的平均差（C-B），注意都是平均差而不是平方差，现在某个用户对A的打分是ra，对C的打分是rc，那么A对B的打分可能是：</p>
<p><strong>rb = (n * (ra &#8211; R(A-&gt;B)) + m * (rc - R(C-&gt;B)))/(m+n)</strong></p>
<p>开源的Slope one的程序包</p>
<ul>
<li>Python
<p><a href="http://www.serpentine.com/blog/2006/12/12/collaborative-filtering-made-easy/" target="_blank">http://www.serpentine.com/blog/2006/12/12/collaborative-filtering-made-easy/</a></li>
<li>Java
<p><a href="http://taste.sourceforge.net/" target="_blank">http://taste.sourceforge.net/</a></p>
<p><a href="http://www.daniel-lemire.com/fr/documents/publications/SlopeOne.java" target="_blank">http://www.daniel-lemire.com/fr/documents/publications/SlopeOne.java</a></p>
<p><a href="http://www.nongnu.org/cofi/" target="_blank">http://www.nongnu.org/cofi/</a></li>
<li>PHP
<p><a href="http://sourceforge.net/projects/vogoo" target="_blank">http://sourceforge.net/projects/vogoo</a></p>
<p><a href="http://www.drupal.org/project/cre" target="_blank">http://www.drupal.org/project/cre</a></p>
<p><a href="http://www.daniel-lemire.com/fr/documents/publications/webpaper.txt" target="_blank">http://www.daniel-lemire.com/fr/documents/publications/webpaper.txt</a> Slope one算法作者写的，简单明了，强烈推荐。</li>
<li>Erlang<br />
<a href="http://chlorophil.blogspot.com/2007/06/collaborative-filtering-weighted-slope.html" target="_blank">http://chlorophil.blogspot.com/2007/06/collaborative-filtering-weighted-slope.html</a></li>
<li>C#<br />
<a href="http://www.cnblogs.com/kuber/articles/SlopeOne_CSharp.html" target="_blank">http://www.cnblogs.com/kuber/articles/SlopeOne_CSharp.html</a> 国人写的C#版本</li>
<li>T-SQL<br />
<a href="http://blog.charliezhu.com/2008/07/21/implementing-slope-one-in-t-sql/" target="_blank">http://blog.charliezhu.com/2008/07/21/implementing-slope-one-in-t-sql/</a></li>
</ul>
<p>还有一些其他语言的版本，请参考<a href="http://en.wikipedia.org/wiki/Slope_One" target="_blank">http://en.wikipedia.org/wiki/Slope_One</a>，即将面世的，居于PHP &amp; Mysql的Slope one算法实现将会在<a href="http://code.google.com/p/openslopeone/" target="_blank">http://code.google.com/p/openslopeone/</a>开源出来，主要优化的是海量数据以及分布式处理，目前在我的笔记本上（迅驰＋1.5G内存），对440W打分记录进行测试，单一线程，3小时47分处理完。速度还算是不错了，最近工作实在太忙了，等我整理好会开源出来放在上面的地址。过几天会有一篇我的算法的详细介绍，盼诸位批评指正，共同学习，共同进步。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2008/09/slope_one/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>利用orange进行关联规则挖掘</title>
		<link>http://www.fuchaoqun.com/2008/08/data-mining-with-python-orange-association_rule/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=data-mining-with-python-orange-association_rule</link>
		<comments>http://www.fuchaoqun.com/2008/08/data-mining-with-python-orange-association_rule/#comments</comments>
		<pubDate>Tue, 26 Aug 2008 09:26:38 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[Data Mining]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[association]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[mining]]></category>
		<category><![CDATA[orange]]></category>

		<guid isPermaLink="false">http://chaoqun.17348.com/?p=54</guid>
		<description><![CDATA[本博客所有原创文章采用知识共享署名-非商业性使用-相同方式共享，转载请保留链接http://chaoqun.17348.com/2008/08/data-mining-with-python-orange-association_rule/ 最近，趁着项目的间隙，折腾了一阵数据挖掘，在同事的帮助下，对新浪音乐用户的听歌记录进行了一个简易挖掘，希望能根据用户以往的听歌记录，推荐出用户可能感兴趣的其他歌曲。 Orange： 一个模块化的C++数据挖掘包，提供python接口（好像也只提供了python接口）,网址是http://www.ailab.si/orange/ 关联分析： 我这里用的是类似购物篮分析，每个用户的听歌id是一个事务，不熟悉关联分析的同学可以去搜一些相关方面的资料。 数据准备： 简单清洗掉一些“脏”数据（逻辑上有问题的数据，比如某个用户在5s听了200首歌），得到类似下面的数据 15615,355029,750367,762147,803787,805014,999712,999712,999712,1013641,1024215,1028429 871029,952779,962769 1023040,1024077,1024215,1025600 757946,873801,873801,873801 862257,873479 286056,286056,286056,286056,286056,286056,286056,286056,286056,286056 873801,873801,873801,873801,873801,947750,947750 473221,473537,504206,504206,504206,504206,504206,504206 947750,1005430,1005430 974748,1024215 873479,873479,873801,873801,947750,965748,999721,1024215,1024215,1024215,1024215,1024215 873801,873801,873801 每一行是一个用户的听歌记录，没有做去重处理（orange示例中也没有，是不是可能会增加歌曲的权重？不清楚，没有去阅读orange代码），注意文件名一定要以.basket为扩展名，程序中文件地址是d:/datamining/sample.basket。 程序： # 导入orange包 import orange &#160; # 导入数据，注意不需要后缀 data = orange.ExampleTable&#40;&#34;d:/datamining/sample&#34;&#41; &#160; # 挖掘关联规则，输入最低支持度、最低置信度、最大项集数 rules = orange.AssociationRulesSparseInducer&#40;data, support = 0.5, confidence = 0.6, maxItemSets = 1000000&#41; &#160; # 打印出规则来 for r in rules: print [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>本博客所有原创文章采用<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" target="_blank">知识共享署名-非商业性使用-相同方式共享</a>，转载请保留链接<a href="http://chaoqun.17348.com/2008/08/data-mining-with-python-orange-association_rule/">http://chaoqun.17348.com/2008/08/data-mining-with-python-orange-association_rule/</a></p></blockquote>
<p>最近，趁着项目的间隙，折腾了一阵数据挖掘，在同事的帮助下，对新浪音乐用户的听歌记录进行了一个简易挖掘，希望能根据用户以往的听歌记录，推荐出用户可能感兴趣的其他歌曲。</p>
<p><strong>Orange</strong>：</p>
<p>一个模块化的C++数据挖掘包，提供python接口（好像也只提供了python接口）,网址是<a href="http://www.ailab.si/orange/" target="_blank">http://www.ailab.si/orange/</a></p>
<p><strong>关联分析</strong>：</p>
<p>我这里用的是类似购物篮分析，每个用户的听歌id是一个事务，不熟悉关联分析的同学可以去搜一些相关方面的资料。</p>
<p><strong>数据准备</strong>：</p>
<p>简单清洗掉一些“脏”数据（逻辑上有问题的数据，比如某个用户在5s听了200首歌），得到类似下面的数据</p>
<blockquote><p>15615,355029,750367,762147,803787,805014,999712,999712,999712,1013641,1024215,1028429<br />
871029,952779,962769<br />
1023040,1024077,1024215,1025600<br />
757946,873801,873801,873801<br />
862257,873479<br />
286056,286056,286056,286056,286056,286056,286056,286056,286056,286056<br />
873801,873801,873801,873801,873801,947750,947750<br />
473221,473537,504206,504206,504206,504206,504206,504206<br />
947750,1005430,1005430<br />
974748,1024215<br />
873479,873479,873801,873801,947750,965748,999721,1024215,1024215,1024215,1024215,1024215<br />
873801,873801,873801</p></blockquote>
<p>每一行是一个用户的听歌记录，没有做去重处理（orange示例中也没有，是不是可能会增加歌曲的权重？不清楚，没有去阅读orange代码），注意文件名一定要以<strong>.basket</strong>为扩展名，程序中文件地址是d:/datamining/sample.basket。</p>
<p><strong>程序</strong>：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># 导入orange包</span>
<span style="color: #ff7700;font-weight:bold;">import</span> orange
&nbsp;
<span style="color: #808080; font-style: italic;"># 导入数据，注意不需要后缀</span>
data = orange.<span style="color: black;">ExampleTable</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;d:/datamining/sample&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># 挖掘关联规则，输入最低支持度、最低置信度、最大项集数</span>
rules = orange.<span style="color: black;">AssociationRulesSparseInducer</span><span style="color: black;">&#40;</span>data, support = <span style="color: #ff4500;">0.5</span>, confidence = <span style="color: #ff4500;">0.6</span>, maxItemSets = <span style="color: #ff4500;">1000000</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#  打印出规则来</span>
<span style="color: #ff7700;font-weight:bold;">for</span> r <span style="color: #ff7700;font-weight:bold;">in</span> rules:
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;%5.3f   %5.3f   %s&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>r.<span style="color: black;">support</span>, r.<span style="color: black;">confidence</span>, r<span style="color: black;">&#41;</span></pre></div></div>

<p>是不是非常的简单？Orange实现的是<a href="http://en.wikipedia.org/wiki/Apriori_algorithm" target="_blank">Apriori算法</a>，由于Apriori算法的问题，一旦数据量非常大，你就等着你的内存消耗光吧，反正我这边要是把所有数据都导入进去的话，笔记本1.5G的的内存根本不够用，可以试试<a href="http://www.guwendong.cn/post/2008/fpgrowth_algorithm.html" target="_blank">FP-tree算法</a>，我这边参考文章<a href="http://203.72.2.115/Ejournal/3012000602.pdf" target="_blank">利用sql改良构建fp-tree之技术</a>，已经把fp-tree的前缀路径都找出来了，需要的朋友可以私下找我要，由fp前缀路径挖频繁集需要用到递归，用sql去处理就非常费劲了，所以后面的算法还需要自己去探索。</p>
<p>居于关联规则的挖掘就告一段落，因为算法的计算复杂度非常高，效果倒不是太好（因为对于音乐，用户可能听多遍，这样打分就不一样，可能用关联规则去挖电影类的数据比较好，因为电影一般最多就看一遍），现在研究的是<a href="http://en.wikipedia.org/wiki/Collaborative_filtering" target="_blank">协同过滤</a>，如果不出意外的话，一个改良版的PHP+Mysql实现<a href="http://en.wikipedia.org/wiki/Slope_One" target="_blank">slope one</a>算法过几天就要出来了，到时候我会开源出来的。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2008/08/data-mining-with-python-orange-association_rule/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->