无监督学习的学习过滤器
一种无监督学习方法,用于学习能够从图像中提取有意义特征的过滤器
数据就是一切。尤其在深度学习中,数据量、数据类型、数据质量是最重要的因素。有时,我们拥有的标记数据的数量不够,或者我们处理的问题领域对使用大量数据没有意义,例如在少量学习中。在这些情况下,重要的因素是算法。在深度度量学习中,我们使用的损失函数是最重要的因素。我们在 DML 中尝试做的是学习一组特征,这些特征可以区分不同的图像样本,同时将相似的图像样本相互匹配。
在我的工作中,我已经开始从事一个项目,我们需要利用深度度量学习方法。我们需要从图像中提取有意义的特征,以便我们能够准确地分类成千上万的图像样本。虽然 DML 是我们构建的系统的问题域,但我在考虑可以从图像中提取有意义特征的其他方法。我回头看了看人类的大脑。
我认为,人脑既不是分类模型,也不是自动编码器模型。人脑是一个 DML 系统,其中每个对象、每个场景和每个输入都用一组嵌入来表示。但是,当我们还是婴儿的时候,有没有人过来给我们看每一件物品并说
“嘿,孩子,看,这个物体和这个物体是不同的,而这些是相同的.”?
嗯……他们没有。就在我们能说话的时候,我们这些好奇的孩子不停地向父母提问。
“嘿,妈妈/爸爸,这是什么?”。
学习我们看到的每件事物的嵌入确实发生在我们学习对大脑中的嵌入进行分类之前,而且这个过程是在无人监督的情况下发生的,就在我们自己的时候。所以,这种学习机制不是 DML 算法。那是什么?
我已经想出了一个解决这个问题的基本方法:特征区分。
特征区分
在这种方法中,我们需要建立一个神经网络,其中每个卷积层在同一级别上尽可能互不相同。所以,当我们用 32 个 5x5 的滤镜对一幅灰度图像进行卷积运算时,这 32 层应该互不相同。我们如何做到这一点?答案是余弦相似度。我们可以通过两个展平层(其中一个被转置)的矩阵乘法来容易地计算余弦相似性。我们需要应用这个操作多少次?答案与卷积层的组合一样多。
让我们开始编码吧,我知道这是你喜欢的部分。
首先,让我们导入我们的库,我将使用 PyTorch 来构建神经网络:
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
import itertools
import numpy as np
import matplotlib.pyplot as plt
接下来是构建卷积图层类:
class ConvLayer(torch.nn.Module):
def __init__(self, in_channels, out_channels, kernel_size, stride):
super(ConvLayer, self).__init__()
self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride)def forward(self, x):
out = self.conv2d(x)
return out
因此,现在我们需要建立两个网络,其中一个包括每个级别的卷积层,而另一个包括所有级别的卷积层。
一级卷积层的网络:
class SSNet(torch.nn.Module): # The child class
def __init__(self,in_filters, out_filters):
super(SSNet, self).__init__()
self.conv1 = ConvLayer(in_filters, 64, kernel_size = 5, stride = 1)
self.conv2 = ConvLayer(64, out_filters, kernel_size = 1, stride = 1)
self.relu = torch.nn.ReLU()
def forward(self, x):
out = self.conv2(self.relu(self.conv1(x)))
return out
你可能会问,“嘿,Evrim,你为什么在每一层中使用两个卷积层?”答案是它们捕捉了更多的要素,并且这种方法比单个卷积图层效果更好。另外,我在单个卷积层的末尾应用的 ReLU 会在一段时间后导致 nan 的损失。当我把 ReLU 放在两个卷积层之间时,我没有得到 nan 值的损失。我没有解释得这么“科学”,我知道。但是,如果你正在寻找科学文章,媒体很可能不是一个“科学”文章的地方,不是吗?😄
不管怎样,我们继续。现在,我们需要构建 main,即包含每个卷积运算级别的母类。正如您在下面的类中所看到的,每个卷积图层被称为一个子图层,它们被追加到一个“子”Python 列表中。如果您在“Sequential”函数的输入中询问“children”列表前面的星号,该星号将解释 children 列表中的每个元素,而没有包围它们的列表。
class SSNetMultiple(torch.nn.Module): #The Holy Mother Class
def __init__(self):
super(SSNetMultiple, self).__init__()
self.children = []
for cnt in range(4):
if cnt == 0:
in_filters, out_filters = 1,16
elif cnt == 3:
in_filters, out_filters = 16,4
else:
in_filters, out_filters = 16,16
self.children.append(SSNet(in_filters, out_filters))
self.main = nn.Sequential(*self.children)
def forward(self, x, queue = 1):
outs = [x]
for cnt,child in enumerate(self.main):
if cnt<queue:
outs.append(child(outs[-1]))
return outs[-1]
我知道您正在考虑 forward 函数中的“队列”问题。你还记得我们需要在卷积层的一个级别中区分每个特征图吗?我们将在几个层中这样做,队列就是为此而工作的。剩下的就看你的了,读读代码,试着理解一下,我们不可能一直过着安逸的生活,对吗?
好了,现在我们上课了。我们给他们打个电话吧。但首先,我们需要数据来训练网络并做一些测试。
transform=transforms.Compose([
transforms.ToTensor()
])
dataset = datasets.MNIST('../data',
train=True,
download=True,
transform=transform)
让我们定义母模型和一些其他必要的参数。
model = SSNetMultiple()
lr = 0.8
optimizer = optim.SGD(model.parameters(), lr=lr)
lossfunc = nn.MSELoss()
loss_obs = 0
epoch = 0
Holly molly,Evrim 这个学习率好高啊!我知道,我知道。我通过反复试验来确定这个学习速度。学习速度越慢,学习就越慢。当我说慢,我是认真的。
现在是时候为训练迭代写一个脚本了。
while epoch<4:
# if epoch>0:
# for cc,param in enumerate(model.main[epoch-1].parameters()):
# print(epoch-1,"grad is deactivated")
# param.requires_grad = True
for cnt,sample in enumerate(dataset):
optimizer.zero_grad()
image, label = sample
out = model(image.unsqueeze(0), queue = epoch+1)
sim_vec = sim_func(out)
loss = lossfunc(sim_vec, torch.zeros(sim_vec.shape))
loss_obs_ = torch.max(torch.abs(sim_vec-torch.zeros(sim_vec.shape)))
loss_obs += loss_obs_
loss.backward()
optimizer.step()
print("__Loss: {}__".format(loss_obs_))if cnt%10 == 0 and cnt!=0:
loss_obs = loss_obs/10
print("Epoch: {}\tSample: {}\tLoss: {}\tLR: {}".format(epoch,cnt,loss_obs,optimizer.param_groups[0]["lr"]))
if loss_obs<0.40:
epoch += 1
break
loss_obs = 0
那么,这里发生了什么?
我们从数据集中提取每个样本,并将其提供给模型。如果我们在第一个纪元中,模型学习区分第一级上的特征图。如果我们在第二个纪元,模型学习区分第二个层次上的特征图,这样继续下去。简单对吗?
那些被评论的部分呢?他们将冻结已经能够区分过滤器的水平的学习过程。你可以激活那部分并尝试,但我发现冻结它们并不能让网络更容易地学习下一级。
因此,在每个时期,我们的相似性向量得到较少的值,因为它最初是针对的。如果观察到的损失(这不同于均方损失,并且不用于反向传播)在最后 10 个损失值的平均值上小于 0.4,则该卷积级别的训练完成。所以,我们跳到下一个。
如你所知,我们这里不需要任何标签。我们只是试图在前馈过程结束时得到最不同的特征图。
此外,网络已经达到数据集的最大 300 个样本,直到它完成每一级的学习过程。
所以,让我们测试一下,看看我们如何从我们的网络中获得准确的结果。
def test(test_index = 0):
img0,label0 = dataset[test_index]
out0 = model(img0.unsqueeze(0), queue = 5)
results = []
for cnt,sample in enumerate(dataset):
if cnt<10000 and cnt!=test_index:
img1, label1 = sample
out1 = model(img1.unsqueeze(0), queue = 5)
first = out0.flatten()
second = out1.flatten()
first_norm = (first - torch.mean(first)) / (torch.std(first) * len(first))
second_norm = (second - torch.mean(second)) / (torch.std(second))
results.append(["{}-{}".format(label0,label1),torch.matmul(first_norm,second_norm.T).detach().numpy()])
sorted_results = sorted(results,key = lambda x:x[1],reverse=True)
print(sorted_results[0:10],"\n")
return sorted_resultssr1 = test(test_index = 2000)
sr2 = test(test_index = 2001)
sr3 = test(test_index = 2002)
sr4 = test(test_index = 2003)
sr5 = test(test_index = 2004)
这里发生了什么?我们给出一个样本索引作为输入。这个样本索引是我们将与其他样本进行比较的锚。然后,我们将每个样本输入神经网络,我们得到嵌入,并将这些嵌入与锚样本的嵌入进行比较。正如你在“如果”条件中看到的,测试样本永远不会与锚定样本相同。
结果?给你:
当我们比较标签为“5”的样本时,我们发现大多数相似的样本都有标签“6 ”,这有点符合逻辑,因为 5 和 6 在视觉上是相似的数字。
当我们比较一个标签为“8”的样本时,我们发现大多数相似的样本都有标签“8”,yeeyyy!
对于标签为“4”的样本,我们找到的最相似的样本是 9,但我们也找到了标签为“4”的相似样本,数量相当多。
对于标签为“2”的样本,网络再次成功。
结论
我们看到,网络已经学会区分特征图,这有助于它创建嵌入,帮助我们准确地对样本进行分类。我知道它没有那么高的精确度。但是记住,这只是一个婴儿的特征提取过程。婴儿还没有长大到足以对从视觉中提取的嵌入进行分类。这将是我需要继续的下一步。
链接到包含代码的回购:链接
链接到这个主题的下一篇文章:链接
用于 TDS 咖啡测量的过滤注射器似乎是不必要的
对以前作品的评论
当我在万维网上闲逛时,我偶然发现了一个关于在进行 TDS(总溶解固体)测量之前过滤浓缩咖啡样本的小研究。 TDS 广泛用于测量咖啡萃取率作为一种更客观的咖啡质量测量方法。这项小型研究对比了使用离心机和注射器过滤器进行样品过滤的情况。他们在几周的时间里,在两个咖啡豆之间分配了 20 个镜头,比较了离心机、注射器过滤器和未过滤的样本。他们一丝不苟地确保样品是好的。
然而,我不同意他们的发现,我认为他们错过了一个机会,因为他们绘制数据的方式。从好的方面来看,他们似乎发现了一些有趣的东西:过滤样本和未过滤样本之间存在直接的相关性和转化。这意味着,即使在没有滤波器的情况下测量 TDS,您也可以高精度地估计滤波后的 TDS。本质上,使用昂贵的离心机或昂贵的注射器过滤器对于在家里或咖啡馆测量 TDS 是不必要的;未过滤的测量是可靠的。
这项研究
之前来自苏格拉底咖啡的数据表明过滤结果只会提高精确度。我之前发现过滤不够有用,不足以证明其成本。最终,对于一个已经非常昂贵的爱好来说,离心机或注射器过滤器是非常昂贵的。
这项研究在多天内采集了 20 份样本,拍摄了多张照片,在两杯咖啡之间进行了分割。然后他们计算概率分布来显示未过滤的样本是有问题的。他们在表格中显示了数据,但没有将数据绘制成散点图。
我对数据很好奇,就拉出来看看。如果他们的数据证明过滤是必要的,我会更倾向于过滤我所有的结果。然而,过滤样品有一个主要的成本障碍,即注射器过滤器很贵,即使离心机不贵,也需要更多的时间。
数据
他们提供了原始数据,我从一些散点图开始。
一条简单的最佳拟合线性线显示 R^2 值为 0.68,这是相当高的。因此,让我们再次将数据分成两个独立的部分,看看这是如何改变这些趋势的。
现在每种咖啡的线性拟合更强,这表明从过滤样品到未过滤样品的转换。让我们将样品排成一行并分类,但按咖啡分类:
同样,它们是相互关联的,所以我们应该计算相关性。相关性是一个有助于理解两个指标趋势的紧密程度的指标:
对于水坑埃塞俄比亚 Roba 来说,相关系数太高,不能忽略。即使是 80 多岁的 Sump Alma Negra 相关系数也表明,未过滤和过滤之间的联系只是一种转换。
将变换应用于每个数据组,我们可以计算常规测量的百分比误差(| x-x _ ground truth |/x _ ground truth),然后根据最佳拟合线变换进行校正。
假设离心样本是真实的,那么校正后的实际误差百分比就没什么可担心的了。
虽然这项研究的作者在控制变量和收集数据方面做得很好,但他们的分析并没有揭示真正的发现,即证明过滤咖啡样品用于 TDS 测量可能是不必要的。不确定性是每种豆子都有不同的校正曲线,如果你非常担心,一项跨多种豆子的更大规模的研究将有助于证实这一理论。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。
我的进一步阅读:
熊猫中的数据过滤
清理数据集的完整指南—第 3 部分
从数据框中过滤数据是清理数据时最常见的操作之一。Pandas 提供了多种根据行和列的位置和标签选择数据的方法。此外,Pandas 还允许您获得基于列类型的数据子集,并使用布尔索引过滤行。
在本文中,我们将介绍从 Pandas 数据框中选择数据子集的最常见操作:(1)按标签选择单个列,(2)按标签选择多个列,(3)按数据类型选择列,(4)按标签选择单个行,(5)按标签选择多个行,(6)按位置选择单个行,(7)按位置选择多个行,(8)同时选择行和列,(9)选择标量值,以及(10)使用布尔选择来选择行。
此外,我们将提供多个编码示例!现在,让我们开始吧:)❤️
法国人 Daphné Be 在 Unsplash 上的照片
数据集
在本文中,我们使用一个小数据集进行学习。在现实世界中,使用的数据集会大得多;然而,用于过滤数据的程序保持不变。
数据框包含一家公司的 10 名员工的信息:(1) id,(2)姓名,(3)姓氏,(4)部门,(5)电话,(6)工资,以及(7)合同类型。
1.按标签选择单个列
要在 Pandas 中选择单列,我们可以同时使用**。操作员和操作员**。
按标签选择单个列
→df[字符串]
以下代码使用两种方法(点符号和方括号)访问 salary 列。
如上图所示,当检索单个列时,结果是一个系列对象。为了在只选择一列时获得一个 DataFrame 对象,我们需要传入一个只有一项的列表,而不仅仅是一个字符串。
此外,重要的是要记住,当列名包含空格时,我们不能使用点符号来访问数据框的特定列。如果我们这样做,就会引发一个语法错误。
2.按标签选择多列
我们可以通过传入一个列名如下的列表来选择一个数据帧的多个列。
按标签选择多列
→df[字符串列表]
如上所示,结果是一个 DataFrame 对象,只包含列表中提供的列。
3.按数据类型选择列
我们可以用 熊猫。data frame . select _ dtypes(include = None,exclude=None) 方法根据列的数据类型选择列。该方法在参数中接受列表或单一数据类型,包括和排除。请记住,必须至少提供其中一个参数(包括或排除),并且它们不能包含重叠的元素。
按数据类型选择列
→ df.select_dtypes(包含=无,排除=无)
在下面的例子中,我们通过将 np.number 对象传递给 include 参数来选择数据帧的数字列(整数和浮点数)。或者,我们可以通过提供字符串’ number’ 作为输入来获得相同的结果。
如您所见, select_dtypes()方法返回一个 DataFrame 对象,其中包含了 include 参数中的 dtypes,并排除了 exclude 参数中的 dtypes。
如前所述, select_dtypes()方法可以接受字符串和 numpy 对象作为输入。下表显示了在 Pandas 中引用数据类型的最常见方式。
提醒一下,我们可以使用 pandas 来检查列的数据类型。data frame . info方法或者用 熊猫。DataFrame.dtypes 属性。前者打印数据框的简明摘要,包括列名及其数据类型,而后者返回一个包含每列数据类型的系列**。**
****
4.按标签选择单行
****数据框和系列不一定有数字索引。默认情况下,索引是指示行位置的整数;但是,它也可以是字母数字字符串。在我们当前的例子中,索引是雇员的 id 号。
要通过 id 号选择单个行,我们可以使用。loc[]索引器提供一个单字符串**(索引名)作为输入。**
按标签选择单行
→ df.loc[string]
下面的代码显示了如何选择 id 号为 478 的雇员。
如上图所示,当单个行被选中时,。loc[]索引器返回一个系列对象**。然而,我们也可以通过向传递一个单元素列表来获得一个单行数据帧**。loc[]** 方法如下。**
5.按标签选择多行
我们可以用选择多行。loc[]索引器**。除了单个标签之外,索引器还接受标签列表或标签切片作为输入**。****
按标签选择多行
→df . loc[字符串列表]
→df . loc[字符串切片]
接下来,我们获取包含 id 号为 478 和 222 的雇员的数据帧的子集,如下所示。
注意,的结束索引。loc[]方法总是包含在内,意味着选择包括最后一个标签。
6.按位置选择单行
****。iloc[]索引器用于按位置索引数据帧。属性选择一行。iloc[]属性,我们将行位置(单个整数)传递给索引器。
按位置选择单行
→df . iloc[整数]
在下面的代码块中,我们选择索引为 0 的行。在这种情况下,返回数据帧的第一行,因为在 Pandas 中,索引从 0 开始。
另外,。iloc[]索引器也支持负整数**(从-1 开始)作为相对于数据帧结尾的位置。**
如上图,当单个行被选中时,。iloc[]索引器返回一个将列名作为索引的系列对象。然而,正如我们对所做的那样。loc[]索引器**,我们也可以通过以下方式将单整数列表传递给索引器来获得一个数据帧。**
最后,请记住,当试图访问一个超出界限的索引时,会引发一个 IndexError 。
7.按位置选择多行
为了按位置提取多行,我们向传递一个 list 或 slice 对象。iloc[]** 索引器。**
按位置选择多行
→df . iloc[整数列表]
→df . iloc[整数切片]
以下代码块显示了如何使用整数列表选择数据帧的前五行。
或者,我们可以使用切片符号获得相同的结果。
如上图,** Python 切片规则(半开区间)适用于**。iloc[]属性**,表示包含第一个索引,但不包含结束索引。**
8.同时选择行和列
到目前为止,我们已经学习了如何使用通过标签或位置选择数据框中的行。loc[]** 和**。iloc[]索引器**。但是,这两个索引器不仅能够选择行,还能够同时选择行和列。**
为此,我们必须提供由逗号分隔的行和列标签/位置,如下所示:
同时选择行和列
→df . loc[行标签,列标签]
→df . iloc[行 _ 位置,列 _ 位置]
其中 row_labels 和 column_labels 可以是单个字符串、字符串列表或字符串片段。同样, row_positions 和 column_positions 可以是单个整数、整数列表或整数片段。
以下示例显示了如何使用一次提取行和列。loc[]** 和**。iloc[]** 索引器。**
- 选择标量值
我们以下面的方式按职位和标签选择 id 号为 478 的雇员的工资。
在这种情况下,两个索引器的输出都是整数。
- 选择一行多列
我们选择 id 号为 478 的雇员的名字、姓氏和薪水,方法是将单个值作为第一个参数,将一个值列表作为第二个参数,结果得到一个 Series 对象。
- 选择不连续的行和列
要选择多个行和列,我们需要向两个索引器传递两个值列表。下面的代码显示了如何提取 id 号为 478 和 222 的雇员的姓名和薪水。
与以前不同,两个索引器的输出都是 DataFrame 对象。
- 选择连续的行和列
我们可以通过使用切片符号提取数据帧的连续行和列。下面的代码片段显示了如何选择 id 号为 128、478、257 和 299 的雇员的姓名和薪水。
如上所示,我们仅使用切片符号来提取数据帧的行,因为我们想要选择的 id 号是连续的(索引从 0 到 3)。
一定要记住。loc[]索引器使用闭合区间**,提取开始标签和停止标签。反之,。iloc[]步进器采用了半开区间,因此停止步进处的值不包括在内。**
9。使用选择标量值。在[]和。iat[] 索引器
如上所述,我们可以通过向传递由逗号分隔的两个字符串/整数来选择一个标量值。loc[]** 和**。iloc【索引器】。此外,Pandas 提供了两个优化的函数来从数据框对象中提取标量值:。在[] 和。iat[]运算符**。前者通过标签提取单个值,而后者通过位置访问单个值。**
通过标签和位置选择标量值
→df . at[字符串,字符串]
→df . IAT[整数,整数]
下面的代码显示了如何使用通过标签和职位选择 id 号为 478 的雇员的工资。在[]** 和**。iat[]索引器**。**
我们可以使用 %timeit 神奇函数来计算这两条 Python 语句的执行时间。如下图所示,。在[]** 和**。iat[]运算符比快得多。loc[]** 和**。iloc[]索引器**。**
****
最后,重要的是要记住。在[]** 和**。iat[]** 索引器只能用于访问单个值,在尝试选择数据帧的多个元素时会引发类型错误。**
10.使用布尔选择选择行
到目前为止,我们已经通过标签和位置过滤了数据框中的行和列。或者,我们也可以使用布尔索引在 Pandas 中选择一个子集。布尔选择包括通过为每行提供一个布尔值(真或假)来选择数据框的行。
在大多数情况下,这个布尔值数组是通过对单个或多个列的值应用一个条件来计算的,该条件的计算结果为 True 或 False,具体取决于这些值是否满足该条件。但是,也可以使用其他序列、Numpy 数组、列表或 Pandas 系列来手动创建一个布尔数组。
然后,将布尔值序列放在方括号[]中,返回与真值相关联的行。
使用布尔选择选择行
→df[布尔序列]
根据单个列的值进行布尔选择
根据单个列的值过滤数据框的最常见方法是使用比较运算符。
比较运算符计算两个操作数(a 和 b)之间的关系,并根据是否满足条件返回 True 或 False。下表包含 Python 中可用的比较运算符。
这些比较运算符可用于数据框的单个列,以获得一系列布尔值。例如,我们通过使用大于运算符来确定雇员的工资是否大于 45000 欧元,如下所示。
输出是一系列布尔值,其中高于 45000 的工资为真,低于或等于 45000 的工资为假。正如您可能注意到的,这一系列的布尔值与原始数据帧具有相同的索引(id 号)。
这个序列可以传递给索引运算符[],以便只返回结果为真的行。
如上所示,我们获得了一个数据框对象,其中只包含工资高于 45000 欧元的雇员。
根据多列的值进行布尔选择
之前,我们已经根据单个条件过滤了数据帧。然而,我们也可以使用逻辑运算符将多个布尔表达式组合在一起。在 Python 中,有三种逻辑运算符:and、or 和 not。但是,这些关键字在 Pandas 中不能用于组合多个布尔条件。相反,使用以下运算符。
下面的代码显示了如何选择工资高于 45000 并且有永久合同的雇员,该永久合同用逻辑运算符&组合了两个布尔表达式。
您可能知道,在 Python 中,比较运算符的优先级高于逻辑运算符。但是,它不适用于熊猫,在熊猫中,逻辑运算符的优先级高于比较运算符。因此,我们需要用括号将每个布尔表达式括起来,以避免错误。
使用熊猫方法的布尔选择
Pandas 提供了大量的内置函数,这些函数返回一系列的布尔表达式,对于结合了比较和逻辑操作符的更复杂的布尔表达式来说,这是一种很有吸引力的替代方法。
- isin 方法
熊猫。Series.isin 方法接受一系列值,并在序列中与列表中的值匹配的位置返回 True。
这个方法允许我们检查一个列中是否存在一个或多个元素,而不需要使用逻辑运算符 or。下面的代码显示了如何使用逻辑运算符 or 和 isin 方法来选择具有永久或临时合同的雇员。
如您所见,isin 方法对于检查同一列中的多个 or 条件非常方便。此外,它更快!
- 间法
以下代码选择工资高于或等于 30000 欧元且低于或等于 80000 欧元的雇员。
正如您所观察到的,两个边界(30000 和 80000)都包括在内。为了排除它们,我们必须以下面的方式传递参数 inclusive=False 。
您可能已经注意到,上面的代码相当于编写两个布尔表达式,并使用逻辑运算符 and 对它们求值。
- 串音方法
此外,我们还可以对字符串方法使用布尔索引,只要它们返回一个布尔序列。
下面的代码显示了如何选择所有包含 57 的电话号码。
当 contains 方法计算一个子串是否包含在一个序列的每个元素中时, 方法计算。series . str . starts with函数检查字符串开头是否存在子字符串。同样, 熊猫。series . str . ends with测试一个子串是否出现在一个字符串的末尾。
以下代码显示了如何选择姓名以“A”开头的雇员。
摘要
在本文中,我们介绍了从 Pandas 数据框中选择数据子集的最常见操作。此外,我们还提供了多个使用示例。现在!在清理自己的数据时,是时候将这些技术付诸实践了!✋
除了数据过滤,数据清理过程还涉及许多其他操作。如果您仍然有兴趣了解更多关于数据清理的知识,可以看看这些文章。
****** [## 使用 Pandas 和 Scikit 实现数据标准化-学习
清洁数据集的完整指南—第 1 部分
towardsdatascience.com](/data-normalization-with-pandas-and-scikit-learn-7c1cc6ed6475) [## 识别熊猫、Statsmodels 和 Seaborn 的异常值
清理数据集的完整指南—第 2 部分
medium.com](https://medium.com/swlh/identify-outliers-with-pandas-statsmodels-and-seaborn-2766103bf67c)
感谢阅读👐
阿曼达·❤️******
Python 中的过滤列表
Python 中的过滤方法
在本帖中,我们将讨论 Python 中列表过滤的三种方法。具体来说,我们将介绍如何使用列表理解、生成器表达式和内置的“filter()”方法来过滤 python 中的列表。
我们开始吧!
使用列表理解进行过滤
假设我们在一个列表中有数据,我们想提取值或根据一些标准减少列表。具体来说,让我们考虑下面的列表,它包含一个带有一些缺失值的医疗费用列表:
medical_charges = ["500", "1000", None, "450", "230", None]
print(medical_charges)
首先,我们可以使用列表理解来过滤掉“无”值:
medical_charges = [n for n in medical_charges if n != None]
print(medical_charges)
我们也可以将列表中的元素转换成整数,只是对列表的理解稍作修改:
medical_charges = [int(n) for n in medical_charges if n != None]
print(medical_charges)
将每个元素转换为整数后,我们还可以根据每个整数的大小进行过滤。假设我们要保持费用大于或等于 500 美元,我们可以写出下面的列表理解:
medical_charges = [n for n in medical_charges if n >= 500]
print(medical_charges)
使用发生器过滤
如果我们正在处理大量的数据,这是医疗记录的常见情况,我们可以使用生成器表达式进行迭代过滤。如果我们想用一个生成器表达式来转换我们的原始列表,我们做如下的事情:
charges = (int(n) for n in medical_charges if n != None)
print(charges)
从列表理解来看,语法上的主要区别是使用了圆括号而不是方括号。我们现在可以迭代生成器:
for charge in charges:
print(charge)
使用“LIST()”和“FILTER()”方法进行筛选
有时候,过滤标准不容易用列表理解或生成器表达式来表达。让我们考虑将我们的字符串值医疗费用原始列表转换为整数并删除缺失值的示例:
medical_charges = ["500", "1000", None , "450", "230", None]
我们可以定义一个函数,它接受一个列表,并尝试将每个元素转换成一个整数。当转换没有抛出错误时,我们返回 true。当转换抛出值错误时,我们使用 except 语句来捕捉错误并返回 false:
def convert_and_filter(input_list):
try:
int(input_list)
return True
except ValueError:
return False
然后,我们可以使用内置的“filter()”和“list()”方法。“filter()”函数创建一个迭代器,“list()”方法允许我们创建一个结果列表:
charges = list(filter(convert_and_filter, medical_charges))
print(charges)
我将在这里停下来,但是可以随意使用上面的例子。例如,您可以尝试更改 list comprehension 示例中的过滤条件,使其只包含少于或等于$500 的费用。
结论
总之,在这篇文章中,我们讨论了 Python 中列表过滤的四种方法。我们讨论了列表理解,这对它的可读性是有用的。我们还讨论了生成器表达式,如果我们想避免从大型数据集生成大型结果,可以使用它。最后,我们讨论了使用内置的“filter()”和“list()”方法以及一个自定义函数来过滤列表。我希望你觉得这篇文章有用/有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!
强化学习中的过滤——它们是什么,为什么我们不需要它们
过滤的数学概念的基本解释,以及我们如何在强化学习中应用它们。
进行强化学习所需的 为 的过滤【来源:【pixabay.com】pixel 2013
偶尔,当阅读强化学习领域的论文时,你可能会偶然发现一些听起来很神秘的短语,如*“我们处理一个过滤的概率空间”、期望值取决于过滤或“决策政策是ℱₜ-可测量的*”。没有测量理论[2,3]的正规训练,可能很难准确理解这种过滤需要什么。正式定义如下所示:
过滤的正式定义([2],自己的工作)
毫无疑问,对于那些熟悉测度理论的人来说,这是样板语言,但除此之外几乎没有帮助。谷歌搜索答案可能会导致通过σ-代数、Borel 集、Lebesgue 测度和 Hausdorff 空间的迷宫,再次假设你已经知道了基本知识。幸运的是,只需要对滤波有一个非常基本的了解,就可以理解它在 RL 域中的含义。本文将提供关于该主题的远非全面的讨论,但旨在给出核心概念的一个简要且直观的轮廓。
一个例子
在 RL 中,我们通常定义一个结果空间ω,它包含所有可能发生的结果或样本,其中 ω 是一个特定的样本路径。为了便于说明,我们将假设我们的 RL 问题与在第 t 日价格为 S ₜ的股票相关。我们当然希望低买高卖(精确的决策问题在这里无关紧要)。我们可以将买入/卖出决策表示为 xₜ(ω) ,,即该决策取决于价格路径。我们从价格 S₀ (一个实数)开始,每天价格按照某种随机过程上涨或下跌。在播放这一集之前,我们可以提前模拟(或数学定义)这样一个价格路径ω=[ω₁,…,ωₜ】。然而,这并不意味着我们应该在股票价格变动实际发生之前就知道它们——即使是沃伦·巴菲特也只能梦想拥有这样的信息!为了声称我们的决策基于ω而不是千里眼,我们可以说结果空间是“过滤的”(使用符号 ℱ ) ,这意味着我们只能观察到时间 t 的样本。
对于大多数 RL 从业者来说,这个限制听起来一定很熟悉。我们通常不是根据当前状态 Sₜ 来做决定的吗?的确,我们有。事实上,由于马尔可夫性质意味着随机过程是无记忆的——我们只需要嵌入在主导状态中的信息 Sₜ — 来自过去的信息是不相关的[5]。正如我们将很快看到的,过滤比状态更丰富、更通用,但实际上它们的含义是相似的。
让我们进一步形式化一下我们的股票价格问题。我们从一个离散的问题设置开始,其中价格要么上升( u )要么下降( -d )。考虑到三天的事件范围,结果空间ω可以通过二项式点阵来可视化[4]:
代表股票价格变化的二项式点阵模型(来源:[1],作者
事件和过滤的定义
在这一点上,我们需要定义一个“事件”的概念A∈ω。或许有点抽象地说,事件是结果空间的一个元素。简单地说,我们可以给一个事件分配一个概率,并断言它是否已经发生。正如我们将很快展示的那样,这与实现 ω 并不相同。
过滤 ℱ 是一个数学模型,代表关于结果的部分知识。本质上,它告诉我们一个事件是否发生过。“过滤过程”可以被视为一系列过滤器,每个过滤器为我们提供更详细的视图。具体地说,在 RL 环境中,过滤为我们提供了计算当前状态 Sₜ 所需的信息,而没有给出过程中未来变化的任何指示【2】。的确,就像马尔可夫性质一样。
形式上,过滤是一个σ-代数,虽然你不需要知道来龙去脉,但一些背景知识是有用的。不严格地定义,σ-代数是结果空间的子集的集合,包含可数个事件以及它们的所有补和并。在测量理论中,这个概念有着重要的含义,为了本文的目的,你只需要记住,σ-代数是事件的集合。
重温示例—离散案例
回到这个例子,因为过滤只有在付诸行动时才会活跃起来。我们首先需要定义事件,使用像’ udu’ 这样的序列来描述价格随时间的变化。在 t=0 时,我们基本上什么都不知道——所有的路径都是可能的。因此,事件集合 A={uuu,uud,udu,udd,ddd,ddu,dud,duu} 包含所有可能的路径ω∈ω。在 t=1 时,我们知道更多一点:股票价格上涨或下跌。对应的事件由uuu、uud、uu*【DD】和d 如果股价上涨,我们可以推测我们的样本路径 ω 将在 Aᵤ 而不是 Aₔ (当然反之亦然)。在 t=2 时,我们有四个事件集: Aᵤᵤ={uuu,uud} 、aᵤₔ={udu、udd }、aₔᵤ={杜 观察信息变得越来越细粒度; ω 可能所属的集合变得越来越小,数量越来越多。在 t=3 时,我们显然知道已经遵循的确切价格路径。*
定义了事件之后,我们可以为 t=0,1,2,3 定义相应的过滤:
二项式点阵示例的筛选(来源:[2],i 由作者创建)
在 t=0 时,每种结果都有可能。我们用空集∅和结果空间ω初始化过滤,也称为平凡**σ*-代数。*
在 t=1 时,我们可以简单地将 Aᵤ 和 Aₔ 加到 ℱ ₀上得到ℱ₁;回想一下定义,每个过滤总是包括其前一个过滤的所有元素。我们可以使用最新披露的信息来计算 S₁。我们也可以窥见未来(实际上没有透露未来的信息!):如果价格上涨,我们就不能在 t=3 时达到最低价格。事件集如下所示
t=1 时事件集 Aᵤ 和 Aₔ 的可视化(来源:[2],作者本人法师*)*
在 t=2 ,我们可以根据目前揭示的价格路径来区分四个事件。这里事情变得有点复杂,因为我们还需要添加并集和补集(符合σ*-代数的要求)。这对 ℱ ₁来说没有必要,因为 Aᵤ 和 Aₔ 的并集等于结果空间,而 Aᵤ 是 Aₔ 的补码。从 RL 的角度来看,你可能会注意到我们有比严格需要的更多的信息。例如,一个向上的运动跟随一个向下的运动产生了与反向运动相同的价格。在 RL 应用中,我们通常不会存储这样的冗余信息,但您可能会意识到数学上的吸引力。*
事件集可视化 Aᵤᵤ、 Aᵤₔ 、 Aₔᵤ 和 Aₔₔ 在 t=2(来源:[2],作者本人法师)
在 t=3 时,我们已经有 256 套,使用与之前相同的程序。你可以看到过滤很快变得非常大。过滤总是包含前面步骤的所有元素——随着时间的推移,我们的过滤变得更加丰富和精细。所有这一切意味着,我们可以更精确地指出我们的样本价格路径可能属于或可能不属于的事件。
一个连续的例子
我们几乎已经做到了,但如果我们只处理分散的问题,那将是我们的失职。在现实中,股票价格不只是“涨”或“跌”;它们将在一个连续的域内变化。许多其他 RL 问题也是如此。虽然在概念上与离散情况相同,但在连续设置中提供过滤的明确描述是困难的。同样,一些插图可能比正式定义更有帮助。
假设在每个时间步,我们模拟一个从实域 [-d,u】的返回。根据我们预测的时间,我们可以定义未来股票价格下跌的区间,比如在给定的时间点【329,335】。然后我们可以在这个域内定义区间。任何任意间隔都可能构成一个事件,例如:
区间的补码可能看起来像
此外,可能会定义过多的联合,例如
正如你可能已经猜到的,有无限多的各种形状和大小的这种事件,但它们仍然是可数的,我们可以给它们每个分配一个概率[2,3]。
我们对未来看得越远,我们就越能偏离当前的股价。我们可以用一个随时间扩展的圆锥形状来想象这一点(下面显示的是 t=50 和 t=80 )。在圆锥内,我们可以定义无穷多个区间。和以前一样,随着时间的推移,我们获得了更详细的视图。
t=50 和 t=80 时连续域中的事件集。在锥内,可以定义无限多个区间来构造过滤。(来源:[2],我法师作者*)*
包装东西
当在任何 RL 论文中遇到过滤时,本文中讨论的基础知识就足够了。从本质上来说,引入过滤的唯一目的是ℱₜ确保决策不会利用尚未披露的信息。当马尔可夫性质成立时,对当前状态进行操作的决策xₜ(sₜ】服务于相同的目的。过滤提供了对过去的丰富描述,然而在无记忆问题中我们不需要这些信息。然而,从数学的角度来看,这是一个优雅的解决方案,有许多有趣的应用。强化学习社区由许多来自不同领域的不同背景的研究人员和工程师组成,并非每个人都讲同一种语言。有时学习另一种语言会有很大的帮助,即使只有几个单词。
【本文部分基于我的 ArXiv 文章《强化学习中过滤的温和讲义》】
参考文献
[1]世界法官协会范·赫斯维克(2020 年)。强化学习中的过滤。arXiv 预印本 arXiv:2008.02622
[2] Shreve,S. E. (2004 年)。金融随机微积分 II:连续时间模型,第 11 卷。斯普林格科学与商业媒体。
[3] Shiryaev,A. N. (1996 年)。概率。斯普林格纽约-海德堡。
4 luen Berger,D. G. (1997 年)。投资科学。牛津大学出版社。
[5]鲍威尔(2020 年)。关于状态变量、Bandit 问题和 POMDPs。arXiv 预印本 arXiv:2002.06238
终于可用和可访问,但错误的方式?
“嵌入式分析是一种数字工作场所功能,数据分析在用户的自然工作流程中进行,无需切换到另一个应用程序。”[1]在 Logi Analytics 年度嵌入式分析状况调查[2]的 500 多名受访者中,超过 85%的受访者(主要来自北美)以某种形式为其 SaaS 应用提供嵌入式分析。听起来不错,但似乎行不通。根据 Gartner 对分析和商业智能的宣传周期,嵌入式分析已经度过了“膨胀的期望”的高峰,正在走向幻灭的低谷,在此期间,“随着实验和实施失败,兴趣减弱”[3]。
来源: Gartner 的分析和商业智能炒作周期,2019 年
为什么采用速度比预期慢?依我拙见,即使技术使可用的数据,读“数据收集并准备使用”,读“容易检索”,但它有多大用处?
终于可用且易得,但方法不对?
在过去的几个月里,我收到了几个关于一些 SaaS 应用程序中嵌入的默认现成仪表板和报告的问题,这让我想知道应用程序团队是如何提出在那里显示指标的。我在这里是什么意思?成熟&成熟的行业/领域/学科通常有一套预定义的标准和关键绩效指标(KPI)来管理和衡量其增长,例如,在客户服务方面,可能是平均响应时间、首次呼叫解决、平均解决时间、票据数量等。如果幸运的话,您的 SaaS 应用程序将跟踪 2-3 个与您的业务相关的指标。如果你想得到比开放票和封闭票数量稍微严重一点的东西,你需要做好花钱的准备。“数据是新的黄金”这句话在这里变成了现实,因为在许多情况下,你需要为每个座位付费。本文的目的是为作为 Freshdesk 最终用户的您提供一些嵌入式仪表盘/报表的替代方案,以防它们无法满足您的某些信息需求/您不想为您的报表倾家荡产。
可用
fresh desk(fresh works Inc .的产品)是一个票证管理解决方案,允许您的客户服务团队管理票证和联系人。收集的数据:票证、对话、联系人、代理、技能、角色、组、公司、讨论、解决方案、满意度、产品等—有关端点的完整列表,请查看 Freshdesk API 文档此处。
来源:Forrester Wave:客户服务解决方案,Q2 2019
可访问
您可以查看的报告和指标数量取决于您的订阅(请参见 Freshdesk 的客户服务指标此处)。如果您不准备让您的订阅成本增加一倍或三倍,您可以查看下面的集成平台即服务(iPaaS),它从您的 Freshdesk 中提取数据并将这些数据加载到您的数据存储中,以便您可以使用商业智能/仪表板工具来访问这些数据,例如,下面的 iPaaS 具有连接 Freshdesk 和 Power BI 的连接器:
1。扎皮尔
2.歌手/缝线
4.工作狂
5.或者,你也可以研究一些专门的工具,比如荧光瞄准镜。如果你预算不足,这里有一个方法可以让你仍然获得客户服务绩效的仪表板/报告。
什么?Python,crontab 文件,数据存储。
1。假设您的系统上已经安装了 Python。如果没有,可以使用 Conda ,一个开源的软件包管理系统和环境管理系统,用于安装多个版本的软件包及其依赖项。
2.检索您的 Freshdesk API 密钥。点击查看帮助文章。
3.更改您的 Freshdesk 和数据库连接,并运行以下代码片段。
看代码这里
4.使用 cron 调度脚本的执行。根据你的操作系统,你需要执行不同的步骤,因此,我会建议你谷歌一下。
就是这样。通过使用现有的连接器或运行您自己的 Python 脚本,您将能够提取几乎所有收集到的数据,对其运行不同类型的报告/分析,并且有希望从中获得价值,而不局限于应用程序团队添加到默认视图中的指标。
参考:
- 位于的 Gartner 词汇表 https://www . Gartner . com/en/information-technology/Glossary/embedded-analytics。于 2020 年 4 月 11 日访问
- Logi Analytics 嵌入式分析状态报告,2018 年。于 2020 年 4 月 11 日访问
- Gartner 的分析和商业智能炒作周期,2019 年在https://www . Gartner . com/en/news room/press-releases/2019-10-02-Gartner-揭示-五大趋势-塑造-演进。于 2020 年 4 月 11 日访问
- Forrester Wave:客户服务解决方案,https://go.oracle.com/LP=86252?elqCampaignId=2299132019 年 Q2。于 2020 年 4 月 11 日访问
最后记住精确和回忆
对基本指标——精确度和召回率——的解释,并以土豆分类为例
你是否也很难记住什么是精度和召回?在计算时,我们必须考虑混淆矩阵的行或列。但是什么是什么呢?它们的含义有什么不同?为什么准确度不够?
本文将解释这些问题,并阐明这两个指标之间的区别。最后,你会发现两个测试你理解能力的问题。
动机
假设你是一个农民——马铃薯种植者。你有一台从地里摘土豆的机器,但有一个问题。机器有时拿石头当土豆(反之亦然)。想象机器本身是一个分类器。如果它接受一个对象,这意味着它认为对象是一个土豆。相反,如果它没有不接受该对象,就意味着它是一块石头,所以我们把它留在现场。只有这两种状态。
罗布·穆德在 Unsplash 上拍摄的照片
精度不够吗?
不,不幸的是没有。让我们考虑一个极端的例子。田地里有 95 颗石头和仅仅 5 个土豆(总共 100 个物体),我们有一个准确率 95% 的模型。这是一个相当高的精度,我们可以满意的模型。然而,我们不知道我们有多少土豆。有更多可能的变体,我们可以得到什么(什么模型认为是一个土豆):
- 5 个土豆和 5 块石头(90 块石头正确留在地里),
- 2 个土豆和 2 块石头(93 块石头正确留在地里),
- 0 个土豆和 0 颗石子(95 颗石子正确留在地里),
- …
所有这些例子都有 95%的准确率,因为它们正确识别了 100 个物体中的 95 个,无论是土豆还是石头。我承认这个例子不太可能。然而,正如我们所看到的,我们可以获得所有土豆以及没有土豆的相同精度。准确性告诉我们关于一个类的任何具体信息。
精确和召回解决了这些问题。一般来说,准确性并不完全适合不平衡的数据,如果我们只对一个类感兴趣(更一般地说:如果我们只对类的子集感兴趣),准确性就不方便了。
回到我们的土豆…
我们制作了一个模型(分类器),学习土豆的样子。模型的学习(训练)看起来是这样的:
老师:“嘿模特,这是土豆。”
型号:“好的,我会记住那个土豆长这样。”
老师:“嘿模特,这又是一个土豆。”
型号:“好的,我会记住土豆也可以是这个样子的。”
老师:“嘿模特,这不是土豆。”
型号:“好的,我会记住那个土豆不是这样的。”
…
这有点抽象。模特训练不完全是对话。但是我们稍后将回到模型记得某事的想法。
假设机器从地面上拿起 10 个物体(真值),并确定它们是否是土豆,如下图所示。我们将在下面的解释中使用这个例子。
作者图片
混淆矩阵
不提到混淆矩阵就无法解释度量。如果您熟悉这个问题,可以跳过这一部分。
混淆矩阵(CM)是一张命中(右侧预测案例——绿色部分:TP、TN)和错误(红色部分:FP、FN)的表格。
作者图片
- TP (真阳性)是正确预测 p 阳性病例的数量(命中)。
- TN (真阴性)是正确预测 n 阴性情况(命中)的数量。
- FP (假阳性)是错误预测 p 阳性病例(错误)的数量。
- FN (假阴性)是错误预测 n 阴性情况(错误)的数量。
然后根据这些值计算各个指标。
如果我们将测试(预测)阶段视为一个对话,它看起来会像这样:
老师:“嘿模特,这是什么?”
型号:“我觉得,是土豆。”
老师:“那是 T 芸香!你称它为 P otato ( P 正值),所以我将增加真正值。”TP += 1
老师:“嘿模特,这是什么?”
型号:“我会说,它是个土豆。”
老师:“不,不是土豆!你说土豆,但它是石头——所以它也是石头。你预测了 P otato ( P 正值),所以我给误报加一。”FP += 1
老师:“嘿模特,那这个呢?”
型号:“我觉得,它不是土豆。”
老师:“那是 F alse,这是土豆!你的预测是 N 不是土豆,所以我必须增加假阴性值。”FN += 1
老师:“嘿模特,这是什么?”
型号:“这样的话,我猜它不是土豆。”
老师:“那是 T rue!正如你所猜测的,这是一个土豆。我给真底片加一。TN+= 1
…
精确
精度告诉我们模型的精度有多高。换句话说,我们收集的物品中有百分之多少实际上是土豆。
它是右预测正值 (TP)除以预测数(检索项——在我们的例子中是 CM 的第一列之和)的比值。
在土豆的例子中,它是检索到的土豆除以所有检索到的对象的比率(我们的机器获取的所有东西——我们的模型归类为土豆的所有东西)。
阳性预测值 (PPV)是精度的别称。
回忆
另一方面,回忆告诉我们收集的土豆占实际土豆的百分比。它是右预测正值 (TP)除以所有现有正值(在我们的例子中是第一行 CM 之和)的比值。
在马铃薯的例子中,它是取回的马铃薯的比率除以田地中生长的所有马铃薯的比率。
这个公式里只有土豆(正值)!它有时被称为敏感度或真阳性率。
好吧,那怎么记呢?
回忆这个词也有“记住”(作为动词)的意思。所以它是模型正确记忆的比率——正确预测的正值。让我们回到前面提到的观点,模型训练就是背诵或者记忆。
在训练中,我们向我们的模型展示了(例如)10 个土豆。现在我们将再次向我们的模型展示同样的 10 个土豆,但是我们将要求模型决定它们是否是土豆。该模型将在 8 种情况下决定(记住)马铃薯(例如)。这意味着召回率等于 80% 。这个模型正确地识别了 10 个土豆中的 8 个。
**边注:**合适的模型要能概括。换句话说,它也应该正确地预测以前未见过的情况。
结论
如果我们只对一类感兴趣,或者数据不平衡**,那么精度**并不完全合适。它是所有正确预测的百分比(土豆和石头加在一起)。
如果我们计算精度,我们只看模型的正面预测。另一方面,只有阳性病例包含在召回计算中。
使用精度,如果农民从田地里尽量少拿石头更重要。如果当务之急是在田地里留下尽可能少的土豆,召回正好相反。
问题—现在清楚了吗?
1)模型选择的内容直接用于(无需进一步分类)食物准备。哪个型号最好?
- 模型 A: 准确率= 100%,召回率= 90%
- 模型 B: 准确率= 90%,召回率= 100%
- 模型 C: 准确度= 98%
2)如果你的目的是从地里尽可能多的获取土豆,那么哪个型号最合适?
- 模型 A: 准确率= 100%,召回率= 90%
- 模型 B: 准确率= 90%,召回率= 100%
- 模型 C: 准确率= 98%
Monika Grabkowska 在 Unsplash 上拍摄的照片
问题的解决
1)模型 A
在这种情况下,精度等于 100% 很重要。我们不想在饭里放石头。
2)模型 B
在这种情况下,召回等于 100% 是重要的。我们不想在地里留下任何土豆。
一旦你直接用你的模型选择的土豆准备午餐,我祝你精度等于 100%。😃
请慢用!;——)
新到中?解锁无限访问(并支持我)!
80/20 分割直觉和另一种分割方法
凯文·施密德在 Unsplash 上的照片
我是一个好奇的人。这是我的天性。这就是为什么我小时候会拆解很多圣诞礼物,我想知道“为什么”。所以当我问这个问题时,“为什么我们在这个数据集上使用 80/20 的训练/测试分割?”而且得不到具体的答案,简直让我抓狂。我一头扎进了训练/测试分裂的“为什么”。可能有比我所能找到的更多的方法,但是我将在“interverse”中介绍几个训练/测试分离练习,看看它们如何达到标准,或者是否重要。
帕累托原理
帕累托法则也被称为 80/20 法则。总的来说,在大多数情况下,80%的结果来自 20%的原因。对于那些想进入这个兔子洞的人,请随意查看维基百科。虽然该原则的序言是基于财富分配,但从统计学角度来看,它确实接近于解释许多人类、机器和环境现象。由于这个原因,并且通常在不知道来源的情况下,许多人使用 80/20 分割来进行训练和测试。
Calum MacAulay 在 Unsplash 上拍摄的照片
缩放定律
1997 年,在一篇名为 的论文中讨论了一种新的方法——验证集训练集大小比 *(Guyon)的标度律。在这里,他们引用了“*针对特定问题的最佳训练/验证分割:防止神经网络的过度训练。他们发现为验证集保留的模式部分应该与自由可调参数数量的平方根成反比。我们的结果推广并证实了他们的结果。”(Guyon,1997 年)。本质上,分裂是由数据集中有多少独特的特征(不包括目标)而不是观测值的数量决定的,这与大多数关于该主题的观点相反。
让我们用可靠的泰坦尼克号数据来看看标度律是否优于假设的帕累托分裂。该数据集已经被估算以填充来自前一个 post 预处理的空值:编码和 KNN 快速估算所有分类特征。
首先,我们将加载数据,确保所有列都可见,并运行. head()方法来验证数据。
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
split_data = pd.read_csv('titanic_encoded_scaled-Copy1.csv')
pd.options.display.max_columns = None
split_data.head()
接下来,我们将去掉未命名的列,并将数据拆分为 X 和 y 变量。因为我们正在测试模型改进,所以最好使用多类目标,所以使用 deck1 列(7 个类)。
split_data = split_data.drop('Unnamed: 0', axis=1)
X = split_data.iloc[:,:-2]
y = split_data.iloc[:,-2]
在之前的另一篇文章中,我们发现将 PowerTransform scaler 设置为“yeo-johnson”方法时,该数据的缩放效果最好。如果您想一窥究竟,只需看一看:预处理:标准化方法的差异
from sklearn.preprocessing import PowerTransformer
yj = PowerTransformer(method = 'yeo-johnson')
yj_data = yj.fit_transform(X)
现在,我们将使用 sklearn 库将我们的数据分成 train 和 test。一、帕累托原理(80/20):
#Pareto Principle Split
X_train, X_test, y_train, y_test = train_test_split(yj_data, y, test_size= 0.2, random_state= 123)
接下来,我们将运行该函数来应用比例法则,并将该数据拆分为不同的变量:
#discover scaling law split
columns = 14
test = 1/np.sqrt(columns)
train = 1 - test
print(test)
print(train)
#Scaling Law Split
A_train, A_test, b_train, b_test = train_test_split(yj_data, y, test_size= test, random_state= 123)0.2672612419124244 #test
0.7327387580875756 #train
帕累托定律和标度定律之间的差异几乎为 7%。现在运行两个数据集的标准逻辑回归模型:
#perform logistic regression using pareto split
from sklearn.linear_model import LogisticRegression
bn1 = LogisticRegression(max_iter=1000)
bn1.fit(X_train, y_train)
pp_preds = bn1.predict(X_test)# use logistic regression using scaling law split
bn2 = LogisticRegression(max_iter=1000)
bn2.fit(A_train, b_train)
sl_preds = bn2.predict(A_test)
以下是帕累托原则的分类报告:
#classification report from pareto split
from sklearn.metrics import classification_report
print(classification_report(y_test, pp_preds)) precision recall f1-score support
0.0 0.00 0.00 0.00 5
1.0 0.38 0.33 0.36 15
2.0 0.37 0.59 0.45 17
3.0 0.38 0.16 0.22 19
4.0 0.52 0.34 0.41 38
5.0 0.67 0.87 0.76 69
6.0 0.82 0.88 0.85 16
accuracy 0.59 179
macro avg 0.45 0.45 0.44 179
weighted avg 0.55 0.59 0.55 179
相当不错的 59%的准确率。现在,比例定律报告:
#classification report from scaling law
print(classification_report(b_test, sl_preds)) precision recall f1-score support
0.0 0.50 0.20 0.29 5
1.0 0.31 0.26 0.29 19
2.0 0.35 0.52 0.42 21
3.0 0.30 0.12 0.17 26
4.0 0.61 0.47 0.53 53
5.0 0.71 0.88 0.78 97
6.0 0.84 0.89 0.86 18
accuracy 0.61 239
macro avg 0.52 0.48 0.48 239
weighted avg 0.59 0.61 0.59 239
准确率提高了 2%,精确度、召回率和 f1 得分也有所提高!
包装完毕
在我看来,从全局来看,2%是一个相当大的增幅。当然,这是一个简单的多类逻辑回归模型,但是正如我所鼓励的,在你拥有的任何数据集上测试这两种分割方法。这真的是一个简单的算法,可以产生额外的差异。
和往常一样,你可以在 Github 上找到我的作品。这个特别的回购在这里是。祝你愉快!
终于可以开始理解机器学习论文了
示例、提示、注释和解释
你上一次打开机器学习论文,看到大量术语和数学,然后决定不打开它是什么时候?我怀疑很多人都有过这样的经历,包括我自己。
数据科学变得越来越容易为所有人所掌握。然而,随之而来的是负面影响——许多通过在线资源学习机器学习的人可能不熟悉阅读深入描述他们日常工作方法的技术论文。这篇文章的目标是给那些以前觉得机器学习论文不适合他们的人一个演示,如果用正确的工具和心态武装起来,他们可以变得多么容易。
当然,一篇文章不足以充实大学课程和学习的时间,从而对机器学习背后的复杂数学有一个坚实的理解。然而,希望它能够在阅读原始机器学习论文突破时给予更大的理解和信心。再多的谷歌搜索或在线资源也无法击败原始论文。
我们将浏览最初的批量标准化论文,许多人认为这是机器学习中最大的突破之一。这篇论文虽然充满了数学,但并不过分技术化、易懂和直观。沿着这条路,本文将提供细目分类、提示、注释和词汇表。记得先读报纸上的剪报。
批处理规范化论文的作者立即开始初始化变量。
提示:众所周知,机器学习论文创造了许多变量,并期望读者在以后引用它们时知道它们的意思。拿一支荧光笔,在变量“初始化”的地方和以后使用的地方突出显示。这将使阅读变得容易得多。
作者提出了随机梯度下降的公式,初始化几个变量,如参数和训练样本集中的最大数量。
glossay:“arg minf(x)指的是最小化以下函数的自变量或输入,在本例中为 f ( x )。
用英语来说,该语句是这样的:“网络的参数θ等于[由函数l概括的所有值的平均值]最小化的值,该函数接受单个训练点和当前参数。”这是神经网络目标的数学上的严格定义。仅仅为了严谨起见,数学方程通常被写得比实际更复杂。写出方程式在人类语言中的含义是很有帮助的。
作者指出,使用 SGD,训练分步骤进行,概述了代表每个“小批量”大小的附加变量 m 。通过使用小批量而不是一次一个示例,损失的梯度是对整个集合的梯度的更好估计。
突出显示的语句为“训练小批量中所有值 i 的[损失函数的变化,其包括当前训练示例和参数,相对于参数]”的平均值。这是“梯度”的定义,它计算损失函数的误差范围,以提供关于应该如何更新参数的见解。使用[分数][sigma]几乎总是一种复杂的方式来表示平均值。
术语表: ∂被普遍用来表示偏导数,或者一个函数中两个或更多变量的变化。简单来说,导数可以被认为是“一个变量对另一个变量的影响的微小变化。”
虽然 SGD 由于各种原因而工作良好,但作者写道,一层输入分布的变化会给下面的层带来困难,因为它们需要适应变化的分布,这种现象被他们称为协变量移位。
虽然传统上这是通过域适配来处理的,但是作者认为该思想可以扩展到子网或层。
第一个突出显示的语句是“损失等于对[一个参数]的任意变换和对(另一个参数和一个输入 u )]的任意变换”。在这份声明中,作者正在建立一个假设的网络来支持他们的想法。作者简化了初始语句,用 x 替换一个组件来表示前一个函数的输入。θ[1]和θ[2]是为了使损耗 l 最小而学习的参数。这些前提等同于一个完整的神经网络,只是以较小的规模构建。
突出显示的方程演示了梯度下降背后的机制,它通过计算偏导数来计算梯度,进度由学习速率决定。该变化可以是正的或负的,从参数θ[2]中减去,并且旨在将参数导向最小化损耗/ F2 的方向。
作者写道,这个梯度下降步骤对于输入为 x 的单个网络 F2 是相同的,以建立真实神经网络和假设神经网络之间比较的合法性。因为 itθ[2]不需要重新调整来补偿 x 的分布变化,所以保持 x 的分布固定一定是有利的。
注:这是机器学习论文中常见的主题。因为机器学习涉及的系统比其他领域涉及的变量多得多,也复杂得多,所以它的论文通常会遵循三个步骤来展示论文是如何工作的:
1。创建一个假设的简单系统。
2。建立它与真实神经网络之间的相同性质。
3。通过对简单系统进行运算得出结论。当然,在更现代的论文中,我们会看到一个完全致力于显示准确性的部分,以及该方法如何在各种常见的基准数据集(如 ImageNet)上工作,并与其他方法进行比较。
此外,作者写道,固定的输入分布对整个网络的输入都是有益的。他们提出了标准方程
z = g(Wu + b) ,其中 W 代表权重, b 代表偏差。 g(x) 被定义为 sigmoid 函数。作者指出,随着 x 与 0 的距离增加,其导数——或梯度——越来越接近 0。
因为导数在极值 x 处倾斜,当分布移动时,由于 sigmoid 函数的性质,给出的信息(梯度)较少。
术语表:g’(x) 是 g(x) 的导数的另一种表示法。
因此,作者得出结论,梯度传播的有用信息在到达网络后部时会慢慢消失,因为分布的变化会导致信息的累积衰减。这也被称为消失梯度问题。(它的反面,爆发式梯度问题,是海量梯度导致权重剧烈波动,导致学习不稳定。)
作为解决这一问题的一个建议,他们考虑了一个向输入添加可学习偏差的层,然后将结果标准化。如果由偏差引起的归一化变化被忽略(偏差的梯度被独立计算和更新),更新 b 和归一化的相应变化的组合在输出层中没有产生变化。
词汇表:E[x] 常用来表示 x 的均值,其中“ E ”表示“期望值”。这将在后面用正式的求和定义来定义。∧**表示“正比于”——b中的 delta(变化)正比于标准的梯度下降公式。
这在数学上得到了证明——由于 x [hat]等于x—E[x]x等于 u + b ,这些语句组合起来就形成了u+b—E[u+b。而对 b 的变化,用δb表示,相互抵消,等于本身没有任何变化。因此, b 将由于故障梯度而无限增长,而损耗保持固定。
提示:往往论文会设置各种语句,突然组合在一起。作者如何得出结论可能令人费解;试着找出各种相关的方程式,看看它们是如何组合在一起的。然而,更重要的是,理解这个等式意味着什么。
出于这些考虑,作者稍微调整了他们的批量归一化公式,以独立地归一化每个标量特征,每个特征都具有零均值和单位方差。通过消除不必要的偏差,该层将所有输入转换为正态分布的输出。
批处理标准化文档中还有很多内容需要阅读和理解。但是,请注意,这些作者得出的结论已被证明存在轻微缺陷,具体来说,内部协变量变化是批处理规范化如此有效的原因。
现在你有了工具…
你已经准备好接受其他机器学习论文了!看看这些伟大的原创论文:
批量归一化论文,辍学论文,用于图像识别的深度残差学习,利用卷积神经网络进行大规模视频分类,生成式对抗网络。
如果您有兴趣了解更多关于批处理规范化的知识,以及它如此有效的真正原因(不是因为内部协变量的变化),请查看这篇文章:
它是如何工作的——又是如何如此有效的?
medium.com](https://medium.com/analytics-vidhya/batch-normalization-the-greatest-breakthrough-in-deep-learning-77e64909d81d)
财务独立——用 Python 模拟 ODEs
作者试图战胜地心引力。波兰 2015。
使用 Python 来设置你的路径。
介绍
想象一下,有一天你醒来,你知道你可以在余生中自由地做任何你想做的事情…而且…钱不再是问题。你变得真正经济独立并且你不再需要工作来保证来年的收入。听起来有吸引力吗?
虽然听起来可能如此,但实现这一目标的道路肯定不容易(不像 Youtube 广告所说的那样)。在处理你的财务问题时,有许多因素需要考虑,而推理往往被复杂性所掩盖。
在本文中,我们将从数学和程序上解决这个问题。
我们将使用一组常微分方程* (ODEs)来为你的钱包建模,稍后我们将使用scipy
库和 Python 来求解。在每个阶段,我们将尝试将数学公式与 python 代码联系起来,并解释其背后的推理。*
目标是使模型具有可解释性和可扩展性。我们将一步一步地创建它,希望这能让我们对底层数学和代码有更直观的理解。作为参考,请看看下面的笔记本:这里。
放弃
在我们进入等式之前,我们想强调的是,这篇文章在任何情况下都不应该被视为财务建议。这篇文章的作者有物理学而不是金融的背景,所以也请原谅使用的词汇中任何可能的不一致。
问题陈述
看钱包有两种方法。
一种方法是看看在任何给定的时间点 t 你有 x(t) 多少钱。另一种方法是看它如何随时间变化。知道初始量 x₀ = x(0) 以及一阶导数 dx/dt ,你就可以预测未来的情况。
因为在我们看来,为导数制定方程是一个简单得多的过程,我们将倾向于这种方法,而不是直接寻找 x(t) 。毕竟,一旦我们有了 dx/dt 的完整表达式, x(t) 就可以通过数值积分 dx/dt 得到:
前提是我们知道 x₀。
简单模型
你朝九晚五地工作…
让我们从一个简单的例子开始,你有一份工作。您现在还没有投资,您的年度余额由以下三个因素决定:
- 你的年收入是多少?
- 你所有的花费……一切:食物、房租、汽车、饮料,无论什么,
- 你为你的收入缴纳的税。
如果没有其他因素起作用,你的收益*(或损失 ) —你变富或变穷的比率是:*
因此,我们可以设定
如果 a,s 和 T 是常数,那么这个等式实际上非常简单,我们可以解析地求解它:
这是一条直线,但是因为我们只是设置了逐渐增加复杂性的路径,所以让我们用 python 来做。
*import numpy as np
import pandas as pd
from scipy.integrate import odeint
class Life:
def __init__(self):
self.income = 10000 # gold pcs. per month
self.spending = 5000 # gold pcs. per month
self.tax_rate = 0.19 # example
def earn(self, t):
return 12 * self.income
def spend(self, t):
return 12 * self.spending
def pay_taxes(self, t):
return self.earn(t) * self.tax_rate
def live_without_investing(x, t, you):
return you.earn(t) - you.spend(t) - you.pay_taxes(t)*
这里,Life
是类,我们将使用它的方法来定义分数贡献。虽然其形式纯粹是为了方便起见,但将贡献的定义分开是有意义的,因为它们本身会变得复杂(例如累进税)。
live_without_investing(...)
函数是我们的衍生物,因此,它有一个精确定义的接口func(x, t, **args)
。
为了执行集成,我们可以使用来自 scipy 的odeint
。
*def simulate(you):
t = np.linspace(0, 100, num=101)
x = odeint(live_without_investing, 0, t, args=(you,))
return pd.DataFrame({'time': t, 'wallet (non-investor)': x})
you = Life()
df = simulate(you)*
这里,我们定义了 100 年的时间线,粒度为 1,并将其作为第三个参数传递给odeint
。作为第二个参数传递的零代表 x₀ = 0 这是我们的初始条件。第四个(可选的)参数允许我们向函数传递额外的参数,我们刚刚通过传递you
object 做到了这一点。
生活的不连续性
很难想象你五岁的时候就已经在交税了。同样,过了某个年龄,你可能会想收获你工作的成果。
为了将这些关键变化融入你的生活,我们将把它分成三个阶段:
- 童年——你完全依赖父母,因此 x(t) = 0 。
- 积极的生活——你挣钱,你消费,你纳税。
- 退休 —你的收入被低于收入的养老金取代,你的支出故意保持在同一水平,但税收被认为已经缴纳。
同时,我们引入了另外两个参数:you.starting_age
和you.retirement_age
作为你在上述阶段之间转换的年龄。
对于我们的数学模型,这种转变意味着存在两个点 t₁ 和 t₂ ,在这两个点 dx/dt 是不连续的。为了正确计算 x(t) ,我们需要对你一生中的 dx/dt 进行分段积分,从摇篮到坟墓。**
对于我们的代码,我们以下列方式修改模型:
*class Life:
def __init__(self):
... # as before
self.pension = 1000
self.starting_age = 18
self.retirement_age = 67
def earn(self, t):
if t < self.starting_age:
return 0
elif self.starting_age <= t < self.retirement_age:
return 12 * self.income
else:
return 12 * pension
def spend(self, t):
... # as before
def pay_taxes(self, t):
... # as before
def life_without_investing(x, y, you):
... # as before*
然后,模拟变成:
*def simulate(you):
t0 = np.linespace(0, you.starting_age - 1, num=you.starting_age)
t1 = np.linespace(you.starting_age, you.retirement_age - 1, num=(you.retirement_age - you.starting_age))
t2 = np.linespace(you.retirement_age, 100, num=(100 - you.retirement_age))
x0 = np.zeros((t0.shape[0], 1))
x1 = odeint(live_without_investing, 0, t1, args=(you,))
x2 = odeint(live_without_investing, x1[-1], t2, args=(you,))
df0 = pd.DataFrame({'time': t0, 'wallet (non-investor)': x0})
df1 = pd.DataFrame({'time': t1, 'wallet (non-investor)': x1})
df2 = pd.DataFrame({'time': t2, 'wallet (non-investor)': x2})
return pd.concat([df0, df1, df2])*
注意,我们还将 x(tₙ) 作为初始条件输入到下一个积分中。虽然 dx/dt 是不连续的,但是 x(t) 就不能这么说了!
图一。示例“使用起始年龄=18 岁”,“退休年龄= 67 岁”,收入= 1000,成本= 650,税率= 19%。注意到一旦过了退休年龄,养老金就不能补偿支出,从而导致债务。
添加非线性
到目前为止,我们假设钱包每年的增长是一个常数函数δ= a—s—T(a),δ≠δ(T)。你可能会获得一些年度加薪或增加你的支出。也有可能你想把税率本身建模成一个依赖于时间的函数。
假设你的收入现在是时间的线性函数 a(t)=α₀+α₁t(T25),这里是你的预期基本收入(平均值),是额外的“黄金个人电脑”数量你每年都会收到。类似地,支出也可以用 s(t)=σ₀+σ₁t(t27)的形式表示,σ₀是平均每月支出,是你未来将要支出的额外金额——一种“生活水平的通胀”。
现在,我们的导数与时间成正比 dx/dt ∝ t ,因此我们可以期望是二次的 x(t) ∝ t 。
同样,以编程方式:
*class Life:
def __init__(self):
... # as before
self.pay_raise = 100
self.life_inflation = 50
def earn(self, t):
... # as before
elif self.starting_age <= t < self.retirement_age:
return 12 * (self.income + self.pay_raise \
* (t - self.starting_age))
else:
... # as before
def spend(self, t):
... # as before
return 12 * (self.costs + self.life_inflation \
* (t - self.starting_age))*
集成保持不变,但它带来了一个新的结果。
图二。使用附加参数的示例:pay _ raise = 100
, life _ inflation = 50
。观察两条曲线的抛物线形状。
投资
如果你按照计算,你可能已经试图根据与你更相关的数字来预测你的财务状况。你可能已经注意到,即使你选择不提高自己的生活水平,平均工资的高增长也不能保证提前或安全退休。
从数学上来说,你可以自由构建任何你想要的“加薪”条款(例如 a(t) ∝ t 或 a(t) ∝ t ),但你可能很难证明它们的实际来源。况且这样的条款只能给你的钱包多项式的增长,说实话,还没有它能得到的那么快。
在这个阶段,你们中的一些人可能已经回忆起了复利的公式:
其中 FV 代表未来值*,PV 为现值(通常称为本金), R 为利率, t 为时间步长(年) n 为每年利息资本化的次数。在我们的例子中,为了简单起见,FV ≡ x(t) 、PV ≡ x₀ 和 n = 1 。*
公式本身可以有两种不同的理解方式。一种方式是理解它作为随后应用某个函数 f: x → x ⋅ (1 + R) 的结果,该函数将输入乘以某个因子 (1 + R) :
另一种方法是把它想成下面导数的一个主要函数:
上面的等式不是别的,只是一个例子,其中一个函数与其自身的增长成比例,我们可以通过重新排列各项并积分来确认这一点:
**
包括对模型的投资
这就是有趣的地方。在实践中,我们更感兴趣的是为投资持续提供资金,而不是投资一些 x₀作为一次性机会。此外,要了解整体情况,重要的是我们仍然要考虑本文前面提到的影响因素。
由于表达式可能会很快变得错综复杂,导数方法似乎是一种更简单、更优雅的表述问题的方式。我们要做的就是不断增加不同的贡献,然后积分方程。
为了更直观,现在让我们定义两个 x 。让 x₁ 做原钱包,而 x₂ 做投资桶。换句话说,你可以将 x₁ 视为你的主要银行账户,在那里你领取工资、支付账单和纳税,但现在你也可以选择将剩余的部分 β ∈ [0,1] 转移到 x₂ 。然后,你用这些钱购买股票、债券、商品、房地产等。无论你做什么,你都在继续*(再)投资*x₂,假设一些预期利率 R 并倍增你的钱。
在这种情况下,初始方程变成两个耦合的常微分方程的系统:
为了说明新的情况,让我们更新代码:
**class Life:
def __init__(self):
... # as before
self.investment_fraction = 0.75 # beta
self.interest_rate = 5 # 5%
... # as before
def live_with_investing(x, t, you):
balance = you.earn(t) - you.spend(t) - you.pay_taxes(t)
if t < self.retirement_age:
x1 = balance * (1 - you.investment_fraction)
x2 = np.log(1 + 0.01 * you.interest_rate) * x[1] \
+ balance * you.investment_fraction
else:
x1 = balance
x2 = 0
return [x1, x2]**
这个实现与我们刚刚讨论的方程组有一点不同。在这里,为了清楚起见,我们假设你退休的决定相当于从 x₂ 取出你所有的钱,并把它提供给 x₁ 。换句话说,在我们的模拟中,我们想要检查你可以用所有积累和产生的资本支持自己多久。
因此,simulate
函数也得到更新:
**def simulate(you):
... # t0, t1, t2 - as before
# non-investor
x1_0 = np.zeros((t0.shape[0], 1))
x1_1 = odeint(live_without_investing, 0, t1, args=(you,))
x1_2 = odeint(live_without_investing, x1_1[-1], t2, args=(you,))
# investor
x2_0 = np.zeros((t0.shape[0], 2))
x2_1 = odeint(live_with_investing, [0, 0], t1, args=(you,))
x2_2 = odeint(live_with_investing, [x2_1[-1].sum(), 0], t2, args=(you,))
df0 = pd.DataFrame({'time': t0, 'wallet (non-investor)': x1_0[:, 0], 'wallet (investor)': x2_0[:, 0], 'investment bucket (investor)': x2_0[:, 1]})
df1 = pd.DataFrame({'time': t1, 'wallet (non-investor)': x1_1[:, 0], 'wallet (investor)': x2_1[:, 0], 'investment bucket (investor)': x2_1[:, 1]})
df2 = pd.DataFrame({'time': t2, 'wallet (non-investor)': x1_2[:, 0], 'wallet (investor)': x2_2[:, 0], 'investment bucket (investor)': x2_2[:, 1]})
return pd.concat([df0, df1, df2])**
观察第 12 行。这就是我们为第三个积分 x₁(t₂) + x₂(t₂) → x₁(t₂) 设置新的初始条件的地方。
图 3。“投资分数= 0.8”和“利率= 3.3%”的示例。观察一下,即使利率如此之低,你也能为自己争取近十年的时间,或者相反,你的提前退休变得更容易实现。
通货膨胀——你的敌人
我们刚刚看到了指数增长的威力。不幸的是,不管你是否选择投资,有一个因素几乎肯定存在,它也具有指数性质,但对你不利。这是通货膨胀**。**
简单来说,通货膨胀不是物价的整体上涨,而是货币随着时间的推移而贬值。比方说,50%的通货膨胀率将导致同样的钞票只有其早期购买力的 2/3。因此,为了在我们的模型中考虑通货膨胀,而不是保持货币的名义价值,而是以某种方式想象价格上涨,我们宁愿将 is 建模为负利率——一种吞噬你的钱的复利。
利用我们以前的知识,并把通货膨胀率表示为ξ,我们只需要稍微修改一下方程组:
现在,注意乘以 x₂ 的项。利用对数的性质,我们可以只用一个常数来表示这两个值,
现在很容易发现,只有当我们战胜通货膨胀时,我们才能从投资中获利。自然,对于“钱包”,我们的数字永远是 λ < 0 ,因为没有 R 来“拉起来”。这又是一个原因,为什么“努力工作,努力储蓄”是一个完全没有希望的想法。
“代码方式”:
**def live_without_investing(x, t, you):
balance = you.earn(t) - you.spend(t) - you.pay_taxes(t)
return balance - np.log(1 + 0.01*you.inflation_proc) * x
def live_with_investing(x, t, you):
balance = you.earn(t) - you.spend(t) - you.pay_taxes(t)
if t < you.retirement_age:
x1 = balance * (1 - you.investment_fraction)
x2 = np.log(1 + 0.01*you.interest_rate_proc) * x[1] \
+ you.investment_fraction * balance
x1 -= np.log(1 + 0.01*you.inflation_proc) * x[0]
x2 -= x2 - np.log(1 + 0.01*you.inflation_proc) * x[1]
else:
x0 = balance
x1 -= np.log(1 + 0.01*you.inflation_proc) * x[0]
x2 = 0
return [x0, x1]**
图 4。前面的例子中,“通货膨胀率”设置为 3.0%,而“利率”设置为 3.3%。
结论
在本文中,我们展示了如何使用常微分方程对财务状况建模,以及如何使用 python 将它们转化为模拟器。
这里讨论的案例没有考虑很多因素。一些因素,如你所在国家的税法,突然的遗产继承,或者由于意外的金融危机导致的通货膨胀,无疑增加了复杂性。此外,我们在这里没有提到贷款或债务,尽管使用刚才介绍的方法,我们确信您能够将它们包含在您的模型中——而这正是本文的目标。
最后,关键在于,特别是对于那些对编码不感兴趣的人,记住那些增长与其价值成正比的函数正是你想要使用并为你所用的机器。
也可以在 Google Colab: 这里找到可以运行的笔记本。您可以随意克隆它、修改它,并随意使用它。让我知道你的想法。
还会有更多…
我计划把文章带到下一个层次,并提供简短的视频教程。
如果您想了解关于视频和未来文章的更新,订阅我的 简讯 。你也可以通过填写表格让我知道你的期望。回头见!
原载于https://zerowithdot.com。**
金融信号处理—第一部分
为统计分析和机器学习处理财务数据
算法交易很难。你不能只是把一打技术分析信号塞进一个神经网络,就指望下个月成为百万富翁。这是因为处理财务数据都是关于细节的。抛开初学者可能犯的所有潜在偏见和错误,大多数金融机器学习和算法交易项目都失败了,因为他们忽略了金融环境中的微妙假设。
为此,今天我将回顾并讨论金融信号处理的基本原理。我将研究金融数据的各种属性,何时以及如何以特定的方式处理它们,以及如何通过机器学习技术来分析它们。
1.对平稳性的需求
大多数机器学习技术都假设数据是平稳的。然而,在金融中很少发现平稳性,这会导致几个问题。
在深入研究金融信号之前,提到平稳性的概念很重要,因为它是大多数现代机器学习技术背后的基本假设。
1.1.什么是平稳性
抛开严格的数学定义,平稳性意味着基础信号的统计数据(例如均值和方差)在一段时间内是恒定的。
例如,考虑涉及猫和狗的分类的最大似然问题,其中动物的潜在生物学不会每天都发生巨大的变化。生物特征的平稳性允许 ML 模型挑选将随时间保持真实的模式,这允许模型在样本外很好地概括。
1.1.金融中的平稳性和潜在问题
然而,在金融领域,稳定性是一个大问题。例如,考虑下图中苹果的价格信号。不需要严格的统计测试就能看出平均价格不会随着时间的推移而保持不变。
作者图片
考虑一个具有上述数据的训练-测试拆分框架,其中 2019 年之前的价格信号用于训练,其余用于测试。如果有人天真地将价格范围从[100,400]扩大到[0,1],就会导致 前瞻偏差 (测试集信息泄露给训练集)。这将导致不切实际的更好的性能,因为 ML 模型通过缩放隐含地知道将来的最高价格。
直觉上,如果你在 2019 年实施这种 ML 模型,你不可能知道 AAPL 的价格在 2020 年最终会达到 400 英镑左右(如果你知道,你首先就不需要 ML)。
如果我们使用训练集来调整价格范围会怎么样?将价格范围从[100,250]缩放到[0,1]将不会导致前瞻偏差,但是测试集中所有大于 250 的价格都将被缩放到大于 1。这对于需要特征在某个比例范围内的 ML 模型来说尤其成问题,例如神经网络。
更好的解决方案是通过对数差分来处理上述信号,如下所述。
2.对数差分和对数回归
对价格数据进行差分可以生成适用于机器学习技术的平稳信号,这通常比原始价格信号更好。
2.1.日志返回的属性
对数差分计算在时间 t-1 和 t 的对数值之间的差值,这通常也称为对数回归,如下所示。
通过对数收益处理的价格信号有许多优点:(1)它使原始信号变得平稳,如下图所示。通过简单的观察,我们可以看到新信号有一个大约为 0 的恒定平均值,以及一个更恒定的方差。(2)对数收益比价格数据更趋于正态分布,这对于依赖于正态假设的经典统计模型来说是很好的。(3)对数回归是时间累加的,这允许我们通过简单的加法计算回测(参见文章,此处有更详细的解释)。
作者图片
2.2。何时不使用日志返回
log-return 的主要缺点是它删除了存储部分,这破坏了定价信息。在大多数应用程序中,这通常不是问题。例如,投资组合优化、动量策略、均值回归策略等方面的大量量化金融文献。依靠多少资产价格一起变化。因此,对数收益的比较比价格的比较更有意义。
然而,对于大宗商品期货等其他金融工具,确切的价格可能会对依赖这些大宗商品的行业产生现实影响。因此,在这种情况下,定价信息可能比对数收益更有意义。
最后,在对数收益的计算中可能有一些额外的微妙之处,可以通过基于体积的采样和分数差分进行调整。这些技术将在以后的文章中讨论。
3.处理日志-返回
R 对数收益的滚动统计可以通过机器学习方法进行处理,从而提供市场洞察力。
3.1.滚动统计
如前所述,对数收益往往遵循更好的分布。对于短期窗口,通常需要分析与该分布相关的不同统计数据,如均值、标准差、偏斜度和峰度,这些数据也趋于稳定。
在 Python 中,这些可以通过 pandas 中的滚动函数轻松计算:
w = 22 # number of trading days in a months1 = rs.rolling(w).mean() # moving average
s2 = rs.rolling(w).std() # moving standard deviation
s3 = rs.rolling(w).skew() # moving skewness
s4 = rs.rolling(w).kurt() # moving kurtosissignals = pd.concat([s1, s2, s3, s4], axis=1)
signals.columns = ['mean', 'std dev', 'skew', 'kurtosis']
signals.plot(subplots=True, figsize=(10,7), legend=True);
作者图片
特别是,标准差的滚动计算在分析市场波动时非常有用。
3.1.波动性和市场机制
波动性在金融机器学习中有着特殊的作用。直观地说,波动性衡量市场中存在多少不确定性/运动/混乱。此外,它还可用于衡量市场中存在的“风险”量(尽管存在其他/更好的风险定义,如“敞口”)。
波动性的概念也与市场机制的概念紧密相连,市场机制可以用来识别不同的市场条件。例如,我们可以对 SP500 在不同时间的波动水平运行聚类算法:
from sklearn.mixture import GaussianMixturew = 22
vol = rs.rolling(w).std()
vol = vol.dropna()labels = GaussianMixture(2).fit_predict(vol.values.reshape(-1,1))prices = prices.reindex(vol.index)
prices[labels==0].plot(style='bo', alpha=0.2)
prices[labels==1].plot(style='ro', alpha=0.2)
plt.title('Volatility Regimes SPY')
作者图片
通过在观察到的波动水平上拟合高斯混合,ML 模型自动推断出看涨和看跌的市场机制。这是直观的,因为市场抛售往往是由恐慌性抛售决定驱动的,这可能导致大幅下跌,加剧市场混乱,导致更高的波动性。相比之下,牛市的特点是价值稳定增长,导致波动性降低。
识别市场机制对于金融机器学习尤其重要,因为在牛市中训练的模型不太可能在熊市中表现良好,反之亦然。
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
我希望你喜欢这篇文章!如果你想看更多这样的内容,请关注我。
此外,查看我的网站的完整代码和其他资源。
寻找并使用“分子”数据集
分子数据集以及在哪里可以找到它们!
机器学习已经在各个领域普及。它有助于提高所有行业的工业流程效率,无论是物流还是国防。尽管制药公司采用机器学习的速度很慢,但他们肯定会迎头赶上。在这篇文章中,我谈到了一些标准数据集,数据科学家可以使用这些数据集开始工作,并为这个令人兴奋的制药和人工智能联盟做出贡献。
分子数据在哪里?来源
如何表示分子?
现在首先想到的问题,是如何把复杂的分子结构表示成机器可以理解的表示法?
环丙沙星抗生素[ 来源
在左边,你可以看到一种叫做Ciprofloxacin
的流行药物的分子结构,它是一种抗生素。在其原始格式中,它不是机器可以理解的。那么解决办法是什么呢?简而言之,这个解决方案被称为简化分子输入线输入系统或 SMILES。
微笑?这是什么?
SMILES 是将化合物的分子结构指定为简单字符串表示的标准方法。上图中结构的字符串表示为OC(= O)C1 = CN(c2cc 2)c3cc(n4cc NCC 4)c(F)cc3c 1 = O。人们可以很容易地将这些字符串表示转换成 2D 图——这使得它成为用于 ML 模型和可视化目的的流行描述。也有其他方法来表示结构,但是 SMILES 更好,因为它更易于阅读,并且可以转换成其他表示类型,比如图形。
由于我是一名数据科学家,并且没有扎实的化学背景,我不会深入研究 SMILES 是如何工作的。但是你可以通过阅读 OPENSMILES 文档更深入的了解。
简而言之,这是一种真正的表示结构的强大方式,并且能够表示不同种类的原子、键、环,甚至复杂的概念,如分支和芳香性。
让我们深入了解开源数据集吧?我们走吧。👌👌
我知道你被这些信息吓到了,但是等等。[ 来源
数据集时间?
我将提到我使用过的三个主要的 SMILES 数据集,它们在计算化学社区中也非常流行。
一)GDB
GDB 数据集来自伯尔尼大学的 Raymond 研究小组。该数据集有两个变体:GDB 11 和 GDB 13。这两个数据集都包含本质上很小的化合物(就字符串表示的长度而言)。对于特征来说,它只是包含了弦,并不具有分子的任何其他性质。
GDB 11 号:包含大约 65k 个分子,大小为 122 MB。
GDB 13 :包含大约 9.77 亿个分子,大小为 2.6 GB。这也是目前发表的最大的小分子数据集。
**b)**锌
锌是商业上可获得的分子的数据集。它有超过 7.5 亿个分子,是研究和生物技术公司使用的标准集之一。除了微笑,它还保存了每个分子的其他信息,如其物理化学性质和商业销售相关信息。
托管数据集的网站还允许用户查询有趣的问题,如“有多少化合物已经用于临床试验?”并以其对查询的快速响应而闻名。它在机器学习社区中也非常受欢迎,在《药物发现》上发表了多篇研究论文,将锌作为基线数据集。
c)ChEMBL
ChEMBL 数据集由欧洲生物信息学研究所开发,不仅为用户提供了关于微笑及其化学性质的信息,还提供了关于其活性和基因组的信息。作为数据集的一部分,它有超过 190 万种化合物。它拥有一系列具有类似药物特性的分子。
由于 ChEMBL 提供的功能数量非常广泛,它是这个领域中最全面的公共数据集之一。可以使用他们的网络界面或 ElasticSearch 来查询数据集。通过使用 ElasticSearch 进行查询,它为用户提供了更多的灵活性,使他们可以在数据集中选择所需的要素。
该实验了!
由于大多数机器学习社区使用 Python,我将谈论一个工具,它将帮助您使用 Python 处理上述数据集。
库是RDKit,是一个开源的知名化学信息学库。用户可以使用conda
安装rdkit
包:
conda install -c rdkit
一旦安装了rdkit
包,给定一个 SMILES 字符串,就可以将其转换为rdkit.Chem.rdchem.Mol
对象,或者换句话说,可以将其转换为分子对象,用户可以对其调用方法以获得额外的功能:
In [**1**]: **from** **rdkit** **import** Chem
In [**2**]: **from** **rdkit.Chem.Descriptors** **import** MolWt## Here Cc1ccccc1 is a SMILES string of a compound
In [**3**]: m = Chem.MolFromSmiles('Cc1ccccc1')In [**4**]: m
Out[**4**]: <rdkit.Chem.rdchem.Mol at 0x10cedf5d0>## Let's get the weight of these molecule (or string)
In [**6**]: MolWt(m)
Out[**6**]: 92.14099999999999
**这只是我们发现的一个特征,但使用 RDKit,我们可以发现其他特征,如字符串的一键编码向量(摩根指纹)化学环总数、价电子数、等。
现在,走出去,开始玩这些数据集。有数不清的机会——你可以潜在地开发治疗疾病的新药,或者预测一种化合物在某种情况下的活性。
我希望你觉得这篇文章有趣并且有用。如果你有,请分享。
此外,如果你觉得有重要的数据集或库,请在评论中随意提及!
💊💊💊💊💊💊💊💊💊谢谢大家!
使用 Python 中的 OSM、Plotly 和 NetworkX 找到并绘制最佳路径
使用 OpenStreetMap、 OSMnx & NetworkX 寻找最佳路径的指南,并使用 Python 中的 Plotly 绘制带有弯曲和曲线的详细路径。
使用 Google Maps API 可以使用许多库来绘制路径,但这会导致灵活性降低。同样,如果你用一组线条来画一条路径,在缺乏更好的词语的情况下,它看起来并不好。让我给你举个例子:
使用 Plotly 生成
此外,在许多情况下,您可能需要一些灵活性,不仅可以更改两点之间的所需路径(例如,您需要满足您的标准的路径,而不是 google maps 给出的最短或最快路径),还可以更改您想要的绘图方式。
在这篇博客中,我试图解决这样一个问题,我们不仅可以找到最佳路径,还可以使用 Plotly 绘制它们。我们先从导入一些库开始。
import osmnx as ox
import networkx as nx
import plotly.graph_objects as go
import numpy as np
OSMnx 库有助于从 OpenStreetMap 检索、分析和可视化街道网络。你可以在这里阅读更多关于 OSMnx 的内容。为了演示,我将下载美国佐治亚州的州界,并使用 OSMnx 库绘制它。
state = ox.gdf_from_place('Georgia, US') ox.plot_shape(ox.project_gdf(state))
使用 OSMnx 库生成的佐治亚州地图
现在让我们下载一张地图。这一次,我们将通过提供一个参数network_type = 'drive'
来下载佐治亚理工学院周围地区的更详细地图。OSMnx 以图形对象的形式下载地图,可以很容易地被 NetworkX 库使用。
# Defining the map boundaries
north, east, south, west = 33.798, -84.378, 33.763, -84.422
# Downloading the map as a graph object
G = ox.graph_from_bbox(north, south, east, west, network_type = 'drive')
# Plotting the map graph
ox.plot_graph(G)
显示使用 OSMnx 库生成的边(道路)和节点的道路网络图
在上图中,我们可以看到所有的节点(蓝色)和边(灰色)以精确的形状表示道路。让我们深入研究一下我们下载的图形对象,看看边和节点是什么样子的:
# Displaying the 3rd node
list(G.nodes(data=True))[2]
(69128194,
{‘y’: 33.7692046,
‘x’: -84.390567,
‘osmid’: 69128194,
‘ref’: '249C ',
’ highway ‘:’ automobile _ junction ’ })
上面的输出显示了节点 id 69128194
的信息及其 x 和 y 坐标、OSM id 和节点类型(交汇点)。同样,我们可以看到边缘的细节:
# Displaying the 1st edge
list(G.edges(data=True))[1]
(69259268,
69508853,
{‘osmid’: 9270483,
‘名称’:‘林赛街西北’,
‘公路’:‘住宅’,
‘单向’:False,
‘长度’:145.352,
‘几何’😃)
这显示了连接节点69259264
到69290452
的边的细节,以及它的 OSM id、名称、类型、单向/双向、长度和一个有趣的 geometry.linestring 类型的元素。我们可以看到这个几何图形是什么样子。
# Displaying the shape of edge using the geometry list(G.edges(data=True))[1][2]['geometry']
边缘的几何形状
这说明边缘不是直线而是曲线路径。我们将在以后绘制这种类型的曲线边时使用这些信息。
现在我们将找到最佳路径。现在,让我们把目标定为找到最小长度的路径。这可以改变以满足任何标准,并将在一个单独的博客中讨论。在决定了起点和终点之后,首先,我们需要得到离这些位置最近的节点。这可以使用 OSMnx 的函数get_nearest_node
来完成。
# define origin and desination locations
origin_point = (33.787201, -84.405076)
destination_point = (33.764135, -84.394980)# get the nearest nodes to the locations
origin_node = ox.get_nearest_node(G, origin_point)
destination_node = ox.get_nearest_node(G, destination_point)# printing the closest node id to origin and destination points origin_node, destination_node
(69425048, 2919090915)
现在,我们可以使用NetworkX
库中的shortest_path
函数,通过 Dijkstra 算法得到总长度最小的最优路径。注意,我们已经提供了weight='length'
。这个函数返回路径中有序节点的列表。
# Finding the optimal path
route = nx.shortest_path(G, origin_node, destination_node, weight = 'length') route
[69425048,
69425021,
69466983,
69466977,
。
。
让我们在地图上标出这些节点。为此,我们将使用 Plotly 库。我们将绘制所有这些节点,并用线将它们连接起来以表示一条路径。让我们看看它看起来怎么样。但是首先,让我们得到这些节点的坐标
# getting coordinates of the nodes# we will store the longitudes and latitudes in following list
long = []
lat = []
for i in route:
point = G.nodes[i]
long.append(point['x'])
lat.append(point['y'])
我们将在地图上多次绘制路径,因此让我们为此定义一个函数:
def plot_path(lat, long, origin_point, destination_point):
"""
Given a list of latitudes and longitudes, origin
and destination point, plots a path on a map
Parameters
----------
lat, long: list of latitudes and longitudes
origin_point, destination_point: co-ordinates of origin
and destination Returns
-------
Nothing. Only shows the map.
""" # adding the lines joining the nodes
fig = go.Figure(go.Scattermapbox(
name = "Path",
mode = "lines",
lon = long,
lat = lat,
marker = {'size': 10},
line = dict(width = 4.5, color = 'blue'))) # adding source marker
fig.add_trace(go.Scattermapbox(
name = "Source",
mode = "markers",
lon = [origin_point[1]],
lat = [origin_point[0]],
marker = {'size': 12, 'color':"red"}))
# adding destination marker
fig.add_trace(go.Scattermapbox(
name = "Destination",
mode = "markers",
lon = [destination_point[1]],
lat = [destination_point[0]],
marker = {'size': 12, 'color':'green'}))
# getting center for plots:
lat_center = np.mean(lat)
long_center = np.mean(long) # defining the layout using mapbox_style
fig.update_layout(mapbox_style="stamen-terrain",
mapbox_center_lat = 30, mapbox_center_lon=-80)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0},
mapbox = {
'center': {'lat': lat_center,
'lon': long_center},
'zoom': 13})
fig.show()
让我们调用函数并在地图上绘制路径:
plot_path(lat, long, origin_point, destination_point)
使用连接节点的直线显示最短路径的地图。橙色方框显示绘制的线与实际道路的偏差。使用 Plotly 库生成。
这看起来不错。我们绘制了一条从源节点到目的节点的路径,这些节点非常接近我们作为源节点和目的节点提供的实际坐标(分别用红色和绿色标记表示)。但是少了点什么。是的,道路上的曲线被连接路径中两个节点的直线所取代。这可以在橙色方框中观察到。如果你记得上面边的几何元素,我们将使用它来解决这个问题。
为了说明,我们将看到这部分路径的边缘形状。该路径位于从终点输入输出路由变量开始的第 6 个和第 7 个节点之间。让我们得到连接这两个节点的边,我们将看到它的形状。
# Getting the start and end node of this part
start_node=route[-7]
end_node=route[-6]# Getting the edge connecting these nodes and storing it as a list in z to maintain the data structure of G.edges
z = []
for i in list(G.edges(data=True)):
if (i[0]==start_node) & (i[1]==end_node):
z.append(i)
z[0][2]['geometry']
上图中橙色框中标记的一条道路的几何图形
这看起来和第二个橙色盒子里的街道一模一样。所以现在我们有一种方法来绘制这些曲线形状。我们只需要得到这些形状,并用我们的原始路线数据替换它们。为此,我们将定义一个函数来实现这一点。它在所有边上循环,如果该边有曲线形状,它就存储该曲线。
def node_list_to_path(G, node_list):
"""
Given a list of nodes, return a list of lines that together
follow the path
defined by the list of nodes.
Parameters
----------
G : networkx multidigraph
route : list
the route as a list of nodes
Returns
-------
lines : list of lines given as pairs ( (x_start, y_start),
(x_stop, y_stop) )
"""
edge_nodes = list(zip(node_list[:-1], node_list[1:]))
lines = []
for u, v in edge_nodes:
# if there are parallel edges, select the shortest in length
data = min(G.get_edge_data(u, v).values(),
key=lambda x: x['length']) # if it has a geometry attribute
if 'geometry' in data:
# add them to the list of lines to plot
xs, ys = data['geometry'].xy
lines.append(list(zip(xs, ys)))
else:
# if it doesn't have a geometry attribute,
# then the edge is a straight line from node to node
x1 = G.nodes[u]['x']
y1 = G.nodes[u]['y']
x2 = G.nodes[v]['x']
y2 = G.nodes[v]['y']
line = [(x1, y1), (x2, y2)]
lines.append(line)return lines# getting the list of coordinates from the path
# (which is a list of nodes)lines = node_list_to_path(G, route)long2 = []
lat2 = []for i in range(len(lines)):
z = list(lines[i])
l1 = list(list(zip(*z))[0])
l2 = list(list(zip(*z))[1])
for j in range(len(l1)):
long2.append(l1[j])
lat2.append(l2[j])
如果我们比较 lat 和 lat2 的长度,我们会注意到 lat2 的坐标是 lat 的 6 倍以上。
print("Length of lat: ", len(lat))
print("Length of lat2: ", len(lat2))
lat: 23 长度
lat 2 长度:141
现在要做的最后一件事是绘制路径,看看它看起来如何。
plot_path(lat2, long2, origin_point, destination_point)
使用 Plotly 库生成的最终路径
这个看起来好多了。在这篇博客中,我们使用了像OSMnx
和Plotly
这样的库来创建我们的方向图。我们使用NetworkX
来获得基于我们目标的最优路径。这里我们使用了最常见的目标——长度,但这可以很容易地替换。
在我的网站上找到原帖【apurv.page/plotthepath.html
用 Python 模块 Newspaper 和 NLTK 查找文章中的常用词
使用 newspaper3k 和 NLTK 从报纸中提取信息和发现见解的分步指南
你想从一篇有趣的文章中提取必要的信息,但是发现这篇文章太长了,无法在有限的时间内阅读。在你一头扎进整篇文章,最终对无关的内容感到失望之前,你应该事先看看摘要和关键词。
newpaper3k
和nltk
是两个有效的工具,可以用来搜集和总结新闻文章。让我们来分析一下我今天在 Medium 上看到的一篇有趣的文章: 我花了两年时间获得了 1000 名粉丝——这是我在整个旅程中使用这两种工具学到的人生经验 。
使用报纸 3k
安装和创建项目的实例
pip install newspaper3kfrom newspaper import Article url = '[https://mystudentvoices.com/it-took-me-2-years-to-get-1000-followers-life-lessons-ive-learned-throughout-the-journey-9bc44f2959f0](https://mystudentvoices.com/it-took-me-2-years-to-get-1000-followers-life-lessons-ive-learned-throughout-the-journey-9bc44f2959f0)'article = Article(url)article.download()
从文章中提取有趣的信息
查找发布日期
article.publish_date
提取顶部的图像并快速浏览图像
image_url = article.top_image**from** **IPython.display** **import** Image
**from** **IPython.core.display** **import** HTML
Image(url=image_url)
输出:
摘录作者姓名
article.authors
输出:
['William Cho']
提取文章关键词:
article.keywords
输出:
['soon',
'ive',
'work',
'journey',
'1000',
'took',
'followers',
'started',
'truth',
'life',
'writing',
'wasnt',
'lessons',
'doing',
'read',
'maybe',
'learned',
'youre']
总结文章
article.summary
输出:
'But I’ve only been writing on Medium for a total of maybe 4.5 months.\nI started writing passionately, and you could tell from my writing that I thought I was enlightened and speaking from authority.\nI’ve noticed that it comes in moments where I put in effort to improve myself — working out, writing, and reading.\nYou’re just doing it to put yourself on a higher ground than your friends, to judge them from a higher platform and deem everything you’re doing more virtuous than what they’re doing.\nI would sidestep and avoid the truth — the truth that would hurt but ultimately set me free.'
通过总结,我们可以快速掌握文章的要点:
- 为了成为一名更好的作家,他通过写作、阅读和锻炼不断提高自己的写作技巧。
- 他的动力曾经来自朋友等外部来源。
- 在他的旅程中有挣扎。但是通过评估他的方法,他让自己自由了。
让我们看看是否可以使用 NLTK 从文章中提取更多的见解
用于文本处理的 NLTK
从从报纸上摘录文字开始
text = article.text
通过查看最常用词的情节,我们对这篇文章的内容有了更好的了解。
让我们利用另一个叫做 WordClouds 的工具来为我们的文章创建一个更有趣的可视化
从这个单词列表中,我可以猜出文章的大意:成为一个更好的作家需要努力。你必须坚持每天写作和阅读来提高你的技能。可能会有怀疑和恐惧,但如果你相信旅程并着眼于更大的愿景,事情最终会有所改善。现在,我可以开始阅读这篇文章了,因为我知道它会给我一些实用的课程来提高我的写作技巧。
结论
newspaper3k
和nltk
是从在线文章中提取重要信息的绝佳组合。你也可以利用这个工具来掌握文章的大意,以决定文章是否值得一读,或者同时分析几篇文章。
在这个 Github repo 中,您可以随意使用本文的代码。
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以通过 LinkedIn 和 Twitter 与我联系。
如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:
您计划在未来 3 年投资几只股票,每只股票的每一美元都有不同的预期回报…
towardsdatascience.com](/choose-stocks-to-invest-with-python-584892e3ad22) [## 用美丽的声音抓取维基百科
关于如何使用 Beautiful Soup 的分步教程,这是一个用于 web 抓取的简单易用的 Python 库
towardsdatascience.com](/step-by-step-tutorial-web-scraping-wikipedia-with-beautifulsoup-48d7f2dfa52d) [## 如何从头开始构建矩阵模块
如果您一直在为矩阵运算导入 Numpy,但不知道该模块是如何构建的,本文将展示…
towardsdatascience.com](/how-to-build-a-matrix-module-from-scratch-a4f35ec28b56) [## 为您的数据科学项目提供 Numpy 技巧
创建数组、矩阵、执行矩阵运算、解决线性代数问题和常见数据科学的技巧…
medium.com](https://medium.com/@khuyentran1476/comprehensive-numpy-tutorials-for-beginners-8b88696bd3a2)
参考
[1]https://care . press reader . com/HC/en-us/articles/203210155-Advanced-Keyword-Search
[2] William Cho,我花了 2 年时间获得了 1000 名粉丝——我在整个旅程中学到的人生经验(2018),我的学生之声
用 Python 找高度相关的股票!
了解如何使用 Python 来识别股票走势的相似性
帕特里克·韦森伯格在 Unsplash 上拍摄的照片
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
无论你是在精心设计投资组合,想要融入多样化,还是试图为配对交易策略寻找股票,计算两只股票走势之间相关性的能力都是必须的。
拥有一个不密切相关的股票投资组合,可以让你投资于不同的表现良好的资产,这些资产可能不会一起下跌太多。举例来说,在疫情期间,仅持有航空股的投资组合今年平均下跌约 38%。然而,通过将投资组合多元化,组合科技、零售或几乎任何其他行业的股票,损失会小得多(如果有的话)。
除非你使用的是配对交易策略,否则最好的办法是降低投资组合中的相关性,以最大限度地分散风险。这就是我们今天要做的——计算和排序一系列股票之间的相关性。这个过程是完全直观的,到本文结束时,您也应该能够在几分钟内重新创建这个程序,并且只需要几行代码!
本文中项目的全部代码都在这个 GitHub 要点中。
开始项目!
介绍
首先,我们必须导入整个程序中需要的所有依赖项。我们将使用的主要库是 Yfinance、Datetime 和 Yahoo-fin。Yfinance 将允许我们覆盖 pandas-datareader 中的不赞成意见,Datetime 将允许我们设置价格的开始/结束日期,Yahoo-fin 将允许我们快速访问不同指数中的报价器列表。
如果您没有安装这些模块,您可以在您的终端中使用 PyPi 和 pip install 命令轻松下载它们。现在我们已经设置了依赖项,我们终于可以开始构建我们的应用程序了!
通过输入您想要开始的年数,我们可以使用 datetime 模块来创建历史数据的开始和结束日期。我们还可以设置道琼斯工业平均指数(DJIA)的报价机列表,但这可以根据您的喜好进行更改。
股票数据
使用 pandas-datareader,我们可以从 Yahoo Finance 中获取在前面代码块中设置的日期和报价机的历史数据。因为我们关注的是股票变动之间的相关性,所以我们可以专注于调整后的收盘价列,然后用每日百分比变化的以 10 为底的对数创建一个新的 Pandas 数据框架。用熊猫的方法。corr(),我们可以创建新数据帧的相关矩阵。
然而,我们还没有完成。相关矩阵包括冗余对,例如 AAPL 到 AAPL 或出现两次的对(AAPL 到 MSFT 和 MSFT 到 AAPL)。我们可以去掉这些,对数据帧进行排序,以获得与下面要点中的函数的最高绝对相关性。
清理数据帧的函数
我们可以使用函数 get_redundant_pairs(df)来去除两只相同股票之间的相关性。通过将变量“pairs_to_drop”设置为一个集合,并对每一列和每一行运行两个 for 循环,我们可以找到双对并返回它。
然后,我们可以创建相关性数据框架,目标绝对值数字,并拆分它,使其更容易阅读。最后,我们可以调用 get_redundant_pairs 函数,将它们从结果数据帧中删除。现在,程序应该返回输入的报价机列表中的最高相关性。在这种情况下,对于 DJIA 去年的数据,我有以下输出。
DJIA 的最高绝对相关性— 1 年
正如你所看到的,高盛、摩根大通和美国运通都如预期的那样有很强的相关性,因为它们都在同一个行业。为了测试输出的准确性,让我们快速地把高盛和摩根大通放在一起。使用 TradingView 的绘图工具,我们可以看到,尽管 JPM 的波动性更大,但这两只股票在过去的一年里几乎是一样的!
高盛(蓝色)对摩根大通(红色)1 年
虽然在这篇文章中,我着重于寻找具有最高绝对相关性的股票,但可能性确实是无穷无尽的。我希望这个算法将来对你有用。非常感谢您的阅读!
免责声明:本文材料纯属教育性质,不应作为专业投资建议。自行决定投资。
如果你喜欢这篇文章,可以看看下面我写的其他一些 Python for Finance 文章!
了解如何在不到 3 分钟的时间内解析顶级分析师的数千条建议!
towardsdatascience.com](/parse-thousands-of-stock-recommendations-in-minutes-with-python-6e3e562f156d) [## 用 Python 制作股票筛选程序!
学习如何用 Python 制作一个基于 Mark Minervini 的趋势模板的强大的股票筛选工具。
towardsdatascience.com](/making-a-stock-screener-with-python-4f591b198261) [## 在 3 分钟内创建一个财务 Web 应用程序!
了解如何使用 Python 中的 Streamlit 创建技术分析应用程序!
towardsdatascience.com](/creating-a-finance-web-app-in-3-minutes-8273d56a39f8)
基于已知点寻找线性变换
线性代数和计算机视觉的代码片段
这个故事展示了如何仅基于几个点的变换来识别线性变换。为了这个故事中的数学,我使用了亚历山大·尼塔的这个作品,以及来自维基百科(线性地图)的描述。代码见这个谷歌 Colab。
例子:让我们假设在三维空间中有一个移动的物体。我们有对象的两个时间戳,并且我们想要识别可以将对象从第一状态移动到第二状态的转换。如果我们知道每个状态中 3 个点的位置(例如 Harris 角点检测,我们可以定义变换的矩阵。
找出埃菲尔铁塔图像之间的变换——基于荣克森公园在 Unsplash 上的照片和佩德罗·甘德拉在 Unsplash 上的照片
线性转换
线性变换(线性映射、线性映射或线性函数)是两个向量空间之间的映射 V →W,保留了加法和标量乘法。
—维基百科(线性地图)
形式上,对于同一域 K 上的向量空间 V , W ,函数f:V→W是一个线性映射如果任意两个向量 u,v ∈ V 和任意标量 c ∈ K 满足以下两个条件:
(1):f(u+v)=f(u)+f(v)
(2):f(cu)= cf(u)
变换矩阵
如果 V 和 W 是有限维向量空间,并且为每个向量空间定义了基,则线性映射 f 可以由变换矩阵来表示。如果 M 是一个 m x n 那么
(3):f(x)=MX 描述一个线性映射 R ⁿ→ R ⁿⁿ.
如果我们知道一个基β={ v ₁, v ₂,…, v ₙ}对于 V ,那么每一个向量 v 都可以写成这个基的线性表示:v=c₁v₁+…+cₙvₙ.
如果f:V→W是线性映射,
因此, f 由 f (v₁),…, f (vₙ).)决定
设γ ={ w ₁,…, w ₘ}为 w 的一个基,那么 f ( v ⱼ)可以写成
线性映射 f 可以由 f (v₁),…, f (vₙ)确定,从而使用 aᵢⱼ系数。矩阵 M 是
如果我们在 a 基中使用【v]ₐ符号】来表示 v 向量,则在有序基中线性变换的矩阵表示为:
有序基中函数的变换矩阵
以下重要等式的证明,参见亚历山大·尼塔的著作。它指出,用 M 矩阵乘以用β基表示的 v 向量变换成用γ基表示的 f(v)。
使用相应的变换矩阵将一种基中的向量变换到另一种基中
因此,如果我们有一个向量 V,一个在向量空间(V,W)和 m 点中的基与{ v , f ( v )}对,我们可以确定线性变换。对于这个,我们要知道,如何把 V 中的点变换成第一基,然后,计算矩阵 M,最后从第二基变换回标准基(如果我们想的话)。
Python 实现
为了得到基 a 的 v]ₐ,我们可以使用[numpy.linalg.solve()](https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.solve.html)
函数:
np.linalg.solve(np.transpose(a), v)
为了得到有序基中的矩阵表示,我们简单地将上面的等式转化为numpy
项:函数lin_map_matrix
使用 f (v₁),…, f (vₙ)的矩阵 FV 和 w₁,…,wₘ.的矩阵 w 产生 m
函数linmap_predict
计算 V 基的 V 向量表示,然后使用 M 矩阵乘法进行转换,并使用 w 得到标准基表示
Python 中的变换矩阵
摘要
如果我们有一个 n 和一个 m 维向量空间,并且我们知道两个空间中的一个基(分别是线性独立的 n 和 m 个向量)和两个空间中的 m 个点,那么如果它存在,我们就可以确定空间之间的线性映射。
在特殊情况下,如果我们在 3D 空间中有 3 个点(不在一条线上),并且我们知道它们在线性变换后的表示,我们可以确定线性变换。
找到类似的产品推荐给用户
在 R 中使用 recommenderlab 获得类似的产品推荐
找到相似的产品来推荐是一件棘手的事情,尤其是当我们有大量产品的时候。我们希望在我们的营销和产品活动中推荐类似的产品,例如在促销电子邮件营销中。
这是我用 autodraw 制作的超级艺术作品,展示了一封营销电子邮件,其中包含对主要产品的类似产品的建议。
类似品牌的促销邮件插图,作者 Muffaddal
在本指南中,我们将使用推荐系统中使用的技术来获取彼此相似的产品列表。虽然推荐系统在用户层面上推荐产品,这意味着每个用户可能有不同的建议,但我们的系统将在产品层面上,所以我们得到一个类似项目的列表,以推荐给与主促销产品交互的每个用户。
但是在我们深入研究如何获得相似的产品之前,我们需要首先了解推荐系统如何找到相似的产品推荐给用户。
推荐系统是如何工作的?
推荐系统,例如基于项目的协同过滤,基于用户先前消费的产品历史来推荐产品。系统寻找用户已经积极互动的产品,然后找到与消费的产品相似的其他产品,并相应地推荐。
Sidharth 在 spatnaik77 上的照片
因此,推荐系统的核心就是寻找与用户已经喜欢的产品相似的产品。
但是产品相似度是怎么计算的呢?如果有多种类似的产品,在这种情况下应该推荐哪种产品呢?关于这些技术如何工作的细节超出了这篇文章的范围,但是你可以参考下面的文章,在文章中,我使用 excel 表格更详细地解释了每一步。
本指南将详细介绍推荐系统的工作原理以及如何在实际工作中实现它…
towardsdatascience.com](/comprehensive-guide-on-item-based-recommendation-systems-d67e40e2b75d)
下面是计算产品相似度的公式:
相似性方程(Muffaddal)
其中,i
是计算相似度的产品,我们的促销产品,而j
是与i
进行比较的产品。r
是用户u
对产品i
的评价。
如果你想深入研究相似度计算技巧,我建议从 这门课开始,这里有 。
寻找产品之间的相似性
我们将使用 RecommenderLab,一个 R 包来构建推荐系统,帮助我们获得相关产品。它有一个名为similarity
的函数,可以帮助计算项目之间的相似度。下面是基本代码:
similarity
函数有三个输入:
数据集: 包含产品及其评级的数据集。数据集应采用 realRatingMatrix 格式。
方法: 这是我们指定计算相似性的技术,比如上面讨论的余弦相似性。其他方法包括 Jaccard,欧几里德,皮尔逊相似性。
其中: 这告诉了 *similarity*
函数在什么层次上计算相似度。它可以是产品级的,也可以是用户级的。产品级计算相似的产品,而用户级计算相似的用户。
现在让我们使用 recommenderLab 的similarity
函数来计算类似的产品。这是我们的主要数据集的样子。
Muffaddal 的评级数据集示例
r 代码来计算我们的评级数据集的相似性。
上面的代码为我们提供了产品间相似性得分的矩阵。
产品之间的相似性得分矩阵,Muffaddal
上面的输出确实让我们得到了每个产品的相似性得分,但是很难知道对于任何给定的项目,什么是最相似的产品。所以,让我们来有序地找出前 50 个高度相似的产品。
下面是输出的样子:
Muffaddal 的类似产品列表
product
列代表主要产品,我们将从中提取其他类似产品。列1
包含与我们的主要产品最相似的产品。所以产品B000GIOPK2’s
最相似的产品是B000IJRK7O
等等。
就是这样!
几行代码为我们提供了用于营销和应用内建议的类似产品列表。
其他相似性计算技术
除了余弦相似度,还有Jaccard, Euclidean, Pearson etc.,
来计算产品之间的相似度得分。每个人都有自己的方法来计算两个产品有多相似。参见 Marvin Lü的文章,他在文章中讨论了所有不同的相似性计算技术。
你只需要用你想用来计算相似性得分的方法替换单词cosine
,例如,对于Jaccard
相似性,我们的代码将改为;
product.similarity <- similarity(rr, method = “**jaccard**”, which = ‘items’)
标准化评级值
除了不同的相似性计算技术之外,我们还可以标准化评分值。正常化有助于迎合人们乐观的天性。不同的人会根据他们的乐观程度对同一件事做出不同的评价。例如,在 5 的范围内,一个人可以给产品打 5 星,而另一个人可以打 3 星,即使他们都非常喜欢这个产品。
RecommenderLab 有一个内置函数来帮助规范化这些值。
r <- normalize(r, “Center”)
关键字“Center”告诉normalize
函数使用哪种方法来标准化评级。除了center
之外,我们还有z-score
来使值规范化。
最后的话
向用户推荐合适的产品不仅可以提高互动率,还可以带来更多的商业转化和回报。基于机器学习找到类似的产品是一种有效的方法,可以让相关的产品用于营销和应用程序中。这样做不仅能提供更好的用户体验,还能增加产品的知名度。
你可能喜欢的类似文章
本指南将详细介绍基于项目的推荐系统是如何工作的,以及如何在实际工作中实现它…
towardsdatascience.com](/comprehensive-guide-on-item-based-recommendation-systems-d67e40e2b75d) [## 基于购买历史的用户细分
根据用户的购买行为对其进行细分,从而改进广告活动。
towardsdatascience.com](/user-segmentation-based-on-purchase-history-490c57402d53)