您的位置:首页 > 大数据 > 人工智能

数据挖掘算法的空间复杂度与时间复杂度分析

2014-02-11 14:17 871 查看
刚才在知乎上看到一个问空间复杂度和时间复杂度的问题,结果把自己也搞晕了。因为我们平常讨论问题复杂度的时候都是说时间复杂度的,对空间复杂度确实没怎么仔细考虑过,毕竟现在64位的操作系统理论上所能提供的存储空间高达2的64次方,怎么搞定是操作系统的事。但这么拿出来讨论,好像确实还需要仔细思量一下。

当时把自己搞晕的原因是开始我下意识的认为:空间复杂度一般不可能太高,因为这是算法,而算法的空间开销来自算法处理过程中所产生的中间数据,中间数据如果也达到类似O(n^2)这样的复杂度,就意味着每多处理一个节点就要和前面所有的历史数据发生勾连,这也就意味着这个模型的事物间的关系太复杂了。所以空间复杂度一般来说应该是个常量。但突然想到自己当时做贝叶斯网挖掘的时候,确实好像存在一个中间函数组合爆炸的问题,所以一下就晕了。

后来打开当时的程序才发现了问题所在:

我开始的想法混淆了模型的结构点数和挖掘这个模型所送入的样本数,我们讲模型一定是讲的结构,反映到IT就是事物以及事物的属性之间的关系;而每一行数据(也就是一个样本)只代表了现实世界中事物间的一次互动的记录。而我们在讨论算法的复杂度时的n是指模型结构的复杂程度和寻找到这个模型结构所需付出的代价,衡量指标是模型的节点数、是属性的数量、是输入的变量个数,因此和样本量其实是无关的。

下面就以自己写的挖掘贝叶斯网的算法而言(蚁群算法中单只蚂蚁的算法)进行下初步的分析:

 

Renew();

while (TestSide())

{

    //挑选一条边作为下一条待添加的边(该边的Score要大于0)

    AdjacencySide SelectSide = PickSide();

    //该边的Scor大于0表示添加了该边则会增加结构的总评分,是在改进结构;Score_AddAParent函数已经增加了Parent

    if (SelectSide.Score > 0)

        m_BNStructure.GetScore_AddAParent(data, SelectSide.SonVarID, SelectSide.ParentVarID);

    //不管是否在结构中添加该边都要删除该边

    DeleteSide(SelectSide.ParentVarID, SelectSide.SonVarID);

    //在选中了边(x,y)后要将所有由y的祖先和x的后代所组成的边删除,以避免造成环路

    List<int> Ancestor = m_BNStructure.GetAncestor(SelectSide.ParentVarID);

    List<int> Descendant = m_BNStructure.GetDescendant(SelectSide.SonVarID);

    var asl = Ancestor.List();

    var dsl = Descendant.List();

    if (asl != null && dsl != null)

        for (int i = 0; i < asl.Length; i++)

            for (int j = 0; j < dsl.Length; j++)

                DeleteSide(dsl[j].Key, asl[i].Key);

 

    for (int k = 0; k < m_BNStructure.VarNumber; k++)

        if (m_Adjacency[k, SelectSide.SonVarID] != null && !m_BNStructure.ParentList[SelectSide.SonVarID].InList(k))

         {

            //如果k还不是j的父亲同时还没有因为会导致环路而删除掉(也就是说可以增加为边),则计算如果增加了(k,j)后该边的评分

            m_Adjacency[k, SelectSide.SonVarID].Score = m_BNStructure.GetScore_IfIsParent(data, SelectSide.SonVarID, k);

            ResetSideOrder(m_Adjacency[k, SelectSide.SonVarID]);

          }

     //局部消息素调整,所有的蚂蚁的初始化邻接矩阵是一样的,所以调整任何一个都是调整了全部的初始化邻接矩阵

      AdjustInfo(SelectSide.ParentVarID, SelectSide.SonVarID, Conf.Info_0);

}

//根据找到的BN结构进行一次局部搜索

m_BNStructure = clsBNStructure.Climbing(m_BNStructure, data);

return m_BNStructure.Score;

 

我们对这个算法的时空复杂度进行一下分析:

存储的开销:

1、各边所组成的邻接矩阵,这个的复杂度是O(n^2)的;

2、祖先列表、后代列表,这个的复杂度是O(n)的;

3、其它一些变量,这个的复杂度是O(1)的;

所以整个的空间开销是O(n^2)的。

 

时间的开销:

1、renew函数是初始化,可以通过预存进行化简,这个的复杂度是O(1)的;

2、循环中的大多数函数都是对边的操作,这个的复杂度是O(n^2)的;

3、最大的问题是循环的趟数,即TestSide函数能否快速收敛,而这取决于评分算法是否高效合理,由于目前的评分算法都比较成熟,我们将TestSide和PickSide组合起来来看,初步将其估算为O(n*lgn);

那么就整个算法来说,就是O(n^3*lgn)了。但这里面还忽略了评分算法的计算开销。

评分是对整个样本集从头到尾进行一次扫描(要考虑到数据挖掘都是大样本集,比如一般的贝叶斯网的节点数多在几十到上百个变量,但送入的样本数起码要在3000以上),然后进行评分,BIC算法本身可以近似的估算为O(n^2)的复杂度,其中还有大量的log运算;

这样整个算法的总开销是O(n^5*lgn),但就数据挖掘这样的算法来说,一方面样本集的数量其实是远大于节点数量的,而且其中会涉及到很多的运算密集型的操作,如log运算等;另一方面,这还只是一只蚂蚁爬一趟的开销,还需要考虑整个蚁群的多只蚂蚁多趟计算,以及出于优化目的的其它处理开销,如爬山等。

 

这样分析下来,出于实际应用目的的算法,由于其结构的节点数不可能太大(否则人类根本无法理解,也就难以应用),所以其空间复杂度是不需要过多考虑的,时间复杂度是我们主要需要考虑,但其中忽略了较多的其它因素,尤其是在大样本集的数据挖掘场景下,而只具有一定的参考意义。

  

 
JXBiz ORM平台编程简明参考手册
JXWork任务管理软件源代码
 
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐