本人数学专业本科,研究生读的计算机,方向是深度学习相关的,在平时上课和自己自学,看论文都是深度学习和机器学习相关的。打算毕业之后从事机器学习相关工作,但是不知道学完Dl,ML的相关算法之后,还需不需要学习传统的数据结构,比如二叉树,图,队列,栈什么的,还有必要学习算法导论里的算法吗?如果都学的话,那感觉时间不够,而且这些难度都挺大的。有没有前辈来指点一二呢?
这是今天逛知乎时看到的一个提问“学习机器学习深度学习之后,还需要掌握传统算法和数据结构吗?”。相信很多机器学习的初学者都会有类似的疑问,特别是半路出家的学习者。为什么这么说呢?因为计算机科班出身的学生,在本科期间都系统地学习过数据结构和算法,他们肯定不会提出这样的问题,他们在学习的过程中会真切感受到这些知识的巨大作用。
最小生成树算法在机器学习中的应用
我最近在看数据聚类方面的论文,有篇文章用改进的MST算法实现稀疏数据集的自动聚类,这种思路让我眼前一亮。该文的主要思路是将多维向量视为空间中的点,向量之间的距离看作边长,将距离小于设定阈值的数据用最小生成树连接起来实现数据集的聚类。最小生成树(MST)虽然是图论中的概念,但是在机器学习领域却有着意想不到的效果。
在上篇文章中,我们介绍了Prim算法的基本思路和python实现。当然除了Prim算法之外,还有很多其它的算法,比如本文将要介绍的Kruskal算法。与Prim算法一样,Kruskal算法也是贪心算法的一种,它的核心思想是:将边按照长度从小到大排序,并依次添加到MST中,但要确保不在MST中形成环路。
Kruskal算法
Kruskal算法与Prim算法有着明显的不同。Prim算法初始化两个集合分别保存MST节点和剩余节点,寻找连接两个集合的最小边,并将边添加到MST中。在整个过程中,边的添加始终是链式的,MST像树一样从根节点慢慢生长。而Kruskal算法只关心边的长度,很可能是多棵子树各子生长,最后组合成一棵完整的树。Kruskal算法的步骤如下:
数据初始化:最小生成树MST为空集,边的集合E={,……},三元组中的P,,代表边的两个端点,W代表边的长度;添加边:按照由小到大的顺序,将边依次添加到MST中,如果新增加的边导致最小生成树出现环路,则删除这条边;循环执行第2步,直到MST中边的数量等于N-1(N是节点的总数)。
与Prim算法相比,Kruskal算法的描述要简单得多,它的核心在于判断新增加的边是否构成环路。本文的思路是为每个节点增加一个根节点属性,如果新增边的两个端点的根节点相同,说明他们已经在一个相同的子树中,增加该边肯定会出现环路,因此予以舍弃。
python实现
在数据初始化阶段,除了构建边长矩阵之外,还要构建一个包含所有边的数组。为了判断两个点的根节点是否相同,我们还要准备一个数组保存所有点的根节点。下图是数据初始化的完整代码,代码中使用了生成器generator、过滤器filter、combinations()函数、sorted()函数,非常pythonic。
判断新增的边是否会产生闭环是该算法的难点所在。通常的思路是判断两个点在新增边之前是否连通,这种算法的时间复杂度很高,查询效率较低。本文的思路是记录每个点的根节点信息,每当增加边成功,就把点的根节点修改为P点的根节点。当需要增加边时,只需要判断M和N的根节点是否相同就可以了。
上图的代码已经非常简洁了,配合注释应该很容易理解。当然如果想让代码更加“面向对象”,可以定义两个类:边Edge和节点Node,端点、边长、根节点这些变量都可以当作属性封装到类中,这样会使代码更加清晰易懂。
总结
程序员绝对是世界上最聪明的一群人,在他们的大脑中存储了大量的设计模式、算法和数据结构,这些知识不仅可以用于应付本职工作,还可以在生活中发挥指导作用。流传于世的算法是无数高智商前辈先贤的智慧结晶,蕴涵了丰富的人生哲学。编程算法在你的生活中有哪些成功的应用案例,期待大家留言交流讨论。