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]), ]
    

      

    结果如图

  • 相关阅读:
    MongoDB的C#驱动
    在C#使用MongoDB
    MongoDB 主从复制
    MongoDB 索引操作
    MongoDB 分片技术
    Mongodb 与sql 语句对照
    MongoDB命令使用示例
    MongoDB 高级操作
    MongoDB 细说增删查改
    MongoDB 运维技术
  • 原文地址:https://www.cnblogs.com/gyjerry/p/6014014.html
Copyright © 2011-2022 走看看