1. 程式人生 > >用python對我和女票的聊天記錄生成心形詞雲

用python對我和女票的聊天記錄生成心形詞雲

前言

最近看到一些利用python製作詞雲的教程,突然想到用自己和女友的聊天記錄做一個詞雲,看看平時我倆最常說的都是啥,然後用愛心的形狀展示出來,以下是成品:

由於匯出的記錄只有最近兩個星期的,再加上這兩個星期我女票她都在備考,因此聊天內容並不是特別多,資料可能不是特別有代表性,但至少也能看看了。

資料處理

首先我們從QQ中匯出txt格式的聊天記錄,並在python中開啟

f = open('/Users/aaron/文件/My one and only.txt')
fl = f.readlines()

我們來檢視一下資料:

['\ufeff訊息記錄(此訊息記錄為文字格式,不支援重新匯入)\n
', '\n', '================================================================\n', '訊息分組:My one and only\n', '================================================================\n', '訊息物件:xxx\n', '================================================================\n', '\n', '2018-01-12 下午4:00:40 xxx\n', '好醜操\n
', '\n', '2018-01-12 下午4:00:49 xxx\n', '好臭\n', '\n', '2018-01-12 下午4:00:50 xxx\n', '好臭\n', '\n', '2018-01-12 下午4:01:27 xxx\n', '我吃牛肉乾\n', '\n',

可以看出前7行是頭資訊,下邊的資料按照:
- 時間,
- 單句聊天記錄,
- ‘\n’

每三行為一組,於是我們首先刪去頭資訊

del fl[:8]

接下來我們只需要從下標為1開始,步長為3的聊天記錄的資料:

fl = fl[1::3]

其中 [1::3] 的意思為下標為1開始,步長為3的切片,比如:

>>> a = [0,1,2,3,4,5,6,7,8,9]
>>> a[1::3]
[1, 4, 7]
>>> a[::3]
[0, 3, 6, 9]
>>> a[:5:2]
[0, 2, 4]

之後的資料變為一個全部由聊天記錄組成的列表:

['好醜操\n',
 '好臭\n',
 '好臭\n',
 '我吃牛肉乾\n',
 '去去味\n',
 '。。。。\n',
 ...
 ]

我們將其組成一個字串,使用 ' '.join(list) 可以將一個列表組合成一個以空格為間隔的字串:

strf = ' '.join(fl)

觀察資料,發現記錄中有非常多的雜質,例如 /扯一扯/糊臉, [放大招], [表情] 等,我們需要將這些雜質都去掉,於是匯入re正則表示式模組:

import re

兩種雜質,一種是以 / 開頭,一種是 [xx] 形式,我們用兩種正則表示式找出並轉換為集合去掉重複元素

list1 = re.findall(r'/.{2,3}', strf)
list2 = re.findall(r'\[.+?\]', strf)
set1 = set(list1)
set2 = set(list2)

我們可以看到:

image

以及

然後去掉這些雜質,因為有些出現頻率太高會影響最後結果

for item in set1:
    strf = strf.replace(item, '')
for item in set2:
    strf = strf.replace(item, '')

還有要自己手動去掉兩條:

strf = strf.replace('請使用最新版本手機QQ檢視', '')
strf = strf.replace('請使用最新版手機QQ體驗新功能', '')

資料乾淨之後就可以製作詞雲了。

jieba庫

我們利用 jieba 庫對記錄進行分詞操作,能將一個句子分為單個詞語。我們對jieba做一個簡單的瞭解,以下為官方文件中的一部分:

jieba.cut 方法接受三個輸入引數: 需要分詞的字串;cut_all 引數用來控制是否採用全模式;HMM 引數用來控制是否使用 HMM 模型

程式碼示例:

# encoding=utf-8
import jieba

seg_list = jieba.cut("我來到北京清華大學", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list))  # 全模式

seg_list = jieba.cut("我來到北京清華大學", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list))  # 精確模式

seg_list = jieba.cut("他來到了網易杭研大廈")  # 預設是精確模式
print(", ".join(seg_list))

seg_list = jieba.cut_for_search("小明碩士畢業於中國科學院計算所,後在日本京都大學深造")  # 搜尋引擎模式
print(", ".join(seg_list))

輸出:

【全模式】: 我/ 來到/ 北京/ 清華/ 清華大學/ 華大/ 大學

【精確模式】: 我/ 來到/ 北京/ 清華大學

【新詞識別】:他, 來到, 了, 網易, 杭研, 大廈    (此處,“杭研”並沒有在詞典中,但是也被Viterbi演算法識別出來了)

【搜尋引擎模式】: 小明, 碩士, 畢業, 於, 中國, 科學, 學院, 科學院, 中國科學院, 計算, 計算所, 後, 在, 日本, 京都, 大學, 日本京都大學, 深造

若相對jieba進行更深的瞭解,可以 點選此處

wordcloud庫

我們使用wordcloud包生成詞雲圖,首先了解一下其用法:

class wordcloud.WordCloud(font_path=None, width=400, height=200, margin=2, ranks_only=None, prefer_horizontal=0.9,mask=None, scale=1, color_func=None, max_words=200, min_font_size=4, stopwords=None, random_state=None,background_color='black', max_font_size=None, font_step=1, mode='RGB', relative_scaling=0.5, regexp=None, collocations=True,colormap=None, normalize_plurals=True)
font_path : string //字型路徑,需要展現什麼字型就把該字型路徑+字尾名寫上,如:font_path = '黑體.ttf'

width : int (default=400) //輸出的畫布寬度,預設為400畫素

height : int (default=200) //輸出的畫布高度,預設為200畫素

prefer_horizontal : float (default=0.90) //詞語水平方向排版出現的頻率,預設 0.9 (所以詞語垂直方向排版出現頻率為 0.1 )

mask : nd-array or None (default=None) //如果引數為空,則使用二維遮罩繪製詞雲。如果 mask 非空,設定的寬高值將被忽略,遮罩形狀被 mask 取代。除全白(#FFFFFF)的部分將不會繪製,其餘部分會用於繪製詞雲。如:bg_pic = imread('讀取一張圖片.png'),背景圖片的畫布一定要設定為白色(#FFFFFF),然後顯示的形狀為不是白色的其他顏色。可以用ps工具將自己要顯示的形狀複製到一個純白色的畫布上再儲存,就ok了。

scale : float (default=1) //按照比例進行放大畫布,如設定為1.5,則長和寬都是原來畫布的1.5倍。

min_font_size : int (default=4) //顯示的最小的字型大小

font_step : int (default=1) //字型步長,如果步長大於1,會加快運算但是可能導致結果出現較大的誤差。

max_words : number (default=200) //要顯示的詞的最大個數

stopwords : set of strings or None //設定需要遮蔽的詞,如果為空,則使用內建的STOPWORDS

background_color : color value (default=”black”) //背景顏色,如background_color='white',背景顏色為白色。

max_font_size : int or None (default=None) //顯示的最大的字型大小

mode : string (default=”RGB”) //當引數為“RGBA”並且background_color不為空時,背景為透明。

relative_scaling : float (default=.5) //詞頻和字型大小的關聯性

color_func : callable, default=None //生成新顏色的函式,如果為空,則使用 self.color_func

regexp : string or None (optional) //使用正則表示式分隔輸入的文字

collocations : bool, default=True //是否包括兩個詞的搭配

colormap : string or matplotlib colormap, default=”viridis” //給每個單詞隨機分配顏色,若指定color_func,則忽略該方法。



fit_words(frequencies)  //根據詞頻生成詞雲
generate(text)  //根據文字生成詞雲
generate_from_frequencies(frequencies[, ...])   //根據詞頻生成詞雲
generate_from_text(text)    //根據文字生成詞雲
process_text(text)  //將長文字分詞並去除遮蔽詞(此處指英語,中文分詞還是需要自己用別的庫先行實現,使用上面的 fit_words(frequencies) )
recolor([random_state, color_func, colormap])   //對現有輸出重新著色。重新上色會比重新生成整個詞雲快很多。
to_array()  //轉化為 numpy array
to_file(filename)   //輸出到檔案

瞭解了這兩個包之後,我們開始正式製作詞雲。

製作詞雲圖

首先匯入所需要的庫:

import matplotlib.pyplot as plt
import jieba
import wordcloud

然後利用詞雲進行分詞操作,並將生成的列表合併成字串:

word_list = jieba.cut(strf, cut_all=True)
word = ' '.join(word_list)

之後利用wordcloud包,注意一定要加上中文字型的路徑,因為wordcloud預設是英文字型,並不支援中文,我們只需自己指定字型即可,我這裡使用的是宋體,並且指定背景顏色是白色。

wc = wordcloud.WordCloud(font_path='/Library/Fonts/Songti.ttc', background_color='white').generate(word)

最後使用matplotlib進行繪製:

plt.imshow(wc)
plt.axis('off')
plt.show()

詞雲圖就生成好了:

心形詞雲

為了生成心形的詞雲,我們首先找一張心形的圖片:

然後:

from scipy.misc import imread

加上mask引數後再次製作詞雲:

pic = imread('/Users/aaron/Pictures/aixin.png')
wc = wordcloud.WordCloud(mask=pic, font_path='/Library/Fonts/Songti.ttc', width=1000, height=500, background_color='white').generate(word)

plt.imshow(wc)
plt.axis('off')
plt.show()

心形詞雲圖誕生!

趕緊學一招然後發給自己的女朋友吧!

或許不是最優方法,歡迎指導。

程式碼

最後附上全部程式碼:

import re
import matplotlib.pyplot as plt
import jieba
import wordcloud
from scipy.misc import imread


# 資料處理
f = open('/Users/aaron/文件/My one and only.txt')   # 改成自己的聊天記錄檔案
fl = f.readlines()
del fl[:8]
fl = fl[1::3]
strf = ' '.join(fl)
list1 = re.findall(r'/.{2,3}', strf)
list2 = re.findall(r'\[.+?\]', strf)
set1 = set(list1)
set2 = set(list2)
strf = strf.replace('請使用最新版本手機QQ檢視', '')
strf = strf.replace('請使用最新版手機QQ體驗新功能', '')
for item in set1:
    strf = strf.replace(item, '')
for item in set2:
    strf = strf.replace(item, '')

# 製作詞雲
word_list = jieba.cut(strf, cut_all=True)
word = ' '.join(word_list)
pic = imread('/Users/aaron/Downloads/aixin.png')    
wc = wordcloud.WordCloud(mask=pic, font_path='/Library/Fonts/Songti.ttc', width=1000, height=500, background_color='white').generate(word)

plt.imshow(wc)
plt.axis('off')
plt.show()