TowardsDataScience-博客中文翻译-2019-四十四-
TowardsDataScience 博客中文翻译 2019(四十四)
机器学习管道:非线性模型堆叠

通常,我们面对的数据集是相当线性的,或者可以被处理成一个数据集。但是,如果我们正在检查的数据集真的应该以非线性的方式来看待呢?步入非线性特征工程的世界。首先,我们来看看非线性数据的例子。接下来,我们将简要讨论作为非线性特征工程手段的 K-means 算法。最后,我们将在逻辑回归的基础上应用 K-means 来构建一个优秀的分类模型。
非线性数据的例子
非线性数据在商业世界中经常出现。示例包括:分组群体行为(营销)、群体活动的库存模式(销售)、以前交易的异常检测(财务)等。[1].举一个更具体的例子(供应链/物流),我们甚至可以在卡车司机超速行驶数据的可视化中看到它[1]:

快速浏览一下,我们可以看到这个数据集中至少有 2 个组。一组分为 100 米以上和 100 米以下。直观地,我们可以看到,在这里拟合一个线性模型将是可怕的。因此,我们需要一个不同类型的模型。应用 K-means,我们实际上可以找到如下所示的四个组[1]:

借助 K-means,我们现在可以对上述驾驶员数据集进行额外分析,以产生预测性见解,帮助企业对驾驶员的行驶距离和超速模式进行分类。在我们的例子中,我们将 K-means 应用于我们自己的虚拟数据集,以节省更多的特征工程现实生活数据的步骤。
k 均值
在我们开始构建我们的数据之前,让我们花一些时间来回顾一下 K-means 实际上是什么。K-means 是一种在未标记的数据集内寻找一定数量的聚类的算法[2]。注意“未标记”这个词。这意味着 K-means 是一个无监督的学习模型。当你得到数据却不知道如何标注时,这非常有用。K-means 可以帮你标记群组——非常酷!
应用非线性特征工程
对于我们的数据,我们将使用来自 sklearn [3]的 make_circles 数据。好吧,让我们来看看例子:
#Load up our packages
import pandas as pd
import numpy as np
import sklearn
import scipy
import seaborn as sns
from sklearn.cluster import KMeans
from sklearn.preprocessing import OneHotEncoder
from scipy.spatial import Voronoi, voronoi_plot_2d
from sklearn.data sets.samples_generator import make_circles
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
%matplotlib notebook
我们的下一步是使用创建一个 K-means 类。对于那些不熟悉类(不是你在学校学的科目)的人来说,把编码中的类想象成一个超级函数,里面有很多函数。现在,我知道 sklearn 中已经有一个 k-means 聚类算法,但是我非常喜欢 Alice Zheng 的这个类,因为它有详细的注释和我们很快就会看到的可视化效果[4]:
class KMeansFeaturizer:
"""Transforms numeric data into k-means cluster memberships.
This transformer runs k-means on the input data and converts each data point
into the id of the closest cluster. If a target variable is present, it is
scaled and included as input to k-means in order to derive clusters that
obey the classification boundary as well as group similar points together. Parameters
----------
k: integer, optional, default 100
The number of clusters to group data into. target_scale: float, [0, infty], optional, default 5.0
The scaling factor for the target variable. Set this to zero to ignore
the target. For classification problems, larger `target_scale` values
will produce clusters that better respect the class boundary. random_state : integer or numpy.RandomState, optional
This is passed to k-means as the generator used to initialize the
kmeans centers. If an integer is given, it fixes the seed. Defaults to
the global numpy random number generator. Attributes
----------
cluster_centers_ : array, [k, n_features]
Coordinates of cluster centers. n_features does count the target column.
""" def __init__(self, k=100, target_scale=5.0, random_state=None):
self.k = k
self.target_scale = target_scale
self.random_state = random_state
self.cluster_encoder = OneHotEncoder().fit(np.array(range(k)).reshape(-1,1))
def fit(self, X, y=None):
"""Runs k-means on the input data and find centroids. If no target is given (`y` is None) then run vanilla k-means on input
`X`. If target `y` is given, then include the target (weighted by
`target_scale`) as an extra dimension for k-means clustering. In this
case, run k-means twice, first with the target, then an extra iteration
without. After fitting, the attribute `cluster_centers_` are set to the k-means
centroids in the input space represented by `X`. Parameters
----------
X : array-like or sparse matrix, shape=(n_data_points, n_features) y : vector of length n_data_points, optional, default None
If provided, will be weighted with `target_scale` and included in
k-means clustering as hint.
"""
if y is None:
# No target variable, just do plain k-means
km_model = KMeans(n_clusters=self.k,
n_init=20,
random_state=self.random_state)
km_model.fit(X) self.km_model_ = km_model
self.cluster_centers_ = km_model.cluster_centers_
return self # There is target information. Apply appropriate scaling and include
# into input data to k-means
data_with_target = np.hstack((X, y[:,np.newaxis]*self.target_scale)) # Build a pre-training k-means model on data and target
km_model_pretrain = KMeans(n_clusters=self.k,
n_init=20,
random_state=self.random_state)
km_model_pretrain.fit(data_with_target) # Run k-means a second time to get the clusters in the original space
# without target info. Initialize using centroids found in pre-training.
# Go through a single iteration of cluster assignment and centroid
# recomputation.
km_model = KMeans(n_clusters=self.k,
init=km_model_pretrain.cluster_centers_[:,:2],
n_init=1,
max_iter=1)
km_model.fit(X)
self.km_model = km_model
self.cluster_centers_ = km_model.cluster_centers_
return self
def transform(self, X, y=None):
"""Outputs the closest cluster id for each input data point. Parameters
----------
X : array-like or sparse matrix, shape=(n_data_points, n_features) y : vector of length n_data_points, optional, default None
Target vector is ignored even if provided. Returns
-------
cluster_ids : array, shape[n_data_points,1]
"""
clusters = self.km_model.predict(X)
return self.cluster_encoder.transform(clusters.reshape(-1,1))
def fit_transform(self, X, y=None):
"""Runs fit followed by transform.
"""
self.fit(X, y)
return self.transform(X, y)
不要让大量的文本困扰你。我只是把它放在那里,以防你想在你自己的项目中试验它。之后,我们将创建我们的训练/测试集,并将种子设置为 420 以获得相同的结果:
# Creating our training and test set
seed = 420training_data, training_labels = make_circles(n_samples=2000, factor=0.2)kmf_hint = KMeansFeaturizer(k=100, target_scale=10, random_state=seed).fit(training_data, training_labels)kmf_no_hint = KMeansFeaturizer(k=100, target_scale=0, random_state=seed).fit(training_data, training_labels)def kmeans_voronoi_plot(X, y, cluster_centers, ax):
#Plots Voronoi diagram of k-means clusters overlaid with data
ax.scatter(X[:, 0], X[:, 1], c=y, cmap='Set1', alpha=0.2)
vor = Voronoi(cluster_centers)
voronoi_plot_2d(vor, ax=ax, show_vertices=False, alpha=0.5)
现在,让我们来看看未标记的非线性数据:
#looking at circles data
df = pd.DataFrame(training_data)
ax = sns.scatterplot(x=0, y=1, data=df)

就像我们司机的 into 数据集一样,我们的圈内圈外绝对不是线性数据集。接下来,我们将应用 K-means 比较视觉结果,给它一个关于我们所想的提示和没有提示:
#With hint
fig = plt.figure()
ax = plt.subplot(211, aspect='equal')
kmeans_voronoi_plot(training_data, training_labels, kmf_hint.cluster_centers_, ax)
ax.set_title('K-Means with Target Hint')#Without hint
ax2 = plt.subplot(212, aspect='equal')
kmeans_voronoi_plot(training_data, training_labels, kmf_no_hint.cluster_centers_, ax2)
ax2.set_title('K-Means without Target Hint')

我发现在有提示和没有提示的情况下,结果相当接近。如果您想要更多的自动化,那么您可能不想应用任何提示。但是如果你能花些时间看看你的数据集给它一点提示,我会的。原因是它可以节省你运行模型的时间,所以 k-means 花更少的时间自己计算。给 k-means 一个提示的另一个原因是,您在您的数据集中有领域专业知识,并且知道有特定数量的聚类。
用于分类的模型堆叠
有趣的部分到了——制作堆叠模型。有些人可能会问,堆叠模型和系综模型有什么区别。集成模型将多个机器学习模型结合起来,形成另一个模型[5]。所以,不多。我认为模型堆叠在这里更精确,因为 k-means 正在进入逻辑回归。如果我们能画一个文氏图,我们会在系综模型的概念中找到堆叠的模型。我在谷歌图片上找不到一个好的例子,所以我运用 MS paint 的魔力来呈现一个粗略的插图,供你观赏。

好了,美术课结束,回到编码。我们要做一个 kNN 的 ROC 曲线,逻辑回归(LR),k 均值馈入逻辑回归。
#Generate test data from same distribution of training data
test_data, test_labels = make_moons(n_samples=2000, noise=0.3, random_state=seed+5)training_cluster_features = kmf_hint.transform(training_data)
test_cluster_features = kmf_hint.transform(test_data)training_with_cluster = scipy.sparse.hstack((training_data, training_cluster_features))
test_with_cluster = scipy.sparse.hstack((test_data, test_cluster_features))#Run the models
lr_cluster = LogisticRegression(random_state=seed).fit(training_with_cluster, training_labels)classifier_names = ['LR',
'kNN']
classifiers = [LogisticRegression(random_state=seed),
KNeighborsClassifier(5)]
for model in classifiers:
model.fit(training_data, training_labels)
#Plot the ROC
def test_roc(model, data, labels):
if hasattr(model, "decision_function"):
predictions = model.decision_function(data)
else:
predictions = model.predict_proba(data)[:,1]
fpr, tpr, _ = sklearn.metrics.roc_curve(labels, predictions)
return fpr, tprplt.figure()
fpr_cluster, tpr_cluster = test_roc(lr_cluster, test_with_cluster, test_labels)
plt.plot(fpr_cluster, tpr_cluster, 'r-', label='LR with k-means')for i, model in enumerate(classifiers):
fpr, tpr = test_roc(model, test_data, test_labels)
plt.plot(fpr, tpr, label=classifier_names[i])
plt.plot([0, 1], [0, 1], 'k--')
plt.legend()
plt.xlabel('False Positive Rate', fontsize=14)
plt.ylabel('True Positive Rate', fontsize=14)

好吧,我第一次看到 ROC 曲线的时候,我就想我该怎么读这个东西?你想要的是最快到达左上角的模型。在这种情况下,我们最精确的模型是堆叠模型——带 k 均值的线性回归。我们的模型工作的分类是挑选哪里,哪个数据点属于大圆或小圆。
结论
唷,我们在这里讨论了相当多的事情。首先,我们来看看现实世界中可能会遇到的非线性数据和例子。其次,我们将 k-means 作为一种工具来发现更多以前没有的数据特征。接下来,我们将 k-means 应用于我们自己的数据集。最后,我们将 k-means 堆叠到逻辑回归中以建立一个更好的模型。总的来说很酷。需要注意的是,我们没有对模型进行调优,这会改变性能,我们也没有比较那么多模型。但是,将无监督学习结合到监督模型中可能会证明非常有用,并帮助您提供通过其他方式无法获得的洞察力!
免责声明:本文陈述的所有内容均为我个人观点,不代表任何雇主。还撒了附属链接。
[1] A,特雷维尼奥,K-means 聚类介绍(2016),【https://www.datascience.com/blog/k-means-clustering
[2] J,VanderPlas,Python 数据科学手册:处理数据的基本工具(2016),https://amzn.to/2SMdZue
[3] Scikit-learn 开发者,sk learn . data sets . make _ circles(2019), https://Scikit-learn . org/stable/modules/generated/sk learn . data sets . make _ circles . html # sk learn . data sets . make _ circles
[4] A,郑等,面向机器学习的特征工程:面向数据科学家的原理与技术(2018),
[5] F,Gunes,为什么堆叠系综模型会赢得数据科学竞赛?(2017),https://blogs . SAS . com/content/subcivily musings/2017/05/18/stacked-ensemble-models-win-data-science-competitions/
机器学习:用 Python 实现多项式回归
在这篇文章中,我们将指导你使用多项式回归进行机器学习的中间步骤。
本帖中使用的缩写:
- 叶:多年经验
先看看线性回归
在我之前的帖子中,我们讨论了关于线性回归。让我们回顾一下。对其值为线性的数据集应用线性回归,如下例:

Salary based on Years of Experience (salary_data.csv)
而现实生活并没有那么简单,尤其是当你从不同行业的很多不同公司去观察的时候。1 个叶老师和 1 个叶工程师工资不一样;甚至 1 叶土木工程师不同于机械工程师;如果你比较两个不同公司的机械工程师,他们的工资也大不相同。那么如何才能预测一个应聘者的薪资呢?
今天,我们将使用另一个数据集来表示多项式形状。

Salary based on Years of Experience (position_salaries.csv)
为了了解工资增长的总体情况,让我们将数据集可视化为一个图表:

Salary based on Years of Experience — Plotting
让我们想想我们的候选人。他有 5 叶。如果我们在这个例子中使用线性回归会怎么样?

Linear visualization
根据上图,我们候选人的工资范围大概是从 减去【10,000 美元到 300,000 美元。为什么?看,这种情况下的工资观察不是线性的。它们呈弧形!这就是为什么在这个场景中应用线性回归不能给出正确的值。是时候进行多项式回归了。
为什么要多项式回归?
因为要准确得多!
我们已经知道 5 叶的工资是 11 万美元,6 叶是 15 万美元。意思是 5.5 叶的工资应该在他们之间!最佳价值应该是这样的:

Polynomial visualization
让我们比较一下使用线性和多项式之间的差距。注意红色圆圈:

Comparison between Linear and Polynomial
太小看不见?缩小它!

Gaps between Linear and Polynomial
比用线性回归准确的多 7.75 倍!
那么我们 5.5 叶候选人的工资怎么算呢?我们可以用平均值来快速计算。因为 5.5 是 5 和 6 的平均值,所以工资可以计算为:
(150,000 + 110,000)/2 =130,000 美元
注:如果你不知道什么是均值,请阅读我之前关于 均值、中位数、众数 的帖子。谢了。
但是不是最高准确率而且太手动!让我们应用机器学习来获得更精确和灵活的计算。是时候启动您的 Spyder IDE 了!
用 Python 实现多项式回归
在这个例子中,我们必须使用 4 个库作为numpy、pandas、matplotlib和sklearn。现在我们必须先导入库并获取数据集:
代码解释:
dataset:该表包含了我们 csv 文件中的所有值X:第 2 列,包含年经验数组y:包含薪资数组的最后一列
让我们分割我们的dataset来得到训练集和测试集(每个集的X和y值)
代码解释:
test_size=0.2:我们将把dataset(10 个观察值)分成两部分(训练集、测试集),并且测试集与dataset的比率为 0.2 (2 个观察值将被放入测试集)。你可以放 1/5 得到 20%或者 0.2,它们是一样的。我们不应该让测试集太大;如果它太大,我们将缺乏数据来训练。通常情况下,我们应该选择 5%到 30%左右。train_size:如果我们已经使用了 test_size,剩余的数据将自动分配给 train_size。random_state:这是随机数发生器的种子。我们也可以放一个RandomState类的实例。如果我们将其留空或为 0,将使用由np.random使用的RandomState实例。
我们已经有了训练集和测试集,现在我们必须建立回归模型。首先,我们将建立一个线性回归模型并将其可视化(在您的练习中不需要包括这一步,我们这样做只是为了比较线性和多项式):
调用viz_linear()函数后,可以看到如下图:

Linear Regression model visualization
另一方面,我们将构建多项式回归模型,并将其可视化以查看差异:
调用viz_polynomial()函数后,可以看到如下图:

Polynomial Regression model visualization
最后一步,让我们使用线性回归模型和多项式回归模型来预测候选值(5.5 YE):
你可以看到,使用线性回归模型和多项式回归模型的预测值是完全不同的!

Comparison between lin_reg and pol_reg
让我们向上滚动,再次检查我们得到了什么?根据我们的数据集,我们的工资应该是:
11 万美元< the salary < $150,000
But the predicted salary using Linear Regression 【 is 24.95 万美元。无法接受(但根据线性回归还是在-1 万到 30 万的范围内)!用多项式回归怎么样?我们的pol_reg值为132,148.43750 美元,非常接近我们的平均值 130,000 美元。
答对了。是时候让我们的候选人知道我们将为他提供 132,148 美元的最高工资了!
在结束我的帖子之前,这里是我们完整的源代码和数据集,供你在操场上练习:
天天快乐学习!
机器学习——用回归预测房价
运行算法以获得最准确的结果
本文是我关于住房数据集的系列文章的最后一篇。对于门外汉,我已经在前两篇文章中介绍了 EDA 和特性工程。
总结到目前为止的工作——我们在第二篇文章中讨论了 EDA 中极其平凡的数据管理工作和细致的功能再造。我们研究了所有的变量,根据变量与目标值的相关性决定保留什么,放弃什么。我们最终选择了 64 个精心挑选的特征来训练数据集并预测最终的房价!

首先,我们将数据集以 80:20 的比例分成训练和测试。
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = .20, random_state = 42)
接下来,我们使用随机森林回归器来训练数据集,并使用随机搜索 CV 来获得最佳超参数。
rf = RandomForestRegressor(random_state = 42)#Hyperparamater tuning using RanodomSearchCV
random_grid = {
'n_estimators': [int(x) for x in np.linspace(start = 200, stop = 2000, num = 10)],
'max_features': ['auto', 'sqrt', 'log2'],
'max_depth' : [6,7,8,9,10],
'min_samples_split' : [2, 5, 10],
'min_samples_leaf' : [1, 2, 4]
}rf_random = RandomizedSearchCV(estimator = rf, param_distributions = random_grid, n_iter = 100, cv = 5, verbose=2, random_state=42, n_jobs = -1)
最后,我们在训练集上拟合模型,并获得可能的最佳分数。
rf_random.fit(X_train, y_train)
print(rf_random.best_params_)
print(rf_random.best_score_)
最好成绩是 0.87。在进行网格搜索时,最佳得分略微增加到 0.88。
#Hyperparameter tuning using GridSearchCVparam_grid = {
'n_estimators': [int(x) for x in np.linspace(start = 600, stop = 2000, num = 10)],
'max_features': ['auto', 'sqrt', 'log2'],
'max_depth' : [7,8,9,10],
'min_samples_split' : [2, 5],
'min_samples_leaf' : [1, 2]
}grid_search = GridSearchCV(estimator = rf, param_grid = param_grid,
cv = 3, n_jobs = -1, verbose = 2)grid_search.fit(X_train, y_train)
print(grid_search.best_params_)
print(grid_search.best_score_)
Lasso 回归和随机搜索给出了一个差得多的最佳分数 0.85。
XGBoost 回归和随机搜索 CV 给出了更高的分数 0.9。
然而我用岭回归得到了最好的分数。
#Ridge Regressorparams_ridge ={
'alpha':[0.25,0.5,1],
'solver':['auto', 'svd', 'cholesky', 'lsqr', 'sparse_cg', 'sag', 'saga']
}ridge = Ridge()
ridge_random = RandomizedSearchCV(estimator = ridge, param_distributions = params_ridge,
n_iter=50, cv=5, n_jobs=-1,random_state=42, verbose=2)
ridge_random.fit(X_train, y_train)
print(ridge_random.best_params_)
print(ridge_random.best_score_)ridge_grid = GridSearchCV(estimator = ridge, param_grid = params_ridge, cv = 5, n_jobs = -1, verbose = 2)ridge_grid.fit(X_train, y_train)
print(ridge_grid.best_params_)
print(ridge_grid.best_score_)
随机搜索和网格搜索给我的最高分都是 0.92。
因此,我们从最佳估计量着手,对测试集进行预测。
model_ridge = ridge_random.best_estimator_
y_pred_ridge = np.exp(model_ridge.predict(X_test))
output_ridge = pd.DataFrame({'Id': test['Id'], 'SalePrice': y_pred_ridge})
output_ridge.to_csv('prediction_ridge.csv', index=False)
这让我在 Kaggle 上得了 0.12460 分!
完整代码请参考以下链接:https://github . com/pritha 21/ka ggle/blob/master/House _ prices . ipynb
你可能需要使用https://nbviewer.jupyter.org/来查看
任何帮助我提高分数的建议都欢迎!
机器学习—概率和统计
机器学习的基本概率与统计
机器学习是一个跨学科领域,它使用统计、概率和算法从数据中学习,并提供可用于构建智能应用程序的见解。在本文中,我们将讨论机器学习中广泛使用的一些关键概念。

概率和统计是数学的相关领域,它们关注于分析事件的相对频率。
概率处理预测未来事件发生的可能性,而统计涉及对过去事件发生频率的分析。
可能性
大多数人对概率的程度都有一个直观的认识,这也是为什么我们在日常对话中会使用“大概”和“不太可能”这样的词,但我们会谈到如何对那些程度做出量化的主张[1]。
在概率论中,一个事件是一个实验的一组结果,一个概率被分配给这些结果。如果**E**代表一个事件,那么**P(E)**代表**E**发生的概率。**E**可能发生(成功)或可能不发生(失败)的情况称为 试验 。
这个事件可以是任何事情,比如扔硬币、掷骰子或者从袋子里拿出一个彩球。在这些例子中,事件的结果是随机的,所以代表这些事件结果的变量被称为随机变量。
让我们考虑一个抛硬币的基本例子。如果硬币是公平的,那么它出现正面的可能性和出现反面的可能性一样大。换句话说,如果我们要反复投掷硬币很多次,我们预计大约一半的投掷是正面,一半是反面。在这种情况下,我们说得到人头的概率是 1/2 或者 0.5。
事件的经验概率由事件发生的次数除以观察到的事件总数得出。如果对于**n**试验,我们观察到**s**成功,成功的概率是 s/n。任何投掷硬币的顺序都可能有多于或少于 50%的正面。
另一方面,理论概率由特定事件发生的方式数除以可能结果的总数得出。所以头可能出现一次,可能的结果是两次(头,尾)。人头的真实(理论)概率是 1/2。
联合概率
用**P(A and B) or P(A ∩ B)**表示的事件 A 和 B 的概率是事件 A 和 B 都发生的概率。**P(A ∩ B) = P(A). P(B)** 。这仅适用于**A**和**B**相互独立的情况,也就是说,如果**A**发生,并不改变**B**的概率,反之亦然。
条件概率
让我们考虑 A 和 B 都不是独立的,因为如果 A 发生了,B 的概率就更高。当 A 和 B 不独立时,计算条件概率 P (A|B)往往很有用,P 是给定 B 发生的概率:**P(A|B) = P(A ∩ B)/ P(B)** 。
以事件 B 为条件的事件 A 的概率被表示和定义
P(A|B) = P(A∩B)/P(B)
同理,**P(B|A) = P(A ∩ B)/ P(A)** 。我们可以把 A 和 B 的联合概率写成**P(A ∩ B)= p(A).P(B|A)**,意思是:“两个事情发生的几率就是第一个发生的几率,然后给第一个发生的几率第二个。”
贝叶斯定理
贝叶斯定理是两个事件的条件概率之间的关系。例如,如果我们想找出在炎热晴朗的日子里卖冰淇淋的概率,贝叶斯定理为我们提供了工具,让我们利用先验知识来判断在任何其他类型的日子里(下雨、刮风、下雪等)卖冰淇淋的概率。).

其中*H*和*E* 是事件,*P(H|E)* 是事件*H*发生的条件概率,假设事件*E* 已经发生。方程中的概率*P(H)*基本是频率分析;给定我们的 先验 数据事件发生的概率是多少。等式中的*P(E|H)*被称为 可能性 ,本质上是证据是正确的概率,给出了来自频率分析的信息。*P(E)* 是实际证据为真的概率。
让*H* 代表我们卖冰淇淋的事件,而*E*代表天气的事件。然后我们可能会问在给定的天气类型下,某一天卖出冰淇淋的可能性有多大?数学上,这被写成P(H=ice cream sale | E= type of weather),相当于等式的左侧。*P(H)*右手边是被称为先验的表达式,因为我们可能已经知道冰淇淋销售的边际概率。在我们的例子中,这是*P(H = ice cream sale)*,也就是说,不管外面的天气如何,都有可能卖出冰淇淋。例如,我可以查看这样的数据:潜在的 100 人中有 30 人实际上在某个地方的某个商店购买了冰淇淋。所以我的*P(H = ice cream sale) = 30/100 = 0.3,* 先于我对天气的任何了解。这就是贝叶斯定理允许我们整合先验信息的方式[2]。
贝叶斯定理的一个经典应用是在临床试验的解释中。假设在一次常规体检中,你的医生告诉你,你的一种罕见疾病检测呈阳性。你也知道这些测试的结果有一些不确定性。假设我们对于 95%的患病患者有一个灵敏度(也称为真阳性率)结果,对于 95%的健康患者有一个特异性(也称为真阴性率)结果。
如果我们让“+”和“-”分别表示阳性和阴性测试结果,那么测试精度就是条件概率:*P*(+|disease) *= 0.95, P*(-|healthy) *= 0.95,*
在贝叶斯术语中,我们希望计算给定阳性测试的疾病概率,*P*(disease|+)。
*P*(disease|+) *= P(*+|disease)** P*(disease)*/P*(+)
如何评价 *P(+)* ,所有阳性病例?我们必须考虑两种可能性,*P*(+|disease) 和*P*(+|healthy)。假阳性的概率*P*(+|healthy)是*P*(-|healthy). 的补码,因此是 *P*(+|healthy) = 0.05。

重要的是,贝叶斯定理揭示,为了计算假设检测结果为阳性时你患病的条件概率,你需要知道你患病的“先验”概率*P*(disease),假设没有任何信息。也就是说,你需要知道该疾病在你所属人群中的总体发病率。假设这些测试应用于实际发现患病人数为 0.5%的人群,*P*(disease)*= 0.005*即*P*(healthy) *= 0.995* 。
所以,*P(disease|+) = 0.95 * 0.005 /(0.95 * 0.005 + 0.05 * 0.995) = 0.088*
换句话说,尽管测试看起来很可靠,但你实际患病的概率仍低于 9%。得到阳性结果会增加你患病的可能性。但是把 95 %的检测准确率解释为你有患病的概率是不正确的。
描述统计学
描述性统计是指总结和组织数据集中信息的方法。我们将使用下表来描述一些统计概念[4]。

元素:为其收集信息的实体称为元素。在上表中,元素是 10 个申请者。元素也称为案例或主题。
变量:一个元素的特性称为变量。它可以为不同的元素取不同的值,例如婚姻状况、抵押贷款、收入、级别、年份和风险。变量也称为属性。
变量可以是定性或定量。
定性:一个定性变量能够使元素根据某种特征被分类或归类。定性变量为marital status、mortgage、rank和risk。定性变量也称为分类变量。
定量:定量变量接受数值,并允许对其进行有意义的运算。定量变量是income和year。定量变量也叫数值变量。
离散变量:一个可以取有限个或可计数个值的数值变量是一个离散变量,每个值可以用图形表示为一个单独的点,每个点之间有空格。‘year’是离散变量的一个例子..
连续变量:可以取无穷多个值的数值变量是连续变量,其可能的值在数轴上形成一个区间,点与点之间没有空格。‘income’是连续变量的一个例子。
群体:群体是对特定问题感兴趣的所有元素的集合。参数是总体的特征。
样本:样本由总体的一个子集组成。样本的特征称为统计量。
随机抽样:当我们抽取一个每个元素都有同等机会被选中的样本。
中心测量:平均值、中间值、众数、中间范围
指出数据的中心部分在数字线上的位置。
平均
平均值是数据集的算术平均值。要计算平均值,请将这些值相加,然后除以值的个数。样本平均值是样本的算术平均值,用 x̄表示(“x-bar”)。总体平均值是总体的算术平均值,用𝜇表示(“myu”,m 的希腊语字母)。
中位数
中值是中间的数据值,当有奇数个数据值并且数据已经按升序排序时。如果是偶数,则中位数是两个中间数据值的平均值。当收入数据按升序排序时,两个中间值分别为$32,100 和$32,200,其平均值为收入中位数$32,150。
方式
众数是出现频率最高的数据值。数量和类别变量都可以有模式,但只有数量变量可以有均值或中位数。每个收入值只出现一次,所以没有模式。年的模式是 2010 年,频率为 4。
中档
中间值是数据集中最大值和最小值的平均值。中档收入是:
mid-range(income) = (max(income) + min(income))/2 = (48000 + 24000)/2 = $36000
可变性的度量:范围、方差、标准差
量化数据中存在的变异、扩散或分散的数量。
范围
变量的范围等于最大值和最小值之差。收入范围是:
range(income) = max (income) − min (income) = 48,000 − 24,000 =$24000
范围只反映了最大和最小观察值之间的差异,但它未能反映数据是如何集中的。
差异
总体方差被定义为平均值的方差的平均值,表示为𝜎*²*(“sigma-squared”):

方差越大,意味着数据越分散。
样本方差s*²*大约是方差平方的平均值,用n-1代替N。出现这种差异是因为样本均值被用作真实总体均值的近似值。

标准偏差
一组数字的标准差或sd 告诉你单个数字与平均值的差异有多大。
样本标准差是样本方差的平方根:sd = √ s*²*。例如,收入偏离均值 7201 美元。
总体标准差是总体方差的平方根: sd= √ 𝜎*²*。

Three different data distributions with same mean (100) and different standard deviation (5,10,20)
标准差越小,峰越窄,数据点越接近平均值。数据点离平均值越远,标准差越大。
位置测量:百分位数、Z 分数、四分位数
指示特定数据值在数据分布中的相对位置。
百分位
数据集的第 p 个百分位数是这样的数据值,即数据集中 p 个百分比的值等于或低于该值。第 50 百分位是中间值。例如,收入中值为 32,150 美元,50%的数据值等于或低于该值。
百分等级
数据值的百分位等级等于数据集中等于或低于该值的值的百分比。例如,百分位数排名。申请人 1 的 38,000 美元的收入的 90%,因为这是等于或小于 38,000 美元的收入的百分比。

四分位数间距(IQR)
第一个四分位数(Q1)是数据集的第 25 个百分位数;第二个四分位数(Q2)是第 50 个百分位数(中位数);第三个四分位数(Q3)是第 75 个百分位数。
IQR 使用公式测量第 75 次和第 25 次观测之间的差异:IQR = Q3 Q1。
数据值 x 是异常值,如果x ≤ Q1 − 1.5(IQR), or x ≥ Q3 + 1.5(IQR).
z 分数
特定数据值的Z 值代表该数据值高于或低于平均值的标准偏差。

所以,如果 z 是正的,就意味着这个值高于平均值。对于申请人 6,Z 得分为(24,000-32,540)/7201 ≈- 1.2,这意味着申请人 6 的收入低于平均值 1.2 个标准差。
单变量描述统计
描述单变量数据模式的不同方式包括集中趋势:均值、众数和中位数,分散:范围、方差、最大值、最小值、四分位数和标准差。

Pie chart [left] & Bar chart [right] of Marital status from loan applicants table.
用于显示单变量数据的各种图表通常是条形图、直方图、饼图。等等。
双变量描述统计
双变量分析涉及两个变量的分析,目的是确定它们之间的经验关系。用于显示双变量数据的各种图通常为散点图、箱线图。
散点图
可视化两个定量变量 x 和 y 之间关系的最简单方法。对于两个连续变量来说,散点图是常见的图形。每个(x,y)点被绘制在笛卡尔平面上,x 轴在水平方向,y 轴在垂直方向。散点图有时被称为相关图,因为它们显示两个变量是如何相关的。
相互关系
相关性是一种旨在量化两个变量之间关系强度的统计数据。相关系数 r量化两个量化变量之间线性关系的强度和方向。相关系数定义为:

其中sx和sy分别代表 x 变量和 y 变量的标准偏差。−1 ≤ r ≤ 1。
如果 r 为正且显著,我们说 x 和 y正相关。x 的增加与 y 的增加相关联。
如果 r 为负且显著,我们说 x 和 y负相关。x 的增加与 y 的减少有关。

Positive correlation (r > 0), Negative correlation (r < 0), No correlation (r = 0)
箱线图
盒状图也称为盒须图,用于描绘值的分布。当一个变量是分类变量而另一个是连续变量时,通常使用箱线图。使用盒状图时,将数据值分成四个部分,称为四分位数。你从寻找中间值开始。中位数将数据值分成两半。找到每一半的中间值会将数据值分成四个部分,即四分位数。
图上的每个框都显示了从框底部下半部分的中值到框顶部上半部分的中值的范围。方框中间的一条线出现在所有数据值的中值处。然后触须指向数据中的最大值和最小值。

数据集的五位数摘要由minimum、Q1、median、Q3和maximum组成。
箱线图对于指示分布是否偏斜以及数据集中是否存在潜在的异常观察值(异常值)特别有用。
左边的须状物向下延伸到最小值,该最小值不是异常值。右边的须状物延伸到不是异常值的最大值。当左须比右须长时,则分布是左偏的,反之亦然。当晶须长度大致相等时,分布是对称的。
结论
概率和统计的基本概念是任何对机器学习感兴趣的人必须具备的。我简要介绍了机器学习中最常用的一些基本概念。我希望你喜欢这篇文章,并学到一些新的有用的东西。
感谢您的阅读。
参考
[1]http://greenteapress.com/thinkstats/thinkstats.pdf
[2]https://seeing-theory . brown . edu/basic-probability/index . html
[4]https://online library . Wiley . com/doi/pdf/10.1002/9781118874059 . app 1
[5]https://medium . com/analytics-vid hya/descriptive-statistics-for-data-science-2f 304 a 36 AC 34
机器学习项目 10 —预测哪些客户购买了 iPhone

iPhone Sales prediction — source pixabay.com
到目前为止,我们已经完成了 9 个项目,涵盖了不同类型的回归。
# 100 daysofml code # 100 projects inml
回归包括预测连续的输出变量或数量。
回归预测建模的示例包括:
- 根据员工的工作经验预测其工资。
- 根据城市和卧室数量预测房价。
- 给定营销预算,预测企业的销售额。
现在,有一组不同的问题需要我们将输出变量分成两个或更多的标签或类别。我们需要预测给定观察的标签或类别。
这些被称为分类预测建模。例子包括:
- 将电子邮件标记为垃圾邮件。
- 预测顾客是否会购买。
- 预测一个人是否会得糖尿病。
以上是二元分类问题的例子。
我们也可能有多标签或多类分类问题。在多类问题中,类是互斥的。输出变量可以被分类成任何一类。例如,一部电影可以被归类为 PG 13 或成人,但不能两者都是。
在多标签问题中,输出变量可以在多个标签下分类。回到我们的电影例子,一部电影可以分为“推理片”和“言情片”。我们将在未来的项目中更详细地讨论这些主题。
让我们从第一个分类问题开始,我们将使用逻辑回归。它被称为逻辑回归,因为它通过画一条直线将输出分成两类,如下所示

项目目标
让我们看看数据集。有趣的是,我们假设这些是购买或未购买 iPhone 的客户的记录。示例行如下所示。完整的数据集可以在这里访问。
我们在这个项目中的目标是,在给定客户的性别、年龄和工资的情况下,预测他们是否会购买 iPhone。
步骤 1:加载数据集
x 将包含所有 3 个独立变量“性别”、“年龄”和“工资”
y 将包含因变量“购买的 iPhone”
步骤 2:将性别转换为数字
对于大多数机器学习算法,我们必须将分类变量转换为数字。这里我们有一个必须转换的“性别”字段。
我们将使用 LabelEncoder 类将性别转换为数字
让我们看看我们的 X 和 y:

步骤 3:将数据分成训练集和测试集
步骤 4:特征缩放
对于逻辑回归算法,我们必须进行特征缩放。为此,我们将使用标准定标器
步骤 5:拟合逻辑回归
我们将使用 sklearn linear_model 库中的 LogisticRegression 类。当我们创建这个类的对象时,它需要很多参数。其中之一是“求解器”,它指定在优化问题中使用哪种算法。
文件指出:
对于小型数据集,“liblinear”是一个不错的选择,而“sag”和“saga”对于大型数据集更快。
对于多类问题,只有‘Newton-CG’,‘sag’,‘saga’和‘lbfgs’处理多项式损失;“liblinear”仅限于一对多方案。
牛顿-cg、lbfgs 和 sag 只处理 L2 惩罚,而 liblinear 和 saga 处理 L1 惩罚。
由于这是一个小数据集,我选择了“liblinear”
第六步:做预测
步骤 7:检查预测的准确性
在分类问题中,我们可以使用混淆矩阵来比较预测结果和实际结果。
混淆矩阵:它会告诉我们正确和错误条目的数量。

让我们花一分钟来分析这个矩阵。这告诉我们什么?
- 如果一个人没有购买 iPhone,预测值也说他们没有购买——这是真负值(TN ),即实际值是 0,预测值也是 0。
- 如果一个人没有购买 iPhone,但预测值显示他们购买了——这是误报(FP ),即实际值为 0,预测值为 1。
- 如果一个人已经购买了一部 iPhone,但预测值显示他们没有购买——这是假阴性(FN ),即实际值为 1,预测值为 0。
- 如果一个人买了一部 iPhone,预测值也说他们买了——这是真正的(TP ),即实际值是 1,预测值也是 1。
准确性得分:这是用于检查模型准确性的最常见的度量。它是正确预测总数占预测总数的百分比。
准确率得分= (TP + TN) / (TP + TN + FP + FN)
回忆分数:是我们正确预测的正面事件的百分比。
召回分数= TP / (TP + FN)
Precision Score: 是预测的阳性事件实际为阳性的百分比。
精度= TP / (TP + FP)
[[65 3]
[ 6 26]]
Accuracy score: 0.91
Precision score: 0.896551724137931
Recall score: 0.8125
我们获得了 91%的准确率,这已经很不错了。
让我们根据上面的公式手动计算分数。
混淆矩阵
- TN = 65
- FP = 3
- FN = 6
- TP = 26
我们可以从上面的矩阵中看到,我们只得到 9 个错误的预测。
Accuracy Score = (TP + TN) / (TP + TN + FP + FN)Accuracy Score =(26 + 65)/ (26 + 65 + 3 + 6)Accuracy Score =91/100 = 0.91 = 91%
Recall Score = TP / (TP + FN)Recall Score =26/ (26 + 6)Recall Score =26/32 = 0.8125 = 81.25%
Precision = TP / (TP + FP)Precision = 26/ (26 + 3)Precision = 26/29 = 0.8965 = 89.65%
第八步:做出新的预测
你能做出以下预测吗——他们是否会购买 iPhone?
- 21 岁男性,年薪 4 万美元
- 21 岁男性,年薪 8 万美元
- 女性,21 岁,收入 4 万美元
- 女性,21 岁,年薪 8 万美元
- 41 岁男性,年薪 4 万美元
- 41 岁男性,年薪 8 万美元
- 41 岁女性,年薪 4 万美元
- 41 岁女性,年薪 8 万美元
让我知道你得到了什么预测。完整源代码是这里。
希望你喜欢这个项目——祝你好运
机器学习项目 17 —比较分类算法
在过去的 7 个项目中,我们使用不同的分类算法实现了同一个项目,即“逻辑回归”、“ KNN ”、“ SVM ”、“核 SVM ”、“朴素贝叶斯”、“决策树、随机森林。
我为每种算法分别写一篇文章的原因是为了理解每种算法背后的直觉。
# 100 daysofml code # 100 projects inml
在真实的场景中,当我们遇到一个问题时,我们无法预测哪种算法会表现得最好。显然从问题中,我们可以判断出是需要应用回归还是分类算法。但是很难事先知道应用哪种回归或分类算法。只有通过反复试验和检查性能指标,我们才能缩小范围并选择某些算法。
今天,我将向您展示如何比较不同的分类算法,并挑选出最佳的算法。而不是用一个算法实现整个项目,然后发现性能不好,我们会先检查一堆算法的性能,然后再决定用哪一个来实现项目。
让我们开始吧。
项目目标
我们将使用在项目 10 中使用的相同数据集。我们的目标是评估几种分类算法,并根据准确性选择最佳算法。
示例行如下所示。完整的数据集可以在访问。
步骤 1:加载数据集
我们将自变量“性别”、“工资”和“年龄”赋给 x。因变量“购买的 iphone”捕捉用户是否购买了该手机。我们会把这个赋值给 y。
步骤 2:将性别转换为数字
我们有一个必须转换成数字的分类变量“性别”。我们将使用 LabelEncoder 类将性别转换为数字。
步骤 3:特征缩放
除了决策树和随机森林分类器,其他分类器要求我们对数据进行缩放。所以让我们现在就开始吧。
步骤 4:比较分类算法
这是所有有趣的事情发生的地方:)
我将比较 6 种分类算法——我在以前的项目中介绍过的算法。也可以随意添加和测试其他内容。
- 逻辑回归
- KNN
- 内核 SVM
- 朴素贝叶斯
- 决策图表
- 随机森林
我们将使用 10 倍交叉验证来评估每个算法,我们将找到平均精度和标准偏差精度。
首先,我们将创建一个列表,并添加我们想要评估的不同分类器的对象。然后,我们遍历列表,使用 cross_val_score 方法来获得准确性。
Here is the output:Logistic Regression: Mean Accuracy = 82.75% — SD Accuracy = 11.37%
K Nearest Neighbor: Mean Accuracy = 90.50% — SD Accuracy = 7.73%
Kernel SVM: Mean Accuracy = 90.75% — SD Accuracy = 9.15%
Naive Bayes: Mean Accuracy = 85.25% — SD Accuracy = 10.34%
Decision Tree: Mean Accuracy = 84.50% — SD Accuracy = 8.50%
Random Forest: Mean Accuracy = 88.75% — SD Accuracy = 8.46%
结论
从结果中,我们可以看到,对于这个特定的数据集, KNN 和内核 SVM 表现得比其他人更好。所以我们可以把这两个人列入这个项目的候选名单。这与我们分别实现这些算法得出的结论完全相同。
希望你玩得开心。你可以在这里找到《T4》的全部源代码。
机器学习项目 9——根据身高和性别预测体重

source: pexels.com
今天我将处理这个 Kaggle 数据集。这个数据集有 10,000 行,提供了人的体重、身高和性别。我们必须在这个数据集上建立和训练一个模型,这样它就可以根据一个人的性别和身高来预测他的体重。这是我们从事的第一个拥有大型数据集的项目。所以这将会很有趣。
# 100 daysofml code # 100 projectsinml
让我们开始吧。
步骤 1:加载数据集
首先,我们将加载数据集。下面是样本数据集——完整的数据文件可以在这里找到。
第二步:分析数据
数据集包含 3 列,即“性别”、“身高”和“体重”。
高度以英寸为单位,重量以磅为单位。
我们来分析一下数据。
- dataset.info():
这个方法返回下面的输出。它基本上显示了条目的数量、列名和列类型。下面是该命令的输出。
<class ‘pandas.core.frame.DataFrame’>
RangeIndex: 10000 entries, 0 to 9999
Data columns (total 3 columns):
Gender 10000 non-null object
Height 10000 non-null float64
Weight 10000 non-null float64
dtypes: float64(2), object(1)
memory usage: 234.5+ KB
- dataset.describe():
描述方法显示数据集数值的基本统计信息,如平均值、标准差、百分位数、最小值和最大值。
例如:对于高度,我们可以看到平均值为 66.36 英寸,最小高度为 54.26 英寸,最大高度为 78.99 英寸。
同样,平均体重为 161.44 磅,最小体重为 64.7 磅,最大体重为 269.98 磅。
下面是该命令的输出。
Height Weight
count 10000.000000 10000.000000
mean 66.367560 161.440357
std 3.847528 32.108439
min 54.263133 64.700127
25% 63.505620 135.818051
50% 66.318070 161.212928
75% 69.174262 187.169525
max 78.998742 269.989699
- dataset.isnull()。sum()
这个方法主要用于检查数据集中是否有空值。这将在每一列中列出空值的数量
下面是该命令的输出。我们可以看到,这 3 列中没有空值。
Gender 0
Height 0
Weight 0
dtype: int64
步骤 3:将性别转换为数字
在运行任何机器学习模型之前,我们必须将所有分类值(文本值)转换为数值。在我们的数据集中,我们可以看到我们有一个字段——“性别”,这是分类。所以我们必须把这个场转换成数值。
将分类值转换为数字的典型方法是使用 LabelEncoder 类将文本转换为数字,然后使用 OneHotEncoder 添加虚拟变量。我们在我们的项目 2 中做到了这一点。
但这仅在分类字段包含 2 个以上的值时有用,例如,假设我们有一个名为“城市”的字段,它包含 2 个以上的值,如“休斯顿”、“纽约”和“旧金山”。
在这种情况下,我们将首先使用 LabelEncoder 将城市转换为数字,如:" Houston" => 0 和" New York" => 1 和" San Francisco" => 2。
然后,我们将使用 OneHotEncoder 添加 3 个虚拟变量,每个城市一个。最后,我们将删除一个哑变量以避免哑变量陷阱。
经验法则是——如果一个分类字段有 k 个值,那么你将需要 k-1 个虚拟变量。
现在在我们的例子中,我们的“性别”字段只包含 2 个值——“男性”和“女性”。当我们使用 LabelEncoder 时,它会转换 say "Male" =>0 和" Female" => 1。因为它只包含 2 个值,所以我们没有必要使用 OneHotEncoder 和添加虚拟变量。如果我们使用 OneHotEncoder,它将最终添加 2 个伪变量,但我们将最终删除 1 个以避免伪陷阱。所以做了也没什么意义。
因此,如果一个分类字段有两个值,我们有两种方法。
-
使用标签编码器
-
直接在数据框中替换
不使用 LabelEncoder,我们可以直接在数据帧中用 0 替换男性,用 1 替换女性,如下所示:
在这两种情况下,性别将被转换为男性 0 和女性 1,如下面 x 的屏幕截图所示。

步骤 4:将数据集分成训练集和测试集
我们将使用 80%的数据进行训练,20%的数据进行测试。
步骤 5:拟合回归模型
我们将使用线性回归来训练我们的模型。
步骤 6:预测测试集值
让我们比较一下预测值(lin_pred)和实际值(y_test)。我们可以看到我们的模型做得相当好。

第七步:模型准确性
我们可以检查几个指标,看看我们的模型表现如何。其中之一是 R 的平方。
我们可以看到,我们的 R 平方显示出几乎 90%的精度,这很好。我们将在未来的项目中探索均方误差和平均绝对误差。
R square = 0.9052889824534557
Mean squared Error = 97.87152220196164
Mean absolute Error = 7.955916525326746 R square = 0.9052889824534557
Mean squared Error = 97.87152220196164
Mean absolute Error = 7.955916525326746
第八步:预测我的体重
让我们看看这个模型在预测我的体重方面做得有多好。我身高 6 英尺 2 英寸,也就是 74 英寸。
My predicted weight = [197.2481918]
我只能说这不准确:)—也许我只是一个离群值—离群值是我们改天再讨论的另一个话题。
我很享受这个项目的建设。寻找我接下来要解决的下一个具有挑战性的项目。
源代码可以在这里找到。
机器学习项目规划
建立机器学习模型之前需要考虑的 10 个问题

Photo by Austin Distel on Unsplash
在建立任何机器学习模型之前,认真坐下来计划你希望你的模型完成什么是很重要的。在深入研究编写代码之前,了解要解决的问题、数据集的性质、要构建的模型的类型以及如何训练、测试和评估模型是非常重要的。
本文将讨论在建立机器学习模型之前需要考虑的 10 个重要问题。
(1)什么是预测变量?
在学术培训项目中,我们经常使用非常简单的数据集,要解决的问题是明确定义的。例如,一个家庭作业问题可以为您提供一些干净的数据集,它可能会要求您使用某些要素集作为预测要素,并使用一个要素作为目标。问题可以更进一步,告诉你建立什么样的模型。在现实生活的数据科学任务中,你不知道预测变量是什么。根据您工作的组织,您可能需要与工程师(工业数据集)、医生(医疗数据集)等团队合作,以便找出目标变量是什么。例如,一个工业系统可能有实时生成数据的传感器,在这种情况下,作为一名数据科学家,您可能不具备有关该系统的技术知识。因此,你必须与工程师和技术人员合作,让他们指导你决定什么是感兴趣的特征,什么是预测变量和目标变量。根据问题的类型和复杂程度,数据集中可能有数百或数千个要素。所以你必须决定哪些对于模型的建立是重要的。
②什么是目标变量?我的目标变量是离散的还是连续的?
您的目标变量是您的模型将要被训练来预测的特征。目标变量可以是连续的(例如,基于诸如房间数量、年龄、平方英尺、邮政编码、学区数量、雇主数量等特征来预测城市中的房价)。)或离散(基于花瓣长度、花瓣宽度、萼片长度、萼片宽度等特征预测鸢尾种类——鸢尾、海滨鸢尾和杂色鸢尾)。同样,在真正的工业数据科学项目中,确定目标变量需要数据科学家与其他可能具有领域专业知识的专业人员合作。例如,问题可能是设计一个机器学习模型来预测装配线上的一个重要设备何时可以关闭。在这种情况下,器件有两种离散状态,即开和关状态。该设备可以具有几个传感器,这些传感器实时生成数据,例如温度数据、气压数据、湿度数据等。在这种情况下,数据科学家必须与工程师合作,以确定应该使用哪些特征来训练模型。
(3)我应该使用聚类、分类、回归分析还是时间序列分析?
如果你的目标变量是连续的,那么回归分析是合适的模型。如果你的目标变量是离散的,那么你必须建立一个分类模型。在无监督学习的情况下,没有目标变量。在这种情况下,您可以使用聚类分析算法来训练您的模型。
如果你的问题涉及到预测一个与时间相关的变量,那么你可以考虑使用时间序列分析。
(4)如何处理数据集中缺失的值?
通常,移除样本或删除整个特征列是不可行的,因为我们可能会丢失太多有价值的数据。在这种情况下,我们可以使用不同的插值技术来估计数据集中其他训练样本的缺失值。最常见的插值技术之一是均值插补,我们只需用整个特征列的平均值替换缺失值。输入缺失值的其他选项有中值或最频繁(模式),后者用最频繁的值替换缺失值。这对于输入分类特征值很有用。另一种可以使用的插补技术是中位数插补。
(5)把变量放到同一个尺度上,应该用归一化还是标准化?
在构建模型之前,将变量调整到相同的比例非常重要。例如,假设我们想要建立一个模型来预测信用价值,如下所示:
信用度=A + B(收入)+ C(信用分)
在这个例子中,收入的范围例如可以从$30,000 到$200,000,而信用评分的范围通常从 0 到 800。建立一个模型而不缩放你的变量会产生一个偏向收入的模型。
有两种常见的方法将不同的功能放在同一个范围内:规范化和标准化。这些术语在不同的领域中经常被不严格地使用,其含义必须从上下文中推导出来。最常见的是,归一化指的是将特征重新缩放到范围[0,1],这是最小-最大缩放的一种特殊情况。
使用标准化,我们将特征列置于均值(μ)和标准差(sigma)的中心,使特征列呈现正态分布的形式,这样更容易学习权重。此外,标准化保留了关于异常值的有用信息,并使算法对它们不太敏感。
(6)我应该降低特征空间的维数吗?
复杂的数据集可能包含成百上千个要素。在包含如此多要素的数据集上训练模型可能会非常复杂,尤其是在要素高度相关的情况下。在这种情况下,降低系统的维数是值得的。这可以使用协方差矩阵图来完成( 使用协方差矩阵 Plo t 进行特征选择和维度缩减)。先进的降维方法包括 PCA、LDA 或 LASSO。
(7)如何调整模型中的超参数?
机器学习模型不是放之四海而皆准的模型。一个模型有那么多超参数( )模型参数和机器学习中的超参数——有什么区别? )。必须针对不同的超参数来训练模型,以便获得具有最佳质量的模型。
(8)我如何评估我的模型来检测数据集中的偏差?
用于模型评估的一些常见度量是均方误差(MSE)、平均误差(me)、平均绝对误差(MAE)、r 平方值(R2 分数)、准确度(对于分类问题)、混淆矩阵、阳性预测值(PPV)、ROC 下面积(AUC)分数等。
(9)我是否应该使用集成方法,即使用不同的模型进行训练,然后进行集成平均,例如使用 SVM、KNN、逻辑回归等分类器,然后在 3 个模型上进行平均?
例如,如果我们想要建立一个模型来确定一个客户是否有信用,那么我们可以使用不同的分类器,如逻辑回归、KNN、SVM、决策树等。,然后通过计算每个分类器的 R2 分数来评估我们的模型。我们可以选择具有最佳性能的分类器,或者计算不同分类器之间的平均 R2 分数。
(10)我如何选择最终型号?
为了选择最终的模型,我们可以选择泛化误差最小的方法,即当模型用于未知(或测试)数据时具有最佳性能的模型。
总之,在建立任何机器学习模型之前,认真坐下来计划你的项目目标和目的是什么是很重要的。这样,你将确保你的模型完成后,将是最好的模型,尽你所能。
机器学习项目:用回归预测波士顿房价

Picture from Unsplash
简介
在这个项目中,我们将开发和评估一个模型的性能和预测能力,该模型根据从波士顿郊区的房屋收集的数据进行训练和测试。
一旦我们得到一个很好的拟合,我们将使用这个模型来预测位于波士顿地区的房子的货币价值。
像这样的模型对于真正的国家代理人来说是非常有价值的,他们可以利用日常提供的信息。
你可以在我的 GitHub 页面上找到完整的项目、文档和数据集:
获取数据和前期预处理
本项目中使用的数据集来自 UCI 机器学习知识库。这些数据是在 1978 年收集的,506 个条目中的每一个都代表了波士顿各郊区房屋的 14 个特征的综合信息。
这些特征可以概括如下:
- CRIM:这是每个城镇的人均犯罪率
- ZN:这是面积大于 25,000 平方英尺的住宅用地的比例
- 印度河:这是每个城镇非零售商业英亩数的比例。
- CHAS:这是查尔斯河虚拟变量(如果区域边界为河流,则等于 1;否则为 0)
- 氮氧化物:这是氮氧化物的浓度(百万分之一)
- RM:这是每个住宅的平均房间数
- 年龄:这是 1940 年以前建造的自有住房的比例
- DIS:这是到五个波士顿就业中心的加权距离
- 拉德:这是放射状公路的可达性指数
- 税收:这是每 1 万美元的全价值财产税税率
- PTRATIO:这是各城镇的师生比率
- b:这是按 1000(Bk — 0.63)计算的,其中 Bk 是各城镇非裔美国人的比例
- LSTAT:这是人口中地位较低的百分比
- MEDV:这是以千美元为单位的自有住房的中值
这是原始数据集及其原始特征的概述:

出于项目的目的,数据集已经过如下预处理:
- 该项目的基本特征是:“RM”、“LSTAT”、“PTRATIO”和“MEDV”。其余特征已被排除。
- “MEDV”值为 50.0 的 16 个数据点已被删除。因为它们可能包含被审查或丢失的值。
- 1 个“RM”值为 8.78 的数据点,它被视为异常值,为了模型的最佳性能,已将其删除。
- 由于该数据已经过时,“MEDV”值已被放大,以解释 35 年的市场通胀。
我们现在将打开一个 python 3 Jupyter 笔记本,并执行以下代码片段来加载数据集并删除不重要的特性。如果正确执行了操作,将收到一条成功消息。
因为我们的目标是开发一个能够预测房屋价值的模型,所以我们将数据集分为要素和目标变量。并将它们分别存储在功能和价格变量中
- 特征“RM”、“LSTAT”和“PTRATIO”为我们提供了每个数据点的定量信息。我们将它们存储在特性中。
- 目标变量“MEDV”将是我们试图预测的变量。我们将把它储存在价格中。
***# Import libraries necessary for this project***
import numpy as np
import pandas as pd
from sklearn.model_selection import ShuffleSplit
***# Import supplementary visualizations code visuals.py***
import visuals as vs
***# Pretty display for notebooks***
%matplotlib inline
***# Load the Boston housing dataset***
data = pd.read_csv('housing.csv')
prices = data['MEDV']
features = data.drop('MEDV', axis = 1)
***# Success***
print("Boston housing dataset has **{}** data points with **{}** variables each.".format(*data.shape))

数据探索
在项目的第一部分,我们将对数据集进行探索性分析,并提供一些观察结果。
计算统计数据
***# Minimum price of the data***
minimum_price = np.amin(prices)
***# Maximum price of the data***
maximum_price = np.amax(prices)
***# Mean price of the data***
mean_price = np.mean(prices)
***# Median price of the data***
median_price = np.median(prices)
***# Standard deviation of prices of the data***
std_price = np.std(prices)
***# Show the calculated statistics***
print("Statistics for Boston housing dataset:**\n**")
print("Minimum price: $**{}**".format(minimum_price))
print("Maximum price: $**{}**".format(maximum_price))
print("Mean price: $**{}**".format(mean_price))
print("Median price $**{}**".format(median_price))
print("Standard deviation of prices: $**{}**".format(std_price))

特征观察
数据科学是对数据做出一些假设和假说,并通过执行一些任务来检验它们的过程。最初,我们可以对每个特性做出以下直观假设:
- 房间越多(RM 值越高)的房子价值越高。通常房间多的房子更大,能容纳更多的人,所以花更多的钱是合理的。它们是成正比的变量。
- 低阶层工人较多的街区(LSTAT 值较高)价值较低。如果较低的工人阶级的比例较高,很可能他们有较低的购买力,因此,他们的房子会更便宜。它们是成反比的变量。
- 学生与教师比率较高(PTRATIO 值较高)的街区价值较低。如果学生与教师的比例更高,很可能附近的学校更少,这可能是因为税收收入更少,这可能是因为附近的人挣钱更少。如果人们挣的钱少了,他们的房子很可能会贬值。它们是成反比的变量。
我们将通过这个项目来验证这些假设是否正确。
探索性数据分析
散点图和直方图
我们将从创建散点图矩阵开始,这将允许我们可视化不同特征之间的成对关系和相关性。
快速浏览一下数据是如何分布的以及它是否包含异常值也是非常有用的。
import matplotlib.pyplot as plt
import seaborn as sns%matplotlib inline***# Calculate and show pairplot***
sns.pairplot(data, size=2.5)
plt.tight_layout()

我们可以发现“RM”和房价“MEDV”之间的线性关系。此外,我们可以从直方图中推断出“MEDV”变量似乎呈正态分布,但包含几个异常值。
相关矩阵
我们现在将创建一个关联矩阵,以量化和总结变量之间的关系。
此相关矩阵与协方差矩阵密切相关,事实上,它是协方差矩阵的重新缩放版本,通过标准化要素计算得出。
它是一个包含人的 r 相关系数的方阵(列数和行数相同)。
***# Calculate and show correlation matrix***
cm = np.corrcoef(data.values.T)
sns.set(font_scale=1.5)
hm = sns.heatmap(cm,
cbar=True,
annot=True,
square=True,
fmt='.2f',
annot_kws={'size': 15},
yticklabels=cols,
xticklabels=cols)

为了拟合回归模型,感兴趣的特征是与目标变量“MEDV”高度相关的特征。从前面的相关矩阵中,我们可以看到,对于我们选择的变量,这个条件是实现的。
开发模型
在项目的第二部分,我们将开发模型进行预测所需的工具和技术。通过使用这些工具和技术,能够对每个模型的性能做出准确的评估,有助于大大增强预测的可信度。
定义性能指标
如果不量化一个给定模型在训练和测试中的表现,就很难衡量它的质量。这通常是使用某种类型的性能度量来完成的,无论是通过计算某种类型的误差、拟合优度,还是其他一些有用的度量。
对于本项目,我们将计算决定系数,R,以量化模型的性能。模型的决定系数在回归分析中是一个有用的统计数据,因为它通常描述了该模型在进行预测方面有多“好”。
R 的值范围从 0 到 1,它捕获目标变量的预测值和实际值之间的平方相关的百分比。
- R 为 0 的模型并不比总是预测目标变量的均值的模型更好。
- 而 R 为 1 的模型完美地预测了目标变量。
- 0 到 1 之间的任何值表示使用该模型,目标变量的百分比可以由特征来解释。
也可以给模型一个负 R2,这表明该模型比总是预测目标变量均值的模型更差。
***# Import 'r2_score'***
from sklearn.metrics import r2_score
def performance_metric(y_true, y_predict):
***"""*** *Calculates and returns the performance score between*
*true (y_true) and predicted (y_predict) values based on the metric chosen.* ***"""***
score = r2_score(y_true, y_predict)
***# Return the score***
return score
混洗和分割数据
在本节中,我们将采用波士顿住房数据集,并将数据分成训练和测试子集。通常,在创建训练和测试子集时,还会将数据打乱成随机顺序,以消除数据集排序中的任何偏差。
***# Import 'train_test_split'***
from sklearn.model_selection import train_test_split
***# Shuffle and split the data into training and testing subsets***
X_train, X_test, y_train, y_test = train_test_split(features, prices, test_size=0.2, random_state = 42)
***# Success***
print("Training and testing split was successful.")

培训和测试
你现在可能会问:
对于学习算法来说,将数据集分割成一定比例的训练和测试子集有什么好处?
一旦我们的模型经过训练,对它进行评估是很有用的。我们想知道它是否从数据的训练分割中正确地学习了。可能有 3 种不同的情况:
1)模型没有很好地学习数据,甚至不能预测训练集的结果,这被称为欠拟合,这是由于高偏差引起的。
2)模型对训练数据学习得太好,以至于它已经记住了它,而不能对新数据进行推广,这称为过拟合,这是由于高方差造成的。
3)该模型刚好在偏差和方差之间具有正确的平衡,它学习得很好,并且能够正确预测新数据的结果。
分析模型性能
在这个项目的第三部分,我们将看看几个模型在各种训练数据子集上的学习和测试性能。
此外,我们将在完整的训练集上研究一个具有递增的'max_depth'参数的特定算法,以观察模型复杂性如何影响性能。
根据不同的标准绘制模型的性能在分析过程中可能是有益的,例如可视化仅从结果中可能不明显的行为。
学习曲线
下面的代码单元为具有不同最大深度的决策树模型生成了四个图形。随着训练集大小的增加,每个图都可视化了训练和测试模型的学习曲线。
请注意,学习曲线的阴影区域表示该曲线的不确定性(以标准差衡量)。使用 R2(决定系数)对训练集和测试集的模型进行评分。
***# Produce learning curves for varying training set sizes and maximum depths***
vs.ModelLearning(features, prices)

学习数据
如果我们仔细观察最大深度为 3:
- 随着训练点数的增加,训练分数降低。相反,考试分数会增加。
- 由于两个分数(训练和测试)趋于收敛,从 300 点阈值开始,具有更多的训练点将不会有益于模型。
- 一般来说,每个观察值的列越多,我们将获得更多的信息,模型将能够更好地从数据集中学习,从而做出更好的预测。
复杂性曲线
下面的代码单元格为决策树模型生成一个图表,该模型已使用不同的最大深度对定型数据进行了定型和验证。该图产生了两条复杂性曲线——一条用于训练,一条用于验证。
与学习曲线类似,两条复杂性曲线的阴影区域表示这些曲线中的不确定性,并且使用performance_metric函数在训练集和验证集上对模型进行评分。
*# Produce complexity curve for varying training set sizes and maximum depths*
vs.ModelComplexity(X_train, y_train)

偏差-方差权衡
如果我们分析偏差方差如何随最大深度变化,我们可以推断:
- 在最大深度为 1 的情况下,图形显示模型在训练和测试数据中都没有返回好的分数,这是拟合不足的症状,因此偏差较大。为了提高性能,我们应该增加模型的复杂性,在这种情况下,增加 max_depth 超参数以获得更好的结果。
- 在最大深度为 10 的情况下,该图显示模型从训练数据(得分接近 1)中学习得非常好,并且在测试数据上返回的结果也很差,这是过度拟合的指示,不能对新数据进行很好的概括。这是一个方差很大的问题。为了提高性能,我们应该降低模型的复杂性,在这种情况下,降低 max_depth 超参数以获得更好的结果。
最佳猜测最优模型
从复杂度曲线中,我们可以推断出模型的最佳最大深度是 4,因为它是产生最佳验证分数的深度。
此外,对于更深的深度,虽然训练分数增加,但验证分数倾向于降低,这是过度拟合的迹象。
评估模型的性能
在项目的最后一部分,我们将构建一个模型,并使用fit_model中的优化模型对客户的功能集进行预测。
网格搜索
网格搜索技术从由 param_grid 参数指定的参数值网格中详尽地生成候选项,param _ grid 参数是具有要评估的超参数值的字典。一个例子可以是:
param_grid = [ {‘C’: [1, 10, 100, 1000], ‘kernel’: [‘linear’]}, {‘C’: [1, 10, 100, 1000], ‘gamma’: [0.001, 0.0001], ‘kernel’: [‘rbf’]}, ]
在本例中,应研究两个网格:一个网格具有线性核,C 值为[1,10,100,1000],第二个网格具有 RBF 核,C 值的叉积范围为[1,10,100,1000],gamma 值为[0.001,0.0001]。
在数据集上拟合时,会评估参数值的所有可能组合,并保留最佳组合。
交叉验证
K-fold 交叉验证是一种技术,用于确保我们的模型得到良好的训练,而不使用测试集。它包括将数据分成 k 个大小相等分区。对于每个分区 I,我们在剩余的 k-1 个参数上训练模型,并在分区 I 上对其进行评估。最终得分是所获得的 K 个得分的平均值。
在评估估计量的不同超参数时,仍然存在过度拟合测试集的风险,因为可以调整参数,直到估计量达到最优。这样,关于测试集的知识可以“泄漏”到模型中,并且评估度量不再报告泛化性能。
为了解决这个问题,数据集的另一部分可以被称为“验证集”:在训练集上进行训练,然后在验证集上进行评估,当实验似乎成功时,可以在测试集上进行最终评估。
然而,通过将可用数据划分为三个集合(训练、验证和测试集合),我们大大减少了可用于学习模型的样本数量,并且得到的模型可能没有得到足够好的训练(欠拟合)。
通过使用 k-fold 验证,我们确保模型使用所有可用于调整模型的训练数据,这可能在计算上是昂贵的,但是允许训练模型,即使只有很少的数据可用。
k-fold 验证的主要目的是获得对新数据的模型泛化的无偏估计。
拟合模型
最终的实现要求我们将所有的东西放在一起,并使用决策树算法训练一个模型。
为了确保我们正在生成一个优化的模型,我们将使用网格搜索技术来训练该模型,以优化决策树的'max_depth'参数。'max_depth'参数可以被认为是决策树算法在进行预测之前可以对数据提出多少个问题。
此外,我们会发现您的实现使用了ShuffleSplit()作为交叉验证的替代形式(参见'cv_sets'变量)。下面的ShuffleSplit()实现将创建 10 个('n_splits')混洗集,对于每个混洗,20% ( 'test_size')的数据将被用作验证集。
***# Import 'make_scorer', 'DecisionTreeRegressor', and 'GridSearchCV'***
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import make_scorer
from sklearn.model_selection import GridSearchCV
def fit_model(X, y):
** *""" Performs grid search over the 'max_depth' parameter for a*
*decision tree regressor trained on the input data [X, y]. """***
***# Create cross-validation sets from the training data***
cv_sets = ShuffleSplit(n_splits = 10, test_size = 0.20, random_state = 0)
***# Create a decision tree regressor object***
regressor = DecisionTreeRegressor()
***# Create a dictionary for the parameter 'max_depth' with a range from 1 to 10***
params = {'max_depth':[1,2,3,4,5,6,7,8,9,10]}
***# Transform 'performance_metric' into a scoring function using 'make_scorer'***
scoring_fnc = make_scorer(performance_metric)
***# Create the grid search cv object --> GridSearchCV()***
grid = GridSearchCV(estimator=regressor, param_grid=params, scoring=scoring_fnc, cv=cv_sets)
***# Fit the grid search object to the data to compute the optimal model***
grid = grid.fit(X, y)
***# Return the optimal model after fitting the data***
return grid.best_estimator_
做出预测
一旦一个模型已经在一组给定的数据上被训练,它现在可以被用来在新的输入数据组上进行预测。
在决策树回归器的情况下,模型已经学习了关于输入数据的最佳问题是什么,并且可以用目标变量的预测来响应。
我们可以使用这些预测来获取有关目标变量值未知的数据的信息,例如模型未被训练的数据。
最优模型
以下代码片段查找返回最佳模型的最大深度。
***# Fit the training data to the model using grid search***
reg = fit_model(X_train, y_train)
***# Produce the value for 'max_depth'***
print("Parameter 'max_depth' is **{}** for the optimal model.".format(reg.get_params()['max_depth']))

预测销售价格
想象一下,我们是波士顿地区的一家房地产代理商,希望使用这种模型来帮助我们的客户对他们想要出售的房屋进行定价。我们从三个客户那里收集了以下信息:

- 我们会建议每个客户以什么价格出售他/她的房子?
- 考虑到各个功能的价值,这些价格是否合理?
为了找到这些问题的答案,我们将执行下面的代码片段并讨论其输出。
***# Produce a matrix for client data***
client_data = [[5, 17, 15], *# Client 1*
[4, 32, 22], *# Client 2*
[8, 3, 12]] *# Client 3*
***# Show predictions***
for i, price in enumerate(reg.predict(client_data)):
print("Predicted selling price for Client {}'s home: ${:,.2f}".format(i+1, price))

从项目开始时进行的统计计算中,我们发现了以下信息:
- 最低价格:105000 美元
- 最高价格:1024800 美元
- 平均价格:454342.944 美元
- 中间价 438900 美元
- 价格标准差:165340.277 美元
根据这些值,我们可以得出结论:
- 客户端 3 的销售价格接近百万美元,接近数据集的最大值。这是一个合理的价格,因为它的特点(8 个房间,非常低的贫困水平和低师生比),房子可能在一个富裕的街区。
- 客户端 2 的销售价格是三个中最低的,鉴于其特性是合理的,因为它接近数据集的最小值。
- 对于客户端 1,我们可以看到它的功能介于后两者之间,因此,它的价格非常接近平均值和中间值。
我们最初对这些特征的假设得到了证实:
- RM '与因变量'价格'成正比关系。
- 相比之下,“LSTAT”和“PTRATIO”与因变量“PRICES”成反比关系。
模型的灵敏度
最优模型不一定是稳健模型。有时,模型要么太复杂,要么太简单,不足以概括新数据。
有时,模型可能使用不适合给定数据结构的学习算法。
其他时候,数据本身可能噪声太大或包含的样本太少,以至于模型无法充分捕捉目标变量,即模型欠拟合。
下面的代码单元格使用不同的训练集和测试集运行fit_model函数十次,以查看特定客户端的预测相对于其训练的数据如何变化。
vs.PredictTrials(features, prices, fit_model, client_data)

我们得到的价格范围接近 70,000 美元,这是一个相当大的偏差,因为它代表了房价中值的大约 17%。
模型的适用性
现在,我们使用这些结果来讨论构建的模型是否应该或不应该在现实世界中使用。一些值得回答的问题是:
- 从 1978 年开始收集的数据与今天的相关性如何?通货膨胀有多重要?
1978 年收集的数据在当今世界没有多大价值。社会和经济变化很大,通货膨胀对价格有很大影响。
- 数据中的特征是否足以描述一个家庭?你认为像家中设备的质量、建筑面积的平方英尺、是否有游泳池等因素应该考虑进去吗?
考虑的数据集非常有限,有许多特征,如房屋的平方英尺大小,是否有游泳池,以及其他与考虑房价非常相关的特征。
- 模型是否足够稳健,能够做出一致的预测?
考虑到 prince 范围的高方差,我们可以保证它不是一个稳健的模型,因此不适合进行预测。
- 在波士顿这样的城市收集的数据适用于农村吗?
从像波士顿这样的大城市收集的数据不适用于农村城市,因为同等价值的房产价格在城市地区要高得多。
- 根据整个社区的特点来判断个人住房的价格公平吗?
总的来说,根据整个社区的特点来估计或预测一个人的房价是不公平的。在同一个街区,价格可能会有巨大的差异。
结论
在整篇文章中,我们做了一个端到端的机器学习回归项目,我们学习并获得了关于回归模型及其开发方式的一些见解。
这是将在这个系列中开发的第一个机器学习项目。如果你喜欢,请继续关注下一篇文章!这将是关于分类算法的理论和概念的介绍。
如果你喜欢这篇文章,那么你可以看看我关于数据科学和机器学习的其他文章 这里 。
如果你想了解更多关于机器学习、数据科学和人工智能的知识 请关注我的 Medium ,敬请关注我的下一篇帖子!
机器学习房地产估价:不仅仅是数据事件

机器学习(ML)为房地产估价带来了巨大的希望。但相关、高质量和及时的房地产数据仍然是一项昂贵的投入。在没有其他资产可用的海量数据的情况下,模型和数据的平衡组合仍是未来几年房地产估值最有可能的途径。这篇文章只是触及了这个问题的表面。
房地产价格是在房产转手时观察到的。典型交易的高成本和巨大的平均交易量(例如与股票市场相比),导致对同一资产的观察很少。在交易期间,房地产专业人士和投资者需要依赖估价——如果房产被拍卖,市场上最有可能获得的价格。这是一个假设的价值,而不是实际的注册价格。
估价相对简单,但仍涉及在接近估价日时市场上交易的享乐变量i方面的类似资产。在缺乏可靠的可比交易的情况下,需要使用估价方法来评估一块房地产(无论是住宅还是商业)的可能价值。从信封背面的上限利率模型、透明的贴现现金流电子表格到复杂的计量经济学模型,任何可靠的估值都会受益于对现金流和贴现率预期水平的准确预测。购买或出售决策进一步受到房地产周期当前状态的影响,但也受到周期预期方向的影响。
预测租金需要很好地理解空间市场中的供求力量、建筑及其融资方式、自然空置率的演变以及公司和工人可能的移民流动等更重要的决定因素。贴现因子的预测涉及对货币政策(作为短期利率的决定因素)和风险溢价期限结构的透彻理解。如果在投资组合环境中进行估价,可能还需要上述变量的未来相关性,以便评估出售或收购某个房地产行业风险敞口的多样化收益。
鉴于估值对贴现率变化的敏感性,有必要花几段时间来确定短期利率和贴现率的无风险部分。
深入货币政策的兔子洞,短期利率水平通常由央行使用泰勒规则的变体来控制。这适用于全球大多数以通胀为目标的央行。该规则是一个将短期利率与产出缺口(衡量观察到的产出离可持续的非通胀水平有多远)和通胀缺口(衡量观察到的通胀离假设目标有多远,通常设定为 2%)联系起来的公式。正缺口导致利率上升,负缺口导致利率下降。
取决于无数其他因素,短期曲线的变化将沿着整个收益率曲线传播,但并不总是以均匀的方式传播。因此,将上述内容扩展到利率期限结构模型,我们可以得出在未来交易日预期观察到的无风险利率。风险溢价在顶部,也是相当可变和周期性的,我们最终会得到未来不同时间点的贴现率。
这一短暂的曲折表明,房地产估值不仅需要大量数据,而且需要大量建模。一项资产所需的持有期越长,就越需要对上述变量进行预测。我们看得越远,估计就越模糊,因此估值就越不可靠。
房地产价格因其长期的周期性行为而臭名昭著,无论是在发达市场还是发展中市场。信贷也是如此。GDP、信贷和房地产之间的相互作用是房地产周期未来走向的宝贵信息来源。仅作为一个简短的激励因素,回想一下美国房地产繁荣和萧条的最近一幕,宽松的贷款标准和高贷款价值(LTV)比率是一些重要的繁荣触发器,而突然和全经济的信贷停止是萧条的催化剂。
周期持续时间和幅度随时间变化,在不同国家有不同的特点。房地产市场(来自当地建筑和分区立法)和信贷市场(放松管制和监管风险限额的变化)的结构性特征的变化,共同改变了房地产周期的统计特性。
这些变化是如何以及何时出现在房地产价格数据中的?这些变化会影响预测吗?房地产估价工作应该如何反映这些变化?这些问题可以在灵活的建模策略中得到解决,在这种策略中,超前-滞后结构的相关性和变量的选择最好留给机器学习算法的辛勤工作。
在这种背景下,并借助于“scar Jordà”、Moritz Schularick 和 Alan M. Taylor 在他们的“宏观金融历史和新商业周期事实”中发布的数据(可在http://www.macrohistory.net/data/获得)我分析了几个发达经济体超过 100 年的 GDP、房地产价格和信贷的时变趋势和周期行为。目标是确定和估计本地与全球周期的相关性,以及其他经济体的金融和实际周期的溢出效应。
如果全球低频成分在所分析的市场中起作用,该统计信息有助于改进估价中采用的预测。尽管房地产市场仍然主要是地方事务,但全球化的贸易和资金流动可以导致从一个房地产市场到另一个房地产市场的溢出效应。将变量分解为趋势和周期成分也有助于评估央行从现在起 3 到 5 年内可能采取的行动,从而提供对未来短期利率的估计。这是因为在典型的泰勒规则中,估计的周期性成分是作为输入所需的缺口。
我们先来看看数据。我计算了住宅房地产价格、人均 GDP 和非金融企业信贷增长率的 10 年移动平均值。数据中存在一些间断,通常在二战期间观察到,但在其他方面数据表现良好。使用 10 年平均值的信贷和房价的同步性非常突出(图 1)。这加强了先前的研究,表明信贷在解释房价动态的重要性。

Figure 1: The GDP-Credit-Property Prices Trio across Time and Countries
人们自然会怀疑 10 年平均值是否是分析这三个变量的相关数据跨度。这里可以使用 ML 来搜索最小化预测误差的最佳窗口大小,因为在预测模型中使用了估计的间隙。这可能会随着时间(在某些时期,10 年的平均数可能是最好的选择,在另一些时期,它可能是 7 年的平均数)、变量和国家而变化。
10 年的平均值可以被认为是对潜在趋势的一个天真的估计。这是数据的低频成分。然后通过从所有时间点的观察值中减去趋势值来获得循环分量。最近一段时间显示,趋势的同步性增加,为观察到的大多数国际市场房地产价格的高相关性提供了一些额外的解释。
此外,通过估算 10 年平均水平的黄土曲线,可以了解各国的联合动态(图 2)。这是一个简单的应用程序,旨在揭示房地产、GDP 和信贷增长中的全球因素。粉色带显示了美国的衰退期。
一个有趣的经验观察是信贷增长和产出之间的时变关系,以及它如何随时间发生质的变化。
在考虑的大部分时间里,高信贷增长率导致更高的产出和房价增长率——回想一下我们谈论的增长率趋势。这三个变量在 20 世纪 20 年代、50 年代和 80 年代同时达到峰值。然而,2007 年的峰值并非如此,当时信贷的高增长导致了房地产价格的高增长,但对趋势 GDP 的反应却很温和。这一观察结果表明,长期停滞可能无法完全解释危机后的疲软增长。

Figure 2: Averages in trends across countries
更具结构性的解释是可能的,例如在立陶宛银行的 Anh D.M. Nguyen 最近的一篇论文中。在本文中,我们建立了一个多变量未观测成分模型来解释一个多世纪以来美国经济产出缺口的演变。该文件的工作版本可在 https://www . lb . lt/en/publications/no-51-mih nea-Constantine scu-Anh-d-m-Nguyen-a-century-of-gap 查阅。
在罗马尼亚银行(http://www . bnr . ro/Bucharest-Economic-Analysis-and-Research-Seminar-(BEARS)-16413 . aspx)和乌克兰银行(https://bank.gov.ua/control/en/publish/article?)最近举行的几个研究研讨会上介绍并讨论了初步结果 art _ id = 87169943&cat _ id = 76291)以及几场学术会议。
在跨国环境中,ML 为选择用于计算全球平均值的最佳权重提供了一个自然的选择。经济理论表明,贸易或国内生产总值可用于构建平均计算中所需的相关权重(例如,在使用国内生产总值进行加权时,较大的经济体在计算中的权重较高)。尽管在经济上更容易解释,但从预测的角度来看,这种方法可能不是最佳的。选择系数的时变矩阵改善了预测练习的结果。自然,对于每个市场,可以使用特定国家的个人交易数据来进一步细化估计。
快速数据/建模/洞察迂回强调,数据虽然是一个重要的输入,但需要一个解释镜头。这是由模型和先前的概念框架提供的,它们分别适合于所选的问题,在我们的例子中是房地产估价。
我们很可能从一个精心选择的将 NVR 与均衡租金联系起来的模型中获得与我们从一大串松散联系的协变量的主成分分析中获得的相同的计量经济学洞见。更好的策略显然是从所有可用的协变量中提取任何有用的信息。毫无疑问,因果可解释性优于黑盒方法。数据洞察需要成为可操作的业务决策,这些决策可以轻松交流和理解,而不是用晦涩的统计术语包装。虽然有时模糊,经济学 101 仍然是一个重要的来源,因果解释和变量选择的模型建立和估计。
人工智能浪潮带来了独特的商业和伦理挑战,房地产也无法幸免。更重要的是,这表明高纯度及时数据发挥了越来越大的作用。区块链存储的交易数据成为一种有价值的生产要素,在人工智能驱动的经济中具有越来越重要的价值。因此,未来的商业模式应该设计新产品和服务,而不是模糊这种投入的价值,以避免对用户的数据贡献进行补偿,而是正式承认其价值,并组织进行交易所需的适当市场。
LSTM 递归神经网络实例

递归神经网络具有广泛的应用。这些包括时间序列分析、文档分类、语音和声音识别。与前馈人工神经网络相反,递归神经网络做出的预测依赖于先前的预测。
具体来说,想象我们决定遵循一个锻炼程序,每天在举重、游泳和瑜伽之间交替进行。然后,我们可以建立一个递归神经网络来预测今天的锻炼,因为我们昨天做了什么。例如,如果我们昨天举重,那么我们今天就去游泳。
通常情况下,你将在现实世界中处理的问题是当前状态和其他输入的函数。例如,假设我们每周注册一次曲棍球。如果我们在应该举重的同一天打曲棍球,那么我们可能会决定不去健身房。因此,我们的模型现在必须区分昨天上瑜伽课但我们没有打曲棍球的情况,以及昨天上瑜伽课但我们今天打曲棍球的情况,在这种情况下我们会直接跳到游泳。
长短期记忆(LSTM)
在实践中,我们很少看到使用常规的递归神经网络。递归神经网络有一些缺点,使它们不实用。例如,假设我们增加了一个休息日。休息日只应在运动两天后休。如果我们使用递归神经网络来尝试和预测我们明天将做什么活动,它可能会陷入循环。
假设我们有以下场景。
- 第一天:举重
- 第二天:游泳
- 第三天:在这一点上,我们的模型必须决定我们是否应该休息一天或瑜伽。不幸的是,它只能访问前一天。换句话说,它知道我们昨天游泳了,但不知道我们前一天是否休息过。所以,最后可以预测瑜伽。
发明 LSTMs 是为了解决这个问题。顾名思义,LSTMs 是有记忆的。就像人类可以在短期记忆中存储大约 7 位信息一样,LSTMs 理论上可以记住几个状态的信息。然而,这提出了一个问题,即他们应该记得多久以前的事情。什么时候信息变得无关紧要了?例如,在我们的练习例子中,我们不应该需要回溯两天以上来决定我们是否应该休息一下。
LSTMs 没有深入研究太多细节,而是通过使用专用神经网络来遗忘和选择信息来解决这个问题。单个 LTSM 层由以特殊方式交互的四个神经网络层组成。

如果你有兴趣了解更多关于 LSTM 网络的内部情况,我强烈建议你去看看下面的链接。
[## 了解 LSTM 网络——colah 的博客
这些循环使得循环神经网络看起来有点神秘。然而,如果你想得更多一点,事实证明…
colah.github.io](https://colah.github.io/posts/2015-08-Understanding-LSTMs/)
关于自然语言处理的一个棘手的事情是,单词的含义会根据上下文而变化。在情感分析的情况下,我们不能仅仅关闭一些单词的出现,比如,因为如果前面是 而不是 就像 不好一样,它的意思完全改变了。计算机也很难识别讽刺之类的东西,因为它们需要从字里行间去解读。事实证明,LSTM 网络特别适合解决这类问题,因为它们能记住与问题相关的所有单词。
密码
在接下来的部分中,我们回顾了我对 Kaggle 竞赛的解决方案,该竞赛的目标是对电影评论集进行情感分析。我们被要求在 0 到 4 的范围内给每个短语贴上标签。对应于每个标签的情感是:
- 0:负
- 1:有些消极
- 2:中性
- 3:有点积极
- 4:积极
如果您想继续学习,可以从下面的链接获得数据集。
从烂番茄数据集中对句子的情感进行分类
www.kaggle.com](https://www.kaggle.com/c/movie-review-sentiment-analysis-kernels-only)
我们将使用以下库。
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
plt.style.use('dark_background')
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from sklearn.model_selection import train_test_split
from keras.utils import to_categorical
from keras.models import Sequential
from keras.layers import Dense, Dropout, Embedding, LSTM, GlobalMaxPooling1D, SpatialDropout1D
语料库包含超过 150,000 个训练样本。如你所见,有些短语不完整,有些重复。
df_train = pd.read_csv('train.tsv', sep='\t')print('train set: {0}'.format(df_train.shape))
df_train.head(10)

测试集包括超过 60,000 个样本。每一行都有一个PhraseId和一个SentenceId,Kaggle 将使用这两个值来评估提交文件中模型所做的预测。
df_test = pd.read_csv('test.tsv', sep='\t')print('test set: {0}'.format(df_test.shape))
df_test.head(10)

ASCII 字符最终被计算机解释为十六进制。因此,对计算机来说,“A”和“A”是不同的。因此,我们想把所有的字符都变成小写。因为我们要根据空格把句子分割成单个的单词,所以后面有句号的单词不等同于后面没有句号的单词( happy)。!= 开心 )。此外,收缩将被解释为不同于原来的,这将对模型产生影响(我!=我就是)。因此,我们使用 proceeding 函数替换所有事件。
replace_list = {r"i'm": 'i am',
r"'re": ' are',
r"let’s": 'let us',
r"'s": ' is',
r"'ve": ' have',
r"can't": 'can not',
r"cannot": 'can not',
r"shan’t": 'shall not',
r"n't": ' not',
r"'d": ' would',
r"'ll": ' will',
r"'scuse": 'excuse',
',': ' ,',
'.': ' .',
'!': ' !',
'?': ' ?',
'\s+': ' '}def clean_text(text):
text = text.lower()
for s in replace_list:
text = text.replace(s, replace_list[s])
text = ' '.join(text.split())
return text
我们可以使用apply将函数应用到序列中的每一行。
X_train = df_train['Phrase'].apply(lambda p: clean_text(p))
让我们看看语料库中每个短语的单独长度。
phrase_len = X_train.apply(lambda p: len(p.split(' ')))
max_phrase_len = phrase_len.max()
print('max phrase len: {0}'.format(max_phrase_len))plt.figure(figsize = (10, 8))
plt.hist(phrase_len, alpha = 0.2, density = True)
plt.xlabel('phrase len')
plt.ylabel('probability')
plt.grid(alpha = 0.25)

神经网络的所有输入必须长度相同。因此,我们将最长的长度存储为一个变量,稍后我们将使用它来定义模型的输入。
接下来,我们为目标标签创建一个单独的数据帧。
y_train = df_train['Sentiment']
计算机不理解单词,更不用说句子了,因此,我们使用分词器来解析短语。在指定num_words时,只保留最常用的num_words-1字。我们使用过滤器来去除特殊字符。默认情况下,所有标点符号都被删除,将文本转换为空格分隔的单词序列。然后,这些记号被矢量化。我们所说的矢量化是指它们被映射到整数。0是一个保留索引,不会分配给任何单词。
pad_sequence用于确保所有短语长度相同。比maxlen短的序列在末尾用value(默认为0)填充。
每当我们处理分类数据时,我们都不想让它成为整数,因为模型会将数字越大的样本解释为更有意义。to_categorical是对数据进行编码的快速而肮脏的方式。
max_words = 8192tokenizer = Tokenizer(
num_words = max_words,
filters = '"#$%&()*+-/:;<=>@[\]^_`{|}~'
)tokenizer.fit_on_texts(X_train)X_train = tokenizer.texts_to_sequences(X_train)
X_train = pad_sequences(X_train, maxlen = max_phrase_len)
y_train = to_categorical(y_train)
我们为超参数定义变量。
batch_size = 512
epochs = 8
然后,我们建立我们的模型使用 LSTM 层。
model_lstm = Sequential()model_lstm.add(Embedding(input_dim = max_words, output_dim = 256, input_length = max_phrase_len))
model_lstm.add(SpatialDropout1D(0.3))
model_lstm.add(LSTM(256, dropout = 0.3, recurrent_dropout = 0.3))
model_lstm.add(Dense(256, activation = 'relu'))
model_lstm.add(Dropout(0.3))
model_lstm.add(Dense(5, activation = 'softmax'))model_lstm.compile(
loss='categorical_crossentropy',
optimizer='Adam',
metrics=['accuracy']
)
如果你不明白嵌入层在做什么,我建议你去看看我写的一篇关于这个主题的文章。
[## 机器学习情感分析和单词嵌入 Python Keras 示例
机器学习的主要应用之一是情感分析。情绪分析就是判断语气…
towardsdatascience.com](/machine-learning-sentiment-analysis-and-word-embeddings-python-keras-example-4dfb93c5a6cf)
我们使用辍学来防止过度拟合。
我们留出 10%的数据进行验证。在我们向解决方案迈出一步之前,每个时代都有 512 条评论通过网络。
history = model_lstm.fit(
X_train,
y_train,
validation_split = 0.1,
epochs = 8,
batch_size = 512
)

我们可以通过使用由 fit 函数返回的历史变量来绘制每个时期的训练和验证准确度和损失。
plt.clf()
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(loss) + 1)
plt.plot(epochs, loss, 'g', label='Training loss')
plt.plot(epochs, val_loss, 'y', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()

plt.clf()
acc = history.history['acc']
val_acc = history.history['val_acc']
plt.plot(epochs, acc, 'g', label='Training acc')
plt.plot(epochs, val_acc, 'y', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

由于数据集是作为 Kaggle 竞赛的一部分获得的,我们没有得到与测试集中的短语相对应的情感。
最后的想法
递归神经网络可用于建模任何依赖于其先前状态的现象。我们在本文中提到的例子是语义的例子。换句话说,一个句子的意思随着它的发展而变化。我们可以使用更复杂的方法来捕捉单词之间的相互作用(例如,电影不是好的),而不是试图基于某个单词(例如,好的)的出现来分类文档。*
正则化和过拟合

http://www.discovery.com/tv-shows/mythbusters/about-this-show/physics-of-seesaws/
注:帖子是我以后参考用的。请随意指出任何异常之处。
首先,我将讨论一些基本的想法,所以如果你认为你已经是有这些想法的家庭,请随意继续。
一个线性模型
线性模型是在预测模型中遵循直线的模型。它可以有单个属性来预测值,也可以有多个属性来预测值,方程看起来像这样。

(a)
这里θ-0 是截距,θ-1 到θ-n 是对应于它们的属性 X-1 到 X-n 的斜率。
成本函数
讲故事有两种方式,一种是艰难的方式,在这种方式中,你被期望达到说话者的标准,或者…
towardsdatascience.com](/machine-leaning-cost-function-and-gradient-descend-75821535b2ef)
成本函数决定了你预测的假设 h(x)和实际点之间有多少差异。因为我们首先考虑一个线性模型,让我们看看它在图上的样子。


一个只有两点,一个有很多点。但是,您认为线性模型或星光线可以表示如下所示的数据吗:

在这种数据集中,拟合直线的可能性非常多。因此,我们开始使用如下所示形式的多项式方程:

它开始形成一条曲线,与直线相比,可以更好地表示数据点。当我们只有一个θ时,这意味着我们只有一个方向的斜率,因此我们得到一条直线,但是,如果我们有许多θ,这意味着许多斜率,因此我们的直线可以以许多不同的方式改变方向。见下图。

https://www.originlab.com/index.aspx?go=Products/Origin/DataAnalysis/CurveFitting
- 我们希望我们的成本函数在直线的情况下最小,我们也希望它在多项式线的情况下最小。
- 我们使用梯度下降,通过不断更新方程中的所有θ来拟合可能的最佳直线。
我们为什么需要正规化?
回答 —防止模型过拟合。

欠拟合:我们看到,我们绘制的假设线并不真正遵循与点相同的趋势。这样,我们的模型就不能给出我们数据的精确描述。
解法:做一个多项式方程,它创建一条曲线而不是直线。
良好拟合:通过使用一个多项式方程,你增加了可以采取不同形状的线的复杂性,然而,如果你有一个变量,比如说“X”和预测“Y”,那么你只是创建了一条单线。
过度拟合:如果你知道通过使你的方程多项式化,你可以调整它以匹配你的数据点,但是,如果你调整假设的直线到试图通过每一个可能的数据点的程度,那么你说你的模型过度拟合。
为什么会产生问题?因为当你要预测未来的事情时,你的模型不能确定这条线将在哪里转弯,因为它没有概括整个模型,而是概括单个数据点。
解决:正规化
正规化
因为我们知道通过改变斜率我们可以改变直线的方向,我们知道我们的模型有太多的精度,所以你会建议从方程的末尾去掉高次项吗?号码

Wrong approach
如果你保留所有的高次项,而是操纵与每个项相关的斜率,会怎么样呢?请记住,每个术语都代表数据集中的一个属性,例如,x1-销售额,x2-利润,x3-支出,等等。
我们如何做到这一点?
在称为正则化的方法的帮助下,您将与每个斜率(θ)相关的项的值增加到更高的值,而与每个项相关的斜率将减少到更低的值。请注意,我们并没有消除较高程度的条款,我们正在增加它的价值,以惩罚其斜率。



Visualize the difference
1-如果斜率为 1,那么 x 的每一个单位变化,y 也会有一个单位变化。等式为“y=mx+c ”,其中 m=1,因此 y=x。
2-如果斜率为 2,等式将为 y=2x+c。这意味着对于半个单位的变化,在 x 中,y 将变化一个单位。因此,x 值越小,斜率越大。
3-如果斜率为 0.5,则等式为 y=0.5x+c。这意味着 x 变化 2 个单位,y 将变化 1 个单位。因此,x 值越高,斜率越低。
这意味着斜率和与之相关的变量值成反比。因此,增加属性“x”的值是有意义的,以便塑造它们的斜率,使它们不会过度适应数据。

摘要
简而言之,当在等式中引入 Lambda 时,模型变得一般化,并给出了更广泛的训练集。如果没有 lambda,模型将试图拟合训练集中的每一个点,因此在测试阶段失败,因为一旦新数据出现,它不知道下一步要去哪里。
机器学习安全性
使用模型来打破模型

本文原载于 blog.zakjost.com。请去那里订阅。
随着越来越多的系统在其决策过程中利用 ML 模型,考虑恶意行为者可能如何利用这些模型,以及如何设计针对这些攻击的防御措施将变得越来越重要。这篇文章的目的是分享我最近在这个话题上的一些心得。
ML 无处不在
可用数据、处理能力和 ML 空间中的创新的爆炸导致了 ML 的无处不在。鉴于开源框架和数据的激增,构建这些模型实际上非常容易(本教程将在大约 5-10 分钟内将零 ML/编程知识的人带到 6 ML 模型)。此外,云提供商提供 ML 即服务的持续趋势使客户能够构建解决方案,而无需编写代码或理解其工作原理。
Alexa 可以使用语音命令代表我们购买。模特识别色情内容,帮助我们的孩子更安全地使用互联网平台。他们在我们的道路上驾驶汽车,保护我们免受骗子和恶意软件的侵害。他们监控我们的信用卡交易和互联网使用情况,寻找可疑的异常情况。
" Alexa,给我的猫买鳄梨色拉酱"
ML 的好处是显而易见的——让一个人手动检查每一笔信用卡交易、每一张脸书图片、每一个 YouTube 视频等等是不可能的。风险呢?
在无人驾驶汽车导航时,不需要太多的想象力就可以理解 ML 算法出错可能带来的危害。常见的说法往往是,“只要它犯的错误比人类少,那就是净收益”。
但是那些恶意的演员试图欺骗模特的情况呢?来自麻省理工学院的学生团体 lab six 3D 打印了一只海龟,它被谷歌的 InceptionV3 图像分类器可靠地归类为“来福枪”,无论相机角度如何[1]。对于语音到文本系统,Carlini 和 Wagner 发现[2]:
给定任何音频波形,我们可以产生另一个超过 99.9%的相似度,但转录为我们选择的任何短语…我们的攻击 100%成功,不管想要的转录或初始源音频样本。
Papernot 等人表明,以有针对性的方式向恶意软件添加一行代码可以在超过 60%的情况下欺骗最先进的恶意软件检测模型[3]。
通过使用相当简单的技巧,一个糟糕的演员甚至可以让最有表现力和最令人印象深刻的模特以他们想要的任何方式出错。例如,这张图片骗过了谷歌模型,让它几乎 100%确定这是一张鳄梨色拉酱图片[1]:

这是一个现实生活中的停车标志的图像,它被操纵,使得计算机视觉模型在驾车实验中 100%的时间都被欺骗,认为它是一个“限速 45 英里/小时”的标志[4]:

怎么这么好,却这么坏?
在所有这些例子中,基本思想是以最大化模型输出变化的方式扰动输入。这些被称为“对立的例子”。有了这个框架,你可以知道如何最有效地调整猫的形象,让模型认为它是鳄梨色拉酱。这有点像让所有的小错误排成一行,指向同一个方向,这样雪花就变成了雪崩。从技术上来说,这就简化为寻找输出相对于输入的梯度——这是 ML 从业者很擅长做的事情!
值得强调的是,这些变化大多是察觉不到的。例如,听这些音频样本。尽管听起来和我的耳朵一样,一个翻译成“没有数据集,文章是无用的”,另一个翻译成“好吧,谷歌,浏览到 evil.com”。更值得强调的是,真正的恶意用户并不总是局限于做出难以察觉的改变,所以我们应该假设这是对安全漏洞的下限估计。
但是我需要担心吗?
好吧,所以这些模型的健壮性存在问题,这使得它们很容易被利用。但除非你是谷歌或脸书,否则你可能不会在生产系统中构建庞大的神经网络,所以你不必担心……对吗?对!?**
不对。这个问题不是神经网络独有的。事实上,被发现欺骗一个模型的对立例子经常欺骗其他模型,即使它们是使用不同的架构、数据集甚至算法训练的。这意味着,即使你要集合不同类型的模特,你的仍然不安全。如果你向外界公开一个模型,即使是间接的,有人可以向它发送输入并得到响应,你就有风险了。这一领域的历史始于暴露线性模型的弱点,只是后来才在深度网络的背景下重新点燃【6】。
我们如何阻止它?
在攻击和防御之间有一场持续的军备竞赛。这份最近出炉的《ICML 2018》最佳论文,“破”了同年会议论文呈现的 9 项答辩中的 7 项。这种趋势不太可能很快停止。
那么,一个普通的 ML 从业者该怎么做呢?他可能没有时间关注 ML 安全文献的最新进展,更不用说无休止地将新的防御结合到所有面向外部的生产模型中了。在我看来,唯一明智的方法是设计具有多种智能来源的系统,这样单点故障不会破坏整个系统的效能。这意味着您假设一个单独的模型可以被破坏,并且您设计您的系统对那种情况是健壮的。
例如,让无人驾驶汽车完全由计算机视觉 ML 系统导航可能是一个非常危险的想法(原因不仅仅是安全)。使用正交信息(如激光雷达、GPS 和历史记录)的环境冗余测量可能有助于反驳对立的视觉结果。这自然假定系统被设计成综合这些信号以做出最终判断。
更重要的一点是,我们需要认识到模型安全性是一个实质性的普遍风险,随着 ML 越来越多地融入我们的生活,它只会随着时间的推移而增加。因此,我们需要建立作为 ML 从业者的肌肉来思考这些风险,并设计强大的系统来抵御它们。就像我们在 web 应用程序中采取预防措施来保护我们的系统免受恶意用户的攻击一样,我们也应该积极应对模型安全风险。正如机构有应用程序安全审查小组进行软件渗透测试一样,我们也需要建立提供类似功能的模型安全审查小组。有一点是肯定的:这个问题不会很快消失,而且可能会越来越严重。
如果你想了解更多关于这个话题的内容,比吉奥和花小蕾的论文给出了该领域精彩的回顾和历史,包括这里没有提到的完全不同的攻击方法(例如数据中毒)[6]。
参考
- “愚弄物理世界中的神经网络。”2017 年 10 月 31 日,www.labsix.org/physical-objects-that-fool-neural-nets。
- 名词(noun 的缩写)卡利尼 d .瓦格纳。"音频对抗示例:针对语音转文本的攻击."arXiv 预印本 arXiv:1801.01944 ,2018。
- K.Grosse,N. Papernot,P. Manoharan,M. Backes,P. McDaniel (2017) 恶意软件检测的对抗示例。载于:Foley S .,Gollmann D .,Snekkenes E .(编辑)《计算机安全——ESORICS 2017》。ESORICS 2017。计算机科学讲义,第 10493 卷。斯普林格,查姆。
- K.Eykhold,I. Evtimov 等人,“对深度学习视觉分类的鲁棒物理世界攻击”。arXiv 预印本 arXiv:1707.08945 ,2017。
- 名词(noun 的缩写)Papernot,P. McDaniel,I.J. Goodfellow。“机器学习中的可转移性:从现象到使用敌对样本的黑盒攻击”。arXiv 预印本 arXiv:1605.07277 ,2016。
- B.花小蕾·比吉奥。"野生模式:对抗性机器学习兴起后的十年."arXiv 预印本 arXiv:1712.03141 ,2018。
原载于blog.zakjost.com。
机器学习安全性及其与模型可解释性的相互作用

机器学习的发展和部署在许多方面带来了机遇和挑战:从高质量和相关数据集的管理,到可推广模型的开发,最后到所述模型的部署。在最后一个阵营中,公平性、问责制和透明度等问题是最近许多研究问题的核心(参见 FATML 社区[1]),以及可解释性和数据隐私。
模型安全性是另一个重要的考虑因素。在实践中,模型安全性旨在防止对手窃取已部署模型的模型参数(可通过 API 访问),这种损失可能会产生竞争/法律/健壮性后果。这种担忧既影响初创公司,也影响公司,特别是 Clarifai、Google、Amazon 等较大的公司,以及其他盈利策略依赖于在其 API 生命周期内摊销模型培训成本的公司[2]。
当一家公司必须在允许访问一个非常强大的 API(带有关于模型输出的详细信息,包括类别标签、置信度得分等)和冒着被对手复制其模型的风险之间做出决定时,这种紧张关系确实令人着迷。即使折衷的解决方案建议 API 只提供有限的信息,法规要求部署的模型提供可解释的解释(法律要求[3]),这可能会再次促进模型窃取[4]。
最近,我和我的合作者介绍了梅斯:对后果性决策的模型不可知的反事实解释[5]。动机是提供一个全封装的方法,以满足对各种 ML 模型和距离度量(代表一组不同的现实世界应用)的可解释解释的法律要求。接下来,我很兴奋地探索反事实解释的潜力,同时提供高质量的解释和可证明的保证,而不透露太多关于模型的内部。实现这一点对于消费者和法律采用 ML 模型是必要的。
[2]https://arxiv.org/pdf/1609.02943.pdf
[3]https://arxiv.org/pdf/1711.00399.pdf
https://arxiv.org/pdf/1807.05185.pdf
https://arxiv.org/pdf/1905.11190.pdf
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
单词嵌入 Python 示例—情感分析

https://www.pexels.com/photo/person-using-appliance-132700/
机器学习的主要应用之一是情感分析。情感分析就是判断一个文档的基调。情感分析的输出通常是 0 到 1 之间的分数,其中 1 表示语气非常积极,0 表示非常消极。情绪分析经常用于交易。例如,情绪分析被应用于交易者的推文,以估计整体市场情绪。
正如人们所料,情感分析是一个自然语言处理(NLP)问题。NLP 是人工智能的一个领域,涉及理解和处理语言。本文的目标是构建一个模型,从语料库的文档中获取单词的语义。在高层次上,可以想象我们将带有单词 好的 的文档分类为肯定的,而将单词 坏的 分类为否定的。不幸的是,问题并没有那么简单,因为单词前面可以有 而不是 如 不好。
密码
说得够多了,让我们深入一些 Python 代码。
import numpy as np
from matplotlib import pyplot as plt
plt.style.use('dark_background')
from keras.datasets import imdb
from keras.models import Sequential
from keras.preprocessing.sequence import pad_sequences
from keras.layers import Embedding, GlobalAveragePooling1D, Dense
参数num_words=10000确保我们只保留训练集中出现频率最高的前 10,000 个单词。为了保持数据的大小易于管理,我们会丢弃一些不常用的单词。
num_words = 10000
我们将使用包含来自互联网电影数据库的 50,000 条电影评论的 IMDB 数据集。后者被分成 25,000 条用于训练的评论和 25,000 条用于测试的评论。训练集和测试集是平衡的,这意味着它们包含相同数量的正面和负面评论。
old = np.load
np.load = lambda *a,**k: old(*a,**k, allow_pickle = True)
(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=num_words)
np.load = old
del(old)print("Training entries: {}, labels: {}".format(len(X_train), len(y_train)))

当我们使用keras.datasets.imdb将数据集导入我们的程序时,它已经经过了预处理。换句话说,每个例子都是一个整数列表,其中每个整数代表字典中的一个特定单词,每个标签都是 0 或 1 的整数值,其中 0 是负面评论,1 是正面评论。我们先在第一次复习的时候来个巅峰。
print(X_train[0])

为了更好地理解我们正在处理的内容,我们将创建一个助手函数,将每个训练示例中的整数映射到索引中的单词。
word_index = imdb.get_word_index()# The first indices are reserved
word_index = {k:(v+3) for k,v in word_index.items()}
word_index["<PAD>"] = 0
word_index["<START>"] = 1
word_index["<UNK>"] = 2 # unknown
word_index["<UNUSED>"] = 3reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])def decode_review(text):
return ' '.join([reverse_word_index.get(i, '?') for i in text])
现在,我们可以使用decode_review功能来显示第一篇评论的文本。
decode_review(X_train[0])

鉴于文档中的每个单词都将被解释为一个特征,我们必须确保电影评论的长度相同,然后才能尝试将它们输入神经网络。
len(X_train[0]), len(X_train[1])

我们将使用pad_sequence功能来标准化长度。
X_train = pad_sequences(
X_train,
value=word_index["<PAD>"],
padding='post',
maxlen=256
)X_test = pad_sequences(
X_test,
value=word_index["<PAD>"],
padding='post',
maxlen=256
)
让我们看看前几个样本的长度。
len(X_train[0]), len(X_train[1])

正如敏锐的读者可能已经猜到的,单词是分类特征。因此,我们不能直接将它们输入神经网络。尽管它们已经被编码为整数,但是如果我们让它们保持原样,模型会将具有较高值的整数解释为比具有较低值的整数具有更高的优先级。通常,您可以通过将数组转换为指示单词出现的向量0和1来解决这个问题,这类似于一种热编码,但是对于单词来说,这是内存密集型的。给定 10,000 个单词的词汇表,我们需要在 RAM 中存储num_words * num_reviews大小的矩阵。
嵌入
这就是嵌入发挥作用的地方。嵌入通过将我们的高维数据映射到低维空间(类似于 PCA)来解决稀疏输入数据(非常大的向量,具有相对较少的非零值)的核心问题。
例如,假设我们有一个由以下两个句子组成的语料库。
- 希望很快见到你
- 很高兴再次见到你
就像 IMDB 数据集一样,我们可以为每个单词分配一个唯一的整数。
[0, 1, 2, 3, 4]
[5, 1, 2, 3, 6]
接下来,我们可以定义一个嵌入层。
Embedding(input_dim=7, output_dim=2, input_length=5)
- input_dim :训练集中词汇的大小(即不同单词的数量)
- output_dim :嵌入向量的大小
- input_length :样本中特征的个数(即每个文档的字数)。例如,如果我们所有的文档都由 1000 个单词组成,那么输入长度将是 1000。
嵌入的工作方式类似于查找表。每个记号(即单词)充当存储向量的索引。当一个令牌被提供给嵌入层时,它返回与该令牌相关联的向量,并通过神经网络传递该向量。随着网络的训练,嵌入也被优化。
+------------+------------+
| index | Embedding |
+------------+------------+
| 0 | [1.2, 3.1] |
| 1 | [0.1, 4.2] |
| 2 | [1.0, 3.1] |
| 3 | [0.3, 2.1] |
| 4 | [2.2, 1.4] |
| 5 | [0.7, 1.7] |
| 6 | [4.1, 2.0] |
+------------+------------+
比方说,我们有下面的单词教师的二维嵌入向量。

我们可以想象一个二维空间,其中相似的单词(即学校、导师)聚集在一起。

在我们的例子中,我们使用 16 维的嵌入向量。因此,我们可能会发现享受、喜欢和棒极了这几个词彼此非常接近。然后,我们的模型可以学习将其单词映射到 16 维空间中彼此接近的嵌入向量的评论分类为正面的。
model = Sequential()
model.add(Embedding(input_dim==num_words, output_dim=16, input_length=256))
model.add(GlobalAveragePooling1D())
model.add(Dense(16, activation='relu'))
model.add(Dense(1, activation='sigmoid'))model.summary()

我们使用亚当作为我们的优化器,使用二元 交叉熵作为我们的损失函数,因为我们试图在两个类之间进行选择。
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy']
)
我们留出 10%的数据进行验证。每个时期,在更新权重之前,512 个评论通过神经网络。
history = model.fit(
X_train,
y_train,
epochs=20,
batch_size=512,
validation_split=0.1,
shuffle=True
)

我们可以通过使用由 fit 函数返回的历史变量来绘制每个时期的训练和验证准确度和损失。
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(loss) + 1)
plt.plot(epochs, loss, 'y', label='Training loss')
plt.plot(epochs, val_loss, 'r', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()

acc = history.history['acc']
val_acc = history.history['val_acc']
plt.plot(epochs, acc, 'y', label='Training acc')
plt.plot(epochs, val_acc, 'r', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

最后,让我们看看我们的模型在测试集上的表现如何。
test_loss, test_acc = model.evaluate(X_test, y_test)
print(test_acc)

最后的想法
当我们处理具有许多类别(即单词)的分类特征时,我们希望避免使用一种热编码,因为它需要我们在内存中存储一个大矩阵并训练许多参数。相反,我们可以将每个类别映射到一个 n 维嵌入向量,并使用嵌入向量作为输入来训练我们的机器学习模型。
机器学习:用 Python 实现简单线性回归
在这篇文章中,我们将指导你使用简单的线性回归来进行机器学习的第一步。
什么是线性?
首先,假设你正在沃尔玛购物。不管你买不买东西,你都要付 2 美元的停车票。每个苹果的价格是 1.5 美元,你必须购买一个( x) 的苹果。然后,我们可以填充如下价格列表:

Crosstab (Quantity & Price) for apple at Walmart
对于本例,使用公式 y=2+1.5x 很容易预测(或计算)基于价值的价格,反之亦然,或者:

Linear Functions
使用:
- a = 2
- b = 1.5
一个线性函数有一个自变量和一个因变量。自变量为 x 因变量为 y 。
- 是常数项或 y 截距。是 x = 0 时因变量的值。
- b 是自变量的系数。它也被称为斜率,给出了因变量的变化率。
为什么我们称之为线性?好了,让我们把上面得到的数据集可视化吧!

Shopping cost (y = 1.5x + 2)
在标绘购物成本的所有值(蓝线)后,你可以看到,它们都在一条线上,这就是为什么我们称之为。用线性方程(y=a+bx),a 是自变量。即使 a=0(停车票不用你出),购物成本线也会下移,他们还是在一条线上(橙色线)。**

Shopping cost (y = 1.5x)
但是在现实生活中,事情并没有那么简单!
我们再举一个例子,在 AB 公司,有一个基于工作年限的工资分配表,如下所示:

Salary based on Years of Experience (salary_data.csv)
假设你是一名人力资源主管,你得到了一名有 5 年工作经验的候选人。那你应该给他开出的最好工资是多少?”
在深入探讨这个问题之前,让我们先将数据集绘制到图中:

Salary Data on Scatter Plot
请仔细看这张图表。现在我们有一个坏消息:所有的观察结果都不在一条线上。这意味着我们找不到计算(y)值的方程。
那现在怎么办?别担心,我们有好消息要告诉你!
向下滚动之前,再次查看散点图。你看到了吗?
所有的点不在一条直线上,但是它们在一条直线上!是线性的!****

Salary Data on Scatter Plot with linear shape
根据我们的观察,我们可以猜测 5 年经验的薪资范围应该在红色范围内。当然,我们可以向候选人提供红色范围内的任何数字。但是如何挑选最适合他的号码呢?是时候使用机器学习来预测我们候选人的最佳薪酬了。
在本节中,我们将在 Spyder IDE 上使用 Python 来为我们的候选人找到最佳工资。好吧,我们开始吧!
用 Python 实现线性回归
在继续之前,我们总结了机器学习的两个基本步骤如下:
- 培养
- 预测
好的,我们将使用 4 个库,如numpy和pandas来处理数据集,sklearn来实现机器学习功能,matplotlib来可视化我们的绘图以供查看:
代码解释:
dataset:该表包含了我们 csv 文件中的所有值X:包含年经验数组的第一列y:包含薪资数组的最后一列
接下来,我们必须将数据集(总共 30 个观察值)分成 2 组:用于训练的训练集和用于测试的测试集:
代码解释:
test_size=1/3:我们将我们的数据集(30 个观察值)分成两部分(训练集、测试集),并且测试集与数据集的比率是 1/3 (10 个观察值将被放入测试集)。你可以放 1/2 得到 50%或者 0.5,它们是一样的。我们不应该让测试集太大;如果它太大,我们将缺乏数据来训练。通常情况下,我们应该选择 5%到 30%左右。train_size:如果我们已经使用了 test_size,其余的数据将自动分配给 train_size。random_state:这是随机数生成器的种子。我们也可以放一个RandomState类的实例。如果我们将其留空或为 0,将使用由np.random使用的RandomState实例。
我们已经有了训练集和测试集,现在我们必须构建回归模型:
代码解释:
regressor = LinearRegression():我们的训练模型,将实现线性回归。regressor.fit:在这一行中,我们通过包含年经历值的X_train和包含具体薪资值的y_train来组成模型。这是训练过程。
让我们设想一下我们的培训模型和测试模型:
运行上述代码后,您将在控制台窗口中看到两个图:

Training Set

Test Set
比较两幅图,我们可以看到两条蓝线是同一个方向。我们的模型现在很好用。
好吧!我们已经有了模型,现在我们可以用它来计算(预测)X 的任何值取决于 y 或y 的任何值取决于 X 。我们是这样做的:

Predict y_pred using single value of X=5
答对了。 X = 5 (5 年经验)的y_pred值为 73545.90
你可以向你的候选人提供 73,545.90 美元的薪水,这对他来说是最好的薪水了!
我们也可以传递一个 X 的数组,而不是 X** 的**单值:****

Predict y_pred using array of X_test
我们也可以用 y 来预测 X。你自己试试吧!
总之,对于简单的线性回归,我们必须按照以下 5 个步骤进行:
- 导入数据集。
- 将数据集分成训练集和测试集(每个集有 X 和 y 两个维度)。通常,测试集应该是数据集的 5%到 30%。
- 将训练集和测试集可视化以进行双重检查(如果需要,可以绕过这一步)。
- 初始化回归模型并使用训练集(X 和 y)对其进行拟合。
- 我们来预测一下!!
资源:
天天快乐学习!
机器学习技术在股票价格预测中的应用

Image generated using Neural Style Transfer.
机器学习有很多应用,其中之一就是预测时间序列。可以说,预测最有趣(或者最有利可图)的时间序列之一是股票价格。
最近我读了一篇将机器学习技术应用于股票价格预测的博文。这里可以看。这是一篇写得很好的文章,探讨了各种技术。然而,我觉得这个问题可以用更严谨的学术方法来处理。例如,在文章中,方法“移动平均”、“自动 ARIMA”和“先知”的预测范围为 1 年,而“线性回归”、“k-最近邻”和“长短期记忆(LSTM)”的预测范围为 1 天。文章的结尾写道:“LSTM 轻而易举地超越了我们迄今为止看到的任何算法。”但是很明显,我们不是在这里比较苹果和苹果。
所以,这是我对这个问题的看法。
问题陈述
我们的目标是预测 Vanguard Total Stock Market ETF(VTI)的每日调整收盘价,使用前 N 天的数据(即预测范围=1)。我们将使用 VTI 从 2015 年 11 月 25 日到 2018 年 11 月 23 日的三年历史价格,可以从雅虎财经轻松下载。下载后,数据集如下所示:

Downloaded dataset for VTI.
我们将把这个数据集分成 60%训练、20%验证和 20%测试。将使用训练集来训练模型,将使用验证集来调整模型超参数,并且最终将使用测试集来报告模型的性能。下图显示了调整后的收盘价,分为相应的训练集、验证集和测试集。

Split the dataset into 60% train, 20% validation, and 20% test.
为了评估我们方法的有效性,我们将使用均方根误差(RMSE)和平均绝对百分比误差(MAPE)指标。对于这两个指标,值越低,预测越好。
最后一个值
在最后一个值方法中,我们将简单地将预测值设置为最后一个观察值。在我们的上下文中,这意味着我们将当前调整后的收盘价设置为前一天的调整后收盘价。这是最具成本效益的预测模型,通常用作比较更复杂模型的基准。这里没有要优化的超参数。
下图显示了使用最后一个值方法的预测。如果仔细观察,您会发现每天的预测值(红叉)只是前一天的值(绿叉)。

Predictions using the last value method.
移动平均数
在移动平均法中,预测值将是前 N 个值的平均值。在我们的上下文中,这意味着我们将当前调整后的收盘价设置为前 N 天调整后的收盘价的平均值。超参数 N 需要调整。
下图显示了不同 N 值的验证集上实际值和预测值之间的 RMSE。我们将使用 N=2,因为它给出了最低的 RMSE。

RMSE between actual and predicted values on the validation set, for various N.
下图显示了使用移动平均法的预测。

Predictions using the moving average method.
你可以查看 Jupyter 笔记本的移动平均法这里。
线性回归
线性回归是一种对因变量和一个或多个自变量之间的关系进行建模的线性方法。我们在这里使用线性回归的方法是,我们将对前 N 个值拟合一个线性回归模型,并使用该模型来预测当天的值。下图是一个 N=5 的例子。实际调整后的收盘价显示为深蓝色十字,我们希望预测第 6 天的价值(黄色方块)。我们将通过前 5 个实际值拟合一条线性回归线(浅蓝色线),并用它来做第 6 天的预测(浅蓝色圆圈)。

Predicting the next value using linear regression with N=5.
下面是我们用来训练模型和进行预测的代码。
import numpy as np
from sklearn.linear_model import LinearRegressiondef get_preds_lin_reg(df, target_col, N, pred_min, offset):
"""
Given a dataframe, get prediction at each timestep
Inputs
df : dataframe with the values you want to predict
target_col : name of the column you want to predict
N : use previous N values to do prediction
pred_min : all predictions should be >= pred_min
offset : for df we only do predictions for df[offset:]
Outputs
pred_list : the predictions for target_col
"""
# Create linear regression object
regr = LinearRegression(fit_intercept=True) pred_list = [] for i in range(offset, len(df['adj_close'])):
X_train = np.array(range(len(df['adj_close'][i-N:i])))
y_train = np.array(df['adj_close'][i-N:i])
X_train = X_train.reshape(-1, 1)
y_train = y_train.reshape(-1, 1)
regr.fit(X_train, y_train) # Train the model
pred = regr.predict(N)
pred_list.append(pred[0][0])
# If the values are < pred_min, set it to be pred_min
pred_list = np.array(pred_list)
pred_list[pred_list < pred_min] = pred_min
return pred_list
下图显示了不同 N 值的验证集上实际值和预测值之间的 RMSE。我们将使用 N=5,因为它给出了最低的 RMSE。

RMSE between actual and predicted values on the validation set, for various N.
下图显示了使用线性回归方法的预测。可以观察到这种方法不能捕捉方向的变化(即下降趋势到上升趋势,反之亦然)非常好。

Predictions using the linear regression method.
你可以查看 Jupyter 笔记本上的线性回归这里。
极端梯度增强(XGBoost)
梯度推进是以迭代的方式将弱学习者转换为强学习者的过程。XGBoost 这个名字指的是推动提升树算法的计算资源极限的工程目标。自 2014 年推出以来,XGBoost 已被证明是一种非常强大的机器学习技术,通常是许多机器学习竞赛中的首选算法。
我们将在训练集上训练 XGBoost 模型,使用验证集调整它的超参数,最后在测试集上应用 XGBoost 模型并报告结果。可以使用的明显特征是最近 N 天的调整收盘价,以及最近 N 天的成交量。除了这些功能,我们还可以做一些功能工程。我们将构建的附加功能有:
- 最近 N 天每天的最高价和最低价之差
- 最近 N 天每天的开盘和收盘之间的差异
在构建这个模型的过程中,我学到了一个有趣的经验,即特征缩放对于模型的正常工作非常重要。我的第一个模型根本没有实现任何缩放,验证集上的预测显示在下面的图中。这里发生的情况是,模型对 89 到 125 之间的调整后收盘价值进行训练,因此模型只能输出该范围内的预测。当模型试图预测验证集时,如果看到超出此范围的值,它就不能很好地进行归纳。

Predictions are highly inaccurate if feature and target scaling are not done properly.
我接下来尝试的是调整训练集,使其均值为 0,方差为 1,并对验证集应用相同的转换。但是很明显这并不奏效,因为这里我们使用了从训练集计算的平均值和方差来转换验证集。由于来自验证集的值比来自训练集的值大得多,因此缩放后,这些值仍然会更大。结果是预测看起来仍然如上,只是 y 轴上的值现在被缩放了。
最后,我所做的是调整训练集,使其均值为 0,方差为 1,并以此来训练模型。随后,当我对验证集进行预测时,对于每个样本的每个特征组,我将调整它们,使均值为 0,方差为 1。例如,如果我们在 T 日进行预测,我将采用最近 N 天(T-N 日至 T-1 日)调整后的收盘价,并将其调整为均值为 0,方差为 1。对于量的特性也是如此,我将取最近 N 天的量,并将它们缩放到均值为 0,方差为 1。对我们上面构建的附加特性重复同样的操作。然后,我们使用这些缩放后的特征进行预测。预测值也将被缩放,我们使用它们相应的平均值和方差对它们进行逆变换。我发现这种扩展方式提供了最好的性能,正如我们将在下面看到的。
下面是我们用来训练模型和进行预测的代码。
import math
import numpy as npfrom sklearn.metrics import mean_squared_error
from xgboost import XGBRegressordef get_mape(y_true, y_pred):
"""
Compute mean absolute percentage error (MAPE)
"""
y_true, y_pred = np.array(y_true), np.array(y_pred)
return np.mean(np.abs((y_true - y_pred) / y_true)) * 100def train_pred_eval_model(X_train_scaled, \
y_train_scaled, \
X_test_scaled, \
y_test, \
col_mean, \
col_std, \
seed=100, \
n_estimators=100, \
max_depth=3, \
learning_rate=0.1, \
min_child_weight=1, \
subsample=1, \
colsample_bytree=1, \
colsample_bylevel=1, \
gamma=0):
'''
Train model, do prediction, scale back to original range and do
evaluation
Use XGBoost here.
Inputs
X_train_scaled : features for training. Scaled to have
mean 0 and variance 1
y_train_scaled : target for training. Scaled to have
mean 0 and variance 1
X_test_scaled : features for test. Each sample is
scaled to mean 0 and variance 1
y_test : target for test. Actual values, not
scaled
col_mean : means used to scale each sample of
X_test_scaled. Same length as
X_test_scaled and y_test
col_std : standard deviations used to scale each
sample of X_test_scaled. Same length as
X_test_scaled and y_test
seed : model seed
n_estimators : number of boosted trees to fit
max_depth : maximum tree depth for base learners
learning_rate : boosting learning rate (xgb’s “eta”)
min_child_weight : minimum sum of instance weight(hessian)
needed in a child
subsample : subsample ratio of the training
instance
colsample_bytree : subsample ratio of columns when
constructing each tree
colsample_bylevel : subsample ratio of columns for each
split, in each level
gamma : minimum loss reduction required to make
a further partition on a leaf node of
the tree
Outputs
rmse : root mean square error of y_test and
est
mape : mean absolute percentage error of
y_test and est
est : predicted values. Same length as y_test
''' model = XGBRegressor(seed=model_seed,
n_estimators=n_estimators,
max_depth=max_depth,
learning_rate=learning_rate,
min_child_weight=min_child_weight,
subsample=subsample,
colsample_bytree=colsample_bytree,
colsample_bylevel=colsample_bylevel,
gamma=gamma)
# Train the model
model.fit(X_train_scaled, y_train_scaled)
# Get predicted labels and scale back to original range
est_scaled = model.predict(X_test_scaled)
est = est_scaled * col_std + col_mean # Calculate RMSE
rmse = math.sqrt(mean_squared_error(y_test, est))
mape = get_mape(y_test, est)
return rmse, mape, est
下图显示了不同 N 值的验证集上实际值和预测值之间的 RMSE。我们将使用 N=3,因为它给出了最低的 RMSE。

Tuning N using RMSE and MAPE.
优化前后的超参数和性能如下所示。

Tuning XGBoost hyperparameters using RMSE and MAPE.
下图显示了使用 XGBoost 方法的预测。

Predictions using the XGBoost method.
你可以在这里查看 XGBoost 的 Jupyter 笔记本。
长短期记忆(LSTM)
LSTM 是一种深度学习技术,被开发用来解决长序列中遇到的消失梯度问题。LSTM 有三个门:更新门、遗忘门和输出门。更新和忽略门确定存储单元的每个元件是否被更新。输出门决定了作为激活输出到下一层的信息量。
下面是我们将要使用的 LSTM 建筑。我们将使用两层 LSTM 模块,中间有一个脱扣层以避免过度拟合。

LSTM network architecture.
下面是我们用来训练模型和进行预测的代码。
import math
import numpy as npfrom keras.models import Sequential
from keras.layers import Dense, Dropout, LSTMdef train_pred_eval_model(x_train_scaled, \
y_train_scaled, \
x_test_scaled, \
y_test, \
mu_test_list, \
std_test_list, \
lstm_units=50, \
dropout_prob=0.5, \
optimizer='adam', \
epochs=1, \
batch_size=1):
'''
Train model, do prediction, scale back to original range and do
evaluation
Use LSTM here.
Returns rmse, mape and predicted values
Inputs
x_train_scaled : e.g. x_train_scaled.shape=(451, 9, 1).
Here we are using the past 9 values to
predict the next value
y_train_scaled : e.g. y_train_scaled.shape=(451, 1)
x_test_scaled : use this to do predictions
y_test : actual value of the predictions
mu_test_list : list of the means. Same length as
x_test_scaled and y_test
std_test_list : list of the std devs. Same length as
x_test_scaled and y_test
lstm_units : dimensionality of the output space
dropout_prob : fraction of the units to drop for the
linear transformation of the inputs
optimizer : optimizer for model.compile()
epochs : epochs for model.fit()
batch_size : batch size for model.fit()
Outputs
rmse : root mean square error
mape : mean absolute percentage error
est : predictions
'''
# Create the LSTM network
model = Sequential()
model.add(LSTM(units=lstm_units,
return_sequences=True,
input_shape=(x_train_scaled.shape[1],1))) # Add dropput with a probability of 0.5
model.add(Dropout(dropout_prob)) model.add(LSTM(units=lstm_units)) # Add dropput with a probability of 0.5
model.add(Dropout(dropout_prob)) model.add(Dense(1)) # Compile and fit the LSTM network
model.compile(loss='mean_squared_error', optimizer=optimizer)
model.fit(x_train_scaled, y_train_scaled, epochs=epochs,
batch_size=batch_size, verbose=0)
# Do prediction
est_scaled = model.predict(x_test_scaled)
est = (est_scaled * np.array(std_test_list).reshape(-1,1)) +
np.array(mu_test_list).reshape(-1,1)
# Calculate RMSE and MAPE
rmse = math.sqrt(mean_squared_error(y_test, est))
mape = get_mape(y_test, est)
return rmse, mape, est
我们将使用与 XGBoost 中相同的方法来缩放数据集。LSTM 网络在调整验证集之前和之后的超参数和性能如下所示。

Tuning LSTM hyperparameters using RMSE and MAPE.
下图显示了使用 LSTM 的预测。

Predictions using the LSTM method.
你可以在这里查看 LSTM 的 Jupyter 笔记本。
调查结果和未来工作
下面,我们在同一个图中绘制了我们之前探索的所有方法的预测。很明显,使用线性回归的预测提供了最差的性能。除此之外,从视觉上很难判断哪种方法提供了最好的预测。

下面是我们探讨的各种方法在 RMSE 和 MAPE 的对比。我们看到最后一个值方法给出了最低的 RMSE 和 MAPE,其次是 XGBoost,然后是 LSTM。有趣的是,简单的最后值方法优于所有其他更复杂的方法,但这很可能是因为我们的预测范围只有 1。对于更长的预测范围,我相信其他方法可以比最后值方法更好地捕捉趋势和季节性。

Comparison of various methods using RMSE and MAPE.
作为未来的工作,探索更长的预测范围将是有趣的,例如 1 个月或 1 年。探索其他预测技术也将是有趣的,如自回归综合移动平均(ARIMA)和三重指数平滑(即。Holt-Winters 方法),并看看它们与上面的机器学习方法相比如何。
如果你有兴趣进一步探索,看看这篇文章。
[## 中等
编辑描述
ngyibin.medium.com](https://ngyibin.medium.com/subscribe)
机器学习——文本分类,使用 fast.ai 的语言建模
将最新的深度学习技术应用于文本处理
T 转移学习是一种技术,在这种技术中,我们不是从头开始训练模型,而是重用预先训练好的模型,然后针对另一项相关任务对其进行微调。它在计算机视觉应用中非常成功。在自然语言处理(NLP)中,迁移学习大多局限于使用预先训练的单词嵌入。在预训练期间使用语言建模领域的研究已经导致许多自然语言处理任务的最先进结果的巨大飞跃,例如通过各种方法进行的文本分类、自然语言推理和问题回答,如 ULMFiT 、 OpenAI Transformer、 ELMo 和谷歌人工智能的 BERT 。

在这篇文章中,我们将讨论单词嵌入方法在自然语言处理问题的迁移学习中的局限性,以及使用语言模型通过 fast.ai 库构建文本分类器。
用语言数据迁移学习
单词嵌入算法 word2vec 和 GloVe 提供了单词到高维连续向量空间的映射,其中具有相似含义的不同单词具有相似的向量表示。这些单词嵌入,在大量未标记数据上预先训练,用于初始化称为嵌入层的神经网络的第一层,然后在特定任务的数据上训练模型的其余部分。NLP 问题中的这种转移学习是 浅 由于学习只转移到模型的第一层,网络的其余部分仍然需要从头开始训练。用单词嵌入初始化的模型需要从头开始学习,不仅要消除单词的歧义,还要从单词序列中推导出含义。为了做到这一点,用这些浅层表示初始化的 NLP 模型需要一个巨大的数据集来实现良好的性能,这也可能导致非常大的计算成本[1]。
语言建模
语言建模的核心目标是语言理解,它需要对复杂的语言现象进行建模,以处理具有挑战性的语言理解问题,如翻译、问答和情感分析。语言模型试图通过分层表示来学习自然语言的结构,因此既包含低级特征(单词表示),也包含高级特征(语义)。语言建模的一个关键特征是它是生成性的,这意味着它的目标是在给定前一个单词序列的情况下预测下一个单词。它能够做到这一点,因为语言模型通常是以无监督的方式在非常大的数据集上训练的,因此该模型可以以比单词嵌入更深入的方式“学习”语言的句法特征[2]。
为了预测一个句子的下一个单词,模型实际上需要了解相当多的语言和相当多的世界知识。这里有一个例子:
- “我想吃个辣 __”:很明显是“狗”,对吧?
- “那天很热 __”:大概是“天”
如你所见,这里没有足够的信息来决定下一个单词可能是什么。但是有了神经网络,你绝对可以,只要你训练一个神经网络来预测一个句子的下一个单词,那么你实际上就有了很多信息。
快速人工智能
fastai 库专注于使用预先训练的语言模型并对其进行微调,分以下三步完成:
- 数据预处理用最少的代码量。
- 创建一个带有预训练权重的语言模型,您可以根据数据集对其进行微调。
- 在语言模型之上创建其他模型,例如分类器。
环境
在我们继续之前,我们需要为 fast.ai 设置环境。
安装和更新
要安装 fastai:
conda install -c pytorch -c fastai fastai pytorch
如果您想尝试一些准备运行的选项:
我使用 Colab 进行初步学习,但面临许多“脱节”的问题。Kaggle 也是一个不错的选择。Floydhub 运行顺利,但在免费积分之后,你需要付费使用。设置好您的环境后,让我们继续进行一些操作。
构建文本分类器
让我们构建一个文本分类器来使用到目前为止讨论的技术对 IMDB 电影数据集的情感进行分类。IMDb 数据集包含 25,000 条用于训练的电影评论,以及 25,000 条用于测试的电影评论。我们已经从之前的帖子中下载了 IMDb 的数据,并保存为 csv 格式。让我们把数据装入数据帧,

‘1’ positive and ‘0’ negative sentiment
使用下面这段代码。
**df_imdb = pd.read_csv(path/'movies_data.csv')
df_imdb.head()**#Loading only few training and validation samples, for quick training time
**trn_texts = df_imdb.loc[10000:14999, 'review'].values
trn_labels = df_imdb.loc[10000:14999, 'sentiment'].values
val_texts = df_imdb.loc[36000:38999, 'review'].values
val_labels = df_imdb.loc[36000:38999, 'sentiment'].values****np.random.seed(42)
trn_idx = np.random.permutation(len(trn_texts))
val_idx = np.random.permutation(len(val_texts))****trn_texts = trn_texts[trn_idx]
val_texts = val_texts[val_idx]****trn_labels = trn_labels[trn_idx]
val_labels = val_labels[val_idx]****col_names = ['labels','text']
df_trn = pd.DataFrame({'text':trn_texts, 'labels':trn_labels}, columns=col_names)
df_val = pd.DataFrame({'text':val_texts, 'labels':val_labels}, columns=col_names)**
我们使用来自培训的 5000 [每个标签 2500]和来自验证示例的 3000[每个标签 1500]。我使用较小的数据集来更快地完成训练,请使用完整的数据集来提高性能。

步骤 1:数据预处理
从原始文本创建数据集非常简单。该库提供了非常易于使用的 API[4],根据我们的数据是如何构造的,创建一个数据类 TextDataBunch 用于文本处理,from_csv、from_folder、from_df更多细节请参考文档。这里我们将使用[TextLMDataBunch](https://docs.fast.ai/text.data.html#TextLMDataBunch)的方法from_df来创建一个特定于语言模型的数据串:
# Language model data
**data_lm = TextLMDataBunch.from_df('./', train_df=df_trn, valid_df=df_val)**
这在幕后做了所有必要的预处理。让我们看看 fast.ai 是如何对数据进行编码的
**data_lm.show_batch()**

我们可以看到许多标签被应用于单词,如上所示。这是为了保留所有可用于收集对新任务词汇理解的信息。所有标点符号、标签和特殊字符也会被保留。该文本使用各种标记编码,如下所示:

**xxbos**:句子的开始**xxfld**:表示文档的独立部分,如标题、摘要等。,每个都将获得一个单独的字段,因此它们将被编号(例如xxfld 1、xxfld 2)。**xxup**:如果所有的大写字母中都有东西,它会变成小写字母,一个名为xxup的标记会被添加进去。全大写的单词,如“我在喊”,标记为“xxup i xxup am xxup shouting”**xxunk**:代币代替生僻字。**xxmaj**: token 表示单词有大写。“The”将被标记为“xxmaj the”。**xxrep**: token 表示重复的单词,如果你连续有 29 个!(即xxrep 29 !)。
词汇表:唯一可能的标记列表称为词汇表。下面按频率顺序列出了前 20 个唯一令牌:
**data_lm.vocab.itos[:20]
['xxunk', 'xxpad', 'xxbos', 'xxfld', 'xxmaj', 'xxup', 'xxrep', xxwrep', 'the', '.', ',', 'a', 'and', 'of', 'to', 'is', 'it', 'in', i', 'this']**
数字化:最后,机器更容易处理数字,因此用 vocab 中的记号位置替换记号:

默认的 vocab 大小设置为 60,000 个单词,添加到 vocab 中的单词的最小计数为 2,以避免权重矩阵变大。
保存和加载:我们可以在预处理完成后保存数据串。我们也可以在需要的时候加载。
**# save and load
data_lm.save(**'tmp_lm'**)** **data_lm = TextClasDataBunch.load('./',** 'tmp_lm'**)**
步骤 2:创建语言模型
Fast.ai 有一个预训练的 Wikitext 模型,由从维基百科提取的 1.03 亿个令牌的预处理子集组成。这是一个理解很多语言和语言所描述的东西的模型。下一步是微调这个模型,并进行迁移学习,以创建一个新的语言模型,它特别擅长预测电影评论的下一个词。

语言模型微调
这是训练的第一阶段,我们使用预训练的语言模型权重,并用 IMDb 电影评论的训练数据对其进行微调。当我们创建一个学习者时,我们必须传递两件事:
- 数据:我们的语言模型数据
(data_lm) - 预训练模型:这里,预训练模型是 Wikitext 103 模型,将从 fastai 为您下载。
# Language model
**learner = language_model_learner(data_lm, pretrained_model=URLs.WT103_1, drop_mult=0.5)**
drop_mult,超参数,用于正则化,设置漏失量。如果模型过度拟合,则增加它,如果拟合不足,则可以减少该数字。
如何在我们的影评数据上对预训练好的模型进行微调?学习率超参数是训练模型最重要的参数之一。Fast.ai 提供了一个方便的实用程序(learn.lr_find)来搜索一系列学习率,以找到最适合我们数据集的学习率。学习率查找器将在每次小批量后增加学习率。最终,学习率太高,损失会变得更严重。现在看看学习率与损失的关系图,确定最低点(下图中大约在1e-1附近),然后返回一个数量级,选择它作为学习率(大约在1e-2附近)。

训练模型:
我们使用fit_one_cycle.以学习速率1e-2开始训练模型

fast.ai 库使用深度学习研究的最新技术, 单周期学习 来自最近的一篇论文,结果证明比以前的任何方法都更准确、更快。第一个参数“1”是纪元运行次数。仅运行一个时期后,我们就获得了 29%的准确度。
它训练了最后几层,基本上保持了模型的大部分原样。但是我们真正想要的是训练整个模型。通常在我们微调了最后几层之后,我们要做的下一件事就是unfreeze(解冻整个模型进行训练)并训练整个模型。
**learn.unfreeze()
learn.fit_one_cycle(1, 1e-3)****epoch train_loss valid_loss accuracy
1 3.897383 3.977569 0.302463**
准确度= 0.3 意味着该模型在大约三分之一的时间内正确猜测电影评论的下一个单词。这听起来是一个相当高的数字。所以这是一个好迹象,表明我的语言模型做得相当好。
用语言模型预测
为了评估我们的语言模型,我们现在可以运行learn.predict并传入一个句子的开头,指定我们希望它猜测的单词数。

这是相当不错的回答,看起来像是正确的语法。在微调之后,我们得到了一个善于理解电影评论的模型,我们可以通过迁移学习对其进行微调,以将电影评论分为正面或负面。让我们保存模型的编码,以便稍后用于分类。
**learn.save_encoder('fine_enc')**
模型中能够理解句子的部分称为编码器。所以我们保存它,以便以后在分类阶段使用。
创建分类器
现在我们准备创建我们的分类器。第一步,创建一个数据串,从语言模型中传递词汇,确保这个数据串有完全相同的词汇。要使用的批量大小bs取决于您可用的 GPU 内存,对于 bs=64 左右的 16GB GPU 将工作良好。你可以找到任何适合你的卡批量,并相应地使用它。
# Classifier model data
**data_clas = TextClasDataBunch.from_df('./', train_df=df_trn, valid_df=df_val, vocab=data_lm.train_ds.vocab, bs=32)**
最后,我们将创建一个文本分类器学习器。载入我们的预训练模型,我们之前保存的编码部分‘fine_enc’。
# Classifier
**classifier = text_classifier_learner(data_clas, drop_mult=0.5)
classifier.load_encoder('fine_enc')**
同样,我们遵循相同的过程来找到学习率并训练模型。

2e-2 附近的学习率似乎是正确的,因此让我们训练分类器:

哇 85%的准确率在 16 分钟的训练和只使用 5K 训练和 3K 验证样本。这就是迁移学习的力量。
损失图:让我们在训练模型时绘制损失图:

损失曲线似乎平稳下降,尚未达到饱和点。fastai 计算损失的指数加权移动平均线,从而使这些图表更容易阅读(通过使曲线更平滑),同时它可能比它们应该在的地方落后一两批。
深度学习超参数调整技术
让我们来理解 fast.ai 在如此令人印象深刻的结果下使用的技术。
区别学习率:从一层到另一层,对不同的层应用不同的学习率。在拟合模型时,您可以传递一个学习率列表,该列表将对每个层组应用不同的学习率。使用已调用split的[Learner](https://docs.fast.ai/basic_train.html#Learner)时,您可以通过四种方式设置超参数:
param = [val1, val2 ..., valn](n =层组数)param = valparam = slice(start,end)param = slice(end)
如果我们选择在方式 1 中设置它,我们必须指定一些值,这些值正好等于图层组的数量。如果我们选择在方式 2 中设置它,选择的值将对所有层组重复。如果你通过了slice(start,end)那么第一组的学习率是start,最后一组是end,剩下的是平均分配。
如果你仅仅通过了slice(end),那么最后一组的学习率就是end,其他所有组都是end/10。例如(对于我们有 3 个层组的学员):
**learn.lr_range(slice(1e-5,1e-3)), learn.lr_range(slice(1e-3))****(array([1.e-05, 1.e-04, 1.e-03]), array([0.0001, 0.0001, 0.001 ]))**
切片的底部和切片的顶部是模型的最低层学习速度与模型的最高层学习速度之间的差异。随着你从一层到另一层,我们降低了学习速度。最低级别被给予较小的学习速率,以便不太干扰权重。
适合一个周期
什么是 fit_one_cycle()?就是一个周期的学习率,开始低,上去,再下来。让我们使用plot_lr绘制每批的学习率

left: learning rate one cycle, right:momentum for one cycle
当我们调用 fit_one_cycle 时,我们实际上是在传递一个最大的学习速率。左侧图显示了学习率变化与批次的关系。学习开始很慢,大约一半的时间增加,然后大约一半的时间减少。当你接近最终答案的时候,你需要调整你的学习速度来磨练它。这背后的动机是,在学习过程中,当学习率较高时,学习率作为正则化方法工作,并防止网络过拟合。这有助于网络避开陡峭的损耗区域,更好地获得平坦的最小值。请参考 Leslie smith 的这篇论文,其中详细讨论了神经网络超参数调整,您可以在 fastai 中找到这些想法的大部分。
动力
还有一个说法(moms=(0.8,0.7) )﹣momentums 等于 0.8,0.7。基本上对于训练递归神经网络(RNNs)来说,它确实有助于稍微降低动量。上面右边是动量图。每次我们的学习率小,我们的冲劲就大。这是为什么呢?因为随着你学习的速度越来越小,但你一直朝着同一个方向前进,你还不如走得更快(更高的动力)。但是由于你学习的学习率很高,但是你一直朝着同一个方向前进,你可能会超过目标,所以势头应该放缓。这一招可以帮你训练快 10 倍。
进一步微调:
为了进一步提高准确性,fast.ai 提供了一些更多的技巧;freeze_to。不要解冻整个东西,而是一次解冻一层。下面的方法效果很好,给出了令人难以置信的结果。
- 解冻最后两层
freeze_to(-2),多训练一点 - 解冻下一层
freeze_to(-3),多训练一点 - 解冻整个东西
unfreeze(),多训练它一点点

我们达到了 90%的准确率。 训练损失仍然高于验证损失,因此我们还没有过度拟合 ,仍然有通过运行更多纪元来提高准确性的空间。
混淆矩阵
在分类问题中,使用一种叫做混淆矩阵的东西是非常有用的,它可以显示每个标签被正确预测了多少次。混淆矩阵是总结分类算法性能的好方法。
我们使用*ClassificationInterpretation*类来为我们做这项工作。

让我们使用我们的分类器来预测一些电影评论:

这被预测为' 0 ',负面评论。太棒了。!!
我们之前使用经典的机器学习方法和对 IMDb 电影评论进行了情感分类,然后使用单词嵌入方法和。使用 fast.ai 的语言建模方法是我见过的最简单也是最强大的工具。该库提供了非常易于使用的方法,只需几行代码,您就可以获得最先进的结果。请参考 jupyter 笔记本这里。
结论
我们简要讨论了迁移学习在 NLP 问题中的应用。我们详细探讨了 fast.ai 库和不同的超参数调优技术。我们创建了一个语言模型,然后将其应用于文本分类问题。我希望你喜欢这篇文章,并学到一些新的有用的东西。
感谢您的阅读。
参考资料:
[1]http://ruder.io/nlp-imagenet/
https://docs.fast.ai/text.html
相关职位
[1]https://towards data science . com/transfer-learning-946518 f 95666
[3]https://blog.floydhub.com/ten-techniques-from-fast-ai/
机器学习与新闻

发生了一些事情。只有一件事。但是如果你在网上关注新闻,你会发现对这一事件的描述如此不同,你想知道实际上发生了什么是情有可原的。有了机器学习,我们可以为此开发一个应用程序。
【本文中的工作随后被应用于金融市场。这个项目在这里讨论过: 阅读市场——机器学习与金融新闻 。】
最近,我花了几个月的时间将自然语言处理(NLP)技术应用于一个大型新闻故事语料库。我的目标是找到一种方法来识别报道同一事件的新闻文章,然后评估这些文章,以了解媒体报道的一致性或均衡性。
最终,我提出了对个别文章和总体报道的评分。这些分数可用于多种目的:
- 在一个比我们的世界更乌托邦的世界里,它们将被集成到一个新闻阅读应用程序中,比如脸书。阅读新闻文章的用户将被呈现一个分数,该分数显示这篇文章在覆盖该故事的文章系列中的位置。然后可以引导他们阅读其他文章,以便对事件有更全面的了解。
- 在政治上,能够在所有媒体上跟踪一篇文章,并衡量情绪和共识,可能是跟踪民意和微调信息的有用工具。
- 在金融市场,衡量共识/分歧,而不仅仅是不同新闻来源的情绪,可能会成为交易决策的有用信号。
该解决方案是用 Python 构建的,需要结合 NLP 的许多工具。在最高级别上,问题可以分为主题挖掘(在 TF-IDF 矢量化的基础上使用一种聚类形式)和情感分析(使用谷歌云平台,VADER 斯坦福 CoreNLP)。让 NLP 按预期表现是一门微妙的艺术。在这种情况下,它需要大量的预处理步骤(词汇化、词性过滤、n 元语法等。)和附加库,如 NLTK 和 spaCy。
本报告由两个主要部分组成。第一部分涉及问题的背景——即对媒体和偏见不可避免性的简要回顾。第二部分给出了问题的解决方案,描述了它的各个组成部分。
所以,如果你对问题的背景感兴趣,从第一部分开始。如果你渴望得到答案,向下滚动到第二部分。(如果你非常好奇,可以得到一份更详细的技术报告。完整的代码可以在项目的 GITHUB 库中找到。)
第一部分:问题
媒体通常对一个故事的基本事实达成一致。但是他们可能仍然不同意人们应该如何看待他们。这是因为尽管事实是清楚的,但它们的含义是模糊的——因此两篇文章对同一个故事持完全相反的观点是完全合理的。
这是真的,只要看一看 2016 年 6 月 29 日两家主要出版物关于班加西专家组报告发布的单一新闻报道就可以确定:

Headlines from June 29, 2016
根据我们看到的头条新闻,我们会认为该小组的报告对克林顿来说是好消息,或者是坏消息。
出于几个原因,关于班加西事件的报道非常吸引人。首先:这两个标题并不明显矛盾,但它们显然以非常不同的方式强调了重点。第二:两篇文章的内容没有什么特别的不同——只是标题不同。第三:这两份出版物中的标题后来都被修改了(在付印后),以使其听起来更加平衡。文章的当前版本可以在这里和这里找到。
很容易认为事情没那么糟,因为报纸最终接受了更加中立的报道。但这可能会忽略一个更广泛的问题:很多观点是在 Twitter 的即时舞台上形成的,在那里,这些文章可能会使用它们最初的标题进行推广。他们修改后的化身对公众舆论的影响会更小。
此外,研究表明,读者从阅读文章中获得的情感更多地是由标题而不是内容驱动的。(例如,见心理学家和认知神经科学家乌烈芝·埃克在实验心理学杂志上的工作:应用 这里)
同样值得注意的是,这两份报纸都可以被视为中间偏左。皮尤研究中心的一项研究将《纽约时报》放在比《华盛顿邮报》更靠左的位置。那项研究衡量的是读者,而不是新闻,但在竞争激烈的市场中,有理由相信大多数读者都在看他们认同的新闻。此外,我们看到,即使是这种观点上的微小差异,也会产生完全不同的标题——人们只能想象,如果我们拓宽视野,把所有媒体都包括进来,我们会发现怎样的多样性。
总结这种情况的一个简单方法是,即使主流媒体也以不同的情绪报道同样的事件。因此,确定这些事件对我们读者的意义并不简单。毫无疑问,会有读者满足于自己的偏见和成见被强化。但是也有一些读者希望对世界有一个更平衡的理解——这个项目就是为他们而设的。
第二部分:解决方案
那么,该怎么办呢?从数学上来说,我们可能倾向于认为,要想知道真实的本质,我们必须阅读报道事件的每一篇文章。不知何故,我们会将所有的噪音平均掉,留下一个关于潜在事件及其影响的消息灵通和无偏见的观点。但是有两个问题:
- 不成比例的一部分媒体可能会用一个声音说话,因此噪音不会平均化,以揭示一些真相。
- 无论如何,阅读每一篇发表的文章都需要极大的自律。
这种纪律虽然值得称赞,但并不是实用主义者对现代世界生活的首选方式——在现代世界,不知情的人可能会淹没在信息的海洋中。这位实用主义者知道我们缺乏这一学科,于是开始寻找算法解决方案。
从广义上讲,该算法必须首先从覆盖我们感兴趣的故事的媒体中识别出一组文章。鉴于发表的文章数量庞大,这不是一个微不足道的问题,但完全可以解决。接下来,分析该组文章以确定:
- 它们包含不同观点的程度。
- 其中,在各种观点中,任何特定的文章排名。
有了这些信息,我们可以:
- 了解我们正在阅读的文章是否是从极端视角写的。
- 提出另一篇文章来阅读,这将对故事有更细致入微的理解。
- 对总覆盖率的中立性进行评分。
使聚集
第一步大致对应于聚类。与自然语言处理的许多方面一样,提取有用的含义是一门手艺。在这种情况下,我们只需要为每篇文章准备一组单词,并希望将这些文章归入涵盖相同故事的那些文章中。最终,语料库中的每篇文章都被替换为 TF-IDF 向量,该向量实际上是其相对信息内容的抽象数字表示。(稍后将详细介绍这一点。)如果我们小心我们的预处理和参数校准,那么向量空间中的近邻可以被可靠地判断为属于同一故事的文章。
该游戏变成了执行 NLP 库中的一组预处理步骤之一。其中包括:
- 去除腐败文章 —最起码可以发现语料库中有很多文章是没有帮助的。它们可能是腐败的,它们可能是包含许多故事中的每一个的句子的摘要文章,等等。当然,这些文章不是我们为了更好地理解一个故事而推荐阅读的文章。
- 关注文章的第一部分——一篇新闻文章的结构通常是这样的,前几个句子(lead 或 lede)说明了故事的人、事、原因、时间、地点和方式。包含在文章的这一部分中的术语更可能在报道相同故事的文章之间共享。
- 同义词替换 —一些实体可以用多种方式引用。如果两个相关的文章以不同的方式引用实体,它们就不太可能被正确配对。为了降低这种风险,常见的同义词被联合起来。比如联邦调查局,FBI,F.B.I .都翻译成 FBI。
- 词性限制 —不同的词性在文章的实际主题上传达了不同的信息量。例如,专有名词可能是最重要的,动词将包含一些信息,形容词通常很少。因此,剔除信息较少的词类有助于提高文章分组的鲁棒性。当然,这需要用算法分析文章,给每个单词分配一个角色。
- 词汇化 —矢量化本质上并不理解单词之间的关系。例如,同一个词根可以用不同的时态表达,等等。如此选举,被选举,选举,选举,选举等。可能指的是同一件事。词汇化是用词根替换单词的过程。这具有增加两个相关文章在向量空间中更接近的机会的优点。
- N-grams —连续词被分组,并在矢量化中用作组合词。这样做的目的是利用这样一个事实,即如果两个术语在两篇文章中相邻出现,那么这些文章比它们出现在文章的不同部分更有可能相关。例如,一篇提到希拉里·克林顿会见比尔·盖茨的文章可能会与一篇关于比尔·克林顿的文章配对,除非我们包含了二元模型——希拉里的文章不会包含“比尔·克林顿”,因此不太可能配对。
- 停用词抑制 —这一步简单地删除定义列表中包含的任何过于常见而无法传达有用信息的词。这降低了向量的维数,但是可能不会显著改变聚类,因为这种常见术语的 IDF 分数将非常低。
目的是生成尽可能集中于传达与故事相关的信息的术语的向量,这些术语是最有可能与覆盖相同故事的其他文章共享的术语,而不太可能出现在不同故事的文章中。
这些步骤可以在许多常见的 NLP 库中执行,并取得不同程度的成功,比如 NLTK 和 spAcy。完成后,使用 sklearn 将每篇文章转换成一个 TF-IDF 向量。
TF-IDF 矢量化是一种流行的主题挖掘方法。它用一个向量表示语料库中的每个文档。该向量包含组合字典中每个术语的值。当文档的主题与术语相关时,值本身是高的,否则是低的。因此,出现在许多文档中的单词被认为传达了很少的信息来区分主题。并且在文档中出现多次的单词被认为对于区分主题更有意义。然后,TF-IDF 值实际上是一个术语在文章中出现的次数,以及该术语在所有提供的文档的语料库中具有的主题区分能力的乘积。
如果我们观察 2016 年某一天一组媒体上的新闻文章,我们会发现一系列非常高维的向量。虽然这些高维向量用于我们执行的处理,但为了可视化正在发生的事情,有必要应用一些标准的数学技术,并将它们的值映射到二维的近似值。这给了我们这样一个图表:

Story clusters inferred from news articles of 2016–09–01
图中的每个点对应一篇文章。用颜色编码的聚类中的文章是算法已经确定的关于相同主题的文章。(为了增加可靠性,这种确定需要用一种新的亲和力度量来代替通常的欧几里得距离。详细情况在完整的项目报告中提供。)
请注意中心区域的大量蓝点。这些文章都是报道他们特殊故事的唯一文章。因为它们是故事中唯一的文章,它们的向量包含低 TF-IDF 值,因此它们聚集在图形中心的原点周围。
这种转变的力量令人印象深刻。乍一看,似乎是“Penn State”的一个粉红色点,实际上是来自几乎相同的向量的一系列三个点,只有放大几次才能看到。
快速浏览一下这些文章的开头可以发现,虽然它们属于同一个故事,但它们肯定不是相同的词汇列表。

Related news articles on the Joe Paterno anniversary
委内瑞拉抗议的故事同样包含三篇极其接近的文章:

Related news articles on the Venezuela protests
在这两种情况下,显而易见的是,该算法成功地将主题从数千篇文章中分离出来,聚类在确定哪些文章足够接近以至于可以被指定为报道同一故事方面做得很好。虽然这些文章之间的联系对人的眼睛来说是显而易见的,但是一旦我们后退一步,想想成千上万的新闻文章,每一篇都有一系列的许多单词,每个单词都传达不同程度的信息,那么我们就可以开始看到,为了得出结论,大脑本身一定在做一些非常聪明的处理。
那么,现在我们已经找到了这组文章,我们可以用它做什么呢?
文章排名
为了给文章排序,我们需要找到一个轴来衡量它们。假设文章反映了相同的事件集合,应该可以利用情感分析的工作来进行评估和排名。
这个过程有几个步骤:
- 恢复文章的原始版本(从词条化之前,等等)。
- 将每篇文章转换成一个句子列表(使用 NLTK)。
- 将分析限制在每篇文章的前 n 个句子。(一项全面的网格搜索发现,辨别情绪的最佳值是每篇文章 10 句左右。)
- 计算每篇文章的情感。这是通过用户在斯坦福 CoreNLP、谷歌云平台的 NLP 库和 Vader 的 NTLK 实现之间的选择来完成的。
- 根据每个库的规模的含义,将结果转换为 in -1/+1。
- 进一步调整结果以考虑 NLP 库实际上可以返回全范围值的可能性。对谷歌来说,对数千篇新闻文章的分析表明,合适的比例是除以 0.86。(与其他图书馆相比,这是一个较小的调整,可能反映了每个图书馆都是针对不同类型的数据进行训练/校准的——谷歌是针对最广泛的数据进行训练的。)
- 最后,组成一个故事的文章的经缩放的标准化情感值被作为输入来计算该故事的总覆盖的中立性得分。
中立分数是使用专门为此项目设计的新公式计算的:

这里 count(x,y) 统计从 x 到 y 范围内有情绪的文章数量。
这个概念非常松散地受到维基百科编辑指南的启发,特别是它对“中立观点”的定义,这意味着包括所有可证实的观点,而不过度重视其中任何一个。该公式在项目的完整技术报告中有相当详细的讨论。
第 3 部分:一些结果
处理主观数据的挑战是找到一种客观的方法来验证结果。对于这个项目,基本的方法是获取一个故事的文章,计算每篇文章的分数,然后计算报道的中立性。然后,这些值被排序,并与前述皮尤量表上文章出版商的相对位置相关联(见本报告)。
显然,这不是一个完美的比较——例如,《纽约时报》的专栏文章可能会也可能不会与该报的总体社论倾向保持一致。但如果我们拿一个故事来说,关于特朗普与墨西哥总统会晤的报道,我们会得到以下内容:

结果似乎表明,媒体机构越左倾,对会议的负面报道就越多。布莱巴特的报告最为热情。CNN 在数字上基本保持中立。路透社完全中立。《卫报》与《纽约时报》争夺最负面的报道。
更多案例见技术报告。
第四部分:几点结论
该项目应用了许多不同的概念,试图回答最初的问题“如何找到并提出一篇以不同方式报道同一故事的文章”?可以得出以下结论:
- 将文章聚集成故事看起来效果很好,但是需要扩展测试来验证这种观点。然而,时间和资源总是这类工作的主要制约因素。
- 中立分数做了一些看起来有意义的事情,但需要进一步增强才能变得真正强大。为了真正了解结果的有效性,可能有必要考虑完全不同的测试方法。对问题进行富有想象力的分解可能会产生一个可以交给机器人的任务。
- 追踪一个故事随时间的演变会很有趣。只要对算法稍加修改,这应该是可行的。
我的主要结论是,新闻文章本质上是复杂的——衡量它们的情绪并不简单。相对于潜在故事/事实的情绪来考虑文章的情绪可能是值得的。这可以更清楚地表明报告中的任何偏见。此外,所报告的语音的情感可能需要与文章其余部分的情感区别对待。我们应该考虑一下,未来新闻机构是否有可能以一种游戏比分的方式来撰写文章——也许是通过掩盖领先优势。这也可以通过标记主角的情绪与文章其余部分的情绪明显偏离的情况来规避。
【本文中的观点随后被扩展并应用于金融市场。这里介绍了这个项目: 阅读市场——机器学习与金融新闻 。]
第 5 部分:所有细节
这篇文章很长,但不足以深入细节。对于这一点,以及更多的例子,这里是到技术报告和源代码库的链接的最后一个提示:
机器学习不会取代投资经理
机器学习有可能改变我们的世界,就像大约一个世纪前电力改变了几乎一切一样。但是,很难想象你的职业会受到怎样的影响。所以,让我们考虑一下机器学习对于投资经理的潜力。
更新:我开了一家科技公司。你可以在这里找到更多
实施投资理念
投资需要一种理念作为寻找、评估和选择新投资机会的框架。这些理念使投资经理能够与众不同,从而吸引特定的客户群。
任何投资理念的实施都有两个组成部分。第一步是将论文引入现实世界,通过提出正确的问题来测试、验证和提炼。第二是它的执行力。
这两个因素对于投资的成功都至关重要,但是执行——你买什么,你投资多少,你什么时候做交易——会导致一个好的投资失败或成功。此外,这需要扩大到足够广泛的股票领域,以便基金能够分配足够的资本,为投资者带来正回报。
机器学习给投资经理带来的好处
因此,投资极其复杂。需要对许多内部和外部因素进行深入彻底的分析,以找到符合这一理念并具有显著上升潜力的早期迹象的股票。
然而,用于投资管理的机器学习可以在任何选定理念的时间受限和资源密集型执行阶段提供竞争优势。
通过学习哲学的关键因素和未来价格表现之间的关系,机器学习可以大规模识别候选股票,并通过缩小可行选项来帮助投资者优化他们的研究分析。
机器学习对投资银行的限制是什么?
机器学习并不像它看起来那么抽象,在许多情况下,它只是广泛使用的线性回归的扩展。然而,在处理输入和目标变量之间的关系是非线性的或者问题有许多维度的边缘情况时,机器学习算法比人和线性回归好得多。
然而,机器学习在投资银行业的成功取决于投资经理要求它回答的问题的质量。
例如,机器学习可以识别和预测价格急剧下跌或上涨的早期迹象,以及预测 IBES 分析师估计的准确性。
此外,由于机器学习模型高度灵活,可以提出的可能问题只受到投资经理创造力的限制。
总之,机器学习不会取代投资经理,因为它无法独立思考。然而,随着时间的推移,在投资银行业使用机器学习的个人将取代那些不使用机器学习的人。
为机器学习处理大数据集
每天都会产生超过 25 万亿字节的数据。世界上 90%的数据都是在过去两年产生的。数据的盛行只会越来越大,所以我们需要学习如何处理这样的大数据。
“大数据就像青少年性行为:每个人都在谈论它,没有人真正知道如何去做,每个人都认为其他人都在做,所以每个人都声称自己在做。”—丹·艾瑞里

想象一下,下载一个包含所有已写推文的数据集,或者脸书所有 23 亿人的数据,甚至是互联网上所有网页的数据。如何分析这样的数据集?
这不是一个孤立的问题,只影响最大的科技公司。在当今时代,数据集已经变得超出了大多数计算机的处理能力。我经常处理卫星数据,这些数据很容易就达到 TB 级——太大了,甚至不适合我的计算机硬盘,更不用说在合理的时间内处理这些数据了。以下是一些令人大开眼界的大数据统计数据:
- 每分钟发送超过 1600 万条短信
- 每分钟都有超过 1 亿封垃圾邮件发出
- 每分钟都有超过一百万次的打火
- 每天,超过 10 亿张照片被上传到 Google 相册
存储这些数据是一回事,但如何处理这些数据并开发机器学习算法来处理这些数据呢?在本文中,我们将讨论如何在云上轻松创建可扩展的并行化机器学习平台,以处理大规模数据。
这可以用于研究、商业或非商业目的,并且与开发自己的超级计算机相比,可以以最小的成本完成。
为了在云上开发一个非常健壮和高性能的并行集群(这也可以在本地机器上使用以提高性能),我们将深入研究以下主题:
- 环境设置
- 与 Dask 和 Kubernetes 并行
- Dask 云部署
- AWS 上的云部署示例
这篇文章将基于以下 GitHub 库的内容,可以在这里找到。在云上建立机器学习平台所需的所有命令都可以在 markdown 文件这里中找到。这是基于哈佛大学应用计算科学研究院的一份指导。
环境设置—码头和集装箱
如果你只看了这个帖子的一部分,就让它是这个部分吧。
当人们建立他们的机器学习环境时,通常他们会将所有的东西直接安装在他们的操作系统上。通常情况下,这没什么,然后你试图下载 PyTorch、TensorFlow 或 Keras 之类的东西,所有东西都爆炸了,你花了几个小时在栈溢出上,试图让东西工作。为了你自己,我恳求你不要这样工作。
这个问题通常是由于某些包对其他包的特定版本的依赖性或相互依赖性而产生的。通常,您的工作并不需要这些包中的一半。更合理的做法是从头开始,只安装手头任务所需的版本和依赖项。这将最终节省你的时间和压力。
如果您正在使用 Anaconda,那么将它们分离到隔离的“容器”中是非常容易和有效的,这样它们都可以运行而不会引起问题。这些容器被称为康达环境。Conda 是 Python 的一个包管理器
您可以将这些环境想象成互不知道对方存在的不同计算机。当我创建一个新环境时,我从一张白纸开始,需要再次安装软件包。最重要的是,你不需要两次下载软件包。当你这样做的时候,会创建一个指针,指向你想要安装的软件包的特定版本,这个版本已经下载到你的计算机上了。
这可能看起来毫无意义,除非你以前在你的电脑上有过依赖问题,但是我可以向你保证这是值得了解的。另一个有用的特性是,你可以在一行中安装所有你喜欢的包,只需使用 YAML(。yml)文件。这是一个文件,它告诉环境您想要安装什么包以及需要下载什么依赖项。您不需要编写这个文件,它可以用一行代码从您已经拥有所有必需的包的环境中导出——非常简洁,对吗?所有需要的命令都显示在下面的要点中。
Example of Linux commands to easily create new environments and dependency files.
下面是运行conda env export > environment.yml命令时 YAML 文件的样子。
将事物分成这样的环境还有另一个很好的理由。如果我想得到我正在做的数据分析的可再现的结果,它可能广泛地依赖于不同包的版本以及你正在工作的操作系统。通过创建包含所有依赖项的 environment.yml 文件,别人可以更容易地重现您的结果。
那么我们在创建康达环境的时候做了什么呢?我们基本上把它和我们系统的其他部分隔离开了。然而,如果我们想要在不仅仅是 Python 包的环境中使用额外的东西呢?在这种情况下,我们使用 Docker 来创建容器。
如果您的应用:
- 使用服务器(例如预载数据的数据库服务器),以及
- 你想把这个服务器和它的数据以及你的应用程序和它的 Python 环境分发给其他人(比如一个开发伙伴或者一个客户),
使用 Docker 可以将整个事情“集装箱化”。
在这种情况下,所有这些组件都将封装在 Docker 容器中:
- 应用程序本身,
- 可以运行你的应用程序的 Conda 环境(因此一个兼容的 Python 版本和包),
- 运行应用程序所需的本地服务器或服务(例如:数据库服务器和 web 服务器)

我承认 Docker 和 containers 背后的概念有点混乱。建立 docker 形象不是一件小事。然而,幸运的是,Jupyter 的人为此创造了 repo2docker 。repo2docker 取一个 GitHub 库,自动制作一个 docker 映像,并上传到 docker 映像库给你。这可以用一行代码来完成。
运行上面的代码后,您应该在终端中弹出一些代码,如下所示:
**Copy/paste this URL into your browser when you connect for the first time,
to login with a token:
http://0.0.0.0:36511/?token=f94f8fabb92e22f5bfab116c382b4707fc2cade56ad1ace0**
只需将 URL 复制并粘贴到您的浏览器中,然后您就可以访问您的 docker 图像并开始工作了!你可以在这里阅读更多关于使用 repo2docker 的内容。
另一个真正有用的东西是活页夹。Binder 建立在 repo2docker 的基础上,提供了一种服务,你可以在其中提供一个 GitHub 库,它给你一个工作的 JupyterHub,你可以在其中“发布”你的项目、演示等。通过点击 ReadMe 部分的链接,可以在 binder 上运行与本教程相关的 GitHub 库。
你可以在这里阅读更多关于使用活页夹的信息。
与 Dask 和 Kubernetes 并行
我们花了很长时间才到达本教程的并行化部分,但是前面的步骤是到达这里所必需的。现在让我们开始使用 Dask 和 Kubernetes。
- Dask——Python 中的并行计算库
- Kubernetes - 一个用于自动化应用程序部署、扩展和管理的开源容器编排系统。
Dask 有两个相关部分:
[1]针对气流等计算进行了优化的动态任务调度。
[2]“大数据”集合,如并行(Numpy)数组、(Pandas)数据帧和列表。
Dask 出现只有几年时间,但由于 Python 在机器学习应用中的流行,它的势头正在逐渐增长。Dask 允许对 Python 应用程序进行扩展(1000 核集群),因此它们的处理速度比普通笔记本电脑快得多。
我建议任何对 Dask 感兴趣的人参考 Tom Augspurger(Dask 的主要创建者之一)的 GitHub 知识库,可以在这里找到。
我们已经讨论了 Dask,Kubernetes 在这里起什么作用呢?如果我们在笔记本电脑上运行 Dask,它允许我们一次将代码分发到多个内核,但它不能帮助我们同时在多个系统上运行代码。我们已经在本地运行了。理想情况下,我们希望在云配置的集群上运行,并且我们希望这个集群能够自我修复——也就是说,我们希望我们的代码能够对故障做出响应,并在需要时扩展到更多的机器上。我们需要一个集群管理器。
Kubernetes 是一个集群管理器。我们可以把它想象成集群的操作系统。它提供服务发现、扩展、负载平衡和自我修复。Kubernetes 认为应用程序是无状态的,可以从一台机器移动到另一台机器,以便更好地利用资源。有一个运行集群操作系统的控制主节点和执行大部分工作的工作节点。如果一个节点(与集群相关的计算机)失去连接或中断,主节点会将工作分配给新的人,就像你停止工作时你的老板会做的那样。
主节点和工作节点由允许其执行任务的几个软件组成。它变得相当复杂,所以我将快速给出一个高层次的概述。
主节点:
- API 服务器,主节点和用户之间的通信(使用 kubectl)
- 调度程序,为每个应用程序分配一个工作节点
- 控制器管理器执行集群级功能,如复制组件、跟踪工作节点、处理节点故障
- etcd 是一个可靠的分布式数据存储,它持久地存储集群配置(在给定时间哪个工作节点在做什么)。
工人节点:
- 码头工人,运行你的集装箱
- 将应用程序的组件打包成一个或多个 docker 映像,并将它们推送到注册表中
- Kubelet,它与 API 服务器对话并管理其节点上的容器
- kube-proxy,它在应用程序组件之间负载平衡网络流量

The configuration of a Kubernetes cluster.
做所有这些都很棒,但是除非我们有 100 台计算机可以利用 Kubernetes 和 Dask 提供给我们的能力,否则这并没有特别大的帮助。
进入云端。
Dask 云部署
如果你想用 Python 运行 Dask 来加速你的机器学习代码,Kubernetes 是推荐的集群管理器。这可以在您的本地机器上使用 Minikube 完成,也可以在 3 个主要的云提供商(Microsoft Azure、Google Compute Cloud 或 Amazon Web Services)上完成。
你可能对云计算很熟悉,因为现在它几乎无处不在。现在,公司将所有计算基础设施都放在云上是非常常见的,因为这可以减少他们在计算设备上的资本支出,并将其转移到运营支出,需要更少的维护,还可以显著降低运营成本。除非您处理的是机密信息或者有非常严格的法规要求,否则您可以在云上运行。
使用云允许您利用几台机器的集体性能来执行相同的任务。例如,如果您正在神经网络上执行超参数优化,并且需要重新运行模型 10,000 次以获得最佳参数选择(这是一个相当常见的问题),那么如果需要 2 周时间,在一台计算机上运行它将是没有意义的。如果你能在 100 台计算机上运行同样的模型,你可能会在几个小时内完成任务。
我希望我已经很好地解释了为什么您应该使用云,但是请注意,如果您使用非常强大的机器(特别是如果您在使用它们之后没有关闭它们,那么它会变得非常昂贵!)
要在云上设置环境,您必须执行以下操作:
- 建立一个 Kubernetes 集群
- 设置Helm(Kubernetes 的包管理器,它就像是 Kubernetes 集群的自制程序)
- 安装 Dask 。
首先运行以下命令
**helm repo update**
然后
**helm install stable/dask**
详见https://docs.dask.org/en/latest/setup/kubernetes-helm.html。
云上深度学习
有几个有用的工具可用于用 Kubernetes 和 Dask 构建深度学习算法。例如,TensorFlow 可以使用 kubeflow 的tf.distributed放到云上。由于不同的模型可以在每个工作节点上运行,因此并行性可以在网格优化过程中得到广泛应用。例子可以在 GitHub 库这里找到。
你用什么?
对于我自己的研究(我是一名环境科学家)和我的咨询工作(机器学习顾问),我经常使用 JupyterHub,一个在哈佛的超级计算机 Odyssey 上带有 Dask 的 Kubernetes 集群,或者我将在 AWS 上运行相同的基础设施(对 Azure 或谷歌云没有真正的偏见,我只是先学会如何使用 AWS)。
AWS 上的云部署示例
在这一节中,我将介绍在 AWS 上运行 Dask 的 Kubernetes 集群的设置。您需要做的第一件事是在 AWS 上设置一个帐户,除非您已经有了一个帐户,否则您将无法运行以下代码行。
首先,我们下载 AWS 命令行界面,并用 AWS 提供的私钥对其进行配置。然后,我们使用 brew 命令为 Kubernetes 安装亚马逊的弹性容器服务(EKS)。
**pip install awscli
aws configure
brew tap weaveworks/tap
brew install weaveworks/tap/eksctl**
创建一个 Kubernetes 集群现在简单得可笑,我们只需要运行一个命令,但是您应该指定集群名称、节点数量和您所在的地区(在这个例子中,我在波士顿,所以我选择了us-east-1)然后运行这个命令。
**eksctl create cluster --name=cluster-1 --nodes=4 --region=us-east-1**
现在,我们必须使用以下命令配置集群:
**kubectl get nodes
kubectl --namespace kube-system create sa tiller
kubectl create clusterrolebinding tiller --clusterrole cluster-admin --serviceaccount=kube-system:tiller**
现在我们在集群上设置 Helm 和 Dask
**helm init --service-account tiller**
等待两分钟完成,然后我们可以安装 Dask。
**helm version
helm repo update
helm install stable/dask
helm status agile-newt
helm list
helm upgrade agile-newt stable/dask -f config.yaml
helm status agile-newt**
更多的 Kubernetes 命令。
**kubectl get pods
kubectl get services**
要了解更多细节和 shell,您需要一个类似这样的命令。你们确切的豆荚名称会有所不同。
**kubectl get pod agile-newt-dask-jupyter-54f86bfdd7-jdb5p
kubectl exec -it agile-newt-dask-jupyter-54f86bfdd7-jdb5p -- /bin/bash**
一旦您进入集群,您就可以克隆 GitHub 存储库并观看 Dask 运行了!
卡格尔·罗斯曼竞赛
我建议一旦你已经启动并运行了 Dask cloud 部署,你就试着运行一下rossman_kaggle.ipynb。这是来自 Kaggle Rossman 竞赛的示例代码,它允许用户使用他们想要的任何数据来尝试和预测欧洲的药店销售。比赛于 2015 年举行。
本笔记本中的步骤向您介绍了如何为多层感知器设置编码环境,以便将其应用于并行集群,然后执行超参数优化。这段代码中的所有步骤都被分解成函数,然后在 sklearn 管道中运行(这是运行大型机器学习程序的推荐方式)。
存储库中还有其他几个例子,您可以在并行集群上运行并使用它们。此外,可以随意克隆存储库并随意修改。
从哪里可以了解更多信息?
要了解有关 Dask 的更多信息,请查看以下链接:
Dask 教程。在 GitHub 上创建一个帐户,为 dask/dask-tutorial 开发做贡献。
github.com](https://github.com/dask/dask-tutorial) [## Dask - Dask 1.1.4 文档
在内部,Dask 以一种简单的格式对算法进行编码,包括 Python 字典、元组和函数。此图表格式…
docs.dask.org](https://docs.dask.org/en/latest/)
要通过 Kubernetes 了解有关 Dask 的更多信息:
dask 的本地 Kubernetes 集成。创建一个帐户,为 dask/dask-kubernetes 的发展做出贡献
github.com](https://github.com/dask/dask-kubernetes) [## Dask Kubernetes-Dask Kubernetes 0 . 7 . 0 文档
目前,它被设计为从 Kubernetes 集群上的一个 pod 上运行,该集群拥有启动其他 pod 的权限…
kubernetes.dask.org](http://kubernetes.dask.org/en/latest/)
要了解更多关于 Helm 的信息:
[## Kubernetes 和 Helm - Dask 1.1.4 文档
如果不是这样,那么您可以考虑在一个常见的云提供商上建立一个 Kubernetes 集群…
docs.dask.org](http://docs.dask.org/en/latest/setup/kubernetes-helm.html)
如果您正在努力完成上述任何步骤,有多个其他演练可以更详细地介绍具体细节:
[## 将 Dask 和 Jupyter 添加到 Kubernetes 集群
在本文中,我们将在运行于 AWS 上的 Kubernetes 集群上设置 Dask 和 Jupyter。如果你没有…
ramhiser.com](https://ramhiser.com/post/2018-05-28-adding-dask-and-jupyter-to-kubernetes-cluster/) [## 在 Jetstream 上的 JupyterHub 旁边的 Kubernetes 中设置私有 dask 集群| Andrea Zonca 的博客
在本帖中,我们将利用 Pangeo 社区提供的软件让 Jupyterhub 的每个用户…
zonca.github.io](https://zonca.github.io/2018/06/private-dask-kubernetes-jetstream.html)
要在 Google Cloud 上设置集群(遗憾的是找不到微软 Azure 的集群),请查看以下链接:
实验性 docker-compose 设置,用于引导分布在 docker-swarm 集群上的程序。-ogrisel/docker-分布式
github.com](https://github.com/ogrisel/docker-distributed) [## 哈默实验室/dask-分布在库伯内特河畔
使用 kubernetes-hammer lab/dask-distributed-on-kubernetes 在 google 容器引擎上部署 dask-distributed
github.com](https://github.com/hammerlab/dask-distributed-on-kubernetes/)
现在,您应该有一个工作的并行集群,可以在其上对大数据或大计算任务执行机器学习!
感谢阅读!🙏****
使用 SQL 的机器学习
这篇文章是关于 SQL 的机器学习。构建/运行数据保留在数据库中的机器学习模型是有意义的。如何开始的分步信息。

Oracle HQ. Source: Pixabay
Python(以及即将推出的带有 TensorFlow.js 的 JavaScript)是机器学习的主导语言。SQL 呢?有一种在 SQL 中建立/运行机器学习模型的方法。在数据库附近运行模型训练可能会有好处,因为数据会保存在数据库中。借助 SQL,我们可以利用现成的强大数据分析功能,运行算法,而无需向外部获取数据(从性能角度来看,这可能是一项昂贵的操作,尤其是对于大型数据集)。这篇文章将描述如何使用 SQL 在数据库中进行机器学习。
我将使用运行在 Oracle 云自由层的 Oracle 自治数据库。Oracle DB 提供了对机器学习的现成支持。最近,Oracle 推出了 Oracle 云免费层,其中包括数据库。这意味着我们可以免费运行它,也可以用于生产。
设置
进入 Oracle 云控制台后,转到自治数据仓库,在那里您可以创建包含 ML 功能的始终免费的数据库实例:

为了能够访问 ML 环境,请确保设置 ML 用户。为此,转到云控制台中的数据库实例并选择服务控制台选项:

然后转到管理部分,选择管理 Oracle ML 用户选项:

在这里,您可以创建一个新用户(我们将使用该用户登录 Oracle ML notebook)。这是数据库用户,这意味着将创建具有相同名称的数据库模式,我们可以使用相同的凭据直接登录数据库:

为了能够通过 SQL Developer 或另一个客户端直接登录(有用,当需要进行数据预处理时),选择数据库连接选项并下载客户端凭证:

用 SQL Developer 连接到 DB,创建表 PIMA_INDIANS_DIABETES(在此阅读更多关于 Pima Indians 糖尿病数据集)。通过运行我的 GitHub repo 中的 SQL 脚本为这篇文章填充数据:

让我们打开 Oracle ML 笔记本。返回 Oracle Cloud console for Autonomous Data Warehouse 并选择开发部分。在此部分,单击 Oracle ML SQL 笔记本:

下一步,它将要求输入用户名/密码。在这里,您应该提供与之前几个步骤中创建的相同的 ML 用户信息(我使用的是用户 REDSAM):

机器学习
甲骨文机器学习主页。点击笔记本,这将导航到创建新笔记本的表格:

创建新笔记本—皮马印第安人糖尿病:

转到笔记本。在 notebook 中,您可以访问相同的数据库模式,就像您从数据库客户端连接并上传数据的模式一样。从技术上讲,您可以直接从 SQL 客户端构建 ML 模型。Oracle ML notebook 提供了更好的用户体验。
在第一步中,让我们从表中获取数据,以确保我们可以访问 DB 模式并查看数据:

接下来,为测试和训练数据集创建 DB 表,您可以从主表直接将数据提取到这些表中:

在运行训练和构建模型之前,建议清理以前训练的模型(如果有):

在这里,我们使用决策树算法来训练模型。指向包含训练数据的表,运行 PL/SQL 函数— CREATE_MODEL ,模型将在后台为您构建:

模型元数据存储在生成的数据库表中:

将预测列添加到测试表中,这是存储预测结果的位置:

使用训练好的模型运行预测函数,结果将存储在预测列中:

我们可以通过将预测值与测试数据集中的实际值进行比较来计算预测精度:

混淆矩阵—这有助于快速了解模型质量:

Oracle 机器学习 SQL 笔记本和数据在我的 GitHub repo 上有。
R 中“糖尿病”数据集的机器学习
用 KNN、逻辑回归和决策树进行分类

受 Susan Li 关于在 Python 中应用基本机器学习技术的文章的启发,我决定在 r 中实现相同的技术。此外,我希望对为什么每种方法都有用以及它们如何相互比较进行一些解释。
以下所有分析均使用 Pima Indians 糖尿病数据集,可通过以下方式在 R 中访问该数据集:
install.packages("mlbench")
library(mlbench)
data(PimaIndiansDiabetes)
# Some of the exact variable names may vary from my subsequent code
总体而言,该数据集由 9 个变量的 768 个观察值组成:8 个变量将用作模型预测值(怀孕次数、血糖浓度、舒张压(mm Hg)、三头肌皮褶厚度(mm)、2 小时血清胰岛素测量值、体重指数、糖尿病谱系函数和年龄)和 1 个结果变量(患者是否患有糖尿病)。
k 近邻
我们将首先应用 k-最近邻法,根据患者与其他患者的相似性对患者进行分类。对于这种方法(以及所有后续方法),我们将从将数据集分为“训练”和“测试”集开始。我们将基于训练集上预测器和结果之间的关系来构建我们的模型,然后使用模型的规范来预测测试集上的结果。然后,我们可以将我们的预测结果与测试集的实际糖尿病状态进行比较,从而为我们提供模型准确性的度量。在我的练习中,我将使用caTools包中的sample.split函数。

An illustration of how the number of neighbors affects the class of a test case. Using the 3 nearest neighbors (solid line) results in a different class than using the 5 nearest neighbors (dashed line). By Antti Ajanki AnAj — [https://commons.wikimedia.org/w/index.php?curid=2170282](http://By Antti Ajanki AnAj - Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=2170282)
对于 k-最近邻,我们通过将每个测试案例与训练集中的“最近邻”进行比较来计算该案例的结果。分配的结果取决于您决定查看这些邻居中的多少个;三个最近邻的多数类可能不同于五个最近邻的多数类(见左图)。
为了确保我们使用一个给出更好模型性能的数字来表示 k,我进行了两部分交叉验证。首先,我将 k 的可能值从 2 变为 10;第二,我重复了 100 次将数据分割成训练集和测试集,以确保对每个 k 的模型性能的稳健估计。我使用了class包中的knn函数,并在测试集上计算了每个折叠的模型精度。
all_test_accuracies_knn <- matrix(nrow=100,ncol=9)
for (split_number in c(1:100)){
train_ind <- sample.split(diabetes$Pregnancies,SplitRatio = 0.8)
test_ind <- !train_ind
neighbors <- c(2:10)
accuracies <- matrix(nrow=1, ncol=9)
for (n_neighbors in neighbors){
knn_fit <- knn(diabetes[train_ind,],diabetes[test_ind,],diabetes$Outcome[train_ind],k=n_neighbors)
cm <- table(Actual = diabetes$Outcome[test_ind],Predicted = knn_fit)
accuracy <- sum(diag(cm))/sum(test_ind)
accuracies[n_neighbors-1] <- accuracy
}
all_test_accuracies_knn[split_number,] <- accuracies
}

KNN model performance accuracy for varying values of k. Black line indicates mean of all 100 folds for each value of k; grey ribbon indicates standard deviation.
从这个分析中,我们可以看到 k-最近邻对于稍微更大的 k,值表现得更好,性能达到大约 73%的最大分类准确度。尽管根据确切的数据分割仍然存在一些差异,但是使用 9 或 10 个邻居似乎可以在测试集上产生相当稳定的模型估计。
逻辑回归
接下来,我们将应用机器学习工具集的另一个基本工具:回归。对于这个数据集,我们预测二元结果(糖尿病诊断),我们使用逻辑回归而不是线性回归(预测连续变量)。同样,我将通过反复将数据分成不同的训练集和测试集来交叉验证逻辑回归模型。
all_test_accuracies_logistic <- matrix(nrow=100,ncol=1)for (split_number in c(1:100)){
train_ind <- sample.split(diabetes$Pregnancies,SplitRatio = 0.8)
test_ind <- !train_ind
logit_fit <- glm(Outcome ~ ., data=diabetes[train_ind,], family="binomial")
p <- predict(logit_fit,diabetes[test_ind,],family="binomial")
probs <- exp(p)/(1+exp(p))
test_outcomes <- probs>0.5
cm <- table(Actual = diabetes$Outcome[test_ind],Predicted = test_outcomes)
accuracy <- sum(diag(cm))/sum(test_ind)
all_test_accuracies_logistic[split_number] <- accuracy
}

Histogram of model accuracy for each of the 100 folds of logistic regression. Mean (red) +- standard deviations (blue) for the KNN approach with k=9 is also shown.
在所有折叠中,我们实现了 77%的平均模型准确性,性能范围从 67–84%不等,具体取决于准确的训练-测试划分。在这个数据集上,逻辑回归似乎比 k-最近邻更准确,即使选择了最优的 k (将填充分布与显示 KNN 近似最优分布的垂直线进行比较)。
决策图表
遵循与选择逻辑回归而不是线性回归相同的逻辑,我们将构建一个分类树而不是回归树。决策树构建了数据分离的“节点”,最终以“叶子”结束,这些叶子给出了模型的指定类别。在这里,我再次实现了 100 倍的训练测试分裂,然后将每个预测值分配给一个输出矩阵,以比较各倍之间的变量重要性。
all_dtree_importance <- matrix(nrow=8,ncol=100)
bucketsize <- 10
for (split_number in c(1:100)){
train_ind <- sample.split(diabetes$Pregnancies,SplitRatio = 0.8)
test_ind <- !train_ind tree <- rpart(as.factor(Outcome) ~ ., data = diabetes[train_ind,],minbucket=bucketsize, model=TRUE)importance <- t(tree$variable.importance)
importance <- importance/sum(importance)
all_dtree_importance[1,split_number] <- importance[,"Glucose"]
all_dtree_importance[2,split_number] <- importance[,"BMI"]
all_dtree_importance[3,split_number] <- importance[,"Age"]
all_dtree_importance[4,split_number] <- importance[,"Insulin"]
all_dtree_importance[5,split_number] <- importance[,"DiabetesPedigreeFunction"]
all_dtree_importance[6,split_number] <- importance[,"Pregnancies"]
all_dtree_importance[7,split_number] <- importance[,"BloodPressure"]
all_dtree_importance[8,split_number] <- importance[,"SkinThickness"]
}
该数据集的示例树如下所示:

One of the classification trees for the diabetes data set. At each leaf, the top number and leaf color indicates the assigned class (blue: 0, green: 1). The overall importance of blood glucose levels, BMI, and age are all readily apparent, one of the advantages of classification trees over other methods.

Mean importance of each predictor (% of model) +- standard deviation, across 100 splits of the data.
在决策树中,血糖始终是树中最重要的变量(>模型的 40%),其次是身体质量指数和年龄,占 10-15%,其余变量的贡献小于 10%。总的来说,决策树模型的准确率在 74–75%左右。
随机森林
与上面使用的简单决策树相反,随机森林聚集了多个去相关的决策树,以便产生预测。当构建每组决策树时,在每次分裂时,仅选择预测器的样本作为分裂候选,而不是允许树从所有可能的预测器中进行选择。因此,每个单独的树不太可能选择与其他树相同的分割。在我在这里使用的randomForest函数的情况下,每次分割时可以选择的预测值的默认数量是floor(ncol(x)/3),或者 2。
for (split_number in c(1:100)){
train_ind <- sample.split(diabetes$Pregnancies,SplitRatio = 0.8)
test_ind <- !train_ind rf <- randomForest(as.factor(Outcome) ~ ., data = diabetes[train_ind,],ntree=100)
train_accuracy <- sum(diag(rf$confusion))/sum(train_ind)
cm <- table(predict(rf,diabetes[test_ind,]),diabetes$Outcome[test_ind])
test_accuracy <- sum(diag(cm))/sum(test_ind)
all_train_accuracies_rf[split_number] <- train_accuracy
all_test_accuracies_rf[split_number] <- test_accuracy
importance <- rf$importance/sum(rf$importance)
all_importances_rf[split_number,1] <- importance["Glucose",]
all_importances_rf[split_number,2] <- importance["BMI",]
all_importances_rf[split_number,3] <- importance["Age",]
all_importances_rf[split_number,4] <- importance["Insulin",]
all_importances_rf[split_number,5] <- importance["DiabetesPedigreeFunction",]
all_importances_rf[split_number,6] <- importance["Pregnancies",]
all_importances_rf[split_number,7] <- importance["BloodPressure",]
all_importances_rf[split_number,8] <- importance["SkinThickness",]
}

Three examples of trees created using the random forest algorithm.

与上面的简单树分类方法相比,在随机森林模型中,每个变量的重要性分布更加均匀。虽然葡萄糖仍然是模型中最重要的因素,但在随机森林中,它仅占模型的 25%。这是直观的,因为随机森林改进决策树的方式之一是通过使每个树不太可能使用相同的(最强的)预测变量(在这种情况下,葡萄糖水平)作为树中的第一次分裂来使袋装树彼此去相关。
总的来说,这种方法相对于交叉验证的决策树也只提供了一点点(但可能仍然有意义)的改进。简单决策树的平均准确率为 74%,范围为 65–82%,而随机森林模型的平均准确率为 76%,范围为 68–82%。因此,正如预期的那样,随机森林方法产生了更健壮、不变的结果。
梯度推进
最后,我们将对数据采用另一种集成学习方法:梯度推进。通常,梯度推进指的是迭代地将模型拟合到先前模型的残差,从而提高整体模型拟合。梯度增强通过连续地将更复杂的树逐渐拟合到数据,并使用前一棵树的残差作为后续树的指导,来“增强”分类的决策树模型。这里的梯度是指通过梯度下降来解决最小化的问题,也就是找到你当前值处的梯度,沿着梯度递减的方向。
install.packages("gbm")
library(gbm)all_gb_accuracies <- matrix(nrow=100)
all_gb_relative_inf <- matrix(nrow=100,ncol=8)
for (split_number in c(1:100)){
train_ind <- sample.split(diabetes$Pregnancies,SplitRatio = 0.8)
test_ind <- !train_ind gb <- gbm(Outcome ~ ., data = diabetes[train_ind,], distribution = "bernoulli")
vals <- predict.gbm(gb, diabetes[test_ind,],n.trees=100)
probs <- exp(vals)/(1+exp(vals))
class1 <- probs>0.5
cm <- table(class1,diabetes$Outcome[test_ind])
gb_accuracy <- sum(diag(cm))/sum(test_ind)
all_gb_accuracies[split_number] <- gb_accuracy
s <- summary.gbm(gb,plotit = FALSE)
all_gb_relative_inf[split_number,1] <- s$rel.inf[s$var=="Glucose"]
all_gb_relative_inf[split_number,2] <- s$rel.inf[s$var=="BMI"]
all_gb_relative_inf[split_number,3] <- s$rel.inf[s$var=="Age"]
all_gb_relative_inf[split_number,4] <- s$rel.inf[s$var=="Insulin"]
all_gb_relative_inf[split_number,5] <- s$rel.inf[s$var=="DiabetesPedigreeFunction"]
all_gb_relative_inf[split_number,6] <- s$rel.inf[s$var=="Pregnancies"]
all_gb_relative_inf[split_number,7] <- s$rel.inf[s$var=="BloodPressure"]
all_gb_relative_inf[split_number,8] <- s$rel.inf[s$var=="SkinThickness"]
}

我们再次看到,葡萄糖水平是决定糖尿病诊断的压倒性主要因素。在这种情况下,最不重要的变量(胰岛素、血压和皮肤厚度)被最小化,甚至比以前的模型更大。总体而言,梯度增强模型的表现略好于随机森林,平均分类准确率为 76%,范围为 68–83 %,相对于随机森林总体提高了约 0.6%。
机器思维、运输和设计的未来
秋千
在我们这个快速发展的以数字为中心的世界里,我经常陷入一个陷阱,把设计当成最新的光鲜亮丽的应用程序或闪亮的消费电子产品。人们很容易忽略这样一个事实:设计和人类一样古老;我们作为一个物种的古老而固有的一部分。
简单地说,设计是对思想、材料或技术的成功安排,以朝着一个目标前进。我们都这样做,设计我们的时间表,家庭和假期。我们有意识和无意识地设计,经历迭代和自我批评,朝着我们的目标不断优化。
在帮助企业的过程中,我经常被问到“什么是好的设计?”可以理解的是,有必要对其进行量化、衡量并确立价值。随着时间的推移,我开始认为好的设计展示了四种不同程度的可量化的品质。我喜欢用不起眼的挥杆作为这些品质多功能性的例子。

Source: https://en.wikipedia.org/wiki/File:MoSchaukel.jpg
- 好的设计是永恒的。我想任何时代的人看到一个秋千,都会知道它到底是干什么的。设计本身不需要改变就能继续有效。这是基础技术和它们所采用的形式的完美结合。
- 好的设计是功能性的。没有人怀疑秋千的功能。它显然实现了让人类一次又一次挑战重力的惊人目标。太神奇了。
- 好的设计就是美。可能是最不可量化的。漂亮的设计往往是每个人都认同的东西,而没有说服力。我发现大多数秋千都很漂亮。如果你仔细想想,我想你会同意的。
- 好的设计是个人的。这里的挥杆很出色。这个座位几乎适合任何人。您可以改变链条的长度来调整高度。感觉它就在你身边。我们围绕好的设计创造记忆和情感。
圆桌会议
下一个适时的话题是设计过程。我们如何设计?我们如何一起设计?
随着设计思维成为商业培训的主流部分,设计过程显然变得流行起来。敏捷和精益是设计思维的近亲——导致这种感觉,即理解我们的客户或用户,然后合作解决问题和潜在的解决方案是超现代的商业实践。需要训练的东西。

Source: https://en.wikipedia.org/wiki/File:King_Arthur_and_the_Knights_of_the_Round_Table.jpg
然而,设计过程并不新鲜。这是我们的根本。从本质上来说,我们寻求解决问题,数千年的进化让人类擅长于互相讲述故事,并一起努力实现共同的目标。亚瑟王和圆桌骑士的传说是这样的例子,将不同技能的团队聚集在一起,并对准一个共同的北极星是一个强大的获胜策略。
从本质上来说,设计过程始终是关于在谈判桌上拥有正确的技能组合,创造允许这些技能组合拥有共同语言的仪式,并利用工具最大限度地发挥在给定媒介中解决问题的潜力。今天我们用的是设计思维、敏捷、精益,以及曾经流行又好玩的设计冲刺。
基本原则
任何一个做过设计师的人都知道,提出一个解决方案往往需要一些解释。设计从根本上来说是一种变革的媒介。改变往往需要努力。
我们自然会抵制变化,因为它会引发一种未知感。记住这种抵抗只是一种基本的人类生存机制是有好处的。通过冷静的推理和公开的演示,大多数人会很容易地看到一个设计良好的解决方案的好处和价值。

Source: https://en.wikipedia.org/wiki/File:Darwin%27s_finches_by_Gould.jpg
我不确定我是什么时候意识到这一点的,但是产品设计其实只有两件事。
- 新产品或新功能的创造。
- 对现有产品或功能的重新设计或改进。
无论哪种情况,都是关于改变。
容量
当我们缩小历史,看看我们不断设计的总体效果,我们看到所有这些变化对一个可测量的价值有重大影响。这个价值就是我们维持人口的承载能力。
早期人类历史
在人类历史的前 95%中,大约 20 万年,我们的人口增长相对缓慢。我们大部分的时间和精力都花在了从一个地方搬到另一个地方,寻找食物和生存上。到早期人类历史末期,全球人口约为 200 万。
农业革命
大约一万年前,我们开始学习如何耕作。这使得有更多的时间来解决其他问题,如建造房屋结构。这使我们有能力维持比以前快得多的人口增长。到 1750 年,全球人口达到 7 亿。
工业革命
通过技术和制造业的快速发展,我们看到世界人口以前所未有的速度增长。从工业革命开始到现在,在不到 200 年的时间里,我们的人口增长了 10 倍以上,达到 77 亿。
当我们解决新类型的问题时,我们增加了维持人口的能力。显然,单纯用人口来衡量我们设计的解决方案的价值是有局限性的。希望这种测量方法能让我们看到,当与我们的生物编程相结合时,我们设计解决方案的内在驱动力会产生深远的影响,从而延续我们的物种。
改变
在上面概述的更广泛的革命中,有一些更小的转变构成了一个特定的时期。例如,农业革命跨越了石器时代、青铜时代和铁器时代。事后来看,这些时间段很容易看到和分类。
纵观我们当前的工业革命,我们显然已经进入了一个由计算机、软件和数字技术的出现所主导的时代。我们可以称之为计算时代或信息时代。但是,要预测什么时候会发生足够多的变化,让我们处于一场新革命的风口浪尖,要困难得多,也许是不可能的。
我之前写的关于承载能力的原因是为了表明技术允许我们维持和增加人口。从农业到城市化再到资本主义,这些冒险帮助我们刺激人口增长。
那么计算时代是如何影响人口增长的呢?客观地说,在过去的 50 年里,全球人口增加的数量超过了人类历史上 20 万年的总和。我们能够使用数字技术来自动化曾经需要大量手工工作的流程,这极大地提高了我们的承载能力。
随着我们对计算时代的深入挖掘,看起来我们在这方面只会越来越快。在过去的 20 年里,企业已经将战略从“数字优先”转向“移动优先”。现在,随着机器学习、自然语言处理和语音界面的成熟,我们正在进入向人工智能优先的转变。
人工智能第一
回想一下设计、过程和基础——使用一组给定的技术和工具,围绕着解决特定类型问题的设计过程,有一些词语和通用词汇是很有帮助的。亚瑟用的是圆桌,现代商业用的是设计思维。
设计思维通过以客户为中心的视角解决问题是有意义的。但是,这些过程和工具会帮助我们提高机器理解人类并为我们构建解决方案的能力吗?
最近我一直在探索下面的想法。
计算设计的前 40 年产生了一个叫做设计思维的过程。下一个 40 年将需要机器思维,以实现设计运输。
机器思维
机器思维是人类用来教机器如何朝着设计目标前进的一套方法和文化。
传统上,在现代产品开发中,你可能会发现一个由产品经理、产品设计师和应用或产品工程师组成的核心团队。在 A.I. First 模型中,我们需要添加一名机器学习工程师和一名机器学习研究员。
与传统的产品开发流程不同,该团队的工作将不再以人类(或用户)的需求为中心,而是专注于为机器创建算法和路径,以进行学习并基于学习进行输出。
在机器思维中,我们正在为机器设计一套交互模型,以学习、输出并与人类(或其他机器)交互,具有潜在的无限变化和结果。
作为设计师,我们自然会关注工作中最细微的细节。但是在人工智能第一模型中,我们不知道许多细节。机器思维不太强调设计输出的完美性,而更强调设计系统的健壮性。
我鼓励团队在他们的周期中花更多的时间来创建强大的系统图,不可知的接口,概述交互模型。在机器思维中,这变得更有价值。
一个简单的机器思维练习:能够解决最大数量的已知事务的最少数量的组件(交互或接口)是什么?
运输工具
设计传达是将抽象的人类直觉解构为可以有机自我延续的可教结构的能力。
目前,世界各地都有人工智能团队在教机器如何设计时装、创作音乐、写诗歌和散文。虽然产出远非完美,但它正以令人难以置信的速度前进。在这一点上,机器越来越擅长写假文章,以至于它们的文章很容易被误认为是人类写的新闻。人工智能生成的人的图像看起来像真实的人的照片,我们会假设他们真的存在。
这些例子的潜力既令人兴奋又令人恐惧。然而,它们仍然需要大量的人工设置和开发,并且只能产生非常特定的输出。换句话说,人类仍然需要为机器定义具体的问题,机器可以被教会设计解决方案。
但是,如果机器可以被教会在没有我们的情况下识别问题,并独立地创建那些解决方案,那会怎么样?他们能比人类更快更好地发现和解决问题吗?如果机器正在解决一切,那么我们作为未来人类的角色会是什么?
认知产品
认知产品:为与人类行为紧密相关的指数学习而设计的产品——贾斯汀·雷利@贾斯汀·雷利
我以前的同事和朋友贾斯汀·雷利(Justin Reilly)对我转向人工智能优先的想法产生了重大影响。他对认知产品的定义很重要,因为它概述了两个关键因素:1)指数学习和 2)与人类行为的深层联系。
我相信,随着我们在机器思维方法论上的成熟,以及我们在设计传达上的能力的提高,那个认知产品将会像一个网站一样成为桌面上的赌注。我们通过任何接触点交互的所有信息都将具有一定的智能水平,这使它比当今最流行的软件和硬件具有明显的优势。
我们已经看到了那些首先转向人工智能的公司的性能优势。网飞是一个明显的受欢迎的软件例子,它擅长以一种与我们的行为密切相关的方式学习和呈现信息。我已经尽了自己最大的努力反对自己的最佳判断。
《华尔街日报》最近关于堡垒之夜的这篇文章引起了我的兴趣和警惕。我第一次听说这个游戏是通过我 6 岁的儿子兴奋地模仿他那些沉迷于这个游戏的大朋友们做“轻拍”和“牙线”的动作。我和大多数父母一样,认为这是孩子们喜欢的最新无害的电子游戏。但《华尔街日报》的文章概述了堡垒之夜的一些不同之处。凭借其庞大的在线用户群和机器学习,堡垒之夜正在不断提高玩家的参与度。它在一个完全不同的层面上争夺孩子们的注意力。
像许多视频游戏一样,玩堡垒之夜的人越多,关于什么最吸引玩家以及什么促使玩家退出的数据就越多。源源不断的信息流增强了游戏设计师使用机器学习来增强玩家参与度的能力。
随着游戏变得越来越智能,家长们感到被超越了。“这是一场不公平的斗争,”儿童和青少年心理学家、《网络儿童:在数字时代重塑童年》一书的作者理查德·弗里德博士说。
对一些人来说,堡垒之夜就像一个不速之客,一个拒绝离开的人。
然后
在引擎盖下,人工智能第一产品将展示 4 个设计特征。
- 强化学习
- 永远在线
- 接口不可知
- 物理和数字之间模糊的界限

Source: https://en.wikipedia.org/wiki/File:Duck_of_Vaucanson.jpg
网飞和堡垒之夜的例子证实了我的信念,即人工智能已经在我们面前,先行者正在取得胜利。这也让我相信,最初走向人工智能优先的趋势不会看起来和感觉上有明显的不同,但认知产品的表现将优于前几代计算设计。
当我们展望未来的设计时,先进技术带来的难以置信的可能性给了我灵感。我也深深意识到伴随着这些现代工具的力量而来的责任。比以往任何时候都更重要的是,作为一个物种,我们要学会并优先考虑对我们真正有价值的东西。
这就是为什么我强烈主张在认知产品的创作中要有多样化的团队和思想的很大一部分原因。只有通过合作和包容性的工作,我们才能找到适用于人工智能第一世界中几乎无限规模的解决方案。随着算法产生莎士比亚和贝多芬的新作品,我们不仅要教会机器,还要教会我们自己,这对人类意味着什么,这将变得越来越重要。
机器翻译:概述
这个故事是机器翻译领域的概述。这个故事介绍了几个被高度引用的文献和著名的应用,但是我想鼓励你在评论中分享你的观点。这个故事的目的是为这个领域的新手提供一个良好的开端。它涵盖了机器翻译的三种主要方法以及该领域的几个挑战。希望故事中提到的文献能够介绍这个问题的历史以及最先进的解决方案。
机器翻译是将文本从源语言翻译成目标语言的任务。机器翻译有许多具有挑战性的方面:1)大量不同的语言、字母和语法;2)对计算机来说,将一个序列(例如一个句子)翻译成一个序列比只处理数字更难;3)没有一个正确答案(如:从没有性别依赖代词的语言翻译过来,他和她可以相同)。
机器翻译是一项相对古老的任务。从 20 世纪 70 年代开始,就有了实现自动翻译的项目。多年来,出现了三种主要方法:
- 基于规则的机器翻译(RBMT):20 世纪 70-90 年代
- 统计机器翻译:20 世纪 90 年代至 2010 年代
- 神经机器翻译(NMT): 2014-

Photo by Gerd Altmann on Pixabay
基于规则的机器翻译
基于规则的系统需要专家对源语言和目标语言的知识来开发句法、语义和词法规则以实现翻译。
RBMT 的维基百科文章包括一个从英语到德语的基于规则的翻译的基本例子。翻译需要一本英德词典、一套英语语法规则和一套德语语法规则
RBMT 系统包含一系列自然语言处理(NLP)任务,包括标记化、词性标注等等。这些工作中的大部分都必须用源语言和目标语言来完成。
RBMT 的例子
SYSTRAN 是历史最悠久的机器翻丨译丨公丨司之一。它可以翻译大约 20 种语言。SYSTRAN 用于阿波罗-联盟号项目(1973 年)和欧洲委员会(1975 年)[1]。它一直被谷歌的语言工具使用到 2007 年。更多信息见其维基百科文章或该公司的网站。随着 STM 的出现,SYSTRAN 开始使用统计模型,最近的出版物显示他们也在试验神经方法[2]。OpenNMT 工具包也是该公司研究人员的一项工作[3]。
Apertium 是根据 GNU 通用公共许可证条款发布的开源 RBMT 软件。它有 35 种语言版本,目前仍在开发中。它最初是为与西班牙语密切相关的语言设计的[4]。下图是 Apertium 管道的示意图。

Apertium pipeline — Photo by Darkgaia1 on Wikipedia
GramTrans 是一家位于丹麦的公司和一家位于挪威的公司的合作,它为斯堪的纳维亚语言提供机器翻译[5]。
优势
- 不需要双语文本
- 独立于域的
- 全面控制(适用于各种情况的新规则)
- 可重用性(当与新语言配对时,现有的语言规则可以转移)
不足之处
- 需要好的字典
- 手动设置规则(需要专业知识)
- 规则越多,系统越难处理
统计机器翻译
这种方法使用基于双语文本语料库分析的统计模型。它在 1955 年首次被介绍[6],但是直到 1988 年 IBM Watson 研究中心开始使用它才引起了人们的兴趣[7,8]。
统计机器翻译背后的思想如下:
给定目标语言中的一个句子 T,我们寻找翻译者产生 T 的句子 S。我们知道,通过选择给定 T 最有可能的句子 S,我们的错误机会被最小化。因此,我们希望选择 S 以最大化 Pr(S|T)。
— 机器翻译的统计方法,1990 年。[8]
使用贝叶斯定理,我们可以将这个最大化问题转化为 Pr(S)和 Pr(T|S)的乘积,其中 Pr(S)是 S 的语言模型概率(S 是在该位置的正确句子), Pr(T|S)是给定 S 的 T 的翻译概率。换句话说,我们正在寻找给定候选翻译的正确程度及其在上下文中的适合程度的最可能的翻译。

因此,SMT 需要三个步骤:1)语言模型(给定上下文,什么是正确的单词?);2)翻译模型(给定单词的最佳翻译是什么?);3)寻找单词正确顺序的方法。
在前面的段落中,我们同时使用了句和词作为翻译单位。最常用的模型介于这两者之间。这叫做基于短语的翻译。例如,英语短语“正在购买”在法语中被翻译成“achète”。

Non-factored and factored translation — Figures from Moses: Open Source Toolkit … [9]
SMT 示例
- 谷歌翻译(2006 年至 2016 年间,当他们宣布改为 NMT )
- 微软翻译器(2016 年改为 NMT )
- Moses :统计机器翻译开源工具包。[9]
优势
- 语言学专家更少的手工工作
- 一个 SMT 适用于更多语言对
- 更少的字典外翻译:使用正确的语言模型,翻译更流畅
不足之处
- 需要双语语料库
- 特定的错误很难修复
- 不太适合语序差异大的语言对
神经机器翻译
神经方法使用神经网络来实现机器翻译。与以前的模型相比,NMTs 可以用一个网络而不是独立任务的流水线来构建。
2014 年,序列到序列模型的引入为 NLP 中的神经网络开辟了新的可能性。在 seq2seq 模型之前,神经网络需要一种方法将序列输入转换为计算机可用的数字(一次性编码,嵌入)。有了 seq2seq,用输入和输出序列训练网络成为可能[10,11]。

LSTM based seq2seq model: a) training phase, b) prediction phase
NMT 很快出现了。经过几年的研究,这些模型优于 SMT[12]。随着结果的改善,许多翻译提供商公司将其网络改为基于神经的模型,包括谷歌[13]和微软。
如果训练数据不平衡,神经网络就会出现问题,模型无法从稀有样本和频繁样本中学习。就语言而言,这是一个常见的问题,例如,有许多罕见的单词在整个维基百科中只使用了几次。训练一个不偏向于频繁单词(例如:在每个维基百科页面上多次出现)的模型可能是具有挑战性的。最近的一篇论文提出了一个解决方案,使用一个后处理步骤,用字典翻译这些生僻字[14]。
最近,脸书大学的研究人员引入了一个无监督的机器翻译模型,该模型与 SMT 和 NMT 一起工作,只需要大型单语语料库,而不需要双语语料库[15]。前面例子的主要瓶颈是缺乏大型翻译数据库。这一模式显示了解决这一问题的前景。
NMT 的例子
- 谷歌翻译(从 2016 年开始)链接到谷歌人工智能的语言团队
- 微软翻译(自 2016 年)链接到微软的机器翻译研究
- 脸书的翻译:链接到脸书 AI 的 NLP
- OpenNMT: 一个开源的神经机器翻译系统。[16]
优势
- 端到端模型(没有特定任务的管道)
不足之处
- 需要双语语料库
- 生僻字问题

Translation quality of statistical and neural MT models by Google — Figure by Google
摘要
在这个故事中,我们讨论了解决机器翻译问题的三种方法。许多重要的出版物与重要的应用程序一起收集。这个故事揭示了该领域的历史,并收集了最先进的模型的文献。我希望这对一个刚涉足这个领域的人来说是个好的开始。
如果你觉得缺少了什么,欢迎和我分享!
参考
[1]托马,P. (1977 年 5 月)。 Systran 作为多语言机器翻译系统。第三届欧洲信息系统和网络大会论文集,克服语言障碍(第 569–581 页)。
[2] Crego,j .,Kim,j .,Klein,g .,,a .,Yang,k .,Senellart,j .,… & Enoue,S. (2016)。 Systran 的纯神经机器翻译系统。arXiv 预印本 arXiv:1610.05540 。
[3]克莱因、金、邓、塞内拉尔特和拉什(2017 年)。OpenNMT:用于神经机器翻译的开源工具包。 arXiv 预印本 arXiv:1701.02810 。
[4] Corbí Bellot、A. M .、Forcada、M. L .、Ortiz Rojas、s .、Pérez-Ortiz、J. A .、Ramírez Sánchez、g .、Sánchez-Martínez、f .、……和 Sarasola Gabiola,K. (2005 年)。一个开源的西班牙罗曼语浅传机器翻译引擎。
[5] Bick,Eckhard (2007), Dan2eng:广覆盖丹麦语-英语机器翻译,载于:Bente Maegaard(编。),机器翻译峰会论文集,XI,10–14。2007 年 9 月,丹麦哥本哈根。第 37-43 页
[6]韦弗,W. (1955 年)。翻译。语言的机器翻译, 14 ,15–23。
[7]布朗,p .,科克,j .,彼得拉,S. D .,彼得拉,V. D .,耶利内克,f .,默瑟,r .,&罗辛,P. (1988 年 8 月)。语言翻译的统计方法。见第 12 届计算语言学会议论文集-第 1 卷(第 71–76 页)。计算语言学协会。
[8]布朗、P. F .、科克、j .、德拉·皮特拉、S. A .、德拉·皮特拉、V. J .、耶利内克、f .、拉弗蒂、J. D .、……和鲁辛,P. S. (1990 年)。机器翻译的统计方法。 计算语言学, 16 (2),79–85。
[9]科恩,p .,黄,h .,伯奇,a .,卡利森-伯奇,c .,费德里科,m .,贝托尔迪,n .,…,戴尔,C. (2007 年 6 月)。Moses:统计机器翻译的开源工具包。在计算语言学协会第 45 届年会的会议录配套卷演示和海报会议的会议录(第 177-180 页)。
[10] Sutskever,I .,Vinyals,o .,& Le,Q. V. (2014 年)。用神经网络进行序列对序列学习。在神经信息处理系统的进展(第 3104–3112 页)。
[11] Cho,k .,Van merrinboer,b .,Gulcehre,c .,Bahdanau,d .,Bougares,f .,Schwenk,h .,和 Bengio,Y. (2014 年)。使用用于统计机器翻译的 RNN 编码器-解码器学习短语表示。 arXiv 预印本 arXiv:1406.1078 。
[12] Bahdanau,d .,Cho,k .,& Bengio,Y. (2014 年)。神经机器翻译通过联合学习来对齐和翻译。arXiv 预印本 arXiv:1409.0473 。
[13] Wu,y .,Schuster,m .,Chen,z .,Le,Q. V .,m .,Macherey,w .,… & Klingner,J. (2016)。谷歌的神经机器翻译系统:弥合人类和机器翻译之间的鸿沟。 arXiv 预印本 arXiv:1609.08144 。
[14] Luong,M. T .,Sutskever,I .,Le,Q. V .,Vinyals,o .,& Zaremba,W. (2014 年)。解决神经机器翻译中的生僻字问题。arXiv 预印本 arXiv:1410.8206 。
[15] Lample,g .,Ott,m .,Conneau,a .,Denoyer,l .,& Ranzato,M. A. (2018 年)。基于短语的&神经无监督机器翻译。 arXiv 预印本 arXiv:1804.07755 。
[16] Klein,g .,Kim,y .,Deng,y .,Senellart,j .,& Rush,A. M. (2017 年)。Opennmt:用于神经机器翻译的开源工具包。 arXiv 预印本 arXiv:1701.02810 。
用伯特的故事学习 NMT
- BLEU-BERT-y:比较句子得分
- 嵌入关系的可视化(word2vec,BERT)
- 机器翻译:一个简短的概述
- 使用 BERT 识别单词的正确含义
- 机器翻译:与 SOTA 相比
- 使用 TensorFlow 2.0 的简单 BERT
机器翻译:与 SOTA 相比
我之前的故事将 BLEU 描述为机器翻译(MT)最常用的度量标准。这个旨在介绍会议、数据集和竞赛,在那里你可以将你的模型与最先进的进行比较,你可以从那里收集知识,在那里你可以见到来自该领域的研究人员。

Conference — Image by 정훈 김 from Pixabay
MT 特定研讨会
WMT 会议
WMT 会议是 ACL 会议(计算语言学协会年会)的一部分,因此缩写为:机器翻译研讨会。第一次研讨会于 2006 年举行,是 NAACL 的一部分(T2 NAACL-2006 统计机器翻译研讨会)。大约在从统计机器翻译转变为神经机器翻译的时候,会议的名称变成了机器翻译会议。今年的发布会在 2019 年 8 月 1-2 日,意大利佛罗伦萨( WMT19 )。
WMT 每年都会发布翻译任务,最顶尖的模特会在这些任务上展开竞争。2016 年宣布的 GNMT(谷歌的神经机器翻译)使用了 WMT 的 14 个英德和英法数据集来评估其性能[1]。脸书、谷歌、微软和许多其他公司都参与了今年的竞争。

English-German results of the WMT19 News Translation Task
分解车间
DiscoMT 2019 ,第四届机器翻译中的话语研讨会,聚焦话语级机器翻译。它将于 2019 年 11 月 3 日在中国香港举行。它使用与 WMT19 相同的任务,但数据集包括话语级注释。DiscoMT 是 EMNLP(自然语言处理经验方法会议)的一部分。
MT 峰会
第 17 届机器翻译峰会,于 2019 年 8 月 19 日至 23 日在爱尔兰都柏林的都柏林城市大学 Helix 剧院举行。该会议由欧洲机器翻译协会(EAMT)组织。
数据集
一个更长的平行文本数据语料库列表在这里。
- 欧洲议会议事录平行语料库1996–2011[3]:欧洲议会议事录 21 种语言。根据不同的语言有 1100 万到 5000 万个单词。
- 对齐加拿大第 36 届国会的议事录【4】:130 万对对齐的法语和英语文本块
- UN translations【5】:6 种语言(ar、en、es、fr、ru、zh)文本共 44 万个句子片段。****
- 维基百科【6】:从维基百科中提取的 20 种语言的句子,共 2590 万句。
出版物
这一部分试图回答“我应该在哪里发表我的机器翻译论文?”。这些统计数据来自谷歌学术搜索“机器翻译”的前 50 个结果。
下图显示了不同颜色(分别为绿色和橙色)的 ACL 和 EMNLP 相关会议。如我们所见,如果我们看看谷歌学术的结果,ACL 是机器翻译领域最重要的会议。基于 ACL 的会议、出版物:
- ACL:计算语言学协会年会
- EACL: 美国律师协会欧洲分会(EACL)
- NAACL-HLT:美国语言学会北美分会年度会议:人类语言技术
- TACL:《TACL 计算语言学协会汇刊》是由 ACL 主办的期刊由麻省理工学院出版社出版
- WMT:机器翻译会议
- 计算语言学: 计算语言学 由麻省理工学院出版社代表计算语言学协会出版。

Conferences, Journals from the top 50 results of Google Scholar search ‘machine translation’
WMT 提交格式
NIST 在 2012 年组织了一次开放机器翻译评测。他们为机器翻译提交定义了 SGML 格式。此后,这种格式被用作标准提交格式。 WMT19 使用相同的描述进行提交。下面是一个格式示例:
****`<refset trglang=”cz” setid=”test2010" srclang=”any”>
<doc sysid=”ref” docid=”idnes.cz/2009/12/10/74900" genre=”news” origlang=”cz”>
<seg id=”1"> ...
... `****
摘要
在这个故事中,我们总结了机器翻译方面的主要会议、研讨会以及要发表的重要期刊。我们看到了最大的公司竞争的比赛,以及这些比赛提交的标准格式的例子。我们还收集了一些广泛使用的语料库。
参考
[1]吴,y,舒斯特,m,陈,z,乐,Q. V,,m,马切里,w,…和克林纳,J. (2016)。谷歌的神经机器翻译系统:弥合人类和机器翻译之间的鸿沟。 arXiv 预印本 arXiv:1609.08144 。
[2] Barrault,l .,Bojar,o .,Costa-jussà,M. R .,Federmann,c .,Fishel,m .,Graham,y .,… & Monz,C. (2019,8 月)。2019 机器翻译大会(wmt19)的发现。第四届机器翻译会议论文集(第 2 卷,第 1-61 页)。
[3]科恩,P. (2005 年 9 月)。 Europarl:一个用于统计机器翻译的并行语料库。在 MT 峰会(第 5 卷,第 79–86 页)。
[4]德国大学(2001 年)。加拿大第 36 届议会的联合议事录。
[5]a . Rafalovitch 和 r . Dale(2009 年 8 月)。联合国大会决议:六种语言平行语料库。在MT 峰会议事录(第 12 卷,第 292–299 页)。**
[6]沃兹尼亚克和马拉塞克(2014 年)。建立主题对齐的可比语料库并挖掘它以获得真正平行的句子对。 Procedia 技术, 18 ,126–132。
用伯特的故事学习 NMT
- BLEU-BERT-y:比较句子得分
- 嵌入关系的可视化(word2vec,BERT)
- 机器翻译:简要概述
- 使用 BERT 识别单词的正确含义
- 机器翻译:对比 SOTA
- 使用 TensorFlow 2.0 的简单 BERT
机器翻译峰会 2019 印象、总结和笔记—第一部分
几周前,最大的年度 NLP 会议之一在爱尔兰都柏林举行— 机器翻译峰会 2019 ,该会议专注于机器翻译(MT)的研究和应用,这是 NLP 中一个具有挑战性的问题。这一周充满了 MT 研究人员和从业者的数十场讲座、研讨会和指导,总体而言,我认为会议非常精彩。

Home sweet home for a week.
这篇文章总结了我对这次会议的印象,也是我对特定演讲、教程和论文的笔记的一个数据转储:)我将它们公之于众,以防其他人发现它们是一个有用的总结。
注意:我在大会上的经历明显受到我碰巧参加的会议(主要是“研究轨道”会议)的影响,但是为了更全面地了解大会,点击这里查看会议日程。
这篇文章是第一部分,涵盖了会议的第 1 天到第 3 天,而第二部分涵盖了第 4 天和第 5 天。前几天是辅导课和研讨会,而最后三天是讲座和海报。
总结和总体印象
- 随着人工翻译的传统角色继续向编辑机器翻译输出(后期编辑;PE),而不是从零开始翻译,有很大的兴趣去理解任何与 PE 相关的东西:PE 对整体翻译质量和风格的影响;后期编辑的生产力、工作模式以及与机器翻译的互动;以及这种向 PE 的转变如何影响实际业务中的生产。
- 我们很高兴看到对递归神经网络(RNNs)和基于统计机器翻译(SMT)的机器翻译模型的研究继续进行——尽管 Transformer 模型现在是 MT 架构 à la mode ,但其他方法在特定情况下仍优于 Transformer(例如,SMT 用于小段翻译),或者可能更容易直观理解。
- 我喜欢探索使用信息而不是文本的工作。使用图像和文本作为翻译模型输入的多模态翻译海报;端到端语音到文本的翻译对话;描述跟踪后期编辑的键盘和鼠标交互的海报;以及在用户与 MT 互动时追踪眼球运动的项目。
- 有相当多的上下文感知机器翻译和话语级现象被提及——我们的标准模型纯粹在句子级别上工作,这忽略了大多数文本存在于段落、章节和文档中的其他文本周围的事实。显式烘焙上下文信息的方法显示出非常有希望的结果。
- 我最喜欢的演讲可能是 Arianna Bisazza 的“理解多语言神经网络模型中的句法和语义转移”——这非常酷,甚至有可能同时用多种语言训练我们的标准 NLP 模型。神经网络的可解释性总是令人感兴趣,但在多语言模型中尤其令人感兴趣,这些模型可以捕捉跨语言表示。
- 我最喜欢的海报是...嗯,这是一个平局。首先是的马尔基西奥及其同事的“控制机器翻译输出的阅读水平”。我惊喜地发现,通过在源语句中插入一个简单的标志,可以如此有效地控制 MT 输出的复杂性。其次,还有 Góis & Martins 的“translator 2 vec:理解和表现人类后期编辑”。诚然,我是所有 x 的 x2vec 的粉丝,但看到人类翻译的工作模式来自他们在后期编辑期间与键盘、鼠标和文本的交互序列,这特别酷。
会议第一天—关于“神经模型在语言解码中的不合理效果”的教程
作者 KantanMT
这是一个半天的教程,由 KantanMT(机器翻译平台的提供商)提供。这是一次更实际的会议,是在去年 KantanMT 和易贝之间的一些神经机器翻译(NMT)实现实验之后进行的。一些亮点:
- 客户首先需要具体的证据证明神经翻译模型优于统计翻译模型。对照实验表明,NMT 模型实际上有较低的 BLEU 分数,但母语为英语的评估者更喜欢 NMT 模型。BLEU 度量尤其可以与 NMT 相比较,因为 NMT 可以生成不太字面上流畅的输出,这仍然是很好的,但不一定在 n-gram 级别上紧密匹配参考翻译。
- 下一组实验是比较用于建模翻译的 3 种主要神经架构之间的性能——RNNs(递归神经网络), CNNs(卷积神经网络);更常见于计算机视觉)和 TNNs(变压器神经网络;或者只是变形金刚)。比较的范围很广,包括自动指标(BLEU、TER、METEOR)、人工评估分数以及技术方面,如训练时间、集成和适应/再训练的容易程度。正如你所料,结果是变形金刚更胜一筹。
- 除了确保您有足够的单词/句子对来开始构建 NMT 模型,还应该检查唯一的单词计数,理想情况下应该尽可能高(例如> 100k)。
- 将深度学习框架从 Theano 切换到 OpenNMT 来训练 NMT 模型,导致它们的速度大幅提高。
- 如果可用于域适配的域内数据量很低,他们发现在适配期间简单地添加这些数据的更多副本是有益的。
会议第二天——“后期剪辑深度学习曲线”**
通过本地化
本教程实际上是由我们,Welocalize 的 MT/NLP 工程团队的几个人提出的,所以,我没有太多的笔记:)简而言之,本教程的目的是提供一个关于后期编辑的行业视角——在我介绍了应用 MT 研究的当前状态后,同事们讨论了 NMT 实施的挑战,不同 MT 提供商的利弊,当然还有一切最终如何影响后期编辑过程。
会议第 3 天——会谈
“PEMT 质量监测的众包和相关工具”
作者莫尼斯
会议的开场白也是关于后期编辑的(PEMT= 后期编辑机器翻译 ),演讲者是 Unbabel 的海伦娜·莫尼斯,一家非常时髦的 MT 初创公司。这次演讲更多地关注人的方面,而不是技术方面,并讨论了 un label 如何管理他们的人工翻译——没有单一的“我是一名翻译”标签,而是根据技能、经验和领域将每个翻译分为不同的类别。这意味着当有新任务时,他们可以迅速找到最合适的翻译。
目前有新一代的翻译正在毕业,他们非常清楚并习惯于与机器学习模型一起工作。这意味着气氛更加合作,越来越不像是一场充满敌意的“人工智能与翻译”之战。
演讲中一个非常酷的部分是一个语音信息应用程序的演示,它允许用户用一种语言记录和发送信息,然后自动翻译和语音合成为接收者的首选语言。我可以肯定地看到,一旦这项技术进一步发展,它会变得越来越流行。目前,这一过程有一个手动部分——如果自动翻译看起来质量很低,人工会纠正翻译错误。合成语音目前是通用的,还不能反映说话者独特的语音特征,尽管这一技术目前正在开发中。
“CLIR 在低资源环境下的强大文档表示”
作者:Yarmohammadi 等人 【论文在此】
信息检索 (IR)是关于获取给定查询的正确信息位,而 跨语言信息检索 (CLIR)在多语言设置中做这件事。因此,用户的查询是用不同于数据库中的文档的语言编写的,任务是优雅地进行机器翻译,并获取相关文档,尽管存在语言障碍。作为一个用例,想象一个新闻记者查询外语新闻源来展开她的故事。
这种 CLIR 系统的主要要求是:
- 对机器翻译错误的鲁棒性。即使存在机器翻译错误,也必须为每个查询返回相关文档。
- 对 ASR 误差的鲁棒性。如果文档数据库包含语音的音频文件,这些文件必须首先通过自动语音识别(ASR)转换成文本,并且该系统还必须对该步骤中出现的任何错误具有鲁棒性。
- 面对低资源语言的鲁棒性。作者在三种低资源(=少量训练数据)语言的背景下考察了 CLIR:索马里语、斯瓦希里语和他加禄语。这三种语言的文档将使用英文查询进行检索。
本文的重点是针对 CLIR 的文档翻译方法(即索马里语、斯瓦希里语和他加禄语文档首先被翻译成英语),但是其他论文以相反的方式完成了这项任务,即将查询翻译成目标语言。这样做的问题是查询可能很短,所以您很难可靠地找到相关的文档。这种方法被用作基线。
任务输入是英文查询,输出是检索与查询相关的文档。“基本事实”是针对一组查询的人类标记的文档相关性排名。困难的部分是 ASR 和 MT:一旦有了翻译的文档,查询到文档的相关性分数计算和排序就由 Elastic Search 和 Okapi 处理。
大部分工作侧重于评估表示文档的不同方式,以及这如何影响 CLIR 的整体性能。文档的 3 种不同“视图”是:
- N-最佳解码。对于文本文档,MT 生成每个句子的 N 个最佳翻译(对于不同的 N 值)。对于语音文档,ASR 为每个片段生成一个 N 最佳列表,MT 解码器为每个片段生成 M 最佳翻译,从而生成一个 NxM 矩阵。无论是使用整个矩阵还是从中采样,都不会对性能产生太大影响。
- 短语包(BOP)翻译。给定源文本,基于短语的 SMT 系统生成所有可能的翻译短语(没有语言模型;所以,不是完全解码搜索)——所有这些翻译选项连接在一起,形成一个短语包。这种方法为文档表示提供了更多的词汇多样性,例如,您可以获得一个特定单词的 10 种可能的翻译。对于语音文档,ASR 也是开始处理文本的第一步。
- 以及两者的结合。您也可以只使用两种表示,N-best translations 和 BOP translation: index,并让搜索功能根据用户查询与任一表示的匹配程度对文档进行评分。
事实证明,用词组袋表示法的词汇多样性来扩充 N-best 列表的更标准的方法执行得最好,并且在所有三种被检查的低资源语言的 CLIR 任务中做得很好。尽管更丰富的文档表示可能更容易出错,但是每个文档拥有尽可能多的信息,并捕捉尽可能多的语言变化,似乎可以得到最好的结果。
“增强端到端语音到文本翻译的转换器”
作者迪甘吉等人 【论文在此】
早期的实时语音翻译系统基于菊花链形式的独立系统,一个语音识别模型生成文本,一个独立的机器翻译模型翻译转录的文本。在这项工作中提出了一种更时尚的方法,该方法采用 Transformer 架构,以允许 端到端语音到文本的翻译 。
作者在本文中研究了 3 种现象:
- 使用变压器完成该任务。以前基于 RNN 的端到端语音到文本翻译模型训练速度慢且计算量大。在这里,他们想使用 Transformer,不是因为它新奇,而是因为它更具并行性,而且肯定比基于 LSTM 的方法训练得更快。
- 利用 2D 注意力处理语音数据。他们想在 声谱图 处理阶段使用 2D 注意力(声谱图是一个音频文件的表示,就像一个语音样本,它包含了一段时间内的频率足迹)。使用 2D 注意力将有助于随着时间的推移保持声谱图属性,允许模型利用 2D 依赖性,而不是将所有依赖于时间的信息浓缩在一起。**
- 增加局部偏向的自我关注。**当输入语音样本很长时,他们观察到,转换者的自我注意机制会试图关注整个序列长度。这不是很有用,因为结果是模型很难捕捉到短程依赖关系。他们引入了局部偏向的自我注意力,以激励注意力机制将注意力集中在它当前工作的区域附近——他们通过增加一个惩罚来做到这一点,如果注意力偏离矩阵对角线太远。
他们基于变压器的模型确实比 LSTM 的训练速度快得多,但性能却差不多。有趣的结果是,添加局部注意力惩罚确实有助于该语音到文本翻译任务的模型,并且还导致训练期间更快的收敛。增加对 2D 的关注也会导致 BLEU 的增加。最后,作者发现,增加模型的大小可以显著提高性能,这表明他们使用的模型仍然太小(这一特定结果似乎在目前的 ML 工作中很常见)。
第 3 天—主要会议海报
那天剩下的时间都集中在海报上。我特别喜欢的一些海报是:
“原始机器翻译对 Word 的日本用户有什么影响:使用眼球追踪的可用性研究的初步结果”
由阿里纳斯等人著 【论文在此】
这项工作调查了用户对他们使用的软件中的机器翻译内容的感受,具体来说,日本参与者要么看到已发布的人类翻译的 Microsoft Word 日语版本,要么看到机器翻译的日语版本。用户被要求在一个 Word 版本中完成一些任务。除了比较任务完成情况、效率和用户满意度之外,他们的眼球运动也被跟踪,以此作为认知努力的衡量标准。
结果表明,日语使用者的任务完成和效率得分在人工翻译的发布词版本中略高,但不显著。然而,他们自我报告的满意度得分明显更高,这表明与处理人工翻译文本相比,处理原始机器翻译可能是一种不太愉快的体验。
“Translator2Vec:理解和表现人类海报编辑”
由高乃依&马丁斯。 【此处论文】
不同的译者处理后期编辑任务的方式不同。为什么不捕捉不同翻译工作时的动作,并检查数据中的模式和聚类呢?这将有助于识别不同的后期编辑风格,并可能判断哪种更有效。从后期编辑收集动作序列数据,包括按键编辑操作、鼠标动作、等待时间和对实际 MT 文本的更改。收集的数据集相当大——来自 300 多人进行的 66k 次编辑后会话的动作序列。
作者表明,动作序列的信息相当丰富,可以用来准确地识别特定的后期编辑,比只使用 PE 前和 PE 后的文本信息要好。您还可以使用 tSNE 对动作序列数据进行降维,并绘制二维的低维向量表示——这使您可以看到 PE 会话的集群,并观察到每个后期编辑都有自己独特的风格。这些编辑器表示也是后期编辑时间的非常有效的预测器。可悲的是,集群之间在工作风格上没有太多直观可理解的差异,但这仍然是一个非常好的结果。
就应用程序而言,您也可以通过这种方式来衡量后期编辑之间的相似性,或者将此作为后期编辑培训工具的一部分——例如,发现给定的工作方式是否与低生产率有关,或者检测您的会话是否不靠近任何群集,这可能意味着您的工作流程与其他翻译人员有很大不同。这是他们论文中的一个很好的图表,展示了英语-德语和英语-法语体育课的 tSNE 图:

这显示了编辑后会话日志对编辑后身份的预测性。
“为资源不足的 NMT 模型利用基于规则的机器翻译知识”
作者托雷格罗萨等人 【论文在此】
神经机器翻译可能会给出令人惊讶的好结果,但它在很大程度上依赖于足够数量的可用训练数据。根据定义,低资源语言对没有太多的并行数据,在这种情况下,使用老式的、手写的、基于规则的机器翻译(RBMT)的元素会非常有帮助。
这项工作试验了利用 RMBT 系统中包含的语言信息的不同方法,以便在低资源环境中改进 NMT 模型。关键的结果是,使用来自基于规则的机器翻译的形态学信息(以词性(POS)标签、依存标签和句法树信息的形式)的特征丰富,在添加到 NMT 系统时,在提高性能方面是有效的。有趣的是,观察到的提升性能类似于使用子词标记化带来的提升。
“斯拉夫语言的形态学神经前处理和后处理”
作者贝尔纳迪内洛 【论文在此】
斯拉夫语(俄语、捷克语、波兰语、保加利亚语等。)形态丰富——词序相当灵活,词的功能由几十种不同的语言形式表示。以下是他们论文中的一些捷克变调例子:

And this is just the start of it.
因此,斯拉夫语的 NMT 系统面临着拉丁语或日耳曼语所没有的挑战。本文通过增加一个额外的预处理步骤来处理斯拉夫语源文本,在该步骤中,屈折词被分解成它们的语言成分。另一方面,当目标语言是斯拉夫语时,类似的处理步骤发生在翻译之后(后处理)。这一过程通过调整标记化过程来更好地处理屈折变化——首先,作者利用在线资源为每种斯拉夫语言建立了形态模型,这是基于数百万个例子的形态类别图。这些然后被用于指导令牌化过程。
—
点击此处查看 我的会议笔记第二部分 ,涵盖了会议第 4 天和第 5 天。
2019 年机器翻译峰会印象、总结和笔记-第二部分
这是最近在都柏林举行的机器翻译会议之后,我撰写的文章的第二部分。

Machine translation enthusiasts overran Dublin’s DCU campus for a week.
点击这里查看我的第一部分帖子中的介绍、会议摘要以及第 1-3 天会议的笔记。
让我们直接进入会议内容的其余部分。
会议第 4 天——研究讲座
“NMT 建筑的内在近邻分析”
by gha der&MonzT8【论文在此】
目前还不清楚 NMT 编码器在隐藏状态表示中实际捕捉到了什么样的语言信息。早期的工作通过观察这些向量中的信息是否可以用于各种句法分类任务(例如,预测语态、时态和词性)来研究 NMT 模型的隐藏状态。在这里,作者也检查编码器隐藏状态,但是通过检查隐藏状态和单词嵌入之间的相似性来直接进行,而不是通过使用它们作为分类器的输入来间接进行。
一个特别有趣的话题是——一个单词的编码器隐藏状态与其原始输入嵌入有何不同?据推测,与输入嵌入相比,编码器隐藏状态捕获了更多的上下文信息。但是这个额外的上下文信息到底是什么,对于 rnn 和 tnn/Transformers 有什么不同吗?除了输入嵌入已经获取的信息之外,还获得了哪些额外的信息?为了回答这些问题,本文使用最近邻方法来比较隐藏状态词表示和输入词嵌入。
该技术的核心是获取单词的隐藏状态表示,并计算 n 个最近邻单词的列表。然后,检查最近邻列表与以下内容的重叠程度:
- 基于相应单词嵌入的单词最近邻列表
- 由 WordNet 词汇数据库记录的同义词和相关词的列表
从他们的论文中找到邻居列表的例子:

作者表明,单词的隐藏状态表示与它们的输入表示非常不同——大多数隐藏状态邻居列表没有被基于嵌入的列表覆盖。然而,隐藏状态确实捕捉了更多的 WordNet 关系。
最后,作者进行了实验来比较在 RNN 和 TNN 编码器的隐藏状态中发现的信息。发现的主要见解是:
- 转换器隐藏状态更好地捕捉词汇语义(词义)
- 而 RNN 隐藏状态更擅长捕捉句法相似性(语法)
- 具体来说,RNN 模型中的反向递归层学习更多的词汇和语义信息..
- ..而 RNN 模型中的前向递归层学习更多长距离的上下文信息。
“通过蒸馏使用高噪声并行数据改进 NMT”
蒙兹。 【论文在此】
众所周知,NMT 渴望数据,比老牌的 SMT 更甚。但是平行语料库很难找到,并且通常在大小、语言和领域方面受到限制。另一方面,从多语言新闻门户等资源中获取自动对齐的语料库相对容易。流行的 Paracrawl 和 ISI 语料库就是这种情况。但是当然,这样的数据集会有很多噪音,噪音的主要来源通常是错位的句子——有时是完全错位的句子,有时是错位的或未翻译的句子片段。其他常见错误包括不正确的语言用法、未翻译的句子以及非语言字符的用法。
NMT 能从这些低质量的短信中获益吗?在 WMT 已经表明,虽然将嘈杂的语料库添加到干净的语料库实际上可以帮助 SMT 系统,但是在 NMT 系统中,这可能导致质量骤降。因此,与“仅干净数据”相比,即使在“干净和有噪声的组合数据”上训练也会降低性能。NMT 不仅数据饥渴,而且数据敏感。
作者提出了一种 蒸馏 策略,当与高质量并行语料库( 干净数据 )结合使用时,利用额外的低质量双文本( 可比数据 )而不进行任何过滤。在这种方法中,他们首先培养一个 NMT 教师模型 上的高质量、干净的数据而已。教师模型然后指导在干净和有噪声/可比数据的组合上训练的最终 学生模型 的训练。
这个想法是基于 Hinton 提出的 知识升华 框架,其中更小的、压缩的 学生网络 使用来自大型 教师网络 的监督来训练。学生的目标是在数据集上模拟教师网络的输出分布,通常是通过最小化两个分布之间的交叉熵或 KL-divergence 损失。使用对数似然损失来训练教师模型,并且在 KL 发散损失 上训练学生模型——使用超参数来平衡两个损失。总结一下——在知识升华中,学生学会了用更少的参数模仿老师的表现。
结果表明,对于两种语言对(阿拉伯语-英语和汉语-英语),所提出的知识提取策略优于语料库过滤和回译替换。
“利用课程学习改进 NMT 的指代消解”
作者斯托扬诺夫斯基&弗雷泽 【论文在此】
指代消解,或者代词消解,就是弄清楚代词指的是什么的问题——例如,在句子“猫去冰箱是因为它饿了”中,“它”指的是什么?是猫饿了,还是冰箱?这些类型的问题对人类来说很容易,但对计算机来说很难。出色地完成这一解析任务对于代词的正确翻译至关重要。尽管上下文感知模型显示代词翻译(以及其他语篇层面的现象)有所改进,但仍有进步空间。
为了提高上下文感知 NMT 中的回指/代词解析,作者建议使用课程学习,这是一种模仿人类学习的渐进性质的学习类型:你从“更容易”的问题开始,随着表现的改善逐渐增加复杂性。这种方法可以导致更快的收敛,并且已经发现在有限的训练数据条件下是有帮助的。在回指解析的情况下,训练从“训练轮”开始——提供了模型可能需要的所有信息来整理代词指代,关系变得明确。这些金标准标注的代词被称为 甲骨文 。随着时间的推移,隐藏越来越多的 oracle 信息会增加任务的难度。
作者发现,尽管基线模型在测试时可以获得完全相同的信息,但使用课程学习来训练上下文感知的 NMT 模型可以提高代词的分辨率。使用针对不同话语现象的神谕可以使这种课程方法得到更广泛的应用。
“用合成数据改善美国手语识别”
作者金&奥尼尔-布朗 【论文在此】
该项目通过开发手语和口语之间的机器翻译系统,解决了(聋人)手语者和非手语者之间的实时通信需求,而无需使用人工翻译。这是一项多模态任务,因为手语是视觉的,而不是基于文本的。
该项目的核心是构建一个 自动化手语识别器模型 (ASLR),它可以识别不同手势背后的语义意图。手语非常复杂——从手的位置、眉毛的动作、肩膀的抬起、一般的姿势和其他细微的动作都与手语的含义有关。这意味着身体上的几乎所有东西都需要被处理和识别。此外,识别系统必须对签名者中存在的自然变化具有鲁棒性,无论是在给定的个人中还是在不同的人之间。
作者使用的设置是用于 3D 视频捕捉的 Kinect 和用于特征提取的 Kinect SDK。他们使用预训练的 OpenPose 模型进行身体姿势检测,生成骨骼化的 25 点身体姿势和 20 点手部位置,并使用预训练的 DeepHand 模型进行手部位置识别。
建立这样一个系统的一个关键挑战是它的资源非常少——获取训练数据既困难又昂贵。作者最初试图使用 GANs 生成合成数据,但他们会得到非常奇怪的三只手人的图像,这不是很有用。他们发现,基于每一帧 2D 操作的不同经典图像增强/数据合成技术——如移位、倾斜、旋转、模糊和对比度变化——是有帮助的。有趣的是,系统性能并没有随着更多的合成数据而单调增加,而是更加呈 U 形。
“话语感知神经机器翻译”
**作者龙跃论文此处;这是最佳论文奖获得者]
NMT 做得相当不错,但仍有很长的路要走——它确实不如人工翻译。但是为什么呢?部分原因可能是 NMT 通常在单个句子层面进行翻译,而不是在语篇层面。正常文本中的句子通常具有连通性的属性(例如回指、共指),并且通过向 NMT 馈送独立的句子来忽略这些依赖性会忽略这些有用的属性,并且会降低 NMT 质量。
论文探讨的问题之一是如何将 文档级上下文 包含在 NMT 中。一种方法是使用分级编码器——它有两级循环网络,在句子级和文档级,以获得概括跨句子上下文的向量,然后可以输入 NMT 系统。探索了整合这种全球背景信息的三种方法:
- 使用跨句子上下文作为初始化状态。也许以上下文感知的初始状态开始模型会改进 NMT。
- 使用它作为附加功能来增强 NMT 解码器。这种方法类似于人类翻译人员在翻译句子的困难部分时有时会回头看单词。
- 使用带有门控机制的上下文向量。很可能上下文中的信息并不总是有用的。也许门控机制会有用,因为它可以过滤掉一些噪音,并动态地决定何时使用以及使用多少上下文信息。
简而言之——上下文信息通常有助于 NMT。
本文还探讨了零回指翻译,这种现象存在于汉语和日语等亲降语言中,在这种语言中,代词可以完全省略,以使句子更加紧凑,但仍然可以理解,因为代词的身份可以从上下文中推断出来。人们发现,使用零代名词将这些省略的信息重新整合到句子中,可以提高几个百分点的性能。
演讲最后列出了几个开放性问题:首先,仅仅通过增加数据可以解决多少话语问题?更多的数据缓解了大多数问题,所以也许这就是我们真正需要的。第二,话语知识在 NMT 建筑中是如何传递的?这是另一个棘手的神经网络内部状态问题。
会议第 4 天—海报
这一天剩下的时间专门用于海报会议。
“控制 MT 输出的读数水平”
作者马尔基西奥等人 【论文在此】
在某些情况下,您可能希望手动控制 MT 输出的某些风格方面。受控制机器翻译输出的正式或礼貌水平的工作的启发,本文提出了一种控制机器翻译输出的复杂性或阅读水平的技术。如果机器翻译输出是为儿童或语言学习者设计的,那么低复杂度输出(简单词汇、简单句子结构)将是有用的,而较高复杂度输出(具有高级词汇和句法结构的简明语言)将更适合于正式的商业环境。
作者提出了两种控制可读性的方法:**
- ****标记。这种标记方法类似于礼貌论文。首先,作者观察到译文的可读性倾向于模仿训练集中目标句子的可读性。鉴于这种观察,他们将训练数据分为“简单”和“复杂”子集(可读性是使用预先存在的度量标准计算的,如 Flesch-Kincaid 分数)。也保留了“中等”复杂性的例子来改进训练。接下来,训练语料库中的源端句子根据其目标端句子的阅读水平进行标记——即,在源端大小的训练句子的末尾添加一个短文本标记,该标记与目标端句子的复杂性类别相匹配。这个想法是变形金刚的注意力机制应该学会在解码时注意这个标签。最后,在测试时,给测试源句子附加一个“简单”或“复杂”标记就足以指定输出的阅读水平!
- ****调整变压器架构。第二种方法通过使用一个联合编码器和两个单独的解码器改变了标准编码器-解码器架构,低复杂度和高复杂度模型各一个。在训练期间,编码器总是随着样本的输入而被训练,但是有一个开关来控制哪个解码器被训练,这取决于是需要简单的还是复杂的输出。
这两种方法通常都工作得很好,但与数据标记方法相比,双解码器方法往往会产生更独特的对比结果,这意味着简单的翻译变得更简单,复杂的翻译变得更复杂。
“金融服务业中的机器翻译:案例研究”
由努恩齐亚蒂尼 【论文在此】
这张关于金融领域机器翻译实施的海报是由 Welocalize 的同事 Mara Nunziatini 展示的,该作品涵盖了在受监管的服务行业中使用机器翻译所面临的技术和实践挑战。本文描述了从试验阶段到生产的过程,以及这种转变如何影响后期编辑、供应商和公司本身。
“用于机器翻译的记忆增强神经网络”
由科利尔&蜜蜂 【博文在此】
记忆增强神经网络 (MANNs)类似于我们的标准 RNNs,不同之处在于它们将计算与记忆分开——内部模型记忆(像它的隐藏状态一样)存储在实际模型的外部,在一组文件中。有趣的是,以前的研究表明,MANNs 有时比 RNNs 学习得更快,概括得更好,但在实践中,它们很少用于像 MT 这样的现实世界任务。在这里,作者通过受 MANNs 启发的附加功能扩展了经典的注意力编码器-解码器。作者有一篇写得很好的博客文章,详细介绍了他们的工作(链接)。
“呼吁谨慎选择子字合并操作”
作者丁等 【此处论文】
NMT 模型从根本上受限于它们的词汇规模——它们只能理解输入单词并生成有用的输出单词,如果它们在它的词汇中的话。这使得传统的基于单词的 NMT 容易受到【OOV】问题的影响,在这种情况下,它不知道如何处理未知的输入单词,当然也不能产生新的单词。处理 OOV 问题的一种常见方法是在子单词级别表示单词,这是有意义的,因为许多单词是更常见的子单词的组合。这浓缩了词汇表,允许潜在的新词生成,并且在形态学上有意义。
给定一个语料库,决定一组子词的最常见算法是(BPE)字节对编码,它连续合并语料库中最常见的字节对,直到达到一定数量的合并。问题是 BPE 合并数参数在许多 NMT 项目中没有得到太多关注,大多数论文默认使用 16k 或 32k BPE 合并操作。本文论证了使用此参数的次优值可能会导致模型成本高达 4 个 BLEU 点,并强调了在构建 NMT 模型时需要处理这一重要的额外超参数,以进行显式优化。**
会议第 5 天——研究讲座
“在神经和统计机器翻译中流利地识别不适当的输出”
作者马丁代尔等人 【论文在此】
在评价翻译质量时,两个核心概念是翻译 流畅 和翻译 充分。流利指的是母语人士对译文的接受程度或流利程度,包括良好的语法和正确的拼写。恰当性指的是译文在源句中捕捉到预期意思的程度。关于 NMT,你首先要了解的一件事是,与它基于统计的前身(SMT)相比,它更经常地产生非常流畅和听起来自然的翻译,而不一定是足够的或相关的。SMT 的情况正好相反。识别“流利不充分”的句子是本文的重点。虽然它们不经常出现,因此不会严重影响表现得分,但在某些领域,流利性不足的输出是非常危险的,流利性可能会使用户更容易相信翻译并被误导。
第一步是找出问题的范围,并能够预测它何时发生。为了预测流利程度,一种常见的方法是使用语言模型,通过句子概率(稍微修改一下,以突出非常罕见的单词的影响)对文本的语法进行评分。为了预测充分性,显而易见的工具是 BLEU 分数。但是 BLEU 也包含了一个流畅性的因素,所以如果你看到一个低的 BLEU 分数,并不能立即清楚流畅性或充分性是问题所在。作者为 BLEU 增加了一个 向量包句子相似度得分 ,它可以有效地捕捉机器翻译输出中信息丢失或出现幻觉的情况。这些为机器翻译输出提供了多组数字分数,但是由于您实际上需要两组二进制标签——流利与不流利以及适当与不适当——您需要根据参考翻译来设置阈值以生成标签。
作者发现,对于类似的质量,SMT 模型的流畅不充分预测比 NMT 少。总的来说,这是一个非常罕见的问题——在他们的实验中,最多只有 2%的翻译出现错误。但是,我们仍然应该关心这个具体问题,因为它似乎是 NMT 的一个固有特点,我们可能无法彻底根除它。此外,您可能并不总是有更多的数据可以扔给模型,在这种情况下,这些错误的比率会更高。罕见的错误也可能是危险的——如果您处理数百万个翻译请求,您仍然会遇到成千上万个这样的错误。最后,罕见的错误可能本质上更危险,因为当它们出现时,用户不会警觉或怀疑。
如何进一步降低这些错误的发生率?通过普遍提高模型质量,例如通过添加更多的训练数据或进行领域适应:随着 BLEU 分数的提高,NMT 系统中的流畅性错误率显著下降。提高训练数据和测试数据之间的相似性尤为重要。最后,改进我们识别这些错误的方法也是一个有希望的方向,因为如果我们能够准确地识别它们,就有可能在 NMT 模型的未来迭代中明确地训练它们。
“用于翻译成形态丰富的语言的字符感知解码器”
作者 Renduchintala 等人 【此处论文】
第一个翻译系统开始使用 单词级表示——模型的输入是整个单词,输出也是在单词级生成的。另一个极端是 字符级表示 ,其中模型只处理字符。这是有帮助的,因为对于字符,您需要处理的词汇要少得多,而且您可以获得更快的 softmax 计算,但是大的缺点是您必须建模更长的序列(因为每个字符都被视为一个单独的标记)。当然,文字中有信息,因为人类将字符排列成文字,而只有字符的表示法会丢失所有这些信息。一种流行的中间解决方案是在子词级别表示文本,这种技术因字节对编码而流行。
在这里,作者探索了 字符感知表示 ,一种结合字符级特征和单词级嵌入的中间解决方案。已经有工作将这个概念应用到源大小的单词嵌入层,但是令人惊讶的是,在目标端没有发现类似的增益。如果能成功地将字符意识扩展到目标方,那就太好了,因为翻译模型将能够根据需要生成他们以前从未见过的新单词。
天真地从单词嵌入切换到 charCNN 特性只会破坏性能(26 到 12 BLEU),但补救措施是组合的组合嵌入方法——您有正常的单词嵌入,并通过门控机制将它们与 charCNN 嵌入组合,这给了您稍高的 BLEU。形态学丰富的语言的性能提高是可以理解的。
“NMT 的后期编辑生产力:对银行和金融领域速度和质量的实证评估”
作者刘勃利等 【论文在此】
这是一项关于翻译生产率的实践研究,涉及一家中型银行 Migrosbank,该银行最近决定采用 NMT。作者进行了一项生产力和质量评估研究,以评估通过使用 NMT 和后期编辑(PE)与仅使用翻译记忆库(TMs)相比,译者的生产力是否更高。
为什么要进行另一项关于后期编辑生产力的研究?之前有很多关于体育及其如何影响质量和生产力的工作,但在这项工作中:
- 它们涵盖了一个新的领域,银行和金融(关于融资和投资的文本)
- 他们着眼于德-法和德-意的翻译,而之前的研究主要集中在英语的翻译上
- 他们在正常的工作环境中使用真正的专业翻译作为实验对象,而不是翻译学生
- 评估如果翻译人员也有翻译记忆库可供使用会发生什么,这在现实世界中是很常见的情况,并且会极大地影响生产率和质量
因此,这项工作试图更接近地模拟翻译人员在工业中面临的真实情况。
在比较 4 名专业内部翻译人员的纯翻译和编辑后条件时,结果显示:
- 后期编辑的方法更快,并且它产生大致相同或稍好的翻译质量。
- 与仅使用翻译模式的场景相比,使用翻译和后期编辑的德语-法语快 60%,德语-意大利语快 10%。
- 根据大学讲师对翻译质量的评分,翻译质量基本相同。他们看不出明显的区别。
- 使用机器翻译可以让翻译团队在内部承担更多的总翻译工作量——在引入 NMT 软件后达到 60%,而在引入软件前只有 40%。外包需求的减少意味着企业可以节省更多成本。
所以度量标准看起来不错,但是翻译人员对使用 MT 感觉如何呢?在这里,他们没有给出任何负面的反馈,也没有对 MT 产生明显的抵触情绪,但这种印象是否完全可靠就不好说了。
其他注意事项:
- 有一些研究表明,编辑高度模糊的匹配(之前翻译的数据中非常相似的字符串)比编辑后的机器翻译更有效。
- WMT 会议最近的结果表明,随着机器翻译质量越来越好,像 BLEU,METEOR,ter 这样的自动评分变得越来越不可靠。因此,也许翻译时间是一个更好的衡量标准。它也更容易为非专家所理解。
“后编辑腔:一种恶化的翻译腔”
由托拉尔 【论文在此】
在翻译中,人工翻译越来越多地对机器翻译输出进行后期编辑,而不是从头开始翻译。这是因为相关的生产率提高,以及同等或更好的质量(就误差而言)。然而,后期编辑(PE)的翻译与从零开始(HT)的人工翻译会有质的不同吗?这篇演讲探讨了这个有争议的话题。
前提是,我们可能期望这两种风格的翻译在理论上产生不同的结果。使用 PE,翻译者被机器翻译的输出所引导,所以 PE 应该包含某种机器翻译的足迹。因为足迹在那里,我们知道机器翻译的问题,那么我们可以得出结论,应该优先选择人工翻译。然而,在实践中,研究报告表明 PE 的质量与 HT 相当,甚至更好。但是质量到底是什么?它通常以错误的数量来衡量…但这就是质量的全部吗?
- 一项研究表明,后期编辑翻译中的术语更接近纯机器翻译,而不是人工翻译。
- 另一项研究表明,对等翻译中的词汇变化比人工翻译中的词汇变化小,这可能是因为机器翻译系统选择最常用的术语作为最佳翻译。
- …但另一项研究发现,不可能区分对等翻译和对等翻译(无论是人类法官还是分类员)。
所以模式还不清楚。这项研究检查了 3 个以前出版的系统,SMT/RBMT,RNNs 和 TNNs,因为不同系统的输出之上的后期编辑可能会导致不同的翻译模式。
总的来说,趋势是 PE 使 MT 看起来更像人类生成的目标语言,但不太达到人类的水平,最常见的排名是 HT>PE>MT,所以,后期编辑不能完全恢复 MT 和 HT 的差异,PE 翻译与 HT不同(无论是轻度后期编辑还是重度摄像后期编辑)。也就是说,对等翻译是:
- 更简单,具有更低的词汇种类和词汇密度(其中 词汇密度 =内容词超过总词数);实词是非填充词,如名词、形容词、动词)
- 长度比例更加标准化。Length ratio 是源/目标长度,以单词为单位;人类翻译在长度方面产生更多的可变性。
- 似乎受到源语言句子的更多干扰。
在本研究中,人工翻译在质量上优于 PE。但是先前的工作已经表明 HT≥PE 中的错误数量,因此似乎我们在错误数量和翻译原则之间有一个折衷。在某些领域,PE 可能比 HT 更适合,比如技术内容,在这些领域,严格的准确性和误译可能比语言多样性更重要。有趣的是,语言多样性也是专家译者的一个标志(新手或非专家,例如 TED talks,倾向于更直译,而专家可能会引入更多的可变性)。
鉴于这些差异,考虑使用这些特征构建分类器来区分 PE/MT 和 ht 可能是有意义的。此外,也许如果你把这些信息给后期编辑,他们可能会随着时间的推移学会改进这些模式,并生成语言上更丰富的后期编辑。然而,如果 PE 的要点是生产率,这将受到负面影响。可能有办法应对语言多样性的 PE 冲击——例如,通过增加温度超参数,你可以从 NMT 模型中获得更多样化的翻译,从而导致 softmax 概率的更大传播。
“理解多语言神经网络模型中的句法和语义转移”
by Bisazza 【纸在此】
最近有很多关于语言和翻译的多语言神经模型的有趣工作。事实证明,在多种语言上训练单个模型是可能的,基本上不需要做任何特殊的事情(比如改变模型的架构)。例如,在多语言翻译中,模型工作所需的唯一变化是向源句子添加一个语言代码标记,告诉模型输入应该翻译成哪种语言。多语言对于低资源语言来说是一个非常有趣的途径,因为您可以使用一种语言对的并行数据来提升其他语言对的翻译性能。甚至有可能将这种技术用于 零镜头翻译 ,在这种情况下,您可以为没有数据的语言对生成翻译。
值得注意的是,与针对特定语言(针对语言模型)或语言对(针对翻译)训练的模型相比,针对多语言数据的训练有时会提高性能,这似乎表明这些多语言模型学会了跨语言共享某种知识或表示。在多语言的人类思维中,语言信息被储存在一起,并在所有层面(语音、句法、语义)进行跨语言的交互。这个演讲调查了类似的现象是否会发生在我们建立的神经多语言模型中。
为什么我们期望多语言 NMT 模型共享独立于语言的语言知识?主要的证据是,多语言模型有时(但神秘的是,并不总是)对性能有帮助,所以它们一定在做正确的事情。我们还知道,句法知识是由神经语言模型隐式捕获的(它们对什么是语法和什么不是语法有很好的理解,尽管这不是由模型显式编码的)——因此,也许还存在跨语言语法。
此外,理论上,只要有可能,多语言模型共享表示是经济的,因为拥有一些共享的隐藏层参数意味着它可以将其他参数用于其他任务。也有先前的工作,通过绘制不同语言句子向量的投影,显示了一些中间语言的证据,并显示句子组织成语义意义簇,而不管语言如何——相同句子翻译成不同语言的译文聚集在一起。这表明出现了独立于语言的意义,一种跨语言的意义空间。
真正发生了多少有意义的语言迁移?选项似乎是:
- ****不转移或很少转移。该模型已经找到了一种方法来压缩它对不同语言的理解,但这里没有太多有意义的交互。
- 浅转移。很大程度上独立系统的压缩,加上一些语言间的信息泄漏。如果是这样,共享的是什么样的信息?
- 深度转移。该模型已经学习了类似数据驱动的国际语言或通用语法的东西。
为回答这些问题而进行的实验有:
- 多语言依存解析实验。
用 mBERT(BERT 的多语言版本,一种流行的基于深度转换器的双向语言模型,常用于迁移学习)探索跨语言解析器迁移。多语言 NLP 模型通常在一些下游任务中进行评估;在这里,作者检查了 mBERT 是否有助于基于图的依赖解析任务。结果表明,简单地将语言模型暴露给具有共享隐藏层参数的非并行语言混合,确实会导致共享的语法空间,并且性能的提升对于真正低资源的语言尤其有利。关于特定的语言对,有一些有趣的结果——语言对的关联性似乎没有像你预期的那样影响迁移学习。例如,即使训练语言包括相关语言朝鲜语,日语的表现仍然很差。
2。多语言远程协议实验。
跨语言互动在双语者中被广泛研究,有证据表明句法信息储存在一个共享的系统中。例如,有证据表明 句法启动——新接触一种语言中被动语态的双语受试者(L1),倾向于在他们的另一种语言中使用被动语态(L2)。也许我们的多语言模型做一些类似的事情。
用于研究这一点的探测任务是 远程协议 。一致涵盖了主谓一致、数量一致、性别一致等语言现象。例如,给出句子“在森林里迷路的男孩被找到了”,模型必须选择正确的形式来完成句子(在这种情况下,男孩们被找到)。协议任务在两种类型的句子上运行:正常句子和没有语义线索的无意义句子(因此迁移学习将真正必须拾取语法信息,而不是使用语义作为拐杖)。
这里的问题是:接触辅助语言 L1 是否能提高相关目标语言 L2 的协议准确性?为了评估这一点,您首先在两种语言的混合上训练一个语言模型(助手 L1 +目标 L2),并在 L2 协议基准上测试。模型设置是一个 2 层 LSTM 模型,它是在维基百科语料库上训练的。此测试的最佳条件可能是 L1 和 L2 关系密切(例如,法语/意大利语),而 L2 资源不足。
有趣的是,结果显示在正常句子上有很小的收获,但在无意义的句子上没有收获,这表明纯粹的语法知识没有被显著地转移。因此,虽然 mBERT 改善了一些东西,但在控制实验中,当消除语义线索时,隐性语法知识的转移是有限的或没有。
这里需要进一步的实验,因为也许数据或模型很小,或者任务太复杂(“一致”涵盖了太多的现象)。也可以尝试不同的词汇或不同的训练方式(例如,先训练法语,然后意大利语;而不是同时)。
3。词性和依存分析树实验。
所以,看起来语法知识并没有在不同的语言之间转移……基本的句法范畴被共享了吗?
有人建议多语模型学习语际词性——如果你观察隐藏层激活的 tSNE 图,用不同词性(POS 名词、动词等。),你会看到根据词类标签和单词的语义的聚类,与语言无关。所以在某种程度上,看起来我们得到了跨语言的语义聚类和共享,但是如何最好地量化这种共享呢?
为了回答词性是否可以被相同的神经激活识别的问题,诊断词性分类器在 L1 上被训练,并且在 L2 上被测试(对于一些不同的语言对)。对于更高级的句法类别——依存标签,完成了类似的分类任务。词性和依存性标记数据取自通用依存性树库。
有趣的是,这也证明效果很差——这里没有太多转移的证据,更高级别的依赖信息根本没有被转移。也没有任何语言相关模式——法语-意大利语迁移比法语-俄语迁移更糟糕。因此,语言相关性并不意味着更好的迁移。此外,令人惊讶的是,你训练的输入语言的数量也不意味着更好的迁移。唯一积极的结果是,当目标是翻译成第三种语言(例如法语/意大利语-英语)时,有一些 POS 转移的证据。
因此,多语言模型的工作不够一致,我们也没有真正理解它们。这意味着它们还不是低资源语言的灵丹妙药。
在多语言模型中,还需要在(积极)迁移和(消极)干扰之间找到适当的平衡——在正常系统中建模良好的语言可能会因为其他语言的存在而开始恶化,因为模型不再有足够的能力来处理这种语言。
总的结论是,仅仅凭借用多语言数据训练我们当前的模型,没有真正的激励让模型学习任何深层意义上的共享。也许我们不应该检查一个模型是否共享一个表示空间,而是应该简单地强迫它这样做,或者以某种方式激励这个结果。也许我们可以做些什么来鼓励模型学习更深层次的共享表征,比如对迫使他们从不同语言学习多种东西的任务进行训练。在架构方面也有工作要做,可能涉及参数的元学习,即明确学习哪些参数应该和不应该在训练多语言模型时共享。
MachineHack,预测医生的咨询费黑客马拉松

MachineHack.com
最近我参加了一个在线机器学习黑客马拉松,它使用机器学习来预测印度医生的咨询价格。尽管我没有取得很好的预测/结果,但这是一次巩固过去几个月所学知识的学习机会。无论如何,对于那些不知道的人来说,我来自一个制药背景,正在通过自己的课程学习数据分析技能。如果你有兴趣涉足这一领域,请务必查看我的课程表这里。
让我们直接进入黑客马拉松吧。这是一个相当小的数据集,有 5961 行和 7 个独特的特征。
- 医生的资格
- 医生多年的经验
- 医生简介
- 患者给出的评级
- 包含医生其他信息的 Miscellaeous _ Info
- 地点(医生所在地的地区和城市)
- 医生收取的费用(因变量)
首先,导入所有依赖项和数据集
import numpy as np
import pandas as pd
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import OrdinalEncoder
from sklearn.model_selection import train_test_split
from sklearn.metrics import make_scorerdf = pd.read_csv("Final_Train.csv")
查看数据以了解给出的信息
df.head()

显然,在任何建模过程之前,需要进行一些数据清理。让我们先来看看这个定型数据集中缺失值的数量。
round(df.isnull().sum()/len(df)*100,2)

上图显示了每列缺失值的百分比。我将单独处理这些缺失的值,所以现在只需记住这些值。
我总是喜欢先从最简单的任务开始,然后再处理更复杂的问题。这里的“Experience”列看起来很简单,因为它只需要从字符串中提取整数值。
# Extract years of experience
df["Experience"] = df["Experience"].str.split()
df["Experience"] = df["Experience"].str[0].astype("int")
第一行代码将字符串分割成一个列表,而第二行代码提取列表的第一个元素并将其转换成整数。
接下来,通过将城市和地区分开,可以很容易地处理“地点”列。
# Extract cities
df["Place"].fillna("Unknown,Unknown",inplace=True)
df["Place"] = df["Place"].str.split(",")
df["City"] = df["Place"].str[-1]
df["Place"] = df["Place"].str[0]
在提取之前,我用字符串‘Unknown,Unknown’替换了该列中所有缺失的值来表示它们。旁注,有时给缺失值一个单独的类是一个好主意,而不是依赖于缺失值插补技术,如均值/中值/众数。例如,在该数据集中,印度的一些地区可能在数据收集期间没有列出它们的位置,但是它们可能来自同一个地区。接下来,在','处拆分字符串,并使用列表的最后一个元素创建一个新列' City '。
转到“评级”列,记住该列有超过 50%的缺失值。在任何其他处理之前,我们必须处理丢失的值。
# Seperate Ratings into bins
df["Rating"].fillna("-99%",inplace=True)
df["Rating"] = df["Rating"].str[:-1].astype("int")bins = [-99,0,10,20,30,40,50,60,70,80,90,100]
labels = [i for i in range(11)]
df["Rating"] = pd.cut(df["Rating"],bins=bins,labels=labels,include_lowest=True)
缺失值被替换为-99%,以区分它们。然后,假设 91%的评级与 99%的评级没有显著差异,我将它们分组到大小为 10 的箱中。缺失值将属于 0 类,而 0-9%将属于 1 类,10-19%将属于 2 类,依此类推。df[“Rating”].value_counts().sort_index()显示分布情况。

对于“资格”栏,它包括医生的各种资格,没有任何标准化的报告方法。我首先进行常规的拆分,并尝试了解不同术语在本专栏中出现的频率。
# Extract relevant qualification
df["Qualification"]=df["Qualification"].str.split(",")
Qualification ={}
for x in df["Qualification"].values:
for each in x:
each = each.strip()
if each in Qualification:
Qualification[each]+=1
else:
Qualification[each]=1
说实话,现阶段我挺迷茫的。如果您查看Qualification字典,大部分限定条件在整个数据集中只出现了一次,一些术语实际上指的是类似的限定条件,但被单独计算。例如,有条目“MBA-医疗保健”和“MBA ”,我认为它们指的是同一个资格。这是非标准化数据输入或数据收集的问题,我相信数据科学家/分析师每天都会看到这一点。我决定采用最简单的方法,简单地确定出现次数最多的前 10 项资格。
most_qua = sorted(Qualification.items(),key=lambda x:x[1],reverse=True)[:10]
final_qua =[]
for tup in most_qua:
final_qua.append(tup[0])for title in final_qua:
df[title]=0
for x,y in zip(df["Qualification"].values,np.array([idx for idx in range(len(df))])):
for q in x:
q = q.strip()
if q in final_qua:
df[q][y] = 1df.drop("Qualification",axis=1,inplace=True)
最终结果是数据集中 10 个最高频率鉴定的虚拟变量。
现在是“简介”专栏。如果您记得的话,我们在这一列中没有任何缺失值。一个快速的value_counts() 检查产生了这个。

这真的很棒。因为整列只有 6 个类,所以 oneHotEncoding 应该可以完成这个任务。在此之前,对我们创建的“City”列的快速检查显示,它也包含少量的类(10)。然而,奇怪的事情突然出现了。

不知从哪里冒出了一个“e”条目,我猜这应该是个错误(错误的条目)。我发现问题发生在第 3980 行,于是我将该行的“城市”和“地点”列改为“未知”。
df["City"][3980] = "Unknown"
df["Place"][3980] = "Unknown"
最后的检查。

好多了。然后,通过只使用一行代码,我们将能够同时为‘Profile’和‘City’列生成虚拟变量。
# Get dummies
df = pd.get_dummies(df,columns=["City","Profile"],prefix=["City","Profile"])
最后,这里是“杂项信息”栏的简短预览

考虑到丢失值的百分比很高(43.95%),并且我找不到该列的任何相关性(我不是 NLP 专家),我决定放弃该列,直接删除它。当然不是最好的方法,但我现在会这么做。
df.drop("Miscellaneous_Info",axis=1,inplace=True)
一旦我们完成了数据预处理,下一步自然应该是数据可视化。注*有些人宁愿在建模前不看你的数据,以防止分析师引入任何偏见,而是看每个人自己的数据。

大多数人会认为医生的经验和他们收取的费用之间有某种联系。确实有,但可能不是我们期望的那样。平均费用随着经验的增加而增加,但在大约 25 年的经验时达到峰值,然后,平均费用随着经验的进一步增加而减少。

评级是另一个值得关注的有趣变量。如果您还记得,我们将评级分为大小为 10 的容器,包括最小值。例如,bin 5 将是 40–49%的等级,bin 10 将是 90–100%,bin 0 将只是数据集中缺失的值。如您所见,高评级与高收费并不相关(事实上,低收费可能是高评级的原因!),而收取的最高平均费用实际上为 30–60%。配色方案描述了每个箱子中的中间体验水平,深绿色代表较高的中间体验。bins 4 和 bin 5 中的平均经验分别为 27 年和 31 年,而 bin 10 中的平均经验只有 14 年,证明了医生在这些 bin 中收取更高费用的能力。


这里有很多东西需要解开。
- 不同城市的医生收费不同
- 对于大多数城市来说,每个城市内不同医生档案的分布是相似的
- 所有城市未知的条目实际上都是皮肤科医生!
之前我提到丢失的数据可能不是随机的,可能是由于数据收集过程,这是一个很好的例子。不知何故,一些城市的皮肤科医生没有记录他们的位置!
注意,所有的可视化都是在 Tableau 中完成的,因为我正在学习这个工具。您可以使用 python 或任何其他可视化工具。
最后,我们可以对我们的数据建模,可以做一些很酷的机器学习。我决定使用支持向量机来完成这项任务,因为它可以用于线性和非线性问题。少量的数据也不能保证使用神经网络。
在实现算法之前,我们必须对分类变量进行编码,并对其特征进行缩放。
X = df.drop("Fees",axis=1)
y = df["Fees"]# Encoding
enc = OrdinalEncoder()
X = enc.fit_transform(X)X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2)# feature scaling
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
正在实施 SVR …
# support vector machine
from sklearn.svm import SVR
m = SVR(gamma="scale")
m.fit(scaler.transform(X_train),y_train)
基于 hackathon 站点,根据均方根对数误差(RMSLE)对提交的内容进行评估,更具体地说,1-RMSLE.
def score(y_pred,y):
y_pred = np.log(y_pred)
y = np.log(y)
return 1 - ((np.sum((y_pred-y)**2))/len(y))**1/2# Prediction
y_pred = m.predict(scaler.transform(X_test))
score(y_pred,y_test)
我们对测试集的预测给了我们一个分数0.7733490738717279。如果你看一下排行榜,得分最高的是0.76162342。当然,我们的测试集不是用于排行榜的真实测试集,不具有可比性。但是它给了我们一个进一步优化的标准。
进行 GridSearchCV 是进行超参数调优的一个很好的方法,但是要注意计算能力,特别是对于像 SVM 这样不能很好伸缩的算法。
# Define own scorer
scorer = make_scorer(score,greater_is_better=True)# Hyperparameter tunning
parameters = {"C":[0.1,1,10],"kernel":["linear","rbf","poly"]}
reg = GridSearchCV(m,param_grid=parameters,scoring=scorer,n_jobs=-1,cv=5)reg.fit(X_train,y_train)
运行reg.best_params_给出了提供最佳得分的超参数组合。这种情况下最好的超参数是 C=10,kernel="rbf "。注*定义您自己的计分器以在 GridSearchCV 中使用,因此它使用计分矩阵进行优化。
最后。
y_pred_tuned = reg.predict(scaler.transform(X_test))
score(y_pred_tuned,y_test)
这里得到的分数是0.8034644306855361。略有改善,但仍然是改善。使用排行榜测试集,这意味着得分为0.72993077,排名 62/169(前 40 个百分点)
这就是了。机器学习竞赛的完整演练。为了取得更好的成绩,我还可以做更多的事情,做更多的功能工程,使用其他算法,但不幸的是,我没有在比赛结束前做到这一点。做这样的比赛有助于巩固你所学的知识,也是练习的好方法。除非你的目标是奖励,否则获胜往往并不重要,而这才是最有成就感的过程。
所有的代码都可以在我的 GitHub 这里找到。
通过实践学习的机器
强化学习与人工智能之路

Go Champion Lee Sedol (right) playing against AlphaGo in 2016 (source)
在我 25 岁左右的时候,我第一次学会了打网球。关于网球的事情是,一旦你开始,就很难让球落在球场的对面(而不是球场后面的树上)。诀窍是在击球的瞬间,大致垂直地握住球拍,并给予球足够的上旋力。经过几个小时的训练和与朋友的练习,我慢慢学会了如何在击球时将球拍调整到合适的角度。
我的大脑能够学习一项新的任务,打网球,主要是通过频繁的练习。它是怎么做到的?机器能做同样的事情吗?机器可以边做边学吗?
人工智能:机器如何学习
人工智能大致有两种不同的方法,研究人员称之为专业化和通用方法。
例如,图像分类的最新进展就是高度专业化的人工智能形式。图像分类模型通常也非常复杂: AlexNet 例如,它在计算机视觉领域最有影响力的论文之一中提出,包含 6000 万个自由参数,需要用大量人类标记的训练数据进行调整。尽管这种系统可以在现实世界中得到有用的应用,但对标记训练数据的需求,以及专业化的程度,使它们在范围上受到了根本的限制:例如,一个经过训练可以区分猫和狗的人工智能系统,无法在 x 光胸片中检测出肺炎。不用说,这样一个系统甚至不知道这些概念是什么意思。称这样一个系统是智能的几乎有点言过其实。

Chest X-ray (left), overlayed with predicted pneumonia probability density map (right) (source)
通用人工智能是一种完全不同的方法。这里的想法是开发更简单,同时更通用的算法和方法,让机器在没有人类参与的情况下学习它们的环境。在我看来,强化学习领域是当今最有希望实现通用人工智能的方法之一。那是什么?
强化学习:学习做什么
强化学习意味着学习做什么:将情境映射到行动。如果这听起来很熟悉,那是因为这本质上是我们人类一直在做的事情。这种想法从根本上不同于监督和非监督机器学习。让我解释一下。
在监督学习中,机器本质上学会给出“正确”的答案:狗还是猫?肺炎还是没有肺炎?在无监督学习中,机器根据现有数据点的相似性(但没有标签)来学习数据的结构:例如,在你的数据库中有五种不同类型的客户,下面是他们的偏好和行为如何不同。强化学习不是做这两件事——它是学习在给定的情况下做什么。这是一种非常通用同时又非常强大的方法:它被设计成甚至可以在完全未知的领域工作。
从技术上讲,RL 问题被框定为所谓的马尔可夫决策过程,这基本上意味着有两个‘当事人’,代理和环境。在任何给定的时间,环境都处于某种状态。代理执行改变其环境状态的动作,并获得回报,回报可以是积极的或消极的。代理人的目标是选择行动,以便在任何给定时间最大化他们未来总报酬的期望值。代理决定动作的逻辑被称为策略。强化学习问题中的主要挑战是代理人学习最优策略,这是将最大化未来回报期望的策略。

Illustration of a Markov decision process (source)
这都是高度理论化的,所以希望一些例子能阐明这个想法。以下是可以被公式化为强化学习问题的所有例子:
- 收集空罐子的清洁机器人。
- 电厂中控制核反应堆的系统。
- 一个正在学习走路的机器人。
- 一种交易股票的系统,旨在实现利润最大化。
- 学习下棋的机器,如国际象棋。
请注意,强化学习植根于心理学领域:政策与刺激反应的心理学概念有关,而奖励则对应于一种快乐或痛苦的形式。

Photo credit: Luca Baggio, Unsplash
探索与利用的权衡
强化学习的一个典型特征是存在着探索与利用的权衡:在同样的情况下,一个智能体是应该坚持一个已知回报的行为(利用),还是尝试一个新的行为以期获得更高的回报(探索)?
考虑所谓的多臂强盗问题:给定一个吃角子老丨虎丨机(环境),比方说,有 10 个臂,每个臂产生不同的、未知的支付金额(奖励)分布,你(代理人)如何决定玩哪个臂?一个被称为贪婪策略的策略是,总是在你过去看到最高回报的地方拉手臂。贪婪的策略纯粹是剥削。为了给你的策略注入一些探索,你可以以小概率(我们称之为ε)随机选择一只手臂:这种策略被称为ε-贪婪。
如果其他分支给出更高的回报,那么贪婪将帮助你找到它们,同时充分利用你已经找到的高回报分支。贪婪是解决探索与剥削两难的一种方式。如果收益随时间变化,这种偶尔随机探索的策略尤其重要。我们称这样的问题为非平稳的,它们通常是强化学习的标准。贪婪的策略可能会错过收益转移的时刻;epsilon-贪婪策略适应。
在我继续之前,让我简单地指出,这里也有一个微妙的人生教训,简单地说就是这个:不时地尝试一些随机的事情。不要墨守成规,即使你的墨守成规有很好的回报。你永远不知道是否有别的东西可以给你更高的回报,你可能会通过一些随机的探索找到它。

Kasparov moving his first piece in the first game of the rematch against Deep Blue (source)
最优策略与计算可行性
原则上,给定无限的时间和计算能力,代理可以学习任何情况下的真正最优策略:这样的代理永远不会出错!
然而实际上,时间和计算能力都是有限的。因此,代理通常只能用逼近最优策略。例如,在游戏中,代理可以通过忽略很少发生的情况来加快计算速度:如果它很少发生或从不发生,为什么要费心去想如果发生了该怎么办?
1997 年,加里·卡斯帕罗夫决定与 IBM 的“深蓝”再赛一场(一年前他赢了一场与这台机器的比赛)。正如内特·西尔弗在《信号与噪音》一书中解释的那样,卡斯帕罗夫的策略是“将程序带出数据库,让它再次盲目飞行”。换句话说,他试图迫使游戏进入一种他可以预期深蓝没有学到最优策略的情况。这就是他在第一轮比赛中的第三步所做的,他忽略了对他的骑士的威胁,而是移动了一个棋子,这是一个非常不寻常的举动。西尔弗指出,棋盘的最终状态也很不寻常,在大师级比赛中只出现过一次。
比赛是怎么结束的?卡斯帕罗夫赢得了这一轮比赛,这可能是也可能不是因为他不寻常的举动迫使深蓝盲目飞行。坏消息是:这是卡斯帕罗夫赢得的最后一轮比赛。深蓝赢了这场比赛,这使得 1997 年成为艾征服国际象棋的一年。
向机器学习:传奇之举 37
让我们离开象棋的世界,进入围棋的世界。在具有历史意义的 2016 年 Deepmind 的 AlphaGo 与世界顶级围棋选手 Lee Sedol 的围棋比赛中,第二局发生了奇怪的事情。AlphaGo 先走 37 步看起来是个失误。评论员和专家不理解这一举动。Sedol 花了超过 15 分钟来决定一个回应。此前输给 AlphaGo 的欧洲围棋冠军范辉后来评论说:“(T2)这不是人的举动。我从未见过人类玩这一招。
第 37 步不是一个错误。人类不理解这步棋,仅仅是因为 AlphaGo 预见了那么多步棋。事实上,AlphaGo 赢得了比赛,以及整场比赛。它发现了一步人类从未想到过的棋,改变了当今最好的棋手对围棋的看法。
当然,围棋只是一种游戏——但诸如药物发现、疾病检测或灾难预测等问题呢?这里的信息是,人工智能有可能为我们指出新的、未经探索的解决方案,以解决我们从未想到的问题。

Photo credit: Mauro Mora, Unsplash
学习就是做人
所有的经历都被我们的新视野丰富地交织在一起,然后新的联系开始出现。城市人行道上流淌的雨水将教会钢琴家如何流动。一片随风轻飘的树叶会教会控制者如何放手。一只家猫会教我如何移动。所有的时刻都变成了每个时刻。—乔希·怀兹金,《学习的艺术》
在《学习的艺术》一书中,乔希·怀兹金讲述了他年轻时成为国际象棋冠军,后来成为武术冠军的经历。他解释了掌握象棋如何帮助他学习武术,反之亦然。建立联系,将一个主题的知识转移到另一个主题的能力,可能是我们拥有的最强大的技能之一,当然也是人工智能极难模仿的技能。
事实是,机器不善于将一项任务中的专业知识转移到另一项任务中。此外,他们没有直觉的概念,直觉在我们以前没有解决的任务中指导我们人类。即使强化学习领域迄今为止已经显示出极其有前途的结果,我相信这可能是我们在走向通用 AI 的旅程中需要克服的两个主要限制。
资源
- 理查德·萨顿和安德鲁·巴尔托,强化学习
- 内特·西尔弗,信号和噪音
- 乔希·威茨金学习的艺术
MachineX:使用 NumPy 和 Pandas 进行数据清理

在这篇博客中,我们将学习如何用 NumPy 和 Pandas 进行数据清理。
大多数数据科学家仅将 20%的时间用于实际数据分析,80%的时间用于查找、清理和重组海量数据,这是一种低效的数据策略。
数据科学家最初被雇佣的原因是开发算法和建立机器学习模型,而这些通常是他们最喜欢的工作部分。然而,在当今的大多数公司中,数据科学家 80%的宝贵时间都花在了查找、清理和重新组织海量数据上。
如果你刚刚进入这个领域或者计划在这个领域发展你的职业生涯,能够处理杂乱的数据是很重要的,无论这意味着缺少值、不一致的格式、畸形的记录还是无意义的离群值。
在本教程中,我们将使用 python 的 NumPy 和 Pandas 库来清理数据,并看看我们可以在多少方面使用它们。
数据集
我们正在使用一些常见的数据集来探索我们的知识,每个数据集都符合我们正在使用的清洗技术,因此您也可以下载自己的数据集并按照说明进行操作。
以下是我们将使用的不同数据集,您可以通过以下链接下载这些数据集,也可以从 githubRepo 直接下载:
- BL-Flickr-Images-Book.csv —包含大英图书馆书籍信息的 csv 文件
- university_towns.txt —包含美国各州大学城名称的文本文件
- olympics.csv —总结所有国家参加夏季和冬季奥运会的 csv 文件
注意:我正在使用 Jupyter 笔记本,推荐使用。
让我们导入所需的模块并开始吧!
>>> import pandas as pd
>>> import numpy as np
现在,让我们在这两个模块的帮助下开始清理数据。我们导入这两个模块,并指定 pd 和 np 作为对象来使用它们。
删除数据帧中不需要的列
为了从数据帧中删除列,Pandas 使用了“ drop ”函数。Pandas 提供了一种使用[drop()](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.drop.html)函数从DataFrame中删除不需要的列或行的简便方法。让我们看一个简单的例子,我们从一个DataFrame中删除了一些列。让我们从 CSV 文件“BL-Flickr-Images-Book.csv”中创建一个DataFrame。在下面的例子中,我们传递了一个到pd.read_csv的相对路径,这意味着所有的数据集都在我们当前工作目录中名为Datasets的文件夹中:
>>> dataF = pd.read_csv('Datasets/BL-Flickr-Images-Book.csv')
>>> dataF.head()Identifier Edition Statement Place of Publication \
0 206 NaN London
1 216 NaN London; Virtue & Yorston
2 218 NaN London
3 472 NaN London
4 480 A new edition, revised, etc. LondonDate of Publication Publisher \
0 1879 [1878] S. Tinsley & Co.
1 1868 Virtue & Co.
2 1869 Bradbury, Evans & Co.
3 1851 James Darling
4 1857 Wertheim & MacintoshTitle Author \
0 Walter Forbes. [A novel.] By A. A A. A.
1 All for Greed. [A novel. The dedication signed... A., A. A.
2 Love the Avenger. By the author of “All for Gr... A., A. A.
3 Welsh Sketches, chiefly ecclesiastical, to the... A., E. S.
4 [The World in which I live, and my place in it... A., E. S.Contributors Corporate Author \
0 FORBES, Walter. NaN
1 BLAZE DE BURY, Marie Pauline Rose - Baroness NaN
2 BLAZE DE BURY, Marie Pauline Rose - Baroness NaN
3 Appleyard, Ernest Silvanus. NaN
4 BROOME, John Henry. NaNCorporate Contributors Former owner Engraver Issuance type \
0 NaN NaN NaN monographic
1 NaN NaN NaN monographic
2 NaN NaN NaN monographic
3 NaN NaN NaN monographic
4 NaN NaN NaN monographicFlickr URL \
0 http://www.flickr.com/photos/britishlibrary/ta...
1 http://www.flickr.com/photos/britishlibrary/ta...
2 http://www.flickr.com/photos/britishlibrary/ta...
3 http://www.flickr.com/photos/britishlibrary/ta...
4 [http://www.flickr.com/photos/britishlibrary/ta...](http://www.flickr.com/photos/britishlibrary/ta...)Shelfmarks
0 British Library HMNTS 12641.b.30.
1 British Library HMNTS 12626.cc.2.
2 British Library HMNTS 12625.dd.1.
3 British Library HMNTS 10369.bbb.15.
4 British Library HMNTS 9007.d.28.
当我们使用该方法查看前五个条目时,head()我们可以看到一些列提供了对图书馆有帮助的辅助信息,但并没有很好地描述书籍本身:Edition StatementCorporate Author、Corporate Contributors、Former owner、Engraver、Issuance type和Shelfmarks。
删除列
我们可以通过以下方式删除这些列:
>>> data_to_drop = ['Edition Statement',
... 'Corporate Author',
... 'Corporate Contributors',
... 'Former owner',
... 'Engraver',
... 'Contributors',
... 'Issuance type',
... 'Shelfmarks']>>> dataF.drop(data_to_drop, inplace=True, axis=1)
上面,我们定义了一个列表,其中包含了我们想要删除的所有列的名称。接下来,我们调用对象上的drop()函数,将inplace参数作为True传入,将axis参数作为1传入。这告诉 Pandas 我们希望直接在我们的对象中进行更改,并且它应该在对象的列中寻找要删除的值。
当我们再次检查DataFrame时,我们会看到不需要的列已被删除:
>>> dataF.head()
Identifier Place of Publication Date of Publication \
0 206 London 1879 [1878]
1 216 London; Virtue & Yorston 1868
2 218 London 1869
3 472 London 1851
4 480 London 1857Publisher Title \
0 S. Tinsley & Co. Walter Forbes. [A novel.] By A. A
1 Virtue & Co. All for Greed. [A novel. The dedication signed...
2 Bradbury, Evans & Co. Love the Avenger. By the author of “All for Gr...
3 James Darling Welsh Sketches, chiefly ecclesiastical, to the...
4 Wertheim & Macintosh [The World in which I live, and my place in it...Author Flickr URL
0 A. A. http://www.flickr.com/photos/britishlibrary/ta...
1 A., A. A. http://www.flickr.com/photos/britishlibrary/ta...
2 A., A. A. http://www.flickr.com/photos/britishlibrary/ta...
3 A., E. S. http://www.flickr.com/photos/britishlibrary/ta...
4 A., E. S. [http://www.flickr.com/photos/britishlibrary/ta...](http://www.flickr.com/photos/britishlibrary/ta...)
更改数据帧的索引
Pandas Index扩展了 NumPy 数组的功能,允许更多的切片和标记。在许多情况下,使用数据的唯一值标识字段作为索引是很有帮助的。
例如,在上一节使用的数据集中,可以预计当图书管理员搜索记录时,他们可能会输入一本书的唯一标识符(值在Identifier列中):
>>> dataF['Identifier'].is_unique
True
让我们使用set_index用这个列替换现有的索引:
>>> dataF = dataF.set_index('Identifier')
>>> dataF.head()
Place of Publication Date of Publication \
206 London 1879 [1878]
216 London; Virtue & Yorston 1868
218 London 1869
472 London 1851
480 London 1857Publisher \
206 S. Tinsley & Co.
216 Virtue & Co.
218 Bradbury, Evans & Co.
472 James Darling
480 Wertheim & MacintoshTitle Author \
206 Walter Forbes. [A novel.] By A. A A. A.
216 All for Greed. [A novel. The dedication signed... A., A. A.
218 Love the Avenger. By the author of “All for Gr... A., A. A.
472 Welsh Sketches, chiefly ecclesiastical, to the... A., E. S.
480 [The World in which I live, and my place in it... A., E. S.Flickr URL
206 http://www.flickr.com/photos/britishlibrary/ta...
216 http://www.flickr.com/photos/britishlibrary/ta...
218 http://www.flickr.com/photos/britishlibrary/ta...
472 http://www.flickr.com/photos/britishlibrary/ta...
480 [http://www.flickr.com/photos/britishlibrary/ta...](http://www.flickr.com/photos/britishlibrary/ta...)
每个记录都可以用loc[]访问,它允许我们做基于标签的索引,这是一个行或记录的标签,不考虑它的位置:
>>> dataF.loc[206]
Place of Publication London
Date of Publication 1879 [1878]
Publisher S. Tinsley & Co.
Title Walter Forbes. [A novel.] By A. A
Author A. A.
Flickr URL http://www.flickr.com/photos/britishlibrary/ta...
Name: 206, dtype: object
换句话说,206 是索引的第一个标签。要通过位置访问它,我们可以使用iloc[0],它执行基于位置的索引。
整理数据中的字段
到目前为止,我们已经删除了不必要的列,并将DataFrame的索引改为更合理的内容。在这一节中,我们将清理特定的列,并将它们转换为统一的格式,以便更好地理解数据集并增强一致性。特别是,我们将清洁Date of Publication和Place of Publication。
经检查,目前所有的数据类型都是object dtype ,这大致类似于原生 Python 中的str。
它封装了任何不能作为数字或分类数据的字段。这是有意义的,因为我们处理的数据最初是一堆杂乱的字符串:
>>> dataF.get_dtype_counts()
object 6
强制使用数字值有意义的一个字段是出版日期,这样我们可以在以后进行计算:
>>> dataF.loc[1905:, 'Date of Publication'].head(10)
Identifier
1905 1888
1929 1839, 38-54
2836 [1897?]
2854 1865
2956 1860-63
2957 1873
3017 1866
3131 1899
4598 1814
4884 1820
Name: Date of Publication, dtype: object
一本书只能有一个出版日期。因此,我们需要做到以下几点:
- 删除方括号中的多余日期:1879 [1878]
- 将日期范围转换为它们的“开始日期”,如果有的话:1860–63;1839, 38–54
- 完全去掉我们不确定的日期,用 NumPy 的
NaN:【1897?] - 将字符串
nan转换为 NumPy 的NaN值
综合这些模式,我们实际上可以利用一个正则表达式来提取出版年份:
regex = r'^(\d{4})'
上面的正则表达式是查找一个字符串开头的任意四位数字。上面是一个原始字符串(意味着反斜杠不再是转义字符),这是正则表达式的标准做法。
\d代表任意数字,{4}重复此规则四次。^字符匹配一个字符串的开头,圆括号表示一个捕获组,这向 Pandas 发出信号,表明我们想要提取正则表达式的这一部分。(我们希望^避免[从管柱开始的情况。)
让我们看看在数据集上运行这个正则表达式会发生什么:
>>> extr = dataF['Date of Publication'].str.extract(r'^(\d{4})', expand=False)
>>> extr.head()
Identifier
206 1879
216 1868
218 1869
472 1851
480 1857
Name: Date of Publication, dtype: object
不熟悉 regex?你可以在 regex101.com查看上面的表达式,并在 Python 正则表达式 HOWTOMakeExpressions 阅读更多内容。
从技术上讲,这个列仍然有object dtype,但是我们可以很容易地用pd.to_numeric得到它的数字版本:
>>> dataF['Date of Publication'] = pd.to_numeric(extr)
>>> dataF['Date of Publication'].dtype dtype('float64')
这导致大约十分之一的值丢失,对于现在能够对剩余的有效值进行计算来说,这是一个很小的代价:
>>> dataF['Date of Publication'].isnull().sum() / len(dataF) 0.11717147339205986
太好了!搞定了。!!!
使用 applymap 函数清理整个数据集
在某些情况下,将定制函数应用于数据帧的每个单元格或元素会很有帮助。Pandas .applymap()方法类似于内置的map()函数,只是将一个函数应用于DataFrame中的所有元素。
我们将从“university_towns.txt”文件中创建一个DataFrame:
>>> head Datasets/univerisity_towns.txt
Alabama[edit]
Auburn (Auburn University)[1]
Florence (University of North Alabama)
Jacksonville (Jacksonville State University)[2]
Livingston (University of West Alabama)[2]
Montevallo (University of Montevallo)[2]
Troy (Troy University)[2]
Tuscaloosa (University of Alabama, Stillman College, Shelton State)[3][4]
Tuskegee (Tuskegee University)[5]
Alaska[edit]
我们看到,我们有周期性的州名,后跟该州的大学城:StateA TownA1 TownA2 StateB TownB1 TownB2...。如果我们观察状态名在文件中的书写方式,我们会发现所有的状态名中都有“[edit]”子字符串。
我们可以通过创建一个 *(state, city)* 元组的列表并将该列表包装在DataFrame中来利用这种模式
>>> university_towns = []
>>> with open('Datasets/university_towns.txt') as file:
... for line in file:
... if '[edit]' in line:
... # Remember this `state` until the next is found
... state = line
... else:
... # Otherwise, we have a city; keep `state` as last-seen
... university_towns.append((state, line))>>> university_towns[:5]
[('Alabama[edit]\n', 'Auburn (Auburn University)[1]\n'),
('Alabama[edit]\n', 'Florence (University of North Alabama)\n'),
('Alabama[edit]\n', 'Jacksonville (Jacksonville State University)[2]\n'),
('Alabama[edit]\n', 'Livingston (University of West Alabama)[2]\n'),
('Alabama[edit]\n', 'Montevallo (University of Montevallo)[2]\n')]
我们可以将这个列表包装在一个 DataFrame 中,并将列设置为“State”和“RegionName”。Pandas 将获取列表中的每个元素,并将State设置为左边的值,将RegionName设置为右边的值。
>>> towns_dataF = pd.DataFrame(university_towns,
... columns=['State', 'RegionName'])>>> towns_dataF.head()
State RegionName
0 Alabama[edit]\n Auburn (Auburn University)[1]\n
1 Alabama[edit]\n Florence (University of North Alabama)\n
2 Alabama[edit]\n Jacksonville (Jacksonville State University)[2]\n
3 Alabama[edit]\n Livingston (University of West Alabama)[2]\n
4 Alabama[edit]\n Montevallo (University of Montevallo)[2]\n
applymap()
虽然我们可以在上面的 for 循环中清理这些字符串,但 Pandas 让它变得很容易。我们只需要州名和镇名,其他的都可以去掉。虽然我们可以在这里再次使用 Pandas 的.str()方法,但是我们也可以使用applymap()将 Python callable 映射到 DataFrame 的每个元素。
我们一直在使用术语元素,但是它到底是什么意思呢?考虑以下“玩具”数据帧:
0 1
0 Mock Dataset
1 Python Pandas
2 Real Python
3 NumPy Clean
在这个例子中,每个单元格(' Mock ',' Dataset ',' Python ',' Pandas '等)。)是一个元素。因此,applymap()将独立地对其中的每一个应用一个函数。让我们来定义这个函数:
>>> def get_citystate(item):
... if ' (' in item:
... return item[:item.find(' (')]
... elif '[' in item:
... return item[:item.find('[')]
... else:
... return item
Pandas 的.applymap()只有一个参数,它是应该应用于每个元素的函数(可调用的):
>>> towns_dataF = towns_dataF.applymap(get_citystate)
首先,我们定义一个 Python 函数,它将来自DataFrame的一个元素作为它的参数。在函数内部,执行检查以确定元素中是否有(或[。
函数根据检查相应地返回值。最后,在我们的对象上调用applymap()函数。现在数据框架更加整洁了:
>>> towns_dataF.head()
State RegionName
0 Alabama Auburn
1 Alabama Florence
2 Alabama Jacksonville
3 Alabama Livingston
4 Alabama Montevallo
方法applymap()从 DataFrame 中取出每个元素,将其传递给函数,原始值被返回值替换。就这么简单!
快乐学习!!!!!!!!!
请查看下面的链接,找到对您的 Python 数据科学之旅有所帮助的其他资源:
- 熊猫文档
- NumPy 文档
- 熊猫的创造者韦斯·麦金尼用于数据分析的 Python
- 数据科学培训师兼顾问 Ted Petrou 撰写的熊猫食谱
参考资料:
realPython.com
data quest . io
注:原发布于->https://blog.knoldus.com/machine-x-data-cleaning-in-python/
MachineX:生成式对手网络(GAN)
在这篇博客中,我们将讨论 GAN(生成式对手网络)的基础知识以及它们实际上是如何工作的。

甘是一个喜欢创作的人,喜欢画肖像画或创作交响乐。这和其他深度学习领域相比是很难的。通过电脑或人来识别莫奈的画要比画一幅容易得多。但是它让我们更接近理解智能。GAN 将我们引向近年来撰写的数千篇 GAN 研究论文。在开发游戏时,我们雇佣许多制作艺术家来制作动画。有些任务是例行公事。通过将自动化应用于 GAN,我们可能有一天会专注于创造性方面,而不是每天重复例行任务。
为了理解它们是如何工作的,想象一个盲人伪造者试图创作大师画作的复制品。首先,他不知道一幅画应该是什么样子。
但是他碰巧有一个朋友,他对曾经画过的每一幅杰作都记忆犹新。
GAN 背后的原理是在 2014 年首次提出的。它描述了一个系统,该系统使两个人工智能系统(神经网络)相互对抗,以提高它们的结果质量。
介绍
生成对抗网络(GAN)是一种使用深度学习方法(如卷积神经网络)进行生成建模的方法。
生成建模是机器学习中的一项无监督学习任务。它包括自动发现和学习输入数据中的规律或模式。以便该模型可以用于生成或输出可能已经从原始数据集中提取的新示例。
GAN 是一种训练生成模型的聪明方法,它通过将问题框架化为具有两个子模型的监督学习问题:我们训练以生成新示例的生成器模型。鉴别器模型试图将示例分为真实的(来自域)或虚假的(生成的)。这两个模型在一个零和游戏中一起训练,对抗,直到鉴别器模型被愚弄了大约一半的时间,这意味着生成器模型正在生成似是而非的例子。
在讨论生成式对手网络之前,让我们先讨论一下生成式模型。所以,
什么是生成模型?
我们将回顾生成模型的思想,跨越有监督和无监督的学习范式,以及区别性和生成性建模。
一个典型的机器学习问题涉及到使用模型进行预测
这需要一个用于训练模型的训练数据集,该数据集由多个称为样本的示例组成,每个示例都具有输入变量( X )和输出类标签( y )。通过显示输入的示例,让模型预测输出,并修正模型以使输出更像预期的输出,来训练模型。

什么是生成性对抗网络?
GAN 模型架构包括两个子模型:用于生成新样本的生成器模型和用于分类的鉴别器模型。生成的例子是真实的,来自领域,还是伪造的,由生成器模型生成。
- 发电机。用于从问题域中生成新的合理示例的模型。
- 鉴别器。用于将示例分类为真实(来自域)或虚假(生成)的模型。
发电机模型
生成器模型将固定长度的随机向量作为输入,并在域中生成样本。
该向量是从高斯分布中随机抽取的,并且该向量用于生成过程的种子。在训练之后,这个多维向量空间中的点将对应于问题域中的点,形成数据分布的压缩表示。
这个向量空间被称为潜在空间,或者由潜在变量组成的向量空间。潜在变量,或隐藏变量,是那些对一个领域很重要但不能直接观察到的变量。
在训练之后,生成器模型被保留并用于生成新的样本。

鉴别器模型
鉴别器模型将来自领域的示例作为输入(真实的或生成的),并预测真实或虚假的二进制类别标签(生成的)。
真实的例子来自训练数据集。生成的示例由生成器模型输出。
鉴别器是一个正常的(也很容易理解的)分类模型。
在训练过程之后,鉴别器模型被丢弃,因为我们对生成器感兴趣。
有时,当生成器已经学会从问题领域的例子中有效地提取特征时,它可以被重新利用。一些或所有特征提取层可以用于使用相同或相似输入数据的迁移学习应用中。

GANs 是一个双人游戏
生成器和鉴别器这两个模型一起训练。生成器生成一批样本,这些样本与来自该领域的真实样本一起被提供给鉴别器,并被分类为真或假。
然后更新鉴别器,以便在下一轮中更好地鉴别真假样品,重要的是。基于生成的样本欺骗鉴别器的程度来更新生成器。
在这种情况下,零和意味着当鉴别器成功识别真假样本时。它被奖励或者不需要改变模型参数,而生成器由于对模型参数的大量更新而受到惩罚。
或者,当生成器欺骗鉴别器时,它被奖励,或者不需要改变模型参数,但是鉴别器被惩罚并且它的模型参数被更新。
在极限情况下,生成器每次都从输入域生成完美的副本,并且鉴别器无法辨别差异,并且在每种情况下都预测“不确定”(例如,50%的真假)。这只是一个理想化情况的例子;我们不需要达到这一点来获得一个有用的发电机模型。

为什么是生成性对抗网络?
在计算机视觉等领域使用深度学习方法的许多重大进步之一是一项名为数据增强的技术。
数据扩充会产生性能更好的模型,既提高了建模技能,又提供了正则化效果,减少了泛化错误。它的工作原理是从模型被训练的输入问题域中创建新的、人工的但似乎合理的例子。
在图像数据的情况下,这些技术是原始的,包括对训练数据集中现有图像的裁剪、翻转、缩放和其他简单变换。
成功的生成式建模为数据扩充提供了另一种可能更特定于领域的方法。事实上,数据扩充是生成式建模的简化版本,尽管很少这样描述。
GANs 对高维数据建模、处理缺失数据的成功能力,以及 GANs 提供多模态输出或多个似是而非答案的能力。
也许 GANs 最引人注目的应用是在需要生成新例子的任务的条件 GANs 中。在这里,Good fellow 指出了三个主要例子:
- 图像超分辨率。生成输入图像的高分辨率版本的能力。
- 创造艺术。伟大的新的艺术形象,素描,绘画,等等的能力。
- 图像到图像的翻译。跨领域翻译照片的能力,例如从白天到夜晚、从夏天到冬天等等。
GAN 应用
- 创造动漫人物

- CycleGAN

- 姿势引导的人物图像生成

我们将在下一部分更深入地讨论这些应用程序,敬请关注。
快乐学习!!!!
最初发布于 knoldus 博客:https://blog . knold us . com/machinex-generalized-attendant-networks-gan/
MachineX:使用 Keras 增强图像数据
在这篇博客中,我们将关注使用 Keras 的图像数据增强以及我们如何实现它。

问题
当我们处理图像分类项目时,用户给出的输入可能在许多方面有所不同,如点击图片时的角度、缩放和稳定性。所以我们应该训练我们的模型去接受和理解几乎所有类型的输入。
这可以通过为所有可能性训练模型来完成。但是当训练集大到 10000 张图片时,我们不能到处点击每个可能角度的相同训练图片!
这可以很容易地通过一种叫做图像数据扩充的技术来解决,这种技术拍摄一幅图像,将其转换并以我们指定的所有可能的形式保存。
图像增强介绍
图像增强是一种用于人工扩展数据集的技术。当我们得到一个只有很少数据样本的数据集时,这是很有帮助的。在深度学习的情况下,这种情况很糟糕,因为当我们在有限数量的数据样本上训练它时,模型往往会过度拟合。
通常用于增加数据样本计数的图像增强参数是缩放、剪切、旋转、预处理 _ 函数等。这些参数的使用导致在深度学习模型的训练期间生成具有这些属性的图像。使用图像增强生成的图像样本通常会导致现有数据样本集增加近 3 到 4 倍。
履行
让我们从导入所有必需的库开始:
pip install tensorflow
pip install scipy
pip install numpy
pip install h5py
pip install pyyaml
pip install keras
我们已经安装了scipy、numpy、h5py、pyyaml,因为它们是keras所需的依赖项,而且由于 keras 工作在tensorflow后端,所以也需要安装它们。你可以在这里阅读更多关于 tensorflow 安装的信息。我们将使用keras进行图像增强。
让我们导入 keras 图像预处理。
from keras.preprocessing.image import ImageDataGenerator,img_to_array, load_img
这里,ImageDataGenerator用于指定我们将用来生成图像的参数,如旋转、缩放、宽度,稍后将会介绍更多的参数。img_to_array用于将给定的图像转换成一个 numpy 数组供ImageDataGenerator使用,load_img将用于加载要修改的图像到我们的程序中。
datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
参数:
我们在此使用ImageDataGenerator()指定生成图像的参数,解释如下:
旋转 _ 范围:旋转量
宽度 _ 移动 _ 范围,高度 _ 移动 _ 范围:宽度、高度的移动量
shear_range : 逆时针方向的剪切角度,以弧度表示
缩放范围:随机缩放的范围
horizontal_flip : 布尔型(真或假)。水平随机翻转输入
fill _ mode:之一。根据给定的模式填充输入边界外的点
在指定参数并将它们存储在datagen变量中之后,我们开始导入我们的图像。
img = load_img('lion.jpg')
在这里,我使用的是狮子图像,你可以简单地使用你自己的样本图像。
x = img_to_array(img) # creating a Numpy array with shape (3, 150, 150)
x = x.reshape((1,) + x.shape) # converting to a Numpy array with shape (1, 3, 150, 150)
用于加载所需的图像,您可以使用任何您喜欢的图像,但我会推荐一张脸像猫、狗或人的图像!
接下来,我们使用img_to_array将图像转换成数字,在本例中,是一个 numpy 数组,它可以很容易地输入到我们的flow()函数中(不要担心,稍后会解释!).我们将转换后的 numpy 数组存储到一个变量x中。
然后,我们必须重塑 numpy 数组,添加另一个大小为 1 的参数。我们这样做是为了使它成为 4 阶而不是 3 阶的 numpy 数组,以容纳名为通道轴的参数。对于灰度数据,通道轴的值应为 1,对于 RGB 数据,通道轴的值应为 3。
这是我的输入图像(一只狮子):

输出:
现在我们已经有了表单输入,让我们开始产生一些输出。
i = 0
for batch in datagen.flow(x,save_to_dir='output', save_prefix='lion', save_format='jpeg'):
i += 1
if i > 20:
break
我们在每次迭代中使用datatgen.flow()函数。我们给了x—输入图像的 numpy 数组、save_to_dir—保存输出的目录、save_prefix—图像名称的前缀和save_format—作为输入的图像格式。
这是我们输出图像的样子:

请注意,由于缩放、旋转、宽度或高度偏移等原因,每张图像都与其他图像略有不同。这将有助于您将要构建的模型识别大量图像,从而提高效率。
这是 keras 中图像增强的概述。
此外,请访问 Machinex 页面,了解更多相同的更新:
魔术:聚会遇上数据科学

When Wizards bans your favourite Angel card. Source: Pixabay.
魔术:多年来,聚会一直是我的爱好之一。其庞大的卡库和悠久的历史使其非常适合数据分析和机器学习。
如果你错过了我的前一篇文章,我将 K-Means 聚类(一种无监督学习技术)应用于一个魔术:收集我从 mtgtop8 收集的数据集。那篇文章解释了技术方面的问题,但没有涉及结果,因为我认为我的读者不会感兴趣。
由于许多人已经站起来表达他们的不同意见,我现在将向你们展示算法学到的一些东西。
这不会是我第一次也不会是最后一次说,无监督学习可能会对它所学的一切感到毛骨悚然,即使你知道它是如何工作的。
数据
我在这个项目中使用的数据集只包含了去年现代格式的专业套牌。我没有在这个分析中包括侧板。在这个 GitHub 项目中,我用于训练和可视化的所有工具和代码都是可用的。
如果你知道任何好的休闲套牌数据集,我很乐意在评论中知道。不然以后可能会刮一个。
在这个分析中,我看了 777 副不同的牌,总共包含 642 张不同的牌(算上地)。
结果呢
首先,我强烈建议您打开资源库,亲自尝试 Jupyter 笔记本,因为可能会有一些您感兴趣的见解,而我可能会遗漏。
也就是说,如果你想知道关于一张特定卡片的数据(假设它是竞争元的一部分,我们已经看到它足够小了),如果你在这里没有看到它,请在评论中问我!
现在,我们要问自己的第一个问题是…
每个魔法:聚集集群看起来像什么?
请记住,我们聚集了一副牌,而不是一张牌,所以我们希望每一组能大致代表一个原型,特别是在现代元中看到的一个。
首先:这里是每个集群的计数。也就是说,每张牌有多少张。

Quantity of decks that fell on each cluster after applying K-Means Clustering.
我们可以马上看到有两个特别小的集群,每个集群不到 30 副牌。让我们仔细看看。
每个集群上的卡
对于第 4 组,我得到了每副牌中出现次数最多的一组 40 张牌,然后找出它们的交集,看看它们有什么共同点。我对第 6 组重复了这一过程。
Cluster number 4:
{'Devoted Druid', 'Horizon Canopy', 'Ezuri, Renegade Leader', 'Forest', 'Elvish Archdruid', 'Pendelhaven', "Dwynen\\'s Elite", 'Llanowar Elves', 'Collected Company', 'Windswept Heath', 'Temple Garden', 'Westvale Abbey', 'Razorverge Thicket', 'Heritage Druid', 'Elvish Mystic', 'Nettle Sentinel','Eternal Witness', 'Cavern of Souls', 'Chord of Calling', 'Vizier of Remedies', 'Selfless Spirit'}Cluster number 6:
{'Funeral Charm', 'Liliana of the Veil', "Raven\\'s Crime", 'Fatal Push', 'Thoughtseize', 'Wrench Mind', 'Bloodstained Mire', 'Smallpox', 'Inquisition of Kozilek', 'Mutavault', 'Urborg, Tomb of Yawgmoth','Infernal Tutor', 'Swamp', 'The Rack', "Bontu\\'s Last Reckoning", 'Shrieking Affliction'}
看起来他们中的一个在玩绿色牌组,使用精灵和绿色土地,而另一个结合了碾磨和丢弃,像 Liliana 和 Kozilek 的宗教裁判。
这是上一个算法对所有集群的结果,看看你能否分辨出每个集群属于哪个原型。这也告诉我们当我得到数据时元的分布情况。
Cards that appear in all decks in a certain cluster.
如果你参加竞技比赛,对一个更近的数据集进行同样的分析甚至可能是有用的。
特定卡片
在这些名单中,有三张牌让我印象深刻:“变跳马”、“对科济莱克的审讯”和“拉诺瓦尔精灵”。我想知道它们是否在其他集群中更常见?我真的不知道 Mutavault 在竞技比赛中如此常见,我认为拉诺瓦尔精灵出现在甲板上告诉了我们一些关于它的事情。


Well, that’s a one-trick pony. Clearly one of the things characterizing Cluster number 4 is the presence of Llanowar Elves.



和往常一样,你可以为任何一张卡片生成这些图表,或者问我你是否对某一张卡片感兴趣。
多功能卡片
最后,我将定义一种新的卡片类别:一张卡片的多功能性将意味着多少不同的组包含至少一副使用它的牌。
诚然,我同意这个定义还可以再完善一点。例如,通过计算幻影而不仅仅是卡片是否在一副牌中。
然而,这种方式的结果是足够连贯的,所以我不认为它需要任何更多的调整。在过滤掉基本的地之后,这里列出了十大最通用的牌。
- 肢解
- 鬼节
- 废墟
- 灵魂洞穴
- 思维抓住
- Mutavault
- 神圣铸造厂
- 常去的地方
- 工程炸丨药
- 植物圣地
他们几乎就是你所期望的那种。然而,我很惊讶闪电没有入选。我不确定非基本地是否应该计算在内,但最后我还是把它们留了下来。
事实上,我不知道“工程炸丨药”是哪张牌,这证明我与超级玩家脱节了,也许我应该玩得更多,但这不是重点。
结论
正如我们所料,《魔法:聚会》是一个有趣的数据来源,我想我们都通过看到这一切学到了一些东西。
就我个人而言,我仍然很惊讶一点点被美化的线性代数可以了解所有关于竞争游戏的元。
如果它在休闲游戏中了解到原型,我会更惊讶,在休闲游戏中,套牌更加多样化,尽管我的直觉告诉我有足够多的集群,即使这样也应该被正确地表征。
你怎么想呢?你想看看其他的信息吗?你期望算法表现良好吗?最后,你认为还有哪些领域适合适当的数据分析,特别是使用其他无监督学习技术?
请让我在评论中知道任何或所有这些!
关注我 中 或 推特 获取更多文章、教程和分析。请考虑 以一份贡献支持我的网站和我的写作习惯 。
原载于 2019 年 4 月 5 日www . datastuff . tech。
使用聊天机器人的主要好处

Facebook Messenger Chatbots are future of the internet marketing
我要告诉你关于未来的事——信使聊天机器人。什么是 Messenger Chatbot,为什么它对您的业务至关重要?基本上,它是一个数字助理,大多数时候是基于人工智能的,它有各种命令的方向,看起来像与你的客户进行自然的声音对话。
现在,您有机会自动与客户进行一对一的个性化对话。我只是想知道,如果你能让这个人确切地回答他们的问题,你会让他们购买的可能性有多大?
聊天机器人可以帮助客户找到关于公司提供的服务的信息,咨询他们的产品可用性,商店位置,进行预订或预定,评估客户对服务的体验以及更多不同的命令。你可以在 Slack、Facebook Messenger、丨t丨e丨l丨e丨g丨r丨a丨m丨s丨、Text Messages、Hangouts 等任何主流聊天应用中采用这项技术。
例如,脸书信使聊天机器人的参与率是电子邮件营销的 10 到 80 倍,而如今新闻订阅上的有机帖子的可见性只有可怜的 1%。更重要的是,信使广告是最有利可图和最便宜的方式在互联网上获得线索!
根据全球网络指数统计,大约 75%的互联网用户使用一个或多个 messenger 平台。尽管研究表明,每个用户平均每月使用 24 个应用程序,但 80%的时间都花在 5-6 个应用程序上。在这篇博客中,我们将介绍开发聊天机器人作为工具的主要好处,无论你是小企业还是大企业,它都可以在内部和外部加强你与客户展位的关系。我们走吧!
为什么您应该根据您的业务定制它
1。支持随时供货
众所周知,客户服务是成功的最重要因素。无论您的企业是在全球还是在当地,拥有全天候的客户服务和即时回答对您客户的满意度和购买意愿有着巨大的影响。当接线员试图给你接通客户服务中心时,大多数客户总是在等待,而聊天机器人对他们的命令百听不厌。
他们可以一年 365 天,一天 24 小时与观众一起工作。此功能可帮助组织处理更多任务,并节省时间来回答有关产品和服务的常见问题,无需客户等待。虽然聊天机器人在某些情况下不能取代真正的客户支持,但它可以补充这种支持,以便实际员工可以提供全面的服务,而不会让客户长时间等待而心情不好。
所有这些都可以大规模地免费提供给成千上万的潜在客户,而无需他们访问你的移动网站!如果你做得好,你可以通过聊天机器人把你的潜在客户从漏斗顶端拉到漏斗底端。您可以用 messenger chatbot 中的所有实现来替换网站体验。多酷啊。
2。管理可能性
您可以与客户保持联系,而不需要像真实商店中的销售人员那样通过实时协助亲自联系他们,从而提供交互式通信。一个良好的聊天机器人可以同时与数千人对话,回答他们的问题,提供特殊优惠券,限时促销或任何你想分享的东西。
企业能够在脸书等社交媒体平台上直接利用成熟的技术提供产品和服务。小而重要的事情,比如计划好的约会;检查你的电子邮件,为你提取数据,最重要的是向你的家人、朋友和客户提供会话更新,这些都是精确地完成的,几乎没有任何出错的机会。它将完全整合你的整个数字生活在一个地方,你可以很容易地访问和自动处理各种任务,没有时间。
他们与客户保持持续友好的联系,消除客户因陌生电话而产生的烦恼。这为推送通知和展示新产品和服务提供了有利的基础。像塔可钟和多米诺这样的公司已经在使用聊天机器人来安排包裹的递送。
3。低维护成本
实现一个全功能的聊天机器人比创建一个跨平台的应用程序或为每项任务雇佣员工要便宜和快捷得多。一个人只能同时应付一到两个人,甚至更多——这对员工来说是非常严峻的挑战。一年 365 天雇佣代理并增加资源来为客户提供基本的支持对公司来说太昂贵了。这不仅可以节省员工成本,还可以避免人为错误带来的问题。根据 Chatbots 杂志,实施虚拟代理可以帮助企业节省高达 30%的成本。
聊天机器人可以让公司节省资金,而且很容易改变以满足不同的需求,这取决于用户的应用。在它们建立的时候,保持它们更新的成本相对较低。根据行业研究,聊天机器人预计将在 5 年内处理 90%的客户查询。这意味着到 2022 年,预计他们将削减 80 亿美元的业务成本。
4。更高的参与度和销售额
让你的客户参与到你的品牌中来很重要,这也是为什么公司开始使用聊天机器人进行社交媒体营销的原因。通过社交媒体吸引客户可以帮助你增加高达 40%的销售额,而脸书在要求现有客户分享他们的积极体验方面成功率最高(根据研究,甚至 29%的人会这样做,并为你的企业带来新的前景)。
聊天机器人的灵活结构意味着将它们与其他渠道整合以提高参与度非常简单。一个简单的例子是与一个在线预订的顾客的对话。该机器人可以将客户带到在线购买页面,并与满意的客户达成交易。
它们可以被编程为自然的声音幽默,这可以使它们看起来更像人类。这让客户感到舒适,让他们对你的业务体验更加愉快。
没有假的电子邮件,假的名字或假的姓氏。通过 messenger 聊天机器人,您可以获得客户的所有真实信息。公司使用聊天机器人来获得客户洞察,从而主动与客户接触。电子邮件营销只有 3%的邮件打开率,而聊天机器人的得分超过 80%!正如我之前所写的,他们通过推送通知或新优惠来保持现有客户对感兴趣的品牌和产品的兴趣。
移动参与的重要性
另一件非常重要的事情是特别考虑手机。当谈到移动参与率时,这种类型的营销有能力完全改变游戏。看一下这些指标。这一点非常重要,因为这一趋势仍在继续,越来越多的人在移动设备上接触品牌,而不是在桌面上。
Facebook Messenger bot 体验完全针对移动设备进行了优化。Prime 用户在访问你的移动网站之前会得到他们需要的基本信息,这是非常重要的。你可以把所有与你的网站相关的不太友好的移动体验和不太好的转换率,通过聊天机器人为 FB messenger 平台重新配置/重新设计,让它工作得更好。
越来越多的脸书消息用户
这是按月用户(百万)统计的美国最受欢迎的移动通讯应用图表。截至 2017 年 9 月,全球 Facebook Messenger 的月活跃用户数达到 13 亿,预计到 2021 年,全球所有消息应用程序的用户数将达到 24.8 亿。想象一下,接触这些潜在客户的机会有多大。
CTR 高 14 倍
2016 年电子邮件营销基准研究显示,49%的邮件是通过移动阅读的,这表明用户在做一些事情的同时阅读通信的倾向。我们决定亲自通过 Facebook Messenger 的推送通知联系用户来测试和验证这一说法,打开率令人震惊。
我们使用 Messenger 聊天机器人和电子邮件向我们的客户发送了相同的活动。聊天机器人的结果比我们预期的要好:点击率(点击率)比通过电子邮件收到的点击率高 14 倍,这导致了整体活动绩效的提高。开放率为 84%。目前还没有其他营销渠道拥有如此高的参与度。
因此,我们相信在不久的将来,信使聊天机器人将变得比电子邮件营销更重要,也许有一天会完全取代它。Facebook Messenger 聊天机器人将成为品牌传播的未来。这些变化不仅会影响电子邮件平台,还会影响所有的交流方式。
Messengers Ad + chatbot =最便宜最高效的组合
你可以运行与智能聊天机器人相关联的 Facebook Messenger 广告活动,以达到任何社交媒体活动的最大目标。这个机器人可以自动发送一系列的文字信息、照片或视频来推销你的产品或服务。
通过与你的受众展开直接、一对一的聊天对话,你可以在个人层面创造超个性化的品牌体验。企业利用广告通过定位与其业务相关的潜在客户来开始对话。无论目标是产生线索、提高品牌或产品的知名度,还是推动销售,企业都可以定制 Messenger 中的对话来满足客户的特定需求——当他们点击广告时,他们将被发送到与您的机器人聊天。
来源:https://developers.facebook.com
用户可以询问关于您的位置或营业时间的问题,获得关于您的产品或服务的更多信息,提供反馈,预约等等——就像打一个令人沮丧的陌生电话,这是他们大多数人不想做的。脸书信使广告也有最便宜的每次点击价格,因此你有机会在一个数字领先杀手中连接两个最具成本效益和效率的广告渠道!
结论
聊天机器人正在改变在线用户体验,将用户从复杂的网站和带有结构化菜单的应用程序转移到一个简化的命令行界面,该界面可针对每个人进行调整。如果你的预算比 Google Adwords 少,那么这种方式会更有效,它很容易建立,只需要很少的维护,而且允许你用比其他渠道更少的钱来测试不同的营销信息。这种类型的广告和营销没有不奏效的地方。你一定要试试!
数据科学的主要课题和职业道路
数据科学(DS)可以总结为统计分析和编程技能的结合,用于分析大量数据集并提供有意义的预测和结果。这需要实施许多技能,如统计学、数据挖掘、回归、分类、预测建模和数据可视化等。
收集数据只是这一实践的开始,因为大多数未经适当过滤、分类和清理的原始数据都是无用的。许多数据需要数据科学家的输入来合并、删除、连接和剪切该数据集的特定部分,以便为特定的分析/建模进一步准备数据集。
当领先公司意识到大数据的重要性及其在决策或业务关系中应用成功战略的用途时,DS 成为当前就业市场的热门话题。对大数据工程和应用科学日益增长的需求促使许多行业雇佣数据科学家作为现代魔术师来预测结果并提供有意义的解释。
当前的数据科学家来自许多不同的背景,如金融、经济、环境科学、计算机科学、统计等。这种多样性和非传统背景可以使他们有一个创新的视角,并应用不同的解决问题的技能。虽然本文并不试图涵盖 DS 中所有相关的职业,但它将试图让当前的教育求职者和求职者熟悉 DS 中的不同领域,如下所示。

公共事务:
在这条职业道路上,数据科学家应用统计学和计算机科学技能为没有得到满足的社会商品创造有效的公共政策结果。这是通过政治调查设计、基础设施/智能城市/交通管理、活动数据解释、政府欺诈检测(例如逃税者)、教育系统管理、公共卫生/住房/执法数据分析等实现的。
商业分析:
业务分析基本上使用与 DS 相同的大数据应用程序,并实施这些应用程序来确定业务决策、识别弱点并在组织内应用实际变化,以改善关键绩效指标或其他增长指标。尽管数据和业务分析有着相同的目标,但后者涉及更多的决策、变更实施和沟通。
金融:
分析已经成为金融服务的核心。价格预测、将统计模型应用于股票市场走势、识别变化、衡量消费者终身价值和欺诈检测是数据科学家可以为金融服务提供商提供的众多优势之一。这导致做出实时决策,创建预测市场机会的交易算法,并基于历史数据和人工智能个性化客户关系。
计算机科学:
统计学可以被认为是一个进化和发展中的科学技术分支,是计算机科学和统计学的一个分支。然而,由于 DS 和 cs 中共享的技能和主题,数据科学家也可以使用这些技术的交叉点,并将数学和编码技能应用于许多 CS 领域,如数据库管理、科学计算和数据挖掘。在计算机视觉、人工智能和自然语言处理等主题中,有更多的生产级代码编写。这需要数据科学家有更多的编码背景。
网络安全:
许多网络安全提供商正在将 DS 功能添加到他们的底层系统中。基于分析模型和人工智能,对新旧威胁的响应变得动态,许多决策是自主做出的。通过 DS 技术,组织可以仔细检查数据并实施更好的入侵检测系统来防止欺诈和保护有价值的信息。
环境科学:
由于工业污染的无节制排放,全球变暖成为近年来的热门话题。环境数据科学家可以将建模和预测技术应用于许多不同的数据集,如污染物水平、水位上升和含盐量、大气值以及来自不同地质生态系统的地理空间数据。研究结果可应用于地理信息系统、气候学、环境监测项目的遥感和全球气候趋势。
国际经济关系:
DS 也可以用来提供对国际政治经济学、环境经济学、全球化进程和贸易/金融关系的深入理解。
微观经济学:
数据科学家可以将其技能应用于反垄断经济学和法规、分析计量经济学、公共和劳动经济学、经济实验和影响评估等领域。
生物技术:
生物技术可以定义为使用任何技术来分析/应用于活的有机体、生物系统或一般的医疗保健系统。许多生物技术公司正在雇用数据科学家,因为他们可以在医疗或非医疗领域提供许多不同的好处。基因组分析和下一代测序需要具有统计和编码知识的生物技术人员为特定研究应用和分析万亿字节的数据。此外,疫苗、副作用分析和微生物/疾病分类等药物发现都可以通过 DS 完成。
随着越来越多的企业开始依赖 DS,对能够收集、组织、解释和可视化数据的专家的需求将会增加。数据分析师和科学家在未来几年将会有很高的需求,该领域的不同职业将会产生应用于数据相关问题的不同技术和知识。
自然语言处理的主要趋势:前交叉韧带研究 20 年回顾
深入分析
计算语言学协会(ACL 2019)第 57 届年会本周在意大利佛罗伦萨开幕。我们借此机会回顾了动画 NLP 领域的主要研究趋势,并从商业角度阐述了一些影响。这篇文章是由过去 20 年中基于统计和自然语言处理的 ACL 论文分析支持的。
1.动机
与其他物种相比,自然语言是人类思维的主要特征之一。NLP 是当今科技讨论中的一个主要术语,它涉及计算机如何理解和生成语言。过去几十年中,自然语言处理的兴起得到了几项全球发展的支持——围绕人工智能的普遍宣传,深度学习领域的指数级进步以及可用文本数据数量的不断增加。但是嗡嗡声背后的实质是什么呢?事实上,NLP 是一个高度复杂的跨学科领域,由语言学、数学和计算机科学的高质量基础研究不断提供。ACL 会议将这些不同的角度汇集在一起。如下图所示,研究活动在过去几年里蓬勃发展:

图 1:各年在 ACL 会议上发表的论文数量
在下文中,我们总结了数据策略、算法、任务以及多语言 NLP 方面的一些核心趋势。该分析基于自 1998 年以来发表的 ACL 论文,这些论文使用 NLP 和机器学习领域的特定领域本体进行处理。
2.数据:解决瓶颈问题
免费提供的文本数据的数量呈指数级增长,这主要是由于 Web 内容的大规模生产。然而,这一庞大的数据体带来了一些关键挑战。第一,大数据本来就有噪音。想想石油和金属等自然资源——它们需要经过提炼和提纯的过程,才能用于最终产品。数据也是如此。一般来说,生产渠道越“民主”,数据就越脏——这意味着需要花费更多的精力来清理数据。例如,来自社交媒体的数据将需要更长的清洗管道。除此之外,你还需要处理大量的自我表达,比如微笑和不规则的标点符号,这些在更正式的场合,比如科学论文或法律合同中通常是不存在的。
另一个主要挑战是标记的数据瓶颈:严格来说,大多数最先进的算法都是受监督的。他们不仅需要有标签的数据,还需要有标签的大数据。这与深度学习家族的高级复杂算法尤其相关。正如儿童的大脑在学习母语之前首先需要最大的输入量一样,为了“深入”,算法首先需要大量的数据来包含语言的整体复杂性。
传统上,小规模的训练数据是手工标注的。然而,对大型数据集进行专门的手动注释会带来效率上的损失,这是很难接受的,尤其是在业务环境中。
有哪些可能的解决方案?一方面,在管理方面有一些增强,包括众包和培训数据即服务(TDaaS)。另一方面,在机器学习社区中也提出了一系列创建带注释数据集的自动变通方法。下图显示了一些趋势:

图 2:培训数据的创建和再利用方法的讨论(通过各年论文数量标准化的提及量)
很明显,在过去的五年中,T2 的预培训已经有了最大的增长。在预训练中,首先在大型通用数据集上训练模型,随后使用特定于任务的数据和目标进行调整。它的流行很大程度上是因为谷歌和脸书等公司正在向开源社区提供开箱即用的大型模型。特别是 Word2Vec、FastText 和 BERT 等预训练的单词嵌入允许 NLP 开发人员跳到下一个级别。迁移学习是跨不同任务重用模型的另一种方法。如果不能重用现有模型,可以利用少量已标记的数据来自动标记更大量的数据,就像在远距离和弱监督中所做的那样——但是,请注意,这些方法通常会导致标记精度下降。
3.算法:深度学习中的一系列中断
在算法方面,近年来的研究主要集中在深度学习家族上:

图 3:深度学习算法的讨论(按各年论文数量标准化的提及量)
单词嵌入显然被占用了。Mikolov 等人(2013)介绍了单词嵌入的基本形式。单词嵌入背后的普遍语言学原则是分布相似性:一个单词可以通过它出现的上下文来表征。因此,作为人类,我们通常可以用合适的词,如“交易”或“合同”来完成句子“客户今天签署了 __”。单词嵌入允许自动完成这项工作,因此对于解决上下文感知问题的核心非常有效。
虽然最初的嵌入算法 word2vec 是基于统计的,并且没有考虑到诸如歧义、上下文敏感性和语言结构之类的生活复杂性,但是随后的方法已经用各种语言信息丰富了单词嵌入。顺便说一句,你不仅可以嵌入单词,还可以嵌入其他内容,如词义、句子和整个文档。
神经网络是深度学习的主力(参见 Goldberg 和 Hirst (2017)对 NLP 背景下基本架构的介绍)。卷积神经网络在过去几年中有所增长,而传统的递归神经网络(RNN) 的受欢迎程度正在下降。一方面,这是由于更高效的基于 RNN 的架构的可用性,如 LSTM 和 GRU 。另一方面,Sutskever 等人(2014)在序列到序列 (seq2seq)模型中引入了一种新的、相当具有破坏性的顺序加工机制——注意。如果你使用谷歌翻译,你可能会注意到几年前翻译质量的飞跃——seq 2 seq 是罪魁祸首。虽然 seq2seq 仍然依赖于管道中的 RNNs,但从 2017 年开始的另一项重大进步, transformer 架构终于摆脱了递归,完全依赖于注意力机制(Vaswani et al. 2017)。
深度学习是一个充满活力和迷人的领域,但从应用的角度来看,它也可能相当令人生畏。当它出现时,请记住,大多数开发都是由大数据规模效率的提高、上下文感知以及对不同任务和语言的可扩展性所推动的。对于数学介绍,Young 等人(2018)对最先进的算法进行了出色的概述。
4.整合各种 NLP 任务
当我们观察特定的 NLP 任务时,如情感分析和命名实体识别,库存比底层算法稳定得多。多年来,从诸如句法分析和信息提取的词干提取的预处理任务到诸如情绪/情感分析和语义分析的面向语义的任务,已经有了梯度发展。这对应于 Cambria 等人(2014)描述的三条“全局”自然语言处理发展曲线——语法、语义和上下文感知。正如我们在上一节中看到的那样,第三条曲线——对更大环境的意识——已经成为新深度学习算法背后的主要驱动力之一。
从更普遍的角度来看,有一个有趣的趋势是任务不可知的研究。在第 2 节中,我们看到了现代数学方法的泛化能力是如何在迁移学习和预训练等场景中得到利用的。事实上,现代算法正在开发惊人的多任务能力——因此,手头特定任务的相关性降低了。下图显示了自 2006 年以来对特定 NLP 任务的讨论的总体下降趋势:

图 4:特定 NLP 任务的讨论量
5.多语研究札记
随着全球化的发展,走向国际成为企业发展的必要条件。传统上,英语是大多数 NLP 研究的起点,但是近年来对可扩展的多语言 NLP 系统的需求增加了。这种需求在研究界是如何体现的?将不同的语言视为我们观察同一个世界的不同镜头——它们共享许多属性,这一事实完全符合现代学习算法日益增强的抽象和概括能力。尽管如此,特定于语言的特性必须彻底解决,尤其是在预处理阶段。如下图所示,ACL 研究中涉及的语言多样性不断增加:

图 5:每年频繁使用的语言(>每种语言 10 次提及)
然而,正如在上一节中看到的 NLP 任务一样,一旦特定语言的差异被下一波算法抵消,我们可以期待一次整合。图 6 总结了最流行的语言。

图 ACL research 研究的语言
对其中一些语言来说,研究兴趣符合商业吸引力:英语、中文和西班牙语等语言汇集了大量可用数据、庞大的母语人口以及相应地理区域的巨大经济潜力。然而,大量的“小型”语言也表明,自然语言处理领域正在朝着理论上合理处理多语言和跨语言泛化的方向发展。
总结
在全球人工智能热潮的推动下,NLP 领域正在以新的方法和颠覆性的改进爆发。有一种向建模意义和上下文依赖的转变,这可能是人类语言中最普遍和最具挑战性的事实。现代算法的泛化能力允许跨不同任务、语言和数据集的有效扩展,从而显著加快 NLP 开发的 ROI 周期,并允许将 NLP 灵活高效地集成到各个业务场景中。
敬请关注 ACL 2019 的回顾和 NLP 趋势的更多更新!
参考
- E.坎布里亚和 b .怀特(2014 年)。跳跃 NLP 曲线:自然语言处理研究综述【综述文章】。比较。智能。玛格。 9,2。
- J.德夫林、m .魏、k .李和 k .图塔诺娃(2018)。BERT:用于语言理解的深度双向转换器的预训练。
- Y.戈德堡和 g .赫斯特(2017)。自然语言处理中的神经网络方法。摩根&克莱普出版社。
- T.Mikolov 等人(2013 年)。词和短语的分布式表示及其组合性。在第 26 届国际神经信息处理系统会议录 —第 2 卷(NIPS’13)。
- R.Prabhavalkar、K. Rao、Kanishka、T. Sainath、B. Li、L. Johnson 和 N. Jaitly (2017 年)。语音识别中序列间模型的比较。939–943.10.21437/散点. 2017–233。
- I. Sutskever、O. Vinyals 和 Q. V. Le (2014 年)。用神经网络进行序列间学习。第 27 届国际神经信息处理系统会议论文集 —第 2 卷(NIPS'14)。
- A.Vaswani,N. Shazeer,N. Parmar,J. Uszkoreit,L. Jones,A. N. Gomez,凯泽和 I .波洛苏欣(2017)。你需要的只是关注。第 31 届国际神经信息处理系统会议论文集(NIPS’17)。
- T.Young、D. Hazarika、s .茯苓和 E. Cambria (2018 年)。基于深度学习的自然语言处理的最新趋势。IEEE 计算智能杂志 —第 13 卷。
用 Python 做一个罗马皇帝掌权的柱状图

作为一个古代史和 Python 编程的爱好者,当我偶然发现这个关于罗马皇帝的数据集时,我知道我必须做什么……用它来制作 Python 中的数据可视化!
浏览这些专栏,我决定绘制皇帝们掌权的不同方式。当然,你可能生来就是皇帝的儿子,但是“夺权”实际上有多少次奏效了呢?
欢迎和我一起编写代码,学习如何阅读 CSV 文件和用 Python 制作条形图!本教程将假设您了解基本的 Python 编程知识,但是即使没有这些知识,您也可以继续学习。
为了查看数据可视化,我将在 Spyder IDE 中编码,您可以下载它作为 Anaconda 发行版的一部分。你也可以在笔记本上写代码。
用熊猫读取 CSV 文件
你可以在这里查看关于罗马皇帝数据的 CSV 文件。这一切都在一个漂亮的数据表中进行了美化,隐藏了 CSV 的实际含义:逗号分隔的值。

So pretty!
如果您查看原始 CSV ,您将会看到所有数据被挤在一起,每一列仅由逗号分隔。呀!

Egads!
但实际上,CSV 是一种很好的文件类型。我们可以使用 Python 库 pandas 轻松读取 CSV 数据。
让我们从导入 pandas(这样我们就可以阅读这个 CSV)和 matplotlib 开始,matplotlib 是另一个允许我们生成一些出版物质量的数据可视化的库。
在代码的顶部,编写:
import pandas as pd
import matplotlib.pyplot as plt
使用简写pd来表示 pandas,使用plt来表示 matplotlib.pyplot 是相当标准的,这也为我们输入长库名省去了很多麻烦。
现在我们可以使用 pandas 来读取 CSV 文件:
df = pd.read_csv("[https://raw.githubusercontent.com/zonination/emperors/master/emperors.csv](https://raw.githubusercontent.com/zonination/emperors/master/emperors.csv)", encoding='latin-1')
是的,就是这么简单!好了,关于代码说几句:
- 为什么我在
df中调用我存储 CSV 的变量?df是一个很常见的用于 DataFrame 对象的变量名,这是 pandas 在读取 CSV 文件时创建的。 - 那个
encoding='latin-1'是怎么回事?当我第一次尝试读取这个 CSV 文件时,我得到了一个 UnicodeDecodeError。堆栈溢出建议我尝试用不同的编码读取文件,比如latin-1。瞧,电脑可以读取文件了!
看到变量中存储了什么总是好的。通过运行以下代码,我们可以看到数据框df的顶部和底部:
print(df.head())
print(df.tail())
你可以按下一个看起来像绿色的“播放”按钮来运行 Spyder 中的程序。

如果您可以在您的控制台中看到一些东西,看起来模糊地像一个带有索引号的数据表,那么您可能就在正确的轨道上!

In this printing of df.head(), you can only see the index and the last column, which credits a Reddit user for the data table. But, there are actually 16 columns!
将数据转换成字典
好的,我有 16 列数据。但是正如我之前提到的,我真正感兴趣的一个列是“上升”列。我想看看是生为皇帝的儿子更普遍,还是通过其他方式夺取权力更普遍。

Yeah, it starts out with a lot of “birthright,” but then things get interesting…
我最初认为我想做一个直方图,但是我从 Python Graph Gallery 中了解到,直方图只接受数字数据,并且只显示它的分布。另一方面,我有分类数据:不同的权力路径,比如“与生俱来的权力”和“夺取的权力”。我还需要计算第二个数字变量:有多少不同的皇帝以这种方式掌权。
有了一个分类变量和一个数值变量(待计算),我想做的是一个条形图。
有了df["rise"],我可以访问通往权力之路的整个栏目,一个长长的列表,比如“与生俱来的权利,与生俱来的权利,参议院的任命,军队的任命”等等。我需要某种方法来计算出生权的数字,军队任命的数字等等。
幸运的是,pandas 通过一个value_counts()方法提供了这个功能。如果我调用列df["rise"]上的value_counts(),它会给我一个数字列表:到底有多少皇帝是通过世袭、任命元老院等等获得权力的。
此外,我可以调用value_counts()上的keys()来找出哪些数字对应于哪种成为皇帝的方法。
将此代码添加到您的中,以获得数字和相应的电源路径:
numbers = df["rise"].value_counts()
paths = df["rise"].value_counts().keys()
现在,我有了一个通往权力的独特路径的列表,以及对应于每条路径的数字。
当然,打印变量的值总是一个好主意,只是为了确保它们包含您认为它们包含的内容。
是时候制作条形图了!
用 matplotlib.pyplot 制作条形图
用 Python 做图的代码太简单了,感觉不可能是真的。但事实如此。
添加此代码,用 Python 生成皇帝死因的条形图:
plt.title("Roman Emperors' Paths to Power")
plt.ylabel("Number of Emperors")
plt.xlabel("Paths to Power")
plt.bar(paths, numbers)
plt.show()

简直令人惊讶(除了 x 轴上的一些压扁的文本——我们很快会处理这个问题)。您会注意到前三行代码只是添加了标题并标记了轴。所有繁重的工作都是通过调用第四行中的plt.bar()来完成的。最后一行只是显示图表。
在这里,我们可以看到“与生俱来”的门槛似乎比其他的更高…所以这可能是比“夺取政权”更可靠的成为皇帝的方式!
收尾
好,所以你实际上看不到 x 轴上的标签,因为它们都被挤在一起了。
幸运的是,您可以用这行代码旋转 x 轴上的标签:
plt.xticks(rotation=90)
在调用plt.show()之前一定要加进去。

最后,我们需要添加一些颜色。我们的可视化应该是引人注目的!
当你调用plt.bar()时,你也可以通过color参数指定你想要的颜色。例如,如果我写:
plt.bar(paths, numbers, color='mcbkyrg')
也就是说,我希望第一列是品红色(m),第二列是青色(c),然后是蓝色(b),黑色(k),黄色(y),红色(r)和绿色(g)。然后顺序又开始了。(点击阅读 matplotlib 中关于颜色的更多信息。)

完美!
扩展ˌ扩张
要为您的条形图添加更多功能,或者获得创建新功能的灵感,请访问 Python Graph Gallery 查看条形图!
以数据科学为生,而不是用时间来换取金钱
单身创业者的 5 个产品创意

你为自己制定了一个计划。
你想在数据科学领域谋生。
那你为什么不申请一份数据科学的工作呢?现在有很多,因为我们都知道数据科学现在很热门。
你告诉我,你想创建一个有价值的、可重复的和可扩展的商业模式,你不想用时间来换取金钱。
我告诉你,你可以搜索正在寻找数据科学联合创始人的初创公司。再说一次,现在有很多机会。
你告诉我你不想那样。相反,你想要建立一个没有联合创始人和投资者的小型自举企业。
我认为你是一个梦想家,你的想法有点疯狂。然而,我越想越喜欢这个想法。
让我们集思广益,想出一些你作为一个个体创业者可以做的数据科学产品创意。
多么复杂的一个词。我们称之为 Solopreneur 。这个术语更难理解。
1.数据科学课程
让我们从最明显的想法开始。你可以在像 Udemy 这样的平台或者你的网站上提供数据科学课程。很多人现在已经在这么做了。
Matt Dancho 是这样做的一个很好的例子。我和他有联系,我喜欢 LinkedIn 上关于他的课程的帖子。
外面有很多课程;然而,细分市场总是有机会的。
2.机器学习模型的付费 API
你可以在特定领域的标记图像上训练一个奇特的神经网络。你发布一个 API,让用户为使用 API 付费。看起来比实际情况复杂。有很多免费的数据集可以用来训练模型。您可以组合不同数据集中的数据。如果你使用迁移学习技术,你甚至不需要很多数据。
3.市场分析
这里面有很多机会。 AirDna 为 Airbnb 的主人和想要投资 Airbnb 房产的人提供市场分析报告。他们还提供了一个定价引擎。
ViralLaunch 或 JungleScout 为想要创办亚马逊 FBA 业务的人提供分析。
为什么不开始这样的事情呢?人们越来越受数据驱动,并且有许多平台。
优步的市场分析怎么样?
4.销售数据
对数据集有巨大的需求。你可以收集数据,并用亚马逊机械土耳其人(AMT)给这些数据贴上标签。然而,这比听起来更复杂,需要时间或/和金钱的投入。你也可能会因为收集属于他人知识产权的图片而遇到法律问题。
你可以用机器学习技术自动标注。要有创意!
5.数据新闻
你可以写数据故事文章并出售。你可以搜寻流行的东西,收集数据,写一篇可视化的文章,然后出售这些文章。
规模不大,但是一旦你出名了,你就能赚很多钱。
结论
数据科学产品对创业者来说是有机会的。
除了数据科学,你还需要其他技能,比如营销或销售,才能变得现实。
然而,如果你掌握了数据科学,你也会掌握这些技能。
我给自己写这个故事是为了集思广益,锻炼我的写作能力。 写这篇文章时,我想到的另一个想法是在媒体上创建一个新的出版物“数据科学 Solopreneur”。 你有更多的想法吗? 你有什么想法? 把你的评论发给我
原载于 2019 年 4 月 14 日https://jenslaufer.com。
通过为这些开源项目做贡献来产生社会影响
玩得开心,一路上帮助数百万人

Photo by Zac Durant on Unsplash
十月是庆祝开源软件的一个月,也被称为另一个标题 Hacktoberfest。
为了邀请其他人通过他们的工作产生影响, Ovio 策划了一个社会影响项目集供您参与。
这里有一个列表,列出了那些你可以用你的工作立即帮助和影响生活的项目。
开放式机器学习
这个知识库属于 OpenML,OpenML 是一个在线机器学习平台,用于共享和组织数据、机器学习算法和实验。
随着机器学习正在增强我们理解自然和建设更美好未来的能力,我们让研究、教育和工业领域的每个人都能够透明和轻松地使用它至关重要。
技术 : CSS,PHP,JavaScript
你可以看到一个开放问题的列表,这里的也标注为 hacktoberfest 。
自(动)调焦装置
这个存储库是一个使用数据科学和技术来解决一个重要问题的项目。
这个项目使用深度学习计算机视觉,根据图像中包含的动物来标记由运动激活的“相机陷阱”拍摄的图像。这项标记任务的精确模型可以解决野生动物保护工作的一个主要瓶颈。
科技 : Jupyter 笔记本
您可以在此处看到一个开放问题列表,您可以立即参与其中。
木卫四
这个存储库包含 Callisto 的源代码,这是一个关于性侵犯的在线报告系统。
幸存者,为了幸存者。Callisto 是一个非营利组织,它创造技术来检测职业性胁迫和性侵犯的惯犯。
技术 : Python
这里有一个列表列出了您可以参与的未决问题。
奥皮亚
Oppia 打算在世界各地教育工作者的帮助下,通过提供免费的高质量课程,为学生提供优质教育。
通过在世界各地教育工作者的帮助下创建一套免费、高质量、明显有效的课程,Oppia 旨在为学生提供高质量的教育,无论他们身在何处,也无论他们可以获得哪些传统资源。Oppia 的使命是帮助任何人以有效和愉快的方式学习他们想要的任何东西。
它有许多开放的问题,你可以开始作出贡献。
技术 : Python,TypeScript,HTML
您可以看到许多未决问题的列表,这些问题在这里也被标记为。
打开街道地图 iD
这个库属于 JavaScript 中的 OpenStreetMap 编辑器。
技术 : JavaScript,CSS
- 故意简单。它让您在不破坏他人数据的情况下完成最基本的任务。
- 它支持所有流行的现代桌面浏览器:Chrome、Firefox、Safari、Opera、Edge 和 IE11。
- iD 还没有为移动浏览器设计,但这是我们希望添加的东西!
- 用 d3.js 渲染数据
它有许多开放的问题,你可以做出贡献,你可以在这里看到。
签名
这个存储库属于 project SignDict,这是一个开放的手语词典,您可以在其中贡献其源代码,或者通过添加一个缺少的符号来贡献词典本身。
SignDict 认为沟通是开放社会的关键。为了增加聋人社区的融合,我们创建了一个生活字典,并邀请每个人都来参与。我们的使命:帮助彼此了解。
技术:药剂,HTML,Vue
它有许多未决的问题,其中许多被标为T21 黑客节,你可以对它做出贡献,你可以在这里看到。**
操作码
这个存储库是应用程序操作代码的前端。
技术 : JavaScript,CSS
我们 Operation Code 致力于为退伍军人和他们的家庭提供一条进入科技职业生涯的有效途径。我们直接与参议员、众议员和女议员合作,通过允许在新兵训练营编码中使用《退伍军人权利法案》,让退伍军人完全控制他们的未来。我们是致力于帮助退伍军人和家庭开始软件开发生涯的最大社区。
这个项目也有许多开放的问题,其中许多都有标签 hacktoberfest ,你可以在这里看到。
操作码资源
这是与编程和网络安全相关的学习资源的操作代码 API 的存储库。
技术 : Python
这里有一个列表,列出了许多你可以立即参与的未决问题。
操作码 Pybot
这个库代表操作码的官方 Slackbot。
技术 : Python
这里有一个列表,列出了许多你可以立即参与的开放性问题。
HOTOSM 网站
这个知识库是人道主义 OpenStreetMap 团队的网站。
HOT 是一个国际团队,致力于通过公开地图进行人道主义行动和社区发展。我们提供地图数据来革新灾害管理、降低风险,并为实现可持续发展目标做出贡献。HOT 通过提供培训、设备、知识交流和实地项目,使社区、非政府组织、国际组织和政府合作伙伴能够使用 OpenStreetMap 并为其做出贡献,以应对与当地相关的挑战。
技术 : HTML,CSS,JavaScript
这里有一个列表标有 hacktoberfest 的未决问题,您可以参与其中。
开放食品网络
这个知识库是关于开放食品网络项目的,它连接了供应商、经销商和消费者来交易当地的农产品。
开放食品网络是开放食品基金会的旗舰项目,旨在为公平和可持续的食品系统开发、积累和保护开源知识、代码、应用程序和平台。
这是一份列表中标记为 hacktoberfest 的未决问题,您可以参与其中。
开放式食品事实服务器
这个存储库属于开放的食品事实产品数据库,这是一个由每个人制作的食品产品数据库,为每个人服务。
开放食品事实是一个食品产品数据库,包括配料、过敏原、营养事实和我们可以在产品标签上找到的所有信息。
开放食品事实是一个非营利性的志愿者协会。像您这样的 25.000 多名贡献者已经添加了来自 150 个国家的 868.000 多件产品,他们使用我们的 Android、iPhone 或 Windows Phone 应用程序或他们的相机扫描条形码并上传产品图片和标签。
技术 : HTML,Perl
这个项目有许多未解决的问题,你可以在这里找到。
打开食品事实 iOS
这个存储库代表了用 Swift 编写的 iOS 开放食品事实的本地版本。
科技:雨燕
这里有一个列表,列出了许多你可以立即参与的未决问题。
开放食品事实机器人
这个库代表了用 Java 编写的 Android 开放食品事实的本地版本。
技术 : Java
这里有一个列表,列出了许多你可以立即参与的开放性问题。
尿布
这个存储库属于 Diaperbase,这是一个尿布库的库存系统。
该应用程序是一个库存管理系统,旨在尽可能直接和明确地解决尿布库的需求。尿布银行维持库存,接受捐赠和其他吸收尿布(和相关用品)的方式,并向社区伙伴组织分发。像任何非营利组织一样,他们也需要对这些数据进行报告,并拥有他们需要的日常运营信息。该应用程序旨在满足所有这些需求,并尽可能方便尿布库自身的一般操作(例如,通过使用条形码阅读器、秤称重、库存审计)。
技术 : Ruby,HTML,CSS,JavaScript
这里有一个列表,上面有许多被标为 hacktoberfest 的未决问题,你可以立即参与其中。
如果-我
这个存储库是一个开源应用程序,旨在用于与亲人分享健康经验。
if-me 是一个心理健康体验社区,鼓励人们与信任的盟友分享他们的个人故事。处理心理健康是我们之所以为人的原因。但对我们大多数人来说,很难公开自己的想法。
技术 : Ruby,JavaScript,HTML,CSS
这是一份列表中的未决问题,标记为 hacktoberfest ,您可以参与其中。
地形故事
该存储库属于应用程序,旨在使当地社区能够定位和映射他们自己关于对他们有重要意义或价值的地方的口头讲故事传统。
Terrastories 由 Mapbox 平台提供支持,设计为完全离线兼容,因此远程社区可以完全访问该应用程序,而无需互联网连接。
技术 : Ruby JavaScript,HTML,CSS,Dockerfile
这里有一个列表标为 hacktoberfest 的未决问题,你可以参与其中。
一切就绪
这个库是 AllReady 的源代码。
AllReady 是一个开源解决方案,侧重于提高当地社区人道主义和救灾组织开展备灾活动的意识、效率和影响。
技术 : C#,HTML
这里有一个列表,上面标有 hacktoberfest ,你可以参与其中。
讨论
这个 GitHub 存储库代表了 app Talk ,为记者提供了更好的评论体验。
网上评论都断了。我们的开源评论平台 Coral 重新思考了审核、评论显示和对话的功能,为围绕您的工作进行更安全、更智能的讨论创造了机会。
这里有一个列表标记为 hacktoberfest 的未决问题,您可以参与其中。
乌沙迪
Ushahidi 是一个用于信息收集、可视化和交互式制图的开源 web 应用程序。
我们是一家社会企业,为众多行业和公民社会提供软件和服务,以帮助改善自下而上的信息流。Ushahidi 在斯瓦希里语中翻译为“证词”,是在 2008 年肯尼亚大选后暴力事件后开发的暴力报告地图。我们相信,如果被边缘化的人能够容易地与那些旨在为他们服务的人沟通。Ushahidi 帮助您从以下来源收集信息:短信、Twitter、RSS 订阅源、电子邮件。它帮助你处理这些信息,分类,地理定位,并在地图上发布。
技术 : JavaScript,HTML
这里有一个列表标记为未完成的拉动式请求,您可以查看。
这是一个很长的列表,应该有希望提供各种各样的项目,您可以从中选择帮助。
您不必成为 Python 专家,也不必掌握某个特定的框架来通过这些存储库产生影响。你甚至可以邀请其他人也为他们做贡献。
跟我上 碎碎念
利用 3 个级别的数据分析做出更好的数据职业决策
如何评估未来雇主作为你数据职业的一部分?

更新:对复杂的分析前景感到困惑?查看我们的书: 《分析学设置指南》 。
几周前,我遇到了一个几年没见的初级软件工程师。我最后一次和他说话是在我(当时的)公司给了他一个职位——他最终拒绝了。“我想从事机器学习和数据方面的工作,”他当时曾说,“我认为另一家公司会给我更好的机会。”
当然,他是完全正确的。我以前的公司没有太多的数据能力;他不可能在我提供给他的角色中学到他想要的技能。但在我们最近的一次会面中,他告诉我,在另一家初创公司,他花了几年时间才进入“真正的”数据科学:“我们现在才开始建立一个数据部门,我正在从一般的软件工程转向数据科学。对此我真的很开心!”
数据团队职业不同于软件工程、产品管理或用户界面设计
他的经历中隐藏着一个有趣的事实,我认为值得在这里更详细地探讨。我朋友的经历反映了一个潜在的现实:数据团队的职业与软件工程、产品管理或用户界面设计的职业不同。它们之所以不同,是因为它们依赖于组织的周围环境,而后三类职业则不然。
在软件工程、产品管理和设计领域,工作要求大体相似。当然,服务公司中的软件工程与产品公司中的软件工程略有不同,但是总的来说,软件人员的职责非常相似。对于 UI/UX 设计师来说也是如此——对于产品经理来说则稍差一些——但是这些角色在很大程度上是围绕着相同类型的体验聚集在一起的。
与在数据团队中工作的数据分析师或数据科学家形成对比。根据他们所在团队的组织,他们的生活经历有很大的不同。某些公司要求他们的分析师进行适当的数据建模。其他人只处理自由形式的 SQL 查询,并在 Google sheets 中共享这些查询。一些幸运者执行机器学习和统计分析。但是还有一些人认为他们的数据分析师只不过是导出 SQL 和 Excel 的猴子。
那么,我们收到分析师写的博客文章,因为“缺乏影响力”而留下数据,这有什么好奇怪的呢?
为什么会这样呢?答案很明显:与软件工程师、产品经理或设计师不同,数据团队成员服务于内部用户,而不是外部用户。这意味着你的日常经历和学习机会在很大程度上取决于你所加入的组织。这意味着你不能假设所有的数据团队角色(在不同的公司)都是平等的。这意味着,就你的职业生涯而言,在你选择为组织工作之前,你必须培养评估组织数据成熟度的能力。
数据分析的三个层次
Emilie Schario 在 GitLab 发表了一篇关于三级数据分析的博文。公司存在于这些级别中的一个,它们必须从一个级别前进到下一个级别。这三个级别依次是:
- 汇报 —汇报是最底层。正如夏里奥所言:当你没有答案时,你永远不会放弃寻找事实。这一级别的示例问题有:“上周有多少新用户访问了我们的网站?”“这个月我们获得了多少线索?”有时,公司甚至达不到这一水平,因为他们缺乏系统收集业务数据的组织能力。其他时候,他们收集数据,但是他们不会花时间去关注它。报告是最底层的数据分析;如果你不收集数据,或者你没有使用数据的文化期望,你就不会根据事实做出决定。
- 洞察 —洞察是报告之上的下一级。如果说报道是收集事实并对其进行报道,那么洞察力就是理解事实之间的关系。通常情况下,只有当您将来自多个来源的数据结合起来时,洞察力才会显现出来。例如:本月取消订阅的新客户数量是一个报告指标。但是,如果我们将这些数据与销售 CRM 中的交易数据结合起来,我们可能会发现我们的目标市场是一个糟糕的细分市场。后一种观察是一种洞察力,可以导致销售和产品中的行为变化(“未来不要瞄准或服务于这个细分市场;我们不适合他们)。
- 预测 —洞察之后才是预测。正是在这个层次上,你开始看到复杂的技术,如统计分析和机器学习。这是有意义的:在你的组织越来越了解各种度量之间的关系之后,你可能开始做出明智的商业决策来推动你想要的结果。一个著名的例子是脸书发现,在头 10 天内添加至少 7 个好友的用户最有可能留下来。这一发现推动了脸书大量的产品决策,并最终导致他们赢得了社交媒体竞赛。只有在报告功能和洞察挖掘功能成为整个组织的第二天性之后,这种预测性发现才会出现。
我提供了沙里奥三个层次的快速总结,但我鼓励你阅读的完整帖子。然而,Schario 关注的是组织内的领导者,她继续讨论了沿着这三个层次前进的一些方法。
我对谈论那个不感兴趣。我的问题更简单:假设你是一名数据分析师,或者数据科学家。你在找下一份工作。很明显,你应该根据数据成熟度来选择组织——如果你想学习机器学习或使用回归模型,你应该选择“预测”层的公司;如果你想对商业决策产生巨大的影响,你希望在一家坚定地站在“洞察力”层面的公司工作。
你如何识别公司目前所处的水平?
(一种更复杂的形式是找出那些即将从一个层次过渡到另一个层次的公司,因为这是你获得最多学习机会的时候。更不用说,随着公司发展到新的水平,你还有机会在公司留下自己的印记。)
但是你是怎么做到的呢?你如何识别公司目前所处的水平?
头部伪题
你想问的是我称之为“T6”的假问题“T7”。假头是美式足球中的一个动作,球员把头转向一个方向,但却跑向另一个方向。假头问题是假装问一件事,但实际上是问另一件事的问题。

例如,如果你面试一家风险投资的创业公司,你可以问“告诉我过去一年你在公司经历的变化。”
对这个问题的一个可接受的回答是对公司成长方式的深思熟虑的回答。另一个很好的回答是“哇,当我想起这件事的时候,我真不敢相信我们做了多少/改变了多少/我们走了多远。”
一个令人担忧的答案是“老实说,差不多。”当风险投资资助的初创公司停滞不前时,它们就会死去,所以你可能想继续问一些关于公司近期历史的问题。
这是一个伪问题,因为很难猜测你真正想要的是什么。表面上,你是在询问关于公司生活的信息。你的面试官可能会认为你在试图衡量一种文化,或者你在试图评估在那里工作是什么样的。或者,他们可能认为你想感受一下公司的发展机会。当然,现实是你想要评估初创公司的增长率,因为这在物质上影响了你在那里的时间(和你的职业生涯)。
同样,当你提问来评估潜在雇主的数据成熟度时,你会希望提问的方式不会完全暴露你的意图。这里有一些建议,不过你显然应该针对你所在的具体行业来定制你的问题:
- “你的数据堆栈是什么样的?”这是一个显而易见的问题,但你要寻找的是告诉你公司目前属于哪个级别的信号。例如,处于“预测”层的公司可能会投入一些精力在服务器上托管 Jupyter 笔记本,而处于“洞察”层的公司则不会。最糟糕的情况是,您需要定期为业务用户手动导出 csv 文件,而这些业务用户在 Excel 中对这些文件进行分析。如果一家公司这样做的话,它离“报告”水平不会太远。
- “销售或营销如何评估他们的表现?”与公司的其他职能相比,公司的销售和营销通常更受数据驱动(如果公司没有销售职能,请将这个问题的主题替换为“客户获取”——即公司的哪个部门带来了新用户)。一个很好的答案是,如果“前端”销售、数据分析和“后端”产品/客户支持之间存在某种跨部门参与。请记住,如果不跨越多个数据源,就无法获得洞察力。如果公司纯粹在销售组织内部评估其销售漏斗,这意味着它最有可能在数据分析的报告级别,而不是更远。
- “哪些部门使用数据团队的报告?”这里的一个好答案是“许多”,每个都有具体的例子。这是比较少见的。一个不错的回答是,销售、营销和产品部门在做,但没有其他人真正关注分析;一个不好的回答是,销售人员在 Excel 中自行完成,而产品人员并没有真正将洞察发现视为一个重要的过程。
当然,在实践中,你要问的问题应该根据你所在行业的规范进行调整。在 Holistics,我们与亚洲公司以及西方公司合作,我们注意到西方公司总体上比东方公司更受数据驱动。一般来说,低利润率的公司比高利润率的公司更倾向于报告驱动型;科技公司往往比非科技公司更受数据驱动,美国公司比国外公司更受数据驱动。你的问题应该反映出你所在就业市场的基本现实。
但实际上,如果你应该从这篇文章中学到什么,那就是数据团队的职业生涯在很大程度上取决于你所在公司的现实。想学数据科学,挑一家做数据科学的公司;如果你想感觉自己作为一名分析师产生了影响,那就选择一家决策以数据为导向的公司。使用三个层次的数据分析来判断一个潜在的公司属于哪一层……在你开始为他们工作之前就这样做。一路顺风,祝你好运。
原文由 Cedric 发布,我的同事于 2019 年 12 月 22 日https://www . holistics . io。
使用 AWS & Lambda (Python)通过 12 个步骤轻松获取数据
告别复杂的 ETL 管道、SQL 数据库和其他复杂系统

本文将简要介绍 AWS Lambda 和构建一个完全无服务器的数据管道。这篇文章是为至少对 Python 有基本(我指的是基本)理解的人写的,但是你也可以是 AWS 的新手。我们将创建一个 AWS 帐户,然后有一个 Lambda 函数从 Craigslist 拉数据,并存储在 S3 桶为我们自动,每天。
关于我:数据科学家和爱好者,他不断尝试学习新技术,让我的生活更轻松。像数据科学社区中的许多人一样,我是自学的,没有统计学或 cs 背景。在前世,我是一名机械工程师,但那感觉像是很久以前的事了。这些年来,我对 Python 和 AWS 的掌握相当不错(我有一些认证),因为我总是从别人那里学到很多东西,所以我认为该轮到我为社区做贡献了。如果你觉得这篇文章有用,请随时在 LinkedIn 上与我联系,或者查看我的 Github 个人资料。

AWS Lambda — Your serveless swiss army knife!
什么是 Lambda
我经常会遇到“我编写了这个 Python 函数,需要它每天运行”的场景。您可以在您的机器上设置一个 Cron,但是如果您的计算机关闭了呢?另一个选择是转向云。用 AWS 做这件事的老方法是启动一个 EC2 实例,SSH 到其中,给它一个函数或者 docker 映像,在那里设置一个 Cron 作业,等等。还不算太糟,但是有点痛。此外,如果我只需要一些日常运行的东西,我真的需要一个 EC2 实例整天运行吗?输入 Lambda(是的,我知道您也可以为此使用 Batch,但这是一个 Lambda 教程)。
AWS 有很多服务,但也许我最喜欢的是 AWS Lambda。基本上,它让你专注于编写代码,而不是处理那些烦人的事情,比如 VPC、EC2 实例、MySQL 数据库等等。只要写一些 Python,把代码交给 Lambda,它就会在云端执行这些代码。更好的是,你可以用各种方式触发代码:每分钟,每天一次,当你把东西放进 S3 桶时,等等。Lambda 非常棒(而且便宜),很快成为我最常用的 AWS 服务。
我们将要做什么
在 12 个简单的步骤中,我们将建立一个 Lambda 函数,每天自动从 Craigslist 获取数据,并将数据存储在 S3(JSON)中。这只是一个例子,但是您可以使用本教程以您指定的时间间隔自动运行任何 Python 函数。诚然,这篇文章有点长,但我想确保它很容易复制,尤其是对初学者来说。如果您遇到了问题,请随时联系我,我们可以尝试调试它。最后要注意的是,这里的一切都应该在免费层内,所以不会花你一分钱。Lambda 每月给你一百万个免费请求,所以除非你打算每秒钟都解雇这个宝贝,否则你应该很棒。
第一步:创建一个免费的 AWS 账户
前往 https://aws.amazon.com 的,注册一个免费账户。请注意,您需要验证您的电话号码,但整个过程应该只需要几分钟。最后,选择“基本”计划,它将为你提供 12 个月的免费计算能力。
第二步:创建一个存储桶来存储我们的数据

Create An S3 Bucket
S3 桶是我们可以存储数据(或者更具体地说是对象数据)的地方。它基本上就像你电脑上的一个文件夹,但是在云中!进入服务>存储> S3,你将被带到 S3 启动画面。点击“创建存储桶”,给你的存储桶起个名字,然后选择离你最近的地区。我用桶来命名“我的超级甜桶”,你可以随意命名你的桶。只要知道桶名必须是全球唯一的,所以你不能有我的可怕的桶名。在给出名称和区域之后,只需使用所有的缺省值(单击 Next,直到创建了您的 bucket)。这将创建您的 bucket,并记下您对它的命名,因为我们稍后会用到它。
第三步:创建一个 Lambda 函数
现在我们有了一个存储来自 Lambda 的数据的桶,是时候创建我们的 Lambda 函数了。如果您将鼠标悬停在顶部的服务上,在计算下方,您会发现 Lambda。

Lambda is found under computer (common AWS Cloud Practitioner exam question)
因为你还没有制作 Lambda,你会看到一个闪屏,向你介绍 Lambda 的世界。点击“创建函数”按钮来创建您的 Lambda。
接下来,您将被要求命名您的函数,指定一种编程语言,并赋予它一个角色。

Create your Lambda function
先不说这个——什么是角色?亚马逊网络服务是一个巨大而神秘的怪兽,有很多事情在发生。值得注意的一点是,AWS 中的几乎所有东西都使用“最小权限”规则,基本上就是说,默认情况下,任何东西都没有访问任何东西的权限。例如,假设您在 AWS 网络中创建了一个名为 Bob 的用户。默认情况下,当 Bob 登录时,他不能访问任何 AWS 服务。鲍勃可以登录,但他不能使用 S3,EC2,Lambda 或其他任何东西。可怜的鲍勃。除非明确说明,否则不允许访问。总之,角色是一种以编程方式授予访问权限的方式。基本上,它会告诉 AWS“这是我的 Lambda 函数,我希望它能够访问 S3”。如果没有这个角色,你的 Lambda 函数将会像可怜的 Bob 一样无法访问。不要让你的 Lambda 像 Bob 一样。

Details for your Lambda function
不管怎样,你可以随意命名你的 Lambda 函数。我创造性地将我的名字命名为“pullCraigslistAds”。因为现在是 2019 年,我们是现代男女,我们将使用 Python 3.7,而不是任何 2.7 的废话。注意,Lambda 可以和许多其他编程语言一起使用,但是这里我们将使用 Python。现在权限可以设置为“创建一个具有基本 Lambda 权限的新角色”。我们将在教程的后面修正我们的角色。
第 4 步:为你的代码选择上传一个. zip 文件

Set your Lambda to take a Zip file
Lambda 的全部意义在于让它为我们执行一些代码。一旦你创建了 Lambda 函数,你会注意到浏览器中有一个代码编辑器。通常你可以直接在编辑器中写代码。然而,在本教程中,我们将使用一些外部(不是内置于 Python 中的)库,比如请求,我们将需要通过上传一个 zip 文件来做一些不同的事情。如果你不需要导入任何不附带 Python 的库,你可以直接内联编写。如果您确实需要导入库,我们将需要 Zip 文件。也就是说,Lambda 可以毫无问题地运行你的 Python 代码——但是如果你不需要 Pandas、Requests、Matplotlib 之类的库或者你用 Pip 安装的任何其他库呢?在本教程中,我们将使用 python-craigslist 库,所以我们使用“上传”。zip 文件”选项。
第五步:我们函数的代码
注意:如果你很急,想跳过一些步骤,你可以克隆 这个库 它会提供你需要交给 Lambda 的最终 Zip 文件。如果您只是复制回购,您可以跳到步骤 8。
如果你不是懒惰的,并且想要跟随,那么在你的机器上的任何地方创建一个新的文件夹,并将下面的代码保存到一个名为" lambda_function.py" 的文件中。
这是在做什么— 基本上它是在用一个叫做 craigslist 的 Python 库为我们抓取 craigslist。前几行导入我们的库。第 7 行是我们定义函数的地方,给出了事件和上下文的输入。如果你想变得书呆子气,去看看 AWS 文档。在高层次上,事件传递关于触发器的函数元数据,而上下文传递运行时信息给函数。对于这个函数,我们不需要过多地使用它们,但是在本系列的下一部分,我们将需要使用事件。例如,如果我们在某个东西被放入 S3 桶时触发一个 Lambda,我们可以使用事件来获取文件名,这通常很方便。
无论如何,对于使用过 Python 的人来说,函数的其余部分相当简单:实例化我们的类,告诉它要拉取什么数据,并将其存储在某个 JSON 中。第 28 到 31 行是我们如何使用 Boto3 将数据发送到 S3 的。如果你从未使用过 Boto3,它是一个 Python SDK,或者简单地说就是你如何通过 Python 与 AWS 交互。Boto3 允许你把东西放到 S3,调用 Lambda,创建一个桶,等等。如果您想从 Python 脚本中使用 AWS 资源,那么 Boto3 就是您的答案。这里我们使用它的一个最基本的特性:输出到我们的 S3 桶。在第 29 行,您需要将 bucket 的名称更新为您在步骤 2 中命名的名称。作为参考,下面是我们函数中的一些样本数据,这些数据来自 Craigslist 上的一个公寓广告。

Sample data
最后要注意的是,这只是我们的样本代码,但这可能是任何东西。例如,它可以调用 API,将数据转储到 JSON,并将 JSON 存储在 NoSQL 数据库中。这里我们将 JSON 输出到一个 S3 桶,但这可能是很多事情。
步骤 6: Pip 安装我们的依赖项
Lambda 在云中为你运行 Python,但它的 Python 版本有什么?任何经常使用 Python 的人都高度依赖库,库是我们可以使用的开源预写代码块(“import pandas as pd”,有人吗)?举个例子,如果我导入请求,在我们的 Lambda 中会发生什么?

Import requests library to our Lambda function
注意:确保在点击测试之前保存你的函数,否则它将测试先前版本的代码而不包括请求。一个好的经验法则是总是保存你的 Lambda 函数,很容易忘记去做,然后你在调试过去的版本。

Fail! Lambda won’t come with external libraries
基本上我们的 Lambda 失败了,因为这个 Python 环境没有请求库。那么我们如何获得它(或任何库)?有几种方法,但这是我发现的最简单的方法。我们已经将我们的 lambda_function.py 文件保存在一个文件夹中。接下来,pip 将您依赖项安装到同一个文件夹中。回头看看我们的代码,我们唯一的依赖是 craigslist 库(json、datetime、os 和 boto3 是其他需要的库,它们都是内置的,所以 Lambda 已经有了它们)。直到最近,我都不知道你可以这样做来 pip 安装到你当前的目录,但是它工作得很好:

Pip install the packages to your current directory
这将把 python-craigslist(及其依赖项)和 lambda_function.py 一起安装到您的文件夹中
第七步:创建一个 Zip 文件
回想一下 AWS 上的 Lambda 函数,我们选择了上传 Zip 文件的选项。现在,我的朋友们,是时候制作上述 Zip 文件了!选择你的文件夹中的所有文件,并将其放入一个 zip 文件,命名为 lambda_function.zip。我使用 7zip,所以我只是突出显示所有文件和文件夹,右键单击,选择 7Zip 并将其添加到一个 Zip 文件中。然后我把它重命名为 lambda_function.zip。你的目录应该看起来像下面这样,尽管现在你只需要那个 zip 文件。

Your current directory after creating the Zip file
第 8 步:上传你的 Zip 文件到 Lambda

Time to upload our Zip file
首先,我能感觉到你对我使用 Windows 的评价,我不喜欢这样。无论如何,点击上传按钮,并选择您新创建的 zip 文件。完成后,点击右上角的“保存”按钮。这将把你的 lambda_function.py 带进内联编辑器,你的 lambda 环境现在将拥有你需要的所有库!同样,从现在开始,如果您需要对代码进行修改,您可以直接编辑它,而不必重新打包您的 zip 文件。您需要重新打包 zip 文件的唯一原因是您对另一个库有新的依赖。如果发生这种情况,请重复步骤 6-8。
步骤 9:创建你的环境变量
完全进入环境变量有点超出了这个已经很长的教程的范围,但是基本上你可以在 Lambda 中完成。如果你看看我们的代码,我们调用了一个环境变量“number_of_posts”,这是我们将拉多少帖子。让我们对 Craigslist 好一点,不要让他们的系统超载,所以只要把它设置成 5 或 10 这样低的值就行了。这就创建了一个环境变量,我们的代码在被调用时会得到这个变量。
第十步:设置你的超时值

Set your max compute time for Lambda to 3 minutes
即将到来的 AWS 开发人员助理考试问题!默认情况下,Lambda 允许 3 秒钟的执行时间。对于这个例子,时间根本不够。您可以在“基本设置”下更改该超时值。最多 15 分钟,但我们应该能在 3 分钟内离开。如果你很吝啬,把你的功能设置成拉很多广告,比如说 200 个,你会需要更多的时间。请注意,Lambda 向您收取内存和计算时间费用。
步骤 10:为你的 Lambda 函数添加权限
我敢肯定,在这一点上,这篇文章就像简·奥斯汀的小说一样冗长,但是回想一下我们创建 Lambda 函数的第 3 步。我让你知道我们需要给 Lambda 一些权限来把东西放进 S3 桶。我们现在已经到了那个时候。我们是这样做的(尽可能简洁):
- 转到服务>安全、身份和合规性> IAM
- 转到左侧导航栏上的角色

Select Roles
- 单击创建角色
- 在“选择将使用此角色的服务”下,选择 Lambda 并单击“下一步:权限”

Specify we are creating a role for Lambda
- 现在您可以分配一个策略。从高层次上讲,策略就是如何授予权限。我们正在创建一个角色,为了让角色能够做任何事情,它需要附加一个定义权限的策略。也就是说,角色本身不授予任何权限。只有附加了策略,它才能访问资源。幸运的是,AWS 已经制定了一系列政策,所以在顶部搜索 S3 并选择“AmazonS3FullAccess”,单击复选框,然后单击下一步。

Click the checkbox next to AmazonS3FullAccess and click Next
- 不要添加任何标签,点击前进(本教程很长,但标签允许您应用元数据)。
- 在最后一步,我们命名我们的角色。我将把我的取名为 LambdaS3AllAccess,但是你可以随便给你的取名。单击“创建角色”按钮,我们就有了一个角色。
- 回到你的 Lambda 函数。
- 在“执行角色”下,选择您的新角色

Apply our spiffy new role to our Lambda function
- 保存你的 Lambda 函数
步骤 11:测试你的函数

The default test should be fine, just give it a name
我们的 Lambda 终于可以接受测试了!那么,我们如何测试这篇文章是不是一派胡言,这些东西是否真的有用呢?幸运的是 Lambda 内置了一个测试函数!如果你看“保存”按钮的右边,有一个“测试”按钮。点击那个!它将要求您创建一个测试输入,但我们现在将跳过它,因为当我们只是从 API 中提取或抓取时不需要它。基本上,如果你的 Lambda 要响应某种类型的输入,你可以在这里给它一个测试输入。我们不需要它,我们只需要它运行,所以只要给它一个名称,然后单击“创建”来测试它。
现在您有了一个测试事件,再次单击“Test ”,您的函数应该运行了!如果神是好的,你应该看到一个巨大的绿色方块形式的正确执行的通用标志。

Success!
如果我们回想一下我们的函数正在做什么,它正在以 JSON blob 的形式向 S3 输出数据。因此,理论上,我们现在应该在我们的 S3 桶中有数据。

Data in S3 from Lambda!
如果你去你的 S3 桶,你现在应该有数据在那里!万岁。让我们进入最后一步:自动化!
第十二步:自动化!
Lambda 的美妙之处在于它可以以多种方式被触发或调用。你可以让 Lambda 函数在任何时候发生,当一个对象进入一个桶,当另一个 Lambda 执行时,或者在一个时间间隔。我们将在这里使用后者,并将其设置为基于时间间隔运行。转到函数顶部,选择“云观察事件”。这就是你如何设置一个标准的时间间隔事件来触发我们的 Lambda。
CloudWatch 有很多功能,但本质上它是一个获取 AWS 环境数据的监控工具。如果你想获得任何 AWS 认证,你需要了解 CloudWatch,因为它会出现在许多考试中。

Add a CloudWatch Event to Fire Your Lambda
下到最下面,保持为“创建新规则”。规则基本上就是控制事件何时触发的东西。我们将创造性地将其命名为“每日”,在描述中,因为创造性的汁液现在真的在流动,我们将说“每天跑一次”。选择“Schedule expression”并输入“rate(1 day)”作为值。注意,这既可以使用 rate()函数,也可以使用 Cron 调度程序。克朗是丑陋的,所以我要去与率,但使用任何浮动你的船。

Setting up your CloudWatch trigger
就是这样!点击“添加”将你的新规则应用到你的 Lambda 函数中,然后点击顶部的“保存”将其应用到你的 Lambda 函数中。你的 Lambda 函数现在将每天提取数据并将其转储到 S3!
总结
Lambda 对于只想获取数据的开发人员或数据科学家来说是非常棒的,因为没有 EC2,没有数据库,没有硬件或其他令人痛苦的东西。它让我们只需简单地编写代码,让 AWS 处理所有烦人的事情。在本教程中,我们创建了一个 Python 函数,可以在本地机器上运行,并使用 Lambda 将其设置为每天在 AWS 上自动运行一次。第一次你可能会觉得很慢,但是一旦你习惯了 Lambda,你就可以开始快速部署了。当你第一次使用 AWS 和 Lambda 时,可能会有点害怕,但请坚持使用它,因为它对数据科学家来说有很多用途,特别是轻松获取数据。正如我提到的,如果你觉得这篇文章有用,请随时在 LinkedIn 上与我联系,分享你对 Lambda 的用例。
让数据再次变得有趣
自从大学毕业后,我就一直从事数据工作,谢天谢地,我有幸能和优秀的人一起工作。工作一直很有趣,因为我周围的人一直都很真实。每个人都公开了自己的优点和缺点,以及他们的技术知识水平。
这导致了工作中一些有趣的时刻。当一名实习生在工作的第一个小时内成功合并了 250 个文件时,我们用他们最喜欢的巧克力向他们表示祝贺。当一位分析师编写了一个 5000 行的 Python 脚本,为我们节省了一个小时的日常工作时,我们吃了一顿延长的午餐来狂欢。当我们所有人成功地部署了一个用了一年多时间构建的 ETL 管道时,我们和客户一起庆祝了一整夜!

This is how Data Geeks celebrate right?
最近,我决定扩大我的数据极客网络。我开始参加当地的聚会,加入不同的在线社区,并在我的母校发表演讲。
来自社区的普遍意见让我意识到,我比自己想象的还要幸运。我一直在进行的很多对话似乎都包含了一连串空洞的问题和充斥着流行词汇的陈述。
这些对话让我担心数据科学的有趣程度,尤其是在这个领域持续增长的情况下。它甚至出现在我上周参加的 React vs 数据科学会议上。React 聚会有趣多了。
现在,这肯定是意料之中的。当一个领域从小众成长为主流,媒体称之为性感、火辣、华丽,并不是每个加入这个领域的人都是出于激情和热情。你甚至可以从 MBA 学生加入科技行业的比例中看出这一点,科技行业长期以来一直是极客和工程师的天堂。

PSA: I DID NOT MAKE THIS NOT PRETTY CHART!
但这并不意味着我们注定要空洞地互相建议,我们肯定需要最新的数据湖连接到使用 Alteryx 构建的红移来运行我们的 AI 超级代理。
我们可以做得更好。我们需要让处理数据再次变得有趣。我认为有一件事我们可以努力做到:真实性。
我说的真实性是什么意思?我的意思是对你的技术知识水平和你处理数据的动机非常开放。
我看到的最大的违反是人们吹嘘他们的技术知识水平。我们在一个领域工作,这个领域需要了解的事情非常多。几乎不可能知道所有的事情,也不可能知道任何正在出现的新事物。
这导致一些人津津有味地吐出他们在最新文章中读到的流行语,就好像他们已经使用该技术多年了。

What I found when I Googled buzzwords. Which is how people probably find buzzwords.
就在昨天,有人告诉我,他们正在研究一个人工智能模型,在 AWS 上有一个大规模的数据存储,这将真正彻底改变病人护理行业。当我追问他们细节时,我发现他们已经看过了一些 YouTube 视频,并且正在玩 Weka 中一个大约 5000 行的数据集,这个数据集存储在 S3 的一个 CSV 文件中。他们不知道不同的机器学习算法是什么,也不知道如何在结构化数据库中存储和处理数据。
现在,这个人正在做的事情绝对没有错,我们都必须从某个地方开始,但吹嘘扼杀了我们的谈话和乐趣。如果他们承认他们的知识范围,我们会继续保持良好的关系。我甚至会考虑帮助他们完成他们的项目。
你可能会认为这是我本周最糟糕的数据时刻。但是唉!上周末,在一次数据黑客马拉松上,一个随机的队友给了我一个击掌相庆的机会,当时我告诉他们我如何只用了 1/3 的变量就获得了比以前更高的准确性。最初我以为他们默认的击掌是跛行,但当我看到他们在烧烤排骨上击掌时,这个假设就被抛弃了!

How I Felt After Seeing the High Five Over the BBQ Ribs
现在,为了拥有一份工作和支付账单而想要或拥有一份工作绝对没有错。不是每个人都会充满激情,尤其是在一个现在触及每个领域和行业的领域。这没关系。
这也要归咎于我们当前的文化,这里有巨大的压力和期望,如果你对工作没有超级热情,那你就有内在的问题。
然而,我们应该尽可能真实地表达我们的激情。我们中仍有很多人热爱这项工作,当你知道谁可以分享这份热情,谁不能分享时,就更容易获得乐趣。
所以,请大家都同意公开我们知道多少,我们有多关心数据。我意识到这是一个很大的要求,特别是在一个这样做很不舒服的社会里,招聘人员不断要求在一项 5 年前的技术上有 10 年的经验。
但至少,我们可以真实地对待我们的数据极客同事,并希望再次让数据变得有趣:)
制造更少的模型

Humphrey Bogart holding the Maltese Falcoln, one of the most famous and expensive MacGuffins. A complete predicrive model may resemble the Maltese Falcon is more than one way.
最近,我的老板要求我们的团队对一个业务领域进行基准测试,以便当一个提议的业务计划被引入时,我们可以知道是否有真正的变化——在完全的 A/B 测试不切实际的情况下,一个替代的 A/B 测试。
当我着手收集数据时,一个想法开始形成。当我在处理数据的时候,为什么不完成这个问题的预测模型呢?总有一天会派上用场的……”
建模是我们大多数数据科学家想要做的事情。这是最初吸引人们进入数据科学的迷人之处。然而,一般来说,只要痛点已经消失,企业就无法区分真正的正面预测模型和电子表格中的经验法则。
没有人要求这个模型。没有人需要这个模型,但是数据就在那里。为什么不做点模特呢?
投机建模显然是有风险的,至少,构建一个没人感兴趣的模型,但是人们要求的模型呢?我们是否应该鼓励用户寻求成熟的预测模型,或者像负责任的医生对待寻求阿片类药物缓解中度疼痛的患者一样,我们是否应该鼓励用户寻找不那么激烈的解决方案?
预测模型如劳斯莱斯
预测模型是数据科学中的每个人都在努力的目标,它们是数据科学的劳斯莱斯,威望模型。当它们是合适的工具时,它们提供了一个全面的解决方案,这个解决方案是准确的,并且通常,如果已经在头脑中进行了建模,这个解决方案可以被解释并且已经说服了主题专家,这些专家可以说服其他用户相信它的可靠性。
然而,达到这一阶段可能是一个昂贵而漫长的过程。支持精确建模的数据清理和预处理通常非常耗时。如果数据清理步骤被克服,模型本身的原始结果对业务用户来说经常是不可用的。相反,您需要格式化结果以满足用户的需求,并围绕预测构建一个平台。
最后,为了达到生产,通常需要大量的软件工程工作,既要确保数据源保持足够准确和及时以提供给评分引擎,又要确保用户界面的每个部分都能正确工作。
实际上,用数据科学的术语来说,预测模型是一种“赌大,赢大”的方法——人们应该追求大胆的目标。但是,如果没有回报,或者如果问题模型不够大,不足以证明成功的预测模型所需的投资是合理的,该怎么办呢?
如果不是预测模型,是什么?
模特常常是麦高芬——一个来自电影的术语,阿尔弗雷德·希区柯克将其定义为“装置,噱头,如果你愿意的话……在骗子的故事中,它几乎总是项链。”也就是说,它是让角色开始追寻的东西——但他们是否找到它并不严格相关。最典型的例子可能是马里恩·克莱恩在《惊魂记》的开头偷的钱,这使她走上了诺曼·贝茨的道路,与真实的故事无关。
通常,数据科学、模型本身可能变得无关紧要,因为我们通过深入和系统地查看数据而发现的东西为企业提供了答案。在这种情况下,模型是一种麦高芬——寻找它是我们找到答案的方式,但它本身并没有很大的价值。
这本身不是问题。然而,如前所述,模型通常需要相当大的投入。更糟糕的是,在商业领域(但也包括生活的其他领域),花费相当大的努力往往意味着人们不愿意放弃对预测的追求,即使开发它的追求已经超过了它的有用目的。
最好找到一种方法来探索数据,不要声称最终输出的是一个预测模型。事实上,约翰·图基的经典文本探索性数据分析背后的原始动机的一个方面是相似的——提出方法来理解数据在说什么,而不开发正式的数学模型。
现实是,在投入设计预测模型和交付预测模型的系统之前,寻找理由在描述性统计和解释性分析上花费更长时间,往往会导致企业的问题在不需要模型的情况下得到解决。这可能是许多数据科学家抱怨他们花 90%的时间在“数据准备”上,而花 10%的时间在“建模”上的一个促成因素——在许多场景中,建模被证明是不必要的。
在商业生活中,期望管理通常是最重要的活动,设定一个项目可能产生模型的期望是有风险的。试图说服业务利益相关者模型可能是不必要的,有助于确保数据科学工作被视为识别和解决问题的廉价、无风险和有效的方式。
罗伯特·德格拉夫的书《管理你的数据科学项目》已经通过出版社出版。
制作令人难忘的数据科学项目
让您的项目脱颖而出,赢得数据科学经理的关注
数据科学就业市场竞争异常激烈。有许多合格的候选人,很难区分他们。对我来说,将最强的申请人与最弱的申请人分开的最简单的方法是通过查看他们的 github 或 kaggle 项目。
在你探索了为了得到一份数据科学工作你应该做的项目之后,是时候做一些修改来让它们真正流行起来了。
下面是一些可以让你的项目更上一层楼的方法。

让你的项目与众不同——项目应该从一个好故事开始。如果你有一个令人信服的理由来使用一个特定的数据集,这会引起我的注意。不要害怕在 github README 或 Kaggle 工作簿的顶部讲述您的项目故事。独特的项目也更难复制。不幸的是,我看到一些候选人未经认证就抄袭作品或整个项目。
收集自己的数据——从 kaggle.com 获得一组数据非常容易。我喜欢候选人使用替代方法获取数据。如果他们使用 API 或者从网站上抓取数据,这向我表明他们愿意投入时间来获得他们想要的信息。能够使用 API 和收集数据对于数据科学家来说是非常有价值的工具。当你为一个项目这样做时,你证明了他们有这些技能。
使用高级特征工程 —我们构建的模型只和输入其中的数据一样好。当你通过添加新功能或改进现有功能而变得富有创造性时,这是令人印象深刻的。我最常见的例子与地理空间数据有关。如果你有一个位置的纬度和经度,你可以找到它与另一个位置的距离。这个距离几乎总是比单个点更有用。
必要时减少要素-您想要使用的一些模型不能很好地处理稀疏性或多重共线性。如果您知道为什么以及何时使用 PCA 或其他特征缩减技术,这总是一个额外的收获。
建立集合模型——这些方法相当普遍;然而,它们通常会产生最好的结果。如果你还没有探索多种模式的结合,你就落后了。
将它们投入生产 —如果你为你的项目建立了一个 API 或网站,你就完成了一个端到端的分析。数据科学家可能拥有的最重要的技能之一是让他们的工作变得有用。通过让其他人也能接触到你的工作,你展示了它的实用性。
让它们对某人有价值 —为自己做一个项目是很棒的,但有时你可以用你的项目来帮助别人。也许你可以做一个分析,帮助你当地的非营利组织降低成本,或者帮助动物收容所提高收养率。像这样的项目有切实的成果和可衡量的、真实的结果。数据科学应该对现实世界产生影响,这些项目说明了这一点。
希望这些建议能提高你的工作质量,帮助你得到雇主的注意!
让你的数据处理代码在 5 分钟内飞起来
在 10 行代码内释放计算机的全部能力
尽管数据科学家被称为 21 世纪“最性感”的工作,但数据处理是数据从业者日常工作的重要组成部分,既费力又不有趣。在大数据时代,数据处理更加耗时,轻松需要几十个小时才能完成。这既是一个挫折,也阻碍了项目的进展。因此,数据从业者愿意编写复杂的代码,只是为了一点点的性能提升。然而,加速数据处理并不难!在本文中,我将介绍一些简单直观的方法来减少几种常见数据处理工作的运行时间。
全力以赴
首先,现代 CPU 快如闪电。像英特尔 i7 系列这样的流行 CPU 可以轻松实现 3 GHz 时钟,并且至少有 4 个内核,这意味着它们应该能够在合理的时间内执行大多数数据处理任务。然而,CPU 经常处于饥饿状态,这意味着代码受到其他因素的限制,如 I/O 延迟(磁盘到 RAM、RAM 到缓存等)。因此,减少 I/O 延迟至关重要。

from David Jeppesen’s ‘Computer Latency at a Human Scale’
正如你所看到的,从硬盘(旋转磁盘)读取数据相当慢。因此,如果您的任务是 I/O 绑定的,您可以通过将数据读/写文件夹移动到 SSD 来提高其速度。
其次,如果操作是 CPU 受限的,我们将不得不更深入地挖掘并行机制。并行性可以充分利用 CPU 的潜力,让您付出的每一分钱都物有所值。Python 提供了各种各样的并行计算库,但不幸的是,其中大多数都需要大量的额外设置代码和对线程/进程/同步等的理解。 Dask 是一个库,它提供了并行计算,而无需向用户暴露并行配置的本质细节。我将向您展示在 Dask 的帮助下加速代码是多么容易。
系统配置
Dask 默认安装在 Anaconda Python 环境中。如果没有安装 dask,只需在终端中输入这一行代码
pip3 install dask
建立一个本地集群(集群中的每个核心都是一个工作者)
# in python
from dask.distributed import Client
client = Client(scheduler = 'threads') # set up a local cluster
client # prints out the url to dask dashboard, which can be helpful

就是这样!你现在有几个工人供你支配。
容易加速的常见任务
a .文件格式转换
例 1:将 JSON 文件转换为 CSV
将 JSON 转换为 CSV 是 web 爬行中的常见任务。处理 JSON 文件的一种常见方法是:
file_list = os.listdir(base_dir)
json_list = [file for file in file_list if file.endswith('.json')]
for file in json_list:
inp = os.path.join(base_dir, file)
out = os.path.join(base_dir, new_name)
json_process(inp, out) # convert each json to a csv
但是,这种串行方法没有充分发挥机器的潜力。稍加修改,我们就能写出更好的代码:
file_list = os.listdir(base_dir)
json_list = [file for file in file_list if file.endswith('.json')]
parallel_work = []
for file in json_list:
inp = os.path.join(base_dir, file)
out = os.path.join(base_dir, new_name)
**parallel_work.append(dask.delayed(json_process)(inp, out))# lazy
dask.compute(*parallel_work) # make dask compute**
dask.delayed()是一个惰性信号,这意味着它不会执行函数(在本例中为 json_process ),除非被明确告知这样做。使用 delayed()的好处是系统会智能确定可并行化部分。
例如,dask 可以在下面的操作中识别底层的任务依赖,然后同时处理尽可能多的操作(在本例中是 4 个任务)
def add(x,y):
return x+y
def minus(x,y):
return x-y;
x = 10
y = 1
result = dask.delayed(add)(x,y) * dask.delayed(minus)(x,y) + dask.delayed(minus)(x,y)/dask.delayed(add)(x,y)
**result.visualize()# show task dependency**

task dependency graph generated by dask
基准:将 JSON 文件处理成 CSV 格式的 dataframe。

you can get the max speedup = # of cores
例 2:将 CSV 合并成一个大 CSV
数据从业者的另一个主要问题是合并 CSV。这是我在网上找到的一个代码:
#code 1
df = pd.read_csv(file)
for file in csv_list:
a = pd.read_csv(os.path.join(base_dir, file))
df = pd.concat([df,a])
这段代码的性能会很差,因为 pd.concat()是一个开销很大的函数。pd.concat(df1,df2)重新分配新的内存空间,并将两个数据帧都复制到新的数据帧中。上面的代码给你二次运行时间。

runtime analysis
更好的解决方案:
#code 2
df_list= []
for file in csv_list[1:]:
df= pd.read_csv(os.path.join(base_dir, file))
df_list.append(df)
df = pd.concat(my_list)
这段代码只复制数据帧一次,因此产生线性运行时间。我们不能显著改进这段代码,但是我们可以使用 dask 对它进行次线性改进。
#code 3 with dask
df_list =[]
for file in csv_list:
df = dask.delayed(pd.read_csv)(os.path.join(base_dir, file))
df_list.append(df)
df = dask.delayed(pd.concat)(df_list).compute)
基准

b .数据汇总
Dask 提供了几种数据结构,dask.dataframe 是其中之一。Dask.dataframe 允许用户将一个巨大的数据帧分成多个块,这允许内核之间的协作。要创建 dask.dataframe,只需:
from dask import dataframe as dd
**dd_df = dd.from_pandas(df, npartitions=6)**
dd_df.visualize()

dask dataframe visualization
Dask.dataframe 对象与 pandas dataframe 非常相似(许多命令完全相同)。举个例子,
# in pandas
df.groupby(['Feature1']).sum()
df['Feature1'].min()
df['Feature1'].rolling(10).mean()# in dask
dd_df.groupby('Feature1').sum().compute()
dd_df['Feature1'].min().compute()
dd_df['Feature1'].rolling(10).mean().compute()
基准测试:groupby()


重要的一点是:数据帧分区不是随机的工作;根据您拥有的内核数量对数据进行分区是一个好主意。太多的分区将不可避免地增加通信开销。
c .特征工程
特征工程是一个好模型的重要前提。尽可能对代码进行矢量化总是一个好主意。例如:
%timeit df['Feature3'] = df['Feature1'] **2
#47.3 ms ± 982 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit df['Feature3'] = df['Feature1'].apply(transformsform)
#2.62 s ± 47.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Pandas 基于 numpy 库,一个高性能的计算库,因此任何矢量化的操作都非常快。幸运的是,我们在 dask 中得到相同的 API:
dd_df['F1'] = dd_df['F1']**2 + dd_df['F2'] (lazy)
然而,并不是所有的作品都可以矢量化。例如:如果您的数据帧看起来像这样,并且您希望提取名字,您必须使用 apply()。

#you can't vectorize this
def operation(x):
return x.split(':')[0]
因为矢量化的操作通常足够快,所以我将重点放在不可矢量化的操作上。
例 1:列变换
def operation(x):
#some un-vectorizable operations with process time M
return ydf['new'] = df.F1.apply(operation) # pandas
ddf['new'] = ddf.F1.apply(operation).compute(**scheduler ='processes'**) # dask
我将调度器设置为‘processes ’,因为这段代码完全由 operation()控制。在这种情况下,向其他进程发送数据以换取真正的并行性是合理的(每个进程在一个分区上工作)。参见 dask 提供的解释:
引用‘线程调度器……是轻量级的……它引入了非常少的任务开销(每个任务大约 50us 然而,由于 Python 的全局解释器锁(GIL),该调度器仅在您的计算由非 Python 代码主导时提供并行性。”
多处理调度程序…每一个任务及其所有的依赖项都被 运至 的一个局部流程,执行完毕,然后它们的结果被 运回 的主流程。这意味着它能够 绕过 GIL 的问题,甚至在纯 Python 代码占主导地位的计算上提供并行性
基准:
移动数据的成本很高,这就是为什么只有当您希望执行的操作比进程间通信成本更高时,使用进程调度程序才有帮助:

both n and theta play roles
正如你所看到的,大的 n 和大的θ可以使分母变小,从而使除法变大,这就是为什么我们想要大的 n 和θ。

operation time and the length of dataframes both matter
你要尽可能靠近右上角。另一方面,如果您的操作不需要那么长时间,或者您的数据帧很小,您可以只使用 pandas。
例 2:多特征工程
如果有多列需要处理,可以同时处理这些列:
#pandas
operation1(df.F1)
operation2(df.F2)
operation3(df.F3)#dask
a = dask.delayed(operation1)(df.F1)
b = dask.delayed(operation2)(df.F2)
c = dask.delayed(operation3)(df.F3)
work = [a,b,c]
result = dask.compute(*work)
基准测试:和前面的例子一样,操作时间和数据长度都很重要。
摘要
数据处理可能非常耗时,尤其是由单线程处理时。我已经说明了利用 dask 充分发挥计算机的能力是多么容易。当然,还有其他多处理/线程库,但我认为 dask 是帮助数据从业者入门的最简单快捷的工具。
现在去加速你的代码吧!
相关材料
Dask 网站:https://docs.dask.org/en/latest/why.html
深度 Dask 教程:https://github.com/dask/dask
达斯克概述:https://www.youtube.com/watch?v=ods97a5Pzw0
让您的数据说话!
使用 matplotlib 和 seaborn 在可视化中从 0 到英雄

Photo by Wynand van Poortvliet on Unsplash
如果TL;博士 : [ Link_To_Note
编辑: 法维奥·巴斯克斯 给这个帖子+4 并回复
“牛逼的文章!恭喜:)”法维奥·巴斯克斯
在推特上!!感谢法维奥·巴斯克斯。
这是我在Tackle类别的帖子中的一个,可以在我的 github repo 这里找到。此类别的所有帖子:
索引
***NOTE:*** This post goes along with ***Jupyter Notebook*** available in my Repo on Github:[[HowToVisualize](https://nbviewer.jupyter.org/github/PuneetGrov3r/MediumPosts/blob/master/Tackle/HowToVisualize.ipynb)]
1.简介 ^
什么是数据,无非是数字。如果我们不把它形象化来更好地理解它里面的世界,我们就会错过很多东西。也就是说,我们可以把数据理解成数字,但是当你试图把它形象化时,奇迹就发生了。它变得更有意义,突然变得更容易理解。
我们是感性的生物,我们通过感官感知周围的事物。视觉、听觉、嗅觉、味觉和触觉。我们可以在一定程度上根据感官来区分周围的事物。对于数据来说,声音和视觉似乎是表示它的最佳选择,因为它可以很容易地转换。我们大多使用视觉作为感知数据的媒介,因为我们可能习惯于通过这种感觉来区分不同的对象,而且,尽管在较低的层次上,我们也习惯于通过这种感觉来感知更高维度的事物,这在多变量数据集中很方便。
在这篇文章中,我们将探讨 Python 中两个最流行的数据可视化库,并使用它们通过可视化让数据说话:
1.1 Matplotlib
Matplotlib 保持了 MATLAB 的绘图风格,尽管它也有一个面向对象的接口。
- MATLAB 风格接口:从 matplotlib 库中导入
pyplot即可使用,使用类似 MATLAB 的函数。
使用该界面时,方法将自动选择当前图形和轴来显示绘图。在您使用pyplot.show方法或在 IPython 中执行您的单元之前,它将一直如此(也就是说,对于您的所有方法调用,这个当前数字将被一次又一次地选择)。
2.面向对象接口:可以这样用:
import matplotlib.pyplot as pltfigure, axes = **plt**.subplots(2) # for 2 subplots# Now you can configure your plot by using
# functions available for these objects.
这是一个低级的库,你可以完全控制你的地块。
1.2 Seaborn
Seaborn 是一个基于 matplotlib 的高级可视化库。它主要用于制作快速和有吸引力的情节,而没有太多的麻烦。虽然 seaborn 试图以一种奇特的方式控制你的情节,但你仍然不能从中获得你想要的一切。为此,你必须使用 matplotlib 的功能,你也可以使用 seaborn(因为它是建立在 matplotlib 之上的)。
2.分布图 ^

Photo by Daniel Leone on Unsplash
分布图告诉我们一个变量是如何分布的。它给了我们在特定范围内找到变量的概率。也就是说,如果我们从一个变量的总范围内随机选择一个数字,它会给出这个变量在不同范围内的概率。
分布图应Normally分布,以获得更好的结果。这是所有线性模型的假设之一,即正态性。Normal distribution看起来像一个中间有光尾巴的中等驼峰。
**Note:** If **TL;DR** (Too Long; Don’t wanna Read), just read initial function used to plot the sub-topic plot and then read through **Tips**. You can easily navigate through tips using **<** and **>** buttons.
Eg: here Tips #1 and plt.hist, below.
(:Tips # 1:)> 1)在大多数情况下,您可以使用
matplotlib.pyplot函数为您的绘图提供的参数。请务必查看函数的参数及其描述。
2) 所有matplotlib的函数甚至seaborn的函数都返回你的图在字典、列表或对象中的所有组成部分。从那里你也可以改变你的组件的任何属性(用matplotlib的语言Artists)。
箱形图和小提琴图在分类部分中。
- 直方图和核密度估计图(kde):
# Simple hist plot
_ = **plt**.hist(train_df['target'], bins=5, edgecolors='white')

# with seaborn
_ = **sns**.distplot(train_df['target'])

(:Tips # 2:)<> 3)为了给你的剧情提供一些有用的信息或者引起对剧情中某些东西的注意,你大多可以用
plt.text()或者plt.annotate()逃脱。4) 绘图最需要的参数是
*label*,绘图最需要的方法是*plt.xlabel*、*plt.ylabel*、*plt.title*、*plt.legend*。为了有效地传达你的信息,你应该从你的图中移除所有不想要的干扰,比如右轴和顶轴,以及你的图中任何其他不想要的结构。
import matplotlib.pyplot as plt_ = **plt**.hist(data, bins=10, color='lightblue',
label=lbl, density=True, ec='white')
**plt**.legend()
**plt**.title("Target variable distribution", fontdict={'fontsize': 19,
'fontweight':0.5 }, pad=15)
**plt**.xlabel("Target Bins")
**plt**.ylabel("Probability");
****
— — — — — — — — — — — — -
import matplotlib.pyplot as plt
from SWMat.SWMat import SWMat**swm** = SWMat(plt) # Initialize your plot**swm**.hist(data, bins=10, ***highlight***=[2, 9])
**swm**.title("Carefully looking at the dependent variable revealed
some problems that might occur!")
**swm**.text("Target is a bi-model dependent feature.\nIt
can be <prop fontsize='18' color='blue'> hard to
predict.<\prop>");**#** **Thats all!** And look at your plot!!

1) Normal Matplotlib, 2) Seaborn, 3) Matplotlib Power, 4) Storytelling With Matplotlib
3.关系图 ^

Photo by Vincent van Zalinge on Unsplash
关系图对于获取两个或多个变量之间的关系非常有用。这些关系可以帮助我们更好地理解我们的数据,并可能帮助我们从现有的变量中产生新的变量。
这是Data Exploration和Feature Engineering中的重要一步。
a)线条图: ^
线图对于检查两个变量之间的线性关系,甚至二次关系、指数关系和所有此类关系非常有用。
5) 你可以通过使用参数'
color' / 'c','alpha,'edgecolors' / 'edgecolor'来给你的剧情一个美学的外观。6)
Seaborn在它的大多数绘图方法中都有一个参数“hue”,您可以用它来显示这些图中分类变量的不同类别之间的对比。你应该用较浅的颜色来画出你想画的部分,但它们不是你想画的重点。
****plt**.plot('AveRooms', 'AveBedrms', data=data,
label="Average Bedrooms")**plt**.legend() # To show label of y-axis variable inside plot
**plt**.title("Average Rooms vs Average Bedrooms")
**plt**.xlabel("Avg Rooms ->")
**plt**.ylabel("Avg BedRooms ->");**

您也可以像这样手动对它们进行颜色编码:
****plt**.plot('AveRooms', 'AveBedrms', data=data, c='lightgreen')
**plt**.plot('AveRooms', 'AveBedrms', data=data[(data['AveRooms']>20)],
c='y', alpha=0.7)
**plt**.plot('AveRooms', 'AveBedrms', data=data[(data['AveRooms']>50)],
c='r', alpha=0.7)**plt**.title("Average Rooms vs Average Bedrooms")
**plt**.xlabel("Avg Rooms ->")
**plt**.ylabel("Avg BedRooms ->");**

**# with seaborn
_ = **sns**.lineplot(x='AveRooms', y='AveBedrms', data=train_df)**
********
— — — — — — — — — — — — -
****swm** = SWMat(plt)**swm**.line_plot(data_x, data_y, line_labels=[line_lbl], highlight=0,
***label_points_after***=60, xlabel=xlbl, point_label_dist=0.9,
***highlight_label_region_only***=True)
**swm**.title("There are some possible outliers in 'AveRooms' and
'AveBedrms'!", ttype="title+")
**swm**.text("This may affect our results. We should\ncarefully
look into these and <prop color='blue'>finda\n
possible resolution.<\prop>",
position="out-mid-right", fontsize=20,
btw_line_dist=2.2);# '**point_label_dist**' (to adjust distance between points' labels and
# lines) in `.line_plot` method and '**btw_line_dist**' (to adjust lines
# between two lines in text) in `.text` method are only used when
# result given by library is not what you want. Most of the times
# this library tries to give the right format, but still some
# mistakes can happen. I will try to make it fully automatic in
# future.**

1) Normal Matplotlib, 2) Seaborn, 3) Matplotlib Power, 4) Storytelling With Matplotlib
b)散点图: ^
并非两个变量之间的每一种关系都是线性的,实际上只有少数是线性的。这些变量中也有一些随机成分,这使得它们几乎是线性的,而其他情况下有一种完全不同的关系,我们很难用线性图来显示。
此外,如果我们有很多数据点,散点图可以方便地检查大多数数据点是否集中在一个区域,是否有任何异常值 w.r.t .这两个或三个变量,等等。
如果我们对 3D 图中的第四个变量进行颜色编码,我们可以绘制两个或三个甚至四个变量的散点图。
7) 你可以用两种方式设置你的地块的大小。您可以从
matplotlib中导入figure并使用类似于:figure(figsize=(width, height))的方法,或者您可以在使用类似于figure, plots = plt.subplots(rows, cols, figsize=(x,y))的面向对象接口时直接指定figsize。当你试图用数据传达信息时,你应该简明扼要。
**from matplotlib.pyplot import figure
figure(figsize=(10, 7))**plt**.scatter('AveRooms', 'AveBedrms', data=data,
edgecolors='w', linewidths=0.1)**plt**.title("Scatter Plot of Average Rooms and Average Bedrooms")
**plt**.xlabel("Average Bedrooms ->")
**plt**.ylabel("Average Rooms ->");**

**# With Seaborn
from matplotlib.pyplot import figure
figure(figsize=(10, 7))**sns**.scatterplot(x='AveRooms', y='AveBedrms', data=train_df,
label="Average Bedrooms");**

8) 在
.text和.annotate方法中有一个参数bbox,它使用一个字典来设置文本周围的框的属性。对于bbox,几乎所有情况下都可以用pad、edgecolor、facecolor、alpha蒙混过关。9) 在
.annotate方法中有一个用于设置箭头属性的参数,如果设置了xytext参数,就可以设置这个参数,它就是arrowprops。它以一个字典作为参数,你可以用arrowstyle和color蒙混过关。10) 你可以使用
matplotlib的fill_between或fill_betweenx来填充两条曲线之间的颜色。这可以方便地突出曲线的某些区域。你应该花时间考虑如何绘制数据,以及哪个特定的图能最大程度地传达你的信息。
**from matplotlib.pyplot import figure
figure(figsize=(10, 7))**plt**.scatter('AveRooms', 'AveBedrms', data=data)
**plt**.plot(train_df['AveRooms'], Y, linewidth=1, color='red',
linestyle='-', alpha=0.8)**plt**.xlabel("Avg Rooms ->")
**plt**.ylabel("Avg BedRooms ->")# Adding annotations:
**plt**.annotate("Possible outliers", xy=(144, 31), xytext=(160, 34),
arrowprops={'arrowstyle':'-[,widthB=4.0', 'color':
'black'},
bbox={'pad':4, 'edgecolor':'orange', 'facecolor':
'orange', 'alpha':0.4})**plt**.annotate("Regression Line", xy=(80, 12), xytext=(120, 3),
arrowprops={'arrowstyle':'->', 'color': 'black',
"connectionstyle":"arc3,rad=-0.2"},
bbox={'pad':4, 'edgecolor':'orange', 'facecolor':
'orange', 'alpha':0.4});**
********
— — — — — — — — — — — — -
****swm** = SWMat(plt)
**plt**.scatter(x, y, edgecolors='w', linewidths=0.3)
**swm**.line_plot(x, *Y*, highlight=0, highlight_color="#000088",
alpha=0.7, line_labels=["Regression Line"])
**swm**.title("'AveBedrms' and 'AveRooms' are highly correlated!",
ttype="title+")
**swm**.text("Taking both of them in regressioin process\nmight not be
necessary. We can either\n<prop color='blue'>take one of
them</prop> or <prop color='blue'>take average.</prop>",
position='out-mid-right', btw_line_dist=5)
**swm**.axis(labels=["Average Rooms", "Average Bedrooms"])# 'SWMat' has an `axis` method with which you can set some Axes
# properties such as 'labels', 'color', etc. directly.**

1) Normal Matplotlib, 2) Seaborn, 3) Matplotlib Power, 4) Storytelling With Matplotlib
c)二维直方图、十六进制图和等高线图: ^
2D 直方图和 Hex 图可用于检查特定位置数据的相对密度。
等值线图可用于绘制 2D 的 3D 数据,或绘制 4D 的 3D 数据。轮廓线(或填充轮廓中的色带)告诉我们函数具有常数值的位置。它让我们熟悉绘图中使用的所有变量。例如,它可以用于绘制深度学习中不同θ的成本函数。但是要做到准确,你需要大量的数据。至于绘制整个景观,你需要该景观中所有点的数据。如果你有一个关于那个景观的函数,你可以很容易地通过手动计算值来绘制这些图。
**from matplotlib.pyplot import figure
figure(figsize=(10, 7))**plt**.hist2d('MedInc', 'target', bins=40, data=train_df)
**plt**.xlabel('Median Income ->')
**plt**.ylabel('Target ->')
**plt**.suptitle("Median Income vs Target", fontsize=18);**

但是seaborn中没有单独的十六进制绘图/2D-历史绘图方法,您可以使用jointplot方法的kind参数来制作十六进制绘图。更多信息请查看seaborn上的联合图。
一个
colorbar需要一个Mappable对象。默认情况下,Contour、Scatter和hist2d等图给出了它们。你可以简单地调用plt.colorbar(),它会在你的图旁边显示一个colorbar。对于其他图,如果需要,您可以手动制作一个colorbar。[在 Jupyter 笔记本的“历史”部分提供了一个例子。]E】总是尽量选择一个简单的,群众容易理解的情节。
**# Hexbin Plot:
from matplotlib.pyplot import figure
figure(figsize=(10, 7))**plt**.hexbin('MedInc', 'target', data=train_df, alpha=1.0,
cmap="inferno_r")**plt**.margins(0)
**plt**.colorbar()
**plt**.xlabel('Median Income ->')
**plt**.ylabel('Target ->')
**plt**.suptitle("Median Income vs Target", fontsize=18);**

**from matplotlib.pyplot import figure
figure(figsize=(10, 7))
**plt**.hist2d('MedInc', 'target', bins=40, data=train_df,
cmap='gist_heat_r')
**plt**.colorbar()
**plt**.xlabel('Median Income ->')
**plt**.ylabel('Target ->')
**plt**.suptitle("Median Income vs Target", fontsize=18)# Adding annotations:
**plt**.annotate("Most Blocks have low med.\nincome and lower target.",
xy=(5, 1.5), xytext=(10, 2),
arrowprops={'arrowstyle': '->', 'color': 'k'},
bbox={'facecolor': 'orange', 'pad':4, 'alpha': 0.5,
'edgecolor': 'orange'});**

等高线图 : 等高线图是在 2D 图上可视化 3D 数据的一种方式。在matplotlib中有两种方法可用,即.contour和.contourf。第一个制作线条轮廓,第二个制作填充轮廓。您可以传递 z 值的 2D 矩阵,也可以为 X 值和 Y 值传递两个 2D 数组 X,Y,为所有相应的 z 值传递一个 2D 数组。
**# For **contour plot**
from matplotlib.pyplot import figure
figure(figsize=(10, 7))**plt**.contourf(Z, levels=30, cmap="gist_heat_r")
**plt**.colorbar()**plt**.suptitle("Target Contour", fontsize=16)
**plt**.title("(with Medium Income and Population)",
position=(0.6, 1.03))
**plt**.xlabel("Medium Income ->")
**plt**.ylabel("Population ->")**

d)配对图: ^
seaborn提供了一个方法pairplot,你可以用它一次绘制出所有可能的关系图。它可以用于快速查看数据中所有变量之间的关系,以及每个变量的分布。
**_ = **sns**.pairplot(train_df)**

4.分类图 ^

Photo by Sharon McCutcheon on Unsplash
分类图在数据探索步骤中也是必要的,因为它们告诉我们不同类别的变量在数据集中是如何分布的。如果我们有足够的数据,我们就可以从这些曲线图中得出该变量不同类别的结论。
因为 *seaborn* 我在这里加了箱子剧情和小提琴剧情。在 *seaborn* 中有一些参数,您可以使用这些参数对不同的分类变量使用这些方法。
a) 条形图
b) 方框图
c) 小提琴剧情
一)条形图 ^
条形图可用于类别之间的对比,其高度代表特定于该类别的某些值。
**from matplotlib.pyplot import figure
figure(figsize=(10, 7))**plt**.bar(np.sort(data.unique()), data.value_counts().sort_index(),
alpha=0.7) **#** You might need to sort; Be carefully with
**#** which values are being plotted with each
**#** other.**plt**.xlabel("Target ->")
**plt**.ylabel("Frequency ->");**

12) 如果在每个
matplotlib和seaborn函数的输出中有你想要改变属性的补丁或对象,你可以通过使用.set函数将属性名作为字符串和属性值传递给它来改变它,或者你可以直接对那个属性使用 set 函数,如set_color、set_lw等。有近 8%的男性是色盲,近 1/10 的女性是色盲。但你还是应该小心他们。对比对他们中的大多数人都有效。
**# Seaborn
from matplotlib.pyplot import figure
figure(figsize=(10, 7))**sns**.barplot(np.sort(data.unique()),data.value_counts().sort_index())**plt**.xlabel("Target ->")
**plt**.ylabel("Frequency ->");**

**from matplotlib.pyplot import figure
figure(figsize=(10, 7))**plt**.bar(np.sort(train_df['target_int'].unique()),
train_df['target_int'].value_counts().sort_index(),
alpha=0.7, width=0.6)**plt**.grid(True, alpha=0.3)
**plt**.xlabel("Target ->", fontsize=14)
**plt**.ylabel("Frequency ->", fontsize=14)
**plt**.title("Target Frequencies", fontsize=18)# Remove top and left spines:
ax = **plt**.gca() # Get current axis (gca)
**ax**.spines['right'].set_visible(False)
**ax**.spines['top'].set_visible(False)# Adding annotations:
counts = train_df['target_int'].value_counts().sort_index()
**plt**.annotate(str(counts[0]), xy=(0, counts[0]),
xytext=(0,counts[0]+400), ha = 'center',
bbox={'boxstyle': 'round', 'pad': 0.5, 'facecolor':
'orange', 'edgecolor': 'orange', 'alpha': 0.6},
arrowprops={'arrowstyle':"wedge,tail_width=0.5",
'alpha':0.6, 'color': 'orange'})
**plt**.annotate(str(counts[1]), xy=(1, counts[1]),
xytext=(1, counts[1]+400), ha = 'center',
bbox={'boxstyle': 'round', 'pad': 0.5, 'facecolor':
'orange', 'edgecolor': 'orange', 'alpha': 0.6},
arrowprops={'arrowstyle':"wedge,tail_width=0.5",
'alpha':0.6, 'color': 'orange'})
**plt**.annotate(str(counts[2]), xy=(2, counts[2]),
xytext=(2, counts[2]+400), ha = 'center',
bbox={'boxstyle': 'round', 'pad': 0.5, 'facecolor':
'orange', 'edgecolor': 'orange', 'alpha': 0.6},
arrowprops={'arrowstyle':"wedge,tail_width=0.5",
'alpha':0.6, 'color': 'orange'})
**plt**.annotate(str(counts[3]), xy=(3, counts[3]),
xytext=(3, counts[3]+400), ha = 'center',
bbox={'boxstyle': 'round', 'pad': 0.5, 'facecolor':
'orange', 'edgecolor': 'orange', 'alpha': 0.6},
arrowprops={'arrowstyle':"wedge,tail_width=0.5",
'alpha':0.6, 'color': 'orange'})
**plt**.annotate(str(counts[4]), xy=(4, counts[4]),
xytext=(4, counts[4]+400), ha = 'center',
bbox={'boxstyle': 'round', 'pad': 0.5, 'facecolor':
'orange', 'edgecolor': 'orange', 'alpha': 0.6},
arrowprops={'arrowstyle':"wedge,tail_width=0.5",
'alpha':0.6, 'color': 'orange'})
**plt**.xticks(ticks=[0, 1, 2, 3, 4], labels=["0 - 1", "1 - 2", "2 - 3",
"3 - 4", "4 - 5"], fontsize=12)
**plt**.ylim([0, 9500]);**
********
— — — — — — — — — — — — -
****swm** = SWMat(plt)
**swm**.bar(cats, heights, highlight={"cat": [-1]}, highlight_type=
{"data_type": "incrementalDown"}, cat_labels=["0-1", "1-2",
"2-3", "3-4", "4-5"], highlight_color={"cat_color":
"#FF7700"}, annotate=True)
**swm**.axis(labels=["Target values", "Frequency"])
**swm**.title("About most expensive houses in California...")
**swm**.text("California is a sea-side state. As most\nexpensive houses
are at sea-side we\ncan easily predict these values if
we\nsomehow <prop color='blue'>combine 'Latitude'
and\n'Longitude' variables </prop>and separate sea\nside
houses from non-sea-side houses.",
btw_text_dist=.1);**

1) Normal Matplotlib, 2) Seaborn, 3) Matplotlib Power, 4) Storytelling With Matplotlib
b)方框图 ^
箱线图是分布图的统计版本。它给出了不同的四分位数,平均值和极值的范围。一些可能的用例是,如果某些点超出了盒须线的范围,您可以使用它来识别可以发现异常值的变量,或者您可以通过图中中间盒的相对位置来检查分布中的偏斜。
**from matplotlib.pyplot import figure
figure(figsize=(15, 7))**plt**.boxplot(train_df['target'], vert=False)**plt**.xlabel("<- Target Values ->")
**plt**.ylabel("Target");**

**# With Seaborn:
from matplotlib.pyplot import figure
figure(figsize=(15, 7))sns.boxplot(train_df['MedInc']);**

13) 您可以通过使用
plt.xlim、plt.ylim、ax.set_xlim、ax.set_ylim功能来改变您的Axes的 x 极限、y 极限。您还可以通过将plt.margings或ax.margins用作plt.margins(x=2, y=-3)来放大和缩小您的绘图。14) 您可以从
plt.style.available中为您的图形使用不同的样式,为您的图形赋予不同的外观,并将其激活为plt.style.use(stylename)。最常用的款式是'fivethirtyeight'和ggplot。15)
seaborn和matplotlib有许多可用的色彩映射表,可用于设置连续变量图的颜色。你可以在这里找他们,在这里找他们。只突出你想引起观众注意的情节部分,只突出那些部分。
**from matplotlib.pyplot import figure
figure(figsize=(20, 7))bp = **plt**.boxplot([x1, x2], vert=False, patch_artist=True,
flierprops={'alpha':0.6, 'markersize': 6,
'markeredgecolor': '#555555','marker': 'd',
'markerfacecolor': "#555555"},
capprops={'color': '#555555', 'linewidth': 2},
boxprops={'color': '#555555', 'linewidth': 2},
whiskerprops={'color': '#555555', 'linewidth': 2},
medianprops={'color': '#555555', 'linewidth': 2},
meanprops={'color': '#555555', 'linewidth': 2})**plt**.grid(True, alpha=0.6)
**plt**.title("Box Plots", fontsize=18)
**plt**.xlabel("Values ->", fontsize=14)
**plt**.ylabel("Features", fontsize=14)
**plt**.yticks(ticks=[1, 2], labels=['MedInc', 'Target'])bp['boxes'][0].set(facecolor='#727FFF')
bp['boxes'][1].set(facecolor="#97FF67")# Adding Text:
**plt**.text(11, 1.5, "There are many potential\nOutliers with respect
to\nMedian Income", fontsize=18,
bbox={'facecolor': 'orange', 'edgecolor': 'orange',
'alpha': 0.4, 'pad': 8});**
********
— — — — — — — — — — — — —
****swm** = SWMat(plt)
bp = **plt**.boxplot([x1, x2], vert=False, patch_artist=True,
flierprops={'alpha':0.6, 'markersize': 6,
'markeredgecolor': '#555555','marker': 'd',
'markerfacecolor': "#555555"},
capprops={'color': '#555555', 'linewidth': 2},
boxprops={'color': '#555555', 'linewidth': 2},
whiskerprops={'color': '#555555', 'linewidth': 2},
medianprops={'color': '#555555', 'linewidth': 2},
meanprops={'color': '#555555', 'linewidth': 2})
**plt**.xlabel("Values ->", fontsize=14)
**plt**.ylabel("Features", fontsize=14)
**plt**.yticks(ticks=[1, 2], labels=['MedInc', 'Target'])
bp['boxes'][0].set(facecolor='#727FFF')
bp['boxes'][1].set(facecolor="#97FF67");**swm**.title("Many unusual outliers in 'MedInc' variable...")
**swm**.text(("It may be because of acquisition of sea side\n"
"places by very wealthy people. This <prop
color='blue'>aquisition\n"
"by many times greater earners</prop> and yet not much\n"
"number has made box plot like this."),btw_line_dist=.15,
btw_text_dist=.01)**

1) Normal Matplotlib, 2) Seaborn, 3) Matplotlib Power, 4) Storytelling With Matplotlib
c)小提琴剧情 ^
小提琴情节是盒子情节的延伸。它也有均值、极值的指标,也可能有不同的四分位数。除此之外,它还显示了两边变量的概率分布。
**from matplotlib.pyplot import figure
figure(figsize=(10, 7))**plt**.violinplot(train_df['target'])**plt**.title("Target Violin Plot")
**plt**.ylabel("Target values ->");**

**# With Seaborn
from matplotlib.pyplot import figure
figure(figsize=(10, 7))**sns**.violinplot(train_df['target']);**

16) 您可以使用
plt.axhline、plt.axvline或ax.axline、ax.axvline功能在绘图区内绘制垂直线或水平线。做一个善于讲故事的人,用大众容易理解的方式通过故事传达你的发现。
**from matplotlib.pyplot import figure
figure(figsize=(10, 7))vp = **plt**.violinplot(train_df['target'], vert=False, showmeans=True,
showmedians=True)**#** Returns a dictionary with keys : ['bodies', 'cbars', 'cmaxes',
**#** 'cmeans', 'cmedians', 'cmins']
**#** Using these we can tinker with our plot:
vp['bodies'][0].set_edgecolor("k")
vp['bodies'][0].set_linewidth(2)
vp['bodies'][0].set_alpha(1.0)
vp['bodies'][0].set_zorder(10)vp['cmeans'].set_linestyle(":")
vp['cmeans'].set_color("r")
vp['cmeans'].set_zorder(101)
vp['cmeans'].set_segments(np.array([[[2.06855817, 0.7], [2.06855817, 1.3]]]))vp['cmedians'].set_linestyle("--")
vp['cmedians'].set_color("orange")
vp['cmedians'].set_zorder(100)
vp['cmedians'].set_segments(np.array([[[1.797, 0.7], [1.797, 1.3]]]))vp['cbars'].set_zorder(99)
vp['cbars'].set_color("k")
vp['cbars'].set_linewidth(0.5)vp['cmaxes'].set_visible(False)
vp['cmins'].set_visible(False)# Legend:
**plt**.legend(handles=[vp['bodies'][0], vp['cmeans'], vp['cmedians']],
labels=["Target", "Mean", "Median"], handlelength=5)
**plt**.title("Target Violin Plot")
**plt**.xlabel("Target")
**plt**.yticks([])
**plt**.grid(True, alpha=0.8)# Adding Text
**plt**.text(x, y, f"({train_df['target'].median()}) Median",
bbox={'facecolor':'orange', 'edgecolor': 'orange', 'pad':4,
'alpha': 0.7}, zorder=12)
**plt**.text(x2, y2, f"Mean ({np.round(train_df['target'].mean(),3)})",
bbox={'facecolor':'red', 'edgecolor': 'red', 'pad':4,
'alpha': 0.6}, zorder=11);**
********
— — — — — — — — — — — — —
**TK Work in Progress...**

1) Normal Matplotlib, 2) Seaborn, 3) Matplotlib Power, 4) Storytelling With Matplotlib
5.多个地块 ^

Photo by Ricardo Gomez Angel on Unsplash
您可以使用plt.subplots方法或通过指定方框坐标手动添加Axes到图形中,或使用plt.GridSpec()方法,根据需要绘制任意多的图形。即
- 要么使用:
fig, axess = plt.subplots(ncols=2, nrows=4)然后你可以通过访问这些Axes中的任何一个作为axess[col_num][row_rum]来绘制它们,然后使用任何Axes方法来绘制它们。 - 或通过使用
plt.axes()方法给出四个百分比值的列表,给出Axes的【左、下、宽、高】以在figure中制作。比如:plt.axes([0.1, 0.1, 0.65, 0.65)。 - 或者使用
plt.GridSpec()方法。如grid = plt.GridSpec(n_row, n_col)。现在,当通过plt.subplot()方法制作Axes时,您可以使用此grid作为 2D 阵列来选择使用多少和哪些栅格来制作电流,一个,Axes。例如plt.subplot(grid[0,:])将选择整个第一行作为一个Axes。如果你愿意,你也可以留下一些。
****plt**.figure(1, figsize=(10, 8))
**plt**.suptitle("Hist-Distribution", fontsize=18, y=1)# Now lets make some axes in this figure
axScatter = **plt**.axes([0.1, 0.1, 0.65, 0.65])
**#** [left, bottom, width, height] in percent values
axHistx = **plt**.axes([0.1, 0.755, 0.65, 0.2])
axHisty = **plt**.axes([0.755, 0.1, 0.2, 0.65])**axHistx**.set_xticks([])
**axHistx**.set_yticks([])
**axHisty**.set_xticks([])
**axHisty**.set_yticks([])
**axHistx**.set_frame_on(False)
**axHisty**.set_frame_on(False)
**axScatter**.set_xlabel("MedInc ->")
**axScatter**.set_ylabel("Population ->")# Lets plot in these axes:
**axScatter**.scatter(x, y, edgecolors='w')
**axHistx**.hist(x, bins=30, ec='w', density=True, alpha=0.7)
**axHisty**.hist(y, bins=60, ec='w', density=True, alpha=0.7,
orientation='horizontal')
**axHistx**.set_ylabel("")# Adding annotations:
**axScatter**.annotate("Probably an outlier", xy=(2.6, 35500),
xytext=(7, 28000),
arrowprops={'arrowstyle':'->'},
bbox={'pad':4, 'facecolor':'orange', 'alpha':
0.4, 'edgecolor':'orange'});**

17)
seaborn有自己的网格/多点对象,即Facet Grid、Pair Grid和Joint Grid。他们有一些方法,如.map、.map_diag、.map_upper、.map_lower等,你可以研究一下,只在 2D 网格中的那些位置绘制图形。读一读科尔·奈弗利克的《用数据讲故事》。这是一本很好的读物,它用一个著名的数据通信者的例子涵盖了每个方面。
**from matplotlib.pyplot import figure
figure(figsize=(10, 8))**sns**.jointplot(x, y);**

6.互动剧情 ^

Photo by Ricardo Gomez Angel on Unsplash
默认情况下,matplotlib中的交互式绘图是关闭的。这意味着只有在您发出最后的plt命令或使用了触发plt.draw的命令(如plt.show())后,该图才会显示给您。您可以通过ion()功能打开交互式绘图,通过ioff()功能关闭交互式绘图。打开它,每个plt功能都会触发plt.draw。
在现代 Jupyter 笔记本/IPython 世界中,有一个魔法命令可以打开这些笔记本中的交互/动画功能,那就是%matplotlib notebook,要关闭它,您可以在使用任何plt功能之前使用魔法命令%matplotlib inline。
matplotlib与许多用户界面工具包(wxpython、tkinter、qt4、gtk 和 macosx)配合使用,以显示交互式绘图。对于这些交互图,matplotlib使用event和事件处理程序/管理器(fig.canvas.mpl_connect)通过鼠标或键盘捕捉一些事件。
这个事件管理器用于将一些内置的事件类型查看器连接到一个自定义函数,如果特定类型的事件发生,该函数将被调用。
有许多可用的事件,如'按钮 _ 按压 _ 事件','按钮 _ 释放 _ 事件','绘制 _ 事件','调整大小 _ 事件','图形 _ 输入 _ 事件',等。可以像fig.canvas.mpl_connect(event_name, func)一样连接。
对于上面的例子,如果event_name事件发生,所有与该事件相关的数据都将被发送到您的函数func中,在这里您应该已经编写了一些代码来使用所提供的数据。该事件数据包含 x 和 y 位置、x 和 y 数据坐标、是否在Axes内点击等信息。如果它们与您的事件类型event_name相关。
**%matplotlib notebook
# Example from matplotlib Docs**class** LineBuilder:
**def** __init__(self, line):
self.line = line
self.xs = list(line.get_xdata())
self.ys = list(line.get_ydata())
self.cid = line.figure.\
canvas.mpl_connect('**button_press_event**', self) **def** __call__(self, event):
print('click', event)
if event.inaxes!=self.line.axes: return
self.xs.append(event.xdata)
self.ys.append(event.ydata)
self.line.set_data(self.xs, self.ys)
self.line.figure.canvas.draw()fig = plt.figure()
ax = **fig**.add_subplot(111)
**ax**.set_title('click to build line segments')
line, = **ax**.plot([0], [0]) # empty line
linebuilder = LineBuilder(line)**# It worked with a class because this class has a __call__
# method.****

Random lines drawn using above code (by consecutive clicking)
7.其他人 ^

3D 剧情: ^
matplotlib的 3D 图不在普通库中。在mpl_toolkits中是因为matplotlib开始只有 2D 图,后来在mpl_toolkits中增加了 3D 图。可以导入为from mpl_toolkits import mplot3d。
导入后,您可以通过将projection='3d'传递给任何Axes初始化器/maker 函数来制作任何Axes 3D 轴。
****ax** = **plt**.gca(projection='3d') # Initialize...# Data for a three-dimensional line
zline = np.linspace(0, 15, 1000)
xline = np.sin(zline)
yline = np.cos(zline)
**ax**.plot3D(xline, yline, zline, 'gray')# Data for three-dimensional scattered points
zdata = 15 * np.random.random(100)
xdata = np.sin(zdata) + 0.1 * np.random.randn(100)
ydata = np.cos(zdata) + 0.1 * np.random.randn(100)
**ax**.scatter3D(xdata, ydata, zdata, c=zdata, cmap='Greens');**

18) 在执行绘图功能之前,您可以通过运行
%matplotlib notebook来交互查看 3D 绘图。
有许多 3D 绘图可用,如line、scatter、wireframe、surface、contour、bar等,甚至还有subplot可用。你也可以用text功能在这些图上写字。
**# This import registers the 3D projection, but is otherwise unused.
from mpl_toolkits.mplot3d import Axes3D# setup the figure and axes
**plt**.figure(figsize=(8, 6))
**ax** = plt.gca(projection='3d')**ax**.bar3d(x, y, bottom, width, depth, top, shade=True)
**ax**.set_title('Bar Plot')**

地理剧情: ^
要用matplotlib绘制地理图,你必须安装另一个由matplotlib开发的名为Basemap的软件包。安装并不容易,在这里寻找官方说明,或者你可以使用conda命令,如果你已经安装了 Anaconda:conda install -c conda-forge basemap,或者如果这些对你来说也不起作用,在这里寻找(特别是最后的评论)。
**from mpl_toolkits.basemap import Basemapm = Basemap()
m.drawcoastlines()**

实际上,您可以在这里使用 matplotlib 的大多数原始函数,如text、plot、annotate、bar、contour、hexbin,甚至是这些投影上的 3D 绘图。
它还有一些与地理图相关的功能,如streamplot、quiver等。
****m** = Basemap(projection='ortho', lat_0=0, lon_0=0)
# There are a lot of projections available. Choose one you want. **m**.drawmapboundary(fill_color='aqua')
**m**.fillcontinents(color='coral',lake_color='aqua')
**m**.drawcoastlines()x, y = map(0, 0) # Converts lat, lon to plot's x, y coordinates.**m**.plot(x, y, marker='D',color='m')**

***# llcrnr: lower left corner; urcrnr: upper right corner*
**m** = Basemap(llcrnrlon=-10.5, llcrnrlat=33, urcrnrlon=10.,
urcrnrlat=46., resolution='l', projection='cass',
lat_0 = 39.5, lon_0 = 0.)
**m**.bluemarble()
**m**.drawcoastlines()**

**from mpl_toolkits.mplot3d import Axes3D**m** = Basemap(llcrnrlon=-125, llcrnrlat=27, urcrnrlon=-113,
urcrnrlat=43, resolution='i')fig = **plt**.figure(figsize=(20, 15))
ax = **Axes3D**(fig)**ax**.set_axis_off()
**ax**.azim = 270 # Azimuth angle
**ax**.dist = 6 # Distance of eye-viewing point fro object point**ax**.add_collection3d(**m**.drawcoastlines(linewidth=0.25))
**ax**.add_collection3d(**m**.drawcountries(linewidth=0.35))
**ax**.add_collection3d(**m**.drawstates(linewidth=0.30))x, y = m(x, y)
**ax**.bar3d(x, y, np.zeros(len(x)), 30, 30, np.ones(len(x))/10,
color=colors, alpha=0.8)**

‘Target’ distribution (red -> high) in California. [From above used California Dataset]
字云剧情: ^
词云在自然语言处理(NLP)中使用,在可以是云或不是云的某个边界内,显示具有最多频率的词,其大小取决于它们的频率。它将数据中单词之间的相对频率差异绘制为其字体的相对大小。在大多数情况下,仅仅通过查看单词云也很容易找到出现频率最高的单词。但这仍然是一种有趣的方式来传达数据,因为它很好理解和容易理解。
有一个 python 包wordcloud,你可以把pip当作pip install wordcloud来安装。
你可以先设置WordCloud的一些属性(比如使用mask参数设置云的形状,指定max_words,指定stopwords等。)然后为给定的文本数据生成具有指定属性的云。
**from wordcloud import WordCloud, STOPWORDS# Create and generate a word cloud image:
wordcloud = **WordCloud**()\ # Use default properties
.generate(text) # Display the generated image:
**plt**.imshow(wordcloud, interpolation='bilinear')
**plt**.axis("off")**

**from PIL import Image
mask = np.array(Image.open("jour.jpg")) # Searched "journalism
# black png" on google
# images...
stopwords = set(STOPWORDS)wc = **WordCloud**(background_color="white", max_words=1000, mask=mask,
stopwords=stopwords)# Generate a wordcloud
**wc**.generate(text)# show
**plt**.figure(figsize=[20,10])
**plt**.imshow(wc, interpolation='bilinear')
**plt**.axis("off")
**plt**.show()**

动画: ^
你可以使用这两个类中的一个来轻松制作动画:
FuncAnimatin:反复调用函数*func*制作动画。ArtistAnimation:使用一组固定的Artist对象的动画。
(:提示# 12:)<
始终保持对实例对象
Animation的引用,否则将被垃圾回收。20) 使用
Animation.save或Animation.to_html5_video方法之一将动画保存到磁盘。21) 您可以使用设置为
True的参数blit来加速/优化动画的绘制。但是如果blit=True你将不得不返回一个由init_func重画的艺术家列表。
在FuncAnimation中,你需要传递至少一个当前的fig和一个将为每一帧调用的函数。除此之外,你还应该查看参数frames (iterable,int,generator,None 要传递给func和动画每一帧的数据源】、init_func(用于绘制清晰帧的函数,否则使用frames的第一帧)和blit(是否使用位块传输)。
**%matplotlib notebookfig, ax = **plt**.subplots()
xdata, ydata = [], []
ln, = **plt**.plot([], [], 'ro')**def** init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,**def** update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
return ln,
# Always keep reference to `Animation` obj
ani = **FuncAnimation**(fig, update, frames=np.linspace(0, 2*np.pi,
128), init_func=init, blit=True)**

8.延伸阅读 ^
- 用数据讲故事——科尔·n·克纳弗里克(一本关于如何通过知名数据交流者使用图形/图表交流数据的好书)
- Python 数据科学手册— Jake VanderPlas
- 在 Jupyter 中嵌入 Matplotlib 动画作为交互式 JavaScript 小部件— Louis Tiao
- 用 Python 生成单词云— Duong Vu
- 底图教程
9.参考文献 ^
- 用数据讲故事——Cole n . Knaflic(一本关于如何通过知名数据交流者使用图形/图表交流数据的好书)
- Python 数据科学手册——杰克·范德普拉斯
- 在 Jupyter 中嵌入 Matplotlib 动画作为交互式 JavaScript 窗口小部件——Louis Tiao
- 用 Python 生成单词云— Duong Vu
- Matplotlib 教程:Python 绘图— Karlijn Willems
- 底图教程
- Matplotlib 文档
- Matplotlib mplot3d 工具包
- Matplotlib —交互式
- Matplotlib —动画
- Seaborn Docs
**Suggestions and reviews are welcome.
Thank you for reading!**
签名:

制作您自己的智能家庭安全摄像机

Security Camera Set-up
一台可以进行面部识别的相机,成本不到 80 美元。

Demo
不久前,我想买一台好的智能相机,但我的需求与相关成本不相称。所以,我决定用我已经有的零件做一个。
所需零件:
- 树莓 PI 3
- 网络摄像头
- PIR 传感器/超声波传感器
所需知识:
- 计算机编程语言
- OpenCV
- dlib
如果你想要更多关于 OpenCV 和 dlib 的信息,那么请看看我的旧文章。
什么是 PIR 传感器?

[Source: Google]
一个被动红外传感器 ( PIR 传感器)是一个电子传感器,它测量从其视野内的物体发出的红外(IR)光。它们最常用于基于 PIR 的运动检测器。所有温度高于绝对零度的物体都以辐射的形式放出热能。通常这种辐射对人眼是不可见的,因为它以红外波长辐射,但它可以被 PIR 传感器检测到。
什么是超声波传感器?

[Source: Google]
超声波传感器是一种使用超声波测量物体距离的仪器。超声波以高于人类听觉范围的频率振动。它使用单个传感器发送脉冲并接收回波。传感器通过测量发送和接收超声波脉冲之间的时间间隔来确定到目标的距离。
方法
通俗地说,PIR 传感器将检测瞬间,摄像头将捕捉帧,Raspberry PI 将执行面部识别并提供最终输出。
更详细地说,我已经将 PIR 传感器与 Raspberry PI 连接起来,网络摄像头正对着我公寓的前门。我没有使用 AWS 或任何其他云服务来执行推理或发送通知。我正在进行局部推断,并在我的扬声器上播放关于谁进入的声音。
到目前为止,单独的 Raspberry PI 还不是一个理想的执行实时推理的嵌入式平台。因此,我使用 PIR 传感器来确定何时启动推理机并执行面部识别。你也可以使用超声波测距仪,但在我的情况下,我打算用它来完成我的另一个项目。
一旦门被打开,有人进入,PIR 传感器将开始检测。当 PIR 传感器检测到任何类型的移动时,摄像机将开始捕捉 10 秒钟的帧。与此同时,OpenCV 的“ Haar Cascades ”将开始检测人脸,dlib 的“ 68 点人脸标志检测”将检测到的人脸标志与保存的标志进行匹配,以检查它是否是入侵者?
使用 OpenCV,我们可以从网络摄像头捕捉帧,并将每个帧转换为 numpy 数组。这里,我们以 320x240 的速率记录帧。我们也可以录制全高清帧,但在 Raspberry PI 上执行人脸检测将花费大量时间。然后使用“haarcascade _ frontal face _ alt 2 . XML”模型,在给定的帧中检测人脸。一旦我们识别了所有的面孔,我们将把它们存储在一个列表中,以便将它们与保存的面孔进行比较。
我们会用 dlib 进行人脸对比。dlib 68 点人脸标志检测将为您提供给定人脸的标志。我们确实有一些已知的面部标志存储在 numpy 文件中,我们将在比较之前加载这些文件。一旦我们有了所有的地标,我们就能找到这些地标之间的距离。我们使用 0.6 作为阈值。给你阈值以下最小距离的面部标志是进入房间的已知人。如果值不低于阈值,那么它是一个入侵者!!
您可以在下面的 git 资源库中找到完整的代码,
[## smitshilu/AISecurityCamera
在 GitHub 上创建一个帐户,为 smitshilu/AISecurityCamera 开发做出贡献。
github.com](https://github.com/smitshilu/AISecurityCamera)
结论
你可以在家里开发一个智能摄像头来获取入侵者的状态。你也可以使用 AWS 或 Google Cloud 等服务向你的手机或短信发送通知。
如果你喜欢这篇文章,请关注我的**或Github或订阅我的 YouTube 频道 。****
使用并行处理让你的熊猫更快地应用函数
蟒蛇短裤
超级熊猫侠

Super Panda
并行化牛逼。
我们数据科学家已经有了四核、八核、睿频的笔记本电脑。我们使用具有更多内核和计算能力的服务器。
但是我们真的利用了我们手头的原始力量吗?
相反,我们等待耗时的过程结束。有时是几个小时,当紧急的交付品就在手边的时候。
我们能做得更好吗?我们能变得更好吗?
在这个名为'Python Shorts,‘的系列帖子中,我将解释由 Python 提供的一些简单构造,一些基本的技巧和我在数据科学工作中经常遇到的一些用例。
这篇帖子讲的是利用我们手头的计算能力,把它应用到我们最常用的数据结构上。
问题陈述
我们有一个巨大的熊猫数据框,我们想对它应用一个复杂的函数,这需要很多时间。
在这篇文章中,我将使用 Kaggle 上 Quora 非真诚问题分类的数据,我们需要创建一些数字特征,如长度、标点符号的数量等。这就去。
比赛是基于内核的比赛,代码需要在 2 小时内运行。所以每一分钟都是至关重要的,有太多的时间花在预处理上。
我们可以使用并行化来提高代码的性能吗?
是的,我们可以。
仅使用单个函数的并行化

Can we make all our cores run?
让我首先从定义我想用来创建我们的特征的函数开始。是我们希望应用于数据的玩具函数。
我们可以使用下面的函数来使用并行应用。
def parallelize_dataframe(df, func, n_cores=4):
df_split = np.array_split(df, n_cores)
pool = Pool(n_cores)
df = pd.concat(pool.map(func, df_split))
pool.close()
pool.join()
return df
它是做什么的?它将数据帧分成n_cores个部分,并产生n_cores进程,这些进程将函数应用于所有部分。
一旦它将函数应用于所有分割的数据帧,它就将分割的数据帧连接起来,并将完整的数据帧返回给我们。
我们如何使用它?
它使用起来非常简单。
train = parallelize_dataframe(train_df, add_features)
这有用吗?
为了检查这个并行化函数的性能,我在我的 Jupyter 笔记本的 Kaggle 内核中对这个函数运行了%%timeit magic。

与只使用现有功能相比:

如您所见,我通过使用并行化功能获得了一些性能。它使用的是只有两个 CPU 的 kaggle 内核。
在实际比赛中,涉及到大量的计算,我使用的add_features函数要复杂得多。这个并行化功能极大地帮助我减少了处理时间,并获得了银牌。
这里是带有完整代码的内核。
结论
并行化不是银弹;这是铅弹。它不会解决你所有的问题,你仍然需要优化你的功能,但是它是你的武器库中的一个很好的工具。
时间一去不复返,有时我们也缺少时间。此时,我们应该能够轻松使用并行化。
并行化不是银弹,而是铅弹
另外,如果你想了解更多关于 Python 3 的知识,我想向密歇根大学推荐一门关于学习中级 Python 的优秀课程。一定要去看看。
将来我也会写更多初学者友好的帖子。让我知道你对这个系列的看法。在 媒体 关注我或者订阅我的 博客 了解他们。一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter @mlwhiz 联系到我。
使用深度学习魔法让您的图片变得美丽

想获得灵感?快来加入我的 超级行情快讯 。😎
摄像技术很美。它给了我们所有人一个保存记忆的机会,当我们在照片中再次看到它们时,我们可以重温它们。
在过去的几年里,这项技术取得了长足的进步。有了各种各样的新功能,如 4K、HDR 和色彩增强,人们可以捕捉到令人惊叹的照片。
但这是有代价的。不是每个人都能买得起最好的相机。消费级 DSLR 相机的价格从几百美元到几千美元不等。不仅如此,并不是每个人都能充分利用这些相机;毕竟我们并不都是专业摄影师!
我们大多数人只是用手机。但与高端数码单反相机相比,智能手机拍摄的照片往往非常平淡。
深度学习改变了这一切。
美化您的照片
来自苏黎世联邦理工学院计算机视觉实验室的研究展示了如何自动增强低质量相机拍摄的照片,使它们看起来像是专业摄影师用 DSLR 拍摄的。
他们是这样做的。
该团队首先收集了一组低质量(来自手机)和高质量(来自 DSLR)的照片,你可以从项目页面下载。这正是我们在这样一个增强任务中想要的数据:输入一个低质量的图像(来自手机),并让深度网络尝试预测高质量的版本(来自 DSLR)会是什么样子。
一幅图像有几个我们可能想要增强的属性:光照、颜色、纹理、对比度和清晰度。深度网络被训练成用四种不同的损失函数来命中所有这些属性:
- 颜色损失:预测图像和目标图像的模糊版本之间的欧几里德距离。
- 纹理损失:基于生成对抗网络(GAN)的分类损失。训练 GAN 来预测灰度照片的质量是高还是低。由于使用了灰度,网络将很好地聚焦于图像的纹理而不是颜色。
- 内容损失:预测图像的 VGG 特征与地面真实之间的差异。这种损失确保了图像中的整体结构和对象(即图像语义)保持不变。
- 总变化损失:图像中的总垂直和水平梯度。这会增强图像的平滑度,这样最终的结果就不会太粗糙或太嘈杂。
最后,将这些损失加起来,训练一个端到端网络来进行预测!整体 GAN 架构如下所示。如果你也想了解更多,你可以查看的论文了解更多细节。

Architecture from the paper
代码
感谢 AI 社区开源思维的美丽,这里有一个公开可用的照片增强器的实现!这是你如何使用它。
首先克隆存储库
git clone [https://github.com/aiff22/DPED](https://github.com/aiff22/DPED)
安装所需的库
pip install tensorflow-gpu
pip install numpy
pip install scipy
所有预先训练的模型都已经在 models_orig 文件夹中的存储库中,所以没有必要下载它们!
将您要增强的照片放在以下目录中:
dped/iphone/test_data/full_size_test_images/
这是“iphone”的默认目录,但是如果你想改变它,你可以在test_model.py脚本中改变代码。它之所以说“iphone”是因为作者最初使用 3 部智能手机的照片训练了 3 个不同的模型:iphone、索尼和黑莓,所以这是你的三个选项。但是这个模型在大多数带有这些选项的照片上都能很好地工作,所以我们可以只选择一个并运行它!
最后,为了增强照片,我们只需运行一个简单的脚本:
python test_model.py model=iphone_orig \
test_subset=full \
瞧啊。您增强的专业照片将保存在visual_results文件夹中!
自己试试代码吧,很好玩的!查看照片增强后的效果。欢迎在下面发布链接,与社区分享您的照片。同时,这里有一些我自己测试的结果。








喜欢学习?
在 twitter 上关注我,我会在这里发布所有最新最棒的人工智能、技术和科学!
用 Python 制作 3 张简单的地图

在处理地理空间数据时,我经常需要以最自然的方式将这些数据可视化:一张地图。如果我们能够使用 Python 快速、轻松地创建您的数据的交互式地图,岂不是很好?在本教程中,我们将使用洛杉矶县所有星巴克咖啡店的数据集。在这篇介绍性文章结束时,您将能够创建:
- 洛杉矶县所有星巴克店的基本点地图
- 一张 choropleth 地图根据每家星巴克包含多少家星巴克来区分洛杉矶县的邮政编码
- 一张热图,突出了洛杉矶县星巴克的“热点”
我们开始吧!
你将需要…
- 蟒蛇包熊猫。这是用来在 Python 中轻松操作数据的
- 蟒蛇包叶子。这是用来非常容易地创建地图
- 洛杉矶县星巴克的经纬度电子表格(在我的 GitHub 上 这里 )
- 一个洛杉矶县的 GeoJSON(基本上是描述复杂形状的 JSON)(此处为)和一个洛杉矶县所有邮政编码的 geo JSON(此处为 )
为了熟悉数据,下面是前几行的快照:

对于这个分析,我们只需要关心纬度、经度和邮政编码字段。
以下是所需的 Python 导入、加载 Starbucks 数据和加载 LA County GeoJSON:
基点地图
从我们的数据框架中的纬度/经度对创建洛杉矶县所有星巴克的基本点地图非常简单。
打开laPointMap.html,我们看到如下地图:

我们可以清楚地看到洛杉矶县所有的星巴克都是洛杉矶县区域内的小红点。当然,您可以自定义任何颜色和形状的点。
等值区域图
在用 Python 玩地图之前,我实际上不知道什么是 choropleth 地图,但事实证明它们在可视化聚合地理空间数据方面非常有用。
我们的 choropleth 地图将回答这个问题:“洛杉矶县哪个邮政编码有最多的星巴克?”。choropleth 地图根据其他变量的值(在我们的例子中是星巴克店的数量)对每个邮政编码进行着色。
让我们先来看看创建一个所需的基本代码:
因为我个人发现要理解如何将 choropleth 的所有组件放置到位更加困难,所以让我们来看看一个单独的视觉效果,看看它是如何工作的。

choropleth 需要知道为邮政编码 90001、填充什么颜色。它检查由数据字段引用的熊猫数据帧,搜索邮政编码的 key_on 列,并找到在列中列出的另一列,即 numStores 。然后它知道它需要填充对应于邮政编码为 90001 的 3 商店的颜色。
然后,它在由 geo_path 字段引用的 GeoJSON 中查找,并找到邮政编码 90001 及其关联的形状信息,这告诉它在地图上为该邮政编码绘制哪个形状。通过这些链接,它拥有所有必要的信息。让我们看看 laChoropleth.html 由此产生的 choropleth!

我们看到它在顶部有一个漂亮的颜色条供参考。
热图
在上面的 choropleth 地图中,我们看到洛杉矶南部地区似乎有更多的星巴克店,但我们能不能再具体一点?我们能不能找出附近哪里有很多星巴克店?基本上,让我们创建一个热图来突出显示洛杉矶县的星巴克“热点”。
热图中需要一些试错的主要参数是半径和模糊,前者控制每个星巴克店周围的圆圈有多大,后者控制圆圈“融合”在一起的程度。
较高的半径意味着任何给定的星巴克影响较宽的区域,而较高的模糊度意味着彼此相距较远的两个星巴克仍然可以对热点有所贡献。参数由你决定!
让我们看看 laHeatmap.html 的天气图。

嗯……很酷,但是看起来好像所有的东西都是红色的。如果放大,热图可能更有价值。让我们放大一点,看看我们是否能确定更具体的热点。

不错!从上面的地图可以很清楚地看出,我们有一些热点和一些非热点(notspots?)在地图里。一个突出的是在洛杉矶市中心的(可以理解)。****
也就这样了!我唯一的遗憾是,我还没有找到一种方法来嵌入这些地图的实际互动版本,所以我只能给你看截图。我强烈鼓励你通过这篇文章运行小代码来为自己玩交互式地图。这是一种完全不同的体验。
我希望这篇文章对你有所帮助,下一篇再见!
包含本分析中使用的所有代码的完整笔记本可以在我的 GitHub 这里找到。
让糟糕的图表不那么糟糕
讲故事是人类相互交流的重要方式之一。为了讲述关于数据的故事,我们使用数据可视化,或者更简单地说,图表。
有一些可怕的图表,我们都见过。但是有更多的图表并不可怕,但仍然很糟糕。
前几天,在浏览我的脸书订阅时,我看到了《南佛罗里达州太阳哨兵报》的一篇关于枪支政治的文章。领先的数据可视化吸引了我的眼球——但不是以一种好的方式。颜色令人讨厌,东西相距太远,无法进行视觉比较,图表的风格也不太理想。
下图是:

Graphic from article in South Florida Sun Sentinel
让我们仔细看看是什么让这个图变得糟糕,看看我们是否可以让它变得不那么糟糕。
颜色
我注意到的关于视觉的第一件事是糟糕的颜色选择。虽然一开始用绿色表示“支持”和用红色表示“反对”可能有意义(就像交通灯的颜色),但应该避免这种颜色组合——这是有充分理由的。众所周知,最常见的色盲类型是红绿色盲,即那些受影响的人不能(或有困难)区分红色和绿色。如果你不能区分这两种颜色,这个图形是没有用的,或者说是令人困惑的。12 个男人中有 1 个,200 个女人中有 1 个患有色盲,红绿组合是一个糟糕的选择。
我开始想象用其他颜色组合的图表会是什么样子。我的第一个想法是:蓝色和橙色怎么样?这是一个常用的数据可视化配对,主要是因为它看起来很简单。但是当我意识到蓝橙色不适合这个图表时,我失望地叹了口气。所代表的数据与攻击性武器禁令的支持程度有关,这是一个不可否认的政治话题。由于蓝色通常用于民主党,红色用于共和党,使用这两种颜色都不是一个好主意。虽然民主党人更可能是支持者,而共和党人更可能是反对者,但用颜色暗示这些事情总是形影不离并不是一个好主意。
所以如果我不能用红色或蓝色,还剩下什么?我可能想待在室内,因为室外的颜色有时会让人分心,所以让我们试试绿色和橙色。从美学角度来看,这不是我最喜欢的选择——但总比不好好。
对比
这个图形恳求观众进行视觉比较,但这并不总是容易做到的。在图中,有三个相关的图形。上面的图表显示了所有佛罗里达人支持和反对攻击性武器禁令的比例,以及不知道或没有答案的人的比例。这是另外两个图表的比较点,这两个图表按性别和政党显示了支持、反对和未决定的比例。但是我的眼睛很难比较。当我试图评估无党派人士的支持水平是高于还是低于所有佛罗里达人的支持水平时,我可以感觉到我的眼球上下跳动。这些项目需要更紧密地结合在一起,以使观众能够合理地做出这些判断。
我也发现比较每个小组中反对者的百分比很有挑战性。比较支持者的百分比要容易得多,因为所有这些棒线都从同一点开始,都是 0%。由于对立类别的棒线都是从稍微不同的点开始,比较它们的长度就更加困难了。支持数据比反对数据更容易比较,这一事实暗示着支持数据可能比反对数据更容易理解,我认为这是一个不公平的假设。
我看到了两种可能的选择,让对立群体之间的比较更容易理解。选项 1:切换每个条形的反对组和未决定组的顺序。该触发器将使观察者能够更快地比较相对条的长度,因为它们都是右对齐的。互换进一步改善了图表,将各组放在一个从积极到消极的尺度上,在支持和反对之间犹豫不决,因为它自然下降。
选项 2:构建一个分组条形图,而不是堆叠条形图。这种类型的图形可能会简化对立物之间的视觉比较,因为所有棒线都从 0%开始。在这个选项中,理解对立数据的重要性与理解支持数据的重要性是同等的。
相同的数据,不同的视觉
下一步是接受不好的事情,让它变得更好(嗯,至少让它变得不那么坏)。我试图改善颜色,让东西更容易比较。这是我的设想:

几个显著的变化:(1)绿色和橙色,而不是绿色和红色,以及(2)两个并排的分组条形图,用水平线显示总体比例,而不是三组堆叠的水平条形图。
我意识到在我的新视野中有些东西丢失了。从表面上看,我的版本不太圆滑。我是一名初露头角的数据科学家,在这一点上,我主要使用 matplotlib 作为我的视觉效果。更实质性的是,关于未决定的群体的信息已经没有了。为了更清楚地比较支持者和反对者,我选择放弃强调每个群体的总和总是 100%。
请让我知道你的想法!我的目标是学习,我将非常感谢任何和所有的反馈。
用 Python 制作一个让孩子学习英语并从中获得乐趣的游戏

目标
为 2-6 岁的孩子建立一个互动游戏,学习英语词汇并从中获得乐趣。(GitHub 链接这里是)。)
这样做的原因
女朋友的姐姐有一个可爱的儿子,是幼儿园的孩子。他喜欢玩,而且精力充沛。像往常一样,就像其他孩子一样,他不喜欢阅读,更不用说说英语了。基于此,我想到为他制作一个游戏,练习他的记忆技巧,教他词汇,最重要的是,享受学习的过程。
游戏流程理念突破
好吧,这是游戏计划。
- 一个单词会显示几秒钟,孩子必须记住这个单词。假设这个词汇是“狗”。
- 将生成六个英文字符,并以随机顺序排列。例如,“A”、“C”、“G”、“D”、“P”和“O”。
- 孩子必须选择所显示的单词的正确顺序。
- 将显示 vocab 的图像并播放发音。




**
Game Design Paper Prototype
第一步——英语词汇列表
老话说,核桃和梨是你为你的继承人种下的。要制作这个游戏,一系列的英语词汇是必须的。除了自己从牛津词典中搜集资料,我们还可以利用他人的成果。所有的荣誉归于 gokhanyavas 。我们可以直接从 这里 下载词表。
*from urllib.request import urlopen
with urlopen('[https://raw.githubusercontent.com/gokhanyavas/Oxford-3000-Word-List/master/Oxford%203000%20Word%20List.txt'](https://raw.githubusercontent.com/gokhanyavas/Oxford-3000-Word-List/master/Oxford%203000%20Word%20List.txt')) as f:
word_list = [x.decode('utf-8') for x in f.read().splitlines()]*
导入词表后,还要做一些预处理工作。
删除带有符号和空格的单词
*import re
# Substitute Symbols with Spaces
word_list= [re.sub('[-.]',' ',word) for word in word_list]# Remove Words with Spaces
word_list= list(filter(lambda x: ' ' not in x, word_list))*
把单词改成小写
*# Change to Lower Cases
word_list= [word.lower() for word in word_list]*
保留 3 到 4 个字符的单词(因为这个游戏是给孩子玩的,我们不能让单词太长,对吗?)
*# Keep the Words with 3 or 4 Characters
word_list = list(filter(lambda x: len(x) in [3, 4], word_list))*
检查单词的词性。我们只保留以下:
CD(基数)/ JJ(形容词)/ NN(名词)/ VB(动词)
*import nltk
# List of Part-of-Speech
pos_list = [nltk.pos_tag([word])[0][1] for word in word_list]
# List of Word Length
len_list = [len(word) for word in word_list]import pandas as pd
# Data Frame
word_df = pd.DataFrame({'Word': word_list,
'POS':pos_list,
'Len': len_list})# Keep CD / JJ / NN / VB
word_df = word_df[word_df['POS'].isin(['CD','JJ','NN','VB'])]*
最终,我们可以得到这样一个数据框:

word_df
第二步——词汇发音
有了单词列表后,我们需要词汇发音 mp3 文件,这样游戏就可以教孩子们正确地发音。简单地说,我们将充分利用谷歌文本到语音包。
*from gtts import gTTS
import os.path
if not(os.path.isdir('Audio')):
os.mkdir('Audio')
print('Audio is downloading. It may take a few minutes.')
for word in list(word_df['Word']):
audio_save_path = 'Audio/'+ word + '.mp3'
gTTS(text=word, lang='en', slow=False).save(audio_save_path)*

English Words Audio Files
第三步——词汇卡通图片
除了声音之外,图像对于留下深刻印象和吸引孩子也至关重要。在这个游戏中,我使用从谷歌下载的图片。您也可以使用 Unsplash 或其他图像源。
*from google_images_download import google_images_download
from shutil import copyfile
from os import listdir
import shutil
if not(os.path.isdir('Image')):
os.mkdir('Image')
print('Audio is downloading. It may take a few minutes.')
for word in list(word_df['Word']):
response = google_images_download.googleimagesdownload()
response.download({"keywords": word,
"limit": 1,
"output_directory":'Temp_Image',
"suffix_keywords":'cartoon image'})
img_dir_list = listdir('Temp_Image')
for img_dir in img_dir_list:
initial_path = os.path.join('Temp_Image', img_dir)
file_name = listdir(initial_path)
if len(file_name) != 0:
file_path = os.path.join(initial_path, file_name[0])
final_path = os.path.join('Image', img_dir[:4].rstrip() + os.path.splitext(file_name[0])[1])
copyfile(file_path, final_path)
shutil.rmtree('Temp_Image')*

English Words Image Files
感谢上帝!所有的准备工作都完成了,接下来是最激动人心的部分——制作游戏。
第四步——智力游戏
在这个例子中,我使用 PyGame 来制作游戏。Pygame 是一套跨平台的 Python 模块,设计用于编写视频游戏。它包括设计用于 Python 编程语言的计算机图形和声音库。

有一些技巧,然后你可以学习和创造自己的游戏。
游戏初始化
*import pygame# Game Init
pygame.init()
win = pygame.display.set_mode((640, 480))
pygame.display.set_caption("KidsWord presented by cyda")run = True
while run:
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.update()
pygame.quit()*
要开始游戏,我们需要一个游戏窗口。有两件事情需要设置。
- 窗口大小-示例:(640,480)
- 窗口显示名称-示例:“cyda 提供的童剑”

添加背景颜色
*win.fill((59, 89, 152))*
RGB 颜色-示例:(59,89,152)

添加文本
*font_1 = pygame.font.SysFont('impact', 55)
font_2 = pygame.font.SysFont('Arial', 25)
win.blit(font_1.render('KidsWord', False,(242, 242, 242)),(215, 45))
win.blit(font_2.render('Presented by cyda', False, (212, 216, 232)), (350, 135))*
要添加文本,您必须指定以下参数。
- 字体样式-示例:“影响”
- 字体大小-示例:55
- 字体颜色-示例:(242,242,242)
- 字体位置-示例:(215,45)

添加几何形状
*pygame.draw.rect(win, (255, 255, 255), (270, 250, 85, 40))*
以画矩形为例,我们必须指定
- 形状颜色-示例:(255,255,255)
- 形状位置-示例:(x_upperleft,y_upper_left,x_bottomright,y_bottom_right)= (270,250,85,40)

添加可点击按钮
事实上,没有正式的或官方的功能让你创建一个按钮。因此,我们必须以一种巧妙的方式来做这件事。
1.定义可点击的按钮区域
*button_area = pygame.Rect(270, 250, 85, 40)*
2.定义触发功能
*def button_pressed():
win.fill((255, 255, 255))
win.blit(font_1.render('Page 2', False, (0, 0, 0)), (230, 240))*
3.添加鼠标点击事件
*if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = event.pos
if (button_area.collidepoint(mouse_pos)):
button_pressed()*

添加计时器
在一个游戏中,计时器是你没有机会摆脱的必要元素。例如,如果玩家不能在一定时间内完成任务,他/她可能会输掉游戏。在我的情况下,我会在时间结束后切换页面。
要设置定时器,请遵循以下步骤:
1.初始化时间参数
*font_3 = pygame.font.SysFont('impact', 120)
clock = pygame.time.Clock()
pygame.time.set_timer(pygame.USEREVENT, 1000)
page = 0
time_limit = 3*
2.更改鼠标点击事件
*if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = event.pos
if (button_area.collidepoint(mouse_pos)):
time_count = time_limit
page = 1
button_pressed()
if page == 1:
if event.type == pygame.USEREVENT:
time_count -= 1
time_text = int(time_count)
if time_text > time_limit:
time_text = time_limit
pygame.draw.rect(win, (59, 89, 152), (420, 50, 100, 160))
win.blit(font_3.render(str(time_text), True, (242, 242, 242)), (440, 50))
pygame.display.flip()
clock.tick(60)
if time_count < 0:
win.fill((255, 255, 255))
win.blit(font_1.render('Page 2', False, (0,0,0)), (230,240))*

添加图像
*image = pygame.image.load('car.png')
image = pygame.transform.scale(image, (600, 300))
win.blit(image, (25, 150))*
PyGame 有一个直接加载图片的功能。但是,你要提醒两件事。
- 不允许使用动画图像。
- 你最好转换图像比例,以便更好地适应你的窗口大小。

播放音频
可以导入 PyGame 支持的混音器模块来播放音频文件。
*from pygame import mixer
mixer.init()
mixer.music.load('car.mp3')
mixer.music.play()*
这些都是我用来建造这个奇妙游戏的技术。而现在,女朋友的表妹愿意坐下来,也爱学英语。
编辑的话
写一篇教程文章并不容易,而且费时。如果你喜欢阅读它,并且觉得它很有用,请分享给你的朋友。将来,我们会发布一系列的教程文章,敬请关注!=)
还有,如果你有兴趣了解更多的窍门和技巧,欢迎你浏览我们的网站:【https://cydalytics.blogspot.com/
领英:
杨皇-https://www.linkedin.com/in/yeungwong/
罗嘉丽-https://www.linkedin.com/in/carrielsc/
其他文章
- 数据可视化技巧(Power BI) —将分类变量转换为虚拟变量
- 中文异状字云(Python)
- 数据科学基础(R):从 Excel 导入数据— readxl
- 数据科学基础(R):从文本文件导入数据— textreadr & readtext
- 数据科学基础(R):导入&导出 Excel 中的数据— xlsx
如何制作一个可以查看交易图表的人工智能(并用于交易)

我们生活在一个大多数事情越来越依赖于计算机视觉和深度学习的世界。从自动标记你夏天的照片到安全摄像头的面部检测,感觉我们生活在一个反乌托邦的未来。
虽然人工智能革命仍在我们身边发生,但对我来说,2019 年的春天是有趣的时刻。在完成一门深度学习课程后,我开始修补深度学习的许多不同用例,如图像分类到自然语言处理(NLP)。在花了几个小时使用 Python 和 Keras 库之后,我训练了一个简单的卷积神经网络(CNN ),它能够区分猫和狗的图像。听起来很简单,几年前这是一个巨大的任务,我很难相信简单的神经网络如何解决一个复杂的问题!通常,如果你想使用 CV 库进行图像识别,你必须进行特征工程,开发你自己的过滤器,并将许多特征硬编码到代码中。即使经过多次尝试,你也只能得到一个大约 60-70%准确的算法,这与我们今天用机器学习所能做到的相差甚远。

Deep Learning Methods Looks into Pictures as Matrices
我完全被深度学习的简单性惊呆了。首先,我定义了一个非常简单的 CNN 架构,然后用猫和狗的图像标记我的数据集。之后开始训练,观察训练精度和验证精度的上升,直到达到令人满意的指标。就是这样!!接下来,加载您的模型和权重文件,然后使用您想要预测的文件运行 model.predict 命令。结果是正确的分数!
深度学习的简单性和准确性简直太棒了!
大约在同一时间,我对经济学和当日交易产生了兴趣。我开始阅读雷伊·达里奥的 生活和工作原则。 (如果你还没看,我只能推荐)
Principles by Ray Dalio
在他的书中,他谈到了他的公司如何创造出专有的算法,做出财务决策来管理他的对冲基金,并成为世界上最成功的基金之一。虽然这个故事非常鼓舞人心,但它让我开始思考,我们不要教计算机任何东西,让它自己解决问题怎么样。与过去计算机视觉的特征工程不同,深度学习还可以用于创建算法,这些算法决定何时买卖股票、外汇、石油以及你能想到的任何东西。
如果数据中有一个模式,你不需要自己去发现,它会被深度学习发现,这就是 Inpredo 项目的开始。

Charts, more charts!
第一步。创建培训数据:
所以在我们进去创造一个赚钱机器之前(小心我过于乐观的评论。)我们需要训练数据。很多!
感谢上帝,这不会很难,因为我们已经从上面的链接访问 CSV 数据。我们需要做的只是创建一个算法,该算法能够查看历史数据,并创建图表,然后根据工具(例如欧元/美元)价格在未来是上涨还是下跌对其进行分类。因为我们有历史数据,我们知道在数据时间范围内的任何给定时间价格发生了什么,所以很容易对生成的图表图像进行分类。
创建图表是容易的部分,我们需要几个库和我为此创建的函数,这个函数叫做 graphwerk.py(发电厂乐团,有人知道吗?)
所以 graphwerk 非常简单,你只需要以列表格式插入所选乐器的历史数据。我们将印刷覆盖 12 小时/蜡烛的图表。所以你的列表长度必须是 12。如果你想覆盖更大的时间范围,那么你需要增加你的列表长度。关于粒度,您可以选择每小时、每天甚至每分钟的数据。如果你想用更多的蜡烛来打印图表,这是完全没问题的,但是我不想在训练数据中引入太多的噪音。
import matplotlib.pyplot as plt
import mpl_finance
import numpy as npdef graphwerk(open, high, low, close, instrument):
# Create Prefixes for correct data
if instrument == 'XAU/USD':
prefix = 'xau'
elif instrument == 'USOil':
prefix = 'USOil'
elif instrument == 'XAGUSD':
prefix = 'xag'
else:
print('Instrument prefix is not defined in graphwerk')
return
fig = plt.figure(num=1, figsize=(3, 3), dpi=50, facecolor='w', edgecolor='k')
dx = fig.add_subplot(111)
mpl_finance.candlestick2_ochl(dx, open, close, high, low, width=1.5, colorup='g', colordown='r', alpha=0.5)
plt.autoscale()
# Create a moving average overlay
sma = convolve_sma(close, 3)
smb = list(sma)
diff = sma[-1] - sma[-2]
for x in range(len(close) - len(smb)):
smb.append(smb[-1] + diff)
dx2 = dx.twinx()
dx2.plot(smb, color="blue", linewidth=8, alpha=0.5)
dx2.axis('off')
dx.axis('off')
timestamp = int(time.time())
file_name = realtime_data + str(prefix) +str(timestamp) + '.jpg'
plt.savefig(file_name, bbox_inches='tight')
#Uncomment this line to see the plot right after script runs.
#plt.show
plt.close()
return file_name
运行该脚本后,它将创建如下所示的图表:

XAU/USD Chart with the past 12 hours data.
我知道图像尺寸很小,但对于深度学习,你不需要 4K分辨率的照片或图表。对于大多数人工智能深度学习应用程序来说,大约 200x200 像素已经足够了。事实上,使用较小尺寸的图像是一件好事,因为为深度学习提供 4K 图像最终将需要一个超级昂贵的 GPU 集群,如新的英伟达 DGX,价格约为 2 万美元。深度学习的酷之处在于,如果你很聪明,你可以使用分辨率较低的图像来大幅降低处理能力,而这些图像仍然携带相同数量的信息:)
如果你也可能注意到了,酒吧看起来并不像现实生活中的样子。原因是我故意操纵它们,在蜡烛之间嵌入额外的信息,降低它们的透明度。这就产生了重叠的蜡烛,这些蜡烛也可以在蜡烛重叠区域的混合颜色中携带信息。
在这个半透明蜡烛的顶部有一个简单的移动平均线(SMA ),当它穿过蜡烛时,透明度也会降低,以创建附加信息。您可以随意改变形状、大小和透明度,以创建完美的训练数据集。
步骤 2:为训练数据集创建 10000 幅图像
所以上面的脚本对于创建单个图像来说是很棒的,但是我们需要更多来训练一个神经网络。我说的是这里有几千个。所以作为开发人员,我们不只是点击按钮一千次,对不对?我们需要自动以滚动时间窗口的方式检查整个 csv 文件,并自动将图表图像放置在正确的文件夹中,如“购买”和“出售”。逻辑非常简单,定义时间窗口 12,(这意味着每小时 csv 文件中的 12 小时窗口),并在 for 循环中的每个循环中将窗口向前移动 1 小时。通过这种方式,我们将能够根据历史数据的大小创建足够数量的样本。
为了能够创建足够数量的训练数据,您只需要以下格式的干净 csv 数据,然后剩下的只是等待脚本完成对数据的完整循环。您将需要为此创建 2 个文件夹,最终将填充 2 种类型的数据:购买和出售。当最后一根蜡烛线的收盘价低于下一根蜡烛线的收盘价时,创建的图表将被保存到“买入”文件夹中。换句话说,如果最后一根蜡烛线的收盘价高于下一根蜡烛线的收盘价,那么“卖出”文件夹将包含图表图像。
第三步:训练一个简单的卷积神经网络
在创建数据集之后,我们需要定义一个神经网络架构,然后输入训练数据来训练神经网络,以区分可能的买入或卖出信号之间的差异。
如果你已经注意到,我不是在谈论任何一种策略或某种算法设计来找出这些模式。人工智能的神奇之处在于,它会自己找出模式。
目前,有许多不同种类的卷积网络架构设计用于图像分类。Xception 是获奖产品之一,但我们不会使用目前先进的产品。
我们的模型将是一个基本的卷积网络,具有丢弃层和全连接层,如下所示:
model = Sequential()
model.add(Convolution2D(nb_filters1, conv1_size, conv1_size, border_mode ='same', input_shape=(img_height, img_width , 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(pool_size, pool_size)))
model.add(Convolution2D(nb_filters2, conv2_size, conv2_size, border_mode ="same"))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(pool_size, pool_size), dim_ordering='th'))
model.add(Convolution2D(nb_filters3, conv3_size, conv3_size, border_mode ='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(pool_size, pool_size), dim_ordering='th'))
model.add(Flatten())
model.add(Dense(1024))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(classes_num, activation='softmax'))
model.summary()
model.compile(loss='categorical_crossentropy',
optimizer=optimizers.rmsprop(),
metrics=['accuracy'])
结果
经过无数个小时摆弄参数和创建,减少,过滤训练数据,人工智能模型能够在 2 年的数据集内以 63%的准确率进行“猜测”!
就像所有正常人会做的那样,我把这个人工智能模型插入了 kraken 的实时交易引擎,进行 BTC 对美元的交易,希望能赚些钱,讲述暴富的故事。顺便说一下,如果你想进入 API 交易,我只能推荐北海巨妖。它们是受监管的交易所,拥有安全稳定的 API。
Have an idea regarding to AI and Machine Learning? Book a time with me and let’s see what we can do together!
非常有趣的是,它真的赚了钱在这个时间段内连续 10 天达到了%5.34 的涨幅。与此同时,BTC 兑美元下跌了%3.29!
所以最酷的是,不管市场是涨是跌。它只是根据情况来缩短或拉长乐器。因此,即使在市场上所有东西都在贬值的情况下,这种模式仍然能够赚钱。

Holy sh.t, it works moment
由于 digitalocean 的超级易用的虚拟机部署,在创建此类模型以持续运行 bot 后,我每月的总支出约为 15 美元。你也可以试试下面的促销代码并获得 100 美元的信用点数来启动一台虚拟机。这相当于 3 个月的免费使用。只需选择一个一键部署的 ubuntu 部署,并使用我在文章末尾附上的 github repo。
所以我写这篇文章的原因是想告诉你还有很多事情需要去做。预测一只股票是涨是跌只是故事的一半。如果你不知道股票上涨或下跌的百分比是多少,这不会有多大帮助,因为你不知道何时兑现你的收益。
所以显然这个人工智能模型需要随着时间的推移而改进。考虑到人工智能模型需要定期更新以适应不断变化的市场条件也是很好的。
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
如果你想自己运行代码,看看结果,看看 github 页面:https://github.com/cderinbogaz/inpredo
Have a project idea to discuss? You can book a time with me using the link above.
查看我在 Medium 上的其他项目和文章:
免责声明:如果你用我的代码用自己的钱在市场上交易,我不对你的损失负责。注意安全,不要去冒自己没有完全理解的风险。
从 Youtube 视频制作影像数据集

如何用逼真的图像改善你的深度学习数据集?
深度学习模型的好坏取决于你提供给它的数据。这就是为什么花足够的时间收集大量的好数据是非常重要的。我所说的“好”是根据手头的问题而变化的。确定你的数据是否合适的一个有用的技巧是考虑用户的输入会是什么样子。这是一个重要的问题,尤其是在处理图像时。光线、对比度、方向、图像质量和视角可能会有很大差异,不考虑这些差异会在预测中产生巨大的误差。例如,如果你想使用你的模型制作一个手机应用程序,不要只在专业相机拍摄的图像上训练它。尝试减少对训练数据的这种偏向的一组好的技术是数据扩充,但是我在这里不详细说明。
编辑(2021 年 2 月) : Youtube 更改了他们网站的源代码,因此get_urls功能不再工作。其余的代码工作正常(最新版本在我的 github 上),所以唯一的问题是获得一个视频 URL 列表。以下是一些建议:
- 手动收集一个 URL 列表,用它代替
get_urls的结果。这样做可能很烦人,但肯定有效。 - 用 Selenium 刮 Youtube,得到一些网址。考虑到网站现在的编码方式,这可能会很复杂,但应该是可行的。
- 使用 Youtube API 获取给定关键字的视频列表。这个 API 非常容易使用。唯一复杂的步骤是使用谷歌账户设置凭证。
如果您需要这些建议的帮助,请联系我:)
抓取图像
这篇长长的介绍说明了数据收集的重要性,并且存在许多工具和数据来源。在这篇文章中,我把重点放在图像上,因为我最熟悉这个话题。当试图收集特定主题的图像时,首先想到的是使用 Beautifulsoup 和 Selenium 等库来抓取谷歌图像。其实我写了这样一个刮刀,你可以在这里找到。然而,在谷歌上可以找到的图片数量是有限的,而且它们通常有相似的风格,如果这种风格不是你感兴趣的风格,这可能是一个问题。


Amateur image of hockey players (left) vs pros (right)
第二个较少被讨论和使用的数据来源是 Youtube。当我从斯坦福大学的人们那里找到一个很好的数据集时,我被激励去研究这个主题,这个数据集可以在这里找到。这是一个超过 100 万个 Youtube 视频链接的集合,涉及近 500 项运动。这在正确的时间落到了我身上,因为我正在研究一个体育分类器,它是根据从谷歌上搜集的图像进行训练的。这个模型有上面提到的问题,它在干净和专业的图片上工作得很好,但在业余爱好者的图片上工作得很差。
因此,这篇文章的想法是描述我如何使用 python 从 Youtube 视频中收集图像。主要步骤是在 Youtube 上搜索一个查询,并收集一部分结果视频作为链接。然后程序下载视频(这可能需要很多时间和数据,取决于你的互联网连接)并保存在本地。然后,在删除视频之前,每个视频被用来提取一定数量的帧,这些帧被保存。这种技术让我能够收集到更真实的图像,但当然,之后还要进行一些手动过滤,因为视频包含了很多额外的视觉效果。显然,这种数据来源更受限制,但它应该对许多主题有用。
代码
这个程序的代码实际上很简单,是由我从互联网上收集的一些小片段组成的。然而,我找不到一个从头到尾都能做我想做的事情的程序,所以我不得不自己连接这些步骤。完整的代码可以在我的 github 上找到并下载。
第一步是导入运行代码所需的所有库。
大部分都是相当标准的,都是 python 自带的。只需使用 pip 就可以获得需要安装的额外组件。分别是:BeautifulSoup 抓取 Youtube 网站并提取链接,pytube 下载视频,OpenCV 从视频中提取图片。
完成后,下一步是创建第一个函数,它在 Youtube 上搜索一个单词或短语,并返回视频的 URL。
构建它的第一步是将查询词/短语转换成 url,以防它包含空格或重音符号之类的东西。Youtube 搜索是通过在 url 中包含查询来完成的,使用 urllib 和 BeautifulSoup 从结果页面中提取 html。后者再次用于查找视频的链接,并将它们添加到列表中,直到达到该函数所请求的最大数量,以便返回该列表。关于 BeautifulSoup 是如何工作的,请看这篇文章。
收集完视频的 URL 后,下一个函数将它们下载到本地系统。再次请注意,这可能会占用你的下载限制很多,如果你有一个。
这是 pytube 库的一个简单应用(参见文档)。该代码只下载特定长度的视频和. mp4。视频的长度隐藏在返回的深处,所以我必须挖掘才能找到它。有很多方法可以获得这类信息,但它们对我不起作用。视频被下载到指定位置或当前工作目录。最后,所有代码都嵌入在 try 语句中,因为有许多视频在被请求时会导致错误。在这种情况下,脚本只是不下载视频并打印错误消息。
一旦视频下载完毕,就可以使用 OpenCV 提取图像了。这是一个相当大的图像处理库,可以做很多事情,但我只用它来做一个非常基本的任务。关于这个强大工具的更多细节,我推荐这个系列教程。
这将 mp4 文件的路径和保存图像的文件夹作为输入,如果还不存在的话就创建一个。使用 OpenCV 打开视频,捕捉图像并保存到正确的位置。通过尝试打开文件进行测试,只是为了确保图像没有损坏,在这种情况下,它会被删除。然后,视频快进指定的时间量,并且该过程继续,直到拍摄了最大数量的图像或视频结束。
图像根据输入中的名称进行标记,起始编号由一个自制函数确定。这是一个非常简单的函数,可以找到像“name_##”这样命名的文件的最大标签。jpg”以便不覆盖现有的图像。代码可以在 github repo 上找到。
该程序的最后一步显然是将所有内容合并到一个函数中,该函数接受一个查询词或短语,并最终将提取的图像保存在一个漂亮的文件夹中。
该函数查找 URL 并将视频下载到当前工作目录。然后,它会检查目录中的所有. mp4 视频,并从每个视频中提取正确数量的图像。使用过的视频之后会被删除,以避免重复使用和浪费磁盘空间。为了达到这篇文章的目的,唯一需要使用的函数是 extract_images_from_word。

Example of image scraped from Youtube about hockey
用网络摄像头制作艺术品
一个风格转移的实现和解释,慢和快。

Starry Stanford
几千年来,人类文化的一个真正重要的特征是我们的艺术。没有其他物种能够创造出甚至有点像利奥·达芬奇或梵高的画的东西。甚至许多人在创作这种质量的艺术时都有困难。直到最近,随着神经风格转移的引入,我们能够获取一幅图像的风格,然后将其应用于另一幅图像的内容。这使得计算机有能力创建如上图所示的图像,这是一张由梵高绘制的斯坦福大学胡佛大楼的照片,以星夜为风格。在这篇文章中,我将谈论神经风格转移,然后是快速风格转移。

(Left: Starry Night by Van Gogh) — (Right: Hoover Tower)
内部运作
在计算机视觉领域,卷积神经网络一直用于从自动驾驶汽车到医疗诊断的各种应用。如果你想了解更多关于它们是如何工作的,请查看我写的关于我如何建立一个皮肤损伤分类工具的文章,这里。一旦你读过这些,你就会知道 CNN 由卷积层(检测图像中的模式和对象)和最终的全连接层(预测)组成。我们在这里真正寻找的是通过卷积层捕获的信息。
在预先训练的 CNN(如 VGG19 网络)中,前 16 层是卷积层,用于捕获特征。

Conv1_1 until Conv5_4 are all used for feature extraction. Source.
最后一对层(FC1、FC2、softmax)仅用于返回图像中存在的不同对象的概率。我们实际上不需要这些图层来进行风格转换,因为我们不会对图像进行分类。靠近网络起点的层可以学习诸如边缘和拐角之类的真正低级的特征。在网络中向上移动,我们得到诸如形状的特征,直到我们最终达到高级特征,这些高级特征是整个对象,例如人的脸或动物的形状。

Features at different levels in a CNN. Source.
我们这里的目标是将某个图像的风格,以及某个图像的内容,转移到一个新的图像风格化的图像。为了实现这种双重优化,我们需要计算两次损失。一次为风格,一次为内容。

Content Loss Function
内容损失是通过测量 CNN 的输出图像与地面真实图像的相似性(欧几里德距离)来计算的,地面真实图像是它试图达到的目标。由于 CNN 中的特征地图只是一大串数字,所以它们可以用高维向量空间来表示。这意味着计算网络输出向量与地面真实向量之间的距离非常简单。我们可以从预先训练的网络(如 VGG16 网络)中检索该特征图。根据我们从网络的哪个部分获取特征地图,输出图像看起来会有所不同。如果我们选择一个真正在网络深处的层,很有可能,我们会得到一个看起来更抽象的输出图像。

Gram Matrix
风格损失依赖于一个叫做 Gram 矩阵的数学对象。Gram 矩阵是一个向量的所有可能内积的矩阵,它非常擅长捕捉非本地化信息。因此,它从图层中的要素地图获取所有信息,并去除该信息在图像中的空间位置。基本上,这是用来提取一个图像的风格。然后,通过再次测量输出图像的 gram 矩阵与风格目标之间的相似性来计算风格损失。

Style Loss Function
我们可以改变风格和内容重建的权重,以获得风格不同的图像。

Changes in weights reflecting on output.
现在快点
很好,现在我们有了一个风格转换的方法,但是速度的问题仍然是一个问题。这是由于模型的架构,减少损失是一个缓慢的迭代过程,无法实时应用。在约翰逊等人的论文中提出了一个解决这个问题的非常聪明的方法。他们没有获得一个图像并将其优化为风格化,而是创建了一个神经网络,可以直接输出风格化的图像。这个流程在几个方面有所不同。不是输入两个图像(内容、风格)并获得风格化图像的迭代输出,而是使用快速风格转换,根据网络的训练内容,输入一个图像并获得预定风格的快速输出。当然,这意味着你仍然要训练一个网络,但是对于你想使用的每一种风格只训练一次。该网络的结构如下图所示。

The architecture of the network.
这里,我们从特定层(3)计算生成的图像和风格化图像之间的内容损失。然后我们计算每个特征图的风格损失。然后,我们将这两个损失结合起来,形成一个整体损失。我们现在可以使用梯度下降来训练这个网络,以最小化这种全局损失。这是一个非常简单的过程,但你可以从中获得一些真正令人惊叹的艺术作品!它还将图像生成过程的速度提高了 1000 倍,同时生成了与标准神经类型转移非常相似的定性结果。你可能已经注意到这个网络有两部分,图像转换网络和损耗网络。
图像变换网络
这是一个简单的 CNN,具有用于网络内下采样和上采样的残差块和步进卷积。这导致输出与输入大小相同。用特征重构感知损失而不是每像素损失来训练该网络。等等…什么是知觉丧失?与更传统的每像素损失相比,它基于从预训练网络中提取的高级图像特征表示之间的差异,而不是图像中单个像素的差异。当我们试图重建图像时,每像素损失有两个问题,它们真的很慢,即使一张照片在视觉上可能与地面真相非常相似,但在数学上它们可能相差很远。这导致在试图修复这些不可见的更改时浪费了大量资源。
损耗网络
这只是一个权重被冻结的亏损网络。我之前解释过了。这个网络基于 VGG16 loss 网络,在微软的 COCO 数据集上训练,该数据集是日常生活中成千上万个常见物体的集合。
如果你想深入了解这一切是如何运作的,你应该阅读提出这个想法的原始研究论文。
这个新网络让我们风格化、实时化。


你可以在我的网站上玩这个游戏。整个事情的代码可以在我的 Github repo 上找到,是用 ML5JS 的风格转换文档制作的,也是基于 deeplearnjs 的。
另一个非常酷的演示是 NVIDIA 的快速照片风格算法,它可以创建照片般逼真的图像,这是风格化的。你可以查看它的源代码,这里。

NVIDIA’s Fast Photo Style Algorithm
后续步骤
虽然这种技术已经很好地工作了,但在我们可以用它做什么方面仍然有一些缺点。仍然没有算法可以接受两幅输入图像并对它们进行风格转换。像这样的技术可能会导致 AR 技术领域的一些疯狂的发展,并可能成为艺术家的宝贵工具!
如果你喜欢我的文章或者学到了新东西,请务必:
- 在 LinkedIn 上与我联系。
- 给我发一些反馈和评论(aryanmisra@outlook.com)。
- 看看这篇文章所基于的两篇论文(这里是这里是,这里是这里是)。
- 去我的网站上玩一个快速风格转换的现场演示吧。
用 Python 制作艺术地图
PYTHON 地图
岩石粉笔 Jayhawk!

Streets of Lawrence, Kansas colored by their length.
目的:我们将学习如何使用来自 OpenStreetMap 的数据用 Python 构建地图。
材料和方法:为了获取我们的数据,我们将使用 OSMNX Python 包。然后,我们将对检索到的数据进行解包,并根据街道的长度为每条街道分配一种颜色。然后使用 OSMNX 功能将数据可视化。最后,我们应用某些调整,使地图美观。
注意:如果你是从零开始,我会建议你按照这篇文章安装所有必要的库。这篇文章的全部内容可以在我的 GitHub 上找到。欢迎你来叉它。最后,为了更好地理解这篇文章,请在 PC 或 Mac 上用大显示器查看,这样你就可以看到地图的细节。

作者的一句话
OSMNX Python 包由 Geoff Boeing 编写,可用于从 OpenStreetMap 中检索、建模、分析和可视化街道网络和其他空间数据。
您可以尝试使用 Anaconda 安装 OSMNX 包,但是,您最终可能会获得一个旧版本的 OSMNX,并且本文中的所有代码都将无法工作。我建议你访问 Geoff Boeing Github 这里并下载这个包的最新版本到你的机器上。完成后,将 OSMNX 文件夹放在工作目录中。您的工作目录应该如下所示:

Figure 1 — Working directory with the OSMNX package.
如果你比我聪明,并且能够使用 conda 或 pip 命令安装 OS mnx 0.11 版,请发表评论。我想把这一步从流程中去掉。

导入库
让我们从导入我们需要的所有库开始。
Script 1 — Importing libraries.
如果你有任何问题,让我们用 Anaconda 安装缺失的包来解决。我将只讨论不常用的包,因为很可能你已经安装了 Pandas、Matplotlib 和其他广泛使用的包。
打开 Anaconda 提示符并导航到所需的 conda 环境。
要安装用于创建、操作和研究复杂网络的网络,请运行:
conda install -c anaconda networkx
要安装 GeoPandas 这是一个开源包,它通过允许对几何类型运行空间操作来扩展 Pandas 数据框的功能:
conda install geopandas
安装 PIL 一个用于图像处理的 Python 包:
conda install -c anaconda pillow
应该可以了。在我们继续之前,让我们运行一个健全性检查,以确保我们使用的是相同版本的包:
Scrip 2 — Checking version of packages.
脚本 2 的输出为:
The NetworkX package is version 2.3
The OSMNX package is version 0.11dev
The Request package is version 2.22.0
The PIL package is version 6.1.0
您可能使用这些包的不同版本而逃脱,但是如果您稍后得到一个讨厌的错误,罪魁祸首可能是您正在使用的不同的包。

获取我们的数据
我们将为堪萨斯州的劳伦斯市制作一张地图——一个我所热爱的城市。
为了制作地图,我们需要一些空间数据。您可以通过访问此站点下载 OpenStreetMap 数据。然而,我发现的最简单的方法是使用 OSMNX 包。让我告诉你这有多简单:
Script 3 — Grabbing spatial data.
因此,通过两行代码,您可以提取任何城市的网络。network_type变量用来描述你要抓取的网络类型。在脚本 3 中,我们将network_type变量设置为“全部”。这意味着我们将获取人行道、街道、高速公路等的数据。为了获取可行驶街道的相关数据,将脚本 3 第 8 行的network_type变量设置为“行驶”。如果您想获取人行道的数据,请将network_type设置为“步行”。
旁白:如果您想提取德克萨斯州达拉斯和德克萨斯州阿灵顿的数据,您可以运行以下脚本:
Script 3a— Grabbing spatial data for two cities.
脚本 3a 可能需要一些时间来运行,因为达拉斯地区很大。如果您想要更多城市的数据,只需将它们添加到places列表中。我建议您访问 OSMNX 示例 Jupyter 笔记本来了解关于这个包的更多功能——在本文中我几乎没有展示它的功能。

拆开我们的数据
ox.graph_from_place()方法返回的G是来自 NetworkX 类的一个MultiDiGraph对象。我们可以使用ox.plot_graph()方法来制作地图,但首先让我们打开它,这样我们就可以为网络中的每条线段分配颜色和宽度。
Script 4 — Unpacks the data from the G MultiDiGraph object.
纸条 4 拆包G。我们感兴趣的是保存在名为data的列表中。data中的每个元素都包含一个字典,该字典指定了一个段的属性,例如唯一 id、街道名称、最大速度、段的长度以及其他规范。下面是存储在data中的第一个字典的例子:

Figure 2 — The first element of the list named data.
你可以看到第一段是一条名为佛蒙特街的住宅双向街,长 81.54 米。当路段类型为人行道/小道时,公路关键字的值将为“人行道”。人行道类型的线段可能没有名称。

为网络中的每个线段指定颜色和线宽
在我们制作地图之前,我们将为每一段指定一种颜色。为此,我们将遍历data的元素。对于每个元素/片段,我们将根据其长度指定一种颜色。然后我们将这个颜色添加到一个名为roadColors的列表中,这个列表稍后将作为变量传递给制作地图的方法。
Script 5 — Assigning colors to each segment based on their length. The length is in meters.
这里是你发挥创造力的地方。例如,您可以更改颜色,添加更多 if 语句,更改每个 if 语句的条件,根据段名或速度限制分配颜色。
最后,我们还将创建一个列表,用于定义每个线段的线条粗细。为此,我们将遍历data的每个元素。数据中的项目是包含“高速公路”关键字的字典。我们将使用它来确定我们拥有的细分市场的类型。如果“highway”关键字的值是“footway ”,这意味着该线段用于步行,因此我们将为该元素指定线宽 1。任何不是“人行道”的部分,我们将指定 2.5 的线宽。根据你的地图的大小,你需要使用这个值来创建一个好看的地图。
Script 6 — Assign each segment a line width.

制作地图
我们终于准备好制作地图了。
Script 7 —Making a map for Lawrence, Kansas.
制作这张地图似乎需要做很多工作,但让我来解释一下脚本 7 中发生了什么:
第 4–6 行:这里我们指定堪萨斯州劳伦斯市的纬度和经度。这是地图的中心。你可以把地图放在任何你想要的纬度和经度的中心。
第 8–12 行:这里我们决定了地图的边界。您应该使用这条线来控制在地图上显示什么。例如,您可以通过向第 4–6 行中定义的纬度和经度分配较小的偏移量来关注城市中较小的区域,如市中心。
第 14–18 行:这里我们使用 OSMNX 包的ox.plot_graph()方法制作地图。我建议您阅读 OSMNX 软件包文档,查看所有可用的输入。我将只讨论我在这里使用的。
G:这是我们在脚本 3 中执行的ox.graph_from_place()方法的输出。
bbox:这是一个设置地图边界的元组。下面应该是语法(北界,南界,东界,西界)。
fig_height和fig_width:图形的高度和宽度,单位为英寸。
dpi:每英寸点数。
bgcolor:用于地图的背景色。默认为白色。
save:布尔型。如果是,将图形作为图像文件保存到磁盘。我们将此设置为 false,因为我们还没有准备好保存该数字。
edge_colors:线段的颜色。我们把这个设为等于roadColors。你也可以只传递你想要的颜色的字符串。
edge_linewidth:各线段的粗细。我们将其设为等于roadWidths。你也可以只传递一个你想要的线条粗细的浮点数。
第 21–47 行:这些行组成一个自定义图例。如果你熟悉 Matplotlib,你应该不会感到陌生。
第 49–50 行:我们在这里保存图形。
如果您为堪萨斯州的劳伦斯市制作一张地图,其中每条线段的长度都用颜色进行了编码,那么您应该会看到以下内容:

Figure 3 — Map of Lawrence, Kansas where each segment is colored by length.
结果真的很酷。诀窍是选择正确的颜色、线条粗细、地图边界和背景色来制作一幅好看的地图。

向地图添加边框和文本
我们基本上完成了地图。然而,我想添加一个边界和一些文字地图,使它看起来更艺术一点。我们将首先定义一些我在 StackOverflow 中发现的助手函数:
Script 8 — Helper functions to add border to map.
我们现在准备给图像添加一个边框。我们将只添加一个底部边框图像,但如果你愿意,你可以选择在顶部、左侧、右侧和底部添加边框。阅读 helper 函数的 docstring 以获得更多关于如何做的细节。
Script 9— Adding border to map.

Figure 4 — Map of Lawrence, Kansas with a bottom border.
那看起来真的很好;).
最后,让我们添加一些文本到图像的底部边框。为此,我们首先需要下载字体。游览ShareFonts.net,搜索“PMINGLIU”。下载字体并将其内容解压缩到您的工作目录中。
Script 10 — Add text to the map. The font type and size are define in line 9. The position, the text, font color, and type of font are define in line 12.

Figure 5 — Map of Lawrence, Kansas.
我们到此为止。)

结束语
为你的家乡制作地图,修改剧本 3 中的第 5 行和剧本 7 中的第 5 行和第 6 行。为了给你的城市创建一个好看的地图,你必须调整地图的边界和线条的粗细。如果你不喜欢我用的颜色,欢迎你更换。我很想看看你制作的任何地图。这里是我的 GitHub 的链接,这样你就可以获得这篇文章的全部内容。
欢迎您在 LinkedIn 上与联系。直到下一次,每天编码!
打赌:预测人工智能自动驾驶汽车何时会流行
无人驾驶汽车问世的基本方程式

Defining an equation for predicting when AI self-driving cars will be prevalent
我们都喜欢一个好的等式。你引用或看过多少次爱因斯坦关于物质和能量的著名方程式?
最著名的概率公式之一是著名的德雷克方程,它是由弗兰克·德雷克在 20 世纪 60 年代设计的,旨在帮助激起关于我们银河系其他地方存在生命以及我们可能能够与之交流的可能性的讨论和辩论。
在这些努力中,一个特别有争议的因素是,我们是否应该对可能存在于别处的智慧生命进行被动搜索还是更主动的搜索。被动搜索包括简单地试图捕捉任何信号的行为,然后在地球上得到内部警报,也许有什么东西在那里。主动搜索包括发出信号,让地球之外的听众知道我们在这里,我们这样做是希望引起回应。当然,引起回应对我们来说可能是好的也可能是坏的,著名的斯蒂芬·霍金曾预先警告说,我们可能会捅马蜂窝,最终导致我们自己的毁灭和灭亡。
你可能会想,除了地球以外,在我们银河系的某个地方有智慧生命的可能性有多大?
让我们首先同意,我们主要对智慧生命感兴趣,这意味着如果某个地方存在某种原始生命,而它或它们无法通过任何现代手段进行交流,我们会把这些放在一边,认为不值得去寻找。
据推测,一种智慧生命形式会发出各种各样的电磁辐射,就像我们在地球上所做的那样。20 世纪 50 年代末,天文学家弗兰克·德雷克一直在西弗吉尼亚使用大型射电天文设备扫描从我们星球反射回来的无线电波。
一亿个世界可能可以维持生命
科学家和天文学家不断猜测数字,特别是宇宙中可能有 1 亿个星球可以维持我们所知的生命。一亿这个数字是怎么得出来的?它是基于这样一种信念,即可能有 1000 亿个太阳,这些太阳中可能有百万分之一的太阳有各种各样的行星围绕太阳旋转,这些行星中可能有百万分之一的行星由孕育生命所需的方面组成。如果你把它相乘,你会得到一亿颗理论上可能有生命存在的行星。
弗兰克·德雷克选择组织一个小型会议,召集那些对智能生命的严肃追求非常感兴趣的人,并希望展开热烈的讨论。在为会议做准备时,他决定记下一种方法来预测我们银河系中存在智慧生命的可能性。
弗兰克提出的方程从那以后成为了著名的德雷克方程,这是对他推导出该方程的肯定。多年来,有许多人指出,这个等式没有包括许多其他因素,而这些因素本来应该包括在内。这很好,这不是弗兰克的断言,他的方程是最终的一切。
弗兰克·德雷克的方程式包括试图得出一个数字 N,这个数字据称是我们银河系中可能展示智慧并有可能与之交流的文明的数量。
德雷克方程是这样的:N = R-star x 因子 p x 因子 ne x 因子 1 x 因子 i x 因子 c x 因子 L
本质上,您将七个关键因素相乘,就会得到数字 n。每个因素在逻辑上都是合理的,因为您在进行这种估计时会考虑这些因素。这些因素倾向于相互建立,以考虑一种饼的方式来做,其中你可以分割一个饼,以递增的方式做,直到你得到最后一片。
我希望你能明白,德雷克方程其实很简单,很容易理解。我这样说并不是在贬低这个公式。事实上,我为这个等式易于理解而喝彩。
如果这个公式是神秘的,我怀疑它会获得如此广泛的兴趣和流行。
乘以因子得到 N
另一个有趣的方面是,这些因素都是相乘的。同样,这意味着简单。
这些因素看起来很简单,方程看起来也很简单,这使得它非常适合使用和讨论。与此同时,让我们都同意,得出这些因素的数字有点更具挑战性。事实上,关于德雷克方程的大多数争论并不是方程本身,而是人们可能插入方程中的因素的估计。
德雷克和他的同事在 1961 年根据他的公式得出的 N 是多少?这个小组决定用一个范围来表示 N 更谨慎,他们通常得出一个介于 1000 到 100000000 之间的值。
在为估计范围辩护时,你可以说他们得出了一个大于零的数字,它也小于一些真正大的数字,如估计数十亿。
德雷克方程有点像一个有用的锚。有一个主持人就像种一棵树,然后你可以看着更多的话语围绕着它生长。
这和 AI 自动驾驶汽车有什么关系?
在控制论人工智能自动驾驶汽车研究所,我们正在开发自动驾驶汽车的人工智能软件。最直言不讳的国家和世界范围内的辩论之一涉及人工智能自动驾驶汽车何时可以投入使用。这个问题不断地在会议上出现,不断地被这个领域内的人提出,也不断地被公众、监管者和许多其他利益相关者提出。
我建议我们推导出一种德雷克方程来帮助辩论。请允许我详细说明。
我想首先澄清和介绍一个概念,即人工智能自动驾驶汽车有不同的级别。最顶层被认为是第 5 层。5 级自动驾驶汽车是由人工智能驾驶的汽车,没有人类驾驶员参与。
对于低于 5 级的自动驾驶汽车,必须有一名人类驾驶员在场。人类司机目前被认为是汽车行为的责任方。人工智能和人类司机共同分担驾驶任务。
人工智能自动驾驶汽车的另一个关键方面是,它们也将在人类驾驶的汽车中行驶在我们的道路上。
预测方程的特征
回到预测人工智能自动驾驶汽车到来的话题,让我们考虑一个等式的特征,它可能有助于如此重要的努力。
首先,考虑谁对人工智能自动驾驶汽车的到来做出预测。
有各种各样的技术专家提供他们对人工智能自动驾驶汽车的看法,并提出我们何时能在街道上看到这些车辆。技术专家的一个好处是,他们有望精通技术,并能够判断人工智能和自主能力进展的有效性。
让我们也考虑一下,那些真正精通人工智能自动驾驶汽车并做出预测的技术专家可能会在没有任何有形的韵律或理由的情况下这样做。有时他们会发表“直觉”或本能宣言。
纵观科技的历史,我们肯定看到了相当多过于乐观的预测,但在规定的时间内都没有实现。这是一个容易落入的陷阱。
我们还需要澄清的是,人工智能自动驾驶汽车的技术可以双管齐下,提供实现自主的能力,但也因为缺乏迄今为止已知的方法、技术和计算工具而抑制了自主。因此,我发现考虑技术进步和它们是如何形成的是有用的,同时也考虑已知的技术障碍甚至是未知的,并将在未来的道路上被发现。
许多做出预测的技术专家通常不包括其他看似与技术无关的因素,这些因素可能会极大地影响技术的发展速度。有人可能会说,这是一种疏忽。
什么样的因素会影响 AI 自动驾驶汽车的问世?
目前,投资和监管有利于人工智能自动驾驶汽车的发展
有些经济因素要么会鼓励在人工智能自动驾驶汽车开发上的支出,要么可能会抑制和破坏这种支出,如果这些支出被抽走并用于其他目的的话。
另一个关键因素是社会和社会对人工智能自动驾驶汽车的接受或抵制。人工智能自动驾驶汽车的进展可能会面临一个艰难的选择,即让它们进入我们的公共道路,同时让它们卷入致命的车祸。
考虑监管环境以及它如何影响人工智能自动驾驶汽车的到来也至关重要。目前,关于在公共道路上使用人工智能自动驾驶汽车的法规相对宽松,并鼓励这种萌芽的创新。如果监管机构突然受到压力,要对人工智能自动驾驶汽车采取一些措施,例如当自动驾驶汽车在道路上行驶时发生死亡或受伤时,它可能会迅速转向更严格的监管环境。
不能仅仅依靠技术专家的观点
我相信你现在已经确信,任何试图预测人工智能自动驾驶汽车到来的等式都不应该仅仅依赖于技术专家的观点。我们希望包括经济视角、社会视角和监管视角。这提供了一个混合的视角,当只使用一个单一的因素时,将有望避免被意外地抓住或被暗算。
这些因素中的每一个都不一定相互独立。事实上,它们很可能会一起朝着同一个方向摆动,尽管有时会有延迟。
在探索一系列因素时,你可能会认为每个因素最终都可能成为人工智能自动驾驶汽车的支持者和推动者,或者每个因素都可能成为反对者,往往会对人工智能自动驾驶汽车的到来造成阻力或抑制。这是一种推拉式的紧张。至关重要的是将这种张力包含在用于做出这种预测的等式中的因素中。
除了核心因素之外,还有其他问题需要考虑。为了这个新方程的目的,让我们假设我们正在试图预测真正的人工智能自动驾驶汽车在公认标准的第 5 级的到来。
我还想提一下,我们需要就某个事物的出现意味着什么达成共识。如果你可以制造一辆 5 级的人工智能自动驾驶汽车,你是否已经达到了该项目的“降临”?不,我不这么认为。尽管你可能做得很好,达到了 5 级实例,但在我们有一些人工智能自动驾驶汽车在周围行驶之前,说它们已经出现似乎是有问题的。
有多少是降临?如果有几十辆真正的人工智能自动驾驶汽车在我们的街道上行驶,那将是一个降临,还是我们需要更多,比如数百辆,或者数千辆。真正的人工智能自动驾驶汽车的普及程度是多少?
有各种方法来衡量流行程度。我将使事情简单化,并建议我们用当时在用汽车的百分比来衡量。正如前面提到的,我们将逐渐看到向人工智能自动驾驶汽车的切换,这将看到传统汽车的退役和人工智能自动驾驶汽车的不断增加。
在所有汽车的总人口中,我们可能会同意,一旦某个百分比成为真正的人工智能自动驾驶汽车,我们就达到了普及。假设你愿意接受这个前提,那么我们可以讨论它是 1%,10%,20%,30%,40%,50%,60%,70%,80%,90%,甚至可能是 100%,然后你会把它称为流行率(我使用了十进制的整数,但它当然可以是 1%到 100%之间的任何数字)。
让我们设定 20%为普遍意义
我现在要用 20%。为什么?在各种研究领域,20%经常被用来表示流行程度。这来自于环境和生物学领域的研究。这似乎是一个足够大的百分比,它不是微不足道的,但也没有大到似乎有些不可能达到。
在美国现有的传统汽车数量(如上所述约为 2.5 亿辆)的情况下,人工智能自动驾驶汽车的出现将占 20%,这是一个相当令人生畏的 5000 万辆这样的汽车。这是一个令人望而生畏的数字,因为想想达到这个数字可能需要多长时间。换句话说,即使人工智能自动驾驶汽车明天就准备好了,生产那么多自动驾驶汽车也需要一段时间,这些人工智能自动驾驶汽车也需要一段时间才能购买并投入使用。
我之前预测过,一旦我们实现了真正的人工智能自动驾驶汽车,很可能会有一个相当快的采用率。我这么说是因为那些真正的人工智能自动驾驶汽车将会赚钱。当有钱可赚的时候,需求就会猛增。这不仅仅是汽车车队,正如我所说,将会有一个由个人消费者组成的完整的家庭手工业,他们将购买人工智能自动驾驶汽车,以利用这些车辆作为个人用途和赚钱。
我现在已经为建立一个方程奠定了基础,这个方程可以用来预测人工智能自动驾驶汽车的到来。
这个谜题的最后一部分是关于基督降临的基础。通过使用一个基数,然后你可以用它乘以各种因子,看看得到的 N 是等于、大于还是小于稻草人基数。我将把基地称为 B 星。
请看图 1。

我们正在尝试求解 n。有一个基本的 B 星,然后乘以八个因子。
出于定义目的:
- n 是流行年数(YTP),使用插入式 20%作为 PV(流行)因子
- b 星是基本年数,然后根据每个因素进行调整
关键因素包括:
- 因子 TA: T 技术 A 进步,估计的分数
- 因素到: T 技术Ob 障碍,估计的小数
- 因子 EP:EeconomicPayoff,估计的小数金额
- 因素 ED: E 经济 D 雨,估计的一小部分量
- 因素 SF:So 其他 F 偏好,估计的分数
- 因数 SO:SOCI etalOp position,估计的小数金额
- 因素 RE: R 调节En 平衡,估计的小数金额
- 因子 RR: R 调节 R 限制,估计的小数
该等式由以下内容组成:
- N (PV 为 20%)= B-star x TA x TO x EP x ED x SF x SO x RE x RR
根据我之前的讨论,有四个主要因素涉及技术、经济、社会和监管问题。对于每个因素,都有推-拉因素,这意味着每个因素都可以被解释为促进和推动人工智能自动驾驶汽车问世的一个因素,还有一个伴随因素是拉人工智能自动驾驶汽车问世的拉力。这是四个关键因素,考虑到推拉效应,总共有八个关键因素。
类似于前面关于方程可用性的评论,我将这个方程保持为 9 个元素,这与流行的神奇数字 7 加或减 2 的经验法则相当。这些因素都很容易理解。这个等式很容易理解。
它无意成为终极目标。它旨在提供一种讨论和辩论的基础。如果没有一个支点,关于这个问题的争论和讨论往往是空洞和迂回的。
请看图 2。

如图所示,我填充了一个电子表格来利用这个等式。
首先,我选择展示如果你只考虑单一因素的观点会发生什么。例如,您可能仅使用技术专家的视角,因此这些因素是唯一填充的因素(其余因素被假设为不在等式中,而不是说值为零,这当然会消除计算)。同样,我展示了一个单独的经济视角,然后一个单独的社会视角,一个单独的监管视角。
在电子表格的最后两行,我提供了一个完整的组合。
我还选择展示乐观主义者的观点和悲观主义者的观点,对每个单因素实例和全混合实例都这样做。这与试图得出一个范围的值,而不是一个单独的值是一致的。乐观观点和悲观观点分别提供了估计的下限和估计的上限。
对于基本的 B 星,问题是使用什么数字。因为有许多专家似乎在 15 年左右浮动,所以我在这个说明性的例子中使用了这个数字。我们可以用 5 年、10 年、20 年、25 年或 30 年,所有这些都在媒体上流传。据推测,无论你选择哪一个基数,这些因素最终都会“修正”它,使其趋向于“实际”预测。
我们正在实施德尔菲法,以达到实质性的下限和上限。德尔菲法是一种成熟的预测方法,通常被称为 ETE(估计-谈话-估计)。在这种情况下,一组人工智能自动驾驶汽车领域的专家已经参与了一系列的德尔福轮次。在每一轮中,被选中的专家可以看到其他专家的指示,并在他们认为合适的时候调整他们自己的估计。
虽然德尔菲法通常受到高度重视,但它可能因群体思维的潜力而受到批评,有时也会因过度的共识而被削弱。尽管如此,这很有启发性,也是引发关于这个话题的有益讨论的另一种方式。
结论
什么时候会有 AI 自动驾驶汽车的问世?一些人通过模糊的预感来回答这个问题。通过使用这里提出的等式,希望可以进行更具体和更有条理的讨论和辩论。
你可能不喜欢所用的因子,或者你可能想添加额外的因子,但至少不管怎样,这个等式让树栽下来了。在降临问题上,从这些根将会期待一个广泛复杂的事业。
一些批评人工智能自动驾驶汽车的人说,我们永远不会有真正的人工智能自动驾驶汽车。如果是这样的话,我想 N 的数字要么是零(我们将定义为它永远不会发生),要么可能是无穷大。我想我会更乐观,会断言 N 有一个数,它既不是零,也不是无穷大,更接近于一个小于 100 的值,很可能小于 50。
方程式,我们喜欢它们,但有时我们讨厌它们(比如在考试或测验时记忆它们)。看看我提出的方程,看看你怎么想。插入一些值。仔细考虑将来可能发生的事情。虽然不是水晶球,但它是一种如何思考未来和真正的人工智能自动驾驶汽车出现的剧本。
关于这个故事的免费播客,请访问:http://ai-selfdriving-cars.libsyn.com/website
这些播客也可以在 Spotify、iTunes、iHeartRadio 等网站上下载。
更多关于人工智能自动驾驶汽车的信息,请参见:www . AI-self-driving-cars . guru
版权所有 2019 兰斯·艾略特博士
通过数据驱动的体育博彩策略“赚大钱”
深度剖析
或者如何在自己的号码上击败庄家

几个月前,我开发了一个 ML-free 算法,用一个简单的泊松过程来预测英超联赛的结果。该程序的跟踪记录比我想象的更令人印象深刻,在第一轮比赛中正确预测了 7/10 场比赛的结果(其中 3 场比赛有确切的比分)。

所以我完成了这个项目,把它放在一边,专注于我的功课。
我上周末看了阿森纳和曼联的比赛,在这场比赛中,主队被普遍认为是失败者。

Image by author. Screenshot from Google.
出乎所有人的意料,阿森纳队名列榜首。任何一种情况都有可能发生。联队在上半场两次击中门柱。但是,在这个混乱的赛季中,大卫·德基对查卡突然转身射门的罕见误判和慷慨的点球又增加了一个不可预测的结果。
我有没有提到托特纳姆热刺队在同一个周末被南安普顿队击败了?
随着英超联赛另一轮令人惊讶的结果的展开,我一直在思考我开发的算法。它能在一致的基础上正确预测结果吗?在这个模型中有一些内在的随机性,但这足以成为 PL 诱人的泰然自若的因素吗?在那里,降级区南安普顿队击败了全明星热刺队。
所以我决定把它带回来重新测试。
1。对抗专家的算法
测试一个算法的困难之一是找到一个好的性能基准。比方说,如果我的预测在 200 次匹配中有 50%的准确率,那么它是好的、坏的还是平庸的?这肯定比随机猜测要好(赢、平、输的概率都是 1/3),但听起来没那么好,不是吗?
把我的结果和职业足球专家比较怎么样?
所以我发现,每周,天空体育网站都会发布一个由保罗·默森【1】对那周比赛的预测,他是一位前阿森纳球员,后成为赢得过几个冠军的权威人士。
老实说,我不是保罗·默森的忠实粉丝,因为我认为他对他的前俱乐部进行了无情的批评。
听听阿森纳前主教练温格对他的评价:
我听到的这些辩论是一个笑话,一场闹剧。管理零场比赛的人,他们教每个人你应该如何表现。简直是闹剧。
尽管如此,这对我来说是一个金矿,因为我现在可以将我的算法与“专家”进行比较。不管你对他有什么看法,一个前阿森纳球员对阿森纳对曼联比赛的预测肯定会比一个随机产生数字的模糊模型更可靠。

The confusion matrix that shows how accurate Merson’s and my algorithm’s predictions are, over 273 matches. Left: Merson’s correctly predicts 150 matches or 54.9%. Right: The Poisson process algorithm got 51+7+117 = 175 matches, a whopping 64.1%
在这里,我比较了默森预测的本赛季 273 场比赛的结果。他达到了 54.9%的准确率(T1),而我的泊松过程算法达到了令人惊讶的 64.1%的准确率(T3)。
有趣的是,默森预测了阿森纳和曼联之间的 2-2 平局,他说“两队将会相互较量,并且会有进球。“我的算法,通过平均阿森纳主场的进球数和失球数,给阿森纳分配了 45%的微弱优势和获胜概率,相比之下,曼联为 27%。
2。从预测到体育博彩
结果让我大吃一惊。超过专家意见 10%的优势是巨大的。除了让心爱的泊松过程剔除数字之外,我甚至不用做太多事情。
这是我开始研究体育博彩的时候。而我进入新游戏对阵新对手: 是我对阵庄家 。
3.理解书签:赔率是如何工作的?
如果你曾经认为你信用卡上的条款和报价很复杂,试着去那些博彩网站试试。他们简直是疯了。
以美国的赔率为例。如果你看到一个+300 的赔率,这意味着如果你赌 100 并且赢了,你的收益是 300 美元。这很好,但是他们有负赔率,比如 150 的赔率。搞什么@#!$%那是?*这意味着为了赚取 100 美元的利润,你需要下 150 美元的赌注。因此,美国赔率是一个大于或等于 100 的数字,有时前面加一个+,表示这个数字是你的利润,有时前面加一个——表示你赢得 100 美元需要下注的金额。
我的意思是,他们仍然使用英尺和华氏温度

为了这个项目的目的,我们将使用一个更好的系统:欧洲赔率。很简单:他们告诉我,如果我赌 1 美元,我会赢回多少钱。例如, Bet365 给出阿森纳击败曼联的赔率为 2.4,平局为 3.6,马努获胜为 3。这意味着,如果我为阿森纳下了 1 美元的赌注,我的口袋里会有 2.4 美元(1.4 美元的利润)。
4。肮脏的小秘密
但是事情并不总是美好而简单的。实际上,为了实现利润最大化,博彩公司雇佣数据科学家团队来分析几十年的体育数据,并开发高度准确的模型来预测体育赛事的结果,并给出对他们有利的赔率。
让我们假设博彩公司的赔率是各个球队赢、平或输的概率的完美反映。因此,对于阿森纳和曼联的比赛,由于阿森纳获胜的赔率是 2.4,所以他们获胜的概率是 1/2.4 = 41.6%,出乎意料地接近我预测的 45%。同样,曼联获胜的概率是 1/3.0 = 33.3%,平局的概率是 1/3.6 = 27.8%。
等一下!!!
41.6% + 33.3% + 27.8% = 102.7%! 真是奇怪(没有双关语!!!)
概率加起来不是 100%的原因是几率不公平。那多出来的 2.7%就是庄家的优势。为了得到真实的概率,我们需要通过除以 102.7 来修正利润。所以博彩公司认为阿森纳获胜的真实概率是 41.6/102.7 = 40.5%,曼联获胜的概率是 33.3/102.7 = 32.5%,平局的概率是 27.8/102.7 = 27.06%。对于一个完全有效的博彩公司来说,这些是每种结果的概率。
现在,这是一件有趣的事情:如果赔率完美地反映了现实,那么我赌哪个结果并不重要——我的预期利润总是一样的。
如果我在阿森纳身上赌 1 美元,我希望能赢回来:

如果我为曼联下注,预期利润是一样的:

而且——你猜对了——如果我赌平局,我希望能赢回 97 美分。平均来说,每下 1 美元赌注,庄家会从我这里拿走大约 3 美分。
4.下注策略:
这种理解并没有阻止我试图利用市场中任何潜在的低效率。首先,我设计了一般的下注策略。
- 我列出了 1000 美元的预算,平均分配给前 30 轮英超联赛。所以每个周末我都有大约 33 美元可以下注。
- 对于每场比赛,将通过以下三种方法之一进行预测:(a)保罗·默森预测,(b)我的泊松过程算法,以及(c)等概率随机分配赢、平、输。
- 通过预测,我找到了 6 家在线投注站中赔率最高的。这意味着如果我赢了,我会得到最高的利润。这将是我下注的赔率。
- 对于每场比赛,赌注的金额将由凯利标准计算,该标准的工作原理是:你应该只投资你财富的一部分。通过保留一些,你不会以破产告终。最佳分数( f )取决于每个单独的赌注:

where p* is the probability that the event occurs and x is an odds
在 R 中实现凯利标准非常简单:
在凯利标准的公式中,问题仍然是什么被认为是事件的真实概率( p* )。正如我们在前面的部分中所看到的,我们可以对任何特定的博彩公司给出的赔率取倒数,但这不会以很大的优势结束,因为他们倾向于对该公司有利。然而,如果我们汇总来自许多不同博彩公司的所有赔率,我们应该能更好地反映博彩公司如何看待某个事件的概率,例如阿森纳击败曼联:

where n is the number of betting houses and xi is a given odds by the house i

The result of this betting strategy using the Poisson-process prediction for the last Matchweek, Round 30. This table shows how the max_odd, probabilities of prediction events, Kelly bet fraction, bet_amount are calculated
对于第 30 轮比赛,正确预测了 5 场比赛,从 6 家赌场中选择了最佳赔率,由于我们的下注策略中嵌入了泊松预测,这一轮我们总共净亏损 0.9 美元或 90 美分。我们最大的损失来自于切尔西主场对狼队没能抢下 3 分。
5。下面是最终结果
现在,假设我从英超联赛一开始就使用这个策略,让我们看看我们是如何迅速致富的。
我的算法和默森的预测——当结合凯利标准的最大奇数策略时,到第 30 个比赛周结束时,净正回报,泊松过程预测实现了惊人的 9.1% 回报,每个比赛周的归一化回报为 0.3% 。客观来看,先锋 S & P 500 ETF 的市场价格回报率为4.6%【4】。
随机法第一次迭代净亏 19% 主要是因为这里那里的几个幸运投注(曼联输给西汉姆)无法弥补大量的烂注(莱斯特,哈德斯菲尔德赢了伊蒂哈德,热刺输给伯恩茅斯,像老实说?).即使我多次重新运行随机预测,也足以说我见过随机方法有正回报的情况不到 10%。

显然,这种最优泊松模型存在固有风险。以第 24 轮比赛为例,我们净亏损 14 美元。默森和泊松过程模型(还有我!!!)对利物浦、曼城、曼联、切尔西分别拿下莱斯特、纽卡斯尔、伯恩利、伯恩茅斯 3 分非常有信心,提出总赌注 $19。结果:利物浦和曼联未能全取 3 分,而切尔西和曼城则被击败。都在同一个周末!!!
最后的话:
在你克隆我的 Github 回购协议并为你的体育对冲基金筹集资金之前,我应该明确表示,没有任何担保。你需要一大笔启动资金(我用 1000 美元模拟,但每周我只有 33 美元可以下注),大量的耐心和冷静的头脑。
如果有的话,这篇文章是一个玩具的例子,你可以做什么。但是博彩公司使得任何人都很难获得可持续的利润。如果博彩公司认为赢的概率是 1/6,那么他会通过将赔率设置为小于 5,也许是 4.6 这样的值来保证他的预期收入减去支出是正的。如果仍然有很多人以 4.6 的赔率下注,那么庄家肯定意识到赢的概率肯定高于他自己的估计,并将赔率调整为 4。很有可能当代码推断出最佳几率时,它已经被修改了。
此外,如果你开始定期盈利,博彩公司可以简单地感谢你的业务,支付你的奖金并取消你的账户。这就是发生在东京大学一个研究小组身上的事情。
在我们开始用真钱下注的几个月后,庄家开始严格限制我们的账户。我们的一些赌注被限制在我们可以下注的赌注金额内,庄家有时要求在接受之前对我们的赌注进行“人工检查”
- *** 重要免责声明:**本文纯粹用作教育材料,*不得视为法律或财务建议。也不建议打赌或赌博。请注意,体育博彩在美国的几个州是不合法的。
如果你喜欢这篇文章,你可能也会喜欢我的另一篇关于有趣的统计事实和经验法则的文章
- 迪士尼电影是对的——我们都是特殊的,从统计数据上看也是如此
- 优化生活的统计法则:呼唤效应
- 规则三:计算尚未发生事件的概率
对于其他深潜分析:
这个项目的完整代码可以在我的 Github 简介中找到
[1]https://www . sky sports . com/football/news/15205/11657461/保罗-莫森斯-预测-阿森纳-曼联-切尔西-狼队-还有更多
[2] 凯利,J. L. (1956)。《信息率新解》 (PDF)。 贝尔系统技术期刊 。35(4):917–926。doi:10.1002/j . 1538–7305.1956 . TB 03809 . x
[3] 考尼茨,l .等人(2017)。“用他们自己的数字击败博彩公司——以及在线体育博彩市场是如何被操纵的”(PDF)。阿尔维克斯
[4]https://advisors . vanguard . com/web/C1/Fas-investment products/VOO/performance
教计算机理解推文的情感
因为我们真的不想读唐纳德·特朗普写的所有东西

Donald Trump is well-known for many things, like his extensive use of Twitter and changing opinions faster than he breathes. What if we could get computers to read his tweets and understand his and his followers opinions towards a given topic? Photo credit: NICHOLAS KAMM/AFP/Getty Images
理解一条推文是正面的还是负面的是人类很少会遇到的问题。然而,对于计算机来说,这是一个完全不同的故事——复杂的句子结构、讽刺、比喻性的语言等等。让计算机很难判断一句话的意思和情绪。然而,自动评估一条推文的情绪将允许人们对各种问题进行大规模的意见挖掘,并有助于理解为什么某些群体持有某些观点。
在更基本的层面上,理解文本的情感是自然语言理解的关键部分,因此,如果我们希望计算机能够与我们有效地交流,这是一项必须解决的任务。
在这篇博文中,我将展示一个小型研究项目的成果,该项目是谢菲尔德大学 SoBigData 项目的一部分。我们测试了处理文本的不同方法,并分析了它们能够提取多少情感。请继续阅读,全面了解该项目及其成果!
介绍
该项目的目的是测试计算机使用机器学习能够在多大程度上理解文本的情感。为了做到这一点,我们给电脑输入了大量的推文,每条推文都被人类标记为积极、中立或消极的情绪。每条推文也有一个相关的主题,这一点很重要,因为根据讨论的主题,一个句子可以有非常不同的情感。例如,如果我们谈论质量,“高”这个词是肯定的,但如果我们谈论价格,这个词就是否定的。“绿色”在讨论环境问题时是积极的,但在讨论艺术时可能是中性的。现在,计算机的任务是预测给定推文和相关主题的情绪。
计算机如何阅读文本?
如果你没有机器学习的经验,这可能看起来是一个奇怪的问题。但机器学习是基于统计的,所以机器学习系统要处理的任何东西都必须用数字来表示。将文本转换成数字发生在所谓的 嵌入模型 中,开发这些本身就是一个主要的研究领域。嵌入模型将一个单词或一个句子变成一个向量,这个向量在训练过程中不断调整,使得具有相似含义的单词和句子以相似的向量结束。理想情况下,向量应该捕捉含义、上下文、情感等。但是这并不是一件容易的事情,这也是为什么许多不同的嵌入模型被开发出来的原因。一般来说,新型号性能更好,但它们也可能针对特定任务进行调整。
成熟的机器学习系统能够在情感分析方面达到最先进的水平,这是一种野兽。它们由多个组件组成,文本嵌入只是其中之一,而且通常很难评估系统的哪些部分是性能瓶颈。由于任何文本都需要表示为一个向量,以便机器学习系统能够处理它,所以任何分析,包括预测推文的情绪,都严重依赖于所选择的嵌入模型。但这并不是说系统的其他部分可能同样重要。
为了使文本嵌入的作用和贡献更加透明,我们开始用一个设计为最小模糊的系统来测试它们预测情感的性能。
我们如何预测情绪?
我们预测情感的方法非常简单,并且受到了协同过滤的启发。每条推文都有一个相关的主题,根据主题评估情绪是非常重要的(因为一个陈述很容易对一个方面持肯定态度,而对另一个方面持否定态度)。因为 tweet 和相应的主题都由相同维度的向量表示,所以我们可以取两者的内积,给我们一个表示情感的数字。没有理由认为这应该与“原始”嵌入一起工作,所以在取内积之前,我们学习并应用一个变换(稍后将详细描述)到主题向量空间。这样,即使之前没有看过题目,也能得到感悟。
我们希望能够预测三种不同的情绪(积极、中立、消极),所以我们实际上学习了话题空间的三种不同变换:一种预测积极情绪,一种预测中立情绪,一种预测消极情绪。当将推文与三个转换后的主题向量中的每一个进行内积时,我们会得到三个数字,可以理解为模型对每一种情绪的押注——数字越高,模型越相信这就是推文的情绪。
项目摘要
我们想测试不同的单词嵌入为一条推文的情感带来了多少信息。为了预测情绪,我们训练了一个模型,该模型学习主题向量的三种转换,使得推文和三个主题向量中的每一个的内积将是模型对三个情绪中的每一个的投票。
我们有几个不同的选择。首先,我们必须选择要测试的嵌入模型。其次,我们需要决定如何转换主题向量。第三,我们需要一个已经被人类贴上情感标签的推特数据集,这样我们就有东西来训练和测试这个模型。
决定设置
数据集
我们使用了为 SemEval-2017 任务 4 提供的英语数据集。这由大约 26k 条不同主题的推文组成,所有推文都被人工标注了情绪。我们保持任务组织者定义的划分,大约 20k tweets 用于训练,6k tweets 用于测试。
嵌入模型
我们选择测试以下四种嵌入模型:
- 【2003 年的神经网络语言模型 (NNLM),这是用神经网络学习单词嵌入的最早尝试之一。该模型构建了 128 维的单词向量,并将作为一种单词嵌入基线,这是更高级的模型应该明显胜过的。
- 如上所述的神经网络语言模型,但现在使用了标准化的单词向量,这有时会产生更好的结果。
- 来自 2018 年初的语言模型 (ELMo)的嵌入,已被证明在许多不同的任务中实现了最先进的结果。构建 1024 维单词向量。
- 通用句子编码器(使用)来自 2018 年初,一个经过训练的模型,可以在许多任务中找到有用的单词嵌入。构建 512 维单词向量。
所有四种嵌入模型都可从 TensorFlow Hub 方便地获得。
转换模型
选择转换主题向量空间的模型是很棘手的。一方面,我们希望尽可能保持原始向量空间不变。另一方面,我们希望转换足够灵活,使得单词嵌入中的信息实际上可以用于预测情感。因此,我们决定测试两种不同的转换模型:
- 一个简单的仿射变换。这种转换只能表示最基本的转换,如缩放、旋转、剪切和平移,因此,在某种意义上,这将测试“原始”嵌入捕获了多少信息。
- 由神经网络表示的更复杂的转换。我们使用具有两个隐藏层的神经网络,每个隐藏层具有 8 倍的嵌入维数、ReLU 激活函数和丢失。网络将主题向量作为输入,并输出转换后的主题向量。这种变换可以以高度非线性的方式扭曲主题空间,因此应该能够获得更高的精度。然而,它将更难训练,并且可能更容易过度适应训练集。
最终的模型将学习上述每种类型的三种转换,对应于我们想要预测的三种情绪。
纠正数据集中的不平衡
处理真实数据总是具有挑战性。特别是,如果单个情绪或主题被过度表达,模型可能会在训练过程中完全专注于此,这将使其他情绪或使用其他主题的预测远离。相反,我们希望确保该模型对所有主题和观点给予同等的权重,无论它们出现的频率如何。做出这些修正的效果是相当戏剧化的,也是值得记住的一课,所以让我们花几分钟来讨论这个问题。
数据集中的不平衡
绘制每个情绪的推文数量,数据集显示了巨大的阶级不平衡。

Distribution of sentiment classes for both the training and the test set.
特别是积极的情绪在训练数据中表现得非常突出——事实上,几乎 73%的训练推特都有积极的情绪。这意味着该模型将从学习预测积极情绪中比其他任何模型受益更多。另一方面,中性情绪与不到 10%的推文相关,如果有助于预测积极情绪,模型可能会简单地学会忽略这种情绪。
测试集中的分布明显不同。负面情绪比正面情绪更丰富,没有一条推文有中性情绪。这使得让模型平等地对待所有情绪变得更加重要。
事实上,对 NNLM 的仿射变换模型的测试表明,由于积极情绪在训练数据中普遍存在,训练的模型明显倾向于积极情绪。在这个测试中,训练数据中的主题被分成分别包含 90%和 10%主题的训练集和评估集。

A confusion matrix showing the actual sentiment of the tweets versus what the model predicted. The percentages show how often a specific, actual sentiment was predicted to be any of the three sentiments by the model. A perfect model would have 100% along the diagonal, meaning that the predictions are always correct. Here, however, it is seen that the model often chooses to predict positive sentiment, regardless of what the actual sentiment is.
该图示出了情绪预测的混淆矩阵,其中每一列对应于一个预测的情绪。每一行都显示了实际的情绪,对于每一行,每个矩阵元素的数量和颜色显示了具有这种实际情绪的推文的百分比,这些推文被预测为具有列中显示的情绪。
理想情况下,对角线应该接近 100%,这意味着预测的情绪对于几乎所有的推文都是正确的,但即使对于训练集来说,也有大量的非对角线元素。这意味着,即使模型知道正确的情绪,它也更倾向于默认预测积极的情绪。43%的负面情绪推文和超过 55%的中性情绪推文被预测为正面情绪。这对于分别为 39%和 78%的评估集来说更糟糕。
然而,在训练集和测试集中,每个主题的 tweets 数量也有很大差异。

Number of tweets associated with each topic for both the training and the test set. The topics have been sorted from left to right based on the amount of associated tweets and the their names have been omitted for clarity.
特别是对于训练集,我们看到每个主题的推文数量有明显的差异-一些主题有超过 100 条推文,而大约一半的主题只有大约 20 条或更少。
回到仿射模型的测试,查看给定主题的推文的情绪预测的平均准确性,显示推文越多的主题通常准确性越高。

The average accuracy of sentiment prediction for tweets in a given topic. There is a clear tendency in that topics with more associated tweets generally achieve a higher average accuracy.
这种趋势是有道理的:模型更多地受益于学习一种转换,这种转换对于有更多 tweets 的主题很有效。但这实际上并不是我们想要的,因为这意味着模型可能无法很好地概括。我们希望模型即使在看不见的主题上也能表现良好,在这方面过度适应几个主题可能没有帮助。
处理此类类别不平衡的一种方法是通过类别频率的倒数来衡量模型因错误预测而受到的惩罚。这意味着,对于频率较低的数据,模型会收到较大的误差,因此会更加关注这些数据。让我们看看这对模型的训练有什么影响。
纠正情绪失衡
仅用情感频率的倒数来重新训练模型和惩罚错误,我们已经获得了一个好得多的模型。

Confusion matrices for the affine model on NNML, correcting for sentiment imbalances in the training set.
对于训练集,所有情感的对角线接近 100%。评估集上的预测也有所改进,尽管还有很大的改进空间。
我们还看到训练集的每个主题的准确性有所提高,尽管这不是明确鼓励的。

Average topic accuracy for the affine model on NNML, correcting for sentiment imbalances in the training set.
有趣的是,评估集上的性能似乎有所下降。一种解释可能是,评估集中的大多数推文都有积极的情绪,因此该模型现在牺牲了一些准确性,以更好地表现消极和中性的情绪。
纠正主题不平衡
接下来,让我们看看当只使用话题频率的倒数来惩罚错误时会发生什么。这也导致了对训练集更好的情绪预测,这可能是因为不管与主题相关的推文数量如何,对主题进行同等加权会使模型暴露于更多种多样的情绪。

Confusion matrices for the affine model on NNML, correcting for topic imbalances in the training set.
但是真正的效果是在查看每个主题的准确性时看到的。对于训练集来说,准确率现在基本上与一个主题中的推文数量无关,大多数主题都接近 1。

Average topic accuracy for the affine model on NNML, correcting for topic imbalances in the training set.
修正情绪和主题的不平衡
最终的模型将基于情绪和主题的频率来衡量错误预测的惩罚。这是通过简单地将主题频率和情感频率的倒数相乘,并使用结果数量作为权重来完成的。这应该鼓励模型在训练期间平等地对待所有情绪和所有主题。
由此产生的模型确实看起来是情感和主题不平衡之间的一个很好的权衡。情绪预测相当准确,在评估集上的性能没有受到影响。

Confusion matrices for the affine model on NNML, correcting for both imbalances in the training set.
每个主题的平均准确率再次独立于与该主题相关的 tweets 的数量。

Average topic accuracy for the affine model on NNML, correcting for both imbalances in the training set.
虽然校正类不平衡对训练集明显有帮助,但在评估集上的性能仍然没有明显变化。该模型似乎不能很好地推广到新的主题,这可能意味着仿射变换限制性太强,或者训练集不能很好地代表评估集。当我们看最后的实验时,我们将回到这一点。
把所有的放在一起
现在,已经考虑了数据集中的类别不平衡,并且已经决定了嵌入和转换模型,我们准备测试模型,并且查看单词嵌入已经能够拾取多少情感信息。
设置遵循标准的机器学习方法:我们使用 10 折交叉验证 (CV)训练模型,并在测试集上评估每个折的最佳模型。这为我们提供了一种方法,当在(稍微)不同的数据集上训练时,我们可以预期模型的性能会有多大的变化。
包含一些基线实验总是一个好主意。这些应该是你能想象到的最简单的方法,如果你的高级模型不能战胜它们,你就知道有问题了。我们选择了两个简单的基线:1)使用来自训练集的最频繁的情感(这将是“积极的”)作为任何推文的预测,以及 2)使用来自训练集的随机情感作为预测。
下图显示了对所有八个模型和两个基线进行训练以及对未知测试集进行评估的结果。穿过数据点的垂直线表示穿过 10 个 CV 倍的一个标准偏差。

这里有许多有趣的观察要做。首先,任何嵌入模型都比基线有很大的改进。因此,正如预期的那样,单词嵌入捕捉到了可用于推导推文情感的信息。其次,转向 NNLM 嵌入,与仿射模型相比,当使用非线性模型时,似乎没有任何改进。这是有趣的,因为它表明嵌入空间足够简单,以至于仿射模型能够使用嵌入中可用的所有情感信息。这与较新的嵌入(ELMo 和 USE)形成对比,在 ELMo 和 USE 中,当使用非线性模型时,我们确实观察到改进,这表明这些模型学习的嵌入空间更复杂。对于 NNLM 来说,标准化的向量确实有比非标准化的向量表现更好的趋势,但在我们的实验中,这种影响并不显著。最后,虽然 ELMo 和 USE 都包含比 NNLM 嵌入更多的信息,但它们在这些实验中的表现非常相似。USE 包含的信息似乎比 ELMo 稍多,但并不多。然而,这仍然是有趣的,因为使用嵌入空间的维数比 ELMo 空间低得多,因此,模型的训练要快得多。
我们到了吗?
不,绝对不行。关于单词嵌入的信息内容,有许多有趣的问题需要回答。
例如,我们用三分制(消极、中立、积极)来处理情绪。扩展到更细粒度的情感,比如五分制,将需要更多的嵌入。嵌入包含这么多信息吗?
询问巨大的嵌入空间是否必要也是合理的。ELMo 嵌入是 1024 维的,但是信息可能嵌入在更低维的空间中。嵌入空间的维数减少如何影响情感的预测?
当测试主题空间的两种不同转换时,我们发现只有较新的嵌入需要非线性转换。扩展转换的类型,包括创建一些更复杂的神经网络,以及测试哪些嵌入受益于哪些转换,这将是很有趣的。这可能会让我们深入了解不同嵌入空间的复杂性。
外卖
在这个项目中,我们想测试不同的单词嵌入携带了多少关于推文情感的信息。我们通过构建两个模型来预测尽可能无干扰的情感,使我们能够看到原始单词嵌入包含多少情感信息。
结果显示,新旧单词嵌入确实携带了情感信息,并且新的嵌入比旧的嵌入包含更多信息,这并不奇怪。结果还表明,对于较新的嵌入,主题向量的非线性变换比仿射变换表现得好得多,这表明这些空间比较旧的嵌入更复杂。
总之,单词嵌入通常包含很多关于推文情感的信息,新的嵌入包含更多的信息。虽然并不令人意外,但它强调了高级嵌入模型对预测推文情绪的重要性。
承认
该项目是谢菲尔德大学计算机科学系 SoBigData 2017 短期科学任务(STSM) 的一部分,与 Diana Maynard 博士合作完成。非常感谢 Isabelle Augenstein 博士在整个项目过程中提供的大量讨论和建议。
让数据科学面试变得更好

Photo by Kaleidico on Unsplash
关于如何改进数据科学面试流程的一些未经请求的建议
我从求职者的角度思考并写了不少关于招聘过程的文章。但最近,在观察了我的朋友们(和其他新兵训练营的毕业生)一次又一次的面试后,我对公司如何更好地面试有了一些建设性的反馈。
面试官没有提前解决的商业案例问题
商业案例面试的实际目标是什么?这是为了测试应聘者在面对开放式问题时批判性思维和创造性思维的能力。
但是作为面试官,你如何评估这些事情呢?批判性思考部分没有那么难——如果这个人在基本的商业战略问题上磕磕绊绊,或者提出没有意义的建议(根据上下文),那么很可能是不行的。
创造性思维和为问题制定新颖解决方案的能力更难评估。我认为面试官(和一般公司)目前在这个方面做得不好——尽管事实上案例面试的主要目的是衡量这种能力。
在我看来,问题在于面试官在进行面试时更喜欢使用已知的、已解决的商业案例(通常是他们自己曾经做过的)。原因很明显:
- 由于已经做过,对面试官来说相对来说并不费力——他或她已经知道答案以及如何处理这个案例。
- 不存在不确定性(也没有看起来愚蠢的风险)。一般来说,包括面试官在内的人都会回避不确定性和风险。
但这些好处也是为什么案例面试没有公司普遍认为的那么有效的原因。
什么时候人们最容易接受新的和新奇的建议?答案是——当他们自己不确定答案是什么的时候。如果他们心中已经有了一个答案,特别是如果这个答案是他们自己想出来的,那么这些人就会被固定下来,可能会有偏见。在这些情况下,如果候选人提出了一个与你不同的解决方案,你可能会花时间解释为什么你的方法更好,为什么他们的方法是错的,而你实际上应该客观地评估候选人的答案。
如果面试官事先不知道答案,面试就变成了一个来回的头脑风暴会议——更准确地模拟了两个人一起工作的情形。与现在相反,案例面试往往会变成面试官坐在那里等着听到某个特定的关键词或概念,而候选人拼命地唠叨,试图检查所有的方框。
所以,公司和面试官们,我恳求你们试试我的建议。如果你带着一个未解决的问题去面试,并且向解决方案迈近了 5%,这难道不是一个强有力的证据,证明雇佣这个候选人会带来互惠互利的工作关系吗?
关注候选人提出正确问题的能力
我个人认为,如果你能提出正确的问题,那么你就成功了 80%。如果你知道如何对数据提出正确的问题并设计正确的实验(来回答这些问题),我会比你记住 OLS 的推导印象更深刻。
是的,花式数学隐含着一定程度的知识和教育。将您的想法合理快速地映射到 Python 代码的能力也很重要。但是我们生活在一个谷歌、维基百科、YouTube 教程和堆栈溢出的世界里。
想想你如何解决工作中的实际问题:
- 首先,你将复杂的开放式问题转化为一系列不太开放的问题,这些问题可以通过你已经拥有或能够收集的数据来解决。
- 然后你收集数据并进行实验。
- 在这样做的时候,如果有你不确定如何写的代码或者一个你不熟悉的算法,你就失去了你的搜索技巧,很可能以栈溢出而告终。
因此,在你的头脑中已经有一个端到端的解决方案几乎是不可能的。因此,你不应该期望你的候选人也有。更确切地说,是评估他们提出正确问题的能力,以及他们足智多谋和快速学习的能力— 因为这些是候选人为你的组织增加价值的能力的更好的长期指标。
感谢阅读,干杯!
我最近的一些帖子,希望你能看看:
利用 OpenVINO toolkit,让深度学习模型为最坏的情况做好准备,并为跨平台做好准备。

Photo by Fatos Bytyqi on Unsplash
随着 2020 年的到来,深度学习专家和爱好者社区期待着该领域创新的重要一年。随着世界各地每天都在构建越来越多的深度学习模型,人类对云和网络(尤其是 TCP)的依赖日益扩大。你可能会想,云依赖有什么问题吗?
最坏的情况:
估计你家里有一个面部检测锁,但建造不当,因为开发人员将模型安装在云上,设备必须使用云服务进行推理。现在,突然有一天,当你面对一个非常糟糕的网络连接,并且没有配置任何安全覆盖方法时,你将成为你的安全系统的受害者。
这种情况的另一个真实例子是位于印度奥里萨邦 Bhuvneshwar 的一家著名多专业医院的故事。他们训练有素地拥有一个深度学习网络,经过适当的训练和领域专业知识的调整,但它的实现方式是,它必须通过 TCP 将患者每秒的心率作为流发送到 web 服务器,以确定心肌梗死。在一场毁灭性的飓风袭击了沿海的奥里萨邦后,这个系统就没用了,因为根本没有手机连接。
如果不采取适当的步骤来部署在任何时刻做出关键决策所需的深度学习模型,该模型可能会面临最糟糕的考验。随着深度学习模型在关键决策操作中的快速发展,如果不考虑边缘情况进行配置,它可能会面临相同的抖振情况。如果安全监控或医疗保健系统突然失灵,可能会发生巨大的问题。
为了使这些模型免受这些问题的影响,我们需要以这样一种方式实现这些模型,即这些模型可以执行实时决策,而不需要连接到任何其他云服务或互联网。事实证明,这种方法更加安全,因为部署的模型在互联网范围之外,因此需要最高安全级别的工作负载可以直接在设备中实施。爱好者称这些 AI 模型为 Edge AI。在这个方案中,模型被直接放置在设备中,并且它们不需要网络连接来进行推理。我们现在将了解这是如何实现的。
中间代表:
我们使用 Tensorflow、Caffe、Pytorch、ONNX 等不同框架构建和训练的模型。可能非常大、资源匮乏,也可能依赖于架构,例如受限于特定平台或 CPU/GPU 内核。为了使这些模型能够成功地从任何设备或任何地方提供推理,我们需要将模型转换为中间表示格式,这包括模型在。xml 格式以及。bin 格式。
使用 OpenVINO toolkit 获取不同的模型并将其转换为 IR 格式:
OpenVino Toolkit ( 开放视觉推理和神经网络优化工具包 ) 是OpenCV 团队最初开发的一个开源深度学习工具包,包括不同的工具,使用模型优化器工具将不同的深度学习模型转换成 IR 格式。在转换由不同框架组成的模型的过程中,模型优化器工具只是作为一个翻译器,它实际上只是翻译经常使用的深度学习操作,如我们看到的 Tensorflow、Conv2D、Conv3D、Dropout、Dense、BatchNormalization 等。对于 Caffe,我们使用卷积、dropout_layer 等。并使用来自训练模型的相关权重和偏差来调整它们。英特尔发布的 OpenVINO toolkit 在以下网站上提供了大量不同的预训练模型,您可以将其部署到不同的设备上。这些预先训练好的模型可以通过模型下载器工具直接下载。使用模型下载器工具下载的预训练模型已经以具有不同精度级别的中间表示格式出现。这些精度水平实际上是模型的保存的权重和偏差的精度水平。不同的精度级别包括 FP32(32 位浮点)、FP16(16 位浮点)、INT16(16 位整数)、INT8(8 位整数,仅适用于预训练模型)等等。这些精度级别实际上很重要,因为它们易于部署到不同的平台上。精度越低,结果越不准确,但模型运行所需的资源少得多,因此可以完全部署到边缘设备中,而不会严重影响设备和模型的性能。让我们看看如何使用模型下载器从英特尔 OpenVINO toolkit 网站下载预先训练好的模型,以及如何使用它们对给定输入进行推断。
以下是预训练模型的链接,包含在输入模型之前对输入进行预处理的文档。
** [## 车辆-属性-识别-障碍-0039-open vino 工具包
该模型提出了一种用于交通分析场景的车辆属性分类算法。颜色平均…
docs.openvinotoolkit.org](https://docs.openvinotoolkit.org/latest/_models_intel_vehicle_attributes_recognition_barrier_0039_description_vehicle_attributes_recognition_barrier_0039.html)
假设在您的本地机器上安装并正确配置了 OpenVINO toolkit,那么让我们直接进入下载上述模型的过程。转到您的 OpenVINO 安装目录,使用管理员权限打开终端或命令提示符。现在,要下载上述模型,发出以下命令:
python C:/<OPENVINO_INSTALLATION_DIRECTORY>/openvino/deployment_tools/tools/model_downloader/downloader.py --name vehicle-attributes-recognition-barrier-0039 --progress_format=json --precisions FP16,INT8 -o \Users\<USER_ID>\Desktop
上述命令使用 downloader.py python 程序来解析命令行参数:
- — name:用于提供模型名称(如果用“— all”代替— name,将下载所有可用的预训练模型)。
- —精度:用于提供不同的精度级别(如果没有提供,将下载模型的所有可用精度级别)
- — progress_format=json:将进度报告的格式设置为 json 格式,程序可以对其进行分析。

Downloading pre-trained models from OpenVINO toolkit already in Intermediate Representation format.
中检查上述模型的中间表示。它是模型的架构模式。bin 文件包含权重和偏差。在。xml 文件,你可以在 XML 标签之间看到深度学习模型的不同层和属性可以在上面的格式中感知。
<layers>
............
<layer > .......... </layer>
<layer> ...........</layer></layers>

.xml file of the pre-trained model
使用中间表示进行推理:
使用 IR 模型格式进行推理非常简单。对于上面的这个模型,我们需要根据输入尺寸对图像进行预处理,并恢复颜色通道。对于推理网络,我们需要使用。load_model()函数与模型。xml 文件
from inference import Network
inference_network = Network()
inference_network.load_model("/<MODEL_DOWNLOAD_FOLDER>/vehicle-attributes-recognition-barrier-0039.xml","CPU", "/<OPENVINO_INSTALL_DIRECTORY>/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_sse4.so")
inference_network.sync_inference(preprocessed_image)
output = inference_network.extract_output()
现在需要处理推理网络的输出,并且需要使用 argmax 函数选择最大值。因此,我们需要以下面的方式处理输出,以确定汽车的类型及其颜色,并将文本叠加到输入图像上,作为推断的结果。
def handle_car(output, input_shape):
color = output["color"]
color_class = np.argmax(color)
car_type = output["type"]
type_class = np.argmax(car_type)
return color_class, type_class


Input Image in the left. After the inference, the output is printed on top of the image.
将张量流模型转换为中间表示;
为了将 Tensorflow 模型转换为 IR 格式,我们需要获取保存在中的 Tensorflow 中训练的模型。pb 格式。剩下的非常非常简单,很容易实现。为了使用 OpenVINO 模型优化器将模型转换为 IR 格式,需要冻结张量流图。冻结 Tensorflow 模型意味着删除模型的预处理和训练相关元数据,以减小模型的大小,从而更容易部署。Tensorflow 提供了冻结和解冻深度学习图的内置功能。*.ckpt 文件包含冻结张量流模型的元图。
from tensorflow.python.tools import freeze_graph
freeze_graph.freeze_graph('Model.pbtxt', "", False, './Model.ckpt', "output/softmax", "save/restore_all", "save/Const:0", 'Model.pb', True, "")
由于模型现在被冻结,所以它现在可以被直接转换成中间表示。以管理员权限进入终端或命令提示符,键入以下命令:
python C:/<OPENVINO_INSTALL_DIRECTORY>/openvino/deployment_tools/model_optimizer/mo_tf.py --input_model= /<MODEL_DOWNLOAD_DIRECTORY>.pb --tensorflow_use_custom_operations_config C:/<OPENVINO_INSTALL_DIRECTORY>/openvino/deployment_tools/model_optimizer/extensions/front/tf/ssd_v2_support.json --tensorflow_object_detection_api_pipeline_config /<MODEL_DOWNLOAD_DIRECTORY>/pipeline.config --reverse_input_channels
我们将使用reverse _ input _ channels到反转颜色通道顺序,因为 OpenCV 使用 BGR 通道而不是 RGB 格式。为了调用对象检测 API 管道,我们需要将 pipeline.config 文件作为命令行参数传递给标志tensor flow _ object _ detection _ API _ pipeline _ config,以便正确配置模型的 IR。在上面和下面的示例中,我们将使用一个实际上是单次多盒检测器(SSD)的模型,因此我们需要使用tensor flow _ use _ custom _ operations _ config参数进一步指定命令,并传入一个 JSON 格式的配置文件。我们指定模型的。pb 文件使用 input_model 自变量。根据网络的深度,转换过程需要很长时间。
例如,我们使用 curl 下载一个预训练的 Tensorflow 模型,并使用tar -xvf提取 tarball


The Details of the Conversion Procedure can be seen in the image above.

On successful execution, the file location of the Intermediate representation of the Tensorflow model can be seen above.
将 Caffe 模型转换为中间表示:
为了将 Caffe 模型转换为 IR 格式,我们不需要像在 TensorFlow 模型中那样通过冻结它们来进行任何特殊类型的预处理。要转换成 IR,我们只需要在*中指定模型文件的位置。caffemodel 使用 input_model 参数,如果它包含一个名称与模型名称不同的 protobuf 文本文件,我们需要使用 input_proto 参数指定它的位置。
对于这个例子,下面我们将 GitHub 中的一个预先训练好的 Caffe 模型下载到我们的 Linux 机器中。并发出了以下命令:
python <OPENVINO_INSTALL_DIRECTORY>/openvino/deployment_tools/model_optimizer/mo.py --input_model <NAME_OF_MODEL>.caffemodel --input_proto <NAME_OF_DEPLOYMENT_PROTOBUF_TEXT>.prototxt

Conversion Procedure into IR from a model trained in Caffe.
因此,在上文中,我们讨论了如何通过 OpenVINO toolkit 的帮助,使用直接部署到设备中,以简单的方式将大型资源饥渴的深度学习模型转换为小型自治系统。在这种部署方式下,模型的数据流变得更加安全、快速和轻便。我们可以轻松降低在云系统的服务器上处理敏感信息的成本,我们可以通过每台设备提供超级敏捷的人工智能体验。
祝大家新年快乐!
真理可以有一千种不同的表达方式,但每一种都可能是真实的~斯瓦米·维威卡难达。**
让深度神经网络绘画来理解它们是如何工作的
深度学习的效果如此之好,这是一个谜。尽管有一些关于为什么深度神经网络如此有效的暗示,但事实是没有人完全确定,对深度学习的理论理解是一个非常活跃的研究领域。
在本教程中,我们将以一种不寻常的方式触及问题的一个微小方面。我们将让神经网络为我们描绘抽象的图像,然后我们将解释这些图像,以发展对引擎盖下可能发生的事情的更好的直觉。另外,作为奖励,在本教程结束时,您将能够生成如下图像(所有内容都少于 100 行 PyTorch 代码。点击查看陪同朱庇特的笔记本:

My neural network wants to be a painter when it grows up.
这个图像是怎么产生的?
这张图片是由一个叫做组合模式产生网络 (CPPN)的简单架构生成的,我是通过这篇博文了解到这个架构的。在那篇博文中,作者通过用 JavaScript 编写的神经网络生成了抽象图像。我的代码在 PyTorch 中实现了它们。
通过神经网络生成图像的一种方法是让它们一次输出完整的图像,比如说类似下面的内容,其中称为“生成器”的神经网络将随机噪声作为输入,并在输出层中生成完整的图像(宽度*高度)。

Image via A Short Introduction to Generative Adversarial Networks
与输出整个图像相反,CPPNs(我们将要探索的架构)输出给定位置像素的颜色(作为输入提供给它)。

Image via Generating Abstract Patterns with TensorFlow
忽略上图中的 z 和 r,注意网络正在接收像素的 x , y 坐标,并输出该像素应该是什么颜色(由 c 表示)。这种网络的 PyTorch 模型如下所示:
注意,它有 2 个输入,3 个输出(像素的 RGB 值)。生成整个图像的方法是输入所需图像(特定大小)的所有 x,y 位置,并将这些 x,y 位置的颜色设置为网络输出的颜色。
神经网络实验
我第一次尝试运行你在上面看到的神经网络时,我最终生成了这些图像。

If I had buyers for this art, I’d sell it in a jiffy.
我花了好几个小时挠头,想知道为什么网络输出的是灰色,而不管我输入的是什么 x,y 位置。理想情况下,这是不应该发生的,因为对于这样一个深度网络。改变输入值应该改变输出值。我还知道,每次初始化神经网络时,它都有可能生成一个全新的图像,因为它的参数(权重和偏差)是随机初始化的。但是很明显,即使经过几次尝试,我从我的神经网络得到的只是这种灰色的粘性物质。为什么?
我的怀疑集中在所使用的特定激活功能上: tanh 。也许后续层中的多个 tanh 序列将所有输入数字压缩到接近 0.5。在输出层(代表灰色)。然而,我关注的博客帖子也使用了 tanh。我所做的只是把用 JavaScript 编写的博客神经网络转换成 PyTorch,没有任何改动。
我终于找到了罪魁祸首。这就是 PyTorch 在初始化新的神经网络时初始化权重的方式。根据他们的用户论坛,他们用一个从-1/sqrt(N)到+1/sqrt(N)范围内随机抽取的数字初始化权重,其中 N 是一层中输入连接的数量。因此,如果隐藏层的 N=16,权重将从-1/4 到+1/4 初始化。我的假设是为什么这会导致一种灰色的粘性物质,因为重量来自一个很小的范围,并且变化不大。
如果网络中的所有权重都在-1/4 到+1/4 之间,当乘以任何输入并加在一起时,也许会发生类似于中心极限定理的效应。
中心极限定理(CLT)证明,在某些情况下,添加独立的随机变量时,即使原始变量本身不是正态分布的,它们的正态和也趋向于正态分布(非正式的“钟形曲线”)
回想一下后续图层上的值是如何计算的。

Image via For Dummies — The Introduction to Neural Networks we all need !
在我们的例子中,第一个输入层有 2 个值(x,y ),第二个隐藏层有 16 个神经元。因此,第二层上的每个神经元得到 2 个乘以从-1/4 到+1/4 的权重的值。这些值相加,然后在它从激活函数 tanh 出来后,变成新值,传递给第三层。
现在,从第二层开始,有 16 个输入要传递给第三层中 16 个神经元的每个。假设这些值中的每一个都由 z. 表示,那么第三层中每个神经元的值是:

这里我们再做一个猜测。因为权重的方差更小(-1/4 到+1/4),z 的值(输入 x,y 乘以权重,然后通过 tanh 函数)也不会有很大变化(因此会很相似)。因此,该等式可以被视为:

并且对于每个神经元,从-0.25 到+0.25 抽取的 16 个权重之和的最有可能的值是零。即使在第一层,总和不接近零,网络的八层给了上述等式足够的机会最终产生接近零的值。因此,不管输入值(x,y)如何,进入激活函数的总值(权重之和*输入)总是接近零值,其 tanh 映射为零(因此,所有后续层中的值保持为零)。

X-axis is inputs to TanH, and Y-axis is output. Note that 0 is mapped to 0.
颜色灰暗是什么原因?这是因为 sigmoid(最后一层的激活函数)将这个传入值 0 映射到 0.5(表示灰色,0 表示黑色,1 表示白色)。

Note how Sigmoid maps 0 input value to 0.5
灰色粘稠物怎么修?
因为罪魁祸首是重量的小偏差,我的下一步是增加它。我更改了默认的初始化函数,将权重从-100 分配到+100(而不是-1/4 到+1/4)。现在运行神经网络,这是我得到的:

Voila! Grey goo is now some blobs of color.
这是一个进步。我的假设是正确的。
但是生成的图像仍然没有太多的结构。太简单化了。
这个神经网络正在做的是将输入乘以权重,推动它们通过 tanh 并最终通过 sigmoid 输出颜色。既然我固定了权重,我可以固定输入以使输出图像更有趣吗?嗯。
请注意,上面的图像是在我输入 X,Y 作为原始像素坐标时生成的,从 0,0 开始,到 128,128 结束(这是图像的大小)。这意味着我的网络从未将负数视为输入,而且由于这些数字很大(比如 X,Y 可能是 100,100), tanh 要么得到一个非常大的数字(它挤压成+1),要么得到一个非常小的数字(它挤压成-1)。这就是为什么我看到原色的简单组合(例如,0,1,1 的 R,G,B 输出代表你在上面的图像中看到的青色)。
如何让图像更有趣?
就像在最初的博文中一样(这是我一直在关注的),我决定将 X 和 y 归一化,所以我将输入(X/image_size)-0.5,而不是输入 X。这意味着 X 和 Y 的值将在-0.5 到+0.5 的范围内(与图像大小无关)。这样做,我得到了下面的图像:

Some more progress!
有趣的是,在前面的图像中,线条在右下方增长(因为 X,Y 值在增加)。在这里,由于 X,Y 值是归一化的,并且现在包括负数,所以线条均匀地向外增长。
但是,图像仍然不够漂亮。
如何让图像更加有趣?
如果你仔细观察,你会发现在图像的中间,似乎比边缘有更多的结构。这是数学之神给我们的暗示,我们应该放大那里去发现美。
有三种向图像中心放大的方法:
- 产生大图像。由于像素坐标是归一化的,我们可以简单地运行神经网络来产生更大的图像。之后,我们可以通过图像编辑工具放大中间,看看我们发现了什么。
- 将 X 和 Y 输入乘以一个小数值(缩放因子),这将有效地实现与前面的方法相同的事情(并避免我们在其余不感兴趣的区域上运行浪费的计算)
- 由于输出是由输入*权重决定的,我们也可以通过将权重值从-100、+100 减少到+3、-3(记住不要减少太多)来缩放,而不是减少输入值。还记得重量在-0.25 到+0.25 之间时出现的灰色粘性物质吗?)
当我采用第二种方法,将 X 和 Y 乘以 0.01 时,我得到的结果如下:

I call it the Neural-Mondrian!
当我采用第三种方法并将权重初始化为-3 到+3 之间时,我得到了下面的图像。

Is your mind blown yet?
更多实验
我将权重初始化更改为正态分布(平均值为 0,标准偏差为 1),并生成了多个图像(来自随机初始化)。



当我删除所有隐藏层(只是输入到输出映射):

0 hidden layers
当我只保留一个隐藏层(而不是默认的 8 个隐藏层)时:

1 hidden layer
当我将隐藏层的数量增加到 16 层时:

16 hidden layers, 16 neurons per hidden layer
正如你所想象的,随着我增加隐藏层的数量,图像变得越来越复杂。我想知道,如果不是将层数增加一倍,而是保持层数不变(8),但每层的神经元数量增加一倍(从 16 到 32),会发生什么情况。这是我得到的:

8 hidden layers, 32 neurons per hidden layer
注意,尽管在上述两种情况下,网络中的总权重数是相似的,但是具有双层的网络比每层具有双层神经元的网络更加像素化。像素表明,在这些区域中,函数急剧变化,因此如果我们进一步放大,就会发现更多的结构。而对于具有原始层数但每层神经元加倍的网络,函数相当平滑,因此“可缩放性”较低。
当然,所有这些都是深度使神经网络更具表现力的另一种说法。正如关于深度神经网络表达能力的论文所建议的:
计算函数的复杂度随着深度呈指数增长
这正是我们所看到的。通用逼近定理说理论上,一个足够大的神经网络,即使只有一个隐层,也可以表示任何函数。但是,在实践中,网络越深,输入- >输出映射就越复杂,这是能够表现出来的。
毫无意义的实验,但是很有趣
如果我们将每层的神经元数量从 8 个增加到 128 个(一个数量级的增加)会怎么样。

Neuro-pollock!
如果我们从每个隐藏层 128 个神经元开始,但在每个后续层中逐渐减半,如下所示。
这是我得到的:

This one looks more “natural” than others.
还有吨 更多的实验可以做,并获得有趣的图像,所以我会把它留在这里给你玩的代码 (Jupyter 笔记本)。尝试更多的架构、激活和层。如果你有什么有趣的东西,在 Twitter 上给我加标签,或者在 Medium 上评论,我会在我的网络上分享。
或者你可以把神经网络生成的图像与神经网络生成的哲学结合起来,做出这样的东西:

My neural network is a stoic.
就是这样。希望你有兴趣生成漂亮的图像。
喜欢这个教程吗?也看看我以前的作品:
- 让你的神经网络说“我不知道”——贝叶斯神经网络使用 Pyro 和 PyTorch 。在 MNIST 数据集上编写贝叶斯图像分类器的教程+代码。
- 通过机器学习为机器学习项目产生新的想法。使用预先训练的语言模型从 2.5k 句子的小型语料库中生成风格特定的文本。PyTorch 代码
- 无梯度强化学习:使用遗传算法进化智能体。在 PyTorch 中实现深度神经进化为 CartPole 进化一个 agent 代码+教程]
在 Twitter 上关注我
我定期发关于人工智能、深度学习、创业公司、科学和哲学的推特。跟着我上https://twitter.com/paraschopra
[## Paras Chopra (@paraschopra) |推特
Paras Chopra 的最新推文(@paraschopra)。@Wingify |的创始人兼董事长写道…
twitter.com](https://twitter.com/paraschopra)
用不到 15 行代码在 R 语言中制作交互式地图
如果你有地理数据,你会想把它显示在地图上。只用几行简单的代码,我们就可以用 r 语言制作一个漂亮的地图。我假设你的电脑上已经安装了 R and R 工作室。
我强烈建议您在自己的计算机上跟随。我在这个项目中使用的数据可以在这个链接获得,它显示了我在过去几年中参观过的所有博物馆。我建议要么下载它,要么找到你自己的地理空间数据来玩。你应该查看我的数据,虽然检查我在做什么。
我还将在 R 中使用管道操作符,这有时会令人困惑,看起来像这样%>%。管道运算符将左边的对象作为右边函数的第一个参数。因此,以下几行 R 代码是等价的:
print(sum(c(1,2,3,4,5)))c(1,2,3,4,5) %>% sum() %>% print()
我们将使用 2 个外包装,传单和 tidyverse。传单构建在 JavaScript 之上,对映射很有用(使用它不需要 JavaScript 知识)。tidyverse 是一个超级包,包含许多其他包,用于读取、组织和清理数据。知道 tidyverse 有很高的投资回报,我建议学习它。
步骤 1:安装软件包
我们在 R Studio 的控制台中运行这些代码行来安装所需的包。
install.packages("tidyverse")install.packages("leaflet")

步骤 2:加载包
从现在开始,我们将在一个新的脚本文件中运行我们的代码。我们现在用 library()函数加载包。
library("tidyverse")
library("leaflet")
步骤 3:加载数据
接下来,我们使用 tidyverse 中的 read_csv()函数读入数据。您可能需要在 read_csv()函数中更改 csv 的文件路径。
library("tidyverse")
library("leaflet")museum <- read_csv("museum.csv")
步骤 4:添加瓷砖
步骤 4A:首先,我们必须使用管道将数据传递给传单函数。光靠这个是做不出地图的。
第 4B 步:在这个链接处挑选出图块(地图的样子)。
步骤 4C:将传单函数的输出传递给 addProviderTiles()函数,唯一的参数是您在步骤 4B 中选择的图块。我选了雄蕊。
library("tidyverse")
library("leaflet")museum <- read_csv("museum.csv")museum %>%
leaflet() %>%
addProviderTiles(providers$Stamen.TonerLite)

从现在开始,我建议在每一步结束时运行所有代码,看看地图是否合你的意。
步骤 5:添加多个图块
步骤 5A:选择另一组要添加的图块。
步骤 5B:使用组参数为每个切片命名,我选择了 ESRI . world imagery。
步骤 5C:添加图层控制(这使您可以看到两个切片)。您可以在右上角选择想要查看的互动程序
library("tidyverse")
library("leaflet")museum <- read_csv("museum.csv")museum %>%
leaflet() %>%
addProviderTiles(providers$Esri.WorldImagery, group = "World Imagery") %>%
addProviderTiles(providers$Stamen.TonerLite, group = "Toner Lite") %>%
addLayersControl(baseGroups = c("Toner Lite", "World Imagery"))

步骤 6:使用数据向地图添加标记
步骤 6A:使用 addMarkers()函数,如果你的数据集有纬度和经度(或它们的缩写),你不需要填写纬度和液化天然气的参数。
步骤 6B:您可以选择设置标签和弹出参数,以便当您将鼠标悬停在标记上或单击它时显示信息。
library("tidyverse")
library("leaflet")museum <- read_csv("museum.csv")museum %>%
leaflet() %>%
addProviderTiles(providers$Esri.WorldImagery, group = "World Imagery") %>%
addProviderTiles(providers$Stamen.TonerLite, group = "Toner Lite") %>%
addLayersControl(baseGroups = c("Toner Lite", "World Imagery")) %>%
addMarkers(label = museum$museum,
popup = ifelse(museum$`Presidential Library`=="Yes",
"A Presidential Library", # Value if True
"Not a Presidential Library")) # Val False

步骤 7:添加集群
如果你有很多很多的数据点,这是一件很好的事情,这样你的地图就不会被淹没。如果你们有非常接近的点,这也很好。我们需要做的就是用 clusterOptions 参数更新我们的 addMarkers()函数。
library("tidyverse")
library("leaflet")museum <- read_csv("museum.csv")museum %>%
leaflet() %>%
addProviderTiles(providers$Esri.WorldImagery, group = "World Imagery") %>%
addProviderTiles(providers$Stamen.TonerLite, group = "Toner Lite") %>%
addLayersControl(baseGroups = c("Toner Lite", "World Imagery")) %>%
addMarkers(label = museum$museum,
clusterOptions = markerClusterOptions(),
popup = ifelse(museum$`Presidential Library`=="Yes",
"A Presidential Library",
"Not a Presidential Library"))

步骤 8:设置开始缩放
这一步并不是必需的,但是如果您想将地图集中在一个特定的位置,您可以使用 setView()函数。我会关注亚特兰大。
library("tidyverse")
library("leaflet")museum <- read_csv("museum.csv")museum %>%
leaflet() %>%
addProviderTiles(providers$Esri.WorldImagery, group = "World Imagery") %>%
addProviderTiles(providers$Stamen.TonerLite, group = "Toner Lite") %>%
addLayersControl(baseGroups = c("Toner Lite", "World Imagery")) %>%
addMarkers(label = museum$museum,
clusterOptions = markerClusterOptions(),
popup = ifelse(museum$`Presidential Library`=="Yes",
"A Presidential Library",
"Not a Presidential Library")) %>%
setView(lat = 33.736309, lng = -84.388298, zoom = 11)

步骤 9:添加小地图
要添加一个小地图到我们的地图,我们只需要使用 addMiniMap()函数。您可以使用 addMiniMap()调整的两个参数是更改图块(这允许您更改地图背景,就像在主视图中一样)和 toggleDisplay(这允许您隐藏地图)。
library("tidyverse")
library("leaflet")museum <- read_csv("museum.csv")museum %>%
leaflet() %>%
addProviderTiles(providers$Esri.WorldImagery, group = "World Imagery") %>%
addProviderTiles(providers$Stamen.TonerLite, group = "Toner Lite") %>%
addLayersControl(baseGroups = c("Toner Lite", "World Imagery")) %>%
addMarkers(label = museum$museum,
clusterOptions = markerClusterOptions(),
popup = ifelse(museum$`Presidential Library`=="Yes",
"A Presidential Library",
"Not a Presidential Library")) %>%
setView(lat = 33.736309, lng = -84.388298, zoom = 11) %>%
addMiniMap(
toggleDisplay = TRUE,
tiles = providers$Stamen.TonerLite
)

我们完了!您可能已经注意到这比 15 行稍微多一点,我选择通过将函数分成多行来优化可读性。祝你所有的地理空间工作好运!
用机器学习制作音乐

Image from https://www.maxpixel.net/Circle-Structure-Music-Points-Clef-Pattern-Heart-1790837
音乐不仅仅是一门艺术,音乐是人类状态的一种表达。当一个艺术家创作一首歌的时候,你经常可以听到他们在那一刻的情感、经历和能量。音乐将世界各地的人们联系在一起,并在不同文化间共享。所以计算机不可能和它竞争,对吗?这是我和我的小组在为我们的机器学习课选择学期项目时问的问题。我们的目标是创造一些东西,让听众相信他们正在听的东西是由人类创造的。我认为我们个人取得了成功,但我会让你来评判(见本文底部的结果)。
方法
为了创作音乐,我们需要某种方法来学习现有歌曲的模式和行为,以便我们能够再现听起来像真实音乐的东西。我们所有人都对深度学习感兴趣,所以我们认为这是探索这项技术的绝佳机会。首先,我们研究了这个问题的现有解决方案,发现了来自sigur skúLi的关于如何使用 Keras 生成音乐的精彩教程。读完他们的教程后,我们对自己想做的事情有了一个很好的想法。
文件格式很重要,因为它将决定我们如何处理这个问题。教程使用了 midi 文件,所以我们照着做了,并决定也使用它们,因为它们很容易解析和学习(你可以在这里了解更多)。使用 midi 文件给了我们几个好处,因为我们可以很容易地检测音符的音高和持续时间。但是在我们一头扎进去,开始建立我们的网络之前,我们需要更多的关于音乐是如何构成的以及需要考虑的模式的信息。为此,我们去找了我的好朋友米奇·伯迪克。他帮助我们确定了一些关于我们方法的事情,并给我们上了一堂简单音乐理论的速成课。
在我们的谈话之后,我们意识到时间步长和序列长度将是我们网络的两个重要因素。时间步长决定了我们何时分析和产生每个音符,而序列长度决定了我们如何学习歌曲中的模式。对于我们的解决方案,我们选择 0.25 秒的时间步长和每个时间步长 8 个音符。这相当于 4/4 的拍号,对我们来说意味着 4 个音符的 8 个不同序列。通过学习这些序列并重复它们,我们可以生成一个听起来像真正音乐的模式,并以此为基础进行构建。作为起点,我们使用了 Skúli 的教程中提到的代码,但是最终我们的实现在几个方面与最初的有所不同:
- 网络体系结构
- 仅限于单键
- 可变长度音符和休止符的使用
- 歌曲结构/模式的使用
网络体系结构
对于我们的架构,我们决定主要依靠双向长短期记忆(BLSTM)层。下面是我们使用的 Keras 代码:
model = Sequential()
model.add(
Bidirectional(
LSTM(512, return_sequences=True),
input_shape=(
network_input.shape[1], network_input.shape[2]),
)
)
model.add(Dropout(0.3))
model.add(Bidirectional(LSTM(512)))
model.add(Dense(n_vocab))
model.add(Activation("softmax"))
model.compile(loss="categorical_crossentropy", optimizer="rmsprop")
我们的想法是,通过使用歌曲中特定位置前后的音符,我们可以生成听起来像人类的旋律。通常在听音乐的时候,之前的音乐有助于听者预测接下来的音乐。有很多次,当我在听一首歌的时候,我可以随着特定的节拍摇摆,因为我可以预测接下来会发生什么。这正是在一首歌中逐渐形成一个落差时会发生的情况。这首歌变得越来越强烈,这使得听众在期待下降时产生紧张感,并在最终下降时产生解脱和兴奋的时刻。通过利用这一点,我们能够产生听起来自然的节拍,并带来我们已经习惯于在现代音乐中期待的同样的情感。
对于 BLSTM 层中的节点数量,我们选择 512,因为这是 Skúli 使用的数量。然而,我们确实对此做了一点试验,但是由于时间限制,我们最终坚持使用原来的数字。30%的辍学率也是如此(点击阅读更多关于辍学率的信息)。对于激活函数,我们选择了 softmax,对于损失函数,我们选择了分类交叉熵,因为它们很适合多类分类问题,如音符预测(你可以在这里阅读更多关于它们的信息)。最后,我们选择 RMSprop 作为我们的优化器,因为这是 Keras 为 RNNs 推荐的。
关键限制
我们做的一个重要假设是,我们将只使用来自同一个调的歌曲:c 大调/A 小调。这样做的原因是,通过让我们制作的每首歌曲都保持同一个调,我们的输出听起来会更像歌曲,因为网络永远不会学习会导致歌曲跑调的音符。为了做到这一点,我们使用了一个脚本,我们发现在这里从尼克凯利。这部分真的很简单,但给我们的结果带来了巨大的改善。
可变长度音符和休止符
音乐的一个重要部分是动态和创造性地使用可变长度的音符和休止符。吉他手敲击的一个长音符,随后是一个平静的停顿,当我们听到演奏者的心和灵魂向这个世界溢出时,这可以向听者发出情感的波动。为了抓住这一点,我们研究了引入长音符、短音符和休止符的方法,这样我们就可以在整首歌中创造不同的情感。
为了实现这一点,我们研究了一个音符的音高和持续时间,并将其作为一个独立的值输入到我们的网络中。这意味着播放 0.5 秒的 C#和播放 1 秒的 C#将被网络视为不同的值。这使我们能够了解哪些音高比其他音高演奏得长或短,并使我们能够结合音符来制作一些听起来自然且适合歌曲该部分的东西。
当然,休止符是不能被遗忘的,因为它们对于引导听众进入期待或兴奋的状态至关重要。一个缓慢的音符和一个停顿,然后是一连串快速的音符,可以创造出一种不同于几个长音符之间长时间停顿的情感。我们认为这一点很重要,这样才能复制听众在听一首轻松的周日下午歌曲或周五晚上的派对歌曲时的体验。
为了实现这些目标,我们必须关注我们的预处理。这里,我们再次从 Skúli 教程中的代码开始,并根据我们的需要进行了修改。
for element in notes_to_parse:
if (isinstance(element, note.Note) or
isinstance(element, chord.Chord
):
duration = element.duration.quarterLength
if isinstance(element, note.Note):
name = element.pitch
elif isinstance(element, chord.Chord):
name = ".".join(str(n) for n in element.normalOrder)
notes.append(f"{name}${duration}") rest_notes = int((element.offset - prev_offset) / TIMESTEP - 1)
for _ in range(0, rest_notes):
notes.append("NULL") prev_offset = element.offset
为了详细说明上面的代码,我们通过将音符的音高和持续时间与一个“$”相结合来创建音符,以馈入我们的网络。例如“A$1.0”、“A$0.75”、“B$0.25”等。都将被单独编码以供我们的网络使用(通过将每个唯一的音符/持续时间映射到一个整数,然后将所有的整数除以唯一组合的数量,从而将每个编码为 0 和 1 之间的浮点数,来对输入进行编码)。更有趣的部分是计算插入多少休止符。我们查看当前音符的偏移,并将其与我们查看的上一个音符的偏移进行比较。我们用这个间隙除以我们的时间步长来计算我们可以容纳多少个休止符(减 1,因为这实际上是计算间隙中可以容纳多少个音符,但其中一个是我们实际的下一个音符,所以我们不想重复计算)。例如,如果一个音符从 0.5 秒开始,而下一个音符直到 1.0 秒才开始。时间步长为 0.25(每个音符以 0.25 秒的间隔播放),这意味着我们需要一个休止符来填补空白。
歌曲结构
最后,写一首歌最重要的部分之一是结构,这是我们发现现有解决方案中缺乏的东西之一。据我所见,大多数研究人员都希望他们的网络能够自己了解这一点,我不认为这是一种被误导的方法。然而,我认为这增加了问题的复杂性,并导致进一步的困难。这可能是我们解决方案的一个改进来源,尽管我们对此采取了更多的手动方法,并假设了一个恒定的模式。
我们做出的一个关键假设是,我们将只制作遵循特定模式 ABCBDB 的歌曲,其中:
- a 是第一节
- b 是合唱
- c 是第二节
- D 是桥
最初,我们尝试了 ABABCB,但这感觉太公式化。为了解决这个问题,我们决定引入第二节,它不同于第一节,但仍然相关。我们从一个随机的音符中生成了第一节,然后在第一节的基础上生成了第二节。实际上,这是生成一个两倍长的单个部分,并将其一分为二。这里的思考过程是,如果我们创作一首诗,第二首应该仍然符合同样的氛围,通过使用第一首作为参考,我们可以实现这一点。
def generate_notes(self, model, network_input, pitchnames, n_vocab):
""" Generate notes from the neural network based on a sequence
of notes """
int_to_note = dict(
(
number + 1,
note
) for number, note in enumerate(pitchnames)
)
int_to_note[0] = "NULL"def get_start():
# pick a random sequence from the input as a starting point for
# the prediction
start = numpy.random.randint(0, len(network_input) - 1)
pattern = network_input[start]
prediction_output = []
return pattern, prediction_output# generate verse 1
verse1_pattern, verse1_prediction_output = get_start()
for note_index in range(4 * SEQUENCE_LEN):
prediction_input = numpy.reshape(
verse1_pattern, (1, len(verse1_pattern), 1)
)
prediction_input = prediction_input / float(n_vocab) prediction = model.predict(prediction_input, verbose=0) index = numpy.argmax(prediction)
result = int_to_note[index]
verse1_prediction_output.append(result) verse1_pattern.append(index)
verse1_pattern = verse1_pattern[1 : len(verse1_pattern)]# generate verse 2
verse2_pattern = verse1_pattern
verse2_prediction_output = []
for note_index in range(4 * SEQUENCE_LEN):
prediction_input = numpy.reshape(
verse2_pattern, (1, len(verse2_pattern), 1)
)
prediction_input = prediction_input / float(n_vocab) prediction = model.predict(prediction_input, verbose=0) index = numpy.argmax(prediction)
result = int_to_note[index]
verse2_prediction_output.append(result) verse2_pattern.append(index)
verse2_pattern = verse2_pattern[1 : len(verse2_pattern)]# generate chorus
chorus_pattern, chorus_prediction_output = get_start()
for note_index in range(4 * SEQUENCE_LEN):
prediction_input = numpy.reshape(
chorus_pattern, (1, len(chorus_pattern), 1)
)
prediction_input = prediction_input / float(n_vocab) prediction = model.predict(prediction_input, verbose=0) index = numpy.argmax(prediction)
result = int_to_note[index]
chorus_prediction_output.append(result) chorus_pattern.append(index)
chorus_pattern = chorus_pattern[1 : len(chorus_pattern)]# generate bridge
bridge_pattern, bridge_prediction_output = get_start()
for note_index in range(4 * SEQUENCE_LEN):
prediction_input = numpy.reshape(
bridge_pattern, (1, len(bridge_pattern), 1)
)
prediction_input = prediction_input / float(n_vocab) prediction = model.predict(prediction_input, verbose=0) index = numpy.argmax(prediction)
result = int_to_note[index]
bridge_prediction_output.append(result) bridge_pattern.append(index)
bridge_pattern = bridge_pattern[1 : len(bridge_pattern)] return (
verse1_prediction_output
+ chorus_prediction_output
+ verse2_prediction_output
+ chorus_prediction_output
+ bridge_prediction_output
+ chorus_prediction_output
)
结果
我们能够通过这种方法获得令人惊讶的结果。我们可以始终如一地创作独特的歌曲,这些歌曲属于我们训练各自网络的适当流派。以下是我们各种网络的一些示例输出。
Ragtime
Christmas
Rap
结论
机器生成音乐确实是可能的。它比人类创作的音乐更好还是可能更好?只有时间能证明一切。从这些结果来看,我认为这是完全可能的。
未来的工作
可以进行一些改进,使之更接近真正的音乐。一些可能的想法/实验包括:
- 学习歌曲中的模式,而不是手动拼凑部分
- 将音符持续时间作为网络的单独输入,而不是单独处理每个音高/持续时间
- 扩展到多种仪器
- 远离 midi 文件,制作/学习真正的 MP3
- 学习时间步长、序列长度和拍号
- 引入随机性来模拟“人为错误/实验”
- 允许多个键
- 学习如何使用介绍和结尾
感谢
我要感谢我的队友 Izaak Sulka 和 Jeff Greene 对这个项目的帮助,以及我的朋友 Mitch Burdick 对音乐的专业知识,使我们能够取得这些伟大的成果。当然,我们要感谢 sigur ur skúLi 的指导,因为它为我们提供了一个很好的起点和一些参考。最后但同样重要的是,我要感谢尼克·凯利的剧本,他把歌曲转到了 c 大调。
这个项目的代码可以在这里找到:https://github.com/tylerdoll/music-generator
声明:我们项目中使用的音乐不属于我们,来自各种公共网站。
使 PATE 双向私有

Photo by Dayne Topkin on Unsplash
PATE,即教师集合的私有聚合,是 Papernot 等人在论文 中提出的一种机器学习框架,用于从私有训练数据 进行深度学习的半监督知识转移。该框架允许使用私有数据进行半监督学习,同时保留直观和强大的隐私保证。
PATE 基于这样一种思想,即如果在不相交的数据上训练的多个模型同意一个输入,那么关于它们的训练示例的私有数据不会泄露,因为所有模型都得出了相同的结论。通过只检索不同“教师”模型之间有很大相关性的输出,我们提供了直观的隐私。另一方面,当没有达成共识时,检索随机化的输出提供了强有力的隐私保证。这种随机选择可以通过噪声的聚集来获得,因此可以通过这种方式实现(ε,δ)-差分隐私。
此外,PATE 框架包含一个额外的步骤,以确保不会对教师的私人数据进行攻击,无论是通过多次查询还是通过模型的参数检查。为此,添加了一个“student”模型,该模型根据教师之前标记的公共数据进行学习。这样做消除了教师在后续查询中的需要,并确保学生模型只学习教师提供的概括。
该框架已经显示出实现了最先进的隐私/效用权衡,同时还具有灵活且广泛适用的实现。然而,在某些情况下,PATE 会陷入困境。这是指无法访问公共数据,或者学生的数据必然是私有的。PATE 要求学生与所有教师共享其数据,因此在此过程中无法保证隐私。这种情况的一个例子是,当一家医院想要训练一个神经网络进行诊断,并使用其他医院作为“老师”来标记其数据集。在这种情况下,PATE 可能是不可行的,因为“学生”医院可能有义务(在道德上或法律上)保持其数据集的私密性。
因此,提出了一个额外的步骤,其中教师集合被视为“机器学习即服务”(MLaaS) ,并且添加了加密来为学生的数据集提供保密性。在这里,我们将探讨如何应用这些变化,以及它如何影响 PATE 框架程序。
用 Pytorch 和 Pysyft 实现 PATE
本指南基于本回购。为了文章的可读性,代码的某些部分将被跳过或修改。
初始设置
首先,我们需要导入必要的库。本指南假定所有库都已安装在本地。
We’re declaring the necessary libraries and hooking Syft with Torch.
为了演示 PATE 的工作原理,我们将构建如下所示的示例:

Diagram of the scenario.
一家医院 S 拥有一些关于其患者的未标记数据,并希望使用这些数据来训练一个分类器。由于它的数据是无标签的,所以不足以训练一个学习算法。为了解决这个问题,医院的考虑使用来自其他医院的标记数据来训练一个学习算法,并使用该算法来标记其数据。尽管其他医院愿意提供帮助,但出于隐私考虑,他们无权与第三方分享自己的数据。
让我们应用 PATE 框架。我们会把 S 医院当做我们的学生,把其他医院当做我们的老师。教师被要求使用他们的私人数据集来训练他们的学习算法。
1.宣布每个医院的工作人员
Syft 利用工人来识别和连接其他设备。在我们的情况下,我们有学生的机器(我们将认为是本地工作人员)和其他医院的设备(将被称为教师)。
Declaring the workers. The local worker is automatically declared when hooking Syft.
在本例中,我们仅使用了 10 名教师,但请记住,使用教师的数量在技术上没有限制,最好使用更大的团队。
2.为教师定义和加载模型
PATE 框架的众多优势之一是它是模型不可知的,这意味着它不局限于特定的学习算法家族。尽管我们对所有教师使用相同的模型架构,但请记住这不是必需的。
This is the model for all the teachers.
本指南假设所有教师的模型都已经过培训。我们只需要加载它们并把它们发送到它们的机器上。在现实生活中,学生在这个过程中没有角色;相反,每个老师将负责实例化他们的模型。
Creating the models, loading them and sending them to each worker.
3.准备学生数据
现在所有的老师都准备好了,让我们从学生那里加载未标记的数据集。对于这个例子,我们使用 MNIST 测试集作为未标记数据集。
Load MNIST’s test dataset. This dataset will be used as the student’s unlabeled data.
在本例中使用已经标记的数据集的优点是,我们可以稍后将结果标签与真实标签进行比较。
至此,我们已经具备了 PATE 框架的所有要求。我们有一个未标记的数据集和多个模型,这些模型先前是在私有的、不相交的数据上训练的。现在,我们只需要将所有教师的意见汇总在一起,就可以得到数据集的标签。
4.将数据发送给每位教师进行分析
作为学生,我们希望从老师那里获得许多关于数据集中每个数据点的意见。从教师的角度来看,为了保护隐私,学生不能访问他们的模型。相反,它必须将其数据发送给每个老师,并等待分析。
Create a secure worker and send the unlabeled data for analysis.
注意,我们已经创建了另一个名为secure_worker 的工作者。 PATE 要求所有的意见都可以在一个点上获得,以生成投票最多的标签。因为我们不希望任何老师或学生看到原始意见,所以我们添加了第三方来负责汇总过程。
一旦完成,secure_worker将有一个形状为(data_size, num_teachers的矩阵。该矩阵包含来自数据集中数据点的所有教师的所有预测标签。
5.汇总意见
让我们考虑一下意见矩阵现在是什么样子。对于数据集的每一行,我们都有一些可能的标签,这些标签是由每个老师分配的。

An example of how the opinions matrix may look like. In some cases, there’s a clear consensus, while others require further processing.
通过为每个数据点选择投票最多的标签,我们获得了数据的广义分类。然而,如果存在没有明显标签的情况,那么我们就有选择一个由于过度拟合而被错误分类的标签的风险。这是一个隐私问题,为了减轻它,我们在所有投票计数中添加了一个仔细测量的拉普拉斯噪声。这样,我们增加了似是而非的可否认性,同时也保持了高准确性。

Previous scenario but with added noise. A high correlation between teachers leads to higher accuracy, while a low consensus with added noise leads to stronger privacy guarantees.
让我们来定义这个函数,我们将称之为“嘈杂的 Argmax 机制”。该函数将接收意见矩阵和ε值。这样,我们可以控制添加的噪声量。
Implementation of the noisy argmax mechanism.
记住意见矩阵在安全工作者的机器里。正因为如此,我们还必须发送要添加的噪声。
6.获得结果标签
既然定义了聚合查询,我们就可以获得结果并与真正的标签进行比较。
Getting the labels and comparing them to the true labels from the MNIST test set.
请注意,当将生成的标签与 MNIST 数据集中分配的标签进行比较时,我们获得了 90%的准确率。考虑到我们使用的ε的数量,这是一个很高的精度。这是迄今为止所做工作的完整图表。

Diagram of the implementation. Orange: unlabeled data sent. Red: predictions obtained. White: noisy labels returned.
在这一点上,学生可以利用这个数据集来训练他们的学习算法,并且没有从教师的私人数据中泄露隐私。
现在已经解释了 PATE 框架,让我们来看看为什么它不适合这个场景,以及应该做哪些改变。
使 PATE 双向私有
仔细观察前面的图表以及 PATE 实现,很明显学生的数据必须发送给所有教师进行分析。当这些数据公开时,这不是问题。但是,在某些情况下可能并非如此。我们医院的例子就是其中之一。在这种情况下,如果教师能够在不直接访问数据的情况下分析数据,那将是更好的。为了实现这一点,我们可以使用 附加秘密共享 对未标记数据集和教师模型进行加密。这意味着一些额外的步骤,并增加了对 PATE 框架的某些要求。
1.确保教师模型是可加密的
添加加密层意味着对数据进行的所有操作都必须兼容(并且安全)。在撰写本文时,仍有许多操作尚未在 PySyft 的库上实现。最重要的是,log_softmax()目前不兼容。这意味着每一个在最终层使用它的模型都必须被修改以允许加密。幸运的是,这种改变不需要重新训练模型。
Adapted model for encryption compatibility. Note that only one line changed.
2.加密模型
既然模型与附加秘密共享兼容,它们就可以被加密。这种加密需要多方共享数据。尽管我们可以使用这个例子中已经初始化的任何一个工人,我们还是要添加两个工人,分别叫做alice和bob。他们唯一的工作就是保存所有的加密值。
create alice and bob
由于附加秘密共享只适用于整数,我们必须将权重和偏差转换为固定的精度值。另外,从 PySyft 0.1.23a1 开始,似乎有一个 bug 在试图加密远程模型的模型参数时会引发异常。这里有一个解决方法。
Encrypting the long way.
3.加密数据集并获取意见
理想情况下,我们只需加密整个数据集,并执行与之前相同的程序来获得预测。遗憾的是,加密计算需要很长时间,而且计算量很大,所以我们必须批量处理。这个想法是,我们从我们的数据集中取出一小批,加密后发给所有老师进行分析。产生的标签被发送到secure_worker进行解密。一旦它们被解密,noisy _ argmax 机制就会被使用,并且生成的一批标签会被发送给学生。最后,学生将每一批连接在一起,以获得所有的标签。
Obtaining noisy labels with an encryption layer.
这个过程需要很长时间才能完成。在我的例子中,获得整个数据集需要大约 7 个小时。这是一个主要缺点,如果要使用这种技术,必须考虑到这一点。
现在我们可以用真正的标签做同样的比较。
Checking the accuracy of our noisy labels obtained through encryption of PATE.
得到的精度与没有加密时一样。现在,学生可以使用这些数据来训练其神经网络,因为他们知道数据集在这个过程中没有受到损害。
结论
PATE 是一个令人惊叹的框架,它提供了良好的结果,同时实现了高隐私保证。然而,在没有公共数据的情况下,传统的 PATE 可能是不可行的。当这种情况发生时,可以添加一层加密,允许数据在不损害其隐私的情况下被处理。尽管如此,实现这一点所需的额外复杂性和时间使它对于日常场景来说是一种不合理的方法。此外,由于学生模型是用私有数据训练的,它仍然容易受到攻击,这些攻击可能会泄露有关数据集的更多信息。因此,当学生数据集的隐私不相关或不必要时,应首选传统 PATE。
附加注释
这篇文章是 Udacity 的安全和私人人工智能纳米学位项目的一部分。这篇文章的目的是呈现和解释我在这门课的期末专题,它应该被视为如此。
文献学
- n .帕伯诺特,m .阿巴迪,厄林松,ú,& Talwar,K. (2016 年)。基于私有训练数据的深度学习半监督知识转移。 ArXiv , 1610 (05755)。从 https://arxiv.org/abs/1610.05755取回
- n . paper not & good fellow,I. (2018 年 4 月 29 日)。隐私和机器学习:两个意想不到的盟友?检索自http://www . clever Hans . io/privacy/2018/04/29/privacy-and-machine-learning . html
- 安全和私人的人工智能纳米学位项目。从https://www.udacity.com/course/secure-and-private-ai-ud 185检索
- 名词项目中 Rogério Saccaro 的私人文件。
- 医院图标取自 PNGio.com
- 人工智能图标取自免费图标库。
- 服务器图标取自 icons8.com
使用键盘宏简化编程—视频
Linus Tech Tips 最近的一个视频介绍了他们的一个编辑器如何使用宏进行视频编辑。这让我开始思考;可以很容易地创建宏来改进我的编程吗?
此视频演示了如何创建代码宏及其用途:
背景

Source: Linus Tech Tips — Can your Keyboard do THIS?? — Make ANY key a MACRO!
如前所述,这个想法是在观看 Linus 技术提示视频后产生的。现在,他可能在 3 个专用于宏的键盘上走得有点远了(如上图所示)。然而,我已经碰巧使用了一个有一些宏按键的,所以为什么不利用它。
我的键盘是罗技 G910,它有 9 个宏按键,3 个轮廓,总共有 27 种可能的组合。
它是如何工作的
幸运的是,罗技软件使这变得非常容易,但用其他设备复制也应该很简单。我只是分配每个宏来创建一个文本块,粘贴一些预定义的代码。

我为总共 10 个宏分配了 5 个键和 2 个配置文件。这些显示在下图中,并在视频中充分展示。

每个宏都粘贴预定义的代码,从而可以快速轻松地执行一些任务,例如:
- 导入包/依赖项
- 导入/导出数据
- 使用设置的格式创建图
- 创建 for 循环
- 定义函数
- 为减价单元格创建 LaTeX 方程

这些只是我发现的主要用例,但我相信每个人都会根据自己的需求有自己的想法。
我希望这对您自己的数据科学任务有用
谢谢
作为一名数据科学家,坚持提出建议
用这六个原则让推荐脱颖而出

你有没有向观众介绍过你的推荐,却让他们无处可去?如果你像大多数数据科学家一样,很可能你以前也遇到过这种情况。
数据科学家的部分工作是能够将您的工作转化为对利益相关者可行的建议和见解。这意味着让你的想法令人难忘,易于理解和有影响力。
在本文中,我们将探索《让 贴上 这本书背后的原理,并在数据科学的背景下应用它。这本书提出,最好的想法遵循六个主要原则:简单、出乎意料、具体、可信、情感和故事(成功)。读完这篇文章后,你将能够把这些原则融入到你的工作中,并增加你的建议和见解的影响力。
简单的
让一个想法变得简单就是把这个想法剥离到它的核心。不是要变笨,而是要创造一些优雅的东西。这意味着你应该避免用想法压倒你的听众,当你试图说三件事时,你什么也没说。使想法简单的另一个关键因素是避免埋没线索。如果在您的分析过程中,您发现 10%的客户贡献了 80%的收入,请以这一关键见解为线索!你应该遵循一个倒金字塔的方法,最初的几分钟传达最多的信息,随着你越走越远,你可以得到更多的细微差别。类比和隐喻也是简单简洁地表达你的想法的好方法。能够使用你的观众能够理解和联系的模式,会使它更容易理解。例如,一个一句话的比喻,比如优步代表 X,可以抓住你想要传达的核心信息。
意想不到的
意想不到的想法是违背人们的期望,利用惊喜的想法。你可以通过几种方式做到这一点,其中之一是让人们承诺一个答案,然后伪造它。例如,在透露真实答案之前,要求猜测员工在完成一项你希望自动化的任务上花费了多少时间。另一种激发兴趣和利用意外原理的方法是使用神秘事物,因为它们会带来“啊哈”时刻。这可能会以一个小故事开始你的陈述,直到最后你才决定。
混凝土
对于非专家来说,抽象是理解的敌人。作为数据科学家,您的工作是让您的建议和见解更加具体。理解的关键是使用具体的图像,并根据人类的行为和感觉来解释想法。具体性的天敌是知识的诅咒。作为数据科学家,我们需要抵制用不必要的技术信息淹没受众的冲动。例如,报告一个模型的均方根误差,可能没有把语言分解成任何人都能理解的更具体的术语有用。
可信
给你的推荐增加可信度有三种形式。当我们想到可信度时,第一个是最常见的,即利用专家来支持声明或断言。另一种方法是使用反权威人士,他们是有着强大故事的真实人物。例如,如果你在谈论吸烟的危害,一个患肺癌的人的故事将比一个无菌的统计数据更有影响力。给你的故事增加可信度的第三种方法是把你观点的可信度外包给你的听众。这意味着创建一个可测试的声明,让受众可以尝试。例如,声称来自区域 A 的客户比来自任何其他区域的客户多花费 80%的客户支持时间。在提出这一主张时,您的受众可以确认这一主张,从而更容易引导您进行推荐。
情绪
在你的想法中加入情感因素是为了让人们关心你。人类天生就能感受人类,而不是抽象概念。因此,一个人往往胜过一个综合统计数据。情绪的另一个组成部分是挖掘你的观众所认同的群体身份。记住这些特征,你就可以把相关的联想联系起来,并唤起你的听众最容易接受的某些图式。例如,如果你知道你的一个听众是一个坚持数字的人,并且想要看到你是如何得出某些结论的详细分类,那么添加一个附录可能是有帮助的。
故事
几个世纪以来,人类一直在讲故事,事实证明这是最有效的教学方法之一。如果你反思过去 5 年读过的书,你更可能记住有趣的故事,而不是客观事实。当把故事编织到你的推荐中时,一定要营造紧张气氛,不要一下子把所有东西都泄露出去。另一个有用的策略是讲故事,作为其他想法的跳板。创造开放式的故事,让你的观众可以在此基础上发展,这是让他们获得主人翁感的好方法。
下一次,当你需要提炼你的见解或推荐时,请记住这六条原则,你将很快创造出简单、意想不到、具体、可信的情感故事!
用 Jupyter 让远程服务器上的深度学习变得可容忍

TL;DR 如何用 Jupyter 和远程服务器设置一个基本的深度学习环境,而不会发疯。
我最近开始从事深度学习,每当我想改变一个超参数时,我几乎疯狂地使用 vim 打开我的 5000 多行代码库。在习惯了 jupyter 之后,我希望能够使用 Jupyter 处理远程服务器上的文件。
如果你不熟悉 Jupyter,这里有一个的好帖子让你开始。熟悉之后,您现在可以继续阅读,将 Jupyter 配置为从本地浏览器运行,并在服务器上处理文件。
- 到远程服务器的 SSH
- 使用终端管理器,它允许我们在终端内创建多个会话。如果与远程服务器的连接丢失,它还可以防止代码被截断。因此,如果我们有需要长时间运行的代码,并且您可能想让它一直运行,那么这是非常有用的。我个人用 byobu 但是你可以用 tumx 。在 Ubuntu 18 中,这些都是预装的。如果您运行的是旧版本,并且没有看到 byobu,您只需使用
sudo apt-get install byobu
在那之后,你可以跑路了
byobu
我们使用终端管理器的主要原因是,当我们运行 Jupyter 笔记本时,终端会被用完。通过 byobu,我们可以为 jupyter 创建一个会话,并在另一个选项卡上运行测试/培训。
3.接下来,我们需要将浏览器上的“localhost”链接到我们第一次启动 Jupyter 的终端上
jupyter notebook -- no-browser -- port=8889
这将迫使 Jupyter 不打开浏览器,而使用端口 8889。我们可以随心所欲地改变它。
接下来,我们将这个端口从我们的服务器链接到本地机器上的“localhost”。我们通过打电话
ssh -N -f -L localhost:8888:localhost:8889 username@remote-server
请用您的用户名替换用户名,用服务器地址替换远程服务器。我们应该会看到这样的提示
The Jupyter Notebook is running at: [http://localhost:8889/?token=57cba986153f10a08c0efafa91e91e3299358a287afefaafa](http://localhost:8889/?token=57cba986153f10a08c0ebb91e91e3299358a287a08a5fd61)
现在我们可以跑了
localhost:8888
这将在浏览器中启动链接到远程服务器的 Jupyter 会话。
页(page 的缩写)启动本地主机时,系统可能会提示您输入代码或令牌。为此,只需从终端复制粘贴令牌 id (/'后的字符串?token= )
你已经准备好了!
感谢阅读!
在 googleVis 中制作桑基图
统计程序 R 可用于强大的数据可视化。
我用一个 R 包创建了一个 Sankey 图,展示了在一次大选中,从召回 2016 年欧盟公投投票到当前投票意向的流程。
制作桑基图
英国民意调查委员会成员民意调查的数据表显示了不同部分对问题(如投票意向)的回答。使用 2019 年 8 月 8 日至 9 日通过互联网小组对 2003 名英国成年人进行的 Opinium 民意调查。这项民意调查是由《观察家报》发起的。
这些数据表提供了受访者的准确人数:

This is an edited part of the Opinium/Observer data tables. (Image: Opinium/Observer)
然后,我们可以创建表格,显示主要政党(保守党、工党、自由民主党、英国退出欧盟党)和其他政党的留欧和脱欧投票。
准备好的数据表显示源变量和目标变量及其值:

使用 googleVis
googleVis 包允许 R 与 Google 图表工具接口。创建 Sankey 图的函数称为 gvisSankey,其选项的结构有些复杂。
要为节点输入正确的颜色,需要按照它们在表中的原始顺序进行排序:第一个源、目标和后续源。这一点还不清楚,需要反复试验。
opinium_sankey_gv <- gvisSankey(opinium_sankey_df, options = list(height = 500, width = 500, tooltip = "{isHtml:'True'}", sankey = "{link: { colorMode: 'source' }, node: { colors: ['#FFC010', '#0069B5', '#DC241F', '#FAA61A', '#12B6CF', '#DDDDDD', '#0087DC'] }, iterations: 1}"))
该图显示了从 2016 年召回欧盟公投投票到当前大选投票意向的流程。以下是 Opinium 民意调查的主要估计:

The interactive version of the Sankey diagram may be viewed. (Image: R/googleVis)
创建有效的数据可视化需要时间。使用 googleVis 也有局限性,比如无法为情节设置标题。
Jen Thompson 还提供了使用 gvisSankey 的指南。Google Sheet 文件可能下载了,并且我的 RPubs 文章可供阅读。
理解 Shapley 值

Image credit: Iker Urteaga at https://unsplash.com/photos/TL5Vy1IM-uA
我第一次听说 Shapley values 是在研究模型可解释性的时候。我遇到了 SHAP,这是一个可以更好地理解为什么你的机器学习模型会这样的框架。事实证明,Shapley 值已经存在了一段时间,它们最初起源于博弈论领域,可以追溯到 1953 年,目的是解决以下情况:
一群不同技能的参与者为了集体奖励而互相合作。奖励应该如何在团队中公平分配?
有趣的是,当一个“旧”的概念应用到另一个领域如机器学习时,它可以获得新的生命。在机器学习中,参与者是你输入的特征,集体支出是模型预测。在这种情况下,Shapley 值用于计算每个特征对模型输出的贡献。
沙普利值是如何计算的?大多数时候,你会在文学作品中看到这个等式:

让我们把它分解一下。在联盟游戏(之前描述的场景)中,我们有一组 N 的 n 玩家。我们还有一个函数 v ,它给出这些玩家的任何子集的值(或支出),即让 S 是 N 的子集,然后 v( S )给出该子集的值。因此,对于一个联盟博弈( N ,v)我们可以用这个等式来计算玩家 i 的支付,即沙普利值。
我不知道你是怎么想的,但当我第一次看到这个等式时,我的第一反应是类似于“这到底是什么???"
我很难理解为什么它看起来是这样的。这花了一些时间,但在尝试了一点之后,它终于开始变得有意义了。所以,让我们开始吧!
好的,我们要做的第一件事是稍微改写一下初始方程

乍一看,我们似乎并没有使我们的处境变得更好,但是请耐心听我说。很快我将分解等式的不同部分,以便理解它们,但是让我们也定义一个玩具场景,我们可以使用它来使它不那么抽象。
假设我们经营一家生产砖的工厂。我们的一个制作团队由四个人组成: A 曼达、 B 恩、 C 莱尔和 D on(从现在开始我会用他们名字的第一个字母来称呼他们)。每周他们一起设法生产出 X 数量的砖。因为我们工厂进展顺利,我们有一笔奖金想分发给团队成员。但是,为了让我们以公平的方式做到这一点,我们需要找出每个人每周为生产 X 数量的砖做出了多少贡献。
这里的困难之处在于,我们有几个影响因素,它们都会影响团队能够生产的砖块数量。其中一个是团队规模,因为团队越大,生产的砖块就越多。另一个可能是团队成员之间合作的好坏。问题是我们无法以有意义的方式量化这些影响,但幸运的是,对我们来说,Shapley 值可以用来回避这个问题。
我们现在已经定义了我们的玩家( A 、 B 、 C 和 D )以及他们正在参与的游戏(生产砖块)。让我们首先决定生产的 X 砖块中有多少可以归因于 D on,即计算 D 的沙普利值。如果我们将其与 Shapley 值公式的参数联系起来,我们就可以得到

所以 D 就是我们的选手 i 而整个团 N 由全部四名队员组成, A 、 B 、 C 和 D 。有了这些,让我们开始仔细看看 Shapley 值公式的这一部分

它说我们需要把我们的一群人和排除我们现在关注的人。然后,我们需要考虑所有可能形成的子集。因此,如果我们从组中排除 D ,我们就剩下 {A,B,C} 。从这个剩余的组中,我们可以形成以下子集(即这些是 S 可以接受的集合)

总的来说,我们可以构建剩余团队成员的 8 个不同子集。这些子集和中的一个是空集,即它没有任何成员。现在让我们把注意力转向这一部分

这就是沙普利价值的一个基本概念开始发挥作用的地方:将玩家 i 加入游戏的边际价值。因此,对于任何给定的子集 S ,我们将把它的值与当你把参与人 i 包括在内时的值进行比较。通过这样做,我们得到了将参与人 i 添加到该子集的边际值。
如果我们把它与我们的例子联系起来,我们想看看如果我们把 D 加到我们的 8 个子集中,每周生产的砖的数量会有什么不同。我们可以将这 8 个边际值直观地表示为

您可以将这些视为不同的场景,我们需要观察这些场景,以便公正地评估 D 对总体产量的贡献。这意味着我们需要观察如果没有人工作(即空集和)会生产多少砖块,并将其与只有和工作时的情况进行比较。我们还需要观察 AB 产生了多少砖块,并将其与 AB 和 D 一起产生的砖块数量进行比较,以此类推,我们可以形成所有 8 个星座。
好了,我们现在已经知道我们需要计算 8 个不同的边际值。沙普利值方程中的求和告诉我们,我们需要把它们加在一起。然而,在我们这样做之前,我们还需要缩放每个边际值,这是等式的这一部分告诉我们的

当我们用除了玩家 i 之外的所有剩余团队成员构建子集时,它会计算每个子集大小的排列数。或者换句话说:如果你有 |N|-1 名选手,你能和他们组成多少组大小 |S| 的队伍?然后我们用这个数字来划分玩家 i 对所有大小为 |S| 的组的边际贡献。
对于我们的场景,我们有 |N|-1 = 3 ,也就是说,当计算 D 的 Shapley 值时,我们剩下的团队成员。在我们的例子中,我们将使用等式的这一部分来计算我们可以组成多少个大小为 0、1、2 和 3 的组,因为这些只是我们可以与剩余玩家一起构建的组大小。因此,举例来说,如果我们有那个 |S|=2 ,那么我们得到我们可以构造这个大小的 3 个不同的组: AB 、 BC 和 CA 。这意味着我们应该将以下比例因子应用于 8 个边际值中的每一个:

让我们思考一下为什么我们要这样做。我们想知道 D 对团队总产量的贡献有多大。为了做到这一点,我们计算了他对我们能组成的团队的每个星座的边际贡献。通过添加这个比例因子,我们平均出团队其他成员对每个子集大小的影响。这意味着当加入到规模为 0、1、2 和 3 的团队中时,我们能够获得 D 的平均边际贡献,而不管这些团队的构成。
好了,我们现在差不多完成了,我们只剩下 Shapley 值方程的最后一部分需要分解,这一点也应该很容易理解

我们还有最后一个比例因子,需要应用于所有的边际值,然后才能对它们求和。我们必须将它们除以参与游戏的玩家数量,即我们总共拥有的团队成员数量。
再说一遍,我们为什么要这么做?好吧,如果我们看一下我们的砖厂例子,我们已经平均了其他团队成员对每个子集大小的影响,允许我们表达 D 对大小为 0、1、2 和 3 的组的贡献。谜题的最后一块是平均出团队规模的影响,也就是说 D 贡献了多少而不考虑团队的规模。对于我们的场景,我们通过除以 4 来实现这一点,因为这是我们可以考虑的不同组大小的数量。
我们现在已经到了可以最终计算出 D 的 Shapley 值的时候了。我们已经观察到他对团队中不同星座的贡献有多大。我们还计算了团队成员构成和团队规模的平均影响,最终使我们能够计算

I’m playing it fast and loose when it comes to using mathematical notation here, but this is more of a graphical illustration of what we’re doing than a mathematical one (it’s how I visualize it in my head).
我们有了,D 的沙普利值。在我们完成这项工作后,团队的其他成员就会知道每个人对每周生产的砖块数量的贡献,这样我们就可以在所有团队成员之间公平地分配奖金。

至此,我希望您已经更好地理解了沙普利价值观是如何运作的。如果你考虑到我们不需要知道任何关于价值函数 v 的内部工作原理,我们只需要观察它给不同子集的值就可以了,我们可以从参与游戏的玩家中制定出这些值。
这是沙普利价值观背后真正的力量和吸引力。然而,这是有代价的。对于一组参与游戏的 n 名玩家,您将拥有需要分析的 2^n 子集,以便计算沙普利值。
有一些方法可以使计算更实际可行,在介绍中我提到了 SHAP 框架,它的主要优势是当应用于机器学习时,它能够更有效地计算 Shapley 值(你可以在这里阅读更多信息)。
非常感谢Albin remng对本文初稿的宝贵反馈。
用 Python 建模新闻报道。第 1 部分:导言
有很多新闻媒体有很多不同的观点。从某种意义上说这很好,但从另一种意义上说,任何人都不可能每天都阅读所有的东西,更别说那些忙碌几天的人了。然而,新闻只是随着时间的推移发生的一系列事件,所以这表明有一种方法可以对它进行建模,这样我们就可以了解正在发生的一些事情。
预测新闻趋势可以被认为是类似于人们已经试图在股票市场上做的事情,我们知道有一系列影响股票价格的因素,如果你得到了正确的因素,你就可以根据今天发生的事情预测出股票的未来价格。同样,如果我们真正理解了新闻中正在发生的事情以及影响新闻制作的因素,那么我们应该能够利用这种理解来预测未来的新闻制作。虽然不一定有经济效益,但了解事件的报道如何随着时间的推移而变化,可能有助于我们理解为什么人们会以不同的方式看待事件,以及事情是如何发展到现在这个地步的。
这是探索新闻报道建模系列文章中的第一篇博文。每篇文章都包含独立于其他文章运行分析的代码。它使用 60 天的数据来写博客(刚好够 SARIMA 以后使用),使用更长的时间会表现得更好。
迄今为止撰写的帖子:
- 第 1 部分:简介(This)随机生成时间序列数据,然后查看一些真实的 Twitter 数据,然后查看一些新闻报道的时间序列,并通过向量自动回归来运行它们,以显示有模式可寻。
- 第 2 部分:用有限的数据开始新闻预测提供了使用现成的神经网络和使用几个新闻报道的时间序列预测报道的基础,然后用 SARIMA 模型做同样的事情。
- 第三部分:新闻网站与谷歌搜索趋势的互动继续使用 SARIMA 模型来研究新闻网站报道与谷歌搜索趋势之间的互动。它使用新闻数据和搜索数据来预测搜索率和新闻报道。
玩时间序列(随机数据)的快速复习
我正在用 python 做这件事,代码全部提供。您应该能够将代码粘贴到启用 python 的笔记本中(例如https://colab . research . Google)并运行它,它应该能够工作。当我有时间的时候,我会回去修复一些东西,但是我想我会把这篇博客文章放在那里,以防有人在寻找开始这种分析的地方。
所以让我们开始吧!使用 index 代表时间,我们可以使用 numpy 的 random 函数在 Python 中创建一个随机的外部(来自外部模型的输入)时间序列:
import pandas as pd
import numpy as np
exogenous = np.random.uniform(size=100)
df = pd.DataFrame(exogenous)
df.plot()

然后,我们可以创建一个内生时间序列,也就是说……我们的外生时间序列的 1.5 倍。
endogenous = 1.5 * exogenous
df = pd.DataFrame([endogenous, exogenous]).T
df.columns = ["endogenous", "exogenous"]
df.plot()

我们现在可以运行 OLS,看到内生的是外生的 1.5 倍
import statsmodels.api as smmodel = sm.OLS(df.endogenous,df.exogenous)
results = model.fit()
results.summary()

OLS Regression Summary on Endo/Exo Series
万岁!我们得到了 1.5 的系数,关于内生导致外生。然而,我们真正想做的是能够提前预测将要发生的事情。由于这些值是随机的,我们不会有任何滞后,但我们可以通过将所有内生值下移一个单位并删除第一个时间序列来改变这一点..
df.endogenous = df.endogenous.shift()
df = df[1:]
model = sm.OLS(df.endogenous,df.exogenous)
results = model.fit()
results.summary()

OLS on shifted series
嗯,我们有一个系数,但是 R 平方和其他指标都不好。这很好,因为现在每个都是随机值。然而,我们希望看到以前的值,所以让我们尝试一个向量自回归模型,为了好玩,加入一些滞后值。
from statsmodels.tsa.api import VARmodel = VAR(df)
results = model.fit(maxlags=3)
results.summary()

VAR results
万岁!该模型估计,内生因素与外生因素的差距仅为 1.5 倍,而外生因素是 0.43+-一些噪声,尽管这些噪声在统计上是显著的(应该是 0.5 倍,它也从滞后中获得了一些随机性)。
哦,只是为了好玩,我们可以很容易地说,我们可以用外生来预测内生,但不能用内生来预测未来的外生。为了测试这种情况有多严重,我们可以使用格兰杰因果关系,这基本上是对每个序列分别运行 OLS,然后看看在第二个时间序列中添加是否有助于我们获得更好的数字。因此,运行测试检查第二个时间序列是否有助于预测第一个时间序列。(也就是说,h_0 将是第二个变量不会导致第一个变量,所以如果我们可以否定 h_0,这意味着第二个变量不会导致第一个变量,尽管否定 h_0 只是表明存在相关性,而不是实际的因果关系)。
from statsmodels.tsa.stattools import grangercausalitytestsgc = grangercausalitytests(df[["endogenous", "exogenous"]], 2)

Granger causality of exogenous on endogenous
在滞后 1 运行从外生到内生的格兰杰因果关系会给我们一个比滞后 1 和滞后 2 更好的检验结果(因为滞后 2 只是噪声)。现在我们可以检查另一个方向。
gc = grangercausalitytests(df[[“exogenous”, “endogenous”]], 2)

Granger causality of endogenous on exogenous
我们从结果中看到,在内生->外生方向上没有统计上的显著关系,所以不能拒绝 h0。
太酷了,我们记住了什么是时间序列,并可以对它们稍加修改。还有其他重要的东西,如正常化趋势和季节性,以及扰乱自相关,但我们可以稍后再担心,现在让我们来看看新闻。最终,在训练数据之外的任何更好的预测都将是我们所关心的,加入不同的函数只是提高了我们用来判断模型是否好的准确性。
新闻时间系列《荒野》(推特)
在进入新闻之前(这是一件痛苦的事情,除非你手头正好有一份新闻文章的档案,我将在稍后介绍一种变通方法),让我们看看一些随机的有新闻价值的推文。谢天谢地,有一个很好的有新闻价值的特朗普推文档案可供查看。
所以我们可以去http://www.trumptwitterarchive.com/archive然后去“下载”——>“JSON”抓取川普所有推文的档案。我们将把弹出的结果复制/粘贴到一个实际的。json 文件在我们的工作目录中;我把它叫做“trump_tweets.json”。

Going here, downloading Trump’s tweets
所以我们可以把它移植到熊猫身上。
df = pd.read_json(“trump_tweets.json”)
df.head()

Head of the json file
所以我们看到我们有一堆推文的数据。我们有一堆 created_at 的时间戳,每条推文有多少赞,id 字符串(通过追加到 https://twitter.com/realDonaldTrump/status/)的末尾链接到原始推文)。最重要的是,我们得到了文本。
所以让我们忽略除了 text 和 created_at 之外的一切。现在,有很多方法可以篡改文本,但是我不知道如何在博客文章的这一点上做好自然语言编程。那么看看他发的微博有什么有趣的呢?
嗯,发生了很长时间的事情是俄罗斯勾结和穆勒报告的整个事情。因此,让我们看看他从 2017 年初开始通过 2019 年 3 月的巴尔备忘录使用一些基本的字符串匹配来发布关于俄罗斯和勾结的推文的频率。我们将从他的文本开始,并使其小写
#convert created_at to datetimeimport datetime
df.created_at = pd.to_datetime(df.created_at)df = df[(df["created_at"] < datetime.datetime(2019,3,1)) & (df["created_at"] > datetime.datetime(2017,1,1))]# create a column for lower case
df[“text_lower”] = df.text.apply(lambda x:x.lower())len(df)
>>> 41420
太好了,我们已经有 41000 条推文了。现在让我们做一些标记
df[“russia”] = df.text_lower.apply(lambda x: x.find(“russia”) > -1)df[“collusion”] = df.text_lower.apply(lambda x: x.find(“collu”) > -1)
我们可以只选择那些提到这两个词的推文
#create df where the previous rows had either russia or collusion labelrc_df = df[df["russia"] | df["collusion"]].set_index("created_at")
我们可以重新采样,得到每天的计数,然后继续绘制
rc_df_d = rc_df[["russia", "collusion"]].resample("d").sum()rc_df_d.plot(figsize=(12,8)

我们可以运行我们的风险值模型
模型= VAR(rc_df_d)
结果=模型.拟合(maxlags=5)
结果.总结()

因此,我们看到,到目前为止,我们为我们的模型计算的大系数是他之前是否在推特上发布过关于这个主题的消息,至少在日常水平上。
但是我们不需要只处理每日粒度,我们也可以查看每周粒度。
rc_df_w = rc_df[[“russia”, “collusion”]].resample(“w”).sum()
rc_df_w.plot(figsize=(12,8))

运行 VAR,我们得到几乎没有关系,除了勾结推文可能与俄罗斯推文 2 周前。
model = VAR(rc_df_w)results = model.fit(maxlags=3)results.summary()

因此,在每周水平上,我们开始看到俄罗斯的推文有一个轻微的系数(. 18),导致在 2 周的滞后期内关于勾结的推文。所以我们也可以加入更多的变量。让我们随便找个东西,比如,哦,中国,扔进去,重新算一遍。
df[“china”] = df.text_lower.apply(lambda x: (x.find(“china”) > -1) or (x.find(“chinese”) > -1))rcc_df = df[df[“russia”] | df[“collusion”] | df[“china”]].set_index(“created_at”)rcc_df_d = rcc_df[["russia", "collusion", "china"]].resample("d").sum()rcc_df_w.plot(figsize=(12,8))

Oh, wait, I think there’s a trend there ish. and a seasonality.I should have covered stationarity and decomp.
所以我们可以检查我们的风险值
model = VAR(rcc_df_d)results = model.fit(maxlags=5)results.summary()

所以在前两者的每日水平上看不到太多,但是看到有一个 0.12 的系数在 4 天的共谋滞后上。
我们可以在那里运行我们的每周 VAR,看看会有什么结果。
model = VAR(rcc_df_w)results = model.fit(maxlags=3)results.summary()

因此,对于这个模型,到目前为止,俄罗斯推文的中国系数有 2 周的滞后,俄罗斯串通有 2 周的滞后,中国串通有 1 周的滞后。所以这里有更多的东西需要挖掘(这涵盖了整个时间段),以检查这些关系何时成立以及多久一次,但现在我们将转而实际查看新闻。因为这个帖子是关于新闻的,不是关于推文的。但现在你看到了如何从 tweets 中提取一些文本,将其转换成时间序列,并运行任何你想在其上运行的模型。
所以终于有了真正的新闻
预标记集合:GDELT
GDELT[https://www.gdeltproject.org]是一个非常酷的项目,它每天检查大约 10 万个新闻网站,给所有文章贴上标签,并使它们可用。有一个版本 1 每天拉和版本 2,每 15 分钟拉一些更好的标签。这些标签包括主题(他们自己编的)、人物、地点和其他一些我一时想不起来的东西。
我们将通过下载过去 60 天的数据来了解这一点。如果你知道你在做什么,你可以继续从他们的 BigQuery 数据库中提取你想要的东西,这个数据库可以追溯到 2014 年(尽管早期的文章很糟糕)。
因此,这将是一个有点内存密集型(15gb 左右),因为我要保持一切在内存中,而不做任何偷偷摸摸的事情。因此,如果你正在使用谷歌 Colab(【https://colab.research.google.com】T2),你会想切换到一个 GPU,并运行你的内存真正快速使用免费的 25GB 内存升级。如果没有,嗯,你真的可以把所有这些都贴上标签,实际上只需选择相关的出版商,但这只是让你开始拥有你想要的一切。
所以让我们开始吧。
首先,让我们确保安装了 gdelt 的 python 包
!pip install gdelt
import gdelt
gd = gdelt.gdelt(version=1)
现在,我们将提取最近 60 天的 CSV,并将其保存为 python pkl,为什么不呢
#re-importing stuff from earlier in case skipped
from statsmodels.tsa.api import VAR
import pandas as pdimport osos.makedirs(“data”,exist_ok=True)import datetime
cur_date = datetime.datetime(2019,10,7)-datetime.timedelta(days=60)
end_date = datetime.datetime(2019,10,7)
while cur_date < end_date:
print(cur_date) year = cur_date.year
month = str(cur_date.month)
day = str(cur_date.day)
if cur_date.month < 10:
month = “0”+month
if cur_date.day < 10:
day = “0”+day
results = gd.Search([‘%s %s %s’%(year, month, day)],table=’gkg’,coverage=True, translation=False) results.to_pickle(“data/%s-%s-%s.pkl”%(cur_date.year, cur_date.month, cur_date.day)) cur_date+=datetime.timedelta(days=1)
所以现在 dir“data”应该包含 60 个 pkl 文件,每个文件都有一天。我们可以通过从每个文件创建一个大的 DF 来加载它们
df = pd.DataFrame()
k = os.listdir(“data”)
for i in k:
print(i)
if i.endswith(“.pkl”):
df = pd.concat([df, pd.read_pickle(“data/”+i)])
现在,万一我们弄坏了东西,我们可以把这个大 df 保存到磁盘上。我认为在这一点上看起来我占用了 6.5gb 左右的内存,保存到 PKL 会崩溃。你也可以保存为 CSV 或任何你喜欢的格式来最小化它所占用的内存,但实际上这一步只是为了加速重置,而不必再次加载所有单独的文件。
df.to_pickle(“first_60_days.pkl”)
好,让我们看看我们有什么。
print(len(df))
>>> 5250547df.head()

我们已经得到了日期,即文章的日期,NUMARTS,如果它为同一个实体提取了多个位置(现在不用担心这个),COUNTS(现在不重要),
- 日期:日期
- NUMARTS: > 1 如果多篇文章(不用担心)
- 计数:与数字相关的术语(例如 50 抗议者)
- 主题:来自 SML 大地中海的一般主题的 NLP 标签
- 位置:地点
- 人:人+人喜欢的东西
- 组织:组织
- 语气:情绪
- CAMEOEVENTIDS:用于随时间跟踪事件的一致 ID 值
- 来源:网站文章来自
- SOURCEURLS:实际文章的原始 URL
让我们快速地看一下 SOURCEURLS。这实际上是用分号分隔的,但总的来说,我们有 262,171 个不同的来源组合。
df.SOURCES.nunique()
>>>262171
我们可以把它更好的分解成一个字典
df.fillna(“”, inplace=True)from collections import Counter
def join_col(x):
big_string = “;”.join(x).split(“;”)
myCount = Counter(big_string)
return dict(zip(myCount.keys(), myCount.values()))x = join_col(df.SOURCES)
x=pd.DataFrame([x]).T.sort_values(by=0, ascending=False)
x

所以我们可以看到一些出版商。如果您希望有一个电子表格版本来标记出版商,而不是使用一个静态数组(就像我马上要使用的一样),您可以很容易地将其导出到 excel 表中:(然后您可以导入带有标记的 excel 表)
x.to_excel(“sources.xlsx”)
无论如何,我们可以选择一些随机的网站,并确保他们得到刮除
mySources = [“nytimes.com”, “washingtonpost.com”, “foxnews.com”, “cnn.com”]for source in mySources:
print("{} is {}".format(source, "good" if source in x.index else "bad"))
因此,一旦我们知道我们的网站是好的,让我们摆脱这个占据我们所有内存的巨大数据框架的大部分,只看那些我们关心的来源。
df = df[df[“SOURCES”].apply(lambda x: x in mySources)]
len(df)
>>> 44112
一个非常易管理的 44k 文章!
因此,GDELT 数据的一个问题是,有时日期被解释为 int,有时被解释为 string,所以我们将所有内容快速转换为 string,然后将其转换为 datetimes。(很容易忽略这一点,我刚刚花了一个小时试图找出为什么我的数据透视表被搞乱了,这是因为类型)。
df.DATE = df.DATE.apply(lambda x: str(x))
df.DATE = pd.to_datetime(df.DATE)
因此,现在我们可以快速查看每个出版商每天有多少文章。我们可以通过按源分组,然后忘记为什么使用数据透视表来做到这一点。
ax = df.groupby([“SOURCES”, “DATE”])[[“SOURCEURLS”]].count().unstack().T.droplevel(level=0).plot(figsize=(12,8))
ax.legend(loc=2)

Coverage over Time
我们可以立即看到出版物有一些季节性,工作日的文章量较高,周末的文章量较低。
df.groupby([“SOURCES”, “DATE”])[[“SOURCEURLS”]].count().unstack().T.droplevel(level=0).plot.box(figsize=(12,8))
我们可以看看箱线图,看看东西是如何分布的。

Boxplots
所以让我们看看不同的出版物都写了些什么!因此,如果我们想记住它们是以“;”的形式存储的,我们可以遍历并提取各个位置不连续的
我们可以在 LOCATIONS 中查找特定的国家,方法是尝试查找单个国家,如下所示:
df[df[“LOCATIONS”].apply(lambda x: x.find(“Syria”) > -1)].LOCATIONS.to_list()[0]
但是实际上不需要知道国家代码(不像主题或人物有一些 NLP 规范化);我们可以搜索一下。
所以让我们看看这些组织多久写一次关于不同国家的文章。我们可以对它们进行编码,如果它们包含我们能想到的地方:
df[“dprk”] = df[“LOCATIONS”].apply(lambda x: x.find(“North Korea”) > -1)
df[“ukraine”] = df[“LOCATIONS”].apply(lambda x: x.find(“Ukraine”) > -1)
df[“russia”] = df[“LOCATIONS”].apply(lambda x: x.find(“Russia”) > -1)
df[“iran”] = df[“LOCATIONS”].apply(lambda x: x.find(“Iran”) > -1)
df["china"] = df["LOCATIONS"].apply(lambda x: x.find("China") > -1)loc_df = df.groupby([“SOURCES”, “DATE”])[[“dprk”, “ukraine”, “russia”, “iran”]].sum()
然后我们可以继续绘制它们
fig, ((ax1, ax2, ax5), (ax3, ax4, ax6)) = plt.subplots(nrows=2, ncols=2)
fig.set_size_inches(12,8)
x=0
subplots = [ax1, ax2, ax3, ax4, ax5]
for column in loc_df.columns:
loc_df[[column]].unstack(level=0).plot(ax=subplots[x])
x+=1
plt.tight_layout()

正如我们之前看到的,我们可以对这些时间序列运行 VAR,以初步了解这些时间序列之间的相互作用。我们只看天,因为如果我们看周,我们只有 8 个数据点,不会那么好。
因此,让我们看看国家的覆盖范围是如何从一个出版商转移到另一个出版商的!一家出版商是否在某些国家领先于其他出版商?
loc_df = loc_df.unstack(level=0)
countries = ["dprk", "ukraine", "russia", "iran", "china"]for country in countries:
model = VAR(loc_df[[x for x in loc_df.columns if x.startswith(country)]], freq="d")
results = model.fit(maxlags=3)
display(results.summary())

Part of results
太酷了,所以我们看到很多出版商倾向于以这种模式效仿华盛顿邮报对朝鲜的报道。同样,他们也关注《纽约时报》关于乌克兰的报道。当然,我们还没有开始评估一个模型是好是坏,但是现在我们开始看到一些模式从数据中显现出来。
现在让我们来看看每份出版物是如何覆盖不同国家的。
for source in mySources: model = VAR(loc_df[[x for x in loc_df.columns if x.endswith(source)]], freq=”d”)
results = model.fit(maxlags=3)
display(results.summary())

Part of results
所以我们可以看到,这里也有一些相互作用。
这应该足以让人开始摆弄 GDELT 数据集了。你可以利用地点、主题和人物的互动来识别不同种类的文章,看看随着时间的推移会有什么结果。在下一篇文章中,我将看看我是否能涵盖分解,一点关于模型评估,并尝试 SARIMA 和神经网络。
抓取您自己的集:
因此,GDELT 数据很好,但它缺少文章的实际文本。它还缺少一些功能,比如作者姓名和文章在网站上的位置。对于这种事情,你可能想要维护你自己的文章来分析自己。
新闻文章可能有点难得到,但是这样做有不同的困难。守护者是。最简单的方法是使用一个 API,允许你请求每一篇文章。纽约时报也有一个 API,但是它返回所有文章的 URL 和一些标签。但是,您可以根据 URL 回到原始 URL,自己抓取文本。这类似于使用 GDELT SOURCEURLS 字段返回并获取原始文本,您也可以对其他出版物这样做。然而,有了 GDELT SOURCEURLS,出版商可以更改旧文件的 URL,所以不能保证你会得到文章。
抓取文章的一个方法是每天抓取新闻网站主页(这是可行的)。但是如果你想要过去文章的档案,你需要能够找出它们在哪里。你可以创建一个谷歌自定义搜索引擎,在白天搜索出版物中的文章,但这需要一段时间。另一种方法是在新闻网站上使用内部搜索引擎。例如《华盛顿邮报》和《福克斯新闻频道》都有内部搜索引擎,你可以搜索特定日期发表的文章,找到需要搜集的文章。
一些新闻网站就是不允许按日期搜索,在这种情况下,你可能想走自定义搜索引擎的路线。其中包括 Breitbart News、Huffington Post 或 CNN。
如果你认为你可能想要一份好的新闻报道档案,那么至少开始每天抓取主页文章是值得的,这样你就可以很好地了解新闻网站在宣传什么。新闻报道变化很快,并不总是很容易回去,找出什么是过去的报道。希望这足以让你开始!
使文本上升
我如何构建和部署机器学习 web 应用程序
我经常发现自己在阅读一篇文章,比如说关于数据科学的文章,并且想知道,在哪里可以读到关于这个主题的更简单的文章?当一个朋友在 LinkedIn 上发布类似问题时,我意识到我不是唯一一个。她问如何在最简单和最复杂之间的特定范围内找到文章。我意识到我们没有一个简单的系统来进行这种类型的搜索,除了手动阅读来寻找合适的信息。
商业理解
基于我对网络搜索的兴趣,我创建了 Text Ascent,这是一个网络应用程序,它使用无监督的 ML 来帮助用户基于文本复杂性发现内容。我希望 Text Ascent 可以成为一种工具,用于在我们学习旅程的所有阶段搜索内容。我为 Text Ascent 设定的核心目标是让人们之间更容易接触到感兴趣的小众话题。

Photo By Ted Bryan Yu from Unsplash
数据理解
我使用了 Wikipedia-API ,这是一个为 Wikipedia 的 API 设计的 python 包装器,用来收集从艺术到科学等主题的文章标题。然后,我运行了一个数据收集函数(scrape_to_mongodb.py ),该函数将这些标题和 11k+文章的摘要、全文和 URL 收集到一个 mongodb 数据库中。我排除了全文少于 300 个单词的文章,因为维基百科中有像“音乐文件”这样的条目不符合我的模型的目的。
参见数据采集笔记本 & 数据探索笔记本。
数据准备
从 Wikipedia-API 包装器返回的内容不需要进一步清理。我确实需要确保当内容显示在 web 应用程序上时,html 被读取为 JSON,以避免向用户显示回车。我使用 textstat 包的 Flesch-Kincaid 等级给每个文档的全文打分。
这些文件保存在 AWS S3 存储桶中,以允许访问 web 应用程序。参见数据准备笔记本。
建模
当前模型使用语料库向量和用户输入向量中的前 20 个重要特征之间的余弦距离来将相似内容从库中返回给用户输入。使用 TF-IDF 矢量器创建模型特征。TF-IDF 矢量器拆分语料库文档中的单词,删除停用词,并计算每个文档中每个单词的词频,根据单词在语料库中出现的频率进行调整。换句话说,不常用的词比常用的词更重要。
复制这个模型
- 获取感兴趣的文档列表,并格式化成类似于
clean_df的数据帧。使用 TextStat 获得文本难度分数。我在 AWS S3 上的例子: clean_df - 使你的语料库适合你的矢量器(从训练集中学习词汇和 idf),它是你的 df 中的文本系列我在 AWS S3 上的例子: 矢量器
- 使用矢量器转换功能(将文档转换为文档术语矩阵)来创建您的语料库向量我在 AWS S3 上的示例: 语料库向量
- 克隆此存储库
- 在
traverse_flask目录中,创建一个名为data的空子目录。 - 用
$ export FLASK_APP=app $ flask run在终端运行traverse_flask中的 flask,实现 flask app。这个瓶子app.py接受functions.py的功能。调整函数以改变后端的数据管道。调整static/templates/index.html中的 brython,改变数据反映给用户的方式。
参见模型功能。
估价
如果用户能够发现与他们已经阅读的内容相关的不同阅读难度的内容,那么这个产品就是成功的。用户满意度、重复使用、网络应用流量和应用分享是我用来评估 Text Ascent 成功的指标。在使用部署在 web 应用程序上的模型之前,我评估了 4 个模型:
- 模型 1:使用 TextStat、Gensim 和 Spacy。
- 模型 2:使用具有 10 个主题的潜在狄利克雷分配(LDA)主题建模,然后将用户内容分类到一个主题中。
- 模型 3:使用 2000 维的 TextStat 和 TF-IDF 矢量器。
- 模型 4:使用具有前 20 个特性的 TextStat 和 TF-IDF 矢量器。
每一次迭代都是为了使结果内容更类似于用户输入的内容。
未来建模
我还想将预训练的神经网络与我当前的 TFIDF 矢量化进行比较,看看返回内容的质量是否有所提高。改进将通过一个简单的手动评分系统添加到网络应用程序的用户反馈来衡量。参见评测笔记本。
部署
Text Ascent 已经作为一个支持 flask 的 web 应用【traverse.sherzyang.com 部署在 EC2 实例上(目前没有运行)。该应用程序使用 brython 在 python 函数和 html 之间进行交互。下面是来自网络应用的两张图片。给定任何用户输入文本,该模型将从库中输出相关文章,标题中有链接到完整长度的文章。用户可以从较简单的内容滚动或遍历到较复杂的内容,表格会相应地更新。


未来迭代
作为我对搜索和我们的一次性答案新世界——谢谢 Alexa、Siri 和 Google Home——的兴趣的一部分,我计划将文本提升部署为亚马逊 Alexa 的一项技能。这项技能将允许用户“滚动”或“遍历”某个主题从简单到复杂的摘要,就像告诉 Alexa 将歌曲播放得更大声或更小声一样。我相信在内容上创造选择会以积极的方式让我们超越一次性答案的世界。
此外,我渴望扩大语料库,以包括来自古滕贝格项目和其他项目的书籍。如果你想看到一些内容被添加到当前的维基百科文章库中,请在 LinkedIn 上给我发消息。我在亚马逊或 Goodreads 上见过几个给一本书的阅读难度打分的网络扩展( Read Up 就是一个很好的例子)。这些产品激励我为将来的文本提升开发一个无语料库的搜索功能。我认为当 Text Ascent 可以返回 Google 或 Bing web search API 支持的内容时,它会变得更加有用。
信用
使用 OCR 和 Elasticsearch 搜索穆勒报告
4 月 18 日标志着穆勒报告的全面发布——这份文件概述了对俄罗斯可能干预 2016 年总统选举的调查。像大多数政府文件一样,这份文件很长(448 页),读起来会非常乏味。

更糟糕的是,实际下载的 PDF 基本上只是一张图片。您不能复制/粘贴文本,或者如果您想在文档中搜索更有针对性的信息,可以使用 ctrl+f 查找文本的特定部分。
然而,我们可以很容易地使用两种伟大的技术来搜索这个文档:光学字符识别(OCR)和弹性搜索。
光学字符识别
OCR 允许我们对文本进行拍照、识别,然后将其转换为实际文本——参见维基百科上的这一描述。幸运的是,在当今时代,有许多开源库/产品来完成这项任务。

宇宙魔方就是这样一个引擎。它最初开发于 80 年代,自 2006 年以来一直是谷歌的项目,是最受欢迎的 OCR 引擎之一。今天,我们将使用 Python 包装器:pytesserac。我从这篇文章中获得了我最初的 PDF-OCR 灵感——看看吧!
弹性搜索
Elasticsearch 是一个可扩展的搜索平台,它使用类似于 TF-IDF 的算法,TF-IDF 代表词频逆文档频率。

本质上,它是一个简单的函数,经常在搜索/相似性空间中使用,根据关键字定位文档。它也不太强调频繁出现的单词。例如,因为单词“the”出现在如此多的文本中,我们不希望它被认为是我们搜索查询的重要部分。TF-IDF 在将您的查询与文档进行比较时会考虑这一点。对于它的基本概述,只需查看维基百科。
装置
你可以从网站或者你的操作系统各自的包管理器下载并安装 elastic。然后你只需要我们将要使用的所有 Python 包。
pip install elasticsearch
pip install pdf2image
pip install pytesseract
OCR 文本提取
首先,将穆勒报告下载到您的主机。然后,我们可以创建一个快速函数,使用 pytesseract 和 pdf2image 库从 PDF 中逐页提取文本。
注意,我设置了默认值num_pages=10。这是因为这份报告真的很长,在你的个人电脑上,从每一页提取文本可能要花很长时间。此外,如果您不打算将本地 Elasticsearch 索引部署到云上,那么它也是大量数据。不过,您可以随意将该参数更改为您选择的任何值。
但是不管怎样,当我们在 PDF 上运行这个函数时,我们现在有了所有 PDF 页面的文本和页码!这是一个字典列表(json ),对于 elastic 来说,这是一个很好的入口,可以让它被搜索到。
弹性研究索引
你需要做的第一件事是确保 elastic 运行在正确的端口上。打开一个终端,启动 elastic(如果在你的$PATH里面,应该就是elasticsearch)。默认情况下,这将在端口 9200 上启动服务。
之后,我们可以很容易地使用 Python 客户机与我们的实例进行交互。如果 elastic 在端口 9200 上运行正常,下面的代码应该创建索引mueller-report,它有两个字段:text和page(它们对应于我们在前面函数中的字典键)。
搜索我们的索引
我不会深入细节,但是 elastic 使用一种叫做 query DSL 的语言来与索引交互。您可以对它做很多事情,但我们在这里要做的只是创建一个将我们的查询矢量化的函数,并将其与我们的索引中的text进行相似性比较。
res将是一个 json,包含我们搜索的一系列信息。实际上,我们只想要相关的结果。所以一旦我们实际调用了这个函数,我们就可以解析 json 来获得最相关的文本和页码。
这样,我们的搜索功能在页面文本中查找“司法部”,并返回结果。上面语句中的[0]只是为了查看第一个最相关的页面文本和编号。但是,您可以定制解析,以便它返回您喜欢的少/多的结果。

使用基巴纳前端
实际上,我们可以使用另一个弹性工具来更好地查看我们的结果,而不是查看我的 jupyter 笔记本中记录不佳的 gif。Kibana 是 elastic 的开源前端,非常适合可视化。首先,从这个链接安装 kibana。

一旦你安装了 Kibana,在终端中运行kibana启动服务,然后在你最喜欢的浏览器中导航到localhost:5601。这将允许您与应用程序进行交互。
在与索引交互之前,我们唯一要做的事情是创建一个索引模式。转到 Management > Create Index Pattern,然后输入“mueller-report”——ki Bana 应该会让您知道该模式与我们之前在 elastic 中创建的索引相匹配。

就是这样!如果你转到左边的 Discover 标签,你可以用一种比我们在 elastic 更容易(也更美观)的方式搜索你的索引。

后续步骤
把它放在 AWS 上可能会很酷,这样任何人都可以使用它(有一个更好的前端),但我现在真的不想把我的信用卡绑定到那个实例上。如果其他人想,请自便!我将很快更新 docker 容器和 github 链接。
更新
2019 年 4 月 21 日—Mueller Report 上有很多关于 OCR 和后续 NLP 的帖子/工作。似乎主要关注的是 OCR 文本的实际质量,因为由于格式或一般的不准确性,结果可能是混乱的。虽然可能没有简单的方法来解决这个问题以供未来分析(除了政府发布了一份有用的文件),但我们至少可以通过在我们的搜索功能中添加一个fuzziness参数来弹性补偿我们搜索中的任何拼写错误。
这是一种粗略但通用的方法,可以解释我们可能在 OCR 后的文本中发现的一些错误。
使用机器学习的恶意软件分类
实施微软恶意软件分类挑战(BIG)的收获

Image Source : Kaggle
如果你喜欢探索大型和具有挑战性的数据集,那么也许你应该试试微软的恶意软件分类。在深入探讨这个问题之前,让我们先来看看你能从中学到什么:
- 如何处理大规模数据? 列车总数据集由 200 GB 数据组成,其中 50 GB 数据为。字节的文件和 150 GB 的数据。asm 文件。
- 应该做什么特色工程?如果到目前为止你一直只处理文本和图像数据,这肯定会提高你对特征工程的直觉。
- 在没有领域知识的情况下,如何逼近一个机器学习问题? 用本次挑战赛第一名获奖者的话说:“交叉验证比领域知识更值得信任”。
业务问题
在过去几年中,恶意软件行业发展非常迅速,辛迪加在技术上投入大量资金来规避传统保护,迫使反恶意软件团体/社区构建更强大的软件来检测和终止这些攻击。保护计算机系统免受恶意软件攻击的主要部分是识别给定的文件/软件是否是恶意软件。
机器学习问题、KPI 和约束
我们可以将业务问题映射为多类分类问题,其中我们需要预测九个类别( Ramnit、Lollipop、Kelihos_ver3、Vundo、Simda、Tracur、Kelihos_ver1、Obfuscator)中每个给定字节文件的类。ACY,加塔克。
KPI:多类日志损失,混淆矩阵
约束:我们需要提供分类概率,错误分类的分类标签应该受到惩罚(这就是为什么 log loss 被选为 KPI)并且应该有一些延迟限制。
处理大尺寸
考虑到数据的规模,建议使用云平台,如 GCP、AWS 或 IBM Cloud。我们在 GCP 完成了这个案例研究,使用基于 Linux 的 1vCPU 机箱,配备 30 GB RAM 和 500 GB HDD。点击此链接了解如何借助 CurlWidget 在 GCP 直接从 jupyter 笔记本上下载数据。下载数据后,下一个挑战将是使用 python 提取这些文件,因为 python 对 7z 文件的支持是有限的。使用名为“p7zip”的软件包,它提供了一个 Linux 命令行工具来提取 7z 文件。
# command to install the package in Linux
sudo apt-get install p7zip-full
# Sample Command to extract the data from terminal
7za x yourfile.tar.7z
数据的关键点
- 总数据集由 10,868 个组成。字节文件和 10,868 个 asm 文件总共有 21,736 个文件。字节文件由 256 个十六进制数字(十进制值范围为 0 到 255)和一个特殊字符(??).Asm 文件是使用智能编译器获得的汇编文件。
- 数据集不平衡。

Distribution of malware classes
关键特性
这个案例研究的好处是,它需要大量的耐心和实验来获得有用的特性。基于我们的直觉和之前在这个领域的工作,我们尝试了以下特性
- 字节文件的 n-gram 特性:我们尝试了单字、双字和三字特性。虽然这些特性的性能很好,但是主要的挑战在于处理它们的大维数。一元语法的特征数是 256,二元语法的特征数是 65531,三元语法的特征数留给你的练习。即使有 30 GB 的 RAM,也不可能加载 65531 个特性的全部数据,所以我们选择了块中的 SVD。首先,我们使用随机样本和 3000 个特征尝试了 elbow 方法,以检查保持方差所需的组件数量,我们发现 1000 是一个好数字。

Elbow method to choose number of components

Code to extract bi-gram features using SVD in chunk
2.字节和 asm 文件的大小:字节和 asm 文件的大小被证明是很好的特性。让我们来看看文件大小的箱线图

3.字节数组的大小:正如我们前面提到的,字节文件由十六进制数字组成。对于每个文件,我们都有一个数组,并将每个元素添加到数组中,并使用这些数组的长度作为一个特征。
4.ASM 文件的段计数和 n-grams:ASM 文件由不同的段组成,如前缀(例如。标题、文本)、操作码(例如 jmp,hlt),关键词(例如。。dll,std:😃,寄存器(例如。edx、epi)等。我们将片段的计数作为一个特征。我们还考虑了 asm 文件的一元、二元和三元模型作为特征。
5.像素强度的字节和 asm 特征:这可能是本案例研究中最具创新性的特征。我们借用了第一名获胜者解决方案的概念。正如我们前面提到的,字节文件中每个元素的值在 0 到 255 之间。我们可以很容易地将这些字节文件和 asm 文件一起转换成灰度图像。据观察,asm 文件的前 800 个像素密度对最终结果有显著影响。

Code to convert asm files to image files
让我们看一下随机 asm 文件在转换后的样子

Random image from converted asm files
降维和特征选择
到目前为止,您一定已经观察到了特征的维度,并对用于训练的最终特征的维度有所了解。为了解决这个问题,我们使用随机森林来选择重要的特征。重要特性的数量是一个超参数。根据我们的经验,我们尝试了各种数字,显然还有改进的余地。让我们看一个样例代码,看看我们是如何选择最好的三元语法 asm 特性的。我们还尝试了 t-SNE 多变量分析。


系统模型化
我们已经尝试了各种线性机器学习模型,如 KNN、多类逻辑回归和具有各种功能组合的集成,如随机森林、XGBoost 和 LightGBM。我们用单一特征以及字节特征和 asm 特征的组合来训练模型。我们还在从 byte 和 asm 文件获得的图像上尝试了各种 CNN 架构,但与微调的机器学习模型相比,获得的结果较差。由于我们没有恶意软件行业的任何领域知识,我们完全依赖交叉验证。由于特性和文件的数量很大,我们选择了 RandomizedCV 进行交叉验证,并且还有改进的余地。你可能会想到另一个问题,为什么我们同时使用 XGBoost 和 LightGBM?实际上,我们已经从 XGBoost 开始,但是发现 LightGBM 的训练延迟比 XGBoost 低得多,并且性能相似或更好。我们从一个随机模型开始,然后在关注性能后逐渐增加模型的复杂性。
结果
最后,如果一个用例不能提供令人满意的结果,它就没有任何价值。在这里,我们只列出校准最终 LightGBM 模型后得到的结果。


Confusion Matrix

Precision Matrix

Recall Matrix
引文
- http://arxiv.org/abs/1802.10135
- https://www.kaggle.com/c/malware-classification/overview
- https://www . Kaspersky . co . in/resource-center/threats/malware-classification
- https://ieeexplore.ieee.org/document/8553780
使用深度学习的恶意软件检测
fast.ai 中使用卷积神经网络的恶意软件检测

Photo by Markus Spiske on Unsplash
什么是恶意软件?
恶意软件是指恶意软件犯罪者派遣感染个人计算机或整个组织的网络。它利用目标系统的漏洞,如合法软件(如浏览器或 web 应用程序插件)中可能被劫持的漏洞。
恶意软件的渗透可能是灾难性的——后果包括数据盗窃、勒索或网络系统瘫痪。
为什么检测恶意软件很重要?
恶意软件是当今互联网上最严重的安全威胁之一。事实上,大多数互联网问题,如垃圾邮件和拒绝服务攻击,都有恶意软件作为其根本原因。也就是说,受到恶意软件危害的计算机通常联网在一起形成僵尸网络,许多攻击都是利用这些恶意的、攻击者控制的网络发起的。
为了应对新产生的恶意软件,需要新的技术来检测它们并防止它们造成的任何损害。

为什么要深度学习?
如今,深度学习已经主导了各种计算机视觉任务。这些深度学习技术不仅使这场比赛取得了快速进展,甚至在许多比赛中超过了人类的表现。这些任务之一是图像分类。
与更传统的机器学习技术方法不同,深度学习分类器是通过特征学习而不是特定于任务的算法来训练的。这意味着机器将学习呈现给它的图像中的模式,而不是要求人类操作员定义机器应该在图像中寻找的模式。简而言之,它可以自动提取特征,并将数据分类到各种类别中。
早期层学习如何检测边缘等低级特征,后续层将早期层的特征组合成更全面和完整的表示。
我们可以使用后面描述的方法将恶意/良性文件转换成灰度图像。然后我们可以对生成的图像应用这些深度学习技术,将它们分类为恶意软件或良性软件。
如何创建恶意软件映像?

为了使用深度学习模型对图像进行分类,我们需要来自良性和恶意文件的图像。我们只做二元分类(恶意类和良性类)。多类分类也可以使用这种技术来完成,其思想是恶意软件文件的变体将具有不同于其他的图像。
准备好数据集后,我们将通过对每个图像执行以下步骤,将每个文件转换为 256x256 灰度图像(每个像素的值在 0 到 255 之间):
**Step 1:** Read 8 bits at a time from the file.
**Step 2:** Treat the 8 bits as a binary number and convert it to its corresponding integer.
**Step 3:** Enter the number as the pixel value.
最大 64 KB 的文件可以容纳 256 x 256 的图像。任何大于 64 KB 的文件,其剩余内容都将被删除。
另一方面,如果文件的大小小于 64 KB,剩余的图像将用 0 填充。
由于恶意软件检测是实时进行的,我们需要在几秒钟内将图像分类为良性或恶意软件。因此,保持图像生成过程简单而简短将有助于我们节省宝贵的时间。
数据集的准备
这一步极其简单。所有图像生成后,将它们分成两个文件夹——训练和验证。这些文件夹中的每一个都包含两个文件夹,即恶意软件文件夹和良性文件夹。
将这两个文件夹存储在另一个名为“dataset.tar”的文件夹中,压缩生成一个. tar 文件。
所以最终的目录结构将是→
dataset.tar 包含验证和训练。验证将有恶意文件夹和良性文件夹。火车将有恶意和良性的文件夹。
将压缩文件夹移动到包含代码的 Jupyter 笔记本所在的目录中。
实施模型
** 这个问题使用的模型是按照 fast.ai 课程的第 1 课(宠物分类)创建的。 **
要从 Google Drive 中读取数据集,请添加以下代码行
!pip install PyDrive #import os
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentialsauth.authenticate_user()
gauth=GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)
一旦你运行了上述代码的最后 4 行,Google SDK 会要求你输入一个验证码。它会提到一个链接,一旦你点击它,你会得到你的安全代码。
link = '1sL4I4xNh657AhrIOOwbr6TX58ahyC'(add the link here )
创建一个变量,该变量包含到。tar 文件包含的数据存储在您的谷歌驱动器。要获取网址,请打开。tar 文件并获取该文件的可共享链接。你不需要整个 URL,只需要它的一部分。所以比如你的可分享链接是“https://drive . Google . com/File/d/1 sl 4 i4 xnh 657 ahrioowbr 6 tx 58 ahyc/view?你只需要粗体部分。
获取数据路径
downloaded = drive.CreateFile({'id':link})
downloaded.GetContentFile('dataset.tar')
import tarfile
tar = tarfile.open("dataset.tar")
path = tar.extractall('DS/')
tar.close()
path = Path.cwd().joinpath("DS/dataset/")
path.ls()data = ImageDataBunch.from_folder(path, ds_tfms=get_transforms(), size=224)## To view data in a batch
data.show_batch(rows=3, figsize=(7,6))
## To know the number of classes in a dataset
print(data.c)
## To know the names of the classes in a dataset
print( data.classes)
创建模型
learn = create_cnn(data, model.resnet34, metrics = error_rate)## To know the model architecture
learn.model## Training the model
learn.fit_one_cycle(4)
learn.fit_one_cycle(10)
下面是我运行上述代码后得到的输出截图:

Output for 4 and 10 epochs.
interp = ClassificationInterpretation.from_learner(learn)
losses,idxs = interp.top_losses()
interp.plot_top_losses(9,figsize=(9,6))

The images with maximum losses.
如何找到并设定一个好的学习率?
到目前为止,我们还没有告诉我们的模型在训练模型时使用什么学习率,我们都知道这是训练时最重要的超参数之一。
为了找到一个好的学习率,请执行以下操作:
learn.lr_find()
learn.recorder.plot()

Finding an optimal learning rate.
learn.fit_one_cycle(5, max_lr=slice(1e-6,1e-4))## Saving the weights of the model
learn.save('stage-1-malware-detection')

Losses are much less compared to before.
注意:每次调用 fit_one_cycle()函数时,权重都不会重新初始化。因此,如果您一个接一个地调用该函数,则历元会累加,这意味着如果您调用 fit_one_cycle(5)然后调用 fit_one_cycle(10 ),则该模型已经被训练了大约 15 个历元。
完整的代码可以在我的 GitHub 账户上找到,链接这里。这些只是代码的一小部分,仅仅遵循它们不会给出可行的代码。
如有任何建议/改进/讨论,请随时联系我们。😄
未来的工作
- 我们可以尝试将数据分为不同类型的恶意软件或良性类别,而不是执行二元分类。
- 我们可以尝试不同的技术来创建一个验证集。在这个阶段,不同类别中的图像以及验证集和训练集中的图像数量是随机选择的。
- 在我们的训练数据集中,尝试恶意软件文件数量与良性文件数量的不同比率。(几乎 1:1 使用)
- 尝试不同的维度来生成恶意软件图像。(使用 256x256)
我认为你会喜欢:D 的其他文章
我很高兴你坚持到了这篇文章的结尾。🎉我希望你的阅读体验和我写这篇文章时一样丰富。💖**
请在这里查看我的其他文章。
如果你想联系我,我会选择推特。
管理地理数据:ISO3166、联合国/地方编码和地名

最近,我需要定义一个数据模型来处理国际级别的地理数据,即,当您的潜在地址在全球任何一个地方时,如何正确管理有关邮政地址的数据。下面是我在处理将地理数据整合到应用程序和数据库时发现的挑战和备选方案的结果。
地区混乱的挑战
当你研究国家是如何组织起来的,你会发现不同的标准,有时地区是相当无形的,很难证明,尤其是在欧洲国家。

仅举一个例子来说明两个国家之间的方法有多么不同:
让我们先来关注一下美利坚合众国,人口 3.25 亿,面积 9525067 平方公里,GDP 20.513 万亿美元。用户使用简单有效模式:
一个国家,27 个州。
第一个和第二个行政命令之间有明确的划分。
现在我们来看看欧元区第四大经济体西班牙,既不是主要国家之一,也不是小国家。人口 4600 万,面积 505990 平方公里,GDP 1.864 万亿美元。这是一个过度复杂的组织的例子:
一个国家,17 个自治区,2 个自治市,50 个省,8124 个直辖市。
由于一些人可能会立即指出,这两个国家决不是可比的(尽管它们是国家,所以它们应该是可比的),我们将只分析美国的一个州。
我们会选择德克萨斯州:它在外延上略大于西班牙,拥有 2600 万人口,GDP 与西班牙相似(1.639 万亿美元)。
得克萨斯州在行政上划分为 254 个县。
同样,这并不复杂,这是一个基本而简单的管理。
美国的邮政地址不需要二级行政级别。他们只是使用国家,因为国家被认为是基本的主要行政单位,这就相当于在西班牙不使用自治区(更不用说省了)。
在某些欧洲国家,这种过于复杂且昂贵的地区行政管理模式很常见。分析的例子并不是唯一的,你可以找到其他国家,如法国有类似的情况。
协调邮政数据
如果您需要处理国际数据,了解一些有用的国际标准可能会有所帮助。
一般来说,每当你必须处理大量参考数据时,最好先检查是否有国家或国际标准。您不仅会找到协调数据的最佳方式(我说的是最佳,而不是完美),而且还会更容易找到主数据来填充和更新信息。
如果有人抱怨数据,你还可以争辩说使用了国际标准。通过这种方式,你只需要为用户提供一种方法,让他们可以将自定义数据与自己的想法混淆起来,即如何在地图上放置或命名重要的本地区域。
这里的要点是,处理邮政数据是一个永远不会让所有人都满意的场景。考虑到这一点,遵循国际公认的标准并实现一个允许用户进行更改的接口,就大功告成了。用户现在是数据的所有者(理应如此)。
在这个前提下,我们将研究您可以使用的标准,并回顾每种标准的优缺点。
ISO 3166–1 国家
如果你需要一个编码系统和一个国家列表,不用再找了:ISO 3166–1是你的朋友。

Alpha-2 Codes ISO3166–1
由于世界上没有那么多国家,除了少数有争议的名字,这是一个独特的、确定的名单。
我喜欢使用 Alpha-2 代码来查找和填充列表。请记住,一旦您在合并记录中使用国家(如已开具的发票),您应包括代码和名称,因为将来可能会有变化。
提示:在用户界面中总是使用表格查找的代码,而不是存储代码本身。在最终文档中存储永久值将反映文档或注册发布时的当前名称;这将使您的数据库对未来的变化具有鲁棒性,并将您从处理历史数据中解放出来。
另一种选择是为条目使用 GUIDs/uuid/IDs,并让一个活动的列反映该特定记录是否停止。在这个列表上维护潜在的更新和保持对过去变化的准确跟踪是相对容易的。但是,我不喜欢这种方法,因为最终您会保留旧信息,并使主数据维护和迁移变得更加困难。
对于信息本身,实际的标准可以在这里买到,虽然信息可以从不同的来源免费获得,比如维基百科。
提示:如果您正在处理一个涉及历史数据集(如宏观经济学)的数据分析项目,并且由于某种原因,您必须包括关于已灭绝国家的信息,请记住,ISO3166–3 为您提供了一个现已灭绝国家的列表,如苏联或南斯拉夫。
ISO 3166–2 个州/省
如导言中所述,对于第二级行政机构来说,情况并不那么容易(有些国家确实有第三级行政机构,即使没有实体或扩展机构要求这样做)。
这里的最佳选择还是 ISO3166-2。您将在这里找到第二和第三个管理级别。

ISO3166–2:FR
同样,你可以购买官方标准,也可以免费使用维基百科中的信息。
为了正确地处理信息,您可以使用这个 PHP 解析器轻松地删除信息。
Python 和 Java 对 ISO-3166 的支持
如果你使用 Python,有一个名为 PyCountry 的非常好的包,它已经包含了为你解析的信息。
在 Java 中,我没有发现任何类似的东西,尽管我个人认为这种信息应该在数据库级别进行管理,所以您可以使用上面的 Python 包创建相关的 CSV,并将它们导入到您的 Java 应用程序中。
UN/LOCODE
一种替代方法是处理来自欧洲经委会的信息。这不仅包括 ISO3166 的分支机构和国家,还包括世界上许多城市的地理位置(包括坐标)。虽然它并不完整(你不会发现每个城市都有一对一的任务),但它提供了额外的信息。它侧重于运输,因为它包括码头、火车站和国际航空运输协会代码等运输设施的可用性信息。

UN/LOCODE Provides information about trading/transportation locations
[## ISO 3166-2 -贸易-欧洲经委会
该表按字母顺序列出了…的国家名称(英语中的官方简称,如 ISO 3166)
www.unece.org](http://www.unece.org/cefact/locode/subdivisions.html)
城市和邮政编码
州和省有点困难(试着弄清楚在法国用什么),所以屏住呼吸,现在考虑如何处理城市和邮政编码。可用城市的数量激增,但在您开始恐慌或考虑使用城市和邮政编码的空文本字段之前,请注意有一个非常体面和简单的解决方案:GeoNames 项目。
[## 地名
GeoNames 地理数据库涵盖所有国家,包含超过 1100 万个可用的地名…
www.geonames.org](https://www.geonames.org/)
GeoNames 是一个广泛使用的、完全免费的全球位置数据库,包括它们与 ISO3166-2 的第二/第三行政级别和邮政编码的关系。
在不集成其他外部服务的情况下,这是您所能做到的最大限度。
要探索的其他选项
经过我的研究,我想知道谷歌地图 API 是否可以成为集成地址搜索功能的一个选项。如果你不得不在街上交易,这可能是一个好的选择。在我的特定场景中,这不是一个需求,所以我决定继续使用 GeoNames(它可以提供不需要与外部系统在线集成的功能)。
在这种情况下,一个好的选择可能是查询国家数据库。大多数发达国家和半发达国家将依靠免费信息,无论是在线服务还是可下载的数据库。
使用 pyenv 管理虚拟环境
大多数 Python 开发人员和数据科学家都已经听说过虚拟环境。然而,管理为不同项目创建的数十个环境可能会令人望而生畏。pyenv 将帮助您简化虚拟环境的创建、管理和激活。
过去,在 virtualenv 流行之前,我会为所有 Python 项目保留一个全局工作空间。每当我安装或升级其中一个库时,它就可以立即用于所有的项目。通常情况下,它会破坏其中的一些项目…
虚拟环境的主要优点是它们为您的每个项目构成了一个单独的工作空间(virtualenv)。安装在这些工作区中的包不会互相干扰,因此您可以安全地安装、升级或删除库,而不会影响其他项目。
pyenv 是 virtualenv 的扩展,增加了一些好处:
- 有可能相邻安装几个 Python 解释器版本(例如 2.7 和 3.8 甚至 PyPy),
- 用户安装的解释器和系统 Python 的和平共存,
- 用于管理虚拟环境的集中式系统,
- 切换到项目文件夹时自动激活虚拟环境。
安装 Python 解释器📜
让我们先来看看主要特性。如果你想亲自尝试一下,请阅读博文末尾的安装指南。
要创建一个虚拟环境,首先需要确保安装了合适的解释器。您可以从列出的可用解释器中进行选择:
pyenv install --list
(你可以用cd $(pyenv root) && git pull更新这个列表)然后安装其中一个:
pyenv install 3.8.0
要激活新环境并开始使用 Python 3.8.0:
pyenv shell 3.8.0
python
这将打开 Python 提示符,并显示熟悉的欢迎屏幕:
Python 3.8.0 (default, Oct 20 2019, 18:15:07)
[GCC 9.1.0] on linux
Type “help”, “copyright”, “credits” or “license” for more information.
>>>
这些都很好,但是除非你还停留在 90 年代,否则你会更喜欢像 notebook 或 IPython 这样的现代 Python 接口。如果有,请继续读下去!
创建虚拟环境💻
到目前为止,我们已经安装了基本的 Python 解释器和标准库。然而,为了让我们的数据科学环境完全发挥作用,我们需要安装数据科学堆栈中的基本包,如 Jupyter、matplotlib 或 pandas。
通常情况下,您的项目将依赖于特定版本的包(这不是最佳实践,但是一些 Python 库比我们的项目运行得更快)。为了隔离一个项目所使用的包,我们可以使用虚拟环境。您可以使用pyenv-virtualenv扩展创建一个(参见下面的安装说明):
pyenv virtualenv 3.8.0 my-data-project
你可以给环境命名(这里,my-data-project),因为它适合你。要激活环境类型:
pyenv shell my-data-project
现在您已经准备好安装您想要使用的库了。您可以从标准 Python 包存储库(PyPi 也称为 cheese shop)中提取它们,并使用pip命令安装在当前环境中:
pip install jupyter notebook matplotlib pandas
最好只安装您将在项目中使用的库。如果以后你意识到少了什么,你仍然可以用pip install添加包。现在,让我们启动笔记本服务器:
jupyter notebook
这应该会在浏览器中打开 Jupyter 笔记本界面。干得好!您刚刚安装了运行在最新最棒的 Python 版本中的 Jupyter🎉!一定要尝试它的一些新特性,比如 Walrus 运算符或 f 字符串表达式。
您还可以使用pyenv versions列出您的系统上安装的所有 Python 版本和环境,它应该会打印出如下列表:
system
3.8.0
3.8.0/envs/my-data-project
system环境是您的默认系统 Python(随您的操作系统一起安装)。另外两个是用 pyenv 创建的。
自动激活环境🚀
没有什么比在安装了额外的库之后才意识到没有激活正确的虚拟环境更令人沮丧的了。这肯定会覆盖当前激活的环境中安装的旧版本的包,并可能破坏您的项目代码。pyenv 的独特优势在于它可以为每个项目自动激活正确的环境。假设您的主目录中有一个名为predict-prices的项目目录。要为项目类型选择虚拟环境:
cd ~/predict-prices pyenv local my-data-project
(以项目命名环境是很常见的,为了避免混淆,我在这里对项目目录和环境使用了两个不同的名称)。
下一次,当您在 shell 中切换到包含项目文件的目录(或其中一个子目录)时,pyenv 将为您激活正确的环境!
请注意,如果您之前使用pyenv shell.激活了环境,自动激活将不起作用
在 IDEs 中使用您的环境
如果你不喜欢,你也可以在你喜欢的 IDE 中使用 pyenv。许多编辑器和 ide 都知道 pyenv 环境,并将为您检测它们。然后,您将能够从下拉菜单中选择当前工作区的环境。

Selecting virtual environment in VS code
但是 pip 只针对 Python 包…
虽然pip主要针对安装 Python 包,但也可以安装其他语言的软件。许多 Python 库包含一些用 C 或类似语言编写的代码。例如,numpy 中的数组在 c 中实现了性能关键的操作。在你的机器上安装这些包时,pip可以编译这样的扩展,但是它需要开发者工具(编译器、连接器、构建工具、头文件)的可用性。然而,现在大多数库也为您的平台(Linux、OSX、Windows)提供二进制文件(编译的代码),打包成一种叫做wheel的格式,可以直接从包库中取出,不需要任何编译。
为什么不是康达?🐍
conda 是数据科学家喜欢的另一个伟大的 Python 包管理器。在很多方面类似于 pyenv + virtualenv + pip combo。它提供了一个丰富的官方软件包库和一个名为conda-forge的用户贡献软件包库。如果这些存储库中没有某些包,您仍然可以使用pip来安装它们。conda 的优势在于它是多平台、语言无关的,并且提供所有必要的构建工具和共享库。缺点是它需要安装一个名为miniconda的独立库。好消息是,在 pyenv 中安装 miniconda 就像在基于 pip 的环境中一样容易:
pyenv install miniconda3-latest
装置
要安装 pyenv,只需遵循几个简单的步骤。首先,将 pyenv git 存储库克隆到您的主目录(pyenv 仅支持 OSX 和 Linux,在 Windows 上您需要使用 Windows 子系统 for Linux ):
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
然后将 pyenv 添加到您的系统路径中:
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.bash_profile
复制粘贴以上几行应该就可以了,但是如果你需要更详细的解释,请查阅官方指南。
我还使用 pyenv 的扩展来管理虚拟环境,称为 pyenv-virtualenv。要安装它,只需克隆 git 存储库:
git clone [https://github.com/pyenv/pyenv-virtualenv.git](https://github.com/pyenv/pyenv-virtualenv.git) $(pyenv root)/plugins/pyenv-virtualenv
要启用自动激活,请将此命令复制到您的终端:
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile
现在,您可以从您的会话中注销,然后再次登录,以便将所有内容设置到位。
流形和神经活动:导论

流形是数学和物理中的重要对象,因为它们允许用更简单的空间来表达和理解更复杂的结构。这是将该理论与神经科学联系起来以理解和解释复杂的神经活动的关键动机。
T he 流形假设陈述了真实世界的数据(图像、神经活动)位于被称为流形的低维空间中,这些流形嵌入在高维空间中。松散流形是局部看起来像欧几里得空间的拓扑空间。为了给流形一个简单的例子,并理解前两个句子,考虑一个球。球体不是欧几里得空间,因为我们不能用直线连接两点,而是需要测地线的概念,但是局部欧几里得几何定律是很好的近似。例如,地球可以近似为一个球体。你不是生活在一个球体上,而是生活在一个平面上。所以我们可以说我们“生活”在一个流形上。我希望这能给术语流形的含义一点直觉。**
流形本身属于拓扑学和微分几何的数学分支。它们存在于任何维度的空间中,但是为了简单起见,为了更直观,我们在这里只考虑三维空间。
在这篇文章中,我不想深入探究它背后的数学,而是探索它在神经科学中的相关性,以及如何利用它从神经活动数据中获得更多见解。如果你对流形的更深入的数学解释感兴趣,你可能会觉得这篇文章很有趣。
为什么我们对神经活动中的流形感兴趣?
最近,神经系统的许多研究正在经历从单个神经元到群体水平的假设和分析的范式转变。大脑中的网络由成千上万的神经元组成。我们可以预期,一个网络的自由度的数量和它的神经元的数量一样大。然而,研究【1】显示了实验证据,表明局部大脑活动被限制在由几个变量跨越的子空间(低维流形)中。
出现的一个关键问题是,除了单独研究每个神经元之外,通过研究这些被记录的神经元群体还能获得什么科学见解。事实上,当它们的活性被平均化时,单个单元通常不显示任何刺激特异性。这就是多重假说的由来。我们希望找到在单个神经元水平上不明显的结构(或特征)。此外,简单地平均许多神经元的响应可能会掩盖重要的信号,因为神经群体在其细胞类型、投射目标等方面通常具有巨大的多样性。【第二】。
在计算神经科学中,流形假设认为,潜在的网络连通性限制了神经群体活动的可能模式,并且这些模式被限制在一个低维流形中,该流形由几个独立变量跨越,我们可以称之为“神经模式”【3】。 盖莱戈等人。艾尔。 进一步说明
“这些神经模式捕获了人口协方差的重要部分。正是这些神经模式的激活,而不是单个神经元的活动,提供了神经动力学和功能的基本构建模块。”
为了识别这些神经模式,我们需要应用一些降维方法来计算高维神经活动的低维表示。
降维背后的直觉
在这里,我不会深入探讨像主成分分析(PCA)这样的特定类型的降维方法,而是会提供一个基于【4】的一般直觉。如果你对 PCA 更深刻的解释感兴趣,请看这篇写得很好的博文。
通常,我们对有 D 个测量变量的数据进行降维,并且我们怀疑这些变量可以通过更少数量的“解释性”变量 K 来更好地表示(或理解)。我们如何提取这些解释变量取决于选择的方法。由于人们不能直接观察到这些变量,它们被称为潜在变量。我们试图以描述我们数据的统计特征来结束,并把我们数据的某些方面作为噪声排除。
在神经科学中,变量 D 通常对应于观察到的神经元数量。由于这些神经元跨越了一个基础网络,因此很可能不是相互独立的,可以假设我们只需要一小部分的潜在变量来解释它们的网络活动。下面是一个思考这些潜在变量的好方法:
“潜在变量可以被认为是共同的输入,或者更一般地说,可以被认为是未被观察到的神经元在与被记录的神经元相同的网络中的集体作用。”
我们通常测量的是一个神经元发出的动作电位的时间序列。在神经科学中,这通常被建模为泊松过程。降维的目的是描述不同神经元的放电频率是如何协变的(并排除作为噪声的尖峰变化)。每一个神经元都提供了由潜在变量捕获的同一潜在过程的不同视图。潜在变量定义了一个 K 维空间,表示在群体反应中突出的共享活动模式。
下一部分将提供一个这样的例子,以及我们如何使用这些潜在的属性来建立一个基于神经模式激活的单个神经元活动的生成模型。
神经流形

Figure 1: (A) Activity of each recorded neuron is a weighted combination of the time varying activation of the neural modes. (B) Trajectory of time-dependent population activity in the neural space spanned by three recorded neurons (red). This trajectory is mostly confined to the neural manifold which is a plane shown in gray and spanned by the neural modes (green and blue vector). (This Figure is adapted from [3])
如上所述,最近的实验工作表明,神经功能可能建立在我们称为神经模式的特定群体活动模式的激活上,而不是建立在单个神经元的独立调节上。为了估计这些神经模式的数量,我们对记录的群体活动应用了类似 PCA 的降维方法。获得的一组神经模式现在定义了一个神经流形。这个流形可以被认为是一个表面,它捕获了记录的活动数据中的大部分差异,参见图 1(B)中的灰色超平面。神经模式的时间相关激活被称为它们的潜在动力学。每个神经元的活动被表示为来自所有模式的潜在动力学的加权组合,见图 1 (A)。
为了让我们刚才说的更清楚一点,把每个神经元想象成一个 N 维状态空间中的一个轴,每个轴对应一个神经元的放电频率。某个时间点的活动对应于该空间中的一个点,神经元活动的时间演化构成了一个轨迹[1]。现在,轨迹(图 1 (B)红线)倾向于被约束到这个状态空间的一个线性子空间(神经流形)而不是在所有方向上自由移动(图 1 (B)灰线)。
每个神经元可以参与一个或多个神经模式,并且神经模式包括群体活动中的大部分神经元。在图 1(B)中,描绘了三个神经元的神经空间(或状态空间)。同样,每个轴代表一个神经元的活动。我们之前提到过,网络连通性限制了群体活动的可能模式,这意味着群体动力学不会探索完整的高维神经空间,而是会保留在低维表面“神经流形”中。在我们的(简单)例子中,这个流形是由两个神经模式 u1 和 u2 跨越的平坦超平面。
神经模式可用于建立实际神经活动的生成模型[3]。我们可以将每个神经模式与一个潜在变量相关联,这样任何时间点的神经活动都是由相应潜在变量加权的神经模式的总和,图 1 (A) [1]。
这些神经模式现在可以用来描述特定任务的神经流形,例如运动皮层[5]。
结论
科学的主要追求是用简单的术语解释复杂的现象。降维使我们能够在群体水平上研究神经元,而不是平均群体反应或单独研究每个神经元。神经模式跨越一个低维流形,其中神经活动受到限制,允许检测网络中的模式。
此外,神经模式及其潜在的动力学提供了对整个大脑许多区域功能的更多了解,这些了解在单个神经元水平上并不明显[【5】](http://A stable, long-term cortical signature underlying consistent behavior)。
尽管如此,在这个研究领域仍有一些悬而未决的问题。例如,神经流形的概念不限于平面。神经流形可能是神经空间内的非线性表面。对于动力学探索神经空间的更大区域的复杂行为,线性方法可能是糟糕的估计,我们需要非线性方法,例如 IsoMap 。
请注意,本文中讨论的研究集中在与某些特定任务相关的神经流形上。另一个问题是不同的流形如何在神经空间内相互组织。
我希望这篇文章让你对什么是神经流形假说有了第一印象。为了进一步阅读,我推荐我在本文中引用的论文。
参考
[1]“扰乱脉冲神经元网络中的低维活动流形”,e . rnberg,A. Kumar
[2]“概念和技术进步为理论神经科学定义了一个关键时刻”,A. K. Churchland,L. F. Abbott
[3]“运动控制的神经流形”,J. A. Gallego,M. G. Perich,L. E. Miller,S. A.Solla
[4]“大规模神经记录的维数约减”,J. P. Cunningham,B. M. Yu
[5]“一致行为背后的稳定、长期的皮层信号”,J. A. Gallego,M. G. Perich,R. H. Chowdhury,S. A. Solla,L. E. Miller
数据科学中的流形——概述

What is this thing?
数据科学需要对数据有深刻的理解。随着越来越多的数据积累,回答以下问题变得更加困难:
我如何以准确且有意义的方式在空间上表示我的数据?
我声称回答这个问题的一个超级有用的步骤是理解什么是流形。这里有一个好消息:很可能你已经理解了什么是流形。流形本质上是可视化的,所以日常例子是丰富的。
在本文中,我将:
- 解释什么是流形,给出一个概念性的定义。
- 在不同的上下文中可视化流形的例子。
- 展示流形在数据科学中的应用。
什么是流形?
流形描述了大量的几何曲面。要成为一个流形,有一个重要的规则需要满足。理解这一属性的最好方法是通过例子。流形存在于任何一个维度,但为了简单起见,让我们考虑一个三维空间。
假设有一只小蚂蚁在三维流形上行走。这个流形可以是弯曲的,扭曲的,甚至有洞。规则如下: 从蚂蚁的角度来看,它走到哪里都应该看起来像一个平面。
这个规则听起来耳熟吗?如果你正在寻找一个应用程序,我想这是一个我们所有人都可以涉及的;我们生活在一个流形上!球面是三维流形中最简单的例子之一。
流形的例子
下面是一些常见的流形例子。请注意,流形只是这些对象的表面,而不是内部。

Basic surfaces that are manifolds.
你能想到是不是流形的曲面吗?这些表面在一些“尖”点会有问题。以下是我首先想到的几个:
- 一个立方体。如果你沿着一边走,到了边上,东西就会太尖,看起来就不再像平面了。
- 一座山的风景。假设峰顶非常尖,在这一点上,物体看起来不会像平面。
- 一个沙漏。假设两半的交点是一个单点,那么这个规则在这里就被打破了。
思考流形的直觉
这些例子的共同主题是它们有些光滑——这意味着没有尖锐的尖峰或边缘。对象的整体形状可以是无定形的,这在描述没有严格边界的数据集时很好。
数据科学中的流形
数据可以来自各种空间。它可以是所有图像的空间,或者来自一个价格和数值范围。这些高维空间具有复杂的表示,并不总是可视化的。然而,数据可能来自由流形表示的特殊子集。
因此,流形可以充当从复杂空间到更简单、更平滑子集的垫脚石。

Manifold of handwritten digits as a two-dimensional representation.
分类问题是流形学习的主要例子——我们专门寻找分离两种类型数据的流形。

Classification problems involve finding manifolds.
其他时候,我们可能对将数据“分解”到更低的维度感兴趣——考虑从螺旋形流形中采样,并学习如何将它从下面的三维表示展开为二维平面表示。

(a) Dataset spatial representation. (b) Smooth surface approximation.
定义流形
不幸的是,流形通常不容易解析定义,大多数几何对象都是如此。机器学习中的许多任务都与学习数据的多种表示有关,然后利用这种表示对剩余空间进行预测。如果你对机器学习的这个分支感兴趣,可以去看看流形学习。
结论
看数据对很多人来说是极其满足的,理解数据的几何结构也随之而来。流形是发现数据的基本表面。一旦你有一个流形来描述你的数据,你就可以预测剩余的空间。
感谢阅读!如果能听到你对这篇文章的反馈以及你将来想看到的东西,那将是非常好的!欢迎在下面的评论中写下任何问题。
用随机状态操纵机器学习结果

Photo by Simon Basler on Unsplash
理解随机状态对模型结果的影响
T 调整超参数、执行正确的特征工程、特征选择等都是构建机器学习模型的数据科学流程的一部分。几个小时花在调整和修改过程的每个部分,以改善我们的模型的结果。
然而,在数据科学中最受欢迎的函数中,有一个参数可以改变,以改变机器学习的结果。
…..它与领域知识或您对数据所做的任何工程无关。
随机状态
ML_model(n_estimators=100,max_depth=5,gamma=0,**random_state=0..)**
一个看似无害的论点可能会改变你的结果,但几乎没有任何文章教你如何优化它。通过对训练数据和模型种子的随机排列进行一些操作,任何人都可以人为地改善他们的结果。
在这篇文章中,我想温和地强调一下大多数数据科学项目中经常被忽视的一个组成部分— 随机状态,以及它如何影响我们在机器学习中的模型输出。
那么随机状态是如何影响分类器输出的呢?
为了展示这是如何影响预测结果的,我将使用 Kaggle 著名的泰坦尼克号数据集来预测乘客的存活率。
使用训练数据集,我应用了一些最少的数据清理和特征工程,只是为了获得足够好的数据用于训练。在这个例子中,我将使用 xgboost 分类器模型进行典型的网格搜索交叉验证。
我将使用的培训数据:
利用网格搜索寻找最优的 xgboost 超参数,得到了模型的最佳参数。
基于交叉验证结果,我的最佳性能达到 82.49%,最佳参数为:
'colsample_bytree': 1.0, 'gamma': 0.5, 'max_depth': 4, 'min_child_weight': 1, 'subsample': 0.8
这个过程是许多机器学习项目的主要内容:搜索一系列超参数,以获得最佳的平均交叉验证结果。这时,工作就被认为完成了。
毕竟,交叉验证应该对随机性具有鲁棒性。对吗?
不完全是

对于数据科学教程或 Kaggle 内核中的结果展示,笔记本将会就此结束。然而,我想拉回到以前的工作流程,以显示不同随机状态的结果如何不同。
这次让我们在分类器上运行具有 5 种不同随机状态的代码:
让我们也改变交叉验证随机状态:
所有返回的结果都不同。对于 xgboost 分类器和交叉验证分割的 5 种不同的随机状态,网格搜索运行产生 25 种不同的最佳性能结果。
拥有多个结果源于这样一个事实,即我们使用的数据和算法有一个随机的成分会影响输出。
然而,这在数据科学过程中产生了巨大的疑问,因为我们一直在改变我们的模型。
对于我所做的每一个改变,我会比较不同运行的结果来验证改进。例如改变“a”可以提高模型 2%,增加“b”可以进一步提高模型 3%。
随着上面显示的结果的变化,这让我想知道我的特征工程是否真的有助于更好的结果或者这种改进完全是偶然的。
也许不同的随机状态会使我的结果比以前更糟。

Photo by dylan nolte on Unsplash
我最初的成绩是 82.49%,但 84.84%更高
请注意,在分类器随机状态 4 和分层洗牌随机状态 2 下,我的结果比我最初的运行高出了 84.84%。
那我该展示哪个结果呢?
呈现最好的模型结果是诱人的,因为随机种子是固定的,结果是可重复的。
结果的 2%的改善仅仅归因于不同的随机状态,这似乎是荒谬的。似乎在一个好的日子里,用正确的种子,我们会得到一个更好的结果。
我们应该如何应对这种不确定性?

在数据科学管道中,有许多方法可以解决这个问题。这绝不是一个完整的列表,而只是我在工作中进行的一些实践。
1)从一开始就固定随机状态
对所有事情都承诺一个固定的随机状态,或者更好的是,确定一个全局随机种子,这样随机性就不会发挥作用。将其视为流程中不可改变的变量,而不是可以修补的东西。
或者,
2)使用预测结果作为区间
由于结果在一个范围内会有所不同,因此您可以选择将交叉验证结果报告为一个范围。用不同的种子重复运行,以产生您可以报告的置信区间。人们可以很轻松地说,该模型的性能范围确实在这个范围之内。
3)减少数据分割的不平衡/随机性
减少随机分割对数据的影响的方法之一是确保分割不会对数据的组成产生太大影响。
将数据分层以减少随机性。对数据进行分层可确保训练测试分割/oob 错误/交叉验证的数据在训练和测试集中分别具有相同的存活者/非存活者比率。分割是通过保留每个职业的百分比来完成的,这样可以减少随机洗牌对结果的影响。甚至可以在多列上进行分层。
值得注意的是,尽管数据是随机的,但表现的变化不应太大。
如果精度结果随种子变化很大,这可能意味着模型不够稳健,你应该考虑改进你的方法以更好地拟合数据。大多数情况下这并不重要,但是当边界非常接近时,考虑所有可以用来提高模型性能的变量,包括随机状态,将是很有诱惑力的。
希望这篇文章已经设法强调了随机性如何影响我们的模型,以及减轻其影响的几种方法。
下面是我用过的代码的 github repo ,都可以转载。感谢阅读!
使用 Python 操作熊猫的数据。
让我们用 Python 来计算我的熊猫数据框架的兼职收入。

Credits: GeoSpatial Training Services
在开始之前,让我给你介绍一下 Pandas ,Pandas 是一个 python 库,它为 Python 编程语言的数据分析工具提供了高性能、易于使用的数据结构,如系列、数据框和面板。为了使用 pandas 库和它的数据结构,你必须安装并导入它。请参见熊猫库的文档以获得更多更好的理解和安装指南。
计算兼职收入的步骤。
- 导入所需的(熊猫)库。
- 将日期、工作时间和收入等值存储在数据帧中。
- 向现有数据帧添加更多行(更新数据帧的行)。
- 计算挣的钱和工作的总时间。
- 用日期和挣得的钱绘制条形图。
- 包括搜索选项,以便搜索相应的工作日期。
- 最后添加工资选项。
让我们开始吧!!!
1。导入所需的(熊猫)库。
在本教程中,我们将只使用 pandas 库来执行以下计算,pandas 库本身将为我们提供计算总和并绘制条形图的选项,您无需导入 matplotlib 来绘制图形,pandas 库将为您提供绘制条形图的选项。这将是非常重要的,以了解如何使用熊猫数据框架绘制条形图。如果你用的是 Google Colab 笔记本,你不需要安装任何熊猫图书馆,只需要导入就可以了。否则,您必须在命令提示符下说 pip install pandas 来手动安装它。别名(pd)的原因是,当我想通过别名使用任何方法时,我不必每次都写给熊猫,我可以改为写 pd.method name。
# Importing pandas library.
import pandas as pd
2。将日期、工作时间和收入等值存储在数据帧中。
# Creating a data frame df.
df = pd.DataFrame({'Date':['11/05/19', '12/05/19', '19/05/19', '25/05/19', '26/05/19', '1/06/19'],'Time Worked': [3, 3, 4, 3, 3, 4],'Money Earned': [33.94, 33.94, 46, 33.94, 33.94, 46]})# Head displays only the top 5 rows from the data frame.
df.head()

Storing the values in a data frame.
在这一步中,我将所有数据分类为数据、工作时间和收入三列。日期栏以日/月/年格式显示工作的日期,它将以字符串形式存储,工作时间以整数形式显示一天内完成的工作总量(小时),收入以整数形式显示一天内收入的总额(加元)。在这里工作一小时,最低工资是 11.51 加元。所有这些只是原始数据,这些数据后来被存储在 pandas DataFrame 中,并被分配给一个变量 df。为此,只需使用“pd。DataFrame”并传入所有数据,通过这样做,熊猫会自动将原始数据转换成 DataFrame。我使用 head()是因为数据框包含 10 行数据,所以如果我打印它们,它们可能会看起来很大并覆盖大部分页面,因此 head()显示数据框中的前 5 行数据。
3。向现有数据帧添加更多行(更新数据帧的行)
在这一步中,我们将学习如何向现有数据框追加或添加更多行,这是一个重要的步骤,因为很多时候您必须通过添加更多行来更新您的数据框,在本例中,我首先创建了一个名为 df2 的新数据框,然后通过将 df2 作为参数传递来调用 append()。您必须像 df.append(df2) (existing)那样将新数据帧附加到现有数据帧。append(新数据帧)),现在在 append 函数中,我们有一些其他参数,如 ignore_index = True,这可以防止数据帧追加新的索引,因此在此示例中,所有索引都是连续的(递增),下一个参数是 sort = False。这是因为我们不想根据索引对数据进行排序,否则我们的数据将完全是一个混合体,您可以通过分别将这些参数的值更改为 False 和 True 来处理这些参数,并注意它们之间的差异。最后,将新的附加数据帧存储到新的变量 df 中。
# Adding more rows
df2 = pd.DataFrame({‘Date’: [‘10/06/19’, ‘12/06/19’, ‘14/06/19’],
‘Time Worked’: [3, 4, 3],
‘Money Earned’: [33.94, 46, 33.94]})
df2

Storing the values in a new data frame df2
# Appending the rows of the old data frame to the new data frame.df = df.append(df2, ignore_index=True, sort = False)
df.head()

Appending the rows of the old data frame to the new data frame.
4。计算挣得的钱和总工作时间的总和
这一步非常简单,因为我们只需获得“挣得的钱”和“工作的时间”两列的总和。要做到这一点,您只需使用 sum()即可,它将返回这两列中所有数据的总和。我只是对 Total_earnings 使用 round()来获得精确的值。确保在 df 中传递正确的列名,因为如果列名不匹配,就会给你带来麻烦。最后,我以可读性更好的方式打印结果。
Total_earnings = df[‘Money Earned’].sum()
Total_time = df[‘Time Worked’].sum()print(“You have earned total of ====>” ,round(Total_earnings),“CAD”)
print(“ — — — — — — — — — — — — — — — — — — — — — — — — — — — ”)
print(“You have worked for a total of ====>”, Total_time, “hours”)

Printing the result of total earnings and total time worked.
5。绘制总持续时间与收入的条形图
正如我前面提到的,要绘制一个图形,您不必导入 matplot 库,pandas 有一个 plot(),它将在一定程度上帮助您绘制一个图形。我已经使用了 plot()并将“日期”和“赚的钱”作为 x 和 y 值传递(因为你需要 x 和 y 值来绘制一个图形;)我想要一个条形图,所以我用了条形图,你也可以使用线,分散到关键字种类。然后我们得到一个漂亮的条形图,其中所有的值都是根据我们的期望绘制的。
# Plotting a bar graph using pandas library.
df.plot(x =’Date’, y=’Money Earned’, kind = ‘bar’)

Plotting the graph of Date vs Money Earned.
上面显示的不是绘制图表的最佳方式,但是我已经向你们展示了熊猫库可以帮助你们绘制图表,有时使用这种方法很方便,因为数据和计算较少,你所要做的就是用 x 和 y 值绘制图表。
6。包括搜索选项,以便搜索相应的工作日期。
这是一个额外的步骤,只是为了给它一种感觉,就像我加入了一些功能的数据库,比如搜索选项。在实时项目中,这是一个方便的功能,你经常需要搜索数据,但你不能手动搜索,所以在下面代码片段的帮助下,你就可以完成任务了。在这个例子中,我使用 str.contains()进行搜索操作,并将数据作为参数传递,现在数据是一个变量,包含用户输入的要搜索的数据。输入日期时,str.contains()会搜索输入的日期,然后显示日期和数据框中的相应值。这将有助于当你想搜索一个特定的数据,并获得时间和金钱,你可以只输入日期,并得到结果快,而不是手动寻找所需的日期。
# Including a search option.
date = input(“Enter the date you want to search ===> “)
df[df[‘Date’].str.contains(date)]

The result of the search option.
7。最后添加工资选项
这更像是一个可选(奖金)步骤,因为这将为输入的数据生成工资,这不是一个行业级工资生成器,而是一个简单的工资生成器,具有不同的功能和打印报表。逻辑非常简单,我所做的就是将姓名、小时数和费率作为用户输入,然后将费率和小时数相乘,并将它们存储在 total_money 中,并将其封装在一个函数中。
# Function payroll contains calculation of total money.
def payroll():
name = input(“Enter the name of the employee: ==> “)
hours = int(input(“Enter the hours worked by the employee ==>“))
rate = float(input(“Enter the pay rate for one hour ==> “)) total_money = hours * rate print(“The total money earned by “, name, “for working “, hours, “hours”, “is ===> “, round(total_money), “CAD”)

The result of the payroll function.
因此,这就是如何使用 pandas 数据框和 python 计算兼职收入的方法。我知道这很容易理解,因为我已经尽可能多地解释了代码,剩下的你可以自己练习。如果你对熊猫图书馆知之甚少,这是一个好的开始,这些是你应该唾手可得的一些基本方法。我就讲到这里,让你们练习代码。如果你有任何疑问,请在评论区告诉我,或者给 tanunprabhu95@gmail.com发邮件让我知道你的问题,我一定会解决你的问题。祝你过得愉快!!!!
在人工智能定义的自动化的新时代,公司会蓬勃发展还是勉强生存?

Photo by Rob Lambert on Unsplash
先前我们讨论了人工智能如何使机器人执行过去无法完成的任务。具体来说,AI 机器人在三大领域实现了突破。但会对目前制造业的格局产生什么影响呢?谁将能够抓住新技术所带来的机遇?哪些公司将面临前所未有的挑战?
人工智能机器人将如何颠覆制造业?
破坏性创新是由哈佛商学院教授克莱顿·克里斯滕森提出的。该理论的中心思想是:行业中的现有参与者一般选择专注于“持续创新”,以改善现有客户的现有产品和服务。这些客户通常是那些产生最多利润的人。
此时,一些资源较少的小公司就会抓住机会,瞄准被忽视的市场需求,站稳脚跟。破坏性创新分为两种类型:低级市场创新和新市场创新。
低层次的市场创新(如数码摄影)

Photo by Jon Tyson on Unsplash
早期的数码相机分辨率差,快门延迟长。然而,随着数码摄影质量和分辨率的提高,数码相机已经逐渐从低端市场走向主流市场。
具有讽刺意味的是,尽管柯达开发了数码相机,但最终还是被新技术淘汰了。原因是柯达不可能放弃该公司三分之二的胶片市场份额。这就是“创新的困境”。尽管目睹了新技术的威胁,但由于现有的公司结构和战略,公司无法应对。
新市场创新(如电话)
新市场创新指公司通过瞄准现有公司不服务的客户来进入市场。比如电话刚问世的时候,只能用于短距离的本地通信。当时电报行业的领头羊西联电讯拒绝购买发明者贝尔的专利,因为该公司最赚钱的业务是长途电报市场。当时,短距离通信甚至不被认为是一个市场。不幸的是,他们无法预见未来无处不在的电话通讯。
AI 机器人带来的正是新市场的 D 颠覆性创新!
汽车和电子制造业目前占工业机械臂出货量的 60%。这就是 FANUC、ABB、库卡和安川等传统机器人公司将大部分资源用于“持续创新”的原因他们专注于自己擅长的领域和主要客户的需求:提高速度和精度。

Comparison of traditional and AI robot innovation strategies (source: Bastiane Huang)
他们忽略了新的市场和应用,包括仓储、食品和制造的配套流程。这些行业的客户不需要如此高速、高精度的工作。他们需要的是灵活性、灵巧性,以及机器人学习识别和处理各种部件的能力。
感知到这些未满足的需求,新的人工智能机器人创业公司开始将人工智能应用于机器人。这些公司开始进入隐蔽的新市场,如配套、包装和仓储。
Source: OSARO
有趣的是,这些创业公司很多都不生产自己的机械臂。相反,他们专注于开发机器学习模型、机器人视觉感知和控制软件。因此,他们与现有的机器人手臂制造商合作,提供硬件支持。你可能会假设,即使这些机器人公司不追求 AI 创新,它们也不会被淘汰,因为自动化仍然需要硬件供应。
然而,这忽略了一些事实:
首先,很少有机器人公司已经发现了商机,并开始与这些初创公司合作或建立自己的人工智能团队。由于他们的领先,这些公司可以在以前没有服务的市场建立客户基础,并领先于他们的竞争对手。
其次,随着 AI 的采用越来越多,产业链中最有价值的组件将逐渐从硬件转移到软件和数据。我们已经可以从自动驾驶汽车的发展趋势中看出这一点。一旦无人驾驶汽车变得高度自主,最赚钱的组件将掌握在特斯拉、谷歌和其他控制机器学习模型和自动驾驶数据的公司手中。
这就是传统汽车制造商高度警惕的原因。汽车制造商要么积极参与并购,要么与硅谷软件人工智能初创公司合作。相比之下,机械臂制造商似乎不像汽车制造商那样对颠覆性的人工智能技术做出反应。
机器人制造商、制造商和人工智能初创公司:谁能在人工智能时代巩固地位?
与汽车行业的同行相比,大多数机器人公司似乎对人工智能的反应不够快。即使他们真的投资人工智能,他们仍将面临与柯达相同的困境。组织的重建和战略的制定,以尽量减少转型的负面影响,将考验每个公司管理层的判断和决心。
另一方面,开发新市场极具挑战性。创业公司仍然需要与制造商密切合作,开发更好地满足客户需求的解决方案。制造过程甚至比仓储更复杂。创业公司不一定像理解人工智能和机器人一样理解制造过程。这给了制造商一个成长和转型的绝佳机会!
如果制造商能够率先与这些新的人工智能创业公司合作,他们将能够通过流程自动化提高生产效率和质量。他们还可以满足少量但高度定制的客户需求,这在过去是很难实现的。这一点尤为重要,因为制造商长期以来一直受困于大规模生产和残酷的定价竞争。
制造中心应该利用他们现有的优势和制造过程中的知识来发展人工智能,最终成为下一个人工智能中心。
与人工智能应用相对成熟的零售或消费网络等其他行业相比,人工智能在制造业的发展仍处于萌芽状态。传统制造商仍然有可能利用他们的优势,包括对应用案例的更好理解和对数据的掌握,来巩固在自动化新时代的地位!
如果你想看更多这样的文章,请点击这里!
Bastiane Huang 是 OSARO 的产品经理,OSARO 是一家总部位于旧金山的初创公司,致力于开发软件定义的机器人。她曾在亚马逊的 Alexa 小组和哈佛商业评论以及该大学的未来工作倡议中工作。她写关于人工智能、机器人和产品管理的文章。跟着她到这里 。
Map-Reduce:梯度下降
使用 PySpark 和 vanilla Python
一些统计模型𝑓(𝑥通过优化依赖于一组参数θ的损失函数𝐿(θ来学习。有几种方法可以找到损失函数的最佳θ,其中一种方法是按照梯度迭代更新:

然后,计算更新:

因为我们假设数据点之间是独立的,所以梯度变成了求和:

其中𝐿𝑖是𝑖-th 数据点的损失函数。

Image by Gerd Altmann from Pixabay
以统计模型𝑓(𝑥)=𝑏0+𝑏1𝑥和损失函数𝐿(θ)=(𝑓(𝑥)−𝑦为例)。如果我们有一组三个数据点𝐷={(𝑥=1,𝑦=2),(𝑥=−2,𝑦=−1),(𝑥=4,𝑦=3)}
那么它们中每一个的损失函数是
𝐿1=(𝑏0+𝑏1−2)、𝐿2=(𝑏0−2𝑏1+1)和𝐿3=(𝑏0+4𝑏1−3)与

如果我们从𝑏1=1 𝑏0=0 的解决方案开始,那么梯度是:

积累后会产生

现在,我们创建一个函数,它将接收参数 b 和一个数据点 x 作为列表,并返回该数据点的预测值(y)。
Ex: f_linear([0, 1], [1]) will give an output of 1
我们定义一个接收预测 y 和实际 y 并返回它们之间的平方误差的函数。
Ex: L(1, 1) will give an output of 0
函数 gf_linear(f,b,x,y)将返回具有参数 b 的函数 f 相对于平方损失函数的梯度,在 x 和实际结果 y 处评估。此函数应返回每个元素𝑗对应于相对于𝑏𝑗和𝑗={0,1,…,𝑝}.的梯度的向量
Ex: x = [1], y = 2, b = [0, 1], gf_linear(f_linear, b, x, y) will give an output of [-2,-2]
地图缩小:
我们开发了一个生成值的地图缩减作业,因此该值的第一个元素是所有数据的平均损失函数。我们将映射函数实现为map_mse(f, b, L, xy),其中f是函数b是函数的参数L是损失函数xy是数据。假设数据将以 RDD 的形式出现,其中每个元素的格式如下:
[x, y]其中x是列表,y是标量
Ex:rdd _ data . map(lambda x:map _ MSE(f _ linear,[0,0,0],L,x))。collect()会给出一个输出为:[[1,[9,1]],[1,[16,1]],[1,[0.0,1]],[1,[0,1]]。这里 key 是 1,b=[0,0,0],我们从 rdd_data 得到 x。map 的输出是每个数据点的键和值。
现在,我们创建一个 reduce 作业,它接收前一个 reduce(或 map)的两个值,并适当地合并它们。在 reduce 作业结束时,值的第一个元素是均方误差。
例如: rdd_data。
map(lambda x:map _ MSE(f _ linear,[0,0,0],L,x))。
reduceByKey(reduce_mse)。first()[1][0]会给我们一个 6.25 的均方误差。(x 和 y 值请遵循 rdd_data)
因此,现在我们将计算数据模型的累积梯度。我们将定义一个映射函数map_gradient(f, gf, b, xy),它将接收一个函数f,它的梯度gf,它的参数b,以及一个数据点xy = [x, y]。此外,我们将定义一个函数reduce_gradient(v1, v2)来适当地组合这两个值。
Ex:rdd _ data . map(lambda xy:map _ gradient(f _ linear,gf_linear,[0,0,0],xy))。reduceByKey(reduce_gradient)。first()[1]将给出[-14.0,-30.0,-20.0]的输出
现在,为了得到一个优化的值,我们运行下面的代码,使 MSE 每次都减少。
感谢你的阅读,我希望你能学会或至少理解梯度下降是如何工作的,以及如何使用 Map-Reduce 实现它。
Linkedin:
[## Harsh Darji -特约撰稿人- Medium | LinkedIn
我是一名数据科学爱好者,追求应用高级分析,建立大数据分析工具…
www.linkedin.com](https://www.linkedin.com/in/harshdarji23/)
GitHub:
在 GitHub 上注册您自己的个人资料,这是托管代码、管理项目和与 40…
github.com](https://github.com/harshdarji23)
绘制争议地图:堕胎辩论
维基百科&辩论的竞技场
安-索菲·索尔森,杰佩·卡姆斯特鲁普,拉斯穆斯·德·尼尔加德和约翰内斯·范登赫维尔。
自从堕胎成为可能以来,围绕这个话题的讨论就一直存在。虽然在现实世界中很容易发现外界的争议,但我们还是去了维基百科,调查一个追求中立的在线百科全书会如何呈现它。
通过使用数字方法和收集在线数据,我们调查了堕胎辩论如何在维基百科的舞台上展开。我们的发现也许向我们展示了当维基百科试图解决社会中有争议的话题时,它和英美世界是如何运作的。
我们所做的:
首先,我们收集了绘制争议地图所需的数据。我们使用了几个 python 脚本,然后对数据进行了清理和排序,这样就可以构建可视化了。这里我们应用了几个不同的程序和应用程序。
这些脚本要么使用维基百科 API,因此向维基百科数据库“请求”信息,然后返回这些信息,要么它们抓取和爬行维基百科。这个过程包括脚本“浏览”有问题的页面,从中提取信息,如文本或链接,并移动到其他连接的页面。
在这样做的时候,我们选择了维基百科类别 堕胎辩论 作为种子,或者“起源页面”,深度为 2,从而移动到所有连接到这个的页面,然后所有的页面链接到那些。这给了我们种子类别的成员,从这个和他们的子类别链接的子类别,总共 204 个维基百科页面。
然后使用其他脚本和程序的组合来处理我们的数据集,如 Gephi、CorTexT、alteryx 和 Tableau。
这为我们的可视化产生了 5 种类型的数据;
- 显示链接到其他页面的页面的数据。
- 特定页面上特定单词的出现。
- 页面中的文本。
- 不同的编辑修改不同的页面。
- 特定用户在特定时间对页面进行的修订或编辑。
产生的 204 个维基百科页面的数据集然后用两个不同的 python 脚本抓取,生成带有全文的文件。一个用于通过 CorTexT 进行语义分析,而另一个用于查询用户指定的关键字。然后,我们通过 API 检索修订历史,以生成所选页面的两条时间线。
最后,我们抓取了维基百科的 HTML,生成了一个由文本链接连接的 204 页的网络,这意味着维基百科文章的主要文本。然后,这与关键字搜索相结合,生成了 11 个衍生网络,按笔记大小显示了选定的问题。

Workflow of our process of data harvesting and construction of visualizations, for a larger size click here.
针,遇到草堆:

Our network, where we sat down and looked for clusters in the network. We identified 4 distinct clusters, but also a middle that did not separate easily. For a larger size, click here.
我们开始使用开源应用程序把从堕胎辩论类别收集来的维基页面排列成一个可视网络。这给了我们一张由两种截然不同的东西组成的地图。点是维基页面的可视化,称为节点。第二件事是连接这些节点的线。这些线表示节点是相连的——在这张地图上,这些线显示了不同的维基页面如何在维基页面的文本中相互链接。在我们的术语中,这些线被称为边。
为了搞清楚这个网络,我们使用了一种力导向的放置算法,称为 ForceAtlas2 。该算法给数据点和它们的连接一种空间感,我们需要这种空间感来直观地分析网络。ForceAtlas2 的工作原理是给边和节点一种推拉效应,其中边的功能就像一种弹簧,将节点绑定在一起,这些节点相互排斥。这样,具有许多共同边的节点彼此更接近。因此,该算法将节点展开,并使得通过 Venturini 等人(Venturini 等人)陈述的 4 条规则对网络进行空间分析成为可能。铝:2015):
1:哪些是主要的集群?
2:分隔它们的主要结构孔是哪些?
3:每个集群中有哪些子集群?
4:分隔它们的是哪些较小的结构孔?
然而,我们的问题是,我们的网络中几乎没有结构上的漏洞——它更像一只海星,而不是中间有洞的相连的集群。因此,我们最终在我们看到的“海星”的明显手臂周围画了圈。
这给了我们爱尔兰、加拿大、宗教、和美国法律体系——但它留给我们一个大中心,我们不知道如何分析。

Map of the category of Abortion debate on Wikipedia, and its subcategories with a depth of two. This map shows the network after the use of the modularity tool in gephi. For a larger size, click here.
为了尝试理解这只海星,我们使用了 Gephi 内置的一个工具,叫做模块化工具。模块化是一种尝试将大集群分成更小的子集群的方式,通过数学定位大网络如何划分成更小的组,彼此之间有更多的内部连接。这些子网络可以指示更大网络内的某些社区。
简而言之,它试图让计算机在理解集群时做一部分分析工作。这是通过用不同的颜色给不同的子簇着色来实现的。
模块化工具给了我们与我们自己挑选的集群大致相同的集群。但它也给了我们两个新的集群,在参考了维基百科的文章后,我们将其命名为权利和边缘。
模块化地图也迫使我们提出另一个观点— 桥。桥是连接集群的节点——它们是维基百科上通过链接不同主题来连接两者的页面的表示。模块化工具简单地为子集群分配一个它最有可能找到的桥接节点。同样地,堕胎节点成为美国法律系统的一部分,尽管它并不在附近。这可能不是最好的情况,一旦你手动查看维基百科上的页面及其内容。
但是我们的新聚类也许也给了我们一些关于维基百科作为媒介的见解——争论集中在英美世界,但也在法律方面。也许网络也向我们展示了英语维基百科如何对堕胎辩论的争议进行排序,或者用 Marres & Moats (Marres,Nortje & David Moats: 2015)的话说:
……我们可以从关注知识内容和争议中的政治利益之间的关系(这是早期 sts 的目标)扩展这种对称方法,以包括媒介和内容之间的关系。
本质上;我们看到媒体,这里是维基百科,是如何组织讨论有争议的事情的。
地区、宗教和法规:
为了更好地区分我们的聚类,我们搜索了特定的关键词,看看这些关键词是否在文章语料库的某些部分使用得更多。请注意,下面的网络是上面网络的循环版本。

Prevalence of regional notions shown by size.
首先,我们调查了在不同地区开展的主题。我们仔细观察了几个英语国家的流行情况。通过对国家术语进行关键字搜索,并在对这些术语进行分组(即“爱尔兰人”、“爱尔兰人”和“爱尔兰人”)时,我们看到两个地理聚类(加拿大和爱尔兰),与模块化工具得出的聚类密切相关。我们进一步看到,美国的观念严重影响了网络。

Prevalence of religious notions shown by size.
我们发现人们对绿色集群很感兴趣,这是使用模块化工具的结果。为了探索这一点,我们对伊斯兰教、犹太教、基督教和天主教进行了关键词搜索。每一个都是通过搜索包含该信仰的几个词(即“穆斯林”和“伊斯兰”)来构建的。通过比较这些,我们都看到所有的宗教彼此之间有很大的关联,大多数都出现在左下方,同时也看到了它们的差异,如天主教更多地出现在“爱尔兰”部分。

Prevalence of different juridical terms shown by size.
在调查网络时,我们注意到很大一部分链接页面都是关于法庭案件的。因此,我们决定调查这个话题对辩论的影响程度。我们看到“法律”严重影响了整个辩论,而“法庭案例”大多位于左上角,大多数位于橙色群集内。最有趣的也许是禁止和管制之间的区别(两者都由动词和名词组成)。我们看到禁酒令在“宗教”绿色集群中更加突出。这可能是因为宗教团体更倾向于谈论禁止堕胎,而监管可能更像是一个法律话题。由于一些集群也有地理上的相似性(如上所述),这里的差异也可能是由于文化或语言的差异。
连通性:单行道还是双行道?

A visualization showing the degree of the graphs in two way — in degree and out degree. For a larger size, click here.
这两张地图展示了维基百科的链接是如何作为一种等级体系运作的。维基百科上的一些文章,如 罗伊诉韦德 在两个网络中都很大。在 Roe 诉 Wade 一案中,两个地图中的这种表述是其历史和法律分歧的产物。在美国,如果不联系到 1973 年美国最高法院的案例,讨论堕胎几乎是不可能的。其后果今天仍在政界和司法界继续。
但是更有趣的是那些在一张地图上很大并且可见,但是在另一张地图上却看不见的。堕胎联系紧密,但这在维基百科的结构方式和我们收集数据的方式上是有意义的。几乎所有关于堕胎辩论的网页,以及它的子分类都会链接到关于堕胎的文章。堕胎的文章本身主要读起来像是一个医疗流程及其与历史和宗教实践的关系。文章很少用在辩论上,辩论有自己的文章。
一些链接不太好,但包含其他页面链接的页面是像 【美国】特纳日记Eugen Relgis和各种关于围绕堕胎主题的游行的文章。因此,有一个大的出度而没有一个大的入度可能会告诉我们,所讨论的节点位于网络的边缘。有些联系甚至可能是试图获得更多的合法性,或者是效仿拉图尔,试图调解自己在争议中的立场。也许特别是如果用户群是非常独特的一篇文章?
语义展开海星:
我们利用 CorTexT.net 网站进行了一系列不同的语义分析。该网站是由两个法国政府机构资助的 LISIS 研究单位的在线平台——IFRIS 和 INRA 。CorTexT 是一个有趣的工具,因为它让我们通过一种算法来运行我们的数字电子表格,这种算法对这些电子表格的内容进行语义分析。这让我们有机会从维基百科中搜集大量的文本,然后将它转化为常用短语的网络。
我们对维基百科堕胎辩论类别中的所有文章页面都做了这样的处理,结果地图如下。

A map of the top 100 phrases and words in the Wikipedia category of abortion debate. Made with CorTexT. For a larger size, click here.
这张地图证实了我们的发现,即美国司法系统在文章描述堕胎辩论的方式中占据显著地位。这可能是一个迹象,表明这个有争议的话题是如何通过法律体系及其决策方式来处理的?显然,美国的制度似乎就是这样运作的。司法的分量使其他形式黯然失色,这些形式可能是处理有争议话题的途径,如宗教或政治,它们在这种关系中发挥的作用较小。
这张地图还缺少一些东西——争议。或者说,它没有表现出来。也许这告诉我们一些关于维基百科辩论结构的事情——对用户之间争议的处理隐藏在文章之外的某个地方,媒体宁愿避开互联网上辩论者的混乱信息来源?我们必须更深入地了解维基百科页面的世界,才能找到这场斗争。
语义映射集群:
下面的可视化是三个图的合成,基本聚类的所有衍生物,从整个网络中移除,聚类中的文章页面的语义分析,以及文章的谈话页面的语义分析。语义分析是通过 CorTexT 完成的。
权限-群集:

Composite of graphs from the Rights cluster. Notice how much of the debate surrounding the production of the article happens in the Talk pages, and how these are often refering to Wikipedias policies. For a larger size, click here.
爱尔兰集群:

Composite of graphs from the Irish cluster. Here a discussion on the representation of the relationship between the Republic of Ireland and Northern Ireland is done in the articles. A reflection on another controversial issue, that is present because of the geographical nature of the articles. For larger size, click here.
边缘集群:

Composite of graphs from the Fringe cluster. Here we also see that, in the analysis of the articles, there are very few bridges between the different clusters. Perhaps a sign that this cluster should be investigated? Maybe a reflection on how well the modularity tool produced a cluster where the contents of it form a community — here it clearly lumped different communities together. For larger size, click here.
加拿大集群:

Composite of graphs from the Canadian cluster. These graphs are interesting in that they display nothing like that looks like a controversy. What has been mapped here is everyday Wikipedia editing of articles. Quite interesting, when one thinks of the subject matter and Canadas geographical connection to America. For larger size, click here.
宗教和伦理集群:

Composite of graphs from the Religious & Ethical cluster. Here the discussion on the Talk pages is about certain denominations of christianity — especially The Church of the Latter Day Saints. For a larger size, click here.
美国法律体系集群:

Composite of graphs from the American Legal System cluster. Once again, we see the use of Wikipedias policies to filter out views, that are controversial in the articles of the online enyclopedia. Also interesting here, is the fact that all discussion is about judicial and political topics. It is a very specific way of treating a complex subject. For larger size, click here.
对我们来说,很明显,文章和谈话页面的单独语义分析给了我们一个媒体技术效果的概述,这是 Marres 和 Moats (Marres,Nortje & David Moats 2015: 6)所讨论的。
它变成了一张地图,不仅是用户和他们的不同意见的地图,也是这些不同意见只能在维基百科的特定空间里使用的地图。对话页面是一种后端,尽管它是公开可见的——你必须寻找它才能使用它。
这种布置作为物品的一种过滤器。由于维基百科的政策而被认为有问题的内容被隔离到谈话页面的空间中,以便成为文章的一部分,或者被简单地丢弃并最终在谈话部分存档。所以我们也看到了我们在堕胎辩论类文章的语义分析图上没有看到的。原因很简单,由于维基百科的内部运作,争议已经以某种方式被过滤掉了。
这种在谈话页中的过滤在边缘、爱尔兰和美国法律体系群中非常明显。在这里,我们在所有这些地图中都有一个大型语义集群,涉及维基百科在编辑中的良好行为政策——这是维基百科上处理分歧的明显方式之一。
对边缘集群的分析也强调了对模块化工具的批判。它似乎将几个不同的文章社区结合在一起,而这一簇簇支离破碎的主题不容易连接起来。模块化工具看起来并不是一个完美的工具,但在批判性使用时仍然非常有用。
维基百科用户,以及如何映射他们:
这张二分图显示了编辑用户和维基百科文章之间的关系。通过以这种方式产生我们的数据,一些有趣的事情出现了。

A bipartite graph showing the relationships between individual users and Wikipedia articles. Users are represented by the red nodes, while the green nodes are Wikipedia articles. Size indicates the level of activity, while the thickness of the edges reflect the amount of times a users has edited one specific article. Based on user revision history data since 2001 from Wikipedia. For a larger size, click here.
例如,右下角的集群是一个主要由爱尔兰用户组成的集群,他们编辑与爱尔兰堕胎法相关的文章。这突出了某些文章编辑的地理性质。2018 年,爱尔兰堕胎法出现在媒体上,因为围绕这些法律的改变举行了全民公决。这可能产生了更多来自当地爱尔兰维基人的与这些页面的互动,他们想在这个展开的讨论中扩展文章。
然后是中间的大集群,诸如堕胎辩论、、反堕胎暴力、、美国反堕胎运动、的周围文章显示大量用户在大集群中的许多不同页面上编辑。
最有趣的是我们也开始在以前的网络上看到的——学位地图。这些页面中的许多在以前看起来并不重要,但是正如我们所看到的,人们对编辑它们有很大的兴趣。尤其是像 詹姆斯·奥基夫 和 白人种族灭绝阴谋论 这样的页面在这个地图上很有意思。这些页面有大量的维基人,他们只编辑网络中的这些特定文章。这些网页是有趣的异常现象——它们在网络中并没有突出的文章,但是它们吸引了大量的活动。这张地图上许多较大的绿色节点都可以这么说。在用户数据进入我们的地图之前,它们中的大多数并不突出。这是争议的标志吗?有些文章确实突出了有争议的话题和人物。也许这值得深入研究一下。
堕胎辩论和白人种族灭绝的阴谋论?

A look into the behaviour and activity of the Wikipedia users editing the Wikipedia article “White Genocide Conspiracy Theory”. For a larger size, click here.
当我们冒险调查编辑白人种族灭绝阴谋论文章的特定维基人时,一张争议话题的地图出现了。这些用户似乎在文章和聊天页面的海洋中航行,在那里,似乎处于永无止境的辩论状态的主题被描述并被制作成一种百科全书式的知识。
许多我们认为是过去几年互联网战场的文章。 Gamergate 争议 、 Alt-right 、 Me Too movement 的文章都是重剪辑发生的地方。

A screenshot of the mainpage of the Gamergate controversy talk pages. Here you can see the different policies being enforced. This article is labelled as controversial and therefore comes with additional scrutiny and sanctions.
这让我们看到了维基百科的温和一面。显而易见,维基百科的政策,如 中立观点 或 原创研究 正在迅速成为我们如何看待文章中争议的经典。这些政策在讨论中被用作武器——尤其是在有争议的讨论页面中。这些规定是摒弃不同意见的方式,或者是压制对文章措辞权威的质疑。
但是这当然没有向我们展示,用户是如何参与有争议的讨论的。他们是版主还是有问题的编辑?进入单个文章的讨论页面并绘制单个用户的评论会给我们一个概览,如果我们走这条路的话,这可能是一条追求的途径。
对于我们的使用来说,可以说这些用户几乎都与大量非常有争议的页面相关——在某种程度上。从这个意义上来说,这是维基百科上意见战场的地图——从文章和他们的谈话页面到管理员的公告栏。互联网上最大的百科全书关于什么是事实的元讨论是通过遵守严格的行为规则并积极执行这些规则来安排的。
一段时间以来的维基百科用户:
到目前为止,我们已经看到用户如何以不同的方式参与不同的主题。上面我们看到了用户在不同的页面上有不同的参与度。下面我们将概述他们是如何随着时间的推移做到这一点的,以及我们是如何绘制的。通过将时间变量引入等式,我们可以看到不同的页面或主题在不同的时间是如何突出的。

Timelines for 13 specific pages, picked by us. Made in Tableau. For a larger size, click here.
上面我们看到了 13 个不同的页面,考虑到随着时间的推移修改(或编辑)的数量。所有的网页都被发现是重要的,要么作为一个集群的中心,要么通过我们的其他可视化。
我们注意到的第一件事是“罗伊诉韦德案”页面的大部分内容完全盖过了其他页面,从而强调了我们之前的想法,即这是堕胎辩论中的一个核心角色。从修订量(节点大小)和独特用户参与度(线条粗细)来看都是如此。
接下来我们要强调的是,我们看到了一种模式,即页面在创建后的最初几年(标为“出生”)会有更多的活动,例外情况是“堕胎法”和“堕胎辩论”页面,它们的活动似乎会随着时间的推移而保持不变。
这可能表明,如果一个页面在第一年后出现活动上升,这要么是因为该主题突然变得有争议,要么是因为随后包含的新事件。我们看到有两页展示了这种行为,即“白人种族灭绝阴谋论”和“爱尔兰宪法第八修正案”。调查第一个提到的页面,我们看到南非事件的迹象开始了一场跨越大西洋到唐纳德·特朗普的争端,然后进一步传播到阴谋论的页面。

Does the genocide of white people originate in South Africa? According to Wikipedia, it certainly travels through the country — invoking the character of President Trump on the way.
在下一节中,我们将进一步探究爱尔兰案例中价格上涨的可能原因。
我们的爱尔兰问题:
我们想通过维基百科页面上对爱尔兰宪法第八修正案(T0)和第三十六修正案(T3)的编辑时间线可视化来说明的一点是,它们都经历了相同的编辑过程。所有四个图表在相同的月份有相似的峰值。正如我们上面的大图显示的,一个大的尖峰“在生命的后期”表明了维基百科之外的改变,但是第 36 次修正是在修订和编辑发生前几个月才创建的。
虽然第 36 修正案是 2018 年 1 月 18 日创建的新维基百科页面,但我们可以看到修订量的峰值和参与编辑的独立用户是如何按时间段连接的。在第八修正案的编辑历史的可视化上也可以看到类似的趋势。

Screenshot from the Wikipedia article page about The Thirty-sixth Amendment of the Constitution of Ireland.
虽然我们从阅读爱尔兰宪法第八修正案的内容中知道,它禁止使用堕胎,而第三十六修正案为必要时绕过第八修正案提供了可能性。

Revision history of the Wikipedia page concerning the Eighth Amendment of the Constitution of Ireland.

Revision history of the Wikipedia page concerning Thirty-sixth Amendment of the Constitution of Ireland.
这两个维基百科页面的内容解释了这两个页面之间的联系,以及同时修订这两个页面的必要性。我们在编辑社区中从独特的用户活动中看到的类似峰值显示了这些变化的相关性。我们认为两个页面上独特编辑的数量是爱尔兰宪法两个修正案政治变化的一个指标。
上面,我们看了维基百科用户随着时间的推移编辑的更一般的方式。现在,我们深入探讨爱尔兰集群的部分内容的编辑。我们想探究维基百科用户是否会在全球范围内追随爱尔兰宪法的变化。
爱尔兰的编辑们:

Data visualization of user data from the Irish cluster. Made with Tableau. For a larger size, click here.
在我们可视化的第一部分,最左边,我们看到大部分编辑是如何由识别的人完成的,几乎所有的修改都是由识别的用户完成的。这已经通过柱状图的使用得到了说明。如果我们将“高”数量的用户编辑和修改与我们可视化的第二和第三个图表进行比较,我们会看到对更新爱尔兰和爱尔兰事务,特别是堕胎的信息感兴趣的独特用户的增加。第一张图让我们相信用户主要是人类,而不是自动机器人。第二张图中的尖峰也表明了某种变化,需要整合到维基百科页面中,就像之前的时间线一样。维基百科页面描述了两部法律,这两部法律相互影响,正在讨论的变化可能是第 36 修正案的通过,这直接影响了第 8 修正案。
上面的图像显示了一个由人类组成的团体,他们在维基百科中的行为主要是爱尔兰式的。这回答了谁以及在某种程度上什么时候的问题。从数据来看,在这个集群中似乎没有关于堕胎的关注或争议,只有关于爱尔兰堕胎的争议或关注,而在集群的其他地方没有类似的关注(Munk:2014)。
正因为如此,我们想在更高的程度上理解事件的时间线。因此,我们继续绘制爱尔兰人的活动图。

Data visualization of user data from the Irish cluster. Made with Tableau. For a larger size, click here.
在第一张图中,我们看到在上述修订时间线峰值的同一时期,匿名和非匿名使用修订的情况有所增加。从这张图表中我们可以了解到的新情况是,在仅仅两个月的增加行动后,我们看到匿名用户的大幅下降。
当跟随修订和唯一编辑的时间线时,在可视化的中间,我们可以看到两条线彼此跟随,直到 2017 年 10 月左右,此时 pages 编辑的下降多于修订。这可能意味着一场“改版战争”,用户将精力用在改变现有内容上,而不是贡献新信息。它也可以指向一个专门的核心用户,他们修改和编辑新的信息。从左边的图表中,我们还可以看到修改页面上的大多数用户都是可识别的。这可能也是爱尔兰集群的普遍情况。正如我们在上面看到的,有一大群人参与了爱尔兰堕胎的话题。
当我们打开维基百科第八修正案和第三十六修正案的评论时,我们看到了民意调查的许多变化。像对第八修正案和第三十六修正案的民意调查这样的单一问题会产生大量的修改,因此会产生峰值。
将关键词映射到堕胎类别:
通过对通过 CorTexT 找到的堕胎辩论的语义关键词进行更深入的研究,并系统地回顾最常见的名词短语,我们可以确定 12 个关键词,我们可以在整个堕胎类别中找到它们。

Maps showing different keywords from the abortion debate category, mapped out on the abortion category of Wikipedia. For larger size, click here.
“反堕胎”和“反堕胎选择”主要与北美堕胎辩论有关。然而,关键词"反堕胎",一个最常被支持堕胎群体用来称呼反对堕胎者的术语,主要出现在关于反堕胎暴力的页面上,显示当暴力被用来攻击堕胎做法时,它被命名为反堕胎而不是反堕胎。
关键词“死亡”主要出现在关于在爱尔兰和美国引发堕胎辩论的人的具体案例的页面中。萨维塔·哈拉帕纳瓦的案件对爱尔兰堕胎辩论和相关立法产生了巨大影响,克米特·戈斯内尔的案件同样是一个关于美国非法堕胎结果的有争议的案件
“权利”被视为既与胎儿的权利相关,这是一个反堕胎的焦点,也与生殖权利的概念相关,这是一个在欠发达国家主要与妇女权利相关的问题。这表明了世界各地权利问题的双重性。

Maps showing different keywords from the abortion debate category, mapped out on the abortion category of Wikipedia. For larger size, click here.
“婴儿”在流产和关于流产的哲学辩论中占主导地位。这显示了不同的观点,婴儿与胎儿依赖流产与堕胎,以及如何从哲学角度就堕胎的道德性进行辩论。
“生存能力”是美国堕胎法律纠纷中的一个核心概念,主要位于这一组中,可能是因为它与胎儿生存能力有关。
“母亲”出现在像共产主义下的堕胎这样的页面下,也许可以用现在和以前的共产主义国家法律来解释,这些法律允许堕胎来保护母亲的生命。
“健康”的分布表明,这一概念在很大程度上与发展中国家妇女的生殖权利和健康有关。
很明显,在某种程度上,描绘一场如此复杂的争议有其自身的生命力,越陷越深最终会产生更多的问题而不是答案。最终在这里,我们希望表明,没有真正的终结,我们仍然有新的机会进行调查,这个关键词分析揭示了以前没有探索的争议方面。这最后的分析标志着我们对堕胎争议和维基百科内部运作的探索的结束。这是一次旅行;一次紧张、激动人心、有时甚至令人疲惫不堪的学习经历。
那么,我们对堕胎辩论了解多少?
回到我们最初的网络,我们不再仅仅看到一只孤独的海星。
相反,我们看到了不同的反对堕胎的观点,以及由此产生的次级争议。我们看到了与主题的联系,从未想象过的联系,我们看到在我们的海星网络中严重缺乏医学专家,这是我们没有预料到的。
那么堕胎辩论是关于什么的呢?谁是持不同意见的一方,他们在哪里会面,分歧是什么,会停止吗?
在我们的映射中,参与堕胎辩论的行动者被简化为维基百科的编辑。他们可以是匿名的,也可以是固定的,甚至是机器人。他们只在维基百科见面,这里是当地的酒吧;一个人了解最新八卦、讨论生活、呐喊和闲逛的地方。尽管我们展示了辩论的主题,但我们没有可视化地展示分歧的实际内容。分歧的核心证据似乎隐藏在谈话页面中,隐藏在回复文章和在页面上添加观点的行列中。虽然我们已经谈到了这一点,但分歧的真正原因似乎从我们的手指间溜走了。
必须说几句维基百科在这场争论中扮演的角色。维基百科的结构和政策为不同意见提供了一定的舞台。我们映射的内容是通过一层层的页面构建的。大多数人从来不会点击超过这篇文章的无争议网页——但我们很少想到它是一个可能会因为用户的内部工作而不断变化的页面,在它背后的 talkpages 上进行辩论——修改和编辑。维基百科的用户一直在构建事实,利用网站的政策作为工具,将文章组织成事实的文学载体。
关于堕胎的争论还有很多方面需要探索,但是通过以上的回顾,无论是争论还是描绘争议的过程,我们希望至少已经阐明了其中的一小部分。
参考书目:
北卡罗来纳州马雷斯和北卡罗来纳州莫茨(2015 年)。用社交媒体描绘争议:对称的例子。https://doi.org/10.1177/2056305115604176
芒克,A. K. (2014 年)。在线绘制风能争议:方法和数据集介绍。
t .文图拉尼,m .雅克米和 d .佩雷拉。视觉网络分析:里约+20 在线辩论的例子。巴黎梅迪亚实验室科学。
绘制布鲁克林的房价图
使用散景的地理测绘教程

在他的小说《如何毁灭一座城市》中,P.E .莫斯科维茨写了美国四个城市中产阶级化的影响:新奥尔良、底特律、旧金山和纽约。他认为地理学家尼尔·史密斯发展了自 1979 年以来关于中产阶级化最有影响力的学术理论——租金差距。中产阶级化是可以预见的。它遵循资本主义经济学的基本原则,“投资者会去潜在回报率最高的地方。”通过检查税收数据,人们可以在短时间内确定哪里的建筑可以便宜买到,哪里的建筑可以变得更贵。头奖将会是在一个中产阶级化的社区的几个街区内找到一栋破旧的建筑。关键是一处房产的可购买价格和一旦改造后的价值之间的差距。租金差距越大,建筑物成为目标的可能性就越大。寻找下一个中产阶级社区的房地产开发商依赖于这样一个事实,即卖家没有意识到潜在的价值。
Kaggle 有很多很棒的数据集,我很幸运地找到了一个很棒的数据集关于 2003 年至 2017 年的布鲁克林房屋销售。这些数据来自纽约冥王星的 shapefiles 和大量的空值。每个条目都有一个地址和 X、Y 坐标,这些坐标将这些点标绘成布鲁克林的形状。

我真的很想在布鲁克林的地图上绘制所有的点,并制作一些交互式的可视化,所以我决定与 Bokeh 合作这个项目。
我的第一步是把我所有的 X 和 Y 坐标转换成纬度和经度,这样我就可以把它们转换成正确的墨卡托坐标。因为你的电脑屏幕是平的,而地球不是平的,所以在绘制地图时,散景只接受墨卡托坐标。
It’s a banana.
由于我无法找到一个免费和快速的地理编码资源,我用我所拥有的。我取了 20 个数据点,一次查找一个数据点的经纬度坐标。利用这些坐标,我创建了一个训练数据集,以便通过简单的线性回归来预测其他 25,000 个点的纬度和经度。
自然地,我也对纵坐标重复了这个操作,并将这些值放入它们自己的列中。结果相当准确。当我比较一个随机数据点的估计坐标和实际坐标时,差异只有几个街区。此外,当我标绘最后一组坐标时,水里和公园里都没有房子。
这是一个将你的经纬度坐标转换成墨卡托坐标的函数。
散景图在交互和用户操作方面有很大潜力。你需要用 conda 命令安装 bokeh。要阅读文档和更详细的说明,请点击这里。以下是开始绘图时需要导入的重要包。
Bokeh 有自己的贴图图块集,允许在没有 shapefiles 或 API 的情况下进行贴图。这对我是一个巨大的加分。他们的牌组在这里列出。请注意,这里的文档中有一些令人困惑的方向。导入图块集的正确方法是直接导入。在上面的代码中,您调用包 bokeh.tile_providers 并导入您想要使用的任何样式的地图。使用 get_provider 或 Vendors 会返回一个错误。有些调色板是列表,有些是字典。确保像这样检查你选择的调色板的数据类型。
如果类型是一个列表,那么你只需要定义你的调色板就可以了。如果类型是字典,您必须在下面的第二行代码中指出要使用多少种颜色。
我会把这一大块的所有东西一行一行的分解。我定义了我的调色板,并指出我想要 10 种不同的颜色,这将对应于所售房屋的 10 个不同的价格范围。点击此处查看所有调色板散景报价。源被定义为我的数据帧,称为 TwoThree。这是 2003 年以来所有相关的住房数据。
我不仅想在地图上绘制数据来显示位置,还想用颜色来区分更贵的房子和不太贵的房子。映射器是为我的颜色条属性定义的。它需要一个字段名,以及一系列低值和高值。散景有一个伟大的可定制的悬停功能。当鼠标悬停在可视化中的任何一点上时,您可以决定在相应的窗口中会弹出什么信息。我使用变量工具提示来定义我想要显示的内容。每个属性都是标签和数据来源的元组。在这里看文档。如果数据来自您的数据集,第二个值必须以“@”开头,如果该值来自可视化本身,如索引或图表中的 X 和 Y 坐标,您将在该值前面加上“$”。我添加了一个小部件滑块,以便可视化能够根据所选年份改变和呈现新数据。我将在另一篇教程中更详细地介绍这一点。滑块现在将纯粹是装饰性的。

Pretty!
我将图形的 X 轴和 Y 轴定义为墨卡托。这将把墨卡托坐标转换成经纬度坐标,所以它将像一个真正的地图!我称之为工具提示,它是当你在每个点上悬停时出现的值,我给我的图形一个标题。因为这是一张地图,所以我也必须添加我的地图框。
我正在创建一个散点图,所以我只需引用引号中相应的列名,就可以在图中添加圆。颜色将由我的 mapper 变量和我的数据源中的值决定。我创建了一个颜色条作为我的点的键,在它下面我表示我想把我的颜色条放在图表的右边。
我可以将我的布局定义为一行或一列。列会将所有内容上下叠放(从上到下),而行会将所有内容并排放置(从左到右)。我现在把我的形象放在我的滑块上面。

2003 年,布鲁克林似乎有很多售价低于 200 万美元的房子。事实上,我的很多数据表明,很多房屋售价低于 1000 美元,很可能是因为止赎。

通过缩放功能,我在公园坡找到了一些更贵的房子。2003 年,我敢肯定一些房地产投资者希望在公园坡北部的 Prospect Heights 附近买房。

是的,就在离这个 300 万美元的家几个街区远的地方,有一栋售价 16.5 万美元的房子。
我计划在这个项目上做更多的工作,并将创建至少一个与散景视觉交互的教程。让我知道你喜欢使用哪些绘图可视化工具,为什么。我一定会检查他们!
使用 Python 分析 Lending Club 贷款-教程
如何使用 pandas,geopandas,matplotlib 处理来自最大的在线 P2P 贷款平台的信贷。
市场借贷是可能存在歧视或不公平借贷行为的场所。在这个帖子系列中,我们研究了 1935-40 年间的红线和今天的 P2P 贷款格局之间的空间相关性。

red —main Redlining cities in the 1930s | green — Lending Club’s highest loan application rejects in 2012 | magenta — Lending Club’s highest interest rates in 2012
问题定式化
作为一家的平等住房贷款机构,一个 P2P 贷款市场应该“不分种族、肤色、宗教、国籍、性别、残疾或家庭状况”地筛选贷款申请系统性地拒绝来自特定邮政编码的贷款可能会伤害少数族裔申请人。这是一种在 1935 年至 1940 年间被称为划红线的做法,当时房主贷款公司或“HOLC”在近 250 个美国城市创建了用颜色标记社区信用价值和风险的地图。这些地图最近被数字化,可以在映射不等式上查看。尽管有联邦公平住房法案,现代的红线最近在美国 61 个城市被曝光。另一项调查发现有几家银行显然将一些少数民族排除在他们客户的投资组合之外。
我们使用 Python、Pandas、Jupyter Notebook 和 Geopandas 库来可视化来自 Lending Club 的 2400 万份贷款申请,Lending Club【】是世界上最大的 P2P 贷款平台。目的是调查来自 20 世纪 30 年代被划红线的邮政编码的申请者是否更有可能被今天的市场拒绝。如果没有,我们将核实此类贷款申请人是否获得更高的违约利率。我们也想探究这些关系如何在 Lending Club 的整个生命周期中演变,从 2006-2007 年到现在。
标记数据收集
绘制不平等网站提供了一个选项,可以下载上世纪 30 年代被划上红线的所有美国城市的形状文件。shapefiles 包含描述每个城市中的街区(区域)的多边形的地理纬度和经度坐标,因为它们是由 HOLC 划定的。
*import geopandas as gpd
df_redlines_map = gpd.read_file('data/HOLC_ALL.shp')
df_redlines_map.head()*

Figure 1
每行代表一个具有以下特征的多边形(区域):
- **状态:美国状态,
- **城市:美国城市,
- looplat,looplng :多边形起始坐标,
- **名称:区域名称,
- holc_id :区域编号,
- holc_grade : HOLC(安全)等级,
- area_descr :区域描述,
- **几何:构建多边形的所有坐标的集合。
HOLC 等级描述了 20 世纪 30 年代分配给该区域的信用价值,如下所示:
- 最好的
- b——仍然可取
- c——肯定下降
- D —危险
我们清除那些 HOLC 等级无效的多边形。
*df_redlines_map = df_redlines_map[df_redlines_map.holc_grade!='E']*
红线功能工程
在开始我们的分析之前,我们先来看看 HOLC 分配的等级分布,不仅是在每个邮政编码内,而且是在州一级。这需要追溯到 20 世纪 30 年代,对每个地区的人口进行估计。一种简单的方法是使用每个 HOLC 等级的分区数。因为相应多边形的大小变化很大,我们可能无法直观地了解人口数量。因此,我们选择使用区域面积(以平方公里为单位)作为基准单位。
我们从开始计算每个区域的平方公里面积,以及它的地理中心(“质心”)。
*proj = partial(pyproj.transform, pyproj.Proj(init='epsg:4326'),
pyproj.Proj(init='epsg:3857'))
df_redlines_map['area'] = [transform(proj, g).area/1e+6 for g in df_redlines_map['geometry'].values]
df_redlines_map['centroid_lat'] = df_redlines_map.geometry.centroid.y
df_redlines_map['centroid_long'] = df_redlines_map.geometry.centroid.x
df_redlines_map.head()*

Figure 2
我们现在将使用每个区域的质心的坐标来添加每个区域的邮政编码。为此,我们依赖免费的 Python 库 uszipcode,,它使用自己最新的地理编码数据数据库对每批 100 个区域进行地理编码。
*from uszipcode import SearchEngine
i = 0
while i < df_redlines_map.shape[0]:
df_redlines_map.loc[i:i+100,'zipcode'] = df_redlines_map[i:i+100].apply(lambda row: search.by_coordinates(row.centroid_lat,row.centroid_long, radius=30, returns=1)[0].zipcode, axis=1)
i = i + 100
df_redlines_map.head()*

Figure 3
计算每个邮政编码的**总红线区域现在很简单。**
*df_redlines = df_redlines_map.groupby(['zipcode']).agg({'area': np.sum}).reset_index().rename(columns={'area': 'zip_area'})
df_redlines.head()*

Figure 4
我们现在可以计算每个州的**总红线区域。**
*df_redlines_state = df_redlines_map.groupby(['state']).agg({'area': np.sum}).reset_index().rename(columns={'area': 'state_area'})
df_redlines_state.head()*

Figure 5
使用前面的计算,我们可以获得每个州内 HOLC 等级的百分比分布。
*df_redlines_state_details = df_redlines_map.groupby(['state','holc_grade']).agg({'area': np.sum}).reset_index().rename(columns={'area': 'holc_area'})
df_redlines_state_details = df_redlines_state_details.merge(df_redlines_state, on='state', how='left')
df_redlines_state_details['holc_ratio'] = df_redlines_state_details.holc_area/df_redlines_state_details.state_area
df_redlines_state_details.head()*

Figure 6
我们还可以计算每个邮政编码的相似值。
*df_redlines_details = df_redlines_map.groupby(['zipcode','holc_grade']).agg({'area': np.sum}).reset_index().rename(columns={'area': 'holc_area'})
df_redlines_details = df_redlines_details.merge(df_redlines[['zipcode','zip_area']], on='zipcode', how='left')
df_redlines_details['holc_ratio'] = df_redlines_details.holc_area/df_redlines_details.zip_area
df_redlines_details.head()*

Figure 7
正如我们将在后面看到的,一些有趣的可视化需要我们将等级值转换成特征。这允许我们计算每个区域内 A、B、C 和 D 分区的面积比,如下所示。我们用零填充缺失的比率值,以考虑没有 HOLC 区的邮政编码。
*for grade in ['A', 'B', 'C', 'D']:
df1 = df_redlines_map[df_redlines_map.holc_grade==grade].groupby(['zipcode']).agg({'area': np.sum}).reset_index().rename(columns={'area': grade + '_area'})
df_redlines = df_redlines.merge(df1, on='zipcode', how='left')
df_redlines[grade + '_ratio'] = df_redlines[grade + '_area'] / df_redlines.zip_areadf_redlines.fillna(0, inplace=True)*
这些比率帮助我们估计所谓的 HOLC 拒绝比率,定义为在 20 世纪 30 年代由于的红线而在一个邮政编码内被拒绝的贷款申请的百分比。假设 A 分区申请人的比率为 0%,C 和 D 分区为 100%,B 分区为 90%。我们选择 B 为 90%,因为它接近文献[ ][ ]中的平均拒绝比率。
*df_redlines['holc_reject_ratio'] = (.9*df_redlines.B_ratio + df_redlines.C_ratio + df_redlines.D_ratio)
df_redlines.head()*

Figure 8
红线勘探
下面的条形图显示,在 20 世纪 30 年代,HOLC 考虑的大多数地区被列为危险区或衰落区。
*redlines_labels = {'grade': ['A', 'B', 'C', 'D'],
'desc':['A - Best', 'B - Still Desirable', 'C - Definitely Declining', 'D - Hazardous'],
'color': ['g', 'b', 'y', 'r']
}
fig, ax = plt.subplots(1,1,figsize=(15,5))
sns.countplot(y='holc_grade',data=df_redlines_map, palette=redlines_labels['color'], ax=ax)
ax.set_title('Count of zones per grade');*

Figure 9
HOLC 划定的区域通常不太大,不到 5 平方公里。我们注意到很少有表面达到 180 平方公里以下的异常值。
*fig, ax = plt.subplots(1,1,figsize=(15,5))
sns.boxplot(y="holc_grade", x="area", palette=redlines_labels['color'],data=df_redlines_map, ax=ax)
sns.despine(offset=10, trim=True)
ax.set_title('Distribution of zone areas (km^2) per HOLC grade');*

Figure 10
根据 HOLC 在 20 世纪 30 年代的分类,阿拉巴马州和堪萨斯州的危险总面积最大。新罕布什尔州和印第安纳州的选区大部分被归类为绝对衰落。
*fig, ax = plt.subplots(1,1,figsize=(20,5))
sns.barplot(x="state", y="holc_ratio", hue='holc_grade', data=df_redlines_state_details, ax=ax)
ax.set_title('Holc Grade Ratio per state');*

Figure 11
贷款特征工程
在探索了红线数据之后,现在让我们来看看今天的贷款情况。在 2007 年第一季度和 2018 年第二季度之间收到的所有贷款申请都是从 Lending Club 网站下载的。这里引用的项目的作者向我们提供了合并和清理后的数据。
*df_loan = pd.read_csv('data/df_reject_ratio_2007-2018.csv')
df_loan.head()*

Figure 12
每个贷款申请由以下特征描述:
- issue_d :收到申请的日期。
- **邮政编码:申请人(借款人)邮政编码的 3 位数字。出于隐私考虑,Lending Club 不公布完整的邮政编码。
- **拒绝:如果申请被 Lending Club 拒绝,则标志值为 1,否则为 0。
- **等级:表示利率的类别(仅适用于未被拒绝的申请)。
根据每一份贷款申请和信用报告,每一笔贷款都被分配一个从 A 到 G 的等级和相应的利率每个贷款等级及其对应的当前利率显示在 Lending Club 网站上。
*print('There have been {} loans requests received at Lending Club since 2007, of which {} have been rejected'.format(df_loan.shape[0], df_loan[df_loan.rejected==1].shape[0]))
There have been 24473165 loans requests received at Lending Club since 2007, of which 22469074 have been rejected*
探索大型时间序列的一种常用方法是根据更大的时间单位(如季度)聚合感兴趣的特征。Lending Club 数据的一个问题是 issue_d 的格式,对于许多行来说是 YYYY-MM-DD,但是我们也可以找到格式为 b-YYYY 的日期。例如,我们看到 2007 年 5 月 26 日和 2011 年 12 月的行。将日期转换为季度时,最好对每种格式进行不同的处理。
具体来说,我们将数据分成两组,每种日期格式一组。
*df1 = df_loan[(df_loan.issue_d.str.len()==10)]
df1['issue_q'] = pd.to_datetime(df1.issue_d, format='%Y-%m-%d').dt.to_period('Q')
df1.head()*

Figure 13
*df2 = df_loan[(df_loan.issue_d.str.len()!=10)]
df2['issue_q'] = pd.to_datetime(df2.issue_d, format='%b-%Y').dt.to_period('q')
df2.head()*

Figure 14
现在,我们可以合并两个数据集。
*df_loan = df1.append(df2)*
我们进一步使用这些数据来计算 Lending Club 贷款拒绝率,定义为每个季度每个邮政编码被拒绝的贷款申请的百分比。
*df_loan_reject_ratio = df_loan[['issue_q','zip_code','rejected']].groupby(['issue_q','zip_code']).agg(['count', 'sum'])
df_loan_reject_ratio.columns = df_loan_reject_ratio.columns.droplevel(level=0)
df_loan_reject_ratio = df_loan_reject_ratio.rename(columns={'count':'lc_total_requested', 'sum':'lc_total_rejected'})
df_loan_reject_ratio['lc_total_accepted'] = df_loan_reject_ratio.lc_total_requested - df_loan_reject_ratio.lc_total_rejected
df_loan_reject_ratio['lc_reject_ratio'] = df_loan_reject_ratio.lc_total_rejected/df_loan_reject_ratio.lc_total_requested
df_loan_reject_ratio = df_loan_reject_ratio.reset_index()
df_loan_reject_ratio.head()*

Figure 15
上面的汇总表给出了每个季度和邮政编码的以下数量:
- lc_total_requested: 收到的贷款申请数量,
- lc_total_rejected: 拒绝的贷款申请数,
- lc_total_accepted: 接受的贷款申请数,
- LC _ reject _ ratio:LC _ total _ rejected*与 lc_total_requested 的比率。*
类似地,我们计算 Lending Club 贷款等级比率(每个邮政编码和季度特定利率的贷款百分比)。
*df_loan_grades = df_loan[df_loan.rejected==0][['issue_q','zip_code','issue_d']].groupby(['issue_q','zip_code']).count().reset_index().rename(columns={'issue_d':'total_accepted'})for grade in ['A', 'B', 'C', 'D', 'E', 'F', 'G']:
df1 = df_loan[(df_loan.rejected==0)&(df_loan.grade==grade)][['issue_q','zip_code','issue_d']].groupby(['issue_q','zip_code']).count().reset_index().rename(columns={'issue_d': 'LC_' + grade + '_accepted'})
df_loan_grades = df_loan_grades.merge(df1, on=['issue_q','zip_code'], how='left')
df_loan_grades['LC_' + grade + '_ratio'] = df_loan_grades['LC_' + grade + '_accepted'] / df_loan_grades.total_accepted*

Figure 16
例如, LC_A_accepted 是被接受并被分配利率 A 的申请数量。 LC_A_ratio 是相应的百分比。
贷款和标记数据合并
我们现在准备合并贷款和红线数据,允许我们尝试不同的可视化,并在查看 2007-2018 年的“贷款与红线”时提出有趣的问题。
因为 Lending Club 只披露了申请人邮政编码的 5 位数中的 3 位数,所以我们必须根据 123xx 邮政编码模式对数据进行汇总和合并。
*df_redlines[‘zip_code’] = df_redlines[‘zipcode’].astype(‘str’)
df_redlines[‘zip_code’] = df_redlines[‘zip_code’].str.pad(5, ‘left’, ‘0’)
df_redlines[‘zip_code’] = df_redlines[‘zip_code’].str.slice(0,3)
df_redlines[‘zip_code’] = df_redlines[‘zip_code’].str.pad(5, ‘right’, ‘x’)
df_redlines_aggr = df_redlines.fillna(0).groupby('zip_code').agg({'zip_area': np.sum,
'A_area': np.sum, 'B_area': np.sum, 'C_area': np.sum, 'D_area': np.sum, 'A_ratio': np.mean,'B_ratio': np.mean,'C_ratio': np.mean,'D_ratio': np.mean,'holc_reject_ratio': np.mean}).reset_index()df_redlines_aggr.head()*

Figure 17
上表显示了 HOLC 在 20 世纪 30 年代对 A、B、C 或 D 区域的总面积(km2 ),这些区域由一个 123xx 邮政编码模式表示,其中 123 是 Lending Club 公布的邮政编码数字的代表数字。还提供了每个 HOLC 等级的总面积比以及总 HOLC 剔除率。
继续这个聚合的红线数据集,我们现在将添加贷款数据。对于缺少贷款数据或标记数据的 123xx 地区,空比率替换为 0。
*df_redlines_loan = df_loan_reject_ratio.merge(df_loan_grades, on=['zip_code','issue_q'], how='left').merge(df_redlines_aggr, on='zip_code', how='left')
df_redlines_loan.issue_q = df_redlines_loan.issue_q.astype('str')
df_redlines_loan.fillna(0, inplace=True)
df_redlines_loan.head()*

Figure 18
结果
看下面的线图,我们可以看到 Lending Club 平均拒绝的贷款比 HOLC 在 20 世纪 30 年代拒绝的要多。我们可以预料,将来拒收的数量会进一步增加。
*fig, ax = plt.subplots(1,1,figsize=(15,5))
sns.lineplot(x="issue_q", y="lc_reject_ratio",data=df_redlines_loan, ax=ax, label='LendingClub reject ratio')
plt.axhline(df_redlines_loan[df_redlines_loan.holc_reject_ratio>0].holc_reject_ratio.mean(), color='r', label='HOLC reject ratio')
plt.axhline(df_redlines_loan.lc_reject_ratio.mean(), color='black', label='LendingClub reject ratio Average')
plt.xlabel('quater')
plt.ylabel('ratio')
plt.title('Average Loan Reject Ratio over time')
plt.legend()
plt.xticks(rotation=45);*

Figure 19
下面的散点图显示了 Lending Club 和 HOLC 的贷款拒绝率之间的正相关关系。这表明了以下假设:在 20 世纪 30 年代,HOLC 拒绝大部分或几乎所有贷款的地区,也是 Lending Club 今天可能拒绝大量贷款的地区。
*fig, ax = plt.subplots(1,1,figsize=(15,5))
sns.scatterplot(x=’lc_reject_ratio’, y=’holc_reject_ratio’, data=df_redlines_loan[df_redlines_loan.holc_reject_ratio>0], ax=ax)
plt.title(‘Loan Reject Ratio per zipcode — LendingClub versus HOLC’);*

Figure 20
如下面的 distplot 所示,Lending Club 拒绝率分布似乎复制了 HOLC 在大面积地区的拒绝率分布,这些地区在 20 世纪 30 年代被划分为危险或明确拒绝贷款。
*fig, ax = plt.subplots(1,1,figsize=(15,5))
sns.distplot(df_redlines_loan[df_redlines_loan.holc_reject_ratio>0].holc_reject_ratio, color='r', hist = False, kde = True, kde_kws = {'shade': True, 'linewidth': 3}, label='HOLC', ax=ax)
sns.distplot(df_redlines_loan[df_redlines_loan.holc_reject_ratio>0].lc_reject_ratio, color='g', hist = False, kde = True, kde_kws = {'shade': True, 'linewidth': 3}, label='LendingClub', ax=ax)
plt.xlabel('ratio')
plt.title('Loan Reject Ratio Distribution over zipcodes');*

Figure 21
从下面的热图来看,HOLC 和 Lending Club 特征之间的相关性非常弱。这可能意味着,一般来说,知道一个地区的 HOLC 等级并不能帮助我们自信地预测 Lending Club 的贷款拒绝或贷款利率。
*corr = df_redlines_loan.corr()
mask = np.zeros_like(corr, dtype=np.bool)
mask[np.triu_indices_from(mask)] = True
f, ax = plt.subplots(figsize=(11, 9))
cmap = sns.diverging_palette(220, 10, as_cmap=True)
sns.heatmap(corr, mask=mask, cmap=cmap, vmax=.3, center=0,
square=True, linewidths=.5, cbar_kws={"shrink": .5})
ax.set_title('Correlation between HOLC and LendingClub');*

Figure 22
下面的分布图表明,几乎没有贷款俱乐部申请人在红线区获得最低利率(A)。大多数申请人获得中等利率(B、C 或 D)。只有少数申请人不得不面对非常高的利率(E、F 或 G)。这种分布表明,Lending Club 在评估信贷冲销风险时可能不会考虑红线。
*f = df_redlines_loan[(df_redlines_loan.holc_reject_ratio==1)&(df_redlines_loan.lc_reject_ratio!=1)].sort_values(by='lc_reject_ratio', ascending=False).reset_index()[['zip_code', 'holc_reject_ratio', 'lc_reject_ratio', 'LC_A_ratio', 'LC_A_ratio', 'LC_B_ratio', 'LC_C_ratio', 'LC_D_ratio', 'LC_E_ratio', 'LC_F_ratio', 'LC_G_ratio']]*

Figure 23
结论
我们的研究为借贷俱乐部的现代划红线提供了一些证据。1930 年代的红线图和今天的贷款俱乐部接受贷款请求和评估违约风险的政策之间存在内在联系的假设仍然有效。
Lending Club 使用的数据中有一些不公平算法或历史偏见的迹象。从我们的探索性数据分析中可以清楚地看到这一点,尤其是 HOLC 拒绝率和 Lending Club 拒绝率之间的正线性趋势。
感谢您阅读至此。
在本系列文章的第二部分中,我们将使用 Geopandas 在美国的地理地图上显示红线区域、贷款拒绝率和贷款利率分布。这将包括一个用于空间时间序列可视化的 choropleth 地图动画,显示 2007 年至 2018 年间 peer-2-peer lending 的地理景观在红线方面如何演变。
文献学
库特曼切,c .,斯诺登,K. (2011 年)。修复抵押贷款危机:HOLC 贷款及其对当地住房市场的影响。《经济史杂志》,第 71 卷第 2 期,第 307-337 页。
[ ]菲什巴克,p .,弗洛雷斯-拉古内斯,a .,霍拉斯,w .,坎特,s .,特雷伯。J. (2010)。20 世纪 30 年代房主贷款公司对住房市场的影响。金融研究评论,24(6),1782 年至 1813 年。
用数字工具绘制知识图谱,解决 21 世纪的医疗保健问题
托普塔尔奖学金赋能未来女性领导者的论文
介绍
当我在医学、学术研究和生物技术领域旅行时,我清楚地认识到,从业者和研究人员正在努力应对我们今天面临的复杂的健康挑战。这些健康问题需要超越生理学和生物化学的理解,因为疾病还受到社会和文化的影响。此外,我们还生活在一个以不断变化的气候和生物多样性丧失所加剧的新情况为特征的时代,当涉及到对人类健康的影响时,我们仍然难以完全理解这些因素。

The effects of climate change and loss of biodiversity on human health cannot be understood by reductionist scientific enquiry alone.
在理想的世界中,我们创造的知识和解决方案应该足以解决这些复杂的问题。不幸的是,纯粹的信息过载使获得一个概览成为一项艰巨的任务,导致大多数研究人员退缩到专业的筒仓中,从职业的角度来看,这些筒仓更容易管理,也更安全。
所有这一切让我意识到,我们今天面临的复杂的健康挑战无法通过当前推动医疗保健研究和知识创造的过程来解决。如果我们要创造持久的解决方案,作为研究人员,我们必须理解更大的图景,获得当今时代导致疾病的许多观点的概述,并将这些观点纳入我们的研究。
在寻找工具和方法来整合健康问题固有的不同观点的过程中,我继续探索远离科学和医学舒适区的领域。第一个是设计思维,或以人为中心的设计。作为斯坦福大学设计研究中心的访问学者,我每天都在学习设计师如何解决问题,并参与了许多设计项目。这一经历让我意识到使用设计方法探索复杂问题空间和以不同方式构建问题的可能性。
虽然设计方法对于创建医疗保健实际挑战的解决方案,甚至帮助组织转型非常有用,但我仍然缺乏获得研究信息概览的方法,而这对于开始更下游的设计过程是必要的。在这种需求的驱动下,我开始冒险进入另一个远远超出我最初专业知识的领域,一个将我带入算法和网络世界的领域。
测绘知识
众所周知,人类大脑处理视觉信息的效率远远高于书面信息,这种现象与大脑同时处理多个视觉信息的能力有关,而不是一次处理一个单词。尽管如此,大多数科学出版物和数据库都严重依赖书面信息。由于无法可视化,研究人员只能在长长的出版物列表中滚动,无法立即获得某个领域的概况。事实上,我遇到的大多数研究人员除了偶尔在一篇研究文章上乱涂乱画,然后存档,再也不会被看一眼之外,没有任何可视化的方法来跟踪他们领域的研究。一些新的 web 应用程序(如 Dimensions 和 Meta)稍微改进了这一过程,尽管数据仍然以长列表的形式呈现,而不是可视化。
在与一位从事图形数据库和网络工作的数据科学家讨论后,我偶然发现了映射的概念。从那里,我发现从事分析科学本身的个人,如科学计量学和科学知识社会学的人,一直在使用机器学习和数据提取技术的工具来绘制知识的演变。尽管如此,在这些专门的亚群体之外,很少有人敢于超越理论领域,将他们的发现付诸实际应用,这使得大多数研究人员、从业人员和政策制定者不太重视这些发现。这可能是解释为什么那些研究科学的人和那些实际实践科学的人之间很少交谈的一个原因。
与数据科学家一起,我们开始探索绘制结核病领域的地图,以找出这种方法可以带来什么。在这个过程中,我们发现许多免费工具要么太复杂,非数据科学家无法使用,要么缺乏复杂性,无法回答我们感兴趣的问题。通过我们的探索,我们开始开发自己的工具,使我们能够直观地浏览网络,并以有趣和创造性的方式处理数据。
将知识网络可视化使我能够从数据中获得洞察力,这在以前是不可能的。例如,使用我们新创建的工具来探索结核病领域的引用网络,很明显该领域正在朝着一个非常独特的方向发展,随着时间的推移,明确的研究领域被放弃。随着调查的深入,废弃区域被发现为结核病诊断区,由于该领域资金缺口巨大,世卫组织最近将该领域确定为优先领域。我们创建的可视化使我们能够在概览中看到这一差距,而无需手动梳理大量文献,我们相信这可以以更有效的方式促进决策者的战略进程。这种类型的分析也与研究人员相关,他们可能能够在更大的领域背景下可视化他们的研究,甚至识别最近被遗忘的潜在有趣的研究,如在中看到的这个例子。

A static screenshot of the interactive citation network using the tool we developed. The program allows users to scroll over each node (research article) and obtain details as well as visualize its direct connections within the network. The network can be seen to have a shape, which tells us that as new articles are published, older ones are no longer being cited. We can observe a clear area that had been thinning out over time, which in this case, corresponded to articles discussing TB diagnostics.
从那时起,通过使用我们的工具,我分析了合作网络中的模式,揭示了学术界和工业界之间的不同合作动态,以及目前处于边缘地位但代表未开发潜力的新兴研究领域。

Analyzing collaboration networks revealed clearly the disconnect between industry and academia in the field of multi-drug resistant tuberculosis. Here, a small cluster involving Johnson and Johnson’s pharmaceutical arm, Janssen Pharmaceuticals can be seen to be disconnected from the main research network.
为了理解围绕健康话题的更广泛的背景,我还分析了围绕结核病和全球健康话题的 twitter 网络,它提供了围绕这些主题的生态系统和观点的广泛概述。

Examining a twitter network reveals the ideas that are spreading and how they are inter-connected within a health topic, in this case, global health. It gives us an idea about the discourse, or the issues that are important in the community; knowledge that cannot be gathered from official research articles.
随着时间的推移,通过这项工作,一个愿景开始出现,一个我觉得令人兴奋且深具意义的愿景。重要的是,我认为这是一个愿景,它解决了知识创造和利用方式中的一个主要差距,因此可能具有深远的潜力,以我们尚未完全预见的方式转变科学进步并造福社会。
视力
你是一名研究人员,需要决定你的下一个调查,以便写下你将要申请的资助。或者,你可能是一个政策制定者,他需要决定是否有更多的钱需要分配给某个特定的领域。你也可以是一名设计师,与当地的流行病学家一起工作,寻求建立一个更好的系统来识别传染病爆发的源头。
在每一种情况下,你的下一步将取决于你对你将要从事的领域的理解和综合能力。这一过程通常需要几个小时、几周甚至几个月的时间来研究这个主题,以便对这个主题的所有可能的角度有一个全面的了解。

Fancy reading through these articles anyone?
现在想象一下另一个现实,点击几下鼠标,你会发现自己在浏览你感兴趣的主题的交互式视觉概览。然后,你迅速确定差距和追求的机会,引导你创建一个合理的和原创的战略或研究方向。当需要时,你现在可以将你更深入的研究锁定在一个非常具体的领域,而不必浪费无数的时间去挖掘不相关的信息。最重要的是,你意识到这是如此有趣,以至于你不断探索,直到你偶然发现一个有趣的见解,让你问了一个你以前从未想过的问题。顺便说一句,这个问题导致了改变生活的疗法或神奇产品的发展,它改变了整个社会人们的健康状况。
如果这个愿景让你兴奋,那么我会说这不是一个遥远未来的愿景。使这成为现实的工具和技术已经存在,而我今天的任务,就是把它引入你们的世界,并为了更大的利益改变我们利用知识的方式。

Data sources that can be used will originate from diverse sources and will be subjected to the same processing to create infoscapes that allow the investigator to play with the visualizations and extract insights.
履行
我们的工具目前处于开发的最后阶段,我们预计我们将能够在年内公开这一点。作为一名非技术(数据科学家)联合创始人,我的职责是在数据科学和医疗保健研究之间架起一座桥梁。为了做到这一点,我打算与该领域的专家建立合作关系,并用现实世界的问题创建用户研究。潜在的合作者已经确定,项目将在未来几个月启动。用户研究对于获得重要反馈至关重要,它将使我们能够进一步改进产品。
仅仅开发一个数字工具是不够的,而不开发使用它的技术。因此,我致力于开发一种方法,允许对数据进行更系统的调查。从这项工作中获得的一些见解可以在这里看到。在接下来的几个月里,我将继续研究这种方法,并对其进行微调,以创建一个完整的框架,供用户在探索数据时参考。
由于我们目前自筹资金,没有外部资金来源,下一步将是积极寻求和确保进一步开发该工具的资金。用户研究将是我们吸引合作伙伴或投资者能力的重要组成部分。尽管我们已经制定了业务计划,确定了增长潜力,并将我们的工具与潜在的竞争对手区分开来,但该计划需要进一步完善,才能更有影响力。
需要明确的是,这个项目的目标不是简单地启动一个创业公司来推广一个产品。该项目旨在通过确保有价值的知识不会迷失在信息的海洋中,确保社会从多年的科学研究中获得最大收益。因此,可能还有其他途径有待探索,以使这一愿景成为现实。
例如,这可能是一个咨询服务的路线,该服务将与产品一起提供,由我领导,以确保用户从使用该工具中获得最大利益。
成为女性领导者
2018 年,我参加了在巴塞罗那举行的 EIT Health 增强女性在健康创新方面的领导力研讨会。在这次研讨会期间,我意识到女企业家在企业家世界中的代表性不足的程度。我还了解到,有抱负的女性企业家应该寻求的最重要的东西之一是导师,而这正是我目前努力的方向。
使 Toptal 的提议特别相关的是它提供的指导支持。我认为,导师不仅仅是传授技术建议,对我来说更重要的是,它是从以前走过这条路的其他人的经验中学习。我理想的导师是一位探索过不同职业道路的女性领导者,从与企业合作到创办自己的企业或咨询公司。独立工作意味着大部分时间要么花在自己身上,要么花在与其他团队成员讨论上,这导致获得外部意见的机会很少。在我职业生涯的这一关键时刻,与导师进行定期讨论不仅能鼓舞士气,还能极大地增强我的观点和视野,并拓宽我的视野,让我能通过其他途径将这一愿景变为现实。
改变世界是一项艰巨的任务,单靠自己是无法完成的。只要有一点帮助,这个想法的种子就可以发芽,形成一个复杂的连接网络来维持它,并开花成为一棵宏伟的树。

The tree of knowledge 😃
使用 Python 绘制多伦多已报告坑洞的位置图
通过开放数据从 311 多伦多收集数据,用于可视化报告的坑洞。
欢迎来到我的第一个教程,可视化多伦多周围的坑洞的位置。我叫 Mumtahin,是一名数据科学专家,目前在加拿大支付行业工作。数据分析和数据科学项目的最大技能包括理解数据准备。为分析/研究收集数据所需的工作量因手头的任务而异。本教程的目的是提供清理数据和图形化表示数据的基本介绍,因为这是我日常工作的一个重要方面。
对于本教程,我们将从由 open data (由多伦多市维护)提供的可公开访问的 API 端点获取 JSON 格式的结构化数据。你可以通读这篇文章,并了解一步一步的过程,或者如果你熟悉下面的概念,请随意使用我的 Github 资源库中的 Jupyter 笔记本进行自己的探索!
入门指南
对于本教程,请确保您安装了 Python 3 版本。我用的是 Python 3.6.6。
如果您想安装并运行我的 Jupyter 笔记本,请确保您已经安装了 Jupyter 笔记本。关于设置 Jupyter 笔记本的简短的初学者友好教程,请点击这里。
安装所需模块
- 熊猫(我用的是 0.24.1 版本)
- matplotlib(我使用的是 3.0.2 版本)
- mpl 传单
导入模块
构建我们的查询
我们有一个由 311 多伦多提供的 API 端点命中。首先,我们需要构造一个查询,其参数反映了我们实际需要的信息。我们将要连接的 API 包含了各种主题的数据,例如垃圾收集、涂鸦清除和其他城市服务的报告数据,以及我们想要的实际坑洞数据。对我们来说,查询是没有意义的,而且可能会使服务器陷入困境,去获取我们一开始就不想要的信息。
到目前为止,我们知道些什么?我们知道我们只需要与报告的坑洞相关的数据。根据 311 发布的 README 文档并查看开放数据目录,我们还了解到以下信息:
- API 记录限制:一次 1000 条记录
- 坑洞修复请求有一个服务代码:c rowr-12
- jurisdiction_id 将始终为“toronto.ca”
- agency_responsible:始终设置为 311 Toronto
- service_notice:未退回
- 邮政编码:未返回
我们需要什么?
- 我们需要决定开始和结束日期范围来构造我们的查询。
选择日期范围并使用 API 限制
当决定一个日期范围时,很难选择一个有意义的时间向我们展示有价值的结果。因为我们的分析是关于坑洞的,一些关于坑洞成因的先验知识会有所帮助。在深度冻结和解冻期间,会导致路面出现裂缝,这是造成坑洞的原因。当我写这篇文章的时候,多伦多正在经历冰冻和解冻的时期,导致这个城市经历了比平常更高的报告。基于这些知识,查看最近 4 个月的数据会很有趣。
假设我们需要 4 个月的数据,记住为 API 响应设置的最大记录限制是很重要的。311 Toronto API 在其响应对象中有 1000 条记录的限制。使用 API 时有大小限制或速率限制是相当常见的。这是一种确保 311 Toronto 的服务器不会因试图满足大量请求而过载的方法,并且可以提供良好的服务质量。为了遵守 1000 条记录的限制,我首先抽查了不同月份的记录总数。我发现一个月的平均数据低于 1000 条记录的限制。考虑到最近该城市的报告比平时多,我们的数据可能会受到限制,但我们仍然应该有足够的数据点用于我们的可视化。我们将我们的日期范围(4 个月)划分为 29 天的时间段,并对这 29 天的每个时间段进行同步请求。
现在我们有了一个将日期分块的函数,我们将继续选择开始和结束日期。我们知道,在冬末和春季的冰冻和解冻季节,坑洞是有问题的。知道了这一点,看看今年冬天的数据会很有趣,因为我们有一些交替的寒冷和温暖的日子。我们在下面定义了我们的日期参数,但是你可以随意从我的 Github 中获取这个笔记本,并更改日期以获得更多信息。如果您在我的存储库中运行该笔记本,或者基于本教程创建您自己的版本,请随意调整日期范围。
使用上面写的函数,我们有一个反映日期范围块的日期列表。从这个列表中,我将把每个偶数索引项作为我的开始日期,每个奇数索引项作为我的结束日期。
[datetime.datetime(2018, 11, 1, 0, 0),
datetime.datetime(2018, 11, 30, 0, 0),
datetime.datetime(2018, 12, 1, 0, 0),
datetime.datetime(2018, 12, 30, 0, 0),
datetime.datetime(2018, 12, 31, 0, 0),
datetime.datetime(2019, 1, 29, 0, 0),
datetime.datetime(2019, 1, 30, 0, 0),
datetime.datetime(2019, 2, 28, 0, 0),
datetime.datetime(2019, 3, 1, 0, 0),
datetime.datetime(2019, 3, 4, 0, 0)]
我们在上面的输出中看到,第一个范围是 2018–11–01 到 2018–11–30。第二个范围是 2018–12–01 到 2018–12–30 等等。我们看到每个偶数位置(0,2,4 等。)是开始日期,奇数位置的项目是结束日期。
提出 API 请求
基本网址:https://secure.toronto.ca/webwizard/ws/requests.json?
使用 311 自述文件中已知的参数,我们可以添加 service_code、jursidiction _ id、start_date 和 end_date 等参数。我们的 API 请求将从上面获取每个开始和结束日期范围分区。我们总共会做 5 个。
现在我们有了一个巨大的列表(data_clob ),其中包含了返回结果的嵌套 JSON,我们看到每个条目都以关键字“service_requests”开头。我们对每个“服务请求”的价值感兴趣。
查看熊猫数据框架中的数据
熊猫可以从 csv、字典、列表、SQL 查询等一系列格式中读取您的数据,并将其放入数据框中。如果您研究这个数据框架,您可以看到我们有一些重要的列,如 long(经度)和 lat(纬度)。
更多清洁
根据自述文件中的信息,我们可以删除以下几列:“机构 _ 责任”、“服务 _ 通知”和“邮政编码”。

计算所需的调查天数和维修天数
我们可以根据“requested_datetime”和“updated_datetime”之间的时间差来计算调查报告的预计天数。“expected_datetime”似乎表示修补坑洞的预期日期,但它通常由一个固定的日期值填充。对于某些报告,我不确定这种自动填充背后的原因是什么。
在下面的要点中,我获取 requested_datetime、updated_datetime 和 expected_datetime 的字符串日期值,并使用 pandas 的 to_datetime 方法将其转换为 datetime 对象(第 4、5 和 6 行)。
一旦我们有了数据框架,我们就可以计算调查和维修所需的平均天数。使用这些平均值,我们设置一个阈值来决定服务请求是慢还是快。
使用上面的分类,我们用 mplleaflet 对应的经度和纬度来绘制坑洞的位置。
- 比平均响应/调查慢(地图上的蓝点)
- 比平均响应/调查更快(地图上的黑点)
- 比平均修复速度慢(地图上的红色方块)
- 比平均修复速度更快(地图上的绿色方块)
上面的文件保存为 HTML 格式,其中包含我们最终的可视化。
您可以在这里查看互动结果:http://www.mmonzoor.com/pot_holes.html
结论
到目前为止,我们已经学习了如何使用 JSON 对象等结构化数据,通过 GET 请求进行 API 调用,使用 pandas 清理数据,以及通过 matplotlib 可视化清理后的数据。现在你有了一个清晰的数据框架,可以随意调查你可能对你的城市有疑问的问题。如果你所在的城市有像 311 Toronto 这样的开放数据目录,试着模仿这个教程,也许你会发现一些有趣的见解!我希望这个教程是有帮助的,我愿意尽我所知回答任何问题,所以请随意评论。
GitHub 知识库
[## mmonzoor/introductive _ pot _ hole _ viz
在 GitHub 上创建一个帐户,为 mmonzoor/introductive _ pot _ hole _ viz 开发做贡献。
github.com](https://github.com/mmonzoor/introductory_pot_hole_viz)
将机器学习服务从 AWS 映射到 Google Cloud 再映射到 Azure
AWS、谷歌云和 Azure 的不同机器学习相关云服务列表。谷歌已经提供信息来帮助人们从 AWS 或 Azure 迁移
https://cloud . Google . com/free/docs/map-AWS-Google-cloud-platformhttps://cloud . Google . com/free/docs/map-azure-Google-cloud-platform
微软也提供了类似的对比—https://docs . Microsoft . com/en-us/azure/architecture/AWS-professional/services
下面的列表是基于上述链接,我添加了 AWS 和 Azure 服务的链接。
语音转文字——亚马逊转录|*|云语音转文字||天蓝色语音转文字*
文字转语音——亚马逊波利 | 云文字转语音||天蓝色文字转语音
对话式 AI — 亚马逊 Lex | 谷歌 dialog flow|*Azure LUIS*
视频智能——亚马逊 Rekognition|*|云视频智能 | Azure 视频索引器*
AutoML—NA|*|Cloud AutoML(beta)||Azure ML Studio*
完全托管 ML——亚马逊 SageMaker | 云机器学习引擎 | Azure ML 服务
亚马逊最近推出了一些新服务,如用于时间序列预测的亚马逊预测和用于创建推荐系统的亚马逊个性化,目前谷歌云和 Azure 都没有类似的服务。
在命名服务方面,亚马逊有最好的名字,如 Polly、Lex 等:)。我认为谷歌和 Azure 应该开始更好地命名他们的服务:)
*[## 将 AWS 服务映射到谷歌云平台产品|谷歌云平台免费层|谷歌云
如果你熟悉亚马逊网络服务(AWS),快速了解各种谷歌云平台…
cloud.google.com](https://cloud.google.com/free/docs/map-aws-google-cloud-platform)* *[## 将 Microsoft Azure 服务映射到 Google 云平台产品| Google 云平台免费层|…
如果你熟悉微软 Azure 服务,快速了解各种谷歌云平台…
cloud.google.com](https://cloud.google.com/free/docs/map-azure-google-cloud-platform)* * [## AWS 与 Azure 服务对比——Azure 架构中心
这篇文章帮助你理解微软 Azure 服务与亚马逊 Web 服务(AWS)的比较。无论你是…
docs.microsoft.com](https://docs.microsoft.com/en-us/azure/architecture/aws-professional/services)*
映射混乱的地址第 1 部分:获取纬度和经度

我的家乡多伦多有幸拥有北美唯一一个大型有轨电车网络,它在战后的街头铁路仇杀中幸存了下来。多伦多的有轨电车是整个快速交通系统的重要组成部分。然而,他们有一个明显的弱点——如果一辆电车被堵了,其他电车就不可能绕过它,所以电车延误有可能引发交通堵塞。我一直在研究一个模型,该模型使用一个公开的关于有轨电车延误信息的数据集来预测和帮助防止这种延误。

Streetcar delays can cause gridlock (photo by author)
电车延误数据集包括自 2014 年 1 月以来系统中每次延误的详细信息,包括延误的时间、持续时间和位置。

Streetcar delay dataset
问题是:杂乱的地址
位置字段完全是非结构化的-交叉点以多种格式表示(“Queen and Sherbourne”、“queen/sherbourne”),街道和地标的指示不一致。

例如,单个地标可能出现在具有多个不同位置值的数据集中:
- 朗塞斯瓦勒斯场
- 朗西场
- 朗克。车房。
我需要可视化延迟的位置,以了解网络的哪些部分最容易出现拥堵。为了可视化位置,我需要将它们转换成纬度和经度值。在本文中,我描述了如何从输入数据集中杂乱的位置获取纬度和经度值。在本系列的下一篇文章中,我将描述如何使用这些纬度和经度值来生成地图以可视化延迟模式。
解决方案第 1 部分:清理位置值以减少冗余
在尝试获取纬度和经度值之前,我开始对位置值进行一些老式的清理,包括:
-
将所有位置值设置为小写
-
替换用多个字符串表示的公共值,包括不一致的街道名称,并对所有交汇点使用一致的连接:
-
应用一个函数为交叉点处的街道名称提供一致的顺序,以避免冗余,如“皇后和宽景”/“宽景和皇后”:
这些简单的清理将唯一位置的数量减少了 35%,从 15.6 k 减少到 10 k 多一点。正如我们将看到的,减少唯一位置的数量意味着对 API 进行更少的调用来将位置转换为经度和纬度值。Google 地理编码 API 每 k 次调用的成本为 5.00 美元,所以我通过减少唯一位置的数量节省了 25 美元。
解决方案第 2 部分:使用 Google 地理编码 API 获取纬度和经度值
我决定使用 Google 地理编码 API 来获取纬度和经度值。这一过程没有我预想的那么简单,我希望如果您使用地理编码 API,您可以从我学到的经验中受益,如下所述。
以下是我在从 Python 调用地理编码 API 之前必须采取的步骤:
- 在 Google Cloud 中建立一个项目。我按照说明这里。
- 查看地理编码 API 介绍材料,并按照其中的说明(1)为您的谷歌云项目激活地理编码 API,以及(2)获取地理编码 API 的 API 密钥
- 查看用于谷歌地图服务的 Python 客户端自述文件,了解如何从 Python 调用地理编码 API 的说明
要准备从 Python 调用地理编码 API:
- 安装客户端
! pip install -U googlemaps
2.将您的 API 键与地理编码 API 客户端相关联,并调用地理编码 API 获取已清理数据集中的样本地址:“lake shore blvd. and superior st .”请注意,传递给地理编码 API 的地址包括数据集中的位置和城市(数据集中所有位置的城市均为“多伦多”)。
3.检查返回的纬度和经度以确认它与输入地址匹配:


Latitude and longitude returned by the Geocoding API match the input location
既然我们已经验证了从位置值到纬度/经度再回到地址的往返过程,那么在我们能够转换整批位置值之前,还有一些障碍需要克服。
障碍#1:地理编码 API 在看似无辜的位置值上受阻
地理编码 API 阻塞了一些位置值,但不是我预期的位置值。我天真地试图通过发送垃圾地址“asdfasdfjjjj”来测试 API,并得到非空的 JSON:
然而,当我试图转换一批位置时,它在一个看起来不错的位置值上失败了:“roncesvalles to neville park”
为了可靠地转换一批位置,我必须将地理编码 API 调用封装在一个函数中,该函数检查返回的列表是否为空,如果是,则返回占位符值:
障碍 2:默认的每日 API 限制对于我需要转换的一批位置来说太小了
使用定义为可靠地调用地理编码 API 的 get_geocode_result 函数,我准备好进行批处理运行来转换位置值。为了最小化对 API 的调用,我定义了一个新的数据帧 df_unique ,它只包含唯一的位置值:
然而,当我调用 get_geocode_result 函数向 df_unique 数据帧添加纬度和经度值时:
我收到以下错误消息:
在谷歌云控制台中检查我的项目的配额页面,我可以看到我每天对地理编码 API 的调用限制只有 1400 次。这就是为什么当我试图为值超过 10k 的 df_unique 数据帧调用 API 时,会出现 OVER_QUERY_LIMIT 错误。

为了增加我对这个项目的地理编码 API 调用的每日限额,我必须向 Google Cloud support 开一张罚单,要求提高我对地理编码 API 的每日限额:

进行批处理运行以将位置转换为经度和纬度
随着我的每日地理编码 API 限制的提高,我能够在 df_unique 数据帧上无错误地调用 API。1.5 小时后(表示大约 110 次 API 调用/分钟),我得到了一个数据帧,其中包括所有不同位置的纬度和经度值:

接下来,我在 df_unique 数据帧中创建不同的经度和纬度列,然后用 df_unique 连接原始数据帧:
最后,我有一个数据帧,包含所有原始数据以及与位置值对应的纬度和经度值:

摘要
下面总结了获取纬度和经度值以对应原始数据集中所有混乱位置所需的步骤:
- 清理原始数据集以移除冗余位置并减少唯一位置的数量
- 通过在 Google Cloud 中创建一个项目,获取一个 API 密钥,并为 Google Maps 服务设置 Python 客户端,设置 Python 对 Google 地理编码 API 的访问
- 使用地址(位置和城市)调用地理编码 API,并解析返回的 JSON 以获得纬度和经度。检查返回空列表的 API,如果您要转换的不同位置的数量大于默认的每日限制,请使用 Google Cloud 支持打开一个票证以获得增加的每日 API 限制。
在本系列的下一篇文章中,我将描述如何使用这些纬度和经度值来生成地图,以可视化来自原始数据集的延迟模式。
如果您想亲自尝试本文中描述的代码:
- 将位置转换为纬度和经度的主要笔记本是这里的。您将需要获得自己的 API 密钥来运行它。
- 你可以在这个笔记本上使用的输入数据帧的一个例子是这里的。请注意,该数据帧中的位置值已经被清除(小写,街道名称以一致的顺序),如上文解决方案第 1 部分:清除位置值以减少冗余一节所述。
绘制混乱的地址第 2 部分:来自叶的见解

Toronto streetcar delay heat map
在本系列第一篇文章的中,我描述了多伦多有轨电车延迟数据集,并经历了从具有不精确、混乱的位置值的原始数据集获取所需的步骤:

到包含所有位置的纬度和经度值的数据帧:

在本文中,我将回顾使用第一篇文章中的纬度和经度值获得延迟数据的地图可视化的步骤。
映射镜头 1:像素化灰尘
我第一次尝试可视化包括纬度和经度的数据集时,我决定使用像素化数据。
安装并导入 Pixiedust 后,显示数据框:
使用键纬度和经度和数值最小延迟:

选择简单的聚类风格,我得到如下的地图:

Some streetcar delay locations are obviously not correct
来自 Pixiedust 可视化的一些观察:
- 加纳以南的大西洋中的值位于本初子午线和赤道的交点(纬度/经度= 0.0/0.0)。在这些位置,地理编码 API 返回一个空列表,上一篇文章中描述的 get_geocode_result 函数返回一个占位符值。
- 在绘制的 10 k 个位置中,超过 97k 个位于多伦多地区,并且是有轨电车延迟的潜在有效地点。

- 除了多伦多地区的 9.7 k 个位置和[0.0,0.0]处的 238 个值之外,在世界其他地方有 43 个位置明显不符合有轨电车延迟的有效地点。

This “Toronto” streetcar is in San Francisco, but the dataset only covers Toronto (photo by author)
说完,我基本上用尽了我能用 Pixiedust 得到的东西。虽然 Pixiedust 没有给我想要的一切,但它确实提供了一些非常快速的见解,有助于节省时间。
贴图拍摄 2:叶子
在穷尽了我可以从 Pixiedust 获得的东西之后,我转向了follow,这是一个在 Python 的上下文中很容易利用 fleet . js 库的设施的库。
Pixiedust 可视化显示有轨电车网络上存在合法延迟位置之外的值。为了准备使用,我删除了位于有轨电车网络边界之外的记录。这将数据集的大小减少了 6.5%,只有 65 k 条记录。

Bounding box for valid streetcar delays
您可能想知道为什么街道网格不与边界框对齐。多伦多街道网格大致垂直于市中心的安大略湖海岸线,因此网格相对于由纬度和经度定义的边界框向左扭曲。
回到代码—现在我们已经准备好安装和导入 Folium 了:
然后,我们可以创建一个简单的映射,显示数据集中前 2.5 k 条记录的延迟聚类:
这是生成的地图,它让我们了解了城市不同区域延误的相对集中程度:

我们可以放大到西部市区。注意女王街西的热点,在巴瑟斯特和奥辛顿之间,由三一贝尔伍兹公园南边的伯爵指示。

放大来仔细观察热点,很明显,公园南面的皇后区和斯特拉坎区是吸引延误的地方。在这个例子中,全市 7%的延误发生在这个十字路口。

既然我们已经查看了集群,让我们修改集群视图的代码,以显示延迟持续时间的热图视图:
这是整个系统的样子:

如果我们放大到市中心的中心部分,延误的集中是显而易见的,包括巴瑟斯特、斯帕迪纳和海湾与皇后码头交汇处的湖泊附近的三个不同的热点。

结论
通过的上一篇文章和这篇文章,我已经描述了从杂乱的自由格式地址到纬度和经度,再到使用 leav 的有用地图可视化的旅程。这些可视化提供了对数据的深入了解,例如街车延误热点的位置,这些数据很难从原始数据集中提取。
如果您想探索本文中描述的代码:
绘制城市中最受欢迎的地方
使用蟒蛇,熊猫和树叶

“Mass” by Gaetano Virgallito. Licensed under CC BY-ND 2.0
当“数据科学”一词出现时,一些与分析人类行为、大城市、服务消费等相关的研究引起了我的兴趣。上次工作时,我为巴西纳塔尔的优步服务制作了一张地图,对如何更好地服务中心街区很感兴趣。这一次,人们的兴趣来自于谷歌的一个地点搜索功能:“大众时报”。

谷歌虽然聪明,但它可以向我们展示(有时甚至是“直播”)你搜索的地方有多忙。所以…
如果我根据热门时间比较几个地方呢?并发现特定类型的地方比其他地方更受欢迎?使用这种数据可以提出许多问题。
那么,为什么不从纳塔尔市中心(我居住的城市)以 15 英里为半径获取不同类型的地方,然后获取每个地方的流行时间数据,并用这些数据绘制一个交互式地图呢?这就是我们在这里做的。
我会尽量解释,用足够的细节不要让这篇文章讨厌,我是怎么做的,以及这个实验如何能被复制。这里用到的技术有 Python,pandas,叶子库。如果你想了解更多,代码可以在 GitHub 上找到,比如interactives Colab notebooks你可以上传自己的数据库并生成地图。
谷歌,谷歌…
在绘制地图之前,我们必须提取我们需要的数据。这将需要两种类型的数据:纳塔尔的一组地点和这些地点中的每一个地点,关于流行时刻的数据。
我们将使用 Google Places API 来获取位置。这个 API 提供了几种服务,对于所有这些服务,您都需要一个访问令牌来消费数据。
我使用了“附近搜索”来寻找纳塔尔市中心附近半径 15 英里的地方。脚本通过类型(健身房、超市、银行……)搜索这些地方——我为每种类型定义了我想要的地方的数量;这样我会得到最相关的结果。然后,该脚本保存。将数据集放置为places.csv的 csv 文件。
现在我们有地方了。通过我设置的过滤器和界限,我们在纳塔尔有 800 个地方。下一步是捕捉所有这些流行的时间。在 Places API 文档中查找该主题,您会注意到没有提到任何“流行时间”(至少直到今天,2019 年 5 月。)但是用谷歌快速搜索,我找到了让我们获得这项服务的回购。回购协议中说,谷歌确实允许这种查询,但不是免费的,这个 API 调用被 SKU 称为“查找当前位置”。你可以用每月分配的预算给这个 API 打 5000 个电话。
使用该 API,get_places_popular_moments.py读取 places 数据集并在其上包含热门时刻,生成新的places_with_moments.csv数据集。现在,我们应该有 800 个地方,但我们只有 300 个,因为没有每个地方的“流行时间”。
到目前为止,我们的数据集看起来像这样:

对于每个工作日列,有 24 个位置,具有一天中每个小时的力矩值。
用 follow 和 Kepler 生成地图
现在,我们希望将这些数据可视化在一个漂亮的交互式地图中。我们将使用基于 fleet . js 的 Python 库——来可视化地图。
这是纳塔尔周一上午 10 点的热门地点地图。圆圈的颜色表示地点的类型和大小,以及时刻值。

生成这个地图代码是这样的:
def generate_map(weekday, hour, types=places_types):
natal = folium.Map(location=[-5.831308, -35.20470], zoom_start=13)
ptypes_groups = {} for ptype in types:
ptypes_groups[ptype] = FeatureGroup(name=ptype) for index, place in natal_places.iterrows():
moments = json.loads(place[weekday])
if (place.type in types):
folium.Circle(location=[place.lat, place.lng],
radius=int(moments[hour])*3,
fill_color=colors[places_types.index(place.type)],
fill_opacity=0.6).add_to(ptypes_groups[place.type])
for ptype, group in ptypes_groups.items():
group.add_to(natal) LayerControl().add_to(natal)
return natal
它将星期几、小时和可选的地点类型子集作为参数。它做的第一件事是创建一个新的地图natal,并为每个想要的类型创建一个FeatureGroup。这个资源允许我们在地图上创建一个带有切换类型选项的菜单。
遍历数据集上的所有项目,我们将每个项目添加到相应的特征组。
深入到 colab 笔记本中,您会看到对数据集进行了修改,使其适合与 Kepler.gl 一起使用,这是一个强大的地理空间分析 web 工具。开普勒给了我们比叶更多的资源,而且性能非常好。所以我们可以这样做:

Anitation made with Kepler
上面的动画是使用开普勒生成的,让我们可以看到纳塔尔在这一周的移动情况。开普勒还允许我们导出环境,使其可以在线访问,在这个地址你可以访问上面的地图。
我们还能做什么?
乍一看,关于流行时间的信息没什么意义。谷歌说的“地方 100 拥挤”是什么意思?这是这个地方的人口密度等级?这些流行的时代数据到底意味着什么?
通过更好地分析一些值,我意识到“momet”的范围是从 0 到 100,这导致了诸如“通常不太忙”或“通常有点忙”之类的分类。但我真正的问题是“这些信息有多大意义?”
为了更好地理解它,我采用了另一种方法,对在数据集中找到一些有用的信息感兴趣。这是我的发现:

这个不错。图表中显示的健身房流量证实了一个常识:健身房周一更忙,周五没那么忙。高峰时间大约是晚上 20 点

大多数图表在午餐时间没有高峰时间,这与机场不同,机场在下午 12 点更忙

星期五下午,医疗诊所有所减少。

纳塔尔的人们喜欢在星期五下午去理发店。
这些是从我们获得的数据中可以推断出的一些有趣的信息。总的来说,我很高兴这些数据与现实相符,这让我相信这确实是“流行时代”数据中的一个含义。这些结果可能会引导我们进行有趣的分析,这对理解纳塔尔,当然还有其他城市的行为是有意义的。
用主题建模描绘技术世界
我们用流行的话题建模算法 LDA 分析了 20 万篇科技新闻文章
克里斯托夫·乔迪、祖卡斯·纳瓦罗、米查什·帕利斯基、马切伊·维拉莫夫斯基(德拉布·UW,华沙大学)

Image by: DELab UW
作为 NGI 前进项目的一部分,德拉布·UW正在支持欧盟委员会的下一代互联网计划,确定与互联网相关的新兴技术和社会问题。我们的团队一直在尝试各种自然语言处理方法,以发现不同类型的在线媒体中的趋势和隐藏模式。您可以在这里找到我们的工具和演示文稿。
这篇文章展示了我们对科技新闻的最新分析结果。我们有两个主要目标:
- 在讨论新兴技术和社会问题的新闻中发现最重要的话题,
- 来映射这些主题之间的关系。
我们的文本挖掘练习基于由 213 000 篇科技媒体文章组成的科技新闻数据集。数据收集时间为 40 个月(2016 年 1 月 1 日至 2019 年 4 月 30 日),包括文章的纯文本。如图所示,出版商位于美国、英国、比利时和澳大利亚。关于数据集的更多信息可以在我们的 Zenodo 知识库中获得。

Sources by number of articles and country
在这篇简短的介绍中,我们关注一种广泛使用的文本挖掘方法:潜在狄利克雷分配(LDA)。LDA 因其易用性、灵活性和可解释的结果而广受欢迎。首先,我们为所有非技术读者简要解释算法的基础。在文章的第二部分,我们展示了 LDA 在一个足够大的数据集上可以实现什么。
皱胃向左移
文本数据是高维的。在最基本的形式中,它通常被表示为单词包(BOW)矩阵,其中每行是一个文档,每列包含一个单词在文档中出现的频率。这些矩阵可通过线性代数方法进行转换,以发现其中隐藏的(潜在的和低维的)结构。
主题建模假设文档(如新闻文章)包含各种不同的主题。例如,报道剑桥分析丑闻的新闻文章可能包含以下主题:社交媒体、政治和技术法规,具有以下关系:60%社交媒体、30%政治和 10%技术法规。另一个假设是,主题包含特征词汇,例如,社交媒体主题由脸书、推特等词描述。
LDA 是由 Blei 等人(2003) 基于贝叶斯统计提出的。该方法的名称提供了它的关键基础。潜在来自于文档包含我们事先不知道的潜在主题的假设。分配表明我们将单词分配给主题,将主题分配给文档。狄利克雷是一个多项式似然分布:它提供了任何数量的结果的联合分布。例如,狄利克雷分布可以描述野生动物园中观察到的物种的出现(唐尼,2013 )。在 LDA 中,它描述了主题在文档中的分布,以及词在主题中的分布。
主题建模方法背后的基本机制很简单:假设文档可以由有限数量的主题描述,我们试图从由特征词组成的主题组合中重建我们的文本。更准确地说,我们旨在通过两个矩阵的组合来重新创建我们的 BOW 单词-文档矩阵:包含文档中主题的狄利克雷分布的矩阵(主题-文档矩阵),以及包含主题中的单词的矩阵(单词-主题矩阵)。最终矩阵的构建是通过一个叫做吉布斯采样的过程实现的。Gibbs 抽样背后的思想是将改变逐字引入两个矩阵:改变文档中所选单词的主题分配,并评估这种改变是否改进了我们文档的分解。在所有文档中重复 Gibbs 抽样的步骤提供了提供样本的最佳描述的最终矩阵。
关于主题建模的更多细节,我们推荐这个和这个的优秀帖子。关于这项研究的完整技术描述,请阅读我们的完整报告。
结果
主题建模最重要的参数是主题的数量。主要目标是达到令人满意的主题分离水平,即主题既不是所有问题都集中在一起,也不是过于分散的问题。为了实现这一点,我们试验了不同的 LDA 超参数水平。对于有 20 个主题的设置,主题是平衡的和可分离的。
因此,我们确定了 20 个主要主题,呈现在下面的可视化中。每个圆圈代表一个主题(大小反映了主题在文档中的流行程度),距离由词汇的相似性决定:共享相同单词的主题彼此更接近。在第二个图中,条形代表当前所选主题的特有术语(对于图示,主题 1。被选中)。一对重叠的条表示给定术语在语料库范围内的频率,以及其特定主题的频率。我们设法达到逐渐减小的主题大小:最大的主题占 19%,第五个 8%,第十个 5%。
要探索呈现结果的交互式可视化,请点击此处。


For the interactive visualisation see: https://mpalinski.github.io/ngi-fwd-deliv/
在研究了这些最相关的术语后,我们用最接近的总括术语标记了每个主题。经过仔细检查,我们将话题数量减少到了 17 个(话题 5 和 16 成为了联合类别太空技术,话题 10 &和 19 被融合在一起形成了一个关于媒体的话题,而话题 14 &和 15 则专注于 CPU 和其他硬件)。在接下来的章节中,我们将简要介绍已确定的主题。
话题一: AI &机器人
人工智能和机器人构成了最大的主题,约占所有令牌的 19%,其特点是机器学习术语(例如训练数据)以及流行的人工智能应用(机器人、自动驾驶汽车)。
话题 2:社交媒体危机
社交媒体话题也同样普遍,涵盖了现代社交媒体平台( facebook 、 twitter )有争议的方面,如隐私权、内容节制、用户禁令或选举干预使用微目标(例如:隐私、禁令、选举、内容、删除)。
话题三:商业新闻
大量科技文章报道了商业新闻,尤其是在主要平台(T0)、T2 亚马逊、云计算(T4 AWS、T5)等服务或物联网、区块链 T9 等新兴技术上。主题词也暗示了对科技公司财务结果的高度关注(收入、亿、销售、增长)。
主题 4:智能手机
主题 4 涵盖了关于 522 亿美元智能手机市场的文章。两大制造商——三星和苹果——以同样的出场次数名列关键词列表之首。文章重点介绍设备的特点、参数及提供的附加服务(摄像头、显示器、 alexa 等)。).
主题 5 和 16:空间
对太空探索的兴奋在科技媒体中很常见。这些主题包括关于美国国家航空航天局、未来的火星和月球任务以及致力于空间技术的公司的报告,如 SpaceX。
主题 6:隐私
主题 6 围绕剑桥分析隐私丑闻展开,并在语料库中收集该关键词的所有提及内容。英国退出欧盟公投期间,剑桥分析公司(Cambridge Analytica)参与公投脱欧运动是一个主要焦点,诸如 eu 和 uk 等关键词的高位表明了这一点。不出所料,在处理加州争议后果的文章中也经常提到 GDPR。
话题七:网络安全
主题 7 涉及网络空间安全问题。它探索恶意软件和系统漏洞的主题,既针对传统的计算机系统,也针对基于区块链的新型分散技术。
主题 8: 5G
备受期待的第五代无线网络具有巨大的潜力,可以通过 ICT 组件改变所有领域。话题 8 涉及向市场提供 5G 技术的全球竞争(华为、爱立信)。它还捕捉到了关于 5G 对网络中立性的影响的争论。5G 的主要质量是实现信号的“分段”,这就引发了一场争论,即根据网络中立法,它是否能像前几代移动通信一样被对待。
话题九:跨平台
主题 9 的重点是操作系统,包括移动( ios 、 android )、桌面( windows 、 macos )以及专用服务(浏览器 chrome 、 mozilla )和应用商店( appstore )。
主题 10 和 19:媒体
媒体主题围绕最重要的媒体平台:流媒体和社交媒体。2018 年,全球视频流媒体市场规模约为 370 亿美元,音乐流媒体在此基础上又增加了 90 亿美元,占音乐行业收入的近一半。特别是,本主题关注主要的流媒体平台( youtube 、网飞、 spotify )、社交媒体( facebook 、 instagram 、 snapchat )、播客的日益流行以及流媒体服务的商业策略(订阅、广告)。
话题 11:微软
在其 40 年的历史中,微软已经进行了 200 多次收购。其中一些被认为是成功的(如 LinkedIn、Skype),而另一些则不那么成功……(诺基亚)。话题 11 收集了描述微软近年来完成、计划和失败的收购的文章( github 、 skype 、 dropbox 、 slack )。
话题 12: 自动驾驶汽车
自主交通是公众辩论的一个重要话题。决策者应该考虑是否应用补贴或税收来平衡这项技术的公共和私人成本和利益。视听技术为社会福利提供了巨大利益的可能性——拯救生命;减少撞车、拥堵、油耗和污染;增加残疾人的行动能力;并最终改善土地利用(兰德,2016 )。专题 12 阐述了该技术的技术缺陷(电池)以及积极的外部性,如降低排放( epa 、排放)。
话题 13:特斯拉
LDA modelling 已经将特斯拉和其他 Elon Musk 项目确定为一个单独的主题。除了特斯拉电动汽车和自动驾驶汽车的发展,该主题还包括与其他移动解决方案相关的词汇(如 Lime)。
主题 14 和 15: CPU 和其他硬件
主题 14 涵盖英特尔和 AMD 之间的 CPU 创新竞赛,以及因国家安全问题被 Donald Trump 阻止的 Broadcom-高通收购事件。主题 15 包括关于各种标准( usb-c )、存储设备( ssd )等的新闻。
主题 17:初创企业
主题 17 集中于创业生态系统和众包融资。文章讨论了创业战场或创业小巷等主要创业竞赛,以及 Patreon 等众筹服务。
话题 18: 可穿戴设备
我们观察到可穿戴设备的采用激增,如健身追踪器、智能手表或增强和虚拟现实耳机。这一趋势带来了重要的政策问题。一方面,可穿戴设备在监测健康方面提供了巨大的潜力。另一方面,它可能会被对用户隐私和个人数据访问的担忧所掩盖。专题 18 中的文章讨论了可穿戴设备领域关于新设备、新功能等的新闻。( fitbit ,心率)。
话题 20: 博彩
主题 20 涉及博彩业。它涵盖了流行游戏(口袋妖怪)、游戏平台(任天堂)、各种游戏控制台( switch )和游戏博览会( e3 )。
结论
我们通过主题建模提供了技术世界的鸟瞰图。主题建模是探索广泛主题的适当基础,如社交媒体危机、人工智能或商业新闻。在这个阶段,我们能够确定引发公众辩论的主要总括主题。
我们的完整报告还包括另一种机器学习方法:t-SNE。在这种算法的帮助下,我们创建了一个新闻的二维地图,其中涉及相同主题的文章是邻居。
使用 Python 中的 Matplotlib、Pandas、Geopandas 和底图进行制图
作为 FORSK TECHNOLOGIES, 的一名实习生,我探索了相当多的 Python 库(Matplotlib、Pandas、Numpy、Seaborn、Shapefile、Basemap、Geopandas ),它们对绘制数据(某种程度上也是实时数据)很有帮助..)过地图。

用 Python 绘制地理地图
在处理数据科学时,可视化地图上的数据非常有用,这可以通过 geopandas 等模块来完成。在这里,我们将探索使用 shapefiles ()创建地理地图并在其上可视化数据的方法。shp)和其他一些 Python 库。
在这里,我们将根据地图上的可视化数据来研究拉贾斯坦邦的城市人口。
本文所需的 shapefile 可以从这个链接下载 点击这里
安装 Shapefile 库
*~ conda/pip install pyshp*
导入库
*import numpy as np
import pandas as pd
import shapefile as shp
import matplotlib.pyplot as plt
import seaborn as sns*
初始化可视化集
*sns.set(style=”whitegrid”, palette=”pastel”, color_codes=True) sns.mpl.rc(“figure”, figsize=(10,6))*
打开矢量地图
矢量地图是一组具有. shp 格式的文件。
*#opening the vector map**shp_path = “\\District_Boundary.shp”**#reading the shape file by using reader function of the shape lib**sf = shp.Reader(shp_path)*
shp.reader 导入的不同形状的数量
*len(sf.shapes())*
结果将是 33,这告诉我们有 33 个形状,或者我们可以说拉贾斯坦邦地区的城市。
要浏览这些记录:
*sf.records()*

A sample output
要浏览特定记录,其中 1 是 Id 或行号,0 表示列:
***sf.records()[1][0]***
结果-
Output= Barmer
将形状文件数据转换为熊猫数据帧:
通过将 shapefile 数据转换为更相关的 Pandas Dataframe 格式,使访问城市变得更加容易。
**def read_shapefile(sf):**
#fetching the headings from the shape file
fields = [x[0] for x in sf.fields][1:]#fetching the records from the shape file
records = [list(i) for i in sf.records()]
shps = [s.points for s in sf.shapes()]#converting shapefile data into pandas dataframe
df = pd.DataFrame(columns=fields, data=records)#assigning the coordinates
df = df.assign(coords=shps)
return df
数据转换为数据帧后的可视化,其中数据帧指的是行和列
*df = read_shapefile(sf)****df.shape***
具有(33,6)形状的数据帧意味着其中有 33 行和 6 列。
让我们看看创建的数据帧的示例
*# sample of a data representation the last point has the coordinates of the data latitude and longitude which will be used to create a specific map shape****df.sample(5)***
结果会是这样的—

Output
这里的线是用来创建地图的纬度和经度。
借助 Matplotlib 绘制拉贾斯坦邦的城市地图或特定形状
a)根据城市坐标绘制形状(多边形),
b)计算并返回该特定形状的中点(x0,y0)。
此中点也用于定义打印城市名称的位置。
**def plot_shape(id, s=None):**
plt.figure()
#plotting the graphical axes where map ploting will be done
ax = plt.axes()
ax.set_aspect('equal')#storing the id number to be worked upon
shape_ex = sf.shape(id)#NP.ZERO initializes an array of rows and column with 0 in place of each elements
#an array will be generated where number of rows will be(len(shape_ex,point))and number of columns will be 1 and stored into the variable
x_lon = np.zeros((len(shape_ex.points),1))#an array will be generated where number of rows will be(len(shape_ex,point))and number of columns will be 1 and stored into the variable
y_lat = np.zeros((len(shape_ex.points),1))
for ip in range(len(shape_ex.points)):
x_lon[ip] = shape_ex.points[ip][0]
y_lat[ip] = shape_ex.points[ip][1]#plotting using the derived coordinated stored in array created by numpy
plt.plot(x_lon,y_lat)
x0 = np.mean(x_lon)
y0 = np.mean(y_lat)
plt.text(x0, y0, s, fontsize=10)# use bbox (bounding box) to set plot limits
plt.xlim(shape_ex.bbox[0],shape_ex.bbox[2])
return x0, y0
设置城市名称以绘制各自的地图
*DIST_NAME = ‘JAIPUR’**#to get the id of the city map to be plotted**com_id = df[df.DIST_NAME == ‘JAIPUR’].index.get_values()[0]****plot_shape(com_id, DIST_NAME)****sf.shape(com_id)*

Output
为了绘制特定的形状,我们必须知道特定城市的 ID,但是将 shapefile 文件数据更改为 Pandas dataframe 使工作变得更加容易和简单,现在我们可以直接调用它的名称。
绘制全图
这个特殊的函数将所有使用坐标制作的单个形状组合起来,并显示为一个组合形状。
def plot_map(sf, x_lim = None, y_lim = None, figsize = (11,9)):
plt.figure(figsize = figsize)
id=0
for shape in sf.shapeRecords():
x = [i[0] for i in shape.shape.points[:]]
y = [i[1] for i in shape.shape.points[:]]
plt.plot(x, y, 'k')
if (x_lim == None) & (y_lim == None):
x0 = np.mean(x)
y0 = np.mean(y)
plt.text(x0, y0, id, fontsize=10)
id = id+1
if (x_lim != None) & (y_lim != None):
plt.xlim(x_lim)
plt.ylim(y_lim)*#calling the function and passing required parameters to plot the full map****plot_map(sf)***

绘制缩放地图
*y_lim = (2900000,3000000) # latitude**x_lim = (200000, 400000) # longitude****plot_map(sf, x_lim, y_lim)***

output
在完整的地图上突出显示一个单一的形状
结合以前的功能就可以了。我们可以在一张完整的地图上画出一个形状。ID 和颜色代码将是该功能的必需参数。
**def plot_map_fill(id, sf, x_lim = None,
y_lim = None,
figsize = (11,9),
color = 'r'):**
plt.figure(figsize = figsize)
fig, ax = plt.subplots(figsize = figsize)
for shape in sf.shapeRecords():
x = [i[0] for i in shape.shape.points[:]]
y = [i[1] for i in shape.shape.points[:]]
ax.plot(x, y, 'k')
shape_ex = sf.shape(id)
x_lon = np.zeros((len(shape_ex.points),1))
y_lat = np.zeros((len(shape_ex.points),1))
for ip in range(len(shape_ex.points)):
x_lon[ip] = shape_ex.points[ip][0]
y_lat[ip] = shape_ex.points[ip][1]
ax.fill(x_lon,y_lat, color)
if (x_lim != None) & (y_lim != None):
plt.xlim(x_lim)
plt.ylim(y_lim)*#plot_map_fill(0, sf, x_lim, y_lim, color=’y’)****plot_map_fill(13, sf,color=’y’)***

Desired Output
用城市 ID 在整个地图上突出显示多个形状
在这个函数的帮助下,作为参数,我们可以给出多个城市的 ID,这将导致突出显示多个城市而不是 1 个。
**def plot_map_fill_multiples_ids(title, city, sf,
x_lim = None,
y_lim = None,
figsize = (11,9),
color = 'r'):**
plt.figure(figsize = figsize)
fig, ax = plt.subplots(figsize = figsize)
fig.suptitle(title, fontsize=16)
for shape in sf.shapeRecords():
x = [i[0] for i in shape.shape.points[:]]
y = [i[1] for i in shape.shape.points[:]]
ax.plot(x, y, 'k')
for id in city:
shape_ex = sf.shape(id)
x_lon = np.zeros((len(shape_ex.points),1))
y_lat = np.zeros((len(shape_ex.points),1))
for ip in range(len(shape_ex.points)):
x_lon[ip] = shape_ex.points[ip][0]
y_lat[ip] = shape_ex.points[ip][1]
ax.fill(x_lon,y_lat, color)
x0 = np.mean(x_lon)
y0 = np.mean(y_lat)
plt.text(x0, y0, id, fontsize=10)
if (x_lim != None) & (y_lim != None):
plt.xlim(x_lim)
plt.ylim(y_lim)
让我们看看地图是什么样子的
*#naming the id numbers of the cities to be coloured**city_id = [0, 1, 2, 3, 4, 5, 6]****plot_map_fill_multiples_ids(“Multiple Shapes”,******city_id, sf, color = ‘g’)***

通过城市名称在整个地图上突出显示多个形状
最近,我们遇到了用城市 ID(索引)突出显示形状的问题,但尽管我们的数据是熊猫数据框架,我们也可以通过提到城市名称来做到这一点。
# plotting the city on the map to be coloured by using the dist_name**def plot_cities_2(sf, title, cities, color):**
df = read_shapefile(sf)
city_id = []
for i in cities:
city_id.append(df[df.DIST_NAME == i.upper()]
.index.get_values()[0])
plot_map_fill_multiples_ids(title, city_id, sf,
x_lim = None,
y_lim = None,
figsize = (11,9),
color = color);
让我们来看看输出
*south = [‘jaipur’,’churu’,’bikaner’]**plot_cities_2(sf, ‘DIST’, south, ‘c’)*

绘制热图
这是一种根据提供的值用不同强度的特定颜色填充形状的地图。它以地理格式提供清晰的数据解释。
在第一个函数中,我们将把我们的数据列表划分为区间或箱,其中每个箱将具有特定的颜色强度,6 个箱和 4 个不同的颜色托盘。
**def calc_color(data, color=None):**
if color == 1:
color_sq = ['#dadaebFF','#bcbddcF0','#9e9ac8F0','#807dbaF0','#6a51a3F0','#54278fF0'];
colors = 'Purples';
elif color == 2:
color_sq = ['#c7e9b4','#7fcdbb','#41b6c4','#1d91c0','#225ea8','#253494'];
colors = 'YlGnBu';
elif color == 3:
color_sq = ['#f7f7f7','#d9d9d9','#bdbdbd','#969696','#636363','#252525'];
colors = 'Greys';
elif color == 9:
color_sq = ['#ff0000','#ff0000','#ff0000','#ff0000','#ff0000','#ff0000'];
else:
color_sq = ['#ffffd4','#fee391','#fec44f','#fe9929','#d95f0e','#993404'];
colors = 'YlOrBr';
new_data, bins = pd.qcut(data, 6, retbins=True,
labels=list(range(6)))
color_ton = []
for val in new_data:
color_ton.append(color_sq[val])
if color != 9:
colors = sns.color_palette(colors, n_colors=6)
sns.palplot(colors, 0.6);
for i in range(6):
print ("\n"+str(i+1)+': '+str(int(bins[i]))+
" => "+str(int(bins[i+1])-1))
print("\n\n 1 2 3 4 5 6")
return color_ton, bins;
函数 plot_cities()和 plot_map_fill_multiples_ids 应进行调整,以利用这种新的颜色方案:
**def plot_cities_data(sf, title, cities, data=None,color=None, print_id=False):**
color_ton, bins = calc_color(data, color)
df = read_shapefile(sf)
city_id = []
for i in cities:
city_id.append(df[df.DIST_NAME ==
i.upper()].index.get_values()[0])
plot_map_fill_multiples_ids_tone(sf, title, city_id,
print_id,
color_ton,
bins,
x_lim = None,
y_lim = None,
figsize = (11,9));**def plot_map_fill_multiples_ids_tone(sf, title, city,
print_id, color_ton,
bins,
x_lim = None,
y_lim = None,
figsize = (11,9)):**
plt.figure(figsize = figsize)
fig, ax = plt.subplots(figsize = figsize)
fig.suptitle(title, fontsize=16)
for shape in sf.shapeRecords():
x = [i[0] for i in shape.shape.points[:]]
y = [i[1] for i in shape.shape.points[:]]
ax.plot(x, y, 'k')
for id in city:
shape_ex = sf.shape(id)
x_lon = np.zeros((len(shape_ex.points),1))
y_lat = np.zeros((len(shape_ex.points),1))
for ip in range(len(shape_ex.points)):
x_lon[ip] = shape_ex.points[ip][0]
y_lat[ip] = shape_ex.points[ip][1]
ax.fill(x_lon,y_lat, color_ton[city.index(id)])
if print_id != False:
x0 = np.mean(x_lon)
y0 = np.mean(y_lat)
plt.text(x0, y0, id, fontsize=10)
if (x_lim != None) & (y_lim != None):
plt.xlim(x_lim)
plt.ylim(y_lim)
让我们举一个例子,以热图演示格式绘制数据。
*names= [‘jaipur’,’bikaner’,’churu’,’bhilwara’,’udaipur’]**data = [100, 2000, 300, 400000, 500, 600, 100, 2000, 300, 400, 500, 600, 100, 2000, 300, 400, 500, 600]**print_id = True # The shape id will be printed**color_pallete = 1 # ‘Purple’****plot_cities_data(sf, ‘Heat map of given cities’, names, data, color_pallete, print_id)***


绘制真实数据
绘制拉贾斯坦邦地区的人口图,这里指的是真实数据。
*# reading data set
census_17 = df.POPULATION**census_17.shape**#plotting**title = ‘Population Distrubution on Rajasthan Region’**data = census_17**names = df.DIST_NAME****plot_cities_data(sf, title, names, data, 1, True)***


希望你已经理解了通过 Python 库绘制地图的概念。
具体代码可以参考我的GITHUB。
使用 Geopandas 制图

我们已经看到了用 Pandas 数据帧进行制图的过程,现在轮到用 Geopandas 数据帧对其进行可视化了。Geopandas 简化了 Python 中地理空间数据(包含地理成分的数据)的处理。它结合了熊猫和 shapely 的功能,通过运行一个更紧凑的代码。这是开始制作 choropleth 地图的最好方法之一。
让我们先通过 Geopandas 绘制一些地图,然后在上面绘制拉贾斯坦邦的人口!
上一主题中使用的 Shapefile 足以进一步用于 Geopandas。
安装
conda install geopandas
第一步是导入所需的库
import pandas as pd
import matplotlib.pyplot as plt
import geopandas as gpd
获取感兴趣的数据
作为印度最大的邦,拉贾斯坦邦是一个人口高度密集的邦。绘制人口地图将使可视化更加简单和高效。让我们设置路径,通过 Geopandas 打开 Rajasthan 地区的 shapefile。
# set the filepath and load
fp = “\\District_Boundary.shp”#reading the file stored in variable fp
map_df = gpd.read_file(fp)# check data type so we can see that this is not a normal dataframe, but a GEOdataframe**map_df.head()**

让我们预览一下地图
#plotting the map of the shape file preview of the maps without data in it
**map_df.plot()**

现在是时候打开包含要绘制的数据的 CSV 文件了。在这里,我们也可以为所需的数据制作一个 csv,但我只从 shapefile 中提取数据,而不是制作 csv 或在 web 上搜索,这样可以节省大量时间。
#opening the csv(.shp) file which contains the data to be plotted on the map
df = gpd.read_file(\\District_Boundary.shp”)df.head()#selecting the columns required
df = df[[‘DIST_NAME’,’POPULATION’]]#renaming the column name
data_for_map = df.rename(index=str, columns={‘DIST_NAME’: ‘DISTRICT’,‘POPULATION’: ‘POP’})
让我们预览一下地理数据框架
# check dat dataframe
**data_for_map.head()**

现在,让我们将地理数据与数据集连接起来
# joining the geodataframe with the cleaned up csv dataframe
merged = map_df.set_index(‘DIST_NAME’).join(data_for_map.set_index(‘DISTRICT’))#.head() returns the top 5(by default ) lines of the dataframe
**merged.head()**

Output after merging datasets
映射时间
首先,我们需要为 Matplotlib 绘制地图做一些预先要求的工作,如设置变量、范围和为地图创建基本图形。
# set a variable that will call whatever column we want to visualise on the map
variable = ‘POP’# set the range for the choropleth
vmin, vmax = 120, 220# create figure and axes for Matplotlib
fig, ax = plt.subplots(1, figsize=(10, 6))
创建地图的时间
merged.plot(column=variable, cmap=’BuGn’, linewidth=0.8, ax=ax, edgecolor=’0.8')

这就是我们想要的,地图已经准备好了!但是需要一些美化和定制。
# remove the axis
ax.axis(‘off’)# add a title
ax.set_title(‘Population of Rajasthan’, fontdict={‘fontsize’: ‘25’, ‘fontweight’ : ‘3’})# create an annotation for the data source
ax.annotate(‘Source: Rajasthan Datastore, 2019’,xy=(0.1, .08), xycoords=’figure fraction’, horizontalalignment=’left’, verticalalignment=’top’, fontsize=12, color=’#555555')
颜色条是地图中必不可少的东西,它告诉我们要寻找的参数,让我们为我们的地图定制它。
# Create colorbar as a legend
sm = plt.cm.ScalarMappable(cmap=’BuGn’, norm=plt.Normalize(vmin=vmin, vmax=vmax))# empty array for the data range
sm._A = []# add the colorbar to the figure
cbar = fig.colorbar(sm)#saving our map as .png file.
fig.savefig(‘map_export.png’, dpi=300)

您可能已经知道为什么使用 Geopandas 进行制图更好了。它有一个非常紧凑和简单的代码,并给出了一个很好的期望输出。通过这种方法,我们可以绘制任何地区的任何类型的数据。
关于 th e 的确切代码,请参考我的 GITHUB 。
使用底图制图

Matplotlib 底图工具包是一个用于在 Python 中的地图上绘制 2D 数据的库。底图本身不进行任何绘图,但提供了将坐标转换为 25 种不同地图投影之一的工具。 Matplotlib 用于在转换后的坐标中绘制轮廓、图像、矢量、线或点。提供了海岸线、河流和政治边界数据集,以及绘制它们的方法。
在本节中,您将了解如何通过底图工具包在地图上绘制数据。
让我们通过底图工具包来查看地图可视化。
安装
conda install basemap
conda install basemap-data-hires
导入库
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import geopandas as gpd
import pandas as pd
注意:如果在导入底图库时遇到任何困难或错误(PROJ_LIB ),您可以直接设置其路径,以便在导入底图之前导入并运行它。
#to import the basemap library give the direct path to the libraryimport os
os.environ["PROJ_LIB"]="C:\\Users\\Anaconda3\\Library\\share"
让我们从 csv 和 shapefile 中获取感兴趣的数据。以下是下载所需 csv 文件的链接 点击此处 和所需 shapefile】点击此处
city=gpd.read_file("F:\\District_Boundary.shp")
csv=pd.read_csv("\\latlong_raj.csv")
我们从加载数据开始。Lat-long 是从一个单独的 csv 中导入的,其他数据如地区名称及其人口来自。在前面部分下载的 shp 文件。
lat=csv['LAT'].values
lon=csv['LONG'].values
population = city['POPULATION'].values
dist=city['DIST_NAME'].values
这些数据已经被保存为一个 numpy 数组,你可以通过[ type(lat)] 来检查它。
接下来,我们设置地图投影,散布数据,然后创建一个颜色栏
fig = plt.figure(figsize=(8, 8))
m = Basemap(projection='lcc', resolution='h',
lat_0=27.0238, lon_0=74.2179,
width=1.05E6, height=1.2E6)
m.shadedrelief()
我们的地图背景现在已经准备好了,可以在上面绘制数据。印度拉贾斯坦邦的 lat-long 已经用“lcc”投影设置了一定的缩放量,以便只聚焦特定的状态。

我们来给它添加一些细节,划分一下界限。
m.drawcoastlines(color='blue',linewidth=3)
m.drawcountries(color='gray',linewidth=3)
m.drawstates(color='gray')

现在是时候在地图投影上散布数据并设置颜色条了。
# scatter city data, with c reflecting population
m.scatter(lon,lat, latlon=True,
c=population,s=700,
cmap='YlGnBu_r', alpha=0.5)#create colorbar
plt.colorbar(label=r'Population')
plt.clim(300000, 4000000)

看起来是不是少了点什么?是啊!当然,区名。我们无法通过这种投影来识别地区。
让我们把它们画出来。
我们在上面的变量中存储了地区名称及其经度,但是我们将数据存储为 numpy 数组,所以我们需要将它们存储在列表或字典中。
dict1={}
list1=[]
list2=[]
list3=[]
n=0#storing each value in different lists
for z in lat:
list1.append(z)
for c in lon:
list2.append(c)
for b in dist:
list3.append(b)#storing the values of lat long in a dictionary with lat as keys and long as values
while(n<len(list1)):
dict1[list1[n]]=list2[n]
n+=1
现在,lat-long 已被存储到字典(dict1)和区名列表(list3)中。让我们用它们来命名区域。
i=0# Map (long, lat) to (x, y) for plotting
#naming the cities of Rajasthan with the help of their lat(z)long(c)for z,c in dict1.items():
x,y = m(c, z)
plt.plot(x, y, 'ok', markersize=5)
plt.text(x, y,list3[i], fontsize=10);
i+=1

参考我的GITHUB获取 th e 确切代码。
这就是了。感谢您的阅读。
有关 Geopandas、Basemap 的更多信息,或者您想了解 Python、ML、DL、AI、IoT 等行业趋势技术,请联系 Forsk Technologies。
使用线程在 C 中从头开始使用 MapReduce:Map

Source: Pixabay
Hadoop 的 MapReduce 不仅仅是一个框架,还是一种解决问题的哲学。
借鉴函数式编程,MapReduce 团队意识到很多不同的问题可以分成两种常见的操作: map ,和 reduce 。
映射和缩减步骤都可以并行完成。
这意味着只要你能以那种特定的方式框定你的问题,就会有一个解决方案,它可以很容易地并行运行。这通常会大大提升性能。
这听起来不错,并行运行通常是一件好事,尤其是在大规模工作时。但是,坐在后面的一些人可能会想,什么是地图和减少?
什么是 MapReduce?
为了理解 MapReduce 框架,我们需要了解它的两个基本操作: Map 和 Reduce 。
它们都是高阶函数:也就是说,它们是可以把其他函数作为自变量的函数。
具体来说,当您需要将 A 类型的某个元素序列转换为 B 类型的一个结果或一系列结果时,您将:
- 将你所有的输入映射到不同的域:这意味着你将用一个选择的函数来转换它们,并应用到每个元素。
- 根据某种标准对映射的元素进行分组,通常是一个分组关键字。
- 用其他函数减少每个组上的映射元素。这个函数需要两个参数并返回一个相同类型的参数,连续运行一个累加器和集合中每个值之间的运算。它应该是交换和关联,因为并行执行不会保证操作的任何顺序。
为了更清楚地说明这一点,让我们看一个例子。
MapReduce 解决方案示例
假设你在一家电子商务公司工作,他们给你一个如下形式的日志文件:
John Surname bought 2 apples
Alice Challice bought 3 bananas
John Surname bought 5 pineapples
然后他们让你告诉他们每个顾客买了多少水果。
在这种情况下,在解析该文件并将其转换为实际格式(如 CSV)后,您可以轻松地遍历每一行,并在字典上的每个名称下添加购买的水果的数量。
你甚至可以用一点 Bash 脚本来解决它,或者将 CSV 加载到熊猫数据帧上并获得一些统计数据。
然而,如果日志文件有一万亿行长,bash 脚本并不能真正减少它。尤其是如果你不是永生的。
您需要并行运行这个。让我提出一个 MapReduce-y 的方法:
- 通过解析每个字符串,将每一行映射成一对形式为<的名称、数量>。
- 按名称分组。
- 通过对数量求和来减少。
如果您熟悉 SQL 和关系数据库,您可能会想到类似的解决方案。该查询类似于
select user, sum(bought_fruits)
from fruit_transactions group by user;
为什么 MapReduce 缩放
注意映射器不需要看到整个文件,只需要看到一些行。另一方面,减速器,只需要具有相同名称的线(属于同一组的线)。
你可以在同一台计算机上用许多不同的线程来做这件事,然后把结果连接起来。
或者,您可以让许多不同的进程运行地图作业,并将它们的输出提供给另一个运行归约作业的集合。
如果日志足够大,您甚至可以在许多不同的计算机上运行 Mapper 和 Reducer 进程(比如说,在一个集群上),然后最终在某个湖中加入它们的结果。
这种解决方案在 ETL 作业和其他数据密集型应用程序中非常常见,但我不会深入研究应用程序。
如果你想了解更多关于这种可扩展解决方案的知识,我建议你去看看这本关于大规模设计应用的 O'Reilly 书籍。
用 C 语言编程 MapReduce
现在你已经了解了什么是 MapReduce,以及为什么 MapReduce 会扩展,让我们开门见山吧。
对于这第一篇文章,我们将编写两个不同的实现 Map 函数的程序。
其中一个将是单线程,介绍几个概念并展示一个简单的解决方案。另一个将使用 pthread 库来制作一个真正的多线程,和快得多的版本的 Map 。最后,我们将对二者进行比较,并运行一些基准测试。
像往常一样,所有的代码都可以在这个 C GitHub 项目上获得。
Map 在 C 中的单线程实现
首先,我们先记住地图是做什么的。
Map 函数接收一个 序列 和一个 函数 ,并返回 将该函数应用于序列中每个元素 的结果。
因为这是 C 语言,表示一个序列可以非常直接:我们可以使用一个指针指向我们映射的任何类型!
然而,有一个问题。C 是静态类型的,我们希望我们的 Map 函数尽可能的通用。我们希望它能够映射任何类型的元素序列(假设它们都共享一个类型)。我们不要在这里失去理智,孩子们。
我们如何解决这个问题?这个问题可能有几种不同的解决方案。我选择了看起来最简单的一个,但也可以随意加入其他想法。
我们将使用void*的序列,并将所有东西都转换成这种类型。这意味着每个元素都将被表示为一个指向随机内存地址的指针,而无需指定类型(或大小)。
我们将相信我们在所有这些序列元素上调用的任何函数都知道如何在使用它们之前将它们转换为正确的类型。我们有效地将那个问题委托出去了。
我们需要解决的一个小问题是序列长度。指向 void 的指针不携带序列有多少元素的信息。它只知道从哪里开始,不知道从哪里结束。
我们将通过传递序列长度作为第二个参数来解决这个问题。知道了这一点,我们的 Map 函数变得非常简单。
您可以看到,该函数接收一个void**来表示它将映射的序列,以及一个void* (*f)(void*)函数,该函数将某种泛型类型的元素转换为另一种(或相同的)元素。
之后,我们可以在任何序列上使用我们的映射函数。我们只需要事先做一些笨拙的包装和指针运算。
这里有一个例子,使用一个函数,对于质数返回 1,对于其他的返回 0。
正如所料,结果指针指向一个整数序列:1 对应于质数,0 对应于合数。
现在我们已经完成了单线程 Map 函数,让我们看看如何在 c 语言中并行运行这个函数。
C 语言中的多线程映射函数
(如果您想使用流程和分叉添加一个基准,请随时提出拉取请求!)
为了在 C 语言中使用并行执行,我们可以求助于进程或线程。
对于这个项目,我们将使用线程,因为它们更轻量级,在我看来,它们的 API 对于这类教程来说更直观一些。
如何在 C 语言中使用线程
C 中的 threads API 非常直观,即使一开始有点晦涩。
- 一个指向
pthread_t的指针:实际的线程。 - 一个配置
struct。在这种情况下,我们将使用NULL作为默认配置。 - 我们希望线程运行的函数。与进程不同,线程只会运行一个函数,直到它返回,而不是继续执行任意代码。这个函数必须接受一个
void*参数,并返回另一个void*值。 - 前述函数的输入。必须投给
void*。
要使用它们,我们必须使用#include <pthread.h>。手册页很好地解释了他们的界面。然而,对于本教程,我们将使用的是pthread_create函数。
pthread_create需要四个参数:
在调用pthread_create之后,一个并行执行线程将开始运行给定的函数。
一旦我们为我们希望映射的每个块调用了pthread_create,我们将不得不对它们中的每一个调用pthread_join,这使得父(原始)线程等待直到它旋转的所有线程完成运行。
否则,程序会在映射完成之前结束。
现在,让我们尽情欣赏一些代码。
在 C 语言中使用 pthread 实现并行 MapReduce
为了用 C 语言编写 MapReduce 的 Map 函数,我们要做的第一件事是定义一个struct来存储它的通用输入和输出,以及我们将要映射的函数。
由于并行执行需要某种方式的切片和分区,我们也将把那个逻辑存储在这个结构中,使用两个不同的索引作为我们切片的开始和结束。
接下来,我们将编写实际执行映射的函数:它将从start到end循环输入,将映射函数应用于每个输入的结果存储在输出指针中。
最后,节目的主角,启动线程的函数,给每个线程分配一个map_argument,等待所有的地图作业运行,最后返回结果。
注意这个函数如何允许我们选择我们想要多少线程,并相应地对数据进行分区。它还处理 pthreads 的创建和加入。
最后,我们在 main 中调用该函数的方式如下所示:
concurrent_map( (void**) numbers, twice, N, NTHREADS)
其中NTHREADS是我们想要的线程数,N是numbers拥有的元素数。
现在代码完成了,让我们运行一些基准测试!这真的会更快吗?所有这些包装代码会使事情变得更慢吗?让我们来了解一下!
C 语言中的映射,基准:单线程与多线程
为了衡量使用并行 Map 带来的性能提升,我测试了一些单线程算法与多线程算法的对比。
第一个基准:slow_twice
对于我的第一个测试,我使用了 slow_twice 函数,它只是将每个数字乘以 2。
你可能会奇怪,“为什么叫慢?”。答案很简单:我们将每个数字翻倍 1000 次。
这使得操作更慢,所以我们可以测量时差,而不必使用太多的数字,初始化需要太长时间。它还让我们对许多内存写入的情况进行基准测试。
因为每个数字的执行时间是恒定的,所以非并行算法的时间随着输入大小几乎成线性增长。
然后我用 2、4 和 8 个线程运行它。我的笔记本电脑有 4 个内核,我发现这也是使用线程的最佳数量。对于其他一些算法,我发现使用我的核心数量的倍数是最佳的,但事实并非如此。
基准测试结果
我将每个基准测试运行 10 次,取平均值,以防万一。
结果如下:

对于这两个测试案例,使用 4 个线程比单线程实现大约快三倍。这证明了使用并行 Map 比使用普通单线程版本要快得多。
添加 4 个以上的线程也是有代价的,可能是由于初始化和上下文切换的开销。
第二个基准:is_prime
对于这个基准测试,我编写了一个朴素的质数测试函数:它简单地遍历所有小于输入的数,如果任何数被整除,则返回 1,否则返回 0。
注意,这个函数对每个元素取 O(n ),而不是 O(1 ),所以数据的一些分区(有序的)会比其他的慢很多。我想知道这会如何影响运行时间?

在这种情况下,并行算法再次击败了单线程算法。没有什么大的意外。然而,这一次当使用超过 4 个线程时有了一个改进!
我认为这是因为在对我们的输入进行分区时,将它分成更小的块会使最慢的分区花费更少的时间,从而使我们的瓶颈变小。
结论
我从这个实验中获得了很多乐趣。
挑选多少线程使用比仅仅“使用相同数量的内核”要困难得多,而且很大程度上依赖于我们的输入,即使是非常愚蠢的算法。
这可能有助于我们理解为什么优化集群的配置对于一个大型应用程序来说是一项如此艰巨的任务。
将来,我可能会添加一个并行的 reduce 实现来完成这个小框架。
其他一些可能会很有趣并且我可能会在未来运行的基准测试是 C 语言中的MapvsPython 列表理解,以及 C 语言 vs SIMD 汇编。
如果你想提升数据科学家的水平,可以看看我的 最佳机器学习书籍 清单和我的 迎头痛击教程 。
记住,你可以以任何你喜欢的方式使用这段代码,或者运行你自己的实验,如果你这样做了,请不要忘记在评论中让我知道你的结果!
如果你想对我说什么或问什么,请随时在 Twitter 、 Medium 或 dev.to 上联系我!
原载于 2019 年 10 月 19 日http://www . data stuff . tech。
马拉松围兜识别和认可
使用深度学习和图像处理来识别马拉松围兜上的数字。

Me after finishing the Mumbai Marathon 2019, and, of course, the bib number recognition (using AWS Rekognition API)
开始
我最近参加了一场马拉松。几天后,我收到了一封电子邮件,里面有一个链接,我可以在那里查看并下载我的比赛日照片。我需要把我的号码放在网页上,它就会调出所有我的照片。这让我思考这是如何成为可能的!
对于那些不熟悉跑步项目的人来说,围兜是一张贴有电子标签的纸。这个标签用来记录运动员在马拉松过程中的准确时间。围兜也有一个独特的围兜号码,用大字体印刷,还有跑步者的名字和其他一些文字。(见照片供参考)
我开始思考标记照片的可能方法。一个显而易见的方法是手动标记——有一组人看着照片,阅读围嘴号码,并用这些围嘴号码标记照片。这是一项繁琐的任务,假设每场马拉松会有超过 5000 张照片。另一种方法是使用计算机视觉。
计算机视觉
我的理念是,任何需要人类看着一幅图像,然后以一种近乎机械的方式跟着它做动作的任务,都可以而且应该用计算机视觉来实现自动化。我们拥有最先进的算法来解决这个问题,并拥有强大的计算能力来实现这些解决方案。为什么不利用它呢?这个项目就是这样开始的。
我开始探索不同的计算机视觉技术,这些技术可以用来给照片贴上号码标签。我将简要描述我能想到的每一种方法:
- EAST text detector+tessera CT text recognition:想法是首先检测图像中的文本区域,然后识别文本以识别 bib 号码。我使用 EAST 文本检测器模型来识别图像中带有文本的区域,然后将这些区域传递给 Tesseract 模型来识别文本。
优点:实施简单快捷。
缺点:不太准确,会检测到照片中的大量其他文本。 - 图像处理使用 OpenCV 识别围脖区域,然后进一步处理围脖区域提取数字。提取的数字可以传递给预先训练的 ML 模型以识别号码。
优点:对计算能力要求不高。
缺点:很难概括不同的围兜设计 - 分割使用深度学习模型,如 MaskRCNN,从图像中分割出 bib。在 bib 上应用图像处理来提取数字。将提取的数字传递给预先训练的 CNN 网络以识别数字。
优点:分割围脖和识别数字的准确性高。
缺点:功耗大,因此速度较慢,难以针对不同的围兜设计推广图像处理方法 - 物体检测使用深度学习模型直接识别 bib 号码区域而不是整个 bib。与以前的方法相比,这可以为我们节省许多图像处理步骤。应用图像处理来提取数字,并将它们传递给预先训练的 CNN 网络来识别它们。
优点:与前面的方法类似,深度学习模型可以非常准确。
缺点:计算要求高 - 人脸识别:这种方法在识别照片中的跑步者方面具有很大的优势,即使围兜被遮挡,这种情况确实经常发生。有多种方法来实现面部识别,我不会进入它的细节,因为它本身可以是一本书。我会马上提到我能想到的几种方法。一种方法是根据注册时提供的身份证照片匹配人脸(可能使用暹罗网络和三联丢失)。另一种方式可以是上述两种方法的混合。我们可以基于人脸识别将每个跑步者的照片聚集在一起,然后尝试从其中一张照片上读取围兜号码,在那里围兜清晰可见。
- 来自谷歌(Vision)、AWS (Rekognition)或微软 Azure 的基于云的 API:使用这些 API 来检测和识别图像中的文本,然后过滤掉 bib 号码(可能使用所有 bib 号码的数据库)。
项目
首先,我尝试了第一种方法,以了解一个经过一般训练的模型将如何处理这个问题。不出所料,它的表现不是很好。无法保证正确识别 bib 编号,而且在图像中检测到大量假阳性文本。我将在以后的文章中写更多关于它的内容。后来,我开始尝试(第三)种方法,包括使用实例分段。这是这个项目的核心。
当我第一次着手解决这个问题时,它似乎不是一个大任务。只有当我深入到这个项目中,细微之处开始浮出水面时,我才意识到这个问题是多么具有挑战性。只是给你一个想法,唯一可能的方法,我可以得到正确阅读的照片上的数字在顶部是使用 AWS Rekognition API。虽然对人类来说阅读这个围嘴可能很容易,但训练计算机阅读这个数字就没那么简单了。我用自定义图像处理管道得到的最好结果是“1044”而不是“21044”。这是有原因的,比如为不同的围兜设计和配色方案创造一个通用的启发。我将在以后的博客中讨论。
我提出的解决方案可能还不是最好的。我意识到对解决方案的改进是无止境的。这个解决方案的端到端执行是本系列文章的主题。我选择这个项目的主要原因是尝试构建计算机视觉项目的各个方面——收集数据集、注释图像、实现用于分割的深度学习模型、图像处理、创建用于 OCR 的 CNN 模型、为给定的数据集定制训练、将这些不同的部分缝合在一起等。
我会把上面提到的每一个部分都写出来,并分享代码。您可以自由地获取代码并进行改进,或者将其用于您自己的应用程序。从这个项目中学到了很多,我希望社区能从中受益。
请随时留下任何建议/评论/批评。我会尽可能快。
这是这个系列的下一部分:
[## 创建数据集—使用 Selenium 和 BeautifulSoup 抓取马拉松图片
创建用于围兜识别的马拉松图像数据集(第 1 部分)
三月版:理解如此多的数据
8 篇必读文章

What are the most pressing problems in data science? Take our survey
在 21 世纪,我们有幸在计算、存储和数据方面取得了快速进步。数据可能是新的石油,但如果没有正确的工具、方法和基础设施,它就像坐在油井上无所事事一样毫无用处。随着越来越多的企业试图从其海量数据存储中获取丰富的信息,大数据不再被大肆宣传,而是一种必需品。机器学习和深度学习模型变得越来越好,越来越快,产出比以前更多,当时它们只是在小型玩具数据集的研究论文中展示。
机器学习与云计算相结合可以成为您组织的主力,帮助您解决现实世界的问题,而不必担心购买、设置和维护基础架构。除此之外,它对于利用大规模集群上的深度学习在 GPU 上进行数字运算非常方便。
随着包括 Auto-ML 和元学习在内的机器学习领域的快速发展,我强烈认为,要构建挖掘机器学习最大潜力的端到端项目,数据科学家应该建立一套多样化的技能,不仅要构建模型,还要能够处理大规模数据集,扩展他们的解决方案,还要关注他们的解决方案最终如何在现实世界中部署和使用的端到端工程方面。我希望我们收集的这些不同的文章能让你对这些方面有所了解。
— 迪潘然(DJ)萨卡尔,TDS 编辑
从 0 到百万用户的规模机器学习
由朱利安·西蒙 — 11 分钟读完
我认为大多数机器学习(ML)模型都是在白板或餐巾纸上构思出来的,诞生于笔记本电脑上。当这些羽翼未丰的生物开始咿咿呀呀地说出它们的第一个预言时,我们充满了自豪,并对它们未来的能力寄予厚望。
如何使用 Dask 数据帧在 Python 中运行并行数据分析
由卢西亚诺·斯特里卡 — 5 分钟阅读
有时候,你打开一个包含 Python 熊猫的大型数据集,试图获取一些指标,整个事情就僵住了。
为什么以及如何使用大数据熊猫
由阿德蒙德·李 — 5 分钟阅读
在现实世界中,数据不可避免地是杂乱的。在清理、转换、操作和分析数据方面,Pandas 是真正的游戏规则改变者。简单来说,熊猫帮着收拾残局。
利用深度学习的最新进展预测股价走势
通过鲍里斯 B — 34 分钟读取
在这本笔记本中,我将创建一个预测股票价格变动的完整过程。坚持下去,我们会取得一些不错的成果。为此,我们将使用一种生成式对抗网络(GAN ),其中 LSTM 是一种递归神经网络,作为生成器,而卷积神经网络 CNN 作为鉴别器。
学习足够有用的 Docker
由杰夫·黑尔 — 7 分钟读完
容器对于提高软件开发和数据科学中的安全性、可再现性和可伸缩性非常有帮助。它们的崛起是当今科技领域最重要的趋势之一。
创业公司数据科学项目流程
通过 Shay Palachy — 20 分钟阅读
最近,我正在咨询的一家初创公司( BigPanda )要求我就数据科学项目的结构和流程发表意见,这让我思考是什么让它们独一无二。
让你的神经网络说“我不知道”——使用 Pyro 和 PyTorch 的贝叶斯神经网络
由 Paras Chopra — 17 分钟阅读
构建图像分类器已经成为新的“hello world”。还记得你第一次遇到 Python 的那一天,你的打印“hello world”感觉很神奇吗?
不,机器学习不仅仅是美化了的统计学
由乔·戴维森 — 10 分钟阅读
机器学习真的没什么好兴奋的,或者它只是古老的统计技术的修正,这种观点越来越普遍;问题是这不是真的。
我们也感谢最近加入我们的所有伟大的新作家,尤金·西多林,埃申·乔利,约翰·科,保罗·穆尼,兰迪·奥,普拉奇·贾恩,格雷格·萨默维尔,贾维尔·伊达米,亚历克斯·克鲁格,萨姆 路易斯·加文,特恩·波林,吉勒斯·范德维尔,柳文欢·拉松,弗洛里安·林德斯塔德以及许多其他人。 我们邀请你看看他们的简介,看看他们的工作。
三月疯狂-分析视频以检测球员、球队和尝试投篮的人
用数据做很酷的事情!
介绍
这是三月疯狂月!这是一个多么激动人心的赛季。作为数据科学家,让我们利用这个机会对篮球片段做一些分析。通过使用深度学习和 opencv,我们可以从视频剪辑中提取有趣的见解。见下面的例子 gif 的游戏 b/w UCF 和杜克大学,我们可以确定所有的球员+裁判,标签球员到球队的球衣颜色为基础。在博客的后面,我将展示我们如何识别哪个球员试图投篮。所有这些都可以实时完成。

Detecting players and teams
你可以在我的 Github repo 上找到代码
那我们开始吧。
检测玩家
我已经使用了一个预训练的检测模型,如更快的 RCNN 来检测球员。很容易从 Tensorflow 对象检测 API 下载一个在 COCO 数据集上训练的更快的 RCNN 并测试它。API 将图像的每一帧作为输入,并在 80 个不同的类别中进行检测。如果你是 Tensorflow 对象检测的新手,想了解更多,请查看这个博客。该模型在检测人方面做得相当好,但是由于人群中有大量的人,所以在该视频中有许多检测。参见下面的样品检测。我抑制了太大的检测,以更干净地分割出球员。您还可以在 API 中使用分数阈值来过滤掉低可信度检测。查看 Github 上的代码,了解如何抑制分数低和多次错误检测的盒子的提示。

Detection output from Pretrained Tensorflow model
探测队
现在有趣的部分来了。我们如何检测哪些球员是 UCF 对杜克大学?我们可以使用 OpenCV 来做到这一点。
如果您不熟悉 OpenCV,请参阅下面的教程:
OpenCV 允许我们识别特定颜色的面具,我们可以用它来识别白人和黑人球员。主要步骤是:
- 将图像从 BGR 转换到 HSV 色彩空间。
- 在 HSV 空间中,指定白色和黑色的颜色范围。这需要一点实验,你可以在笔记本中想象不同阈值的影响。
- 使用 OpenCV 遮蔽(着色)阈值范围内的像素。
- OpenCV Bitwise_and 将不在蒙版中的任何像素涂成黑色
白色请参见下面的输出。它们被伪装成“粉红色”,背景中的其他东西都是黑色的

Detecting white colour pixels
为了识别每个玩家的团队,我们从 tensorflow 对象检测中提取边界框,并计算边界框中非黑色像素的百分比,以确定该玩家的团队。
整体代码工作得很好。然而,这是一个识别黑白球衣球员的硬编码逻辑。通过使用聚类来查找相似的玩家,可以使其更通用
检测姿势和拍摄者
OpenPose 是一个实时多人姿势检测库。它可以检测图像中的人,并输出每个人的主要关节的关键点——每个人最多可以有 25 个关键点。代码是开源的。你必须按照自述文件中的建议安装这里。安装后,你可以通过它运行图像,并获得场景中所有球员的关键点,如下所示。

Open pose output
那么我们如何识别试图投篮的球员呢?
我们可以寻找手腕关键点在头顶的玩家。意味着举起双手。这可能表明像上面的场景一样准备射击,或者可能是防御性的。此外,球的坐标以及手腕关键点的坐标可用于识别哪个玩家举手将球靠近他们。
结论
深度学习通过链接不同的想法,使得进行真正酷的分析成为可能。有许多开源代码和预训练的模型,您可以使用这些数据开始学习。以上只是起点。其他可以做的很酷的事情包括:
- 使用 OCR 读取比赛分数,让您的系统了解哪个队赢了
- 跟踪球以预测何时射门得分
- 跟踪玩家以获得每个玩家的统计数据
- 检测事件,如灌篮,三分篮球等。
希望你拉代码自己试试。
我有自己的深度学习咨询公司,喜欢研究有趣的问题。我已经帮助许多初创公司部署了基于人工智能的创新解决方案。请到 http://deeplearninganalytics.org/的来看看我们吧。
你也可以在https://medium.com/@priya.dwivedi看到我的其他作品
如果你有一个我们可以合作的项目,请通过我的网站或 info@deeplearninganalytics.org 联系我
参考文献
- Tensorflow 对象检测 API
- 关于使用 OpenCV 检测颜色的好教程
马里奥对瓦里奥——第二轮:CNN 在 PyTorch 和 Google Colab

在 PyTorch 中快速构建卷积神经网络对视频游戏截图进行分类
很长一段时间我都在玩 Google Colab(是的,免费访问 GPU…)。我认为这是一个非常棒的倡议,它使个人电脑上没有 GPU 的人能够玩深度学习和训练模型,否则他们将无法训练。基本上,我们有 12 个小时的时间来玩,然后虚拟机就死了。但是,我们当然可以开始一个新的会议,并且有办法继续以前会议的工作。
在这篇文章中,我想介绍我之前的作品的延伸。然而这一次,我将使用 PyTorch 构建一个 CNN,并在 Google Colab 上对其进行训练。最终,我希望取得比以前更好的成绩!开始吧:)
1。建立谷歌实验室
Medium 上已经有一些关于如何开始使用 Google Colab、如何启用 GPU 等的好文章。我想展示几个有用的命令来检查我们实际上在做什么样的硬件/软件:


我们看到我们正在开发 Tesla K80,并且已经安装了 Cuda 9.2。这样事情就简单多了!
找到如何有效处理存储在 Google Drive 上的大型数据集并不容易。许多课程和帖子使用 PyTorch 或其他库中的内置数据集。但是一开始,我发现使用我自己的一组图像有点棘手。所以我做了以下事情:
- 将数据集(带有训练/测试文件夹的压缩文件)上传到 Google Drive。
这可以通过驱动程序 UI 轻松完成。最初的目录树如下所示:
mario_vs_wario/
training_set/
mario/
mario_1.jpg
mario_2.jpg
...
wario/
wario_1.jpg
wario_2.jpg
...
test_set/
mario/
mario_1.jpg
mario_2.jpg
...
wario/
wario_1.jpg
wario_2.jpg
...
- 安装 Google Drive
使用 Colab 时,重要的是将文件存储在 Colab 目录中,而不是安装在 Google Drive 上。下面的单元格包含连接到 Google Drive 并安装该驱动器的代码,这样我们就可以访问存储在那里的所有文件。然而,用从 Google Drive 加载的数据训练神经网络(即使启用了 GPU)在大多数情况下会比在 CPU 上本地训练它慢得多。这是由于在 Colab 和 Drive 目录之间复制所有数据,这非常慢。
- 将 zip 文件从我的 Google Drive(通过可共享的链接)移动到在 Colab 环境中创建的目录中,然后解压缩。
为了解决上述问题,我分别压缩了训练集和测试集,并通过使用gdown和 Google Drive 的链接(当您在 Drive 的 UI 中单击 download shareable link)下载文件。然后,我将包含图像的文件夹解压到指定的目录。在最后一步,我删除了一个剩余的目录。
2.加载数据
在这一部分,我加载并预处理数据(图像)。我将一步一步地描述这个过程:
- 首先,我定义了一些参数和我想在图像上执行的转换(调整到 128x128,转换成张量和归一化)。这也是我可以进行图像放大(随机裁剪,剪切,旋转等)的步骤。).然而,由于这个特殊的问题是关于视频游戏图像的分类,我认为应用这些转换没有意义,因为图像将不再类似于原始截图。但是,如果您正在构建一个猫/狗分类器,并且没有真正大的数据集(即使您有),这将是应用转换的地方。
- 我为训练/测试数据指定目录,并应用所选择的转换。
- 我从训练集中随机选择了一个索引子集来使用它们进行验证。我还创建了从给定索引(不是整个数据集)中采样图像的
SubsetRandomSampler。 - 我通过组合数据集和采样器来创建
DataLoader。在 GPU 上训练的情况下,我使用pin_memory = True(推荐设置)。对于test_loader,我也混洗数据集,否则,它将首先从一个类中取出所有观察值,然后从第二个类中取出所有观察值,而不进行任何混洗。在测试集的情况下,这实际上无关紧要。但是知道这个功能是很好的。
在下面的代码中,我检查了 10 张随机选择的图片。由于DataLoaders作为迭代器工作,我首先使用iter(),然后使用next()来获得随机选择的图像及其标签(来自第一批)。

3.CNN 架构
我提出了两种定义神经网络结构的方法。第一种方法是构建一个继承自nn.Module的类。第二个更类似于 Keras,我们创建了一系列的层。这里没有对错,完全看个人喜好。
在这两种方法中,我使用了相同的架构,所以在培训之前应该只使用一种。
3.1.课堂教学方法
我定义了一个继承自nn.Module的类,它与super().__init__()结合创建了一个跟踪神经网络架构的类,并提供了各种方法和属性。需要注意的是,该类必须继承自nn.Module。
该类必须包含两个方法:__init__和forward。
我会对每一个必需的方法做更多的解释:
__init__-用于定义类的属性,并在初始化时填充指定的值。一个规则是总是调用super()方法来初始化父类。除此之外,我们可以定义所有的层,这些层具有一些要优化的参数(要调整的权重)。我们不需要定义激活函数,比如这里的relu,因为给定相同的输入,它们将总是返回相同的输出。定义的层的顺序并不重要,因为这些纯粹是定义,而不是指定层如何连接的架构。forward-在这种方法中,我们定义了层之间的连接。我们指定它们连接的顺序,并最终返回网络的输出。另外,变量不一定要被称为x,重要的是它以正确的顺序通过各层。
3.2.顺序方法
对于那些使用过 Keras 的人来说,Sequential方法可能很熟悉。我创建了一个OrderedDict,按照执行的顺序指定了每一层。使用OrderedDict的原因是我可以给这些层起一个有意义的名字。如果不这样做,它们的名字将是整数。
开始时,我定义了一个Flatten类,它基本上将矩阵重新整形为一个长向量,就像 CNN 通常做的那样。OrderedDict放在nn.Sequential中,它定义了我们的模型。
4.损失函数和优化器
第一步是将模型转移到 Cuda,以防它将在 GPU 上训练。然后,我将二进制分类问题的损失函数和优化器指定为学习率为 0.01 的随机梯度下降。
5.训练网络
网上已经有很多关于训练神经网络所需步骤的资料。我将只概述这些步骤:
- 正向通过网络(如
forward()方法中所述) - 根据网络输出计算损耗
- 用
loss.backward()反向通过网络计算梯度 - 通过使用优化器来更新权重
还有其他一些事情值得一提:
optimizer.zero_grad()-当使用相同的参数进行多次反向传递时,梯度在累积。这就是为什么我们需要在每次向前传递时将梯度归零。- 训练时,我们可能会使用辍学来防止过度适应。然而,对于预测/验证,我们想要使用整个网络,因此我们需要通过使用
model.eval()将丢失概率更改为 0(关闭它)。要返回训练模式,我们使用model.train()。 torch.no_grad()-关闭验证渐变,节省内存和计算
为了有一个可重用的框架来训练 CNN,我将逻辑封装在一个函数中。我假设网络将在训练和验证损失的情况下被训练。当然,它可以进一步参数化,只有当参数不是None时,才可以考虑验证集。不过对于这款笔记本的情况来说,相信这已经足够了。
那么训练模型就归结为:

我检查了显示培训/估价损失随时代演变的图表。我们的目标不仅是减少培训损失,也是减少验证损失。如果训练损失继续减少,而验证损失增加,我们将观察到过度拟合-模型将不能很好地概括训练期间没有看到的数据。在这种情况下,我们看到模型的损失在第 7 个历元之后(或者更早,取决于偏好)没有显著减少。
鉴于此,我将从第 7 纪元开始加载模型。通过保存所有的中间模型,我能够看到测试集的性能会是什么样子(以防万一,我想比较)。
6.评估测试集的结果
在这一部分,我在测试集上评估网络的结果,即网络在训练期间没有见过的那个。我编写了一个与验证脚本类似的脚本,不同之处在于我存储的用于评估的指标数量。
准确率 99%,甜!让我们来看一些更详细的统计数据:
- 99.2%的召回率——这意味着从数据集中的所有 Wario 截图来看,该模型正确预测了其中的 99.2%。
- 99.3%的精确度——这意味着在所有的 Wario 预测中,99.3%实际上都是 Wario。
- 99.25%的 F1 分数—没有明确的解释,因为 F1 分数是精确度和召回率的加权平均值。在类分布不均匀的情况下,F1 比精度更有用。就像在这种情况下,测试集中有相同数量的 Mario/Wario 类,准确度= F1 分数。
总的来说,该网络在图像分类方面做得非常出色。2000 张照片中只有 15 张分类错误。为了获得更多的洞察力,我们将在下面考察其中的一些。

我不得不说,网络在这些图片上遇到麻烦并不奇怪。有些明显是来自游戏的过渡帧(地图和关卡之间或者屏幕之间加载屏幕)。没有办法从中推断出正确的游戏。其余的是地图或来自 Wario(第三张图片)的特定屏幕。这些游戏的地图非常相似,就像从等轴视图中看到的角色一样。
我不得不说,我对这个网络的表现和 PyTorch 总体上非常满意。它提供了很多可能性,并且非常具有 pythonic 风格。要了解更多关于 PyTorch 的基础知识,我会推荐你去 Udacity 的免费“PyTorch 深度学习简介”MOOC,你可以在这里找到。
如果你对这篇文章有任何反馈,请在评论中告诉我。一如既往,整个笔记本可以在我的 GitHub repo 上找到。
马克·吐温曾写道…或者是爱伦坡?

BiblioEater is all set to identify the writer
作者归属的 StanfordNLP 和 Keras
假设你追随某个作家,吞食了她/他的任何一部作品。如果给你提供一本全新的书,你检查几段就能认出作者的风格吗?
很可能你会。这篇文章的目的是探索一台机器完全做到这一点的可能性。我们将分析两位著名作家作品的一些文学特征,然后训练一个神经网络将新的文本分配给一位或另一位作家。
我们的工具将是刚刚推出的 StanfordNLP Python 包,我们最近写了一个简短介绍以及直观的深度学习 API Keras,在我们的例子中是 Tensorflow。我们将由此产生的模型戏称为食书者。

Edgar Allan Poe and Mark Twain
作者和他们的书
我们选出了两位十九世纪的著名作家。一边是非常有趣的马克·吐温,另一边是才华横溢的讲故事者埃德加·爱伦·坡。两个原因导致我们选择他们。我们需要足够老的作品进入公共领域。我们还希望两位作者使用大致相同的语言变体,在他们的例子中是美国英语。
请记住,StanfordNLP 包括能够处理 53 种不同人类语言的模型,因此您可以使用相同的方法将雨果与左拉或塞万提斯与奎维多进行比较。
我们将从一个稍微更具挑战性的角度来处理这个问题,而不是像机器学习中的规范那样,获取每个作者的一批文本,并在训练和验证桶中分割数据集。我们将用两本小说进行训练,用两本不同的作品进行验证。即:
- 亚瑟·戈登·皮姆的叙述将被用来训练埃德加·爱伦·坡式的读书人。
- 《汤姆·索亚历险记》将被用来为马克·吐温做同样的事情。
- Eureka 将用于验证 Poe 模型。爱伦·坡主要写短篇小说,但我们选择了长篇小说,尽管不太长。
- 而哈克贝利·费恩历险记是吐温为了验证而选的作品。
这种方法有许多障碍:书籍的主题不同,作者可能随着时间的推移而演变,等等。
此外,在所选的吐温小说中,作者使用了当地方言。虽然这可能有助于对文本进行分类,但从解析的角度来看,这将是一个挑战。
另一方面,《尤利卡》不是一部虚构的作品,爱伦坡在写作的时候,他的个性可能已经跨越了天才和疯子之间的界限。
然而,我们打赌,每个作者的作品中都有某种文学特征。
环境
我们在一个 Ubuntu 盒子里用 Python 3.6 工作过。GitHub 中提供了用于生成本文中讨论的结果的完整代码(细节在底部)。
数据集足够小,可以在没有 GPU 的工作站上运行神经网络训练,尽管有一个 GPU 总是有帮助的。下载英文版的 StanfordNLP 模型可能是更耗时的任务。

Polishing the text — but not a lot!
文本准备
只要遵守许可条款,古腾堡计划就有数以千计的免费电子书——大多数情况下,你必须避免分发任何修改过的副本。我们用网络浏览器下载了上面提到的四篇文章。
之后,我们用标准的文本编辑器删除了不需要分析的文本部分。这使得我们无法按照古登堡计划的许可分发它们,所以如果你想运行代码,你需要直接从古登堡计划下载电子书。
我们还在吐温的两部作品中发现了许多弯曲的双引号和下划线。我们在文本编辑器中处理它们。对于我们的目的,这种级别的数据清理就足够了。然而,让我们记住,一流的数据准备+平均算法往往胜过平均数据清理+一流的算法。
从语法上分析
正如我们在上一篇文章中所解释的,我们将应用 StanfordNLP 模型来解析这些书中的每一个句子。这将为每个单词分配的词性和的特征。例如:
他拿起画笔,平静地开始工作
从汤姆·索亚,变成了
He (PRON - Case=Nom|Gender=Masc|Number=Sing|Person=3|PronType=Prs) took (VERB - Mood=Ind|Tense=Past|VerbForm=Fin) up (ADP - _) his (PRON - Gender=Masc|Number=Sing|Person=3|Poss=Yes|PronType=Prs) brush (NOUN - Number=Sing) and (CCONJ - _) went (VERB - Mood=Ind|Tense=Past|VerbForm=Fin) tranquilly (ADV - _) to (PART - _) work (VERB - VerbForm=Inf)
看看不同句子中语言的使用,我们期望捕捉到作者的部分写作风格。例如,这项研究的一个目标曾经写道:
当你抓住一个形容词时,杀死它。(马克·吐温)
所以你不会期望在他的文章中过度使用形容词。事实上,我们会看到坡在形容词的使用上超过了吐温——尽管不是很多。
一些文体特征
我们接受这样的假设,每个作家都有他/她自己的文学风格,这样的个人足迹应该是显而易见的,即使看一些粗糙的特征,就像下面的那些。有一门名为文体学的成熟学科专门研究这些现象。
句子长度

你喜欢简短直接的句子,还是喜欢制造复杂冗长的句子?(哦不,四个形容词,对不起马克!)在所附的图表中,很明显吐温比爱伦·坡更喜欢使用短句——这并不奇怪。
以这样或那样的方式,我们的作者属性算法应该捕捉这个特征,因为它看起来很有鉴别性。
词类的使用
在 StanfordNLP 的帮助下,我们为两本书的每个句子都指定了词类。作者中动词、形容词和名词的比例是多少?数据会有什么不同吗?

Usage of parts-of-speech in both works
Poe 倾向于更重视介词,如中的或到*,以及从属连词,如 if 或 while。这暗示了一种更复杂的风格。吐温的书比坡的书包括更多的标点符号,这与组成更短的句子是一致的。*
这个简单的分析没有显示出词性之间的顺序关系。正如我们将要展示的,这是一份适合阅读者的好工作。
其他功能
以上只是我们可以在两个文本中分析的特征的几个例子。鉴于 StanfordNLP 所提供的,我们可以看看作品的其他特点:
- 单词特征可用于建立动词的使用方式(哪种时态和模式是首选?)以及类似的名词(单数、复数)。
- 词汇的使用。例如,单词 vessel 在《亚瑟·戈登·皮姆》中出现了 96 次,而在《汤姆·索亚》中一次也没有出现。同样,吐温写了 156 次男孩,这个词没有出现在 Pym 中。这似乎是一个棘手的话题,因为词汇可能过多地与情节联系在一起,就像这里的情况,而不是与写作风格联系在一起。
- 我们甚至还没有触及 StanfordNLP 中的依赖解析器。它分析句子,识别主要术语或句法中心。那些词头(动词、名词等)的选择。)可能与每个作家的选择有关。
文本结构分类与作者归属
让我们直接进入分类。给定这些书中的一篇短文,找出它最可能的作者。
战略
有许多关于二进制或多标签文本分类的深入文章。这就是为什么我们在这里做一些稍微不同的事情。我们不是用实际的文本来训练我们的网络,而是只输入它的语法结构。
所以对于 BiblioEater 来说,这两句话看起来是一样的:
红狮子追逐瞪羚
我们年轻的研究员找到了解决办法
因为两者都符合 DET-ADJ-名词-动词-DET-名词的顺序。让我们记住,我们不会使用单词特征,例如限定词是被定义的冠词()还是所有格代词( Our )。
通过这样做,我们忽略了大量的信息,我们的模型可能会因为保留它们而变得更好。然而,这篇文章的目的是要表明,即使信息有限,我们也能捕捉到作者的部分风格。请继续阅读。
一键编码
如果我们是在处理文字,比如加利纳·奥莱尼克 这里所解释的 word2vec 将是一个自然的选择。但是我们只处理 17 种不同的词性。因此,我们可以很容易地提供一个独热编码,将它们中的每一个表示为长度为 17 的向量,所有元素都设置为零,只有一个元素对应于语音的顺序位置。视觉上,
红狮子追赶瞪羚。(DET-ADJ-名词-动词-DET-名词-标点)
转换为

段落,而不是句子
在确定了我们将如何处理文本之后,我们现在来解决我们向模型提供多少文本以确定作者的问题。一次一个句子似乎太少了,因为两个作者产生相同句法结构的几率有时似乎很高。
我们决定输入 3 个连续的句子作为网络的输入。我们称之为一个段落,尽管从技术上来说,大部分时间它并不是一个段落。
Tom Sawyer 是两部作品中最长的一部,我们对所有生成的段落进行采样,因此 Tom 和 Pym 在训练过程中使用相同数量的段落来代表他们。
输出显然是二进制的:要么是 Poe,要么是 Twain 是作者。

Ready to eat books
阅读者——神经网络
在定义神经网络的拓扑结构时,你可以随心所欲地发挥创造力。但是考虑几件事情:
- 我们讨论的是输入层的几千个段落。不完全是大数据,是吗?我们必须小心,不要设计太重的网。
- 整个练习归结为一个简化的文本分类问题,就像 Yoon描述的用词性代替原始单词的问题。
因此,我们选择了相对简单的设计,甚至比 Yoon 论文中的设计还要简单:

BiblioEater topology
它由一系列基本的卷积层和最大池层对组成,最后由两个密集层组成,以获得二进制输出。你也可以找几个脱层作为防止过度合身的安全网。该代码保存了 BiblioEater 类中的所有细节。
驱动训练过程的各种参数,例如过滤器数量、步幅等。可以在代码中找到。它们被隔离为常量,以便于调整和比较结果。
当 StanfordNLP 使用 PyTorch 进行机器学习时,我们自然会选择 PyTorch 而不是 Keras。然而,我们用 Keras,因为它通常更容易阅读。
结果
利用代码中保存的建模值, BiblioEater 有 18,954 个参数,不是很多,因此即使是一个无 GPU 的工作站也可以轻松处理训练工作。我们输入了来自两本书的偶数个带标签的段落,得到了 0.9313 的准确度。不算太坏,我们已经提到了所有的警告。
但是当我们强迫食书者吞下《尤利卡》和《哈克贝利·费恩历险记》时,布丁的真正证据就来了。请记住,这些书中的任何文本都没有包含在培训中。还要记住,每次网络上出现的都是 3 句话的段落,这并不多。这是我们得到的混淆矩阵。

因此,阅读者在 90%以上的时间里都对两本它以前没看过的书。这是考虑到我们决定不包括但在文本中存在的所有特征。如果我们给它输入 4 句话的段落,我们可以为每个作者增加大约 0.015 的准确率。
调整参数,我们得到了类似的结果,但结果有些不稳定,这表明数据集有点小。也许我们应该选择狄更斯的所有作品!
我能运行代码吗?
你当然可以。从 github 下载,请先通读 README.md 文件。
结论
作家在作品中打上自己风格印记并不新鲜。我们在这篇文章中试图传达的是他如何仅仅基于三个连续句子的词性来处理文本归属。添加我们忽略的功能后,我们的结果应该会显著改善。高质量开源软件(Keras、Tensorflow 和最近的 StanfordNLP)的出现使这成为可能。
降价单元格— Jupyter 笔记本
我不知道如何开始。这将是我第一个与编程相关的故事。今天,我将努力缩小 Jupyter 笔记本中的降价单元格描述。我想我不必在 Jupyter 笔记本上花费太多的文字。根据 Jupyter.org的说法,“ Jupyter 笔记本是一个开源的网络应用程序,允许你创建和分享包含实时代码、方程式、可视化和叙述文本的文档”。Markdown 是一种流行的标记语言,被用作数据科学家和分析师的标准。它既不是 HTML Markdown 的超集,也不是 HTML 的替代品,甚至接近它。它的语法非常小,只对应于 HTML 标签的一个非常小的子集。通常在 Jupyter Notebook 中,单元格类型默认为 code。如果我们想要输入任何文本来描述不被认为是代码的任何东西,那么我们需要使用单元格类型作为 Markdown。
要将 code 单元格转换为 markdown 单元格,我们可以使用快捷键 m 从切换工具栏或单元格菜单中更改单元格类型。现在让我们简要讨论 Jupyter Notebook 支持的 markdown 语法。


Convert cell type from Code to Markdown
标题:有六种类型的标题,每种标题都以散列符号**(#)**开头,后跟一个空格,其中最大的标题使用单个散列,最小的标题使用六个散列符号。
可选地,标题可以以标记标签开始,即,从标题 1 到标题 6,具有以下语法。如果我们单击工具栏上的 run 按钮,输出文本将如下图所示。如果有人想描述几个问题,用几个标题类型来突出问题的重要性是很容易的。

Output for Headings and Headings 2 markdown cell.
样式和变化(粗体、斜体文本、背景):markdown 中的标题和其他文本都可以是粗体、斜体或常规字体样式,有几种颜色和不同的背景颜色。我们也可以改变字体 像时间新罗马或 Calibri。
枚举列表:通过 markdown 可以形成有序列表、项目符号列表或嵌套的条目列表。一个编号列表是由 HTML 的<ol>标签完成的,也可以应用在 Markdown 中。也可以应用几种其他方法来制作这种有序或无序的列表。
1\. First
1\. First one
2\. First two
2\. Main list <br>
a. Sub-list <br>
b. sub list
3\. Main list
* main list
* A
* B
* C
+ A
+ B
+ C
- A
- B
- C
内部&外部链接(超链接):以 http 或 https 开头的 Markdown 文本自动呈现超链接。外部和内部超链接都可以通过以下方式添加。Markdown 中的内部链接以<a>标签开始,该标签具有由属性‘id’定义的唯一 id。
<a> [https://www.google.com](https://www.google.com) </a> <br>
<a href="[http://www.google.com](http://www.google.com)">Google</a><br>[http://typora.io](http://typora.io)<br>
[Google]([https://www.google.com](https://www.google.com))<br><a id =integer> </a>
[Arman](#integer)
表格:表格可以在 markdown 单元格中通过管道符号**(|)**和破折号**(-)**组成,用来标记列和行。分号(:)或 das **(-)** 符号用于对齐各列。
图像:您可以从工具栏中插入图像,方法是从编辑菜单中选择“插入图像”,并从您的计算机中选择目标文件夹中的图像。我们还可以通过以下命令在 markdown 单元格上添加图像。
<img src="Name.png" width="240" height="240" align="right"/>


Inserting image using the Edit menu.
方程式:在 markdown 单元格中提到方程式时,数学符号包含在 ' $symbol here$ ' 中。内联表达式可以通过用$包围 latex 代码来添加,而在它们自己的行上的表达式用$$包围。
$e^{i\pi} + 1 = 0$
$$e^x=\sum_{i=0}^\infty \frac{1}{i!}x^i$$
$$e^{i\pi} + 1 = 0$$<br>
$\sqrt{k}$
Github 风味降价:使用反引号或左引号 **()**` 键三次,我们可以获得与降价单元格输出相同的代码风味甲酸盐。
```python
A = "Python syntax highlighting"
print(A)
for i in range(0,10):
print(A)
输出:

GitHub flavored Markdown.
**块引号、换行符和水平线:**换行符使用 2 个空格或该代码进行手动换行符:`<br>`。可以通过使用符号`'>'`或包含预期文本分块列表的`<blockquote>text for blockquote</blockquote>`获得块引号。我们还可以使用`(___) or (***) or (---)`三个连字符或标记标签添加一条水平线`<hr>.`文本或标题可以通过`<center>text<center>`集中。
Professor says
It's good forThis is good> 1 Blockquotes2 Blockquotes
3 Blockquotes
4 Blockquotes
8 BlockquotesAsterisks
Underscores
hipen--- #
This is a centered header
```我已经在 GitHub 库中添加了 markdown 单元格的所有命令。你可以在这里查看。
[## arman-Null/Markdown-Cells-Jupyter-笔记本
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/Arman-Null/Markdown-Cells---Jupyter-Notebook.git)
我感谢丹尼尔·布克、乔纳森·惠、何塞·马西亚尔·波尔蒂利亚和威尔·科尔森以及其他一些人,他们总是激励我在这个神奇的平台上写作。我会试着继续写具体的问题。
参考链接:
- https://www . data camp . com/community/tutorials/markdown-in-jupyter-notebook
- https://www . tutorialspoint . com/jupyter/jupyter _ notebook _ markdown _ cells . htm
- https://jupyter-Notebook . readthedocs . io/en/stable/examples/Notebook/Working % 20 with % 20 Markdown % 20 cells . html # Markdown-basics
- https://medium . com/IBM-data-science-experience/markdown-for-jupyter-notebooks-cheat sheet-386 c05 aeebed
基于购物篮分析的关联规则挖掘
无监督学习&数据库中的知识发现

https://sarit-maitra.medium.com/membership
M 市场购物篮分析 (MB)是一种关联分析,是一种流行的数据挖掘技术。这是一种数据中的知识发现(KDD) 这种技术可以应用于各种工作领域。在这里,我将使用一个零售交易数据,并展示如何向企业提供信息来捕获买方的购买行为。这也可以是决策支持系统的一部分。
各种形式的数据挖掘可应用于这类数据集,例如分类、关联、预测、聚类、异常值分析等。在这里,我将重点介绍关联规则挖掘技术,它发现隐藏在数据集中的有趣关系。如果你有兴趣,可以访问我早前的文章(1);(2);(3)。
我们很多人都熟悉 UCI 机器学习数据库发布的以下数据集。MB 分析中使用的数据是事务性数据。在这里,数据具有 MB 分析的所有基本成分。然而,从我的经验来看,交易数据很少或者我们可以说,从来不会以这种格式出现。因此,由于交易数据的复杂性,数据清理和数据读取是 MB 分析的主要活动。



让我们看看数据框的尺寸以及唯一的发票号和客户号

如果我们比较【发票号】和【描述】,我们可以看到一些行没有发票号。
data[‘invoiceno’].value_counts()

让我们删除没有发票号的行,并删除信用交易(发票号包含 C 的交易)。

现在,我们需要将商品合并为每行 1 个交易,每个商品 1 个热编码。让我们检查数据框中的国家名称。

让我们看看澳大利亚的销售情况,并将结果与法国的销售情况进行比较。在我们深入分析之前,让我们先了解一下关联规则。
关联规则挖掘
在这种情况下,规则生成是挖掘频繁模式的首要任务。关联规则是形式为 x → y,的蕴涵表达式,其中 x 和 y 是不相交的项目集。为了评估这样一个关联规则的【兴趣】,已经开发了不同的度量标准。我将使用 支持、 和 提升 度量。
韵律学
假设商品 x 正在被客户购买,那么商品 y 在同一个交易 ID 下被客户挑选的几率也就被找出来了。衡量联想有 3 种方式: 支持度、 信心度、 升力度。
Support {freq (x,y) / n,range: [0,1]} 给出包含项目 x 和 y 的交易的分数。它告诉我们经常购买的项目或经常购买的项目组合,我们可以筛选出频率较低的项目。
Confidence {freq(x,y) / freq (x),range: [0,1]} 根据 x 出现的次数,告诉我们 x 项和 y 项一起出现的频率。
Lift { support/support(x) support(y),range: [0,inf]}* 表示一个规则对 x 和 y 的随机出现的强度,它解释了一个规则的强度,Lift 越大就是强度越大。
Apriori 算法
这是一种数据挖掘方法,也是关联规则的基础。Apriori 算法使用【频繁项集】生成关联规则。它考虑到了一个【频繁项集】的子集也一定是一个【频繁项集】。【频繁项集】 >的值超过一个阈值(即支持度)。

数据中有相当多的零,但我们还需要确保任何正值都被转换为 1,任何小于 0 的值都被设置为 0。因此,让我们对数据应用一种热编码,并删除邮资列;我们不打算探讨邮资。

既然数据的结构是正确的,我们可以生成支持度至少为 7%的频繁项集(选择这个数字是为了让我得到足够多有用的例子)。
数据挖掘中的信心和支持
- 为了选择感兴趣的规则,我们可以使用最著名的约束,这些约束是置信度和支持度的最小阈值。
支持度是项集在数据集中出现频率的指示。信心是规则被发现为正确的频率的指示”
# generate the rules with their corresponding support, confidence
# and lift
frequent_itemsets = apriori(basket_sets, min_support=0.07, use_colnames=True)
print (frequent_itemsets)rules = association_rules(frequent_itemsets, metric=”lift”, min_threshold=1)
rules.head()

如果我们打印关联的数量,我们会看到找到了 800 条关联规则。



support=rules.as_matrix(columns=[‘support’])
confidence=rules.as_matrix(columns=[‘confidence’])
下面的支持度和置信度散点图显示了数据集的关联规则(前 10 个规则)。

让我们看看这告诉了我们什么。例如,我们可以看到有相当多的规则具有很高的值,这意味着它比给定的交易和产品组合的数量所预期的更频繁地出现。我们还可以看到几个 置信度 也很高的地方。在这方面,领域专长有很大优势。我就在这里找一个大 抬 (6)高 信心 (0.8)。

查看规则,我们可以发现," RED retro spot CAKE STAND "和 "36 支铅笔管 RED RETROSPOT" 是一起购买的,而 "4 个传统旋转陀螺"、"闹钟 BAKELIKE GREEN "和" RED DINER WALL CLOCK" 是一起购买的,购买方式高于整体概率。在这一点上,我们可能想看看有多少机会可以利用一种产品的受欢迎程度来推动另一种产品的销售。

我们可以看到,虽然有关联规则存在,但是相比于 385 个数字的“36 支铅笔管红色逆行点”而言,只有 73 个数字的“红色逆行点蛋糕摊”所以也许企业必须采取某种策略来使两者不相上下。
同样有趣的是,看看不同购买国家的组合是如何变化的。让我们来看看在法国有哪些流行的组合。



所以,这样我们就可以比较,准备一份分析报告。根据我们定义的关联规则,我们发现一些产品之间存在显著的相关性。这里应用的先验算法具有一定的阈值。我们也可以试验不同阈值。**越大抬抬**意味着联想越有趣。具有高 支持度 的关联规则是潜在有趣的规则。类似地,具有高 置信度的规则 也会是有趣的规则。
购物篮分析——多支持频繁项目集挖掘
对缺省 MSApriori 算法的改进。

Pic credit: Upgrad
简介:
从交易数据库(购物篮)中生成关联规则的问题是许多零售商感兴趣的。关联规则的形式是𝑋 → 𝑌,其中 x,y 是 I(所有产品(或项目)的集合)和𝑋 ∩ 𝑌 = ∅.的子集
可以将上述关联规则的含义理解为,如果顾客购买了集合 X 中的物品,那么他可能购买集合 y 中的物品。关联规则的一些众所周知的例子可以是{ Milk }--> {Bread } 、{ Milk }--> { Bread,Eggs} 、{ Bread,Butter }--> { Jam }和幽默的{ Diapers }--> { Beer }。请注意,关联规则是不可交换的,即𝑋 → 𝑌不等于𝑌 → 𝑋.
为给定的交易数据库(市场篮)寻找关联规则的问题定义如下:
a.给定一个大小为 z 的事务数据库,其中有 n 个不同的项目和一个输入支持度和置信度,找出满足给定支持度和置信度约束的所有规则𝑋 → 𝑌。
b.支持度是一个阈值,该阈值将确定 X 中的项目是否足够频繁以被考虑用于关联规则生成。更具体地说,如果{X}。count / Z >= support,那么 X 被认为是一个频繁项集。
c.置信度是决定购买 y 的条件概率的阈值。更具体地说,如果{𝑋⋃𝑌}.count / {X}。计数> =置信度,则𝑋 → 𝑌被视为有效的关联规则。
假设零售商销售了“N”种不同的商品/产品,那么计数和生成关联规则的强力方法的复杂度为 O(N!).
Apriori 算法是对蛮力算法的改进,它基于这样的观察:只有当 X 的所有真子集都是频繁项目集时,项目集 X 才是频繁项目集。这将减少为生成所有可能的关联规则而需要探索的状态/规则的数量。Apriori 算法根据这一原理工作,分两步执行
a.在大小为 1,2,3…k 的事务数据库中查找所有频繁项集。
b.从频繁项目集 2,3,4…k 中生成所有有效的关联规则。
c.如果不能再生成 k + 1 大小的频繁项集,则停止。
Apriori 算法至少需要对事务数据库进行“k”次扫描。
MSApriori:
MSApriori 代表多重支持 Apriori,它是 Apriori 算法在现实生活场景中的一个更受约束的定义。Apriori 算法只考虑交易中所有项目的一个支持值,而不管项目是频繁销售的项目(如杂货)还是不太频繁销售的项目(高价项目,如家居装饰)。因此,要为经常/很少售出的商品建立称重方案,每件商品都有单独的支撑。MSApriori 算法的问题定义修改如下:
a.给定一个交易数据库和每个项目和置信度的不同最小输入支持(MIS ),找出满足给定支持和置信度约束的所有规则𝑋 → 𝑌。
b.支持度是一个阈值,该阈值将确定 X 中的项目是否足够频繁以被考虑用于关联规则生成。由于 MSApriori 中对不同的项目有不同的支持,任何满足其集合中项目的最小 MIS 的项目集合都被认为是频繁的。更具体地说,如果
a.|X| = 1,
- {X}。count/n > = miss(X),那么 X 被认为是一个频繁项集。
b.|X| >= 1,
- {X}。count / n >= MIN (MIS(X1),MIS(X2),MIS(X3)…MIS(Xk));Xi ∈ X,i=1 到 k
c.为了阻止非常频繁和不太频繁的项目一起出现在任何频繁项目集合中,在候选项目集合 X 上施加支持差异约束φ
a.|X| >= 1,
- MAX(Supp(X1),Supp(X2)…Supp(Xk))–MIN(Supp(X1),Supp(X2) … Supp(Xk)) <= Φ
The task of assigning MIS to items must be done in a meticulous manner. For highly moving items such as daily groceries, a high value of MIS is desired. For not so frequently sold items such as high end electronics, a less value of MIS is desired. One such assignment of MIS can be done using the following approximation.
MIS (item) = δ * Supp (item); δ ∈ [0, 1]
The above assignment is discussed in 刘兵等人的网络挖掘。求解 MSApriori 的算法也是刘兵在上面的书里提出的,姑且称之为默认的 MSApriori 算法。默认的 MSApriori 算法对每个候选项集 Ck 扫描事务数据库;k > =2 来计算频繁项集 Fk。
考虑到数据库中有“Z”个总事务和“N”个唯一项,默认的 MSApriori 算法需要计算对所有 C2 的支持;如果每个项目的 MIS 按上述等式定义,C2 将有 N*(N-1)/2 个项目集。
总时间复杂度= N*(N-1)/2 * Z ~ O(n3)。
类似地,C3、C4… Ck 也会有相应的复杂性,这是基于项集的大小乘以数据库中的事务数量。
对 MSApriori 的改进建议:
对缺省 MSApriori 提出的改进是使用一种前瞻策略,在事务数据库扫描的第一遍中计算每个 Ck 的支持,将它们存储在哈希表(Hk)中,并在需要时检索它们。在事务数据库扫描的第一遍中,对于长度为“L”的每个事务,每个 Ck (k <= L) is generated locally and the count of its support increased in Hk. So, for C2, the proposed modification would work as follows,
/* modified MSApriori Algorithm form Bing et al */Modificaiton-1: init-pass()For each item(i) in Transaction T:a. Compute/increment the support of item(i)b. For each item(j) in Transaction T: // (j>i)
Compute the hashcode of itemset(i,j)
Retrieve the support of itemset(i,j) from the hash table(H2)
Initialize/Increment the support of itemset(i,j).Modificaiton-2: CandidateGen2() //Candidate generation function for 2-itemsetFor each item(i) in list L/C2:
For each item(j) in list L: // (j>i)
Compute the hashcode of itemset(i,j)
Retrieve the support of itemset(i,j) from the hash table(H2)
If support > MIS(item(i)) // and other constrains like Φ
Return itemset(i,j) into F2.
NOTE: CandidateGen2() directly returns the items into F2, no need for scanning the transaction database again!
In the Modificaiton-1, an extra sub-loop is added for each transaction to compute the support for 2-itemsets, assuming the average length of transaction is ‘L’ then this step would add further processing time of L*(L-1)/2 for each transaction in the database. Assuming, there are ‘Z’ transactions in the database, the time required to complete the init-pass() is
Time complexity (init-pass) = L*(L-1)/2 * Z
~= c * Z ~ O(Z) //for all practical reasons L << Z
In the Modificaiton-2, I am adding an extra step for accessing the hash table (H2) which can be done in constant time (TH) in most library implementations. The time required to complete CandidateGen2() is given as
Time complexity = N(N-1)/2TH ~ O(n2).
Combining both modifications, total time complexity = O(Z) + O(n2) < O(n3)! (from the default algorithm).
Verification of the result:
The default MSApirioi algorithm is implemented by Phillipe et al in the 开源 java data mining library SPMF )。我已经用我在 MSAprori _ H.java 程序中提出的修改修改了 SPMF 库中的默认 MSApriori 算法。MSApriori 和 MSApriori_H 的执行结果如下:
考虑的数据集:retail1.txt
数据集中不同项目的数量:N = 2603。
数据集中的事务数量:Z = 541909。

关于此算法的哈希函数要求的注释。理想情况下,我们需要一个散列函数,它能为一组整数提供唯一的散列值,而不考虑给定集合中整数的顺序。生成这样一个散列函数肯定不是一件简单的任务,所以我在实现中将散列值放宽为一个 Java 对象。我选择了一个要在 MSApriori_H.java 中实现的 BitSet 对象。
MSApriori_H.java 中的哈希函数:
/* Input k-item set in Integer[] items */BitSet hashcode = new BitSet(Integer.MAX_VALUE);for(int i=0; i<items.length; i++) {hashcode.set(items[i])};return hashcode;
带推荐人的购物篮分析
我对购物篮分析的看法——第 2 部分,共 3 部分

Photo by Victoriano Izquierdo on Unsplash
O verview
最近我想学习一些新的东西,并挑战自己进行端到端的市场篮子分析。为了继续挑战自己,我决定将我的努力成果展示给数据科学界。
这是三柱中的第二柱,排列如下:
加载包
*# Importing libraries
library(data.table)
library(tidyverse)
library(knitr)
library(recommenderlab)*
数据
为了进行分析,我将使用在第 1 部分中准备和清理的retail数据集。如果你想继续这篇文章,确保你得到了数据集并运行第 1 部分的 R 代码,你可以在我的 Github 简介中找到。
***glimpse(retail)
## Observations: 528,148
## Variables: 10
## $ InvoiceNo <dbl> 536365, 536365, 536365, 536365, ...
## $ StockCode <chr> "85123A", "71053", "84406B", "...
## $ Description <fct> WHITE HANGING HEART T-LIGHT HOLDER, ...
## $ Quantity <dbl> 6, 6, 8, 6, 6, 2, 6, 6, 6, 32, 6, 6, 8, ...
## $ InvoiceDate <dttm> 2010-12-01 08:26:00, 2010-12-01 08:26:00, 2010-12...
## $ UnitPrice <dbl> 2.55, 3.39, 2.75, 3.39, 3.39, 7.65, ....
## $ CustomerID <dbl> 17850, 17850, 17850, 17850, 17850, ...
## $ Country <fct> United Kingdom, United Kingdom, ...
## $ Date <date> 2010-12-01, 2010-12-01, 2010-12-01, ...
## $ Time <fct> 08:26:00, 08:26:00, 08:26:00, 08:26:00, ...***
系统模型化
对于这个项目的分析部分,我使用的是re commender lab,这是一个 R 包,它提供了一个方便的框架来评估和比较各种推荐算法,并快速建立最适合的方法。
创建评级矩阵
在开始之前,我需要在一个评级矩阵中安排购买历史,订单按行排列,产品按列排列。这种格式通常被称为 user_item matrix ,因为“用户”(例如客户或订单)往往位于行上,而“项目”(例如产品)位于列上。**
推荐者实验室接受两种类型的评级矩阵用于建模:
- 实际评分矩阵由实际用户评分组成,需要标准化。
- 二进制评级矩阵,由 0 的和 1 的组成,其中 1 的表示产品是否被购买。这是分析所需的矩阵类型,不需要标准化。
但是,在创建评级矩阵时,很明显有些订单不止一次包含相同的商品,如下例所示。
***# Filtering by an order number which contains the same stock code more than onceretail %>%
filter(InvoiceNo == 557886 & StockCode == 22436) %>%
select(InvoiceNo, StockCode, Quantity, UnitPrice, CustomerID)## # A tibble: 2 x 5
## InvoiceNo StockCode Quantity UnitPrice CustomerID
## <dbl> <chr> <dbl> <dbl> <dbl>
## 1 557886 22436 1 0.65 17799
## 2 557886 22436 3 0.65 17799***
向 UCI 机器学习库 捐赠该数据集的公司可能有一个订单处理系统,该系统允许将一个项目多次添加到同一订单中。对于这个分析,我只需要知道一个项目是否包含在一个订单中,因此需要删除这些重复的项目。
***retail <- retail %>%
# Create unique identifier
mutate(InNo_Desc = paste(InvoiceNo, Description, sep = ' ')) # Filter out duplicates and drop unique identifier
retail <- retail[!duplicated(retail$InNo_Desc), ] %>%
select(-InNo_Desc)# CHECK: total row count - 517,354***
我现在可以创建评级矩阵。
***ratings_matrix <- retail %>%
# Select only needed variables
select(InvoiceNo, Description) %>% # Add a column of 1s
mutate(value = 1) %>%# Spread into user-item format
spread(Description, value, fill = 0) %>%
select(-InvoiceNo) %>%# Convert to matrix
as.matrix() %>%# Convert to recommenderlab class 'binaryRatingsMatrix'
as("binaryRatingMatrix")ratings_matrix
## 19792 x 4001 rating matrix of class 'binaryRatingMatrix' with 517354 ratings.***
评估方案和模型验证
为了确定模型的有效性,推荐者实验室实施了许多评估方案。在这个scheme中,我选择 train = 0.8 进行 80/20 训练/测试分割,将数据分割成一个训练和一个测试集。我还设置了 method = "cross" 和 k = 5 进行 5 重交叉验证。这意味着数据被分成 k 个大小相等的子集,80%的数据用于训练,剩下的 20%用于评估。模型被递归估计 5 次,每次使用不同的训练/测试分割,这确保了所有用户和项目都被考虑用于训练和测试。然后可以对结果进行平均,以产生单个评估集。
选择 given = -1 意味着对于测试用户来说,除了 1 个项目外,所有随机选择的项目都被保留进行评估。
***scheme <- ratings_matrix %>%
evaluationScheme(method = "cross",
k = 5,
train = 0.8,
given = -1)scheme
## Evaluation scheme using all-but-1 items
## Method: 'cross-validation' with 5 run(s).
## Good ratings: NA
## Data set: 19792 x 4001 rating matrix of class 'binaryRatingMatrix' with 517354 ratings.***
设置算法列表
推荐实验室的主要特性之一是能够一次评估多个算法。首先,我用我想要估计的algorithms创建一个列表,指定所有的模型参数。在这里,我考虑在二元评级矩阵上评估的方案。我包含了随机项目算法,用于基准测试。**
***algorithms <- list(
"association rules" = list(name = "AR",
param = list(supp = 0.01, conf = 0.01)),
"random items" = list(name = "RANDOM", param = NULL),
"popular items" = list(name = "POPULAR", param = NULL),
"item-based CF" = list(name = "IBCF", param = list(k = 5)),
"user-based CF" = list(name = "UBCF",
param = list(method = "Cosine", nn = 500))
)***
评估模型
我现在要做的就是将scheme和algoritms传递给evaluate()函数,选择 type = topNList 来评估前 N 个产品推荐列表,并使用参数 n = c(1,3,5,10,15,20) 指定要计算多少个推荐。
请注意基于 CF 的算法每种都需要几分钟来估计。
***results <- recommenderlab::evaluate(scheme,
algorithms,
type = "topNList",
n = c(1, 3, 5, 10, 15, 20)
)## AR run fold/sample [model time/prediction time]
## 1 [0.32sec/73.17sec]
## 2 [0.24sec/72.72sec]
## 3 [0.23sec/72.27sec]
## 4 [0.24sec/72.82sec]
## 5 [0.24sec/72.69sec]
## RANDOM run fold/sample [model time/prediction time]
## 1 [0sec/20.08sec]
## 2 [0sec/19.01sec]
## 3 [0sec/18.69sec]
## 4 [0sec/19.26sec]
## 5 [0.02sec/19.41sec]
## POPULAR run fold/sample [model time/prediction time]
## 1 [0.01sec/15.94sec]
## 2 [0sec/16.34sec]
## 3 [0sec/15.91sec]
## 4 [0.02sec/16.02sec]
## 5 [0.01sec/15.86sec]
## IBCF run fold/sample [model time/prediction time]
## 1 [515.11sec/3.11sec]
## 2 [513.94sec/2.88sec]
## 3 [509.98sec/3.05sec]
## 4 [513.94sec/3.13sec]
## 5 [512.58sec/2.81sec]
## UBCF run fold/sample [model time/prediction time]
## 1 [0sec/296.54sec]
## 2 [0sec/291.54sec]
## 3 [0sec/292.68sec]
## 4 [0sec/293.33sec]
## 5 [0sec/300.35sec]***
输出存储为包含所有评估的列表。
***results## List of evaluation results for 5 recommenders:
## Evaluation results for 5 folds/samples using method 'AR'.
## Evaluation results for 5 folds/samples using method 'RANDOM'.
## Evaluation results for 5 folds/samples using method 'POPULAR'.
## Evaluation results for 5 folds/samples using method 'IBCF'.
## Evaluation results for 5 folds/samples using method 'UBCF'.***
想象结果
推荐者实验室有一个基本的plot功能,可用于比较型号性能。然而,我更喜欢把结果整理成整齐的格式,以增加灵活性和图表定制。
首先,我以一种方便的格式安排一个模型的混淆矩阵输出。
***# Pull into a list all confusion matrix information for one model
tmp <- results$`user-based CF` %>%
getConfusionMatrix() %>%
as.list() # Calculate average value of 5 cross-validation rounds
as.data.frame( Reduce("+",tmp) / length(tmp)) %>% # Add a column to mark the number of recommendations calculated
mutate(n = c(1, 3, 5, 10, 15, 20)) %>%# Select only columns needed and sorting out order
select('n', 'precision', 'recall', 'TPR', 'FPR')## n precision recall TPR FPR
## 1 1 0.06858938 0.07420981 0.07420981 0.0002327780
## 2 3 0.04355442 0.14137351 0.14137351 0.0007171045
## 3 5 0.03354715 0.18148235 0.18148235 0.0012076795
## 4 10 0.02276376 0.24627561 0.24627561 0.0024423093
## 5 15 0.01762715 0.28605934 0.28605934 0.0036827205
## 6 20 0.01461690 0.31627924 0.31627924 0.0049253407***
然后,我把前面的步骤代入一个公式。
***avg_conf_matr <- function(results) {
tmp <- results %>%
getConfusionMatrix() %>%
as.list()
as.data.frame(Reduce("+",tmp) / length(tmp)) %>%
mutate(n = c(1, 3, 5, 10, 15, 20)) %>%
select('n', 'precision', 'recall', 'TPR', 'FPR')
}***
接下来,我使用purrr包中的map()函数以一种整齐的格式获得所有结果,为图表制作做好准备。
***# Using map() to iterate function across all models
results_tbl <- results %>%
map(avg_conf_matr) %>% # Turning into an unnested tibble
enframe() %>%# Unnesting to have all variables on same level
unnest()results_tbl## # A tibble: 30 x 6
## name n precision recall TPR FPR
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 association rules 1 0.0428 0.0380 0.0380 0.000197
## 2 association rules 3 0.0306 0.0735 0.0735 0.000579
## 3 association rules 5 0.0266 0.0979 0.0979 0.000944
## 4 association rules 10 0.0224 0.139 0.139 0.00179
## 5 association rules 15 0.0202 0.162 0.162 0.00255
## 6 association rules 20 0.0188 0.176 0.176 0.00325
## 7 random items 1 0.000202 0.000219 0.000219 0.000250
## 8 random items 3 0.000253 0.000820 0.000820 0.000750
## 9 random items 5 0.000242 0.00131 0.00131 0.00125
## 10 random items 10 0.000222 0.00241 0.00241 0.00250
## # ... with 20 more rows***
受试者工作特征曲线
可以使用 ROC 曲线来比较分类模型的性能,该曲线绘制了真阳性率 (TPR)与假阳性率* (FPR)。***
基于项目的协同过滤模型是明显的赢家,因为它在任何给定的 FPR 水平上都实现了最高的 TPR。这意味着,对于相同级别的不相关推荐(误报),该模型正在产生最高数量的相关推荐(真阳性)。
注意使用fct_reorder2()按最佳最终 FPR 和 TPR 排列情节图例条目,用曲线排列它们,使情节更容易阅读。
***results_tbl %>%
ggplot(aes(FPR, TPR,
colour = fct_reorder2(as.factor(name),
FPR, TPR))) +
geom_line() +
geom_label(aes(label = n)) +
labs(title = "ROC curves", colour = "Model") +
theme_grey(base_size = 14)***

精确回忆曲线
另一种比较分类模型性能的常用方法是使用精度与召回曲线。Precision 显示模型对假阳性(即推荐不太可能被购买的商品)的敏感程度,而 Recall(TPR 的另一个名称)则显示模型对假阴性(即不推荐极有可能被购买的商品)的敏感程度。**
通常,我们关心的是准确预测哪些商品更有可能被购买,因为这将对销售和收入产生积极影响。换句话说,我们希望在精度相同的情况下,最大化召回(或最小化 FNs)。**
该图证实了基于项目的协作过滤器* (IBCF)是最好的模型,因为它对于任何给定的精度水平都具有更高的召回率。这意味着 IBCF 将所有级别的第一手资料的 FNs 降至最低(即不建议购买可能性很高的物品)。***
***results_tbl %>%
ggplot(aes(recall, precision,
colour = fct_reorder2(as.factor(name),
precision, recall))) +
geom_line() +
geom_label(aes(label = n)) +
labs(title = "Precision-Recall curves", colour = "Model") +
theme_grey(base_size = 14)***

对新用户的预测
最后一步是生成具有最佳性能模型的预测。为此,我需要创建一个虚构的采购订单。
首先,我创建了一个包含 6 个随机选择的产品的字符串。
***customer_order <- c("GREEN REGENCY TEACUP AND SAUCER",
"SET OF 3 BUTTERFLY COOKIE CUTTERS",
"JAM MAKING SET WITH JARS",
"SET OF TEA COFFEE SUGAR TINS PANTRY",
"SET OF 4 PANTRY JELLY MOULDS")***
接下来,我将这个订单以一种推荐者 lab* 接受的格式放置。***
***new_order_rat_matrx <- retail %>% # Select item descriptions from retail dataset
select(Description) %>%
unique() %>% # Add a 'value' column with 1's for customer order items
mutate(value = as.numeric(Description %in% customer_order)) %>% # Spread into sparse matrix format
spread(key = Description, value = value) %>% # Change to a matrix
as.matrix() %>% # Convert to recommenderlab class 'binaryRatingsMatrix'
as("binaryRatingMatrix")***
现在,我可以创建一个Recommender。我使用getData来检索训练数据,并设置 method = "IBCF" 来选择性能最好的模型(“基于项目的协同过滤”)。
***recomm <- Recommender(getData(scheme, 'train'),
method = "IBCF",
param = list(k = 5))recomm## Recommender of type 'IBCF' for 'binaryRatingMatrix'
## learned using 15832 users.***
最后,我可以将Recommender和生成的订单传递给predict函数,为新客户创建前 10 名推荐列表。
***pred <- predict(recomm,
newdata = new_order_rat_matrx,
n = 10)***
最后,建议的项目可以作为一个列表进行检查
***as(pred, 'list')## $`1`
## [1] "ROSES REGENCY TEACUP AND SAUCER"
## [2] "PINK REGENCY TEACUP AND SAUCER"
## [3] "SET OF 3 HEART COOKIE CUTTERS"
## [4] "REGENCY CAKESTAND 3 TIER"
## [5] "JAM MAKING SET PRINTED"
## [6] "RECIPE BOX PANTRY YELLOW DESIGN"
## [7] "SET OF 3 CAKE TINS PANTRY DESIGN"
## [8] "GINGERBREAD MAN COOKIE CUTTER"
## [9] "3 PIECE SPACEBOY COOKIE CUTTER SET"
## [10] "SET OF 6 SPICE TINS PANTRY DESIGN"***
评论
这就结束了这个项目的建模和评估部分,我发现这很简单,也很愉快。 recommenderlab 直观易用,我特别欣赏它同时评估和比较几种分类算法的能力。总之,我已经学会了如何在 R 中使用 recommenderlab 进行市场购物篮分析,以解释结果并选择表现最佳的模型。
代码库
完整的 R 代码可以在我的 GitHub 简介中找到
参考
- 有关推荐的实验室包,请参见:https://cran.r-project.org/package=recommenderlab
- 关于推荐者实验室软件包简介,请参见:https://cran . r-project . org/web/packages/re commender lab/vignettes/re commender lab . pdf
原载于 2019 年 3 月 25 日https://diegousei . io。**
市场概况:金融市场的统计观点
关于如何在 Matplotlib 中绘制市场轮廓的简单介绍和简短方法

Market profile is a technique used to contextualize current market conditions.
市场概况方法简介
市场分析是 J. Peter Steidlmayer 在 60 年代开发的一种技术。该方法代表给定市场在给定时期的统计分布。
Steidlmayer,一个富裕农民的儿子,在 60 年代成为 CBOT 的场内交易者,并最终在 80 年代初成为 CBOT 导演之一。他融合了最小相关价格变动、平衡和高斯分布的概念,定义了一种方法,可以跟踪特定市场在特定时间的变动情况。
市场概况理论在几本书中都有适当的介绍,在互联网上也有一些好的资料。这种方法在 80 年代末和 90 年代引起了极大的兴趣,Steidlmayer 是这种方法的主要推动者,他还在 80 年代初负责在 CBOT 提供第一批电子数据服务。虽然它不再是一种主流的分析技术,但它仍然拥有一批积极使用它的追随者。
市场概况使用时间和价格来定位交易时段的价值区域(即参与者认为给定资产/工具的公允价格所在的价格区域)。虽然它不是一种交易方法或系统,但它是一种分析给定市场当前状态的可靠方法,因为它有助于澄清市场是否正在盘整或形成趋势。
市场概况优于交易量概况的一个优点是不需要交易量数据。这对于不受监管的场外交易市场来说尤其有趣,在这种市场中,交易量信息要么不可用,要么没有意义。它还允许使用非昂贵的历史数据进行模拟。
由于市场概况使用 TPO(时间价格机会)的概念来反映感兴趣的领域,这些领域与高交易量领域高度相关。所以最后,这两种方法可以得到相似的结果,有时看到这两种情况如此相似真的令人吃惊。对此的解释是,在市场上以给定的价格移动大量货物需要时间,而这一时间转化为给定价格下的大量 TPO。这有效地有助于关联市场概况和数量概况。
尽管所有主要的交易软件都有一些插件,但市场概况在某种程度上是一个不同的野兽。在 20 世纪 90 年代的巅峰时期,市场概况通常是通过专业软件(如 Steildmayer 曾经发行的软件 Capital Flow)来开发的。这种软件包价格昂贵,因为它们是为基金和机构参与者设计的。
我一直对市场和销量非常感兴趣,在过去的几个月里,我一直在深入研究和研究这些领域。
这些分析技术帮助你确定主要参与者可能在哪里,他们的行动方向是什么。有人可能会说,市场剖析是另一个时代的技术;我们不能忘记,这是 60 年代为大宗商品场内交易构想的一种方法,一些帮助市场概况发光的配套信息(如 CBOT 的流动性数据库)不再可用,但我认为支持该方法的基本统计概念仍然适用。
在我看来,平衡/不平衡和高斯分布概念的使用使该方法强大并得到科学支持,因为这些概念有助于处理无法以确定性方式描述的复杂自然过程——股票市场很适合这一类别。这是个人观点,我可能有偏见,因为我的市场策略是尽可能利用统计数据。
我对市场概况的兴趣特别集中在日内交易上。我特别使用 30 分钟蜡烛线,这是为市场概况定义的原始时间框架。30 分钟是一个没有被广泛使用的时间框架,但它有一个很大的优势,足够大以避免小时间框架的玩家(特别是 HFT),并且足够小以获得足够的日内交易。在不久的将来,我想将市场概况的概念扩展到更大的时间范围,就像 90 年代基金使用的所有主要软件一样。超越 30 分钟时间框架的优点是可以检测到有效周期——不容易但可行——通过这样做,可以预测更大的市场波动。因此,可以计划回转操作。关于如何实现这一点的一些信息包含在下一部分的书籍中。
掌握市场概况
市场概况是一个复杂的方法,需要专注和经验来掌握。对于那些有兴趣了解更多的人,我会指出我所找到的关于这个主题的最相关的书籍。

141 West Jackson and Markets & Market Logic are the classic books writen by Steidlmayer about Market Profile
关于市场概况的经典书籍有“ 141 West Jackson ”(对于那些好奇的人,那是 CBOT 在芝加哥的地址)和“ Markets & Market Logic ”。
一个更现代的重温将是 J. Peter Steidlmayer 和 Steven B. Hawkins 的《 Steidlmayer 谈市场:用市场概况进行交易》。
这三本书都很好地介绍了市场概况。“141 West Jackson ”特别令人愉快,而“Steidlmayer on Markets:Trading with Market Profile”可能是最实用的一个。
作为建设性的批评,我要指出,在某些方面,一些摘录可能过于关注专有软件的功能,而没有对这些功能如何工作进行适当的解释,这可能会给人一种被促销营销所针对的感觉。除此之外,书籍值得任何对该主题感兴趣的人阅读,因为它们是由该方法的关键利益相关者编写的。
Matplotlib 和 Python 中的市场概况
作为一个关于市场概况的实践示例,我使用 Matplotlib 在 Python 中包含了一个获取市场概况分布及其绘图的例程。
假设您在 Python 中有以下市场概况数据:
day_market_profile = [
(Decimal(1.4334), 1, 'n'),
(Decimal(1.4335), 1, 'n'),
(Decimal(1.4336), 1, 'n'),
...
(Decimal(1.4360), 14, 'bcdijklmpqrsuv'),
...
(Decimal(1.4482), 1, 'E'),
(Decimal(1.4483), 1, 'E'),
]
该数据是在定制的 market_profile 例程中获得的,该例程使用 30 分钟 TPOs 生成每日市场概况。
day = datetime(2010,1,5)
day_market_profile = market_profile(day, Decimal('0.0001'))
for i in day_market_profile:
print(str(i[0]) + ' | ' + str(i[1]).rjust(2,' ') + ' | ' + i[2])
打印元组列表会导致:
1.4334 | 1 | n
1.4335 | 1 | n
1.4336 | 1 | n
1.4337 | 1 | n
1.4338 | 1 | n
1.4339 | 1 | n
1.4340 | 1 | n
1.4341 | 1 | n
1.4342 | 3 | noq
1.4343 | 3 | noq
1.4344 | 3 | noq
1.4345 | 4 | noqr
1.4346 | 5 | bnoqr
1.4347 | 6 | bmnoqr
1.4348 | 6 | bmnoqr
1.4349 | 7 | bcmnoqr
1.4350 | 8 | bckmnoqr
1.4351 | 9 | bckmnoqrs
1.4352 | 10 | bckmnoqrst
1.4353 | 11 | bckmnopqrst
1.4354 | 14 | bcklmnopqrstuv
1.4355 | 14 | bcklmnopqrstuv
1.4356 | 13 | bcklmopqrstuv
1.4357 | 13 | bcklmopqrstuv
1.4358 | 12 | bcklmopqrsuv
1.4359 | 12 | bcdklmpqrsuv
1.4360 | 14 | bcdijklmpqrsuv
1.4361 | 14 | bcdijklmpqrsuv
1.4362 | 13 | bcdijklmpqrsu
1.4363 | 11 | bdhijklmpqs
1.4364 | 10 | bdhijklmpq
1.4365 | 11 | bdfhijklmpq
1.4366 | 12 | bdfghijklmpq
1.4367 | 11 | bdefghjklpq
1.4368 | 10 | bdefghklpq
1.4369 | 9 | bdefghklq
1.4370 | 7 | befghkl
1.4371 | 7 | abefghk
1.4372 | 6 | abefgh
1.4373 | 5 | abegh
1.4374 | 2 | ab
1.4375 | 1 | a
1.4376 | 1 | a
1.4377 | 1 | a
1.4378 | 1 | a
1.4379 | 1 | a
1.4380 | 1 | a
1.4381 | 1 | a
1.4382 | 1 | a
1.4383 | 2 | Ya
1.4384 | 2 | Ya
1.4385 | 2 | Ya
1.4386 | 4 | XYZa
1.4387 | 5 | TXYZa
1.4388 | 5 | TXYZa
1.4389 | 5 | TXYZa
1.4390 | 5 | TXYZa
1.4391 | 5 | TXYZa
1.4392 | 5 | TXYZa
1.4393 | 5 | TXYZa
1.4394 | 4 | TXYZ
1.4395 | 4 | TXYZ
1.4396 | 4 | TXYZ
1.4397 | 5 | TWXYZ
1.4398 | 5 | TWXYZ
1.4399 | 4 | TWXY
1.4400 | 5 | MTWXY
1.4401 | 6 | MTUWXY
1.4402 | 6 | MTUWXY
1.4403 | 5 | MTUWY
1.4404 | 5 | MTUWY
1.4405 | 5 | MTUWY
1.4406 | 7 | HMSTUWY
1.4407 | 6 | HMSTUW
1.4408 | 6 | HMSTUW
1.4409 | 8 | HMNSTUVW
1.4410 | 8 | HMNSTUVW
1.4411 | 8 | HMNSTUVW
1.4412 | 8 | HMNSTUVW
1.4413 | 8 | HMNSTUVW
1.4414 | 10 | HILMNSTUVW
1.4415 | 10 | HILMNSTUVW
1.4416 | 11 | AHILMNSTUVW
1.4417 | 12 | AHILMNOSTUVW
1.4418 | 13 | AHIJLMNOSTUVW
1.4419 | 13 | AHIJLMNOSTUVW
1.4420 | 14 | AHIJKLNORSTUVW
1.4421 | 14 | AHIJKLNORSTUVW
1.4422 | 15 | AGHIJKLNORSTUVW
1.4423 | 15 | AGHIJKLNORSTUVW
1.4424 | 15 | ABGHIJKLNORSUVW
1.4425 | 14 | ABGHIJKLNORSUV
1.4426 | 13 | ABGHIJKLORSUV
1.4427 | 13 | ABGHIJKLORSUV
1.4428 | 12 | ABGHIJKLORUV
1.4429 | 11 | BGIJKLOPRUV
1.4430 | 11 | BGIJKLOPRUV
1.4431 | 12 | BGIJKLOPQRUV
1.4432 | 12 | BGIJKLOPQRUV
1.4433 | 12 | BGIJKLOPQRUV
1.4434 | 11 | BGIJKLOPQRU
1.4435 | 10 | BGIJKLOPQR
1.4436 | 9 | BGIJKLPQR
1.4437 | 9 | BGIJKLPQR
1.4438 | 6 | BGIPQR
1.4439 | 5 | BGPQR
1.4440 | 5 | BGPQR
1.4441 | 4 | BGPQ
1.4442 | 4 | BGPQ
1.4443 | 4 | BGPQ
1.4444 | 4 | BGPQ
1.4445 | 4 | BGPQ
1.4446 | 5 | BCGPQ
1.4447 | 5 | BCFGP
1.4448 | 5 | BCFGP
1.4449 | 5 | BCFGP
1.4450 | 5 | BCFGP
1.4451 | 5 | BCFGP
1.4452 | 6 | BCDFGP
1.4453 | 6 | BCDFGP
1.4454 | 6 | BCDFGP
1.4455 | 5 | BCDFP
1.4456 | 4 | BCDF
1.4457 | 4 | BCDF
1.4458 | 4 | BCDF
1.4459 | 5 | BCDEF
1.4460 | 5 | BCDEF
1.4461 | 5 | BCDEF
1.4462 | 5 | BCDEF
1.4463 | 5 | BCDEF
1.4464 | 5 | BCDEF
1.4465 | 3 | BDE
1.4466 | 3 | BDE
1.4467 | 3 | BDE
1.4468 | 3 | BDE
1.4469 | 3 | BDE
1.4470 | 3 | BDE
1.4471 | 3 | BDE
1.4472 | 3 | BDE
1.4473 | 3 | BDE
1.4474 | 3 | BDE
1.4475 | 2 | DE
1.4476 | 2 | DE
1.4477 | 1 | E
1.4478 | 1 | E
1.4482 | 1 | E
1.4483 | 1 | E
这是一个老学校的茎和叶图,它是代表市场概况的规范方式。虽然这些信息是相关的,因为字母代码为您提供了关于“何时何地价格为”的直观指导,但您通常可能只对价格-时间分布感兴趣,这在没有字母代码的图表中很容易查看。如果你的简介涵盖 24 小时,这一点尤其正确,因为很难跟踪这么多的字母代码。在这种简化的情况下,更容易将数据绘制成常规图表,尽管您会丢失交易期间价格变化的信息:
%matplotlib inlinempl.rcParams['interactive'] = False
mpl.rcParams['figure.figsize'] = (16.0, 12.0)
mpl.rcParams['lines.markerfacecolor'] = 'blue'# Define price labels, we print just values ending in 0.0005 or 0.0010
df.loc[df['price'] % Decimal('0.0005') == 0, 'label'] = df['price']
df['label'].fillna('',inplace=True)
df['label']=df['label'].astype(str)df.plot.barh(x='label', y='tpo_count', legend=None)
plt.xlabel('TPO Count')
plt.ylabel('Price')
plt.title('Market Profile | EURUSD | January 5th, 2010')
plt.show()
注意我们是如何创建一个新的标签列来保存 y 轴刻度标签的。我们将只打印以 0.0005 和 0.0010 结尾的价格,因此我们使用。loc ,。fillna 并最终转换为 str 以使我们的熊猫系列被用作标签。

The graphical alternative removing the code letters enable a quick read on the areas of interest of the trading session. While the letter code is relevant information, if we want to detect areas of high activity in the session this chart is easier to read.
摘要
在文章中,我简要介绍了市场概况。我已经解释了为什么我认为市场概况在今天仍然有意义,以及我为什么这样想的一些理由。我还列举了三个主要的经典书籍,涵盖了理论和一小部分摘录代码如何绘制市场概况。没有给出获取市场概况的例程,因为它非常具体地说明了如何存储数据,但是在这个例子中,用 Python 编写的原型只用了 50 行代码。这只是一页代码。
取得联系
我对这个特定的领域非常感兴趣,所以如果你在这个行业工作,并且对市场概况感兴趣,请随时联系我。我很乐意探索任何与市场概况和数量概况相关的合作(以及服务/雇佣)。
市场反应模型

使用 Python 实现数据驱动的增长
预测促销活动的增量收益
这一系列文章旨在解释如何以一种简单的方式使用 Python,通过将预测方法应用于您的所有行动来推动您公司的发展。它将是编程、数据分析和机器学习的结合。
我将在以下九篇文章中讨论所有主题:
1- 了解你的衡量标准
2- 客户细分
3- 客户终身价值预测
4- 流失预测
7-市场反应模型
文章将有自己的代码片段,使您可以轻松地应用它们。如果你是编程的超级新手,你可以在这里很好地介绍一下 Python 和 Pandas (一个我们将在任何事情上使用的著名库)。但是仍然没有编码介绍,您可以学习概念,如何使用您的数据并开始从中产生价值:
有时候你必须先跑,然后才能走——托尼·斯塔克
作为先决条件,确保你的电脑上安装了 J upyter Notebook 和 P ython 。代码片段只能在 Jupyter 笔记本上运行。
好吧,我们开始吧。
第 7 部分:市场反应模型
通过使用我们在以前的文章中建立的模型,我们可以轻松地细分客户和预测他们的终身价值 (LTV)以达到目标。顺便提一下,我们也知道我们的销售数字会是多少。但是我们怎样才能增加销售额呢?如果我们今天打折,预计会有多少增量交易?
细分客户和进行 A/B 测试使我们能够尝试许多不同的想法来增加销售额。这是增长黑客技术的基石之一。你需要不断地思考和实验来寻找成长的机会。
将我们要向其发送产品的客户分为测试组和对照组,有助于我们计算增量收益。
让我们看看下面的例子:

在此设置中,目标群体被分为三组,以寻找以下问题的答案:
1-提供报价会增加转化率吗?
2-如果是,什么样的报价表现最好?打折还是买一送一?
假设结果具有统计学意义,折扣(A 组)看起来最好,因为它比对照组增加了 3%的转化率,比买一送一多带来了 1%的转化率。
当然,在现实世界中,事情要复杂得多。一些优惠在特定的细分市场表现更好。因此,您需要为选定的细分市场创建一个产品组合。而且,不能指望转化是成功的唯一标准。总会有成本的权衡。一般来说,当转换率上升时,成本也会增加。这就是为什么有时你需要选择一个成本友好但转化较少的报价。
现在,通过实验,我们知道了哪个报价比其他报价表现得更好。但是预测呢?如果我们预测给出一个报价的效果,我们可以很容易地最大化我们的交易,并对成本有一个预测。市场反应模型帮助我们建立这个框架。但是做这件事的方法不止一种。我们可以把它们分成两类:
1-如果你没有一个控制组(想象你对每个人做了一次公开推广,并在社交媒体上公布),那么你就无法计算增量。对于这种情况,最好建立一个预测整体销售的回归模型。之前的假设是,该模型将为促销日提供更高的销售数字。
为了建立这种模型,您的数据集应该包括促销和非促销日销售数字,以便机器学习模型可以计算增量。
2-如果您有一个控制组,您可以基于细分或个人级别建立响应模型。对他们两人来说,假设是一样的。给出要约应该会增加转化的概率。个人转化概率的上升会给我们带来增量转化。
让我们开始编码,看看我们如何建立一个个体水平的反应模型。在本例中,我们将在这里使用营销数据集和。但是我做了一些修改,使它与我们的案例更相关(你可以在这里找到****)。)
让我们导入我们需要的库并导入我们的数据:
我们数据的前 10 行:

我们的前 8 列提供个人级别的数据,转换列是我们预测的标签:****
- 最近:自上次购买以来的月数
- 历史:历史采购的价值
- used_discount/used_bogo:指示客户是否使用了折扣或先买一送一
- zip_code:邮政编码的分类,如郊区/城市/农村
- is_referral:指示客户是否是从推荐渠道获得的
- 渠道:客户使用的渠道,电话/网络/多渠道
- 报价:发送给客户的报价,折扣/买一送一/无报价
我们将建立一个二元分类模型,对所有客户的转换概率进行评分。为此,我们将遵循以下步骤:
- 构建提升公式
- 探索性数据分析(EDA)和特征工程
- 对转换概率进行评分
- 观察测试集上的结果
隆起公式
首先,我们需要构建一个函数来计算我们的提升。为了简单起见,我们假设每次转换意味着 1 个订单,平均订单价值为 25 美元。
我们将计算三种类型的抬升:
转化率提升:试验组转化率-对照组转化率
订单提升:转换提升 #测试组中已转换的客户*
收入增加:订单增加*平均订单金额
让我们构建我们的calc _ upgrade函数:
def calc_uplift(df):
#assigning 25$ to the average order value
avg_order_value = 25
#calculate conversions for each offer type
base_conv = df[df.offer == 'No Offer']['conversion'].mean()
disc_conv = df[df.offer == 'Discount']['conversion'].mean()
bogo_conv = df[df.offer == 'Buy One Get One']['conversion'].mean()
#calculate conversion uplift for discount and bogo
disc_conv_uplift = disc_conv - base_conv
bogo_conv_uplift = bogo_conv - base_conv
#calculate order uplift
disc_order_uplift = disc_conv_uplift * len(df[df.offer == 'Discount']['conversion'])
bogo_order_uplift = bogo_conv_uplift * len(df[df.offer == 'Buy One Get One']['conversion'])
#calculate revenue uplift
disc_rev_uplift = disc_order_uplift * avg_order_value
bogo_rev_uplift = bogo_order_uplift * avg_order_value
print('Discount Conversion Uplift: {0}%'.format(np.round(disc_conv_uplift*100,2)))
print('Discount Order Uplift: {0}'.format(np.round(disc_order_uplift,2)))
print('Discount Revenue Uplift: ${0}\n'.format(np.round(disc_rev_uplift,2)))
print('-------------- \n')print('BOGO Conversion Uplift: {0}%'.format(np.round(bogo_conv_uplift*100,2)))
print('BOGO Order Uplift: {0}'.format(np.round(bogo_order_uplift,2)))
print('BOGO Revenue Uplift: ${0}'.format(np.round(bogo_rev_uplift,2)))
如果我们将这个函数应用到我们的数据帧,我们将看到下面的结果:

如果我们想获得更多的转化率,折扣似乎是一个更好的选择。与没有收到任何优惠的客户相比,这带来了 7.6%的增长。BOGO(买一送一)也上涨了 4.5%。
让我们开始探索哪些因素是这种增量变化的驱动因素。
EDA 和特征工程
我们逐一检查每个特性,找出它们对转化率的影响
1-新近度
理想情况下,转换率应该下降,而新近度上升,因为不活跃的客户不太可能再次购买:
df_plot = df_data.groupby('recency').conversion.mean().reset_index()
plot_data = [
go.Bar(
x=df_plot['recency'],
y=df_plot['conversion'],
)
]plot_layout = go.Layout(
xaxis={"type": "category"},
title='Recency vs Conversion',
plot_bgcolor = 'rgb(243,243,243)',
paper_bgcolor = 'rgb(243,243,243)',
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)

直到最近 11 个月,一切都如预期的那样。然后就增加了。这可能是由于许多原因,如在这些桶中的客户数量较少或给定优惠的影响。
2-历史记录
我们将创建一个历史集群并观察其影响。让我们应用 k 均值聚类来定义历史上的重要群体:
kmeans = KMeans(n_clusters=5)
kmeans.fit(df_data[['history']])
df_data['history_cluster'] = kmeans.predict(df_data[['history']])#order the cluster numbers
df_data = order_cluster('history_cluster', 'history',df_data,True)#print how the clusters look like
df_data.groupby('history_cluster').agg({'history':['mean','min','max'], 'conversion':['count', 'mean']})#plot the conversion by each cluster
df_plot = df_data.groupby('history_cluster').conversion.mean().reset_index()
plot_data = [
go.Bar(
x=df_plot['history_cluster'],
y=df_plot['conversion'],
)
]plot_layout = go.Layout(
xaxis={"type": "category"},
title='History vs Conversion',
plot_bgcolor = 'rgb(243,243,243)',
paper_bgcolor = 'rgb(243,243,243)',
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)
聚类和图与转换的概述:
****
历史价值较高的客户更有可能转化。
3-二手折扣& BOGO
我们将结合下面的代码行来检查这两个特性:
df_data.groupby(['used_discount','used_bogo','offer']).agg({'conversion':'mean'})
输出:

之前使用过这两种产品的客户拥有最高的转化率。
4-邮政编码
与其他地区相比,农村地区的转化率更高:
df_plot = df_data.groupby('zip_code').conversion.mean().reset_index()
plot_data = [
go.Bar(
x=df_plot['zip_code'],
y=df_plot['conversion'],
marker=dict(
color=['green', 'blue', 'orange'])
)
]plot_layout = go.Layout(
xaxis={"type": "category"},
title='Zip Code vs Conversion',
plot_bgcolor = 'rgb(243,243,243)',
paper_bgcolor = 'rgb(243,243,243)',
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)

5-转介
如下所示,来自推荐渠道的客户转化率较低:

它们显示出几乎少了 5%的转化率。
6 通道

正如我们预期的那样,多通道显示了更高的转化率。使用多个渠道是高参与度的标志。
7-报价类型

获得折扣优惠的客户显示出约 18%的转化率,而 BOGO 的转化率为约 15%。如果客户没有得到优惠,他们的转化率下降约 4%。
这些数据的特征工程将非常简单。我们将应用。get_dummies()** 将分类列转换为数字列:**
df_model = df_data.copy()
df_model = pd.get_dummies(df_model)
是时候建立我们的机器学习模型来评估转换概率了。
评分转换概率
为了构建我们的模型,我们需要遵循我们在文章前面提到的步骤。
让我们从分割特征和标签开始:
#create feature set and labels
X = df_model.drop(['conversion'],axis=1)
y = df_model.conversion
创建训练集和测试集:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=56)
我们将拟合模型并得到转换概率。我们模型的 predit_proba()** 函数为每一行分配概率:**
xgb_model = xgb.XGBClassifier().fit(X_train, y_train)
X_test['proba'] = xgb_model.predict_proba(X_test)[:,1]
让我们看看概率栏是什么样子的:

从上面可以看出,我们的模型为每个客户分配了转换概率(从 0 到 1)。
最后,我们需要了解我们的模型是否运行良好。
测试集的结果
现在我们假设,折现概率、bogo 和控制组的差异应该类似于它们之间的转换差异。
我们需要使用我们的测试集来找出答案。
让我们计算折扣的预测和实际订单增长:
real_disc_uptick = len(X_test)*(X_test[X_test['offer_Discount'] == 1].conversion.mean() - X_test[X_test['offer_No Offer'] == 1].conversion.mean())pred_disc_uptick = len(X_test)*(X_test[X_test['offer_Discount'] == 1].proba.mean() - X_test[X_test['offer_No Offer'] == 1].proba.mean())
对于实际上涨计算,我们使用了转换列。对于预测的那个,我们换成了 proba 。

结果相当不错。真正的订单上升是 966 ,模型预测为 948 (1.8%误差)。****
收入上涨预测对比: 24150 vs 23700。
我们需要检查结果是否对 BOGO 有利:
real_bogo_uptick = len(X_test)*(X_test[X_test['offer_Buy One Get One'] == 1].conversion.mean() - X_test[X_test['offer_No Offer'] == 1].conversion.mean())pred_bogo_uptick = len(X_test)*(X_test[X_test['offer_Buy One Get One'] == 1].proba.mean() - X_test[X_test['offer_No Offer'] == 1].proba.mean())

BOGO 有希望的结果:
订单上升-实际与预测: 563 与 595
收入增长—实际与预测: 14075 对 14875
误差率在 5.6%左右。该模型可以受益于提高对 BOGO 要约类型的预测分数。
计算转换概率在不同领域对我们也有很大帮助。我们已经预测了不同类型优惠的回报,但它也可以帮助我们找到最大限度提升的目标客户。在下一篇文章中,我们将构建自己的提升模型。
你可以在这里找到这篇文章的 Jupyter 笔记本。
需要帮助来发展你的公司吗?点击此处与我预约免费课程。
R (PCA & K-means 聚类)市场细分—第 1 部分
已经存在了几十年的市场研究方法的数据科学方法
什么是市场细分?
对于那些营销领域的新手,这里有一个方便的维基百科式的解释:市场细分是营销中使用的一个过程,根据客户的特征(人口统计、购物行为、偏好等)将客户分为不同的群体(也称为细分)。)同一细分市场的顾客往往对营销策略的反应相似。因此,细分过程可以帮助公司了解其客户群体,锁定正确的群体,并为不同的目标群体量身定制有效的营销策略。
个案研究
本文将通过使用 r 的样本调查数据集演示数据科学方法进行市场细分的过程。在本例中,便携式手机充电器制造商 ABC company 希望了解其细分市场,因此它通过调查研究从便携式充电器用户那里收集数据。调查问题包括四种类型:1)态度 2)人口统计 3)购买过程和使用行为 4)品牌认知。在这种情况下,我们将只使用态度数据进行细分。在现实中,决策者选择不同类型的输入变量(人口统计、地理、行为等。)基于它们的个别情况进行分段。尽管如此,无论您选择哪种输入,想法都是一样的!
(注:Thomas W. Miller 在他的书营销数据科学:用 R 和 Python 进行预测分析的建模技术中提出了一个关于使用销售交易数据作为细分输入的很好的观点。简而言之,他警告不要用销售交易数据进行细分,因为销售信息只对当前客户可用。当你有一个新客户时,如果没有他/她的销售数据,你很难利用你获得的洞察力。)
在我们深入研究方法和模型之前,请记住,作为一名负责任的数据分析师,首先要了解您的数据!
检查数据
# Importing and checking Dataraw <- read.csv(“Chargers.csv”)
str(raw)
head(raw)

Data Structure

A snippet of the data
我们数据中的每一行代表一个回答者,每一列代表他/她对相应调查问题的回答。共有 2500 名受访者和 24 个态度问题。所有这些都是评级问题,询问受访者对某一陈述的看法。答案在 1-5 的范围内。这里有一个例子:
请指出您对以下陈述的同意或不同意程度(1 =完全不同意,5 =完全同意)。
在购买便携式手机充电器时,我最看重款式。
…
理解了问题的本质,我们接下来可以验证数据集中的数据。编写一个简单的函数有时会有用:
# Verifying Data describe(raw)
colSums(is.na(raw)) #Checking NAs
table(unlist(raw[,]) %in% 1:5) #Simple Test
R 中的 validate 包也是一个方便的数据验证工具。它允许您根据自己创建的一组规则来测试数据。然而,我发现在处理大型数据集时,它并不是最方便的。我仍在寻找有效验证数据质量的替代方法(最好是系统)。我将非常感谢任何建议。
现在我们已经验证了我们的数据,我们对它们有信心,让我们继续更有趣的东西!
主成分分析
“维度缩减”这个术语曾经让我感到恐惧。然而,它并不像听起来那么复杂:它只是从无数数据中提取本质的过程,因此新的、更小的数据集可以表示原始数据的独特特征,而不会丢失太多有用的信息。可以把它想象成毕加索的立体主义绘画,他用几条线和几个形状优雅地抓住了一个物体的本质,忽略了许多细节。对我来说,我总是喜欢想起他的吉他。如果你有其他的作品,请评论!!

Guitar 1914 by Pablo Picasso
PCA 是一种降维形式。StatQuest 的这个视频(大声说出我最喜欢的统计/数据科学视频频道)非常直观地解释了这个概念。如果这是你第一次听说 PCA,我强烈建议你观看这个视频。简而言之,PCA 允许您获取具有大量维度的数据集,并将其压缩为具有较少维度的数据集,这仍然可以捕获原始数据中的大多数差异。
你会问,为什么 PCA 有助于将客户分成不同的群体?假设您需要根据客户对这些调查问题的回答来区分他们。您遇到的第一个问题是如何根据它们对 24 个变量的输入来区分它们。当然,你可以试着想出几个主要的主题来总结这些问题,并为每个主题给每个回答者分配一个“分数”,然后根据分数将他们分组。但是你怎么能确定你提出的主题在划分人方面是真正有效的呢?你如何决定每个问题的权重?再者,如果你有 5000 个变量而不是 24 个,你会怎么做?人脑根本无法在短时间内处理这么多信息。至少我的大脑肯定不能。

Photo by ME.ME on Facebook
这就是 PCA 可以介入并为您完成任务的地方。对我们的数据执行 PCA,R 可以将相关的 24 个变量转换成更少的不相关变量,称为主成分。有了更小的压缩变量集,我们可以轻松地执行进一步的计算,并且可以研究数据中一些最初难以发现的隐藏模式。
当有大量的文献/视频/文章提供了关于五氯苯甲醚的详尽解释时,我希望为那些认为这些材料过于专业的人提供一些关于五氯苯甲醚的高层次观点:
- 可变性使数据变得有用。想象一个有 10,000 个统一值的数据集。它没有告诉你太多,而且很无聊。😑
- 同样,主成分分析的功能是创建一个更小的变量子集(主成分),以捕捉原始的、大得多的数据集中的可变性。
- 每个主成分是初始变量的线性组合。
- 每个主成分彼此具有正交关系。这意味着它们不相关。
- 第一个主成分(PC1)捕获数据中最大的可变性。第二主成分(PC2)抓住了第二多的。第三主成分(PC3)抓住了第三最……等等****
此外,如果您计划为您的项目运行 PCA,您应该知道以下几个术语:
- ****加载描述了原变量和新主成分之间的关系。具体来说,它描述了在计算新的主成分时赋予原始变量的权重。
- ****分数描述了原始数据和新生成的轴之间的关系。换句话说,score 是主成分空间中数据行的新值。
- ****方差比例表示每个主成分占总数据可变性的份额。它通常与累积比例一起使用,以评估主成分的有用性。
- ****累计比例代表累计由连续主成分解释的方差比例。所有主成分解释的累积比例等于 1(解释了 100%的数据可变性)。
在 R 中运行 PCA
在运行 PCA 之前,您应该查看一下您的数据相关性。如果您的数据不是高度相关的,您可能根本不需要 PCA!
# Creating a correlation plot library(ggpcorrplot)
cormat <- round(cor(raw), 2)
ggcorrplot(cormat, hc.order = TRUE, type = “lower”, outline.color = “white”)

Correlation Plot
如图所示,我们的变量非常相关。我们可以愉快地前往✌.的 PCA️
# PCA
pr_out <-prcomp(raw, center = TRUE, scale = TRUE) #Scaling data before PCA is usually advisable!
summary(pr_out)

PCA Summary
有 24 个新的主成分,因为我们首先有 24 个变量。第一个主成分占数据方差的 28%。第二主成分占 8.8%。第三种占 7.6%…我们可以用一个 scree 图来形象化这一点:
# Screeplot
pr_var <- pr_out$sdev ^ 2
pve <- pr_var / sum(pr_var)
plot(pve, xlab = "Principal Component", ylab = "Proportion of Variance Explained", ylim = c(0,1), type = 'b')

Scree plot
x 轴描述主成分的数量,y 轴描述每个主成分解释的方差(PVE)的比例。解释的方差在 PC2 后急剧下降。这个点通常被称为拐点,表示应该用于分析的 PC 数量。
# Cumulative PVE plot
plot(cumsum(pve), xlab = "Principal Component", ylab = "Cumulative Proportion of Variance Explained", ylim =c(0,1), type = 'b')

Cumulative Proportion of Variance
如果我们只选择 2 个主成分,它们将产生不到 40%的数据总方差。这个数字也许不够。
选择 PC 数量的另一个规则是选择特征值大于 1 的 PC。这被称为凯泽规则,这是有争议的。你可以在网上找到很多关于这个话题的辩论。
基本上,没有单一的最佳方法来决定电脑的最佳数量。人们出于不同的目的使用 PCA,在做出决定之前,考虑您想从 PCA 分析中获得什么总是很重要的。在我们的案例中,由于我们使用 PCA 来确定有意义且可行的市场细分,我们应该明确考虑的一个标准是我们决定的电脑在现实世界和商业环境中是否有意义。
解释结果
现在让我们挑选前 5 台电脑,因为 5 个组件并不太难处理,而且它遵循凯泽法则。
接下来,我们想让这些电脑有意义。还记得在计算新的主成分时,负荷描述了每个原始变量的权重吗?它们是帮助我们解释 PCA 结果的关键。当直接处理主成分分析负荷可能会很棘手和混乱时,我们可以轮换这些负荷以使解释更容易。
有多种旋转方法,我们将使用一种称为“varimax”的方法。(注意,这一步旋转不是 PCA 的一部分。它只是有助于解释我们的结果。这里的是一个很好的话题。)
# Rotate loadings
rot_loading <- varimax(pr_out$rotation[, 1:5])
rot_loading

Varimax-rotated loadings up to Q12
这是截至 Q12 的 varimax 旋转负载的不完整部分。表中的数字对应于我们的问题(原始变量)和所选组件之间的关系。如果数字为正,则变量对分量的贡献为正。如果是负的,那么它们是负相关的。数字越大,关系越密切。
有了这些数据,我们可以参考我们的调查问卷,了解每台电脑的功能。例如,我们来看看 PC1。我注意到 Q10、Q3 和 Q7 对 PC1 有负面影响。另一方面,我发现 Q8 和 Q11 对 PC1 有积极的贡献。查看问卷,我意识到 Q10、Q3 和 Q7 是与充电器的风格相关的问题,而 Q8 & Q11 关注的是产品的功能。因此,我们可以暂时得出结论,PC1 描述了人们对产品功能的偏好。更看重功能的人可能不太在乎风格,这是有道理的。
然后,您可以转到 PC2,按照相同的步骤解释每台 PC。我不会在这里介绍完整的过程,我希望你已经明白了。一旦你检查了所有的个人电脑,感觉每一台都描述了独特的、逻辑上连贯的特征,并且你相信它们具有商业意义,你就可以进行下一步了。但是,如果您觉得 PCs 中缺少或重复了一些信息,您可以考虑返回并包含更多的 PCs,或者您可以删除一些。您可能需要经历几次迭代,直到获得满意的结果。
我们完了!!
开玩笑的。但是你已经成功了一半。您已经完成了将大型数据集压缩为较小数据集的过程,其中包含一些变量,可以帮助您使用 PCA 识别不同的客户群。在下一篇文章中,我将介绍如何使用聚类方法,根据我们获得的 PC 对我们的客户进行细分。
最后,祝所有了不起的女超人#国际快乐👯👧 💁 👭!
感谢阅读!💚随时和我联系Linkedin!**
Zalando 的营销 A/B 测试

Zalando Office Tamara-Danz-Straße, Berlin-Friedrichshain
深入分析
使用聚类分析启用基于位置的 A/B 测试
供稿人:卡斯滕·拉希、托马斯·佩尔、马丁·卡斯滕、让·德·布雷西
Zalando 营销 A/B 测试分析的目标是得出营销行动的增量影响。这些分析的结果形成了在所有营销渠道中优化预算分配的基础,从而形成了高效的营销投资回报导向。这是我们在 Zalando 的需求计划&分析的 A/B 测试团队的任务。
我们的主要测试方法之一是地理实验,在这种实验中,我们将一个市场分成高度相关的区域组。测试组和控制组之间高度相关的销售行为是 geo A/B 实验的前提条件,因为测试和控制区域之间的低相关性会导致预测中的噪声,从而降低识别影响(如果有影响的话)的概率。芬兰是唯一一个营销渠道不以投资回报为导向的市场,因为基于地理位置的 A/B 测试在该国并不简单。这是因为大多数芬兰人生活在南部,仅乌西马地区就有约 30%的人口[1]。因此,订单总额的地区差异很大。芬兰北部地区的每日订单数量很少,因此在根据给定的地区总量(如联邦州、市)比较时间序列时,几乎不可能找到高度相关的组。
因此,我们需要为芬兰找到不同的位置定义。克服这个问题的一个解决方案是,与现有的区域定义相比,将国家分成更小的集群。以这种方式,可以增加区域分裂组合,因此也增加了发现“区域双生子”的可能性。这可以通过使用谷歌营销领域(GMA 的)来实现。但是,GMA 定义不适用于芬兰。
出于这个原因,我们创建了城市集群定义,以使芬兰可测试。这是通过 K-均值聚类分析方法实现的。
在城市位置数据中查找聚类
K-Means 聚类算法是在数据集中发现 K 个不同类别的相似对象的常用方法[2]。在这种情况下,聚类方法依赖于公开可用的城市位置数据[3],包括带有芬兰 317 个城市的纬度和经度信息的 GPS 坐标[图 1]。

Figure 1: GPS data of 317 Finnish locations, shown in a Cartesian coordinate system (left) and in a cylindrical projection map [4] (right).
为了显示芬兰城市的区域分布,笛卡尔坐标被转换为柱坐标,并通过地理点绘图仪绘制在芬兰地图上[4]。所使用的数据集仅限于由广告投放系统控制的城市列表,如谷歌和脸书。如果输入数据还包括不可操纵的城市,则可能存在由于不干净的 A/B 测试分割而导致聚类结果不可用的风险,并且聚类内的观测值数量可能不足。
除了原始数据之外,算法[图 2]需要聚类数 K 作为输入。原因是,聚类是一种无监督学习方法【5】,意味着算法“从未标记的数据中发现[s]隐藏的结构”[6],并且不会自动导出最佳 K 参数[7]。

Figure 2: K-Means Clustering Algorithm.
定义 K 参数后,K 均值聚类算法分 3 步进行[8]:
- 在随机位置初始化 K 个聚类中心(质心);
- 基于数据点和质心之间的最小欧几里德距离对数据进行分组;
- 通过平均分配给相应聚类的所有数据点来重新计算聚类中心。
最后两步迭代重复,直到算法收敛到稳定的聚类分配。当簇内方差不能再降低时,达到收敛标准[7],使得簇尽可能紧凑[9]。
更正式地说,给定 k 个簇的数据点{x1,…,xn}和质心{c1,…,ck},这意味着“最小化[…]平方误差函数”[7]:

换句话说,等式 1.1 的目标是最小化所有组中聚类内距离平方和的总和。收敛的阈值是 1e-4 [10]。该表达式

上式中是欧氏距离函数,也可以写成[11]:

欧几里德距离是距离测量的常用度量,定义为“两个向量[11] x 和 c 的对应元素之间的平方差之和的平方根”。该度量用于根据数据点之间的最小距离将数据点分配到最近的质心[12]。
值得一提的是,该算法在任何情况下都收敛于局部最小值,而不一定是全局最小值[12]。这意味着不能保证当前结果是可能的最佳输出,因为初始质心的随机选择会导致每次运行的不同聚类结果。为了找到一个可能更好的结果,算法执行应该重复几次,如图 3 所示。

Figure 3: Clustering score for a fixed K (K=7) after 1000 iterations.
图 3 表明,平方距离之和(SSE)在 1000 次迭代步骤中并不完全稳定,这意味着由于随机起始参数,每次运行都可能产生略微不同的 SSE。
选择最佳聚类数
K 参数的值决定了聚类的数量,从而也决定了数据点向聚类的分配。在我们的例子中,“肘方法”被用作估计最佳聚类数 k 的常用技术。第二步,我们通过比较聚类之间的阶数来验证肘方法的结果。平衡聚类的订单量非常重要,因为太小的聚类产生的噪声数据会降低在 geo A/B 测试中获得显著结果的可能性。“弯管法”包括以下步骤[13]:
- 针对不同的 K 值对数据集执行 K 均值算法,在这种情况下,K 的范围在 1 和 20 之间;
- 计算每个 K 的城市和质心之间的 SSE
- 在折线图中绘制结果。
SSE 随着 K 参数的增加而减小。所选择的 K 参数应该在它的值和 SSE 仍然很小的点。有一个 K,上证指数的下跌速度急剧变化,曲线开始变平。这是最佳的 K 参数,称为“肘点”。

Figure 4: Clustering score for a range of different K parameters.
图 4 显示,在这种情况下,拐点并不明显,但可以考虑 K 参数的范围,因为在曲线开始变平之前,从 1 到大约 8 的 K 值越小,SSE 下降的速率越高。为此,对不同 K 参数的这个值范围执行 K 均值算法。这样,通过比较相应的聚类结果并选择 K 值,可以找到最佳 K 参数,该 K 值产生总订单量的聚类内方差尽可能低的聚类分配。组内方差越低,高度相关组的概率越高,从而在 geo A/B 测试中检测到潜在影响的概率越高。
由于至少需要两个集群作为控制或测试组,K 参数 1 可以忽略。介于 2 和 6 之间的 k 值导致城市分组不理想,这反映在聚类之间的订单量差异很大。群集有序级别的高变化意味着该国被划分为人口密集的地区和农村地区。由于地区之间销售行为的差异较大,这可能导致较低的聚类内相关性,从而导致检测潜在影响的可能性较小。对于大于 6 的 K 值,最大的城市坦佩雷和赫尔辛基被单独分组,并且每个聚类的订单数更加均衡,这增加了高度相关的聚类的机会。
K 参数 K=7 被证明是所用数据集的最佳值,因为 K=8 的 K 参数不会导致聚类输出的进一步改善。原因是,这只是导致芬兰北部进一步分裂成一个额外的集群,这意味着该国人口较少的部分被分成更小的集群。结果是订单量的群内方差再次增加。
K 参数的验证
由于初始质心是随机定位的,该算法每次运行都会产生不同的结果[14]。几次迭代之间的平方距离之和的偏差大小可以指示聚类算法的稳定性。为了弄清楚这一点,该算法已经执行了 1000 次,并且对每次运行都绘制了平方距离的总和(见图 3)。图 3 中绘制的线表明,虽然每次运行的算法输出不相同,但是 1000 次迭代之间的平方距离之和的变化很小。这意味着聚类结果仅略有不同,并且对于 K=7,聚类分数相当稳定。
为了分析几次运行的聚类结果之间的聚类分配的可变性,通过对 K=7 的固定 K 值重复该算法,产生了 6 个聚类输出(图 5)。

Figure 5: Clustering results of 6 runs of the K-Means algorithm for K=7 with the 7 city clusters and their centroids (marked as stars).
比较的角度是在 6 次算法运行中质心位置的可变性,以找出哪些聚类变化导致了聚类分数的小波动。聚类输出的比较表明,质心的位置在 6 次运行中保持相当稳定。这意味着聚类分配仅针对几个单独的城市而改变,最大比例的数据点在迭代中保持在同一个聚类中。
只有主要包括拉普兰地区的最北部集群显示出质心位置的可见变化。这是因为该区域的观测数量较少,导致它们之间的距离较大。因此,1000 次迭代之间的平方距离之和的变化(如上所述)可能主要是由位于北部的城市的相对不稳定的组分配引起的。如下所示,由于这些城市的聚类将与其相邻的聚类进行分组,因此可以忽略聚类分配的变化。
聚类结果:可测试的地理分割
K-Means 分类产生了七个城市集群及其中心(图 6 左侧)。为了确保每个聚类中的日订单量处于可测试的水平,五个较小的聚类被分组以形成一个较大的区域(图 6 右侧)。

Figure 6: Result of the K-Means Cluster Analysis, showing the output with 7 clusters (left) and the final grouping into 3 geo testing regions (right).
每日订单数量越少,数据中出现噪音的风险就越高。噪声数据的后果是聚类之间的相关性较低,因此检测潜在影响的概率较低。
结果,我们得到了三个地理分割区域:“赫尔辛基”(区域 1)、“坦佩雷”(区域 2)和“芬兰北部”(区域 3)。这种区域分割证明是一种可测试的设置,因为在 2018 年 10 月至 2019 年 1 月中旬的时间段内,区域时间序列之间的相关性达到约 98%的值(就总订单而言)。此外,在计算 2018 年全年的相关性时,这些值大致保持在相同的范围内(96%-98%)。
由于赫尔辛基是订单总量最大的地区,因此被分配到试验组,坦佩雷和芬兰北部被分配到对照组。测试区域应该具有最高的总订单份额,因为这是被测试通道被打开的组。这确保了测试活动在全国大部分地区运行,从而尽可能减少 geo A/B 测试的总印象数。这对于保证测试后的最佳活动范围非常重要,因为测试总是要求将一些地区从活动目标中排除。
为了验证这种分割,对这些区域进行了可能影响的测试。赫尔辛基(试验组)与两个地区坦佩雷和芬兰北部(对照组)之间的相对效应差异通过抬升分析进行测试。分析得出 0.2%的不显著效应(52%显著性),两组之间的相关性为 99.5%。该结果证实了高度相关的总顺序行为,并且在测试之前,组之间没有显著差异,因为测量的效果接近于零,并且明显低于 90%的显著性水平。
聚类结果用于实施芬兰的首个地理分割设置。本次地理测试的目的是测量 2019 年 Zalando 赛季开始活动期间展示计划的增量性能。赫尔辛基区域被定义为测试组,在该测试组中,被测通道被打开并运行 4 周。另外两个区域坦佩雷和芬兰北部被设置为控制区域,这意味着在相应的城市中没有打开显示编程。测试停止后,可以计算对总订单的增量影响,这是测试组中观察到的数据和模型预测之间的累积每日差异。
这是 Zalando 芬兰投资回报指导的开始,因为该国的营销预算分配可能首次基于 A/B 测试结果。
局限性和后续步骤
在 2019 年 Zalando 赛季开始活动期间,对显示程序性地理分割测试的分析产生了重要而可信的结果。这意味着所示方法已被证明是在芬兰为 geo A/B 测试创建测试和控制区域的有用方法。尽管使用的测试设置产生了高度相关的组,但是仍然有优化集群的空间。考虑到当前的划分只包含 3 个组,并且尽管进行了测试,但仍应确保最佳的活动范围,因此重新分组的选项非常有限。这增加了发生系统性错误的风险,因为赫尔辛基地区可能会由于大都市和农村地区的人之间潜在的不同行为而导致大都市效应。重新聚类和使用具有更多可测试组的更可变的聚类有助于克服这个问题。为此,人口最稠密的地区赫尔辛基和坦佩雷可以进一步划分成更小的集群。更多数量的区域增加了区域分割组合,从而增加了 geo A/B 测试能力。
参考
[1]欧盟委员会, 赫尔辛基-Uusimaa 地区(2019 年 2 月 15 日),区域创新监测 Plus。
[2] M. Khan, KMeans 聚类分类(2017 年 8 月 2 日),走向数据科学。
[3] 芬兰城市&城镇人口(2004–2019),Tageo -地理坐标信息。**
[4] D .沃特金斯,地理点绘图仪。一个快速绘制出地理坐标列表的工具 (n. d.) 。
[5] P. Sayak,K-用 scikit 表示 Python 中的聚类-learn(2018 年 7 月 5 日),DataCamp 教程。
[6] G .塞尔丁, 新课程:Python 中的无监督学习(2017 年 2 月 22 日),DataCamp 教程。**
[7] S. Sayad,《数据科学导论》。K-均值聚类(2010–2019)。**
[8] F. Doukkali, 利用 K-means 算法进行聚类 (12/19/2017),走向数据科学。
[9] B. Boehmke, UC 商业分析 R 编程指南。 K-means 聚类分析 (n. d .),辛辛那提大学,大学讲座。
[10]sci kit-学习开发者。sk learn . cluster . k means(2007–2018)。**
[11] S. Borgatti, 距离与相关性(2007 年春季),多元统计,波士顿学院,大学讲座。
[12] A .特雷维尼奥,学习数据科学,机器学习。K-means 聚类简介(2016 年 12 月 6 日)。**
[13] R. Gove, 利用肘方法确定 k-means 聚类的最优聚类数(2017 年 12 月 26 日),Robert Gove's Blocks。**
[14] M. V. B. T. Santhi,V. R. N. Sai Leela,P. U. Anitha,& D. Nagamalleswari,增强 K 均值聚类算法 (2011)。国际计算机科学杂志&技术,IJCST , 2 (4),73–77。**
营销分析——任何人都可以做到

Marketing Analytics
就在几年前,与营销分析相关的工作还很少。那么现在,这个行业正在蓬勃发展,就业机会正在上升。原因可能是数据科学被广泛采用后,与市场营销自然结合。而且因为直接关系到一个公司的销售业绩,所以越来越受到重视。
我经常收到这些问题。营销分析是做什么的?我该怎么做?营销分析的职业道路是什么?本文就是要解决这些问题。
- 营销分析通过分析营销数据优化公司投资回报率。
- 任何拥有数据分析技能、营销和产品意识的人都可以从事营销分析工作。
- 营销分析部门的工作范围很广,有能力领导一家公司的营销分析职能。
这份工作主要服务于公司的营销部门。就是通过分析各类营销数据来优化回报率,以指导公司的资源配置。营销分析在我看来可以分为两个分支:客户生命周期分析和营销渠道分析(见下图)。

Image Copyright: Dr. Alan Zhang
营销的本质是面对和服务消费者。每个消费者都有他或她的生命周期。因此,营销分析的一个重要分支是客户生命周期分析。就是围绕消费者进行数据分析,产生洞察来指导营销活动。具体来说,它包括市场细分、消费者终身价值分析、获取新客户、维护老客户和提高客户参与度等分析。其中,企业对企业的营销(B2B 营销),由于其购买过程的独特性,会有一些特定的分析,如需求漏斗分析,线索评分,等等。
营销分析的另一个重要分支是营销渠道分析。营销信息的传播依赖于渠道或媒介,如何高效地让消费者接收信息非常重要。信息的制作和渠道的部署需要资金和人力。因此,每个公司的当务之急是分配资源,使投资回报最大化。要做到这一点,需要一系列研究和分析的支持。
信息从渠道传播出去后,我们需要通过技术进行跟踪,衡量每一条信息/渠道的效果。一般来说,消费者在购买之前会通过多种渠道收到多种营销信息。我们需要准确地归因,以帮助公司获得正确的反馈。在这上面,我们会用一些统计模型比如营销组合建模,从各种因素中剔除无关信息,得到相应的影响参数。这些参数最终将用于优化资源分配的决策。
因为每个渠道/媒体都有其独特性,企业往往需要通过数据分析来优化渠道。例如,在电子邮件营销中,何时发送给哪些消费者会影响打开率和点击率。随着消费者在网上花费越来越多的时间,数字营销分析已经成为许多公司的首要任务,涉及搜索引擎优化、社交媒体优化等分析。程序化广告也是一个方向,目标是优化曝光,最大化转化率。
相关技能有哪些?
在最高级别,它是使用分析方法在复杂多样的数据中发现模式的能力,并生成可供营销人员决策使用的商业见解。我具体阐述如下(见下图)。

Image Copyright: Dr. Alan Zhang
第一,你要有分析常见营销问题的能力。与咨询行业的案例研究一样,它遵循一个特定的框架。例如,电子邮件营销团队需要您帮助开展一项活动。首先,你可能想确定事件的性质,是品牌曝光、促销还是事件。第二,你可以决定哪些指标需要优化,是打开率,点击率,购买率,还是用户参与度。再者,你可以确定目标群体是谁,是潜在客户还是长期不购买的老客户。还有,活动举办后,你需要确定用什么方法来分析活动的效果和影响范围。一些传统的分析方法是细分、群组分析、客户终身价值等。
第二,你应该具备基本的统计学知识,以及建立统计学或机器学习模型来解释和预测行为的能力。扎实的统计知识确保产生的业务洞察具有统计意义,例如 A/B 测试。各种类型的机器学习模型可以帮助你从数据中快速提取模式,预测未来的行为。仅仅知道如何使用一个包或者编写算法是不够的。更重要的是能够提出正确的业务问题,并使用这些工具来解决它们。此外,一些具体的营销分析方法,如营销组合模型和流失模型,也是很好的了解。
再者,你也要有技术能力。它包括使用 SQL 从数据库中提取有用的信息,以及使用 R 或 Python 处理数据和建立预测模型。知道数据可视化工具也是很可爱的,比如 Tableau,Looker,PowerBI 等。,并将分析结果呈现给职能合作伙伴。知道如何使用第三方管理工具更好,例如用于网站流量跟踪的 Google Analytics、用于 CRM 的 Salesforce 等等。
最后但同样重要的是,最关键的能力是向你的听众简明扼要地传达复杂的技术问题,以影响决策。如图 1 所示,营销分析服务于营销职能,但也需要与其他部门合作,如销售、产品、工程等。因此,你能否让招聘经理相信你能有效沟通,将是需要评估的软技能。
如何获得这些技能?
熟能生巧!你可以在网上找资源学习基础知识,比如网络课程、博客、书籍等。,并做一些相关的项目。如果你能找到在该领域更有经验的同行作为导师,学习将更有效率,并有助于避免一路上走弯路。
作者简介:Alan Zhang 博士以前是一名市场营销教授,他的研究兴趣是电子邮件营销、客户生命周期管理和客户终身价值。《哈佛商业评论》报道了他对客户温贝克的研究。他现在是 GitHub 的营销分析经理。
在业余时间,他教授营销分析的各种主题。他在 Udemy 上有一门关于客户终身价值的入门课程。补充这篇文章的是 PASS(数据专业人士社区)邀请他做的一次演讲,主题是营销分析:为什么、做什么和如何做。
营销分析:客户 EDA 回归

最近,我一直在做一些数据科学营销咨询,并希望分享一些在此过程中应用的技能。在本文中,我们将回顾探索性数据分析(EDA ),以及应用逻辑回归对客户进行的营销活动。
在营销活动中,客户参与度是衡量营销努力的一个关键指标。例如,电子邮件客户参与度可以通过打开或未打开的电子邮件数量来衡量[1]。有利可图的营销活动将创造大量的参与度。另一方面,糟糕的营销会让顾客远离你的生意。我们都经历过——收到烦人的广告。有时,当我确实需要他们的服务时,我会从他们的直接竞争对手那里购买。
EDA 帮助我们理解为什么要使用数据。借助 EDA,您可以分析对结果至关重要的驱动因素。回归是一种工具,可以用来检查驱动因素和预期结果之间的关系。我们将回顾逻辑回归模型来分析是什么创造了更好的客户参与度。有趣的数据科学访谈事实上,逻辑回归是为寻找二元结果而创建的(例如,是/否、癌症/没有癌症、已购买/未购买等)。) [2].
加载数据
#Load up packages and data
import matplotlib.pyplot as plt
import pandas as pd
import statsmodels.api as smmdata = pd.read_csv('WA_Fn-UseC_-Marketing-Customer-Value-Analysis.csv')
#How big the data set is:
mdata.shape
(9134, 24)
#Taking a look at the values
mdata.head()

客户参与的期望输出是 Response 列,它不会被转换为数字。逻辑回归模型喜欢用数字来表示值,所以我们必须帮助它。
#Converting our target/output variable into a numerical
mdata['Engaged'] = mdata['Response'].apply(lambda x: 0 if x == 'No' else 1)
检查参与率
接下来,我们将检查参与率,即接触过我们营销的客户的百分比。
engagement_rate_mdata = pd.DataFrame(mdata.groupby('Engaged').count()['Response'] / mdata.shape[0] * 100.0)
engagement_rate_mdata

有更多的客户没有参与我们的营销,所以从原始数据进行分析是很困难的。为了使分析更容易,我们将构建饼图。
engagement_by_sales_channel_mdata.plot(kind='pie',figsize=(15, 7),startangle=90,
subplots=True,autopct=lambda x: '%0.1f%%' % x)plt.show()

从这些图表中可以看出,约一半的参与客户来自代理商,而未参与客户分布在不同的渠道。
索赔总额
在我们开始回归分析之前,我们先来看看箱线图中的总索赔额。
ax = mdata[['Engaged', 'Total Claim Amount']].boxplot(
by='Engaged',showfliers=False,figsize=(7,5))ax.set_xlabel('Engaged')
ax.set_ylabel('Total Claim Amount')
ax.set_title('Total Claim Amount Distributions by Engagements')plt.suptitle("")
plt.show()

箱线图是查看连续变量分布的好方法。矩形代表第一个四分位数到第三个四分位数,绿线代表中位数。末端是最小值和最大值。showfliers=False 允许我们发现可疑的异常值,如下所示:
ax = mdata[['Engaged', 'Total Claim Amount']].boxplot(
by='Engaged',showfliers=True,figsize=(7,5))ax.set_xlabel('Engaged')
ax.set_ylabel('Total Claim Amount')
ax.set_title('Total Claim Amount Distributions by Engagements')plt.suptitle("")
plt.show()

圆点是基于四分位距(IQR)的可疑异常值。可疑异常值的公式是第三个四分位数以上 1.5 IQR 或第一个四分位数以下 1.5 IQR。
回归分析
在回归中,特征变量需要是连续的,因此可以找到特征的线性组合来估计输出变量。现在,让我们检查一下特征变量,它们符合我们的逻辑回归模型。
mdata.dtypes

连续变量是没有“对象”数据类型的变量。
continuous_vars = ['Customer Lifetime Value', 'Income', 'Monthly Premium Auto',
'Months Since Last Claim', 'Months Since Policy Inception',
'Number of Open Complaints', 'Number of Policies', 'Total Claim Amount']
接下来,我们需要将分类变量转换成数字变量。一种方法是因式分解。
gender_values, gender_labels = mdata['Gender'].factorize()
print(gender_values)
print(gender_labels)

在因式分解中,变量变成了 1 或 0。但是如果顺序很重要呢?我们可以应用分类函数。
categories = pd.Categorical(
mdata['Education'], categories=['High School or Below', 'Bachelor', 'College', 'Master', 'Doctor'])
现在,数字 0、1、2、3 和 4 分别适用于高中或以下、学士、大学、硕士和博士的教育。这将允许我们将数据放入逻辑模型中。
mdata['GenderFactorized'] = gender_values
mdata['EducationFactorized'] = categories.codes
让我们把分类变量和连续变量结合起来!
logit = sm.Logit(
mdata['Engaged'],
mdata[['Customer Lifetime Value','Income','Monthly Premium Auto',
'Months Since Last Claim','Months Since Policy Inception','Number of Open Complaints',
'Number of Policies','Total Claim Amount','GenderFactorized','EducationFactorized']])logit_fit = logit.fit()logit_fit.summary()
z(z-score 的缩写)是平均值的标准偏差数[3]。P>|z|(表示 P 值)表示偶然观察到关系的可能性。通常,0.05 是 p 值的标准临界值,小于 0.05 的值意味着输入和输出变量之间的这种关系发生巧合的可能性较小。例如,在数字变量中,我们可以看到收入、每月保费汽车、自上次索赔以来的月数、自保单开始以来的月数以及保单数量变量与参与度(输出变量)有显著关系。如果我们观察自上次索赔以来的月份变量,它是显著的(p 值非常低),并且与敬业度负相关(z 值为负)。换句话说,随着索赔时间的推移,客户不太可能参与营销。
从分类变量中,我们可以看到男性(0)不太可能从事营销,这同样适用于较低的教育水平(0 代表高中,4 代表博士)。
结论
很好,现在你有了另一个 EDA 工具——逻辑回归。作为总结,我们以表格形式检查了接洽率,以饼图形式检查了销售渠道以便于解释,以箱线图形式检查了总索赔额以查看范围和潜在异常值,并通过回归分析发现了强劲的趋势。现在,您可以利用逻辑回归来隔离趋势,然后将其输入到另一个机器学习模型中,而不是在输出中使用逻辑回归作为预测模型!
边注:如何堆叠机器学习模型的例子可以看这里: https://towardsdatascience . com/machine-learning-pipelines-nonlinear-model-stacking-668 f2b 720344
免责声明:本文陈述的所有内容都是我个人的观点,不代表任何雇主。
参考
[1] Marketo,参与营销(2019),https://www.marketo.com/engagement-marketing/
[2] S. Swaminathan,logistic Regression(2018),https://towards data science . com/logistic-Regression-detailed-overview-46 C4 da 4303 BC
[3] Y. Hwang,《营销数据科学实践》( 2019 年),派克特出版社
营销分析:客户参与,随机森林风格

我们将讨论如何建立一个关于客户营销参与的随机森林预测模型。通过更好地预测客户将如何参与某些营销活动,营销人员可以为不同的受众量身定制策略[1]。我们在这里寻找的官方营销术语是“参与的可能性”一个具体的例子是区分哪种类型的客户会对哪种类型的广告做出反应(例如,20-39 岁的女性对脸书广告和谷歌广告的反应——完全是编造的)。
数据设置
今天的数据由 ka ggle[2]:
https://www . ka ggle . com/pankajjsh 06/IBM-Watson-marketing-customer-value-data/downloads/IBM-Watson-marketing-customer-value-data . zip/1慷慨提供
是时候导入所有的包了。
import matplotlib.pyplot as plt
import pandas as pd
%matplotlib inline
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score
from sklearn.metrics import roc_curve, auc
接下来,带来数据。
#load data
df = pd.read_csv('WA_Fn-UseC_-Marketing-Customer-Value-Analysis.csv')
custd.head()

作为模型输出的“响应”变量不是一个数字。这将被调整成一个数字,否则 Python 会发疯的。
#Encoding output variable
custd['Engaged'] = custd['Response'].apply(lambda x: 1 if x == 'Yes' else 0)
应用功能将“是”的回答转换为“1 ”,将其他所有回答转换为“0”。“是”表示客户参与了,而“否”表示没有参与。所以平均参与率是
custd['Engaged'].mean()
0.1432,意味着我们的平均参与率大约为 14%。现在,你知道为什么他们说销售是一个数字游戏。只有少数人说是。
特征工程
让我们来看看我们的客户参与模型的特性。
#Checking out features
custd.describe()

酷,我们用 describe 隔离了所有的数值或连续列。
continuous_features = ['Customer Lifetime Value', 'Income', 'Monthly Premium Auto',
'Months Since Last Claim', 'Months Since Policy Inception',
'Number of Open Complaints', 'Number of Policies', 'Total Claim Amount']
现在,来处理所有的分类栏目。
columns_to_encode = ['Sales Channel', 'Vehicle Size', 'Vehicle Class', 'Policy', 'Policy Type',
'EmploymentStatus', 'Marital Status', 'Education', 'Coverage']categorical_features = []
for col in columns_to_encode:
encoded_df = pd.get_dummies(custd[col])
encoded_df.columns = [col.replace(' ', '.') + '.' + x for x in encoded_df.columns]
categorical_features += list(encoded_df.columns)
custd = pd.concat([custd, encoded_df], axis=1)
custd['Is.Female'] = custd['Gender'].apply(lambda x: 1 if x == 'F' else 0)categorical_features.append('Is.Female')
在将所有需要的变量编码成数字后,我们需要将所有内容组合回一个数据框架中。
all_features = continuous_features + categorical_features
response = 'Engaged'
sample_custd = custd[all_features + [response]]
sample_custd.columns = [x.replace(' ', '.') for x in sample_custd.columns]
all_features = [x.replace(' ', '.') for x in all_features]
sample_custd.head()

在一些特征工程之后总是检查你的数据以确保你没有错过任何东西,这不是一个坏主意。在我们的例子中,看起来我们成功地将所有东西都转换成了数字。现在来看模型!
构建随机森林
我们需要做的第一件事是在训练集和测试集之间分割数据,以便稍后进行评估。
# model phase - train/test
x_train, x_test, y_train, y_test = train_test_split(sample_custd[all_features], sample_custd[response], test_size=0.3)
现在我们可以训练和拟合随机森林模型。请随意调整模型设置,以获得更好的解决方案。
#Building random forest model
rf_model = RandomForestClassifier(n_estimators=200,max_depth=5)#Features
X = x_train
#Output
y = y_train#Fit model to training data
rf_model.fit(X, y)

另外,在随机森林中,你可以看到一棵树是如何投票的。
#looking at individual trees
rf_model.estimators_
#individual tree setting
rf_model.estimators_[0]
#individual tree prediction
rf_model.estimators_[0].predict(x_test)[:10]

上面的数组是 0 号树对前 10 个样本的投票结果。很酷,对吧?回到 random forest,我们来看看模型是怎么想的,哪些功能对客户参与度最重要。
#Examining what RF thinks are important features
rf_model.feature_importances_
feature_importance_df = pd.DataFrame(list(zip(rf_model.feature_importances_, all_features)))
feature_importance_df.columns = ['feature.importance', 'feature']featsorted = feature_importance_df.sort_values(by='feature.importance', ascending=False)
featsorted

好吧,那是一张长桌子。让我们以图形的形式让它更容易阅读——十大最重要的特性。
featsortedtop10 = featsorted.head(10)featsortedtop10.plot(kind='bar', x='feature')

根据 random forest 模型,退休员工最倾向于参与我们的营销工作。这并不奇怪,因为我们的数据集是关于一家保险公司的营销。
模型评估
in_sample = rf_model.predict(x_train)
out_sample = rf_model.predict(x_test)print('In-Sample Accuracy: %0.4f' % accuracy_score(y_train, in_sample))
print('Out-of-Sample Accuracy: %0.4f' % accuracy_score(y_test, out_sample))
样本内精度:0.8746
样本外精度:0.8814
准确度是正确预测的数量除以预测的总数。基本上,随机森林模型在预测谁将参与营销活动方面是正确的。
print('In-Sample Precision: %0.4f' % precision_score(y_train, in_sample))
print('Out-of-Sample Precision: %0.4f' % precision_score(y_test, out_sample))
样本内精度:0.9574
样本外精度:0.8714
精度是真阳性的数量除以真阳性和假阳性的数量。当你想知道预测有多正确时,你需要精确。例如,有多少客户实际参与了 X 营销活动,而不是那些被预测参与和没有参与的客户。
print('In-Sample Recall: %0.4f' % recall_score(y_train, in_sample))
print('Out-of-Sample Recall: %0.4f' % recall_score(y_test, out_sample))
样本召回率:0.1450
样本外召回:0.1618
召回是真阳性的数量除以真阳性和假阴性的数量。换句话说,有多少模型正确地预测了与 X 活动接触的客户,而不是那些实际接触的客户。
当我学习精确和回忆的区别时,我有点困惑。对我有帮助的是看到一个好的和另一个坏的区别。例如,高精度和低召回率可以发现目标输出,但是会遗漏一些目标输出机会。另一方面,高召回率和低精确度可能导致发现所有目标输出,但是预测实际上没有的目标输出。
# ROC and AUC curves
in_sample = rf_model.predict_proba(x_train)[:,1]
out_sample = rf_model.predict_proba(x_test)[:,1]
in_sample_fpr, in_sample_tpr, in_sample_thresholds = roc_curve(y_train, in_sample)
out_sample_fpr, out_sample_tpr, out_sample_thresholds = roc_curve(y_test, out_sample)
in_sample_roc_auc = auc(in_sample_fpr, in_sample_tpr)
out_sample_roc_auc = auc(out_sample_fpr, out_sample_tpr)print('In-Sample AUC: %0.4f' % in_sample_roc_auc)
print('Out-Sample AUC: %0.4f' % out_sample_roc_auc)
样本内 AUC: 0.8824
样本外 AUC: 0.8623
plt.figure(figsize=(10,7))plt.plot(
out_sample_fpr, out_sample_tpr, color='darkorange', label='Out-Sample ROC curve (area = %0.4f)' % in_sample_roc_auc
)
plt.plot(
in_sample_fpr, in_sample_tpr, color='navy', label='In-Sample ROC curve (area = %0.4f)' % out_sample_roc_auc
)
plt.plot([0, 1], [0, 1], color='gray', lw=1, linestyle='--')
plt.grid()
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('RandomForest Model ROC Curve')
plt.legend(loc="lower right")plt.show()

ROC 曲线显示了真阳性和假阳性的比率,您希望曲线最快到达左上角以获得最佳模型性能。我们的样本内和样本外曲线都没问题。如果两者之间的差距越来越大,那么这是一个迹象,表明该模型过于适合训练数据,而没有找到营销参与的一般模式[4]。
结论
恭喜,我们已经从头到尾建立了一个营销客户参与随机森林模型。首先,我们做了一些简单的数据探索,并对数据进行了特征工程处理,使之成为数值。接下来,我们创建了随机森林模型,并查看了各个决策树。之后,我们评估了训练集和测试集的数据,得到了一个非常好的 ROC 曲线。从我们的数据来看,客户退休似乎是一个关键特征,而总索赔和收入接近。向前发展的业务解决方案可以建议总是预先获取这些数据点。
免责声明:本文陈述的所有内容都是我个人的观点,不代表任何雇主。
参考
[1] A. McEachern,什么是客户参与,为什么它很重要?(2019)https://blog . smile . io/什么是客户参与度以及它为什么重要
[2] IBM Watson,营销客户价值数据(n . d .)
https://www . ka ggle . com/pankajjsh 06/IBM-Watson-Marketing-Customer-Value-Data/downloads/IBM-Watson-Marketing-Customer-Value-Data . zip/1
[3] B. Mikulski,Precision vs . recall-explain(n . d .)https://www . mikulskibartosz . name/Precision-vs-recall-explain/
[4] Y. Hwang,《营销数据科学实践》( 2019 年),派克特出版社
通过马尔可夫链进行营销分析
通过马尔可夫链了解客户的下一步行动

Image Source : http://setosa.io/ev/markov-chains/
假设你是一家在市场上销售快速消费品的公司。
让我们假设客户将遵循以下流程进行最终购买:

这些是客户在购买过程中的任何时候都会处于的状态。
现在,如何找出客户在 6 个月后会处于哪种状态?
马尔科夫链来救援了!!
我们先来了解一下什么是马尔可夫链。
马尔可夫链:
马尔可夫链是描述一系列可能事件的随机模型,其中每个事件的概率仅取决于前一个事件达到的状态
马尔可夫链是在概率上彼此相关的连续事件。
这些事件也称为状态
这些状态一起形成了所谓的状态空间。
下一个事件或下一个状态的概率只取决于当前状态,而不取决于先前的状态。马氏链的这个性质叫做无记忆性。它不关心过去发生了什么,只关注当前的信息来预测下一个状态会发生什么。
马尔可夫链——状态、概率和转移矩阵
让我们深入一点。
马尔可夫链提供了
关于当前状态的信息
&
从一种状态转移到另一种状态的转移概率
利用以上两个信息,我们可以预测下一个状态。
用数学术语来说,当前状态称为初始状态向量
所以,我们得到的是:
最终状态=初始状态*转移矩阵
经典例子
马尔可夫链的一个经典例子是预测天气。我们有两种不同的天气状况:晴天和雨天。让我们假设今天是晴天。我们有以下可能性:
假设今天是晴天,明天是晴天的概率(处于相同状态的概率):0.9
假设今天是晴天,明天下雨的概率:0.1
假设今天下雨,明天是晴天的概率(处于相同状态的概率):0.5
假设今天下雨,明天下雨的概率(处于相同状态的概率):0.5

Source: Wikipedia
这里的初始向量是:

转换矩阵=

第二天的天气=

回忆一下终态=初态*转移矩阵?以上代表相同。
那么推论是什么呢?
第二天有 90%的可能性天气晴朗,10%的可能性下雨。
回到问题
回到问题上来,我们需要知道产品发布 6 个月后客户的状态。
我们可以假设客户在任一时间点可能处于 4 种状态!!
1.意识
2.考虑
3.购买
4.不购买
我们有以下信息:
客户总数= 200,000
每个州/类别的客户数量
从一个状态转移到另一个状态的转移概率
关于在这几个月开展的一些活动或广告的信息(活动/广告的目的是增加购买产品的客户数量)
营销分析目标:
获得 6 个月后所有 4 个州的客户数量
评估该活动在增加购买该产品的顾客数量方面是否有效
所以,让我们深入数学部分。
注:A —认知,C —考虑,P —购买,NP —不购买
初始状态向量=

转换矩阵=

可以更清楚地看到所有 4 个状态之间的运动:

顾客的最终状态=初始状态向量*转移矩阵

结果评估
现在让我们评估我们的结果。
起始向量

最终向量

我们可以注意到,“了解”和“考虑”的人数有所减少。这是一件好事,因为人们实际上从“意识”和“考虑”状态转移到了“购买”状态(增长了近 34%!!)还要注意,处于“不购买”状态的人数减少了(减少了 11%)。
总的来说,我们的分析表明活动/广告奏效了!!
马尔可夫链在营销分析和 NLP 等其他领域有许多其他应用。
敬请关注更多文章…
如果你喜欢我的文章,请给它几个掌声!!!
更多详情,请联系我:
另外,一定要看看我们在 MMM 上的视频:
版权所有 2018https://www.arymalabs.com/版权所有。
Python 中 Markov 链的营销渠道属性——第 2 部分:完整演练

在渠道属性的背景下,arkov chains 为我们提供了一个框架,以统计方式模拟用户旅程,以及每个渠道如何考虑用户从一个渠道到另一个渠道的旅行,最终转换(或不转换)。通过使用这些转移概率,我们可以确定单个渠道对我们总转化率的统计影响。
关于营销归因和马尔可夫链的更多细节,参见第 1 部分。
在关于这个主题的第一部分中,我们讨论了什么是营销归因,为什么准确和正确的归因越来越重要,以及马尔可夫链背后的理论如何应用于这个领域。
虽然那篇文章包含了如何以编程方式将马尔可夫链应用于 Python 中的示例客户数据集的实际例子,但它也涉及到对 R 包channel attribute的严重依赖。
对于生产应用程序来说,这种对独立软件和语言的依赖程度并不理想,相反,我们希望将整个归属过程放在一个应用程序中——在本例中是 Python。
在本文中,我将通过实际的代码示例来说明如何实现这一点。
数据
对于这个更新的演练,我已经更新了数据集,以便与我们在实际生产环境中可能遇到的数据格式更加一致。数据集可以在 这里下载 。
对于每一个独特的客户和访问我们的数据集这一次包含以下信息在每一行:
- Cookie:随机生成的客户 id,使我们能够将后续访问与同一个客户联系起来
- 时间戳:访问发生的日期和时间
- 交互作用:分类变量,表示发生的交互作用的类型
- Conversion:指示转换是否发生的布尔变量
- 转换值:潜在转换事件的值
- 渠道:将客户带到我们网站的营销渠道
该数据集包含约 240,000 名独立客户的约 586,000 个营销接触点,这些接触点产生了约 18,000,000 次转化事件。在表格格式中,数据集将如下所示:

数据预处理
为了将我们的数据转换成适用于马尔可夫链算法的理想格式,我们需要做一些预处理。
我们将从导入熊猫开始,加载我们的数据集,并创建一个列来指示每个用户的接触点顺序:
接下来,我们希望将数据框从长格式格式化为宽格式,因此我们最终将得到一个数据框,其中包含每个用户一行,以及一个接触点列表中按时间顺序排列的用户旅程总数。
我们首先将按时间顺序排列的接触点分组到一个列表中,将最终转换/非转换事件的列表合并到该数据框中,最后在用户旅程列表的末尾添加一个“空”或“转换”事件。
这将为我们提供一个如下所示的数据框架:

马尔可夫链
我们现在可以转向实际的马尔可夫链方法。
马尔可夫链的算法可以总结为两个步骤:
- 计算状态空间中所有状态之间的转移概率
- 计算移除效应(关于移除效应的更多信息,参见第 1 部分
我们将从定义所有用户旅程、总转化率和基础转化率的列表开始。所有我们以后会用到的东西:
接下来,我们将定义一个函数来识别所有潜在的状态转换,并输出包含这些转换的字典。在计算转移概率时,我们将使用它作为输入:
并且计算所有转移概率的函数可以定义为:
上面应该给我们留下一个字典,其中包含所有的转换以及给定历史数据时它们各自的转换概率。
最后一步是确定每个营销渠道的去除效果。为此,我们将利用线性代数和矩阵操作,因此让我们将上述转移概率字典转换为数据框架(矩阵):
我们刚刚制作的转换矩阵本身实际上包含了大量有价值的信息。它的一个直接衍生物将是生成一个方向图或转换热图来可视化典型的用户旅程。

Heat map for transition probabilities in our data set
使用历史背景和上面的热图,我们不仅可以深入了解每个营销渠道如何推动用户参与我们的转化活动,还可以获得营销渠道之间如何互动的关键信息。鉴于当今典型的多点接触转化之旅,这些信息可以证明是非常有价值的,并允许我们优化我们的多渠道客户转化之旅。
现在,我们可以迭代地遍历每个通道,并评估如果我们从状态空间中删除一个通道,它将对整体转换产生的影响。我们将这样做,并将产生的移除效果添加到输出词典中:
由此产生的移除效应字典可用于计算我们每个营销渠道的马尔可夫链属性:
为了更好地感受我们的劳动成果,让我们来看一下每个渠道的最终归因转换值。
如果您一直关注我们的原始数据集,您应该会看到下面的条形图,其中显示了通过马尔可夫链算法归属于每个渠道的总转化率:

重要的是要记住,虽然本例中的数据集包含大量数据,但它只包括 5 个营销渠道。在现实世界中,我们可能会使用数倍于此数量的渠道(如果我们应用更细粒度的模型,如特定于活动的归因模型,则数量会更多),因此增加了典型用户旅程的复杂性,以及对支持这种复杂程度的归因模型的需求。
为营销渠道分配准确的信用可能是一项复杂但有益的任务。使用本文中概述的马尔可夫链方法,可以让你的属性更准确地反映你的用户是如何与你的营销互动的。
关于作者
Morten 是 Wealthsimple 的一名数据科学家,他利用数据科学帮助人们实现财务自由。
Wealthsimple 的数据科学团队一直在寻找新的创新、聪明和有抱负的人加入团队。查看我们的职业页面或联系 LinkedIn 。
基于 Python 的马尔可夫链分析与仿真
用概率解决现实世界的问题
马尔可夫链是一个离散时间的随机过程,它以一定的概率从一个状态前进到另一个状态,这可以用一个图和状态转移矩阵 P 来表示,如下所示:

这样的链,如果它们是一阶马尔可夫链,展示了马尔可夫性质,即下一个状态仅依赖于当前状态,而不依赖于它是如何到达那里的:

在这篇文章中,我们看两个不同的概念,一个是从马尔可夫链模拟,另一个是计算它的平稳分布。稳定分布是当样本数量接近无穷大时,系统在每个状态下花费的时间分数。如果我们有 N 个状态,平稳分布是一个长度为 N 的向量,其值总和为 1,因为它是一个概率分布。
我们还看两个例子,一个简单的玩具例子,以及一个可能的现实世界场景分析问题。
计算平稳分布
注意,在下面的第一个实现中,不是对状态转换的模拟,只是对稳定分布的计算。
让我们从计算分布的迭代方法开始。我们正在做的是将转移矩阵提升到迭代次数的幂:

平稳分布通常被称为π。
因此

import numpy as np
import pandas as pd
from random import seed
from random import random
import matplotlib.pyplot as plt
P = np.array([[0.2, 0.7, 0.1],
[0.9, 0.0, 0.1],
[0.2, 0.8, 0.0]])state=np.array([[1.0, 0.0, 0.0]])
stateHist=state
dfStateHist=pd.DataFrame(state)
distr_hist = [[0,0,0]]for x in range(50):
state=np.dot(state,P)
print(state)
stateHist=np.append(stateHist,state,axis=0)
dfDistrHist = pd.DataFrame(stateHist)
dfDistrHist.plot()plt.show()
计算很快收敛到稳定分布:


如前所述,π是稳定分布。
在这种情况下,这也可以通过一组超定方程的线性代数解来实现:
A=np.append(transpose(P)-identity(3),[[1,1,1]],axis=0
b=transpose(np.array([0,0,0,1]))
np.linalg.solve(transpose(A).dot(A), transpose(A).dot(b)
这也返回[0.49,0.42,0.09],平稳分布π。
我们是如何计算的,如下所示:
可以证明,如果πP=π,πi=1,马尔可夫链是平稳的,具有平稳分布π
其中 i 为单位列向量,即概率之和必须恰好为 1,也可以表示为

做一些代数运算:

结合π i =1:

而 b 是除最后一个元素外所有元素都为 0 的向量。
继鲁切-卡佩里之后,

假设增广矩阵[A|b]的秩等于系数矩阵 A 的秩,则 as 可以由此求解 Pi,即平稳分布。
同样,这个算法实现可以被通用化、扩展,并作为一个类来实现。
从马尔可夫链模拟
通过注意到来自任何给定状态(概率矩阵中的对应行)的移动集合形成多项式分布,可以从马尔可夫链进行模拟。因此,可以通过模拟多项式分布来模拟马尔可夫链。
从多项式分布进行模拟的一种方法是将长度为 1 的线分成与概率成比例的区间,然后根据 0 和 1 之间的均匀随机数选取一个区间。
参见维基百科这里https://en.wikipedia.org/wiki/Multinomial_distribution。
这在下面的函数 simulate_multinomial 中进行了说明。我们从

然后我们使用 cs ,即 P 中概率的累积和,以便按比例分配随机数。
import numpy as np
import pandas as pd
from random import seed
from random import random
import matplotlib.pyplot as pltP = np.array([[0.2, 0.7, 0.1],
[0.9, 0.0, 0.1],
[0.2, 0.8, 0.0]])stateChangeHist= np.array([[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0]])state=np.array([[1.0, 0.0, 0.0]])
currentState=0
stateHist=state
dfStateHist=pd.DataFrame(state)
distr_hist = [[0,0,0]]
seed(4)# Simulate from multinomial distribution
def simulate_multinomial(vmultinomial):
r=np.random.uniform(0.0, 1.0)
CS=np.cumsum(vmultinomial)
CS=np.insert(CS,0,0)
m=(np.where(CS<r))[0]
nextState=m[len(m)-1]
return nextStatefor x in range(1000):
currentRow=np.ma.masked_values((P[currentState]), 0.0)
nextState=simulate_multinomial(currentRow) # Keep track of state changes stateChangeHist[currentState,nextState]+=1 # Keep track of the state vector itself
state=np.array([[0,0,0]])
state[0,nextState]=1.0 # Keep track of state history
stateHist=np.append(stateHist,state,axis=0)
currentState=nextState # calculate the actual distribution over the 3 states so far
totals=np.sum(stateHist,axis=0)
gt=np.sum(totals)
distrib=totals/gt
distrib=np.reshape(distrib,(1,3)
distr_hist=np.append(distr_hist,distrib,axis=0)print(distrib)
P_hat=stateChangeHist/stateChangeHist.sum(axis=1)[:,None]
# Check estimated state transition probabilities based on history so far:print(P_hat)dfDistrHist = pd.DataFrame(distr_hist)# Plot the distribution as the simulation progresses over timedfDistrHist.plot(title="Simulation History")
plt.show()
从图中可以看出,在大约 400 个模拟步骤之后,分布开始收敛到稳定分布。

分布收敛到[0.47652348 0.41758242 0.10589411]:
该分布与我们之前通过求解马尔可夫链计算的平稳分布非常接近。其实四舍五入到两位小数是一样的:[0.49,0.42,0.09]。
正如我们在下面看到的,从转换历史中重建状态转换矩阵给了我们预期的结果:
[0.18,0.72,0.10]
【0.91,0.00,0.09】
【0.19,0.80,0.00】
这个算法实现可以是通用的、可扩展的,并作为一个类来实现。
它展示了如何用 Python 实现简洁紧凑的算法。
媒体、电信或类似行业的应用。
比方说,对于与高价值客户一致的特定人口统计,我们在订阅媒体市场(例如付费电视)中有 4 个“竞争对手”,分布相对稳定但不断变化[.55,0.2,0.1,0.15],最后一组有 15%的人没有任何特定的订阅服务,更喜欢按需消费免费内容。

https://www.livechatinc.com/blog/churn-rate/
第二大竞争对手(b)刚刚推出了一款新的高端产品,现任者怀疑该产品正在侵蚀他们的市场份额。他们想知道如果他们不干预,最终会如何影响他们的市场份额。他们还想了解自己内部的客户流失动态,以及这与他们的市场份额之间的关系。
让我们假设他们知道他们有时会失去竞争对手的客户,包括免费内容,特别是随着他们的高平均每用户收入(ARPU)客户群的发展,他们有时会赢得客户,但他们不了解全貌。
所以,我们想象他们委托我们做一项研究。
为了简单起见,我们在这里对人口动态做了很多隐含的假设。例如,我们假设转移概率保持不变。
首先,我们进行一项市场调查,以了解消费者如何在不同的供应商之间移动,从那里我们可以构建一个概率矩阵如下:

a、b、c、d 代表我们的市场参与者。
市场研究表明,消费者从一个服务提供商转向另一个服务提供商的估计概率如下:

我们感兴趣的第一个问题是,考虑到所有其他流失概率,如果 A 继续以估计的速度流失客户到 B,将会发生什么。
使用我们之前导出的矩阵解,并用 Python 编码,我们可以计算新的平稳分布。
P = np.array([[0.9262, 0.0385, 0.01, 0.0253],
[0.01, 0.94, 0.01, 0.04],
[0.01, 0.035, 0.92, 0.04],
[0.035, 0.035, 0.035, 0.895]])A=np.append(transpose(P)-identity(4),[[1,1,1,1]],axis=0)b=transpose(np.array([0,0,0,0,1]))np.linalg.solve(transpose(A).dot(A), transpose(A).dot(b))
这给了我们新的平稳分布[0.19,0.37,0.18,0.25]
然而,当我们检查系数矩阵和增广矩阵的秩时,我们注意到,与更简单的例子不同,它们并不对应。这意味着分析问题的公式可能没有唯一的解,所以我们想用另一种技术来检验它。
NP . linalg . matrix _ rank(NP . append(A,NP . transpose(b . shape(1,5)),axis=1))
5
np.linalg.matrix_rank(A)
4
可以看出,迭代解(其中我们将转移矩阵提升到 n 的幂)不收敛,这给我们留下了模拟选项。


从上面我们可以估计,长期来看,平稳分布会是这样的:[0.19,0.4,0.18,0.23],实际上非常接近解析解。
换句话说,现有企业的市场份额预计将下降到 20%左右,而竞争对手的市场份额将上升到 40%左右。
由此也可以看出,对于更复杂的问题,现实世界中看似合理的解析解和模拟解,确实还是对应的。

我希望您喜欢这篇关于如何使用离散马尔可夫链解决现实世界问题的基本介绍,并鼓励您思考自己组织中可以用这种方式回答的问题。您还可以通过计算留住客户的价值来扩展这个示例,从而计算出在留住客户方面投资的价值。
版权所有 2020 Herman Scheepers
特此免费授予任何获得本条款中的代码和相关文档文件所暗示的本软件副本(“软件”)的人不受限制地经营本软件的权利,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售本软件副本的权利,并允许获得本软件的人根据以下条件这样做:
上述版权声明和本许可声明应包含在软件的所有副本或重要部分中。
本软件按“原样”提供,不含任何明示或暗示的担保,包括但不限于对适销性、特定用途适用性和不侵权的担保。在任何情况下,作者或版权所有者都不对任何索赔、损害或其他责任负责,无论是在合同诉讼、侵权诉讼或其他诉讼中,还是在与软件或软件的使用或其他交易相关的诉讼中。
音乐生成的马尔可夫链

从本文中,您将了解马尔可夫链模型,以及如何将它应用于音乐生成。
什么是马尔可夫链?
马尔可夫链是描述一系列可能事件的模型。这个序列需要满足马尔可夫假设——下一个状态的概率取决于前一个状态,而不是序列中的所有前一个状态。
这听起来像是对真实案例的简化。例如,为了应用马尔可夫链进行天气预测,我们需要假设明天的天气只取决于当前的天气,并假设没有其他因素,如一年中的时间等
尽管在许多情况下这种简化,我们将能够生成有用的预测,但同时,我们将能够通过降低计算成本来更快地解决我们的任务。
马尔可夫链模型在金融、自然语言处理和任何有时间序列数据的地方都有很多应用。
用马尔可夫链生成音乐
有很多优秀的论文和博客文章解释了马尔可夫链。所以不深究理论细节,让我们把这个模型应用到实践上!马尔可夫链最普遍的应用是语言和语音,例如,预测句子中的下一个单词。但是如果我们尝试创造音乐呢?
和自然语言一样,我们可以把音乐想象成一系列音符。但是因为我弹吉他,所以我会用和弦来操作。如果我们研究和弦序列并学习它的模式,我们会发现某些和弦可能更多地跟随特定和弦,而其他和弦很少跟随那个和弦。我们将构建我们的模型来发现和理解这种模式。
好吧,计划是这样的:
- 取和弦集
- 计算和弦跟随特定和弦的概率分布
- 定义第一个和弦或随机选择
- 考虑概率分布,随机选择下一个和弦
- 对生成的和弦重复步骤 4
- …
- 随机音乐太棒了!
分步指南:
对于数据源,我准备了一个带有和弦序列的 CSV 文件,这些和弦序列来自利物浦的一个著名乐队。你可以在 GitHub 上找到这个文件。
序列示例:
['F', 'Em7', 'A7', 'Dm', 'Dm7', 'Bb', 'C7', 'F', 'C', 'Dm7',...]
首先,我们制造二元模型:
['F Em7', 'Em7 A7', 'A7 Dm', 'Dm Dm7', 'Dm7 Bb', 'Bb C7', ...]
现在,如果我把和弦 F 作为一个序列中的初始和弦,其他和弦跟随它的概率是多少?
有 18 个以和弦 F 开头的二元组:
['F Em7', 'F C', 'F F', 'F Em7', 'F C', 'F A7sus4', 'F A7sus4', ...]
然后,我们将计算每个独特的二元模型在序列中出现的频率:
{'F Em7': 4, 'F C': 4, 'F F': 3, 'F A7sus4': 4, 'F Fsus4': 2, 'F G7': 1}
如果我们归一化,我们会得到概率:
{'F Em7': 0.222,
'F C': 0.222,
'F F': 0.167,
'F A7sus4': 0.222,
'F Fsus4': 0.111,
'F G7': 0.056}
这通常可以用图表的形式来解释:

Weighted graph of possible next chord
这个图的每个节点,除了中间的初始节点 F,代表了我们的序列可以达到的可能状态,在我们的例子中,它们是可能跟随 F 的弦,一些弦比其他弦有更高的概率,一些弦根本不能跟随 F 弦,例如 Am,因为没有二元模型可以将这个弦与 F 组合。
现在,马尔可夫链是一个随机过程,或者你更喜欢随机过程。为了进入下一个状态,我们将随机选择和弦,但是根据概率分布,在我们的例子中,这意味着我们更有可能选择和弦 C 而不是 G7。
对于给定的和弦 F,下一个和弦有 6 个候选和弦:
options
>>> ['Em7', 'C', 'F', 'A7sus4', 'Fsus4', 'G7']
每个和弦都有相应的概率:
probabilities
>>> [0.222, 0.222, 0.167, 0.222, 0.111, 0.056]
Numpy 由于 1.7.0 版本可以根据给定的概率分布执行随机采样,所以我们使用:
import numpy as npchoise = np.random.choice(options, p=probabilities)
假设我们随机选择的结果是 Em7。现在我们有了一个新的状态,可以再次重复整个过程。
整个工作流程如下所示:
# Our current state
chord = 'F'# create list of bigrams which stats with current chord
bigrams_with_current_chord = [bigram for bigram in bigrams if bigram.split(' ')[0]==chord]# count appearance of each bigram
count_appearance = dict(Counter(bigrams_with_current_chord))# convert apperance into probabilities
for ngram in count_appearance.keys():
count_appearance[ngram] = count_appearance[ngram]/len(bigrams_with_current_chord)# create list of possible options for the next chord
options = [key.split(' ')[1] for key in count_appearance.keys()]
# create list of probability distribution
probabilities = list(count_appearance.values())# Make random prediction
np.random.choice(options, p=probabilities)
因为这是一个随机过程,每次你运行这个模型,都会得到不同的结果。为了实现可重复性,您可以像这样设置种子:
np.random.seed(42)
我们可以将整个过程概括为两个功能:
def predict_next_state(chord:str, data:list=bigrams):
"""Predict next chord based on current state."""
# create list of bigrams which stats with current chord
bigrams_with_current_chord = [bigram for bigram in bigrams if bigram.split(' ')[0]==chord]
# count appearance of each bigram
count_appearance = dict(Counter(bigrams_with_current_chord))
# convert apperance into probabilities
for ngram in count_appearance.keys():
count_appearance[ngram] = count_appearance[ngram]/len(bigrams_with_current_chord)
# create list of possible options for the next chord
options = [key.split(' ')[1] for key in count_appearance.keys()]
# create list of probability distribution
probabilities = list(count_appearance.values())
# return random prediction
return np.random.choice(options, p=probabilities)def generate_sequence(chord:str=None, data:list=bigrams, length:int=30):
"""Generate sequence of defined length."""
# create list to store future chords
chords = []
for n in range(length):
# append next chord for the list
chords.append(predict_next_state(chord, bigrams))
# use last chord in sequence to predict next chord
chord = chords[-1]
return chords
现在我们可以生成一个我们想要的长度的序列:
generate_sequence('C')
序列示例:
['Bb',
'Dm',
'C',
'Bb',
'C7',
'F',
'Em7',
'A7',
'Dm',
'Dm7',
'Bb',
'Dm',
'Gm6'
...
]
我试着用吉他弹奏它,它听起来确实像一首来自利物浦的乐队可能写的歌。唯一缺少的是文本,但我们可以使用在文本语料库上训练的相同模型来为歌曲生成文本:)。
摘要
我们仅仅用简单的马尔可夫链触及了冰山一角,随机模型的世界是如此之大,包括隐马尔可夫链、马尔可夫链蒙特卡罗、哈密顿蒙特卡罗等等。但是在每个模型的本质上都有相同的马尔可夫假设——下一个状态依赖于当前状态,而不依赖于先前的状态序列。
因为这个简单而强大的规则,马尔可夫链模型在许多领域得到了应用,也可以成功地应用于音乐的产生。
这里最酷的事情之一是,我们将根据我们训练模型的语料库得到不同的结果。在来自电台司令和模型的语料库上训练将生成电台司令风格的和弦序列。
代码和数据集可以在我的 GitHub 资源库中找到。
参考资料:
体育运动中的马尔可夫链模型
一个模型从数学上描述了我们对数据的期望——在这种情况下,来自体育数据。一种简单类型的模型,称为马尔可夫链,在几种不同运动的分析中得到应用——每一种运动都有某种离散的性质,我很快会对此进行精确的解释。属于这一类的运动包括网球、棒球和排球。对于这篇博文,我会考虑网球。

Tennis star Serena Williams
如果一个模型描述了我们对数据的期望,我们必须承认所涉及的数据很难捕捉到游戏的一切。具体来说,网球的马尔可夫链模型描述了我们对有限数据的预期——这些数据只记录了哪个球员在比赛中赢得了每一分。关于其他一切的信息,如球的轨迹,甚至截击的长度或发球的失误,仍然是未知的。此外,数据只涉及两个玩家之间相遇的一小部分。网球比赛分成几组,几组分成几场比赛。所以如果小威赢得了她的第一场比赛,她将需要留下来赢得更多的比赛。我们的模型只关注这些游戏中的一个游戏的分数结果数据。
在网球比赛中,当一名选手达到两个目标时,每场比赛就赢了:她的得分(1)必须至少达到 4 分,并且(2)必须超过对手 2 分。分数以“爱”(0 分)开始,然后是“15”(1 分)、“30”(2 分)、“40”(3 分)。如果双方都至少得了 2 分,比分就是“平手”。如果两个玩家都至少得 2 分,但其中一个领先 1 分,则得分为“优势【那个玩家】”。
每打出一个点,只有两种情况可能发生:一个玩家(姑且称她为“A”)可以赢得该点,或者另一个玩家(姑且称她为“B”)可以赢得该点。该模型将值 p 分配给玩家 A 赢得一分的概率,并将值 q 分配给玩家 B 获胜的概率。对于每个点,不存在其他可能性,所以 p + q = 1。重要的是,该模型假设这些概率永远不会改变,无论游戏如何展开。此外,每个点的结果独立于其他点的结果。
我把游戏的每一个分数放在一个图表上(见下面),并用箭头指出,哪个分数可以导致下一个分数,导致其他分数。在马尔可夫链术语中,每个分数代表游戏的一个状态,从这个状态可以发生零个或多个转换到其他状态。如上所述,从大多数状态来看,恰好存在两种可能的转换(A 赢得下一点,或者 B 赢得下一点)。在网球中,有 15 种这样的状态,显示为圆圈。马尔可夫链术语称它们为瞬态。从另外两个状态开始,游戏不再继续,也不会发生进一步的转换。我将这些异常的吸收态显示为矩形,分别标记为“A 赢”和“B 赢”我们的建模假设意味着,游戏最终肯定会离开所有的瞬态,进入一个吸收态(因此有了这个术语)。经验证实了这一预期。

A diagram of the Markov chain for tennis
在这个图中,每个圆都有两个箭头。如果玩家 A 赢得这一点,游戏向左转移,沿着标有 p (其概率)的箭头指向“A 赢”。然而,对于概率 q,游戏遵循另一个箭头,(记住 p + q = 1),向右朝着“B 赢。”
是什么让这个模型成为马尔可夫链?首先,状态之间的特定转换仍然是不确定的,但是,像所有随机现象一样,服从可量化的概率规则。第二,该模型满足被称为马尔可夫属性的条件,该条件向分析师保证,为了预测关于游戏未来的任何事情,游戏的当前状态包括关于游戏的所有相关信息(过去和当前),这些信息可以帮助做出这样的预测(未来)。
换句话说,Markov 属性断言,假设我们已经知道当前状态,那么通过图采取的先前路径不会给我们提供有用的额外信息来对游戏进行预测。例如,如果 A 赢得了前 3 分,但随后输掉了接下来的 3 分,游戏可能会进入平手状态。或者,A 可能会失去 3 个未回答的点,然后赶上。还存在许多其他平手的途径,实际上是无限的,因为游戏可能会在平手、优势 A 和优势 b 之间无限波动。马尔科夫属性表明,无论采取哪种途径,对未来的预测都只取决于当前状态平手,而不是游戏如何到达那里。
马尔可夫属性仍然只是一个建模假设。关于真正的网球是真的吗?模型不会告诉我们。只有从许多实际游戏中获得大量数据,我们才能评估支持或反对这一假设的证据的强度。相反,体育运动中流行的“动量”概念可能表明,最近得分更多的球员有更有利的未来——比马尔可夫链预测的更有利。或者,一个“重整旗鼓以东山再起的假设”可能暗示,最近输球的玩家比我们的模型所认为的更有机会获胜。不用说,马尔可夫性质明确地否定了这些可能性:根据我们编纂的假设,不存在这样的现象。
统计学家经常重复乔治·博克斯的话,说所有的模型都是错的,但有些是有用的。马尔可夫链可能不能完美地代表网球,但该模型仍然有用,因为它可以产生对比赛的宝贵见解。请注意,该模型只包含一个参数, p 或 q (一个参数,因为这两个量加起来等于 1——一旦知道了其中一个,就可以确定另一个)。有了这些知识,个人的结果仍然是不确定的,但你可以发现任何事件的概率,此外,任何与游戏相关的量的分布。
例如,知道了 p 不会让你知道 A 是否会赢得任何给定的分数,更不用说任何给定的游戏、盘或比赛。当然啦!也就是说,知道了 p ,模型将允许你确定 A 赢得游戏的概率,至少假设建模假设成立。此外,虽然您无法预先知道任何一个特定游戏将持续多长时间,但您可以发现,例如,在一个模型游戏中所玩点数的分布。事实上,您可以计算这种分布的相关统计数据——包括平均值、中值、标准差,甚至超过 10 分的游戏比例。事实上,所有这些计算都可以完成,不仅仅是对单个值的 p ,而是对任何可能的值,这使得模型真正有用,并给建模者带来了希望,即关于模型的一般事实将转化为关于游戏的深刻见解。如果我们碰巧观察到一场或多场比赛持续超过 50 分,在一场有 250 场比赛的锦标赛中,假设所有球员都旗鼓相当,我们应该有多惊讶?用我们的模型对网球进行分析,证实了 Box 的格言,尽管在许多细节上不可避免地存在错误,但仍可能证明是有启发性的。
马尔可夫链蒙特卡罗
将您对 MCMC 的理解提升到中级水平
当我学习马尔可夫链蒙特卡罗(MCMC)时,我的导师告诉我们有三种方法来解释 MCMC。
- 基本知识:MCMC 允许我们利用计算机来做贝叶斯统计。
- 中级 : MCMC 是一种可以找到我们感兴趣的参数的后验分布的方法。具体来说,这种类型的算法以一种依赖于马尔可夫属性的方式生成蒙特卡罗模拟,然后以一定的速率接受这些模拟以获得后验分布。"
- 进阶:一堂完整的统计学课。
我写这篇博客的目的是让你达到中级水平。
先从基础的开始吧。
MCMC 到底是什么?要回答这个问题,我们首先需要复习一下贝叶斯统计。贝叶斯统计是建立在这样一个理念上的,即一件事情发生的概率受事先假设的概率和数据显示的某件事情发生的可能性的影响。在贝叶斯统计中,概率用分布来表示。
如果先验和似然概率分布是正态分布,我们就能够用一个函数来描述后验分布。这被称为封闭解。这种类型的贝叶斯如下所示。正如你所看到的,后验分布是由先验分布和似然分布共同形成的,并在中间的某处结束。

Created in Matplotlib inspired by Matt Brems
但是当概率不是很大的时候呢?当概率看起来更像这样时会发生什么?

Rbb [CC BY-SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0)], from Wikimedia Commons
在这种情况下,可能性没有正态分布,所以我们最终得到一个右偏后验分布。因为我们不能用公式来表达,我们必须使用马尔可夫链蒙特卡罗。
马尔可夫链蒙特卡罗的三个部分
一:蒙特卡洛
- 蒙特卡罗模拟通过生成随机数来模拟复杂系统。
- 在下面的 gif 的情况下,蒙特卡洛生成一个参数为(0-1,0-1)的随机点,通过确定曲线下结束的点的数量,我们能够近似整个圆的面积,并从π开始。

nicoguaro [CC BY 3.0 (https://creativecommons.org/licenses/by/3.0)], from Wikimedia Commons
二:马尔可夫链
- 马尔可夫链本质上是一个变量如何在图中“行走”的表示,或者一个随机变量如何随时间从一种状态改变到另一种状态。

image source http://www.mathcs.emory.edu/~cheung/
- 上图展示了情绪状态的马尔可夫链。在这个链条中,如果你很快乐,有 20%的几率你会把情绪状态变成一般,20%的几率你会变得悲伤,60%的几率你会保持快乐。
马尔可夫链由马尔可夫属性决定
F(Xt+1|Xt) = f(Xt+1|Xt,Xt-1,Xt-2,….)
如果我知道现在正在发生什么,知道发生了什么让我们走到这一步或前一步,等等。没给我提供更多信息。
这方面例子有:
- 孟德尔遗传学。在下面的例子中,子豆的颜色完全受父豆的颜色影响。第一代的豆子颜色受到前一代的影响,但在确定第二代的颜色时不需要考虑这一点。

Pbroks13 [CC BY-SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0)]
- 棋盘游戏:当玩大富翁游戏并试图确定玩家去某个空间的概率时,你需要的唯一信息是玩家目前在哪里。玩家之前的回合在哪里并不影响它接下来的走向,除了它决定了这一回合在哪里。
三:接受-拒绝抽样
MCMC 的第三部分是接受-拒绝抽样。当我们对新的观察进行采样时,我们决定它是否在正确的方向上,然后决定我们是保留它还是丢弃它。
两种常见的接受-拒绝算法是 Metropolis-Hasting 算法和不掉头采样器。不准掉头的数学比我在这篇中等文章中解释的要复杂,但是如果你想深入研究,可以看看这篇文章。
这是我对大都市生活的高层次解释
- 我们在 x 点。
- 我们对下一步做一个猜测。我们称之为 x*
- 然后,我们计算 x*/x 的概率比。这是使用似然性和先验分布的乘积计算的。
- 如果 p(x)/p(x)的比值(也称为接受概率)大于 1,我们接受 x作为新位置。
- 即使接受概率小于 1,我们也不自动拒绝 x。我们通过从均匀(0,1)分布中选择一个随机数来抛硬币。如果数字小于接受概率,我们接受 x,如果数字大于接受概率,我们拒绝 x*,并重新开始这个过程。
把所有的放在一起
- 我们随机生成数字:这是蒙特卡罗部分
- 我们允许我们生成的数字影响下一个生成的数字:这就是马尔可夫链
- 然后我们决定生成的新数字是否“朝着正确的方向前进”:接受-拒绝算法
- 然后我们检查收敛性:我们确定我们的数据何时收敛到一个合理的分布。收敛点之后随机生成的值成为我们的后验分布
我希望这有助于您在中级水平上理解 MCMC。
1.(经允许)直接从马特·布莱姆斯的演讲中借用。
2。一个很棒但是很数学的 MCMC 移植:https://blog . stata . com/2016/11/15/Bayesian-statistics-introduction-to-part-2-MCMC-and-the-metropolis-Hastings-algorithm/
马尔可夫链和 hmm
内部 AI
主要概念、属性和应用

Hidden Markov
在本文中,我们将关注马尔可夫模型,何时何地应该使用它们,以及隐马尔可夫模型。本文将着重于理论部分。在第二篇文章中,我将展示这些主题的 Python 实现。
马尔可夫模型,尤其是隐马尔可夫模型(HMM)用于:
- 语音识别
- 书写识别
- 物体或人脸检测
- 经济情景生成和特定财务任务
- 和几个 NLP 任务…
本文原载于我的个人博客:【https://maelfabien.github.io/machinelearning/HMM_1/#
我在这个资源库上发布我所有的文章和相应的代码:
本报告包含练习、代码、教程和我的个人博客文章
github.com](https://github.com/maelfabien/Machine_Learning_Tutorials)
不要犹豫开始回购:)
一.随机模型

Discrete-Time Stochastic Process
让我们从定义什么是随机模型开始。它本质上是一个离散时间过程,在时间 1,2,…取值,称为“状态,观察到:q1,q2,…”。状态简单地对应于过程的实际值,通常由有限空间定义:S=1,…Q。
该过程从初始状态开始 q1。然后,根据转移概率,我们在状态之间移动。我们可以使用贝叶斯法则计算状态序列的概率:

为了描述模型的特征,我们需要:
- 初始概率 P(q1)
- 所有的转移概率
正如你可能猜到的,这很难实现,因为我们需要知道很多参数。
二。离散时间马尔可夫链模型(DTMC)
1.什么是马尔可夫链?

DTMC
离散时间马尔可夫链(DTMC)是时间和事件的离散随机过程。马尔可夫链依赖于马尔可夫特性,即在过程中有一个有限的相关性:


让我们来说明这一点:考虑一个简单的迷宫,其中有一只老鼠被困。我们将把 qt 表示在 t 步之后老鼠所处的迷宫的位置。我们假设老鼠对它在迷宫中走过的路程没有记忆(T21)。它只是按照写在每一步棋旁边的概率,随机地走到那个位置。

DTMC Illustration
这里的状态可以代表很多东西,包括在 NLP 中。例如,我们可以:
- 1 =名词,
- 2 =动词,
- 3 =形容词…
例如,我们会对名词后有动词的概率感兴趣。
2.转移概率
如果离散时间马尔可夫链的转移概率不依赖于时间 t,则称其为齐次:

我们可以将该过程概括为一个转移矩阵,表示为 A =【AIJ】,i ∈ 1…Q,j ∈ 1…Q。如果:
- 所有条目都是非负的
- 每行总计为 1
在我们的例子中,转移矩阵是:

Transition matrix
注意,如果 a 是随机的,那么 A^n 也是随机的。
3.州
描述一个状态有几种方式。设 pii 为离开 I 后回到状态 I 的概率:
- 如果 pii <为 1,则状态 I 为瞬态
- 如果 pii=1,状态 I 是循环的
- 如果 aii=1,则状态 I 正在吸收
因此,如果返回到表示为 Tii 的相同状态之前的平均时间是有限的,则状态是正循环的。
如果一个状态 j 可以从任何其它状态 I 经过有限步到达,则 DTMC 是不可约的。不可约的 DTMC 实际上是一个强连通的图。
如果离散时间马尔可夫链只能在大于 1 的某个整数的倍数处返回状态,那么该链中的状态就是周期性的。
例如:

Periodic Markov Chain
否则称为非周期性。具有自循环的状态总是非周期性的。
4.逗留时间
设 Ti 是跳到其他状态之前在状态 I 花费的时间。
然后,Ti,即逗留时间,遵循几何分布:

预期花费的平均时间是 E(T)=1 / aii
5.m 步转换
在 m 个步骤中从 I 到 j 的概率表示为:

M-step transition
我们可以将 a22(4)视为时间 t=4 时鼠标位于位置 2 的概率。因此,从 I 到 j 正好 n 步的概率由 fij(n)给出,其中:

6.状态的概率分布
设πi(n)是在时间 n 处于状态 I 的概率:πI(n)= P(Xn = I)
那么,π(n)=[π1(n),π2(n),…]是概率分布的向量,它取决于:
- 初始转移矩阵 A
- 初始分布π(0)
注意π(n+1) = π(n)A,递归地:

对于不可约/非周期 DTMC,分布π(n)收敛到一个极限向量π,它与π(0)无关,是π = πP 的唯一解
并且∑i πi = 1
πi 也叫定态概率,稳态或均衡分布。
7.生成序列
为了模拟老鼠在迷宫中的路径,我们可能希望生成序列。
当我们想产生一个序列时,我们从一个初始状态 q1=1 开始。总的想法是:
- 我们选择一个随机数来知道我们应该从哪个状态开始
- 然后,选择一个随机数来知道我们移动到哪个状态
假设我们有以下简单的模型:

这对应于下面的矩阵 A 和初始概率向量π:

生成器的工作方式如下,通过连续抽取随机数来识别哪个过渡是指。

Sequence Generation, Step-by-step
第一步,我们选择一个随机数,看看它在初始概率向量中的位置。这给了我们第一个状态。
然后,我们选择下面的数字,它对应于状态 q1 的转移概率(矩阵 A 的第一行)。如果值小于 0.3,我们停留在 q1。否则,我们移到 q2。诸如此类…
8.解码序列
解码一个序列的目的是识别通向当前状态的最可能的路径。例如,如果鼠标处于状态 3,并经过 5 步到达那里,您需要确定最可能的路径。
9.用例
可以使用马尔可夫链:
- 通过解码字符序列并识别最可能的语言来识别句子的语言。
- 预测宏观经济形势,如市场崩溃和衰退与扩张之间的周期。
- 预测资产和期权价格,并计算信用风险。
- …
三。隐马尔可夫模型
隐马尔可夫模型(HMM)广泛用于:
- 语音识别
- 书写识别
- 物体或人脸检测
- 词性标注和其他自然语言处理任务…
我推荐看看 Luis Serrano 在 HMM 上做的介绍。
我们将把重点放在词性标注上。词性标注是一个过程,通过这个过程,我们能够将一个给定的单词标注为名词、代词、动词、副词…

例如,PoS 可以用于文本到语音的转换或词义消歧。

在这个具体情况下,同一个单词bear有完全不同的意思,对应的 PoS 也因此不同。
让我们考虑下面的场景。在你的办公室里,有两个同事经常聊天。你知道他们要么谈论工作要么谈论假期。因为他们看起来很酷,你想加入他们。但是你离理解整个对话太远了,你只能听到句子中的一些单词****
在加入对话之前,为了不显得太怪异,你想猜猜他说的是工作还是假期。例如,你的朋友可能会说这样的句子:

1.排放概率
你只听清楚 python 或 bear 这几个字,并试着猜测句子的上下文。由于你的朋友都是 Python 开发人员,所以当他们谈论工作时,他们 80%的时间都在谈论 Python。

这些概率被称为排放概率。
2.转移概率
你听着他们的对话,每分钟都在试图理解这个话题。你朋友的谈话有某种连贯性。事实上,如果一个小时他们谈论工作,下一分钟他们谈论假期的可能性更低。
我们可以为这种情况定义我们称之为的隐马尔可夫模型:

改变或不改变话题的概率被称为转移概率。
- 你理解的词语被称为观察,因为你观察它们。
- 他们谈论的主题被称为隐藏状态,因为你无法观察到它。
3.离散时间隐马尔可夫模型
HMM λ是由两个随机过程组合而成的序列:
- 一个观察到一个:O=o1,o2,…,oT,这里的话
- 一个隐藏的一:q=q1,q2,…qT,这里是谈话的话题。这被称为过程的状态。
HMM 模型由下式定义:
- 初始概率的向量 π=[π1,…πq],其中πi=P(q1=i)
- 未观察到的序列 a 的转移矩阵:a =[AIJ]= p(Qt = j∣qt1 = j)****
- 观察值的概率矩阵b =【bki】= p(ot = sk∣Qt = I)****
HMMs 背后的主要假设有哪些?
- ****观测值对隐藏态的条件独立性:p(O1,…,ot,…,oT ∣ q1,…,qt,…,qT,λ) = ∏i P(ot ∣ qt,λ)
- 平稳马尔可夫链 : P(q1,q2,…,Qt)= p(q1)p(q2∣q1)p(q3∣q2)…p(qt∣qt−1)
- ****观测值和状态序列的联合概率:p(O1,o2,…oT,q1,…,qT ∣ λ) = P(o1,…,oT ∣ q1,…,qT,λ) P(q1,…,qT)
HMM 是贝叶斯网络的一个子案例。
4.求转移概率
跃迁概率是基于我们所做的观察。我们可以假设,在仔细听完之后,每一分钟,我们都能理解他们谈论的话题。不过,这并没有给我们提供他们目前正在谈论的话题的全部信息。
在过去的 15 分钟里,你有 15 次观察, W 表示工作, H 表示假期。

我们注意到,在五分之二的情况下,话题工作导致话题假期,这解释了上图中的转移概率。
5.找出排放概率
因为我们对他们讨论的话题有观察,并且我们观察了讨论中使用的词语,我们可以定义排放概率的估计值:

6.随机时间内某个主题的概率
假设你要去喝咖啡,当你回来的时候,他们还在说话。你根本不知道他们在说什么!在那个随机时刻,他们谈论工作或假期的概率是多少?
我们可以从之前的观察中数出:10 次他们谈论假期,5 次谈论工作。因此,它表明我们有 1/3 的机会让他们谈论工作,2/3 的机会让他们谈论假期。
7.如果听到“Python”这个词,每个题目的概率是多少?
如果你听到“Python”这个词,那么这个话题是工作还是假期的概率就是用贝叶斯定理定义的!

接近 57%。
8.如果你听到一个单词序列,每个题目的概率是多少?
让我们从连续两次观察开始。假设我们连续听到“Python”和“Bear”这两个词。有哪些可能的组合?
- 巨蟒和工作联系在一起,熊和工作联系在一起
- 蟒蛇和假期联系在一起,熊和工作联系在一起
- 蟒蛇和假期联系在一起,熊和假期联系在一起
- 蟒蛇和工作联系在一起,熊和假期联系在一起
这些场景可以这样总结:

所以最有可能隐藏的状态就是节假日和假期。如果你听到两个以上的单词呢?假设是 50?计算所有可能的路径变得非常具有挑战性!这就是为什么维特比算法被引入,以克服这个问题。
9.维特比算法解码
维特比算法**背后的主要思想是,当我们计算最优解码序列时,我们并不保留所有的潜在路径,而是只保留最大似然对应的路径。**
它是这样工作的。我们从一系列观察到的事件开始,比如说Python, Python, Python, Bear, Bear, Python。这个序列简单地对应于一个观察序列:P(o1,o2,…,oT ∣ λm)

对于第一个观察,假设我们观察 Python,主题是 Work 的概率是它是 Work 的概率乘以假设它是 Work,它是 Python 的概率。
最可能的状态序列简单地对应于:

然后我们可以继续下一个观察。接下来会发生什么:

对于每个位置,我们使用前一个主题是工作或假期的事实来计算概率,对于每个情况,我们只保留最大值,因为我们的目标是找到最大可能性。因此,下一步是对假日主题进行同样的估计,并保持两条路径之间的最大值。

如果您解码整个序列,您应该会得到与此类似的东西(我已经对每一步的值进行了舍入,所以您可能会得到稍微不同的结果):

因此,当我们观察Python, Python, Python, Bear, Bear, Python时,最有可能的序列是Work, Work, Work, Holidays, Holidays, Holidays。
如果在这么长时间的跟踪之后,你终于去和你的同事聊天,你应该期待他们谈论假期:)
在时间 T 结束于状态 I 并且对应于观测 o1,…,oT 的潜在状态的最佳序列的联合概率由δT(i)表示。这是上述可能的途径之一。

通过递归,可以表明:

其中 bj 表示观察矩阵 B 的概率,aij 表示未观察序列的转移矩阵的值。这些参数是从一系列观察值和可用状态中估计出来的。δ就是我们在前进的每一步中取的最大值。
我不会在这里详细讨论。你应该简单地记住有两种方法来解决维特比,向前(正如我们已经看到的)和向后。
当我们只观察到部分序列并且面对不完整的数据时,使用 EM 算法。
10.生成序列
正如我们在马尔可夫链中看到的,我们可以用 hmm 生成序列。为此,我们需要:
- 首先产生隐藏状态 q1
- 从 q1 开始,生成 o1,例如 Work then Python
- 然后产生 q1 到 q2 的转换
- 从 q2 生成 o2
- …
流程是如何运作的?如上所述,这是一个两步过程,我们首先生成状态,然后进行观察。

Sequence Generation
结论:
👏👏👏
在本文中,我们介绍了马尔可夫链和 hmm 的基本理论,包括术语、假设、性质、序列生成和解码。
我希望这篇关于马尔可夫链和隐马尔可夫模型的介绍是有帮助的。我在下面的部分列出了我的消息来源。
在下一篇文章中,我将尝试用 Python 来说明这些概念。
来源:
- 国家高级矿业学院:https://www.emse.fr/~xie/SJTU/Ch4DMC.ppt
- MVE220 财务风险:http://www . math . chalmers . se/Stat/grund ub/CTH/mve 220/1617/reding projects 16-17/intromarkovchainsandapplications . pdf
- Udacity 的 HMMs:https://www.youtube.com/watch?v=kqSzLo9fenk
- 个人博客主持人:https://maelfabien.github.io/machinelearning/HMM_1/#
- 个人博客嗯:https://maelfabien.github.io/machinelearning/HMM_2/#
马尔可夫链:如何训练文本生成像乔治·马丁那样写作

马尔可夫链已经存在了一段时间,而且还会继续存在。从预测键盘到交易和生物学应用,它们已经被证明是多功能工具。
下面是一些马尔可夫链的行业应用:
- 文本生成(你是为此而来的)。
- 金融建模和预测(包括交易算法)。
- 物流:模拟未来的运输或行程。
- 搜索引擎:PageRank 可以看作是用马尔可夫链模拟一个随机的互联网冲浪者。
到目前为止,我们可以告诉这个算法是有用的,但到底什么是马尔可夫链?
什么是马尔可夫链?
马尔可夫链是一个随机过程,它模拟一组有限的状态,具有从一个给定状态跳到另一个状态的固定的条件概率。
这意味着,我们将有一个“代理”,它随机地在不同的状态之间跳跃,有一定的概率从一个状态跳到另一个状态。
为了展示马尔可夫链是什么样子,我们可以使用一个有向图,其中每个节点是一个状态(带有标签或相关数据),从节点 a 到节点 b 的边的权重是从状态 a 跳到状态b的概率。
这里有一个例子,将天气建模为马尔可夫链。

我们可以将从状态 a 到状态 b 的概率表示为矩阵分量,其中整个矩阵表征了我们的马尔可夫链过程,对应于有向图的邻接矩阵。

然后,如果我们将当前状态表示为一个独热编码,我们可以通过获取当前状态并查看其对应的行来获得下一个状态的值的条件概率。
之后,如果我们重复采样由第 n 个状态的行描述的离散分布,我们可以模拟一系列任意长度的状态。
文本生成的马尔可夫链
为了用马尔可夫链生成文本,我们需要定义一些东西:
- 我们的国家会是什么样的?
- 从一个状态跳到另一个状态的概率是多少?
我们可以为文本生成做一个基于字符的模型,其中我们将我们的状态定义为我们看到的最后 n 个字符,并尝试预测下一个字符。
我已经在我的用于文本生成的LSTM文章中对此进行了深入研究,结果喜忧参半。
在这个实验中,我将选择使用之前的 k 单词作为我的当前状态,并对下一个令牌的概率进行建模。
为了做到这一点,我将简单地为每一个由 k 个单词组成的不同序列创建一个向量,它有 N 个组成部分,其中 N 是我的语料库中不同单词的总数。
然后我会在第 i 个向量的第 j 个分量上加 1,其中 I 是第Ik 个单词序列的索引, j 是下一个单词的索引。
如果我归一化每个单词向量,那么我将有下一个单词的概率分布,给定前面的 k 记号。
迷惑?让我们看一个小语料库的例子。
训练我们的链条:玩具例子。
假设我的语料库是下面这句话。
This sentence has five words
我们将首先选择 k :在采样/ 预测下一个单词之前,我们的链将考虑的单词量。对于这个例子,让我们使用 k=1。
现在,我们的句子中有多少个不同的单词序列?它有 5 个,每个单词一个。如果它有重复的单词,他们不会添加到这个数字。
我们将首先初始化一个 5×5 的零矩阵。
之后,我们将在“this”行的“sentence”对应的列中加 1。然后在“句子”的行上加上 1,在“has”的列上加上 1。我们将继续这个过程,直到我们看完整个句子。
这将是生成的矩阵:

The diagonal pattern comes from the ordering of the words.
因为每个单词只出现一次,所以这个模型只是一遍又一遍地生成同一个句子,但是你可以看到添加更多的单词会使这个变得有趣。
我希望现在事情更清楚了。让我们跳到一些代码!
用 Python 编写我们的马尔可夫链
现在是有趣的部分!我们会在整个一首冰与火之歌文集上训练一个马尔可夫链(哈!你以为我会引用这部剧吗?太糟糕了,我是个爱看书的人!).
然后我们将为 k 生成不同值的句子。
在这个实验中,我决定将两个空格之间的任何内容都视为一个单词或标记。
按照惯例,在自然语言处理中,我们处理标点符号(如','或'.')作为令牌。为了解决这个问题,我将首先以两个空格的形式给每个标点符号添加填充。
下面是这个小预处理以及加载语料库的代码:
我们将立即开始训练我们的马尔可夫链,但首先让我们看看我们的数据集:
我们有超过 200 万个代币,代表超过 32000 个不同的单词!对于一个作家来说,这是一个相当大的语料库。
要是他能多加 80 万就好了……
训练我们的链条
继续,下面是我们如何为任意的 k (在本例中为 2)初始化我们的“k 序列后的单词”计数矩阵。
语料库中有 2185918 个单词,429582 个不同的 2 个单词的序列,每个序列后面都有 32663 个单词中的一个。
这意味着矩阵中只有 0.015%多一点的成分是非零的。
因此,我使用了 scipy 的 dok_matrix ( dok 代表键的字典),一个稀疏矩阵实现,因为我们知道这个数据集将非常稀疏。
在初始化我们的矩阵后,采样是非常直观的。
下面是代码:
这里有两件事可能引起了你的注意。第一个是 alpha 超参数。
这是我们的链的创造力:一个(通常很小,或零)的机会,它会选择一个完全随机的单词,而不是语料库建议的那些。
如果数字很高,那么下一个单词的分布将接近均匀。如果为零或更接近,那么分布将更接近语料库中看到的分布。
对于我将展示的所有示例,我使用了值为 0 的 alpha 。
第二件事是加权选择函数。我必须实现它,因为 Python 的随机包不支持超过 32 个元素的列表的加权选择,更不用说 32000 个元素了。
结果:生成的句子
首先,作为基线,我尝试了一种确定性的方法:如果我们选择一个单词,使用 k=1,并总是跳到当前单词之后最有可能的单词,会发生什么?
至少可以说,结果并不令人满意。
**I** am not have been a man , and the Wall . " " " "
**he** was a man , and the Wall . " " " " " " "
**she** had been a man , and the Wall . " " " " " "
因为我们是确定性的,“a”后面总是跟着“man”,“the”后面总是跟着“Wall”(呵呵)等等。
这意味着我们的句子会很无聊,可预测,而且有点荒谬。
现在对于一些实际的世代,我尝试使用一个词的随机马尔可夫链,α值为 0。
一词马尔可夫链结果
以下是一些由 15 个单词组成的句子,种子单词用粗体表示。
'**the** Seven in front of whitefish in a huge blazes burning flesh . I had been'
'**a** squire , slain , they thought . " He bathed in his head . The'
'**Bran** said Melisandre had been in fear I've done . " It must needs you will'
'**Melisandre** would have feared he'd squired for something else I put his place of Ser Meryn'
'**Daenerys** is dead cat - TOOTH , AT THE GREAT , Asha , which fills our'
'**Daenerys** Targaryen after Melara had worn rich grey sheep to encircle Stannis . " The deep'
正如你所看到的,产生的句子是非常荒谬的,尽管比前几个有趣得多。
每一对单词都有一定的意义,但整个序列完全没有意义。
这个模型确实学到了一些有趣的东西,比如丹妮莉丝后面通常跟着坦格利安,对于只知道前一个单词来说,“本该害怕”是一个很好的结构。
然而,总的来说,我认为这还远远没有达到它应有的水平。
当增加单词链的 alpha 值时,我得到的句子开始变得更加随机。
2 字马尔可夫链的结果
两个单词的链产生了一些更有趣的句子。
尽管它通常听起来完全随机,但它的大部分输出可能会在开始时愚弄你一会儿。
'**the world** . *And Ramsay loved the feel of grass* *welcomed them warmly* , the axehead flew'
'**Jon Snow** . *You are to strike at him* . *The bold ones have had no sense*'
'**Eddard Stark** had done his best to give her *the promise was broken* . By tradition the'
'**The game** of thrones , so you must tell her the next buyer who comes running ,'
'**The game** trail brought her messages , strange spices . *The Frey stronghold was not large enough*'
'**heard the** scream of fear . I want to undress properly . Shae was there , fettered'
句子保持了局部的连贯性(你要打击他,或者拉姆齐喜欢草的感觉),但随后将非常连贯的单词序列连接成一团乱麻。
任何句法、语法或语义的感觉都明显缺失。
顺便说一下,我根本没有挑选那些句子,这些是我采样的第一批输出。
随意自己玩代码,你可以在评论里分享你得到的最古怪的句子!
作为最后一个实验,让我们看看用三个词的马尔可夫链能得到什么。
三字链结果
以下是模型在用 3 个单词的序列进行训练时生成的一些句子。
'**I am a** master armorer , lords of Westeros , sawing out each bay and peninsula until the'
'**Jon Snow is** with the Night's Watch . I did not survive a broken hip , a leathern'
'**Jon Snow is** with the Hound in the woods . He won't do it . " Please don't'
'**Where are the** chains , and the Knight of Flowers to treat with you , Imp . "'
'**Those were the** same . Arianne demurred . " So the fishwives say , " It was Tyrion's'
'**He thought that** would be good or bad for their escape . If they can truly give us'
'**I thought that** she was like to remember a young crow he'd met briefly years before . "'
好吧,我真的很喜欢其中的一些,尤其是最后一个。这听起来有点像你能在书中找到的真实句子。
结论
实现马尔可夫链比听起来容易得多,在真实语料库上训练它很有趣。
坦白地说,结果比我预期的要好,尽管在 LSTM 的小失败后,我可能把标准定得太低了。
在未来,我可能会尝试用更长的链或完全不同的语料库来训练这个模型。
在这种情况下,尝试一个 5 个单词的链又有了基本确定的结果,因为每个 5 个单词的序列几乎总是唯一的,所以我不认为 5 个单词和以上的链是感兴趣的。
你认为哪个语料库会产生更有趣的结果,尤其是对于更长的链?请在评论中告诉我!
如果你想了解更多关于马尔可夫链的知识,可以考虑查看一下 这本深入的书 。那是一个代销商链接,也就是说我从中获得一小笔佣金。
原载于 2019 年 10 月 25 日http://www . data stuff . tech。
马尔科夫风险投资公司
利用马尔可夫链生成风险投资公司名称的探索
风险投资家在命名方面不是很有创意,所以我决定尝试使用马尔可夫链来生成一些名字。(我是帮手。)
首先,我尝试了数据科学中描述的普通马尔可夫链。基本上,我把我的投资者姓名数据集转化成一个配对列表。所以如果我们有:
Sequoia Capital
Union Square Ventures
GV (Google Ventures)
我们最终会得到:
('Sequoia', 'Capital')
('Union', 'Square')
('Square', 'Ventures')
('GV', '(Google')
('(Google', 'Ventures)')
然后我们根据第一个单词分组,找出所有可能的转换。例如,从我的未删节数据集:
'Sequoia': [
'Capital',
'Financial',
'National',
'Capital',
'Capital',
'Capital',
'Capital',
'Scout',
'Apps',
'Investment',
'Capital',
'Energy',
'Private',
'Capital',
'Capital',
'Apps',
'Capital',
'Capital',
'Capital',
'Capital'
]
当我等待循环突突地创建所有这些重复的列表时,我的眼睛开始抽搐。这可以做得更好。
不管怎样,现在您可以选择一个起始单词(比如“Benchmark”),然后从列表中随机选择一个与“Benchmark”配对的单词,以获得名称中的下一个可能的单词。然后在某个时候你切断了它。
这种方法的结果并非不切实际:
Adler & Jack W. Baird Capital # 5 words
Dongxing Capital Corp Equity # 4 words
Sage Hill Angels # 3 words
…但我认为我们可以做得更好。
改进算法
首先,我们随机选择第一个单词。由于大约 50%的风险投资家的名字中有“合伙人”、“资本”、“基金”或一些类似的样板词,很可能我们会以第一个词“LLC”或其他什么结束。因此,我们应该有一些“开始词”的概念,所以我们将来只从那个集合中选择。
同样困扰我的是,我必须明确地说出我希望名字有多长:当你到了“LP”的时候,你可以很确定这个名字已经结束了。因此,让我们添加一个“停用词”的概念。
最后,大部分代码和时间都花在了将
修改后的配对生成看起来像:
import networkx as nxgraph = nx.DiGraph()
START_WORD = '---START---'
STOP_WORD = '---STOP---'def AddPair(start, stop):
"""Add an edge to the graph (or increment the weight of an existing edge)."""
if start in graph and stop in graph[start]:
graph[start][stop]['weight'] = graph[start][stop]['weight'] + 1.0
else:
graph.add_edge(start, stop, weight=1.0)def AddName(name):
words = name.split(' ')
AddPair(START_WORD, words[0])
for i in range(0, len(words)-1):
AddPair(words[i], words[i+1])
AddPair(words[-1], STOP_WORD)investors.name.apply(AddName)
…这只需要运行时间的一小部分。另一个好处是你可以生成漂亮的图表:

嗯,有点漂亮。
现在我们可以从START_WORD开始,随机选择一条路径,直到到达STOP_WORD:
def GenerateVc():
name = []
current_word = ChooseNext(START_WORD)
while current_word != STOP_WORD:
name.append(current_word)
current_word = ChooseNext(current_word)
return ' '.join(name)
ChooseNext会取一个词,根据边权重随机选择。numpy有一个很好的np.random.choice方法,它采用一个概率数组,但是这些概率的总和必须是 1。首先,我要遍历所有的边,缩小权重,作为概率。
def NormalizeWeights():
for start in graph:
total_weight = graph.out_degree(start, weight='weight')
for stop in graph.successors(start):
graph[start][stop]['weight'] = graph[start][stop]['weight'] / total_weight
然后使用这些权重实现ChooseNext:
def ChooseNext(word):
next_words = list(graph.successors(word))
weights = [graph[word][n]['weight'] for n in next_words]
return np.random.choice(next_words, p=weights)
然后我们可以调用GenerateVc来创建一个不错的 VC 名称数组:
for i in range(0, 20):
print(GenerateVc())# Produces:
Cream City Digital Farm Ventures LLC
INESA Venture Fund LLC
Koms Co. Ltd.
Startup Lab
Japan Securities Investment Management Co. Ltd.
Novestra
Desert Sky Venture Capital Partners Co Ltd
Vuzix
Warren Citrin Impact Partners
Advantage Capital Partners
Genesis Campus, a Day
Denota Ventures LLC
Main Street Capital
Dry Canyon Creek Capital
Cenes Immo
Sheffield University of Iowa Capital Partners
Hamilton Portfolio Ltd.
CSC
Brocade Communications
BPL Global Health & Associates
听起来差不多。
大规模枪击和恐怖主义
我们对小概率和罕见事件的痴迷

我上个月在我父亲的忌日前后开始考虑这篇文章。即使是圣诞节,节日前后的几个星期也总是有些阴郁。死亡和死亡的想法与我的孩子们对圣诞老人的到来和新年的欢迎的天真兴奋交织在一起。我父亲于 2001 年去世,就在 911 事件后几个月。在与胃肠癌短暂斗争后,他去世了。在他的治疗过程中,我们有机会思考恐怖分子是如何改变世界的。
我没有理解这个悖论。我和我父亲认为,美国面临的最大威胁已经显现。但是,当时我也坚信他的癌症是个异数。也许这要归咎于他年轻时的暴露;反常的事情。多年以后,我开始意识到我的想法是多么简单。比起死于恐怖袭击,我更有可能与癌症抗争。
我现在明白了暴力,就像恐怖主义和大规模枪击事件一样,在我们的生活中扮演了一个很小的角色。我在经历了我应得的那份死亡后发表了这个声明。在过去的 16 年里,我一直是美国陆军的一名士兵,我可以证明,在 2:1 的比例下,战斗并不是军人葬礼的主要原因。
事实上,上周末我刚刚参加了另一场非战斗军事葬礼。自杀、摩托车事故、车祸、癌症和心脏病比巡逻队从地球上夺走了更多的朋友。这显然不会是每个士兵的经历,但对大多数人来说是这样的,而且与数据一致。
事实是,你可能不会死于大规模枪击或恐怖事件。它们是极其罕见的事件。你可能以前被告知过这一点,但这与此类事件获得的新闻报道和政治关注形成了鲜明的对比。在过去的半个世纪里,美国人口中受害者的平均数量接近下面列出的数值。
+ — — — — — — — — + — — — — — — — — — - — — — — — — +
| Incident Type | Avg Annual Victims |
+ — — — — — — — — + — — — — — — — — — - — — — — — — +
| Mass Shootings | 2.5 per 10 mil in population |
| Terrorism | 18.8 per 10 mil in population |
+ — — — — — — — — + — — — — — — — — — - — — — — — — +
我们关注这些事件有很多原因。也许是因为它们非常适合政治叙事。或者,也许暴力是我们祖先最关心的问题,而我们的生物线路没有文明变化得那么快。
然而,有基于数据的理由来证明罕见事件的困扰。它们(罕见事件)可能是更大事件的前兆。有时草丛中无法解释的运动是一只狮子。也许偶尔发生的涉及枪支和恐怖主义的事件是流行病迅速蔓延的征兆,而不仅仅是偶发的社会背景噪音。从数据科学的角度来看,此类事件的影响是非线性的。简单来说,这些事件是指数级恶化还是频率快速增加?
我几乎总是发现忽视人类的直觉是一个错误。通常,人们持有特定的信仰是有充分理由的。在大规模枪击和恐怖主义的情况下,数据的一些特征可能解释了我们的痴迷。看看美国,这是每起事故中受害者总数的视图。

这些事件类型中的每一种都有一个故事要讲述。通常对于离散的罕见事件,使用泊松过程进行建模和预测。这就是,例如,T2,地震通常是如何被理解的。然而,泊松过程具有稳定的到达间隔时间(事件之间的平均时间)的无记忆假设。可视化统计到达间隔时间显示大规模枪击事件变得越来越常见(目前与恐怖主义一样常见),从 80 年代开始频率急剧增加。

令人欣慰的是,大规模枪击事件的平均受害者总数逐年稳定。另一方面,恐怖主义在到达间隔方面是稳定的,但在每次事件的受害者总数方面有很大的变化。观察这两种罕见事件之间差异的另一种方法是比较事件之间的平均时间与死亡人数。

大规模枪击事件的死亡人数似乎被限制在 100 人左右,而不管事件之间的时间间隔。然而,在恐怖主义问题上,引人注目的局外人讲述了一个不同的故事。趋势线(不可否认是粗略的)表明,事件之间的时间间隔越长,可能的死亡人数就越多。事实上,死亡人数呈非线性增长。因此,举例来说,每增加 10 年的平均间隔时间,死亡人数就会增加 10 倍。
从这个角度来看,一个真正大规模的恐怖主义事件,杀死 10 万到 100 万人,不仅是可能的,而且是可能的。根据这个基本模型的极端界限,我们可以预期这样的事件每 50-100 年发生一次。
这些类型的罕见事件趋势可以被我们的心理所识别,甚至在我们有意识地意识到它之前。大规模枪击事件的频率正在加快,低影响力恐怖主义是一个更大事件的指标。这两个问题都在我们的脑海中,因为我们的直觉告诉我们要注意,数据也是如此。
用于创建本文的所有数据和代码都可以在这个 MatrixDS 项目中找到。
通过解决黑客马拉松问题掌握机器学习的基础知识
了解如何一步一步解决回归问题,并在黑客马拉松排行榜中获得体面的排名
黑客马拉松是在短时间内学习和实现新概念的好方法。今天,我们将讨论机器学习的基本步骤,以及如何在试图使用 MachineHack 黑客马拉松的数据集获得体面排名的同时,获得回归问题的良好准确性。
解决任何机器学习问题的基本步骤是
- 识别目标和独立特征
- 清理数据集
- 特征工程
- 特征编码和缩放
- 功能选择
- 检查目标变量的分布
- 从图表中获得微调特性的洞察力
- 模型应用和超参数整定
- 组合不同的模型
唷…要涵盖很多步骤,初学者很容易被吓倒…所以让我们深入这个问题,一步一步来…
您可以通过在 MachineHack 网站上创建帐户来下载数据集,并通过注册以下黑客马拉松来下载数据集:- 机票价格预测
现在,您从黑客马拉松获得的 zip 文件中提供了 3 个文件:-

Files provided in the dataset: 1)Data_train.xlsx 2)Sample_submission 3)Test_set
这里的Data_Train.xlsx包含我们需要用来训练模型的数据集,Sample_submission顾名思义指定了在黑客马拉松中需要提交的输出的格式,Test_set是我们需要应用我们的模型来预测机票价格的数据集,我们在黑客马拉松中的分数将基于该数据集进行评估。
现在,我们需要记住的一件事是,无论我们将对Data_Train数据集特征应用何种转换,都需要对Test_set数据集应用相同的转换,以便模型从两者获得相似类型的输入。
接下来,从 GitHub 资源库下载 juptyer 笔记本,该资源库详细介绍了上述所有步骤:
好吧,如果你已经走到这一步,这意味着你对学习新事物是认真的,那么在另一个标签中开始一些好听的音乐,进入 区 让我们开始吧…
1.识别目标和独立特征
解决任何机器学习问题的第一步是识别源变量(自变量)和目标变量(因变量)。
在机器学习环境中,目标变量是应该输出的变量。例如,如果进行分类,它可以是二进制 0 或 1;如果进行回归,它可以是连续变量。
独立变量(也称为特征)是被分析过程的输入。
我们在官方网站上获得了关于数据集的以下信息:-
训练集的大小:10683 条记录
测试集大小:2671 条记录
特性 :
航空公司:航空公司的名称。
旅行日期:旅行的日期
Source:服务开始的来源。
目的地:服务结束的目的地。
路线:航班到达目的地所采用的路线。
Dep_Time:旅程从源头开始的时间。
到达时间:到达目的地的时间。
持续时间:飞行的总持续时间。
Total_Stops:出发地和目的地之间的总停靠站数。
Additional_Info:关于航班的附加信息
价格:门票的价格
让我们使用pd.read_excel命令在 jupyter 笔记本中导入数据集。你可以在这里找到关于在熊猫中导入各种文件的信息。
让我们在 pandas 中使用df.head()命令来了解数据集中的列。请记住,我已经将我们用来训练模型的数据集的名称保留为df_train

df.head() is used to print first 5 rows of the dataset
在这里,我们可以看到价格列是目标变量,因为它有连续的值,也就是说,它不能被分类到特定的类别,这个问题是一个监督回归问题。
2。清理数据集:
首先,让我们使用df.isnull()命令检查数据集中缺失值的数量:-
Check null values
由于我们的数据集中只有一个空值,我只是简单地删除它,因为试图估算一个值似乎不是一个好的选择。
但是请记住,一般的经验法则是,如果任何特定列中超过 30%的值丢失,那么我们可以排除该列。
在 pandas 中,通过运行下面的命令很容易删除空值:-
此处inplace参数用于隐式执行操作,即将操作直接应用于指定的数据帧。
接下来,我们应该检查我们的数据集是否有任何重复的行并删除它们:-
df.duplicated()用于查找数据帧中重复条目的总数。
Check duplicate rows
接下来,我们需要通过运行以下命令删除重复的条目:-
#remove duplicate rows in training dataset
df_train.drop_duplicates(keep='first',inplace=True)
在上面的drop_duplicates命令中,keep='first'选项允许我们保留第一次出现的行值,同时删除所有后续出现的行值。
现在,您还可以只通过在这一步查看数据集来删除不必要的列。在当前的数据集中,没有这样的列,所以我们可以继续。
如果您观察笔记本的 数据清理 部分中采取的步骤,我们已经合并了Additional_Info列中的重复值,并重命名了 Total_Stops 列中的值。
- 特征工程:-
特征工程是使用问题的领域知识和一点常识来创建新特征的过程,这些新特征可以增加机器学习模型的预测能力。这一步确实需要相当多的想象力,对输入特性的批判性思考,以及运用你的创造性。
Date_of_Journey列本身并不十分有用,但我们可以从中创建新的功能,如航班是否在周末、星期几和月份。
Feature engineering
惊叹声...这看起来像是一段很难理解的复杂代码…相信我,这不是我一个人想出来的,可能永远也不会。但这就是 StackOverflow 前来救援的地方。你可以从下面的链接中进一步阅读代码,因为这将有助于你
a)理解在 python 中完成相同任务的各种方式
b)以防明天这段代码变得多余或对你不起作用,猜猜哪个网站会帮助你找到解决方案😉
链接:-
查看熊猫的某一天是否是周末
从熊猫的日期时间变量中获取年、月和日
然后,我们将持续时间列的值转换为分钟:-
Feature engineering on duration column
如果您看一下Duration列,值的格式类似于2h 50m,一些行只包含小时值,而一些行只包含分钟值(就像某人如何享受不到一小时就结束的飞行,但这是改天讨论的问题)
所以在上面的代码中,最初的 for 循环将小时和分钟部分分开,而第二个 for 循环用于将持续时间转换为分钟。
我甚至试着转换成秒来提高准确度,但是请不要遵循这些愚蠢的步骤,除非你有大量的空闲时间,并且一心想要提高排行榜上的排名👻
接下来,我们创建了一个名为Duration_minutes的新列,并从 dataframe 中删除了原来的Duration列。
我也在 Arrival_Time 列执行了类似的步骤,您可以在笔记本中跟进。
- 特征编码和缩放:-
我们通常对独立的输入变量进行特征缩放和编码,因此让我们在数据帧中将目标变量和输入变量彼此分开。
Split the dataset
这里X包含输入特征的数据框,而y是我们的目标变量。我将在下一节介绍对y应用对数转换的原因。现在,让我们关注我们的输入变量 dataframe,即X
第一步是将输入变量分为分类变量和数字变量。
分类变量包含有限数量的类别或不同的组。分类数据可能没有逻辑顺序。例如,分类预测包括性别、材料类型和支付方式。
数值变量顾名思义包含连续或离散的数值。
我们可以使用df.select_dtypes()方法进行拆分:-
select_dtypes is used to separate numerical and categorical features
在分类特征的情况下,我们可以应用标签编码或一个热编码。
您可以在这里进一步了解这两种技术:
在当前数据集中,我们已经对分类要素进行了标注编码。
Label encoding variables
对于数字特征,我们可以执行不同类型的缩放,如最小最大、标准缩放器或 BoxCox 变换。
我尝试了各种标准缩放、最小-最大缩放和数字的 boxcox 变换。最终,boxcox 变换给出了最好的准确度分数。
Boxcox transformation
Box-Cox 变换是一系列幂变换函数,用于稳定方差并使数据集看起来更像正态分布。关于 box-cox 变换的解释可以在这里找到。
lam变量指定要应用的转换类型:-
- λ=-1。是一种互易变换。
- λ=-0.5 是倒数平方根变换。
- λ= 0.0 是对数变换。
- λ= 0.5 是平方根变换。
- λ= 1.0 就是没有变换。
完成上述转换后,我们将分类和数字特征连接起来,得到一组转换后的输入变量。
- 功能选择 :-
我们可以应用基于树的回归模型,如随机森林回归器、额外树和 xgboost,来获得特性的重要性。
例如,RandomForestRegressor 模型可应用于数据集,如下所示
Random Forest
我们首先使用train_test_split方法将数据集分成训练和测试样本。test_size参数指定了训练和测试数据的比例。值为 0.3(即 30%)会将数据分为 70:30 的训练数据和测试数据。然后,我们定义了 RandomForestRegressor 模型,并将其应用于训练样本(X_train,y_train)。
然后对测试输入样本(X_test)进行预测,并与原始目标样本(y_test)进行比较,得到各种精度指标。我将在本文的后续部分讨论准确性度量。
现在,让我们使用下面的函数来看看模型预测的特征重要性:-
Feature Importances
在上面的函数中,我们根据模型提供的特征重要性,按照重要性降序创建了一个新的数据框架。
然后,我们使用 matplotlib 库创建一个水平条形图,以直观地查看特性的重要性。
在随机森林回归的情况下,函数的输出为:-

Feature Importances
正如我们所看到的,持续时间列具有最高的重要性,而航班始发的来源城市具有最低的特征重要性。
我们可以从上面生成的图表中手动选择特性,也可以使用sklearn中的SelectFromModel模块自动选择最合适的特性。
我尝试根据上述功能的重要性在选定的功能上运行该模型,但准确性略有下降,如果我们在现实世界中部署该模型,这可能会很好,因为该模型现在有点更健壮,但对于黑客马拉松来说,准确性最重要,所以我最终保留了所有功能。
- 检查目标变量的分布:-
我们应该使用分布图来检查回归问题中目标变量的分布。如果它是偏斜的,那么对数、指数或 sqrt 变换的应用可以帮助减少偏斜以获得正态分布。
在我们的例子中,目标变量的分布最初有点向右倾斜

应用对数变换后,它呈正态分布:-

Normalized distribution
最后,对数转换确实提高了模型的整体准确性,这也是我在上面第 4 步开始时对目标输入应用对数转换的原因。
- 从图表中获得洞察力:-
检查目标列相对于输入变量的变化以及各种输入变量的分布:-

Scatter plot
价格应该随着持续时间的增加而增加,但这里的情况并非如此。
接下来,我们检查价格相对于停靠点总数的变化:-

Total stops vs Price
从上图中可以看出:-
正如所料,经停次数越多,机票价格越高
数字特征的分布可以使用直方图来检查,而分类特征的分布可以使用条形图或箱线图来检查。
在分类特征的情况下,检查是否有任何列值可以组合在一起,而在数字特征的情况下,检查分布是否可以归一化,即均匀分布。

Airlines frequency bar plot
后来,我回到分类特征,把最后四个航空公司分类组合在一起。
对Additional_Info列执行类似的步骤:-

Additional Info frequency bar plot
您可以在 jupyter 笔记本中找到数值特征的直方图,并根据需要进行必要的转换。

- 模型应用和超参数调整:-
在尝试了不同类型的回归模型后,我发现 ExtraTrees、RandomForest 和 XGboost 比其他模型的精度略高,因此是时候对所有 3 个模型进行超参数调整以进一步提高精度了。
在机器学习中,超参数是在学习过程开始之前设置其值的参数。我们需要得出超参数的最佳值,因为这些值在模型之外,并且它们的值不能从数据中估计。
超参数调整是为学习算法选择一组最佳超参数的过程。进行超参数调优的两种常见方法是 GridSearchCV 和 RandomisedSearchCV。
虽然 GridSearchCV 是详尽的,但 RandomisedSearchCV 有助于快速获得一系列相关值。更多关于他们的信息可以在这里找到。
Randomized Search CV
在 RandomForest 算法的例子中,下面这篇来自《走向数据科学》的文章有助于我们理解如何正确地进行超参数调优:- 文章链接
类似的方法可以应用于 ExtraTrees 和 XGBoost 回归模型。
- 组合不同型号
堆叠是一种集成学习技术,其中我们可以通过元分类器或元回归器来组合多个回归模型。基于完整的训练集来训练基础级模型,然后基于基础级模型的输出作为输入特征来训练元模型。
在最后一步中,我使用叠加技术将上述三个模型结合起来,以提高整体准确性
Stacked model
这里使用的基本模型是 ExtraTrees、Random Forest 和 XGBoost 回归器,而使用的元模型是 Lasso。你可以在这里了解更多关于如何实现堆栈的信息。
接下来,我们拟合堆叠模型,并对测试数据样本进行预测
Fit the model
接下来,我创建了一个简单的函数来打印回归模型中所有可用的准确性指标
Print accuracy report
一旦我们训练了堆叠模型,我们只需将模型应用于预测数据集,并将值提交给 hackathon 网站,这就完成了解决机器学习问题所需的所有基本步骤。
堆叠模型的最终指标是:-
R - 平方在 0-1 范围内测量模型和因变量之间的关系强度。关于其他指标的信息可以在这里找到。
希望在完成上述所有步骤后,你至少对如何处理有监督的机器学习问题有了一点了解。如果你有任何疑问、建议或更正,请在评论区提出来,如果你喜欢这篇文章,请与他人分享,以示欣赏。
最后但并非最不愉快的编码🤓





浙公网安备 33010602011771号