之前用智源上面一个虚假新闻检测的比赛练了练手,数据集可以在比赛官网上下载task1。可以看成中文文本分类任务,之前只是跑了跑模型,没有关注词向量的训练以及多模型融合。目前我在细化,会不断和大家分享,相互学习,欢迎交流,结束后我会把代码更新github
任务介绍
虚假新闻文本检测:文本是新闻信息的主要载体,对新闻文本的研究有助于虚假新闻的有效识别。具体任务为:给定一个新闻事件的文本,判定该事件属于真实新闻还是虚假新闻。
虚假新闻文本检测任务中,训练集共包含38,471条新闻,其中包含真实新闻19,186条,虚假新闻19,285条。初赛测试集共4,000条,复赛测试集3,902条,真假新闻比例与训练集基本一致。
数据字段:
id:新闻id,每条文本中id均不相同,唯一表征一条新闻;
text: 新闻的文本内容;
label: 取值为{0,1},0表示真实新闻,1表示虚假新闻。
每支队伍在参赛期间可随时提交验证集的预测结果,将验证结果在一个文本文件中进行提交,命名为submit.csv,格式如下:
id,label
123,1
456,0
......
其中,对于虚假文本检测任务, id是新闻id,label是该新闻文本对应的预测结果,int类型,取值范围为{0,1},虚假新闻为1,真实新闻为0;
数据集
官方给的数据集有Excel表格给出,该数据集共有38471条数据,其中19186条假新闻,19185条真新闻。每条数据由[id,text,label]三个元素组成,其中qid是每一条数据的唯一id标识,text是中文新闻文本,label是0/1,0表示真实新闻,1表示虚假新闻。测试数据集需要提交到后台判定。对数据集进行分析可以得到:
最大句子长度 | 最小句子长度 | 平均数据长度 | 分词后词的个数 |
929 | 0 | 50.883678615060695 | 73915 |
相关库函数的载入
import time
import jieba
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer,CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn import metrics
import pandas as pd
import numpy as np
from gensim.models import Word2Vec
from keras.layers import *
from keras.models import *
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.engine.topology import Layer
from tqdm import tqdm
maxlen = 100
(一)数据处理
1.数据清洗
之前做的一个英文文本分类在数据处理上,主要做了标点符号的整理,颜文字等特殊符号的处理,大小写的转换,数字的清理,以及利用一个手写的小字典对数据的拼写错误进行检测。数据清洗后,利用keras的tokenizer接口将句子进行符号化,并padding到等长,为将来向量化做准备。
在中文数据处理上与英文有所不同,主要做了去除指定无用的符号,只保留文本中的文字,利用一个手写的list记录所有停用词,去除停用词并对文本进行分词。数据清洗后,需要将句子进行符号化,由于中文没有分词器tokenizer,我先构建了一个vocab保存所有分好的词,共有73915个单词,根据词典将句子序列化,再将句子padding到等长,为将来向量化做准备,下面上代码
数据清洗的代码:
"去除指定无用的符号,这里我们主要拿空格举例"
puncts = [' ']
def clean_text(x):
x=x.strip()
for punct in puncts:
x=x.replace(punct,'')
return x
"让文本只保留文字"
def is_chinese(xchar):
if xchar>=u'\u4e00' and xchar<=u'\u9fa5':
return True
else:
return False
def keep_chinese_text(x):
out_str=''
for i in x:
if is_chinese(i):
out_str=out_str+i
return out_str
def seg_sentence(sentence,stopwords):
"对句子进行分词和去除停用词"
sentence_seged=jieba.cut(sentence)
outstr=''
for word in sentence_seged:
if word not in stopwords:
outstr+=word
outstr+=" "
return outstr
词典的构建以及文本序列化的代码
def build_vocab(sentences,verbose=True):
"追踪训练词汇表,遍历所有文本对单词进行计数"
vocab={}
for sentence in tqdm(sentences,disable=(not verbose)):
for word in sentence.split():
try:
vocab[word]+=1
except KeyError:
vocab[word]=1
#vocab=sorted(vocab.items(),key=lambda d:d[1],reverse=True) # 分词后共出现70634个单词
# vocab=vocab[:vocab_size]
print(len(vocab))
return vocab
def texts_to_sequences(sentences,vocab,verbose=True):
seq_sentences=[]
for sentence in tqdm(sentences,disable=(not verbose)):
seq_sentence=[]
for word in sentence.split():
seq_sentence.append(vocab.get(word))
seq_sentences.append(seq_sentence)
return seq_sentences
数据处理的全部代码
def load_and_prec():
#文件读取
train_df=pd.read_csv('data/news_classification_dataset.csv')
#创建停用词列表
stopwords = ['的', '呀', '这', '那', '就', '的话', '如果']
train_df["text"]=train_df["text"].apply(lambda x:clean_text(x))
train_df["text"]=train_df["text"].apply(lambda x:keep_chinese_text(x))
train_df["text"]=train_df["text"].apply(lambda x:seg_sentence(x,stopwords))
vocab=build_vocab(train_df["text"],True)
# split to train and val
train_df,val_df=train_test_split(train_df,test_size=0.1,random_state=2019)
# print("Train shape: ",train_df.shape) # (34623, 3)
# print("Val shape: ",val_df.shape) # (3848, 3)
## Get the input values
train_X=train_df["text"].values
val_X=val_df["text"].values
## Get the target values
train_y=train_df["label"].values
val_y=val_df["label"].values
np.random.seed(2019)
trn_idx=np.random.permutation(len(train_X))
val_idx=np.random.permutation(len(val_X))
train_X=train_X[trn_idx]
val_X=val_X[val_idx]
train_y=train_y[trn_idx]
val_y=val_y[val_idx]
# Tokenize the sentences
train_X=texts_to_sequences(train_X, vocab)
val_X=texts_to_sequences(val_X,vocab)
# Pad the sentences
train_X=pad_sequences(train_X,maxlen=maxlen)
val_X=pad_sequences(val_X,maxlen=maxlen)
return train_df,val_df,train_X,val_X,train_y,val_y,vocab
2. 词向量的训练
def word2vec_model(train_df, val_df, vocab):
count=0
nb_words=len(vocab)
print(nb_words)
start=time.clock()
all_data=pd.concat([train_df["text"],val_df["text"]])
file_name='data/word2vec.model'
if not os.path.exists(file_name):
model=Word2Vec([[word for word in sentence.split()] for sentence in all_data.values],
size=embed_size,window=5,iter=10,workers=11,seed=2019,min_count=2)
model.save(file_name)
else:
model=Word2Vec.load(file_name)
print("add word2vec finished...")
end=time.clock()
print('Running time: %s Seconds' %(end-start))
nb_words=min(max_features,len(vocab))
embedding_word2vec_matrix=np.zeros((nb_words,embed_size))
for word,i in vocab.items():
if i>max_features:continue
embedding_vector=model[word] if word in model else None
if embedding_vector is not None:
count+=1
embedding_word2vec_matrix[i]=embedding_vector
else:
unk_vec=np.random.random(embed_size)*0.5
unk_vec=unk_vec-unk_vec.mean()
embedding_word2vec_matrix[i]=unk_vec
del model;
gc.collect()
return embedding_word2vec_matrix
3. 主函数中直接运行即可
if __name__ == '__main__':
train_df, val_df, train_X, val_X, train_y, val_y, vocab=load_and_prec()
embedding_word2vec_matrix=word2vec_model(train_df,val_df,vocab)
print(embedding_word2vec_matrix.shape) #(73915, 200)