[Python舆情分析] 二.时间间隔分布研究及幂律分布图绘制

本文主要是做者学习舆情分析、情感分析、人类行为动力学分析的在线笔记,主要包括两方面内容,一是幂律特性,二是讲解时间间隔分布,三是Python绘制基于时间间隔分布的幂律特性图,四提供了另外一种方法。基础性文章,但愿对您有所帮助。python

参考前文:
[Python舆情分析] 一.舆情事件的幂律特性分析及时间间隔分布图绘制
[python数据分析] 简述幂率定律及绘制Power-law函数web

PS:最近参加CSDN2018年博客评选,但愿您能投出宝贵的一票。我是59号,Eastmount,杨秀璋。投票地址:https://bss.csdn.net/m/topic/blog_star2018/indexsql


一.幂律分布

在咱们的平常生活中Power Law(幂次分布,Power-law Distributions)是常见的一个数学模型,如二八原则。这个世界上是20%的人掌握80%的人的金钱去经营,20%的人口拥有80%的财富,20%的上市公司创造了80%的价值,80%的收入来自20%的商品,80%的利润来自20%的顾客等等。数据库

下图表示人类的财富幂率分布图,极少数人拥有微弱优点的人却拥有天文级别的财富。数组

为何会有这样的差异呢?
这是由于时间的乘积效应,智力上的微弱优点,乘以时间,就会获得价值(财富)几何级的增加。经济学财富分布知足Pareto Power law tail分布,语言中有词频的幂律分布,城市规模和数量知足幂律分布,音乐中有f分之1噪音(幂律分布)。一般人们理解幂律分布就是所谓的马太效应,二八原则,即少数人汇集了大量的财富,而大多数人的财富数量都很小,由于胜者通吃的原则。网络

f(x)表示某一数量指标x的发生次数,即幂率分布公式。app

幂率公式推导参考kevinelstri大神的 博客,以下图所示:svg

再如钱学森通讯反应间隔分布:函数


二.舆情分析基础知识

该部分主要借鉴引用以下论文,强烈推荐读者学习,尤为是研究舆情分析、图书情报、人类行为动力学的同窗。学习

  • 闫小勇. 人类个体出行行为的统计特征. 电子科技大学学报, 2011.
  • 刘海鸥, 等. 在线社交活动中的用户画像及其信息传播行为研究. 情报科学, 2018.
  • 梁晓敏, 等. 舆情时间中评论对象的情感分析及其关系网络研究. 情报科学, 2018.
  • 郭宇, 等. 基于情感分析的社会网络用户影响力模型研究. 情报科学, 2018.
  • Barabasi A-L. The origin of bursts and heavy tails in human dynamics. Natrue(London),2005,435:207-211.
  • 王澎. 人类在线行为的实证和建模. 安徽:中国科学技术大学,2010.

随着互联网迅速发展,社交网络发展为民众了解社会现象、舆情事件的重要平台,带来便利的同时,部分网民也会在互联网上宣泄情感,引起公共舆情事件。为了更好地进行舆情监控和情感预警,把握网民的情感趋向,基于人类行为动力学的舆情事件分析,探究舆情对象的情感变化和关系演化是很是必要的。

人类个体行为是隐藏在许多复杂社会经济现象背后的驱动力,定量理解人类行为是现代科学的一个重要研究课题。2005年,Barabási研究显示人类行为间隔规律是高度非均匀的,称之服从幂律分布,并在《天然》发表了一篇文章,开创了“人类行为动力学”的新研究方向。目前,科学家经过大量的实证统计发现了一些人类行为,如邮件通信、短信通信、网页浏览、电影点播、微博事件等的时间间隔近似服从幂律分布,这种幂律分布特性不管在群体水平仍是个体水平上均可以获得证明。除了发现人类行为的时间间隔分布中普遍存在的幂律现象外,近年来证明研究发如今人类的空间运动行为中也存在幂律分布特性,如停留时间分布和出行距离分布。

常见的人类行为动力学分析包括:时间间隔分布、活跃性分析、时间间隔分布宽度、时间间隔重标度、交互周期与热度分析、交互的阵发性和记忆性分析等。刘海鸥等老师研究发现微博、QQ群、天涯论坛、人人网服从幂律分布以下图所示,代表在线社交活动少数人处于活跃状态,积极频繁地发布消息,而大部分红员活跃性较低,处于静默状态。


三.Python时间间隔分布图绘制

为解释人类个体为什么具备高几率进行长时间停留的特征,一般会对个体在统计时间段内的平常活动事件序列进行分析。幂律特性分析一般会获得以下图所示的图形,而它如何经过Python进行绘制呢?

1.数据集
假设做者定义网络爬虫抓取了天涯社区某一个事件(如“嫦娥四号”事件)的992条回复信息,包括id、主题用户、评论点赞数、评论被追评数、评论内容、评论时间、积极情绪分数。如今须要绘制时间间隔分布图。

2.SQL语句
接着经过Python调用本地的MySQL数据库,并获取每一个评论的时间,而后绘制胖尾图,其中SQL语句核心代码以下:

select zhutishijian from yq_ml;

输出结果以下所示:

Python访问MySQL数据库的核心代码以下,本地数据库名为“20181228db”。

class lianjie(object):
    def __init__(self):
        pass
    def connect(self,hostaddress):
        self.conn = msd.connect(host = hostaddress,user = "root",passwd = "123456",db = "20181228db",charset = 'utf8')
        #cur = self.conn.cursor()
        return self.conn
    def guanbi(self):
        return self.conn.close()

3.时间间隔分布胖尾图

核心步骤以下:

  • 经过SQL语句获取每条评论的时间
  • 对评论时间数组进行排序,而后依次获取两两评论时间的时间间隔
  • 经过函数计算myset内容的无重复项,并统计每一个时间间隔出现的频次
  • 最后绘制Pow-low幂律分布图

完整代码以下:

# -*- coding: utf-8 -*-
from pylab import *
import MySQLdb as msd
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime

#绘图显示中文字体和负号
plt.rcParams['font.sans-serif'] = ['SimHei'] 
myfont = matplotlib.font_manager.FontProperties(fname='C:/Windows/Fonts/msyh.ttf')  
plt.rcParams['axes.unicode_minus'] = False 
font1 = {'family' : 'Times New Roman', 'weight' : 'normal', 'size'   : 26}

#连接本地数据库20181228db
class lianjie(object):
    def __init__(self):
        pass
    def connect(self,hostaddress):
        self.conn = msd.connect(host = hostaddress,user = "root",passwd = "123456",
                                db = "20181228db",charset = 'utf8')
        return self.conn
    def guanbi(self):
        return self.conn.close()

#时间间隔 幂律分布
if __name__ == '__main__':
    #调用数据
    lj = lianjie()
    conn = lj.connect("localhost")
    cur=conn.cursor()  
    #查询评论时间
    sql = "select zhutishijian from yq_ml;"
    cur.execute(sql)
    times = cur.fetchall()
    PLTimeList = [] #评论时间列表
    Period= [] #时间间隔
    PeriodSeconds = []

    #获取时间
    for i in times:
        PLTimeList.append(datetime.strptime(str(i[0]),"%Y-%m-%d %H:%M:%S"))

    PLTimeList.sort() #时间排序
    PLTimeList.reverse() #列表中元素反向

    #获取时间间隔再赋值给列表
    for i in range(0, len(PLTimeList)-1):    
       cnt = (PLTimeList[i]-PLTimeList[i+1]) 
       Period.append(cnt)
    #获取秒
    for i in Period:
        PeriodSeconds.append(i.seconds)
    print (PeriodSeconds)

    #myset是另一个列表,里面的内容是mylist里面的无重复项
    x = []
    y = []
    myset = set(PeriodSeconds)  
    for item in myset:
        #print("the %d has found %d" %(item, PeriodSeconds.count(item)))
        x.append(item)
        y.append(PeriodSeconds.count(item)) #出现数量

    #绘图
    plt.subplot(111)
    plt.plot(x, y,'ko')
    plt.yscale('log')
    plt.ylabel('P', font1)
    plt.xlabel('timespan', font1)
    plt.xscale('log')
    plt.ylim(0.5,20)
    #plt.xlim(0.001,)
    plt.show()

绘制最终的结果以下所示:


四.SQL语句获取时间间隔

因为做者比较喜欢SQL语句解决一些问题(虽而后台语言积极更好),但这里也提供这种SQL语句计算时间间隔的方法。由于感受语言之间相互转化并解决问题挺有意思的,但愿读者也试试。

1.时间间隔排序,ord_num为序号,输出下标从2开始,命名为A

select a.id, a.zhutishijian, (@i := @i + 1) as ord_num 
from yq_ml a,(select @i := 1) d 
order by zhutishijian

2.时间间隔排序,ord_num为序号,下标从1开始,命名为A。

3.利用TIMESTAMPDIFF获取A和B的时间间隔,该SQL语句较为复杂。

select TIMESTAMPDIFF(SECOND, A.zhutishijian, B.zhutishijian) sub_seconds, count(A.id)
from 
(select a.id, a.zhutishijian, (@i := @i + 1) as ord_num from yq_ml a,(select @i := 1) d 
 order by zhutishijian) as A 
LEFT JOIN 
(select a.id, a.zhutishijian, (@j := @j + 1) as ord_num from yq_ml a,( select @j := 0) c 
 order by zhutishijian) as B 
on A.ord_num=B.ord_num GROUP BY sub_seconds;

输出结果是各时间差出现的频次。

4.Python完整代码。

# -*- coding: utf-8 -*-
from pylab import *
import MySQLdb as msd
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime

#绘图显示中文字体和负号
plt.rcParams['font.sans-serif'] = ['SimHei'] 
myfont = matplotlib.font_manager.FontProperties(fname='C:/Windows/Fonts/msyh.ttf')  
plt.rcParams['axes.unicode_minus'] = False 
font1 = {'family' : 'Times New Roman', 'weight' : 'normal', 'size'   : 26}

#连接本地数据库20181228db
class lianjie(object):
    def __init__(self):
        pass
    def connect(self,hostaddress):
        self.conn = msd.connect(host = hostaddress,user = "root",passwd = "123456",
                                db = "20181228db",charset = 'utf8')
        return self.conn
    def guanbi(self):
        return self.conn.close()

#时间间隔 幂律分布
if __name__ == '__main__':
    #调用数据
    lj = lianjie()
    conn = lj.connect("localhost")
    cur=conn.cursor()  
    #查询评论时间
    sql = """select TIMESTAMPDIFF(SECOND, A.zhutishijian, B.zhutishijian) sub_seconds, count(A.id) from (select a.id, a.zhutishijian, (@i := @i + 1) as ord_num from yq_ml a,(select @i := 1) d order by zhutishijian) as A LEFT JOIN (select a.id, a.zhutishijian, (@j := @j + 1) as ord_num from yq_ml a,( select @j := 0) c order by zhutishijian) as B on A.ord_num=B.ord_num GROUP BY sub_seconds; """
    cur.execute(sql)
    result = cur.fetchall()

    #时间间隔 单位秒
    time1 = [n[0] for n in result]
    del time1[0] #第一个值为空
    print len(time1)
    print time1
    
    #出现频次
    num1 = [n[1] for n in result]
    del num1[0] 
    print len(num1),type(num1)
    print num1.index(max(num1)) #获取最大值的序列
    
    #绘图
    plt.subplot(111)
    plt.plot(time1, num1, 'ko')
    plt.yscale('log')
    plt.ylabel('P', font1)
    plt.xlabel('timespan', font1)
    plt.xscale('log')
    plt.ylim(0.5,20)
    #plt.xlim(0.001,)
    plt.show()

输出结果以下图所示,

这是2019年的基础性文章,但愿对你们有所帮助,不喜勿喷。同时,寒假已开始了本身奋斗学习之路,但愿一个月的时间能坚持把英语、专业课巩固上来。考博之路很艰辛,且努力且珍惜。娜女神和我一块儿加油,也但愿读者给我投一票吧。我是59号,Eastmount,杨秀璋。
投票地址:https://bss.csdn.net/m/topic/blog_star2018/index

(By:Eastmount 2019-01-24 下午2点 http://blog.csdn.net/eastmount/ )