192. 统计词频

本文介绍如何使用Bash脚本统计文本文件中各单词的出现频率,并按频率降序排列输出结果。通过一系列Unix管道命令,如cat、tr、sort、uniq及awk等,实现对文本文件words.txt的高效处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写一个 bash 脚本以统计一个文本文件 words.txt 中每个单词出现的频率。

为了简单起见,你可以假设:

  • words.txt只包括小写字母和 ' ' 。
  • 每个单词只由小写字母组成。
  • 单词间由一个或多个空格字符分隔。

示例:

假设 words.txt 内容如下:

the day is sunny the the
the sunny is is

你的脚本应当输出(以词频降序排列):

the 4
is 3
sunny 2
day 1

说明:

  • 不要担心词频相同的单词的排序问题,每个单词出现的频率都是唯一的。
  • 你可以使用一行 Unix pipes 实现吗?

解析:

1、sort语法复习 
      sort -n 将字符串转数字 
      sort -r 指定顺序为从大到小 
      sort -k 2 指定第二个字段作为排序判断标准

  tr -s ' ' '\n' 是将所有连续的空格 空行删除并保证每一行只有一个字符串 
  sort | uniq -c 通常一起用来统计重复出现的次数。

cat words.txt | tr -s ' ' '\n' | sort | uniq -c | sort -rn | awk '{print $2, $1}'

2、 awk 是逐行检索文本。分为3的部分。 
BEGIN{#这里进行一些检索文本前的初始化操作} 
{#这里是对应每一行的操作}

例如这里 for(i=1;i<=NF;++i){++m[$i]}就是将每一行分隔的字段,进行词频统计。 
NF是分隔的字段数。 
$0表示整行字符串 
$1到$NF表示从分隔的第一个字符串到最后一个字符串 
awk中的数组可以用作hashtable做来词频统计。 
END{#在检索文本后的操作} 
for(k in m) k表示的就是m的key。

awk -F' ' '{for(i=1;i<=NF;i=i+1){print $i}}' words.txt|sort|uniq -c|sort -nr|awk -F ' ' '{printf("%s %s\n", $2, $1)}'

 

import jieba import pandas as pd import matplotlib.pyplot as plt from matplotlib import gridspec from wordcloud import WordCloud import numpy as np from PIL import Image from gensim.models import Word2Vec from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.neighbors import KNeighborsClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import GridSearchCV from sklearn.metrics import accuracy_score, classification_report import joblib plt.rcParams["font.sans-serif"] = ["SimHei"] plt.rcParams["axes.unicode_minus"] = False # 读取数据 file_path = r'D:\.AAAA单雨萱重要文件\A大三下\自然语言处理\A课设\新闻分类数据\教育新闻数据.xlsx' df = pd.read_excel(file_path) df = df.drop_duplicates()# 去除重复行 df = df.dropna()# 删除含缺失值的行 # 清理文本干扰字符 def clean_text(text): if isinstance(text, str): return text.replace("\n", "").replace("\t", "").replace("\xa0", "").replace("\u3000", "") return "" df["新闻内容"] = df["新闻内容"].apply(clean_text) # 绘制各栏目总发布量柱状图 column_counts = df["栏目名称"].value_counts() plt.figure(figsize=(10, 6)) plt.bar(column_counts.index, column_counts.values) plt.xlabel("栏目类型"),plt.ylabel("发布数量") plt.title("各个栏目的新闻发布数量"),plt.xticks(rotation=45) for x, y in enumerate(column_counts.values): plt.text(x, y + 2, f"{y}", ha="center", va="bottom", fontsize=9) plt.tight_layout() plt.show() # 处理时间,提取月份 df['发布时间'] = pd.to_datetime(df['发布时间']) df['月份'] = df['发布时间'].dt.to_period('M') grouped = df.groupby(['栏目名称', '月份']).size().reset_index(name='发布数量') pivot_df = grouped.pivot(index='月份', columns='栏目名称', values='发布数量') # 绘制各栏目各月份折线图 fig=plt.figure(figsize=(12, 7)) gs = gridspec.GridSpec(1, 2, width_ratios=[3, 7]) ax1 = fig.add_subplot(gs[0]) ax1.plot( pivot_df.index.astype(str),pivot_df['滚动'],marker='o',linestyle='--',) plt.xlabel('月份'),plt.ylabel('发布数量') plt.title('滚动栏目新闻发布数量变化趋势'),plt.xticks(rotation=45) plt.legend() ax2 = fig.add_subplot(gs[1]) markers = ['s', '^', 'D', 'v', '*', 'p','h'] linestyles = ['-.', ':', '-', '--', '-.', ':', '-'] for i, col in enumerate(pivot_df.columns): if col != '滚动': # 为每个栏目循环使用不同的标记和线型 marker = markers[i % len(markers)] linestyle = linestyles[i % len(linestyles)] plt.plot(pivot_df.index.astype(str),pivot_df[col],marker=marker, linestyle=linestyle, label=col) plt.xlabel('月份'),plt.ylabel('发布数量') plt.title('其余栏目新闻发布数量变化趋势'),plt.xticks(rotation=45) plt.legend() plt.tight_layout() plt.show() # 加载停用词 stopwords = set() with open('stopword.txt', 'r', encoding='gbk') as f: for line in f: stopwords.add(line.strip()) # 补充空格等特殊符号到停用词 stopwords.add(' ') stopwords.add('\u3000') def process_text(text): words = jieba.lcut(text) # 过滤停用词、空字符串、特殊符号 return [word for word in words if word not in stopwords and word.strip() != ''] # 对新闻内容批量处理 df['分词结果'] = df['新闻内容'].apply(process_text) # 构建词频统计 all_words = [] for words in df['分词结果']: all_words.extend(words) # 统计词频 word_freq = pd.Series(all_words).value_counts() x = [word for word in all_words if len(word) > 1] word_freq1 = pd.Series(x).value_counts() # 绘制词云图 mask = np.array(Image.open('background.jpg')) wordcloud = WordCloud(font_path=r"C:\WINDOWS\FONTS\SIMHEI.TTF",width=800,height=600,background_color='white',mask=mask).generate_from_frequencies(word_freq) plt.figure(figsize=(10, 6)) plt.imshow(wordcloud) plt.axis('off') plt.title('新闻文本词云图') plt.tight_layout() plt.show() # 绘制排名前10的词语词频饼图 top10_words = word_freq1.head(10) plt.figure(figsize=(8, 8)) plt.pie(top10_words,labels=top10_words.index,autopct='%.1f%%',startangle=140) plt.title('排名前10词语词频占比饼图') plt.tight_layout() plt.show() #训练192维词向量模型 print("开始训练192维词向量模型...") # 提取所有分词结果(格式需为句子列表,每个句子是词语列表) corpus = df['分词结果'].tolist() # 配置Word2Vec参数(vector_size=192) model = Word2Vec( sentences=corpus, vector_size=192, # 关键参数:设置192维向量 window=5, # 上下文窗口大小 min_count=2, # 最小词频 workers=4, # 并行线程数 sg=1, # 1表示使用Skip-gram模型 epochs=10 # 训练轮次 ) # 保存训练好的模型 model.save('education_news_word2vec.model') print("192维词向量模型训练完成,已保存为education_news_word2vec.model") # 生成文本词向量矩阵 # 定义函数:将单篇新闻的分词转换为192维向量(词向量求和后平均) def text_to_vector(words): vector = np.zeros(192) # 初始化192维零向量 valid_words = 0 for word in words: if word in model.wv: # 只处理在词向量模型中的词 vector += model.wv[word] valid_words += 1 if valid_words > 0: return vector / valid_words # 求平均 return vector # 若无有效词,返回零向量 # 对所有新闻生成词向量 print("开始生成新闻文本的192维向量...") df['word_vector'] = df['分词结果'].apply(text_to_vector) df.to_pickle('news_with_192d_vectors.pkl')# 保存带词向量的数据集 # 提取特征矩阵和标签 X = np.array(df['word_vector'].tolist()) # 192维特征矩阵 y = df['栏目名称'].values # 分类标签 # 标签编码(将文本标签转为数字) le = LabelEncoder() y_encoded = le.fit_transform(y) # 划分训练集与测试集(80%训练,20%测试) X_train, X_test, y_train, y_test = train_test_split( X, y_encoded, test_size=0.2, random_state=42 ) #模型定义与参数调优 models = { 'SVM': SVC(random_state=42), 'K近邻': KNeighborsClassifier(), '随机森林': RandomForestClassifier(random_state=42) } param_grids = { 'SVM': { 'C': [0.1, 1, 10, 100], # 正则化强度 'kernel': ['linear', 'rbf','sigmoid'], # 核函数 'gamma': ['scale', 'auto', 0.1, 0.01] # RBF核参数 }, 'K近邻': { 'n_neighbors': [3, 5, 7, 9], # K值 'weights': ['uniform', 'distance'], # 权重策略 'metric': ['euclidean', 'manhattan'] # 距离度量 }, '随机森林': { 'n_estimators': [100, 200, 300], # 树的数量 'max_depth': [None, 10, 20], # 树的最大深度 'min_samples_split': [2, 5, 10] # 分裂节点的最小样本数 } } # 存储最佳模型和评估结果 best_models = {} all_results = {} # 对每个模型进行网格搜索和交叉验证 for model_name, model in models.items(): print(f"\n=== 开始评估 {model_name} 模型 ===") # 初始化网格搜索 grid_search = GridSearchCV( estimator=model, param_grid=param_grids[model_name], cv=5, # 5折交叉验证 n_jobs=-1, # 使用所有CPU核心 scoring='accuracy', # 评估指标:准确率 verbose=1 # 输出详细信息 ) # 模型训练 grid_search.fit(X_train, y_train) # 记录最佳模型和参数 best_model = grid_search.best_estimator_ best_params = grid_search.best_params_ best_cv_score = grid_search.best_score_ best_models[model_name] = best_model # 在测试集上评估 y_pred = best_model.predict(X_test) test_accuracy = accuracy_score(y_test, y_pred) # 输出评估结果 print(f"最佳参数: {best_params}") print(f"5折交叉验证准确率: {best_cv_score:.4f}") print(f"测试集准确率: {test_accuracy:.4f}") print(f"分类报告:\n{classification_report(y_test, y_pred)}") # 保存结果 all_results[model_name] = { 'params': best_params, 'cv_score': best_cv_score, 'test_accuracy': test_accuracy } # 比较各模型的测试集准确率 model_accuracies = {name: results['test_accuracy'] for name, results in all_results.items()} best_model_name = max(model_accuracies, key=model_accuracies.get) best_accuracy = model_accuracies[best_model_name] print(f"\n=== 模型比较结果 ===") for name, accuracy in model_accuracies.items(): print(f"{name} 测试集准确率: {accuracy:.4f}") print(f"\n最佳模型: {best_model_name},准确率: {best_accuracy:.4f}") # # 保存最佳模型到文件 # model_save_path = 'best_education_news_classifier.pkl' # joblib.dump(best_models[best_model_name], model_save_path) # print(f"最佳模型已保存至: {model_save_path}") 此代码运行后模型部分结果: === 模型比较结果 === SVM 测试集准确率: 0.6522 K近邻 测试集准确率: 0.6285 随机森林 测试集准确率: 0.6482 最佳模型: SVM,准确率: 0.6522 给出详细的方法优化准确率,并给出完整代码,不改变输出格式和东西
最新发布
06-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值