zoukankan      html  css  js  c++  java
  • [读书笔记]机器学习:实用案例解析(11)

    第11章 分析社交图谱

    因为twitter的api方式改变了,因此按照书上的方法已经不能从twitter上获取到数据了,只能采用代码中附上的数据进行分析,而我安装的gephi无法打开图文件(.graphml)。因此本章仅讨论分析社交的思路,如果后面对web理解深入一点,再把调用api的部分补上。

    “个体网络”:指在网络中直接包围在一个单独节点周围的社交关系结构;是一个网络的子集,包括一个种子(个体)和它的邻居,也就是直接与种子相连的节点、节点与种子相连的边、以及各节点之间的边。

    以图的方式进行思考:无向图、有向图、带权有向图。

    “入边”(edges in)与“出边”(edges out):入边可以看做是粉丝;出边可以看做是朋友或者关注的人,对于个体的研究,出边比较有意义,可以推荐个体希望关注的人。

    调用API获取数据部分(暂时略)

    =============================================================================

    分析社交网络数据:

    第一步:提取图的核心元素。

    (1)“k核分析”:提取图形的2核子图:基于节点的连通性分解一个图,k核分析会得到一个k度的子图,2核分析就是由度大于等于2的节点构成的子图。选择2度的原因是,搜索方式的副作用会在网络外围产生很多单边连接的附属节点,贡献很少,需要删除。

    (2)种子节点的个体网络:只考虑出边连接的节点。

    第二步:对个体网络进行分析。

    (1)测量图中所有节点之间的距离

    (2)根据距离进行层次聚类,最开始所有节点都在一个大类里,最后分到每个节点单独一个类,画出聚类树状图。

    library(igraph)
    source('ML_for_Hackers/11-SNA/01_google_sg.R')
    
    #载入数据
    user <- 'johnmyleswhite'
    user.net <- read.graph(paste("ML_for_Hackers/11-SNA/data/", user, "/", user, "_net.graphml", sep = ""), format = "graphml")
    user.net <- set.vertex.attribute(user.net, "Label", value = get.vertex.attribute(user.net, "name"))
    #2核分析得到一个2度子图
    user.cores <- graph.coreness(user.net, mode = "in")
    user.clean <- subgraph(user.net, which(user.cores>1))
    #得到种子节点的个体网络子图
    user.ego <- subgraph(user.net, c(1, neighbors(user.net, user, mode = "out")))
    #测量图中所有 节点之间的距离
    user.sp <- shortest.paths(user.ego)
    #dist()函数由生成距离矩阵(主要目的是将user.sp的格式转换为hclust()可用的格式);
    #hclust()函数进行聚类,返回全部聚类信息的对象
    user.hc <- hclust(dist(user.sp))
    #画出聚类树状图
    plot(user.hc)
    

      

    使用Gephi可视化聚类网络(略)

    建立“感兴趣的人”引擎:

    基本原理:朋友的朋友是朋友(因为所谓的“敌人”在社交网络的好友功能无法体现,因此不考虑“敌人”的情况)

    #设置研究对象
    user <- 'drewconway'
    user.graph <- read.graph(paste("ML_for_Hackers/11-SNA/data/", user, "/", user, "_net.graphml", sep = ""), format = "graphml")
    #获取种子的所有朋友的用户名.V()可以返回图的某一特定属性,这里即是name
    friends <- V(user.graph)$name[neighbors(user.graph, user, mode = "out")]
    #get.edgelist()函数生成图的完整边列表
    user.el <- get.edgelist(user.graph)
    #检查矩阵中每一行是否包含了种子用户没有关注的“朋友的朋友”
    #ifelse()函数的逻辑:首先判断是否是种子用户或者第一个元素(起点)不是种子用户的朋友,两者之一为真就跳过这一行;
    #                    再看当前行的第二个元素(目标节点)是否是种子用户的朋友,若为真则跳过这一行
    non.friends <- sapply(1:nrow(user.el), function(i) ifelse(any(user.el[i, ]==user | !user.el[i, 1] %in% friends) | user.el[i, 2] %in% friends, FALSE, TRUE))
    #提取合适的行,并建立包含名字出现次数的表格
    non.friends.el <- user.el[which(non.friends==TRUE), ]
    friends.count <- table(non.friends.el[, 2])
    #找到这份数据中出现最多的用户,用table()函数创建的向量来创建一个数据框;
    #并使用归一化方法计算最应该被关注的推荐用户,即计算种子用户的朋友关注候选推荐用户的百分比
    #最后根据百分比递减排序,查看前10条数据
    friends.followers <- data.frame(list(Twitter.Users = names(friends.count), Friends.Following = as.numeric(friends.count)), stringsAsFactors = FALSE)
    friends.followers$Friends.Norm <- friends.followers$Friends.Following/length(friends)
    friends.followers <- friends.followers[with(friends.followers, order(-Friends.Norm)), ]
    friends.followers[1:10, ]
    

      

    但是这个推荐结果里面有很多用户是种子已经关注的人了。另一种思路是,除了推荐“朋友的朋友外”,也可以推荐某个已知维度上和种子用户类似的朋友的朋友,也就是通常所说的圈子。

    #推荐某个圈子中的“朋友的朋友”
    #结果的friends.partitions矩阵中,第一列是分割编号,第二列是用户名
    user.ego <- read.graph(paste("ML_for_Hackers/11-SNA/data/", user, "/", user, "_ego.graphml", sep = ""), format = "graphml")
    friends.partitions <- cbind(V(user.ego)$HC8, V(user.ego)$name)
    head(friends.partitions)
    

      

    #这个函数的目的是,输入分割编号(不同的编号代表不同的圈子),输出这个分割编号里被种子用户的朋友关注最多的用户,也就是要给种子用户推荐的那个用户
    partition.follows <- function(i) {
      friends.in <- friends.partitions[which(friends.partitions[, 1] == i), 2]
      partition.non.follow <- non.friends.el[which(!is.na(match(non.friends.el[, 1], friends.in))), ]
      if (nrow(partition.non.follow) < 2) {
        return(c(i, NA))
      } else {
        partition.favorite <- table(partition.non.follow[, 2])
        partition.favorite <- partition.favorite[order(-partition.favorite)]
        return(c(i, names(partition.favorite)[1]))
      }
    }
    
    partition.recs <- t(sapply(unique(friends.partitions[, 1]), partition.follows))
    partition.recs <- partition.recs[!is.na(partition.recs[, 2]) & !duplicated(partition.recs[, 2]), ]
    

      

    结果如图

  • 相关阅读:
    PAT 1088. Rational Arithmetic
    PAT 1087. All Roads Lead to Rome
    PAT 1086. Tree Traversals Again
    PAT 1085. Perfect Sequence
    PAT 1084. Broken Keyboard
    PAT 1083. List Grades
    PAT 1082. Read Number in Chinese
    求最大公因数
    [转载]Latex文件转成pdf后的字体嵌入问题的解决
    [转载]Matlab有用的小工具小技巧
  • 原文地址:https://www.cnblogs.com/gyjerry/p/6014014.html
Copyright © 2011-2022 走看看