CNN中文垃圾邮件分类(二)

版权声明:转载请注明出处 https://blog.csdn.net/The_lastest/article/details/81746887

本文整理自唐宇迪老师视频,谢谢他!

1.思路

在上一篇博客CNN中文垃圾邮件分类(一)中介绍了两种预处理方式,现在来介绍第二种,先用分好词的数据作为训练语料,选择前n个词作为词表(或者去掉出现频率较低的词),然后先训练出每个词所代表的词向量。再根据词表得到每封邮件中每个词在词表中的索引,然后按索引取出向量量堆叠起来。

2. 数据预处理

第一步同之前一样,先去掉非中文的其它字符,然后分词

def clean_str(string):
    string.strip('\n')
    string = re.sub(r"[^\u4e00-\u9fff]", " ", string)
    string = re.sub(r"\s{2,}", " ", string)
    return string.strip()


def cut_line(line):
    line = clean_str(line)
    seg_list = jieba.cut(line)
    cut_words = " ".join(seg_list)
    return cut_words


def load_data_and_labels(positive_data_file, negative_data_file):
    positive = []
    negative = []
    for line in open(positive_data_file, encoding='utf-8'):
        positive.append(cut_line(line).split())
    for line in open(negative_data_file, encoding='utf-8'):
        negative.append(cut_line(line).split())

    x_text = positive + negative

    positive_label = [[0, 1] for _ in positive]  # 构造one-hot 标签[[0, 1], [0, 1], [0, 1], [0, 1],....]
    negative_label = [[1, 0] for _ in negative]  # 构造one-hot 标签[[0, 1], [0, 1], [0, 1], [0, 1],....]
    y = np.concatenate([positive_label, negative_label], axis=0)

    return x_text, y

positive_data_file = '../data/ham_100.utf8'
negative_data_file = '../data/ham_100.utf8'
x_text, y = load_data_and_labels(positive_data_file,negative_data_file)
print(x_text)

处理后的结果形式如下:

[['溶血', '几乎', '可以', '忽略不计', '没什么', '关系', '关键', '是', '溶血', '不过', '亚洲', '人', '大多数', '都', '是', '因子', '阳性', '所以', '溶血', '的', '概率', '很', '低', '不太', '清楚', '国内', '的', '验血', '查不查', '因子', '米国', '这边', '是', '查', '的', '只要', '阳性', '人家', '就', '不会', '管', '你', '是否', '溶血', '呢', '其实', '偶是'],['型', '老公', '是', '型', '按', '血型', '系统', '偶们', '这种', '组合', '是', '很', '容易', '溶血', '的', '但是', '这边', '医生', '提都', '没', '跟', '偶提', '过', '估计', '是', '忽略不计', '的', '从', '网上', '看', '的', '文章', '周', '的', '时候', '去', '医院', '建卡', '然后', '做', '第一次', '产检', '周', '的', '时候', '再', '做', '第一次', '超', '是不是', '这样', '呢']]

按设定的最大句子长度来Padding样本(长度不够的用’UNK’来填充)

def padding_sentence(sentences, padding_token='UNK', padding_sentence_length=None):
    max_padding_length = padding_sentence_length if padding_sentence_length is not \
                                                    None else max([len(sentence) for sentence in sentences])
    for i,sentence in enumerate(sentences):
        if len(sentence) < max_padding_length:
            sentence.extend([padding_token] * (max_padding_length - len(sentence)))
        else:
            sentences[i] = sentence[:max_padding_length]
    return sentences, max_padding_length

padded_sentences, max_padding_length = \
    padding_sentence(sentences=x_text, padding_sentence_length=100)
print(padded_sentences)

处理后的结果形式如下:

['浙江', '杭萧', '钢构', '股份', '有限公司', '为', '国内', '最大', '的', '钢结构', '公司', '现在', '北京', '设立', '海外部', '诚征', '致力于', '此', '的', '有识之士', '共同', '开拓', '海外', '市场', '文秘', '要求', '熟练', '运用', '常用', '办公', '软件', '会', '英文', '打字', '及', '日常', '英文', '商业', '信函', '的', '处理', '为', '人', '可靠', '踏实', '项目经理', '要求', '有', '进出口', '贸易', '或', '工程', '方面', '的', '经验', '熟练', '运用', '英文', '进行', '交流', '对', '事业', '具有', '开拓精神', '对', '专业', '要求', '上', '进', '而', '不仅', '限于', '皮毛', '工作', '地点', '北京', '三环', '以内', '有意者', '请', '将', '简历', '电邮', '至', '请', '注明', '应聘', '的', '职位', '或', '致电', 'UNK', 'UNK', 'UNK', 'UNK', 'UNK', 'UNK', 'UNK', 'UNK', 'UNK']

将每个样本用对应词的词向量堆叠的形式代替

关于Word2Vec的介绍戳此处Gensim之Word2Vec使用手册

def embedding_sentences(embedding_file='./embedding.model',
                        padded_sentences=None,
                        embedding_size=50,
                        min_count=5,
                        window=5):
    if os.path.exists(embedding_file):
        model = Word2Vec.load(embedding_file)
    else:
        model = word2vector(sentences=padded_sentences,
                            embedding_size=embedding_size,
                            min_count=min_count,
                            window=window)
    all_vectors = []
    embedding_unknown = [0 for i in range(embedding_size)]
    for sentence in padded_sentences:
        this_vector = []
        for word in sentence:
            if word in model.wv.vocab:
                this_vector.append(model[word])
            else:
                this_vector.append(embedding_unknown)
        all_vectors.append(this_vector)
    return all_vectors, len(model.wv.vocab)

x = np.array(embedded_sentences)
print(x.shape)

#结果(每个样本都是一个[100,50]的矩阵
(200, 100, 50)

3.训练

总体上CNN的结构不变,可以看如下对比:

没有预训练词向量的版本:

with tf.device('/cpu:0'), tf.name_scope('embedding_layer'):
    self.W = tf.Variable(tf.truncated_normal([vocab_size, embedding_size])) # 随机初始化一个词向量矩阵
    self.embedded_chars = tf.nn.embedding_lookup(self.W, self.input_x)# 将每个样本用词向量堆叠的形式表示
    self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1)# 扩维

预先训练好词向量的版本:

self.embedded_chars = self.input_x #输入的就已经是词向量的表示形式
self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1)

源码

猜你喜欢

转载自blog.csdn.net/The_lastest/article/details/81746887