PHP

如何用PHP机器学习分析推文情绪

艾伦•麦格雷戈
分享

本文由Wern Ancheta.感谢所有SitePoint的同行审必威西盟体育网页登录稿人,让SitePoint的内容成为最好的!


最近,似乎每个人都在谈论机器学习。你的社交媒体上充斥着关于ML、Python、TensorFlow、Spark、Scala、Go等的帖子;如果你和我一样,你可能会想,PHP怎么样?

是的,机器学习和PHP怎么样?幸运的是,有人足够疯狂,不仅提出了这个问题,而且还开发了一个通用的机器学习库,我们可以在下一个项目中使用。在这篇文章中,我们来看看PHP-ML-一个PHP的机器学习库-我们将编写一个情感分析类,我们可以在我们自己的聊天或推特机器人中重用。这篇文章的主要目标是:

  • 探索机器学习和情感分析的一般概念
  • 回顾PHP-ML的功能和缺点
  • 定义我们要解决的问题
  • 证明尝试在PHP中进行机器学习并不是一个完全疯狂的目标(可选)

机器大象

什么是机器学习?

机器学习是人工智能的一个子集,专注于赋予“计算机在没有明确编程的情况下学习的能力”。这是通过使用可以从特定数据集“学习”的通用算法来实现的。

例如,机器学习的一个常见用途是分类。分类算法用于将数据放入不同的组或类别中。分类应用程序的一些例子如下:

  • 垃圾邮件过滤器
  • 市场细分
  • 欺诈检测

机器学习是一个涵盖了不同任务的许多通用算法的总称,有两种主要的算法类型根据它们的学习方式进行分类——监督学习和无监督学习。

监督式学习

在监督学习中,我们使用输入对象(向量)和期望输出值形式的标记数据训练我们的算法;该算法分析训练数据并产生所谓的推断函数,我们可以将其应用于新的未标记数据集。

在这篇文章的剩余部分,我们将专注于监督学习,因为它更容易看到和验证关系;请记住,这两种算法同样重要和有趣;有人可能会说,无监督更有用,因为它排除了标记数据的要求。

无监督学习

另一方面,这种类型的学习从一开始就适用于未标记的数据。我们不知道数据集的期望输出值,我们让算法从数据集中推断;在进行探索性数据分析以发现数据中的隐藏模式时,无监督学习特别方便。

PHP-ML

PHP- ml,一个号称是PHP机器学习的新方法的库。该库实现了算法、神经网络和工具来进行数据预处理、交叉验证和特征提取。

我首先承认PHP是机器学习的一个不寻常的选择,因为该语言的优势并不适合机器学习应用程序。也就是说,并不是每个机器学习应用程序都需要处理pb级的数据并进行大量计算——对于简单的应用程序,我们应该能够使用PHP和PHP- ml。

目前我所能看到的这个库的最佳用例是分类器的实现,可能是垃圾邮件过滤器,甚至是情感分析。我们将定义一个分类问题并逐步构建一个解决方案,以了解如何在我们的项目中使用PHP-ML。

这个问题

为了举例说明实现PHP-ML并在我们的应用程序中添加一些机器学习的过程,我想找一个有趣的问题来解决,还有什么比构建一个tweet情感分析类更好的方法来展示分类器呢?

构建成功的机器学习项目所需的关键要求之一是一个体面的起始数据集。数据集是至关重要的,因为它们将允许我们针对已经分类的示例训练我们的分类器。由于最近媒体上关于航空公司的噪音很大,还有什么比客户对航空公司的推文更好的数据集呢?

幸运的是,我们已经可以使用推文数据集Kaggle.io.推特美国航空公司情绪数据库可以从他们的网站下载使用这个链接

解决方案

让我们首先看一下我们将要处理的数据集。原始数据集有以下列:

  • tweet_id
  • airline_sentiment
  • airline_sentiment_confidence
  • negativereason
  • negativereason_confidence
  • 航空公司
  • airline_sentiment_gold
  • 的名字
  • negativereason_gold
  • retweet_count
  • 文本
  • tweet_coord
  • tweet_created
  • tweet_location
  • user_timezone

看起来像下面的例子(可横向滚动的表):

tweet_id airline_sentiment airline_sentiment_confidence negativereason negativereason_confidence 航空公司 airline_sentiment_gold 的名字 negativereason_gold retweet_count 文本 tweet_coord tweet_created tweet_location user_timezone
570306133677760513 中性 1.0 维珍美国航空公司 cairdin 0 @dhepburn说了什么。 2015-02-24 11:35:52 -0800 东部时间(美国和加拿大)
570301130888122368 积极的 0.3486 0.0 维珍美国航空公司 jnardino 0 @维珍美国,再加上你在体验中添加了广告…真俗气。 2015-02-24 11:15:59 -0800 太平洋时间(美国和加拿大)
570301083672813571 中性 0.6837 维珍美国航空公司 yvonnalynn 0 @维珍美国,我今天没有,这一定意味着我需要再旅行一次! 2015-02-24 11:15:48 -0800 让我们玩 中部时间(美国和加拿大)
570301031407624196 1.0 坏的飞行 0.7033 维珍美国航空公司 jnardino 0 “@维珍美国,在你的客人面前播放令人讨厌的”“娱乐”“真的很咄咄逼人,他们几乎没有追索权” 2015-02-24 11:15:36 -0800 太平洋时间(美国和加拿大)
570300817074462722 1.0 不能告诉 1.0 维珍美国航空公司 jnardino 0 @维珍美国,这是一件非常糟糕的事情 2015-02-24 11:14:45 -0800 太平洋时间(美国和加拿大)
570300767074181121 1.0 不能告诉 0.6842 维珍美国航空公司 jnardino 0 “@维珍美国真的会为没有这段视频的座位支付30美元。
这真的是乘坐VA唯一不好的事情。” 2015-02-24 11:14:33 -0800 太平洋时间(美国和加拿大)
570300616901320704 积极的 0.6745 0.0 维珍美国航空公司 cjmcginnis 0 “@VirginAmerica是的 几乎每次我飞VX的时候,这个“耳朵蠕虫”都不会消失:) 2015-02-24 11:13:57 -0800 加州旧金山 太平洋时间(美国和加拿大)
570300248553349120 中性 0.634 维珍美国航空公司 飞行员 0 “@维珍美国真的错过了一个模仿《无头男人》的绝佳机会 在那里。https://t.co/mWpG7grEZP” 2015-02-24 11:12:29 -0800 洛杉矶 太平洋时间(美国和加拿大)

该文件包含14640条推文,所以这是一个不错的数据集。现在,有了当前可用的列的数量,我们有了比我们的例子需要的更多的数据;出于实际目的,我们只关心以下列:

  • 文本
  • airline_sentiment

在哪里文本将成为我们的特色和airline_sentiment成为我们的目标。其余的列可以被丢弃,因为它们不会用于我们的练习。让我们从创建项目开始,并使用以下文件初始化composer:

{" name": "amacgregor/phpml-exercise", "description": "用PHP-ML实现Tweet情感分析的示例","type": "project", "require": {" php-ai/ PHP-ML": "^0.4.1"}, "license": "Apache license 2.0", "authors": [{" name": "Allan MacGregor", "email": "amacgregor@allanmacgregor.com"}], "autoload": {" psr-4": {"PhpmlExercise\\": "src/"}}, "minimum-stability": "dev"}
作曲家安装

如果需要对Composer的介绍,请参见在这里

为了确保设置正确,让我们创建一个快速脚本来加载我们的Tweets.csv数据文件,并确保它有我们需要的数据。将以下代码复制为reviewDataset.php在我们项目的根源:

<?php名称空间PhpmlExercise需要__DIR__“/供应商/ autoload.php”使用Phpml数据集CsvDataset元数据集CsvDataset“数据集/生/ Tweets.csv”,1foreach元数据集->getSamples作为美元的样品{print_r美元的样品}

现在,运行脚本php reviewDataset.php,让我们回顾一下输出:

数组0]= >569587371693355008数组0]= >569587242672398336数组0]= >569587188687634433数组0]= >569587140490866689

这看起来没什么用,不是吗?让我们来看看CsvDataset类来更好地了解内部发生了什么:

<?php公共函数__construct字符串filepath美元,int美元的特性,保龄球headingRow美元真正的{如果file_existsfilepath美元{FileException::missingFilebasenamefilepath美元}如果= = =美元的处理打开外部文件filepath美元,rb的{FileException::cantOpenFilebasenamefilepath美元}如果headingRow美元{元数据:美元的处理,1000,”、“这个美元->columnNamesarray_slice元数据,0,美元的特性}其他的{这个美元->columnNames范围0,美元的特性-1}元数据:美元的处理,1000,”、“= = !{这个美元->样品]array_slice元数据,0,美元的特性这个美元->目标]元数据美元的特性]}文件关闭美元的处理}

CsvDataset构造函数有3个参数:

  • 源CSV的文件路径
  • 指定文件中特性数量的整数
  • 一个布尔值,表示第一行是否是标题

如果我们仔细观察,可以看到类将CSV文件映射到两个内部数组:samples和targets。样品包含文件和提供的所有特性目标包含已知值(负数、正数或中性)。

根据以上,我们可以看到我们的CSV文件需要遵循的格式如下:

| feature_1 | feature_2 | feature_n | target |

我们将需要生成一个干净的数据集,其中只有我们需要继续工作的列。让我们称之为脚本generateCleanDataset.php

<?php名称空间PhpmlExercise需要__DIR__“/供应商/ autoload.php”使用Phpml异常FileExceptionsourceFilepath美元__DIR__' /数据/生/ Tweets.csv 'destinationFilepath美元__DIR__“/数据/ clean_tweets.csv”行美元]行美元getRowssourceFilepath美元,行美元writeRowsdestinationFilepath美元,行美元/ * * *@paramfilepath美元@param行美元@return数组* /函数getRowsfilepath美元,行美元{美元的处理checkFilePermissionsfilepath美元元数据:美元的处理,1000,”、“= = !{行美元]元数据10],元数据1]]}文件关闭美元的处理返回行美元}/ * * *@paramfilepath美元@param字符串美元的模式@return保龄球|资源@throwsFileException* /函数checkFilePermissionsfilepath美元,美元的模式rb的{如果file_existsfilepath美元{FileException::missingFilebasenamefilepath美元}如果= = =美元的处理打开外部文件filepath美元,美元的模式{FileException::cantOpenFilebasenamefilepath美元}返回美元的处理}/ * * *@paramfilepath美元@param行美元@internal参数$list */函数writeRowsfilepath美元,行美元{美元的处理checkFilePermissionsfilepath美元,“白平衡”foreach行美元作为行美元{函数美元的处理,行美元}文件关闭美元的处理}

不要太复杂,只要足够就行了。我们用phpgenerateCleanDataset.php

现在,让我们继续,指向reviewDataset.php脚本返回干净的数据集:

这将是我第三次接到800-433-7300的电话,没人说话我就挂断了。我现在该怎么办??)@AmericanAir AA真是太蠢了。我已经等了2.5周关于取消航班退款的消息&现在已经等待了1小时49分钟)

砰!这是我们可以利用的数据!到目前为止,我们一直在创建简单的脚本来操作数据。下面,我们将开始创建一个新类src /分类/ SentimentAnalysis.php

<?php名称空间PhpmlExercise分类/** *类情感分析*@packagePhpmlExercise分类* /SentimentAnalysis{公共函数火车{}公共函数预测{}}

在我们的情感分析类中,我们的情感类需要两个函数:

  • 一个训练函数,它将使用我们的数据集训练样本和标签以及一些可选参数。
  • 一个预测功能,它将获取一个未标记的数据集,并根据训练数据分配一组标签。

在项目的根目录中创建名为classifyTweets.php.我们将使用他的脚本来实例化和测试我们的情感分析类。下面是我们将使用的模板:

<?php名称空间PhpmlExercise使用PhpmlExercise分类SentimentAnalysis需要__DIR__“/供应商/ autoload.php”//第一步:加载数据集//步骤2:准备数据集//步骤3:生成训练/测试数据集//步骤4:训练分类器//步骤5:测试分类器的准确率

步骤1:加载数据集

我们已经从前面的示例中获得了用于将CSV加载到数据集对象的基本代码。我们将使用相同的代码进行一些调整:

<?php...使用Phpml数据集CsvDataset...元数据集CsvDataset“数据集/ clean_tweets.csv”,1美元的样品]foreach元数据集->getSamples作为美元的样品{美元的样品]美元的样品0]}

这将生成一个只有特征(在本例中是推文文本)的平面数组,我们将使用它来训练分类器。

步骤2:准备数据集

现在,拥有原始文本并将其传递给分类器并不有用或准确,因为每条推文本质上都是不同的。幸运的是,在尝试应用分类或机器学习算法时,有处理文本的方法。在这个例子中,我们将使用以下两个类:

  • 令牌计数矢量器:这将把一个文本样本集合转换为一个标记计数向量。从本质上讲,我们的推文中的每个单词都变成了一个唯一的数字,并跟踪某个单词在特定文本样本中的出现次数。
  • Tf-idf变压器:是词频逆文档频率的缩写,是一种数值统计,旨在反映一个词在集合或语料库中对文档的重要性。

让我们从文本矢量器开始:

<?php...使用PhpmlFeatureExtractionTokenCountVectorizer使用Phpml标记WordTokenizer...vectorizer美元TokenCountVectorizerWordTokenizervectorizer美元->适合美元的样品vectorizer美元->变换美元的样品

接下来,应用Tf-idf转换器:

<?php……使用Phpml \ FeatureExtraction \ TfIdfTransformer;...$tfIdfTransformer = new tfIdfTransformer ();tfIdfTransformer - >适合美元($样本);tfIdfTransformer - >变换(样本);

我们的样本数组现在的格式很容易被我们的分类器理解。我们还没有完成,我们需要用相应的情绪标记每个样本。

步骤3:生成训练数据集

幸运的是,PHP-ML已经满足了这个需求,代码非常简单:

<?php……使用数据集Phpml \ \ ArrayDataset;...$dataset = new ArrayDataset($samples, $dataset->getTargets());

我们可以继续使用这个数据集训练我们的分类器。然而,我们缺少一个用于验证的测试数据集,所以我们将稍微“欺骗”一下,将原始数据集分为两个:一个是训练数据集,另一个是用于测试模型准确性的小得多的数据集。

<?php……使用Phpml \ CrossValidation \ StratifiedRandomSplit;...$randomSplit = new stratifierandomsplit ($dataset, 0.1);$trainingSamples = $randomSplit->getTrainSamples();$trainingLabels = $randomSplit->getTrainLabels();$testSamples = $randomSplit->getTestSamples();$testLabels = $randomSplit->getTestLabels();

这种方法被称为交叉验证。这个术语来源于统计学,可以定义如下:

交叉验证,有时也称为旋转估计,是一种模型验证技术,用于评估统计分析的结果如何推广到一个独立的数据集。它主要用于目标是预测的设置,并且人们想要估计预测模型在实践中的表现有多准确。- - - - - -Wikipedia.com

步骤4:训练分类器

最后,我们准备返回并实现我们的SentimentAnalysis类。如果你现在还没有注意到,机器学习的很大一部分是关于收集和操作数据;机器学习模型的实际实现往往不那么复杂。

为了实现我们的情感分析类,我们有三个可用的分类算法:

  • 支持向量分类
  • KNearestNeighbors
  • NaiveBayes

在这个练习中,我们将使用其中最简单的,朴素贝叶斯分类器,所以让我们继续更新我们的类来实现train方法:

<?php名称空间PhpmlExercise分类使用Phpml分类NaiveBayesSentimentAnalysis{受保护的美元的分类器公共函数__construct{这个美元->分类器NaiveBayes}公共函数火车美元的样品,美元的标签{这个美元->分类器->火车美元的样品,美元的标签}}

正如您所看到的,我们让PHP-ML为我们做了所有繁重的工作。我们只是为我们的项目创建一个漂亮的小抽象。但是我们怎么知道我们的分类器是否真的在训练和工作呢?是时候使用我们的testsample而且testLabels

步骤5:测试分类器的准确性

在继续测试分类器之前,我们必须实现预测方法:

<?php...SentimentAnalysis{...公共函数预测美元的样品{返回这个美元->分类器->预测美元的样品}}

再一次,PHP-ML帮了我们一个大忙,为我们做了所有繁重的工作。让我们更新classifyTweets相应的类:

<?php...predictedLabels美元美元的分类器->预测testsample美元

最后,我们需要一种方法来测试我们训练过的模型的准确性;谢天谢地,PHP-ML也涵盖了这一点,并且它们有几个度量类。在我们的例子中,我们感兴趣的是模型的准确性。让我们看一下代码:

<?php...使用Phpml度规精度...回声的准确性:精度::分数testLabels美元,predictedLabels美元

我们应该看到如下内容:

精度0.73651877133106

结论

这篇文章有点冗长,所以让我们来回顾一下到目前为止我们学到了什么:

  • 从一开始就拥有一个好的数据集对于实现机器学习算法至关重要。
  • 监督学习和无监督学习的区别。
  • 交叉验证在机器学习中的意义和应用。
  • 这种向量化和转换对于为机器学习准备文本数据集至关重要。
  • 如何使用PHP-ML的NaiveBayes分类器实现Twitter情绪分析。

这篇文章还介绍了PHP-ML库,希望能让您了解这个库可以做什么,以及如何将它嵌入到您自己的项目中。

最后,这篇文章绝不是全面的,有很多东西需要学习、改进和实验;下面是一些建议,可以帮助你开始进一步改善工作:

  • 将朴素贝叶斯算法替换为支持向量分类算法。
  • 如果您尝试对整个数据集(14,000行)运行,您可能会注意到该进程的内存占用有多大。尝试实现模型持久性,这样就不必在每次运行时都进行训练。
  • 将数据集生成移动到它自己的助手类。

我希望这篇文章对您有用。如果你有一些关于PHP-ML的应用想法或任何问题,不要犹豫,把它们放在下面的评论区!

Baidu