基于jieba分词的文本抄袭自动检测分析
如果你是某新闻单位工作人员(这里假设source=新华社),为了防止其他媒体抄袭你的文章,你打算做一个抄袭自动检测分析的工具
1.定义可能抄袭的文章来源
2.与原文对比定位抄袭的地方
原始数据:sqlResult.csv,共计89611篇
从数据库导出的文章,字段包括:id, author, source, content, feature, title, url
中文停用词:chinese_stopwords.txt
完整代码:
# jieba 第三方中文分词库 import jieba import numpy as np import pandas as pd # model_selection主要是对数据的分割,以及与数据划分相关的功能 # train_test_split将原始数据按照比例分割为“测试集”和“训练集” from sklearn.model_selection import train_test_split # 加载停用词 with open('chinese_stopwords.txt', 'r', encoding='utf-8') as file: # i[:-1] 每行最后一个是回车,回车符不要 stopwords = [i[:-1] for i in file.readlines()] # print(stopwords) # 加载数据 news = pd.read_csv('sqlResult.csv', encoding='gb18030') print(news.shape) print(news.head(5)) # 处理缺失值 (subset=['content'] 删除在content列中含有空数据的全部行) news = news.dropna(subset=['content']) print(news.shape) # 分词 def split_text(text): # .replace方法把前者用后者替换掉 # 替换掉空格 text = text.replace(' ', '') # 替换掉换行符 text = text.replace('\n', '') # 替换掉回车符 text = text.replace('\r', '') # 分词切割(默认精确模式) # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列 # 注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符 text2 = jieba.cut(text.strip()) result = ' '.join([w for w in text2 if w not in stopwords]) # print('方法中:', result) return result # 打印新闻第1行的数据,其索引为0 print(news.iloc[0].content) # 调用自定义分词方法,对第1行数据进行分词 print(split_text(news.iloc[0].content)) # pickle 可以序列化、反序列化数据 import pickle, os # 判断corpus.pkl文件是否已存在 if not os.path.exists('corpus.pkl'): # 对所有的新闻进行分词(调用分词方法,对新闻中的每条新闻进行分词,得到一个列表) corpus = list(map(split_text, [str(i) for i in news.content])) print(corpus[0]) # 打开一个corpus.pkl文件,以二进制形式wb写入数据(w:写, b:二进制) # with语句帮我们自动调用close()方法 with open('corpus.pkl', 'wb') as file: # dump()方法 序列化对象(写入磁盘),数据写入 pickle.dump(corpus, file) else: # 调用上次的处理结果(打开一个corpus.pkl文件,以二进制形式rb读取数据) with open('corpus.pkl', 'rb') as file: # load()方法 反序列化对象(从磁盘中读取),数据加载(读取) corpus = pickle.load(file) # feature_extraction模块,可以用于从包含文本和图片的数据集中提取特征,以便支持机器学习算法使用。 # .text就是文本特征提取 # CountVectorizer函数用来构建语料库的中的词频矩阵;TfidfTransformer函数用来计算词语的tfidf权值。 from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer # 得到corpus的TF-IDF矩阵 # CountVectorizer()构建词频矩阵对象 # min_df=0.015 最小词频率 countVectorizer = CountVectorizer(encoding='gb18030', min_df=0.015) # TfidfTransformer()构建词语的权值对象 tfidfTransformer = TfidfTransformer() # 构建corpus数据的词频矩阵 countVector = countVectorizer.fit_transform(corpus) # 构建词频矩阵中词语的权值 tfidf = tfidfTransformer.fit_transform(countVector) # print(type(tfidf)) # <class 'scipy.sparse.csr.csr_matrix'> # 标记是否为自己的新闻(通过判断新闻数据源中,每一条新闻中是否存在'新华'两个字) label = list(map(lambda source: 1 if '新华' in str(source) else 0, news.source)) # 数据集切分(tfidf.toarray() 将tf-idf矩阵抽取出来) X_train, X_test, y_train, x_train = train_test_split(tfidf.toarray(), label, test_size=0.3) # 朴素贝叶斯(是一种分类算法) # 因为样本特征的分是多元离散值,使用MultinomialNB(MultinomialNB就是先验为多项式分布的朴素贝叶斯) from sklearn.naive_bayes import MultinomialNB # 创建朴素贝叶斯对象 clf = MultinomialNB() # 拟合数据,模型训练 clf.fit(X_train, y_train) # 对全数据进行预测 prediction = clf.predict(tfidf.toarray()) # 全数据标签列表转化为数组 labels = np.array(label) # 全数据的预测值和真实值构建成DataFrame compare_news_index = pd.DataFrame({'prediction': prediction, 'labels': labels}) # 预测是新华社,实际不是 copy_news_index = compare_news_index[ (compare_news_index['prediction'] == 1) & (compare_news_index['labels'] == 0)].index # 实际为新华社的新闻 xinhuashe_news_index = compare_news_index[(compare_news_index['labels'] == 1)].index # print(xinhuashe_news_index) # Normalizer(归一化) 数据预处理包 from sklearn.preprocessing import Normalizer # 创建归一化对象 normalizer = Normalizer() # 归一化数据预处理 scaled_array = normalizer.fit_transform(tfidf.toarray()) # KMeans k均值聚类算法 from sklearn.cluster import KMeans # 使用KMeans对全量文档进行聚类(聚成25类) kmeans = KMeans(n_clusters=25) # 拟合预处理后的数据,并且进行预测 k_labels = kmeans.fit_predict(scaled_array) # 保存到文件,方便下次使用 with open('label.pkl', 'wb')as file: pickle.dump(k_labels, file) # k_labels分类进行id化 # enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,(接下行) # 同时列出数据和数据下标,一般用在 for 循环当中 # 一个id对应一个class id_class = {index: class_ for index, class_ in enumerate(k_labels)} with open('id_class.pkl', 'wb') as file: pickle.dump(id_class, file) # 创建空集合的字典 # defaultdict的作用是在于,当字典里的key不存在但被查找时,返回的不是keyError而是一个默认值 from collections import defaultdict class_id = defaultdict(set) for index, class_ in id_class.items(): # 只统计新华社发布的class_id if index in xinhuashe_news_index.tolist(): class_id[class_].add(index) with open('class_id.pkl', 'wb') as file: pickle.dump(class_id, file) # 余弦相似度 # 用cosine_similarity计算相似度 from sklearn.metrics.pairwise import cosine_similarity # 查找相似文本 def find_similar_text(cpindex, top=10): # 只在新华社发布的文章中查找 dist_dict = {i: cosine_similarity(tfidf[cpindex], tfidf[i]) for i in class_id[id_class[cpindex]]} # 从大到小进行排序 Top10 return sorted(dist_dict.items(), key=lambda x: x[1][0], reverse=True)[:top] # 在copy_news_index里面找一个 cpindex = 3352 similar_list = find_similar_text(cpindex) print(similar_list) print('怀疑抄袭\n', news.iloc[cpindex].content) # 找一篇相似的原文 similar2 = similar_list[0][0] print('相似原文\n', news.iloc[similar2].content)
注:电脑好像不太行,很久没有跑出来结果。
今天是重感冒渐好的第二天,我快活过来了!嘿嘿嘿

浙公网安备 33010602011771号