创作背景
在数字化时代,社交媒体和即时通讯工具已成为人们日常生活中不可或缺的一部分。微信,作为中国最流行的即时通讯软件之一,不仅承载了人们的日常交流,更记录了无数情感的起伏与心灵的触碰。小明,一个对生活充满好奇与热情的年轻人,最近通过微信结识了一位特别的女生——小芳。他们的聊天从最初的礼貌问候,逐渐深入到彼此的兴趣爱好、生活琐事乃至心灵深处的感悟。
然而,面对这段新建立的友情,小明不禁产生了更多的好奇与期待。他渴望更加深入地了解小芳,尤其是她的性格特点——是活泼开朗,还是温婉细腻?是乐观向上,还是多愁善感?为了更科学地解读小芳的内心世界,小明决定利用自己所学的技术知识,开发一个基于微信聊天记录的分析工具。
这个工具将整合多种技术和库,包括用于文本分词的jieba、用于生成词云的wordcloud、以及用于情感分析的cnsenti。通过这些技术的结合,小明希望能够从海量的聊天记录中提炼出关键信息,如高频词汇、主题分布以及情感倾向,从而帮助自己更准确地把握小芳的性格特点和内心世界。
环境准备
pip安装以下可能需要使用的库
pip install jieba wordcloud pandas cnsenti matplotlib Pillow -i https://pypi.tuna.tsinghua.edu.cn/simple
下载Memotrace(留痕)
批量导出聊天记录的csv表格数据
csv表格字段解释
localId | TalkerId | Type | SubType | IsSender | CreateTime | Status | StrContent | StrTime | Remark | NickName | Sender |
localId:每条聊天记录在本地都有唯一的Id,用于唯一确定某一条聊天记录
TalkerId:用于唯一识别某一个发送消息的人
IsSender:为1是“我”发送,不唯一则为对方发送
CreateTime:用长整数表示发送的时间
StrContent:聊天记录
StrTime:聊天记录的时间(字符串)
其他字段暂时没有使用,不作过多的解释
需求分析
基于现有的jieba、cnsenti,wordcloud等nlp库,我们在接下来的几期博客会进行词频统计并生成常用词云图,聊天的情感类型分析、积极消极程度等分析。当然,你也可以根据自己的需求,进行聊天的时段分析、聊天的掌控度等定制化的分析,如果数据量较大,可以使用PySpark/Scala Spark进行辅助分析,我也会在后续的几期博客给出示例。
指标一:词频统计
实现步骤
用pandas库读取文件,调用jieba的方法进行分词,最后输出到文件。
注:我过滤掉了词频<=3的词语,你也可以根据需要修改代码逻辑,过滤掉一些高词频的词语,如:的,了,你,我等
处理单个文件的代码
import pandas as pd
import jieba
from collections import Counter
import os
def is_chinese_only(word):
for char in word:
if not '\u4e00' <= char <= '\u9fff':
return False
return True
def process_csv_file(csv_file_path):
df = pd.read_csv(csv_file_path, encoding='utf-8')
word_counts = Counter()
for text in df['StrContent']:
if pd.notna(text):
words = jieba.lcut(text)
filtered_words = [word for word in words if is_chinese_only(word)]
word_counts.update(filtered_words)
# 过滤掉词频小于等于3的词语
filtered_word_counts = {word: count for word, count in word_counts.items() if count > 3}
# 创建一个DataFrame来存储词频结果
word_freq_df = pd.DataFrame(filtered_word_counts.items(), columns=['Word', 'Frequency'])
# 保存到CSV文件
output_file_path = os.path.join(os.path.dirname(csv_file_path), "word_counts_overall.csv")
word_freq_df.to_csv(output_file_path, index=False, encoding='utf-8')
# 指定要处理的CSV文件路径
csv_file_path = 'D:\\MemoTrace\\data\\聊天记录\\...\\...csv'
process_csv_file(csv_file_path)
处理多个文件的代码
观察文件的结构,我们可以发现一个共同点
就是在聊天记录这个主文件夹下,有若干个以备注名+(wxid...)命名的文件夹,然后我们需要的csv文件其实就是去除括号及其内部的内容+csv构成的,找到这个规律,我们可以递归处理多个文件
处理两人共同聊天记录
import pandas as pd
import jieba
from collections import Counter
import os
import re
def is_chinese_only(word):
for char in word:
if not '\u4e00' <= char <= '\u9fff':
return False
return True
def process_csv_in_folder(folder_path):
# 提取文件夹名(去除括号及其内容)
folder_name = os.path.basename(folder_path)
clean_folder_name = re.sub(r'\(.*?\)', '', folder_name)
# 构造预期的CSV文件名
csv_file_name = f"{clean_folder_name}.csv"
# 构造CSV文件的完整路径
csv_file_path = os.path.join(folder_path, csv_file_name)
# 检查CSV文件是否存在
if os.path.exists(csv_file_path):
# 使用pandas读取CSV文件
df = pd.read_csv(csv_file_path, encoding='utf-8')
# 初始化一个Counter对象来存储当前CSV文件的词频
word_counts = Counter()
# 遍历DataFrame中的每一行,对StrContent列进行分词并统计词频
for text in df['StrContent']:
if pd.notna(text):
words = jieba.lcut(text)
filtered_words = [word for word in words if is_chinese_only(word)]
word_counts.update(filtered_words)
# 过滤掉词频小于等于3的词语
filtered_word_counts = {word: count for word, count in word_counts.items() if count > 3}
# 创建一个DataFrame来存储词频结果
word_freq_df = pd.DataFrame(filtered_word_counts.items(), columns=['Word', 'Frequency'])
# 保存到CSV文件,可以选择保存到原文件夹或指定位置
# 这里为了保持清晰,我们保存到原文件夹下,但文件名添加前缀或后缀以区分
output_file_path = os.path.join(folder_path, "word_counts.csv")
word_freq_df.to_csv(output_file_path, index=False, encoding='utf-8')
top_dir = 'D:\\MemoTrace\\data\\聊天记录'
for subdir, dirs, files in os.walk(top_dir):
process_csv_in_folder(subdir)
处理两人各自聊天记录(根据IsSender分组)
import pandas as pd
import jieba
from collections import Counter
import os
import re
def is_chinese_only(word):
for char in word:
if not '\u4e00' <= char <= '\u9fff':
return False
return True
def process_csv_in_folder(folder_path):
folder_name = os.path.basename(folder_path)
clean_folder_name = re.sub(r'\(.*?\)', '', folder_name)
csv_file_name = f"{clean_folder_name}.csv"
csv_file_path = os.path.join(folder_path, csv_file_name)
if os.path.exists(csv_file_path):
df = pd.read_csv(csv_file_path, encoding='utf-8')
if 'IsSender' in df.columns: # 检查是否包含IsSender列
# 根据IsSender的值分组
grouped = df.groupby('IsSender')
for sender, group in grouped:
word_counts = Counter()
# 遍历DataFrame中的每一行,对StrContent列进行分词并统计词频
for text in group['StrContent']:
if pd.notna(text):
words = jieba.lcut(text)
filtered_words = [word for word in words if is_chinese_only(word)]
word_counts.update(filtered_words)
# 过滤掉词频小于等于3的词语
filtered_word_counts = {word: count for word, count in word_counts.items() if count > 3}
# 创建一个DataFrame来存储词频结果
word_freq_df = pd.DataFrame(filtered_word_counts.items(), columns=['Word', 'Frequency'])
# 保存到CSV文件,文件名根据IsSender的值区分
output_file_path = os.path.join(folder_path, f"word_counts_where_isSender_{sender}.csv")
word_freq_df.to_csv(output_file_path, index=False, encoding='utf-8')
else:
print(f"No 'IsSender' column found in {csv_file_path}")
top_dir = 'D:\\MemoTrace\\data\\聊天记录'
for subdir, dirs, files in os.walk(top_dir):
process_csv_in_folder(subdir)
词云生成
处理多文件
注:我去除了词频前七的词语,尽量保证了过于常用的词语不出现在词云里
并且你可以根据自己喜好,到C盘Windows->Fonts文件夹下找到特定的字体,拷贝路径写在font_path下。
import os
import pandas as pd
from wordcloud import WordCloud, STOPWORDS
from PIL import Image
import matplotlib.pyplot as plt
# 设定根目录
root_dir = 'D:\\MemoTrace\\data\\聊天记录'
# 遍历根目录下的所有子文件夹
for subdir, dirs, files in os.walk(root_dir):
for file in files:
if file == 'word_counts.csv':
# 读取CSV文件
file_path = os.path.join(subdir, file)
df = pd.read_csv(file_path)
# 准备词频字典
word_frequencies = dict(zip(df['Word'], df['Frequency']))
# 排除出现频次最多的七个词语
# 首先,将字典转换为列表,按频次排序,然后反转列表以获取频次最高的词语
sorted_words = sorted(word_frequencies.items(), key=lambda x: x[1], reverse=True)
# 排除前七个
top_seven_words = [word for word, freq in sorted_words[:7]]
# 更新字典,排除这些词语
for word in top_seven_words:
if word in word_frequencies:
del word_frequencies[word]
# 加载背景图像(可选,如果不使用背景图像则不需要)
# mask = np.array(Image.open("your_mask_image.png"))
# 创建词云对象
wc = WordCloud(
font_path='C:\\Windows\\Fonts\\STXINGKA.TTF', # 指定字体路径
width=800, height=400,
background_color='white',
# mask=mask, # 如果使用背景图像,则取消注释
stopwords=STOPWORDS.union(top_seven_words) # 合并默认的停用词和自定义的停用词
)
# 根据词频生成词云图
wc.generate_from_frequencies(word_frequencies)
# 保存词云图到子文件夹
image_path = os.path.join(subdir, 'wordcloud.png')
wc.to_file(image_path)
# 如果你还想在Jupyter Notebook中显示词云图(可选)
# plt.imshow(wc, interpolation='bilinear')
# plt.axis('off')
# plt.show()
print(f'词云图已保存到 {image_path}')
处理单文件
import pandas as pd
from wordcloud import WordCloud, STOPWORDS
# 读取CSV文件
file_path ='写你的文件地址'
df = pd.read_csv(file_path)
# 准备词频字典
word_frequencies = dict(zip(df['Word'], df['Frequency']))
# 排除出现频次最多的七个词语,将字典转换为列表,按频次排序,然后反转列表以获取频次最高的词语
sorted_words = sorted(word_frequencies.items(), key=lambda x: x[1], reverse=True)
# 排除前七个
top_seven_words = [word for word, freq in sorted_words[:7]]
# 更新字典,排除这些词语
for word in top_seven_words:
if word in word_frequencies:
del word_frequencies[word]
# 创建词云对象
wc = WordCloud(
font_path='C:\\Windows\\Fonts\\STXINGKA.TTF',
width=2000, height=1000,background_color='white',stopwords=STOPWORDS.union(top_seven_words)
)
# 根据词频生成词云图
wc.generate_from_frequencies(word_frequencies)
# 保存词云图到子文件夹
image_path = '写你的文件地址'
wc.to_file(image_path)
print(f'词云图已保存到 {image_path}')
查看生成的词云图
一张美丽的词云图就完成啦!