基于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)

注:电脑好像不太行,很久没有跑出来结果。


 今天是重感冒渐好的第二天,我快活过来了!嘿嘿嘿

 

posted @ 2020-10-29 16:32  mingke07  阅读(270)  评论(0)    收藏  举报