Python文本统计实战:从聊天记录中精准统计关键词频次

发布时间:2026/7/15 23:57:51
Python文本统计实战:从聊天记录中精准统计关键词频次 最近在整理团队训练数据时发现一个有趣的需求如何统计特定成员在训练中的参与频次比如寻雨2026上半年成训喊过多少次善禹这样的问题看似简单却涉及数据采集、文本分析和统计逻辑的完整技术链条。本文将基于Python实战演示从原始聊天记录到精准统计的全流程解决方案适合数据分析入门者和需要处理文本统计的开发者直接复用。1. 需求分析与技术选型1.1 业务场景理解成训喊话统计这类需求常见于团队管理、社群运营等场景核心是通过分析聊天记录、会议纪要等文本数据统计特定关键词的出现频次。技术难点在于数据清洗、模糊匹配和去重逻辑的处理。1.2 技术方案设计针对文本统计需求我们采用Python作为主力工具其丰富的文本处理库和简洁的语法非常适合此类任务。核心流程分为四个阶段数据采集与预处理从原始文件读取数据进行格式标准化关键词匹配算法实现精准匹配和模糊匹配两种模式统计逻辑实现按时间范围、发言人等多维度统计结果可视化生成直观的统计报表2. 环境准备与依赖配置2.1 基础环境要求Python 3.8本文示例使用Python 3.9操作系统Windows/Mac/Linux均可内存至少4GB处理大文件时建议8GB2.2 必要依赖库安装pip install pandas openpyxl jieba matplotlib各库的作用说明pandas数据处理核心库用于表格操作和统计分析openpyxlExcel文件读写支持jieba中文分词工具用于关键词扩展匹配matplotlib数据可视化图表生成2.3 项目目录结构training_stats/ ├── data/ # 原始数据目录 │ ├── chat_2026.xlsx │ └── training_records.csv ├── src/ # 源代码目录 │ ├── data_loader.py │ ├── keyword_matcher.py │ └── stats_analyzer.py ├── output/ # 结果输出目录 └── main.py # 主程序入口3. 数据采集与预处理实战3.1 支持的数据格式实际项目中训练记录可能来自多种来源Excel文件.xlsx, .xlsCSV文件文本文件.txt数据库导出文件3.2 数据读取完整代码# 文件路径src/data_loader.py import pandas as pd import os from datetime import datetime class DataLoader: def __init__(self, data_path): self.data_path data_path def load_excel_data(self, file_name): 读取Excel格式的训练记录 file_path os.path.join(self.data_path, file_name) try: df pd.read_excel(file_path, engineopenpyxl) print(f成功读取Excel文件: {file_name}) print(f数据形状: {df.shape}) return df except Exception as e: print(f读取Excel文件失败: {e}) return None def load_csv_data(self, file_name): 读取CSV格式的训练记录 file_path os.path.join(self.data_path, file_name) try: df pd.read_csv(file_path, encodingutf-8) print(f成功读取CSV文件: {file_name}) return df except UnicodeDecodeError: # 尝试其他编码格式 df pd.read_csv(file_path, encodinggbk) return df def validate_data_structure(self, df): 验证数据基本结构 required_columns [时间, 发言人, 内容] missing_columns [col for col in required_columns if col not in df.columns] if missing_columns: print(f数据缺少必要列: {missing_columns}) return False # 检查时间格式 df[时间] pd.to_datetime(df[时间], errorscoerce) invalid_dates df[时间].isna().sum() if invalid_dates 0: print(f发现{invalid_dates}条无效时间记录) return True3.3 数据清洗关键步骤# 文件路径src/data_cleaner.py import re import jieba class DataCleaner: def __init__(self): # 添加专业术语到分词词典 jieba.add_word(成训) jieba.add_word(善禹) def clean_text(self, text): 文本清洗函数 if pd.isna(text): return # 去除特殊字符和多余空格 text re.sub(r[^\w\s\u4e00-\u9fa5], , str(text)) text re.sub(r\s, , text).strip() return text def extract_keyword_variations(self, keyword): 提取关键词的变体形式 variations set() variations.add(keyword) # 分词后组合可能的变体 words jieba.lcut(keyword) if len(words) 1: variations.add(.join(words)) # 无缝连接 variations.add( .join(words)) # 空格分隔 return list(variations)4. 核心匹配算法实现4.1 精准匹配模式# 文件路径src/keyword_matcher.py class KeywordMatcher: def __init__(self, keyword): self.keyword keyword self.variations self._generate_variations() def _generate_variations(self): 生成关键词的可能变体 base_variations [ self.keyword, self.keyword.replace(, |), # 全角转半角 self.keyword.lower(), self.keyword.upper() ] return base_variations def exact_match(self, text): 精确匹配算法 text_clean text.lower().strip() for variation in self.variations: if variation.lower() in text_clean: return True return False4.2 模糊匹配增强版def fuzzy_match(self, text, threshold0.8): 模糊匹配算法考虑分词后的组合 import jieba from difflib import SequenceMatcher text_words set(jieba.lcut(text)) keyword_words set(jieba.lcut(self.keyword)) # 计算Jaccard相似度 intersection len(text_words keyword_words) union len(text_words | keyword_words) if union 0: return False similarity intersection / union return similarity threshold def advanced_match(self, text): 综合匹配策略先精确后模糊 if self.exact_match(text): return exact elif self.fuzzy_match(text): return fuzzy else: return None5. 完整统计流程实战5.1 主统计类实现# 文件路径src/stats_analyzer.py from datetime import datetime import pandas as pd class TrainingStatsAnalyzer: def __init__(self, data_loader, keyword): self.data_loader data_loader self.keyword keyword self.matcher KeywordMatcher(keyword) def filter_by_time_range(self, df, start_date, end_date): 按时间范围过滤数据 df[时间] pd.to_datetime(df[时间]) mask (df[时间] start_date) (df[时间] end_date) return df[mask] def count_occurrences(self, df, speakerNone): 统计关键词出现次数 results { total_count: 0, exact_matches: 0, fuzzy_matches: 0, by_speaker: {} } # 如果指定了发言人先过滤数据 if speaker: df df[df[发言人] speaker] for _, row in df.iterrows(): content str(row[内容]) match_result self.matcher.advanced_match(content) if match_result: results[total_count] 1 if match_result exact: results[exact_matches] 1 else: results[fuzzy_matches] 1 # 按发言人统计 current_speaker row[发言人] if current_speaker not in results[by_speaker]: results[by_speaker][current_speaker] 0 results[by_speaker][current_speaker] 1 return results5.2 时间段统计专项功能def analyze_by_time_period(self, df, periodmonthly): 按时间周期分析统计趋势 df[时间] pd.to_datetime(df[时间]) if period monthly: df[period] df[时间].dt.to_period(M) elif period weekly: df[period] df[时间].dt.to_period(W) else: df[period] df[时间].dt.date period_stats {} for period_val, group in df.groupby(period): count self.count_occurrences(group)[total_count] period_stats[str(period_val)] count return period_stats6. 完整项目集成示例6.1 主程序入口# 文件路径main.py from src.data_loader import DataLoader from src.stats_analyzer import TrainingStatsAnalyzer from datetime import datetime def main(): # 初始化数据加载器 loader DataLoader(data/) # 加载训练记录数据 df loader.load_excel_data(training_records_2026.xlsx) if df is None: print(数据加载失败请检查文件路径和格式) return # 验证数据结构 if not loader.validate_data_structure(df): print(数据结构验证失败) return # 创建分析器实例 analyzer TrainingStatsAnalyzer(loader, 善禹) # 设置统计时间范围2026年上半年 start_date datetime(2026, 1, 1) end_date datetime(2026, 6, 30) # 过滤数据 filtered_df analyzer.filter_by_time_range(df, start_date, end_date) print(f时间范围内共有 {len(filtered_df)} 条记录) # 统计寻雨喊话善禹的次数 results analyzer.count_occurrences(filtered_df, speaker寻雨) # 输出结果 print(\n 统计结果 ) print(f总出现次数: {results[total_count]}) print(f精确匹配: {results[exact_matches]}) print(f模糊匹配: {results[fuzzy_matches]}) # 按月统计趋势 monthly_stats analyzer.analyze_by_time_period(filtered_df, monthly) print(\n 月度趋势 ) for month, count in monthly_stats.items(): print(f{month}: {count}次) if __name__ __main__: main()6.2 示例数据格式为了测试程序可以创建示例数据文件# 文件路径data/sample_data.py import pandas as pd from datetime import datetime # 创建示例数据 sample_data { 时间: [ 2026-01-15 09:30:00, 2026-02-20 14:15:00, 2026-03-10 10:00:00, 2026-04-05 16:30:00, 2026-05-12 11:20:00, 2026-06-08 13:45:00 ], 发言人: [寻雨, 寻雨, 其他成员, 寻雨, 寻雨, 其他成员], 内容: [ 今天善禹表现很好, 善禹继续努力, 寻雨在喊善禹, 善禹训练认真, 善禹成训加油, 大家向善禹学习 ] } df pd.DataFrame(sample_data) df.to_excel(data/training_records_2026.xlsx, indexFalse)7. 常见问题与解决方案7.1 数据读取问题排查问题现象可能原因解决方案读取Excel失败文件损坏或格式不支持检查文件完整性尝试用Excel打开验证中文乱码编码格式不匹配尝试utf-8、gbk、gb2312等编码时间解析错误时间格式不统一统一时间格式或使用错误处理机制7.2 匹配精度优化# 优化匹配策略 class OptimizedMatcher(KeywordMatcher): def __init__(self, keyword): super().__init__(keyword) # 添加同义词扩展 self.synonyms self._get_synonyms() def _get_synonyms(self): 获取关键词的同义词 synonym_map { 善禹: [善宇, shanYu, SY], 成训: [训练, 培训, 练习] } return synonym_map.get(self.keyword, [])7.3 性能优化技巧处理大量数据时可以采用以下优化策略# 使用向量化操作提升性能 def vectorized_match(df, keyword): 向量化匹配提升大数据量处理性能 import numpy as np # 将匹配逻辑向量化 exact_mask df[内容].str.contains(keyword, caseFalse, naFalse) fuzzy_mask df[内容].apply(lambda x: fuzzy_match_score(x, keyword) 0.7) total_matches np.where(exact_mask | fuzzy_mask, 1, 0).sum() return total_matches8. 结果可视化与报告生成8.1 基础统计图表# 文件路径src/visualizer.py import matplotlib.pyplot as plt import pandas as pd class ResultsVisualizer: def __init__(self, results): self.results results def plot_monthly_trend(self, monthly_stats): 绘制月度趋势图 months list(monthly_stats.keys()) counts list(monthly_stats.values()) plt.figure(figsize(10, 6)) plt.plot(months, counts, markero, linewidth2) plt.title(关键词出现次数月度趋势) plt.xlabel(月份) plt.ylabel(出现次数) plt.xticks(rotation45) plt.grid(True, alpha0.3) plt.tight_layout() plt.savefig(output/monthly_trend.png, dpi300) plt.show()8.2 生成详细统计报告def generate_report(self, filename统计报告.md): 生成Markdown格式的详细报告 report_content f # 训练喊话统计报告 ## 统计概览 - 统计关键词{self.results[keyword]} - 总出现次数{self.results[total_count]} - 统计时间范围{self.results[time_range]} ## 详细统计 ### 按匹配类型 - 精确匹配{self.results[exact_matches]}次 - 模糊匹配{self.results[fuzzy_matches]}次 ### 按发言人统计 for speaker, count in self.results[by_speaker].items(): report_content f- {speaker}: {count}次\n with open(foutput/{filename}, w, encodingutf-8) as f: f.write(report_content)9. 工程最佳实践9.1 配置管理规范建议使用配置文件管理参数避免硬编码# config.yaml data_settings: data_path: data/ supported_formats: [.xlsx, .csv, .txt] matching_settings: fuzzy_threshold: 0.8 enable_synonyms: true min_confidence: 0.6 time_settings: default_start: 2026-01-01 default_end: 2026-06-309.2 错误处理与日志记录import logging # 配置日志系统 logging.basicConfig( levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s, handlers[ logging.FileHandler(app.log), logging.StreamHandler() ] ) class RobustAnalyzer(TrainingStatsAnalyzer): def safe_count_occurrences(self, df, speakerNone): 带错误处理的统计方法 try: return self.count_occurrences(df, speaker) except Exception as e: logging.error(f统计过程中发生错误: {e}) return {total_count: 0, exact_matches: 0, fuzzy_matches: 0}9.3 性能监控与优化对于大规模数据处理建议添加性能监控import time from functools import wraps def timing_decorator(func): wraps(func) def wrapper(*args, **kwargs): start_time time.time() result func(*args, **kwargs) end_time time.time() print(f{func.__name__} 执行时间: {end_time - start_time:.2f}秒) return result return wrapper本文完整演示了从需求分析到代码实现的文本统计全流程重点解决了中文匹配、时间范围过滤、多维度统计等实际问题。在实际项目中可根据具体需求调整匹配算法和统计逻辑这种技术方案同样适用于其他类似的文本分析场景。