查看原文
其他

Python:文本数据增强

连享会 连享会 2023-10-24

👇 连享会 · 推文导航 | www.lianxh.cn

连享会课程 · 2023 暑期班

⛳ Stata 系列推文:

  • 全部  | Stata入门 |  Stata教程 |  Stata资源 | Stata命令
  • 计量专题 | 论文写作 | 数据分享 |  专题课程
  • 结果输出 | Stata绘图 | 数据处理 |  Stata程序
  • 回归分析 |  面板数据  | 交乘项-调节  | IV-GMM
  • 内生性-因果推断 |  倍分法DID |  断点回归RDD |  PSM-Matching |  合成控制法
  • Probit-Logit |  时间序列 |  空间计量 | 分位数回归 | 生存分析 | SFA-DEA
  • 文本分析-爬虫 |  Python-R-Matlab | 机器学习
  • Markdown  | 工具软件 |  其它

PDF下载 - 推文合集

作者:张洪洋 (西南财经大学)
邮箱:1750410339@qq.com

温馨提示: 文中链接在微信中无法生效。请点击底部「阅读原文」。或直接长按/扫描如下二维码,直达原文:

编者按:本文主要参考自 西南财经大学国际联合实验室《利用Python学习NLP》课件,特此致谢!


目录

  • 1. 文本数据截断

  • 2. 数据扩充

    • 2.1 直接复制

    • 2.2 反译

  • 3. 噪声技术

    • 3.1  同义词替换

    • 3.2  随机插入

    • 3.3  随机删除

  • 4. 相关推文



文本数据增强可以简单理解为由少量数据生成大量数据的过程。一般比较成功的神经网络拥有大量参数,使这些参数正确工作需要用大量的数据进行训练,但实际情况是数据并没有那么多,因此需要做数据增强。

相较于图像、语音方面的数据增强而言,文本的数据增强更具有挑战性,因为文本中微小的改动就可能带来语义的变化,从而破坏了原文本,导致数据质量降低。本文将介绍通用几种文本数据增强方法,除了这些通用的增强方法之外,大多数时候需要针对具体的 NLP 任务设计对应的文本数据增强方法。

1. 文本数据截断

在处理长文本的过程中,通常需要按照某个阈值对文本进行截断,但是又不能直接在当前阈值截断,可能会破坏句子结构。比较理想的方案是,在某一个阈值向前搜索并找到句子的末位 (例如句号) 处进行截断,剩下的若还超过阈值,则重复截断。下面以 example_text_data.csv 这个文件为例。

import pandas as pd
data = pd.read_csv(r'https://file.lianxh.cn/data/e/example_text_data.csv')
data['text_len'] = data['text'].map(len) 
data['text_len'].describe()
count     600.0000
mean      223.5000
std       281.2513
min        25.0000
25%       121.0000
50%       163.0000
75%       268.2500
max      5949.0000
Name: text_len, dtype: float64

可以看到大部分文本长度在 300 以内,存在少量超长文本。一般而言,为了避免维度过大以及提升计算效率,大多数 NLP 模型将文本的输入长度限制在了 512 或 1024 之内,这就意味着对于少量的超长文本,需要抛弃或者进行文本截断操作。

truncated_data = pd.DataFrame(columns=['id','text'])  #新建dataframe
max_len = 300  #假设句子最长为300
for j in range(len(data)):  
    text = data['text'][j]  #text
    left_index = 0          #设定句子的左索引,默认为0
    temp_text_list = []     #list
    count = 0
    df = {}    #存放新增的内容
   
    while len(text[left_index:])>= max_len :
        count +=1
        for z in range(100):  # 只需向前搜索一定步数,加快运算
            if text[left_index+max_len-z] in ['!','。','>',';','•',') '] :  
                #出现list里的这些符号认为为句子末尾,可自定义
                temp_text_list.append(text[left_index: left_index+300-z+1])   
                #截断的第一个句子
                left_index += max_len-z+1  # 将左索引右移到截断除
                break
        if count>=40:  #可能会出现长文本里面没有结尾的情况,限制搜索范围为max_len*4个字节
            break
    
    temp_text_list.append(text[left_index:])  #截断的句子存放处
    
    for i in temp_text_list:
        df["id"] = data['id'][j]  #装入df
        df["text"] = i
        truncated_data = truncated_data.append(df,ignore_index=True)  # 向dataframe内添加行

truncated_data['text_len'] = truncated_data['text'].map(len)
truncated_data['text_len'].describe()  
count     681.00000
mean      196.91630
std       193.08095
min        10.00000
25%       121.00000
50%       164.00000
75%       258.00000
max      4266.00000
Name: text_len, dtype: float64

2. 数据扩充

机器学习模型需要足够的数据支撑才能进行更好地训练,但实际生活中,作为开发者往往无法获取大量的数据,而专业的数据采集和标注公司提供的数据服务也并不便宜。因此,解决此问题有一个较为不错的初级方案,那就是进行数据扩充。

数据扩充 (data augmentation) 的本质:缺少海量数据时,为了保证模型的有效训练,一分钱掰成两半花。这里介绍两种数据扩充的方法。

2.1 直接复制

在 Python 中,直接用等于符号或者运用 copy() 函数可以返回一个复制。然而单纯地运用等于符号和 copy() 函数,只会返回一个浅复制 (浅拷贝)。

对于浅复制而言,其中一个发生变化,另一个被复制的对象或原对象也会发生变化。而对于深复制(深拷贝)而言,一旦复制出来了,就是独立的,其中一个发生变化,另一个不会随之发生变化。因此,增加数据量最简单和直接的方法就是直接复制拷贝一份新的数据。

new_data  = data.copy(deep=True)  #深复制
data = pd.concat([new_data,data], ignore_index = True)  #pd.concat将两个dataframe进行拼合
print(f"扩充后的数据data.shape: {data.shape}")
扩充后的数据data.shape: (12003)

2.2 反译

对于文本数据而言,将文本翻译成其他语言再翻译成回来后,利用翻译器的特点,使得翻译回来的文本与原来的文本语义高度相似,又引入了其他词汇,增加了模型可学习的内容。gooletrans 是一个免费的调用谷歌翻译库的 python api,可以通过以下代码安装:

!pip install googletrans==4.0.0rc1

下面利用 gooletrans 来进行中文的反译操作:

import csv
from googletrans import Translator

translator = Translator(service_urls=[ 
      'translate.google.cn' 
    ]) #接入谷歌的翻译服务,设定service_urls为translate.google.cn即可翻译中文
translator.raise_Exception = True  #避免ip被限制

chinese_text = '下面的代码,我只涉及到了“中文”和“英语”两种语言的循环翻译,没有涉及到其他的语言。'
print(f"原句子: \n{chinese_text}\n")

english_text = translator.translate(chinese_text).text  # 调用translate方法
print(f"汉译英: \n{english_text}\n")

re_chinese_text = translator.translate(english_text,dest='zh-CN').text  # 设定为英译汉
print(f"英译汉:\n{re_chinese_text}\n")
原句子: 
下面的代码,我只涉及到了“中文”和“英语”两种语言的循环翻译,没有涉及到其他的语言。

汉译英: 
In the following code, I only involve cyclic translations of two languages: 
"Chinese" and "English", which does not involve other languages.

英译汉:
在以下代码中,我仅涉及两种语言的循环翻译:“中文”和“英语”,不涉及其他语言。

将 example_data 进行批量的反译:

import pandas as pd
data = pd.read_csv('example_text_data.csv')  # 读入
trans_data = data.copy(deep = True)  #深拷贝

translator.raise_Exception = True   #避免ip被限制
trans_data['trans_text'] = trans_data['text'][:5].map(lambda x: \
    translator.translate(translator.translate(x).text,dest='zh-CN').text)
# map和lambda函数是dataframe中非常重要的函数,可以很方便的灵活的对dataframe进行批量操作
display(trans_data.head())

3. 噪声技术

噪声技术旨在通过向文本中注入噪声数据,来生成新的文本,最后使得训练的模型对扰动具有鲁棒性。EDA (Easy Data Augmentation) 是一种通用且易于实现的 nlp 噪声技术,能显著提高卷积和递归神经网络的性能,仅使用 50% 的可用训练集进行 EDA 训练便达到了与使用所有可用数据进行正常训练相同的准确度。

EDA由四个简单但功能强大的操作组成:同义词替换、随机插入、随机交换和随机删除。

3.1  同义词替换

同义词替换(Synonym Replacement, SR)是指从句子中随机选取 n 个不属于非停止词,并随机选择其同义词替换它们。

!pip install synonyms 
#若未安装synonoyms,运行此代码,若synonyms安装错误,请检查是否有安装jieba等前置库
import jieba
import random
from random import shuffle
import sys
import synonyms 
#一个中文近义词工具包,开源地址在https://github.com/chatopera/Synonyms
#synonyms第一次调包可能会很慢,您可以选择将文件夹中的"words.vector.gz"文件放入该包路径".//synonyms//data//"中,
#以anaconda为例,路径为应该为"//anaconda//lib//site-packages//synonyms//data//"

我们通过 synonyms.display()synonyms.nearby() 来具体看一下 synonyms 是怎么展示中文同义词结果。

synonyms.display("飞机"
#synonyms.display()将输出"飞机"的近义词组,并以单词相似性由高到低排序
'飞机'近义词:
  1. 飞机:1.0
  2. 直升机:0.84233904
  3. 客机:0.83930016
  4. 滑翔机:0.7872388
  5. 军用飞机:0.7832081
  6. 水上飞机:0.77857226
  7. 运输机:0.77247417
  8. 航机:0.7664748
  9. 航空器:0.76592904
  10. 民航机:0.74209654
synonyms.nearby("飞机"
#synonyms.nearby()返回一个包含"近义词"和"该近义词得分"的元组,二者均以列表的形式存储
(['飞机''直升机''客机''滑翔机''军用飞机''水上飞机''运输机''航机''航空器''民航机'],
 [1.0,
  0.84233904,
  0.83930016,
  0.7872388,
  0.7832081,
  0.77857226,
  0.77247417,
  0.7664748,
  0.76592904,
  0.74209654])

接下来我们将利用同义词库去构建 EDA 中的相关方法,包括同义词替换和随机插入。

random.seed(2022#设置随机种子

#构建停用词列表
with open('停用词.txt''r',encoding='utf-8'as f:   
    stop_words = [s.rstrip() for s in f.readlines()]
#分词
sentence = "我也期待着能和你飞去同一片土地"
words = jieba.lcut(sentence)  # 调用jieba进行分词
print(words)  # 分词结果
['我''也''期待''着''能''和''你''飞去''同''一片''土地']

进行同义词替换主要只进行二步,第一步是找到同义词列表,第二部是随机选择同义词列表中的一个词进行替换。

# 同义词替换:替换一个语句中的n个单词为其同义词
def synonym_replacement(words, n):
    new_words = words.copy()  #深拷贝
    random_word_list = list(set([word for word in words if word not in stop_words])) 
    #生成非停止词列表    
    random.shuffle(random_word_list) 
    #将列表中元素打乱顺序,便于后续随机选择同义词进行替换
    num_replaced = 0      
    #被替换的词的数量,初始为0  
    for random_word in random_word_list:          
        synonyms_word = synonyms.nearby(random_word)[0
        #调用刚才定义的函数get_synonyms,返回意思最相近的词语
        if len(synonyms_word) >= 1:
            synonym = random.choice(synonyms_word) 
            #在同义词列表中随机选择一个同义词  
            new_words = [synonym if word == random_word else word for word in new_words] 
            #将随机选择的同义词添加进词表,并替换原单词  
            num_replaced += 1
        if num_replaced >= n: #当n个单词被替换后结束循环
            break
    return new_words
print(f"替换前:\n{words}\n")
print(f"替换后:\n{synonym_replacement(words, 1)}\n")  
#调用synonym_replacement,设置n=1,即随机替换一个同义词
替换前:
['我''也''期待''着''能''和''你''飞去''同''一片''土地']

替换后:
['我''也''期待''着''能''和''你''飞去''同''一片''田地']

3.2  随机插入

随机插入 (Random Insertion,RI) 是指从句子中随机选择一个非停止词,然后找到它对应的同义词,并将其插入到句子中的一个随机位置

# 随机插入n个同义词
def add_word(new_words):
    synonyms = []  # 同义词表
    counter = 0  # 计数器
    random_word_list = list(set([word for word in new_words if word not in stop_words])) 
    #生成非停止词列表   
    while len(synonyms) < 1:
        #这里主要指随机选择random_word_list中一个词
        random_word = random_word_list[random.randint(0, len(random_word_list)-1)] 
        #random.randint()方法随机返回指定范围内的一个整数,
        #并且可以取到右侧边界值,为防止索引超出列表容量,因此会减1
        synonyms = get_synonyms(random_word) 
        #调用上面定义的函数get_synonyms,返回一个包含10个同义词的list
        counter += 1
        if counter >= 10:
            return
    random_synonym = random.choice(synonyms)  #从同义词中随机进行选择
    random_idx = random.randint(0, len(new_words)-1#选择一个随机索引,便于随机选择的同义词插入
    new_words.insert(random_idx, random_synonym)  #在随机索引处插入同义词

def random_insertion(words, n):  #调用随机插入方法,重复n次
    new_words = words.copy()
    for _ in range(n):
        add_word(new_words) # 调用上面定义的函数add_word
    return new_words
print(f"插入前:\n{words}\n")
print(f"插入后:\n{random_insertion(words, 1)}\n"#随机插入n =1个同义词
插入前:
['我''也''期待''着''能''和''你''飞去''同''一片''土地']

插入后:
['我''也''期待''着''能''和''你''飞去''同''盼望''一片''土地']

3.3  随机删除

随机删除 (Random Deletion,RD) 指以概率 随机删除句子中的单词。

def random_deletion(words, p):
    if len(words) == 1:  #至少要大于1个单词才能随机删除
        return words
    new_words = []
    for word in words:
        r = random.uniform(01#随机生成一个在 (0,1) 范围内的实数
        if r > p: #以1-p的概率向新词列表添加单词
            new_words.append(word)
    if len(new_words) == 0#若删除概率p为1,则随机保留词表中的一个单词
        rand_int = random.randint(0, len(words)-1)
        return [words[rand_int]]
    return new_words
print(f"删除前:\n{words}\n")
print(f"删除后:\n{random_deletion(words, 0.1)}\n"#以0.1的概率随机删除单词
删除前:
['我''也''期待''着''能''和''你''飞去''同''一片''土地']

删除后:
['我''也''期待''着''能''和''你''飞去''同''一片''土地']

4. 相关推文

Note:产生如下推文列表的 Stata 命令为:
lianxh 文本, m
安装最新版 lianxh 命令:
ssc install lianxh, replace

  • 专题:专题课程
    • ⏩ 专题课:文本分析-爬虫-机器学习-2022年4月
    • 连享会:助教入选通知-2022文本分析与爬虫
    • ⚽助教招聘:文本分析-爬虫-机器学习
    • 助教入选结果 - 连享会 文本分析与爬虫直播课
  • 专题:数据分享
    • 数据库分享:年报文本语气数据库
  • 专题:Stata命令
    • Stata:计算文本语调-onetext
  • 专题:文本分析-爬虫
    • Stata文本分析:lsemantica-潜在语义分析的文本相似性判别
    • textfind:文本分析之词频分析-TF-IDF
    • Stata文本分析之-tex2col-命令-文字变表格
    • Stata: 正则表达式和文本分析
  • 专题:Python-R-Matlab
    • Python文本分析:将词转换为向量-Word2Vec
    • Python:文本分析必备—搜狗词库
    • Python: 使用正则表达式从文本中定位并提取想要的内容
  • 专题:公开课
    • ⭐ 公开课:王菲菲-文本分析在经济金融领域的应用

课程推荐:2023 暑期班
主讲老师:连玉君,王群勇
🍓 课程主页https://www.lianxh.cn/news/fdc69c3695aec.html

New! Stata 搜索神器:lianxhsongbl  GIF 动图介绍
搜: 推文、数据分享、期刊论文、重现代码 ……
👉 安装:
. ssc install lianxh
. ssc install songbl
👉  使用:
. lianxh DID 倍分法
. songbl all

🍏 关于我们

  • 连享会 ( www.lianxh.cn,推文列表) 由中山大学连玉君老师团队创办,定期分享实证分析经验。
  • 直通车: 👉【百度一下: 连享会】即可直达连享会主页。亦可进一步添加 「知乎」,「b 站」,「面板数据」,「公开课」 等关键词细化搜索。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存