第二個情感分析,主要通過python實現qq群訊息分析,分析群成員發言總次數,群成員情緒對比,單個群成員的發言詞雲狀況以及單個同學的發言情感走勢。 用到一下庫:
- re正則,matplotlib,wordcloud,numpy,jieba分詞,snownlp情感分析。
- 上述庫的用法很簡單,安裝也很簡單,所以不需要擔心門檻。
最好結合第一篇或者先看第一篇 詳細說一下模組的製作流程:
- 正則匹配文字內容,第一篇只考慮總計文字的展示,並沒有考慮到群成員的群體。所以要用字典{}講學生的qq/郵箱和暱稱存一下。還有他的發言記錄。這裡有個比較重要的是他的暱稱可能是變得,你的群訊息裡面展示的是那個時候他的群暱稱,,可能從大演說家變成啥啥啥的。所以我的思想就是主要按照qq/郵箱這個點確定唯一,而暱稱只用第一次出現的。文字先相加。
value={}
def analyseinformation(lines):
qqnow=''#qq或者email當前使用者
for line in lines:
if line != "\n" and line.strip() != "\n" and line != None and not line.__contains__("撤回了"):
line = line.replace("[表情]", " ").replace("@全體成員", " ").replace("[表情]", " ").\
replace("[QQ紅包]我發了一個“專享紅包”,請使用新版手機QQ查收紅。", "").replace("\n", " ").replace("[圖片]",'')
if pattern.search(line):#匹配到正確的物件
# print(line)
if pattern3.search(line):
qq1=str(pattern3.search(line).group(3))
namenow=str(pattern3.search(line).group(1))
if not qq1 in value.keys():
value[qq1]={'name':namenow,'qq':qq1,'text':[]}
qqnow=qq1#當前使用者發言發生了更改
elif pattern4.search(line):
email=str(pattern4.search(line).group(2))
namenow=str(pattern4.search(line).group(1))
if not email in value.keys():
value[email]={'name':namenow,'qq': email,'text':[]}
qqnow=email
# print(name)
elif not qqnow.__eq__(''):#初始化的時候的坑,初始化為'',前幾行沒用文字直接過濾
value[qqnow]['text'].append(str(line))
複製程式碼
- 上面就說講所有有用的資訊放到字典value中,但是我想用幾個小陣列分開儲存一些資訊。可以稍微處理一下:
time=[]#次數
text=[]#文字
name=[]#姓名
qq=[]#qq或者郵箱提取
def getmotion(values):
for key in values:
print(values[key])
time.append(values[key]['text'].__len__())
usertxt=''
for txt in values[key]['text']:
usertxt+=txt+' '
text.append(usertxt)
name.append(values[key]['name'])
qq.append(key)
複製程式碼
- 剩下就可以開始完成自己想要展示的部分了。首先,我想檢視這段時間每個人到底發言多少次。因為matplotlib圖形顯示不了太多,我顯示部分(可以自己更改,只不過是效果問題),你還可以自定義排序完成排序然後再展示:
#展示各個同學的發言次數
def getspeaktimeall(time,name):
Xi = np.array(time[20:50])#根據自己展示的需要需改範圍,我們群人數太多
Yi = np.array(name[20:50])
x=np.arange(0,30,1)
width=0.6
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來正常顯示中文標籤
plt.figure(figsize=(8, 6)) ##指定影像比例: 8:6
plt.barh(x , Xi, width, color='SkyBlue',alpha=0.8)
plt.xlabel("time")
plt.ylabel("name")
for a,b,c in zip(Xi,Yi,x):
print(a,b,c)
plt.text(a+10,c-0.4,'%d'%int(a),ha='center',va='bottom')
plt.yticks(x,Yi)
# plt.legend()
plt.show()
plt.close()
複製程式碼
- 我還想看到所有人的發言情感總的比較。那麼我就將所有同學的發言成為一個大的字串,然後用snownlp去分析,snownlp的api很簡單。 s=SnowNLP(text) print(s.sentiments)就出來了,這部分的坑點是標籤的展示我以前記錄過可以結合著看,就不詳述了。這部分詳細程式碼為:
def getemotionall(time,text,name,qq):
emotion=[]
for i in range(0,len(qq)):
print(name[i],text[i])
s=SnowNLP(text[i])
emotion.append(s.sentiments*100)
print(len(name),len(emotion))
Xi = np.array(emotion[10:40])
Yi = np.array(name[10:40])
x = np.arange(0, 30, 1)
width = 0.6
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來正常顯示中文標籤
plt.figure(figsize=(8, 6)) ##指定影像比例: 8:6
plt.barh(x, Xi, width, color='red',label='同學發言總情緒', alpha=0.8)
plt.xlabel("emotion")
plt.ylabel("name")
for a, b, c in zip(Xi, Yi, x):
print(a, b, c)
plt.text(a + 2, c - 0.4, '%d' % int(a), ha='center', va='bottom')
plt.yticks(x, Yi)
# plt.legend()
plt.show()
plt.close()
複製程式碼
- 接下來我想分析的是每個人的發言詞雲,這部分第一篇也講過實現的方式,程式碼就留在完整貼了。你可以檢視你討厭的人,喜歡的人,或者兩個人的聊天記錄。看看她關心啥。。嘿嘿?。
- 我還想看的就是每個人的情感走向,這個也挺有價值的,你可以分析她或他最近的若干條的情感走勢,如果整合最小二乘法預測還能畫一條情感預測的走勢出來,這裡就先不畫了。我才用的是折線圖,1代表積極,0代表消極,0.5代表中性。因為有的人發言太多,不利於圖示展示,我只去了他最近200條記錄,沒用基於時間,如果有興趣你還可以把時間整合進來。核心程式碼為:
def getemotionbyqq(value,qq):
va=value[qq]['text']
emotion=[]
for q in va[len(va)-200:len(va)]:
s = SnowNLP(q)
emotion.append(s.sentiments)
#print(s.sentiments)
x=np.arange(len(emotion))
y=np.array(emotion)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來正常顯示中文標籤
plt.figure(figsize=(12, 6)) ##指定影像比例: 8:6
plt.plot(x,y,label='emotion status')
plt.xlabel("最近200次發言情緒走勢")
plt.ylabel("0-1表示消極-積極")
plt.legend()
plt.show()
複製程式碼
附上程式碼和展示:
import re
from snownlp import SnowNLP
import numpy as np
import matplotlib.pyplot as plt ##繪相簿
from wordcloud import WordCloud
import jieba.analyse
time=[]#次數
text=[]#文字
name=[]#姓名
qq=[]#qq或者郵箱提取
value={}
pattern=re.compile(r'(\d*)-(\d*)-(\d*) .* .*')#匹配 2018-05-05 15:55:40 2班某某(1315426911) 有一個坑點就是2018-05-07 13:48:39 2XXX<xxxx@qq.com>這種格式
#pattern2=re.compile(r'(\d+):(\d+):\d+')#匹配 15:55:40
pattern3=re.compile(r'(\S+)(\()(.*?)(\))')#匹配 2班某某(1315426911)相關內容
pattern4=re.compile(r'(\S+)[<](.*)[>]')
def getemotionbyqq(value,qq):
va=value[qq]['text']
emotion=[]
for q in va[len(va)-200:len(va)]:
s = SnowNLP(q)
emotion.append(s.sentiments)
#print(s.sentiments)
x=np.arange(len(emotion))
y=np.array(emotion)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來正常顯示中文標籤
plt.figure(figsize=(12, 6)) ##指定影像比例: 8:6
plt.plot(x,y,label='emotion status')
plt.xlabel("最近200次發言情緒走勢")
plt.ylabel("0-1表示消極-積極")
plt.legend()
plt.show()
def getstudentcloudbyqq(value,qq):
va=value[qq]['text']
text=''
for q in va:
text+=q+' '
print(text)
ags = jieba.analyse.extract_tags(text, topK=40)
text=' '.join(ags)
wc = WordCloud(background_color="white",
width=1500, height=1000,
min_font_size=40,
font_path="simhei.ttf",
max_font_size=300, # 設定字型最大值
random_state=40, # 設定有多少種隨機生成狀態,即有多少種配色方案
) # 字型這裡有個坑,一定要設這個引數。否則會顯示一堆小方框wc.font_path="simhei.ttf" # 黑體
# wc.font_path="simhei.ttf"
my_wordcloud = wc.generate(text)
plt.imshow(my_wordcloud)
plt.axis("off")
plt.show()
plt.close()
def getemotionall(time,text,name,qq):
emotion=[]
for i in range(0,len(qq)):
print(name[i],text[i])
s=SnowNLP(text[i])
emotion.append(s.sentiments*100)
print(len(name),len(emotion))
Xi = np.array(emotion[10:40])
Yi = np.array(name[10:40])
x = np.arange(0, 30, 1)
width = 0.6
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來正常顯示中文標籤
plt.figure(figsize=(8, 6)) ##指定影像比例: 8:6
plt.barh(x, Xi, width, color='red',label='同學發言總情緒', alpha=0.8)
plt.xlabel("emotion")
plt.ylabel("name")
for a, b, c in zip(Xi, Yi, x):
print(a, b, c)
plt.text(a + 2, c - 0.4, '%d' % int(a), ha='center', va='bottom')
plt.yticks(x, Yi)
# plt.legend()
plt.show()
plt.close()
#展示各個同學的發言次數
def getspeaktimeall(time,name):
Xi = np.array(time[20:50])#根據自己展示的需要需改範圍,我們群人數太多
Yi = np.array(name[20:50])
x=np.arange(0,30,1)
width=0.6
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來正常顯示中文標籤
plt.figure(figsize=(8, 6)) ##指定影像比例: 8:6
plt.barh(x , Xi, width, color='SkyBlue',alpha=0.8)
plt.xlabel("time")
plt.ylabel("name")
for a,b,c in zip(Xi,Yi,x):
print(a,b,c)
plt.text(a+10,c-0.4,'%d'%int(a),ha='center',va='bottom')
plt.yticks(x,Yi)
# plt.legend()
plt.show()
plt.close()
def getmotion(values):
for key in values:
print(values[key])
time.append(values[key]['text'].__len__())
usertxt=''
for txt in values[key]['text']:
usertxt+=txt+' '
text.append(usertxt)
name.append(values[key]['name'])
qq.append(key)
#getmatplotlibtime(time,text,name,qq)
# getmatplotlibemotion(time,text,name,qq)
# print(time)
def analyseinformation(lines):
qqnow=''#qq或者email當前使用者
for line in lines:
if line != "\n" and line.strip() != "\n" and line != None and not line.__contains__("撤回了"):
line = line.replace("[表情]", " ").replace("@全體成員", " ").replace("[表情]", " ").\
replace("[QQ紅包]我發了一個“專享紅包”,請使用新版手機QQ查收紅。", "").replace("\n", " ").replace("[圖片]",'')
if pattern.search(line):#匹配到正確的物件
# print(line)
if pattern3.search(line):
qq1=str(pattern3.search(line).group(3))
namenow=str(pattern3.search(line).group(1))
if not qq1 in value.keys():
value[qq1]={'name':namenow,'qq':qq1,'text':[]}
qqnow=qq1#當前使用者發言發生了更改
elif pattern4.search(line):
email=str(pattern4.search(line).group(2))
namenow=str(pattern4.search(line).group(1))
if not email in value.keys():
value[email]={'name':namenow,'qq': email,'text':[]}
qqnow=email
# print(name)
elif not qqnow.__eq__(''):#初始化的時候的坑,初始化為'',前幾行沒用文字直接過濾
value[qqnow]['text'].append(str(line))
# print(name)
#print(value[name])
if __name__ == '__main__':
f = open('E:/text.txt', 'r', encoding='utf-8') # 要進行分詞處理的文字檔案 (統統按照utf8檔案去處理,省得麻煩)
lines = f.readlines()
#執行這個函式獲取分析才能解析value{}
analyseinformation(lines)
getmotion(value)#這個函式獲取一些name[]陣列的值
#核心分析函式:
getspeaktimeall(time,name)#選定區間的同學發言次數
getemotionall(time,text,name,qq)
getstudentcloudbyqq(value,'694459644')
getemotionbyqq(value,'694459644')
複製程式碼
- 發言的次數(我專挑小的區間為了展示)
- 情緒總的比較(跑的比較慢因為多)
- 某個同學的發言詞雲(我偷偷選了發言較多的班長。。)
- 單個人的情感走勢(我又偷偷分析了班長的?) 可以看到這小子最近幾次發言不太良好呢。
其實還是有遺憾的,因為snownlp訓練的是商品評論正負語料,有的地方不一定很準。希望有機會自己能做一個情緒分析的包。哎,路還很長。
水平優先,比較喜歡這塊,程式不夠精簡,如有改進地方,大佬請指正!