本文为 AI 研习社编译的技术博客,原标题 What App Descriptions Tell Us: Text Data Preprocessing in Python,作者为Finn Qiao。
翻译 | nick李 校对 | 付腾 整理 | 令双
除了数据清洗和数据探索的主题外,许多有效的NLP(自然语言处理)分析都是依赖于对文本数据的预处理。因此,我决定手把手展现一个对来自苹果App Store简述的文本数据预处理的过程,并且对这些数据使用K均值聚类算法。
为什么要选择App Store呢?Kaggle的数据集包括了7197个应用及其各自的应用简述。应用开发者在应用简述中用尽所能来“推销”他们的应用。我使用这些预处理的数据,检验了一个问题——是否能根据应用简述对应用类别进行良好预测?
我所使用的预处理“框架”主要如下:
翻译*
去除非字母字符
大写转小写
分词
去除停用词
词干提取(stemming)**
数据分析
* 我首先对所有简述进行翻译的原因是,非字母字符的正则表达式可能会将某些语言去除掉,例如日文和中文。
** 在这一步中我省去了词形还原(lemmatization)因为我想要在后面的步骤中着眼于词汇多样性。
和普遍做法一样,我们先以读取csv文件获得相关数据开始。在这里,我们将有基本应用信息的数据帧(Dataframe)和有应用简述的数据帧合并。
由于大部分特征变量的数据类型都是合理的,让我们先概览一下相关数据。
不出所料的是,App Store中大部分应用是游戏,这一类别大约占数据集的54%。其次是”娱乐“和”教育“,与游戏相差甚远,分别占比7%和6%。
平均评分最高的类别是”效率“和”音乐“。有趣的是,目前为止”商品指南“、“经济”和“图书”为App Store中评分最低的三个应用类别。
预处理过程
1 译成英文
开始预处理我们首先将所有应用简述翻译为英文。此处我们可以使用googletrans包来调用谷歌翻译的API。遗憾的是,这个API调用有15000个字符的限制。我们可以通过在数据帧的每一行重新初始化translator来应对字数限制,尽管这不是优雅的编程方式。
当应用简述已经是英文的时候,我们可以使用langdetect包来进行检测并仅在语言不是英文才调用API,这样以减少无用的API调用操作。
有46个应用的简述返回了error。这些应用的简述可能超出了字数,而其他的应用则没有问题。考虑到出错的个数仅仅是整个数据集中的一小部分,我们完全可以抛弃掉这些数据。
2 去除非字母字符
现在我们确信诸如日文和中文的简述不会被正则表达式筛除,我们可以创建一个表达式[^a-zA-Z]来返回所有字母和空格。除此之外的其他字符被帮助函数cleaned()中的re.sub()方法去除。空格被保留以用于分词。
3 大写转小写
文本数据正则化的另一步就是将所有字符转化为小写。这一步too simple,只需要对数据帧的相应列运行str.lower()方法即可。
4,5,6 分词,去停用词和词干提取
鉴于这三步已经被nltk实现,我写了一个帮助函数来把它们集成起来。
分词指的是讲一个长句切分成小的块或标识符。这个和使用既定的切分器对一个字符串运行切分函数并得到一个它的各个部分的列表的做法差不多。我们在这里使用nltk包中的word_tokenize()方法来进行分词。
停用词是指可以被过滤掉而不影响文本大意的词。其中包括诸如'a', 'to', 'and'等词。我们通过使用stopwords.words('english')来获得nltk中英文停用词集合。
词干提取指的是去除词的词缀。例如,'climbing'去除词缀变成'climb'。我们使用nltk中的SnowballStemmer('english')来初始化词干提取器。
下面的帮助函数首先将句子分词,然后检查每个词是否为停用词并且过滤停用词,最后运行词干提取器去除词缀并将词加入列表中。
7 数据分析
让我们现在深入已经清洗好的数据。
7.1 词云生成
哪些词被最多地用来描述应用类别呢?尽管使用简单的词频统计或tf-idf vectorizer可以返回词的排名列表,使用词云可能会更加有效地展示那些最常用的词。
为了给每个类别生成一个词云,我为每个建立了一个清洗过的应用简述语料库(或者说是集合)。比较幸运的是,wordcloud包可以很方便地从一个给定语料库生成词云。
wordcloud包通过创建语料库中排名前200的词列表和它们正则化后的词频统计列表来工作。得到词排名的列表后,我们使用Pythin Image库来绘制词云。这个总结并没有对他的代码公正,你可以在下图得到更多相关信息。
取"游戏","天气","购物"和"音乐"的一小部分词为例,我们可以看出,最显著的词其实就是我们所期望的代表其类别的词。但是,尽管在这些类别中效果显著,在其他类别中代表词的区分却不明显。我们将会在下文中聚类时讨论这一点。
7.2 词汇多样性
诸如“游戏“的不同的类别是否本来就有更多样的语言和描述呢?我通过使用一个评估词汇多样性的简单公式来回答这个问题。我用每个过滤列表中的唯一词个数除以相应简述的词总数得到一个数值。这个数值越高就表示词汇多样性越高。
如同预期的一样,“游戏”和“图书”的平均词汇多样性的得分是最高的。可能的原因主要是这两个类别有较多子类别以及它们的简述相对更加“吸引人心”。
而商品指南的描述就可以说是相当的无聊了。
7.3 情感分析
是否存在某些类别的应用简述的态度比其他类别的更加积极?对此我决定用Textblob包来进行情感分析展示。
情感极性为0意味着中立态度,极性小于0表示负面情感,极性大于0表示(你猜对了)正向的情感。
类别“游戏”、“经济”和“医疗“具有最低的平均情感极性。如果游戏内包含有消极主题,例如战争与恐惧(这些主题被很好的体现),"游戏"则可能会有很低的极性。"经济"和"医疗"的极性很低的原因可能是因为其描述了并不乐观的经济或医疗情况。
可能对某几本催人泪下作品的简述构成了“图书”的主要基调。而提到了“捕捉快乐时光”似乎构成了“摄影与录像“的主旋律。
7.4 K均值聚类
现在来到了我们最初的问题——是否能根据应用简述对应用类别进行良好预测?
为了回答这个问题,我对词向量应用可K均值进行聚类并观察它们映射到实际的类别的表现好坏。
当我们设立10个簇并运行聚类算法时,每个簇的前10个词如下图所示:
乍一看的话,似乎某些簇是可以被解释并标记的:
簇0: 面向儿童的应用
簇3: 音乐类应用
簇4: 包含战争/打斗/怪兽的游戏
簇6: 文字游戏
簇7: 摄影与录像应用
簇9: 汽车相关应用
那么这些簇是如何映射到实际中的应用类别的呢?
上面所示的标签看起来具有代表性但是实际上却存在一个问题,在这个样例中,游戏被过度表示了。其他类别的颜色在图表中太浅了以至于几乎没有意义。下图展示了去除了“游戏”后的热图分布。
没有了“游戏”的过度表示后,其他类别的程度就可以清晰识别了。其中较为明显的是簇3和“教育”,簇4和“经济”以及“购物”,簇7和“购物”,还有簇9和“摄影和录像“。
那如果我们将簇的个数增加到与实际类别数相同会怎么样呢(不包含游戏共22个)?
同样,还是先横向比较一下这些簇和各自常用词之间的关系。
在这20个簇中,比较容易定义的簇有:
簇0:购物
簇9:健康&健美
簇10:音乐
簇11:摄影与录像
簇13:教育
簇14:经济
簇17:天气
可以看到,只有三分之一的类别被较好地表示出来,而且其中两个最明显的类别具有很不平衡的样本大小。而且,各个类别之间的词存在重叠现象。导致这些的原因有很多。
不平衡的样本大小
正如一开始所提到的,数据集中大约54%的应用是游戏。即便在将“游戏”类别筛除之后,仍有较大部分游戏被表示在“教育”和“娱乐”类别中。
全都是游戏
如果在所有类别中都挑选一定的样本数量,那么结果可能会更好,但是那样的基础是需要一个更大的整体样本。
词重叠
尽管样本的数量很少,“天气”类应用还是被簇17所表示。那些能够被簇所表示出来的类别是因为其具有独特的命名系统。
且看类别“工具“和”参考“的词云,它们都包含了一些在其他类别中也有所表示的词。
也许可以生成一个列表,其中包含一些跨类别词,并将这个列表中的词从清洗之后的句子中过滤掉。尽管如此,像”效率“和”工具“这样的类别还是有可能和其他类别具有重叠的词,因此无法被完全聚类。
在解决本文的NLP分析里的一些问题后,我想创立一个模型并利用应用简述以及更多的信息来预测应用类别的模型。
我也在尝试使用markovify来生成每个类别的应用简述。这是“体育”类的一些例子:
如你所见,其实也不是特别好(摊手)¯\_(ツ)_/¯
最后,感谢阅读,代码在此
https://github.com/finnqiao/apple_appstore
https://towardsdatascience.com/what-app-descriptions-tell-us-text-data-preprocessing-in-python-afc7ed88360d
领取专属 10元无门槛券
私享最新 技术干货