名称唯一性
你的名字有多独特?
有了像我这样的名字,关于名字的话题就出现了很多。幸运的是,我非常喜欢我的名字和它在美国的独特性。不管魔鬼经济学家怎么说,我愿意相信我名字的独特性对我的生活有所帮助,或者至少让它变得更有趣。
为了量化我的名字有多独特,我发现在我出生的那一年,我是美国一个由 101 个名叫简的男孩组成的俱乐部的成员。简单的说,我的名字在那一年出生的所有男婴中不到 0.005%是很不常见的。到目前为止,我还没有见过其他 100 个难以捉摸的简中的一个。
我从 www.ssa.gov社会安全管理局(SSA)网站的美国婴儿名字数据集中找到了这个数据。虽然他们有一些很好的视图(比如某个时期最受欢迎的名字)来找到上面的统计数据,但我需要下载数据并自己使用它。我把它上传到 Tableau,发现自己发现了许多比自己更有趣的名字和趋势。
数据
在开始可视化之前,确保理解数据是如何生成的总是明智的。在阅读了 SSA 文档并发现数据集故意排除了一些出生数据后,我找到了第二个数据来源。将美国的总出生人数(下面的棕色线)与婴儿名字数据集(下面的灰色线)中的每年出生人数进行比较,我可以想象出有多少数据丢失了。
SSA 的文件解释说,许多 1937 年以前出生的人从未申请过社会保障卡,所以他们的名字不包括在婴儿姓名数据集中。这解释了我们在这个日期之前看到的两条线之间的巨大但正在缩小的差异。(接下来,我们将删除这些不完整的数据。)
Visualization 1: Total Births
近年来,这两条线之间的差异越来越大。文档再次告诉我们,出于匿名的原因,任何在给定年份出现少于 5 次的名字都不会被记录。所以,这个差距实际上告诉我们出生时有非常独特的名字(< 5 次)的数量,并表明最近每年比几十年前有更多非常独特的名字。
这引起了我的好奇心,我决定随着时间的推移深入研究名称唯一性和名称通用性的想法。
名称唯一性
当我们观察任何一年中唯一名字的数量(出现 5 次或更多次)时,我们会发现几十年来有很大的变化。下图显示了 20 世纪 40 年代不到 10000 个唯一名称,到 2000 年代增加了两倍多,达到 30000 个。此外,女婴的名字总是比男婴的名字更多样化。
Visualization 2: Unique Names
穿越时间到 20 世纪 60 年代末,我们开始看到独特名字的数量在加速增长,并持续到新千年的开始。20 世纪 60 年代中期标志着婴儿潮一代的结束和 X 一代的开始,虽然美国历史不是我的强项,但我假设当时的大文化转变(部分原因是越战、非裔美国人民权运动、英国入侵等)。)在我们看到的趋势中扮演了一个因素。
继续我们的时间之旅,我们开始看到这种加速在 2000 年代后期逆转。这一次,一代人的转变与我们在图中看到的趋势并不完全一致。维基百科将千禧一代(又名 Y 代)的终结时间定在 20 世纪 90 年代中期至 21 世纪初。这种转变正好发生在一些唯一名称增长最快的地方。当我们看到下降趋势时,我们已经进入 z 世代了。
宏观下降趋势似乎是由独特的女孩名字的减少所驱动的(因为男孩名字持平/略有下降)。很难说为什么会发生这种逆转,我也没有一个很好的假设来解释为什么会这样。根据我的挖掘,以下假设不太可能是原因。
- 假设 1:与男婴相比,父母给女婴起的独特名字越来越少。不太可能。当研究数据时,在 2010 年代首次使用(或产生)的新的独特名字的百分比代表了 2010 年代男女所有独特名字的 20%。男孩和女孩之间几乎没有差别,这不太可能导致我们上面看到的只生女孩的趋势。
Visualization 3: Unique name distribution by origin decade
- **假设 2:女孩非常独特的名字(<每年出生 5 个)比男孩增加得多,从而弥补了我们可以测量的独特女孩名字减少的趋势。**不太可能。虽然我们无法确定这一点,因为我们无法获得这些数据,但鉴于我们拥有的数据,我们可以提出强有力的理由。下图显示了用独特性桶着色的十年间的增长情况(51-500 独特性桶中的一个名字在该十年中有 51-500 个同名新生儿)。在最近十年中,所有独特性存储桶都以类似的负速率增长,因此,很可能,我们无法衡量的非常独特的存储桶也将以类似的负速率增长(而不是正速率)。最重要的是,我们可以测量的非常独特的名字的数量(第一桶:< 50 个)是男孩的,而不是女孩的。
Visualization 4: “Uniqueness” growth — note that 2010 is not a full decade
虽然我们仍然没有一个很好的假设来解释为什么女婴名字的独特性在几十年来首次下降,但男婴名字的独特性似乎仍在增加——只是速度比以前小。如果你有另一个假设,请在回答中分享(如果你用这个数据集或其他地方的证据支持它,会加分)。
顺便提一下,上图中 20 世纪 70 年代相当有趣的趋势与我们在可视化 1 中看到的增长趋势一致,并为正在发生的事情增添了色彩。随着所有其他存储桶开始加速增长,代表超过 1 万个出生的名称的唯一性开始下降。名字越独特,成长越大。
名称通用性
虽然这些年来我们通过观察名字的独特性学到了很多,但我们忽略了一些非常重要的东西:出生的分布。
这种分布是很重要的,因为如果没有它,我们就不能确定大多数新生儿是只集中在一小部分独特的名字上,还是均匀分布在所有的名字上。快速猜一下是哪一个。
利用帕累托原则(或更广为人知的 80/20 法则),让我们看看最常见的名字有多少出生。简单地说,80/20 法则认为 80%的结果可以归因于 20%的原因。如果这在名字世界中成立,我们应该会发现,20 世纪 40 年代的大约 200 个名字和 21 世纪初的大约 600 个名字应该占出生人数的大约 80%(见我们在第一部分的学习)。
当计算这些数字时,我们发现 20 世纪 40 年代 20%的独特名字占出生人数的 64 %, 2000 年代占 60%。虽然我们没有达到神话中的 80/20 的比例,但这个理论仍然成立,即名字的一小部分促成了许多出生。下图显示了前 100 个最常见的名字在一段时间内的贡献,但是是按性别划分的。
Visualization 5: Contribution of the top 100 names
我们看到男婴的名字比女婴的名字更常见(在 1947 年的高峰期为 78%到 70%)。根据我们之前的发现,这并不奇怪——男孩的名字不那么独特,普通的名字比女孩的名字更受欢迎。
20 世纪 40 年代末,名字的普通性开始减少。女婴的死亡率非常高,而男婴的死亡率则逐渐下降。到 2010 年,我们看到前 100 个男孩和女孩的名字分别只占 11%和 5%。对于男孩来说,这个比例从排名前 100 名的婴儿中的五分之四下降到十分之一。
Visualization 6: Contribution of the top 5 names
看看 1947 年的顶级名字,23%的男婴被命名为詹姆斯、罗伯特、约翰、威廉或理查德。然而,排名前五的女孩名字(见下文)仅占所有女婴出生的 17%。对于女孩来说,名字的共性下降得如此之快,以至于在 1975 年,排名前五的女孩名字只占 2%,而男孩的这一比例仍然是 10%。
Visualization 7: Top 10 — # births in 1947
随着时间的推移,看看这些名字,我们看到其中许多在 1947 年达到顶峰,即婴儿潮一代的开始。看看琳达!这个名字在不到十年的时间里非常流行,然后迅速急剧下降。虽然琳达的变化是最引人注目的,但这些名字中的许多如今远不如婴儿潮一代受欢迎。
Visualization 8: Names over generations — Want to type in your name? Click here
是什么影响了这些尖峰信号?现在流行什么名字?最近有没有什么旧名死灰复燃?如果你想研究这些问题或想发现自己的趋势,请查看这个 Tableau 仪表盘,在这里你可以用任何你喜欢的名字来重现上述情节——你的名字,你妈妈的名字,甚至你的英雄的名字。
感谢阅读。👶
更新:如果你有兴趣阅读更多关于婴儿名字数据集的有趣趋势,请查看这篇后续报道,在这篇报道中,我用这些数据展示了一个初创企业或商业的衡量框架。
纳米神经元——解释机器如何学习的 7 个简单 JS 函数
7 个简单的 JavaScript 函数,让你感受一下机器是如何“学习”的。
Image by mohamed_hassan on pixabay
TL;速度三角形定位法(dead reckoning)
纳米神经元是神经网络中神经元概念的过度简化版本。纳米神经元被训练成将温度值从摄氏温度转换成华氏温度。
NanoNeuron.js 代码示例包含 7 个简单的 JavaScript 函数(模型预测、成本计算、向前和向后传播、训练),这些函数将让您感受到机器实际上是如何“学习”的。没有第三方库,没有外部数据集和依赖,只有纯粹简单的 JavaScript 函数。
☝🏻这些函数无论如何都不是机器学习的完整指南。很多机器学习的概念在那里被跳过,被过度简化!这种简化的目的是让读者对机器如何学习有一个真正基本的理解和感受,并最终使读者有可能称之为“机器学习魔法”而不是“机器学习数学”🤓。
对于更高级的机器学习示例(在 TensorFlow 和 Python 上实现递归和卷积神经网络),您可以继续🤖 交互式机器学习实验 s 知识库。
纳米神经元会学习什么
你可能在神经网络中听说过神经元。我们下面要实现的纳米神经元有点像它,但简单得多。为了简单起见,我们甚至不打算在纳米神经元上建立网络。我们将独自拥有它,为我们做一些神奇的预测。也就是说,我们将教会这个简单的纳米神经元将温度从摄氏温度转换(预测)为华氏温度。
顺便说一下,把摄氏温度转换成华氏温度的公式是这样的:
但是现在我们的纳米神经元还不知道它…
纳米神经元模型
让我们实现我们的纳米神经元模型函数。它实现了x
和y
之间的基本线性依赖,看起来像y = w * x + b
。简单的说我们的纳米神经元就是一个可以在XY
坐标中画直线的“小孩”。
变量w
、b
是模型的参数。纳米神经元只知道线性函数的这两个参数。
这些参数是纳米神经元在训练过程中将要“学习”的东西。
纳米神经元唯一能做的就是模仿线性依赖。在其predict()
方法中,它接受一些输入x
并预测输出y
。这里没有魔法。
function **NanoNeuron**(w, b) {
this.w = w;
this.b = b;
this.predict = (x) => {
return x * this.w + this.b;
}
}
(…等等… 线性回归 是你吗?) 🧐
摄氏到华氏的转换
以摄氏度为单位的温度值可以使用以下公式转换为华氏温度:f = 1.8 * c + 32
,其中c
是以摄氏度为单位的温度,f
是以华氏温度为单位的计算温度。
function **celsiusToFahrenheit**(c) {
const w = 1.8;
const b = 32;
const f = c * w + b;
return f;
};
最终,我们希望教会我们纳米神经元模仿这一功能(学习w = 1.8
和b = 32
),而无需事先知道这些参数。
这是摄氏到华氏转换函数的样子:
Celsius to Fahrenheit conversion function
生成数据集
在训练之前,我们需要基于celsiusToFahrenheit()
函数生成训练和测试数据集。数据集由成对的输入值和正确标记的输出值组成。
在现实生活中,大多数情况下,这些数据是收集的,而不是生成的。例如,我们可能有一组手绘数字图像和一组相应的数字,这些数字解释了每张图片上写的是什么数字。
我们将使用训练样本数据来训练我们的纳米神经元。在我们的纳米神经元成长并能够自己做出决定之前,我们需要用训练样本教会它什么是对的,什么是错的。
我们将使用测试示例来评估我们的纳米神经元在训练期间没有看到的数据上的表现。在这一点上,我们可以看到我们的“孩子”已经长大,可以自己做决定了。
function **generateDataSets**() {
// xTrain -> [0, 1, 2, ...],
// yTrain -> [32, 33.8, 35.6, ...]
const xTrain = [];
const yTrain = [];
for (let x = 0; x < 100; x += 1) {
const y = celsiusToFahrenheit(x);
xTrain.push(x);
yTrain.push(y);
} // xTest -> [0.5, 1.5, 2.5, ...]
// yTest -> [32.9, 34.7, 36.5, ...]
const xTest = [];
const yTest = [];
// By starting from 0.5 and using the same step of 1 as we have used for training set
// we make sure that test set has different data comparing to training set.
for (let x = 0.5; x < 100; x += 1) {
const y = celsiusToFahrenheit(x);
xTest.push(x);
yTest.push(y);
} return [xTrain, yTrain, xTest, yTest];
}
预测的成本(误差)
我们需要一些指标来显示我们的模型预测与正确值的接近程度。纳米神经元产生的正确输出值y
和prediction
之间的成本(误差)的计算将使用以下公式:
这是两个值的简单区别。数值越接近,差异越小。我们在这里使用2
的能力只是为了去掉负数,这样(1 - 2) ^ 2
就和(2 - 1) ^ 2
一样了。除以2
只是为了进一步简化反向传播公式(见下文)。
这种情况下的成本函数非常简单:
function **predictionCost**(y, prediction) {
return (y - prediction) ** 2 / 2; // i.e. -> 235.6
}
正向传播
进行前向传播意味着对来自xTrain
和yTrain
数据集的所有训练样本进行预测,并计算这些预测的平均成本。
我们只是让我们的纳米神经元说出它在这一点上的意见,只是让他猜一猜如何换算温度。这可能是愚蠢的错误。平均成本将显示我们的模型现在是多么的错误。这个成本值非常有价值,因为通过改变纳米神经元参数w
和b
并再次进行正向传播,我们将能够评估纳米神经元在参数改变后是否变得更聪明。
将使用以下公式计算平均成本:
其中m
是训练示例的数量(在我们的例子中是100
)。
下面是我们如何用代码实现它:
function **forwardPropagation**(model, xTrain, yTrain) {
const m = xTrain.length;
const predictions = [];
let cost = 0;
for (let i = 0; i < m; i += 1) {
const prediction = nanoNeuron.predict(xTrain[i]);
cost += predictionCost(yTrain[i], prediction);
predictions.push(prediction);
}
// We are interested in average cost.
cost /= m;
return [predictions, cost];
}
反向传播
现在,当我们知道纳米神经元的预测有多正确或错误(基于此时的平均成本)时,我们应该做些什么来使预测更精确呢?
反向传播是这个问题的答案。反向传播是评估预测成本和调整纳米神经元参数w
和b
的过程,以便下一次预测更加精确。
这就是机器学习看起来像魔法🧞♂️.的地方这里的关键概念是导数,它显示了采取什么步骤来接近成本函数最小值。
记住,找到一个成本函数的最小值是训练过程的最终目标。如果我们会发现w
和b
的值使得我们的平均成本函数很小,这将意味着纳米神经元模型做了非常好和精确的预测。
衍生品是一个独立的大话题,我们不会在本文中讨论。MathIsFun 是一个很好的资源,可以让你对它有一个基本的了解。
关于导数,有一点可以帮助你理解反向传播是如何工作的,那就是导数的含义是函数曲线的切线,它指出了函数最小值的方向。
图片来源: 马蒂斯芬
例如,在上面的图中,你可以看到,如果我们在(x=2, y=4)
点,那么斜率告诉我们走left
和down
到达函数最小值。还要注意,斜率越大,我们向最小值移动的速度越快。
我们的averageCost
函数对参数w
和b
的导数如下所示:
其中m
是一些训练例子(在我们的例子中是100
)。
你可以在这里 阅读更多关于导数规则以及如何得到复杂函数的导数 。
function **backwardPropagation**(predictions, xTrain, yTrain) {
const m = xTrain.length;
// At the beginning we don't know in which way our parameters 'w' and 'b' need to be changed.
// Therefore we're setting up the changing steps for each parameters to 0.
let dW = 0;
let dB = 0;
for (let i = 0; i < m; i += 1) {
dW += (yTrain[i] - predictions[i]) * xTrain[i];
dB += yTrain[i] - predictions[i];
}
// We're interested in average deltas for each params.
dW /= m;
dB /= m;
return [dW, dB];
}
训练模型
现在,我们知道如何评估我们的模型对于所有训练集示例的正确性(正向传播),我们也知道如何对纳米神经元模型的参数w
和b
(反向传播)进行小的调整。但问题是,如果我们只运行一次前向传播和后向传播,我们的模型从训练数据中学习任何规律/趋势是不够的。你可以把它和给孩子上一天小学相比较。他/她应该去学校不是一次,而是日复一日,年复一年地学习一些东西。
因此,我们需要为我们的模型多次重复向前和向后传播。这正是trainModel()
功能的作用。它就像是我们纳米神经元模型的“老师”:
- 它将花一些时间(
epochs
)在我们还有点愚蠢的纳米神经元模型上,并尝试训练/教授它, - 它将使用特定的“书籍”(
xTrain
和yTrain
数据集)进行训练, - 它将通过使用学习率参数
alpha
来推动我们的孩子更努力(更快)地学习
说几句学习率alpha
。这只是我们在反向传播期间计算的dW
和dB
值的乘数。因此,导数为我们指出了找到成本函数的最小值需要采取的方向(dW
和dB
符号),它还为我们指出了需要多快到达那个方向(dW
和dB
绝对值)。现在,我们需要将这些步长乘以alpha
,以使我们的移动更快或更慢。有时,如果我们使用一个大值alpha
,我们可能会跳过最小值,永远找不到它。
与老师的类比是,他越是逼迫我们的“纳米孩子”,我们的“纳米孩子”就会学得越快,但是如果老师逼得太紧,“孩子”就会精神崩溃,什么也学不到🤯。
下面是我们如何更新模型的w
和b
参数:
这是我们的培训师职能:
function **trainModel**({model, epochs, alpha, xTrain, yTrain}) {
// The is the history array of how NanoNeuron learns.
const costHistory = []; // Let's start counting epochs.
for (let epoch = 0; epoch < epochs; epoch += 1) {
// Forward propagation.
const [predictions, cost] = forwardPropagation(model, xTrain, yTrain);
costHistory.push(cost); // Backward propagation.
const [dW, dB] = backwardPropagation(predictions, xTrain, yTrain);
nanoNeuron.w += alpha * dW;
nanoNeuron.b += alpha * dB;
} return costHistory;
}
把所有的碎片放在一起
现在让我们使用上面创建的函数。
让我们创建我们的纳米神经元模型实例。此时,纳米神经元不知道参数w
和b
应该设置什么值。所以我们随机设置w
和b
。
const w = Math.random(); // i.e. -> 0.9492
const b = Math.random(); // i.e. -> 0.4570
const nanoNeuron = new NanoNeuron(w, b);
生成训练和测试数据集。
const [xTrain, yTrain, xTest, yTest] = generateDataSets();
让我们在70000
时期用小的(0.0005
)步骤来训练模型。你可以摆弄这些参数,它们是根据经验定义的。
const epochs = 70000;
const alpha = 0.0005;
const trainingCostHistory = trainModel({model: nanoNeuron, epochs, alpha, xTrain, yTrain});
让我们检查一下成本函数在培训期间是如何变化的。我们期望培训后的费用会比以前低得多。这意味着纳米神经元变得更加聪明。相反的情况也是可能的。
console.log('Cost before the training:', trainingCostHistory[0]); // i.e. -> 4694.3335043
console.log('Cost after the training:', trainingCostHistory[epochs - 1]); // i.e. -> 0.0000024
这就是培训成本在不同时期的变化。在x
轴上是纪元编号 x1000。
Training cost change over the epochs
让我们来看看纳米神经元的参数,看看它学到了什么。我们期望纳米神经元参数w
和b
与我们在celsiusToFahrenheit()
函数中的参数w = 1.8
和b = 32
相似,因为我们的纳米神经元试图模仿它。
console.log('NanoNeuron parameters:', {w: nanoNeuron.w, b: nanoNeuron.b}); // i.e. -> {w: 1.8, b: 31.99}
评估我们的模型对测试数据集的准确性,看看我们的纳米神经元如何处理新的未知数据预测。对测试集进行预测的成本预计将接近训练成本。这将意味着纳米神经元在已知和未知数据上表现良好。
[testPredictions, testCost] = forwardPropagation(nanoNeuron, xTest, yTest);
console.log('Cost on new testing data:', testCost); // i.e. -> 0.0000023
现在,由于我们看到我们的纳米神经元“孩子”在训练期间在“学校”表现良好,即使对于它没有看到的数据,他也可以正确地将摄氏温度转换为华氏温度,我们可以称之为“智能”,并问他一些问题。这是整个培训过程的最终目标。
const tempInCelsius = 70;
const customPrediction = nanoNeuron.predict(tempInCelsius);
console.log(`NanoNeuron "thinks" that ${tempInCelsius}°C in Fahrenheit is:`, customPrediction); // -> 158.0002
console.log('Correct answer is:', celsiusToFahrenheit(tempInCelsius)); // -> 158
如此接近!和所有人一样,我们的纳米神经元是好的,但并不理想:)
祝你学习愉快!
如何发射纳米神经元
您可以克隆存储库并在本地运行它:
git clone https://github.com/trekhleb/nano-neuron.git
cd nano-neuronnode ./NanoNeuron.js
跳过机器学习概念
为了解释简单,跳过并简化了以下机器学习概念。
列车/测试装置拆分
通常你有一大组数据。根据该集合中示例的数量,您可能希望对训练/测试集按 70/30 的比例进行拆分。在分割之前,应该随机打乱数据集中的数据。如果示例的数量很大(即数百万),那么对于训练/测试数据集,拆分可能以更接近 90/10 或 95/5 的比例发生。
网络带来力量
通常你不会注意到仅仅一个独立神经元的使用。力量就在这类神经元的网络中。网络可以学习更复杂的特性。纳米神经元本身看起来更像简单的线性回归,而不是神经网络。
输入归一化
在训练之前,最好将输入值标准化。
矢量化实现
对于网络来说,矢量化(矩阵)计算比for
循环要快得多。通常,如果以矢量化形式实现并使用 Numpy Python 库进行计算,前向/后向传播会工作得更快。
成本函数的最小值
我们在这个例子中使用的成本函数过于简化。它应该有对数分量。改变成本函数也将改变其导数,因此反向传播步骤也将使用不同的公式。
激活功能
正常情况下,神经元的输出应该通过激活函数,如 Sigmoid 或 ReLU 或其他。
更多更新和新文章 在 Twitter 上关注我
美国宇航局小行星分类
对小行星是否危险进行分类。
Source: https://unsplash.com/
介绍
太空中的一切仍然是个谜。科学家们继续努力在外层空间寻找新的东西。虽然预计会发现很多东西,但让我们看看已经发现了什么。
小行星
是的!!意大利牧师兼天文学家朱塞普·皮亚齐在 1801 年的一次偶然发现,导致了我们今天所称的小行星。朱塞佩发现第一颗名为谷神星的小行星在火星和木星之间运行。从那以后,许多小行星被像美国宇航局这样的太空组织发现和研究。
小行星是小行星,尤其是太阳系内部的小行星。较大的小行星也被称为小行星。存在着数百万颗小行星,并且绝大多数已知的小行星在位于火星和木星轨道之间的中央小行星带内运行,或者与木星共轨运行(木星木马**)。**
对小行星的研究也至关重要,因为历史事件证明其中一些是危险的。还记得希克苏鲁伯陨石坑吗?—6500 万年前,一颗小行星形成的陨石坑可能毁灭了所有的恐龙。
作为一名数据科学爱好者,我想到了使用机器学习来预测小行星是否危险。在 Kaggle 上搜索,我找到了美国国家航空航天局关于迄今发现的一些小行星的数据集。该数据集包含关于小行星的各种信息,并将每个小行星标记为危险或无害。
你可以在这里 找到数据集 。
现在让我们看看数据集。
小行星数据集
数据是关于小行星的,由 NEOWS(近地天体网络服务)提供
A glimpse of the dataset
数据集由 **4687 个数据实例(行)**和 **40 个特征(列)**组成。此外,数据集中没有空值。
下面给出了一些特征的描述;
- *‘近地天体参考号’:*该特征表示分配给小行星的参考号。
- *‘名字’:*这个特征表示给小行星起的名字。
- *‘绝对星等’:*这个特征表示小行星的绝对星等。一颗小行星的绝对星等是如果小行星被放置在 1 个天文单位(AU)之外,距离太阳 1 个天文单位,并且相位角为零,观察者将记录的视觉星等。
- *‘以千米(分钟)为单位的估计直径’:*该特征表示以千米(公里)为单位的小行星的估计直径。
- *‘以米(分)为单位的估计直径’:*这个特征表示以米(米)为单位的小行星的估计直径。
- *‘相对速度千米每秒’:*这个特征表示小行星的相对速度千米每秒。
- *‘相对速度千米每小时’:*这个特征表示小行星的相对速度千米每小时。
- *“轨道天体”:*这一特征表示小行星围绕其旋转的行星。
- *“木星 Tisserand 不变量”:*该特征表示小行星的 Tisserand 参数。 Tisserand 的参数(或 Tisserand 的不变量)是由一个相对较小的天体和一个更实质的‘扰动体’的几个轨道要素(半长轴、轨道偏心率、倾角)计算出来的值。它被用来区分不同种类的轨道。
- *‘偏心度’:*该特征表示小行星轨道的偏心度值。就像太阳系中的许多其他天体一样,小行星形成的领域不是正圆,而是椭圆。标有偏心率的轴是每个轨道离圆形有多远的量度:偏心率数字越小,范围越圆。
- *‘半长轴’:*该特征表示小行星轨道的半长轴的值。如上所述,小行星的领域是椭圆形而不是圆形。因此,半长轴存在。
- *“轨道周期”:*这个特征表示小行星的轨道周期值。轨道周期是指小行星绕其轨道运行一周所需的时间。
- *‘近日点距离’:*这个特征表示小行星的近日点距离值。对于绕太阳运行的天体,距离最近的点是近日点。
- *‘远日点距离’:*该特征表示小行星的远日点距离值。对于绕太阳运行的天体来说,最远点是远日点。
- *‘危险’:*这个特征表示小行星是否危险。
总之,数据集中的特征不仅包括小行星的几何信息,还包括其路径和速度。
方法
和往常一样,你可以在下面的 Github 资源库 中找到这篇文章的代码。
值得注意的事实是,一般来说,体积较大的小行星比相对较小的小行星更危险。
如果我们考虑在这个数据集中被标记为危险的小行星的平均直径,那么结果是 **0.70 公里。**相比之下,非危险小行星的平均直径为 0.40 公里。 因此,我们得出结论,数据集支持一般理论。
让我们开始吧。
特征工程
可以看出,数据集中存在几个不必要的特征,这些特征对分类几乎没有贡献。
特征“名称”和“近地天体参考号”表示给予小行星的识别号。这些特征对于机器学习模型是没有用的,因为小行星的名称并没有促成它是危险的事实。此外,这两个特征包含相同的值。
因此,我们可以删除这两个特征。
特征*‘接近日期’也是不必要的,因为它给出了小行星接近地球的日期。小行星最接近地球的时间并不能说明小行星是否会对 T21 造成危险。相反,当出现时,它会告诉*。因此,我们也将删除此功能。
出于类似的原因,我们也将删除*‘轨道确定日期’特征。***
现在,让我们看看*‘轨道体’的特性。它只包含一个值“地球”。因此,也删除这个特征(因为只有一个值的特征对机器学习技术没有贡献)。
此外,特征‘Equinox’*只包含一个值‘j 2000’,因此也删除了该特征。
考虑以下特征:
‘以千米(分)为单位的预计直径’,
‘以米(分)为单位的预计直径’,
‘以英里(分)为单位的预计直径’,
‘以英尺(分)为单位的预计直径’,
所有这些特征以不同的单位表示小行星的估计直径,公里=公里,米=米,等等。这是冗余数据的一个很好的例子,因为它是以不同方式表示的相同值。这种冗余应该删除。统计分析的美妙之处在于,它能识别数据集中的这类错误,即使数据科学家会忽略它们。让我们现在不要删除这些特征,而是用统计方法识别它们。
到目前为止,对上述特征的去除是基于直觉的。现在让我们看看统计分析,找出哪些特征是统计相关的。
统计分析
在此之前,我们先来看一下*‘危险’*特性。值为“真”或“假”,分别编码为 1 和 0。
现在,让我们形成数据集的相关矩阵。
Correlation matrix
因此,相关矩阵表示存在一些彼此相关的特征,这意味着它们可以毫不犹豫地被移除。
回到特征:
‘预计直径,单位为千米(最小)’,‘预计直径,单位为千米(最大)’,
‘预计直径,单位为米(最小)’,
‘预计直径,单位为英里(最小)’,‘预计直径,单位为英里(最大)’,
‘预计直径,单位为英尺(最小)’,‘预计直径,单位为英尺(最大)’
就像上面提到的,相关矩阵很快识别出这个冗余,我们现在可以删除重复的信息了。
我要删除特征;
‘以米(最小)为单位的预计直径’,‘以米(最大)为单位的预计直径’,
‘以英里(最小)为单位的预计直径’,
‘以英尺(最小)为单位的预计直径’,‘以英尺(最大)为单位的预计直径’。
对于这些特征可以给出类似的解释;
‘相对速度公里每秒’,‘相对速度公里每小时’, , ‘脱靶量’。‘天文’,Dist 小姐。‘阴历’,Dist 小姐。‘公里’,‘距离小姐。(英里)’
除了上面提到的特征,我将保留*‘相对速度千米每秒’和‘脱靶量’。(天文数字)’。*
如果我们查看*‘预计直径,单位为千米(最大)’和‘预计直径,单位为千米(最小)’*,我们可以看到它们之间有很强的相关性。
让我们看看他们的散点图,以便有一个清晰的概念。
散点图显示特征*‘预计直径,单位为千米(分)’和‘预计直径,单位为千米(最)’完全相关,因为从散点图中可以观察到两者之间的线性关系。
所以建议删除其中一个功能。我将删除‘以千米(最大)为单位的估计直径’*特征。
现在让我们看看*【危险】*特性的变化
计数图描述了不平衡数据集的情况。我们有一个类,在数据条目的数量上领先于另一个类。
83.89%的数据实例被标记为 0(不危险),只有
16.10%被标记为 1(危险)。
这意味着,即使我们有一个预测所有值都为 0(不危险)的破损模型,那么准确率也会是 83.89% 。因此,我们不能仅仅依靠准确性来评估在这个数据集上训练的机器学习分类器。为了清楚地了解用于评估分类模型的不平衡数据和众多指标,请阅读 这篇文章 。
机器学习模型
数据已经过分析和清理;现在,是时候建立那些机器学习模型了。
让我们将数据集分成一个 80:20 的比例,分别作为训练集和测试集。
训练集(根据 my code 生成)包含 3749 个数据实例,并有 610 个案例标记为 1(危险),这意味着如果一个模型预测所有值为 0,那么准确率将为 83.72% 。这将被视为训练集的基线精度。
类似地,测试集的基线精度(根据我的代码)将是 84.54% 。
我们的模型应该比这些精度做得更好,或者应该足够健壮以处理类别不平衡。
使用了以下模型:
- 朴素贝叶斯分类器
- SVM
- 决策树
- LightGBM
结果在表中列出,如下所示:
****
如果你想了解更多关于上面用于模型评估的指标,那么请参考这篇文章 。现在让我们来讨论每种型号。
朴素贝叶斯
如果我们查看朴素贝叶斯的表格,我们会看到测试集和训练集的精度等于基线精度**。此外,如果我们查看测试集的特异性、Mathews 相关系数和假阳性率,则这些是**【nan】,意味着模型被破坏**,并且预测所有值为 0(无危险)。这样的模型没有任何意义,因为当一个模型永远无法实现它的目的时,使用它是没有意义的。**
让我们也看看混淆矩阵,因为没有混淆矩阵,分类问题似乎是不完整的。
Confusion matrices for Naive Bayes Classifier
混淆矩阵清楚地表明,该模型甚至未能将单个数据实例预测为 1(危险),因此该模型不够稳健**。**
SVM
根据记录,就计算速度而言,SVM(SVC)被证明是最慢的。****
SVC 的结果表非常类似于朴素贝叶斯的结果表。因此,它清楚地表明 SVC 也失败(因为特异性、Mathews 相关系数和假阳性率再次为‘nan’)。
让我们看看 SVC 的混淆矩阵。
Confusion matrices of Test and Train set for SVC
测试集的混淆矩阵显示,SVC 甚至无法将单个值预测为 1(危险)。训练集的混淆矩阵显示只有两个数据实例(3749 个中的)被预测为一个,并且所做的两个预测是正确的。
与朴素贝叶斯分类器相比,这是一个微小的(但可以忽略不计的)改进。但尽管如此,我还是要说,这个模型完全被打破了,没有零实际意义。
如果您是数据科学的新手,那么您可能会想知道如何找到一种方法(或模型)来处理数据不平衡,因为这是一个迫在眉睫的严重问题。
多亏了研究人员,一些分类模型足够强大,可以处理这种不平衡的数据。请考虑以下情况。
决策图表
****决策树分类器的结果表证明它是一个非常健壮和几乎完美的模型。测试集的准确率为 99.4% ,非常好,而且 Mathews 相关系数和 F1 得分的值几乎接近 1,表明模型实际上是完美的。
让我们看看决策树的相关矩阵。
Confusion matrices for the test set and train set for Decision Tree
混淆矩阵也描述了这样一个事实,即该模型是稳健的,几乎是完美的。
在测试集中只有六个错误预测的值,而在训练集中没有。
决策树是能够处理类别不平衡数据的健壮模型的一个很好的例子。
决策树可能已经给了我们很好的结果,但是还有比它更健壮、更有效的模型。
集合模型更稳健,因为它们是弱预测器的“集合”。因此,我也将使用 LightGBM。
LightGBM
LightGBM 的结果表显示,该模型几乎是完美的,并给出了很好的结果。测试集的准确率为 99.3% ,马修斯相关系数为 0.971,F1 得分为 0.996 。
让我们看看 LightGBM 的混淆矩阵;
Confusion matrices for Train and Test set for LightGBM
测试集的混淆矩阵显示,只有 7 个(比决策树多 1 个)不正确的预测,而训练集只有一个错误的预测。****
结论
在这篇文章中,我们了解了小行星,更重要的是建立了一个几乎完美的分类器来预测小行星是否危险。
为数据集选择的特征是完美的,因为机器学习模型获得的结果非常好。
我希望你喜欢这篇文章,我相信你一定从中有所收获。
如果有任何疑问或建议,请在评论中告诉我。
谢谢你。
自然语言生成第 1 部分:回归基础
你有没有遇到过那些脸书或推特上的帖子,显示一个人工智能被“强迫”看电视或看书的输出,它得出的新输出与它看到或读到的相似?它们通常非常有趣,并不完全遵循某人实际上是如何说或写的,但它们是自然语言生成的例子。NLG 是 ML 的一个非常有趣的地区,在这里玩玩,想出你自己的模型会很有趣。也许你想做一个瑞克和莫蒂星际迷航穿越脚本,或者只是创建听起来像另一个人的推文的推文。
随着研究和硬件的进步,使用 ML 生成文本、图像和视频变得越来越普遍。随着基于深度学习的系统的最新进展,例如 OpenAI 的 GPT-2 模型,我们现在看到语言模型可以用于从大量其他示例中生成非常真实的声音文本。我对构建一个以另一种风格或人物的风格生成假文本的系统很感兴趣,所以我决定专注于学习不同的 ML 方法,并概述我使用这些不同技术所学到的东西。
回归基础
不要直接跳到花哨的深度学习技术,让我们看看一种非常容易理解和容易实现的技术作为起点。多年来,语言生成最常用的方法之一是 马尔可夫链 ,这是一种非常简单的技术,但却惊人地强大。马尔可夫链是一种随机过程,用于在只给定前一事件的情况下描述序列中的下一事件。这很酷,因为这意味着我们真的不需要跟踪序列中所有先前的状态来推断下一个可能的状态。
在我们的例子中,状态将是前一个单词(一元)或 2 个单词(二元)或 3 个单词(三元)。这些通常被称为 ngrams,因为我们将使用最后 n 个单词来生成序列中的下一个可能的单词。马尔可夫链通常通过概率加权来选择下一个状态,但在我们的例子中,这只会创建在结构和单词选择上过于确定的文本。你可以考虑概率的权重,但是真正的随机选择有助于让生成的文本看起来更有创意。
建立语言模型
创建语言模型相当简单。首先,我们需要一些示例文本作为我们的语料库来构建我们的语言模型。它可以是任何类型的文本,如书籍段落,推文,reddit 帖子,你能想到的。在我的语料库中,我使用了多位总统的总统演讲。
一旦我们收集了文本,我们需要做以下步骤。注意,我将标记“#END#”添加到我的语言模型中,以便于确定任何示例语音中的结束状态。
- 对文本进行标记
- 对令牌做任何预处理(在我的例子中没有)
- 从令牌生成 ngrams
- 创建从 ngram 到文本中找到的下一个可能单词的映射
为了更好地理解这个模型是如何构建的,让我们看一个超级简单的例子。假设我们有一个简单的文本“狗跳过月亮。狗很有趣。”。使用上面的过程,我们将生成下面的语言模型。
(The, dog) -> [jumped, is]
(dog, jumped) -> [over]
(jumped, over) -> [the]
(over, the) -> [moon.]
(dog, is) -> [funny.]
(is, funny) -> [#END#]
一旦我们完成了 ngram 映射,这个模型就可以用来生成一些新的文本了。现在,通过传入一个示例 ngram 的种子(如“The dog ”),或者让系统从提取的 ngram 密钥中随机选择一个起始点,就可以相当容易地做到这一点。一旦我们选择了一个种子 ngram,我们就从可能的单词列表中随机选择下一个单词,然后从目前生成的文本中选择下一个 ngram,并选择下一个状态等等…
简单的 Python 马尔可夫链
既然我们已经从概念上了解了它是如何工作的,那么让我们来看看训练和生成文本的完整代码。下面是我从网上其他例子中拼凑的 python 脚本,它用 python 构建了一个基本的马尔可夫模型。
让我们更深入地研究一些代码。它主要只有两个功能。学习功能和生成功能。让我们首先看一下 learn 函数,它从一系列大小为 n 的记号和 n 元语法中构建模型。
def learn(self,tokens,n=2):
model = {}
for i in range(0,len(tokens)-n):
gram = tuple(tokens[i:i+n])
token = tokens[i+n]
if gram in model:
model[gram].append(token)
else:
model[gram] = [token]
final_gram = tuple(tokens[len(tokens) - n:])
if final_gram in model:
model[final_gram].append("#END#")
else:
model[final_gram] = ["#END#"]
self.model = model
return model
我们从从第一个标记到列表长度减 n 的循环开始。随着我们的进行,我们建立了在标记化文本中找到的相邻单词的 ngrams 字典。在循环之后,我们在输入文本的最后 n 个单词之前停止,并创建最终的令牌变量,然后用“#END#”将其添加到模型中,以表示我们已经到达了文档的末尾。
我要指出的这种方法的一个局限性是,我将所有文本放在一个列表中,所以我们实际上只有一个结束状态。进一步的改进是我们处理的每个文档都有结束状态,或者可以更进一步,在句子的末尾添加结束状态,这样我们可以更好地知道什么时候开始一个新的句子等等。接下来我们有生成函数。
def generate(self,n=2,seed=None, max_tokens=100):
if seed is None:
seed = random.choice(list(self.model.keys()))
output = list(seed)
output[0] = output[0].capitalize()
current = seed
for i in range(n, max_tokens):
# get next possible set of words from the seed word
if current in self.model:
possible_transitions = self.model[current]
choice = random.choice(possible_transitions)
if choice is "#END#" : break
if choice == '.':
output[-1] = output[-1] + choice
else:
output.append(choice)
current = tuple(output[-n:])
else:
# should return ending punctuation of some sort
if current not in string.punctuation:
output.append('.')
return output
生成新文本的代码接受我们训练的 ngrams 的大小,以及我们希望生成的文本有多长。它还接受一个可选的种子参数,如果没有设置,它将从模型中学习的可能的 ngrams 中随机选取一个起始种子。在循环的每次迭代中,我们查看前一个 ngram,并随机选择下一个可能的过渡词,直到我们到达结束状态之一或到达文本的最大长度。
下面是一个使用二元模型作为语言模型的脚本输出示例。
Us from carrying out even the dishonest media report the facts! my hit was on the 1st of december, 1847, being the great reviews & will win on the front lines of freedom. we are now saying you will never forget the rigged system that is what we do at a 15 year high. i can perceive no good reason why the civil and religious freedom we enjoy and by the secretary of war would be 0.0 ratings if not.
如你所见,这很有道理,但听起来也有点随意。如果我们尝试使用三元语法语言模型呢?
Was $7,842,306.90, and during the seven months under the act of the 3d of march last i caused an order to be issued to our military occupation during the war, and may have calculated to gain much by protracting it, and, indeed, that we might ultimately abandon it altogether without insisting on any indemnity, territorial or otherwise. whatever may be the least trusted name in news if they continue to cover me inaccurately and with a group, it’s going to be open, and the land will be left in better shape than it is right now. is that right? better shape. (applause.) we declined to certify the terrible one-sided iran nuclear deal. that was a horrible deal. (applause.) whoever heard you give $150 billion to a nation
嗯,这听起来好多了…但是等一下,当我深入研究样本语料库时,我注意到它从语料库中提取了大量的文本。在现实中,除非你有大量的数据来构建,否则一旦你开始使用三元模型或更高的模型,大多数模型都会表现出这种行为。这是马尔可夫模型方法的一个缺点。虽然 bigram 模型听起来更随机,但似乎每次运行都会生成相当独特的输出,并且不会从语料库中提取文本部分。
火花分布马尔可夫链
比方说,我们创建了一个更大的数据集,从整个子数据集或多年的推文中提取数据。如果我们想让 python 脚本运行足够长的时间,并在我们的机器上有足够的内存,那么它可能可以处理数据集,但最终它可能不容易扩展。让我们做同样的事情,但是使用 Apache Spark 并使用它的分布式计算能力来构建和存储模型。下面是基于 spark 的模型的完整代码,我们也将深入挖掘它的操作。
最大的障碍是试图找出如何在 Spark 中生成 ngram 模型,创建类似字典的结构并对其进行查询。幸运的是,Sparks mllib 已经在框架中内置了 ngram 特征提取功能,因此 park 已经被处理好了。它只是接收一个 Spark dataframe 对象,即我们的标记化文档行,然后在另一列中将 ngrams 输出到一个新的 dataframe 对象。
ngram = NGram(n=self.n, inputCol='tokenized_text',outputCol='ngram')
ngram_df = ngram.transform(text_df)
使用 Sparks ngram 模块,让我创建一个函数来映射数据帧中的每一行,并处理文本以生成每个 ngram 的相邻单词。这是在 Spark 进程的第一个 map 调用中调用的函数。它的目标是只获取文档的 ngram 列表,并以[(ngram,adjacent term)]的形式循环生成每个文档的元组列表。现在,列表中可能会有重复的(ngram,相邻项)元组。
def generate_adjacent_terms(ngrams):
adjacent_list = []
for i in range(0, len(ngrams)):
if(i == len(ngrams) - 1):
adjacent_tuple = (ngrams[i], "#END#")
adjacent_list.append(adjacent_tuple)
else:
adjacent_tuple = (ngrams[i], ngrams[i+1].split(" ")[-1])
adjacent_list.append(adjacent_tuple)
return adjacent_list
平面映射将所有元组列表放入一个平面 rdd 中,而不是每个 rdd 元素都是来自每个文档的列表。下一个映射是设置 reduceByKey,因此我们获取每个元素并将其修改为一个(ngram,list object)元组,然后可以使用该元组将 ngram 键组合在一起,最终以(ngram,[相邻术语列表])的形式创建模型。重要的是要注意邻接表中会有重复的术语。我保留了这些副本,作为我们算法随机选择特定下一个状态的可能性的加权。
self.ngram_model = ngram_df.rdd.map(lambda x: PreProcess
.generate_adjacent_terms(x.asDict()['ngram'])) \
.flatMap(lambda xs: [x for x in xs]) \
.map(lambda y: (y[0], [y[1]])) \
.reduceByKey(lambda a, b: a + b)
下面是我用来创建基于 Spark 的马尔可夫链代码的完整代码。文本生成逻辑与其他脚本非常相似,只是我们不是查询字典,而是查询 rdd 来获取序列中的下一个术语。实际上,这很可能是在 api 调用之后,但是现在我们可以直接调用 rdd。
Spark 代码将生成与第一个 python 脚本类似的输出,但是理论上,当在集群上运行大型数据集时,应该可以更好地扩展。
您可以随意查看代码和脚本,并让我知道您的想法/我应该研究哪些改进!https://github.com/GeorgeDittmar/MarkovTextGenerator。下一轮工作是能够保存模型以用新数据扩展它们,以及添加更多的示例脚本供人们使用。
感谢阅读!
自然语言处理:速成班!
Next word prediction is one of the applications of NLP
自然语言处理(NLP)是机器学习的一个越来越重要的子领域,它通过从各种大型文本语料库开发各种语言模型来处理一般理解。在本文中,我们讨论了 5 种常见的 NLP 问题及其相关模型:
(i) 文本分类
(二)文字嵌入创作
(三)词性标注
(iv) 序列间翻译
(v) 命名实体识别
文本分类
Spam classification is a famous example of Text Classification
这是 NLP 最基本的用途之一,而输入模型给定一个单词或一个单词集,它必须预测给定的一个或多个单词属于一组类别中的哪一个。这与任何其他类型的分类问题非常相似!让我们看一个例子,并介绍一些方法。
文本分类问题的一个主要例子是垃圾邮件分类。这种特殊类型的问题是二元分类,这意味着任何给定的电子邮件只能属于两种可能的类别,即垃圾邮件或非垃圾邮件。现在,让我们强调并讨论解决这个问题的三种可能的方法:
- 感知器
- 最大熵分类器
- 多层感知器(又名神经网络)
感知器
The perceptron algorithm is an error-based approach
单层感知器是一种错误驱动的方法,旨在通过不断调整其权重来最小化训练数据的分类错误数量。
感知器训练算法的伪代码如下:
weights = random vector of weights
for the desired number of epochs:
for point in training points:
predicted_class = maximum score index(weights^T*point)
if predicted_class is not actual_class
weights[predicted_class]-=point
weights[actual_class]+=point
让我们一点一点地分析一下:
(1)第一行随机初始化感知器的权重
(2)外部循环指定历元的数量(或者我们将在所有给定的训练数据点上“训练”我们的感知器的次数)
(3)内部循环简单地循环所有的训练数据
(4)第 4 行有意思。表达式 w^Tx 实际上是计算各个类的分数,然后取最大分数的指数表示我们将预测这个特定输入点属于哪个类。
这就是奇迹发生的地方。如果我们的预测类与当前点的实际类不匹配,算法会“惩罚”错误预测类的权重,并“提升”实际类的权重。因此,感知器在未来不太可能犯同样的错误。
感知器预测算法的伪代码非常简单。我们通过训练简单地使用更新的权重来为每个可能的输出类分配单独的分数,并挑选具有最高结果分数的一个:
predicted_class = maximum score index(updated_weights^T*test_point)
最大熵分类器
与单层感知器相反,最大熵分类器试图最大化所有给定训练数据点的可能性,然后旨在找到一组权重,进而最大化该总体可能性。
我们先来探讨一下什么是可能性。一般来说,似然性告诉我们在特定的参数配置下,一组给定的观察值(数据点)的概率。
特别是对于最大熵分类器,唯一的参数是我们用来形成预测的权重向量。因此,存在的单个数据点的概率表达式如下:
以下是上述表达式中两个主要部分的概述:
w -我们的分类器正在训练的一组权重
phi(X,y) —输入向量 X 和输出类别标签 y 的特征向量
此外,整个训练数据的似然性的表达式简单地通过遍历所有单独的训练数据点并乘以单独的概率来获得训练数据出现的总概率而导出:
最后,我们可以将上述个体概率的自然对数(ln)值相加,从而将似然表达式转换为一个称为对数似然的等价表达式,得到以下公式:
因此,这种类型的分类器的整体优化将涉及找到权重以最大化对数似然量,并且可以数学地写成如下:
多层感知器(神经网络)
经常用于文本分类的第三种方法是多层感知器,这只是神经网络的另一个名称。虽然我们不能在这篇文章中深入神经网络如何工作的所有细节,但让我们涵盖一些核心方面。
为了理解多层感知器,我们可以从理解单个神经元如何工作开始。一个神经元只是接受一些
一组输入,将它们乘以各自的权重,然后将这组乘积相加,并将总和传递给激活函数。听起来像是满嘴?下图很好地总结了这个过程:
Structure of a single neuron
这里有三个主要组件:
(1) X1 & X2 :神经元的输入
(2) W1 & W2 :用于乘以输入的权重
(3) f :上述神经元的激活函数
现在,一个多层感知器包括将这些单个的神经元堆叠在一起,这样就会有多层神经元。典型地,多层感知器的最简单结构将包括一个输入层,一个单一隐藏层,以及最后一个输出层,如下所示:
Sample Multi-layer Neural Network
具体到垃圾邮件分类的情况,我们最终的神经网络架构如下所示:
上述模型从输入的电子邮件中导出一组特征,将这些特征馈送到多层网络的输入层,然后通过单个隐藏层传播,最后通过输出层,并为每个类别产生大小为 2 的概率向量。在这种情况下,电子邮件是垃圾邮件的概率和不是垃圾邮件的概率。
在上图中,“常规激活函数”是指常用于神经网络的激活函数,包括但不限于:
- s 形函数
- ReLU 功能
- Tanh 功能
Softmax 函数是一种特殊类型的激活函数,它将一组类得分转换成一组等价的类概率:
本质上,上面的 softmax 函数将一个向量作为输入,并返回一个概率向量作为输出。
训练神经网络
在我们结束对神经网络的介绍之前,让我们简单地谈谈训练网络。培训任何网络都涉及到一些基本组件,所以让我们在下面讨论一下:
损失函数
损失函数将用来衡量我们当前的一组预测与相应的真实值之间的差距。机器学习中常用的损失函数的一些例子包括:
- 均方误差
- 均方根误差
- 交叉熵损失(二元分类)
均方误差和均方根误差都用于连续预测,而交叉熵损失用于分类问题,因此交叉熵损失的二进制版本可以用于垃圾邮件分类。
梯度下降
训练神经网络的第二个主要部分是一种称为梯度下降的算法,它能够优化神经网络损失函数。整个伪代码如下所示:
Pick a random start point for a loss function
while magnitude of gradient is < threshold:
- store current gradient value
- update the point based on the calculated derivative
可视化这个算法使它变得相当直观,所以让我们走这条路。作为起点,假设我们有以下平滑凸函数:
在这种情况下,我们的主要目标是尝试找到使函数 y 的值最小化的 x 的值。作为这种方法有效的证明,让我们以函数 y 的最小值两侧的点为例。首先,让我们从最小值左侧的点开始:
由于上述函数在点 x0 处的导数为负,我们将在梯度下降更新函数中看到上述移动:
- 数学上
- 视觉上
现在很容易看出重复应用这一更新将如何最终找到使函数 y 最小的 x 值。请注意,我们将多快达到这一最小值,或者我们最终是否会完全超过它,在很大程度上取决于我们为学习速率α选择的值。
对于最小值右边的点,很容易看到现在 dy/dx > 0,所以 x 会不断地向左移动,直到它达到函数 y 的全局最小值。
最后但同样重要的是,让我们通过接触前向和后向传播来完成训练神经网络的循环。
正向传播
前向传播,顾名思义,就是遍历构建好的神经网络,得出一组当前预测的过程。
反向传播
反向传播,或称为反向传播,是一种真正开始使实现神经网络可行的算法。它用于有效地计算损失函数相对于权重的导数。
因此,训练神经网络的整个伪代码将如下所示:
for desired number of epochs (aka training cycles):
for data_point in training_data:
forward propagate on the current inputs
backward propagate to calculate dL/dw(current data point)
dL/dw+=dL/dw(current data point)
average out dL/dw based on size of training_data
weight update: w_{i+1} = w_{i} - learning_rate*[dL/dw]
单词嵌入创建
Photo by Giulia May on Unsplash
单词嵌入是简单的向量,用于表示不同的单词,并帮助获得更好的个人和词组的数学意义。在深入研究将单词转换为单词嵌入的技术细节之前,让我们先了解一下单词嵌入的一些最常见的应用:
- 分析文档/句子/单词相似度:智能地将文档或语料库中的单个单词嵌入组合在一起,可以让我们将该文档或语料库表示为单词嵌入。
- 序列到序列的转换:这将在本文后面讨论,用于从给定的输入序列预测期望的输出序列。
除此之外,事实仍然是向量更适合机器学习背后的所有数学,因此在 NLP 中到处都使用了单词嵌入。
所以,事不宜迟,让我们直入主题吧。将单词转换为单词嵌入的方法有很多种,但是让我们来看看三种最流行、最基本的方法:
- 跳格模型
- 连续词袋(CBOW)模型
- 单词表示的全局向量(手套)模型
跳格模型
让我们通过首先查看我们可能在极大的训练语料库中遇到的例句来介绍 Skip-Gram 模型:
保持饥饿,保持愚蠢。
我们的第一个目标是大致了解在任何给定的句子中哪些单词可能彼此接近。自然地,我们从定义“近”的含义开始,结果,我们得到了上下文的概念。
你看,上面句子中的每个单词都有一个语境**,**,它仅仅是由周围的单词组成的。此外,我们可以定制我们希望的上下文的大小。例如,在大小为 1 的上下文的情况下,单词“hungry”将具有[“Stay”、“Stay”]的上下文。另一方面,单词“stay”会有[“hungry”、“傻瓜”]的上下文。
The respective length-1 contexts for ‘hungry’ and ‘stay’
对数百个、数千个甚至数百万个句子重复做这个练习会建立一个敏锐的直觉,知道哪些单词可能是给定单词的上下文单词。跳跃语法模型利用了这种直觉,然后根据语料库中每个独特的单词在输入单词的上下文中出现的可能性来分配概率。
连续词袋模型
与 Skip-Gram 模型不同,CBOW 模型将一组上下文单词作为输入,并尝试预测这些单词所在的上下文中的单词。本质上,对于上面的两种情况,这将如下所示:
单词表征的全局向量(GloVe)模型
最后,与上述两个模型不同,GloVe 模型不依赖于单词上下文来训练单词嵌入,而是依赖于共现矩阵的概念。
到底什么是共生矩阵?简单地说,这是一个 2d 整数数组,它捕捉了所有可能的单词组合在同一个句子或跨度中出现的频率。然后,它利用这个矩阵中的所有计数来导出每个单词的嵌入。
词性标注
Photo by Edho Pratama on Unsplash
词性标注是自然语言处理领域的一个研究热点,有多种方法。让我们从回顾一些基本的语言建模概念开始,然后逐步为维特比算法开发一个框架。
隐马尔可夫模型
A sample HMM for M total observations and 3 hidden states
当我们必须表示一系列无法直接观察到的元素时,隐马尔可夫模型非常有用。这使得它们成为用于词性标注的理想模型,因为我们只观察单个单词,并且必须推断它们的相关标签。下面是用于词性标注的 HMM 的基本组件的分类:
- **Q = q_{1}q_{2}…q_{N}【一组隐藏状态】😗*在我们的例子中,这些将是我们所有可能的词性标签(例如。{'O ‘,’ VBG ‘,’ NN ‘,’ NP ',…})
- A = a_{11}…a_{ij}…a_{NN}[转移概率矩阵]: 这些将是特定状态之后一个状态的个体概率。比如 a_{11} = Pr(下一个单词的 tag = q_{1} |当前单词的 tag = q_{1})。
- **O = o_{1},…,o_{M}【一组观察值】😗*这些只是我们模型的一组单独的输入单词。
- **S = s_{1},…,s_{N}【一组起始状态概率】😗*每个可能状态的一组概率,它们是所讨论的序列的起始状态。
上述 HMM 也受两个假设支配:
- **马尔可夫假设:**一个观察对应的状态只取决于这个观察之前的状态。[ P(q_{i} | q_{i-1}) ]
- **输出独立性假设:**一个观测只与当前对应的状态有关。[ P(o_{i} | q_{i}) ]
An example transition probabilities matrix for the sample HMM from above.
Example emission probabilities for the above examples.
HMMs 的 3 个主要功能
事实证明,hmm 用于对一组顺序观察执行 3 个主要功能:
(1) **序列评分:**给定一个观察序列{o_{1},…,o_{n}},指定一个概率,表示该序列有多大可能给出上述一组跃迁和发射概率。
(2) **序列解码:**给定一个观测序列,找出最大化该观测序列发生概率的隐藏状态序列。
(3) **HMM 学习:**给定一个观察序列,调整 HMM 模型的转移和发射概率,以最大化该观察序列发生的概率。
HMMs 的问题是
为什么 hmm 不是我们在顺序位置标签中使用的主要结构?事实证明,我们为了计算一个最优的状态序列而必须经历的概率的绝对数量是非常大的,并且对于具有大的转移矩阵的数据集的计算是不可行的!
让我们通过基于上面的 HMM 计算样本观察值序列{观察值 1、观察值 2、观察值 3 }的可能性的示例来说明这一点:
本质上,这里我们有需要求和的个体概率!扩展也变得很困难。如果总共有 n 个隐藏状态和 m 个观测值,那么总起来说,就有 N^M 总数的情况!
解决方案:动态编程!
在本节的其余部分,我们将利用一种非常流行和有用的算法技术,称为动态编程。虽然了解细节很容易,但您需要理解的是,动态编程通过重用过去已经计算过的信息来加快算法运行时间!
介绍:格子架
听到关于动态编程的总结后,合乎逻辑的下一个问题是我们计划如何重用过去的信息。对于词性标注问题,我们将使用一种称为 Trellis 的结构,它由一组用于每个观察时间戳的节点组成:
A Trellis for our example given {observation 1, observation 2, observation 3}. The first layer of probabilities is labeled.
但是每个单独的节点持有什么确切的信息呢?嗯,隐藏状态 I 在时间步长 j 的节点,代表了处于隐藏状态 I 的概率,给定前 j 个观察值。在数学上,这可以表示如下:
现在,我们可以很容易地计算序列{观察 1,观察 2,观察 3}的可能性,方法是将上面网格的最后一层中的值相加:
介绍:维特比算法(通过词性标注)!
现在我们可以将维特比算法应用于我们的词性标注问题。让我们从设置我们的中心问题开始:我们有一个令牌序列,我们试图找到一组相关的词性标签(我们的隐藏状态)。
这是我们将用来有效重用子序列概率的网格结构:
让我们定义维特比算法的两个主要组成部分,即最佳 POS 标签序列概率和相应的反向指针:
(1)最优序列概率
(2) POS-Tag 反向指针
此外,维特比算法可以分为以下三个阶段:
**(1)初始化:**这里我们需要为隐藏状态概率以及节点反向指针的初始集合设置第一层的值:
**(2)递归:**这代表所有中间步骤,在这些步骤中,我们计算所有单个时间步长最佳标签,以及每一层的最佳后向指针:
**(3)终止:**这最后一个阶段涉及计算可能的最高整体隐藏状态序列概率,并且还设置我们将遵循的最终反向指针,以找到我们的 POS 标签的最佳序列。
下图直观地显示了这三个阶段分别应用于网格的哪些部分:
一旦我们正确地设置了反向指针,我们就可以简单地按照它们来获得我们的 POS 标签的最佳序列!伪代码类似于:
current_tag = end
optimal_tag_sequence = [end]
while backpointers[current_tag] != start:
current_tag = backpointers[current_tag]
optimal_tag_sequence = [current_tag] + optimal_tag_sequence
optimal_tag_sequence = [start] + optimal_tag_sequence
序列间翻译
Photo by Romain Vignes on Unsplash
序列到序列的翻译包括利用神经网络结构将输入的单词序列转换成期望的输出单词序列。它经常用于语言翻译,例如将提供的单词集从英语翻译成其他语言,比如法语。
从整体模型的宏观视图开始,然后讨论各个组件如何工作。整个系统看起来如下:
本质上,该模型将输入的令牌序列分解为单个单元,将这些单个单元输入到左侧所示的编码器模型中,然后该编码器模型产生一个整体序列嵌入,这是一个捕获输入序列中整体信息的向量。然后,这个序列嵌入被传递给解码器,解码器又返回一个输出令牌序列。现在,让我们来分解各个组件:
单个 RNN(递归神经网络)节点
与常规的神经网络节点相反,rnn 经常用于我们想要在更广泛的序列中对单个标记进行预测的情况。这种潜在的使用差异在 RNN 节点的整体结构中非常明显:
- 设 x_{i} =输入序列中的第 I 个记号
- 设 h_{i} =隐藏层输出中的第 I 个令牌
“展开”上面的 RNN,我们可以看到下面的结构:
到目前为止,我们一直在黑盒子 RNN 节点的内部结构,所以让我们打破它真正快速。它由两个权重组成,一个充当时间戳 t 处的输入令牌的系数,另一个充当时间戳 t 处的隐藏状态的系数。这两个权重分别乘以其对应的权重,两个结果相加并最终传递到激活函数 f:
这是 RNN 节点在时间戳 t 的输出,并作为时间戳(t+1)的节点的隐藏层输出!这种递归性质就是为什么 rnn 是递归神经网络的原因。
编码器型号
好消息是,一个简单的编码器模型遵循了我们前面举例说明的精确结构!它将简单地一个接一个地接受输入标记,并继续计算中间隐藏状态。最后,它将把生成的最终隐藏状态向量传递给解码器模型。
我们可以使用各种各样的创造性策略来提高编码器模型的嵌入能力,其中大多数策略包括将每个单独导出的隐藏状态巧妙地组合到最终的嵌入向量中。你也可以选择使用更复杂的递归神经网络结构,比如 LSTMs(长短转记忆网络)和 GRUs(门控递归单元)。
解码器模型
解码器模型结构将与编码器模型结构非常相似,但在这种情况下,我们将有一个最终的 softmax 层,以便我们为输出词汇表中的每个单词分配概率,并尝试通过最大概率预测输出序列中的每个标记:
Single Decoder Node
A more complete picture of the model.
关于训练序列间模型的简要说明
正如在训练机器学习模型中常见的那样,在序列到序列模型的训练阶段,主要焦点是调整我们之前提到的所有权重,以希望提供最好的结果。然而,简单的梯度下降在这种情况下根本不会很好地工作。相反,必须利用一种称为随机梯度下降的方法来训练模型。
命名实体识别
Photo by Kyle Glenn on Unsplash
最后但同样重要的是,让我们触及命名实体识别问题。命名实体识别(NER) 是一个非常普遍的问题,涉及到给命名实体分配类别。下面是一个简单的例子:
Example from Wikipedia’s Named Entity Recognition article.
命名实体识别的组件
(1)一个输入句子 s,由一串单独的单词标记表示,我们想要在其中识别命名实体。
(2)给定句子中每个标记的一组可能的命名实体标签 t。
(3)一组特征函数 f,其接受诸如给定单词的相邻标签和句子信息的信息,并输出相应的第 I 个标签以分配输入句子中的第 I 个单词。
条件随机场
我们将探索条件随机场(CRFs) ,它是用于 NER 提取和其他类型的顺序分类任务的最基本模型之一。通用报告格式由两个关键部分组成:
(I)评分功能,其接受一组预测的标签和输入的句子,并返回指示标签与句子标记匹配程度的分数;
(ii)用于归一化上面得到的标签序列分数的公式,使得每个分数在 0 和 1 之间:
然后,该模型简单地利用这些导出的概率来返回输入句子的最佳标签序列。
培训通用报告格式
以上两个部分清楚地说明了我们如何为任何输入的句子选择一个最优的 NER 标签序列,但是在训练 CRF 的过程中到底发生了什么呢?我们查看训练数据,并为特征函数 f 的集合调整各个系数(c_{1},…,c_{n})。训练它们的一种方法是利用梯度下降,这一点我们在前面的文本分类部分已经强调过了!
额外挑战
目前,在上面的概率公式中,我们正在查看分母中所有可能的 NER 标签集,这是非常低效的。使用我们之前关于动态编程的讨论,尝试提出一个可以更有效地计算最佳标签集的算法!
摘要
Photo by Aaron Burden on Unsplash
总的来说,本文旨在提供自然语言处理领域中常用的一些主要问题和算法的概述。这是一个压缩在一个地方的大量信息,所以最好是多次重温或按照自己的速度阅读!
自然语言处理和体育子编辑
如果你必须知道关于我的两件事,那就是我热爱运动和在 Reddit 上浪费我的空闲时间。如果你必须知道关于我的三件事,那就是我也喜欢发现新的应用自然语言处理(NLP)技术。因此,当被分配一个项目任务,通过从子数据集获取真实数据来探索我新发现的 NLP 技能时,我欣然接受了这个机会。
一段时间以来,Reddit 上关于体育的讨论让我特别感兴趣。俗话说,“凡事皆有子编辑”,所以自然 reddit 上的每个体育联盟都会有一个社区。从 NFL 和英格兰超级联赛,到 Overwatch 联盟和冰壶大满贯,几乎每个体育迷都有一个社区。他们每个人都有自己讨论体育的语言,更不用说他们自己的笑话和每周的话题讨论了。基于这些兴趣,我想进行一个项目来比较两个最大的体育子街道, r/NFL 和 r/NBA ,看看语言有什么不同,并使用 NLP 来预测一个帖子的来源,仅仅基于它的语言。
我将带您浏览数据、数据清理过程、矢量化、建模、预测,并评估模型在数据的一些有趣变化上的表现。我分析不同子主题中的语言的目的是确定哪些主题或趋势最能区分这些联盟的讨论。对每个模型的最重要的词特征的观察和每个模型的分类性能将用于得出我的结论。
数据是从哪里来的?
实际分析 Reddit 数据的第一步是…从 Reddit 获取数据。然而,这并不是一个非常困难的任务!幸运的是,Reddit 内置的 API 功能允许任何用户在网站上查询给定页面上热门帖子的. json 文件。例如,你可以现在就去 https://www.reddit.com/r/nba.json,你会看到。r/NBA 上前 25 个帖子的 json。然而,出于我的目的,我只需要提取每个帖子的标题和“自我文本”。
因此,我们需要多次遍历 subreddit 的页面来提取这些帖子。Python 的requests
模块可以下载。json 文件直接放入代码中,准备好进行操作。然而,为了获得有用的数据,我需要多次这样做。此外,我想只提取这个的特征。在我的建模过程中很有价值的 json。我使用以下函数来完成这项任务:
使用函数的num
参数,我告诉函数在页面中循环指定的次数。每个页面都有一个“after”参数,您可以从。json 文件,它引用页面上第一篇文章的文章 ID。您可以将这个参数传递到 URL 中,API 将为您提供在“after”ID 之后索引的所有帖子。
这个函数将返回一个相当大的熊猫 dataframe 对象。我们能够检索 Reddit 帖子的几乎所有功能,包括发布帖子的用户名、其 upvote 分数、任何附加图片的 URL、唯一的帖子 ID,当然还有帖子的标题。这是一个很大的数据量,但它现在能够被清理和建模!
计数矢量化与 TF-IDF
我们已经有了 reddit 帖子,现在我们该做什么呢?我将探索的 NLP 模型不能简单地解释出现在网站上的英语,我们需要在将其用于机器学习模型之前将其转换为数字数据。当文件用数字表示时,计算机想要读取文件。文档是 NLP 模型要评估的文本主体,在我们的例子中,是标题文本和“自身文本”主体的组合。
当文档可以用数字来解释时,计算机和程序员都更容易理解文档。为了对文档进行分类,每个文档都使用一个“输入”,并且类标签是“输出”、,在本例中是 r/NBA 或 r/NFL。大多数分类机器学习算法以数字向量作为输入,因此我们需要将 post 文档转换为固定长度的数字向量。
NLP 中的计数向量化允许我们将文本分割成句子和单词,收集文本文档并建立一个已知单词的词汇表。这是通过评估文档的整个语料库来完成的,获取在语料库的词汇表中找到的每个单词,并基于在单个文档中找到的词汇表为文档分配一个向量。
Word vectors, visualized. Source: https://towardsdatascience.com/natural-language-processing-count-vectorization-with-scikit-learn-e7804269bb5e
本质上,计数矢量器计算每个单词在文档中出现的次数,并根据语料库中已建立的词汇在矢量中为文档分配适当的值。
类似于计数矢量化,术语频率—逆文档频率,或 **TF-IDF,查看整个语料库以形成其词汇。TF-IDF 的不同之处在于,它根据单词在文档中出现的频率对单词进行加权。这背后的逻辑是,如果一个单词在文档中多次出现,我们应该提高它的相关性,因为它应该比出现次数较少的其他单词更有意义(TF)。然而,如果一个单词在一个文档中多次出现,而且还出现在许多其他文档中,则模型会降低该单词的权重,就好像它只是一个频繁出现的单词,而不是因为它是相关的或有意义的(IDF)。
因此,现在我已经确定了如何预处理文档以便在模型中使用,我需要清理实际的文档本身。我使用正则表达式,或者说 RegEx ,在每个文档中找到要删除或替换的单词和字符的特定模式。计数矢量器和 TF-IDF 都将把互联网帖子中的杂乱条目(如 URL 和表情符号)解释为令牌,因此只向它们提供字母数字文本非常重要。例如,我用来删除 URL 的代码行如下所示:
sub['text'] = sub['text'].map(lambda x: re.sub(r"((http|ftp|https):\/\/)?[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?",
' ',
x)
正如您所看到的,解释正则表达式并不简单,但它是清理文本的一个非常有效的工具。然而,RegEx 是非常通用的,因为它也被用在这个项目中来删除某些扭曲我的结果的单词、短语和字符序列。在这个 URL 清理器的例子中,它也在字符串中寻找独特的模式。
既然我们已经组装了矢量器,并清除了文本中不需要的特征,现在是建模的时候了!
建模!
在我的建模过程中,我的主要兴趣之一是确定在预测源的子编辑时,哪些单词具有更大的重要性,而不是简单地对某些预测单词进行计数。因此,虽然我确实利用了计数矢量化模型,但我发现使用 Scikit-Learn 的 TF-IDF 功能生成的加权矢量化结果TfidfVectorizer
在评估每个模型时会产生更多信息。然而,为了便于理解,我将分享两个矢量器产生的结果。
我评估的第一个模型是多项式朴素贝叶斯(NB)模型,同时具有计数矢量器和 TF-IDF 矢量器。计数矢量化 NB 模型在 97%的情况下正确预测了帖子是否在 r/NFL,在 93%的情况下正确预测了帖子是否在 r/NBA。
# run the Count Vectorized model with the optimal hyperparameters
cvec = CountVectorizer(stop_words='english', ngram_range=(1, 2), max_features=20000, max_df=0.60)
train_raw = cvec.fit_transform(X_train)
train_df = pd.SparseDataFrame(train_raw, columns=cvec.get_feature_names())test_raw = cvec.transform(X_test)
test_df = pd.SparseDataFrame(test_raw, columns=cvec.get_feature_names())train_df.fillna(0, inplace=True)
test_df.fillna(0, inplace=True)# fit the multinomial NB model
cvec_nb = MultinomialNB()
cvec_nb.fit(train_df, y_train)
Feature importances for the Count Vectorized NB Model, ranked by class probability.
在对来自 r/NBA 的帖子进行分类时,模型中最重要的词引用了自由球员的举动,如“威斯布鲁克”、“科怀”、“勒布朗”,但“交易”和“挑选”等加权术语也很重要。对来自 r/NFL 的帖子进行分类的最重要的词采取了不同的方向,其中“day”具有最高的计数,在关于实际足球比赛的讨论中发现的术语,如“round”、“yards”和“pass”,也非常重要。
TF-IDF 模型在 98%的时间里正确预测了一个帖子是否在 r/NFL,在 91%的时间里正确预测了 r/NBA。在对 r/NBA 的帖子进行分类时,模型中最重要的词再次引用了自由球员的举动,如“威斯布鲁克”、“科怀”和“勒布朗”。我还看到,在对来自 r/NFL 的帖子进行分类时,最重要的词是在关于实际足球比赛的讨论中发现的术语,如“highlight”、“yard”和“td”。
讨论我收集数据的时间很重要,因为很明显,尽管两个数据集都是在各自运动的休赛期发布的,但两个子数据集的侧重点是不同的。大多数帖子都是在 2019 年 7 月 8 日至 2019 年 7 月 12 日这一周被刮下来的,正如 NBA 球迷可能记得的那样,这是相当疯狂的一周。当 NBA 超级巨星拉塞尔·维斯特布鲁克、凯文·杜兰特、凯里·欧文和科怀·伦纳德决定加入新球队时,他们都在 NBA 世界产生了冲击波,这反映在我正在分析的数据中。这并不是说 r/NFL 或 NFL 媒体不讨论自由球员的转会,但至少 r/NBA 的文化是主要关注这项运动中的人物,而不是这项运动本身。
知道了这一点,我想看看不同的分类算法如何衡量每个文档的特征,以及我是否可以提高我的准确性指标。因此,我决定通过一个支持向量分类器(SVC) 运行这个相同的数据集。SVC 是非常强大的分类模型,它试图使用一个“分离超平面”将一个数据集分类到有标签的类中,例如 origin 的 subreddit。换句话说,给定一个二维空间,这个超平面是一条将平面分成两部分的线,其中每一类位于两侧。在支持向量机之下还有很多事情要做,但是出于我的目的,使用了 SVC,因为它是一个全面而强大的建模工具。
因此,我对从 r/NBA 和 r/NFL 收集的数据运行了 TF-IDF 矢量器和 SVC。该模型的得分不如多项式 NB 模型高,但仍然表现得非常好,发布了 93.14%的准确度得分和 93%的加权精度。带有我选择的超参数的模型如下:
# fit tf-idf svc model for best hyperparameters
tfidf = TfidfVectorizer(max_features=20000, ngram_range=(1, 1), stop_words='english', max_df=.6)
train_raw = tfidf.fit_transform(X_train)
test_raw = tfidf.transform(X_test)svc = SVC(C = 1, kernel='linear', gamma = 'auto', probability=True)
svc.fit(train_raw, y_train)
The weighted coefficients from the SVC model.
该模型选择的重要特征类似于 NB 分类器,但倾向于将专有名词如球员姓名、球队名称甚至记者的权重更高。然而,与主题相关的更一般的术语,如“篮球”和“足球”,也被赋予了更大的权重。
大学体育呢?
在预测涵盖不同运动的两个子主题的帖子来源时,我没有看到模型有太大的差异,所以我想给我的建模过程一个新的挑战。我想确定我是否可以创建一个模型来确定一个帖子的来源,这些帖子来自覆盖同一项运动,但在不同的联盟。
如果你需要知道关于我的四件事,那就是我热爱运动,在 Reddit 上浪费我的空闲时间,发现 NLP 的新应用,为 UVA 篮球队加油。因此,很自然地,我想以某种方式将r/学院篮球纳入这个分析*。*
使用与我收集 r/NFL 和 r/NBA 帖子相同的收集技术,我从 r/CollegeBasketball 收集帖子,清理文本,并将这些帖子与 r/NBA 帖子一起组合在 Pandas 数据框架中。我通过 SVC 模型运行了这些帖子,结果让我有些吃惊。
The SVC model, this time weighting the words from r/collegebasketball posts alongside r/nba.
这个模型表现很好,发布了 91.39%的准确度分数和 91%的加权准确度,但它显然没有根据 r/NFL 的内容对 r/NBA 的帖子进行分类时那么准确。这个模型倾向于给专有名词,比如球员名字和球队名字赋予更高的权重。“锦标赛”、“转会”和“提交”等术语在 r/CollegeBasktball 中非常重要,因为它们在关于 NCAA 篮球的讨论中比在 r/NBA 中使用得更广泛。然而,我们发现像“卡利帕里”这样的教练的名字比球员的名字更重要。一些有趣的区别是“basketball”和“gif ”,这两个词在任一子编辑中都很常见,但 r/CollegeBasketball 的权重更大。
结论
对所有迭代的子网格数据进行分类的所有模型得分都很高,但计数矢量化多项式朴素贝叶斯在训练和测试数据中表现最佳且最一致。支持向量机模型的表现不如 NB 模型,但让我更好地理解了哪些词/术语在分类帖子时是至关重要的。
在这个项目中分析的所有模型中,他们能够让我理解在分类子编辑之间的帖子时什么类型的内容是重要的。对于 r/NBA 来说,很明显,球员姓名和交易是帖子中非常频繁的话题,尤其是考虑到数据拍摄的时间。对于 r/NFL 来说,主题更倾向于面向团队,但是像“td”和“yard”这样的游戏专用术语在所有模型中都很重要。对于 r/CollegeBasketball 来说,很明显学校的骄傲和竞争是帖子主题中出现最多的,因为某些学校的名字权重最大,而教练往往比个人球员更经常进行讨论。
作为一个经常光顾这三个子街道的人,我非常好奇这个项目的结果会告诉我什么。不仅看到每个模型如何解释来自每个子编辑的帖子特别有趣,而且我能够结合我自己对每个社区中讨论的主题语言的知识以及模型来解释结果。虽然像单词云这样的东西是可视化 subreddit 语言选择的一种简洁方式,但对帖子进行矢量化和分类让我对每个社区如何讨论这项运动有了新的认识。
如果你想探索这个项目和收集的数据,Temple 已经上传了所有相关的 Jupyter 笔记本和。csv 文件在他的公共 GitHub 上。
使用深度学习和 Word2Vec 的自然语言处理分类
Photo by Victoria Kubiaki on Unsplash
介绍
我以前体验过机器学习算法,用于不同的问题,如货币汇率预测或图像分类。我最近在做一个文本分类的项目,我读了很多关于这个主题的文献。NLP(自然语言处理)的例子很吸引人。当你开始思考的时候,你意识到没那么简单,在分类之前,还有这个问题:
“一个算法到底是怎么读懂文字的?”。一种解决方案是将单词转换成向量,用数字来表示它们。这种解决方案并不新鲜,几年前,一篇文章提出了 Google Word2Vec 无监督算法:向量空间中单词表示的高效估计(Mikolov & al。,2013) 。可以找到许多关于它的文档,但本文的重点是从头到尾详细介绍如何构建用于文本分类的机器学习算法。我将演示如何将 Word2Vec 与预训练的 Google 新闻数据集一起使用,以及如何用您的数据自己训练它。然后,我将演示两种技术;一个是做你的文档词的意思,另一个是保持你的数据像他们一样,这保留了更多的信息,但它有点复杂,需要更多的时间来训练。所以这取决于你,你认为在你的情况下和你的数据下什么更好。
1 首先我们需要导入数据
对于这一步,确保包含您的评论的文件夹与笔记本在同一个文件夹中。
我用的数据是可以在这里找到的影评:影评。我拿的是“句子极性数据集 1.0 版”。我拿的是“句子极性数据集 1.0 版”。我选择这些是因为我可以将我的结果与论文用于句子分类的卷积神经网络(Yoon Kim,2014) 进行比较。本文的优势在于为该数据集提供了一个神经网络,但它将其结果与表 2 中的其他算法进行了比较,这非常有趣,因为我们有许多来自不同论文的算法来比较我们的结果。
提取你下载的带有链接的文件。
好了,现在我们基本上有一个名为**“rt-polarity data”的文件夹,其中有两个名为“rt-polarity . neg”和“rt-polarity . pos”**的文件。负面评价和正面评价)。我们在这里的工作将是把每一个数据放入熊猫数据框进行分析。开始将它们转换成 CSV 文件。
现在,我们正在创建数据的“标签”, 1 表示正面评价,0 表示负面评价。
现在结果应该如下
Figure 1: Our Dataframe, with the text of the review, and its label
好的,看起来很棒!现在,我们将每个评论都放入我们的 pandas dataframe,命名为“评论”,并带有特定的标签(1 表示正面评论,0 表示负面评论)。
2 使用 Word2Vec 查看我们单词之间的相似性距离
ord2Vec 是一个很好的用于单词嵌入的神经网络模型。它主要用于词语的相似上下文。我们将在我们的数据上训练模型,使我们所有的词之间有一个距离,以查看哪些词在语义上彼此接近。还有其他型号,但我选择这款有两个原因:
- 这是尹金在他的文章中使用的
- 是 Google 开发的模型,似乎是完全推荐的,文档也很容易找到,而这篇文章:向量空间中单词表示的高效估计(Mikolov & al,2013) 很好地解释了所有的过程。
2.1 标记化
现在,你的数据帧应该是这样的
Figure 2 : The dataframe, with the tokens
对于培训来说,重要的是将每个评论表示为单词列表,如“令牌”列中所示。
2.2:使用预先训练好的谷歌新闻数据集
首先你需要在这里下载数据集:谷歌新闻数据集。然后,将其提取到您的文件夹中。我将它提取到名为“model”的子文件夹中
就这么简单!现在你已经有了一个名为**“w2v _ model”**的模型,它经过了训练,包含了数据集中用向量表示的每个单词。
2.2.1 根据您的数据训练模型
你也可以用你的个人数据来训练这个模型。但是,我不建议对小文档使用这种技术,因为 Word2Vec 不能正确地捕捉单词的上下文,并且它不会给出令人满意的结果。我在这篇文章的数据上进行了测试,结果明显比预先训练的 Google Word2Vec 要好。在另一个平均每个文档 200 个单词的数据集上,它更可靠,并且在某些情况下显示出比预训练模型更好的结果。
我们将把工作分成 3 个步骤
Word2Vec()
。用模型的所有参数初始化模型- 从一系列句子中构建词汇
.train()
我们训练我们的模型
2.3 结果
现在,我们可以用一些单词来测试我们的模型,看看哪些单词与它们最相似。
我们用以下方式进行测试:
- 电影
- 小说
- 好的
对于“好”这个词,我有这些结果
Figure 3 : Words that are the most similar to “good”
这些结果是通过预先训练的谷歌新闻数据集获得的。
然而,我们可以看到,该模型并不完美,没有捕捉到单词的语义,因为我们有[很好、很差、很棒、不错]。这可能是一个问题,因为在这里好在“语义上”接近坏。事实上,它们可以在相同的上下文中使用,但它们的含义是不一样的。
2.5 一点点数据可视化
上面是我们数据集的一万字的图。语义相近的,在地图上是挨着的。我用散景让地图变得动态,我们可以和它互动,你可以把鼠标放在一个点上,看看对应的单词。我们现在可以清楚地看到所有单词之间的关系,以及哪些是近的或远的。
Figure 4 : Bokeh chart of 10000 words of our dataset
3 对数据做一点工作
3.1 列车测试分割
现在我们有了数据框架,我们需要将数据分成一个训练变量和一个测试变量。通过训练,我们的算法将学习它的参数,通过测试,我们将测试它们。
我们将训练和测试分开,以查看是否存在不过度拟合的问题,这在深度学习领域是经常出现的。这意味着我们的模型对它所学习的数据有很好的结果,但它有一个概括的问题,并且它在其他数据集上会有不好的结果,这显然不是目标。
3.2 构建向量
我们在这里做的是使用来自sklearn
的TfidfVectorizer
。该功能反映了文档中单词的强度。
我们使用行tfidf = dict(zip(vectorizer.get_feature_names(), vectorizer.idf_))
将所有的单词放入一个名为tfidf
的向量中,如果你执行它,你可以在上面看到。这是我在 Ahmed BESBES 的博客上发现的一个提示。这真的很有趣,值得一读。
现在只是为了好玩,为了形象化,我用 WordCloud 来描绘我们字典中最重要的 100 个单词。我们可以看到像戏剧、电影、场景和故事这样的词,它们显然对关于电影评论家的数据集很重要。我使用了 Ahmed BESBES 的另一个博客来使用这个库。
Figure 5 : The most “important” words in our corpus
现在我们将构建一个函数来计算给定评论家的“平均值”。我们的 w2v_model 给了我们哪些单词彼此接近,所以对于每一个单词,我们都将它们乘以它们在“字典”中的重要性:w2v_model[word].reshape((1, size)) * tfidf[word]
。
注意:我们使用 reshape 函数,因为我们对语料库的每个文本都这样做,所以例如在X_train
中我们有 8529 个文本,如果我们对其应用该函数,我们将得到一个二维形状矩阵(8529,300)。
- 8529 代表我们语料库中的文本数量
- 300 代表 Word2Vec 创建的向量的大小。
就这样,现在我们把它除以观察次数,我们很好地得到了所有这些的平均值。
该计算可以恢复如下:
Figure 6: Formula of the mean of the words by ponderation with their Tf-idf
其中:
n
是文本中的字数- 对于给定的字 i ,向量 Word2Vec 的大小是 300
Ti
是给定字 i 的值 tfidf
现在我们将这个函数应用于我们的数据。
所以我说过,buildWordVector
有两个参数,令牌,和大小。尺寸是 300 因为 word2vec 模型我们得到了 300 的形状。对于标记,它将循环增加,以覆盖我们的训练语料库的所有 8529 个文本和我们的测试语料库的 2133 个文本。
4 第一个神经网络
第一个神经网络只是一个简单的人工神经网络,只有两个密集层,为了避免过拟合,压差为 0.7。对于这一个,我们把给定评论中每个词的平均向量作为输入。
4.1 构建神经网络
下面是这个简单分类器的特征。
- 致密层数: 2
- 激活函数: relu,和 sigmoid 为最后一个密集层
- 辍学: 0.7
- 优化器: Adadelta
- **损失:**二元交叉熵
Figure 7 : summary of the classifier
4.2 训练神经网络
现在,我们使用批量为 50 的训练数据和 20 个时期来训练我们的神经网络。
做更多的历元似乎不会改变精度。使用不同的 batch_size 和时期数进行网格搜索以查看更好的参数可能是有用的。
最后,我们绘制训练的历史以观察演变,并比较训练和测试预测
Figure 8: accuracy and loss for the first classifier
最终,我们的训练精度为 0.8342,测试精度为 0.7286。这并不坏,重要的是要注意,我们没有太多的过度拟合。
5 A 卷积神经网络
CNN 主要用于图像分类,因为它可以通过模式的过滤图来识别模式。但在 2014 年,当 Yoon Kim 发表他的文章时,他表明它们也可以用于文本分类。事实上,这个想法并不完全疯狂,因为句子也有模式。
5.1 构建神经网络
首先,我们试图找到所有的参数来构建我们的神经网络。这将是一个 CNN,但不是给他一个句子中所有单词向量的意思,我们会给他一个给定句子中所有的单词向量。
还有,结构有点变化,每层神经元更多。
Figure 9: structure of our CNN
我们的神经网络与我上面描述的 Yoon Kim (2014)构建的神经网络相同。
- 卷积层数: 3
- 致密层数: 2
- **特征图数量:**每卷积 128
- 激活功能: relu,和最后一个致密层的 sigmoid
- 滤镜尺寸: 3、4、5
- 辍学: 0.5
- 优化器: Adadelta
- **损失:**二元交叉熵
这个 CNN 和 Yoon Kim 用的差别不大:
1。他刚有了 1 密层
2。他从来没有用过乙状结肠。他在每个卷积中使用了 100 个特征图,而不是 128 个
然而,我有更好的结果与那些小的变化,所以我保持他们那样。
为了构建它,我们需要一些参数,嵌入维数(word2vec 向量的大小),vocab 大小的最大值(我们有多少个唯一的词),以及最大序列长度(每次评论的最大字数)。
下面的代码为您提供了所有这些参数,如果您用另一个数据集测试它,只需用代码的结果更改三个变量:
现在,我们创建将在 CNN 中使用的训练和测试输入。对于少于最大字数的每个文档,我们用“0”来完成它们。这并没有改变我们的结果,因为 CNN 识别模式,无论在某一点或另一点,模式仍然是相同的。例如,对于一个图像,这意味着如果一个图像比其他图像小,我们将把它的黑色边框。这不会改变形象。
5.2 定义 CNN
汇总的结果应该如下所示:
Figure 10: Summary of the CNN
让我们进行 10 个纪元的训练课程,再来一次批量 50 个!
Figure 11: accuracy and loss for the cnn
在 10 个时期结束时,训练集的准确度为 0.915,测试集的准确度为 0.7768。我们有一点过度拟合,验证损失相当不稳定,但结果在这里。我用更多的纪元来训练它,但这似乎是我们能做到的最好的了。
6 个结论
我们可以清楚地看到 CNN 更适合这个任务,用我的其他数据帧,我个人也有同样的结果。
但是,它仍然有一个不方便的地方,它要更深,有更多的参数,并且需要更多的时间来训练。对于这个小数据集,差异并不重要,但我必须根据我的工作数据来训练它,简单的分类器需要 13 分钟训练,而 CNN 需要 5 个小时!所以要用哪个由你自己决定。
这两个分类器仍然显示出一些不错的结果,我注意到它们拥有的数据越多,文档的长度越重要,它们就越好。对于一个包含 70 000 个数据和最大长度为 2387 个文档的数据集,我的测试精度是 0.9829,这非常令人鼓舞!
7 个视角
我有两个主要的想法去尝试更好的结果。首先,使用第一个分类器,我们可以使用另一个更复杂的神经网络,如递归神经网络(CA-:使用上下文对齐的递归神经网络对句子相似性建模(陈,胡& al ., 2018).)或现在开始使用的注意网络(用于文档分类的分层注意网络(Yang & al .,2016) )。
第二个想法是针对单词嵌入,2018 年谷歌展示了一个新的模型,叫做 BERT ( BERT:用于语言理解的深度双向转换器的预训练(Devlin,Chang & al。,2018) )谁更有优势使用分割令牌。例如,如果我们的数据中有单词考古学家,它可以记住“考古”,当像“考古”这样的单词出现时,它会知道它与考古学家有关,而 word2Vec 会忽略它不认识的单词。
自然语言处理—事件提取
从新闻文章中提取事件
每天生成的文本量令人震惊。数以百万计的数据以新闻文章、博客、消息、手稿等形式发布,自动组织和处理它们的能力变得不可或缺。
随着神经网络算法的改进,计算机能力的显著提高,以及对综合框架的轻松访问,自然语言处理似乎从未如此吸引人。它的一个常见应用称为事件提取,这是一个收集文本中发现的周期性事件的知识的过程,自动识别关于发生了什么以及何时发生的信息。
例如:
2018/10-唐纳德·特朗普总统的政府禁止各国进口伊朗石油,七个国家除外。
2019/04-美国国务卿迈克·蓬佩奥宣布,他的国家将不会在最后期限后开放更多的例外。
2019/05-美国结束了允许各国从伊朗进口石油而不受美国制裁的豁免。
这种将信息置于背景中的能力让我们能够将时间分布的事件联系起来,吸收它们的影响,以及一系列事件如何随着时间的推移而展开。这些有价值的见解推动了像 EventRegistry 和 Primer 这样的组织。AI ,为不同的市场领域提供技术。
在本文中,我们将构建一个简单的事件提取脚本,它接收新闻提要并输出事件。
获取数据
第一步是收集数据。它可以是任何类型的文本内容,只要它可以在时间线中表示。这里我选择使用 newsapi ,这是一个简单的新闻源 api,免费开发者计划每天最多 500 个请求。以下是为处理请求而构建的函数:
给定一个特定的查询,最后一个函数返回大约 2,000 篇文章的列表。我们的目的只是提取事件,因此,为了简化过程,我们只保留标题(理论上,标题应该包含新闻背后的核心信息)。
这给我们留下了一个类似下面的数据框,包括日期、描述和标题。
赋予句子意义
准备好标题后,我们需要用机器可读的方式来表示它们。注意,我们在这里跳过了整个预处理阶段,因为这不是本文的目的。但是如果你从 NLP 开始,确保在应用模型之前包括那些基本的预处理步骤→ 这里有一个很好的教程。
为了给独立的单词赋予意义,从而给整个句子赋予意义,让我们使用 Spacy 的预训练单词嵌入模型( en_core_web_lg )。或者,您可以使用任何预先训练的单词表示模型(Word2Vec、FastText、GloVe……)。
默认情况下,Spacy 将句子的向量视为其标记向量之间的平均值。这是一种简单的方法,不考虑单词的顺序来编码句子。对于更复杂的策略,看看像 Sent2Vec 和 SkipThoughts 这样的模型。这篇关于无监督摘要的文章很好地介绍了跳过思想。
现在,让我们保持简单:
因此,每个标题都有一个第 300 维的数组,如下所示:
聚集这些向量
即使我们是通过搜索词来过滤文章,不同的主题也可能出现在同一个查询中。例如,搜索“巴黎”可能会得到:
一场毁灭性的火灾后,巴黎团结起来
或者:
巴西足球传奇人物贝利在巴黎住进医院
为了对不同主题的文章进行分组,我们将使用聚类算法。
在这个特殊的例子中,我想尝试 DBSCAN 算法,因为它不需要预先指定集群的数量。相反,它自己决定要创建多少个集群,以及它们的大小。
ε参数决定了两个样本之间的最大距离,使它们被视为处于相同的邻域中,这意味着如果 eps 太大,将形成较少的聚类,但如果太小,大多数点将被分类为不属于某个聚类,这也将导致一些聚类。下图显示了 epsilon 的集群数量:
调整 eps 值可能是最微妙的步骤之一,因为结果会根据您认为句子相似的程度而有所不同。正确的值将通过实验得出,试图保留句子之间的相似性,而不会将相近的句子分成不同的组。
一般来说,因为我们希望在同一个集群中得到非常相似的句子,所以目标应该是返回更多类别的值。因此,我选择了一个介于 0.08 和 0.12 之间的数字。查看 Scikit Learn 文档,了解更多关于该参数和其他参数的信息。
以下是一些集群及其大小:
-1 类代表没有聚类的句子,其余为聚类索引。最大的集群应该代表评论最多的主题。
让我们来看看其中的一个集群:
转换成事件
下一步是按时间顺序排列这些句子,并根据相关性进行过滤。这里,我选择每天显示一篇文章,这样时间线就清晰一致了。
由于每天都有很多关于同一主题的句子,我们需要一个标准来从中选择一个。它应该是最能代表事件本身的,也就是那些标题试图传达的意思。
为此,我们可以对每日标题进行聚类,并为每个聚类选择离聚类中心最近的标题。给定一系列句子,下面是查找中心向量的函数:
s
最后,使用 Plotly,我们可以想出一种方法来绘制一个方便的时间线图:
就是这样。使用 2000 篇随机文章,我们制作了一个脚本来提取和组织事件。想象一下,每天将这种技术应用到数百万篇文章中会有多有用。以股票市场和每日新闻的影响为例,我们可以开始窥视事件提取的价值。
可以包括几个组件来改善结果,比如适当地预处理数据,包括词性标注和 NER ,应用更好的句子到向量模型,等等。但是从这一点出发,可以很快达到一个理想的结果。
感谢你阅读这篇文章。这是一篇关注自然语言处理和事件提取的文章。如果你想了解更多关于数据科学和机器学习的知识,请确保关注我的个人资料,并随时留下任何想法、评论或担忧。
TF IDF | TFIDF Python 示例
Photo by Raphael Schaller on Unsplash
自然语言处理(NLP)是人工智能的一个子领域,处理理解和处理人类语言。鉴于机器学习的新进展,许多组织已经开始将自然语言处理应用于翻译、聊天机器人和候选人筛选。
不再拖延,让我们深入一些代码。首先,我们将导入必要的库。
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
在本文中,我们将使用两个简单的文档,每个文档包含一个句子。
documentA = 'the man went out for a walk'
documentB = 'the children sat around the fire'
机器学习算法不能直接处理原始文本。相反,文本必须转换成数字向量。在自然语言处理中,从文本中提取特征的一种常见技术是将文本中出现的所有单词放在一个桶中。这种方法简称为袋字模型或弓。它被称为一个 【袋】 的单词,因为任何关于句子结构的信息都丢失了。
bagOfWordsA = documentA.split(' ')
bagOfWordsB = documentB.split(' ')
通过将单词包转换为一个集合,我们可以自动删除任何重复的单词。
uniqueWords = set(bagOfWordsA).union(set(bagOfWordsB))
接下来,我们将为语料库(文档集合)中的每个文档创建一个单词及其出现次数的字典。
numOfWordsA = dict.fromkeys(uniqueWords, 0)for word in bagOfWordsA:
numOfWordsA[word] += 1numOfWordsB = dict.fromkeys(uniqueWords, 0)for word in bagOfWordsB:
numOfWordsB[word] += 1
单词袋方法的另一个问题是它没有考虑噪音。换句话说,某些单词被用来构成句子,但没有给文本增加任何语义。例如,英语中最常用的单词是*,它代表了所有书面或口头单词的 7%。考虑到文本中包含单词和,你无法对文本做出任何推断。另一方面,像 good 和 awesome 这样的词可以用来确定一个评级是否是正面的。*
在自然语言处理中,无用词被称为停用词。python 自然语言工具包库提供了一个英文停用词列表。
*from nltk.corpus import stopwordsstopwords.words('english')*
通常,当以理解文本为目标构建模型时,您会看到所有停用词都被删除了。另一种策略是使用 TF-IDF 对单词的相对重要性进行评分。
词频(TF)
一个单词在文档中出现的次数除以文档中的总单词数。每个文档都有自己的词频。
以下代码在 python 中实现了词频。
*def computeTF(wordDict, bagOfWords):
tfDict = {}
bagOfWordsCount = len(bagOfWords)
for word, count in wordDict.items():
tfDict[word] = count / float(bagOfWordsCount)
return tfDict*
下面几行计算了我们每个文档的词频。
*tfA = computeTF(numOfWordsA, bagOfWordsA)
tfB = computeTF(numOfWordsB, bagOfWordsB)*
逆数据频率(IDF)
日志中的文档数除以包含单词 w 的文档数。逆数据频率决定了语料库中所有文档中稀有词的权重。
以下代码在 python 中实现了反向数据频率。
*def computeIDF(documents):
import math
N = len(documents)
idfDict = dict.fromkeys(documents[0].keys(), 0)
for document in documents:
for word, val in document.items():
if val > 0:
idfDict[word] += 1
for word, val in idfDict.items():
idfDict[word] = math.log(N / float(val))
return idfDict*
所有文件的 IDF 计算一次。
*idfs = computeIDF([numOfWordsA, numOfWordsB])*
最后,TF-IDF 就是 TF 乘以 IDF。
*def computeTFIDF(tfBagOfWords, idfs):
tfidf = {}
for word, val in tfBagOfWords.items():
tfidf[word] = val * idfs[word]
return tfidf*
最后,我们可以计算语料库中所有单词的 TF-IDF 分数。
*tfidfA = computeTFIDF(tfA, idfs)
tfidfB = computeTFIDF(tfB, idfs)df = pd.DataFrame([tfidfA, tfidfB])*
我们可以使用 sklearn 提供的类,而不是自己手动实现 TF-IDF。
*vectorizer = TfidfVectorizer()vectors = vectorizer.fit_transform([documentA, documentB])feature_names = vectorizer.get_feature_names()dense = vectors.todense()denselist = dense.tolist()df = pd.DataFrame(denselist, columns=feature_names)*
这些值略有不同,因为 sklearn 使用了平滑版本的 idf 和各种其他小优化。在具有更多文本的示例中,单词的得分将大大降低。**
面向自动化特征工程的自然语言处理
如何使用 Featuretools 应用 nlp-primitives 库。
当试图在机器学习管道中利用真实世界的数据时,经常会遇到文本。文本数据可以包含许多有价值的信息,但经常被忽略,因为很难将文本翻译成算法可以解释的有意义的数字。
在 Featuretools 、、原语函数、用于为不同类型的数据自动创建特征,使机器学习模型能够充分利用你的数据集中的数据。
在本文中,我探索了使用 nlp-primitives 库从文本数据中创建特征,通过使用一个示例数据集来研究机器学习模型中的这些附加特征。然后,我解释为什么这些原语对模型的准确性有如此大的影响。
一个使用 nlp 原语的机器学习演示
在这个演示中,我将使用来自这个 Kaggle 数据集的数据,该数据集包含旧金山地区 57 家餐馆的 100 条评论。数据集相对较小,但足以用 Featuretools 和 nlp-primitives 库演示特征工程。您可以使用这个库中的Jupyter 笔记本继续学习。
首先,让我们确定问题:根据每个评论者的反馈,确定他们对餐厅的看法。该模型的成功与否将取决于它能在多大程度上准确预测每个评审者根据给定数据和评审给出的评级。在数据集中,评论有 5 个可能值,从 1 星到 5 星,所以问题是一个 5 类分类问题。
为了评估 NLP 原语的有效性,我还使用没有这些新原语函数的深度特征合成 (DFS)创建了一个基线特征矩阵,以便我可以看到这些新原语的有效性。利用这个基线特征矩阵,我创建了一个机器学习模型,准确率大约为 50%。
baseline_feature_matrix, baseline_features = ft.dfs(entityset=es,
target_entity='reviews',
verbose=True,
ignore_variables=ignore)**built 33 features**base_rfc = RandomForestClassifier(n_estimators=100,
class_weight = "balanced",
n_jobs=-1)
base_rfc.fit(baseline_train_fm, baseline_y_train)
base_rfc.score(baseline_test_fm, baseline_y_test)**0.5156462585034014**
这个模型预测大多数评论属于最常见的评论类别,所以它的预测不是很准确,正如你在下面的混淆矩阵中看到的。
在基线模型和使用 nlp 原语的模型之间,只有一个因素发生了变化:NLP 原语库的使用。
trans = [DiversityScore, LSA, MeanCharactersPerWord,
PartOfSpeechCount, PolarityScore, PunctuationCount,
StopwordCount, TitleWordCount, UniversalSentenceEncoder,
UpperCaseCount]
features = ft.dfs(entityset=es, target_entity='reviews',
trans_primitives=trans, verbose=True,
features_only=True, ignore_variables=ignore,
drop_contains=drop_contains, max_depth=4)**Built 333 features**
通过 DFS 调用中的这个小变化,生成的特性数量增加了 10 倍。
这个库非常容易合并,只需要几行额外的代码就可以导入库和原语,然后将这些原语添加到ft.dfs
函数用来创建特征的默认原语中。在基线模型和 nlp-图元模型中,DFS 用于查找特征,尽管 NLP-图元具有修改的深度场,允许 DFS 创建堆叠在 NLP 特征之上的图元。
在运行 DFS 并创建结果特征矩阵后,我们可以将数据分成训练集和测试集,并在 sklearn 机器学习模型中使用这些集来测试它们的准确性。
vot = VotingClassifier(voting='soft',
estimators=[('lgr', lgr),('rfc', rfc),
('hgbc', hgbc)],
weights=[3, 1, 6])
vot.fit(train_feature_matrix, y_train)
vot.score(test_feature_matrix, y_test)**0.6925170068027211**
当使用 nlp-primitives 库时,模型能够实现大约 70%的准确性,混淆矩阵被准确地分布(深蓝色表示猜测),大多数不正确的猜测非常接近实际答案(1-由更明显的对角线上的深蓝色表示)(完美的算法将在向下的对角线上有 1,表示预测和真实标签一致,在每个其他类别中有 0-了解更多关于混淆矩阵的信息此处)。
这两个模型使用相似的训练和测试步骤(基线模型使用稍微不太复杂的函数,因为更复杂的函数不会改变准确性),但是具有 NLP 功能的模型的准确性比基线高大约 40%。由于其他一切都保持不变,很明显 NLP 原语库是准确性大幅提高的原因。此外,当我们检查特性重要性时,我们看到使用 NLP 原语的特性排名最高(更多详细信息,请参见笔记本)。
为什么这些原语会有所不同?
数据必须格式化为数字,以便机器学习模型从中“学习”。文字很难放进数字,或者至少很难放进数字而不失去很多意义。例如,获得一段文本的字数是相当简单的,但是,通常这并不是一个足够的意义度量。尽管这有时可能是一个有用的功能,但文本的意义远不止它包含的字数。
那么,解决办法是什么呢?如何以有意义的方式将文本编码成数字?一种解决方案是将文本的含义矢量化。NLP 原语,如 UniversalSentenceEncoder、LSA(潜在语义分析)和 PartOfSpeechCount 都使用这种方法。它们都是多输出原语,这意味着它们接受一个字段并创建一个具有多个字段的要素。在这种情况下,这些字段表示向量的维数。在下面的例子中,每个文本字符串对应两个输出,因为 LSA(潜在语义分析)为每个给定的字符串创建一个长度为 2 的向量。
from nlp_primitives import LSA
import pandas as pd
data = ["hello, this is a new featuretools library",
"this will add new natural language primitives",
"we hope you like it!"]
lsa = LSA()
pd.DataFrame(lsa(data).tolist()).T
在下一个示例中,原语 PartOfSpeechCount 为每个输入生成 15 个值。这个向量的每个维度代表一个词性,以及该词性在输入文本字段中出现的次数。
from nlp_primitives import PartOfSpeechCount
data = ["hello, this is a new featuretools library",
"this will add new natural language primitives",
"we hope you like it!"]
pscount = PartOfSpeechCount()
pd.DataFrame(pscount(data).tolist()).T
这些原语以这样一种方式对向量中文本字段的含义进行编码,即具有相似含义的两个文本字段具有相似的向量,即使它们由不同的单词组成。这使得这些方法特别有用,因为以类似方式编码类似含义的能力允许机器学习模型学习特定向量的结果,并将该向量的结果与类似向量相关联。
然而,处理许多输出常常是具有挑战性的,尤其是当试图堆叠原语时——将一些原语的输出用作其他原语的输入。当存在许多实体或数据源时,这会产生更多的信息。Featuretools 很好地处理了这一点,这使用户能够跨实体以及在实体内收集信息,以最大限度地利用当前数据。Featuretools 自动【堆叠】图元的能力进一步增强了这一点,甚至在特征工程步骤中进一步扩展了任何单个图元转化特征的能力。
关键要点
- **NLP-primitives 库在处理文本数据时增强了模型的准确性。**这种额外的准确性源于对文本含义的编码,而不仅仅是计算简单的描述性指标。
- **使用正确的工具使机器学习过程变得更容易。**当我们修改了几行代码来合并 nlp-primitives 库时,准确性提高了,而代码的复杂性保持不变。
- **正确性可以通过多种方式进行评估。**当一个模型不准确的时候,理解哪里出了问题是很重要的——它仅仅是错误的(像基线模型)还是错误的,但接近正确的(像 nlp-primitives 模型)?
最后的想法
这个库已经发布,可以独立安装或者通过使用pip
的功能工具安装。但是,它仍处于发展的初级阶段,我们欢迎任何关于它的反馈。此外,自然语言处理领域是一个快速发展的领域,所以如果您看到一个添加新原语的机会,请作为 GitHub 问题提出建议,或者尝试自己创建——该库是开源的,因此任何人都可以做出贡献!
原载于 2019 年 8 月 23 日https://blog.featurelabs.com。
“神经概率语言模型”中的自然语言处理
Credit: smartdatacollective.com
这是 PLN(计划):在 Bengio 等人于 2003 年提出的名为 NPL(神经概率语言)的模型中,通过概率的镜头讨论 NLP(自然语言处理)。论文发表的那一年对于一开始就考虑是很重要的,因为它是我们如何使用计算机分析人类语言的历史上的一个支点时刻。诺姆·乔姆斯基的语言学可以被看作是像机器一样使用人类大脑并系统地将语言分解成越来越小的成分的努力。他从句子开始,到单词,然后是语素,最后是音素。计算机化利用了这个强大的概念,并使它成为对人类更重要的东西:它从与个人相关开始,到团队,然后到公司,最后到政府。乔姆斯基博士真正改变了我们交流的方式,这种影响至今仍能感受到。语言学刚引入的时候很强大,今天也很强大。N-gram 分析,或者任何一种计算语言学,都来源于这位伟人,这位先行者的工作。本博客将总结本吉奥小组的工作,他们是思想领袖,高举知识的火炬,推进我们对自然语言以及计算机如何与之交互的理解。
自 2003 年以来,人工智能已经发生了巨大的变化,但本文提出的模型抓住了它为什么能够起飞的本质。自从这篇论文发表以来,机器学习和深度学习都已经成为人工智能经典的一部分,随着计算能力的不断增长,它们变得越来越重要。数据科学是多个领域的融合,今天我们将考察作为该学科基石的一个领域:概率。本文提出的概率分布模型,本质上是我们提高处理自然语言能力的主要原因。
英语,被认为是所有字母语言中单词最多的,是一个概率噩梦。甚至在最基本的句子中排列单词组合的可能性也是不可思议的。我们正面临着所谓的维度的诅咒。为了更具体地说明这一点,作者提供了以下内容:
…如果想要对自然语言中 10 个连续单词的联合分布进行建模,并且词汇量 v 的大小为 100,000,则可能存在 100,000^10 1 = 10^50 1 自由参数。
在数据驱动的自然语言处理任务中,实际上存在无限的离散变量,因为英语词汇的数量以指数形式超过 100K。当试图比较被分成训练集和测试集的数据时,你怎么能期望提出一个容易概括的语言模型呢?你的数据中的这两个部分几乎肯定是非常不同的,非常不可概括的。你被模型中大量的可能性,大量的维度所诅咒。能做些什么?
本吉奥小组的创新不是通过使用神经网络,而是通过大规模使用它们。语言学及其创始人诺姆倾向于了解一个词如何与句子中的所有其他词相互作用。Bengio 等人专注于学习单词序列分布的统计模型。该研究论文首先通过不考虑给定单词如何与同一个句子中的其他单词相似,而是考虑可以填充给定单词角色的新单词来改进 NLP。其次,他们考虑了 n 元语法方法,超出了单元语法( n = 1)、二元语法( n = 2)甚至三元语法(研究人员通常使用的 n )直到 5 的 n 。
n 元模型的数学公式如下:
该公式用于为要预测的下一个单词构建条件概率表。当对 NLP 建模时,可以通过利用单词顺序,以及通过认识到单词序列中时间上更接近的单词在统计上更具依赖性,来提高对抗维数的几率。在所讨论的上下文中,这最终意味着什么?这是在解决什么问题?提出的语言模型减少了维数灾难,增加了不便。也就是说,计算和存储复杂性是以线性方式而非指数方式增长的。它通过学习每个单词的特征向量来表示相似性,并通过神经网络学习单词如何连接的概率函数,从而改进了过去的工作。让我们仔细看看所说的神经网络。
我们现在看到的是一种叫做多层感知器的东西。那些层是什么?三个输入节点构成了底部的基础,由所研究文本上下文中单词的索引提供。中间标记为 tanh 的层代表隐藏层。Tanh 是一种称为 hyberbolic tangent 的激活函数,是 s 形的,有助于减少在为正在处理的语言赋值时模型“卡住”的机会。**这是怎么回事?**在该研究团队建立的系统中,负值很大的值被赋予非常接近-1 的值,反之亦然。只有零值输入被映射到接近零的输出。最上层是输出,即 softmax 函数。它用于将我们的值范围带入概率领域(在从 0 到 1 的区间内,其中所有向量分量的总和为 1)。
也不要忽略将输入直接连接到输出的绿色虚线。该特性的可选包含在本文的结果部分中提出。它提供了一个有趣的权衡:包括输入和输出之间的直接连接导致训练时间减半(10 个时期收敛而不是 20 个)。没有它们,模型通过隐藏层中形成的更紧密的瓶颈产生更好的概括。
如果一个句子中包含的单词与之前观察到的单词相似,则该句子有可能获得高概率(即使模型之前从未遇到过它)。难就难在:诺姆·乔姆斯基和后来的语言学家受到批评,说他们发展的系统太脆弱了。这种方法为一种新的学习——深度学习——奠定了基础。当与向量语义结合使用时,这确实是强大的东西。通过这篇论文,Bengio 团队打开了通往未来的大门,并帮助开创了一个新时代。一个 AI 的时代。
作品引用:
一个神经概率语言模型,Bengio 等人。
试图在 5 篇论文中描述 NLP 的历史:第二部分。
https://theclevermachine.wordpress.com/tag/tanh-function/
银行业务中的自然语言处理:当前应用
银行应用自然语言处理的三个领域
银行正在使用一种称为自然语言处理(NLP)的人工智能分支来自动化某些文档处理、分析和客户服务活动。三种应用包括:
- 智能文档搜索:在大量扫描文档中查找相关信息。
- 投资分析:自动化收益报告和新闻的常规分析,以便分析师可以专注于阿尔法世代。
- 客服&洞察:部署聊天机器人回答客户查询,了解客户需求。
我们将讲述银行在这些领域所做工作的真实例子。首先,让我们回顾一下自然语言处理的能力。
自然语言处理导论
自然语言处理(NLP) 是人工智能的一个分支,使计算机能够理解人类的语言,并做出类似的反应。这包括训练计算机处理文本和语音,并在上下文中解释单词、句子和段落的含义。
人机交互
人机“对话”可以分解如下(我们稍后会谈到具体的人工智能方法):
- 我们提供文本或语音输入(例如,键入聊天机器人界面或与智能扬声器交谈)。
- 计算机将文本/语音转换成它能理解的格式(例如,将语音转换成文本,将单词转换成矢量)。这有助于计算机对不同的单词进行聚类和分类。
- 计算机使用自己的数据集计算出意思和上下文。
- 计算机确定一个适当的反应,并将其转换成我们理解的文本或语音,并对我们做出反应。
我们每天都与使用自然语言处理的应用程序进行交互:
- 谷歌翻译:我们输入文本和语音,谷歌为我们翻译。
- Gmail 智能撰写:你可能会注意到 Gmail 会提示你已经开始输入的句子的剩余部分。此功能使用电子邮件主题和以前的电子邮件来建议相关文本。有点吓人,但也有点酷。
- 语法上:你使用的流行的语法检查工具,因为它比微软 Word 的拼写检查好得多。
- 智能音箱:不,你和 Alexa 的对话并不神奇(抱歉)。
理解、处理和生成语言
自然语言处理实际上是一个包含两种相关方法的总称:自然语言理解和自然语言生成。
自然语言理解(NLU)指出文本和语音背后的含义。把这个当成阅读或者听力。这包括从人类那里获取非结构化的文本和语音输入,并将其转换为计算机可以理解的结构化格式。例如,当你向 Alexa 请求天气预报时,它会使用自然语言理解来判断你在说什么。
自然语言生成(NLG)是指计算机生成的文本和语音。NLG 将结构化数据转化为人类能够理解的文本和语音。继续我们之前的例子,Alexa 在回应“今天天气晴朗”时使用自然语言生成。你想订购太阳镜吗?
用于自然语言处理的人工智能方法
自然语言处理经常与其他人工智能方法一起使用,如神经网络、深度学习和光学字符识别。两个流行的自然语言模型是 Word2vec 和单词包。
在没有获得技术的情况下,神经网络是机器学习的子集。当用于自然语言处理时,它们可以处理文本,对单词进行分类,对相似的单词进行聚类,并将单词和短语与含义相关联。也使用深度学习方法(即多层神经网络),如递归神经网络。
光学字符识别(OCR)使计算机能够识别扫描文档中的文本。OCR 可以与自然语言处理一起使用,以分析扫描的文档或手写文本。
单词袋和相关算法是流行的自然语言技术,通过类别或类型对短语和文档进行分类。单词包简单地统计每个单词在文档中出现的频率(计数)。该算法然后比较文档并确定每个文档的主题。这可以用来训练神经网络。Gmail 的 Smart Compose(前面提到过)使用了谷歌的单词包和递归神经网络模型。搜索引擎也使用这些技术。
Word2vec 是另一种流行的自然语言模型。它是一个两层神经网络对文本进行分类以确定含义。它将单词转换成计算机可以理解的数学“向量”。矢量转换是必需的,因为神经网络更好地处理数字输入。
给定足够大的数据集,代表相似单词的向量被分组在一起——相似单词被数学地检测。如果部署得当,Word2vec 可以根据过去的外观高精度地推断单词含义。这对于文档搜索、情感分析,甚至建议接下来应该用哪些词来完成一个句子都很有用。
银行如何使用自然语言处理
Image by Author
银行可以对大量文本和语音数据应用自然语言处理,以提取信息、获得洞察力并简化手动任务。虽然节省时间和成本是显而易见的好处,但识别关键信息的能力(众所周知的大海捞针)可以成为一个有竞争力的差异制造者。
以下是银行应用自然语言处理的三个领域。
智能文档搜索
摩根大通的 COIN (合同智能)软件使用自然语言处理来帮助银行的法律团队搜索和审查大量的法律文件。
据报道,COIN 每年可以为银行的法律团队节省 360,000 小时或 15,000 天的文档搜索任务。例如,它可以提取关键数据和条款来帮助信贷员审查商业贷款协议。
COIN 显然受过训练,能够识别银行法律团队标记为重要的文档中的关键信息(属性)。这使得软件能够从结构不同的文档中提取关键信息。该银行声称,它在几秒钟内从 12,000 份商业信贷协议中提取了 150 个相关属性。
该软件的工作是不公开的,因为是内部使用。我们可以推测,它可以由自然语言处理(在文档中搜索)、光学字符识别(识别扫描文档中的字符)和机器学习(对文档中的数据进行分类和聚类,并随着时间的推移改进搜索算法)来驱动。
这些方法可以应用于其他银行活动。它可以帮助银行提取他们没有时间跟踪的客户数据类型。这些数据有助于预测客户需求和识别交叉销售机会。它还可以加快需要文档分析的“了解您的客户”( KYC)流程,从而使客户的加入更加容易。
投资分析
银行的证券研究部门正在使用自然语言处理在堆积如山的公司报告和电话会议中寻找有价值的见解。
银行以前雇佣大量分析师来梳理收益报告和其他文件,并将相关数据输入数据库和估值模型。
现在,银行正在使用自然语言处理工具,一次“阅读”数百份文件,并为人类分析师总结关键信息。语音分析工具可以“倾听”分析师电话会议,以确定公司管理层讲话背后的语气和情绪,这可以为股票分析提供洞察力。这些工具节省了大量的时间,并允许分析师专注于 alpha 生成。
银行也使用自然语言处理进行情绪分析。这些工具分析大量新闻和社交媒体帖子,以提取关键见解,确定公司的观感,或跟踪市场对重大事件的反应。这些及时的见解可以为分析师的建议提供信息。
银行要么使用内部开发的工具,要么使用供应商开发的工具。一家供应商 Dataminr 声称可以分析社交媒体和金融新闻,以识别相关信息,包括意想不到的新闻、新兴趋势或风险。
Dataminr 的客户最先知道关键事件和突发信息,使他们能够更快地采取行动…
www.dataminr.com](https://www.dataminr.com/)
例如,在卖方,自然语言生成工具会根据收益报告和新闻自动生成报告。
客户服务和见解
各大银行正在通过聊天机器人引入某种程度的客户服务自动化。2019 年初,美国银行推出了移动虚拟助理 Erica ,通过美国银行的移动应用程序,很快积累了超过百万用户。
Erica 接受语音和文本命令,并将预测分析与自然语言处理相结合,以帮助客户:
- 检查余额并转账
- 按需搜索过去的交易和账户信息
- 跟踪消费习惯*(可能使用预测分析,这是一种鼓励更多使用聊天机器人的增值)*
- 帮助客户管理经常性付款或逾期付款
聊天机器人让客户可以在手机上访问账户信息和进行基本交易,而不是使用网上银行或访问当地分行。通过干净的聊天机器人界面执行交易也可能花费更少的时间。
对银行来说,一个更大的胜利将是使用自然语言处理进行**客户洞察。**使用上述智能文档搜索和情感分析相关方法,银行可以更好地了解和预测客户需求和痛点。情绪分析工具可以监控社交媒体,了解人们对这家银行的看法。文档搜索工具可以分析反馈表和客户信息,以应对问题,提供定制产品,并增加客户保留率。
银行高管的关键要点
银行业领导人意识到,自然语言处理可以实现日常文档分析、研究和客户服务的自动化。
节约成本只是冰山一角。通过更快地分析文本和语音数据,并提取更多关于客户和市场的可行见解,银行可以更好地为客户服务,并做出更好的投资。更大的市场份额和收入的潜力是真正的差异制造者。
虽然我们没有涵盖所有可能的用例,但银行可以将自然语言技术应用于任何处理大量文本或语音数据的功能。例如,在合规、风险管理或订单执行方面有许多应用。
关键考虑因素包括是否在内部构建人工智能和自然语言处理工具,或者从人工智能供应商那里获得软件许可。内部建设需要数据科学家、开发人员和有组织的人工智能战略。虽然这需要时间,但内部开发的解决方案可能比供应商产品更能满足银行的需求。此外,还必须解决跨部门的数据质量和可用性问题。
鉴于自然语言处理可以应用于广泛的银行活动,跨部门应用这些解决方案的银行可能会看到更大的投资回报。
自然语言处理:概述《权力的游戏》的剧本
这篇文章将使用“现成的”数据科学工具,使用 Trifacta 、数据争论软件和 SkipThoughts 来更好地理解《权力的游戏》。
GOT Script
这篇文章的灵感来自于下面这篇文章中提供的代码: 使用句子嵌入的无监督文本摘要 。本帖包含完整的代码和对实现的详细解释。
然而,这篇文章是在几封短邮件上实现的,所以我对这些技术如何有效地应用于更长更复杂的文本很感兴趣。
包含第七季剧集的剧本可以在 Kaggle 上的这里找到。
仅供参考,一个 Amazon EC2 p2.xlarge 实例断断续续使用了大约一周,粗略估计成本不超过 15 美元。我在使用较小的实例时遇到了超时问题。使用 p2.xlarge,执行在这里找到的笔记本需要大约半个小时。
计算时间不包括为模型定型所花费的计算时间。该模型在 BookCorpus 数据集上进行训练,该数据集包含来自 16 种不同流派的超过 11,000 本书籍。
SkipThoughts 论文陈述了具有 2400 尺寸的单跳、单向编码器和包含具有 1200 尺寸的前向和后向编码器的双跳、双向编码器模型总共花费了四周的时间进行训练。(En 编码器型号 s)
bi-skip 型号包含两个具有不同参数的编码器:一个编码器以正确的顺序给出句子,而另一个编码器以相反的顺序给出句子。然后将输出连接起来形成一个 2400 维的向量。
即使使用扩展的 BookCorpus 仍然有可能没有包括一些单词,为了解决这个问题,使用了 word2Vec 嵌入,并将其映射到包含在 BookCorpus 词汇表中的单词。
如前所述,可以在上面提到的帖子中找到总结文本所需的 NLP 管道的更好、更全面的解释。但是,该逻辑的高级描述如下:
- 将文本分词成句子
- 将每个句子编码成一个向量,(创建每个句子的数字表示)
- 聚类得到的句子嵌入;每个簇代表一个主题句。然后,概要由每个聚类的一个主题句组成,并且每个主题句代表来自原始文本内的所有最相似的句子嵌入。
第一季的每一集都在这个笔记本里有总结,下面包括的一个总结是关于 is 第一季第一集原文的 10% :
This stitch is very... - It's beautiful. I saw the white walkers. Get back on your horse. A man of his... stature? Go on. - Quick, Bran! What is it? Viserys of House Targaryen, the third of his name, the rightful King of the Andals and the First Men, and his sister, Daenerys of House Targaryen. Would you please shut up? It won't be long now. They murdered the last Hand. ...King of the Andals and the First Men... - Father will know if you do. he showed me What was what. No, Your Grace. - Oh. Hey, Hey, Hey, hey. Ned. Who have we here? - No? Go on, Tommy, shear him good. Your Grace. The Dothraki are not known for their punctuality. It's a direwolf. I'm a Northman. Winter is coming. You should be the Hand of the King. Lord Eddard Stark... Now you want Ned to take the job? Of course, they will behead you as a deserter. And I know I'm a deserter. I hear he's more than earned it. - And you never worry about anything. Soon? Where's the Imp? I want to pay my respects. Why is your mother so dead set on us getting pretty for the king? Arya! Thank you for saying yes. - Your Grace. Uncle Benjen. Did I offend you? - Thank you. A different time. I know what I'm putting you through. - Don't get up. It's Maester Luwin, my lord. The king rode for a month to ask for Lord Stark's help. Lady Stark thought it might insult the royal family to seat a bastard in their midst. I take you for a king. I don't know how to say "thank you" in Dothraki. Is this your first time in the North, Your Grace? Jadi, zhey Jorah andahli! No. She always does it and it's not funny! Thank you, ser. - He saw us.
这段文字也来自第一季第一集第 17 集,然而这段摘要只代表了原文的 30%。这种方法在一个方面稍加修改。在开始编码步骤之前,整个段落被分成 4 个相等的部分(桶),并且每个桶被单独处理。每个部分产生的主题句加在一起。这个微小的修改使得 simplify 试图对结果摘要的顺序有更多的控制。
第一集更长的摘要如下…
'They won't trouble us no more.You don't think he'll ask us how they died?Get back on your horse.Whatever did it to them could do it to us.They even killed the children.It's a good thing we're not children.You want to run away south, run away.Of course, they will behead you as a deserter.If I don't catch you first.Get back on your horse.I won't say it again.Your dead men seem to have moved camp.They were here.See where they went.What is it?It's...Go on, Father's watching.And your mother.Fine work, as always. They won't last without their mother.- Right. "Our way is the old way"?The man who passes the sentence should swing the sword.Is it true he saw the white walkers?The white walkers have been gone for thousands of years.So he was lying?A madman sees what he sees.What is it?Mountain lion?There are no mountain lions in these woods.It's a freak.It's a direwolf.Tough old beast.There are no direwolves south of the Wall.Now there are five.You want to hold it?Where will they go?Their mother's dead.They don't belong down here.Better a quick death. "What if Jon Arryn told someone? - we should head back to the Wall.Do the dead frighten you?Our orders were to track the wildlings.We tracked them.' 'Our way is the old way"?The man who passes the sentence should swing the sword.Is it true he saw the white walkers?The white walkers have been gone for thousands of years.So he was lying?A madman sees what he sees.What is it?Mountain lion?There are no mountain lions in these woods.It's a freak.It's a direwolf.Tough old beast.There are no direwolves south of the Wall.Now there are five.You want to hold it?Where will they go?Their mother's dead.They don't belong down here.Better a quick death. - But who would he tell?My husband.If he told the king, both our heads would be skewered on the city gates by now.Whatever Jon Arryn knew or didn't know, it died with him.And Robert will choose a new Hand of the King,someone to do his job while he's off fucking boars and hunting whores.Or is it the other way around?And life will go on.You should be the Hand of the King.That's an honour I can do without.Their days are too long,their lives are too short.All these years,and I still feel like an outsider when I come here.You have five northern children.You're not an outsider.I wonder if the old gods agree.It's your gods with all the rules.I am so sorry, my love.- Tell me. They won't last without their mother.- Right. - There was a raven from King's Landing.Jon Arryn is dead.A fever took him.I know he was like a father to you.- Your sister, the boy? - They both have their health,gods be good.The raven brought more news.The king rides for Winterfell...' 'Our way is the old way"?The man who passes the sentence should swing the sword.Is it true he saw the white walkers?The white walkers have been gone for thousands of years.So he was lying?A madman sees what he sees.What is it?Mountain lion?There are no mountain lions in these woods.It's a freak.It's a direwolf.Tough old beast.There are no direwolves south of the Wall.Now there are five.You want to hold it?Where will they go?Their mother's dead.They don't belong down here.Better a quick death. I won't say it again.Your dead men seem to have moved camp.They were here.See where they went.What is it?It's...Go on, Father's watching.And your mother.Fine work, as always. - But who would he tell?My husband.If he told the king, both our heads would be skewered on the city gates by now.Whatever Jon Arryn knew or didn't know, it died with him.And Robert will choose a new Hand of the King,someone to do his job while he's off fucking boars and hunting whores.Or is it the other way around?And life will go on.You should be the Hand of the King.That's an honour I can do without.Their days are too long,their lives are too short.All these years,and I still feel like an outsider when I come here.You have five northern children.You're not an outsider.I wonder if the old gods agree.It's your gods with all the rules.I am so sorry, my love.- Tell me. They won't last without their mother.- Right. "What if Jon Arryn told someone?' 'Our way is the old way"?The man who passes the sentence should swing the sword.Is it true he saw the white walkers?The white walkers have been gone for thousands of years.So he was lying?A madman sees what he sees.What is it?Mountain lion?There are no mountain lions in these woods.It's a freak.It's a direwolf.Tough old beast.There are no direwolves south of the Wall.Now there are five.You want to hold it?Where will they go?Their mother's dead.They don't belong down here.Better a quick death. - No!Put away your blade.- I take orders from your father, not you. He's got hundreds of people. - But who would he tell?My husband.If he told the king, both our heads would be skewered on the city gates by now.Whatever Jon Arryn knew or didn't know, it died with him.And Robert will choose a new Hand of the King,someone to do his job while he's off fucking boars and hunting whores.Or is it the other way around?And life will go on.You should be the Hand of the King.That's an honour I can do without.Their days are too long,their lives are too short.All these years,and I still feel like an outsider when I come here.You have five northern children.You're not an outsider.I wonder if the old gods agree.It's your gods with all the rules.I am so sorry, my love.- Tell me. - I'm told he drinks all night.How much could he possibly drink?'
此外,第一季每一集的摘要都可以在这个笔记本中找到。
参考文献:
**@article{zhu2015aligning,
title={Aligning Books and Movies: Towards Story-like Visual Explanations by Watching Movies and Reading Books},
author={Zhu, Yukun and Kiros, Ryan and Zemel, Richard and Salakhutdinov, Ruslan and Urtasun, Raquel and Torralba, Antonio and Fidler, Sanja}, journal={arXiv preprint arXiv:1506.06724}, year {2015}
}**
使用斯坦福 CoreNLP 的自然语言处理
只用两行代码分析文本数据
介绍
使用斯坦福的 CoreNLP 分析文本数据使文本数据分析变得简单高效。只需几行代码,CoreNLP 就可以提取所有类型的文本属性,比如命名实体识别或词性标注。CoreNLP 是用 Java 编写的,需要在您的设备上安装 Java,但它为几种流行的编程语言提供了编程接口,包括 Python,我将在本演示中使用 Python。此外,它还支持英语以外的四种语言:阿拉伯语、中文、德语、法语和西班牙语。
一、如何安装 CoreNLP
首先,我们要下载 CoreNLP。如果您使用的是 MacBook,请打开终端,输入以下代码行,然后按回车键:
**wget** https://nlp.stanford.edu/software/stanford-corenlp-full-2018-10-05.zip https://nlp.stanford.edu/software/stanford-english-corenlp-2018-10-05-models.jar
这将开始下载 CoreNLP 的最新版本(截至 2019 年 2 月为 3.9.2)。您应该会在屏幕上看到类似这样的内容:
下载 CoreNLP 需要一段时间,取决于您的互联网连接。下载完成后,剩下的工作就是用以下命令解压文件:
**unzip** stanford-corenlp-full-2018-10-05.zip
**mv** stanford-english-corenlp-2018-10-05-models.jar stanford-corenlp-full-2018-10-05
命令 mv A B 将文件 A 移动到文件夹 B,或者将文件名从 A 改为 B
二。启动服务器并安装 Python API
为了能够使用 CoreNLP,您必须启动服务器。这样做非常简单,因为您所要做的就是移动到步骤 1 中创建的文件夹中,并使用 Java 运行 CoreNLP。让我们看看为此需要的命令:
**cd** stanford-corenlp-full-2018-10-05
**java -mx6g** -cp "*" edu.stanford.nlp.pipeline.StanfordCoreNLPServer **-timeout 5000**
cd 命令打开我们创建的文件夹。然后,为了运行服务器,我们使用 Java。参数**-mx6g**
指定 CoreNLP 允许使用的内存量。在这种情况下,它是 6gb。**-timeout 5000**
参数以毫秒为单位指定超时时间。
现在,您应该看到类似这样的内容:
在 Python 中使用 CoreNLP 时,我所强调的数字将非常重要。
在开始分析文本之前,最后需要安装一个 Python API:
**pip install** pycorenlp
我将使用 py-corenlp,但是还有其他 Python 包,您可以在这里查看。如果您碰巧是 NLTK 的狂热用户,也有一个 NLTK API 可以让您使用 CoreNLP。完整的说明可以在这里找到。
三。带核心语言的语言
安装完 CoreNLP 后,我们终于可以开始分析 Python 中的文本数据了。首先,让我们导入 py-corenlp 并初始化 corenlp。这就是我上面强调的数字发挥作用的地方:
**from** pycorenlp **import** StanfordCoreNLPnlp = StanfordCoreNLP('[http://localhost:**9000**'](http://localhost:9000'))
NLTK 中的语法非常相似:
**from** nltk.parse **import** CoreNLPParser
result = CoreNLPParser(url='http://localhost:**9000**')
本演示的其余部分将集中在 py-corenlp 上,但是正如上面指出的,您也可以使用 NLTK。这两者之间的主要区别是,在 py-corenlp 中,输出一个原始的 JSON 文件,然后您可以用它来提取您特别感兴趣的内容,而 NLTK 为您提供了这样做的函数。
使用 py-corenlp 执行 NLP 所需的唯一其他函数是**nlp.annotate()**
。在函数内部,可以指定 CoreNLP 应该执行什么样的分析。在这个演示中,我将看看四个不同的句子,它们有着不同的情感。所有这些都可以在一行代码中完成,但是出于可读性的考虑,最好将其扩展到几行。
text = "This movie was actually neither that funny, nor super witty. The movie was meh. I liked watching that movie. If I had a choice, I would not watch that movie again."result = nlp.annotate(text,
properties={
'annotators': 'sentiment, ner, pos',
'outputFormat': 'json',
'timeout': 1000,
})
注释器参数指定 CoreNLP 将要做什么样的分析。在这种情况下,我已经指定让 CoreNLP 进行情感分析以及命名实体识别和词性标注。JSON 输出格式将允许我轻松地对结果进行索引,以便进一步分析。
情感分析
CoreNLP 的情感分析非常简单。运行完上面的代码块后,就不需要进一步的计算了。让我们看看上面定义的四个句子的结果:
for s in result["sentences"]:
print("{}: '{}': {} (Sentiment Value) {} (Sentiment)".format(
s["index"],
" ".join([t["word"] for t in s["tokens"]]),
s["sentimentValue"], s["sentiment"]))
运行这个 for 循环输出情感分析的结果:
0: 'This movie was actually neither that funny , nor super witty.': 1 (Sentiment Value) Negative (Sentiment)1: 'The movie was meh.': 2 (Sentiment Value) Neutral (Sentiment)2: 'I liked watching that movie.': 3 (Sentiment Value) Positive (Sentiment)3: 'If I had a choice , I would not watch that movie again.': 1 (Sentiment Value) Negative (Sentiment)
情绪值的范围从 0 到 4。零意味着这个句子非常消极,而四意味着它非常积极。如你所见,CoreNLP 做得非常好。第一句话很棘手,因为它包含了像“滑稽”或“机智”这样的积极词汇,然而,CoreNLP 正确地意识到它们被否定了。较简单的句子也能正确分类。
当试图理解这些分类时,另一个选择是看一看情绪分布,其范围也是从零到四。我们来看看第二句的情绪分布:
如您所见,分布峰值在情感值 2 附近,因此可以归类为中性。
词性标注
词性标注,就像情感分析一样,不需要任何额外的计算。与上面的代码块类似,检索所需信息所需要的只是一个 for 循环:
pos = []
for word in result["sentences"][2]["tokens"]:
pos.append('{} ({})'.format(word["word"], word["pos"]))
" ".join(pos)
运行该代码将返回以下内容:
'I (PRP) liked (VBD) watching (VBG) that (IN) movie (NN) . (.)'
括号中的缩写代表 POS 标签,遵循 Penn Treebank POS 标签集,您可以在这里找到。给你一个直觉,PRP 代表人称代词,VBD 代表过去时态的动词,NN 代表名词。
命名实体识别
CoreNLP 的另一个可能用途是命名实体识别。为了让命名实体识别更有意义,让我们创建一个新句子:
吉姆在美国芝加哥机场逛苹果店时给杰西卡买的耳机很棒
同样,我们需要做的就是定义一个 for 循环:
pos = []
for word in result["sentences"][1]['tokens']:
pos.append('{} ({})'.format(word['word'], word['ner']))
" ".join(pos)
运行上面的代码会得到以下结果:
'The (O) earphones (O) Jim (PERSON) bought (O) for (O) Jessica (PERSON) while (O) strolling (O) through (O) the (O) Apple (ORGANIZATION) store (O) at (O) the (O) airport (O) in (O) Chicago (CITY) , (O) USA (COUNTRY) , (O) was (O) meh (O) . (O)'
我们可以看到,CoreNLP 已经正确地识别出 Jim 和 Jessica 是人,Apple 是组织,芝加哥是城市,美国是国家。
在解释如何关闭服务器之前,我想指出 CoreNLP 提供了许多其他功能(词汇化、词干化、标记化等。)都可以被访问,而不必运行任何额外的计算。可以在 的处找到**nlp.annotate()**
所有参数的完整列表。
四。关闭服务器&结论
如果您想关闭服务器,请导航到您之前用来启动服务器的终端窗口,然后按**Ctrl + C**
。
总而言之,CoreNLP 的效率是它如此方便的原因。您只需指定一次您感兴趣的分析,并避免不必要的计算,这些计算可能会在处理较大的数据集时降低您的速度。如果你想知道更多关于 CoreNLP 如何工作的细节以及有哪些选项,我推荐你阅读文档。
参考文献:
[1] Manning、Christopher D .、Mihai Surdeanu、John Bauer、Jenny Finkel、Steven J. Bethard 和 David McClosky,斯坦福 CoreNLP 自然语言处理工具包 (2014),计算语言学协会第 52 届年会会议录:系统演示,第 55–60 页
[2] Taylor A .、Marcus M .、Santorini B .,宾夕法尼亚树库:概述 (2003),文本、语音和语言技术,第 20 卷
用脸书的快速文本(自然语言处理)介绍文本分类
快速文本系列
一个初学者友好的文本分类库。
最初发表于我的博客。
文本分类是机器学习的一个非常常见的应用。在这样的应用中,机器学习被用于将一段文本分类成两个或多个类别。文本分类有监督学习模型和非监督学习模型。在这篇文章中,我们将看到如何使用脸书的快速文本库进行一些简单的文本分类。
由脸书开发的 fastText 是一个流行的文本分类库。该库是 GitHub 上的一个开源项目,非常活跃。该库还提供了用于文本分类的预建模型,包括监督和非监督的。在这篇文章中,我们将了解如何在库中训练监督模型进行快速文本分类。该库可以用作命令行工具,也可以用作 Python 包。为了让事情变得简单,在这篇文章中我们将只看几个 CLI 命令。
安装 fastText
为命令行安装 fastText 就像克隆 Git repo 并在目录中运行 make 命令一样简单:
git clone [https://github.com/facebookresearch/fastText.git](https://github.com/facebookresearch/fastText.git)
cd fastText
make
一旦你这样做了,你就已经安装了 fastText CLI,只要你没有得到任何错误。您也可以通过从同一目录运行以下命令来安装 Python 库:
pip install .
您可以通过运行以下命令来验证安装:
./fasttext
您应该在终端中看到类似这样的内容:
usage: fasttext <command> <args>The commands supported by fasttext are:supervised train a supervised classifier
quantize quantize a model to reduce the memory usage
test evaluate a supervised classifier
test-label print labels with precision and recall scores
predict predict most likely labels
predict-prob predict most likely labels with probabilities
skipgram train a skipgram model
cbow train a cbow model
print-word-vectors print word vectors given a trained model
print-sentence-vectors print sentence vectors given a trained model
print-ngrams print ngrams given a trained model and word
nn query for nearest neighbors
analogies query for analogies
dump dump arguments,dictionary,input/output vectors
这表明您已经安装了该工具。下一步是获取我们的数据集。
获取数据
脸书开发者已经包含了一个测试这个库的数据集。所以我们会用同样的数据。这是一个关于烹饪的 stackexchange 问题集。这里的目的是对问题进行自动分类。因为我们使用监督学习,我们必须确保我们在数据中标记问题的类别。幸运的是,这些数据都带有已经标记的类别。所以先下载数据吧。数据在这里以压缩文件的形式提供:https://dl . fbaipublicfiles . com/fast text/data/cooking . stack exchange . tar . gz。我们可以下载数据并手动解压缩,也可以从 CLI 运行以下命令:
wget [https://dl.fbaipublicfiles.com/fasttext/data/cooking.stackexchange.tar.gz](https://dl.fbaipublicfiles.com/fasttext/data/cooking.stackexchange.tar.gz) && tar xvzf cooking.stackexchange.tar.gz
解压缩后,目录中会有一些文件。但是我们的数据在一个名为cooking . stack exchange . txt的文件里。如果你打开文件或者头它,你会看到这样的东西:
__label__sauce __label__cheese How much does potato starch affect a cheese sauce recipe?
__label__food-safety __label__acidity Dangerous pathogens capable of growing in acidic environments
__label__cast-iron __label__stove How do I cover up the white spots on my cast iron stove?
__label__restaurant Michelin Three Star Restaurant; but if the chef is not there
__label__knife-skills __label__dicing Without knife skills, how can I quickly and accurately dice vegetables?
__label__storage-method __label__equipment __label__bread What’s the purpose of a bread box?
__label__baking __label__food-safety __label__substitutions __label__peanuts how to seperate peanut oil from roasted peanuts at home?
__label__chocolate American equivalent for British chocolate terms
__label__baking __label__oven __label__convection Fan bake vs bake
__label__sauce __label__storage-lifetime __label__acidity __label__mayonnaise Regulation and balancing of readymade packed mayonnaise and other sauces
如你所见,这篇文章有些不寻常。在每一行中,我们都有*_ _ 标签 __* 文本。这其实就是问题的范畴。因此,在训练数据中指定类别的方法是包含文本 label ,后跟类别。我们也可以为一个问题指定多个类别,从上面的例子可以看出。现在我们已经准备好了数据,让我们把它分成训练和测试数据。
将数据分为训练数据和测试数据
在开始训练我们的模型之前,我们必须分割数据,以便我们有一个数据集用于训练模型,一个数据集用于测试模型的准确性。如果你想知道为什么这是必要的或者如何用 Python 来做,你可以在这里阅读我关于它的帖子。通常,我们将数据分成 80-20 份,80%的数据用于训练,20%用于测试。要做到这一点,我们首先需要看看我们有多少问题。每行有一个问题,所以获取文件中的行数就可以了:
$ wc -l cooking.stackexchange.txt
15404 cooking.stackexchange.txt
正如我们从输出中看到的,文件中有 15404 行。其中 80%是 12323.2,所以我们将前 12324 行作为训练数据集。剩下的 3080 行将是我们的测试数据。为此,我们将运行以下命令:
$ head -n 12324 cooking.stackexchange.txt > training_data.txt
$ tail -n 3080 cooking.stackexchange.txt > testing_data.txt
我们现在将有两个新文件,一个用于培训,一个用于测试。接下来,我们将使用训练数据训练模型。
训练模型
这实际上是这个库的一个非常简单的命令。我们只需使用监督的命令运行 fastText CLI 工具,并提供输入文件(这是我们的训练数据文件),以及将要生成的模型的名称。该命令如下所示:
./fasttext supervised -input training_data.txt -output cooking_question_classification_model
如您所见,这是一个非常容易理解的命令。-输入选项指定输入文件,而*-输出*选项指定将要生成的模型的名称。运行该命令后,您应该会得到类似如下的输出:
$ ./fasttext supervised -input training_data.txt -output cooking_question_classification_model
Read 0M words
Number of words: 14492
Number of labels: 735
Progress: 100.0% words/sec/thread: 47404 lr: 0.000000 avg.loss: 10.243105 ETA: 0h 0m 0s
我们的模型现在已经训练好了,可以回答一些问题进行分类了。让我们现在试试。
用一些问题测试我们的模型
当我们在上一步中训练我们的模型时,该命令生成了几个新文件:cooking _ question _ class ification _ model . bin和cooking _ question _ class ification _ model . vec。。bin 文件,或者模型的二进制文件,就是我们现在要用的。我们可以通过运行以下命令开始测试模型:
./fasttext predict cooking_question_classification_model.bin -
如您所见,我们使用 predict 命令告诉我们的模型,我们现在要做一些预测。命令末尾的破折号(-)表示我们将在命令行中键入问题。我们也可以给命令一个包含多个问题的文件,但是我们将在下一篇文章中讨论这个问题。一旦你运行这个命令,模型将开始监听问题,你可以输入一个问题,然后点击回车或回车键得到一个预测。现在让我们试试:
how to bake a cake
__label__baking
how to cook some rice
__label__food-safety
Does milk make cakes lighter or tougher?
__label__baking
How to prepare dried tortellini?
__label__food-safety
What exactly is a chowder?
__label__baking
How bad is it to freeze vegetables in glass for a maximum of 4 weeks?
__label__baking
我的每个问题都用文本 label 回答,后跟模型认为该问题所属的类别。正如你已经知道的,这个模型没有得到所有的答案或者正确的分类。这是意料之中的,因为我们还没有真正清理我们的数据或调整模型。我们可以通过对数据进行一些预处理来对模型进行微调,使其更加清晰,便于模型理解。
这个例子是您第一次尝试 fastText 时会遇到的。你可以登录 fastText 网站获取更多关于这个库和这个教程的信息。因为我想把这篇文章限制在基础知识上,所以我不打算谈论验证模型或预处理我们的数据以获得更好的结果。
我们可以获得更好结果的另一种方法是使用 n 元语法,并将句子视为单词序列。一旦我们开始以这种方式看待单词,我们将能够更多地了解我们训练的数据中的模式,并更好地预测。我会写另一篇关于什么是 n-gram (因为它值得有一篇自己的帖子)以及我们如何使用概率来更好地理解我们的数据。
如果你喜欢我在 Medium 或我的个人博客上的帖子,并希望我继续做这项工作,请考虑在 Patreon 上支持我。