TowardsDataScience-博客中文翻译-2019-七十-

TowardsDataScience 博客中文翻译 2019(七十)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

基于情节摘要使用 NLP 查找相似的电影

原文:https://towardsdatascience.com/using-nlp-to-find-similar-movies-based-on-plot-summaries-b1481a2ba49b?source=collection_archive---------14-----------------------

人人都爱电影,对吧?本文将介绍 NLP 中的一些基本概念,并展示如何使用 scikit-learn 和 NLTK 库实现一个简单的模型来比较电影摘要之间的相似性。

这篇文章的内容基于这个 DataCamp 项目,并且这篇文章中使用的数据由来自维基百科和 IMDb 的 100 部电影的情节摘要组成。

准备数据

在处理文本数据时,我们需要对数据集进行一些特殊的调整,比如标记化、词干化和矢量化。我们将会看到这些步骤的作用。

标记化

给定一个字符序列,标记化是将它分解成具有有用和基本意义的基本语义单元的过程。这些碎片被称为代币。比如:句子“你今天过得怎么样?”可以拆分为“如何”、“s”、“你的”、“日”和“日”等标记。".每一个都有特定的含义。

堵塞物

想想这些句子:“我们需要更多的计算能力”和“我们需要计算机更强大”。两者意思都差不多,只是主词的写法不同(computational/计算机,power/强大)。我们可以将这些词的屈折形式简化为词根或基本形式,例如“comput”和“power”具有相同的意思。这样,词汇表的大小就减少了,使模型更容易在有限的数据集上进行训练。

…向量化…

除了数字,计算机不能处理任何东西。为了实现对文本的任何操作,我们首先需要将文本转换成数字。这个过程被称为矢量化,顾名思义,它们被组织成向量。有多种向量化文本的方法。这里我们将使用单词袋和 TF-IDF。

  • 单词包(BoW) :每个句子被表示为一个固定大小的向量,其大小等于词汇表中的单词数,每个位置表示一个特定的单词。这个位置的值是该特定单词在句子中出现的次数。
  • 词频-逆文档频率(TF-IDF) :当我们需要比较两个文档之间的相似性时,为文档中的每个单词指定一个重要性度量是很有帮助的,这样我们就可以专注于特定的部分。TF-IDF 在于通过两个术语的乘积来发现这种“重要性”: TF 术语表示该单词在文档中的出现频率,而 IDF 术语表示文档中出现该特定单词的频率。基本思想是:如果这个词在很少的文档中出现很多,那么它一定很重要。如果在很多文档中出现很多,那一定不重要(比如“the”、“of”、“a”)。

代码

我们现在准备实施这些概念。首先,我们将导入一些库,如 Pandas 来操作我们的数据, scikit-learn 来创建我们的管道并训练我们的模型,以及 NLTK 用于自然语言的分词器、停用词和词干。

CSV 文件被加载到熊猫数据帧中。电影数据集有两列用于绘图:wiki_plotimdb_plot。我们将它们连接成一个名为plot的新列,这样我们就可以有一个包含更多信息的单列。

import numpy as np
import pandas as pd
import re
import nltkmovies_df = pd.read_csv('datasets/movies.csv')movies_df['plot'] = movies_df['wiki_plot'].astype(str) + "\n" + movies_df['imdb_plot'].astype(str)

然后定义函数normalize,它将对数据集的每个文档的每个单词中的特殊字符进行分词、词干提取和过滤。

from nltk.stem.snowball import SnowballStemmer
stemmer = SnowballStemmer("english", ignore_stopwords=False)def normalize(X): 
  normalized = []
  for x in X:
    words = nltk.word_tokenize(x)
    normalized.append(' '.join([stemmer.stem(word) for word in words if re.match('[a-zA-Z]+', word)]))
  return normalized

被定义为具有三个步骤的管道:

  • 应用normalize功能
  • 使用单词包对所有文档进行矢量化处理(这一步还会删除停用词)
  • 将单词包转换成 TF-IDF 矩阵

然后,我们在管道上调用fit_transform,并将所有电影的情节列作为参数传递。该方法将按顺序运行每个步骤,沿途转换数据并返回上一步的结果,这是一个(n_movies,n_words)矩阵,其中包含每个电影的相应 TF-IDF 向量。

from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer
from sklearn.preprocessing import FunctionTransformer

pipe = Pipeline([
  ('normalize', FunctionTransformer(normalize, validate=False)),
  ('counter_vectorizer', CountVectorizer(
    max_df=0.8, max_features=200000,
    min_df=0.2, stop_words='english',
    ngram_range=(1,3)
  )),
  ('tfidf_transform', TfidfTransformer())
])

tfidf_matrix = pipe.fit_transform([x for x in movies_df['plot']])

由于句子被转换成向量,我们可以计算它们之间的余弦相似度,并表示这些向量之间的“距离”。使用tfidf_matrix计算余弦相似度,并返回一个具有维数(n_movies,n_movies)的矩阵,其中包含它们之间的相似度。

from sklearn.metrics.pairwise import cosine_similarity similarity_distance = 1 - cosine_similarity(tfidf_matrix)

使用相似性距离,可以创建一个树状图:

import matplotlib.pyplot as plt
from scipy.cluster.hierarchy import linkage, dendrogram

mergings = linkage(similarity_distance, method='complete')
dendrogram_ = dendrogram(mergings,
               labels=[x for x in movies_df["title"]],
               leaf_rotation=90,
               leaf_font_size=16,
              )

fig = plt.gcf()
_ = [lbl.set_color('r') for lbl in plt.gca().get_xmajorticklabels()]
fig.set_size_inches(108, 21)

plt.show()

Dendrogram of similar movies

我们甚至可以创建一个功能来搜索与另一部电影最相似的电影。这里我们使用一个 numpy 方法argsoft来寻找矩阵中第二相似的电影。这是因为一部电影的最小距离是和自己。这可以在主对角线的similarity_distance中看到(所有值都为零)。

def find_similar(title):
  index = movies_df[movies_df['title'] == title].index[0]
  vector = similarity_distance[index, :]
  most_similar = movies_df.iloc[np.argsort(vector)[1], 1]
  return most_similarprint(find_similar('Good Will Hunting')) # prints "The Graduate"

结论

为 NLP 中基本任务训练机器学习模型是简单的。首先,对数据进行令牌化和过滤,以便可以用称为令牌的单元来表示。我们还可以将单词表示为它们的词根形式,因此词汇量也可以减少,然后我们使用一种算法对数据集进行矢量化,这种算法取决于我们试图解决的问题。之后,我们可以训练一些机器学习模型,生成更多的文本,可视化我们的数据,等等。

下次见!

利用自然语言处理理解法律

原文:https://towardsdatascience.com/using-nlp-to-understand-laws-95278624ae5?source=collection_archive---------13-----------------------

对《安大略省残疾人无障碍法》的非监督分析

法律推理和决策过程严重依赖于文本中存储的信息。像尽职调查、合同审查和法律发现等传统上非常耗时的任务可以从 NLP 模型中受益并实现自动化,从而节省大量时间。但是 NLP 能被用来提高公众对法律的理解吗?

其想法是获得法律的抽象表示,这将更容易提取文本中定义的规则和义务,并理解哪些实体负责合规,突出各行业的相似模式,公共和私人责任之间的差异,甚至识别不清楚的部分。

挑战

处理法律法规给分析增加了一些难度:

  • 由于使用了特定于法律文档的格式、缩写和引用,语言解析和标记化变得更加困难。
  • 词汇表相对有限且非常专业,但解释对上下文高度敏感,并且没有包含语义分析的行业特定的预训练模型。
  • 句子的句法通常是复杂的和非线性的,使得信息提取更加困难。

Extract from the Accessibility for Ontarians with Disabilities Act (AODA) — bullet points, references and general formatting break out-of-the=box tokenizations algorithms.

结构

为了克服这些挑战,在缺乏标记集的情况下,我们开发了一种方法,将基于规则的系统与标准 NLP 管道和无监督 ML 的元素相结合,以定义一个可以推广到各个领域的分析框架,而不是训练单个模型。

NLP 管道中与框架相关的模块有:

  • Tokenizer:将文档分割成称为记号的单元,同时丢弃不含信息的字符,如空格和标点。
  • Lemmatizer :减少屈折形式并将单词映射到它们的字典形式。
  • 词性标注器:将每个标记分配给一组具有相似语法属性(词性)的单词
  • 依存解析器:通过识别中心词和修饰这些中心词的词来识别句子的语法结构,建立语法依存关系树。

source:spacy

在此框架内,我们的目标是根据法规中定义的规则、负责合规的实体提取信息,并将规则组织到同类组中。

The three stages of the analysis

为了测试这种方法,我们根据安大略省残疾人无障碍法案(AODA) 制作了一份概念证明,该法案于 2005 年通过,定义了无障碍规则和要求,并规定了消除安大略省残疾人障碍的流程。

规则提取

我们的第一个目标是使扫描法律文本和提取定义规则的句子的过程自动化。在 AODA 的环境中,我们对负担特别感兴趣,即组织必须遵守的要求或义务。

为了解决没有标签集进行训练的问题,我们构建了一个轻量级的本体,并识别表达规则或义务的动词。这可以通过在 WordNet 中查询表示义务的动词的同义词来实现,例如应该必须责成等。包含这些动词之一的句子被标为负担。

这是一个粗略的分类规则,但在这种情况下,句子遵循一个定义良好的模板,并且词汇有限,这对我们有利。在 AODA 上,它达到了 0.89 的整体准确率和 0.97 的负担召回率。

主题提取

下一步是确定负责遵守提取的负担的实体。这相当于识别句子的语法主语,其中主语是表示谁或什么执行动词动作的单词或短语。

依存解析器可以用来识别充当动词主语的标记。然而,当主题是一个短语时,仅靠解析器不足以识别主题。这里有一个例子:

作为学校董事会或教育或培训机构的负责组织应保留所提供培训的记录。

在这个句子中,主语是短语义务组织,即学校董事会或教育或培训机构,但是依存解析器只将组织标记为名词主语( nsubj )。

The subject of the sentence includes, in practice, all the dependencies of the nsubj “organization”

这里一个可能的解决方案,就是用依存树找到句子的主语,然后用广度优先搜索导航树,找到所有和主语有父子关系的标记。这为我们提供了定义负责遵守上一步提取的规则的实体所涉及的所有单词。

主题聚类

一旦确定了负责的实体,我们希望将它们分成同类的组。这是通过将主题作为输入传递给 k-means 聚类来完成的,但是在我们继续进行聚类之前,需要将主题投影到一个向量空间中。这种预处理包括:

  • 规范化:标记被词汇化,停用词被删除。
  • 向量表示:单词嵌入(手套)用于将标准化的单词投影到语义空间,然后对每个主题的单词向量进行平均,以便我们可以对每个主题进行单向量表示。
  • 降维:谱分解用于降维,只保留前两个分量。

最后,我们通过 k-means 运行主题向量并提取三个组。

结果

K-means 对数据进行分组,以便将每个数据点分配给具有最近平均值的聚类,这意味着聚类的平均值(它们的质心)可以用作这些组的原型。

我们正在寻找一种表述方式,使我们能够简化对我们提取的规则的解释和理解,我们特别感兴趣的是区分私人和公共责任,即落在私人企业身上的负担和政府机构的责任。

主题向量的 2d 图表明这些组被很好地分开,但是为了真正理解这些组代表什么,我们看一下质心的 tf-idf 。这表示一个词/词在一个主题中的平均频率,用一个与该词在所有主题中的使用频率成比例的数量进行加权。

组#1 中质心的前 20 个单词的 tf-idf 分布非常向右倾斜,并且由单词运输服务提供者支配,因此这些负担的大约 90%来自运输标准部分就不足为奇了。这大约是我们提取的所有负担的 20%,很有意义,因为我们在谈论可访问性。

第二组中前 20 个单词的偏斜较小,分布更接近均匀。这一组中的大多数单词都是指得分最高的实物、表面坡道,以及许多其他单词,如步道楼梯等。我们在第一阶段分析中提取的总负担中,有 25%属于这一组,其中 80%来自公共空间设计部分。同样,没有迹象表明公共或私营实体的要求之间存在区别。

在最后一组中,tf-idf 的最高分遥遥领先于组织,而其他所有组织之间的差距要小得多。这些词是政府和非政府实体的混合指针——我们有部长市政以及雇主个人。这些负担占总负担的 50%,来自各种部门,主要指向管理、合规和标准,但不清楚公共义务和私人义务之间是否有区别。

摘要

我们开始时没有一个带标签的集合,但仍然能够建立一个通用的方法,允许我们自动提取规则,并以良好的准确性找到由立法定义的负担。通过提取句子的语法主题,我们能够识别受立法影响的实体,最终我们能够将规则组织成同类的组,这有助于我们理解这项立法的重点,甚至找到文本中模糊不清、需要澄清的部分。

这是走向法律抽象表述的第一步,至少在几个方面可以达到提高法律可解释性的目的。

一方面,它有助于提取信息并进行汇总,以便需要遵守规则和要求的任何人都可以更容易地了解这些规则和要求,无论他们是有法律部门的组织还是普通人。另一方面,它可以通过突出立法中模糊不清的部分来帮助立法者,这些部分可以重写或修改,以使其更加清晰易懂。

最终,这一框架可以成为一种工具,既有助于理解现有的立法,也有助于改进法律的编写方式,以便今后我们的立法者能够编写更容易理解和解释的法律,从而使每个人都更容易理解。

将对象检测用于复杂的图像分类场景第 3 部分:

原文:https://towardsdatascience.com/using-object-detection-for-complex-image-classification-scenarios-part-3-770d3fc5e3f7?source=collection_archive---------8-----------------------

利用 MobileNet 和迁移学习进行策略识别

TLDR;本系列基于在下面的现实生活代码故事中检测复杂策略的工作。该系列的代码可以在这里找到。

第 3 部分:使用 MobileNet 和迁移学习进行策略识别

在之前的教程中,我们概述了我们的策略分类挑战,并展示了我们如何使用定制视觉认知服务来应对它。本教程介绍深度迁移学习作为一种手段,利用多个数据源来克服数据稀缺问题。

处理图像

Our goal is to extract the differential signal from our training images

在我们尝试为我们的复杂策略构建分类器之前,让我们先来看看 MNIST 数据集,以便更好地理解关键的图像分类概念,如一个热编码、线性建模、多层感知、掩蔽和卷积,然后我们将把这些概念放在一起,并将其应用到我们自己的数据集。

A sample of the images in the MNIST Dataset

为了在 MNIST 上训练一个分类模型,我们首先需要一种方法来表示我们的图像和标签。有许多方法可以将图像表示为张量(T12)、矩阵(T14)、向量(T15)或向量(T17)。

对于我们的第一个模型,我们将使用矢量表示。为了做到这一点,我们首先将图像展平成一个长矢量,就像解开一根布的线一样。

Unraveling a cloth to a thread source

当我们将此过程应用于下面的尺寸为 28 x 28 图像像素的“3”的图像时,它将产生长度为 784 像素的展平数组。

The MNIST image 28 x 28 image pixels, it will result in a flattened array of length 784.

现在,尽管我们很容易看到这个图像并知道它是一个“3”,但计算机天生不知道这一点,我们需要训练一个模型来学习如何识别图像中有一个“3”。要做到这一点,我们首先需要一种方法来表示上面的图片包含一个“3”的图像这一事实。

编码图像标签

为此,我们将我们的每个图像与一个 1-hot 编码标签相关联,其中第一个索引对应于数字0,最后一个索引对应于数字9

A one hot encoded vector representation of an MNIST 3

当我们训练一个模型时,我们使用这个值作为我们的目标。下面的 Keras 代码加载 MNIST 数据

**from** **keras.datasets** **import** mnist 
**from** **keras.utils** **import** np_utils output_dim = nb_classes = 10 
batch_size = 128 
nb_epoch = 5*# the data, shuffled and split between train and test sets* 
(x_train, y_train), (x_test, y_test) = mnist.load_data()input_dim = 784 *#28*28* 
X_train = x_train.reshape(60000, input_dim) 
X_test = x_test.reshape(10000, input_dim) 
X_train = X_train.astype('float32') 
X_test = X_test.astype('float32') 
X_train /= 255 
X_test /= 255Y_train = np_utils.to_categorical(y_train, nb_classes) 
Y_test = np_utils.to_categorical(y_test, nb_classes)

现在,我们已经处理了 MNIST 图像及其标签,让我们使用 Keras 训练我们的第一个图像分类模型。

线性模型

逻辑回归 (LR)是一种基本的机器学习技术,它使用特征的线性加权组合,并生成不同类别的基于概率的预测。

为了在 MNIST 上训练上面的 LR 模型,我们应用以下步骤:

  1. 初始化 784 个值的随机权重向量
  2. 取第一个 784 位 MNIST 训练图像向量,如上面的“3 ”,并将其乘以我们的权重向量。
  3. 取我们相乘的结果,对 784 个值求和,直到得到一个数
  4. 将数字传递到一个函数中,该函数取我们的总和,并将其拟合为 0-9 之间的分布,然后对输出进行热编码。对于第一个例子,这个数字很可能是不正确的,因为我们乘以了随机值
  5. 将输出向量与图像标签向量进行比较,并使用损失函数计算我们的预测有多接近。损失函数的输出被称为损失
  6. 针对损失值应用诸如 SGD 的优化,以更新权重向量中的每个值。

[## 损失函数和优化算法。去神秘化。

深度学习模型的优化算法和损失函数的选择可以在生产过程中发挥重要作用

medium.com](https://medium.com/data-science-group-iitr/loss-functions-and-optimization-algorithms-demystified-bb92daff331c)

然后,我们对 MNIST 训练集中的每个图像重复这个过程。对于每个图像,权重值被更新,以便它们可以更好地将我们的输入 MNIST 向量转换为与其标签相匹配的值。

The machine learning process Source

当我们在称为 时期 的训练集上完成上述步骤时。在第一个时期之后,值仍然可能是差的,但是在改组数据集并重复该过程几个更多的时期之后,线性模型学习线性权重,它们收敛在我们的数据的体面表示上。

下面的 Keras 代码显示了这个过程的结果。

**from** **keras.models** **import** Sequential 
**from** **keras.layers** **import** Dense, Activation model = Sequential() 
model.add(Dense(output_dim, input_dim=input_dim, activation='softmax')) 
model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy']) 
history = model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch,verbose=1, validation_data=(X_test, Y_test)) 
score = model.evaluate(X_test, Y_test, verbose=0) 
print('Test Loss:', score[0]) 
print('Test accuracy:', score[1]) 
Train on 60000 samples, validate on 10000 samples
Epoch 1/5
60000/60000 [==============================] - 1s 16us/step - loss: 1.2899 - acc: 0.6898 - val_loss: 0.8185 - val_acc: 0.8255
Epoch 2/5
60000/60000 [==============================] - 1s 17us/step - loss: 0.7228 - acc: 0.8374 - val_loss: 0.6113 - val_acc: 0.8588
Epoch 3/5
60000/60000 [==============================] - 1s 11us/step - loss: 0.5912 - acc: 0.8575 - val_loss: 0.5281 - val_acc: 0.8724
Epoch 4/5
60000/60000 [==============================] - 1s 11us/step - loss: 0.5280 - acc: 0.8681 - val_loss: 0.4821 - val_acc: 0.8800
Epoch 5/5
60000/60000 [==============================] - 1s 13us/step - loss: 0.4897 - acc: 0.8749 - val_loss: 0.4514 - val_acc: 0.8858
Test Loss: 0.4514175675392151
Test accuracy: 0.8858

非线性模型(MLP)

可以想象,仅仅基于一个输出增加和求和权重向量值是次优的,并且在某些情况下是无效的。

毕竟不是所有的数据都是线性的。

以垃圾邮件和非垃圾邮件这两个图像类别为例。无论我们如何更新我们的权重,没有线性权重,我们可以学习区分这些类。

但是,如果我们有一种方法来组合多个线性模型以获得更好的表示能力呢?然后我们可以训练一个模型来区分这两种图像类别。

我们可以通过前馈神经网络来实现这一点,例如多层感知

Multi Layer Perception

对于 MLPs 的工作,我们需要一个非线性的激活函数,如 RELU。为了简洁起见,我们将把它作为一个黑盒。更多关于这个主题的内容,请见下面的帖子。

[## 理解神经网络中的激活函数

最近,我的一个同事问了我几个类似“为什么我们有这么多激活功能?”,“为什么是…

medium.com](https://medium.com/the-theory-of-everything/understanding-activation-functions-in-neural-networks-9491262884e0)

下面的 keras 代码显示了如何在 MNIST 上训练一个多层感知器,以获得比我们的线性模型更好的结果。

**from** **keras.models** **import** Sequential 
**from** **keras.layers** **import** Dense, Activation 
output_dim = nb_classes = 10 
batch_size = 128 
nb_epoch = 5model = Sequential() 
model.add(Dense(input_dim, input_dim=input_dim, activation='relu')) 
model.add(Dense(input_dim, input_dim=input_dim, activation='relu'))
model.add(Dense(output_dim, input_dim=input_dim, activation='softmax')) model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy']) 
history = model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch,verbose=1, validation_data=(X_test, Y_test)) 
score = model.evaluate(X_test, Y_test, verbose=0) 
print('Test Loss:', score[0]) 
print('Test accuracy:', score[1])
Train on 60000 samples, validate on 10000 samples
Epoch 1/5
60000/60000 [==============================] - 9s 150us/step - loss: 1.0790 - acc: 0.7676 - val_loss: 0.5100 - val_acc: 0.8773
Epoch 2/5
60000/60000 [==============================] - 9s 143us/step - loss: 0.4401 - acc: 0.8866 - val_loss: 0.3650 - val_acc: 0.9011
Epoch 3/5
60000/60000 [==============================] - 12s 194us/step - loss: 0.3530 - acc: 0.9032 - val_loss: 0.3136 - val_acc: 0.9127
Epoch 4/5
60000/60000 [==============================] - 16s 272us/step - loss: 0.3129 - acc: 0.9124 - val_loss: 0.2868 - val_acc: 0.9188
Epoch 5/5
60000/60000 [==============================] - 12s 203us/step - loss: 0.2875 - acc: 0.9194 - val_loss: 0.2659 - val_acc: 0.9246
Test Loss: 0.2659078140795231
Test accuracy: 0.9246

当我们有很多非常大的图像时会发生什么?

请注意,MLP 模型比我们简单的线性模型要精确得多,但也慢得多。当我们有大于 500Kb 到 1Mb 的图像时,将我们的图像作为一个序列进行处理的计算成本越来越高。此外,在我们的序列数据中检测复杂的自参照和层次模式也变得更具挑战性。

这种维数灾难是计算机视觉领域停滞不前的关键原因之一,直到 2012 年 AlexNet 的出现。

如果不是将我们的完整图像作为向量表示来传递,而是将我们的图像表示为矩阵(28×28 ),而是提取代表性特征来做出分类决策,会怎么样?这就是计算机视觉直到最近的工作方式。让我们通过尝试使用边缘作为模型的特征来更深入地了解传统的图像特征提取。

为了做到这一点,我们首先采取如下图所示的图像。

Src Wikimedia Commons

然后我们使用一个预定义的图像遮罩,在这种情况下是一个用于提取边缘的索贝尔矩阵

src researchgate publication #275073476

我们应用索贝尔矩阵掩模像过滤器一样大步前进到我们的图像

当我们可视化生成的图像时,我们得到下面的边缘,这些边缘可以用作特征

Src Wikimedia Commons

手工制作像 Sobel 面具这样的面具是一项艰苦而脆弱的工作,如果我们能学会面具会怎么样呢?这是卷积神经网络或 CNN 背后的关键见解。

卷积神经网络介绍(CNN 101)

The result of applied different learned conventional filters on a source imageSource: video

CNN 是一个深度神经网络,由一系列层组成,其中一层的输出被馈送到下一层(有更复杂的架构,可以跳过具有 dropout 的层,我们现在将把这视为给定的)。通常,CNN 从卷积层和汇集层(向下采样)之间的交替开始,然后以分类部分的全连接层结束。

盘旋

卷积层是一组过滤器。每个滤波器由权重( W )矩阵和偏差( b )定义。

联营

一旦我们应用我们的面具,我们使用池来减少前一层的维度,这加快了网络。

Source: stanford.io/2Td4J2d

有许多不同的汇集方法最大平均汇集是最常见的。

这是一个步长为 2 的最大和平均池的示例:

Various Pooling operations | Source: bit.ly/2K5zlP2

将所有这些放在一起:

在大多数 CNN 中,我们堆叠一组卷积层和池层,直到我们有一组代表性的特征,我们可以将其展平并用于类预测。

src mathworks.com

下面的代码显示了如何从上面的 MNIST 图像训练 CNN。

**from** **keras.layers** **import** Dropout, Flatten
**from** **keras.layers** **import** Conv2D, MaxPooling2Dmodel = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(nb_classes, activation='softmax'))model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adadelta(),
              metrics=['accuracy'])model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=nb_epoch,
          verbose=1,
          validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1]) 
Train on 60000 samples, validate on 10000 samples
Epoch 1/5
60000/60000 [==============================] - 177s 3ms/step - loss: 0.2638 - acc: 0.9204 - val_loss: 0.0662 - val_acc: 0.9790
Epoch 2/5
60000/60000 [==============================] - 173s 3ms/step - loss: 0.0882 - acc: 0.9732 - val_loss: 0.0404 - val_acc: 0.9865
Epoch 3/5
60000/60000 [==============================] - 166s 3ms/step - loss: 0.0651 - acc: 0.9806 - val_loss: 0.0350 - val_acc: 0.9883
Epoch 4/5
60000/60000 [==============================] - 163s 3ms/step - loss: 0.0549 - acc: 0.9836 - val_loss: 0.0334 - val_acc: 0.9887
Epoch 5/5
60000/60000 [==============================] - 159s 3ms/step - loss: 0.0472 - acc: 0.9859 - val_loss: 0.0322 - val_acc: 0.9899
Test loss: 0.03221080291894468
Test accuracy: 0.9899

在 MNIST 数据集中,我们有成千上万的训练样本,如果我们的策略任务中的数据更少会怎样?这就是我们可以使用迁移学习的地方。从头开始训练一个深度神经网络需要成千上万的图像,但训练一个已经学习了你正在适应的领域的特征的网络需要的图像要少得多。

第四部分迁移学习简介

什么是迁移学习?

迁移学习,使用预先训练好的模型,并使其适应我们自己的问题。在迁移学习中,我们利用在基本模型的培训过程中学习到的功能和概念。旧的和新的预测层的输入与基础模型相同,我们只是重复使用训练过的特征。然后,我们训练这个修改后的网络,或者只训练新预测层的新权重,或者训练整个网络的所有权重。

例如,当我们有一小组与现有训练模型处于相似领域的图像时,可以使用这种方法。在我们的例子中,这意味着使在 ImageNet 图像上训练的网络适应策略分类的任务。

预训练模型(MobileNet)

Aditya Ananthram 的 repopost 是本节的灵感来源,我强烈建议您查看一下。

对于这个任务,我们选择使用预训练的 MobileNet 模型作为我们的基础模型。虽然有许多分类体系结构,但我们将使用 MobileNet,因为它在 CPU 上运行速度很快,并提供强大的结果。

**from** **keras.layers** **import** Dense,GlobalAveragePooling2D
**from** **keras.applications** **import** MobileNet
**from** **keras.preprocessing** **import** image
**from** **keras.applications.mobilenet** **import** preprocess_input
**from** **keras.preprocessing.image** **import** ImageDataGenerator
**from** **keras.models** **import** Model
**from** **keras.optimizers** **import** Adambase_model=MobileNet(weights='imagenet',include_top=**False**) *#imports the mobilenet model and discards the last 1000 neuron layer.*x=base_model.output
x=GlobalAveragePooling2D()(x)
x=Dense(1024,activation='relu')(x) *#we add dense layers so that the model can learn more complex functions and classify for better results.*
x=Dense(1024,activation='relu')(x) *#dense layer 2*
x=Dense(512,activation='relu')(x) *#dense layer 3*
preds=Dense(2,activation='softmax')(x) *#final layer with softmax activation*model=Model(inputs=base_model.input,outputs=preds)
**for** layer **in** model.layers[:20]:
    layer.trainable=**False**
**for** layer **in** model.layers[20:]:
    layer.trainable=**True** Downloading data from [https://github.com/fchollet/deep-learning-models/releases/download/v0.6/mobilenet_1_0_224_tf_no_top.h5](https://github.com/fchollet/deep-learning-models/releases/download/v0.6/mobilenet_1_0_224_tf_no_top.h5)
17227776/17225924 [==============================] - 13s 1us/step

让我们来看看这个 MobileNet 模型

model.summary()_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, None, None, 3)     0         
_________________________________________________________________
conv1_pad (ZeroPadding2D)    (None, None, None, 3)     0         
_________________________________________________________________
conv1 (Conv2D)               (None, None, None, 32)    864       
_________________________________________________________________
conv1_bn (BatchNormalization (None, None, None, 32)    128       
_________________________________________________________________
conv1_relu (ReLU)            (None, None, None, 32)    0         
_________________________________________________________________
conv_dw_1 (DepthwiseConv2D)  (None, None, None, 32)    288       
_________________________________________________________________
conv_dw_1_bn (BatchNormaliza (None, None, None, 32)    128       
_________________________________________________________________
conv_dw_1_relu (ReLU)        (None, None, None, 32)    0         
_________________________________________________________________
conv_pw_1 (Conv2D)           (None, None, None, 64)    2048      
_________________________________________________________________
conv_pw_1_bn (BatchNormaliza (None, None, None, 64)    256       
_________________________________________________________________
conv_pw_1_relu (ReLU)        (None, None, None, 64)    0         
_________________________________________________________________
conv_pad_2 (ZeroPadding2D)   (None, None, None, 64)    0         
_________________________________________________________________
conv_dw_2 (DepthwiseConv2D)  (None, None, None, 64)    576       
_________________________________________________________________
conv_dw_2_bn (BatchNormaliza (None, None, None, 64)    256       
_________________________________________________________________
conv_dw_2_relu (ReLU)        (None, None, None, 64)    0         
_________________________________________________________________
conv_pw_2 (Conv2D)           (None, None, None, 128)   8192      
_________________________________________________________________
conv_pw_2_bn (BatchNormaliza (None, None, None, 128)   512       
_________________________________________________________________
conv_pw_2_relu (ReLU)        (None, None, None, 128)   0         
_________________________________________________________________
conv_dw_3 (DepthwiseConv2D)  (None, None, None, 128)   1152      
_________________________________________________________________
conv_dw_3_bn (BatchNormaliza (None, None, None, 128)   512       
_________________________________________________________________
conv_dw_3_relu (ReLU)        (None, None, None, 128)   0         
_________________________________________________________________
conv_pw_3 (Conv2D)           (None, None, None, 128)   16384     
_________________________________________________________________
conv_pw_3_bn (BatchNormaliza (None, None, None, 128)   512       
_________________________________________________________________
conv_pw_3_relu (ReLU)        (None, None, None, 128)   0         
_________________________________________________________________
conv_pad_4 (ZeroPadding2D)   (None, None, None, 128)   0         
_________________________________________________________________
conv_dw_4 (DepthwiseConv2D)  (None, None, None, 128)   1152      
_________________________________________________________________
conv_dw_4_bn (BatchNormaliza (None, None, None, 128)   512       
_________________________________________________________________
conv_dw_4_relu (ReLU)        (None, None, None, 128)   0         
_________________________________________________________________
conv_pw_4 (Conv2D)           (None, None, None, 256)   32768     
_________________________________________________________________
conv_pw_4_bn (BatchNormaliza (None, None, None, 256)   1024      
_________________________________________________________________
conv_pw_4_relu (ReLU)        (None, None, None, 256)   0         
_________________________________________________________________
conv_dw_5 (DepthwiseConv2D)  (None, None, None, 256)   2304      
_________________________________________________________________
conv_dw_5_bn (BatchNormaliza (None, None, None, 256)   1024      
_________________________________________________________________
conv_dw_5_relu (ReLU)        (None, None, None, 256)   0         
_________________________________________________________________
conv_pw_5 (Conv2D)           (None, None, None, 256)   65536     
_________________________________________________________________
conv_pw_5_bn (BatchNormaliza (None, None, None, 256)   1024      
_________________________________________________________________
conv_pw_5_relu (ReLU)        (None, None, None, 256)   0         
_________________________________________________________________
conv_pad_6 (ZeroPadding2D)   (None, None, None, 256)   0         
_________________________________________________________________
conv_dw_6 (DepthwiseConv2D)  (None, None, None, 256)   2304      
_________________________________________________________________
conv_dw_6_bn (BatchNormaliza (None, None, None, 256)   1024      
_________________________________________________________________
conv_dw_6_relu (ReLU)        (None, None, None, 256)   0         
_________________________________________________________________
conv_pw_6 (Conv2D)           (None, None, None, 512)   131072    
_________________________________________________________________
conv_pw_6_bn (BatchNormaliza (None, None, None, 512)   2048      
_________________________________________________________________
conv_pw_6_relu (ReLU)        (None, None, None, 512)   0         
_________________________________________________________________
conv_dw_7 (DepthwiseConv2D)  (None, None, None, 512)   4608      
_________________________________________________________________
conv_dw_7_bn (BatchNormaliza (None, None, None, 512)   2048      
_________________________________________________________________
conv_dw_7_relu (ReLU)        (None, None, None, 512)   0         
_________________________________________________________________
conv_pw_7 (Conv2D)           (None, None, None, 512)   262144    
_________________________________________________________________
conv_pw_7_bn (BatchNormaliza (None, None, None, 512)   2048      
_________________________________________________________________
conv_pw_7_relu (ReLU)        (None, None, None, 512)   0         
_________________________________________________________________
conv_dw_8 (DepthwiseConv2D)  (None, None, None, 512)   4608      
_________________________________________________________________
conv_dw_8_bn (BatchNormaliza (None, None, None, 512)   2048      
_________________________________________________________________
conv_dw_8_relu (ReLU)        (None, None, None, 512)   0         
_________________________________________________________________
conv_pw_8 (Conv2D)           (None, None, None, 512)   262144    
_________________________________________________________________
conv_pw_8_bn (BatchNormaliza (None, None, None, 512)   2048      
_________________________________________________________________
conv_pw_8_relu (ReLU)        (None, None, None, 512)   0         
_________________________________________________________________
conv_dw_9 (DepthwiseConv2D)  (None, None, None, 512)   4608      
_________________________________________________________________
conv_dw_9_bn (BatchNormaliza (None, None, None, 512)   2048      
_________________________________________________________________
conv_dw_9_relu (ReLU)        (None, None, None, 512)   0         
_________________________________________________________________
conv_pw_9 (Conv2D)           (None, None, None, 512)   262144    
_________________________________________________________________
conv_pw_9_bn (BatchNormaliza (None, None, None, 512)   2048      
_________________________________________________________________
conv_pw_9_relu (ReLU)        (None, None, None, 512)   0         
_________________________________________________________________
conv_dw_10 (DepthwiseConv2D) (None, None, None, 512)   4608      
_________________________________________________________________
conv_dw_10_bn (BatchNormaliz (None, None, None, 512)   2048      
_________________________________________________________________
conv_dw_10_relu (ReLU)       (None, None, None, 512)   0         
_________________________________________________________________
conv_pw_10 (Conv2D)          (None, None, None, 512)   262144    
_________________________________________________________________
conv_pw_10_bn (BatchNormaliz (None, None, None, 512)   2048      
_________________________________________________________________
conv_pw_10_relu (ReLU)       (None, None, None, 512)   0         
_________________________________________________________________
conv_dw_11 (DepthwiseConv2D) (None, None, None, 512)   4608      
_________________________________________________________________
conv_dw_11_bn (BatchNormaliz (None, None, None, 512)   2048      
_________________________________________________________________
conv_dw_11_relu (ReLU)       (None, None, None, 512)   0         
_________________________________________________________________
conv_pw_11 (Conv2D)          (None, None, None, 512)   262144    
_________________________________________________________________
conv_pw_11_bn (BatchNormaliz (None, None, None, 512)   2048      
_________________________________________________________________
conv_pw_11_relu (ReLU)       (None, None, None, 512)   0         
_________________________________________________________________
conv_pad_12 (ZeroPadding2D)  (None, None, None, 512)   0         
_________________________________________________________________
conv_dw_12 (DepthwiseConv2D) (None, None, None, 512)   4608      
_________________________________________________________________
conv_dw_12_bn (BatchNormaliz (None, None, None, 512)   2048      
_________________________________________________________________
conv_dw_12_relu (ReLU)       (None, None, None, 512)   0         
_________________________________________________________________
conv_pw_12 (Conv2D)          (None, None, None, 1024)  524288    
_________________________________________________________________
conv_pw_12_bn (BatchNormaliz (None, None, None, 1024)  4096      
_________________________________________________________________
conv_pw_12_relu (ReLU)       (None, None, None, 1024)  0         
_________________________________________________________________
conv_dw_13 (DepthwiseConv2D) (None, None, None, 1024)  9216      
_________________________________________________________________
conv_dw_13_bn (BatchNormaliz (None, None, None, 1024)  4096      
_________________________________________________________________
conv_dw_13_relu (ReLU)       (None, None, None, 1024)  0         
_________________________________________________________________
conv_pw_13 (Conv2D)          (None, None, None, 1024)  1048576   
_________________________________________________________________
conv_pw_13_bn (BatchNormaliz (None, None, None, 1024)  4096      
_________________________________________________________________
conv_pw_13_relu (ReLU)       (None, None, None, 1024)  0         
_________________________________________________________________
global_average_pooling2d_1 ( (None, 1024)              0         
_________________________________________________________________
dense_7 (Dense)              (None, 1024)              1049600   
_________________________________________________________________
dense_8 (Dense)              (None, 1024)              1049600   
_________________________________________________________________
dense_9 (Dense)              (None, 512)               524800    
_________________________________________________________________
dense_10 (Dense)             (None, 2)                 1026      
=================================================================
Total params: 5,853,890
Trainable params: 5,817,986
Non-trainable params: 35,904
_________________________________________________________________

让我们处理我们的数据

下面的代码展示了如何使用 Keras 在我们的定制策略上训练一个定制的 MobileNet 模型。

训练数据/测试数据

train_datagen=ImageDataGenerator(preprocessing_function=preprocess_input) *#included in our dependencies*train_generator=train_datagen.flow_from_directory(
'/data/dataset/Beverages/Train/',
target_size=(224,224),
color_mode='rgb',
batch_size=32,
class_mode='categorical',
shuffle=**True**)test_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)
test_generator = test_datagen.flow_from_directory(
    directory=r"/data/dataset/Beverages/Test/",
    target_size=(224, 224),
    color_mode="rgb",
    batch_size=1,
    class_mode='categorical',
    shuffle=**False**,
    seed=42
)
Found 180 images belonging to 2 classes.Found 60 images belonging to 2 classes.

查看图像数据样本

i = 0
**for** data **in** test_generator:
    **if** i > 3: **break** 
    **else**: i+=1
    img, cls = data
    print(np.argmax(cls))
    plt.imshow(img[0])
    plt.show()
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).0

Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).0

Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).0

Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).0

火车模型

model.compile(optimizer='Adam',loss='categorical_crossentropy',metrics=['accuracy'])
*# Adam optimizer*
*# loss function will be categorical cross entropy*
*# evaluation metric will be accuracy*step_size_train=train_generator.n//train_generator.batch_size
model.fit_generator(generator=train_generator,
                   steps_per_epoch=step_size_train,
                   epochs=5)
Epoch 1/5
5/5 [==============================] - 96s 19s/step - loss: 0.8017 - acc: 0.7313
Epoch 2/5
5/5 [==============================] - 77s 15s/step - loss: 0.0101 - acc: 1.0000
Epoch 3/5
5/5 [==============================] - 79s 16s/step - loss: 0.0289 - acc: 0.9937
Epoch 4/5
5/5 [==============================] - 111s 22s/step - loss: 0.0023 - acc: 1.0000
Epoch 5/5
5/5 [==============================] - 87s 17s/step - loss: 0.0025 - acc: 1.0000

基准模型

正如我们在下面看到的,MobileNet 是一个学习和展示我们玩具政策的强大模型。

**from** **utils** **import** classification_report
y_true = np.concatenate([np.argmax(test_generator[i][1], axis=1) **for** i **in** range(test_generator.n)])
y_pred =  np.argmax(model.predict_generator(test_generator, steps=test_generator.n), axis=1)
classification_report(y_true, y_pred)
precision    recall  f1-score   support 0       1.00      1.00      1.00        30
           1       1.00      1.00      1.00        30 micro avg       1.00      1.00      1.00        60
   macro avg       1.00      1.00      1.00        60
weighted avg       1.00      1.00      1.00        60Confusion matrix, without normalization
[[30  0]
 [ 0 30]]
Normalized confusion matrix
[[1\. 0.]
 [0\. 1.]]

然而,如果我们的政策更复杂,我们可能很难以这种方式建模。在下一篇文章中,我们将深入探讨如何在复杂的图像分类场景中使用对象检测。

资源

[## Pythic Coder 推荐的 Azure 机器学习入门内容

Tldr 由于 DevOps 资源上的帖子很受欢迎,而且很难找到文档,所以我…

medium.com](https://medium.com/microsoftazure/the-pythic-coders-recommended-content-for-getting-started-with-machine-learning-on-azure-fcd1c5a8dbb4) [## aribornstein —概述

@ pythiccoder。aribornstein 有 68 个存储库。在 GitHub 上关注他们的代码。

github.com](https://github.com/aribornstein) [## 认知服务|微软 Azure

微软 Azure Stack 是 Azure 的扩展——将云计算的灵活性和创新性带到您的…

azure.microsoft.com](https://azure.microsoft.com/services/cognitive-services/?v=18.44a&v=18.44a&v=18.44a&WT.mc_id=medium-blog-abornst) [## 图像分类的一大妙招

来拿你的深度学习好东西吧

towardsdatascience.com](/a-big-of-tricks-for-image-classification-fec41eb28e01) [## 理解基于深度学习的图像分类器的终极纳米书

在当今世界,我们广泛使用图像。不是吗?你有没有想过脸书是如何自动…

towardsdatascience.com](/https-medium-com-rishabh-grg-the-ultimate-nanobook-to-understand-deep-learning-based-image-classifier-33f43fea8327)

下一篇文章

在下一篇文章中,我们将深入探讨如何将物体检测用于复杂的图像分类场景。未来的职位将涵盖。

  • 使用 Azure ML 服务在云上训练和计算机视觉模型
  • 使用 Azure 机器学习在远程集群上训练计算机视觉模型

如果您有任何问题、评论或希望我讨论的话题,请随时在 Twitter 上关注我。如果您认为我错过了某个里程碑,请告诉我。

关于作者

亚伦(阿里) 是一个狂热的人工智能爱好者,对历史充满热情,致力于新技术和计算医学。作为微软云开发倡导团队的开源工程师,他与以色列高科技社区合作,用改变游戏规则的技术解决现实世界的问题,然后将这些技术记录在案、开源并与世界其他地方共享。

将对象检测用于复杂的图像分类场景第 4 部分:

原文:https://towardsdatascience.com/using-object-detection-for-complex-image-classification-scenarios-part-4-3e5da160d272?source=collection_archive---------14-----------------------

使用 Keras RetinaNet 进行策略检测

TLDR;本系列基于在下面的现实生活代码故事中检测复杂策略的工作。该系列的代码可以在这里找到。

对象检测简介

到目前为止,我们一直在对原始图像进行分类如果我们可以使用这些图像来生成有针对性的特征,以帮助我们应对高级分类挑战,那会怎么样。

We will use object detection to extract features for more complex classification Src

端到端对象检测管道:

对象检测需要大量带注释的数据。传统上,这是一项非常手动密集型的任务,理想的管道将标记与模型训练相结合,以实现主动学习。

视觉对象标记工具(VoTT)

视觉对象标记工具 VoTT 为从视频和图像资产生成数据集和验证对象检测模型提供端到端支持。

VoTT 支持以下功能:

  • 标记和注释图像目录或独立视频的能力。
  • 使用 Camshift 跟踪算法对视频中的对象进行计算机辅助标记和跟踪。
  • 将标签和资源导出为 Tensorflow (PascalVOC)或 YOLO 格式,用于训练对象检测模型。
  • 在新视频上运行和验证经过训练的对象检测模型,以利用 docker 端点生成更强的模型。

区域提议目标检测算法的基本进展

以下部分将简要强调将用于该任务的区域提议对象检测的进展。对于更深入的教程,我强烈推荐乔纳森·惠的《中级系列》

[## 物体探测系列

概观

medium.com](https://medium.com/@jonathan_hui/object-detection-series-24d03a12f904)

滑动窗接近和后退

本系列的最后两篇文章是关于图像分类的。将图像分类器转换成对象检测器的最简单方法是在给定图像上使用一系列不同维度的滑动窗口。

Sliding Window Source

如果我们认为在给定的窗口中有一个我们正在寻找的对象,那么我们可以返回被捕获对象的尺寸。

地区有线电视新闻网

不幸的是,滑动窗口方法虽然简单,但也有一些缺点。评估多个窗口大小很慢,而且不精确,因为我们事先不知道图像中每个对象的正确窗口大小。

如果我们可以只对可能包含对象的感兴趣区域执行分类,而不是在整个图像上使用滑动窗口,会怎么样?这是区域提议对象检测器背后的主要直觉。传统上,我们使用一种叫做选择性搜索的算法来提出感兴趣的区域。

快速 RCNN

虽然传统的 RCNN 方法在准确性方面工作良好,但是它的计算成本非常高,因为必须对每个感兴趣的区域评估神经网络。

快速 R-CNN 通过对每个图像只评估网络的大部分(具体来说:卷积层)一次来解决这个缺点。根据作者的说法,这导致测试期间的速度提高了 213 倍,训练期间的速度提高了 9 倍,而没有损失准确性。

更快的 RCNN

Faster RCNN architecture src

更快的 R-CNN 建立在以前的工作基础上,使用深度卷积网络有效地对对象提议进行分类。与以前的工作相比,更快的 R-CNN 采用了一个区域建议网络,它不需要对候选区域建议进行选择性搜索。

RetinaNet

RetinaNet 是一个对象检测器,它建立在更快的 RCNN 的直觉基础上,提供了特征金字塔和优化的焦损失,实现了比 Faster RCNN 更快的评估时间,并提供了焦损失,有助于防止过度拟合背景类。在撰写本文时,RetinaNet 是当前最先进的区域求婚网络。

更多信息请参见:

[## RetinaNet 背后的直觉

这篇博文的最终目的是让读者直观地了解 RetinaNet 的深层工作原理。

medium.com](https://medium.com/@14prakash/the-intuition-behind-retinanet-eb636755607d)

让我们用视网膜网络来解决我们的挑战

VoTT 可用于生成直接数据集,这些数据集可与 Azure 机器学习一起使用,以训练自定义对象检测模型。

[## 快速入门:Python - Azure 机器学习服务入门

Python 中的 Azure 机器学习服务入门。使用 Python SDK 创建一个工作空间,它是…

docs.microsoft.com](https://docs.microsoft.com/en-us/azure/machine-learning/service/quickstart-create-workspace-with-python?WT.mc_id=blog-medium-abornst)

然而,由于培训 RetinaNet 需要访问 N 系列 GPU 机器,出于时间的考虑,并确保本教程仅针对 CPU,我冒昧地对模型进行了预培训。在下一篇文章中,我们将讨论如何用 Azure 机器学习服务来训练这些模型。

让我们看看如何使用我们定制的预训练对象检测模型

*# import keras_retinanet*
**import** **keras**
**from** **keras_retinanet** **import** models
**from** **keras_retinanet.utils.image** **import** read_image_bgr, preprocess_image, resize_image
**from** **keras_retinanet.utils.visualization** **import** draw_box, draw_caption
**from** **keras_retinanet.utils.colors** **import** label_color*# load image*
**def** evaluate_single_image(model, img_path):
    image = read_image_bgr(img_path) *# preprocess image for network*
    image = preprocess_image(image)
    image, scale = resize_image(image) *# process image*
    start = time.time()
    boxes, scores, labels = model.predict_on_batch(np.expand_dims(image, axis=0))
    print("processing time: ", time.time() - start) *# correct for image scale*
    boxes /= scale

    **return** (boxes[0], scores[0], labels[0])**def** visualize_detection(img_path, model_results):
    image = read_image_bgr(img_path)
    boxes, scores, labels = model_results *# visualize detections*
    draw = image.copy()
    draw = cv2.cvtColor(draw, cv2.COLOR_BGR2RGB) **for** box, score, label **in** zip(boxes, scores, labels):
        *# scores are sorted so we can break*
        **if** score < 0.5:
            **break** color = label_color(label)
        b = box.astype(int)
        draw_box(draw, b, color=color) caption = "**{}** **{:.3f}**".format(labels_to_names[label], score)
        draw_caption(draw, b, caption) plt.figure(figsize=(15, 15))
    plt.axis('off')
    plt.imshow(draw)
    plt.show()*# load retinanet model*
soda_model = models.load_model('models/retina_net_soda.h5', backbone_name='resnet50')
labels_to_names = {0: 'shelf1', 1: 'shelf2', 2: 'shelf3'}valid_example_path = 'dataset/Beverages/Test/Valid/IMG_4187.JPG'
detection_results = evaluate_single_image(soda_model, valid_example_path)
visualize_detection(valid_example_path, detection_results)
processing time:  10.065604209899902

挑战:你能想出我们可以用这些盒子来表明政策无效的方法吗?

用瓶子启发式预测

现在,我们有了一个用于寻找瓶子的对象检测模型,让我们开发一个启发式方法来确定货架是否正确存储,并在两个样本图像上测试它。

我们的试探法将按如下方式工作:

  • 我们将找到每个架类的最小 y1 和最大 y2 的用法
  • 我们将确认汽水架在果汁架之上,果汁架在水架之上
  • 对于每个最大值,我们将确保在它们之间没有其他类
**def** predict_bottles(model_results):
    bounds = {}
    beverages = {0: [], 1: [], 2: []}
    boxes, scores, labels = model_results **for** box, score, label **in** zip(boxes, scores, labels):
        *# scores are sorted so we can break*
        **if** score < 0.5:
            **break**
        beverages[label].append(box)

    *# Find the use the min y1 and max y2 of each of the tag classes*
    **for** bev **in** beverages:
        **if** len(beverages[bev]) == 0:
            **return** **False**
        y1 = min(beverages[bev], key=**lambda** b: b[1])[1]
        y2 = max(beverages[bev], key=**lambda** b: b[3])[3]
        bounds[bev] = {"y1":y1, "y2":y2} 
    *# Confirm that soda is above juice which is above water*
    **if** (bounds[0]["y1"] < bounds[1]["y1"]) **and** (bounds[1]["y1"] < bounds[2]["y1"]):
        *# For each of the max's we will ensure that there are no other clases that are in between them*
        **for** b **in** bounds.keys():
            **for** bev_type **in** (set(bounds.keys()) - set([b])):
                **for** bev **in** beverages[bev_type]:
                    **if** bev[1] > bounds[b]["y1"] **and** bev[3] < bounds[b]["y2"]:
                        **return** **False** 
        **return** **True**
    **else**:
        **return** **False**visualize_detection(valid_example_path, detection_results)
predict_bottles(detection_results)

Trueinvalid_example_path = 'dataset/Beverages/Test/Invalid/IMG_4202.JPG'
detection_results = evaluate_single_image(soda_model, invalid_example_path)
visualize_detection(invalid_example_path, detection_results)
predict_bottles(detection_results)
processing time:  8.053469896316528

False

基准瓶启发式

通常,为了将此应用于我们的整个数据集,我们将使用批处理,因为我们试图节省内存,我们将一次评估一个图像。

**from** **tqdm** **import** tqdm_notebook
**from** **utils** **import** classification_report
**from** **keras.preprocessing.image** **import** ImageDataGeneratory_pred = []
y_true = []print("Testing Invalid Cases")img_dir = 'dataset/Beverages/Test/Invalid/'
**for** img_path **in** tqdm_notebook(os.listdir(img_dir)):
    detection_results = evaluate_single_image(soda_model, os.path.join(img_dir, img_path))
    y_pred.append(predict_bottles(detection_results))
    y_true.append(**False**)print("Testing Valid Cases")
img_dir = 'dataset/Beverages/Test/Valid/'
**for** img_path **in** tqdm_notebook(os.listdir(img_dir)):
    detection_results = evaluate_single_image(soda_model, os.path.join(img_dir, img_path))
    y_pred.append(predict_bottles(detection_results))
    y_true.append(**True**)

分类报告

classification_report(y_true, y_pred)
precision    recall  f1-score   support False       1.00      1.00      1.00        30
        True       1.00      1.00      1.00        30 micro avg       1.00      1.00      1.00        60
   macro avg       1.00      1.00      1.00        60
weighted avg       1.00      1.00      1.00        60Confusion matrix, without normalization
[[30  0]
 [ 0 30]]
Normalized confusion matrix
[[1\. 0.]
 [0\. 1.]]

结论

我们可以看到,对于某些任务,使用具有良好启发性的对象检测可以优于定制视觉服务。然而,重要的是要考虑注释我们的数据和构建对象检测模型所需的权衡和工作。

资源

[## Pythic Coder 推荐的 Azure 机器学习入门内容

Tldr 由于 DevOps 资源上的帖子很受欢迎,而且很难找到文档,所以我…

medium.com](https://medium.com/microsoftazure/the-pythic-coders-recommended-content-for-getting-started-with-machine-learning-on-azure-fcd1c5a8dbb4) [## aribornstein —概述

@ pythiccoder。aribornstein 有 68 个存储库。在 GitHub 上关注他们的代码。

github.com](https://github.com/aribornstein) [## 认知服务|微软 Azure

微软 Azure Stack 是 Azure 的扩展——将云计算的灵活性和创新性带到您的…

azure.microsoft.com](https://azure.microsoft.com/en-us/services/cognitive-services/?v=18.44a) [## 物体探测系列

概观

medium.com](https://medium.com/@jonathan_hui/object-detection-series-24d03a12f904)

以前的帖子:

[## 在复杂图像分类场景中使用对象检测第 1 部分:

人工智能计算机视觉革命

towardsdatascience.com](/using-object-detection-for-complex-image-classification-scenarios-part-1-779c87d1eecb) [## 将对象检测用于复杂的图像分类场景第 2 部分:

定制视觉服务

towardsdatascience.com](/using-object-detection-for-complex-image-classification-scenarios-part-2-54a3a7c60a63) [## 将对象检测用于复杂的图像分类场景第 3 部分:

利用 MobileNet 和迁移学习进行策略识别

towardsdatascience.com](/using-object-detection-for-complex-image-classification-scenarios-part-3-770d3fc5e3f7)

下一篇文章

本系列的下一篇文章将回顾如何训练你自己的对象检测模型使用 Azure ML 服务的云,后续文章将讨论部署。

如果您有任何问题、评论或希望我讨论的话题,请随时在 Twitter 上关注我。如果您认为我错过了某个里程碑,请告诉我。

关于作者

亚伦(阿里) 是一个狂热的人工智能爱好者,对历史充满热情,致力于新技术和计算医学。作为微软云开发倡导团队的开源工程师,他与以色列高科技社区合作,用改变游戏规则的技术解决现实世界的问题,然后将这些技术记录在案、开源并与世界其他地方共享。

使用开源工具创建交互式政治调查地图

原文:https://towardsdatascience.com/using-open-source-tools-to-create-interactive-maps-of-political-surveys-f10ee0195984?source=collection_archive---------31-----------------------

设想英国地区对硬英国退出欧盟的支持

这个星期谁说了谁的坏话?谁将被投票淘汰出局?谁去勾搭这一季的人气先生?不,我们不是在谈论爱情岛或单身汉,而是另一个越来越受欢迎的真人秀节目:BBC 的议会频道。英国退出欧盟可能有点像一辆破车,但它确实提供了一些有趣的民意调查。

我们将使用今年 3 月的民意调查数据(以 SPSS 文件的形式)来查看对无交易英国退出欧盟的支持,并将结果显示为交互式地图。最终结果将如下图所示:

Support for a no-deal Brexit across regions shortly after Theresa May announced that she’d reached a deal with the EU.

轮询数据

为了读取 SPSS 文件并计算我们的结果,我们将使用开源软件库 Quantipy ,这是一个专门为处理调查数据而设计的库。我们以前写过 Jupyter 笔记本环境对于处理调查数据有多好,我们在这里再次使用它。

import quantipy as qp
dataset = qp.DataSet(“Political survey”)
dataset.read_spss(“results.sav”)

现在我们已经导入了数据集,让我们来看看我们想要可视化的问题,Deal_or_no_deal:

dataset.crosstab(“Deal_or_no_deal”, “Regions”, pct=True)

我们还清理空列(“Northern Ireland”和“Other”)的输出,并删除“All”列,以使结果更容易阅读。然后,我们将只提取结果数据行“不再向欧盟让步,必要时不达成协议就离开”,并给它一个漂亮的简短报告标签:“不达成协议”。

vote = dataset.crosstab(‘Deal_or_no_deal’, 
                        “Regions”, pct=True, f=filter)
vote = vote.droplevel(level=0,axis=1)
vote = vote.droplevel(level=0,axis=0)
vote = vote.drop([‘Other’,‘Northern Ireland’,“All”],axis=1)
vote.index.name = ‘No deal’
poll_result = vote.iloc[5,:]

这是我们的数据,但是在地图上看起来像什么呢?

使用 geopandas 通过 python 映射数据

为了绘制我们的结果,我们使用 geopandas python 库,这是一个非常强大但易于使用的库,它可以将地理空间数据转换为 pandas 数据框架。方便的是,有人已经在 GitHub 上收集了英国大部分主要的地理空间数据(这就是使用开源解决方案的好处,通常有人会为你做大部分艰苦的工作),我们使用 UK-geo JSON/JSON/electronic/GB/文件夹中的 eer.json 文件。将其保存到文件后,我们将其导入到 geopandas:

import geopandas
gdata = gpd.read_file(‘eer.json’)
gdaga.head()

请注意,这些区域存储在列“EER13NM”中。我们将这个数据框的结果与我们之前计算的数据合并。

gdata = gdata.join(poll_result, on=”EER13NM”)
gdata.plot(columns=”No more concessions to the EU, leave without a deal if necessary”)

现在我们有进展了。但是我们想知道不同性别和不同地区的投票结果有什么不同。所以我们给 DataSet.crosstab()方法发送了一个过滤器。

dataset.crosstab("Deal_or_no_deal", 
                 "Regions", pct=True,
                 f={"Gender":[1]})

交互式 Jupyter 小工具

接下来,我们需要一个交互式小部件,允许我们选择要查看的过滤器。我们使用 Jupyter 的 ipywidgets,它允许我们在笔记本中注入交互性。我们使用 dropdown 小部件,并使用 dataset.value_texts()和 dataset.codes()来填充它们。

gender = widgets.Dropdown(
   options=[(“All”, None)] + 
      list(zip(dataset.value_texts(‘Gender’), 
      dataset.codes(‘Gender’)))[:2],value=None,  
      description=’Gender:’,
      disabled=False
)age = widgets.Dropdown(
    options=[(“All”, None)] +    
    list(zip(dataset.value_texts(‘grouped_age’),
    dataset.codes(‘grouped_age’))),
    value=None,
    description=’Age:’,
    disabled=False
)

最后,将 Jupyter 的交互式 dropdown 小部件连接到我们的地图,这样我们就可以使用名为 interactive 的 ipywidgets 库的一部分来控制它所显示的内容(这是一种在笔记本中连接 Jupyter 前端和 python 后端的简单方法)。

interactive(update_map, gender=gender, age=age)

我们的 update_map 方法封装了过滤器的计算和地图的绘制。

def update_map(gender, age): filter = []
    if gender:
        filter.append( {‘Gender’: [gender]})
    if age:
        filter.append({‘grouped_age’: [age]}) vote_data = get_vote_data(filter).to_dict() map = gdata.join(get_vote_data(filter),
               on=”EER13NM”).plot(vmin=0, vmax=60,
               column=”No more consessions to the EU,
               leave without a deal if necessary”)

    out.clear_output()
    # out is a Jupyter Widget that captures output
    with out:
        display(map.figure)

为了简洁起见,我们省略了图的一些格式(改变颜色图、边框、图例格式)和一个我们调用的方法,以便用不同的过滤器检索数据。但我们现在已经准备好了,有了一张互动地图,可以显示不同地区的人们的观点是如何不同的。

现在你知道了,使用开源解决方案不仅可以计算公众对“不交易英国退出欧盟”意见的地区差异,还可以使这些差异对消费信息的人有意义。

盖尔·弗雷松是 Datasmoothie 的联合创始人,这是一个专门从事调查数据分析和可视化的平台。如果你对使用开源软件进行调查数据分析感兴趣,注册我们的时事通讯,名为自发认知

使用 OpenStreetMap 切片进行机器学习

原文:https://towardsdatascience.com/using-openstreetmap-tiles-for-machine-learning-4a3e41bb3ea6?source=collection_archive---------18-----------------------

使用卷积网络自动提取特征

Performance of the network when predicting the population of a given tile

OpenStreetMap 是一个不可思议的数据源。1000 名志愿者的集体努力创造了一套丰富的信息,几乎覆盖了地球上的每个地方。

在许多问题中,地图信息可能会有所帮助:

  • 城市规划,描述街区的特征
  • 研究土地使用、公共交通基础设施
  • 确定营销活动的合适地点
  • 识别犯罪和交通热点

然而,对于每个单独的问题,都需要进行大量的思考,以决定如何将用于制作地图的数据转换为对当前任务有用的要素。对于每项任务,您需要了解可用的功能,并编写代码从 OpenStreetMap 数据库中提取这些功能。

这种手动特征工程方法的替代方法是在渲染的地图块上使用卷积网络

如何使用卷积网络?

如果地图切片图像和响应变量之间存在足够强的关系,则卷积网络可能能够学习对每个问题都有帮助的地图切片的视觉组件。OpenStreetMap 的设计者已经做了大量的工作来确保地图渲染尽可能多地展示我们的视觉系统所能理解的信息。卷积网络已经被证明非常能够模仿视觉系统的性能,因此卷积网络可以学习从图像中提取哪些特征是可行的,这对于每个特定的问题领域来说都是耗时的编程工作。

检验假设

为了测试卷积网络是否可以从地图切片中学习有用的特征,我选择了简单的测试问题:估计给定地图切片的人口。美国人口普查提供了人口普查区域级别的人口数量数据,我们可以使用区域的人口来近似地图区块的人口

涉及的步骤:

  1. 人口普查局下载人口普查区域级别的人口数据。
  2. 对于给定的缩放级别,识别与一个或多个人口普查区域相交的 OpenStreetMap 切片。
  3. MapTiler 下载 OpenMapTiles 的本地实例中的图块。
  4. 对每个分块内的区域人口进行求和,并添加与分块相交的区域的分数人口

Visualizing the census tracts which overlap with the 3 example tiles

这给了我们:

  • 输入 X:OpenStreetMap 图块的 RGB 位图表示
  • 目标 Y :瓦片的估计人口

再重复一遍,网络用来预测人口的唯一信息是 OpenStreetMap 图块的 RGB 值

在这个实验中,我为加利福尼亚的瓦片和土地生成了一个数据集,但是同样的过程可以在美国的每个州进行。

模特培训和表演

通过使用简化的 Densenet 架构,并最小化对数标度的均方误差,网络在几个时期后实现了以下交叉验证性能:

0.45 的平方误差是对 0.85 的改进,如果你每次只是猜测平均人口,你会得到 0.85。这相当于每个瓦片的对数标度的平均绝对误差为 0.51。因此预测往往是正确的数量级,但是相差 3 倍(我们没有做任何事情来优化性能,所以这是一个不错的开始)。

摘要

  • 在估计人口的示例中,OpenStreetMap 切片中有足够的信息,显著优于人口的简单估计。
  • 对于信号足够强的问题,OpenStreetMap 切片可用作数据源,无需手动进行要素工程

学分:

  • 非常感谢所有支持 OpenStreetMap 的志愿者
  • 免费提供人口普查数据的美国政府
  • OpenMapTiles 为研究目的提供地图渲染服务

最初发布于shuggiefisher . github . io

使用 Panda 的“转换”和“应用”在组级别处理缺失数据

原文:https://towardsdatascience.com/using-pandas-transform-and-apply-to-deal-with-missing-data-on-a-group-level-cb6ccf060531?source=collection_archive---------1-----------------------

Image by Brett Hondow from Pixabay

了解当您不想简单地丢弃丢失的数据时应该怎么做。

根据 Businessbroadway 进行的一项分析,数据专业人员花费高达 60%的时间来收集、清理数据和可视化数据。

Source: Businessbroadway

清理和可视化数据的一个关键方面是如何处理丢失的数据。 Pandas 以 **fillna** 方法的形式提供了一些基本功能。虽然fillna在最简单的情况下工作得很好,但是一旦数据中的组或数据的顺序变得相关时,它就不够用了。本文将讨论解决这些更复杂情况的技术。

这些案例通常是由不同制度(时间序列)、组甚至子组组成的数据集。不同情况的例子有几个月、几个季度(一般时间范围)或一段暴雨期。数据中的组的一个例子是性别。亚组的例子有年龄组和种族。

本文旨在作为一篇代码文章。因此,请随意启动笔记本电脑,开始工作。

文章的结构:

  1. 熊猫的 fillna
  2. 当订单不相关时,处理缺失数据
  3. 当订单相关时,处理缺失数据

熊猫概述fillna

Image by skeeze from Pixabay

Pandas 通过调用fillna()有三种处理丢失数据的模式:

  • **method='ffill':** Ffill 或 forward-fill 将最后一个观察到的非空值向前传播,直到遇到另一个非空值
  • **method='bfill':** Bfill 或 backward-fill 将第一个观察到的非空值向后传播,直到遇到另一个非空值
  • **explicit value:** 也可以设置一个精确值来替换所有缺失。例如,这种替换可以是-999,表示缺少该值。

例如:

**IN:** demo = pd.Series(range(6))
demo.loc[2:4] = np.nan
demo**OUT:** 0    0.0
1    1.0
*2    NaN
3    NaN
4    NaN*
5    5.0
dtype: float64**# Forward-Fill
IN:** demo.fillna(method='ffill')**OUT:** 0    0.0
1    1.0
*2    1.0
3    1.0
4    1.0*
5    5.0
dtype: float64**# Backward-Fill**
**IN:** demo.fillna(method='bfill')**OUT:** 0    0.0
1    1.0
*2    5.0
3    5.0
4    5.0*
5    5.0
dtype: float64**# Explicit value**
**IN:** demo.fillna(-999)**OUT:** 0      0.0
1      1.0
*2   -999.0
3   -999.0
4   -999.0*
5      5.0
dtype: float64

当订单不相关时,处理缺失数据

Image by PublicDomainPictures from Pixabay

通常,在处理缺失数据时,排序并不重要,因此,用于替换缺失值的值可以基于全部可用数据。在这种情况下,您通常会用自己的最佳猜测(即,可用数据的平均值或中间值)替换缺失值

让我们快速回顾一下为什么应该小心使用这个选项。让我们假设你调查了 1000 个男孩和 1000 个女孩的体重。不幸的是,在收集数据的过程中,一些数据丢失了。

**# imports**
import numpy as np**# sample 1000 boys and 1000 girls**
boys = np.random.normal(70,5,1000)
girls = np.random.normal(50,3,1000)**# unfortunately, the intern running the survey on the girls got distracted and lost 100 samples** for i in range(100):
    girls[np.random.randint(0,1000)] = np.nan**# build DataFrame**
boys = pd.DataFrame(boys, columns=['weight'])
boys['gender'] = 'boy'girls = pd.DataFrame(girls, columns=['weight'])
girls['gender'] = 'girl'df = pd.concat([girls,boys],axis=0)
df['weight'] = df['weight'].astype(float)

一个分组

不用多想,我们可能会用整个样本的平均值来填充缺失值。不过,结果看起来有些奇怪。女孩的 KDE 有两个驼峰。有人可能会得出结论,在我们的样本中有一个较重的女孩子群。因为我们预先构建了发行版,所以我们知道情况并非如此。但是如果这是真实的数据,我们可能会从这些数据中得出错误的结论。

KDE of weights for boys and girls where we replaced missing data with the sample mean (code below the chart)

**# PLOT CODE:**
sns.set_style('white')
fig, ax = plt.subplots(figsize=(16, 7))**mean = df['weight'].mean()**sns.distplot(
 **df[df['gender'] == 'girl']['weight'].fillna(mean),**
    kde=True,
    hist=False,
    ax=ax,
    label='girls'
)sns.distplot(
    df[df['gender'] == 'boy']['weight'],
    kde=True,
    hist=False,
    ax=ax,
    label='boys'
)plt.title('Kernel density estimation of weight for boys and girls')sns.despine()

用组的平均值填充缺失值

在这种情况下,Panda 的转换功能就派上了用场。使用 transform 提供了一种在组级别解决问题的便捷方法,如下所示:

df['filled_weight'] = df.groupby('gender')['weight'].transform(
    lambda grp: grp.fillna(np.mean(grp))
)

运行上述命令并绘制filled_weight值的 KDE,结果如下:

KDE of weights for boys and girls where we replaced missing values with the group mean (code below the chart)

**# PLOT CODE:**
sns.set_style('white')
fig, ax = plt.subplots(figsize=(16, 7))sns.distplot(
    df[df['gender'] == 'girl']['filled_weight'],
    kde=True,
    hist=False,
    ax=ax,
    label='girls')
sns.distplot(
    df[df['gender'] == 'boy']['filled_weight'],
    kde=True,
    hist=False,
    ax=ax,
    label='boys'
)plt.title('Kernel density estimation of weight for boys and girls')sns.despine()

多个子组

让我们使用前面的例子,但这一次,我们走得更远一点,另外将我们的数据分成年龄组。让我们创建一些模拟数据:

**# paramter for the weight distribution (mean, std)**
param_map = {
    'boy':{
        '<10':(40,4),
        '<20':(60,4),
        '20+':(70,5),
    },
    'girl':{
        '<10':(30,2),
        '<20':(40,3),
        '20+':(50,3),
    }
}**# generate 10k records**
df = pd.DataFrame({
    'gender':np.random.choice(['girl','boy'],10000),
    'age_cohort':np.random.choice(['<10','<20','20+'],10000)
})**# set random weight based on parameters**
df['weight'] = df.apply(
    lambda x: np.random.normal(
        loc=param_map[x['gender']][x['age_cohort']][0],
        scale=param_map[x['gender']][x['age_cohort']][1]
    ),axis=1
)**# set 500 values missing**
for i in range(500):
    df.loc[np.random.randint(0,len(df)),'weight'] = np.nan

绘制数据揭示了有点奇怪的双峰分布(代码如下)。

KDE of weight by age_cohort and gender were we replaced missing values with the sample mean

**# PLOT CODE**
df['filled_weight'] = df['weight'].fillna(
    df['weight'].mean()
)g = sns.FacetGrid(
    df,
    col='age_cohort',
    row='gender',
    col_order=['<10','<20','20+']
)g.map(sns.kdeplot,'filled_weight')

现在,如果我们只是用各自性别的平均值来代替缺失值,这还不够,因为不仅男孩和女孩的体重不同,而且不同年龄组的体重也有很大差异。

幸运的是,transform可以像以前一样应用。我们将在两列上分组,而不是像这样只在一列上分组:

df['filled_weight'] = df.groupby(['gender','age_cohort'])['weight'].transform(
    lambda grp: grp.fillna(np.mean(grp))
)

运行上面的代码片段将生成这个更加清晰的图:

KDE of weight by age_cohort and gender were we replaced missing values with each group’s mean

当订单相关时,处理缺失数据

Photo by Jake Hills on Unsplash

在处理时序数据时,经常会出现两种情况。

  1. 调整日期范围:假设你按年查看各国的 GDP、教育水平和人口增长。对一些国家来说,你错过了最初的几年,后来的几年,或者中间的几年。当然,你可以忽略它们。尽管如此,出于可视化的目的,您可能希望保留它们,并将您的第一个观察值投影到开始,将您的最后一个观察值投影到调查期结束,并得出对中间值有意义的东西。
  2. 插值:查看时间序列数据插值,从而排序变得非常相关。用基于截至 2019 年的数据计算出的平均值替换 2012 年缺失的股票数据,肯定会产生一些古怪的结果。

我们将根据 2019 年世界幸福报告的数据来看一个例子,我们解决了这两种情况。《世界幸福报告》试图回答哪些因素影响着全世界的幸福。该报告调查了 2005 年至 2018 年的数据。

加载数据

**# Load the data**
df = pd.read_csv('[https://raw.githubusercontent.com/FBosler/you-datascientist/master/happiness_with_continent.csv'](https://raw.githubusercontent.com/FBosler/you-datascientist/master/happiness_with_continent.csv'))

样品检验

df.sample(5)df.head(5)相反,选择五个随机行,从而给你一个更公正的数据视图。

Data sample from the downloaded DataFrame

让我们来看看每年我们有数据的国家的数量。

Number of countries we have data for per year

**# PLOT CODE:**
df.groupby(['Year']).size().plot(
    kind='bar',
    title='Number of countries with data',
    figsize=(10,5)
)

我们可以看到,特别是前几年,我们没有很多国家的数据,而且在整个样本期间也有一些波动。为了减轻丢失数据的影响,我们将执行以下操作:

  1. 按国家分组并重新索引整个日期范围
  2. 根据我们对每个国家的观察结果,对之间的年份进行插值,并对范围之外的年份进行外推

1.按国家和重新索引日期范围分组

**# Define helper function**
def add_missing_years(grp):
    _ = grp.set_index('Year')
    _ = _.reindex(list(range(2005,2019)))
    del _['Country name']
    return _**# Group by country name and extend**
df = df.groupby('Country name').apply(add_missing_years)
df = df.reset_index()

我们现在大约有 600 多行。然而,那些观察现在都是null

Extended DataFrame, where every country has rows for every year between 2005 and 2018

2.根据我们对每个国家的观察结果,对之间的年份进行插值,并对范围之外的年份进行外推

**# Define helper function**
def fill_missing(grp):
    res = grp.set_index('Year')\
    .interpolate(method='linear',limit=5)\
    .fillna(method='ffill')\
    .fillna(method='bfill')
    del res['Country name']
    return res**# Group by country name and fill missing**
df = df.groupby(['Country name']).apply(
    lambda grp: fill_missing(grp)
)df = df.reset_index()

fill_missing函数向终点和起点进行插值和外推,结果是:

完美!现在我们有了样本中所有国家从 2005 年到 2018 年的数据。当我写这篇关于可视化的文章时,上面的方法对我来说很有意义。如果你想了解更多关于幸福报告的信息,可以去看看。

[## 了解如何使用 Python 创建漂亮而有洞察力的图表——快速、漂亮和…

数据显示,金钱可以买到幸福。用 Python 可视化的综合代码指南,解释了…

towardsdatascience.com](/plotting-with-python-c2561b8c0f1f)

总结和结束语

今天到此为止。在本文中,您学习了如何使用transformapply用比之前或之后的值更有意义的值来替换丢失的值。

如果你发现了一些奇妙的新的可视化效果,想要提供反馈或进行聊天,请在 LinkedIn 上联系我。

如果你喜欢你所读的,看看我在 Medium 上写的其他文章。

使用 Python 和 Robinhood 创建一个简单的低买高卖交易机器人

原文:https://towardsdatascience.com/using-python-and-robinhood-to-create-a-simple-buy-low-sell-high-trading-bot-13f94fe93960?source=collection_archive---------6-----------------------

Photo by Ishant Mishra on Unsplash

所以我最近一直在折腾 Robinhood,一直在努力理解股票。我不是金融顾问或其他什么人,但我想创建一个简单的交易机器人,这样我就可以在创建更复杂的代码之前多理解一点。对于那些还没有查看的人,我创建了一篇关于如何使用 Python 连接 Robinhood 数据的文章。

[## 使用 Python 获取罗宾汉数据

让我们自动化一些股票,可以用来建造一个交易机器人。

towardsdatascience.com](/using-python-to-get-robinhood-data-2c95c6e4edc8)

我做的第一件事就是把我所有的股票都存到一个数据框里。我不喜欢如何布局的数据帧和我的需要转置它会使我的机器人更简单。然后将索引移动到滚动条列中。我还将某些列切换为 floats,因为它们当前被表示为一个字符串。代码在下面,输出的数据帧也在下面。

所以我创造了低买高卖。我只想玩玩average_buy_price中低于 25 美元的股票,并给自己设定每只股票限购 5 只。然后我把它分成两个独立的数据框架,一个是买入,一个是卖出。

对于买入,如果percent_change跌破. 50%,那么只有当股票数量为 1 时才会触发买入。然后,它以市场价格购买 4 只股票。

对于 sell 来说,基本上是相反的。如果percent_change上涨超过 0.50%,数量为 5,触发卖出。这是我的代码,需要一些清理,但我只是测试出来。我将滚动条移动到一个列表中,然后使用robin_stocks来执行命令。

我通常只在工作日开市时运行一次。到目前为止,我已经取得了几美分的正回报。它不多,但它可以发展成更好的东西。

将来,一旦我做了更多的研究,我会计划增加更复杂的交易策略。股票对我来说是相当新的,所以请不要把这当成财务建议。我不对你的任何输赢负责。但希望这能激发一些想法。

在这里进入代码。

别忘了在 LinkedIn 上联系我。

使用 Python 和 Selenium 实现鼠标点击和表单填写的自动化

原文:https://towardsdatascience.com/using-python-and-selenium-to-automate-filling-forms-and-mouse-clicks-f87c74ed5c0f?source=collection_archive---------2-----------------------

对于这个例子,我们将通过 Instagram 的网站应用程序登录。

实际上,我在日常工作流程中使用 Python 和 Selenium。在我工作的公司,我们有自己的网络应用程序,可以在线发送报告。每份报告都有一个账户。

由于我们每天都有客户加入,我们还需要创建新的帐户。随着我们雇佣更多销售团队成员,客户数量呈指数级增长。创建新账户是一个非常手工的过程,看一份报告,然后输入信息。这是我发现硒的地方。

是一款针对网页浏览器的自动化工具。除了 Python 之外,您还可以将它用于许多不同的编程语言。他们也有一个版本,你可以记录你使用浏览器的过程,他们能够模仿他们。

如果你有任何容易重复的任务,这是非常有用的。例如,在我的工作中,我从客户成功团队那里获得了一份新客户列表。在该文件中,它有帐户名、帐户 ID 和地址。我必须为每个新账户手工输入。硒可以解决这个问题。

让我们从简单的东西开始,自动登录 Instagram。登录任何网站基本上都是我们发送的一个小表格。我们将填写凭证的“表格”,然后单击提交按钮。

要求: 1。Python w/ selenium 模块
2。chrome driver(selenium 使用的特殊谷歌 chrome)

首先要做的是下载并在必要时安装需求。假设你已经安装了 Python,你可以在模块上做一个pip install。我们需要的 chromedriver 可以在这里找到。

我们现在可以创建一个新的 Python 文件。让我们从我们的进口开始。

from selenium import webdriver

因为我们使用 chromedriver 作为应用程序。我们需要告诉 Python 它的位置。我刚刚下载了它,并把它放在我的下载文件夹中。我可以用它的路径设定它的位置。

chromedriver_location = "/Users/Downloads/chromedriver"

一旦我们知道了 chromedriver 的位置,我们现在就可以使用 Selenium 的 webdriver 调用它,告诉它去 Instagram 主页。

driver = webdriver.Chrome(chromedriver_location)
driver.get(‘https://www.instagram.com/')

我们现在可以试着运行这个脚本,看看会得到什么。如果设置正确,将会弹出一个新的 Google Chrome 实例,并把你带到所请求的站点。

让我们回到我们的代码,假设我们已经有了 Instagram 凭证。我们想告诉 Selenium 点击蓝色的链接中的日志:

Selenium 通过在 web 页面中查找元素来简化自动化。有多种方法可以找到 web 元素,比如 id、类名、文本等等。在这种情况下,我们将使用 Selenium webdriver 的find_element_by_xpath

回到谷歌浏览器窗口,右键点击蓝色的登录链接。你想点击 inspect,应该会弹出一个窗口,显示所有的 web 元素和一个高亮显示的行。您现在想要点击高亮显示的行并复制 xpath。

一旦完成,你应该有这样的东西,当你粘贴下来。

//*[[@id](http://twitter.com/id)=”react-root”]/section/main/article/div[2]/div[2]/p/a

同样,用户名、密码和登录按钮的输入字段也是同样的过程。

我们可以在当前页面上继续操作。我们可以将这些 xpaths 作为字符串存储在代码中,以使其可读。

我们应该有三个来自这个页面的 xpaths 和一个来自初始登录的 xpaths。

first_login = '//*[[@id](http://twitter.com/id)=”react-root”]/section/main/article/div[2]/div[2]/p/a'username_input = '//*[[@id](http://twitter.com/id)="react-root"]/section/main/div/article/div/div[1]/div/form/div[2]/div/label/input'password_input = '//*[[@id](http://twitter.com/id)="react-root"]/section/main/div/article/div/div[1]/div/form/div[3]/div/label/input'login_submit = '//*[[@id](http://twitter.com/id)="react-root"]/section/main/div/article/div/div[1]/div/form/div[4]/button/div'

既然我们已经定义了 xpaths,现在我们可以告诉 Selenium webdriver 单击并发送一些输入字段的键!

让我们再次从第一次登录开始。我们使用find_element_by_xpath,并给它一个first_login变量。然后我们可以告诉它点击。

driver.find_element_by_xpath(first_login).click()

现在,它会将您带到带有输入字段的凭证页面。类似的过程,但现在我们希望 Selenium 用我们的用户名和密码填充这些字段。Selenium 有另一个叫做send_keys的方法,它让我们可以很容易地自动化打字。我们只要放一个字符串进去,它就会为我们打字。我们现在可以尝试虚拟变量,看看它是否有效。此外,尝试登录,知道我们会被拒绝。

driver.find_element_by_xpath(username_input).send_keys(“username”)
driver.find_element_by_xpath(password_input).send_keys(“password”)
driver.find_element_by_xpath(login_submit).click()

如果一切设置正确,我们的最终代码应该如下所示:

from selenium import webdriverchromedriver = "/Users/Downloads/chromedriver"driver = webdriver.Chrome(chromedriver)driver.get('https://www.instagram.com/')first_login = '//*[@id="react-root"]/section/main/article/div[2]/div[2]/p/a'username_input = '//*[@id="react-root"]/section/main/div/article/div/div[1]/div/form/div[2]/div/label/input'password_input = '//*[@id="react-root"]/section/main/div/article/div/div[1]/div/form/div[3]/div/label/input'login_submit = '//*[@id="react-root"]/section/main/div/article/div/div[1]/div/form/div[4]/button/div'driver.find_element_by_xpath(first_login).click()driver.find_element_by_xpath(username_input).send_keys("username")driver.find_element_by_xpath(password_input).send_keys("password")driver.find_element_by_xpath(login_submit).click()

我们现在可以运行这个脚本,并在浏览器中看到自动化。这个特定的脚本将工作,但从 Instagram 得到一个错误,因为我们没有适当的凭据。继续使用您自己的信息更改send_keys周围的用户名和密码字符串,它应该会让您成功登录。

正如你所看到的,这只是一个简单的例子,不同的人有不同的情况。可能性是无限的。

我还提供 家教和 职业指导在这里

如果你喜欢这些内容,请随时在 Patreon 上支持我!

如果你们有任何问题、意见或担忧,请不要忘记通过 LinkedIn 与我联系!

使用 Python 创建一个 Slack Bot

原文:https://towardsdatascience.com/using-python-to-create-a-slack-bot-fdc2c335915d?source=collection_archive---------21-----------------------

Photo by Lenin Estrada on Unsplash

在一家初创公司工作时,我们需要自动处理消息,以便获得某些事件和触发的通知。例如,我工作的公司处理与某些商店的联系。如果连接中断,Python 将读取我们数据库中的信息。我们现在可以将该数据发送到一个 Slack 通道,专门用于重新连接该存储。

我们可以为这个 Slack Bot 创造许多可能性,我的同事创造的另一个例子是将 Python 错误消息输出到通道。不仅创建通知,还创建持续的错误日志。

我们现在可以做些简单的事情。对于这个项目,我们将构建一个 Slack Bot,如果它检测到脚本运行的日期是美国假日,它将输出一条消息。

这个项目需要什么:
1。 Python
2。松弛工作空间/帐户

所需 Python 模块:
1。 datetime (告知脚本运行的日期并标准化日期时间)
2。 熊猫 (主要用于将数据组织成 dataframe)
3 . 请求 (连接到我们从网站获取的数据,并将数据发送到 slack API)
4 . bs4 (我们正在从网站获取的数据的数据解析)
5。 json (对数据进行编码,以便 slack API 可以使用)

首先,让我们创建一个新的 Python 文件并导入所需的模块。

from datetime import date, datetime, timedelta
import pandas as pd
import requestsfrom bs4 
import BeautifulSoup
import json

我们可以使用datetime模块获取今天的日期时间,并将其存储为年-月-日这样的字符串格式。

today = datetime.now().strftime(‘%Y-%m-%d’)
#today = '2019-10-29'

使用模块requests,我们现在可以连接到我们想要获取数据的网站。为此,我连接到这个 网站 获取假期。当我们从一个网站获取数据时,它会发送我们在该页面上看到的所有内容。我们只想要这个数据中的假期。这就是 BeautifulSoup 发挥作用的地方,使用模块bs4我们可以很容易地解析这些数据。我们现在可以把它放到一个数据框架中。

这不是将数据传输到数据帧的最佳方式,但我们只需要完成这项工作。

regionalHolidaysList = []
for result in results:    
     date = result.contents[0].text + ', ' + datetime.today().strftime('%Y')    
     weekday = result.contents[1].text    
     holidayName = result.contents[2].text    
     observance = result.contents[3].text     
     stateObserved = result.contents[4].text
     regionalHolidaysList.append((date, weekday, holidayName, observance, stateObserved))regionalHolidayDf = pd.DataFrame(regionalHolidaysList, columns = ['date', 'weekday', 'holidayName', 'observance', 'stateObserved'])regionalHolidayDf['date'] = regionalHolidayDf['date'].apply(lambda x: (datetime.strptime(x, '%b %d, %Y').strftime('%Y-%m-%d')))

我们现在可以从这个数据帧创建一个日期时间列表

dateList = regionalHolidayDf['date'].tolist()

如果today在这个dateList中,我们可以告诉它打印到请求的空闲通道。为了让 Python 使用 Slack 发送东西,我们需要创建一个传入的 webhook。Slack 有一些关于如何做到这一点的文档,在 https://api.slack.com/messaging/webhooks。

如果一切都做得正确,那么我们应该有这样的东西:

https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

最后一部分变得有点复杂,所以我将在代码中用标签来发布我的评论。

#So we get the date if it is in this list it will send a message in slackif today in dateList:
     todayHoliday = regionalHolidayDf[regionalHolidayDf['date'] ==          today]    
     info=[]    
     for holiday in todayHoliday.itertuples():
          info.append(':umbrella_on_ground:' +                       holiday.holidayName +  ' in ' +                      holiday.stateObserved.replace('*', ''))    
     if len(info) >1:        
          infoFinal = '\n'.join(info)    
     else:        
       infoFinal = info[0]#Here is where we can format the slack message, it will output any holiday with todays

     message = f'@here Fun fact! \n Today({today}) is: \n {infoFinal}'        
     print('Sending message to the happyholiday channel...')
     slackmsg = {'text': message} #Using the module json it formats it where the slack API can accept it
#we can store the slack link into a variable called webhook webhook='https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
response = requests.post(webhook,  data=json.dumps(slackmsg), headers={'Content-Type': 'application/json'})    
     if response.status_code != 200:        
          raise ValueError('Request to slack returned an error %s, the response is:\n%s'            % (response.status_code, response.text)        )    
     print('Request completed!')
else:    
     print('No regional holiday today! See you next time!')

现在我们终于可以运行这个脚本了,如果成功,它将根据脚本运行的日期输出一个假日。

为了进一步自动化,我们可以将它放在 EC2 上,让它每天运行!但这需要更多的证书和设置,让我知道如果这是另一个话题,你们有兴趣!

访问我的代码这里

我在这里也有家教和职业指导。

如果你们有任何问题、评论或顾虑,请不要忘记通过 LinkedIn与我联系!

使用 Python 获取罗宾汉数据

原文:https://towardsdatascience.com/using-python-to-get-robinhood-data-2c95c6e4edc8?source=collection_archive---------6-----------------------

Photo by Ray Hennessy on Unsplash

让我们自动化一些股票,可以用来建造一个交易机器人。

所以我已经和罗宾汉纠缠了几个月了。谈到股票或交易,我不是专家。但我认为用 Python 连接到我的 Robinhood 帐户会很酷。

在网上看了之后,我偶然发现了一个叫做robin_stocks.的 Python 模块,所以这个模块非常方便,它可以做你在网站上可以做的任何事情。所以如果你想下订单,这是给你的。或者如果你想卖这个也是给你的。它还可以为您检索历史数据。

让我们开始假设你已经知道 Python 是如何工作的,我只做一个pip install robin_stocks

我做的第一行代码是导入,我还导入了pandas来把它放入一个数据帧,并导入了matplotlib.pyplot来绘制它。导入之后,我们现在需要登录 Robinhood。只需在正确的字段中替换您的用户名和密码。

当我们运行脚本时,它应该要求一个代码,通常发送到您的手机号码。输入,你现在应该连接上了。我们现在可以使用build_holdings()获得所有的股票信息。当我们打印出my_stocks时,它看起来会像这样:

对于我个人的使用,我想把它放入一个数据框中。我尝试了df = pd.DataFrame(my_stocks),但是结果是股票代码被作为索引读取,数据旋转不符合我的喜好。所以我多加了一点代码。

对不起,我的股票我不确定我在买卖什么,但是数据框架应该是这样的:

我们还可以获得某些股票的历史数据,对于这个例子,我将获得特斯拉的周数据并绘制它。代码、数据帧和绘图如下所示:

正如你可以告诉我还没有探索这个模块的能力。此外,我对股票市场有点缺乏经验,还没有玩过。但希望这能延伸到更有知识的人,这样他们就可以在日常生活中使用它。非常有可能建立自己的机器人投资者!

访问我的代码这里

我在这里也可以得到辅导和职业指导!

如果你们有任何问题、评论或顾虑,请不要忘记通过 LinkedIn与我联系!

如何使用 Python 获取 SalesForce 数据

原文:https://towardsdatascience.com/using-python-to-get-salesforce-data-97bb5a7ef2cf?source=collection_archive---------3-----------------------

Photo by Denys Nevozhai on Unsplash

我在一家大量使用 SalesForce 的初创公司工作。

当我第一次开始时,我们必须通过 Salesforce 网站登录。转到“报告”选项卡,创建一个包含必要字段的报告。下载逗号分隔值电子表格。在这里和那里做一些数据清理。主要是过滤字段,看看有没有空值或细微差别。再次导出 CSV,并在 Excel 中做一个 Vlookup,看看我们有什么数据。

我心想,一定有一种更简单的方法,我只需运行一个 Python 脚本就可以完成这项工作。做了一些谷歌搜索,发现了[simple_salesforce](https://github.com/simple-salesforce/simple-salesforce/blob/master/README.rst)

来自他们的网站 — Simple Salesforce 是一个为 Python 2.6、2.7、3.3、3.4、3.5 和 3.6 构建的基本 Salesforce.com REST API 客户端。目标是为 REST 资源和 APEX API 提供一个非常底层的接口,返回 API JSON 响应的字典。

使用 Python 拉 Salesforce 数据需要的东西:
1。Python 模块simple _ sales force
2。具有 API 访问权限的 SalesForce 凭据

假设你已经掌握了 Python 的基本知识,那么继续在你的机器上安装simple_salesforce

pip install simple_salesforce

完成后,我们可以继续创建我们的 Python 文件,并进行必要的导入。我们还需要我们的 SalesForce 凭据。如果不能联系您的 SalesForce 开发人员,帐户必须具有 API 访问权限。

from simple_salesforce import Salesforcesf = Salesforce(
username='myemail@example.com', 
password='password', 
security_token='token')

如果您还没有 SalesForce 安全令牌,请登录到 SalesForce 网站。导航到设置。然后到我的个人信息,在那个下拉菜单下应该重置我的安全令牌。这将以带有字母数字代码的电子邮件形式发送给您。

使用 SOQL 查询 SalesForce 数据

我们现在可以使用 Python 登录到 SalesForce。为了查询数据,simple_salesforce有一个叫做query_all的方法,这使得获取数据变得非常容易。SalesForce 有自己的方式来编写查询,称为 SalesForce 对象查询语言。

以下是使用 Python 和自定义字段进行查询的示例:

"SELECT Owner.Name, store_id__c, account_number__c, username__c, password__c, program_status__c, FROM Account WHERE program_status__c IN ('Live','Test')"

我们现在可以将这个 SOQL 代码插入到方法中,并将其提取到一个变量中:

sf_data = sf.query_all("SELECT Owner.Name, store_id__c, account_number__c, username__c, password__c, program_status__c, FROM Account WHERE program_status__c IN ('Live','Test')")

输出将是 JSON 格式,但是我们可以使用[pandas](https://pandas.pydata.org/pandas-docs/stable/index.html)很容易地将其转换成数据帧。JSON 返回了一些我认为不必要的属性,所以我放弃了它们。

sf_df = pd.DataFrame(sf_data['records']).drop(columns='attributes')

我们现在有了一个数据框架,可以进行数据分析和数据清理。

访问我的代码这里

我在这里也有家教和职业指导

如果你们有任何问题、评论或担忧,别忘了在 LinkedIn 上联系我!

使用 Python 将您的熊猫数据框推送到 Google Sheets

原文:https://towardsdatascience.com/using-python-to-push-your-pandas-dataframe-to-google-sheets-de69422508f?source=collection_archive---------4-----------------------

Photo by Christian Kielberg on Unsplash

这也可以作为像使用数据库一样使用 Google Sheets 的简单方法。

假设您已经安装了最新版本的 Python。为此需要的 Python 模块有:

  1. pandas(获取和读取数据)
  2. gspread(连接到谷歌工作表)
  3. df2gspread(与谷歌工作表互动)

仔细安装这些模块后,我们现在可以创建一个 Python 文件,并开始导入。

import pandas as pd
import gspread
import df2gspread as d2g

现在我们需要任何类型的数据,我们可以从 CSV 或其他来源获取。利用熊猫,我们可以把它组织成一个数据框架。任何类型的数据框架都可以。如果你还没有,让我们用熊猫做一个。

d = {'col1': [1, 2], 'col2': [3, 4]}
df = pd.DataFrame(data=d)

现在棘手的部分,获得凭证访问。为了使用 Python,我们需要从 Google 获得某种形式的 密钥 。这个 主要是出于安全目的,将采用 JSON 文件的格式。

让我们登录我们希望使用的谷歌账户,并按照这里的说明进行操作。如果一切顺利,JSON 文件应该看起来像这样:

{
    "private_key_id": "2cd … ba4",
    "private_key": "-----BEGIN PRIVATE KEY-----**\n**NrDyLw … jINQh/9**\n**-----END PRIVATE KEY-----**\n**",
    "client_email": "473000000000-yoursisdifferent@developer.gserviceaccount.com",
    "client_id": "473 … hd.apps.googleusercontent.com",
    "type": "service_account"
}

这个 JSON 文件需要与 Python 脚本在同一个文件夹中。对于这个例子,我将其命名为jsonFileFromGoogle.json。我们可以在代码中调用 JSON 文件,并将其设置为连接的凭证。我们还可以设置范围,我们希望凭证被发送到哪里以便进行连接。

scope = ['[https://spreadsheets.google.com/feeds'](https://spreadsheets.google.com/feeds'),
         '[https://www.googleapis.com/auth/drive'](https://www.googleapis.com/auth/drive')]credentials = ServiceAccountCredentials.from_json_keyfile_name(
    'jsonFileFromGoogle.json', scope)gc = gspread.authorize(credentials)

您现在应该能够以这种方式连接到 Google。是时候把数据帧发送到谷歌电子表格了。对于我的目的,我发现创建一个新的工作表并获取电子表格键更容易。电子表格密钥可以在这里用红色标记的 URL 中找到。

复制它,并将其设置为一个名为spreadsheet_key的变量。如果您的工作表有多个工作表,也要设置工作表名称。我在我的代码里设置为wks_name,默认情况下会叫“Master”。

spreadsheet_key = 'red_url_code_goes_here'
wks_name = 'Master'
d2g.upload(df, spreadsheet_key, wks_name, credentials=credentials, row_names=True)

现在,当您最终运行这个脚本时,您设置的 DataFrame 将把它上传到 Google Sheets。这有许多其他的可能性,但是你可以用它作为一个更新的小数据库,你可以和你的同伴分享。

我在这里也有家教和职业指导!

如果你喜欢这些内容,请随时在 Patreon 上支持我!

如果你们有任何问题、意见或担忧,请不要忘记通过 LinkedIn 与我联系!

使用 PyTorch 生成疟疾感染细胞的图像

原文:https://towardsdatascience.com/using-pytorch-to-generate-images-of-malaria-infected-cells-c2b4de260b23?source=collection_archive---------16-----------------------

不同的自动编码器和不同的初始化方案

在我寻求掌握机器学习和深度学习(为了做出令人兴奋的生物学发现)的过程中,我将变分自动编码器(VAEs)作为我清单上的下一个目标。看似简单,VAE 包括一个编码器,一个解码器和一个适当的损失函数。然而 VAEs 创造性应用的例子比比皆是,包括生成图像音乐蛋白质部分。我们马上就会看到为什么他们在这些事情上如此受欢迎!出于某种原因,人们似乎喜欢用 VAEs 生成数字为和面部为的图像,所以我想尝试一些不同的东西。在寻找了一段时间后,我在 Kaggle 上发现了一个关于人类血细胞(健康的以及被疟疾病原体感染的恶性疟原虫)的数据集(顺便说一下,对数据集来说很棒)。由于这两个类别都包含了大约 14000 张图片,这并不算太差,所以我决定继续这样做,为这两个类别建立 VAEs 来生成健康的受感染细胞的图片。那有用吗?我不知道(可能不是太多),但这是一个很好的学习经历,看起来肯定很愉快!

Examples of input images (not particularly pretty but hey you take what you can get, right?). Upper row are three healthy blood cells, lower row are three blood cells infected by the malaria pathogen P. falciparum (easily seen through the purple spots).

但是在我们沉浸在深度学习的乐趣中之前,先了解一些背景知识。VAEs 对大部件的标称任务在于预测它们的输入,称为重构。虽然这听起来可能微不足道,但是所有的自动编码器、vae 都有一个瓶颈结构。体系结构边缘的层比中间的层有更多的节点。因此,宽编码器通向最窄的瓶颈层,相应的解码器从那里开始,将输入恢复到原始尺寸。这阻止了 VAE 简单地将身份转换应用于其输入并完成它。

Structure of a standard autoencoder. Variational autoencoders replace the ‘z’ layer with vectors of means and variances to create sampling distributions. Source

因此,网络必须学习图像的基本特征,以便重新创建它。瓶颈层所必需的这种受限表示是自动编码器通常用于去噪的主要原因。由于只有图像的真实特征才会出现在潜在特征中,因此在重建时会去除噪声。通过比较原始图像和重建图像并最小化它们的差异(理解为:最小化重建误差,例如可以是均方误差),我们已经有了损失函数。或者说,对于普通的自动编码器来说,我们已经做到了。

然而,可变自动编码器也有一个生成组件。实际上,它们可以让你得到输入图像的调整变体,而不是陈腐的复制,这就是为什么它们在音乐或视觉艺术等创意领域如此受欢迎。架构的不同之处在于,VAE 编码器输出的是均值向量和标准差向量,而不是永无止境的密集层阵列。这些现在可以用来形成样本分布。然后,我们从每个分布中抽取一个值,这些值填充瓶颈层。这就是导致变化的随机性发挥作用的地方。由于我们从分布中取样,所以每次运行 VAE 时,即使所有权重保持不变,输出也会不同。

到目前为止,一切顺利。如果我们按照指示改变架构,那么我们完成了吗?不完全是。我们仍然需要修改我们的损失函数。对于重建误差,我们将使用二值交叉熵。然而,我们还需要损失函数中的另一项,即kull back–lei bler 散度 (KL 损失)。简单来说,这就是概率分布之间的差异。在我们的情况下,它将是 VAE 生成的概率分布和正态分布之间的差异之和。通过最小化这一点,我们迫使潜在空间中的分布围绕中心聚集(正态分布)。这导致在潜在空间中生成分布的重叠,并改善图像生成。因为否则,VAE 可能会通过为每种输入类型创建清晰分离的概率分布来“记忆”输入。通过对重建误差& KL 损失求和,我们得到我们的最终损失函数,我们试图在训练期间使其最小化。

现在我们可以建造了!如果你想尝试或者只是为你自己的项目窃取代码,我在 Jupyter 笔记本这里有全部内容。VAE 在 PyTorch 中实现,这是一个深度学习框架,甚至像我这样的生命科学人士都觉得使用它足够舒适。我开始无耻地从 PyTorch repo 中窃取 VAE 代码,然后调整&修改它,直到它符合我的需要。通常我会在谷歌的联合实验室上运行这些东西,因为它会免费给你一个特斯拉 K80 GPU,这绝对很棒!您可以将它与 Jupyter 笔记本电脑配合使用,连续运行长达 12 小时。

获得图像后,您必须将它们转换成 PyTorch 数据集。在我的笔记本中,这个实现非常简单,但是通常 PyTorch 数据集对象需要一个索引器(getitem)和一个长度(len)。我们可以利用这个机会对图像进行一些变换,比如使它们的大小相同,并使它们正常化。然后,我们可以将数据集馈送到数据加载器,数据加载器会将它分解成可用于训练的小批次。很简单,对吧?对于 VAE 本身,我们在 init 部分实例化层,并在“forward”部分定义层交互。基本上就是一堆线性图层加上偶尔的 ReLU 激活功能。因为 VAEs 在训练中可能有点棘手(想想消失和爆炸的渐变,耶!),我还在编码器和解码器上加了两个批归一化层。通过减少协变量偏移(增加两个交互层的独立性),它们允许在训练期间更稳定,甚至具有轻微的正则化效果(这就是为什么如果您将模型切换到 eval 模式,它们会被关闭)。最后,我们需要一个 sigmoid 激活函数用于二进制交叉熵损失,以便所有值都在 0 和 1 之间。

显著增加训练稳定性的最后一点是层初始化。输入某一组权重可以在训练稳定性方面产生巨大的差异,尤其是对于深度神经网络。我开始用 Xavier 初始化我所有的线性层,这最终允许我训练 VAE 没有任何爆炸。这种方法从受给定层的输入&输出连接数量影响的随机均匀分布中采样初始权重。但是最近我偶然发现了一篇关于初始化方案的优秀博文,包括明凯初始化,所以我决定也尝试一下那个,并与 Xavier 初始化的 VAE 进行比较。显然,这种方法最适合类似 ReLU 的激活函数,它由一个从标准正态分布中提取的权重张量乘以一个与该层的传入连接数成反比的因子组成。

VAE-generated images of blood cells, either healthy (left panel) or infected with malaria (right panel). Here, the VAE was initialized with Xavier initialization.

此外,我添加了一个衰减的学习率(每一个时期后减半)以获得更好的性能。经过 10 个时期的训练后,我开始用训练好的 VAEs 生成图像。为此,从标准正态分布中采样随机值,将它们输入到训练好的 VAE 的瓶颈层,并将它们解码成生成的图像就足够了。如果我们看一看由 Xavier 初始化的 VAE 产生的图像,我们可以清楚地看到 VAE 确实从图像中学到了一些东西。未感染细胞(黄色)和感染细胞(紫色)之间的颜色差异非常明显。然后,如果你仔细观察,未感染的细胞似乎比感染的细胞更圆,形状更均匀。虽然你可以在受感染的细胞中看到一些粒度,但它并不真的像输入图像中一样清晰。对于从明凯初始化的 VAEs 生成的图像,我们也可以观察到明显的色差,但这里的粒度似乎更不明显。此外,图像似乎相当模糊。事实上,VAE 生成的图像已经被指出有点嘈杂。有时候,这并不一定是坏事。如果您还记得输入图像的粗糙边缘,那么边缘周围的一点模糊至少会使生成的图像更加美观。

VAE-generated images of blood cells, either healthy (left panel) or infected with malaria (right panel). Here, the VAE was initialized with Kaiming initialization.

从这里去哪里?据报道,与 VAEs 相比,生成敌对网络(GANs)可以创建分辨率更高的图像,因此如果这是一个因素,GANs 可能会有吸引力。此外,尤其是对于图像,使用线性图层可能不如使用卷积图层。建立一个 CNN-VAE 可能会大大提高生成图像的质量,所以如果你喜欢,就去试试吧!原则上,对这种未感染/感染细胞设置使用自动编码器可以让您了解相应细胞状态的特征(通过研究构建的潜在空间中的参数),并可能有助于疟疾的自动诊断。无论如何,我非常喜欢做这个小东西,并且学到了更多关于深度学习& PyTorch 的知识。期待下一个项目!

额外收获:如果你设置正确的参数,你可以强制你的 VAE 生成看起来像宝石或彩色鹅卵石的细胞图像。因为我们都值得美丽的形象!

Can you figure out how to get those beautiful cells from a different universe?

使用 R 进行探索性数据分析(EDA) —分析高尔夫统计数据

原文:https://towardsdatascience.com/using-r-for-exploratory-data-analysis-eda-analyzing-golf-stats-812b5feb077a?source=collection_archive---------3-----------------------

无论您是数据架构师、数据工程师、数据分析师还是数据科学家,在开始一个新的数据项目时,我们都必须使用不熟悉的数据集。有点像和新数据集相亲。在感到舒适之前,你会想更多地了解它。

那么,我们怎么去呢?答案是探索性数据分析(EDA)

探索性数据分析是对数据集进行初步分析和发现的术语,通常在分析过程的早期进行。

作为一名数据专家,经历过这个过程后,我们会睡得更香。如果忽略这一步,在以后的步骤中会浪费很多时间..在架构基础和数据处理管道建立之后,需要重新工作来解决数据问题。

样本数据集

四大赛事结束后,泰格赢得了历史性的大师赛冠军,为什么不看看一些高尔夫统计数据呢?我在 espn.com 网站【http://www.espn.com/golf/statistics 上找到了 2019 年的高级统计数据。我把内容放在一个 Googlesheet 中以便于访问。正如您将很快看到的,这是一个非常基本的数据集,但它将让我们专注于 EDA 过程。

下面是我们数据集的样本行。

espn golf stats

我们将使用“googlesheets”库将数据集加载到 R 中。(Googlesheet 文件名为“golf_stats_espn”,sheetname 为“2019_stats”)。

library(googlesheets)googlesheet <- gs_title(“golf_stats_espn”)
df_2019 <- googlesheet %>% gs_read(ws = “2019_stats”)

EDA 步骤 1:数据验证和数据质量

函数将对结构进行健全性检查,并显示每个变量的样本数据。

str(df_2019)

str() function

如果你有使用 R 的经验,你可能很熟悉 summary() 函数。它工作得很好,但是一个更完整的函数是“skimr”包中的 skim() 函数。它按类型分解变量,并提供相关的摘要信息,以及每个数值变量的小直方图。

library(skimr)
skim(df_2019)

skim() function

除了“年龄”变量的看起来不错。使用 R 和许多其他分析工具,在读入内容时会自动分配数据类型,称为“读取时模式”。对于“年龄”,我们的变量被赋予了字符类型,而不是数字类型。然而,我想把 AGE 作为一个数值类型,以便在下游应用数值函数。为什么 R 创建年龄变量作为字符类型?

让我们做更多的 EDA,并对年龄变量运行一个 table() 函数。

with(df_2019, table(AGE))

table() function

table()函数在第一行显示变量的不同值,并在下一行显示出现的次数。对于年龄变量,我们可以看到“-”出现 1 次。r 别无选择,只能将变量定义为“字符”类型。

我们可以通过使用“DPLYR”包来解决这个问题。DPLYR 专门研究“数据角力”。使用这个包,您可以高效地完成很多工作——数据帧操作、转换、过滤、聚合等。

下面的 R 命令在执行了项目符号所描述的操作后创建了一个新的数据帧。

df_2019_filtered <- df_2019 %>%          # create new dataframe
 mutate(AGE_numeric = !(is.na(as.numeric(AGE)))) %>% 
 filter(AGE_numeric == TRUE) %>% 
 mutate(AGE = as.numeric(AGE))
  • mutate →创建一个新的布尔变量,标识它的值是否为数字
  • filter →使用在上面的 mutate 行中创建的新布尔变量过滤掉非数字变量
  • 突变→替换“年龄”变量;现在定义为数值变量

下面是我们新的数据框架。

str() function

还有一个调整,我将把列“RK”重命名为一个更好的名称。

df_2019_filtered <- rename(df_2019_filtered, “RANK_DRV_ACC” = “RK”)

让我们在这里暂停一分钟。

处理脏数据

  • 对于本文,缺失的年龄行被过滤掉了。在一个真正的分析项目中,我们将不得不寻找最佳的行动方案(过滤行,替换字符数据,用 NULL 替换,等等)。

探索性数据分析(EDA)——第二部分

随着我们的数据集被检查和清理…

第 2 部分更倾向于数据分析师和数据科学家。您可能会对在此阶段获得的见解感到惊讶,即使是在这个非常基础的数据集上。

【plot _ histogram()】

我们将使用“DataExplorer”库来了解关于我们的数据集的更多信息。 plot_histogram() 函数将为我们的每个数字变量返回一个单独的条形图。它显示了变量中每个值的频率(出现的次数)。

*library(DataExplorer)
plot_histogram(df_2019_filtered)*

plot_histogram() function

例如,“GREENS_REG”变量包含的值大约在 55 到 75 之间。根据条形图,我们看到大多数高尔夫球手大约有 65-70%的时间在果岭上击球。

plot _ box plot()

箱线图(盒须图)显示变量的数据分布。这个方框向我们展示了“五个数字的总结”——最小值、第一个四分位数、中间值、第三个四分位数和最大值。

下面的 plot_boxplot() 函数创建了 5 个箱/分区。我们将首先关注每驱动码数(YDS 驱动)变量。

plot_boxplot(df_2019_filtered, by = “YDS_DRIVE”)

plot_boxplot() function

我们可以看到一些非常有趣的相关性,将“年龄”变量与“每次驾驶的 YDS”进行比较。

  • 年纪大的人打不了那么远。
  • 有一个异常值。与同年龄组的其他人相比,一些 50 多岁的人仍在努力。

接下来,我们从“年龄”的角度再做一个箱线图。

plot_boxplot(df_2019_filtered, by = “AGE”)

plot_boxplot() function

  • 左上角年龄最大的群体(48–55)的“驾驶准确率”(DRIVING_ACC)非常低。我希望年纪大的球员击球更短,但更准确…这不是真的,数据不会说谎。
  • 年龄较大的群体(48-55 岁)也在推杆方面有困难。他们有最高的平均每洞推杆数(AVG 推杆)。

探索性数据分析(EDA)——第三部分

让我们把这个分析带到另一个层次。

这个库中的功能更接近数据科学家花费时间的地方。

“ggcorrplot”为我们提供了一个“热图”,显示了关系之间的显著性(或不显著性)。人类不可能盯着电子表格并确定数据的列和行之间的模式/关系。

让我们使用“ggcorrplot”库。有时候,关键是更聪明地工作,而不是更努力地工作!

*library(ggcorrplot)ggcorrplot(corr, type = “lower”, outline.col = “black”,
 lab=TRUE,
 ggtheme = ggplot2::theme_gray,
 colors = c(“#6D9EC1”, “white”, “#E46726”))*

ggcorrplot() function

1 =高度相关;0 =无关系;-1 =反比关系

运行该函数比盯着电子表格,试图查看行和列之间的关系要容易得多!

1 .我们的变量之间最重要的关系是“每次击球的码数”和“规则中的果岭数”。

2 .相反,最显著的反比关系存在于“年龄”和“每次行驶码数”之间。

如果你喜欢圆形胜过正方形,下面是使用圆形方法得到的相同数据。

*ggcorrplot(corr, type = “lower”, outline.col = “black”,
 method=”circle”,
 ggtheme = ggplot2::theme_gray,
 colors = c(“#6D9EC1”, “white”, “#E46726”))*

结论

尽管 EDA 过程至关重要,但它只是典型数据分析项目生命周期的开始。最有可能的是,一个组织的有价值的数据将不会来自 googlesheet,而是更有可能被埋藏在不同的数据库中,或者来自第三方供应商,甚至可能来自物联网数据流。

利用 R 和 EDA 过程将有助于为成功的分析项目铺平道路。

Jeff Griesemer 是 Froedtert Health 的一名分析开发人员。

使用随机森林来判断是否有代表性的验证集

原文:https://towardsdatascience.com/using-random-forest-to-tell-if-you-have-a-representative-validation-set-4b58414267f6?source=collection_archive---------17-----------------------

这是一个快速检查,检查您最重要的机器学习任务之一是否设置正确

Photo by João Silas on Unsplash

当运行预测模型时,无论是在 Kaggle 比赛中还是在现实世界中,您都需要一个代表性的验证集来检查您正在训练的模型是否具有良好的泛化能力,也就是说,该模型可以对它从未见过的数据做出良好的预测。

那么,我所说的“代表”是什么意思呢?嗯,它真正的意思是,你的训练和验证数据集是相似的,即遵循相同的分布或模式。如果不是这样,那么你就用苹果来训练你的模型,然后试着用橙子来预测。结果将是非常糟糕的预测。

您可以进行大量探索性数据分析(EDA ),并检查两个数据集中的每个要素的行为是否相似。但那可能真的很费时间。测试您是否有一个有代表性的或好的验证集的一个简洁而快速的方法是运行一个随机的森林分类器。

在这个 Kaggle 内核中,我正是这样做的。我首先准备了训练和验证数据,然后添加了一个额外的列“train ”,当数据是训练数据时,它的值为 1,当数据是验证数据时,它的值为 0。这是随机森林分类器将要预测的目标。

# Create the new target
train_set['train'] = 1
validation_set['train'] = 0# Concatenate the two datasets
train_validation = pd.concat([train_set, validation_set], axis=0)

下一步是准备好独立(X)和从属(y)特性,设置随机森林分类器,并运行交叉验证。

我使用的是度量标准 ROC AUC ,这是分类任务的常用度量标准。如果指标是 1,那么你的预测是完美的。如果分数是 0.5,那么你和基线一样好,这是如果你总是预测最常见的结果,你会得到的分数。如果分数低于 0.5,那么你做错了。

# Import the libraries
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score# Split up the dependent and independent variables
X = train_validation.drop('train', axis=1)
y = train_validation['train']# Set up the model
rfc = RandomForestClassifier(n_estimators=10, random_state=1)# Run cross validation
cv_results = cross_val_score(rfc, X, y, cv=5, scoring='roc_auc')

现在,如果训练集和验证集表现相同,您认为 ROC AUC 应该是多少?……没错, 0.5 !如果分数是 0.5,那么这意味着训练和验证数据是不可区分的,这正是我们想要的。

一旦我们运行了交叉验证,让我们得到分数…和好消息!分数确实是 0.5。这意味着 Kaggle 主机已经为我们建立了一个代表性的验证集。有时情况并非如此,这是一个很好的快速检查方法。然而,在现实生活中,你必须自己想出一个验证集,这有望派上用场,以确保你设置了一个正确的验证集。

print(cv_results)
print(np.mean(cv_results))[0.5000814  0.50310124 0.50416737 0.49976049 0.50078978]
0.5015800562639847

使用 RandomForest 预测医疗预约失约

原文:https://towardsdatascience.com/using-randomforest-to-predict-medical-appointment-no-shows-b33575e3ff42?source=collection_archive---------27-----------------------

Photo by Adhy Savala on Unsplash

对医疗机构来说,失约或错过预约的患者很常见,而且代价高昂。美国一项研究发现,多达 30%的患者会错过他们的预约,每年因此损失 1500 亿美元。

识别潜在的失约可以帮助医疗机构采取有针对性的干预措施(例如,提醒电话、重复预约预约时段)来减少失约和财务损失。

资料组

Kaggle 数据集包含了来自巴西一个城市的公共医疗机构的 11 万份预约记录。这些约会发生在 2016 年的 6 周内。

以下是数据集功能的总结:

Table summarising the dataset’s original variables

患者 id 是不唯一的,这表明同一患者在 6 周内有多次预约。为了避免数据泄露(如果将同一患者的数据用于验证和测试,就会发生这种情况),我们将只在模型中包含患者的最新预约。

数据清理

有两个主要的清洁步骤:

  1. 二进制编码(1,0)失约,性别和障碍。我假设障碍应该是二进制的,因为它在 Kaggle 上有描述。
  2. 删除逻辑不一致的观察结果,如负年龄,以及计划日期晚于预约日期。

特征工程

特征工程用于记录日期时间特征,并保留从以前的约会(最近的约会之前的约会)中捕获的信息。

List of original dataset features and engineered features. Colours indicate the features from which the engineered features were created from.

通过从每个患者的失约和预约总数中分别减去 1 来计算先前失约和先前预约。

计划日期和约会日期分为星期几(DoW)和月几。预定时间也被分成一天中的几个小时。

天数差是指预定日期和约会日期之间的天数差。

总病情是高血压、糖尿病、残疾和酒精中毒的总和。换句话说,它显示了病人所患疾病的数量。

特征选择

特征是根据它们的信息值(IV) 选择的,这些信息值根据它们对目标的预测程度对特征进行排序和评分。

Selected features and their Information Value (IV) scores.

IV 分数< 0.02(非常差的预测因子的阈值)的特征被丢弃。使用保守阈值有助于确保有用的特征不会过早地从模型中排除。

事实证明,大多数特征对目标的预测能力很差。

此外,还去除了 ID 特征、冗余特征和邻域。邻域被删除是因为我找不到关于它们的额外信息,而且在模型中包含 80 个虚拟变量是不可取的。

在数据清理和特征选择之后,大约 62k 的观测值仍然存在。其中 20%没有出现。

五重交叉验证

数据集被分成 20%的测试数据集和 80%的交叉验证数据集。

使用 5 个训练-验证折叠,数据适合四个监督学习算法:

  1. 逻辑回归
  2. 朴素贝叶斯
  3. k-最近邻(KNN)
  4. 随机森林

RandomCVSearch (5 倍,10 次迭代,50 次拟合)用于调整 KNN 和随机森林的超参数。

根据模型的平均准确性和受试者工作特征曲线下面积(ROC AUC)评分对模型进行评估。

不幸的是,这些型号的性能相似,我无法选择最佳型号。

注意:我没有使用 F1 分数,因为它取决于所选的分类阈值,我打算在选择模型后对其进行调整。我使用 ROC AUC 评分和准确性,因为我想要最好的模型,而不考虑阈值。

使用更多数据进行验证。

由于交叉验证对模型选择没有用,用于训练和验证的 80%被重新分成 60%训练和 20%验证。(以前交叉验证使用 64%用于训练,16%用于每个折叠的验证)。希望有一个更大的验证集会使模型之间的差异更加明显。

Graph depicting models’ ROC curves, and table of models’ accuracy scores

从 ROC 曲线分析,我们可以看到 RandomForest 优于其他算法。它的精确度也与其他的相当。我们将使用 RandomForest 作为未来的模型。

调整分类阈值

RandomForest 的分类阈值是基于这样的假设进行调整的,即医疗机构希望在大规模推广干预措施之前对其进行测试。因此,精确度优先于回忆。

我选择的阈值是 0.38,因为这大约是两条曲线逐渐变细的时间。这个阈值意味着 74%的时间(精确度)可以正确识别未出现者,并且大约四分之一的未出现者可以被识别(回忆)。

测试

使用 80%的数据重新训练该模型,并对剩余的 20%进行测试。

测试分数与验证分数相似,这表明该模型概括得很好。

近距离观察 RandomForest

RandomForest 的特征重要性表明,时差和先前的未出现在预测未出现中是重要的。

Histograms depicting the differences in distributions for shows and no-shows, for prior no shows and day difference.

特别是,失约者的预定日期和约定日期之间的差异更大,而且有失约的历史。

特征重要性的知识对于选择干预措施是有用的。例如,那些提前预约的病人可能会忘记他们的预约。一个可能的干预措施是建立更多的个人患者接触点(例如电话,因为短信似乎没有效果)。

另一方面,对于有失约史的患者来说,原因可能更习惯性。如果机构无法说服这些病人出现,重复预约他们的位置可能是一个可行的解决方案。

结论

总之,似乎可以从患者信息和预约数据中预测失约。更多关于诊所位置(如交通便利)、寻求的护理类型(如初级、专科)和患者(如教育、收入)的信息可能会改进模型。该模型还可以受益于对可能的干预措施的成本效益分析,以实现最具商业意义的精确度和召回率之间的平衡。

** * 查看我的GitHub上的代码

用 Python 在遗传学中使用正则表达式

原文:https://towardsdatascience.com/using-regular-expression-in-genetics-with-python-175e2b9395c2?source=collection_archive---------11-----------------------

如何在生物序列数据中发现模式

Image Courtesy of National cancer Institute via Unsplash

Python 中的正则表达式(regex)可以用来帮助我们发现遗传学中的模式。当我们分析生物序列数据时,我们可以利用正则表达式,因为我们经常在 DNA、RNA 或蛋白质中寻找模式。这些序列数据类型只是字符串,因此非常适合使用 regex 进行模式分析。我们可能有兴趣寻找:导致人类疾病的核苷酸重复序列、DNA 转录因子结合位点、限制性酶切位点和特定突变。为了能够使用 regex 实现这一点,我们必须首先掌握 regex 的基本语法和一些特定于 regex 模块的函数。在本教程的第一部分,例子将使用 4 个 DNA 核苷酸;a,T,G,c。

这个简短的教程旨在:

1.介绍正则表达式语法,并举例说明遗传学

2.展示我们如何使用普通的正则表达式函数来寻找模式

正则表达式

以下字符在正则表达式中是特殊的:\(^.*+?{ } [ ] | \并在表 1 中显示了相应的描述。^和\)元字符被称为锚点,代表输入字符串中的位置。^匹配字符串的开头,而\(匹配字符串的结尾。模式^CCC 将匹配 CCCGGG,但不匹配 GGGCCC。模式 AAA\)将匹配 TTTAAA,但不匹配 AAAGGG。

答。句点(或小数点)是查找任何字符的通配符。如果蛋白激酶具有共有序列“RXYVHXFDEXK ”,其中 X 表示任何氨基酸,那么正则表达式“R.YVH.FDE.K”将成功搜索底物。但是,需要注意的是,句号(。),将匹配任何甚至不是字母的字符。因此,模式“R.YVH.FDE.K”将匹配“R8YVH FDE&K”,这可能不是我们想要的。

元字符,,+,?、和{ }是量词运算符。这些用于指定字符或字符组的重复。字符或组后面的星号表示该字符或组是可选的,但也可以重复。遗传学领域中使用星号元字符的一个例子是,当我们搜索 RNA-seq reads 以通过搜索 AAAAAA找到 3’-聚腺苷酸化的序列时。这个正则表达式将精确地找到 5 个 A,后面跟着零个或更多个 A。+元字符类似于*,只是它会一次或多次找到该字符。答?零次或一次查找前面的字符或字符组。

如果需要具体或者匹配特定的重复次数,我们可以使用花括号符号。花括号中的单个数字将与前面的字符或组中的重复次数完全匹配。例如,CA{3}GATT 将匹配 CAAAGATT,但不匹配 CAAGATT 或 CAAAGATT。要指定一个范围,我们可以使用相同的花括号语法,并使用一般模式,其中{ nx }查找在 nx 时间之间的前一个字符或组。例如,TCG{2,4}A 将匹配模式 TCGGA、TCGGGA、TCGGGA,但不匹配 TCGA 或 TCGGGGGA。表 1 总结了这些元字符。

匹配一个图案

re 模块用于在 Python 中编写正则表达式(regex)。要加载这个模块,我们需要使用 import 语句。以下代码行必须包含在代码的顶部:

进口 re

为了使用正则表达式模块中的工具,有必要在它前面加上模块名。最简单的正则表达式函数 re.search()确定模式是否存在于字符串中的某个位置。re.search()有两个参数,都是字符串。第一个参数是要搜索的模式,第二个参数是要搜索的字符串。为了清楚起见,在下面的例子中,我包含了两个参数作为关键字参数。通常没有必要包含这些关键字参数。为了完整起见,我包括了被注释掉的另一个 syntaxic 版本。

下面的代码演示了一个简单的例子;在这里,我们正在寻找一个硬编码 DNA 变量中 A 碱基的三核苷酸重复序列的存在。

许多 re 函数调用的输出是一个匹配对象。如果我们查看上面的匹配对象,我们可以确定是否有匹配。span 标识出现匹配的字符串的索引,而 match 标识得到匹配的确切字符串。

正则表达式搜索也可以用作条件语句的一部分:

提取匹配对象值

通常在我们的脚本中,我们不仅要确定是否匹配,还要确定匹配发生在哪里。我们可能还想提取匹配本身。幸运的是,Python 使得提取匹配对象值变得很简单,比如匹配的索引位置和匹配的确切字符串。这可以通过在 match 对象上使用一些方法来实现。

交替和字符组

re.search()也可以用来寻找更灵活的模式。举例来说,NCII 限制酶识别核苷酸序列模式“CCSGG”,其中核苷酸代码“S”可以是 C 或 g。我们可以使用一个改变来捕获这种变化,而不是编写两个正则表达式搜索。这里,为了表示许多不同的替代项,我们将替代项写在括号内,并使用管道字符将它们分隔开(元字符|也称为交替运算符,请参见表 1)。

交替组的实用性来自于它们作为重复单位的能力。例如,为了确定一个序列是否由起始和终止密码子限定,并因此有可能成为开放阅读框,我们可以编写以下正则表达式:

这个正则表达式将在序列的末尾搜索 UAA、UAG 和 UGA。为了改进这个正则表达式,并确保起始和终止密码子在同一个框架中,我们可以将正则表达式改为:

这将检查起始和终止密码子之间的所有字符都是 3 的倍数。

字符组

字符组也可以用来捕捉单个模式中的变化。考虑蛋白质中共有的 N-糖基化位点。该序列基序具有以下模式:Asn,后跟除 Pro 以外的任何东西,后跟 Ser 或 Thr,后跟除 Pro 以外的任何东西。

使用相应的单字母氨基酸代码和字符组,我们可以将此模式写为:

这种模式将识别单个字母代码 N,后跟任何不是 P 的字符(参见表 1,取反的字符组),后跟 S 或 T,再后跟任何不是 P 的字符。一对带有字符列表的方括号可以表示这些字符中的任何(参见表 1)。

Regex 的威力

当这些工具一起使用时,regex 的真正威力就发挥出来了。考虑下面的场景。许多人类遗传性神经退行性疾病,如亨廷顿氏病(HD ),都与特定基因中三核苷酸重复数目的异常扩增有关。HD 的病理严重程度与编码亨廷顿蛋白的基因 htt 的外显子-1 中的(CAG) n 重复的数量相关。在亨廷顿氏病中,重复次数越多意味着疾病发作越早,疾病进展越快。CAG 密码子指定谷氨酰胺,HD 属于一大类多谷氨酰胺疾病。这种基因的健康(野生型)变异体具有 6-35 个串联重复,而超过 35 个重复几乎肯定会患病。

我们可以使用正则表达式来破译多聚谷氨酰胺重复数。这首先包括写一个模式以找到高于设定阈值的三核苷酸重复数。

密码子 CAA 也编码谷氨酰胺,因此,在上面的 htt_pattern 中,我们必须使用| alternation 操作符。然后,我们可以使用上面讨论的花括号符号来指定我们希望找到这个模式的次数。在这里,我选择了 18 次或更多次,通过故意离开上限。

我首先在 NCBI 核苷酸数据库中搜索了 htt mRNA 序列,并将其下载到我的工作目录中。然后我读取了这个序列,并使用我的模式来确定谷氨酰胺串联重复序列的长度超过 18。为了清楚起见,我在 NCBI·法斯特的文件中突出了这场比赛。我还使用了 re.findall()函数,因为 re.search()只会找到第一个匹配项,在这种情况下可能会找到许多匹配项。

结论:

本教程简要介绍了正则表达式在遗传学中的具体应用。正则表达式中的知识是高度可转移的,特别是在 Python 和许多其他主流编程语言(如 Perl 和 r)中,语法形式和功能表现大致相似。

使用强化学习在 NES 上玩超级马里奥兄弟

原文:https://towardsdatascience.com/using-reinforcement-learning-to-play-super-mario-bros-on-nes-using-tensorflow-31281e35825?source=collection_archive---------9-----------------------

强化学习是目前机器学习领域最热门的话题之一。对于我们最近参加的一次会议(在慕尼黑举行的令人敬畏的数据节),我们开发了一个强化学习模型,学习在 NES 上玩超级马里奥兄弟,这样一来,来到我们展台的参观者就可以在关卡完成时间方面与代理竞争。

推广活动取得了巨大成功,人们喜欢“人机”竞赛。只有一名选手能够通过一条人工智能不知道的秘密捷径打败人工智能。此外,用 Python 开发模型非常有趣。因此,我决定写一篇关于它的博文,涵盖强化学习的一些基本概念以及我们的超级马里奥代理在 TensorFlow 中的实际实现(注意,我使用的是 TensorFlow 1.13.1,在撰写本文时 TensorFlow 2.0 尚未发布)。

回顾:强化学习

大多数机器学习模型在输入和输出之间有明确的联系,这种联系在训练期间不会改变。因此,很难对输入或目标本身依赖于先前预测的系统进行建模或预测。然而,通常情况下,模型周围的世界会随着所做的每一个预测而自我更新。听起来很抽象的东西实际上是现实世界中非常常见的情况:自动驾驶、机器控制、过程自动化等。—在许多情况下,模型做出的决策会对其周围环境产生影响,从而影响下一步要采取的行动。在这种情况下,经典的监督学习方法只能在有限的范围内使用。为了解决后者,需要能够处理相互依赖的输入和输出的时间相关变化的机器学习模型。这就是强化学习发挥作用的地方。

在强化学习中,模型(称为代理)通过从环境的每个状态中的一组可能的动作(动作空间)中进行选择,与它的环境进行交互,这些动作从环境中引起正面或负面的回报。把奖励想象成一个抽象的概念,表明所采取的行动是好是坏。因此,由环境发出的奖励可以是即时的,也可以延迟到将来。通过从环境状态、动作和相应的奖励的组合中学习(所谓的转换,代理试图达到一组最优的决策规则(策略策略),使代理在每个状态下收集的总奖励最大化。

Q 学习和深度 Q 学习

在强化学习中,我们经常使用一个叫做 Q-learning 的学习概念。Q-learning 基于所谓的 Q 值,它帮助代理在给定当前环境状态的情况下确定最佳行动。q 值是“贴现”的未来奖励,是我们的代理在培训期间通过采取行动和在不同环境状态中移动收集的。q 值本身试图在训练期间被近似,或者通过简单的环境探索,或者通过使用函数近似器,例如深度神经网络(如我们这里的情况)。通常,我们在每个状态中选择具有最高 Q 值的行动,即,给定环境的当前状态,最高的贴现未来回报。

当使用神经网络作为 Q 函数逼近器时,我们通过计算预测 Q 值和“真实”Q 值之间的差异进行学习,即当前状态下最佳决策的表示。基于计算的损失,我们使用梯度下降更新网络的参数,就像在任何其他神经网络模型中一样。通过经常这样做,我们的网络收敛到一个状态,在给定当前环境状态的情况下,它可以近似下一个状态的 Q 值。如果近似足够好,我们简单地选择具有最高 Q 值的动作。通过这样做,代理人能够在每种情况下决定哪种行为在奖励收集方面产生最好的结果。

在大多数深度强化学习模型中,实际上涉及两个深度神经网络:在线网络和目标网络。这样做是因为在训练期间,单个神经网络的损失函数是针对稳定变化的目标(Q 值)计算的,这些目标是基于网络权重本身的。这增加了优化问题的难度,或者可能导致根本不收敛。目标网络基本上是在线网络的副本,具有不直接训练的冻结权重。相反,在一定数量的训练步骤之后,目标网络的权重与在线网络同步。强制在每个训练步骤之后不改变的目标网络的“稳定输出”确保了计算损耗所需的计算的目标 Q 值不会稳定地改变,这支持了优化问题的收敛。

深度双 Q 学习

Q-learning 的另一个可能的问题是,由于选择最大 Q 值来确定最佳动作,模型有时会在训练期间产生非常高的 Q 值。基本上,这并不总是一个问题,但可能会变成一个问题,如果对某些行为的强烈关注导致对不太有利但“值得一试”的行为的忽视。如果一直忽略后者,模型可能会陷入局部最优解,甚至更糟的是一直选择相同的动作。处理这个问题的一个方法是引入 Q-learning 的更新版本,称为双 Q-learning

在双 Q 学习中,每个状态中的动作不是简单地通过选择具有目标网络的最大 Q 值的动作来选择的。相反,选择过程分为三个不同的步骤:(1)首先,目标网络在采取行动后计算状态的目标 Q 值。然后,(2)在线网络计算采取行动后状态的 Q 值,并通过找到最大 Q 值来选择最佳行动。最后,(3)使用目标网络的目标 Q 值来计算目标 Q 值,但是是在在线网络的所选动作指数处。这保证了不会出现对 Q 值的高估,因为 Q 值不是基于它们自身更新的。

健身房环境

为了构建一个强化学习应用程序,我们需要两样东西:(1)一个代理可以与之交互并向其学习的环境(2)代理,它观察环境的状态并使用 Q 值选择适当的动作,这(理想情况下)会给代理带来高回报。环境通常被提供为所谓的体育馆(gym ),一个包含必要代码的类,以模拟作为代理的动作的函数的环境的状态和回报以及进一步的信息,例如关于可能的动作空间。以下是 Python 中一个简单环境类的示例:

class Environment:
    """ A simple environment skeleton """
    def __init__(self):
       # Initializes the environment
        pass

    def step(self, action):
       # Changes the environment based on agents action
        return next_state, reward, done, infodef reset(self):
        # Resets the environment to its initial state
        passdef render(self):
       # Show the state of the environment on screen
        pass

环境有三个主要的类函数:(1) step()执行环境代码作为代理选择的动作的函数,并返回环境的下一个状态、关于action的奖励、指示环境是否已经到达其终止状态的done标志以及关于环境及其状态的附加信息的字典,(2) reset()将环境重置为其原始状态,以及(3) render()在屏幕上打印当前状态(例如显示超级马里奥兄弟游戏的当前帧)。

对于 Python 来说,寻找健身房的必去之地是 OpenAI 。它包含许多不同的游戏和问题,非常适合使用强化学习来解决。此外,还有一个名为 Gym Retro 的开放人工智能项目,包含数百个世嘉和 SNES 游戏,随时可以通过强化学习算法解决。

代理人

代理消耗环境的当前状态,并基于选择策略选择适当的动作。该策略将环境状态映射到代理要采取的操作。寻找正确的策略是强化学习中的一个关键问题,通常涉及深度神经网络的使用。下面的代理只是观察环境的状态,如果state大于 0,则返回action = 1,否则返回action = 0

class Agent:
    """ A simple agent """
    def __init__(self):
        passdef action(self, state):
        if state > 0:
            return 1
        else:
            return 0

这当然是一个非常简单化的政策。在实际的强化学习应用中,环境的状态可能是非常复杂和高维的。一个例子是视频游戏。环境的状态由屏幕上的像素和玩家之前的动作决定。我们的代理人需要找到一种策略,将屏幕像素映射为从环境中产生回报的行为。

环境包装

健身房环境包含在强化学习场景中使用它们所需的大部分功能。然而,有一些功能并不是健身房中预先内置的,例如图像缩小、跳帧和堆叠奖励剪辑等等。幸运的是,有所谓的健身房包装器提供这种实用功能。在这里可以找到一个可以用于很多视频游戏的例子,比如 Atari 或者 NES。对于视频游戏健身房来说,为了实现代理的良好性能,使用包装函数是非常常见的。下面的例子展示了一个简单的奖励剪辑包装器。

import gymclass ClipRewardEnv(gym.RewardWrapper):
  """ Example wrapper for reward clipping """
    def __init__(self, env):
        gym.RewardWrapper.__init__(self, env)def reward(self, reward):
        # Clip reward to {1, 0, -1} by its sign
        return np.sign(reward)

从上面的例子可以看出,通过“覆盖”环境的核心功能,可以改变环境的默认行为。这里,基于奖励的符号,使用np.sign()将环境的奖励修剪为[-1,0,1]。

超级马里奥兄弟 NES 环境

对于我们的超级马里奥兄弟强化学习实验,我使用了 gym-super-mario-bros 。这个 API 很简单,非常类似于开放人工智能健身房 API 。下面的代码显示了一个随机代理玩超级马里奥。这导致马里奥在屏幕上扭动,当然,不会导致游戏成功完成。

from nes_py.wrappers import BinarySpaceToDiscreteSpaceEnv
import gym_super_mario_bros
from gym_super_mario_bros.actions import SIMPLE_MOVEMENT# Make gym environment
env = gym_super_mario_bros.make('SuperMarioBros-v0')
env = BinarySpaceToDiscreteSpaceEnv(env, SIMPLE_MOVEMENT)# Play random
done = True
for step in range(5000):
    if done:
        state = env.reset()
    state, reward, done, info = env.step(env.action_space.sample())
    env.render()# Close device
env.close()

代理通过从环境的动作空间中选择随机动作来与环境交互。视频游戏的动作空间实际上相当大,因为你可以同时按下多个按钮。这里动作空间缩减为SIMPLE_MOVEMENT,涵盖了四面八方跑、跳、鸭等基本游戏动作。BinarySpaceToDiscreteSpaceEnv将二进制动作空间(所有按钮和方向的虚拟指示器变量)转换为单个整数。例如,整数动作 12 对应于按下右键和 A(跑步)。

使用深度学习模型作为代理

当在 NES 上玩超级马里奥兄弟时,人类看到的是游戏屏幕——更准确地说,他们看到的是高速显示在屏幕上的连续像素帧。我们人类的大脑能够将来自我们眼睛的原始感官输入转换为电信号,这些电信号由我们的大脑处理,从而触发相应的动作(按下控制器上的按钮),这些动作(有希望)将马里奥引向终点线。

在训练代理人时,健身房根据代理人采取的相应动作,将每个游戏帧呈现为像素矩阵。基本上,这些像素可以用作任何机器学习模型的输入。然而,在强化学习中,我们经常使用卷积神经网络(CNN ),与其他 ML 模型相比,它擅长图像识别问题。我不会在这里深入 CNN 的技术细节,有太多关于 CNN 的精彩介绍文章,比如这篇

不仅仅使用当前游戏屏幕作为模型的输入,通常使用多个堆叠的帧作为 CNN 的输入。通过这样做,模型可以处理屏幕上连续帧之间的变化和“运动”,这在仅使用单个游戏帧时是不可能的。这里,我们模型的输入张量的大小是[84, 84, 4]。这对应于 4 个灰度帧的堆栈,每个帧的大小为 84×84 像素。这对应于二维卷积的默认张量大小。

深度学习模型的架构包括三个卷积层,随后是一个扁平化和一个具有 512 个神经元的全连接层,以及一个输出层,由actions = 6个神经元组成,对应于游戏的动作空间(在这种情况下是RIGHT_ONLY,即向右移动马里奥的动作——扩大动作空间通常会导致问题复杂性和训练时间的增加)。

如果你仔细看看下面的 TensorBoard 图像,你会注意到这个模型实际上不仅由一个,而是由两个相同的卷积分支组成。一个是在线网络分支,另一个是目标网络分支。在线网络实际上是使用梯度下降来训练的。目标网络不是直接训练的,而是通过将权重从网络的在线分支复制到目标分支,定期同步每个copy = 10000步骤。通过使用分支输出层周围的tf.stop_gradient()函数,将目标网络分支排除在梯度下降训练之外。这将导致输出层的梯度流停止,因此它们无法沿分支传播,因此权重不会更新。

代理通过以下方式进行学习:(1)随机抽取历史转换样本,(2)使用目标网络分支和双 Q 学习规则,根据行动后的环境状态next_state计算“真实”Q 值,(3)使用gamma = 0.9对目标 Q 值进行贴现,(4)根据网络内部 Q 预测和target_q提供的真实 Q 值运行批量梯度下降步骤。为了加快训练过程,代理不是在每个动作后进行训练,而是每隔train_each = 3帧进行训练,这相当于每隔 4 帧进行一次训练。此外,不是每一帧都存储在重放缓冲器中,而是每第 4 帧。这叫做跳帧。更具体地,执行最大汇集操作,该操作聚集最后 4 个连续帧之间的信息。这是由于连续的帧包含几乎相同的信息,这不会给学习问题增加新的信息,并且可能引入强自相关的数据点。

说到相关数据:我们的网络使用自适应矩估计(ADAM)和梯度下降在 a learning_rate = 0.00025进行训练,这需要 i.i.d .数据点才能正常工作。这意味着,我们不能简单地随后使用所有新的转移元组进行训练,因为它们高度相关。为了解决这个问题,我们使用了一个叫做经验重放缓冲区的概念。因此,我们将游戏的每个过渡存储在一个环形缓冲区对象中(Python 中的deque()函数),当我们获取batch_size = 32的训练数据时,会随机从中抽取样本。通过使用随机采样策略和足够大的重放缓冲区,我们可以假设得到的数据点(希望)是不相关的。下面的代码框显示了DQNAgent类。

import time
import random
import numpy as np
from collections import deque
import tensorflow as tf
from matplotlib import pyplot as plt class DQNAgent:
    """ DQN agent """
    def __init__(self, states, actions, max_memory, double_q):
        self.states = states
        self.actions = actions
        self.session = tf.Session()
        self.build_model()
        self.saver = tf.train.Saver(max_to_keep=10)
        self.session.run(tf.global_variables_initializer())
        self.saver = tf.train.Saver()
        self.memory = deque(maxlen=max_memory)
        self.eps = 1
        self.eps_decay = 0.99999975
        self.eps_min = 0.1
        self.gamma = 0.90
        self.batch_size = 32
        self.burnin = 100000
        self.copy = 10000
        self.step = 0
        self.learn_each = 3
        self.learn_step = 0
        self.save_each = 500000
        self.double_q = double_qdef build_model(self):
        """ Model builder function """
        self.input = tf.placeholder(dtype=tf.float32, shape=(None, ) + self.states, name='input')
        self.q_true = tf.placeholder(dtype=tf.float32, shape=[None], name='labels')
        self.a_true = tf.placeholder(dtype=tf.int32, shape=[None], name='actions')
        self.reward = tf.placeholder(dtype=tf.float32, shape=[], name='reward')
        self.input_float = tf.to_float(self.input) / 255.
        # Online network
        with tf.variable_scope('online'):
            self.conv_1 = tf.layers.conv2d(inputs=self.input_float, filters=32, kernel_size=8, strides=4, activation=tf.nn.relu)
            self.conv_2 = tf.layers.conv2d(inputs=self.conv_1, filters=64, kernel_size=4, strides=2, activation=tf.nn.relu)
            self.conv_3 = tf.layers.conv2d(inputs=self.conv_2, filters=64, kernel_size=3, strides=1, activation=tf.nn.relu)
            self.flatten = tf.layers.flatten(inputs=self.conv_3)
            self.dense = tf.layers.dense(inputs=self.flatten, units=512, activation=tf.nn.relu)
            self.output = tf.layers.dense(inputs=self.dense, units=self.actions, name='output')
        # Target network
        with tf.variable_scope('target'):
            self.conv_1_target = tf.layers.conv2d(inputs=self.input_float, filters=32, kernel_size=8, strides=4, activation=tf.nn.relu)
            self.conv_2_target = tf.layers.conv2d(inputs=self.conv_1_target, filters=64, kernel_size=4, strides=2, activation=tf.nn.relu)
            self.conv_3_target = tf.layers.conv2d(inputs=self.conv_2_target, filters=64, kernel_size=3, strides=1, activation=tf.nn.relu)
            self.flatten_target = tf.layers.flatten(inputs=self.conv_3_target)
            self.dense_target = tf.layers.dense(inputs=self.flatten_target, units=512, activation=tf.nn.relu)
            self.output_target = tf.stop_gradient(tf.layers.dense(inputs=self.dense_target, units=self.actions, name='output_target'))
        # Optimizer
        self.action = tf.argmax(input=self.output, axis=1)
        self.q_pred = tf.gather_nd(params=self.output, indices=tf.stack([tf.range(tf.shape(self.a_true)[0]), self.a_true], axis=1))
        self.loss = tf.losses.huber_loss(labels=self.q_true, predictions=self.q_pred)
        self.train = tf.train.AdamOptimizer(learning_rate=0.00025).minimize(self.loss)
        # Summaries
        self.summaries = tf.summary.merge([
            tf.summary.scalar('reward', self.reward),
            tf.summary.scalar('loss', self.loss),
            tf.summary.scalar('max_q', tf.reduce_max(self.output))
        ])
        self.writer = tf.summary.FileWriter(logdir='./logs', graph=self.session.graph)def copy_model(self):
        """ Copy weights to target network """
        self.session.run([tf.assign(new, old) for (new, old) in zip(tf.trainable_variables('target'), tf.trainable_variables('online'))])def save_model(self):
        """ Saves current model to disk """
        self.saver.save(sess=self.session, save_path='./models/model', global_step=self.step)def add(self, experience):
        """ Add observation to experience """
        self.memory.append(experience)def predict(self, model, state):
        """ Prediction """
        if model == 'online':
            return self.session.run(fetches=self.output, feed_dict={self.input: np.array(state)})
        if model == 'target':
            return self.session.run(fetches=self.output_target, feed_dict={self.input: np.array(state)})def run(self, state):
        """ Perform action """
        if np.random.rand() < self.eps:
            # Random action
            action = np.random.randint(low=0, high=self.actions)
        else:
            # Policy action
            q = self.predict('online', np.expand_dims(state, 0))
            action = np.argmax(q)
        # Decrease eps
        self.eps *= self.eps_decay
        self.eps = max(self.eps_min, self.eps)
        # Increment step
        self.step += 1
        return actiondef learn(self):
        """ Gradient descent """
        # Sync target network
        if self.step % self.copy == 0:
            self.copy_model()
        # Checkpoint model
        if self.step % self.save_each == 0:
            self.save_model()
        # Break if burn-in
        if self.step < self.burnin:
            return
        # Break if no training
        if self.learn_step < self.learn_each:
            self.learn_step += 1
            return
        # Sample batch
        batch = random.sample(self.memory, self.batch_size)
        state, next_state, action, reward, done = map(np.array, zip(*batch))
        # Get next q values from target network
        next_q = self.predict('target', next_state)
        # Calculate discounted future reward
        if self.double_q:
            q = self.predict('online', next_state)
            a = np.argmax(q, axis=1)
            target_q = reward + (1\. - done) * self.gamma * next_q[np.arange(0, self.batch_size), a]
        else:
            target_q = reward + (1\. - done) * self.gamma * np.amax(next_q, axis=1)
        # Update model
        summary, _ = self.session.run(fetches=[self.summaries, self.train],
                                      feed_dict={self.input: state,
                                                 self.q_true: np.array(target_q),
                                                 self.a_true: np.array(action),
                                                 self.reward: np.mean(reward)})
        # Reset learn step
        self.learn_step = 0
        # Write
        self.writer.add_summary(summary, self.step)

训练代理玩游戏

首先,我们需要实例化环境。在这里,我们使用第一级的超级马里奥兄弟,SuperMarioBros-1-1-v0,以及一个离散的事件空间与RIGHT_ONLY的行动空间。此外,我们使用了一个包装器,该包装器将帧大小调整、堆叠和最大池、奖励剪辑以及惰性帧加载应用到环境中。

当训练开始时,代理通过采取随机行动开始探索环境。这样做是为了积累初步经验,作为实际学习过程的起点。在burin = 100000游戏帧之后,代理慢慢开始用 CNN 政策决定的动作来代替随机动作。这被称为ε贪婪政策。ε-同意意味着代理以概率\ε采取随机动作,或者以概率(1-\ε)采取基于策略的动作。这里,\epsilon 在训练期间以因子eps_decay = 0.99999975线性减小,直到它达到eps = 0.1,在训练过程的剩余时间内保持不变。重要的是不要完全消除训练过程中的随机行为,以避免陷入局部最优解。

对于采取的每个动作,环境返回四个对象:(1)下一个游戏状态,(2)采取动作的奖励,(3)如果一集结束,则返回一个标志,以及(4)包含来自环境的附加信息的信息字典。在采取动作之后,返回对象的元组被添加到重放缓冲区,并且代理执行学习步骤。学习后,当前statenext_state更新,循环递增。如果done标志为True,则 while 循环中断。这相当于马里奥的死亡或者成功完成关卡。在这里,特工接受 10000 集的训练。

import time
import numpy as np
from nes_py.wrappers import BinarySpaceToDiscreteSpaceEnv
import gym_super_mario_bros
from gym_super_mario_bros.actions import RIGHT_ONLY
from agent import DQNAgent
from wrappers import wrapper # Build env (first level, right only)
env = gym_super_mario_bros.make('SuperMarioBros-1-1-v0')
env = BinarySpaceToDiscreteSpaceEnv(env, RIGHT_ONLY)
env = wrapper(env)# Parameters
states = (84, 84, 4)
actions = env.action_space.n# Agent
agent = DQNAgent(states=states, actions=actions, max_memory=100000, double_q=True)# Episodes
episodes = 10000
rewards = []# Timing
start = time.time()
step = 0# Main loop
for e in range(episodes): # Reset env
    state = env.reset() # Reward
    total_reward = 0
    iter = 0 # Play
    while True: # Show env (disabled)
        # env.render() # Run agent
        action = agent.run(state=state) # Perform action
        next_state, reward, done, info = env.step(action=action) # Remember transition
        agent.add(experience=(state, next_state, action, reward, done)) # Update agent
        agent.learn() # Total reward
        total_reward += reward # Update state
        state = next_state # Increment
        iter += 1 # If done break loop
        if done or info['flag_get']:
            break # Rewards
    rewards.append(total_reward / iter) # Print
    if e % 100 == 0:
        print('Episode {e} - +'
              'Frame {f} - +'
              'Frames/sec {fs} - +'
              'Epsilon {eps} - +'
              'Mean Reward {r}'.format(e=e,
                                       f=agent.step,
                                       fs=np.round((agent.step - step) / (time.time() - start)),
                                       eps=np.round(agent.eps, 4),
                                       r=np.mean(rewards[-100:])))
        start = time.time()
        step = agent.step# Save rewards
np.save('rewards.npy', rewards)

在每一集游戏结束后,这一集的平均奖励将被添加到rewards列表中。此外,每 100 集后会打印不同的统计数据,如每秒帧数和当前 epsilon。

重播

在训练期间,程序在save_each = 500000帧检查当前网络,并在磁盘上保存 10 个最新型号。我在培训期间下载了几个模型版本到我的本地机器上,并制作了下面的视频。

看到代理人的学习进步真是太牛逼了!在 Google Cloud 上的 GPU 加速虚拟机上,培训过程花费了大约 20 个小时。

总结与展望

强化学习是机器学习中令人兴奋的领域,同样在科学和商业中提供了广泛的可能应用。然而,强化学习代理的训练仍然相当麻烦,并且通常需要对超参数和网络体系结构进行冗长的调整,以便很好地工作。最近有一些进展,如 RAINBOW (多种 RL 学习策略的组合),旨在为训练强化学习代理提供更强大的框架,但该领域仍然是一个活跃的研究领域。除了 Q-learning,强化学习中还有许多其他有趣的训练概念被开发出来。如果您想尝试不同的 RL 代理和培训方法,我建议您查看稳定基线,这是一个轻松使用最先进的 RL 代理和培训概念的好方法。

如果你是一个深度学习初学者,并且想了解更多,你应该查看我们全新的 STATWORX 深度学习训练营,这是一个为期 5 天的现场介绍,涵盖了开发你的第一个深度学习模型所需知道的一切:神经网络理论,反向传播和梯度下降,Python,TensorFlow 和 Keras 中的编程模型,CNN 和其他图像识别模型,时间序列数据和 NLP 的递归网络和 LSTMs,以及深度强化学习和 GANs 等高级主题。

如果您对我的帖子有任何意见或问题,请随时联系我!此外,请随意使用我的代码(链接到 GitHub repo )或在你选择的社交平台上与你的同行分享这篇文章。

如果你对更多类似的内容感兴趣,请加入我们的邮件列表,不断为你带来来自我和我在 STATWORX 的团队的新鲜数据科学、机器学习和人工智能阅读和对待!

最后,如果你对更多感兴趣,请在 LinkedIn 上关注我,或者在 Twitter 上关注我的公司网站!

原载于 2019 年 5 月 29 日https://www.statworx.com

使用最先进的技术优化深度学习交易机器人

原文:https://towardsdatascience.com/using-reinforcement-learning-to-trade-bitcoin-for-massive-profit-b69d0e8f583b?source=collection_archive---------0-----------------------

让我们教我们的深度 RL 代理使用特征工程和贝叶斯优化赚更多的钱

在上一篇文章中,我们使用深度强化学习创造了不赔钱的比特币交易机器人。虽然代理商盈利了,但结果并不令人印象深刻,所以这次我们要更上一层楼,大幅提高我们模型的盈利能力。

提醒一下,这一系列文章的目的是试验最先进的深度强化学习技术,看看我们能否创造出盈利的比特币交易机器人。现状似乎是迅速关闭任何创建强化学习算法的尝试,因为这是“构建交易算法的错误方式”。然而,该领域的最新进展表明,在相同的问题域内,RL 代理通常能够比监督学习代理学习更多的东西。出于这个原因,我写这些文章是为了看看这些交易代理能给我们带来多大的利润,或者说现状的存在是有原因的。

我们将首先改进我们的模型的策略网络,并使输入数据集保持稳定,这样我们就可以从更少的数据中学习更多的知识。接下来,我们将使用高级特征工程来改善我们的代理的观察空间,并微调我们的奖励函数,以产生更有吸引力的策略。最后,我们将使用一种称为贝叶斯优化的技术,在训练和测试最终代理盈利能力之前,锁定最有利可图的超参数。各位坐稳了,这将是一场疯狂的旅程。

[## 更明智地交易和投资——强化学习方式

深入探讨 TensorTrade——一个用于培训、评估和部署稳健交易的开源 Python 框架…

towardsdatascience.com](/trade-smarter-w-reinforcement-learning-a5e91163f315)

当你读完这篇文章后,看看TensorTrade——这篇文章中产生的代码库的后继框架。

修改

为了提高我们模型的盈利能力,我们需要做的第一件事是对我们在上一篇文章中写的代码做一些改进。如果你还没有代码,可以从我的 GitHub 中抓取。

循环网络

我们需要做的第一个改变是更新我们的策略,使用一个循环的长短期记忆(LSTM)网络,代替我们以前的多层感知器(MLP)网络。由于循环网络能够随着时间的推移保持内部状态,我们不再需要滑动的“回顾”窗口来捕捉价格行为的运动。相反,它被网络的递归性质所固有地捕获。在每个时间步,来自数据集的输入与来自最后一个时间步的输出一起被传递到算法中。

Source: https://adventuresinmachinelearning.com/recurrent-neural-networks-lstm-tutorial-tensorflow/

这允许 LSTM 维护一个内部状态,当代理“记住”和“忘记”特定的数据关系时,该状态在每个时间步得到更新。

Source: https://adventuresinmachinelearning.com/recurrent-neural-networks-lstm-tutorial-tensorflow/

Here we update our PPO2 model to use the MlpLstmPolicy, to take advantage of its recurrent nature.

平稳数据

我在上一篇文章中还指出,我们的时间序列数据不是稳定的,因此,任何机器学习模型都将很难预测未来的值。

平稳时间序列的均值、方差和自相关(与自身的滞后相关)是恒定的。

底线是,我们的时间序列包含一个明显的趋势和季节性,这两个影响我们的算法准确预测时间序列的能力。我们可以通过使用差分和转换技术从现有的时间序列中产生一个更正态的分布来解决这个问题。

差分是从每个时间步长的值中减去该时间步长的导数(回报率)的过程。在我们的例子中,这有消除趋势的预期结果,但是,数据仍然有明显的季节性。我们可以尝试通过在差分前对每个时间步长取对数来消除这种影响,这将产生最终的平稳时间序列,如下图右侧所示。

我们可以通过运行一个增强的 Dickey-Fuller 测试来验证产生的时间序列是平稳的。这样做得到的 p 值为 0.00,允许我们拒绝测试的零假设,并确认我们的时间序列是平稳的。

Here we run the Augmented Dicker-Fuller Test on our transformed data set to ensure stationarity.

现在我们已经解决了这个问题,我们将使用一点特征工程来进一步更新我们的观察空间。

特征工程

为了进一步改进我们的模型,我们将做一些功能工程。

特征工程是使用特定领域的知识来创建额外输入数据以改进机器学习模型的过程。

在我们的案例中,我们将向我们的数据集添加一些常见但有见地的技术指标,以及来自 StatsModels SARIMAX 预测模型的输出。技术指标应该向我们的数据集添加一些相关的滞后信息,这将由我们的预测模型的预测数据很好地补充。这些特性的组合应该为我们的模型提供一个很好的有用观察的平衡。

技术分析

为了选择我们的技术指标集,我们将比较[ta](https://github.com/bukosabino/ta) 中所有 32 个指标(58 个特征)的相关性。我们可以使用pandas找到同一类型(动量、成交量、趋势、波动)的每个指标之间的相关性,然后从每个类型中只选择相关性最小的指标作为特征。这样,我们可以从这些技术指标中获得尽可能多的好处,而不会给我们的观察空间增加太多的噪音。

Seaborn heatmap of technical indicator correlation on BTC data set.

事实证明,波动率指标和一些动量指标都是高度相关的。当我们移除所有重复的特征(在它们的组内具有绝对平均相关性> 0.5 的特征)时,我们剩下 38 个技术特征添加到我们的观察空间。这是完美的,所以我们将创建一个名为add_indicators的实用方法来将这些特征添加到我们的数据框中,并在我们的环境初始化中调用它,以避免必须在每个时间步长上计算这些值。

Here we initialize our environment, adding the indicators to our data frame before making it stationary.

统计分析

接下来我们需要添加我们的预测模型。我们选择使用季节性自回归综合移动平均(SARIMA)模型来提供价格预测,因为它可以在每一步快速计算,并且在我们的静态数据集上相当准确。另外,它实现起来非常简单,并且允许我们为它的未来预测创建一个置信区间,这通常比单个值更有洞察力。例如,当置信区间很小时,我们的主体可以学习更加谨慎地相信预测,而当置信区间很大时,我们的主体可以学习冒更大的风险。

Here we add the SARIMAX predictions and confidence intervals to our observation space.

既然我们已经更新了政策,使用了更适用的循环网络,并通过上下文特征工程改善了我们的观察空间,现在是优化所有事情的时候了。

奖励优化

有人可能会认为我们上一篇文章中的奖励函数(即奖励增加的净值收益)是我们所能做到的最好的,然而,进一步的研究表明这与事实相差甚远。虽然我们上次的简单回报函数能够盈利,但它产生了不稳定的策略,经常导致资本的巨大损失。为了改善这一点,除了简单的未实现利润之外,我们还需要考虑其他奖励指标。

正如 Sean O'Gordman 在我上一篇文章的评论中提到的,对这个策略的一个简单的改进是,不仅在价格上涨时奖励持有 BTC 的利润,而且在价格下跌时奖励不持有 BTC 的利润。例如,当我们的代理持有 BTC/美元头寸时,我们可以对其净值的任何增量增加进行奖励,而当其不持有任何头寸时,我们可以对其 BTC/美元价值的增量减少进行奖励。

虽然这种策略在奖励增加的回报方面很棒,但它没有考虑到产生这些高回报的风险。投资者早就发现了简单利润指标的这一缺陷,传统上转向风险调整后的回报指标来解释这一缺陷。

基于波动性的指标

最常见的风险调整回报指标是夏普比率。这是一个简单的投资组合的超额收益与波动性的比率,在一段特定的时间内测量。为了保持高夏普比率,投资必须同时具有高回报和低波动性(即风险)。其数学原理如下:

这一指标经受住了时间的考验,然而它对我们的目的来说也是有缺陷的,因为它惩罚了上行波动。对于比特币来说,这可能会有问题,因为参与上行波动(价格大幅上涨)通常会非常有利可图。这就引出了我们将与代理一起测试的第一个奖励指标。

索蒂诺比率与夏普比率非常相似,只是它只将下行波动视为风险,而不是整体波动。因此,这一比率不会对上行波动造成不利影响。数学是这样的:

其他指标

我们将在该数据集上测试的第二个奖励指标是 Calmar 比率。到目前为止,我们的所有指标都没有考虑到的缩减

提取是衡量投资组合价值从高峰到低谷的具体损失。

大额提款可能不利于成功的交易策略,因为长期的高回报可能会被突然的大额提款迅速逆转。

为了鼓励积极防止大规模提款的策略,我们可以使用专门说明这些资本损失的奖励指标,如卡尔马比率。这个比率与夏普比率相同,除了它使用最大提款来代替投资组合价值的标准差。

我们的最后一个指标是欧米伽比率,在对冲基金行业被大量使用。理论上,在衡量风险与回报时,Omega 比率应优于 Sortino 和 Calmar 比率,因为它能够在单一指标中说明风险与回报分布的整体情况。要找到它,我们需要计算一个投资组合在特定基准之上或之下移动的概率分布,然后取两者之比。比率越高,上涨潜力超过下跌潜力的概率就越高。

If this looks complicated, don’t worry. It get’s simpler in code.

代码

虽然为这些奖励指标中的每一个写代码听起来真的 有趣,但是我选择使用[empyrical](https://github.com/quantopian/empyrical) 来计算它们。幸运的是,这个库恰好包含了我们上面定义的三个奖励标准。获取每个时间步长的比率非常简单,只需向相应的经验函数提供一段时间内的回报和基准回报列表。

Here we set the reward at each time step based on our pre-defined reward function

既然我们已经决定了如何衡量一个成功的交易策略,是时候找出这些指标中哪一个能产生最吸引人的结果了。让我们将这些奖励函数中的每一个都插入到 Optuna 中,并使用传统的贝叶斯优化来为我们的数据集找到最佳策略。

工具集

任何优秀的技术人员都需要一套优秀的工具。我们不会重新发明轮子,而是要利用我们之前的程序员的痛苦和折磨。对于今天的工作,我们最重要的工具将是optuna库,它使用树结构 Parzen 估计器 (TPEs)实现贝叶斯优化。TPE 是可并行化的,这允许我们利用我们的 GPU,大大减少了我们的总搜索时间。简而言之,

贝叶斯优化是一种有效搜索超空间以找到最大化给定目标函数的参数集的技术。

简单来说,贝叶斯优化是改进任何黑盒模型的有效方法。它通过使用代理函数或代理函数的分布来建模您想要优化的目标函数。随着算法探索超空间和产生最大价值的区域,这种分布会随着时间而改善。

这如何适用于我们的比特币交易机器人?本质上,我们可以使用这种技术来找到使我们的模型最有利可图的一组超参数。我们正在大海捞针,贝叶斯优化是我们的磁铁。让我们开始吧。

实施 Optuna

用 Optuna 优化超参数相当简单。首先,我们需要创建一个optuna研究,它是我们所有超参数试验的父容器。试验包含超参数的特定配置及其从目标函数产生的成本。然后我们可以调用study.optimize()并传入我们的目标函数,Optuna 将使用贝叶斯优化来找到产生最低成本的超参数配置。

在这种情况下,我们的目标函数包括在我们的比特币交易环境中训练和测试我们的 PPO2 模型。我们从函数中返回的成本是测试期间的平均回报,被否定。我们需要否定平均回报,因为 Optuna 将较低的回报值解释为更好的试验。optimize函数为我们的目标函数提供了一个试验对象,然后我们用它来指定要优化的每个变量。

optimize_ppo2()optimize_envs()方法接受一个试验对象并返回一个参数字典进行测试。我们每个变量的搜索空间由我们在试验中调用的特定suggest函数定义,我们将参数传递给该函数。

例如,trial.suggest_loguniform('n_steps', 16, 2048)将以对数方式建议 16–2048 之间的新浮点数(16,32,64,…,1024,2048)。此外,trial.suggest_uniform('cliprange’, 0.1, 0.4)将以一种简单的、相加的方式建议浮点数(0.1,0.2,0.3,0.4)。我们在这里不使用它,但是 Optuna 也提供了一个建议分类变量的方法:suggest_categorical('categorical', ['option_one', ‘option_two'])

稍后,在使用合适的 CPU/GPU 组合运行我们的优化功能一夜之后,我们可以从我们告诉 Optuna 创建的 sqlite 数据库中加载研究。这项研究跟踪其测试中的最佳试验,我们可以用它来获取我们环境的最佳超参数集。

我们修改了我们的模型,改进了我们的功能集,优化了我们所有的超参数。现在是时候看看我们的代理商如何使用他们的新奖励机制了。我已经训练了一个代理人来优化我们的四个回报指标:简单利润、索提诺比率、卡尔马尔比率和奥米加比率。让我们在一个测试环境中运行每一个优化的代理,这个测试环境是用它们没有被训练过的价格数据初始化的,看看它们是否有利可图。

标杆管理

在我们看结果之前,我们需要知道成功的交易策略是什么样的。对于这种叛逆,我们将参照几个常见但有效的交易比特币获利的策略。信不信由你,在过去的十年里,交易 BTC 最有效的策略之一就是买入并持有。我们将要测试的另外两个策略使用非常简单,但是有效的技术分析来产生买入和卖出信号。

  1. 买入并持有

这个想法是尽可能多的购买,并尽最大努力持有(HODL)。虽然这种策略并不特别复杂,但它在过去取得了很高的成功率。

2.RSI 背离

当连续收盘价随着 RSI 继续下降而继续上涨时,这是一个负面趋势反转(卖出)的信号。当收盘价随着 RSI 连续上升而连续下跌时,表明趋势正反转(买入)。

3.简单移动平均线交叉

当长期的 SMA 在短期的 SMA 上面交叉时,一个负面的趋势反转(卖出)信号被发出。当短期的 SMA 在长期的 SMA 上面交叉时,一个积极的趋势反转(买入)被发出信号。

根据这些简单的基准测试的目的是证明我们的 RL 代理实际上在市场上创造 alpha。如果我们不能击败这些简单的基准测试,那么我们就是在浪费无数小时的开发时间和 GPU 周期,只是为了做一个很酷的科学项目。让我们证明事实并非如此。

结果呢

我必须在这一节之前声明,这一节中的正利润是错误代码的直接结果。由于当时的日期排序方式,代理商可以随时提前 12 小时看到价格,这是一种明显的前瞻偏差。这个问题已经得到了解决,尽管还没有投入时间来替换下面的每个结果集。请理解,这些结果是完全无效的,极不可能被复制。

也就是说,仍然有大量的研究进入了这篇文章,目的从来不是为了赚大量的钱,而是为了看看当前最先进的强化学习和优化技术有什么可能。因此,为了让这篇文章尽可能地接近原文,我将把旧的(无效的)结果留在这里,直到我有时间用新的、有效的结果来替换它们。

代理在数据集的前 80%接受训练(来自 CryptoDataDownload 的每小时 OHCLV 数据),并在最后 20%接受测试,以查看策略如何推广到新数据。这种简单的交叉验证足以满足我们的需求,因为当我们最终将这些算法发布到野外时,我们可以在整个数据集上进行训练,并将新的输入数据视为新的测试集。

让我们快速浏览失败者,这样我们就能得到好的东西。首先,我们有欧米茄策略,这最终是对我们的数据集相当无用的交易。

Average net worth of Omega-based agents over 3500 hours of trading

观察这个代理交易,很明显这个奖励机制产生了过度交易的策略,并且不能利用市场机会。

基于 Calmar 的策略比基于 Omega 的策略稍有改进,但最终结果非常相似。看起来我们已经投入了大量的时间和精力,只是为了让事情变得更糟…

Average net worth of Calmar-based agents over 3500 hours of trading

还记得我们的老朋友,简单的增量利润吗?虽然在我们的上一篇文章中,这种奖励机制并不太成功,但我们所做的所有修改和优化似乎都极大地提高了代理的成功率。

在我们四个月的测试期内,平均利润刚刚超过初始账户余额的 350% 。如果你不知道平均市场回报,这种结果绝对是疯狂的。当然,这是我们在强化学习中所能做到的最好的了…对吗?

Average net worth of Profit-based agents over 3500 hours of trading

不对。按排序比例奖励的代理商产生的平均利润接近 850% 。当我看到这些策略的成功时,我必须快速检查以确保没有错误。编者注:准备好接受下面这句话的讽刺吧。]经过彻底检查后,很明显代码没有错误,这些代理只是非常擅长交易比特币。

Average net worth of Sortino-based agents over 3500 hours of trading

这些代理人没有过度交易和资金不足,而是似乎明白低买高卖的重要性,同时将持有 BTC 的风险降至最低。不管代理人学会了什么具体策略,我们的交易机器人显然已经学会了交易比特币并从中获利。如果你不相信我,你自己看吧。

One of the Sortino-based agents trading BTC/USD. Green triangles signal buys, red triangles signal sells.

我不是傻瓜。我明白,这些测试的成功可能[阅读:不会]推广到现场交易。也就是说,这些结果远比我迄今为止见过的任何算法交易策略都令人印象深刻(这应该是出了问题的第一个线索……)。考虑到这些代理人事先不知道市场如何运作或如何盈利交易,而是通过反复试验(以及一些良好的前瞻性偏见)学会了获得巨大成功,这确实令人惊讶。很多很多的尝试和错误。

结论

在这篇文章中,我们优化了我们的强化学习代理,以便在交易比特币时做出更好的决策,从而赚更多的钱!这需要做相当多的工作,但我们通过以下方式成功完成了这项工作:

  • 升级现有模型,使用具有固定数据的循环 LSTM 政策网络
  • 工程师使用特定领域的技术和统计分析为代理学习 40 多项新功能
  • 改善代理人的报酬系统,考虑风险,而不是简单的利润
  • 使用贝叶斯优化微调模型的超参数
  • 以普通交易策略为基准,确保机器人总是跑赢市场

理论上,高利润的交易机器人是伟大的。然而,我收到了相当多的反馈,声称这些代理人只是在学习拟合曲线,因此,在实时数据上交易永远不会盈利。虽然我们在独立数据集上训练/测试的方法应该可以解决这个问题,但是我们的模型可能过度适合这个数据集,而可能不能很好地推广到新数据。也就是说,我有一种感觉,这些代理正在学习的不仅仅是简单的曲线拟合,因此,他们将能够在实时交易中获利。

为了对这一假设进行实验,在社区的帮助下,我建立了一个成熟的强化学习框架,用于交易股票、外汇、加密货币和任何其他带有 API 的金融工具。下面来看看吧。

[## 更明智地交易和投资——强化学习方式

深入探讨 TensorTrade——一个用于培训、评估和部署稳健交易的开源 Python 框架…

towardsdatascience.com](/trade-smarter-w-reinforcement-learning-a5e91163f315)

作为一个题外话,仍然有很多事情可以做,以提高这些代理的性能,但是我只有这么多时间,我已经在这篇文章上工作了太长时间,不能再推迟发布了。如果你感兴趣,拿着我做的和去改进它吧!如果你能击败我的结果,把你得到的发给我,我们谈谈。

重要的是要明白,本文中记录的所有研究都是出于教育目的,不应作为交易建议。你不应该根据本文定义的任何算法或策略进行交易,因为你很可能会失去你的投资。

感谢阅读!一如既往,本教程的所有代码都可以在我的 GitHub 上找到。如果您有任何问题或反馈,请在下面留下评论,我很乐意收到您的来信!我也可以通过@notadamking 上的Twitter联系到。

你也可以通过下面的链接在 Github 赞助商 或者Patreon上赞助我。

[## GitHub 赞助商

嗨,我是亚当。我是一名开发人员、作家和企业家,尤其对深度…

github.com](https://github.com/users/notadamking/sponsorship)

Github 赞助商目前正在 1:1 匹配所有捐款,最高可达 5000 美元!

[## 亚当·金正在创造改变世界的内容

嗨,我是亚当。我是一名开发人员、作家和企业家,尤其对深度…

patreon.com](https://patreon.com/notadamking)

资源

[1.]《Python 和 TensorFlow 中的递归神经网络和 LSTM 教程》机器学习历险记,2017 年 10 月 9 日。

[2.] “用 Python 进行时间序列预测的 SARIMA 简介。”机器学习掌握,2019 年 5 月 12 日。

[3.】辛格,艾西瓦娅。"用 Python 处理非平稳时间序列的简明介绍."分析 Vidhya ,2019 年 5 月 7 日。

[4.] “超参数优化算法”神经信息处理系统进展 24 (NIPS 2011),2011。

[5.] 普拉多马科斯洛佩斯德。金融机器学习的进展。威利,2018。

使用 RNNs 进行机器翻译

原文:https://towardsdatascience.com/using-rnns-for-machine-translation-11ddded78ddf?source=collection_archive---------8-----------------------

Photo by Atharva Tulsi on Unsplash

介绍 RNN 和 LSTM 网络及其应用。

故事是人类文化的精髓。它们包含了我们过去的信息和未来的理论。它们让我们能够深入人类思维的内部运作和微妙之处,发现传统上不可能分析的方面。

虽然过去故事总是由我们人类撰写,但随着深度学习领域的发展和研究,我们看到计算机程序能够编写故事,并像人类一样使用语言,但如何做到呢?

当你读最后两段时,你对每个单词的理解都是基于前面的句子和单词。你用以前的数据来理解现在的数据。传统的神经网络会查看循环中的每个单词,并且只理解每个单词的字面意思,而不考虑其上下文或之前可能添加了信息的任何单词。这使得它们在试图理解上下文(和过去的信息)重要的信息时非常糟糕。那么我们如何解决这个问题呢?

递归神经网络

RNNs 是一种特殊类型的神经网络,具有循环,允许信息在网络的不同步骤中保持不变。

该循环使神经网络在决定当前单词的实际意思之前,返回并检查所有先前单词中发生的事情。RNN 可以被认为是一次又一次地复制粘贴同一个网络,每一次新的复制粘贴都会比前一次添加更多的信息。

RNN 神经网络的应用与传统神经网络有很大的不同,因为它们没有一个输出和输入集作为一个具体的值,相反,它们把序列作为输入或输出。

那么我们可以用 RNNs 做什么呢?

  • 自然语言处理
  • 股票市场数据(时间序列分析)
  • 图像/视频字幕
  • 翻译
  • 还有更多

RNN 也有不同的模式可以效仿。

  1. 固定到序列

RNN 接受固定大小的输入,并输出一个序列。

Image captioning takes an image and outputs a sentence of words

2.序列到固定

RNN 接受一个输入序列并输出一个固定的大小。

Sentiment analysis where a given sentence is classified as expressing positive or negative sentiment

3.序列到序列

RNN 接收一个输入序列并输出一个序列。

Machine Translation: an RNN reads a sentence in one language and then outputs it in another

这应该有助于你对 RNNs 有一个高层次的理解,如果你想了解更多关于 RNN 运算背后的数学知识,我推荐你查看这个链接

消失梯度问题

这个问题发生在任何使用基于梯度的优化技术的网络中。当计算反向传播时(计算相对于权重的损失梯度),随着反向传播算法在网络中移动,梯度变得非常小。这导致早期层的学习速度比后期层慢。这降低了 rnn 的有效性,因为它们通常不能完全考虑长序列。随着所需信息之间的差距越来越大,RNN 变得越来越低效。

现在,这个问题的一个常见解决方案是使用不会导致渐变消失的激活函数,如 RELU,而不是其他激活函数,如 sigmoid 或双曲线正切。一个更好的解决方法是使用长短期记忆网络!

长短期记忆

LSTM 网络的建立只有一个目的——解决传统无线网络的长期依赖性问题。记住很久以前的事情是他们与生俱来的天性,他们根本不会为此而挣扎。

The repeating module in an LSTM contains 4 layers, as opposed to only one in an RNN.

LSTMs 工作良好的原因主要是由于网络中存在的小区状态。这是您在图中看到的穿过网络顶部的线。信息很容易在细胞状态中流动而不会改变。连接到单元状态的门能够在需要时添加或删除信息。有一堆更复杂的数学材料,你可以在这里阅读更多关于的内容,但总的来说,LSTMs 真的很擅长记忆旧信息。

神经机器翻译

既然我们对 LSTMs 和 RNNs 有了基本的了解,让我们试着用 Keras 开发一个机器翻译模型。

这将演示一个序列到序列 LSTM 网络如何被用来将文本从英语翻译成法语。数据可以在这里找到。

我们从 Keras 导入 LSTM 层,并在这里设置几个重要的变量。

现在我们需要我们的文本矢量化成数字格式,这使得神经网络更容易处理。你可以在这里阅读更多关于这是如何工作的

现在我们需要创建我们的模型。因为这是一个序列到序列模型,我们需要两个部分——编码器和解码器。编码器抛出一个隐藏状态,它包含了作为输入获得的所有信息。然后,解码器获取这些信息,然后生成指定格式的输出(在本例中是法语)。

在这之后,就像训练模型和使用它一样简单。所有代码的详细回顾可以在这里找到。在我的网站上查看现场演示。

TL;速度三角形定位法(dead reckoning)

RNNs 和 LSTM 网络今天正在提供非常酷的用例,我们看到它在大量技术中得到应用。

递归神经网络不同于传统的人工神经网络,因为它们不需要固定的输入/输出大小,并且它们还使用以前的数据来进行预测。

LSTM 网络是专门为解决 rnn 中的长期依赖性问题而制造的,并且它们超级擅长通过使用小区状态来利用来自前一段时间的数据(这是其本质所固有的)。

如果你喜欢我的文章或者学到了新东西,请务必:

使用 Rtweet R package 与肯尼亚电力和照明公司(KPLC)一起分析肯尼亚人的困境。

原文:https://towardsdatascience.com/using-rtweet-r-package-to-analyze-the-plight-of-kenyans-with-the-kenya-power-lighting-77f6b1cd4bce?source=collection_archive---------35-----------------------

Kenyans on the streets demonstrating against KPLC.

引言。

肯尼亚电力和照明公司(KPLC)向肯尼亚各地的客户输送、分配和零售电力。它是服务的唯一提供者。

在过去的几周里,肯尼亚人在推特上表达了他们对公用事业公司糟糕的服务的不满。KPLC 意识到了困境,但正在花时间解决这个问题。

在本文中,我们将使用 Rtweet 包来收集和分析针对 KPLC 的 twitter 投诉,并更好地了解肯尼亚人在使用 KPLC 服务时所面临的问题。

入门。

我们必须建立一个 twitter 账户(如果你没有的话)。

使用这个帐户,我们将建立一个应用程序,能够使用 r 访问 twitter。

关于在 twitter 中设置应用程序以访问推文的全面指南,请阅读使用您的 twitter 帐户设置 twitter 应用程序中的指南。

我们将使用 rtweet、tidy texttidy verse**软件包,并使用以下命令安装它们:**

***Install.packages(c(“rtweet”,”tidytext”,”tidyverse”))***

然后,我们将使用以下命令加载库:

*****#loading required libraries*** *library(rtweet)
library(tidyverse)
library(tidytext)***

在推特上搜索对 KPLC 的投诉。

让我们首先找到所有带有 KPLC 标签的推文。我们将使用带有以下参数的search _ tweets()函数:

问 —这是我们要寻找的查询词。

n —我们希望返回的推文数量。twitter 设定的最大限额是 18000 条推文。

Include_rts() —如果我们想要包含共享的推文(retweets),我们将它设置为 TRUE,否则我们使用 FALSE。

郎:我们将只过滤那些英文推文。

****#collecting tweets**kplc<-search_tweets(q=”KPLC”,n=15000,lang=”en”,include_rts = FALSE)**

策划推文。

下图显示了从 7 月 24 日到 7 月 31 日每天生成的推文的时间序列。大多数推文都是在 7 月 24 日生成的,有趣的是,这一天正是示威游行在街头举行的日子。

****#plot time series of the tweets**
kplc %>% ts_plot(by="days",trim = 1L)+
          geom_point()+
          theme_minimal()+
          theme(plot.title = element_text(size=15, hjust=0.5, face="bold", colour="red", vjust=-1),
                 plot.subtitle=element_text(size=10, hjust=0.5, face="italic", color="red"))+
          labs(x="Day of Tweet",y="Tweet Count",title = "COMPLAINTS TWEETS COUNTS FOR THE PAST DAYS",
               subtitle = "Tweet Count Generated on a daily basis")**

Tweet counts per day by the KPLC customers

清洁&分析客户投诉推文。

我们将分析推特上使用的文本,以理解肯尼亚人对公用事业公司的困境。

****#preview of the text elements**
head(kplc$text)
[1] "[@KenyaPower_Care](http://twitter.com/KenyaPower_Care) Dear Kenya Power. It's been 5months since our power was disconnected ostensibly to investigate unlawful connection of power by an individual living among us in Utawala. We have made countless trips to KPLC offices to pursue this matter in vain. This darkness is a security threat."
[2] "[@KenyaPower_Care](http://twitter.com/KenyaPower_Care) Dear Kenya Power. It's been 5months since our power was disconnected ostensibly to investigate unlawful connection of power by an individual living among us in Utawala. We have made countless trips to KPLC offices to pursue this matter in vain. This darkness is a security threat."                 
[3] "[@KenyaPower_Care](http://twitter.com/KenyaPower_Care) [@kot](http://twitter.com/kot) [@citizentvkenya](http://twitter.com/citizentvkenya) how long do one  need to visit kplc office for your matter to be solved?\n#kplcmonoply should stop"** 

在进行分析时,URL 并不重要,我们将通过以下命令消除它们:

****#removing http element**
kplc$text<-gsub("http.*","",kplc$text)**

然后我们将使用 tidytext 包中的 unnest_tokens() 函数来神奇地清理文本。该函数清除以下内容:

与文本相关的所有标点符号(逗号、句号)都将被删除。

添加与每个 tweeted 单词的出现相关联的唯一 id。

推文被转换成小写。

我们创建一个新的变量单词来保存清理后的文本。

****#remove punctuation, convert to lowercase, add id for each** tweettext_clean<-kplc %>% select(text) %>% unnest_tokens(word,text)**

然后,我们将按照出现的顺序对前 20 个单词进行排序,并绘制结果。

****#plotting the top 20 words in the tweets**text_clean %>% count(word,sort = TRUE) %>%top_n(20) %>%mutate(word=reorder(word,n)) %>%ggplot(aes(x=word,y=n))+geom_col()+coord_flip()+theme_minimal()+theme(plot.title = element_text(size=15, hjust=0.5, face="bold", colour="red", vjust=-1))+labs(x="Unique Words",y="Word Count",title="Count Of Unique Words Used")**

Unique words used in the complaints tweets

从我们的情节来看,有些独特的词,如 to、From、on、at,对我们的分析来说并不重要。这些字是 停止字 ,我们将使用 anti_join() 命令删除它们。

****#removing stop words**
kplc_clean<-text_clean %>% anti_join(stop_words)**

然后,我们只过滤推文中使用的前 10 个词,然后绘制结果。

****#plotting top 10 words**
kplc_clean %>% count(word,sort = TRUE) %>%
  top_n(10) %>%
  mutate(word=reorder(word,n)) %>%
  ggplot(aes(x=word,y=n))+
  geom_col()+
  coord_flip()+
  theme_minimal()+
  theme(plot.title = element_text(size=15, hjust=0.5, face="bold", colour="red", vjust=-1))+
  labs(x="Unique Words",y="Word Count",
      title="Count Of Unique Words Used")**

Top unique words used in the text

结果。

Kenyapower_care 是公用事业公司的客户关怀 twitter 句柄,因此大多数投诉都引用该句柄,同时在 Twitter 上发布他们的问题。

账户、预付费、已确认、mpesa、transcation、余额 都是向 KPLC 某预付费账户的移动资金转账报文。大多数发推的客户都有他们预付 KPLC 账户的问题,希望服务提供商解决这个问题。

探索一起出现的单词。

我们希望通过探索一起出现的单词来对文本做进一步的分析,以获得更多的见解。

我们将使用 widyr 软件包进行分析。

*****#loading package***
library(widyr)**

我们将使用unnest _ token()函数对文本进行清理,并保存在一个名为 paired_words 的变量中。 ngrams 指定单词是成对的, n 是单词在一起的个数。

我们对一起使用的前 10 个单词进行排序,然后输出一个图。

*****#exploring words that occur together***
library(widyr)
kpl_pairs<-kplc %>% select(text) %>% unnest_tokens(paired_words,text,token = "ngrams",n=5)kpl_pairs %>% count(paired_words,sort = TRUE) %>% top_n(10) %>%
   mutate(paired_words=reorder(paired_words,n)) %>%
  ggplot(aes(x=paired_words,y=n))+
  geom_col()+
  coord_flip()+
  theme_minimal()+
  theme(plot.title = element_text(size=15, hjust=0.5, face="bold", colour="red", vjust=-1))+
  labs(x="Unique Words",y="Word Count",
      title="Count Of Unique Words Used")**

Exploring words used together in the tweets

为预付 KPLC 账户发送的大部分移动货币(M-Pesa)金额在 【凯斯 500】凯斯 1000凯斯 100凯斯 300 的维度中。

分析 KPLC 对投诉的回应。

在这个分析中,我们将分析公用事业公司 customer care 如何回应 twitter 投诉。

我们将使用get _ timeline()函数来获取客户关怀 twitter 句柄专门发送的推文数量(n)。

*****# obtaining customer care response tweets***
kplc_timeline<-get_timeline("KenyaPower_Care",n=10000)**

我们将清理后的文本保存在变量 care_response 中,然后绘制输出。

Response by Kenya power customer care

KPLC 客户服务部无法立即解决该问题,并要求客户在处理令牌生成问题时保持耐心。

结论。

我们从 twitter 文本分析中获得了关于肯尼亚人与公用事业公司 KPLC 的困境的宝贵见解。

有关收集和分析 Twitter 数据的更多指导,您可以查看以下链接:

https://mkearney.github.io/nicar_tworkshop/#1

** [## 用 R 中的 TidyText 挖掘 Twitter 数据

完成本教程后,您将能够:清理或“管理”社交媒体数据,为分析做准备。使用…

www.earthdatascience.org](https://www.earthdatascience.org/courses/earth-analytics/get-data-using-apis/text-mining-twitter-data-intro-r/) [## 社交媒体分析的力量:使用 R

介绍

medium.com](https://medium.com/@wanjirumaggie45/the-power-of-social-media-analytics-twitter-text-mining-using-r-1fceb26ac32b)

欢迎喜欢、评论和分享这篇文章。更多讨论,你可以通过 Linkedlntwitter 联系我。**

使用 Spark 预测客户流失

原文:https://towardsdatascience.com/using-spark-to-predict-churn-c69e675272bf?source=collection_archive---------30-----------------------

Image by author

在面向客户的业务中,预测客户流失是一个具有挑战性且常见的问题。由于预测通常是根据大量的用户活动日志做出的,我们需要一种分布式的方法来有效地处理大型数据集,而不必一次将它放入我们的内存中。

该项目将探索如何使用 Spark 建立客户流失预测模型,包括以下步骤:

关于数据集

我们将使用名为 Sparkify 的音乐流媒体服务的用户事件日志(持续时间约为 2 个月)作为我们的数据集。通过这些日志,我们可以预测该用户是更有可能留下来还是更有可能流失。

A log(row) will be appended whenever a user interacts with the service: play the next song, add a song to playlist, thumb up/down a song, etc.

这里,我们仅使用一个数据子集(128MB)来训练我们的带有本地 Spark 的流失预测模型。为了使用完整数据集(12GB)进行模型训练,您可能需要在云服务上部署一个集群。

加载和清理数据

加载数据

user_log = spark.read.json('mini_sparkify_event_data.json')
user_log.count()
# 286500
user_log.printSchema()
# root
 |-- artist: string (nullable = true)
 |-- auth: string (nullable = true)
 |-- firstName: string (nullable = true)
 |-- gender: string (nullable = true)
 |-- itemInSession: long (nullable = true)
 |-- lastName: string (nullable = true)
 |-- length: double (nullable = true)
 |-- level: string (nullable = true)
 |-- location: string (nullable = true)
 |-- method: string (nullable = true)
 |-- page: string (nullable = true)
 |-- registration: long (nullable = true)
 |-- sessionId: long (nullable = true)
 |-- song: string (nullable = true)
 |-- status: long (nullable = true)
 |-- ts: long (nullable = true)
 |-- userAgent: string (nullable = true)
 |-- userId: string (nullable = true)

干净的数据

在我们的数据集中检查缺失/null/空值之后,我们发现了一些事实:

  • 所有列中没有缺失(NaN)值。

  • 在与用户信息和歌曲信息相关的列中发现空值。

  • 不是NextSong的页面的artistlengthsong将为空值。

  • 仅在列userId中发现空值。

  • userId的用户是没有注册登录的用户。

由于空userId的日志无法帮助我们识别后面的用户,所以我们无法对他们进行预测。所以我们把它们从分析中去掉了。

# drop rows with empty userId
df = user_log.filter(F.col('userId')!='')
df.count()
# 278154

探索性数据分析

定义流失

我们将使用Cancellation Confirmation事件来定义客户流失。搅动的用户将在列churn中有一个1,这是我们模型的标签列。

flag_churn = F.udf(lambda x: 1 if x == 'Cancellation Confirmation' else 0, T.IntegerType())
df = df.withColumn('churn', flag_churn('page'))

转换数据

在这一步中,我们将把原始数据集(每个日志一行)转换成具有用户级信息或统计数据的数据集(每个用户一行)。在进行聚合之前,我们将首先执行以下步骤:

  1. 将时间戳(毫秒)转换为日期时间
    tsregistration列是使用以毫秒为单位的时间戳记录的,非常难以读取,因此我们将它们转换为日期时间对象,并保存为两个新列:dtreg_dt
  2. 推断每个用户的观察开始日期
    a .对于reg_dt min_dt(整个分析的开始日期)早的用户:使用min_dt作为obs_start(观察开始日期)列的值;b。对于reg_dt``min_dtfirst_dt(用户第一个日志的dt)之间有*的用户:使用reg_dt作为obs_start列的值;
    c .对于reg_dt 晚于first_dt的用户:使用first_dt作为obs_start列的值。
    奇怪的是注册日期在第一次登录日期之后,但有些用户(如 userId=154)会发生这种情况。*
  3. 推断每个用户的观察结束日期
    a .对于流失用户,使用他们最后的日志dt(他们流失的日期)作为列obs_end(观察结束日期)的值;对于非流失用户,使用max_dt(整个分析的结束日期)作为obs_end栏的值。
  4. 获取每个用户的最后订阅级别
    将用户的最后订阅级别保存到新列last_level

然后,我们按用户聚合所有必需的列:

在聚合之后,我们还提取了一些与事件相关的基于时长的特征。

并添加一些会话级特性。

最后,我们只选择这些对于以后的探索和分析是必要的列。

*root
 |-- userId: string (nullable = true)
 |-- churn: integer (nullable = true)
 |-- gender: string (nullable = true)
 |-- last_level: string (nullable = true)
 |-- sum_length: double (nullable = true)
 |-- n_session: long (nullable = false)
 |-- reg_days: integer (nullable = true)
 |-- obs_hours: double (nullable = true)
 |-- n_act_per_hour: double (nullable = true)
 |-- n_about_per_hour: double (nullable = true)
 |-- n_addFriend_per_hour: double (nullable = true)
 |-- n_addToPlaylist_per_hour: double (nullable = true)
 |-- n_cancel: long (nullable = true)
 |-- n_downgrade_per_hour: double (nullable = true)
 |-- n_error_per_hour: double (nullable = true)
 |-- n_help_per_hour: double (nullable = true)
 |-- n_home_per_hour: double (nullable = true)
 |-- n_logout_per_hour: double (nullable = true)
 |-- n_song_per_hour: double (nullable = true)
 |-- n_rollAdvert_per_hour: double (nullable = true)
 |-- n_saveSettings_per_hour: double (nullable = true)
 |-- n_settings_per_hour: double (nullable = true)
 |-- n_submitDowngrade_per_hour: double (nullable = true)
 |-- n_submitUpgrade_per_hour: double (nullable = true)
 |-- n_thumbsDown_per_hour: double (nullable = true)
 |-- n_thumbsUp_per_hour: double (nullable = true)
 |-- n_upgrade_per_hour: double (nullable = true)
 |-- avg_session_items: double (nullable = true)
 |-- avg_session_mins: double (nullable = true)
 |-- avg_session_songs: double (nullable = true)*

浏览数据

在这里,我们将重点比较留下来的用户和离开的用户之间的行为。

Distribution of Churn

Distributions of Categorical Features

Correlations among Numerical Features

根据上述相关性,我们发现这些高度相关(> 0.8)的变量对(组):

  • 流失,obs_hours,n_cancel
  • 总和 _ 长度,n _ 会话
  • 平均会话项目数,平均会话分钟数,平均会话歌曲数
  • n_act_per_hour,n_addFriend_per_hour,n_addToPlaylist_per_hour,n_downgrade_per_hour,
    n_help_per_hour,n_home_per_hour,n_song_per_hour,n_thumbsUp_per_hour

Correlations among ‘n_help_per_hour’ Numerical Features

删除高度相关的列后,相关性看起来好得多。

Correlations between Numerical Features (after removing highly correlated columns)

Distributions of Numerical Features

特征工程

现在我们总共有 16 个特性(不包括userIdlabel(churn)列)。

*root
 |-- userId: string (nullable = true)
 |-- label: integer (nullable = true)
 |-- gender: string (nullable = true)
 |-- last_level: string (nullable = true)
 |-- n_session: long (nullable = false)
 |-- reg_days: integer (nullable = true)
 |-- n_about_per_hour: double (nullable = true)
 |-- n_error_per_hour: double (nullable = true)
 |-- n_logout_per_hour: double (nullable = true)
 |-- n_song_per_hour: double (nullable = true)
 |-- n_rollAdvert_per_hour: double (nullable = true)
 |-- n_saveSettings_per_hour: double (nullable = true)
 |-- n_settings_per_hour: double (nullable = true)
 |-- n_submitDowngrade_per_hour: double (nullable = true)
 |-- n_submitUpgrade_per_hour: double (nullable = true)
 |-- n_thumbsDown_per_hour: double (nullable = true)
 |-- n_upgrade_per_hour: double (nullable = true)
 |-- avg_session_items: double (nullable = true)*

在特征工程的正常情况下,在将它们输入到我们的模型之前,我们必须将它们编码、缩放和组合成一个特征向量。但是由于我们这次使用 pipeline 来构建模型,而不是现在就处理它们,我们只是将它们准备为一些数据处理阶段。

建模

将数据分成训练集和测试集

从上一节展示的流失分布来看,我们知道这是一个不平衡的数据集,只有 1/4 的用户被标记为流失。为了避免随机分裂中的不平衡结果,我们首先用标签抽样建立一个训练集,然后从整个数据集中减去它们得到测试集。

型号选择

为了选择一个好的模型进行最终调整,我们在 Spark 的 MLlib 中比较了三个不同的分类器模型。

  • 因为 Spark 提供的评估器不太适合我们的使用,所以我们定制了一个评估方法,以便在测试原型时查看分数。

**

*<class 'pyspark.ml.classification.LogisticRegression'>
train time: 30s
----------pred_train----------
f1-score:0.88
precision:0.91
recall:0.84
accuracy:0.94
confusion matrix:
TP:32.0	 | FP:3.0
FN:6.0	 | TN:122.0
----------pred_test----------
f1-score:0.75
precision:0.90
recall:0.64
accuracy:0.90
confusion matrix:
TP:9.0	 | FP:1.0
FN:5.0	 | TN:47.0

 <class 'pyspark.ml.classification.DecisionTreeClassifier'>
train time: 23s
----------pred_train----------
f1-score:0.93
precision:1.00
recall:0.87
accuracy:0.97
confusion matrix:
TP:33.0	 | FP:0.0
FN:5.0	 | TN:125.0
----------pred_test----------
f1-score:0.62
precision:0.60
recall:0.64
accuracy:0.82
confusion matrix:
TP:9.0	 | FP:6.0
FN:5.0	 | TN:42.0

 <class 'pyspark.ml.classification.RandomForestClassifier'>
train time: 27s
----------pred_train----------
f1-score:0.88
precision:1.00
recall:0.79
accuracy:0.95
confusion matrix:
TP:30.0	 | FP:0.0
FN:8.0	 | TN:125.0
----------pred_test----------
f1-score:0.64
precision:0.64
recall:0.64
accuracy:0.84
confusion matrix:
TP:9.0	 | FP:5.0
FN:5.0	 | TN:43.0*

基于测试集的 f1 分数,我们决定使用LogisticRegression进行最终调整。

分层交叉验证的模型调整

由于被搅动的用户是一个相当小的子集,我们将使用 f1 分数作为优化的主要指标。如上所述,Spark 的评估器不太适合我们的使用,所以我们需要构建一个FbetaScore评估器类来使用交叉验证器。

因为 PySpark 的[CrossValidator](https://spark.apache.org/docs/latest/api/python/pyspark.ml.html#pyspark.ml.tuning.CrossValidator)目前只支持简单的 K-fold CV,我们将使用 pip 库[spark-stratifier](https://github.com/interviewstreet/spark-stratifier)为不平衡数据集执行分层 K-fold CV。

explainParams()maxIter参数的解释:

  • maxIter:最大迭代次数(> = 0)。(默认值:100)

现在让我们发动引擎!我们的目标是超过原型的 0.75 分。

*train time: 3113s
----------pred_train----------
f1-score:0.88
precision:0.91
recall:0.84
accuracy:0.94
confusion matrix:
TP:32.0	 | FP:3.0
FN:6.0	 | TN:122.0
----------pred_test----------
f1-score:0.75
precision:0.90
recall:0.64
accuracy:0.90
confusion matrix:
TP:9.0	 | FP:1.0
FN:5.0	 | TN:47.0*

与原型相比没有观察到改进…也许原型LogisticRegression已经是最好的了;)

特征重要性

让我们检查一下最重要的特性是否有意义。

  1. *reg_days(注册后天数)
    注册天数越短的用户越容易流失。
    从数据探索会话中数字特征的分布可以得出相同的结论。
  2. 设置-每小时检查事件
    用户检查设置越频繁,他们就越有可能流失!
  3. 每小时升级相关的事件
  4. 每小时观看的广告
  5. 每小时播放的歌曲

对我来说,这一切似乎都是合理的…尽管我期望在查看数字特征的分布时,否定事件具有更高的重要性:(

结论

到目前为止,我们已经完成了这些步骤:

关于这个项目有趣或困难的方面:

  • 如何使用 Spark 的数据框架进行聚合
  • 如何处理不平衡数据集

改进:

  • 给定一些日志作为输入,实际预测哪些用户更有可能流失
  • 在模型优化会话中探索更多参数
  • 一种更加自动化的方法来过滤掉高度相关的特征

感谢阅读!完整的代码可以在这个报告中找到。

使用 SQL 检测异常值

原文:https://towardsdatascience.com/using-sql-to-detect-outliers-aff676bb2c1a?source=collection_archive---------8-----------------------

An outlying black cat (photo by author)

SQL 不具备像 R 或 Python 这样的语言的特性,但这并不意味着你不能用它来通过寻找异常点或异常值来对数据进行初步清理。

许多数据科学家习惯于这样的工作流,即在用 R 或 Python 进行真正的工作之前,他们从符合 SQL 的数据库中吸取数据。这显然是低效的,因为这意味着有缺陷的、不正确的或由于某些其他原因最终不可用的数据需要移动到真正的分析环境中。

虽然 SQL 确实缺乏统计工具和分布库,但这并不意味着它不能用于进行有用的数据分析,只是工具集仅限于您可以动态编码的工具。

一旦知道如何检测异常值和其他数据异常,您就可以在 SQL 中轻松完成一项重要任务。我们将看看两种对 SQL 代码友好的方式。

一种这样的方法是使用中间绝对偏差来检测数据异常值。这种方法实际上比人们通常使用的 z 分数更可靠,因为它没有对数据的分布进行假设。

从概念上讲,这种方法的优点是非常简单。任意观测值的中位数绝对偏差是该观测值的绝对差与所有观测值的中位数以及所有观测值的中位数绝对差与所有观测值的中位数的比值。

在非参数统计中,工作人员已经提出了中位数绝对偏差的临界值 5,因为中位数绝对偏差值略低于 1.5 相当于一个标准偏差,所以 MAD = 5 大约等于 3 个标准偏差。

这是 SQL 编码,缺点是您需要使用一个公共表表达式或其他解决方法,因为这种方法需要对聚合函数的结果进行进一步的操作。另一个有点挑战性的部分是,在主要的 SQL 实现中还没有一个简单的“中间值”函数。在下面的代码中,我使用了' Percentile_Cont '函数,我将在下面对其进行更多的注释。

有三个步骤,需要两个 cte 来捕捉中间步骤—

  1. 求感兴趣的变量的中值。您需要这个值来进行进一步的计算,如果没有 CTE,作为一个集合是很困难的。
  2. 计算中值偏差。偏差就是上面发现的中值体重和个体体重之间的绝对差值。求这个值的中间值。
  3. 最后找到…的偏差

此处的代码创建了一个学龄前儿童的体重(以千克为单位)和年龄(以岁为单位)的表格,可能会在儿科诊所或市婴儿健康服务中心记录。最后一张表显示了每个学龄前儿童的体重及其与表中所有学龄前儿童体重中位数的偏差:

CREATE TABLE KidWts (Name nvarchar(20),Age int ,Weight float);INSERT INTO KidWts VALUES(‘Lily’,3,15), (‘Muhammad’,30,98), (‘Daphne’, 3, 16), (‘Max’, 2, 12),(‘Chloe’,1,11),(‘Jackie’,2,14),(‘Albert’,3,17);WITH MedianTab (MedianWt)AS(SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY Weight)OVER () as MedianWeightFROM KidWts),DispersionTab (AbsDispersion)AS(SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY (Abs(Weight-MedianWt)))OVER () as AbsDispersionFROM MedianTab JOIN KidWts on 1=1)Select DISTINCT *,ABS((Weight-MedianWt)/AbsDispersion) FROM KidWts Join DispersionTab on 1=1JOIN MedianTab on 1=1

该查询返回以下结果:

The results of the query — Muhammad looks a little out of place

看着表格,一个结果突出了出来——穆罕默德的 98 公斤没有,与中位数的偏差为 41.5,是非常不合适的。经过一点调查,我们意识到,原因是穆罕默德的问题,是穆罕默德阿里,98 公斤是他在 1974 年与乔治·福尔曼比赛前的体重。对一个重量级拳击手来说并不算特别重,但对一个学龄前儿童来说却不合适。可能是一个装箱悲剧 DBA 在输入真实数据之前使用装箱统计数据来测试数据库功能,并且没有完全清除测试数据—这是一个极端的例子,但并非不可能。

MAD 值 41.5 可能比您在现实生活中看到的要大,并且旨在说明只是错误地出现在数据集中的数据类型,这是现实生活数据集中出现异常或异常值的一种方式。

更详细地看代码,Percentile_Cont 函数在最新的 ANSI SQL 标准中,但这并不意味着它在 SQL 的每一个实现中都有效——我在 SQL Server 上测试过,我的信息是这个函数在 Oracle 和 PostgreSQL 中也可用。MySQL 没有这个功能,所以你需要使用另一种方法来寻找中间值。

您可能想从下面的文章中选择您最喜欢的——Joe Celko 的关于 SQL 中值的文章——但是请注意,它是在 cte 之前写的,因此可以通过用 cte 替换临时表或视图来改进这些解决方案。正如 Joe Celko 的文章所示,在 SQL 中有很多计算中位数的方法——找到适合您的方法,并相应地更新代码。

罗伯特·德格拉夫是《管理你的数据科学项目 》一书的作者,该书将于 2019 年 7 月中旬由 Apress 出版社出版。

你可以在推特上关注罗伯特:https://twitter.com/RobertdeGraaf2

使用 SQL 改进缺失值

原文:https://towardsdatascience.com/using-sql-to-improve-missing-values-d1d14cf69797?source=collection_archive---------23-----------------------

Missing data points can sometimes feel like missing jigsaw pieces (photo: author)

几个月来,我们一直在研究在数据科学中使用 SQL 的不同方式——最近一次是在中使用 SQL 检测异常值(与检测异常不同,尽管那是将来的事情)。

在这个零星系列的第一篇文章中,我们看到了如何通过计算一列中空值的比例来评估缺失数据。然而,简单地查找和计算丢失的数据点用处有限——如果您找到这些丢失的数据点,您需要有工具可以使用。

所有数据科学家都应该熟悉处理缺失值的核心方法,这句话的意思是“如果你不熟悉,你应该记住下面的列表”:

  1. 列表式删除:如果一个变量丢失了太多的事例,以至于看起来毫无用处,那就删除它。
  2. 逐例删除:如果某个特定的观察结果缺少太多因素,则将其删除。
  3. 虚拟变量调整:如果变量在特定情况下缺失,使用一个假设值代替它。根据问题的不同,中间值可能是直观的选择或代表“中性”设置的值。
  4. 插补:使用一种算法来填充值,从最基本端的简单随机数到更复杂端的由自己的模型插补的值。

很明显,SQL 在其中一些方面比其他方面更好。列表式删除就像在 SELECT 语句中去掉列名一样简单;逐例删除可能像 WHERE 子句测试空值一样简单。

使用这两种方法会带来风险——如果数据不是完全随机缺失的,您很容易引入偏差。不难想到由于数据中反映的特定情况而没有收集度量的情况。Frank Harrell 在他的书《回归建模策略》中给出的一个例子是血压测量,这些测量并不针对预期不久就会死亡的患者——因此排除了患者观察值。在患者结果模型中遗漏的血压测量值可能会选择性地排除已经死亡的患者,从而造成明显的偏差。

虽然上面的例子说明了按病例删除的风险,但从同一个例子中也可以看出按列表删除的缺点——如果你忽略所有血压信息,你就忽略了许多对解释医疗结果有用的信息。

一种更复杂的方法是使用 Paul Allison,他是 Sage 系列统计学短评《缺失数据》的作者,他称之为“虚拟变量调整”,其中包括创建一个变量来指示缺失信息的存在。您还需要更新原始变量,以包含一个常数值来代替空值。在 SQL 中,这可能是一个简单的 CASE 语句。我们假设数值常数为 2:

SELECT CASE Missing_var WHEN var is null THEN 1 ELSE 0 END, coalesce(var, 2)FROM Table

上面的代码是与实现无关的——例如,如果使用 MySQL,您可以用“ifnull”替换“isnull”函数,因为“isnull”是 null 的一个快捷逻辑测试(它可以替换上面的 CASE 语句),其他实现可能也有类似的快捷方式。

这些处理缺失值的技术是最基本的。虽然公平地说,一些最先进的技术很难在 SQL 中实现,但这些仍然可以在您的旅程中带您走一段合理的距离。

在数据库中使用执行这些步骤的一个原因是,您可以通过延迟选择建模环境(如 R、Python、Rapidminer 等)来将数据准备和探索步骤与建模步骤分离。,直到你有一个稍微准备好的数据集。您甚至可以在多个环境中执行分析以检查结果。

因此,通过使用 SQL“就地”分析数据并做一些基本的数据准备,您可以通过在第一时间转移到建模环境来保持比可能的更高程度的灵活性。

罗伯特·德格拉夫的书《管理你的数据科学项目》》已经通过出版社出版。

在 Twitter 上关注罗伯特

在 Python 中使用标准差

原文:https://towardsdatascience.com/using-standard-deviation-in-python-77872c32ba9b?source=collection_archive---------3-----------------------

Standard Deviation in Practice

Python 中的均值、标准差和误差线

正如这篇文章提到的,通过标准差,你可以了解你的数据是接近平均值还是分布在很大范围内。例如,如果一个雇主想确定他的一个部门的工资对所有员工是否公平,或者是否有很大的差异,他可以使用标准差。为此,他可以找到该部门的平均工资,然后计算标准偏差。一个场景可能如下所示:他发现标准差略高于他的预期,他进一步检查了数据,发现虽然大多数员工都属于类似的薪酬等级,但有四名忠诚的员工在该部门工作了 15 年或更长时间,比其他人长得多,由于他们在该公司工作的时间长,他们的薪酬也高得多。

一般来说,低标准偏差意味着数据与平均值非常接近,因此非常可靠,而高标准偏差意味着数据与统计平均值之间存在较大差异,因此不太可靠。

标准差最重要的应用之一是比较两个数据集。如果两个数据集有相同的平均值,这并不意味着它们一定完全相同,对吗?例如,数据集199, 200, 2010, 200, 400都具有相同的平均值(200,但是第一个数据集与第二个数据集( s =200)相比具有非常小的标准差( s =1)。

样本或总体的标准偏差

群体 数据集包含指定组的所有成员(可能数据值的完整列表)。例如,人口可能是“居住在加拿大的所有人”。 样本 数据集包含群体的一部分或子集。样本的大小总是小于被抽取样本的总体大小。例如,样本可能是“生活在加拿大的一些人”。

我们通常对了解 总体 标准差 感兴趣,因为它包含了我们想要分析的所有值。如果我们有整个人口或更大人口的样本,我们通常会计算人口标准差,但我们不想将我们的发现推广到整个人口。在许多情况下,我们有一个样本数据,我们想从中归纳出一个群体的分析。一般来说,如果您只有一个数据样本,并且想要对从中抽取样本的总体标准偏差进行陈述,则需要使用样本标准偏差。在本文中,我将重点讨论总体标准差。总体标准差公式如下:

formula from here

例如,如果我们的数据集是[13, 22, 26, 38, 36, 42,49, 50, 77, 81, 98, 110],总体均值或平均值将是:数据集中所有单个项目的总和除以项目数,结果将是53.5

现在,从集合中的每个项目中减去平均值,并计算每个数字与平均值之间的差值的平方。例如,对于第一个项目13,我们有:

(13–53.5)=(-40.5) and square of (-40.5) will be: 1,640.25

然后,对所有的平方差求和(10,581),并将这个和除以项目数。结果将是881.75‬。这个数字被称为方差。求方差的平方根,求出标准差。所以这个数据集的标准差会是29.69

Python 中的标准差

可以使用 Python 中的Numpy库计算数据集的总体均值和标准差。下面的代码展示了这项工作:

import numpy as np
dataset=[13, 22, 26, 38, 36, 42,49, 50, 77, 81, 98, 110]print('Mean:', np.mean(dataset))
print('Standard Deviation:', np.std(dataset))Mean:53.5
Standard Deviation: 29.694275542602483

在 Python 中使用标准差比较两个数据集

下面的两个数据集显示了两个城市在 15 天内的高温(以华氏度为单位)。我们想比较这两个城市气温的平均值和标准偏差。

City A= 36, 37, 36, 34, 39, 33, 30, 30, 32, 31, 31, 32, 32, 33, 35City B= 41, 35, 28, 29, 25, 36, 36, 32, 38, 40, 40, 34, 31, 28, 30

两个城市的平均气温分别是 A 市的33.4和 B 市的33.5,非常接近。两个城市都有点冷。但是 A 市的标准差2.60远小于有4.83的 B 市。这表明城市 A 的温度比城市 B 更稳定。换句话说,城市 B 的温度每天变化更大。

为了在图中显示这种变化,我在 Python 中使用了误差线。误差线对问题解决者很有用,因为它们显示了一组计算值的置信度或精度。可以使用 Python 中的matlibplot库来描述平均值和标准偏差。如下图所示,与城市 b 相比,城市 A 的变化较小。

Error bar with mean and standard deviation

用于创建误差线的 Python 代码

现在我将解释我是如何创建误差线的。

首先,在导入库之后,我计算了两个数据集的平均值和标准差:

City_A=[36,37,36,34,39,33,30,30,32,31,31,32,32,33,35] 
City_B=[41,35,28,29,25,36,36,32,38,40,40,34,31,28,30] Mean_City_A=np.mean(City_A)
Mean_City_B=np.mean(City_B) STDV_City_A=np.std(City_A)
STDV_City_B=np.std(City_B)

然后,我创建一个图形对象并设置轴标签:

# Create a figure with customized size
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111) # Set the axis lables
ax.set_xlabel('Day', fontsize = 18)
ax.set_ylabel('Temperature', fontsize = 18)

我们需要给 X 轴分配天数(15 天的周期):

# X axis is day numbers from 1 to 15
xaxis = np.array(range(1,16))

当我们在线上创建误差线时,我们也可以设置该图形的颜色和线条设置:

# Line color for error bar
color_City_A = 'red'
color_City_B = 'darkgreen' # Line style for each dataset
lineStyle_City_A={"linestyle":"--", "linewidth":2, "markeredgewidth":2, "elinewidth":2, "capsize":3}lineStyle_City_B={"linestyle":"-", "linewidth":2, "markeredgewidth":2, "elinewidth":2, "capsize":3}

现在,我们为每个数据集项、标准偏差和我们设置的线条样式创建两个误差线。

# Create an error bar for each datasetline_City_A=ax.errorbar(xaxis, City_A, yerr=STDV_City_A, **lineStyle_City_A, color=color_City_A, label='City A')line_City_B=ax.errorbar(xaxis, City_B, yerr=STDV_City_B, **lineStyle_City_B, color=color_City_B, label='City B')

我想在每一行上显示数字,这就是为什么,我使用annotate 函数给点添加文本。功能中的xy显示数字在图形上的位置,xytext显示标签的位置。

# Label each dataset on the graph, xytext is the label's position for i, txt in enumerate(City_A):   
     ax.annotate(txt, xy=(xaxis[i], City_A[i]), 
             xytext=(xaxis[i]+0.03,City_A[i]+0.3),
             color=color_City_A) for i, txt in enumerate(City_B):        
     ax.annotate(txt, xy=(xaxis[i], City_B[i]), 
            xytext=(xaxis[i]+0.03,
            City_B[i]+0.3),color=color_City_B)

此外,我将为图形绘制一个图例,以及关于图例样式、轴字体样式的其他设置,并向图形添加一个灰色网格:

# Customize the legend font and handle 
lengthparams = {'legend.fontsize': 13,          'legend.handlelength': 2}
plt.rcParams.update(params) # Customize the font
font = {'family' : 'Arial', 'weight':'bold','size': 12}
matplotlib.rc('font', **font) # Draw a grid for the graph and set face color to the graph
ax.grid(color='lightgrey', linestyle='-')
ax.set_facecolor('w')

最后,使用plt.show()命令显示误差栏。

在下面找到 Python 代码:

感谢您阅读本文!

使用统计过滤器提高盈利能力

原文:https://towardsdatascience.com/using-statistical-filters-to-improve-profitability-an-applied-example-to-a-dax30-volatility-mean-df2dd8e1a837?source=collection_archive---------14-----------------------

DAX30 波动率/均值回归策略的应用实例

Every analysis must begin with a profitable equity curve backtested over different market regimes and during several years (analysis can be split by periods, in this example just one year will be covered).

找到合理的盈利策略并不是一件容易的事情,因此任何提高盈利能力和减少亏损的资源都值得探索。

在本文中,我将通过使用统计过滤器来讨论策略优化。

统计过滤器和参数蒙特卡罗分析是优化交易策略最简单的方法。

统计数据更易于应用,可用于改变尺寸或在某些操作中过滤掉。这种方法只需要来自回测的结果数据集,尽管推荐通过自动化回测引擎进行最终检查。

值得一提的是,这一过程并不专门针对盈利能力和/或权益曲线,但它也可能具有减少执行交易数量的积极副作用,这有效地消除了一些费用并减轻了操作者的心理压力——如果策略被设计为任意执行的话。

在这个例子中,正在分析一个自主策略。该策略是围绕 DAX30 工具(期货或差价合约)的风险控制和情境化均值回归/波动率设置而设计的。

任何策略和任何工具/资产都可以以类似的方式进行分析,因为过滤器可以应用于任何设置。

设计滤波器与其说是一门科学,不如说是一门艺术,需要大量的数据观察。数据观察包括读取实际数据和图表以及创建辅助图表,以识别和隔离可能对盈利能力或权益曲线产生影响的因素。

在解释数据时,必须考虑每个参数或设置在市场环境中的意义。这意味着在阅读数据时发挥积极的作用,因为最初的假设需要建立,然后通过进一步的统计分析来证实或反驳。

优化不一定涉及盈利能力。可能会有优化目标来平滑权益曲线。一条友好的权益曲线更容易通过金融杠杆或信用来衡量,而一条起伏不定的权益曲线的严重下降很容易使我们的资本面临严重风险。

输入数据

分析从来自策略的人工回溯测试的数据开始,这同样适用于自动交易。这些数据作为 CSV 文件合并到分析中。

本文专门讨论回测结果的统计分析。尽管将包含一些命令来展示如何添加键列,但我假设任何对应用这些概念感兴趣的人都知道如何编写统计分析代码。

Figure 1. CSV File incorporated to Analysis.

股票曲线与市场条件

回溯测试可以让你重新发现你的策略,并且经常会揭示策略中隐藏的行为和偏见,这些行为和偏见不是最初定义的一部分。

根据基础资产/工具直观检查权益曲线,以确定特定市场条件和权益曲线行为之间是否存在潜在相关性,这一点极其重要。可以检查大量项目:潜在趋势、趋势强度/斜率、超买和超卖条件、波动性、成交量、较高时间框架市场条件等。—仅举几个例子--。

有些项目可以量化(波动性可以通过 ATR 量化),但其他项目则不能(趋势、趋势强度或市场机制可能是主观的)。对于那些无法量化的数据,可以手动将操作员注释或代码合并到数据集中。

绘制权益曲线

对数据的第一个操作是合并策略中的累计权益列。假设您的数据已经合并到一个名为 data 的 Pandas 数据框架中,下面的命令将添加一个新的列来提供股票曲线。

数据['权益'] =数据['利润']。累计和(轴=0)

虽然利润栏预计是以欧元表示的利润/损失,但回溯测试已经调整,因此 1€对应一个点,因此该栏实际上代表每次交易的工具点利润。实际利润可以很容易地通过定义正在操作的期货合约的数量来获得,或者如果策略是使用 CFD 工具操作的,则通过定义批量来获得。

Figure 2. Equity Curve vs. Trades

该战略的权益曲线如图 2 所示。x 轴代表已执行的交易,y 轴以点数显示累计利润。这条曲线有助于直观地理解策略的机制,包括连续亏损和盈利的次数,以及每次交易的相对盈利/亏损点数。这种表现与时间上的权益曲线相关,但并不匹配,因为交易并不是随时间线性分布的。

Figure 3. Equity Curve vs. Time

这两张图都很有意义,第一张图关注的是交易的顺序,第二张图给出了股票随时间发展的思路。

Figure 4. DAX Futures for the backtested period.

从图表中可以看出,在上半年,该战略的执行是有利可图的。市场已经下跌了 2000 点左右,该策略已经能够从该运动中捕捉到 1250 点。在下一季度,该战略已经能够纳入额外的 500/600 个利润点。

相反,今年下半年根本没有盈利。它已经累积了 500/600 点的跌幅。分析图表和最大交易的进场设置,我们推断试图捕捉更大波动的交易可能会亏损。从回溯测试的执行来看,我也有这样的主观感觉,持久的交易往往是输家,而最好的交易会很快达到盈利目标。这实际上符合策略中使用的基本原则:波动性和均值回归。

主观感觉不能重新定义策略,但它们构成了进一步分析的合法线索,因为它们是经营者市场知识的一部分(通常是启发性的)。

交易盈亏点与交易持续时间

如前所述,出现的一个问题是交易持续时间是否与交易的盈亏概率相关。一个简单的分析方法是使用散点图,在 y 轴上画交易规模,在 x 轴上画交易持续时间。在这个例子中,我用蓝色标出了盈利的交易,用红色标出了亏损的交易。额外的色谱柱易于整合:

data[' trade size ']= ABS(data[' S/L ']—data[' T/P '])
data[' trade duration ']= data[' close time ']—data[' open time ']

交易规模的定义有点武断,带止损或带盈利点同样有效。

对盈亏交易进行分类很容易,你只需要为每个图表系列生成一个新的过滤熊猫数据框。

子数据=数据[数据['利润']。astype(float) < 0]

Figure 5. Scatter plot to analyse trade size/trade duration relation

可以清楚地看到,大多数交易都集中在大约 400 点/ 5000 分钟的区域。在这个范围之外,只有 13 个观察值。

我将从离群值开始,因为它们更容易分析。将它们过滤掉将有助于关注交易集中的区域。

我之前提到过,我们所关注的主观感受指向:

  1. 大额交易可能无利可图。
  2. 长期交易是亏损的。

从图表上看,我注意到在这个特定的案例中,大额交易是有利可图的。只有 6 笔交易的目标是交易规模大于 400,而在这 6 笔交易中,有 2 笔是亏损的。然而,值得一提的是,六次观察可能是一个太小的样本量,无法获得统计相关的结果。

关于第二个假设,在持续时间大于 5000 分钟的所有交易中,7 个是亏损交易,3 个是盈利交易。同样,10 次交易可能不足以提取信息,所以如果可以重新定义策略来避免这些交易,会更安全。

即使利用这种简单的分析,第一滤波器也可以被选作假设。我将分析在密度更大的区域会发生什么。事实上,我们会选择持续 180 分钟以上的平仓交易——这个值是经过反复选择的。就差价合约而言,它还将取消互换费用。

在期货交易中,如果交易持续时间超过结算期,它可以避免对合约进行展期。我们也可以评估其他过滤器,如对交易止损设置 100 点的限制。这将有助于满怀信心地增加杠杆,因为我们不接受止损较大的交易。

缺乏对大额交易和较长交易持续时间的观察可能会导致嘈杂的结果,因为这些领域的观察数量很少,因此更容易发生变化。

我将最初纳入贸易超时过滤器。这个分析并不准确,因为我不知道在交易结束时会发生什么。它们可能会导致部分盈利或亏损。我会先假设赢和输是有补偿的。缩短交易持续时间的想法很有吸引力。直觉上,这可能会产生更平滑的权益曲线,降低费用(尤其是差价合约中的掉期费用)并简化操作。

这些结果可以在以后用新的回溯测试来验证,最好是运行一组新的数据,即不同的年份,以避免过度拟合。

Figure 6. Scatter plot to analyse trade size/trade duration relation for <5000 minutes

Figure 7. Scatter plot to analyse trade size/trade duration relation for <180 minutes

图 6 和图 7 显示了两个条件子集,分别进一步限制了持续时间小于 5000 分钟和 180 分钟的交易。在这两种情况下,但特别是在第二种情况下,可以看到蓝色占主导地位的红色。

这个说法可以通过绘制 180 分钟时限权益曲线来证明。

Figure 8. Equity curve removing the trades longer than 180 minutes: Too good to be true.

在这条股票曲线中,我假设当你在 180 分钟后平仓时,亏损和盈利的交易互相补偿。这可能是真的,也可能不是,但可以肯定的是,他们可能会对下降产生影响。

这一简化方法的关键信息是,当遵循这一途径时,公平似乎会得到改善。因此,花时间进一步回测这个场景是值得的。

回溯测试超时交易场景

现在看来,在 180 分钟后过早平仓可能会改善股票曲线,我们分析一下实际情况。为了做到这一点,我们编写了一个定制的回溯测试引擎(实际上只是 Python 中的几行代码),在实际交易时输入交易,并对 SL、TP 或超时的结果进行回溯测试。

这个新的回溯测试给出了一个更真实但仍有改进的结果,如图 9 所示。

Figure 9. Actual equity curve closing trades that last longer than 180 minutes.

虽然曲线不如理论曲线好,但已经实现了显著的改善。在最初的策略中,最大减仓是持续 30/40 交易的 750 点的大减仓。

通过应用这个简单的过滤器,我们将下降减少到 300 点,减少了 60%。过滤器提供了与原始策略相似的利润水平。

有限的提款,有效地提供更平滑的权益曲线,是策略中最重要的方面。即使实现了较小的利润。利润可以很容易地通过财务杠杆或具有更安全权益曲线的信贷来扩大。

Figure 10. Same strategy without and with filter applied. Improvement on drawdown is evident.

图 10 显示了两种策略之间的比较(有无滤波器)。虽然将计算两种策略的夏普比率,以量化哪种策略更好,但在这种情况下,很明显,滤波器改善了策略。

夏普比率将风险(标准差)与盈利能力联系起来,它可以用作给定策略或基金经理的品质因数。虽然我不会在本文中讨论夏普比率,但它值得一提,因为它适用于正确量化两种策略并与其他策略进行比较。

摘要

在这篇文章中,使用简单的统计过滤器的概念,以改善盈利能力和/或下降已经提出。整个逻辑过程包括分析数据、绘制权益曲线、做出一些初始假设和反复测试数据。

已经强调了提款和权益曲线的相关性,并提供了已实现结果的最终比较。

虽然该示例非常简单,并且没有探索进一步的过滤器或更数学的方法来优化结果,但它实现了以一种易于理解的方式说明统计过滤器的使用的目标。它还显示了有时简单的数据观察和有限的一组图和迭代如何能够在没有复杂数学的情况下改进策略。

[1]https://www.investopedia.com/terms/s/sharperatio.asp

使用生存分析来衡量资产表现

原文:https://towardsdatascience.com/using-survival-analysis-to-gauge-asset-performance-2013afdb071?source=collection_archive---------25-----------------------

用概率解决现实世界的问题

介绍

生存分析顾名思义就是对某个人或某件事的生存分析。可以想象,我们需要一些数据来进行分析。最初,这些数据是人们从出生到死亡的存活时间。

它起源于 17 世纪,是一种决策支持工具。首先,用于确定特定区域的人口增长是否证明开设商店是合理的,其次,用于帮助确定年金。

负责这些创新的两位早期数据科学先驱是约翰·格兰特和埃德蒙多·哈雷。这个事实对哈雷的改进版本尤其有效,因为它有效地标志着精算科学的诞生。

Early Life Table by John Graunt — https://circa-navigate.corsairs.network/

Improved Edmond Halley Life Table — https://papp.iussp.org/

生存分析起源于精算界和医学界。然而,它可以用于研究关于同一受试者的任何两对相关事件,其中所述受试者是群体的一部分。例如,从我们委托资产到特定故障模式发生的时间,或者订户第一次加入服务的时间和她最终取消或退出的日期。

因此,当我们说资产时,我们指的是需要维护或保留的为组织产生收入的任何东西,包括但不限于物理资产、员工和订户。

在本文中,我们查看一些理论背景,以及对一些现实世界中的资产故障数据的分析,以获得具体的见解。

生存分析背景。

生存函数 S 的定义由下式给出,

有了时间, T 感兴趣的事件的时间。就资产可靠性而言,我们称之为可靠性函数。

可靠性定义为在特定条件下,资产或零件在给定时间内执行其预期功能的概率。

在可靠性工程、其故障和订阅取消的情况下,生存函数是感兴趣事件的累积分布的补充。

由于根据定义,整个群体或队列将存活至所选研究、分析或报告间隔开始,并且没有一个将无限期持续,因此我们通常可以声称:

特定人群作为时间函数的确切生存概率可以从数据中得知。这可以使用参数化和非参数化方法来完成,正如我们在后面的真实例子中看到的。

不可靠度 F(t)是累积失效分布,是可靠度函数的补函数,即 F(t) = P (T < = t) = 1-R(t),本次 F(t) = P (T < = t) = 1-R(t)。

根据定义,故障时间的密度函数为

危险率或瞬时故障率函数描述如下:

还记得我们之前说过,根据定义 f(t)=-R'(t)。

关于生存函数的更多背景,请访问维基百科,这里是 https://en.wikipedia.org/wiki/Survival_function,关于失败率和风险函数,这里是 https://en.wikipedia.org/wiki/Failure_rate。

事件时间数据分析

要将生存分析技术应用于事件数据,如委托和失败的资产或订户加入和取消,需要将数据转换成通常的格式。

在这个实际的例子中,我们考虑资产被安装在特定的功能位置,并在出现故障时被替换。个人的“寿命”定义为从第一次安装到第一次更换的时间,或者从一次更换到下一次更换的时间间隔。这个间隔可以用许多不同的方式来定义。对于一个特定的研究或决策支持生产系统来说,清晰和一致的完成是至关重要的。确保数据工程的高效和正确也很关键。

在下图中,每条线代表一个资产位置,每个初始点代表第一次安装,每个后续点代表更换事件。两条垂直线代表“研究”或“实验”的开始和结束。第一行代表初始数据,第二行代表今天。圆点和间隔替换时间代表我们的样本。

Original Time to Event Data distributed in time

我们把我们的数据重新整理成生活或生存数据集。研究/报告结束前的每个更换时间/故障代表一个事件,而在该期间结束时仍在使用的每个资产代表一个“审查观察”

生存数据可以用表格的形式表示,如下表所示。

Table 1 — Event Observations

Event=1 表示发生了故障,即生命线在当前观察期之前结束,Event=0 表示感兴趣的事件将在未来某个未知时间发生。

挑战

我们的客户怀疑他们的一些资产类别受到婴儿死亡率的影响,希望更好地了解情况。他们最近启动了可靠性数据质量计划,可以为我们提供最近的故障观察。数据很可能不足以做全面的生存分析,构建完整的生命表和浴缸曲线。然而,它应该足以获得一些关于婴儿死亡率的见解,并建立一个部分生命表。

分析

通常情况下,我们从 Kaplan Meier 估计量开始。正如几个世纪前的格兰特和哈雷一样,卡普兰和迈耶对生存分析和精算科学做出了根本性的贡献。当他们在 1958 年发表这种创新的非参数方法来估计存在删失数据的生存曲线时,这一成就就发生了。

此示例的工程数据集子集可在此处找到:https://drive . Google . com/OpenID = 1 q w9 b 0 mdjmodppo 9 iib Cl2 xvkiqrjjerm

library(survival)
library(ggfortify)################################################################################### Do Meier Kaplan estimation##################################################################################dfEventsArea <- read.csv(file="D:/ACE/initiatives/APA/DATA/eventDataArea.csv", header=TRUE, sep=",")survRecent=Surv(dfEventsArea$LIFE, dfEventsArea$EVENT)
eventsRecent.km <- survfit(survRecent ~ 1, data=dfEventsArea)
summary(eventsRecent.km, times = seq(0,5,0.5))
autoplot(eventsRecent.km, main="Kaplan Meier estimate of survival")

这里使用的汇总为我们提供了这一资产类别的生命表。

Life Table for Asset Class

时间的单位是年。它表示对其余变量有效的区间。当时的事件数由 n.event 给出,生存概率由生存给出。

ggfortify 库允许我们根据输入数据,仅使用一个命令,就可以绘制出估计的可靠性/存活率函数的可视化图形。

我们还对每个运营区域的资产可靠性感兴趣。

注意,这也可以是每个制造商、安培小时(从物联网或其他仪器获得)、容量等级或任何其他感兴趣的因素。

n_recentOU.km <- survfit(Surv(LIFE, EVENT) ~ OU, data=dfEventsArea)
autoplot(n_recentOU.km,main=”Survival probability of asset per area”)

正如我们在下面看到的,在可靠性方面,有两个区域似乎很突出——一个高于标准,一个低于标准。

对于一般预期持续 15 年或更长时间的资产类别来说,在过去四年中有超过 60%的资产似乎是一个值得关注的原因。从这里,人们可以对问题的根源展开调查。这可能包括设计不足、操作条件或主要向该地区供货的制造商的质量问题。

如前所述,我们还可以用参数方法分析故障事件时间数据集。

这在下面举例说明,不要太深入所涉及的理论。从随后的图表中可以看出,参数威布尔生存曲线与非参数曲线吻合得相当好。

recent.wbs <- survreg( Surv(LIFE, EVENT)~ 1, data=dfEventsArea, dist='weibull', x=TRUE)# There are multiple ways to parameterize a Weibull distribution. The survreg
# function embeds it in a general location-scale family, which is a
# different parameterization than the rweibull function, and often leads
# to confusion.#   survreg's scale  =    1/(rweibull shape)
#   survreg's intercept = log(rweibull scale)
#   For the log-likelihood all parameterizations lead to the same value.rweibullShape = 1/recent.wbs$scale
rweibullScale  = exp(recent.wbs$coefficients)
weibSurv <- function(x, shape, scale) pweibull(x, shape=shape,
scale=scale, lower.tail=FALSE)# Survivalcurve(weibSurv(x, shape=1/recent.wbs$scale, scale=exp(coef(recent.wbs))), from=0, to=18,
ylim=c(0,1), ylab="Survival probability", xlab="Time")# Survival 2curve(pweibull(x, scale=exp(coef(recent.wbs)), shape=1/recent.wbs$scale,lower.tail=FALSE),from=0, to=5, main="Weibull fit of Survival Probability in first few years of asset class", ylab = "probability", xlab = "time in years", ylim=c(0,1))lines(eventsRecent.km, col="blue")

我们还可以推导并绘制风险函数:

# Hazard
curve( dweibull(x, shape=1/recent.wbs$scale,
                scale=exp(coef(recent.wbs)))/pweibull(x, scale=exp(coef(recent.wbs)), shape=1/recent.wbs$scale,lower.tail=FALSE),from=0, to=5,
      main="Parametric estimate of failure rate based on recent data"
      , ylab = "h(t)", xlab = "time in years")

危险函数和浴缸曲线的左侧

上面绘制的危险函数也是浴盆曲线的左侧。

在这种情况下,没有足够的数据来确定该群体的失败概率是否会随着成员年龄的增长而增加。因此,无法构建完整的浴盆曲线。

然而,我们可以从非常高的初始失败率和随后迅速下降的失败率中得出结论,人口中的婴儿死亡率很高。这给了我们进一步的线索,告诉我们应该如何研究提高资产可靠性的方法。

结论

精算方法在资产管理中的应用是一个广阔而令人兴奋的领域。我希望你喜欢这个简短的介绍。其他应用包括远期风险预测计算、检查优先级排序和剩余使用寿命估计。

利用 TED 演讲进行机器学习

原文:https://towardsdatascience.com/using-ted-talks-for-machine-learning-1cbbf22b4d72?source=collection_archive---------25-----------------------

在我第一次尝试建立一个机器学习项目时,我对网上提供的大量资源和教程印象深刻。看看我经历了什么。

Photo by Miguel Henriques on Unsplash

这一切是如何开始的

今年夏天,我在学习一门关于应用机器学习的课程,并被要求寻找一个项目创意。在我研究的时候,我遇到了一个朋友。这个朋友话很多。我说的很多是指从一个句子开始另一个句子,直到不清楚他在说什么。当他继续说的时候,我试着去想他的句子结构会有多复杂。用积极的话来说:它们一定是在我周围摇曳的美丽而复杂的树。因此我有了一个宽泛的想法:分析文本的结构。我的另一个重要目标是掌握机器学习的四个阶段,即:

  1. 框定问题,
  2. 准备数据,
  3. 训练 ML 模型并
  4. 使用 ML 模型进行预测。

在这个领域做了一些研究(实际上是一整袋新的墨西哥卷饼,我真的很惊讶和不知所措)之后,一个特定的算法引起了我的注意:Word2vec 建模(这里是 Memo Akten 关于单词嵌入及其应用的一篇非常有趣的文章)。

This is a web application where you can look for similar words according to TED talks, the final result of my work

什么是 word2Vec 算法?

作为输入,该算法接收大量文本数据(演讲、书籍内容、字典、从网站抓取的文本等),并将每个单词分配给空间中相应的向量(向量的维度通常在 50–1000 左右,取决于数据集)。这些“单词向量”的位置靠近在类似上下文中使用的其他单词,例如在同一个句子中。例如,单词“sing”可以位于“song”附近。但是作业也取决于数据集(不管你用的是新闻文章还是哲学论文,但我会在最后一个阶段讲到)。

机器学习的四个阶段

The four stages of a machine learning project

下面我将解释我是如何经历机器学习的四个阶段的。

1.框定问题

通常,首先弄清楚你想要解决的问题是什么以及一些成功指标,以及机器学习是否是唯一合适的技术是有帮助的(参见 this) 。但是我没有什么特别的问题,我只是好奇去探索可能性并从中获得灵感。此外,我还想知道如何将机器学习输出用于艺术目的。因此,我的方法是探索各种可能性,并学习建立这样一个项目的基本步骤。

2.准备数据

准备数据是最有见地的部分。首先,问题是我想使用什么样的数据。因为 word2Vec 模型使用大量的文本是有帮助的,所以我决定使用英语的 TED 演讲记录。TED 演讲提供了大量关于各种事物的演讲。从 kaggle 导入数据集后,该准备数据了。从多个教程(像这个或者这个一个)我用了以下方法:

英语中有这种缩写,比如“has not”或“is not”,尤其是在口语中,比如 TED 演讲。为了确保这些短语不会影响训练,我扩展了文本语料库中的每个缩写。

删除特殊字符和数字 这是一个很容易解释的步骤,用来清理模型并专注于单词。

删除停用词 停用词是常用词(如‘a’,‘the’,‘of’,‘in’),对文本的意义没有贡献,可能会严重影响模型的性能。

小写全字
这是我经过几次训练后实施的一个步骤。预先降低所有单词的大小写可以极大地改进模型,因为如果没有它,模型将对“雄心”和“抱负”进行不同的处理。

对文本进行词汇化 词汇化或词干化是自然语言处理中的常用术语。在我们所说的语言中,我们经常使用从另一个词派生出来的词。
因此,有必要将这些特定的单词转换回词根,以避免冗余。

特别是对于 TED talk 抄本:移除抄本注释 前面所有的步骤实际上都可以应用于所有的 nlp 项目。但是看一看个人的语料库也是很重要的,所以我注意到了在我的文本中频繁出现的抄本评论。因为它们总是以括号开始和结束,所以很容易通过正则表达式删除它们。

我对这些方法的顺序掌握得越精确,越能确保它们真正清理了语料库,训练就越好。

我的最后一步是将语料库分成句子,并将每个句子分成模型的单词标记。

3。训练 ML 模型

就在培训之前,我检查了最常用的单词,以确保准备足够精确。如您所见,最常见的单词不包含任何特殊字符,并且几乎没有停用词。

Checking out the most frequent words before training the model

然后我初始化了模型。我在这个项目中使用了 Gensim Word2Vec 模型。经过多次测试,这个数据集的理想维数是 50。超过 100 导致拟合不足,从而导致不显著的结果。

我将最小计数调整为 50,忽略了所有出现频率低于这个最小计数的单词。这导致了总共 4703 个词汇。后来我用 30 个历元训练了这个模型。培训没有像我预期的那样持续很长时间。总共是 3 分钟。

4。使用 ML 模型预测

由于 word2vec 模型是无监督的,所以我所能测试的就是单词根据一个人的上下文直觉映射的有多好。

最有见地的是绘制模型。这意味着将高维向量投射到 2D 画布上(这里是一个很棒的教程,我就是为了这个而遵循的)。由于模型应该理想地将相似的词放置在彼此更近的位置,这些点应该显示某种聚类,因此这个情节非常令人宽慰(你必须想象:在长时间准备数据和训练之后,最终看到这样的结果是值得的)。

Plotting the word2vec model via TSNE

当绘制类似的单词云,如“食物”、“经济”或“爱情”时,你会注意到模型训练得有多好。尤其是看到这些单词云的位置与我将要使用它们的上下文如此接近,令人印象深刻。

我的申请

为了使用这个经过训练的模型,我构建了一个 web 应用程序,它不用深入代码就能提供相似的单词。

这真的很有趣。我用了 node.jsp5 。在这里你可以查看我的 github

替代文本语料库

我也试过尼采的书和维基百科的电影情节。由于复杂的文本风格,尼采没有像其他模型那样成功。但是它提供了大量不同的词汇。

维基百科的动机图比谈话语料库大 10 倍,所以准备数据需要更长的时间。结果还没有出来,所以等我的下一篇文章吧😉。

结论

总而言之,训练一个模型,而不仅仅是使用一个从模型中派生出来的应用程序,是一次很好的学习经历。现在有如此多的资源,用一些合理的编程知识开始一个项目并不困难。到目前为止,我还不能将这个模型用于艺术目的,但是让我们看看几个月后我会发布什么😉。

使用 TF IDF 通过关键词提取形成描述性章节摘要。

原文:https://towardsdatascience.com/using-tf-idf-to-form-descriptive-chapter-summaries-via-keyword-extraction-4e6fd857d190?source=collection_archive---------11-----------------------

Source: https://pixabay.com/photos/library-books-education-literature-869061/

TF IDF 是一种自然语言处理技术,用于提取一组文档或章节中的重要关键字。首字母缩写代表“术语频率-逆文档频率”并描述了该算法如何工作。

数据集

作为我们的数据集,我们将采用玛丽·雪莱的《弗兰肯斯坦》的脚本(由古腾堡项目提供),并基于 TFIDF 算法的输出生成每章中事件的感觉。为了做到这一点,我们首先要理解为什么 TFIDF 算法如此成功:

TFIDF 算法

该算法分两部分工作。首先,我们计算我们的“项频率”。这将根据每个单词在文档中出现的次数对其进行排序(加权)——我们重复的次数越多,它越重要的可能性就越大。

然后,这个术语通过除以整个组中的单词数而被标准化。这是因为出现在一小段中的单词,例如标题,比成千上万行中的同一个单词具有更大的权重。

接下来,我们有'逆文档频率'部分。这很重要,因为它根据单词在特定文本片段中的个性对单词进行排序。在这里,我们将在文本的单个部分中频繁使用的单词与在各处中频繁使用的单词分开。这意味着只有当前文档/章节的本地标识词被标记为重要。我们使用以下公式进行计算:

*1 + log_exp ( number_documents / (document_frequency + 1))*

这两个术语结合起来提供了每个单词相对于其所在部分的重要性的权重。

预处理

与所有数据科学任务一样,我们需要为算法中使用的数据做好准备。将所需文本读入 python 后,我们可以用空格替换所有句点,并用 regex 模块(re)删除所有非单词字符:

text = text.replace('.',' ')
text = re.sub(r'\s+',' ',re.sub(r'[^\w \s]','',text) ).lower()

接下来,我们根据单词' chapter ' (+一个数字)分割数据集,尽管这可以是 LaTeX 中的\section{.*}或您选择的任何其他分隔符。

corpus = re.split('chapter \d+',text)

将数据输入算法

最简单的方法是使用 python 中的 scikit-learn 包。在这里,我们可以直接输入我们的数据,并获得它来计算每个组的单词排名:

import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizervectorizer = TfidfVectorizer()
vectors = vectorizer.fit_transform(corpus)names = vectorizer.get_feature_names()
data = vectors.todense().tolist()# Create a dataframe with the results
df = pd.DataFrame(data, columns=names)

过滤掉停用词

在自然语言处理中,停用词是一组对最终输出没有什么意义的词。这些通常是常用词,如I,a,all, any,and,the,them,it,dont,has等。使用自然处理库nltk,我们可以过滤掉包含这些的所有列。

from nltk.corpus import stopwords
nltk.download('stopwords')
st = set(stopwords.words('english'))#remove all columns containing a stop word from the resultant dataframe. df = df[filter(lambda x: x not in list(st) , df.columns)]

打印出每章排名前 N 位的单词

这是通过选择每一行/数据集来完成的——由于我们之前的选择,这些代表不同的章节,并在打印之前选择 N 个排名最高的列。

N = 10;for i in df.iterrows():
    print(i[1].sort_values(ascending=False)[:N])

解释结果

现在,这就是我们看到我们的算法在预测关键词方面有多好的地方。因为有 25 个章节,我们在下面只展示了一些随机选择的章节。在该选择中,我们将章节提要与由 TFIDF 算法选择的排名最高的关键字进行比较,并决定它在描述现有事件方面的表现。

第一章弗兰肯斯坦设定了场景,描述了他的母亲如何发现了被一个意大利家庭遗弃的伊丽莎白,并收养了她。

mother      0.084748
beaufort    0.079967
child       0.068566
father      0.062509
orphan      0.054138
daughter    0.053630
poverty     0.049939
italy       0.047980
infant      0.043612
abode       0.043612
Name: 1, dtype: float64

第 3 章维克多(弗兰肯斯坦)离开日内瓦去上大学。在这里,自然哲学教授 Krempe 说服他,他学习炼金术的时间是一种浪费。结果,他参加了沃尔德曼教授举办的化学讲座,教授说服他从事科学研究。

science       0.074137
natural       0.071721
professor     0.065336
philosophy    0.059502
modern        0.054772
krempe        0.049489
waldman       0.049489
lecture       0.043557
chemistry     0.043557
principal     0.036860
Name: 3, dtype: float64

第 4 章维克托斯对他在理解生命科学方面的工作表现出极大的热情。以至于他对创造生命的迷恋成为他唯一的追求,这在很大程度上导致他忽视了生活中的朋友,并秘密进行令人讨厌的实验。

pursuit       0.053314
study         0.050588
life          0.046087
one           0.040652
corruption    0.039524
would         0.036956
science       0.036134
eagerness     0.035029
natural       0.034180
secret        0.034180
Name: 4, dtype: float64

这个怪物一直在学习一个小茅屋里的居民的语言和历史。费利克斯最近在这里遇到了萨菲。萨菲的母亲是一名信奉基督教的阿拉伯人,在嫁给萨菲的父亲之前曾被土耳其人奴役。

felix        0.164026
safie        0.136081
turk         0.112066
paris        0.087163
leghorn      0.084299
daughter     0.083509
deliverer    0.070249
lacey        0.045272
merchant     0.045272
christian    0.042149
Name: 14, dtype: float64

维克多和亨利穿越了英格兰和苏格兰,但是维克多开始迫不及待地想要开始他的工作,摆脱他和怪物的束缚。

oxford        0.060545
city          0.058641
edinburgh     0.048436
lakes         0.042927
scotland      0.042927
might         0.038131
visited       0.037911
matlock       0.036327
cumberland    0.036327
clerval       0.034506
Name: 19, dtype: float64

第二十三章伊丽莎白被怪物杀死。在未能说服裁判官让这个生物负责后,维克多·沃斯让他的生命去摧毁他的创造。

magistrate    0.048762
room          0.047945
exert         0.039379
pistol        0.039379
arms          0.036325
punishment    0.034900
rushed        0.034054
might         0.033068
elizabeth     0.032818
wandered      0.032088
Name: 23, dtype: float64

维克多失去了所有的家人,他追踪怪物来到北方的冰雪之地。在临终前,维克多讲述了他的故事,并恳求沃尔顿在他死后继续他的追求。

yet             0.051022
ice             0.048866
vengeance       0.037918
shall           0.033370
still           0.031682
die             0.030744
frankenstein    0.030744
would           0.027350
death           0.026679
feel            0.026679
Name: 24, dtype: float64

结论

看起来,至少对于这本玛丽·谢利的小说来说,术语频率-逆文档频率算法很容易使用,并作为提取每章描述性关键词的可靠方法。所以为什么不亲自尝试一下,看看你会有什么发现呢?

进一步的工作

这种和平的延续:将情感和情绪分析应用于《弗兰肯斯坦》,可以使用下面的链接找到。

[## 使用情感分析探索文本中的情感

应用两种自然语言处理技术来比较玛丽·雪莱的《弗兰肯斯坦》中的情感和 TF-IDF 关键词分析…

towardsdatascience.com](/using-sentiment-analysis-to-explore-emotions-within-text-ae48e3e93999)

利用生日悖论教授概率基础知识

原文:https://towardsdatascience.com/using-the-birthday-paradox-to-teach-probability-fundamentals-c08bbcb351d1?source=collection_archive---------0-----------------------

你的两个朋友同一天生日的可能性有多大?

简答:这取决于你有多少朋友…

Here’s the audio version of the article, read for you by the author.

今天是我亲爱的人的生日(万岁!),这是一个神话般的借口来涵盖一些生日语言中的概率基础知识。我们的目标是一起找出这个常年统计作业排行榜榜首:

如果你有 N 个人在一个小组里,至少有一个人是同一天生日的概率是多少?

如果你还没想过这个,花点时间猜猜看。想象一下这个小组有 30 个人,他们是 T2。两个人在同一天得到蛋糕的几率有多大?或者,如果这让人望而生畏,只需回答这个问题:你愿意跟我赌 10 美元有生日副本,还是 10 美元没有?让我们看看你的直觉有多好!

我们将作为笑点到达那里,但是首先我们将开发所有你需要自己解决生日问题的乐高积木(下面的大字体)

最基本的基础

为了纯粹的卖弄学问,让我们抛开这个令人瞠目结舌的启示:概率介于 0 和 1 之间(或者 0%和 100%,如果你愿意)。酷毙了。现在你知道为什么像“我 1000%确定,他们会迟到”这样的句子会让数据人员感到恐慌。

概率的三种方法

思考概率有三种主要方法:

  • 基于事件的 (包括枚举事件并计数)
  • 基于频率的 (涉及分布象征着如果我们在无限平行宇宙中观察我们的现象,事物会如何发生变化)

如果你上了一堂统计学课,而你的教授并没有采用强调显而易见的东西的木槌敲脑袋的方式,那么让我来详细说明这些东西在你的课本中的什么地方。

基于事件的概率

概率=[分子]/[分母]

前几章倾向于从基于事件的概率 方法 开始。这是因为这是一个简单的游戏场,大多数人可能已经有了这方面的直觉。例子:你的硬币正面朝上的几率有多大?1/2.你在六面骰子上掷出 6 的几率有多大?1/6.这里发生了什么事?**

分子:我们感兴趣的事件可能发生的方式的数量。

分母:任何(相关)事件可能发生的方式的数量。

在一枚硬币上,可能的相关事件是正面和反面。这就是 2 的由来。很简单。

A small amusement for you on the topic of heads and tails…

清点东西

要使用 基于事件的概率 ,您需要能够枚举事件并对其进行计数。这就是为什么你的教科书可能会把你拖进 组合学 直到你彻底厌倦为止。组合学给你计算事件发生的方式的数学知识(为了你所追求的分子和分母)。

欢迎来到大量的家庭作业问题,都是关于“我有多少种不同的方法可以从 100 名候选人中选出 10 名委员会成员?”( 17,310,309,456,440 )设置 4 位 PIN 码时,我可以选择多少种不同的选项?”(10000)

在基于事件的世界里,所有的积木事件都是同样可能发生的,这样它们就可以不受层层杂乱修饰词的干扰,进行基本的算术运算。这是一个所有的硬币都是公平的,所有的骰子都是平衡的,所有的牌都是无填料的,所有的生日都是同等概率的世界。

Since we’re on the topic of Counting things.

对于生日问题,我们需要快速了解一下计数:

“和”要求您乘以(x)个计数

“或”要求您添加(+)计数

如果你喜欢的话,去找一个证明…或者用一个简单的例子来满足你自己,然后继续:如果我有两个素食的选择或者三个荤菜的选择,那么我有多少餐的选择?2 + 3 = 5.如果我可以选择一道主菜和两道甜点中的一道呢?我从多少种不同的食物中选择?5 x 2 = 10。用具体的菜品例子试试,不信都写出来。

随机选择的一餐是素食友好型的概率有多大?

分子= 2 x 2 = 4;分母= 10。答案= 4/10 = 40%

The difference between a combination and a permutation is that order matters with permutations but not with combinations. If you think about the image above for a moment, you’ll see why the number of possible options is bigger with permutations than with combinations (if you run the numbers on choosing 7 from 200, you’ll see that the answer on the left is a 13 digit number while on the right it’s a 17 digit number, and if you ogle the formula you’ll see that there’s an extra term in the combination’s denominator that removes the effect of ordering after selection, dumping all the pills into a single container and shaking it). Fun fact: your so-called “combination” bike lock is actually a permutation-with-replacement bike lock. (Technically, a combination lock that opens with 1008 should also open with 0810 because order doesn’t matter.)

超越事件

你已经学了 3 章,突然你的课本把组合学忘得一干二净。就在你掌握所有这些组合和排列的窍门时(见上图),它们再也没有消息了。反而突然到处都是分布。那是怎么回事?

考虑这个问题:“你需要等 10 分钟以上公交车的概率有多大?”这将很难计算(以纳秒为单位?)也很痛苦,因为计算事件意味着你不能把时间当作一件连续的事情来处理。更糟糕的是,如果你有一个公共汽车司机,他有可能停下来抽根烟,这取决于公共汽车已经晚点了多长时间。你打算怎么列举呢?你不是。也许计数事件不是你在这里的朋友…

Your bus is here!

输入 基于频率的定义 ,其内容类似于“如果这是发生在无限个平行宇宙中的随机事件(由我指定的规则管理,呃,假设),其中有多少个公共汽车需要超过 10 分钟才能到达?”(平行宇宙?!是啊,难怪我们统计学家有一双疯狂的眼睛。)

然后——通常是很久以后——当你在你的贝叶斯统计教科书中碰到 主观定义 时,你就可以根据你感觉有可能发生的事情来编造分布。看看当我们剥夺你列举事件的能力时,你会得到什么样的扭曲的东西?嗯,幸运的是,对于生日问题,*如果我们假设所有 366 个生日的概率是相等的 ,我们可以继续计数。咻!**

*什么,你不喜欢我的假设?战胜你自己——所有的统计都是为了简化假设——否则宇宙就是一个可怕的地方。如果你不喜欢我的假设,那么你需要想出一个不同的解决方案,因为我的对你没有好处。统计变得有创造性,因为我们都被允许做任何我们喜欢的假设。引用乔治·博克斯的话:“所有的解决方案都是错的,但是无论哪一个符合你愿意接受的假设,都可能对你有用。”

不是赞美

对于生日问题,我们需要的最后一块积木是补语,也就是通常所说的谦逊的 NOT。

P(非 A) = 1 — P(A)

这被解读为“一个事件(我们将其命名为事件 A,因为我们缺乏创造力)不发生的概率等于 100%减去该事件发生的概率。”

那么掷骰子得不到 6 的概率有多大呢?1–1/6 = 5/6

好了,就这些。我们准备好解决生日问题了!

Why is the birthday problem also called the birthday paradox? The paradox has to do with the vast number of birthday possibilities in a group of people versus the surprising probably of a match. The paradox resolution is to flip the problem to think about unique birthdays.

生日问题

问题是什么来着?啊,这个:

如果你有 N 个人在一个小组里,至少有一个人是同一天生日的概率是多少?

所以,让我们用我们的乐高积木试一试…

生日分母

一个人有多少生日选择?366(见上文)。

N=30 人我们有多少生日选择?

我们有第一个人 366,第二个人 366,第三个人 366……第 n 个人 366。在所有的 and 处放一个乘法,瞧!

分母= 366 ^ N =天啊,这么多数字!如果 N 是 30,就是 77 个。这可不仅仅是一个 quattuorvigintillion。(给东西命名不是很好玩吗?)

生日分子

准备好头晕吧。我们必须计算所有不同的方式,以使任何两个人中至少有一个匹配。因此,人 1 有 366 个选项,人 29 有 1 个选项,因为他们与人 1 匹配,但也可能是人 2 和人 17 或两对,或者可能是三个人同一天生日,或者…或者…不,这将很快变得混乱,而我们跑来跑去,试图让所有的选项在我们的脑海中保持直线。

…这就是为什么这是一个有趣的家庭作业问题。你应该用你的头去撞它,直到你明白其中的诀窍。(或者求网上的作弊码。你就是这样找到这篇博文的吗?太酷了,我抓住你了。)

解决生日问题的诀窍!

与其数出人们过生日的所有方式,不如把问题重新措辞,数出一个简单得多的事情:相反!

p(至少有一个共同的生日)=

1 — P(所有生日都是唯一的)

所以我们需要找到这个问题的答案:“人群中没有任何生日分享的概率是多少?”换句话说,所有生日都是独一无二的概率有多大?

独特的生日分母

仍然是 366 ^ N。通过处理互补事件,我们转移了对分子的关注。分母毫发无损。

唯一生日分子

这是美丽而光荣的魔法发生的地方!

第一个人有 366 个生日选择(贪婪的猪),第二个人只有 365 个,因为我们强迫他们过不同的生日。如果第一个人出生在 10 月 8 日,我们强迫我们的房间里有 N 个不同的生日,我们会把所有 10 月 8 日生日的人拒之门外。每个申请房间的人都少了一个选择。

因此,第 1 个人有 366 个选项,第 2 个人有 365 个选项,第 3 个人有 364 个选项,第 N 个人有(367— N)个选项。

如果 N 是 30,放入乘号,嘣!

366 x 365 x 364 x 363 x 362 x 361 x 360 x 359 x 357 x 356 x 355 x 354 x 353 x 352 x 351 x 350 x 349 x 348 x 347 x 346 x 345 x 344 x 343 x 342 x 341 x 340 x 339 x 338 x 337 =…

呸,又是一个 77 位数的大数字。

但是,对我们来说幸运的是,如果我们友好地请求,计算机会替我们处理除法。

不是我们想要的可能性

p(所有 30 个生日都是唯一的)=(366 x 365 x 364 x 363 x 362 x 360 x 359 x 358 x 357 x 356 x 355 x 354 x 353 x 352 x 351 x 350 x 349 x 348 x 347 x 346 x 345 x 344 x 343 x 342 x 341 x 340 x 339 x 338 x 338

= 0.3(四舍五入到我的注意力范围)

终于,我们想要的答案来了!

p(30 人一组的共同生日)= 1 — 0.3 = 70%

一个 30 人的团队,有大约 70%的机会是同一天生日。

我希望你没有跟我赌 10 美元,说在一个 30 人的小组中,同一天出生的人比同一天出生的人更少……但是如果你赌了,我不会说不,如果你愿意把它捐给维基百科。

赌错了一方,是因为低估了找到一个没有重复房间的房间有多难——如果你是门口的保镖,负责赶走那些生日被占的人,用不了多久,你就会赶走第一个失望的人。

这取决于你有多少朋友…

在我的笔记本电脑上打开 2 分钟和 R ,我可以为 N 的任何一个选择画出答案。如果你想知道实际的数字(50%发生在 N = 23 时,99%发生在 N = 55 时),继续用在你的浏览器中用我下面丑陋但功能强大的小代码片段玩,不需要安装。

# Initialize settings for N = 1:
probability <- 0
numerator <- 366
denominator <- 366# Loops are terrible in R, let's make one anyways:
for (N in 2:80) {
  numerator <- numerator * (366 + 1 - N)
  denominator <- denominator * 366
  p <- 1 - (numerator / denominator)
  probability <- c(probability, p)
}# Look at the answer to 2 decimal places:
paste("For N =", 1:80, "prob is", round(probability, 2))# Plot!
plot(1:80, probability, xlab = "Group Size", ylab = "P(Shared birthdays)", type = "l", col = "red", main = "The Birthday Solution")

我们在这里学到了什么?

除了一些概率基础知识(比如不同的概率方法、补数、分子和分母的取值)和计数原则(求和规则和乘积规则)之外,这篇文章要讲的是为什么你会按照一定的顺序学习某些概念。

为什么数数在你的课本中是一件大事,然后突然消失了,让每个人都不高兴?事实证明,这主要是达到目的的一种手段,因为假设所有基本事件都同样可能发生,对于大多数专业人士来说太业余了,以至于无法接受… 甚至对于生日来说。有趣的是,当非专业人士想到我们这些统计人员整天都在做什么时,他们往往会想到算牌和扔硬币。有些谣言是很难抹杀的!

生日问题之所以成为统计学本科生经历中的一个经典问题,很大程度上是因为它给了你足够的痛苦来抓住一个关键点:初出茅庐的统计学家需要学习如何重新表述问题,以便他们的活动部分更容易处理。蛮力方法往往太难计算,所以我们学会了斜着看事情。如果你选择统计的生活,那就做好大量翻转和反转的准备。

这篇文章有意不同于我平时的文章。有时候尝试新的东西来看看人们是否喜欢它们是很好的——如果你想知道更多这是从哪里来的,喜欢和分享是你让我知道的方式。❤

感谢阅读!人工智能课程怎么样?

如果你在这里玩得开心,并且你正在寻找一个为初学者和专家设计的有趣的应用人工智能课程,这里有一个我为你制作的娱乐课程:

Enjoy the entire course playlist here: bit.ly/machinefriend

利用数据科学谱找到适合您的数据科学职业道路

原文:https://towardsdatascience.com/using-the-data-science-spectrum-to-find-the-right-data-science-career-path-for-you-eff98b6c589c?source=collection_archive---------11-----------------------

并非所有的数据科学工作都是一样的

我刚大学毕业的时候,数据科学还没有作为一个职业存在。我受过精算师和统计师的训练,所以我去做了精算分析师。

当我第一次听说数据科学时,我已经从事过各种与数据相关的工作,所以当我申请第一个真正的数据科学职位时,我已经有了多年的相关经验。

虽然研究生数据科学角色确实存在,但这些角色可能很难获得,而且竞争非常激烈。更重要的是,顾名思义,他们通常是针对刚毕业的学生,而不是那些试图在职业生涯中期跳槽的人。

因此,很少有人的第一个数据相关职位是数据科学家。

更常见的情况是,人们从一个非数据科学家但与数据相关的角色开始,然后利用这一经验说服雇主他们有能力担任数据科学家。

与申请数据科学职位相比,针对非数据科学家的数据相关职位通常是更有效的进入数据科学的方法,特别是对于那些来自非数据背景的人来说,因为这些职位通常比数据科学家职位更常见,并且通常对技术和经验的要求更低。

这当然提出了一个问题:哪些与数据相关的角色是进入数据科学的最佳敲门砖?答案取决于你对数据科学的兴趣所在。

数据科学领域

数据科学通常被视为统计学和计算机科学的结合,根据这些学科对特定职位的相对重要性,在该行业中的角色也有所不同。我称之为数据科学光谱。

例如,更接近统计端的数据科学角色可能专注于使用统计和机器学习技术来从数据中获得洞察力,而更接近计算机科学端的角色可能更专注于开发机器学习模型,以作为人工智能系统的一部分进行部署。

在这个范围内,角色可以根据资格水平和所需的技术技能而有所不同。

我还将与数据相关的角色包括在内,这些角色虽然不是实际的数据科学职位,但与数据科学角色有一些重叠,可以为数据科学职业道路提供早期步骤。

因为数据科学角色可以存在于光谱上的任何一点,而非数据科学角色通常被错误地命名为“数据科学家”(反之亦然),所以仅根据职称来判断数据相关角色可能会产生误导。

然而,如果你看了足够多的数据相关职位的招聘广告,模式就开始出现了,使得识别各种类型的数据角色成为可能,而与职位无关。

七种类型的数据角色

在 2019 年 4 月 22 日至 2019 年 5 月 5 日期间,我从 LinkedIn 收集了 200 个数据相关角色的招聘广告(即,标题为数据科学家(100 个广告)、数据分析师(40 个广告)、商业智能分析师(20 个广告)、机器学习工程师(20 个广告)和数据工程师(20 个广告)的角色),横跨四个英语国家(澳大利亚、加拿大、英国和美国)。

我超越了“数据科学家”这个头衔的工作,考虑到了潜在的命名错误,以及不同雇主对一份工作具体要求的差异。

通过将 k-means 聚类应用于这些广告,使用选择标准作为特征,我能够将招聘广告分组为七个聚类或角色类型。这些是:

  1. 报告和 ETL 分析师;
  2. 数据科学通才;
  3. 洞察分析师;
  4. ML 研究数据科学家;
  5. ML 软件工程师;
  6. 平台和仓库工程师;和
  7. 数据科学专家。

我在我的文章中详细描述了这些角色:你是什么类型的数据科学家?。但是,下表总结了每种角色类型所需的典型学位要求,包括级别和领域以及关键技术。

根据他们在数据科学领域所处的位置,将上面列出的七种角色类型进行分组,并根据所涉及的技术要求级别对他们进行排名,从而出现了两条进入数据科学的职业道路。

职业道路#1:统计和洞察数据科学

对于那些有统计或数学背景的人来说,洞察分析师的角色可以提供进入众所周知的数据科学大门的一只脚,而不需要硕士学位。

Insights analyst 角色通常以“数据分析师”的头衔进行广告宣传,尽管在一些组织中也可能以“数据科学家”的职位进行广告宣传,并且通常专注于提取、争论和分析数据,以便提供见解并生成报告和/或仪表板。这些技能都与在统计领域工作的数据科学家通常需要的技能相重叠。

insights 分析师角色和真正的数据科学职位之间的主要区别在于,insights 分析师通常不需要拥有数据科学家所需的机器学习和统计技术方面的高级知识。然而,这并不意味着这些技能不能在担任这样的角色时得到发展(无论是通过开发涉及这些技能的工作项目,还是通过额外的学习)。

随着相关技能和经验的发展,洞察分析师角色自然会成为数据科学通才,而这又自然会成为数据科学专家角色。

职业道路#2:工程和开发数据科学

另一方面,对于那些更接近计算机科学的人来说,报告和 ETL 分析师、平台和仓库工程师或 ML 软件工程师都可以提供数据科学的切入点,这取决于你的计算机科学和软件开发技能水平。

报告和 ETL 分析师(通常以“数据分析师”或“商业智能分析师”的头衔宣传),以及平台和仓库工程师(通常宣传为“数据工程师”)角色都非常强调能够管理数据库、仓库或平台中的数据。

两者通常只需要计算机科学学士学位,报告和 ETL 分析师倾向于更关注传统(关系型)数据库,平台和仓库工程师更关注更现代的(非关系型)大数据平台。

这些角色通常位于数据科学/分析团队中,让他们有机会与数据科学家合作,尽管在机器学习和统计方面没有相同的技术要求。然而,根据团队经理的态度,这些角色的人可能有能力随着时间的推移提升技能并过渡到数据科学角色。

平台和仓库工程师角色也经常有很强的软件开发方面,导致这些角色自然地进入 ML 软件工程师角色(通常在标题“机器学习工程师”下广告)。

机器学习软件工程师和机器学习研究数据科学家本质上是一枚硬币的两面,前者专注于模型部署,后者专注于模型开发。因此,随着技能和资格的增长,机器学习软件工程师角色可以自然地成为机器学习研究数据科学家。

上面介绍的两条职业道路绝不是进入数据科学的唯一职业道路。仅仅因为你开始是一名报告和 ETL 分析师,并不意味着你不会有一天成为数据科学专家。

这不是捉鬼敢死队,溪流可以穿越。

举例来说,我自己的职业生涯包括在成为数据科学通才之前担任洞察分析师,然后成为 ML Research 数据科学家。

然而,对于那些希望过渡到数据科学,或在数据科学阶梯上向上移动的人来说,这些职业道路提供了一个模板来指导你,并提供了一种方法来确定你的技能在数据科学层次中的位置。

因此,如果你正在寻找数据科学方面的角色,找到你的技能最接近的角色类型,并开始搜索和申请该类型的数据相关角色。一旦你得到了第一个角色,看看接下来是什么角色,然后开始朝那个方向努力。

数据科学是一个旅程,就像任何其他旅程一样,如果你有一张地图,这将容易得多。

Genevieve Hayes 博士是数据科学家、教育家和人工智能及分析专家,拥有Genevieve Hayes Consulting。你可以在LinkedIn或者Twitter上关注她。她还是 价值驱动数据科学 的主持人,这是一个每月两次的播客,面向希望最大化其数据和数据团队价值的企业。

想要发掘企业数据的价值,但不知道从哪里开始?**下载免费的数据科学项目发现指南。

在 R 中使用来自 Google 的新 Turbo 调色板

原文:https://towardsdatascience.com/using-the-new-turbo-palette-from-google-in-r-af19b9424cc0?source=collection_archive---------19-----------------------

注意:这是最初发布在我的博客上的

几天前,一名来自谷歌的人工智能工程师发布了一个他开发的新调色板。这个调色板“Turbo”和广泛使用的“jet”调色板一样丰富多彩,但感觉上是统一的,并且像的绿色调色板一样对色盲友好。他分享了使用调色板的 python 和 C 代码,但 R 中没有任何内容。其他人从开始发布 R 中的代码,尽管还需要一点工作来使其可用于我最喜欢的图形包 ggplot2。这是一篇关于如何快速开始在 ggplots 中使用 Turbo 的短文。

编辑:这篇文章的代码现在也可以在这里找到:https://github.com/dbaranger/turbo_palette_R

首先,我们需要颜色的实际值,这是在 sRGB 给出的。然后我把这些转换成十六进制代码,这就是 ggplot2 使用的。

install.packages("colorspace")
library(colorspace)A<-c((0.18995),(0.19483),(0.19956),(0.20415),(0.2086),(0.21291),(0.21708),(0.22111),(0.225),(0.22875),(0.23236),(0.23582),(0.23915),(0.24234),(0.24539),(0.2483),(0.25107),(0.25369),(0.25618),(0.25853),(0.26074),(0.2628),(0.26473),(0.26652),(0.26816),(0.26967),(0.27103),(0.27226),(0.27334),(0.27429),(0.27509),(0.27576),(0.27628),(0.27667),(0.27691),(0.27701),(0.27698),(0.2768),(0.27648),(0.27603),(0.27543),(0.27469),(0.27381),(0.27273),(0.27106),(0.26878),(0.26592),(0.26252),(0.25862),(0.25425),(0.24946),(0.24427),(0.23874),(0.23288),(0.22676),(0.22039),(0.21382),(0.20708),(0.20021),(0.19326),(0.18625),(0.17923),(0.17223),(0.16529),(0.15844),(0.15173),(0.14519),(0.13886),(0.13278),(0.12698),(0.12151),(0.11639),(0.11167),(0.10738),(0.10357),(0.10026),(0.0975),(0.09532),(0.09377),(0.09287),(0.09267),(0.0932),(0.09451),(0.09662),(0.09958),(0.10342),(0.10815),(0.11374),(0.12014),(0.12733),(0.13526),(0.14391),(0.15323),(0.16319),(0.17377),(0.18491),(0.19659),(0.20877),(0.22142),(0.23449),(0.24797),(0.2618),(0.27597),(0.29042),(0.30513),(0.32006),(0.33517),(0.35043),(0.36581),(0.38127),(0.39678),(0.41229),(0.42778),(0.44321),(0.45854),(0.47375),(0.48879),(0.50362),(0.51822),(0.53255),(0.54658),(0.56026),(0.57357),(0.58646),(0.59891),(0.61088),(0.62233),(0.63323),(0.64362),(0.65394),(0.66428),(0.67462),(0.68494),(0.69525),(0.70553),(0.71577),(0.72596),(0.7361),(0.74617),(0.75617),(0.76608),(0.77591),(0.78563),(0.79524),(0.80473),(0.8141),(0.82333),(0.83241),(0.84133),(0.8501),(0.85868),(0.86709),(0.8753),(0.88331),(0.89112),(0.8987),(0.90605),(0.91317),(0.92004),(0.92666),(0.93301),(0.93909),(0.94489),(0.95039),(0.9556),(0.96049),(0.96507),(0.96931),(0.97323),(0.97679),(0.98),(0.98289),(0.98549),(0.98781),(0.98986),(0.99163),(0.99314),(0.99438),(0.99535),(0.99607),(0.99654),(0.99675),(0.99672),(0.99644),(0.99593),(0.99517),(0.99419),(0.99297),(0.99153),(0.98987),(0.98799),(0.9859),(0.9836),(0.98108),(0.97837),(0.97545),(0.97234),(0.96904),(0.96555),(0.96187),(0.95801),(0.95398),(0.94977),(0.94538),(0.94084),(0.93612),(0.93125),(0.92623),(0.92105),(0.91572),(0.91024),(0.90463),(0.89888),(0.89298),(0.88691),(0.88066),(0.87422),(0.8676),(0.86079),(0.8538),(0.84662),(0.83926),(0.83172),(0.82399),(0.81608),(0.80799),(0.79971),(0.79125),(0.7826),(0.77377),(0.76476),(0.75556),(0.74617),(0.73661),(0.72686),(0.71692),(0.7068),(0.6965),(0.68602),(0.67535),(0.66449),(0.65345),(0.64223),(0.63082),(0.61923),(0.60746),(0.5955),(0.58336),(0.57103),(0.55852),(0.54583),(0.53295),(0.51989),(0.50664),(0.49321),(0.4796))
B<-c((0.07176),(0.08339),(0.09498),(0.10652),(0.11802),(0.12947),(0.14087),(0.15223),(0.16354),(0.17481),(0.18603),(0.1972),(0.20833),(0.21941),(0.23044),(0.24143),(0.25237),(0.26327),(0.27412),(0.28492),(0.29568),(0.30639),(0.31706),(0.32768),(0.33825),(0.34878),(0.35926),(0.3697),(0.38008),(0.39043),(0.40072),(0.41097),(0.42118),(0.43134),(0.44145),(0.45152),(0.46153),(0.47151),(0.48144),(0.49132),(0.50115),(0.51094),(0.52069),(0.5304),(0.54015),(0.54995),(0.55979),(0.56967),(0.57958),(0.5895),(0.59943),(0.60937),(0.61931),(0.62923),(0.63913),(0.64901),(0.65886),(0.66866),(0.67842),(0.68812),(0.69775),(0.70732),(0.7168),(0.7262),(0.73551),(0.74472),(0.75381),(0.76279),(0.77165),(0.78037),(0.78896),(0.7974),(0.80569),(0.81381),(0.82177),(0.82955),(0.83714),(0.84455),(0.85175),(0.85875),(0.86554),(0.87211),(0.87844),(0.88454),(0.8904),(0.896),(0.90142),(0.90673),(0.91193),(0.91701),(0.92197),(0.9268),(0.93151),(0.93609),(0.94053),(0.94484),(0.94901),(0.95304),(0.95692),(0.96065),(0.96423),(0.96765),(0.97092),(0.97403),(0.97697),(0.97974),(0.98234),(0.98477),(0.98702),(0.98909),(0.99098),(0.99268),(0.99419),(0.99551),(0.99663),(0.99755),(0.99828),(0.99879),(0.9991),(0.99919),(0.99907),(0.99873),(0.99817),(0.99739),(0.99638),(0.99514),(0.99366),(0.99195),(0.98999),(0.98775),(0.98524),(0.98246),(0.97941),(0.9761),(0.97255),(0.96875),(0.9647),(0.96043),(0.95593),(0.95121),(0.94627),(0.94113),(0.93579),(0.93025),(0.92452),(0.91861),(0.91253),(0.90627),(0.89986),(0.89328),(0.88655),(0.87968),(0.87267),(0.86553),(0.85826),(0.85087),(0.84337),(0.83576),(0.82806),(0.82025),(0.81236),(0.80439),(0.79634),(0.78823),(0.78005),(0.77181),(0.76352),(0.75519),(0.74682),(0.73842),(0.73),(0.7214),(0.7125),(0.7033),(0.69382),(0.68408),(0.67408),(0.66386),(0.65341),(0.64277),(0.63193),(0.62093),(0.60977),(0.59846),(0.58703),(0.57549),(0.56386),(0.55214),(0.54036),(0.52854),(0.51667),(0.50479),(0.49291),(0.48104),(0.4692),(0.4574),(0.44565),(0.43399),(0.42241),(0.41093),(0.39958),(0.38836),(0.37729),(0.36638),(0.35566),(0.34513),(0.33482),(0.32473),(0.31489),(0.3053),(0.29599),(0.28696),(0.27824),(0.26981),(0.26152),(0.25334),(0.24526),(0.2373),(0.22945),(0.2217),(0.21407),(0.20654),(0.19912),(0.19182),(0.18462),(0.17753),(0.17055),(0.16368),(0.15693),(0.15028),(0.14374),(0.13731),(0.13098),(0.12477),(0.11867),(0.11268),(0.1068),(0.10102),(0.09536),(0.0898),(0.08436),(0.07902),(0.0738),(0.06868),(0.06367),(0.05878),(0.05399),(0.04931),(0.04474),(0.04028),(0.03593),(0.03169),(0.02756),(0.02354),(0.01963),(0.01583))
C<-c((0.23217),(0.26149),(0.29024),(0.31844),(0.34607),(0.37314),(0.39964),(0.42558),(0.45096),(0.47578),(0.50004),(0.52373),(0.54686),(0.56942),(0.59142),(0.61286),(0.63374),(0.65406),(0.67381),(0.693),(0.71162),(0.72968),(0.74718),(0.76412),(0.7805),(0.79631),(0.81156),(0.82624),(0.84037),(0.85393),(0.86692),(0.87936),(0.89123),(0.90254),(0.91328),(0.92347),(0.93309),(0.94214),(0.95064),(0.95857),(0.96594),(0.97275),(0.97899),(0.98461),(0.9893),(0.99303),(0.99583),(0.99773),(0.99876),(0.99896),(0.99835),(0.99697),(0.99485),(0.99202),(0.98851),(0.98436),(0.97959),(0.97423),(0.96833),(0.9619),(0.95498),(0.94761),(0.93981),(0.93161),(0.92305),(0.91416),(0.90496),(0.8955),(0.8858),(0.8759),(0.86581),(0.85559),(0.84525),(0.83484),(0.82437),(0.81389),(0.80342),(0.79299),(0.78264),(0.7724),(0.7623),(0.75237),(0.74265),(0.73316),(0.72393),(0.715),(0.70599),(0.69651),(0.6866),(0.67627),(0.66556),(0.65448),(0.64308),(0.63137),(0.61938),(0.60713),(0.59466),(0.58199),(0.56914),(0.55614),(0.54303),(0.52981),(0.51653),(0.50321),(0.48987),(0.47654),(0.46325),(0.45002),(0.43688),(0.42386),(0.41098),(0.39826),(0.38575),(0.37345),(0.3614),(0.34963),(0.33816),(0.32701),(0.31622),(0.30581),(0.29581),(0.28623),(0.27712),(0.26849),(0.26038),(0.2528),(0.24579),(0.23937),(0.23356),(0.22835),(0.2237),(0.2196),(0.21602),(0.21294),(0.21032),(0.20815),(0.2064),(0.20504),(0.20406),(0.20343),(0.20311),(0.2031),(0.20336),(0.20386),(0.20459),(0.20552),(0.20663),(0.20788),(0.20926),(0.21074),(0.2123),(0.21391),(0.21555),(0.21719),(0.2188),(0.22038),(0.22188),(0.22328),(0.22456),(0.2257),(0.22667),(0.22744),(0.228),(0.22831),(0.22836),(0.22811),(0.22754),(0.22663),(0.22536),(0.22369),(0.22161),(0.21918),(0.2165),(0.21358),(0.21043),(0.20706),(0.20348),(0.19971),(0.19577),(0.19165),(0.18738),(0.18297),(0.17842),(0.17376),(0.16899),(0.16412),(0.15918),(0.15417),(0.1491),(0.14398),(0.13883),(0.13367),(0.12849),(0.12332),(0.11817),(0.11305),(0.10797),(0.10294),(0.09798),(0.0931),(0.08831),(0.08362),(0.07905),(0.07461),(0.07031),(0.06616),(0.06218),(0.05837),(0.05475),(0.05134),(0.04814),(0.04516),(0.04243),(0.03993),(0.03753),(0.03521),(0.03297),(0.03082),(0.02875),(0.02677),(0.02487),(0.02305),(0.02131),(0.01966),(0.01809),(0.0166),(0.0152),(0.01387),(0.01264),(0.01148),(0.01041),(0.00942),(0.00851),(0.00769),(0.00695),(0.00629),(0.00571),(0.00522),(0.00481),(0.00449),(0.00424),(0.00408),(0.00401),(0.00401),(0.0041),(0.00427),(0.00453),(0.00486),(0.00529),(0.00579),(0.00638),(0.00705),(0.0078),(0.00863),(0.00955),(0.01055))

turbo_colormap_data<-cbind(A,B,C) 
turbo_colormap_data_sRGB<-sRGB(turbo_colormap_data)
turbo_colormap_data_HEX = hex(turbo_colormap_data_sRGB)

现在让我们来看看调色板:

install.packages("pals")
library(pals)TurboPalette<-colorRampPalette(colors = turbo_colormap_data_HEX ,space="rgb", interpolate = "spline")
pal.test(TurboPalette)

整体 Turbo 表现相当不错。它缺少的一个地方是亮度曲线(灰色线,右下角)。亮度在调色板的中途达到峰值,因此使用整个调色板进行连续缩放可能不是在所有情况下都能很好地工作。

最后,我编写了一个更短的助手函数,以便更容易地将调色板集成到 ggplot2 中:

Turbo <- function(pal.min = 0,pal.max = 1,out.colors = NULL,pal = turbo_colormap_data_HEX,reverse = F) {
 # pal.min = lower bound of the palette to use [0,1]
 # pal.max = upper bound of the palette [0,1]
 # out.colors = specify the number of colors to return if out.colors = 1, will return pal.min color. if unspecified, will return all the colors in the original palette that fall within the min and max boundaries
 # pal = vector of colors (HEX) in palette
 # reverse = flip palette T/F - performed as last step

  if(pal.min == 0){pal.start = 1}
  if(pal.min > 0){pal.start = round(length(pal)*pal.min) }
  pal.end = round(length(pal)*pal.max )
  out = pal[pal.start:pal.end]

 if(!is.null(out.colors)){
   pal2 = colorRampPalette(colors = out ,space="rgb", interpolate = "linear")
   out = pal2(out.colors)
 }
  if(reverse == T){out = rev(out)}
  return(out)
}

该函数将调色板分成子集,如果需要,将输出指定数量的颜色(对分类变量有用)。

现在让我们来兜一圈吧!下面我从 http://r-statistics.co/的中借用分类变量和一个连续变量。

分类变量是一个华夫图。请注意,下面我已经注释掉了原来的颜色,它是一个 colorBrewer 刻度,并替换为一个手动刻度,其颜色由我的新 Turbo()函数提供:

var <- mpg$class  # the categorical data 
nrows <- 10
df <- expand.grid(y = 1:nrows, x = 1:nrows)
categ_table <- round(table(var) * ((nrows*nrows)/(length(var))))
categ_table
df$category <- factor(rep(names(categ_table), categ_table)) ggplot(df, aes(x = x, y = y, fill = category)) + 
  geom_tile(color = "black", size = 0.5) +
  scale_x_continuous(expand = c(0, 0)) +
  scale_y_continuous(expand = c(0, 0), trans = 'reverse') +
 ####scale_fill_brewer(palette = "Set3") +####
  scale_fill_manual(values = Turbo(out.colors = 7))+ ## This is the change
  labs(title="Waffle Chart", subtitle="'Class' of vehicles",
       caption="Source: mpg") + 
  theme(panel.border = element_rect(size = 2),
        plot.title = element_text(size = rel(1.2)),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        legend.title = element_blank(),
        legend.position = "right")

我已经用“scale _ fill _ manual(values = Turbo(out . colors = 7)”替换了“scale _ fill _ brewer(palette = " set 3"”。

如果我们不喜欢它的颜色,两端很暗,我们可以改变调色板的最小值和最大值:“scale _ fill _ manual(values = Turbo(out . colors = 7,pal.min = .1,pal.max = .9)”

好多了!现在让我们用一个连续的尺度来尝试一下,像热图,再次借用 http://r-statistics.co/。

library(ggplot2)
library(plyr)
library(scales)
library(zoo)
df <- read.csv("https://raw.githubusercontent.com/selva86/datasets/master/yahoo.csv")
df$date <- as.Date(df$date)  # format date
df <- df[df$year >= 2012, ]  # filter red years
# Create Month Week
df$yearmonth <- as.yearmon(df$date)
df$yearmonthf <- factor(df$yearmonth)
df <- ddply(df,.(yearmonthf), transform, monthweek=1+week-min(week))  # compute week number of month
df <- df[, c("year", "yearmonthf", "monthf", "week", "monthweek", "weekdayf", "VIX.Close")]
# Plot
ggplot(df, aes(monthweek, weekdayf, fill = VIX.Close)) + 
  geom_tile(colour = "white") + 
  facet_grid(year~monthf) + 
  ###scale_fill_gradient(low="red", high="green") +##
  scale_fill_gradientn(colours = Turbo()) + ## this is new
  labs(x="Week of Month",
       y="",
       title = "Time-Series Calendar Heatmap", 
       subtitle="Yahoo Closing Price", 
       fill="Close")

请注意,我已经将“scale_fill_gradient(low="red ",high="green ")”替换为“scale _ fill _ gradient n(colours = Turbo())”。

上面图的一个问题是绿色“弹出”太多,所以我们注意中间值,而不是最大值。这是因为,正如上面的第一张图所示,亮度曲线在调色板的中间达到峰值,在绿色部分。因此,我们可以用颜色的子集来绘图,并翻转调色板,使较浅的颜色更高。这里我把填充改为:“scale _ fill _ gradient n(colors = Turbo(pal . min = . 6,pal.max = 1,reverse = T))

现在,哪一天包含最高值就清楚多了。

就这些了,祝大家策划愉快!

使用熊猫数据框作为数据库。

原文:https://towardsdatascience.com/using-the-pandas-data-frame-as-a-database-282edec5a3ab?source=collection_archive---------5-----------------------

让我们了解如何使用熊猫数据框作为数据库。

Image Credits: Usejournal

在开始之前,让我快速介绍一下 pandas data frame:它是一个 python 库,为 python 编程语言的数据分析工具提供了高性能和易于使用的数据结构。下面的文章解释了在熊猫数据框上执行的原始操作。

[## 使用 Python 操作熊猫的数据。

让我们用 Python 来计算我的熊猫数据框架兼职收入。

towardsdatascience.com](/manipulating-the-data-with-pandas-using-python-be6c5dfabd47)

让我们开始吧,这是一个编程教程,所以我推荐你们和我一起练习。我喜欢使用谷歌笔记本或 T2 笔记本。简而言之,我将教你们如何使用熊猫数据框作为数据库来存储数据并对其执行一些基本操作。与数据库相比,此数据框具有几乎所有的功能。它几乎类似于一个数据库。也要获得完整代码请访问我的 GitHub 资源库 下面:

[## 塔努-北帕布/Python

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/Tanu-N-Prabhu/Python/blob/master/Using_the_Pandas_Data_Frame_as_a_Database_.ipynb)

本教程将遵循的步骤有

  1. 创建熊猫数据框

2.向数据框添加行

3.从数据框中删除行

4.从数据框中访问行的值

5.更改数据框中行的值

让我们看看如何执行上面声明的所有步骤

1。创建熊猫数据框

要创建数据框,首先需要导入数据框,然后必须按如下所示的顺序指定列名和值:

import pandas as pd

让我们创建一个新的数据框。我正在存储公司名称、创始人、创办人和员工人数。您可以在数据框中存储您选择的数据。

df = pd.DataFrame({‘Company Name’:[‘Google’, ‘Microsoft’, ‘SpaceX’,‘Amazon’,‘Samsung’]‘Founders’:[‘Larry Page, Sergey Brin’, ‘Bill Gates, Paul Allen’,’Elon Musk’,’Jeff Bezos’, ‘Lee Byung-chul’],‘Founded’: [1998, 1975, 2002, 1994, 1938],‘Number of Employees’: [‘103,459’, ‘144,106’, ‘6,500’, ‘647,500’, ‘320,671’]})df **# used to print the data frame df, or use print(df) both are same**

不要担心,这里没有什么复杂的,只是价值观可能会让你困惑,因为它们只是公司名称、创始人、创办人等。小心括号,如果你弄乱了它,你的生活会变得很痛苦。

2.向数据框添加新行

假设现在您想要向数据框添加一个新行,您所能做的就是将新行添加到数据框的末尾或您选择的任何特定位置。

情况 1:在数据帧的末尾添加一行:

要将行追加到数据框的末尾,您需要使用“ append 方法,传递您想要追加的值。以下是 append 函数的官方文档:

[## 熊猫。DataFrame.append - pandas 0.25.3 文档

将 other 的行追加到调用方的末尾,返回一个新对象。“其他”中不在调用者中的列是…

pandas.pydata.org](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.append.html)

让我们用新值创建一个新的数据框,然后将其追加到现有数据框的末尾。

df1 = pd.DataFrame({‘Company Name’:[‘WhatsApp’], 
‘Founders’:[‘Jan Koum, Brian Acton’], 
‘Founded’: [2009], 
‘Number of Employees’: [‘50’] })df1

df1 是我们想要添加到现有数据帧 df 的新数据帧

df = df.append(df1, ignore_index=True)df

案例 2:在特定位置添加新行

现在让我们在索引 3 处添加一个新的值行,意思是在“SpaceX”公司下面。为此,我们可以通过指定索引和要添加的值来使用 pandas " iloc 方法。以下是 iloc 方法的文档

[## 熊猫。DataFrame.iloc - pandas 0.25.3 文档

完全基于整数位置的索引,用于按位置选择。主要基于整数位置(从到的…

pandas.pydata.org](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.iloc.html)

df.iloc[3] = [‘YouTube’, ‘Chad Hurley, Steve Chen, Jawed Karim’, 2005, ‘2,800’]df

在 iloc 的帮助下,我们可以在数据框内的任意位置添加新行。

3.从数据框中删除行

有时,您可能很少需要从数据库或数据框中移除不必要的数据。为此,pandas 中的“ drop 方法”完成了这项工作。让我们来看两种情况,比如删除带有索引的行和借助值删除行。下面是熊猫下降方法的文档:

[## 熊猫。data frame . drop-pandas 0 . 25 . 3+0 . g 851328575 . dirty 文档

从行或列中删除指定的标签。通过指定标签名称和相应的轴来删除行或列,或者…

pandas.pydata.org](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.drop.html)

案例 1:删除带有索引的行

现在,这可以通过在 drop 方法中提到索引来实现

df = df.drop([df.index[5]])df

如上所示,索引 5,即 WhatsApp 公司的行被完全删除。

案例 2:借助值删除一行。

现在让我们看看如何删除一行及其值。

df = df[df.Founders != ‘Chad Hurley, Steve Chen, Jawed Karim’]df

现在 YouTube company 的行在提供其值的帮助下被删除。

4.从数据框中访问行的值

从数据框中访问值非常简单,您所要做的就是使用“ loc 方法”。loc 方法接受索引作为参数,通过指定它,您可以从中检索值。以下是 loc 方法的文档:

[## 熊猫。data frame . loc-pandas 0 . 25 . 3+0 . g 851328575 . dirty 文档

通过标签或布尔数组访问一组行和列。主要基于标签,但也可用于…

pandas.pydata.org](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.loc.html)

现在,让我们假设我们需要访问第三行的值,调用 loc2 ,你的工作就完成了。这些行从第 0 个索引开始存储,因此第 3 行索引是 2 (0,1,2)。

df.loc[2]**Company Name SpaceX 
Founders Elon Musk 
Founded 2002 
Number of Employees 6,500
Name: 2, dtype: object**

5.更改数据框中行的值

这可以通过使用“at”方法来完成。要使用“at”方法,您只需指定它的索引和列名的位置,然后指定需要更改的值。以下是“at”方法的文档:

[## 熊猫。DataFrame.at - pandas 0.23.1 文档

编辑描述

pandas.pydata.org](https://pandas.pydata.org/pandas-docs/version/0.23/generated/pandas.DataFrame.at.html)

举个例子,假设我想把微软的员工人数改成 20 万人(对不起微软为了我的教程我不得不这么做)。

df.at[1, ‘Number of Employees’] = ‘200,000’df

This is after the change of value (Microsoft)

This is before the change of value (Microsoft)

这就是如何将熊猫数据框用作数据库。您已经成功完成了本教程的所有步骤。我希望你喜欢读它。在数据帧上可以执行更多的操作、功能或方法。我不能一口气解释所有的操作,如果你们需要更多关于这些概念的教程,请告诉我。此外,如果你们有任何疑问,请联系我或在评论区发表回复,我会尽快回复。不要忘记阅读我在本教程中提供的熊猫官方数据框的所有文档链接。在那之前再见。祝你愉快。

使用熊猫“重采样”功能

原文:https://towardsdatascience.com/using-the-pandas-resample-function-a231144194c4?source=collection_archive---------1-----------------------

Photo by JESHOOTS.COM on Unsplash

改变过去的下一件最好的事情——将它聚合起来。熊猫重采样功能的技术介绍。

T 他的文章是对用于日期时间操作的熊猫重采样功能的技术方面的介绍。我希望它能成为那些不太愿意去挖掘熊猫源代码的人的一个可读的伪文档来源!

如果您想查看用于生成示例的代码并查看本文中未包含的更多示例,请单击此处的链接。

我们开始吧!

什么是重采样?

当给定一个以某个时间间隔记录的数据集,并且您想将时间间隔更改为其他时间间隔时,重新采样是必要的。例如,您可以将每月数据聚合为年度数据,或者将每小时数据向上采样为分钟数据。

重采样的语法非常简单:

<DataFrame or Series>.**resample(arguments).<aggregate function>**

我将深入探讨什么是参数以及如何使用它们,但首先这里有一个基本的、现成的演示。您将需要一个日期时间类型的索引或列来执行以下操作:

# Given a Series object called data with some number value per date
>>>
╔═══════════════════════╦══════╗
║         date          ║ val  ║
╠═══════════════════════╬══════╣
║ 2000-01-01 00:00:00   ║    0 ║
║ 2000-01-01 00:01:00   ║    2 ║
║ 2000-01-01 00:02:00   ║    4 ║
║ 2000-01-01 00:03:00   ║    6 ║
║ 2000-01-01 00:04:00   ║    8 ║
║ 2000-01-01 00:05:00   ║   10 ║
║ 2000-01-01 00:06:00   ║   12 ║
║ 2000-01-01 00:07:00   ║   14 ║
║ 2000-01-01 00:08:00   ║   16 ║
╚═══════════════════════╩══════╝
Freq: T, dtype: int64# We can **resample this** to every other minute instead and aggregate by summing the intermediate rows:
data.resample('2min').sum()>>>

╔═════════════════════╦══════╗
║        date         ║ val  ║
╠═════════════════════╬══════╣
║ 2000-01-01 00:00:00 ║    2 ║
║ 2000-01-01 00:02:00 ║   10 ║
║ 2000-01-01 00:04:00 ║   18 ║
║ 2000-01-01 00:06:00 ║   26 ║
║ 2000-01-01 00:08:00 ║   16 ║
╚═════════════════════╩══════╝Freq: 2T, dtype: int64

现在,我们已经对重采样有了基本的了解,让我们进入代码!

争论

按照源代码的顺序:

pd.DataFrame.resample
(
**rule,** 
how=None, 
**axis=0,** fill_method=None, 
**closed=None, 
label=None,** 
convention=”start”, 
kind=None, **
loffset=None,** 
limit=None, 
**base=0, 
on=None,** 
**level=None** )

我已经大胆提出了我将涉及的论点。其余部分要么被弃用,要么用于句点,而不是日期时间分析,我在本文中将不再赘述。

1.“规则”参数

string包含规则别名和/或数字

这是重采样的核心。您在这里输入的字符串决定了数据重新采样的时间间隔,如下行的粗体部分所示:

data.resample('**2min**').sum()

如您所见,您可以在字符串前插入浮点数或整数来更改频率。您甚至可以在非常特定的时间内将多对浮点/字符串组合在一起!例如:

'3min' or '3T' = 3 minutes'SMS' = Two times a month'1D3H.5min20S' = One Day, 3 hours, .5min(30sec) + 20sec

为了省去查找重采样字符串的麻烦,我发布了下表:

From Pandas documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#offset-aliases

一旦你加入了你的规则,你需要决定如何减少旧的数据点或者填充新的数据点。该函数紧接在重采样函数调用之后:

data.resample('2min').**sum()**

重采样有两种:

  1. 下采样 —在更宽的时间范围内(从几个月到几年)重新采样
  • 这非常简单,因为它可以使用所有的 groupby 聚合函数,包括 mean()、min()、max()、sum() 等等。
  • 在下采样中,行数从下降到

2 .上采样 —在更短的时间内(从小时到分钟)重新采样

这将导致额外的空行,因此您有以下选项用数值填充这些空行:

1\. ffill() or pad()
2\. bfill() or backfill()
  • ‘向前填充’或‘填充’—使用最后一个已知值填充新值。
  • ‘回填’—使用下一个已知值来填充新值。
  • 您还可以使用不带参数的 asfreq() 函数用 nan 填充。这将产生包含 nan 的新数据点,您可以稍后使用 fillna() 函数。

以下是向前和向后填充的一些演示:

Starting with months table:
╔════════════╦═════╗
║    date    ║ val ║
╠════════════╬═════╣
║ 2000-01-31 ║   0 ║
║ 2000-02-29 ║   2 ║
║ 2000-03-31 ║   4 ║
║ 2000-04-30 ║   6 ║
║ 2000-05-31 ║   8 ║
╚════════════╩═════╝print('Forward Fill')
print(months.resample('SMS').ffill())╔════════════╦═════╗
║    date    ║ val ║
╠════════════╬═════╣
║ 2000-01-15 ║ NaN ║
║ 2000-02-01 ║ 0.0 ║
║ 2000-02-15 ║ 0.0 ║
║ 2000-03-01 ║ 2.0 ║
║ 2000-03-15 ║ 2.0 ║
║ 2000-04-01 ║ 4.0 ║
║ 2000-04-15 ║ 4.0 ║
║ 2000-05-01 ║ 6.0 ║
║ 2000-05-15 ║ 6.0 ║
╚════════════╩═════╝# Alternative to ffill is bfill (backward fill) that takes value of next existing months point
print('Backward Fill')
print(months.resample('SMS').bfill())╔════════════╦═════╗
║    date    ║ val ║
╠════════════╬═════╣
║ 2000-01-15 ║   0 ║
║ 2000-02-01 ║   2 ║
║ 2000-02-15 ║   2 ║
║ 2000-03-01 ║   4 ║
║ 2000-03-15 ║   4 ║
║ 2000-04-01 ║   6 ║
║ 2000-04-15 ║   6 ║
║ 2000-05-01 ║   8 ║
║ 2000-05-15 ║   8 ║
╚════════════╩═════╝

2.“关闭”参数

'left', 'right', or None

我将在这里包括他们的文档注释,因为它相当简洁地描述了基础知识。

仓区间的哪一侧是封闭的。除了“M”、“A”、“Q”、“BM”、“T20”、“BA”、“BQ”和“W”之外,所有频率偏移的默认值都是“左”。

closed 参数告诉哪一侧被包括在内,‘closed’是在每个时间间隔的计算中包括的一侧(意味着另一侧不包括在内)。你可以在这里看到它的表现:

# Original Table 'minutes'

╔═════════════════════╦═════╗
║        date         ║ val ║
╠═════════════════════╬═════╣
║ 2000-01-01 00:00:00 ║   0 ║
║ 2000-01-01 00:01:00 ║   2 ║
║ 2000-01-01 00:02:00 ║   4 ║
║ 2000-01-01 00:03:00 ║   6 ║
║ 2000-01-01 00:04:00 ║   8 ║
║ 2000-01-01 00:05:00 ║  10 ║
║ 2000-01-01 00:06:00 ║  12 ║
║ 2000-01-01 00:07:00 ║  14 ║
║ 2000-01-01 00:08:00 ║  16 ║
╚═════════════════════╩═════╝# The default is closed='left'
df=pd.DataFrame()
df['left'] = minutes.resample('2min').sum()
df['right'] = minutes.resample('2min',closed='right').sum()
df
>>>╔═════════════════════╦══════╦═══════╗
║ index               ║ left ║ right ║
╠═════════════════════╬══════╬═══════╣
║ 2000-01-01 00:00:00 ║ 2    ║ 6.0   ║
║ 2000-01-01 00:02:00 ║ 10   ║ 14.0  ║
║ 2000-01-01 00:04:00 ║ 18   ║ 22.0  ║
║ 2000-01-01 00:06:00 ║ 26   ║ 30.0  ║
║ 2000-01-01 00:08:00 ║ 16   ║ NaN   ║
╚═════════════════════╩══════╩═══════╝

3.“标签”参数

'left', 'right', or None

同样,文档非常有用。

用哪个箱柜边缘标签来标记桶。除了“M”、“A”、“Q”、“BM”、“BA”、“BQ”和“W”之外,所有频率偏移的默认值都是“左”。

此参数不会更改基础计算,它只是在执行聚合后根据所需的边重新标记输出。

df=pd.DataFrame()
# Label default is left
df['left'] = minutes.resample('2min').sum()
df['right'] = minutes.resample('2min',label='right').sum()
df>>>╔═════════════════════╦══════╦═══════╗
║                     ║ left ║ right ║
╠═════════════════════╬══════╬═══════╣
║ 2000-01-01 00:00:00 ║    2 ║ NaN   ║
║ 2000-01-01 00:02:00 ║   10 ║ 2.0   ║
║ 2000-01-01 00:04:00 ║   18 ║ 10.0  ║
║ 2000-01-01 00:06:00 ║   26 ║ 18.0  ║
║ 2000-01-01 00:08:00 ║   16 ║ 26.0  ║
╚═════════════════════╩══════╩═══════╝

4.“Loffset”参数

string匹配规则符号。

这个论点也是不言自明的。它没有改变任何计算,只是在指定的时间内移动标签。

df=pd.DataFrame()
df['no_offset'] = minutes.resample('2min').sum()
df['2min_offset'] = minutes.resample('2min',loffset='2T').sum()
df['4min_offset'] = minutes.resample('2min',loffset='4T').sum()
df>>>
╔═════════════════════╦═══════════╦═════════════╦═════════════╗
║ index               ║ no_offset ║ 2min_offset ║ 4min_offset ║
╠═════════════════════╬═══════════╬═════════════╬═════════════╣
║ 2000-01-01 00:00:00 ║         2 ║ NaN         ║ NaN         ║
║ 2000-01-01 00:02:00 ║        10 ║ 2.0         ║ NaN         ║
║ 2000-01-01 00:04:00 ║        18 ║ 10.0        ║ 2.0         ║
║ 2000-01-01 00:06:00 ║        26 ║ 18.0        ║ 10.0        ║
║ 2000-01-01 00:08:00 ║        16 ║ 26.0        ║ 18.0        ║
╚═════════════════════╩═══════════╩═════════════╩═════════════╝

5.“基本”参数

numeric与重采样规则中使用的单位相关的输入

将计算的基准时间移动一段时间。正如文档所描述的,该函数移动“原点”。

minutes.head().resample('30S').sum()
>>>

╔═════════════════════╦═════╗
║        date         ║ val ║
╠═════════════════════╬═════╣
║ 2000-01-01 00:00:00 ║   0 ║
║ 2000-01-01 00:00:30 ║   0 ║
║ 2000-01-01 00:01:00 ║   2 ║
║ 2000-01-01 00:01:30 ║   0 ║
║ 2000-01-01 00:02:00 ║   4 ║
║ 2000-01-01 00:02:30 ║   0 ║
║ 2000-01-01 00:03:00 ║   6 ║
║ 2000-01-01 00:03:30 ║   0 ║
║ 2000-01-01 00:04:00 ║   8 ║
╚═════════════════════╩═════╝minutes.head().resample('30S',base=15).sum()
>>>

╔═════════════════════╦═════╗
║        date         ║ val ║
╠═════════════════════╬═════╣
║ 1999-12-31 23:59:45 ║   0 ║
║ 2000-01-01 00:00:15 ║   0 ║
║ 2000-01-01 00:00:45 ║   2 ║
║ 2000-01-01 00:01:15 ║   0 ║
║ 2000-01-01 00:01:45 ║   4 ║
║ 2000-01-01 00:02:15 ║   0 ║
║ 2000-01-01 00:02:45 ║   6 ║
║ 2000-01-01 00:03:15 ║   0 ║
║ 2000-01-01 00:03:45 ║   8 ║
╚═════════════════════╩═════╝The table shifted by 15 seconds.

6.轴','开'和'水平'

这些参数指定重采样所基于的列名或索引。

如果数据的日期是沿着列而不是沿着行,请指定axis = 1

如果日期列不是索引,请使用以下命令指定该列的名称:

on = 'date_column_name'

如果您有一个多级索引数据帧,使用level指定要重新采样的正确日期时间索引的级别。

7.未涉及的其他参数

由于使用其他方法捕获功能,其余的参数已被否决或多余。例如,howfill_method 在重采样调用后不再需要聚合函数,但是how用于下采样,fill_method用于上采样。如果你感兴趣,你可以在源文档中读到更多关于这些论点的内容。

谢谢大家!

今天就到这里吧!我希望我能阐明重采样是如何工作的,以及它的每个参数是做什么的。敬请关注更多教程和其他数据科学相关文章!

在 Android 应用程序中使用 Spotify API:要点

原文:https://towardsdatascience.com/using-the-spotify-api-with-your-android-application-the-essentials-1a3c1bc36b9e?source=collection_archive---------4-----------------------

概观

在本教程中,我将向您展示如何与 Spotify API 进行交互。如何认证、调用和解析结果。我们将发现 Spotify API 的能力,可以获得什么样的信息,以及我们可以对它进行什么样的操作。

虽然它是一个 REST API,因此对每个客户端都是一样的,但 iOS、Android 和 Web 的身份验证有很大不同。所以,在这篇文章中,我们将聚焦于 Android 认证。我们将要对 API 进行的调用也可以在 iOS 或 web 应用程序中以同样的方式使用。为了在 Android 上创建调用,我们将使用广为人知的凌空框架(【https://github.com/google/volley】)。

所以,我们走吧!

免责声明:Spotify API 可能会发生变化,因此在该功能中,这些调用可能不再有效,或者必须进行更改。如果出现问题,请查阅官方文档。

[## Web API |面向开发者的 Spotify

注意:使用 Spotify 开发者工具,即表示您接受 Spotify 开发者服务条款。基于简单的休息…

developer.spotify.com](https://developer.spotify.com/documentation/web-api/)

创建 Spotify API 项目

首先,我们需要创建一个 Spotify API 项目,以允许我们使用它进行认证。为此,我们前往https://developer.spotify.com/dashboard,用我们的 Spotify 账户登录。

现在我们必须执行以下步骤:

  1. 点击右上角的“创建客户 ID”
  2. 填写表单、名称、描述和我们正在构建的内容(手机应用程序)
  3. 回答我们是否正在开发商业集成。答案:否
  4. 接受服务条款。

现在,我们必须将重定向 URI 添加到我们的白名单中。为此,让我们进入“编辑设置”,在“重定向 URIs”下,我们添加要重定向的包名。例如,在我的例子中,这将是" com . spotifyapiexample://callback "。请注意,在 URI 中不允许有下划线。也可以在知道包名之后再做,但是必须在我们第一次运行应用程序之前完成。

很好,现在我们已经完成了,我们可以继续我们的 Android 项目了。

创建 Android 项目

让我们用一个空活动创建一个基本的 android 项目。我将调用我的 Spotify_api_example 。请随意选择你的名字。如果您还没有将您的应用程序列入白名单,现在是时候使用“😕/callback”来这样做了

首先,我们需要将 Spotify Android auth 库添加到我们的项目中。从 https://github.com/spotify/android-auth/releases.下载项目 解压文件夹,并将文件夹复制到项目根目录下的/app/libs 目录下。

然后打开你的 build.gradle (Module: app)文件,添加对库的依赖:

认证和获取用户信息

现在,让我们创建一个新的活动(空活动),我把它叫做 SplashActivity。在这个活动中,我们要做三件事:验证 Spotify API,获取当前用户的一些信息,并在获取令牌和信息后重定向到主活动。

首先,打开您的 AndroidManifest.xml 并将启动活动更改为我们新创建的 SplashActivity。此外,将互联网权限添加到清单中,这样我们就可以与外界通信了。

现在打开你的水花活动。让我们创建一个名为 authenticateSpotify() 的新方法。

  • 首先,我们打开一个 AuthenticationRequest,其中包含我们的 ClientID、我们想要的响应类型(在本例中是一个身份验证令牌)和 RedirectURI ( 这个 URI 必须被列入我们在 https://developer.spotify.com/dashboard 的项目中的白名单)
  • 然后,我们设置我们请求的范围(例如,用户最近阅读播放)。这些是我们需要向用户请求的不同权限,例如,读取他的个人信息的权限。请求的作用域将显示给用户,他必须将它们授予您的应用程序。
  • 最后,我们发送请求。这将打开 Spotify(如果安装了的话)或者返回到用户必须登录的 WebView。REQUEST_CODE 只是一个静态数字(例如 1337)来标识我们刚刚启动的应用程序。

现在,让我们定义一些我们需要的常量。用您的 ClientID 和 RedirectURI 替换它们。您可以在 Spotify 仪表盘中找到 ClientID。

当用户登录时。他将被重定向到您的应用程序。如果请求成功,我们将在那里接收令牌。将以下内容添加到 SplashActivity 类:

用户从 Spotify API 被重定向回来。然后你的应用识别 RequestCode,所以很明显它是从 Spotify 重定向过来的。然后,应用程序检查它是否收到了令牌,并相应地继续进行。我们使用 shared preferences(https://developer . Android . com/reference/Android/content/shared preferences)将令牌保存在我们的持久存储中。请务必查看评论,进一步了解正在发生的事情。

最后,我们必须初始化我们的共享首选项,并调用 authenticateSpotify()方法。将以下代码添加到您的 SplashActivity 中:

恭喜你。我们现在收到了有效的 API 令牌,可以开始使用 Spotify API 了。如果您想尝试一下,请取消对 waitForUserInfo()的注释;调用 onActivityResult。您应该可以使用您的 Spotify 帐户登录。但遗憾的是,其他事情都不会发生。

我们要打的第一个电话是获取一些关于我们用户的信息。例如,如果您想跟踪谁在使用您的应用程序。您可以通过用户唯一的 Spotify ID 来识别他们。

让我们首先用我们将从 Spotify API 收到的信息为我们的用户创建一个模型。创建一个名为“用户”的新类,并添加以下代码:

现在,为了保持结构化,让我们为将要使用的每个 API 端点创建一个服务类。创建一个名为“Connectors”的新包,创建一个名为“UserService”的新类,并添加以下代码:

如果我们查看 Spotify API 文档,我们会发现这个请求非常简单。这是一个对端点的标准 GET 请求,我们只需要我们的承载令牌(在上一步中收到的那个)作为报头。不需要其他参数。

https://developer.spotify.com/documentation/web-api/reference/users-profile/get-current-users-profile/

这里,我们用 JsonObjectRequest 生成一个基本的 GET 请求。我们简单地用 Gson 和我们创建的用户类解析结果。所以我们创建了一个新的用户对象,一旦我们从 API 得到响应,我们就用结果填充对象的值。VolleyCallBack 接口有助于我们知道何时收到了有效的响应,然后我们可以相应地继续进行。

为了让我们的回调工作,我们创建了一个名为“VolleyCallBack”的新接口

我们只需要一个方法,当请求成功并且我们收到响应时通知我们。

现在我们需要在 SplashActivity 类中实现 waitForUserInfo()方法。

现在,如果您启动您的应用程序,您应该获得您的令牌,获得用户信息,并应被重定向到 MainActivity,它将只显示“Hello World!”。在后台,您的应用程序获取了一个有效的认证令牌,并请求有关登录用户的附加信息。Spotify ID 保存在永久存储器中,因此我们可以在以后再次访问它。我们只需要显示信息。

我们不打算构建一个大的用户界面,本教程的主要目标是向您展示如何获取数据,如何使用数据由您决定。

获取最近播放的歌曲

现在我们已经收到了令牌和用户信息,是时候使用另一个 API 端点了。我们将获取用户最近播放的歌曲。为你的歌曲建立一个新的模型,类似于我们已经创建的用户模型。

接下来,让我们创建一个非常简单的 UI 来显示 Spotify ID、一首歌曲的标题和一个按钮。

现在让我们编写两个新方法并初始化我们的 UI 元素。

在我们的 getTracks()方法中,我们调用了 SongService 方法,该方法将从 API 中获取歌曲。收到数据后,我们将使用 updateSong()方法更新歌曲的名称。

我们需要一个名为 SongService 的新类,我们将从 Spotify API 中获取歌曲。这个类类似于我们实现的 UserService,处理我们发送给 API 的请求。

同样,如果我们查看 Spotify API 文档,我们会看到这是一个简单的 GET 请求,除了头中的 Bearer token 之外,没有任何必需的参数。

https://developer.spotify.com/console/get-recently-played/

典型的响应如下所示:

让我们在 SongService 中实现它

The UI should look like this, but feel free to change things around

这一次,解析结果比上一次稍微困难一些。因为我们收到了一个 JSON 数组,所以我们必须遍历那个数组中的每一项,并将该项分配给我们的 song 对象。我们像上次对 Gson 那样做。最后,我们返回一个类型为 < Song >数组列表,其中包含了我们从 API 中获取的歌曲。

现在,如果你启动这个应用程序,你应该会看到你最近听过的一首歌的名字。我们只展示一个。这个按钮还不能做任何事情,所以我们来改变它。

将歌曲添加到您喜欢的歌曲

为我们的按钮创建一个 OnClicklistener,并将其分配给我们的按钮。

我们需要生成一个 PUT 请求。这一次我们必须提供一个主体,它必须包含一组 Spotify ID 字符串。我们将在这个数组中只包含一个 ID,因为我们将为每首歌曲生成一个请求。

https://developer.spotify.com/console/put-current-user-saved-tracks/

编辑 SongService 类并添加以下行:

首先,我们准备主体,这里称为有效载荷。我们生成一个新的 JSONArray,并添加一个带有歌曲 ID 的条目。我们将整个东西包装在一个 JSONObject 中,有效载荷就准备好了。

现在我们准备将要发送的请求。这次是一个 PUT 请求,所以方法发生了变化。另外,它类似于我们已经发送的其他请求。最后,我们将请求添加到我们的队列中,因此它将被异步执行。

如果您启动该应用程序,您应该能够看到这首歌,如果您按下添加按钮,它会将这首歌添加到 Spotify 帐户中您喜欢的歌曲中,并且会列出一首新歌,您可以再次将其添加到您的资料库中。继续检查它是否工作。

结论

关于 Spotify API 的教程到此结束。这是 Spotify API 可以实现的一个小例子。可能性几乎是无穷无尽的,也许你知道你想用它做什么。不管怎样,祝你编码愉快!

看看我的另一个 Android 项目,我用 Spotify API 提供了更多的功能和调用,比如添加和删除播放列表、播放歌曲等等。

[## hyferion/SpotifyRecLabelingAndroid

这个应用程序是基于机器学习的应用程序的一部分,用于歌曲的分类和制作…

github.com](https://github.com/Hyferion/SpotifyRecLabelingAndroid)

另外,你可以在 Github 上找到本教程的代码:

[## Hyferion/spotify_api_example

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/Hyferion/spotify_api_example)

在我的下一篇文章中,我将谈论我在 Spotify API 上开发的另一个应用程序。

使用无监督的机器学习来发现隐藏的科学知识

原文:https://towardsdatascience.com/using-unsupervised-machine-learning-to-uncover-hidden-scientific-knowledge-6a3689e1c78d?source=collection_archive---------14-----------------------

Word2vec 从数百万份摘要中学习材料科学

Credit: Olga Kononova

跟上新科学文献出版的步伐变得越来越困难。一个研究人员可能要花几个月的时间来做一个广泛的文献综述,即使是一个单一的主题。如果一台机器可以在几分钟内阅读所有发表在特定主题上的论文,并告诉科学家最佳的前进方向,会怎么样?嗯,我们离那还很远,但是我们下面描述的研究提出了一种新的方法,在最少的人类监督下,利用科学文献发现材料。

为了让计算机算法利用自然语言,单词需要以某种数学形式来表示。2013 年,名为 Word2vec [ 12 的算法的作者发现了一种有趣的方法,可以从大量文本中自动学习这种表示。出现在文本中相似上下文中的单词通常具有相似的含义。因此,如果训练神经网络来预测目标单词的相邻单词,它将学习相似目标单词的相似表示。他们表明,单个单词可以有效地表示为高维向量(嵌入),单词之间的语义关系可以表示为线性向量运算(参见此处获取更详细解释 Word2vec 的教程)。这种语义关系的一个著名例子是表达式

“国王”——“王后”≘“男人”——“女人”(1),

其中在相应单词的向量之间执行减法。(1)两边的成对词之间的这种语义关系代表了性别的概念。

Figure 1: Analogies between pairs of words are captured by linear operations between the corresponding embeddings. Figure on the right borrowed from 3.

自然地,如果我们使用纯粹的科学文本,而不是普通的文本源,如普通爬虫维基百科,在我们的例子中[ 3 是几百万份材料科学摘要,这些向量运算嵌入了更专业的知识。举个例子,

“z ro2”-“Zr”≘“NiO”-“Ni”,

其中上述表达式代表氧化物的概念。

语义关系的另一个例子是单词相似度,由嵌入的点积(投影)决定。在最初的 Word2vec 模型中,单词“large”和“big”具有彼此接近的向量(具有大的点积),但是远离“亚美尼亚”的向量。在我们的专业模型中,与“LiCoO2”最相似的词是“LiMn2O4”,这两种都是锂离子电池的阴极材料。事实上,如果我们使用 t-SNE [ 4 ]将大约 12,000 种最受欢迎的材料(文中提到了 10 种以上)投影到 2D 平面上,我们会发现这些材料主要根据它们的应用和成分相似性进行聚类。

Figure 2: Materials used for similar applications as well as with similar chemical compositions cluster together. The most common elements in each “application cluster” match our materials science knowledge. Each chart on the bottom is obtained by counting chemical elements in the compositions of the materials from the corresponding application clusters. Figure borrowed from 3.

现在,我们可以做一些更有趣的事情,根据特定的应用给图 2 左上角的“材质贴图”上色。对应于单一材料的每个点可以根据其嵌入与应用词嵌入的相似性来着色,例如“热电”(用于描述热到电的转换的词,反之亦然)。

Figure 3: Materials “light up” according to their similarity to the application keyword. Figure borrowed from 3.

正如你们中的许多人可能已经猜到的,上图中最亮的地方是众所周知的热电材料,在科学摘要中与“热电”一词一起被明确提到。然而,其他一些亮点从未作为热电学进行过研究,因此该算法正在指示一种没有在文本中明确写入的关系。问题是,这些材料能成为尚待发现的良好热电材料吗?令人惊讶的是,答案是是的!

我们测试这个假设的几种方法之一是通过训练单词嵌入,就好像我们还在过去一样。我们将 2000 年至 2018 年之间发表的科学摘要一年一年地删除,并训练了 18 个不同的模型。我们使用这些模型根据材料与“热电”一词的相似性(图 3 中颜色的强度)对材料进行了排序,并选取了当年未被研究为热电材料的前 50 种材料。事实证明,这些材料中的许多后来被报道为热电材料,如下图所示。

Figure 4: If we went to the past one year at a time and made prediction using only the data available at that time, many of them would have come true by now. Each grey line corresponds to the predictions for a given year, and the solid red and blue lines are averaged across all prediction years. Figure borrowed from 3.

事实上,2009 年的五大预测之一应该是 CuGaTe2,它被认为是 2012 年才发现的当今最好的热电学之一。有趣的是,当我们的手稿[ 3 ]在准备和审查中时,我们用所有可用的摘要做出的 50 个预测中有 3 个也被报道为良好的热电学。

那么,这一切是如何运作的呢?我们可以通过查看预测材料的上下文词得到一些线索,看看这些上下文词中,哪些与材料和应用关键词“热电”都有很高的相似度。下面列出了前 5 个预测中的 3 个预测的一些主要上下文单词。

Figure 5: Context words for 3 of our top 5 predictions that contribute the most to the predictions. The width of the connect lines is proportional to cosine similarities between the words. Figure borrowed from 3.

实际上,该算法捕获对热电材料很重要的上下文单词(或者更准确地说,上下文单词的组合)。作为材料科学家,我们知道硫族化物(一类材料)通常是良好的热电材料,带隙的存在在大多数时候是至关重要的。我们看到算法是如何利用单词的共现来学习的。上图仅捕捉了一阶连接,但高阶连接也可能有助于预测。

对于科学应用,自然语言处理(NLP)几乎总是被用作从文献中提取已知事实的工具,而不是进行预测。这不同于股票价值预测等其他领域,例如,在股票价值预测中,对有关公司的新闻文章进行分析,以预测其股票价值在未来将如何变化。但即便如此,大多数方法还是将从文本中提取的特征输入到其他更大的模型中,这些模型使用结构化数据库中的附加特征。我们希望这里描述的想法将鼓励科学发现的直接、无监督的 NLP 驱动的推理方法。Word2vec 并不是最先进的 NLP 算法,因此下一步自然是用更新颖的、上下文感知的嵌入来替代它,比如 BERT [ 5 和 ELMo [ 6 ]。我们还希望,由于这里描述的方法需要最少的人工监督,其他科学学科的研究人员将能够使用它们来加速机器辅助的科学发现。

笔记

获得良好预测的关键步骤是对材料使用输出嵌入(Word2vec 神经网络的输出层),对应用关键字使用单词嵌入(Word2vec 神经网络的隐藏层)。这有效地转化为预测摘要中单词的共现。因此,该算法正在识别研究文献中的潜在“差距”,例如研究人员未来应该研究的功能应用的化学成分。详见原版的补充资料。

我们用于 Word2vec 训练和预训练嵌入的代码可在https://github.com/materialsintelligence/mat2vec获得。代码中的默认超参数是本研究中使用的参数。

放弃

这里讨论的工作是我在劳伦斯伯克利国家实验室担任博士后时进行的,与一个了不起的研究团队一起工作——约翰·达吉伦、利·韦斯顿、亚历克斯·邓恩、秦子·荣、奥尔加·科诺诺娃、克里斯汀·a·佩尔松、格布兰德·塞德尔和阿努巴夫·贾恩。

也非常感谢 Ani Nersisyan 对这个故事提出的改进建议。

参考

[1] T. Mikolov,K. Chen,G. Corrado & J. Dean,向量空间中词表征的有效估计(2013),【https://arxiv.org/abs/1301.3781】

2 T. Mikolov,I. Sutskever,K. Chen,G. Corrado & J. Dean,单词和短语的分布式表征及其组合性(2013),【https://arxiv.org/abs/1310.4546】

3 V. Tshitoyan,J. Dagdelen,L. Weston,A. Dunn,Z. Rong,O. Kononova,K. A. Persson,G. Ceder & A. Jain,无监督单词嵌入从材料科学文献中捕获潜在知识(2019), Nature 571,95–98

[4] L. Maaten & G. Hinton,使用 t-SNE 可视化数据(2008 年),机器学习研究杂志

[5] J. Devlin,M.-W. Chang,K. Lee & K. Toutanova,Bert:用于语言理解的深度
双向转换器的预训练(2018),https://arxiv.org/abs/1810.04805

[6] M. E. Peters,M. Neumann,M. Iyyer,M. Gardner,C. Clark,K. Lee,L. Zettlemoyer,深度语境化的词表征(2018),https://arxiv.org/abs/1802.05365

使用 USE(通用语句编码器)检测假新闻

原文:https://towardsdatascience.com/using-use-universal-sentence-encoder-to-detect-fake-news-dfc02dc32ae9?source=collection_archive---------26-----------------------

自从引进通用语句编码器(使用)以来,它已经成为 Tensorflow Hub 中下载量最多的预训练文本模块。通用句子编码器系列包括:

通用句子编码器具有用于语义相似性和问答检索的不同模块。

我们将使用通用句子编码器 large 进行假新闻检测,这是一个文本分类问题。假新闻(也称为垃圾新闻、伪新闻或恶作剧新闻)是一种黄色新闻或宣传,由通过传统新闻媒体(印刷和广播)或在线社交媒体传播的故意虚假信息或骗局组成

我们使用 PythonJupyter Notebook 来开发我们的系统,我们将使用的库包括KerasT6、Numpy、Pandas、 SklearnMatplotlibTensorflowTensorflow Hub 。完整的代码和数据可以从这里下载。

数据探索

首先,我们将看看我们的数据。我们的数据有三列,即标题、文本和标签。

data = pd.read_csv('fake_or_real_news.csv')
data = data[['title', 'text', 'label']]
data.columns =  ['Title', 'Text', 'Label']
data.head()

现在我们检查标题和文本的最大字数。

最大标题长度:289
最大文本长度:115372

由于新闻文章的文本更重要,而且我们也有内存限制,所以我们将只使用文本进行分类。

print("Max title length:", data.Title.str.len().max())
print("Max text length:", data.Text.str.len().max())

现在我们看到了阶级分布。我们有 3171 个真的和 3164 个假的例子。

data.Label.value_counts()

为了得到数据集的形状,我们使用熊猫数据框的形状属性。我们总共有 6335 个例子。

data.shape

因为我们的问题是二元分类。我们需要给我们的模型传递一个二维输出向量。为此,我们在数据框中添加了两个 one hot 编码列。

pos = []
neg = []
for l in data.Label:
    if l == 'FAKE':
        pos.append(0)
        neg.append(1)
    elif l == 'REAL':
        pos.append(1)
        neg.append(0)data['Pos']= pos
data['Neg']= neg

现在让我们看看我们的数据框架。

data.head()

将数据分为测试和训练

现在,我们将数据集分为训练集和测试集。我们将使用 90 %的数据进行训练,10 %的数据进行测试。我们使用随机状态,所以每次我们都得到相同的训练和测试数据。

data_train, data_test = train_test_split(data, 
                                         test_size=0.10, 
                                         random_state=42)

加载通用语句编码器

下一步是加载通用句子编码器。使用 tensorflow_hub 很容易做到。这一步可能需要一些时间。

module_url = "[https://tfhub.dev/google/universal-sentence-encoder-large/2](https://tfhub.dev/google/universal-sentence-encoder-large/2)" 
embed = hub.Module(module_url)

获取嵌入

现在我们将把训练句子转换成嵌入。这是通过简单地将整个句子传递给 embed object 来实现的。我们为每个句子得到一个 512 维的向量。

with tf.Session() as session:
    session.run([tf.global_variables_initializer(), 
                 tf.tables_initializer()])
    training_embeddings = session.run(embed(data_train.Text.to_list()))

定义神经网络

我们现在将设计一个总共有两层的浅层神经网络。嵌入被传递到具有“Relu”激活和 128 个单元的密集层。接下来是我们的输出层。这一层有两个单元,因为我们的模型是一个二元分类器。Softmax 用作输出层的激活函数。

model = Sequential()
model.add(Dense(128, activation = 'relu'))
model.add(Dense(2, activation = 'softmax'))model.compile(loss='binary_crossentropy', 
              optimizer='adam',
              metrics=['acc'])

model.summary()将打印所有图层的摘要以及输出的形状。

model.summary()

培养

历元数是您的模型将循环和学习的数量,批量大小是您的模型在单个时间看到的数据量。

num_epochs = 30
batch_size = 32history = model.fit(training_embeddings, 
                    data_train[label_names].values, 
                    epochs=num_epochs, 
                    validation_split=0.1, 
                    shuffle=True, 
                    batch_size=batch_size)

绘制准确度和损失图

首先,我们将绘制测试和训练精度相对于历元数的曲线。

plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

现在,我们将绘制测试和训练损失与历元数的关系图。

plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

测试

现在我们将把测试例子转换成嵌入。

with tf.Session() as session:
    session.run([tf.global_variables_initializer(), 
                 tf.tables_initializer()])
    test_embeddings = session.run(embed(data_test.Text.to_list()))

哇!只需三十次迭代和一个小数据集,我们就能获得 90 %的准确率。请记住,我们没有对数据进行预处理,因此这种准确性可以得到认可。

predictions = model.predict(test_embeddings, 
                            batch_size=1024, 
                            verbose=1)
labels = ['REAL', 'FAKE']prediction_labels=[]
for p in predictions:
    prediction_labels.append(labels[np.argmax(p)])print("Accuracy:", sum(data_test.Label==prediction_labels)/len(prediction_labels))

如果你有任何问题或建议,欢迎在下面留言。你也可以在Linkedin上和我联系。

使用“假设工具”研究机器学习模型。

原文:https://towardsdatascience.com/using-what-if-tool-to-investigate-machine-learning-models-913c7d4118f?source=collection_archive---------7-----------------------

Google 的一个开源工具,无需编码就能轻松分析 ML 模型。

Photo by Pixabay from Pexels

好的从业者扮演侦探的角色,探索以更好地理解他们的模型

在这个可解释和可解释的机器学习时代,人们不能仅仅满足于简单地训练模型并从中获得预测。为了能够真正产生影响并获得好的结果,我们还应该能够探索和研究我们的模型。除此之外,在继续使用模型之前,算法的公平性约束和偏见也应该清楚地记住。

调查一个模型需要问很多问题,并且需要有侦探的敏锐度来探查和寻找模型中的问题和不一致之处。此外,这样的任务通常很复杂,需要编写大量的自定义代码。幸运的是, What-If 工具已经被创建来解决这个问题,使得更多的人能够更容易、更容易、更准确地检查、评估和调试 ML 系统。

假设工具(WIT)

Source

假设工具 是一个交互式可视化工具,旨在研究机器学习模型。缩写为 WIT,它使人们能够检查、评估和比较机器学习模型,从而能够理解分类或回归模型。由于其用户友好的界面和对复杂编码的较少依赖,每个人,无论是开发人员、产品经理、研究人员还是学生,都可以出于自己的目的使用它。

WIT 是 Google 在PAIR(People+AI Research)倡议下发布的开源可视化工具。PAIR 将谷歌的研究人员聚集在一起,研究并重新设计人们与人工智能系统的交互方式。

该工具可以通过 TensorBoard 访问,或者作为 Jupyter 或 Colab 笔记本的扩展。

优势

该工具的目的是为人们提供一种简单、直观和强大的方法,仅通过可视化界面在一组数据上使用经过训练的 ML 模型。以下是机智的主要优势。

What can you do with the What-If Tool?

我们将在使用该工具的示例演练中涵盖上述所有要点。

民众

为了说明假设工具的功能,PAIR 团队发布了一组使用预训练模型的演示。您可以在笔记本上运行演示,也可以直接通过网络运行。

Take the What-If Tool for a spin!

使用

WIT 可以在 JupyterColab 笔记本内部使用,或者在 TensorBoard 网络应用内部使用。这已经在文档中很好很清楚地解释了,我强烈建议你去读一遍,因为通过这篇短文解释整个过程是不可能的。

整个想法是首先训练一个模型,然后使用假设工具可视化训练好的分类器对测试数据的结果。

使用 WIT 与 Tensorboard

要在 TensorBoard 中使用 WIT,您的模型需要通过 TensorFlow 模型服务器提供服务,并且要分析的数据必须作为 TFRecords 文件存在于磁盘上。有关在 TensorBoard 中使用 WIT 的更多详细信息,请参考文档

在笔记本上使用 WIT

为了能够在笔记本中访问 WIT,您需要一个 WitConfigBuilder 对象来指定要分析的数据和模型。这篇文档提供了在笔记本上使用 WIT 的一步一步的概要。

您也可以使用演示笔记本并编辑代码以包含您的数据集来开始工作。

游戏攻略

现在让我们通过一个例子来探索 WIT 工具的功能。这个例子取自网站上提供的演示,叫做收入分类,其中我们需要根据一个人的人口普查信息来预测他的年收入是否超过 5 万美元。该数据集属于 UCI 人口普查数据集 ,由年龄、婚姻状况、受教育程度等多个属性组成。

概观

让我们从探索数据集开始。这里有一个链接到网络演示,以便跟进。

假设分析工具包含两个主要面板。右侧面板包含您已加载的数据集中各个数据点的可视化。

在这种情况下,蓝点是模型推断收入低于 50k 的人,而红点是模型推断收入高于 50k 的人。默认情况下,WIT 使用 0.5 的肯定分类阈值。这意味着,如果推断得分为 0.5 或更高,则该数据点被认为处于积极的类别,即高收入。

这里值得注意的是数据集是在 Facets Dive 中可视化的。Facets Dive 是 PAIR 团队再次开发的 FACETS 工具的一部分,帮助我们理解数据的各种特性并探索它们。如果您不熟悉这个工具,您可以参考我不久前写的这篇关于 FACETS 功能的文章。

[## 用 Google FACETS 可视化机器学习数据集。

Google 的开源工具,可以轻松地从大量数据中学习模式

towardsdatascience.com](/visualising-machine-learning-datasets-with-googles-facets-462d923251b3)

您也可以通过简单地从下拉菜单中选择字段,以大量不同的方式组织数据点,包括混淆矩阵、散点图、直方图和小倍数图。下面列举了几个例子。

左侧面板包含三个标签Datapoint Editor,``Performance & Fairness;还有Features.

1.数据点编辑器选项卡

数据点编辑器有助于通过以下方式进行数据分析:

  • 查看和编辑数据点的详细信息

它允许深入到一个选定的数据点,该数据点在右侧面板上以黄色突出显示。让我们尝试将年龄从 53 更改为 58,并单击“运行推理”按钮,看看它对模型的性能有什么影响。

通过简单地改变此人的年龄,模型现在预测此人属于高收入类别。对于这个数据点,早些时候正面(高收入)阶层的推断得分是 0.473,负面(低收入)阶层的得分是 0.529。但是,通过改变年龄,正的班级分数变成了 0.503。

  • 寻找最近的反事实

了解模型行为的另一种方式是查看哪些小的变化会导致模型改变其决策,这被称为反事实 s。只需点击一下,我们就可以看到与我们选择的数据点最相似的反事实,以绿色突出显示。在数据点编辑器选项卡中,我们现在还可以在原始数据点的特征值旁边看到反事实的特征值。绿色文本表示两个数据点不同的特征。WIT 使用 L1 和L2 距离来计算数据点之间的相似性。

在这种情况下,最接近的反事实稍老,有不同的职业和资本收益,但在其他方面是相同的。

我们还可以使用“显示与所选数据点的相似性”按钮查看所选点和其他点之间的相似性。WIT 测量从选定点到每隔一个数据点的距离。让我们更改 X 轴散点图,以显示到所选数据点的 L1 距离。

  • 分析部分相关图

部分相关性图(短 PDP 或 PD 图)显示了一个或两个特征对机器学习模型的预测结果的边际效应( J. H. Friedman 2001 )。

数据点的年龄和教育的 PDP 如下:

上图显示:

  • 该模型已经了解到年龄和收入之间的正相关关系
  • 更高的学位使模型对更高的收入更有信心。
  • 高资本收益是高收入的一个非常强有力的指标,远远超过任何其他单一特征。

2.绩效与公平选项卡

该选项卡允许我们使用混淆矩阵和 ROC 曲线来查看整体模型性能。

  • 车型性能分析

为了测量模型的性能,我们需要告诉工具什么是基本事实特征,即模型试图预测的特征,在这种情况下是“超过 50K ”。

我们可以看到,在默认阈值水平为 0.5 时,我们的模型大约有 15%的时间是不正确的,其中大约 5%的时间是假阳性,10%的时间是假阴性。更改阈值以查看其对模型准确性的影响。

还有一个“成本比率设置和一个“优化阈值按钮,也可以调整。

  • ML 公平性

机器学习中的公平性与建模和预测结果一样重要。训练数据中的任何偏差将反映在训练的模型中,并且如果部署这样的模型,则结果输出也将有偏差。WIT 可以以几种不同的方式帮助调查公平问题。我们可以设置一个输入要素(或一组要素)来分割数据。例如,让我们看看性别对模型性能的影响。

Effect of gender on Model’s performance

我们可以看到这个模型对女性比对男性更准确。此外,该模型对女性高收入的预测比男性低得多(女性为 9.3%,男性为 28.6%)。一个可能的原因可能是由于女性在数据集中的代表性不足,我们将在下一节探讨这个问题。

此外,该工具可以最优地设置两个子集的决策阈值,同时考虑与算法公平性相关的多个约束中的任何一个,例如人口统计均等或机会均等。

3.功能选项卡

要素选项卡提供数据集中每个要素的汇总统计数据,包括直方图、分位数图、条形图等。该选项卡还允许查看数据集中每个要素的值的分布。例如,让我们探讨性别、资本收益和种族特征。

我们推断 capital gain非常不均匀,大多数数据点被设置为 0。

Native Country DIstribution || Sex distribution

类似地,大多数数据点属于美国,而女性在数据集中没有得到很好的代表。由于数据是有偏差的,它的预测只针对一个群体是很自然的。毕竟,一个模型从提供给它的数据中学习,如果数据来源有偏差,结果也会有偏差。机器学习已经在许多应用和领域证明了它的实力。然而,机器学习模型的工业应用的关键障碍之一是确定用于训练模型的原始输入数据是否包含歧视性偏见。

结论

这只是一些假设工具特性的快速浏览。WIT 是一个非常方便的工具,它提供了探究模型的能力,并将其传递到最重要的人手中。简单地创建和训练模型不是机器学习的目的,但理解为什么以及如何创建模型才是真正意义上的机器学习。

参考资料:

  1. 假设工具:机器学习模型的无代码探测
  2. https://pair-code.github.io/what-if-tool/walkthrough.html
  3. https://github . com/tensor flow/tensor board/tree/master/tensor board/plugins/interactive _ inference

使用 word2vec 分析新闻标题并预测文章成功

原文:https://towardsdatascience.com/using-word2vec-to-analyze-news-headlines-and-predict-article-success-cdeda5f14751?source=collection_archive---------2-----------------------

深入分析

文章标题的单词嵌入能预测受欢迎程度吗?关于情绪和股票的关系,我们能了解到什么?word2vec 可以帮助我们回答这些问题,还有更多。

Sentiment distributions for popular news websites

单词嵌入是表示单词以及文档(单词集合)中包含的潜在信息的一种强大方式。使用新闻文章标题的数据集,其中包括来源、情感、主题和受欢迎程度(份额数)的特征,我开始查看我们可以通过文章各自的嵌入来了解它们之间的关系。

该项目的目标是:

  • 使用 NLTK 预处理/清理文本数据
  • 使用 word2vec 创建单词和标题嵌入,然后使用 t-SNE 将它们可视化为集群
  • 形象化标题情绪和文章流行度的关系
  • 尝试从嵌入和其他可用特征预测文章流行度
  • 使用模型堆叠来提高流行度模型的性能(这一步并不成功,但仍然是一个有价值的实验!)

整个笔记本托管在这里,使用 nbviewer

导入和预处理

我们将从进口开始:

**import** **pandas** **as** **pd**
**import** **gensim**
**import** **seaborn** **as** **sns**
**import** **matplotlib.pyplot** **as** **plt**
**import** **numpy** **as** **np**
**import** **xgboost** **as** **xgb**

然后读入数据:

main_data = pd.read_csv('News_Final.csv')
main_data.head()

# Grab all the titles 
article_titles = main_data['Title']*# Create a list of strings, one for each title*
titles_list = [title **for** title **in** article_titles]

*# Collapse the list of strings into a single long string for processing*
big_title_string = ' '.join(titles_list)

**from** **nltk.tokenize** **import** word_tokenize

*# Tokenize the string into words*
tokens = word_tokenize(big_title_string)

*# Remove non-alphabetic tokens, such as punctuation*
words = [word.lower() **for** word **in** tokens **if** word.isalpha()]

*# Filter out stopwords*
**from** **nltk.corpus** **import** stopwords
stop_words = set(stopwords.words('english'))

words = [word **for** word **in** words **if** **not** word **in** stop_words]

*# Print first 10 words*
words[:10]

接下来,我们需要加载预先训练好的 word2vec 模型。你可以在这里找到几款这样的。由于这是一个新闻数据集,所以我使用了谷歌新闻模型,该模型被训练了大约 1000 亿个单词(哇)。

*# Load word2vec model (trained on an enormous Google corpus)*
model = gensim.models.KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary = **True**) 

*# Check dimension of word vectors*
model.vector_size

所以模型会生成 300 维的词向量,我们要做的就是创建一个向量,让它通过模型。每个向量看起来像这样:

economy_vec = model['economy']
economy_vec[:20] *# First 20 components*

word2vec(可以理解)不能从一个不在其词汇表中的单词创建向量。正因为如此,我们需要在创建单词向量的完整列表时指定“if word in model.vocab”。

*# Filter the list of vectors to include only those that Word2Vec has a vector for*
vector_list = [model[word] **for** word **in** words **if** word **in** model.vocab]

*# Create a list of the words corresponding to these vectors*
words_filtered = [word **for** word **in** words **if** word **in** model.vocab]

*# Zip the words together with their vector representations*
word_vec_zip = zip(words_filtered, vector_list)

*# Cast to a dict so we can turn it into a DataFrame*
word_vec_dict = dict(word_vec_zip)
df = pd.DataFrame.from_dict(word_vec_dict, orient='index')df.head(3)

基于 t-SNE 的维数约简

接下来,我们将使用 t-SNE 挤压(阅读:对这些单词向量进行降维),看看是否有任何模式出现。如果你不熟悉 t-SNE 和它的解释,看看这篇关于 t-SNE 的优秀的、互动的 distill.pub 文章

摆弄 SNE 霸王龙的参数很重要,因为不同的值会产生非常不同的结果。我测试了 0 到 100 之间的几个困惑值,发现每次都产生大致相同的形状。我还测试了几个介于 20 和 400 之间的学习率,并决定保持默认的学习率(200)。

出于可见性(和处理时间)的考虑,我使用了 400 个单词向量,而不是大约 20,000 个单词向量。

**from** **sklearn.manifold** **import** TSNE

*# Initialize t-SNE*
tsne = TSNE(n_components = 2, init = 'random', random_state = 10, perplexity = 100)

*# Use only 400 rows to shorten processing time*
tsne_df = tsne.fit_transform(df[:400])

现在,我们准备绘制缩减的单词向量数组。我使用adjust_text智能地将单词分开,以提高可读性:

sns.set()# Initialize figure
fig, ax = plt.subplots(figsize = (11.7, 8.27))
sns.scatterplot(tsne_df[:, 0], tsne_df[:, 1], alpha = 0.5)

*# Import adjustText, initialize list of texts*
**from** **adjustText** **import** adjust_text
texts = []
words_to_plot = list(np.arange(0, 400, 10))

*# Append words to list*
**for** word **in** words_to_plot:
    texts.append(plt.text(tsne_df[word, 0], tsne_df[word, 1], df.index[word], fontsize = 14))

*# Plot text using adjust_text (because overlapping text is hard to read)*
adjust_text(texts, force_points = 0.4, force_text = 0.4, 
            expand_points = (2,1), expand_text = (1,2),
            arrowprops = dict(arrowstyle = "-", color = 'black', lw = 0.5))

plt.show()

如果你有兴趣尝试一下adjust_text来满足自己的绘图需求,你可以在这里找到它。一定要用 came caseadjustText导入,请注意adjustText目前不兼容matplotlib 3.0 以上版本。

令人鼓舞的是,即使向量嵌入已经减少到二维,我们也看到某些项目聚集在一起。例如,我们在左/左上角有个月,我们在底部有个公司财务术语,我们在中间有更多的个通用的、非主题性的词(比如‘full’,‘really’,‘slew’)。

请注意,如果我们用不同的参数再次运行 t-SNE,我们可能会观察到一些类似的结果,但我们不能保证看到完全相同的模式。t-SNE 不是决定性的。相关地,聚类的紧密度和聚类之间的距离并不总是有意义的。它主要是作为一种探索工具,而不是相似性的决定性指标。

平均单词嵌入

我们已经了解了单词嵌入如何应用于这个数据集。现在我们可以转移到一些更有趣的 ML 应用程序上:找到聚集在一起的标题,看看会出现什么样的模式。

我们可以使用一个更简单的(有时甚至更有效)技巧:对每个文档中单词向量的嵌入进行平均,而不是使用 Doc2Vec,doc 2 vec 没有可用的预训练模型,因此需要漫长的训练过程。在我们的例子中,文档指的是标题。

我们需要重做预处理步骤来保持标题完整——正如我们将看到的,这比拆分单词要复杂一些。谢天谢地,Dimitris Spathis 已经创建了一系列函数,我发现它们非常适合这个用例。谢谢你,迪米特里斯!

**def** document_vector(word2vec_model, doc):
    *# remove out-of-vocabulary words*
    doc = [word **for** word **in** doc **if** word **in** model.vocab]
    **return** np.mean(model[doc], axis=0)

*# Our earlier preprocessing was done when we were dealing only with word vectors*
*# Here, we need each document to remain a document* 
**def** preprocess(text):
    text = text.lower()
    doc = word_tokenize(text)
    doc = [word **for** word **in** doc **if** word **not** **in** stop_words]
    doc = [word **for** word **in** doc **if** word.isalpha()] 
    **return** doc

*# Function that will help us drop documents that have no word vectors in word2vec*
**def** has_vector_representation(word2vec_model, doc):
    *"""check if at least one word of the document is in the*
 *word2vec dictionary"""*
    **return** **not** all(word **not** **in** word2vec_model.vocab **for** word **in** doc)

*# Filter out documents*
**def** filter_docs(corpus, texts, condition_on_doc):
    *"""*
 *Filter corpus and texts given the function condition_on_doc which takes a doc. The document doc is kept if condition_on_doc(doc) is true.*
 *"""*
    number_of_docs = len(corpus)

    **if** texts **is** **not** **None**:
        texts = [text **for** (text, doc) **in** zip(texts, corpus)
                 **if** condition_on_doc(doc)]

    corpus = [doc **for** doc **in** corpus **if** condition_on_doc(doc)]

    print("**{}** docs removed".format(number_of_docs - len(corpus)))

    **return** (corpus, texts)

现在我们将使用这些来进行处理:

*# Preprocess the corpus*
corpus = [preprocess(title) **for** title **in** titles_list]

*# Remove docs that don't include any words in W2V's vocab*
corpus, titles_list = filter_docs(corpus, titles_list, **lambda** doc: has_vector_representation(model, doc))

*# Filter out any empty docs*
corpus, titles_list = filter_docs(corpus, titles_list, **lambda** doc: (len(doc) != 0))x = []
**for** doc **in** corpus: *# append the vector for each document*
    x.append(document_vector(model, doc))

X = np.array(x) *# list to array*

t-SNE,第二轮:文档向量

现在我们已经成功地创建了文档向量数组,让我们看看用 t-SNE 绘制它们时是否能得到类似的有趣结果。

*# Initialize t-SNE*
tsne = TSNE(n_components = 2, init = 'random', random_state = 10, perplexity = 100)

*# Again use only 400 rows to shorten processing time*
tsne_df = tsne.fit_transform(X[:400])fig, ax = plt.subplots(figsize = (14, 10))
sns.scatterplot(tsne_df[:, 0], tsne_df[:, 1], alpha = 0.5)

**from** **adjustText** **import** adjust_text
texts = []
titles_to_plot = list(np.arange(0, 400, 40)) *# plots every 40th title in first 400 titles*

*# Append words to list*
**for** title **in** titles_to_plot:
    texts.append(plt.text(tsne_df[title, 0], tsne_df[title, 1], titles_list[title], fontsize = 14))

*# Plot text using adjust_text*
adjust_text(texts, force_points = 0.4, force_text = 0.4, 
            expand_points = (2,1), expand_text = (1,2),
            arrowprops = dict(arrowstyle = "-", color = 'black', lw = 0.5))

plt.show()

挺有意思的!我们可以看到,t-SNE 将文档向量折叠到一个维度空间中,在这个空间中,文档根据其内容是与国家、世界领导人和外交事务有关,还是与技术公司有关而展开。

现在让我们来探讨一下文章流行度。人们普遍认为,一篇文章的标题越煽情或越吸引人,它就越有可能被分享,对吗?接下来,我们将看看在这个特定的数据集中是否有这方面的证据。

流行度和情感分析

首先,我们需要删除所有没有流行度测量或来源的文章。流行度的零测量在该数据中表示为-1。

*# Drop all the rows where the article popularities are unknown (this is only about 11% of the data)*
main_data = main_data.drop(main_data[(main_data.Facebook == -1) | 
                                     (main_data.GooglePlus == -1) | 
                                     (main_data.LinkedIn == -1)].index)

*# Also drop all rows where we don't know the source*
main_data = main_data.drop(main_data[main_data['Source'].isna()].index)

main_data.shape

我们仍然有 81,000 篇文章要处理,所以让我们看看是否可以找到情绪和股票数量之间的关联。

fig, ax = plt.subplots(1, 3, figsize=(15, 10))

subplots = [a **for** a **in** ax]
platforms = ['Facebook', 'GooglePlus', 'LinkedIn']
colors = list(sns.husl_palette(10, h=.5)[1:4]) 

**for** platform, subplot, color **in** zip(platforms, subplots, colors):
    sns.scatterplot(x = main_data[platform], y = main_data['SentimentTitle'], ax=subplot, color=color)
    subplot.set_title(platform, fontsize=18)
    subplot.set_xlabel('') 

fig.suptitle('Plot of Popularity (Shares) by Title Sentiment', fontsize=24)

plt.show()

很难确定这里是否有任何关系,因为一些文章在它们的份额计数方面是显著的异常值。让我们试着对 x 轴进行对数变换,看看我们是否能揭示任何模式。我们还将使用一个 regplot,因此seaborn将为每个图覆盖一个线性回归。

*# Our data has over 80,000 rows, so let's also subsample it to make the log-transformed scatterplot easier to read*

subsample = main_data.sample(5000)

fig, ax = plt.subplots(1, 3, figsize=(15, 10))

subplots = [a **for** a **in** ax]

**for** platform, subplot, color **in** zip(platforms, subplots, colors):
    *# Regression plot, so we can gauge the linear relationship*
    sns.regplot(x = np.log(subsample[platform] + 1), y = subsample['SentimentTitle'], 
                ax=subplot, 
                color=color,
                *# Pass an alpha value to regplot's scatterplot call*
                scatter_kws={'alpha':0.5})

    *# Set a nice title, get rid of x labels*
    subplot.set_title(platform, fontsize=18)
    subplot.set_xlabel('') 

fig.suptitle('Plot of log(Popularity) by Title Sentiment', fontsize=24)

plt.show()

与我们可能预期的相反(来自我们对高度情绪化、点击量大的标题的想法),在这个数据集中,我们发现标题情绪和文章受欢迎程度(通过分享数量来衡量)之间没有关系。

为了更清楚地了解流行度本身是什么样子,让我们按平台绘制一个最终的 log(流行度)图。

fig, ax = plt.subplots(3, 1, figsize=(15, 10))

subplots = [a **for** a **in** ax]

**for** platform, subplot, color **in** zip(platforms, subplots, colors):

    sns.distplot(np.log(main_data[platform] + 1), ax=subplot, color=color, kde_kws={'shade':**True**})

    *# Set a nice title, get rid of x labels*
    subplot.set_title(platform, fontsize=18)
    subplot.set_xlabel('') 

fig.suptitle('Plot of Popularity by Platform', fontsize=24)

plt.show()

作为我们探索的最后一部分,让我们看看情绪本身。出版商之间似乎有所不同吗?

*# Get the list of top 12 sources by number of articles*
source_names = list(main_data['Source'].value_counts()[:12].index)
source_colors = list(sns.husl_palette(12, h=.5))

fig, ax = plt.subplots(4, 3, figsize=(20, 15), sharex=**True**, sharey=**True**)

ax = ax.flatten()
**for** ax, source, color **in** zip(ax, source_names, source_colors):
    sns.distplot(main_data.loc[main_data['Source'] == source]['SentimentTitle'],
                               ax=ax, color=color, kde_kws={'shade':**True**})
    ax.set_title(source, fontsize=14)
    ax.set_xlabel('')

plt.xlim(-0.75, 0.75)
plt.show()

这些分布看起来相当相似,但是当它们都在不同的地块上时,很难说出有多相似。让我们试着把它们都叠加在一个图上。

*# Overlay each density curve on the same plot for closer comparison*

fig, ax = plt.subplots(figsize=(12, 8))

**for** source, color **in** zip(source_names, source_colors):
    sns.distplot(main_data.loc[main_data['Source'] == source]['SentimentTitle'],
                               ax=ax, hist=**False**, label=source, color=color)
    ax.set_xlabel('')

plt.xlim(-0.75, 0.75)
plt.show()

我们看到,来源对文章标题的情感分布非常相似——就正面或负面标题而言,似乎没有任何一个来源是异常的。相反,所有 12 个最常见的来源都以 0 为中心分布,尾部大小适中。但这能说明全部情况吗?让我们再来看看这些数字:

# Group by Source, then get descriptive statistics for title sentiment
source_info = main_data.groupby('Source')['SentimentTitle'].describe()# Recall that `source_names` contains the top 12 sources
# We'll also sort by highest standard deviation
source_info.loc[source_names].sort_values('std', ascending=False)[['std', 'min', 'max']]

WSJ has both the highest standard deviation and the largest range.

我们可以一眼看出,与其他任何顶级来源相比,《华尔街日报》的标准差最高,范围最大,最低情绪最低。这表明《华尔街日报》的文章标题可能异常负面。为了严格验证这一点,需要进行假设检验,这超出了本文的范围,但这是一个有趣的潜在发现和未来方向。

流行预测

我们为建模准备数据的第一个任务是用各自的标题重新连接文档向量。幸运的是,当我们预处理语料库时,我们同时处理了corpustitles_list,所以向量和它们所代表的标题仍然匹配。同时,在main_df中,我们已经删除了所有流行度为-1 的文章,所以我们需要删除代表这些文章标题的向量。

在这台计算机上,按原样在这些巨大的向量上训练一个模型是不可能的,但我们会看看我们可以做些什么来降低维度。我还将从发布日开始设计一个新特性:“DaysSinceEpoch”,它基于 Unix 时间(在这里阅读更多)。

**import** **datetime**

*# Convert publish date column to make it compatible with other datetime objects*

main_data['PublishDate'] = pd.to_datetime(main_data['PublishDate'])

*# Time since Linux Epoch*
t = datetime.datetime(1970, 1, 1)

*# Subtract this time from each article's publish date*
main_data['TimeSinceEpoch'] = main_data['PublishDate'] - t

*# Create another column for just the days from the timedelta objects* 
main_data['DaysSinceEpoch'] = main_data['TimeSinceEpoch'].astype('timedelta64[D]')

main_data['TimeSinceEpoch'].describe()

正如我们所看到的,所有这些文章都是在 250 天之内发表的。

**from** **sklearn.decomposition** **import** PCA

pca = PCA(n_components=15, random_state=10)

*# as a reminder, x is the array with our 300-dimensional vectors*
reduced_vecs = pca.fit_transform(x)df_w_vectors = pd.DataFrame(reduced_vecs)

df_w_vectors['Title'] = titles_list# Use pd.concat to match original titles with their vectors
main_w_vectors = pd.concat((df_w_vectors, main_data), axis=1)

*# Get rid of vectors that couldn't be matched with the main_df*
main_w_vectors.dropna(axis=0, inplace=**True**)

现在,我们需要删除非数字和非虚拟列,以便将数据输入到模型中。我们还将对DaysSinceEpoch特性应用缩放,因为与减少的词向量、情感等相比,它在数量上要大得多。

*# Drop all non-numeric, non-dummy columns, for feeding into the models*
cols_to_drop = ['IDLink', 'Title', 'TimeSinceEpoch', 'Headline', 'PublishDate', 'Source'] 

data_only_df = pd.get_dummies(main_w_vectors, columns = ['Topic']).drop(columns=cols_to_drop)

*# Standardize DaysSinceEpoch since the raw numbers are larger in magnitude* 
**from** **sklearn.preprocessing** **import** StandardScaler

scaler = StandardScaler()

*# Reshape so we can feed the column to the scaler*
standardized_days = np.array(data_only_df['DaysSinceEpoch']).reshape(-1, 1)
data_only_df['StandardizedDays'] = scaler.fit_transform(standardized_days)

*# Drop the raw column; we don't need it anymore*
data_only_df.drop(columns=['DaysSinceEpoch'], inplace=**True**)

*# Look at the new range*
data_only_df['StandardizedDays'].describe()

# Get Facebook data only
fb_data_only_df = data_only_df.drop(columns=['GooglePlus', 'LinkedIn'])# Separate the features and the response
X = fb_data_only_df.drop('Facebook', axis=1)
y = fb_data_only_df['Facebook']

*# 80% of data goes to training*
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 10)

让我们对数据运行一个非优化的XGBoost,看看它是如何开箱即用的。

**from** **sklearn.metrics** **import** mean_squared_error

*# Instantiate an XGBRegressor*
xgr = xgb.XGBRegressor(random_state=2)

*# Fit the classifier to the training set*
xgr.fit(X_train, y_train)

y_pred = xgr.predict(X_test)

mean_squared_error(y_test, y_pred)

至少可以说,结果平平。我们可以通过超参数调整来提高这种性能吗?我从这篇 Kaggle 文章中提取并重新调整了一个超参数调整网格。

**from** **sklearn.model_selection** **import** GridSearchCV

*# Various hyper-parameters to tune*
xgb1 = xgb.XGBRegressor()
parameters = {'nthread':[4], 
              'objective':['reg:linear'],
              'learning_rate': [.03, 0.05, .07], 
              'max_depth': [5, 6, 7],
              'min_child_weight': [4],
              'silent': [1],
              'subsample': [0.7],
              'colsample_bytree': [0.7],
              'n_estimators': [250]}

xgb_grid = GridSearchCV(xgb1,
                        parameters,
                        cv = 2,
                        n_jobs = 5,
                        verbose=**True**)

xgb_grid.fit(X_train, y_train)

根据xgb_grid,我们的最佳参数如下:

{'colsample_bytree': 0.7, 'learning_rate': 0.03, 'max_depth': 5, 'min_child_weight': 4, 'n_estimators': 250, 'nthread': 4, 'objective': 'reg:linear', 'silent': 1, 'subsample': 0.7}

用新参数再试一次:

params = {'colsample_bytree': 0.7, 'learning_rate': 0.03, 'max_depth': 5, 'min_child_weight': 4, 
          'n_estimators': 250, 'nthread': 4, 'objective': 'reg:linear', 'silent': 1, 'subsample': 0.7}

*# Try again with new params*
xgr = xgb.XGBRegressor(random_state=2, **params)

*# Fit the classifier to the training set*
xgr.fit(X_train, y_train)

y_pred = xgr.predict(X_test)

mean_squared_error(y_test, y_pred)

大约好了 35,000,但我不确定这说明了很多。在这一点上,我们可以推断,当前状态的数据似乎不足以让这个模型运行。让我们看看我们是否可以用更多的功能工程来改进它:我们将训练一些分类器来区分两个主要的文章组:哑弹(0 或 1 份额)与非哑弹。

这个想法是,如果我们可以给回归变量一个新的特征(文章将具有极低份额的概率),它可能会在预测高度共享的文章方面表现得更好,从而降低这些文章的残值并减少均方误差。

迂回:检测无用的文章

从我们之前制作的对数转换图中,我们可以注意到,一般来说,有 2 个文章块:1 个簇在 0,另一个簇(长尾)从 1 开始。我们可以训练一些分类器来识别文章是否是“无用的”(在 0-1 股票箱中),然后使用这些模型的预测作为最终回归的特征,这将预测概率。这叫做模型叠加

# Define a quick function that will return 1 (true) if the article has 0-1 share(s)
def dud_finder(popularity):
    if popularity <= 1:
        return 1
    else:
        return 0# Create target column using the function
fb_data_only_df['is_dud'] = fb_data_only_df['Facebook'].apply(dud_finder)
fb_data_only_df[['Facebook', 'is_dud']].head()

# 28% of articles can be classified as "duds"
fb_data_only_df['is_dud'].sum() / len(fb_data_only_df)

现在我们已经有了无用的特征,我们将初始化分类器。我们将使用一个随机森林、一个优化的 xgb 分类器和一个 K-最近邻分类器。我将省去调优 XGB 的部分,因为它看起来与我们之前进行的调优基本相同。

from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_splitX = fb_data_only_df.drop(['is_dud', 'Facebook'], axis=1)
y = fb_data_only_df['is_dud']# 80% of data goes to training
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 10)# Best params, produced by HP tuning
params = {'colsample_bytree': 0.7, 'learning_rate': 0.03, 'max_depth': 5, 'min_child_weight': 4, 
          'n_estimators': 200, 'nthread': 4, 'silent': 1, 'subsample': 0.7}# Try xgc again with new params
xgc = xgb.XGBClassifier(random_state=10, **params)
rfc = RandomForestClassifier(n_estimators=100, random_state=10)
knn = KNeighborsClassifier()preds = {}
for model_name, model in zip(['XGClassifier', 'RandomForestClassifier', 'KNearestNeighbors'], [xgc, rfc, knn]):
    model.fit(X_train, y_train)
    preds[model_name] = model.predict(X_test)

测试模型,获得分类报告:

from sklearn.metrics import classification_report, roc_curve, roc_auc_scorefor k in preds:
    print("{} performance:".format(k))
    print()
    print(classification_report(y_test, preds[k]), sep='\n')

f1 成绩最好的是 XGC,其次是 RF,最后是 KNN。然而,我们也可以注意到,在召回(成功识别哑弹)方面,KNN 实际上做得最好。这就是为什么模型堆叠是有价值的——有时,即使是 XGBoost 这样优秀的模型也可能在像这样的任务中表现不佳,显然要识别的函数可以进行局部近似。包括 KNN 的预测应该会增加一些急需的多样性。

*# Plot ROC curves
for model in [xgc, rfc, knn]:
    fpr, tpr, thresholds = roc_curve(y_test, model.predict_proba(X_test)[:,1])
    plt.plot([0, 1], [0, 1], 'k--')
    plt.plot(fpr, tpr)

plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curves')
plt.show()*

人气预测:第二轮

现在,我们可以对三个分类器的概率预测进行平均,并将其用作回归变量的一个特征。

*averaged_probs = (xgc.predict_proba(X)[:, 1] +
                  knn.predict_proba(X)[:, 1] + 
                  rfc.predict_proba(X)[:, 1]) / 3X['prob_dud'] = averaged_probs
y = fb_data_only_df['Facebook']*

接下来是另一轮惠普调整,包括新的特性,我将不再赘述。让我们看看我们的表现如何:

*xgr = xgb.XGBRegressor(random_state=2, **params)# Fit the classifier to the training set
xgr.fit(X_train, y_train)y_pred = xgr.predict(X_test)mean_squared_error(y_test, y_pred)*

啊哦!这种性能本质上与我们进行任何模型堆叠之前是一样的。也就是说,我们可以记住,MSE 作为一种误差度量,往往会加重异常值。事实上,我们还可以计算平均绝对误差(MAE ),它用于评估具有显著异常值的数据的性能。在数学术语中,MAE 计算残差的 l1 范数,本质上是绝对值,而不是 MSE 使用的 l2 范数。我们可以将 MAE 与 MSE 的平方根进行比较,后者也称为均方根误差(RMSE)。

*mean_absolute_error(y_test, y_pred), np.sqrt(mean_squared_error(y_test, y_pred))*

平均绝对误差只有 RMSE 的 1/3 左右!也许我们的模型没有我们最初想象的那么糟糕。

作为最后一步,让我们根据 XGRegressor 来看看每个特性的重要性:

*for feature, importance in zip(list(X.columns), xgr.feature_importances_):
    print('Model weight for feature {}: {}'.format(feature, importance))*

Aha! prob_dud was found to be the most important feature.

整洁!我们的模型发现prob_dud是最重要的特性,我们的定制StandardizedDays特性是第二重要的特性。(特征 0 到 14 对应于简化的标题嵌入向量。)

尽管通过这一轮的模型堆叠,整体性能并没有得到改善,但是我们可以看到,我们确实成功地捕获了数据中可变性的一个重要来源,而模型正是利用了这个来源。

如果我继续扩展这个项目以使模型更加准确,我可能会考虑用外部数据增加数据,包括通过宁滨或哈希将 Source 作为变量,在原始的 300 维向量上运行模型,并使用每篇文章在不同时间点的流行度的“时间切片”数据(该数据的配套数据集)来预测最终的流行度。

如果您觉得这个分析很有趣,请随意使用代码,并对其进行进一步扩展!笔记本在这里是(注意,一些单元格的顺序可能与这里显示的略有不同),这个项目使用的原始数据在这里是。

使用包装器登录 Python

原文:https://towardsdatascience.com/using-wrappers-to-log-in-python-ccffe4c46b54?source=collection_archive---------7-----------------------

使用 Python 进行日志记录可能会很乏味,尤其是在使用它进行调试的时候。我本人并不喜欢 Conda 或 Pycharm(或任何其他花哨的 IDE),但对于那些喜欢的人来说,当你必须将代码投入生产时,你总是会遇到调试/控制的问题。添加大量代码来查看发生了什么,浪费了大量宝贵的时间,而 Python 调试器(pdb)至少提供了很少的帮助。

但更重要的是,大多数时候,作为开发人员,我们需要向代码中添加日志,所以日志记录很可能不是我们可以选择退出的选项。

出于这个原因,我决定发表这篇文章,在这篇文章中,我将向你展示一个非常简单、省时和强大的方法来记录你的 Python 脚本。您可以将细节推断到其他语言,只要它们有包装器和记录器(我可能会在将来的另一篇文章中讨论这些)。

主要概念相当简单:您希望在每次进入或退出函数时进行记录。您希望大多数函数都是这样,至少上层函数是这样,这样,如果代码在某个点中断,您就知道它在哪里中断以及中断的原因。每当您想要记录函数的进入或退出(或任何其他重要事件)时,问题就来了。但是每个问题都有一个解决方案,在这种情况下,解决方案是包装。

首先我将展示包装在 Python 中是如何工作的,然后是日志记录,然后我将把两者结合起来展示一个简单的例子。最后,我将展示一个更复杂的例子来描述这个相当简单的概念的威力。

包装材料

Photo by freestocks.org on Unsplash

对于那些不知道什么是包装的人。包装一个函数意味着无论什么时候调用这个函数,都要做一些事情。这就是你在包装器中定义的东西。包装器的示例:

这里得到

在这种情况下,作为 wrap 函数中的参数接收的 pre 和 post 变量是您将在被包装的函数之前和之后调用的函数。例如,如果您正在包装函数 bake_pie(),并将函数 before_baking 和 after_baking 作为参数传递给包装器,代码将执行函数 before_baking(),然后是 bake_pie(),最后是 after_baking()。

包装器函数的通常形式是这样的:

如您所见,函数进入和退出的参数是另一个函数(您正在包装的函数)及其参数。

让我们继续日志记录!

记录

日志记录就像打印一样,只是打印到一个文件中,有许多控制选项和时间显示。它主要用于了解服务器上的应用程序正在发生什么,或者在部署时进行调试。Python 中的基本日志配置如下所示:

如您所见,您可以声明想要写入的文件名、想要的调试级别(以便只将某些消息写入文件)以及关于消息格式的一些其他配置。我不会详细讨论日志,因为已经有很多关于日志的文章了,说实话这并不有趣!

使用包装器记录日志

所以现在我们有了包装器和记录器,只是把它们加起来的问题。我们需要做的是在进入()和退出()函数中加入日志记录功能,以显示当我们遍历代码的不同函数时,日志文件中发生了什么。一个基本的例子可能是这样的:

我们在进入和退出函数中添加了日志消息。

剩下的最后一件事是将包装器“标签”添加到我们想要包装的函数中。这个标签通常被称为 anotation,它只是一个“@”符号,后面跟一个包装器的名字,就在你的函数上面:

如果我们把所有的部分放在一起,看起来会是这样的:

Logging with wrappers 101

例如,如果您使用 bake_pie(3)执行函数 bake_pie,您将得到下一个日志文件:

2019–03–08 09:38:47800 调试进入 bake_pie
2019–03–08 09:38:47800 调试退出 bake _ pie

你可以添加注释@wrap(进入,退出)到任何其他函数,它也会这样做,这就是它的强大之处,所有的功能只需添加一行简单的代码

使用包装器的奇特日志记录

Photo by Jordane Mathieu on Unsplash

当然,你还可以做更有趣的事情。为了展示其中的一些,这里还有一个例子:

我已经改变了“pre”函数中的参数,所以它现在通过*args 接收它所包装的函数的参数。

现在,我们更改重要的部分,pre 函数本身,以便它给出关于它正在记录的函数的更详细的信息:

如您所见,我们现在记录了以下内容:

  • 函数名
  • 函数文档字符串
  • 它在文件中的位置(行号)和文件名
  • 传递给函数的第一个参数(如果有)

所有具有不同日志级别(调试、信息和警告)的日志

这是运行 bake_pie(3)将写入日志文件的内容:

2019–03–08 10:15:44919 DEBUG 进入 bake _ pie
2019–03–08 10:15:44919 INFO 烘烤一定量的馅饼
2019–03–08 10:15:44919 INFO 函数在 log gin _ with _ wrappers . py
2019–03–08 10:15:44919 警告

要检查一些很酷的内置你可以在这里显示 go 。你肯定会为包装器添加大量逻辑而疯狂,以便获得必要的最佳日志记录信息…

我希望这篇文章能帮助你减少花在日志记录上的时间和质量。

快乐日志:)

利用你自己设定的截止日期|今天就开始吧

原文:https://towardsdatascience.com/utilize-your-self-imposed-deadlines-punch-today-in-the-face-86f6e885164c?source=collection_archive---------28-----------------------

Photo by Kevin Ku at Unsplash

为自己设定最后期限的艺术至关重要,不仅是为了超越要求,也是为了让我们在实现大大小小目标的过程中更加顺利。爱他们或者恨他们;它们是令人难以置信的激励期限!然而,在处理截止日期时,有两件事我们应该尽量避免,完美主义或在截止日期前死去,这两件事都会增加压力。

即使是一个项目、一个目标、一次会议等,自我安排的技术也可以实现。没有实际的截止日期。它帮助我们组织我们处理每一个必须完成的任务或我们想要完成的目标的方式。这些自我设定的截止日期应该根据每项工作的优先级进行战略上的

为了让未来激励当前的行动,它必须让人感觉迫在眉睫。为了创造这种迫在眉睫的感觉,我们操纵了时间度量——考虑时间的单位(例如,天、年)。——小尼尔

目标是在几个月后取得重大胜利,这很好;然而,我们应该建立小的里程碑,小的成功!在几天内而不是几周或几个月内设定最后期限会在潜意识里激发一种更严肃和优先的意识。

无论我们是要写一篇文章,做一个项目,会见一个客户,计划一个营销活动,计划一个重大的变化,还是开始一项新的业务,我们都可以利用一些技巧和工具来避免淹没在焦虑中,因为延长的截止日期会对我们的健康造成严重破坏。

内部强加的期限减少了拖延。所以,自己设定最后期限可能比别人为你设定更好。—psychreg.com

技术

在过去的五年里,我每天都在使用的三个技巧是实现许多大大小小的里程碑的关键因素。他们让我明白了如何闯入数据科学和数字营销的世界。

ⓐ专注,提高生产力!

Photo by Patrick Tomasso at Unsplash

为了获得高质量的结果,每天专注于一项任务是至关重要的。记住,如果你想同时做所有的事情,你最终会一事无成!自我设定的期限是衡量你的行动是成功还是失败的重要标准。因此,优先考虑什么是最重要的,每天工作 3-4 小时,然后庆祝你的小里程碑!保持动力。

ⓑ建立短期里程碑,并庆祝!

Photo by Estée Janssens at Unsplash

处理大任务或大项目的一个很好的技巧是把它们分解成小的、小的里程碑。因此,这会让事情变得更加可行,这有助于开始工作并朝着最后期限努力。

完成任何一个里程碑后,犒劳或欺骗自己!设定最后期限,利用奖励和结果。

例如,作为我职业发展计划的一部分,我设定了一个目标,通过参加由 AJ & Smart 担任辅导员的设计冲刺大师班,在两周内阅读、学习和应用 设计冲刺 的力量。我决定,一旦我完成了这个项目,拿到了证书,我就再看一遍《指环王》三部曲!我做到了。

早起,今天又打脸了!

Photo by Johnson Wang at Unsplash

不管你是不是一个早起的人,在早上完成尽可能多的任务会提高你的生产力水平,鼓励你实现短期的里程碑。不过,提前计划是至关重要的!知道你早上要做什么,第二天早上要做什么,等等,将帮助你尽早实现每天的目标,然后,你就可以享受一天的剩余时间。然而,不要超出你的日常任务,除非你还在 3 到 4 个小时的范围内,或者你想为第二天节省一些时间。坚持每天的最后期限,保持专注,不断激励自己。

工具

他们不是必须的,但是,有时候你需要他们被组织起来,被激励着继续前进。你需要记录你的进展,记录你在每项任务上花费的时间。以下是我经常用来帮助我完成每个项目或任务的工具。

ⓐ时间追踪,用番茄工作法!

  • Klokki for Mac :自动计时,记录我在一项任务或整个项目上花了多少时间。

Photo Courtesy by Klokki.com

  • Toggl :另一个伟大的工具,我用它在我所有的设备上追踪每一个任务的时间。

Photo Courtesy by Klokki.com

****番茄工作法:一种时间管理技巧,用来提高你的注意力和工作效率。这项技术应用一个计时器将一项任务分解成多个间隔,传统上是 25 分钟,中间间隔 5 分钟。

ⓑ工作管理

  • 体位法:它有助于专注于你的工作目标、项目和日常任务。

Photo Courtesy by asana.com

你利用什么动机、工具、提示和奖励来满足自己设定的期限?

使用 CNN 来理解我们基因组的复杂性和预测未来的疾病

原文:https://towardsdatascience.com/utilizing-convolutional-neural-networks-cnns-for-predicting-dna-protein-interactions-and-ee22cf9095c5?source=collection_archive---------20-----------------------

在过去的几年里,机器和深度学习领域的指数级进展已经为解决医疗保健的一些最困扰的问题提供了一种新的方法:深度学习。事实上,医疗保健领域的人工智能市场预计到 2025 年将超过360 亿美元!从比放射科医生更准确地诊断各种形式的癌症患者,到了解 cfDNA 甲基化模式如何对应癌症诊断,使用 AI 和深度学习的应用层出不穷。我们可以想象这样一个世界,人工智能已经成功地让我们实际上绘制了我们的整个基因组,并且在致病突变发生前几年就预测它们!Deep GenomicsFreenome 这样的初创公司在这个行业处于领先地位,而像 VerilyCalico 这样的大型生物技术初创公司正在得到谷歌的资助,并开始开发使用人工智能的应用程序。但为什么人工智能在医疗保健领域的应用市场发展如此迅速?

基因组数据量和可访问性的增加

2003 年,人类基因组计划(HGB)花费了 30 亿美元成功测序了第一个人类基因组。现在,领先的基因测序公司之一 Illumina 已经提供了迄今为止最便宜的测序测试,仅售 47 美元。随着 23andMe DNA 测试等服务的普及,以及对个性化医疗的进一步研究,这有助于大幅增加可用数据量,这是训练人工智能模型的必要条件。尽管如此,我们理解基因组的能力几乎只是它实际意义的一小部分。正如来自 Deep Genomics 的 Brendan Frey 所说,我们使用基因测序和基因编辑工具来测量和改变生物学的能力远远超过了我们实际理解生物学的能力。人工智能正在改变这一切。

我发现 Deep Genomics 正在做的工作绝对是疯狂的,我想亲自尝试一下,了解一下这两个快速发展的学科的交集。我决定从事一个涉及生物功能的项目,这个项目已经在许多实验室进行过,从斯坦福到 Deep Genomics 等公司。我想了解DNA-蛋白质结合相互作用是如何工作的以及基因变异如何影响转录因子蛋白质在转录过程中的作用。

但是等等!等等,这些词是什么意思?让我们退一步,了解什么是转录因子蛋白质,以及它们如何影响转录。是时候上一点生物学 101 课了!

转录因子是如何工作的,为什么会与 DNA 结合?

我们基因组中的每个基因都由三个主要部分组成:启动子、内含子和外显子。启动子本质上是基因中负责转录的部分,也就是将 DNA 转录成 RNA 的过程。接下来的部分是内含子,将近 10000 个核苷酸长,包含基因的逻辑。生物学家把它比作计算机程序,或者基因背后的大脑。内含子有助于组织绑定的工作方式。另一方面,外显子只有 100 个核苷酸长,并且负责执行内含子的逻辑,或者使用计算机程序模拟的打印语句。

这个过程是如何工作的,DNA 被转录成 RNA,RNA 被翻译成蛋白质。蛋白质对于身体组织和器官的结构、功能和调节是必不可少的,因此这一过程是必不可少的。这个过程通过转录因子结合来调节,转录因子结合控制转录和翻译发生的频率。这听起来可能很简单,但这三个组成部分之间的关系有许多复杂之处,通常情况下,我们的基因突变不会导致结合。影响一个核苷酸的小突变会导致疾病和病症,如家族性高胆固醇血症,并可能导致某些形式的癌症!

为了解决理解这一过程如何工作以及检测基因变异的问题,我一直在致力于一个项目,以在 PyTorch 和 Tensorflow 等现代机器学习框架上实现由 UofT 的研究人员在 2015 年创建的工具【Deep bind】。这个模型是用 Matlab 编写的,我想看看我是否可以借助现在用于开发模型的更好的软件包和工具来提高或达到类似的精度。

deep bind 如何工作

DeepBind 是一种卷积神经网络架构,它接受有噪声的实验数据并输出结合亲和力,即转录因子蛋白质结合或粘附到序列上的可能性。虽然 CNN 通常用于图像数据,但该网络在基因组数据上工作得非常好,随机选择输入序列通过网络输出得分预测。根据我从 ENCODE 获得的实验数据,序列可以有不同的长度,从大约 15-100 个核苷酸。对于任何序列 s,该模型使用四个阶段计算结合分数 f(s)。

卷积阶段在整个序列中用参数 M 扫描一组模体检测器(4 x m 矩阵)。这使得系数不必是概率或对数奇数比(这是表达概率的另一种方式),不像位置权重矩阵(PWMs),其通常用于理解这些相互作用的序列特异性。

接下来,整流级将通过移动 motif 检测器的响应并使用整流线性单位函数(ReLU)将任何负值箝位至零来隔离任何模式。然后,它经过汇集阶段,其中模型计算每个基序检测器的最大值和平均值, M-k. 通过最大化,模型可以识别任何较长基序或模式的存在,而平均有助于增加或累积较短模式的效果。这两种汇集方法的贡献是由学习决定的。

Neural Network Produces Binding Score

最后,将神经网络输入到一个非线性神经网络中,权重为 W,结合基序检测器的响应产生一个分数。它采用维度为 d 的特征向量 z ,这是汇集到该输出分数中的输出,简单地使用可调权重的 (d+1) 维度向量,其中权重基于其对输出的贡献应用于向量中的每个值,并最终使用附加的偏置项来获得输出。然而,根据不同的网络配置,这是不同的。例如,如果我们实现 dropout,我们偶尔会忽略向量 z 的中间值,这具有很强的正则化效果。要了解这方面的更多信息,我建议查看他们发表在《自然》杂志上的论文的补充说明,这在我实现这个模型时对我非常有用。

然后,该模型将使用损失函数来比较模型的输出与结合相互作用的目标值,然后使用反向传播和随机梯度下降(sgd)来更新不同的参数,例如学习率。

DeepBind 运行良好的一个独特特性是自动训练管道。深度学习的最大障碍之一是模型对校准参数或超参数非常敏感。这些参数包括与训练算法相关的参数,如辍学、学习率、批量,而其他参数则与模型架构相关(层数和隐藏单元数),甚至更多!熟练地校准这些参数是提高模型准确性的关键。DeepBind 通过评估超参数的随机校准来自动化这一点,其中精度最高的模型根据训练数据进行训练。基于具有最佳准确度的候选,在新数据上测试超参数的校准,并且保存超参数校准用于在新数据上的进一步训练和测试。PyTorch 实现中保存超参数的代码如下所示:

deep bind 在基因组学研究中的应用

虽然这真的很酷,很迷人,但我们如何应用它来帮助解决医学和基因组学领域的问题呢?使用 DeepBind,我们可以通过计算机模拟来改变基因中某些结合位点的核苷酸,并确定它在结合上是积极还是消极的相互作用。例如,看看胆固醇基因的突变,我们可以看到某些突变可以通过影响结合亲和力来破坏结合位点。有时,这些突变对基因有积极的影响或没有影响,而其他突变会导致消极的原因,如胆固醇水平异常。

Source: NIPS 2017 Talk by Brendan Frey, CEO of Deep Genomics

结论

总之,人工智能在医疗保健领域的应用和可能性是无限的。从早期诊断,到了解疾病机制以开发治疗方法,人工智能以如此多的方式让我们以如此多的不同方式进一步解释基因组。使用 DeepBind,我们可以了解 DNA-蛋白质相互作用是如何工作的,并识别遗传变异和突变的影响。使用人工智能和深度学习,我们有机会了解隐藏在基因组内的许多秘密,并了解更多有关基本过程的信息。让我们确保我们理解生物学的能力与我们测量和改变生物学的能力相匹配,这样我们就能在治疗和研究方面做出最好的决定。

关键要点

  1. 人工智能和基因组学是两个快速发展的学科;将它们结合起来给了我们很多机会来改善医疗保健治疗和我们对基因组的理解。
  2. 使用 DeepBind,我们可以了解转录因子(TF)结合是如何工作的,并预测蛋白质是否会与基因结合。
  3. 通过计算机模拟,我们可以测试突变对基因的影响,以及它们是导致正突变还是负突变。
  4. 人工智能为我们提供了最好的机会,让我们理解生物学的能力与我们目前改变(想想 CRISPR-CAS9 和基因编辑)和测量生物学的能力相提并论。

后续步骤

如果您喜欢这篇文章,请务必遵循这些步骤,与我未来的项目和文章保持联系!

  1. 看看我在这个项目上发表的演讲
  2. 在 Linkedin上与我联系,了解我未来的发展和项目。我目前正在研究 NVIDIA 在 2018 年 12 月创建的 StyleGAN,每天都在阅读更多的论文!
  3. 请务必订阅我的每月简讯,以查看我参加的新项目、会议和发表的文章!
  4. 随时给我发电子邮件在 seyonec@gmail.com 谈论这个项目和更多!

利用免费图像工具实现家庭安全

原文:https://towardsdatascience.com/utilizing-free-image-tools-for-home-security-fd4a6630181c?source=collection_archive---------18-----------------------

为 2019 年开发者周黑客马拉松创建的 Webapp

在之前的一篇文章中,我展示了开箱即用的图像识别软件如何让面部检测变得几乎微不足道,但在这篇博客中,我将分享其他免费使用的 API 与图像应用的不同应用。我最近和丹尼·门多萨本杰明·梁史蒂文·欧洋一起参加了三藩市的开发者周黑客马拉松,在那里我们制作了一个名为 HomeView 的家庭安全网络应用的演示。这款应用背后的前提是,我们将使用 Clariai 的图像分类 API 来实现家庭安全目的,1)检测家庭入侵,2)更智能地监控婴儿。在最高级别上,我们的家庭入侵探测器拍摄图像(来自生产环境中的实时视频),并对人脸进行计数,以确保其中至少有一个人住在房子里。婴儿监视器检测图片中是否有婴儿,或者婴儿是否处于危险状态,即图片中有刀或火。在任何危险情况下,我们都会向用户发送短信,提醒他们家中存在不安全情况。如果你想使用 Flask 构建一个类似的 webapp,这个项目的代码在 my GitHub 上。

Source

该项目的家庭入侵部分利用了 Clarifai 的人脸嵌入人脸检测模型。人脸嵌入模型将图片作为输入,并输出描述该人脸的 1024 维向量。使用我和队友的照片,我们将我们的面部向量存储为与任何新面孔进行比较的向量。为了比较我们的脸,我们使用了余弦相似度,一种与两个向量的角度而不是大小相关的距离度量。这是稀疏向量的常见比较度量,因为当许多维度通常为 0 时,它们会删除可以测量角度的自由度,从而限制我们的比较空间。因此,我们可以用一种比评估欧几里得距离稍微更敏感的方法来测量人脸之间的距离。在评估高维稀疏向量时,这种更大的粒度使我们在断言新面孔是或不是项目成员时更有信心。下面的代码显示了我们使用的函数:

一旦我们存储了地面真实人脸向量,我们将运行人脸检测模型来计算新图片中的人脸数量。然后,我们将新图片中的每张脸与我们的地面真实脸进行比较,并确保至少有一个余弦相似度高于设定的阈值。如果没有一个比较高于这个阈值,我们可以断言没有一个面部足够接近我们的地面真实面部来被认为是“安全的”,因此,存在入侵者。

我们 webapp 的婴儿监视器部分使用了不同的 Clarifai 产品:通用模型。Clarifai 的通用模型是一个卷积神经网络,经过训练,可以对具有数千个标签的图片中的对象进行分类。给定左边的图片,模型将分配标签“婴儿”和“狗”,估计图片中既有婴儿也有狗。知道我们可以把图像标签看作一个二元分类问题,我们简单地从一个视频中输入一系列图片给模型,并问它“图片中有没有婴儿?”。如果没有,我们会发短信给父母或任何安装 webapp 的人。由于通用模型被训练的标签过多,我们可以增加婴儿监视器的“智能”,也可以检查危险情况。我们添加了一个危险阈值来确定婴儿是否在玩玩具(这是不应该的),房间里是否有火,或者婴儿是否有刀。如果根据框架中的项目,婴儿被认为处于危险之中,我们将向父母发送短信。

我们使用 Twilio API 来发送短信。在安装、获得 API 密钥并导入包之后,我们将他们的 create message 函数插入到我们的逻辑中。下面的代码显示了一个示例:

from twilio.rest import Clientbody = "Text for your message"
client.messages.create(to="YOUR PHONE NUMBER", 
                       from_="ORIGIN PHONE NUMBER",
                       body=body)

使用 if/else 逻辑,我们可以为不同的情况创建定制的文本消息,使用独特的文本和图像来描述情况,这可以在我们的存储库中的 app.py 文件中找到。

为了构建这项技术的演示,我们需要创建一个用户界面。Flask 是一个很好的工具,允许我们使用 Python 函数来影响网页,以显示我们编写的函数的效果。它太棒了,以至于有必要再写一篇博文来介绍所有这些伟大的特性。因为我是个老好人,我就把你联系到三个:烧瓶 伟大的

在许多层面上都有大量优秀的图像识别工具——从为图片中的对象调用 API 到整个训练好的神经网络架构。像大多数编码领域一样(尤其是在 Python 中),您通常不需要重新创建轮子来创建优秀的图像处理应用程序。由于这些可用的工具,可能需要几个小时、几天或几周训练的东西现在可以成为黑客马拉松挑战中进展最快的部分之一,所以使用它们吧!

联合国会议数据,以更好地了解全球趋势

原文:https://towardsdatascience.com/utilizing-un-session-data-to-better-understand-global-trends-c2dc3d1a46f3?source=collection_archive---------14-----------------------

探索文本分类的应用

介绍

第二次世界大战后成立的联合国,是建立和维护全球社会的最重要步骤之一。自 1945 年成立以来,联合国年度会议一直是解决紧迫全球问题的平台,因此记录了一段时间以来的主要问题和趋势。

通过这个项目,我想利用一个名为“联合国一般性辩论”的 Kaggle 数据集来探索这些全球趋势。

了解数据集

这个数据集有一些有意义的特征。每个实例都包含年份、会议编号、发言国家和会议记录。该数据集包含 1970 年至 2015 年的会话数据,时间范围为 46 年。我的第一步是汇总每年的会议,并为每年生成一个文本文件。然后,我使用 Sklearn 的 CountVectorizer 类来执行单词包,并输出每年排名前 10 的单词。有了这些信息,我用 Illustrator 生成了每年更常见单词的可视化描述。

生成数据可视化的思维过程

对于视觉效果,我心中有几个要点

  1. 可读的时间线— 观众应该能够直观地理解时间年表
  2. 关注趋势— 数据可视化的主要收获是快速流畅地理解数据中存在的主要趋势和异常。
  3. 访问数据— 虽然我想关注趋势,但我仍然希望浏览者能够看到数据(每年最常出现的词),并可能根据世界历史的先验知识或通过数据中有趣实例引发的研究得出自己的结论。

我想出了两个模型:

  1. 一种是按十年来划分数据——更容易理解,允许观众挑选他们想关注的细节
  2. 一个包含 1970 年至 2015 年间每年的数据,虽然需要考虑更多内容,但不会直观地将趋势划分为任意类别,而实际上,每年的数据趋势在本质上是连续的。

下面是第二个数据可视化,它记录了 1970 年到 2015 年之间的每年实例。

设计和数据表示

用色彩传达趋势

有些术语多年来一直出现,而有些只出现一两次。某些术语出现在数据集的中间,并且一直持续到最后。为了突出这些主要趋势和异常值,我给每个术语分配了颜色来标记它们。这样,观众可以在视觉上跟踪一个术语的存在和随时间变化的流行度。在整个数据集中一致的术语被分配较深的颜色,这提供了足够的但与背景(社区、权利、发展)几乎没有对比。被认为值得注意但不太重要的术语也被赋予较深的颜色(reform,2015)。在数据集时间线中间出现的术语,然后仍然是一个流行词,被赋予稍微明亮的颜色值(全球,气候)。此外,与世界危机和人类苦难原因相关的术语被赋予了明亮和不和谐的色彩(恐怖主义、核)。最后,那些只被提及几次的强有力的词被赋予了明亮柔和的颜色(千禧年,希望)。最后两个类别被指定为上述颜色类型,以便它们在浏览者看来最为突出。

关于主观数据分析的注记

我想简要说明一下我在这个数据表示中所做的主观选择。

清理文字稿:在清理文字稿时,我首先删除了一般的英语停用词。然而,在计算每年的前十个词时,我发现前十个词中的大多数词在过去的 46 年中保持一致。这些术语都是特定领域的术语。为了能够更深入地挖掘会议的内容,我删除了许多特定领域的术语。我想指出的是,我这样做是基于哪些术语出现得非常频繁,但设置了一个任意的阈值,即哪些术语出现得足够频繁,可以删除,哪些可以保留。改变阈值无疑会改变来自单词袋的结果。回顾已完成的工作,也许较低的去除单词的阈值会给出更具体和独特的逐年数据集。较低的门槛将消除诸如“社区”、“权利”和“发展”等术语。

删除了一些词语:国际、国家、联合、我们、世界、和平、国家、人民、组织、会议、安全、经济、政府

类别分配:我分配术语类别的过程本质上是非常定性的。像决定“合作”是相关的和有意义的,“支持”这样的选择是经过深思熟虑的,但仍然是主观的决定。

词根和词类:在我当前的项目实现中,为了简单和直接,像“开发”和“发展”这样的术语被视为同一术语。但是,需要注意的是,两者的区别中有加密的有意义的信息。有了语言学背景,人们可以根据单词的名词或动词形式所暗示的句子结构,潜在地得出关于时间段的结论(即,动词形式的频率可能暗示更有可能采取行动)。

有趣的数据发现

  • 1989 年— 环境:第一次提到前 15 名中的环境。
  • 1990-1991—希望:当我们在 1988 年看到“希望”的时候,这个词在 1990 年和 1991 年的前 15 名中再次出现。
  • 1991 年— 民主党:‘民主党’出现在前 15 名。
  • 1996 — 武器:‘武器’出现在前 15 名。
  • 2001—9 月:这个词出现在 2001 年的前 15 名中,表明 9/11 和恐怖主义是主要话题之一
  • 2004 年— 今天:“今天”一词进入了 2004 年的前十名。在那之后,“今天”这个词开始频繁出现在前 15 名中,这可能暗示了观点的转变
  • 气候和可持续性— 这些术语在 2000 年代开始频繁出现
  • 2015—“2015”在 2013 年和 2014 年出现的次数比 2015 年多。这可能意味着 2015 年将出台一项政策或在 2015 年实现一个目标。2015 年可能讨论了 2015 年议程的影响或发现。
  • 社区— 历年来使用频率最高的词,其次是“权利”

虽然我将这一部分作为有趣的数据发现包括在内,但看到许多有趣的收获都在前 15 名中,这表明也许删除一些更多的流行语会每年显示一个更独特的故事。与此同时,有趣的是,人权和社区等永恒的讨论仍然非常重要,但在优先级别上有所波动。

反思项目

我使用 Sklearn 的计数矢量器来生成每年的热门词汇。TF-IDF(术语频率-逆文档频率)可能会提供关于逐年趋势的更有见地的信息,因为它会突出显示逐年的异常,而不是强调所有会话数据中常见的术语。

有趣的扩展

我对年复一年的会议数据运行了一个主题生成算法(潜在的狄利克雷分配),只是为了看看该算法每年输出的头号主题是什么。以下是一些亮点:

1977: new rights africa south nuclear relations time situation independence east struggle that disarmament great israel
 — — — — — — — — — 
1990: new south africa rights region europe war time hope state end crisis relations kuwait east
 — — — — — — — — — 
1995: new rights nuclear social cooperation war time work process many important member region year weapons
 — — — — — — — — — 
2000: new millennium rights summit cooperation process global state globalization time work first role poverty social
 — — — — — — — — — 
2001: terrorism new global cooperation year poverty terrorist secretary september many process work africa state rights
— — — — — — — — — 
2009: global change crisis climate new financial that president challenges cooperation nuclear 09 time year rights
 — — — — — — — — — 
2014: global new that climate sustainable agenda 2015 rights change state year today goals post many

维斯。使用 Tensorflow 生成图像

原文:https://towardsdatascience.com/vaes-generating-images-with-tensorflow-61de08e82f1f?source=collection_archive---------9-----------------------

更新 25/01/2021:我会很快更新这些帖子,在 Twitter 上关注我以获得更多信息https://twitter.com/mmeendez8

我的前一篇文章中,我介绍了可变自动编码器背后的理论。现在是时候动手开发一些代码来引导我们更好地理解这项技术了。我决定使用 Tensorflow,因为我想用它来提高我的技能,并适应被推向 2.0 版本阅读更多信息

VAEsemane——一种用于音乐人机交互的可变自动编码器

原文:https://towardsdatascience.com/vaesemane-a-variational-autoencoder-for-musical-human-robot-interaction-b588ca7b9d12?source=collection_archive---------21-----------------------

类人机器人解决越来越困难的任务,因为它们稳步提高了与环境智能互动的技能。这个项目的目标是用软件合成器或人形机器人【Roboy】交互式播放音乐。音乐即兴创作是对当前呈现的音乐序列产生自发反应的行为,要求对乐器和呈现的音乐序列在音调、节奏和和声方面有很高的理解,这使得将这一系统付诸实践尤为困难。

Google Magenta(music vae)和ETH Zurich(MIDI-VAE)的研究人员最近一直在研究用软件生成音乐的可变自动编码器(VAEs) 。乔治亚理工大学展示了一个软硬件结合的系统,名为“西蒙机器人】

Fig. 1: Shimon robot developed at Georgia Tech University [Source: https://www.shimonrobot.com/]

对于这个项目,VAEs 被选为即兴创作的基础。VAEs 有一个很大的好处,那就是它们产生了一个连续的潜在空间,允许重建和解释数据。在 VAE 被训练之后,VAE 的解码器可以用来随机生成数据,该数据类似于它通过从单位高斯采样而被训练的数据。这种随机生成过程显示在下面的一个视频示例中。

该系统

Fig. 2: A full framework for robotic improvisation in real time

系统等待音乐序列的输入,以即兴序列来响应。它被分成所示的模块(见图 2)。任何 MIDI 控制器、键盘或合成器都可以用来播放音乐序列,为系统提供现场输入。该序列由 VAE 的编码器处理,将其嵌入潜在空间。音乐序列的潜在表示也称为嵌入,可以使用称为潜在空间修改器的图形用户界面(GUI)来重建或修改。GUI 允许修改 100 维潜在向量的值,创建由 VAE 解码器解码的新潜在向量,以形成新的音乐序列。可选地,序列可以被音符平滑器模块平滑,该模块将短 MIDI 音符视为噪声,并根据用户定义的阈值删除它们。即兴序列可以由软件合成器演奏,或者通过机器人操作系统(ROS)发送给模拟的机器人 Roboy** ,以便机器人在木琴上演奏。**

该系统使用卷积 VAE,而不是使用递归 VAE(如 Google Magenta 和 ETH Zurich 所示)。图 3 显示了 VAE 的编码器。解码器由编码器的逆映射组成。

Fig. 3: Architecture of the VAE encoder (adapted from Bretan et al. 2017). The decoder consists of the inverse mapping without the reparametrization step. The figure was created using NN-SVG.

使用 PyTorch 实现 VAE,并用 MAESTRO 数据集 进行训练。图 3 显示了所有的卷积运算。在一个音乐序列被嵌入到一个 100 维潜在向量之前有 4 个密集层。解码器由编码器的逆映射组成,没有重新参数化步骤。此外,批处理标准化和 ELU 激活函数适用于每一层。描述这个框架核心的 VAE 模型的代码如下所示。你可以在这里 找到 项目的完整源代码。****

模拟使用 CARDSFlow 框架(cards flow 的源代码这里,论文这里)这是 Roboy 项目(与香港中文大学合作)开发的肌肉骨骼机器人的设计、模拟和控制的工作流。图 4 显示了从 Autodesk Fusion 360 中的机器人设计到实际硬件控制的流程。

Fig. 4: CARDSFlow pipeline. It consists of (from left to right): 1) Robot design in Autodesk Fusion 360, 2) Simulation in Gazebo, 3) Muscle control through CASPR in Gazebo and 4) Control of the real robot.

下图(图 5)展示了在 ROS 的可视化工具 RVIZ 中模拟 Roboy 机器人的设置。

Fig. 5: Setup of Simulation in RVIZ.

例子

有五个典型的视频。其中三个展示了 VAE 模型在软件中生成音乐,而两个视频展示了机器人进行即兴创作。GUI,也称为潜在空间修改器,有 100 个数字电位计来修改当前嵌入序列的潜在向量。修改潜在向量导致解释或即兴创作,因为它略微改变了当前嵌入序列的高斯分布。在包括模拟 Roboy 机器人的示例中,绿色轮廓显示了机器人击打木琴球杆时的目标姿势。注:模拟机器人在演奏木琴时会跳过 MIDI 音符。这就是为什么它播放的音符比软件中生成的音符少的原因。

生成模式

第一个示例显示了 VAE 模型在“生成模式”下的性能。在这种模式下,从单位高斯分布中随机采样一个潜在向量,然后由 VAE 解码器解码以生成看不见的音乐序列

Variational Autoencoder — “Generate Mode” (Software Generation)

交互模式

下面的例子使用了“交互模式”,它允许人机交互。软件/机器人等待人类输入,并基于当前输入序列产生音乐响应。

Variational Autoencoder — “Interact Mode” (Software Improvisation)

Variational Autoencoder and Roboy robot — “Interact Mode” (Robotic Improvisation)

无尽模式

下面的例子显示了“无休止模式”,它等待人工输入,然后根据顺序开始播放音乐,直到你停止它。当前生成的序列(从 VAE 解码器输出)被馈送到输入端以产生解释。除了为软件/机器人即兴创作提供指导的第一个序列之外,没有其他互动。通过改变数字电位计的值,您可以遍历已学习的潜在空间,从而听到 VAE 模型学习了什么。

Variational Autoencoder — “Endless Mode” (Software Improvisation)

Variational Autoencoder and Roboy robot — “Endless Mode” (Robotic Improvisation)

机器人项目

Roboy 项目是一个用于肌肉骨骼机器人开发的开源平台,其目标是将人形机器人推进到机器人和人体一样好的状态。 Roboy 从其他机器人中脱颖而出,因为它是由模仿人类肌肉和肌腱的电机和肌腱驱动的,而不是每个关节中的电机。查看机器人项目网站Github 账户以获得更多信息。

Chest of Roboy 2.0 [Source: https://roboy.org]

Vaex:具有超级字符串的数据帧

原文:https://towardsdatascience.com/vaex-a-dataframe-with-super-strings-789b92e8d861?source=collection_archive---------3-----------------------

Vaex’ strings are super fast, not related to M-theory yet

字符串操作是数据科学的重要组成部分。Vaex 的最新版本为所有常见的字符串操作增加了令人难以置信的速度和内存效率支持。与 Pandas(Python 生态系统中最受欢迎的数据帧库)相比,字符串操作在四核笔记本电脑上快 30-100 倍,在 32 核计算机上快 1000 倍。

虽然 Pandas 对 Python 在数据科学中的流行负有很大责任,但它渴望内存。随着数据变得越来越大,你必须小心不要有记忆或者毁了你的一天。切换到更强大的机器可能会解决一些内存问题,但现在您的 31 个核心处于闲置状态。熊猫只会用你花里胡哨的机器 32 个核心中的一个。有了 Vaex,所有的字符串操作都在核心之外,并行执行,延迟评估,使您可以毫不费力地处理十亿行数据集。

"字符串处理速度几乎快了 1000 倍,相当于 1 分钟对 15 个小时!"

Vaex 和超弦

Vaex 现在正在超越快速数字处理,扩展到(超级)字符串领域。最新发布的包括了几乎所有熊猫的串串操作。现在,您可以轻松地执行所有的字符串操作,通过计算包含一个 googol (1 后跟 100 个零)行的数据帧中的字符串长度就可以证明这一点。

一个 googol 长度的数据帧展示了惰性评估的优势。当在严重畸形的输入数据上试验正则表达式时,您不必等一分钟就能看到您的所有操作是否正常。相反,您应用您的操作,打印出数据帧,并直接看到预览(头部和尾部),没有任何延迟。仅评估您看到的值。

性能基准

最终,你必须处理所有的数据。惰性评估不会加速操作,只会推迟操作。如果你需要导出数据或者把它传递给机器学习库,这需要最终发生,对吗?那么 vaex 表现如何呢?让我们拿一个有 1 亿行的人工数据集(详见附录),用 Pandas 和 Vaex (Spark 随后)进行同样的操作:

NOTE: Larger is better, x is logarithmic. Speedup of Vaex compared to Pandas on a quadcore laptop or 32 core machine. On your laptop you may expect 30–100x, on an AWS h1.8xlarge (32 core) we measured close to a 1000x speedup!

Vaex 在我的四核笔记本电脑上的运行速度提高了约 190 倍,在 AWS h1 . x8 大型计算机上甚至提高了约 1000 倍!最慢的操作是正则表达式,这是意料之中的。正则表达式是 CPU 密集型的,这意味着大部分时间花在运算上,而不是所有的簿记工作。简而言之,Python 的开销很低,而且 Python 的正则表达式引擎已经很快了,所以我们“仅仅”获得了 10-60 倍的加速。

如何:GIL、C++和 ApacheArrow

这怎么可能呢?涉及到三个要素:C++、 Apache Arrow 和全局解释器 Lock GIL (GIL)。在 Python 中,多线程受到 GIL 的阻碍,使得所有纯 Python 指令实际上都是单线程的。当迁移到 C++时,GIL 可以被释放,机器的所有内核都将被使用。为了利用这一优势,Vaex 在 C++中执行所有的字符串操作。

下一个要素是定义一个内存和磁盘上的数据结构,该数据结构能够有效地使用内存,这就是 Apache Arrow 发挥作用的地方。Apache Arrow 定义了一个经过深思熟虑的 StringArray,可以存储在磁盘上,对 CPU 友好,甚至支持屏蔽/空值。最重要的是,这意味着所有支持 Apache Arrow 格式的项目将能够使用相同的数据结构,而无需任何内存复制。

达斯克怎么办?

人们经常问 Dask 和 Vaex 相比如何。 Dask 是一个神奇的库,允许 Python 并行计算。事实上,我们希望将来在 dask 的基础上构建 Vaex,但是它们不能相提并论。然而,Vaex 可以与 dask.dataframe 相比较,dask . data frame 是一个使用 Dask 并行熊猫的库。对于我们运行的基准测试,dask.dataframe 实际上比纯熊猫慢(~ 2 倍)。由于 Pandas 字符串操作不释放 GIL,Dask 不能有效地使用多线程,因为它使用 numpy 进行计算时会释放 GIL。绕过 GIL 的一个方法是使用 Dask 中的进程。然而,与 Pandas 相比,它的运行速度慢了 40 倍,Pandas 慢了 1300 倍。)相比 Vaex。大部分时间都花在酸洗和拆线上。

虽然 Dask 是一个神奇的库,但 dask.dataframe 无法在字符串领域施展魔法。它继承了 Pandas 的一些问题,并且由于酸洗,使用进程会产生很大的开销。尽管可能有方法可以加快速度,但开箱即用的性能对于字符串来说并不太好。

火花呢?

Apache Spark 是 JVM/Java 生态系统中处理数据科学的大型数据集的库。如果 Pandas 不能处理特定的数据集,人们通常会求助于 PySpark,即 Spark 的 Python 包装器/绑定。如果你的工作是产生结果,而不是在本地或甚至在一个集群中产生火花,这是一个额外的障碍。因此,我们还针对相同的操作对 Spark 进行了基准测试:

NOTE: Larger is better, x is logarithmic. Comparing Vaex, Pandas and Spark.

Spark 的表现比熊猫更好,这是多线程的缘故。我们惊讶地看到 vaex 比 Spark 做得好得多。总的来说,如果你想在笔记本电脑上进行交互式工作:

  • 熊猫每秒可以处理数百万条字符串(并且不可扩展)
  • Spark 每秒可以处理 1000 万个字符串(并且会随着内核数量和机器数量的增加而增加)。
  • Vaex 每秒可以处理 1 亿个字符串,并且会随着内核数量的增加而增加。在一台 32 核的机器上,我们每秒可以处理十亿个字符串。

注意:有些操作会随字符串长度缩放,因此根据问题的不同,绝对数可能会有所不同。

今后

熊猫将永远存在,它的灵活性是无与伦比的,这在很大程度上是 Python 在数据科学中流行的原因。然而,当数据集变得太大而无法处理时,Python 社区应该有很好的答案。达斯克。dataframe 试图通过在熊猫的基础上构建来攻击大型数据集,但继承了它的问题。或者,nVidia 的 cuDF(RAPIDS 的一部分)通过使用 GPU 来解决性能问题,但需要现代 nVidia 显卡,内存限制更多。

Vaex 不仅试图通过使用更多的 CPU 内核和高效的 C++代码进行扩展,而且还通过其表达式系统/惰性评估采取了不同的方法。计算和操作仅在需要时进行,并以块的形式执行,因此不会浪费内存。更有趣的是,导致您的结果的表达式被存储。这是 vaex-ml 的基础,vaex-ml 是一种进行机器学习的新方法,其中管道成为您探索的人工产物。敬请关注。

结论

Vaex 使用 ApacheArrow 数据结构和 C++将字符串操作的速度在四核笔记本电脑上提高了大约 30-100 倍,在 32 核计算机上提高了 1000 倍。Pandas 几乎支持所有的字符串操作,内存使用几乎为零,因为惰性计算是分块进行的。

附录

基准测试从来都不公平,有时可能是人为的,并且与真实世界的性能不完全相同。每个人都知道或者应该知道这一点。基准测试给你一个预期的印象,但是特别是对于像正则表达式这样的操作,比较就变得很棘手。有基准总比没有好。在任何情况下,如果您想要重现这些结果,您可以通过使用这个脚本通过来实现。火花基准可以在这个位置找到

关于作者

Maarten Breddels 是一名企业家 和自由职业的开发人员/顾问/数据科学家,主要在 Jupyter 生态系统中使用 Python、C++和 Javascript。vaex . io创始人。他的专业领域从快速数值计算、API 设计到 3d 可视化。他拥有 ICT 学士学位,天文学硕士和博士学位,喜欢编码和解决问题。

这项工作是在约万·韦利亚诺斯基帕特里克·博斯 布拉特·亚米诺夫 的帮助下完成的

验证你的机器学习模型

原文:https://towardsdatascience.com/validating-your-machine-learning-model-25b4c8643fb7?source=collection_archive---------1-----------------------

机器学习

超越 k 倍交叉验证

Photo by NeONBRAND on Unsplash

我认为创建你的机器学习模型最被低估的一个方面是彻底的验证。使用适当的验证技术有助于您理解您的模型,但最重要的是,估计一个无偏的泛化性能。

没有适用于所有场景的单一验证方法。了解您是在处理组、时间索引数据,还是在验证过程中泄漏数据是很重要的。

哪种验证方法适合我的用例?

在研究这些方面时,我发现了大量描述评估技术的文章,但是验证技术通常停留在 k 倍交叉验证。

我将向您展示使用 k-Fold CV 的世界,并进一步深入到嵌套 CVLOOCV ,以及模型选择技术。

将演示以下验证方法:

  • 训练/测试分割
  • k 倍交叉验证
  • 留一交叉验证
  • 留一组交叉验证
  • 嵌套交叉验证
  • 时间序列交叉验证
  • Wilcoxon 符号秩检验
  • 麦克内马试验
  • 5x2CV 配对 t 检验
  • 5x2CV 组合 F 测试

1.拆分您的数据

所有验证技术的基础是在训练模型时拆分数据。这样做的原因是为了理解如果你的模型面对之前没有见过的数据会发生什么。

训练/测试分割

最基本的方法是训练/测试分离。原理很简单,您只需将数据随机分成大约 70%用于训练模型,30%用于测试模型。

Creating a train/test split with X being your features and y the target

这种方法的好处是,我们可以看到模型如何对以前看不到的数据做出反应。

然而,如果我们数据的一个子集只有特定年龄或收入水平的人呢?这通常被称为采样偏差:

抽样偏倚是由于人口中的非随机样本引起的系统误差,导致人口中的一些成员比其他成员更不可能被包括在内,从而导致有偏倚的样本。

A great illustration of sampling bias by http://www.jondornart.com/

在讨论有助于解决采样偏差的方法(如 k 倍交叉验证)之前,我想先讨论一下额外的维持集。

维持集

当优化您的模型的超参数时,如果您使用训练/测试分割进行优化,您可能会过度拟合您的模型。

为什么?因为模型会搜索符合您所做的特定训练/测试的超参数。

要解决这个问题,您可以创建一个额外的保持集。这通常是您在任何处理/验证步骤中没有使用的数据的 10%。

在训练/测试分割上优化您的模型之后,您可以通过验证维持集来检查您是否没有过度拟合。

提示:如果只使用训练/测试分割,那么我建议比较你的训练和测试集的分布。如果它们差别很大,那么你可能会遇到泛化的问题。使用刻面轻松比较它们的分布。

2.k 倍交叉验证(k 倍 CV)

为了最小化抽样偏差,我们可以考虑稍微不同的方法验证。如果我们不是进行一次拆分,而是进行多次拆分,并对这些拆分的所有组合进行验证,会怎么样呢?

这就是 k 折叠交叉验证的用武之地。它将数据分成 k 个折叠,然后在 k -1 个折叠上训练数据,并在被遗漏的一个折叠上进行测试。它对所有组合执行此操作,并对每个实例的结果进行平均。

5-Fold Cross-Validation

优点是所有的观察值都用于训练和验证,并且每个观察值只用于一次验证。我们通常选择 i=5 或 k =10,因为它们在计算复杂性和验证准确性之间找到了一个很好的平衡:

提示:交叉验证技术得出的每个折叠的分数比人们想象的更有洞察力。它们主要用于简单地提取平均性能。然而,人们也可以查看结果折叠的方差标准偏差,因为它将给出关于不同数据输入的模型稳定性的信息。

3.留一法交叉验证(LOOCV)

k 折叠 CV 的一个变体是留一交叉验证(LOOCV)。LOOCV 使用数据中的每个样本作为单独的测试集,而所有剩余的样本形成训练集。此变体与 k 相同——当 k = n (观察次数)时折叠 CV。

Leave-one-out Cross-Validation

使用 sklearn 可以轻松实现:

Leave-one-out Cross-Validation

注意:由于模型需要训练 n 次,LOOCV 的计算成本非常高。只有当数据很小或者你能处理那么多计算时才这样做。

留一组交叉验证

k 文件夹 CV 的问题是,你可能希望每个文件夹只包含一个组。例如,假设您有一个包含 20 家公司及其客户的数据集,您希望预测这些公司的成功。

Leave-one-group-out Cross-Validation

为了保持文件夹的“纯粹性”并且只包含一个公司,您可以为每个公司创建一个文件夹。这样,你就创建了一个 k 倍简历和 LOOCV 的版本,其中你漏掉了一家公司/集团。

同样,可以使用 sklearn 实现:

Leave-one-group Out Cross-Validation

4.嵌套交叉验证

当您优化模型的超参数,并使用相同的 k-Fold CV 策略来调整模型和评估性能时,您会面临过度拟合的风险。您不希望在找到最佳超参数的同一分割上评估模型的准确性。

相反,我们使用嵌套交叉验证策略,允许将超参数调整步骤与误差估计步骤分开。为此,我们嵌套了两个 k 重交叉验证循环:

  • 超参数调谐的内循环和
  • 估算精确度的外环。

Nested Cross-Validation (Outer loop: 5-Fold CV, Inner loop: 2-Fold CV)

下面的示例显示了一个对内部和外部循环都使用 k-Fold CV 的实现。

您可以自由选择在内部和外部循环中使用的交叉验证方法。例如,如果要按特定的组进行分割,可以对内部循环和外部循环都使用 Leave-one-group-out。

5.时间序列 CV

现在,如果你对时间序列数据使用 k -Fold CV 会发生什么?过度拟合将是一个主要问题,因为你的训练数据可能包含来自未来的信息。重要的是,所有的训练数据都发生在测试数据之前。

验证时间序列数据的一种方法是使用 k -fold CV,并确保在每个 fold 中,训练数据发生在测试数据之前。

5-Fold Time Series CV

幸运的是,sklearn 再次伸出了援手,它有一个内置的时间序列 CV:

注意:确保根据您使用的时间索引对数据进行排序,因为您没有为时间序列片段提供时间索引。因此,它将简单地根据记录出现的顺序创建拆分。

6.比较模型

什么时候你认为一个模型比另一个更好?如果一个模型的准确性比另一个高得不明显,这是选择最佳模型的充分理由吗?

作为一名数据科学家,我想确保我了解一个模型是否真的比另一个模型更准确。幸运的是,有许多方法将统计学应用于机器学习模型的选择。

Wilcoxon 符号秩检验

其中一种方法是 Wilcoxon 符号等级测试,这是配对学生的 t 测试的非参数版本。当样本量很小并且数据不符合正态分布时,可以使用它。

我们可以应用这个显著性测试来比较两个机器学习模型。使用 k 折叠交叉验证,我们可以为每个模型创建 k 个准确度分数。这将产生两个样本,每个模型一个。

然后,我们可以使用 Wilcoxon 符号秩检验来检验这两个样本是否存在显著差异。如果是的话,那么一个比另一个更准确。

Wilcoxon signed-rank test procedure for comparing two Machine Learning models

下面,您可以看到这个过程的实现。

Application of the Wilcoxon signed-rank test

结果将是一个 p- 值。如果该值低于 0.05,我们可以拒绝模型之间没有显著差异的无效假设。

注意:在模型之间保持相同的折叠是很重要的,以确保样本来自相同的人群。这可以通过在交叉验证过程中简单地设置相同的 random_state 来实现。

麦克内马试验

McNemar 检验用于检查一个模型和另一个模型之间的预测匹配程度。这被称为列联表的同质性。从该表中,我们可以计算出 x ,该值可用于计算p-值:

McNemar’s test for comparing two Machine Learning models

同样,如果p-值低于 0.05,我们可以拒绝零假设,并看到一个模型明显优于另一个。

我们可以使用[mlxtend](http://rasbt.github.io/mlxtend/installation/)包创建表格并计算相应的p-值:

McNemar’s test

5x2CV 成对t-测试

5x2CV 配对t-测试由于其强大的统计学基础,是一种常用于比较机器学习模型的方法。

该方法工作如下。假设我们有两个分类器,A 和 b。我们随机地将数据分成 50%的训练和 50%的测试。然后,我们根据训练数据训练每个模型,并计算来自测试集的模型之间的精确度差异,称为。然后,在 DiffB 中反转训练和测试分割并再次计算差异。

这重复五次,之后计算差异的平均方差( S )。然后,用于计算t-统计量:

其中 DiffA₁ 为第一次迭代的均值方差。

5x2CV paired t-test procedure for comparing two Machine Learning models

同样,我们可以使用[mlxtend](http://rasbt.github.io/mlxtend/installation/)包来计算相应的p-值:

:你可以使用组合的 5x2CV F 检验来代替,它被证明是稍微更稳健的( Alpaydin,1999 )。该方法在mlxtend中实现为
from mlxtend.evluate import combined_ftest_5x2cv

结论

验证可能是一个棘手的问题,因为它需要对数据有深刻的理解,以便选择正确的程序。希望这能帮助你对经常用于验证的方法有所了解。

所有的代码都可以在这里找到:

* [## MaartenGr/验证

这个报告包含了验证博客的代码。

github.com](https://github.com/MaartenGr/validation)*

感谢您的阅读!

如果你像我一样,对人工智能、数据科学或心理学充满热情,请随时在 LinkedIn 上添加我,或者在 Twitter 上关注我。

验证方法

原文:https://towardsdatascience.com/validation-methods-e4eefcbee720?source=collection_archive---------17-----------------------

在本帖中,我们将讨论以下概念,它们都旨在评估分类模型的性能:

  1. 模型的交叉验证。
  2. 混乱矩阵。
  3. ROC 曲线。
  4. 科恩的 κ 分数。
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import warningswarnings.filterwarnings('ignore')

我们首先创建一些具有三个特征和二进制标签的简单数据集。

from sklearn.model_selection import train_test_split# Creating the dataset
N = 1000 # number of samples
data = {'A': np.random.normal(100, 8, N),
        'B': np.random.normal(60, 5, N),
        'C': np.random.choice([1, 2, 3], size=N, p=[0.2, 0.3, 0.5])}
df = pd.DataFrame(data=data)# Labeling 
def get_label(A, B, C):
    if A < 95:
        return 1
    elif C == 1:
        return 1
    elif B > 68 or B < 52:
        return 1
    return 0df['label'] = df.apply(lambda row: get_label(row['A'],row['B'],row['C']),axis=1)# Dividing to train and test set
X = np.asarray(df[['A', 'B', 'C']])
y = np.asarray(df['label'])
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

为了演示的目的,让我们尝试使用一个简单的逻辑回归。

from sklearn import linear_model
from sklearn.model_selection import cross_val_scoreclf = linear_model.LogisticRegression()
clf.fit(X_train, y_train)print(">> Score of the classifier on the train set is: ", round(clf.score(X_test, y_test),2))>> Score of the classifier on the train set is:  0.74

交叉验证

交叉验证背后的想法很简单——我们选择某个数字 k ,通常是 k =5 或者 k =10 (5 是 sklearn 中的默认值,参见[1])。我们将数据分成 k 个大小相等的部分,在这些部分的k1 上训练模型,并在剩余部分上检查其性能。我们这样做 k 次,我们可以对分数进行平均以获得一个 CV 分数。

优点:使用交叉验证可以给你一个暗示,告诉你你的模型做得有多好,它的优点是非常健壮(与简单的训练-测试分割相反)。它还可以用于参数的超调:对于给定的参数,使用 CV 分数以稳健的方式优化其值。

让我们看看我们的例子的 CV 分数:

scores = cross_val_score(clf, X_train, y_train, cv=10)
print('>> Mean CV score is: ', round(np.mean(scores),3))
pltt = sns.distplot(pd.Series(scores,name='CV scores distribution'), color='r')>> Mean CV score is:  0.729

还可以使用 CV 分数的值来导出置信区间,在该置信区间中,我们可以确保找到实际分数的概率很高。

混淆矩阵

这个想法相当简单。我们希望显示真阳性(TP),真阴性(TN),假阳性(FP)和假阴性(FN)。更一般地,当有几个标签时,我们显示属于标签 i 但被归类为 j 的数据点的数量。这个数字被定义为混淆矩阵的( ij )条目。

from sklearn.metrics import confusion_matrix
C = confusion_matrix(clf.predict(X_test),y_test)
df_cm = pd.DataFrame(C, range(2),range(2))
sns.set(font_scale=1.4)
pltt = sns.heatmap(df_cm, annot=True,annot_kws={"size": 16}, cmap="YlGnBu",  fmt='g')

ROC 曲线

让我们仔细看看混淆矩阵。我们讨论了真阳性(TP)和假阳性(FP)的概念。很明显,如果我们允许 FP 为 1,那么 TP 也将等于 1;一般来说,如果 TP 和 FP 相等,我们的预测和随机猜测一样好。

ROC 曲线被定义为 TP 作为 FP 的函数的图。因此,根据以上讨论,ROC 曲线将位于直线 y = x 上方。

ROC 曲线的构建来自我们的分类器分配给每个点的概率;对于用标签 li ∈{0,1}预测的每个数据点 xi ,我们有一个概率 pi ∈[0,1】使得 yi = li

from sklearn.metrics import confusion_matrix, accuracy_score, roc_auc_score, roc_curve
pltt = plot_ROC(y_train, clf.predict_proba(X_train)[:,1], y_test, clf.predict_proba(X_test)[:,1])

考虑到 ROC 曲线,有几个重要的概念:

(ROC 曲线下面积(AUC),是分类器质量的重要度量。对于一个随机的猜测,我们有 AUC=∫ x d x =1/2,所以我们排除了一个知情分类器的分数> 1/2。概率解释如下:随机正数比均匀抽取的随机负数排在前面(根据模型的概率)的概率。ROC AUC 是机器学习中常用的一种(3)。

(2)图上标记的点是 TP 和 FP 的比率,正如我们前面在混淆矩阵中看到的。

(3)如果 ROC 曲线位于线 y = x 之下,这意味着通过反演分类器的结果,我们可以得到一个信息性的分类器。拥有一个总是给出错误答案的算法和拥有一个好的算法一样好!下面是绘制 ROC 曲线的代码(摘自2)。

def plot_ROC(y_train_true, y_train_prob, y_test_true, y_test_prob):
    '''
    a funciton to plot the ROC curve for train labels and test labels.
    Use the best threshold found in train set to classify items in test set.
    '''
    fpr_train, tpr_train, thresholds_train = roc_curve(y_train_true, y_train_prob, pos_label =True)
    sum_sensitivity_specificity_train = tpr_train + (1-fpr_train)
    best_threshold_id_train = np.argmax(sum_sensitivity_specificity_train)
    best_threshold = thresholds_train[best_threshold_id_train]
    best_fpr_train = fpr_train[best_threshold_id_train]
    best_tpr_train = tpr_train[best_threshold_id_train]
    y_train = y_train_prob > best_threshold cm_train = confusion_matrix(y_train_true, y_train)
    acc_train = accuracy_score(y_train_true, y_train)
    auc_train = roc_auc_score(y_train_true, y_train) fig = plt.figure(figsize=(10,5))
    ax = fig.add_subplot(121)
    curve1 = ax.plot(fpr_train, tpr_train)
    curve2 = ax.plot([0, 1], [0, 1], color='navy', linestyle='--')
    dot = ax.plot(best_fpr_train, best_tpr_train, marker='o', color='black')
    ax.text(best_fpr_train, best_tpr_train, s = '(%.3f,%.3f)' %(best_fpr_train, best_tpr_train))
    plt.xlim([0.0, 1.0])
    plt.ylim([0.0, 1.0])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('ROC curve (Train), AUC = %.4f'%auc_train) fpr_test, tpr_test, thresholds_test = roc_curve(y_test_true, y_test_prob, pos_label =True) y_test = y_test_prob > best_threshold cm_test = confusion_matrix(y_test_true, y_test)
    acc_test = accuracy_score(y_test_true, y_test)
    auc_test = roc_auc_score(y_test_true, y_test) tpr_score = float(cm_test[1][1])/(cm_test[1][1] + cm_test[1][0])
    fpr_score = float(cm_test[0][1])/(cm_test[0][0]+ cm_test[0][1]) ax2 = fig.add_subplot(122)
    curve1 = ax2.plot(fpr_test, tpr_test)
    curve2 = ax2.plot([0, 1], [0, 1], color='navy', linestyle='--')
    dot = ax2.plot(fpr_score, tpr_score, marker='o', color='black')
    ax2.text(fpr_score, tpr_score, s = '(%.3f,%.3f)' %(fpr_score, tpr_score))
    plt.xlim([0.0, 1.0])
    plt.ylim([0.0, 1.0])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('ROC curve (Test), AUC = %.4f'%auc_test)
    plt.savefig('ROC', dpi = 500)
    plt.show() return best_threshold

科恩的 κ 得分

Cohen 的 κ 分数给出了两个分类器对相同数据的一致性。定义为κ= 1(1-po)/(1-PE),其中 po 为观察到的符合概率, pe 为符合的随机概率。

让我们看一个例子。我们需要再使用一个分类器。

from sklearn import svmclf2 = svm.SVC()
clf2.fit(X_train, y_train)print(">> Score of the classifier on the train set is: ", round(clf2.score(X_test, y_test),2))>> Score of the classifier on the train set is:  0.74

我们计算列车组上的 κ

y = clf.predict(X_test)
y2 = clf2.predict(X_test)
n = len(y)p_o = sum(y==y2)/n # observed agreementp_e = sum(y)*sum(y2)/(n**2)+sum(1-y)*sum(1-y2)/(n**2) # random agreement: both 1 or both 0kappa = 1-(1-p_o)/(1-p_e)print(">> Cohen's Kappa score is: ", round(kappa,2))>> Cohen's Kappa score is:  0.4

这表明两个分类器之间存在某种一致性。 κ =0 表示不一致,而 κ < 0 也可以发生在两个分类器不一致的时候。

结论

我们讨论了对您的模型进行评分并将其与其他模型进行比较的几种基本策略。在应用机器学习算法和比较它们的性能时,记住这些概念很重要。

参考文献

[1]https://sci kit-learn . org/stable/modules/cross _ validation . html

2此处提供评估 ROC 曲线的函数:https://github.com/bc123456/ROC

[3]https://en . Wikipedia . org/wiki/Receiver _ operating _ character istic

https://en.wikipedia.org/wiki/Cohen%27s_kappa

价值投资仪表盘,配有 Python Beautiful Soup 和 Dash Python

原文:https://towardsdatascience.com/value-investing-dashboard-with-python-beautiful-soup-and-dash-python-43002f6a97ca?source=collection_archive---------7-----------------------

价值投资的 Web 抓取与快速 Dash 可视化概述

Creating Python Value Investing Dashboard for data extractions

问题陈述

所以我通常在 SGX 或雅虎财经等交易网站上搜索股票,并将相关数据一个一个复制粘贴到我的电子表格中

“应该可以快速访问最相关的股票信息,以便我做出买入/卖出决定”

我仍然记得我的朋友如何吹嘘他从 SGX(新加坡证券交易所)复制粘贴的不同股票比率的辛苦工作的工作表。出于纯粹的决心,他一个接一个地复制数据,通过数百次查看和点击来检索股票信息,并将其转储到 excelsheet,在那里他手动保存所有公式。

整个过程看起来很滑稽,因为有很多手动滚动和点击来提取看起来很大的数字,以做出买/卖决定。这个问题启发我构建自己的工具来自动提取和快速处理相关的财务比率。

免责声明:本免责声明告知读者,文中表达的观点、想法和意见仅属于作者,不一定属于作者的雇主、组织、委员会或其他团体或个人参考文献是从列表中挑选的,与其他作品的任何相似之处纯属巧合

这篇文章纯粹是作者的个人项目,绝无任何其他不可告人的目的。

解决方案:Web 抓取和仪表板可视化

在这个项目中,我将向您展示一个仪表板,您可以使用它快速获得重要的财务反馈。用户只需输入股票代码(如谷歌或 MSFT),应用程序将处理所有必要的关键比率和未来价格的计算。从 MarketWatch 检索到信息后,应用程序会将数字处理成预定义的值子集。最终结果将显示用户是否应该根据用户定义的边际价值和市场价格来购买/出售某些股票

该应用程序旨在消除用户访问股票市场网站的需求,如 SGX,雅虎/谷歌金融,他们可以使用我们的应用程序作为所有关键股票信息,基本分析和警告信号的一站式用户学习。

下面是应用程序演示,请注意屏幕将如何根据用户输入更新股票代码:

Value Investing Application Dashboard. This will help you screen and extract relevant financial ratio quickly (from Google to GameStop Stocks)

更新:6 月 27 日

我已经清理并部署了应用程序。请在这里尝试一下!

[## 破折号

编辑描述

value-investing.herokuapp.com](https://value-investing.herokuapp.com)

用途和 Github 代码

本概念证明(POC)是作为我目前管理的投资方项目的一部分而创建的。毕业后不久,肖恩·西的书《和沃伦·巴菲特一起去钓鱼》启发了我投资的想法。这本书启发我创造了自己的价值投资工具。这个应用程序的目标是帮助您快速检索和显示关于某个公司股票的正确的财务信息。

在 POC 中,我使用 Beautiful Soup 作为 Web 抓取工具,使用 Pandas data-reader API 获取金融股票价格,最后使用 Python 和 Flask/Dask 作为 Web 应用程序框架。Github 代码位于下面。

[## 文森特/价值投资

价值投资仪表板。通过在 GitHub 上创建帐户,为 VincentTatan/ValueInvesting 的发展做出贡献。

github.com](https://github.com/VincentTatan/ValueInvesting)

随时克隆回购,有空随时贡献。

项目范围

对于这一应用,我想强调 5 个过程:

Workflows on the Python Stocks Dashboard

让我们试着一个一个地分解它

股票输入刮削

在这个列表中,我们将提取股票列表及其代码,例如:谷歌(Google)或微软(MSFT)。我们将从 3 个来源提取这些信息:

从维基百科获取 SP500 股票信息

S & P 道琼斯指数维护的 S & P 500 股票市场指数,由 500 大盘股公司发行的 505 普通股组成,并在美国证券交易所交易(包括构成道琼斯工业平均指数的 30 家公司),按市值计算覆盖了美国股票市场的 80%左右。—维基百科

为了提取这些信息,我们将使用股票指数的链接。

[## 标准普尔 500 公司列表-维基百科

由 S&P 道琼斯指数维护的标准普尔 500 股票市场指数由 500 家公司发行的 505 种普通股组成

en.wikipedia.org](https://en.wikipedia.org/wiki/List_of_S%26P_500_companies)

SP500 Stocks Table from Wikipedia

可以用美汤 4 之类的网页抓取库提取这个表。请随意参考这里的文章。

[## 美丽的汤 4 蟒蛇

概述本文是对 Python 中 BeautifulSoup 4 的介绍。如果你想知道更多,我推荐你...

www.pythonforbeginners.com](https://www.pythonforbeginners.com/beautifulsoup/beautifulsoup-4-python)

首先,我们将创建到美丽的汤传递 URL 链接。这将提取一些值作为汤

import requestsresp = requests.get('http://en.wikipedia.org/wiki/List_of_S%26P_500_companies')
soup = BeautifulSoup(resp.text, 'lxml')

这个 soup 对象将保存 HTML 文本,您可以通过运行以下命令提取这些文本。

for row in table.findAll('tr')[1:]:
        ticker = row.findAll('td')[0].text
        security = row.findAll('td')[1].text
        gics_industry = row.findAll('td')[3].text
        gics_sub_industry = row.findAll('td')[4].text

        tickers.append(ticker.lower().replace(r"\n", " "))
        securities.append(security)
        gics_industries.append(gics_industry.lower())
        gics_sub_industries.append(gics_sub_industry.lower())

该命令将查找表,然后迭代每一行以检索每一列的数据。提取出来的内容将被放入一个列表中,这个列表稍后将被转储到一个键和值对的字典列表中。

# Create a list of dict based on tickers and labels
dictlist = []
for index, row in stocks_info_df.iterrows():
     dictlist.append({'value':row['tickers'], 'label':row['labels']}) 
return dictlist

获取罗素股票信息

获取罗素股票信息甚至更简单,因为数据是公开的。请随意参考现有的 Russel 股票库。我们可以使用 pandas readcsv 方法来读取它。

dfrussel=pd.read_csv('C:/Users/vintatan/Desktop/Investment/RussellandData.csv',index_col='Symbol')

添加自己的股票信息列表

对于 SP200 或 Russell 列表中不存在的任何报价器,我们可以手动将我们的股票价值和标签传递到字典列表中。

# self append
def save_self_stocks_info():
    print("Adding own list of stocks info")

    dictlist = []

    dictlist.append({'value':'sq', 'label':'SQ Square SA'})
    dictlist.append({'value':'kbsty', 'label':'Kobe steel'})
    dictlist.append({'value':'NESN', 'label':'Nestle'})
    dictlist.append({'value':'BN', 'label':'Danone'})

结论

从这些提取 3 个不同来源的方法中,你可能意识到我正在传递一个字典对象的列表。这是因为破折号组合框输入需要格式化。请参考此处的 Dash 可视化工具

dcc.Dropdown(
    id='my-dropdown',
    options=save_sp500_stocks_info()+save_self_stocks_info(),
    value='coke'
),

Stock Ticker Dash Combo Box Inputs

雅虎股票价格与熊猫数据阅读器刮

我们将使用熊猫-数据阅读器生成基于雅虎的股票价格。在这里,我们向 web 传递了 4 个参数。DataReader

自动收报机,在这种情况下,它会把 MSFT,谷歌等

数据来源是雅虎

开始时间,从 2013 年 1 月 1 日开始。

结束时间,也就是现在。

一旦我们生成了 stockpricedf,我们就返回一个带有关键字“data”的字典,并返回 x 轴上的日期和 y 轴上的收盘价。

 stockpricedf = web.DataReader(
        selected_dropdown_value.strip(), data_source='yahoo',
        start=dt(2013, 1, 1), end=dt.now())

This is the Stocks Price DataFrame Retrieved from Web.DataReader

这将转化为你在这里看到的价格图表

 return {
        'data': [{
            'x': stockpricedf.index,
            'y': stockpricedf.Close
        }]
    }

Price Chart over 5 years

资产负债表和损益表摘录与美丽的汤

在这个子主题中,我们将尝试提取重要的比率,并将其显示为 Dash 表。以下是我们感兴趣的比率:

每股收益是公司利润分配给每股普通股的部分

ROE(股本回报率)是对财务绩效的一种衡量,计算方法是将净收入除以股东权益

ROA(资产回报率)是一个公司相对于其总资产盈利程度的指标

长期债务将包括公司债券发行或长期租赁,它们已经在公司的资产负债表上资本化

总收入象征着公司的收入

债转股用于评估公司的财务杠杆

利息保障率用于确定公司支付未偿债务利息支出的难易程度

这些定义来自 Investopedia。请在下面找到更多详细信息

[## 更敏锐的洞察力。更明智的投资。

股市基础想知道股市到底是怎么运作的?这本指南将教你一些基本知识。最佳经纪人…

www.investopedia.com](https://www.investopedia.com/)

我们将使用市场观察资产负债表和损益表链接,并将它们分配给变量。注意这里的股票代号指的是公司的股票代号。因此,苹果损益表的链接是https://www.marketwatch.com/investing/stock/AAPL/financials,苹果资产负债表的链接是https://www.marketwatch.com/investing/stock/AAPL/financials/资产负债表

urlfinancials = 'https://www.marketwatch.com/investing/stock/'+ticker+'/financials'
urlbalancesheet = 'https://www.marketwatch.com/investing/stock/'+ticker+'/financials/balance-sheet'text_soup_financials = BeautifulSoup(requests.get(urlfinancials).text,"lxml")
text_soup_balancesheet = BeautifulSoup(requests.get(urlbalancesheet).text,"lxml")

类似于提取公司代码,我们还使用 Beautiful Soup 从财务和资产负债表 url 中识别比率。我们将通过使用标签文本作为指示符遍历所有的同级属性来提取它们。

# Income Statement
for title in titlesfinancials:
    if 'EPS (Basic)' in title.text:
        epslist.append ([td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text])
    if 'Net Income' in title.text:
        netincomelist.append ([td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text])
    if 'Interest Expense' in title.text:
        interestexpenselist.append ([td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text])
    if 'EBITDA' in title.text:
        ebitdalist.append ([td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text])

# Balance sheet
titlesbalancesheet = text_soup_balancesheet.findAll('td', {'class': 'rowTitle'})
equitylist=[]
for title in titlesbalancesheet:
    if 'Total Shareholders\' Equity' in title.text:
        equitylist.append( [td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text])
    if 'Long-Term Debt' in title.text:
        longtermdebtlist.append( [td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text])

我们将提取的值填充到单独的数据框中。

df= pd.DataFrame({'eps': eps,'epsgrowth': epsgrowth,'netincome': netincome,'shareholderequity': shareholderequity,'roa': 
              roa,'longtermdebt': longtermdebt,'interestexpense': interestexpense,'ebitda': ebitda},index=[2013,2014,2015,2016,2017])

Result of the extractions

该数据帧将被转储到 dash 表对象中,如下所示

Critical Variables and Ratios Table

基于价值投资逻辑的警示信号列表

然后,我们将创建 eligibilitycheck.py 来遍历这些规则,并根据提取的比率识别一些可能的风险。

给定公司列表,找出投资的可行性
进入市场至少 10 年
有跟踪记录(每年 EPS)
有效率(ROE > 15%) —净收入/股东权益
确定操纵(ROA > 7%) —净收入/总资产
有小额长期债务(长期债务< 5*总收入)
低负债权益比
支付利息的能力:(利息保障比率> 3) — EBIT /利息支出

使用上面生成的数据帧,我们将检索一个警告列表

Warning Flags

基于股票每股收益边际价格的决策机

然后,我们将通过从用户定义的参数中推导出用户是否应该从预期未来值和边际值中购买来创建我们的最后一个步骤。以下是在 futurepricing.py 中实施的步骤

根据给定的价值投资方法,每家公司根据回报率做出决策
找出每股收益的年复合增长率
估计 10 年后的每股收益
估计 10 年后的股价(股价每股收益*平均每股收益)
根据回报率确定今天的目标价格(贴现率 15%/20%)
增加安全边际(安全网 15%)
如果市场价格低于边际价格,则买入
如果市场价格高于边际价格,则卖出

从这里,我们将从 Sean Seah 的书的逻辑中生成以下参数。

在此功能中,我们将允许用户输入诸如折扣率和边际率。贴现率表示 5 年期间的预测通货膨胀率,差额计算率是误差容限。在计算错误的情况下,你增加了额外的安全网。保证金计算率越高,你越厌恶风险,反之亦然。

Discount and Margin Calculation Rate at 15% for both

dfprice['peratio'] = findMinimumEPS(stockpricedf,financialreportingdf)

dfprice['FV'] = dfprice['futureeps']*dfprice['peratio']

dfprice['PV'] = abs(np.pv(discountrate,years,0,fv=dfprice['FV']))
dfprice['marginprice'] = dfprice['PV']*(1-marginrate)
dfprice['lastshareprice']=stockpricedf.Close.tail(1).values[0]

dfprice['decision'] = np.where((dfprice['lastshareprice']<dfprice['marginprice']),'BUY','SELL')

这将生成包含以下数据和决策(买入/卖出)的数据框架

Future Price and Decision Making Calculation

在这种情况下,基于每股收益增长和市盈率,你可以找到未来价格和当前价格的估值。加上折扣率和利润率,你会得到边际价格。由于保证金价格低于上一次股价,我们可以假设股票目前被高估,即使给定容许误差率。因此做出了卖出的决定。相反的还为购买的决定效力

这是一个非常简单的逻辑,但却是你购买股票的有力杠杆。当然,需要注意的是,在购买股票之前,你应该对定性分析进行尽职调查。

结果

开发完这个工具后,我觉得有必要测试一下。因此,在 2017 年,我决定利用这个工具的筛选来购买一些股票。

购买斯凯奇

Skechers View from Value Investing Dashboard

正如您在此处看到的,该应用程序将 Skechers 标记为异常高的边缘化价格。这意味着给定 10%的贴现率假设(来自经济不稳定或通货膨胀)和 50%的边际利率假设(来自潜在误差程度),我们仍然认为边际股价非常高——我们的估价。

对每股收益增长的进一步了解显示了斯凯奇从 2012 年到 2016 年的快速增长。然而,与此同时,如果你查看长期债务比率,斯凯奇的债务已经减少或稳定。总的来说,增加收入、高增长和低长期债务是我购买斯凯奇的最大原因之一。在一年半的时间里,我的股票价格上涨了 34.55%

购买高通

2017 年,我收到了高通与苹果公司发生纠纷的消息。这使得股票下跌到 44。因此,我尝试使用这个工具来看看我是否能快速提取信息并进行定量分析。快速看了一眼后,我意识到,考虑到市盈率和年增长率,高通给了我很高的未来价值 115 美元。即使我把 50%作为利润率(我是一个非常厌恶风险的人),我可以看到边际价格仍然远远高于目前的股价。由于除了一年的负增长,没有太多的预警信号和长期债务的增加,我买了高通。在一年半的时间里,我的股票价格上涨了 62.87%。

购买 Gamestop

Gamestop 是我用价值投资仪表板做的最新投资。这被认为是一种烟头投资,因为这是一种没有投资者想要的增长下降的股票,因此,烟头(明白吗?!哈哈)。在警告信号中,出现了三个警告:负增长,长期债务高,净资产收益率低。然而,如果你看一看底部的决定:应用程序将它标注为购买。原因是尽管股票随着负增长而下跌,但市场对股票的估价太低:人们太害怕投资 GameStop。生意下降的速度低于市场情绪下降的速度。正如你所看到的,即使当我把利润率设为 50%时,我仍然看到利润价格(13 美元)高于股价(8 美元)。出于这个原因,我买了 Gamestop,希望投资者能意识到这一差距,同时也希望收购。到现在为止,我亏了 7.58%。

持有 18%的投资组合回报

使用这个应用程序,我首先筛选、购买和持有股票。目前,我成功购买的公司包括:DC 吉宝房地产投资信托公司、CSE 全球有限公司、高通和斯凯奇。一些经过筛选的股票,如斯凯奇和高通是迄今为止表现最好的股票。

Results: Stocks Portfolio Gain by 18.53% since 2017

正如你所看到的,我目前管理的工作投资组合在持有一年半后产生了 18%的最新回报率。如果包括股息,那么回报率估计为 22%。虽然这是一年后的巨大回报,但这仍然不足以证明这款应用的有用性。请随意尝试,并在下面发表评论。

此外,我想进一步强调重要的警告:做你的尽职调查。

你仍然应该通过询问以下定性评估来评估你的股票:

业务优势(产品差异化、品牌、低价生产商、高转换成本、法律准入壁垒)

有勇无谋的管理能力(即使傻瓜也会跑)

避免价格竞争的业务。了解企业如何创收。

最后,我希望这个应用程序或者至少是我投资旅程中的一小段能激发你的创新。请随意查阅这些代码,以便更好地理解我是如何处理这些数字来得出买入/卖出行为的。然后,如果您想进一步改进,请随意发表意见。

一切都是免费的!!请做出贡献,使其成为最好的开源价值投资工具。

结论和未来工作

这个项目给了我解决一个实际相关问题的机会,我的许多金融朋友似乎都面临着这个问题。我们可以添加许多功能来改善用户体验,但目前,该应用程序已经成功地处理了前面提到的核心问题,即提取相关的财务比率和信息以进行初步的股票筛选。

从这个项目中,我还学到了许多基本的金融理论,我可以用这些理论来评估股票。我不是金融专家,我打赌你可能比我更清楚。因此,请随意改进您认为合适的解决方案。如果你想打个招呼或者进行一次轻松的讨论,我的联系方式如下:)

感谢

我想感谢我的会计和金融同行朋友们,是他们启发我开发了这个工具。我真的很喜欢从他们那里学到一堆金融术语,并用它们来解决他们遇到的现实生活中的问题。

最后…

咻…就是这样,关于我的想法,我把它写成了文字。我真的希望这对你们来说是一个伟大的阅读。因此,我希望我的想法可以成为你发展和创新的灵感来源。

请通过我的 LinkedIn 联系我,并订阅我的 Youtube 频道

请在下面留言,寻求建议和反馈。

快乐编码:)

温哥华的数据科学家市场

原文:https://towardsdatascience.com/vancouvers-data-scientist-market-24c43307d784?source=collection_archive---------10-----------------------

在温哥华做一名数据科学家需要什么?

Credit: David G Gordon (2015)

我最近读了哈尼夫·萨马德的一篇文章,他在文章中颠倒了他的招聘问题。他想知道新加坡的数据科学家在被聘用到目前的职位之前做了什么,而不是寻找公司在招聘信息中想要的内容?作为一个希望进入这一领域的人,我有兴趣回到我居住的城市温哥华的公司今天正在寻找他们的数据科学家的基本情况。

我有两个原因:1)我将很快在温哥华寻找数据科学家的职位(自私的原因);2)我目前是 UBC 数据科学硕士项目(利他主义原因)的助教。因此,我想看看哪些职位最符合我目前的知识和技能,以及基于平均水平的数据科学家工作,我目前的差距是什么?而且,我想帮助这些学生准备他们的项目,为他们毕业时找到一份好工作做好准备。

为此,我求助于 LinkedIn。我想查看温哥华的所有职位,而不是单独查看每个职位或其中的一个样本。所以,我转向了 LinkedIn 的网页抓取。

网页抓取 LinkedIn

正如 Hanif 提到的,LinkedIn 抓取网页的合法性目前还没有得到证实(尽管这可能只是改变了!).招聘启事都是公开的(毕竟他们正在试图雇佣某人),但是在他们的网站上使用抓取程序会让你违反他们的服务条款。如果您试图修改或复制此代码,请谨慎操作。为此,我同时使用了硒和 BeautifulSoup。完整代码见 Github 库

1。编制所有相关公告的列表

截至发稿时,有 133 个帖子符合我的标准。LinkedIn 实际上会根据浏览器显示不同的网页设置。Chrome 有一个无限滚动的按钮,可以显示更多帖子。加载页面后,我设置它多次点击那个按钮,直到它不出现。然后,所有的链接都在边上

2。刮掉每张帖子

这一部分包括检查一个示例工作发布的 html,以获得正确的 HTML 标签。职位存储在 h1 下,公司存储在 class _ nametop card _ _ org-name-link下,大部分信息存储在 class _ name“description下。我将这些都存储在一个字典中,并在访问下一页之前将其添加到一个列表中。

3。一起清理和编译数据

这是一个痛苦的部分,需要大量的试验和错误。最后,我通过搜索下一个文本元素是列表开头的字符串,让它工作起来,这在招聘信息中很常见。大多数都有 1-3 个部分,我将其归类为“需求”、“资产”和“责任”。需求和资产之间的分离对于填补您需要的空白以及看到什么可以让您与众不同是很重要的。

然后,我在每个职位描述部分搜索关键词。我基于我以前的知识会很重要,或者通过浏览一些帖子(例如,我最初不打算包括 C++,但它出现在亚马逊的一份工作的摘录中,所以我想知道这有多普遍)。我还必须对一些关键词进行创新,以获得正确的用法(例如,“MS”通常被用作科学硕士的简写,但也是许多复数词的结尾,如“programs”、“aims”和“teams”)。).

Example of Amazon job posting with two sections (‘requirements’ and ‘assets’).

现在数据已经清理完毕,我们可以看看我们发现了什么。

发现 1:研究生教育很普遍

在近 50 个帖子中出现了某种形式的大学教育,其中 33 个提到了研究生教育的要求(硕士或博士)。这些教育要求中的大部分都列在“要求”部分,专业或专业通常作为资产包括在内。

这些数字确实显示了这种教育在数据科学这样一个新领域的负面影响。大学和学院中的数据科学学位课程开始越来越多,显然有大量涵盖类似内容的训练营和在线课程。许多工作甚至没有将学士学位列为要求,这可能表明他们对你在这个特定领域的知识更感兴趣,而不需要学位来支持。

发现 2: SQL 至高无上

SQL 是所有招聘信息中最常被提及的语言(64;需求和资产一起)。Python 紧随其后(54),R 远远落后(19)。其他编程语言也出现了,但可能是在需要高性能 C++代码的更特殊的位置。

Jim Halpert obviously saw the dominance of SQL coming.

除了一些主要的编程语言,一些软件和服务也出现在很多帖子中。Spark 位居榜首,Tableau 紧随其后,两者都出现了两次以上。

发现 3:利基工作的利基知识

数据科学家训练营和课程强调的一些事情只出现在少数帖子中。神经网络(包括 CNN 和 RNN)只在 4 篇文章中明确列出。自然语言处理(NLP)只在 9 中列出。如果这些是你真正想进入的领域,这些专业的数据科学家职位显然需要它们,但似乎大多数职位招聘的是更“通才”的数据科学家职位。(有关这方面的更多信息,请查看我喜欢的关于数据科学中专家与通才辩论主题的播客片段

Definitions: RNN: NLP: Natural language processing; Recurrent neural network; CNN: Convolutional neural network.

虽然这并不是贬低这些方法的有用性,也不是说它们可能会在面试中出现,但这并不是公司在发布大部分帖子时的首选。

发现 4:不仅仅是技术

知识就是力量。数据科学家的工作也不例外。虽然你可能需要进行分析,但很多工作也希望你了解分析背后的理论,以确保你在适当的时候应用了正确的方法和技术。

整体

我很有兴趣看看数据科学工作(在温哥华,BC)的总体情况。这些发现可能并不太令人惊讶,但它确实展示了整体情况,以及你可能需要填补知识空白的地方,以便为就业市场做好准备。

我错过了什么你感兴趣的吗?下面评论,给我发消息或者随意自己探索这里

注意事项

  1. 代码可以在另一个城市复制,或者在这里深入研究。

使用套索的可变选择

原文:https://towardsdatascience.com/variable-selection-using-lasso-493ac2e5660d?source=collection_archive---------14-----------------------

Photo by Priscilla Du Preez on Unsplash

这是套索;它被用来挑选和捕捉动物。作为一个非英语母语的人,我第一次接触这个词是在监督学习中。在本 Lasso 数据科学教程中,我们将通过逐步介绍如何将这种有用的统计方法应用于 R 中的分类问题,以及 Lasso 如何“类似地”用于挑选和选择与当前分类问题相关的输入变量,来讨论 LASSO 逻辑回归的优势。

数据分析师和数据科学家针对不同类型的分析问题使用不同的回归方法。从最简单的到最复杂的。人们谈论最多的方法之一是套索。Lasso 经常被描述为最有用的线性回归工具之一,我们即将找到原因。

Lasso 其实是“最小绝对收缩与选择算子”的缩写,基本概括了 LASSO 回归的工作原理。Lasso 使用收缩参数“数据收缩到某个中心点”1进行回归分析,并通过惩罚强制“不太重要”变量的系数变为零来执行变量选择。

现在,为了更好地了解这个强大的工具,我们将把这个例子应用到一个现实世界的问题中。

我们从 Kaggle.com[2获得了一些乳腺癌诊断病例的数据。这将用于整个演示过程。该数据集包含乳腺肿块的细针抽吸(FNA)的数字化图像中存在的细胞核的特征。我们正在解决的问题是确定乳房肿块的物理特征,这些特征显著地告诉我们它是良性的还是恶性的。

准备数据

我们将数据分为训练集和测试集。

训练模型

在训练训练集之后,我们使用交叉验证来确定最佳的 lambda。

预测

我们预测测试集的响应变量,然后,查看混淆矩阵。

检查性能

我们比较了响应集的实际值和预测值。

为了比较,我们也将使用普通的最小二乘法来解决相同的问题,然后比较它们的结果。

训练模型

预测

检查性能

现在,比较两种方法的准确性,Lasso 得到 166/171 的正确预测,给出 97.01%的准确性,而普通最小二乘法得到 162/171 的正确预测,给出 94.74%。然而,由于良性到恶性病例的分布,我们期待这种性能,让我们看看两个模型的 F1。这是为了同等重视假阳性(或非恶性病例被归类为恶性)和假阴性(或恶性病例被归类为非恶性)的数量,因为它们在我们的癌症问题中都很重要。我们希望尽可能地减少错误分类,因为分类决定了应该为患者提供什么样的具体护理或健康措施。看看 F1,Lasso 给出了 97.70%,而普通最小二乘法给出了 95.90%。同样,套索优于最小二乘法。

看起来这两者的性能几乎相同,我们可以使用其中任何一个来解决这个特定的问题。然而,如果我们深入研究模型的样子以及它们是如何形成的,我们可以很容易地看出这两种方法之间的显著差异。

检查 OLS 模型时,数据集中的所有输入变量都在模型中考虑。系数请参考下图。

现在,看看套索模型,我们会注意到模型中考虑的变量很少(只有 11/30 的自变量)。其余的被忽略或被模型视为在因变量的结果中不重要。然而,该模型的准确性在 97%左右,高于考虑所有自变量的模型。请参考该型号的下图。

我们发现,平均纹理、平均凹点、平均分形维数、半径的标准误差、分形维数的标准误差、最差半径、最差纹理、最差平滑度、最差凹度、最差凹点和最差对称性共同强烈地识别乳房块中的细胞核是良性还是恶性。

以上告诉我们的是,有时,有必要放弃使模型不稳定的其他变量。因为这些有噪声的/不相关的变量促使模型去适应噪声,也称为过适应。

让我们看看套索的显著特征,为什么它在这个特定的案例中比 OLS 更好。正如一开始提到的,LASSO 的一个重要特征是可变选择。Lasso 只选择模型中的重要变量。如果我们仔细观察现有的数据,我们会注意到有很多预测因素,一些独立变量实际上是相互关联的,或者我们可以将它们分组。这实际上已经给了我们一个暗示,可能有必要删除一些变量。

因此,获得预测更容易,因为我们在推断过程中需要准备的特征更少。不像在 OLS,我们必须输入数据集中的所有值才能获得响应值。

最后,让我们概括一下套索的重要特征。Lasso 是一种监督算法,其中该过程识别与响应变量密切相关的变量。这叫做变量选择。然后,Lasso 迫使变量的系数趋向于零。这就是现在收缩的过程。这是为了使模型对新数据集不那么敏感。由于选择的输入变量较少,这些过程有助于缓解人类认知的局限性。

如果你想了解更多关于 Lasso 回归的知识,我推荐你参加 Coursera [ 3 ]的课程,或者通读一下这篇[ 4

帖子到此为止。我们很想听听你对这些文章和其他相关数据的看法。SpectData 是一家精品数据科学咨询公司,擅长人工智能和自然语言处理。本文由我们的数据科学家 Marriane M。

原载于 2019 年 8 月 7 日http://www.spectdata.com

变量类型和示例

原文:https://towardsdatascience.com/variable-types-and-examples-5e575af69eb7?source=collection_archive---------41-----------------------

通过具体的例子学习定量(连续和离散)和定性(顺序和名义)变量之间的区别

Photo by Mika Baumeister

介绍

如果你碰巧经常使用数据集,你可能知道数据集的每一行代表一个不同的实验单元(也称为观察),每一列代表一个不同的特征(称为变量)。

例如,如果您对您所在大学的 100 名学生的体重和身高进行研究,您很可能会有一个包含 100 行和 3 列的数据集:

  1. 一个用于学生的身份识别(可以匿名也可以不匿名),
  2. 一个代表重量,
  3. 一个是身高。

这三列代表了 100 名学生的三个特征。它们被称为变量

在本文中,我们将关注变量,尤其是统计中存在的不同类型的变量。

不同类型的变量用于不同类型的统计分析

首先,有人可能想知道为什么我们对定义我们感兴趣的变量的类型感兴趣。

我们经常将变量分为不同类型的原因是因为不是所有的统计分析都可以在所有的变量类型上进行。例如,不可能计算变量“头发颜色”的平均值,因为你不能将棕色和金色头发相加。

另一方面,寻找连续变量的模式实际上没有任何意义,因为大多数时候不会有两个完全相同的值,所以不会有模式。即使在有一个模式的情况下,这个值的观测值也很少。举个例子,试着找出你们班学生身高的模式。如果你幸运的话,几个学生会有同样的尺寸。然而,大多数时候,每个学生都有不同的尺寸(特别是如果身高是以毫米为单位的话),因此没有模式。要查看每种类型变量的可能分析,请参阅文章“手动描述性统计”和“R 中的描述性统计”中的更多详细信息。

类似地,一些统计测试只能在特定类型的变量上进行。例如,皮尔逊相关性通常是根据定量变量计算的,而独立性卡方检验是根据定性变量进行的,而学生 t 检验方差分析需要混合定量和定性变量。

特种宽银幕电影

在统计学中,变量分为 4 种不同的类型:

Image by author

数量的

一个数量变量是一个反映数量概念的变量,也就是说,如果它可以取的值是数字。因此,数量变量代表一种度量,并且是数字的。

定量变量分为两种:离散型连续型。这种差异将在以下两节中解释。

分离的

定量离散变量是其取值为可数且有有限个可能性的变量。这些值通常(但不总是)是整数。以下是一些离散变量的例子:

  • 每个家庭的孩子数量
  • 一个班的学生人数
  • 一个国家的公民人数

即使统计一个大国的公民人数需要很长时间,但在技术上还是可行的。而且,对于所有的例子,可能性的数量都是有限的。无论一个家庭有多少个孩子,都不会是 3.58 或 7.912,所以可能性的数量是有限的,因此是可数的。

连续的

另一方面,定量连续变量是其值不可数的变量,并且具有无限多种可能性。例如:

  • 年龄
  • 重量
  • 高度

为了简单起见,我们通常用年、千克(或磅)和厘米(或英尺和英寸)分别代表年龄、体重和身高。然而,一个 28 岁的男人实际上可能是 28 岁 7 个月 16 天 3 小时 4 分 5 秒 31 毫秒 9 纳秒。

对于所有的测量,我们通常在一个标准的粒度级别停止,但是没有什么(除了我们的测量工具)阻止我们更深入,导致无限数量的潜在值。事实上,值可以采取无限多的可能性,使它不可数。

定性的

与定量变量相反,定性变量(也称为分类变量或 R 中的因子)是而非数值的变量,其值属于类别

换句话说,定性变量是一个以模态、类别或甚至水平为其取值的变量,与测量每个个体的数量定量变量相反。

定性变量分为两种:名义序数

名义上的

定性标称变量是一个定性变量,其中没有排序是可能的或隐含在级别中。

例如,变量性别是名义上的,因为在级别中没有顺序(无论你为性别考虑多少级别——只有两个是女性/男性,或者两个以上是女性/男性/其他,级别都是 un ordered)。眼睛颜色是名义变量的另一个例子,因为蓝色、棕色或绿色眼睛之间没有顺序。

名义变量可以有:

  • 两个层次(例如,你吸烟吗?是/不是,还是你怀孕了?是/否),或者
  • 大量的水平(你的大学专业是什么?每个专业在那种情况下都是一个级别)。

请注意,正好具有两个级别的定性变量也被称为二元二元变量。

序数

另一方面,一个定性序数变量是一个具有隐含在等级中的顺序的定性变量。例如,如果道路交通事故的严重程度是按轻度、中度和致命事故的等级来衡量的,那么这个变量就是一个定性的顺序变量,因为在等级中有一个明确的顺序。

另一个很好的例子是健康,它可以取值为差、合理、好或优秀。同样,这些级别有明确的顺序,所以在这种情况下,健康是一个定性的序数变量。

变量转换

有两种主要的变量转换:

  1. 从连续变量到离散变量
  2. 从量变到质变

从连续到离散

假设我们对婴儿的年龄感兴趣。收集的数据是婴儿的年龄,因此是一个定量的连续变量。然而,我们可能只处理出生后的周数,从而将年龄转换为离散变量。年龄变量仍然是一个定量的连续变量,但我们正在研究的变量(即出生后的周数)是一个定量的离散变量。

从量变到质变

假设我们对身体质量指数(身体质量指数)感兴趣。为此,研究人员收集了个人身高和体重的数据,并计算出身体质量指数。身体质量指数是一个定量的连续变量,但研究人员可能希望将其转化为定性变量,方法是将低于某个阈值的人归类为体重不足,高于某个阈值的人归类为超重,其余的人归类为正常体重。原始身体质量指数是一个定量的连续变量,但身体质量指数的分类使转换后的变量成为一个定性(顺序)变量,在这种情况下,其水平是权重不足的< normal < overweighted.

Same goes for age when age is transformed to a qualitative ordinal variable with levels such as minors, adults and seniors. It is also often the case (especially in surveys) that the variable salary (quantitative continuous) is transformed into a qualitative ordinal variable with different range of salaries (e.g., < 1000€, 1000–2000€, > 2000€)。

关于误导性数据编码的附加说明

最后但并非最不重要的是,在数据集中,数字经常用于定性变量。例如,研究人员可能会将数字“1”分配给女性,将数字“2”分配给男性(或者将答案“否”分配为“0”,将答案“是”分配为“1”)。尽管进行了数字分类,性别变量仍然是一个定性变量,而不是看上去的离散变量。数字分类仅用于方便数据收集和数据管理。写数字“1”或“2”确实比写“女性”或“男性”更容易,因此不容易出现编码错误。

这同样适用于每个观察的识别。假设你收集了 100 名学生的信息。您可以使用他们的学生证在数据集中识别他们(以便您可以追溯他们)。大多数情况下,学生的 ID(或一般的 ID)被编码为数值。乍一看,它可能看起来像一个数量变量。然而,ID 显然不是一个数量变量,因为它实际上对应于学生的名字和姓氏的匿名版本。仔细想想,在 IDs 上计算平均值或中值是没有意义的,因为它确实代表了一种度量(而只是一种识别学生的简单方法)。

如果您面临这种设置,不要忘记在执行任何统计分析之前将变量转换成正确的类型。通常,在主要统计分析之前,一个基本的描述性分析(以及关于已测量变量的知识)足以检查所有变量类型是否正确。

感谢阅读。我希望这篇文章能帮助你理解不同类型的变量。如果您想了解 R 中不同数据类型的更多信息,请阅读文章“R中的数据类型”。

和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。

相关文章

原载于 2019 年 12 月 30 日https://statsandr.com

变量类型和示例

原文:https://towardsdatascience.com/variable-types-and-examples-cf436acaf769?source=collection_archive---------24-----------------------

通过具体的例子学习定量连续变量、定量离散变量、定性序数变量和定性名义变量之间的区别

特种宽银幕电影

在统计学中,变量分为 4 种不同的类型:

Types of variables

数量的

一个数量变量是一个反映大小概念的变量,也就是说,如果它可以取的值是数字。因此,数量变量代表一种度量,并且是数字的。

定量变量分为两种:离散连续。这种差异将在以下两节中解释。

分离的

定量离散变量是其取值为可数且有有限个可能性的变量。这些值通常(但不总是)是整数。以下是一些离散变量的例子:

  • 每个家庭的孩子数量
  • 一个班的学生人数
  • 一个国家的公民人数

即使统计一个大国的公民人数需要很长时间,但在技术上还是可行的。而且,对于所有的例子,可能性的数量都是有限的。无论一个家庭有多少个孩子,都不会是 3.58 或 7.912,所以可能性的数量是有限的,因此是可数的。

连续的

另一方面,定量连续变量是其值不可数并具有无限种可能性的变量。例如:

  • 年龄
  • 重量
  • 高度

为了简单起见,我们通常用年、千克(或磅)和厘米(或英尺和英寸)分别代表年龄、体重和身高。然而,一个 28 岁的男人实际上可能是 28 岁 7 个月 16 天 3 小时 4 分 5 秒 31 毫秒 9 纳秒。

对于所有的测量,我们通常在一个标准的粒度级别停止,但是没有什么(除了我们的测量工具)阻止我们更深入,导致无限数量的潜在值。事实上,值可以采取无限多的可能性,使它不可数。

定性的

与定量变量相反,定性变量(也称为分类变量或 R 中的因子)是而非数值的变量,其值属于类别

换句话说,一个定性变量是一个以模态、类别甚至水平为其取值的变量,与测量每个个体的数量定量变量相反。

定性变量分为两种:标称序数

名义上的

定性标称变量是一个定性变量,其中不可能排序或在等级中没有暗示。例如,变量性别是名义上的,因为在女性/男性级别中没有顺序。眼睛颜色是名义变量的另一个例子,因为蓝色、棕色或绿色眼睛之间没有顺序。

一个名义变量可以有两个级别(例如,你吸烟吗?是/否或者你的性别是什么?女/男)和一大批水平(你大学专业是什么?每个专业在那种情况下都是一个级别)。

序数

另一方面,定性序数变量是具有隐含在等级中的顺序的定性变量。例如,如果道路交通事故的严重程度是按轻度、中度和致命事故的等级来衡量的,那么这个变量就是一个定性的顺序变量,因为在等级中有一个明确的顺序。

另一个很好的例子是健康,它可以取值为差、合理、好或优秀。同样,这些级别有明确的顺序,所以在这种情况下,健康是一个定性的序数变量。

变量转换

有两种主要的变量转换:

  1. 从连续变量到离散变量
  2. 从量变到质变

从连续到离散

假设我们对婴儿的年龄感兴趣。收集的数据是婴儿的年龄,因此是一个定量的连续变量。然而,我们可能只处理出生后的周数,从而将年龄转换为离散变量。年龄变量仍然是一个定量的连续变量,但我们正在研究的变量(即出生后的周数)是一个定量的离散变量。

从量变到质变

假设我们对身体质量指数(身体质量指数)感兴趣。为此,研究人员收集了个人身高和体重的数据,并计算出身体质量指数。身体质量指数是一个定量的连续变量,但研究人员可能希望将其转化为定性变量,方法是将低于某个阈值的人归类为体重不足,高于某个阈值的人归类为超重,其余的人归类为正常体重。原始身体质量指数是一个定量的连续变量,但身体质量指数的分类使转换变量成为一个定性(顺序)变量,在这种情况下,其水平为体重不足

当年龄被转换成一个定性的顺序变量时,年龄也是如此,包括未成年人、成年人和老年人。通常情况下(尤其是在调查中),可变工资(定量连续)被转换为具有不同工资范围的定性有序变量(例如,< 1000€, 1000–2000€, > 2000€)。

附加注释

不同类型的变量用于不同类型的统计分析

我们经常将变量分为不同类型的原因是因为不是所有的统计分析都可以在所有的变量类型上进行。例如,不可能计算变量“头发颜色”的平均值,因为你不能将棕色和金色头发相加。

另一方面,寻找连续变量的模式实际上没有任何意义,因为大多数时候不会有两个完全相同的值,所以没有模式。即使在有一个模式的情况下,这个值的观测值也很少。举个例子,试着找出你们班学生身高的模式。如果你幸运的话,几个学生会有同样的尺寸。然而,大多数时候,每个学生都有不同的尺寸(特别是如果身高是以毫米为单位的话),因此没有模式。要查看每种类型变量的可能分析,请参阅文章“手工描述性统计”和“R中的描述性统计”中的更多详细信息。

类似地,一些统计测试只能在特定类型的变量上进行。例如,相关性只能对定量变量进行计算,而独立性卡方检验是对定性变量进行的,而学生 t 检验方差分析需要混合定量和定性变量。

误导性数据编码

最后但并非最不重要的是,在数据集中,数字经常用于定性变量。例如,研究人员可能会将数字“1”分配给女性,将数字“2”分配给男性(或者将答案“否”分配为“0”,将答案“是”分配为“1”)。尽管进行了数字分类,性别变量仍然是一个定性变量,而不是看上去的离散变量。数字分类仅用于方便数据收集和数据管理。写数字“1”或“2”确实比写“女性”或“男性”更容易,因此不容易出现编码错误。

如果您面临这种设置,不要忘记在执行任何统计分析之前将变量转换成正确的类型。通常,在主要统计分析之前,一个基本的描述性分析(以及关于已测量变量的知识)足以检查所有变量类型是否正确。

感谢阅读。我希望这篇文章能帮助你理解不同类型的变量。如果您想了解 R 中不同数据类型的更多信息,请阅读文章“R中的数据类型”。

和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。

相关文章

原载于 2019 年 12 月 30 日【https://statsandr.com】

金融中的变分自动编码器

原文:https://towardsdatascience.com/variational-autoencoder-in-finance-53ee5eb9ed98?source=collection_archive---------7-----------------------

金融时间序列的降维与指数构建

本文通过 Keras 和 Python 探讨了使用可变自动编码器来降低金融时间序列的维数。我们将进一步检测不同市场中金融工具之间的相似性,并将使用获得的结果来构建自定义指数。

免责声明:本文介绍的研究来自我们在多伦多大学继续教育学院的深度学习课程的 2019 年冬季学期项目。这是与温贝托·里贝罗·德·索萨合作完成的。概念和想法是我们自己的。我们绝不代表我们现在或以前的雇主。

第 1 部分:使用变分自动编码器降维

在本节中,我们将讨论:

  • 创建几何移动平均数据集
  • 用随机模拟扩充数据
  • 建立变分自动编码器模型
  • 获得预测。

创建几何移动平均数据集

为了比较不同价格范围的时间序列,我们选择计算收益的几何移动平均时间序列,定义如下:

我们选择了 d=5 ,因为它代表了 5 个工作日的典型交易周。

本文使用的数据集包含 2016 年 1 月 4 日至 2019 年 3 月 1 日期间的 423 个几何移动平均时间序列。

读者可以按照数据处理笔记本中描述的步骤构建自己的数据集。应该和这个差不多:

可以通过绘制一些样本股票价格时间序列及其几何移动平均线来验证结果:

然后,可以将刚刚构建的数据帧分成两个长度相等的时间段,只将第一个时间段的数据帧进行置换。周期 1 从 2016 年 1 月 12 日到 2017 年 8 月 4 日。周期 2,从 2017 年 8 月 7 日至 2019 年 3 月 1 日。

我们将仅使用周期 1 的数据来获得预测。

# Divide in two
geoMA_5d_stocks_p1 = geoMA_5d_stocks.head(int(len(geoMA_5d_stocks)/2))
geoMA_5d_stocks_p2 = geoMA_5d_stocks.tail(int(len(geoMA_5d_stocks)/2))# Transpose the dataframe for period 1
geoMA_5d_stocks_p1_T = geoMA_5d_stocks_p1.T

我们转置数据帧,以便每行代表给定股票的时间序列:

用随机模拟增加数据

我们将使用随机模拟来生成合成的几何移动平均线。目标不是精确地模拟回报,而是获得与真实数据行为相似的曲线。通过仅用模拟曲线训练模型,我们可以保留真实数据来获得预测。

使用几何布朗运动生成合成曲线。我们遵循以下步骤:

  • 使用第一期数据框架,随机选择 100 个分笔成交点
  • 对于每个选定的报价器,计算一个对数回报向量,如下所示:

  • 然后,对于选择的每个股票,我们将生成 100 条路径,这样:

以下是模拟曲线和真实曲线的示例:

我们将 423 个时间序列的数据集扩展为 100*100 = 10,000 个与股票数据集相似(但不相等)的新时间序列。

这将允许我们保留实际的股票数据集用于预测,甚至不必使用它进行验证。

在建立 VAE 模型之前,创建训练集和测试集(使用 80%-20%的比率):

# Shuffle the generated curves
shuffled_array = np.random.permutation(sim_paths_matrix)# Split the simulated time series into a training and test set
x_train = shuffled_array[0:8000]
x_test = shuffled_array[8000:]

读者还应该注意,在训练模型之前,不需要删除时间序列的季节性和趋势。

建立变分自动编码器(VAE)模型

我们将使用变分自动编码器将具有 388 个项目的时间序列向量的维度降低到二维点。

自动编码器是用于压缩数据的无监督算法。它们由一个编码器、一个解码器和一个损失函数构成,以测量压缩和解压缩数据表示之间的信息损失。

我们的目标不是再写一篇关于 autoencoder 的文章。不熟悉自动编码器的读者可以在 Keras 博客自动编码变分贝叶斯论文上阅读更多,作者是 Diederik Kingma 和 Max Welling。

我们将使用一个简单的 VAE 架构,类似于 Keras 博客中描述的架构。

编码器型号具有:

  1. 一个长度为 388 的输入向量
  2. 一个长度为 300 的中间层,具有整流线性单元(ReLu)激活功能
  3. 一个二维编码器。

Encoder Model Summary

解码后的模型具有:

  1. 一个二维输入向量(从潜在变量中取样)
  2. 一个长度为 300 的中间层,具有整流线性单元(ReLu)激活功能
  3. 具有 sigmoid 激活函数的长度为 388 的解码向量。

Decoder Model Summary

以下代码改编自 Keras team Github 上的variable _ auto encoder . py。它用于构建和训练 VAE 模型。

训练后,我们绘制训练和验证损失曲线:

获得预测

我们将只使用编码器来获得预测。我们将使用一个实值矩阵,包括股票数据集和一个或多个感兴趣的时间序列。

在我们的项目中,我们针对在另一个国家以不同货币上市的近月期货合约测试了一个股票数据集。

# Obtaining the predictions:
encoded_p1 = encoder.predict(matrix_to_test_p1, batch_size=batch_size)# Convert the predictions into a dataframe
encoded_p1_df = pd.DataFrame(data = encoded_p1, columns = ['x','y'], index = dataframe_to_test_p1.T.index)

我们获得了以下结果:

在绘制结果之前,我们必须:

  1. 计算期货合约点和数据框架中所有其他股票之间的距离
  2. 选择最接近期货合约的 50 品脱
# Calculate the distances between the futures contract point and all other points in the stocks datasetref_point = encoded_p1_df.loc['Futures'].values
encoded_p1_df['Distance'] = scipy.spatial.distance.cdist([ref_point], encoded_p1_df, metric='euclidean')[0]# Get the 50 closest points:
closest_points = encoded_p1_df.sort_values('Distance', ascending = True)
closest_points_top50 = closest_points.head(51)[1:] #We take head(51), because the Futures reference point is the first entry
closest_points_top50['Ticker'] = closest_points_top50.index

现在,我们可以绘制所获得的结果,以直观显示最接近的 50 只股票:

我们已经对另一个国家上市的期货合约进行了分析。然而,对于来自同一交易所的股票,可以遵循第 1 部分中的相同步骤。

第 2 部分:索引构建

让我们使用第 1 部分中获得的结果来创建一个索引。

由于 VAE 模型的随机性,我们不会在每次运行中获得相同的前 50 名股票的精确列表。为了获得最接近的 50 个点的公平表示,我们将运行 VAE 模型 10 次(每次运行时重新初始化和重新训练它)。然后,我们将采用每次运行中找到的 50 个最近点来创建长度为 500 的数据帧closest _ points _ df

一旦建立了 最近点 _df 数据帧:

  1. 按距离对点进行排序
  2. 丢弃重复的代码,只保留第一个出现的代码
sorted_by_dist = results_df.sort_values('Distance', ascending = True)sorted_by_dist.drop_duplicates(subset='Ticker', keep='first', inplace = True)

删除重复的点后,我们将只保留 50 个最接近的点。

计算每只股票的权重

在指数构建中,股票权重是通过使用不同的方法计算的,如市场资本总额或股票价格。

相反,我们将计算每只股票的权重,这样最接近期货合约点的点将比远离期货合约点的点获得更高的权重。

对于非匿名的股票数据,在计算股票权重之前过滤 获得的结果非常重要。离群值应剔除,市值范围应细化。

# Calculate the weights
top50 = sorted_by_dist.head(50).copy() # Keep the closest 50 points
top50['Weight'] = (1/top50['Distance'])/np.sum(1/top50['Distance'])

Sample of weights calculated

计算每只股票的股数

计算完权重后,我们计算每只股票在我们的自定义指数中的股份数。我们需要:

  • 获取每只股票在 2016 年 1 月 4 日(周期 1 的第一天)的价格
  • 定义净资产金额
  • 计算股份的数量
#Get the stock prices on January 4th 2016jan4_2016_stockPrice = np.zeros(len(stock_data_top50.columns))
for i in range(len(jan4_2016_stockPrice)):
  if stock_data_top50.columns[i] == top50['Ticker'].iloc[i]:
    jan4_2016_stockPrice[i] = stock_data_top50[stock_data_top50.columns[i]].iloc[0]top50['Price Jan4_2016'] = jan4_2016_stockPrice

We add a column for the stock prices on January 4th, 2016

# We compute the number of sharesnet_assets = 10000000 # We chose net assets = 10 million (in the currency of the stock market)numShares = np.zeros(len(stock_data_top50.columns))
for i in range(len(jan4_2016_stockPrice)):
  if stock_data_top50.columns[i] == top50['Ticker'].iloc[i]:
    numShares[i] = int(net_assets*top50['Weight'].iloc[i]/top50['Price Jan4_2016'].iloc[i])

top50['numShares'] = numShares

We add a column for the number of shares

构建索引

为了构建该指数,我们将使用拉斯派尔斯指数计算如下:

stock_index = np.zeros(len(stock_data_top50))for i in range(len(stock_data_top50)):
  sum_num = 0
  sum_denom = 0
  for j in range(len(stock_data_top50.columns)):
    sum_num = sum_num + stock_data_top50[stock_data_top50.columns[j]].iloc[i]*top50['numShares'].iloc[j]
    sum_denom = sum_denom + stock_data_top50[stock_data_top50.columns[j]].iloc[0]*top50['numShares'].iloc[j]
  stock_index[i] = sum_num /sum_denom# We arbitrarily start the index at 100
stock_index_df = pd.DataFrame(stock_index*100, columns =  ['stock_index'], index = stock_data_top50.index)

我们绘制了自定义索引:

比较我们的定制指数和期货时间序列

我们必须缩放期货价格数据,以便将其绘制在与自定义指数相同的图表中。为此,我们必须:

  • 计算期货价格数据的每日百分比变化
  • 设置 S_0 = 100
# Calculate the percentage change
futures_data_stock_data_pct_change = futures_data_stock_data.pct_change()
futures_data_stock_data_pct_change.dropna(inplace = True)# Scale the time series
futures_theoretical = np.zeros(len(stock_index_df))
futures_theoretical[0] = stock_index_df.iloc[0]
for i in range(len(futures_theoretical)-1):
  futures_theoretical[i+1] = (1+futures_data_stock_data_pct_change.iloc[i])*futures_theoretical[i]

我们现在在同一张图中绘制两条曲线:

我们的指数除了 2018 年下半年之外,大部分趋势与参考期货时间序列相同。因为我们使用匿名数据,我们没有过滤股票的异常值和市值限制。此外,在观察到的两个时间段内没有重新平衡,我们忽略了分布。

如果识别出报价器并剔除异常值,自定义指数完全有可能跑赢期货指数。

我们鼓励我们的读者利用在线免费的 GPU 实例来创建他们自己的索引。这对我们来说是一个有趣的实验,我们发现了一些有趣的股票模式。

请随意下载 GitHub 上的两款笔记本:

  1. 3546 深度学习项目—数据处理. ipynb
  2. 3546 深度学习项目— VAE &索引构建. ipynb

结论

使用可变自动编码器可以加快外国股票市场新指数的开发,即使分析师对它们并不熟悉。此外,可以创建利基指数或投资组合来满足客户的兴趣。

虽然这种方法可以用来创建 ETF,但我们相信它也可以为全球的直接指数和 Robo Advisors 公司创造新的投资机会。

具有生成重放的变分连续学习

原文:https://towardsdatascience.com/variational-continual-learning-with-generative-replay-bfd43464d250?source=collection_archive---------24-----------------------

利用生成重放记忆进行持续学习的贝叶斯方法

介绍

这篇博客文章解释了由 Cuong V. Nguyen,Yingzhen Li,Thang D. Bui,Richard E. Turner 在 2018 年 ICLR 会议上发表的论文“不断变化的学习”中提出的方法。本文使用变分推理的贝叶斯方法来解决连续学习问题。在第二部分中,我们提出了 Y. Gal 和 S. Farquhar 提出的“变分生成重放”方法,扩展了第一篇文章。

1.持续学习模型旨在从输入的数据流中学习。数据不断到达,并且数据分布随时间而变化(非平稳性)。成功的持续学习可以处理两件事:

  • 应该从根据先前数据训练的先前模型执行迁移学习,以训练最新的模型
  • 避免灾难性的遗忘。即最终的模型在旧的任务上应该仍然表现良好。

2.贝叶斯方法是一种机器学习的概率方法,它将关于模型参数的先验知识形式化,并对模型权重的分布进行建模。

变分连续学习理论

一般来说,在机器学习中,根据概率将判别模型定义为:

其中 f 属于由θ参数化的一类函数。例如,前馈神经网络执行分类(softmax 作为最后一层,θ作为权重和偏差)。

经典的贝叶斯方法通过权重值的分布来对权重建模。它还使用贝叶斯规则来利用θ分布的先验信念。

在持续学习的框架中,一个自然的想法是将最后的后验概率视为新任务的θ的最佳先验分布(来自新分布的新一批数据)。事实上,我们注意到:

这是随时间推移的后验分布的递归公式。在前面的公式中,我们不关心通常难以处理的归一化因子的计算,因为我们要执行后验分布的近似。(因此有了比例符号)

在大多数情况下,后验分布是难以处理的。为了克服这个问题,我们可以用更简单的变分分布来近似后验分布

为了进行这种近似,我们考虑:

我们将通过一个更简单的分布来递归地近似后验概率:给定时间步长 t-1 的近似值,我们可以按照前面的公式计算时间步长 t 的近似值。这种方法叫做变分推理。我们正在寻找由一组参数(μVI,σVI)定义的近似分布(此处为高斯平均场),该分布与目标分布相匹配。通过拟合,我们意味着最小化两个分布之间的差异。通常,Kullback-Leibler 散度用于定义两个分布之间的差异。

Gaussian mean-field approximation

因此,为了找到近似的变分后验概率,我们最小化下面的 Kullback-Leibler 散度。

因此,我们将损失定义为:

KL 项可以解析地计算为两个高斯函数之间的 Kullback-Leibler 散度。利用蒙特卡罗方法和重新参数化技巧,我们可以很容易地估计出期望的对数似然性:

  • 假设很难评估期望值 E =Ex∾p【f(x)】人们可以通过采样 x1,x2,..xN∞p 并得到 E 的近似值:

This estimator is unbiased but to reduce variance, it is better to use high N

  • 从高斯分布中提取的θ的重新参数化技巧是独立于分布参数(μVI,σVI)重写θ的简单方法

因此,可以为可学习参数(μVI,σVI)计算损失函数的梯度,并且可以执行随机梯度下降。

为了在连续设置中改进学习,我们可以考虑多头架构。事实上,单头架构非常适合 i.i.d 实例或只有输入分布随时间变化的实例。多头架构能够利用任务之间的共享参数和为每个任务训练的特定头。

变分分布的递归近似可能影响模型性能,并触发灾难性遗忘。为了避免这种灾难性的遗忘,引入了核心集:训练数据的样本存储在核心集中(并从训练数据中移除),并用于在预测之前改进后验近似。可以选择不同的技术来选择训练批次的子集。随机抽样是最简单的选择。可以执行 k-均值聚类来保持训练数据的有意义的子集:质心被选择放入核心集中。理论上,我们注意到:

我们现在关注这个新的变分分布,它只在非核心集数据上训练。我们可以用类似的方式计算这些变分分布的递归公式:

事实上,在实现中,他们从不从核心集中删除任何点。因此,公式变得更简单:

有趣的是,与本文提出的理论相反,与本文相关的原始实现并不是在进行预测之前对整个核心集进行训练,而是只对与测试任务相对应的核心集子集进行训练。因此,这是一种最后一分钟的培训,在持续学习的框架内并不真正令人满意。

我们总结了变分连续学习算法:

变分生成重放

在之前的一篇论文《深度生成重放(DGR)》(Shin et al .,2017)中,作者以一种完全不同的方式解决了持续学习的问题。他们在每项任务上训练生成对抗网络(GAN ),以便能够使用生成的 GAN 输出来确保后一项符合前一项任务的对数似然性。这种思想,在接下来的段落中称为似然聚焦连续学习,可以集成到称为先验聚焦连续学习的变分连续学习中(因为它聚焦于先验变分近似)。这种混合方法在 S. Farquhar 和 Y. Gal 最近撰写的论文《连续学习的统一贝叶斯观点》[2019]中被称为变分生成重放。让我们回顾一下这些方法背后的理论:

以前为重点的持续学习:

这是在《不断变化的学习》一文中提出的方法。这种方法侧重于任务间的迁移学习,这要归功于先前对从先前任务中学习到的权重的信念。

它可以被解释为用概率分布加权的模型集合,该概率分布是从关于它的先验信念正则化的。时间步长 t 的先验置信是在时间步长 t-1 计算的后验置信。

注重可能性的持续学习:

这是深度生成重放(DGR)一文中提出的方法。这种方法试图确保后验概率符合所有以前看到的数据的可能性,使用以前任务中训练的 GANs 生成的数据。实际上,这个想法是要符合以下棘手的损失函数(因为我们不能直接访问以前看到的数据):

因此,进行了以下近似,为先前的任务引入了生成模型 pt′(x,y)

变化生成重放的连续学习;

这种方法是在《持续学习的统一贝叶斯观点》一文中发展起来的。它混合了以先验为重点的持续学习方法和以可能性为重点的持续学习方法:

基本上,变分生成重放在实现中取代了核心集,是一种新的记忆形式。

结论

总之,具有生成重放的变分连续学习是一种使用来自贝叶斯深度学习和生成对抗网络的工具来实现连续学习的新途径。它可以被看作是一种人类启发的方法,我们在以前的任务基础上建立的先验知识被用来执行新的任务。此外,深度生殖重播有时被比作梦,当人类提醒自己过去的行为以进一步学习时。然而,使用这种新方法,所需的内存随着任务的数量而线性增长,这对于一般的连续学习模型来说可能是不令人满意的。

代码可在https://github.com/pihey1995/VariationalContinualLearning获得

C.阮,李,裴东光,特纳。不断变化的学习。ICLR (2018 年)。

南法夸尔和 y .高尔。持续学习的统一贝叶斯观点(2019)。

韩 ul Shin、Jung Kwon Lee、Jaehong Kim、Jiwon Kim 深度生殖重播(DGR) (2017 年)

各种类型的卷积神经网络

原文:https://towardsdatascience.com/various-types-of-convolutional-neural-network-8b00c9a08a1b?source=collection_archive---------7-----------------------

该帖子将出现在 CNN 的各种类型上,在图像处理和物体识别的各个领域中成功设计并实现。如果你对卷积神经网络有所了解会更好。
你可能听说过 ImageNet 。这是一个大型的有组织的视觉图像数据库,供研究人员和开发人员用来训练他们的模型。现在,他们主办了一年一度的竞赛,名为 ImageNet 大规模视觉识别挑战赛(ILSVRC)——一场与大规模物体检测和图像分类相关的竞赛。一般来说,这场比赛中表现最好的选手能够在物体分类领域设定一个基准。这份各种建筑的列表,在他们的设计中是独一无二的,在这场竞赛中获得了最高的位置,并且正在成功地应用于各种任务中。
注意:除非另有说明,这些网络都实现了同填充,实质上保留了图像卷积后的原始大小。
让我们看看它们:

LeNet:

LeNet Architecture.

没有这一点,就不能开始讨论有线电视新闻网的架构。就对象分类而言,这是一个开创性的算法,是同类算法中的第一个,也是有能力的。最初接受 MNIST 数据集 0-9 手写数字分类的训练。它由 7 层组成,均由可训练参数组成。它采用 32 X 32 像素的图像,相对于训练网络的数据集内的图像,其尺寸相对较大。应用的激活功能为 RELU 功能。这些层按以下方式排列:

LeNet Architecture, but with more details.

  1. 第一卷积层6 个尺寸为5 X 5的滤波器和 1 个的步长组成。
  2. 第二层尺寸 2×2亚取样平均汇集层,2 的步距。
  3. 第三层也是卷积层,由 16 个 5×5尺寸的滤波器和1 步长的滤波器组成。
  4. 第四层同样是平均汇集层尺寸为 2×2跨距为 2。
  5. 第五层第四层 ( 400 参数)的输出连接到 120 节点的全连接层
  6. 第六层是一个类似的全连接层,由 84 个节点组成,从第五层的 120 个节点的输出中导出。
  7. 第七层(,或最后一层)包括将最后一层的输出分类成 10 类,与它最初被训练分类的 10 位数字相关。

它是当时实现的对手写数字进行分类的成功的数字识别算法之一。今天,在数据集上实现这种架构,使用各种库,可以获得大约 98.9 %的准确率。然而,当涉及到处理大尺寸图像和在大量类别的对象中进行分类时,该网络在计算成本或准确性方面不能有效地工作。

链接到论文。

AlexNet:

AlexNet Architecture

ImageNet ILSVRC-2012 竞赛的获胜者 AlexNet 由 Alex Krizhevsky、Ilya Sutskever 和 Geoffery E. Hinton 设计。它能够将前五名的错误率降低到 15.3 %** ,而该比赛亚军的错误率为 26.2%。该网络类似于 LeNet 架构,但与原始 LeNet 相比具有大量过滤器,因此能够在一大类对象中进行分类。此外,它使用“退出”而不是正则化来处理过度拟合。(退出实质上减少了在训练/学习过程中要考虑的参数数量的大小)。简而言之,让我们来定义这些层。**

它输入一个尺寸为 224 X 224 的颜色 (RGB) 图像。

  1. 首先,尺寸为 11×11 且步距为 4 的 96 个滤波器的卷积层(CL)** 。**
  2. 接下来,一个 Max-Pooling Layer (M-PL)过滤器大小为 3 X 3,跨距= 2。
  3. 同样,256 的一个 CL 过滤大小为 5×5 且跨距= 4 的
  4. 然后,一个 M-PL 的滤镜大小为 3×3,步幅= 2。
  5. 同样,384 个尺寸为 3×3 且跨距= 4 的滤波器的 CL。
  6. 同样,384 个尺寸为 3×3 且跨距= 4 的滤波器的 CL。
  7. 同样,256 个大小为 3×3 且跨距= 4 的滤波器的 CL。
  8. 然后,滤波器大小为 3×3 并且跨距= 2 的一个 M-Pl。
  9. 当最后一层的输出被转换成输入层时,像对于由 9261 个节点组成的全连接块一样, 全连接到具有 4096 个节点的隐藏层。
  10. 第一隐藏层再次 完全连接到由 4096 个节点组成的另一隐藏层。
  11. 最后一个隐藏层 完全连接到输出层,实现 1000 个节点的“softmax 回归”。

现在,我所写的可能看起来与第一张图片(原始图片)中所示的架构大相径庭。仔细查看,对于两个管道(或两个部分),在每个块输出中添加它们的通道号,并查看它是否与描述相匹配。造成这种差异的原因是 AlexNet 同时在两个 Nvidia GeForce GTX 580 GPU上进行训练,导致了架构的这两条流水线。
这个网络有6230 万个参数,需要十亿个计算单元。这种巨大的计算成本导致在多个 GPU 上同时训练该架构以加速该过程。最初的网络只在两个 GPU 上训练。
他们从网络中获得的一个有趣的结果是在分析了来自两个 GPU 的第一个卷积块的滤波器之后。他们发现,一个生成高频灰度特征,另一个生成低频颜色特征。

Visualization of few layers at the beginning of the AlexNet model.

链接到论文。

VGGNet 16:

这个特殊的网络架构是由 Simonyan 和 Zisserman 设计的 ILSVRC-2014 竞赛的亚军。很容易达到 5.1% 的前五名错误率。虽然这看起来很复杂,需要考虑一大堆参数,但实际上非常简单。当谈到特征提取时,开发人员非常喜欢它,因为它遵循简单的模式。关于卷积层和汇集层的过滤器尺寸和步距的基本超参数是恒定的:卷积层具有尺寸为 3×3过滤器和步距= 1** ,而最大汇集层具有尺寸为 2×2过滤器和步距= 2 。这些层以特定的顺序应用于整个网络。只有为每个卷积块定义的滤波器数量不同。让我们来看看:**

The VGG16 Network Architecture.

它接收 224 X 224 尺寸的彩色(RGB)图像。

  1. 64 个滤波器的卷积层(CL)。
  2. CL 64 的再次过滤。
  3. 最大池层(M-PL)
  4. 128 个过滤器的 CL。
  5. CL 128 的再次过滤。
  6. M-PL。
  7. 256 个过滤器的 CL。
  8. CL 256 的再次过滤。
  9. CL 256 的再次过滤。
  10. M-PL。
  11. CL 512 过滤器。
  12. CL 512 的再次过滤。
  13. CL 512 的再次过滤。
  14. M-PL。
  15. CL 512 过滤器。
  16. CL 512 的再次过滤。
  17. CL 512 的再次过滤。
  18. M-PL。
  19. 最后一个池层的输出被送入由 4096 个节点组成的 全连接隐藏层。
  20. 这是再次完全连接到另一个同样由 4096 个节点组成的隐藏层。
  21. 这是 f 完全连接到实现“softmax 回归”的输出层,在 1000 类对象中分类。

那有很多层。因此,它有将近 1 . 4 亿个参数需要处理,这使得实现这个网络的任务充满挑战。然而,预先训练的 VGGNet 的权重很容易获得,并且可以由开发人员在他们的项目中使用。

链接到论文。

GoogleNet / Inception:

Inception Network Architecture

GoogleNet 或盗梦空间网络是 ILSVRC 2014 竞赛的冠军,取得了 6.67%前五名错误率,几乎等同于人类水平的表现,太棒了!该模型由谷歌开发,包括原始 LeNet 架构的一个更智能的实现。这是基于先启模块的思想。
这些模块背后的基本思想是,我们不是在不同的层中实现各种超参数的卷积层,而是一起进行所有的卷积,以输出包含来自所有滤波器操作的矩阵的结果。这是一个简单 inception 模块的图像,其中各种卷积层一起实现:

The Inception module.

级联输出由所有卷积运算的结果组成。请注意,实现了一个包含大小为 1 X 1 的滤波器的卷积层。这减小了图像的大小,在该图像上应用了包含大小为 5×5 的滤波器的另一个卷积层。这背后的原因是,计算单元的总数在很大程度上减少了
比如,当一只 Conv。32 层大小为 5×5 的滤波器被应用于某层的输出矩阵,其尺寸为 28×28×192。因此,总计算次数为28×28×32(输出矩阵大小)* 5×5×192(权重矩阵大小)****= 1.2 亿(接近)
而若一个 Conv。在实施 Conv 之前,首先应用大小为 1 X 1 的 16 个过滤器层。大小为 5×5 的 32 个滤波器的层,矩阵的大小减小到28×28×16,然后进行第二次卷积。
因此总计算次数= {
28×28×16(第一 conv 层的输出)* 1×1×192(第一 conv 层的权重矩阵的大小)}+{28×28×32(第二 conv 层的输出)* 5×5×16(第二 conv 层的权重矩阵的大小)}
=
240 万+1000 万(接近)因此,总成本降低了。
上面显示的 inception 模块(图片很难查看,但是相信我,我没有发现更好的图片可以有更清晰的细节),是这个网络的
构建模块。仔细看看盗梦空间网络图像。这是一个由许多块开始块组成的堆栈,在一些块之间有一些 Max-Pooling 层来改变图像的尺寸。最后一层是全连接网络层,后面是“soft max 回归”,用于输出层中的分类。

链接到论文。

ResNets:

A 34-layer deep ResNet Architecture

大概是在 AlexNet 之后,CNN 架构开发领域最具开创性的发展发生在 ResNet 或者残余网络身上。这是基于“跳过连接”的思想,并实现了重批量标准化,这有助于它有效地训练数千层,而不会降低长期性能。随着对更深层次网络的训练,问题出现了。“消失梯度”的问题,当梯度被反向传播时,重复的乘法操作使得梯度无限小。这导致性能下降。(看一看反向传播和梯度下降,以便清楚地了解在训练阶段实际发生了什么。)
这个架构中注入的思想是“身份快捷连接”,这意味着将一些层的结果转移到一些更深的层,跳过中间的一些其他层。这张图片可能有助于你理解这个想法:

The skip-connection in ResNet models.

其背后的直觉是,较深的层不应该比其较浅的对应层产生更高的训练错误。跳过连接就是为了实现这个想法。该网络的开发人员实现了残差块的预激活变体,其中梯度可以通过快捷方式连接到早期层,从而减少“消失梯度”问题。希望这个图像能够解释它自己。这个 1001 层深度 ResNet 实现了3.57%的前 5 名错误率,在数据集上实际上击败了人类水平的性能。尽管它有很深的网络,但它提供了比大多数 VGGNet 架构更好的性能。它囊括了 2015 年 ILSVRC 在分类、检测和定位领域的所有奖项

希望你喜欢读它。请评论,如果有任何错误或错误的信息从我这边提供。欢迎任何形式的建议。

链接到论文。

长命百岁,编码。

基于 VAR & VECM 的时间序列分析:统计方法

原文:https://towardsdatascience.com/vector-autoregressions-vector-error-correction-multivariate-model-a69daf6ab618?source=collection_archive---------0-----------------------

股票市场数据的案例研究

时间序列随机数据建模

Image by author

https://sarit-maitra.medium.com/membership

V ECTOR 自回归(VAR)集成模型包含多个时间序列,是一种非常有用的预测工具。它可以被认为是自回归(ARIMA 的 AR 部分)模型的延伸。VAR 模型涉及多个独立变量,因此有多个方程。每个方程使用所有变量的滞后和可能的确定性趋势作为解释变量。VAR 的时间序列模型通常是基于将 VAR 应用于平稳序列,并对原始序列进行一阶差分,因此,总有可能丢失关于积分序列之间关系的信息。

因此,对序列进行差分以使其稳定是一种解决方案,但代价是忽略了级别之间可能重要的(“长期”)关系。一个更好的解决方案是检验回归水平是否可信。)通常的做法是用 Johansen 的方法来检验是否存在协整。如果答案为“是”,则可以估计结合了级别和差异的【VECM】向量误差校正模型,而不是级别中的 VAR。因此,我们将检查 VECM 是否能够超越我们现有系列的 VAR。

这是我以前发表的 文章 的延伸。

加载所有数据集(黄金、白银和原油)

经过必要的清理和预处理(用以前的值填充丢失的值),我们最终有了三个时间序列用于必要的分析。

快速测试是检查数据是否是随机的。随机数据在滞后图上不会显示出结构。

时间序列图清楚地表明了序列之间的某种关系。滞后曲线的线性形状表明 ar 模型是更好的选择。我们也没有在数据中看到任何异常值。这里的数据显示线性模式,表明正自相关的存在。

经济数据的时间序列通常是随机的,或者具有不稳定的趋势,这意味着数据有一个根单位

# plots the autocorrelation plots at 75 lags
for i in dataset:
 plot_acf(dataset[i], lags = 50)
 plt.title(‘ACF for %s’ % i) 
 plt.show()

平稳性检查

def augmented_dickey_fuller_statistics(time_series):
  result = adfuller(time_series.values)
  print('ADF Statistic: %f' % result[0])
  print('p-value: %f' % result[1])
  print('Critical Values:')
for key, value in result[4].items():
  print('\t%s: %.3f' % (key, value))

通过上面的函数,我们可以对所有列进行增广的 Dickey Fuller (ADF)检验,这清楚地表明原始序列是非平稳的并且包含单位根。

print('Augmented Dickey-Fuller Test: Gold Price Time Series')
augmented_dickey_fuller_statistics(X_train['Gold'])
print('Augmented Dickey-Fuller Test: Silver Price Time Series')
augmented_dickey_fuller_statistics(X_train['Silver'])print('Augmente
d Dickey-Fuller Test: Oil Price Time Series')
augmented_dickey_fuller_statistics(X_train['Oil'])

向量自回归模型

VAR 模型还可以用来分析使用格兰杰因果关系检验所涉及的变量之间的关系。格兰杰因果关系表明,如果 y1t 中的信息有助于改善 y2t 的预测,则变量 y1t 是变量 y2t 的因果关系。

格兰杰因果检验试图确定一个变量(x1)是否可以作为另一个变量(x2)的预测值,而另一个变量的过去值可能有帮助,也可能没有帮助。这意味着 x1 的解释超越了 x2 过去的值。这里有两个重要的假设-

  • x1 和 x2 都是静止的
  • 它们的当前值和过去值之间存在线性关系。

这意味着,如果 x1 和 x2 是非平稳的,我们必须在检验格兰杰因果关系之前使它们平稳。

将序列拆分为训练和测试数据

我们将在 X_train 上拟合 VAR 模型,以预测接下来的 10 个观测值。这些预测将与测试数据(X_test)中的实际值进行比较。我们将使用多种预测准确性指标。

级数变换

差分变换是从时间序列中去除系统结构的一种简单方法。我们将通过从序列中的每个值减去前一个值来移除趋势,这是一阶差分。为了简单起见,我们将做一阶差分或季节差分。

如果我们对 n 个时间序列进行积分排序,并且如果我们对差值和时间进行一次排序,我们将得到 0 个序列积分排序。

X_train_log = np.log(X_train)
X_train_log_diff =(X_train_log).diff().dropna()
X_train_log_diff.describe()

查看该图,我们可以发现数据集看起来是标准化的

变换序列的自相关函数分析

下面的函数绘制了每只股票的价格与前一个交易日的价格相差 75°的自相关图。

fig, ax = plt.subplots(1,2, figsize=(10,5)) 
ax[0] = plot_acf(X_train_log_diff['Gold'], ax=ax[0])
ax[1] = plot_pacf(X_train_log_diff['Gold'], ax=ax[1])

我们已经展示了 ACF & PACF 的变形金系列;同样,也可以绘制其他系列。

ADF 测试转换系列

print('Augmented Dickey-Fuller Test: Gold Price Time Series')
augmented_dickey_fuller_statistics(X_train_log_diff['Gold'])
print('Augmented Dickey-Fuller Test: Silver Price Time Series')
augmented_dickey_fuller_statistics(X_train_log_diff['Silver'])
print('Augmented Dickey-Fuller Test: Oil Price Time Series')
augmented_dickey_fuller_statistics(X_train_log_diff['Oil'])
Augmented Dickey-Fuller Test on "Oil" 

格兰杰因果检验

格兰杰因果检验用于确定一个时间序列是否有助于预测另一个时间序列。如果通常通过对 X 的滞后值(也包括 Y 的滞后值)的一系列 t-检验和 f 检验可以表明,那些 X 值提供了关于 Y 的未来值的统计上有意义的信息,则称时间序列 X 为格兰杰原因 Y

多变量分析

这里,对于多变量格兰杰因果关系分析,通过对时间序列拟合一个 VAR 来进行。考虑下面是一个 d 维多元时间序列—

格兰杰因果关系是通过拟合具有 L 个时滞的风险值模型来实现的,如下所示:

其中ε ( t)是白高斯随机向量,τ是每个τ的矩阵。一个时间序列 X i 称为另一个时间序列 Xi 的格兰杰原因,如果τ = 1,…,L 中至少有一个元素 A τ ( j,I)显著大于零。

print(grangercausalitytests(X_train_log_diff[['Gold','Silver']], maxlag=15, addconst=True, verbose=True))
print(grangercausalitytests(X_train_log_diff[['Gold','Oil']], maxlag=15, addconst=True, verbose=True))
print(grangercausalitytests(X_train_log_diff[['Oil','Silver']], maxlag=15, addconst=True, verbose=True))

下面显示了黄金和石油的产量,这与滞后 4 之前的测试假设不同。

VAR(p)过程的基本形式是:

这里 yt 表示一个向量中收集的一组变量,c 表示一个常数向量,a 是自回归系数矩阵, e t 是白噪声。由于 a 的参数是未知的,我们必须估计这些参数。模型中的每个变量都有一个方程。每个变量的当前(时间 t )观察值取决于其自身的滞后值以及 VAR 中每个其他变量的滞后值。

滞后订单选择

我已经通过 VAR (p)实现了 Akaike 的信息标准(AIC ),以确定滞后订单值。在 fit 函数中,我已经传递了最大数量的滞后和用于订单选择的订单标准。

#Initiate VAR model
model = VAR(endog=X_train_log_diff)
res = model.select_order(15)
res.summary()

#Fit to a VAR model
model_fit = model.fit(maxlags=3)
#Print a summary of the model results
model_fit.summary()

预测 VAR 模型

预测是根据模型使用的训练数据生成的。

# Get the lag order
lag_order = model_fit.k_ar
print(lag_order)# Input data for forecasting
input_data = X_train_log_diff.values[-lag_order:]
print(input_data)# forecasting
pred = model_fit.forecast(y=input_data, steps=nobs)
pred = (pd.DataFrame(pred, index=X_test.index, columns=X_test.columns + '_pred'))
print(pred)

逆变换

因此,要将其恢复到原始比例,我们需要对原始输入数据进行去差分。我们的数据是第一次对数转换,然后差分。因此,为了求逆,我们必须首先使用累积和去微分,然后使用指数。自然对数是 exp()的倒数。

# inverting transformation
def invert_transformation(X_train, pred_df):
  forecast = pred.copy()
  columns = X_train.columns
for col in columns:
  forecast[str(col)+'_pred'] = X_train[col].iloc[-1] + forecast[str(col) +'_pred'].cumsum()
  return forecastoutput = invert_transformation(X_train, pred)
print(output)output_original = np.exp(output)
print(output_original)

VAR 预测评估

#Calculate forecast bias
forecast_errors = [X_test['Oil'][i]- output_original['Oil_pred'][i] for i in range(len(X_test['Oil']))]
bias = sum(forecast_errors) * 1.0/len(X_test['Oil'])
print('Bias: %f' % bias)#Calculate mean absolute error
mae = mean_absolute_error(X_test['Oil'],output_original['Oil_pred'])
print('MAE: %f' % mae)#Calculate mean squared error and root mean squared error
mse = mean_squared_error(X_test['Oil'], output_original['Oil_pred'])
print('MSE: %f' % mse)
rmse = sqrt(mse)
print('RMSE: %f' % rmse)

“众所周知,当数据相当持久时,动态回归模型的最小二乘参数估计在小样本中会表现出相当大的偏差”

VECM 估计和分析

由于存在非平稳但协整的数据形式,VECM 施加了额外的限制。它将协整限制信息应用到其规范中。在协整已知后,下一步的检验过程是通过使用误差修正方法来完成的。通过向量误差修正模型,我们可以解释长期和短期方程。我们需要确定协整关系的数量。VECM 相对于 VAR 的优势在于,从 VECM 表示得到的 VAR 具有更有效的系数估计。

Johansen 协整

为了拟合向量误差修正模型,我们需要使用 VEC 秩检验来确定协整关系的数量。

vec_rank1 = vecm.select_coint_rank(X_train, det_order = 1, k_ar_diff = 1, method = 'trace', signif=0.01)
print(vec_rank.summary())

我们在第三列中找到λtrace 统计数据,以及相应的临界值。测试统计值 38.25 低于临界值(41.08),因此至多一个协整合向量的零不能被拒绝。

让我们采用另一种统计,最大特征值统计(λmax)。

vec_rank2 = vecm.select_coint_rank(X_train, det_order = 1, k_ar_diff = 1, method = 'maxeig', signif=0.01)
print(vec_rank2.summary())

测试输出报告了λmax 统计信息的结果,该统计信息与 trace 统计信息相差不大;临界值(29.28)仍然高于测试统计值。

我们仍将继续估计 VECM,因为在缺乏协整的情况下,它对短期动态仍有价值。让我们用 9 个滞后、1 个协整关系和协整关系中的一个常数来估计价格的向量误差修正模型。我使用了【慈利】**【ci】——协整关系中的常数和【李】——协整关系中的线性趋势的组合

vecm = VECM(endog = X_train, k_ar_diff = 9, coint_rank = 3, deterministic = ‘ci’)
vecm_fit = vecm.fit()
vecm_fit.predict(steps=10)

forecast, lower, upper = vecm_fit.predict(10, 0.05)
print(“lower bounds of confidence intervals:”)
print(lower.round(3))
print(“\npoint forecasts:”)
print(forecast.round(3))
print(“\nupper bounds of confidence intervals:”)
print(upper.round(3))

VECM 预测评估

虽然我们有迹象表明,VAR 将是我们的价格预测数据集的最佳选择;然而,我们出于实验和说明目的展示了 VECM。这是一个解释 VAR 的简单程序。然而,如果我们能够看到一个变量的冲击如何在随后的时期影响其他变量,也可以将脉冲响应分析和方差分解等其他程序引入实验。

关键要点

经济数据的时间序列通常是随机的,或者具有不稳定的趋势,这意味着数据有一个根单位。能够用数据来估计一个模型-

VAR-的步骤

  1. 测试数据的平稳性和整合程度
  2. 滞后长度的确定
  3. 检验格兰杰因果关系
  4. 风险值估计
  5. 方差分解

VECM 的预测步骤-

  1. 滞后长度的确定
  2. 检验格兰杰因果关系
  3. 协整度检验
  4. 向量误差修正模型估计
  5. 方差分解

我这里可以到达

注意:此处描述的程序是实验性的,应谨慎使用。所有此类使用风险自负。

参考文献:

(1)饶,B. (2007)。协整:应用经济学家斯普林格。

(2) Ashley,r . a .&Verbrugge,R. J. (2009)。差异还是不差异:向量自回归模型中推断的蒙特卡罗研究。国际数据分析技术和策略杂志,1(3),242–274。

(3)吕特克波尔,H. (2011 年)。向量自回归模型。《国际统计科学百科全书》(第 1645-1647 页)。施普林格柏林海德堡。

(4)郭春英(2016)。向量误差修正模型在预测股价上比其他模型表现更好吗?剩余收益评估理论的一个应用。经济模型,52,772–789。

矢量化:如何用 x78 加速你的机器学习算法

原文:https://towardsdatascience.com/vectorisation-how-to-speed-up-your-machine-learning-algorithm-by-x78-times-faster-e330df8c9b27?source=collection_archive---------13-----------------------

给定一个等式,我们将看到 step by step 如何不仅在速度方面实现 x78 倍的更高效代码,而且仅使用 3 行代码!让我们深入了解一下…

介绍

作为一种解释语言, Python for loops 天生就比 C 语言慢。这对臭名昭著的编程语言来说是一个很大的瓶颈,因为深度学习和机器学习算法严重依赖于矩阵运算,它们通过for循环来执行。

这就是开发人员开发包的原因,比如numpy,他们在numpy数组上提供矢量化动作。这意味着它将通常在 Python 中完成的for循环推到了更快的 C 层

Python + C 级速度=天堂

问题是

(如果你能理解 EM 算法,你可以跳过解释部分)

我们希望将期望最大化 (EM)算法用于无监督学习任务(例如,识别 MNIST 数据集中的手写数字),并且我们的数据是二进制的(例如二进制图像)。一个自然的方法是将我们的数据建模为一个伯努利混合模型。伯努利分布的加权和,其中每个分布具有其自己的标量权重**π**和其自己的均值向量**μ** ,并且表示数据的聚类(例如,如果我们的数据是数字 2、3 & 4 的图像,并且我们使用 3 个伯努利来对它们建模,一个伯努利将是数字 2,另一个是数字 4,等等)。总的来说,前者是一个向量,后者是一个矩阵。

Bernoulli mixture model (1)

Distribution of one observation x given the cluster k (2)

设 N =观察值的数量,D =一个观察值的维数,K =聚类的数量。因为这对我们的问题很重要,所以我们的随机变量类型有:
**X**;我们的数据 a NxD 矩阵
(N 是图像的数量,D 是图像的维数→ 5 张 2828 的图像会组成一个 5x784 的矩阵 X)
π;一个向量 K,一个代表权重的标量。
(例如三个伯努利可以有π=[0.2,0.75,0.05]加权向量)
**μ**;每个聚类的平均 KxD 矩阵。
(一幅图像的维数为 D=28
28=784,其中每一幅图像代表一个像素值。对属于同一聚类的图像的每个像素取平均值,比如数字 2,我们得到 784 的平均向量。因此,**μ**将是 KxD 的矩阵)

E 步骤中,我们特别感兴趣的是潜在变量后验的期望值,或者所谓的责任

E-step of EM algorithm (3)

γ实际返回期望值的观测值(图像)n属于聚类k
γ 是一个 NxK 矩阵;对于每个观察值,我们分配一个属于每个聚类的概率。具有最大值的是我们分配给。

我为什么要说这些?

"矢量化中最重要的事情是理解变量的维数."

责任的计算是我们要向量化的内容

总结一下:
**X**:NxD 矩阵
**π**:1xK 向量
**μ**:KxD 矩阵
**γ**:NxK 矩阵****

管道

我们将创建一个函数E_step来运行计算上面的表达式,并用下面的代码测试它

**observations = [5, 10, 20, 50, 100, 200, 500, 1000]
for n in observations:
    X_test = bin_train_data[:n]
    D_test, K_test = X_test.shape[1], 10 mu_test = np.random.uniform(low=.25, high=.75, 
                                size=(K_test,D_test))
    pi_test = np.ones(K_test) / K_test t0 = time.time()
    gamma_test = E_step_1(X_test, mu_test, pi_test)
    runtime = time.time() - t0
    **assert** gamma_test.shape == (n, K_test)**

放心先自己试一试吧!

尝试№1

在我们的第一次尝试中,我们将使用 for 循环编写所有内容;在向量/矩阵运算中,只有标量。

通过看方程,我们可以看到有 3 个循环;每个例子一个N,每个集群一个K,每个物体的每个维度一个D,我们将按这个顺序循环。所以我们要一次用一个元素填充矩阵γ

**def E_step(X, mu, pi):
    N, D = X.shape
    K = pi.shape[0]
    gamma = np.zeros((N, K))
    for n in range(N):
        for k in range(K):
            m = 1
            for i in range(D):
                m *= mu[k][i]**X[n][i] * (1-mu[k][i])**(1-X[n][i])
            gamma[n][k] = m * pi[k]
        gamma[n] /= gamma[n].sum()
    return gamma**

我们的结果可以在下图中看到。

我们肯定能做得更好!

尝试 2

最好从内部循环开始,然后向外部循环推进。这正是我们要做的!

我们想摆脱 for 循环D。因此,依赖于D的每一项现在都应该变成一个向量。在这个 for 循环中,我们有两个变量;μx(见等式。(2))。因此xμ →矢量。问题;这是μ**x,向量到另一个向量的幂,很难计算。如果我们能绕过这个…

有一个函数可以将乘幂运算转化为乘法运算。没错,就是对数!让我们对表达式取对数,然后取结果的指数!

对数概率上的运算是优选的,因为它们提供了数值稳定性

尽管在我们的例子中它没有任何影响,但是每次使用 log 时,在表达式中使用一个常量epsilon以保持稳定性(为了不归零,使用 is -inf)。

因此,我们将不得不进行逐元素的向量乘法。容易;)

**def E_step(X, mu, pi):
    N, D = X.shape
    K = pi.shape[0]
    gamma = np.zeros((N, K))
    for n in range(N):
        for k in range(K):
            log_gamma = np.log(pi[k]) + (X[n] * np.log(mu[k]) \
                        + (1 - X[n])*np.log(1 - mu[k])).sum()
            gamma[n][k] = np.exp(log_gamma)
        gamma[n] /= gamma[n].sum()
    return gamma**

我们的结果是…

这是一个巨大的胜利!似乎 x 轴比得上Algor. 1!但是,我们可以做得更好;)

尝试№3

一次一圈:轮到K了!

在矢量化过程中,我们的移动如下:

标量→矢量→矩阵

随着我们用numpy数组替换越来越多的循环,越来越多的代码将在 C 上运行→更快的&更干净的代码。

我们采用之前的实现,希望移除循环的K。因此,每一个依赖于K的标量都会变成一个vector,而每一个vector都会变成一个matrix。这意味着X将保持不变,而μ将变成矩阵,而πγ将变成向量。注意最后一条;随着γ字段的一行一行,我们表达式的结果现在必须是一个向量!所以μX的操作必须产生一个1xK向量,快速指示器是(I)它们必须与向量π相加,向量也是1xK (ii)结果是矩阵γ的一行,向量也是1xK

将我们的结果编码成:

**def E_step(X, mu, pi):
    N, D = X.shape
    K = pi.shape[0]
    gamma = np.zeros((N, K))
    for n in range(N):
        log_gamma = np.log(pi) + np.log(mu) @ X[n] \
                    + np.log(1 - mu) @ (1 - X[n])
        gamma[n] = np.exp(log_gamma)
        gamma[n] /= gamma[n].sum()
    return gamma**

结果是:

********

太神奇了!我们已经为n=1000争取到了一半的时间!跟Algor. 1真的没法比。但是,我们能做得更好吗?

尝试№4

我们还有一个循环。我们能有一个计算循环-python-free 吗?N,你的时间到了!**

由于我们要将一个matrix * vector运算转化为一个matrix @ matrix运算,我们需要取前者的传输矩阵(@是正则矩阵乘法)。请记住,现在我们的输出必须是整个γ矩阵。我想现在你已经知道它是怎么回事了;).

所以我们的代码应该是

**def E_step(X, mu, pi):
    gamma = np.exp(np.log(pi) + X @ np.log(mu.T) \
            + (1 - X) @ np.log(1 - mu.T))    
    gamma /= gamma.sum(axis=1)[:, np.newaxis]
    return gamma**

没有一个循环!代码看起来很优雅,而且只有三行长!现在是结果,鼓声…

********

就是这样,不能再好了!对于n=1000,我们只用了三行代码就从运行时的11.6880.012

摘要

那么,当你想对一个表达式进行矢量化时,你需要做什么呢?

了解矩阵的尺寸
纸笔:记下公式,从求和到求和,化为等价矩阵运算
数学是你的朋友;总是考虑任何表达式必须返回的维数;观察邻居求和运算,因为它们具有相同的维数
逐循环、逐步进行:
标量→向量→矩阵
对数并确保引入归一化常数ε
代码您的方法的矢量化版本并闪耀:D****

供应商—定义您对#AI 的使用

原文:https://towardsdatascience.com/vendors-define-your-usage-of-ai-9495b30ebd28?source=collection_archive---------15-----------------------

Photo by Lukas on Unsplash. Used with permission.

作为一名行业分析师,我听取了许多供应商的简报。在这些简报中越来越常见的是,厂商频繁而随意地使用缩写【AI】来描述他们产品或服务的各种功能。

在最近的一次简报中,这种做法在一家大型供应商那里尤为明显。他们的短语是:AI+BI;用 AI…的力量去探索他们的数据;有了 AI……变得更聪明;AI 让数据可访问;人工智能…从根本上改变了分析的使用方式;由 AI 驱动;注入了人工智能。所有这些都在前 13 张幻灯片中!

:这是我的一面大红旗!我完全避免在我的文章中使用 AI 这个缩写词,因为它经常含糊不清,并且分散了我想要传达的信息。

我问了这个问题,“你们公司是怎么定义 AI 的?

这个首字母缩略词是指…描述性分析之外的任何分析吗?预测未来事件的分析?因果关系的发现?模仿人类的思维过程?超过人类专家水平的分析?深度神经网络的使用?业务流程自动化?或者,仅仅是又一个分析技术时代?

更新 2019–03–13:文章 AI 已经变得毫无意义 作者 Ian Bogost 在《大西洋月刊》中有许多明确的例子和一些有用的替代方法。

厂商的回答很简单……AI 的意思是增强智能,不是人工智能。这个回答让我很惊讶。

但是 AI =人工智能

对大多数专业人士来说,AI 这个缩写意味着人工智能。如果供应商暗示了一个替代概念,比如增强智能,他们就不应该使用这个缩写。

此外,我想知道为什么这个短语没有明确地出现在他们的幻灯片中,所以我继续问定义他们的 AI 用法的问题。

外卖:厂商应该把 AI 这个缩写词限制在描述一般的技术趋势,避免把 AI 这个缩写词和产品/服务特性联系起来。

强调增加

我说这是一个好的回答,因为它强调了自动化(取代人类)与增强(增强人类)的关键问题。增强智能意味着人类的智能正在增强,而不是被更好、更便宜或更快的东西取代。这是一个微妙但关键的转变,它承认人类的价值,特别是他们的直觉、创造力、经验和判断力。

然后,我建议他们应该在营销信息中强调这一点,因为对其增强的准确陈述将是一个实质性的营销点。换句话说,他们已经错过了与现有观众交流的大好机会。

外卖:供应商应该总是强调增加,而不是取代人类的智慧。此外,清楚地展示如何利用和增强个人的独特能力。

强调学习

人工智能系统的一个关键方面是它能够让 T2 学习 T3。不幸的是,这个主题不是这个供应商的简报的一部分,这意味着他们的“人工智能”能力是创造性的静态算法。这应该被认为是“人工智能”吗?

重要的一点不是人工智能系统学习,而是系统通过展示良好的行为范例被教授令人满意的行为。这是从静态逻辑到学习逻辑的范式转变,随着更多例子的使用,这种转变会得到改善。参见这篇关于新价值观的文章 [1]

因此,重要的是要知道…谁在教学?又是怎么做到的?

在传统的机器学习中,这种教学是由人类对示例数据集的管理来驱动的,这些示例数据集是从原始数据中精心制作的显著特征。如今人工智能系统的核心——神经网络——正在通过投掷原始数据,通过从其他模型转移训练,或者通过与其他神经网络竞争来学习。可以更有效地进行学习逻辑的教学。因此,教授这个学习人工智能系统的机制是一个关键的方面,需要一个清楚的解释。

外卖:厂商应该定义他们的人工智能产品如何学习。AI 模型的教学(训练)是如何进行的?

定义价值

供应商关于增强智能的回答暗示了一个明显的下一个问题:通过学习型人工智能系统增强人类智能如何给组织带来价值

几十年来,IT 行业一直在追求增强智能,当我在 20 世纪 60 年代末参与进来时,它被贴上了“决策支持系统”的标签。我立刻想到了约翰·图基在 20 世纪 70 年代早期在一辆瓦里安 620 上演示 PRIM-9。这里有一篇关于这一历史瑰宝的简短博客(和视频)!2

面临的挑战是如何通过提高个人的效率和/或效力来确定具体的增强对组织的价值。

彼得·德鲁克(Peter Drucker)那句臭名昭著的名言与此相关:“效率就是把事情做对;有效性就是做正确的事情。【③】

增强人类的智力,让人们能够更快、更便宜、更可靠地完成特定的任务(做正确的事情)是件好事。然而,如果这个人能够定制任务以满足特定情况的需要 ( 做正确的事情),那就更好了。这一点在这篇关于新价值观的文章中解释为 智能效能 。[4]

要点:供应商应该精确地了解人类的智能是如何增强的。并且,展示这种增强如何为组织增加价值,尤其是智能效率。

术语 AI 的随意使用是欺骗性的

首字母缩写词 AI 的随意使用充其量是含糊不清的,而且经常具有欺骗性,尤其是在营销信息中!

对于一些观众来说,不幸的是,它的使用传达了产品/服务的一种神奇的品质,暗示着“来买这个吧,你所有的商业问题都会很快消失。”这就是首字母缩写 AI 背后微妙但误导人的魅力!

任何了解深度神经网络当前研究和实践的人都意识到,企业中的实际人工智能应用范围有限,难以开发,部署麻烦,难以实现价值……尽管大型技术供应商进行了迷人的演示!没有魔法,只有一个关于一百万个简单数字的群集如何能够模拟现实的复杂性的秘密。

许多专家得出结论,人工智能技术仍然处于“炼金术”阶段,作为一门原始科学,就像中世纪的化学一样……关于“什么-如何-为什么”的问题比理论更多。详见本文。[1]

我同意,从长远来看,这项技术有巨大的潜力。与此同时,早期采用者(和他们的供应商)应该预料到背后会有很多箭!

外卖:厂商应抵制利用人工智能的空洞营销炒作。那些日子已经过去了。相反,深入思考并清楚地解释你的产品为增强某人的能力和学习提高其能力所带来的价值。

用人工智能处理伦理问题

这是随意使用 AI 首字母缩写词的积极一面。准备好面对黑暗面了吗?

越来越多的人认为,人工智能意味着业务流程的自动化,导致人类的替代,以及失业、技能灭绝、管理集中化、财富集中和政治控制等令人讨厌的影响。

将未来押在人工智能上的厂商应该非常谨慎,并对道德含义有政治头脑。在汤姆·达文波特(Tom Davenport)和比尔·弗兰克斯(Bill Franks)的 2019 年 IIA 预测和分析优先事项中,他们的第一个预测是: 将越来越强烈地关注分析的道德 ,并敦促他们的客户 今天就开始正式解决分析道德问题 ![5]

你的公司是否明确批准并热情鼓励公开和诚实的讨论,以及政策的形成,关于你的产品/服务在人工智能旗帜下营销的道德含义?

几十年来,我经历了许多技术浪潮。对我来说,现在的深度神经网络浪潮,特别刺激,特别有挑战性。然而,我必须承认,我越来越觉得自己像一个 1940 年代开发核能的科学家。这是一个巨大的好的潜力…也是一个悲剧!

忘记人工智能机器人奴役人类的威胁吧。真正的威胁是人工智能系统正在被武器化以对抗其他系统,这是有意的,尤其是天真的。像核能一样,这个大国必须得到明智的管理。[6, 7, 8]

要点:供应商应该公开诚实地面对道德问题。帮助他们的客户理解和管理这些道德问题。

如果你有类似的动机,请与我合作。作为 Bolder 技术的一部分,请查看我目前在 BizSmartAnalytics 的工作。[9]一些掌声将不胜感激;)

© Bolder Technology — CC BY 3.0 US

更新 2019–06–29:发了这个 JPEG 来强调以上几点。请在与同事讨论时使用。

参考

  1. Hackathorn,管理者应该如何准备深度学习:新范式
    https://towards data science . com/How-Managers-Should-Prepare-for-Deep-Learning-New-Paradigms-28de 63054 ea 6
  2. 黑客马拉松,交互式三维数据可视化的开端,
    https://www . immersiveanalytics . com/2015/11/Beginning-of-Interactive-3D-Data-Visualization/
  3. 彼得·德鲁克, 经营效益管理。第 53-60 页。
  4. 黑客马拉松,管理者应该如何准备深度学习:新价值观
    https://towardsdatascience . com/How-Managers-Should-Prepare-for-Deep-Learning-New-Values-f 29 a 98 b 70 BD 8
  5. 达文波特和弗兰克斯,关于 2019 年分析预测&优先事项的网络研讨会,由国际分析研究所于 2018 年 12 月 6 日举办,https://www . ii Analytics . com/2019-Analytics-Predictions-Priorities-Webinar/
  6. Chollet,我担心什么 AI,
    https://medium . com/@ Francois . chollet/What-Worries-Me-About-AI-ed 9df 072 b 704
  7. 入伙上艾,
    https://www.partnershiponai.org/】T21
  8. 骑士,AI 的父亲之一担心它的未来,
    https://medium . com/MIT-technology-review/One-of-the-Fathers-of-AI-is-Future-a 7996 cddce 72
  9. 黑客马拉松,深度学习系统的管理挑战,
    https://BizSmartAnalytics.com/

Python 中的维恩图和单词云

原文:https://towardsdatascience.com/venn-diagrams-and-word-clouds-in-python-1012373b38ed?source=collection_archive---------12-----------------------

所有你不需要知道的西雅图宠物名称和品种

Photo by Jakob Owens on Unsplash

在我对西雅图宠物的调查中,我发现自己很想知道宠物的名字——最流行的宠物名字是什么?猫的名字和狗的名字是不同的吗,就像猫和狗是不同的一样(平均来说,我们都有这样一个朋友,当你来到门口的时候,他会跑过来迎接你,当你叫他的时候,他会过来,玩捡东西的游戏。或者当它的家人举行聚会时,那只藏在椽子里的狗…)?还有宠物品种——西雅图的每只狗都是狮子狗混种吗?这些经常出现在我家后院的奇特的猫有多常见(还没有被我的小狗贝克汉姆注意到,它以前从来没有在一楼住过)?

还有其他心怀不满的纽约巨人队球迷,他们用小奥德尔·贝克汉姆的名字给他们的狗命名,但当他搬到克利夫兰·布朗(NFL 历史上统计数据最差的球队之一)时,他们感到非常失望,在那里他迅速开始了他最糟糕的一年。我本人是一个骄傲的西雅图和海鹰队的球迷,但我嫁给了一个新泽西巨人队的球迷(他慷慨地编辑了这篇文章,并利用他的编辑控制权表达了他对巨人队的失望——迄今为止只有 3 胜 11 负——和小奥黛尔·贝克汉姆)。

不管怎样…在这个过程中,我意识到了一个维恩图的绝佳机会,甚至维恩图单词云可以帮助回答这些问题。

顶级猫狗名

我从横条图开始,查看西雅图最常见的 50 个猫狗名。

fig, axes = plt.subplots(ncols=2, figsize=(12,12))
plt.subplots_adjust(wspace=.3)axes[0].barh(cat_t50['name'], cat_t50['count'], .5, color='#294AB9', 
             alpha=0.8)
axes[0].invert_yaxis()
axes[0].set_title("Frequency of Seattle's Top 50 Cat Names", 
                  fontsize=12)
axes[0].set_xlabel("Number of Cats")axes[1].barh(dog_t50['name'], dog_t50['count'], .5, color='#1896ac', 
             alpha=0.8)
axes[1].invert_yaxis()
axes[1].set_title("Frequency of Seattle's Top 50 Dog Names", 
                  fontsize=12)
axes[1].set_xlabel("Number of Dogs");

注意这里使用的一些matplotlib工具:

  • 使用plt.subplots_adjust(hspace=.3)水平分隔支线剧情,这样名字就不会出现在其他剧情中。在文档中找到更多关于调整支线剧情的信息。
  • ax.invert_yaxis()将翻转 y 轴,使数据集中的第一项出现在顶部。

我马上注意到的一件事是,前 50 名狗名单和前 50 名猫名单上的名字有很多重叠:我称之为“物种中性名字”。为了形象化这一点,我做了一个文氏图。

注意:根据 PyPI 文档,您需要pip installeasy-install matplotlib-venn,并确保您拥有依赖关系:numpyscipymatplotlib

from matplotlib_venn import venn2, venn2_circles
from matplotlib import pyplot as plt# setup the figure
fig, ax = plt.subplots(figsize = (12,10)
ax.set_title(‘Top 50 Cat and Dog names in Seattle’, fontsize=20)# make the venn diagram
v = venn2([set(cat_t50[“name”]), set(dog_t50[“name”])],
set_labels=[‘Cat Names’, ‘Dog Names’])# adjust labels from counts to names
v.get_label_by_id(‘10’).set_text(‘\n’.join(cat_only_names))
v.get_label_by_id(‘01’).set_text(‘\n’.join(dog_only_names))
v.get_label_by_id(‘11’).set_text(‘\n’.join(overlap_names))# add circle outlines
c = venn2_circles([set(cat_t50[“name”]), set(dog_t50[“name”])],
                  linestyle=’solid’)

使用matplotlib-venn的一些注意事项:

  • venn2(两个圆圈)的参数编号如下:“10”=仅左侧项目,“01”=仅右侧项目,“11”=左侧和右侧项目。相同的框架适用于venn3(三个圆圈):‘100’=仅第一组项目,‘010’=仅第二组项目,‘110’=第一和第二组的交集,但不在第三组中,等等。
  • Get_label_by_id()允许您.set_text()
  • get_patch_by_id()允许您.set_alpha().set_color()
  • venn2_circles添加轮廓,并允许您为不同的圆设置不同的轮廓,使用索引指示哪个圆,set_lw(*width*)指示线宽,.set_ls(*linestyle*)指示线型。c[0].set_ls(‘dotted’)例。记住matplotlib有多种内置的线条样式,包括‘实线’、‘虚线’、‘虚线’,以及定制功能。

注意猫专用名(Shadow、Loki、Smokey)和狗专用名(Cooper、Sadie、Bailey)的区别。狗更有可能被赋予“人类”的名字吗?改天的问题…

作为调整颜色的一个例子,我决定看看猫和狗的名字通常是如何重叠的。

from matplotlib_venn import venn2, venn2_circles
from matplotlib import pyplot as pltfig, ax = plt.subplots(figsize = (10,10))
ax.set_title(‘Species-neutral names in Seattle’, fontsize=20)v = venn2([set(cat_names[“name”]), set(dog_names[“name”])],
          set_labels=[‘Cat Names’, ‘Dog Names’])
v.get_patch_by_id(‘10’).set_color(‘red’)
v.get_patch_by_id(‘10’).set_alpha(0.4)
v.get_patch_by_id(‘01’).set_color(‘blue’)
v.get_patch_by_id(‘01’).set_alpha(0.4)
v.get_patch_by_id(‘11’).set_color(‘purple’)
v.get_patch_by_id(‘11’).set_alpha(0.4)c = venn2_circles([set(cat_names[“name”]),set(dog_names[“name”])],
                  linestyle=’solid’)

请注意,圆圈内的标签和大小是基于猫/狗名称的数量,而不是数量,尽管注册的狗数量比西雅图注册的猫数量多。

在我寻找显示维恩图中名字的方法时,我看到了 Paul Broaderson 的这个可爱的包,它在你的维恩图中创建了一个单词云。你所需要做的就是安装matplotlib-venn-wordcloud,然后你就可以使用与上面相同的语法开始比赛了。默认的配色方案是黑色和白色,但是您可以按照matplotlib-venn中使用的相同策略添加背景色。注意,单词的大小并不自动反映单词的频率。查看文档添加该功能。

from matplotlib_venn_wordcloud import venn2_wordcloud
fig, ax = plt.subplots(figsize=(10,10))
ax.set_title(‘Top 50 Cat and Dog Names in Seattle’, fontsize=20)v = venn2_wordcloud([set(cat_t50[‘name’]), set(dog_t50[‘name’])],
                    ax=ax, set_labels=[‘Cats’, ‘Dogs’])# add color
v.get_patch_by_id(‘10’).set_color(‘red’)
v.get_patch_by_id(‘10’).set_alpha(0.4)
v.get_patch_by_id(‘01’).set_color(‘blue’)
v.get_patch_by_id(‘01’).set_alpha(0.4)
v.get_patch_by_id(‘11’).set_color(‘purple’)
v.get_patch_by_id(‘11’).set_alpha(0.4)

Ragamuffin Kitten from Togle1 [CC BY-SA 4.0 ] on wikimedia commons

猫和狗的品种

接下来看看品种,猫似乎在完全不科学的最佳品种名称( Ragamuffin )和最可爱品种名称( Munchkin )奖项中拔得头筹。与此同时,令人惊讶的是,这些狗并不都是涂鸦狗。不管走在街上看起来如何,他们实际上只占 9%左右。

Munchkin Cat (inspired by the Wizard of Oz) from Tasy Hong [CC0] on Wikimedia Commons

仔细看看最常见的涂鸦:拉布拉多涂鸦金毛涂鸦,我们看到在 34,882 只注册狗中,大约有 10,000 只或 28%的西雅图注册狗将其中一只(拉布拉多或金毛)作为它们的主要或次要品种。大约四分之一具有金毛血统的狗是金杜,而接近 15%具有拉布拉多血统的狗是拉布拉多。然后还有 135 个金达多。我们的数据集中没有双涂鸦(拉布拉多金毛狗混种),尽管这可能受到宠物注册数据收集过程的限制,该过程只允许主人识别主要和次要品种。这指出了维恩图中不精确的地方,但总的来说,这是一个非常棒的工具。

from matplotlib_venn import venn3, venn3_circles
fig, ax = plt.subplots(figsize = (10,10))
ax.set_title(‘Poodle-Lab-Golden Mixes in Seattle’, fontsize=20)v = venn3([set(poodle_dogs), set(labs), set(goldens)],
          set_labels=[‘Poodle’, ‘Labrador Retriever’, 
                      ‘Golden Retriever’], 
          ax=ax)
c = venn3_circles([set(poodle_dogs), set(labs), set(goldens)],
                  linestyle=’solid’, ax=ax)

A certain Labradoodle puppy

最后,我想知道,在西雅图的贵宾犬中,有多少是涂鸦?

答案是:很多。而matplotlib-venn像 champ 一样处理这种情况,为了美观,只要求最右边补丁的标签设置为" "。

from matplotlib_venn import venn2, venn2_circles
fig, ax = plt.subplots(figsize = (10,10))
ax.set_title(‘Poodles vs. Poodle Mixes in Seattle’, fontsize=20)v = venn2([set(poodle_dogs), set(doodle_dogs)], set_labels=[“”,””], 
          ax=ax)
v.get_label_by_id(‘10’).set_text(‘Poodle’)
v.get_label_by_id(‘11’).set_text(‘Doodle’)
v.get_label_by_id(‘01’).set_text(‘’)c = venn2_circles([set(poodle_dogs), set(doodle_dogs)], 
                  linestyle=’solid’, ax=ax)

和往常一样,查看 GitHub repo 了解更多细节。

临别赠言:作为一个养狗名为小奥戴尔·贝克汉姆(O'dell Beckham Jr. Honold)(注册名为‘Beckham’)的人,我对西雅图只有一只注册名为‘Ichiro’的宠物感到震惊和错愕。但振奋地发现有 39 个威尔逊 39 个格里菲斯 29 个埃德加 22 个谢尔曼,21 个拉塞尔,以及 6 个马肖恩,佩顿,邓普西。其中 22%是猫,78%是狗,相比之下,32%是猫,67%是狗。这句话是在说猫和狗的本性,猫和狗的主人,还是两者都是?

对凯文来说,原来还有另外两只小贝夫妇,一只金毛寻回犬,另一只短毛吉娃娃。

Goldendoodle puppy by William Warby [CC BY 2.0] on Wikimedia Commons

在 Python 和 R 中验证线性回归的假设

原文:https://towardsdatascience.com/verifying-the-assumptions-of-linear-regression-in-python-and-r-f4cd2907d4c0?source=collection_archive---------2-----------------------

Source

深入探究高斯-马尔可夫定理和线性回归的其他假设!

线性回归是最基本的机器学习算法之一,经常被用作更高级模型的基准。我假设读者知道线性回归是如何工作的,以及一般来说回归问题是什么。这就是为什么在这篇短文中,我想重点介绍算法的假设——它们是什么,以及我们如何使用 Python 和 r 来验证它们。我并不试图在这里应用解决方案,而是指出它们可能是什么。

在本文中,我主要使用 Python(在 Jupyter Notebook 中),但我也展示了如何使用rpy2——一种“两种语言之间的接口,以便在使用另一种语言时受益于一种语言的库”。它使我们能够在同一个笔记本中运行 R 和 Python,甚至在两者之间传输对象。直觉上,我们也需要在我们的计算机上安装 R。

声明:一些使用rpy2的单元格不工作,我不得不“欺骗”在 R 中运行它们来显示结果。使用ggplot2的细胞大多如此。尽管如此,我还是把代码留在了这个单元里。如果这对你有用,请在评论中告诉我:)

开始吧!

1.数据

在本文中,我使用了一个经典的回归数据集——波士顿房价。为了简单起见,我只取数值变量。这就是为什么我放弃了唯一的布尔特征——CHAS。我不打算深究这些特性的含义,但这总是可以通过运行print(boston.DESCR)来检查。

2.运行线性回归

大多数读者可能会估计这样的线性回归模型:

Coefficients: [-1.13139078e-01  4.70524578e-02  4.03114536e-02 -1.73669994e+01
  3.85049169e+00  2.78375651e-03 -1.48537390e+00  3.28311011e-01
 -1.37558288e-02 -9.90958031e-01  9.74145094e-03 -5.34157620e-01]
Intercept: 36.89195979693238
R^2 score: 0.7355165089722999

这当然不是错误的方法。然而,从 R 到 Python,我对默认接收的信息量有更高的期望。要在我们的笔记本中运行 R,我们首先需要运行这个神奇的命令:

%load_ext rpy2.ipython

随后,使用另一个神奇的命令表明该单元包含 R 代码。在这一步,我还使用了输入命令-i来指示我正在将一个对象从 Python 传递到 R。要将 R 的输出检索到 Python,我们可以使用-o。运行这两行会产生更多的信息,包括统计显著性和一些指标,如 R。

当然,Python 不会落后,我们可以使用另一个流行的库— statsmodels获得类似级别的细节。需要记住的一点是,当在statsmodels中使用线性回归时,我们需要添加一列 1 作为截距。为此我使用了add_constant。结果比来自sklearn的默认结果信息丰富得多。

所以现在我们来看看如何在 R 和 Python 中运行线性回归。让我们继续假设。我把这些分成两部分:

  • 高斯-马尔可夫定理的假设
  • 其余的假设

3.高斯-马尔可夫定理

在您的统计学或计量经济学课程中,您可能听说过线性回归中的缩写词 BLUE。这是什么意思?根据高斯-马尔可夫定理,在线性回归模型中,普通最小二乘(OLS)估计器给出系数的最佳线性无偏估计器(蓝色),前提是:

  • 误差(残差)的期望值是 0
  • 误差是不相关的
  • 误差具有相等的方差——误差的同方差

此外,蓝色的“最佳”表示与其他无偏线性估计相比,导致估计的最低方差。

对于蓝色的估计器,残差不需要遵循正态(高斯)分布,也不需要独立且同分布

模型的线性

因变量(y)被假定为模型中指定的自变量(X,特征)的线性函数。规格参数必须是线性的。将线性模型拟合到具有非线性模式的数据会导致严重的预测错误,尤其是样本外(未用于训练模型的数据)。

为了检测非线性,可以检查观察值与预测值或残差与预测值的关系图。期望的结果是,在前一个图中,点对称地分布在对角线周围,或者在后一个图中,点对称地分布在水平线周围。在两种情况下都有大致恒定的方差。

观察到“弓形”模式表明,每当该模型做出异常大或小的预测时,它都会犯系统性错误。当模型包含许多特征时,非线性也可以通过残差与单个特征的关系图中的系统模式来揭示。

对图的检查表明,线性假设不满足。

潜在解决方案:

  • 因变量/自变量的非线性变换
  • 添加额外的功能,这些功能是已经使用的功能的转换(例如方形版本)
  • 添加以前没有考虑到的功能

残差的期望值(均值)为零

这个很容易检查。在 Python 中:

lin_reg.resid.mean()
# -1.0012544153465325e-13

而在 R:

%%R
mean(lin_reg$resid)
# 2.018759e-17

结果有点不同,据我所知,这是一个数值近似值问题。但是,我们可以假设残差的期望值确实是 0。

无(完全)多重共线性

换句话说,这些特征应该是线性独立的。这在实践中意味着什么?我们不应该能够使用一个线性模型来准确地预测一个特征使用另一个特征。让我们以 X1 和 X2 作为特征的例子。有可能发生 X1 = 2 + 3 * X2,这违背了假设。

需要注意的一个场景是“虚拟变量陷阱”——当我们使用虚拟变量对分类特征进行编码时,不要忽略模型中的基线水平。这导致虚拟变量和常数项之间的完美关联。

多重共线性可以存在于模型中,只要它不是“完美”的。在前一种情况下,估计效率较低,但仍然是无偏的。估计会不太精确,对特定的数据集高度敏感。

我们可以使用方差膨胀因子 (VIF)来检测多重共线性。在不涉及太多细节的情况下,VIF 的解释如下:给定变量的 VIF 的平方根显示了与该预测因子与模型中的其他要素不相关的情况相比,标准误差要大多少。如果没有相关的要素,则 VIF 的所有值都将为 1。

%%R
library(car)
vif(lin_reg)

为了处理多重共线性,我们应该反复移除具有高 VIF 值的要素。移除的经验法则可能是 VIF 大于 10 (5 也是常见的)。另一种可能的解决方案是使用 PCA 将特征减少到一个更小的不相关组件集。

提示:我们还可以查看特性的相关性矩阵,以确定它们之间的依赖关系。

残差的同方差(等方差)

当残差不具有恒定方差时(它们表现出异方差),很难确定预测误差的真实标准差,通常会导致置信区间过宽/过窄。例如,如果残差的方差随着时间的推移而增加,样本外预测的置信区间将变得非常窄。异方差的另一个影响也可能是在估计系数时对数据子集(误差方差最大的子集)赋予过多的权重。

为了研究残差是否是同方差的,我们可以查看残差(或标准化残差)与预测值(拟合值)的关系图。我们应该警惕残差作为预测值或时间的函数增长的情况(在时间序列的情况下)。

我们也可以使用两种统计检验:Breusch-Pagan 和 Goldfeld-Quandt。在这两种情况下,零假设假设假设同异方差,而低于某一水平(如 0.05)的 p 值表明我们应该拒绝零假设而支持异方差。

在下面的片段中,我绘制了残差(和标准化值)与拟合值的关系,并进行两个提到的测试。为了确定图中的同方差,点的放置应该是随机的,并且不应该有可见的模式(残差值的增加/减少)- R 图中的红线应该是平的。我们可以看到,对于我们的数据集,情况并非如此。

结果表明,假设不成立,我们应该拒绝同异方差假设。

潜在解决方案:

  • 因变量的对数变换
  • 在时间序列的情况下,如果它涉及货币价值,则对序列进行缩减
  • 使用 ARCH(自回归条件异方差)模型来模拟误差方差。一个例子可能是股票市场,其中的数据可以显示随着时间的推移波动性增加或减少的周期(波动性聚类,参见本文了解更多信息)

无残差自相关

这种假设在时间序列模型中尤其危险,因为残差中的序列相关性意味着模型还有改进的空间。极端的序列相关性通常是模型严重错误的标志。残差中序列相关的另一个原因可能是违反了线性假设,或者是由于可以用省略变量(可识别条件的交互项或虚拟变量)解释的偏差。前一种情况的一个例子可能是对数据拟合一条(直线),该数据随时间呈指数增长。

这个假设在非时间序列模型的情况下也有意义。如果残差在特定条件下总是具有相同的符号,这意味着当预测者具有特定配置时,模型系统地低估/高估了发生的情况。

为了研究自相关是否存在,我使用了 ACF(自相关函数)图和 Durbin-Watson 检验。

在前一种情况下,我们希望了解 ACF 的值对于任何滞后是否显著(如果没有时间序列数据,则使用行号)。在调用该函数时,我们指出我们感兴趣的显著性水平(更多细节见本文),并在图上标出关键区域。显著的相关性不在这个范围之内。

注意:当处理没有时间维度的数据时,我们可以选择绘制残差与行号的关系。在这种情况下,应以(仅)取决于要素值的方式对行进行排序。

第二种方法是使用德宾-沃森测试。我不会详细介绍它是如何构造的,但会提供一个高层次的概述。检验统计提供了对滞后 1 处的显著残差自相关的检验。DW 统计大约等于2(1-a),其中a是滞后 1 残差自相关。DW 测试统计位于statsmodels回归的默认汇总输出中。

关于德宾-沃森测试的一些注释:

  • 测试统计值总是介于 0 和 4 之间
  • 值为 2 表示样本中没有自相关
  • 数值< 2 indicate positive autocorrelation, values > 2 负一。

潜在解决方案:

  • 在轻微正自相关的情况下,可能有一些微调模型的空间,例如,添加因变量/自变量的滞后
  • 模型可能无法捕捉到某些季节性因素,请使用虚拟变量或季节性调整变量来解释这些因素
  • 如果 DW < 1,则可能表明模型规范中可能存在问题,考虑通过差分、记录和/或缩减(在货币值的情况下)对时间序列变量进行平稳化
  • 在显著负相关的情况下,一些变量可能被过度区分
  • 使用广义最小二乘法
  • 包括线性(趋势)项,以防残差中出现一致的增加/减少模式

4.其他假设

下面我介绍一些其他的线性回归的普遍验证的假设。

特征和残差是不相关的

为了研究这个假设,我检查了每个特征和残差之间的皮尔逊相关系数。然后报告 p 值,以测试两个考虑系列之间缺乏相关性。

我不能拒绝任何一对的零假设(缺乏相关性)。

观察的数量必须大于特征的数量

这个很简单。我们可以通过使用 Python 中的shape方法或 r 中的dim函数来检查数据的形状。此外,根据经验,我们应该在数据集中有 30 个以上的观察值。这取自中心极限定理,该定理指出,当样本大小大于 30 时,即使随机变量本身不是高斯型的,添加 IID 随机变量也会导致归一化分布。

特征上肯定有一些可变性

这种假设表明特征中一定存在一些差异,因为对于所有或大多数观察值具有恒定值的特征可能不是一个好的预测器。我们可以通过简单地检查所有特征的方差来检验这个假设。

X.apply(np.var, axis=0)

在 R 的caret包中有一个名为nearZeroVar的函数,用于识别方差为零或接近零的特性。

%%R
library(caret)apply(X, 2, var)
nearZeroVar(X, saveMetrics= TRUE)

残差正态性

当这个假设被违反时,它会导致计算置信区间和系数的各种显著性测试的问题。当误差分布明显偏离高斯分布时,置信区间可能太宽或太窄。

导致非正态残差的一些潜在原因:

  • 数据中存在一些大的异常值
  • 模型假设可能存在一些其他问题(违规)
  • 另一个更好的模型规范可能更适合这个问题

从技术上讲,如果我们假设模型方程是正确的,并且我们的目标是估计系数并生成预测(在最小化均方误差的意义上),我们可以忽略这个假设。

然而,通常我们感兴趣的是从模型中做出有效的推断,或者估计给定预测误差在特定方向上超过某个阈值的概率。为此,必须满足关于残差正态性的假设。

为了研究这个假设,我们可以看看:

  • 残差的 QQ 图(详细描述可以在这里找到)。例如,偏离对角线的弓形模式意味着残差具有过度的偏斜度(即,分布是不对称的,在一个方向上有太多的大残差)。s 形偏差模式意味着残差的峰度过大——在两个方向上都有太多或两个大误差。
  • 使用统计检验,如科尔莫戈罗夫-斯米尔诺夫检验、夏皮罗-维尔克检验、贾尔克-贝拉检验和安德森-达林检验

根据上述结果,我们可以推断残差不遵循高斯分布——根据 QQ 图的形状,以及在所有统计测试中拒绝零假设。来自ols_test_normality的 Kolmogorov-Smirnov 显示不同结果的原因是它没有运行“双边”版本的测试。

潜在解决方案:

  • 目标变量或特征非线性变换
  • 移除/处理潜在的异常值
  • 可能会出现两个或两个以上的数据子集具有不同的统计特性,在这种情况下,可以考虑单独的模型

5。奖金:异常值

这不是一个真正的假设,然而,在我们的数据中异常值的存在会导致违反上述一些假设。这就是为什么我们应该调查数据,并核实一些极端的观察是否有效,对我们的研究是否重要,或者仅仅是一些我们可以消除的错误。

我不会深究离群点检测方法,因为已经有很多关于它们的文章了。一些可能的方法:

  • z 分数
  • 箱形图
  • 杠杆-衡量一个点的特征值与不同观测值之间的距离。高杠杆点是变量的极值点,在该点附近缺少观测值使得拟合的回归模型接近该特定点。
  • 库克距离-衡量删除观察如何影响回归模型的一种方法。调查具有高库克距离的点是有意义的。
  • 隔离森林——更多详情见这篇文章

6.结论

在本文中,我展示了线性回归的假设是什么,如何验证它们是否满足,以及我们可以采取哪些潜在的步骤来解决模型的潜在问题。本文使用的代码可以在 GitHub 上找到。

一如既往,我们欢迎任何建设性的反馈。你可以在推特上或者评论里联系我。

喜欢这篇文章吗?成为一个媒介成员,通过无限制的阅读继续学习。如果你使用这个链接成为会员,你将支持我,而不需要额外的费用。提前感谢,再见!

参考

  1. http://people.duke.edu/~rnau/testing.htm

数据科学家的版本控制:实践介绍

原文:https://towardsdatascience.com/version-control-for-data-scientists-a-hands-on-introduction-4a9f3d33edfd?source=collection_archive---------20-----------------------

从历史上看,许多数据科学家不使用像版本控制系统这样的“软件开发”工具。如今,随着他们的代码变得越来越复杂,数据科学家越来越多地受到他们的软件工程合作伙伴的影响,学习如何熟练地使用 Git 这样的版本控制系统变得越来越重要。

在这个简短的动手介绍中,您将学到足够的 Git,以便当您获得一份数据科学家的工作时,能够跟踪您的变化,并与您的同事分享。

什么是版本控制?

版本控制系统允许你跟踪你对你的工作所做的改变。这有点像谷歌文档中的“跟踪修改”,但不同的是,你可以保存一组文件的修改,而不仅仅是单个文件内的修改。大多数版本控制系统也支持分支的思想,允许不同的人对相同的底层文件进行不同的更改,然后在以后将他们的工作合并在一起。

数据科学家如何使用版本控制?

作为一名数据科学家,即使你只处理一个文件(比如一个 Jupyter 笔记本),你也可以使用版本控制系统来跟踪你的变更(通常会这样)。它允许您定期保存您的工作,这使得您可以轻松地将笔记本恢复到早期版本。

随着项目变得越来越复杂,版本控制变得更加有价值。用一个 Jupyter 笔记本开始一个项目是很常见的。随着时间的推移,笔记本变得充满了清理导入数据的小功能,以至于很难专注于笔记本的重要部分。

解决这个问题的一个好方法是将这些函数分解成单独的 Python 文件,您可以使用一行代码调用这些文件。通过这种方式,任何希望了解您的项目的人都可以从 Jupyter 笔记本中获得一个高层次的视图,然后如果他们想了解您的数据清理脚本的细微差别,他们可以随时深入研究您的支持 Python 文件。这种策略也使得编写自动化单元测试来确认您的数据清理脚本将您期望的转换应用于各种类型的输入变得更加容易。

一旦您的项目有多个需要保持同步的文件,像 Git 这样的版本控制系统就特别有用,因为它允许您对多个文件进行一系列更改,然后将它们一起“提交”,这样您就可以轻松地将所有文件恢复到提交后的状态。

安装 Git

如果你还没有安装 Git,请点击这里,按照你的操作系统的安装程序进行操作。

Git 101

让我们从定义几个关键概念开始,这些概念在我们讨论 Git 时会有所帮助:

  • 一个库——这是 Git 对一个项目的名称。它包括项目中的所有文件,以及它们如何随时间变化的所有信息。如果您有一个存储库的完整副本(通常称为“repo”),您可以查看项目的当前状态,但也可以查看项目以前所处的任何状态。
  • 提交 —在 Git 中,历史由一系列保存在变更日志中的提交组成。每当您对项目进行一组有意义的更改时,您都应该提交它们,这样您就可以在将来将项目恢复到那个状态。
  • 暂存区 —这就像一个用于版本控制的购物篮。在这里,您可以加载您希望在下一次提交时使用的更改集,因此,如果您编辑了三个文件,但希望对其中两个文件进行一次提交,对第三个文件进行另一次提交,您只需使用命令“暂存”前两个文件,然后使用适当的消息提交它们,然后分别添加和提交最后一个文件。

Git 入门

让我们用 Git 做一些实践。如果你用的是 windows,打开“Git Bash”程序,如果你用的是 Mac 或 Linux,只需打开一个终端窗口。重要的是不要在 windows 机器上只打开 Powershell 或默认终端——它不会正常工作。

转到您的主目录中的某个目录(这样您就有写权限)。让我们确保您还没有在一个属于 Git 存储库的目录中(不太可能,但是会发生):

> git status
fatal: not a git repository (or any of the parent directories): .git 

很好。我们向 Git 询问我们所在的存储库的状态,它让我们知道我们不在 Git repo 中。这很好——在另一个中创建一个 Git repo 会让您和 Git 都感到困惑!

现在让我们创建一个新的 Git repo 和目录:

> git init my_first_repo 
Initialized empty git repository in /Users/peterbell/Dropbox/code/my_first_repo/.git/

完美。所以它在我所在的目录下创建了一个存储库。让我们使用 Unix 的“更改目录(cd)”命令去那里:

**>** cd my_first_repo
my_first_repo git:(master) 

好了,我的终端通过显示git:(master)消息来告诉我什么时候我在 Git repo 中。让我们看看这个项目的状态:

> git status
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)

酷毙了。如果您看到稍微不同的消息,不要担心——它们因操作系统和 Git 版本而异,但底线是 Git 告诉我们还没有任何提交,我们在“主”分支(主分支)上,这里没有任何文件要保存到版本控制中。

初始配置

让我们检查一下您是否有 Git 的基本配置,这样当您保存文件时,它就知道您的姓名和电子邮件地址。

> git config --global user.name
Peter Bell

使用上面的命令,我们可以访问您计算机上 Git 的配置设置。*--global*标志意味着我们正在查看配置设置,这些设置将应用于您在这台机器上作为这个用户登录的所有项目。不常见的*--system*标志用于访问机器上所有用户共享的设置。最后,*--local*标志访问特定项目的设置——所以只有当您运行命令时,它才在 Git repo 中工作。

当您向 git config 传递一个不带值的键(在本例中是键)时,它返回现有的值。如果您还传递了一个值,它将设置该值。根据您的设置,您可能会看到您的名字,什么也没看到,一条 Git 没有正确设置的消息,甚至一条找不到文件的错误消息。如果你看到除了你的名字之外的任何东西,像这样设置你的名字:

> git config --global user.name ‘Your Name’ 

然后运行:

> git config --global user.name
Your Name

现在你应该看到你的名字了!让我们为您的电子邮件地址做同样的事情:

> git config --global user.email
this@that.com

如果它没有您想要的值,请将其设置为某个值。不需要引号:

> git config --global user.email this@that.com 
> git config --global user.email 
this@that.com

还有很多其他的设置,但是至少 Git 现在知道用什么名字和电子邮件地址来保存你的提交了!

添加一些文件

创建测试文件最简单的方法是使用 Unix 命令“touch”如果文件存在,它只会更新时间戳。如果没有,它将创建一个空白文件,然后我们可以添加到版本控制中。

所以让我们创建三个文件。它们不会有任何内容,但我们会给它们起一些名字,在进行真正的数据科学项目时可能会用到。

> touch index.ipynb 
> touch import.py 
> touch clean.py 
> git status 
On branch master 
No commits yet 
Untracked files: (use "git add <file>..." to include in what will be committed) 
      clean.py 
      import.py 
      index.ipynb 
nothing added to commit but untracked files present (use "git add" to track) 

好的,我们还是在主分支上。我们还没有提交(保存到 Git 中的永久历史中),这三个文件是“未被跟踪的”——在我们添加它们之前,Git 并没有真正关注它们。

现在假设我们想对 Jupyter 笔记本文件(index.ipynb)进行一次初始提交,然后对导入和清理脚本进行另一次提交。

> git add index.ipynb
> git status
On branch master 
No commits yet
Changes to be committed 
  (use "git rm --cached <file>..." to unstage)
      new file:   index.ipynb
Untracked files:
  (use "git add <file>..." to include in what will be committed)
      clean.py
      import.py

这告诉我们,当我们现在提交时,index.ipynb 文件将被保存。让我们这样做:

> git commit -m 'Add Jupyter Notebook file' 
[master (root-commit) 998db10] Add Jupyter Notebook file 
1 file changed, 0 insertions(+), 0 deletions(-) 
create mode 100644 index.ipynb

好吧,这是怎么回事?首先,我告诉 Git 提交—将这组更改保存到历史中。我向它传递了-m标志,以传递提交消息。我在-m后面加上了我希望与这个提交相关联的消息,用单引号或双引号括起来。提交消息的目的是让将来的任何人都更容易理解我做了什么更改以及为什么做这些更改。

重要的是要知道,每次提交都需要两件事——一条提交消息和至少一个添加、修改、重命名或删除的文件。根据您的操作系统和 Git 的版本,如果您没有传递提交消息,它要么会为您创建一个默认消息,要么会将您扔进您与 Git 一起使用的任何文本编辑器(注意,它可能有点像 vi )来添加提交消息。

而回应是什么意思?嗯,它告诉我们,我们仍然在主项目上,我们刚刚对这个项目进行了根(非常第一次)提交。它为我们提供了十六进制 SHA-1 哈希的前 7 个字符,这是 Git 存储库中每次提交的唯一标识符,它共享了我的提交消息以及有多少文件被更改。在本例中,我们添加了 1 个文件,但是没有添加或删除任何内容行,因为文件是空的。它还显示了提交中的文件(index.ipynb ),并显示“创建模式 100644 ”,您几乎可以忽略它。

酷毙了。我们现在的 Git 状态如何?

> git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
	clean.py
	import.py
nothing added to commit but untracked files present (use "git add" to track)

完美。所以它看到我们还有两个未被跟踪的文件。让我们将它们添加到临时区域:

> git add . 

在 Git 中,有很多方法可以将文件添加到“暂存区”。您可以一次给它们命名一个(git add clean.py import.py)。您可以使用 fileglob 模式(git add *.py)匹配一组文件,或者您可以只添加 repo 中的所有文件(git add .)。

无论采用哪种方法,都会将另外两个新文件添加到临时区域。

> git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
	new file:   clean.py
	new file:   import.py

所以我们要做的就是承诺他们:

> git commit -m ‘Add import and cleaning scripts’
[master 625e7a1] Add import and cleaning scripts
 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 clean.py
 create mode 100644 import.py

很好——它在 master 上进行了一次新的提交(对我来说是625e7a1—对你来说会有所不同,因为它部分基于这次和以前提交中使用的用户名和电子邮件),并添加了两个新文件(但没有文本行,因为在这个简单的教程示例中,它们都是空白文件)。

恭喜你!您刚刚创建了一个新的 Git repo,并暂存和添加了一些文件!

集结地是怎么回事?

现在,你可能会问一个非常合理的问题“为什么我们必须运行两个单独的命令 *git add* 然后 *git commit* 来保存我们的工作?”

首先,这不是你必须一直做的事情。作为一名数据科学家,您将大部分时间花在修改文件上——通常是您的 Jupyter 笔记本和一些支持 Python 的文件。当你修改文件时,Git 给出了一个快捷方式git commit -am “your message here*"*,它将在一行中添加修改的文件并提交它们,所以大多数时候你只需要键入一个命令。

但是 staging area 的真正强大之处在于,每当您做出多个更改,然后想要返回并将它们分类到单独的提交中时。

您可能会问“为什么要有一堆不同的提交呢?”这是一个特别常见的问题,来自那些使用过 subversion 之类的旧版本控制系统的人,在 subversion 中提交是一个较慢的过程,他们通常只是写一整天的代码,然后保存他们的更改,并显示一条类似于“我在周一做的事情”的信息!

创建有意义的提交消息的原因很重要,每种类型的更改都有一个提交(“更新的可视化”、“添加了一个分类数据的热编码”等),这样当您或您的团队回到您的日志时,就很容易理解您是如何到达这里的,并找到甚至恢复(撤销)任何有问题的东西。这和你不把你的变量命名为“a”、“b”和“c”是一个道理——计算机不会介意,但是下次你拿起代码并试图弄清楚它到底是什么的时候,它不会让你的生活变得更容易!

后续步骤

关于 Git 还有很多要学的。我们还没有介绍分支、从远程服务器推和拉、撤销更改、更高级的配置设置,或者如何检查以前的提交,但是一旦您理解了 staging area 的基本原理,您将会领先于许多已经使用 Git 一段时间的人。在接下来的几周里,请关注本系列的更多文章!

最初发表于

版本控制 ML 模型

原文:https://towardsdatascience.com/version-control-ml-model-4adb2db5f87c?source=collection_archive---------1-----------------------

dvc workflow from https://dvc.org

机器学习操作(姑且称之为 mlOps 在当前的流行语格局 xxOps 下)与传统的软件开发操作( devOps )有很大的不同。原因之一是 ML 实验除了代码(小的纯文本文件)之外,还需要大的数据集和模型工件。

这篇帖子提出了一个用 git 和 dvc ( 数据版本控制)对机器学习模型进行版本控制的解决方案。

此解决方案将提供以下功能:

  1. ML 模型具有可伸缩性、安全性、可用性和几乎无限的存储空间
  2. ML 模型受版本控制,即它的任何特定版本都可以被方便地标记和访问
  3. ML 模型的可审计性、透明性和可再现性可以通过版本控制数据集和分析代码来保证
  4. 基于现有的模型设置,新的实验可以被快速和协作地初始化

吉特和 DVC

该解决方案包括两层版本控制:

  1. git :处理代码和元数据(数据集和模型工件的)
  2. dvc :处理大型数据集和模型工件

首先,我们准备好项目文件夹并安装好工具。

# Download code
git clone [https://github.com/iterative/example-versioning.git](https://github.com/iterative/example-versioning.git)
cd example-versioning# install and initialize git
# install and initialize dvc ([https://dvc.org/doc/get-started/install](https://dvc.org/doc/get-started/install))

然后将 dvc 连接到后端存储,数据集和模型工件将实际存储在这里(在本例中为 AWS S3 )。

dvc remote add -d s3remote s3://[my-test-bucket-dvc](https://console.aws.amazon.com/s3/#)/myproject 

现在,在我们将进行 ML 实验的示例版本化文件夹中,应该包含两个元数据子文件夹。

.dvc/
.git/

工作流程

下一步,我们使用来自 dvc.org 的数据和脚本训练一个模型

cd example-versioning# Install dependencies
pip install -r requirements.txt# Download data
cd example-versioning
wget [https://dvc.org/s3/examples/versioning/data.zip](https://dvc.org/s3/examples/versioning/data.zip)
unzip data.zip
rm -f data.zip# Build the ML model
python train.py

获得模型(model.h5)后,使用 dvc + git 工作流将其置于版本控制之下。

步骤 1:向 dvc 添加模型元数据

dvc add model.h5

输出:

可以观察到:

  • “真实”模型存储在。dvc/cache/40
  • 模型元数据 model.h5.dvc 记录它在哪里

步骤 2:通过将模型推送到后端存储来持久化模型

dvc push model.h5.dvc

在 s3 中,我们可以在模型元数据的指导下检查模型是否被正确存储

步骤 3:用 git 持久化模型元数据

模型元数据可以引导我们找到存储在后端存储中的真正的模型对象。为了防止丢失元数据,应该使用 git 将它添加到版本控制中。

git add .gitignore model.h5.dvc data.dvc metrics.json
git commit -m "model first version, 1000 images"
git tag -a "v1.0" -m "model v1.0, 1000 images"

这里可以使用“git 标签”来记录模型的版本。

第四步:随时访问模型

通过搜索 git branch 上的标签,很容易获取模型的特定版本。从 git 中,我们可以检查模型元数据。

git checkout tags/<tag_name> -b <branch_name>

根据元数据,我们可以找到模型对象,并使用命令将其下载到当前工作区

dvc pull model.h5.dvc

结论

同理,也可以解决机器学习实验的大数据集版本控制问题。解决 ML 管道挑战的其他类似工具例如有ML flowdatanami神圣

很有空间感!基于人工智能的视差 3D 视频。

原文:https://towardsdatascience.com/very-spatial-507aa847179d?source=collection_archive---------14-----------------------

三维本·伯恩斯效应

T T 以下是我热爱 AI 开发的几个原因。新技术途径意想不到的可能性令人惊喜的品质。并且:团队工作。每个模型背后都有人,他们编写、测试、增强、审查模型。

人的因素是人工智能背后最重要的因素。

在这个 3D 本·伯恩斯模型的情况下也是如此。

本·伯恩斯效应。

本·伯恩斯效应 得名于电影纪录片导演本·伯恩斯,他用变焦和相机移动曝光静态照片来模拟视频镜头。

后来,这种效果通过视差效果得到了增强,静止图像被分成几层,类似于剧院舞台装饰。来模拟深度。并且虚拟摄像机在第三维中移动。它有各种各样的用途——用于视频游戏(模仿第三维),用于网站(沉浸式体验),用于电影(重复使用照片作为动态镜头)。

Layered scene — from a computer game The Whispered World (source).

这种方法早在 20 世纪 20-30 年代就已经被德国动画师洛塔·赖尼格采用了。这里你也可以看到这样的分层背景是如何在没有任何 CGI 的情况下实现的:

对于视频,您可以手动使用 Photoshop+Adobe After effects,或者像“Photomotion”这样的特殊解决方案来制作视差视频。就像我曾经做过的多语言项目一样。

但是——人工智能提供了新的可能性!

因此,一个研究团队:西蒙·尼克劳斯(波特兰州立大学)、龙脉(Adobe Research)、杨笈每(Adobe Research)和刘峰(波特兰州立大学)致力于基于深度学习的解决方案:

3D 本·伯恩斯效应。
论文:《单幅图像的 3D 本·伯恩斯效应》https://arxiv.org/abs/1909.05483

上下文感知修复和深度估计是关键词。

Source: Paper “3D Ken Burns Effect from a Single Image

该模型可以识别背景,模拟深度,用内容敏感的填充来填充缺失的区域,添加新的角度——简而言之:用一张图像就可以制作一个空间 3D 视频镜头。

观看由撰写的 2 分钟的论文卡罗利·佐尔奈-费希尔视频解释这一模式(一如既往地提供大量信息):

本周,西蒙·尼克劳斯可能会从 Adobe 获得公开代码的批准(= > GitHub )。

从现在开始,每个人都可以尝试这个解决方案,比如人工智能研究员兼艺术家乔纳森·弗莱:

或者博客作者兼技术专家安迪·拜奥:

或者我自己:

它可以完美地处理街道的透视图像,也可以处理室内。

Andy Baio 在他的 Waxy.org 博客中发布了一个历史照片平行排列的图库(如果你想的话,也可以是 3d 立体图)。在这篇博文中,他还发布了他的 Colab 笔记本,并配有 3D 本·伯恩斯模型以供试用。电脑工程师马努·罗梅罗对笔记本进行了一些改进,包括多张图片上传

这就是:一个 3D 本·伯恩斯效果的 Colab 笔记本。

这里是我的一些结果。请注意深度和 3D 尺寸的显著识别。

在评论中发布你自己视差照片的结果。

更新 1(2020 年 1 月 22 日)。

通过使用 #DeOldify 和 3D 本·伯恩斯效果,我们可以让一条古老的纽约街道重现生机:

[## 重现历史

正在使用的深度学习模型

towardsdatascience.com](/re-animated-history-6b5eb1a85efa)

更新 2(2020 年 1 月 22 日)

如果对“autozoom.py”中的参数进行微调,可以得到有趣的结果。例如,这些值

objectTo = process_autozoom({'dblShift': 10.0,'dblZoom': 10000000000000000000000000000000000000000000000000000000,'objectFrom': objectFrom})numpyResult = process_kenburns({'dblSteps': numpy.linspace(0.0, 8.0, 400).tolist(),'objectFrom': objectFrom,'objectTo': objectTo,'boolInpaint': True})

产生更长的摄像机飞行时间:

因为团队合作仍在继续——现在用创造性的方法!

基于 Python 和 Keras 的血管分割

原文:https://towardsdatascience.com/vessel-segmentation-with-python-and-keras-722f9fb71b21?source=collection_archive---------3-----------------------

Photo by Erica Leong on Unsplash

动机:

医学图像的自动分割是提取有用信息帮助医生做出诊断的重要步骤。例如,它可以用于分割视网膜血管,以便我们可以表示它们的结构并测量它们的宽度,这反过来可以帮助诊断视网膜疾病。

在这篇文章中,我们将实现一个神经基线,对视网膜血管图像进行图像分割。

数据集:

http://www.isi.uu.nl/Research/Databases/DRIVE/browser.php

我们使用 DRIVE(用于血管提取的数字视网膜图像)数据集进行所有实验。它是 40 个视网膜图像(20 个用于训练,20 个用于测试)的数据集,其中在像素级(参见上面的例子)对血管进行注释,以在图像的每个像素(I,j)处标记血管的存在(1)或不存在(0)。

问题设置:

问题:我们想给每个像素分配一个“1”标签,如果它是图像中血管的一部分,否则为“0”。
直觉 / 假设:相邻像素值对于对每个像素(I,j)进行预测很重要,所以我们应该考虑上下文。预测不依赖于图像上的特定位置,因此分类器应该具有某种平移不变性。
解决方案:用 CNN!我们将使用 U-net 架构来进行血管分割。它是一种广泛用于语义分割任务的架构,尤其是在医学领域。

型号:

U-net

U-net 架构是一个编码器-解码器,在编码器和解码器之间有一些跳跃连接。这种架构的主要优点是在对像素进行预测时能够考虑更广泛的背景。这得益于上采样操作中使用的大量通道。

输入图像处理:

我们在把它传送给 CNN 之前应用了这一系列的处理步骤。

  • 标准化:我们将像素强度除以 255,因此它们在 0-1 的范围内。
  • 裁剪:由于汇集操作,网络希望输入图像的每个维度都能被 2⁴整除,因此我们从每个图像中随机裁剪 64*64。
  • 数据扩充:随机翻转(水平或垂直或两者)、随机剪切、随机平移(水平或垂直或两者)、随机缩放。仅在培训期间执行。

我们训练模型的三个变体:

  • 预先接受过 ImageNet VGG 编码器+数据增强的培训。
  • 从零开始训练+数据扩充。
  • 在没有数据扩充的情况下从头开始训练。

我们将使用 AUC ROC 指标来比较这三个模型,并且我们将在评估中仅考虑视网膜掩膜内的像素(这意味着图像圆圈周围的黑边将不计算在内)。

结果:

  • 从零开始训练+数据增强 AUC ROC : 0.9820
  • 从零开始训练,没有增加 AUC ROC : 0.9806
  • 预训练编码器+数据增强 AUC ROC : 0.9811

这三种变体的性能很接近,但在这种情况下,预训练似乎没有帮助,而数据扩充有一点帮助。

Best model predictions

上图中的预测看起来相当酷!😄

Predictions on top of ground Truth

我们还画出了预测和实际情况之间的差异:蓝色为假阴性,红色为假阳性。我们可以看到,该模型在预测只有一两个像素宽的精细血管时存在一些困难。

结论:

在这篇文章中,我们实现了一个神经网络来进行图像分割,应用于视网膜图像中的血管检测。我们获得的 AUC ROC 值为 0.9820 ,非常接近最先进水平(https://paperswithcode.com/search?q=vessel)。关于实验结果,我发现最有趣的是,对于像这样的一些任务,我们可以在少至 20 张图像上训练一个深度神经网络,并仍然获得良好的性能和非常酷的结果。

重现结果的代码可从这里获得:https://github.com/CVxTz/medical_image_segmentation

如果你有任何建议,请不要犹豫发表意见😸

VGG 神经网络:AlexNet 之后的下一步

原文:https://towardsdatascience.com/vgg-neural-networks-the-next-step-after-alexnet-3f91fa9ffe2c?source=collection_archive---------3-----------------------

2012 年 AlexNet 问世,是革命性的进步;它改进了传统的卷积神经网络(CNN),成为图像分类的最佳模型之一……直到 VGG 问世。

Photo by Taylor Vick on Unsplash

AlexNet。当 AlexNet 发布时,它轻松赢得了 ImageNet 大规模视觉识别挑战赛(ILSVRC ),并证明了自己是最有能力的对象检测模型之一。它的主要特性包括使用 ReLU 代替 tanh 函数、针对多个 GPU 的优化以及重叠池。它通过使用数据扩充和删除来解决过拟合问题。那么 AlexNet 到底出了什么问题?嗯,没有什么,比如说,特别“错误”的。人们只是想要更精确的模型。

数据集。图像识别的一般基线是 ImageNet,这是一个由超过 1500 万张图像组成的数据集,标记有超过 22,000 个类别。通过网络抓取图像和众包人类贴标机,ImageNet 甚至举办了自己的竞争:前面提到的 ImageNet 大规模视觉识别挑战(ILSVRC)。来自世界各地的研究人员面临着创新方法的挑战,以产生最低的前 1 名和前 5 名错误率(前 5 名错误率将是正确标签不是模型的五个最可能标签之一的图像的百分比)。比赛给出 120 万幅图像的 1000 类训练集,5 万幅图像的验证集,15 万幅图像的测试集;数据是丰富的。AlexNet 在 2012 年赢得了这场比赛,基于其设计的模型在 2013 年赢得了比赛。

Configurations of VGG; depth increases from left to right and the added layers are bolded. The convolutional layer parameters are denoted as “conv”. Image credits to Simonyan and Zisserman, the original authors of the VGG paper.

VGG 神经网络。虽然 AlexNet 以前的衍生产品专注于第一卷积层的较小窗口大小和步长,但 VGG 解决了 CNN 的另一个非常重要的方面:深度。让我们来看看 VGG 的建筑:

  • 输入。 VGG 接受 224x224 像素的 RGB 图像。对于 ImageNet 竞赛,作者在每个图像中裁剪出中心 224x224 的补丁,以保持输入图像大小一致。
  • 卷积层。VGG 的卷积层使用非常小的感受域(3x3,仍然可以捕捉左/右和上/下的最小可能尺寸)。还有 1x1 卷积滤波器,它充当输入的线性变换,后跟一个 ReLU 单元。卷积步距固定为 1 个像素,以便在卷积后保持空间分辨率。
  • 全连接层。 VGG 有三个全连接层:前两层各有 4096 个通道,第三层有 1000 个通道,每个类别一个通道。
  • 隐藏层。VGG 的所有隐藏层都使用 ReLU(Alex net 的一项巨大创新,减少了训练时间)。VGG 通常不使用本地响应标准化(LRN),因为 LRN 增加了内存消耗和训练时间,但准确性没有特别提高。

区别。 VGG 虽然基于 AlexNet,但它与其他竞争车型有几个不同之处:

  • VGG 没有使用像 AlexNet 这样的大感受野(11x11,步幅为 4),而是使用非常小的感受野(3x3,步幅为 1)。因为现在有三个 ReLU 单元,而不是只有一个,所以决策函数更具区分性。参数也更少(27 倍通道数而不是 AlexNet 的 49 倍通道数)。
  • VGG 合并了 1x1 卷积层,以在不改变感受野的情况下使决策函数更加非线性。
  • 小尺寸卷积滤波器允许 VGG 具有大量的权重层;当然,层数越多,性能越好。不过,这并不是一个不常见的特性。GoogLeNet 是另一个使用深度 CNN 和小型卷积滤波器的模型,也在 2014 年的 ImageNet 竞赛中亮相。

Performance of VGG at multiple test scales. Image credits to Simonyan and Zisserman, the original authors of the VGG paper.

战果。在单个测试量表上,VGG 取得了 25.5%的前 1 名误差和 8.0%的前 5 名误差。在多个测试量表中,VGG 得到的前 1 名误差为 24.8%,前 5 名误差为 7.5%。VGG 还在 2014 年 ImageNet 竞赛中以 7.3%的前五名误差获得了第二名,提交后该误差降至 6.8%。

现在怎么办? VGG 是一种创新的物体识别模型,支持多达 19 层。作为一个深度 CNN,VGG 在 ImageNet 之外的许多任务和数据集上也优于基线。VGG 现在仍然是最常用的图像识别架构之一。

我在下面附上了一些有趣的资源

VGGNet vs ResNet

原文:https://towardsdatascience.com/vggnet-vs-resnet-924e9573ca5c?source=collection_archive---------7-----------------------

消失梯度问题的清晰答案!

Photo by Bench Accounting on Unsplash

"你能解释一下 VGGNet 和 ResNet 的区别吗?"是人工智能和机器学习领域的一个流行的面试问题。虽然答案就在网上,但我还没能找到一个简明扼要的答案。我们将从什么是 VGGNet 开始,它遇到了什么问题,以及 ResNet 是如何解决这个问题的。

VGGNet

VGG 代表视觉几何小组(一组牛津的研究人员开发了这种架构)。VGG 架构由块组成,其中每个块由 2D 卷积和最大池层组成。VGGNet 有两种风格,VGG16 和 VGG19,其中 16 和 19 分别是它们各自的层数。

Fig. 1 VGGNet architecture

在卷积神经网络(CNN)中,随着层数的增加,模型适应更复杂函数的能力也会增加。因此,层数越多越好(不要与人工神经网络混淆,后者不一定随着隐藏层数的增加而提供明显更好的性能)。所以现在你可以争论为什么不用 VGG20,或者 VGG50 或者 VGG100 等等。

嗯,有一个问题。

使用反向传播算法更新神经网络的权重。反向传播算法以减少模型损失的方式对每个权重进行小的改变。这是怎么发生的?它更新每个权重,以便在损失减少的方向上迈出一步。这个方向不过是这个重量的梯度(相对于损失)。

使用链式法则,我们可以找到每个重量的梯度。它等于(局部梯度)x(从前方流出的梯度),如图 2 所示。

Fig. 2 Flow of Gradients through a Neuron

问题来了。由于这个梯度不断流向初始层,这个值不断乘以每个局部梯度。因此,梯度变得越来越小,使得对初始层的更新非常小,大大增加了训练时间。

如果局部梯度不知何故变成了 1,我们就能解决这个问题。

瞧啊。输入 ResNet。

雷斯内特

局部梯度怎么会是 1,也就是说,哪个函数的导数总是 1?身份功能!

Fig. 3 Mathematics behind solving the Vanishing Gradient problem

因此,当这个梯度反向传播时,它的值不会减少,因为局部梯度是 1。

ResNet 架构,如下所示,现在应该可以很好地理解它是如何不允许渐变消失问题发生的。ResNet 代表残余网络。

Fig. 4 ResNet architecture

这些跳跃连接充当坡度高速公路,让坡度畅通无阻。现在你可以理解为什么 ResNet 有 ResNet50、ResNet101 和 ResNet152 这样的风格了。

我希望这篇文章对你有所帮助。

另一篇值得一读的文章:用 Keras 增强图像数据!

参考资料:

[1] 用于视觉识别的 CS231n 卷积神经网络作者 Andrej Karpathy。

2 K. Simonyan 和 A. Zisserman。用于大规模图像识别的非常深的卷积网络。2015 年在 ICLR。

3 K. He,X. Zhang,S. Ren 和 J. Sun,“用于图像识别的深度残差学习”,2016 年 IEEE 计算机视觉和模式识别会议(CVPR),拉斯维加斯,NV,2016 年,第 770-778 页。

[4] draw.io 供图。

视频:关于自动编码器的一切

原文:https://towardsdatascience.com/video-all-about-autoencoders-ab0a85b8d1fa?source=collection_archive---------42-----------------------

深入了解应用程序

A 自动编码器是一个非常强大的工具,可以利用未标记的数据来解决各种问题——你经常会在获奖的 Kaggle 提交文件以及先进的行业解决方案中发现它们的组件。例如,您可以使用它们来学习“特征提取器”,以帮助构建更强大的分类器,发现异常,或进行缺失值插补。

该视频介绍了自动编码器,深入探讨了它们的工作原理,并解释了如何使用它们。

想了解更多类似内容,可以在 blog.zakjost.com订阅我的邮件列表或者关注WelcomeAIOverlords YouTube 频道

Python 中张量分解的视频分析

原文:https://towardsdatascience.com/video-analysis-with-tensor-decomposition-in-python-3a1fe088831c?source=collection_archive---------13-----------------------

人工智能。深度学习。卷积神经网络。强化学习。这些都是机器学习领域的革命性进步,让不可能变成了可能。尽管有这些优点,也有缺点和限制。例如,神经网络由于需要庞大的训练集而容易过度拟合。它们通常是特定于任务的,并且它们的能力不能很好地转化到其他环境中。

Neural Network Illustration, by Arden Dertat, https://towardsdatascience.com/applied-deep-learning-part-1-artificial-neural-networks-d7834f67a4f6

虽然正在进行的研究解决了这些问题(我个人对 OpenAI 在人工通用智能方面的努力很感兴趣),但替代方法也可以拯救这些问题。例如,计算机视觉的主要挑战之一是涉及的数据量:一幅图像通常被表示为具有数百万元素的矩阵,而一个视频包含数千幅这样的图像。此外,这种数据中经常存在噪声。因此,减少维数的无监督学习技术是改进的潜在来源。

考虑到这一点,张量分解的概念在高维数据环境中尤其强大。在 Python 中实现这些思想来分析视频产生了重要的见解,并且可以在其他方法之前充当有用的预处理阶段。

高维数据

高维数据分析的概念指的是一组问题,其中特征的数量比观察值的数量大。在许多应用程序中(回归是最常见的),这会导致速度和模型学习问题,例如过度拟合或者甚至不可能产生模型。这在计算机视觉、材料科学甚至商业中很常见,因为互联网上捕获了大量数据。

一种解决方案是找到数据的低维表示,并在我们的模型中使用它作为训练观察值,因为维度减少缓解了上面列出的问题。这个低维空间通常包含大部分信息,因此是一个合适的替代物。样条、正则化和张量分解是这种方法的例子。我们将深入研究后一种方法,并看看它的一个应用。

Projecting 3D data onto a 2D plane. Credit: May Morrison

数学插曲

本文的核心概念是张量,它只是一个多维数组:

  • 数字是一个零维张量
  • 向量是一维张量
  • 矩阵是二维张量
  • 除此之外,我们只提到张量的维数

这种数据结构对于存储图像或视频特别有用。在传统的 RGB 模型中,单幅图像由一个 3D 张量表示:

  • 每个像素在矩阵中具有(x,y)坐标;因此,矩阵的大小取决于图像的分辨率
  • 每个颜色通道(红色、绿色、蓝色)都有自己的矩阵,矩阵中给定像素的值编码了这种特定颜色的强度

Representation of a 3D tensor. For an image, K = 3, and I and J depend on the resolution of the image. Credits: Kolda, Tamara G., and Brett W. Bader.

更进一步说,视频就是一系列的帧,每一帧都是一幅图像。这变得有点难以想象,但这可以存储在 4D 张量中:3 维用于存储单个帧,第四维编码时间的流逝。

Each slice is a 3D tensor for one frame, and there are multiple such slices over time. Credits: Kamran Paynabar

更具体地说,让我们以 60fps(每秒帧数)和 800 x 600 分辨率的 60 秒视频为例。这个视频可以存储在一个 800 x 600 x 3 x 3600 的张量中。因此它将有 50 亿个元素!这是太多的希望建立一个可靠的模型。这就是张量分解的用武之地。

有大量关于张量分解的文献,我向感兴趣的读者推荐科尔达和巴尔德关于这个主题的伟大研究。特别地,Tucker 分解有许多应用,例如张量回归,用张量作为目标或预测变量。关键是它允许提取核心张量,即原始数据的压缩版本。如果这让你想起了 PCA,那么你是正确的:Tucker 分解的步骤之一实际上是高阶奇异值分解,是 SVD 的扩展。

现有算法允许提取核心张量以及分解矩阵(在我们的应用中没有使用)。超参数是 n 秩。不涉及太多细节,主要思想是 n 秩值越高,分解越精确。n 阶也控制核心张量的大小。对于小的 n 秩,重建的张量可能不完全匹配原始张量,但是我们在降维方面获得了很多:权衡取决于手边的应用。

A, B and C are factorizing matrices while G is the core tensor, whose dimensions are specified by the n-rank. Credits: Kolda, Tamara G., and Brett W. Bader.

提取这个核心张量产生了重要的好处,正如我们在实际数据的应用中所看到的。

应用

举个玩具的例子,我用手机拍了三个 10s 的视频:

  • 我喜欢的咖啡馆的露台
  • 停车场
  • 在我下午通勤期间,汽车在高速公路上行驶

我把它们(和开发笔记本)上传到了 GitHub 上。我的主要目标是确定我们是否可以根据相似性对潜在的配对进行严格的排序,假设停车场和通勤视频最相似。

我利用流行的 OpenCV Python 库在分析之前加载和操作这些数据。步骤如下:

  • 创建 VideoCapture 对象并提取每个对象的帧数——我使用较短的视频来截断其他两个对象,以便有一个共同的比较基础
# Import libraries
import cv2
import numpy as np
import random
import tensorly as tl
from tensorly.decomposition import tucker# Create VideoCapture objects
parking_lot = cv2.VideoCapture('parking_lot.MOV')
patio = cv2.VideoCapture('patio.MOV')
commute = cv2.VideoCapture('commute.MOV')# Get number of frames in each video
parking_lot_frames = int(parking_lot.get(cv2.CAP_PROP_FRAME_COUNT))
patio_frames = int(patio.get(cv2.CAP_PROP_FRAME_COUNT))
commute_frames = int(commute.get(cv2.CAP_PROP_FRAME_COUNT))
  • 在适当维度的张量中阅读它们。我选择 TensorLy 和 tensors 一起工作
# Create function to read all frames of a video in an array
def read_frames(video_capture, max_frames):
    """
    INPUTS:
    video_capture: an OpenCV VideoCapture object whose frames we   want to read
    max_frames: the maximum number of frames we want to read

    OUTPUT:
    array of all the frames until max_frames
    """
    # Initialize empty array
    frames_array = []

    # Keep track of the frame number
    frame_nb = 0

    # iterate through the frames and append them to the array
    while video_capture.isOpened() and frame_nb < max_frames:
        ret, frame = video_capture.read()
        if not ret:
            break
        frames_array.append(frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        frame_nb += 1

    # release the video capture
    video_capture.release()
    cv2.destroyAllWindows()

    # return the array
    return(frames_array)# Read in all the videos
parking_lot_array = read_frames(video_capture=parking_lot, max_frames=commute_frames)patio_array = read_frames(video_capture=patio, max_frames=commute_frames)commute_array = read_frames(video_capture=commute, max_frames=commute_frames)# Create tensors from matrices
parking_lot_tensor = tl.tensor(parking_lot_array)
patio_tensor = tl.tensor(patio_array)
commute_tensor = tl.tensor(commute_array)
  • 从这些张量中随机抽取 50 帧,以加速未来的运算
# Set the seed for reproducibility
random.seed(42)
random_frames = random.sample(range(0, commute_frames), 50)# Use these random frames to subset the tensors
subset_parking_lot = parking_lot_tensor[random_frames,:,:,:]
subset_patio = patio_tensor[random_frames,:,:,:]
subset_commute = commute_tensor[random_frames, :, :, :]# Convert three tensors to double
subset_parking_lot = subset_parking_lot.astype('d')
subset_patio = subset_patio.astype('d')
subset_commute = subset_commute.astype('d')

经过这些步骤,就有了三个 50 x 1080 x 1920 x 3 的张量。我们可以继续分析。

结果

为了确定这些视频彼此之间的相似程度,我们需要一种方法来对它们进行排序。两个张量之差的 L2 范数是相似性的常用度量。较小的值与较大的相似性相关联。数学上,张量的范数是

Each I represents a given dimension, and x is a given element, identified by position

因此,差的范数类似于欧几里德距离。

用全张量实现这一点产生了不令人满意的结果。

# Parking and patio
parking_patio_naive_diff = tl.norm(subset_parking_lot - subset_patio)# Parking and commute
parking_commute_naive_diff = tl.norm(subset_parking_lot - subset_commute)# Patio and commute
patio_commute_naive_diff = tl.norm(subset_patio - subset_commute)

将相似性显示为表格:

不仅配对之间没有明确的排名,而且停车场和天井视频也似乎最相似,这与最初的假设形成了鲜明对比。这就是塔克分解发挥作用的地方。

TensorLy 库使得分解张量变得相对容易(尽管很慢):我们需要的只是张量和它的 n 阶。尽管 AIC 准则是寻找该参数最优值的常用方法,但在这种特定情况下,达到最优实际上是不必要的,因为目的是进行比较。我们需要一个跨越所有三个变量的公共 n 秩。因此,我们选择 n-rank = [2,2,2,2],这是精度和速度之间的一个很好的折衷。作为旁注,n-rank = [5,5,5,5]超过了 LAPACK(引擎盖下的线性代数例程)的能力,这表明这些方法在计算上是多么昂贵。

一旦我们提取了核心张量,我们可以做同样的比较。

# Get core tensor for the parking lot video
core_parking_lot, factors_parking_lot = tucker(subset_parking_lot, ranks = [2,2,2,2])# Get core tensor for the patio video
core_patio, factors_patio = tucker(subset_patio, ranks = [2,2,2,2])# Get core tensor for the commute video
core_commute, factors_commute = tucker(subset_commute, ranks = [2,2,2,2])# Compare core parking lot and patio
parking_patio_diff = tl.norm(core_parking_lot - core_patio)
int(parking_patio_diff)# Compare core parking lot and commute
parking_commute_diff= tl.norm(core_parking_lot - core_commute)
int(parking_commute_diff)# Compare core patio and commute
patio_commute_diff = tl.norm(core_patio - core_commute)
int(patio_commute_diff)

再次在表格中显示结果:

这些结果是有意义的:虽然天井视频与停车场和通勤视频不一样,但后两者在数量级上是最接近的。

结论

在本文中,我展示了无监督学习方法如何为我们的数据提供洞察力。只有在通过 Tucker 分解降低维度以从视频中提取核心张量之后,它们的比较才有意义。我们确认停车场和通勤视频最相似。

随着视频成为越来越常见的数据源,这项技术有许多潜在的应用。我想到的第一件事(由于我对电视的热情以及视频流媒体服务如何使用数据)是通过检查电影/电视节目的预告片或一些关键场景如何彼此相似来改进现有的推荐系统。第二个是在材料科学领域,加热金属的红外视频可以根据其与基准的相似性进行分类。为了使这些方法完全可扩展,计算成本应该得到解决:Tucker 分解在我的计算机上对三个 10 秒的视频很慢。并行化是一种潜在的加速方法。

除了这些直接的应用之外,这种技术与介绍中提出的一些方法结合起来也是有前途的。使用核心张量而不是完整的图像或视频作为神经网络中的训练点,可以帮助解决过度拟合问题并加快训练速度,通过解决两个主要问题来推动该方法。

[1]:科尔达,塔玛拉 g,和布雷特 w .巴德。"张量分解和应用."暹罗评论 51.3(2009):455–500。

视频游戏是人工智能的完美游乐场

原文:https://towardsdatascience.com/video-games-as-a-perfect-playground-for-artificial-intelligence-3b4ebeea36ce?source=collection_archive---------7-----------------------

为什么科学家使用虚拟世界来创造现实生活中的解决方案

Photo by Franck V. on Unsplash

近年来,人工智能领域发展迅速,人工智能背后的一系列技术有望改善我们生活的几乎每个方面。因此,人工智能被用于提高制造效率,为汽车创造自动驾驶系统,预测股票价格,安排工业产品的维修,以及其他可以直接改善我们生活的有用事情。

然而,人工智能算法的另一个应用似乎没有带来任何经济效益,但仍被广泛研究——玩视频游戏的人工智能。

在这里,我们不是在谈论作为你在游戏中旅程的一部分的 NPC(游戏中的非人类角色,机器人),尽管它们中的一些是稍微有点人工智能的,使它们感觉更真实。焦点在于真正的人工智能算法,即像任何其他独立演员一样玩视频游戏,当他们按下控制器上的按钮时,完全像人类一样。从这里,一个问题出现了——为什么开发者和研究人员在似乎没有增加价值的算法上投入了如此多的精力,因为他们只是在玩游戏?

科学家如何将游戏和人工智能结合起来?

答案很简单——玩电子游戏的人工智能不仅仅是为了玩电子游戏而被创造出来的(令人惊讶)。在这种情况下,游戏环境充当不同类型算法的游戏场,它们可以在那里测试和尝试新事物;这些结果可以应用于现实生活或未来的研究中。

例如,这是 the Verge 写的关于 DeepMind 的人工智能代理玩《雷神之锤 3》的内容:

“和以往类似的研究一样,我们的目标不是在电子游戏中真正打败人类,而是找到新的方法来教会智能体在复杂的环境中导航,同时追求共同的目标。换句话说,它是关于教授集体智慧的——这是(尽管有大量相反的证据)人类作为一个物种的成功所不可或缺的。“夺旗只是未来更大游戏的一个代表。”

在视频游戏中测试的人工智能技术的主要子集是机器学习,更具体地说,是强化学习。强化学习是一种机器学习,它意味着代理通过执行动作并获得反馈来学习如何在环境中表现。换句话说,这种类型的机器学习类似于人类甚至狗早年的学习方式:

采取行动→收到反馈(正面或负面)→根据反馈得出结论,行动是好是坏。

视频游戏中也使用了类似的结构。想象一个计算机系统,它有一个视频游戏和控制器。系统不知道该做什么,但它有一套可以执行的操作。如果它在一局游戏中前进,没有死亡,环境给系统一些奖励(没死:+1)。如果系统右移并死亡,则不获得奖励(死亡:0)甚至获得惩罚(死亡:-1)。由此,一台机器明白了向前比向右好。最终,算法的目标是最大化从其行为中获得的回报。

显然,这是对背景中实际发生的事情的简化,但是为了将重点放在视频游戏而不是实际的算法上,这个例子应该足够了。关于更多细节,有一篇很好的文章解释了 RL 如何工作的基本原理:

[## 强化学习导论

本文是🕹️. tensor flow 深度强化学习课程的一部分点击这里查看教学大纲

medium.freecodecamp.org](https://medium.freecodecamp.org/an-introduction-to-reinforcement-learning-4339519de419)

DeepMind Technologies 首次成功尝试在视频游戏中实现机器学习,他们创造了一种深度强化学习算法,可以玩旧的 Atari 2600 游戏。

然而,最新和最有趣的进展之一是由来自埃隆·马斯克共同创立的“专注于奇点的智库”开放人工智能的研究人员取得的。这组研究人员应用了一种所谓的“好奇心驱动的方法,这意味着他们没有解释算法要做什么,甚至没有解释获胜意味着什么。相反,他们编写了自然的“好奇心”来驱动机器“探索”事物,而机器只是出于好奇而玩游戏。

“这并不像听起来那么奇怪。发展心理学家认为内在动机(即好奇心)是发展早期的主要驱动力:婴儿似乎采用无目标探索来学习对以后生活有用的技能。还有很多其他不需要外在奖励的例子,从玩《我的世界》到参观当地动物园。”

[## 研究人员给了人工智能好奇心,它整天玩视频游戏

如果你教机器人钓鱼,它很可能会捉到鱼。然而,如果你教它好奇,它只会看电视…

thenextweb.com](https://thenextweb.com/artificial-intelligence/2018/08/23/researchers-gave-ai-curiosity-and-it-played-video-games-all-day/)

所以总的来说,在电子游戏中测试不同 AI 算法的总体思路是收集数据,为现实世界的应用或后续研究创建知识库。

为什么电子游戏对机器学习如此有益?

视频游戏在人工智能研究人员中流行背后的第一个原因是视频游戏在许多方面模仿现实生活的趋势。当涉及到老游戏时,这个想法不是很直接,因为它们有街机风格的图形和物理。

Photo by Kelly Sikkema on Unsplash

内在动机

然而,深入挖掘一下,我们会发现,即使在像马里奥这样的卡通游戏中,前进和执行某些动作的动机与我们的日常生活并没有太大的不同。作为一个英雄,你有一个你想要实现的特定目标,你采取特定的行动来让自己更接近这个目标。如果你的英雄在游戏中死亡,你将此视为负面反馈并改变策略。

向主要目标迈进一步→获得反馈→根据反馈改进→再试一次。

简·麦克戈尼格尔(Jane McGonigal)等作者甚至将这种反馈循环描述为在现实生活中使用游戏方法实现目标的聪明策略,因此人工智能算法可以直接从视频游戏中学习这一点是很自然的。正如 ITUNews 所说的:

“视频游戏旨在通过让玩家专注于包括克服障碍和跟随子故事在内的元素来挑战人类的思维。游戏设计的一个核心理念——也是许多人喜欢玩游戏的部分原因——是玩家一直在学习。”

真实的生活,但又安全又快捷

说到现代电子游戏,对现实生活的模拟更加明显。例如,侠盗猎车手,这基本上是一个带有有趣元素的生活模拟器,已经被某些研究人员用来训练自动驾驶汽车。由于交通规则、道路和汽车物理已经编码在游戏中,科学家在那里测试算法比在现实生活中更容易。由于 GTA 非常逼真,它可以用来生成“与使用真实世界图像生成的数据一样好”的数据。

Classifying different objects in the road scenes. Source: MIT Technology Review

此外,视频游戏安全而快速——不需要与真实环境进行交互来训练 AI,而虚拟环境允许算法训练和开发的速度比物理空间快得多。据称,在机器人可以执行 10 项任务并在现实生活中获得有用反馈的时间内,一个算法可以玩一个游戏 10,000 次,并生成有价值的数据。对于自动驾驶系统等人工智能应用领域,这一功能尤其有用,因为收集道路数据非常耗时,而在交通方面,人们的生命也岌岌可危。

此外,视频游戏很复杂,但提供了一个渐进的过程,使学习过程可以自然进行。因此,游戏往往以不同但相对容易的关卡开始,并随着每个后续的关卡而逐渐变得更难。因此,人工智能算法可以像人类一样学习玩游戏——通过试错和随着时间的推移提高技能。

“视频游戏是训练人工智能算法的一种很好的方式,因为它们旨在让人类的思维逐渐进入越来越困难的挑战。”

简单数据

另一个要点与数据清理有关。对于现实生活中的观察,大多数导出的数据在用于机器学习之前应该被“清洗”,因为诸如缺少某些值或有偏见的反馈之类的不完善之处在现实中会出现。然而,可以预期的是,由于视频游戏基本上是由数据点创建的,所以在让机器从那里学习之前,您不需要清理太多数据。这在理论上应该可以减少一个机器学习项目所需的时间相关资源。

电子游戏很有趣

最后,在电子游戏中实现人工智能算法的一个简单原因是游戏很有趣。这种类型的娱乐与高参与度相关,一些游戏拥有数百万忠实粉丝,这在其他类型的活动中不像游戏那样常见。

因此,如果一项科学成就不是用数学术语而是用游戏洞察力来解释,人们更有可能对它感兴趣。例如,创造一种算法,让在《星际争霸》中击败职业电竞玩家,或者以极高的效率玩雅达利游戏,吸引了大量的关注,并增加了媒体对这项研究的报道。这让人们更加了解人工智能和视频游戏,这对所有参与方来说都是一个双赢的局面。

视频:欺诈检测中的神经网络入门

原文:https://towardsdatascience.com/video-getting-started-with-neural-networks-in-fraud-detection-b17932ea215?source=collection_archive---------27-----------------------

从预处理到学习范畴嵌入

神经网络(NNs)最常用于处理自然数据,如文本、语音或图像。在处理传统的表格数据时,很少使用它们。然而,它们可以提供许多好处。我在一个关于卡格尔信用卡欺诈检测竞赛的新视频中探讨了这个话题。

首先,您可以通过将 NN 模型与更传统的基于树的模型预测相结合来提高性能。这是有效的,因为神经网络很可能学到了一些不同的,正是这种差异导致了有用的集合。【如果你想了解更多关于组装的知识,你可以在这里 观看我关于这个话题的视频 [。]](https://youtu.be/lgnl-Jiu1D0)

其次,学习嵌入本身可以启发分析。例如,在上图中,我们绘制了完整事务嵌入的 2D 投影。这显示了许多集群的有趣结构。通过分析这些聚类,我们可以看到模型认为哪些交易是相似的。这可以帮助我们创造新的功能,以促进更好的学习。

你可以在这里看到视频:

更多类似的内容,你可以订阅我在blog.zakjost.com的邮件列表

视频:如何通过集成提升性能

原文:https://towardsdatascience.com/video-how-to-boost-performance-with-ensembling-eec57821864c?source=collection_archive---------35-----------------------

关于信用卡欺诈检测问题的演练

作为关于信用卡欺诈检测的新 Kaggle 竞赛的视频系列的一部分,我将向您展示如何通过将几个模型组合在一起来极大地提高模型性能。我还讨论了处理类别不平衡和将数据分成训练/验证集的策略。

自上而下的观点:首席数据官研讨会的三点收获

原文:https://towardsdatascience.com/view-from-the-top-3-takeaways-from-the-chief-data-officer-symposium-fbd446952356?source=collection_archive---------31-----------------------

当今世界最具创新性的 CDO 在做什么

Photo by Skye Studios on Unsplash

本月早些时候,我有幸第一次参加了麻省理工学院的首席数据官研讨会。来自美国、加拿大、德国、荷兰等地的 60 多名 CDO 出席了会议。财富 500 强公司、政府机构和学术界的顶级数据组织都有代表出席。对我来说,这明确了即将到来的一年将是重要的一年,因为 CDO 的角色变得更加明确,并开始影响各个行业。

我被会议上的能量所鼓舞,并想分享当今最具创新性的 CDO 正在做的事情,这些事情让我觉得是每个数据优先公司都应该考虑的及时之举:

# 1:CDO 正在为自己以及数据行业定义角色

随着 CDO 努力塑造自己的角色,以及他们对底线的重要性不断增加,这促使人们自然而然地思考公司应该从他们的数据中获得什么,以及真正的数据驱动意味着什么。我在研讨会上听到的一些关键要点是:

  • 进攻的重要性,而不仅仅是防御,在您的数据战略中
  • 管理和投资于数据的“基础”
  • 接近收入并证明数据工作的投资回报

注意:对于更长时间的思考,汤姆·达文波特在《福布斯》上有一个的精彩总结

但上述优先事项给我留下最深刻印象的是——以及它们在角色和业务成熟度方面的标志——这是 CDO 崛起的一个独特时刻。(毕竟,说到政府,你知道我们已经掌握了一种趋势:7 月初,白宫授权每个机构任命一名首席数据官。)

在私营部门,CDO 角色在组织中日益重要的表现是:

  • 报告结构越来越接近首席执行官
  • 责任越来越大,包括分析、数据工程、BI
  • 与公司目标相关的明确使命和章程

如今,每个组织都需要有一个数据战略,而 CDO 是掌舵这一战略的最佳人选。但挑战在于如何让数据计划成功超越数据功能的界限,并对更广泛的组织产生影响。

一个叫 CDO 的人告诉大家,他创造了一个新的角色,叫做“数据素养负责人”,为整个企业服务。这个人负责确保这个~10K 员工组织中的每个业务单元“数据流畅”例如,他们正在为每个业务部门创建记分卡,以根据数据技能(如 Excel、SQL、R、Python 等)来衡量职能部门的绩效。然后,他们帮助每个职能部门定义他们的数据素养目标(即,每个人应该知道什么技能,以及达到什么样的深度和广度);培训/教育团队,帮助成员提高技能;作为一个组织,总体上变得更加“数据流畅”。

在组织中建立一个单一的责任点是非常强大的,可以让整个公司以一种非常具体、可衡量的方式掌握数据。

#2:使用数据推动有意义的商业价值,并对其进行量化

在研讨会期间的一个小组中,一位 CDO 分享了这个关于如何思考数据“防御”工作的价值的伟大比喻:

想象一下:你的公司是一个隐喻的杂货店。想象一下,如果货架上所有的商品都杂乱无章,购物者找不到他们需要的商品——这是一种多么可怕的体验。同样,当你的数据杂乱无章时,这也是数据消费者的感受——他们不知道在哪里可以找到他们需要的数据。现在想象商店里的物品被棕色的袋子覆盖着。购物者不知道他们在买什么。类似地,这就是为什么您需要收集和组织元数据来描述和理解您的资产。

我要指出的是,大型科技公司已经建立了解决其中一些问题的本土解决方案,比如 Lyft 的阿蒙森和 LinkedIn 的数据中心

但最具创新性的 CDO 不会止步于防御。公司现在将数据作为竞争优势;例如,使用它来确定新的市场成熟的破坏,新产品或新功能的开发,新的方法来提高成本和效率。事实上,如果做得好,您的数据战略不仅会紧密联系在一起,还会极大地影响您的业务战略。如今,数据团队实际上扮演着各种功能的业务合作伙伴的角色,作为他们的营销、销售、客户成功、产品和工程对应方的积极思维伙伴。数据团队参与业务合作伙伴的 KPI 以提高绩效的情况并不少见。业务成功就是数据组织的成功。

#3:在业务需求的驱动下,寻找并采用新技术

将创新和自动化引入一个行业可以从根本上改变商业运作的方式——从我们构建、运营和成功的方式。就我个人而言,我认为我们将会看到这种创新,其形式是自动化和工程概念被新应用于数据。我之前写过关于数据可靠性以及团队如何发展以变得更加主动地管理他们的数据停机时间以及以 AI/ML/自动化优先、可扩展的方式解决这个问题的需求。擅长采用数据和新技术来管理数据的公司将占据上风。

一位来自东海岸的 CDO 在一个小组中分享道,她上任后做的第一件事就是组织公司的数据主管去拜访西海岸的同行。他们与具有前瞻性思维的数据组织会面,交流最佳实践,了解有用的新技术,并确保他们在数据、自动化、AI/ML 等方面推动自己的思维。另一位财富 500 强金融机构的 CDO 表示,她将自动化视为其组织的首要任务;以至于她和她的团队几乎 30%的工作都与识别和采用新平台有关,以使她的数据团队更加有效!

数据行业的创新和变革步伐是巨大的,我迫不及待地想看看几年后我们会在哪里。无论您是数据科学家、分析师、工程师还是业务人员,我们都有责任尽可能成为最好的数据管家,带领我们的组织完成这一转型。有一点是清楚的:成为这场运动的一部分,这无疑是一个特殊的历史时刻。

通过机器的眼睛看文本

原文:https://towardsdatascience.com/viewing-text-through-the-eyes-of-a-machine-db30c744ee17?source=collection_archive---------11-----------------------

如何让黑盒语言模型更加透明

Visualising how machines read text. In this article we will build a heatmap to identify where a text model is ‘reading’ to determine whether a coffee is a light or dark roast

多年来,我们已经能够在计算机视觉任务中揭开卷积神经网络(CNN)的盖子。这给该领域带来了重大改进,具体表现在:

  • 提高模型的稳健性;
  • 模型偏差的可见性和减少;和
  • 更好地理解对立图像如何改变深度学习模型的输出。

既然更好的模型理解带来了如此明显的好处,为什么我们在自然语言处理(NLP)领域对模型可解释性的关注程度似乎不一样呢?

This is what a neural network thinks dumbbells look like. Notice that the model has not separated arms from weights in this case and therefore has not learned generalised representations of this class. Photo from Google AI Blog

创建一个 CNN 正在看的地方的可视化:

在这篇文章中,我们将看到如何应用同样的技术来理解基于视觉的 CNN 在看什么,并将其应用于文本。然后,我们将创建一个热图,显示 CNN 在输入文本的特定区域“聚焦”的位置,以便进行分类。

是的,我知道,在 GPT-2,伯特,埃尔莫等时代,CNN 现在被认为有点“过时”。然而,它们仍然提供了很好的现实世界性能,没有这些尖端模型带来的大模型大小,长推理时间和大内存使用。

预测咖啡烘焙:

为了浏览一个例子,我们将首先建立一个简单的分类器,根据它的描述来预测一杯咖啡是浅烘焙咖啡还是深烘焙咖啡。

我们的数据集是一系列咖啡评论。在这张桌子上,我们将使用盲品笔记来尝试预测烘焙的颜色是浅还是深。

在 Keras 中构建 CNN 并根据这些数据对其进行训练的代码如下:

X = df.blind_assesment.values
y = df.y.valuestokenizer = Tokenizer(num_words=4000)
tokenizer.fit_on_texts(X)X = tokenizer.texts_to_sequences(X)vocab_size = len(tokenizer.word_index) + 1  # Adding 1 because of reserved 0 indexmaxlen = 200
embedding_dim = 50X = pad_sequences(X, padding='post', maxlen=maxlen)sequence_input = layers.Input(shape=(maxlen,), dtype='int32')
embedded_sequences = layers.Embedding(vocab_size, embedding_dim, input_length=maxlen)(sequence_input)
l_cov1  = layers.Conv1D(317, 3, activation='relu')(embedded_sequences)
l_pool1 = layers.MaxPooling1D(2)(l_cov1)
l_cov2  = layers.Conv1D(317, 1, activation='relu')(l_pool1)
l_cov3  = layers.Conv1D(317, 2, activation='relu')(l_cov2)
l_pool3 = layers.GlobalMaxPooling1D()(l_cov3)  # global max pooling
l_bnorm = layers.BatchNormalization()(l_pool3)
l_dense = layers.Dense(128, activation='relu')(l_pool3)
preds   = layers.Dense(1, activation='sigmoid',name='preds')(l_dense)model = Model(sequence_input, outputs=preds)model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])
model.summary()model.fit(X, y, epochs=3, validation_split=0.1, batch_size=10)

如果 Keras 中的模型看起来有点不同,这是因为它使用了函数式 API ( 这里有更多细节)。该代码训练并拟合模型,验证准确率约为 75–80%。有很多关于构建 CNN 文本分类器的其他帖子,所以我在这里不再赘述。相反,我们将关注如何解释这个分类器做出的预测。

创建激活图:

使用 Keras,这既快速又简单,只需要几行代码:

  1. 得到模型预测和网络的最终 CNN 层:

You can get a breakdown of the model structure in Keras using model.summary(). Here conv1d_45 is the name of the final CNN layer in the model

然后,以下代码获取预测类和最后一个 CNN 图层:

class_idx = np.argmax(y_pred[0]) #not needed in this case as only two classes
class_output = model.output[:, class_idx]
last_conv_layer = model.get_layer("conv1d_45")

2.由此,我们可以计算类输出相对于特征图的梯度,然后汇集所有的梯度。这听起来很复杂,但使用 Keras 后端函数,只需几行代码就可以完成:

grads = K.gradients(class_output, last_conv_layer.output)[0]
pooled_grads = K.mean(grads)
iterate = K.function([model.input], [pooled_grads, last_conv_layer.output[0]])
pooled_grads_value, conv_layer_output_value = iterate([Xtst])

3.然后,我们对该特征图进行平均,并将其归一化到 0 和 1 之间:

heatmap = np.mean(conv_layer_output_value, axis=-1)
heatmap = np.maximum(heatmap,0)
heatmap /= np.max(heatmap)#normalise values in the prediction

我们现在有了预测类在最后一个 CNN 层的输出形状长度上的激活热图。我们现在需要做的就是根据原始输入的长度(单词数)来调整(拉伸)它,以了解哪些单词触发了网络。

用 HTML 可视化输出:

向最终预测添加一些基本的 HTML 可以创建一个非常有影响力的用户界面,同时增加了理解模型如何达到其预测的能力:

norm_len = maxlen/last_conv_layer.output_shape[1] # find the ratio of the text vs the conv layer lengthhtml = ""
if y_pred[0]>0.5:
  pred = 'light'
else:
  pred = 'dark'
html += "<span><h3>Based on the description, the model believes that this is a {} coffee roast. ".format(pred)
html += "<small><br>Confidence: {:.0f}%<br><br></small></h3></span>".format(abs(((y_pred[0][0]*100)-50)*2))
for j,i in enumerate(tokenizer.sequences_to_texts(Xtst)[0].split()):
  html += "<span style='background-color:rgba({},0,150,{})'>{} </span>".format(heatmap[math.floor(j/norm_len)]*255,heatmap[math.floor(j/norm_len)]-0.3,i)HTML(html)

这个 HTML 片段在 Google Colab 中创建了以下输出:

Here we can see the model has ‘read’ that the coffee in question has tastes of ‘wild strawberry’ and has a ‘sweet’, ‘fresh acidity’ and is therefore (correctly) confident that this is a light roast.

总之,在本文中,我们已经看到了如何轻松地突出显示模型正在“阅读”的文本区域,以进行预测。这些信息对于以下工作至关重要:

  1. 执行基本模型调试和意义检查。
  2. 更好地理解为什么模型会对训练样本进行错误分类。
  3. 检测潜在的模型偏差。

感谢阅读。如果你有任何问题,请在评论中告诉我。

完整的代码可以在下面的 Colab 笔记本中找到:

[## CNN 文字热图

文本可解释性

colab.research.google.com](https://colab.research.google.com/drive/1taIt9A9tsENJTYh3eK0ZuUyRIdrHeNty)

小提琴情节——是时候抛弃盒子情节了

原文:https://towardsdatascience.com/violin-plot-its-time-to-ditch-the-box-plots-785629b0ff3a?source=collection_archive---------9-----------------------

在您的数据探索之旅中,您很可能遇到过许多类型的图表,它们的主要目标是提供您正在处理的数据的可视化摘要。

Photo by Providence Doucet on Unsplash

你已经得到了你的直方图和/或 KDE 图,向你展示一个特定的属性是如何分布的,你已经得到了你的箱线图来寻找最终的异常值。但是你觉得把这两种图表结合起来的想法怎么样?

这就是小提琴情节的由来。

在潜入文章之前,我先说清楚这篇文章是给看的。如果你已经每天都在使用小提琴的情节,并且对它们了如指掌,你可能就不应该继续读下去了。但是对于其他人来说,这篇文章将是一个很好的复习资料,甚至对于初次学习者来说是一个很好的资源。

小提琴情节——精粹

violin 图背后的主要思想是结合直方图(或 KDE 图,更准确地说是)和箱形图的功能。也就是说,violin plots 将显示您将在方框图中看到的所有信息,例如:

  • 中值(中间的白点,稍后你会看到)
  • 四分位数范围 (IQR,白点周围的粗黑条)
  • 下/上限值(从粗黑条延伸的线,定义为 Q1-1.5 IQR 和 Q3+1.5 IQR-用于异常值检测)

你知道上面所有的那些术语是什么,因为我相信你以前见过一个盒子图,所以没有必要继续纠缠下去。

然而,这三件事并没有使小提琴情节变得特别(因为那是盒子情节的工作)。它的特别之处在于,它还显示了数据的整体分布

让我们来看看实际情况,我将从标准正态分布中抽取一个样本,然后在 KDE 旁边绘制直方图,然后是箱线图,最后是小提琴图:

执行上面的代码将产生以下输出:

爽!简单提一下,如果你对调整 Matlotlib 图表的外观感兴趣,请参考我的上一篇文章

现在,当我们了解了基础知识后,让我们进一步探索在真实数据集上绘制 violin 图的能力。

向下钻取

为了这篇文章,我将使用技巧数据集,您可以免费下载并跟随它。很容易将它加载到熊猫中,不需要下载 CSV 文件,只需传入 URL:

执行上面的代码将显示数据集的前几行:

以防你想知道 Bamboolib 是什么。现在我真的不想对这个数据集进行深入分析,因为,嗯,今天是圣诞节 ( 祝你节日快乐,我的读者朋友),但是我将探索小提琴情节的一些属性。

首先是total_bill属性(代码:sns.violinplot(tips_df['total_bill'])):

如你所见,分布有点倾斜。右侧有异常值(延伸条结束处右侧的区域),表明有几张昂贵的钞票,大约在 40 美元以上。

现在,让我们更深入地探索每天和每次总账单金额(代码:`sns.violingplot(x='day', y='total_bill', data=tips_df)``)的 violin 情节:

嗯,这很奇怪。不要误会我的意思,所有的情节都很好,但似乎酒吧/餐厅在周一,周二和周三不工作。有史以来最高的账单是在周六,大约 60 美元,但是每天都有异常值。

有一句老话说,吸烟者往往在酒吧和餐馆花更多的钱(我只是为了证明一点而编造的),让我们看看这是不是真的(代码:sns.violinplot(x='day', y='total_bill', hue='smoker', data=tips_df):

看起来这种说法在大多数日子里都是正确的,至少如果我们看一下账单金额的中位数(中的白点),但对于周五来说,情况通常不是这样。当然,有一些异常值,但是你不能真的指望他们作为大多数数据。

这个hue的东西实质上是图表上小提琴图数量的两倍,这有点不必要,因为小提琴图是对称的,你只要看它的一边就可以得出相同的结论。这就是split参数派上用场的地方。让我们看看它在示例中做了什么(代码:sns.violinplot(x='day', y='total_bill', hue='smoker', data=tips_df, split=True):

现在有了这张更加紧凑的图表,你可以像以前一样看到每一点信息。

在你走之前

现在,您已经拥有了将数据分析技能提升到下一个水平所需的基本工具。箱形图很好,KDE 图也很好,但是小提琴图会让你在做决定时节省一些时间。

我鼓励你继续深入探索,在评论区与世界分享你的发现。

感谢阅读。保重。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

[## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)

小提琴情节解释

原文:https://towardsdatascience.com/violin-plots-explained-fb1d115e023d?source=collection_archive---------0-----------------------

Source: Unsplash

学习如何使用小提琴情节,以及它们比盒子情节有什么优势!

一般来说,violin 图是一种绘制数字数据的方法,可以被认为是盒图核密度图的组合。在小提琴图中,我们可以找到与盒子图中相同的信息:

  • 中值(小提琴图上的白点)
  • 四分位范围(小提琴中间的黑条)
  • 下/上相邻值(从条上拉伸的黑线)——分别定义为first quartile — 1.5 IQRthird quartile + 1.5 IQR。这些值可用于简单的异常值检测技术(图基栅栏),位于这些“栅栏”之外的观察值可被视为异常值。

Source

与箱线图相比,小提琴图无可置疑的优势在于,除了显示上述统计数据之外,它还显示了数据的整体分布。这是令人感兴趣的,尤其是当处理多峰数据时,,即,具有一个以上峰值的分布。

用 Python 实现

在本文中,我们使用以下库:

seaborn    0.9.0
numpy      1.17.2
pandas     0.25.1
matplotlib 3.1.1

我们首先定义我们将从某些分布中抽取的随机观察值的数量,以及为结果的可重复性设置种子。

N = 10 ** 4
np.random.seed(42)

然后,我们定义一个绘制以下内容的函数:

  • 具有核密度估计的直方图(KDE)
  • 箱线图
  • 小提琴的情节

我们将使用这个函数来检查随机创建的样本。

def plot_comparison(x, title):
    fig, ax = plt.subplots(3, 1, sharex=True)
    sns.distplot(x, ax=ax[0])
    ax[0].set_title('Histogram + KDE')
    sns.boxplot(x, ax=ax[1])
    ax[1].set_title('Boxplot')
    sns.violinplot(x, ax=ax[2])
    ax[2].set_title('Violin plot')
    fig.suptitle(title, fontsize=16)
    plt.show()

标准正态分布

我们从最基本的分布开始——标准正态分布。我们随机抽取 10000 个数字并绘制结果。

sample_gaussian = np.random.normal(size=N)
plot_comparison(sample_gaussian, 'Standard Normal Distribution')

我们可以做一些观察:

  • 在直方图中,我们可以看到分布的对称形状
  • 我们可以在箱线图和小提琴图中看到前面提到的指标(中位数、IQR、图基围栏)
  • 用于创建小提琴图的内核密度图与添加到直方图顶部的内核密度图相同。小提琴图的较宽部分代表观察值取给定值的较高概率,较薄部分对应较低概率。

我相信把这三个情节放在一起展示,可以很好地直观地了解小提琴的情节到底是什么,以及它包含了什么样的信息。

对数正态分布

在第二个例子中,我们考虑对数正态分布,它肯定比正态分布更偏斜。

sample_lognormal = np.random.lognormal(size=N)
plot_comparison(sample_lognormal, 'Log-normal Distribution')

高斯混合物—双峰

在前两个例子中,我们已经看到小提琴图比盒子图包含更多的信息。当我们考虑多式联运配送时,这一点更加明显。在本例中,我们创建了一个双峰分布,作为两个高斯分布的混合。

如果不看直方图/密度图,就不可能在我们的数据中找到两个峰值。

高级用法

小提琴图通常用于比较给定变量在某些类别中的分布。我们在下面介绍了几种可能性。为此,我们从seaborn加载tips数据集。

tips = sns.load_dataset("tips")

在第一个例子中,我们看看小费在不同性别中的分布。此外,我们改变了 violin 图的结构,只显示四分点。一些其他的可能性包括point用于显示所有的观察结果,或者box用于在小提琴图内绘制一个小方框图。

ax = sns.violinplot(x="sex", y="tip", inner='quartile', data=tips)
ax.set_title('Distribution of tips', fontsize=16);

我们看到,两种性别尖端的整体形状和分布是相似的(四分位数彼此非常接近),但男性的异常值更多。

在第二个例子中,我们研究了每天账单总额的分布。此外,我们按性别划分。我们立刻发现,性别分布形状的最大差异发生在周五。

ax = sns.violinplot(x="day", y="total_bill", hue="sex", data=tips)
ax.set_title('Distribution of total bill amount per day', fontsize=16);

在最后一个例子中,我们调查了与前一个例子相同的事情,但是,我们设置了split=True。这样做,我们得到的不是 8 把小提琴,而是 4 把——小提琴的每一面对应不同的性别。

ax = sns.violinplot(x="day", y="total_bill", hue="sex", split=True, data=tips)
ax.set_title('Distribution of total bill amount per day', fontsize=16);

结论

在这篇文章中,我展示了什么是小提琴情节,如何解释它们,以及它们相对于盒子情节的优势。值得注意的最后一点是,只要四分位数保持不变,箱线图就不会发生变化。我们可以用四分位数不变的方式修改数据,但分布的形状会有很大的不同。下面的 GIF 说明了这一点。

Source

一如既往,我们欢迎任何建设性的反馈。你可以在推特或评论中联系我。您可以在我的 GitHub 上找到本文使用的代码。

喜欢这篇文章吗?成为一个媒介成员,通过无限制的阅读继续学习。如果你使用这个链接成为会员,你将支持我,而不需要额外的费用。提前感谢,再见!

病毒时尚、网络和统计物理学

原文:https://towardsdatascience.com/viral-fashion-networks-statistical-physics-373bebd36b13?source=collection_archive---------15-----------------------

模拟德国人为何放弃与互动代理人的关系

“所有的模型都是错误的,但有些是有用的”——乔治·博克斯

2017 年 5 月,当德国总理安格拉·默克尔会见德国汽车制造商戴姆勒和梅赛德斯-奔驰的首席执行官迪特·蔡澈,为一家新工厂奠基时,德国商界的一些人并没有关注增加电动交通投资的信息,而是在学习办公室着装。蔡澈是美国最有权势和影响力的商人之一,他不打领带。

接下来几周的反应是决定性的。据坊间报道,德国企业中打领带的比例从 90%骤降至 10%。

服装上如此迅速协调的变化是怎么发生的?一个可能的解释很简单:蔡澈对什么是合适的影响如此之大,以至于他的行动单枪匹马地改变了绝大多数德国上班族的想法。

另一种解释更复杂,也可能更有见地。着装习惯的突然改变表明,打领带可能不是每个人的首选(几乎所有打领带的人都证实了这一点),而是为了迎合他人。蔡澈的行为打破了在公共场合的这种一致性,也许只有少数人不打领带。这些人的行为会影响其他人,这种影响会在人群中扩散。

这项研究采用了流行病学的方法,表明在工作场所打领带的决定与疾病在人群中传播的方式非常相似。不管多么简单,探索这样一个模型有可能突出趋势和规范如何在社会群体中传播。

How tie wearing evolves after an influencer (red) doesn't wear a tie for one day. Light colours indicate that a tie is worn, dark indicate that no tie is worn.

该模型假设每个人根据其网络中大多数人前一天的穿着决定每天是否打领带,稍微倾向于不打领带。随着时间的推移,打领带的人口比例显示出与德国一样的大幅下降。

The influencer wears no tie on day 5. The change to a new stable state of no ties is abrupt.

这个过程表明,所有打领带的人群处于一种亚稳态——如果影响者永远不会放弃打领带,那么没有人会放弃,每个人都会无限期地打领带。然而,如果系统被某人(被称为影响者,他们的身份无关紧要)扰乱,行动将会蔓延,没有人会留下领带。这种状态可与过热的水相媲美,纯水即使在 100 度以上的温度下也会保持液态。引起所有水蒸发所需要的只是引入少量污染物以提供成核位置。

Right: Pressure-Density of water, reproduced from “Critical Mass” by Phillip Ball. Left: Hypothetical tie wearing model. The metastable state described previously is at point (a).

此外,模型和示例中描述的这种变化是突然的,似乎不存在领带佩戴者和非领带佩戴者共存的稳定状态,就像液态水和汽化水通常不存在于相同的条件下一样。

当描述水和其他物质的状态时,要用相图来描述物质在不同压力和温度下的相态(固态、液态或气态)。

Source: MIT

这些相似性表明,领带穿着习惯可能有一个相图,它描述了系统的稳定状态如何随着模型参数的调整而变化。这是引入影响者后系统的稳定状态。这让我们可以探索如果人们真的不介意打领带,或者如果蔡澈只影响了一小部分人,德国的情况会发生怎样的变化。

Tie wearing phase diagram starting at state where everyone wears a tie. Black indicates no-tie is stable, grey indicates tie wearing is stable. Influence is measured as the proportion of individuals that are connected to the influencer’s node in the network. Tie annoyance is the size of the penalty to utility from wearing a tie in relation to the utility gained from conforming, a measure of how much individuals would prefer to not wear a tie.

上图表明,蔡澈的影响在决定会议后的最终状态方面并不十分重要,只要至少其他一些人受到影响。然而,有一个最低水平的领带烦恼需要克服的愿望,以符合。

进一步的参数可以调整。稳定状态对网络中的个体数量是鲁棒的,只要平均连接数与个体数量相比是小的。个体之间的联系也可以调整,无论是平均数量还是可变性。

The phase diagrams are produced for a range of connections and connection variability.

随着平均连接数和连接可变性的增加,影响者改变群体习惯的机会减少。此外,在所有连接配置中,影响者的影响并没有产生很大的效果,相反,对关系的厌恶似乎是决定性因素。这是一个合乎逻辑的结论,因为对领带的厌恶是驱动最初的领带佩戴状态变得亚稳定而不是内在稳定的原因。

那么,这个模型有用吗?

这些模拟和由此产生的复杂行为依赖于遵循一套简单规则的一群相互作用的个体。这种简化方法忽略了办公室时尚的细微差别,而这种差别是存在的。忽视他们无疑会让每个人的行为变得错误。然而,这并不意味着整个人口的统计行为是不正确的,只要每个个体决策模型中的误差大致相互抵消。事实上,办公室里的一些人很少注意其他人的着装,而另一些人则确保他们的着装不仅符合标准,而且超出平均水平。通过这些人口规模属性,该模型可以揭示手头的过程,并增强我们对规范如何在社会中传播的理解。在其他应用中,这种类型的模型已经被证明对模拟行人运动社会政策很有用。

技术说明:

个人决策:

使用以下效用函数,将是否打领带的决定建模为效用最大化问题:

无论哪一个决定(平局或不平局)产生更大的效用,都是当天的决定。

网络布局:

网络被生成为完全连接的随机图。虽然小世界网络更适合用来模拟社会联系,但随机图的使用产生了相似的特征路径长度,并减少了长时间模拟的运行时间。

代码:

所有代码都可以在 Github 的这里获得。

从招聘角度看香港的虚拟银行竞赛

原文:https://towardsdatascience.com/virtual-banking-race-in-hong-kong-from-hiring-perspective-70fb5282d831?source=collection_archive---------22-----------------------

即使你不在找工作,招聘广告也是有用的吗?

Photo by Autri Taheri on Unsplash

如果你一直在关注香港虚拟银行牌照的相关新闻,你可能会听说过这些名字——Livi VB、SC Digital Solutions、ZhongAn 和 WeLab 。前 3 家公司于 3 月 27 日获得香港金融管理局颁发的第一张虚拟银行牌照,WeLab 于 4 月 10 日加入该俱乐部。关于这些公司的信息有限,本文试图通过分析它们的职位空缺来了解更多。

他们是谁?

你可能听说过自 2013 年以来一直在 P2P 融资领域的 WeLab ,以及 2017 年在香港上市的众安母公司,但其余公司对普通大众来说似乎相当“神秘”。

根据SCMP

香港金融管理局(Hong Kong Monetary Authority)表示,由中国银行(香港)、JD Digits and Jardines、渣打银行(香港)、HKT、PCCW 和携程组成的合资公司 SC Digital Solutions 以及由中安在线和国金资讯组成的合资公司中安虚拟金融(香港)共同拥有的 Livi VB 将成为前三个牌照的运营商

职位空缺:不同的扩展重点

根据他们的商业计划,这些新获得牌照的虚拟银行打算在获得牌照后的 6 至 9 个月内推出其服务。在如此短的承诺期限内,这些公司自确认其银行地位以来一直在更加积极地招聘。

在过去的 2 周里,我一直在收集这 4 家公司的虚拟银行职位空缺。截至 4 月 22 日,我已经从这 4 家公司的各种网上来源收集了 73 个虚拟银行职位空缺。图表中只有 3 家公司,因为我找不到与 Livi VB 相关的角色。通过分析这些新虚拟银行发布的职位空缺,我们可以看到这些公司团队扩张重点的一些有趣模式。

渣打银行、WeLab 和众安也有类似数量的职位空缺,每个都招聘 25 个左右的职位。为了了解每家公司关注的领域,我将这些角色归类到它们相应的业务职能中。例如,角色“高级 FP&A 经理”被归类为“财务”业务功能,“后端开发人员”被归类为“工程等。

我发现下面这张雷达图挺有意思的:

当我们试图在雷达图中将相关的业务功能放在一起时,它揭示了每个公司的相对扩张重点—

渣打银行

  • 大量强调扩展技术相关功能(工程、项目管理、安全)
  • 风险/合规
  • 营销(尤其是在线/社交媒体渠道)

中安

  • 当务之急是加强核心业务职能(运营、风险、财务)
  • IT 和管理

WeLab

  • 与众安类似,首要任务是强化核心业务功能。而众安更强调扩大运营团队,WeLab 目前的重点是扩大财务团队。
  • 建立各种营销/关系功能,这在其他两家公司中是没有的——期待更多的营销活动?
  • 工程
  • 招聘实习生

职位描述中的关键词

除了像扩展焦点这样的高层次见解,如果我们更深入地研究工作描述,还会有其他有趣的发现。

一份工作描述通常至少由两部分组成——(I)角色的职责,以及(ii)角色的要求职责更多的是关于角色(任务),而要求更多的是关于人(需要的技能)。我将这两个部分分开,并对它们分别应用关键词提取(前 5 个关键词)。

我们使用由名为 textacy 的软件包提供的 SGRank 算法,该软件包在 spacy 的基础上提供了许多方便的 NLP 工具包。SGRank 算法提取的前 5 个关键词相当不错,即使没有任何微调。

比如 WeLab 中的行政助理角色,职责关键词是["地面交通"、"差旅预订、"商务会议"、"会议日程安排、"级别高管"],需求关键词是[" 沟通技巧、" ms word】、"优秀人际交往、"高度灵活性、"良好英语]。这些很好地总结了角色的性质和所需的技能。

使用单词嵌入和 t-SNE 将角色聚类成组

spacy 为我们提供了名词块单词嵌入,这在我们试图将单个数据点聚类成组时非常有用。spacy 内置的词性标注器在从给定文本中提取名词块方面做得非常好。这些名词很好的代表了角色性质。

如果你拿到了。vector 属性,它将返回名词块的单词嵌入(向量表示)。单词嵌入允许我们量化单词之间的关系(两个单词/短语有多相似)。它甚至使文字上的算术成为可能!

在我们的例子中,我对每个角色的需求列的 noun_chunks 单词嵌入进行了平均,并应用了一种称为 t-SNE 的方法来将 300 维向量减少到(x,y)坐标中。结果显示在由散景创建的交互式绘图中。

如果我们悬停在相邻的点上,我们可以看到这些点之间的一些结构。剧情下部多为工程角色,fullstack 开发者介于前端开发者和后端开发者之间。在左边,行政助理、行政助理、接待员等管理角色彼此靠近,在图的其他部分也存在类似的结构。当人力资源经理/招聘人员试图分析市场上竞争对手的职位空缺时,这种技术可能会很有用。

关闭

我们可以从一家公司的职位空缺中获知很多信息,尤其是当这家公司正在积极招聘时。这可以解释为什么像对冲基金这样的“秘密”行业倾向于通过代理人招聘。

与此同时,职位空缺可以向候选人/投资者/公众传达一个信号,表明你公司的“舞台”或“品味”——你最常聘用的是什么样的角色,这可能会讲述一个关于“舞台”的故事;职位描述中列出的技术/技能很能说明你公司的“品味”。

鉴于这一子行业所享有的优势,虚拟银行的前景只会越来越好。2018 年,渣打银行在租金/建筑相关事务上花费了 7.9 亿 HKD[1],占总运营支出 116.47 亿英镑的 6.78%。当银行可以取消分支机构时,70.74 亿英镑的员工成本可以得到更有效的利用。几年后,零售银行业可能会大不相同。

[1]https://av.sc.com/hk/zh/content/docs/hk-c-ar2018-101.pdf第 256 页

附录:本分析中使用的数据

Python 虚拟环境指南

原文:https://towardsdatascience.com/virtual-environments-104c62d48c54?source=collection_archive---------1-----------------------

它们是什么,如何使用它们,以及它们实际上是如何工作的。

The Gate of Dependency Hell: “Abandon all hope, ye who enter here.” Illustration by Gustave Doré.

Python 的虚拟环境让生活变得更加轻松。轻松很多

☄在本指南中,我们将涵盖虚拟环境的基础知识以及如何使用它们。然后,我们将深入了解虚拟环境实际上是如何工作的。

⚠️注意:在本指南中,我们将在 macOS Mojave 上使用最新版本的 Python 3.7.x。

目录

为什么要使用虚拟环境?
什么是 Virtualenv?!
使用虚拟环境
管理环境
虚拟环境如何工作
延伸阅读

为什么要使用虚拟环境?

虚拟环境为大量潜在问题提供了一个简单的解决方案。特别是,它们可以帮助您:

  • 通过允许你为不同的项目使用不同版本的包来解决依赖问题。例如,您可以对项目 X 使用包 A v2.7,对项目 y 使用包 A v1.3。
  • 通过在一个需求文件中捕获所有的包依赖,使你的项目自包含可重复
  • 在您没有管理员权限的主机上安装软件包。
  • 通过消除在系统范围内安装包的需要来保持你的全局目录整洁,你可能只需要一个项目。

听起来很方便,不是吗?当你开始构建更复杂的项目并与其他人合作时,你会发现虚拟环境是多么重要。如果你像我一样是一名数据科学家,你也会想熟悉他们的多语言表亲 Conda environments

但是首先要做的是。

什么是虚拟?!

到底是什么虚拟环境?

虚拟环境是用于依赖管理项目 隔离的 Python 工具。它们允许 Python 站点包(第三方库)被本地安装在特定项目的一个隔离的目录中,而不是被全局安装(即作为系统范围 Python 的一部分)。

太好了。这听起来不错,但是什么是虚拟环境呢?嗯,虚拟环境就是一个包含三个重要组件的目录:

  • 安装第三方库的site-packages/文件夹。
  • 符号链接到系统上安装的 Python 可执行文件。
  • 脚本确保执行的 Python 代码使用安装在给定虚拟环境中的 Python 解释器和站点包。

最后一点是所有的 s***下降的地方。稍后我们将更深入地了解一下,但是现在让我们看看我们实际上是如何使用虚拟环境的。

Virgil appeases Cerberus — Canto VI. Illustration by Gustave Doré.

使用虚拟环境

创造环境

假设我们想要为一个名为test-project/的项目创建一个虚拟环境,它有如下的目录树。

test-project/
├── data        
├── deliver           # Final analysis, code, & presentations
├── develop           # Notebooks for exploratory analysis
├── src               # Scripts & local project modules
└── tests

我们需要做的就是执行[venv](https://docs.python.org/3/library/venv.html)模块,它是 Python 标准库的一部分。

% cd test-project/
% python3 -m venv venv/       # Creates an environment called venv/

⚠️注:您可以根据您的环境用不同的名称替换“venv/”。

瞧啊。一个虚拟的环境诞生了。现在我们的项目看起来像这样:

test-project/
├── data        
├── deliver      
├── develop      
├── src      
├── tests    
└── venv                 # There it is!

♻️提醒:虚拟环境本身就是一个目录。

剩下唯一要做的就是通过运行我们前面提到的脚本来“激活”我们的环境。

% source venv/bin/activate             
(venv) %                               # Fancy new command prompt

我们现在在一个活动的虚拟环境中(由以活动环境的名称为前缀的命令提示符指示)。

在这一点上,我们将像往常一样工作在我们的项目上,安全地知道我们的项目与我们系统的其余部分是完全隔离的。在我们的环境内部,我们无法访问系统范围的站点包,并且我们安装的任何包在我们的环境外部都是不可访问的。

当我们完成我们的项目时,我们可以用

(venv) % deactivate
%                                    # Old familiar command prompt

安装软件包

默认情况下,只有pipsetuptools安装在新环境中。

(venv) % pip list                    # Inside an active environmentPackage    Version
---------- -------
pip        19.1.1
setuptools 40.8.0

如果我们想安装一个特定版本的第三方库,比如说numpy的 v1.15.3,我们可以照常使用pip即可。

(venv) % pip install numpy==1.15.3
(venv) % pip listPackage    Version
---------- -------
numpy      1.15.3
pip        19.1.1
setuptools 40.8.0

现在我们可以在脚本或活动 Python shell 中导入numpy。例如,假设我们的项目包含一个脚本tests/imports-test.py,其代码如下。

#!/usr/bin/env python3          

import numpy as np

当我们直接从命令行运行这个脚本时,我们会得到:

(venv) % tests/imports-test.py           
(venv) %                                 # Look, Ma, no errors!

成功。我们的剧本顺利地引进了🥳.的numpy

Dante and Virgil cross the river Styx — Canto VIII. Illustration by Gustave Doré.

管理环境

需求文件

使我们的工作可以被其他人复制的最简单的方法是在我们项目的根目录(顶层目录)中包含一个需求文件。为此,我们将运行pip freeze,它列出已安装的第三方包及其版本号,

(venv) % pip freeze
numpy==1.15.3 

并将输出写入一个文件,我们称之为requirements.txt

(venv) % pip freeze > requirements.txt

每当我们更新一个包或者安装一个新的包时,我们可以使用这个命令来重写我们的需求文件。

现在,我们共享项目的任何人都可以通过使用我们的requirements.txt文件复制我们的环境,在他们的系统上运行我们的项目。

复制环境

等等——我们到底该怎么做?

想象一下,我们的队友 Sara 从我们团队的 GitHub 库中取出了我们的 T8。在她的系统上,项目的目录树如下所示:

test-project/
├── data        
├── deliver      
├── develop      
├── requirements.txt
├── src    
└── tests

注意到任何轻微的不寻常的事情吗?是的,没错。没有venv/文件夹。我们已经把它从我们团队的 GitHub 库中排除了,因为包含它会引起麻烦

这就是为什么拥有一个requirements.txt文件对于复制你的项目代码来说是必要的

为了在她的机器上运行我们的test-project/, Sara 需要做的就是在项目的根目录中创建一个虚拟环境

Sara% cd test-project/
Sara% python3 -m venv venv/

并使用咒语pip install -r requirements.txt在一个活动的虚拟环境中安装项目的依赖项。

Sara% source venv/bin/activate
(venv) Sara% pip install -r requirements.txtCollecting numpy==1.15.3 (from -r i (line 1))
Installing collected packages: numpy
Successfully installed numpy-1.15.3                  # Woohoo! 🎊

现在,Sara 系统上的项目环境与我们系统上的环境完全相同。很整洁,是吧?

解决纷争

可悲的是,事情并不总是按照计划进行。最终你会遇到问题。也许你已经错误地更新了一个特定的站点包,现在发现自己处于依赖地狱的第九层,无法运行你项目的一行代码。话说回来,也许也没那么糟糕。也许你只发现自己在第七关

无论你发现自己处于什么水平,逃离火焰并再次看到阳光的最简单方法是重新创建你项目的虚拟环境。

% rm -r venv/                           # Nukes the old environment
% python3 -m venv venv/                 # Makes a blank new one
% pip install -r requirements.txt       # Re-installs dependencies

就是这样。多亏了你的requirements.txt档案,你才得以重操旧业。总是在项目中包含需求文件的另一个原因。

Dante speaks with the traitors in the ice — Canto XXXII. Illustration by Gustave Doré.

虚拟环境是如何工作的

你想知道更多关于虚拟环境的事情,是吗?比如活动环境如何知道如何使用正确的 Python 解释器以及如何找到正确的第三方库。

echo $PATH

这一切都归结于路径的值,它告诉您的 shell 使用哪个 Python 实例以及在哪里寻找站点包。在您的 base shell 中,路径看起来或多或少会像这样。

% echo $PATH
/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin

当您调用 Python 解释器或运行.py脚本时,您的 shell 会按照的顺序搜索路径中列出的目录,直到遇到 Python 实例。要查看哪个 Python 实例路径先找到,运行which python3

% which python3
/usr/local/bin/python3                 # Your output may differ

也很容易看出这个 Python 实例在哪里寻找带有[site](https://docs.python.org/3/library/site.html#site.getsitepackages)模块的站点包,该模块是 Python 标准库的一部分。

% python3                           # Activates a Python shell
>>> import site                      
>>> site.getsitepackages()          # Points to site-packages folder['/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages']

运行脚本venv/bin/activate会修改 PATH,这样我们的 shell 会在搜索系统的全局二进制文件之前搜索项目的本地二进制文件

% cd ~/test-project/
% source venv/bin/activate
(venv) % echo $PATH~/test-project/venv/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin

现在我们的外壳知道使用我们项目的本地 Python 实例

(venv) % which python3
~/test-project/venv/bin/python3

以及在哪里可以找到我们项目的本地站点包。

(venv) % python3
>>> import site
>>> site.getsitepackages()['~/test-project/venv/lib/python3.7/site-packages']    # Ka-ching 🤑

理智检查

还记得我们之前的tests/imports-test.py剧本吗?它看起来像这样。

#!/usr/bin/env python3          

import numpy as np

我们能够毫无问题地从我们的活动环境中运行这个脚本,因为我们环境的 Python 实例能够访问我们项目的本地站点包。

如果我们在项目的虚拟环境之外运行来自的相同脚本会发生什么?

% tests/imports-test.py                # Look, no active environmentTraceback (most recent call last):
  File "tests/imports-test.py", line 3, in <module>
    import numpy as npModuleNotFoundError: No module named 'numpy' 

是的,我们得到了一个错误— 正如我们应该得到的。如果我们不这样做,这将意味着我们能够从项目外部访问项目的本地站点包,破坏了拥有虚拟环境的整个目的。我们得到一个错误的事实证明我们的项目完全 与我们系统的其余部分隔离。

环境的目录树

有一件事可以帮助我在头脑中组织所有这些信息,那就是对环境的目录树有一个清晰的了解。

test-project/venv/               # Our environment's root directory
├── bin
│   ├── activate                           # Scripts to activate
│   ├── activate.csh                       # our project's
│   ├── activate.fish                      # virtual environment.
│   ├── easy_install
│   ├── easy_install-3.7
│   ├── pip
│   ├── pip3
│   ├── pip3.7
│   ├── python -> /usr/local/bin/python    # Symlinks to system-wide
│   └── python3 -> python3.7               # Python instances.
├── include
├── lib
│   └── python3.7
│       └── site-packages              # Stores local site packages
└── pyvenv.cfg

Dante and Virgil return to the mortal realm — Canto XXXIV. Illustration by Gustave Doré.

进一步阅读

如果你的好奇心还没有得到满足,你还想了解更多关于虚拟环境的知识,我强烈推荐 Real Python 的关于虚拟环境的极好的入门。如果你发现自己沉迷于古斯塔夫·多雷的出色插图,我强烈推荐你阅读但丁的 地狱

除此之外,我们差不多做到了。如果你想了解我最新的数据科学帖子,请随时在 twitter 上关注我。

干杯,祝阅读愉快。

虚拟现实趋势

原文:https://towardsdatascience.com/virtual-reality-trends-2019-64003e2667ef?source=collection_archive---------8-----------------------

四大虚拟现实趋势值得关注

Virtual Reality Trends

2019 年对于虚拟现实来说将会是梦幻般的一年。这是改变我们生活、社交和工作方式的技术之一。它正以更快的速度前进。

从一个完全沉浸式的计算机生成的世界到像 Ready Player One 这样给你一个真实世界视图的创新,虚拟现实的进步令人着迷。谁知道 Cox Connect app 还推出了一些针对 Cox bill pay 的 VR 功能。

对虚拟现实的回顾

虚拟现实不是一项为创造另一个世界而设计的独立技术。它能够创造出逼真的现实。这是所有技术中最令人身临其境的。它包括佩戴一个耳机,创造一个 360 度的模拟。用户被放置在一个数字环境中,他感觉自己真的在那里。

另一方面,增强现实用通常由移动设备生成的数字图像覆盖物理环境。Pokémon Go 游戏是 AR 的一个显著例子。它使用玩家的 GPS 位置来寻找和捕捉数字生物。

2019 年虚拟现实趋势

1。虚拟现实和人工智能的增强

没有人工智能VR 的趋势清单永远不完整。这对组合有改变世界的潜力。首先,这两家公司还处于起步阶段,但它们已经出现了一些。

以 Instagram 和 Snapchat 为例。狗脸和其他有趣的滤镜是人工智能和虚拟现实的创造。如果你在寻找一个科学的例子,谷歌的机器学习显微镜是一个完美的例子。这个工具能够突出癌组织。现在就等着 AR 和 VR 创造出什么厉害的东西。

2。消费娱乐

Oculus 已经与 NBA 合作。该品牌正在使用虚拟现实为其用户提供最先进的娱乐。是的,你猜对了。当你戴着 Oculus VR 耳机坐在球场边时,你会感觉好像真的在 NBA 比赛中一样。很酷,对吧?

VR 头戴技术变得比以前更容易获得。不仅仅局限于游戏玩家。电视观众也可以得到娱乐。

3。教育和培训

教育和培训是工作场所中最昂贵和最危险的活动之一。有了虚拟现实技术,组织可以削减成本,为员工提供最好的培训,而不会让他们面临风险。

最近,沃尔玛已经使用了 17,000 个 Oculus Go 耳机来培训其客户服务部门的员工。同样,美国陆军一直在使用微软 HoloLens 技术为士兵提供他们环境的实时更新。

4。旅行和旅游

通过虚拟现实旅行是一种不同的旅行。身临其境的视频让你甚至在打包行李之前就能体验你的目的地。有了虚拟现实,你可以拥有“先试后买”的体验。

如果你认为你会觉得在邮轮特等舱幽闭恐惧症,那么为什么不测试水域?也许你穿西装会感觉更好。虚拟现实允许你在预订之前探索游轮房间以及酒店房间。

除了检查你的房间,你还可以看到街景,检查场地和附近的餐馆。有了这个虚拟旅游,你可以决定你为自己挑选的目的地是好是坏。

这还不是全部,有了 VR 旅行 app,你甚至可以在回国后重温假期。这是你肯定会珍惜的东西。

VR 的未来如何?

专家表示,虚拟现实的未来是基于位置的。但是等等,这和 GPS 技术无关。基于位置意味着将虚拟现实体验带给用户,无论他们身在何处。他们无需购买就能接触到技术。

然而,为此,客户需要意识到虚拟现实的主动性。他们一定也对家用虚拟现实感兴趣。它还有很长的路要走。

结论

当今时代的消费者追求的是体验。VR 有能力在未来的学习和发展中发挥巨大的作用。通过虚拟仿真,用户可以以很少的成本获得真实的生活体验。

虚拟现实的未来仍在发展中。这很像不同频道的考克斯频道阵容。并非所有受欢迎的频道在所有地区都可用。一些虚拟现实技术和应用已经投入使用,但大部分仍在开发中。

可视化 100,000 件亚马逊产品

原文:https://towardsdatascience.com/vis-amz-83dea6fcb059?source=collection_archive---------8-----------------------

快速句子嵌入 (fse) 使您能够在几分钟内计算数百万条评论的句子嵌入。

t-SNE Mapping of 100,000 Amazon Products. © Oliver Borchers

本文中的 fse 代码可能会被弃用。请确保使用Github上概述的更新代码。

介绍

在我的博士研究中,我经常研究句子嵌入。更具体地说,我使用平均[1]和平滑逆频率(SIF)2嵌入。虽然 Github 上的原始实现非常有用,但我总是发现它们很难集成到我使用的任何 NLP 管道中。这是由于非标准化的接口和缺乏优化。因此,我决定在一个优化的包中实现 Average、SIF 和 uSIF 3嵌入,这个包巧妙地集成到 Gensim 中。部分是因为我喜欢挑战,部分是因为我需要好的工具。这个包叫做 fse ,在 Github 和 Pypi 上都有。看看教程笔记本看看它是怎么工作的。

pip install -U fse

您将需要常规的 Python (>3.6)包,特别是 Numpy、Scipy、Cython 和 Gensim。
TL;DR:如果你需要快速的句子嵌入,就用:

from gensim.models import FastText
sentences = [["cat", "say", "meow"], ["dog", "say", "woof"]]
ft = FastText(sentences, min_count=1, size=10)from fse.models import Average
from fse import IndexedList
model = Average(ft)
model.train(IndexedList(sentences))model.sv.similarity(0,1)

这篇文章是为技术数据科学受众而写的。我们将探索如何使用快速句子嵌入来可视化众所周知的亚马逊评论数据集。这个故事中使用的交易工具是 fse 、FIt-SNE 和 Tableau。

这条管道的结果显示在本文的第一张图中。在这篇文章的最后,你会发现一个交互式 Tableau 地图的链接,可以浏览所有 100,000 种产品。

关于这个库内部工作的更详细的介绍,请随意阅读我的第一篇关于句子嵌入的文章。

数据

如果你和 NLP 一起工作,你很可能已经听说过公共的斯坦福亚马逊评论数据集。三年前,我收到了朱利安·麦考利的完整版本,用于我的市场营销博士研究,并不时地继续使用它。第二大类别是“电子产品”类别,共有 7,824,482 条评论。知道里面到底有什么不是很好吗?

为了获得每个产品的嵌入,我们需要评论数据和元数据。两者都由唯一的 Amazon ASIN 标识符连接。我已经准备好了一个很好的熊猫数据框架(不允许我分享)。让我们来看看元数据:

Metadata of Amazon Reviews. © Oliver Borchers

为了实际可视化数据(例如,将每个产品表示为一个可映射的向量),我们只能使用每个产品的评论。因此,我们正在处理多对一嵌入。在过滤掉少于 10 条评论的 asin 后,我们最终得到 97,249 条唯一 asin 和 6,875,530 条评论。

我们不对文本数据进行任何预处理。
为什么?
因为。

从评论到产品嵌入

为了获得每个评论的嵌入,我们首先需要某种预训练的嵌入。评论很可能包含许多不认识的单词。幸运的是, fse 提供了开箱即用的 FastText 模型支持。我们首先加载公开可用的 FastText 模型:

from gensim.models.keyedvectors import FastTextKeyedVectors
ft = FastTextKeyedVectors.load("../models/ft_crawl_300d_2m.model")

接下来,我们实例化来自 fse 的 SIF 模型。

from fse.models import SIF
model = SIF(ft, components=10, lang_freq="en")

组件的数量等于 10,这在 STS 基准再现性部分中报告。

请注意 lang_freq 参数。一些预先训练的嵌入不包含关于语料库中词频的信息。 fse 支持多种语言预训练模型的词频归纳,这对于 SIF 和 uSIF 模型是必不可少的(这可能需要一段时间,取决于您的词汇量)。

所有的 fse 模型都要求输入是一个元组列表。元组的第一个条目是标记列表(句子),第二个条目表示句子的索引。后者确定句子被添加到嵌入矩阵中的目标行。我们稍后将在单行上写多个句子(评论)(多对一)。

s = (["Hello", "world"], 0)

fse 提供了多个输入类,它们都提供了不同的功能。有 6 个输入类可供选择:

  • IndexedList:用于已经拆分的句子。
  • 索引列表:对于已经预先拆分的句子,每个句子有一个自定义的索引。
  • SplitIndexedList:用于未拆分的句子。会分裂琴弦。
  • Split C IndexedList:用于未拆分的句子,每个句子有一个自定义索引。
  • SplitIndexedList:用于未被拆分的句子。会分裂琴弦。您可以提供自定义拆分功能。
  • CSplitCindexed list:用于你想提供自定义索引和自定义 Split 函数的句子。
  • IndexedLineDocument:用于从磁盘上流式传输句子。可编入索引以方便搜索相似的句子。

这些是按速度排序的。也就是说,IndexedList 是最快的,而CSplitCindexed list 是最慢的变体(调用越多=越慢)。为什么要上多节课?因为我希望每个 getitem 方法有尽可能少的代码行,不会降低计算速度。

对于我们的审查数据,我们使用 Split C IndexedList,因为我们不想预分割数据(预分割 700 万)。评论会占用大量内存)。在内部,该类将指向我们的评论,并且只在您调用 getitem 时执行预处理。

from fse import SplitCIndexedListreview = ["I really like this product.", "Its nice and comfy."]
s = SplitCIndexedList(review, custom_index = [0, 0])
print(s[0])
print(s[1])>>> (['I', 'really', 'like', 'this', 'product.'], 0)
>>> (['Its', 'nice', 'and', 'comfy.'], 0)

注意,两个句子都指向索引 0。因此,它们都将被添加到索引为 0 的嵌入中。为了将每个 ASIN 映射到一个索引,我们只需要一些更方便的函数。

from fse import SplitCIndexedListASIN_TO_IDX = {asin : index for index, asin in enumerate(meta.index)}indexed_reviews = SplitCIndexedList(data.reviewText.values, custom_index = [ASIN_TO_IDX[asin] for asin in data.asin])

既然一切都准备好了,我们可以打电话了

model.train(indexed_reviews)

该模型在具有 16 个内核和 32 GB ram 的云实例上进行训练。整个过程大约需要 15 分钟,大约 8500 条评论/秒。每条评论平均包含 86 个单词,我们总共遇到 593,774,622 个单词。我们将大约 700 万条评论压缩成一个 10 万* 300 的矩阵。添加更多的工人没有什么区别,因为预处理(分割)是瓶颈。

如果你的数据已经预先拆分,在普通的 MacBook Pro 上你可以达到每秒 500,000 句。如果你想了解更多,可以看看教程笔记本

使用和可视化嵌入

在训练句子嵌入之后,我们可以通过索引或完整的嵌入矩阵来访问每个单独的嵌入。该语法尽可能接近 Gensims 语法,以便于使用。

model.sv[0]       # Access embedding with index 0
model.sv.vectors  # Access embedding matrix 

相应的 Sentencevectors (sv)类提供了相当多的函数来处理生成的句子嵌入。例如,您可以使用相似性、距离、最相似、按单词相似、按句子相似或按向量相似。

如果我们回到标准的 sklearn t-SNE 实现,可视化这么多数据可能需要非常长的时间。因此,让我们尝试一种更优化的方法: FIt-SNE 。这种优化的 t-SNE 实现利用傅立叶变换来加速 t-SNE 的计算。请随意阅读这篇论文。它工作起来很有魅力,使用了机器的所有 16 个核心。

import sys; sys.path.append('../FIt-SNE')
from fast_tsne import fast_tsnemapping = fast_tsne(model.sv.vectors, perplexity=50, seed=42)

计算完映射后,我们已经有效地完成了最困难的部分。将元数据中的一些信息添加到每个点,我们最终可以将所有内容导出到 Tableau。

表格映射

要访问相应的图形,请访问我的公共 tableau 页面:

https://public . tableau . com/views/product map _ 15674406439260/TSNEPrice?:embed = y&:display _ count = yes&:origin = viz _ share _ link

您可以将鼠标悬停在每个点上,获取关于产品价格、名称、品牌等信息。

观察嵌入,我们观察到每个聚类中包含相当多的信息。

Map of Amazon Reviews. © Oliver Borchers

此外,我研究了数据,并手动标记了一些聚类,以确定这些聚类的形成是否至少在某种程度上是有效的。看起来映射捕获了评论中包含的大量信息。

请记住:我们所做的是平均每个评论的所有单词,并总结所有评论。我对使用简单的基于平均值的嵌入所能实现的东西感到非常震惊。

Manual Category Labels of Amazon Reviews. © Oliver Borchers

结论

句子嵌入是自然语言处理流水线的重要组成部分。这篇博文展示了如何使用快速句子嵌入、FIt-SNE 和 Tableau 来可视化众所周知的亚马逊评论数据集。

我希望你能从使用 fse 中找到乐趣。请随时建议可能有用的进一步模型或功能。

相应的 fse 包可在 pip / Github 上获得,为数据科学家提供了一种快速计算句子嵌入的方法。

如有疑问,欢迎联系 me

如果你喜欢这些内容,别忘了关注我:-)

附加说明

这篇文章的代码可以在 Github 和 pip 上找到:

pip install -U fse

文学

  1. Iyyer M,Manjunatha V,Boyd-Graber J,Daumé III H (2015)深度无序合成与文本分类的句法方法相匹敌。继续。第 53 届 Annu。见面。协会计算机。语言学家。第七国际。Jt。糖膏剂纳特。郎。过程。, 1681–1691.
  2. Arora S,Liang Y,Ma T (2017)一个简单但难以击败的句子嵌入基线。里面的糖膏剂学习。代表。(法国土伦),1-16 岁。
  3. Ethayarajh,Kawin (2018)无监督随机行走句子嵌入:一个强大而简单的基线。NLP 表征学习第三次研讨会会议录,91–100。
  4. 林德曼 G C,拉赫 M,霍斯金斯 J G,斯坦纳伯格 S,克鲁格 Y (2019)基于快速插值的 t-SNE,用于改进单细胞 RNA-seq 数据的可视化。自然方法(16),243–245 页。

放弃

所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。作者对本网站内容的任何错误或遗漏不承担任何责任或义务。本网站包含的信息按“原样”提供,不保证完整性、准确性、有用性或及时性。

视觉失认症:一个神经网络类比

原文:https://towardsdatascience.com/visual-agnosia-a-neural-network-analogy-8e208438b1ec?source=collection_archive---------40-----------------------

Visual Agnosia: Intricate Brain Imbroglio

本周,我开始阅读奥利弗·萨克斯博士的故事《把妻子错当成帽子的男人》,这是一个引人入胜的故事,讲的是一位失去视觉解读能力的 P 博士,这种能力在神经学上被称为视觉失认症。故事从对他的症状的粗略描述开始,逐步发展到详细描述他进入功能失调的视觉系统的妄想世界。从一个具有深刻视觉想象力和判断力的人到一个像卷积神经网络一样以非常抽象的方式看待世界的人,这是一种诗意的衰退。我越来越多地阅读这个故事,不禁将它与表现糟糕的卷积/胶囊/RNN 网络和相应的生成网络相提并论,试图用一些其他图像来弥补不足。

在这篇文章中,我提出了一些理论,你可以称之为未经训练的头脑的漫谈,可能是一个长镜头,将神经心理学和深度学习两个不同领域的片段放在一起。考虑到激发这篇文章和最初故事的音乐家 P 博士的情况,这似乎是合适的。虽然,要注意的是,这篇文章只是理论上的,没有实验基础,所以它的论点应该被大量的盐(不是一点点我的意思)。

理论 1:缺失神经元理论

症状:视觉皮层 esp 丢失部分图像。像人脸一样的动画。有时这些脸会出现在随机的地方,比如柱子等。视觉缺失的部分被其他东西代替,比如一顶帽子代替了 P 博士妻子的头。

假设:顶叶和枕叶部分神经元的脱落/失活。

解释:P 博士表现出的无法识别面孔的症状或这些面孔被帽子或鞋子等无生命物体取代的情况,可能是由于右半球的病变/肿瘤而导致一些神经元不放电的情况,以及大脑通过产生随机意象/视觉来填补这种功能障碍所导致的缺陷的绝望尝试。我想用一张图表来说明这一点,这张图表应该模拟了你前额叶皮层中的一些神经元,至少我希望如此。

Defective visual discriminator and adversary

如果你看到上面的图表,很明显,在试图识别它通过眼睛接收的视觉信息的鉴别器网络中有一些错误。问题可能在于这个过程中的一些关键神经元已经停止运作。因此,大脑中的视觉皮层生成的图像是不完整的,因为它几乎正确地获得了各个部分,但在某些方面却缺失了,这妨碍了整体场景的创建。

为了弥补这一缺失,大脑生成了另一个片段,比如一张脸,并用这一片段来填补那些缺失的地方。但问题是,这个生成的脸被预期为对场景的上下文是正确的,因为应该告诉生成网络这个脸是否合适的对手本身缺乏一些神经元,因此呈现出扭曲的判断。

可能的处理:

一种可能的治疗方法是开出能够重新触发或模拟顶叶和枕叶神经元的药物。

第二种方法可能是重现病人遇到这些场景或人的某些场景,这样仍然完整的记忆可以用来重新点燃这些神经元。

同样,所有这些治疗建议都只是瞎猜,并不是基于彻底的研究。

理论 2:情感缺失

症状:P 博士无法识别他的学生/人,尽管他能够识别出诸如长鼻子、卷发或身高等个人特征。这意味着视觉的病理部分没有问题。除此之外,他以一种非常抽象、粗略的形式识别人,就像一台机器主要是 CNN,它的卷积层识别特征,最大池增加了一般化所必需的不变性。另一个限制是他能够通过听到人们的声音或他们演奏的音乐来识别他们。这就像失去的与视觉刺激相关的人类触觉/情感部分通过听觉重新获得。

假设:大脑右半球和杏仁核控制的情绪都有问题。这些情感是我们生活中与人联系的基本要素,是增加亲密关系的桥梁,是识别我们的朋友和家人的基本要素,就像是我们的视觉系统所依赖的 KPI 或独立变量。我想提出的理论是,由于杏仁核的功能障碍,这些情绪在网络的输入中缺乏,这导致 P 博士无法识别人。

Emotional Deficit Compensated By Music

音乐起作用的原因是,它刺激杏仁核唤起与某个情况或某个人相关的情绪,并加强输入向量,以便视觉识别起作用。

可能的处理:

一种可能的治疗是再次刺激杏仁核中的神经元/腺体,以产生进入大脑视觉识别机制的情绪输入。这些神经元可以通过讲述能够重现相同视觉意象的故事来激活。

另一种方法是重现能够唤起与一个人相关的记忆的情景,从而激活杏仁核的相同部分,重现相同的情绪。通过这种方式,输入将得到加强,并可能协调分离的部分。

理论 3:节奏难题

症状:如果 P 医生在进行身体活动或动作时哼的歌曲受到干扰,他似乎会失去对该身体活动或动作的上下文/判断。这也许是他表现出的最奇特的症状。P 博士似乎失去了很多识别和判断的能力,但他失去了什么,他得到了音乐敏锐度。这意味着,如果他一边哼着一首特定的歌曲,一边进行像刮胡子这样的动作,他就像一台加满油的机器,像正常人一样进行活动,但一旦像敲击这样的小事打破了他的节奏,他就会失去所有的上下文,并陷入停顿,直到同一首曲子以某种方式重新点燃精神进步。

假设:一个动作的序列有一个时间维度。与神经网络世界中的 RNN 平行的那个。在这种情况下,该 RNN 是编码器解码器网络,其中编码器将过去的动作编码成上下文向量,并将其输入到解码器以预测接下来的动作。在 P 博士的例子中,这个特殊的背景向量似乎在每个时间步都被大脑产生的音乐所强化。这种音乐在某种程度上给我们提供了一种注意力环境,告诉大脑注意什么和什么时候注意。但是一旦音乐停止,这个上下文就丢失了,解码器停止获得下一个时间步长的任何信息,并且变成空白。这导致了上下文和运动的丢失。

Missing context reinforced by music attention

可能的处理:

通过语音指令重新训练大脑。一遍又一遍地重复它们,直到活动完成。这可能有助于激活休眠的神经元。然后慢慢地开始让说明变得稀疏,然后完全放弃它们,让这个人自己建立那个环境。

机器人视觉注意力

原文:https://towardsdatascience.com/visual-attention-for-robotics-8fca83cbd95a?source=collection_archive---------41-----------------------

利用视觉任务聚焦注意强化视觉运动策略

Teacher-Student framework for the task of robotic object manipulation. Please read our CVPR 2019 paper for more details. Also, the code and data are available on our project page.

物体操纵是机器人研究的主要任务之一。通过演示训练策略神经网络是设计视觉运动策略的一种方式。然而,重新编写演示既昂贵又耗时。此外,在记录训练演示样本后,环境可能会发生变化。例如,在测试期间,未知物体可能进入机器人的视觉场景。在这种情况下,大多数视觉运动策略都会失败,因为它们遇到了一个看不见的状态。此外,干扰可以是物理的或视觉的,这意味着某些东西可以干扰或接触物体一会儿,并阻止机器人完成工作(物理干扰)或只是机器人摄像机输入流中的一些意外视觉模式(视觉干扰)。由于存在无限的干扰场景,为每一个可能的物理干扰收集训练样本是不切实际的。

我们研究了一种在良性条件下训练策略神经网络的方法,这意味着在训练期间零干扰,同时在测试时间对物理/视觉干扰具有鲁棒性。

秘密成分?视觉注意!

我们设计了一个师生系统,从输入帧中提取丰富的特征,这些特征对看不见的干扰具有鲁棒性。我们的教师网络是一个简单的文本(机器人的任务)框架接地(作为注意力地图)网络。我们称之为任务聚焦视觉注意(TFA)。

学生网络是一个可变自动编码器(VAE)-GAN,它不仅试图重建输入帧,而且试图模仿教师网络产生的注意力。这是知识升华的一种形式。教师网络可以捕捉任务(在我们的实验中是自然语言句子)来构建知识,而学生网络可以通过模仿教师的行为来获得相同的知识,并提供移动机器人的运动网络。

我们表明,学生网络不仅可以学习注意力,还可以产生对干扰具有鲁棒性的特征。知道干扰会在注意过程中被忽略。

请阅读我们的论文了解更多详情。

此外,代码和数据可在我们的项目页面上获得。

请不要犹豫提出你的问题。

您也可以观看我的 YouTube 演示,了解更多详细信息和讨论:

视觉贝叶斯:你的伴侣忠诚吗?

原文:https://towardsdatascience.com/visual-bayes-is-your-partner-faithful-90b2fdba7cc8?source=collection_archive---------19-----------------------

什么可以解释伴侣手机上一个未知号码的心形表情符号?

“Just relax” says Bayes. Source

在大学期间,我收到了许多关于贝叶斯定理的令人不满意的解释。第一次是在统计 101。教授只是把公式写在白板上,让我们背下来。给定一个问题陈述,只需将变量输入公式,得到输出,得到一个 a。更像是一个 b。

我遇到的第二个解释使用了一棵树。它可以在 YouTube 视频这里找到。问题是不够直观。要处理的信息太多了,你无法在你祖母看电视的时候向她解释。

接下来,我尝试了一门名为“社会科学家数据分析 T2”的在线课程。麻省理工学院讲师萨拉·费希尔在几次讲座中讨论了这个定理。甚至她声明这不是很直观。在内特·西尔弗写出《信号和噪音》之前,我对一个简单且持续不断的解释失去了所有希望。

这是迄今为止我发现的最好的解释,我将尝试给它一个我在别处找不到的视觉扭曲。在我看来,贝叶斯定理允许决策者就一个困境提出 3 个问题。这是测试你的勇气和减少偏见的一种方式。

想象一下,你在伴侣的手机里看到一条短信,上面有一个来自未知号码的心形表情符号。他/她欺骗你的可能性有多大?你发现的新的证据是文本,你试图估计你的伴侣在哪里出轨的假设。如果你愿意探究 3 个问题,我们可以找到你的伴侣出轨的可能性。

  1. 忘掉证据。她/他欺骗你的可能性有多大?这就是所谓的先验。如果你没有看到这篇文章,你认为你的伴侣出轨的可能性有多大?这很难考虑,尤其是当你情绪激动的时候,但是这是减少你自己偏见的第一步。研究发现,在任何一年的任何一方,这个数字都是 4%。
  2. 假设她/他没有作弊,那么文本出现的几率有多大?所以,最好的可能情况:这只是一场误会。我们假设他们是忠实的。什么能解释这篇文章?一个密友?对一张图片的反应?也许他的某个家庭成员换了手机?我们给它分配 50%的概率。
  3. 鉴于她/他在欺骗,那么该文本出现的几率有多大?最坏的情况。如果他们在欺骗,那么新来的人给他们发短信是有道理的。话说回来,他们会更加小心。我们给它 70%的机会。

综上所述,你需要估计三件事。一个清白概率没有任何证据的情况下,给出证据的最好情况的几率和给出证据的最坏情况的几率。对于任何决定来说,这是 3 件值得考虑的事情。每当你收到有影响力的新闻时,就后退一步,想想用贝叶斯框架来看待它是否有意义。

内特用一个不同的事件作为证据:你在卧室里发现了不属于你的内衣。

Chapter 8: The Signal and the Noise

使用我们的数字:

  • 先前(x): 4%
  • 最坏情况(y): 70%
  • 最佳情况(z): 50%
  • 结果(后验):5%

内特的数字导致了更高的后验概率。但是有道理。他认为最好的情况是 5%。很难想象为什么内衣会出现在卧室里,如果它们不是出轨的话。在我们的例子中,一个文本可以有多种解释。毕竟,心形表情符号在很多情况下都是有用的。

当然,在这个例子中,最坏和最好的情况概率是主观的。然而,好消息是你可以在任何给定的情况下分配你自己的权重。

直观解释

这里有一个链接供您更改输入:
https://www.desmos.com/calculator/gyb1jzchr8

让我们把注意力集中在积极的象限。x 是“干净概率”。可以确定另外两个量,求后验如何反应(Y)。

增加“最佳情况(c)”的机会将线条拖到右下角。因此,即使有很高的先验,如果最好的情况有很高的概率,后验概率也不会很大。听起来像是我们的场景。有人收到心形表情符号的概率相当高。Bayes 说“放松就好”。

增加“最坏情况(a)”的几率将线条拖到左上角。如果最坏的情况发生的可能性很大,你应该更加谨慎。

这是一个非常对称的图表,显示了这个定理是多么的基本。希望这能节省你理解它的时间。如果你想深入数学,我推荐这篇文章。推导定理并不疯狂。如果你对配方本身感兴趣,更多信息请点击这里这里。如果你想看这个定理的实际应用,点击这里或者这里。在下一篇文章中,我将使用 Desmos 来解释一个非常基本的神经网络。欢迎任何评论!

视觉深度计算机视觉

原文:https://towardsdatascience.com/visual-deep-computer-vision-f1e9fcca8f3b?source=collection_archive---------9-----------------------

或者你如何在不是专家的情况下运行计算机视觉的深度学习算法。

介绍

深度学习已经推动并解决了各种计算机视觉问题,如对象检测、运动跟踪、动作识别、人体姿势估计、语义分割等。

由于卷积神经网络(CNN ),该领域的最大进步已经成为可能。CNN 具有独特的特征学习能力,即基于给定数据集自动学习特征。CNN 对于变换也是不变的,这对于某些计算机视觉应用来说是一个巨大的资产。

你可以在这里了解更多信息:

[## 全卷积神经网络|第一部分

导师指导的学习指南,以应对 Coursera 深度学习专业化课程 4

towardsdatascience.com](/convolutional-neural-networks-for-all-part-i-cdd282ee7947)

请观看 Brandon Rohrer 关于他们的精彩视频:

我们通常是怎么做的

通常我们用深度学习编程来做计算机视觉,学习新的 API,有些比其他的更难,有些真的很容易,比如 Keras 或 PyTorch。为此,你需要理解深度学习、计算机视觉概念、OpenCV 等等。但是有一个问题。

如果你想运行实验,测试不同数量的时期,参数,估计,优化等等。当你编程时,这些事情开始变得复杂。在这里,我想向大家展示一个非常简单但非常强大的方法,用深度学习通过一个叫做深度学习工作室的平台来做计算机视觉。

新的方式

我之前已经讨论过这个平台,如果你想对它有一个大概的了解,可以看看这些文章:

[## 深度认知让深度学习变得简单

在过去的一个月里,我有幸见到了 DeepCognition.ai 的创始人

becominghuman.ai](https://becominghuman.ai/deep-learning-made-easy-with-deep-cognition-403fbe445351) [## 深度认知的视频漫游

大家好!在本文中,我将与您分享几个视频,带您浏览深度认知的平台…

towardsdatascience.com](/a-video-walkthrough-of-deep-cognition-fd0ca59d2f76)

但在这里,我想向你展示三个使用深度计算机视觉平台的超级有用的方法。

1.上传你的 Keras 模型并训练它

假设您在自己的 jupyter 笔记本或 IDE 中创建了 Keras 模型。您希望使用该平台的所有功能。这很简单。

你要做的就是去站台:

[## 主页

我们想邀请您在 3 月 26 日至 29 日的 GPU 技术大会上加入 Deep Cognition 的团队,展位号为 1035…

deepcognition.ai](https://deepcognition.ai/)

并启动 app(你得先创建一个账号,是免费的 btw)。当你进入平台时,你会看到:

然后点击箭头上传你的模型。我们将在 Keras 中尝试使用带有卷积网络的 CIFAR-10 模型。这里重要的是:这个模型应该与 Keras 1.2.2 兼容,这是我们目前唯一的限制。

我们将上传合作创建的模型,您可以在此处访问:

[## keras-team/keras

人类的深度学习。通过在 GitHub 上创建一个帐户,为 keras-team/keras 开发做出贡献。

github.com](https://github.com/keras-team/keras/blob/keras-1/examples/cifar10_cnn.py)

如果你想从这里复制,我创建了一个要点:

在尺寸订购部分选择否。

之后,一个新的项目将会以 Python 文件的名称创建。然后点击打开,你会看到:

在数据部分选择 cifar-10-public,以便能够训练模型。顺便说一句,如果你想训练一个不同的模型,你可以上传你自己的图像数据集。

现在,如果您单击 Model 选项卡,您将看到刚刚上传的代码的可视化表示:

你可以玩玩它,看看不同的选项。在那里你可以改变你的超参数,当然也可以训练模型。

我将这个配置用于超参数:

然后你去训练你的模型。在下面的视频中,您可以看到如何使用培训选项卡解决不同的问题:

2.将您的 Keras 代码转换为 Tensorflow、Pytorch、MXNet 等

有时你的经理或公司会要求你在不同的框架中编写你的深度学习算法。如果你没有时间学习 X 数量的新 API,你可以很容易地将 Keras 代码转换成不同的框架。

在模型选项卡中,只需点击<>按钮,您将看到:

在可用选项中,您可以在不同的框架中获得您的模型:

Pytorch :

张量流:

你可以免费得到所有这些。你甚至可以下载一个桌面版本并使用你自己的 GPU,点击这里查看:

[## 深度学习工作室桌面

Deep Learning Studio - Desktop 是在您的硬件上本地运行的单用户解决方案。桌面版允许您…

deepcognition.ai](https://deepcognition.ai/products/desktop/)

3.将您的模型部署为 Web 服务或 REST APIs:

Having a magic button to deploy your models would be awesome.

当你完成你的模型,可悲的是很多时候它会永远留在你的电脑上。这太可悲了。想象一下,一个画家不能向任何人展示他的杰作。

通过 DLS 的部署功能,您将能够看到自己和他人的模型在运行。

让我们看看如何做到这一点。

当你建立你的实验时,你给它们命名。我将部署一个由 SGD 优化的模型,命名为 sgd-2(这只是一个名字):

在推理/部署选项卡中,单击部署:

选择运行,创建服务名,然后选择是要使用正在使用的实例还是远程实例进行部署。

如果你这样做,它会问你更多的信息。我将使用我的云实例进行部署:

之后,您将会看到类似这样的内容:

如果您还记得,CIFAR-10 数据集由 10 类 60000 幅 32x32 彩色图像组成。这些类是飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船和卡车。所以我们试着上传一张飞机的图片,看看模型能不能探测到。我将用这张船的图片:

http://www.seatrade-cruise.com/media/k2/items/cache/3356e0cd9331018e19a8cee016f484a2_XL.jpg

记住我们模型船中的是第 8 级。所以我只需点击上传面板:

点击提交,我们看到:

现在你知道了!您自己的具有深度学习的计算机视觉模型部署起来超级容易!

结论

生活已经够艰难的了,让它变得更加艰难。如果你是一名程序员、数据科学家、机器学习工程师或类似的人,我可以向你保证,我在这里展示的一些内容正在让你日复一日地奋斗。

借助这些工具,您可以满怀信心地轻松试验、测试和部署您的计算机视觉问题(以及更多问题)。我希望你能从中发现价值。

稍后我会添加更多不同主题的示例:)

成为数据科学家的视觉指南

原文:https://towardsdatascience.com/visual-guide-to-become-a-data-scientist-a8ae6430a249?source=collection_archive---------27-----------------------

现在是进入数据科学的最佳时机!

我们生活在一个前所未有的数据创造时代。我们参与的每个流程都是数字化的,并且会留下数字足迹。这意味着需要收集、利用和提取有用信息的数据。这就是为什么现在是成为数据科学家的最佳时机。这里有一个成为其中一员的视觉指南。

How to become a Data Scientist in easy, visual steps.

开始学习

这是数据学习的开始:

GitHub 上的项目

然后,您应该开始在 GitHub 上构建一个数据科学项目组合:

数据科学书籍

你绝对应该开始阅读关于数据科学的书籍。以下是您开始的标题:

成为一名优秀的数据科学家

如果你有你的 GitHub 作品集,读了一两本书,你可能会开始找工作。以下是一些关于数据科学求职的建议:

数据科学工作类型

你应该记得有不同类型的数据科学工作:

工作访谈

最后,当你准备好并研究了你想去工作的公司后,你应该为面试做准备:

一锤定音

如果你已经做到了这一步,你应该准备好找到你的第一份(或第二/第三份)数据科学家工作。恭喜你!现在开始最激动人心的冒险。

Data Science Job

最后,如果你想了解成为一名数据科学家意味着什么,那么看看我的书数据科学工作:如何成为一名数据科学家,它将指导你完成这个过程。

祝你好运!

数据科学可视化指南

原文:https://towardsdatascience.com/visual-guide-to-data-science-d46bd3d9c69f?source=collection_archive---------24-----------------------

厌倦了阅读关于进入数据科学的长文?这是最短的一个。

数据科学是目前最热门的工作之一。全球有大量的机会,而且肯定会更多,因为我们才刚刚进入数据时代。那么,为什么不自己成为一名数据科学家?这应该是视觉引导,使你容易。那就是我:

Hello!

步骤 0:修改你的统计学和线性代数

第一步:阅读数据科学书籍从 Python 开始

第二步:在 GitHub 上建立一个开源项目组合。使用 Kaggle 数据集。

第三步:免费学习哈佛和其他好地方的在线课程

第 4 步:准备数据科学面试

第五步:永远不要停止学习

让我知道你如何喜欢这个指南,你会有什么建议。

如果你喜欢我创造的东西,请关注我的媒体频道订阅我的 YouTube 频道,在那里我也每天谈论数据科学和机器学习。

最后,如果你想了解成为一名数据科学家意味着什么,那么看看我的书数据科学工作:如何成为一名数据科学家,它将指导你完成这个过程。

Data Science Job

用 KMeans 进行聚类的直观介绍

原文:https://towardsdatascience.com/visual-introduction-to-clustering-with-kmeans-89e71e97c60f?source=collection_archive---------27-----------------------

通过二维和三维空间以及交互式图形中的可视化方式直观了解 KMeans 聚类

聚类是一种无监督学习,当我们事先不知道数据中的每个观察值属于哪个组时,我们会使用它。

用于聚类的 KMeans 算法基本上由 5 个步骤组成:

  • 第一步:选择簇的数量 K
  • 第二步:随机选择 K 个点作为聚类中心
  • 步骤 3: 将每个数据点分配到最近的质心
  • 步骤 4: 计算并放置每个聚类的新质心
  • 步骤 5: 重复步骤 4,直到没有观察值改变聚类

因此,让我们先看看我们将使用的数据,然后再进入下一步。

加载数据

**In [1]:**import pandas as pd
data = pd.read_csv('mall.csv')
data = data.drop(['CustomerID', 'Genre'], axis=1)
data.head() **Out [1]:** **Age  Annual Income (k$)  Spending Score (1-100)**
0   19                  15                      39
1   21                  15                      81
2   20                  16                       6
3   23                  16                      77
4   31                  17                      40

注意:我只放弃了流派特性,因为二进制数据在可视化时看起来不那么吸引人。这个功能本来也可以用的。

该数据描述了商场中顾客的 3 个特征,总共有 200 次观察。在接下来的步骤中,我们将只处理年收入(k$)和支出分数(1-100 ),并将其可视化为二维。稍后我会用所有的数据展示它在三维空间中的样子。

第一步:选择簇的数量K

不幸的是,对于聚类来说,没有找到准确的聚类数的终极方法。然而,有相当多的好工具可以帮助你,其中之一就是使用 yellowbrick 库中的 KElbowVisualizer。正如你在下面看到的,自动“肘”检测器说 5 个集群将是最好的选择。我们选择最佳点的方法是找到曲线上开始变平最多的点(这导致大量的自我解释)。

通过绘制数据,我们可以看到,这看起来确实是数据中合理的集群数量。

第二步:随机选择 K 个点作为聚类中心

在我们的下一步中,我们基本上只是在图上选择 5 个随机点作为初始聚类。

步骤 3:将每个数据点分配到最近的聚类

在下一步中,我们只需计算所有观测值到每个聚类的距离,并找出距离最小的聚类,这将是该观测值将被分配到的聚类。我们使用的距离就是我们所说的欧几里德距离,这只是直接距离的一种数学说法。

步骤 4:计算并放置每个聚类的新质心

这是我们看到算法开始工作的一步,捕捉数据中的模式。对于数据集中的每个聚类,我们计算分配给该聚类的观察值的平均年收入(k$) 和平均支出分数(1-100)。我们看到,紫色的聚类在中间获得了相当多的分配给它的观察值,这意味着支出得分(1–100)的平均值很可能会向上和向左移动一点(这意味着当我们移动聚类时,它可能会更接近最初没有连接到该聚类的其他观察值)。我们看到在下一张图中也是这种情况,星星显示了星团的初始位置。注意一些观察是如何改变聚类的。中间几乎所有的观测都和现在的紫色星团有联系。

步骤 5:重复步骤 4,直到没有观察值改变聚类

最后,我们只需重复第 4 步,直到没有观察值改变集群,我们有我们的最终集群指定。对于下图,我们只是在第二次迭代,我们看到集群已经看起来相当合理。实际上,我们可能需要重复第四步一到两次,才能让星团稳定在它们真正的中心。

在三维空间中可视化

实际上,当我们进入高维空间时,KMeans 聚类并没有什么不同。唯一的区别是,当我们超过 3 个特征时,我们就不能再想象它了。让我们试着检查一下星团在三维空间中的样子。

获取代码

If the code does not appear properly, you can click the filename at the bottom and jump directly to GitHub or download the Jupyter Notebook directly here: click here.

我希望这篇简短的介绍和对 KMeans 的可视化描述能够帮助您更好地理解集群。请随意留下您的评论或问题。你也可以看看更多关于神经网络或者决策树的其他文章。

面向分布式深度学习的环形全递归视觉直觉

原文:https://towardsdatascience.com/visual-intuition-on-ring-allreduce-for-distributed-deep-learning-d1f34b4911da?source=collection_archive---------5-----------------------

最近,我发现自己正在处理一个非常大的数据集,这是一个需要并行学习才能实现的数据集。我立刻想到了优步的 Horovod 。我之前在优步的一次技术演讲中听说过它,但并没有真正使用过。我发现它非常有趣,是一个很棒的框架,从高级简化到支持这个框架的算法。在这篇文章中,我将尝试描述我对后者的理解。

那么它到底是做什么的呢?

对此需要理解的重要一点是,在深度学习中,我们需要计算梯度,以便能够调整我们的权重。没有这个学习就不可能发生。为了计算这个梯度,我们需要处理所有的数据。当这样的数据太大时,这就成了一个问题。这就是我们并行处理这些计算的原因。这意味着我们将有几台计算机并行处理一部分数据。当这些处理单元或工作者(它们可以是 CPU、GPU、TPU 等)中的每一个时,)完成了对其子集的梯度计算之后,他们需要将其结果传达给所涉及的其余过程。实际上,每个流程都需要与其他流程/工作人员交流结果。幸运的是,其他人在过去也遇到过这个问题,并设计了 Allreduce 算法,它正好可以做到这一点。我先描述一下这个。

全归算法

从概念上讲,该算法让每个进程/工作者与所有其他进程共享其数据,并应用归约操作。这种运算可以是任何一种归约运算,如求和、相乘、求最大值或最小值。换句话说,它将所有进程/工作进程中的目标数组缩减为一个数组,并将结果数组返回给所有进程。

例如,这个:

Before Allreduce operation

在所有的减少总和之后会变成这样:

After Allreduce operation

那么你真的会怎么做呢?我马上想到了天真的方法。互相发送数据数组,然后对每个进程应用 sum 运算,如下所示:

Message passing using naive Allreduce

事实证明,这种方式并不理想。它发送了太多不必要的消息,可能会使消息网络饱和。

另一种更简单的常见方法是选择一个流程/工人作为驱动者。然后,所有其他进程会将其数组发送给驱动程序,驱动程序会应用该操作,并将结果重新分配给工作进程。看起来像这样的东西:

这种方法的问题是它不能很好地扩展。驱动程序进程成为瓶颈,因为它的通信和归约操作的应用与进程的数量成比例增加。这在我只有 4 个进程的玩具例子中可能不明显。

Allreduce 算法还有许多其他实现。一些尝试最小化带宽,一些尝试最小化延迟。在研究这个问题的时候,我意识到还有很多其他的架构可以让我在这篇文章中讨论,而不会让它变得无聊。如果你想知道更多,我找到了这篇伟大的论文,它描述了一些最常见的方法。

Figure 2, from the paper, copyright by John Francis Canny

现在我们已经知道了一些不同的实现方法,让我们来描述它的环形版本,并探索它的好处。

环所有-减少

Allreduce 的环形实现有两个阶段。第一阶段,份额减少阶段,然后是纯份额阶段。

在 share-reduce 阶段,每个进程 p 向进程 (p+1) % p 发送数据,其中%是模运算符。所以进程 A 会发送给进程 B,以此类推。这就是产生类似环的连接的原因。此外,长度为 n 的数据数组除以 p,这些块中的每一个都将由 i 向前索引。大概是这样的:

Each process sends chunks of its array to the next process

第一个份额减少步骤会让进程 A 将 a0 发送给进程 B,进程 B 将 b1 发送给进程 C,依此类推。大概是这样的:

然后,当每个进程接收到来自前一个进程的数据时,它会应用 reduce 操作符,然后继续将它再次发送到环中的下一个进程。请记住,在我们的示例中,归约运算符是一个 sum。它看起来像这样:

Each process sends an intermediate result of the reduce operation.

同样重要的是,我们的归约运算符是 关联的 ,以及交换的 否则您无法将中间结果从一个流程传递到另一个流程。当每个进程持有块的完全缩减时,共享缩减阶段结束。此时,每个进程持有最终结果的一部分,它看起来像这样:

The state of the processes after the share-reduce step is completed

第二步,仅共享步骤非常简单,只是以类似环形的方式共享数据的相同过程,而不应用 reduce 操作。这巩固了每个进程中每个块的结果。

像这样:

The state of all processes after the Allreduce is completed

对发送数据的简单分析

如果我们比较驱动程序进程 Allreduce 和环 Allreduce 发送的数据量,我们会发现为什么环 Allreduce 是现代网络架构中共享梯度的最佳选择。

在我们的驱动程序进程 Allreduce 中,在这篇文章的前面描述过;其他所有进程都将其数组发送给驱动程序。最初的发送是发送 N 个元素(P-1)次,然后驱动程序进程将应用归约操作符并将结果发送回其他进程,因此将是另一个 N × (P-1) 通过网络发送,总共是 2(N ×(P-1))。这是一个与 p 成正比的项。

在 ring Allreduce 的 share-reduce 步骤中,每个进程发送 (N/P) 个元素,它执行 (P-1) 次,所以 (N/P) ×(P-1)。在仅共享步骤中,每个进程发送它计算的块的结果。那就是一个附加的(N/P)元素做了(P-1)次,所以一个附加的 (N/P) ×(P-1)。总共加起来是2((N/P)×(P-1))**

从这里我们可以观察到,这将缓解瓶颈,因为这是几乎相同的术语,只是驱动程序进程的 N 和环形进程的 (N/P) 不同。让我们记住,这个计算只针对环形体系结构的一个过程。即使你将得到的等式乘以 P 你也会得到同样的另一个等式,但是它仍然分布在 P 进程中,而不是全部在驱动程序进程中。这就是如何缓解瓶颈,这就是为什么他们称这种算法为最佳带宽。

结论

我们调查了为什么在计算深度神经网络中的梯度时,我们需要分布数据。我们直观地探索了 ring Allreduce 算法是如何工作的,并执行了一个基本的分析,将它与其他 Allreduce 范式进行了比较,了解了什么使它成为更好的选择,以及为什么它被用在 Horovod 这样的框架中。据我所知,它现在甚至内置在 tensor flowcollectiveallreducedstrategy中。

参考文献:
https://eng.uber.com/horovod/

https://www . research gate . net/publication/259239833 _ Sparse _ all reduce _ Efficient _ Scalable _ Communication _ for _ Power-Law _ Data

https://preferred research . jp/2018/07/10/technologies-behind-distributed-deep-learning-all reduce/

https://www . toms hardware . com/news/Baidu-svail-ring-all reduce-library,33691.html

https://mpitutorial.com/tutorials/mpi-reduce-and-allreduce/

视觉网络:营销顾问

原文:https://towardsdatascience.com/visual-networks-the-marketing-consultant-d152b04a5e46?source=collection_archive---------42-----------------------

理解非线性关系和营销诡计

神经网络在分类图像创建原文方面取得成功的原因有很多。其中的几个原因是低廉的培训成本、可扩展的实现和该领域的投资。特别有趣的是他们捕捉非线性关系的能力。这种关系的一些例子是税级和收入、关税和贸易量、你的年中公司销售奖金、人口数量和时间等。像“过了这一点它会翻倍”或者“它会变得越来越糟糕”这样的短语隐藏了非线性关系。

Tax Brackets(y) and Income(x)

另一方面,线性关系是直接的。以工资和工作时间为例。你打卡的时间越多,月底你得到的存款就越多。很简单,每小时工资 10 美元,你工作 7 小时可以赚 70 美元。

营销投资并非一帆风顺。公司在广告上的花费和他们的回报当然是非线性的。让我们试着用神经网络来捕捉这种关系。

想象一下,你有数百家公司的营销投资和预算,你想要一种方法来预测你未来的回报。你知道,沃尔玛投资 7 美元获得 14 美元的回报,埃克森美孚投资 13 美元获得 26 美元的回报,数百美元也是如此。你能预测你的投资会有什么回报吗?

Return(Y) and Investment(X)

鉴于你要投资 15 美元,之前公司的经验对你有什么帮助?有没有办法用数据捕捉投资和回报之间的关系?

在这种情况下最常用的工具是线性回归。我们试图找到一条尽可能接近图中所有点的线。德斯莫斯建立了线性回归模型。这里有一个链接到这个例子。

Linear Regression in Desmos

我们将直线与点拟合,并找到一种方法来预测我们的回报。看起来我们会做得很好。红点在上面很高,只在联想下面。你很兴奋,决定投资 15 美元到脸书广告公司。几个星期后,你看到你的回报,得到 6 美元。如何解释如此灾难性的表现?你用了数学,你试图从以前的经验中学习,但还是失败了。

“营销投资并不是直截了当的。公司在广告上的花费和他们的回报当然是非线性的”

至少这不是世界末日,你只损失了 15 美元。但你还是想明白为什么会这样。幸运的是,你有一个每天都在做脸书广告的朋友。他是领域专家。你给他看数据,他马上就能看出你失败的原因。他说是“创造性疲劳”。显然,脸书用户对一个创意感到疲惫,并停止点击它。你还在花钱却没有得到好的业绩。

在你决定数学是一个骗局之前,我们需要再看看数据。用线性模型获取数据不是正确的方法。让我们回到德斯莫斯,现在我们知道了创造性枯竭。看来投资太多是要罚款的。也许福特在埃克森美孚之下的原因不是随机的。

我们不能使用线性模型。我们需要一种非线性的方法来拟合数据。这就是机器学习的全部内容。曲线拟合。有关曲线拟合工作原理的更多详细信息。连杆连杆连杆

我们需要一种工具来适应不断变化的市场决策。这就是神经网络可以发挥作用的地方。你可以点击以下 3 个交互式可视化来了解更多关于神经网络如何工作的信息。

直观解释

One Neuron

在其最简单的形式中,神经网络只能描述线性关系。一个神经元不会让你走那么远。

点击这里: 链接

Three Neurons

三个神经元能够紧密配合我们的非线性问题。有一些误差,但比线性模型小。您可以移动不同的值,看看可以描述什么类型的关系。

点击这里 : 链接

Six Neurons

我们可以用六个神经元来拟合任意的关系。

点击这里: 链接

最后,神经网络可以捕捉任意怪异的关系。您只需要数据,输出是一个定义明确的函数。很多问题随之而来。怎样才能开始做推理而不是预测?我们如何避免过度拟合?我们如何从神经网络中提取人类可解释的关系?当你在查看 3 个或数千个输入变量时,这变得越来越复杂。我们如何解释一段有数千个变量的关系?很多人都在研究这些问题,并取得了令人兴奋的成果。更多信息这里,这里这里,这里这里,这里这里

Recurrent Neural Chat Boats is where it’s at.

智能零售收银台的视觉产品搜索

原文:https://towardsdatascience.com/visual-product-search-for-smart-retail-checkout-eb7e1f34a351?source=collection_archive---------21-----------------------

用数据做酷事!

简介

人工智能正在改变几个经济领域,如汽车、营销和医疗保健。零售业可能是下一个。在商店购物的基本零售体验几十年来一直没有改变。人工智能可以从根本上改变这种体验,让它以高成本效益的方式为每个消费者提供大规模的完全个性化、沉浸式和优化的体验。

我们正在这里写一系列博客,详细介绍人工智能在零售业的应用。每个博客处理不同的用例,并分享演示可行性的实际代码。这是第一个。

视觉产品搜索

很多时候,我们发现很难回忆起一件产品的确切名称,或者无法清晰地描述它以便谷歌搜索,或者想要重新订购我们看到别人穿的衣服。在所有这些情况下,以及更多的情况下,“视觉产品搜索”是拯救。我们不需要描述,只需要给产品拍张照片,然后搜索它。

Visual Product Search

视觉产品搜索是如何工作的?

视觉产品搜索的概念也称为反向图像搜索,是将图像表示为特征向量。现代深度学习技术可以使用预训练的 CNN 将图像编码成特征向量。特征向量类似于图像描述符,并对深度学习已经学习到的相关图像信息进行编码。为了运行视觉产品搜索,我们有一个可以编码成特征向量的图像数据库。然后,我们获得一个查询图像,并将其向量与整个数据库进行比较,以获得最接近的匹配。

视觉产品搜索的应用

视觉产品搜索在人工智能中可以有很多应用。两个这样的应用是:

  • 对于在线订购,我们可以使用摄像头进行搜索,并自动将商品添加到商店购物车中。许多大型零售商如亚马逊、Nordstrom 已经提供这种服务。只需拍摄一张照片即可添加到购物车中
  • 对于实体店,我们可以有一个智能结账系统,它可以使用一个摄像头来自动为产品向客户收费。零售商会喜欢它,因为它会削减成本,顾客会享受顺利结账的体验。干脆买了就走。没有队列。

我们已经通过可视化产品搜索为智能结账做了一个演示。我们开始吧!

Who likes long checkout queues?

智能结账系统

我们使用 Google Vision API 来构建这个应用程序。他们有一个功能叫做视觉产品搜索。如果您是 API 的新手,请参考这个文档了解如何开始。

创建一个物品数据库

有两种方法可以创建将被搜索的数据库:

  1. 创建一个空的产品集,并使用在线导入向其中逐个添加图像
  2. 使用批量导入同时创建产品集,创建多个产品及其参考映像。

我们通过从互联网上抓取图片,创建了一个常见零售商品的数据库——冷饮、饼干、薯条、面条等。然后,我们使用批量导入将这些图像添加到 API 中。通过这样做,API 将每个图像转换成一个特征向量。

对于批量导入,主要步骤是:

  • 将你的数据库上传到谷歌云存储
  • 创建描述数据库中图像的 CSV 文件。CSV 文件的细节在下一节给出。将这个 CSV 文件上传到 Google 云存储桶中。
  • 使用存储在 Google 云存储桶中的图像或 base64 编码的本地图像向 Vision API 产品搜索发出请求。

CSV 包含各种列。列名及其说明如下:

  • image-uri :参考图片的 Google 云存储 uri。
  • image-id :您可以提供的唯一值。否则,系统将分配一个唯一的值。
  • product-set-id :导入图像的产品集的唯一标识符。
  • 产品类别:允许值为家居用品-v2、服装-v2、玩具-v2 和包装商品-v1。
  • 产品-显示-名称 : 可选 。如果不为产品提供名称,显示名称将被设置为" "。
  • 标签 : 可选 。描述参考图像中产品的键值对字符串(带引号)。比如:“品类=鞋子”,“颜色=黑色,款式=正式”。
  • 包围多边形 : 可选 。指定参考图像中的感兴趣区域。如果一个边界框没有被指定。如果 API 检测到多种产品,单个图像中的多个区域可能会被编入索引。

我们现在可以用我们的查询图像向 api 发出请求。这是使用 curl 完成的,如这里的所述

实验及结果:

我们通过网络搜集创建了一个普通零售产品的图片数据库。对于实际用例,这将是零售商存档的产品图像。为了测试 API,我们传递了一个通过手机摄像头捕捉的查询图像。以下为面条的查询图片:

Noodles Query Image

对 api 的请求给出了以下匹配的产品

API result on Noodles Image

然后我们传递了一张可口可乐的查询图片如下:

Coke Query Image

对 api 的请求为 coke image 提供了以下匹配产品。

API result for Coke Query image

还不错!API 能够非常准确地导航到正确的产品类型。这是很有希望的,因为过程相对简单,API 成本也相当合理。

这个简单的演示表明,通过对商店销售的整个数据库进行编码,上述技术可以扩展到更智能的客户结账。在结账时,安装的摄像头可以检测每个对象的位置,裁剪它们的图像,并对 API 进行批量查询,以获得数据库中最匹配的产品,从而进行结算。

结论

根据全球市场洞察,到 2024 年,零售部门对人工智能的投资将超过 80 亿美元。人工智能在零售领域有很多应用,智能结账将是一个革命性的变化。

我有自己的深度学习咨询公司,喜欢研究有趣的问题。我已经帮助许多初创公司部署了基于人工智能的创新解决方案。请到 http://deeplearninganalytics.org/来看看我们。如果你有一个我们可以合作的项目,那么请通过我的网站或在info@deeplearninganalytics.org联系我

你也可以在https://medium.com/@priya.dwivedi看到我的其他作品

参考文献:

带有红色节点的视觉识别应用程序

原文:https://towardsdatascience.com/visual-recognition-app-with-node-red-b362e8691d69?source=collection_archive---------19-----------------------

这篇博文演示了如何在 10 分钟内毫不费力地让定制的人工智能服务参与到自己的解决方案中,并学习了一种基于 Node-Red 的新的节点流代码开发。

为了实现这一点,您将了解 Watson 视觉识别(这是一项经验丰富的商业行业级人工智能服务,可通过 IBM Cloud 获得),Watson Studio for fast machine learning,Node-Red-一种基于 javascript 的图形节点流语言,可在在线模式下使用创建的视觉识别分类器。

为什么

我是一名全栈开发人员,一直在寻找可以在现代系统中使用的优秀技术。自从我创办了一家机器人初创公司以来,我一直对无人机和机器人的人工智能视觉识别服务的使用感到惊讶。在这篇博文中,我将与你分享现在让人工智能为你和你的系统/机器人/无人机做事情是多么容易。回到 10 年前,我试图在一群机器人中使用自主机器人来探测武装入侵者——当时在我看来,如果没有巨大的财政资源,这个任务是不可能完成的。今天,解决方案可以在一整天的黑客马拉松后交付。_Man,我希望我那时就知道我现在要与你分享什么;) _

此外,联合国、红十字会和 IBM 等组织支持 CallForCode.org 黑客马拉松来帮助受灾难影响的人们。使用具有图像识别功能的无人机可能会影响并改善所有受影响者的福祉。我将展示检测受野火、洪水等影响的房屋的代码。所以为什么不接这个电话,为事业做贡献,帮助别人!

在 Node-Red 中使用 Watson 视觉识别

沃森视觉识别是一种经过训练的基于人工智能的服务,它可以告诉你它在经过预训练的分类器的图片上看到了什么。它可以检测颜色、人、脸、一些物体、食物等。你会非常喜欢的。

Node-Red 是一个开源项目,是一个编程工具,用于以新颖有趣的方式将硬件设备、API 和在线服务连接在一起。它提供了一个基于浏览器的编辑器,使用调色板中的大量节点可以很容易地将流连接在一起,只需单击一下就可以将这些节点部署到它的运行时环境中(在 nodered.org 站点之后重复)

因此,让我们从 IBM 视觉识别开始——我上次检查是在 2019 年 5 月 30 日——你可以使用 IBM Cloud lite 帐户免费调用该服务,每月大约一千次。你可以通过点击我的个性化链接(如果你使用这个网址,我会被告知这个博客很不错)为自己获得一个免费的建兴账户(只需提供你的电子邮件地址):cloud.ibm.com——使用以下链接创建账户给我一些印象分——https://ibm.biz/Bd2CUa

补充说明一下——只需使用 IBM Cloud Lite 帐户,您就可以轻松地为投资者准备一个可行的概念验证原型。

注册后,登录并打开目录,从人工智能类别中选择 Watson 视觉识别服务,然后创建它。之后,您还需要创建 Node-RED Starter 服务。这两种服务都可以在免费层工作!

提供节点红色服务后,将其与之前创建的 Watosn 视觉识别服务连接。将它们连接在一起后,您需要重新准备节点红色服务。当您设置服务运行时,您可以创建第一个流并使用以下 Node-RED lab:https://github . com/Watson-developer-cloud/Node-RED-labs/tree/master/basic _ examples/visual _ recognition

小提示:在 Node-RED 实验页面的底部有一个链接,指向所需 Node-RED 流程的完整 JSON。只需复制流的 JSON,从剪贴板导入流编辑器中的 JSON,就可以在 1 分钟内启动这个服务!不要忘记使用“部署”按钮来安装新的或更改的流。

您的服务将如下所示:

现在,您可以通过这个简单的 web 应用程序在您的 web 浏览器中尝试您的测试服务(只需使用带有/reco扩展名的链接),例如:【http://my-node-red-app.mybluemix.com】T2/reco

使用自定义分类器自定义人工智能服务

如果你想添加一些新的东西——创建一个定制的分类器——你需要提供 1000 张图片进行阳性检测,正如我被告知的那样——这个数字中大约有一半是“阴性”图片——即不代表所选分类的图片。

最基本的例子是从十几张图片开始。John Walicki 提供了一个完美的例子,他训练了一个定制的分类器来检测无人机拍摄的照片中被烧毁的房屋。你可以使用他的一个实验室来做这样一个无人机分类器——这个基于 github 的实验室介绍了创建一个分类器来检测被野火摧毁或被洪水淹没的房屋的实验室:【https://github.com/IBM/drones-iot-visual-recognition

我制作了一个简短的视频,展示了这是如何一步一步完成的(然而视频被加速了 2-3 倍):https://youtu.be/kW7cjuWuPS0

为了训练 Watson 视觉识别,您将使用 IBM Watson Studio。概括来说,训练视觉识别服务需要提供单独的图片或将它们组合在 zip 文件中——一个是正面图片,一个是负面图片集。在自由层,你可以得到这样的两个等级。

现在,为了查看它,只需用一个额外的功能节点扩展您现有的节点-红色流,并用下面的代码填充它。更多细节在链接中的步骤 3-https://github.com/blumareks/ai-visrec-under-10min

摘要

使用创建的自定义分类器,您可以为您的无人机或软件配备检测灾难幸存者和受害者的能力。沃森视觉识别的能力可以用在好的方面,在 CallForCode.org 黑客马拉松和更远的地方。

你打算用它实现什么解决方案?让我知道!

在推特上关注我

使用图形的视觉识别

原文:https://towardsdatascience.com/visual-recognition-using-graphs-9c446005736e?source=collection_archive---------18-----------------------

Graph convolutions

介绍

卷积神经网络在视觉识别任务中取得了巨大成功。本文特别关注语义分割。使用 CNN 背后的逻辑是图像具有位置感,也就是说,彼此靠近的像素更相关。CNN 能够通过卷积运算捕捉到这一点,并且考虑的局部区域(正式称为感受野)取决于核的大小。图像中还存在长程相关性,这有助于视觉识别任务。为此,概念是堆叠许多卷积层,这将在理论上增加感受野。因此,现在长程和短程依赖性都被考虑在内,把网络放在训练上,你很容易得到结果,对不对!

但是我相信你很清楚,理论和实践并不总是一致的。最近发表了一篇论文(作者罗、等)表明感受野并不随卷积层数线性增长,而且受到严格限制。此外,感受野取决于各种其他因素,如初始化方案。那么解决办法是什么呢?

图表来拯救

如果我们能够将图像分组为区域,并使用这些区域来提取特征并进一步处理图像,情况会怎样?除此之外,地区之间也存在依赖关系,这将有助于获得长期依赖关系。所有这些都可以使用图像的图形表示来实现。

广义地说,图中的所有顶点代表图像中的不同区域。边缘将表示区域之间的关系或相似性。

圆圈代表具有代表该区域的相应特征向量的区域。边缘是区域之间的相似之处。

语义分割

语义分割是给每个像素分配其所属的类别的任务。一个基本的技术是,将有一个编码器,后面跟着一个解码器,其输出将是像素级的分配。

分段是如何工作的?让我们举一个非常基本的例子,假设有一个图像只由红色、蓝色、绿色组成,如

Fig1

假设这些颜色代表一些物体。现在假设谁想把图像分割成用颜色表示的三个物体。要做到这一点,你需要什么样的特征向量?对这个只有颜色就足够了。如果我们说根据特征向量,那么每个特征向量的深度是 3;对于红色[0,0,1],对于蓝色[1,0,0],对于绿色[0,1,0]。正如你所看到的,这些特征足以将图像分割成 3 个区域。现在考虑一个现实生活中的图像,如图 2 所示。只用颜色你能完成任务吗?不,没错。我们需要图像中存在的每个对象的特征表示,以将其与其他对象分开,并使相似的对象更加接近,这就是编码器发挥作用的地方。它将彩色图像表示转换成某种潜在空间表示,在这种潜在空间表示中,同一物体的特征更接近,而不同物体的特征彼此远离。显然,编码器需要训练。一旦我们在一些分离不同物体的潜在空间中有了特征,我们就需要将信息传播到像素级,这就是解码器发挥作用的地方。

让我们理解图在语义分割中是如何有用的。一旦使用编码器提取了特征向量,图形就开始发挥作用。考虑图 2 中的图像。图像从上到下依次分别是实际图像、地面真实、用 FCN 分割、用 GCU 分割。在此图中,使用 FCN 时,枕头和床类别的概率非常接近。因此,你可以在图 2 中看到枕头和床被合并。

现在假设编码器后面有一个图形表示。从编码器得到的图像的特征向量表示被迫分成多达 8 个区域(即 8 个顶点的图)]。如果我说就损失而言,如果顶点是空的,即没有像素被分配给它,则损失更高。在训练的初始阶段,枕头和床也将被分配到同一个班级。但是当我们进一步训练网络时,每个特征向量被分配给一个顶点,即没有顶点是空的。图像在图形表示中被分割的可能区域是在地面上的区域。因此在训练结束时枕头和床将被分割成两个不同的区域。通过乘以一些权重来进一步处理分配给顶点的特征,并且所得到的特征向量与来自编码器的特征向量一起被进一步用于分割。因此,图形表示进一步改进了图像的特征表示。

一个显而易见的可能发生的事情是当将图像划分为区域时,图像的过度分割。但是过度分割的区域将在进一步的操作如卷积后重新组合。

现在的问题是如何将基于网格的图像表示转换为这种图形表示,并学习图形表示的参数,答案是图形卷积单元(GCU)。

Fig2

图形卷积单位(GCU)

就像卷积在网格状结构上操作一样,GCU 在图形状结构上操作。GCU 有三个主要步骤

  1. 图形投影:在这个步骤中,图像的网格状表示被转换成图形表示。该图由以下参数参数化:
  • V :图中顶点的数量,暗示图像将被分割的区域的数量。
  • W :表示区域的特征向量。形状是(d,V),其中 d 是特征向量的维数
  • 方差:它是分配给特定顶点的所有像素在每个维度上的方差。形状是(d,V),其中 d 是特征向量的维数。

V 是固定的,而 W方差是在训练中学习的。假设存在具有高度 H 和宽度 W 的图像的 2-D 特征图,并且每个元素具有维度 D。计算属于每个顶点的每个特征向量的概率,这产生概率矩阵 q。下面的等式用于计算概率:

其中,xᵢⱼ是二维特征图的 iᵗʰ行和 jᵗʰ列的特征向量,wₖ是表示 kᵗʰ区域(顶点)的特征,σₖ是沿着顶点 k 的所有维度的方差。现在,通过取残差的加权平均值来计算所有顶点的特征编码。残差越多,它在计算编码特征中的贡献就越小。使用下面给出的等式:

其中 zₖ是编码特征。邻接矩阵由 ZᵀZ 计算,它给出不同顶点之间的余弦相似性。这一步总共计算了 3 样东西

  • 概率矩阵 Q,形状(HW,d)
  • 编码特征 Z,形状(d,V)
  • 邻接矩阵 A,shape ( V,V)-表示区域之间的相似性,因此它捕获了图像中的长程相关性。

Overall pipeline for GCU

2.图形卷积:该步骤类似于卷积的前一步,即在生成的图形上进行卷积。使用下面给出的公式:

其中 W g 是形状的权重矩阵(d,dₒᵤₜ).如您所见,等式中有一个邻接矩阵 A,在计算新的编码特征时会考虑长程相关性。因此新的编码特征依赖于所有的区域(A)和当前的编码特征(Z)。关于图形卷积的阅读,请参考这篇文章这篇。这些文章中给出了非常容易理解且足够的信息。

3.图形重投影:最后将图形转换回网格状结构,以便可视化或做进一步操作。等式如下所示

架构和实现

使用的架构是预训练的 ResNet 50/101,扩展被添加到最后两层,因此输出被降采样 8 倍。其次是 GCU。在最初的实现中,4 个 gcu 的输出连接到 ResNet 的输出,如下图所示。

在这种情况下,d 是 1024,dₒᵤₜ是 256。串联后输出的深度将是 1024(来自 ResNet50) + 256x4 = 2048。使用双线性插值对级联输出进行上采样。接下来,卷积层用于将像素分配到不同的类别。用于最小化误差的损失函数是负对数似然损失函数。

Fig3 Training loss curve

我实现的 Pytorch 在这里可用。我在下面给出了实现细节。使用的数据集是 ADE20K。

  • 使用 resnet 50 expanded,在 ADE20K 上进行预训练,此处可用。ResNet50 的输出深度是 2048。
  • gcu 跟随 ResNet50。在论文中,4 个 GCU 单元被连接在一起,但由于计算能力有限,我只使用了 1 个 16 顶点的 GCU。我写了一个通用代码,所以你可以很容易地修改 4 个 gcu 的代码。要了解更多关于 GCU 实现的细节,请参考我的下一篇帖子
  • 在这种情况下,d 是 2048,dₒᵤₜ是 256。串联后输出的深度将是 2048(来自 ResNet50) + 256= 2304
  • 接着是双线性上采样操作,然后是 1 个卷积层。
  • 图像在传送到网络之前会被调整到 512×512 的大小。
  • 由于计算量有限,我使用的批量大小为 1,训练了 120 个时期,每个时期有 1000 次迭代。
  • SGD 用的是 0.9 的动量。学习率从 0.01 开始,并随着训练的进行而衰减
  • 目前,该模型使用 2 个 GPU。一个 GPU 专用于 ResNet,另一个用于所有其他计算,如 GCU、上采样和卷积。

培训损失图如图 3 所示。用给定的超参数进行训练后,训练准确率约为 78%。

这篇文章基于李因和阿比纳夫·古普塔的论文。

如有任何疑问或建议,欢迎联系我😃。还有,在 Twitter Linkedin上找我。再见!!

视觉文本校正

原文:https://towardsdatascience.com/visual-text-correction-can-we-detect-and-fix-an-inaccuracy-in-a-video-caption-38540312dbc4?source=collection_archive---------37-----------------------

我们可以检测并修复视频字幕中的错误吗?

Given a video and an inaccurate description, the Visual Text Correction (VTC) task is to detect and fix the inaccurate word(s). [1]

数据集、论文和幻灯片:https://amirmazaheri1990.github.io/VTC/

代号:【https://github.com/amirmazaheri1990/Visual-Text-Correction

视频、图像和句子是可以表达相同语义的媒介。人们可以通过阅读一个句子来想象一幅图画,或者用一些词语来描述一个场景。然而,句子中即使很小的变化也会导致与相应视频/图像的显著语义不一致。例如,通过改变一个句子的动词,意思可能会彻底改变。已经有许多努力来编码视频/句子并将其解码为句子/视频。

在这篇文章中,我将介绍我最近的一篇论文。本文介绍了一个新的问题,称为视觉文本校正(VTC),即在视频的文本描述中找到并替换一个不准确的单词。句子和视频之间或者句子的单词之间的语义不一致会导致不准确的描述。我们提出了一个深度网络,它可以同时检测句子中的错误,并通过替换不正确的单词来修复它。我们的方法利用了视频和单词的语义相互依赖性,以及句子中单词的短期和长期关系。据我们所知,这项工作是视觉文本校正任务的第一次。

作为一名社交媒体爱好者,我不得不说,在很多场合,我看到过朋友们发来的视频,标题写得不太好。在许多情况下,字幕有语法错误,或者与上传的视频并不相关。主要问题是,机器能学会阅读视频字幕并修复不太准确的字幕吗?

尽管社交媒体是第一个想到视觉文本纠正(VTC)的例子,但它有许多应用程序。例如,想象一个人工智能(AI)系统,它可以根据警官可穿戴相机或犯罪现场可用的安全相机记录的视频来验证警方的报告。多酷啊。

方法:

The proposed framework for Visual Text Correction. The goal is to find and replace the inaccurate word in the descriptive sentence of a given video. There are two main modules: 1) The Inaccuracy Detection module finds the inaccurate word, and 2) the Correct Word Prediction module predicts an accurate word as a substitution. Both of these modules use the encoded text and visual features. The Inaccuracy Detection uses Visual Gating Bias to detect inaccuracy and the Word Prediction Modules uses an efficient method to encode a sentence and visual features to predict the correct word. [1]

视觉编码:

我们使用预训练的 VGG19 和 C3D 网络来编码视频。然而,我们使用时间最大池从整个视频中获得一个特征向量。在消融研究中,我们表明每个特征都对最终结果有贡献。

文本编码:

一个句子中有两种类型的依存关系,叫做长期依存关系和短期依存关系。句子中每个单词的意义和作用会受到相邻单词的影响,也会受到句子中所有单词的影响。在我们的方法中,我们分别使用 1D CNN 和比尔斯特姆对短期和长期依赖性进行建模。

我们可以仅通过使用文本来找到不准确性分数:

Detection by reconstruction for inaccurate word detection in a sentence. [1]

事实上,我们试图重构每个单词,并通过句子中的实际单词来找到它的距离。

视觉门控偏差:

不是所有的单词都有视觉外观。例如,像颜色、物体和动作动词这样的词具有清晰的视觉外观。另一方面,许多单词在视觉单词中没有任何模式。比如“满意”这个词,并不是一个视觉概念。

为了解决这一现象,我们引入了一种新的融合方法,其中,我们与每个词的视觉特征门。事实上,没有任何视觉外观的单词可以关闭视觉特征上的所有闸门,使其成为全零向量。

Gating the visual features based on each of words in the sentence. [1]

最后,我们将门控视觉偏差与重建项相加:

The visual bias term is added to the detection by reconstruction formulation. [1]

事实上,视觉特征对不同的单词重构有不同的影响。

在找到句子中最不准确的单词后,任务是建议字典中最好的单词来替换句子中不准确的单词。为此,我们使用重构的单词向量来预测正确的单词,以替换不准确的单词。

关于更详细的公式,请看看的原始论文,或者看看我在这篇文章底部的 YouTube 演示文稿。

实验:

据我们所知,没有关于“视觉文本校正”任务的可用数据集。因此,我们建议生成一个。我们为 VTC 任务构建数据集的方法背后的主要思想是从每个句子中删除一个单词,并用一个不准确的单词替换它;然而,为了构建真实的数据集,有几个挑战需要解决。在这里,我们列举了一些,并提出了我们应对这些挑战的方法。我们的目标是建立一个包含各种视频和文本描述的大型数据集。我们要求数据集的词汇和视频样本的数量足够大,以训练一个深度网络;因此,我们选择“大规模电影描述挑战(LSMDC)”数据集[ 链接 ]2,这是可用的最大视频描述数据集之一。此外,LSMDC 还被注释为“视频填空(FIB)”任务2。在 FIB 数据集中,每个视频描述包含一个或多个需要填充的空白。对于 VTC 问题,我们引入不准确的词来代替 FIB 数据集中的空白。如果在 FIB 数据集的一个句子中有一个以上的空格,我们生成该句子的多个例子。

请注意,有一些与替换单词的选择相关的要点,我们需要记住。首先,原始单词和替换单词之间不应该有很高的相关性。比如我们经常把“car”这个词换成“bicycle”,任何方法都会有偏差,总会建议在所有的句子里把“bicycle”换成“car”。第二,我们希望我们的句子即使在单词替换后看起来也很自然。因此,替换单词应该具有相同的“词性”(POS)标签。比如一个单数动词最好换成另一个单数动词。为每个样本手动标注和选择替换词的成本很高,因为视频数量很大,并且数据集的词汇量很大。此外,人类注释者很难防止原始单词和替换单词之间的相关性。我们已经考虑了所有提到的要点来构建我们的数据集。有关如何生成数据集的更多信息,请阅读我们的全文

结果:

为了成功地解决 VTC 任务,应该正确地检测不准确的单词,并且找到最准确的单词进行替换。这两个步骤中任何一步的失败都意味着整个 VTC 任务的失败。下面我们展示我们的结果表:

K: Number of inaccurate words in the sentence, WB: Word Based measurement in which each corrected word has a value, SB: Sentence Based measurement in which the whole corrected sentence has a value. We also show both MAP and Accuracy measurements.

提出的职训局问题是其研究路线的第一项工作。我们希望将这项工作扩展到更真实的数据集,并将其应用于社交媒体中人为的不准确性。

我想邀请观众观看我的 18 分钟 YouTube 演示,并阅读我们的全文。我感谢任何意见,以改善这项研究在未来。

参考资料:

[1]马扎赫里,阿米尔,和穆巴拉克沙阿。"视觉文本校正。"欧洲计算机视觉会议论文集(ECCV) 。2018.

2马哈拉杰、甘特等人,“通过填空问答理解视频数据的数据集和模型探索。”IEEE 计算机视觉和模式识别会议论文集。2017.

3马扎赫里、埃米尔、董璋和穆巴拉克·沙阿。"视频使用 lr/rl lstm 填补空白,具有时空注意力."IEEE 计算机视觉国际会议论文集。2017.

Visual_UI

原文:https://towardsdatascience.com/visual-ui-54ab27216c8e?source=collection_archive---------11-----------------------

我的任务是为机器学习库创建一个图形用户界面(GUI)(在这里是【fastai】),目的是提供各种训练参数的无缝集成,提高用户可用性,并且不需要任何代码!

学习机器学习中的各种概念和训练机器学习模型时可用的过多选项已经足够具有挑战性了。

例如,您必须选择您的标准化参数(imagenet、cifar、mnist 或自定义设置)、您的架构(resnet18、resnet34、resnet50、xresnet、alexnet、vgg16、vgg19、densenet121、densenet161、densenet169、squeeznet1_0、squeeznet 1 _ 1…仅举几个例子)、您是否想要预训练的权重、选择您的批量大小、图像大小、众多增强参数(缩放、旋转、扭曲、光照、翻转…)、训练),你的学习速度,周期长度,如何查看你的结果… 列表很广泛

这导致必须按顺序运行大量单元来执行您的代码。

很明显,选择的数量是巨大的,在某些情况下,你甚至不知道所有的选项是什么。

下面是一个 Jupyter 笔记本或 Google Colab 笔记本目前可能的样子:

code from fast.ai

该项目的目标是将多个代码单元转换为一个代码单元,允许用户在一个视线内改变各种参数:

GUI displaying ‘Data’ and ‘Augmentation’ tabs

概念

我喜欢演奏音乐,并拥有许多合成器。我对雅马哈的DX7特别着迷,这是第一个成功的数字合成器。

Yamaha DX7 (1983–1989)

我喜欢键盘上显示按钮和算法的方式,这简化了合成器的功能。各种算法的图形表示打印在各种按钮上方,向用户显示每种算法的功能。

这就是我最终想要为机器学习库重新创建的图形用户界面..然而..但这是一项正在进行的工作。

如前所述fastai在我看来是目前为止最好的机器学习库,这个项目( Vision_UI )是基于使用 fastai 库创建一个图形用户界面。你可以通过从我的 GitHub 页面克隆我的项目来使用 Visual _ UI或者直接在Google Colab上实验。******

Visual_UI 是使用 ipywidgets 制作的,它们是用于 Jupyter 笔记本和 IPython 内核的交互式 HTML 小部件。这允许用户获得对其数据的控制,并且可以可视化数据中的变化。对于文件选择,我决定使用 Tkinter ,它是一个内置的 Python 模块,可以跨不同的平台兼容(虽然不是在 Google Colab 或 AWS 上,因为 Tkinter 为文件选择创建了一个新窗口,而 Colab 和 AWS 是在云上运行的,它们不能在你的机器上打开一个窗口。在这种情况下,使用了 Colab 章节中提到的另一种方法。这允许 GUI 使用面向对象编程的形式,即 事件驱动 ,程序响应事件,这些事件是用户采取的动作。****

设计

Fastai 提供了一种组织管道的结构化方式。加载数据、选择您的增强参数、学习率、选择您的训练指标、训练并查看结果)

Model Pipeline

这是 Visual_UI 中选项卡的基础(后来添加了其他选项卡)。该设计是使用 ipywidgets 的 Accordion 小部件实现的。

>信息 标签:方便查看相关系统信息,如 fastai 版本、GPU 信息(或 TPU,如果使用 Colab)、python 版本、访问 fastai 文档以及选择数据所在文件夹的路径。

‘Info’ tab

选择数据所在的文件夹需要使用 Tkinter,这会打开一个新窗口,您可以从中选择文件夹。(对于 Colab,我使用了另一种方法,因为 Tkinter 不支持 Colab)

Tkinter is a great tool that allows the ability to choose folders and files within a notebook

>数据 选项卡:方便地允许选择各种数据参数,例如指定如何存储您的数据(目前 Visual_UI 仅适用于存储在文件夹中的数据,我正在处理包括来自数据框和来自 csv 的数据)、归一化值、架构、预训练值、批量大小和图像大小。

‘Data’ tab uses a mixture of widgets to construct a GUI

“数据”选项卡使用了许多小部件(完整列表可在此处找到),与雅马哈 DX7 的概念非常相似。Toggle 小部件(提供一种方便的方式来查看所有可用的选项,以及使用不同的颜色来区分小部件的其他部分),CheckBox 小部件和 FloatSlider 小部件被用来构建界面。**

>增强 选项卡:该选项卡显示各种增强参数,并混合使用 Toggle 和 FloatSlider 小部件来创建效果。您可以将增强图像作为一批 8 张图像进行查看。

真正方便的是能够查看不同的增强参数如何影响图片(例如,在下图中,缩放和扭曲参数被更改,我们可以看到这如何影响图像)

Example of 2 different augmentations used (bottom picture: zoom and warp parameters were changed)

>批量 选项卡:该选项卡方便地显示从前两个选项卡中选择的所有参数,数据和增强,并显示一批将用于训练的图像。这是查看所使用的增量是否适合训练数据的好方法。

>模型 标签:这可以方便地显示模型的概要表示

‘Model’ tab

>指标 选项卡:允许轻松选择将在培训中使用的指标。在这种情况下,再次使用了垂直对齐的 Toggle 小部件。在未来的更新中,将添加更多指标。

‘Metrics’ tab

> 训练 选项卡:该选项卡再次允许查看训练参数的选项,以及使用学习率查找器的选项,以便找到训练的最佳学习率。一旦确定了这一点,就可以设置学习率和周期长度。目前,Visual_UI 使用 Leslie Smith 提出的单周期策略,并在本文****中进行了讨论。特别是,在训练复杂模型时,这种策略可以快速给出结果。这个政策在这个 帖子 里解释的极其到位。****

一旦训练完成,模型将自动保存在 models 文件夹中,命名顺序如下:' architecture '+' pre trained '+batch size+image size,因此使用批大小为 32、图像大小为 128 的预训练 resnet34 architectur 将保存为 resnet 34 _ pre trained _ True _ batch _ 32 _ image _ 128 . PTH

‘Train’ tab

>结果 选项卡:这是迄今为止所有选项卡中最有趣的一个!还有选择最多的一个。结果选项卡是一个独立的实体,因为它不需要来自任何其他选项卡的输入。在这种情况下,必须指定文件夹路径以及加载保存的模型文件。再次使用 Tkinker 允许无缝集成选择相关文件夹和。pth 文件。**

在这种情况下,可以轻松加载之前保存的文件 resnet 34 _ pre trained _ True _ batch _ 32 _ image _ 128 . PTH。一旦模型被加载,附加选项变得可用(混淆矩阵、多 _ 顶 _ 损失、顶 _ 损失)。关于这些选项的更多信息可以在 fastai 优秀的 文档 中找到

我在'混淆矩阵'选项卡中做了最大的改动(需要注意的是,目前,这仅在不超过 2 个类的情况下有效)。我经常发现自己想知道更多关于混淆矩阵的结果。**

典型的混淆矩阵是这样的:

Typical Confusion Matrix

除了这些数字,很难看出是什么驱使这个模型得出这些结果。我想知道更多关于真阳性、真阴性、假阳性和假阴性的图像。我还想选择使用热图(一种很好的可视化模型所关注的内容的方式)以及查看分配到 4 个象限的图像的能力。考虑到这一点,我对混淆矩阵选项进行了改进。

首先是查看结果是否带有热图的选项

View Heatmaps?

其次是选择色图、插值和阿尔法参数的选项,以便更好地匹配正在查看的数据

Various Heatmap options

下图显示了使用不同色彩映射表选项的示例:

并且通过添加 4 个可点击的按钮来更新混淆矩阵本身,这 4 个按钮全部对应于每个象限中的值

Updated confusion matrix

每个可点击的按钮将相应的图像保存到单独的文件夹中(假阴性、真阳性、假阳性、真阴性),从而允许用户更详细地查看图像。下图是打开热图选项时每个文件夹中图像的外观示例。

Images above using the Chest Xray dataset

在 Google Colab 上使用 Visual_UI

让 Visual_UI 在 Google Colab 上工作存在一些挑战。点击 这里 可以进入 Colab 笔记本:

第一个挑战是 Colab 中 Accordion 小部件的不兼容性。不幸的是,这将所有选项卡显示在一起,您无法单独单击任何选项卡。

ipywidgets Accordion does not render correctly in Google Colab

这里的修正是改为使用 Colab 小部件,这里有一个很棒的教程了解更多信息。第二个挑战是决定如何选择文件夹路径或增强图像,因为Tkinter 与 Colab 不兼容,您必须安装 Google drive 才能访问文件。

驱动器 ”选项卡自动装载驱动器。

选择文件夹或图像路径的选项是通过使用文本小部件来完成的,它允许您轻松地复制和粘贴文件或文件夹路径,并使用按钮小部件来执行选择。这个选项延续了不使用任何代码的主题。

It is easy to copy and paste the path

总结一下我想要实现的概念:

目前,Visual_UI 是这样的:

有一些相似之处,但显然需要做更多的工作,因为我希望包括额外的功能,并希望在未来形成各种架构和参数的可视化表示。您可以通过在我的 github 页面上克隆这个项目或者在 Google Colab 上测试 Visual_UI 来查看代码并进行测试。**

嵌入关系的可视化

原文:https://towardsdatascience.com/visualisation-of-embedding-relations-word2vec-bert-64d695b7f36?source=collection_archive---------17-----------------------

在这个故事中,我们将可视化单词嵌入向量,以理解由嵌入描述的单词之间的关系。这个故事重点讲 word2vec [1]和 BERT 2。为了理解嵌入,我建议阅读不同的介绍(比如这个),因为这个故事并不打算描述它们。

这个故事是我使用 BERT 情境化嵌入向量开发神经机器翻译(NMT)之旅的一部分。欢迎建议!

单词嵌入

单词嵌入是为单词生成计算机友好的数字向量表示的模型。Word2vec 为每个单词产生 300 个介于 0 和 1 之间的浮点数。对计算机来说可能更容易理解,但对人来说则相反。

下图显示了 5x60 矩阵中 300 数值的灰度像素。看着图像,我们能观察到的东西并不多。

我们可以认为,第 42 列的较轻值在所有与人类相关的单词中是相似的,而在单词 apple 中是完全不同的。

另外,queen-woman+man = king是计算机可以理解的东西。字典中与queen-woman+man最接近的单词是king,这被认为是单词嵌入的重要特征之一。但是很难看到

Word2vec representation of certain words

嵌入投影

嵌入投影背后的基本思想是将表示向量的维度减少到 2D 或 3D,因此它可以被可视化。这背后的数学称为线性投影:如果我们有一个 n 维向量 x ,我们想要一个 m 维投影(m < n) y ,我们需要找到一个 m*n 矩阵 A ,秩为 m,并计算 y =A x

Illustration of projection in Wikipedia (cc)

让我们关注 2D!如果我们想要一个投影,其中某个单词到(1,0)点,而另一个单词到(0,1)点,我们想要解 I=AX 线性方程,其中 I 是 2 大小相同的矩阵, A 是投影的矩阵, X 矩阵包含我们想要的作为列的基础中的向量。

如果 A 矩阵是一个方阵,这就是 X 的逆矩阵,这个问题可以用高斯消去法很容易地解决。这里,我们希望将更大的向量投影到 2D 子空间中,因此,它不是一个正方形矩阵(对于 word2vec 为 2x300,使用 BERT base 为 2x768)。这里我们要的叫做左逆矩阵。然而,我们将使用伪逆或 Moore-Penrose 逆 ,因为它在 Numpy 中有一个实现,并且生成一个接近于单位([numpy.linalg.pinv](https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.pinv.html))的矩阵。

好吧。我们来编码吧!我们有一个单词列表:[‘man’, ‘woman’, ‘rich’, ‘poor’, ‘queen’, ‘king’, ‘fisherman’, ‘teacher’, ‘actress’, ‘actor’]我们想要一个 2D 子空间,其中男女线是一个轴,贫富线是另一个轴。为此,我们将把man-woman投影到(1,0)并将rich-poor投影到(0,1),在投影之后,我们将移动这些点以适合轴。

Code to project words for 2D visualisation

下图显示了投影的结果。观察这张图片我们可以看到一个渔夫,一个国王和一个演员更像一个男人,而不是一个女王女演员。同样,我们可以说一个国王和一个王后接近而一个老师接近

Projection of the words in a subspace with poor-rich and man-woman axes

要看更高级的 word 投影,我可以推荐 TensorFlow 嵌入式投影仪

句子投射

BERT 提供了依赖于上下文的嵌入。在这里,我们想要研究,我们能从中观想什么。我之前没有看到类似的东西,所以可能是第一次有人这么做。否则,我很高兴在评论中看到其他解决方案!

这种可视化背后的思想是,BERT 中的每个句子都以一个[CLS]标记开始,以一个[SEP]标记结束,因此,将句子投影为(1,0)是[CLS]标记,而(0,1)是[SEP]标记,我们可以在 2D 子空间中说明句子,并且嵌入以所有句子都从(1,0)开始并以(0,1)结束的方式进行归一化。

[CLS] This is a sentence example. [SEP]

这背后的数学原理和以前一样。我们使用预先训练好的 BERT base bert_12_768_12_book_corpus_wiki_en_uncased

Code for the sentence-dependent embedding projection

为了演示令牌的顺序,让我们用箭头将点连接起来!我们可以观察到第一个标记''更靠近起始标记和最后一个标记'’离安德令牌更近,但其他的都在相对较小的区域。

Sentence visualisation using contextualised embeddings

让我们把句子中的单词' sky 改成' sea '!点天空和海洋被标记。我想指出的是,主要区域中的点的顺序被改变了(尝试在故事的结尾链接的代码以获得更好的分辨率)。虽然海句子没有十字箭头,但天空句子的顺序看起来完全是随机的。

Difference between the sky and the sea in the sentence “The … is blue today.”

让我们来调查时态的变化!从这张图片(与其他句子相比)来看,我认为这个模型在句子的时态方面没有太大的差异。

Difference between tenses. is / was / will be

与时态相比,句末的标点符号对嵌入的影响更大。

Difference between punctuation characters.

正如我们之前提到的,BERT 嵌入是依赖于上下文的。为了说明这一点,下面的例子展示了包含单词 Mexico 的复杂句子。墨西哥点被标记。

Sentences with Mexico in it

在前面的例子中,我们可以看到句子“那也在墨西哥”与我们到目前为止看到的其他句子有些不同。它主要在 2D 空间的负域区域上。换句话说,离[CLS]令牌还远着呢。

为了猜测为什么会发生这种情况,我们必须研究一下 BERT 的训练数据。使用两个无监督的任务来训练 BERT,其中一个是掩蔽语言建模(Masked LM),另一个是下一句预测(NSP)。在第二个任务中,句子对用一个分隔符训练,像这样:
[CLS] This is the first sentence. [SEP] This is the second one. [SEP]

正如我们在这里看到的,第二个句子以一个[SEP]标记开始,而不是以[CLS]标记开始。我认为这是观察到的不规则现象背后的原因。换句话说,句子,即对话中的反应,可能离[CLS]标记更远。让我们看看能否用更多的例子来支持这个论点!

Possible reaction sentences to see x<0 points

我们也可以在 y<0 区域捕捉到一些点,但是不太明显。我认为对这些特殊句子的观察显示了进一步工作的潜力。

最后,让我们检查一些不正确的句子!我们可以看到,这些非句子也试图适应点的规则区域。

Incorrect sentences compared to two correct ones

摘要

在这个故事中,我们讨论了一种可视化单词嵌入的方法,并以一种新颖的方式讨论了将其用于句子可视化的想法。

所有代码都可以在 Google Colab 上找到。

参考

[1] Mikolov,t .,Chen,k .,Corrado,g .,& Dean,J. (2013 年)。向量空间中单词表示的有效估计。 arXiv 预印本 arXiv:1301.3781

2 Devlin,j .,Chang,M. W .,Lee,k .,& Toutanova,K. (2018 年)。 Bert:用于语言理解的深度双向转换器的预训练。 arXiv 预印本 arXiv:1810.04805

用伯特的故事学习 NMT

  1. BLEU-BERT-y:比较句子得分
  2. 嵌入关系的可视化(word2vec,BERT)
  3. 机器翻译:简要概述
  4. 使用 BERT 识别单词的正确含义
  5. 机器翻译:对比 SOTA
  6. 使用 TensorFlow 2.0 的简单 BERT

来自原始 Twitter 数据的信息可视化——第二部分

原文:https://towardsdatascience.com/visualisation-of-information-from-raw-twitter-data-part-2-11707a65e920?source=collection_archive---------22-----------------------

想要了解用户活动,查看某些用户是否是机器人,制作 Tweet 出版物的时间序列等等吗?接着读下去!

前一篇文章介绍了如何从 Twitter 下载关于某个主题的数据,在 Jupyter 笔记本中准备好这些数据,从这些数据中发现的见解,并探索了一些非常酷的可视化技术。如果您尚未阅读,您可以在此处找到它:

[## 来自原始 Twitter 数据的信息可视化—第 1 部分

让我们探索一下我们可以从原始 Twitter 数据中轻松检索到什么样的信息!

towardsdatascience.com](/visualization-of-information-from-raw-twitter-data-part-1-99181ad19c)

这第二篇文章将描述其他令人敬畏的可视化,同时也探索一些可以从下载的 tweets 中获得的更多信息。

我们将从发现发布推文的用户的信息开始:

#Lets take a look at the users who are posting these tweets:print("There are {} different users".format(tweets['Username'].nunique()))

在我的例子中,条推文是由 59508 个不同的用户发布的。

使用我们精心准备的数据框架我们可以看到谁是发布最多推文的用户,更酷的是:看到高度活跃的用户成为机器人的几率!

#Going to see who are the users who have tweeted or retweeted the #most and see how
#Likely it is that they are botsusertweets = tweets.groupby('Username')#Taking the top 25 tweeting userstop_users = usertweets.count()['text'].sort_values(ascending = False)[:25]
top_users_dict = top_users.to_dict()
user_ordered_dict =sorted(top_users_dict.items(), key=lambda x:x[1])
user_ordered_dict = user_ordered_dict[::-1]#Now, like in the previous hashtags and mention cases, going to make #two lists, one with the username and one with the valuedict_values = []
dict_keys = []
for item in user_ordered_dict[0:25]:
    dict_keys.append(item[0])
    dict_values.append(item[1])

这段代码非常类似于我们在上一篇文章中使用的代码,以查看最常用的标签或提到的用户。现在,像前面的例子一样,我们将绘制结果。

#Plot these resultsfig = plt.figure(figsize = (15,15))
index = np.arange(25)
plt.bar(index, dict_values, edgecolor = 'black', linewidth=1)
plt.xlabel('Most active Users', fontsize = 18)
plt.ylabel('Nº of Tweets', fontsize=20)
plt.xticks(index,dict_keys, fontsize=15, rotation=90)
plt.title('Number of tweets for the most active users', fontsize = 20)
plt.savefig('Tweets_of_active_users.jpg')
plt.show()

Bar chart of the number of tweets produced by the top 25 tweeting users.

我们可以看到,最活跃的用户@CrytoKaku ,发布的推文超过 400 条。太多了!他/她是机器人吗?让我们来看看吧!

为此,我们需要下载并导入僵尸工具 Python 库,并获得一个能够使用他们的 API 的密钥。有关如何做到这一点的信息可以在以下链接中找到:

[## Botometer API 文档(OSoMe) | RapidAPI

Botometer(以前的 Truthy BotOrNot)检查 Twitter 账户的活动,并根据可能性给它打分

rapidapi.com](https://rapidapi.com/OSoMe/api/botometer?utm_source=mashape&utm_medium=301)

此外,我们将需要检索我们的 Twitter API 密钥,因为我们将需要它们来允许 Botometer 访问我们想要研究其活动的帐户的信息。

首先,我们将导入两个库。考虑到 Botometer 和 Tweepy 都必须使用您选择的软件包管理器预先下载

#Now we will see the probabilities of each of the users being a bot #using the BOTOMETER API:import botometer
import tweepy

之后,我们将输入所需的 API 键:

#Key from BOTOMETER API
mashape_key = "ENTER BOTOMETER API KEY"#Dictionary with the credentials for the Twitter APIs
twitter_app_auth = {
    'access_token' : "ENTER ACCESS TOKEN",
    'access_token_secret' : "ENTER ACCESS TOKEN SECRET",
    'consumer_key' : "ENTER CONSUMER KEY",
    'consumer_secret' : "ENTER CONSUMER SECRET",    
}

像以前的文章一样,把“ 回车… ”换成相应的键,就可以了。

运行下面的代码块来访问僵尸工具 API,,让我们看看前 25 名推特用户中哪些账户最有可能成为僵尸工具!

#Connecting to the botometer API
bom = botometer.Botometer(wait_on_ratelimit = True, mashape_key = mashape_key, **twitter_app_auth)#Returns a dictionary with the most active users and the porcentage #of likeliness of them bein a Bot using botometerbot_dict = {}
top_users_list = dict_keys
for user in top_users_list:
    user = '@'+ user
    try:
        result = bom.check_account(user)
        bot_dict[user] = int((result['scores']['english'])*100)
    except tweepy.TweepError:
        bot_dict[user] = 'None'
        continue

这个模块的输出是一个字典 (bot_dict) ,其中的关键字是我们正在检查的帐户名称,值是一个介于 0 和 1 之间的数值分数,它描述了每个用户成为机器人的概率,其中考虑了某些因素,如关注者/被关注者的比例、帐户描述、发布频率、发布类型以及更多参数。

对于一些用户,Botometer API 得到一个 拒绝请求错误,所以这些将有一个“”作为它们的值。

对我来说,我在检查 bot_dict 时得到如下结果:

{'@CryptoKaku': 25,
 '@ChrisWill1337': 'None',
 '@Doozy_45': 44,
 '@TornadoNewsLink': 59,
 '@johnnystarling': 15,
 '@brexit_politics': 42,
 '@lauramarsh70': 32,
 '@MikeMol1982': 22,
 '@EUVoteLeave23rd': 66,
 '@TheStephenRalph': 11,
 '@DavidLance3': 40,
 '@curiocat13': 6,
 '@IsThisAB0t': 68,
 '@Whocare31045220': 'None',
 '@EUwatchers': 34,
 '@c_plumpton': 15,
 '@DuPouvoirDachat': 40,
 '@botcotu': 5,
 '@Simon_FBFE': 42,
 '@CAGeurope': 82,
 '@botanic_my': 50,
 '@SandraDunn1955': 36,
 '@HackettTom': 44,
 '@shirleymcbrinn': 13,
 '@JKLDNMAD': 20}

这其中,成为 Bot 几率最高的账号是 @CAGeurope,概率为 82%。让我们来看看这个账户,看看为什么 Botometer 赋予它如此高的概率成为一个机器人。

Twitter account of @CAGeurope

这看起来像一个合法的帐户,然而,有各种各样的原因解释为什么 Botometer 给了它这么高的概率是一个机器人。首先,这个账户关注的账户数量几乎是关注它的账户数量的三倍。其次,如果我们看看他们的推文出版物的周期性,我们可以看到他们始终如一地每小时发布各种推文,有时间隔 5 分钟,这是一个很大的推文。最后,他们的推文内容总是非常相似,都是简短的文本、一个 URL 和一些标签。

如果您不想编写任何代码或获取 API 密钥,Botometer 还提供了一个基于 web 的解决方案,在这里您还可以检查帐户成为机器人的可能性:

Web based solution offered by Botometer

看来我不得不停止发送垃圾消息和大量关注他人,以使我的 Twitter 账户更像人类:P

酷!通过 tweet 的 JSON 中的‘user’对象,我们可以看到更多关于用户的信息,然而,这将留到另一篇文章中。

现在,让我们制作一个推文出版物的时间序列,这样我们就可以看到哪一天关于所选主题的推文比较多,并尝试找出哪些事件导致了这些较高的推文产量

我们将绘制特定月份每天发布的条推文的数量。要显示与此类似的图,但时间更长,必须添加一些额外的代码。

首先,我们需要修改 dataframe 的“时间戳字段,使用 Pandas incorporated 函数 to_datetime 将其转换为 Datetime 对象

tweets['Timestamp'] = pd.to_datetime(tweets['Timestamp'], infer_datetime_format = "%d/%m/%Y", utc  = False)

然后,我们创建一个返回 DateTime 对象的日期的函数,并将其应用到我们的' Timestamp' '字段,为我们的 dataframe 创建一个新列,存储发布 tweet 的日期。此外,我们将把这些天组合在一起,统计每天产生的 tweets (使用' text' 字段)的数量,并用结果创建一个字典 ( timedict) ,其中键是对应于一个月中某一天的数字,值是当天发布的 tweets 的数量。

def giveday(timestamp):
    day_string = timestamp.day
    return day_stringtweets['day'] = tweets['Timestamp'].apply(giveday)
days = tweets.groupby('day')
daycount = days['text'].count()
timedict = daycount.to_dict()

做完这些,我们就可以准备好绘制我们的结果了!

fig = plt.figure(figsize = (15,15))
plt.plot(list(timedict.keys()), list(timedict.values()))
plt.xlabel('Day of the month', fontsize = 12)
plt.ylabel('Nº of Tweets', fontsize=12)
plt.xticks(list(timedict.keys()), fontsize=15, rotation=90)
plt.title('Number of tweets on each day of the month', fontsize = 20)
plt.show()

Time Series of 2 days tweet collection for the #Brexit (Left) and for a whole month on the #Oscars (right)

如果像我一样,你只收集了几天的推文,你会得到一个很短的时间序列,就像左边的图片。然而,右边的一个显示了从关于奥斯卡的推文的数据集制作的整月时间序列,这是通过查询一个多月推文的流媒体 API 构建的。在这第二个时间序列中,我们可以看到在月初很少有推文被生成,随着仪式日期的临近推文的生成开始上升,在活动当晚达到顶峰。

厉害!现在,我们将绘制一个关于从产生推文设备的图。

由于该代码与前面的条形图所使用的代码非常相似,所以我将在这里发布它,不做进一步的解释:

*#Now lets explore the different devices where the tweets are #produced from and plot these resultsdevices = tweets.groupby('device')
devicecount = devices['text'].count()#Same procedure as the for the mentions, hashtags, etc..
device_dict = devicecount.to_dict()
device_ordered_list =sorted(device_dict.items(), key=lambda x:x[1])
device_ordered_list = device_ordered_list[::-1]device_dict_values = []
device_dict_keys = []
for item in device_ordered_list:
    device_dict_keys.append(item[0])
    device_dict_values.append(item[1])*

现在我们绘图,看看结果:

*fig = plt.figure(figsize = (12,12))
index = np.arange(len(device_dict_keys))
plt.bar(index, device_dict_values, edgecolor = 'black', linewidth=1)
plt.xlabel('Devices', fontsize = 15)
plt.ylabel('Nº tweets from device', fontsize=15)
plt.xticks(index, list(device_dict_keys), fontsize=12, rotation=90)
plt.title('Number of tweets from different devices', fontsize = 20)

plt.show()*

Plot of tweet production from different devices

通过查看这张图表,我们可以看到大多数推文是由智能手机发布的,在这一类别中,Android 设备以微弱优势击败了 Iphones。

网络产生的推文也可能来自移动设备,但产生于浏览器,而不是 Twitter 应用程序。除了这些网络发布的推文(我们无法判断它们是来自 PC、Mac 还是移动网络浏览器),很少有推文来自公认的 Mac 或 Windows 设备。这些结果非常符合社交网络的轻松随和的本质。

最后,让我们看看一些可以从收集的数据中容易获得的额外信息

*#Lets see other useful information that can be gathered:#MEAN LENGTH OF THE TWEETS
print("The mean length of the tweets is:", np.mean(tweets['length']))#TWEETS WITH AN URL
url_tweets = tweets[tweets['text'].str.contains("http")]
print(f"The percentage of tweets with Urls is {round(len(url_tweets)/len(tweets)*100)}% of all the tweets")#MEAN TWEETS PER USER
print("Number of tweets per user:", len(tweets)/tweets['Username'].nunique())*

对我来说,这是平均长度为的145 条推文,23%的推文有 URL,平均每个用户的推文产量为2.23 条推文

就是这样!你可以在这里 找到这篇文章和上一篇文章 使用的 Jupyter 笔记本,以及我关于 Twitter 数据收集的其他文章的脚本和笔记本。

还有,更多关于自然语言处理和机器学习的牛逼资源,可以看看这个牛逼的博客: 如何学习机器学习

非常感谢你的阅读,请鼓掌,继续发微博,再见!

用 Python 可视化选举

原文:https://towardsdatascience.com/visualising-elections-with-python-4973c0c60bbe?source=collection_archive---------11-----------------------

公平地说,全球政治格局目前正在发生很多变化,无论你是美国人、T2 人、以色列人、委内瑞拉人,还是介于两者之间的任何人(作为一名英国人,我有自己的地狱般的经历,比如英国退出欧盟)。不管任何政治局势的细微差别,它们都有一个共同点,那就是它们产生的丰富多样、复杂的数据,等待人们去探索。例如,考虑一下你可能需要知道什么来完美预测选举之夜的表现:理解宣言政策及其后果;对人们将如何对政策和政治家做出反应的心理理解;社会学关于人口变化和人们作为一个群体如何投票的知识;以及博弈论预测在给定的制度下人们会如何投票。

但在所有这些之前,一个未来的政治学家必须能够捕捉和想象人们的情绪。在本帖中,我们将通过绘制英国的选举地图,向选举之夜优势迈出第一小步。

这种地图,正式名称为 choropleth 地图,有多种风格。我将详细介绍我如何使用 Python 创建两种类型的 choropleth 地图:英国的地理现实地图hex 地图,如下所示。对这里产生的观想的分析将在以后的文章中讨论。用于生成地图的代码可以在我的 Github 上看到。

A giant election map on the BBC piazza. I’ve opted for a slightly higher-tech approach.

创建地理地图

为了创建英国的基本 choropleth,我选择使用 Python 包 GeoPandas ,它扩展了 Pandas 来处理地理空间数据。

GeoPandas 使得使用一种流行的 GIS 数据格式 shapefile 绘制地图变得很简单。对那些试图绘制英国地图的人来说幸运的是,划分成选区的地图——英国的投票边界——是由国家统计局免费提供的。只需从网站上下载你选择的任何粒度的地图作为形状文件。

注意:shapefiles 由几个单独的文件组成,它们包含独立的信息。你需要保存 zip 文件夹中提供的所有文件。

要在 GeoPandas 中加载和绘制 shapefile:

import geopandas as gpd
import matplotlib.pyplot as pltmap_df = gpd.read_file("uk_generalized_2015.shp")
# map_df is a Pandas dataframef, ax = plt.subplots(1, figsize=(6, 6))
ax = map_df.plot(ax=ax)
ax.set_axis_off()

Sorry, Northern Ireland.

正如我们所看到的,GeoPandas 将 shapefile 转换成我们都熟悉和喜爱的数据帧。

增添一些趣味

我们开始得很好,但是地图看起来很无趣。我们现在需要掌握一些选区级别的变量,通过这些变量我们可以给地图着色。

为了这篇文章的目的,我们决定使用签署请愿书的选民的百分比来废除第 50 条。给那些不知情的人一个简单的入门:英国公民可以通过政府官方网站发起请愿,如果达到一定数量的签名,政府将在议会辩论请愿的主题。2019 年 3 月,一份要求撤销英国离开欧盟的法律机制第 50 条的请愿书在短短几天内就获得了数百万个签名。

每份请愿书都附有一份 JSON,其中包括按议会选区划分的签名数量,因此我们可以很容易地绘制一张地图,直观地显示国民对任何请愿书的情绪。但是,在将这些数据添加到 dataframe 之前,我们需要将 JSON 转换成 csv。

import csv
import jsonfile = "petition_data.json"
with open(file, "r", encoding="utf-8") as json_file:
  data = json.load(json_file)
data = data["data"]["attributes"]["signatures_by_constituency"]keys = data[0].keys()
save_file = "petition_data.csv"
with open(save_file, 'w') as f:
  dict_writer = csv.DictWriter(f, keys)
  dict_writer.writeheader()
  dict_writer.writerows(data)

现在我们需要结合数据,计算签名数占选民的百分比。请注意,要做到这一点,我们还需要关于每个选区选民规模的信息,这些数据也可以在国家统计局网站上获得。

import pandas as pddata_df = pd.read_csv("petition_data.csv")# Combine the two dataframes by their constituencies
combined = map_df.set_index("pcon15nm")
           .join(data_df.set_index("name"))
           .reset_index()# Also join the dataset containing electorate numbers
# Not included here for brevity# Clean the data
combined["electorate"].fillna(1e8, inplace=True)
combined["mp"].fillna("No MP", inplace=True)
combined["signature_count"].fillna(0, inplace=True)# Calculate the percentage votes
combined["signature_pc"] = 100 * combined["signature_count"] /           
                           combined["electorate"] 

虽然我们从中检索数据的请愿书非常受欢迎,但任何选区的最大签名比例只有 40%左右。我们将色彩映射表的最大值设置为这个值,否则大部分选区会向色谱的一端移动到无法区分的程度。

fig, ax = plt.subplots(1, figsize=(6, 6))
combined_data.plot(column="signature_pc", cmap="viridis", 
                   linewidth=0.8, ax=ax)
ax.axis("off")

vmin = 0.
vmax = 40.
sm = plt.cm.ScalarMappable(cmap="viridis", 
                           norm=plt.Normalize(vmin=vmin, 
                           vmax=vmax))
sm._A = []
cbar = fig.colorbar(sm)

Overly large colourbars are in this year.

虽然这不是你见过的最漂亮的地图,但它让我们可以快速方便地看到某样东西在全国的受欢迎程度。

创建十六进制地图

看着上面的地图,你会有这样的想法,因为请愿书只在几个选区获得了很高比例的签名,所以总体来说,它不受欢迎。然而,熟悉这个国家的人可能会认出地图右下角的亮点。那个亮点是伦敦,它是几百万人的家园。

这很好地证明了绘制百分比而非绝对受欢迎程度的地图在得出结论时会误导人们。虽然像这样的地图对于展示一个事物的地理分布非常有用,但我们偏向于赋予更大的区域更大的重要性。

努力创造无偏见的视觉效果,无论最终可能多么徒劳,我们现在将绘制六边形地图——在地图中,每个选区由一个大小相等的六边形表示。这些地图用地理现实主义来平衡地图上每个区域的重要性。

首先,我们需要每个选区六边形的坐标。因为在十六进制地图中,区域的大小被严重扭曲(在英国,最小的选区是一平方英里,最大的选区超过 4000 平方英里),所以不可能像在更真实的地图上那样排列选区。

在这篇文章中,我们从 ODILeeds 那里得到了底图,他们创造了一个神奇的工具来生成你自己的英国十六进制地图。对地图满意后,下载 HexJSON 并将其转换为 CSV 格式,如前所述。

不幸的是,研究用 Python 绘制这种地图的现成方法并没有取得成功:Matplotlib 的 hexbin 虽然目的相似,但将数据点隐藏起来,并且证明太难正确组织。有必要绘制单独的六边形,为此使用了 Matplotlib 补丁。下面是如何实现这一点的简单示例:

from matploblit.patches import RegularPolygon
import numpy as np

d = 0.5 / np.sin(np.pi/3)  # radius of poylgon
o = 0.5 * np.tan(np.pi/3)  # orientation of polygon
y_diff = np.sqrt(1 - 0.5**2)  
# difference in y location for consecutive layers

colors = ["red", "blue","green"]
hcoord = [0.5, 0, 1]
vcoord = [y_diff, 0, 0]

fig, ax = plt.subplots(1)

for x, y, c in zip(hcoord, vcoord, colors):
    hex = RegularPolygon((x, y), numVertices=6, radius=d,
                         facecolor=c, alpha=0.2, edgecolor='k')
    ax.add_patch(hex)ax.set_xlim([-0.5, 1.5])
ax.set_ylim([-0.6, 1.45])
plt.show()

Great maps, like great food, are built on honeycombs.

在创建全英国地图之前,剩下的一个挑战是计算出六边形的坐标:连续的行有一个交替的起点,这是蜂窝的性质。ODILeeds 提供的地图使用“ odd-r ”格式,这意味着奇数行包含最右边的六边形。

def calc_coords(row, column):
  if row % 2 == 1:
    column = column + 0.5
  row = row * y_diff
  return row, column

为了创建英国,我们遍历选区,并为每个区域绘制一个六边形。然而,当试图创建平滑的颜色图时,如上所述,手动提供颜色将是一项乏味的任务。我们利用 PatchCollection 对六边形进行分组,并提供一个 Matplotlib colourmap 来完成繁重的彩色提升。

from matplotlib.collections import PatchCollectionfig, ax = plt.subplots(1, figsize=(6, 6))
ax.axis("off")patches = []
colours = []
for i in range(combined.shape[0]):
  # here, combined is a join of hex csv and petition data
  # creating combined has been omitted for brevity
  row = combined.loc[i, "r"]
  col = combined.loc[i, "q"]
  row, col = calc_coords(row, col)
  c = combined.loc[i, "signature_pc"]hexagon = RegularPolygon((col, row), numVertices=6, radius=d, 
                         edgecolor='k')
patches.append(hexagon)
colours.append(c)p = PatchCollection(patches, cmap=plt.get_cmap("viridis"), 
                    alpha=1.0) 

Title and labels not included.

有了这张地图,我们可以看到伦敦的全貌,以及它与周围地区的对比。知道了选区的人口大致相似,我们就能更清楚地看到这一请愿在英国有多普遍。

最后的想法和下一步

除了这篇文章中所展示的,我还使用了定期从撤销第 50 条请愿书中获取的数据,以可视化整个英国的请愿书的传播。生成的地图可以在 GitHub 上看到。我最诚挚地感谢奥迪利兹的斯图尔特·劳收集并提供了请愿资料。

虽然回想起来我会认为这是一次成功的练习,但创建十六进制地图的过程让我相信,使用奇异的地图来可视化选举并不是 Matplotlib 非常适合的工作。如果我或任何阅读这篇文章的人决定创建更复杂的地图,可能有必要看看其他工具,如 d3牵牛星

毫不奇怪,选举报道和分析的范围远远超出了本文的范围。有各种各样的地图用于覆盖世界各地的选举,每一张部署到传达稍微不同的意思。然而,这里探讨的两种类型可以构成相当翔实的政治分析的基础。

在这个项目之后,就我而言,我期待着英国的下一次选举,期待着有机会利用这些地图,如果没有其他事情的话。在那之前,我只能满足于请愿。

为深度学习可视化过滤器和特征图

原文:https://towardsdatascience.com/visualising-filters-and-feature-maps-for-deep-learning-d814e13bd671?source=collection_archive---------4-----------------------

想获得灵感?快来加入我的 超级行情快讯 。😎

深度神经网络是最强大的机器学习模型之一。有了足够的数据,它们在计算机视觉和自然语言处理(NLP)等任务中的准确性是无与伦比的。

许多科学家会评论的唯一缺点是,这些网络完全是黑箱作业。对于深度网络如何如此好地学习它们的目标模式,尤其是所有神经元如何一起工作以实现最终结果,我们仍然知之甚少。

对 ML 模型如何工作有某种内部了解会带来一些关键优势:

  • 它们更容易调整,因为当我们看到网络出错时,我们可以直接指出原因
  • 可以解释网络的功能和预期行为,特别是对非技术利益相关者
  • 我们可以进一步扩展和改进模型的整体设计,因为我们已经了解了当前的设计,包括它的优点和缺点

令人高兴的是,研究人员已经开始探索理解深层网络内部情况的技术。特别是,我们现在有能力可视化卷积神经网络(CNN)从其计算机视觉任务训练中学习的过滤器,以及 CNN 应用于图像时产生的特征图。

本教程将教你如何做到这一点:可视化的过滤器和特征地图的 CNN 训练的图像分类。我们甚至可以在超级易用的 Keras 中完成!

挑选我们的模型

首先,我们需要选择一个模型来可视化。

在 Keras 中,最简单的方法是选择一个预先训练好的图像分类模型。在它的应用页面中有很多这些表现最好的模型。他们都在 ImageNet 数据集上进行了训练,该数据集包含超过 100 万张图片。

对于本教程,我将挑选 VGG16 型号。它很简单,我们可以浏览我们的教程,并仍然保持其作为一个相当准确的模型。结构如下所示。

在 Keras 中加载模型的过程如下所示。当您从keras.applications导入模型时,Keras 会自动将权重下载到适当的目录中。然后,我们加载模型并打印出它的结构概要。

可视化过滤器

我们将创建的第一个可视化是 CNN 过滤器。

当深度学习的人们谈论“过滤器”时,他们指的是卷积的学习权重。例如,单个 3×3 卷积称为“滤波器”,该滤波器总共有 10 个权重(9 + 1 偏差)。

通过可视化学习的权重,我们可以了解我们的网络学习得有多好。例如,如果我们看到许多零,那么我们将知道我们有许多对我们的网络没什么用的死过滤器——这是为模型压缩做一些修剪的好机会。

看看下面可视化过滤器的代码,然后向下滚动查看它如何工作的解释。

在导入了所有必需的库并加载了模型之后,我们在第 7 行构建了模型中各层的字典。这将允许我们通过层名称访问每个层的权重。如果你想查所有的名字,你可以打印出字典中的关键字。

接下来,我们将在第 9 行设置我们想要显示其滤镜的图层的名称。我选择了“block5_conv1 ”,但您可以选择任何您喜欢的卷积块。

在第 13 行中,我们调用get_weights()函数从我们选择的层中获取过滤器和偏置权重。

在第 16 行和第 17 行,我们对过滤器值进行了归一化处理,使它们介于 0 和 1 之间。当我们在屏幕上以颜色显示重量时,这将有助于创建清晰的视觉效果。

最后,我们从第 21 行开始的循环显示了一些过滤器。对于我们选择的“绿色”色图,黄色代表值 1,深蓝色代表值 0。

查看下面 VGG16 的 block5_conv1 层的输出!

可视化特征地图

CNN 的特征图捕捉将过滤器应用于输入图像的结果。即在每一层,特征图是该层的输出。

将特定输入图像的特征映射可视化的原因是为了试图了解我们的 CNN 检测到了什么特征。也许它检测到了我们想要的物体的某些部分,而没有检测到其他部分,或者激活在某一层消失了。

直接观察深度学习中的一个常见想法也很有趣,即网络的早期层检测低级特征(颜色、边缘等),网络的后期层检测高级特征(形状和对象)。

看一下下面的可视化特征地图的代码,然后向下滚动查看它是如何工作的解释。

前两个步骤保持不变:加载模型并选择你想要可视化的层的名称。一个小的变化是我们修改了我们的模型,使得最终输出是 VGG16 的最后一个特征地图的输出,因为我们并不真正需要最后两个完全连接的层。

接下来,我们将在第 16 到 19 行加载并准备我们的图像。你可以选择任何你喜欢的图像;我选择了一个老虎的形象,因为老虎是令人敬畏的。

第 16 到 19 行的代码将读取图像并应用 VGG16 模型所需的必要预处理。如果您的图像像 4K 分辨率一样大,也不用担心,因为 VGG 总是希望图像的大小为 224x224,所以输入在处理之前总是会重新调整大小。

在第 22 行,我们将 VGG16 模型应用于输入图像;输出将是我们想要的特征地图。我们将遍历地图的几个通道,并在 matplotlib 图形中可视化它们。

查看下面的结果图。注意在图像的边缘和纹理上有很多激活,尤其是我们的老虎的轮廓!

喜欢学习?

在 twitter 上关注我,我会在这里发布所有最新最棒的人工智能、技术和科学!也在 LinkedIn 上和我联系吧!

Santa2Graph:使用 Giotto Mapper 可视化高维数据

原文:https://towardsdatascience.com/visualising-high-dimensional-data-with-giotto-mapper-897fcdb575d7?source=collection_archive---------13-----------------------

拓扑数据可视化的 Mapper 算法的简单介绍,包括使用 giotto-learn 中的实现的教程

由弗朗西斯科·帕尔马、大卫·伯巴、路易斯·汤斯顿、托马斯·博伊斯编剧

教程链接:https://github.com/giotto-ai/tutorial_mapper

除非你天生擅长数字,否则数据可视化仍然是数据分析最直接、最有效的洞察来源。特征之间的视觉相互作用提供了影响许多选择的洞察力,如特征工程和特征选择。

我们都喜欢有很多功能。好的一面是潜在的更多信息;不利的一面是很难分离这些信息。由于我们不能轻易地可视化三维以上的物体,标准的可视化方法不太适合高维数据。

Mapper 算法提供了一种在单个图形中可视化数据内在形状的方法。这个图表是通过一个巧妙的聚类过程构建的,揭示了底层数据的粗略结构。实际上,理论结果证实了输出的拓扑准确性。

在本文中,我们将介绍映射器算法,以及基于 giotto-learn 库给出的实现的教程。它的一个很酷的特性允许您与一些映射器参数进行交互,而无需重新运行代码。

Interactive Mapper available in giotto-learn.

映射器算法的应用

自 2007 年以来,Mapper 一直用于简化复杂交互的可视化。它提供了对大特征空间的定性分析,有助于在医学、材料科学和基因组学中的应用。最近,它也被应用于提高神经网络的鲁棒性。

下面我们总结了映射器算法的两个著名应用:

1)乳腺癌患者分析

在一项乳腺癌研究中,只有 200 名患者,需要一种专门的方法来处理基因型特征空间的 30k 维。Mapper 算法已成功应用于对患者进行更精细的细分,从而大大改善了靶向治疗。在两个不同的数据集上进行了相同的分析,并提供了一致的输出,证明了算法的稳定性。

2)NBA 球员的分类

如果你打过篮球,你就会知道篮球一直有五个位置:控卫、得分后卫、小前锋、大前锋和中锋。使用球员的统计数据和比赛中的表现,Mapper 算法确定了 13 种反映现代篮球动态的新打法。这让团队的总经理知道了组建团队时不可错过的技能。

映射器算法

摘自原创论文:

我们并不试图获得一个数据集的完全准确的表示,而是获得一个易于理解的低维图像,它可以指出感兴趣的领域。

为了生成表示数据结构的粗略图形,该算法将点合并成节点,并在不同节点的公共点处连接它们。

这个过程是由神经定理驱动的,它保证了映射器输出在拓扑上等同于数据采样的形状。

实际上,该算法是一个三步过程:

  1. 过滤:我们通过使用过滤函数 f. 将数据点映射到ℝ
  2. 覆盖:我们用重叠区间覆盖过滤值。
  3. 聚类:对于每个区间,我们将一个聚类算法应用于在该区间中映射的观察值。

Among the points that are close in filter value, we cluster together the one that are similar in the original space. Nodes are connected whenever they share a point. (Source: https://arxiv.org/abs/1904.11044)

1)过滤

映射器的第一步在于通过过滤函数f:ℝⁿℝᵐ.将每个数据点 x 映射到低维空间ℝᵐ通常我们选择 m=1 或者 m=2

过滤函数的选择对映射结果有很大的影响,因为过滤值较远的点没有机会聚集在一起。因此,过滤函数用作接近度的粗略测量。

在上图中,作者使用了高度函数,但是原则上任何函数都可以完成这项工作。但是,一些常见的选择是:

  1. 轴上的投影
  2. PCA
  3. 怪癖
  4. 密度

2)覆盖

我们以覆盖所有滤波器值的方式将图像空间划分成重叠的区间(或者区间的乘积,如果 m > 1 )。我们称这样的结构为盖。

通常我们将封面设定为由相同尺寸的 m 维间隔制成。例如,如果 filter 函数采用ℝ中的值,则 cover 由一系列等长的重叠线段组成。

在这种情况下,要选择的参数是间隔数及其重叠百分比。在上面的例子中,有 4 个 25%重叠的区间。

3)聚类

在最后一步中,我们在封面的每个区间上连续地执行聚类。通过过滤函数每次取间隔的预图像,在原始空间上进行聚类。输出图由以下部分组成:

  • 节点,表示数据点的集群;
  • 边缘代表聚类对(共享一些数据点的聚类)之间的非空交集。由于时间间隔重叠,这是可能的。

在这一点上,每个聚类代表图的一个节点,并且边对应于具有共同观察的聚类。

教程:使用映射器检索圣诞老人

直观理解映射器如何工作的最好方法是使用它并“玩”它的参数。

Giotto 是一个开源项目,包含 giotto-learn,一个易于使用的拓扑数据分析工具包。它使用了一个类似 Scikit-learn 的 API,并提供了一种通过管道函数来适应映射器的便捷方法。给定 Numpy 数组形式的数据集,构建图形的代码如下:

pipeline = make_mapper_pipeline(
    filter_func=Projection(column_indices=2),
    cover=OneDimensionalCover(n_intervals=10, overlap_frac=0.1),
    clusterer=DBSCAN(eps=0.5),
)
graph = pipeline.fit_transform(data)

我们将 Mapper 算法应用于数据集,该数据集包含从圣诞老人形状(即所谓的“圣诞老人云”)中采样的 20,000 个三维数据点。

Left: dataset sampled from here using CloudCompare. Right: Mapper output using different parameters.

作为第一次尝试,我们使用覆盖和聚类的默认参数以及高度上的投影作为过滤函数,即 f: [ x,y,z ]↦ z。我们通过点的平均颜色给每个节点着色:

With the default parameters Santa might make it through the chimney.

该图不代表数据集,因为我们无法区分圣诞老人身体的任何特征。除了节点的任意位置之外,给圣诞老人一个蛇形的外观,该图相当于一条连接节点的线。这表明聚类算法的默认参数需要改变,因为我们总是将所有的过滤器间隔聚集在一起。

为了解决这个问题,我们执行了更精细的聚类:

Mapper output: DBSCAN(eps = 0.06).

太好了!这是一个不平凡的图形结构。特别是我们看到树枝的外观,代表圣诞老人的胳膊和腿。然而,在这幅画中,圣诞老人有四只手臂。

我们通过调整封面中间隔之间的重叠部分(默认值为 0.1)来解决这个问题:

Mapper output: DBSCAN(eps = 0.06), overlap_frac = 0.35.

这次我们可以清楚地分辨出腿、胳膊和头。虽然它非常简单,但一般来说,这足以抓住主要结构。

我们可以通过增加封面中的区间数(默认为 10)来进一步完善我们的研究。这样,我们看到了代表帽子的节点的外观,以及将胸部与胡须分开的分支:

Mapper output: DBSCAN(eps = 0.06), overlap_frac = 0.35, n_intervals = 20.

结论

giotto-learn 库提供了 Mapper 算法的快速完整的 Python 实现。我们正在分享一个关于 3-d 数据的教程,现在你可以用你自己的映射图来表现高维数据集了。

特别感谢 Umberto Lupo 和Lewis Tunstall在 giotto-learn 中实现映射器。

链接:

用 Google 的 FACETS 可视化机器学习数据集。

原文:https://towardsdatascience.com/visualising-machine-learning-datasets-with-googles-facets-462d923251b3?source=collection_archive---------8-----------------------

谷歌的一个开源工具,可以从大量数据中快速学习模式

Photo by Franki Chamaki on Unsplash

更多的数据胜过聪明的算法,但更好的数据胜过更多的数据

关于大量训练数据如何对机器学习模型的结果产生巨大影响,已经有了很多争论。然而,除了数据量之外,质量也是构建一个强大而健壮的 ML 系统的关键。毕竟,“垃圾输入:垃圾输出”,也就是说,你从系统中得到的,将代表你输入到系统中的。

机器学习数据集有时由数千到数百万的数据点组成,这些数据点可能包含数百或数千个特征。此外,现实世界的数据是混乱的,包括缺失值、不平衡数据、异常值等。因此,在继续建模之前,我们必须清理数据。可视化数据可以帮助定位这些不规则性,并指出数据需要清理的地方。数据可视化提供了整个数据的概览,无论其数量多少,并能够快速准确地执行 EDA。

面状

facets 在字典中的意思可以归结为某事物的某一方面或特征。同样的, FACETS 工具帮助我们理解数据的各种特性并探索它们,而无需显式编码。

Facets 是 Google 在 (People+AI Research)倡议下发布的开源可视化工具。这个工具帮助我们理解和分析机器学习数据集。Facets 由两个可视化组成,这两个可视化有助于挖掘数据并提供很好的洞察力,而无需在用户端做太多工作。

  • 刻面概述

顾名思义,这种可视化提供了整个数据集的概览,并提供了数据的每个要素的形状。Facets Overview 总结了每个功能的统计信息,并比较了训练数据集和测试数据集。

  • 刻面跳水

此功能有助于用户深入研究数据的单个特征/观察结果,以获得更多信息。它有助于一次交互式地探索大量数据点。

这些可视化实现为聚合物网络组件,由打字稿代码支持,可以很容易地嵌入到 Jupyter 笔记本或网页中。

使用和安装

有两种方法可以将方面用于数据:

网络应用

它可以直接从它的演示页面使用,其链接嵌入在下面。

[## 面向 ML 数据集的可视化

Dive 提供了一个交互式界面,用于探索所有不同的数据点之间的关系…

配对代码. github.io](https://pair-code.github.io/facets/)

这个网站允许任何人直接在浏览器中可视化他们的数据集,而不需要任何软件安装或设置,数据不会离开你的计算机。

在 Jupyter 笔记本/合作实验室内

也可以在 Jupyter 笔记本/协作室中使用刻面。这提供了更大的灵活性,因为整个 EDA 和建模可以在一个笔记本上完成。请参考他们的 Github 库以获得安装的完整细节。然而,在本文的后面,我们将看到如何在 colab 中使用刻面。

数据

虽然您可以使用演示页面上提供的数据,但我将使用另一组数据。我将在贷款预测数据集上做 EDA。问题陈述是为了预测一个申请人是否会偿还一家公司给予的贷款。这在 ML 社区中是一个众所周知的例子。

已经划分为训练集和测试集的数据集,可以从这里的 进入 。让我们把数据载入数据库。

import pandas as pd
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')

现在让我们了解如何对这些数据使用 Facets Overview。

方面概述

概览自动让您快速了解数据各种要素的值分布。还可以即时比较训练和测试数据集之间的分布。如果数据中存在某种异常,它会立即从数据中跳出来。

通过此功能可以轻松访问的一些信息包括:

  • 平均值、中值和标准差等统计数据
  • 列的最小值和最大值
  • 缺失数据
  • 值为零的值
  • 由于可以查看测试数据集的分布,我们可以很容易地确认训练和测试数据是否遵循相同的分布。

有人会说,我们可以用熊猫轻松完成这些任务,为什么我们要投资另一种工具。这是真的,当我们只有少量具有最小特征的数据点时,可能不需要。然而,当我们谈论大型数据集时,情况就不同了,在这种情况下,分析多列中的每个数据点变得有点困难。

谷歌协同实验室使工作变得非常容易,因为我们不需要安装其他东西。通过编写几行代码,我们的工作就完成了。

# Clone the facets github repo to get access to the python feature stats generation code
!git clone [https://github.com/pair-code/facets.git](https://github.com/pair-code/facets.git)

为了计算特征统计数据,我们需要使用 Python 脚本中的函数GenericFeatureStatisticsGenerator()

 # Add the path to the feature stats generation code.
import sys
sys.path.insert(0, '/content/facets/facets_overview/python/')# Create the feature stats for the datasets and stringify it.
import base64
from generic_feature_statistics_generator import GenericFeatureStatisticsGeneratorgfsg = GenericFeatureStatisticsGenerator()
proto = gfsg.ProtoFromDataFrames([{'name': 'train', 'table': train},
                                  {'name': 'test', 'table': test}])
protostr = base64.b64encode(proto.SerializeToString()).decode("utf-8")

现在,通过下面几行代码,我们可以轻松地在笔记本上显示可视化效果。

# Display the facets overview visualization for this data
from IPython.core.display import display, HTMLHTML_TEMPLATE = """<link rel="import" href="[https://raw.githubusercontent.com/PAIR-code/facets/master/facets-dist/facets-jupyter.html](https://raw.githubusercontent.com/PAIR-code/facets/master/facets-dist/facets-jupyter.html)" >
        <facets-overview id="elem"></facets-overview>
        <script>
          document.querySelector("#elem").protoInput = "{protostr}";
        </script>"""
html = HTML_TEMPLATE.format(protostr=protostr)
display(HTML(html))

当您输入Shift+Enter时,您会受到这个优秀的交互式可视化的欢迎:

在这里,我们看到了贷款预测数据集的五个数字特征的方面概述可视化。要素按不均匀性排序,分布最不均匀的要素位于顶部。红色的数字表示可能的故障点,在这种情况下,数字特征具有设置为 0 的高百分比值。右侧的直方图允许您比较训练数据(蓝色)和测试数据(橙色)之间的分布。

上面的可视化显示了数据集的八个分类特征之一。要素按分布距离排序,训练数据集(蓝色)和测试数据集(橙色)之间偏斜最大的要素位于顶部。

多面跳水

Facets Dive 提供了一个易于定制的直观界面,用于探索不同特征之间的数据点关系。使用 Facets Dive,您可以根据其特征值控制每个数据点的位置、颜色和视觉表示。如果数据点具有与其相关联的图像,则图像可以用作视觉表示。

要使用 Dive 可视化,必须将数据转换成 JSON 格式。

# Display the Dive visualization for the training data.
from IPython.core.display import display, HTML**jsonstr = train.to_json(orient='records')**
HTML_TEMPLATE = """<link rel="import" href="[https://raw.githubusercontent.com/PAIR-code/facets/master/facets-dist/facets-jupyter.html](https://raw.githubusercontent.com/PAIR-code/facets/master/facets-dist/facets-jupyter.html)">
        <facets-dive id="elem" height="600"></facets-dive>
        <script>
          var data = {jsonstr};
          document.querySelector("#elem").data = data;
        </script>"""
html = HTML_TEMPLATE.format(jsonstr=jsonstr)
display(HTML(html))

运行代码后,您应该能够看到以下内容:

Facets Dive Visualisation

现在,我们可以轻松地执行单变量和双变量分析,并让我们看看获得的一些结果:

单变量分析

在这里,我们将单独查看目标变量,即 Loan_Status 和其他分类特征,如性别、婚姻状况、就业状况和信用历史。同样,您也可以尝试不同的功能。

推论:

  • 数据集中的大多数申请者都是男性。
  • 同样,数据集中的大多数申请人都已经结婚并偿还了债务。
  • 此外,大多数申请人没有家眷,是半城市地区的毕业生。

现在让我们来看一下顺序变量,即受抚养人、教育和财产面积。

从上面的柱状图可以得出以下推论:

  • 大多数申请人没有任何家属。
  • 大多数申请者都是毕业生。
  • 大多数申请者来自半城市地区。

现在,您可以继续使用数字数据进行分析。

双变量分析

我们将找到目标变量和分类自变量之间的关系。

从上面的柱状图可以推断出:

  • 对于已批准的贷款,已婚申请人的比例较高。
  • 有一个或三个以上受抚养人的申请者在两种贷款状态类别中的分布是相似的。
  • 似乎信用记录为 1 的人更有可能获得贷款批准。
  • 半城市地区获得贷款批准的比例高于农村或城市地区。

结论

FACETS 提供了一个简单直观的环境来为数据集执行 EDA,并帮助我们获得有意义的结果。唯一的问题是,目前,它只适用于 Chrome

在结束本文之前,让我们也看看一个有趣的事实,它强调了如何使用 FACETS Dive 捕获 CIFAR-10 数据集中的一个小的人为标记错误。在分析数据集时,它注意到一张青蛙的图片被错误地标注为猫。嗯,这的确是一项成就,因为对于人类的眼睛来说,这是一项不可能完成的任务。

Source

在 Python 中可视化缺失的面板数据

原文:https://towardsdatascience.com/visualising-missing-panel-data-in-python-8dc79f6dbeb3?source=collection_archive---------20-----------------------

Photo by Iker Urteaga on Unsplash

如果您开始处理新的数据集,一个重要的分析是完整性测试。现实生活中的数据从来都不是完美的,可能经常包含缺失值。如果您正在使用 Pandas(如果您正在进行数据争论,您应该这样做),有一些简洁的函数可以填充缺失的数据,比如 。菲尔娜() 但是,在填充缺失的数据之前,最好先了解缺失的内容等。这个简短的教程展示了面板数据完整性的一些可视化。

什么是面板数据?

Score 1 Dataframe

Score2 Dataframe

面板数据是多维数据,通常包含多个时间段的多个变量。例如,假设我们跟踪不同的健康得分(身体质量指数、血糖等。)对于一群多年来的参与者来说。对于每个变量(例如,得分 1、得分 2),这将导致二维数据框架。这显然是不方便的,因为我们不想处理多个数据帧,并且认为 3D 是不直观的。因此,我们通常“堆叠”数据帧,其中每一行代表参与者和年份的唯一组合。

Stacked dataframe

让我们以堆叠格式创建一个面板数据集:

该样本包含一组人在 1955 年至 2019 年之间的(健康)得分。数据中有我们想要探究的缺失值(代码在最后)。打印数据帧的头部,我们可以看到很多缺失的数据。因此,我们希望对缺失的数据有更好的感觉,并试图了解是否有任何模式。

Head of the dataframe

我写了一个小函数,为感兴趣的变量创建一个图形。在 y 轴上,您可以看到观察结果(本例中为名称)。在 x 轴上你看到了年份。可用值以蓝色高亮显示,而缺失数据以灰色显示。

我们在这里能看到什么?

我们可以看到,Score 的可用值最多,而 Score 2 的可用值最少。大多数缺失值是随机的,但也有少数组成员没有值或所有值都可用(例如蓝色水平线)。这个函数可以在一个循环中使用,以方便地遍历所有变量,并允许直接发现模式。如果一些分数可以作为替代,我们应该在这种情况下使用 score1,因为它具有最完整的信息。

使用 2000 年至 2019 年间 1000 家公司的真实财务信息,图表如下所示。还有更多的信息缺失。我们可以直接发现,没有 2000 年的信息。此外,我们看到一些公司不是每季度报告一次,而是每年报告一次,只有每年第四季度的数据。一些公司只是出现的时间晚一些,而另一些则消失了。

可视化损失函数和梯度下降之间的关系

原文:https://towardsdatascience.com/visualising-relationships-between-loss-activation-functions-and-gradient-descent-312a3963c9a5?source=collection_archive---------6-----------------------

梯度下降处理损失/激活函数

本文假设你有训练神经网络的先验知识,并试图通过可视化揭示损失函数、梯度下降和反向传播之间的关系。

左图显示了损失函数和梯度下降之间的关系。

为了可视化梯度下降,想象一个过度简化为神经网络的最后一个节点输出一个权重值 w,目标值为 0 的例子。在这种情况下,损失函数是均方误差(MSE)。

当 w 大于 0 时,MSE 的导数 dy/dw 为正。正 dy/dw 可以解释为 w 的正阶跃将导致 y 的正变化,为了降低损耗,需要 w 方向的负阶跃:

当 w 小于 0 时,MSE 的 dy/dw 为负,这意味着 w 的正阶跃将导致 y 的负变化,为了降低损耗,需要在 w 方向上有一个正阶跃:

因此,总结权重更新的公式如下:

其中 learning_rate 是一个常数,用于调整导数应该步进的百分比。应该调整 Learning_rate,防止 w 的步长太小或太大。还应该调整 Learning_rate,以防止梯度爆炸(梯度过大)或消失梯度问题(梯度过小)。

对于更长且更实际的计算图,其中权重在 sigmoid 激活之后,为了更新权重 w1,损失相对于 w1 的导数可以如下找到:

the derivative of loss with respect to weight, w1

从上述步骤可以看出,神经网络中的权重是由损失函数的导数而不是损失函数来修正或反向传播的。损失函数对反向传播没有贡献。

L2 Loss

MSE (L2 损耗)的导数的大小为 2w。MSE 的导数的幅度变化有助于当 w 远离目标 0 时向 w 反向传播较大的步长,而当 w 靠近目标 0 时向 w 反向传播较小的步长

L1 Loss

平均绝对误差(MAE)(L1 损失)具有 1 或负 1 的常数导数,这在区分 w 离目标有多远时可能不理想。反向传播只使用损失函数的导数,不使用损失函数。

Cross-Entropy Loss

交叉熵损失只涉及 0 和 1 之间的 w 的定义域。当 w 接近 1 时,交叉熵减小到 0。交叉熵的导数是-1/w。

Sigmoid activation

Sigmoid 函数的导数范围在 0 到 0.25 之间。sigmoid 函数的导数的乘积可能导致非常小的接近于 0 的数,这使得反向传播无用。这就是所谓的消失梯度问题。

Relu activation

当导数为 1 或 0 时,Relu 成为良好的激活函数,允许在反向传播中对权重进行恒定更新或对权重进行 0 更新。

想象新加坡不断变化的天气模式:1983–2019

原文:https://towardsdatascience.com/visualising-singapores-changing-weather-patterns-1983-2019-a78605fadbdf?source=collection_archive---------11-----------------------

通过使用像 Plotly Express 这样的经典和新的可视化库,我试图发现东南亚城市国家 36.5 年的天气数据背后的模式。

Animated gif of maximum monthly recorded temperatures in Singapore from 1983 to June 2019.

缺少季节变化使许多人认为新加坡的天气是可预测的,不会改变。事实并非如此,气候变化让这个城市国家的天气变得更加不可预测。

我们开始感受到更暖和的天气和更强烈的风暴的影响。从地面来看,新加坡似乎在较早的时候变得更暖和了。

在许多日子里,早上 8 点迎接我的太阳感觉更像是我在上午晚些时候期待的东西。午后的火焰从未如此强烈。

在这个项目中,我将尝试使用经典的和新的可视化库,如 Plotly Express ,来展示新加坡不断变化的天气模式。

该项目的回购在此为。这个中帖的图表可以在这个笔记本中找到,而数据可以在这里这里 (raw 版本)。

1。数据预处理

这个数据集是我能在新加坡公共领域找到的为数不多的详细的多年数据集之一。本文中的图表来自四个表格,这些表格针对少量缺失值进行了轻微处理,并针对额外的日期时间相关列进行了功能设计(参见笔记本此处)。

第一张表是来自气象局网站的一组每日记录,从 1983 年 1 月 1 日到 2019 年 6 月 30 日。虽然每日记录可以追溯到 1980 年,但 1980 年至 1982 年之间的记录大多不完整。出于一致性的考虑,我将所有四个表的共同起点设置为 1983 年。

第二张第三张第四张表格是来自新加坡政府数据机构网站的月度综合天气数据——分别为最高月气温、平均月气温和月降雨量。

本项目气象数据的原始来源可以在这里这里找到。

2.暖气打开了——显示每日和每月的温度记录

根据新加坡国家气候变化秘书处的数据,从 1948 年到 2016 年,该国的年平均气温平均每十年上升 0.25 摄氏度。

该机构预测,未来日平均气温将上升 1.4 摄氏度至 4.6 摄氏度,在本世纪余下的时间里,从 2 月到 9 月,白天和夜晚将更加温暖。一组简单的折线图显示了我们的前进方向:

无论你怎么看,新加坡正在变暖,最高、最低和平均记录温度的趋势线都指向上方。

然而,在线图中经常会丢失细节,尤其是当彼此相邻分组时。在这种情况下,箱线图会很有用,它让我们深入了解多年来中值的分布以及异常值在哪里。

每个方框末端的水平线(或“胡须”)指的是当年各自的最小值和最大值,而中间的线指的是中间值。黑色的“钻石”是异常值。

一目了然,我们可以知道某一年的最高或平均温度范围,以及哪些年份的温度高于或低于正常温度。

可视化温度变化的另一个经典方法是使用热图:

左侧的热图显示的是月平均气温,描绘了几十年来更清晰的趋势,右侧较暗的斑块表明月平均气温在上升。中间较暗的区域也告诉你哪里最热。

右侧热图中最高月气温的模式有点难以解读。较暗的部分主要集中在 2 月至 5 月期间,尽管近年来从 2014 年开始,10 月份也有一片有趣的深红色。

2.1 实验#1:脊线图

随着更严肃的图表的出现,让我们看看更不常见的技术/库是否会产生更有趣的东西。

自从我在 2018 年末第一次遇到山脊线地块(或曾被称为 joyplots)以来,我一直很喜欢它们锐利、棱角分明的外观。它们看起来很棒,但我要诚实地说,在这种情况下,它们不一定像更简单的 Seaborn 图表那样清晰地呈现温度趋势。

2.2 实验#2:用 PLOTLY EXPRESS 制作 3D 动画图

Plotly Express 提供了大量有趣的功能,包括制作交互式 3D 动画图表的能力,如下图所示。诚然,这不是最清晰或最有效的方式来说明一种趋势,但它在视觉上令人兴奋,并在适当使用时为演示添加了一个有趣的新选项:

Medium 不便于将交互式图表嵌入到帖子中。要查看上图和下图,请点击查看完整的笔记本

3.大雨将至——可视化每日和每月的降雨记录

在 1983 年 1 月至 2019 年 6 月期间,有 6399 天的降雨和 6931 天的干旱-大致持平。随着气候变化,预计会有更强烈的风暴。同样,让我们从经典和简单的图表开始,然后尝试不同的方法来显示每日和每月的降雨量数据。

上面的图表简单明了,总结了年降雨量并按年份分组。1997 年和 2015 年是年降雨量最少的年份,而 2007 年是年降雨量最多的年份。

但就年总降雨量而言,还没有持续的大幅上升或下降的迹象。让我们从更细的角度来看一下数据。

对于关于降雨量记录的第二个图表,我决定打破一些小规则,将 y 轴反转来模拟降雨的样子。我不确定这在“适当的”数据可视化中是否会遭到反对,但我觉得这是一种视觉上吸引人的数据呈现方式,也是数据本质的有机组成部分。

一眼看去,你就能知道异常值在哪里,是日降雨量还是月降雨量。

2011 年 1 月 30 日是过去 36 年来单日降雨量最大的一天。事实上,根据英国气象局对 2011 年天气的回顾,那是“自 1869 年有记录以来,一月份一天中最高的降雨量”。

转向右边的图表,我们看到 2006 年 12 月的月降雨量是该数据集中最大的。很快就可以看出,缺乏交互性是这种图表的一个问题,在这种图表中,您希望能够通过将鼠标悬停在特定数据点上来调出该数据点。在这种情况下,给图表添加注释会很麻烦。

同样,Plotly Express 图表在这种情况下很方便:

3.1 实验#3:条形图竞赛

最近,条形图比赛在社交媒体上变得非常流行。我用荣景上的模板为每月的降雨数据做了一个:

我明白为什么这样的图表在社交媒体上表现良好。但它们在传达趋势方面是否真的有效值得怀疑。你能把这个放在正式的报告里吗?

4.当风吹过的时候

由于地理位置的原因,风速在新加坡没有得到太多关注,这使得该岛免受热带气旋等严重风暴的影响。但快速浏览一下风力数据的历史模式,寻找潜在变化的迹象,仍然很有意思。

右边的图表表明,新加坡的平均风速在过去几十年里没有增加多少。在左图中,有趣的是看到了 2010 年以来记录的一系列强风。

过去 36 年中记录的最强阵风是在 2010 年 11 月 29 日,当时最大风速达到 90.7 公里/小时——约为同期记录的平均最大风速的 2.6 倍。

4.1 风&雨

我们自然也会把强风和暴雨联系在一起。让我们看看这两个条件是如何随时间变化的:较大的三角形表示降雨量较高,阴影较暗的三角形表示较新的降雨量,而阴影较浅的三角形则反映较早的降雨量记录。

这是使用 Plotly Express 复制的同一张图表,因此可以使用交互功能快速调用各个值:

5。一次又一次:矩阵面板比较

如果你想把天气数据按照月和日分解成一个面板矩阵,Plotly Express 有一个简洁的功能。

我为 1988 年、1998 年、2008 年和 2018 年的天气记录绘制了四个这样的矩阵,以比较四十年来的温度-降雨模式。较大和较暗的圆圈表示暴雨较大。

我在这里只包括了图表的截屏。对于完整的交互式图表,请查看笔记本这里,您可以将鼠标悬停在各个点上以获取更完整的数据。要放大感兴趣的特定区域,只需在图表上单击并拖动即可。

观想的可能性是无穷无尽的,这感觉像是在疲劳到来之前停下来的好时机。我很好奇你会用同样的数据集得出什么结论。请通过以下方式与我分享:

推特:@chinhon

领英:【https://www.linkedin.com/in/chuachinhon/

通过开放式银行和地理信息系统可视化消费行为

原文:https://towardsdatascience.com/visualising-spending-behaviour-through-open-banking-and-gis-9e7045674538?source=collection_archive---------34-----------------------

金融习惯历来是人们不太在意的东西,但随着信息量和可用工具的增加,一种新的金融控制态度正在透明的数字银行中越来越受欢迎。新型金融机构(如 Monzo、Starling、Revolut 和 N26)正在利用数字产品让他们的客户能够更好地访问和控制他们的支出。他们通过提供现代移动应用程序、实时通知、更好的安全性和开发人员 API 来实现这一目标,这些 API 允许任何有想法的人进行分析和产品化。

技术也在其他方面帮助了人类行为。当人们想起一件事或一段记忆时,他们通常指的是它发生的地方。当试图在手机上查找一张照片时,描述照片的拍摄地点往往比日期更容易,例如“我们在西班牙”或“这是在我格林威治的家里”。同样的人类行为也适用于财务决策和支出。一份写着“XDB 商品报 82.00 美元”的声明无助于解释交易背后的故事和决定,让人们感到困惑,拼命想知道这可能是什么。

我对在地图上探索金融交易的表现很感兴趣,这有助于回答关于消费发生在哪里的问题,并引发对所去过的地方的记忆。该地图与其他数据层相结合,还可以用于识别和确定历史消费习惯,寻找新的旅游地点,甚至通过位置识别欺诈和异常交易。

数据大小和范围

在这个实验中,我使用了 Monzo,它提供了一个非常全面的 API 来提取他们平台上的用户信息。收集这些数据需要非常明确的同意来收集和存储数据,因此对于这个练习,我只使用了我自己的数据,尽管可以构建一个可扩展的应用程序,并在其他用户允许的情况下分析他们的数据。

该数据集包含了过去 3 年我个人活期账户上的每一笔交易,记录刚刚超过 5000 条。数据被格式化为 JSON,并被结构化为一个对象数组,每个交易都包含时间戳、便士/美分整数形式的金额、货币、描述、类别、注释、附件(如收据)、元数据、结算信息和商家信息。商家信息包含名称、坐标、地址、Google Places ID、国家和一个近似的标志(在估计商家位置时进行标记)。

初步分析

该数据集提供了一个令人兴奋的机会,可以发现和分析更多关于我的消费习惯,并更好地了解 Monzo API 的功能。我创建了一个 JavaScript 程序来解析交易,并做一些非常基本的主题分类。

在数据集中,我发现大约 1/3 的交易花在外出就餐上,1/3 的交易花在喝咖啡上。咖啡馆代表了超过 400 笔交易,但总的来说消费相对较低,平均每次消费仅超过 3.5 英镑。金额最大的交易是工作支出,最昂贵的个人购买是购物,还有一个极端的异常值,是我去年完成的一个飞行员执照预付费飞行课程的第二高交易金额的近 5 倍。大多数交易发生在伦敦,但它们分布在五大洲,最孤立的交易发生在塔斯马尼亚的霍巴特。

Figure 1: All global transactions weighted by amount

三年间,通过该账户转移的资金总额达到了惊人的 20 万英镑(其中包括业务支出和向其他银行的转账),仅包括个人支出的 9 万英镑。Monzo 不是我唯一的银行,这些数字之间的明显差异说明了使用原始数据得出有意义的结论的复杂性。业务支出不代表个人财务习惯,很容易扭曲形象;为了确保地图的准确性和丰富性,数据需要进行消毒。

初始实验

为了了解使用该数据集的可能性,并了解制图软件 QGIS 可能提供的限制和机会,我从 MapBox 加载了一个底图,并导入了所有 5000 个事务。

软件渲染速度很慢,而且所有的点都是重叠的。即使为每个类别的交易分配不同的颜色,地图也没有用,或者不容易从中得出任何有意义的东西。拥有太多的信息意味着项目重叠,并且没有像我最初希望的那样给出有用的结论。

Figure 2: All transactions layered on a base map with equal weighting

以这种方式呈现事务确实让我发现了数据集有趣的异常值和复杂性,如果不做这个实验,我是不会注意到这些的。网上购物在地理位置上尤其成问题(例如,AWS 显示美国的地理中心)。对于那些谷歌不知道他们的实际地址,而把商家放在国家地理中心的商家来说也是如此。

伦敦的默认中心是特拉法尔加广场,那里没有商店,所以可以肯定地说这些商户的位置是不准确的。

清理数据集

我修改了 JavaScript 应用程序来迭代事务,并执行一些过滤和规范化。首先,任何被归类为费用、账单、财务和存款的交易都将被删除,只留下个人费用。我还删除了商家不存在或没有地理信息的交易。我还重命名了一些键,使数据更容易在中处理,并简化了 JSON 结构,使其更容易转换为 CSV。这就建立了一个文件,其中只包含在实体商家中发生的交易,而不是称为“Monzo Sanitised Transactions”的业务费用。

Figure 3: The node app iterates over the dataset and writes a CSV file containing the location data

为了让数据更容易实验,我还创建了一个仅包含外出就餐交易的数据子集(称为“Monzo 外出就餐”)。这个较小的数据集解决了我在使用 QGIS 时遇到的一些性能问题。

我想使用地图标记的大小参数在可视化中反映交易的价值。我面临的另一个问题是,所有的交易金额大部分都是负数(因为这些代表的是钱从账户中流出的交易)。映射软件 QGIS 需要正整数标度,因此我通过调整清理公式将交易金额乘以-1 来修改金额值。这样做的一个后果是现在退款为负值;为了解决这个问题,我将最小表示值限制为零,确保只显示借记的交易。

Figure 4: Eating out transactions individually represented in Soho, London

我担心使用单个交易不能代表每个商家的合计总额和计数(这在统计上更有意义),也不能消除积分相互叠加的问题。我在 JavaScript 应用程序中创建了一个新功能,根据唯一的商家 id 对数据进行消毒,然后为每个商家创建一个交易总和和计数。

虽然该功能正确地减少了商家 ID 匹配的数据,但这种方法并不完美,因为商家数据是众包的,而且通常同一家商店不会共享相同的 ID。

Figure 5: Eating out transactions in London individually sized by amount

Figure 6: Eating out transactions in London aggregated by merchant and sized by amount

当汇总的数据被导入到地图上时,结果很有趣,因为从单个的可视化中几乎不可能理解或看到差异。极端的购买是非常异常的,很难看出小额消费之间的差异(价值和数量)。即使将转换曲线应用于该数据集,可视化仍然不如单个交易那样引人注目,因此我放弃了这种方法,并专注于其他更有效地可视化信息的方法。

地图图层

我最初使用 MapBox studio 创建了一个定制的基础层,以矢量格式在网络上提供服务。MapBox 是 Google maps 的一个很好的替代品,因为它可以在应用程序开发中使用。使用街道地图进行数据可视化的问题是地图在视觉上非常复杂。有许多颜色和标签分散了上层有趣数据的注意力。

我探索了一些其他地图视觉风格,并从野生动物地图中获得灵感,这些地图使用非常简单的线条和阴影来显示区域边界和重要位置。移除所有用于寻路的图层会对商家位置产生更大的影响,也更容易解释。

对于这些线,我选择了伦敦县的行政区和选区边界。这些形状文件可以在英国政府的开放数据库(data.gov.uk)上方便地获得,该数据库公布了其部门收集的开放数据,并提供了 2018 年边界测量的矢量形状文件。

转换坐标参考系统

使用政府底图时,我立即注意到的一个问题是,数据集不在同一个坐标参考系统中,并且地图本身存在偏差。数据由英国政府使用本地系统[OSGB36]生成,其中 Monzo 使用全球数字标准[WGS84]。我调整了数据层以使用基础层的 CRS。

成品地图

Figure 7: Map created using the sanitised data and base layers

最终的地图将 5 个支出类别分层,并对金额进行标准化,因此标记的大小代表支出的价值。

每个类别都用颜色表示,并且不透明,因此交易越频繁,颜色越丰富。兴趣点(住宅/工作地点)、铁路网络和一些有趣的异常值周围有清晰的聚类。

最大的集群并不令人惊讶,在伦敦市中心,外出就餐有大量的交易层层叠加,根据最初的分析,这大约是总交易数量的 1/3。并非巧合的是,这三个绿色集群都在我工作过的三个地方(肖尔迪奇、法灵顿和苏荷区)附近。很容易得出结论,我在工作地点附近和城市里的外出就餐上花了很多钱。

该图还显示了许多没有任何事务的空白区域。它显示了在过去的 3 年里我在伦敦西部度过的时间有多少,这可能是一个在那个地区尝试更多餐馆和商店的好机会。将这些信息与一个热门名单结合起来,可能是探索和核对伦敦和世界各地的好方法。

这种可视化也可能是抑制消费习惯的一种好方法,方法是随着时间的推移跟踪这些类别,并将目标游戏化,以取代用杂货外出就餐或减少总数来帮助省钱。

进一步发展

以这种方式向最终用户呈现商家数据可能是 Monzo 或 Google 验证商家位置并进一步众包关于商家正确定位的反馈的好方法。我有一个假设,人们思考他们在哪里/他们在哪里支付了一些东西,以这种方式呈现交易允许在人们质疑交易的地方询问离群值。它甚至可以帮助发现欺诈性交易,或通过提供交易发生地的急需上下文来减少假标记的欺诈。

我在我的数据集中发现了土耳其的一笔交易,我从未去过这个国家,但有一家在线商家在那里注册。我还在伦敦北部看到咖啡异常高的交易量,我很少去那里,但那里是商人总部所在地。这些例子表明,熟悉自己习惯的人可以如何对数据集做出贡献,并帮助创建更丰富、更准确的商家位置表示。

企业和政府可以从了解这些类别的位置中受益匪浅,以帮助提供信息:议会分区、企业价格设定/调整、瞄准“高流量”街道或路线、帮助个人管理他们的支出,甚至作为一种产品来帮助找到受欢迎的餐馆、景点或便利设施附近的住房。

事实证明,这项任务令人难以置信地发人深省,并开启了一种思考行为支出的新方式。在未来的版本中,我有兴趣在更大的用户群中继续这个实验,来比较人们之间的花费。探索其他参数(如一周中的某一天)如何影响消费者支出的变化和模式也是很有趣的。

Eating out locations by amount (pink) and frequency (blue)

版权和来源

英国政府,“国家统计”,开放数据[data.gov.uk],2018 年

包含国家统计数据官方版权和数据库权利[2015]和包含地形测量数据官方版权和数据库权利[2015]

Monzo,“开发者 API”,开发者文档[api.monzo.com],2019

MapBox,“工作室和地图 API”,[mapbox.com],2019 年

图形和印刷品使用来自 Mapbox 和 OpenStreetMap 及其数据源的地图数据。要了解更多,请访问 https://www.mapbox.com/about/maps/的和 http://www.openstreetmap.org/copyright

帕克,交易数据,2019

使用真实世界的复杂网络可视化墨卡托图布局/嵌入。

原文:https://towardsdatascience.com/visualising-the-mercator-graph-layout-embeddings-using-a-real-world-complex-network-bf065c316b7a?source=collection_archive---------29-----------------------

A network of the Master Chemical Mechanism

制图领域长期以来一直使用投影将高维数据(即地球,扁球体)转换成平面表示。

在最近的一篇论文“ 墨卡托:揭示复杂网络的忠实双曲线嵌入(2019) ”中,采用了将球形地球转换为圆柱形表示的相同数学方法,能够将恒定方位角映射为线性段,并应用它来产生无向和未加权网络内的节点嵌入。

我们的数据

我感兴趣的复杂网络是 2019 年北京空气质量活动中对流层(低层空气)化学的近显式表示。当使用传统的力定向或静电图形算法作图时,我们看到高度连接的物质形成了“毛团”。许多真实世界的图表就是这种情况。

Plotting the network using the Force Atlas algorithm.

应用墨卡托图布局

为了应用图表布局,我们使用https://github.com/networkgeometry/mercator提供的代码。这读入我们网络的边列表,并返回我们计算嵌入的极坐标。在绘制这些图时,我们得到了下图。

Plotted output of the Mercator embedding.

将输出转换成 JSON 文件

因为我们的绘图将在 Javascript 中完成,所以我们将嵌入输出转换成 JSON 格式,可以由可视化软件读取。

'''
To plot run python plot.py <filename>
This reads <filename>.edges and <filename>.inf_coord
'''import sys,json
import pandas as pd
name = sys.argv[1]edge= pd.read_csv(name+'.edge',comment='#',header=None,sep='\s+',index_col= None)[[0,1]]
edge.columns = 'source target'.split()df = pd.read_csv(name+'.inf_coord',comment='#',header=None,sep='\s+',index_col=0)
df.columns = 'k theta r'.split()save = {}
save['nodes'] = df.T.to_dict()
save['edges'] = edge.T.to_dict()json.dump(save,open(name+'.json','w'))

使用 D3.js 绘图

如果你对 Javascript 或 D3 不熟悉,我推荐你看看www.observablehq.com。这有许多关于如何制作图像和在图像中放置元素的例子。

对于那些能够分配点数的人,我们首先用d3.json('../data.json', data => {...})读入我们的数据,然后设置一个横跨半个页面的径向标尺:

size = Math.min(width,height)var r = d3.scaleLinear().domain(d3.extent(d3.values(data.nodes).map(d=>d.r))).range([0,size/2])

接下来,我们使用sinecosine函数将极坐标从墨卡托输出转换成笛卡尔坐标。

node_data = {};
    d3.entries(data.nodes).forEach(d => {node_data[d.key] = {'x': r(d.value.r) * Math.cos(d.value.theta),
        'y':r(d.value.r) * Math.sin(d.value.theta)
      }});

最后,编写我们希望用来绘制节点的脚本

svg.selectAll(".node")
      .data(d3.values(data.nodes))
      .enter()
      .append("circle")
      .attr("r", 2)
      .attr('cx', d=> d.y)
      .attr('cy', d=> d.x)
      .style("fill", "steelblue")
      .style("opacity", 0.6)
      .attr('transform',`translate(${size/2},${size/2})`)

边缘捆绑

边捆绑是一种用于简化图中的边的技术。这里,边缘被模拟为柔性弹簧,如果满足一定的几何兼容性标准,它们会相互吸引。这通常用于减少可视化中链接的混乱。欲了解更多信息,请阅读

我们首先从D3-forcegebundling . js下载相关的库文件,并将其放入当前目录。从这里,我们可以使用脚本标签将它导入到我们的程序中:

<script type="text/javascript" src="d3-ForceEdgeBundling.js"></script>

我们现在可以引入边缘捆绑功能:

var fbundling = d3
      .ForceEdgeBundling()
      .step_size(.2)
      .compatibility_threshold(.70)
      .nodes(node_data)
      .edges(data.edges);const results = fbundling();

然后,我们遍历每个返回的边,并将其添加到我们的图像中:

var d3line = d3
      .line()
      .x(function(d) {
        return d['x'] ;
      })
      .y(function(d) {
        return d['y'];
      })
      .curve(d3.curveLinear);results.forEach(function(edge_subpoint_data,i) { svg
        .append("path")
        .attr("d", d3line(edge_subpoint_data,i))
        .style("stroke", "#222")
        .style("fill", "none")
        .style("stroke-width",0.25)
        .style("stroke-opacity", .39)
        .attr('transform',`translate(${size/2},${size/2})`)});

调整兼容性阈值

最后,我们可以调整兼容性阈值来改变不同边相互吸引的程度。这将把上面的线性图转换成下列之一。

钦佩结果

这就是我们的数据集的墨卡托图嵌入的边捆绑表示。

注意:所有图像都受版权保护。如果在任何地方使用,请引用“丹尼尔·埃利斯 2019”。

从 Python 可视化开始— Matplotlib

原文:https://towardsdatascience.com/visualization-in-python-matplotlib-c5c2aa2620a?source=collection_archive---------17-----------------------

对任何数据科学家或分析师来说,可视化数据都是一项重要的技能。这可以更好地了解数据的样子,允许检测模式或异常值的存在等。此外,它还是传达信息的一个有用工具,因为一个好的视觉效果可以很容易地告诉你很多文字不能告诉你的东西。古语有云,“一图胜千言”。这在数据科学/分析领域尤为重要。考虑到这一点,我写了这篇文章,通过 matplotlib 库向用户介绍 python 可视化的基础知识。

Photo by Luke Chesser on Unsplash

一幅画胜过千言万语

一如既往,第一步是导入所有需要的库。

import matplotlib.pyplot as plt
import numpy as np
from random import sample
%matplotlib inline

让我们为绘图练习生成一些数据,并绘制一个简单的线图。

x = np.linspace(0,10,20)#Generate 20 points between 0 and 10
y = x**2 # Create y as X squared
plt.plot(x,y) # Plot the above data

Figure 1

绘制上图只需要一行命令。虽然它很简单,但这并不意味着我们没有定制它的选项。

plt.plot(x, y, color='green', linestyle='--',
linewidth=2, alpha= 0.5)

Figure 2

在绘图命令控件内传递的参数用于:

颜色表示线条的颜色,甚至可以作为 RGB 十六进制代码给出

线条样式‘是你想要线条的样子,可以是’—‘或’—’对于虚线

线宽取整数输入表示线条的粗细

alpha 控制线条的透明度

有时一行可能还不够,您甚至需要指出哪些是确切的数据点,在这种情况下,您可以添加标记

plt.plot(x, y, marker = 'o', markerfacecolor = 'red', markersize = 5)

Fig 3

这块地有红色的圆形标记。这些标记可以通过修改它们的边界来进一步定制。

plt.plot(x, y, marker = 'o', markerfacecolor = 'red', markersize = 10, markeredgewidth = 2, markeredgecolor = 'black')

Fig 4

标记和以前一样,但现在它们有一个黑色的边界。

控制标记的参数有:

标记'表示您希望标记是什么形状,可以是' o '、' * '或'+'

标记面颜色表示标记的颜色

标记大小类似于线宽控制标记的大小

marked gewidth和’marked gecolor分别用于指定边界的粗细和颜色。

让我们将以上所有内容结合到一个图中:

Figure 5

不是最漂亮的情节,但你得到的想法。

虽然这涵盖了绘制数据的基础,但在标题、轴范围、图例等方面还有很多工作要做。

最简单的方法是使用 Matplotlib 的面向对象方法。

面向对象的方法

Matplotlib 有一个面向对象的 API,允许你创建图形和轴对象。然后可以有序地调用这些对象来执行诸如绘制数据或定制图形之类的功能。

fig, ax = plt.subplots()

Fig 6

上述命令返回图形和轴对象,并创建一个空图。

然后,这可用于重新创建上面的图,带有图和轴标题以及图例。

fig, ax = plt.subplots()#Create the objects
ax.plot(x,y,label = 'X squared')#The data to be plotted and legend
ax.set_title('Plot 1')#Plot title
ax.set_xlabel('X')#X axis title
ax.set_ylabel('Y')#Y axis title
ax.set_xlim(0,10)#Range of X axis
ax.set_ylim(0,110)#Range of Y axis
plt.legend()#Command to display the legend

Fig 7

上面的图(图 7)具有轴和图标题、图例以及 X 轴和 Y 轴的不同范围。

绘制多条线

假设你想比较两组不同的数据,例如,在同一个图中绘制多条线。在这种情况下,您只需要再添加一个 plot 命令。

fig, ax = plt.subplots()#Create the objects
ax.plot(x,y,label = 'X squared')#The data to be plotted and legend
ax.plot(x,x**3,label = 'X cubed')#The data to be plotted and legend
ax.set_title('Plot 1')#Plot title
ax.set_xlabel('X')#X axis title
ax.set_ylabel('Y')#Y axis title
ax.set_xlim(0,10)#Range of X axis
ax.set_ylim(0,110)#Range of Y axis
plt.legend()#Command to display the legend

Fig 8

另一种比较方法是并排显示两个不同的图。

fig, ax = plt.subplots(1,2)#Create the objects
ax[0].plot(x,y,label = 'X squared')#The data to be plotted and legend
ax[1].plot(x,x**3,label = 'X cubed')#The data to be plotted and legend
ax[0].set_title('Plot 1')#Plot title
ax[1].set_title('Plot 2')#Plot title
ax[0].legend()#Command to display the legend for plot 1
ax[1].legend()#Command to display the legend for plot 2
plt.tight_layout()#To ensure no overlap

Fig 9

这是通过首先在“subplot()”函数中传递绘图的数量来完成的。上面的(1,2)意味着应该有 1 行地块和 2 列地块,实际上意味着 2 个地块。对每一个图重复这些函数,并且‘tight _ layout()’命令确保没有重叠。这里的一个小变化是显示图例的命令。plot.legend()函数只显示一个图的图例,要同时显示两个图,需要为每个图指定图例。

第三种比较方法是使用插图。在一个更大的情节里,有一个更小的情节。

fig, ax = plt.subplots(figsize = (12,4))
axins = ax.inset_axes([0.1,0.6,0.4,0.3] )#Left, Bottom, Width, Heightax.plot(x,y,label='X squared')# Main plot
axins.plot(x,1/x,label='X inverse')# Inset plotax.set_xlabel('X')#X axis title
ax.set_ylabel('Y')#Y axis title
axins.set_xlabel('X')#X axis title
axins.set_ylabel('Y')#Y axis titleax.set_title('Main Plot')#Main plot title
axins.set_title('Inset Plot')# Inset plot title
ax.legend()#Legend for main plot
axins.legend()#Legend for inset plot

Fig 10

“subplots()”函数中的“figsize”参数允许更改图形的大小。“插入轴”功能用于创建插入图,同时指定位置和大小。前两个数字以百分比的形式指定绘图位置。在上面的例子中,前两个数字 0.1 和 0.6 指定绘图应该分别在 Y 轴和 X 轴的左侧 10%和上方 60%。最后两个数字 0.4 和 0.3 指定绘图应为主绘图宽度和高度的 40%和 30%。

您可能已经注意到主图的图例与插图重叠。虽然 matplotlib 会自动选择图例的最佳位置,但也可以使用“loc”参数手动移动。

fig, ax = plt.subplots(figsize = (12,4))
axins = ax.inset_axes([0.1,0.6,0.4,0.3] )#Left, Bottom, Width, Heightax.plot(x,y,label='X squared')
axins.plot(x,1/x,label='X inverse')ax.set_xlabel('X')#X axis title
ax.set_ylabel('Y')#Y axis title
axins.set_xlabel('X')#X axis title
axins.set_ylabel('Y')#Y axis titleax.set_title('Main Plot')
axins.set_title('Inset Plot')
ax.legend(loc = 4)
axins.legend()

Fig 11

“loc”参数接受 0 到 10 之间的输入,对应于图中的位置。0 表示 Matplotlib 将选择可能的最佳位置,这是默认选项,所有其他整数对应于绘图中的一个位置。在这里,我将“4”传递给“loc”参数,这意味着图例位于右下角。

我将介绍的最后一个定制是改变剧情背景。

fig, ax = plt.subplots(figsize = (12,4))
axins = ax.inset_axes([0.1,0.6,0.4,0.3] )#Left, Bottom, Width, Heightax.plot(x,y,label='X squared')
axins.plot(x,1/x,label='X inverse')ax.set_xlabel('X')#X axis title
ax.set_ylabel('Y')#Y axis title
ax.grid(True)#Show grid
axins.set_xlabel('X')#X axis title
axins.set_ylabel('Y')#Y axis title
axins.grid(color='blue', alpha=0.3, linestyle='--', linewidth=2)#Grid modificationsax.set_title('Main Plot')
axins.set_title('Inset Plot')
ax.legend(loc = 4)
axins.legend()

Fig 12

这里的主图有默认的网格,只需调用 grid()函数就可以创建它。

网格线也可以像地块线一样进行修改。这些修改可以在插图中看到。与主图相比,图中的网格线具有不同的颜色、样式和宽度。

特殊情节

除了简单的线图,matplotlib 还可以创建许多不同类型的图。

散点图:

fig, ax = plt.subplots()
ax.scatter(x,y,label='X squared')
ax.set_xlabel('X')#X axis title
ax.set_ylabel('Y')#Y axis title
ax.set_title('Plot')
ax.legend()

Fig 13

直方图:

x = sample(range(1,100), 60)
fig, ax = plt.subplots()
ax.hist(x)
ax.set_title('Histogram')

Fig 14

柱状图

x = np.linspace(0,10,11)
y = x**2
fig, ax = plt.subplots()
ax.bar(x, y)
ax.set_title('Bar plot')

Fig 15

这涵盖了 matplotlib 可用的一些基本绘图和自定义。虽然 matplotlib 有高级绘图和统计绘图的选项,但最好使用 Seaborn 来实现。

Seaborn 是一个基于 matplotlib 构建的统计数据可视化库。我将在以后的文章中介绍它,在这里学到的基础知识也将有助于在 Seaborn 建造地块。

你也可以在 LinkedIn 上与我联系

使用 Matplotlib 实现数据可视化

原文:https://towardsdatascience.com/visualization-library-in-python-matplotlib-470a2e631d73?source=collection_archive---------35-----------------------

在我之前的故事中,我已经描述了 python 中两个最重要的 Python 库: Numpy 和 Pandas 。今天我将讲述 Matplotlib,它是 python 中最流行和最广泛使用的可视化库。不再耽搁,我们开始吧。

[Matplotlib](https://www.numpy.org)是一个 Python 2D 绘图库,它以多种硬拷贝格式和跨平台的交互环境生成出版物质量数字。这是一个流行的 python 绘图库,可以让您控制图形的各个方面。它被设计成有一种类似于MATLAB图形绘制的感觉。它可以提供大量的优势,如简单的绘图容易开始,支持自定义标签和文本,对图形中每个元素的良好控制,多种格式的高质量输出,非常可定制等。

要在您的系统中安装Matplotlib库并进一步了解 python 基础知识,您可以点击以下链接:

[## 机器学习和数据分析—仁荷大学(第一部分)

第 1 章:基本 python 和安装

towardsdatascience.com](/machine-learning-and-data-analysis-inha-university-part-1-be288b619fb5)

现在要在程序中使用Matplotlib,我们需要导入模块。为了方便起见,一般将Matplotlib包定义为plt的缩写。但是您可以使用任何想要的东西来导入它。

**import matplotlib.pyplot as plt** # importing matplotlib**x=pd.Series([1,2,3,4])** # create pandas series **y=2*x+3** # define y **plt.plot(y)** # Functional plot **plt.show()** # show plot

输出:

当使用 Jupyter 笔记本作为模拟环境时,我们需要在命令行中提到%matplotlib inline,它允许查看 Jupyter 笔记本内部的情节。

**import matplotlib.pyplot as plt** # importing matplotlib
**import numpy as np  **              # importing numpy
**%matplotlib inline** # see plot in Jupyter notebook
**x=np.arange(0,10,0.5)** # define x **y1=2*x+3** # define y1 **y2=3*x** # define y2 **plt.figure(1,figsize=(12,12))** # create a figure object
**plt.subplot(331)** # divide the figure 3*3, 1st item
**plt.plot(x,y1,'r-')** # Functional plot
**plt.title('Line graph')** # define title of the plot
**plt.subplot(332)**                  # divide the figure 3*3, 2nd item
**plt.plot([1,3,2,7],[10,20,30,40])** # Functional plot
**plt.title('Two-dimensional data')** # define title of the plot
**plt.subplot(333)** # divide the figure 3*3, 3rd item
**plt.plot([10,20,30,40],[2,6,8,12], label='price')** # set label name
**plt.axis([15,35,3,10])** # axis scale - x:15-35, y:3-10
**plt.legend()** # show legends on plot
**plt.title('Axis scaled graph')** # define title of the plot
**plt.subplot(334)** # divide the figure 3*3, 4th item
**plt.plot(x,y1,'r-',x,y2,'b--')**    # y1 - red line, y2 - blue line
**plt.title('Multi line plot')** # define title of the plot
**plt.subplot(335)**                  # divide the figure 3*3, 5th item
**x=np.random.normal(5,3,1000)**      # normal distribution - mean: 5, variance: 3, number of data: 1000
**y=np.random.normal(5,3,1000)**      # normal distribution - mean: 5, variance: 3, number of data: 1000
**plt.scatter(x,y,c='k')** # Functional plot
**plt.title('Scatter plot')**
**plt.subplot(336)**                  # divide the figure 3*3, 6th item
**player=('Ronaldo','Messi','Son')**
**goal=[51,48,25]**
**plt.bar(player,goal,align='center',color='red',width=0.5)** 
**plt.title('Bar plot')** # define title of the plot **plt.show()** # show plot

Matplotlib 中的 3D 绘图

为了启动 matplotlib 中的 3D 绘图,我们需要从mpl_toolkits.mplot3d导入Axes3D

**import numpy as np** # importing numpy **import matplotlib.pyplot as plt** # importing matplotlib **from mpl_toolkits.mplot3d import Axes3D** # importing Axes3D, 3d plot **fig = plt.figure()** # create a figure object **ax = Axes3D(fig)** # defining 3d figure ax **X = np.arange(-4, 4, 0.25)** # defining X **Y = np.arange(-4, 4, 0.25)** # defining Y **X, Y = np.meshgrid(X, Y)    
R = np.sqrt(X ** 2 + Y ** 2)
Z = np.sin(R)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=plt.cm.hot)**#plot **ax.contourf(X, Y, Z, zdir='z', offset=-2, cmap=plt.cm.hot)
ax.set_zlim(-2, 2)** # set z-axes limit **plt.show()**

输出:

当使用 matplotlib 执行子情节时,我们需要为每个情节保持紧凑的布局,以避免图形之间的混乱。我们可以保持正方形图形尺寸来避免这个问题,或者我们可以使用tight_layout()

**fig,ax = plt.subplots(nrows=3,ncols=3)
plt.tight_layout()
plt.show()**

输出:

在 Matplotlib 中保存图形

Matplotlib 可以生成 PNG、JPG、EPS、SVG、PGF、PDF 格式的高质量图形,我们可以用 matplotlib 保存图形。我们还可以将图形保存在我们想要的文件位置。我们可以按照下面的例子,图保存在一个目标文件位置。

**import matplotlib.pyplot as plt** # importing matplotlib **%matplotlib inline** # see plot in Jupyter notebook **x = [0, 2, 4, 6]** # define x **y = [1, 3, 4, 8]** # define y **plt.plot(x,y)** # functional plot **plt.xlabel('x values')** # define x label **plt.ylabel('y values')** # define y label **plt.title('plotted x and y values')** # define title **plt.legend(['line 1'])** # define legend# save the figure **plt.savefig('plot.png', dpi=300, bbox_inches='tight')
fig.savefig('E:\Bioinformatics/foo.png')****plt.show()**

输出:

为了保存其他格式的数字,我们需要用它来代替png。如果你正在使用 jupyter 笔记本,并且想要将任何图形保存到另一个想要的文件夹中,那么你可以遵循命令fig.savefig("E:\Bioinformatics/foo.png",其中 foo 是图形的名称。

图例

为了在 Matplotlib 中提到图例,我们可以使用ax.legend(),其中 ax 是图形的名称。我们还可以在ax.plot()中定义标签的名称。为了更好的理解,我们可以看下面的例子。

**import matplotlib.pyplot as plt** # importing matplotlib **%matplotlib inline** # see plot in Jupyter notebook **x = np.array([0, 2, 4, 6])** # define x **fig = plt.figure()** # create a figure object **ax = fig.add_axes([0,0,1,1])** # axes with (L,B,W,H) value **ax.plot(x, x**2, label = 'X2', color='red')** # functional plot **ax.plot(x, x**3, label = 'X3', color='black')** # functional plot **ax.set_xlim([0, 5])** # set x-axes limit **ax.set_ylim([0,100])** # set y-axes limit **ax.legend()** #show legend **plt.show()** # show plot

输出:

我们可以估计传说的位置。ax.legend(loc=0)为传说中的最佳位置,loc=10为中心位置。我们也可以定义位置。十六进制代码也可用于定义图中的color。我们还可以使用set_xlim([0,5])set_ylim([0,100])设置 x 轴和 y 轴的极限,其中提到了极限的下限和上限。

非常感谢你的时间。你可以关注我的其他教程简介。我已经发表了机器学习和数据分析系列的 4 个部分,这是基于 Inha 大学提供的研究生课程。你可以按照Part-1Part-2Part-3,** Part-4 来获得用 Python 进行机器学习移动的起始思路。非常感谢任何建议或批评。**

Part-1:python 基础及安装
Part-2
:第二章:Python 数据结构—数据类型
Part-3
:Python 中的控制语句(循环)
Part:4
:Python 函数【T39

参考链接:

  1. ****Matplotlib cheet sheet:https://S3 . amazonaws . com/assets . data camp . com/blog _ assets/Python _ Matplotlib _ Cheat _ sheet . pdf
  2. ****教程:https://www . tutorialspoint . com/matplotlib/matplotlib _ Tutorial . pdf

3.http://courses . csail . MIT . edu/6.867/wiki/images/3/3f/Plot-python . pdf

4.https://riptutorial.com/Download/matplotlib.pdf

来自原始 Twitter 数据的信息可视化——第 1 部分

原文:https://towardsdatascience.com/visualization-of-information-from-raw-twitter-data-part-1-99181ad19c?source=collection_archive---------4-----------------------

让我们探索一下我们可以从原始 Twitter 数据中轻松检索到什么样的信息!

大家好!在之前的文章中,我们探讨了如何使用 Python 和两个 Twitter APIs 高效地下载数据:下载实时生成的推文的流 API ,以及下载用户时间线和关注者等历史信息的 REST API

这篇文章是两篇文章中的第一篇,将致力于从使用 Twitter 流媒体 API 下载的数据中提取酷的可视化和信息,没有任何类型的机器学习或任何其他复杂的算法。

放松放松,让我们开始吧!

1.收集数据:

首先,我们需要收集我们想要可视化信息的数据。我们将使用流 API 来收集关于某个主题的 tweets,这可以通过使用 stream 对象的 filter 参数来查询特定的 hashtags 来完成。

如果您对此不熟悉,我建议您看看我关于如何使用流式 API 下载数据的帖子:

[## 使用流式 API 从 Twitter 下载数据

在这篇文章中,我们将介绍如何使用流媒体 API 来获取包含特定单词或标签的推文,以及如何…

medium.com](https://medium.com/@jaimezornoza/downloading-data-from-twitter-using-the-streaming-api-3ac6766ba96c)

基本上,在 tweet 下载脚本中类似这样的行上面

l = StdOutListener()    auth = OAuthHandler(consumer_key, consumer_secret)    auth.set_access_token(access_token, access_token_secret)    stream = Stream(auth, l)    stream.filter(track=tracklist)

包括以下代码行:

tracklist = ['#HASHTAG1', '#HASHTAG2', '#HASHTAG3']

并将 #HASHTAG1、#HASHTAG2 和#HASHTAG3 的值更改为与您想要收集数据的主题相关的 HASHTAG。这个列表中可以包含或多或少的标签。

一旦脚本准备好了,就运行它,并以这种方式将其输出传输到一个. txt 文件,就像前面提到的帖子中描述的那样:

Twitter _ downloader . py>Twitter _ data . txt

让它运行一段时间,或者设置最大数量的推文,就这样,你的数据准备好被分析了!

2.准备数据:

现在我们的数据已经准备好了,让我们看看我们可以从中获得什么样的见解!为了这篇文章,我下载了大约两天的关于英国退出欧盟的推文,在 API 中查询带有英国退出欧盟相关标签的推文,如英国退出欧盟、英国退出欧盟、人民投票或游行。

打开 Jupyter 笔记本,开始编码:

首先,像往常一样,我们需要导入分析和可视化所需的库:

#Import all the needed libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import json
import seaborn as sns
import re
import collections
from wordcloud import WordCloud

然后,我们将读取我们收集的数据并对其进行处理。请记住,流式 API 的输出是每个 tweet 的 JSON 对象,其中有许多字段可以提供非常有用的信息。在下面的代码块中,我们从。txt 文件,它们存储在:

#Reading the raw data collected from the Twitter Streaming API using #Tweepy. 
tweets_data = []
tweets_data_path = 'Brexit_tweets_1.txt'
tweets_file = open(tweets_data_path, "r")
for line in tweets_file:
    try:
        tweet = json.loads(line)
        tweets_data.append(tweet)
    except:
        continue

为此,您必须将字符串 tweets_data_path 更改为存储数据的文档的名称。我还建议你在存储下载的 tweets 的同一个文件夹中创建笔记本,这样你在加载数据时就不必考虑任何相对路径。

下载数据时,可能会出现连接问题或其他类型的错误,所以在。在我们存储推文的地方,可能有一些行应该是推文,但却是错误代码。要消除它们,请在阅读完。txt 文件。

#Error codes from the Twitter API can be inside the .txt document, #take them off
tweets_data = [x for x in tweets_data if not isinstance(x, int)]

现在,让我们看看我们收集了多少条推文:

print("The total number of Tweets is:",len(tweets_data))

以我为例,我下载了133030推文。

好了,现在我们已经读了。txt 文件,并在笔记本中准备好 JSON 格式的 tweets,我们将实现一些函数来将这些 JSON 对象的一些参数映射到 Pandas dataframe 的列,从现在开始,我们将在那里存储 tweets

首先,我们将创建一个函数,允许我们查看选择的 tweet 是否是一个 retweet 。这是在中通过评估 JSON 对象是否包含名为'retweed status '的字段来完成的。如果推文是转发,这个函数返回一个布尔值 True,否则返回 False。

#Create a function to see if the tweet is a retweetdef is_RT(tweet):
    if 'retweeted_status' not in tweet:
        return False      
    else:
        return True

现在,我们将做一些类似的事情来评估下载的推文是否是对其他用户的推文的回复。同样,这是通过检查 JSON 对象中是否缺少某些字段来完成的。我们将使用“in _ reply _ to _ screen _ name”字段,这样除了查看推文是否是响应之外,我们还可以查看推文正在响应哪个用户。

#Create a function to see if the tweet is a reply to a tweet of #another user, if so return said user. def is_Reply_to(tweet):
    if 'in_reply_to_screen_name' not in tweet:
        return False      
    else:
        return tweet['in_reply_to_screen_name']

最后,tweet JSON 对象包括一个' source '字段,它是发布 tweet 的设备或应用程序的一种标识符。Twitter 没有提供如何将这个源字段映射到实际设备的详细指南,所以我手动列出了我认为源信息可以映射到的列表。

#Create function for taking the most used Tweet sources off the #source column def reckondevice(tweet):
    if 'iPhone' in tweet['source'] or ('iOS' in tweet['source']):
        return 'iPhone'
    elif 'Android' in tweet['source']:
        return 'Android'
    elif 'Mobile' in tweet['source'] or ('App' in tweet['source']):
        return 'Mobile device'
    elif 'Mac' in tweet['source']:
        return 'Mac'
    elif 'Windows' in tweet['source']:
        return 'Windows'
    elif 'Bot' in tweet['source']:
        return 'Bot'
    elif 'Web' in tweet['source']:
        return 'Web'
    elif 'Instagram' in tweet['source']:
        return 'Instagram'
    elif 'Blackberry' in tweet['source']:
        return 'Blackberry'
    elif 'iPad' in tweet['source']:
        return 'iPad'
    elif 'Foursquare' in tweet['source']:
        return 'Foursquare'
    else:
        return '-'

好吧!创建完所有这些函数后,我们就可以将我们的 tweets 传递到一个数据帧中,以便于处理。请注意,从 JSON 对象中提取的 dataframe 的一些列不需要定制函数,因为我们只是从 JSON 中获取这些列的原始数据。然而,数据框架的一些列确实需要一些进一步的解释。

dataframe 的' text '列要么用 JSON 对象的普通' text 字段填充,要么用' extended_tweet' 全文填充。这样做是因为有些 tweets 的文本长度在 140 到 280 个字符之间,对于它们来说,JSON 对象的' text '字段并不包含全部文本。

#Convert the Tweet JSON data to a pandas Dataframe, and take the #desired fields from the JSON. More could be added if needed.tweets = pd.DataFrame()
tweets['text'] = list(map(lambda tweet: tweet['text'] if 'extended_tweet' not in tweet else tweet['extended_tweet']['full_text'], tweets_data))
tweets['Username'] = list(map(lambda tweet: tweet['user']['screen_name'], tweets_data))
tweets['Timestamp'] = list(map(lambda tweet: tweet['created_at'], tweets_data))
tweets['lenght'] = list(map(lambda tweet: len(tweet['text']) if'extended_tweet' not in tweet else len(tweet['extended_tweet']['full_text']) , tweets_data))
tweets['location'] = list(map(lambda tweet: tweet['user']['location'], tweets_data))
tweets['device'] = list(map(reckondevice, tweets_data))
tweets['RT'] = list(map(is_RT, tweets_data))
tweets['Reply'] = list(map(is_Reply_to, tweets_data))

dataframe 的‘Username’列描述了发布推文的用户,所有其他列都是不言自明的。

如果我们看一下数据帧的头部,它应该是这样的:

tweets.head()

厉害!我们的数据框架已经建立,我们已经准备好探索数据了!

3.数据分析和可视化

首先,我们将探索可以使用流式 API 检索的不同 tweet 类别。让我们看看有多少条转发转发例如:

#See the percentage of tweets from the initial set that are #retweets:RT_tweets = tweets[tweets['RT'] == True]
print(f"The percentage of retweets is {round(len(RT_tweets)/len(tweets)*100)}% of all the tweets")

对我来说转发量占所有推文的 73%

这提供了一些关于 Twitter 如何工作的有趣信息:大多数用户不发布自己的内容,而是转发其他用户的内容。

如果我们获取 RT_tweets 数据帧并打印其头部,我们会得到如下结果:

RT_tweets.head()

从这个数据帧中,我们可以看到当推文转发时,流媒体 API 返回的推文的文本结构。这种格式如下:

" RT @InitialTweetingUser: Tweet 文本"

其中开头的 RT 表示该 tweetretweet@InitialtweetingUser 为发布原始 tweet 的账户的 Twitter 用户名,Tweet Text 为所述初始 Tweet 的文本。

通过我们创建的回复栏,我们还可以看到从流媒体 API 下载的条推文中有多少条是对另一个用户的条推文的回复:

#See the percentage of tweets from the initial set that are replies #to tweets of another user:Reply_tweets = tweets[tweets['Reply'].apply(type) == str]
print(f"The percentage of retweets is {round(len(Reply_tweets)/len(tweets)*100)}% of all the tweets")

对我来说,回复的百分比大约是所有推文的 7%。

同样,如果我们看一下这个 Reply_tweets 数据帧,我们可以看到流式 API 返回的回复的结构:

正如我们所看到的,这些回复具有以下格式:

" @InitialTweetingUser 回复文本"

其中 @InitialTweetingUser 是发布被回复推文的用户,回复文本是回复。

现在让我们看看有提及但没有被转发的推文的百分比。请注意,这些推文包括了之前的回复推文。

#See the percentage of tweets from the initial set that have #mentions and are not retweets:mention_tweets = tweets[~tweets['text'].str.contains("RT")  & tweets['text'].str.contains("@")]
print(f"The percentage of retweets is {round(len(mention_tweets)/len(tweets)*100)}% of all the tweets")

对我来说,这占了全部推文的 11%。带有提及但未回复或转发的推文只是在文本中间某处包含所述提及的推文,例如:

“我们的工作假设仍然是英国将在 3 月 29 日离开”,英国退出欧盟的@EU_Commission spox 说。动词“remain”用得好。

最后,让我们看看有多少推文只是纯文本推文,没有提及或转发:

#See how many tweets inside are plain text tweets (No RT or mention)plain_text_tweets = tweets[~tweets['text'].str.contains("@")  & ~tweets['text'].str.contains("RT")]
print(f"The percentage of retweets is {round(len(plain_text_tweets)/len(tweets)*100)}% of all the tweets")

对我来说,这是所有推文 的 15%左右。

让我们将所有这些类别绘制成图表,以便更好地比较它们的比例:

#Now we will plot all the different categories. Note that the reply #tweets are inside the mention tweetslen_list = [ len(tweets), len(RT_tweets),len(mention_tweets), len(Reply_tweets), len(plain_text_tweets)]
item_list = ['All Tweets','Retweets', 'Mentions', 'Replies', 'Plain text tweets']
plt.figure(figsize=(15,8))
sns.set(style="darkgrid")
plt.title('Tweet categories', fontsize = 20)
plt.xlabel('Type of tweet')
plt.ylabel('Number of tweets')
sns.barplot(x = item_list, y = len_list,  edgecolor = 'black', linewidth=1)

plt.show()

厉害!让我们来看看哪些是最常用的标签和最常被提及的用户:

#To see the most used hashtags.hashtags = []
hashtag_pattern = re.compile(r"#[a-zA-Z]+")
hashtag_matches = list(tweets['text'].apply(hashtag_pattern.findall))hashtag_dict = {}
for match in hashtag_matches:
    for singlematch in match:
        if singlematch not in hashtag_dict.keys():
            hashtag_dict[singlematch] = 1
        else:
            hashtag_dict[singlematch] = hashtag_dict[singlematch]+1

为此,我们将使用正则表达式(包含在 Python 库 re 中)创建一个模式来检测文本中的标签。然后,我们将创建一个包含所有找到的 hashtag 的字典,其中键是 hashtag 文本,值是 hash tag 被发布的次数。

#Making a list of the most used hashtags and their valueshashtag_ordered_list =sorted(hashtag_dict.items(), key=lambda x:x[1])
hashtag_ordered_list = hashtag_ordered_list[::-1]#Separating the hashtags and their values into two different lists
hashtag_ordered_values = []
hashtag_ordered_keys = []
#Pick the 20 most used hashtags to plot
for item in hashtag_ordered_list[0:20]:
    hashtag_ordered_keys.append(item[0])
    hashtag_ordered_values.append(item[1])

之后,我们将根据值对字典进行排序,并将值和标签分成两个不同的列表。通过这样做,我们现在可以绘制出 20 个最常用的标签,以及它们出现的次数:

#Plotting a graph with the most used hashtagsfig, ax = plt.subplots(figsize = (12,12))
y_pos = np.arange(len(hashtag_ordered_keys))
ax.barh(y_pos ,list(hashtag_ordered_values)[::-1], align='center', color = 'green', edgecolor = 'black', linewidth=1)
ax.set_yticks(y_pos)
ax.set_yticklabels(list(hashtag_ordered_keys)[::-1])
ax.set_xlabel("Nº of appereances")
ax.set_title("Most used #hashtags", fontsize = 20)
plt.tight_layout(pad=3)
plt.show()

从该图中可以清楚地看到,#英国退出欧盟是使用最多的标签,这是非常明显的,因为它是用于下载英国退出欧盟话题推文的标签之一。可以用这些信息制作的另一个很好的可视化表示是使用 Wordcloud Python 库的 Wordcloud。单词云是不同单词的拼贴,这些单词具有相应的数值(如出现的次数),并根据该值进行缩放:具有最高值的单词将是拼贴中最大的单词。

#Make a wordcloud plot of the most used hashtags, for this we need a #dictionary 
#where the keys are the words and the values are the number of #appearanceshashtag_ordered_dict = {}
for item in hashtag_ordered_list[0:20]:
    hashtag_ordered_dict[item[0]] = item[1]
wordcloud = WordCloud(width=1000, height=1000, random_state=21, max_font_size=200, background_color = 'white').generate_from_frequencies(hashtag_ordered_dict)
plt.figure(figsize=(15, 10))
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis('off')

plt.show()

Wordcloud representation of the most used hashtags

看起来很酷吧?现在让我们对提及做同样的事情。

#Now we will do the same with the mentions: mentions = []
mention_pattern = re.compile(r"@[a-zA-Z_]+")
mention_matches = list(tweets['text'].apply(mention_pattern.findall))mentions_dict = {}
for match in mention_matches:
    for singlematch in match:
        if singlematch not in mentions_dict.keys():
            mentions_dict[singlematch] = 1
        else:
            mentions_dict[singlematch] = mentions_dict[singlematch]+1

同样,我们使用正则表达式来构建一个提及的模式,并创建一个字典,其中的键是被提及的用户,值是他们被提及的次数。考虑到这种提及模式也将从转发和回复中获取提及,因此该字典还将包括未被明确提及的用户,以及其帖子已被转发或回复的用户。

#Create an ordered list of tuples with the most mentioned users and #the number of times they have been mentionedmentions_ordered_list =sorted(mentions_dict.items(), key=lambda x:x[1])
mentions_ordered_list = mentions_ordered_list[::-1]#Pick the 20 top mentioned users to plot and separate the previous #list into two list: one with the users and one with the valuesmentions_ordered_values = []
mentions_ordered_keys = []
for item in mentions_ordered_list[0:20]:
    mentions_ordered_keys.append(item[0])
    mentions_ordered_values.append(item[1])

现在,如果我们画出这些结果:

fig, ax = plt.subplots(figsize = (12,12))
y_pos = np.arange(len(mentions_ordered_values))
ax.barh(y_pos ,list(mentions_ordered_values)[::-1], align='center', color = 'yellow', edgecolor = 'black', linewidth=1)
ax.set_yticks(y_pos )
ax.set_yticklabels(list(mentions_ordered_keys)[::-1])
ax.set_xlabel("Nº of mentions")
ax.set_title("Most mentioned accounts", fontsize = 20)

plt.show()

由此可以看出谁是被提及最多的账号:@theresa_may,Theresa May 的官方账号。我们还可以在这张图表中看到其他政治人物,如@jeremycorbyn(杰里米·科尔宾)或@Anna_Soubry(安娜·苏布里),属于政党的账户(@英国工党,@保守党),新闻来源(@BBCNews,@BBCPolitics,@SkyNews),以及不同的记者(@georgegalloway)

这种见解可能非常有用,在未来的帖子中,我们将探索如何使用不同的 Twitter 交互来创建网络,并查看这些最常提到的用户在这些网络中的角色。

至于标签,让我们也做一个词云表示:

#Make a wordcloud representation for the most mentioned accounts toomentions_ordered_dict = {}
for item in mentions_ordered_list[0:20]:
    mentions_ordered_dict[item[0]] = item[1]
wordcloud = WordCloud(width=1000, height=1000, random_state=21, max_font_size=200, background_color = 'white').generate_from_frequencies(mentions_ordered_dict)
plt.figure(figsize=(15, 10))
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis('off')

plt.show()

Worcloud representation of the most mentioned users

结论

我们已经探索了一些有趣的可视化,可以从原始 Twitter 数据中获得,而无需任何复杂的算法,并且还研究了 Twitter 的流媒体 API 的响应格式。

在下一篇文章中,我们将继续一些其他很酷的可视化技术:查看哪些用户发布了最多的推文,他们是机器人的可能性,我们还将创建推文发布的时间序列,检查产生推文的设备,并获得一些进一步的见解。

更多牛逼的自然语言处理和机器学习资源,请查看本博客: 如何学习机器学习

感谢您的阅读,祝您愉快,再见!

可视化恒温器折扣数据

原文:https://towardsdatascience.com/visualize-data-fast-watson-studio-ae1ec63e9b8f?source=collection_archive---------27-----------------------

github repo 上的逐步说明。

正如一些读者所知,通过提供设备折扣,智能恒温器对美国消费者更具吸引力。你可能不知道的是,恒温器的折扣根据邮政编码的不同而不同。这篇博客调查了美国哪些地区的回扣较高或较低,并直观地展示了结果。对于这个分析,我使用了 IBM 的 Watson Studio ,它使得与数据的可视化交互变得简单而快速。

数据分布

让我们从数据分布开始,这将为我们提供所有可能值的概述,以及它们出现的频率。用视觉术语来说,这意味着绘制恒温器折扣的直方图。为简单起见,我们可以使用从更大的数据集中提取的 1k 行的统一样本。

Watson Studio 中的数据提炼工具可以让您轻松地绘制柱状图,以及许多其他一次可能涉及多列的图表(散点图、时间序列等)。

Distribution of Thermostat Rebates

请注意,超过一半的恒温器折扣在 100 美元到 120 美元之间。我注意到只有少数邮政编码有超过 140 美元或低于 60 美元的折扣,这激起了我的兴趣。我决定在一张地图上标出获得最低和最高折扣的地区。幸运的是,数据已经包含了经度和纬度信息,所以一旦我指定了从最低(蓝色)到最高(红色)的色谱,我就可以将数据放在州地图上:

我注意到北加州的回扣比美国其他大多数地区都低。我还注意到,大多数最大的回扣都在得克萨斯州。老实说,我还是不确定为什么会这样。如果你有猜测,一定要让我知道。

Watson Studio 中的数据提炼工具有地图,您可以使用它来放置经度/纬度数据,它让您可以使用数据集的任何列轻松配置色谱。

与人口统计特征的相关性

为了更深入地了解恒温器折扣分布,我做了一个按邮政编码连接,以引入额外的人口统计特征,如家庭收入中值和平均值,以及人口规模。这些邮政编码的人口统计特征似乎都与恒温器折扣没有线性关系。唯一强相关的是家庭收入的平均值和中值,这并不奇怪。

Correlation Plots Created with Data Refinery.

更多图表可供探索

除了直方图和地图,Watson Studio 中的数据提炼工具还提供了广泛的可视化选择,包括用于可视化高维数据的 t-SNE:

Chart Options in Data Refinery (part of Watson Studio)

github repo 上的逐步说明。

特别感谢史蒂夫·摩尔对这篇文章的大力反馈。

推特:@ castan LinkedIn:@jorgecasta

基于 t-SNE 的可视化降维

原文:https://towardsdatascience.com/visualize-high-dimensional-data-fast-watson-studio-ebad7e7e1b6a?source=collection_archive---------13-----------------------

github repo 上的分步说明

t-SNE on MNIST Database of Handwritten Digits

不需要编码,Python 或 R。只需插入您的高维数据,并使用沃森工作室中的数据提炼工具将其可视化。不要误解我,我喜欢用 Python 和 R 编写代码,但是当涉及到快速可视化数据时,我只是使用数据精炼。

重要的事情先来。在这篇博客中,我提到的高维数据是指数据集的特征数量,而不一定是指观察值的数量。图像由大量像素组成,这些像素可以被投影到二维空间。但是为什么要投影到二维呢?将代表相同对象的图像组合在一起可以帮助我们对图像进行分类。为了直观地验证我们的分组技术有多好,我们需要首先投射到二维或三维空间。我将介绍一个例子,其中为了可视化的目的,手写数字的图像从 784 维投影到 2 维。

方法

t-随机近邻嵌入(t-SNE)技术是由 L.J.P. van der Maaten 和 G.E. Hinton 于 2008 年提出的一种非线性降维方法。人们通常使用 t-SNE 进行数据可视化,但你也可以将其用于许多其他机器学习任务,例如减少特征空间和聚类,等等。(你可以在这里了解更多关于 t-SNE 方法及其在几种编程语言中的实现。)

与最流行的降维技术主成分分析(PCA)相比,t-SNE 更擅长捕捉数据中的非线性关系。PCA 基于寻找最大化数据线性变化的新向量来降低特征空间的维度。因此,当数据的线性相关性很强时,PCA 可以在不丢失信息的情况下显著降低数据的维数。(你不需要总是在 PCA 或 t-SNE 之间选择,因为你可以将它们结合起来,并获得每种技术的好处。参见示例这里的,其中 PCA 用于减少特征空间,t-SNE 用于可视化 PCA 减少的空间。)

t-SNE 最重要的参数:

  1. 困惑-根据经验猜测每个点的近邻数量。帮助平衡数据的本地和全局方面。
  2. 学习率 —通过指定每次迭代改变多少权重,该值影响学习的速度。
  3. 最大迭代次数 —执行迭代次数的上限。

数据

在这个例子中,我使用了 MNIST 手写数字数据库,你可以在这里下载。该数据库包含数千幅从 0 到 9 的数字图像,研究人员用这些图像来测试他们的聚类和分类算法。完整的数据集由 60,000 张用于训练的图像和 10,000 张用于测试的图像组成,但是为了简化这个示例,我从数据库中每位数抽取了大约 1,000 张图像,因此总共有 10,000 张图像。样本数据集的每一行都是原始图像的矢量化版本(大小为 28 x 28 = 784)以及每个图像的标签(零、一、二、三、…、九)。因此,数据集的维数是 10,000(图像)乘 785 (784 像素加一个标签)。

我在探索 SNE 霸王龙时学到了什么

在写这篇博客之前,我从来没有机会了解 SNE 霸王龙。每当我需要降低特征空间的维数时,我都会使用 PCA。我知道主成分分析对于降低列线性相关的数据集的维数非常有用。现在我知道,当你的列的关系是非线性的时候,t-SNE 是一个可行的选择。

这是几百次迭代后 t-SNE 分组的样子…

t-SNE on MNIST Data Set (at iterations 620)

github 回购上的分步说明。

在这里找到更多关于 Watson Studio 桌面的信息,或者在这里找到数据精炼的信息。

特别感谢史蒂夫·摩尔对这篇文章的巨大反馈。

Twitter:@ castan LinkedIn:@jorgecasta

使用 tiobeindexpy 可视化编程语言流行度

原文:https://towardsdatascience.com/visualize-programming-language-popularity-using-tiobeindexpy-f82c5a96400d?source=collection_archive---------7-----------------------

尽管我们中的大多数人会用一种主要的编程语言进行编码,但是关注编程世界中发生的变化总是有好处的。TIOBE 是一个已经为编程语言创建了一个索引的组织,并且每个月跟踪这个索引的变化。

在本帖中,我们将使用tiobeindexpy Python 包来可视化编程语言的流行程度,这样它就可以作为一个小追踪器,供我们每个月重温。

关于套餐:

tiobeindexpy是一个 Python 包(PyPi 上有),给我们提供了官方网站的 TIOBE 索引摘录。

安装:

使用pip可以安装tiobeindexpy的稳定版本。

pip install tiobeindexpy

如果你有 Python3,请确保使用pip3 install tiobeindexpy以避免任何冲突。

目标

在练习结束时,我们要努力完成三件事。

  • 最流行的 20 种编程语言是什么(截至 2019 年 2 月)
  • 谁是前 5 名收益者(2018 年 2 月与 2019 年 2 月-当前前 20 名中的收益者)
  • 谁是前 5 名输家(2018 年 2 月与 2019 年 2 月-当前前 20 名中的输家)

加载库

作为典型的体面的编码风格,让我们从加载所需的库开始。

from tiobeindexpy import tiobeindexpy as tbpy
import seaborn as sns

需要注意的是,一旦库被加载,tiobeindexpy从 TIOBE 索引网站下载所需的数据。因此,所有其他后续函数将只获取该数据,而不会进行实际的服务器调用。

地块大小和主题

我也更喜欢在开始时设置地块大小及其主题——如果有人想在不深入研究代码的情况下使用这些参数,这会更容易。

sns.set(style = "whitegrid")
sns.set(rc={'figure.figsize':(11.7,8.27)})

前 20 名

首先,我们将使用来自tiobeindexpy的函数top_20()来提取基于 TIOBE 指数评级的前 20 种编程语言。

top_20 = tbpy.top_20()

在我们开始可视化数据之前,让我们通过打印来验证数据是否真的可用。

top_20

从上面的输出可以看出,很明显 Python 对象top_20是一个熊猫数据帧,它实际上是 2019 年 3 月的数据帧。您可能还会注意到 Ratings and Change.1 列中数值旁边的%符号——这也意味着这些列在提取的数据帧中必须是字符串,因此需要进行前置处理。

数据预处理

在这一步,我们将strip(移除)上述两列中的%符号,并将它们类型转换为浮点字段。

top_20['Ratings'] = top_20.loc[:,'Ratings'].apply(lambda x: float(x.strip("%")))top_20['Change.1'] = top_20.loc[:,'Change.1'].apply(lambda x: float(x.strip("%")))

开始数据可视化

我们已经对数据进行了预处理,现在可以开始可视化编程语言排名了。

前 20 名编程语言

我们可以从一个非常简单的排名前 20 位语言的条形图开始(基于它们的 TIOBE 指数评级)

sns.barplot('Ratings', 'Programming Language', data = top_20).set_title('Mar 2019 - Programming Popularity')

Java、C、Python —是基于 TIOBE 指数的前 3 名语言。Java 和 Python 之间的评级差异似乎很大,这让我想了解一下 TIOBE Index 方法论的清晰性。

在 2018 年到 2019 年之间

世界上发生了很多变化,特别是在 2018 年和 2019 年之间的技术领域,所以让我们试着看看一年内的变化是什么样的:

涨幅前五名

sns.barplot('Programming Language', 'Change.1', 
            data = top_20.sort_values("Change.1",ascending = False)[0:5]).set_title('Mar 2018 vs 2019 - Language Popularity - Biggest Gainers from Top 20')

【VB.NET】c++Python跃居首位。

前 5 名输家

sns.barplot('Change.1', 'Programming Language', 
            data = top_20.sort_values("Change.1",ascending = True)[0:5]).set_title('Mar 2018 vs 2019 - Language Popularity - Biggest Losers from Top 20')

****C#、PHP、Ruby——在变化百分比(负值)方面一直是排行榜冠军。

到目前为止,这给了我们一个很好的月度图片,以及编程语言的流行程度是如何变化的。

名人堂——过去 15 年

让我们抽象一下,看看每年名人堂的获奖者是什么编程语言。

我们可以简单地使用tiobeindexpy的函数hall_of_fame()来提取名人堂数据。

hof = tbpy.hall_of_fame()

上面输出的一个稍微格式化的表。

hof.style.set_properties(**{'background-color': 'black',
                           'color': 'lawngreen',
                           'border-color': 'white'})

这些数据一次又一次地显示出,当一种新的趋势出现时,Python 如何选择,并且以这种方式,它如何成为名人堂中出现次数最多的条目之一。

摘要

在这篇文章中,我们看到了如何使用 python 包tiobeindexpyseaborn来可视化基于 TIOBE 索引的编程语言流行度(排名)。

参考

文本挖掘中关联规则的可视化

原文:https://towardsdatascience.com/visualizing-association-rules-for-text-mining-6cb80dc71171?source=collection_archive---------16-----------------------

一种新颖的关联规则可视化系统

关联是一种强大的数据分析技术,经常出现在数据挖掘文献中。关联规则是 X→Y 形式的蕴涵,其中 X 是一组前提项,Y 是结果项。超市数据库的一个示例关联规则是,购买尿布和婴儿爽身粉的人中有 80%也购买婴儿油。

关联规则的分析有多种用途,包括商品库存、保险欺诈调查和气候预测。多年来,科学家和工程师开发了许多可视化技术来支持关联规则的分析。

然而,许多可视化在处理大量的规则或具有多个前提的规则时表现不佳。这一限制给需要了解大型数据库关联信息的分析师带来了严峻的挑战。

这篇博客是对研究论文 可视化文本挖掘关联规则 的总结,该论文提出了一种新颖的关联规则可视化系统,旨在解决这些问题。

关联规则定义

关联规则的定义随着规程和实现的不同而不同。基本方法是挖掘描述项目集之间关联的定性规则。

给定一组项,S = {i1,i2,…,ij,…,in}其中 n ≥ 2。关联规则是 X→ij 形式的蕴涵,其中 X→S,ij → S,使得 ij→X。项目集 X 是关联规则的前因,而项目 ij 是关联规则的后果。X 的大小在 1 到(n-1)个项目之间。规则 X → ij 的支持度定义为 S 中满足 X 和 ij 中项的并集的项的百分比。规则的置信度是满足 X 和 ij 的文章的百分比。

关联规则可视化

关联规则的可视化涉及五个参数:

  • 先行项目集
  • 后续项目
  • 前因和后果之间的联系
  • 规则支持
  • 规则的可信度

当前技术

二维矩阵和有向图是关联规则可视化的两种方法。

二维矩阵

将前因项和后果项定位在正方形矩阵的独立轴上,并在连接相应关联规则的前因项和后果项的某些矩阵瓦片上绘制定制图标。

The coloured column indicates the association rule B → C. Different icon colours are used to show different metadata values of the association rule.

该图描述了一个关联规则(B →C)。列图标的高度和颜色都可以用来表示元数据值。置信度和支持度的值被映射到分别构建在矩阵瓦片之上和之下的 3D 列。在 MineSet 的规则可视化器中,磁盘和条形等图标用于可视化元数据。

Very difficult to determine the differences between (A+B →C) and (A →C and B →C).

2D 矩阵的问题:2D 矩阵是显示一对一二元关系的最有效的技术。然而,当我们需要可视化多对一的关系时,例如具有多个先行项的关联规则,2D 矩阵的优势就失效了。

有向图

Left: A →C and B →C. Right: A+B →C.

有向图的节点代表项目,边代表关联。图中显示了三个关联规则(A→C,B→C,A+B→C)。这种技术只适用于少数项目(节点)和关联(边)。一个关联图可以变成一个只有十几条规则的混乱显示。

一种新的可视化技术

这种技术是可视化多对一关联规则。它不是使用 2D 矩阵的瓦片来显示项目到项目的关联规则,而是使用矩阵来描述规则到项目的关系。

A visualization of item associations with support 0.4% and confidence 50%.

矩阵底层的行表示项目,列表示项目关联。每个规则的蓝色和红色块代表规则的前因和后果。矩阵的右侧显示了项目的身份。矩阵远端不同比例的相应条形图给出了规则的置信度和支持度。

该系统通过使用弹出菜单来限制要包括在可视化中的关键项目,从而支持基本的查询命令。显示器具有鼠标控制的缩放功能,以支持上下文/焦点分析。

规则到项目可视化方法的优势:

  • 先行词中的项数没有上限。
  • 它可以分析两者的分布,关联规则(水平轴)以及其中的项目(垂直轴)。
  • 由于关联规则中有多个先行项,没有新的先行组。
  • 没有屏幕交换,动画,或人类互动(除了基本的鼠标缩放)来分析规则。

从实验来看,这种可视化技术在 17 英寸的监视器屏幕上处理多达数百条关联规则和几十个先行主题时效果很好。这是对传统的 2D 项目到项目关联可视化的重大改进。

结论

当存在一对一的二元关系时,二维矩阵是最有效的。在多对一关系的情况下,二维矩阵的强度会下降。有向图也适用于只有少量节点和关联的情况。当项目增加到一打时,它会变成一个混乱的显示。然而,规则到项目的可视化方法可以在对先行项中的项目数量没有任何上限的情况下实现。

因此,从二维矩阵的项目到项目的排列切换到规则到项目的设计,让我们有效地显示具有多个先行主题的关联规则。

可视化朴素贝叶斯定理

原文:https://towardsdatascience.com/visualizing-bayesian-theorem-ccea9e3696a2?source=collection_archive---------12-----------------------

贝叶斯定理通过维恩图、树形图和饼状图可视化

曾经需要记忆贝叶斯定理公式吗?通过维恩图可视化贝叶斯定理,不需要再次记忆。

根据下面的文氏图,在一个 100 人的班级中,随机挑选的学生是女生的概率, P(女生)是女生在 100 名学生中的比例:

假设学生是女生,她穿粉色的条件概率, P(穿粉色|女生)是所有女生中穿粉色的比例:

学生是女生并且穿粉色的概率, P(穿粉色∩女生)P(穿粉色∩女生)是 100 个学生中女生穿粉色的比例:

因此,假设学生穿粉红色衣服,则该学生是女生的条件概率, P(女生|穿粉红色衣服)是所有穿粉红色衣服的女生的比例,可以通过将交集除以穿粉红色衣服的概率 P(穿粉红色衣服)得到:

更常见的是,贝叶斯概率可以通过树形图来计算:

任何一个学生穿粉色的概率, P(穿粉色) = P(穿粉色的女生)+ P(穿粉色的男生)= 23/100+2/100 = 25/100 =0.25

假设学生是女生,她穿粉色衣服的条件概率是 23/55 = 0.418

知道学生是女生,她穿粉色的概率(0.418)整体上大于任何一个学生穿粉色的概率(0.25)。因此知道学生是女生,就增加了她穿粉色的概率。也可以说,作为一个女孩和穿粉红色是相关联的,它们不是相互独立的事件。

另一方面,以下示例显示了相互独立的事件:

任意一个学生免费吃饭的概率, P(免费吃饭)为 P(女生免费吃饭)+ P(男生免费吃饭)= 22/100+18/100 = 40/100 =0.4

假设学生是女生,她有空吃饭的条件概率是 22/55 = 0.4

知道是女生,她有空吃饭的概率(0.4)和整体上有空吃饭的人的概率(0.25)是一样的。因此知道是女生,并没有增加或减少她有空吃饭的概率。也可以说,做女生和免费吃饭是没有关联的,它们是相互独立的事件。

假设有另一个条件概率,学生穿短裤,假定她是女生, P(穿短裤|女生) = 1/4。 P(穿短裤|少女)P(穿粉色|少女)相互独立。

由于 P(穿短裤|女生)P(穿粉色|女生)相互独立,所以女生是否穿粉色并不影响女生穿短裤的概率(总是 1/4)。穿粉色的女生有 1/4 穿短裤。1/4 不穿粉色的女生也穿短裤。因此,假设学生是女生,穿粉色短裤的学生的条件概率 P(穿短裤,穿粉色|女生)为:

Xi 指的是女孩的不同特征。由于假定 P(穿短裤|女孩)P(穿粉色|女孩)之间相互独立,这种从给定类别标签的多个特征中提取条件概率的方法被称为朴素贝叶斯。

如果 P(穿短裤|女孩)P(穿粉色|女孩)之间不假设相互独立,知道女孩穿粉色可能会降低女孩穿短裤的概率。1/5 穿粉色的女生也穿短裤。6/7 不穿粉色的女生也穿短裤。于是, P(穿短裤,穿粉色|少女)不可能是 P(穿短裤|少女) P(穿粉色|少女)。T* 女孩穿短裤的条件概率假设她是一个女孩并且穿粉色, P(穿短裤|穿粉色,女孩)需要在 P(穿短裤,穿粉色|女孩)c 能够被发现之前首先被发现。

给出了预测具有特征 X1 至 Xi 的示例属于类 j 的概率的朴素贝叶斯分类器公式:

其中 P(Cj|X1,..、Xi) 为待预测的后验概率, P(Xi|Cj) 为特征 I 给定类 j 的条件概率, P(Cj) 为类j****P(Xi)Xi 的概率。

可视化贝塔分布和贝叶斯更新

原文:https://towardsdatascience.com/visualizing-beta-distribution-7391c18031f1?source=collection_archive---------4-----------------------

眼见为实:通过模拟、想象和检查每一步来建立直觉

与伯努利分布、二项式分布和几何分布相比,贝塔分布是更深奥的分布之一。它在实践中也很少见,因为它没有现成的真实世界的类比来帮助直觉。更糟糕的是,在线教程往往用复杂的公式(beta & gamma 函数)和听起来怪异的名字(共轭先验)来恐吓读者。所以在这篇文章中,我将放弃那些技术细节,通过视觉动画和模拟实验来补充一些急需的直觉。

简介

贝塔分布是概率的概率分布。这是什么意思?大家都是通过抛硬币开始学习概率的。那么让我们从一枚硬币开始。首先,定义 p 为头部落地的概率。如果硬币是公平的,那么很有可能有一半的时间硬币正面着地。在这种情况下, p = 50%p. 最有可能的值,但是等等,不公平硬币也有可能意外地表现得像公平硬币。所以我们不能排除硬币不公平的可能性,即使我们有一半的时间观察正面。

注意我是如何用概率来描述概率 p 的。这是贝塔分布的本质:它描述了 p 取 0 到 1 之间的每个值的可能性。贝塔分布由𝛽).beta(𝛼的参数化𝛼和𝛽 共同描述了 p 取某一值的概率。这是你完成这篇文章所需要的唯一公式。

之前

先验是我们在进行实验之前所相信的。如果你看一枚硬币的两面,看到一面是正面,另一面是反面,你可能会相信这枚硬币是公平的。一枚公平的硬币有 𝛼 = 𝛽,,数量描述了你对自己的信仰有多自信。如果你有信心,那么你可以给 𝛼 = 𝛽 = 10 打高分。不太自信的人可能会认为𝛼 = 𝛽 = 3。差异总结如下。

当然,两条曲线都以 p = 50%为中心,但是如何量化“置信度”呢?在你真正掷硬币之前,把 𝛼𝛽 想象成抛硬币:𝛼 - 1 是你得到的正面数, 𝛽 - 1 是反面数。如果你想象你已经抛了 18 次,得到了 9 个正面和 9 个反面 (𝛼 = 𝛽 = 10) ,你比那些只想象了 4 次结果是 2 个正面和 2 个反面 (𝛼 = 𝛽 = 3)的人更有信心认为硬币是公平的。我们需要减去 1 的原因是,通过设置 𝛼 = 𝛽 = 1,我们将分子减少为常数 1。这给了我们一个无信息的先验——我们假设零次假想的硬币投掷。

无信息先验

在翻动硬币甚至看硬币之前,我们对硬币了解多少?我们什么都不知道,当我们什么都不知道的时候,我们说什么都有可能发生。它同样可能是一个公平的硬币,一个双头硬币,一个双尾硬币,或者任何一边比另一边重的合金混合物。在我们什么都不知道的情况下,落地头的概率是均匀分布。这是β的特例,参数化为 Beta(⍺=1,β=1)。

根据用例的不同,我们可能需要也可能不需要无信息的先验。有时候在实验过程中,我们不希望我们已经知道的东西影响我们解释数据的方式。在其他情况下,我们希望利用早期实验的结果,因此我们不必从头开始学习一切。然而,在这两种情况下,我们使用贝叶斯更新从新的证据中学习。

贝叶斯更新

我们之前认为 𝛼𝛽 是想象中的掷硬币游戏。虽然这是一个概念上的便利,但好消息是 Beta 分布并不区分虚的和实的。如果我们抛硬币,观察一个人头,我们简单地更新 𝛼 ← 𝛼 + 1(反之亦然 𝛽 )。这个过程被称为贝叶斯更新(见此处为证明)。

建立直觉:模拟

让我们从一个无信息的先验开始,假设硬币确实是公平的。你预计会发生什么?当我们掷硬币时,我们会观察到数量大致相等的正面和反面,掷得越多,我们就越有信心认为硬币是公平的。所以概率密度函数在 p = 50%时变得越来越尖锐。

先前的效果

现在考虑硬币偏向正面 20%的情况,我们从无信息先验开始。它立即出现在 20%左右,并集中在 20%左右。这并不奇怪,因为我们没有偏见。注意,我还模拟了补体事件( p = 80%)。这是贝塔分布的一个重要性质:每次试验最终只能有两种可能的结果。

如果我们先相信硬币是公平的,我们会看到贝塔分布的峰值(模式)更慢地收敛到真实值。

我们先前的信念越强,如果它们不同,我们接受真相的速度就越慢。在下面的例子中,先验足够强( 𝛼 = 𝛽 = 100) 以至于我们无法在 1000 次迭代中收敛到真实值。

如果先验是不对称的,我们将看到更接近先验的β比远离先验的β收敛得更快(并且其峰值更高)。这是直觉的:如果现实与我们的信念一致,我们会欣然接受,并对我们的信念更加自信。相比之下,如果真相与我们的信念相矛盾,我们接受真相的速度会慢一些。

棒球击球统计

对于现实世界应用的具体例子,让我们考虑棒球击球率(改编自这篇帖子)。全国平均打击率为 0.27。如果某个新玩家加入游戏时没有之前的表现记录,我们可以将他与全国平均水平进行比较,看他是否有任何优势。先验公式为 Beta(⍺=81,β=219) 以给出 0.27 的期望当他挥动球棒时,我们沿途更新了 β 。在 1000 次击球后,我们观察到 300 次击中和 700 次未击中。后验变成 Beta(⍺=81 + 300,β=219 + 700),带期望381 / (381 + 919) = 0.293。

摘要

这篇文章介绍了 Beta 分布,并通过模拟和可视化揭示了它的基本属性。对于用概率分布描述概率意味着什么,先验如何与证据相互作用,以及它如何与现实世界的场景相关,你应该已经建立了一些直觉。

贝叶斯更新是一个非常强大的概念,在商业智能、信号过滤和随机过程建模中有着广泛的应用。我将在不久的将来研究其中的一些应用。下一个帖子是对 Google Analytics 的多臂土匪实验的近距离考察(这个帖子的第一个动画实际上来自一个 8 臂土匪实验)。

延伸阅读

下面的博客涵盖了与 AB 测试相关的主题,以及对本文中提到的关键概念的更深入的回顾。

  • 理解置信区间[ 链接
  • A/B 测试的力量[ 链接
  • 超越 A/B 测试:多臂强盗实验[ 链接
  • 你知道可信区间[ 链接
  • 代码在我的 Kaggle 笔记本里。

超越三维的视觉化

原文:https://towardsdatascience.com/visualizing-beyond-3-dimensions-67531b431119?source=collection_archive---------22-----------------------

窥视看不见的复杂数据

视觉可以说是我们人类最大的优势之一。一旦你找到一种可视化的方法,即使是最复杂的想法也会变得容易理解(或者至少,更容易理解)——我们的枕叶帮了我们大忙。这就是为什么当你处理超过 3 维的数据集时,仅仅理解数据集内部的情况是一个挑战,更不用说向他人展示你的发现了。这就是我们今天要应对的挑战。

为此,我们将使用 King County 房屋销售数据集,其中包含 2014 年和 2015 年超过 21,000 套真实房屋的销售信息。这个数据集恰好在每一条记录中包含 21 条信息,比如价格、平方英尺、房产状况等等——换句话说,这个数据集是 21 维的。实际上,我不得不将它转置,以适应下一个镜头的水平方向。

*df.head(10).T*

Sweet mother of data science.

我们从哪里开始呢?最简单的方法之一是绘制所有指标的直方图,或者在散点图中根据您选择的目标(如价格)绘制所有特征。

*df.hist()* 

It’s a start, but it doesn’t tell us everything.

这告诉我们关于我们所有的数据片段的一些事情,但是没有告诉我们它们是如何相互关联的。输入散点图—* 是的,我刚才说散点图对此也没有太大帮助,但是请耐心听我说。*

出于可见性的考虑,让我们设计一个price_thousands特性,并从我们的数据点中随机抽取大约 3%的样本。在这种情况下,3%仍然是 600 左右,超过这个数字,情节就会变得过于拥挤。

*df['price_thousands'] = df['price'] / 1000
np.random.seed(25565)
df = df.sample(n=round(len(df)/33))plt.figure(figsize=(9, 9))
sns.scatterplot(x='price_thousands', 
                y='sqft_living', 
                palette='Blues', 
                data=df);*

结果看起来像这样:

It’s something.

然而,只要添加几个新参数,我们就可以让它看起来像这样…

*sns.scatterplot(x='price_thousands', 
                y='sqft_living', 
                hue='grade', 
                size='sqft_living', 
                palette='Blues', 
                data=df);*

Much better.

通过本质上增加色调作为一个维度,我们能够本质上在二维空间中表现三维空间——这是一个不错的交易!注意,我们在这里也两次表示了sqft_living:一次作为轴,然后再次作为点的比例。如果您自己认为使用点的刻度来表示sqft_living和 y 轴来表示数据的其他特征会更好,那么原则上我完全同意您的观点。然而在实践中,对于这个特殊的数据集,这种尝试变得如此混乱,以至于数据在视觉上变得难以处理。至少我们可以通过两次表示sqft_living来增加这些数据的可读性,所以看起来并不是一无所获。我要说的是,从这个角度来看,数据可视化更多的是一门艺术,而不是科学。

回到手边的主题:如何超越三维可视化。也许我们可以将改变颜色梯度和点大小的新技巧与实际的 3D 散点图结合起来?嗯,是的,但实际上不是。

*from mpl_toolkits.mplot3d import Axes3Dfig = plt.figure(figsize=(9, 9))
ax = fig.add_subplot(111, projection='3d')x_param = 'price_thousands'
y_param = 'sqft_living'
z_param = 'bedrooms'
x = df[x_param]
y = df[y_param] * 25
z = df[z_param]
ax.set_xlabel(x_param)
ax.set_ylabel(y_param)
ax.set_zlabel(z_param)ax.scatter(x, y, z, 
           c='b', s=50,
           edgecolors='w', 
           marker='o', 
           alpha=0.4);*

It’s 3D, but it’s not quite all we hoped.

色调和点大小的变化是 Seaborn 的一个特点,但据我所知,Seaborn 不支持 3D 散点图。相反,Matplotlib 可能能够绘制三维图,但它不支持那些如此可爱和有用的变换色调和点大小。总之,没有(据我所知的)现成的解决方案可以让我们既吃蛋糕又吃 t。如果这确实存在,请分享评论!

让我们尝试另一种方法:曲面图。

*fig = plt.figure(figsize=(9, 9))
ax = fig.gca(projection='3d')
ax.plot_trisurf(y, x, z, cmap=plt.cm.viridis, linewidth=0.2)
ax.view_init(30, 145)
plt.show();*

嗯。事实证明,除非我们对它们的值进行排序,否则表面图非常混乱。然而,虽然对值进行排序会让我们更清楚,但不一定会让我们更有用。

*x = np.sort(x)
y = np.sort(y)
z = np.sort(z)
fig = plt.figure(figsize=(9, 9))
ax = fig.gca(projection='3d')
ax.plot_trisurf(y, x, z, cmap=plt.cm.viridis, linewidth=0.2)
ax.view_init(35, 140)
plt.show();*

所有这些变量都有很强的相关性,所以我们最终得到的是一个很窄的线性形状,很难分辨。最后,散点图似乎提供了更有效的可视化,至少对于这个特定的数据集是如此。然而,其他人对这种媒体的翻译要好一些。

*iris = sns.load_dataset('iris')
fig = plt.figure(figsize=(9, 9))
ax = fig.gca(projection='3d')ax.plot_trisurf(iris['sepal_length'],
                 iris['sepal_width'],
                 iris['petal_length'],
                 cmap=plt.cm.viridis, 
                 linewidth=0.2)
ax.view_init(30, 145)
plt.show();*

还有一些我们还没有尝试过的技巧(比如不同的点形状或者让我们的情节随着时间而变化的动画),但是事实是我们还没有接近同时可视化 21 个维度——这完全不可能。但这并不意味着我们不能从超维数据中获得有意义的见解。我们可能不太关心这些数据的所有 21 个维度,而更关心这些数据实际能为我们做些什么,比如让我们更准确地预测价格。为此,我们可以简单地在两个维度上绘制误差值。

*residuals = model_1st.resid
fig = sm.graphics.qqplot(residuals, dist=stats.norm, line='45', fit=**True**)
plt.xlabel('Quantiles of Standard Normal Distribution')
plt.ylabel('Quantiles of Residuals')
plt.title('Distribution of Residuals (Best Model)')
fig.show()*

Error Distribution vs Normal Distribution

即使我们不能同时看到所有 21 个维度,也有很多方法可以从这些数据中获取有意义的见解。如果你还知道什么,请告诉我!

使用嵌入式投影仪可视化数据中的偏差

原文:https://towardsdatascience.com/visualizing-bias-in-data-using-embedding-projector-649bc65e7487?source=collection_archive---------6-----------------------

使用开源嵌入投影工具进行嵌入的交互式可视化和解释

t-SNE projection of MNIST Digits

在调试模型之前先调试数据

在部署机器学习模型之前,会对其性能进行评估。然而,除了性能方面之外,了解模型学到了什么也很重要。这是必要的,以确保模型没有学到歧视或偏见的东西。

解决这个问题的一个方法是从数据可视化的角度。通过可视化模型如何对数据进行分组,我们可以了解模型认为哪些是相似的数据点,哪些是不相似的数据点。这对于理解模型为什么做出某些预测以及什么样的数据被输入到算法中是有益的。

在本文中,我们将看看一个名为 的嵌入投影仪 的工具,它使我们能够轻松地可视化高维数据,以便我们能够理解模型从数据中学到了什么。

介绍

嵌入的本质上是一个低维空间,高维向量可以被转换到其中。在翻译期间,嵌入通过在嵌入空间中将相似的输入紧密地放置在一起来保持输入的语义关系。让我们试着用例子来理解这个概念。这是嵌入式投影仪的创作者的一个截图。

Source: https://www.youtube.com/watch?v=wvsE8jm1GzE

单词也可以表示为嵌入。这是一个 300 维嵌入的例子,它将单词映射到实数的向量。值得注意的是,这些向量中的个体维度不能提供太多信息。然而,对机器学习有用的是不同向量之间的距离和位置的整体模式。

Source

嵌入的优势

多维空间有助于将语义相关的项目组合在一起,同时将不同的项目分开。这在机器学习任务中非常有用。考虑以下真实嵌入的可视化:

Source: Embeddings- Translating to a Lower-Dimensional Space

这些嵌入捕捉了动词时态、国家资本关系和性别类比等词之间的语义关系。

嵌入式投影仪应用程序

嵌入投影仪 是一个 web 应用工具,它通过从我们的模型中读取嵌入,并以二维或三维的方式呈现它们,从而交互式地可视化嵌入。这是一万张被标签着色的 MNIST 图像的可视化。

visualisation of the ten thousand MNIST images

使用

嵌入式投影仪是开源的,集成到 TensorFlow 平台中,或者可以在projector.tensorflow.org作为独立工具独立工具无需安装和运行 TensorFlow 即可工作。

布局

The main view of Embedding Projector

上图显示了 web 应用程序的主视图,它由五个不同的面板组成。

  • 数据面板,在这里我们可以选择要检查的数据集。嵌入式投影仪网站包括一些数据集可供使用,或者我们可以加载我们自己的数据集。也可以通过点击“发布”按钮来发布并与他人共享我们的嵌入。
  • 投影面板在这里我们可以选择投影的类型。
  • 检查面板我们可以在这里搜索特定的点,并查看最近邻居的列表。
  • 书签面板让我们将当前状态(包括任何投影的计算坐标)保存为一个小文件,然后可以共享。
  • 可视化面板是显示数据的区域

预测

嵌入式投影仪提供了四种众所周知的降低数据维数的方法。每种方法都可以用来创建二维或三维的探索视图。

  • 主成分分析

PCA 是从现有数据中提取一组新变量称为 分量的技术。这些主成分是原始要素的线性组合,并试图从原始数据集中获取尽可能多的信息。嵌入式投影仪计算数据的前 10 个主成分,我们可以从中选择两个或三个进行查看。让我们看看 10000 个 MNIST 数字的 PCA 投影。每个 MNIST 数字有 784 个像素,投影将每个像素视为一个维度。

  • t-SNE

t-SNE 或 T-分布式随机邻居嵌入通过在二维或三维地图中给每个数据点一个位置来可视化高维数据。这种技术发现数据中的聚类,从而确保嵌入保留了数据中的含义。下面著名的 MNIST 数据集的 t-SNE 投影清楚地显示了相似的数字聚集在一起。

  • 风俗

自定义投影是水平轴和垂直轴上的线性投影,已使用数据标签指定。自定义投影主要有助于解读数据集中有意义的“方向”。

  • UMAP

UMAP 代表一致流形逼近和投影降维。t-SNE 是一种可视化高维数据集的优秀技术,但具有某些缺点,如高计算时间和大规模信息的丢失。另一方面,UMAP 试图克服这些限制,因为它可以轻松处理相当大的数据集,同时还保留了数据的局部和全局结构。

如果你正在寻找数学描述,请参见 UMAP 的论文。

探测

我们现在将检查已经被训练来处理文本的 Word2Vec 模型如何对单词的含义进行分组。看到这些分组会很有趣,因为它们会揭示很多单词之间的关系。工具中包含了数据集。

维基百科将 Word2vec 描述为一组用于产生单词嵌入的相关模型。Word2vec 将文本的大型语料库作为其输入,并产生一个向量空间,通常具有数百个维度,语料库中的每个唯一单词被分配一个空间中的相应向量。

我们将使用 Word2Vec 10K 数据集。这里每个点代表一个单词,每个单词有 200 个维度。让我们快速浏览一下创建投影的步骤:

  • 从数据面板中选择所需的数据集。这里的每一个数据点都来自一个根据维基百科文章训练的模型。
  • 现在,让我们通过查看一组预定义点的最近邻居来进行邻域分析。这将使我们清楚地了解模型已经学习了哪些关系。
  • 在“检查器”面板中,键入单词“ Apple ”。
  • 该工具会建议一些匹配的单词。点击apple,我们会得到空间中最近点的列表,其中包括与apple相似的单词。
  • 要去除噪声,点击标有isolate 101 points的灰色按钮,分离相关点。这些点包括选定的点及其 100 个最近的邻居。
  • 我们还可以旋转空间,缩放,甚至平移一点点。

注意juicewinefruit是如何一起出现的,而Macintoshtechnologymicroprocessor也在顶部组合在一起。这里需要注意的是,模型并没有被告知单词的意思,相反,它只是显示了数百万个句子作为单词用法的例子。

这里还有一些例子,会使事情变得更清楚。

左边是与sound相关的一串单词。中间的显示与silver相似的单词,而最右边的显示与soccer相关的单词。

发掘我们语言中的偏见

有时,模型会学习一些令人担忧的事情,特别是当机器学习模型被用来为人类做决策时。这一次我们将使用 Word2Vec All 语料库并搜索单词 Engineer 来查看其最近的邻居。嵌入式投影仪还允许我们重新定向可视化,以便为这些情况执行更复杂的测试,因此我们将使用自定义投影选项卡重新定向我们的结果。

Visualising Bias in data

我固定了一条从的轴,所以靠近男的字偏向左边而类似女的字会出现在右边上。让我们看看我们的锚词是 Engineer,的结果。

看来工程师这个词已经比女人更接近男人了。更接近男性的词用橙色表示,包括astronomer, physicist, mathematician ,而像dancer, songwriter, teacher这样的词看起来更接近女性。

把锚词改成数学怎么样?成绩受影响吗?让我们自己来看看:

我们有类似于computational, geometry, arithmetic挨着男人、的词,而女人最近的邻居是music, teaching, philosophy等等。

想象一下,如果在这个数据集上训练的机器学习算法被用来预测某人在艺术或数学相关的工作中有多好?还有,如果一家公司依靠这样的算法来雇佣潜在的工程师,会发生什么?该模型可能会错误地认为,性别会影响候选人的表现,最终的决定会带有性别偏见。

结论

机器学习模型中的偏差是一个值得关注的领域。但是,重要的是要理解,在大多数情况下,用于训练模型的训练数据实际上是有偏差的,这最终会反映在模型中。因此,尽管强调创建准确的模型很重要,但调试训练数据中存在的任何偏差或异常也很重要。

参考

使用交互式地图和动画可视化伦敦的自行车移动性

原文:https://towardsdatascience.com/visualizing-bike-mobility-in-london-using-interactive-maps-for-absolute-beginners-3b9f55ccb59?source=collection_archive---------12-----------------------

探索 Python 中的数据可视化工具

Photo by Max Adulyanukosol on Unsplash

近年来,自行车共享系统已经成为流行的出行方式,为大都市的市民提供了一种绿色灵活的交通方案。世界上许多政府都认为这是一项创新战略,有可能带来许多社会效益。例如,它可以减少汽车的使用,从而减少温室气体排放,缓解市中心的交通拥堵。

报道显示 77%的伦敦人同意骑自行车是短途旅行最快的方式。从长远来看,这也可能有助于提高城市的预期寿命。

我一直在研究一种数据驱动的经济有效的算法,用于优化(重新平衡)伦敦公共自行车租赁计划桑坦德自行车系统,一旦我的论文发表,我应该就此发表一篇文章(更多信息这里)。在真正研究算法之前,我必须深入研究大量数据,如果我能以某种方式将它们可视化,那将非常有帮助。

TL;DR——让我们看看如何使用图表、地图和动画来可视化自行车共享系统。

你可以在这个 页面 找到网络地图。大多数地图、动画和源代码都可以在GitHub上找到。数据现已在ka ggle上。

目录

原载于我的博客edenau . github . io。我的作品灵感来源于 文森特·隆尼 德鲁米尔·帕特尔 。看看他们的帖子!

关于数据的更多信息—枯燥的部分

我从伦敦交通局(TfL)获得了关于自行车旅行的数据。自 2012 年以来,他们系统中的每一次自行车旅行都被记录下来,这些公开数据可以在网上获得。

分析了从 2017 年 8 月 1 日到 9 月 13 日的 36 天旅程记录。在此期间,伦敦 700 多个自行车停靠站的行程超过 150 万次。从 2014 年开始,我们见证了自行车旅行的增长超过 190%。该系统中自行车和停靠站的数量都增加了两倍多,以适应伦敦市中心和地区自行车需求的显著增长。确切的数据将在我即将发表的论文中给出。敬请期待

数据操作

我相信工作日和周末的出行模式会有很大的不同。我们来做一些编码,看看这是不是真的。我们首先通过pd.read_csv()导入旅程数据。

# Load journey dataf = 'journeys.csv'
j = pd.read_csv(f)date = j['date'].values
month = j['month'].values
year = j['year'].values
hour = j['hour'].values
minute = j['minute'].values
station_start = j['id_start'].values
station_end = j['id_end'].values

然后,我们通过date.weekday()提取工作日数据,并将一天 24 小时平均分成 72 个时间片,这样每个时间片代表 20 分钟的间隔。

# Compute IsWeekdayweekday = np.zeros(len(date))
weekday[:] = np.nan
cnt = 0for _year, _month, _date, _hour, _minute in zip(year, month, date, hour, minute):
  _dt = datetime.datetime(_year, _month, _date, _hour, _minute)
  _weekday = _dt.weekday()
  weekday[cnt] = _weekday
  cnt += 1IsWeekday = weekday < 5
j['IsWeekday'] = IsWeekday# Compute TimeSlicej['TimeSlice'] = (hour*3 + np.floor(minute/20)).astype(int)

我们还需要检查这些自行车旅行是否是从/到被废除的车站,因为没有办法获得这些车站的信息,如位置、车站名称等。(干得好,TfL)。我们把它们称为“无效”旅行。

# Load station dataf = 'stations.csv'
stations = pd.read_csv(f)
station_id = stations['station_id'].values# Extract valid journeysvalid = np.zeros(len(date))
valid[:] = False
cnt = 0for _start, _end in zip(station_start, station_end):
  if np.logical_and((_start in station_id), (_end in station_id)):
    valid[cnt] = True
  cnt += 1j['Valid'] = valid

最后,我们只保留在工作日进行的“有效”的旅程,这占数据的 73%左右。

df = j[j["IsWeekday"] == True].drop(columns="IsWeekday")
df = df[df["Valid"] == True].drop(columns="Valid")print('Ratio of valid journeys= {:.2f}%'.format(df.shape[0] / j.shape[0] * 100))

条形图

我们最后深入研究可视化部分!数据可视化最简单的形式可以说是图表。通过一个简单的groupby('TimeSlice')函数,我们可以看到不同时间的旅行有多频繁。

grp_by_timeslice = df.groupby('TimeSlice').count().values[:,0]plt.bar(range(0,72), grp_by_timeslice)
plt.xlabel('Time Slice')
plt.ylabel('Departures')
plt.show()

Average departure rates on weekdays (left) and weekends (right)

看到了吗?我们的假设是对的!工作日和周末的出行模式如此不同,因为我们可以看到工作日的两个高峰时间,大多数人在那里通勤,但周末不是。我们也可以用类似的方式观察旅行持续时间和速度的分布。

Distribution of journey duration (left) and speed (right)

请注意,由于数据限制(它们不跟踪您的运动),我们假设采用的是直线路径,这将比实际路径短,因此根据起点站和终点站之间的距离计算的速度将被低估。如果顾客在租车的同一个站点归还自行车,计算出的速度将是 0,这解释了为什么会出现 0 公里/小时的奇怪峰值。

交互式地图

如果图表很奇特,地图就更奇特了。我们将使用[folium](https://python-visualization.github.io/folium/),它是制作交互式地图的fleet . js的 Python 包装器。确保通过以下方式安装最新版本

*$ pip install folium==0.7.0*

(或其conda install等价物)。我在谷歌合作实验室工作,预装版本是功能最少的0.2.0

我创建了一个简单的模板,用圆圈标记(不同的颜色)生成地图。)使用集群。

*import folium# Change coloursdef color_change(c):
    if(c < 15):
        return('red')
    elif(15 <= c < 30):
        return('orange')
    else:
        return('green')# Create base mapLondon = [51.506949, -0.122876]
map = folium.Map(location = London,
                 zoom_start = 12, 
                 tiles = "CartoDB positron")
marker_cluster = MarkerCluster(locations=[lat, lon]).add_to(map)# Plot markersfor _lat, _lon, _cap, _name in zip(lat, lon, cap, name):
    folium.CircleMarker(location = [_lat, _lon], 
                        radius = 9, 
                        popup = "("+str(_cap)+") "+_name, 
                        fill_color = color_change(_cap), 
                        color = "gray", 
                        fill_opacity = 0.9).add_to(marker_cluster)

f = 'map_station_cluster.html'
map.save(f)*

为什么是集群?MarkerCluster()缩小时,标记如果靠得太近,可以聚集在一起。你不希望你的地图太乱,标记互相重叠。

Station cluster map

当您放大时,它会自动分解/展开:

Station cluster map — zoomed in

但是我答应你 互动 地图。您可以设置popup参数,当您点击它时会显示站点名称及其容量。太棒了。

Interactions in the station cluster map

此地图在https://edenau.github.io/maps/station-cluster/上有售。

密度图

上面的代码使用了一个动态的颜色方案,这个方案取决于站点的容量。我们还可以根据每个车站的出发和到达次数,为这些圆形标记实施动态半径方案。我们可以获得我们称之为 的密度图 ,它显示了每个站点的净出发/到达。

*def DensityMap(stations, cnt_departure, cnt_arrival):London = [51.506949, -0.122876]

  map = folium.Map(location = London, 
                   zoom_start = 12, 
                   tiles = "CartoDB dark_matter")

  stations['Total Departure'] = cnt_departure
  stations['Total Arrival'] = cnt_arrivalfor index, row in stations.iterrows():
    net_departure = row['Total Departure'] - row['Total Arrival']

    _radius = np.abs(net_departure) 
    if np.isnan(_radius):
      _radius = 0

    if net_departure > 0:
      _color= '#E80018' # target red
    else:
      _color= '#81D8D0' # tiffany blue

    lat, lon = row['lat'], row['lon']
    _popup = '('+str(row['capacity'])+'/'+str(int(_radius))+') '+row['station_name']

    folium.CircleMarker(location = [lat,lon], 
                        radius = _radius, 
                        popup = _popup, 
                        color = _color, 
                        fill_opacity = 0.5).add_to(map)

  return map*

我在这里使用了不同的配色方案(目标红蒂芙尼蓝都是在美国注册的颜色)来显示某个车站的出发人数是多于还是少于到达人数。大圆圈标记代表较大的出发-到达差异。

让我们看看早晚高峰时段的密度图:

*# Select peak hoursTimeSlice = [25,53] # morning and evening
keyword = ['map_morning', 'map_evening']# Journeys depart between 0820 and 0859, and between 1740 and 1819
for ts, kw in zip(TimeSlice, keyword):
  df_1 = df[df["TimeSlice"] == ts]
  df_2 = df[df["TimeSlice"] == (ts+1)]
  df_target = df_1.append(df_2) cnt_departure = df_target.groupby("id_start").count().iloc[:,0]
  cnt_arrival = df_target.groupby("id_end").count().iloc[:,0] vars()[kw] = DensityMap(stations, cnt_departure, cnt_arrival)*

Density map in morning peak hours

Density map in evening peak hours

密度图在https://edenau.github.io/maps/density-morning/https://edenau.github.io/maps/density-evening/上可用。

连接图

前面提到的所有地图都关注车站而不是旅程,但是我们也可以通过我们所谓的连接地图,通过简单地在地图上绘制完成的旅程来可视化旅程。无需深究细节:**

Connection map

我们还可以通过folium.LayerControl()添加多层连接,将频繁使用和不频繁使用的路径分开。

Multi-layer connection map

连接图在https://edenau.github.io/maps/connection-morning/https://edenau.github.io/maps/connection-morning-layers/上都有。**

动画片

到目前为止,我们已经演示了如何通过图表可视化时间和分布信息,以及通过各种地图可视化空间信息。但是如果我们在连续的时间实例上生成多个地图呢?我们可以用动画来可视化时空信息!

生成的地图是中的 web 地图。html 文件。这个想法是:

为每个时间实例生成一个地图,在 web 浏览器上浏览,截屏并保存图片,并将所有图片链接成视频或. gif 文件。

我们将在[selenium](https://www.seleniumhq.org/)之前实现网页浏览和屏幕截图过程的自动化。我们还需要一个网络驱动,作为 Chrome 用户,我选择了chromedriver

**from selenium import webdriverdef a_frame(i, frame_time, data):
    my_frame = get_image_map(frame_time, data)

    # Save the web map    
    delay = 5 # give it some loading time
    fn = 'frame_{:0>5}'.format(i)
    DIR = 'frames'
    f = DIR + '/' + fn + '.html'
    tmpurl='file://{path}/{mapfile}'.format(path=os.getcwd()+
'/frames',mapfile=fn)
    my_frame.save(f) # Open the web map and take screenshot
    browser = webdriver.Chrome()
    browser.get(tmpurl)
    time.sleep(delay)
    f = DIR + '/' + fn + '.png'
    browser.save_screenshot(f)
    browser.quit() f = 'frames/frame_{:0>5}.png'.format(i)
    image = Image.open(io.BytesIO(f))
    draw = ImageDraw.ImageDraw(image)
    font = ImageFont.truetype('Roboto-Light.ttf', 30)

    # Add text on picture
    draw.text((20, image.height - 50), 
              'Time: {}'.format(frame_time),
              fill=(255, 255, 255), 
              font=font)

    # Write the .png file
    dir_name = "frames"
    if not os.path.exists(dir_name):
        os.mkdir(dir_name)
    image.save(os.path.join(dir_name, 'frame_{:0>5}.png'.format(i)), 'PNG') return image**

然后我们可以在[ffmpeg](https://www.ffmpeg.org/)之前制作视频或 gif。对于 Mac 用户来说,在自制软件的帮助下,安装ffmpeg简直不费吹灰之力,因为

家酿安装了你需要的苹果没有的东西。

安装 Homebrew(用一个命令)后,只需输入

**$ brew install ffmpeg**

瞧!要创建一个 .mp4 文件,请尝试

**$ ffmpeg -r 10 -i frames/frame_%05d.png -c:v libx264 -vf fps=25 -crf 17 -pix_fmt yuv420p video.mp4**

对于。gif 文件,试试

**$ ffmpeg -y  -t 3 -i frames/frame_%05d.png \ -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png$ ffmpeg -r 10  -i frames/frame_%05d.png -i palette.png -filter_complex \ "fps=10,scale=720:-1:flags=lanczos[x];[x][1:v]paletteuse" animation.gif**

查看全天密度图的动画:

Animation of density maps throughout a day

以及不同时间旅程的动画:

Animation of journeys in the morning

Animation of journeys after midnight

结论

伦敦的自行车共享系统使用条形图、密度图、连接图和动画进行可视化。

Python 的抽象使其成为时空数据可视化的非常好的工具(以计算时间为代价)。我利用了foliumseleniumchromedriverbrewffmpeg,以及最重要的,来自文森特代码的部分构建模块来实现这一点。

评论

如果您对 Python 或编程感兴趣,以下文章可能会有所帮助:

** [## 我希望我能早点知道的 5 个 Python 特性

超越 lambda、map 和 filter 的 Python 技巧

towardsdatascience.com](/5-python-features-i-wish-i-had-known-earlier-bc16e4a13bf4) [## 绝对初学者使用 XArray 处理 NetCDF 文件

探索 Python 中与气候相关的数据操作工具

towardsdatascience.com](/handling-netcdf-files-using-xarray-for-absolute-beginners-111a8ab4463f)

再次感谢 Vincent LonijDhrumil Patel 展示相关作品。

这项工作基于我的硕士论文 基于站点的自行车共享系统 的优化。敬请关注我即将发表的论文。

原载于我的博客edenau . github . io

参考

可视化气候变化

原文:https://towardsdatascience.com/visualizing-climate-change-65ea422cf2dd?source=collection_archive---------30-----------------------

Plotly 和 Dash 用于创建交互式可视仪表盘

Photo by Frederik Schönfeldt on Unsplash

几个月前,我写了一篇文章,将否认气候变化视为某种应用数据科学问题:收集数据,可视化趋势,并进行统计测试,以说明气候变化的影响已经显而易见。在过去的几周里,我更新了这个项目,增加了更多的城市(几乎所有美国人口排名前 100 的城市)和一个交互式仪表盘来展示结果。我很高兴地宣布,结果已经在 isclimatechangeabigdeal.com 的揭晓。

在这篇文章中,我将介绍什么是数据,它对气候变化意味着什么,并详细介绍如何创建一个仪表板。首先,这些数据向我们展示了什么?

数据和可视化

正如我在第一篇文章中所详述的,我从 NOAA 中提取了数据,其中有许多年来详细的历史天气和气候数据。出于几个原因,我关注两个指标,每日最高温度和每日最低温度。首先,考虑到提取这么多城市的数据需要多少 API 请求,提取多个不同的测量值很快就会变得很麻烦。另一个问题是,在整个观察期间,并非每个城市都有每个指标。一个可以说是更好的温度指标是日平均温度(考虑到温度在一天中的变化,这个数字不一定是一天中最高和最低温度的平均值),但许多城市没有追溯到 50 年代的每日累计数字。

目前的城市列表几乎与维基百科上按人口统计的美国城市列表完全相同,只有少数例外。维基百科上的一些城市没有 NOAA ids,我怀疑是因为它们离大城市太近了。例如,科罗拉多州的奥罗拉是更大的丹佛统计区域的一部分,这可以解释为什么它似乎没有单独存储的指标。丘拉维斯塔和圣地亚哥也是如此,亨德森和拉斯维加斯可能也是如此。不幸的是,内布拉斯加州的奥马哈也丢失了——似乎我在 NOAA 数据库中查看的一个或两个指标都不完整,并且我的一些 api 请求返回了空结果。我向奥马哈的人们道歉!我在寻找一个好的替代数据来源。

目前,我有三种方式汇总数据:对每日最大值和每日最小值进行逐年平均,并计算每年每日最大值超过 90 度的天数。从某些方面来说,这些都是用起来很钝的工具;首先,在一些地区,气候变化可能以更复杂的方式表现出来,而不仅仅是所有温度的上升或下降。尽管如此,我认为更大的趋势可能用平均指标来合理地表示。

我遇到的另一个问题是,将 90 度以上的天数作为度量标准有多敏感。NOAA 提供了每个测量站的数据,许多被调查的城市都有多个测量站。不同的站点并不总是有相同的每日最大值和最小值-考虑到一些城市的足迹有多大,这是有意义的。我需要决定如何汇总拥有多个测量站的每个城市的数据,我选择简单地将每个测量站的数据平均在一起。因此,如果某一天一些气象站的最大值超过 90,但其他气象站没有,并且所有气象站之间的平均值没有完全超过 90,则这一天不会计入该城市超过 90 的天数。因此,我的数字可能与其他地方的其他来源的数值不完全匹配——其他人可能会通过计算每天至少有一个站超过 90 或要求所有站都高于 90 来使该指标或多或少敏感。

右边仪表板的最后一块将你在过去 10 年中选择的指标与 20 世纪后半叶的平均值进行了比较。例如,在默认页面上,你会看到,与 1950 年至 2000 年期间相比,纽约的日平均最高气温在过去十年中上升了 1.25 度。当然,正如您将在图表中清楚看到的,这些指标每年都会有一点反弹,因此不同年份样本之间的差异很可能归因于样本的随机性。为了说明这一点,我还执行了一个统计测试来比较这两个平均值,并将结果显示为比值。这些概率都被四舍五入到一个合理的整数。

关于气候变化,这些数据说明了什么?

我鼓励你自己摆弄一下仪表盘,看看你的家乡(或离你家乡最近的大城市)的气温是否有显著变化。在我的探索中,几个趋势是显而易见的:

1。气候变化的影响因地而异。

在这个国家的不同城市或不同地区之间,趋势看起来非常不同。在一些城市,这一趋势看起来清晰而显著。以圣安娜为例,现在的平均日最高气温比 20 世纪高 2.5 度(日最低气温比 20 世纪高 4 度以上):

Average daily maximum temperatures by year in Santa Ana

相比之下,托莱多似乎没有太多的趋势。日平均最高气温上升了 0.6 度,但与年与年之间的差异相比,这一差异非常小。

Average daily maximum temperatures by year in Toledo

一些城市的日平均最高气温甚至有所下降,但是…

2。总体趋势倾向于变暖

如果我们观察到的唯一差异是由于随机抽样造成的,那么你会认为大约一半的城市看起来变暖了,而另一半看起来更冷了。事实并非如此。大多数城市都经历了某种程度的变暖。在这里显示的 86 个城市中,只有 5 个城市在过去十年里的日平均最高气温低于 20 世纪下半叶。如果你住在像丹佛这样的城市,你就不必太担心极端高温,因为过去十年的日平均最高气温比前一时期低了 1 度左右:

Average daily maximum temperatures by year in Denver

这是否意味着丹佛的居民知道气候变化对他们没有威胁就可以高枕无忧了?不完全是…

3。不同的指标揭示不同的趋势

如果您比较不同的可用指标,您有时会注意到非常不同的效果。丹佛最近看到平均每日最高值下降,但如果你看看每日最低值,你会看到相反的效果。在过去的十年里,日最低温度比以前高了 1.5 度以上:

Average daily minimum temperatures by year in Denver

这是怎么回事?嗯,每日最低气温上升的幅度超过了每日最高气温。天气和气候是复杂的系统,气候变化的不同方面有不同的方式。也许某个地区的最高温度更直接地取决于太阳总辐照度,并更受当地云量等因素的影响,而每日最低温度则受大气影响,即使云层阻止每日最高温度上升那么多,也可能相对于以前的时期上升。

所有这些都是说丹佛还没有完全摆脱困境。丹佛很可能正在经历气候变化的影响,这种影响不像日最高气温上升那么简单,但也同样重要。

技术细节

在 python 中,使用 Plotly 和 Dash 等工具构建这样的交互式仪表板并不复杂。Plotly 是一个非常强大的绘图工具,用最少的额外代码就可以制作出交互式的非常吸引人的图形。上面所有的温度图都是由几行代码组成的,如下所示:

关于 Plotly 的工作原理,需要理解的基本内容是,它在两个独立的对象中接收数据和布局信息。在我上面的例子中,数据是 plotly graph 对象的列表,图表中的每个元素对应一个 graph 对象。我有两行(指标和滚动平均值),所以我需要一个包含两个图形对象的列表。这些是由 x 和 y 数据的系列或列表加上特定类型的图表组成的——在本例中是线条。其他布局信息存在于布局对象中(在本例中,我只包含了一个图表标题)。Plotly 为创建了一个交互式的 html 对象,但是可以方便地保存一个静态的。如果你需要的话。

整个应用程序的代码稍微复杂一点。然而,Dash 允许您调整 python 中页面的 html 布局,并加入交互式元素。该应用程序的一个简单版本,只有一个城市和一个下拉菜单来选择指标,可以通过以下代码实现:

Dash 允许您向页面添加元素,并使用列表和字典从 python 控制底层 html。Dash 也方便地拥有自己的一套交互功能对象,比如我使用的下拉菜单、滑块或文本输入框。关键的事情是将输入与你希望它产生效果的元素恰当地联系起来。在更复杂的页面中,这可能意味着处理多个回调和元素 id。

希望这能启发你建立交互式仪表盘,并可能阻止即将到来的气候灾难。

可视化漫画人物的性别和超能力

原文:https://towardsdatascience.com/visualizing-comic-characters-genders-and-superpowers-ae7c2311cb89?source=collection_archive---------19-----------------------

如何使用 D3 & React 创建带工具提示的堆积条形图?以及关于漫画、性别和超能力的简短讨论

A small piece of the final chart

摘要

1。可视化超能力和性别

2。查询漫画数据

3。创建 React 组件

4。设置工具提示

5。参考资料学习 D3 &反应积分

React 和 D3 是我在这里使用的工具。我指出这个版本不同于常规 D3 版本的核心部分,常规 D3 版本基于enter()exit()update()

我写这篇文章是为了了解一点 D3 并且想用 React 方式编码的人。如果你不知道如何使用 React 编码,我强烈推荐 Scrimba 上的这个 100%免费互动 课程

https://github.com/heberleh/learn-react-d3/】这是 GitHub 条形图库:

这是我漫画人物系列的第二部分:

  1. 用 SQL 和 Javascript 创建漫威数据库,最简单的方法
  2. 形象化漫画人物的性别和超能力【这】
  3. 用数据可视化比较漫威和 DC

Legend of Marvel & DC visualization: https://heberleh.github.io/comics-universe/

1。可视化超能力和性别

本节首先引导您进入交互式条形图,并描述有关该图的详细信息。然后,它给你一个关于漫画人物的能力和性别的简单讨论。

交互式堆积条形图

https://heberleh.github.io/learn-react-d3/

我的意图是展示男性、女性和其他性别在超级能力中的分布,同时展示超级能力的受欢迎程度。在这种情况下,堆积条形图是一个合理的选择。

每个条形代表一种能力。它的大小代表字符的数量。全部来自 Wikidata。

鼠标悬停会显示该技能的详细信息,如描述和数字。

我在这张图表中使用了许多颜色。如果我想关注一些特定的信息,这可能会被认为是杂乱的。

例如,在漫威& DC 可视化中显示的条形图中,我只选择了 2 种颜色。一个是黑暗,另一个是突出非男性角色多于男性角色的能力。

这里我只使用了来自任何虚构世界的喜剧角色的实例;在漫威和 DC 的可视化中,我使用了虚拟角色的实例和子类,从虚拟宇宙等于漫威/DC。

解释和讨论

当解释这个情节时,我们需要考虑到,事实上,在大多数(如果不是全部的话)虚构的宇宙中,男性多于女性和其他性别。我们可以预计每个宇宙中平均有 60%到 70%的角色是男性。因此,在大多数受欢迎的能力中,也期待更多的男性。

另一方面,我们可以发现女性人数多于男性的不太受欢迎的技能。其中有力场植身术冷冻术气动术弹力术概率操纵后知后觉御血术。有什么历史或社会事实可以解释吗?

Marvel Premier — Dark Phoenix Artist Proof by theopticnerve. Under CC BY-NC-ND 3.0

很少有角色的性别不同于男性和女性。

在图中发现的一个性别被命名为agender——查看绿色条。

那就是凤凰力的情况。

性别、种族和其他因素比以前被更多地讨论,作者们也更加关注它。

举个例子,Jacques Nyemb 讨论了这个话题的一些优点。在第篇文章中,他写道他的漫画是有关联的:

“我得出了一个我不想得出的结论。读者是白人男性,而我的角色是黑人。”

雅克还写了他在创造一个虚构的科学家,一个白人男性时的第一个想法:

“……我很快问自己为什么没有一个女科学家?一个黑人中年人?她的动机在我的新故事中比我坚持原来的想法更有意义。”

对我来说,我不是专家,任何想要与我们的现实相联系的宇宙都需要代表不同的人和文化来保持一致。创造一个多样化的虚构世界是为了包容和更接近我们的现实,特别是当它的观众是整个世界的时候。

2.查询漫画数据

为了创建一个图表来显示有多少角色具有每种能力(堆叠的条形大小)以及这些数字如何在性别(颜色、条形)之间分布,我从漫画数据库中查询了一个包含以下信息的表:

  • 性格;角色;字母
  • 能力
  • 性别

要使用这个数据库,你只需要下载一些。js 和。json 文件并导入,然后可以使用 SQL 命令进行查询。如果你想了解如何从维基数据中查询数据并创建一个 Javascript 数据库,请查看第一篇文章。这是我的SELEC命令:

经过一些数据处理后,我的数据形成为:

  • labels矢量:性别标签
  • data:每个能力一个向量,包含每个性别的字符总数向量,根据labels索引

示例:

我定义了堆叠条形图组件接收数据模型作为输入。它包含获取标签和总计的数据和辅助函数:

你可以在这里找到skillsDistributionByGender()的完整代码。

3.创建 React 组件

在定义了我的数据集之后,我开始基于这篇文章和 Kacper Goliński 的代码创建一个简单的条形图。

如果您没有使用 React 和 D3 创建任何图表,您可能会发现从一个简单的条形图开始更容易,然后回来检查我是如何做堆叠图的以及我是如何添加工具提示的。

Kacper 还实现了 ResponsiveWrapper ,它根据可见窗口的宽度控制图表的width

在这一点上,我认为你知道create-react-app。如果没有,就去搜索一下,或者查一下我开头提到的课程。

我们最终的 SVG 将有两个主要的 React 组件,负责显示 y 轴和技能的标签(<Axes/>)以及堆叠的条形图(<StackedBars/>)。我设置了一个额外的组件来控制工具提示,显示在每个条的鼠标上(<ReactTooltip/>):

集成 D3 和 React 有不同的方法

第一种方法是使用 React 对应用程序进行模块化,并使用 D3 通过 enter()、update()和 exit() 来控制 SVG 元素。

第二种方法是使用 React 控制所有 SVG 元素,这对 React 应用程序更有意义。因此,我们不会调用.attr('width', 200),而是将它直接设置为组件或 SVG 元素,如下例所示:

这段代码返回了<rect>元素,我们将把这些元素放入一个<g>中,对每个条形/能力的矩形进行分组。因此,我们可以将它添加到一个函数中,并为每个能力调用它,代码如下:

这段代码将为每个能力创建一个<g>和一个最终的<g>,其中包含了构成图表的所有条形。我们可以在 React 组件中编写所有这些代码,就像我在我的<StackedBars /> ( 见这里)中所做的那样。

最初,我创建了xy轴,但是我意识到实际的轴在我的图表中是不必要的信息。

去掉对你的观众来说不重要的东西可以减少混乱!

因此,我让 y 轴保持原样,只使用 CSS 样式stroke-opacity: 0省略了pathline元素(你可以试试display:none)。通过移除 React 组件调用,我省略了 x 轴。

这是 React & D3 集成的第二个重要案例,因为d3.axis函数需要 SVG 元素来绘制。这意味着我们不能调用d3.axis并获得一个将在 React 组件中返回的 SVG 元素,就像我们在上一个例子中所做的那样。

在这种情况下,我们需要给 D3 对 DOM 的临时控制权。为此,我们选择引用当前组件的元素,并告诉 D3 处理它。这里有一个例子:

我们用ref={(el) => { this.axisElement = el; }}设置轴节点(见上图),然后用 D3 选择它,并调用 D3 轴函数,就像这里的d3.select(this.axisElement).call(axis)一样,这将追加轴元素。

上面的例子将在<g>元素中绘制轴,并且我们在渲染后将其全部返回给父组件。

"ref更新发生在componentDidMount或组件更新生命周期方法之前"-文档

因此,我们的代码首先执行this.axisElement = el,然后执行renderAxis()

在结论中,我们定义了使用 React 和 D3 创建 SVG 可视化的两种主要方法:

  1. 声明性地:你控制 SVG 元素;
  2. refs :赋予 D3 对特定被引用节点的控制权。

根据 React 文档,首选第一种,尽可能避免第二种。如果 D3 中的函数返回 SVG 元素,你可以声明性地使用结果(不使用 ref),否则,ref似乎是避免进入退出更新函数的唯一方法。

4.设置工具提示

创建工具提示的一种方法是为每个条或堆叠的条构建一个单独的组件;另一种方法是构建一个控制所有工具提示的组件。

这就是反应工具提示的作用。你只需要在工具提示出现的地方设置一些属性,以及 SVG 之外的一个组件<ReactTooltip/>的属性。在工具提示将出现的元素中,您设置了两个属性:数据-提示数据-用于。第一个是文本,第二个是 ReactTooltip 组件 id,如下所示:

ReactTooltip website: https://www.npmjs.com/package/react-tooltip

5.学习 D3 和 React 集成的参考资料

到目前为止,我已经接触了三个主要活跃作者的内容,他们使用 D3 和 React,创建教程并分享他们的代码:

6.在幕后

这些是我在编码图表时拍摄的一些屏幕截图。如你所见,我开始展示这些轴,最后却把它们拿走了。

See all these lines and axes? I don’t need them here.

Adjusting the bar sizes and placement.

请留下您对任何主题的评论或私人笔记。

谢谢你看我的文章!

用 Neo4j 可视化图形中的文本嵌入和上下文

原文:https://towardsdatascience.com/visualizing-context-with-googles-universal-sentence-encoder-and-graphdb-c5f92b2f3db3?source=collection_archive---------16-----------------------

Neo4j 中的句子嵌入和图形连接

Photo by Alina Grubnyak on Unsplash

介绍

定量分析文本的挑战之一是对字符串进行分类。比方说,我们想研究现有客户的职业概况。我们希望根据他们的专业背景向他们发送有针对性的活动。我们的顾客来自各种背景。当一个人创建一个个人资料时,有些字段是他们作为自由文本输入的。职业就是其中之一。由于这些是自由文本字符串,具有相似职业(相似行业或工作)的人可能会以不同的方式输入他们的。

Figure 1: Example of Occupations (source: Image by author)

我们想要解决基于上述场景的问题。我们必须根据客户注册时输入的职业,为他们创建不同内容的有针对性的交叉销售活动。

我们有大约 10,000 个不同的字符串,我们希望将这些字符串按照客户的职业分为 30 到 40 个行业特定的组。我们发现了许多与工程师、医生、艺术家、国防、教育、设计师、劳工、警卫、食品、交通、企业主等相关的主题。挑战在于以无人监管的方式找到这些主题。

这是嵌入模型的一个很好的用例。随着 Word2Vec、Glove、ELMo 和最近的 BERT 等模型的出现,轻松解决复杂的 NLP 任务已经成为可能。在本文中,我们将尝试理解,对于多单词字符串,句子嵌入比单词嵌入的优势。此外,我们将看到如何使用这些嵌入来分析图形数据库 Neo4j 中相似字符串内的“概念转移”。

大声喊出单词嵌入!

像 Word2Vec 和 glove 这样的模型无疑为我们的生活提供了“背景”,使之变得更容易。这些模型已经在来自各种来源的大型语料库上被训练。这些模型背后的直觉是,

在同一语境中出现和使用的词在语义上彼此相似,具有相似的意义。

这些模型使我们能够使用迁移学习来完成 NLP 任务。我们可以直接使用这些模型的嵌入来获得固定大小的浮动向量,或者在我们的语料库上微调模型。这使我们能够用少量的数据找到有意义的聚类。

数据挑战

Figure 2: Challenges in Data (source: Image by author)

上图显示了客户输入的实际字符串,我们认为这些字符串可以归入“医疗”类别。通过观察字符串,我们可以直接看到数据中的一些挑战:

  • 拼写错误——Doctor 写成 Doctor
  • 不止一个词——骨科医生
  • 缩写——医生写成 Dr
  • 各种类型的医生——神经外科医生、牙医、医疗主管等。

因此,我们需要一种方法,以某种方式将所有这些字符串组合在一起。实现这一点的一种方法是使用 Word2Vec 模型。Word2Vec 是一个在大型语料库上训练的神经网络,它为每个单词提供固定大小的浮点数向量。出现在相似上下文中的单词有相似的向量。所以,“博士”、“docter”、“dr”都用在相似的语境中,因此有相似的嵌入。

然而,我们的数据可能包含多个单词字符串,我们希望使用模型进行推理,而不是进行微调。Word2Vec 返回一个单词的向量。一种方法是对多单词串中每个单词的嵌入取平均值。尽管这种策略可能适用于我们的职业数据,但对于较长的句子,它不会产生很好的结果。因为我们对每个单词进行平均嵌入,所以我们失去了整个句子的上下文。这就是句子编码器的用武之地。谷歌的通用句子编码器,嵌入任何可变长度的文本到一个 512 大小的矢量中。TF-hub 上有两种型号可供选择。一个是基于变压器网络,第二个是基于深度平均网络 的嵌入。要理解这些是如何工作的,请看谷歌研究中心的这篇论文。

让我们举一些具体的例子来理解对于多单词串,句子嵌入比单词嵌入的优势。假设我们有两种职业——“专业牙医”和“医疗顾问”。因为这两个职业都属于医学领域,我们可以预期它们有相似的嵌入,因此有很高的余弦相似性。让我们看看下面两种方法返回的余弦相似性的比较。

方法 1 —取 Word2Vec 嵌入的平均值

Figure 3.1: Word2Vec approach (source: Image by author)

在这里,我们首先将字符串拆分成单词,并使用Gensim(Google news-vectors-negative 300)中的 Word2Vec 模型获得单词嵌入。我们取相应职业返回的单词嵌入向量的平均值。然后,我们计算两个平均向量之间的余弦相似度。

方法 2——使用谷歌句子编码器

Figure 3.2: Sentence Encoder approach (source: Image by author)

这里,我们使用来自 Tensorflow hub 的 DAN 模型得到句子嵌入。然后我们简单地取返回向量之间的余弦相似性。

我们可以看到第二种方法给了我们更好的结果。与 Word2Vec 和 Google 通用句子编码器的更多余弦相似性比较:

Figure 4: Comparison of cosine similarities (Word2Vec vs Sentence Encoder) (source: Image by author)

对于所有的职业对,我们观察到句子编码器执行单词嵌入。这是可以理解的,因为“专家”可以是任何人。因此,Word2Vec 为“专家”返回的嵌入是通用的,并不依赖于单词“牙医”(参见图 3.1)。同样,第二职业中的“顾问”可以是任何职业。句子编码器返回与单词“Healthcare”和“Consultant”相互依赖的嵌入。因此,我们得到具有更高余弦相似性的嵌入向量。
此外,请注意句子编码器为汇丰员工和银行经理返回的高余弦相似性。算法知道汇丰是银行!在我们拥有少量数据的情况下,我们无法使用计数矢量器和 tf-idf 方法实现这一点。

可视化嵌入

一旦我们有了字符串的嵌入,我们使用 t-SNE 将数据的维度从 512(句子编码向量的大小)减少到 2。此外,我们使用 K 个最近邻生成多个聚类。
我们使用 plotly express 围绕 plotly graph 对象的高级包装器在散点图上绘制结果。

Figure 5: 2D t-SNE clusters for Occupation (source: Image by author)

正如我们在上面看到的,相似的职业已经聚集在一起。例如,所有与纺织相关的职业(天蓝色的集群),如“裁缝”、“女装店”、“纱丽批发店”、“roohi 服装”,彼此之间的距离越来越近。我们可以把所有这些分类归入“纺织品”一类。同样,所有与“教育”相关的职业(紫色部分)都聚集在一起。左边的绿色污迹是一类严重的拼写错误,与其他聚类完全不同,因此彼此相似:)

用 Neo4j 跟踪图中的概念

t-SNE 图能够给我们的数据一个静态的 2D 表示。类似地,嵌入的相关图会给我们职业字符串之间的一级关系。如果我们想跟踪二级或二级以上的关系呢?

为了做到这一点,我们可以创建一个图表,其中每个职业都与另一个职业有关联。大概是这样的:

Figure 6: Graph schema for storing strings (source: Image by author)

在这里,“律师”与“最高法院法官”有二级联系。边(关系)的权重表示节点之间的余弦相似性。注意,我们只连接余弦相似度≥ 0.75 的那些节点。这确保了只有高度相关的数据在图中被连接。

上述模式在 Neo4j 中得到了应用。最常用的图形数据库之一。一定要观察它是如何从“概念”转移到“概念”的。
(注意:如果在浏览器上,强烈建议放大以便更好地查看)

  1. 先导

Figure 7.1: Graph of “Pilot” (source: Image by author)

主题 1——酒店试点

飞行员->航空->航空专业->空乘->机舱服务员->酒店工作->其他酒店工作

主题 2——飞行员对国防

飞行员->空军->陆军->海军和商船队

飞行员既可以是私人航空公司的飞行员,也可以是空军飞行员。这就是我们在上述两个主题中看到的。一个分支走向接待,另一个分支走向防御。

2.作家

Figure 7.2: Graph for “Writer” (source: Image by author)

主题——作家对新闻记者

作家->文档作家->编辑->记者->记者->电视新闻记者

3.机械师

Figure 7.3: Graph for Mechanic (source: Image by author)

主题—技工到建筑工人和结构工程师

技工->交流技工->交流技术员->电工->焊工->钢筋工->建筑

4.摄影师

Figure 7.4: Graph for Photographer (source: Image by author)

主题 1——摄影师到建筑师

摄影师->时尚摄影师->服装设计师->室内设计师->建筑师

他们 2 —拍摄素材的摄影师

摄影师->视觉特效艺术家->助理摄影师->视频导演->电影制作人->更多电影素材

5。农民

Figure 7.5: Graph for Farmer (source: Image by author)

主题——奶农到牛奶供应商

农民->农业->奶牛场->牛奶和奶制品企业->牛奶供应商

最后的想法

结合嵌入的图成为理解信息流的强大可视化工具。我们提供了一个简单的例子,说明如何使用图表来理解和跟踪文本文档中的上下文。由于问题的小性质,很容易理解为什么“飞行员”既指向“空军”,又指向“酒店”。然而,

我们可以将其扩展到更大文档的应用程序,如研究论文、法律文档、书籍,并在图表上构建推荐或搜索系统。

如果你想了解更多关于文本嵌入的知识,可以看看这篇令人惊叹的文章:自然语言处理的深度迁移学习,作者 Dipanjan (DJ) Sarkar

用 Pytorch 可视化卷积神经网络

原文:https://towardsdatascience.com/visualizing-convolution-neural-networks-using-pytorch-3dfa8443e74e?source=collection_archive---------2-----------------------

Photo by Karsten Würth (@karsten.wuerth) on Unsplash

卷积神经网络 (CNN)是另一种类型的神经网络,可用于使机器可视化事物并执行任务,如图像分类、图像识别、对象检测、实例分割等。但神经网络模型通常被称为“黑盒”模型,因为很难理解模型如何学习输入中存在的复杂依赖关系。此外,很难分析为什么在推断过程中做出给定的预测。

在本文中,我们将探讨两种不同类型的可视化技术,例如:

  1. 可视化学习的滤波器权重。
  2. 对图像执行遮挡实验。

这些方法帮助我们理解过滤器学习什么?什么样的图像会导致某些神经元放电?输入图像的隐藏表示有多好?。

引用注: 本文内容和结构基于四分之一实验室深度学习讲座——帕德海 。如果你有兴趣,可以去看看那里的课程。

神经元感受野

在我们继续和可视化卷积神经网络的工作之前,我们将讨论 CNN 中存在的过滤器的感受野。

假设我们有一个两层卷积神经网络,并且我们通过网络使用 3×3 滤波器。第 2 层中以黄色标记的中心像素实际上是对第 1 层中的中心像素应用卷积运算的结果(通过使用 3×3 内核和步长= 1)。类似地,层 3 中存在的中心像素是对层 2 中存在的中心像素应用卷积运算的结果。

神经元的感受野定义为输入图像中能够影响卷积层中神经元的区域,即……原始图像中有多少像素正在影响卷积层中的神经元。

很明显,层 3 中的中心像素依赖于前一层(层 2)的 3×3 邻域。存在于层 2 中的包括中心像素的 9 个连续像素(用粉红色标记)对应于层 1 中的 5×5 区域。随着我们在网络中越来越深入,更深层的像素将具有高感受野,即……相对于原始图像的感兴趣区域将更大。

从上面的图像中,我们可以观察到,第二卷积层中突出显示的像素相对于原始输入图像具有较高的感受野。

可视化 CNN

为了形象化 CNN 的工作,我们将探索两种常用的方法来理解神经网络如何学习复杂的关系。

  1. 使用预先训练的模型进行过滤可视化。
  2. 使用预训练模型进行遮挡分析。

在 Colab 中运行此笔记本

文章中讨论的所有代码都在我的 GitHub 上。在 Github 上直接打开my Jupyter Notebook with Colab 可以用任何设置打开 code notebook,Colab 运行在 Google 的虚拟机上。如果您只想快速打开笔记本并按照本教程进行操作,请单击此处的。

在执行 Colab 中的代码之前,不要忘记将输入图像文件夹(可以从 Github Repo 下载)上传到 Google Colab。

[## niranjankumar-c/deep learning-PadhAI

来自 pad hai-Niranjankumar-c/deep learning-pad hai 的深度学习课程相关的所有代码文件

github.com](https://github.com/Niranjankumar-c/DeepLearning-PadhAI/tree/master/DeepLearning_Materials/6_VisualizationCNN_Pytorch)

可视化输入图像

在本文中,我们将使用包含 1000 个类别的 ImageNet 数据集的一个小子集来可视化模型的过滤器。数据集可以从我的 [GitHub repo](http://If you want to skip the theory part and get into the code right away,) 下载。

为了可视化数据集,我们将实现自定义函数imshow

函数imshow有两个参数——张量中的图像和图像的标题。首先,我们将针对 ImageNet 平均值和标准偏差值执行图像的逆归一化。之后,我们将使用matplotlib来显示图像。

Sample Input Image

过滤器可视化

通过可视化训练模型的过滤器,我们可以了解 CNN 如何学习图像中存在的复杂的空间和时间像素依赖性。

过滤器捕捉什么?

假设我们有大小为 4x4 的 2D 输入,我们从图像的左上角开始对图像应用 2x2 的过滤器(用红色标记)。当我们在图像上从左到右、从上到下滑动内核来执行卷积运算时,我们会得到比输入更小的输出。

每个卷积运算(如 h₁₄)的输出等于输入向量和权重向量的点积。我们知道,两个向量之间的点积与向量之间夹角的余弦成正比。

在卷积运算过程中,当我们在输入图像的某些部分(如包含狗脸的图像部分)上应用滤镜时,这些部分可能会给出较高的值。在上面的例子中,让我们讨论在什么样的情况下我们的输出 h₁₄会很高?。

如果矢量之间的余弦值很高,即……余弦值应该等于 1,则输出 h₁₄会很高。如果余弦角等于 1,那么我们知道向量之间的角度等于 0⁰.这意味着输入向量(图像的一部分) X 和权重向量 W 都处于神经元将最大程度地触发的相同方向。

当输入 X (用于卷积的图像的一部分)等于单位向量或单位向量的倍数时,在滤波器向量 W 的方向上,神经元 h₁₄将最大程度地激发。

换句话说,我们可以把滤镜想象成一个图像。当我们在输入上从左到右、从上到下滑动过滤器时,只要过滤器与输入的类似部分重合,神经元就会触发。对于输入图像中与滤镜不对齐的所有其他部分,输出将会很低。这就是我们称核或权重矩阵为过滤器的原因,因为它过滤掉输入图像中与过滤器不一致的部分。

要了解过滤器学习哪种模式,我们可以绘制过滤器,即…与过滤器相关的权重。对于过滤器可视化,我们将使用预先用 ImageNet 数据集训练的 Alexnet。

#alexnet pretrained with imagenet data
#import model zoo in torchvisionimport torchvision.models as models
alexnet = models.alexnet(pretrained=True)

Alexnet 包含 5 个卷积层和 3 个全连接层。ReLU 在每次卷积运算后应用。请记住,在 3D (RGB)图像的卷积运算中,由于内核和图像具有相同的深度,因此内核不会随深度移动。我们将以两种方式可视化这些过滤器(内核)。

  1. 通过将三个通道组合成一个 RGB 图像来可视化每个滤镜。
  2. 使用热图独立显示过滤器中的每个通道。

绘制重量的主要功能是plot_weights。该函数有 4 个参数,

model — Alexnet 模型或任何经过训练的模型

layer_num —卷积层数以可视化权重

single_channel —可视化模式

collated —仅适用于单通道可视化。

plot_weights函数中,我们采用训练好的模型并读取该层号处的层。在 Alexnet (Pytorch model zoo)中,第一卷积层用层索引零来表示。一旦我们提取了与该索引相关的层,我们将检查该层是否是卷积层。因为我们只能看到卷积层。在验证层索引之后,我们将提取该层中存在的学习重量数据。

#getting the weight tensor data
weight_tensor = model.features[layer_num].weight.data

根据输入参数single_channel,我们可以将重量数据绘制成单通道或多通道图像。Alexnet 的第一个卷积层有 64 个大小为 11x11 的滤镜。我们将以两种不同的方式绘制这些过滤器,并了解过滤器学习哪种模式。

可视化过滤器—多通道

single_channel = False的例子中,我们有 64 个深度为 3 (RGB)的滤镜。我们将把每个过滤后的 RGB 通道合并成一个大小为 11x11x3 的 RGB 图像。结果,我们将得到 64 个 RGB 图像作为输出。

#visualize weights for alexnet — first conv layer
plot_weights(alexnet, 0, single_channel = False)

Filters from first convolution layer in AlexNet

从这些图像中,我们可以解读出内核似乎学会了模糊的边缘、轮廓和边界。例如,上图中的图 4 表示过滤器正在尝试学习边界。类似地,图 37 表明过滤器已经学习了轮廓,这可以帮助解决图像分类的问题。

可视化过滤器—单通道

通过设置single_channel = True,我们将过滤器中的每个通道解释为一个单独的图像。对于每个滤波器,我们将得到代表每个通道的 3 个单独的图像,因为对于第一次卷积运算,滤波器的深度是 3。总之,我们将有 64*3 的图像作为可视化的输出。

Filters from the first convolution layer in AlexNet (A subset out of 192 images)

从上图中,我们可以看到总共 64 个滤波器(0–63)中的每个滤波器通道都是单独可视化的。例如,图 0,0 表示图像表示对应于第零通道的第零滤波器。类似地,图 0,1 表示图像表示对应于第一通道的第零个滤波器,依此类推。

单独可视化过滤器通道可以更直观地了解不同过滤器基于输入数据正在尝试学习什么。通过仔细观察过滤器可视化,可以清楚地看到,在来自同一过滤器的一些通道中发现的模式是不同的。这意味着并非滤波器中的所有通道都试图从输入图像中获取相同的信息。随着我们越来越深入网络,过滤模式变得越来越复杂,它们倾向于捕捉高层次的信息,如狗或猫的脸。

随着我们越来越深入到网络中,用于卷积的滤波器数量也在增加。我们不可能将所有这些滤光器通道单独可视化为单个图像或单独的每个通道,因为有大量这样的滤光器。Alexnet 的第二卷积层(在 Pytorch 顺序模型结构中索引为层 3)具有 192 个过滤器,因此我们将得到 192*64 = 12,288 个单独的过滤器通道图用于可视化。绘制这些过滤器的另一种方法是将所有这些图像连接成一个带有灰度的热图。

#plotting single channel images
plot_weights(alexnet, 0, single_channel = True, collated = True)

Filters from the first convolution layer in AlexNet — Collated Values

#plotting single channel images - second convolution layer
plot_weights(alexnet, 3, single_channel = True, collated = True)

Filters from the second convolution layer in AlexNet — Collated Values

#plotting single channel images - third convolution layer
plot_weights(alexnet, 6, single_channel = True, collated = True)

Filters from the third convolution layer in AlexNet — Collated Values

如您所见,在第一个卷积图层的图像中有一些可解释的特征,如边缘、角度和边界。但是随着我们深入网络,解释过滤器变得更加困难。

图像遮挡实验

执行遮挡实验以确定图像的哪些碎片对神经网络的输出贡献最大。

在一个图像分类问题中,我们如何知道模型实际上是在拾取一个感兴趣的对象(例如汽车车轮),而不是周围的背景图像?。

在遮挡实验中,我们通过用设置为零的灰色补片遮挡图像的一部分并监控分类器的概率,来系统地迭代图像的所有区域。

例如,我们通过灰化图像的左上角来开始遮挡实验,并通过将修改后的图像通过网络来计算特定类别的概率。类似地,我们将迭代图像的所有区域,并查看每个实验的分类器的概率。上图中的热图清楚地显示,如果我们遮挡我们感兴趣的对象,如车轮或狗的脸(深蓝色区域),真实类别的概率会显著下降。

遮挡实验告诉我们,我们的卷积神经网络实际上正在学习一些意义模式,如从输入中检测狗的脸。这意味着该模型真正选择了狗的位置,而不是根据周围的环境(如沙发或躺椅)来识别。

为了清楚地理解这个概念,让我们从我们的数据集中取一个图像,并在其上进行遮挡实验。

对于遮挡实验,我们将使用在 ImageNet 数据上预先训练的 VGG-16。

#for visualization we will use vgg16 pretrained on imagenet data
model = models.vgg16(pretrained=True)

为了进行实验,我们需要编写一个自定义函数来对输入图像进行遮挡。函数occlusion有 6 个参数——模型、输入图像、输入图像标签和遮挡超参数。遮挡超参数包括遮挡片的大小、遮挡步幅和遮挡像素值。

首先在函数中,我们得到输入图像的宽度和高度。之后,我们将基于输入图像尺寸和遮挡片尺寸来计算输出图像的宽度和高度。然后,我们将根据输出的高度和宽度初始化热图张量。

现在,我们将遍历热图中的每个像素。在每次迭代中,我们将计算原始图像中要替换的遮挡片的尺寸。然后,我们用指定位置的遮挡补丁替换图像中的所有像素信息,即…通过用灰色补丁替换特定区域来修改输入图像。一旦我们有了修改后的输入,我们将通过模型进行推理,并计算真实类别的概率。然后,我们用概率值更新相应位置的热图。

获得热图后,我们使用 seaborn 绘图仪显示热图,并将梯度的最大值设置为概率。

Occlusion Heatmap

从热图上看,颜色越深代表概率越小,意味着该区域的遮挡非常有效。如果我们在原始图像中用较暗的颜色遮挡或覆盖该区域,那么分类该图像的概率显著下降(小于 0.15)。

[## niranjankumar-c/deep learning-PadhAI

来自 pad hai-Niranjankumar-c/deep learning-pad hai 的深度学习课程相关的所有代码文件

github.com](https://github.com/Niranjankumar-c/DeepLearning-PadhAI/tree/master/DeepLearning_Materials/6_VisualizationCNN_Pytorch)

下一步是什么?

如果你想用 Keras & Tensorflow 2.0 (Python 或者 R)学习更多关于人工神经网络的知识。查看来自 Starttechacademy 的 Abhishek 和 Pukhraj 的人工神经网络。他们以一种简单化的方式解释了深度学习的基础。

结论

在这篇文章中,我们讨论了神经网络的感受野。之后,我们讨论了两种不同的方法来可视化 CNN 模型以及 Pytorch 实现。可视化神经网络模型使我们更直观地了解如何为广泛的应用程序改进模型的性能。

推荐阅读

[## 理解卷积神经网络 ELI5 方法

了解卷积运算和 CNN 的

towardsdatascience.com](/understanding-convolution-neural-networks-the-eli5-way-785330cd1fb7) [## Pytorch FashionMNSIT 数据集影像分类简介

在这篇博客文章中,我们将讨论如何建立一个卷积神经网络,可以分类时装 MNIST 数据使用…

www.marktechpost.com](https://www.marktechpost.com/2019/07/30/introduction-to-image-classification-using-pytorch-to-classify-fashionmnist-dataset/)

如果你在实现我的 GitHub 库中的代码时遇到任何问题,请随时通过 LinkedIn 或 T2 Twitter 联系我。

直到下次和平:)

NK。

免责声明——这篇文章中可能会有一些相关资源的附属链接。你可以以尽可能低的价格购买捆绑包。如果你购买这门课程,我会收到一小笔佣金。

用 Python 和 Graphviz 在 Jupyter 笔记本中可视化决策树

原文:https://towardsdatascience.com/visualizing-decision-trees-in-jupyter-notebook-with-python-and-graphviz-78703230a7b1?source=collection_archive---------3-----------------------

决策树回归器和分类器被广泛用作独立的算法或更复杂模型的组件。为了正确理解算法内部是如何做出某些决定的,将它们可视化是至关重要的,这对于业务应用程序来说总是很重要的。

https://unsplash.com/photos/tGTVxeOr_Rs

在这个简短的教程中,我想简单描述一下从 sklearn 库中可视化决策树模型的过程。注意:运行下面的代码需要安装和配置 Graphviz。

作为一个玩具数据集,我将使用一个众所周知的虹膜数据集。让我们导入主库并下载实验数据。

现在,我们将创建一个简单的决策树分类器,并将其应用于整个数据集。

最后,有趣的步骤来了。我们将拟合的决策树导出为一个。dot 文件,这是 graphviz 文件的标准扩展名。这个 tree.dot 文件将会保存在你的 Jupyter 笔记本脚本所在的目录下。不要忘记包含特征名称参数,该参数表示特征名称,将在显示树时使用。

现在,通过运行下面的命令,我们将转换。点档到档。png 文件。这只适用于 Jupyter 笔记本,如“!”符号表示该命令将直接在控制台中执行。

在这个操作之后,tree.png 文件将出现在同一个文件夹中。现在我们可以很容易地显示它,使用众所周知的库。

你会看到下图。

完整的 Jupyter 笔记本代码:

结论

如您所见,可视化决策树可以通过使用 export_graphviz 库轻松完成。不过,设置 grahpviz 本身可能是一项相当棘手的任务,尤其是在 Windows 机器上

推荐书籍

使用 Scikit-Learn 进行机器实践学习

用 Python 实现机器学习和深度学习

Python 机器学习简介:数据科学家指南

可视化不同的 NFL 球员风格

原文:https://towardsdatascience.com/visualizing-different-nfl-player-styles-88ef31420539?source=collection_archive---------16-----------------------

CC by 2.0

不同的玩家有不同的优点和缺点——有没有一种方法可以将它们形象化?

介绍

早在 21 世纪初,纽约巨人队就有一对令人兴奋的跑卫搭档。Tiki Barber(“闪电”)一年跑了大约 1000 码,接了 550 码。这本身就令人印象深刻,但更令人印象深刻的是,早期的第一轮选手罗恩·戴恩(“雷霆”)也在同一支球队。戴恩的总码数不太令人印象深刻(大约 40 码/场),但他获得的码数都很难获得,他获得了大量的达阵机会。他在球门线,后面不远。不难理解他们的绰号是怎么来的。

在整个联盟中,在所有的位置上,在同一个位置上有不同的球员风格和球员角色。使用主成分分析 (PCA)和聚类算法,我们可以很容易地将这些球员分成不同的类别,这样做没有可能来自电影研究的偏见。PCA 和聚类算法听起来很奇特,但它们非常直观。我远不是第一个做这种分析的人——这里有一个来自纳迪尔·尼布拉斯的 NBA 球员相同过程的伟大版本。

步骤 1:选择功能

对玩家进行分类的第一步是找出是什么将某些玩家与其他玩家区分开来。有非常明显的特征,像每场比赛的码数或一个赛季的达阵数。你不需要无监督的学习算法来区分 Cam Newton 和 Blaine Gabbert,如果这就是我所比较的,那么这篇文章现在应该已经结束了。身高和体重也是显而易见的特征,尤其是如果你看过蒂基·巴伯和罗恩·戴恩的话,所以我从 pro-football-reference.com 那里收集了他们的资料。我最终为每个玩家提供了相当多的特性,只要它们都是相关的,这并不是一件坏事。我选择的特征是主观的,并且是可以讨论的!

  1. 年龄/身高/体重——不言自明
  2. 每场比赛的回退—不言自明
  3. 完成率、TD 率、INT 率——完成率、触地得分率和截球率除以总回球率
  4. Sack 率,QB 命中率——sack 很重要,因为只需要一个就可以杀死一个驱动器。我考虑包括平均码损失和标准偏差码损失的麻袋,但我认为这只会增加噪音。像埃利·曼宁和山姆·布拉德福德这样的四分卫不会在口袋里移动,当他们感到压力时,他们只会龟缩。亚伦罗杰斯和拉塞尔威尔逊永远不会被发现不推出至少一点点。这些是关键的区别,我想我们必须等待玩家跟踪数据!
  5. EPA/Dropback,成功率—大量的 per dropback 统计数据!这两个都是密切相关的高级属性。如果你在寻找两个最能衡量 QB 能力的属性,我会选择这两个。EPA/Dropback 衡量四分卫平均每落后一次会增加多少分。成功率衡量的是有多少百分比的回落导致阳性 EPA。
  6. 每完成码数,完成爆发力😈——这是我第一次使用我的爆发力统计,这是我写这些的足够理由。每完成码数是不言自明的。完成爆发力是所有完成的基尼系数,即百分之多少的完成码属于大戏?如果基尼系数很高,那就意味着有很多温和到低的收益,也有少数巨大的收益。Saquon Barkley 是使用这个定义的“爆炸性”球员的典型例子。或者,较低的基尼系数表明一名球员的许多收益是相似的(即,如果一名球员有许多 7 码的收益,但从未有过 80 码的 TD)。
  7. 空气码统计,空气码爆发力——也称为平均目标深度(aDOT)。一些四分卫,即 2018 年的瑞安·菲茨帕特里克,喜欢把球扔得很深,希望他们的接球手带球下来。其他的是验钞机……我想到了埃利·曼宁,尽管还有很多其他的例子。瑞安菲茨帕特里克有高空码,而埃利·曼宁没有。我把机场分为完成机场(CAY)和不完成机场(ICAY)。
  8. 接球后 10 码,YAC 爆发力——与上面的统计相反.当一个接球员接到球时,他们能接多远?说到埃利·曼宁,当他有奥德尔·贝克汉姆时,他会斜打奥德尔,奥德尔接球后有 75 码。我猜从技术上来说是 Odell 的 YAC,但对于 Eli 来说,知道他的产量有多少百分比来自于带球跑的接球手,这是值得衡量的。伊莱的 YAC 爆发力也很高,因为他的码数中有更高比例属于大打。有时大的 YAC 是因为在开阔场地的接收者很好,其他时候是因为 QB 在穿越路线上大步击中了球员,而接收者有大量的开阔场地。QB 确实对它有影响,更多(更多)你可以在这里阅读。
  9. 增加了所有的 QB 冲刺数据——每场比赛的冲刺码数,每场比赛的冲刺次数,奔跑爆发力,冲刺胜利概率。
  10. 平均获胜概率—尝试传球时的平均获胜概率。我选择包括这一点,因为当防守期望传球时,一些 QB 在后面传球。其他人上升了两个分数,不同的结果是可以预料的。这也是对四分卫天赋的粗略衡量。
  11. 近似值(av)——一项职业足球参考统计,主要衡量球员相对于其他位置的价值。这是一个粗略的衡量,但在我看来,值得包括在内。

毫无疑问,这个分析中选择的统计数据是有争议的。我没有提到薪水和职位草案,但是我可以根据你的分析(我的薪水数据也不完整)看到包含它们的理由。如果我有现成综合统计数据,我可能也会把它们包括在内。

第二步:足够的文字,更多的图片。我们来分析一下!

上面 26 个统计数据的热图:

/D means per dropback, /G means per game

好吧,这是压倒性的。我们会解决的!但是它包含了大量有用的信息。例如,如果你越过顶行,你可以看到年龄是如何与其他变量相关联的。许多变量根本没有意义上的相关性,但是有一些有趣的高度相关性。一个简单的例子是,EPA/Dropback(基本上是一个衡量你有多好的指标)与完成和 TDs 高度相关,而与不完成和拦截负相关。另一个例子是,每场比赛的得分尝试与 sacks 和 hits 相关——基本上,如果你被击中,你必须争夺更多。也有一些不太令人期待的相关性。高个子四分卫不经常抢球。接球后的码数与 QB 跑位统计相关…如果你在前场和/或抢球时打接球手,我猜接球手在空地上有更多的活动空间。这些是我找到的第一批,你自己看看吧!

第三步:信息太多!我们需要 PCA。

首先,本文纯致力于解释 PCA,如果需要进一步解释,我推荐!

假设,我们有 26 个独立的四分卫特征。许多这些特征是高度相关或反相关的——它们基本上告诉我们同样的事情。举例来说,你已经知道,一个具有高完成量、低截获量和高 TD 率的 QB 将具有高的 EPA/drop back。我们只需要一个组件来告诉我们“好的 QB”或“坏的 QB”。我们可以将这三个成分(完成、拦截和 TD 比率)提取为一个主成分。那个主成分将是一个试图最大化你能从它的 3 个子成分中得到的信息的数字。

实际上,主成分分析是某种手动波动魔法,可以将 26 个成分变成 25 个成分、24 个成分、23 个成分,任何我们想要的更小的数字...并且它寻求最小化它所牺牲的每个组件的信息丢失。

PCA 的优势在于,我们可以开发给定四分卫的二维或三维表示,从上述 26 个特征中提取最大可能的信息。缺点是我们对每个维度没有任何真正的意义,我们只会知道彼此相似的四分卫会彼此靠近。

此外,如果我们的 26 个特征选择不当,PCA 将输出完整的垃圾。因此,尽管我很想加入“鞋钉外观评分”或“1-10 分的啤酒搭配”等特征,但它们会打乱分析。最后,离群值会把事情搞糟。拉马尔杰克逊可能是一个很好的例子,一个 QB,可以弄乱冲统计,因为他会有很多尝试。

以上是 2009 年至 2019 年 QB 赛季的 3D PCA 图示例。这里有几个问题,但我仍然认为它足够酷,可以包括。

第一,从现在开始我会用 2D 图。在二维屏幕上很难看到三维的差异。也许当我们使用增强现实来可视化图形时,我们将能够理解 3D 图形。在那之前,我们必须失去另一个维度的信息。

二,有什么意义??我们可以看到 QB 季节的云,它很酷,持续了 2 秒钟,但它能帮助我们吗?

第四步:真正提取有意义的信息

现在我们已经绘制了这些点,我们可以将这些 QB 分组到不同的类别中。我们不需要手工创建类别并标记它们,我们可以欺骗并使用聚类算法来为我们做这件事。我将使用最著名的一个——k means 聚类。我也尝试了 DBSCAN,但结果不太好。

使用 KMeans 聚类,您可以指定所需的聚类数,然后算法会尝试根据给定的聚类数找到最佳分组。显然,我没有给出太多的数学细节,这是故意的。每一个聚类算法都有优点和缺点,我只是喜欢这个算法如何处理六个聚类。

好吧,来吧,这很酷。在右下角的海蓝色类别中,我们有一组非超级移动、真正高效、名人堂级别的 QB。我想知道为什么他们离蒂姆·泰博那么远🤔。我还会猜测他们的完成百分比通常更高,而他们的 aDOT 更低。顺便说一句,这是一个好迹象,同一个球员在几个赛季中通常都在同一个地区。很长一段时间里,培顿·曼宁显然是同一个 QB。在右上角,我们有更多的移动性,爆炸性,但仍然有效的 QBs。我认为中间的黄色可能是你在《幻想》后期起草的那种一年一年一致的 QB。马特·斯塔福德,菲利普·里弗斯等。当你在 x 轴上负向移动时,你的传球效率会越来越差。当你在 y 轴上走负向时,你的机动性/爆发力会降低(我认为)。紫色=检查下来的机器,蓝绿色=移动/爆炸,但不是有效的传球者。

重申一下,这只是我对主要成分的解读。像身体高度和 YAC 爆发力这样的东西被混合在一起,所以谁知道到底发生了什么。我喜欢 PCA 和聚类的一点是它如何创建独特的比较。我从来没想过拿乔希·艾伦和蒂姆·泰博做比较,但这很有意义。

我们可以逐季分析每个 QB 的变动。移动队伍、更换进攻协调者或者受伤的 QB 都会在这张图上移动。那只是四分卫!如果这是一份全职工作,我可能会分析很多。既然不是,我就只举一个例子。这里有一个挑战:你能指出公羊队从杰夫·费舍尔转变为肖恩·麦克维的确切时间吗?

Other young notables marked for reference. Was 2017 an outlier for Carson Wentz? Is Mitch Trubisky being slept on because of his bad accuracy?

(对于那些不关注足球的人来说,杰夫费舍尔在 2016 年是出了名的保守/传统,2017 年肖恩麦克维解锁了戈夫和公羊队的进攻)。

顺着这个思路,为什么不做一个动画呢?我从科里·杰斯的体育分析报告中得到这个想法/代码灵感,这要感谢本·鲍德温NFL scraper一篇 R 教程

似乎每次我运行一个新的程序,我都会学到一些新的东西,或者它们打开了我以前从未想过的视野。在这种情况下,汤姆·布拉迪和德鲁·布里斯年复一年的表现非常一致,这并不奇怪。同样不足为奇的是,埃利·曼宁可能已经展现了他的极限。然而,我很惊讶 Aaron Rodgers 在过去的 4 年里效率并不高!我认为这被他多高的个人得分所掩盖了,大部分的责任都不在他身上。最后,瑞安·菲茨帕特里克在 2018 年的跳跃确实令人震惊。

外接球手

所以这个我不能马上理解。最终,我发现 x 轴代表目标效率,y 轴代表目标的危险程度。目标体积没有明显的轴,这就是第三维度派上用场的地方。著名的吃角子老丨虎丨机/短靶球员在右下角海军蓝集群中非常突出。在它们的对面,中间上方,有一个紫色的深威胁集群。我有点惊讶,像安东尼奥·布朗,迪安卓·霍普金斯,胡里奥·琼斯这样的接球手并没有完全脱颖而出。事实证明,在《梦幻足球》中,高接球员更多地位于图表的右上角。另外,我觉得很奇怪,我看到的是 2016 年的胡里奥·琼斯,而不是 2015 年的胡里奥·琼斯。2015 年是胡里奥有史以来的一年!然后我看得更近一点,这是因为 2016 年胡里奥少了 2 场比赛和 50 个目标的类似数字(而且,结果是 2015 年胡里奥就在附近,我检查过)。因此,似乎更有效的接收器肯定突出!或者在 2018 年开尔文·本杰明的情况下,在图表的左端,非常低效的接收器也很突出。这也解释了 2018 年泰勒·洛科特在 x 轴上大约 6 点的位置。似乎海鹰队应该扔给他更多的球。有了这些信息,为什么不把它应用到我最喜欢的过去时光之一,梦幻足球上呢?

上面我画了每个集群的幻想点分布。黄色,右上方的接收者平均得分最高。紫色深度威胁接收器的平均水平没有那么高,但是它们可以像黄色集群一样玩“爆炸”游戏。插槽/短目标接收器非常类似于联盟平均水平的接收器,但根据我的定义,稍微不那么“爆炸性”。两个绿团效率都很低,也没得多少幻想分,但至少有一半(海绿团)得到了像样的目标质量。

跑锋

跑卫可能是迄今为止最有趣的比赛。从左到右,你得到越来越强的冲季。RB 螺柱位于右上方。对我来说,图表中有趣的部分是右下角的海绿色星团。只有极少数例子表明跑卫是非常高效的冲球员(每次跑动大约 6 码),但根本不构成威胁。格斯·爱德华兹、迈克·吉利斯利和克里斯·伊沃都跑得非常好,但根本没有接到传球。这种后卫的例子可能很少,因为当这些跑卫在比赛中时,防守队员应该知道如何堆叠禁区。在我的数据集中只有一个相反类型的回跑的例子,一个接收效率极高但没有冲效率的例子:LaRod Stephens-Howling。也许他应该换成吃角子老丨虎丨机?

雷电交加

我在这篇文章中讨论了蒂基·巴伯和罗恩·戴恩,所以我觉得我应该试着策划他们在 2001 年的最佳组合赛季。我尽了最大努力填写我没有的统计数据(我的数据集只追溯到 2009 年):

令人惊讶的是,罗恩·戴恩那年在小样本量上接球效率很高。随着时间的推移,罗恩·戴恩趋向于联盟平均水平,而蒂基·巴伯变成了一个怪物。

最后,这里的是我在这篇文章中使用的代码。

可视化特征值和特征向量

原文:https://towardsdatascience.com/visualizing-eigenvalues-and-eigenvectors-e2f9e3ac58d7?source=collection_archive---------8-----------------------

特征值和特征向量是线性代数和一般机器学习中非常重要的概念。在我之前的文章中,我已经从主成分分析的角度介绍了这些概念,并提供了实际的例子。在这篇文章中,我将更详细地阐述这些概念背后的数学原理,为我将要解释的内容提供一个几何解释。

为此,我将讨论以下主题:

  • 线性转换
  • 特征值和特征向量
  • 代数和几何的多重性

那么就从第一个话题开始吧。

线性转换

一般来说,变换是定义在定义域空间 V 上的任何函数,其输出在余定义域 W 中(其中 V 和 W 是多维空间,不一定是欧几里得的)。

保留加法和标量乘法运算的变换,如下所示:

叫做线性变换,从现在开始我们称之为 t。

让我们考虑下面的两个数值例子来清楚地了解它。假设我们有一个定义在 R2 上的变换 T,输出为 R:

如你所见,这种转换不是线性的,因为它不保持可加性。这个怎么样?

此外:

如你所见,加法和标量乘法被保留,因此转换是线性的。值得注意的是,从 R2 到 R 的唯一线性变换是那些看起来像 w=ax+by 的变换,因此是域向量分量的线性组合。

表示定理给出了线性系统的一个非常重要的性质,表示线性变换可以表示如下:

其中 A 是所谓的表示矩阵。我们将使用这个公式,因为它更紧凑,更方便。

现在,每一个变换都可能影响一个向量的方向和范围(关于多维空间中向量形状的更清楚的解释,你可以在这里阅读我以前的文章)。然而,给定一个变换 T,存在一类非常有趣的向量,它们只在外延上受变换的影响,因为方向保持不变。具有该属性的通用向量 v 是这样的:

其中λ是扩展因子。那些向量被称为特征向量,并且与它们相关联的值被称为特征值。

特征值和特征向量

正如所预料的,特征向量是那些一旦通过固定的 T 变换其方向保持不变的向量,而特征值是那些与它们相关的扩张因子的值。

更准确地说,特征向量是不平凡的向量,因此不同于 0 。那是因为上面的等式总是至少有一个解,就是其中 v=0 的平凡解。

在特征向量和特征值不同于平凡向量的情况下,如何找到我们的特征向量和特征值?为此,让我们用表示定理来重新构造我们的线性系统:

正如预期的那样,这个系统至少有一个解,这是一个平凡的解。因此,我们想要找到矩阵的行列式(A-*λ** I)等于零的那些λ值(否则,由于克莱姆定理,这将意味着系统有 1 个唯一解)。

让我们来设定我们的等式:

这个方程叫做特征方程,它的根就是特征值。再者,由于代数基本定理“每一个 n 次多项式在 C(复数集)中有 n 个解”,我们知道特征方程的次数将是与那个系统相关的特征值的个数。

让我们考虑下面的例子:

从特征方程中,我们导出了两个特征值 3 和-1。为了提供一个数字示例,我将找到与λ= 3 相关联的向量,称为特征向量(同样的推理适用于λ=-1)。如果我们考虑矩阵 A,这一目的的快速捷径可能是有用的。事实上,由于我们要求解的非唯一性,我们已经知道矩阵的行列式(A-lI)等于 0,因此在求解最终系统时,我们可以直接摆脱两个约束之一:

让我们想象一下:

基本上,位于该直线上的所有向量都是与特征值 3 相关联的特征向量:一旦通过 T 进行变换,它们将仅被延长/缩短,但方向不会改变。例如,考虑以下向量:

现在让我们来转换它:

如你所见,现在它的大小是原来的 3 倍,但是方向还是一样。

现在让我们转向本文的最后一个主题,即与特征值和特征向量相关的代数和几何重数。

代数和几何的多重性

现在假设你有一个 n 次特征方程,但是你只找到了一个根。因此,因为次数是 n ,所以称该根的代数重数为 n 。让我们考虑以下两个例子:

在第一个例子中,我们有一个等于-2 的特征值,没有重数(因为它的幂等于 1),而特征值-1(来自二次多项式)的重数等于 2。

现在的问题是:这个多重性在问题的几何方面也受到尊重吗?换句话说,一个特征值在一个解中出现的次数是否等于对应的特征空间(即相关特征向量的集合)的维数/自由度?

答案并不总是如此。每当我们有一个重数等于 n 的特征值和一个对应的维数小于 n 的特征空间时,我们称该λ系数为不规则的(否则,称该特征值为规则的)。

让我们用上面的例子直观地展示一下:

正如你所看到的,即使我们有一个重数为 2 的特征值,相关的特征空间只有一维,因为它等于 y=0。

结论

特征值和特征向量通常是数据科学和建模的基础。除了它们在 PCA 中的使用之外,它们还被用在谱聚类和图像压缩中。因此,记住它们的几何解释是很重要的。

可视化 ELMo 上下文向量

原文:https://towardsdatascience.com/visualizing-elmo-contextual-vectors-94168768fdaa?source=collection_archive---------19-----------------------

上下文向量对于词义消歧很有用。

单词嵌入的问题

处理世界感官的单词嵌入存在困难。无论一个单词有多少个义项,单词嵌入方法都将所有义项嵌入到一个单一的向量表示中。这可能会给下游的 NLP 任务(如文档分类)带来问题。

比如银行这个词,可以指金融机构,也可以指水以外的坡地。根据单词嵌入演示,使用 Google News 上训练好的模型,向量空间中银行最近的前 5 个单词分别是 banks、banking、bank、lender 和 banker。我们可以看到, bank 在这里的语义是指金融机构,除了水之外并没有包含坡地的意思。因此,文本“Sandy walks along the river bank”在文档分类中会被错误分类到“金融机构”类别,因为 bank 的词向量指向金融机构的含义。

语境向量

另一方面,单词的上下文向量可以捕捉单词的不同含义。顾名思义,上下文单词向量的向量表示取决于它在句子中的相邻单词。所以“我在银行取钱”中的单词 bank 和“她在河边散步很愉快”会有非常不同的单词向量。

根据最近的研究,将上下文向量添加到各种 NLP 任务中,如文本蕴涵、命名实体提取和问题回答,已经显示出极大地改善了最先进的结果。这些上下文向量是预先训练的语言模型的输出。关于预训练语言模型的细节可以在论文 ELMoBERT 中找到。下面我将使用 ELMo 模型来生成上下文向量。

可视化 ELMo 上下文向量

让我们尝试使用 ELMo 模型生成上下文向量,并使用 PCA 将向量投影到 2D 空间进行可视化。在 ELMo 的论文中,有 3 层单词嵌入,第 0 层是基于字符的上下文无关层,接下来是两个双 LSTM 层。作者根据经验表明,从第一双 LSTM 层生成的词向量可以更好地捕捉语法,而第二层可以更好地捕捉语义。我们将为具有多种含义的三个单词——银行、工作和工厂——可视化第 1 层和第 2 层上下文向量。

银行

先来重温一下银行这个词。我挑选了 5 个包含银行、银行这两个词的句子,可以是金融机构,也可以是水边的坡地。以下是 5 个句子:

1\. The river **bank** was not clean
2\. One can deposit money at the **bank**
3\. I withdrew cash from the **bank**
4\. He had a nice walk along the river **bank**
5\. My wife and I have a joint **bank** account

下面是使用 PCA 的预测结果。每个色点代表在其上下文中的词向量:

我们可以将上述上下文向量分为两组。右上簇的 bank 的词向量表示除水之外的坡地,左下簇则有金融机构的意思。

类似地,我们可以看到在第 2 层 ELMo 向量空间中有 2 个簇。

通过使用上下文向量, bank 根据不同的上下文有不同的词向量,意义相同的词在向量空间中会彼此接近!

工作

工作是另一个有多重含义的词。 Work 作为名词的意思是做或做的事情,作为动词的意思是工作。以下是包含上述两种意思之一的 5 个句子:

1\. I like this beautiful **work** by Andy Warhol
2\. Employee **works** hard every day
3\. My sister **works** at Starbucks
4\. This amazing **work** was done in the early nineteenth century
5\. Hundreds of people **work** in this building

下面是使用 PCA 的预测结果。每个色点代表作品在其上下文中的词向量:

查看第 1 层向量,我们无法立即将一个集群与另一个集群区分开来。然而,我们知道左边的三个向量把 work 作为动词,意思是工作,右边的两个向量把 work 作为名词,意思是做或做某事。

对于第 2 层向量,我们在右下角观察到作为动词的工作的清晰聚类,并且在左上角观察到作为名词的工作的另一聚类。

植物

植物可以表示“一个活的有机体”或者“把一颗种子埋在地里”以下是包含上述两种意思之一的 5 个句子:

1\. The gardener **planted** some trees in my yard
2\. I plan to **plant** a Joshua tree tomorrow
3\. My sister **planted** a seed and hopes it will grow to a tree
4\. This kind of **plant** only grows in the subtropical region
5\. Most of the **plants** will die without water

下面是使用 PCA 的投影结果,每个色点代表植物在其上下文中的词向量:

右上方的簇是向量,其含义是将种子放在地上以种植植物。对于左下方的簇,单词 plant 表示有生命的有机体。

在该图中可以发现类似的结果。左上的 3 个向量形成了具有含义为“将种子放在地里”的植物的簇,右下的 2 个向量形成了具有含义为活的有机体的词语植物的簇。

有趣的一点是,在上述所有 3 个实验中,与第 1 层相比,第 2 层 ELMo 向量空间中的簇形成似乎更清晰,并且簇质心之间的距离更大。ELMo 的论文提到,在词义消歧任务中使用第二层比使用第一层导致更高的 F1 分数。我们对第二层向量空间中更大距离的观察显示了对论文发现的可能解释。

生成上述图形的代码可以在这个 github 库中找到。

结论

通过可视化具有多种含义的单词的上下文向量,我们从经验上表明:

  1. 具有相同意义的上下文单词向量将形成一个簇。然后,我们可以计算每个词义的聚类质心,并使用简单的 1-最近邻方法来消除句子中词义的歧义。
  2. 具有相同意义的 ELMo 第 2 层单词向量形成清晰的簇,并且簇质心之间的距离大于第 1 层。

欢迎对这篇文章的任何建议或评论!

可视化情感

原文:https://towardsdatascience.com/visualizing-emotions-cec2215e9178?source=collection_archive---------27-----------------------

当我们通读一篇文章时,我想展示它的情感。

我从探索词汇数据库 WordNet 开始。我最初的想法是使用 WordNet 创建一个所有单词(不包括停用词)与其同义词相连的图表,并在单词出现在文本中时对其进行跟踪。我希望他们能创造出一串相关的单词。

Visualized with Gephi (find the shortest path)

但是哎呀!他们是偶然的;我错过了一些重要的东西。比方说,A 和 B 共享同素集,B 和 C 也共享同素集。然而,A 和 C 可能在意义上没有关系。例如,一个公共节点连接‘take’‘occupy’。另一个节点连接【关注】【占领】。这将【take】【concern】联系起来,尽管它们的含义并不相似。

下一次,我再次使用 WordNet,试图形成一个通过上位词连接的树。我尝试使用派生相关的形式、相似的 to 和动词组,将尽可能多的叶节点扩展到根‘实体’。我用迈克·博斯托克的径向树状图来展示数据。

Visualized with Mike Bostock’s Radial Dendrogram

这一次,虽然它形成了聚类,但单词不是基于含义聚类的。

例如,感觉群集被放置在远离物理实体群集的地方。然而,在情感群中,“高兴”和“愤怒”的节点就在附近。虽然这两个节点通过上位词密切相关,但它们在意义上是相反的。

终于!

最后,我选择了国家研究委员会的情感强度词典,也就是 Saif M. Mohammad 的情感强度词典。它包含四种情绪的 0 到 1 分的单词:愤怒、恐惧、快乐和悲伤。我考虑了三种情绪,用它们的分数和色轮来找到它们的位置。

var xyArray=[];
function data2rgb(filename)
{
    let D=2*R;
    let rgbArray=[];
    let scaleColor= d3.scaleLinear().domain([0,1]).range([0,255]);
    d3.csv(filename).then(function(data) 
    {
        for(let i=0;i<data.length;i++)
        {
            let [red,green,blue]=
               [scaleColor(data[i]["anger"]),
                scaleColor(data[i]["joy"]),
                scaleColor(data[i]["fear"])];

            let xyval=rgb2xy(red,green,blue,data[i]["negate"]);
            xyArray.push({i:i, word:data[i].word, x:xyval.x,
                      y:xyval.y, h:xyval.h, s:xyval.s, v:xyval.v});
        }   
        intervalLoop(xyArray);
    });
}

首先,我借助了 Cory Forsyth 的文章用画布手工编写色轮。我开始收集一篇文章中可以在词典中找到的单词,以及它们的分数。然后,我将每个分数在 0 到 255 的范围内,并给它分配了一种颜色(绿色代表快乐,红色代表愤怒,蓝色代表恐惧)。将 RGB 值转换成 HSV 后,我可以从 H 和 S 得到它在圆中的位置,从 v 得到它的值。

function repeating()
{
    timeouts=setTimeout(function()
    {  if(i==xyArray.length-1) 
       return 0;
       drawNode(xyArray[i],xyArray[i+1]);
       i++;
       repeating();
       },tt); function drawNode(a,b)
    {...}
}
repeating();

然后,使用 setTimeout()方法,我评估了该函数,以便在一个间隔之后定期绘制 SVG 元素。在这段时间里,通过 d3 转换,我可以在节点之间进行线性转换,并转换节点的颜色。但是我想创造一个更平滑的路径;不是线性的。

因此,我创建了一个 Catmull-Rom 样条线使用 d3 的无中风或填充,并打破了它成段。然后,我将沿着断开线段的点的数据添加到每个单词的数据中,以便在 setTimeout()函数中使用。

if (b.seg.length!=0)
{ 
      circles.attr("cx",R+p)
         .attr("cy",R+p); let pathSeg=svg.append("path").attr("id","pathSeg")
         .data([b.seg])
         .attr("d", d3.line()
         .curve(d3.curveCatmullRom))
         .attr("fill","none")
         .attr("stroke-width","0")
         .attr("transform", "translate("+ R+p +"," + R+p + ")"); circles.transition()
         .duration(t)
         .attrTween("transform", translateAlong(pathSeg.node()))
         .attr("fill",d3.hsv(b.h,b.s,b.v))
         .attr("r",scaleRadius(b.v));
}
else
{
      circles.attr("cx",R+b.x+p)
         .attr("cy",R+b.y+p)
         .transition().duration(t)
         .attr("fill",d3.hsv(b.h,b.s,b.v))
         .attr("r",scaleRadius(b.v));
}

最后,为了表示 HSV 颜色的 V 值,我改变了节点的半径,使其与 V 成比例,看起来像是在垂直于屏幕的方向上平移。此外,为了匹配背景,我重叠了一个黑色圆圈,不透明度等于 1-V。

svg.append("circle").attr("id","cvalue")
     .attr("cx",R+p).attr("cy",R+p).attr("r",R)
     .attr("fill","black").attr("fill-opacity",1-a.v)
     .transition().duration(t).ease(d3.easeLinear)
     .attr("fill-opacity",1-b.v);

还有刷新!

And refresh!

参考文献:

[1]赛义夫·穆罕默德, NRC 影响强度词典

2 C. Forsyth,用画布手工编码色轮 (2017)

倒影:

  1. 还有很多事情要做。(例如,在 VADER,根据标点符号或强调符号来修改分数)。
  2. 我们如何知道一个词在文本和词典中的意义?比如某本书里提到的‘邪灵’,词典上可能会认为是‘精神好’
  3. 假设快乐、愤怒和恐惧这三种情绪相距 120 度是正确的吗?将悲伤视为快乐的对立面,并将其置于愤怒和恐惧之间(冷静和勇气也是如此),这样做对吗?

这个项目是我第一次尝试数据可视化和自然语言处理。如果你有任何反馈或建议,给我发邮件到 nive.mathan21@gmail.com,或者在回复中告诉我。我很乐意连接!

可视化房价分布

原文:https://towardsdatascience.com/visualizing-house-price-distributions-fb0e6c2c264d?source=collection_archive---------22-----------------------

Photo by John Lockwood on Unsplash

有了 Zillow 和 python 的 than,比以往任何时候都容易。

等等,但是为什么?

我正在关闭我在佐治亚州亚特兰大的第一个家,并一直在大量使用各种房地产网站,如 Zillow,Redfin 和 Trulia。我也一直在摆弄 Zillow 的 API,尽管在功能和文档方面有些参差不齐。尽管它有缺点,但当我阅读了由 Lukas Frei 撰写的帖子后,我受到了充分的启发,该帖子讲述了如何使用该库无缝地创建基于地理的可视化。几天后,我结合 Zillow 和 leav 制作了一些亚特兰大和美国各地房价的酷炫视觉效果。

主题

  • API 集成
  • 图形遍历
  • 形象化

一个小例子

让我们从使用一些我从 Zillow 网站下载的预汇总数据开始。该数据集显示了美国每个州从 1996 年 4 月到 2019 年 5 月每个月的平方英尺价格中位数。自然,人们可以对这些价格随时间的发展建立丰富的可视化;然而,现在让我们坚持使用最新的价格,它在文件的最后一列。

看看排名前 10 的州,并没有多少惊喜。需要说明的是,最初我对其中一些城市的订单感到措手不及,特别是华盛顿和夏威夷名列榜首。但是,回想一下指标中“每平方英尺”的标准化。因此,考虑到加州的面积,我可能更惊讶于它仍然排在第三位。

Top 10 price/sqft in thousands of $$$ (May 2019)

不管怎样,上节目吧!由于这是一篇可视化的文章,我将避免在你面前扔太多行代码,并在文章的结尾将所有内容链接到它。简而言之,我从叶 repo 下载了一个美国各州的 GeoJSON 文件。这是一个伟大的发现,因为它立即为我提供了无缝流程所需的数据模式;我需要添加的唯一信息是价格数据(在最终的地图中生成颜色)。在提供了这些之后,仅仅 5 行代码就给了我下面的情节:

Heatmap of price/sqft of homes in the U.S. for May 2019

更进一步

既然我已经把脚趾伸进了 Zillow 和 leav 的水里,我已经准备好沉浸其中了。我决定画一张亚特兰大房价的热图。Zillow API 的一个缺点是它的搜索功能非常有限——我找不到任何基于经纬度坐标的搜索方法,这对于创建粒度热图来说非常方便。尽管如此,我还是把它作为一个机会来温习一些爬虫风格的代码;我使用一个城市名称的初始搜索结果作为未来调用的种子,以获得这些房屋的 comps (通过 GetComps 端点)。

值得注意的是,Zillow 确实有很多基于 URL 的搜索过滤器,可以用来进行纬度/经度搜索(见下文)。然而,从网页上获取房屋就变成了一项搜集工作,你会受到 Zillow 网页结构突然变化的影响。也就是说,抓取项目会有很多乐趣;如果你想把这个放进我做的东西里,请告诉我!

# an example of a Zillow search URL, with plenty of specifications
[https://www.zillow.com/atlanta-ga/houses/2-_beds/2.0-_baths/?searchQueryState={%22pagination%22:{},%22mapBounds%22:{%22west%22:-84.88217862207034,%22east%22:-84.07880337792972,%22south%22:33.53377471775447,%22north%22:33.999556422130006},%22usersSearchTerm%22:%22Atlanta,%20GA%22,%22regionSelection%22:[{%22regionId%22:37211,%22regionType%22:6}],%22isMapVisible%22:true,%22mapZoom%22:11,%22filterState%22:{%22price%22:{%22min%22:300000,%22max%22:600000},%22monthlyPayment%22:{%22min%22:1119,%22max%22:2237},%22hoa%22:{%22max%22:200},%22beds%22:{%22min%22:2},%22baths%22:{%22min%22:2},%22sqft%22:{%22min%22:1300},%22isAuction%22:{%22value%22:false},%22isMakeMeMove%22:{%22value%22:false},%22isMultiFamily%22:{%22value%22:false},%22isManufactured%22:{%22value%22:false},%22isLotLand%22:{%22value%22:false},%22isPreMarketForeclosure%22:{%22value%22:false},%22isPreMarketPreForeclosure%22:{%22value%22:false}},%22isListVisible%22:true}](https://www.zillow.com/atlanta-ga/houses/2-_beds/2.0-_baths/?searchQueryState=%7B%22pagination%22:%7B%7D,%22mapBounds%22:%7B%22west%22:-84.88217862207034,%22east%22:-84.07880337792972,%22south%22:33.53377471775447,%22north%22:33.999556422130006%7D,%22usersSearchTerm%22:%22Atlanta,%20GA%22,%22regionSelection%22:%5B%7B%22regionId%22:37211,%22regionType%22:6%7D%5D,%22isMapVisible%22:true,%22mapZoom%22:11,%22filterState%22:%7B%22price%22:%7B%22min%22:300000,%22max%22:600000%7D,%22monthlyPayment%22:%7B%22min%22:1119,%22max%22:2237%7D,%22hoa%22:%7B%22max%22:200%7D,%22beds%22:%7B%22min%22:2%7D,%22baths%22:%7B%22min%22:2%7D,%22sqft%22:%7B%22min%22:1300%7D,%22isAuction%22:%7B%22value%22:false%7D,%22isMakeMeMove%22:%7B%22value%22:false%7D,%22isMultiFamily%22:%7B%22value%22:false%7D,%22isManufactured%22:%7B%22value%22:false%7D,%22isLotLand%22:%7B%22value%22:false%7D,%22isPreMarketForeclosure%22:%7B%22value%22:false%7D,%22isPreMarketPreForeclosure%22:%7B%22value%22:false%7D%7D,%22isListVisible%22:true%7D)

回到选择的路径,我提到我使用最初的结果作为某个城市的家庭网络的入口点。有了这些入口点,我不断递归调用每个家庭的 comps。这里的一个重要假设是,Zillow 对房屋相似性的定义,除了其他因素之外,还包括位置邻近性。如果没有位置邻近性,基于 comp 的住宅遍历相对于位置将非常不平滑。

那么,我们有什么算法可以以不同的方式遍历节点网络呢?当然,广度优先搜索(BFS)和深度优先搜索(DFS)很快就会浮现在脑海中。出于好奇,看看下面它的基本逻辑流程。除了集合成员保护之外,只有当新的 homes 满足在meets_criteria函数中断言的约束时,它们才会被添加到集合中。现在,我在预定义的根纬度/经度位置和当前家的位置之间做一个简单的 L2 距离检查。这一标准鼓励搜索停留在根的本地,目的是为了一个良好连接和粒度的热图。下面的实现通过弹出列表的末尾(第 5 行)并添加到列表的末尾(第 14 行)来使用 DFS,但是通过更改任一行(但不是两行)来使用列表的前面,可以快速实现 BFS。

让这个算法在亚特兰大的房屋上运行 10,000 次迭代,在几分钟内就会产生下面的地图!更重要的是,由 folium 生成的网页是交互式的,允许像缩放和平移这样的常见地图导航工具。为了证明它的模块化,我还生成了一些波士顿、马萨诸塞州西雅图、华盛顿州的小比例价格地图。

Heat map of Atlanta housing prices. See the interactive version here.

代码

正如承诺的那样,这是项目。它有一个 Make+Docker 设置,便于使用和再现。如果您想了解这两种工具如何完美结合以实现可重现的数据科学,请继续阅读这里的。无论哪种方式,README 都可以让你很快上手,无论是通过脚本还是 Jupyter 笔记本。快乐的 viz!

[## agnone3/zillium

用 Zillow+leav 实现房地产可视化。在…上创建帐户,为 aagnone3/zillium 开发做出贡献

github.com](https://github.com/aagnone3/zillium)

现在怎么办?

接下来,我们可以沿着许多不同的方向发展这个逻辑。我在下面详细介绍了一些激励措施,但我更喜欢朝着最能获得支持、影响和协作的方向前进。你怎么想呢?

原载于https://anthonyagnone.com

可视化在 MNIST 数据集上训练的 CNN 的中间激活

原文:https://towardsdatascience.com/visualizing-intermediate-activations-of-a-cnn-trained-on-the-mnist-dataset-2c34426416c8?source=collection_archive---------11-----------------------

在本文中,我们不仅要使用 Keras 和 Python 训练一个卷积神经网络来分类手写数字,还要可视化卷积神经网络的中间激活,以便深入了解每一层学习图像的哪些特征。

我们将使用 MNIST 数据集,它可以在 Kaggle 上的这里找到。该数据集在训练集中包含 42000 行,在测试集中包含 24000 行。每行包含 784 个像素值,表示包含从 0 到 9 的手写单数数字的 28 x 28 图像。

让我们深入研究代码。

首先,我们必须导入所有模块:

import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D, Input
from keras.models import Model
from sklearn.model_selection import train_test_split

现在,让我们将 CSV 文件加载到一个熊猫数据帧中,并使用 numpy 将它们重新整形为 28 x 28 x 1 的图像。

注意:所有图像都是灰度图像,因此它们只有一个通道

train_df = pd.read_csv("../input/train.csv")
test_df = pd.read_csv("../input/test.csv")train_labels = train_df['label']
train_dataset = train_df.drop('label',axis=1)X = np.array(train_dataset).reshape(train_df.shape[0],28,28,1)
Y = np.array(train_labels).reshape(train_df.shape[0],1)

让我们来看看我们的一些训练图像:

f, axes = plt.subplots(2, 10, sharey=True,figsize=(20,20))for i,ax in enumerate(axes.flat):
    ax.axis('off')
    ax.imshow(X[i,:,:,0],cmap="gray")

构建我们的 CNN 架构

我们将使用 Keras Functional API 来构建我们的 CNN 模型。我从 Chris Deotte 的 Kaggle 笔记本中获得了 CNN 架构的灵感。

def model():

    inputs = Input(shape=(28,28,1))
    x = Conv2D(24,kernel_size=(3,3),padding='same',activation="relu")(inputs)
    x = MaxPooling2D(pool_size=(2, 2))(x)
    x = Conv2D(48, (3, 3), padding='same',activation='relu')(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)
    x = Conv2D(64, (3, 3), padding='same',activation='relu')(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)
    x = Flatten()(x)
    x = Dense(128, activation='relu')(x)
    x = Dropout(0.25)(x)
    output = Dense(num_classes,activation="softmax")(x)

    model = Model(inputs,output)

    model.compile(loss='categorical_crossentropy', 
              optimizer='adam', 
              metrics=['accuracy'])

    return model

现在是训练的时候了:

X_train, X_test, y_train, y_test = train_test_split(X,Y_one_hot,test_size=0.20, random_state=42)epochs = 20
batch_size=256

model = model()
history = model.fit(X_train,y_train,
         epochs=epochs,
         batch_size=batch_size,
         validation_data=(X_test,y_test))

这最终给出了 99.50%的训练准确度和 98.83%的验证准确度。

注意:我们本可以在验证准确性方面做得更好,使用数据增强并对 Dropout 和 BatchNorm 层进行试验但是本文的重点不是获得极高的准确性,而是能够深入了解网络的每一层实际上在学习什么,对于这项任务,我们的模型将做得很好。

让我们快速绘制一张我们的训练和验证准确性以及损失的图表:

让模型旋转一下

figure = plt.figure(figsize=(20,20))for i in range(5):
    figure.add_subplot(1,5,i+1)
    plt.imshow(test_images[i+50,:,:,0],cmap="gray")
    plt.axis("off")
    print(np.squeeze(np.argmax(model.predict(test_images[i+50].reshape(1,28,28,1)),axis=1),axis=0),end="\t")

如我们所见,我们的模型给出了相当不错的结果。

可视化中间激活

我们期待已久的时刻。

我们首先要决定哪一层的激活我们想要可视化,并建立我们的激活模型。

layer_outputs = [layer.output for layer **in** model.layers[1:7]]
activation_model = Model(inputs=model.input,outputs=layer_outputs)

我们现在从测试数据集中选择一个随机图像,我们将在其上使用我们的激活模型。

img = test_images[51].reshape(1,28,28,1)fig = plt.figure(figsize=(5,5))
plt.imshow(img[0,:,:,0],cmap="gray")
plt.axis('off')

我们现在使用我们的激活模型来输出所选层的激活。

activations = activation_model.predict(img)

是时候用一些 matplotlib 魔法将它们可视化了。🙂

layer_names = []
for layer in model.layers[1:7]:
    layer_names.append(layer.name) # Names of the layers, so you can have them as part of your plot

images_per_row = 16for layer_name, layer_activation in zip(layer_names, activations): # Displays the feature maps
    n_features = layer_activation.shape[-1] # Number of features in the feature map
    size = layer_activation.shape[1] #The feature map has shape (1, size, size, n_features).
    n_cols = n_features // images_per_row # Tiles the activation channels in this matrix
    display_grid = np.zeros((size * n_cols, images_per_row * size))
    for col in range(n_cols): # Tiles each filter into a big horizontal grid
        for row in range(images_per_row):
            channel_image = layer_activation[0,
                                             :, :,
                                             col * images_per_row + row]
            channel_image -= channel_image.mean() # Post-processes the feature to make it visually palatable
            channel_image /= channel_image.std()
            channel_image *= 64
            channel_image += 128
            channel_image = np.clip(channel_image, 0, 255).astype('uint8')
            display_grid[col * size : (col + 1) * size, # Displays the grid
                         row * size : (row + 1) * size] = channel_image
    scale = 1\. / size
    plt.figure(figsize=(scale * display_grid.shape[1],
                        scale * display_grid.shape[0]))
    plt.title(layer_name)
    plt.grid(False)
    plt.imshow(display_grid, aspect='auto', cmap='viridis')

由此我们可以推断出几点:

  • 第一层几乎保留了图像的全部形状,也保留了图像中的大部分信息
  • 随着我们深入网络,我们可以看到激活变得更加复杂和抽象。它开始对边缘、曲线和角度等高级特征进行编码。
  • 此外,随着我们深入研究,我们可以看到我们的许多过滤器没有被激活,这表明我们的模型正在达到其学习能力。

我们已经成功地可视化了选定的中间激活中的每个通道,并且希望我已经能够给出 CNN 中不同层如何在图像中找出不同模式的基本理解。

Keras 模型的轻量级可视化

原文:https://towardsdatascience.com/visualizing-keras-models-49d591931209?source=collection_archive---------19-----------------------

我喜欢 Keras 让构建神经网络变得简单明了。将 Keras 连接到 Tensorboard 并不难,但我总觉得对于许多经常想快速浏览底层模型的 Keras 用户来说,重量级解决方案过于复杂。

有了 wandb,您只需一行额外的 python 代码就可以可视化您的网络性能和架构。

为了展示这是如何工作的,我修改了 Keras examples 目录中的几个脚本。

要安装 wandb,只需运行“pip install wandb ”,我的所有 Keras 示例都将为您工作。

1。简单的 CNN

我从必备的 mnist_cnn.py 开始。

我在下面添加了来自 wandb import magic 的——你也可以看看我的 mnist_cnn.py 从 Keras 示例中派生出来的一行代码。

现在,当模型运行时,wandb 在后台启动一个进程,保存相关指标并将它们传输到 wandb。可以去https://app . wandb . ai/l2k 2/keras-examples/runs/ovptynun/model看看我运行的输出。

我可以准确地看到我的模型所标注的数据,并自动查看损耗和精度曲线。

2。‍国际会议的结果

接下来,我分叉 cifar10_resnet.py ,做了同样的一行修改。你可以在https://app . wandb . ai/l2k 2/keras-examples/runs/ieqy 2e 9h/model看到一个很好的 resnet 可视化。

系统页面上,我可以看到这个模型使用的我的单个 GPU 比 mnist 例子多一点。

3。暹罗网

接下来,我尝试了暹罗网络的例子。在这里,我可能想看看 TensorFlow 图,幸运的是,通过我们的一行代码,我们可以自动检测和托管 TensorBoard。你可以在 https://app.wandb.ai/l2k2/keras-examples/runs/fsc63n6a?找到这款跑鞋 workspace=user-l2k2 。

对于每个模型,这个工具花费了我不到一分钟的时间,增加了很少的计算开销,并且应该适用于您正在处理的任何 Keras 模型。当您想要跟踪更多内容时,您可能希望用以下内容替换该行:

导入 wandb

wandb.init(magic=True)

然后,您可以使用我们的自定义 wandb.log()函数来保存您想要的任何内容。你可以在我们的文档中了解更多信息。

我真的希望你觉得这有用!

可视化识字率差异

原文:https://towardsdatascience.com/visualizing-literacy-rate-disparity-19f375486965?source=collection_archive---------27-----------------------

——作者尼格什·普拉贾帕蒂让·梁约翰·亨特亚什·米塔尔

“为理解而设计”项目的目标是使用视觉方法向我们的用户传达数据,并牢记两个不同的最终目标。

  1. 清晰的沟通和推理:这需要构建一系列图表,以提供深入、公正、清晰的数据描述。
  2. 说服性沟通和讲故事:这需要以引人注目的方式呈现数据,并对用户产生持久的影响。

为了这个项目,我们选择了 1980 年至 2016 年间世界各地成年男性和女性识字率的数据集。我们的最终目标是展示这一时期男女识字率的差异。一些最终的可视化显示如下。

Clear communication mandates simplicity. Persuasion may require sacrificing accuracy.

左边的图表显示了我们清晰的交流和理解的一个可视化。完整的投资组合可点击查看。右边的视频展示了项目的说服沟通和讲故事部分。你可以在这里与可视化互动。

数据选择

数据选择步骤本身就是一个过程。最初,我们很难找到一个好的、有趣的、相对干净的数据集,并提供实验的广度。我们对小组中每个成员感兴趣的不同领域进行了头脑风暴,并初步决定使用美国不同交通方式的死亡率数据。然而,我们很快意识到处理这种特殊数据的复杂性,因为它需要我们组合多个数据表,并需要我们处理太多的变量,这使得这个过程非常混乱。数据数量的差异也是如此之大,以至于我们无法有效地显示任何数据。我们最终决定使用识字率数据集,因为它的格式简单明了,尽管它确实需要我们组合多个来源,这仍然比之前的选项更容易。此外,这些数据似乎对我们所有人都很有吸引力,我们都很兴奋能够参与其中。

—为什么关注识字率?

全世界的识字率在很大程度上一直在上升,但具体国家的识字率是如何变化的呢?识字率和国家财政状况之间有关联吗?各国识字率的性别均等情况如何?这个因素会影响一个国家的表现吗?这些都是我们遇到的问题,导致我们今天为您创建了数据可视化。识字率或多或少显示了一个特定国家的教育水平,我们希望在识字率和一个国家的总体成功之间建立具体的联系。我们的小组开始创造一些设计,让我们的观众理解我们试图传达的数据,然后推导出这些数据,这样我们的用户就可以看到一个清晰的相关性。

5 张设计流程

对于该设计流程,我们决定使用 5 板材流程的衍生产品。我们所做的基本上是 5 张纸的过程,但范围稍大,合并了一些步骤。5 页设计流程是设计可视化的直观方法。它让我们能够准确地展示我们是如何想出我们的设计,以及是什么影响了我们的设计选择。在开始时,这个过程允许我们扩大项目的范围,随后以一种其他方式很难做到的方式缩小和完善我们的细节。通过下面的表格,你将会看到我们是如何从头脑风暴到设计再到实施的。

—头脑风暴和筛选想法

Brainstorming (without any restrictions) different ways of visualizing our literacy data

上图展示了我们头脑风暴会议的一些草图。本次会议的目的是产生尽可能多的想法关于我们可以清楚地交流数据的方式。如图所示,我们没有把自己局限于考虑一个特定的可视化是否可能被创建。这是为了确保我们从不同的角度看问题。

我们的下一步是从头脑风暴中过滤我们的想法。为此,我们问自己这样的问题:

每一个想法在多大程度上有效地描述了我们数据的无偏见观点?
数据展示对我们的用户来说足够吸引人吗?

这些问题为我们挑选最佳创意提供了必要的基础。

—构思草图

一旦我们想好了要在演示中表达什么想法,我们就必须选择最好的方式。在这个过程中,我们从 5 张设计流程中获得了灵感。我们为每个想法绘制了潜在的布局,详细说明了它将关注什么以提供对数据的深入理解,并讨论了使用该方法的积极和消极方面。这篇文章数据可视化—最佳实践和基础对于找出可视化数据的最佳方式特别有帮助。

例如,为了比较全世界男性和女性的识字率,我们决定使用折线图,因为折线图非常适合于比较多个群体在一段时间内的微小变化。同样,我们使用散点图来显示不同国家的男性和女性识字率,因为散点图非常适合探索两组数据之间的关系。关于我们的说服部分,我们使用地图可视化数据,因为以这种方式显示特定国家的数据在逻辑上最有意义。这也让我们能够发挥创意,设计出有趣的、互动的、也很吸引人的作品。总的来说,我们希望我们所有的数据可视化简洁明了,但仍然能够抓住并保持任何感兴趣的人的眼球。

We discussed the feasibility of our ideas by noting down the pros and cons of the designs.

第一次冲刺——发展

—数据预处理

我们从世界银行网站获得了 csv 格式的识字数据。如前所述,数据集相对干净,但我们仍然需要填充缺失的数据。为了能够以更好的方式呈现数据,我们做出了以下重要假设。

  • 我们假设一个国家的识字率保持不变,直到下一年的数据观察可用。
  • 世界银行的数据集没有主要国家的数据,包括但不限于美国、加拿大、墨西哥和英国。一旦这些国家的成人识字率达到 99%以上,我们就使用这个 HBS 数据集来估计识字率差异为零。

—用于理解的表格

我们希望确保我们的用户以一种不难操作的格式接收清晰、准确、易读的数据。为此,我们使用了 Tableau,它使我们能够相对容易和简单地显示我们的数据。当查看我们的 Tableau 仪表板时,用户将看到三个图表,显示我们所有的数据结果以及如何在图表中导航的方向。

Tableau offers powerful functionality to add detail to your plots. Tooltips, filters and more.

我们的第一张图表显示了世界各地识字率的性别差异,我们认为这是我们应该展示的第一件事,因为它很宽泛,包含了性别差异的一般概念。第二,我们显示了世界不同地区的性别差异,这使得我们的用户可以看到性别识字差异,并有更多的地区特异性。在第三个也是最后一个图表上,我们有一个散点图,显示了各个国家不同时期的识字率差异,因此我们的用户可以看到各国在性别识字率差异方面与世界其他国家相比的情况,以及它们如何朝着均等的方向发展。我们希望,通过我们的 Tableau 仪表板,人们将能够与我们的数据进行互动,并就世界上的性别识字差异及其意义得出明确的结论。

—将 JQVMap 用于动画地图

我们的团队想通过使用 Tableau 之外的工具来挑战自己。我们的目标是

表明世界各地识字率的性别差距正在缩小,欠发达地区的差距相对较大

在头脑风暴阶段,我们认为世界地图是展示这一想法的最佳方式。我们的数据世界在他们关于识字率的博客 帖子中有一些令人着迷的世界地图,所以我们开始寻找工具来重现这些可视化。我们最终使用 JQVMap,一个与 D3 相比学习曲线不太陡峭的 JavaScript 库,来创建如下所示的世界地图。阴影越深,表示男女识字率的差距越大。最初,我们使用默认的蓝色配色方案,但后来我们将其更改为橙红色。我们做出这个选择是因为红色通常与消极联系在一起,而蓝色则与冷漠联系在一起,正如这里的所支持的

Evolution of our visualization for persuasion

我们都同意,我们想要一个随着时间的推移颜色会自动变化的动画地图。我们还添加了一个按钮,可以在需要的时候暂停和恢复动画。在最初的几次迭代之后,我们向一些朋友寻求反馈。他们建议我们添加缩放控件,这样人们可以近距离观察特定的地区或国家。一些人还告诉我们,他们想知道一个国家的确切识字率差距。为了更好的用户体验,我们增加了当有人悬停在某个国家时显示工具提示的功能。

—结果和反馈

在课堂演示日期间,我们收到了很多来自同行的反馈,这让我们能够对我们的设计进行一些工具性的修改。所要求的改变并不激烈,所以我们没有任何理由来彻底修改设计。这些建议旨在调整我们的视觉效果,使之更直观,更容易得出结论。

“我希望能提供更多的背景。这是一个有趣的话题。”"如果他们在散点图中记录国家会怎么样?"

大多数反馈都与配色方案和其他视觉变化有关,或者希望在整个可视化过程中跟踪特定的国家。其他人要求在我们的仪表板上的图表上配一段叙述。虽然这些变化需要一些工作,但它们并不太密集,并允许相同的可视化看起来和感觉更好。

第二次冲刺——弥补过失

—设计

A layout sheet to guide our dashboard reorganization

在演示日之后,我们还有一周的时间来修改我们的可视化效果。我们从固化一个叙述开始,将 Tableau 仪表盘中的所有三个图表联系起来,这是我们在演示日期间从一个其他小组获得的灵感。

类似地,我们得到的另一个评论是用户可以在散点图上追踪单个国家。我们自己无法做到这一点,所以我们向巴克内尔大学的商业智能架构师 Ken Flerlage 寻求帮助。他能够帮助我们解决这个问题。此外,他给了我们一些改进其他图表的建议。

此后,我们对世界地图可视化做了一些 UI 调整。最大的修改是将图例分成有限的几个类别。在此之前,地图有一个梯度比例作为其图例,这使得我们的用户很难区分橙色和红色的许多阴影。为了解决这个问题,我们使用了专门为制图推荐的调色板YlOrRd这里

A large number of splits has the same problem as a gradient. So we stuck with only four splits with an additional one to represent unavailable data.

—样式

我们也对我们的可视化风格做了一些改变,以使它对用户更有吸引力。我们想要一个美观的仪表盘来滚动,同时避免颜色和动画“过头”。我们决定使用无衬线字体 Roboto ,因为它既优雅又不分散注意力。至于颜色,我们实现了“交通灯”配色方案,因为这些颜色很容易区分。我们还决定采用这种配色方案,因为色盲的人能够毫不费力地区分这些颜色。(我们使用这个色盲模拟器来确保每个图表对于每种类型的色盲都是可区分的。)

最后的话

总之,我们对这个数据可视化项目的结果非常满意。我们认为,我们能够以一种易于理解和容易得出结论的方式来展示我们的数据。整个过程对我们来说很有趣,从选择数据集到实现你看到的所有数据可视化。我们觉得我们的图表和可视化出来的结果很清晰,几乎和我们预想的一模一样。

可视化深度神经网络的损失情况…..但是我们能相信他们吗?

原文:https://towardsdatascience.com/visualizing-loss-landscape-of-deep-neural-networks-but-can-we-trust-them-3d3ae0cff46e?source=collection_archive---------11-----------------------

我们能相信深度神经网络的损失景观可视化吗?

Landscape from this website

简介

最近开发了一种方法来可视化深度神经网络的损失情况。我个人认为这是一个巨大的突破,然而,我对创建的可视化的有效性感到有点怀疑。今天,我将研究作者的可视化方法,并介绍一些我认为非常酷的其他方法。

方法

创建亏损景观的整个过程非常简单直接。

  1. 训练网络
  2. 创建随机方向
  3. 给固定重量加上不同的扰动量,看看损失值是如何变化的。

唯一需要注意的是这些随机方向是如何产生的。我们来看看作者的方法。

他们的方法被称为“过滤器标准化”,非常容易理解。(这里是链接到作者的代码)。基本上,对于四维张量如(64,3,3,3),我们将匹配关于第一维的范数,因此(64,1,1,1),在权重的范数和随机方向的范数之间。(用一个更简单的术语来说,我们可以将这理解为匹配权重和随机方向之间的比例)。

以上是运行作者代码时的部分结果。现在我们可以利用张量运算来简化整个过程。(我稍后会展示)

网络

绿球 →输入图像(64,64,3)
蓝色矩形 →卷积+ ReLU 激活
红色矩形 →软最大输出

对于这篇文章,我在 CIFAR 10 数据集上训练了三个九层完全卷积神经网络(如上所示)。无任何归一化、批量归一化和局部响应归一化。

并且从上面的图中我们可以看到,批量归一化的网络取得了最高的性能。

从现在起我将把每个网络称为如下的
正常:没有任何归一化层的网络
批量规范:具有批量归一化层的网络
局部规范:具有局部响应归一化层的网络

滤波归一化

上面的代码片段展示了如何使用张量运算进行过滤器标准化。

Normal, Batch Norm, Local Norm

Normal, Batch Norm, Local Norm — Log Scale

当我们使用滤波归一化方法来可视化损失景观时,我们可以看到每个景观看起来并没有太大的不同。只有在我们以对数比例显示景观的情况下,我们才能看到,事实上,局部响应归一化的景观要清晰得多。

当我们将这三幅图按原始比例叠加在一起时,我们可以看到它们看起来是多么相似。

滤波器正交化

上述方法只是作者方法的简单修改,我们从简单的高斯分布生成随机方向,但是通过 QR 分解我们使方向正交化。

Normal, Batch Norm, Local Norm

Normal, Batch Norm, Local Norm — Log Scale

当我们将不同维度的方向正交化时,我们可以立即看到创建的损失景观是如何彼此不同的。与作者的方法相比,我们可以看到三个网络之间的损耗情况有所不同。

正交权重投影

这与滤波器正交化基本相同,唯一的区别在于,对不同维度的收敛权重执行 ZCA 白化,而不是从高斯分布生成。

Normal, Batch Norm, Local Norm

Normal, Batch Norm, Local Norm — Log Scale

类似于滤波器正交化,我们可以看到生成的可视化之间的一些差异。

重量的主要方向

最后一种方法是在不同的维度之间,在它们的第一主方向上扰动权重。

Normal, Batch Norm, Local Norm

Normal, Batch Norm, Local Norm — Log Scale

我们可以清楚地看到所产生的损失情况之间的差异。

讨论

我写这篇文章的唯一原因是为了表明,根据我们使用的方向,创造的损失景观可以发生巨大的变化。因此,我们需要质疑生成的损失景观的有效性,它们是否真正反映了训练网络的特征。

代码

要访问创建可视化效果的代码,请点击此处。
要查看整篇博文的代码,请点击此处

遗言

我不想做任何大胆的断言,但似乎不同的方向选择会产生不同的视觉效果。问题仍然存在,哪个方向是最‘正确’的?可有正确的,哪一个揭示了真相?此外,我想提一下名为“尖锐极小值可以推广到深度网络的论文,该论文表明已经收敛到尖锐极小值的深度神经网络可以很好地推广,并且该理论不适用于具有 ReLU 激活的网络。就像那篇论文如何证明我们的观察可以根据我们的定义而改变一样,我们应该致力于创造反映真理的定义。

还有更多研究要做,我很期待。如果你希望看到更多这样的帖子,请访问我的网站

参考

  1. 李,h,徐,z,泰勒,g,斯图德,c,&戈尔茨坦,T. (2017)。可视化神经网络的损失景观。arXiv.org。2019 年 5 月 3 日检索,来自https://arxiv.org/abs/1712.09913
  2. tomgoldstein/loss-landscape。(2019).GitHub。检索于 2019 年 5 月 3 日,来自https://github.com/tomgoldstein/loss-landscape
  3. https://prateekvjoshi . com/2016/04/05/what-is-local-response-normalization-in-convolutionary-neural-networks/

可视化音乐表演

原文:https://towardsdatascience.com/visualizing-musical-performance-5da28b96957a?source=collection_archive---------13-----------------------

作为一名音乐家和数据科学家,我对可视化音乐表演的想法很感兴趣。在这篇文章中,我概述了如何可视化来自 MAESTRO 数据集的钢琴演奏录音。示例在整个帖子中提供。下面,我使用 Python 的 Mido、Seaborn 和 Pandas 包,一步一步地布置了在 MAESTRO 数据集中打开、清理和可视化钢琴演奏的说明和代码。文章最后展示了弗朗茨·李斯特的匈牙利狂想曲第 2 号和一段音乐录音,这样读者就可以通过视觉观看音乐的展开。还提供了用于创建可视化的完整 Python 脚本的链接。

Joint density plot of Johann Sebastian Bach’s Prelude and Fugue in D Minor, WTC I, BWV 851

数据

MAESTRO 数据集包含来自国际钢琴电子竞赛的超过 200 小时的钢琴演奏。比赛的参与者在雅马哈唱片播放器上表演,这是一种声学钢琴,也可以捕捉和播放乐器数字接口数据。MAESTRO 数据集包含来自参赛者表演的 MIDI 数据以及表演的音频记录。

MIDI 是一种允许数字乐器通过“信息”相互通信的协议。这些信息储存了关于用于回放的乐器类型、要演奏的音符、音符何时开始、音符何时结束等信息。

简介:用 Python 打开 MIDI 文件

要在 Python 中打开 MIDI 文件,请安装 mido 包。从 Mido 包中,导入 MidiFile。下面是使用 MidiFile 在 Python 中打开文件的示例代码。对于 MAESTRO 数据,这个过程将创建一个包含两个音轨的 MidiFile 对象。第一轨道包含关于演奏的元数据(例如,作品的拍号)。第二个轨道包含性能消息。

Joint density plot of Wolfgang Amadeus Mozart’s Sonata in D Major

阐述:管理数据

下面的步骤是我在这篇文章中用来处理数据以创建可视化效果的。

步骤 1: 分离第二个轨迹,然后遍历轨迹提取消息。结果应该是一个消息对象列表。迭代时,省略第一条和最后一条消息。第一个消息是节目消息,最后一个是指示轨道结束的元消息。这两条消息都没有提供关于所演奏的音符的数据。

步骤 2: 遍历消息列表,将消息转换为字符串。可以使用基本 python 中的 str()函数或 mido 包中的 format_as_string()方法完成到字符串的转换。

步骤 3: 使用将消息字符串分割成包含键和值的子字符串。拆分(“”)。

这将创建一个列表列表。单个列表如下所示:

列表的第一个子字符串只包含一个值(消息类型)。为了将数据转换为字典,必须删除该子字符串。

第四步:删除第一个子串,存储在一个列表中,将列表转换为 dataframe。

步骤 5: 将列表中的其他子字符串转换成字典,然后转换成 dataframe。=分隔子字符串中的键和值。下面的代码遍历列表和每个子字符串来创建键值对。然后,它将这些键值对存储在一个字典列表中(每个子字符串列表一个字典)。最后,它将字典转换成数据帧。

步骤 6: 将属性数据帧(df2)与包含消息类型的数据帧(df1)连接起来。

步骤 7: 数据帧中的时间变量表示自最后一条消息以来经过的时间。音符变量表示弹奏的钢琴键。为了绘制数据,需要测量经过的时间来绘制随时间变化的数据。可以使用 Python 的创建 time_elapsed 变量。cumsum()方法。音符变量表示弹奏的钢琴键。绘制注释需要将变量从 string 类型转换为 float 类型。

步骤 8: 过滤掉控制消息和 note_off 消息,因为这些消息不会在可视化中使用。控制信息指示延音和弱音踏板何时被按下和释放。控制消息的消息类型等于“控制”。note_off 消息由速度为0 的 note_on 类型消息指示。

步骤 9: 从数据帧中删除不必要的列。

步骤 10:munging 过程的最后一步是在数据帧的开头和结尾添加一行。添加这些行将在可视化的边缘和数据点之间提供一些空间。新的第一行被分配一个音符值 0(钢琴较低音域之外的值)和一个等于最大经过时间值的-0.05 倍的经过时间值。(第一个 note_on 消息的 time_elapsed 值大于 0)。新的最后一行被分配了音符值 127(钢琴上限范围之外的值)和时间流逝值,该时间流逝值等于最大时间流逝值的 1.5 倍。添加这些行还可以生成边缘平滑的可视化效果。

Joint density plot of Edvard Grieg’s Lyric Piece in A Minor, “Waltz,” Op. 12 № 2

发展:可视化

为了可视化性能,我使用了 Python 的 Seaborn 包。x 轴代表经过的时间(时间从左到右增加),y 轴代表从低(下)到高(上)弹奏的音符的音高。这些图使用十六进制箱显示了一段时间内音符的联合密度。颜色用于传达十六进制 bin 中包含的音高和时间段范围内的音符频率。在上图中,较高的频率由较暗的绿色阴影表示。

关节密度图显示了十六进制 bin 定义的范围内的音高频率,以及这些频率如何随着演奏的进行而变化。结果是一个曲线图,该曲线图可视化了音高(y 轴)和音高频率(颜色)随时间(y 轴)的变化。该图包含了所有必要的信息,以及在图中可视化的作品的性能(见下面的匈牙利狂想曲示例演示)。

以下步骤分解了这篇文章中的可视化是如何绘制的。

步骤 1: 设置海风风格为“白色”。这一步提供了一个干净的白色背景,在此基础上建立可视化。

第二步:定义绘图,x 轴的界限和 y 轴的界限。这就是在 munging 过程的步骤 10 中添加第一行和最后一行有助于可视化的地方。x 轴限制由最短经过时间和最长经过时间定义。这两个数量都由附加行设置。y 轴限制设置为 16 和 113。这样做的原因是为了给图提供平滑的边缘。MIDI 音符值(绘制在 y 轴上)可以取 0 到 127 之间的值。然而,钢琴只有 88 个键,它们的 MIDI 音符值在 21 到 108 之间。第一行和最后一行的音符值被设定在钢琴的可能值范围之外。因此,通过在第一行和最后一行设定的最小和最大音符值内设定 y 轴限制,绘图:

  1. 显示钢琴的所有可能值,
  2. 不显示第一行和最后一行的人工音符值,
  3. 包括每个可视化的边缘与最低和最高音符之间的空间,并且
  4. 该空间的颜色与地块的背景颜色相同。

关于 plot 函数的另一个注意事项。gridsize 表示 x 方向上十六进制箱的数量。改变 gridsize 会改变 hex bins 的大小,从而改变绘图中 hexgons 的大小。里姆斯基·科萨科夫的《大黄蜂的飞行》的最终情节如下。

Joint density plot of Rimsky-Korsakov’s Flight of the Bumblebee (with labels and marginal plots)

第三步:去掉不需要的剧情元素。为了提供联合密度图的艺术再现,我移除了边缘图、轴和刻度标签以及轴。(注意:删除这些元素是提供有意义的可视化的最佳实践的对立面。)下面的代码删除了轴、边缘图、轴标签和刻度标签。

Joint density plot of Nikolai Rimsky-Korsakov’s Flight of the Bumblebee

重述:

这篇文章介绍了从 MAESTRO 数据集打开、清理和可视化 MIDI 演奏数据的步骤。提供了代码片段来演示这些步骤。使用 Seaborn 的 jointplot 方法可视化性能数据。这些图显示了一段时间内音高的密度(或者,弹奏音符的频率)。其结果是在一幅图像中捕捉一段音乐的艺术描绘。

对于那些有兴趣了解可视化如何与音乐作品的表现相结合的读者,下面是一个例子。可视化是弗朗茨·李斯特的匈牙利狂想曲№ 2。视频之后是 Adam Gyorgy 的表演视频。对于对创建自己的可视化感兴趣的读者,我的脚本和文档可以在 GitHub 上找到。

Joint density plot of Alban Berg’s Sonata Op. 1

尾声:匈牙利狂想曲№ 2

下面是弗朗茨·李斯特的《匈牙利狂想曲 2》的视频以及亚当·乔吉演奏该作品的视频。当你听视频的时候,通过视觉跟随表演。

Joint density plot of Liszt’s Hungarian Rhapsody № 2

文献学

柯蒂斯·霍桑、安德烈·斯塔舍克、Adam Roberts、伊恩·西蒙、黄承志、桑德·迪勒曼、埃里希·埃尔森、杰西·恩格尔和道格拉斯·埃克。"使用 MAESTRO 数据集实现因式分解的钢琴音乐建模和生成."在 2019 年国际学习代表大会上。

克拉克一世(2016 年 4 月 25 日)。回复:MIDI 规范【在线讨论组】。检索自https://www . midi . org/forum/228-writing-midi-software-send-note-off,-or-zero-velocity-note-on

使用 Folium 插件在交互式和动画地图上可视化纽约市自行车数据

原文:https://towardsdatascience.com/visualizing-nyc-bike-data-on-interactive-and-animated-maps-with-folium-plugins-c2d7645cd19b?source=collection_archive---------7-----------------------

Visualizing NYC Bike Data on interactive and animated maps with Folium plugins

当哪里的科学还不够

当分析交通和流动性时,在地图上画图总是很有帮助的。这有助于我们回答问题“事情在哪里发生?”

尽管如此,如果我们不考虑时间,很多时候分析的结果会发生巨大的变化。也许最明显的例子是在分析通勤模式时:如果你分析一整天,看起来去市中心的人和去相反方向的人大致相同。当你按一天中的时间划分时,你可以看到人们早上(去上班)和下午(回家)的移动方式有很大的不同。

在这种情况下,我们想要加深对特定情况的理解,我们需要在分析中添加第二个变量:时间。这将帮助我们在事情发生时回答

在我们想要加深对特定情况的理解的情况下,我们需要在分析中加入第二个变量: 时间

友情提醒:请帮我鼓掌(或者很多!)当你读完之后如果觉得这篇文章有帮助。

你会在这篇文章中发现什么

在这篇文章中,我们与纽约自行车共享服务的公开可用数据争论,以介绍一些插件,它们可以帮助我们在 Jupyter 笔记本中用 Python 的叶子库制作动画、交互式地图。

我们不会关注数据分析工作流程或我们从不同的视觉效果中得到的结论。我们将尝试优化这里显示的代码,以获得我们正在寻找的动画地图。

我们会发现一些例子:

导入库

和往常一样,我们做的第一件事是导入我们将使用的 Python 库。

import numpy as np 
import pandas as pd 
import geopandas as gpd 
import folium 
import datetime

如果您是 Python 用户,您可能已经熟悉了前三个库。如果你开始使用 Python 并且想了解更多,我强烈推荐你阅读杰克·范德普拉斯的名著《Python 数据科学手册》,以获得完整的介绍。它是免费的,你可以直接从你的电脑上阅读。

第四行是导入leave,这是一个将 Leaflet.js 引入 Python 的库,让我们只用几行代码就能创建交互式地图。

在最后一行,我们导入了 datetime 库,这将使我们能够更轻松地处理时间序列。如果你有兴趣了解更多关于如何有效处理时间序列的知识,你可以阅读本书的这一部分。我发现它很有帮助。

导入和浏览数据

纽约花旗自行车共享服务的数据是公开的,可以在这里下载。在本笔记本中,我们使用了 2019 年 5 月的数据。

将文件下载到工作目录后,运行以下脚本导入数据:

*# Import the file as a Pandas DataFrame*
fp = 'file.csv' 
nyc = pd.read_csv(fp) 
nyc.head()

数据看起来很完整。我们对每次旅行都有很多信息:

  • 行程持续时间:行程的持续时间,以秒为单位。
  • 开始时间:行程的开始日期和时间。
  • 停止时间:行程的结束日期和时间。
  • 起点站 id、名称、纬度和经度:识别和定位起点站的所有有用信息。纬度和经度值在 WGS84 投影(GPS 投影)中,这将使我们以后的工作更容易。
  • 终点站 id、名称、纬度和经度:识别和定位旅行终点站的所有有用信息。
  • bikeid: 旅途中骑过的自行车的 id。
  • 用户类型:用户是订户(年卡)还是顾客(不同于年卡)。
  • 出生年份
  • 性别:表示用户是女性(2)、男性(1)还是未知(0)

对这些变量的完整解释可以在花旗自行车的网页上找到。

转换

我们注意到变量开始时间停止时间被作为文本(字符串)导入:

为了让 Pandas 充分发挥时间序列的功能,我们将做以下工作:

  1. 将这些变量的类型更改为日期时间。
  2. start time定义为数据帧的索引。这将使我们能够更容易地按一天中的时间对值进行透视(分组)。
  3. 创建一个名为【类型】的新列来帮助我们进行旋转。
*# Setting the right format for starttime and stoptime*
nyc['starttime'] = nyc['starttime'].str[:-5]
nyc['stoptime'] = nyc['stoptime'].str[:-5]
nyc['starttime'] = pd.to_datetime(nyc['starttime'])
nyc['stoptime'] = pd.to_datetime(nyc['stoptime'])

*# Define the startime as index and create a new column*
nyc = nyc.set_index('starttime')
nyc['type'] = 'station'
nyc.head(1)

这正是我们想要为每个可视化开始特定转换的格式。我们开始吧!

时间戳 GeoJson

这个插件允许我们在交互式叶子地图上绘制数据,并根据时间变量(年、月、日、小时等)制作动画,并且支持任何类型的几何图形(点、线串等)。你唯一要做的就是确保用 geojson 以正确的格式“输入”它。

为此,我们将开始转换数据框。首先,我们计算每个车站每小时的发车次数:

*# Aggregate number of trips for each start station by hour of the day*
start = nyc.pivot_table('tripduration', 
                      index = ['start station id', 
                               'start station latitude', 
                               'start station longitude',
                                nyc.index.hour],
                      columns = 'type',
                      aggfunc='count').reset_index() start.head()start.head()

在上面的代码中,我们使用了 pandaspivot _ table()函数来帮助我们以任何我们想要的方式对数据进行分组。注意,我们使用的最后一个索引是“NYC . index . hour”。这将获取数据帧的索引,因为它是 datetime 格式,所以我们可以获得该值的小时,如上所示。我们可以类似地得到日子或月份。

尽管如此,我们得到的计数是整个月的。为了得到日平均值,我们将除以天数。

days = nyc.index.day.max() 
start['station'] = start['station']/days

现在,为了方便起见,我们将更改列的名称,并定义我们希望地图上的点具有的颜色。

*# Rename the columns*
start.columns = ['station_id', 'lat', 'lon', 'hour', 'count']

*# Define the color*
start['fillColor'] = '#53c688'

*# The stops where less than one daily trip*
*# will have a different color*
start.loc[start['count']<1, 'fillColor'] = '#586065'
start.head(1)

在将数据框转换为我们需要的格式后,我们必须定义一个函数,从其中获取值,并使用正确的属性创建 geojson 以在插件中使用。

def create_geojson_features(df):
    features = []

    for _, row in df.iterrows():
        feature = {
            'type': 'Feature',
            'geometry': {
                'type':'Point', 
                'coordinates':[row['lon'],row['lat']]
            },
            'properties': {
                'time': pd.to_datetime(row['hour'], unit='h').__str__(),
                'style': {'color' : ''},
                'icon': 'circle',
                'iconstyle':{
                    'fillColor': row['fillColor'],
                    'fillOpacity': 0.8,
                    'stroke': 'true',
                    'radius': row['count'] + 5
                }
            }
        }
        features.append(feature)
    return features
start_geojson[0]

让我们来看看函数:

  1. 它获取一个数据帧并遍历其行
  2. 它创建一个要素并将几何定义为一个点,从数据框中获取纬度和经度变量
  3. 它使用其他变量定义其余的属性:
  • 它使用小时变量来创建一个时间属性。这是最重要的数据动画。
  • 创建 fillColor 属性需要 fillColor
  • 它将点的半径定义为计数变量的函数

一旦定义了函数,我们就可以在数据框中使用它并获得 geojson。

start_geojson = create_geojson_features(start) 
start_geojson[0]

有了这个,我们现在可以创建我们的第一个互动和动画地图。

from folium.plugins import TimestampedGeoJson

nyc_map = folium.Map(location = [40.71958611647166, -74.0431174635887],
                    tiles = "CartoDB Positron",
                    zoom_start = 14)

TimestampedGeoJson(start_geojson,
                  period = 'PT1H',
                  duration = 'PT1M',
                  transition_time = 1000,
                  auto_play = True).add_to(nyc_map)

TimestampedGeoJson 插件的参数是:

  • 有数据的 geojson
  • 周期:是动画从第一个值开始的时间步长。例如:' P1M ' 1/月,' P1D ' 1/天,' PT1H ' 1/小时,' PT1M ' 1/分钟。
  • 持续时间:时间过后,要素将在地图上显示的时间段。如果没有,将显示所有以前的时间。

结果看起来像这样:

双重地图

上面的地图看起来很酷,我们可以清楚地看到,在早高峰,许多行程从市中心周围的地方开始,而在下午,有大量的行程从地图中心的车站开始。

分析一天中不同时间的旅行终点可能是个好主意。更重要的是,并排查看两张地图并尝试识别一种模式可能会很有趣。

DualMap 插件可以帮助我们实现这一点。为了使用它,我们将首先运行一个与上面类似的脚本,以获得一天中每个时间在每个车站结束的车次。

nyc1 = nyc.reset_index().set_index('stoptime')
end = nyc1.pivot_table('tripduration', 
                     index = ['end station id', 
                              'end station latitude', 
                              'end station longitude', 
                              nyc1.index.hour],
                     columns = 'type',
                     aggfunc='count').reset_index()

end['station'] = end['station']/days

end.columns = ['station_id', 'lat', 'lon', 'hour', 'count']
end['fillColor'] = '#e64c4e'
end.loc[end['count']<1, 'fillColor'] = '#586065'
end_geojson = create_geojson_features(end)

在这之后,我们只需要创建我们的对偶地图。

from folium.plugins import DualMap

dualmap = DualMap(location = [40.71958611647166, -74.0431174635887],
                 tiles = 'cartodbpositron',
                 zoom_start = 14)

TimestampedGeoJson(start_geojson,
                  period = 'PT1H',
                  duration = 'PT1M',
                  transition_time = 1000,
                  auto_play = True).add_to(dualmap.m1)

TimestampedGeoJson(end_geojson,
                  period = 'PT1H',
                  duration = 'PT1M',
                  transition_time = 1000,
                  auto_play = True).add_to(dualmap.m2)

dualmap

请注意,我们首先创建对偶地图,然后将 start_geojson 添加到左侧地图(m1),将 end_geojson 添加到右侧地图(m2)。

正如我们所猜测的那样,在早上,大部分行程都在地图中间的车站结束(右边地图上的红色圆圈),而在下午,大部分行程都从那里开始(左边地图上的绿色圆圈),并分布在整个城市。有理由假设那里有一个大的中转站(也许是一个火车站),带着许多人去曼哈顿工作,穿过这座桥。

这是一个很好的例子,说明向空间数据添加时间变量可以帮助我们更好地理解某些情况。

蚂蚁路径

这个插件帮助我们在地图上制作路径动画。在这种情况下,我们没有每次旅行的确切路径,因此我们将创建从起点到目的地的线。

在开始处理我们的数据之前,让我们看看这个插件需要什么设置。从现场演示中我们可以看到设置包括权重(线条粗细)和延迟(动画的速度,延迟越高,动画越慢)。在我们的例子中,利用这些设置来更好地表示两个站点之间的活动水平是很有趣的。今后我们将牢记这一点。

从我们之前看到的地图来看,似乎在地图中间有一个很大的车站,可能值得单独分析。我先从筛选与之互动最多的前 6 个站开始。

df = nyc.pivot_table('tripduration', 
                     index = ["start station name", 
                              "end station name",],
                     columns = ['type'],
                     aggfunc='count').reset_index().sort_values(by='station', ascending=False)
df.head()

现在,我们可以将这前 6 个站点作为掩码,在接下来的步骤中过滤信息。

mask1 = df["start station name"].head(10)
mask2 = df["end station name"].head(10)
mask = mask1.append(mask2)
mask = mask.unique()

在用袖扣做了一个关联热图后,我发现最有趣的分析站是“Grove St PATH”(你可以去笔记本找这个的代码,因为这不是本文的目的)。

因此,格罗夫圣路径似乎是最有趣的那里,但我们也将切片我们的数据一点点,以了解的事情发生。正如我们在盖有时间标记的 geojson 地图上看到的,早上最大的流量是流向Grove St PATH,而下午主要的流量是来自 Grove St PATH 在制作数据动画之前,将我们的数据分成这些时间段似乎会很有用。

*# Assign to each row a period of the day*
nyc['time_of_day'] = pd.cut(nyc.index.hour,
                            [0,6,10,16,20,24],
                            labels = ['am_valley', 'am_peak', 'mid_valley', 'pm_peak', 'pm_valley'], 
                            right=False)

*# Create a different dataframe for each peak*
am = nyc.loc[nyc['time_of_day'] == 'am_peak', :]
pm = nyc.loc[nyc['time_of_day'] == 'pm_peak', :]

*# Filter the trips that end in Grove St PATH during the morning peak*
*# and the trips that start in Grove St PATH during the afternoon peak*
to_st_path = am.loc[(am['end station name'] == 'Grove St PATH') & (am['start station name'].isin(mask)), :]
from_st_path = pm.loc[(pm['start station name'] == 'Grove St PATH') & (pm['end station name'].isin(mask)), :]

现在我们已经根据需要过滤了信息,我们将转换数据框来创建插件需要的格式。我将在文章中展示将转换为 _st_path 数据帧的过程,但对 from_st_path 也是如此。你可以在这里下载整个笔记本的完整代码。

to_st_path = to_st_path.pivot_table('tripduration',
                                   index = ['start station name', 
                                            'start station latitude',
                                            'start station longitude',
                                            'end station name',
                                            'end station latitude',
                                            'end station longitude'],
                                   columns = ['type'],
                                   aggfunc='count').reset_index().sort_values(by='station', ascending=False)

现在我们可以为每一行再创建两个变量:权重延迟。都将是的功能。

  • 对于体重,我决定在 1 到 10 的范围内。站越高就是越重
  • 对于延迟,我决定在 100 到 800 的范围内进行。较高的工位是较低的工位(它将移动得更快)。
*# Define the weight*
to_st_path['weight'] = to_st_path['station']*10/(to_st_path['station'].max())

*# Get the needed values for interpolating*
a_to_st_path = (800-100)/(to_st_path['station'].min() - to_st_path['station'].max())
b_to_st_path = 100 - to_st_path['station'].max()*a_to_st_path

*# Define the delay interpolating*
to_st_path['delay'] = a_to_st_path*to_st_path['station'] + b_to_st_path

对另一个数据框运行相同的代码后,我们现在可以创建一个双地图,显示上午高峰时朝向 Grove St PATH 的活动和下午高峰时来自 Grove St PATH 的活动

from folium.plugins import DualMap

dualmap = DualMap(location = [to_st_path.loc[0, 'end station latitude'], to_st_path.loc[0, 'end station longitude']],
                         tiles='cartodbpositron',
                         zoom_start=15)

to_st_path.apply(lambda row: folium.plugins.AntPath([(row['start station latitude'],
                                                      row['start station longitude']),
                                                     (row['end station latitude'],
                                                      row['end station longitude'])],
                                                    color='blue',
                                                    weight = row['weight'],
                                                    delay = row['delay']).add_to(dualmap.m1),
                   axis=1)

from_st_path.apply(lambda row: folium.plugins.AntPath([(row['start station latitude'],
                                                        row['start station longitude']),
                                                       (row['end station latitude'],
                                                        row['end station longitude'])],
                                                      color='blue',
                                                      weight = row['weight'],
                                                      delay = row['delay']).add_to(dualmap.m2),
                   axis=1)

dualmap

热图时间

根据这个插件的文档,它需要的输入是一个列表列表:

"数据([lat,lng]或[lat,lng,weight] 形式的点列表列表)-您想要绘制的点。外部列表按顺序对应不同的时间步长。(权重在(0,1)范围内,如果没有为点指定权重,则默认为 1)"

也就是说,我们需要为一天中的每个小时创建一个点列表,然后将所有这些列表放入一个新列表中。为此,我们创建了一个函数:

*# Create an empty list*
df_hour_list = []

*# Create a series with the different hours of the day*
hours = pd.Series(nyc.index.hour.unique().sort_values())

*# Create a list of points for each hour of the day*
def create_list(hour):
    df_hour_list.append(nyc.loc[nyc.index.hour == hour,
                                ['start station latitude',
                                 'start station longitude']].
                        groupby(['start station latitude', 
                                 'start station longitude']).sum().reset_index().values.tolist())
hours.apply(create_list);

之后,我们可以很容易地创建时间热图。

from folium.plugins import HeatMapWithTime

*# Add trip events to the map*
map_time = folium.Map(location=location, 
                      tiles="CartoDB Positron", 
                      zoom_start=12)

HeatMapWithTime(df_hour_list, 
                auto_play=True, 
                max_opacity=0.5, 
                gradient = {0.2: '#FBD973', 
                            0.4: '#fa782f', 
                            0.75: '#F16578', 
                            1: '#782890'}).add_to(map_time)
map_time

目前就这些了,希望你觉得有用。

如果你觉得它有帮助,请留下一些掌声来帮助我继续下去;)

感谢阅读!

参考

赫尔辛基大学 AutoGIS 课程

杰克·范德普拉斯的 Python 数据科学手册

用树叶地图可视化空气污染

How to:follow for maps,heatmaps &时间分析作者 Dave Ian Hickey

叶子文档 叶子插件文档

原载于https://www.linkedin.com

用矩阵变换可视化主成分分析

原文:https://towardsdatascience.com/visualizing-principal-component-analysis-with-matrix-transforms-d17dabc8230e?source=collection_archive---------5-----------------------

理解特征值、特征向量和主分量的指南

主成分分析(PCA)是一种通过识别特征值和特征向量将数据分解成不相关成分的方法。以下内容旨在帮助您直观地了解这些不同的值代表什么以及它们是如何计算的。首先,我将展示如何使用矩阵来转换数据,然后在 PCA 中如何使用这些矩阵。

矩阵变换

对于以下各项,我将对这个圆和网格应用矩阵变换:

让我们使用这个作为我们的“数据”图像来帮助可视化每个转换发生了什么。图像上的点可以用原点位于圆心的[x,y]坐标来描述,我们可以使用 2D 变换矩阵来变换这些点。对于每个示例,我将用蓝色显示转换后的数据图像,用绿色显示原始数据图像。

缩放矩阵

比例矩阵是所有非对角元素为零的对角矩阵。

如果对角线元素小于 1,它会使数据图像在该方向变小。如果它大于 1,它会使数据图像在该方向变大。比如我们设vₓ= 1.2vᵧ= 0.6,就会变宽( vₓ > 1),变短( vᵧ < 1)。

旋转矩阵

旋转矩阵将围绕原点旋转数据一个角度 θ 而不改变其形状,如下所示:

这里我将图像旋转了正 20 度。注意它是逆时针旋转的。

剪切矩阵

剪切矩阵通过具有非零的非对角线元素来倾斜轴。

λ 越大,剪切力越大。这里,x 值被移动以产生剪切。

这里,y 值被移动。

对称矩阵

对称矩阵将基本上以相反的方向旋转 x 轴和 y 轴。

作为对称矩阵只要求每个非对角元素 i,j 与元素 j,i 相同。

非对角线元素的符号决定了歪斜的方向。而且,对角元素是相互独立的,不管它们的值是多少,矩阵仍然是对称的。

矩阵分解

对称矩阵的一个特性是它们可以分解成三个矩阵,其关系如下:

其中 Q 是正交矩阵( Q ⁻ = Qᵀ ),而 D 是对角矩阵。

注意旋转矩阵是正交的(r(θ)⁻=r(-θ)=r(θ)),缩放矩阵是对角的。这意味着我们的对称矩阵实际上可以用旋转和缩放矩阵的组合来代替:

因此,数据图像的对称变换与旋转是一回事,沿 x 轴和 y 轴缩放,然后再旋转回来。这里我将使用三种变换(旋转、缩放、反旋转)来进行与上面对称例子相同的最终变换。

另一种思考方式是对称矩阵 A 与缩放矩阵 Sᵥ 相同,但它只是以相对于 x 轴和 y 轴的角度 θ 进行缩放。一个不是一个对角矩阵的唯一原因是它是一个相对于 x 轴和 y 轴缩放的度量。如果我们创建一组旋转了角度 θ 的新轴(如下所示),并制作一个相对于这些轴测量的缩放矩阵,这将是一个对角矩阵。

A 沿其缩放的这些轴是主分量轴。

在相当于 A 的对角缩放矩阵中,对角元素是数据沿主分量轴延伸的量。它们描述了数据的形状,告诉我们数据在不同的方向上是变长了还是变短了。那些对角线元素是特征值

旋转矩阵包含一组给出主分量轴旋转的向量。这些向量就是特征向量。**

单个特征值及其对应的特征向量给出了一个主分量的幅度和方向。**

数据示例

现在让我们找出一组随机数据点的主成分。

让我们制作一些数据,使其以原点为中心(这是矩阵变换正确的必要条件),并从 x 轴倾斜 30°(因此,斜率为δy/δx=tan30°)。

一个协方差矩阵显示了数据集中两个矢量元素的协方差。如果两个向量元素一起变化,它们将具有更高的协方差。如果一个元素的变化完全独立于另一个元素,那么它们的协方差会变为零。数据中的斜率意味着 x 和 y 值不是独立的,因此它将具有非零的非对角线值。让我们看看数据的协方差矩阵。

注意这个矩阵是对称的。这是因为 ij 元素的协方差与 ji 元素的协方差相同(它们是相同的两个元素的协方差)。协方差矩阵 C 因此可以分解为:

V 是矩阵,其中每列是不同的特征向量, D 是特征值的对角矩阵。

既然我们知道我们旋转数据的角度,让我们计算我们期望得到的特征向量的值(列 V ):

接下来,我们来计算特征值。特征值将是沿着主分量轴的数据的方差。我们可以通过用特征向量对数据进行反旋转来测量这些值,然后找出 x 和 y 方向上的方差。

这里的数据是反旋转的:

x 和 y 方向的方差:

x 方向的方差最大,因此数据中的大部分信息都在该分量中。这是的第一个* 主成分。进一步的主成分基于它们的方差从最大到最小排序。*

既然我们已经知道会发生什么,让我们使用 scikit-learn 的 PCA 模块并将结果与我们的进行比较。首先,让我们打印出主成分。(该模块以行的形式返回特征向量,所以我将打印出转置,将它们放入如上所示的列中。)

注意这和我们计算的旋转矩阵相似。列是按重要性排序的特征向量,显示第一分量、第二分量等的方向。

接下来,让我们打印出解释的差异:

这些与我们计算的方差一致。同样,这些组件按从大到小的顺序排列。

查看组件

为了更清楚地理解独立的特征向量以及它们如何旋转数据,让我们使用它们来创建图像,以便直观地将主成分与数据进行比较。

一般来说,我们可以将一个特征向量乘以任意数,它会给出该点在主分量轴上的 x 和 y 值。让我们使用噪声的三个标准偏差作为该数字,它可以通过以下关系使用方差来计算

使用 3σ处的点可以很好地指示不同主分量的相对噪声。让我们创建一个值为[-3σ,3σ]的数组,对于我们的第一个主成分,它将是

然后,我们可以将数组乘以第一特征向量,这将给出这两个值沿第一主分量轴的 x 和 y 分量。

类似地,这可以通过改变所使用的指数来对其他主要成分进行。通过在每个主成分的 3σ点之间绘制一条线(通过简单的plt.plot(x_comp,y_comp)使用 matplotlib),我们可以查看它们的噪声范围。

简而言之,两条红线表示两个主分量的方向。它们的旋转角度由特征向量计算,它们的长度由特征值确定,以显示沿轴的 3σ噪声范围。

降维

为了更好地理解特征值的重要性,让我们在一个降维的例子中使用它们。

如果想知道总方差中有多少是由不同的分量解释的,可以用每个特征值除以特征值的总和。

这意味着 94.6%的解释方差在第一部分。然而,有一种更快的方法可以得到解释方差的比率:

第二主成分占数据中方差信息的 5.4%,可能主要是噪声。如果要进行降维,可以去掉第二个主成分,只保留第一个主成分的信息。

首先,我将展示如何用特征向量来实现这一点,然后如何用 scikit-learn 轻松实现这一点。

如果我们首先从主分量与 x、y 轴对齐的旋转数据(上面的rotated_data)开始,点的 x 分量实际上是第一主分量。我们可以通过使用第一个特征向量,将主分量旋转回原始方向,就像我们在上面绘制 3σ线一样。

这是first_component和旋转后的数据一起绘制的。

这是与原始数据一起绘制的first_component_xy

数据点现在位于第一主成分轴上。

要使用 scikit-learn 获得第一个主成分,只需将成分数设置为 1 并转换数据。

数组first_componentfirst_component_xy将和上面显示的一样。

总结

与基本矩阵变换相比,主成分分析更容易理解。我们可以将协方差矩阵分解为旋转和缩放矩阵。

**旋转矩阵:这些矩阵旋转数据而不改变其形状。类似地,特征向量用于将数据“旋转”到一个新的坐标系中,以便相关的特征与新的轴(主分量轴)对齐。

**缩放矩阵:这些对角矩阵沿着不同的坐标轴缩放数据。类似地,特征值的对角矩阵给出了沿着不同主分量轴的数据方差(它们的尺度)的度量。

最后,降维与首先旋转具有要与主分量对齐的特征值的数据,然后仅使用具有最大特征值的分量是相同的。

posted @ 2024-10-13 15:25  绝不原创的飞龙  阅读(264)  评论(0)    收藏  举报