September 4, 2009

在之前的一个文里有谈及到过最长公共字序列的问题,这个可以用来衡量俩个序列的相似度。

今年的Goolge Code jam的qualification Round 也有一道类似的问题:

【Sub-Sequence-Match】x=[]是一序列,y=[]是另一序列:问x中共有多少个不同的子序列等于y

和这个问题有一点类似的问题是IJCAI07的一篇文里提到的:

【All-Common-Subquence】x=[]是一序列,y=[]是另一序列:问x,y共有多少个不同的公共子序列

想法还是DP:

For S-S-M:

def f(x,y):
    if len(x)<len(y):
        return 0
    if len(y)==1:
        count=0
        for k in x:
            if k==y:
                count=count+1
        return count
    a=len(x)
    b=len(y)
    if x[a-1]==y[b-1]:
        return f(x[0:a-1],y[0:b-1])+f(x[0:a-1],y[0:b])
    if x[a-1]!=y[b-1]:
        return f(x[0:a-1],y[0:b])

意思就是:
如果x长度比y小,那么返回0;如果长度y=1了,那么就看x串中有几个y,返回这个个数;
不然的话
如果最后一个元素相等,那么让x’为x去掉最后一个元素的序列,y’为y去掉最后一个元素序列:
返回s-s-m(x’,y’)+s-s-m(x’,y)

如果最后一个元素不等,那么直接返回s-s-m(x’,y)

当然可以把上面的递归改写成递推的,这样效率会大大提高,并且不改的话,Code jam的大数据肯定是要会TLE的,改写起来很简单就不写鸟。

再来看看A-C-S的DP,大家基本可以自己想想就可以解决了,和上面的思路很类似

N(i, j) = N(i − 1, j − 1) × 2, if Ai = Bj
N(i, j) = N(i − 1, j) + N(i, j − 1) − N(i − 1, j − 1),
if Ai!= Bj

如果最后的元素相同,实际就是前面的A-C-S(i-1,j-1)×2.(有或没有最后一个item作为CS的一部分)
不然的话等于下面那个,注意要扣除掉重复计算的A-C-S(i-1,j-1)

E-O-F

Tags: ,,.
August 12, 2009

Association Rule Learning是一种用来发掘目前的数据库里的变量之间潜在的关系的例子,这里最有名的例子当属“啤酒与纸尿布”的故事了,实际就是 做了A,然后又会去做B 。

一个直接的应用就是购物篮分析,或者更流行的,推荐系统( recommendation system )。这些都是能很快想到的应用。可能用到的场所比如沃尔玛(也是之前的啤酒尿布的故事来源)、豆瓣儿(我猜,我猜,我猜猜猜)、AmazonTaobao或者NetFlix之类的。

提到关联规则几乎第一个跳出来的要讲的就是Apriori系列的算法,此算法是前IBM Lab的Rakesh Agrawal大牛在94的VLDB的一篇叫《Fast Algorithms for Mining Association Rules》的paper里提出来的,该算法在2006年的ICDM里被评选为Top 10 algorithms in data mining. 这个paper也有超过8k的引用,可谓是非常非常的seminal了。

这儿有个八卦,2006年的时候微软偷偷挖走了Rakesh,IBM一看急了,你这个把我们数据组核心专家挖走了以后日子还怎么过啊!而且IBM之前也是给了有超过70万美金的股票期权等来试图以这种方式留人,结果二月份时候Rakesh先是把期权给卖了,然后才加入了M$。IBM就直接一纸诉状给他告上了法庭。结果不了了之,搞技术的挖墙角的事儿见多了。

回到正题,Apriori要解决的是:找出出现的次数大于一个指定的threshold的项集(itemSet)。直接暴力解决的复杂性是不言而喻的,单一个n元素的集合的不同的子集的个数就有{2^n}个,就别说再搭配了。而Apriori的算法的核心思想就是化大为小,从item很小开始做起,慢慢变大。

“老鼠的爸爸也是老鼠”原理:非频繁项集的超集也是非频繁的
if an itemset is not frequent, any of its superset is never frequent

很容易理解吧,因为超集的support(支撑度def: Freq/Obs)肯定小于等于子集嘛。理解了这么多基本就可以猜出算法啦:

image

第三行的函数Apriori-gen函数分两步走:

  1.  
    1. 连接步: R_{k+1},连接所有的满足前{k-1}个元素相同的P_k和R_k生成一个k+1元的itemset
      e.g.:P_k={ a_1, a_2, …a_{k-1}, a_k},  R_k={ a_1, a_2, …a_{k-1}, a_k’ }
            ---> R_{ k+1 }={ a_1, .. a_{k-1}, a_k, a_k’ }
    2. 剪枝步: 如果R_{k+1}中有任一k元子集R’不是频繁集,那么直接剪去该枝,如前所言,必须要是所有的自己都是频繁的,那么超集本身才可能是频繁的。

与此同时,Apriori的缺点也是一堆啦,频繁的扫描数据库,必然带来算法效率的低下,下篇给一个算法Demo和潜在的改进。

Tags: ,,.
March 14, 2009

最近一段时间非常慵懒,加上连日阴雨。除了窝在宿舍看看闲书,偶尔出去打打球之外基本没有什么活动,实在是浪费韶华。

今天出门一瞥,竟然花开燕语春欣然而至也!遂决定从连日冬眠里复苏,重出江湖。

先弄个昨日的题目:

Subset SUM Problem
{a[1],a[2]...a[k]} choose some a[i]s
S.T.
\sum a[i]=T   T is a positive integer.

其实就是个简单的0-1背包问题
可以用DP来解:

f(i,x)=Max{  f(i-1,x-a[i])+a[i]   f(i-1,x) }

这个是背包的变种。。i.e.  重量w[i]和价值c[i]是一样的。
采取非递归算法(只需要从f(1,x)开始往上推就好了),复杂度 O(KT)

那如果这个背包的解是f(k,T)=T那么问题就解决了。

-----------------

不了解0-1背包的同志,可以看看这个Zero One Knapsack Problem

Tags: ,,.