FRAUDAR: Bounding Graph Fraud in the Face of Camouflage 论文理解及算法解析
来源:互联网 发布:js写计算器 编辑:程序博客网 时间:2024/06/08 08:20
FRAUDAR: Bounding Graph Fraud in the Face of Camouflage
1、一段话概括算法
FRAUDAR算法来源于2016年KDD会议,该论文获得了当年的最佳论文奖。该算法要解决的问题是找出站内最善于伪装的虚假账户簇。其原理是虚假账户会通过增加和正常用户的联系来进行伪装,而这些伪装(边)会形成一个很紧密的子网络,这样就可以通过定义一个全局的度量,再移除二部图结构中的边,使得剩余网络结构对应的度量的值最大,这样就找到了最紧密的子网络,而这个网络就是最可疑的。
2、论文主页
http://www.andrew.cmu.edu/user/bhooi/projects/fraudar/index.html
3、背景
在社交网络或者电商网站中,存在着用户关注其他用户或者用户浏览商品的二部图,其中的虚假用户会通过关注正常用户来伪装自己,而用户也会通过多浏览其它商品来伪装其真正要浏览的商品。更严重的情况是有一些正常的用户可能被盗,从而被利用来进行关注或者浏览等。在这样的情况下,虚假用户或者被盗用户与目标之间就会形成一个“dense”的子网络。算法的目的就是找到这样的子网络,从而完成虚假用户行为的识别。
4、计算过程
算法的核心计算过程可以简要描述如下,具体可以参考原论文中Algorithm1的伪代码:
- a、建立优先树(一种用于快速移除图结构边的树结构);
- b、对于二部图中的任意节点,贪心地移除优先级最高(由优先树得到)的节点,直至整个网络结构为空;
- c、比较上述每一步得到的子网络结构对应的全局的度量,取该值最大的子网络结构,那么该子网络结构就是最紧密的子网络,也就是最可疑的团伙。
其中最关键的地方是定义了一个全局度量,该Metric的定义是(目标度量),可以理解成子网络结构中每个点的平均可疑程度
其中,
通过这样的定义,很容易可以得出4条性质:
- 固定其他条件,包含更高可疑度节点的子网络比包含较低可疑度节点的子网络更可疑;
- 固定其他条件,增加可疑的边使得子网络更可疑;
- 如果节点和边的可疑程度固定,那么大的子网络比小的子网络更可疑;
- 总的可疑程度相同,那么包含节点数少的子网络更可疑。
5、优先树
该算法的核心计算过程就是贪心地移除图中的点,使得每次变更f的变化最大,在移除一个节点的同时,只有与之相邻的节点会发生变化,那么这样最多产生O(|E|)次变更,如果找到合适的数据结构使得访问节点的时间复杂度为O(log|V|),那么总的时间复杂度就是O(NlogN)。
基于这样的考虑建立了优先树,这是一个二叉树,图中的每个节点都是树的一个叶子节点,其父节点为子节点中优先级较高的,树建完之后就可以按照O(log|V|)的速度获得优先级最高的节点。
6、通过Column-weighting来实现Camouflage Resistance
如何实现抵抗虚假行为呢?一个直观的方法是将图中每个边的嫌疑程度设为相等,但是为了实现抵抗虚假行为,我们不能这样做!如果节点i到一个度较大的节点j,那么将其边Cij的嫌疑降低,这是因为度较大的点本身可能就是很受欢迎的,例如大V和销售良好的商品。这使得我们不是仅仅关注度较大的节点,而是关注dense的子网络。
如果我们的邻接矩阵中,行代表用户,列代表目标。那么虚假用户向正常的目标增加边并不会使得子网络的嫌疑程度变低,因为虚假用户向正常的目标增加边只会使得正常目标对应的边的嫌疑程度下降,而嫌疑子网络内的权重却不会变化。
作者的实验指出Column-weighting函数选择类似于idf比较好,即
7、重要代码赏析
# 实际上这里只考虑了edge weight,没有考虑node weight,# 贪心算法只能保证是局部最优的,而不能保证是全局最优的def fastGreedyDecreasing(M, colWeights): (m, n) = M.shape Md = M.todok() Ml = M.tolil() # copy sparse matrix M Mlt = M.transpose().tolil() rowSet = set(range(0, m)) colSet = set(range(0, n)) curScore = c2Score(M, rowSet, colSet) print "curScore", curScore SSS = (len(rowSet) + len(colSet)) print "SSS", SSS bestAveScore = curScore / SSS print "bestAveScore", bestAveScore bestSets = (rowSet, colSet) print "finished setting up greedy" # 横轴是1,纵轴是0 rowDeltas = np.squeeze(M.sum(axis=1).A) # *decrease* in total weight when *removing* this row print "rowDeltas", type(rowDeltas) #print rowDeltas colDeltas = np.squeeze(M.sum(axis=0).A) print "colDeltas", type(colDeltas) #print colDeltas print "finished setting deltas" rowTree = MinTree(rowDeltas) colTree = MinTree(colDeltas) print "finished building min trees" numDeleted = 0 deleted = [] bestNumDeleted = 0 initLength = len(rowSet) while rowSet and colSet: if (len(colSet) + len(rowSet)) % 10000 == 0: pass # print "current set size = ", len(colSet) + len(rowSet) (nextRow, rowDelt) = rowTree.getMin() (nextCol, colDelt) = colTree.getMin() if rowDelt <= colDelt: # 如果行的权重变化小于列的,那么就减去行的,这样保留下来的较大 curScore -= rowDelt # 减去行之后,计算这行对所有列的影响,与该行有联系的列 # 更新列树,列树的权重由每一列相加得到 # colWeights,代表列中object的权重 #print "Ml.rows[nextRow]" #print Ml.rows[nextRow] # 减去要去掉的行对所有列的影响 # ml for j in Ml.rows[nextRow]: delt = colWeights[j] # 最核心的一句 colTree.changeVal(j, -colWeights[j]) rowSet -= {nextRow} rowTree.changeVal(nextRow, float('inf')) deleted.append((0, nextRow)) else: curScore -= colDelt # 计算这一列去掉后对每一行的影响,而这一列的权重就是colWeights[nextCol] # mlt,按照列查找与其相邻的所有行 for i in Mlt.rows[nextCol]: delt = colWeights[nextCol] # 最核心的一句 rowTree.changeVal(i, -colWeights[nextCol]) colSet -= {nextCol} colTree.changeVal(nextCol, float('inf')) deleted.append((1, nextCol)) numDeleted += 1 #print "numDeleted", numDeleted curAveScore = curScore / (len(colSet) + len(rowSet)) if curAveScore > bestAveScore: # print "curAveScore", curAveScore # print "bestAveScore", bestAveScore bestAveScore = curAveScore bestNumDeleted = numDeleted # reconstruct the best row and column sets finalRowSet = set(range(m)) finalColSet = set(range(n)) for i in range(bestNumDeleted): if deleted[i][0] == 0: finalRowSet.remove(deleted[i][1]) else: finalColSet.remove(deleted[i][1]) return ((finalRowSet, finalColSet), bestAveScore, bestNumDeleted)
# this is edge weight constructdef logWeightedAveDegree(M): print "begin computing weight matrix" print type(M) # print M, m is users in row, n is objects in column (m, n) = M.shape print "m, n", m, n colSums = M.sum(axis=0) print "colSums.shape", colSums.shape asum = colSums.A print "asum", type(asum) # print asum tempsqueeze = np.squeeze(asum) # squeeze, Remove single-dimensional entries from the shape of an array. print "tempsqueeze", type(tempsqueeze) #print tempsqueeze colWeights = 1.0 / np.log(tempsqueeze + 5) #print "colWeights", colWeights # row based sparse matrix colDiag = sparse.lil_matrix((n, n)) """Fills the diagonal elements {a_ii} with the values from the given sequence. If k != 0, fills the off-diagonal elements {a_{i,i+k}} instead. values may have any length. If the diagonal is longer than values, then the remaining diagonal entries will not be set. If values if longer than the diagonal, then the remaining values are ignored. """ colDiag.setdiag(colWeights) # print "colDiag", type(colDiag) # print colDiag #print "M", M W = M * colDiag # print "W", W print "finished computing weight matrix" return fastGreedyDecreasing(W, colWeights)
8、一些缺点及改进(个人观点)
- 因为是贪心计算,所以不能保证全局最优,文章中作者给出了理论上的“界”。
- 只能找出最dense的网络,通过循环地执行FRAUDAR算法可以得到多个子网络。
- 只考虑了edge的权重,没有考虑node的权重。
- FRAUDAR: Bounding Graph Fraud in the Face of Camouflage 论文理解及算法解析
- 【论文笔记】Applications of Graph Theory in Computer Science
- Blue in the face
- [深度学习论文笔记][Face Recognition] DeepFace: Closing the Gap to Human-Level Performance in Face Verificati
- 论文提要“DeepFace: Closing the Gap to Human-Level Performance in Face Verification”
- 【翻译+原创】DeepFace: Closing the Gap to Human-Level Performance in Face Verification 论文笔记
- FaceBook 论文:DeepFace: Closing the Gap to Human-Level Performance in Face Verification 笔记
- POJ 2553 The Bottom of a Graph TarJan算法题解
- Handbook of Face recognition 理解
- 《An Experimental Comparison of Partitioning Strategies in Distributed Graph Processing》——论文笔记
- 论文:The Role of Emotions in Context-aware Recommendation总结
- Exploring the Hidden Dimension in Graph Processing论文注释(待续。。)
- The first face-to-face with the living in London
- Agile Project Management: How to Succeed in the Face of Changing Project Requirements
- Clique in the Divisibility Graph
- 图割论文阅读笔记:Interactive Graph Cuts for Optimal Boundary & Region Segmentation of Objects in N-D Images
- The Documentatiion of Kinect Face Tracking
- The Documentatiion of Kinect Face Tracking
- Spring入门hello world常见问题及解决办法
- FastDFS单机配置
- 算法提高 计算器
- spring aop获取目标对象的方法对象及方法上的注解
- struts中日期格式转换
- FRAUDAR: Bounding Graph Fraud in the Face of Camouflage 论文理解及算法解析
- I2C
- 布局、浮动、塌陷现象
- 游戏跨服架构进化之路
- node express ejs 搭建个人网站(3)
- css 一些会用到的小技巧
- 如何用Tomcat部署前端静态文件
- Button背景颜色选择器。
- 华硕笔记本U盘启动BIOS设置方法