# 数据爬取
1. 维度表
- 微博用户画像表
用户id - 头像 - 昵称 - 粉丝数 - 微博数 - 微博链接 - 性别 - 所在地 - 微博内容表
微博id - 发布者id - 评论者id - 评论时间 - 回复数 - 点赞数 - 内容
2. 明细表
- 微博发布记录明细
微博id - 发布者id - 发布时间 - 转发数 - 评论数 - 点赞数 - 内容 - 微博内容链接 - 微博转发记录明细
转发微博id - 原始微博id - 发布者id - 转发者id - 转发时间 - 转发数 - 评论数 - 点赞数 - 内容 - 转发内容链接 - 微博评论记录明细
微博id - 发布者id - 评论者id - 评论时间 - 回复数 - 点赞数 - 内容
3. 用户关系表
- 发布者-转发者
# 数据分析挖掘
1. 意见领袖识别 - 影响最大化
寻找社会网络中最终影响范围最大的K个节点,从而使得这K个节点作为初始活跃节点集合,经过影响在社会网络中的传播,最终影响的节点数最多。
- 输入:G=(V, E, W), K
- 输出:种子节点集合S(使得最后网络中被激活的节点个数最多)
- 衡量标准
- 运行时间
- 算法精度(PageRank没有考虑传播过程)
- 可扩展性(能够适应海量数据)
1.1 影响最大化算法分类
- 贪心算法
- 优点:每次选择提供最大影响值的节点,通过局部最优解来近似全局最优解;
- 缺点:算法复杂度高(每次增加一个节点都要算影响范围),运行时间长;
- 思路:在当前活跃节点集合中,额外增加一个节点作为初始活跃节点,所能带来的最终影响值的增加量。
- 启发式算法
- 优点:设置启发式策略来选取最优影响力的节点,不需要精确计算结点的影响值;
- 缺点:运行时间短、效率高;
1.2 DegreeDiscount启发式
- Degree启发式:
- 思路:
以节点的度数来衡量节点的影响力,选择度数最大的K个节点;
网络中同其它节点平均距离最近的节点有更大的几率可以影响其它节点; - 特点:
执行时间短,精度差;
- 思路:
- DegreeDiscount启发式:
- 思路:
如果节点v的邻居节点存在节点u被选为初始活跃节点,由于两者的影响力存在重叠,则需要对节点v的度数进行度量折扣。
- 思路:
val url = jobConfig.getString("input.string")
val K = 10
// 将边文件转为Graph图对象
val graph = GraphLoader.edgeListFile(sc,url)
val s = ArrayBuffer[Long]()
var k = 0
// 用于进行折扣的矩阵:节点、出度数
var g = ArrayBuffer[Array[Long]]()
val od = graph.outDegrees.collect()
for(ele <- od){
g += Array(ele._1, ele._2, 0)
}
for(i <- 1 to K){
// 根据出度数进行排序
g.sortWith((a,b) => a(1)>b(1))
// 将邻居数最多的假如种子节点集合
s.insert(0, g(0)(0))
g.remove(0)
val edges = graph.edges.collect
// 找到刚取出节点的邻居节点集合
val neighbours = edges.filter(_.srcId == s(0))
var neighbourIds = ArrayBuffer[Long]()
for(ele <- neighbours)
neighbourIds += ele.dstId
for(ele <- neighbourIds){
// 如果剩下的折扣矩阵中存在拿出节点的邻居节点
if(g.exists({x:Array[Long] => x(0)==ele})){
k = g.indexWhere({x:Array[Long] => x(0) ==ele})
//更新t
g(k)(2) = g(k)(2)+1
//对其邻居节点的度进行折扣
g(k)(1) = (g(k)(1) - 2*g(k)(2) - (g(k)(1)-g(k)(2))*g(k)(2)) / 100
}
}
}
//result
s
2. 事件简介
事件简介模板
{事件微博总数} - {源头微博发布时间} - {源头微博发布主题、内容} - {事件持续时间}
3. 事件趋势
根据时间段,计算微博转发、原创数量;
4. 传播途径
按时间段划分,取不同时间段转发量的极大值作为传播途径关键节点;
5. 热点词
ANSJ分词包,根据TF-IDF计算词的权重,取Top20;
val hotWords = initialWeibo.flatMap(_.split("\n")).flatMap(line => {
val content = line.split("\t")(6)
val titlePattern = "【(.*?)】".r
val visualText = content.replaceAll("#.*?#|<.*?>|【|】", "")
val title = titlePattern.findFirstIn(content).getOrElse("").replaceAll("【|】", "")
val kwc = new KeyWordComputer[Analysis](20)
val result = kwc.computeArticleTfidf(title, visualText)
val keyWordList: Array[(String, Double)] = result.toArray().map(item => {
val keyWordCount = item.toString.split("/")
(keyWordCount(0), keyWordCount(1).toDouble)
})
keyWordList.take(20)
}).reduceByKey(_ + _).sortBy(-_._2).take(50)
6. 热门消息
将转发微博按原微博进行聚合,计算微博转发量、评论量提取原微博博主、微博内容等信息;
val original_input_collect = original_input.collect.groupBy(x => x(1))
original_input_collect.foreach(row => {
row._2(0) = row._2.maxBy(_ (3).toLong)
})
val original_input_sorted = original_input_collect.toSeq.sortWith(_._2(0)(3).toLong > _._2(0)(3).toLong)
var result = new java.util.ArrayList[Array[Any]]()
val forword_most_input_8 = original_input_sorted.take(8)
forword_most_input_8.foreach(row => {
val row_user_desc = user_desc.collect.find(x => x(0) == row._2(0)(1))
//微博头像、微博昵称、发布时间、转发数、评论数、点赞数、内容、微博内容链接
result.add(Array(row_user_desc.get(1),
row_user_desc.get(2),
row._2(0)(2),
row._2(0)(3),
row._2(0)(4),
row._2(0)(5),
row._2(0)(6),
row._2(0)(7)
))
})
7. 情绪分析
根据正则表达式提取微博中所有的表情符号,计算表情符号的WC,取Top n;
8. 传播主体分析
提取微博中的位置信息,根据位置做WC,再与省份匹配;
9. 核心传播人
Spark SQL关联两张表:用户信息表和评论转发表
先在评论转发表,聚合找到被转发数多的传播人;再关联用户信息表,获取用户信息即可;
case class WeiBoUser(user_id: Long, pic: String, user_name: String,fans:Long,follow:Long)
case class WeiBoHeat(WeiBoId:Long,user_id:Long,ZhuanFa:Long,Content:String)
//创建uesr-desc表
val user_desc = userDesc.map(_.split("\t")).map {
splited =>WeiBoUser(splited(0).toLong, splited(1).toString, splited(2).toString,splited(3).toLong,splited(4).toLong)
}.toDF()
user_desc.registerTempTable("user_desc")
val bigDatas1 = sqlContext.sql("select * from user_desc")
val weiboUserList = bigDatas1.javaRDD.collect()
//创建weibo_heat表
val weibo_heat = weiboHeat.map(_.split("\t")).map{
splited =>WeiBoHeat((0).toLong,splited(1).toLong,splited(2).toLong,splited(3).toString())
}.toDF()
weibo_heat.registerTempTable("weibo_heat")
val bigDatas2 = sqlContext.sql("select * from weibo_heat")
val weiboHeatList = bigDatas2.javaRDD.collect()
val digDatas3=sqlContext.sql("SELECT a.*,b.`ZhuanFa`,b.`Content` FROM `user_desc` a JOIN `weibo_heat` b ON a.`user_id`=b.`user_id` ORDER BY a.`fans` DESC,b.`ZhuanFa` DESC")
val heBingList=digDatas3.rdd.map{t => (t(0),(t(1),t(2),t(3),t(4),t(5),t(6)))}.groupBy(x => (x._1,x._2._3)).collect()
implicit val sortAnyByLong = new Ordering[Any]{
override def compare(a: Any, b: Any) =
a.toString.toLong.compare(b.toString.toLong)
}
val rdd1 = sc.parallelize(heBingList).sortBy(_._1._2,false).collect()
10. 影响分析
10.1 粉丝分布
根据用户粉丝数计数
10.2 海内外统计
根据海内外标签计数
10.3 男女比例
根据性别字段计数