从文本数据构建特征
介绍
文本数据不同于结构化表格数据,因此,在其上构建特征需要完全不同的方法。在本指南中,您将学习如何从原始文本中提取特征以进行预测建模。您还将学习如何执行文本预处理步骤,以及如何创建 Tf-Idf 和词袋 (BOW) 特征矩阵。我们将从探索数据开始。
数据
在本指南中,我们将使用有关“Apple”公司的推文数据。目标是创建可用于构建情绪预测模型的特征。
该数据集包含 1181 个观测值和 3 个变量,如下所述:
推文:由用户的 Twitter 评论组成。Twitter 数据是公开的。
平均:推文的平均情绪(-2 表示极其负面,而 +2 表示极其正面)。此分类是使用 Amazon Mechanical Turk 完成的。
情绪:由情绪标签组成 - 积极、消极和中性。
加载所需的库和模块
# Import required libraries
import pandas as pd
import matplotlib.pyplot as plt
import re
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import string
import nltk
import warnings
%matplotlib inline
warnings.filterwarnings("ignore", category=DeprecationWarning)
from nltk.corpus import stopwords
stop = stopwords.words('english')
加载数据并执行基本数据检查
下面的第一行代码将数据读入为 pandas 数据框,而第二行打印形状 - 3 个变量的 1,181 个观测值。第三行打印前五个观测值。
dat = pd.read_csv('datatweets.csv')
print(dat.shape)
dat.head(5)
输出:
(1181, 3)
| | Tweet | Avg | Sentiment |
|--- |--------------------------------------------------- |------ |----------- |
| 0 | iphone 5c is ugly as heck what the freak @appl... | -2.0 | Negative |
| 1 | freak YOU @APPLE | -2.0 | Negative |
| 2 | freak you @apple | -2.0 | Negative |
| 3 | @APPLE YOU RUINED MY LIFE | -2.0 | Negative |
| 4 | @apple I hate apple!!!!! | -2.0 | Negative |
我们将首先对数据进行基本分析。下面的代码行根据“情绪”标签打印推文数量。输出显示,推文数量最多的是负面情绪,而数量最少的是正面情绪。
# Get the number of dates / entries in each month
dat.groupby('Sentiment')['Tweet'].count()
输出:
Sentiment
Negative 541
Neutral 337
Positive 303
Name: Tweet, dtype: int64
推文的情绪得分存储在变量“Avg”中,范围从 -2(极度负面)到 +2(极度正面)。我们将探索“情绪”标签上的平均情绪得分是否存在差异。下面的代码行执行此任务,输出显示平均负分数为 -0.74,而平均正分数为 0.57。
dat.groupby('Sentiment')['Avg'].mean()
输出:
Sentiment
Negative -0.743068
Neutral 0.000000
Positive 0.574257
Name: Avg, dtype: float64
从原始文本构建简单特征
可以从原始文本数据中提取许多简单但重要的特征,如下所述。
字符长度
假设推文中字符的长度会根据其所表达的情绪而变化。下面的第一行代码创建了一个新的变量“character_cnt”,该变量从“Tweet”变量中获取文本并计算文本中的字符数。第二行对“情绪”标签执行“groupby”操作并打印标签上的平均字符长度。
输出显示,与正面和负面的推文相比,中性情绪的平均字符数较低。此推断可用于将中性推文与其他类型的推文区分开来。
dat['character_cnt'] = dat['Tweet'].str.len()
dat.groupby('Sentiment')['character_cnt'].mean()
输出:
Sentiment
Negative 91.763401
Neutral 85.379822
Positive 94.825083
Name: character_cnt, dtype: float64
字数统计
就像推文中的字符数一样,字数也是一个有用的功能。下面的第一行代码创建了一个新的变量“word_counts”,它从“Tweet”变量中获取文本并计算文本中的单词数。第二行对“Sentiment”标签执行“groupby”操作并打印标签上的平均单词长度。
输出显示,负面情绪的平均字数最高,这表明失望的顾客倾向于写较长的推文。这一推论对于区分“情绪”标签很有用。
dat['word_counts'] = dat['Tweet'].str.split().str.len()
dat.groupby('Sentiment')['word_counts'].mean()
输出:
Sentiment
Negative 15.336414
Neutral 12.356083
Positive 14.676568
Name: word_counts, dtype: float64
每个单词的平均字符长度
由于我们已经创建了“character_cnt”和“word_counts”特征,因此很容易创建这两个变量的比率,从而得出每条推文中每个单词的字符的平均长度。
下面的第一行代码创建了一个新的变量“characters_per_word”,它是一条推文中的字符数和单词数的比率。第二行对“Sentiment”标签执行“groupby”操作,并在标签上打印每个单词的平均字符长度。
输出显示,中性情绪的每个单词的平均字符长度最高。此推断对于区分“情绪”标签很有用。
dat['characters_per_word'] = dat['character_cnt']/dat['word_counts']
dat.groupby('Sentiment')['characters_per_word'].mean()
输出:
Sentiment
Negative 6.191374
Neutral 7.425695
Positive 6.687928
Name: characters_per_word, dtype: float64
特殊字符计数
还可以创建一个包含特殊字符(如“@”或“#”)计数的功能。下面的第一行代码创建了一个新的功能“spl”,它从“Tweet”变量中获取文本并计算以特殊字符“@”开头的单词数。我们使用starts with函数来执行此操作。第二行打印包含“Tweet”和“spl”变量的前五个观察值。
dat['spl'] = dat['Tweet'].apply(lambda x: len([x for x in x.split() if x.startswith('@')]))
dat[['Tweet','spl']].head()
输出:
| | Tweet | spl |
|--- |--------------------------------------------------- |----- |
| 0 | iphone 5c is ugly as heck what the freak @appl... | 2 |
| 1 | freak YOU @APPLE | 1 |
| 2 | freak you @apple | 1 |
| 3 | @APPLE YOU RUINED MY LIFE | 1 |
| 4 | @apple I hate apple!!!!! | 1 |
數量
就像我们创建了推文中单词计数的特征一样,我们也可以创建推文中数字计数的特征。下面的第一行代码创建了一个新的变量“num”,它从“Tweet”变量中获取文本并计算文本中数字的数量。第二行对“Sentiment”标签执行“groupby”操作并打印标签上数字的平均数量。
输出显示,中性情绪标签在推文中的平均数字计数最低,而负面推文的平均数字计数最高。
#Number of numerics
dat['num'] = dat['Tweet'].apply(lambda x: len([x for x in x.split() if x.isdigit()]))
dat.groupby('Sentiment')['num'].mean()
输出:
Sentiment
Negative 0.125693
Neutral 0.068249
Positive 0.108911
Name: num, dtype: float64
预处理原始文本
到目前为止,我们已经从原始文本中创建了简单的特征。我们还可以创建更高级的特征,但在此之前,我们必须清理文本。常见的预处理步骤总结如下:
删除标点符号- 经验法则是删除所有不属于 x,y,z 格式的符号。下面的第一行代码执行此任务。
删除停用词- 这些是无用的词,例如“the”、“is”、“at”。这些词没有用,因为此类停用词在语料库中出现的频率很高,但它们无助于区分目标类别。删除停用词也会减少数据量。下面的第二行代码执行此任务。
转换为小写- 像“Phone”和“phone”这样的单词需要被视为一个单词。因此,这些单词被转换为小写。下面的第三行代码执行此任务。
词干提取- 词干提取的目的是减少文本中出现的单词的屈折形式数量。这使得诸如“argue”、“argued”、“arguing”、“argues”等单词被简化为它们的共同词干“argu”。有很多方法可以执行词干提取,其中最流行的是 Martin Porter 的“Porter Stemmer”方法。下面的第四到第六行代码执行此任务。
最后一行代码打印了我们迄今为止构建的所有新功能的摘要。
dat['processedtext'] = dat['Tweet'].str.replace('[^\w\s]','')
dat['processedtext'] = dat['processedtext'].apply(lambda x: " ".join(x for x in x.split() if x not in stop))
dat['processedtext'] = dat['processedtext'].apply(lambda x: " ".join(x.lower() for x in x.split()))
#Lines 4 to 6
from nltk.stem import PorterStemmer
stemmer = PorterStemmer()
dat['processedtext'] = dat['processedtext'].apply(lambda x: " ".join([stemmer.stem(word) for word in x.split()]))
dat[['character_cnt','word_counts','characters_per_word', 'spl', 'num', 'processedtext']].head()
输出:
| | character_cnt | word_counts | characters_per_word | spl | num | processedtext |
|--- |--------------- |------------- |--------------------- |----- |----- |--------------------------------------------- |
| 0 | 64 | 11 | 5.818182 | 2 | 0 | iphon 5c ugli heck freak appl iphonecompani |
| 1 | 16 | 3 | 5.333333 | 1 | 0 | freak you appl |
| 2 | 16 | 3 | 5.333333 | 1 | 0 | freak appl |
| 3 | 25 | 5 | 5.000000 | 1 | 0 | appl you ruin my life |
| 4 | 24 | 4 | 6.000000 | 1 | 0 | appl i hate appl |
词频-逆文档频率 (TF-IDF) 向量
我们已经清理了文本,现在将其存储在新变量“processedtext”中。但是,为了使用它来构建机器学习模型,我们必须将其转换为词频向量。
最流行的方法之一是通过TF-IDF表示,它在文本挖掘应用中用作加权因子。简而言之,TF-IDF 试图突出显示在文档中频繁出现但不在文档之间出现的重要单词。这些术语的简要解释如下:
词频(TF):总结了文档中规范化的词频。
<font style="vertical-align: inheri
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~