基于协同半监督学习的交通事故文本分类

Keras、Numpy、Pandas、Sklearn

一、背景

前面所作工作:

利用Pandas、Numpy对多数据表之间相互匹配并创建交通数据集

交通事故文本多分类——做一个快乐的调包侠(传统机器学习)

利用word2vec、textCNN、jieba对事故文本多分类及致因修复(三维向量)

在之前的建模中,存在一个比较大的问题就是数据量太少,真正匹配出来有对应label的文本仅仅2000来条,一部分还是需要修复的其他类,去除掉后真正用于训练的只有1300条左右。

经过TextCNN、GRU、LSTM、LSTM(改)、SVM三个模型的拟合过后效果如下:

左到右顺序分别为:拟合曲线图、混淆矩阵图、ROC曲线图

上到下顺序分别为CNN、GRU、LSTM、LSTM(改)、SVM

CNN:

GRU:

LSTM:

LSTM(改):

SVM:

可以看出,经过几十到几百次的拟合,所有模型已经几乎过拟合,这时候调各种参数的作用也不大,因此想着能不能扩大数据量,解决过拟合的问题。

因此,把眼光默默的放在了那剩下的7000多条没有label的文本上。那心情,宛如看着佳肴不能入口般难受。也罢,得想个办法吃了他们,由此想到了闻名已久的半监督学习。

所谓半监督学习,也就是指当你在拥有一个巨大的数据集时,很不巧的是真正有label的却很少,在现在的社会中这种现象也特别普遍。尽管标记员这个职业随着人工智能的普及,大幅度增多。但对于巨佬们来说,数据量还是远远不够。因此,怎么样利用少部分的label_data辅上大量的no_label_data中,这就是一个热门的问题。也因为它使用到了label_data和no_label_data,介于监督学习和无监督学习中,因此称此类训练为半监督学习。

大概普及一下知识后,咱们就进入主题,看看怎么吃掉这一堆没label的文本叭!

二、思路

先简要的把整个思路给大家说一遍。

第一步:取出之前已训练好的模型

第二步:对所有no_label_data用word2vec做向量处理,整理成同样的数据格式

第三步:循环迭代,取出no_label_datas里的一条数据,用三个模型进行预测,如果有任意俩个模型对此判别类别相同,则将此条数据标上伪标签,将其丢入训练集中,并从no_label_datas里除去。如果三个类别都不同,则将其放入no_label_datas尾部,继续预测下一条。

第四步:如此循环,直到no_label_datas里的数据全被取出,就达到了最佳状态。

所谓协同,也就是指模型之间协同训练、学习。

第五步:用最终的训练集对模型继续训练,直到拟合。

三、详细过程:

第一步:

我们将之前的模型先进行保存,.save方法直接保存模型的结构及各参数、训练好的权重。

model_cnn.save("cnn.h5")
model_lstm_1.save("lstm_1.h5")
model_lstm_1.save("lstm.h5")

并将之前训练模型划分好的训练集、测试集保存出来,用此文件读入。

X_csv_train = X_train.reshape(159720, 100)
X_csv_test = X_test.reshape(39930, 100)

X_csv_train = pd.DataFrame(X_csv_train)
X_csv_train.to_csv("X_csv_train.csv",index = False)

X_csv_test = pd.DataFrame(X_csv_test)
X_csv_test.to_csv("X_csv_test.csv", index = False)


y_csv_train = pd.DataFrame(y_train)
y_csv_train.to_csv("y_csv_train.csv", index = False)

y_csv_test = pd.DataFrame(y_test)
y_csv_test.to_csv("y_csv_test.csv", index = False)

由于pandas不能直接将三维表导出,因此先将其重构为二维表,等读入时再重构回三维。

然后另开一个jupyter文件,将模型进行导入和训练集、测试集。并用测试集记录三个模型初始评估结果。

X_train = pd.read_csv("./X_csv_train.csv")
X_train = X_train.values
X_train = X_train.reshape(1452, 110, 100)

X_test = pd.read_csv("./X_csv_test.csv")
X_test = X_test.values
X_test = X_test.reshape(363, 110, 100)

y_train = pd.read_csv("./y_csv_train.csv")
y_test = pd.read_csv("./y_csv_test.csv")

cnn:86.22%、lstm:82.92%、lstm_1:84.85%

第二步:

将no_label_datas进行预处理,转为向量形式

#导包
import numpy as np
import pandas as pd
import sys
from gensim.models import word2vec
import os
import gensim
from gensim.models.word2vec import LineSentence
from sklearn.preprocessing import label_binarize
data = pd.read_excel("./wenben.xls")
data

#判断字符串是不是中文
def check_contain_chinese(check_str):
    for ch in check_str:
        if u'\u4e00' <= ch <= u'\u9fff':
            return True     
        else:
            return False
#分词
import jieba
jieba.load_userdict('../dic.txt')
stop = [line.strip() for line in open('../stopwords.txt').readlines()]
#去停用词
out = ''
for index in range(len(data)):
    ct = jieba.cut(data.loc[index,'x'])
    out = ''
    for word in ct:
        if word not in stop:
            if check_contain_chinese(word) == True:
                if (word.endswith("省") == False):
                    if (word.endswith("市") == False):
                        if (word.endswith("县") == False):
                            if (word.endswith("镇") == False):
                                if (word.endswith("村") == False):
                                    out += word
                                    out += " "
    data.loc[index,'split'] = out
#读取出数据
import pprint
text = data['split']
sentences = []
for item in text:
    sentence = str(item).split(' ')
    sentences.append(sentence)
#训练
model = word2vec.Word2Vec(sentences,size = 100)
model.save('jk.model')

用所有文本重新训练word2vec模型。

def buildWordVector(imdb_w2v,text, size):
    vec = np.zeros(size).reshape((1, size))
    pad = np.zeros(size).reshape((1, size))
    count = 0
    for word in text.split():
        try:
            vec = np.vstack((vec, imdb_w2v[word].reshape((1, size)))) 
            count += 1
        except KeyError:
            print (word)
    vec = np.delete(vec, 0, 0)
    if len(vec) < 110:
        for i in range(110 - len(vec)):
            vec = np.vstack((vec, pad))
    else:
        vec = vec[0:110]
    return vec
model_word = word2vec.Word2Vec.load('./jk.model')
result = buildWordVector(model_word, data.loc[1]['split'] , 100)
for i in range(1,len(data)):
    result = np.concatenate((result, buildWordVector(model_word, data.loc[i]['split'] , 100)), axis = 0)
result.shape
x_all = result.reshape(len(data),110,100)

至上,转换完毕。

第三步:

循环迭代,妈的,这一段折腾死人,python里的list、array、DataFrame这几种类型增删改查的方法都不一样,对array的操作,百度排第一的就是个智障,居然还有这么多的阅览数,完全把list当array弄,坑死人。

直接贴代码吧就

while len(x_all) != 0:

    #取出no_label_datas的第一条数据
    x_pre = x_all[0]

    #因为后面拼接需要,这里特别蛋疼的需要把(110,100)重构为(1,11,100)
    x_pre.resize(1,110,100)

    #用模型进行类别预测后,便于后面拼接,重新二值化
    type_cnn = label_binarize(cnn.predict_classes(x_pre), classes = [0,1,2])
    type_lstm = label_binarize(lstm.predict_classes(x_pre), classes = [0,1,2])
    type_lstm_1 = label_binarize(lstm_1.predict_classes(x_pre), classes = [0,1,2])

    #flag变量
    right = False
    if np.argmax(type_cnn) == np.argmax(type_lstm):
        y_pre = type_cnn
        right = True
    elif np.argmax(type_cnn) == np.argmax(type_lstm_1):
        y_pre = type_cnn
        right = True
    elif np.argmax(type_lstm) == np.argmax(type_lstm_1):
        y_pre = type_lstm
        right = True
    if(right):

        #如果符合条件,蛋疼的拼接到训练集中
        X_train = np.vstack([X_train, x_pre])

        #伪标签也时,拼拼拼
        y_train = pd.concat([y_train, pd.DataFrame(y_pre, columns = ['0','1','2'])],ignore_index = True)
        print("cnn: ")

        #意思意思,三个模型都迭代一次
        cnn.fit(X_train, y_train.values,epochs=1,batch_size = 128, validation_data=(X_test, y_test.values))
        print("lstm: ")
        lstm.fit(X_train, y_train.values,epochs=1,batch_size = 128, validation_data=(X_test, y_test.values))
        print("lstm_1: ")
        lstm_1.fit(X_train, y_train.values,epochs=1,batch_size = 128, validation_data=(X_test, y_test.values))
        #删除掉这一条
        x_all = x_all[1:]
        right = False
    else:
        #把这条放在最后
        x_all = x_all[1:]
        x_all[len(x_all)] = x_pre
    print("The length of the no_label_data is : " + str(len(x_all)))

然后就关屏幕,等它跑吧,算了一下大概需要的时间,cnn1秒,lstm2秒,lstm(改)2秒,就算每一条都符合,也要9000*(1+2+2) / 60 / 60 = 12.5小时....睡一觉,明早应该就好了吧可能。

这样就到了最后一步:

代码就不贴了,就是正常的fit(xxxxxx),然后就调库画个过程图看看这次半监督的效果叭,暂时开来,效果挺好的,还没有经过进一步的训练就已经有所提升。

至上,这次比赛我所需要做的大概也就差不多完了。

整个持续了3-6月,从校初赛、校决赛、国初赛,到本月25号即将到来的国决赛,收获满满,也希望这次能有个完美的结局,也算对得起这段时间想破头皮的写代码了。

最后,惯例还是:

(数据涉密,不能外放,见谅!)

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值