微信基本上是使用最頻繁的一款軟體了,因為工作、學習、興趣愛好等各種各樣的原因,加入了很多很多群。今天,就利用 Python 對加入的微信群聊天記錄進行一些簡單的分析。
資料分析工作在 Jupyter 環境下開展,使用到的庫主要有:
- pandas
- numpy
- matplotlib
- seaborn
- re
1 資料獲取
要對微信群聊天記錄進行分析,首先需要獲取微信群聊天記錄。微信聊天記錄除儲存在騰訊的伺服器,也會在本地進行儲存。因此,我們可以從手機端將聊天記錄匯出,獲取我們需要的資料。
iPhone 版微信聊天記錄匯出可以參考 hangcom 的分享,Android 版可借鑑於 @godweiyang 的分享。
微信本地資料庫儲存在 EnMicroMsg.db
中,該資料庫中的比較重要的表有:
- userinfo: 使用者個人資訊
- voiceinfo: 傳送過的語音訊息
- VoiceTransText: 轉換為語音訊息後的文字
- chatroom: 微信群資訊
- message: 聊天記錄
- HardDeviceRankInfo: 硬體裝置資訊 ~ 微信運動資料
- EmojiGroupInfo: 表情包組資訊
- rcontact: 聯絡人資訊
- friend_ext: 朋友相關資訊
- SportStepItem: 個人運動步數 ~ 一天可能會存在多條資料
本次分析中主要使用到的有 chatroom, message, rcontact
三張表,使用 sqlcipher.exe
及之前獲得的密碼將需要用到的表匯出為 csv
格式。
2 資料預處理
在獲得相關資料後,我們將之匯入 pandas 進行一些預處理,以便於後續資料分析工作。
import re
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
pd.options.display.max_rows = 10
plt.rcParams['font.sans-serif']=['SimHei']
sns.set(font='SimHei')
%matplotlib inline
定義一些後續會使用到變數:
my
: 個人微訊號
my = 'wxid_********22'
2.1 資料讀取
匯入資料時需注意:
- 先將 csv 檔案在本地轉換為 ‘utf-8’ 格式(使用 pandas 以 ‘gb2312’ 匯入出錯);
- 匯入時將 message 設定
index_col=6
,以訊息傳送或收取時間為索引,便於後續分析。
chatroom = pd.read_csv('chatroom.csv')
message = pd.read_csv('message.csv', index_col=6)
rcontact = pd.read_csv('rcontact.csv')
各 DataFrame 中要使用的資料及含義如下:
- chatroom: 微信群資訊
- chatroomname: 微信群名 ~ 微信自動生成 ~ 唯一
- memberlist: 使用者列表 ~ 微訊號列表
- roomowner: 群主微訊號
- memberCount: 群成員數量(可能存在錯誤)
- message: 聊天記錄
- type: 訊息型別
- isSend: 傳送或接收訊息
- createTime: 傳送訊息的時間 ~ 已被設定為 Index
- talker: 聊天物件
- content: 聊天內容
- rcontact: 聯絡人 ~ 實際上是有過聯絡的所有人(包括微信群中的非好友)
- username: 使用者名稱資訊 ~ 微訊號 ~ 自動生成
- alias: 別名 ~ 修改過的微訊號
- conRemark: 備註名
- nickname: 暱稱
- type: 聯絡人型別
chatroom = chatroom[['chatroomname', 'memberlist', 'roomowner', 'memberCount']]
chatroom.head()
chatroomname | memberlist | roomowner | memberCount | |
---|---|---|---|---|
0 | 5604******@chatroom | wxid_********22;fj*****71;wxid_****82... | Gr******92 | 18 |
1 | 1202******@chatroom | Gr******92;lk******09;zh******75;sh... | su***e | 24 |
2 | 7766*****@chatroom | ww**4;cha****;wxid_***22;wxid_... | dc****25 | 166 |
3 | 1682****@chatroom | wxid_****;wxid_****21;wxid_2... | wxid_****21 | 9 |
4 | 4346****@chatroom | wxid_*****22;wxid_****22;wxid_2... | wxid_*****22 | 52 |
message = message[['type', 'isSend', 'talker', 'content']]
message.head()
type | isSend | talker | content | |
---|---|---|---|---|
createTime | ||||
1537709186000 | 318767153 | 0.0 | weixin | <msg>\n <appmsg appid="" sdkver="0">\n ... |
1537709314000 | 1 | 0.0 | weixin | 歡迎你再次回到微信。如果你在使用過程中有任何的問題或建議,記得給我發信反饋哦。 |
1534500421000 | 1 | 0.0 | 5604****@chatroom | w***i:\n又下雨了[捂臉] |
1534500558000 | 1 | 0.0 | 5604****@chatroom | ch***6:\n吃個飯先 |
1534500839000 | 1 | 0.0 | 5604****@chatroom | XL***45:\n來玩嗎 |
rcontact = rcontact[['username', 'alias', 'conRemark', 'nickname', 'type']]
rcontact.head()
username | alias | conRemark | nickname | type | |
---|---|---|---|---|---|
0 | filehelper | NaN | NaN | 檔案傳輸助手 | 1 |
1 | qqmail | NaN | NaN | QQ郵箱提醒 | 33 |
2 | floatbottle | NaN | NaN | 漂流瓶 | 33 |
3 | shakeapp | NaN | NaN | 搖一搖 | 33 |
4 | lbsapp | NaN | NaN | 附近的人 | 33 |
2.2 rcontact 預處理
rcontact.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4569 entries, 0 to 4568
Data columns (total 5 columns):
username 4568 non-null object
alias 1036 non-null object
conRemark 389 non-null object
nickname 4498 non-null object
type 4569 non-null int64
dtypes: int64(1), object(4)
memory usage: 178.6+ KB
對於部分聯絡物件(如群聊)無 alias, conRemark
是十分正常的現象,對於這兩列資料直接填充為 ‘EMPTY’;而無 username
的聯絡人僅 1 條資料,直接刪除即可。
rcontact.dropna(subset=['username'], inplace=True)
rcontact.fillna({'alias': 'EMPTY', 'conRemark': 'EMPTY'}, inplace=True)
rcontact[rcontact.nickname.isnull()]
username | alias | conRemark | nickname | type | |
---|---|---|---|---|---|
436 | 5479****@chatroom | EMPTY | EMPTY | NaN | 2 |
445 | fake_1573021893227 | EMPTY | EMPTY | NaN | 0 |
1261 | fake_1538661262204 | EMPTY | EMPTY | NaN | 0 |
1340 | fake_1541554264077 | EMPTY | EMPTY | NaN | 0 |
1342 | fake_1539142500399 | EMPTY | EMPTY | NaN | 0 |
... | ... | ... | ... | ... | ... |
4174 | fake_1576654843913 | EMPTY | EMPTY | NaN | 0 |
4205 | fake_1577183589467 | EMPTY | EMPTY | NaN | 0 |
4217 | fake_1577447590269 | EMPTY | EMPTY | NaN | 0 |
4328 | fake_1578041960745 | EMPTY | EMPTY | NaN | 0 |
4501 | fake_1580712150796 | EMPTY | EMPTY | NaN | 0 |
70 rows × 5 columns
對於 nickname
為空剩餘 70 位聯絡人,其中 63 位以 'fake_'
開頭,4 個群聊和另外 3 個使用者,暫時將這部分資料先保留,填充為 'ALIEN'
。
nan = rcontact.nickname.isnull()
name = rcontact.username.str
print('fake_: ', rcontact[nan & name.startswith('fake_') ]['username'].count())
print('@chatroom: ', rcontact[nan & name.endswith('@chatroom') ]['username'].count())
fake_: 63
@chatroom: 4
rcontact.fillna({'nickname': 'ALIEN'}, inplace=True)
經個人整理推斷,rcontact.type 表示含義如下:
- 0: 使用過的小程式
- 1: 新增使用者的好友 ~ 含公眾號
- 2: 群聊
- 3: 使用者主動新增的好友 ~ 含關注的公眾號
- 4: 同微信群非好友
- 7: 聊天頻次高的好友
- 8, 9, 10, 11: 已刪除或被刪除的好友
- 33: 微信官方
- 259: 不讓他看我朋友圈
- 2051: 置頂好友
- 8193: 未聊過天的好友
- 65536, 65537, 65539: 不看對方朋友圈的好友
rcontact[rcontact.username.str.endswith('@chatroom')].type.value_counts()
2 92
0 2
Name: type, dtype: int64
也即,在本地資料庫中存在兩個微信群 'type'
標註錯誤的情況,將之修正。
rcontact.loc[rcontact.username.str.endswith('@chatroom'), 'type'] = 2
為便於後續運算將微信聯絡物件簡化為並選取 contact_type
為 ['好友', '非好友', '群聊']
三類。
contact_dict = {1:'好友', 2:'群聊', 3:'好友', 4:'非好友', 7:'好友', 8:'非好友', 9:'非好友', 10:'非好友',
11:'非好友', 259:'好友', 2051:'好友', 8193:'好友', 65536:'好友', 65537:'好友', 65539:'好友'}
rcontact['contact_type'] = rcontact['type'].map(contact_dict)
rcontact = rcontact[rcontact.contact_type.isin(['好友', '非好友', '群聊'])]
rcontact.contact_type.value_counts()
非好友 2697
好友 552
群聊 94
Name: contact_type, dtype: int64
2.3 chatroom 處理
從匯入的情況來看,共有 94 個群聊,為了獲取關於群聊更詳細的資料,我們需要將 chatroom
與 rcontact
合併。
chatroom = pd.merge(chatroom, rcontact, left_on='chatroomname', right_on='username')
chatroom.groupby(['alias', 'conRemark'])['chatroomname'].count()
alias conRemark
EMPTY EMPTY 94
Name: chatroomname, dtype: int64
也即,alias, conRemark
兩列資料均為填充資料,實際上,微信群也沒有「別名」和「備註」的概念,將這兩列直接拿掉。另,chatroomname
和 username
重複,去掉其中一列。
chatroom.drop(columns=['alias', 'conRemark', 'username'], inplace=True)
chatroom.head()
chatroomname | memberlist | roomowner | memberCount | nickname | type | contact_type | |
---|---|---|---|---|---|---|---|
0 | 5712****@chatroom | wxid_***... | Gr****92 | 18 | 首屆吐槽大會 | 2 | 群聊 |
1 | 1202****@chatroom | Gr*6... | s****e | 24 | 2018?? | 2 | 群聊 |
2 | 7766***@chatroom | ww*_... | d**** | 166 | 建投公司 | 2 | 群聊 |
3 | 1682****@chatroom | wxid_... | wxid_** | 9 | 2017 | 2 | 群聊 |
4 | 4346****@chatroom | wxid_... | wxid_****22 | 52 | 沒有煩惱的青春 | 2 | 群聊 |
chatroom['memberCount'].value_counts()
-1 9
7 5
11 5
10 5
18 4
..
36 1
25 1
230 1
34 1
418 1
Name: memberCount, Length: 47, dtype: int64
我們發現,memberCount
群成員數量中出現負數 ~ 明顯不正常,需要進行調整;而群成員數量可通過 memberlist
計數獲取。
chatroom.memberlist.str.split(';').str.len().value_counts().sort_index()
2 2
3 3
4 4
5 3
6 1
..
166 1
206 1
230 1
405 1
418 1
Name: memberlist, Length: 48, dtype: int64
(chatroom.memberlist.str.split(';').str.len() == chatroom.memberCount).sum()
85
經測算,通過對群成員計數獲得的群成員數與 memberCount
相等共有 85 項,也即除 memberCount
為 -1 的情況均相等;採用對 memberlist
計數的值完善 memberCount
。
chatroom['memberCount'] = chatroom.memberlist.str.split(';').str.len()
2.4 message 預處理
本次計劃對微信群聊天記錄進行分析,也即對 talker
以 '@chatroom'
的聊天記錄進行分析。
message = message[message.talker.str.endswith('@chatroom')]
索引 createTime
是以毫秒為單位的累計時間,將之轉換為常見格式。
message.index = pd.to_datetime(message.index, unit='ms', utc=True).tz_convert('Asia/Shanghai')
message.head()
type | isSend | talker | content | |
---|---|---|---|---|
createTime | ||||
2018-08-17 18:07:01+08:00 | 1 | 0.0 | 5604****@chatroom | we****:\n又下雨了[捂臉] |
2018-08-17 18:09:18+08:00 | 1 | 0.0 | 5604****@chatroom | ch**:\n吃個飯先 |
2018-08-17 18:13:59+08:00 | 1 | 0.0 | 2434****@chatroom | tc**:\n來玩嗎 |
2018-08-17 18:14:04+08:00 | 3 | 0.0 | 5604****@chatroom | XL**:\n<msg><img cdnbigimgurl="null" hd... |
2018-08-17 18:14:13+08:00 | 1 | 0.0 | 1285**@chatroom | l***:\n加班 |
message.info()
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 155485 entries, 2018-08-17 18:07:01+08:00 to 2020-02-16 11:38:21+08:00
Data columns (total 4 columns):
type 155485 non-null int64
isSend 155477 non-null float64
talker 155485 non-null object
content 155415 non-null object
dtypes: float64(1), int64(1), object(2)
memory usage: 5.9+ MB
message 表 isSend
缺 8 項,content
缺 70 項:
isSend
為空值時表示群通話結束 ~ 與發起群語音通話對應,可直接刪除;content
為分析重點,缺項少,空值直接刪除。
message.dropna(subset=['isSend', 'content'], inplace=True)
需注意的是,isSend
有三種值:
- 1: 表示自己發出的訊息;
- 0: 表示接受訊息;
- 2: 其他訊息,出現的包括群語音通話和我發起的拉人入群。
message.isSend.value_counts()
0.0 153785
1.0 1611
2.0 11
Name: isSend, dtype: int64
經推斷,不同的 type
表示的訊息種類如下:
- 1: 普通文字訊息
- 3: 普通圖片
- 34: 語音訊息
- 42: 公眾號名片
- 43: 普通視訊
- 47: 表情包
- 48: 定位訊息
- 49: 公眾號或小程式分享
- 64: 群語音通話 ~ 發起群語音通話 isSend 為 2,結束 isSend 為 NaN
- 10000: 撤回訊息
- 1048625: 收藏的表情
- 16777265: 網頁分享
- 436207665: 微信紅包
- 486539313: 轉發公眾號內的視訊
- 520093745: 微信卡包 ~ 禮品卡
- 570425393: 邀請加入群聊資訊
- 587202609: 小程式訊息 ~ 遊戲
- 805306417: 微信接龍
- 822083633: 引用回覆訊息
- -1879048186: 位置共享
為便於後續處理,對型別進行簡化處理:
message_dict = {1: '文字', 3: '圖片', 34: '語音', 42: '公眾號', 43: '視訊', 47: '表情', 48: '位置',
49: '公眾號', 64: '通話', 10000: '撤回', 1048625: '表情', 16777265: '網頁',
436207665: '紅包', 486539313: '視訊', 520093745: '公眾號', 570425393: '加群',
587202609: '公眾號', 805306417: '文字', 822083633: '文字', -1879048186: '位置'}
message['message_type'] = message.type.map(message_dict)
此外,content
列不僅包含聊天的內容,還包括髮言人員的微訊號;微訊號與聊天內容以 ':'
進行分割,微訊號僅包含 [a-zA-Z0-9_\-]
字元。
使用 map
適合單列對映,但此處還需用到 type
資訊幫助判斷,因此並不適合 ~ 直接拆分後文字中含 :
的非使用者發言會被當做使用者發言;無 :
會被全部當成本人。此處藉助於 apply
函式實現
regex = re.compile('([a-zA-Z0-9_\-]+):(.*)', flags=re.S)
username = set(rcontact.username)
def split_content(record):
content = str(record.content).strip()
if record.isSend == 0:
# 即使用者接受的訊息
m = regex.match(content)
# print(m.groups())
if m and (m.group(1) in username):
# 即正確匹配上並且拆分的使用者名稱在 username 中
return (m.group(1), m.group(2).strip())
else:
# 實際上沒有使用者的情況
return ('None User', content)
elif record.isSend == 1:
# 使用者傳送的訊息
return (my, content)
else:
# 其他訊息 record.isSend == 2
return ('None User', content)
message['username'], message['real_content'] = message.apply(split_content, axis=1).str
message[message.username == 'None User'].type.value_counts()
10000 1745
570425393 780
64 8
Name: type, dtype: int64
也即,只有「撤回訊息」、「拉人進群」以及「群通話」共 2533 條訊息被標記為 ‘None User’。
3 初步分析
進行簡單初步分析:
- 聯絡人 ~ 好友、非好友發言頻次分析
- 發言型別 ~ 依據群聊人數多少分析發言型別之間的差異
3.1 發言頻次分析
首先,統計所有聯絡人發言的頻次資訊;再將之與 rcontact
合併。
people = message.groupby('username')['real_content'].count()
people = pd.merge(people, rcontact, left_index=True, right_on='username', how='right')
people.head()
real_content | username | alias | conRemark | nickname | type | contact_type | |
---|---|---|---|---|---|---|---|
0 | NaN | filehelper | EMPTY | EMPTY | 檔案傳輸助手 | 1 | 好友 |
48 | 1611.0 | wxid_*****22 | **** | EMPTY | M** | 1 | 好友 |
49 | NaN | gh_** | z*u | EMPTY | Z*會 | 3 | 好友 |
51 | NaN | gh_* | ls** | EMPTY | 龍*網 | 3 | 好友 |
52 | NaN | wxid_** | EMPTY | 大* | 學* | 1 | 好友 |
將 'real_content'
列名改為 'counts'
,該列為空的實際就表示該聯絡人未發言,可直接填充為 0。
people.columns = ['counts', 'username', 'alias', 'conRemark', 'nickname', 'type', 'contact_type']
people.fillna(0, inplace=True)
people.sort_values(by='counts').tail(10)
counts | username | alias | conRemark | nickname | type | contact_type | |
---|---|---|---|---|---|---|---|
2888 | 2432.0 | wxid_** | li**h | EMPTY | 雨眠** | 4 | 非好友 |
2459 | 2473.0 | wa** | EMPTY | EMPTY | 小業* | 4 | 非好友 |
2815 | 2677.0 | wxid_** | a5** | EMPTY | 白濤** | 4 | 非好友 |
2955 | 2757.0 | wxid_** | Y** | EMPTY | 花** | 4 | 非好友 |
3125 | 2976.0 | O* | EMPTY | EMPTY | 開心** | 4 | 非好友 |
3115 | 4117.0 | wxid_** | EMPTY | EMPTY | 金** | 4 | 非好友 |
357 | 5264.0 | wxid_** | Y** | 飛** | 大** | 3 | 好友 |
2869 | 5300.0 | H* | EMPTY | EMPTY | T* | 4 | 非好友 |
2920 | 5646.0 | wxid_** | EMPTY | EMPTY | rap** | 4 | 非好友 |
2790 | 10204.0 | h** | s** | EMPTY | 豆* | 4 | 非好友 |
也即,10 個發言最多的人 ~ None User 除外以及一位是自己的好友,其餘均為同微信群中的非好友。
而作為加群最多的自己發言排在第 23 位,哈哈。
rank = people['counts'].rank(method='max')
rank.max() - rank[people[people.username == my].index] + 1
48 23.0
Name: counts, dtype: float64
再來看看不同型別的好友發言量總量、平均量、方差。
people.groupby('contact_type')['counts'].agg(['sum', 'mean', 'median', 'std', 'count'])
sum | mean | median | std | count | |
---|---|---|---|---|---|
contact_type | |||||
好友 | 58605.0 | 106.168478 | 0.0 | 354.541844 | 552 |
群聊 | 0.0 | 0.000000 | 0.0 | 0.000000 | 94 |
非好友 | 94269.0 | 34.953281 | 0.0 | 309.216804 | 2697 |
我們可以很明顯的看到好友和非好友之間發言上的差異,好友的發言均值要明顯高於非好友;而兩者都有的共同點就是方差大 ~ 而潛水使用者佔據比例高。
people[people.counts == 0].groupby('contact_type')['username'].count() / people.contact_type.value_counts()
好友 0.54529
群聊 1.00000
非好友 0.62551
dtype: float64
在分析聊天物件時微信群可直接去掉。
people = people[people.contact_type != '群聊']
將使用者按發言次數進行分組:[[0.0, 1.0) < [1.0, 10.0) < [10.0, 100.0) < [100.0, 1000.0) < [1000.0, 10205.0)]
,檢視各組人數並繪製柱狀圖。
people_groups = ['深水炸彈', '潛伏者', '小氣泡', '活躍分子', '資深話癆']
people_bins = [0, 1, 10, 100, 1000, people.counts.max()+1]
people['cat'] = pd.cut(people['counts'], people_bins, labels=people_groups,right=False)
people['cat'].value_counts()
深水炸彈 1988
潛伏者 610
小氣泡 450
活躍分子 168
資深話癆 33
Name: cat, dtype: int64
cat_counts = pd.crosstab(people.cat, people.contact_type)
cat_counts.plot(kind='bar')
也即,無論是好友或非好友,不發言的均佔據絕大多數。
3.2 發言型別分析
將群聊和發言合併,並選取需要的資料列
room = pd.merge(chatroom, message, left_on='chatroomname', right_on='talker')
room = room[['chatroomname', 'memberCount', 'message_type']]
按群大小進行分組:(0, 10] < (10, 20] < (20, 50] < (50, 100] < (100, 419]
,檢視各個大小群發言型別偏好。
room_groups = ['小小群', '小群', '中型群', '大型群', '巨型群']
room_bins = [0, 10, 20, 50, 100, chatroom.memberCount.max()+1]
room['cat'] = pd.cut(room['memberCount'], room_bins, labels=room_groups)
不同大小群各種型別發言總量偏好
room_total = room.groupby('cat')['chatroomname'].count()
talk_count = pd.crosstab(room.cat, room.message_type)
talk_count
message_type | 位置 | 公眾號 | 加群 | 圖片 | 撤回 | 文字 | 紅包 | 網頁 | 表情 | 視訊 | 語音 | 通話 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
cat | ||||||||||||
小小群 | 19 | 365 | 57 | 891 | 145 | 7920 | 207 | 1 | 523 | 90 | 68 | 0 |
小群 | 56 | 619 | 90 | 1751 | 396 | 28293 | 328 | 0 | 2650 | 205 | 235 | 2 |
中型群 | 27 | 405 | 235 | 733 | 264 | 10278 | 49 | 0 | 536 | 88 | 492 | 0 |
大型群 | 6 | 346 | 103 | 1562 | 159 | 4053 | 465 | 6 | 183 | 384 | 600 | 0 |
巨型群 | 32 | 1073 | 295 | 4011 | 798 | 75176 | 241 | 4 | 6999 | 500 | 387 | 6 |
talk_per = talk_count.div(room_total, axis=0) * 100
talk_per
message_type | 位置 | 公眾號 | 加群 | 圖片 | 撤回 | 文字 | 紅包 | 網頁 | 表情 | 視訊 | 語音 | 通話 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
cat | ||||||||||||
小小群 | 0.184717 | 3.548513 | 0.554151 | 8.662259 | 1.409683 | 76.997861 | 2.012444 | 0.009722 | 5.084581 | 0.874976 | 0.661093 | 0.000000 |
小群 | 0.161733 | 1.787726 | 0.259928 | 5.057040 | 1.143682 | 81.712635 | 0.947292 | 0.000000 | 7.653430 | 0.592058 | 0.678700 | 0.005776 |
中型群 | 0.205997 | 3.089952 | 1.792935 | 5.592432 | 2.014191 | 78.416114 | 0.373846 | 0.000000 | 4.089418 | 0.671397 | 3.753719 | 0.000000 |
大型群 | 0.076268 | 4.398119 | 1.309267 | 19.855091 | 2.021101 | 51.519003 | 5.910766 | 0.076268 | 2.326173 | 4.881149 | 7.626795 | 0.000000 |
巨型群 | 0.035745 | 1.198588 | 0.329528 | 4.480463 | 0.891401 | 83.974889 | 0.269208 | 0.004468 | 7.818190 | 0.558522 | 0.432296 | 0.006702 |
利用各種分組的群發訊息的類別繪製熱力圖。
f, ax = plt.subplots(figsize=(9, 6))
sns.heatmap(np.sqrt(np.sqrt(talk_per)), annot=True, linewidths=.5, ax=ax, cmap='Set3')
從佔比上看,任何分組的「文字訊息」均佔據絕大多數,而且佔比之間差異過大,因此在將佔比兩次開方後繪製。
從結果上看,除文字訊息均佔據最大比中外,圖片、表情也是使用佔比普遍較高的訊息種類;小、中型群分享位置更多,中大型群撤回訊息佔比更多!
本次分析主要集中在資料預處理上,具體分析比較少,後續再依據發言時間、發言具體內容進行分析。
4 參考資料
- 韋陽的部落格, 韋陽, 微信聊天記錄匯出為電腦 txt 檔案教程, 2020/3/2.
- hangcom 寫字的地方, hangcom, 微信聊天記錄匯出–釋出, 2020/3/2.
- Asher117, 【Python】DataFrame 一列拆成多列以及一行拆成多行, 2020/3/2.
- 風淺安然, Matplotlib 及 Seaborn 中文顯示問題, 2020/3/2.
本作品採用《CC 協議》,轉載必須註明作者和本文連結