·请参考本系列目录:【英文文本分类实战】之一——实战项目总览
·下载本实战项目资源:神经网络实现英文文本分类.zip(pytorch)

[1] 为什么要清洗文本

  这里涉及到文本分类任务中:词典、词向量两个概念。

  首先明确我们做的是“英文文本分类”,所以是不需要像中文那样分词的,只用按照空格截取英文单词就行。

  假设训练集train.csv中有10w个文本,我们以空格为分隔符截取英文单词,一共截下来2w个单词,我们把这些单词从0到2w依次编号,称为“词典”。

【注】:这样的词典是不能接受的。从机器学习的角度看,词典中的某些词只出现一两次,对分类完全没有影响,反而徒增算法计算量(可以去加了解一下TF-IDF的思想)。同样,在神经网络模型中,也需要把每个词表示成一个n维的词向量,所以我们可能只去前1w个频率最高的词,放入“词典”。

  要知道,我们只以空格为分隔符截取英文单词肯定不行,因为文本中不缺乏特殊字符、标点符号、开头单词大小写等等问题,所以我们要进行数据清洗。

  那么我们如何评判清洗后的词典的优劣呢?

  由于我们会使用预训练的词向量,可以以预训练词向量中的词典覆盖率作为参考。

【注】:使用预训练词向量是常用操作,需要仔细了解。

  总结:由于文本中有特殊字符、标点符号、开头单词大小写等等问题,会干扰到提取的词典,所以需要清洗文本数据。我们计算提取的词典与预训练词向量中的词典的覆盖率作为提取的词典的好坏标准。

[2] 提取数据集词典

  vocab字典,建立单词与其出现频次的映射,代码如下:

# ## 创建英文词典
def build_vocab(sentences, verbose=True):vocab = {}for sentence in tqdm(sentences, disable=(not verbose)):for word in sentence:try:vocab[word] += 1except KeyError:vocab[word] = 1return vocab# ## 进度条初始化
tqdm.pandas()
# ## 加载数据集
df = pd.read_csv("../@_数据集/TLND/data/labelled_newscatcher_dataset.csv", encoding='utf-8', sep=';')# ## 创建词典
sentences = df['title'].progress_apply(lambda x: x.split()).values
vocab = build_vocab(sentences)

  我们来看一下建立好的vocab字典是什么样子,任取几个单词看一下:

{'Insulated': 3, 'Mergers': 9, 'Acquisitions': 9}

[3] 加载预训练embeddings

  词向量是指用一组数值来表示一个汉字或者词语,这也是因为计算机只能进行数值计算。最简单的方法是one-hot,假如总的有一万个词,那词向量就一万维,词对应的那维为1,其他为0,但这样的表示维度太高也太稀疏了。

  所以后来就开始用一个维度小的稠密向量来表示,词向量一般都50,100,200或者300维。预训练指提前训练好这种词向量,对应的是一些任务可以输入词id,然后在做具体的任务内部训练词向量,这样出来的词向量不具有通用性,而预训练的词向量,是在极大样本上训练的结果,有很好的通用性,无论什么任务都可以直接拿来用具体的训练方法。

  从最开始的word2vec,elmo到现在的bert。

  一些预训练词向量下载地址为:

   glove

   网址:https://nlp.stanford.edu/projects/glove/

   GLOVE的工作原理类似于Word2Vec。上面可以看到Word2Vec是一个“预测”模型,它预测给定单词的上下文,GLOVE通过构造一个共现矩阵(words X context)来学习,该矩阵主要计算单词在上下文中出现的频率。因为它是一个巨大的矩阵,我们分解这个矩阵来得到一个低维的表示。有很多细节是相互配合的,但这只是粗略的想法。


   fasttext

   网址:https://fasttext.cc/

   ​ FastText与上面的两个嵌入有很大的不同。Word2Vec和GLOVE将每个单词作为最小的训练单元,而FastText使用n-gram字符作为最小的单元。例如,单词vector,“apple”,可以分解为单词vector的不同单位,如“ap”,“app”,“ple”。使用FastText的最大好处是,它可以为罕见的单词,甚至是在训练过程中没有看到的单词生成更好的嵌入,因为n-gram字符向量与其他单词共享。这是Word2Vec和GLOVE无法做到的。


   下载好预训练词向量后,尝试加载词向量,代码如下:

# ## 加载预训练词向量
def load_embed(file):def get_coefs(word, *arr):return word, np.asarray(arr, dtype='float32')if file == '../@_词向量/fasttext/wiki-news-300d-1M.vec':embeddings_index = dict(get_coefs(*o.split(" ")) for o in open(file,encoding='utf-8') if len(o) > 100)else:embeddings_index = dict(get_coefs(*o.split(" ")) for o in open(file, encoding='latin'))return embeddings_index# ## 加载词向量
glove = '../@_词向量/glove/glove.6B.50d.txt'
fasttext = '../@_词向量/fasttext/wiki-news-300d-1M.vec'
embed_glove = load_embed(glove)
embed_fasttext = load_embed(fasttext)

[4] 检查预训练embeddings和vocab的覆盖情况

  创建了词典后并且加载了预训练词向量后,我们编写代码来查看覆盖情况:

# ## 检查预训练embeddings和vocab的覆盖情况
def check_coverage(vocab, embeddings_index):known_words = {}  # 两者都有的单词unknown_words = {}  # embeddings不能覆盖的单词nb_known_words = 0  # 对应的数量nb_unknown_words = 0#     for word in vocab.keys():for word in tqdm(vocab):try:known_words[word] = embeddings_index[word]nb_known_words += vocab[word]except:unknown_words[word] = vocab[word]nb_unknown_words += vocab[word]passprint('Found embeddings for {:.2%} of vocab'.format(len(known_words) / len(vocab)))  # 覆盖单词的百分比print('Found embeddings for  {:.2%} of all text'.format(nb_known_words / (nb_known_words + nb_unknown_words)))  # 覆盖文本的百分比,与上一个指标的区别的原因在于单词在文本中是重复出现的。unknown_words = sorted(unknown_words.items(), key=operator.itemgetter(1))[::-1]print("unknown words : ", unknown_words[:30])return unknown_wordsoov_glove = check_coverage(vocab, embed_glove)
oov_fasttext = check_coverage(vocab, embed_fasttext)

  查看输出:

100%|██████████| 108774/108774 [00:00<00:00, 343998.85it/s]
100%|██████████| 108774/108774 [00:00<00:00, 313406.97it/s]
100%|██████████| 123225/123225 [00:00<00:00, 882523.98it/s]
Found embeddings for 18.88% of vocab
Found embeddings for  51.99% of all text
unknown words :  [('COVID-19', 6245), ('The', 5522), ('New', 3488), ('Market', 2932), ('Covid-19', 2621), ('–', 2521), ('To', 2458), ('US', 2184), ('Coronavirus', 2122), ('How', 2041), ('A', 2029), ('In', 1904), ('Global', 1786), ('Is', 1720), ('With', 1583), ('Of', 1460), ('For', 1450), ('Trump', 1440), ('And', 1361), ('Man', 1340), ('August', 1310), ('Apple', 1148), ('UK', 1132), ('On', 1122), ('What', 1113), ('Coronavirus:', 1077), ('Google', 1054), ('League', 1044), ('Why', 1032), ('China', 987)]
100%|██████████| 123225/123225 [00:00<00:00, 786827.09it/s]
Found embeddings for 50.42% of vocab
Found embeddings for  87.50% of all text
unknown words :  [('COVID-19', 6245), ('Covid-19', 2621), ('Coronavirus:', 1077), ('Covid', 824), ('2020:', 736), ('COVID', 670), ('TikTok', 525), ('cases,', 470), ("Here's", 414), ('LIVE:', 345), ('Size,', 318), ('Share,', 312), ('COVID-19:', 297), ('news:', 280), ('Trends,', 270), ('TheHill', 263), ('coronavirus:', 259), ('Report:', 256), ('Analysis,', 247), ('Fortnite', 245), ("won't", 242), ('Growth,', 234), ("It's", 234), ('Covid-19:', 229), ("it's", 224), ("Trump's", 223), ('English.news.cn', 203), ('COVID-19,', 196), ('Here’s', 196), ('updates:', 177)]

   分析上面的输出:

  大写的问题很严重,我们先把数据集的文本中,大写字母转小写。

[5] 文本单词全部小写

# ## 词典全部小写
print("=========转化小写后")
sentences = df['title'].apply(lambda x: x.lower())
sentences = sentences.progress_apply(lambda x: x.split()).values
vocab_low = build_vocab(sentences)
oov_glove = check_coverage(vocab_low, embed_glove)
oov_fasttext = check_coverage(vocab_low, embed_fasttext)

  查看输出:

=========转化小写后
100%|██████████| 108774/108774 [00:00<00:00, 354067.79it/s]
100%|██████████| 108774/108774 [00:00<00:00, 317075.17it/s]
100%|██████████| 102482/102482 [00:00<00:00, 1007395.77it/s]
Found embeddings for 42.97% of vocab
Found embeddings for  86.47% of all text
unknown words :  [('covid-19', 8897), ('–', 2521), ('covid', 1543), ('coronavirus:', 1338), ('2020:', 736), ('—', 626), ('tiktok', 529), ('covid-19:', 526), ("here's", 525), ('cases,', 502), ('live:', 464), ("it's", 459), ('news:', 363), ('size,', 326), ('updates:', 325), ('share,', 316), ("won't", 310), ("don't", 297), ('report:', 295), ("'the", 291), ('review:', 287), ('trends,', 280), ('covid-19,', 269), ('thehill', 263), ('update:', 260), ('analysis,', 253), ('here’s', 252), ("'i", 249), ('fortnite', 245), ('growth,', 244)]
100%|██████████| 102482/102482 [00:00<00:00, 778784.32it/s]
Found embeddings for 37.95% of vocab
Found embeddings for  85.17% of all text
unknown words :  [('covid-19', 8897), ('covid', 1543), ('coronavirus:', 1338), ('2020:', 736), ('tiktok', 529), ('covid-19:', 526), ("here's", 525), ('cases,', 502), ('live:', 464), ("it's", 459), ('meghan', 401), ('news:', 363), ('size,', 326), ('updates:', 325), ('share,', 316), ("won't", 310), ("don't", 297), ('huawei', 297), ('report:', 295), ('sushant', 292), ('review:', 287), ('trends,', 280), ('covid-19,', 269), ('thehill', 263), ('update:', 260), ('analysis,', 253), ('here’s', 252), ('fortnite', 245), ('growth,', 244), ('xiaomi', 237)]

  可以看到,转化为小写后,覆盖率有了极大的提升,但是85%左右的覆盖率还远远不够。我们尝试再去除特殊字符。

[6] 去除特殊字符

# ## 去除特殊字符
def clean_special_chars(text, punct, mapping):for p in mapping:text = text.replace(p, mapping[p])for p in punct:text = text.replace(p, f'{p}')specials = {'\u200b': ' ', '…': ' ... ', '\ufeff': '', 'करना': '', 'है': ''}  # Other special characters that I have to deal with in lastfor s in specials:text = text.replace(s, specials[s])return text# ## 去除特殊字符
print("=========去除特殊字符后")
punct = "/-'?!.,#$%\'()*+-/:;<=>@[\\]^_`{|}~" + '""“”’' + '∞θ÷α•à−β∅³π‘₹´°£€\×™√²—–&'
punct_mapping = {"‘": "'", "₹": "e", "´": "'", "°": "", "€": "e", "™": "tm", "√": " sqrt ", "×": "x", "²": "2", "—": "-", "–": "-", "’": "'", "_": "-", "`": "'", '“': '"', '”': '"', '“': '"', "£": "e", '∞': 'infinity', 'θ': 'theta', '÷': '/', 'α': 'alpha', '•': '.', 'à': 'a', '−': '-', 'β': 'beta', '∅': '', '³': '3', 'π': 'pi', }
sentences = df['title'].apply(lambda x: clean_special_chars(x, punct, punct_mapping))
sentences = sentences.apply(lambda x: x.lower()).progress_apply(lambda x: x.split()).values
vocab_punct = build_vocab(sentences)
oov_glove = check_coverage(vocab_punct, embed_glove)
oov_fasttext = check_coverage(vocab_punct, embed_fasttext)

  查看输出:

=========去除特殊字符后
100%|██████████| 108774/108774 [00:00<00:00, 359101.46it/s]
100%|██████████| 108774/108774 [00:00<00:00, 368426.97it/s]
100%|██████████| 55420/55420 [00:00<00:00, 1182299.35it/s]
Found embeddings for 80.79% of vocab
Found embeddings for  97.48% of all text
unknown words :  [('covid', 11852), ('tiktok', 680), ('fortnite', 372), ('bbnaija', 288), ('thehill', 263), ('ps5', 260), ('oneplus', 212), ('jadon', 168), ('havertz', 144), ('wechat', 135), ('researchandmarkets', 132), ('redmi', 129), ('realme', 116), ('brexit', 108), ('xcloud', 94), ('valorant', 84), ('note20', 69), ('airpods', 68), ('nengi', 67), ('vaping', 64), ('fiancé', 62), ('selfie', 62), ('pokémon', 60), ('1000xm4', 59), ('sarri', 55), ('iqoo', 52), ('miui', 52), ('wassce', 51), ('beyoncé', 50), ('kiddwaya', 49)]
100%|██████████| 55420/55420 [00:00<00:00, 1066584.97it/s]
Found embeddings for 67.35% of vocab
Found embeddings for  95.61% of all text
unknown words :  [('covid', 11852), ('tiktok', 680), ('meghan', 435), ('fortnite', 372), ('huawei', 364), ('sushant', 326), ('markle', 302), ('bbnaija', 288), ('xiaomi', 276), ('thehill', 263), ('ps5', 260), ('oneplus', 212), ('degeneres', 176), ('jadon', 168), ('buhari', 164), ('cagr', 162), ('solskjaer', 150), ('havertz', 144), ('perseid', 140), ('wechat', 135), ('researchandmarkets', 132), ('redmi', 129), ('fauci', 98), ('xcloud', 94), ('ardern', 93), ('valorant', 84), ('rtx', 83), ('akufo', 82), ('sadc', 82), ('kildare', 82)]

  可以看到,去除特殊字符后,覆盖率达到了97.5%,已经够用了。观察生词,这些都是最近几年出的新词,如‘covid’、'tiktok’等,这是无法改变的。

【注】:因为预训练词向量是在大规模语料库上训练出的,我们使用了预训练词向量后,可以选择在反向传播时不去修改嵌入层的参数(固定下来),也可以选择在使用预训练词向量后,在反向传播时继续修改嵌入层的参数(这叫微调,微调随着Bert的提出越来越流行)。

[7] 进行下一篇实战

  【英文文本分类实战】之四——词典提取与词向量提取

【英文文本分类实战】之三——数据清洗相关推荐

  1. 【英文文本分类实战】之四——词典提取与词向量提取

    ·请参考本系列目录:[英文文本分类实战]之一--实战项目总览 ·下载本实战项目资源:神经网络实现英文文本分类.zip(pytorch) [1] 提取词典   在这一步,我们需要把训练集train.cs ...

  2. 【英文文本分类实战】之二——数据集挑选与划分

    ·请参考本系列目录:[英文文本分类实战]之一--实战项目总览 ·下载本实战项目资源:神经网络实现英文文本分类.zip(pytorch) [1] 数据集平台   在阅读了大量的论文之后,由于每一篇论文都 ...

  3. 【英文文本分类实战】之一——实战项目总览

    [1] 总览   [英文文本分类实战]系列共六篇文章:   [英文文本分类实战]之一--实战项目总览   [英文文本分类实战]之二--数据集挑选与划分   [英文文本分类实战]之三--数据清洗   [ ...

  4. 英文文本分类实战总结

    之前参加了一个英文文本的分类比赛.比赛结束到了过年,加上开学又有一些事情,所以总结的工作就一直没有进行.现在空了一些,所以把之前的工作写一写,比赛中用到的代码也会放到github上. 对这个比赛的任务 ...

  5. 人工智能框架实战精讲:Keras项目-英文语料的DNN、Word2Vec、CNN、LSTM文本分类实战与调参优化

    Keras项目-英文语料的文本分类实战 一.机器学习模型 1.1 数据简介 1.2 数据读取与预处理 1.3 数据切分与逻辑回归模型构建 二.全连接神经网络模型 2.1 模型训练 2.2 模型结果展示 ...

  6. 英文文本分类——电影评论情感判别

    目录 1.导入所需的库 2.用Pandas读入训练数据 3.构建停用词列表数据 4.对数据做预处理 5.将清洗的数据添加到DataFrame里 6.计算训练集中每条评论数据的向量 7.构建随机森林分类 ...

  7. textcnn文本词向量_基于Text-CNN模型的中文文本分类实战

    1 文本分类 文本分类是自然语言处理领域最活跃的研究方向之一,目前文本分类在工业界的应用场景非常普遍,从新闻的分类.商品评论信息的情感分类到微博信息打标签辅助推荐系统,了解文本分类技术是NLP初学者比 ...

  8. 【BERT-多标签文本分类实战】之五——BERT模型库的挑选与Transformers

    ·请参考本系列目录:[BERT-多标签文本分类实战]之一--实战项目总览 ·下载本实战项目资源:>=点击此处=< [1] BERT模型库   从BERT模型一经Google出世,到tens ...

  9. 【BERT-多标签文本分类实战】之二——BERT的地位与名词术语解释

    ·请参考本系列目录:[BERT-多标签文本分类实战]之一--实战项目总览 ·下载本实战项目资源:>=点击此处=< [注]本篇将从宏观上介绍bert的产生和在众多模型中的地位,以及与bert ...

最新文章

  1. java.lang.OutOfMemoryError: PermGen space及其解决方法
  2. 我的世界java版幻翼_我的世界:熬夜3天能见到“幻翼”?你错了,还要满足这7个条件!...
  3. 多线程之HttpClient
  4. 读《编程珠玑》 (三)
  5. 深度学习网络调试技巧
  6. 跟优秀的人一起进步:四月组队学习
  7. 做优化的数据库工程师请参考!CynosDB的计算层设计优化揭秘
  8. YII 框架使用之——创建应用
  9. 部署shop++,启动eclipse遇到内存溢出。
  10. 内蒙古电大计算机考试成绩查询成绩查询,中考查分系统
  11. 带自动定位的水印相机_水印相机自动定位应该如何设置
  12. cs231n作业——softmax
  13. cmip5数据读取Matlab,CMIP5数据下载-其它文档类资源
  14. 用无线局域网设置服务器,无线局域网怎样配置
  15. blob写法的浏览器兼容性
  16. 从零到万的粉丝:抖音的推荐算法到底是怎样的?
  17. 参考文献怎么查找,去哪里查找?一篇文章讲明白这些问题
  18. 实验吧-who are you?
  19. 什么是ASR、TTS?
  20. 项目分享-校园宿舍管理系统

热门文章

  1. KC shop 开发历程------注册界面
  2. java与fabric区块链--fabric-ca-server 注册---(3)
  3. ThinkPHP读取数据库数据到模板文件
  4. Machine Learning | (11) 回归性能评估与欠拟合、过拟合
  5. 第十四课.Transformer
  6. sklearn解决回归问题
  7. 现实世界充满了bug_为啥程序会有bug?
  8. 适用于Linux命令的10个R函数
  9. QIIME 2教程. 30补充资源SupplementaryResources(2021.2)
  10. Nature-2018-抗菌药物组合有望特异性治疗耐多药性的细菌感染