本文经Wern Ancheta同行评审。感谢所有SitePoint的同行评审员,使SitePoint的内容达到最佳状态!
最近,似乎每个人都在谈论机器学习。你的社交媒体信息流充斥着关于ML、Python、TensorFlow、Spark、Scala、Go等等的帖子;如果你像我一样,你可能会想知道,PHP呢?
是的,机器学习和PHP呢?幸运的是,有人疯狂地不仅提出了这个问题,而且还开发了一个通用的机器学习库,我们可以在下一个项目中使用它。在这篇文章中,我们将看看PHP-ML——一个用于PHP的机器学习库——我们将编写一个情感分析类,稍后可以将其重用于我们自己的聊天机器人或推特机器人。这篇文章的主要目标是:
阅读更好的PHP开发工具和技术,使你成为更好的开发者!阅读此书 阅读此书!
机器学习是人工智能的一个子集,它专注于赋予“计算机无需明确编程即可学习的能力”。这是通过使用可以从特定数据集“学习”的通用算法来实现的。
例如,机器学习的一个常见用途是分类。分类算法用于将数据分成不同的组或类别。分类应用程序的一些示例包括:
机器学习是一个涵盖许多不同任务的通用算法的总称,并且根据学习方式主要分为两种算法类型——监督学习和无监督学习。
在监督学习中,我们使用标记数据来训练我们的算法,标记数据采用输入对象(向量)和所需输出值的格式;算法分析训练数据并产生所谓的推断函数,我们可以将其应用于新的未标记数据集。
在本帖的其余部分,我们将重点关注监督学习,因为它更容易看到和验证关系;请记住,这两种算法同样重要且有趣;有人可能会认为无监督学习更有用,因为它排除了标记数据的需求。
另一方面,这种类型的学习从一开始就使用未标记的数据。我们不知道数据集的所需输出值,我们让算法从数据集中得出推论;无监督学习在进行探索性数据分析以查找数据中的隐藏模式时特别方便。
认识PHP-ML,一个声称是PHP机器学习新方法的库。该库实现了算法、神经网络和工具,用于进行数据预处理、交叉验证和特征提取。
我首先承认,PHP是机器学习的不寻常选择,因为该语言的优势并不太适合机器学习应用程序。也就是说,并非每个机器学习应用程序都需要处理PB级数据并进行大量计算——对于简单的应用程序,我们应该能够使用PHP和PHP-ML。
我现在能看到的这个库最好的用例是分类器的实现,无论是垃圾邮件过滤器还是情感分析。我们将定义一个分类问题,并逐步构建解决方案,以了解如何在我们的项目中使用PHP-ML。
为了举例说明实现PHP-ML并将一些机器学习添加到我们的应用程序中的过程,我想找到一个有趣的问题来解决,还有什么比构建一个推特情感分析类更好的方法来展示分类器呢?
构建成功的机器学习项目所需的关键要求之一是良好的起始数据集。数据集至关重要,因为它们将允许我们针对已分类的示例训练我们的分类器。由于媒体最近围绕航空公司出现了大量噪音,还有什么比使用客户对航空公司的推文更好的数据集呢?
幸运的是,由于Kaggle.io,我们已经可以使用推文数据集。可以使用此链接从其网站下载Twitter美国航空公司情绪数据库
让我们首先看看我们将要处理的数据集。原始数据集包含以下列:
并且看起来像下面的例子(可侧向滚动的表格):
tweet_id
airline_sentiment
airline_sentiment_confidence
negativereason
negativereason_confidence
airline
airline_sentiment_gold
name
negativereason_gold
retweet_count
text
tweet_coord
tweet_created
tweet_location
user_timezone
570306133677760513 neutral 1.0 Virgin America cairdin 0 @VirginAmerica What @dhepburn said. 2015-02-24 11:35:52 -0800 Eastern Time (US & Canada) 570301130888122368 positive 0.3486 0.0 Virgin America jnardino 0 @VirginAmerica plus you’ve added commercials to the experience… tacky. 2015-02-24 11:15:59 -0800 Pacific Time (US & Canada) 570301083672813571 neutral 0.6837 Virgin America yvonnalynn 0 @VirginAmerica I didn’t today… Must mean I need to take another trip! 2015-02-24 11:15:48 -0800 Lets Play Central Time (US & Canada) 570301031407624196 negative 1.0 Bad Flight 0.7033 Virgin America jnardino 0 “@VirginAmerica it’s really aggressive to blast obnoxious “”entertainment”” in your guests’ faces & they have little recourse” 2015-02-24 11:15:36 -0800 Pacific Time (US & Canada) 570300817074462722 negative 1.0 Can’t Tell 1.0 Virgin America jnardino 0 @VirginAmerica and it’s a really big bad thing about it 2015-02-24 11:14:45 -0800 Pacific Time (US & Canada) 570300767074181121 negative 1.0 Can’t Tell 0.6842 Virgin America jnardino 0 “@VirginAmerica seriously would pay $30 a flight for seats that didn’t have this playing. it’s really the only bad thing about flying VA” 2015-02-24 11:14:33 -0800 Pacific Time (US & Canada) 570300616901320704 positive 0.6745 0.0 Virgin America cjmcginnis 0 “@VirginAmerica yes nearly every time I fly VX this “ear worm” won’t go away :)” 2015-02-24 11:13:57 -0800 San Francisco CA Pacific Time (US & Canada) 570300248553349120 neutral 0.634 Virgin America pilot 0 “@VirginAmerica Really missed a prime opportunity for Men Without Hats parody there. https://www.php.cn/link/76379ed89eafe43c8f6bd64fd09e3852” 2015-02-24 11:12:29 -0800 Los Angeles Pacific Time (US & Canada) 该文件包含14,640条推文,因此对于我们来说是一个不错的工作数据集。现在,使用我们当前可用的列数,我们拥有比示例所需更多的数据;出于实际目的,我们只关心以下列:
其中text将成为我们的特征,airline_sentiment将成为我们的目标。其余列可以丢弃,因为它们不会用于我们的练习。让我们从创建项目开始,并使用以下文件初始化composer:
<code>{ "name": "amacgregor/phpml-exercise", "description": "Example implementation of a Tweet sentiment analysis with PHP-ML", "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" }</code>
<code>composer install </code>
如果您需要 Composer 入门介绍,请参见此处。
为了确保我们正确设置,让我们创建一个快速脚本,它将加载我们的Tweets.csv数据文件并确保它具有我们需要的数据。将以下代码复制为项目根目录中的reviewDataset.php:
<?php namespace PhpmlExercise; require __DIR__ . '/vendor/autoload.php'; use Phpml\Dataset\CsvDataset; $dataset = new CsvDataset('datasets/raw/Tweets.csv',1); foreach ($dataset->getSamples() as $sample) { print_r($sample); }
现在,使用php reviewDataset.php运行脚本,让我们查看输出:
<code>Array( [0] => 569587371693355008 ) Array( [0] => 569587242672398336 ) Array( [0] => 569587188687634433 ) Array( [0] => 569587140490866689 ) </code>
现在这看起来没用,不是吗?让我们看看CsvDataset类,以便更好地了解内部发生的情况:
<?php public function __construct(string $filepath, int $features, bool $headingRow = true) { if (!file_exists($filepath)) { throw FileException::missingFile(basename($filepath)); } if (false === $handle = fopen($filepath, 'rb')) { throw FileException::cantOpenFile(basename($filepath)); } if ($headingRow) { $data = fgetcsv($handle, 1000, ','); $this->columnNames = array_slice($data, 0, $features); } else { $this->columnNames = range(0, $features - 1); } while (($data = fgetcsv($handle, 1000, ',')) !== false) { $this->samples[] = array_slice($data, 0, $features); $this->targets[] = $data[$features]; } fclose($handle); }
CsvDataset构造函数采用3个参数:
如果我们仔细观察,我们可以看到该类正在将CSV文件映射到两个内部数组:samples和targets。Samples包含文件提供的所有特征,而targets包含已知值(负、正或中性)。
基于上述内容,我们可以看到我们的CSV文件需要遵循的格式如下:
<code>| feature_1 | feature_2 | feature_n | target | </code>
我们将需要生成一个干净的数据集,其中只包含我们需要继续工作的列。让我们将此脚本称为generateCleanDataset.php:
<?php namespace PhpmlExercise; require __DIR__ . '/vendor/autoload.php'; use Phpml\Exception\FileException; $sourceFilepath = __DIR__ . '/datasets/raw/Tweets.csv'; $destinationFilepath = __DIR__ . '/datasets/clean_tweets.csv'; $rows =[]; $rows = getRows($sourceFilepath, $rows); writeRows($destinationFilepath, $rows); /** * @param $filepath * @param $rows * @return array */ function getRows($filepath, $rows) { $handle = checkFilePermissions($filepath); while (($data = fgetcsv($handle, 1000, ',')) !== false) { $rows[] = [$data[10], $data[1]]; } fclose($handle); return $rows; } /** * @param $filepath * @param string $mode * @return bool|resource * @throws FileException */ function checkFilePermissions($filepath, $mode = 'rb') { if (!file_exists($filepath)) { throw FileException::missingFile(basename($filepath)); } if (false === $handle = fopen($filepath, $mode)) { throw FileException::cantOpenFile(basename($filepath)); } return $handle; } /** * @param $filepath * @param $rows * @internal param $list */ function writeRows($filepath, $rows) { $handle = checkFilePermissions($filepath, 'wb'); foreach ($rows as $row) { fputcsv($handle, $row); } fclose($handle); }
没有什么太复杂的,只是足以完成这项工作。让我们用php generateCleanDataset.php执行它。
现在,让我们将reviewDataset.php脚本指向干净的数据集:
<code>Array ( [0] => @AmericanAir That will be the third time I have been called by 800-433-7300 an hung on before anyone speaks. What do I do now??? ) Array ( [0] => @AmericanAir How clueless is AA. Been waiting to hear for 2.5 weeks about a refund from a Cancelled Flightled flight & been on hold now for 1hr 49min )</code>
BAM!这是我们可以使用的数据!到目前为止,我们一直在创建用于操作数据的简单脚本。接下来,我们将开始在src/classification/SentimentAnalysis.php下创建一个新类。
<?php namespace PhpmlExercise\Classification; /** * Class SentimentAnalysis * @package PhpmlExercise\Classification */ class SentimentAnalysis { public function train() {} public function predict() {} }
我们的情感类将需要在我们的情感分析类中使用两个函数:
在项目的根目录中创建一个名为classifyTweets.php的脚本。我们将使用此脚本来实例化和测试我们的情感分析类。这是我们将使用的模板:
<?php namespace PhpmlExercise; use PhpmlExercise\Classification\SentimentAnalysis; require __DIR__ . '/vendor/autoload.php'; // 步骤 1:加载数据集 // 步骤 2:准备数据集 // 步骤 3:生成训练/测试数据集 // 步骤 4:训练分类器 // 步骤 5:测试分类器的准确性
我们已经拥有可以用于将CSV加载到我们早期示例中的数据集对象的代码。我们将使用相同的代码并进行一些调整:
<?php ... use Phpml\Dataset\CsvDataset; ... $dataset = new CsvDataset('datasets/clean_tweets.csv',1); $samples = []; foreach ($dataset->getSamples() as $sample) { $samples[] = $sample[0]; }
这将生成一个仅包含特征(在本例中为推文文本)的扁平数组,我们将使用它来训练我们的分类器。
现在,拥有原始文本并将该文本传递给分类器将不会有用或准确,因为每条推文本质上都是不同的。幸运的是,在尝试应用分类或机器学习算法时,有一些方法可以处理文本。对于此示例,我们将使用以下两个类:
让我们从文本向量化器开始:
<code>{ "name": "amacgregor/phpml-exercise", "description": "Example implementation of a Tweet sentiment analysis with PHP-ML", "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" }</code>
接下来,应用Tf-idf转换器:
<code>composer install </code>
我们的samples数组现在采用了一种格式,可以很容易地被我们的分类器理解。我们还没完成,我们需要用其相应的情绪标记每个样本。
幸运的是,PHP-ML已经涵盖了这个需求,代码非常简单:
<?php namespace PhpmlExercise; require __DIR__ . '/vendor/autoload.php'; use Phpml\Dataset\CsvDataset; $dataset = new CsvDataset('datasets/raw/Tweets.csv',1); foreach ($dataset->getSamples() as $sample) { print_r($sample); }
我们可以继续使用此数据集并训练我们的分类器。但是,我们缺少用作验证的测试数据集,因此我们将“作弊”一点,并将我们的原始数据集分成两部分:一个训练数据集和一个用于测试模型准确性的更小得多的数据集。
<code>Array( [0] => 569587371693355008 ) Array( [0] => 569587242672398336 ) Array( [0] => 569587188687634433 ) Array( [0] => 569587140490866689 ) </code>
这种方法称为交叉验证。该术语来自统计学,可以定义如下:
交叉验证,有时称为旋转估计,是一种模型验证技术,用于评估统计分析的结果将如何推广到独立数据集。它主要用于预测的目标设置,并且想要估计预测模型在实践中的准确性。— Wikipedia.com
最后,我们准备返回并实现SentimentAnalysis类。如果你现在还没注意到,机器学习的很大一部分是关于收集和操作数据;机器学习模型的实际实现往往涉及较少的内容。
为了实现我们的情感分析类,我们有三种可用的分类算法:
对于此练习,我们将使用最简单的一种,即朴素贝叶斯分类器,因此让我们继续更新我们的类以实现train方法:
<?php public function __construct(string $filepath, int $features, bool $headingRow = true) { if (!file_exists($filepath)) { throw FileException::missingFile(basename($filepath)); } if (false === $handle = fopen($filepath, 'rb')) { throw FileException::cantOpenFile(basename($filepath)); } if ($headingRow) { $data = fgetcsv($handle, 1000, ','); $this->columnNames = array_slice($data, 0, $features); } else { $this->columnNames = range(0, $features - 1); } while (($data = fgetcsv($handle, 1000, ',')) !== false) { $this->samples[] = array_slice($data, 0, $features); $this->targets[] = $data[$features]; } fclose($handle); }
如你所见,我们让PHP-ML为我们完成所有繁重的工作。我们只是为我们的项目创建了一个很好的抽象。但是我们如何知道我们的分类器是否真的在训练和工作呢?是时候使用我们的testSamples和testLabels了。
在我们继续测试我们的分类器之前,我们确实必须实现预测方法:
<code>{ "name": "amacgregor/phpml-exercise", "description": "Example implementation of a Tweet sentiment analysis with PHP-ML", "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" }</code>
同样,PHP-ML为我们提供了帮助,并为我们完成了所有繁重的工作。让我们相应地更新classifyTweets类:
<code>composer install </code>
最后,我们需要一种方法来测试我们训练模型的准确性;谢天谢地,PHP-ML也涵盖了这一点,并且他们有几个指标类。在我们的例子中,我们对模型的准确性感兴趣。让我们看看代码:
<?php namespace PhpmlExercise; require __DIR__ . '/vendor/autoload.php'; use Phpml\Dataset\CsvDataset; $dataset = new CsvDataset('datasets/raw/Tweets.csv',1); foreach ($dataset->getSamples() as $sample) { print_r($sample); }
我们应该看到类似以下内容:
<code>Array( [0] => 569587371693355008 ) Array( [0] => 569587242672398336 ) Array( [0] => 569587188687634433 ) Array( [0] => 569587140490866689 ) </code>
这篇文章有点长,所以让我们回顾一下到目前为止我们学到了什么:
这篇文章也作为PHP-ML库的介绍,并希望让你对该库的功能以及如何在自己的项目中嵌入它有一个很好的了解。
最后,这篇文章绝非全面,还有很多需要学习、改进和实验的地方;以下是一些想法,可以帮助你进一步改进:
我希望你发现这篇文章有用。如果你有一些关于PHP-ML的应用程序想法或任何问题,请随时在下面的评论区中提出!
提高情感分析的准确性涉及多种策略。首先,确保你的训练数据尽可能干净和相关。这意味着删除任何不相关的数据,例如停用词、标点符号和URL。其次,考虑使用更复杂的算法。虽然朴素贝叶斯分类器是一个很好的起点,但其他算法(如支持向量机 (SVM) 或深度学习模型)可能会提供更好的结果。最后,考虑使用更大的数据集进行训练。你的模型可以学习的数据越多,它就越准确。
是的,你可以使用其他编程语言进行情感分析。例如,Python 因其广泛的机器学习库(如NLTK、TextBlob和scikit-learn)而成为一种流行的选择。但是,PHP也可以有效地用于情感分析,特别是如果你已经熟悉该语言或你的项目是基于PHP框架构建的。
处理情感分析中的讽刺和反语是一项具有挑战性的任务。这些语言特征通常涉及说某事但意味着相反的意思,这对于机器学习模型来说很难理解。一种方法是使用可以理解上下文的更复杂的模型,例如深度学习模型。另一种方法是使用专门的讽刺检测模型,该模型可以使用讽刺评论的数据集进行训练。
情感分析的原理可以应用于任何文本数据,包括来自其他社交媒体平台的帖子。主要区别在于你如何收集数据。每个社交媒体平台都有自己的API用于访问用户帖子,因此你需要熟悉你感兴趣的平台的API。
是的,情感分析可以用于任何语言。但是,分析的有效性将取决于你的训练数据的质量。如果你使用的是英语以外的语言,则需要使用该语言的数据集来训练你的模型。一些机器学习库也直接支持多种语言。
有很多方法可以可视化情感分析结果。一种常见的方法是使用条形图来显示正面、负面和中性推文的数量。另一种方法是使用词云来可视化数据中最常用的词。PHP有几个用于创建这些可视化的库,例如pChart和GD。
情感分析有很多实际应用。企业可以使用它来监控客户对其产品或服务的意见,政治家可以使用它来衡量公众对政策问题的意见,研究人员可以使用它来研究社会趋势。可能性是无限的。
表情符号可以携带重要的情感信息,因此将它们包含在你的分析中很重要。一种方法是在将数据输入模型之前,将每个表情符号替换为其文本描述。有一些库可以帮助你做到这一点,例如PHP的Emojione。
拼写错误在情感分析中可能是一个挑战。一种方法是在将数据输入模型之前使用拼写检查器来更正错误。另一种方法是使用可以处理拼写错误的模型,例如深度学习模型。
保持你的情感分析模型最新涉及定期使用新数据对其进行再训练。这确保你的模型与语言使用和情感的变化保持同步。你可以通过设置一个重新训练模型的计划来自动化此过程。
以上是如何分析PHP机器学习的推文观点的详细内容。更多信息请关注PHP中文网其他相关文章!