TowardsDataScience-博客中文翻译-2020-三十四-

TowardsDataScience 博客中文翻译 2020(三十四)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

交叉熵损失函数

原文:https://towardsdatascience.com/cross-entropy-loss-function-f38c4ec8643e?source=collection_archive---------0-----------------------

法托斯 BytyqiUnsplash 上的照片

当处理机器学习或深度学习问题时,损失/成本函数用于在训练期间优化模型。目标几乎总是最小化损失函数。损失越低,模型越好。交叉熵损失是最重要的代价函数。它用于优化分类模型。交叉熵的理解依赖于对 Softmax 激活函数的理解。我在下面放了另一篇文章来讨论这个先决条件

[## Softmax 激活功能——实际工作原理

Softmax 是放置在深度学习网络末端的函数,用于将 logits 转换为分类概率。

towardsdatascience.com](/softmax-activation-function-how-it-actually-works-d292d335bd78)

考虑一个4级分类任务,其中图像被分类为狗、猫、马或猎豹。

输入图片来源:Victor Grabarczyk 在 Unsplash 上拍摄的照片。作者图解。

在上图中,Softmax 将 logits 转换为概率。交叉熵的目的是获取输出概率(P)并测量与真值的距离(如下图所示)。

交叉熵(L)(来源:作者)。

对于上面的例子,对于类别dog的期望输出是[1,0,0,0],但是模型输出是[0.775, 0.116, 0.039, 0.070]

目标是使模型输出尽可能接近期望的输出(真值)。在模型训练期间,模型权重被相应地迭代调整,目的是最小化交叉熵损失。调整权重的过程就是定义模型训练的过程,随着模型不断训练并且损失最小化,我们说模型正在学习

交叉熵的概念可以追溯到信息论领域,克劳德·香农在 1948 年引入了熵的概念。在深入交叉熵代价函数之前,让我们先介绍一下熵。

随机变量 X 的熵是该变量可能结果中固有的不确定性水平。

对于p(x)——概率分布和随机变量 X,熵定义如下

等式 1:熵的定义。注对数以 2 为基数计算。

负号原因: log(p(x))<0(0,1)中的所有p(x)。p(x)是一个概率分布,因此值必须在 0 和 1 之间。

log(x)的图。对于 0 到 1 之间的 x 值,log(x) <0 (is negative). (Source: Author).

The greater the value of entropy, 【 , the greater the uncertainty for probability distribution and the smaller the value the less the uncertainty.

示例

考虑以下三种形状的“容器”:三角形和圆形

3 个三角形和圆形容器。(来源:作者)。

容器 1: 拣出三角形的概率是 26/30,拣出圆形的概率是 4/30。由于这个原因,选择一种形状和/或不选择另一种形状的概率更确定。

容器 2: 选择三角形的概率为 14/30,否则为 16/30。几乎有 50–50%的机会选择任何特定的形状。选择给定形状的确定性比 1 中的低。

容器 3: 从容器 3 中选取的形状极有可能是圆形。选择圆形的概率是 29/30,选择三角形的概率是 1/30。很有可能选择的形状是圆形。

让我们计算熵,这样我们就能确定我们的断言,即选择一个给定的形状是确定的。

正如所料,第一个和第三个容器的熵小于第二个容器。这是因为在容器 1 和 3 中选择给定形状的概率比在容器 2 中更确定。我们现在可以继续讨论交叉熵损失函数。

交叉熵损失函数

又称对数损失对数损失逻辑损失。将每个预测类别概率与实际类别期望输出 0 或 1 进行比较,并计算得分/损失,该得分/损失基于该概率与实际期望值的差距来惩罚该概率。惩罚本质上是对数的,对于接近 1 的大差异产生大的分数,对于趋向于 0 的小差异产生小的分数。

当在训练期间调整模型权重时,使用交叉熵损失。目标是最小化损失,即损失越小,模型越好。完美模型的交叉熵损失为 0。

交叉熵被定义为

等式 2:交叉熵的数学定义。请注意,对数是以 2 为基数计算的,与 ln()相同。

二元交叉熵损失

对于二进制分类(具有两个类别 0 和 1 的分类任务),我们将二进制交叉熵定义为

等式 3:数学二元交叉熵。

二进制交叉熵通常被计算为所有数据示例的平均交叉熵,即,

等式 4

例子

考虑具有以下软最大概率(S)和标签(T)的分类问题。目标是在给定这些信息的情况下计算交叉熵损失。

Logits)和具有分类交叉熵损失函数的一键编码真值标签(T ),用于测量预测概率和真值标签之间的“距离”。(来源:作者)

分类交叉熵的计算如下

Softmax 是连续可微函数。这使得计算损失函数相对于神经网络中每个权重的导数成为可能。该属性允许模型相应地调整权重以最小化损失函数(模型输出接近真实值)。

假设在模型训练的一些迭代之后,模型输出以下逻辑向量

0.095小于前次损失,即0.3677暗示模型正在学习。优化过程(调整权重以使输出接近真实值)一直持续到训练结束。

Keras 提供了以下交叉熵损失函数:二元、分类、稀疏分类交叉熵损失函数。

范畴交叉熵和稀疏范畴交叉熵

类别交叉熵和稀疏类别交叉熵都具有等式 2 中定义的相同损失函数。两者之间唯一的区别是如何定义真理标签。

  • 当真实标签被一热编码时,使用分类交叉熵,例如,我们对于 3 类分类问题[1,0,0][0,1,0][0,0,1].具有以下真实值
  • 在稀疏分类交叉熵中,真值标签是整数编码的,例如,3 类问题的[1][2][3]

我希望这篇文章能帮助你更清楚地理解交叉熵损失函数。

[## Softmax 激活功能——实际工作原理

Softmax 是放置在深度学习网络末端的函数,用于将 logits 转换为分类概率。

towardsdatascience.com](/softmax-activation-function-how-it-actually-works-d292d335bd78)

感谢阅读:-)

强化学习的交叉熵方法

原文:https://towardsdatascience.com/cross-entropy-method-for-reinforcement-learning-2b6de2a4f3a0?source=collection_archive---------7-----------------------

Unsplash 上由 Franck V. 拍摄的照片

如果你曾经鼓起勇气探索强化学习领域,很有可能你会发现自己迷失在花哨的词汇中。大词,复杂算法的名字,背后有更复杂的数学。但是,如果有更简单、更直观、效率更高的算法能够很好地工作呢?

来看看交叉熵方法:一种用于参数化政策优化的进化算法,John Schulman 声称这种算法在复杂的 RL 问题上“令人尴尬地好”。

什么是交叉熵方法?

从生物学的角度来看,这是一种 T4 进化算法。一些个体是从群体中抽样出来的,只有最优秀的个体才能决定后代的特征。

在数学上,它可以被视为一种无导数优化 (DFO)技术,即,它可以在没有计算导数的开销的情况下找到最优解(无反向传播!).

这种方法是如何工作的?

假设您不知道什么是代理、环境和策略。你只是得到了一个“黑匣子”,它接受一些数字作为输入,输出一些其他的数字。您只能选择输入值并观察输出。如何猜测输入,使输出成为您想要的值?

一种简单的方法是获取一组输入,观察产生的输出,选择产生最佳输出的输入,并对其进行调整,直到您对看到的输出满意为止。这本质上就是交叉熵方法所做的。

那么,我该如何用它来解决我的 RL 问题呢?

让我们通过一个例子来逐步理解 CEM 的工作原理。为了更好地理解实现,我在每个步骤中都添加了一些 python 代码片段。代码大量借用了 Udacity 关于深度强化学习的课程(惊人的 python RL 资源 btw,本文末尾 Github 链接)。

考虑你的政策网络。你想要找到最佳的权重,它可以基于你的代理的状态采取正确的“有意义的”行动。用于找到这些权重的基于 CEM 的方法如下:

第一步:从随机分布中抽取一串初始权重。尽管通常选择高斯分布,但您可以选择您认为权重来自的任何分布。假设我从具有均值 μ 和方差 σ 的高斯分布中抽取了 10 个权重候选值 w1w2 、…、 w10

考虑μ=0,σ=1,n_weights=10(候选数),weights_dim 表示权重向量的维数。

mean = 0.0       
std = 1.0
n_weights = 10weights_pop = [mean + std*np.random.randn(weights_dim) for i_weight in range(n_weights)]

步骤 2: 现在让代理根据这些权重从策略网络中选择行动,让代理运行一集并收集环境生成的奖励。对于我们的例子,比如说 w1 产生一个累积奖励 r1w2 产生 r2 等等。

用于代理的评估方法将权重候选作为输入,播放一集并输出来自该集的累积奖励。

rewards = [agent.evaluate(weights) for weights in weights_pop]

第三步:找出产生最佳回报的权重。假设最佳的 4 种重量是 w1w2w5w6 (也称为“精英”重量)。这里 4 是我们选择的一个数字。一般来说,你考虑最好的 n 权重,其中 n 由你选择。

n_elite = 4
elite_idxs = np.array(rewards).argsort()[-n_elite:]
elite_weights = [weights_pop[idx] for idx in elite_idxs]

步骤 4:精英权重定义的分布中选择新权重。说 μ' 是最佳权重的平均值( w1w2w5w6)σ'是它们的方差。我们现在从具有平均值μ’和方差σ’的高斯分布中抽取 10 名候选人。

mean = np.array(elite_weights).mean()
std = np.array(elite_weights).std()weights_pop = [mean + std*np.random.randn(weights_dim) for i_weight in range(n_weights)]

第五步:重复第二步到第四步,直到你对得到的奖励感到满意。

如果你不喜欢 python 代码,而你喜欢用数学术语阅读算法,这里有一些伪代码:

鸣谢:约翰·舒尔曼关于深度强化学习的 MLSS 2016

结论

交叉熵方法是一种简单的算法,可以用来训练 RL 代理。在包括 Tetris⁴.游戏在内的著名任务上,该方法已经胜过了几种 RL 技术在转向更复杂的 RL 算法(如 PPO、A3C 等)之前,您可以将此作为基线。CEM 有几种变体,但是,本文中定义的结构是所有变体的主干。

这篇关于交叉熵强化学习方法的文章到此结束。我希望您喜欢您刚刚阅读的内容,并感谢您的宝贵时间。

参考

[1]https://github . com/uda city/deep-reinforcement-learning/tree/master/cross-entropy

[2] MLSS 2016 关于深度强化学习由约翰·舒尔曼(https://www.youtube.com/watch?v=aUrX-rP_ss4)

[3]http://karpathy.github.io/2016/05/31/rl/

[4] I. Szita 和 A. Lorincz,用有噪声的交叉熵方法学习俄罗斯方块 (2006),神经计算

交叉熵方法性能分析

原文:https://towardsdatascience.com/cross-entropy-method-performance-analysis-161a5faef5fc?source=collection_archive---------37-----------------------

深度强化学习讲解— 07

交叉熵训练循环的实现

在这篇文章中,我们将详细描述交叉熵方法的训练循环,这是我们在上一篇文章中跳过的,同时看看我们如何在考虑更复杂的神经网络的情况下改进代理的学习。此外,我们将介绍该方法的改进变体,它为训练过程的多次迭代保留“精英”片段。最后,我们将展示交叉熵方法激励其他方法的局限性。

1.训练循环概述

接下来,我们将详细介绍构成我们在上一篇文章中介绍的训练循环的代码。

本帖的 完整代码可以在 GitHub 上找到,使用此链接 可以作为 Colab 谷歌笔记本运行。

主要变量

代码从定义方法的主要参数开始。

BATCH_SIZE = 100
GAMMA = 0.9PERCENTILE = 30
REWARD_GOAL = 0.8

助手类

我们建议使用两个助手类来简化代码的可解释性:

from collections import namedtupleEpisode = namedtuple(‘Episode’, field_names=[‘reward’, ‘steps’])EpisodeStep = namedtuple(‘EpisodeStep’, 
                          field_names=[‘observation’, ‘action’])

这里我们将定义两个助手类,它们被命名为标准库中的collections包中的元组:

  • EpisodeStep:这将用来表示我们的代理在剧集中做的一个单独的步骤,它存储了从环境中观察到的状态以及代理完成了什么动作。奖励没有被记录,因为它总是0.0,除了最后一个过渡。请记住,我们将使用“精英”剧集中的剧集步骤作为训练数据。
  • Episode:这是储存了总折扣奖励和 EpisodeStep 集合的单集。

变量的初始化

此时,我们将在训练循环中使用的一组变量被初始化。我们将按照循环中的要求逐一介绍:

iter_no = 0reward_mean = 0full_batch = []
batch = []episode_steps = []
episode_reward = 0.0state = env.reset()

训练循环

我们在上一篇文章中了解到,实现交叉熵算法的代理的训练循环重复 4 个主要步骤,直到我们对结果满意为止:

1 —播放 N 集数

2-计算每集的预期回报,并确定回报界限

3-丢弃所有回报低于界限的剧集。

4-使用“精英”剧集中的剧集步骤训练神经网络

我们已经决定,代理必须接受培训,直到达到一定的奖励阈值。具体来说,我们决定了一个 80%的阈值,如变量REWARD_GOAL所示:

while reward_mean < REWARD_GOAL:

步骤 1-播放 N 集

下一段代码是生成包含剧集的批处理的代码:

action = select_action(state)
next_state, reward, episode_is_done, _ = env.step(action)episode_steps.append(EpisodeStep(observation=state,action=action))episode_reward += rewardif episode_is_done: # Episode finished
    batch.append(Episode(reward=episode_reward,
                         steps=episode_steps))
    next_state = env.reset()
    episode_steps = []
    episode_reward = 0.0 <STEP 2> <STEP 3> <STEP 4>state = next_state

我们将使用的主要变量是:

  • batch累积Episode实例的列表(BATCH_SIZE=100)。
  • episode_steps累积当前剧集中的步骤列表。
  • episode_reward为当前剧集维护一个奖励计数器(在我们的例子中,我们只在剧集的结尾有奖励,但是该算法是针对更一般的情况描述的,其中我们不仅可以在最后一步有奖励)。

情节步骤列表增加了(观察、行动)对。值得注意的是,我们保存了用于选择动作的观察结果state(而不是作为动作结果由环境返回的观察结果next_state):

episode_steps.append(EpisodeStep(observation=state,action=action))

奖励将添加到当前剧集的总奖励中:

episode_reward += reward

当当前剧集结束时(洞或目标状态),我们需要将最终完成的剧集添加到批处理中,保存我们已采取的总奖励和步骤。然后,我们重置环境以重新开始,我们重置变量episode_stepsepisode_reward以开始跟踪下一集:

batch.append(Episode(reward=episode_reward, steps=episode_steps))next_obs = env.reset()
episode_steps = []
episode_reward = 0.0

第二步——计算每集的回报,并确定回报界限

下一段代码实现了步骤 2:

if len(batch) == BATCH_SIZE:
    reward_mean = float(np.mean(list(map(lambda s: 
                  s.reward, batch))))
    elite_candidates= batch
    ExpectedReturn = list(map(lambda s: s.reward * (GAMMA **          
                     len(s.steps)), elite_candidates))
    reward_bound = np.percentile(ExpectedReturn, PERCENTILE)

当运行了等于BATCH_SIZE的播放次数时,训练循环执行该步骤:

if len(batch) == BATCH_SIZE:

首先,代码计算当前批次中所有剧集的预期回报:

elite_candidates= batch
ExpectedReturn = list(map(lambda s: s.reward * (GAMMA **          
                 len(s.steps)), elite_candidates))

在此步骤中,根据给定的剧集批次和百分点值,我们计算边界奖励,该奖励将用于过滤“精英”剧集以训练代理神经网络:

reward_bound = np.percentile(ExpectedReturn, PERCENTILE)

为了获得边界奖励,我们将使用 NumPy 的 percentile 函数,该函数从值列表和所需的百分位数中计算百分位数的值。在这段代码中,我们将使用前 30%的剧集(由变量PERCENTILE表示)来创建“精英”剧集。

在此步骤中,我们计算用于决定何时结束训练循环的reward_mean:

reward_mean = float(np.mean(list(map(lambda s: s.reward, batch))))

第三步——扔掉所有回报低于界限的剧集

接下来,我们将使用以下代码过滤掉我们的剧集:

train_obs = []
train_act = []
elite_batch = []for example, discounted_reward in zip(elite_candidates, 
                                      ExpectedReturn):
    if discounted_reward > reward_bound:
       train_obs.extend(map(lambda step: step.observation, 
                            example.steps))
       train_act.extend(map(lambda step: step.action, 
                            example.steps))
       elite_batch.append(example)full_batch=elite_batch
state=train_obs
acts=train_act

对于批次中的每一集:

for example, discounted_reward in zip(elite_candidates,
                                      ExpectedReturn):

我们将检查这一集的总回报是否高于我们的界限:

if discounted_reward > reward_bound:

如果有,我们将填充我们将训练的观察状态和动作的列表,并跟踪精华片段:

train_obs.extend(map(lambda step: step.observation,example.steps))
train_act.extend(map(lambda step: step.action, example.steps))
elite_batch.append(example)

然后,我们将使用“精英”剧集更新该树变量,这些剧集是我们用来训练神经网络的状态和动作列表:

full_batch=elite_batch
state=train_obs
acts=train_act

步骤 4——使用“精英”剧集中的剧集步骤训练神经网络

每当我们的循环累积足够的片段(BATCH_SIZE)时,我们计算“精英”片段,并且在相同的迭代中,循环用以下代码训练代理的神经网络:

state_t = torch.FloatTensor(state)
acts_t = torch.LongTensor(acts)optimizer.zero_grad()
action_scores_t = net(state_t)
loss_t = objective(action_scores_t, acts_t)
loss_t.backward()
optimizer.step()

iter_no += 1
batch = []

这段代码使用“精英”剧集中的剧集步骤训练神经网络,使用状态 s 作为输入,发出动作 a 作为标签(期望输出)。让我们更详细地注释所有代码行:

首先,我们将变量转换成张量:

state_t = torch.FloatTensor(state)
acts_t = torch.LongTensor(acts)

我们将神经网络的梯度归零

optimizer.zero_grad()

并将观察到的状态传递给神经网络,获得其动作得分:

action_scores_t = net(state_t)

这些分数被传递给目标函数,该函数将计算神经网络输出和代理采取的动作之间的交叉熵

loss_t = objective(action_scores_t, acts_t)

请记住,我们只考虑“精英”行动。这种想法是为了加强我们的神经网络,以执行那些带来良好回报的“精英”行动。

最后,我们需要使用backward方法计算损失的梯度,并使用优化器的step方法调整神经网络的参数:

loss_t.backward()
optimizer.step()

监控代理的进度

为了监控代理的学习进度,我们在培训循环中加入了以下内容:

print(“%d: loss=%.3f, reward_mean=%.3f” % 
      (iter_no, loss_t.item(), reward_mean))

我们用它来显示迭代次数、损失和批次的平均回报(在下一节中,我们也将相同的值写入 TensorBoard 以获得一个漂亮的图表):

0: loss=1.384, reward_mean=0.020 
1: loss=1.353, reward_mean=0.040  
2: loss=1.332, reward_mean=0.010  
3: loss=1.362, reward_mean=0.020  
4: loss=1.337, reward_mean=0.020   
5: loss=1.378, reward_mean=0.020 . . .639: loss=0.471, reward_mean=0.730  
640: loss=0.511, reward_mean=0.730 
641: loss=0.472, reward_mean=0.760 
642: loss=0.481, reward_mean=0.650 
643: loss=0.472, reward_mean=0.750 
644: loss=0.492, reward_mean=0.720 
645: loss=0.480, reward_mean=0.660 
646: loss=0.479, reward_mean=0.740 
647: loss=0.474, reward_mean=0.660  
648: loss=0.517, reward_mean=0.830 

我们可以检查reward_mean变量的最后一个值是允许完成训练循环的值。

2.用更好的神经网络改进智能体

在之前的帖子中,我们已经介绍了 TensorBoard,这是一个有助于数据可视化过程的工具。取而代之的是上一节中使用的“打印”,我们可以用这两个句子来描绘这两个变量的行为:

writer.add_scalar(“loss”, loss_t.item(), iter_no)
writer.add_scalar(“reward_mean”, reward_mean, iter_no)

在这种情况下,输出是:

更复杂的神经网络

出现的一个问题是,我们是否可以改进代理的神经网络。例如,如果我们考虑一个具有更多神经元的隐藏层,比如说 128 个神经元,会发生什么情况:

HIDDEN_SIZE = 128
net= nn.Sequential(
           nn.Linear(obs_size, HIDDEN_SIZE),
           nn.Sigmoid(),
           nn.Linear(HIDDEN_SIZE, n_actions)
           )objective = nn.CrossEntropyLoss()
optimizer = optim.Adam(params=net.parameters(), lr=0.001)train_loop()

结果可以在这里显示(或者执行 GitHub 代码):

我们可以看到,这个网络比前一个网络学习得更快。

ReLU 激活功能

如果我们改变激活函数会发生什么?例如,用 ReLU 代替乙状结肠?

下面你可以看到发生了什么:网络收敛得更早,仅仅 200 次迭代就已经完成了。

3.交叉熵算法的改进

到目前为止,我们已经展示了如何改进神经网络架构。但我们也可以改进算法本身:我们可以将“精英”剧集保留更长时间。该算法的前一版本从环境中采样剧集,对最佳剧集进行训练,然后将其丢弃。然而,当成功剧集的数量很少时,可以将“精英”剧集保持更长时间,保持它们几次迭代以在其上进行训练。我们只需要修改代码中的一行:

elite_candidates= full_batch + batch#elite_candidates= batch

通过 TensorBoard 看到的结果是:

我们可以看到所需的迭代次数再次减少。

4.交叉熵方法的局限性

到目前为止,我们已经看到,通过所提出的改进,通过很少的训练循环迭代,我们可以找到一个好的神经网络。但这是因为我们在谈论一个非常简单的“防滑”环境。但是如果我们有一个“湿滑”的环境呢?

slippedy_env = gym.make(‘FrozenLake-v0’, is_slippery=True)class OneHotWrapper(gym.ObservationWrapper):
      def __init__(self, env):
          super(OneHotWrapper, self).__init__(env)
          self.observation_space = gym.spaces.Box(0.0, 1.0,
                (env.observation_space.n, ), dtype=np.float32)

      def observation(self, observation):
          r = np.copy(self.observation_space.low)
          r[observation] = 1.0
          return renv = OneHotWrapper(slippedy_env)

再次 TensorBoard 是一个大的帮助。在下图中,我们看到了算法在第一次迭代中的行为。它不能够脱去奖赏的价值:

但是,如果我们再等待 5000 次迭代,我们会看到它会有所改善,但从那里开始,它会停滞不前,不再能够超过某个阈值:

尽管我们已经等待了两个多小时,但它仍然没有改善,没有超过 60%的阈值:

5.摘要

在这两篇关于交叉熵方法的文章中,读者熟悉了这种方法。我们选择这种方法是因为它是一个很好的热身,因为它简单但非常强大,尽管它有局限性,并且合并了强化学习和深度学习。

我们将它应用于冰冻湖环境。我们已经看到,对于简单的“防滑”环境,with 可以找到一个很好的神经网络。但是如果我们考虑一个“光滑”的环境,交叉熵方法就无法找到(训练神经网络的)解决方案。在本系列的后面,您将熟悉解决这些限制的其他方法。

在开始本系列新部分的下一篇文章中,我们将转向对 RL 方法的更系统的研究,并讨论基于值的方法家族。

下期见!。

这篇文章的全部代码可以在 GitHub上找到,使用这个链接 可以作为一个 Colab 谷歌笔记本运行。**

鸣谢:这篇文章中的代码是从 Maxim Lapan 的代码中得到启发的,他写了一本关于这个主题的优秀的实用书籍。

深度强化学习讲解系列

UPC 巴塞罗那理工大学 巴塞罗那超级计算中心

一个轻松的介绍性系列以一种实用的方式逐渐向读者介绍这项令人兴奋的技术,它是人工智能领域最新突破性进展的真正推动者。

** [## 深度强化学习解释-乔迪托雷斯。人工智能

本系列的内容](https://torres.ai/deep-reinforcement-learning-explained-series/)

关于这个系列

我在五月开始写这个系列,在巴塞罗那的封锁期。老实说,由于封锁,在业余时间写这些帖子帮助了我 #StayAtHome 。感谢您当年阅读这份刊物;它证明了我所做的努力。

免责声明 —这些帖子是在巴塞罗纳封锁期间写的,目的是分散个人注意力和传播科学知识,以防对某人有所帮助,但不是为了成为 DRL 地区的学术参考文献。如果读者需要更严谨的文档,本系列的最后一篇文章提供了大量的学术资源和书籍供读者参考。作者意识到这一系列的帖子可能包含一些错误,如果目的是一个学术文件,则需要对英文文本进行修订以改进它。但是,尽管作者想提高内容的数量和质量,他的职业承诺并没有留给他这样做的自由时间。然而,作者同意提炼所有那些读者可以尽快报告的错误。**

对脏数据的最后一击

原文:https://towardsdatascience.com/cross-field-validation-using-pandas-f7a316fd37b7?source=collection_archive---------28-----------------------

用熊猫进行跨领域验证

照片由 伊恩·贝克利 像素

介绍

如今,数据不再来自单一来源。通常情况下,它被收集在不同的位置,并合并在一起。合并数据时的一个常见挑战是数据完整性。简而言之,通过使用多个字段检查另一个字段的有效性来确保我们的数据是正确的。用更好的术语来说,这个过程叫做交叉字段验证

对数据集的数据完整性进行健全性检查对于进行准确的分析和运行机器学习模型至关重要。交叉字段验证应该在您处理了大多数其他清理问题(如缺失值插补、确保字段约束到位等)之后进行。

我为这篇文章写了关于执行时间的代码片段。由于跨字段验证可能涉及对数百万个观察值跨多个列执行操作,因此执行速度非常重要。这里建议的解决方案应该具有足够的可伸缩性,甚至可以处理大规模数据集。

设置

我生成了假数据来进行跨领域验证:

交叉字段验证,示例 1

在设置部分,我们加载了一个假的people数据集。举例来说,我们将假设这些数据是从两个来源收集的:提供每个人的全名和生日的人口普查数据,这些数据后来与他们的医院记录合并在一起。

为了进行准确的分析,我们应该确保我们的数据是有效的。在这种情况下,我们可以检查两个字段的有效性:年龄和身体质量指数(身体质量指数)。

先说年龄。我们必须确保当我们从当前年份中减去他们的出生年份时,结果与age列相匹配。

当您执行跨字段验证时,速度应该是主要考虑的问题。与我们的小例子不同,您可能需要处理数百万次观察。对任何规模的数据集进行跨字段验证的最快方法之一是pandasapply函数。

这里有一个简单的apply的例子:

上面是一个按列执行的例子。apply接受一个函数名作为参数,并在被调用的列的每个元素上调用该函数。该函数有一个额外的参数axis,默认设置为0rows。如果我们将其设置为1columns,该功能将转换为按行执行。

关于axis参数的说明:axis='rows'表示沿着垂直的行轴执行操作,因为行是垂直堆叠的。axis='columns'表示沿水平的列轴执行操作,因为列是水平堆叠的。这两个术语让很多人感到困惑,因为它们看起来像是在做与他们被告知的相反的事情。事实上,只需要改变视角,或者用你愿意的话来说。

让我们创建一个函数来验证一个人的年龄:

因为我们将使用apply进行逐行操作,所以它的输入将是数据集的每一行。这就是为什么我们可以像在正常情况下一样轻松地访问每一列的值。

使用我们之前导入的datetime包,我们将存储今天的日期。然后,我们通过相互减去年份来计算年龄。为此,您必须确保birthday列具有datetime数据类型。

return语句中,我们比较了计算的年龄和给定的年龄,如果它们匹配,则返回True,否则返回False:

该功能按预期工作。现在,我们可以对无效年龄(如果有)的数据进行子集划分:

people[people['age_valid'] == False]

有 75 行的年龄无效。如果你算一下,年龄是不匹配的。为了纠正这些值,我们可以编写一个新的函数,但是这将涉及代码重复。我们可以更新validate_age来用有效值替换任何无效值:

我们可以使用assert语句来确保操作成功:

交叉字段验证,示例 2

接下来,我们将验证体重指数列。

体重指数是从一个人的体重和身高得出的数值。

快速的谷歌搜索给出了计算身体质量指数的公式:

图片由 维基 提供

使用第一个示例中的思想,我们将为身体质量指数创建用正确值替换无效身体质量指数的函数:

validate_启动所有的验证函数是一个很好的实践。这向代码的读者发出了您正在执行验证的信号。

跨字段验证、速度比较

在本节中,我们将对不同的跨字段验证方法进行速度比较。我们将从验证bmiapply函数开始:

10k 数据集大约需要 0.3 秒。接下来,我们将使用熊猫iterrows()的 for 循环:

花了 10 倍的时间!况且这个时间差不会是线性的。对于更大的数据集,这种差异变得越来越大。我不认为任何 for 循环能打败apply函数,但我们也试试一般比iterrows()更快的itertuples:

还是比apply慢很多。所以,跨字段验证的一般经验是总是使用apply函数。

如果你喜欢这篇文章,请分享并留下反馈。作为一名作家,你的支持对我来说意味着一切!

阅读更多与主题相关的文章:

[## 掌握 DS/ML 中最耗时的任务,#1

处理常见的数据问题

towardsdatascience.com](/data-type-constraints-data-range-constraints-duplicate-data-with-pandas-44897a350b1e) [## 掌握 DS/ML 中最讨厌的任务

用 Pandas 清理分类数据

towardsdatascience.com](/master-the-most-hated-task-in-ds-ml-3b9779276d7c) [## FuzzyWuzzy:Python 中的模糊字符串匹配,初学者指南

…以及在真实数据集上的动手实践

towardsdatascience.com](/fuzzywuzzy-fuzzy-string-matching-in-python-beginners-guide-9adc0edf4b35) [## 数据科学中的数据一致性

处理熊猫最常见的一致性问题

towardsdatascience.com](/data-uniformity-in-data-science-9bec114fbfae) [## 认识熊猫最难的功能,第一部分

掌握 pivot_table()、stack()、unstack()的时机和方式

towardsdatascience.com](/meet-the-hardest-functions-of-pandas-part-i-7d1f74597e92)

基于颤振的跨平台 NLP 图形用户界面

原文:https://towardsdatascience.com/cross-platform-nlp-gui-on-flutter-75d59170864?source=collection_archive---------14-----------------------

Flutter + Python REST 后端的情感分析 GUI

适用于 Android、平板电脑和网络(iOS 也是!)

目标:

根据我的上一篇文章 [2],我启动了一个项目来构建一个黑仔聊天应用程序,该应用程序利用 NLP 情绪分析器在实时聊天中执行实时聊天分析。本文是该项目的 R & D 阶段:

  • 用于情感分析的后端 REST 服务
  • 前端可视化工具来查看模型产生的结果

虽然我可以在 Python 笔记本中更容易地做到这一点,但我最终将在 Flutter 中构建聊天 GUI,所以这是一个很好的实践!

后端 Python 服务

在对 NLP 情感分析器的变体进行了大量研究之后[4],我挑选了几个简单的进行交叉比较:

  • 维德
  • 文本 Blob
  • Azure 文本分析(认知服务)
  • 谷歌云自然语言 API

还有十几个其他的库,我计划建立我自己的“Foo NLP”(为了体验),我将在另一个博客中详述。最终,我会添加圣杯 BERT [5],但这需要一些关于如何微调和操作 w/o 的策略,这让我在 Azure 上花费了$$$计算时间。

我的 REST API 有一个简单的接口:

  • 输入:文本字符串
  • 输出:情绪得分(-1 到+1,即从负到正的范围)

URL 获取格式为"【http://nlp.foostack.ai/nlp/sa/all?textinput=I 爱你】"您可以现场测试并查看其余 JSON 结果:

休息服务结果

Python 实现使用了 Flask web 框架,并公开了一个 REST API,该 API 反过来调用一些 NLP 情感分析器库或 web 服务,并将结果聚合到 JSON 响应中。Azure 上简单而便宜的托管服务。

REST 服务的代码[1]

颤振跨平台图形用户界面

大多数人都知道 Flutter 是一个很棒的 Android+iOS 跨平台开发系统,但截至 2019 年年中,它还做 Web。网络支持工作得非常好,尽管有它的怪癖:

  • 一些第三方控件可能无法工作。(例如,Url 启动器直到最近升级后才在 web 上运行)
  • 复制-粘贴在 Web 中不起作用。文本等看起来像不可点击的图像或奇怪的东西(我需要进一步调查)
  • 开发周期是一个有点笨重的单独构建和测试 web
  • 添加自定义 web 控件或 HTML/JS 似乎很困难

最终,Flutter Web 对 FooStack 的客户来说绰绰有余。

我的应用程序的结构

Flutter 将所有内容嵌套在子部件中。比如,垂直堆叠条目的列部件,增加空间的填充部件,标签的文本部件,等等。使一个简单的乐高式可互换系统。只需找出要抓取的组件,并将其堆叠在另一个小部件的上方、下方或内部。

我的 Flutter 应用程序的抽象结构:

- <Widget build>
 - Scaffold               # shortcut with top,body,footer areas
   - appBar:
   - body:Center          # centers all subcomponents
     - Column             # aligns subcomponents down the col
       - Padding
       - Text             # title (Foo Sentiment Analyzer)
       - ContrainedBox    # width controlling container
        - TextFormField   # input box for text to analyze
       - FlatButton       # submit button
       - Text             # title (Results)
       - Wrap             # wrap n-results across and down 
        - Container
         - Column         # single column result table 
          - DataTable     # formatted results table
            - DataColumns # headers  
            - DataCells   # rows
   - floatingButton:      # bottom right help button

相同逻辑应用的可视化:

颤振代码/布局的直观表示

应用程序的实际飞镖/颤振代码

另一个有趣的代码是我们如何从 GUI 调用 REST 服务。在 Go 按钮上,我们有一个事件处理程序“onPressed ”,它被映射到 _submit 函数。

**FlatButton** (
  child: Text(**'**Go**'**),
  color: Colors.*blue*,
  textColor: Colors.*white*,
 **onPressed: _submit,** ),

我们将 submit()定义为一个向 REST 服务发出 HTTP 请求并返回 JSON 的方法。JSON 被重新映射到供 GUI 处理的映射列表。还有更多关于 GUI 如何自动更新的内容,我就不多说了(StatefulWidgets 等)。

**void _submit() async {
***// call REST service and extract JSON body* var host = 'http://flaskmli.azurewebsites.net/nlp/sa/alldata=';var response = await http.get(host+inputController.text);
  var resp = response.body; *// extract JSON "results" array to a Map (dictionary)
  // push it onto the new dataList array (list of Maps)*  Map<String, dynamic> nlps = jsonDecode(resp);
  List<dynamic> results = nlps['results'];
  List<Map<String, dynamic>> dataList = [];
  results.forEach((result) {
    dataList.add(result);
  }); *// bit of hack here, add input text to _rawContentList*  _rawContentList.insert(0,[dataList, inputController.text])inputController.text = ''; *// reset focus (clears keyboard on mobile devices)*  FocusScope.*of*(context).requestFocus(FocusNode());
  setState(() {});   *// make GUI refresh from _rawContentList*
}

都搞定了! 我越来越擅长旋舞了,这个只用了几天就造好了。

我可以通过 Android Studio 和谷歌 Play 商店开发并发布我的 Android、平板电脑和 iPhone 应用程序。要发布我的 Flutter Web 应用程序,我只需运行“flutter build web”并手动将 web/build 构件部署到我的 Web 服务器上(实际上是将它们复制到一个现有的站点上,在我的例子中是复制到http://foostack.ai/nlp——请随意测试)。

现场 Foostack NLP 试用http://foostack.ai/nlp

感谢阅读。

参考与启示

[1]之前我的 Flutter NLP 聊天项目的文章—https://medium . com/Flutter-community/NLP-Chat-on-Flutter-azure-676 a 4768 fbb

[2]学习颤振的前期文章—https://code burst . io/why-I-a-Sr-manager-learned-Flutter-8d a9 a 05 b 2326?来源= - 5 -

[3]启发我的好文章—https://towards data science . com/a-practices-guide-to-natural-language-processing-part-I-processing-understanding-text-9 F4 abfd 13 e 72

[4]关于 BERT 和一些其他 NLP 模型的一些信息—https://medium . com/swlh/BERT—双向—编码器—表示—来自—变压器—C1 ba 3 ef 5 e 2 f 4

交叉验证和超参数调整:如何优化你的机器学习模型

原文:https://towardsdatascience.com/cross-validation-and-hyperparameter-tuning-how-to-optimise-your-machine-learning-model-13f005af9d7d?source=collection_archive---------0-----------------------

Alexis Baydoun 在 Unsplash 上拍摄的照片

非常准确地预测 Fitbit 的睡眠分数

在本文的前两部分,我获取并预处理了 Fitbit 睡眠数据,将数据分为训练集、验证集和测试集,训练了三个不同的机器学习模型,并比较了它们的性能。

第 2 部分中,我们看到使用随机森林和极端梯度增强的默认超参数并评估验证集上的模型性能导致多元线性回归表现最佳,随机森林和梯度增强回归器表现稍差。

在文章的这一部分,我将讨论只使用一个验证集的缺点,我们如何解决这些缺点,以及我们如何调整模型超参数来提高性能。让我们开始吧。

交叉验证

简单训练、验证和测试分割的缺点

在本文的第 2 部分中,我们将数据分为训练集、验证集和测试集,在训练集上训练我们的模型,并在验证集上评估它们。我们还没有接触测试集,因为它旨在作为一个保留集,代表以前从未见过的数据,一旦我们觉得机器学习模型准备好进行最终测试,这些数据将用于评估机器学习模型的泛化能力。

因为我们只将数据分为一组训练数据和一组验证数据,所以我们的模型的性能指标高度依赖于这两组数据。它们只被训练和评估一次,因此性能取决于那一次评估,并且当对相同数据的不同子集进行训练和评估时,性能可能会非常不同,这仅仅是因为如何挑选子集的性质。

如果我们可以多次进行训练和验证测试,每次针对不同的数据子集,每次都训练和评估我们的模型,并在多次评估中查看模型的平均性能,会怎么样?这正是 K 倍交叉验证背后的想法。

k 倍交叉验证

在 K-fold 交叉验证(CV)中,我们仍然从数据集中的剩余数据中分离出一个测试/保留集,用于我们模型的最终评估。剩余的数据,即除测试集之外的所有数据,被分成 K 个折叠(子集)。交叉验证然后遍历折叠,并且在每次迭代中使用 K 个折叠中的一个作为验证集,同时使用所有剩余的折叠作为训练集。重复这个过程,直到每个折叠都被用作验证集。以下是五重交叉验证的流程:

通过在相同训练数据的不同子集上对模型进行 K 次训练和测试,我们可以更准确地表示我们的模型在以前从未见过的数据上的表现。在 K-fold CV 中,我们在每次迭代后对模型进行评分,并计算所有评分的平均值,以获得与仅使用一个训练和验证集相比模型表现如何的更好表示。

Python 中的 k 重交叉验证

因为 Fitbit sleep 数据集比较小,所以我准备使用 4 重交叉验证,比较目前使用的三种模型:多元线性回归、随机森林和极端梯度提升回归器。

请注意,4 重 CV 也可以很好地与第 2 部分中的训练和验证数据进行比较,因为我们将数据分为 75%的训练数据和 25%的验证数据。一个四重 CV 本质上做同样的事情,仅仅四次,并且每次使用不同的子集。我创建了一个函数,它将我们想要比较的模型列表、特征数据、目标变量数据和我们想要创建的折叠数作为输入。该函数计算我们之前使用的性能测量,并返回一个表,其中包含所有模型的平均值以及每种类型的测量在每个折叠中的分数,以备我们进一步研究。下面是函数:

现在,我们可以创建一个要使用的模型列表,并使用 4 重交叉验证调用上面的函数:

生成的比较表如下所示:

使用一个 4 重 CV,随机森林回归器在所有性能指标上都优于其他两个模型。但是在第 2 部分中,我们看到多元线性回归有最好的性能指标,为什么会改变呢?

为了理解为什么交叉验证会产生与第 2 部分中的简单训练和验证不同的分数,我们需要更仔细地看看模型在每个折叠中的表现。上面的 cv_comparison()函数也为每个折叠返回每个不同模型的所有分数列表。让我们来看看三个模型的 R 平方在每次折叠时的比较。为了得到表格格式的结果,让我们快速地将它转换成数据帧:

上表清楚地表明了为什么从四重 CV 获得的分数不同于训练和验证集的分数。R 平方因褶皱而异,特别是对于极端梯度增强和多元线性回归。这也说明了为什么使用交叉验证如此重要,尤其是对于小数据集。如果你只依赖一个简单的训练和验证集,你的结果可能会有很大的不同,这取决于你最终得到的数据的分割。

既然我们知道了什么是交叉验证以及它为什么重要,那么让我们看看是否可以通过调整超参数从我们的模型中获得更多。

超参数调谐

不同于在模型训练期间学习并且不能任意设置的模型参数,超参数是可以由用户在训练机器学习模型之前设置的参数。随机森林中超参数的示例包括森林中决策树的数量、每次分割时要考虑的最大要素数量或树的最大深度。

正如我之前提到的,寻找最佳超参数没有一个放之四海而皆准的解决方案。对于一个机器学习问题表现良好的一组超参数可能在另一个问题上表现不佳。那么我们如何计算出最优超参数是什么呢?

一种可能的方法是使用有根据的猜测作为起点来手动调整超参数,改变一些超参数,训练模型,评估其性能,并重复这些步骤,直到我们对性能满意为止。这听起来像是一个不必要的乏味的方法,事实也的确如此。

比较超参数调音和吉他调音。你可以选择用耳朵给吉他调音,这需要大量的练习和耐心,而且可能永远不会达到最佳效果,尤其是如果你是初学者的话。幸运的是,有电吉他调音器可以通过解释吉他弦的声波并显示其读数来帮助你找到正确的音调。你仍然需要使用机器头来调弦,但这个过程会快得多,电动调音器可以确保你的调弦接近最佳。那么电吉他调音师的机器学习等同于什么呢?

随机网格搜索交叉验证

在 scikit-learn 中,一种最流行的调整机器学习超参数的方法被称为 RandomizedSearchCV()。我们来剖析一下这是什么意思。

在随机网格搜索交叉验证中,我们首先创建一个超参数网格,我们希望优化这些超参数的值。让我们看一个随机森林回归器的超参数网格示例,以及如何设置它:

首先,我们为每个想要调优的超参数创建一个可能值的列表,然后我们使用一个包含键值对的字典来设置网格,如上所示。为了找到和理解机器学习模型的超参数,你可以查看模型的官方文档,参见随机森林回归器的文档这里

生成的网格如下所示:

顾名思义,随机网格搜索交叉验证使用交叉验证来评估模型性能。随机搜索意味着该算法从网格中为每个超参数随机选择一个值,并使用超参数的随机组合来评估模型,而不是尝试所有可能的超参数组合(在我们的示例中为 27,216 个组合)。

尝试所有可能的组合在计算上会非常昂贵,并且需要很长时间。随机选择超参数可以显著加快这一过程,并且通常为尝试所有可能的组合提供了一个类似的好解决方案。让我们看看如何使用随机网格搜索交叉验证。

随机森林的超参数调整

使用之前创建的网格,我们可以为我们的随机森林回归量找到最佳超参数。我将使用三重 CV,因为数据集相对较小,并且运行 200 个随机组合。因此,总的来说,随机网格搜索 CV 将训练和评估 600 个模型(200 个组合的 3 倍)。因为与极端梯度提升等其他机器学习模型相比,随机森林往往计算缓慢,所以运行这么多模型需要几分钟时间。一旦该过程完成,我们就可以获得最佳的超参数。

下面是如何使用 RandomizedSearchCV():

我们将在最终模型中使用这些超参数,并在测试集上进行测试。

超参数调谐,实现极端梯度提升

对于我们的极端梯度推进回归器,过程基本上与随机森林相同。由于模型的性质,我们试图优化的一些超参数是相同的,一些是不同的。你可以在这里找到 XGBRegressor 的超参数的完整列表和解释。我们再次创建网格:

生成的网格如下所示:

为了使性能评估具有可比性,我还将使用具有 200 种组合的 3 重 CV 进行极端梯度提升:

最佳超参数如下:

同样,这些将在最终模型中使用。

虽然对一些人来说这可能是显而易见的,但我只想在这里提一下:我们不为多元线性回归进行超参数优化的原因是因为模型中没有要调整的超参数,它只是一个多元线性回归。

既然我们已经获得了最佳超参数(至少在我们的交叉验证方面),我们终于可以根据我们从分析一开始就坚持的测试数据来评估我们的模型了!

最终模型评估

在评估了我们的机器学习模型的性能并找到最佳超参数之后,是时候对模型进行最终测试了——全能坚持集。

为了做到这一点,我们在迄今为止所有评估中使用的全部 80%的数据上训练模型,即除测试集之外的所有数据。我们使用在上一部分中找到的超参数,然后比较我们的模型在测试集上的表现。

让我们创建并训练我们的模型:

我定义了一个函数,该函数对所有最终模型进行评分,并创建一个数据框架来简化比较:

用我们的三个最终模型调用该函数,并调整列标题,得到以下最终评估结果:

获胜者是:随机森林回归者!

随机森林在测试集上实现了 80%的 R 平方和 97.6%的准确性,这意味着它的预测平均只相差约 2.4%。还不错!

多元线性回归的表现并不落后,但极端梯度推进未能达到其在该分析中的宣传效果。

结论意见

想出这整个分析和实际进行分析的过程充满了乐趣。一段时间以来,我一直试图弄清楚 Fitbit 是如何计算睡眠分数的,很高兴对它有了更好的理解。最重要的是,我设法建立了一个机器学习模型,可以非常准确地预测睡眠分数。话虽如此,我还是想强调几点:

  1. 正如我在第 2 部分中提到的,多元线性回归系数的解释可能不准确,因为要素之间存在高度的多重共线性。
  2. 我用于此分析的数据集相当小,因为它依赖于从 Fitbit 获得的 286 个数据点。这限制了结果的通用性,需要更大的数据集才能训练更稳健的模型。
  3. 这种分析只使用了一个人的 Fitbit 睡眠数据,因此可能无法很好地推广到具有不同睡眠模式、心率等的其他人。

我希望你喜欢这篇关于如何使用机器学习来预测 Fitbit 睡眠分数的透彻分析,并了解不同睡眠阶段的重要性以及睡眠时间。

我非常感谢建设性的反馈,您可以随时通过 LinkedIn 联系我。

感谢阅读!

交叉验证

原文:https://towardsdatascience.com/cross-validation-c4fae714f1c5?source=collection_archive---------23-----------------------

验证您的机器学习模型性能

来源:维基百科

交叉验证可以是各种模型验证技术中的任何一种,这些模型验证技术用于评估预测模型将多好地推广到该模型以前没有见过的独立数据集。因此,它通常用于我们预测某些事情,并且我们希望粗略估计我们的预测模型在实践中的表现。

“在创建任何机器学习模型之前,我们必须知道什么是交叉验证,以及如何选择最佳的交叉验证”——Abhishek tha kur,Kaggle 的第一位 4x 特级大师

在这篇文章结束时,你将对流行的交叉验证技术有一个很好的理解,我们如何使用 scikit-learn 实现它们,以及如何选择给定特定问题的正确 CV。

流行的交叉验证技术

本质上,选择正确的交叉验证技术归结于我们手头的数据,因此为什么一个交叉验证的选择可能对另一组数据起作用,也可能不起作用。然而,采用交叉验证技术的目标保持不变,我们希望估计预测模型对未知数据的预期拟合水平,因为有了这些信息,我们可以做出必要的调整来制作预测模型(如果需要)或决定使用完全不同的模型。

基于保留的交叉验证

我可能会受到一些经验数据科学家、机器学习和/或深度学习从业者对不恰当术语的滥用,因为交叉验证通常允许预测模型在各种拆分上进行训练和测试,而保留集则不允许。不管怎样,当我们把数据分成一个训练集和一个测试集时,就需要进行基于坚持的交叉验证。这通常是您要实现的第一个验证技术,也是最容易理解的。它包括把你的数据分成不同的部分,你可以在一个数据集上训练你的预测模型,并在测试集上测试它。

注意:有些人更进一步,会有一个训练数据集、一个验证数据集和测试数据集。验证数据集将用于调整预测模型,测试集将用于测试模型的泛化能力。

在划分数据时,要记住的一点是,您必须确定哪些数据用于训练,哪些用于测试。我见过从 60%(训练)-40%(测试)到 80%(训练)-20%(测试)的各种分裂。我相信可以有把握地说,60%-80%的数据应该用于训练预测模型,其余的可能直接用于测试集(或者再次分成验证集和测试集)。

图 1:基于拒绝的验证的例子(来源: Adi BronshteinPython 中的训练/测试分割和交叉验证)

# [https://bit.ly/3fUuyOy](https://bit.ly/3fUuyOy)**import** **numpy** **as** **np**
**from** **sklearn.model_selection** **import** train_test_split
X, y = np.arange(10).reshape((5, 2)), range(5)
**print**(X)
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7],
       [8, 9]])**print(**list(y))
[0, 1, 2, 3, 4]

当我们有一个非常大的数据集时,执行基于拒绝的验证技术是最有效的。由于不需要在各种分割上进行测试,这种技术使用的计算能力要少得多,因此使其成为在大型数据集上进行验证的首选策略。

k 倍交叉验证

我简单地提到了由上述“c 组成的交叉验证,ross 验证通常允许预测模型在各种拆分上进行训练和测试,而保留集则不允许— 换句话说,交叉验证是一个重采样的过程。当“k”出现在机器学习讨论中时,它通常用于表示常数值,例如 k-means 聚类中的 k 是指聚类的数量,k 近邻中的 k 是指执行多元投票(用于分类)时要考虑的近邻数量。这种模式也适用于 K-Fold 交叉验证,其中 K 表示给定数据样本应该分成的组的数量。

k 倍交叉验证中,原始样本被随机分成 k 个大小相等的组。从 k 个组中,一个组将作为保留组被移除,并且剩余的组将是训练数据。然后,将预测模型拟合到训练数据上,并在保留集上进行评估。这个过程是 k 次,因此所有的组正好服务一次作为坚持组。

图 KFold 交叉验证的例子(来源: Scikit-Learn 文档)

**#** [https://bit.ly/2POmqVb](https://bit.ly/2POmqVb)**import** **numpy** **as** **np**
**from** **sklearn.model_selection** **import** KFoldX = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
y = np.array([1, 2, 3, 4])
kf = KFold(n_splits=2)
**print(**kf.get_n_splits(X))
2**print**(kf)
KFold(n_splits=2, random_state=None, shuffle=False)**>>> for** train_index, test_index **in** kf.split(X):
**... **    **print**("TRAIN:", train_index, "TEST:", test_index)
**... **    X_train, X_test = X[train_index], X[test_index]
**... **    y_train, y_test = y[train_index], y[test_index]
TRAIN: [2 3] TEST: [0 1]
TRAIN: [0 1] TEST: [2 3]

由于易于理解,k-fold 交叉验证相当流行。并且与执行基于拒绝的验证相比,它通常会产生偏差较小的结果。这种技术通常是回归问题的一个很好的起点,尽管如果目标变量的分布不一致,使用分层 k-fold 可能更好,这将需要目标变量的宁滨。需要考虑的是 k 的配置,它必须分割数据,以便数据样本的每个训练/测试分割足够大,能够在统计上代表更广泛的数据集。

分层 K 折叠

到目前为止,我们介绍的两种技术在许多情况下都是相对有效的,尽管当目标数据具有不平衡的标签时,可能会出现误导性的结果(以及潜在的整体失败)——我一直很小心,不只是将这作为分类任务的一个问题,因为我们可以以某种方式调整回归任务,以便能够执行分层 k-fold 进行验证。相反,一个更好的解决方案是以这样一种方式随机划分,即我们在每个子集中保持相同的类别分布,这就是我们所说的分层。

:除了我们随机分割数据的方式,分层 k 重交叉验证与简单 k 重交叉验证是一样的。

图 StratifiedKFold 的例子(来源: Scikit-Learn 文档

**#** [https://bit.ly/3iCHavo](https://bit.ly/3iCHavo)**import** **numpy** **as** **np**
**from** **sklearn.model_selection** **import** StratifiedKFoldX = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
y = np.array([0, 0, 1, 1])
skf = StratifiedKFold(n_splits=2)
**print**(skf.get_n_splits(X, y)
2**print**(skf)
StratifiedKFold(n_splits=2, random_state=None, shuffle=False)**for** train_index, test_index **in** skf.split(X, y):
   **print**("TRAIN:", train_index, "TEST:", test_index)
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]TRAIN: [1 3] TEST: [0 2]
TRAIN: [0 2] TEST: [1 3]

根据第一个 4X Kaggle 特级大师 Abhishek Thakur 的说法,可以肯定地说,如果我们有一个标准的分类任务,那么盲目地应用分层 k-fold 交叉验证根本不是一个坏主意。

留一交叉验证

留一交叉验证可以被认为是 k 重交叉验证的特例,其中 k = n ,n 是原始数据集中的样本数。换句话说,数据将在 n - 1 个样本上训练,并将用于预测被遗漏的样本,这将被重复 n 次,使得每个样本充当被遗漏的样本。

图 4:留一简历示例(来源: DataCamp

#[https://bit.ly/2POw0HU](https://bit.ly/2POw0HU)**import** **numpy** **as** **np**
**from** **sklearn.model_selection** **import** LeaveOneOutX = np.array([[1, 2], [3, 4]])
y = np.array([1, 2])
loo = LeaveOneOut()
**print**(loo.get_n_splits(X))
2**print**(loo)
LeaveOneOut()**for** train_index, test_index **in** loo.split(X):
    **print**("TRAIN:", train_index, "TEST:", test_index)
   X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
    **print**(X_train, X_test, y_train, y_test)TRAIN: [1] TEST: [0]
[[3 4]] [[1 2]] [2] [1]
TRAIN: [0] TEST: [1]
[[1 2]] [[3 4]] [1] [2]

这种技术可能需要大量的计算时间,在这种情况下,k 倍交叉验证可能是更好的解决方案。或者,如果数据集很小,那么预测模型将丢失大量数据(特别是如果交叉验证很大),因此在这种情况下,留一法是一个很好的解决方案。

组 K-折叠交叉验证

GroupKFold 交叉验证是 k-fold 交叉验证的另一种变体,它确保同一组不出现在训练和测试集中。例如,如果我们想要建立一个预测模型,从患者皮肤的图像中对恶性或良性进行分类,很可能我们会有来自同一个患者的图像。由于我们没有在训练和测试集中分割单个患者,因此我们恢复到 GroupKfold 而不是 k-fold(或分层 k-fold),因此,患者将被视为组。

图 5:分组文件夹的例子(来源: Scikit-Learn 文档

**#** [https://scikit-learn.org/stable/modules/cross_validation.html](https://scikit-learn.org/stable/modules/cross_validation.html)**from** **sklearn.model_selection** **import** GroupKFold

X = [0.1, 0.2, 2.2, 2.4, 2.3, 4.55, 5.8, 8.8, 9, 10]
y = ["a", "b", "b", "b", "c", "c", "c", "d", "d", "d"]
groups = [1, 1, 1, 2, 2, 2, 3, 3, 3, 3]

gkf = GroupKFold(n_splits=3)
**for** train, test **in** gkf.split(X, y, groups=groups):
   print("*%s* *%s*" % (train, test))[0 1 2 3 4 5] [6 7 8 9]
[0 1 2 6 7 8 9] [3 4 5]
[3 4 5 6 7 8 9] [0 1 2]

注意:这种技术的另一个变体是分层 K 折叠交叉验证,当我们想要保持类别分布并且我们不想同一个组出现在两个不同的折叠中时,执行这种验证。scikit-learn 没有内置的解决方案,但是在这个 Kaggle 笔记本中有一个很好的实现。

包裹

交叉验证是建立机器学习模型的第一步,在决定采用什么技术时,我们考虑我们拥有的数据是极其重要的——在某些情况下,甚至有必要根据数据采用新形式的交叉验证。

“如果你有一个好的交叉验证方案,其中验证数据代表训练和真实世界的数据,你将能够建立一个良好的高度可概括的机器学习模型。”——Abhishek tha kur

这个故事的灵感来自于第一位 4x Kaggle 特级大师 Abhishek Thakur 的《接近(几乎)任何机器学习问题 》(链接是而不是附属链接,并且我没有被要求推广这本书)。如果你已经有了一些机器学习的经验,并且想要更多实用的建议,那么我强烈推荐这本书。

如果你想和我联系,我在 LinkedIn 上最容易找到:

[## Kurtis Pykes -人工智能作家-走向数据科学| LinkedIn

在世界上最大的职业社区 LinkedIn 上查看 Kurtis Pykes 的个人资料。Kurtis 有一个工作列在他们的…

www.linkedin.com](https://www.linkedin.com/in/kurtispykes/)

使用 KNN 进行交叉验证

原文:https://towardsdatascience.com/cross-validation-using-knn-6babb6e619c8?source=collection_archive---------1-----------------------

这是 KNN 系列的第三篇文章。如果你还没有阅读前两部分,我建议你先浏览一遍。第一部分第二部分

在本文中,我们将了解什么是交叉验证,为什么需要它,以及什么是 k 倍交叉验证?

为了更好地理解交叉验证的必要性,让我先回顾一下如何确定“K”的正确值?

假设,我们有一个数据集,我们将它按照 70:30 的比例分成训练数据和测试数据。也就是说,我保留总数据的 70%来训练我的模型,剩下的 30%来测试它。接下来,我用不同的“K”值训练我的模型,并在我的测试数据上捕捉它的准确性。假设我们得到如下表格:

作者图片

现在,如果你观察,那么在 K=3 时,我得到 90%的最高精度,之后,我们看到精度下降的趋势。所以,我们得出结论的基础是,我的 K=3 的合适值。

这一切听起来不错,但有一个小问题。让我问你一个非常简单而有趣的问题。

机器学习的目的是什么?

如果我考虑上面的例子,并且基于我的理解,对于一个未来看不见的数据点,我的模型将如何准确地预测类别标签。当一个算法在一个看不见的数据点上表现良好时,它被称为推广。机器学习的整体目标是推广。

想想 KNN,我们使用测试数据来确定 K 的正确值,使用训练数据来寻找最近的邻居。我们在测试数据上获得了 90%的准确性,我们还使用这些数据来确定“K”的正确值。我是否可以说,既然我的测试数据达到了 90%的准确率,我就能在未来看不到的数据上保持这种大致的准确率?答案是

为了自信地说,我们可以在未来看不见的数据上达到大约 90%的准确性,我需要首先在看不见的数据上测试这个模型。

但是我该怎么做呢?我有我的数据集,我已经把它分成了 70:30 比例的训练和测试数据。我没有更多可用的数据。

为了解决这个问题,我给你介绍一下交叉验证的概念。

在交叉验证中,我们不是将数据分成两部分,而是分成三部分。训练数据、交叉验证数据和测试数据。在这里,我们使用训练数据来寻找最近的邻居,我们使用交叉验证数据来寻找“K”的最佳值,最后我们在完全看不见的测试数据上测试我们的模型。这个测试数据相当于未来看不见的数据点。

为了更好地理解,请考虑下图,该图清楚地区分了拆分:

作者图片

左边的部分没有交叉验证,右边的部分有交叉验证。

在交叉验证部分,我们使用 D_Train 和 D_CV 来找到 KNN,但我们不接触 D_Test。一旦我们找到一个合适的“K”值,我们就在 D_Test 上使用这个 K 值,它也作为一个未来看不见的数据,来发现模型执行的准确程度。

现在,我们已经理解了交叉验证的概念和它的必要性,让我们解决一个与之相关的问题。

问题:

如果你参考上面的图片,我们已经按照 60:20:20 的比例分割了数据,其中我们使用 60%的数据来训练我们的模型,20%用于交叉验证,其余 20%用于测试。在这个交叉验证的过程中,我们丢失了将近 20%的数据,这些数据本来是用于训练的,众所周知,训练数据越多,算法就越好。那么,有没有办法在训练数据下使用那 20%的交叉验证数据呢?

这个问题的答案是 k 倍交叉验证

那么,在 k 倍交叉验证中会发生什么呢?考虑下面的例子:

作者图片

在将总数据集(D_n)分割成训练(D_Train)和测试(D_Test)数据集后,以 80:20 的比例,我们进一步随机将训练数据分割成 4 等份。

作者图片

D1、D2、D3 和 D4 是 D_Train 的四个随机拆分的相等部分。完成分割后,我们按如下方式进行:

作者图片

第一步:对于 K=1,我选择 D1、D2 和 D3 作为我的训练数据集,并将 D4 设置为我的交叉验证数据,并找到最近的邻居并计算其准确性。

第二步:同样,对于 K=1,我选择 D1、D2 和 D4 作为我的训练数据集,并设置 D3 作为我的交叉验证数据,我找到最近的邻居并计算其准确性。

我用 D2 和 D1 作为我的交叉验证数据集重复上述步骤,并计算相应的准确度。完成后,对于 K=1 的相同值,我得到了 4 个精度。因此,我考虑这些精度的平均值,并将其作为 K=1 时的最终值。

现在,我对 K=2 重复上述步骤,找到 K=2 的平均精度。依此类推,我计算不同 k 值的精度。

现在,请注意,对于 K 的每个值,我必须计算 4 次精度。这是因为我随机地将我的训练数据集分成 4 个相等的部分。假设我将我的数据集随机分成 5 个相等的部分,那么我将不得不为每个 K 值计算 5 个不同的精确度,并取它们的平均值。

请注意:大写“K”代表 KNN 中的 K 值,小写“K”代表 k 倍交叉验证中的 K 值

因此,对于上述示例,k-fold 交叉验证中的 k 值是 4(即 k=4),如果我们将训练数据分成 5 个相等的部分,则 k 值=5。

k =我们随机将训练数据集分成的部分的数量。

现在,我们使用全部 80%的数据来计算最近邻以及 KNN 的 K 值。

K 重交叉验证的一个缺点是,我们要对(KNN 的)每个 K 值重复计算。所以基本上增加了时间复杂度。

结论

我们已经理解了交叉验证的概念,为什么我们需要它,以及 k 倍交叉验证是什么意思。尽管时间复杂度很高,但这个过程是值得的,因为它增加了模型的泛化能力。

感谢阅读!

我希望这些资源和想法对您的数据科学之旅有所帮助。

迪帕克·贾恩

众包数据标签

原文:https://towardsdatascience.com/crowd-sourced-data-labeling-68fb92b291a5?source=collection_archive---------21-----------------------

照片由乔丹·康纳在 Unsplash 上拍摄

如何利用外包人员获得高质量的标注数据集

作为一名数据科学家,我们花了大量的时间处理数据——清理、规范化、标记。令人欣慰的是,如今许多解决方案将标记工作交给了第三方,解放了数据科学家的宝贵时间,并减轻了手动文本、图片或视频标记的负担。

然而,作为一名数据科学家,我们想知道第三方在标记任务上的表现如何,因为我们通常称输出为“黄金数据集”有几种方法可以检查数据集的注释情况。

注释者间协议(IAA) —是两个或更多注释者之间关于标签的协议。例如,如果我们有一个观察,由 7 个不同的人独立地标记为 3 个可能的标签,IAA 是多少注释者同意应该分配的标签的度量。如果所有 7 个人都分配了相同的标签,IAA 将为 100%。也就是说注释者之间的一致是两个(或更多)注释者对某个类别做出相同注释决定的程度的度量。

然而,在现实世界中,并不是所有的注释者都具有相同的技能水平。一些人类注释者在这项任务中可能更有经验,所以他们应该有更高的权重。这时候加权 弗莱斯卡帕 进来了。这是计算注释者一致性的标准,因为有些注释者比其他人更熟练。

如果我们有一份法律文件,并且每个文本段落需要被分类为 3 个可能的标签,例如,特殊法律条款样板法律文本合同细节。此外,我们希望每个文本段落由 5 个不同的人类标签分类。一个贴标签的专家应该有更强的发言权,标签应该是什么。这个较高的权重是基于正确性的历史运行平均值。这意味着如果专家始终是正确的,特别是在贴标机不能就标签达成一致的低 IAA 观察上。那么专家的投票将具有更高的权重- 2 个或更多标签员的投票。

众包贴标机的另一个改进是当他们的标签与共识标签不一致时提示贴标机。作为一个节省成本的措施,设置一个小样本——10%由多个标注者标注(抽样率)

通过如上所述的自动设置,可以获得高精度的群体标记系统,其中大量初始观察被发送到甲骨文,并且随着时间的推移,专家将出现,因为他们的标签与低注释者间一致性观察的甲骨文相一致。同样,如果注释者在没有阅读/理解问题的情况下随机分配标签,那么他们的分类将与大多数样本的分类不同。在一个例子中,许多注释者同意类应该是特殊法律条款当“坏的”注释者选择合同细节作为答案时,设置将随着时间的推移降低标注者的等级,甚至完全禁止他们为您标注。

工作示例

在我的工作中,当我的团队需要廉价和高质量的数据集时,我们使用 MTurk。例如,对于一个获得大约 20,000 个高质量标记数据点来微调基于变压器的 NLP 模型的项目,我们做了以下工作

  1. 我们(ML 工程师和 SME)手工标记了大约 200 个(或 1%)观察值。
  2. 我们在 20 个预先标记的观察值上为 Turkers 设置了资格作业。这将决定哪些 Turkers 我们想登上我们的主要标签工作。这是它看起来的样子—

尝试标记合格测试的 10 台机器的样本

你可以看到 10 号工人甚至没有努力,f1 分数为 23%。我们让 f1 超过 90%的员工来完成这项任务。

3.我们以这样一种方式设置任务,即每个观察将被 5 个不同的 Turkers 标记。每个这样的任务将包含 100 个观察值,99 个未标记,1 个观察值已经由我们的团队预先标记,但对 Turkers 不可见。

4.我们总共发布了 200 个这样的任务,每个任务有 100 个观察值。任务将以最大化观察完整性的方式提供给 Turkers,即,我们希望任务 1 在转移到下一个任务之前由不同的 Turkers 完全完成,以此类推。这里的风险是,如果所有任务对 Turker 都可用,我们将没有可靠的指标,因为 Turker 1 将从任务#10 开始,而 Turker 2 将从任务#103 开始,以此类推,从而妨碍 IAA 计算。

5.Turkers 在连续的 100 次观察中标记了主要的 19,980 (20,000–20)个数据集,我们将监控每个 Turkers 的 IAA 指标。如果任何一个 Turker 的 IAA 降得太低,我们编写的代码就会将他们排除在我们的标记之外。

6.我们还监控了 Turkers 在我们团队预先标记的少数观察中的表现,以确保 Turkers 不会集体误入歧途,因为 IAA 指标监控的是相关性而不是正确性。

7.在整个任务完成后,我们将提升某些工人为主工人,下次我们做标记时,这些工人不需要参加资格考试。在这里,我们甚至可以进行扩展,使这些 Turker 的投票数在 IAA 的计算中更高。

我上面描述的系统是由我们构建的,充分利用了 AWS 的 MTurk APIs,我们不必担心标记者变得懒惰并开始随机标记数据,因为他们会自动从池中删除。

结论

在数据科学家团队中,我们经常需要带标签的数据。对于现代人工智能团队来说,拥有一种自动化的方式来搭载众包工人,以自动化的方式评估和监控贴标机的性能是非常重要的。这些原则中的一些甚至被用于数据编程,在数据编程中,标记功能可以被认为是单个的工人,鉴别器试图辨别哪些标记功能执行,哪些不执行。

如果你有兴趣用 apis ping me 建立自己的自动化众包系统,我们可以抓取☕️电子咖啡👍。

如何:用 ObservableHQ 和 Mechanical Turk 对数据进行群体测试

原文:https://towardsdatascience.com/crowd-testing-data-viz-observablehq-and-mechanical-turk-e3663f9fa5f8?source=collection_archive---------48-----------------------

在可观察的笔记本上开发数据可视化和用户在 Mechanical Turk 上测试它们的技术指南。

(图片来自作者)

数据可视化看似复杂。即使是简单的可视化也有多个组件以令人惊讶的方式交互。出于这个原因,用真人测试可视化是至关重要的。在大多数情况下,做一些(定性的)用户测试,修复问题,然后发布就足够了。

但是有时候你需要更多的确定性。例如,如果你正在为公众设计可视化效果,如果你正在进行学术研究,或者如果可视化效果将成为产品或应用程序的一部分,你可能需要评估一些不同的设计变体,以了解哪种表现最好。

定性测试使得比较设计的不同版本变得困难,因为像排序效应这样的问题。传统的 A/B 测试也没有帮助,因为它们不会透露太多关于用户是否“得到”图表的信息。幸运的是,还有机械土耳其人。

用户测试数据,即机械土耳其人

如果你需要测试数据可视化,你需要统计精度,机械土耳其人是你的朋友。Mechanical Turk 可以(相对)轻松地快速接触到大量“工人”受众,并向他们询问几乎任何问题。

当你测试数据时,你给工人一个“测验”,基于你的想象,看看他们表现如何。显然你不是在测试用户,而是在测试你的设计。用户正确回答的问题越多,回答的速度越快,您就越有信心可视化是健壮的。

迈克·博斯托克杰弗里·赫尔 在斯坦福发表了一项研究证实了这一点。他们检查了 Mechanical Turk,特别是作为测试数据可视化的平台,并发现“众包感知实验是可行的,并为可视化设计提供了新的见解。”

挑战:测试设置

像赫尔和博斯托克这样的研究面临的挑战是,它们通常需要相当多的设置。通常这包括实际启动一个服务器来托管可视化和你自己的“测验”。这并不是一个巨大的负担,但这是可以花在更有启发性的事情上的时间。

不过,多亏了 ObservableHQ ,你可以在一个可观察的笔记本中构建整个实验,并将可视化结果完全无服务器地嵌入到一个机械土耳其人“HIT”(或人类智能任务)中。

额外的好处是,实际上在可观察中对可视化进行原型化通常是快速、令人愉快的,并且支持简单的协作。

在最近的一个实验中,我测试了条形图 v.s .棒棒糖图 v.s .点图,使用这个 ObservableHQ + Mechanical Turk 设置,在几个小时内评估了 3 种不同的有争议的图表类型,有 150 名不同的参与者(发现对理解的准确性和速度有显著影响)。

工作原理:

在本指南中,我将介绍使 Bar /棒棒糖/ Dot 实验工作的技术方面。为了简单起见,我们将构建一个更简单的玩具实验(测试不同颜色的条形图)。

这些实验的完整代码在两个地方:

  1. 此处的可观察笔记本
  2. 这个包含 MTurk HIT 的 HTML 的要点在这里

步骤:

假设我们想做一个实验,看看条形图的颜色是否对理解或速度有任何影响。我们决定测试红色、绿色和蓝色条形图。

为此,我们将…

  • 在 ObservableHQ 笔记本中构建 3 种不同的可视化效果
  • 将 3 个可视化效果中的 1 个随机嵌入到一个机械 Turk HIT 中
  • 将问题作为简单的 HTML 表单输入添加到 HIT 中
  • 开展活动!
  • 评估结果

在可观察的笔记本中构建可视化效果

首先,在 ObservableHQ 上新建一个笔记本。

然后,我们将从导入 d3 开始。按照惯例,它们通常放在笔记本的底部,但为了保持时间顺序,把它们放在上面。

d3 = require("d3@5")

接下来,我们将制作一个简单的条形图。我们会给它一个color参数,这样我们就可以使用这个相同的条形图来测试我们 3 个实验变体的所有 3 种颜色。

然后,我们可以测试它在下一个单元格中的工作方式:

barChart([1,2,3,4,3,5].map((d,i)=>({x:i, y:d})))

然后,让我们为 3 个不同的变体制作 3 个不同的函数:一个红色条形图、一个蓝色条形图和一个绿色条形图。我们将它们存储在chartVariants中,用变体名称:'red''green''blue'键接。

chartVariants= ({
  'red': (data,params)=>(barChart(data, {...params, color: '#EB4137'})),
  'green': (data,params)=>(barChart(data, {...params, color: '#8CC432'})),
  'blue': (data,params)=>(barChart(data, {...params, color: '# t'})),
})

接下来,我们将生成一个数据集,并用测试可视化来呈现。

测试数据集很可能是静态的,但是如果我们希望看到可视化在各种数据形状上的表现,那么我们需要用各种底层数据集来测试它。为了在实验中做到这一点,我们将在每次加载图表时使用不同的随机生成的数据集来呈现条形图(因此每个实验参与者都会看到使用不同数据集填充的图表)。

假设我们选择烘焙义卖商品销售作为测试数据集的主题。这很好,有两个原因:1)烘焙销售项目很美味,通常考虑起来很愉快;2)烘焙销售项目是一个广泛熟悉的主题,所以它们对我们的测试参与者来说更容易推理。记住,我们不是在测试工人,我们是在测试可视化。

我们生成测试数据如下…

//Note: if you re-run this cell, it generates a new dataset every time
data0 = ["Brownies", "Cookies", "Cupcakes", "Donuts"].map((treatLabel)=>({x: treatLabel, y: Math.round(Math.random() * 100)}))

(按照惯例,我发现对数据集的变量名及其对应的图表进行编号,可以更容易地跟踪单个实验中的多个图表。这对于我们的单个图表来说显然是矫枉过正了)。

现在我们想看看数据在每个图表变量中的样子。为了在笔记本中方便起见(稍后为了将参与者分配到实验组),我们将定义一个名为chartVariant的变量,然后使用测试数据呈现由chartVariant定义的图表。

但是首先,我们将导入一个单选控件,添加一个 UI 选择器,以便在我们查看笔记本时方便地选择chartVariant

import { radio } from "@meetamit/multiple-choice-inputs"

然后我们将创建chartVariant选择器,同样是为了在我们查看笔记本时方便地选择chartVariant:

viewof chartVariant = radio({
  title: 'Choose Chart',
  description: 'Please choose which chart to evaluate.',
  options: [
    { label: 'Red', value: 'red' },
    { label: 'Green', value: 'green' },
    { label: 'Blue', value: 'blue' },
  ],
  value: 'red'
})

现在,让我们把它们放在一起,看看我们选择的chartVariant在我们的测试数据集上看起来如何。请注意,如果您在单选按钮中选择不同的颜色,图表将在笔记本中自动更新。

chart0 = {
  const chartFn = chartVariants[chartVariant]
  return chartFn(data0)}

然后点击笔记本上的“发布”,我们就完成了 Observable。我们会在机械土耳其人里做其他的事情。

制造轰动

在《土耳其机器人》的世界里,一个击中(“人类智能任务”)是一个“需要答案的问题”。或者,更具体地说,它是一个需要答案的问题的模板。

机械土耳其人给你一吨的灵活性时,建设击中。通过将所有内容包装在一个 HTMLQuestion 元素中,您可以在 HIT 中包含几乎任何任意的 HTML。为了这个实验的目的,我们不需要太花哨的东西,我们只需要建立一个基本的形式。

要设计和构建 HIT,只需在您最喜欢的编辑器中创建一个普通的 HTML 文件。我们将像构建任何普通 HTML 页面一样构建和调试表单,然后在准备就绪时将其复制并粘贴到 Mechanical Turk 中。

HIT HTML 的结构如下所示:

正如您在上面看到的,这是一个基本的 HTML 表单,底部有一些 javascript,用于设置可观察的嵌入和验证表单。

上面遗漏了两个部分,我们将在下面讨论:

  1. 将笔记本元素嵌入该 HTML 的代码
  2. 一种跟踪用户回答问题时的时间戳的方法

将可观察图表嵌入 HTML:

Observable 使得将笔记本的各个部分嵌入到网络上的其他页面变得非常简单。你可以在这里看到他们的指南。

在这个实验中,我们希望将图表嵌入到我们创建的笔记本的最后一个单元格(chart0)中。为此,单击单元格左侧的垂直点,然后从菜单中选择“嵌入代码”。它会向您展示一个如下所示的片段:

<div id="observablehq-befff29e"></div>
<script type="module">
import {Runtime, Inspector} from "[https://cdn.jsdelivr.net/npm/@observablehq/runtime@4/dist/runtime.js](https://cdn.jsdelivr.net/npm/@observablehq/runtime@4/dist/runtime.js)";
import define from "[https://api.observablehq.com/@elibryan/observable-mechanical-turk-guide.js?v=3](https://api.observablehq.com/@elibryan/observable-mechanical-turk-guide.js?v=3)";
const inspect = Inspector.into("#observablehq-befff29e");
(new Runtime).module(define, name => name === "chart0" ? inspect() : undefined);
</script>

上面的内容对于静态用例来说很好,但是我们还需要做一些调整,所以你所需要的就是上面的 URL 路径,看起来像是/@elibryan/observable-mechanical-turk-guide.js?v=3.复制它,并用你笔记本的路径替换下面代码中的路径。

我们将使用以下代码将笔记本图表嵌入到我们的 HIT 中:

我们正在做一些值得注意的事情:

  • 我们正在从 Observable 公司进口笔记本:import define from “https://api.observablehq.com/@elibryan/observable-mechanical-turk-guide.js?v=3";
  • 在开关内部,我们使用return inspect0()呈现图表,并将随机生成的数据集保存到表单中的隐藏元素:document.getElementById("data0").value = JSON.stringify(value);
  • 我们通过从图表变量中随机选择来设置experimentVariant,然后将变量键保存到一个隐藏字段document.getElementById(“experiment-variant”).value = experimentVariant;,这样我们就可以在分析时访问它。我们还更新了嵌入图表的状态,以显示带有observableCharts.redefine(“chartVariant”, experimentVariant);的所选变量

此时,如果您在浏览器中加载 HIT HTML,您应该会看到图表呈现。

提出好的测验问题

在上面的 HTML 中,我包含了两个玩具问题的例子。如果你要在现实生活中运行它,你会希望设计得更仔细一点。查看条形/棒棒糖/圆点实验记录,了解评估图表理解能力的实际调查问题的示例和解释。

跟踪答案时间戳

知道一个图表是否能引导观众找到正确的答案是很重要的。但我们也想确保用户可以快速、轻松地搜索图表。为了确定这一点,我们想知道用户回答关于图表的每个问题需要多长时间。

为此,我们存储用户每次“回答”一个问题的时间戳(即每当他们改变表单中的一个字段时)。然后,当我们进行分析时,我们可以通过从之前的时间戳中减去当前答案的时间戳来粗略了解用户回答一个问题花费了多长时间。

这里的方法并不完美。出于很多原因,您不能将此解释为“用户 X 花了 Y 秒回答问题 Z”,但是如果样本足够大,您可以使用此进行比较(例如,“A 组的用户比 B 组的用户多花了 10%的时间”)。

上面的代码遍历表单中的每个单选按钮和文本输入,并对每个按钮和文本调用addTimeStampFieldaddTimeStampField在每个原始输入字段下添加一个相应的hidden元素。addTimeStampField还将onChange添加到相关的输入事件处理程序中,这样,如果原始输入发生变化,onChange会在隐藏字段中存储当前时间戳,从而节省用户“回答”问题的时间。

就是这样!同样,完整的热门 HTML 的要点可以在这里找到:observable-mturk-experiment-hit.html。这应该既可以在 Mechanical Turk 向导中工作,也可以在浏览器中查看 HTML(这使得构建/调试更加容易)。

接下来,我们将创建一个机械土耳其人项目,并将上述 HTML 复制/粘贴到 HIT 中。

运行实验

要运行该实验,请转到 Mechanical Turk 请求者页面,然后创建一个新项目。创建项目时要记住一些设置:

  • 根据赫尔和博斯托克的说法,你为每次点击支付的金额(“每次回应的奖励”)实际上不会影响回应的质量,但会影响人们对你的点击做出回应的速度。他们建议每个问题支付 0.02 美元,以达到美国的最低工资标准。
  • 在决定受访者的数量(即有多少独特的员工将参与)时,您可能希望选择一个高于您实现适当统计功效所需的数字。因为人们被随机分配到每个实验组,你可能会以不均衡的小组规模结束,一些小组可能会动力不足。
  • 对于工作人员需求,您可以通过设置较高的命中率(例如> = 95%)来获得更好的响应,但是您仍然应该期望随机填写一些答案,并且您将需要一个过程来在实验运行后过滤掉这些答案。

一旦您选择了正确的设置,您将转到设计布局选项卡。它可能会显示一个 WYSIWIG 编辑器,在这种情况下,切换到原始 HTML 视图。然后只需从上面复制/粘贴命中的 HTML。

您可以确保预览和完成屏幕上的一切都正常。您应该可以从您的观察笔记本中看到图表和调查问题。您还应该看到,当您刷新浏览器时,图表会在不同的变量之间切换。

我是谁?不,不,你是谁?!

嗨!我是伊莱·霍德。我帮助客户设计和开发忙碌的人和他们杂乱的数据之间的有效接口。如果你是一名创始人、创客、讲故事者、非营利行善者或商业领袖,正在思考数据、设计和用户心理的交集,我很乐意联系并聆听你的故事。

你可以发电子邮件到 eli@3isapattern.com 给我,或者在推特上关注我。

参考资料:

咀嚼数字。建立模型。预测未来。现在怎么办?

原文:https://towardsdatascience.com/crunch-numbers-build-models-predict-the-future-now-what-3948b82e737f?source=collection_archive---------43-----------------------

菜鸟数据科学家,还是顶级美元价值创造者?你想成为谁?

图片来自皮克斯拜戈登·约翰逊

我可以告诉你去哪里看,但我不能告诉你看什么。

你是一名数据科学家。恭喜你!你的新工作头衔是“21 世纪最性感的工作”。你肯定在做别人做不到的正确的事情。否则为什么你的技能会有很高的需求?不然你为什么会赚到令人羡慕的薪水?已经对未来感到兴奋了吗?有什么可能出错呢?

你是一名数据科学家。告诉我更多。你的具体职责是什么?对大数据进行统计分析?构建可在分布式系统上扩展的数据管道?成为 SQL 和 Python 的专家?了解 docker 和 kubernetes 的一切?在云上部署预测模型?我错过了什么吗?

再问一次,可能出了什么问题?显然,很多!你看,最性感的工作伴随着大量的嗡嗡声。数据科学,作为一个短语,在过去的十年里已经建立了很多宣传。数据科学作为一种功能,同时也失去了它的焦点。它被抛来抛去,覆盖了比它应该覆盖的更多的功能领域。这对你这个几乎不是人类的数据科学家有什么影响?现在应该学习什么新的回归算法?我还应该掌握哪种编程语言?我该何去何从?有一个简单的答案。

跟着钱走。

不,我不是指追逐通常伴随工作而来的高薪和股票期权,或者盲目地学习技能,根据招聘人员的说法,这些技能可以保证六位数的薪水。更确切地说,“钱”是你对公司目标的直接和切实的贡献——这些目标是你公司的领导层,也就是你,被支付报酬去实现的。是收入和收益的增长吗?是最大化客户的快乐和满意度吗?它是在分析你的应用程序的使用数据,以判断你的产品是否符合市场需求吗?是在控制假新闻在社交媒体上的传播吗?它是在制造无需驾驶的自动驾驶汽车吗?

找出答案是你的责任。当你这样做的时候,定义衡量你的公司是否达到其使命和目标的标准。到那时,所有的人工智能、机器学习、测试和实验都将变得有意义。在你开始享受乐趣之前,先了解你的目标。不是所有的公司都严格用金钱来定义他们的成功。一些公司,尤其是早期创业公司,优先考虑中期目标,这些目标有望为他们未来的成功奠定基础。你的公司愿意烧钱和放弃短期利润来优先考虑客户的幸福吗?如果你还不知道,那就离开你的办公桌去问你的老板。如果你的老板不知道答案,那就去问其他知道答案的人。

“那又怎么样?”

你曾经在完成 15 分钟的演示和一个小时的分析练习后被问过这个问题吗?作为一名有抱负的数据科学家,我的职业生涯从数据工程开始,然后过渡到高级分析和机器学习。我喜欢解决复杂的统计问题和优化问题。和我的同龄人一样,我也痴迷于 python 中最新的大数据工具,尤其是每六个月就有一款新工具问世的时候。如果你追求错误的目标,这一切都没有用。

数据科学是达到目的的手段。它本身并不是目的。

我们不都犯过那些新手的错误吗,比如没有花时间可视化数据,或者在运行分析之前没有识别偏差?当你被天花乱坠的宣传搞得心烦意乱时,你解决不了任何问题。然而,最有害的影响是忘记了你更大的职业目标,这些目标最初让你成为了一名数据科学家。现在,让我告诉你一个好消息。当然,如果你愿意对自己诚实,纠正你的思维过程会更容易。跟着钱走就行了。但是,你可能会问,怎么做呢?这是一个实际可行的框架。

如果你认为你创造了很酷的东西,问问你自己——那又怎样?

是的,你就是那个建立了一个二进制分类器的高手,它有 95%的准确率和一条让你的研究生院机器学习教授骄傲的 ROC 曲线。现在,你能不能用一句话解释一下你想解决的问题是什么?在数据科学中钻研“科学”并觉得自己很重要确实很有诱惑力。然而,除非你真正理解了你试图回答的问题,否则你的工作不会太重要。你可能知道指示你的模型离事实有多远的诊断工具。它们能帮助你和你的利益相关者做出可行的商业决策吗?

相对于随机选择的结果,你的发现有多不确定?

学会定义衡量你想要的结果的标准。根据你的模型减少不确定性的能力来判断你的结果,并给它一个美元值。数据科学社区不断有引人注目的新发展。不要犯不知所措的错误。相反,退一步,想想值得解决的问题,让你的公司和你的职业朝着正确的方向前进。

处理奥斯卡外语片的数据

原文:https://towardsdatascience.com/crunching-the-data-of-the-foreign-language-oscar-fe435716b66?source=collection_archive---------38-----------------------

《寄生虫》让历史赢得了最佳影片,但它也证实了外语类影片的一种新趋势

去年的奥斯卡季中,我们分析了哪些奥斯卡提名更有可能赢得最佳影片的数据,并跟踪了有强烈女性表演的电影与只有男性表演提名的电影的成功。

今年,随着韩国电影《T2》的热播,我们仔细研究了奥斯卡外语片的数据。以下是我和我的合作伙伴若昂·席尔瓦创建的数据 viz,我将分两部分对其进行简要评论。

欧洲独霸奥斯卡最佳外语类奖项

欧洲国家总共获得了 51 个最佳外语片奖

自 1956 年以来,奥斯卡最佳国际故事片奖(Academy Award for the best International Feature Film)每年都会颁发给在美国以外制作的、对白主要为非英语的长篇电影。我们数据的第一部分 viz 使用了一个由旗帜组成的条形图来显示全球四个地区的成功分布情况。

不可否认,这是由欧洲国家的电影主导的——意大利获得了 11 项奥斯卡奖,其次是法国,是最成功的两个国家。这两个国家帮助欧洲获得了 80%的奖项,而美洲只获得了 8%,非洲制作了 5%的获奖电影。昨晚之前,亚洲排名第三,但随着《寄生虫》赢得最佳外语片奖(击败四个欧洲候选人),亚洲现在与美洲持平,获得 5 个奖项。

但是奥斯卡获奖者有一个新的趋势

在过去的 20 年里,50%的获奖者都不是欧洲人

看看我们数据的第一部分,你可能会认为这纯粹是欧洲占主导地位的故事。但在第二部分,我们在时间线上绘制了非欧洲的胜利,以突出一个新的趋势。阿尔及利亚电影《T4》Z 是第一部在 1969 年获奖的非欧洲电影。象牙海岸在 20 世纪 70 年代获得了唯一一个非欧洲奖项,而阿根廷的一部电影在 20 世纪 80 年代代表了世界其他地区。

从 2000 年开始,随着亚洲第一部获奖电影卧虎藏龙的问世,一种新的潮流开始形成。在过去的 20 年里,现在 50%的获奖者都是非欧洲人,寄生虫证实了这一类别中新形式的多样性。

昨晚,《寄生虫》成为第一部赢得最佳影片最高奖项的外语电影——这一成就是备受赞誉的墨西哥罗马去年未能实现的,也是这一类别中最成功的国家 1998 年未能与精彩的意大利生活是美丽的实现的。这有望为更多关注非英语电影打开大门,或者至少延续比过去更加多样化的外语电影类别的趋势。

我们如何创建我们的数据,即

我们梳理了这一类别的奥斯卡数据,并决定按世界地区(欧洲、亚洲、非洲和美洲)对奥斯卡获奖作品进行分类。然后,我们使用基于浏览器的 UI 和 UX 设计应用程序 Figma 来设计数据,即。

我们使用国旗下载获奖电影的原产国国旗的图像,以形成条形图,每个国家的获奖数量都有重复的旗帜。我们在时间表中再次重复使用旗帜来显示获奖电影的年份,省略了欧洲国家。这清楚地显示了过去 20 年中非欧洲国家的集群。

粉碎零售葡萄酒数据

原文:https://towardsdatascience.com/crushing-retail-wine-data-with-selenium-and-python-f16a13e046a4?source=collection_archive---------19-----------------------

现实世界中的 DS

使用 Selenium 和 Python

照片由阿克谢·肖汉Unsplash 上拍摄

在我的上一篇文章中,我谈到了网络抓取作为一种工具,通过从相关零售和电子商务网站中提取知识来帮助你关注竞争或定价趋势。

今天,我们将仔细看看这个过程。我们将用简单的调查术语(谁、什么、为什么、在哪里和如何)来处理它,因为为你的刮擦设置策略将帮助你更快地通过这个过程。

我们还将分享一些使用 Python 和 Selenium 包收集数据并将其压缩成可以操作的数据帧的技巧。

在开始之前,您需要确保您的 Selenium 包安装在 Python 中,并且 ChromeDriver 设置为与 Selenium 一起运行。有关设置 SeleniumChromeDriver 的更多信息,请点击以下链接。

世卫组织(您将从中获取信息的网站)?

当你浏览一个网站时,要考虑三个关键因素:

  1. 查看网站的条款和条件,确保您没有违反任何潜在协议。你很可能不希望失去对网站的访问,所以花一些时间了解他们是否会对你抓取他们的数据有意见。在接下来的讨论中,我们将假设一个站点可以被你浏览。
  2. 评估你感兴趣的网站。考虑给谷歌 Chrome 添加一个像 BuiltWith 这样的技术剖析器,从顶部了解网站是如何构建的,是什么让它运行的(这将有助于你以后识别元素)。你还将利用谷歌的元素面板来检查你将可以抓取哪些元素(稍后会有更多相关内容)。此外,注意你与网站的交互方式——如果网站返回的结果没有巨大的滚动,你很幸运,如果它是一个无限滚动的网站(像脸书或 Twitter ),你可能需要在代码中考虑一些额外的选项。
  3. 识别一个完整的网址:当你用 Python 写代码时,你需要识别你想要访问的特定网址。我的建议是访问该网站,输入标准来执行您希望进行的任何搜索,并捕获结果网址,以便在发送您的 web scraper 之前满足您的标准。准备好那个网址,作为设置你的网页抓取代码的第一步,通过 Selenium 告诉 ChromeDriver 到底要打开和抓取什么网站。

右键单击页面上的任何文本、图像或价格点,以访问检查功能并打开元素面板

(我们要找的)是什么?

如上所述,我们依靠谷歌的 Inspect 功能和元素面板窗口来检查哪些元素你可以抓取。右键点击页面上你感兴趣的任何一项(图片或文字),在弹出的菜单中,向下滚动到“Inspect”并点击(见上图)。

这将带您进入元素面板,以便您可以查看站点的文档对象模型(DOM)树,并找到您要提取的元素的正确标识符。

页面上的每个元素都将被引用到 DOM 上的一个节点。面临的挑战是为您需要的每个元素找到最有效、最可靠的定位器。幸运的是,Selenium 为您提供了一个工具箱,里面装满了可供选择的工具,因此,无论是哪个网站,您都有很大的机会使用以下命令找到您需要的东西:

  • 按 ID 查找元素
  • 按名称查找元素
  • 按类名查找元素
  • 通过 XPath 查找元素
  • 通过 CSS 选择器查找元素
  • 通过链接文本查找元素
  • 通过部分链接文本查找元素
  • 通过标记名查找元素

您可能需要试验其中的一些定位器类型来获得您想要的结果,并且您可能会发现通过在整个代码中使用多个定位器来访问您想要抓取的元素是最好的。互联网上有很多关于部署这些 find 命令的最佳方法的建议。对于本例,我们将使用“按类名查找元素”,如下所示:

当您检查图像或文本时,它会引导您找到它在 DOM 中的元素标识符。这里是一个类名,“vintage title _ _ wine—U7t9G”

在您的代码中,您将调用这个元素来帮助将所需的相关文本抓取到您的文件中—参考第四行:wine = browser . find _ elements _ by _ class _ name(" vintage title _ _ wine—U7t9G ")

(在 GitHub Gist**可以访问上面的代码片段 )

为什么(我们这样刮?)

使用 Python 和 Selenium,有一种更简单的方法将所有信息放入一个列表中——但是结果非常冗长、麻烦且难以操作。

然而,为了能够更有效地处理数据,并最终将它放入我们可以管理的 Python Pandas 数据帧中,我们将使用一个两步过程来定位各个元素,然后访问相关的文本。

这些元素在哪里?

这些元素遍布站点的 DOM 树。因此,对于我们的两步过程,我们的第一步是识别所有的元素,第二步是运行一个简单的 for/循环来遍历每个元素,让 selenium 为我们的审查挑选最好的文本。

在上面的代码中,我们建立了五个单独的列表来存放我们的元素集合。当我们遍历每一个单独的元素列表时,我们将创建五个新的文本列表,它们都是相互对应的。因此,在这个具体的例子中,我们收获了我们的 winery 元素,并用 Selenium 为我们精选的最好的数据粉碎了我们的 winery_list。

Selenium 将收获关键元素,然后我们会告诉它用 for 循环粉碎相应的数据。

如何(我们现在使用这些信息)?

我们现在有五个伟大的列表提供我们收集的数据,我们只是一个简单的 Python 字典,将我们的列表压在一起,形成一个数据帧,我们可以清理,分析,添加,然后提供并与我们的同事分享我们的见解。

一个简单的字典代码,将我们的五个列表压缩成一个单一的数据框架

(在 GitHub Gist 这里 可以访问上面的代码片段)

我们的最终数据框架(在清洁、EDA 或特征工程之前)

如您所见,生成的数据框架以一种我们可以分析并从中获得更多价值的方式汇集了我们的数据,更不用说我们已经建立了一个相对简单的程序来在需要时更新我们的信息。

总的来说,网络抓取可以为我们提供很好的自动化数据访问,这反过来帮助我们获得洞察力,推动我们的业务向前发展。在我们开始写代码之前,建立我们的抓取策略(并考虑谁、什么、哪里、为什么和如何),对获得我们想要的结果有极大的帮助。

直到下一次…

干杯!

使用 Python 进行股票和加密货币的均值-方差分析

原文:https://towardsdatascience.com/cryptocurrencies-the-new-frontier-part-1-940e787c7ab9?source=collection_archive---------14-----------------------

照片由 Clifford 摄影Unsplash

Python,均值-方差分析,有效边界以及加密货币如何拓展边界。

加密货币多年来一直是一个热门话题,这是有充分理由的。对一些人来说,它们是一个黑匣子,对另一些人来说,它们是金融不可避免的未来。不用说,任何人,只要花了至少一部分时间和金钱投资股票和其他资产,近年来都会考虑投资这种新颖的资产类别。

在本文中,我将从均值-方差的角度分析将加密货币纳入传统股票投资组合的影响。本分析的目的不是给出投资建议或对未来做出预测,而是展示为什么考虑将加密货币等替代资产类别与股票一起纳入投资组合是值得的,不管你对它们的看法如何。

如果你对加密货币、金融理论、投资或使用 Python 编程感兴趣,这篇文章是为你准备的。我将深入基础金融理论,并解释如何使用 Python 执行均值-方差分析。虽然这些是复杂的数学主题,但我将主要关注底层逻辑,因为太多的公式会使任何事情看起来比它需要的更复杂。

这篇文章的结构如下:

  1. 简要财务概述
  2. 解释均值-方差分析
  3. 将均值-方差分析应用于股票
  4. 使用 Python 计算有效边界
  5. 使用 Python 计算资本市场线
  6. 向投资组合中添加加密货币并调查结果
  7. 比较加密货币与其他替代资产的效果
  8. 结论意见

本文的第 1 部分涵盖了第 1 点到第 5 点。您可以在这里找到将加密货币引入投资组合的部分:

[## 加密货币——新的前沿

Python、均值-方差分析、有效边界以及加密货币如何拓展边界

towardsdatascience.com](/cryptocurrencies-the-new-frontier-part-2-7218c6a489f9)

金融中的一些重要措施

提到股票价格(以及一般的任何资产价格)时,最重要和最常用的两个指标是回报率和波动性。

我们所说的回报率通常是指收益率,最常见的形式是简单收益率和对数收益率。要了解这两者之间的区别,请看这篇博客文章。现在,把回报想象成股票价格在给定时间间隔内的百分比变化,也就是说,如果某个股票价格今天是 100 美元,明天跳到 105 美元,回报(简单回报率)是 5%。

对于波动性,我们指的是回报的标准差,即回报方差的平方根。方差是对收益数据集分布程度的一种度量。因为方差是使用平方偏差计算的,所以它与原始观测值没有相同的测量单位。取平方根,即计算标准偏差,将这种测量转换成相同的单位,从而使分布的测量更容易解释和跨数据集比较。更大的利差意味着更多的上下波动,这就是为什么在金融中标准差通常是风险的衡量标准。更多关于标准差这里

投资者通常会查看平均回报和风险来比较股票并做出投资决策。一般来说,与债券等其他资产相比,股票往往相对不稳定,降低投资股票风险的一种方法是投资多只股票。这就是习语“不要把所有的鸡蛋放在一个篮子里”的实际执行,被称为多元化。

分散投资或通过投资多只股票来降低整体投资组合风险背后的直觉是,选择价格和回报不会同步波动的股票。这样,如果一个下降,另一个可能保持不变或上升。你可以认为这是一种“平衡”。将历史上从未一起波动的股票包括在内,会使投资组合更加平衡。

当我们分析由多只股票组成的投资组合时,我们希望能够计算整个投资组合的预期收益和方差,而不是单只股票的预期收益和方差。为了做到这一点,除了它们的平均回报和标准差之外,我们需要知道投资组合中股票的两个度量之一:它们的协方差或相关性。

协方差和相关性是两个变量之间关系和依赖性的度量。本质上,相关性只是协方差的标准化版本,它测量两个变量之间线性关系的强度和方向。相关性的可能值介于-1 和 1 之间。正相关意味着两个变量趋向于同向移动,负相关意味着两个变量趋向于反向移动,零相关意味着变量之间没有关系。因此,对于投资组合多样化来说,最好的建议是组合那些回报具有低相关性或负相关性的股票(想想“平衡”的类比)。

计算投资组合的预期收益和方差的数学方法超出了本文的介绍范围,但是这篇博客文章用一个双资产投资组合提供了一个很好的解释。我们现在需要知道的是,整个投资组合的预期收益是投资组合中个股预期收益的加权平均值。投资组合的预期方差有点复杂,但本质上是单个股票的方差、它们在整个投资组合中各自的权重以及每对股票之间的相关性的产物。

什么是均值-方差分析?

均值-方差分析,通常被称为现代投资组合理论(MPT ),是一种关于投资组合构建的理论,由 Harry Markowitz 于 1952 年首次提出,后来他获得了诺贝尔经济学奖。该理论背后的主要思想是,通过调整投资组合中单个资产的权重,有可能构建最佳投资组合,在给定的风险水平下,提供最大可能的预期回报。MPT 的一个关键观点是,单个资产的回报率和波动性不应由其本身来评估,而应根据它对投资组合整体回报率和波动性的贡献来评估。

最佳投资组合,即在给定风险水平下最大化预期回报或在给定回报水平下最小化预期波动性的投资组合,可以绘制在图表上。连接最优投资组合的线将是一条向上倾斜的双曲线,它被称为有效边界。之所以称之为“有效”,是因为在给定的风险水平下,基于它的投资组合能提供最高的预期回报。

让我们看看使用 Python 应用均值-方差分析是什么样子的。对于接下来的部分,假设对 Python 有一个基本的了解,但是即使没有它,基本的逻辑和结论也将是清楚的(我强烈建议那些真正想了解 Python 的人搜索未知的 Python 术语)。

将均值-方差分析应用于股票

在开始分析之前,我们需要将股票价格数据导入 Python。令人欣慰的是,Pandas 有一个名为 pandas-datareader 的子程序包,可以很容易地从各种互联网资源中提取数据,并放入 pandas DataFrame 中。我将从雅虎财经中提取股票价格数据。但是我们如何决定提取哪些股票价格数据呢?

在这个例子中,我关注了标准普尔 500 中的 30 只股票。为了简单起见,我假装是一个业余投资者,他知道为了有一个多元化的投资组合,建议投资组合中有 15 到 30 只股票。因为我也知道来自不同行业的股票往往比来自同一行业的股票相关性更低,所以我试图构建投资组合,使其中包含的股票来自许多不同的行业。因为我有点懒,我就查了一下标准普尔 500 的成分,找到了一个按权重排序的列表,浏览了一下列表,从不同行业挑选了股票,直到我有了一个 30 只的列表。这绝不是选择股票的好策略,而且在我们的样本中必然会导致生存偏差,但为了简单起见,这已经足够好了(这也类似于许多人会考虑的相当多样化的投资组合)。

在接下来的内容中,我将包括最重要的代码块和可视化。完整的笔记本可以在这里找到

下面是从 Yahoo Finance 中提取股票价格数据的代码:

这一提取提供了近五年的股票价格数据。我选择 2015 年 8 月 6 日作为开始日期的原因将在后面的分析中变得清楚。在我继续均值-方差分析之前,让我们简要地看一下这个分析中包含的股票价格的演变。以标准化方式绘制时间序列股票价格数据会产生以下图形:

正如时间序列显示的那样,亚马逊等一些股票在过去五年里取得了令人印象深刻的涨幅。似乎新冠肺炎的传播也导致了 2020 年初所有股票价格的大幅下跌。另一个观察结果是,尽管有不同的轨迹,股票价格往往一起移动,这意味着它们是正相关的。稍后将详细介绍。

正如我前面提到的,MPT 的主要思想围绕着寻找一个投资组合中的股票权重,在给定的波动水平下,这些股票可以带来最高的预期回报。但是我们如何计算出这些“最佳”重量呢?

在我继续之前,我想介绍两个公式,它们将是分析的基础(我知道我说过我将主要关注底层逻辑,但是这些公式对于理解下面的代码是必不可少的)。对于这两个公式以及随后的所有计算,我们假设只允许多头头寸(即只买入股票,不卖出股票),并且头寸总和为 100%(即权重总和为 1)。第一个是投资组合的预期回报公式:

资料来源:Yves Hilpisch 的《金融 Python》

在上面的公式中,历史平均收益被假定为预期收益的最佳估计值,并被假定为正态分布。最后一个等式是投资组合的预期收益是单个资产预期收益的加权平均值,以向量乘法的形式表示。

第二个基本公式是投资组合的预期方差公式:

资料来源:Yves Hilpisch 的《金融 Python》

上述公式中的最后一个等式只是资产权重向量乘以协方差矩阵和资产权重向量的乘积的转置。

翻译成 Python,这两个公式都可以归结为一行代码,我将很快展示。回到资产的权重。

因为目前我们不知道“最优”资产权重是多少,所以一个好的开始是运行蒙特卡罗模拟,在其中我们随机分配 0 到 1 之间的权重(以权重相加为 1 的方式)。然后,我们计算由此产生的投资组合的预期收益和方差,重复这些步骤,无论我们认为需要多少次,并绘制结果。

我定义了一个函数,它将每日回报的数据帧和一个数字 N 作为输入,N 告诉函数要运行多少次模拟。值得注意的是,收益和(共)方差的“年化”是在收益相互独立且同分布的假设下计算的:

当使用 30 只股票的每日日志回报和 5,000 次模拟调用该函数并绘制结果时,我们得到以下散点图:

在散点图中,我根据夏普比率给点着色。夏普比率是金融中最常见的风险回报指标之一。它被定义为一项投资的超额回报(即超过无风险利率的回报)除以该项投资的波动性。计算夏普比率可以很容易地比较不同风险回报的投资。一般来说,夏普比率越高越好。在这个项目中,我假设无风险利率为 1%。

在下一节中,我将解释我们如何从随机生成的投资组合分散到计算有效边界。

使用 Python 计算有效边界

正如我前面提到的,有效边界是由所有的最优投资组合组成的,这些最优投资组合是由可用于组成这些投资组合的股票组成的。正如“最优投资组合”这个名字所暗示的,寻找构成这些投资组合的权重归结为一个优化问题。但是我们优化什么呢?

让我们考虑一下。我们希望找到在给定风险水平下具有最大预期回报的投资组合。由于 Python 的 SciPy 库中优化函数的设置方式,我们不得不将它重新定义为最小化问题。对于给定的风险水平,寻找具有最大期望回报的投资组合等同于对于给定的期望回报,寻找具有最小风险水平的投资组合。

我们需要做的是定义一个返回重要投资组合统计数据的函数:预期回报、波动性和夏普比率。在设置了最小化函数中使用的一些约束和初始权重后,我们可以调用该函数并生成预定义数量的最优投资组合,我们可以绘制这些投资组合并用于进一步分析。下面的代码就是这样做的:

调用 30 只美国股票的有效边界函数,并将其绘制在随机生成的投资组合散点图的顶部,会得到以下图形:

在上面的观想中,我包括了三颗星星。

蓝星代表最小方差投资组合。每一个位于该恒星上方和右侧的“x”构成了有效边界。位于蓝色星号下方和右侧的“x”不是有效的,因为很明显,具有相同预期波动率(x 轴值)的投资组合具有更高的预期回报(y 轴值)。

红星代表最大夏普比率投资组合,白星代表 5000 个随机生成的投资组合之一。

对于一些人来说,尤其是那些在大学或其他地方看过有效边界可视化的人,可能会感到困惑,为什么位于有效边界上的 x 距离随机生成的投资组合如此之远。其原因是,在沿着有效边界的投资组合中,许多股票被赋予了零权重,因为这是给定波动率下的最大回报。在蒙特卡洛模拟中,每只股票都被赋予一个介于 0 和 1 之间的权重,由于所包含股票的风险回报和协方差特征,这不会导致最优的投资组合分配。以下是最大夏普比率投资组合与白星代表的投资组合的配置比较:

比较最优和次优投资组合的权重分配

权重比较显示,随机选择的投资组合过度分配给不太“有价值”的股票(这里的有价值是指增加投资组合的多样化,同时也有助于预期回报),而不足分配给更“有价值”的股票。

但是为什么最优投资组合只将资本分配给一部分股票呢?例如,为什么亚马逊在投资组合中占据了 50%以上的份额?为什么谷歌没有投资,但麦当劳却获得了大约 10%的资本分配?

通过查看股票的相关矩阵,并记住上表中显示的预期年回报率,我将提供一个基本逻辑的简单解释。整个相关矩阵太大,无法在此列出,但可以在笔记本中找到。

亚马逊在最大夏普比率投资组合中占据如此大的一块,原因很简单,因为它迄今为止的预期回报率最高,年回报率为 35.5%。此外,如果你考虑到亚马逊的预期波动性,它的吸引力就变得更加明显了。尽管拥有最高的预期回报率,但它的波动性在所有股票中仅排在第七位。事实上,亚马逊的预期波动性与摩根大通非常接近,后者的预期年回报率为 9.2%。

谷歌在最大夏普比率投资组合中的权重为零的原因是因为它是回报与亚马逊的相关性最高的股票。因为亚马逊已经在投资组合中占据了如此大的一部分,以分散投资,从而降低整体投资组合风险,所以剩余的权重需要分配给回报率与亚马逊相关性较低的股票。

这就是麦当劳的用武之地。它的股票回报率与亚马逊股票的相关性最低,这就是为什么尽管回报率平均,但从整个投资组合的角度来看,将它加入投资组合是有价值的。

必须谨慎地做出类似这样的简化陈述,因为在投资组合配置中,人们不能仅通过查看两只股票的风险回报情况和它们之间的相关性来得出任何结论,而是始终需要将投资组合视为一个整体。话虽如此,我认为使用亚马逊、谷歌和麦当劳的例子是理解底层逻辑的一个很好的起点。

短暂的转移话题后,让我们回到有效边界。在这一点上,有效边界的观想只包括单个的点,但是为了使它成为一个合适的边界,我们希望它是一条连续的线。为了使用构成有效边界的现有点创建一条连续线,我们可以插入数据点的 B 样条表示。听起来令人困惑,数学相当先进,但本质上 B 样条插值所做的是将曲线拟合(即近似)为一组点。这使我们能够把有效边界画成一条连续的线,但它也给了我们一个有效边界的连续函数,这在下一节会派上用场。

生成的连续曲线如下所示:

现在我们有了作为连续函数的有效边界,我们可以计算资本市场线。

使用 Python 计算资本市场线

到目前为止,我只考虑了由风险资产(这里是股票)组成的投资组合,但如果我们考虑无风险投资(通常是大型银行的现金账户)与风险投资相结合,会怎么样呢?

事实证明,这是资本市场线(CML)背后的基本理念。本质上,该理论建议投资者首先确定一个有效的风险资产组合(正如我们所做的那样),然后在组合中加入一种无风险资产。正如我将很快展示的,将无风险投资与高效投资组合相结合,会极大地增强投资者的高效投资机会。

我们选择与无风险投资相结合的有效投资组合,是指有效边界的切线在绘制有效边界的 y 轴上恰好穿过无风险投资的回报。对于利率为 1%(即其回报率)的无风险投资,y 轴上的点将是(0,0.01)。

你们中的一些人可能还记得微积分课程(这里是给那些不知道的人的链接)我们可以用一个函数的一阶导数来找到这个函数在特定点定义的曲线的切线。这就是 B 样条插值给了我们一个连续(可微)函数的事实派上用场的地方。使用该连续函数及其一阶导数,结合一些条件,我们可以求解 CML。为了找到资本市场线,我们使用 SciPy 的 fsolve 函数(它找到一个连续函数的根),条件如下:

资料来源:Yves Hilpisch 的《金融 Python》

换句话说,第一个条件意味着在 x=0 时,函数必须等于无风险利率的回报,即 CML 的直线必须通过 y 轴上的该点。第二个条件简单地说明,对于 x 的任何值,函数必须满足线性函数方程(有些人可能记得在高中时写为 y=mx+b)。第三个条件规定函数的一阶导数必须等于参数 b,即斜率。

允许我们求解有效投资组合的代码是这样的,切线穿过 y 轴上无风险资产的收益:

这导致了以下资本市场线:

在上面的图像中,蓝色的星代表有效的投资组合,切线穿过无风险利率。至少根据现代投资组合理论,通过将无风险投资添加到有效投资组合中,投资者可以通过调整投资于无风险资产的财富比例,获得位于无风险资产和有效投资组合之间直线上的任何风险回报组合(甚至通过借钱超越该点)。投资于无风险资产的比例越大,你就越接近 CML 的原点,反之亦然,(风险)有效投资组合的比例越大,你就越接近蓝星。

下面是上述可视化的放大版本,以便与之前的版本进行比较:

随着 CML 的计算和绘制,本文的第一部分已经完成,我们可以继续分析在投资组合中包含加密货币会产生什么影响。你可以在这里找到文章的第二部分。

加密货币——新的前沿

原文:https://towardsdatascience.com/cryptocurrencies-the-new-frontier-part-2-7218c6a489f9?source=collection_archive---------26-----------------------

照片由 Clifford 摄影Unsplash

Python,均值-方差分析,有效边界以及加密货币如何拓展边界。

在这篇文章的第一部分中,我使用了 30 只来自不同行业的美国股票来计算有效前沿和资本市场线(CML)。在本文的这一部分,我将把加密货币添加到组合中,并分析它们对投资组合的影响。

让我们快速回顾一下到目前为止我们所知道的。由于一些股票的风险回报状况,特别是亚马逊,由此产生的有效投资组合显示了令人印象深刻的风险回报状况。由此得出的 CML 的斜率为 1.21,这是沿着这条线的任何财富分配的夏普比率。最优(正切)投资组合的预期年收益率为 27.4%。有效边界和资本市场线看起来像这样:

有可能把这些数字推得更高吗?如果是这样,我们会怎么做?

正如我在本文第 1 部分中提到的,增加与现有投资组合不相关的资产并获得可观的回报,可能会改善整个投资组合的风险回报状况。让我们使用一些流行的加密货币来实现这一点。

关于如何计算最优投资组合的详细描述,Python 中的有效边界和资本市场线请看本文的第一部分:

[## 使用 Python 进行股票和加密货币的均值-方差分析

Python,均值-方差分析,有效边界以及加密货币如何拓展边界。

towardsdatascience.com](/cryptocurrencies-the-new-frontier-part-1-940e787c7ab9)

将加密货币加入投资组合

首先,我们需要导入加密货币价格数据,我们可以将这些数据添加到我们迄今为止分析的 30 只美国股票的价格数据中。在这篇分析中,我重点关注四种最知名和最大的加密货币(就市值而言):比特币、以太坊、Tether 和莱特币。

绘制加密货币价格随时间变化的归一化时间序列如下图所示:

关于上述时间序列的一些观察结果:

  1. 用正常的术语来说,以太坊在 2018 年经历了极端的峰值。
  2. y 标签刻度的增量为 10,000(与第一部分中的股价时间序列的 y 轴相比)!).
  3. 看起来莱特币、以太币和比特币似乎倾向于一起移动(即相关),但 Tether 没有显示相关性,甚至没有移动。

因为上图中正常化的时间是 2015 年 8 月 6 日(这是以太坊价格被纳入雅虎财经的第一天),这是一个加密货币极其新颖且价格非常低的时期,y 轴的刻度一直上升到 50,000。以太坊的起价为 2.77 美元,2018 年最高达到 1396.42 美元,几乎是起价的 504 倍。这显然是一个非常特殊的案例,我将在稍后对此进行评论。

上述时间序列揭示了一条对任何投资者都很直观的经验法则(但也可以说在生活中有更广泛的应用),即更高的回报往往伴随着更高的风险。在这段时间内,投资加密货币的回报可能是巨大的,但时间序列图有很多起伏,在以太坊的情况下,非常极端,使它们非常危险。

在提取相关的加密货币价格并计算每日日志回报后,我很好奇加密货币价格的回报与股票回报之间的相关性。完整的相关性矩阵可以在笔记本中找到,但总结一下,在 2015 年年中到 2020 年年中的时间段内,加密货币回报和股票回报之间几乎没有相关性(至少对于本分析中包含的那些来说)。

加密货币似乎与现有投资组合中的任何股票都几乎不相关,加上它们令人印象深刻的回报,这一事实表明,从均值-方差的角度来看,将它们加入投资组合可能是有益的。让我们看看那是什么样子。

在上面的可视化中,蓝色聚类表示仅基于股票的随机生成的投资组合,橙色聚类表示基于股票和加密货币的随机生成的投资组合。橙色集群在 x 轴上分布得更广,这意味着基于股票和加密货币的随机生成的投资组合具有更广泛的可能风险,特别是朝着风险更高的一端。与此同时,即使风险水平相同,橙色集群也往往位于蓝色集群之上,表明橙色集群的风险回报状况更好。

同时使用股票和加密货币可以实现的有效边界位于仅使用股票的有效边界的上方和左侧,因此可以为任何风险提供更高的回报。

红星代表最大夏普比率投资组合,根据聚类和有效边界,使用股票和加密货币构建的投资组合提供了更高的回报,但也带来了更多的风险。纯股票投资组合和组合投资组合的夏普比率分别为 1.21 和 1.49。

画出各自的资本市场线使画面完整:

将加密货币添加到组合中,并将由此产生的高效投资组合与无风险投资相结合,可以提供比仅使用股票和无风险投资更高的风险回报。

在这一点上,有些人可能会说,“但是,等一下,你所做的只是将一种回报率几乎不相关的资产添加到投资组合中,难道你不能用任何回报率接近与投资组合不相关的资产,如黄金或白银,来实现同样的目标吗?”这是一个很好的观点。让我们看看那个。

黄金和白银与加密货币

在这一节中,我将遵循我用于将加密货币添加到股票投资组合中的相同步骤,但我将把黄金和白银添加到投资组合中,而不是加密货币。

首先,让我们再来看看标准化的时间序列:

一些观察结果:

  1. 用正常的术语来说,在特定的时间段内(尤其是临近尾声的时候),黄金的表现优于白银。
  2. 黄金和白银价格似乎密切相关。
  3. 新冠肺炎事件导致了黄金和白银的震荡,但白银受到的冲击尤为严重。

查看黄金、白银和所选的 30 只股票之间的相关性矩阵(可在笔记本中找到)突出了一个有趣的事实,这一组新的可用资产与之前的略有不同。与加密货币的回报大多与股票的回报呈小正相关不同,黄金和白银的回报与所选股票的回报呈小负相关(超过 5 年的时间段)。此外,黄金的波动性相对较低,但回报也不错。由于其优越的风险回报状况,黄金在所有最优投资组合中具有一定的正权重,而白银的权重为零。

基于黄金的这两个特征,即与大多数股票的负相关性和良好的风险回报状况,将黄金加入投资组合可以降低包括加密货币在内的货币无法实现的风险(因为它们与股票的相关性大多为正)。让我们看看有效前沿是如何比较的。

在上面的可视化中,绿色聚类稍微集中在蓝色聚类的左侧,但在垂直位置上大致处于相同的水平,这意味着将黄金和白银添加到投资组合中会产生随机投资组合,与只有股票的投资组合相比,其预期回报大致相同,但风险较低。

有趣的是,对于相对较低的风险水平(x 轴上的 0.1 到 0.15 之间),股票和黄金以及股票和加密货币的有效边界似乎几乎重叠。我将很快放大到有效边界的那一部分。

红星代表最大夏普比率投资组合,由股票和黄金组成的最大夏普比率投资组合位于仅由股票或股票和加密货币组成的投资组合的下方和左侧。这进一步表明了将黄金加入投资组合的影响:它具有降低风险的效果,但由于其有限的预期回报,也降低了可以实现的回报。

放大股票和黄金以及股票和加密货币的有效前沿为我们提供了一个有趣的视角:

存在一个小的预期波动窗口,其中使用股票和黄金构建的最优投资组合实际上提供了比使用股票和加密货币构建的最优投资组合略高的预期回报。

最后,让我们比较一下资本市场线(为了保持形象清晰,我省略了有效边界):

使用由股票和黄金组成的有效投资组合结合无风险投资可以实现的 CML 介于仅股票和股票与加密货币之间。它的斜率更接近股票和加密货币的 CML。一个重要的注意事项是,蓝星代表最优投资组合,其切线穿过无风险利率截距。如果我们假设没有借款(出于多种原因,但主要是因为借款利率往往不同于投资利率),这些蓝星也是沿着 CML 可以实现的有效投资集的极限。这意味着,尽管其斜率接近使用股票和加密货币的 CML 的斜率,但使用股票和黄金的 CML 的有效投资集在可实现的预期回报方面要有限得多。这是与比特币和以太坊相比,将黄金作为替代资产纳入投资组合的主要区别之一。

对于那些对将所有三种资产类别(股票、密码和金属)结合在一起或引入其他资产类别的效果感兴趣的人,我相信你现在可以自己尝试一下了(如果你遇到困难,请随时联系)。

结论意见

虽然本文中的分析得出了一些有趣的发现和令人印象深刻的风险回报结果,但我想再次说明,这绝不是投资建议,也不能在未来以任何方式复制。我想强调分析的几个非常重要的方面:

  1. 该分析基于历史股票价格,这意味着最优投资组合的计算是事后诸葛亮。没有理由相信这些也将是未来的最优投资组合配置。
  2. 被包括在内的股票的挑选方式受到生存偏差的影响。这些股票是通过简单地浏览当今标准普尔 500 中的顶级股票列表来挑选的,这意味着为了接近该列表的顶部,它们必须在最近几年中表现相对良好。因此,在我分析的时间范围内,这些股票注定会有不错的风险回报。
  3. 加密货币在本次分析期间经历了令人难以置信的价格上涨,这种情况不太可能再次发生(至少以类似的方式)。
  4. 根据均值-方差分析,最优投资组合的投资组合配置可能是最优配置,但这并不意味着只投资于少数股票,当这些股票组合成一个投资组合时,可以产生高夏普比率,从而形成一个非常多样化的投资组合,特别是从长期来看。原因是投资组合风险的重要维度超出了标准差。其中一个维度是终极财富转移(TWD),更多信息请见这里的。
  5. 仅仅因为某个资产类别与另一个资产类别不相关,并不意味着将其加入投资组合是有益的。Tether 就是一个很好的例子。由于其作为由法定货币支持的“稳定硬币”的性质,Tether 不会给投资组合增加任何回报。在投资任何资产之前进行研究是非常重要的,这对于加密货币尤其重要!
  6. 现代投资组合理论的一些基本假设可能不是当今金融现实世界的完美代表。整个分析的一个基本假设是资产回报是正态分布的。我们来看看亚马逊和比特币的回报分布:

两种分布似乎都有“厚尾”和“高峰”,这意味着更接近平均值的回报和远离平均值的回报比正态分布更有可能出现。离群值似乎也会影响分布。在亚马逊的情况下,最高的每日日志回报大约是均值以上 6.5 个标准差,而在比特币的情况下,最负的每日日志回报几乎是均值以下 10 个标准差。正态分布回报的假设虽然在理论上非常有用,但在现实世界中可能并不完美。

尽管如此,本文的目的并不是预测未来或构建完美的投资组合。本文的目的是解释什么是均值-方差分析,以及如何使用 Python 来完成它。我的目标是用更容易理解的语言解释这个有点复杂的话题,同时指出为什么单单投资股票可能会限制一个人多样化的可能性。

我希望你喜欢这个现代投资组合理论的演示。如果您有任何问题或想聊些什么,请随时通过 LinkedIn 与我联系。

感谢阅读!

用 LSTM 预测加密货币

原文:https://towardsdatascience.com/cryptocurrency-prediction-with-lstm-4cc369c43d1b?source=collection_archive---------13-----------------------

如何预测汇率的趋势

虽然第一种重新分配的加密货币(比特币)是在 2009 年创造的,但数字货币的想法却出现在 20 世纪 80 年代。近年来,加密货币获得了惊人的流行。作为传统货币,加密货币的价值随着时间而变化。使用历史数据,我将使用 LSTM(长短期记忆)层实现一个递归神经网络,以预测未来加密货币价值的趋势。

安德烈·弗朗索瓦·麦肯齐在 Unsplash 上的照片

Kaggle 上有一个关于加密货币市场价格的庞大数据集。我只使用莱特币历史价格数据的一部分。

和往常一样,我们从导入库开始:

import numpy as np
import pandas as pdimport matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="darkgrid", font_scale=1.5)%matplotlib inline

导入库后,我们现在可以获得我们需要的数据:

df = pd.read_csv("crypto-markets.csv", parse_dates=["date"], index_col="date")df.shape
(942297, 12)df.head()

该数据集包括近 100 万行。我只需要“莱特币”的“开放”王子。

df = df[df.slug == "litecoin"][["open"]]df.shape
(2042, 1)

我们现在有莱特币从 2013 年 4 月到 2018 年 11 月的历史数据。让我们来看看它是如何随着时间而变化的。

plt.figure(figsize=(12,6))
sns.lineplot(x=df.index, y="open", data=df).set_title("Price of Litecoin")

在经历了 2013 年底的一个小高峰后,市场陷入了长时间的沉默。然后在 2017 年底达到最高值。我们可以通过应用下采样使图形看起来更平滑。

df.resample('10D').mean().plot(figsize=(12,6))plt.figtext(.5,0.9,"Down-sampled to 10-day periods", fontsize=20, ha='center')

型号

长短期记忆(LSTM)是一种递归神经网络(RNN ),对序列数据建模非常强大,因为它保持一种内部状态来跟踪它已经看到的数据。LSTMs 的常见应用包括时间序列分析和自然语言处理。

LSTM 要求输入是具有形状(batch_size,timesteps,input_dim)的 3D 张量。

我将建立一个模型,使用过去的 90 个值(从 t-90 到 t-1)预测时间 t 时莱特币的价值。因此时间步长的数量是 90。我仅使用“开盘价”进行预测,因此 input_dim 为 1。目标变量是莱特币的“公开”价格,它会受到许多其他因素的影响。例如,另一种加密货币的价值可能会对莱特币产生影响。如果我们还使用第二个变量来进行预测,那么 input_dim 将是 2。

数据预处理

我将重新组织数据,使用前 90 天的值序列来预测时间 t 的值。由于在神经网络中进行了过多的计算,因此最好将这些值标准化。

data = df.iloc[:, 0]hist = []
target = []
length = 90for i in range(len(data)-length):
    x = data[i:i+length]
    y = data[i+length]
    hist.append(x)
    target.append(y)

第一个元素的最后一个时间步长与原始数据的第 90 个时间步长相同,这正是我们计划要做的。

hist 的第二个元素应该只是第一个元素的一个时间步长偏移版本。因此,第二个元素中的最后一个时间步长应该等于目标变量的第一项,即原始数据中的第 91 个时间步长。

让我们仔细检查以确认:

print(hist[1][89])
print(data[90])
print(target[0])2.9
2.9
2.9

Hist 和 target 是列表。我们需要将它们转换成 numpy 数组,并对目标变量进行整形。

hist = np.array(hist)
target = np.array(target)target = target.reshape(-1,1)

让我们检查历史数组和目标数组的形状:

hist.shape
(1952, 90)target.shape
(1952, 1)

Hist 阵列包括 1952 个观测值,每个观测值包括 90 个时间步长(90 天)。

现在,我们可以对数据进行归一化,压缩 0 到 1 范围内的所有数据点,使最大值和最小值分别为 1 和 0。标准化可以通过应用一个简单的数学方程或者仅仅使用一个像 MinMaxScaler 这样的函数来完成。

from sklearn.preprocessing import MinMaxScalersc = MinMaxScaler()
hist_scaled = sc.fit_transform(hist)
target_scaled = sc.fit_transform(target)

预处理的最后一步是调整输入数组的形状,使其与 LSTM 图层兼容。

hist_scaled = hist_scaled.reshape((len(hist_scaled), length, 1))
print(hist_scaled.shape)
(1952, 90, 1)

训练和测试集

我们的数据集包括 1951 个样本(天)。输入样本包括连续 90 天的莱特币价值,目标变量是 90 天后第二天的莱特币价值。

我将以一种方式分割数据集,即 1900 个样本用于训练,然后该模型将用于预测未来 51 天的趋势。

X_train = hist_scaled[:1900,:,:]
X_test = hist_scaled[1900:,:,:]y_train = target_scaled[:1900,:]
y_test = target_scaled[1900:,:]

构建神经网络

import tensorflow as tffrom tensorflow.keras import layers

我将建立一个有 3 个 LSTM 层和 1 个输出层的密集层的模型。

model = tf.keras.Sequential()model.add(layers.LSTM(units=32, return_sequences=True,
                  input_shape=(90,1), dropout=0.2))model.add(layers.LSTM(units=32, return_sequences=True,
                  dropout=0.2))model.add(layers.LSTM(units=32, dropout=0.2))model.add(layers.Dense(units=1))model.summary()

我们现在需要编译模型。编译模型时,应选择用于调整权重的优化器。Tensorflow 提供了许多优化器。回归任务中常用的优化器有“adam”和“rmsprop”。此外,应该选择损失函数。由于这是一个回归任务,我们可以选择“均方误差”。

model.compile(optimizer='adam', loss='mean_squared_error')

是时候训练模型了。我们需要在这里指定两个超参数:

  • batch_size=在更新模型的内部参数之前,通过神经网络工作的样本数。如果 batch_size 为 1,则在将每个样本(或观察值)馈送到神经网络后,会更新参数。
  • 次数:整个训练集向前和向后通过神经网络的次数。
history = model.fit(X_train, y_train, epochs=30, batch_size=32)

该模型似乎在 30 个时期内收敛,因此没有必要进行额外的时期。损失不到 0.002 我觉得已经很不错了。

让我们想象一下随着时代数量的增加,损失是如何变化的。

loss = history.history['loss']
epoch_count = range(1, len(loss) + 1)
plt.figure(figsize=(12,8))
plt.plot(epoch_count, loss, 'r--')
plt.legend(['Training Loss'])
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.show();

看起来这个模型在 15 个纪元后已经收敛了。之后亏损在 0.0018 附近上下反弹。

现在是做预测的时候了。

pred = model.predict(X_test)plt.figure(figsize=(12,8))
plt.plot(y_test, color='blue', label='Real')
plt.plot(pred, color='red', label='Prediction')
plt.title('Litecoin Price Prediction')
plt.legend()
plt.show()

我们的模型很好地确定了趋势。您可能已经注意到,这些值比原始值小得多,因为我们在训练模型之前对这些值进行了规范化。我们可以进行逆变换来反映真实价格,但趋势是相同的。

pred_transformed = sc.inverse_transform(pred)
y_test_transformed = sc.inverse_transform(y_test)

总有改进的空间。神经网络的燃料是数据,因此我们可以通过收集更多的数据来建立一个更鲁棒和准确的模型。我们还可以尝试调整一层中的节点数量或添加额外的 LSTM 层。我们还可以尝试增加时间步长的数量,在我们的模型中是 90。另一种改进方法是使用 GridSearchCV 调整参数。

请记住,提高模型精度并不总是好的,因为我们最终可能会有一个过度拟合的模型。

你可以在这里找到整个 jupyter 笔记本。

感谢阅读。如果您有任何反馈,请告诉我。

清晰的强化学习

原文:https://towardsdatascience.com/crystal-clear-reinforcement-learning-7e6c1541365e?source=collection_archive---------25-----------------------

用于此插图图片的像素图像

强化学习的综合简明概念

强化学习(RL)是人工智能和机器学习的最热门领域,在过去几年中有许多惊人的突破。这篇文章试图给出整个 RL 光谱的一个简明的视图,而不要过多地进入数学和公式,同时也不要忽略茂密复杂的森林中的树木。

现在首先让我们了解什么是强化学习或 RL?

RL 意味着在头脑中考虑长期结果或累积 回报的情况下采取最佳行动。

用于此插图图片的像素图像

强化学习(RL)是通过环境交互进行的学习。强化学习代理从其动作的结果中学习,而不是从明确的教导中学习,它根据其过去的经验(利用)以及新的选择(探索)来选择其动作,这是必不可少的,试错学习就像孩子学习一样。RL-agent 接收到的强化信号是一个数字的奖励,它编码了一个动作结果的成功,agent 试图学习选择那些随着时间的推移使累积奖励最大化的动作。

用于此插图图片的像素图像

在我们深入研究 RL 之前,让我们先看看为什么 RL 在人工智能和机器学习领域如此重要。参考下面的图表,它显示了 RL 在生活的各个领域中的应用。

用于此插图图片的像素图像

现在,我将介绍一些经常用来解释强化学习的术语,在深入研究算法和更吸引人的概念之前,人们必须理解这些术语。

用于此插图图片的像素图像

在上图中,我列出了名称、标准符号和图示。现在,我将分别对它们进行定义。

代理人

任何使用某种传感器感知其环境并能够在环境中产生行动的东西都被称为代理。代理执行动作,接受观察,并给予奖励。

环境

环境是代理交互的总体表示。该媒介不被认为是环境的一部分。环境接受一个动作,发出观察和奖励。

状态

状态描述了当前的情况,并决定了接下来会发生什么。代理可能有状态的局部视图,这被称为观察

报酬

当一个代理在一个州采取行动时,它会收到一个奖励。这里的术语“奖励”是一个抽象的概念,描述来自环境的反馈。奖励可以是正面的或负面的。当奖励为正时,对应的是我们通常意义上的奖励。当奖励为负时,对应的就是我们通常所说的“惩罚”。

Pixabay,Atari & Tesla 图像用于此插图图片

奖励是代理在每个时间步从环境中得到的反馈。然后,它可以使用这个奖励信号(对于好的行为可以是积极的,对于坏的行为可以是消极的)来推断在一种状态下如何表现。总的来说,目标是解决一个给定的任务,尽可能获得最大的回报。这就是为什么许多算法对代理采取的每一个动作都有一个微小的负奖励,以激励它尽快解决任务。奖励是在 RL 中至关重要的设计决策,因为这将鼓励 RL 代理优化行为。例如,以更少的时间赢得象棋比赛或以平均速度驾驶汽车但不发生任何碰撞(汽车可以在空旷的高速公路上加速,而在繁忙的道路上缓慢行驶)。奖励告诉我们什么是好的直接感觉。比如雅达利游戏,每一个时间步代理都是得分或者失分的。

贴现因素

现在的奖励比未来的奖励更有价值。贴现因子,通常表示为γ,是一个乘以未来预期回报的因子,在[0,1]的范围内变化。它控制着未来回报相对于眼前回报的重要性。折扣因子越低,未来的回报就越不重要,代理人将倾向于专注于只产生即时回报的行动。贴现率被限制为小于 1 的事实是一个使无限和有限的数学技巧。这有助于证明某些算法的收敛性。贴现因子用于确定未来报酬现值(类似于由于通货膨胀等因素贴现的未来货币的现值)。

状态值

状态值“V(S)”是从该状态开始的一段时间内代理可以期望积累的奖励总额。与奖励信号不同,价值函数指定了长期 中什么是好的。

行动

动作是代理在每个状态下可以做的事情。例如,机器人的步幅只能是 0.01 米到 1 米。围棋程序只能在 19 x 19(即 361)个位置中的一个位置放下棋子。自动驾驶汽车可能会向不同的方向行驶。

动作值

动作值或状态-动作值函数(Q 函数)指定代理在具有策略π的状态下执行特定动作的良好程度。Q 函数用 Q(S,A)表示。它表示在遵循策略π的状态下采取行动的价值。这里的‘q’指的是一个动作的质量

政策

策略是代理从状态中选择的动作。策略是在一种状态下行动的映射,这种状态可以是确定性的随机性的。该策略由 π表示。

环境模型

这个模型是对环境的模拟。它知道从一个状态到另一个状态的转换,以及对环境的高层次理解。

用于此插图图片的像素图像

现在,我将介绍一些基本概念,如勘探、开发、策略上、策略下等。在我们深入研究 RL 算法之前。

开采和勘探

开发和探索的概念与人类的本性有着内在的联系,作为人类,我们更喜欢已知而不是未知。例如,去餐馆,你可以选择去你最喜欢的餐馆,因为你已经喜欢那里的食物,但除非你尝试另一家餐馆,否则你不会知道是否存在更好的餐馆。

用于此插图图片的像素图像

因此,开发就是去做同样的事情,从一个国家获得最大的价值(这通常被称为贪婪的行为),而探索就是尝试新的活动,从长远来看,这些活动可能会带来更好的回报,即使眼前的回报可能并不令人鼓舞。在上图中,如果代理人只考虑即时奖励,通过跟随红色路径获得最大奖励,它将在稍后发现具有更高价值的蓝色路径,即使即时奖励较低。这就是为什么需要探索来获得更好的长期回报。

符合政策和不符合政策

在非策略学习中,我们评估目标策略(π),同时遵循另一个称为的策略行为策略 (μ)(这就像机器人遵循视频或基于另一个代理获得的经验的代理学习)。“在策略上”表示代理遵循它用来更新目标的相同策略。

用于此插图图片的像素图像

规划和学习

RL 算法可分为规划学习算法。在规划中,代理需要知道环境的模型(代理知道转移概率),然后在该模型下规划最优策略。在学习问题中,代理不了解环境的动态,它需要通过试错进行交互,以了解环境,从而得出最优策略或最优状态值。

基于模型和无模型

在基于模型的 RL 问题中,代理知道环境的模型,这意味着它知道转换动态,并且主要目标是计划最优动作。在无模型 RL 中,代理不知道转换或其他动态;相反,它必须通过与环境的互动来学习什么样的可选动作会产生最佳结果。

强化学习“规划”算法

马尔可夫决策过程(MDP)

马尔可夫决策过程(MDP)是复杂决策过程的数学表示。(MDP)正式描述强化学习的环境。环境是完全可观察的和静止的(意味着规则不随时间改变)。几乎所有的 RL 问题都可以用 MDP 来形式化。MDP 的定义是:

  • 一个状态 S,它代表了在一个定义的世界中,一个人可能处于的每一个状态。只有现在重要,这意味着转移函数仅取决于当前状态 S,而不取决于任何先前状态。

用于此插图图片的像素图像

  • 一个模型或转移函数 P,它是当前状态、所采取的行动以及我们最终所处的状态的函数。这种转变产生了一定的概率,以状态 S '结束,在途中获得奖励 R,从状态 S 开始,并采取行动 a。
  • 奖励是处于一种状态的一个标度值。它告诉我们进入状态的用处。

MDP 的最终目标是找到一个政策,它可以告诉我们,对于任何一个州,该采取什么行动(记住,将州映射到行动是我们的政策)。最优策略是使长期预期回报最大化的策略。一旦找到最优策略,RL 问题就解决了

在 RL 中,我们考虑如何计算任意策略π的状态值函数 V(S)。这在 RL 文献中被称为政策评估(也称为预测问题)。通过使新策略相对于原始策略的价值函数变得贪婪来改进原始策略的过程被称为策略改进或控制。

广义策略迭代

广义策略迭代(GPI)是指让策略评估和策略改进过程相互作用的总体思想,独立于两种方法的粒度和其他细节。这就像梅西和 c 罗在同一支球队踢一场足球赛。他们每次传球都是为了个人进球而互相竞争,但他们也互相协助为球队赢得比赛。同样,GPI 就像一场足球比赛,最终目标是找到最优政策/最优价值函数。在一次扫描中(可能是全部情节,也可能是每一步或几步),对策略进行评估,以计算出该策略的价值。然后通过对旧政策采取贪婪的行动来改进政策。重复这一过程,直到出现收敛,并找到最优策略或最优值。

贝尔曼方程

特定状态的值等于当前状态的奖励,加上从该点开始从当前状态 S 过渡到未来状态 S’时得到的折扣奖励。

价值迭代

为了求解贝尔曼方程,我们通常从所有状态的任意值开始,然后基于邻居(从当前状态可以到达的所有状态)更新它们。最后,我们重复直到收敛。这个过程叫做“价值迭代。”值迭代是一个组合一个(或多个)政策评估扫描,然后执行另一个政策改进扫描。重复这个过程,直到收敛发生。价值迭代包括:寻找最优价值函数 +一个策略抽取。这两者没有重复,因为一旦价值函数是最优的,那么由此得出的策略也应该是最优的(即,收敛的)。

策略迭代

这是一个 GPI 过程,其中通过执行单调改进的策略和值函数来改进策略:通过重复策略评估,然后执行策略改进。每一个策略都保证是对前一个策略的严格改进(除非它已经是最优的)。因为有限的 MDP 只有有限数量的策略,所以这个过程必须在有限数量的迭代中收敛到最优策略和最优值函数。这种寻找最优策略的方式称为策略迭代。策略迭代包括策略评估 + 策略改进,两者反复迭代直到策略收敛。

RL“学习”算法

在 RL 问题中,我们的目标是找到每个状态的最优值或者找到最优策略。根据算法是如何制定的,它们大致分为三类。我们还可以根据策略(开或关)选择不同的模式

基于值的算法

用于此插图图片的像素图像

蒙特卡洛学习

蒙特卡罗方法是一个简单的概念,当它与环境交互时,代理学习状态和奖励。在这种方法中,代理生成经验样本,然后基于平均回报,为状态或状态-动作计算值。下面是蒙特卡罗(MC)方法的关键特征:

  1. 没有模型(代理不知道状态 MDP 转换)
  2. 代理人采样的经验中学习
  3. 通过体验来自所有采样剧集的平均回报,学习策略π下的状态值 vπ(s )(值=平均回报)
  4. 仅在完成一集之后,值才被更新(因为该算法收敛缓慢,并且更新发生在一集完成之后)
  5. 没有自举
  6. 仅可用于偶发性问题

在蒙特卡罗方法中,我们使用代理人根据政策采样的经验回报率,而不是预期回报率。考虑下面的图表,我们看到五个不同的轨迹(轨迹是代理在一集里所走的路径),代理从一集开始到结束都经历了这些轨迹。在这种情况下,for starting 状态出现在所有五个样本中,并且该状态的值将是在五个展开中采样的五个值的平均值。

有两种 MC 方法:第一次访问 MC 和每次访问 MC。

用于此插图图片的像素图像

在计算一个状态的值时,只计算第一次访问,即使该状态被多次访问。在每次访问 MC 中,每次在一集内访问该州时,该州的值都会受到访问次数的影响(参考以下示例中的 S3 州值。

用于此插图图片的像素图像

TD(0)

TD(0)是时间差分(TD)学习的最简单形式。在这种形式的 TD 学习中,在每一步值函数都用下一个状态的值和沿途的更新后,得到奖励。这种观察到的回报是保持学习接地气的关键因素,算法在足够数量的采样后收敛(在无穷大的极限内)。所有 TD 方法都具有以下特征:

  1. 没有模型(代理不知道状态 MDP 转换)
  2. 代理采样的经验中学习(类似于 MC)
  3. 像 DP 一样,TD 方法部分基于其他学习的估计更新估计,而不等待结果(它们像 DP 一样引导)。
  4. 它可以从不完整的插曲中吸取教训;因此,该方法同样可以用于连续问题
  5. TD 将猜测更新为猜测,并根据实际经验修改猜测。

参考下图,其中状态值在每一步之后从下一个状态值更新(学习率(α) 是一个决定从下一个状态和当前状态之间的差中取多少来更新当前状态的因素)。这种差异被称为 TD 误差

用于此插图图片的像素图像

萨尔萨

控制或改进的 TD 算法之一是 SARSA。SARSA 的名字来源于这样一个事实,即代理从一个状态-动作值对向另一个状态-动作值对迈出一步,并在此过程中收集奖励 R(因此它是 S( t),A( t),R (t+1),S (t+1) & A(t+1)元组,它创建了术语 S,A,R,S,A )。SARSA 是一种基于策略的方法。SARSA 使用动作值函数 Q 并遵循策略π。 GPI (广义策略迭代)用于基于策略π采取行动(ε-贪婪确保探索以及贪婪改进策略)。参考下图,我们可以看到下一个操作可以是基于策略的任何下一个操作。

用于此插图图片的像素图像

q 学习

Q-learning 是一种非策略算法。DQN(深度 Q-learning)登上了《自然》杂志的头版,它是一种基于 Q-Learning 的算法(几乎没有额外的技巧),在雅达利游戏中超越了人类水平的专业知识(我将在未来的帖子中详细介绍 DQN)。在 Q-learning 中,目标策略是贪婪策略,行为策略是ε-贪婪策略(这确保了探索)。

用于此插图图片的像素图像

参考下图。接下来的行动是基于一个贪婪的政策。

用于此插图图片的像素图像

预期 SARSA

预期 SARSA 就像 Q-learning 一样,除了它使用期望值(基于概率的平均值)而不是下一个状态-动作对的最大值,同时考虑了每个动作在当前策略下的可能性。给定下一个状态,Q-learning 算法确定性地将向同一方向移动,而 SARSA 按照期望跟随,因此,它被称为期望 SARSA。参考下文,下一步行动基于预期值。

用于此插图图片的像素图像

基于 SARSA 概念的这些控制算法的主要区别如下图所示。

用于此插图图片的像素图像

接下来,我们将介绍一些基于时间差概念的算法,但这些算法的值不会立即更新,而是在几步之后更新,或者基于几个状态的平均值进行更新。

n 步 TD / SARSA

在 n 步 TD 中,状态值或动作值在一定数量的时间步后更新。在这些情况下,代理在值更新之前收集更多的奖励。在一定数量的步骤之后,根据沿途收集的所有折扣奖励和状态或状态-动作的价值函数来更新价值。

用于此插图图片的像素图像

TD(λ)

TD(λ)是 n 步 TD 的扩展。直觉是将所有可能的 n 步回报平均成一个单一的回报。我们使用随时间呈指数衰减的权重对 n 步回报进行加权。这是通过引入因子λ(值在 0 和 1 之间)并将第 n 次返回加权为(n-1)次幂λ来实现的。因为我们希望所有这些权重相加为一(得到一个加权平均值),所以我们将它们归一化。

我们可以看到,当λ = 1 时,只保留最后一项,这本质上是蒙特卡罗方法,作为状态,作用过程一直进行到最后,当λ = 0 时,该项还原 TD (0)方法,对于 0

用于此插图图片的像素图像

这可以使用资格跟踪来进一步改进,这是一个绝妙的想法,它允许我们基于对过去发生的事情的记忆来更新每个状态值,并使用当前信息来更新我们到目前为止看到的每个状态的状态值。资格追踪结合了两件事:一是多频繁二是一个州多近。在 RL 中,将在下一个状态学到的东西也扩展到先前的所有状态以加速学习将是有用的。为了实现这一目标,需要有一个短期记忆机制来存储在最后步骤中访问过的状态。这就是资格跟踪概念出现的地方。λ∈[0,1]是称为 trace-decayaccumulating trace,的衰减参数,其定义了每个被访问状态的更新权重。痕迹随时间减少。这允许对不频繁的状态给予小的权重,而对最近访问的状态给予大的权重。对于λ=0,我们有 TD(0)的情况,只有前一个预测被更新。TD(1)可以被认为是使用 TD 框架的 MC 方法的扩展。在 MC 方法中,我们需要等到剧集结束时更新状态。在 TD(1)中,我们可以在线更新所有之前的状态,并且我们不需要剧集的结尾。现在让我们看看在一个事件中特定的状态跟踪会发生什么。我将考虑一集七次访问,其中访问了五个州。在该事件期间,状态 s1s1 被访问两次。让我们看看它的踪迹会发生什么变化。

参考上图;开始时,迹线等于零。在第一次访问 S1(第一步)后,迹线上升到 1.0,然后开始衰减。在第二次访问(第 3 步)之后,将+1 加到当前值(0.50),获得 1.50 的轨迹。在三个以上的步骤之后,S1 被重新访问,使得踪迹值为 1.75(注意,这里指数衰减仅仅被显示为在每个步骤中减少 0.25,为了说明的自由,实际值将会不同)。

TD(λ)如何更新值函数?在 TD(λ)中,先前的状态是可访问的,但是它们是基于资格跟踪值更新的。具有小资格轨迹的州将被少量更新,而具有高资格轨迹的州将被大量更新。

深 Q 网(DQN)

这是整合深度学习和强化学习的主要成功故事之一,它打开了新算法的闸门,并重新引起了人们对强化学习领域的兴趣。深度神经网络用作 Q 值的函数逼近器。深度 Q 学习简单地应用神经网络来近似每个动作和状态的 Q 函数,这可以节省大量的计算资源,并且潜在地扩展到连续时间动作空间。

体验回放:我们运行代理,将最近的 10 万个过渡(或视频帧)存储到一个缓冲区中,并从这个缓冲区中抽取一个 512 大小的小批量样本来训练深度网络。当我们从重放缓冲区随机取样时,数据更加相互独立,更接近于同分布(独立同分布)。这使得降雨稳定。

目标网络:我们创建两个深度网络θ-(目标网络)和θ(Q-网络)。我们使用第一个来检索 Q 值,而第二个包括训练中的所有更新。比如说 50,000 次更新后,我们将θ-与θ同步。目的是暂时固定 Q 值目标,这样我们就没有一个移动的目标可以追逐。此外,参数变化不会立即影响θ-,因此即使输入也变得接近 i.i.d。

下面是 DQN 的图表和步骤。

  1. 预处理并将状态提供给 DQN,后者将返回状态中所有可能动作的 Q 值
  2. 使用ε-贪婪策略(行为策略)选择一个动作。对于概率ε,我们选择随机动作 a,,对于概率 1-ε,我们选择具有最大 Q 值的动作,例如 A= argmax (Q(S,A,θ))
  3. 在状态 S 中执行该动作,并移动到新的状态 S ' 以获得奖励 r。在 Atari 模拟器的情况下,该状态 S '是下一个游戏屏幕的预处理图像。我们将这个过渡存储在我们的重放缓冲器中作为< S,A,R,S’>
  4. 接下来,从重放缓冲区中随机抽取一些批次的转换样本,并计算损失,这只是目标 Q(奖励+贴现的最大下一个 Q 值(贪婪目标策略))和预测 Q 之间的平方差。
  5. 根据我们的实际网络参数执行梯度下降,以最小化这种损失
  6. 每 N 次迭代后,将我们的实际网络参数(θ)复制到目标网络参数(θ-)
  7. 重复这些步骤达 M 集数以收敛参数θ

双 Q 学习

Q-Learning 在一些随机环境中表现很差。由于在 Q-learning 中使用Max Q(S’,A’)导致动作值被大大高估,从而导致性能不佳。主要概念是通过将目标中的 max 操作分解为动作选择动作评估来减少高估。在 Doble Q-learning 中,我们维护两个 Q 值函数 Q-A 和 Q-B(在 Double Deep Q 网络中,这两个通过称为目标网络和 Deep Q 网络的两个不同的函数近似来支持),每个都从另一个获得下一个状态的更新。Q-A 决定在下一个状态中导致最佳动作值的动作,而 Q-B 使用 Q-A 选择的那个动作来决定状态动作的期望值是多少(这里的算法是维护两个网络)。

用于此插图图片的像素图像

决斗 DQN

q 值可以分解为两部分:状态值函数 V 和优势值 a。优势函数捕获在给定状态下,某个动作与平均动作相比有多好(参见 A3C,了解优势函数的直观解释)。同时,正如我们所知,价值函数捕捉到了处于这种状态有多好。

决斗 Q 网络背后的整个思想依赖于将 Q 函数表示为值和优势函数的总和。

我们简单地用两个网络来学习和的每一部分,然后我们合计它们的输出。参考下图,其中全连接(FC)层有两个头(一个用于 V,一个用于所有 A)。

将这种类型的结构添加到网络中允许网络更好地区分彼此的动作,并且显著地改进了学习。在许多状态下,不同动作的值非常相似,采取哪种动作并不重要。这在有许多操作可供选择的环境中尤其重要。

基于策略的算法

用于此插图图片的像素图像

在基于策略的方法中,我们不是学习告诉我们给定一个状态和一个动作的期望回报总和的值函数,而是直接学习将状态映射到动作的策略函数(选择动作而不使用值函数)。政策梯度背后的关键思想是提高导致更高回报的行动概率,而降低导致更低回报的行动概率,直到我们得出最优政策。

策略梯度方法的目标是直接建模和优化策略。策略 π (A|S)通常用参数化函数 θ 建模。奖励(目标)函数的值取决于这个策略,然后可以应用各种算法来优化 θ 以获得最佳奖励。在基于策略的方法中,我们显式地构建一个策略的表示(映射π:S→A ),并在学习期间将其保存在内存中。

很自然地期望基于策略的方法在连续空间更有用。因为存在无限数量的动作和(或)状态来估计值,因此基于值的方法在连续空间中在计算上过于昂贵。例如,在一般化的策略迭代中,策略改进步骤需要对动作空间进行全面扫描,遭受了维数灾难

用于此插图图片的像素图像

加固

加强(蒙特卡洛政策梯度)依赖于通过蒙特卡洛方法使用事件样本更新政策参数θ的估计回报。因为样本梯度的期望值等于实际梯度,所以加强是可行的。在加强中,代理使用其当前策略收集一集的轨迹τ,并使用它来更新策略参数。下面是加固的步骤。

  1. 随机初始化策略参数θ。
  2. 在策略π上生成一个轨迹
  3. 估算每个时间步的回报,直到最终状态
  4. 通过一步梯度上升更新政策参数:θ(价值函数的梯度可以计算为政策梯度(的对数)的梯度期望值乘以奖励— 这是政策梯度的主要技巧)
  5. 重复 2–4 直到收敛

强化以基于策略的方式训练随机策略。这意味着它通过根据其随机策略的最新版本对行为进行采样来进行探索。动作选择的随机性取决于初始条件和训练程序。在整个训练过程中,策略通常变得越来越不随机,因为更新规则鼓励它利用它已经发现的奖励。这可能导致策略陷入局部最优。下图是对钢筋的解释。我们希望更新有正回报的策略参数,并减少有负回报的策略参数。

需要注意的重要一点是,这里没有使用马尔可夫性质,这也可以用于部分观测的 MDP,而不需要在算法上做任何改变。

这种方法的一个主要缺点是方差大和收敛慢。

用基线加强

为了减少方差,一个想法是从返回 G(S)中减去一个称为基线 B(S)的值,其中 B(S)不依赖于动作 a。从数学上仍然可以看出,政策梯度仍然在预期中给出无偏的结果。

所以现在的问题是如何选择 B(S)。对基线的选择之一是计算状态值 V(S,w)的估计,其中 w 是通过诸如蒙特卡罗的一些方法学习的参数向量。

演员-评论家算法

用于此插图图片的像素图像

政策梯度的两个主要组成部分是政策模型和价值函数。除了策略之外,学习价值函数是很有意义的,因为知道价值函数可以帮助策略更新,例如通过减少普通策略梯度中的梯度方差,并且这正是参与者-批评家方法所做的,其中参与者是策略并且批评家是价值函数

行动者-批评家方法由两个模型组成,这两个模型可能共享也可能不共享参数:

  • 评论家更新值函数参数‘w’,根据算法,它可以是动作值 Q 或状态值 v。
  • 行动者按照批评者建议的方向更新策略参数‘θ’。

正如我们前面看到的,减少政策梯度方法的方差和增加稳定性的一个方法是用基线减去累积回报(回报)。该基线减法在预期中是无偏的。因此,我们在这里做的是通过一些基线来调整回报,这减少了方差。有许多方法可以改进增强算法。

A3C

异步优势行动者-批评家(A3C) 算法是一种经典的策略梯度方法,特别关注并行训练。这是一个典型的政策梯度方法,特别强调平行培训。该算法使用多个代理,每个代理都有自己的网络参数和环境副本。这些代理与它们各自的环境异步交互,在每次交互中学习。一个全球网络控制着每个代理。随着每个代理获得更多的知识,它有助于全球网络的总知识。全球网络的存在允许每个代理具有更多样化的训练数据。这种设置模拟了人类生活的真实环境,因为每个人都从其他人的经验中获得知识,从而使整个“全球网络”变得更好。

与基于价值迭代法或策略梯度法的一些更直接的技术不同,A3C 算法结合了这两种方法的最佳部分,即该算法预测价值函数和最优策略函数。

典型地,在实施策略梯度(优势的价值)时,代理人也知道回报比其平均值(期望值)好多少。这提供了对环境中的代理的新发现的洞察力,因此学习过程更好。以下表达式提供了 advantage 函数。

优势(S,A) =行动价值(S,A) —状态价值(S)。

参考下图,该图解释了具有四个动作的状态的优势函数,并显示了动作的概率(为了解释,这被用作确定性离散动作,但该概念同样适用于随机连续动作空间)。这里,行动 A3 中的优势值最高,行动者在这种状态下会更多地遵循该行动,如评论家所建议的那样(优势函数)。

请参考下图,该图显示了 A3C 架构如何与工人和全球网络参数一起工作。与此同时,不同的主体从环境中获取不同的信息,并且所有主体都合作学习对环境和问题的全局理解。

A2C

A2C 是 A3C 的“同步”确定性版本;这就是为什么它被命名为“A2C”,去掉了第一个“A”(“异步”)。在 A3C 中,每个代理独立地与全局参数对话,所以有时特定于线程的代理可能会使用不同版本的策略。因此,聚集更新将不是最佳的。为了解决这种不一致,A2C 的协调器在更新全局参数之前等待所有并行参与者完成他们的工作。然后在下一次迭代中,并行参与者从相同的策略开始。同步梯度更新使训练更有凝聚力,并可能使收敛更快。A2C 还能够更有效地利用 GPU,更好地处理大批量数据,同时实现与 A3C 相同或更好的性能。

请参考下图。所有 n 个代理线程等待,直到它们都有更新要执行。然后,我们通过对全局网络的一次更新来平均这 n 个线程上的梯度。事实上,由于批量较大,这应该更有效。

TRPO

为了提高训练的稳定性,我们应该避免一步改变策略太多的参数更新。信任区域策略优化(TRPO) 通过在每次迭代中对策略更新的大小实施 KL 发散约束来实现这一思想。TRPO 是一种基于策略的算法。TRPO 可用于具有离散或连续动作空间的环境。

TRPO 通过采取尽可能大的步骤来更新策略,以提高性能,同时满足允许新旧策略接近程度的特殊约束。这种约束用 KL-Divergence 来表示,这是新旧政策概率分布之间距离的一种度量。

这不同于标准策略梯度,标准策略梯度在参数空间中保持新旧策略接近。但是,即使参数空间中看似很小的差异也会在性能上产生相当大的差异——因此,一个错误的步骤就可能导致策略性能崩溃。这使得对普通策略梯度使用大的步长变得很危险,从而损害了它的采样效率。TRPO 很好地避免了这种崩溃,并倾向于快速单调地提高性能。参考下图,这是 TRPO 如何使用信任区域(循环空间)来限制后续策略的卡通说明,以便新策略不会漂移太多,从而永远不会达到最优策略。红色、黄色和橙色策略在信任区域(由 KL-divergence 设置)之外,因此无法恢复或解决局部最优。

用于此插图图片的像素图像

TRPO 旨在最大化服从信任区域约束的目标函数,该约束强制由 KL-divergence 测量的新旧策略之间的距离在参数δ内足够小。这样,当满足这一硬约束时,新旧政策不会相差太多。请参考下图,了解约束如何适用于两种策略。

聚苯醚(Polyphenylene Oxide 的缩写)

TRPO 实现起来相当复杂。近似策略优化(PPO) 通过使用修剪替代目标来简化它,同时保留类似的约束和类似的性能。PPO 消除了由约束优化产生的计算,因为它提出了一个裁剪代理目标函数。它不是强加硬约束,而是将约束形式化为目标函数中的惩罚。

对于 PPO,我们通过将 KL 散度从一个约束条件转化为一个惩罚项来简化问题,类似于,例如,L1,L2 权重惩罚(以防止权重增长到很大的值)。

PPO-Penalty 近似地解决了类似 TRPO 的 KL 约束更新,但是惩罚目标函数中的 KL-divergence,而不是使其成为硬约束,并且在整个训练中自动调整惩罚系数,以便其被适当地缩放。

PPO-Clip 在目标中没有 KL-divergence 项,完全没有约束。而是依赖于目标函数中的专门剪裁来消除新策略远离旧策略的激励。PPO 确实将政策比率(更新政策与旧政策的比率)限制在 1.0 左右的小范围内,其中 1.0 表示新政策与旧政策相同。

DDPG

(深度确定性策略梯度),是一种无模型的非策略行动者-批评家算法,它同时学习 Q 函数(行动值)和策略。它使用非策略数据和贝尔曼方程学习 Q 函数,并使用 Q 函数学习策略。DDPG 可以被认为是针对连续动作空间的深度 Q 学习。

  • DDPG 是一个非策略算法(使用重放缓冲)
  • DDPG只能用于有连续动作空间的环境

当存在有限数量的离散动作时,最大值不会造成问题,因为我们可以单独计算每个动作的 Q 值,并直接比较它们,这给了我们最大化 Q 值的动作。但是当动作空间是连续的时,我们不能穷尽地评估该空间(我们必须评估无限数量的动作),并且因为每次代理想要在环境中采取任何动作时都需要运行它,这是不可行的。

在 DDPG,我们使用重放缓冲区来计算目标,然后更新 Q 函数(梯度下降),然后更新策略(梯度上升)。我们想学习一个确定性的策略,给出最大化 Q 函数的动作。由于动作空间是连续的,并且我们假设 Q 函数相对于动作是可微的,我们执行梯度上升来求解仅相对于策略参数的最大 Q 值。注意,当我们进行梯度上升以更新策略参数时,Q 函数参数在这里被视为常数。

TD3:双延迟深度确定性政策梯度

双延迟深度确定性策略梯度(TD3)算法是一种无模型、在线、脱离策略的行动者-批评家算法。DDPG 的一个常见故障模式是,学习到的 Q 函数开始显著高估 Q 值,然后导致策略破坏,因为它利用了 Q 函数中的错误。TD3 算法是 DDPG 算法的扩展。

TD3 比 DDPG 做了以下改进。

  1. TD3 代理学习两个 Q 值** ( “孪生”)函数,并在策略更新期间使用最小值函数估计。**
  2. TD3 更新策略(和目标网络)比 Q 功能更不频繁(“延迟”)(一个策略更新两个 Q 功能更新,这就是孪生延迟名称的由来)
  3. 当更新策略时,TD3 代理向目标动作添加噪声,这使得策略不太可能利用具有高 Q 值估计的动作。

上图显示了算法中的步骤。我将在这里尝试以简化的方式描述这些步骤。

  1. 第一步是初始化策略和 Q 函数的函数近似参数(两个 Q 参数),将目标参数设置为主参数(1 个用于策略,2 个用于 Q 函数)
  2. 重复许多集以收集状态、动作(我们添加噪声和剪辑)、奖励、下一个状态、终端状态指示符来构建重放缓冲区
  3. 从重放缓冲器中随机抽取一批过渡细节,并计算目标动作 A’(S’)(使用演员目标网络、剪辑和噪声属性)
  4. 计算目标 Q 值,在批评家目标 1** 网络中的 Q’1**
  5. 计算目标 Q 值,Q'2 在批评家目标 2** 网络中**
  6. 从 Q'1 和 Q'2 中取 Q 值的最小值。
  7. 使用 Critic Model1 中的一步梯度下降计算 Q 函数的损失(将步骤 6 中的 Q 值作为目标 )
  8. 使用 Critic Model2 中的一步梯度下降法计算 Q 函数的损失(将步骤 6 中的 Q 值作为目标 )
  9. 采取步骤 7 和 8 计算总损失,并更新评估模型 1** 和评估模型 2 的参数**
  10. 每两次迭代中,我们使用从评论家模型 1 输出的 Q 值通过一步梯度上升来更新演员模型的策略参数(步骤 7)
  11. 每两次迭代中,我们通过 Polyak 平均更新一次目标网络的参数(演员目标,评论家目标 1 &评论家目标 2 )。

我们继续上述步骤,直到参数收敛。

软演员兼评论家

软行动者-批评家(SAC)基于最大熵强化学习,这是一个框架,旨在既最大化预期回报(这是标准的 RL 目标)又最大化政策的** ( 熵越高的政策越随机),这直观地意味着最大熵强化学习更喜欢仍然实现高回报的最随机的政策。**

软演员评论家(SAC)结合了限幅双 Q 技巧(像 DDPG 一样),SAC 的一个中心特征是熵正则化。该策略被训练为最大化预期回报和熵之间的权衡,熵是策略中随机性的度量。这与探索-利用权衡有着密切的联系:增加熵会导致更多的探索,这可以加速以后的学习。它还可以防止策略过早地收敛到一个坏的局部最优

  • SAC 是一种非策略算法。
  • SAC 可以在连续或离散的动作空间中工作。

黑斑羚

****IMPALA(重要性加权行动者-学习者架构)受流行的 A3C 架构启发,使用多个分布式行动者来学习代理的参数。每个参与者都使用策略参数的克隆来在环境中操作。

IMPALA 使用为学习策略和基线函数 v 而设置的行动者-批评家。该架构由一组行动者组成,重复生成经验轨迹,一个或多个学习者使用从行动者发送来的经验学习策略非策略。

****演员周期性地暂停他们的探索,以与中央参数服务器共享他们已经计算的梯度,中央参数服务器通过计算梯度来应用更新。在 IMPALA 中,生成经验的过程与学习参数策略和基线函数 v 是分离的。多个参与者并行生成经验,而学习者使用所有生成的经验优化策略和值函数参数。参与者定期用来自学习者的最新策略更新他们的参数。因为表演和学习是分离的,我们可以添加更多的演员机器来生成更多的时间单位轨迹。由于训练策略和行为策略不完全同步,它们之间有一个间隙,因此我们需要称为 V-trace 的非策略修正。

图像参考:深度思维

中央学习器计算梯度,产生具有完全独立的参与者和学习者的模型。

图片来自谷歌人工智能博客

为了利用现代计算系统的规模,可以使用单个学习器机器或在它们之间执行同步更新的多个学习器来实现重要性加权的参与者-学习器架构。以这种方式分离学习和行动还有增加整个系统吞吐量的优点,因为行动者不再需要像在诸如批处理 A2C(如下图所示)的架构中那样等待学习步骤。

图像参考:深度思维

然而,将表演和学习分离会导致参与者的策略落后于学习者。为了补偿这种差异,IMPALA 使用了一种称为 V-trace 的非政策优势演员-评论家公式,用于补偿演员非政策获得的轨迹。

最后一个音符

强化学习很复杂,但这并不意味着它必须是深奥的。这个领域正在迅速发展;新的想法和论文层出不穷。我尽量避免所有的数学表达式,这些表达式对于理解更复杂的算法是必不可少的。感兴趣的读者可以深入下面的参考列表,享受数学细节和进一步的解释。

我期待看到您的反馈或分享任何其他更直接的解释或参考任何不同的算法,您可能希望看到作为本文的一部分。

感谢阅读。你可以在 LinkedIn 上联系我。

只需每月 5 美元,就可以无限制地获取最鼓舞人心的内容…点击下面的链接,成为媒体会员,支持我的写作。谢谢大家!
https://baijayanta.medium.com/membership

参考:

https://spinningup.openai.com/en/latest/
https://github.com/dennybritz/reinforcement-learning
https://lilianweng . github . io/lil-log/2018/04/08/policy-gradient-algorithms . html

CSV kit:CSV 数据的瑞士军刀?

原文:https://towardsdatascience.com/csvkit-a-swiss-army-knife-for-csv-data-286db551547b?source=collection_archive---------41-----------------------

评估 csvkit 从命令行操作数据的潜力

马库斯·斯皮斯克在 Unsplash 上拍摄的照片

当面对一个新的 CSV 数据集进行分析时,我们大多数数据科学家会立即启动我们最喜欢的 IDE 或笔记本编辑器,从通常的numpypandas导入开始。

这并没有什么错,但是今天我想向您展示如何在不离开命令行的情况下近距离接触您的数据。

我将使用csvkit,一个专门为此设计的工具。我还将在示例中使用 Kaggle 数据集,它也可以从命令行下载,如下所示:

pip install kaggle kaggle datasets download datafiniti/hotel-reviews unzip hotel-reviews.zip

探索数据集

csvcut :

我们对这个数据集了解不多,只知道它与酒店有关。首先,我们想知道那里有哪些列。简单:

csvcut -n Datafiniti_Hotel_Reviews.csv

csvlook :

假设您想看看列provincepostalCode的前几个值。在下面的代码中,我们选择带有csvcut的列的子集,并将其作为csvlook的输入:

csvcut -c country,province,postalCode Datafiniti_Hotel_Reviews.csv | csvlook --max-rows 10

或者,我们可以将csvlook的输出传送到head命令,而不是使用--max-rows参数。

csvstat :

现在给定上面的输出,我们可能想要检查数据是否只覆盖美国。要了解更多关于特定列的信息,我们可以使用csvstat:

csvcut -c country,province,postalCode Datafiniti_Hotel_Reviews.csv | csvstat

这是很多非常有用的信息,非常容易获得!注意,我们还从上面的输出中获得了文件中的行数。

如果您想获得所有列的统计数据,您当然可以直接使用csvstat而不用管道:

csvstat Datafiniti_Hotel_Reviews.csv

csvort:

假设现在我们想快速浏览一下最近的评论和城市。我们可以试着用csvsort来做:

csvcut -c reviews.date,city,reviews.title Datafiniti_Hotel_Reviews.csv | csvsort -c reviews.date -r | csvlook --max-rows 10

旁注:根据我选择的列,我有时会得到一个值错误,类似于Row has X values, but Table has Y columns。在这种情况下,添加--snifflimit 0可以解决问题。

csvgrep :

为了结束探索阶段,让我们寻找所有提到“安静”或“和平”酒店的评论标题。在下面的命令中,我添加了带有-l标志的行号。csvgrep命令的一个缺点是我不能将它的输出通过管道传递给其他命令。

csvcut -c name,reviews.title -l Datafiniti_Hotel_Reviews.csv | csvgrep -c reviews.title -r "(?i)(quiet|peaceful)

查询数据集

csvkit的一个非常酷的特性是能够用 SQL 从命令行查询数据。

例如,让我们再次搜索安静的酒店,但这次输出他们的城市和酒店名称:

csvsql --query "select city, name from Datafiniti_Hotel_Reviews where [reviews.text] LIKE '%quiet%' limit 10;" Datafiniti_Hotel_Reviews.csv

运行此命令会产生以下输出:

不幸的是,我不得不说,运行这个查询相当慢,这有点违背了使用命令行的初衷。

尽管我们可以将 CSV 保存为本地数据库,然后查询该数据库,但我再次发现,如果我打算走数据库这条路,我还不如全力使用编程语言。

结论

总而言之,我发现 csvkit 的前提很有趣,但是 sql 请求的缓慢运行速度是一个很大的失望。对我来说,价值主张不足以让我放弃熊猫和 jupyter,即使是为了探险。

CubeTrack:使用 Unity + ML-Agents 进行主动跟踪的深度 RL

原文:https://towardsdatascience.com/cubetrack-deep-rl-for-active-tracking-with-unity-ml-agents-6b92d58acb5d?source=collection_archive---------35-----------------------

游戏视图中的立方体追踪(图片由作者提供)

CubeTrack ,对我来说,是一次用 主动对象跟踪 (AOT)和游戏引擎支持的 深度强化学习 (RL)来弄脏我的手的练习,同时我等待着开发一个更复杂、更逼真的模拟我的真实世界部署环境的工具。到目前为止,我一直在现成的健身房环境中工作,但是对定制环境的需求让我选择了 Unity 和 ML-Agents。

ML-Agents 示例环境(图片来自Unity ML-Agents Toolkit Github 库)

ML-Agents 附带的示例环境不包含跟踪问题,因此我遵循创建新环境的指导原则,在平台上保持相同的多维数据集设置。有了这样一个相似、简单的设计,我认为整理这个项目并不需要太多的努力,把我和一些 ML-Agents 项目预置放在一起的游戏对象交换出去(只是为了风格的一致性),并使这个项目成为一个公共回购。示例环境对于学习、实践、测试和构建非常有用。希望 CubeTrack 可以以同样的方式使用,但在不同的问题空间。

该项目在https://github.com/kirstenrichardson/CubeTrack进行

如果您只是想使用环境,那么您需要知道的一切都在自述文件中。如果你是 RL 的新手,我建议你看一下史云光·斯廷布鲁格的 Youtube 频道上的一些视频,以获得一个总体概述,并进一步了解这里介绍的工作中使用的算法 PPO(近似策略优化)。或者,如果你有更多的时间,并且想更深入地研究,我推荐《深度思维》的大卫·西尔弗的《RL 简介》系列讲座。

如果你已经熟悉 RL,但对如何在 Unity 中用自定义环境解决自定义问题感兴趣,那么请继续阅读,我将介绍 ML-Agents 以及 CubeTrack 是如何组装的。如果你已经熟悉 Unity 和 ML-Agents,只是想知道基于学习的决策促进了成功的跟踪,那么跳到设计选择

ML-Agents 是 将常规 Unity 场景转化为学习环境 的插件。它提供了一个 Python 低级 API(包含在 Python 包mlagents_envs中),用于处理 Unity 环境中的通信器和 Python 训练脚本之间的通信(要么是工具包附带的实现,它们是自己的 Python 包mlagents的一部分,要么是您选择的实现,可以选择使用第三个 Python 包gym-unity将 Unity 环境包装在 gym 包装器中)。在将 ML-Agents repo 克隆到本地目录(设置为 pipenv )并安装各种 ML-Agents 包之后,我打开 Unity Hub 并在同一位置创建了一个新的 3D Unity 项目。

Version information:
  ml-agents: 0.18.0,
  ml-agents-envs: 0.18.0,
  Communicator API: 1.0.0,
  TensorFlow: 1.14.0,
  Unity: 2019.4.4f1,
  Python: 3.6.9

统一场景

这里没有华而不实。我所需要的是一个非玩家角色(NPC)(不受人类玩家控制的游戏对象)在一个区域内随机移动,提供一个移动的,以及一个游戏对象代表跟踪器(或 代理 ,使用 RL 术语)响应一些外部“玩家”输入而移动。令人困惑的是,Unity 可以将 NPC 称为人工智能控制的,但人工智能在这里是指预编程的,因此是独立的,而不是像我们的 RL 模型“玩家”那样主动学习,它位于 Unity 的外部。

层级窗口示例(按作者排序的图像)

CubeTrack 有两个几乎相同的场景,CubeTrack 和 VisualCubeTrack,后者在代理立方体上增加了第一人称视角摄像头。除了游戏相机和照明,场景只包含一个名为 Area(或 VisualArea)的预设——一个包含所有组成 RL 环境的组件的空游戏对象。这个容器预置使复制环境变得容易,拥有多个环境实例可以加速训练,将我们的代理立方体车队的“共享大脑”暴露给并行的多种体验。该区域可分为三个部分:

  • 训练场:由一系列立方体组成的场地和墙壁。此外,13 个圆柱体(航路点)以网格模式放置在地面上,它们的网格渲染器组件和胶囊碰撞器组件未选中,因此它们都是不可见的,并且能够通过。
  • 目标:一个紫色的立方体,用更小的子对象立方体作为头带、眼睛和嘴巴。为了让立方体在平台上移动,添加了一个名为 NavMesh 代理的组件和一个名为TargetMovement的脚本。一个 NavMesh 被烤到了地上(区域预置是开放的,因此它存在于每个区域实例中),每个航路点都被赋予了标签RandomPoint。然后可以通过脚本从标签为RandomPoint的对象列表中选择一个随机航路点,并将航路点的位置设置为 NavMesh 代理的目的地,即目标立方体。更多细节请参见此视频
  • 代理:一个蓝色的立方体,有头带、眼睛和嘴巴,这次有一个刚体组件,使它能够在物理的控制下行动,并施加力。你可以使用刚体的质量和阻力参数来改变立方体滑动的方式。当使用视觉观察时,添加了一个相机作为子对象,并定位为指向正面(向下看的那个transform.forward)。

场景视图显示航路点对象和代理摄像机 FOV(图片由作者提供)

学习环境建立

通过 ML-Agents,将这个普通的 Unity 场景转变为人工智能的训练场所变得超级简单。做这件事的文档是这里是,但是这些是基本步骤..

  • 安装 Unity 包

选择游戏对象作为你的 RL 代理..

  • 添加一个脚本组件
  • 添加一个行为参数组件
  • 添加一个决策请求器组件
  • (可选)添加一个摄像头传感器组件

转到您的本地 ML-Agents repo 目录(或本地 CubeTrack repo 目录)并..

  • 添加一个配置文件

所有这些都准备好了,你的 Unity 场景就可以训练一个模型了。要开始训练,请确保代理多维数据集的行为参数组件下的模型字段显示无。打开终端并使用单一命令行实用程序…

*mlagents-learn ./config/ppo/CubeTrack.yaml --run-id=runName*

…带有结尾标记的任何选项(使用-h 探索 mlagents-learn 命令的完整用法)。然后转到 Unity 编辑器,点击▶️.提供了很大的灵活性,包括恢复尚未结束的训练运行(全局 max_steps 参数)或在现有模型的基础上进行训练。更多详情见此处

当训练运行完成或提前终止时,模型权重被保存到。“结果”文件夹中的 nn(神经网络)文件。mlagents-learn 命令需要从与您正在使用的配置和结果文件夹相同的位置调用。如果您已经克隆了 ML-Agents repo,那么您可以将您的配置文件与示例环境的所有 yaml 文件放在一起,并从 ML-Agents repo 目录的根目录运行命令。cube track repo 有自己的配置和结果文件夹,因此可以在没有 ML-Agents repo 本地副本的情况下使用。在这种情况下,从 CubeTrack repo 目录的根目录发出命令。

推断非常简单,只需复制并粘贴。nn 文件到您的项目资产文件夹,拖动到模型领域,并点击▶️.

设计选择

观察

首先,我试图用向量观察来培养追踪行为。被选作观察集的变量组在不同的实验运行中有所不同,但最终成为以下 12 个观察集:

  • 代理的位置(2 个 obs,对象变换位置的 xz 组件)
  • 目标的位置
  • 代理的速度(velocity.magnitude)
  • 目标的速度
  • 代理的面向方向(transform.forward)(矢量 so 3 obs)
  • 目标面对的方向

一旦以这种方式实现了跟踪,就添加了一个相机传感器,删除了CollectObservations()功能,并将检查器窗口中的空间大小设置为 0。相机传感器设置为传送 84 x 84 PNG 型号的图像。下面的 GIF 演示了代理的 POV(注意,这是在调整图像大小之前——模型从同一台相机接收图像,但分辨率较低)。喊出身临其境的极限视觉变色龙教程由亚当凯利在这里。

从代理的机载摄像头查看-游戏视图显示 2(图片由作者提供)

在我整理项目和利用 ML-Agents 示例环境中使用的游戏对象之前,我已经通过选择具有最高对比度的材质颜色(黑色目标立方体、浅灰色地面和白色墙壁)、关闭阴影和关闭阴影投射,给了我的代理成功进行视觉观察的最佳机会。在此设置中,足以传递模型灰度 84 x 84 图像(相机传感器组件下的勾选框),但在 VisualCubeTrack 的较新版本中,需要彩色图像。

(左)最新版本的 CubeTrack(右)早期版本的 CubeTrack(图片由作者提供)

行动

最初,动作空间被设置为连续的。该模型传入了两个浮点值,这两个值在用作同时沿 xz 轴施加的力的大小之前,都使用Mathf.Clamp在-1 和 1 之间进行了限幅。我后来决定了一个简单的 5 选离散行动空间..

行动空间(图片由作者提供,灵感来自托马斯·西蒙尼尼Unity ML-Agents 简介)

通过将每个动作选项分配给一个箭头键,并对看起来合理的选项进行实验,来测试每种情况下施加的力的大小。前进/后退的幅度为 500,转弯的幅度为 250。

我遇到的一个问题可以被描述为代理持续“超调”,导致旋转行为或钟摆般的向前然后向后移动。我意识到我将决策请求者的决策周期设置为 10,但勾选了“在决策之间采取行动”,导致连续十步采取相同的行动。将决策周期更改为 1 并没有使 sim 不堪重负,也没有消除超调。

奖励

我第一次尝试奖励工程学是受到了下面的博客的启发,这篇博客是由亚当·普莱斯写的关于利用课程学习进行追逃(见他的开源追逃游戏这里)。

* [## 使用 Unity ML-agent 的课程学习

教一队猎人捕捉猎物。

towardsdatascience.com](/curriculum-learning-with-unity-ml-agents-c8e7a1aa5415)

复制“延伸”行为非常有效。我增加了目标的速度,减少了被认为“足够接近”目标的距离。然后,我尝试在这个模型的基础上进行新的培训,鼓励使用计数器变量进行跟踪,计算目标范围内连续FixedUpdate()呼叫的数量。目标速度再次增加,这一次“持续时间”阈值(计数器变量需要达到的值)也增加了。第二阶段进展缓慢!一旦剧集终止代码被删除,代理人的最终行为是只跟踪导致奖励的时间长度,然后失去兴趣(显然是回想起来)。

我需要一个函数来分配每一步的比例奖励,我在的一篇论文中看到了一个这样的例子罗等人(2018) 。该功能如下所示:

奖励函数(图片来自罗等(2018) )

  • Adcλ 都是调谐参数。 Ad 纯属设计选择, A 为一步可分配的最大奖励(设置为 1,与罗纸相同) d 为最佳前进/后退距离(根据游戏视图中看似合理的差距设置为 3)。
  • 括号的左边是奖励代理的位置,右边是代理面对的方向。为了生成[-1,1]范围内的奖励,需要设置 cλ 以使括号中的最大值为 2。Unity 中的旋转从-180°到 180°,因此如果旋转和定位的权重相等,则 λ 应该总是 1/180。 c 的值根据所用训练场地的大小而变化。
  • xy 代表从代理到目标的航向矢量的 xz 分量。取方向分量总和的平方根,计算矢量的长度,即距离。当代理和目标在 x 平面上的位置相同,但heading.z为+3 时,整项为零,奖励最高。我意识到heading.z的符号根据目标的行进方向而变化,导致代理人有时因在目标后面而被奖励,有时因在目标前面而被奖励(没有帮助!).因此,有一个额外的代码块来确保在目标的后面发布最高奖励,即使根据世界 z 轴,代理在技术上在目标的前面。
if (Vector3.Dot(heading.normalized, Target.transform.forward) > 0)
 {
  heading.z = Mathf.Abs(heading.z);
 } else {
  heading.z = -Mathf.Abs(heading.z);
 }
  • a 是代理的transform.forward矢量和航向矢量之间的角度。这鼓励目标去目标。最初我将 a (在下面的引用中)的描述解释为代理的transform.forward和目标的transform.forward之间的角度,但是后来的实现(指向的角度)工作得更好,我认为这是有意义的,特别是在视觉设置中。

“当物体完美地站在智能体前面距离 d 处,且不旋转时,奖励 A 最大”—罗等(2018)

下面是该项目的函数的代码实现。

var rDist = Mathf.Sqrt(Mathf.Pow(heading.x, 2f) + Mathf.Pow((heading.z - d), 2f));        
 var r = A - ((rDist/c) + (a*lam));
 AddReward(r);.

结果

培训在我的联想 Thinkpad T480s 笔记本电脑(英特尔酷睿 i7–8550 u 处理器,4 核,8 线程,1.80 GHz 处理器主频)上进行,将max_steps设置为 5M。下图是 TensorBoard 生成的平滑度为 0.99 的累积奖励图。

使用矢量观察(粉色)进行的训练最初需要大约 5 个小时,但使用六个训练场后减少到大约 2 个小时(参见立方体轨道场景中的游戏视图显示 2)。在这种情况下,奖励值代表六个区域实例的平均奖励。曲线图的坐标轴模糊不清,但累积奖励稳定在 2500 左右。注意,在一集中可实现的最大奖励是 3000(除非该集的累积奖励下降到-450 以下,否则该集在 3000 步处终止),但是将要求代理的随机开始位置和面向方向是从奖励函数中引出直接+1 的位置和面向方向。

5 次不同训练跑的累计奖励超过 500 万步(图片由作者提供)

下面的深蓝色线条说明了 VisualCubeTrack 的第一个版本中视觉观察跟踪的成功,具有高对比度的颜色,没有阴影或阴影。在较新版本的 VisualCubeTrack 中使用灰度图像进行训练导致了显著的性能下降(浅橙色),而仅改变为彩色观察对改善事情(红色)几乎没有作用。在这两种情况下,训练都被缩短了。直到视觉编码器从simple (2 个卷积层)变为resenet ( IMPALA ResNet —三个堆叠层,每个层有两个剩余块),进展才有所改善(浅蓝色),累积奖励稳定在 2300 左右,推理呈现合理行为。这次训练包括一个训练场地,持续了大约 56 个小时。

范围

本博客主要讨论的是第一个“设置”(奖励功能,环境设置,训练配置等。等等。)来引出令人信服的跟随行为,仅此而已。受过训练的代理在 VisualCubeTrack 中的表现尤其有改进的余地。改进的途径包括..

  • 进一步调整配置文件中的超参数
  • 进一步奖励工程,例如增加长期奖励
  • 使用不同的算法(ML-Agents 提供软演员评论家的实现)或不同的实现(在使用 ML-Agents 之前,我选择的 RL 库是来自 Antonin RAFFIN 和其他人的稳定基线
  • 使用额外的技术,例如已经提到的课程学习或称为好奇心的内在奖励信号
  • 例如,使用域随机化使学习到的策略更加健壮
  • 通过在多个环境实例上进行训练或使用可执行文件而不是在编辑器中进行训练来提高训练效率

除了在当前版本的环境中提高性能之外,具有深度 RL 的 AOT 还可以通过以下方式进一步提高..

  • 增加学习问题的复杂性,例如引入与目标或增加的障碍碰撞的惩罚
  • 使用更加复杂和真实的 sim 卡!!

CubeTrack.nn 上的推论(图片由作者提供)

如果你发现任何疏忽或有任何想法或问题等。那么,请在下面发表评论或在@ KN _ Richardson 给我发推文。注意安全!

[1]:朱利安尼,a .,伯格斯,v .,滕,e .,科恩,a .,哈珀,j .,埃利翁,c .,戈伊,c .,高,y .,亨利,h .,马塔,m .,兰格,D. (2020)。Unity:智能代理的通用平台。 arXiv 预印本arXiv:1809.02627https://github.com/Unity-Technologies/ml-agents

[2]:罗文伟、孙平、钟、冯芳、刘文伟、张、汤、王(2018 年 7 月)。基于强化学习的端到端主动目标跟踪。在机器学习国际会议(第 3286–3295 页)。

[3]: A .希尔,a .拉芬,m .埃内斯托斯,a .格莱夫,a .卡内维斯托,r .特拉奥雷,p .达里瓦尔,c .黑塞,o .克里莫夫,a .尼科尔,m .普拉波特,a .拉德福德,j .舒尔曼,s .西多尔,y .吴,《稳定的基线》,,2018。*

用于深度学习的 WSL2 上的 Cuda 第一印象和基准

原文:https://towardsdatascience.com/cuda-on-wsl2-for-deep-learning-first-impressions-and-benchmarks-3c0178754035?source=collection_archive---------14-----------------------

不打算说谎,微软一直在软件开发社区做一些好事。我喜欢用 Visual Studio 代码编写代码,如果你想为生产优化你的深度学习模型,ONNX 非常棒。WSL2 允许你访问整个 Linux 内核正是我一直想要的,但缺乏 CUDA 支持意味着它对我这个人工智能工程师来说是不可能的。

作为一名人工智能工程师和内容创作者,我需要 Windows 作为工具来创建我的内容,但我需要 Linux 来轻松运行和培训我的人工智能软件项目。我在我的机器上有一个双启动设置,但它并不理想。我讨厌当我在训练一个模型时,我不能使用我的创作工具。所以我必须同步工作而不是异步工作。

我知道大多数深度学习库支持 Windows,但让东西工作的体验,尤其是开源人工智能软件,总是令人头疼。我知道我可以使用类似qemu的东西在 Linux 上运行 Windows 软件,但这需要我将整个 GPU 隔离到 VM,导致我的 Linux 实例无法访问它。

支持 CUDA WSL2 的微软和 Nvidia 来了!所有 Linux 工具在 Windows 上本机运行的承诺将是我的工作流的一个梦想。当他们发布一个预览版本时,我马上就接受了。在这篇文章中,我将写下我的第一印象以及一些基准!

在 WSL2 上设置 CUDA

在 WSL2 上设置 Cuda 对我来说超级简单。Nvidia 有很好的文档解释你需要采取的步骤。令我惊喜的是,我没有遇到一个错误!我不记得上一次设置仍在测试阶段的软件时发生这种情况是什么时候了。

设置我的机器学习工具

作为一名专门花大量时间进行深度学习的人工智能工程师,我需要一些工具来改善我的开发体验。

  1. 支持 CUDA 的 docker(NVIDIA-docker
  2. PyTorch 作为我选择的深度学习框架

自从双引导进入 Linux 后,我还没有尝试过 WSL2,所以我惊喜地发现我可以像在普通的 Ubuntu 机器上一样轻松地下载和安装我的工具。我安装这些软件包都没有问题。正如你所料,这是一次 Ubuntu 体验。

培训模型

好了,这是真正的考验。首先我将谈谈我的经验,然后我将展示一些基准来比较 WSL2 和裸机 Linux 上的 Cuda。

我认为在训练深度学习模型时,无论你是否有自己的硬件或是否在云上训练,一个常见的工作流程是为所有数据准备一个单独的磁盘,为实际的操作系统准备一个磁盘。WSL2 将自动检测和安装 Windows 10 识别的任何磁盘,因此很酷;但是我在安装的数据驱动器上遇到了文件permissions的问题。

注意 : 这个问题只出现在挂载的驱动器上,如果你在你的 WSL2 文件系统中做任何事情,它都会正常工作。

因此,由于文件权限受到限制,我的训练脚本会在随机数据文件上出错。所以我读了 WSL 文档,它说…

从 WSL 访问 Windows 文件时,文件权限或者从 Windows 权限中计算,或者从 WSL 添加到文件中的元数据中读取。默认情况下,不启用此元数据。

好的,WSL2 计算文件权限,有时会出错,我想,我只需要启用这个元数据就能让它正常工作对吗?嗯,差不多吧…所以我添加了元数据,然后对我所有的数据文件做了chmod -R 777,这是一种快速而肮脏的方法,可以释放权限,这样我就可以继续训练了!嗯,有一点效果...然后它又出现了同样的权限错误!所以我查看了权限,它不知何故恢复了我的更改,回到了受限访问。更有意思的是,如果我多次检查文件权限,它就会恢复到我的 chmod 权限。所以这是随机改变权限,我知道的唯一方法是用ls -l检查权限。我发现了一个奇怪的 WSL2 量子现象,我将硬币...薛定谔的文件权限 当我使用chmod 700将完全的读、写和执行权限只授予 WSL2 用户而不是每个人和他们的妈妈时,问题就解决了。这在某种程度上解决了薛定谔的文件权限问题,所以我继续生活。

从那以后,我开始训练,没有任何问题!一切看起来都很好,模型损失正在下降,没有什么看起来不寻常的。我决定做一些基准测试,比较 Ubuntu 与 WSL2 Ubuntu 与 Windows 10 的深度学习训练性能。

基准测试——Ubuntu vs . wsl 2 vs . Windows 10

为了进行基准测试,我使用了来自 Pytorch 示例回购的 MNIST 脚本。我修改了脚本,使网络更大,以获得更大模型的更准确读数。

*class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 128, 3, 1)
        self.conv2 = nn.Conv2d(128, 128, 3, 1)
        self.conv3 = nn.Conv2d(128, 128, 3, 1)
        self.dropout1 = nn.Dropout2d(0.25)
        self.dropout2 = nn.Dropout2d(0.5)
        self.fc1 = nn.Linear(15488, 15488//2)
        self.fc2 = nn.Linear(15488//2, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = self.conv3(x)
        x = F.relu(x)
        x = F.max_pool2d(x, 2)
        x = self.dropout1(x)
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)
        output = F.log_softmax(x, dim=1)
        return output*

我的机器规格是…

  • 英特尔 i9 10920X — 12 个内核,24 条线程
  • 英伟达 RTX 2080 TI — 11GB VRAM

我对…进行了 3 次测试

  • Ubuntu 20.04
  • WSL2 Ubuntu 20.04
  • Windows 10

我使用 FP32 精度的 512 批次大小,运行 14 个时期。以下是结果…

**

所以说实话成绩还不算太差!在我的英伟达 RTX 2080 Ti 上,支持 CUDA 的 WSL2 比原生 Ubuntu 多花了 18%的时间来训练 MNIST 模型。WSL2 对 CUDA 的支持仍处于早期预览模式,我希望工程师和研究人员以及微软和 Nvidia 最终会达到接近 Ubuntu 的性能。

对于一些人来说,花 18%的时间来训练模型可能是不可行的,但对我来说,如果这意味着我可以异步地训练深度学习模型,并使用我的 Windows 兼容软件工具来创建内容,我可以接受这种小的性能打击。我打算暂时继续使用 Windows 10 和 WSL2 作为我的日常驱动程序,看看效果如何!

✍🏽原载于【https://www.michaelphi.com

🥇注册我的 电子邮件简讯 ,了解最新的文章和视频!

📺喜欢看基于项目的视频?来看看我的 Youtube

科莫说,21%的纽约居民患有新冠肺炎。这是正确的吗?

原文:https://towardsdatascience.com/cuomo-says-21-of-new-york-residents-have-had-covid-19-is-this-correct-23e8a63d2045?source=collection_archive---------60-----------------------

处理统计数据时因果推理的案例研究

撰稿*,编辑* 拉明·拉梅扎尼 。—2020 年 5 月 4 日

如果被选择偏差污染,数据可能会欺骗你。我们的分析需要超越数据本身,调查数据生成/收集过程。图片:来源

“选择偏差”是由优先排除数据中的样本引起的[1]。它是验证统计结果的一个主要障碍,在实验或观察研究中几乎检测不到。这一切都始于我们通常在科学研究中使用样本群体,并假设样本代表总体(统计学方法)。让我们从一个真实的例子开始。

在新冠肺炎疫情危机期间,一项全州范围的研究报告称,21.2%的纽约市居民已经感染了新冠肺炎病毒。该研究对全州 3000 名纽约居民在杂货店和大卖场进行了抗体测试,以表明某人是否感染了该病毒。Cassie Kozyrkov【3】认为这项研究可能受到选择偏差的污染。假设是,研究中的队列主要偏向于高风险人群和已经感染病毒的人群。总人口的大部分可能包括规避风险和谨慎呆在家里的人;这些人被排除在研究样本之外。因此,报告的死亡人数(即 21.2%)很可能是夸大的。Cassie Kozyrkov 在解释这项研究中选择偏差的原因方面做了惊人的工作[3]。但在这里,我们试图调查一个更通用的方法来当场选择偏差问题。

幸运的是,我们有因果推理的工具。因果推断要求我们在分析数据时做出某些似是而非的假设。数据并不总是完整的,也就是说,它并不总是能说明全部情况,仅从数据得出的分析结果(例如,虚假关联)往往会产生误导。例如,人们可能会发现吸烟的人可能会患肺癌,同时有黄色的指甲。如果我们发现这种联系(肺癌和黄指甲)很强,我们可能会得出一些错误的结论,即一个导致另一个。

图片:来源

回到我们的新冠肺炎故事,在抗体测试研究中我们可以做出什么因果假设?让我们考虑图 1,其中以下每个假设代表一个优势。

I)我们知道,如果我们做相关的测试,将会发现抗体。

ii)感染过新冠肺炎病毒并存活下来的人会产生该病毒的抗体。

iii)敢于冒险的人更有可能去户外并参与测试研究。

iv)为了在图表中突出样本群组和总体人口之间的差异, [Elias Bareinboim](http://elias bareinboim columbia) 提出了一个假设变量 S(代表“选择”)。图 1 中方框内的变量代表两个群体不同的特征。您也可以将 S 视为包含/排除标准。变量 S 具有来自变量“冒险”和“携带病毒”的输入边。这意味着样本队列和总体人群在这两个方面有所不同。

图 1:说明选择偏差场景的图形模型。变量 S(方形)是一个产生差异的变量,它是一个假设变量,指出两个群体的不同特征。

现在,我们已经将我们的假设编码成一个透明而简单的图表。你可能想知道为什么我们要费尽周折制作这个图表?这对我们识别选择偏差甚至去偏差过程有什么价值?

好问题。让我们从这样一个问题开始:它如何帮助我们找到识别选择偏差的共同模式/原则?

用因果图识别选择偏差

识别选择偏差的几个快速提示:1)在原因变量和结果变量之间的后门路径上找到任何碰撞器变量,2)当你的数据收集过程以这些碰撞器变量为条件时,选择偏差发生[1]。注意,这些提示是发现选择偏差的充分条件,但不是必要条件。我们所说的条件作用是指只考虑一个变量的一些可能性,而不是全部。

技巧 1 中的后门路径是指原因变量(COVID 测试)和效果变量(抗体%)之间的任何路径,带有指向原因变量的箭头([4],第 158 页)。在我们的例子中,唯一的后门路径是“新冠肺炎测试←冒险→ S ←携带病毒→抗体%”。如果我们封锁每一条后门路径,就会消除虚假关联。我们如何知道后门路径是否被阻止?

Judea Pearl 在他的书[4]中谈到了 3 条规则,告诉我们如何阻止后门路径和虚假的关联流。如果你对这 3 个规则的完整数学证明感兴趣,请参考[5]

A)在链式连接中,A→B→C,以 B 为条件阻止关于 A 的信息到达 C,反之亦然。

B)在一个分叉或混杂连接中,A←B→C,以 B 为条件阻止关于 A 的信息到达 C,反之亦然。

C)在对撞机中,A→B←C,正好相反的规则成立。当没有以 B 为条件时,A 和 C 之间的路径被阻塞。如果我们以 B 为条件,则该路径是畅通的。请记住,如果这条路径被阻塞,A 和 C 将被视为相互独立。

有了这样的背景知识,我们知道再看我们的图解。我们现在看到,后门路径上有 3 个基本组件:1)一个分叉“新冠肺炎测试←高风险→S”;2)一个对撞机“高风险→ S ←携带”;3)另一个叉“S ←携带病毒→抗体%”。现在我们看到,如果我们不在碰撞器中对变量 S 进行条件运算(规则 c),这个后门路径就被阻塞了。如果我们以变量 S 为条件(例如,set S={high risk,had virus }),后门路径将被打开,并在您的抗体检测结果中引入虚假关联。

现在我们认识到,如果我们在原因→结果之间的后门路径上以碰撞子为条件并打开后门路径,我们将遇到选择偏差问题。有了这个结论,我们可以很快确定我们的研究是否有选择偏差的问题。当图形复杂时,这种识别过程也可以自动化。所以,我们把这种判断交给算法和计算机。希望您在这一点上确信,使用图形模型是识别选择偏差的更通用和自动化的方法。

do-calculus 无偏估计

为了测量两个变量 X 和 Y 之间的因果关系,Judea Pearl 引入了 do-calculus 符号[4]。例如,P(Y|do(X=x))表示当每个 X 固定为值 X 时,从 X 到 Y 的因果效应.注 P(Y| X=x)反映了 Y 在 X 值为 X 的个体中的总体分布.后者只能表示 Y 与 X 之间的关联.如果你对更多细节感兴趣,请参考([6],53 页).

现在我们感兴趣的是“新冠肺炎试验→抗体%”之间的因果估计,P(抗体|do(试验))。换句话说,如果我们测试群体中的每个人,因果效应代表抗体发现的可能性。我们的读者可能想知道 do-calculus 在这一点上是否有意义,但是我们如何计算和删除 do-operator 呢?

do-calculus 只有 3 个规则来减少我们熟悉的计算。下面三个规律的完整证明可以参考[7]。

a)当我们观察到一个与 Y 无关的变量 W 时,那么 Y 的概率分布不会改变,

P(Y|do(X),Z,W) = P(Y|do(X),Z)。

b)如果一组 Z 个变量阻塞了从 X 到 Y 的所有后门路径,那么以 Z 为条件,do(X)等价于 see(X),

P(Y|do(X),Z) = P(Y|X,Z)。

c)如果从 X 到 Y 没有因果路径,那么

P(Y|do(X)) = P(Y)。

在我们的例子中,

我们可以看到,在方程的最后一步,我们需要在研究中测量四个概率项,以获得无偏估计。如果我们假设封闭世界(风险= {高,低},病毒= {真,假}),这意味着我们需要测量每一个分层的群体。在报告[1]中,他们报告的数值是 P(抗体|测试,风险=高,病毒={。})这与真正的因果效应相比是有偏差的。

现在我们已经看到,do-calculus 可以帮助我们确定我们需要哪些部分来恢复无偏估计。希望您在进行因果推理时,对图形模型结合 do-calculus 的强大功能印象深刻。

参考文献

[1]埃利亚斯·巴伦博姆和朱迪亚·珀尔。控制因果推理中的选择偏差。《人工智能和统计》,第 100-108 页,2012 年。

[2]杰里米·伯克。cuomo 说,一项全州范围的抗体研究估计,2020 年,21%的纽约市居民患有冠状病毒。

[3]卡西·科济尔科夫。21%的纽约市居民真的感染了新型冠状病毒吗?, 2020.

[4]珀尔、朱迪亚和达纳·麦肯齐。原因之书:因果的新科学。基础书,2018。

[5]盖革、丹、托马斯·维尔马和朱迪亚·珀尔。"识别贝叶斯网络中的独立性."网络 20.5(1990):507–534。

[6]珀尔、朱迪亚、玛德琳·格雷穆尔和尼古拉斯·朱厄尔。统计学中的因果推断:初级读本。约翰·威利父子公司,2016 年。

[7]黄、李一民和马可·瓦尔托塔。"珀尔的干涉计算完成了."arXiv 预印本 arXiv:1206.6831 (2012)。

杯形 R-闪亮工具

原文:https://towardsdatascience.com/cuped-r-shiny-tool-7a4869d77f0a?source=collection_archive---------32-----------------------

CUPED 简介

最近,我一直在探索提高实验灵敏度的方法——通过减少与实验前信息相关的方差。如果可以确定实验前指标(协变量)和实验指标之间的强相关性,则在进行任何显著性测试之前,可以控制实验指标中存在的方差。当使用预实验数据(CUPED)方法实施控制时,有几个不同的程序值得考虑,但我在 以前的中型帖子 (改编自【Booking.com】)中已经写过关于“协变方法”的内容。协变量方法关注预实验和实验指标之间的关系(这通常是一个连续变量),忽略实验开始前存在的差异。所述方差的减少导致实验能力的增加,这意味着您更有可能检测到统计上显著的影响(考虑这是一种降噪的方法,以便检测在您的实验条件之间可能存在或可能不存在的任何真实影响)。

我以前在 CUPED 方法方面的工作包括一个使用我在 Python 中的一些工作的例子,以及如何将预实验信息合并到您在 cookie_id 单元上的实验数据中。遗憾的是,执行这种分析可能是相当劳动密集型的,包括导入数据帧,确保它们具有唯一的标识符,然后执行与实验前和实验数据帧的合并(我们大多数人都没有那么多时间)。

出于这个原因,我构建了一个前端的、用户友好的 R Shiny 工具,它只需要上传几个简单的文件,所有繁重的工作都会为您完成。除了将我的 Python 作品翻译成 R 函数,这是一个相当简单的工作,你可以在这里 找到该工具的 链接。

你也可以在我的 GitHub 上找到该工具的代码。

使用工具

可以通过上面的 url 访问 CUPED 分析工具。您只需为协变量和实验指标填写两个单独的 xlsx 文件。您可以下载这些模板并将它们上传回应用程序。

一旦这些文件被上传回应用程序,就会为您计算 CUPED 调整后的指标,因此不需要额外的代码。应用于每个 cookie_unit 的常数(θ)计算如下:

cor_frame <- inner_join(covariate, metric, by = ‘User_Id’)

 covariance <- cov(cor_frame$Metric, cor_frame$Covariate_Metric)

 variance <- var(cor_frame$Covariate_Metric)

 theta <- covariance/variance

 cor_frame$CUPED_Adjusted_Metric <- cor_frame$Metric — (cor_frame$Covariate_Metric — mean(cor_frame$Covariate_Metric)) * theta

然后,您可以为您的协变量和实验指标绘制散点图;还提供了您的 R 和 p 值,这有助于您确定变量之间的关系强度,以及随后您的协变量是否适合 CUPED 方法:

图一。实验前协变量和实验指标之间的相关性,以及每个实验条件和指标的分布。r 和 p 值在图上给出。

在确定了实验前指标和实验指标之间的关系后,您可以对 CUPED 调整后的指标执行显著性测试。此输出提供组间方差分析(ANOVA)的结果,其中 p 设置为 0.05 :

图二。经 CUPED 调整的指标的组间单向方差分析的输出。

然后,您可以分别生成实验指标和实验前协变量的平均值和标准差的表格。此表中最右边的一行显示了在显著性测试之前,您的 CUPED 调整指标忽略的相对差异量:

图 3。计算前后平均值和标准偏差的表格输出。方差减少的百分比是两个标准差之间的相对差值。

从图 3 中可以看出,在对所有三个实验条件进行显著性测试之前,已经减少了大量的差异。进行这种分析意味着你将提高实验的灵敏度,并得出更大数量的具有统计学意义的测试结论。

您还可以在您的实验中使用的每个个体变体之间生成成对比较(重复 t 检验)。这不仅有助于您识别给定的变异是否超出了您的控制条件,还能识别所有其他比较之间的统计差异:

图 4。表输出显示了 CUPED 调整指标的实验条件之间的独立 t 检验

享受这个工具吧!

弗兰克

使用 K-Means 聚类管理两个人的 Spotify Discover 播放列表

原文:https://towardsdatascience.com/curating-a-spotify-discover-playlist-for-two-people-with-k-means-clustering-a926a9e1ec7d?source=collection_archive---------46-----------------------

选择一个朋友一起发现全新的音乐。我们通过机器学习创建了一个符合你两种口味的冒险播放列表。

照片由晨酿Unsplash 拍摄

iTunes 革新了音乐。Spotify 又这么做了。

音乐是我生活中的必需品。不仅因为我可以即时访问 5000 万首歌曲和超过 100 万个播客(耐心等待 9 月份的罗根),还因为内置的推荐功能,在我还没有听完之前,它就神奇地告诉我我最新喜欢的歌曲是什么。Spotify 研究了我过去 7 年的收听历史,在彻底改变我的音乐品味方面发挥了巨大作用。我对 90 年代地下新灵魂 boombap 的热爱不是由我的韩国家庭介绍给我的,也不是来自我成长的爱看排行榜前 50 名的尔湾郊区。这是因为连续几个小时一次又一次地陷入 Spotify 推荐算法的兔子洞。我已经能够发现最喜欢的艺术家,并使我的流派调色板多样化,这远远超出了没有 Spotify 的情况。

对我的音乐探索之旅最重要的帮助就是 Spotify 的 Discover Weekly 播放列表。通过访问超过 1.1 亿用户的收听历史,Spotify 数据科学家每周一为用户推荐 30 首新歌曲,充分发挥了他们的 ML 能力。

我的每周探索播放列表截图

在 Spotify 的推荐中寻找一颗隐藏的宝石是如此令人愉快的经历,以至于我想知道是否有可能将这变成一次合作体验。我想创建一个探索每周播放列表,了解两个人的音乐品味,并为他们推荐歌曲。由于隔离仍然是一件事,我认为这个“一起发现”播放列表可以作为一种新颖的社交活动。所以我和我的朋友 Arjun Reddy 合作,我们准备好了。

点击这里查看完整的 GitHub 回购:https://github.com/trustinyoon/Spotify-Discover-2gether

数据收集

Arjun 和我决定将为我们的集体音乐品味策划的“一起发现”播放列表自动化,作为一项测试。我们使用 Spotify Web API 的轻量级 Python 库 Spotipy,并创建了一个 Spotify 开发者应用程序来获得 Spotify 个人资料数据的授权。这是官方的 Spotipy 文档:https://spotipy.readthedocs.io/en/2.13.0/

我们还从 Plegas Gerasimos 的回购协议中派生出授权流程代码,其中包含授权流程代码,可在此处找到:【https://github.com/makispl/Spotify-Data-Analysis

然后,我们创建了一个代码,授权访问用户的 Spotify 个人资料,使用 Spotify 的 current_user_top_tracks()函数提取他们的 50 首中期歌曲。中期是最佳的时间范围,因为短期歌曲太短(大约 1 周的歌曲)而长期太长(基本上是用户所有时间的歌曲历史)。然后将用户的前 50 首中期歌曲提取到一个. csv 文件中,并对第二个用户重复这一过程。

我们将前 50 首歌曲合并成一个包含 100 首歌曲的数据框架,用于分析和推荐歌曲。每首歌曲都有 Spotify 提供的关于其不同声音特征的官方数据:可跳舞性、能量、调(音乐调)、响度、模式(小调或大调)、语速、声学、乐器性、活跃度、效价(听起来有多积极/快乐/欢快)和节奏。这些特性用于从我们的数据帧创建集群。在得出其他特征对我们的分析来说是噪音的结论后,我们选择将重点放在可跳性、能量、语速、声音、效价和节奏上。这是我们最近最喜欢的歌曲的分布图。

k 均值聚类

现在我们有了两个用户的前 50 首歌曲,我们可以使用这些歌曲来推荐适合两个人最近音乐品味的新歌。K-means 聚类是我们选择的方法,以便我们可以将组合歌曲中的每首歌曲分组到具有相似声音特征的聚类(子流派/歌曲类型)中。我们选择 k=20,即使 elbow 方法显示最佳 k=6,因为我们希望有更多指定的聚类,并基于不太一般化的聚类来推荐歌曲。如果歌曲在 6 轴图上的位置接近欧几里德距离,则它们将被聚集在一起。下面是 100 首歌曲的三维可视化,分别用它们各自的聚类来标记。

可视化时,一些信息会丢失,因为我们将 6 个特征展平到 3 个维度上。我们仍然能够可视化 20 个聚类,其中在给定的聚类中,每首歌曲彼此之间具有接近的欧几里德距离。

我们可以在下面进一步探究每个集群的摘要。

每个聚类的歌曲数量直方图(左)聚类的平均歌曲特征分布(右)

构建“一起发现”播放列表

一旦我们获得了每个集群的歌曲列表,我们就将每个列表输入到 Spotipy 的 recommendation()函数中,该函数接受 5 首种子歌曲作为推荐的基础。对于包含 5 首以上歌曲的聚类,我们从列表中随机选择 5 首来代表该聚类。包含少于 5 首歌曲的集群,我们保持原样。我们为每个聚类运行推荐功能,每次它为包含少于 5 首歌曲的聚类产生 1 首推荐曲目,为包含 5 首歌曲的聚类产生 2 首推荐曲目。我们想把更多的权重放在有更多歌曲的集群上,因为这意味着我们通常更喜欢那些集群中的歌曲。在获取所有推荐的曲目后,我们将它们放入一个列表中作为 Spotify 函数的参数,该函数会自动创建一个播放列表,并将给定的歌曲列表直接放入用户的 Spotify 库中。

结论

经过一周的编码,我们终于自动化了“一起发现”播放列表!下面是它的样子!

虽然有几首歌我们已经听过了,但我们普遍对推荐的质量非常满意,我们每个人都在个人播放列表中添加了几首推荐的歌曲!

“一起发现”还没有被开发成一个有效的公共网络应用。我们正在寻找任何能够熟练使用 JSON、web APIs 或 UI/UX 的应用程序开发人员,他们有兴趣帮助我们将这个项目变成一个可供任何两个想要一起探索新音乐的人使用的应用程序!如果你感兴趣,请通过 trustinyoon@gmail.com 或 arjunravulareddy@gmail.com联系我们!


9/14/20 更新:我们已经建立了一个功能正常的网络应用程序,正在寻找出色的用户界面/UX 和图形设计师来帮助我们的标志,着陆页面美学和营销材料!如果有兴趣,请给 trustinyoon@gmail.com 发邮件,附上你的投资组合链接:)

Python 中装饰者的奇特案例

原文:https://towardsdatascience.com/curious-case-of-decorators-in-python-9644a99e538?source=collection_archive---------37-----------------------

学习使用 Python 中的函数作为对象

作者图片

我第一次接触 Python 中的 decorators 是在我使用 Flask 部署我的模型的时候。我在浏览 Flask 文档时遇到了一个 decorator 函数,读起来像@app.route("/")。我很感兴趣,开始阅读更多关于它的内容,并意识到装饰者的概念非常有趣和有用。

如果你也遇到了类似于 @some_function 的东西,并且你很想知道它,那么你应该通读这篇文章。装饰者的概念被认为有点难以破解,本文试图简化对装饰者的理解。

让我们快速浏览基础和构建模块以理解概念。

目录:

  1. 函数是 Python 中的第一个类对象
  2. 嵌套函数的一个重要特征
  3. 建造装饰者
  4. 广义装饰者
  5. 结论
  6. 参考

为了掌握装饰者的概念,我们应该首先知道并习惯于将函数作为对象使用。

函数是 Python 中的第一类对象

在 Python 中,一切都是对象,称某个对象为第一类对象只是一个花哨的形容词,用于表示具有以下特权的对象。

  • 函数可以存储在列表、元组和字典等数据结构中。
  • 变量可以被分配给一个函数。
  • 函数可以作为参数传递给其他函数。
  • 函数可以从函数返回。

简而言之,一个第一类对象就像一个足球,可以在程序中的任何地方传递和投掷。让我们把上面提到的第一类对象的所有特征一个一个地看一下。

函数可以存储在列表、元组、字典等数据结构中:

让我们创建几个简单的函数,并将它们作为集合存储在一个列表中。

首先,我们定义了两个函数“加法”和“乘法”。

其次,将这两个函数添加到一个列表中,然后通过列表访问这些函数来调用它们。

因此,由此我们可以很容易地看出,函数可以存储到一个集合类型的数据结构中。

变量可以分配给一个函数:

我们可以将一个变量赋给一个函数,然后使用所赋的变量名调用该函数。下面给出的代码显示了同样的情况。

在代码中,我们将变量“var_add”赋给了函数“add”。最后,分配的变量已被用来成功调用函数。


函数可以作为参数传递给其他函数:

在 Python 中,函数是一个对象,所以它也可以作为参数传递给其他函数。


这里要注意的一件重要事情是,当我们将函数作为对象传递时,我们从不使用带括号的函数。原因很简单,函数和括号是用来进行函数调用的。

下面提到的代码显示了不同之处。我们知道 type()函数返回对象/类的类型,因此我们将 type function 应用于带括号和不带括号的函数名,以了解两者之间的区别。


一个函数可以从一个函数返回:

如上所述,我们知道函数是一个对象,因此函数可以返回一个函数对象。下面的代码显示了同样的情况。


嵌套函数的一个重要特征

为了理解 Decorators,我们需要知道嵌套函数的一个非常重要的特性,我们将在这里简要讨论这个特性。

在下面的代码中,我们定义了一个外部函数,一个内部函数嵌套在外部函数中。这里要注意的有趣的事情是,内部嵌套函数可以访问外部函数的参数/自变量。

注意:参数指的是我们定义函数时的变量,而实参是调用函数时赋给那些参数的值。

嵌套函数可以访问封闭范围的参数/变量。这种功能的嵌套函数叫做 闭包 。这个特性在装饰者中被广泛使用。


建造装饰者

现在,我们知道了函数对象的一些最重要的特性。因此,我们有完美的基础来建立装饰者的概念。

首先让我们看一下装饰函数的定义。

Python 中的 decorator 是一个接受另一个函数作为参数的函数,它通常会修改或增强它接受的函数,并返回修改后的函数。

为了理解 decorator 的定义,让我们一步一步地看下面给出的代码。

首先,我们定义了一个名为“decorator”的装饰函数。此函数接受另一个函数“func”作为参数。

其次,decorator 函数是一个外部函数,它还有一个内部函数,名为“wrapper ”,定义在 decorator 函数内部。这个包装函数调用 func(a,b)函数,返回 func(a,b)函数返回值的平方。

第三,这个装饰函数接受' func '作为参数,并返回包装函数。

第四,我们还单独定义了一个函数 add。定义这个函数的目的是将这个函数传递给装饰函数,并检查它是如何被修改的。


我们可以看到,在对它应用装饰函数之后,“添加”函数的行为被完全修改了。

如果我们更深入地检查底层函数的名称,我们会看到它是包装函数,运行在名称“add”下。因此' add '只是一个赋给包装函数的变量名。

这就是为什么在应用装饰器之后,原始函数“add”不是将数字相加,而是将数字的和平方的原因。

装饰者中@的使用:

为了提高装饰器的可读性,我们使用@和装饰器函数名。

# Without using @
add = decorator(add)

或者

# with @
@decorator
def add(x,y):
     return x+y

两种方式(有或没有' @ ')我们都可以分配一个装饰函数。然而,使用' @ '是一种普遍接受的、干净的方法,可以给 python 函数分配 decorators。

广义装饰者

装饰器通常在它修改的函数之前定义。然而,在上面定义的装饰器中,包装函数使用的参数数量与装饰器所应用的函数中的参数数量相同。这只是一个简单的例子,展示了 decorator 如何工作。

与上面定义的装饰器相比,如果我们想要创建一个可以应用于任何函数的装饰器,那么我们需要在分配参数数量上的灵活性。这种灵活性是通过args 和**kwargs 实现的。args 和**kwargs 允许我们向函数传递多个参数或基于关键字的参数。

从下面的代码中我们可以看到,在调用函数 xyz 时,我们传递了多个参数。

多个参数存储在变量 args 中,而*用于解包这些参数,因此我们能够实现函数中参数数量的灵活性。

我们可以用两个参数调用同一个 xyz 函数,它工作得很好。

类似地,我们可以理解下面代码中提到的kwargs 的功能。这里再次充当解包操作符,而 kwargs 充当键值对的字典。


现在,在知道了*args 和**kwargs 之后,我们可以创建一个与参数数量无关的通用装饰器。

下面提到的代码显示了我们如何根据包装函数的要求使用*args,**kwargs,因为最终包装函数将通过使用原始函数的参数来替换原始函数(add_num(x,y))。

在对原始函数 add_num 应用装饰函数之后,它被修改了,它开始返回参数的平方和,而不是添加参数。

我们可以在带有任意数量参数的函数上应用这个装饰器(参考下面的代码)。所以我们可以一次创建一个装饰器,并在任何需要的地方使用它。

结论

本文的目的是给你足够的信息,让读者更容易理解、工作和构建装饰者的基础。

对于数据爱好者来说,有几个地方你会遇到 Python 中的 decorators:

  1. 同时使用 Flask 或 Django 等框架部署您的模型。
  2. 创建 web 应用程序时。
  3. Python 中有几个内置的 decorators,比如@classmethod 和@staticmethod,它们在定义类时被用来创建可选的构造函数等等。
  4. 关于 decorators 的更多信息,请浏览参考列表中给出的文章和文档。

参考

  1. 文献:https://wiki.python.org/moin/PythonDecoratorLibrary
  2. 盖尔·阿恩 Hjelle 的《Python 装饰者入门》
  3. https://python 101 . python library . org/chapter 25 _ decorators . html
  4. 关闭:https://www.programiz.com/python-programming/closure
  5. Derrick MW iti 关于装饰者的文章

使用 Unity ML-agent 的课程学习

原文:https://towardsdatascience.com/curriculum-learning-with-unity-ml-agents-c8e7a1aa5415?source=collection_archive---------25-----------------------

教一队猎人捕捉猎物。

要查看我为本文编写的代码,请点击这里查看 GitHub repo:https://github.com/adamprice97/UnityPursitEvasionGame

介绍

当一个人面临一个新问题时,他们需要足够的背景知识来解决它。你不能指望有人不先学几何就去学微积分。我们的强化学习代理也是如此!

在本文中,我将展示一个具有挑战性的游戏环境,并向您展示如何使用 Unity ML-Agents 和课程学习来解决这个问题。

追逐-逃避游戏

追逐-逃避游戏是一系列问题,要求一组代理人追踪另一组成员。在我们的实现中,我们将训练一组 3 个猎人来捕捉一个猎物。每一集,猎人们在森林空地的边缘产卵,他们的目标是在猎物逃进树林之前抓住它!

奖励信号

我们可以通过奖励代理在环境中完成任务来影响他们的学习。为了让代理在培训中取得成功,我们需要定义一套奖励,引导他们找到游戏的解决方案。

猎人捕获了猎物。

猎物逃脱了。

  • 捕获猎物(+5)。这三名特工必须都足够靠近猎物才能将其捕获。
  • 猎物逃跑(-3)。如果猎物逃进了树里,猎人将会受到惩罚。
  • 代理离开清算(-1)。这将鼓励代理在训练中远离空地的边缘,但惩罚足够小,不会阻止代理将猎物追逐到边缘。
  • 每个时间步长(-0.001)。这鼓励了代理人迅速捕捉猎物。

观察和行动

为了在环境中导航,代理需要采取行动。这些操作让代理直接与环境交互,并由代理的策略选择。该策略是代理观察的函数,它输出代理要执行的动作。

我们的猎人进行并采取以下观察和行动:

猎人特工的观察和行动向量。

这种环境是完全可以观察到的,因为每个智能体都知道自己、其他智能体和猎物的确切位置。您还会注意到观察向量是堆叠的,前两个观察向量通知当前要采取的行动。这样做可以让代理推断每个实体的速度信息。

我们的代理人的行动让他们在 Z 和 X 平面上前后推动自己,让他们在固定的平面上完全移动。

猎物启发式

最后,环境的最后一个要素是猎物。它是由一个简单的启发式算法控制的,这个算法将直接远离猎人代理的平均位置。启发法很简单,但是代理必须作为一个团队工作,因为需要一个交叉点来捕捉快速的猎物。

培养

代理人需要找到最大化奖励信号的行动。为此,我们使用神经网络作为代理的策略。然后,在训练期间,奖励信号用于更新神经网络和改进代理的策略。

训练配置。

我们需要一种算法来处理这些神经网络的训练。幸运的是,Unity ML-Agents 提供了 Open-AI 的近似策略优化(PPO)算法的实现。

我们为 Unity 提供了一个配置文件来开始训练。有很多变量需要考虑,每一个都会对训练产生巨大的影响。有关所有这些的信息,请查阅 Unity 的文档。

PPO 是一个强大的算法,但是我们的环境太复杂了,一个代理不可能盲入。我们需要为我们的代理创造一个更好的学习环境。

课程学习

复杂的环境可能要求代理在开始利用环境的奖励信号之前掌握多个概念。这些概念可能如此先进,以至于随机探索将无法可靠地强化为获得奖励而采取的行动。我们的追逃游戏就是一个例子。猎物很容易逃脱天真的特工,所以猎人永远不会发现他们捕获它会得到的奖励。

未经训练的特工不太可能随机捕捉猎物。

这就是课程学习的用武之地!

我们没有让代理在困难的环境中放松,而是首先向他们介绍一个更简单的游戏版本。从那里开始,我们可以慢慢增加难度,逐步增加难度。

我们的追逃游戏的难度由两个参数控制:

  • 猎物速度——施加在猎物身上使其移动的标量力。越高,它跑得越快。
  • 捕捉范围— 猎人特工能从猎物处捕捉到的最大距离。

我们的第一课需要非常简单;新特工需要先学会走路,然后才能打猎。我们从一个固定的目标(猎物速度= 0)和一个非常宽的捕捉范围开始。课程结束后,我们会缩小捕捉范围。

猎人与猎物之间的距离在两堂课之间减少。

一旦代理完全掌握了导航到猎物的方法,我们就可以开始让猎物以逐渐增加的速度移动:

有了我们的课程计划,我们只需要定义通过一课的标准。幸运的是,这很容易。当代理在一定数量的剧集中累积的奖励值超过阈值时,我们认为每一课都“通过”。在我们的培训中,当代理在 200 集内每集平均获得超过 4 个奖励时,课程就通过了。在实践中,代理人需要在 9 次中捕获 8 次猎物(超过 200 集)才能通过一堂课。

运行时间

我们在一个加速的 unity 环境中训练代理,以减少实时训练时间。我以 2.5 倍的速度训练了 300 万个时间步。如果您想观看代理培训,您可以观看下面的视频:

Unity ML-Agents 制作了许多 tensorboard 图表来告知我们培训的进展情况,但这两个图表对我们来说是最重要的:

超过 300 万步的奖励累积和课程进度。

你可能已经注意到奖励积累的异常学习曲线。通常情况下,我们希望奖励积累在整个培训过程中不断增加。然而,当使用课程学习时,我们环境的回报变得更难获得,因此获得它变得更困难。我们仍然可以看到每一课的个人学习曲线。第 14 课大约 60 万就是一个很好的例子。

结果

我们可以通过代理通过的课程数量来衡量他们的成功。前 300 万步的训练让他们通过了前 37 课。不幸的是,这意味着代理仍然比猎物快,这在一定程度上降低了团队合作的需要。所以,我又训练了 300 万个时间步。代理人达到第 59 课,猎物比猎人更快,所以团队行为出现了。

600 万集后的表现。

左边的 gif 显示黄色特工移动进行拦截,而另外两个猎人在追击。

你会注意到代理人面对的方向是他们最后用力的方向。黄色特工也有效地学会了突破。如果猎物调整路线,这将是拦截猎物的关键。

我希望我已经阐明了学习课程的力量。即使我们的学习算法在过去几年里有了很大的改进,我们仍然不能指望它们自己解决所有问题。

批量规范化的诅咒

原文:https://towardsdatascience.com/curse-of-batch-normalization-8e6dd20bc304?source=collection_archive---------8-----------------------

使用批处理规范化有哪些缺点?

弗雷迪·科林斯在 Unsplash 上拍摄的照片

批量规范化确实是深度学习领域的重大突破之一,也是过去几年研究人员讨论的热门话题之一。批量标准化是一种广泛采用的技术,能够实现更快和更稳定的训练,并已成为最有影响力的方法之一。然而,尽管它的多功能性,仍然有一些点阻碍了这种方法,正如我们将在本文中讨论的,这表明规范化方法仍然有改进的空间。

我们为什么要使用批处理规范化?

在讨论任何事情之前,首先,我们应该知道什么是批处理规范化,它是如何工作的,并讨论它的用例。

什么是批处理规范化

在训练期间,当我们更新先前的权重时,每个中间激活层的输出分布在每次迭代时移动。这种现象被称为内部协变移位(ICS)。因此,如果我想防止这种情况发生,很自然的事情就是修复所有的发行版。简而言之,如果我有一些问题,我的分布在四处移动,我会夹紧它们,不让它们四处移动,以帮助梯度优化和防止梯度消失,这将有助于我的神经网络训练更快。因此,减少这种内部协变变化是推动批量标准化发展的关键原则。

它是如何工作的

批次归一化通过减去批次的经验平均值除以经验标准差来归一化前一个输出图层的输出。这将有助于数据看起来像 高斯分布

其中 musigma_square 分别为批均值和批方差。

并且,我们根据两个可学习的参数 γβ学习新的均值和协方差。所以简而言之,你可以认为批量标准化是帮助你控制批量分布的一阶和二阶矩的东西。

从 VGG-16 网络的中间卷积层输出的特征分布。1.(之前)没有任何规范化,2。(之后)应用批处理规范化。

利益

我将列举使用批处理规范化的一些好处,但我不会说得太详细,因为已经有成吨的文章在讨论这个问题了。

  • 更快的收敛。
  • 降低初始权重的重要性。
  • 对超参数稳健。
  • 需要较少的数据进行归纳。

1.更快的收敛,2。对超参数稳健

被诅咒的批处理规范化

所以,回到文章的动机,在很多情况下,批处理规范化开始损害性能或者根本不起作用。

使用小批量时不稳定

如上所述,批量标准化层必须计算平均值和方差,以标准化整个批量的先前输出。如果批量相当大,并且随着批量的减小而不断减小,这种统计估计将相当准确。

用 32、16、8、4 和 2 个图像/GPU 训练的 ResNet-50 的批量常模的验证误差

以上是 ResNet-50 的验证误差图。可以推断,如果批次大小保持为 32,其最终验证误差约为 23,并且误差随着批次大小的减小而不断减小(批次大小不能为 1,因为它将是其自身的平均值)。而且损失有很大的差别(10%左右)。

如果小批量是一个问题,为什么我们不用一个更大的批量呢?嗯,我们不能在任何情况下都使用更大的批量。考虑微调,我们不能使用高批量来不伤害我们的高梯度模型。考虑分布式训练,您的大批量最终将作为一组小批量分布在实例中。

导致培训时间增加

作为 NVIDIA 和卡内基梅隆大学进行的实验的结果,他们声称“即使批量规范化不是计算密集型的,收敛所需的总迭代次数也减少了。每次迭代的时间可能会显著增加。,并且它可以随着批量的增加而进一步增加。

使用 Titan X Pascal 在 ImageNet 上的 ResNet-50 训练时间分布

如您所见,批量标准化消耗了总训练时间的 1/4。原因是因为 batch norm 需要通过输入数据进行两次迭代,一次用于计算批处理统计数据,另一次用于归一化输出。

训练和推理的不同结果

例如,考虑现实世界的应用程序“对象检测”。在训练对象检测器时,我们通常使用大批量(YOLOv4 和 Faster-RCNN 都是在批量默认为 64 的情况下训练的)。但是这些车型投入生产后,这些车型工作 不如训练时的 好。这是因为它们是用大批量训练的,而在实时中,它们得到的批量等于 1,因为它必须随后处理每一帧。考虑到这种限制,一些实现倾向于使用基于训练集激活的预先计算的均值和方差。另一种可能性是基于您的测试集激活分布来计算平均值和变化值,但仍然不是分批的。

不利于在线学习

与批量学习相反,在线学习是一种学习技术,其中系统通过顺序输入数据实例进行增量训练,这些数据实例可以单独输入,也可以通过称为小批量的小组输入。每一步学习都是快速而廉价的,因此系统可以在新数据到达时即时学习。

典型的在线学习渠道

由于它依赖于外部数据源,数据可能单独或成批到达。由于每次迭代中批量大小的变化,它不能很好地概括输入数据的规模和变化,这最终会影响性能。

对递归神经网络不好

尽管批量归一化显著地加快了卷积神经网络的训练和泛化速度,但它们被证明难以应用于递归结构。可以在 RNN 的堆栈之间应用批量归一化,其中归一化是“垂直”应用的,即每个 RNN 的输出。但是它不能“水平地”应用,即在时间步长之间应用,因为它会由于重复重新缩放导致的爆炸梯度而损害训练。

【注意】:一些研究实验声称批处理规范化使神经网络容易出现对抗性漏洞。但由于缺乏研究和证明,我们没有包括这一点。

可供选择的事物

所以这是使用批处理规范化的一些缺点。在批处理规范化不能保持的情况下,有几种替代方法。

  • 图层规范化。
  • 实例规范化。
  • 分组标准化(+权重标准化)。
  • 同步批量标准化。

结论

所以训练深度神经网络很简单,但我认为还不太容易。从这个意义上说,我可以选择的架构很少,每个人都使用固定的学习速度,固定的优化器和固定的技巧。这些技巧是通过自然选择选择出来的,几乎就像有人想出了一些技巧,如果它有效,他们就引入它,如果它无效,人们最终会忘记它,没有人会再使用它。除此之外,批处理规范化是深度学习发展中的一项里程碑技术。然而,正如所讨论的,沿着批处理维度进行规范化会引入一些问题,这表明规范化技术仍有改进的空间。

用 Python 实现股票数据内插的凹函数

原文:https://towardsdatascience.com/curve-function-to-interpolate-stocks-data-cd01523ed0a0?source=collection_archive---------38-----------------------

照片由威廉·艾文Unsplash 上拍摄

动手教程

雅加达综合指数的案例研究(JCI)

目录(仅适用于 web)

1 [Overview](#5838)
2 [Let’s Practice with Python](#587f)
3 [Conclusion](#5ffa)
4 [References](#f360)

概观

股票投资者必须考虑的一个特征是不稳定性。因此,投资者必须制定一个聪明的策略来获得投资的资本收益,例如,财务预测。分析师必须从财务数据中找出模式和见解。例如,我们需要创建雅加达综合指数(JCI)的数据分析。这些数据很容易在雅虎上下载。金融。但是,我们分析的一个考虑因素是数据的缺失值。

一般证券交易所周一到周五上班,除非是节假日。为了进行插值,Mittal 和 Goel (2012)提出了凹函数。如果给定日期的 JCI 值为 X ,下一个可用值为 Y ,中间缺少 n 天,则 X1 的第一个缺失值可以使用**(*X+Y*)/2**来近似,并对其他缺失值重复。

让我们用 Python 来练习一下

在我们开始曲线功能之前,首先我们必须从 Yahoo!金融。你可以很容易地选择任何股票,但对于本教程,我将使用 2019 年的 JCI 数据。负责人向我的 GitHub 的 回购了数据。

# Import libraries
import pandas as pd   # Dataframe manipulation
import numpy as np    # Mathematics operation
import datetime       # Date and time
# Load the data
ihsg_data = pd.read_csv('Datasets/^JKSE.csv')
print('Dimension of JCI data:\n{}'.format(ihsg_data.shape[0]),
      'rows and {}'.format(ihsg_data.shape[1]),'columns')
ihsg_data.head()

JCI 的原始资料(图片由作者提供)

# Get the metadata of columns
ihsg_data.info()
# Check missing value
ihsg_data.isna().sum()

JCI 数据中的元数据和缺失值信息(图片由作者提供)

导入数据后,我们创建将应用于数据的函数。这些功能如下:

  • **imput_date**:输入我们数据中未列出的日期
  • **return_stocks**:计算股票回报率
  • **curve_function**:使用曲线功能对缺失值进行插值

插值股票数据的凹函数

让我们运行**return_stocks**的第一个函数。输出是带有新的 return 列的数据集。我们对熊猫使用的**pipe**方法如下:

# Calculate the return of stocks
ihsg_data_clean = ihsg_data.pipe(return_stocks,col='Adj Close', date='Date')
print('Dimension of financial news:\n{}'.format(ihsg_data_clean.shape[0]),
      'rows and {}'.format(ihsg_data_clean.shape[1]),'columns')
ihsg_data_clean.head()

应用**return_stocks**功能后的 JCI 数据(图片由作者提供)

在运行了**return_stocks**函数之后,我们得到了数据中列出的所有日期的返回结果,但是问题是如果我们的日期为空,我们如何在返回结果中插入缺失值。所以,在实现**curve_function**之前,我们需要以区间形式提供日期。很简单,运行**imput_date**的功能即可。代码和结果如下。

# Input the missing data on date column
ihsg_data_clean = ihsg_data_clean.pipe(imput_date,col='Date')
print('Dimension of financial news:\n{}'.format(ihsg_data_clean.shape[0]),
      'rows and {}'.format(ihsg_data_clean.shape[1]),'columns')
ihsg_data_clean.head()

应用**imput_date**功能后的 JCI 数据(图片由作者提供)

那好吧。**Date**列上缺失的数据已经由**imput_date**函数填充。结果很棒。现在,我们必须确定这些日期是否是自由日。理论上,交易活动是从周一到周五,这是我们的原始数据,只提供交易日的信息。**curve_function**使用来自这里的信息,所以我们必须提供它。

# Create dummy variable for deterimining free day or not
free = []
for i in range(ihsg_data_clean.shape[0]):
    if pd.isna(ihsg_data_clean.iloc[i]['Volume']):
        free.append(0)
    else:
        free.append(1)

在确定了某个具体日期是否是自由日之后,我们只需轻松运行**curve_function**的主函数即可。

# Interpolate the return by curve function
ihsg_data_curve = ihsg_data_clean.pipe(curve_function)
print('Dimension of financial news:\n{}'.format(ihsg_data_curve.shape[0]),
      'rows and {}'.format(ihsg_data_curve.shape[1]),'columns')
ihsg_data_curve.head()

应用**curve_function**功能后的 JCI 数据(图片由作者提供)

最后一步是将自由日的列与上表合并。当我们用这些数据进行分析时,它是有用的。关于原始数据的信息仍然存在,我们可以使用**Free**列对其进行过滤。

# Concatenate previous-interpolated data with dummy
ihsg_data = pd.concat([ihsg_data_curve,pd.Series(free,name='Free')],axis=1)
ihsg_data.head()

最终数据还是 JCI(图片由作者提供)

用于实现凹面功能的笔记本

结论

凹函数是在股票——金融数据中进行数据分析或机器学习之前,第一个也是至关重要的数据预处理。每日股票数据的模式被假定为平稳线性。使用凹函数,分析师可以捕获一年中 365 天的股票数据可用性,但可以根据需要进行定制。

请前往我的 GitHub repo 查看完成的代码。

参考

[1] A .米塔尔,a .戈埃尔。 利用 Twitter 情绪分析进行股票预测 (2012 年)http://cs 229 . Stanford . edu/proj 2011/goelmittalstockkmarkedpredictionusingtwittersentimentanalysis . pdf

拘留死亡:分析数据揭露警察暴行

原文:https://towardsdatascience.com/custodial-deaths-analyzing-data-to-uncover-police-brutality-ae19fa539312?source=collection_archive---------39-----------------------

大量警察在羁押期间死亡却逍遥法外,而且这一趋势还在上升。

叶韩晶上拍照

今年 6 月,印度惊觉一对父子死于警方的监禁酷刑。他们如何受到性侵犯和极其残忍的虐待的悲惨故事提醒人们,监禁中的酷刑和随后的死亡在印度已经成为一种常态。

警察一再利用大量人口不知道宪法赋予他们的权利这一事实。

在这篇文章中,我从开放政府数据(OGD)平台印度获取了数据,以了解印度羁押期间死亡有多普遍,以及罪犯是否受到惩罚。

OGD 印度是一个支持印度政府开放数据倡议的平台。

该门户是对印度政府各部委、部门和组织发布的数据集、文档、服务、工具和应用程序的单点访问。

数据在网站上完全免费提供,任何人都可以访问。

在这篇文章中,我使用了一个数据集,其中包含了 2001 年至 2012 年印度在押人员死亡的所有数据。

注意:包含所有代码和可视化的 Jupyter 笔记本在我的 Github 资源库中,其链接在本文末尾提到。

数据分析

第一步是导入所有必需的库。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

然后,我查看数据集,了解数据是如何存储的。

df = pd.read_csv("CD.csv")
df

行包含州,列包含数据,每 4 列包含每年的数据。

但是向下滚动时,我注意到有 3 行(索引 28、36、37)没有表示与州有关的数据。

当我稍后执行数据可视化时,我会记住这一点。

目前,该数据集包含每年的数据,但没有汇总数据。为了执行数据分析,我将向这个数据集中再添加 4 列。

第一栏将显示 2001 年至 2012 年间羁押中死亡的总人数。

#Total custodial deaths per statetotal_deaths_per_state = []
per_state = 0

for row in range(0, 38):
    per_state = 0
    for col in range(1, len(df.columns), 4):
        #print(df.iloc[row, col])
        per_state += df.iloc[row, col]
    total_deaths_per_state.append(per_state)

print(total_deaths_per_state)

我从“2001 年羁押中死亡数”栏下的“羁押中死亡数”开始,进行第 4 步,得出下一年的数据,以此类推,直到 2012 年,同时将每年的数据附加到一个列表中。

我将列表转换成 panda 系列,并将其作为新列添加到数据集。

x = pd.Series(total_deaths_per_state)
df['TOTAL CUSTODIAL DEATHS'] = x.values
df.head()

同样,我添加了其余 3 列——登记的案件总数、被指控的警察总数和被定罪的警察总数。

完成后,我将其保存为一个新的数据集。

df.to_csv("CD_Updated.csv", index = False)

可视化将在我之前创建的新数据集“CD_Updated.csv”上执行。

final_df = pd.read_csv("CD_Updated.csv")
final_df.tail(10)

数据结果

1.拘留期间死亡、登记的案件、被指控的警察、被定罪的警察

我通过选择最后 4 列和最底部的一行(包含整个国家的数据)来获取必要的单元格,并使用 Matplotlib 绘制条形图。

x1_values = list(["CUSTODIAL DEATHS", "CASES REGISTERED", "COPS CHARGESHEETED", "COPS CONVICTED"])
y1_values = list(df.iloc[37, -4:]) #last row and last 4 columns# Figure Size 
fig, ax = plt.subplots(figsize =(16, 9)) 

# Horizontal Bar Plot 
ax.barh(x1_values, y1_values, color = ["#cccc00", "#6666ff", "#ff9933", "#ff6699"]) 

# Remove axes splines 
for s in ['top', 'bottom', 'left', 'right']: 
    ax.spines[s].set_visible(False) 

# Remove x, y Ticks 
ax.xaxis.set_ticks_position('none') 
ax.yaxis.set_ticks_position('none') 

# Add padding between axes and labels 
ax.xaxis.set_tick_params(pad = 5) 
ax.yaxis.set_tick_params(pad = 10) 

# Add x, y gridlines 
ax.grid(b = True, color ='grey', 
        linestyle ='-.', linewidth = 0.5, 
        alpha = 0.2) 

# Show top values  
ax.invert_yaxis() 

# Add annotation to bars 
for i in ax.patches: 
    plt.text(i.get_width()+0.2, i.get_y()+0.5,  
             str(round((i.get_width()), 2)), 
             fontsize = 10, fontweight ='bold', 
             color ='grey')# Add title 
ax.set_title('Statistics Regarding Custodial Deaths in India 2001-12', 
             loc ='left', ) 

# Add Text watermark 
fig.text(0.9, 0.15, 'By Sthitaprajna Mishra', fontsize = 12, 
         color ='grey', ha ='right', va ='bottom', 
         alpha = 0.7) 

# Show Plot 
plt.show()

这里的数字差异非常令人震惊。

在 12 年中,有 1157 人在被警方拘留期间死亡,而只有 26 名警察被判有罪。

2.跨州羁押死亡

我得到了这个图的 y 值和 x 值。

x2_values = list(final_df['STATE/UT'].values)
y2_values = list(final_df['TOTAL CUSTODIAL DEATHS'].values)

但是,包含 x 值的列表还包含 3 行,它们是州、联邦直辖区(UTs)和整个国家的总计。我在一开始看数据时就指出了这一点,记得吗?

现在,我将这 3 行从 x 值中移除。

x2_values.remove('TOTAL (ALL-INDIA)')
x2_values.remove('TOTAL (UTs)')
x2_values.remove('TOTAL (STATES)')

我还必须删除所有这些行的相应 y 值。我回到我的数据集,记下这些行的索引,并从我的 y 值中删除它们。

y2_values.remove(y2_values[37])
y2_values.remove(y2_values[36])
y2_values.remove(y2_values[28])

在获得坐标轴的正确值后,我绘制了图表。

# Figure Size 
fig, ax = plt.subplots(figsize =(16, 9)) 

# Horizontal Bar Plot 
ax.barh(x2_values, y2_values, color = ["#cccc00", "#6666ff", "#ff9933", "#ff6699"]) 

# Remove axes splines 
for s in ['top', 'bottom', 'left', 'right']: 
    ax.spines[s].set_visible(False) 

# Remove x, y Ticks 
ax.xaxis.set_ticks_position('none') 
ax.yaxis.set_ticks_position('none') 

# Add padding between axes and labels 
ax.xaxis.set_tick_params(pad = 5) 
ax.yaxis.set_tick_params(pad = 10) 

# Add x, y gridlines 
ax.grid(b = True, color ='grey', 
        linestyle ='-.', linewidth = 0.5, 
        alpha = 0.2) 

# Show top values  
ax.invert_yaxis() 

# Add annotation to bars 
for i in ax.patches: 
    plt.text(i.get_width()+0.2, i.get_y()+0.5,  
             str(round((i.get_width()), 2)), 
             fontsize = 10, fontweight ='bold', 
             color ='grey')# Add title 
ax.set_title('Custodial Deaths across States in India 2001-12', 
             loc ='left', ) 

# Add Text watermark 
fig.text(0.9, 0.15, 'By Sthitaprajna Mishra', fontsize = 12, 
         color ='grey', ha ='right', va ='bottom', 
         alpha = 0.7) 

# Show Plot 
plt.show()

当我们看一下全国拘留期间的死亡人数时,几乎所有的州都是两位数。

印度拘留死亡人数最多的 3 个邦是马哈拉施特拉邦、安得拉邦和古吉拉特邦,其中马哈拉施特拉邦有 271 人死亡。

3.跨州定罪的警察

我获取这个图形的 y 值和 x 值。

y3_values = list(final_df['TOTAL POLICEMEN CONVICTED'].values)
x3_values = list(final_df['STATE/UT'].values)

因为我想绘制一个跨州的图表,并且不希望显示我的国家数据,所以我去掉了那些行,就像我在前面的可视化中所做的那样,然后绘制数据。

x3_values.remove('TOTAL (ALL-INDIA)')
x3_values.remove('TOTAL (UTs)')
x3_values.remove('TOTAL (STATES)')#duplicate values present, hence use del instead of remove
del y3_values[37]
del y3_values[36]
del y3_values[28]# Figure Size 
fig, ax = plt.subplots(figsize =(16, 9)) 

# Horizontal Bar Plot 
ax.barh(x3_values, y3_values, color = ["#cccc00", "#6666ff", "#ff9933", "#ff6699"]) 

# Remove axes splines 
for s in ['top', 'bottom', 'left', 'right']: 
    ax.spines[s].set_visible(False) 

# Remove x, y Ticks 
ax.xaxis.set_ticks_position('none') 
ax.yaxis.set_ticks_position('none') 

# Add padding between axes and labels 
ax.xaxis.set_tick_params(pad = 5) 
ax.yaxis.set_tick_params(pad = 10) 

# Add x, y gridlines 
ax.grid(b = True, color ='grey', 
        linestyle ='-.', linewidth = 0.5, 
        alpha = 0.2) 

# Show top values  
ax.invert_yaxis() 

# Add annotation to bars 
for i in ax.patches: 
    plt.text(i.get_width()+0.2, i.get_y()+0.5,  
             str(round((i.get_width()), 2)), 
             fontsize = 10, fontweight ='bold', 
             color ='grey')# Add title 
ax.set_title('Cops Convicted across States in India 2001-12', 
             loc ='left', ) 

# Add Text watermark 
fig.text(0.9, 0.15, 'By Sthitaprajna Mishra', fontsize = 12, 
         color ='grey', ha ='right', va ='bottom', 
         alpha = 0.7) 

# Show Plot 
plt.show()

与上图形成鲜明对比的是,这张图显示了在大多数州,没有一个警察被定罪。

另一个严峻的事实是,关押期间死亡人数最多的前三个州在 12 年里也没有定罪。

4.多年来采取的行动

现在,我想绘制一个多线图表,显示多年来羁押死亡分布与被定罪的警察,以判断每年对与羁押死亡有关的警察采取了多少行动。

我的 x 值将是 2001-12 年。

x4_values = [i for i in range(2001, 2013)]

由于这是一个多线图,我将有 2 个不同的 y 值。第一个 y 值将是监管死亡的分布。

y4_1_values = []for i in range(1, 48, 4):
    y4_1_values.append(int(final_df.iloc[37, i]))

第二个 y 值是被定罪警察的分布。

y4_2_values = []for i in range(4, 52, 4):
    y4_2_values.append(int(final_df.iloc[37, i]))

print(y4_2_values)

现在,我绘制图表。

# plotting the line 1 points 
plt.plot(x4_values, y4_1_values, label = "Deaths", color="#ff9900", linestyle='dashed', linewidth = 2, 
         marker='o', markerfacecolor='#ff3300', markersize=8)# plotting the line 2 points 
plt.plot(x4_values, y4_2_values, label = "Convicted", color= "#6666ff", linestyle='dashed', linewidth = 2, 
         marker='o', markerfacecolor='blue', markersize=8)# Add x, y gridlines 
plt.grid(b = True, color ='grey', 
        linestyle ='-.', linewidth = 0.5, 
        alpha = 0.2)plt.title('Custodial Deaths vs Cops Convicted 2001-12')
plt.legend()

从这个数字中可以看出死亡人数和被定罪的警察人数之间的差异。虽然从 2007 年至 2010 年,羁押期间的死亡人数似乎有所下降,但自那以后,死亡人数一直在增加,而且似乎只是在上升。

另一方面,警察被定罪的情节似乎是一条直线。

5.跟踪司法程序

在看到如此强烈对比的数字后,我想找出司法系统在哪里动摇了。

针对警察的案件数量减少了吗?还是法院不会公布对警察的指控?还是司法当局没有给足够多的警察定罪的错?

为了获得整个数据集的整体视图,我绘制了一个更详细的多线图。

我得到了所有登记案件和所有警察的 y 值,并将它们一起绘制出来。

y5_1_values = [] #cases registeredfor i in range(2, 48, 4):
    y5_1_values.append(int(final_df.iloc[37, i]))y5_2_values = [] #cops chargesheetedfor i in range(3, 48, 4):
    y5_2_values.append(int(final_df.iloc[37, i]))# plotting the line 'death' points 
plt.plot(x4_values, y4_1_values, label = "Deaths", color= "#cc3300", linestyle='dashed', linewidth = 2, 
         marker='o', markerfacecolor='#802000', markersize=8)# plotting the line 1 points 
plt.plot(x4_values, y5_1_values, label = "Cases Registered", color="#ff9900", linestyle='dashed', linewidth = 2, 
         marker='o', markerfacecolor='#ff3300', markersize=8)# plotting the line 2 points 
plt.plot(x4_values, y5_2_values, label = "Chargesheeted", color= "#cccc00", linestyle='dashed', linewidth = 2, 
         marker='o', markerfacecolor='#808000', markersize=8)# plotting the line 3 points 
plt.plot(x4_values, y4_2_values, label = "Convicted", color= "#6666ff", linestyle='dashed', linewidth = 2, 
         marker='o', markerfacecolor='blue', markersize=8)# Add x, y gridlines 
plt.grid(b = True, color ='grey', 
        linestyle ='-.', linewidth = 0.5, 
        alpha = 0.2)plt.title('Tracking Custodial Death Proceedings 2001-12')
plt.legend()

这个数字让我们更详细地发现了缺乏行动的地方。

虽然在所有拘留期间死亡的案件中,只有不到 50%的案件是针对警察的,但受到指控的警察人数非常少。其中,被定罪的警察人数更少。

这一分析的结果表明,在对警察采取行动时,司法系统是多么的脆弱。

这背后的一个主要原因是,由于害怕成为警察的目标,受害者提起的案件数量很少,这是可以理解的,因为尽管有这么多针对警察的案件登记,但几乎没有几份起诉书被公布。

除非越来越多的人站出来,司法部门采取合理的行动,否则警察将继续逍遥法外。

尽管这一数据相对较旧,但它仍然有效,或者更糟,差距甚至更大,因为这种情况近年来才有所增加。

如果你想看看更多的数据,并在自己挖掘的同时进行研究,我建议你访问开放政府数据(OGD)平台印度

Github 库:

https://github.com/sthitaprajna-mishra/custodial_deaths

创建虚拟背景应用程序

原文:https://towardsdatascience.com/custom-calculators-in-mediapipe-5a245901d595?source=collection_archive---------12-----------------------

如何创建一个具有人像分割和媒体管道的缩放式虚拟背景应用程序

这是我正在撰写的 MediaPipe 系列的第 2 部分。

之前,我们看到了如何开始使用 MediaPipe 并将其用于您自己的 tflite 模型。如果你还没看过,在这里查看一下

我们尝试在现有的细分渠道中使用纵向细分 tflite 模型,并在 MediaPipe 中使用计算器

纵向分段媒体管道—第 1 部分

厌倦了蓝色的背景后,我决定用一些虚拟的缩放背景,比如美丽的星星或者疯狂的云来玩玩:)

虚拟云背景—第 2 部分

为此,我编写了一个自定义计算器,并将其用于现有的管道。

所以今天我将展示我是如何制作这个应用程序的

在我们开始之前,我建议你浏览一下解释基本计算器流程的这部分文档。

https://Google . github . io/media pipe/framework _ concepts/calculators . html

现在,让我们从代码开始

1.从第 1 部分克隆肖像分割库

$ git clone [https://github.com/SwatiModi/portrait-segmentation-mediapipe.git](https://github.com/SwatiModi/portrait-segmentation-mediapipe.git)

2.管道的新流程(在图表中进行更改。pbtxt 文件)

之前,渲染/着色是由重新着色计算器完成的,它使用图像和遮罩 gpu 缓冲区作为输入,并返回 gpu 缓冲区渲染输出(使用 opengl 渲染)

这里,为了用图像(jpg/png)替换背景,我使用了 OpenCV 操作。

注意 : OpenCV 操作在 CPU-Image frame 数据类型上执行,而 opengl 操作在 GPU-Image-buffer 数据类型上执行

portrait _ segmentation . Pb txt

我们将背景屏蔽计算器替换重新计算器

*node {
  calculator: "BackgroundMaskingCalculator"
  input_stream: "IMAGE_CPU:mask_embedded_input_video_cpu"
  input_stream: "MASK_CPU:portrait_mask_cpu"
  output_stream: "OUTPUT_VIDEO:output_video_cpu"
  }*

这个计算器将转换后的图像和蒙版(都是 ImageFrame 数据类型)作为输入,并用给定的图像改变背景。

为了将图像和遮罩 GpuBuffer 转换成 ImageFrame,我使用了GpuBufferToImageFrameCalculator。**

3.编写计算器文件(background _ masking _ Calculator . cc 文件)

在这里,我们将编写处理和创建背景遮罩效果的逻辑

background _ masking _ calculator . cc

将此background _ masking _ calculator . cc放入**media pipe/calculators/image/**

a.扩展基本计算器

b.GetContract()

这里我们只是验证我们的输入和它们的数据类型

c.打开()

准备计算器的每图运行状态。

d.流程()

background_masking_calculator 中 Process()方法的小概述

获取输入,转换为 OpenCV Mat 并进一步处理以获得所需的输出

4.将background _ masking _ calculator . cc 添加到包含依赖关系** 的图像文件夹的构建文件中**

media pipe/calculators/image中构建文件

我们需要这样做,以便在编译和执行时计算器是可用的和可访问的

您在这里看到的 dep(依赖项)是您在计算器中使用的导入

此处使用的名称也在图形构建文件中引用

5.将 background _ masking _ calculator . cc 添加到图形构建文件中

在图形/纵向 _ 分段中建立文件

添加背景 _ 蒙版 _ 计算器到 deps 并删除重新着色 _ 计算器,我们现在不使用

现在我们已经准备好构建了,我们只需要添加资产(要在背景上隐藏的图像)

****注意:这种资产读取方法在桌面上尝试时非常简单,但在 Android 版本上则完全不同。

因此,我们将逐一查看桌面和 Android 版本

桌面版本:

在 background _ masking _ calculator . cc 中,将资产文件读取为

现在,我们准备建造

**bazel build -c opt --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11  mediapipe/examples/desktop/portrait_segmentation:portrait_segmentation_gpu**

构建将在大约 10–15 分钟内成功完成

**INFO: Build completed successfully, 635 total actions**

现在,您可以使用以下代码运行管道

**GLOG_logtostderr=1 bazel-bin/mediapipe/examples/desktop/portrait_segmentation/portrait_segmentation_gpu   --calculator_graph_config_file=mediapipe/graphs/portrait_segmentation/portrait_segmentation.pbtxt**

网络摄像头启动,您将能够看到输出窗口

虚拟背景应用程序—桌面构建

Android 版本:

1.导出背景遮罩图像

将以下代码添加到 testdata 文件夹(包含背景资产图像的文件夹)中的构建文件中

**exports_files(
    srcs = glob(["**"]),
)**

2.将资源添加到 android 应用程序使用的 android_library

将文件和 tflite 模型一起添加到 android_library

在 android 项目中修改examples/android/…中构建文件。/portraitsegmentationgpu/

3.在 background_masking_calculator 中读取此图像文件

这里,首先使用 MediaPipe 的 PathToResourceAsFile 方法,我们尝试查看资产是否可用,如果可用,我们使用它的值作为文件的路径来读取它

另外,这个方法是 mediapipe/util/ folder 中 resource_util.h 的一部分。所以无论何时你导入一个新文件到你的计算器中,确保将它添加到 pt 中提到的构建文件中。4

现在我们准备建造 APK

**# BUILD 
bazel build -c opt --config=android_arm64 mediapipe/examples/android/src/java/com/google/mediapipe/apps/portraitsegmentationgpu# On successfully building the APK, it printsINFO: Elapsed time: 1499.898s, Critical Path: 753.09s
INFO: 2002 processes: 1849 linux-sandbox, 1 local, 152 worker.
INFO: Build completed successfully, 2140 total actions**

首次构建时,这大约需要 20-25 分钟,因为它会下载构建的所有外部依赖项。下次它将使用缓存的依赖项,因此构建速度会更快。

**# INSTALL
adb install bazel-bin/mediapipe/examples/android/src/java/com/google/mediapipe/apps/portraitsegmentationgpu/portraitsegmentationgpu.apk**

现在,您已经准备好运行 APK 并测试它了。

虚拟背景应用程序— Android Build

在这里,我们成功地添加了我们自己的计算器,并修改了管道和图表,首先在桌面上测试,然后最终在 Android 上进行最小的更改。

欢迎在评论中提问,或者你可以亲自联系我。

你可以在swatimodi.com找到更多关于我的信息

参考

  1. https://blog . gofynd . com/media pipe-with-custom-TF lite-model-d3ea 0427 B3 C1
  2. https://media pipe . readthedocs . io/en/latest/framework _ concepts . html
  3. https://mediapipe.readthedocs.io/en/latest/calculator.html
  4. https://github.com/google/mediapipe/issues
  5. 从这里获取代码—https://github.com/SwatiModi/virtual-background-app

自定义着色树状图以 R 结尾

原文:https://towardsdatascience.com/custom-coloring-dendrogram-ends-in-r-f1fa45e5077a?source=collection_archive---------45-----------------------

作者图片

作为一名研究微生物群落数据的研究生,我从事的大多数项目都涉及某种聚类分析。对于其中的一个,我想用元数据中的一个变量来给一个树状图的两端着色,以可视化该变量是否作为另一个图形的一部分跟随聚类。R 中有一些优秀的包,比如 ggdendro ,它允许您在树状图下绘制彩色条来表示组是如何聚类的,或者通过聚类本身来给终端段着色。

也就是说,我仍然没有找到一种简单的方法来基于用户定义的元数据改变树状图本身的终端颜色,我个人认为在某些情况下这可能更美观。本教程描述了我是如何做到的,并提供了可复制的代码,如果你希望做同样的事情!

树状图基础

在我开始之前,树状图到底是什么?

树状图是层次聚类的图形表示。聚类可以以不同的方式构建(即自顶向下或自底向上),最常见的是在 R 中通过在距离矩阵上应用hclust()。树状图是通过将节点连接到分支或其他节点来构建的,从而产生一个树状图形,该图形基于多个变量来显示各个事物如何相互关联。

假设我们想要从众所周知的 R-core 数据集中比较单个虹膜如何聚类。该数据帧包含四个数字向量(Sepal.LengthSepal.WidthPetal.LengthPetal.Width)以及一个字符向量(Species)。我们可以很容易地构建并绘制一个包含所有这些以 R 为基数的数字数据的树状图,但是如果我们想根据鸢尾的种类对末端片段进行着色,以可视化物种是否遵循由hclust()确定的聚类呢?

步骤 1:安装软件包

对于本教程,您需要加载三个 R 包:tidyverse用于数据操作和可视化,ggdendro用于将树状图分段数据提取到数据帧中,RColorBrewer用于为树状图末端制作自动定制调色板。如果你想让你的树状图具有交互性,一定要加载plotly

pacman::p_load(tidyverse, ggdendro, RColorBrewer, plotly)

步骤 2:加载数据

现在我们要将iris数据帧加载到我们的环境中。作为生物信息学家,我们通常有映射到每个观察结果的样本名称,所以我们希望从一开始就创建自己的名称(sample_name)。

有了微生物群落数据,我的工作流程本质上涉及两个对象:一个巨大的 ASV 矩阵(扩增子序列变体;该术语用于描述基于sample_name的 DNA 序列相似性)丰度的分类,以及与每个样本相关的元数据。为了模拟这一点,我们将把iris分成numeric_datametadata,根据 T8,我们将计算距离并构建一个树状图,为了我们的目的,T9 将简单地包含每个sample_name的鸢尾种类。对于这个工作流,每个观察都有一个sample_name标识符是很重要的;它将是最后融合一切的基础。

# label rows with unique sample_name
dat <- iris %>%
 mutate(sample_name = paste(“iris”, seq(1:nrow(iris)), sep = “_”)) # create unique sample ID# save non-numeric metadata in separate dataframe
metadata <- dat %>%
 select(sample_name, Species)# extract numeric vectors for distance matrix
numeric_data <- dat %>%
 select(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width, sample_name)# check data 
head(numeric_data)

作者图片

步骤 3:标准化数据并创建树状图

在我们制作树状图之前,我们将使用dist()基于numeric_data计算一个距离矩阵。在进行此计算之前,最好对数据进行标准化处理;因此,我将在 0 到 1 的范围内对向量中的所有值进行归一化。

这样做之后,我们可以创建一个距离矩阵(dist_matrix)并从我们的标准化数据中生成一个dendrogram

# normalize data to values from 0 to 1 
numeric_data_norm <- numeric_data %>%
 select(sample_name, everything()) %>%
 pivot_longer(cols = 2:ncol(.), values_to = “value”, names_to = “type”) %>%
 group_by(type) %>%
 mutate(value_norm = (value-min(value))/(max(value)-min(value))) %>% # normalize data to values 0–1
 select(sample_name, value_norm) %>%
 pivot_wider(names_from = “type”, values_from = “value_norm”) %>%
 column_to_rownames(“sample_name”)# create dendrogram from distance matrix of normalized data
dist_matrix <- dist(numeric_data_norm, method = “euclidean”)
dendrogram <- as.dendrogram(hclust(dist_matrix, method = “complete”))

步骤 4:使用 ggdendro 提取树状图片段数据

现在让我们快速地看一下使用基数 R 时我们的树状图是什么样子的:

plot(dendrogram)

作者图片

好吧,它不是很漂亮,但是请原谅我。这是一个有用的视图,展示了我们将如何使用ggdendro::dendro_data()从树状图对象中提取坐标数据,以生成一个更好的图形。每个树状图都是通过在 x 和 y 网格上的点之间添加单独的线段来绘制的。

当我们应用dendro_data()并查看提取的分段数据时,我们看到每个树状图有四个向量:xyxendyend。您在基数 R 图中看到的每条水平线或垂直线最终都是由以下数据帧中的一行构成的:

# extract dendrogram segment data
dendrogram_data <- dendro_data(dendrogram)
dendrogram_segments <- dendrogram_data$segments # contains all dendrogram segment datahead(dendrogram_segments)

作者图片

我们将把这些坐标数据分成两个数据帧:dendrogram_segments,包含所有线段,和dendrogram_ends,仅包含图形的终端分支。如上图所示,当 y 方向的值为 0(即yend == 0)时,仅包括图底部的单个线段:

# get terminal dendrogram segments
dendrogram_ends <- dendrogram_segments %>%
 filter(yend == 0) %>% # filter for terminal dendrogram ends
 left_join(dendrogram_data$labels, by = “x”) %>% # .$labels contains the row names from dist_matrix (i.e., sample_name)
 rename(sample_name = label) %>%
 left_join(metadata, by = “sample_name”) # dataframe now contains only terminal dendrogram segments and merged metadata associated with each iris

查看dendrogram_ends,我们现在有一个数据帧,其中包含与sample_nameSpecies向量匹配的树状图坐标数据。我们现在准备在ggplot2开始绘图!

head(dendrogram_ends)

作者图片

步骤 5:使用 RColorBrewer(可选)基于元数据变量为树状图末端生成自定义调色板

如果您想要基于感兴趣的元数据向量包含多少唯一变量来动态创建颜色列表,您可以运行以下代码。在这个例子中,我们的metadata只包含三种鸢尾,所以这可以相当快地手动完成。但是,如果数据集中的唯一元数据变量的数量超过这个数目,就像微生物群落数据中常见的那样,那么您可能希望自动执行这个过程。

# Generate custom color palette for dendrogram ends based on metadata variableunique_vars <- levels(factor(dendrogram_ends$Species)) %>% 
 as.data.frame() %>% rownames_to_column(“row_id”) # count number of unique variables
color_count <- length(unique(unique_vars$.))# get RColorBrewer palette
get_palette <- colorRampPalette(brewer.pal(n = 8, name = “Set1”))# produce RColorBrewer palette based on number of unique variables in metadata:
palette <- get_palette(color_count) %>% 
 as.data.frame() %>%
 rename(“color” = “.”) %>%
 rownames_to_column(var = “row_id”)
color_list <- left_join(unique_vars, palette, by = “row_id”) %>%
 select(-row_id)
species_color <- as.character(color_list$color)
names(species_color) <- color_list$.

如果您不想在本教程中使用上述代码,您可以手动创建一个命名的字符向量作为替代:

# Alternatively, create a custom named vector for iris species color:species_color <- c(“setosa” = “#E41A1C”, “versicolor” = “#CB6651”, “virginica” = “#F781BF”)

第 6 步:绘制自定义颜色的树状图!

现在是时候绘制我们的树状图了!您将需要为geom_segment定义两个几何图形:一个绘制从步骤 4 中提取的所有未着色的分段数据,另一个仅绘制树状图的末端分支,这是我们将在上一步骤中用species_color着色的部分。如果你用plotly(见下文)包装这个图,我建议增加一个额外的text美学来控制哪些信息将显示在你的输出上。

p <- ggplot() +
 geom_segment(data = dendrogram_segments, 
 aes(x=x, y=y, xend=xend, yend=yend)) +
 geom_segment(data = dendrogram_ends,
 aes(x=x, y=y.x, xend=xend, yend=yend, color = Species, text = paste(‘sample name: ‘, sample_name,
 ‘<br>’,
 ‘species: ‘, Species))) + # test aes is for plotly
 scale_color_manual(values = species_color) +
 scale_y_reverse() +
 coord_flip() + theme_bw() + theme(legend.position = “none”) + ylab(“Distance”) + # flipped x and y coordinates for aesthetic reasons
 ggtitle(“Iris dendrogram”)

p

作者图片

如果你想变得更有趣,你可以用 plotly 包装你的 ggplot,使你的树状图具有交互性!确保指定tooltip = “text”来控制显示哪些信息。

ggplotly(p, tooltip = “text”)

现在你已经知道了——树图的末端由元数据中的一个变量动态着色!正如我们所看到的,iris 的种类似乎遵循由hclust()确定的层次聚类,这可以通知您在探索性分析管道中完成的进一步测试。

用 7 行代码进行自定义实例分段训练。

原文:https://towardsdatascience.com/custom-instance-segmentation-training-with-7-lines-of-code-ff340851e99b?source=collection_archive---------3-----------------------

用 7 行代码训练您的数据集,以实现实例分割和对象检测。

图片来源:Wikicommons.com(CC0)

图像分割是计算机视觉的一个重要领域,它应用于生活的各个领域。PixelLib 是一个库,创建该库是为了方便将分段应用于现实生活中的问题。它支持 Coco 模型的对象实例分割。使用 coco 模型的分段是有限的,因为您不能执行超出 coco 中可用的 80 个类的分段。现在只需 7 行代码就可以用 PixelLib 库训练你的自定义对象分割模型。

安装 PixelLib 及其依赖项:

安装 Tensorflow 与:(PixelLib 支持 tensorflow 2.0 及以上版本)

  • pip3 安装张量流

安装 imgaug,包括:

  • pip3 安装 imgaug

安装 PixelLib 与

  • pip3 安装 pixellib

如果已安装,请使用以下工具升级至最新版本:

  • pip3 安装 pixellib —升级

训练自定义模型所需的步骤。

第一步:

准备您的数据集:

我们的目标是创建一个可以对蝴蝶和松鼠执行实例分割和对象检测的模型。

为要检测的对象收集图像,并为自定义训练标注数据集。 Labelme 是用来对对象进行多边形标注的工具。创建一个根目录或文件夹,并在其中创建培训和测试文件夹。分离训练(至少 300 张)和测试所需的图像。将您要用于训练的图像放入 train 文件夹,将您要用于测试的图像放入 test 文件夹。您将注释 train 和 test 文件夹中的两个图像。下载 Nature 的数据集作为本文中的样本数据集,解压到 images’文件夹。这个数据集将作为一个指南,让你知道如何组织你的图像。请确保数据集目录的格式与其相同。Nature 是一个数据集,有两个类 butterflysquirrel。每类有 300 幅图像用于训练,每类有 100 幅图像用于测试,即 600 幅图像用于训练,200 幅图像用于验证。自然是一个有 800 张图片的数据集。

阅读这篇文章来学习如何使用 labelme 来注释对象。

[## 使用 Labelme 的图像注释

Labelme 是多边形注记最方便的注记工具之一。这篇文章解释了如何使用 labelme…

medium.com](https://medium.com/@olafenwaayoola/image-annotation-with-labelme-81687ac2d077)

Nature >>train>>>>>>>>>>>> image1.jpg
                           image1.json
                           image2.jpg
                           image2.json >>test>>>>>>>>>>>>  img1.jpg
                           img1.json
                           img2.jpg
                           img2.json 

注释后的文件夹目录示例。

注意: PixelLib 支持用 Labelme 标注。如果您使用其他注释工具,它将与库不兼容。

第二步:

可视化数据集

在训练之前可视化样本图像,以确认遮罩和边界框生成良好。

import pixellib
from pixellib.custom_train import instance_custom_trainingvis_img = instance_custom_training()

我们导入了 pixellib ,从 pixellib 我们导入了类instance _ custom _ training并创建了该类的一个实例。

vis_img.load_dataset("Nature”)

我们使用 load_dataset 函数加载数据集。 PixelLib 要求多边形标注为 coco 格式。当您调用 load_dataset 函数时,train 和 test 文件夹中的单个 json 文件将分别转换成单个 train.jsontest.json训练和测试 json 文件将作为训练和测试文件夹位于根目录中。新文件夹目录现在将如下所示:

Nature >>>>>>>>train>>>>>>>>>>>>>>> image1.jpg
               train.json           image1.json
                                    image2.jpg
                                    image2.json >>>>>>>>>>>test>>>>>>>>>>>>>>> img1.jpg
                  test.json           img1.json
                                      img2.jpg
                                      img2.json

load_dataset 函数中,注释是从 jsons 的文件中提取的。从注释的多边形点生成遮罩,并且从遮罩生成边界框。封装遮罩所有像素的最小框被用作边界框。

vis_img.visualize_sample()

当您调用此函数时,它会显示一个带有遮罩和边框的示例图像。

太好了!数据集适合训练, load_dataset 函数成功地为图像中的每个对象生成遮罩和边界框。在 HSV 空间中为遮罩生成随机颜色,然后将其转换为 RGB。

最后一步:

使用数据集训练自定义模型

这是执行训练的代码。只需 7 行代码,您就可以训练数据集。

train_maskrcnn.modelConfig(network_backbone = "resnet101", num_classes= 2, batch_size = 4) 

我们调用函数 modelConfig,即模型的配置。它采用以下参数:

  • network_backbone: 这是 CNN 网络,用作 mask-rcnn 的特征提取器。使用的特征提取器是 resnet101。
  • num_classes: 我们将类的数量设置为数据集中对象的类别。在这种情况下,我们在自然界的数据集中有两个类(蝴蝶和松鼠)。
  • batch_size: 这是训练模型的批量。它被设置为 4。
train_maskrcnn.load_pretrained_model("mask_rcnn_coco.h5")train_maskrcnn.load_dataset(“Nature”)

我们将使用迁移学习技术来训练模型。Coco 模型已经在 80 个类别的对象上进行了训练,它已经学习了许多将有助于训练模型的特征。我们调用函数 load_pretrained_model 函数来加载 mask-rcnn coco 模型。我们使用 load_dataset 函数加载数据集。

这里下载 coco 模型。

train_maskrcnn.train_model(num_epochs = 300, augmentation=True,path_trained_models = “mask_rcnn_models”)

最后,我们调用 train 函数来训练 mask r-cnn 模型。我们称之为 train_model 函数。该函数采用以下参数:

  • num_epochs :训练模型所需的次数。它被设置为 300
  • 扩充:数据扩充应用于数据集。这是因为我们希望模型学习对象的不同表示。
  • path_trained_models: 这是在训练过程中保存训练好的模型的路径。具有最低验证损失的模型被保存。
Using resnet101 as network backbone For Mask R-CNN modelTrain 600 images 
Validate 200 images Applying augmentation on dataset Checkpoint Path: mask_rcnn_modelsSelecting layers to trainEpoch 1/200
100/100 - 164s - loss: 2.2184 - rpn_class_loss: 0.0174 - rpn_bbox_loss: 0.8019 - mrcnn_class_loss: 0.1655 - mrcnn_bbox_loss: 0.7274 - mrcnn_mask_loss: 0.5062 - val_loss: 2.5806 - val_rpn_class_loss: 0.0221 - val_rpn_bbox_loss: 1.4358 - val_mrcnn_class_loss: 0.1574 - val_mrcnn_bbox_loss: 0.6080 - val_mrcnn_mask_loss: 0.3572

Epoch 2/200
100/100 - 150s - loss: 1.4641 - rpn_class_loss: 0.0126 - rpn_bbox_loss: 0.5438 - mrcnn_class_loss: 0.1510 - mrcnn_bbox_loss: 0.4177 - mrcnn_mask_loss: 0.3390 - val_loss: 1.2217 - val_rpn_class_loss: 0.0115 - val_rpn_bbox_loss: 0.4896 - val_mrcnn_class_loss: 0.1542 - val_mrcnn_bbox_loss: 0.3111 - val_mrcnn_mask_loss: 0.2554

Epoch 3/200
100/100 - 145s - loss: 1.0980 - rpn_class_loss: 0.0118 - rpn_bbox_loss: 0.4122 - mrcnn_class_loss: 0.1271 - mrcnn_bbox_loss: 0.2860 - mrcnn_mask_loss: 0.2609 - val_loss: 1.0708 - val_rpn_class_loss: 0.0149 - val_rpn_bbox_loss: 0.3645 - val_mrcnn_class_loss: 0.1360 - val_mrcnn_bbox_loss: 0.3059 - val_mrcnn_mask_loss: 0.2493 

这是训练日志。它显示了用于训练 mask-rcnn 的网络主干,即 resnet101 ,用于训练的图像数量和用于验证的图像数量。在 path_to_trained models 目录中,模型按照有效性损失减少的原则保存,典型的模型名称如下:mask _ rcnn _ model _ 25–0.55678 it 保存为及其对应的有效性损失。

网络骨干:

有两个网络骨干用于训练 mask-rcnn

  • Resnet101
  • Resnet50

谷歌 colab: 谷歌 colab 提供单个 12GB 英伟达特斯拉 K80 GPU,可连续使用长达 12 小时。

使用 Resnet101: 训练 Mask-RCNN 消耗大量内存。在使用 resnet101 作为网络主干的 google colab 上,你将能够以 4 的批量进行训练。默认的网络主干是 resnet101 。Resnet101 被用作默认主干,因为它在训练期间似乎比 resnet50 更快地达到更低的验证损失。对于包含多个类和更多图像的数据集,这种方法也更有效。

使用 resnet 50:resnet 50 的优点是占用内存较少。因此,根据 colab 随机分配 GPU 的方式,您可以在 google colab 上使用 6 或 8 的 batch_size。

支持 resnet50 的修改代码会是这样的。

完整代码

与原代码的主要区别在于,在模型的配置函数中,我们将 network_backbone 设置为 resnet50 ,并将批量大小改为 6

培训日志中的唯一区别是:

Using resnet50 as network backbone For Mask R-CNN model

说明我们在用 resnet50 进行训练。

注意:给出的 batch _ sizes 是用于 google colab 的样本。如果您使用的是功能较弱的 GPU,请减少批量大小。例如,对于配有 4G RAM GPU 的 PC,resnet50 或 resnet101 的批处理大小都应该为 1。我使用批量大小 1 在我的 PC 的 GPU 上训练我的模型,训练了不到 100 个历元,它产生了 0.263 的验证损失。这是有利的,因为我的数据集并不大。配有更强大 GPU 的 PC 应该可以使用批量大小为 2。如果您有一个包含更多类和更多图像的大型数据集,您可以使用 google colab 免费访问 GPU。最重要的是,尝试使用更强大的 GPU,并为更多的纪元进行训练,以产生一个自定义模型,该模型将跨多个类高效地执行。

通过使用更多图像进行训练来获得更好的结果。建议培训的最低要求是每个班级 300 张图片。

车型评测

当我们完成训练后,我们应该评估验证损失最低的模型。模型评估用于访问测试数据集上已训练模型的性能。从这里下载训练好的模型。

输出

mask_rcnn_models/Nature_model_resnet101.h5 evaluation using iou_threshold 0.5 is 0.890000

模型的 mAP(平均精度)为 0.89。

你可以一次评估多个模型,你只需要传入模型的文件夹目录。

输出日志

mask_rcnn_models\Nature_model_resnet101.h5 evaluation using iou_threshold 0.5 is 0.890000mask_rcnn_models\mask_rcnn_model_055.h5 evaluation using iou_threshold 0.5 is 0.867500mask_rcnn_models\mask_rcnn_model_058.h5 evaluation using iou_threshold 0.5 is 0.8507500

使用 Resnet50 进行评估

注意:C 如果您正在评估 resnet50 型号,请将 network_backbone 更改为 resnet50。

用自定义模型进行推理

我们对模型进行了训练和评估。下一步是观察模型在未知图像上的表现。

我们将在我们训练过的班级上测试这个模型。

Sample1.jpg

资料来源:Wikicommons.com(CC0)

import pixellib
from pixellib.instance import custom_segmentation segment_image =custom_segmentation()
segment_image.inferConfig(num_classes= 2, class_names= ["BG", "butterfly", "squirrel"])

我们导入了用于执行推理的类 custom_segmentation ,并创建了该类的一个实例。我们调用了模型配置的函数并引入了一个额外的参数 class_names。

class_names= ["BG", "butterfly", "squirrel"])

class_names: 这是一个列表,包含模型被训练的类的名称。“背景”是指图像的背景。它是第一个类,并且必须与类名一起提供。

注意:如果你有多个类,并且你不知道如何根据它们的类 id 来排列这些类的名字,在数据集的文件夹中的 test.json 中,检查类别列表。

{"images": [{
"height": 205,"width": 246,"id": 1,"file_name": "C:\\Users\\olafe\\Documents\\Ayoola\\PIXELLIB\\Final\\Nature\\test\\butterfly (1).png"},],
"categories": [{"supercategory": "butterfly","id": 1,"name": "butterfly"},{"supercategory": "squirrel","id": 2,"name": "squirrel"}],

从上面 test.json 目录的样本中可以观察到,test.json 中图片列表之后是物体类别列表。类名和它们对应的类 id 都在那里。蝴蝶有一个类 id 1松鼠有一个类 id 2 。记住,第一个 id“0”是为背景保留的。

segment_image.load_model("mask_rcnn_model/Nature_model_resnet101.h5)segment_image.segmentImage("sample1.jpg", show_bboxes=True, output_image_name="sample_out.jpg")

定制模型被加载,我们调用函数来分割图像。

当参数 show_bboxes 设置为 True,我们将能够执行带有对象检测的实例分割。

test_maskrcnn.segmentImage(“sample1.jpg”,show_bboxes = False, output_image_name=”sample_out.jpg”)

show_bboxes 被设置为 False 时,我们仅获得分段屏蔽。

Sample2.jpg

资料来源:Wikicommons.com

test_maskrcnn.segmentImage(“sample2.jpg”,show_bboxes = True, output_image_name=”sample_out.jpg”)

哇!我们已经成功地训练了一个定制模型,用于在蝴蝶和松鼠上执行实例分割和对象检测。

用自定义模型进行视频分割。

样本 _ 视频 1

我们想对视频中的蝴蝶进行分割。

test_video.process_video("video.mp4", show_bboxes = True,  output_video_name="video_out.mp4", frames_per_second=15)

调用函数 process_video 对视频中的对象进行分割。

它采用以下参数:-

  • video_path: 这是我们想要分割的视频文件的路径。
  • 每秒帧数:该参数用于设置已保存视频文件的每秒帧数。在这种情况下,它被设置为 15,即保存的视频文件每秒将有 15 帧。
  • output _ video _ name:This 是保存的分段视频的名称输出的视频将保存在您当前的工作目录中。

输出 _ 视频

与我们的自定义模型的另一个分段视频样本。

您可以使用以下代码使用您的自定义模型执行实时摄像机分段:

您将用 process_camera 功能替换 process_video 功能。在函数中,我们替换了要捕获的视频文件路径,即我们正在处理摄像机捕获的帧流,而不是视频文件。为了显示摄像机画面,我们添加了额外的参数:

  • 显示帧:该参数处理分段摄像机帧的显示。
  • 这是显示的摄像机框架的名称。

访问 Google colab 为训练自定义数据集而设置的笔记本。

[## 谷歌联合实验室

编辑描述

colab.research.google.com](https://colab.research.google.com/drive/1LIhBcxF6TUQUQCMEXCRBuF4a7ycUmjuw?usp=sharing)

访问 Pixellib 的官方 Github 库

访问 Pixellib 的官方文档

通过以下方式联系我:

邮箱:【olafenwaayoola@gmail.com

领英:阿尤拉·奥拉芬娃

推特: @AyoolaOlafenwa

脸书:阿尤拉·奥拉芬娃

使用 Python 生成器定制迭代模式

原文:https://towardsdatascience.com/custom-iteration-patterns-with-python-generators-12b98e552b38?source=collection_archive---------32-----------------------

创建定制迭代模式

来源

Python 有几个内置的迭代模式,比如由“range()”和“reversed()”方法提供的那些模式。“range()”方法接受“start”和“stop”参数,并返回一个我们可以迭代的不可变序列。“reverse()”方法接受一个输入序列并返回反向迭代器。假设我们想要实现一个定制的迭代模式,其行为与这些内置函数不同。在这篇文章中,我们将讨论如何在 python 中实现定制迭代模式。

我们开始吧!

首先,让我们创建一个迭代模式,它产生一个不断增加的浮动范围。该函数将接受“开始”、“停止”和“增量”参数:

def increment_pattern(start, stop, increment):

接下来,我们将初始化将要增加的变量, x :

def increment_pattern(start, stop, increment):
    x = start

现在,让我们写一个控制流条件,这样,只要一个 x 小于或等于“停止”输入值,随后的任何过程都将继续:

def increment_pattern(start, stop, increment):
    x = start
    while x < stop:

由于我们想编写一个定制的迭代模式,类似于' range()',我们想返回一个生成器。我们使用“yield”关键字来实现这一点:

def increment_pattern(start, stop, increment):
    x = start
    while x < stop:
        yield x

最后,我们增加值, x :

def increment_pattern(start, stop, increment):
    x = start
    while x <= stop:
        yield x
        x += increment

我们现在可以在“for-loop”中调用我们的生成器,并迭代值。让我们传入‘开始’= 0,‘停止’= 3,让我们递增 0.5:

for value in increment_pattern(0, 3, 0.5):
    print(value)

我们还可以定义一个递减模式。让我们定义一个新的函数并改变 while 循环条件,使 x 大于或等于‘stop’值。让我们也反复减去减量值:

def decrement_pattern(start, stop, decrement):
    x = start
    while x >= stop:
        yield x
        x -= decrement

在“for-loop”内的函数调用中,让我们交换 start 和 stop 的值,并递减 0.5:

for value in decrement_pattern(3, 0, 0.5):
    print(value)

最后,我们来看一个更实际的例子。让我们使用一个定制的迭代模式来生成一个对应于指数增长函数的值列表。具体来说,让我们考虑复利的例子:

等式中的各项如下:

  1. A 表示经过一段时间后的金额
  2. P 代表原则,也就是你开始的钱数
  3. r 代表利率
  4. n 是复利的倍数
  5. 代表以年为单位的时间量

假设你出生时在一个储蓄账户里有 1000 美元,你想计算你每年会有多少钱,直到你年满 18 岁,每月复利 8%。让我们定义我们的复利函数。这里,我们将原则初始化为开始时的 1000 美元。我们还将年份 t 初始化为“开始”值。我们还写下了这样一个条件:当年份 t,小于‘停止’时,我们将递增:

def compound_interest_monthly(start, stop, increment):
    t= start
    principle = 1000
    while t < stop:

接下来,我们定义等式中的利息部分:

def compound_interest_monthly(start, stop, increment):
    ...
        interest = (1+ 0.08/12)**(12*t)

然后我们返回生成器并增加我们的年份:

def compound_interest_monthly(start, stop, increment):
    ...
        interest = (1+ 0.08/12)**(12*t)
        yield principle*interest
        t+= increment

总功能如下:

def compound_interest_monthly(start, stop, increment):
    t= start
    principle = 1000
    while t< stop:
        interest = (1+ 0.08/12)**(12*t)
        yield principle*interest
        t+= increment

让我们称我们的生成器为“for-loop ”,其中“start ”= 0 年,“stop ”= 19 年,每年递增:

for value in compound_interest_monthly(0, 19, 1):
    print(value)

让我们看看复利,从相同的原则开始,在相同的时间段内,以 4%的利率按季度复利计算:

def compound_interest_quarterly(start, stop, increment):
    t= start
    principle = 1000
    while t< stop:
        interest = (1+ 0.04/4)**(4*t)
        yield principle*interest
        t+= increment

让我们迭代我们的生成器:

for value in compound_interest_quarterly(0, 19, 1):
    print(value)

我就讲到这里,但是您可以自己随意摆弄代码。

结论

总之,在这篇文章中,我们讨论了如何用 python 中的生成器定义定制迭代模式。我们创建了定制的递增和递减迭代模式,允许我们生成一系列的浮点。然后我们开发了一个更实用的定制迭代模式来计算复利。我希望你觉得这篇文章有趣/有用。这篇文章中的代码可以在 GitHub 上找到。感谢您的阅读!

Tensorflow 2.0 中的自定义损失函数

原文:https://towardsdatascience.com/custom-loss-function-in-tensorflow-2-0-d8fa35405e4e?source=collection_archive---------2-----------------------

高低位执行亏损。

2020 年不逃 2.0 版本

当我学习在 Tensorflow (TF)中编写自己的图层时,我遇到的第一个困难是如何编写一个损失函数。TF 包含了几乎所有你需要的损失函数,但有时这还不够。当实现深度强化学习或构建您自己的模型时,您可能需要编写您的损失函数。这正是这篇博文想要阐明的。我们将以两种不同的方式编写损失函数:

  1. 对于 tf.keras 模型(高级)
  2. 对于定制 TF 型号(低级别)

对于这两种情况,我们将构建一个简单的神经网络来学习数字的平方。网络将接收一个输入,并有一个输出。这个网络绝不是成功或完整的。这是非常初级的,只是为了演示不同的损失函数实现。

1.tf.keras 自定义损失(高级别)

我们来看一个高阶损失函数。我们假设已经使用 tf.keras 构建了一个模型。可以通过以下方式实现模型的自定义损失函数:

tf.keras 中的高级损耗实现

首先,自定义损失函数总是需要两个参数。第一个是实际值(y_actual),第二个是通过模型预测的值(y_model)。需要注意的是,这两个都是 TF 张量而不是 Numpy 数组。在函数内部,你可以随意计算损失,除了返回值必须是一个 TF 标量。

在上面的例子中,我使用 tensor flow . keras . back end . square()计算了平方误差损失。然而,没有必要使用 Keras 后端,任何有效的张量运算都可以。

一旦损失函数被计算出来,我们需要在模型编译调用中传递它。

model.compile(loss=custom_loss,optimizer=optimizer)

完整的代码可以在这里找到:链接

2.自定义 TF 损失(低水平)

在前一部分中,我们看了一个 tf.keras 模型。如果我们想在 TF 中从头开始写一个网络,在这种情况下我们会如何实现 loss 函数呢?这将是模型的低级实现。让我们再写一个同样的模型。下面给出了完整的实现,

TF 2.0 中模型的底层实现

乌夫!代码太多了。让我们解开信息。

init() :构造器构造模型的层(不返回 tf.keras.model。

run() :通过将输入手动传递到各层来运行给定输入的模型,并返回最后一层的输出。

get_loss() :计算损失并将其作为 TF 张量值返回

到目前为止,实现 loss 似乎很容易,因为我们直接处理模型,但现在我们需要通过自动微分来执行学习。这是在 TF 2.0 中使用 TF 实现的。GradientTape()。函数 get_grad() 计算层变量的梯度 wrt。需要注意的是,所有的变量和自变量都是 TF 张量。

network_learn() :我们使用从 get_grad()函数获得的梯度在这个函数中应用梯度下降步骤。

写完所有内容后,我们可以如下实现训练循环:

x=[1,2,3,4,5,6,7,8,9,10]
x=np.asarray(x,dtype=np.float32).reshape((10,1))
y=[1,4,9,16,25,36,49,64,81,100]
y=np.asarray(y,dtype=np.float32).reshape((10,1))
model=model()
for i in range(100):
    model.network_learn(x,y)

完整代码可以在这里找到:链接

结论

在这篇文章中,我们看到了 TensorFlow 2.0 中自定义损失函数的高级和低级植入。知道如何实现自定义损失函数在强化学习或高级深度学习中是不可或缺的,我希望这篇小帖子能让你更容易实现自己的损失函数。关于自定义损失函数的更多细节,我们请读者参考张量流文档

Keras 中的自定义指标以及它们在 tensorflow2.2 中的使用有多简单

原文:https://towardsdatascience.com/custom-metrics-in-keras-and-how-simple-they-are-to-use-in-tensorflow2-2-6d079c2ca279?source=collection_archive---------19-----------------------

使用 Keras 和 tensorflow2.2 无缝添加用于深度神经网络训练的复杂指标

Keras 已经大大简化了基于 DNN 的机器学习,并且越来越好。在这里,我们展示了如何基于混淆矩阵(回忆、精度和 f1)实现指标,并展示了在 tensorflow 2.2 中如何简单地使用它们。可以直接在 Google Colab 中运行笔记本

当考虑一个多类问题时,人们常说,如果类不平衡,准确性就不是一个好的度量。虽然这肯定是真的,但是当所有的类训练得不一样好时,即使数据集是平衡的,准确性也是一个糟糕的度量。

在这篇文章中,我将使用时尚 MNIST 来突出这一方面。然而,这不是本文的唯一目标,因为这可以通过在培训结束时在验证集上简单地绘制混淆矩阵来实现。我们在这里讨论的是轻松扩展keras.metrics.Metric类的能力,以便在训练期间生成一个跟踪混淆矩阵的指标,并可用于跟踪特定类的召回率、精确度和 f1,并以 keras 的常用方式绘制它们。

在训练期间获得特定类别的召回率、精确度和 f1 至少有两个好处:

  1. 我们可以看到训练是否稳定——图不会跳得太多——在每个职业的基础上
  2. 我们可以基于类统计实现更定制的训练——提前停止甚至动态改变类权重。

此外,自 tensorflow 2.2 以来,由于新的模型方法train_steptest_step,将这种自定义指标集成到训练和验证中变得非常容易。还有一个助手predict_step,我们在这里没有用到,但也以同样的精神工作。

所以让我们言归正传。我们首先创建一个定制的度量类。虽然还有更多的步骤,并在参考的 jupyter 笔记本中显示,但重要的是实现与 Keras 培训和测试工作流的其余部分集成的 API。这就像实现和update_state一样简单,它接受真正的标签和预测,一个reset_states重新初始化指标。

class ConfusionMatrixMetric(tf.keras.metrics.Metric):

    def update_state(self, y_true, y_pred,sample_weight=None):
        self.total_cm.assign_add(self.confusion_matrix(y_true,y_pred))
        return self.total_cm

    def result(self):
        return self.process_confusion_matrix()

    def confusion_matrix(self,y_true, y_pred):
        """
        Make a confusion matrix
        """
        y_pred=tf.argmax(y_pred,1)
        cm=tf.math.confusion_matrix(y_true,y_pred,dtype=tf.float32,num_classes=self.num_classes)
        return cm

    def process_confusion_matrix(self):
        "returns precision, recall and f1 along with overall accuracy"
        cm=self.total_cm
        diag_part=tf.linalg.diag_part(cm)
        precision=diag_part/(tf.reduce_sum(cm,0)+tf.constant(1e-15))
        recall=diag_part/(tf.reduce_sum(cm,1)+tf.constant(1e-15))
        f1=2*precision*recall/(precision+recall+tf.constant(1e-15))
        return precision,recall,f1 

在正常的 Keras 工作流中,将调用方法result,它将返回一个数字,不需要做任何其他事情。然而,在我们的例子中,我们有三个返回的精度、召回和 f1 的张量,Keras 不知道如何开箱即用。这就是 tensorflow 2.2 新特性的用武之地。

自 tensorflow 2.2 以来,可以透明地修改每个训练步骤(即小批量训练)中发生的事情(而在早期,必须编写一个在自定义训练循环中调用的无界函数,并且必须用 tf.function 对其进行修饰以实现自动签名)。

同样,细节在参考的 jupyter 笔记本中,但关键是以下几点

class MySequential(keras.Sequential):

    def train_step(self, data):
        # Unpack the data. Its structure depends on your model and
        # on what you pass to `fit()`. x, y = data with tf.GradientTape() as tape:
            y_pred = self(x, training=True)  # Forward pass
            # Compute the loss value.
            # The loss function is configured in `compile()`.
            loss = self.compiled_loss(
                y,
                y_pred,
                regularization_losses=self.losses,
            ) # Compute gradients
        trainable_vars = self.trainable_variables
        gradients = tape.gradient(loss, trainable_vars) # Update weights
        self.optimizer.apply_gradients(zip(gradients, trainable_vars))
        self.compiled_metrics.update_state(y, y_pred)
        output={m.name: m.result() for m in self.metrics[:-1]}
        if 'confusion_matrix_metric' in self.metrics_names:
            self.metrics[-1].fill_output(output)
        return output

就是这样。现在你可以创建(使用上面的类而不是 keras。Sequential),编译并装配一个顺序模型(处理函数式和子类化 API 的过程非常简单,只需实现上述函数即可)。产生的历史现在有像val_F1_1等元素。

这样做的好处是我们可以看到各个班级是如何训练的

火车和 val F1s 的演变为 10 级时装 MNIST 作为时代的进步

我们看到第 6 类训练非常糟糕,在验证集上 F1 大约为 0.6,但是训练本身是稳定的(图没有太多跳跃)。

正如在开始时提到的,在培训期间获得每个类的指标至少有两个好处:

  1. 我们可以看到训练是否稳定——图不会跳得太多——在每个职业的基础上
  2. 我们可以基于基于类统计的早期停止或者甚至动态改变类权重来实现更定制的训练。

最后,让我们看看困惑矩阵,看看第 6 类发生了什么

时尚 MNIST 的困惑矩阵

在混淆矩阵中,真实类在 y 轴上,预测类在 x 轴上。我们看到衬衫(6)被错误地标注为 t 恤(0)、套头衫(2)和外套(4)。相反,贴错标签的衬衫大多发生在 t 恤上。这种类型的错误是合理的,我将在另一篇文章中讨论在这种情况下如何改进培训。

参考:

  1. github 上的代码
  2. 谷歌 Colab 笔记本

Keras 中的自定义神经网络:街头战士构建图表指南

原文:https://towardsdatascience.com/custom-neural-networks-in-keras-a-street-fighters-guide-to-build-a-graphcnn-e91f6b05f12e?source=collection_archive---------33-----------------------

如何建立具有自定义结构和层的神经网络:Keras 中的图形卷积神经网络(GCNN)。

在我们生活中的某个时刻,Tensorflow Keras 中预定义的图层已经不够用了!我们想要更多!我们希望建立具有创造性结构和奇异层的定制神经网络!幸运的是,我们可以通过定义自定义层和模型,在 Keras 中轻松执行这项任务。在这个循序渐进的教程中,我们将建立一个具有并行层的神经网络,包括图形卷积层。等一下!什么是图上的卷积?

图形卷积神经网络

在传统的神经网络层中,我们执行层输入矩阵 X 和可训练权重矩阵 W 之间的矩阵乘法。然后我们应用激活函数 f. 因此,下一层的输入(当前层的输出)可以表示为 f(XW)。在图卷积神经网络中,我们假设相似的实例在图中连接(例如,引用网络、基于距离的网络等)。)并且来自邻域的特征在(无人监督的)任务中可能是有用的。设 A 是图的邻接矩阵,那么我们要在一个卷积层中执行的操作就是 f(AXW) 。对于图中的每个节点,我们将聚集来自其他连接节点的特征,然后将该聚集乘以权重矩阵,然后应用激活。这种图形卷积公式是最简单的。这对于我们的教程来说很好,但是 graphCNN 要复杂得多!

好吧!现在,我们准备好了!

第一步。准备

首先,我们需要导入一些包。

# Import packages
from tensorflow import __version__ as tf_version, float32 as tf_float32, Variable
from tensorflow.keras import Sequential, Model
from tensorflow.keras.backend import variable, dot as k_dot, sigmoid, relu
from tensorflow.keras.layers import Dense, Input, Concatenate, Layer
from tensorflow.keras.losses import SparseCategoricalCrossentropy
from tensorflow.keras.utils import plot_model
from tensorflow.random import set_seed as tf_set_seed
from numpy import __version__ as np_version, unique, array, mean, argmax
from numpy.random import seed as np_seed, choice
from pandas import __version__ as pd_version, read_csv, DataFrame, concat
from sklearn import __version__ as sk_version
from sklearn.preprocessing import normalizeprint("tensorflow version:", tf_version)
print("numpy version:", np_version)
print("pandas version:", pd_version)
print("scikit-learn version:", sk_version)

您应该收到作为输出的导入包的版本。在我的例子中,输出是:

tensorflow version: 2.2.0 
numpy version: 1.18.5 
pandas version: 1.0.4 
scikit-learn version: 0.22.2.post1

在本教程中,我们将使用 CORA 数据集:

Cora 数据集包括 2708 份科学出版物,分为七类。引文网络由 5429 个链接组成。数据集中的每个出版物由 0/1 值的词向量来描述,该词向量指示字典中相应词的存在与否。这部词典由 1433 个独特的单词组成。

让我们加载数据,创建邻接矩阵并准备特征矩阵。

# Load cora datadtf_data = read_csv("https://raw.githubusercontent.com/ngshya/datasets/master/cora/cora_content.csv").sort_values(["paper_id"], ascending=True)
dtf_graph = read_csv("https://raw.githubusercontent.com/ngshya/datasets/master/cora/cora_cites.csv")# Adjacency matrix
array_papers_id = unique(dtf_data["paper_id"])
dtf_graph["connection"] = 1
dtf_graph_tmp = DataFrame({"cited_paper_id": array_papers_id, "citing_paper_id": array_papers_id, "connection": 0})
dtf_graph = concat((dtf_graph, dtf_graph_tmp)).sort_values(["cited_paper_id", "citing_paper_id"], ascending=True)
dtf_graph = dtf_graph.pivot_table(index="cited_paper_id", columns="citing_paper_id", values="connection", fill_value=0).reset_index(drop=True)
A = array(dtf_graph)
A = normalize(A, norm='l1', axis=1)
A = variable(A, dtype=tf_float32)# Feature matrix
data = array(dtf_data.iloc[:, 1:1434])# Labels
labels = array(
    dtf_data["label"].map({
        'Case_Based': 0,
        'Genetic_Algorithms': 1,
        'Neural_Networks': 2,
        'Probabilistic_Methods': 3,
        'Reinforcement_Learning': 4,
        'Rule_Learning': 5,
        'Theory': 6
    })
)# Check dimensions
print("Features matrix dimension:", data.shape, "| Label array dimension:", labels.shape, "| Adjacency matrix dimension:", A.shape)

最后,让我们定义一些对神经网络训练有用的参数。

# Training parameters
input_shape = (data.shape[1], )
output_classes = len(unique(labels))
iterations = 50
epochs = 100
batch_size = data.shape[0]
labeled_portion = 0.10

正如您可以从上面的代码中推断出的,对于每个模型,我们将执行 50 次迭代,在每次迭代中,我们将随机选择 10%的标记集(训练集),并训练模型 100 个时期。

需要指出的是,本教程的范围不是在 CORA 数据集上训练最准确的模型。相反,我们只想提供一个用 keras 定制层实现定制模型的例子!

模型 1:具有连续层的神经网络

作为基线,我们使用具有顺序层的标准神经网络(一个熟悉的 keras 顺序模型)。

# Model 1: standard sequential neural networktf_set_seed(1102)
np_seed(1102)model1 = Sequential([
    Dense(32, input_shape=input_shape, activation='relu'),
    Dense(16, activation='relu'),
    Dense(output_classes, activation='softmax')
], name="Model_1")
model1.save_weights("model1_initial_weights.h5")model1.summary()
plot_model(model1, 'model1.png', show_shapes=True)

我们可以绘制模型来查看顺序结构。

图片作者。模型 1 的结构:连续致密层。

让我们看看这个模型表现如何。

# Testing model 1tf_set_seed(1102)
np_seed(1102)acc_model1 = []for _ in range(iterations): mask = choice([True, False], size=data.shape[0], replace=True, p=[labeled_portion, 1-labeled_portion])
    labeled_data = data[mask, :]
    unlabeled_data = data[~mask, :]
    labeled_data_labels = labels[mask]
    unlabeled_data_labels = labels[~mask] model1.load_weights("model1_initial_weights.h5") model1.compile(
        optimizer='adam',
        loss=SparseCategoricalCrossentropy(from_logits=False),
        metrics=['accuracy']
    ) model1.fit(labeled_data, labeled_data_labels, epochs=epochs, batch_size=batch_size, verbose=0) acc_model1.append(sum(argmax(model1.predict(unlabeled_data, batch_size=batch_size), axis=1) == unlabeled_data_labels) / len(unlabeled_data_labels) * 100)print("\nAverage accuracy on unlabeled set:", mean(acc_model1), "%")

你应该获得 55%的平均准确率。

模型 2:具有平行层的神经网络

下面介绍一个对之前模型的小修改。这一次我们希望有一个具有两个平行隐藏层的网络。我们使用 Keras 功能 API 。使用函数式 API,我们可以构建具有非线性拓扑的模型、具有共享层的模型以及具有多个输入或输出的模型。基本上,我们需要将每一层分配给一个变量,然后引用该变量来连接不同的层,以便创建一个有向无环图(DAG)。然后,可以通过传递输入层和输出层来构建模型。

# Model 2: neural network with parallel layerstf_set_seed(1102)
np_seed(1102)m2_input_layer = Input(shape=input_shape)
m2_dense_layer_1 = Dense(32, activation='relu')(m2_input_layer)
m2_dense_layer_2 = Dense(16, activation='relu')(m2_input_layer)
m2_merged_layer = Concatenate()([m2_dense_layer_1, m2_dense_layer_2])
m2_final_layer = Dense(output_classes, activation='softmax')(m2_merged_layer)model2 = Model(inputs=m2_input_layer, outputs=m2_final_layer, name="Model_2")
model2.save_weights("model2_initial_weights.h5")model2.summary()
plot_model(model2, 'model2.png', show_shapes=True)

平行层 m2_dense_layer_1m2_dense_layer_2 依赖于同一个输入层 m2_input_layer ,然后在 m2_merged_layer 中串接形成一个唯一层。这个神经网络应该是这样的:

图片作者。模型 2 的结构:平行密集层。

让我们测试这个模型。

# Testing model 2tf_set_seed(1102)
np_seed(1102)acc_model2 = []for _ in range(iterations): mask = choice([True, False], size=data.shape[0], replace=True, p=[labeled_portion, 1-labeled_portion])
    labeled_data = data[mask, :]
    unlabeled_data = data[~mask, :]
    labeled_data_labels = labels[mask]
    unlabeled_data_labels = labels[~mask] model2.load_weights("model2_initial_weights.h5")
    model2.compile(
        optimizer='adam',
        loss=SparseCategoricalCrossentropy(from_logits=False),
        metrics=['accuracy']
    ) model2.fit(labeled_data, labeled_data_labels, epochs=epochs, batch_size=batch_size, shuffle=False, verbose=0) acc_model2.append(sum(argmax(model2.predict(unlabeled_data, batch_size=batch_size), axis=1) == unlabeled_data_labels) / len(unlabeled_data_labels) * 100)print("\nAverage accuracy on unlabeled set:", mean(acc_model2), "%")

平均准确率近 60% (+5)!

模型 2:具有图形 conv 层的神经网络

到目前为止,我们已经看到了如何使用 Keras Functional API 创建自定义网络结构。如果我们需要用用户定义的操作定义自定义层怎么办?在我们的例子中,我们想定义一个简单的图卷积层,如本教程开始时所解释的。为此,我们需要从类创建一个子类,并定义方法 initbuildcall

# Graph convolutional layerclass GraphConv(Layer): def __init__(self, num_outputs, A, activation="sigmoid", **kwargs):
        super(GraphConv, self).__init__(**kwargs)
        self.num_outputs = num_outputs
        self.activation_function = activation
        self.A = Variable(A, trainable=False) def build(self, input_shape):
        # Weights
        self.W = self.add_weight("W", shape=[int(input_shape[-1]), self.num_outputs])
        # bias
        self.bias = self.add_weight("bias", shape=[self.num_outputs]) def call(self, input):
        if self.activation_function == 'relu':
            return relu(k_dot(k_dot(self.A, input), self.W) + self.bias)
        else:
            return sigmoid(k_dot(k_dot(self.A, input), self.W) + self.bias)

在初始化过程中,你可以要求和保存任何有用的参数(如激活函数,输出神经元的数量)。在我们的例子中,我们还需要邻接矩阵 A 。在构建方法中,初始化层的可训练权重。在 call 方法中,声明了向前传递计算。

与前面的模型一样,我们定义了一个具有平行层的网络。

# Model 3: neural network with graph convolutional layertf_set_seed(1102)
np_seed(1102)m3_input_layer = Input(shape=input_shape)
m3_dense_layer = Dense(32, activation='relu')(m3_input_layer)
m3_gc_layer = GraphConv(16, A=A, activation='relu')(m3_input_layer)
m3_merged_layer = Concatenate()([m3_dense_layer, m3_gc_layer])
m3_final_layer = Dense(output_classes, activation='softmax')(m3_merged_layer)model3 = Model(inputs=m3_input_layer, outputs=m3_final_layer, name="Model_3")model3.save_weights("model3_initial_weights.h5")model3.summary()
plot_model(model3, 'model3.png', show_shapes=True)

它看起来像前面的模型,但有一层是卷积的:每个实例的固有特征与从邻域计算的聚合特征连接在一起。

图片作者。模型 3 的结构:卷积层和自定义结构。

在编制该模型时应进一步注意。由于卷积层需要整个邻接矩阵,我们需要传递整个特征矩阵(标记和未标记的实例),但是模型应该只在标记的实例上训练。因此,我们定义了一个定制的损失函数,其中稀疏分类 cossentropy 仅在标记的实例上计算。此外,我们将未标记实例的标签随机化,以确保它们不会在训练中使用。

# Testing model 3tf_set_seed(1102)
np_seed(1102)acc_model3 = []for i in range(iterations):
    mask = choice([True, False], size=data.shape[0], replace=True, p=[labeled_portion, 1-labeled_portion])
    unlabeled_data_labels = labels[~mask]
    # Randomize the labels of unlabeled instances
    masked_labels = labels.copy()
    masked_labels[~mask] = choice(range(7), size=sum(~mask), replace=True) model3.load_weights("model3_initial_weights.h5")
    model3.compile(
        optimizer='adam', 
        loss=lambda y_true, y_pred: SparseCategoricalCrossentropy(from_logits=False)(y_true[mask], y_pred[mask]),
        metrics=['accuracy']
    ) model3.fit(data, masked_labels, epochs=epochs, batch_size=batch_size, shuffle=False, verbose=0) predictions = argmax(model3.predict(data, batch_size=batch_size), axis=1)
    acc_model3.append(sum(predictions[~mask] == unlabeled_data_labels) / len(unlabeled_data_labels) * 100)print("\nAverage accuracy on unlabeled set:", mean(acc_model3), "%")

这个实验的平均准确率为 63% (+3)。

有趣的是,在最后一个实验中,我们基本上是在用 graphCNN 执行一个 半监督学习 :来自未标记实例的信息与标记实例一起用于构建一个基于图的直推模型

包含代码的完整 Jupyter 笔记本可以在这里找到。

参考

联系人:LinkedIn|Twitter

使用暗网的自定义对象检测

原文:https://towardsdatascience.com/custom-object-detection-using-darknet-9779170faca2?source=collection_archive---------3-----------------------

创建自定义对象检测器指南—第 1 部分

以 15 fps 的速度输出视频

在这篇文章中,你将使用 【暗网】 训练模型进行蒙版检测。

本文可参考训练任何自定义物体探测器

引用:视频输出可以在 YouTube 上通过彭博快带获得,用于训练的下载图片可以在 Kaggle 上作为开源获得。这些图片是我个人电脑的截图。非常感谢我的同事 Shauryasikt Jena

您无需从头开始训练自己的模型,而是可以在现有模型的基础上进行构建,并根据自己的目的对其进行微调,而不需要太多的计算能力。我用 Google Colab 进行训练,用 CPU(本地机器)进行测试。

什么是暗网?

Darknet 是一个开源的神经网络框架。这是一个快速和高度准确的(定制训练模型的准确性取决于训练数据、时期、批量大小和一些其他因素)框架,用于实时对象检测(也可用于图像)。最重要的原因是它很快,因为它是用 C 和 CUDA 编写的。

为了了解 C 有多快—

Mandelbrot 集合执行时间的比较

欲了解更多对比数据,请访问本页

[## python 3 vs C gcc——哪些程序最快?计算机语言基准游戏

Python 3 C gcc -哪些程序最快?

benchmarksgame-team.pages.debian.net](https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/python3-gcc.html)

内容

  1. 装置
  2. 收集图像
  3. 给图像加标签
  4. 获取和设置暗网
  5. 训练我们的暗网

让我们开始吧,非常简单。只需浏览文章并按照步骤操作即可。谢谢:)

1.装置

我们将在 Google colab 上训练我们的模型,因此没有额外的库需要安装

但是如果你在本地机器上测试这个模型,这里有你需要的库—

opencv==4.2.0
tensorflow==1.13.2
numpy==1.18.1
pandas==1.0.2
keras==2.3.1
matplotlib==3.2.0
PIL==7.0.0
ffmpeg==4.2.2

请分别使用 anaconda cloud 或 Pypi 上的 conda 或 pip 在您的本地系统上安装这些库。

注意:ffmpeg 用于保存输出视频文件,因此需要特定的版本。

conda install ffmpeg

2.收集图像

你可以通过点击下载从这个链接获得图片—

[## 医用口罩数据集

人们戴着医用口罩的照片

www.kaggle.com](https://www.kaggle.com/vtech6/medical-masks-dataset)

注:该链接包含一个 zip 文件,其中的图像及其标签/注释已经存在,但确保它们是正确的(相对于屏蔽/非屏蔽的坐标)。只是为了确保我手动标记它,这样我就不需要再次训练模型。

下载的文件将只有大约 700 张图片,这不足以获得良好的准确性。你也可以从这些链接中得到它们..

[## 面罩数据集

Kaggle 是世界上最大的数据科学社区,拥有强大的工具和资源来帮助您实现您的数据…

www.kaggle.com](https://www.kaggle.com/shreyashwaghe/face-mask-dataset)

你可以从这里得到蒙版和非蒙版的图像—

[## 掩膜数据集 V1

戴口罩和不戴口罩的人。

www.kaggle.com](https://www.kaggle.com/ahmetfurkandemr/mask-datasets-v1)

现在你已经收集了 1300 多张图片(如果可能的话,你可以添加更多的图片,这肯定会提高准确性),这是一个有点繁琐但很重要的步骤。

3.标记

在收集了大约 1300 或更多的图像后,你必须手动标记它们。是的,这是一个非常繁琐的任务,但正确标记图像是非常重要的,否则它会反映在模型上,精度不会令人满意!

要给图像加标签,你可以使用一个非常有名的工具 Labelimg。

你可以在你的系统上克隆这个链接—

[## 佐他林/标签

LabelImg 是一个图形化的图像注释工具。它是用 Python 写的,使用 Qt 作为它的图形界面…

github.com](https://github.com/tzutalin/labelImg)

注意:克隆完成后,我建议您查看安装步骤,因为您必须在命令提示符下写两三行

关于安装指南,您可以观看任何标签安装视频。别担心,安装很容易,但是标签部分是……你知道我的意思。

  1. 转到文件并打开包含图像的文件夹

这是运行 labelimg.py 后的样子

2.单击“创建”复选框,开始标记蒙版图像

从目录中打开图像

3.拖动遮罩周围的区域,然后键入 masked

遮罩图像的标签

4.我们也需要非蒙版,因此同样的程序点击创建/选择框,拖动非蒙版面,并标记为非蒙版

非遮罩面部的标签

5.标记每张脸后,保存并移动到下一张图片

老实说,根据你的速度,你需要 2 到 3 个小时来完成这项工作。所以祝你好运;)

4.获取和设置暗网

获得暗网

你可以直接在 google colab 上克隆这个 GitHub 库用于训练—

[## pjreddie/darknet

Darknet 是用 C 和 CUDA 编写的开源神经网络框架。它速度快,易于安装,并支持 CPU…

github.com](https://github.com/pjreddie/darknet)

注意:除了这个存储库之外,还有另一个存储库,它是 pjreddie 的派生版本。我使用 pjreddie 是因为在第一次尝试时,它对我来说很好。

设置暗网

  1. 你需要一个名为 darknet53.conv.74 的文件,你可以从这里下载并放入 darknet
  2. 在 cfg 文件夹中,使用记事本创建一个名为 yolov3_custom_train.cfg 的文件,将 yolov3.cfg 中的所有内容复制到新文件中。复制这 22 行,而不是文件中的行
[net]
#Testing
#batch=1
#subdivisions=1
#Training
batch=24
subdivisions=8
width=416
height=416
channels=3
momentum=0.9
decay=0.0005
angle=0
saturation = 1.5
exposure = 1.5
hue=.1learning_rate=0.001
burn_in=1000
max_batches = 6000
policy=steps
steps=5400
scales=.1,.1

在文件中使用 ctrl + f 搜索[yolo],并在各处进行这些更改(将有三个[yolo]块)。

注意:更改将发生在每个【yolo】的 和【yolo】正上方的【卷积】块中,仅此而已。cfg,别忘了保存!

[convolutional]
size=1
stride=1
pad=1
filters=21
activation=linear[yolo]
mask = 6,7,8
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=2
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1

让我们简单了解一下我们刚刚做了什么..

我们改变了类=2,因为我们有两个类 屏蔽非 _ 屏蔽 并且在[卷积]中,过滤器=21

过滤器数量的公式是—

过滤器=(类别数+ 5)*3

3.使用记事本在数据文件夹中创建一个名为 yolo.names 的新文件,并复制以下几行..

masked
not_masked

..完成后,保存它。(我们需要这个文件进行测试)

4.创建另外两个文件 train.txt 和 val.txt,并在 training 95% Validation-5%中划分您的图像。

darknet
    ├── cfg
    |   
    ├── data
    |   ├── images
    |          ├── some_image.jpg
    |          ├── other_image.jpg
    |          ├── ...
    |   ├── labels
    |          ├── Some_image.txt
    |          ├── other_image.txt
    |          ├── ...
    |   ├── train.txt 
    |   ├── val.txt
    |
    ├── ...
    .
    .
    ├── darknet53.conv.74
    ...

现在棘手的部分来了..您已经下载的图像应该放在 darknet 的图像文件夹中,而注释/标签放在文件夹中。在 train.txt 和 val.txt 中,你必须像这样给出每个图像的路径..

train.txt 包含全部图像的 95%

val.txt 包含总图像的剩余 5%

提示:你可以写一个简单的 python 代码来做这件事,只需要 2 分钟,不需要手动写全部内容

5.使用记事本创建一个文件“yolo.data ”,并将其粘贴到该文件中..

classes= 2
train  = data/train.txt
valid  = data/val.txt
names = data/yolo.names
backup = backup

5.训练我们的暗网

最期待的部分终于来了。从这里开始,你不需要做任何事情,只需要运行一些代码,然后等待训练完成。

现在只要把你的 darknet 文件夹上传到 google drive 上,我们就快成功了。

提示:如果在任何情况下 google colab 因为你的 GPU 运行时间已经超过而自动断开与的连接,你可以保存你生成的权重文件的检查点,这样你就可以从那个时期继续,也可以测试哪个权重文件给出最好的结果。您可以转到 examples 文件夹中的 detector.c 文件并进行这些更改,以便每 100 个时期后获得权重文件,1000 个时期后获得每 1000 个时期后的权重

在我的驱动器中你的 darknet 文件夹外创建一个备份文件夹

void train_detector(char *datacfg, char *cfgfile, char *weightfile, int *gpus, int ngpus, int clear)
{ .... 
  ....
  ....
  if(i%1000==0 || (i < 1000 && i%100 == 0)){
#ifdef GPU
    if(ngpus != 1) sync_nets(nets, ngpus, 0);
#endif
       char buff[256];
       sprintf(buff, "%s/%s_%d.weights", backup_directory, base, i);
       save_weights(net, buff);
    }

现在我们就快到了,只要确保你有训练模型所需的一切,因为你不想再做一遍。

行..现在让我们训练模型(耶..最后)

最简单的步骤就在这里,但首先要确保你给出的路径是正确的。一个细胞一个细胞地运行这些代码。将 colab 运行时改为 GPU****

注意:下面的命令只适用于 linux,因此我们使用 Google Colab

google.colab import drive
drive.mount('/content/drive')#If you have a zipped darknet
!unzip "/content/drive/My Drive/darknet.zip"%cd /content/darknet
!make
!chmod +x ./darknet!rm /content/darknet/backup -r
!ln -s /content/drive/'My Drive'/backup /content/darknet!sudo apt install dos2unix
!dos2unix ./data/train.txt
!dos2unix ./data/val.txt
!dos2unix ./data/yolo.data
!dos2unix ./data/yolo.names
!dos2unix ./cfg/yolov3_custom_train.cfg#To start the training
%cd /content/darknet
!./darknet detector train data/yolo.data cfg/yolov3_custom_train.cfg darknet53.conv.74

注意:当你从一个检查点开始训练,比如说在 2000 个纪元后,只需将训练命令改为..

!./darknet detector train data/yolo.data cfg/yolov3_custom_train.cfg yolov3_custom_train_2000.weights

就是这样!!感谢您通读整篇文章

为了部署这个经过训练的模型,请看看我的下一篇文章—

** [## 实时自定义对象检测

测试用于对象检测的定制训练暗网模型

towardsdatascience.com](/real-time-custom-object-detection-a95d955cecda)

想了解更多关于暗网的信息,请点击这个链接

[## darknet:C 语言中的开源神经网络

darknet:c 语言中的开源神经网络。

pjreddie.com](https://pjreddie.com/darknet/)**

对象检测:在 Karens 攻击 Keras 和 OpenCV 之前阻止他们

原文:https://towardsdatascience.com/custom-object-detection-using-keras-and-opencv-ddfe89bb3c3?source=collection_archive---------33-----------------------

关于如何构建自己的面部检测系统的演练,该系统可以确定某人是否戴着面具,或者他们是快乐、中立还是愤怒。

模型演示(作者照片)

在新冠肺炎时代,我们已经看到戴口罩可以大大减少病毒的传播。然而,正如我们有时在网上看到的,有很多人强烈反对这种说法。网上的视频显示,当人们被要求遵守这个协议时,他们变得非常不满。在这个项目中,我将向您展示如何创建一个神经网络,它可以检测某人是否戴着面具,如果没有,我们将检测他们脸上的面部表情。随着规模的扩大,这可以应用于当地企业,以便经理们可以检测到某人是否戴着面具,以及他们是否确实是一个准备罢工的卡伦。

照片来自 Giphy

模型演示(作者照片)

** 本教程的代码可以在我的GitHub** **上找到

要求

  • 克拉斯
  • OpenCV
  • NumPy
  • Matplotlib
  • tqdm
  • Sklearn

数据

  1. 面罩:~12K 图像数据集( Kaggle )
  2. 情感:~30K 图像数据集( Kaggle )

掩模检测

这个项目的第一步是建立一个神经网络,可以检测一个人是否戴着面具。对于这一部分,我们将使用 Mobilenet。

在构建模型之前,我们需要提取每张图像并对其进行预处理,以便可以将它输入 Mobilenet。在上面的数据集中,我们看到在最外层有三个目录:(1)训练,(2)测试,和(3)验证。下面是如何提取每个图像,为 mobilenet 预处理它们,并将它们保存到 NumPy 数组的代码。

运行上面的单元格后,您应该会看到这样的窗口。

列车测试拆分(作者供图)

在后面的小节中,我们将重用函数 get_image_value,这就是为什么我们要传递一个参数,说明应该为哪个模型类型检索图像。

现在我们有了图像值,是时候建立神经网络来检测遮罩了。确保在当前目录中有一个名为 ModelWeights 的文件夹。在这个文件夹中,我们将保存我们训练的每个模型的权重。

上面,我们指定模型应该训练 2000 个纪元。因为模型可能不需要 2000 个历元,我们包括了一个早期停止参数,以防止模型在连续 5 次迭代后过度拟合,而损失没有变化。运行上面的单元格后,您应该会看到如下窗口:

训练完成后,您应该会在 ModelWeights 文件夹中看到一个名为 Mobilenet_Masks.h5 的. h5 文件。在该文件中,存储了模型的权重,稍后当我们将该神经网络应用于实时视频时,将会使用该文件。

上面,我们看到了 mobilenet 培训的 ROC 得分、混淆矩阵和损失/准确性。考虑到我们使用的数据量,这些指标已经很不错了。对于验证集,只有 13 幅图像被错误分类。至于损耗和准确度,损耗能够低于 0.1,准确度远高于 94%。最后,ROC 分数显示了巨大的成功,因为每个班级都有 1.0 的满分,而每个班级的 f 1 分数都大于 0.98。

情感检测

与上一个模型一样,我们必须首先提取图像值,并将它们放入一个 NumPy 数组中。正如我前面提到的,我们将在一个新的函数中重用 get_image_value 函数,该函数被设计为只提取情感图像。该数据集包含 7 个类别:愤怒、快乐、中性、悲伤、厌恶、恐惧和惊讶。对于这个项目,我们将只关注前三类:愤怒、快乐和中立。此外,我们将用于训练的模型将采用大小为(48,48,3)的输入图像,这比(224,224,3)的 mobilenet 维度小得多。

情绪训练测试分裂(作者照片)

正如你在上面看到的,我们限制每个类最多只能包含 4000 张图片。这样做是为了让训练更快,这样我们就可以在平衡班级的情况下正确地跟踪学生的表现。

运行上面的代码后,您应该会看到一个与之前类似的窗口,如下所示:

情绪训练测试分裂(作者照片)

现在我们有了训练测试分离阵列,我们将建立神经网络来检测一个人脸上的情绪。下面是如何建立这个神经网络的代码。与 mobilenet 不同,我们不会对数据集应用增强。

情绪训练(作者供图)

运行上面的代码后,您应该会看到一个类似这样的窗口:

情绪训练(作者供图)

一旦训练完成,您应该找到一个名为 Normal_Emotions.h5 的. h5 文件,它将包含模型的权重。与我们之前训练的模型一样,这将用于下面的实时视频部分。

上面,我们看到了情绪模型的 ROC 分数、混淆矩阵和损失/准确性。考虑到我们使用的数据量,这些指标相当不错,但不如 mobilenet。对于训练集,在大约 12,000 幅图像中,只有 1,786 幅图像被错误分类。至于损耗和准确度,损耗能够低于 0.7,准确度保持在 70-75%之间。最后,ROC 分数显示了相当好的成功,因为每个类都保持了大于 0.9 的分数,而每个类的 F1 分数都在 0.7 到 0.9 之间。

部署

现在我们已经训练好了每个模型,我们将使用 OpenCV 将它们应用于现场视频。对于这一部分,您必须在本地机器上安装网络摄像头。

在我们进入代码之前,让我先解释一下这是如何工作的。

  1. 使用哈尔级联分类器,我们将在一个视频帧中找到人脸的坐标(下载链接
  2. 在找到人脸的坐标后,我们将提取该部分,也称为我们的感兴趣区域(ROI)。
  3. 因为我们想弄清楚是否存在一个遮罩,所以我们将首先将 ROI 重新整形为(224,224),以便可以将其输入到我们的 mobilenet 模型中。
  4. 如果 mobilenet 模型预测有一个掩码,那么它将继续而不使用情感模型。
  5. 但是,如果 mobilenet 模型预测没有遮罩,那么它将再次使用 ROI 并将其输入到情感模型中。

下面是它如何工作的代码。乍一看,for 循环中似乎有很多条件,但只要慢慢读,就会明白。

运行上面的代码后,会弹出一个如下所示的窗口。要停止此过程,请按键盘上的“q”按钮。

模型演示(作者照片)

限制

  • 据我所知,如果画面中的人戴着眼镜,这个模型很难区分面具是否存在。
  • 更多包含戴口罩戴眼镜的人的数据将改善这种局限性

未来方向

  • 我打算找一台能探测热量的相机(如果我能找到一台价格实惠的话)
  • 使用摄像头来检测热量以及这些其他功能有利于防止人们在发现发烧时进入商店。

此外,我目前正在寻找一份数据科学方面的工作,所以如果你在这方面有任何建议,请通过LinkedIn联系我!

本教程的代码可以在我的*GitHub **上找到

自定义熊猫统计功能

原文:https://towardsdatascience.com/custom-pandas-statistics-functions-731e767d4807?source=collection_archive---------33-----------------------

生成统计数据的三个有用的 Pandas 函数

照片由像素上的 Pixabay 拍摄

Pandas 是一个有用的 python 库,可用于各种数据任务,包括统计分析、数据插补、数据争论等等。在本帖中,我们将介绍三个有用的自定义函数,它们允许我们从数据中生成统计数据。

我们开始吧!

出于我们的目的,我们将使用葡萄酒评论数据集,可以在这里找到。

首先,让我们导入 pandas 和 numpy 包:

import pandas as pd 
import numpy as np

接下来,让我们将显示列和行的最大数量设置为“None”:

pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)

现在,让我们读入数据:

df = pd.read_csv('winemag-data-130k-v2.csv')

接下来,我们将打印前五行数据,以了解列类型及其值(列结果被截断):

print(df.head())

我们可以考虑一个有趣的函数,它为分类列中的给定类别生成数值列的平均值。该函数将接受一个分类列名、该分类列的分类值和一个数字列名:

def get_category_mean(categorical_column, categorical_value, numerical_column):

在函数中,我们需要过滤该类别值的数据帧,并取该类别数值的平均值:

def get_category_mean(categorical_column, categorical_value, numerical_column):
    df_mean = df[df[categorical_column] == categorical_value]
    mean_value = df_mean[numerical_column].mean()

最后,我们可以使用 python“f 字符串”来打印结果:

def get_category_mean(categorical_column, categorical_value, numerical_column):
    df_mean = df[df[categorical_column] == categorical_value]
    mean_value = df_mean[numerical_column].mean()
    print(f"Mean {categorical_column} for  {numerical_column}", np.round(mean_value, 2))

现在,让我们调用包含分类列“国家”、国家值“意大利”和数字列“价格”的函数:

get_category_mean('country', 'Italy', 'price')

我们也可以调用类别为“品种”、品种值为“黑皮诺”、数值列为“价格”的函数:

get_category_mean('variety', 'Pinot Noir', 'price')

我们可以考虑的另一个函数是为分类列中的每个分类值生成数字列的平均值。我们可以使用熊猫的“分组”方法来实现这一点:

def groupby_category_mean(categorical_column, numerical_column):
    df_groupby = df.groupby(categorical_column)[numerical_column].mean()
    df_groupby = np.round(df_groupby,2)
    print(df_groupby)

如果我们用“国家”和“价格”调用我们的函数,我们将打印每个国家的平均价格(为了清楚起见,结果被截断):

groupby_category_mean('country', 'price')

为了进行健全性检查,我们看到我们得到了与上一个函数中相同的意大利平均价格。我们还可以将该函数应用于葡萄酒品种和价格(为了清楚起见,结果被截断):

groupby_category_mean('variety', 'price')

我们将讨论的最后一个函数为另一个分类列的每个值生成分类列的模式。我们也可以使用熊猫的“分组”方法来实现这一点:

def groupby_category_mode(categorical_column1, categorical_column2):
    df_groupby = df.groupby(categorical_column1)[categorical_column2].agg(pd.Series.mode)
    print(df_groupby)

让我们找到每个国家的葡萄酒品种。这将告诉我们每个国家最常出现的葡萄酒品种:

groupby_category_mode('country', 'variety')

我将在这里停下来,但是您可以自己随意摆弄代码和数据。

结论

总之,在这篇文章中,我们讨论了如何使用 Pandas 定义三个自定义函数来从数据中生成统计洞察。首先,我们展示了如何定义一个函数,在给定分类列和类别值的情况下,计算数字列的平均值。然后,我们展示了如何使用“groupby”方法为分类列中的每个类别生成数值列的平均值。最后,我们展示了如何为一个分类列的每个值生成另一个分类列的模式。如果你有兴趣学习更多关于熊猫的数据操作、机器学习甚至只是 python 编程的一些基础知识,请查看Python for Data Science and Machine Learning:Python 编程、熊猫和 Scikit-初学者学习教程 。我希望你觉得这篇文章有用/有趣。这篇文章中的代码可以在 GitHub 上找到。感谢您的阅读!

定制 PySpark 累加器

原文:https://towardsdatascience.com/custom-pyspark-accumulators-310f63ca3c8c?source=collection_archive---------30-----------------------

约书亚·索蒂诺在 Unsplash 上拍摄的照片

pyspark 蓄能器的字典、列表和设置类型

默认情况下,Spark 提供支持交换和关联操作的 int/float 累加器。尽管 spark 也提供了一个类 AccumulatorParam 来继承,以支持不同类型的累加器。只需要实现两个方法 zeroaddInPlace。zero 定义累加器类型的零值,addInPlace 定义累加器类型的两个值如何相加。

在上一篇文章中,我讨论了管理 pyspark 累加器,这也提供了一个很好的累加器概述:

[## 广播 PySpark 累加器

以及如何管理它们

towardsdatascience.com](/broadcasting-pyspark-accumulators-343104c18c44)

在这篇文章中,我将讨论三种不同类型的自定义累加器:dict、list 和 set。

口述积累器

字典累加器的目标是累加字典。现在,当我们积累字典时,有多种考虑因素:

  1. 现有键:如果键已经存在于累积字典中,我们该怎么办?
  2. Key 的值类型:如何处理 list 和 set 等键的不同类型的值?

现有密钥

我们至少有三种策略:

  • 用新值替换该项的值
  • 保持旧值
  • 添加到现有值

注意,前两个操作是不可交换的,因为它取决于要累加的字典的顺序。如果我们想为一个给定的键保留所有的或者唯一的值,那么我们可以分别用一个列表或者集合来表示值。

键的值类型

如上所述,值的类型对于跟踪给定键的所有或所有唯一值可能是有用的。在这种情况下,我们需要一个列表或集合。可能有其他场景需要其他类型,但这超出了本文的范围。

所以现在我们已经讨论了五种不同风格的录音机。我们没有为每个实现一个类,而是实现了枚举来跟踪组合方法。

白藓积累法

  • REPLACE:如果键存在,则用新值替换当前值,否则将键值添加到字典中
  • KEEP:如果键存在,则保留旧值,否则将键值添加到字典中
  • ADD:如果键存在,则向现有值添加新值,否则向字典添加键值
  • LIST:如果键存在,将新列表添加到现有列表中,否则将键和列表作为值添加到字典中
  • SET:如果关键字存在,则将新集合(从新列表转换)与现有集合值(从现有集合转换为值)联合,否则将关键字和列表值添加到字典中

init 拯救世界

现在我们知道了不同风格的 DictAccumulator,那么如何使用一个单独的类实现来创建呢?很少宣传的事实是用于 AccumulatorParam,init 方法,但是它不需要被指定,首先,因为它是 python 中的类的构造函数。

用 DictAccumulatorMethod 初始化 DictAccumulator 解决了给它调味的问题。除非指定,否则将使用 REPLACE。在 addInPlace 方法中,我们只是用需要合并到 first ( v1 )中的 seconds ( v2 )字典中的键和值来调用方法。

单元测试指令累积器

首先只是设置单元测试。将累加器管理器设置为广播累加器,通过测试设置中的 get_spark 方法和 input_datardd 产生火花。

更换

在这个单元测试中,我们首先为作为字典的键添加双倍的键值,然后添加相同的键值。相同的密钥值会替换双倍的密钥值。

保持

首先在下面的测试中,我们将字典添加到累加器中,其中值是键的两倍。然后将字典添加到值与键相同的累加器中。在第二遍之后,键值应该是键值的两倍,因为我们将累加器初始化为 keep。

增加

在下面的测试中,我们只是将所有的值添加到定义为“ count ”的键中。count键的值与 input_data 的 sum 相同。

列表

在此测试中,我们将所有奇数和偶数数据组合到其各自的密钥中,该密钥是从数字除以 2 的余数中导出的。每个值都被附加到相应键的列表中。

设置

在下面的测试中,残差被添加到键中。因为它的设置只有值 0 和 1 在列表中(键值)。如果是列表,我们会看到多个 0 和 1。

列表累加器

ListAccumulator 的实现相当简单。在这个场景中,我们只添加两个列表,并在 addInPlace 方法中返回它。

单元测试列表累加器

在单元测试中,我只是在加倍后将一个数字列表添加到 ListAccumulator 中。我在驱动程序上创建了相同的数据并进行比较,结果是匹配的。

设定累加器

在 SetAccumulator 实现中,它只是两个集合的并集,作为 addInPlace 方法的返回。

单元测试设置累加器

测试方法与测试过的带 set 类型的录音机相似。多次添加剩余的列表,最后,我们只得到两个剩余的 0 和 1,而不是 0 和 1。

结论

在这篇文章中,讨论了基于列表和集合的 pyspark 累加器,并围绕实现进行了推理。替换和保留字典的累加器是不可交换的,所以使用它们时要小心。下面是 GitHub 上的实现。

[## salil Jain/PySparkCustomAccumulators

在 GitHub 上创建一个帐户,为 salil Jain/PySparkCustomAccumulators 的开发做出贡献。

github.com](https://github.com/SalilJain/PySparkCustomAccumulators)

scikit-learn 中带有最近邻回归的自定义用户定义指标

原文:https://towardsdatascience.com/custom-user-defined-metrics-with-nearest-neighbors-regression-in-scikit-learn-8bec2f303499?source=collection_archive---------36-----------------------

自定义度量教程:预测日平均温度

阿道夫·费利克斯在 Unsplash 上拍摄的照片

在过去的几年里,公众可用的数据科学工具的数量急剧增加。一个这样的工具是 Python 库 scikit-learn (通常被称为 sklearn)。对于 scikit-learn 最近的介绍性概述,您可以看看最近由 Sadrach Pierre 发表的帖子。

在这篇文章中,我将讨论 k 近邻回归。具体来说,我们将了解如何使用用户定义的指标。这个领域受到的关注少得惊人。我将给出一个简单的例子,在这个例子中,实现我们自己的距离度量是有益的。我们将详细了解如何实现这一点,并评论这种方法的优点。

教程概述

任何具有 Python 基础知识的人都可以阅读本教程,完整的代码作为参考。教程中使用的所有数据、代码和图像都在这个 Github 资源库中提供。本教程分为不同的部分:

  • kNN 回归简介
  • 自定义指标的应用示例
  • 创建数据集
  • 实施自定义指标
  • 交叉验证以优化 k
  • 不同指标的准确度比较

kNN 回归简介

当试图预测新点的目标属性( y )时,kNN 对近邻的目标属性值进行加权平均,以计算新点的 y 值。通常,可以通过考虑最近的近邻具有更显著的影响来提高预测精度。这是通过用与其距离成反比的权重对所有 k 个最近的邻居进行加权来实现的。在 scikit-learn 中,我们只需在 kNN 回归器中选择选项weights =‘distance’就可以做到这一点。这意味着更近的点(更小的距离)在预测中将具有更大的权重。形式上,目标资产在新点 n 处的价值,与 k 最近的邻居,计算如下:

关于 kNN 回归的更详细的解释,以及权重函数的影响,请随意参考我最近关于这些主题的博客文章。

自定义指标的应用示例

作为对定义自定义指标感兴趣的一个例子,我们使用一个简单的数据集,该数据集包含加拿大气象站 2019 年每天的平均温度。我们的数据集由一个描述符(一年中的某一天)和一个目标属性(气象站的日平均温度)组成。

2019 年,地球与太阳的最远距离(远日点)为 1.521×10⁸公里,最近距离(近日点)为 1.471×10⁸公里。这两个值非常相似(相差~3%),所以为了简单起见,我们在这里假设地球的轨道是圆形的。这种近似可以在下图中可视化,其中围绕太阳的实际轨道以橙色显示,圆形近似轨道以白色显示。

图片由 Sch维基共享CC BY-SA 3.0

在一年中,地球绕太阳转一圈。因此,一年中两个日期之间的距离可以计算为地球在此期间沿其轨道运行的距离。沿着轨道的两点之间的距离,与我们最初可能天真地计算出的直接欧几里得距离不同。

在下图中,我们显示了两点 B 和 C 相对于初始点 A 的相对距离。例如,当我们直接使用欧几里德度量(红色)计算 A-B 和 A-C 距离的比率时,我们得到大约 0.7,这意味着 A-B 距离大约是 A-C 距离的 70%。但是,如果我们考虑沿圆周(绿色)计算的距离,我们得到 A-B 距离是 A-C 距离的 50%。我们可以很容易地观察到最后一个度量是如何正确描述我们的问题的:1 月和 4 月之间的距离的 50%

作者图片

创建数据集

我们从美国国家海洋和大气管理局 climate.gov 站获取温度数据。我们重点关注加拿大马尼托巴省天鹅河站(CA00504K80K 站)2019 年的数据。

原始数据由日期 (YYYYMMDD)和 T (十分之一摄氏度)组成。我们将数据转换为(从 1 到 365)和 T (摄氏度)。我们提供了这四列的数据,虽然代码中只使用了最后两列,2019 年的 364 天(缺少 7 月 30 日的数据)。下面我们展示这些数据的样子,完整的数据集在这个 Github 仓库中提供。

实施自定义指标

在 scikit-learn 中,k-NN 回归默认使用欧几里德距离,尽管还有更多的距离度量可用,例如曼哈顿和切比雪夫。此外,我们可以使用关键字 metric 来使用用户定义的函数,该函数读取两个数组 X1X2 ,其中包含我们想要计算其距离的两个点的坐标。

下面,我们展示了一个带有函数 mimic_minkowski 的简单代码,因此使用 metric=mimic_minkowski 会产生与使用默认 minkowski(欧几里得)度量和metric =‘Minkowski’完全相同的结果。

因为我们想研究圆周上各点的距离,所以使用极坐标非常方便。我们在下面展示了由此产生的距离方程。

请注意,我们的函数将用于计算距离之间的相对差异,因此我们可以将上述等式简化为:

在我们的数据集中,我们有每天的日期,所以我们可以很容易地将时差转换成角度差(θ₁-θ₂).假设地球的轨道是圆形的,并且以恒定的速度运动,我们可以将一年中 Day₁和 Day₂两天之间的差异转换为角度差异,如下所示。

最后,我们可以创建我们的 custom_metric 函数,如下所示。

交叉验证以优化 k

选择 k 个最近邻的最佳数量以进行精确预测的简单方法是使用网格搜索。网格搜索包括尝试不同的 k 值,最后选择一个最小化预测误差的值。

与任何机器学习模型一样,人们面临着选择将用于训练模型的数据和将用于测试模型准确性的数据的任务。

由于我们有相对少量的低维数据,我们将使用留一交叉验证(对于更复杂的数据集,可以选择 k 倍交叉验证)。为了对具有 N 个样本的数据集使用留一交叉验证,人们用 N-1 个点训练机器学习模型,并使用剩余的点作为测试。这被重复 N 次,所以每个点正好被用作一次测试。这种交叉验证的示意图如下所示。

作者图片

结果,每个点都有一个预测值。然后,将每个点的预测值与其实际值进行比较。作为误差指标,我们使用了均方根误差(rmse)。最后,我们可以比较针对不同的 k 值获得的(rmse ),并选择最小化 rmse 的值作为最佳的 k 值。包括这个网格搜索在内的完整代码如下所示。

使用该代码,我们得到最小 rmse 是在 k=2 时获得的,结果是 rmse=2.725 C 。这意味着我们可以估计 2019 年任何一天的日平均温度,只需知道今年剩余时间的日平均温度,平均误差为 2.725 摄氏度。

不同指标的准确度比较

我们可以合理地问,使用这一新指标的好处是什么。如果我们在上面代码的第 39 行更改为 metric= 'minkowski' ,我们得到最佳邻居的数量为 k=2,平均误差为 rmse=2.740 C 。因为我们使用一个非常简单的例子,只有一个描述符,使用一个更合理的度量标准的改进很小:大约 0.5%。

然而,人们应该始终确保使用合理的度量标准。此外,这 0.5%的误差可能对你的问题至关重要。此外,随着数据集复杂性的增加,采用适当指标的改进可能会增加。

结论

我们已经介绍了 k-最近邻回归的基础知识以及如何将其应用于简单的数据集。我们还看到了如何实现用户定义的定制度量函数,以及如何使用正确的度量来提高您的预测准确性。

请记住,这里展示的数据集、代码、图像等。在这个 Github 库中提供。

这个教程对你有帮助吗?让我知道你是否能够成功实现你自己的距离度量!

客户行为建模:聚合统计的问题

原文:https://towardsdatascience.com/customer-behavior-modeling-the-problem-with-aggregate-statistics-be369d95bcaa?source=collection_archive---------28-----------------------

使用综合统计数据来判断客户行为模型的强度不是一个好主意

作为一名数据科学家,我花了相当多的时间思考客户终身价值(CLV)以及如何对其建模。一个强大的 CLV 模型实际上是一个强大的客户行为模型——你越能预测下一步行动,你就能越好地量化 CLV。

在这篇文章中,我希望通过一个玩具和现实世界的例子来证明,为什么使用综合统计来判断客户行为模型的强度是一个坏主意

相反,最好的 CLV 模型是在个体层面上有最强预测的模型。探索客户生命周期价值的数据科学家应该主要,也可能是唯一,使用个人层面的指标来充分理解 CLV 模型的优势和劣势。

CLV 模型本质上是猜测一个人在你店里购物的频率以及他们会花多少钱。rupixen.com 在 Unsplash拍照

第 1 章什么是 CLV,为什么它很重要?

虽然这是为数据科学家准备的,但我想说明本文的业务分支,因为理解业务需求将告知我为什么持有某些观点,以及为什么对我们所有人来说掌握好的 CLV 模型的额外好处是重要的。

CLV:顾客将来会花多少钱

CLV 是一个商业关键绩效指标,在过去的几年里,它的受欢迎程度激增。原因是显而易见的:如果你的公司能够准确预测客户在未来几个月或几年的花费,你就可以根据预算调整他们的体验。从市场营销到客户服务,再到整体商业战略,这都有着巨大的应用空间。

以下是“精确 CLV”可以帮助实现的业务应用的快速列表:

  • 营销受众生成
  • 断代分析
  • 客户服务票订购
  • 营销提升分析
  • CAC 投标封顶营销
  • 折扣活动
  • VIP 购买体验
  • 忠诚度计划
  • 分割
  • 董事会报告

还有很多,这些只是我想到最快的。

伟大的数字营销源于对客户的深刻理解。活动创建者Unsplash 上的照片

有如此多的商业计划处于危险之中,精通技术的公司正忙于寻找哪种模式最能抓住他们客户群的 CLV。最流行和最常用的客户终身价值模型使用总收入百分比误差(ARPE)等统计数据,根据总指标来衡量它们的实力。我之所以知道这一点,是因为我的许多客户已经用汇总统计数据将他们的内部 CLV 模型与我的模型进行了比较。

我认为这是一个严重的错误。

下面的两个例子,一个是玩具,一个是真实的,将有望展示总体统计数据是如何把我们引入歧途,并隐藏在个体水平上非常明显的模型缺陷的。这是特别有先见之明的,因为大多数业务用例在个体层面上需要一个强大的 CLV 模型,而不仅仅是在集合层面上。

第二章一个玩具例子

当你依赖于总体指标而忽略个体层面的不准确性时,你就错过了很大一部分技术叙述。考虑以下 4 个客户及其 1 年 CLV 的示例:

这个示例包括高、低、中 CLV 客户,以及一个不满意的客户,为智能模型创建了一个很好的分布来捕获。

现在,考虑以下验证指标:

  1. MAE :平均绝对误差(预测之间的平均差异)

  2. ARPE :总收入百分比误差(总收入和预测收入之间的总体差异)

MAE 是在客户层面上,而 ARPE 又是一个聚合统计。这些验证指标的值越低越好。

这个例子将展示一个集合统计如何掩盖低质量模型的缺点。

要做到这一点,可以将一个虚拟的平均值猜测与 CLV 模型进行比较,两者相差 20%。

模型 1:假人

虚拟模型只会猜测每个顾客 40 美元。

车型二:CLV 车型

该模型试图在客户层面做出准确的模型预测。

我们可以使用这些数字来计算三个验证指标。

这个例子说明了一个总体上相当差的模型(CLV 模型差 20%以上)在个体层面上实际上是更好的。

为了让这个例子更好,让我们给预测添加一些噪声。

# Dummy Sampling:
# randomly sampling a normal dist around $40 with a SD of $5np.random.normal (40,5,4)OUT: (44.88, 40.63, 40.35, 42.16)#CLV Sampling:
# randomly sampling a normal dist around answer with a SD of $15
max (0, np.random.normal (0,15)),
max (0, np.random.normal (10, 15)),
max (0, np.random.normal (50,15)),
max  (0, np.random.normal (100, 15))OUT: (0, 17.48, 37.45, 81.41)

上面的结果表明,即使一个人的统计数据比你希望的百分比高,这些 CLV 数的分布也更符合我们所寻找的:一个区分高 CLV 客户和低 CLV 客户的模型。如果你只看 CLV 模型的综合指标,你就错过了故事的主要部分,你可能最终为你的企业选择了错误的模型。

但是,即使汇总一个在个人层面上计算的误差指标,比如 MAE 或 MAPE 等替代指标,也可能隐藏关于你的模型的优点和缺点的关键信息。主要是,其创建 CLV 分数的精确分布的能力。

为了进一步探讨这个问题,让我们来看一个更现实的例子

第三章一个真实的例子

恭喜你!你,读者,被我刚刚虚构的电子商务公司 BottleRocket Brewing Co 聘为数据科学家。(我们将使用的数据基于我为这篇文章挑选的一家真实的电子商务公司)

有趣(虚假)的事实:BottleRocket Brewing 在加州是一个相当受欢迎的品牌。照片由海伦娜·洛佩斯Unsplash 拍摄

作为数据科学家,您的首要任务是:为 BottleRocket 的业务选择最佳的 CLV 模型…

……但是“最好”是什么意思呢?

但你没有被吓住,你用以下模型做了一个实验:

  1. 帕累托/NBD 模型(PNBD)

帕累托/NBD 模型是一个非常受欢迎的选择,也是当今大多数数据驱动的 CLV 预测的模型。引用文档:

1987 年推出的帕累托/NBD 模型将活跃客户交易的[负二项分布]与异质退出过程结合在一起,至今仍被认为是购买直到死亡模型的黄金标准 【链接】

但另一方面,该模型学习两种分布,一种是流失概率,另一种是交易时间间隔(ITT),并通过从这些分布中取样来进行 CLV 预测。

**用更多的技术细节描述 BTYD 模型有点超出了本文的范围,本文主要讨论错误度量。如果你对关于 BTYD 模型的更深入的文章感兴趣,请发表评论,我很乐意写一篇后续文章!更新:查看我关于 BTYD 车型的文章 **

2。梯度增压机(GBM)

梯度增强机器模型是一种流行的机器学习模型,其中弱树被训练和组装在一起以形成强的整体分类器。

**与 BTYD 模型一样,我不会详细介绍 GBM 是如何工作的,但是如果您想让我写一些关于方法/模型的东西,请在下面再次发表评论

3。虚拟 CLV

这个模型被简单地定义为:

Calculate the average ITT for the business
Calculate the average spend over 1yrIf someone has not bought within 2x the average purchase time:
    Predict $0
Else:
    Predict the average 1y spend

4。非常哑的假人模型(Avg 假人)

该模型仅猜测所有客户超过 1 年的平均支出。包括作为模型性能的基线

第 3.1 章汇总指标

我们可以将所有这些模型的预测整合到一个漂亮的小熊猫数据框架“combined_result_pdf”中,如下所示:

combined_result_pdf.head()

给定这个客户表,我们可以使用下面的代码计算误差指标:

from sklearn.metrics import mean_absolute_erroractual = combined_result_pdf['actual']
rev_actual = sum(actual)for col in combined_result_pdf.columns:
    if col in ['customer_id', 'actual']:
        continue
    pred = combined_result_pdf[col]
    mae = mean_absolute_error(y_true=actual, y_pred=pred)
    print(col + ": ${:,.2f}".format(mae))

    rev_pred = sum(pred)
    perc = 100*rev_pred/rev_actual
    print(col + ": ${:,} total spend ({:.2f}%)".format(pred, perc))

通过这四个模型,我们尝试预测瓶装旧酒客户的 1 年 CLV,按 MAE 评分排序:

这张表格中有一些有趣的见解:

  1. GBM 似乎是 CLV 的最佳模式
  2. PNBD,尽管是一个受欢迎的 CLV,似乎是最糟糕的。事实上,它比一个简单的 if/else 规则列表更糟糕,只比一个只猜测平均值的模型稍微好一点!
  3. 尽管 GBM 是最好的,但它只比虚拟的 if/else 规则列表模型好几个美元

如果数据科学家/客户接受的话,第三点特别有意思。如果这些结果的解释者真的认为一个简单的 if/else 模型可以捕捉 GBM 可以捕捉的几乎所有复杂性,并且比常用的 PNBD 模型更好,那么一旦成本、训练速度和可解释性都被考虑在内,显然“最佳”模型将是虚拟 CLV。

这让我们回到了最初的主张——,即总体误差指标,即使是在个体层面上计算的,也会掩盖模型的一些缺点。为了证明这一点,让我们将数据框架重新加工成混淆矩阵。

统计数据有时非常令人困惑。对于混淆矩阵,它们是字面上的混淆。照片由内森·杜姆劳Unsplash 上拍摄

迷你章:什么是混淆矩阵?

单从它的名字来看,理解一个混乱矩阵听起来令人困惑&具有挑战性。但是理解这篇文章中的观点是至关重要的,也是添加到您的数据科学工具包中的一个强大工具。

一个混淆矩阵是一个表格,它概括了分类的准确性,以及模型常见的错误分类。一个简单的混淆矩阵可能如下所示:

上面混淆矩阵的对角线,突出显示的绿色,反映了正确的预测——当它实际上是一只猫的时候预测它是一只猫,等等。这些行的总和将达到 100%,这使我们能够很好地了解我们的模型捕捉回忆行为的情况,或者我们的模型在给定特定标签的情况下正确猜测的概率。

从上面的混淆矩阵中我们还可以看出..

  1. 在给定真实标签为猫的情况下,该模型在预测猫方面表现出色(猫召回率为 90%)
  2. 这个模型很难区分狗和猫,经常把狗误认为猫。这是模型最常犯的错误。
  3. 虽然有时会把猫误认为狗,但这远没有其他错误常见

记住这一点,让我们探索我们的 CLV 模型如何使用混淆矩阵捕捉客户行为。一个强大的模型应该能够正确地将低价值客户和高价值客户进行分类。我更喜欢这种可视化的方法,而不是像 CLV 分数直方图那样的东西,因为它揭示了建模分布的哪些元素是强的和弱的。

为此,我们将把货币价值预测转换为低、中、高和最佳的量化 CLV 预测。这些将从每个模型预测生成的分位数中提取。

最佳模型将正确地将客户分为低/中/高/最佳这四类。因此每个模型我们将制作一个如下结构的混淆矩阵:

并且最佳模型将具有落在该对角线内的最多数量的预测。

Ch。3.2 各项指标

这些混淆矩阵可以用下面的代码片段从我们的 Pandas DF 中生成:

from sklearn.metrics import confusion_matrix
import matplotlib.patches as patches
import matplotlib.colors as colors# Helper function to get quantiles
def get_quant_list(vals, quants):
    actual_quants = []

    for val in vals:
        if val > quants[2]:
            actual_quants.append(4)
        elif val > quants[1]:
            actual_quants.append(3)
        elif val > quants[0]:
            actual_quants.append(2)
        else:
            actual_quants.append(1)
    return(actual_quants)# Create Plot
fig, axes = plt.subplots(nrows=int(num_plots/2)+(num_plots%2),ncols=2, figsize=(10,5*(num_plots/2)+1))fig.tight_layout(pad=6.0)
tick_marks = np.arange(len(class_names))
plt.setp(axes, xticks=tick_marks, xticklabels=class_names, yticks=tick_marks, yticklabels=class_names)# Pick colors
cmap = plt.get_cmap('Greens')# Generate Quant Labels
plt_num = 0
for col in combined_result_pdf.columns:
    if col in ['customer_id', 'actual']:
        continue
    quants = combined_result_pdf[col]quantile(q=[0.25,0.5,0.75])
    pred = combined_result_pdf[col]
    pred_quants = get_quant_list(pred,quants)

    # Generate Conf Matrix
    cm = confusion_matrix(y_true=actual_quants, y_pred=pred_quants)
    ax = axes.flatten()[plt_num]
    accuracy = np.trace(cm) / float(np.sum(cm))
    misclass = 1 - accuracy
     # Clean up CM code
    cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] *100
    ax.imshow(cm, interpolation='nearest', cmap=cmap)
    ax.set_title('{} Bucketting'.format(col))
    thresh = cm.max() / 1.5

    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): ax.text(j, i, "{:.0f}%".format(cm[i, j]), horizontalalignment="center", color="white" if cm[i, j] > thresh else "black")

    # Clean Up Chart
    ax.set_ylabel('True label')
    ax.set_xlabel('Predicted label')
    ax.set_title('{}\naccuracy={:.0f}%'.format(col,100*accuracy))
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.spines['bottom'].set_visible(False)
    ax.spines['left'].set_visible(False)
    for i in [-0.5,0.5,1.5,2.5]:
        ax.add_patch(patches.Rectangle((i,i),
        1,1,linewidth=2,edgecolor='k',facecolor='none')) plt_num += 1

这会生成以下图表:

图表的颜色表示某个预测/实际分类的集中程度——绿色越深,落入该方块的示例越多。

与上面讨论的混淆矩阵示例一样,对角线(用黑线突出显示)表示客户的适当分类。

第 3.3 章:分析

假人模特(第一排)

Dummy1 ,每次只预测平均值,分布只有平均值。它没有区分高价值客户和低价值客户。

稍微好一点的是, Dummy2 要么预测 0 美元,要么预测平均值。这意味着它可以对分销提出一些要求,事实上,分别获得 81%的最低价值客户和 98%的最高价值客户。

但是这些模型的主要问题是,当涉及到区分客户群时,这些模型没有什么复杂性,这一点在研究 MAE 时并不明显(但是如果你知道它们的标签是如何生成的,这一点就很明显了)。对于第 1 章中列出的所有业务应用程序,这是构建一个强大的 CLV 模型的全部要点,区分客户类型是成功的关键

CLV 车型(底排)

首先,不要让整体的准确性吓到你。同样,我们可以通过汇总统计数据来隐藏事实,我们也可以通过推出的准确性度量来隐藏分布建模的强度。

其次,与上表相反,从这张图中可以很清楚地看出,虚拟模型如此命名是有原因的——这些第二排模型实际上是在捕捉一个分布。即使 Dummy2 捕获了更高比例的低价值客户,这也可能是长尾 CLV 分布的产物。很明显,这些是你想要选择的模型。

看对角线,我们可以看到 GBM 在预测大多数类别方面都有重大改进。主要的错误标注——少了两个方格——大大减少了。GBM 方面最大的增长是对中等水平客户的认可,这是一个很好的迹象,表明分布是健康的,我们的预测是现实的。

Ch4。结尾

如果你只是浏览了这篇文章,你可能会认为 GBM 是一个更好的 CLV 模型。这可能是真的,但模型选择更复杂。您可能想问的一些问题:

  • 我想预测未来很多年吗?
  • 我想预测客户流失吗?
  • 我想预测交易的数量吗?
  • 我有足够的数据来运行监督模型吗?
  • 我在乎可解释性吗?

虽然这些问题与本文的主题无关,但是在将您的模型换成 GBM 之前,需要回答这些问题。

选择正确的模型需要对您的业务和用例有深刻的理解。由布雷特·乔丹Unsplash 上拍摄的照片

选择模型时要考虑的第一个基本变量是您正在处理的公司数据。通常 BTYD 模型工作良好,并可与 ML 替代方案相媲美。但是 BTYD 模型对客户行为做了一些强有力的假设,所以如果这些假设被打破,它们的表现就不是最优的。进行模型比较对于做出正确的模型决策至关重要。

虽然个体层面的问题对于虚拟模型来说是显而易见的,但公司通常会通过运行“幼稚的”/“简单的”/“基于 excel 的”模型来做这件事,从而成为这些问题的牺牲品,即尝试在您的整个客户群中应用一个聚合数字。在一些公司,CLV 可以简单地定义为将收入平均分配给所有客户。这可能适用于一两份董事会报告,但实际上,这并不是计算如此复杂数字的适当方法。事实是,并非所有的客户都是平等的,你的公司越早将注意力从总体客户指标转移到强有力的个人层面预测,你就能越有效地营销、制定战略并最终找到你的最佳客户。

希望这本书读起来和写起来一样令人愉快,内容丰富。

感谢阅读!

客户案例研究:使用 AssemblyAI 在 PyTorch 中构建端到端语音识别模型

原文:https://towardsdatascience.com/customer-case-study-building-an-end-to-end-speech-recognition-model-in-pytorch-with-assemblyai-473030e47c7c?source=collection_archive---------36-----------------------

本文由assembly ai的机器学习研究工程师 Michael Nguyen 和comet . ml的 Niko Laskaris 撰写。AssemblyAI 使用 Comet 来记录、可视化和理解他们的模型开发管道。

随着端到端模型的引入,深度学习改变了语音识别领域的游戏。这些模型接收音频,并直接输出转录。目前最流行的两种端到端模型是百度的 Deep Speech 和谷歌的 Listen accept Spell(LAS)。深度语音和 LAS 都是基于递归神经网络(RNN)的架构,具有不同的建模语音识别的方法。深度语音使用连接主义者时间分类(CTC)损失函数来预测语音转录本。LAS 使用序列对网络体系结构进行序列预测。

这些模型通过利用深度学习系统从大型数据集学习的能力,简化了语音识别管道。有了足够的数据,从理论上讲,你应该能够建立一个超级健壮的语音识别模型,它可以考虑语音中的所有细微差别,而不必花费大量的时间和精力手工设计声学特征,或者处理更老式的 GMM-HMM 模型架构中的复杂管道。

深度学习是一个快速发展的领域,深度语音和 LAS 风格的架构已经很快过时了。你可以在下面的最新进展部分了解该行业的发展方向。

如何在 PyTorch 中构建自己的端到端语音识别模型

让我们看看如何在 PyTorch 中构建自己的端到端语音识别模型。我们将构建的模型受到 Deep Speech 2(百度对其著名模型的第二次修订)的启发,并对架构进行了一些个人改进。该模型的输出将是字符的概率矩阵,我们将使用该概率矩阵来解码音频中最有可能说出的字符。你可以在谷歌联合实验室找到完整的代码,也可以在 GPU 的支持下运行它。

准备数据管道

数据是语音识别最重要的方面之一。我们将原始音频波转换成 Mel 光谱图。

你可以从这篇精彩的文章这里阅读更多关于这一转变的细节。在这篇文章中,你可以把 Mel 声谱图想象成声音的图像。

为了处理音频数据,我们将使用一个名为 torchaudio 的非常有用的工具,这是 PyTorch 团队专门为音频数据构建的库。我们将在 LibriSpeech 的子集上进行训练,这是一个从有声读物中获得的阅读英语语音数据的语料库,包括 100 个小时的转录音频数据。您可以使用 torchaudio 轻松下载该数据集:

import torchaudio train_dataset = torchaudio.datasets.LIBRISPEECH("./", url="train-clean-100", download=True) 
test_dataset = torchaudio.datasets.LIBRISPEECH("./", url="test-clean", download=True)

数据集的每个样本都包含波形、音频的采样率、话语/标签以及关于样本的更多元数据。你可以从源代码这里查看每个样本的样子。

数据扩充— SpecAugment

数据扩充是一种用于人为增加数据集多样性以增加数据集大小的技术。当数据不足或模型过拟合时,这种策略尤其有用。对于语音识别,您可以使用标准的增强技术,如改变音调、速度、注入噪声以及给音频数据添加混响。

我们发现谱图增强(SpecAugment)是一种更简单、更有效的方法。SpecAugment 在论文中首次介绍:SpecAugment:一种用于自动语音识别的简单数据扩充方法,其中作者发现,简单地剪切连续时间和频率维度的随机块显著提高了模型的泛化能力!

在 PyTorch 中,您可以使用 torchaudio 功能 FrequencyMasking 屏蔽频率维度,使用 TimeMasking 屏蔽时间维度。

torchaudio.transforms.FrequencyMasking()
torchaudio.transforms.TimeMasking()

现在我们有了数据,我们需要将音频转换成 Mel 频谱图,并将每个音频样本的字符标签映射成整数标签:

class TextTransform:
    """Maps characters to integers and vice versa"""
    def __init__(self):
        char_map_str = """
        ' 0
        <SPACE> 1
        a 2
        b 3
        c 4
        d 5
        e 6
        f 7
        g 8
        h 9
        i 10
        j 11
        k 12
        l 13
        m 14
        n 15
        o 16
        p 17
        q 18
        r 19
        s 20
        t 21
        u 22
        v 23
        w 24
        x 25
        y 26
        z 27
        """
        self.char_map = {}
        self.index_map = {}
        for line in char_map_str.strip().split('\n'):
            ch, index = line.split()
            self.char_map[ch] = int(index)
            self.index_map[int(index)] = ch
        self.index_map[1] = ' 'def text_to_int(self, text):
        """ Use a character map and convert text to an integer sequence """
        int_sequence = []
        for c in text:
            if c == ' ':
                ch = self.char_map['']
            else:
                ch = self.char_map[c]
            int_sequence.append(ch)
        return int_sequencedef int_to_text(self, labels):
        """ Use a character map and convert integer labels to an text sequence """
        string = []
        for i in labels:
            string.append(self.index_map[i])
        return ''.join(string).replace('', ' ')train_audio_transforms = nn.Sequential(
    torchaudio.transforms.MelSpectrogram(sample_rate=16000, n_mels=128),
    torchaudio.transforms.FrequencyMasking(freq_mask_param=15),
    torchaudio.transforms.TimeMasking(time_mask_param=35)
)valid_audio_transforms = torchaudio.transforms.MelSpectrogram()text_transform = TextTransform()def data_processing(data, data_type="train"):
    spectrograms = []
    labels = []
    input_lengths = []
    label_lengths = []
    for (waveform, _, utterance, _, _, _) in data:
        if data_type == 'train':
            spec = train_audio_transforms(waveform).squeeze(0).transpose(0, 1)
        else:
            spec = valid_audio_transforms(waveform).squeeze(0).transpose(0, 1)
        spectrograms.append(spec)
        label = torch.Tensor(text_transform.text_to_int(utterance.lower()))
        labels.append(label)
        input_lengths.append(spec.shape[0]//2)
        label_lengths.append(len(label))spectrograms = nn.utils.rnn.pad_sequence(spectrograms, batch_first=True).unsqueeze(1).transpose(2, 3)
    labels = nn.utils.rnn.pad_sequence(labels, batch_first=True)return spectrograms, labels, input_lengths, label_lengths

定义模型—深度演讲 2(但更好)

我们的模型将类似于 Deep Speech 2 架构。该模型将具有两个主要的神经网络模块——N 层残差卷积神经网络(ResCNN)来学习相关的音频特征,以及一组双向递归神经网络(BiRNN)来利用学习到的 ResCNN 音频特征。该模型以一个完全连接的层结束,该层用于在每个时间步长对角色进行分类。

卷积神经网络(CNN)擅长提取抽象特征,我们将把同样的特征提取能力应用于音频频谱图。我们选择使用残留的 CNN 层,而不是普通的 CNN 层。残差连接(又名跳过连接)首次在论文图像识别的深度残差学习中介绍,作者发现,如果你将这些连接添加到 CNN 中,你可以建立具有良好精度增益的真正深度网络。添加这些剩余连接也有助于模型更快地学习和更好地概括。论文可视化神经网络的损失景观表明,具有剩余连接的网络具有“更平坦”的损失表面,使模型更容易浏览损失景观,并找到更低和更可概括的最小值。

递归神经网络(RNN)天生擅长序列建模问题。RNN 一步一步地处理音频特征,对每一帧进行预测,同时使用前一帧的上下文。我们使用 BiRNN 是因为我们不仅想要每一步之前的帧的上下文,还想要每一步之后的帧的上下文。这可以帮助模型做出更好的预测,因为在做出预测之前,音频中的每一帧都将具有更多信息。我们使用 RNN 的门控循环单元(GRU 的)变体,因为它比 LSTM 的需要更少的计算资源,并且在某些情况下工作得一样好。

该模型输出字符的概率矩阵,我们将使用该矩阵输入到我们的解码器中,以提取模型认为最有可能说出的字符。

class CNNLayerNorm(nn.Module):
    """Layer normalization built for cnns input"""
    def __init__(self, n_feats):
        super(CNNLayerNorm, self).__init__()
        self.layer_norm = nn.LayerNorm(n_feats)def forward(self, x):
        # x (batch, channel, feature, time)
        x = x.transpose(2, 3).contiguous() # (batch, channel, time, feature)
        x = self.layer_norm(x)
        return x.transpose(2, 3).contiguous() # (batch, channel, feature, time)class ResidualCNN(nn.Module):
    """Residual CNN inspired by [https://arxiv.org/pdf/1603.05027.pdf](https://arxiv.org/pdf/1603.05027.pdf)
        except with layer norm instead of batch norm
    """
    def __init__(self, in_channels, out_channels, kernel, stride, dropout, n_feats):
        super(ResidualCNN, self).__init__()self.cnn1 = nn.Conv2d(in_channels, out_channels, kernel, stride, padding=kernel//2)
        self.cnn2 = nn.Conv2d(out_channels, out_channels, kernel, stride, padding=kernel//2)
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)
        self.layer_norm1 = CNNLayerNorm(n_feats)
        self.layer_norm2 = CNNLayerNorm(n_feats)def forward(self, x):
        residual = x  # (batch, channel, feature, time)
        x = self.layer_norm1(x)
        x = F.gelu(x)
        x = self.dropout1(x)
        x = self.cnn1(x)
        x = self.layer_norm2(x)
        x = F.gelu(x)
        x = self.dropout2(x)
        x = self.cnn2(x)
        x += residual
        return x # (batch, channel, feature, time)class BidirectionalGRU(nn.Module):def __init__(self, rnn_dim, hidden_size, dropout, batch_first):
        super(BidirectionalGRU, self).__init__()self.BiGRU = nn.GRU(
            input_size=rnn_dim, hidden_size=hidden_size,
            num_layers=1, batch_first=batch_first, bidirectional=True)
        self.layer_norm = nn.LayerNorm(rnn_dim)
        self.dropout = nn.Dropout(dropout)def forward(self, x):
        x = self.layer_norm(x)
        x = F.gelu(x)
        x, _ = self.BiGRU(x)
        x = self.dropout(x)
        return xclass SpeechRecognitionModel(nn.Module):
    """Speech Recognition Model Inspired by DeepSpeech 2"""def __init__(self, n_cnn_layers, n_rnn_layers, rnn_dim, n_class, n_feats, stride=2, dropout=0.1):
        super(SpeechRecognitionModel, self).__init__()
        n_feats = n_feats//2
        self.cnn = nn.Conv2d(1, 32, 3, stride=stride, padding=3//2)  # cnn for extracting heirachal features# n residual cnn layers with filter size of 32
        self.rescnn_layers = nn.Sequential(*[
            ResidualCNN(32, 32, kernel=3, stride=1, dropout=dropout, n_feats=n_feats) 
            for _ in range(n_cnn_layers)
        ])
        self.fully_connected = nn.Linear(n_feats*32, rnn_dim)
        self.birnn_layers = nn.Sequential(*[
            BidirectionalGRU(rnn_dim=rnn_dim if i==0 else rnn_dim*2,
                             hidden_size=rnn_dim, dropout=dropout, batch_first=i==0)
            for i in range(n_rnn_layers)
        ])
        self.classifier = nn.Sequential(
            nn.Linear(rnn_dim*2, rnn_dim),  # birnn returns rnn_dim*2
            nn.GELU(),
            nn.Dropout(dropout),
            nn.Linear(rnn_dim, n_class)
        )def forward(self, x):
        x = self.cnn(x)
        x = self.rescnn_layers(x)
        sizes = x.size()
        x = x.view(sizes[0], sizes[1] * sizes[2], sizes[3])  # (batch, feature, time)
        x = x.transpose(1, 2) # (batch, time, feature)
        x = self.fully_connected(x)
        x = self.birnn_layers(x)
        x = self.classifier(x)
        return x

选择合适的优化器和调度器——AdamW 具有超强的融合能力

优化器和学习率计划在让我们的模型收敛到最佳点方面起着非常重要的作用。选择正确的优化器和调度器还可以节省您的计算时间,并帮助您的模型更好地推广到现实世界的用例。对于我们的模型,我们将使用 AdamW单周期学习率调度器Adam 是一个广泛使用的优化器,它可以帮助你的模型更快地收敛,从而节省计算时间,但它因不能像随机梯度下降又名 SGD 一样泛化而臭名昭著。

AdamW 首次在解耦权重衰减正则化中引入,被认为是对 Adam 的“修正”。论文指出,最初的 Adam 算法有一个错误的权重衰减实现,AdamW 试图修复这个错误。这个修正有助于解决亚当的泛化问题。

单周期学习率调度器首次在论文中介绍:超收敛:使用大学习率非常快速地训练神经网络。这篇论文表明,使用一个简单的技巧,你可以训练神经网络的速度提高一个数量级,同时保持它们的泛化能力。你从一个低的学习速率开始,升温到一个大的最大学习速率,然后线性衰减到你最初开始的同一点。

因为最大学习率比最小学习率高很多,所以您也获得了一些正则化的好处,这有助于您的模型在数据集较少的情况下更好地进行概化。

对于 PyTorch,这两个方法已经是包的一部分了。

optimizer = optim.AdamW(model.parameters(), hparams['learning_rate'])
scheduler = optim.lr_scheduler.OneCycleLR(optimizer,
	max_lr=hparams['learning_rate'],
	steps_per_epoch=int(len(train_loader)),
	epochs=hparams['epochs'],
	anneal_strategy='linear')

CTC 丢失功能—将音频与抄本对齐

我们的模型将被训练来预测我们馈入模型的声谱图中每一帧(即时间步长)字母表中所有字符的概率分布。

图片取自 distill.pub

传统的语音识别模型会要求你在训练之前将抄本文本与音频对齐,并且该模型会被训练来预测特定帧处的特定标签。

CTC 丢失功能的创新之处在于它允许我们跳过这一步。我们的模型将在训练过程中学习对齐脚本本身。这其中的关键是由 CTC 引入的“空白”标签,它使模型能够说某个音频帧没有产生一个字符。你可以从这篇精彩的帖子中看到关于 CTC 及其工作原理的更详细的解释。

PyTorch 还内置了 CTC 丢失功能。

criterion = nn.CTCLoss(blank=28).to(device)

评估你的语音模型

在评估您的语音识别模型时,行业标准使用单词错误率(WER)作为度量标准。单词错误率确实如其所言——它获取模型输出的转录和真实转录,并测量它们之间的错误。你可以在这里看到这是如何实现的。另一个有用的指标叫做字符错误率(CER)。CER 测量模型输出和真实标签之间的字符误差。这些指标有助于衡量模型的性能。

对于本教程,我们将使用“贪婪”解码方法将模型的输出处理成字符,这些字符可以组合起来创建副本。“贪婪”解码器接收模型输出,该模型输出是字符的 softmax 概率矩阵,并且对于每个时间步长(谱图帧),它选择具有最高概率的标签。如果标签是空白标签,我们会将其从最终抄本中删除。

def GreedyDecoder(output, labels, label_lengths, blank_label=28, collapse_repeated=True):
    arg_maxes = torch.argmax(output, dim=2)
    decodes = []
    targets = []
    for i, args in enumerate(arg_maxes):
        decode = []
        targets.append(text_transform.int_to_text(labels[i][:label_lengths[i]].tolist()))
        for j, index in enumerate(args):
            if index != blank_label:
                if collapse_repeated and j != 0 and index == args[j -1]:
                    continue
                decode.append(index.item())
        decodes.append(text_transform.int_to_text(decode))
    return decodes, targets

使用 Comet.ml 训练和监控您的实验

Comet.ml 提供了一个平台,允许深度学习研究人员跟踪、比较、解释和优化他们的实验和模型。Comet.ml 提高了我们在 AssemblyAI 的工作效率,我们强烈推荐团队使用这个平台进行任何类型的数据科学实验。Comet.ml 设置起来超级简单。只需几行代码就能完成。

# initialize experiment object
experiment = Experiment(api_key=comet_api_key, project_name=project_name)
experiment.set_name(exp_name)# track metrics
experiment.log_metric('loss', loss.item())

Comet.ml 为您提供了一个非常高效的仪表盘,您可以在其中查看和跟踪模型的进度。

您可以使用 Comet 来跟踪度量、代码、超级参数、您的模型的图表,以及其他许多东西!Comet 提供的一个非常方便的特性是能够将您的实验与许多其他实验进行比较。

Comet 有丰富的特性集,我们不会在这里一一介绍,但是我们强烈建议使用它来提高生产率和健全性。

这是我们培训脚本的其余部分。

class IterMeter(object):
    """keeps track of total iterations"""
    def __init__(self):
        self.val = 0def step(self):
        self.val += 1def get(self):
        return self.valdef train(model, device, train_loader, criterion, optimizer, scheduler, epoch, iter_meter, experiment):
    model.train()
    data_len = len(train_loader.dataset)
    with experiment.train():
        for batch_idx, _data in enumerate(train_loader):
            spectrograms, labels, input_lengths, label_lengths = _data 
            spectrograms, labels = spectrograms.to(device), labels.to(device)optimizer.zero_grad()output = model(spectrograms)  # (batch, time, n_class)
            output = F.log_softmax(output, dim=2)
            output = output.transpose(0, 1) # (time, batch, n_class)loss = criterion(output, labels, input_lengths, label_lengths)
            loss.backward()experiment.log_metric('loss', loss.item(), step=iter_meter.get())
            experiment.log_metric('learning_rate', scheduler.get_lr(), step=iter_meter.get())optimizer.step()
            scheduler.step()
            iter_meter.step()
            if batch_idx % 100 == 0 or batch_idx == data_len:
                print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                    epoch, batch_idx * len(spectrograms), data_len,
                    100\. * batch_idx / len(train_loader), loss.item()))def test(model, device, test_loader, criterion, epoch, iter_meter, experiment):
    print('\nevaluating…')
    model.eval()
    test_loss = 0
    test_cer, test_wer = [], []
    with experiment.test():
        with torch.no_grad():
            for I, _data in enumerate(test_loader):
                spectrograms, labels, input_lengths, label_lengths = _data 
                spectrograms, labels = spectrograms.to(device), labels.to(device)output = model(spectrograms)  # (batch, time, n_class)
                output = F.log_softmax(output, dim=2)
                output = output.transpose(0, 1) # (time, batch, n_class)loss = criterion(output, labels, input_lengths, label_lengths)
                test_loss += loss.item() / len(test_loader)decoded_preds, decoded_targets = GreedyDecoder(output.transpose(0, 1), labels, label_lengths)
                for j in range(len(decoded_preds)):
                    test_cer.append(cer(decoded_targets[j], decoded_preds[j]))
                    test_wer.append(wer(decoded_targets[j], decoded_preds[j]))avg_cer = sum(test_cer)/len(test_cer)
    avg_wer = sum(test_wer)/len(test_wer)
    experiment.log_metric('test_loss', test_loss, step=iter_meter.get())
    experiment.log_metric('cer', avg_cer, step=iter_meter.get())
    experiment.log_metric('wer', avg_wer, step=iter_meter.get())print('Test set: Average loss: {:.4f}, Average CER: {:4f} Average WER: {:.4f}\n'.format(test_loss, avg_cer, avg_wer))def main(learning_rate=5e-4, batch_size=20, epochs=10,
        train_url="train-clean-100", test_url="test-clean",
        experiment=Experiment(api_key='dummy_key', disabled=True)):hparams = {
        "n_cnn_layers": 3,
        "n_rnn_layers": 5,
        "rnn_dim": 512,
        "n_class": 29,
        "n_feats": 128,
        "stride": 2,
        "dropout": 0.1,
        "learning_rate": learning_rate,
        "batch_size": batch_size,
        "epochs": epochs
    }experiment.log_parameters(hparams)use_cuda = torch.cuda.is_available()
    torch.manual_seed(7)
    device = torch.device("cuda" if use_cuda else "cpu")if not os.path.isdir("./data"):
        os.makedirs("./data")train_dataset = torchaudio.datasets.LIBRISPEECH("./data", url=train_url, download=True)
    test_dataset = torchaudio.datasets.LIBRISPEECH("./data", url=test_url, download=True)kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}
    train_loader = data.DataLoader(dataset=train_dataset,
                                batch_size=hparams['batch_size'],
                                shuffle=True,
                                collate_fn=lambda x: data_processing(x, 'train'),
                                **kwargs)
    test_loader = data.DataLoader(dataset=test_dataset,
                                batch_size=hparams['batch_size'],
                                shuffle=False,
                                collate_fn=lambda x: data_processing(x, 'valid'),
                                **kwargs)model = SpeechRecognitionModel(
        hparams['n_cnn_layers'], hparams['n_rnn_layers'], hparams['rnn_dim'],
        hparams['n_class'], hparams['n_feats'], hparams['stride'], hparams['dropout']
        ).to(device)print(model)
    print('Num Model Parameters', sum([param.nelement() for param in model.parameters()]))optimizer = optim.AdamW(model.parameters(), hparams['learning_rate'])
    criterion = nn.CTCLoss(blank=28).to(device)
    scheduler = optim.lr_scheduler.OneCycleLR(optimizer, max_lr=hparams['learning_rate'], 
                                            steps_per_epoch=int(len(train_loader)),
                                            epochs=hparams['epochs'],
                                            anneal_strategy='linear')iter_meter = IterMeter()
    for epoch in range(1, epochs + 1):
        train(model, device, train_loader, criterion, optimizer, scheduler, epoch, iter_meter, experiment)
        test(model, device, test_loader, criterion, epoch, iter_meter, experiment)

训练功能根据完整的数据时段训练模型。测试功能在每个时期后根据测试数据评估模型。获取模型的 test_loss 以及 cerwer 。您现在可以在 Google 联合实验室的 GPU 支持下开始运行训练脚本。

如何提高准确率

语音识别需要大量的数据和计算资源。展示的示例是在 LibriSpeech (100 小时的音频)的子集和单个 GPU 上训练的。为了获得最先进的结果,你需要对分布在许多机器上的数十个 GPU 上的数千小时的数据进行分布式训练。

另一种大幅提高精度的方法是使用语言模型和 CTC 波束搜索算法解码 CTC 概率矩阵。CTC 类型的模型非常依赖于这个解码过程来获得好的结果。幸运的是,有一个方便的开源库可以让你这么做。

本教程更容易理解,因此与 BERT(3.4 亿个参数)相比,它是一个相对较小的模型(2300 万个参数)。看起来你的网络越大,它的表现就越好,尽管回报是递减的。然而,正如 OpenAI 的研究 Deep Double Descent 所证明的那样,更大的模型等同于更好的性能并不总是如此。

这个模型有 3 个剩余的 CNN 层和 5 个双向 GRU 层,这应该允许您在一个至少有 11GB 内存的 GPU 上训练一个合理的批量大小。您可以调整 main 函数中的一些 hyper 参数,以根据您的用例和计算可用性来减少或增加模型大小。

深度学习语音识别的最新进展

深度学习是一个快速发展的领域。似乎你不能一个星期没有一些新的技术得到最先进的结果。在语音识别的世界里,这里有一些值得探索的东西。

变形金刚(电影名)

变形金刚席卷了自然语言处理世界!在论文中首先介绍的是,变形金刚已经被采用和修改来击败几乎所有现存的 NLP 任务,淘汰 RNN 的类型架构。转换器看到序列数据的完整上下文的能力也可以转换成语音。

无监督预训练

如果你密切关注深度学习,你可能听说过伯特、GPT 和 GPT2。这些 Transformer 模型首先与带有未标记文本数据的语言建模任务相关,然后在各种 NLP 任务上进行微调,并获得最先进的结果!在预训练期间,模型学习语言统计的一些基本知识,并利用这种能力在其他任务中表现出色。我们相信这项技术在语音数据上也有很大的前景。

单词片段模型

我们上面定义的模型输出字符。这样做的一些好处是,在对语音进行推理时,该模型不必担心词汇以外的单词。所以对于单词 c h a t 来说,每个字符都有自己的标签。使用字符的缺点是效率低,而且模型容易出错,因为您一次只能预测一个字符。已经探索了使用整个单词作为标签,并取得了一定程度的成功。使用这种方法,整个单词聊天将成为标签。但是使用全词,您将不得不保存所有可能词汇的索引来进行预测,这是内存低效的,在预测期间可能会用完词汇。最佳点是使用单词片段或子单词单元作为标签。您可以将单词分割成子单词单元,并使用这些子单词单元作为标签,即 ch at ,而不是单个标签的字符。这解决了词汇表之外的问题,并且更有效,因为它需要比使用字符更少的解码步骤,并且不需要所有可能单词的索引。单词片段已经成功地用于许多 NLP 模型,如 BERT,并且也可以自然地用于语音识别问题。

客户流失分析

原文:https://towardsdatascience.com/customer-churn-analysis-4f77cc70b3bd?source=collection_archive---------4-----------------------

决策树分类器在客户流失分析和预测中的应用。

客户流失是全球信用卡公司、有线电视服务提供商、SASS 和电信公司等企业面临的最重要和最具挑战性的问题之一。尽管看起来不是最有趣的,但客户流失指标可以帮助企业提高客户保持率。

freestocksUnsplash 上拍摄的客户流失照片

我们可以通过将客户分成不同的类别来对客户流失进行分类。合同流失适用于有线电视公司和 SAAS 服务提供商等企业,是指客户决定不再继续使用到期的合同。另一方面,自愿流失是指客户决定取消现有服务,这适用于预付费手机和流媒体订阅提供商等公司。也有消费者没有完成交易就离开可能的购买的时候。我们可以将这些情况归类为非合同流失,这适用于依赖零售场所、在线商店或在线借贷服务的企业。最后,还有非自愿流失,例如,客户不能支付他们的信用卡账单,不再留在信用卡公司。

客户流失的原因可能各不相同,并且需要领域知识来正确定义,但是一些常见的原因是:产品使用率低,服务差,而其他地方的价格更好。不管不同行业的具体原因是什么,有一点适用于每个领域,那就是获取新客户的成本要高于留住现有客户的成本。这对公司的运营成本和营销预算有直接影响。

rupixen.com 在 Unsplash拍照

由于客户流失在企业中的重要性,利益相关者正在投入更多的时间和精力来找出他们组织内部的原因,他们如何准确预测可能停止与他们做生意的现有客户的类型,以及他们可以做些什么来最大限度地减少客户流失。

避免客户流失的最好方法是了解你的客户,而了解你的客户的最好方法是通过历史和新的客户数据。

在本文中,我们将浏览一些消费者数据,看看我们如何利用数据洞察和预测建模来提高客户保持率。在我们的分析中,我们将使用 Python 和各种机器学习算法进行预测。

我们的第一个客户数据集来自一家信用卡公司,在那里我们可以查看客户属性,如性别、年龄、任期、余额、他们订阅的产品数量、他们的估计工资以及他们是否停止了订阅。

我们可以看到我们的数据集,但我们也希望确保数据是干净的,因此作为清理过程的一部分,我们会查看缺失的值和数据类型。

当我们查看统计数据时,我们看到我们客户的平均年龄为 39 岁,客户成为会员的平均月数为 5,预计平均工资为 10 万英镑。

当我们观察预计薪资的性别和地理分布时,我们发现在法国和西班牙,男性客户的预计平均薪资高于女性,而在德国,女性客户的预计平均薪资更高。

当我们看年龄和信用评分之间的关系时,为了明确定义相关性,线性关系非常弱。

基于我们的基本探索性分析,我们可以定义重要的客户属性,这些属性可以为我们提供最佳的洞察力,以便预测可能流失的客户类型。我们可以继续这一分析来回答一些基本问题,例如,“较低的估计工资会增加流失率吗?”或者“较低的信用评分会增加客户流失率吗?”诸如此类。我们可以用不同的方式对数据集进行分组和汇总,以从客户属性中获得更多的洞察力。我们将在下一个数据集中深入探讨这些问题。现在,让我们开始考虑预测哪些客户会流失。

在这种情况下,我们可以将目标(响应)变量标记为客户流失。这意味着我们可以创建一个分类模型,并执行不同的算法方法,如决策树、随机森林、逻辑回归或支持向量机。当谈到机器学习模型时,我们寻找两个主要条件;1-特征集的正态分布,2-特征集的相同尺度。

在这个数据集中,我们可以选择信用评分,地理位置,性别,年龄,任期和估计工资属性作为特征集,流失作为目标变量。

我们必须确保将分类变量更新为数字变量,因为我们将应用的机器学习技术要求所有客户属性都是数字的。

我们可以进一步随机地将我们的数据集分为训练和测试数据集,以便用训练数据集拟合我们的模型,并用测试数据集测试预测。其思路是用训练数据集训练模型,用测试数据集测试预测。如果我们不使用训练和测试数据集,而是使用整个数据集,该算法将只对我们的数据集进行准确的预测,而不会对任何新的数据进行预测。

在此数据集中,让我们使用 DecisionTreeClassifier 和 RandomForestClassifier 来创建我们的模型和预测,进一步评估它们,看看哪一个更好。

根据度量评估,虽然决策分类器模型有 73%的预测是准确的,但 RandomForestClassifier 模型有 82%的预测是准确的。在这种情况下,我们更喜欢使用随机森林。

当我们观察流失和未流失客户的分布时,我们看到数据是公正的。这意味着我们不能仅仅依赖预测模型的准确性度量分数。让我们看看第二个客户数据集,看看我们是否可以做更好的分析和预测模型。

这次,我们将查看一家电信公司及其现有的客户属性,例如他们当前的计划、费用、所在州的位置、客户服务呼叫量、客户时长和客户流失率。

数据集中没有缺失数据,并且数据类型正确。让我们看看分类值和它们的独特值。

当我们查看州和流失率时,我们看到加利福尼亚州和新泽西州是流失率最高的州。

我们还发现,国际计划客户的流失率较高,而语音邮件计划客户的流失率较低。

留在公司的顾客比离开公司的顾客多得多。如果您还记得之前对信用卡公司的分析,这意味着数据中的不平衡,并对预测模型的开发产生影响。(我们之前没有提到的一个重要方面是,我们没有使用电话号码、客户 id 或账号等唯一标识符来选择功能。)

糟糕的客户服务是客户流失的众所周知的原因之一。在我们的案例中,我们可以看到客户服务呼叫量和客户流失率之间存在很强的正线性关系。

有了这个数据集,让我们开发多个不同的模型,并对它们进行评估,看看哪一个最适合解决我们的客户流失业务问题。

与之前的信用卡客户数据集类似,我们需要执行预处理,并将分类变量更新为数值变量,以便创建我们的模型。

现在,我们准备分割数据集来训练/测试和创建我们的模型。先说随机森林。

我们为预测电信公司客户流失而创建的随机森林模型的准确率为 0.89。然而,我们应该进一步分析这一点,因为数据是公正的。

我们可以查看其他评估指标,如交叉验证矩阵,它将为我们提供真阳性、假阳性、真阴性和假阴性的数量、精确度、召回率和 f1 分数。通过查看哪些特征对预测贡献最大,我们还可以了解我们可以做些什么来改进模型。

该模型预测 560 个真阴性,13 个假阳性,54 个假阴性,40 个真阳性。

当我们用随机森林分类器评估模型时,我们看到:

精确度分数是 0.729

回忆分数是 0.372

ROC 曲线如下:

AUC 分数(roc 曲线下的面积)是 0.83,f1 分数是 0.49。

我们还发现,为了从模型中获得最佳性能,我们需要将 n 估计量设置为 30。(目前,我们的模型使用 100)

我们可以进一步查看特征的重要性,看看哪些特征对预测的影响最大。

最重要的是,我们可以明确地从模型中移除状态。

让我们使用支持向量机创建另一个模型。

当我们创建模型并查看准确性时,我们已经看到支持向量机的准确性分数低于随机森林分类。

当我们创建模型并查看准确性时,我们已经看到支持向量机的准确性分数低于随机森林分类。

该模型预测 567 个真阴性,6 个假阳性,83 个假阴性,11 个真阳性。尽管假阳性计数略有下降,但与 RandomForestClassifier 相比,真阳性明显较少。

精确度分数(0.647)和召回分数(0.11)都比随机分类器低得多。roc 曲线下面积(auc)为 0.83,与随机森林分类器相同。支持向量机的最佳选择度是 1。(当前设置为默认值 3)。

基于我们创建的两个预测模型,我们用随机森林分类器创建的第一个模型将是更好的选择。我们还可以调整这个模型,并通过更新 n_estimator 和从特征集中删除状态变量来改进它,以便更好地预测。

借助现有的数据消费者洞察,公司可以预测客户可能的需求和问题,针对他们制定适当的战略和解决方案,满足他们的期望并保留他们的业务。基于预测分析和建模,企业可以通过细分和提供定制的解决方案,有针对性地集中注意力。分析客户在使用服务的生命周期中流失是如何发生的以及何时发生的,将使公司能够采取更多先发制人的措施。

利用分类建模预测客户流失

原文:https://towardsdatascience.com/customer-churn-analysis-eda-a688c8a166ed?source=collection_archive---------15-----------------------

第 1 部分:探索性数据分析

在今天的商业世界里,竞争是激烈的,每个顾客都是有价值的。理解客户是最重要的,包括能够理解客户的行为模式。客户流失率是商业客户(在 SaaS 平台上非常普遍)离开商业业务并把钱带到别处的比率。了解客户流失对公司的成功至关重要,而流失分析是了解客户的第一步。

粘土银行Unsplash 上拍摄

我决定从一个 Kaggle 数据集中执行客户流失分析,该数据集给出了一家电信公司(Telcom)的客户信息数据,试图更好地了解他们的客户流失可能性。虽然我们最终将构建一个分类模型来预测客户流失的可能性,但我们必须首先深入探索数据分析(EDA)流程,以更好地了解我们的数据。包含代码和笔记本的 Github 库可以在这里找到。

数据

如上所述,数据来源于 Kaggle。在我们的数据集中,我们有 7043 行(每行代表一个唯一的客户)和 21 列:19 个特征,1 个目标特征(客户流失)。数据由数字和分类特征组成,因此我们需要分别处理每种数据类型。

目标:

  • 客户流失—客户是否流失(是,否)

数字特征:

  • 任期——客户在公司工作的月数
  • 月度费用—每月向客户收取的费用
  • 总费用——向客户收取的总费用

分类特征:

  • CustomerID
  • 性别—男/女
  • 老年人—客户是否是老年人(1,0)
  • 合作伙伴—客户是否有合作伙伴(是,否)
  • 受抚养人——客户是否有受抚养人(是,否)
  • 电话服务—客户是否有电话服务(是,否)
  • 多条线路—客户是否有多条线路(是,否,无电话服务)
  • 互联网服务—客户的互联网服务类型(DSL、光纤、无)
  • 在线安全—客户是否有在线安全插件(是、否、无互联网服务)
  • OnlineBackup —客户是否有在线备份插件(是、否、无互联网服务)
  • 设备保护—客户是否有设备保护附件(是、否、无互联网服务)
  • 技术支持—客户是否有技术支持附加服务(是、否、无互联网服务)
  • 流媒体电视—客户是否有流媒体电视(是,否,无互联网服务)
  • 流媒体电影—客户是否有流媒体电影(是,否,无互联网服务)
  • 合同—客户合同的期限(每月、1 年、2 年)
  • 无纸账单—客户是否有无纸账单(是,否)
  • 支付方式—客户的支付方式(电子支票、邮寄支票、银行转账(自动)、信用卡(自动))

目标

我们可以从左边的饼图中看到,我们的数据集中大约有 27%的电信客户最终会流失。这看起来确实是一个相当高的数字,但是由于我不在电信公司工作,也没有电信领域知识的经验,我将只考虑它的价值,而不会过多地考虑它。由于这是我们的目标变量,我们将在大多数变量的 EDA 中使用 Churn 作为一个元素。

数字特征

使用数字特征时,我们可以查看的最具信息性的统计数据之一是数据的分布。我们将使用一个核密度估计图来显示相关变量的概率分布。此图将向我们展示新数据点落在数据集上的可能性最大的位置。我们将为所有数字要素创建一个 KDE。

为了以稍微不同的方式查看我们的数据以获得更多的信息,并且因为“任期”由月份表示,这可能是一个 bi 噪音,我决定根据他们的任期对客户进行分组。

结论:

  • 客户流失最有可能发生在任期的 20 个月之前。
  • 流失的客户最有可能每月收费超过 60 美元。
  • 一般来说,随着月费的增加,客户流失的可能性也会增加
  • 总费用的分布非常普遍,因此我们将重点关注“每月费用”的显著性

分类特征

性别

结论:

  • 我们的数据中,老年人明显少于非老年人
  • 总的来说,更多的非老年人会比老年人流失
  • 老年公民比非老年公民流失的比例更高
  • 一旦月费超过 60 美元,老年人和非老年人都开始流失
  • 非老年人最有可能每月收费 20 美元左右
  • 与老年人相比,非老年人在每月收费低于 60 美元的情况下更容易流失

合作伙伴和家属

结论:

  • 对于有合作伙伴的客户,数据集是分开的
  • 那些没有伴侣的人比那些有伴侣的人流失率略高
  • 没有家眷的客户比有家眷的客户流失率略高
  • 对于合作伙伴价值和从属价值而言,流失和不流失客户的月费用非常相似

电话服务和线路数量

结论:

  • 只有电话服务的客户不会比其他客户流失更多
  • 只有电话服务的人 25%的时间会流失
  • 使用电话服务的客户只需支付更高的月平均费用
  • 拥有多条线路的客户与拥有单一线路的客户的流失率大致相同
  • 拥有多条电话线的用户比拥有单一电话线的用户更频繁地支付更高的月费

互联网服务

结论:

  • 光纤是最受欢迎的互联网选择
  • 光纤互联网客户流失率远远高于 DSL 或无互联网客户
  • 光纤是一项非常昂贵的服务,当客户拥有这项服务时,他们的流失率会比没有这项服务时稍高
  • 当 DSL 用户的月费用在 40 到 60 美元之间时,他们最有可能流失。

附加服务

结论:

  • 拥有电视流媒体和/或电影流媒体服务的客户比所有其他附加服务的客户流失更多
  • 大多数类别的客户流失率将在每月 100 美元左右达到峰值

契约

结论:

  • 超过一半的顾客选择每月付款
  • 越来越多的客户因月度计划而流失
  • 计划越长,流失率越低
  • 合同时间越长,月费通常越高

无纸化账单和支付

支付结论:

  • 非无纸化计费的客户流失率比无纸化客户高出近 15%
  • 当每月价格低于 60 美元时,无纸客户的流失率与非无纸客户相似,一旦超过 60 美元,无纸客户的流失率就比非无纸客户高
  • 使用电子支票支付的客户流失率比使用所有其他支付方式的客户高出 10%
  • 无论月费多少,用信用卡支付的顾客都有稳定的流失率,而用银行转账、电子支票或邮寄支票支付的顾客,一旦月费超过 60 英镑,他们的流失率就会上升。

后续步骤

因此,我们刚刚浏览了数据集的每个要素,并探索了每个要素的至少几个不同方面。正如任何项目中的 EDA 一样,总是有更多的方法来处理数据集以继续学习。与任何数据科学项目一样,拥有业务领域和底层数据理解的坚实基础至关重要。既然我们已经看了关键特征和它们相互作用的方式,我们可以开始构建我们的分类模型了。看看我的下一篇博客来看看它的实际效果吧!

电信领域的客户流失

原文:https://towardsdatascience.com/customer-churn-in-telecom-segment-5e49356f39e5?source=collection_archive---------7-----------------------

快门架

开发用于流失预测的机器学习模型

公司通常更关注客户的获取,而把留住客户放在第二位。然而,吸引一个新客户的成本是留住一个现有客户的五倍。根据贝恩公司的研究,T2 的客户保持率提高 5%,T4 的利润会增加 25%到 95%。

客户流失是一项指标,显示客户停止与某家公司或某项服务进行交易,也称为客户流失。通过遵循这一指标,大多数企业可以做的是试图了解流失数字背后的原因,并通过反应行动计划解决这些因素。

但是,如果你能提前知道某个特定的客户可能会离开你的企业,并有机会及时采取适当的行动以防止其发生,那该怎么办?

导致客户做出取消决定的原因可能很多,包括服务质量差、客户支持延迟、价格、新的竞争对手进入市场等等。通常,没有单一的原因,而是一系列事件的组合,最终导致顾客的不满。

如果你的公司不能识别这些信号并在点击取消按钮之前采取行动,就没有回头路了,你的客户已经走了。但是你还有一些有价值的东西:数据。你的顾客留下了很好的线索,让你知道你的需求在哪里。它可以成为有意义的见解的宝贵来源,并培训客户流失模型。从过去学习,并且手头有战略信息改善未来经验,这都是关于机器学习的。

说到电信领域,这里有巨大的机会空间。运营商收集的财富数量的客户数据可以为从被动转变为主动做出很大贡献。复杂的人工智能和数据分析技术的出现进一步帮助利用这些丰富的数据以更加有效的方式解决客户流失问题

在本文中,我将使用一个匿名运营商的客户群数据集,由平台 IBM 开发者提供。该数据集总共包含 7,043 个客户和 21 个属性,来自个人特征、服务签名和合同细节。在这些条目中,5,174 个是活跃客户,1,869 个是不稳定客户,这表明数据集非常不平衡。该评估的目标变量将是特性Churn

主要目标是开发一个机器学习模型,能够根据客户的可用数据预测客户流失。对于这个实现,我将主要使用 Python、 PandasScikit-Learn 库。完整的代码你可以在我的 GitHub 上找到。

为此,我将完成以下步骤:

  • 探索性分析
  • 数据准备
  • 训练、调整和评估机器学习模型

探索性分析

由于本实验的目的是识别可能导致客户流失的模式,我将主要关注数据集的流失部分,以进行探索性分析。

客户生命周期(以月为单位)由特征Tenure表示,客户流失率由特征Churn表示,这是本实验的目标变量。下面的柱状图可以很好地揭示客户流失在客户生命周期中的分布情况。

我们可以看到,最大的大多数客户在第一个月取消或不续订,总计 20.3%的客户退出。这种高费率的原因可能是糟糕的首次体验、试用期或预付费帐户,如果在预定义的期限内没有充值,这些帐户将自动过期。

继续分析数据集的变动部分,我现在将重点关注分类特征和它如何将与目标特征Churn关联起来。为此,我将特性分为三组:个人属性、订阅的服务和合同属性。

个人属性

数据集上可用的个人属性有:Gender, SeniorCitizen, Partner, Dependents。下图可以提供一些有意义的见解,例如:

  • 没有家眷的客户流失的可能性是普通客户的四倍
  • 老年人流失的可能性降低了三倍
  • 伴侣离开的可能性几乎减少了两倍

流失客户的个人属性

服务属性

这组功能表明客户订购了哪种服务,或者是否不适用。这个群体聚集的特征列表PhoneService, MultipleLines, InternetService, OnlineSecurity, OnlineBackup, DeviceProtection, TechSupport, StreamingTV and StreamingMovie

下图显示了可以注意到的类别之间高差异的特征。它提供了关于客户更有可能使用哪种运营商服务的见解:

  • 取消订购的大多数客户都启用了电话服务
  • 使用光纤网络服务的客户比使用 DSL的客户更有可能取消**
  • 没有启用在线安全、设备保护、在线备份和技术支持服务的客户更有可能离开

流失客户的服务属性

合同属性

这组特征表明了合同方面并收集了属性Contract, PaperlessBillingPaymentMethod.下面的图表提供了关于可能使订户更容易流失的合同方面的见解:

  • 大多数取消订阅的客户都启用了逐月合同类型和无纸化计费
  • 使用电子支票付款方式的顾客更有可能离开

流失客户的合同属性

数据准备

不平衡数据

将用于 ML 模型训练的目标变量将是Churn。我们需要确保两个Churn类(‘Yes’和‘No’)具有相等的分布,否则,它会在模型中引入偏差。

流失率

从左侧的图表中,我们可以看到数据集非常不平衡,包含 73.5%的“否”条目(表示活跃账户),而 26.5%的“是”条目(表示失败账户)。

有不同的技术来处理不平衡数据。在这个特殊的例子中,我使用了欠采样,简单地说,这意味着移除大多数类的一些观察值。之后,条目的数量平均分布在训练数据集的每个类中的 1,406 次出现中。

特征编码

机器学习算法只能读取数值。因此,数据准备的一个重要部分是将分类特征编码成数值,这个过程称为特征编码。

对于只有两个类(二进制)的分类特征,比如genderSeniorCitizenPartnerDependentsPhoneServicePaperlessBilling,我使用了 Scikit-Learn 的 LabelEncoder ,这是一个实用程序类,用于帮助标准化标签,使它们只包含 0 和 n_classes-1 之间的值。

当涉及到具有两个以上类别的分类特征时,例如MultipleLinesInternetServiceOnlineSecurityOnlineBackupDeviceProtectionTechSupportStreamingTVStreamingMoviesContractPaymentMethod,我使用了方法从 Pandas Dataframe 中获取 _dummies ,该方法将分类变量转换为哑变量/指示变量。

分割训练和测试数据

订户的数据集被分成 75%用于训练,25%用于测试。当暴露于新数据时,训练集将用于生成所选算法将使用的模型。测试集是我将接触的最终数据集,用于根据一些指标测量模型性能

训练、调整和评估机器学习模型

韵律学

对于客户流失问题,理想的衡量标准是召回。Recall 回答以下问题:正确识别出实际阳性的比例是多少?在这种情况下,召回衡量的是在所有搅动中被正确分类的搅动的百分比,这也是我们在分析 ML 分类器的性能时所要寻找的。

例如,考虑一个免费赠送 1 GB 数据使用量的再参与活动。您可能希望确保这份额外礼物的精确度很高。换句话说,你会想尽可能减少将获得奖金的快乐用户的数量,而不是让这种奖金几乎只击中处于危险中的用户。

模型

在这个实验中,我应用了四种不同的 ML 算法来分析和比较它们各自获得的召回分数。下面列出了这些:

为了比较它们的性能,作为第一步,我应用了交叉验证方法,这是一种将数据划分为子集的技术,在一个子集上训练数据,并使用另一个子集来评估模型的性能。表现最好的是 SVM (0.78 回忆分数)和物流回归(0.79 回忆分数)。但仍有优化的空间。

通过超参数调谐

为了提高整体性能,在谈到召回指标时,我使用网格搜索SVM逻辑回归调整了分类器超参数。

最有表现力的改进来自 SVM 车型,从 0.78 变为 0.93。这意味着基于 SVM 实施的 ML 模型在预测客户流失时提供了 94%的精确度。另一方面,它的误报率很高,这意味着 63%的满意客户可能被错误地预测为流失。这些结果可以在下面的相关矩阵中看到,其中 1 表示流失,0 表示不流失。

SVM 和逻辑回归分类器的相关矩阵

逻辑回归模型经过调整后略有改善,召回分数从 0.79 提高到 0.82。尽管如此,它的误报率更低。实际上,这意味着你将能够吸引 82%的客户,而这些客户将会流失,但你将会错过另外的 18%。此外,你可能有 28%的人被错误地预测为搅动。

根据重新参与活动的情况,锁定有流失风险的尽可能多的客户,同时无意中接触到一些满意的客户,这可能是一个良好的权衡,而不是在没有采取适当行动的情况下让大量客户取消。

结论

没有哪种算法能 100%准确地预测客户流失。在精确度和召回率之间总会有一个权衡。这就是为什么测试和理解每个分类器的优点和缺点并充分利用它们是很重要的。

如果目标是吸引和接触客户以防止他们搅动,与那些被错误标记为“没有搅动”的人接触是可以接受的,因为这不会造成任何负面影响。这可能会让他们对这项服务更加满意。如果对其产生的有意义的信息采取适当的行动,这是一种可以从第一天起增加价值的模型。

感谢您的宝贵时间!

我希望这个项目能有助于你的目标。如果你有任何问题或任何类型的反馈,请随时在 LinkedIn 上联系我,并在 GitHub 上查看我的其他项目。

使用 PySpark 预测音乐流中的客户流失

原文:https://towardsdatascience.com/customer-churn-prediction-within-music-streaming-using-pyspark-a96edd4beae8?source=collection_archive---------45-----------------------

Unsplash 照片由 Cezar Sampaio 拍摄

音乐流媒体业务的关键是识别可能流失的用户,即有可能从付费和免费订阅降级到取消服务的用户。如果一家音乐流媒体公司提前准确地识别出这些用户,他们可以向他们提供折扣或其他类似的激励措施,从而节省数百万美元的收入。众所周知,获得一个新客户比留住一个现有客户的成本更高。这是因为回头客可能会在你公司的产品和服务上多花 67%的钱。

1.1 项目概述

我们希望 确定可能会取消其帐户并离开服务 的用户。我们在这个项目中的目标是帮助一个虚构的企业(类似于 Spotify 和 Pandora),方法是建立和训练一个二进制分类器,该分类器能够根据从用户过去的活动和与该服务的交互中获得的模式,准确识别取消音乐流媒体服务的用户。

  • 定义流失变量: 1 —在观察期内取消订阅的用户,以及 0 —始终保持服务的用户

由于数据集的规模,该项目是通过利用 Apache Spark 分布式集群计算框架功能,使用 Python API for Spark,PySpark 来实施的。

1.2 加载数据

**# import libraries**from pyspark import SparkContext, SparkConf
from pyspark.sql import SparkSession
from pyspark.sql import Window
from pyspark.sql.functions import udf, col, concat, count, lit, avg, lag, first, last, when
from pyspark.sql.functions import min as Fmin, max as Fmax, sum as Fsum, round as Fround
from pyspark.sql.types import IntegerType, DateType, TimestampTypefrom pyspark.ml import Pipeline
from pyspark.ml.feature import VectorAssembler, Normalizer, StandardScaler
from pyspark.ml.regression import LinearRegression
from pyspark.ml.classification import LogisticRegression, RandomForestClassifier, GBTClassifier
from pyspark.ml.clustering import KMeans
from pyspark.ml.tuning import CrossValidator, ParamGridBuilder
from pyspark.ml.evaluation import BinaryClassificationEvaluator,**# create a Spark session**
spark = SparkSession \
.builder \
.appName(‘CustomerChurn’) \
.getOrCreate()**# Check Spark configuration**
spark.sparkContext.getConf().getAll()path = "mini_sparkify_event_data.json"
df = spark.read.json(path)

2.数据理解

该数据集包含 2018 年 10 月 1 日至 2018 年 12 月 1 日期间记录的用户活动日志。完整数据集包含大约 2600 万行/日志,而子集包含 286 500 行。完整的数据集收集了 22,277 个不同用户的日志,而子集仅涵盖 225 个用户的活动。子集数据集包含 58 300 个免费用户和 228 000 个付费用户。两个数据集都有 18 列,如下所示。

root
 |-- artist: string (nullable = true)
 |-- auth: string (nullable = true)
 |-- firstName: string (nullable = true)
 |-- gender: string (nullable = true)
 |-- itemInSession: long (nullable = true)
 |-- lastName: string (nullable = true)
 |-- length: double (nullable = true)
 |-- level: string (nullable = true)
 |-- location: string (nullable = true)
 |-- method: string (nullable = true)
 |-- page: string (nullable = true)
 |-- registration: long (nullable = true)
 |-- sessionId: long (nullable = true)
 |-- song: string (nullable = true)
 |-- status: long (nullable = true)
 |-- ts: long (nullable = true)
 |-- userAgent: string (nullable = true)
 |-- userId: string (nullable = true)

每个活动日志都属于一个特定的用户。数据集中的七列代表静态的用户级信息(对于属于特定用户的所有日志是固定的):

艺术家:用户正在听的艺术家
userId :用户标识;
sessionId: 标识服务的用户的单个连续使用时段的唯一 Id。多个用户可以使用相同的 sessionId
:用户的名
:用户的姓
性别:用户的性别;2 类( MF )
位置:用户位置
userAgent :用户访问流媒体服务使用的代理;57 不同类别
注册:用户的注册时间戳
级别(非静态):订阅级别;2 类(免费付费 )
页面:该事件生成时用户正在访问哪个页面。不同类型的页面将在下一节中详细介绍

页面列包含用户在应用程序中访问过的所有页面的日志。

>>> df.select('page').distinct().show(10)
+--------------------+
|                page|
+--------------------+
|              Cancel|
|    Submit Downgrade|
|         Thumbs Down|
|                Home|
|           Downgrade|
|         Roll Advert|
|              Logout|
|       Save Settings|
|Cancellation Conf...|
|               About|
+--------------------

根据执行的分析,仍然属于同一个会话的两个连续日志之间的最大时间似乎是一个小时。

# Explore the auth column
df.groupby('auth').count().show()+----------+------+
|      auth| count|
+----------+------+
|Logged Out|  8249|
| Cancelled|    52|
|     Guest|    97|
| Logged In|278102|
+----------+------+

我们还可以看到用户相当活跃,其中一个顶级用户总共列出了大约 8000 首歌曲。下面的图表表明,被搅动的用户通常来自加州和新泽西州,大多数付费用户正在离开音乐应用程序,而更多的男性比女性倾向于取消他们的订阅。加利福尼亚州和纽约州的人口往往更密集,因此可以预期更高的流失率和更高的整体参与度。从下图中很容易看出,所提供的 Sparkify 数据集是一个不平衡数据集的例子,因为与 174 相比,被搅动用户的份额仅略高于 20% (52)。

分类特征(last level 0-免费,1-付费;性别 0-男性,1-女性)

3.特征工程

首先,我们必须将原始数据集(每个日志一行)转换成具有用户级信息或统计数据的数据集(每个用户一行)。我们通过执行几个映射实现了这一点(例如,获取用户的性别、观察期的长度等。)和聚合步骤。

3.1 转换

对于 10 月 1 日之后注册的少数用户,注册时间与实际日志时间戳和活动类型不一致。因此,我们必须通过在页面列中查找提交注册日志来识别延迟注册。这一步并不简单,因为此类日志事件没有映射到任何用户 Id ,所以必须从会话 Id 信息中提取这些事件。

对于少数注册较晚的用户,观察开始时间被设置为他们第一次日志的时间戳,而对于所有其他用户,则使用默认的 10 月 1 日。

# Lag the page column
windowsession = Window.partitionBy('sessionId').orderBy('ts')
df = df.withColumn("lagged_page", lag(df.page).over(windowsession))windowuser = Window.partitionBy('userId').orderBy('ts').rangeBetween(Window.unboundedPreceding, Window.unboundedFollowing)# Identify users that registered after the start of observation, and infer the start date accordingly
df = df.withColumn("beforefirstlog", first(col('lagged_page')).over(windowuser))
df = df.withColumn("firstlogtime", first(col('ts')).over(windowuser))
df = df.withColumn("obsstart", 
                   when(df.beforefirstlog == "Submit Registration", df.firstlogtime).otherwise(obs_start_default))# For each log compute the time from the beginning of observation...
df = df.withColumn("timefromstart", col('ts')-col("obsstart"))
# ...and time before the end of observation
df = df.withColumn("timebeforeend", col('obsend')-col('ts'))

与上面类似的还有在默认观察期结束前取消服务的用户,即所谓的被搅动用户。对于每个这样的用户,相应观察期的结束已经被设置为他/她的最后日志条目的时间戳,而对于所有其他用户,默认为 12 月 1 日。

3.2 特征工程—汇总统计数据

新创建的用户级数据集包括以下栏目:

lastlevel :用户最后的订阅级别,转换为二进制格式(1 —付费层,0 —免费层)
性别 : 性别,转换为二进制格式(1 —女性,
obsstart,obsend :用户特定观察期的开始和结束

endstate :用户在观察期内的最后一次交互
nact :用户在观察期内的总交互次数
nsongs、ntbup、ntbdown、nfriend、nplaylist、ndgrade、nupgrade、nhome、nadvert、nhelp、nsettings、nerror :播放的歌曲数、竖起大拇指、竖起大拇指向下拇指、添加的朋友、添加到播放列表的歌曲、降级、升级、主页访问

nact_recent,nact_oldest: 用户在观察窗最后一天和第一天 k 的活动,分别为 nsongs_recent,nsongs_oldest :观察窗最后一天和第一天 k 播放的歌曲,分别为

# Aggregation by userId
df_user = df.groupby(‘userId’)\
.agg(
 # User-level features
 first(when(col(‘lastlevel’) == ‘paid’, 1).otherwise(0)).
alias(‘lastlevel’),
 first(when(col(‘gender’) == “F”, 1).otherwise(0)).alias(‘gender’),
 first(col(‘obsstart’)).alias(‘obsstart’),
 first(col(‘obsend’)).alias(‘obsend’),
 first(col(‘endstate’)).alias(‘endstate’),

 # Aggregated activity statistics
 count(col(‘page’)).alias(‘nact’),
Fsum(when(col(‘page’) == “NextSong”, 1).otherwise(0)).alias(“nsongs”),
 Fsum(when(col(‘page’) == “Thumbs Up”, 1).otherwise(0)).alias(“ntbup”),
 Fsum(when(col(‘page’) == “Thumbs Down”, 1).otherwise(0)).alias(“ntbdown”),
 Fsum(when(col(‘page’) == “Add Friend”, 1).otherwise(0)).alias(“nfriend”),
 Fsum(when(col(‘page’) == “Add to Playlist”, 1).otherwise(0)).alias(“nplaylist”), 
 Fsum(when(col(‘page’) == “Submit Downgrade”, 1).otherwise(0)).alias(“ndgrade”),
 Fsum(when(col(‘page’) == “Submit Upgrade”, 1).otherwise(0)).alias(“nugrade”),
 Fsum(when(col(‘page’) == “Home”, 1).otherwise(0)).alias(“nhome”),
 Fsum(when(col(‘page’) == “Roll Advert”, 1).otherwise(0)).alias(“nadvert”),
 Fsum(when(col(‘page’) == “Help”, 1).otherwise(0)).alias(“nhelp”),
 Fsum(when(col(‘page’) == “Settings”, 1).otherwise(0)).alias(“nsettings”),
 Fsum(when(col(‘page’) == “Error”, 1).otherwise(0)).alias(“nerror”),

 # Aggregated activity statistics in different periods 
 Fsum(when(col(‘timebeforeend’) < trend_est, 1).otherwise(0)).alias(“nact_recent”),
 Fsum(when(col(‘timefromstart’) < trend_est, 1).otherwise(0)).alias(“nact_oldest”),
 Fsum(when((col(‘page’) == “NextSong”) & (col(‘timebeforeend’) < trend_est), 1).otherwise(0)).alias(“nsongs_recent”),
 Fsum(when((col(‘page’) == “NextSong”) & (col(‘timefromstart’) < trend_est), 1).otherwise(0)).alias(“nsongs_oldest”) )

汇总活动统计

4.探索性数据分析

完成特征工程步骤后,我们分析了构建特征之间的相关性。

# For visualization purposes we switch to pandas dataframes
df_user_pd = df_user.toPandas()# Calculate correlations between numerical features
cormat = df_user_pd[['nact_perh','nsongs_perh', 'nhome_perh', 'ntbup_perh','ntbdown_perh', 'nfriend_perh','nplaylist_perh', 
'nadvert_perh', 'nerror_perh', 'upgradedowngrade', 'songratio', 'positiveratio','negativeratio', 
'updownratio', 'trend_act', 'trend_songs', 'avgsessionitems',  'avgsessionlength','avgsongs']].corr()# Plot correlations
plt.rcParams['figure.figsize'] = (10,10)
plt.subplots_adjust(left=0.20, right=0.9, top=0.95, bottom=0.15)
sns.heatmap(cormat, cmap = "YlGnBu", square = True, vmin = -1, vmax = 1);
plt.title('Feature correlations');
plt.savefig('correlations.png')

上面的热图描述了变量 nact_perhnsongs_perh 之间的高度相关性。这是意料之中的,因为听歌显然是最常见的用户活动。出于同样的原因,在 trend_acttrend_songs 之间有很高的相关性。在这两种情况下,我们决定简单地从所有进一步的分析中删除,只保留衡量最重要的交互的变量——播放歌曲。

为了进一步减少数据中的多重共线性,我们还决定在模型中不使用 nhome_perhnplaylist_perh 。此外, avgsessionlength 与每个会话中的平均项目高度相关,因此也可以忽略。

4.1 与搅动变量的关系

从下面呈现的可视化中,可以得出以下观察结果:

  • 平均而言,喝醉的用户每小时会播放更多的歌曲;
  • 受刺激的用户每小时明显会拒绝更多的广告,平均不得不看更多的广告;
  • 对于喝醉的用户,歌曲和积极互动相对于总活动的比率通常较低
  • 被搅动的用户平均每次对话互动较少
  • 免费订阅计划的用户流失率更高
  • 男性用户的流失率略高

根据此分析,没有删除任何功能。

4.建模和评估

我们首先通过交叉验证执行网格搜索来测试几个参数组合的性能,所有这些都是基于从较小的 Sparkify 用户活动数据集获得的用户级数据。基于在交叉验证中获得的性能结果(通过 AUC 和 F1 分数衡量),我们确定了性能最好的模型实例,并在整个训练集上对它们进行了重新训练。

4.1 网格搜索方法

逻辑回归

  • maxIter (最大迭代次数,默认= 100):【10,30】
  • regParam (正则化参数,默认= 0.0):【0.0,0.1】
  • elasticNetParam(混合参数—L2 罚 0,L1 罚 1,默认= 0.0):【0.0,0.5】

随机森林分类器

  • (最大树深,默认= 5):【4,5,6,7】
  • (树的数量,默认= 20):【20,40】****

梯度增强树分类器

  • max depth****(最大树深,默认= 5):【4,5】**
  • (最大迭代次数,默认= 20):【20,100】

在定义的网格搜索对象中,每个参数组合的性能默认通过在四重交叉验证中获得的平均 AUC 分数(ROC 下的面积)来衡量。下文第 4.4 节简要解释了 AUC。**

***numeric_columns = [‘nsongs_perh’, ‘ntbup_perh’,’ntbdown_perh’, ‘nfriend_perh’, 
‘nadvert_perh’, ‘nerror_perh’, ‘upgradedowngrade’, ‘songratio’, ‘positiveratio’,’negativeratio’, 
‘updownratio’, ‘trend_songs’, ‘avgsessionitems’,’avgsongs’]# Combining multiple numerical features using VectorAssembler
numeric_assembler = VectorAssembler(inputCols = numeric_columns, outputCol = “numericvectorized”)# Standardizing numerical features
scaler = StandardScaler(inputCol = “numericvectorized”, outputCol = “numericscaled”, withStd = True, withMean = True)# Adding the two binary features
binary_columns = [‘lastlevel’, ‘gender’]
total_assembler = VectorAssembler(inputCols = binary_columns + [“numericscaled”], outputCol = “features”)# Defining three different pipelines with three different classifiers, all with default parameters
# Logistic regression 
lr = LogisticRegression()
pipeline_lr = Pipeline(stages = [numeric_assembler, scaler, total_assembler, lr])# Random forest classifier
rf = RandomForestClassifier()
pipeline_rf = Pipeline(stages = [numeric_assembler, scaler, total_assembler, rf])# Gradient-boosted tree classifier
gb = GBTClassifier()
pipeline_gb = Pipeline(stages = [numeric_assembler, scaler, total_assembler, gb])***

4.2 绩效指标

F1 分数是这个问题的首选性能指标。输入的用户级数据集不平衡。音乐流媒体服务旨在识别大部分可能流失的用户(目标是高召回,但同时不希望无缘无故给予太多折扣(目标是高精度),即给予实际上对服务满意的用户(误报)——这可以帮助音乐流媒体业务防止财务损失。**

***class F1score(Evaluator):
def __init__(self, predictionCol = “prediction”, labelCol=”label”):
 self.predictionCol = predictionCol
 self.labelCol = labelColdef _evaluate(self, dataset):

 # Calculate F1 score 
 tp = dataset.where((dataset.label == 1) & (dataset.prediction == 1)).count()
 fp = dataset.where((dataset.label == 0) & (dataset.prediction == 1)).count()
 tn = dataset.where((dataset.label == 0) & (dataset.prediction == 0)).count()
 fn = dataset.where((dataset.label == 1) & (dataset.prediction == 0)).count()

 # Add epsilon to prevent division by zero
 precision = tp / (tp + fp + 0.00001)
 recall = tp / (tp + fn + 0.00001)

 f1 = 2 * precision * recall / (precision + recall + 0.00001)

 return f1def isLargerBetter(self):
 return True***

在完整数据集上测试

表现最好的模型的 AUC 值为 0.981,F1 值为 0.855。

如上图所示,识别混乱用户最重要的特性是 nerror_perh ,它测量每小时向用户显示多少个错误页面。用户经历的错误越多,他/她对服务不满意的可能性就越大。

第二个和第三个最重要的特征也是如此, ntbdown_perhnadvert_perh 分别测量每小时给出的拇指向下数和每小时看到的广告数。

最有趣的功能是 trend_songs 变量,它测量用户的歌曲收听活动趋势,这是第四个最重要的功能。

5.结论和改进

梯度增强的树分类器的 F1 值(精度和召回率)为 0.855,可以根据过去的用户活动和与音乐流媒体服务的交互来识别被搅动的用户,这可以帮助企业防止严重的财务损失。

一些改进是在完整的 Sparkify 数据集上对模型执行全面的网格搜索利用到目前为止已经被忽略的歌曲级特征,例如,根据在指定的观察期内收听的不同歌曲/艺术家来计算用户的收听多样性等。建立新特征,例如歌曲收听会话的平均长度、跳过或部分收听歌曲的比率等。**

关于这个项目的更多细节,请点击这里查看我的 Github 链接。

使用 DBSCAN 进行客户聚类

原文:https://towardsdatascience.com/customer-clustering-using-dbscan-4672f51fe5aa?source=collection_archive---------22-----------------------

Rajendra Biswal 在 Unsplash 上的照片

在这篇博客中,我们将学习我最喜欢的聚类算法之一,那就是 DBSCAN 算法。我们将首先理解理论,然后我将借助一个非常简单的例子演示 DBSCAN 的工作原理。

DBSCAN 代表对有噪声的应用进行基于密度的空间聚类。

它在 1996 年左右被引入,并且由于其识别不同类型的聚类形状的有效聚类能力以及即使在存在噪声的情况下也能正确识别聚类的能力,在社区中获得了显著的普及。

让我们跳到一些有助于理解算法基本工作原理的关键术语。

有两个参数在算法中起着至关重要的作用。1)最小点数和 2)ε。

该算法通过单独处理每个数据点来工作,特别是对于每个点。它会构建一个以点为中心,半径等于ε的圆。

敏点:

最小点是距离该点ɛ距离内必须存在的点数。

Epsilon(ɛ) :

它是每个物体周围的距离或半径。

核心点:

考虑下图,画一个以查询点为圆心,以ɛ.为半径的圆如果圆内的点数大于 MinPoints(本例中为min points = 2),查询点将成为核心点。所以查询点有资格成为核心点。

(图片由作者提供)核心点演示:1。圆的半径= ɛ, 2。中心是考虑中的点

边界点:

如果查询点在ɛ内小于最小点,但在ɛ距离内具有核心点,则它是边界点。

噪声点:

既不是核心点也不是边界点的点称为噪声点。见下图。

(图片由作者提供)噪点演示

DBSCAN 将以这种方式处理每一个对象/点,并且最终它将获得所有点的分类,作为核心、边界或噪声点。

一旦获得了点的分类,下一步就是使用它们来构建聚类。DBSCAN 选取一个核心点,然后查看其ε半径圆内的点,并为这些点分配一个聚类标签。

所以关键的思想是给一个核心点的圆内的所有点以相同的标号。

将为不同的核心点运行多次迭代以分配聚类标签,请注意算法不会为那些在早期迭代中已经考虑的点分配新的聚类标签。

现在让我们看一下 DBSCAN 在客户数据上的工作示例。

问题陈述:
你拥有商场,想根据顾客过去的购买数据了解他们。这种分析将有助于营销团队采取一些策略来锁定目标客户。

数据:

您的数据由客户 ID、年龄、性别、年收入和支出分数等列组成。支出分数是您根据您定义的参数(如客户行为和购买数据)分配给客户的分数。

你可以从 Kaggle.com 得到这个数据集。

https://www . ka ggle . com/vjchoudhary 7/customer-segmentation-tutorial-in-python

Python 代码:

# DBSCAN Clustering
# Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd# Importing the dataset
dataset = pd.read_csv(Mall_customers.csv')
data = dataset.iloc[:, [3, 4]].values
dataset.head()

该数据集中有 200 行

# visualizing the dataset
plt.scatter(data[:, 0], data[:, 1], s = 10, c = 'black')

(图片由作者提供)年收入和支出分数散点图

# Fitting DBSCAN to the dataset and predict the Cluster label
from sklearn.cluster import DBSCANdbscan = DBSCAN(eps=5.5, min_samples=4)
labels = dbscan.fit_predict(data) 
np.unique(labels)

聚类标签。注意 Cluster = -1 表示噪声点

# Visualising the clusters
plt.scatter(data[labels == -1, 0], data[labels == -1, 1], s = 10, c = 'black')plt.scatter(data[labels == 0, 0], data[labels == 0, 1], s = 10, c = 'blue')
plt.scatter(data[labels == 1, 0], data[labels == 1, 1], s = 10, c = 'red')
plt.scatter(data[labels == 2, 0], data[labels == 2, 1], s = 10, c = 'green')
plt.scatter(data[labels == 3, 0], data[labels == 3, 1], s = 10, c = 'brown')
plt.scatter(data[labels == 4, 0], data[labels == 4, 1], s = 10, c = 'pink')
plt.scatter(data[labels == 5, 0], data[labels == 5, 1], s = 10, c = 'yellow')      
plt.scatter(data[labels == 6, 0], data[labels == 6, 1], s = 10, c = 'silver')plt.xlabel('Annual Income')
plt.ylabel('Spending Score')
plt.show()

(图片由作者提供)黑点是噪点。

祝贺您,您的第一次客户聚类迭代已经完成。

结论:

由于聚类是无监督的学习,您需要分析每个聚类并有一个关于业务数据的定义,因为聚类总是受一些业务规则的指导。一旦您的集群接近业务规则,您的模型就有意义了。

我们还可以更改 eps 和 Min_sample 的值来调整模型,使聚类的形状更好。

感谢您的阅读。

参考:https://www . ka ggle . com/vjchoudhary 7/customer-segmentation-tutorial-in-python

竞争激烈的商业环境中的客户参与

原文:https://towardsdatascience.com/customer-engagement-in-a-highly-competitive-business-environment-942b855efdf5?source=collection_archive---------65-----------------------

赢得客户的忠诚度并降低流失率

了解你的客户——作者图片

这篇文章强调了中小型企业如何使用预测方法来预测客户行为。企业必须赢得客户的忠诚度,降低流失率。

目的是帮助线下商家(特别是中小企业)更好地了解他们的客户,降低他们的流失率,增加客户对品牌的忠诚度。通过忠诚度和接送选项等多种产品选项,商家可以识别他们的最佳客户,并知道如何最好地吸引他们。

这篇文章需要结合机器学习、数据分析和编程。将审查关于客户及其订单的信息,并确定任何不同的细分市场或趋势。

概述

客户忠诚度和保留率对任何业务的发展都至关重要。线下商家(特别是中小商店)努力为他们的顾客提供个性化服务。同样,顾客希望得到与网飞、亚马逊等主要品牌相同的参与度。有无数的选择供客户选择,这些企业必须发展,否则就有被甩在后面的风险。

小型企业面临的个性化挑战是什么?

中小型商家没有足够的资源来收集和解释客户数据。他们面临的一些挑战包括:

  • 数据不足
  • 无法获得可靠的数据
  • 无法解释数据

客户为什么会离开(客户流失)?

客户流失是指客户不再光顾某个品牌或企业的趋势。各种原因可能会影响客户的决定,如果在同一时期有太多的客户放弃某个品牌,该业务就有彻底关闭的风险。以下是客户流失的常见原因;

  • 企业主无法与大客户建立关系
  • 企业主不能向客户提供任何形式的个性化服务/互动
  • 企业主缺乏与大企业竞争的资源

为了实现这一点,店主了解顾客行为并根据购买行为和人口统计数据对顾客进行分类至关重要。这将有助于建立一种能带来客户忠诚度的关系。

案例分析

星巴克是一个利用顾客数据的优秀品牌范例。他们在一周的特定时间向特定的客户发送特定的报价。

  • 他们向最有可能改变购买习惯的顾客提供最好的交易
  • 他们只为客户提供投资回报率最高的交易
  • 他们试图把不常光顾的顾客变成常客

假设和假设

我们应该思考“应该问什么类型的问题?数据应该怎么审核?”

我们的假设是:

  • 忠诚的顾客可能会比新顾客花费更多
  • 获得新客户的成本可能高于留住客户的成本
  • 上午的交易量高于晚上
  • 甜点和其他产品受到的影响更大
  • 如果能提供个性化的体验,顾客更有可能做生意
  • 奖励会让顾客再次光顾

我们将使用 Nugttah 数据集(忠诚度应用程序)的子集来测试我们的假设

风险和限制

这些是本项目中可能预期的潜在限制。但是,在数据分析过程中会适当考虑这些因素:

  • 缺乏足够和准确的数据是这个项目的最大限制。分析的结果只会和用来执行分析的数据一样好。
  • 另一个限制是商店不会记录他们交易的每一个方面。因此,根据分析需要,可能必须做出一些假设。
  • 还存在用错误的模型分析数据的风险。
  • 由于广泛的新冠肺炎疫情引起的顾客行为的改变可能导致错误的销售预测。

进场和流程

机器学习和数据科学项目的一个优秀方法如下:

  • 加载和预处理数据
  • 干净的数据
  • 对数据进行数据可视化和探索性数据分析(EDA)
  • 最后,分析所有模型,找出最有效的模型。

加载&数据的预处理

在此步骤中,我们将导入数据集并将其签出

在这里,数据集将被导入和检查。 read_csv 功能将用于读取工作表

% matplotlib inline将用于在笔记本中生成内联图。 sns.set() 将被添加到代码中,以将可视化样式修改为基本 Seaborn 样式:

import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import numpy as np  # linear algebra
import seaborn as sns  # data visualization library  
import matplotlib.pyplot as plt
import seaborn as sns
import datetime
import datetime as dt
from matplotlib.ticker import FuncFormatter
import matplotlib.ticker as ticker
import json# Figures inline and set visualization style
%matplotlib inline
sns.set()plt.rcParams[‘figure.dpi’] = 150
np.set_printoptions(suppress=True)
np.set_printoptions(precision=3)orders_df = pd.read_csv('data/orders.csv')

我们将使用 head() 函数来显示数据集的前 5 个观察值,并使用 shape 特性来找出数据帧中有多少列和多少行。

orders_df.head()

orders_df.head()

使用形状的数据集中的行和列的总数

orders_df.shape

orders_df.shape

数据由 104850 个观察值和 29 个特征组成。

此时,可以使用 describe() 返回平均值、计数、最小值和最大值、标准偏差和数据质量来确定汇总统计数据。

orders_df.describe()

orders_df.describe() —作者照片

清除数据

数据在被分析之前必须经过清理过程。一些数据清理过程包括:

  • 缺少值
  • 空值
  • 重复值
  • 噪声值
  • 格式化数据
  • 极端值
  • 将数据分成单列和多列
  • 转换数据类型
  • 其他数据完整性问题

已加载下列数据文件:

  • 订单数据
  • 客户数据
  • 商业数据
  • 产品数据
  • 奖励数据
  • 最终 _ 单项 _ 订单

注意:原始数据最初在各种数据表中被打乱。必须使用 pd.merge 来收集和合并数据帧。

删除有重复数据的数据字段

# Redundant data exist in the dataset so we need to delete columns that are all same to reduce complexity
def is_unique(s):
    a = s.to_numpy()
    return (a[0] == a[1:]).all()for col in orders_df:
    if is_unique(orders_df[col]):
        del orders_df[col]
        print("{} is deleted because it's redundant".format(col))

使每一笔采购成为一个单行

数据是从 MongoDB 中提取的,有些列是 JSON 数据格式,整个数据类型将显示为字符串。为了改变这一点,使用 json.loads 将其转换为 json,作为字典数据结构进行访问。

new_df = pd.DataFrame(columns=['_id', 'earned_points', 'visits_count', 
                               'business', 'brand', 'branch',
       'customer', 'cashier', 'reference', 'products', 'payment_amount',
       'price', 'final_price', 'transaction_type', 'purchased_at',
       'created_at', 'updated_at'])
new_list = []
def get_product(row):
    prod_js = json.loads(row['products'])
    for p in prod_js:
        row['products'] = p
        vals = list(row.to_numpy())
        new_list.append(vals)
_ = orders_df.apply(lambda row: get_product(row), axis=1)keys = ['_id', 'earned_points', 'visits_count', 'business', 'brand', 'branch',
       'customer', 'cashier', 'reference', 'products', 'payment_amount',
       'price', 'final_price', 'transaction_type', 'purchased_at',
       'created_at', 'updated_at']  
new_df = pd.DataFrame(new_list, columns=keys)prod_id = new_df.apply(lambda row: row['products']['product']["$oid"], axis=1)
quantity = new_df.apply(lambda row: row['products']['quantity'], axis=1)
original_price = new_df.apply(lambda row: row['products']['original_price'], axis=1)
final_price = new_df.apply(lambda row: row['products']['final_price'], axis=1)# insert these product information to dataset
new_df.insert(1, 'prod_final_price', final_price)
new_df.insert(1, 'prod_original_price', original_price)
new_df.insert(1, 'prod_quantity', quantity)
new_df.insert(1, 'prod_id', prod_id)
del new_df['products']
del new_df['payment_amount']
del new_df['price']

检查空值

final_df = pd.read_csv('data/final_with_new_unified_names.csv')pd.isna(final_df).any()

如果有空值,要么删除它,要么替换它

final_df[‘city_text’] = final_df[‘city_text’].fillna(‘unknown’)
cities = [city.strip() for city in list(final_df[‘city_text’])]
final_df[‘city_text’] = cities
#final_df.to_csv(‘data/final_merged_single_item_orders.csv’,index=False)
# final_df.head()# fill business - brand - cashier with 'unknown'
final_df[['brand', 'business', 'cashier']] = final_df[['brand', 'business', 'cashier']].fillna(value="unknown")final_df.columns

更改任何没有意义的值

删除异常值的功能

# def drop_outliers(df, field_name):
#     distance = 6.0 * (np.percentile(df[field_name], 75) - np.percentile(df[field_name], 25))
#     df.drop(df[df[field_name] > distance + np.percentile(df[field_name], 75)].index, inplace=True)
#     df.drop(df[df[field_name] < np.percentile(df[field_name], 25) - distance].index, inplace=True)def drop_outliers(df, field_name):
    df_copy = df.copy()
    Q1 = np.percentile(df[field_name].values,25)
    Q2 = np.percentile(df[field_name].values,50)
    Q3 = np.percentile(df[field_name].values,75)
    IQR = Q3 - Q1    
    lower_fence = Q1 - 1.5 * (IQR)
    upper_fence = Q3 + 1.5 * (IQR)print("lower_fence: ",lower_fence)
    print("upper_fence: ",upper_fence)

    df_copy = df_copy[~((df_copy[field_name] < lower_fence)|(df_copy[field_name]  > upper_fence))]return df_copy

现在,商店数据、忠诚度数据、客户数据和其他可用数据集都有了很好的描述。

EDA &数据可视化

数据清理过程完成后,将对数据进行数据可视化和统计分析。通过单独的数据集来可视化分类数据是一个很好的做法。

现在将从分析的数据中得出模式和见解。

客户分析| 性别分布

customers_data = final_df.drop_duplicates(['customer'])# See the distribution of gender to recognize different distributions
print(customers_data.groupby('gender')['gender'].count())
chart = sns.countplot(x='gender', data=customers_data)
chart.set_xlabel("Gender")
chart.set_ylabel("Counts (Number of Orders)")
plt.title('Distribution of Gender')

这表明我们的数据集中有 1711 名女性和 5094 名男性

直方图是发现每个属性分布的好方法。

图表 1 —作者提供的照片

图表显示,男性顾客的比例略高于女性顾客。

为了获得更多信息,我们将根据注册年份对他们进行划分

plt.figure(figsize=(9, 5))
chart = sns.countplot(data = customers_data, x = 'year', hue = 'gender')
chart.set_title('Membership Since Year Distibution By Gender', fontsize = 15, y = 1.02)
chart.set_ylabel("Counts (Number of Orders)")
chart.set_xlabel("Year")

图表 2 —作者照片

客户分析| 年龄分析

在年龄分析中,我们首先检查的是异常值,并发现了一些异常值,因此任何发现的异常值都从数据集中删除。

chart = sns.boxplot(x=final_df[‘cust_age’])
chart.set_xlabel(“Customer Age”)

图表 3 —作者照片

# drop outliers
final_df_without_outliers = drop_outliers(final_df, 'cust_age')chart = sns.boxplot(x=final_df_without_outliers.cust_age)
chart.set_xlabel("Customer Age")

图表 4 —作者照片

如下图所示,年龄范围在 20 到 40 岁之间。突出显示 describe() 调用结果的有效性。

feature = final_df_without_outliers['cust_age']
sns.distplot(feature)
plt.title('Normal Distribution of Customer Age', fontsize=15);
plt.xlabel('Customer Age',fontsize=15)
plt.show()

图表 5 —作者照片

平均年龄为 26 岁。这表明,与其他群体相比,年轻人更喜欢咖啡。较长的右尾表明这种分布是右偏的。

统计与客户年龄相关的客户

图表 6 —作者照片

消费习惯

该图描述了女性比男性花费更多,尽管我们的女性用户较少。

图表 7

【引用分析】| 按用户居住地排名前 20 的城市

图表 8 —作者照片

达曼的人咖啡消费量最高。

引用分析| 前 20 名活跃客户所在城市(最频繁最大订单数)

图表 9 —作者照片

可视化成对关系

活跃客户重要变量之间的相关矩阵图

相关性描述了两个变量之间的相似变化。当这种变化发生在同一个方向时,就被认为是正相关。如果变化发生在不同的方向,它被认为是负相关。

简单来说,相关矩阵就是每一对属性之间的相关性。它可以绘制在图表上,以辨别几个变量之间的相关程度。

了解这种计算是很有用的,因为如果数据中存在高度相关的输入变量,一些机器学习算法(如线性和逻辑回归)的性能可能会很差

相关矩阵

上面,矩阵可以被看作是对称的,即矩阵的左下和右上是相同的。此外,它在一个图中显示相同数据的 6 个不同视图。还可以推断出,最强的相关变量在最终价格(总支出)和积分之间。这是一种正相关关系,客户在该数据集中获得的最终价格越高,他们的盈利点就越高。然而,其他变量没有这种相同的相关性。然而,它们提供了有用的信息,并且基于相同的基本原理工作。

业务和产品分析

当审查平均价格的偏斜度时,可以推断出有少数昂贵的项目,但一般来说,价格属于一组。此外,负偏度意味着中位数低于平均值——这通常是由低价产品引起的。

十大热门类别

产品描述—作者照片

p_desc = product_desc.loc[product_desc['total_revenue'] >= sorted(product_desc.total_revenue, reverse=True)[10]]
sns.set_style('whitegrid')
plt.rcParams['figure.dpi'] = 250
chart = sns.scatterplot('counts', # Horizontal axis
           'average_price', # Vertical axis
           data=p_desc, # Data source
           size = 10,
           legend=False)chart.set_xlabel("Counts (Number of Orders)")
chart.set_ylabel("Avg. Price")
plt.title("Most Revenue Production 10 items")for line in range(0, p_desc.shape[0]):
    chart.text(p_desc.counts[line]+300, p_desc.average_price[line], 
             p_desc.index[line], verticalalignment='top', horizontalalignment='left', 
             size=5, color='black', weight='normal')

十大产品—作者照片

订单分析

total_data = final_df.drop_duplicates(['_id'])import calendar
calendar.setfirstweekday(calendar.SATURDAY)
months_names = {i:calendar.month_name[i] for i in range(1,13)}
total_data['month'] = total_data['month'].map(months_names)
total_data.groupby(['month', 'year'])['customer'].count()

每月分析-作者照片

如图所示,2020 年 4 月记录了 264 笔销售,可以归类为 2018 年数据中的单一异常值。

订单分析|年度

plt.figure(figsize=(13,8))
chart = sns.countplot(x='year', hue='month', data=total_data)
chart.set_xlabel("Year")
chart.set_ylabel("Counts (Number of Orders)")
plt.title('Distribution of Orders over Years with Months')

图表 11 —作者照片

还有,2019 年 5 月销量大幅下滑。这种由疫情引起的下降从 2020 年初开始,到 2020 年 4 月急剧下降。

订单分析|月度

订单 _ 月刊—作者照片

订单分析|每周

订单 _ 周刊—作者照片

在沙特阿拉伯,周四和周五被视为周末。然而,星期五比星期四低得多。

新冠肺炎·疫情对顾客行为(POS)的改变:

在分析了过去 3 个月沙特阿拉伯所有食品和饮料的统计数据并将其与我们的数据集输出进行比较后,我们发现了以下结果

last_3_months_orders = total_data[(total_data['month'].isin(['January','February','March'])) & \
                                  (total_data['year'].isin(['2020']))]last_3_months_orders_month_group = last_3_months_orders.groupby(['month', 'year']).agg({
                    '_id': ['count'],
                    'final_price':['sum']})last_3_months_orders_month_group.columns = ['number_of_transactions', 'total_sales']
last_3_months_orders_month_group = last_3_months_orders_month_group.reset_index()
last_3_months_orders_month_group.head()

过去 3 个月订单输出-作者提供的照片

SAMA 统计—作者照片

stats _ 统计 _ 输出—作者提供的照片

RFM 分析

在这里,我们将执行以下操作:

  • 对于最近,计算当前日期和每个客户的最后订单日期之间的天数。
  • 对于频率,计算每个客户的订单数量。
  • 对于货币,计算每个客户的购买价格的总和。
# Filter on Dammam city (the most active city)
Dammam_orders_df = final_df[final_df['city_text']=='Dammam']# present date
PRESENT = dt.datetime.utcnow()
# print(PRESENT)
# print(Dammam_orders_df['created_at'].iloc[0])Dammam_orders_df['created_at'] = pd.DatetimeIndex(Dammam_orders_df['created_at']).tz_convert(None)# drop duplicates
Dammam_orders_df = Dammam_orders_df.drop_duplicates()# Transform to proper datetime
Dammam_orders_df['created_at'] = pd.to_datetime(Dammam_orders_df['created_at'])# Remove records with no CustomerID
Dammam_orders_df = Dammam_orders_df[~Dammam_orders_df['customer'].isna()]# Remove negative/0 prices
Dammam_orders_df = Dammam_orders_df[Dammam_orders_df['final_price'] > 0]Dammam_rfm = Dammam_orders_df.groupby('customer').agg({
                    'created_at': lambda date: (PRESENT - date.max()).days,
                    '_id': lambda num: len(num),
                    'final_price': lambda price: price.sum()})Dammam_rfm.columns = ['Recency (days)','Frequency (times)','Monetary (CLV)']
Dammam_rfm['Recency (days)'] = Dammam_rfm['Recency (days)'].astype(int)Dammam_rfm.head()

RFM _ 输出—作者提供的照片

RFM 分析| 计算 RFM 值的分位数

新近发生率、频率和金额最低的客户被视为顶级客户。

qcut() 是基于分位数的离散化函数。qcut 根据样本分位数对数据进行分类。例如,4 个分位数的 1000 个值将产生一个分类对象,指示每个客户的分位数成员资格。

Dammam_rfm['r_quartile'] = Dammam_rfm['Recency (days)'].apply(lambda x: r_score(x))
Dammam_rfm['f_quartile'] = Dammam_rfm['Frequency (times)'].apply(lambda x: fm_score(x, 'Frequency (times)'))
Dammam_rfm['m_quartile'] = Dammam_rfm['Monetary (CLV)'].apply(lambda x: fm_score(x, 'Monetary (CLV)'))Dammam_rfm.head()

qcut_output —作者提供的照片

RFM 分析| RFM 结果解释
将所有三个四分位数(r_quartile,f_quartile,m_quartile)组合在一列中,此排名将帮助您对客户进行细分。

Dammam_rfm['RFM_Score'] = Dammam_rfm.r_quartile.map(str) + Dammam_rfm.f_quartile.map(str) + Dammam_rfm.m_quartile.map(str)Dammam_rfm.head()

combine _ output 作者提供的照片

【RFM 分析】| 筛选出顶级/最佳客户

top5 —作者照片

top5_output —作者提供的照片

装置类型

图表 13 —作者照片

Nuggtah 似乎更受 IOS 用户的欢迎,尽管它分布在沙特阿拉伯

解决方案

机器学习主要建立在进行预测和分类的概念上。然而,要理解的最重要的事情是,它不是关于一个方法有多奇特,而是它与测试数据的兼容性。

预测时,只选择预测结果所需的最重要的属性是至关重要的。此外,必须选择适当的 ML 方法。关于客户讨论,建议以下建议:

推荐客户细分 of 忠诚度活动,如奖金奖励、积分充值、免费等级升级,以及专门优化的奖励计划,以提高收入和投资回报率。因此,对客户进行了细分,以发现最佳群体。

细分对于大规模个性化至关重要。此外,该系统应该分析与其他用户没有直接关联但在搜索和购买模式中共享相同标准的志同道合的用户的数据(借助于 ML 算法来提供更多细节并显示用户简档之间的相似性)。

销售预测可以用来预测未来的销售量。通过进一步分析,可以推导出单店销售额、品类销售额、产品销售额等数据。

终身价值预测可用于根据细分客户和行为模式识别最合适的客户。

流失预测可用于确定特定时期内的流失量。

最后一步:设计预测模型

  • 估计系数
  • 设计模型
  • 进行预测并存储结果。
  • 分析模型
  • 初始化随机数发生器

继续将随机数发生器初始化为固定值(7)。

这一步对于保证这个模型的结果可以再次被复制是至关重要的。它还确保训练神经网络模型的随机过程可以被复制。

结论

有了正确的数据,个性化是可以实现的。今天,中小型企业不需要一个大型的分析师或营销人员团队来预测客户行为和趋势。

细分可以帮助企业识别正确的客户,并在正确的时间向他们发送正确的信息。

资源

名称:作为商业模式的推荐系统

  • 角色:进行订单/交易的用户。
  • 描述:提供建议并捕捉用户之间的关系。
  • 利用显性和隐性特征/模式以及用户之间的关系来构建一个好的推荐系统的最佳方法之一是多方面的协作过滤模型,本演示对此进行了清晰的描述。
  • 演示文稿包含所有需要的信息(问题、愿景、技术、使用的数据集和评估)。

名称:采购预测模型

  • 角色:店主。
  • 描述:预测用户下一个订单中的下一个购买产品
  • 数据集:关于“如何赢得数据科学竞赛”的 Kaggle 期末项目

名称:未来销售预测模型

走向数据科学篇

客户体验、人工智能和机器学习——来自 Oovvuu、Canva 和 Minerva Collective 的思考

原文:https://towardsdatascience.com/customer-experience-artificial-intelligence-and-machine-learning-748d8c1e1127?source=collection_archive---------26-----------------------

人工智能(AI)和机器学习(ML)现在是热门话题,它对重新定义商业的许多方面做出了重大贡献,这是理所当然的。然而,许多人仍然对 AI 和 ML 在增强客户体验方面的应用持怀疑态度。

一些人可能会认为,机器不可能接管客户服务,这种服务非常注重人与人之间的互动。机器缺乏同理心和情商核心来提供出色的客户体验。另一方面,许多人也看到了应用人工智能和人工智能来自动化重复性任务的好处,允许人类将更多的时间用于,嗯,做人。

我们联系了来自 Oovvuu、Canva 和 Minerva Collective 的一些专家,向他们请教这个问题。

摩根·豪斯尔在 Unsplash 上的照片

客户体验的现状如何,你如何看待 AI & ML 技术的发展?

目前的客户体验“到处都是,结果大相径庭。Minerva Collective 的数据科学家和联合创始人安东尼·托卡尔(Anthony Tockar)表示:“使用同一服务的两个客户对他们的体验可能会有完全不同的印象,在许多情况下,该服务既笨重又结构不良。不幸的现实是,由于糟糕的服务体验,78%的消费者放弃了交易或没有购买意向。事实上,公司只听取了 4%的不满意客户的意见。消费者有如此多的选择,找到另一家提供类似产品的公司比花时间抱怨或打电话解决问题要容易得多。这就是为什么非常有必要关注客户体验,这一因素对于留住现代客户变得越来越重要。

Canva 的机器学习工程师 Paul Tune 认为“改善客户体验有两种趋势:

  • 随着越来越多的关于每个客户的数据被大规模收集,出现了为个人量身定制的趋势;
  • 通过预测客户的需求,在多个接触点为客户提供流畅体验的趋势。"

为了展示客户体验是如何发展的,Paul 继续举了一个例子。“早期的推荐系统,如 21 世纪初亚马逊和网飞开发的推荐引擎,主要为特定的客户群提供更粗糙的推荐。在不久的将来,推荐的粒度将会更细。例如,我最近和一位来自网飞的工程师交谈过,他提到当电视连续剧被选中时,用户最喜欢的角色会出现在菜单中。这意味着必须更多地了解每个客户,并预测他们的习惯。我们也看到智能个人助理的形式,如 Alexa 和 Siri,”他说。

Oovvuu 的创始人兼首席执行官里奇·萨顿补充说,尽管人工智能和人工智能“在(客户体验中)肯定有一个要素可以发挥作用,但它也缺乏一个关键要素……同理心。所以我认为它会进化。人工智能用得越多,它就学得越多,变得越好,但人类层面的同理心目前仍是一个白日梦。”

图片来自 https://unsplash.com/的。

你从将智能技术应用于客户体验中学到的最大教训是什么?

对于安东尼来说,这个教训是人们需要使用智能技术来正确理解它——“我的经验是,人们通常不信任他们不理解的东西。最新的技术很容易成为头条新闻,但只有最具前瞻性的企业才会认真应用这些技术来获取价值。这不一定是件坏事——领域知识对于好的数据科学至关重要,盲目依赖新方法有许多内在风险。随着时间的推移,我们对客户体验有了很多了解,有必要使用正确的语言向商业人士解释智能技术,让他们充分认识到它的价值。”

对 Paul 来说,最重要的是客户的端到端体验。这意味着与客户的所有接触点都应该是无缝的。对他来说,“整合智能技术以改善用户体验的挑战与管理任何其他复杂系统类似:随着更多移动部件的出现,系统出现故障的几率更高。天真地应用机器学习来改善客户体验是被误导的。如果机器学习是对客户体验的补充,那么它就能发挥最大的作用,有助于提升伟大产品的体验。”

“在 Canva,我们的目标很简单:我们希望给客户最好的体验,让他们能够创造和设计。为此,我们关注两个方面。首先,我们如何让他们的设计所需的内容易于访问。其次,我们如何预测哪些资源在未来可能对他们有帮助。我们通过改善搜索和推荐服务来提升客户体验,从而实现这些目标。”

对里基来说,最大的教训是“AI 把人类变成了超人,但只是为了某些任务。”—“当我们开始 Oovvuu 时,我们聘请编辑阅读文章并找到相关视频,他们每人每天能够阅读一份出版物并找到 40 个相关视频。使用我们创建的人工智能工具的同一个人,现在每天可以阅读 10 万个出版商和 30 万个故事,涵盖 2600 万个主题,并找到来自 40 多个全球广播公司的相关视频。人工智能在自动化人工任务方面非常强大,但人类在所有让我们成为人类的事情上仍然更好。”

对于试图整合 AI & ML 技术和客户体验的企业来说,有哪些挑战?

Anthony、Paul 和 Ricky 都认为,企业面临的一个巨大挑战是没有一个可靠的数据基础架构,或者没有对实现业务目标和客户满意度的确切衡量标准的深刻理解。

“许多公司与我们接洽,寻求将人工智能作为解决商业问题的现成灵丹妙药。还有人来要求玩 AI,这样就能找到商机。两者都不太管用。”里基说。“对我们来说,解决方案是了解我们试图解决的业务问题:也就是说,在全球范围内发布的每篇文章中放入相关视频。然后我们使用人工智能来解决它,但我们开始做的是非常基础的工作,无法胜任。我们有一个团队培养了近 1000 天的教学,以达到它的目的。”

Anthony 继续补充道,“没有灵丹妙药,需要优秀的数据科学家将这些算法转化为商业价值。拥有可靠的数据科学战略至关重要,通过良好的领导力、不断提高的数据素养以及对如何建立高性能数据科学团队的理解,企业可以利用这些技术打造竞争优势。”

Paul 总结了许多企业在流程中采用 AI & ML 时面临的另一个常见挑战——数据量。“目前的机器学习技术依赖于相对大量的数据来提供良好的预测,”他说。“虽然目前正在进行基础研究,以(有望)减少训练这些机器学习模型所需的数据量,但在可预见的未来,目前需要大量数据的主要技术限制仍将存在。”但“幸运的是,如果收集的数据质量足够高,这种影响可以减轻。”

你是如何实施人工智能和人工智能来改善客户体验的?在下面的评论中与我们分享你的故事吧!

关于贡献者

安东尼·托卡尔

Anthony 是数据科学领域的领导者,研究过保险、忠诚度、技术、电信、社会部门甚至神经科学领域的问题。作为一名受过正规培训的精算师,Anthony 在著名的西北大学获得了分析学硕士学位。他在 Neustar 发表的关于数据隐私的帖子成为头条新闻后,他回到悉尼作为一名数据科学家进行实践,同时联合创立了 Minerva Collective 和数据科学早餐会。他还帮助组织了其他几次数据科学家会议和项目,这符合他的使命,即扩大数据的范围和影响,以帮助人们。

保罗·图恩

保罗是 Canva 的机器学习工程师,负责为 Canva 的客户开发定制和个性化内容的解决方案。他在著名的计算机科学会议和期刊上发表了几篇文章,包括 2015 年的 ACM SIGCOMM 会议。他的兴趣包括深度学习、统计学和信息论。你也可以在媒体上找到他。

里奇·萨顿

里奇是 Oovvuu 的创始人兼首席执行官,Oovvuu 是一家由 IBM 和亚马逊支持的初创公司,利用人工智能将全球广播公司的视频与全球出版商进行匹配。它的任务是使用人工智能在每篇文章中插入相关的短格式和长格式视频。通过这样做,它旨在以一种新的、更有说服力的方式讲述新闻,结束假新闻,并通过这样做,将脸书和谷歌的数十亿美元返还给制作内容的记者和广播公司。

原贴于 织于

离散时间契约环境下的顾客终身价值

原文:https://towardsdatascience.com/customer-lifetime-value-in-a-discrete-time-contractual-setting-math-and-python-implementation-af3ef606cefe?source=collection_archive---------24-----------------------

数学和 Python 实现

激励性问题

在按月/按年(即离散时间)订阅业务环境(即合同)中,根据我们当前客户的特征,新客户的预期价值是什么?

  • 请注意,我们的设置是离散时间合同设置。如果你的商业模式不是基于订阅的(即非合同的),请查看 Python 中的生命周期包。

假设

  • 这里我们只关注收入,而忽略了客户获取成本,以及其他成本。

等式

(法德尔、彼得和布鲁斯(2007 年 a))

客户生命周期价值期望值的等式非常简单:

  • m:订阅率
  • s(t):t 时刻的生存函数
  • d:反映货币时间价值的贴现率

例子

这里有一个来自论文推子,彼得和布鲁斯(2007 年 b)的例子。假设我们有 1000 个客户,在第 1 年(t0),我们有所有 1000 个客户。在第 2 年(t1),只有 631 个客户是活跃的。到了第 5 年,只有 326 个客户仍然活跃。假设我们的订阅费率为 100 美元/年,折扣率为 10%。

  • m = 100 美元/年
  • d = 10%

  • 基于 CLV 方程,我们可以填入数据并改写方程,如上所示。
  • 问题:唯一的问题是我们不知道未来的存活率。因此,我们可以使用几何贝塔模型来模拟我们的数据和预测生存函数。

几何贝塔模型

(法德尔、彼得和布鲁斯(2007 年 a))

客户持续时间~ geometric(𝜃)

我们假设客户持续时间/生命周期遵循几何分布,因为客户只能流失一次。

  • 流失概率:𝜃
  • 留任概率:1−𝜃
  • 时间 t 时客户流失的概率:

  • 时间 t 时的存活率:

  • 时间 t 时的保留率:

𝜃∼𝑏𝑒𝑡𝑎(𝛼,𝛽)

我们将𝜃的异质性建模为贝塔分布。我们使用贝塔分布,因为它以区间[0,1]为界,并且它有各种可能的形状。

  • 定义在区间[0,1]上

几何贝塔分布

然后我们可以结合几何分布和贝塔分布,计算联合分布。并且通过一些贝塔函数和伽玛函数的计算,我们可以计算出客户在任意时刻 t 的流失概率,以及任意时刻 t 的留存率。

  • 可能性函数:在 t1 失去𝑛1n1 客户的概率,在 t2 失去𝑛2 客户的概率,以及在观察期结束时保留𝑛−∑𝑛_t 客户的概率。

对数似然函数:𝐿𝐿(𝛼,𝛽|𝑑𝑎𝑡𝑎)=𝑙𝑛(𝐿(𝛼,𝛽|𝑑𝑎𝑡𝑎))

找出𝛼和𝛽的最大似然估计量

  • 为了找到参数的最大似然估计量,我们将对数似然函数最大化或负对数似然函数最小化。通过最优化过程,我们得到了𝛼和𝛽.的最大似然估计值

计算 CLV

给定𝛼和𝛽,计算每个时间点的存活率

  • 𝑟(𝑡)=(𝛽+𝑡−1)/(α+β+t−1)
  • t = 0 时的𝑠(𝑡)=1
  • 𝑠(𝑡)=𝑟(𝑡)𝑠(𝑡−1)当 t>0 时

计算 CLV

为 k 选择一个合理的大数

Python 实现

最大似然估计

这是我的 Python 实现,用于计算对数似然函数,并优化负对数似然函数。注意,我们需要给参数一个初始值,作为优化的起点。在我们的例子中,𝛼和𝛽的初始值都是 1。

通过优化,优化后的负对数似然为 1409.5,𝛼和𝛽的最大似然分别为 0.78 和 1.35。

模型拟合

这是我访问模型拟合的函数。这里我只是比较观察到的和计算出的存活率。你可以改变这个函数来比较似然函数和保持率。

这里的第一个图使用了初始参数(1,1)作为模型参数,我们可以看到模型计算出的存活率不是很理想。第二个图使用参数的最大似然值,模型计算的存活率非常接近观察到的存活率。

计算 CLV

现在,我们可以使用 MLE 参数来计算客户终身价值的期望值。我们可以看到,一个新客户的期望值是 362 美元。

参考资料:
Fader,Peter S .和 Bruce G.S. Hardie (2014),“一个懂电子表格的非统计学家的贝塔几何模型指南。”http://brucehardie.com/notes/032/
Fader,Peter S .和 Bruce G.S. Hardie (2017),“探索客户终身价值的分布(在合同环境中)。”http://brucehardie.com/notes/035/

通过保留实现客户终身价值——在 Python 中,使用 Pandas 和 Numpy

原文:https://towardsdatascience.com/customer-lifetime-value-via-retention-in-python-with-pandas-and-numpy-143171cc98bc?source=collection_archive---------9-----------------------

埃菲社在 Unsplash 上拍摄的照片

在基于订阅的例子中

将这些视为客户终身价值的入门书:这三个部分非常容易理解,会给你一个很好的介绍 LTV 的机会。在第一部中,我浏览了逻辑部分,所以如果你感兴趣,去看看吧!在第二部分中,我展示了一个例子,展示了群组保留如何增加客户的平均加权寿命。在第 3 部分中,我添加了一个 Python 蓝图代码,您可以使用并改进它来推断您的客户 LTV。

零件和内容

第一部分:通过群组保持率估算客户终身价值, CLV 或 LTV 称之为

第二部分:加权队列寿命,作为队列保持的总和,不是证明而是实验

第 3 部分:通过保留实现客户终身价值——在 Python 中,使用 Pandas 和 Numpy

在我开始之前,我想重申一下,LTV 不是一个财务指标,仅仅是一个估计,然而,它允许比直接猜测更好的近似。LTV 最重要的用途之一是客户获取成本的基准,因为它允许设定合理的支出上限。

目的

本系列的目的是阐述一种简单的技术,通过历史趋势的推断,为您提供客户终身价值的估计。在 Python 中,你可以用 Pandas 和 NumPy 做到这一点——这再简单不过了。因此,在这篇文章中,我们不会深究更高级的涉及个体 LTV 预测的技术。我正在考虑写一篇关于此事的独立博文。最后,您可能需要考虑底部列出的一些附加改进。

数据集和假设

在这篇文章中,我们将生成虚拟的月度订阅数据。我们需要 客户 id认购日期到期日 直到认购被取消,否则直到当前日期,以及平均 认购金额

对于这篇文章,我将生成 34 个月的数据。如果你没有这么多的数据,你将不得不对群体行为和寿命做出更多的假设。绘制保留曲线和研究衰变率可能有助于实现这一目的。

Python 实现

虚拟数据

总的来说,我们将遵循本系列第一部分中的逻辑:1)获得群组矩阵;2)获得边际留存;3)外推边缘保持力;4)使用(3)外推(1)。按群组估计的寿命将是第(4)点按行的总和。

首先,我们需要一个订阅数据集。我从 Python 博客文章的 队列分析中获得了一些技术,这些技术对队列的虚拟数据生成和可视化有很好的想法。

下面是我们将用来生成的几个帮助函数:a)客户列表 b)订阅日期、到期日和订阅价值 c)将 a 和 b 放在一个数据框架中。

Helper 函数为客户命名,礼貌地向Fabian Bosler和他的博客帖子

用于随机订阅日期和结果数据框架的辅助函数

当所有这些加在一起时,我们有 4000 行的随机数据帧看起来有点像这样。最后一列是订阅日期的月初,相当于分组。

队列保持率

群组保持率是已获得的客户中达到到期时间 t 的比例。在这种情况下,到期时间是取消订阅之前的时间,或者,如果订阅在当前日期之前有效,则是订阅开始日期和今天之间的时间。

一个有用的功能是绘制保留热图。

从我们的数据中获取数据的方法之一是两步:1)旋转上面的数据框架,以获得到期的群组客户的计数 2)将从 T+1 到 T 的所有客户相加,因为在 T+1 活跃的所有客户都在 T 活跃。

枢纽队列数据

回滚订阅者的数量

将月活跃用户数除以群组规模,最终得到三角形保留矩阵,其中每个值都在[0,1]之间。根据下面的留存矩阵,您已经可以对平均寿命和寿命价值做出假设,这对于在营销活动中选择客户群非常有用。

应用我们上面创建的热图绘图功能,我们可以看看队列如何保持超过 34 个月。

群组保持原样,您可以看到下面的外推版本并进行比较

边际保留率

边际保留略有不同:它取每一列 T+1,其中 T ≠ 1,然后除以 T。结果,我们得到了上个月的订阅者中在下个月重新订阅的一部分。

取前 N 行的平均值来外推矩阵:

你可以看到边际保留率是如何在矩阵中平均和外推的。如果你期望边际保留率发生变化,这是调整的好时机。

外推的边缘队列保持率

把所有的东西放在一起

在外推的边缘保留和队列保留矩阵准备好之后,我们可以外推队列的保留矩阵。

你可以在热图上看到群体保持率是如何推断出来的:

外推队列保持率

寿命与价值

群组中平均客户的生命周期,或平均群组生命周期,是整个到期期间保留百分比的总和。

进一步改进

显然,这种方法给出了一个队列的平均寿命和价值,因此您可以将其与这个采集时间所花费的 CAC 进行比较。如果你想把 LTV 定为“高于平均水平”的目标,并根据收购时间进行调整,这也会有所帮助。但是,在某些情况下,您可能希望预测某个特定的个人客户的 LTV。为此,您可以使用预测建模,我将在后面介绍。

另一个容易实现的改进是将运营利润添加到订阅价值中。这将为您提供一个更好的客户获取成本对比基础。差价会告诉你,一旦客户被吸引过来,第一笔订单送达,这笔生意还剩多少。

对于我们这些熟悉金融中贴现概念的人来说。来自 Investopedia :确定未来将收到的一笔或一系列付款的现值的过程。)—可以纳入你的估算。

你可以考虑的另一个改进是你的业务的季节性,并在你正在做的推断中考虑它。当你查看热图时,可以发现季节性:模式将非常明显,并可能形成一条对角线。

与季节性相似,可能会有一个针对群组的调整或边际保留,您可能希望基于基本知识引入。例如,如果您开展一项活动来影响保留率或提高参与度,则有可能在计算中包含一个变化率。你可以从 计算订阅终身价值的电子表格 中获得一些灵感,这是一篇非常整洁的博客文章——带有电子表格。

说到留存率的计算,您可能已经注意到了,如果有 N 个值可用,那么代码采用窗口为 N 的简单滚动平均。群组规模权重可用于加权平均值

最后,因为在我的代码中,一半的群组和边缘矩阵是按元素填充的,计算可能在较大的矩阵上运行缓慢,所以那里肯定有改进的空间。

最后,我把我的 Colab 笔记本分享给有兴趣复印的朋友:https://Colab . research . Google . com/drive/1 viht 58-NSW-idjbp 1 ks brx 7 _ q 4 DSN 5h 3?usp =共享

如果你想和我联系,你可以在 LinkedIn 和 Twitter 上找到我

https://www.linkedin.com/in/areusova/T14https://twitter.com/khunreus

好好呆着!

人工智能助力平台商业时代的顾客偏好

原文:https://towardsdatascience.com/customer-preferences-in-the-age-of-the-platform-business-with-the-help-of-ai-98b0eabf42d9?source=collection_archive---------25-----------------------

照片由晨酿Unsplash 拍摄

在经营平台业务时,如何利用深度学习发现客户的喜好,了解产品库存

M 营销和产品团队的任务是了解客户。为此,他们关注客户偏好——动机、期望和倾向——这些与客户需求相结合,驱动他们的购买决策

作为一名数据科学家,我了解到客户——他们的偏好和需求——很少(或者从来没有?)落入我们用来理解它们的简单的客观桶或分段中。相反,客户的偏好和需求是复杂的,相互交织的,并且不断变化。

虽然理解客户已经够有挑战性了,但许多现代数字企业也不太了解他们的产品。他们运营数字平台来促进生产者和消费者之间的交流。数字平台商业模式创造了具有网络效应的市场和社区,允许其用户进行互动和交易。平台企业不像线性企业那样通过供应链控制库存。

图片由来自 Pixabay 的穆罕默德·哈桑拍摄

描述平台业务的一个很好的方式是,他们不拥有生产手段,而是创造连接手段。平台业务的例子有亚马逊脸书YouTubeTwitterEbayAirBnB ,像 Zillo 这样的房地产门户网站,以及像旅游预订网站这样的聚合业务。在过去的几十年里,平台业务开始主导经济。

在平台业务时代,我们如何利用人工智能来理解我们的客户和产品?

这篇博文是我之前关于营销中行为数据新黄金标准的讨论的延续:

[## 人工智能符合营销细分模型

新的黄金标准:使用机器学习从行为数据中获得用户和产品分类,为一个…

towardsdatascience.com](/data-science-powered-segmentation-models-ae89f9bd405f)

在这篇博文中,我们使用了一种更先进的深度神经网络来为客户和产品建模。

神经网络体系结构

与 CCBY、 ProSymbolslastsparkJuan Pablo Bravo

我们使用具有以下元素的深度神经网络:

  1. 编码器:获取描述产品或客户的输入数据,并将其映射到特征嵌入中。(嵌入被定义为将一些输入投影到另一个更方便的表示空间)
  2. 比较器:将客户和产品特征嵌入组合成一个偏好张量
  3. 预测器:将偏好转化为预测购买倾向

我们使用神经网络来预测产品购买,因为我们知道购买决策是由客户的偏好和需求驱动的。因此,我们教导编码器从客户行为数据、客户和产品属性中提取此类偏好和需求。

我们可以分析和聚类学习到的客户和产品特征,以得出数据驱动的细分。稍后将详细介绍。

晨酿Unsplash 拍摄的照片

TensorFlow 实现

以下代码使用 TensorFlow 2 和 Keras 来实现我们的神经网络架构:

代码创建 TensorFlow 特征列,可以使用数字以及分类特征。我们正在使用 Keras 功能 API 来定义我们的客户偏好神经网络,该网络可以使用二进制交叉熵作为损失函数,通过 Adam 优化器进行编译。

使用 Spark 训练数据

我们需要客户偏好模型的训练数据。作为一个平台企业,你的原始数据将属于大数据类别。为了从点击流、产品搜索和交易中准备 TB 的原始数据,我们使用 Spark。面临的挑战是将这两种技术结合起来,并将来自 Spark 的训练数据输入 TensorFlow。

[OC]

大量 TensorFlow 训练数据的最佳格式是将其存储为 TFRecord 文件格式,这是 TensorFlow 自己基于协议缓冲区的二进制存储格式。二进制格式极大地提高了加载数据并将其输入模型训练的性能。例如,如果您使用 csv 文件,您将花费大量计算资源来加载和解析数据,而不是训练您的神经网络。TFRecord 文件格式确保您的数据管道不会成为神经网络训练的瓶颈。

Spark-TensorFlow 连接器允许我们用 Spark 保存 TFRecords。只需将它作为 JAR 添加到新的 Spark 会话中,如下所示:

spark = (
  SparkSession.builder
  .master("yarn")
  .appName(app_name)
  .config("spark.submit.deployMode", "cluster")
  **.config("spark.jars.packages","org.tensorflow:spark-tensorflow-connector_2.11:1.15.0")**
  .getOrCreate()
)

并将火花数据帧写入 TFRecords,如下所示:

(
  training_feature_df
  .write.mode("overwrite")
  **.format("tfrecords")**
  **.option("recordType", "Example")
  .option("codec", "org.apache.hadoop.io.compress.GzipCodec")**
  .save(path)
)

要使用 TensorFlow 加载 TFRecords,需要定义记录的模式,并使用 TensorFlow 数据集 API 将数据集解析到 python 字典的迭代器中:

SCHEMA = {
  "col_name1": tf.io.FixedLenFeature([], tf.string, default_value="Null"),
  "col_name2: tf.io.FixedLenFeature([], tf.float32, default_value=0.0),
}data = (
  **tf.data.TFRecordDataset**(list_of_file_paths, compression_type="GZIP")
  .map(
    lambda record: **tf.io.parse_single_example**(record, SCHEMA),
    num_parallel_calls=num_of_workers
  )
  .batch(num_of_records)
  .prefetch(num_of_batches)
)

使用 Spark 和 PandasUDFs 进行批量评分

在训练我们的神经网络之后,有明显的实时评分应用,例如,在产品搜索中对搜索结果进行评分,以解决拥有成千上万产品的平台上的选择瘫痪问题。

但是有一个高级分析用例来查看产品/用户特性和偏好洞察,并创建数据驱动细分来帮助产品开发等。为此,我们对我们的整个客户群和产品目录进行评分,以获取我们模型的编码器和比较器的输出,用于聚类

为了捕获中间神经网络层的输出,我们可以如下重塑我们训练的张量流:

trained_customer_preference_model = tf.keras.models.load_model(path)
customer_feature_model = tf.keras.Model(
  inputs=trained_customer_preference_model.input,
  outputs=trained_customer_preference_model.get_layer(
    "customer_features").output
)

出于性能原因,我们使用 PandasUDF 对 Spark 的用户进行评分,一次对一批用户进行评分:

from pyspark.sql import functions as F
import numpy as np
import pandas as pdspark = SparkSession.builder.getOrCreate()
customerFeatureModelWrapper = CustomerFeatureModelWrapper(path)
CUSTOMER_FEATURE_MODEL = spark.sparkContext.broadcast(customerFeatureModelWrapper)[**@F**](http://twitter.com/F)**.pandas_udf("array<float>", F.PandasUDFType.SCALAR)
def customer_features_udf(*cols):**
  model_input = dict(zip(FEATURE_COL_NAMES, cols))
  model_output = CUSTOMER_FEATURE_MODEL.value([model_input])
  return pd.Series([np.array(v) for v in model_output.tolist()])(
  customer_df
  .withColumn(
    "customer_features",
    **customer_features_udf(*model_input_cols)**
  )
)

我们必须将 TensorFlow 模型包装到一个包装器类中,以允许序列化、在 Spark 集群中广播以及在所有工作器上对模型进行反序列化。我使用 MLflow 来跟踪模型工件,但是您可以简单地将它们存储在任何没有 MLflow 的云存储上。实现一个下载功能,从 S3 或者任何存储模型的地方获取模型工件。

class CustomerFeatureModelWrapper(object):
  def __init__(self, model_path):
    self.model_path = model_path
    self.model = self._build(model_path)
  **def __getstate__(self):**
    return self.model_path
  **def __setstate__(self, model_path):**
    self.model_path = model_path
    self.model = self._build(model_path)
  **def _build(self, model_path):**
    local_path = download(model_path)
    return tf.keras.models.load_model(local_path)

你可以在我之前的文章中了解更多关于 MLflow 如何帮助你完成数据科学项目的信息:

[## 用 Mlflow 为非傻瓜完成数据科学项目模板。

数据科学项目最佳实践,适用于在本地或云中工作的每个人,从刚起步的忍者到大…

towardsdatascience.com](/complete-data-science-project-template-with-mlflow-for-non-dummies-d082165559eb)

聚类和分割

使用 Spark 对我们的客户群和产品库存进行评分后,我们有了一个包含以下特征和偏好向量的数据框架:

+-----------+---------------------------------------------------+
|product_id |product_features                                   |
+-----------+---------------------------------------------------+
|product_1  |[-0.28878614, 2.026503, 2.352102, -2.010809, ...   |
|product_2  |[0.39889023, -0.06328985, 1.634547, 3.3479023, ... |
+-----------+---------------------------------------------------+

( Pixabay )

作为第一步,我们必须创建一个有代表性的但小得多的客户和产品样本,用于聚类。重要的是,你要对你的样本进行分层,每层的客户和产品数量相等。通常,我们有许多匿名客户,他们没有什么客户属性,比如人口统计等。为了分层。在这种情况下,我们可以根据客户与之交互的产品的产品属性对客户进行分层。这符合我们的一般假设,即他们的偏好和需求决定了他们的购买决策。在 Spark 中,您使用地层键创建一个新列。按层次获取客户和产品的总数,并计算每个层次对样本的份额,大约等于按层次的计数。你可以用 Spark 的

DataFrameStatFunctions.sampleBy(col_with_strata_keys, dict_of_sample_fractions, seed)

创建分层样本

为了创建我们的分割,我们使用 T-SNE 来可视化我们的分层数据样本的高维特征向量。T-SNE 是一种随机 ML 算法,以可视化的方式降低维度,将相似的客户和产品聚集在一起。这也被称为邻居嵌入。我们可以使用额外的产品属性为 t-sne 结果着色,以解释我们的聚类,作为我们分析的一部分,从而产生洞察力。在我们从 T-SNE 获得结果之后,我们在 T-SNE 邻居嵌入上运行 DBSCAN 来找到我们的聚类

[OC]

利用来自 DBSCAN 输出的集群标签,我们可以计算集群质心:

centroids = products[["product_features", "cluster"]].groupby(
    ["cluster"])["product_features"].apply(
    lambda x: np.mean(np.vstack(x), axis=0)
)cluster
0     [0.5143338, 0.56946456, -0.26320028, 0.4439753...
1     [0.42414477, 0.012167327, -0.662183, 1.2258132...
2     [-0.0057945233, 1.2221531, -0.22178105, 1.2349...
...
Name: product_embeddings, dtype: object

在我们获得聚类质心后,我们将所有的客户群和产品目录分配给它们的代表聚类。因为到目前为止,我们只对大约 50,000 个客户和产品进行了分层抽样。

我们再次使用 Spark 将我们所有的客户和产品分配到他们最近的集群质心。我们使用 L1 规范(或出租车距离)来计算客户/产品到群集质心的距离,以强调每个特征对齐

**distance_udf = F.udf(lambda x, y, i: float(np.linalg.norm(np.array(x) - np.array(y), axis=0, ord=i)), FloatType())**customer_centroids = spark.read.parquet(path)
customer_clusters = (
    customer_dataframe
    .**crossJoin**(
        F.broadcast(customer_centroids)
    )
    .withColumn("distance", **distance_udf**("customer_centroid", "customer_features", F.lit(1)))
    .withColumn("distance_order", F.row_number().over(Window.partitionBy("customer_id").orderBy("distance")))
    .filter("distance_order = 1")
    .select("customer_id", "cluster", "distance")
)+-----------+-------+---------+
|customer_id|cluster| distance|
+-----------+-------+---------+
| customer_1|      4|13.234212|
| customer_2|      4| 8.194665|
| customer_3|      1|  8.00042|
| customer_4|      3|14.705576|

然后,我们可以总结我们的客户群,得出集群突出度:

total_customers = customer_clusters.count()
(
    customer_clusters
    .groupBy("cluster")
    .agg(
        F.count("customer_id").alias("customers"),
        F.avg("distance").alias("avg_distance")
    )
    .withColumn("pct", F.col("customers") / F.lit(total_customers))
)+-------+---------+------------------+-----+
|cluster|customers|      avg_distance|  pct|
+-------+---------+------------------+-----+
|      0|     xxxx|12.882028355869513| xxxx|
|      5|     xxxx|10.084179072882444| xxxx|
|      1|     xxxx|13.966814632296622| xxxx|

这完成了从我们的神经网络嵌入中导出数据驱动分段所需的所有步骤:

[OC]

在我的上一篇文章中阅读更多关于细分和从我们的模型中提取洞察力的方法:

[## 人工智能符合营销细分模型

新的黄金标准:使用机器学习从行为数据中获得用户和产品分类,为一个…

towardsdatascience.com](/data-science-powered-segmentation-models-ae89f9bd405f)

实时评分

要了解关于如何部署实时评分模型的更多信息,我推荐我以前的一篇文章:

[## 如何将 Spark ML 模型作为 Kafka 实时流应用程序嵌入到生产部署中

用于生产评分的 2 种模型部署

towardsdatascience.com](/how-to-embed-a-spark-ml-model-as-a-kafka-real-time-streaming-application-for-production-deployment-933aecb79f3f)

一般注意事项和建议

  • 与链接文章中的协同过滤方法相比,神经网络学会了一般化,经过训练的模型可以用于新客户和新产品。神经网络有没有冷启动的问题。
  • 如果除了历史购买和其他客户档案数据之外,您至少使用一些行为数据作为您客户的输入,那么您训练的模型甚至可以对没有任何交易或客户档案数据的新客户做出购买倾向预测。
  • 学习到的产品特征嵌入将会比你的客户特征嵌入聚类成更大数量的不同聚类。大多数顾客都归入一个大群体并不罕见。这并不意味着 90%的顾客都是一样的。如简介中所述,您的大多数客户都有复杂、交织且不断变化的偏好和需求。这意味着它们不能被分成不同的组。不代表他们是同一个。集群的简化无法捕捉到这一点,这只是重申了机器学习对客户意义的需求。
  • 虽然许多利益相关者会喜欢该模型产生的洞察力和细分,但该模型的真正价值在于其预测购买倾向的能力。

Jan 是公司数据转型方面的成功思想领袖和顾问,拥有将数据科学大规模应用于商业生产的记录。他最近被 dataIQ 评为英国 100 位最具影响力的数据和分析从业者之一。

在 LinkedIn 上连接:https://www.linkedin.com/in/janteichmann/

阅读其他文章:https://medium.com/@jan.teichmann

使用机器学习进行客户细分和获取

原文:https://towardsdatascience.com/customer-segmentation-and-acquisition-using-machine-learning-a219ce0ec139?source=collection_archive---------8-----------------------

斯特凡诺·阿莱马尼在 Unsplash 上拍摄的照片

使用无监督学习根据人口统计数据将客户聚类成细分市场,并使用监督学习来预测潜在客户

介绍

这篇博文是关于我在 Udacity 的机器学习工程师纳米学位项目中做的最后一个项目。该项目基于 Arvato Financial Solutions 提供的真实数据。任务是了解销售有机产品的邮购公司的客户群,并将这些客户群与总体数据进行比较,以预测未来可能的客户。

这个项目尽可能接近真实世界的数据科学项目。这很有挑战性,也很有趣,我在这方面学到了很多。我决定写这篇关于我的学习的文章。

本文的结构:

  • 什么是客户细分
  • 项目介绍
  • 数据描述和分析
  • 使用无监督学习的客户细分
  • 使用监督学习预测未来客户

客户细分

将客户分成具有共同特征的个体的过程称为客户细分。这种细分使营销人员能够为特定的客户群创建有针对性的营销信息,从而增加人们购买产品的机会。它允许他们创建和使用特定的沟通渠道来与不同的细分市场进行沟通,以吸引他们。一个简单的例子是,公司试图通过社交媒体帖子吸引年轻一代,通过广播广告吸引老一代。这有助于公司建立更好的客户关系,并提高公司的整体绩效。

三种最常见的客户细分类型

尽管有三种以上的客户细分类型,我们还是要看看三种最常见的客户细分策略。

1.人口细分

年龄、性别、教育程度、收入、财务状况等参数。从人口统计学的角度来看。这种细分是最常见的客户细分方法,因为这种数据易于获取和分析。此外,人口统计与一个人最重要的特征相对应,这将有助于营销人员做出明智的决策。例如,一家航空公司可以发送电子邮件,向低收入群体提供经济舱机票,向高收入群体提供头等舱机票。

2.地理分割

顾名思义,这种客户细分是基于一个人的物理位置来完成的。在这种情况下,一个制造空调系统的公司就是一个例子。它不能向印度和冰岛的人们提供同样的产品。

3.行为细分

这种客户细分是基于客户的行为数据。基于购买习惯、消费习惯、品牌互动、浏览历史或对应于行为或人的任何其他数据来进行分组。我们今天在网上看到的所有定向广告都使用某种行为细分来决定哪个广告针对哪个客户。

项目介绍

Arvato 在该项目中提供的数据是其客户的人口统计数据和德国一般人口的人口统计数据。因此,任务是根据人口统计数据进行客户细分。该数据包括对应于每个人的 366 个特征,这些特征指示年龄、性别、生活阶段、经济状况、家庭状况、家庭状况、房屋位置、邻居信息。这些特征只是数据中 366 个特征中的几个。

问题陈述

问题陈述表述为“给定一个人的人口统计数据,邮购公司如何高效地获取新客户”。

根据这一陈述,我们可以得出结论,我们必须以某种方式比较现有的客户数据和总体数据,以推断它们之间的关系。手动方式是比较客户和普通人群之间的统计数据。例如,可以比较年龄的平均值和标准偏差,以确定哪个年龄组更有可能成为客户,或者可以比较工资,以查看哪一组人成为客户,等等。

但是这种分析会给出许多结果,必须再次对这些结果进行分析,以得出最终的策略。这个过程将需要大量的时间,到这个分析完成时,市场上的竞争对手将占领大部分人口,公司将倒闭。今天,随着机器学习(ML)技术在每个领域的出现,这个问题也可以在 ML 算法的帮助下得到解决。

数据描述和分析

如前所述,Arvato 提供的数据包含现有客户的人口统计数据和一般人口数据。此外,还为监督学习部分提供了两个额外的文件,一个用于培训,一个用于测试。最后,测试集上的预测将提交给 Kaggle competition。此外,还提供了两个附加文件,其中包含有关特征值及其描述的信息。这两个文件是有益的,因为所有的功能名称都是德语和简短的形式。让我们看看关于数据集的信息。

普通人群-包含德国普通人群的人口统计数据,相当于 891,211 人,每个人有 366 个特征。(891211x366)

客户数据-包含邮购公司现有客户的人口统计数据,对应于 191,652 人,每个人有 369 个特征。这三个额外的特性是特定于公司的,涉及如何下订单以及订单的数量。(191652x366)

训练数据-由 42,982 人的人口统计数据组成,并带有一个除 366 之外的附加列,指示一个人是否是客户,用于训练监督学习模型。

测试数据-由 42,833 人的人口统计数据组成,具有相同的 366 个特征,但没有目标。

包含功能信息的两个附加文件

数据清理

数据分析从将错误记录的值替换为 NaN 值开始。这些错误记录的值是使用给定的信息文件确定的。例如,根据属性信息文件中给出的描述,列“LP_STATS_FEIN”只需包含“1–5”中的值,但给出的数据包含“0”。这意味着记录的这些值有错误,这些值必须被视为缺失值。属性信息文件还包含关于哪些值对应于某些列中的未知值的信息。这些信息在某种程度上是有帮助的,所有错误的信息都可以转换为缺失值。

图 1:缺失值超过 30%的列

在清理了错误记录的值之后,下一步是处理丢失的值本身。对每列缺失值的百分比进行分析,以确定有多少列有缺失值,以及它们是否包含多少百分比。图 1 显示了缺失值超过 30%的列。在此分析之后,选择阈值 30 来删除列。随后,必须按行对缺失值进行分析,以移除具有缺失特征的观测值。这里,选择每个观测值缺失 50 个特征的阈值来删除行。在此分析之后,得到的形状是:

普通人群— (737288x356)

客户数据— (13426x356)(忽略额外的客户特定功能)

特征工程

有一些用数值编码的分类特征(事实上有很多,但为了简单起见,只给出了几个)。这些特征用二进制编码。此外,一些功能包含太多信息,例如,在一个单独的列中包含关于财务状况和年龄的信息。这种类型的特征被识别,或者被重新编码以包含更广泛的信息,或者被分成两列以分别包含两种特征。在属性信息文件的帮助下,任何包含超过 20 个类别的特征要么被丢弃,要么被重新构建成有用的东西。

由于许多要素包含转储到单个列中的分类值,这一步有助于简化后面步骤的数据。这一步产生了 353 个特征。

输入缺失值

即使在根据某个阈值删除了列和行之后,我们仍然会得到一些缺少值的数据。这个问题在简单估算器的帮助下得到解决,它用一些我们可以控制的值来填充缺失的数据。数值特征的一般方法是用中值或平均值估算缺失值。但是更常见的分类特征方法是用最常见的值进行估算。由于数据对应于总体,因此用最常见的值来估算缺失值更为敏感。

现在,数据是干净的,可以进行建模了,最后一步是缩放数据,即将所有要素纳入同一范围。这是使用标准的定标器来完成的。

使用无监督学习的客户细分

对于聚类分割,需要执行两个步骤。

  • 降维
  • 使聚集

降维

虽然我们有 353 个特征,但并不是所有的特征都有变化,也就是说,有些特征对所有人来说可能是相同的。我们可以浏览这里的所有特性,看看每个特性有多少唯一值,以选择具有所需变化的特性。但是更系统的方法是在删除任何列之前执行某种分析。因此,已经进行了主成分分析来分析主成分分析成分的解释方差。PCA 对数据应用线性变换以形成新的坐标系,使得新坐标系中的分量代表数据的变化。

图 2: PCA 解释的方差图

这种分析将帮助我们确定有多少特征具有足够的方差来解释数据中的变化。解释的方差图用于选择分量的数量,即缩减坐标空间中的维数。从上面的图中可以看出,在大约 150 个组件的帮助下,几乎 90%的差异都可以得到解释。现在,在 PCA 变换之后,我们剩下 150 个 PCA 分量,每个分量由主要特征之间的线性组合组成。

使聚集

降维之后,下一步就是把普通人群和客户人群划分成不同的细分。K-Means 聚类算法已被选为这项任务。因为它测量两个观察值之间的距离来分配一个聚类,所以它是简单的并且适合于这个任务。该算法将帮助我们在简化特征的帮助下将一般人群分成指定数量的聚类,并使用该聚类信息来了解一般人群和客户数据中的相似性。借助于肘形图,群集的数量被选择为“8”。

聚类分析

图 3:集群比例

普通人群和客户人群已经被分成了几个部分。图 3 显示了进入每个集群的人口比例。一般群体的聚类分布是均匀的,这意味着一般群体已被均匀地聚类成 8 个段。但客户群似乎来自“0”、“3”、“4”和“7”这几个类别。如图 4 所示,我们可以通过计算客户群和普通人群群的比例来进一步证实这一点。

图 4:集群比例比率

如图 4 所示,如果比例比大于 1,这意味着该集群在现有人口中拥有更多的客户,并有可能拥有更多的未来客户。如果比率小于 1,这意味着这些集群拥有未来客户的可能性最小。

还执行更详细的聚类分析,解释每个聚类和相应的组件。它记录在用于本项目的 jupyter 笔记本中。我不在这里解释,因为这篇博文已经太长了。

使用监督学习获取客户

在分析了一般人群和客户数据之后,了解应该关注哪些细分市场。我们可以进一步扩展这种分析,利用最大似然算法来进行决策。由于我们已经有了客户数据和一般人群数据,我们可以将它们组合起来形成训练数据,并训练 ML 模型来预测是否接近客户。

在这种情况下,使用给定的训练和测试数据进行监督学习。由于该问题是一个高度不平衡的分类,AUROC 分数已被选为评估标准。基线性能是用逻辑回归模型设置的,该模型在基于树的集成模型的帮助下得到进一步改进。AdaboostClassifier 和 XGBoostClassifier 是最终选定的模型,它们的预测被提交给 Kaggle,以便在只有两次提交的情况下(在提交之日)获得前 30%的位置。

图 5: Kaggle 排行榜

结论

使用无监督学习算法对普通人群和顾客人群进行了比较和分割。我们能够确定哪些集群有更多的客户,哪些是潜在的集群有可能的客户。我们还使用监督学习算法,根据人口统计数据预测未来可能的客户。

由此产生的分析产生了很好的结果,使我在竞赛领导委员会中名列前 30%。排行榜的最高分是 0.81063,和我达到的分数(0.80027)相差不远。数据准备步骤还有改进的余地。

项目报告中给出了对每个步骤以及算法和指标选择背后的原因的更全面的解释,并且所有步骤都记录在这个笔记本中。

最后,我要感谢 Arvato Financial Solutions 和 Udacity 提供了这个处理真实数据的绝佳机会。这帮助我获得了宝贵的经验,并帮助我使用和提高我的技能。

参考

  1. https://www . business 2 community . com/customer-experience/4-type-of-customer-segmentation-all-markets-should-know-02120397
  2. https://blog.alexa.com/types-of-market-segmentation/
  3. https://clever tap . com/blog/customer-segmentation-examples-for-better-mobile-marketing/
  4. https://www.shopify.com/encyclopedia/customer-segmentation
  5. https://www.liveagent.com/academy/customer-segmentation/
  6. https://www . data novia . com/en/lessons/determining-the-optimal-number-of-clusters-3-must-know-methods/
  7. https://towards data science . com/what-metrics-we-should-use-on-unbalanced-data-set-precision-recall-roc-e2e 79252 aeba

原载于 2020 年 4 月 16 日https://pranaymudukuru . github . io

Python 中的客户细分

原文:https://towardsdatascience.com/customer-segmentation-in-python-9c15acf6f945?source=collection_archive---------4-----------------------

无监督学习

基于 K-均值聚类算法的图像分割。

里卡多·戈麦斯·安吉尔在 Unsplash 上的照片

T4:假设我们有一家公司销售该产品,你想知道该产品的销售情况如何。

你有我们可以分析的数据,但是我们能做什么样的分析呢?

嗯,我们可以根据客户在市场上的购买行为对他们进行细分。

请记住,数据非常庞大,我们无法用肉眼来分析。我们将使用机器学习算法和计算能力。

本文将向您展示如何使用 Python 中的 K-Means 算法根据客户的行为对客户进行聚类。

我希望这篇文章能帮助你从准备数据到聚类,一步一步地进行客户细分。

行动(或活动、袭击)计划

在我们进入这个过程之前,我会简要地告诉你我们将采取什么样的步骤。

  • 收集数据
  • 创建最近频率货币(RFM)表
  • 管理偏斜度并衡量每个变量
  • 探索数据
  • 对数据进行聚类
  • 解读结果

分析

数据收集

在这一步中,我们将首先收集数据。对于这种情况,我们将从 UCI 机器学习中获取名为在线零售数据集的数据。

数据集本身是一个交易数据,包含一家英国在线零售商从 2010 年 12 月 1 日到 2011 年 12 月 9 日的交易。

每一行代表发生的交易。它包括产品名称、数量、价格和其他表示 ID 的列。

您可以从这里访问数据集。

这是数据集的大小。

(541909, 8)

在这种情况下,我们不使用所有的行。相反,我们将从数据集中抽取 10000 行作为样本,并假设这是客户进行的全部交易。

代码看起来会像这样,

**# Import The Libraries**
# ! pip install xlrd
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np**# Import The Dataset**
df = pd.read_excel('dataset.xlsx')
df = df[df['CustomerID'].notna()]**# Sample the dataset**
df_fix = df.sample(10000, random_state = 42)

这是数据集的一瞥,

创建 RFM 表

在我们对数据进行采样之后,我们将使数据更容易进行分析。

为了细分客户,我们可以使用一些指标,如客户上次购买产品的时间、客户购买产品的频率以及客户为产品支付的金额。我们将这种分割称为 RFM 分割。

为了制作 RFM 表,我们可以创建这些列,比如 Recency、Frequency 和 MonetaryValue 列。

要获得最近的天数列,我们可以用事务发生的日期减去快照日期。

要创建 frequency 列,我们可以计算每个客户的交易量。

最后,为了创建货币值列,我们可以对每个客户的所有交易进行求和。

代码看起来像这样,

**# Convert to show date only** from datetime import datetime
df_fix["InvoiceDate"] = df_fix["InvoiceDate"].dt.date**# Create TotalSum colummn**
df_fix["TotalSum"] = df_fix["Quantity"] * df_fix["UnitPrice"]**# Create date variable that records recency**
import datetime
snapshot_date = max(df_fix.InvoiceDate) + datetime.timedelta(days=1)**# Aggregate data by each customer**
customers = df_fix.groupby(['CustomerID']).agg({
    'InvoiceDate': lambda x: (snapshot_date - x.max()).days,
    'InvoiceNo': 'count',
    'TotalSum': 'sum'})**# Rename columns**
customers.rename(columns = {'InvoiceDate': 'Recency',
                            'InvoiceNo': 'Frequency',
                            'TotalSum': 'MonetaryValue'}, inplace=True)

这是数据集的一瞥,

目前,数据集由最近、频率和货币值列组成。但是我们还不能使用数据集,因为我们必须对数据进行更多的预处理。

管理偏斜度和缩放比例

我们必须确保数据符合这些假设,

数据应该满足假设,即变量没有偏斜,并且具有相同的均值和方差。

正因为如此,我们必须管理变量的偏斜度。

这是每个变量的可视化,

从左到右:最近、频率和货币值列

正如我们从上面看到的,我们必须转换数据,所以它有一个更对称的形式。

我们可以使用一些方法来管理偏度,它们是,

  • 日志转换
  • 平方根变换
  • box-cox 变换

注意:当且仅当变量只有正值时,我们才能使用转换。

下面是每个变量的可视化,有和没有转换。每个变量从左上顺时针方向显示了没有变换、对数变换、平方根变换和 box-cox 变换的图。

左:最近列,右:频率列

基于这种可视化,它显示了具有 box-cox 变换的变量显示出比其他变换更对称的形式。

为了确保这一点,我们使用 skew 函数计算每个变量。结果看起来像这样,

**variable, without, log, sqrt, box-cox transformations
Recency, 14.77, 0.85, 3.67, 0.16
Frequency, 0.93, -0.72, 0.32, -0.1**

下面是如何解读偏斜度值。如果该值接近 0,变量往往具有对称形式。然而,如果不是这样,变量就有偏斜。基于这种计算,我们使用使用 box-cox 变换的变量。

基于该计算,我们将利用使用 box-cox 变换的变量。MonetaryValue 变量除外,因为该变量包含负值。为了处理这个变量,我们可以对数据使用立方根变换,所以比较看起来像这样,

不含和含立方根变换

通过使用这种转换,我们将得到不那么扭曲的数据。偏斜度值从 16.63 下降到 1.16。因此,我们可以用这段代码转换 RFM 表,

from scipy import stats
customers_fix = pd.DataFrame()
customers_fix["Recency"] = stats.boxcox(customers['Recency'])[0]
customers_fix["Frequency"] = stats.boxcox(customers['Frequency'])[0]
customers_fix["MonetaryValue"] = pd.Series(np.cbrt(customers['MonetaryValue'])).values
customers_fix.tail()

它看起来会像这样,

我们现在能使用数据吗?还没有。如果我们再看一下这个图,每个变量都没有相同的均值和方差。我们必须把它正常化。为了规范化,我们可以使用 scikit-learn 库中的 StandardScaler 对象来实现。代码看起来会像这样,

**# Import library**
from sklearn.preprocessing import StandardScaler**# Initialize the Object**
scaler = StandardScaler()**# Fit and Transform The Data**
scaler.fit(customers_fix)
customers_normalized = scaler.transform(customers_fix)**# Assert that it has mean 0 and variance 1**
print(customers_normalized.mean(axis = 0).round(2)) **# [0\. -0\. 0.]** print(customers_normalized.std(axis = 0).round(2)) **# [1\. 1\. 1.]**

数据会像这样,

最后,我们可以使用这些数据进行聚类。

系统模型化

在我们对数据进行预处理之后,现在我们可以专注于建模了。为了从数据中进行分割,我们可以使用 K-Means 算法来实现。

K-Means 算法是一种无监督学习算法,它使用几何原理来确定哪个聚类属于数据。通过确定每个质心,我们计算到每个质心的距离。如果每个数据与另一个数据的距离最小,则该数据属于一个质心。如此重复,直到下一次总距离没有比之前有显著变化。

用 Python 实现 K-Means 很容易。我们可以使用 scikit 中的 KMeans 函数——学会做这件事。

为了使我们的聚类达到最佳性能,我们必须确定哪个超参数适合数据。为了确定哪个超参数最适合我们的模型和数据,我们可以使用肘方法来决定。代码看起来会像这样,

from sklearn.cluster import KMeanssse = {}
for k in range(1, 11):
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(customers_normalized)
    sse[k] = kmeans.inertia_ # SSE to closest cluster centroidplt.title('The Elbow Method')
plt.xlabel('k')
plt.ylabel('SSE')
sns.pointplot(x=list(sse.keys()), y=list(sse.values()))
plt.show()

这是结果,

如何解读剧情?x 轴是 k 的值,y 轴是数据的 SSE 值。我们将通过查看 k 值在下一个连续 k 值的线性趋势来选择最佳参数。

根据我们的观察,k 值为 3 是我们模型的最佳超参数,因为下一个 k 值往往具有线性趋势。因此,我们对数据的最佳模型是 K-Means,聚类数是 3

现在,我们可以用这段代码来拟合这个模型,

model = KMeans(n_clusters=3, random_state=42)
model.fit(customers_normalized)
model.labels_.shape

通过拟合模型,我们可以得到每个数据所属的聚类。借此,我们可以分析数据。

解释该部分

我们可以根据聚类来总结 RFM 表,并计算每个变量的平均值。代码看起来会像这样,

customers["Cluster"] = model.labels_
customers.groupby('Cluster').agg({
    'Recency':'mean',
    'Frequency':'mean',
    'MonetaryValue':['mean', 'count']}).round(2)

代码的输出如下所示,

汇总表

除此之外,我们可以使用蛇情节来分析片段。它需要标准化数据集和聚类标签。通过使用该图,我们可以很好地从数据中直观地了解集群之间的差异。我们可以通过使用这些代码来绘制图表,

**# Create the dataframe**
df_normalized = pd.DataFrame(customers_normalized, columns=['Recency', 'Frequency', 'MonetaryValue'])
df_normalized['ID'] = customers.index
df_normalized['Cluster'] = model.labels_**# Melt The Data**
df_nor_melt = pd.melt(df_normalized.reset_index(),
                      id_vars=['ID', 'Cluster'],
                      value_vars=['Recency','Frequency','MonetaryValue'],
                      var_name='Attribute',
                      value_name='Value')
df_nor_melt.head()**# Visualize it**
sns.lineplot('Attribute', 'Value', hue='Cluster', data=df_nor_melt)

这是结果,

蛇的阴谋

通过使用这个图,我们知道每个部分是如何不同的。它描述的比我们使用的汇总表更多。

我们推断,集群 0 是经常性的,花费更多,他们最近购买产品。因此,这可能是一群的忠实客户

然后,集群 1 的频率较低,花费较少,但他们最近购买了该产品。因此,它可能是新客户的集群。

最后,集群 2 的频率更低,花费更少,他们在旧时间购买产品。因此,这可能是一群被搅动的顾客

结论

总之,客户细分对于了解每个客户的特征是非常必要的。本文向您展示了如何使用 Python 实现它。希望这篇文章对你有用,可以落实到你的案例上。

如果你想知道代码是如何编写的,你可以查看这个谷歌实验室这里

参考

[1] Daqing C .,Sai L.S,和 kung g .在线零售业的数据挖掘:使用数据挖掘进行基于 RFM 模型的客户细分的案例研究 (2012),数据库营销和客户战略管理杂志
【2】mill man k . J,Aivazis M. 面向科学家和工程师的 Python(2011),科学中的计算&工程
【3】rade CIID处理偏斜数据的 3 大方法 (2020),走向数据科学。
【4】肘法求 k 中最优值 KMeans ,极客为极客。

感谢您阅读我的文章,您也可以在下面查看我以前的文章:

[## R 时间序列分析导论

从探索,到预测。使用印度尼西亚 2002 年 12 月至 2020 年 4 月的消费者价格指数(CPI)数据

towardsdatascience.com](/introduction-to-time-series-analysis-with-r-a2f97650baa3) [## R 中 ARIMA 模型的时间序列预测

从勘探到预测 1970 年至 2015 年的二氧化碳排放数据。

towardsdatascience.com](/time-series-forecasting-with-arima-model-in-r-77f4e2ae7abb) [## 企业家的数据工程

这是一家更加数据驱动的公司。

towardsdatascience.com](/data-engineering-for-entrepreneurs-fa10f9190831)

客户细分:K 均值聚类和 A/B 检验

原文:https://towardsdatascience.com/customer-segmentation-k-means-clustering-a-b-testing-bd26a94462dd?source=collection_archive---------17-----------------------

该项目旨在研究数字平台上的客户行为,在没有任何先验知识的情况下对客户进行分组,并进行 A/B 测试,以帮助提高业务绩效。

照片由 nrdUnsplash 上拍摄

语境

我在广告业工作了近 3 年,特别是数字媒体和表演,客户行为分析是我日常工作的核心内容之一。在不同分析平台(例如 Google Analytics、Adobe Analytics)的帮助下,我的生活变得比以前更加轻松,因为这些平台自带了内置的细分功能,可以跨维度和指标分析用户行为。

然而,尽管提供了便利,我还是希望 利用机器学习来进行客户细分 ,这可以 扩展并适用于 数据科学中的其他优化(例如 A/B 测试)。然后,我偶然发现了 Google Analytics 为 Kaggle 比赛提供的数据集,并决定将它用于这个项目。

如果您感兴趣,请随意查看数据集这里!注意数据集有几个子数据集, 每个子数据集都有超过 90 万行

A.解释性数据分析(EDA)

这始终是每个数据科学项目中必不可少的一步,以确保数据集干净并经过适当的预处理以用于建模。

首先,让我们导入所有必需的库并读取 csv 文件:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as snsdf_raw = pd.read_csv("google-analytics.csv")
df_raw.head()

1.展平 JSON 字段

正如您所看到的,上面的原始数据集有点“混乱”,根本不容易理解,因为一些变量被格式化为 JSON 字段,将不同子变量的不同值压缩到一个字段中。例如,对于地理网络变量,我们可以知道有几个子变量,如大陆、次大陆等。组合在一起。

多亏了 Kaggler 的帮助,我能够通过展平那些 JSON 字段,将这些变量转换成更容易理解的变量:

import os
import json
from pandas import json_normalizedef load_df(csv_path="google-analytics.csv", nrows=None):
    json_columns = ['device', 'geoNetwork', 'totals', 'trafficSource']
    df = pd.read_csv(csv_path, converters={column: json.loads for column in json_columns},dtype={'fullVisitorID':'str'}, nrows=nrows)
    for column in json_columns:
        column_converted = json_normalize(df[column])
        column_converted.columns = [f"{column}_{subcolumn}" for subcolumn in column_converted.columns]
        df = df.drop(column, axis=1).merge(column_converted, right_index=True, left_index=True)
    return df

在展平这些 JSON 字段后,我们能够看到一个更加清晰的数据集,尤其是那些被拆分为子变量的 JSON 变量(例如,设备被拆分为 device_browser、device_browserVersion 等。).

2.数据重新格式化和分组

对于这个项目,我选择了我认为对用户行为有更好影响或相关性的变量:

df = df.loc[:,['channelGrouping', 'date', 'fullVisitorId', 'sessionId', 'visitId', 'visitNumber', 'device_browser', 'device_operatingSystem', 'device_isMobile', 'geoNetwork_country', 'trafficSource_source', 'totals_visits', 'totals_hits', 'totals_pageviews', 'totals_bounces', 'totals_transactionRevenue']]df = df.fillna(value=0)
df.head()

接下来,由于新数据集的变量更少,但数据类型不同,我花了一些时间来分析每个变量,以确保数据在建模前“足够干净”。下面是一些要清理的未清理数据的快速示例:

**#Format the values**
df.channelGrouping.unique()
df.channelGrouping = df.channelGrouping.replace("(Other)", "Others")**#Convert boolean type to string** 
df.device_isMobile.unique()
df.device_isMobile = df.device_isMobile.astype(str)
df.loc[df.device_isMobile == "False", "device"] = "Desktop"
df.loc[df.device_isMobile == "True", "device"] = "Mobile"**#Categorize similar values**df['traffic_source'] = df.trafficSource_sourcemain_traffic_source = ["google","baidu","bing","yahoo",...., "pinterest","yandex"]df.traffic_source[df.traffic_source.str.contains("google")] = "google"
df.traffic_source[df.traffic_source.str.contains("baidu")] = "baidu"
df.traffic_source[df.traffic_source.str.contains("bing")] = "bing"
df.traffic_source[df.traffic_source.str.contains("yahoo")] = "yahoo"
.....
df.traffic_source[~df.traffic_source.isin(main_traffic_source)] = "Others"

重新格式化后,我发现 fullVisitorID 的唯一值少于数据集的总行数,这意味着记录了多个 full visitorid。因此,我继续按 fullVisitorID 对变量进行分组,并按收入进行排序:

df_groupby = df.groupby(['fullVisitorId', 'channelGrouping', 'geoNetwork_country', 'traffic_source', 'device', 'deviceBrowser', 'device_operatingSystem'])
               .agg({'totals_hits':'sum', 'totals_pageviews':'sum', 'totals_bounces':'sum','totals_transactionRevenue':'sum'})
               .reset_index()df_groupby = df_groupby.sort_values(by='totals_transactionRevenue', ascending=False).reset_index(drop=True)

df.groupby()和 df.sort_values()

3.异常值处理

任何 EDA 过程中不可忽视的最后一步是检测和处理数据集的异常值。原因是异常值,尤其是那些边缘极端的异常值,会影响机器学习模型的性能,大多数是负面的。也就是说,我们需要从数据集中移除这些异常值,或者转换它们(通过均值或模式)以使它们适合大多数数据点所在的范围:

**#Seaborn Boxplot to see how far outliers lie compared to the rest** sns.boxplot(df_groupby.totals_transactionRevenue)

sns.boxplot()

如您所见,大多数收入数据点都低于 200,000 美元,只有一个极端异常值接近 600,000 美元。如果我们不移除这个异常值,模型也会考虑它,从而产生不太客观的反映。

因此,让我们继续下去,并删除它,并请这样做,为其他变量。简单说明一下,有几种处理异常值(比如分位数间)的方法。然而,在我的例子中,只有一个,所以我只是继续定义我认为非常适合的范围:

df_groupby = df_groupby.loc[df_groupby.totals_transactionRevenue < 200000]

B.k 均值聚类

什么是 K 均值聚类,它如何帮助客户细分?

聚类是最著名的无监督学习技术,它通过识别相似的组/聚类,特别是借助 K-Means,在未标记的数据中发现结构。

K-Means 试图解决两个问题:(1) K: 我们期望在数据集中找到的聚类(组)的数量,以及(2) Means: 我们试图最小化的数据到每个聚类中心(质心)的平均距离。

此外,值得注意的一点是,K-Means 有几种变体,典型的有:

  1. init = 'random': 随机选择每个簇的质心
  2. init = 'k-means++': 随机选择第一个质心,其他质心尽可能远离第一个质心

在这个项目中,我将使用第二个选项来确保每个集群之间有很好的区分:

from sklearn.cluster import KMeansdata = df_groupby.iloc[:, 7:]kmeans = KMeans(n_clusters=3, init="k-means++")
kmeans.fit(data)labels = kmeans.predict(data)
labels = pd.DataFrame(data=labels, index = df_groupby.index, columns=["labels"])

在应用该算法之前,我们需要定义“ n_clusters ”,这是我们期望从建模中得到的组的数量。这种情况下,我随机放 n_clusters = 3。然后,我继续使用两个变量可视化数据集是如何分组的:收入和浏览量:

plt.scatter(df_kmeans.totals_transactionRevenue[df_kmeans.labels == 0],df_kmeans.totals_pageviews[df_kmeans.labels == 0], c='blue')plt.scatter(df_kmeans.totals_transactionRevenue[df_kmeans.labels == 1], df_kmeans.totals_pageviews[df_kmeans.labels == 1], c='green')plt.scatter(df_kmeans.totals_transactionRevenue[df_kmeans.labels == 2], df_kmeans.totals_pageviews[df_kmeans.labels == 2], c='orange')plt.show()

如你所见,x 轴代表收入数,而 y 轴代表浏览量。建模后,我们可以看出 3 个集群有一定程度的差异。然而,我不确定 3 是否是集群的“正确”数量。也就是说,我们可以依赖 K-Means 算法的估计量, inertia_ ,它是每个样本到质心的距离。特别是,在我的例子中,我们将比较范围从 1 到 10 的每个集群的惯性,并查看哪个是最低的以及我们应该走多远:

#Find the best number of clustersnum_clusters = [x for x in range(1,10)]
inertia = []for i in num_clusters:
    model = KMeans(n_clusters = i, init="k-means++")
    model.fit(data)
    inertia.append(model.inertia_)

plt.plot(num_clusters, inertia)
plt.show()

型号.惯性 _

从上面的图表中,惯性从第 4 个或第 5 个集群开始缓慢下降,这意味着这是我们可以获得的最低惯性,所以我决定使用“ n_clusters=4 ”:

plt.scatter(df_kmeans_n4.totals_pageviews[df_kmeans_n4.labels == 0], df_kmeans_n4.totals_transactionRevenue[df_kmeans_n4.labels == 0], c='blue')plt.scatter(df_kmeans_n4.totals_pageviews[df_kmeans_n4.labels == 1],
df_kmeans_n4.totals_transactionRevenue[df_kmeans_n4.labels == 1], c='green')plt.scatter(df_kmeans_n4.totals_pageviews[df_kmeans_n4.labels == 2],
df_kmeans_n4.totals_transactionRevenue[df_kmeans_n4.labels == 2], c='orange')plt.scatter(df_kmeans_n4.totals_pageviews[df_kmeans_n4.labels == 3],
df_kmeans_n4.totals_transactionRevenue[df_kmeans_n4.labels == 3], c='red')plt.xlabel("Page Views")
plt.ylabel("Revenue")plt.show()

将浏览量切换到 x 轴,将收入切换到 y 轴

这些集群现在看起来更容易区分了:

  1. 集群 0(蓝色):高浏览量,但几乎没有收入
  2. 集群 1(红色):中等浏览量,低收入
  3. 集群 2(橙色):中等浏览量,中等收入
  4. 集群 4(绿色):浏览量趋势不明朗,收入高

除了第 0 类和第 4 类(不清楚模式),它们超出了我们的控制,第 1 类和第 2 类可以在这里讲述一个故事,因为它们似乎有一些相似之处。

为了了解可能影响每个集群的因素,我按照通道、设备和操作系统对每个集群进行了划分:

群组 1

群组 2

如上所述,在群组 1 中,推荐渠道贡献的收入最高,其次是直接搜索和有机搜索。相比之下,在第 2 类中做出最大贡献的是 Direct。类似地,虽然 Macintosh 是集群 1 中最主要的设备,但集群 2 中的 Windows 实现了更高的收入。两个集群之间唯一的相似之处是设备浏览器,Chrome 浏览器被广泛使用。

瞧啊。这种进一步的细分有助于我们判断哪个因素(在本例中是渠道、设备浏览器、操作系统)更适合每个集群,因此我们可以更好地评估未来的投资!

C.通过假设检验进行 A/B 检验

什么是 A/B 检验,假设检验如何补充这一过程?

A/B 测试对于从事广告和媒体工作的人来说并不陌生,因为它是帮助以更高的成本效率提高性能的强大技术之一。特别是,A/B 测试将观众分为两组:测试与控制。然后,我们向测试组展示广告/展示不同的设计,只是为了看看两组之间是否有任何显著的差异:暴露组与未暴露组。

图片鸣谢:https://product Coalition . com/are-you-segmenting-your-a-b-test-results-c 5512 c 6 def 65?gi=7b445e5ef457

在广告中,市场上有许多不同的自动化工具,可以轻松地帮助一键完成 A/B 测试。然而,我仍然想在数据科学中尝试一种不同的方法来做同样的事情:假设检验。方法基本相同,假设检验比较零假设(H0)和替代假设(H1 ),看看两者之间是否有显著差异!

假设我开展了一项推广活动,向测试组展示了一则广告。下面是用假设检验来检验结果时需要遵循的步骤的快速总结:

  1. 样本量确定
  2. 先决条件:正态性和相关性检验
  3. 假设检验

对于第一步,我们可以依靠功效分析来确定从人群中抽取的样本量。功效分析需要 3 个参数:(1)效果大小,(2)功效和(3)α。如果你正在寻找关于如何进行功耗分析的细节,请 参考我前段时间写的一篇深入的文章

下面是每个参数的快速注释,便于您快速理解:

#Effect Size: (expected mean - actual mean) / actual_std
effect_size = (280000 - df_group1_ab.revenue.mean())/df_group1_ab.revenue.std() #set expected mean to $350,000
print(effect_size)#Power
power = 0.9 #the probability of rejecting the null hypothesis#Alpha
alpha = 0.05 #the error rate

准备好 3 个参数后,我们使用 TTestPower() 来确定样本大小:

import statsmodels.stats.power as smsn = sms.TTestPower().solve_power(effect_size=effect_size, power=power, alpha=alpha)print(n)

结果是 279,这意味着我们需要从每组中抽取 279 个数据点:测试组和对照组。由于我没有真实的数据,我使用 np.random.normal 来生成收入数据列表,在本例中,每组的样本量= 279:

#Take the samples out of each group: control vs testcontrol_sample = np.random.normal(control_rev.mean(), control_rev.std(), size=279)
test_sample = np.random.normal(test_rev.mean(), test_rev.std(), size=279)

转到第二步,我们需要确保样本(1)正态分布和(2)独立(不相关)。同样,如果您想更新一下本步骤中使用的测试,请参考我上面的文章。简而言之,我们将使用(1)夏皮罗作为正态性检验和(2)皮尔逊作为相关性检验。

#Step 2\. Pre-requisite: Normality, Correlationfrom scipy.stats import shapiro, pearsonrstat1, p1 = shapiro(control_sample)
stat2, p2 = shapiro(test_sample)print(p1, p2)stat3, p3 = pearsonr(control_sample, test_sample)
print(p3)

对照组和试验组的 Shapiro p 值分别为 0.129 和 0.539,p 值> 0.05。因此,我们不拒绝零假设,并且能够说 2 组是正态分布的。

皮尔逊的 p 值为 0.98,大于 0.05,意味着 2 组相互独立。

最后一步到了!由于有两个变量需要相互测试(测试组与对照组),我们使用 T-Test 来查看运行 A/B 测试后收入是否有任何显著差异:

#Step 3\. Hypothesis Testingfrom scipy.stats import ttest_indtstat, p4 = ttest_ind(control_sample, test_sample)
print(p4)

结果是 0.35,大于 0.05。因此,进行的 A/B 测试表明,接触广告的测试组并没有比没有接触广告的对照组表现出任何优势。

瞧啊。这个项目到此结束——客户细分和 A/B 测试!我希望这篇文章对你有用并且容易理解。

在不久的将来,请留意我的即将到来的数据科学和机器学习项目!与此同时,您可以在这里查看我的 Github 以获得完整的资源库:

github:【https://github.com/andrewnguyen07T2
LinkedIn:www.linkedin.com/in/andrewnguyen07

谢谢!

使用 Instacart 数据集进行客户细分

原文:https://towardsdatascience.com/customer-segmentation-using-the-instacart-dataset-17e24be9c0fe?source=collection_archive---------17-----------------------

当您想要的数据不存在时发挥创造力

照片由法比奥·布拉克特Unsplash 上拍摄

我最近有机会使用来自 Instacart (via Kaggle) 的数据集完成了一个开放式数据分析项目。经过一番探索,我决定尝试客户细分。幸运的是,我找到了 Tern Poh Lim 的一篇文章,这篇文章为我如何做到这一点提供了灵感生成了一些方便的可视化工具来帮助我交流我的发现。在这篇文章中,我将介绍我是如何在 Instacart 数据集上采用 RFM(近期、频率、货币)分析进行客户细分的。由于数据集实际上不包含时间戳或任何关于收入的信息,我必须有点创意!

看看那些购物车

照片由 Alexandru TuguiUnsplash 上拍摄

如果你不熟悉的话, Instacart 是一个杂货店购物服务。用户通过应用程序订购食品,就像其他零工经济公司一样,自由职业者“购物者”负责完成用户订单。 Instacart 市场购物篮分析数据集是为特定应用而设计的:试图预测客户未来会再次订购哪些商品。如果您查看 Kaggle 上的文档,您会看到数据集包含以下类型的信息:

  • 每个订单的记录,包括星期几和小时(但没有实际的时间戳);
  • 每个订单中每个产品的记录,以及每个项目添加到给定订单中的顺序,以及该项目先前是否由同一客户订购的指示;和
  • 每个产品的名称、通道和部门。

这些数据已经完全匿名化,因此除了用户 ID 和订单历史记录之外,没有关于用户的任何信息—没有位置数据、实际订单日期或订单的货币价值。

这一点很重要,因为这些缺失的信息类型对业务分析非常重要。公司非常想知道用户最近是否活跃,他们在过去一天/一周/一个月/一个季度的活跃程度,以及他们对公司的货币价值。如果我想用这个数据集进行客户细分,我必须找到一个创造性的解决方案。

客户细分:基础知识

照片由德鲁·比默Unsplash 上拍摄

简单来说,客户细分意味着根据客户的真实或可能行为将他们分类,以便公司能够更有效地与他们合作。例如,一家公司可以向其最忠实的客户提供一种促销或折扣,而向新客户或不经常光顾的客户提供不同的激励。

进行客户细分的典型方法是进行 RFM 分析。(这是对 RFM 分析的一个很好的介绍。)RFM 代表“最近性、频率、金钱”,从公司的角度来看,代表了客户的一些最重要的属性。为了进行这种分析,您需要收集每个客户的相关数据,并根据每个 RFM 变量的相似值将客户分组。这背后的数学可能更复杂或更简单,这取决于您是否希望对 RFM 变量进行不同的加权。

Tern Poh Lim 的文章概述了如何使用 k-means 对客户进行聚类分析。更好的是,他指出,你可以迭代地使用 k-means 来计算要使用的最佳聚类数,从而消除聚类过程中的大量猜测。正如您将在下面看到的,我改编了他的一些代码,使用不同数量的聚类的剪影分数来生成肘图,并生成蛇图来总结每个聚类的属性。但我已经超越自我了!首先,让我们看看我对 Instacart 客户进行细分的总体方法。

走向细分的步骤

我采取了四个基本步骤来细分 Instacart 客户:

  • 设计一些功能来取代 RFM,因为我没有这些变量的正确数据;
  • 使用肘形图确定要计算的最佳聚类数;
  • 创建 TSNE 图并检查聚类的可分性;
  • 描述每个集群的关键属性。

步骤 1:特征工程

在缺乏适当的数据进行 RFM 分析的情况下,我不得不创建一些功能来捕捉用户行为的类似方面。经过一些实验,我发现了三个与 RFM 非常相似的特性:

  • 每个客户的订单总数;
  • 每个客户的订单之间的平均延迟(天数);和
  • 每位客户的订单(产品)平均规模。

总订单和每个客户的平均延迟类似于近期和频率;他们捕获了客户使用 Instacart 的次数(尽管在这种情况下,使用分布在一个不确定的时间段内)。每位客户的平均订单规模是货币价值的一种代表。虽然我不确定 Instacart 究竟是如何评估送货和服务费的,但我做了一个大致的假设,即订单的大小可能与其货币价值有关(至少它的大小是我可以实际测量的!).即使我的功能没有完美地映射到 RFM,它们仍然捕捉到了许多关于客户如何使用 Instacart 的重要信息。

所有功能都已标准化,订单数量也已对数转换。

因为我要将这些特征传递给 k-means 算法,所以我需要注意非正态分布和异常值,因为聚类很容易受到这两种情况的影响。当我检查我的三个特性的分布时,每个客户的订单数显示了一个很强的正偏态。我使用了对数转换来解决这个问题。然后我标准化了所有三个特性(使用 sk learn . preprocessing . standard scaler ),以减轻任何剩余异常值的影响。就这样,我为下一步做好了准备!

步骤 2:确定最佳 k

K-means 可以把你的客户进行聚类排序,但是你要告诉它你想要多少个聚类。这可能很棘手。两个集群有意义吗?10 点怎么样?通过测试 k 的一组值,我们可以更清楚地了解有多少聚类真正适合我们的数据。

我们可以使用几个指标来评估 k 聚类与给定数据集的吻合程度。对于我的项目,我使用了两个指标:失真分数轮廓分数

失真分数有点像残差平方和;它测量一个簇内的误差,或者每个数据点与其指定簇的质心之间的距离。较低的失真分数意味着更紧密的聚类,这意味着该聚类中的客户有很多共同点。

剪影得分将任何给定数据点与其指定聚类中心之间的距离与该数据点与其他聚类中心之间的距离进行比较。基本上,剪影分数是问,“这个点实际上更接近其他一些集群的中心吗?”同样,我们希望该值较低,这意味着我们的集群在向量空间中更紧密,彼此之间也更远。

我将这两个指标放在肘图中,肘图显示了具有不同数量的聚类的模型的分数。我任意选择了 2 到 10 个集群进行尝试。两个图都显示了在 4 个集群的得分(或肘部)的巨大变化。

Tern Poh Lim 的文章中,我了解到这是一种常见的做法,不仅要用你最好的 k ,还要用 k — 1 和 k + 1。这三个选项中的一个可能会给你最可分离的集群,这就是你想要的。

步骤 3:检查聚类的可分性

我在这一步寻找的是尽可能少重叠的集群。任何时候两个集群彼此非常接近,都有可能靠近一个集群边缘的任何一个客户更适合相邻的集群。你知道,我们不想向 30 岁以下的顾客发送关于老年人折扣的电子邮件!越容易画一条直线来分隔我们的聚类,我们的聚类分配就越可能准确。TSNE 图获取了我们所知道的关于每个客户的一切信息,并将其缩减为二维,这样我们就可以很容易地看到各个集群之间的关系。看看这个:

当只有 3 个集群时,它们看起来很容易分开(而且相当均衡——没有一个集群比其他集群大很多)。4 个集群中的两个比我希望的要重叠一些,5 个集群到处都是。看起来 3 个集群是该客户群和这些功能的最佳选择。

步骤 4:描述每个集群

使用 k = 3,我使用 k-means 将每个客户分配到一个集群。现在怎么办?嗯,你可以总结每个集群的每个特性的价值,从而了解该集群的购买习惯。再次遵循 Tern Poh Lim 的文章,我使用了一个“蛇图”(一个 Seaborn 点图)来可视化每个集群的三个特征的平均值。情节是这样:

我们可以用这些信息做什么?以下是我根据这个情节给营销团队的建议:

  • 集群 0:这些是我们最喜欢的客户!他们大量使用 Instacart,做中型订单。针对这些客户的营销可以侧重于保持他们的忠诚度,同时鼓励他们下订单,为公司带来更多收入(无论这意味着更多的商品、更贵的商品等。).
  • 集群 1:这些客户不经常使用 Instacart,但当他们使用时,他们会下大订单。当然,我们可以专注于将他们转化为更频繁的用户,根据 Instacart 从订单中产生收入的确切方式,我们可能会促使他们做出更频繁、更小的订单,或者继续做出那些大订单。
  • 第 2 组:这是我们最有改进空间的部分。他们尝试过 Instacart,但不经常使用,购买的物品也不多。针对这些人的营销策略可以侧重于增加订单频率和/或数量。

我希望我已经说服你,即使没有通常用于客户细分的数据,你也可以获得一些关于客户的非常有用的见解。你可以在我的 GitHub 上查看这个项目的所有代码。对 Tern Poh Lim 为这个项目的灵感(和许多有用的代码)最后一次大喊!

基于 K 均值聚类的客户细分

原文:https://towardsdatascience.com/customer-segmentation-with-kmeans-e499f4ebbd3d?source=collection_archive---------16-----------------------

营销活动不再采用一刀切的方式

照片由汉娜·林Unsplash 上拍摄

并非所有的顾客都是平等的。—我(还有许多其他人)

你永远不会像对你的伴侣那样对你的父母说话,也不会像对你的经理那样对你的孩子说话。那么,为什么你的营销团队在你的营销材料中使用一刀切的语言呢?

利用机器学习和人工智能处理大量的消费者历史、网络流量和产品评论,可以对营销活动产生重大影响。通过利用统计和分析工具的力量,可以根据三个简单的行为特征将客户划分为不同的群体,从而影响多渠道营销活动中使用的语言,并提高点击率和转化率。

你越了解你的顾客,你就越富裕。

作为客户,你不希望被视为达到目的的手段。你想成为社区的一员。作为一名零售商,你的工作是了解你的顾客,并告诉他们你对他们的了解。不要被动,了解他们的痛点,了解他们的购买习惯,建立信任。收入也会随之而来。

市场细分和 RFM 模型

一般来说,有四种方法来划分你的消费群:

  • 人口统计—年龄、性别、社会经济地位
  • 地理——他们在世界的什么地方?
  • 心理分析——寻找结婚戒指,计划买房子
  • 行为——一旦你的客户到达你的网站,他们会做什么?

谷歌的 BigQuery API 允许你对谷歌分析数据进行类似 SQL 的查询。如果你通过谷歌分析账户进行电子商务跟踪,你就可以获得客户的行为数据。该研究是在 2016 年 8 月至 2017 年 8 月期间对谷歌商品商店的数据进行的。在此期间,超过 740,000 名不同的人访问了 merch 商店,购买了 11,500 件商品,总价值超过 200,000 美元。

为了补充我们从谷歌商品商店获得的网络数据,我们将设计一些功能,以便根据 RFM 模型为每个客户“打分”。该技术采用最近一次购买的最近度(R ),所有购买的频率(F)或计数减 1,以及由平均订单金额定义的货币值(M)。

RFM 特色工程

为了对数据进行分段,您需要从三列开始:唯一的客户 id、交易日期和交易金额。我用这个函数将谷歌商店的数据处理成一种我们可以用来建模的格式

一旦我们通过这个函数运行我们的数据框架,我们就剩下以下信息:

值得注意的是,你的网站可能也有不购物的访问者,但是这种细分方法是针对已经转化的客户的。另一项研究可以——也应该——对那些不购买的人的行为进行研究,这样你就可以提高网站的转化能力。

基于 Kmeans 的无监督机器学习

既然我们的数据已准备好进行聚类,我们将测试几个聚类级别并比较肘形图中的误差平方和,以确定对每个要素单独进行聚类的最佳级别。

看起来,频率开始在五个集群水平,最近在四或五,收入在四或五。根据您的业务模型,您可能有理由选择较低或较高数量的集群。经过几次反复,我决定了五个频率、四个最近和五个收入。

从这里开始,我们将需要一些辅助函数来从最差到最好对集群进行排序,并为每个数据点分配相应的集群。

结果如下:

  • 频率——绝大多数客户属于较低的类别,在 3 到 4 之间有一个巨大的跳跃,只有一个客户购买超过 15 次
  • 最近——大多数客户都很不活跃(你真正需要多少件谷歌 t 恤?)最近的窗口变得越大,聚类分配越好。
  • 收入——绝大多数消费者平均在谷歌商品商店购买了价值 17 到 19 美元的商品。这五个收入群分布相当均匀,平均订单支出不超过 23 美元。

我们将通过合计每个聚类的得分来确定总体得分,并由此确定细分分层。

rfm_df[‘OverallScore’] = rfm_df[‘RecencyCluster’] + rfm_df[‘FrequencyCluster’] + rfm_df[‘RevenueCluster’]rfm_df.groupby(‘OverallScore’)[‘Recency’,’Frequency’,’logRevenue’].mean()

根据你的商业模式,你可能已经有了一定的细分市场。在这里,我把他们分成三组。不活跃、
不频繁、低消费的客户是低价值客户,中值客户高于平均收入,平均收入高于平均收入,最近消费频率高于平均收入,高价值客户属于至少两个特征的上层客户。

# Naming and defining segments
rfm_df[‘Segment’] = 0
rfm_df.loc[rfm_df[‘OverallScore’]>4,’Segment’] = 1 
rfm_df.loc[rfm_df[‘OverallScore’]>6,’Segment’] = 2

现在来看看每个集群,看看我们做得有多好:

看看那些轮廓优美的集群!

从该图中,我们可以看到,有些客户并没有花很多钱,但是经常访问该网站,并且最近进行了购买,这也属于高价值类别。分数似乎被非常不频繁的购买或很久以前的最后一次购买拉低了。

从这里,你可以将这些信息传递给你的营销团队,或者如果你是营销团队,使用这些信息为针对每个客户特定购买行为的电子邮件营销活动或广告设计语言。您已经播下了种子,现在看看您的收入如何增长吧!

基于机器学习的客户细分

原文:https://towardsdatascience.com/customer-segmentation-with-machine-learning-a0ac8c3d4d84?source=collection_archive---------1-----------------------

机器学习

K-means 算法应用于现实世界的电子商务销售数据

图怀亚特Unsplash 上拍摄

想象一下,你对待你每天购物的杂货店老板,就像你对待你的另一半一样。开始的时候可能会很有趣,但是也可能会导致灾难性的情况。同样,对一家公司来说,以同样的方式管理与每个客户的关系也是不利的。

客户细分使公司能够定制与客户的关系,就像我们在日常生活中所做的那样。

当你进行客户细分时,你会发现每个客户的行为和需求都有相似的特征。然后,将它们归纳成组,以满足不同策略的需求。此外,这些策略可以作为

  • 针对特定群体的营销活动
  • 推出符合客户需求的功能
  • 产品路线图的开发

市场上有不同的产品/解决方案,从套装软件到 CRM 产品。今天我就用 Python 来应用一个无监督的机器学习算法

这个从 2018 年 11 月到 2019 年 4 月的数据集是由一家电子商务公司提供的实际销售数据。这是提供给我的一个采访案例研究。

是的,他们有一个令人惊讶的面试过程,但更多的在那之后,在这篇文章的结尾。我也没有得到这个角色,主要是因为远程就业后勤,但这是另一个故事了。

我将通过以下步骤对数据集应用 K 均值聚类。

  1. 商业案例
  2. 数据准备
  3. 基于 K-均值聚类的分割
  4. 超参数调谐
  5. 结果的可视化和解释

在这个过程中,我将解释 K-means 聚类是如何工作的。最后,我将为形成的细分市场提供具体的策略。

出于保密原因,我对数据进行了匿名处理。

你可以按照笔记本上的步骤进行:

[## nbviewer 笔记本

客户细分将使用 scikit-learn 的 K-means 聚类应用于电子商务客户数据库。它…

nbviewer.jupyter.org](https://nbviewer.jupyter.org/github/cereniyim/Customer-Segmentation-Unsupervised-ML-Model/blob/0418ed702b0b8f87b472d68971c84a4913fa956e/Customer_Segmentation_Kmeans_Clustering.ipynb)

…并在这里 找到 GitHub 库

1.商业案例

在案例研究中,我从不同方面形象化了客户行为和特征。更进一步,我将围绕这个问题形成商业案例:能否将客户群分组以发展定制关系?

我将从行为角度(替代方法可以是地理或人口统计学角度)探讨这个问题,以更好地了解顾客的消费和订购习惯,其特征如下:订购的产品数量、平均退货率和总消费。

2.数据准备

原始数据集中大约有 25000 个不同的客户及其订单信息:

数据集格式良好,没有 NA 值。所以,我们可以从形成特征开始。将根据customer_id计算 3 个特征,它们将在后面的步骤中帮助我们进行可视化(使用 Plotly 库)和算法解释。数据准备将由熊猫熊猫完成。

  • 订购产品数量:通过以下函数计算客户订购的product_type:

  • 平均退货率:客户所有订单的平均returned_item_quantityordered_item_quantity之比。

  • 总支出:总销售额的总和,是税后和退货后的最终金额。

计算后,3 个特征合并到customers数据框中:

我们来看看特性的个体分布:

所有 3 个分布都是正的偏斜分布。订购产品呈幂律分布,99%的顾客平均退货率为 0。

3 特性具有不同的范围,在[1,13]、[0,1]和[0,1000]之间变化,这是一个重要的观察结果,表明特性需要缩放!

缩放:

K-means 算法将customers数据帧中的每一行解释为三维空间中的一个点。当对它们进行分组时,它使用数据点和组中心之间的欧几里德距离。由于范围变化很大,算法的性能可能很差,无法按预期形成分组。

为了使 K-means 有效执行,我们将使用对数变换来缩放数据,对数变换是一种适用于倾斜数据的变换。这将按比例缩小我们的数据分布的 3D 空间,同时保持点之间的邻近性。

应用上述函数后, customers 数据帧准备好送入 K-means 聚类:

3.基于 K-均值聚类的分割

我们将使用 scikit-learn 中的 K-means 算法。我们先来了解一下算法会如何形成客户群体:

  1. 随机或智能初始化 k = n 个质心 = 簇数
  2. 基于欧几里德距离将每个数据点分配到最近的质心,从而形成组
  3. 将中心移动到聚类中所有点的平均值

重复步骤 2 和 3,直到收敛

k-表示 n 个质心=3 的作用中。来源:维基媒体

运行步骤至时,该算法会检查每个聚类的聚类点和中心之间的距离平方和。从数学上来说,它试图最小化—优化每个簇 簇内距离平方和惯性

聚类内距离平方和或惯性的数学表达式,其中 X 是聚类中的点,并且是当前质心

惯性 值不再最小化时,算法收敛。因此,迭代停止。

from sklearn.cluster import Kmeans
kmeans_model = KMeans(init='k-means++', 
                      max_iter=500, 
                      random_state=42)
  • 带有k-means++init参数允许算法灵活地放置初始中心,而不是随机的。
  • max_iter是算法在单次运行中的最大迭代次数,默认值为 300。
  • random_state保证模型结果的再现性。

该算法易于理解,在计算时间方面非常适合大数据集,并且保证了收敛性。然而,当随机初始化质心时,算法可能不会以最佳方式将点分配给组。

一个重要的考虑是选择 k 。换句话说,应该组成多少个小组?例如,上面应用的 K-means 使用 k=8 作为默认值。

下一步,我们将选择 K 均值中最重要的超参数 k

4.超参数调谐

在选择 k、时,我们将使用肘方法来决定 K 均值、惯性的优化标准。我们要用 k 值 1 到 15 建立不同的 K 均值模型,并保存相应的惯性值。

results = make_list_of_K(15, customers.iloc[:,3:])
k_values_distances = pd.DataFrame({"clusters": clusters,
                                   "within cluster sum of squared distances": results})

当我们绘制惯性k 值时:**

对于肘法,我们将选择惯性下降稳定的 k 值。

k=1 惯性最大时,意味着数据尚未分组。惯性急剧下降,直到 k=2。k=24、之间,曲线继续快速下降。

k=4 处,下降稳定并继续直线下降,在 k=4 处形成一个弯头。这就指出了客户群的最佳数量是 4

5.结果的可视化和解释

让我们将 k=4 插入 K-means,想象一下客户群是如何创建的:

# create clustering model with optimal k=4
updated_kmeans_model = KMeans(n_clusters = 4, 
                              init='k-means++', 
                              max_iter=500, 
                              random_state=42)updated_kmeans_model.fit_predict(customers.iloc[:,3:])

每个数据点的值可以在这里交互观察

数据点显示在球体中,每组的质心用立方体显示。4 客户群如下:

****蓝色:至少订购了一种产品,最高总消费为 100 英镑,平均退货率最高的客户。他们可能是电子商务网站的新来者。

****红色:订购 1 至 4 件商品,平均总消费 150,最高退货率 0.5 的客户。

****紫色:订购 1 至 4 件商品,平均总消费 300,最高退货率 0.5 的客户。

****绿色:订购 1 至 13 件商品,平均总消费 600,平均退货率为 0 的客户。它为公司创造了最有利的客户群。

让我们来看看每个组中有多少客户——称为集群数量:

总体策略是保留最有利的客户群——绿色客户群,同时将蓝色客户群转移到红色和紫色区域。

Blue group 占所有客户的 42%,在该客户群中实现的任何改进都将显著增加收入。消除高回报率和提供礼品卡可以将这个客户群体转移到低平均回报率和高总消费领域。如果我们假设他们是新来的,礼品卡可以加速他们的回头客。

红紫集团合计占所有客户的 50%。从平均退货率和订购产品的角度来看,它们表现出相同的特征,但与总支出不同。这些群体可以定义为已经知道该品牌并订购多种产品的人。这些客户可以通过一些专门的沟通和折扣来了解最新的品牌信息。

绿色客户群占所有客户的 8%,形成对品牌最有利的客户群。他们订购多种产品,并且极有可能保留这些产品。为了保持并可能扩大这个群体,特价和产品发布会可能会有所帮助。此外,它们可以吸引新客户,影响客户群的扩大。

结论

我们从行为角度研究了客户细分问题,包括每位客户订购的产品数量、平均退货率和总支出。使用 3 个特性有助于我们理解和可视化模型。

总而言之,数据集易于执行无监督的机器学习问题。起初,我们只有带有订单信息的客户数据,不知道他们是否属于任何组。使用 K-means 聚类,可以发现数据中的模式,并进一步扩展到组中。我们为形成的群体制定了策略,从最初是尘云的数据集中获取意义。

关于面试;我喜欢参与案例研究,面试过程是我迄今为止最棒的面试经历。这是对我在一个典型的、实际的任务中的技能的一个非常现实的评估,我会经常执行这个任务。这使得整个过程非常简单有趣。我希望这种实用的数据科学面试成为主流,让应聘者和雇主都受益。

感谢您的阅读,对于评论或建设性的反馈,您可以通过回复、 TwitterLinkedin 联系我!

看过此物品的顾客也看过…

原文:https://towardsdatascience.com/customers-who-viewed-this-item-also-viewed-40026c4eb700?source=collection_archive---------28-----------------------

每次你完成一部关于网飞的电影,你都会看到一个新电影的推荐。每次打开 YouTube 都会看到一些推荐视频,因为你看了类似的东西。我最喜欢的一个是亚马逊的推荐算法,因为你甚至不需要购买或查看某样东西就可以看到它是推荐。如果你谈到了手机附近的一本书,你会在亚马逊的建议中看到它。就这么简单!

感谢查尔斯·德鲁维奥的照片

这些推荐功能,也称为推荐系统,在过去十年中成为一种有用和流行的机器学习算法。其背后的算法实际上并不令人困惑。例如,该系统可以基于过去的购买或评论推荐一个人可能感兴趣的产品。为了理解细节,我们应该熟悉余弦相似度的概念。

余弦相似度

余弦相似度表示一个人的品味或偏好在多大程度上可以用另一个人的选择来描述。在数学中,它计算两个向量的余弦值。在这种情况下,向量由人们的选择来表示。我们发现余弦相似性,我们计算 2 个向量的单位向量的点积。

假设人 A 的偏好用向量 A 表示,人 B 的偏好用向量 B 表示。

余弦相似度是介于-1 和 1 之间的数字。如果 A 人和 B 人的选择完全相同,他们的余弦相似度为 1。如果它们完全不相似,它们的余弦相似度是-1。这是一个重要的细节,因为-1 余弦同样能告诉我们这两个人的偏好。这意味着他们喜欢彼此相反的产品。人 A 喜欢某部电影,而人 B 不喜欢同一部电影。在-1 余弦相似度中仍然有信息。然而,如果余弦相似度为 0,人 A 的选择没有给出关于人 B 的偏好的信息。

一旦我们理解了余弦相似性的概念,推荐系统就更有意义了。通常有两种常见类型的推荐系统。这些是基于内容的推荐系统和协作推荐系统。

照片由 Unsplash 上的 Nordwood Themes 拍摄

基于内容推荐系统

在基于内容的推荐系统中,目标是对相似的实例(电影、书籍等)进行分组。)根据它们的产品特性分成不同的组。聚类是基于产品的实际特征建立的。

在上面的例子中,不管用户怎么看,每部电影都有不同的特点。在基于内容的推荐系统中,用户(顾客)并不扮演积极的角色。这里我们的向量是表格的行。我们找到每个向量与其他向量的余弦相似性。

在实践中,我们从特征工程开始,使每个记录成为一个数值,然后我们类似地计算余弦。余弦相似度告诉我们最相似的向量。使用这种方法,当您插入一个新的电影名称时,它将返回与产品功能最相似的电影。

协同推荐系统

协同推荐系统将用户考虑在内。用户的行为是产生推荐的一个非常重要的输入。该算法利用用户-产品交互。协同推荐系统也分为两个主要的模型。

  1. 基于用户的协同推荐系统
  2. 基于项目的协同推荐系统

基于用户的协同推荐系统基于用户的购买或评级,使用余弦相似性数学对用户进行聚类。

在上面的例子中,我们看到了 4 部电影的用户评分。用户 1 和用户 2 之间有相似之处,因为他们都喜欢和不喜欢相同的电影。基于这个事实,我们可以向用户 1 推荐《十二怒汉》,因为用户 2 喜欢。此外,我们不应该向用户 5 推荐“教父”,因为用户 4 不喜欢它,并且他们有相似的偏好。

这种推荐系统的一个缺点是它完全依赖于客户的评分。不是每个顾客都喜欢给产品评级。此外,众所周知,有负面经历的人比有正面经历的人更有可能提交评级分数。这就是为什么许多公司从基于评级的推荐系统转向基于购买的推荐系统。基于购买的系统更可靠,因为它们考虑了用户的实际行为。此外,收集数据也容易得多。让我们看看下面的例子:

基于购买决策,我们可以向用户 A 推荐“Forest Gump ”,因为他的购买行为与用户 B 相似,并且用户 B 观看了它。这种特殊型号与“顾客购买这种产品同时也购买了……”的概念相同。

基于项目的协同推荐系统非常类似于基于用户的协同推荐系统。不同的是矩阵是转置的。在基于项目的协同推荐系统中,我们查看产品屏幕,发现电影的余弦相似性。

在上面的例子中,用户用 1-5 的尺度给电影评分。电影“12 个愤怒的人”可以呈现给用户 1,因为这部电影已经从相同的人那里收到了与“搏击俱乐部”相同的反应。如果用户 1 喜欢“搏击俱乐部”,他也可能喜欢“12 个愤怒的人”。

排除用户 1;《搏击俱乐部》的 s 向量= [ 4,3,4,4]和《十二怒汉》的 s 向量= [ 5,3,4,4]非常相似。

推荐系统在 Python 中的实现

实际上,当我们创建一个推荐系统时,我们首先创建一个数据透视表。在 Python 中,我们使用。pivot_table( ) 函数就是这么做的。例如基于项目的推荐系统,产品的名称(可以是电影、书籍或音乐名称等。)将是我们的数据帧的索引,用户信息(名称或 Id,取决于您的数据集)将在列中。这个。pivot_table( ) 函数将返回一个巨大的表格,向我们展示每个用户对每部电影的行为。当然,不是每个人对所有产品都有一种行为(这种行为意味着评级,或购买信息),这就是为什么我们会在数据透视表中看到许多 NaN 或“0”值。这就是稀疏矩阵派上用场的地方。快速提醒;稀疏矩阵获取数据帧,并通过移除所有“0”值将其压缩成更轻的格式。我们的数据帧的信息没有改变,但它在计算机中占用的空间要少得多,因为稀疏矩阵没有零的负担。这里我们可以认为“0”和 NaN 值携带的信息相等;因为当数据是二进制的时候,“0”意味着没有行为发生或者没有购买发生。因此,在使用稀疏矩阵之前,可以将“NaN”值转换为“0”。

一旦你创建了稀疏矩阵,你需要做的就是计算余弦相似度。Scikit-Learn 库有一个 pairwise_distances 函数,可以为我们计算余弦。该函数返回一个正方形矩阵,将每个产品与其他产品进行比较。

这里我们必须注意到,我们的推荐者矩阵不再有用户信息。当我们的稀疏矩阵携带用户输入时,成对距离函数将其转换成推荐者矩阵。推荐矩阵是一个方阵,它只有每个产品之间的余弦相似性信息。

该推荐者矩阵也没有项目标题。我们可以从 pivot_table 中获取这些标题,并将其与推荐者矩阵组合在一个大的快乐数据框架中。

这里需要注意的另一个重要事项是,与实际的余弦相似性值不同,scipy 库的。pairwise _ distance()函数以不同的比例返回相似性数字。通常,余弦相似标度在-1 和 1 之间。如前所述,余弦相似度=1 意味着项目具有非常相似的接受度,余弦相似度= -1 意味着项目具有完全相反的接受度。在的结果中。pairwise _ distance()函数,但这是完全不同的。当我们在推荐矩阵中看到“0”时,我们知道这些项目是相似的,当我们看到“1”时,我们知道这些项目非常不相似。因此,scipy . pairwise _ distances()函数的余弦值介于 0 和 1 之间。

希望这篇文章有助于你理解推荐系统背后的算法。如果您有任何问题或意见,请在下面留下您的评论。

定制 Vim 以充分利用它

原文:https://towardsdatascience.com/customising-vim-to-get-the-best-out-of-it-a5a4dae02562?source=collection_archive---------14-----------------------

.vimrc中设置默认值以提高效率

照片由 Marius NiveriUnsplash 上拍摄

Vim 的命令是这样的,它的全部功能仅使用键盘就能实现。但是这并不容易。需要一段时间来适应。毕竟是各种程序员都信誓旦旦的编辑器。

作为刚接触 Vim 的程序员,我们经常在终端中偶然发现它,完全被新的编辑界面所迷惑,感觉完全不知所措,敲打键盘键以弄清楚如何管理 Vim。难怪“如何退出 Vim”一直是堆栈溢出过去最受欢迎的问题之一。

当开始使用 Vim 时,真正重要的是首先创造一个让人们使用 Vim 感到舒适的环境。如果没有配置任何默认设置,Vim 看起来一点也不吸引人,您也不太可能使用 Vim。这意味着您最终会错过这个极其强大的模态编辑器,这对程序员来说是一个巨大的损失。

Vim 是高度可定制的,它应该可以帮助你编辑;而不是相反。因此,让我们进入一些设置,让 Vim 有宾至如归的感觉。

  • syntax on:开启语法高亮显示。毫无疑问,需要打开这个设置。
  • colorscheme desert:该设置使用“沙漠”配色方案突出显示语法。我个人很喜欢。
    获取所有可用配色方案的列表:
    ls -l /usr/share/vim/vim*/colors/
    有很多选项可供选择!我在另一篇博客文章这里中更详细地讨论了语法突出显示(在标题 语法突出显示 下)。
  • set showmatch:当文本指示器在匹配的大括号上时,显示匹配的大括号
  • set number:显示行号
  • set relativenumber:在numberrelativenumber都设置的情况下,当前行显示该行的实际编号,其上下的行相对于当前行进行编号。这有助于了解在行与行之间上下跳动的确切数字。
  • set ignorecase:该设置使搜索不区分大小写
  • set smartcase:该设置使搜索不区分大小写,但如果搜索包含任何大写字母,则区分大小写。
  • set incsearch:此设置允许在您键入时搜索,而不是只在您按回车键时搜索
  • 这是一个非常烦人的设置,但是对于 Vim 新手来说非常有用(是的,我打开了这个设置)。它不鼓励使用箭头键在 Vim 中浏览文本,并提示您使用hjkl键。一开始你会行动缓慢,但慢慢地这将成为你的第二天性。
**" comments in vimrc start with "
" in normal mode**
nnoremap <Left>  : echoe "Use h" <CR>
nnoremap <Right> : echoe "Use l" <CR>
nnoremap <Up>    : echoe "Use k" <CR>
nnoremap <Down>  : echoe "Use j" <CR>**" in insert mode**
inoremap <Left>  : echoe "Use h" <CR>
inoremap <Right> : echoe "Use l" <CR>
inoremap <Up>    : echoe "Use k" <CR>
inoremap <Down>  : echoe "Use j" <CR>
  • 编辑:另一个必须在.vimrc中设置的是缩进行。我花了很长时间试图找到一个允许缩进的选项,类似于 Visual Studio 或 Sublime,但还没有找到一个有效的。同时,set autoindent肯定会使在 Vim 中编辑比以前容易得多。

将这些设置添加到您的.vimrc文件中,并注意不同之处!您肯定会发现现在在 Vim 中编辑文本更有吸引力了!

点击 查看第 2 部分 中一些非常需要的补充内容!

参考

使用 purrr 和 ggplot2 可定制 R 中的关联热图

原文:https://towardsdatascience.com/customizable-correlation-plots-in-r-b1d2856a4b05?source=collection_archive---------6-----------------------

不用任何相关绘图包制作高质量的相关图

如果你曾经觉得被R中的关联热图包所限制,这篇文章将向你展示如何编写你自己的函数来将众多的关联整理成一个ggplot2友好的绘图形式。

最后,您将能够运行一个函数来获得一个整理好的相关性数据框架。然后,您可以在这个数据框上运行ggplot2代码来制作您自己的关联热图。

如果你只是想要代码,你可以跳到最后。你也可以在我的网站上阅读我的其他博客文章, KHstats

我真的很感激一些允许我使用R超快速地制作相关图的包和函数。这里有几个例子:

corrplot::corrplot(cor(mtcars))

corrgram::corrgram(mtcars)

ggcorrplot::ggcorrplot(cor(mtcars))

所有这些都很好,但没有一个最终能像我需要的那样可定制。接下来我将展示如何绕过使用其他人的函数约束,以一种ggplot2友好的格式在数据中准备相关性。

我们可以使用基本的R函数cor()来得到我们的相关性,但是我不喜欢缺省的数据。相反,我使用 Frank Harrell 的Hmisc::rcorr()函数有两个原因:

  1. 默认情况下,它会丢弃丢失的对
  2. 它返回 p 值,因此只需要一个函数就可以获得相关系数和匹配的 p 值

让我们加载我们为此需要的库,它们是使用kable显示表格的knitrtidyverse(我们将具体使用tidyrdplyrggplot2tibblepurrr)。

library(knitr) library(tidyverse, warn.conflict=F)

首先,让我们看看我们将使用的相关函数的输出,Hmisc::rcorr()。它要求输入是一个矩阵,并输出三个矩阵的列表。

mtcars_cor <- Hmisc::rcorr(as.matrix(mtcars))

这三个矩阵包括相关系数(默认为皮尔逊系数)、r、p 值、P以及用于每个相关的观察值数量n。让我们把每个矩阵变成一个data frame,用headkable来看前六行。

相关系数,r:

data.frame(mtcars_cor$r) %>% head() %>% kable()

Pp 值:

data.frame(mtcars_cor$P) %>% head() %>% kable()

观察次数,n。在mtcars数据集中没有缺失数据,因此有 32 对用于所有相关。

data.frame(mtcars_cor$n) %>% head(n=3) %>% kable()

接下来,我们可以编写一个函数,为Hmisc::rcorr()正确格式化一个data frame,然后依次处理列表中的三个元素(rnP)

cors <- function(df) { 
   # turn all three matrices (r, n, and P into a data frame)
   M <- Hmisc::rcorr(as.matrix(df))
   # return the three data frames in a list return(Mdf)
   Mdf <- map(M, ~data.frame(.x))
  }

在这个函数中没有发生太疯狂的事情。现在我们只有三个数据帧的列表。我们可以使用first()查看列表的第一个元素,它显示了所有变量之间的相关性:

cors(mtcars) %>% first() %>% head() %>% kable()

下一步是准备好用ggplot2绘图的数据。我们现在可以将数据保存在一个列表中,并使用来自purrrmap()函数。

首先,我们需要使用tibble::rownames_to_column()将行名移动到它们自己的列中。的输出如下所示:

cors(mtcars) %>% 
   map(~rownames_to_column(.x, var="measure1")) %>%
   # look at the first element of the list (r)
   first() %>%
   head() %>%
   kable()

接下来,我们可以使用tidyr::pivot_longer()将列移动到名为measure2的单个列

cors(mtcars) %>%
 map(~rownames_to_column(.x, var="measure1")) %>%
 # format each data set (r,P,n) long
 map(~pivot_longer(.x, -measure1, "measure2")) %>%
 # look at the first element of the list (r)
 first() %>%
 head() %>%
 kable()

现在,我们准备使用bind_rows()取消数据列表。这将把我们的相关性变成一个很长的数据帧,所有的行从r开始,然后是n,然后是P

cors(mtcars) %>%
 map(~rownames_to_column(.x, var="measure1")) %>%
 # format each data set (r,P,n) long 
 map(~pivot_longer(.x, -measure1, "measure2")) %>%
 # merge our three list elements by binding the rows
 bind_rows(.id = "id") %>%
 head() %>%
 kable()

对于ggplot2,我们需要将rnP作为它们自己的列。我们可以用pivot_longer()来做到这一点。

cors(mtcars) %>%
 map(~rownames_to_column(.x, var="measure1")) %>%
 # format each data set (r,P,n) long 
 map(~pivot_longer(.x, -measure1, "measure2")) %>%
 # merge our three list elements by binding the rows
 bind_rows(.id = "id") %>%
 pivot_wider(names_from = id, values_from = value) %>%
 head() %>%
 kable()

最后,我们可以添加一些列,这些列在以后可能会对我们的相关图提供更多信息非常有用。让我们添加告诉我们 p 值是否小于 0.05 的列,如果是,返回 1)p 值和 2)相关系数,以防我们想要用这些值标记我们的图。

cors(mtcars) %>%
 map(~rownames_to_column(.x, var="measure1")) %>%
 # format each data set (r,P,n) long 
 map(~pivot_longer(.x, -measure1, "measure2")) %>%
 # merge our three list elements by binding the rows
 bind_rows(.id = "id") %>%
 pivot_wider(names_from = id, values_from = value) %>%
 mutate(sig_p = ifelse(P < .05, T, F), p_if_sig = ifelse(P <.05, P, NA), r_if_sig = ifelse(r <.05, r, NA)) %>% 
 head() %>%
 kable()

这似乎是我想画的所有东西。当然,你可以添加更多。在这一点上,我将我的格式化相关性转换成一个函数:

formatted_cors <- function(df){
 cors(df) %>%
 map(~rownames_to_column(.x, var="measure1")) %>%
 map(~pivot_longer(.x, -measure1, "measure2")) %>% 
 bind_rows(.id = "id") %>%
 pivot_wider(names_from = id, values_from = value) %>%
 mutate(sig_p = ifelse(P < .05, T, F), p_if_sig = ifelse(P <.05, P, NA), r_if_sig = ifelse(P <.05, r, NA)) 
}

我们可以测试该功能是否如预期的那样工作:

formatted_cors(mtcars) %>% head() %>% kable()

我们终于准备好在ggplot2中绘制我们的关联热图了。

该图最简单的形式只需要我们分别在xy轴上指定measure1measure2。然后,我们可以将相关性r映射到fill aes合成,并添加一个图块作为geom合成。

formatted_cors(mtcars) %>%
 ggplot(aes(x = measure1, y = measure2, fill = r)) +
 geom_tile()

我们可以做一些小的美学上的改变,比如填充颜色比例、标题和字体系列。

formatted_cors(mtcars) %>%
 ggplot(aes(x = measure1, y = measure2, fill = r)) +
 geom_tile() +
 labs(x = NULL, y = NULL, fill = "Pearson's\nCorrelation", title="Correlations in Mtcars") +
 # map a red, white and blue color scale to correspond to -1:1 sequential gradient scale_fill_gradient2(mid="#FBFEF9",low="#0C6291",high="#A63446", limits=c(-1,1)) +
 theme_classic() +
 # remove excess space on x and y axes
 scale_x_discrete(expand=c(0,0)) +
 scale_y_discrete(expand=c(0,0)) +
 # change global font to roboto
 theme(text=element_text(family="Roboto"))

我们可以添加额外信息的相关性。对于这个特殊的图,我只添加了显著的(p 值小于 0.05)相关性,使用从formatted_cors()输出的列r_if_sig

formatted_cors(mtcars) %>% 
 ggplot(aes(measure1, measure2, fill=r, label=round(r_if_sig,2))) +
 geom_tile() +
 labs(x = NULL, y = NULL, fill = "Pearson's\nCorrelation", title="Correlations in Mtcars", subtitle="Only significant Pearson's correlation coefficients shown") + scale_fill_gradient2(mid="#FBFEF9",low="#0C6291",high="#A63446", limits=c(-1,1)) +
 geom_text() +
 theme_classic() +
 scale_x_discrete(expand=c(0,0)) +
 scale_y_discrete(expand=c(0,0)) +
 theme(text=element_text(family="Roboto"))

另一个版本可以包括不同大小的正方形,以使用geom_point来表示相关性的强度,其中shape被设置为来自这些可用的 [geom_shape](http://www.sthda.com/english/wiki/ggplot2-point-shapes) s值。一定要取相关的绝对值,这样强的负相关也可以表示得更大。

formatted_cors(mtcars) %>%
 ggplot(aes(measure1, measure2, col=r)) +
 ## to get the rect filled geom_tile(col="black", fill="white") + geom_point(aes(size = abs(r)), shape=15) + labs(x = NULL, y = NULL, col = "Pearson's\nCorrelation", title="Correlations in Mtcars") + theme_classic() +
 scale_color_gradient2(mid="#FBFEF9",low="#0C6291",high="#A63446", limits=c(-1,1)) +
 scale_x_discrete(expand=c(0,0)) +
 scale_y_discrete(expand=c(0,0)) +
 theme(text=element_text(family="Roboto")) +
 scale_size(range=c(1,11), guide=NULL)

cors <- function(df) {
 M <- Hmisc::rcorr(as.matrix(df)) 
 Mdf <- map(M, ~data.frame(.x)) return(Mdf) }formatted_cors <- function(df){
 cors(df) %>%
 map(~rownames_to_column(.x, var="measure1")) %>%
 map(~pivot_longer(.x, -measure1, "measure2")) %>% 
 bind_rows(.id = "id") %>%
 pivot_wider(names_from = id, values_from = value) %>%
 mutate(sig_p = ifelse(P < .05, T, F), p_if_sig = ifelse(P <.05, P, NA), r_if_sig = ifelse(P <.05, r, NA)) }formatted_cors(mtcars) %>% 
 ggplot(aes(measure1, measure2, fill=r, label=round(r_if_sig,2))) +
 geom_tile() + 
 labs(x = NULL, y = NULL, fill = "Pearson's\nCorrelation", title="Correlations in Mtcars", subtitle="Only significant Pearson's correlation coefficients shown") + 
 scale_fill_gradient2(mid="#FBFEF9",low="#0C6291",high="#A63446", limits=c(-1,1)) +
 geom_text() +
 theme_classic() +
 scale_x_discrete(expand=c(0,0)) + 
 scale_y_discrete(expand=c(0,0)) +
 theme(text=element_text(family="Roboto"))

原载于 2020 年 3 月 15 日https://www.khstats.com

自定义分类模型输出层

原文:https://towardsdatascience.com/customize-classification-model-output-layer-46355a905b86?source=collection_archive---------24-----------------------

使用 Keras 在自定义层中保存分类标签和最高机密

图像分类是深度学习应用的手册示例。制作分类模型的标准方法包括预处理步骤,在该步骤中,人类可读的类标签(例如:“汽车”、“人”、“猫”)被改变成机器可用的数字(例如:0,1,2)。最常见的方法是将可能的类列表与它们的索引进行映射。当然,这也需要一个后处理步骤,将结果转换成预期的形式。一种常见的方法是存储具有最高分数的类的标签和分数(对此广泛使用的术语是置信度)。

在这个故事中,我将展示一个在模型末尾使用自定义图层在模型中存储标签的示例。我的模型的首选输出是前 k 标签及其置信度得分的列表。格式化的输出在产品是模型的生产中是有用的,并且标签必须存储在模型中。或者,当标签列表随着模型的每次迭代而改变时。

Input: image(W,H,C) Outputs: labels(k) string, confidences(k) float

照片由大卫·兰格尔Unsplash 上拍摄

训练分类模型

对于这个故事,我将使用一个简单的分类模型。这个 Colab 笔记本展示了一个在时尚 MNIST 数据集上训练的分类器的例子(在 60000 张图片上训练,在 10000 张图片上测试)。该模型预期 28x28x1 灰度图像,并返回 10 类的 softmax 概率。类别标签列表包括:

class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

处理模型输出的一种简单方法是简单的映射:找到得分最高的索引并使用该索引的标签。

class_names[np.argmax(predictions[0])]获取图像的标签 0。

时尚 MNIST 范例(作者 Zalando,麻省理工学院许可)。

构建自定义图层

要了解如何在 Keras 中制作自定义图层,建议阅读 Keras 和 TensorFlow 中的原始文档

我想实现一个自定义层来存储labels 和一个topn值,这样该层的输出可以是前 n 个置信度标签及其分数。为此,我们必须覆盖图层的__init__callcompute_output_shapeget_config 功能。

带有标签和 Top_k 选择的自定义图层

初始化

在 init 函数中,我们将构造函数参数存储为类的字段。不要忘记调用父类的构造函数!super(LabelLimitLayer, self).__init__(**kwargs)

打电话

call 函数期望前一层的输出作为输入,并计算top_k 类及其标签。为此,我使用了张量流函数。

为了从标签列表中创建一个(?,len(labels)) 形状的张量,我们首先使用列表(我们自定义类的参数)创建一个张量,然后使用前一层输出的形状扩展它(我们从中提取batch_size )。这些步骤是:

tf_labels = tf.constant([self.labels], dtype=”string”)弦型张量
tf_labels = tf.tile(tf_labels,[batch_size,1])展开得到(?1)处理批次的动态形状。

为了选择最高的 k 个分数,我使用了相应的 TensorFlow 函数。我们存储这些指数,这样我们就可以映射这些指数的标签以及置信度值。
top_k = tf.nn.top_k(x, k=self.topn, sorted=True, name=”top_k”).indices

为了使用一个张量的索引来获取另一个张量的值,我使用了 tf.gather 函数。
top_conf = tf.gather(x, top_k, batch_dims=1) top_labels = tf.gather(tf_labels, top_k, batch_dims=1)

最后,该层返回最后两个张量。
return [top_conf, top_labels]

计算输出形状

由于有两个输出张量,Keras 层不能自动计算输出形状。好在可以这样计算:
top_shape = (batch_size, self.topn) return [top_shape, top_shape]

获取配置

为了序列化定制层(当保存模型时),必须用类参数的值更新配置。不要忘记将超类的配置添加到字典中!

将输出图层添加到模型

在这个例子中,我在基本分类模型的末尾添加了一个自定义层,带有标签(class_names)和 top_k 值(2)。

label_layer = LabelLimitLayer(class_names, 2)(base_model.output) label_model = Model(base_model.input, label_layer)

时尚 MNIST 数据集中的预测标签

保存和加载模型

最后,为了保存一个模型,我们可以使用 Keras 模型的 save 函数。要加载带有自定义层的模型,必须在custom_objects 参数中定义该自定义层。

label_model.save(‘test.h5’) restored_model = keras.models.load_model(“test.h5”, custom_objects={“LabelLimitLayer”:LabelLimitLayer})

摘要

这个片段展示了如何使用 Keras 自定义层来创建字符串标签作为模型的输出。这个故事还使用 top_k 只保留相关的类。相应的代码可在这款 Colab 笔记本上找到。

定制损失函数,使 LSTM 模型更适用于股票价格预测

原文:https://towardsdatascience.com/customize-loss-function-to-make-lstm-model-more-applicable-in-stock-price-prediction-b1c50e50b16c?source=collection_archive---------10-----------------------

损失函数不要只考虑价格差异,方向损失也很重要!!!

尼克·崇在 Unsplash 上的照片

背景

这里有很多在线教程或文章教你如何建立一个 LSTM 模型来预测股票价格。无论是简单的还是复杂的,我们都可以以某种方式获得一个“想要的”结果,类似于下图(图表 1)。是的,如果我们简单地通过查看均方差(MSE)来判断模型,这是可取的。

但是,在现实世界的交易中,做得好就能帮我们赚大钱吗?很遗憾,答案总是否定的。在本文中,我们将尝试定制损失函数,使我们的 LSTM 模型更适用于现实世界。

附件 1——基于简单 LSTM 模型的汇丰(0005.HK)股票价格预测

面临的问题

我这不是因为教程出了问题或者模型训练得不够好。但是从根本上说,有几个主要的限制很难解决。

1.所有免费库只提供每日股价数据没有实时数据,我们不可能在当天执行任何订单

2.常用的损失函数(MSE)是一个纯粹的统计损失函数——纯粹的价格差异不代表全貌

  1. LSTM 模型或任何其他递归神经网络模型始终是一个黑箱——交易策略只能基于没有任何理由支持的价格运动,并且这些策略很难扩展到投资组合分配

如果没有更多的资源,限制(1)和(3)很难解决。对于(1),解决方案可能是连接到实时交易数据提供商,如彭博,然后训练出一个实时 LSTM 模型。下一秒的交易指令可以自动下达。但是很遗憾地说,如果你不在交易大厅工作,很难做到这一点。

对于(3),如果旨在通过一些解释扩展到投资组合分配,可能其他概念如均值-方差优化、一些稳健的估计量,然后考虑风险价值(VaR)更合适。但那完全是另一回事了。

在本文中,我们将指出第二个限制,并重点关注一种可能的方法— 通过考虑方向损失来定制损失函数,以使 LSTM 模型在有限的资源下更适用。

存在的困难

L et 回到上图(附表 1)。它看起来很完美,表明该模型的预测能力非常高。诚然,在训练 300 个历元后,其训练损失的 MSE 仅为 0.000529,但其预测第二天价格运动方向的准确性仅为 0.449889 ,甚至低于抛硬币!!!

MSE 主要关注真实价格和预测价格的差异,而不考虑预测的方向是否正确。如果我们应用基于 LSTM 模型预测的卖出/买入期权这样的交易策略,这一特征会造成巨大的麻烦。从这个角度来看,应该强调方向的正确性。

此外,该模型是基于给定数据可用性的每日价格,并试图预测第二天的收盘价,这并没有捕捉到当天的价格波动。在这种情况下,方向的准确性甚至比价格差异更重要。甚至有些日子你可能会赚得少,但至少不会导致金钱损失。

方法论

N 现在,我们开始自定义损失函数。关于数据预处理的细节以及如何建立简单的 LSTM 模型股票预测,请参考 Github 链接这里。完整的代码也可以在那里找到。

步骤 1:从损失函数的输入张量中提取必要的信息

def **custom_loss**(y_true, y_pred):

	*#extract the "next day's price" of tensor*
	y_true_next = y_true[1:]
	y_pred_next = y_pred[1:] *#extract the "today's price" of tensor* 	y_true_tdy = y_true[:-1]
	y_pred_tdy = y_pred[:-1]

永远记住损失函数的输入是两个张量, y_true (真实价格)和 y_pred (预测价格)。首先,我们必须创建四个新的张量来存储来自两个输入传感器的“第二天的价格”和“今天的价格”,以备将来使用。

第二步:创建新的张量来记录价格运动(涨/跌)

*#substract to get up/down movement of the two tensors*
y_true_diff = tf.subtract(y_true_next, y_true_tdy)
y_pred_diff = tf.subtract(y_pred_next, y_pred_tdy)*#create a standard tensor with zero value for comparison*
standard = tf.zeros_like(y_pred_diff)*#compare with the standard; if true, UP; else DOWN*
y_true_move = tf.greater_equal(y_true_diff, standard)
y_pred_move = tf.greater_equal(y_pred_diff, standard)

TF . subtract是从 y_true_next 张量中减去 y_true_tdy 张量中的元素值。然后,我们将两个差分张量( y_true_diffy_pred_diff )与标准零张量进行比较。如果该值大于或等于零,则属于向上运动,否则属于向下运动。 tf.greater_equal 将返回一个布尔张量。

第三步:找出两个张量运动方向不同时的指标

*#find indices where the directions are not the same*
condition = tf.not_equal(y_true_move, y_pred_move)
indices = tf.where(condition)ones = tf.ones_like(indices)
indices = tf.add(indices, ones)

(a)TF . not _ equal比较两个布尔张量 y_true_movey_pred_move ,生成另一个新的布尔张量——条件。如果第二天的方向在真实运动和预测运动之间相同,则返回,否则返回

(b)在条件张量中 tf.where 返回“真”的位置。

(c)TF . add索引张量中的每个元素加 1。如果您足够仔细,您可能会注意到任何处理过的张量的形状都是(49,1),比原始输入的形状(50,1)短一个单位。加 1 意味着我们在一天后移动索引,这代表了第二天在原始输入张量中的真实位置。

第四步:创建一个张量来存储方向损耗,并将其放入自定义损耗输出

direction_loss = tf.Variable(tf.ones_like(y_pred), dtype='float32')
updates = K.cast(tf.ones_like(indices), dtype='float32')
alpha = 1000
direction_loss = tf.scatter_nd_update(direction_loss, indices, alpha*updates)custom_loss = K.mean(tf.multiply(K.square(y_true - y_pred), direction_loss), axis=-1)

现在,我们正在创建最重要的张量—direction _ loss由于它应该是一个可训练的张量并被放入最终输出custom _ loss它必须被设置为一个变量张量,使用 tf.Variable.

张量 索引 存储了真实价格和预测价格之间方向不匹配的位置。通过TF . scatter _ nd _ update,我们可以通过指定位置来更新张量direction _ loss中的值,并用新值替换。但是请记住,索引和更新的形状必须相同。direction _ loss的最终乘积是一个值为 1 或 1000 的张量。

最后,我们用 方向损失 张量乘以真实价格和预测价格的平方差。这里的概念是,如果当天的真实价格和预测价格之间的方向匹配,我们将损失保持为平方差。如果不匹配,那么我们用α(1000)乘以差值的平方。

最后,定制的损失函数完成。我们现在已经考虑了预测价格是否与真实价格同向。如果我们应用具有相同设置(批量:50,时期:300,时间步长:60)的 LSTM 模型来预测汇丰银行(0005。HK),预测价格方向的精度从 0.444343 提高到 0.561158。这是一个很大的进步,但仍远非完美。如果我们想建立一个更好的损失函数,我们将在本文的最后部分讨论一些需要克服的障碍。

一些可以帮你节省时间的技巧

M 大多数时候,我们可能要用和上面完全不同的概念来定制损失函数。以下是一些技巧,可以帮助您节省时间或跟踪过程中的错误。

(a)get _ shape—当你不确定张量的形状时,毫不犹豫地用这个函数把它打印出来。几乎所有的处理函数都要求所有输入张量的形状相同。

(b)keras . back end . cast—当错误消息称张量中的元素格式与其他元素不匹配时,尝试使用此功能将张量的元素格式更改为特定类型。

(c)tensor flow . reshape—当错误消息称形状与原始输入不匹配时,应保持(x,1)的一致形状,尝试使用此函数 tf.reshape(tensor,[-1]) 展平张量。

(d)custom _ loss—记住,最终产品必须由两个输入的张量 y_truey_pred 组成,并将返回到 LSTM 模型的主体进行编译。

需要克服更多障碍…

他的成绩现在已经有了很大的进步,但还远远不够完美。然而,要更进一步,许多障碍在等着我们,下面是其中的一些。

(a)难以平衡价格差异和方向性损失 —如果 alpha 设置过高,您可能会发现预测价格波动很小。如果我们画出来,它几乎是一条直线。这意味着方向损耗主导了损耗函数。在这种情况下,预测的价格变得毫无意义,但只有它的方向是有意义的。我们只是在打赌第二天的价格是上涨还是下跌。

(b)难以将分类分类器应用于股票价格预测—你们中的许多人可能会发现,如果我们只是简单地押注价格运动(上涨/下跌),那么我们为什么不应用分类分类器来做预测,或者将损失函数变成TF . binary _ cross entropy。很抱歉,结果没有任何改善。我试过先把所有的价格数据转换成用 0(跌)或 1(涨)表示的“运动数据”,输入进行训练。但是由于数据的本质是时间序列,与手写识别不同,每个训练批次中的 0 或 1 数组不足以进行第二天价格运动的预测。一些方法,如支持向量机(SVM)和卷积神经网络(CNN),在分类中表现很好,但很难应用于这种情况。

(c) Alpha 对每只股票来说都非常具体——我曾试图将相同的模型应用于其他 10 只股票的股价预测,但并不是所有股票都有很大的改善。对于每一只股票来说,价差和方向性亏损之间的关系似乎非常独特。所以我们可能要花很多时间来找出每只股票的最佳组合。

结论

从最小化均方误差的角度出发,建立一个理想的 LSTM 模型来预测股票价格总是不难的。但是它在现实世界中并不适用。本文介绍了一种可能的方法——通过考虑方向损耗来定制损耗函数,并讨论了在此过程中的一些困难并提供了一些建议。我希望它将开启关于如何改进我们的 LSTM 模式的讨论。如前所述,如果我们想更进一步,就必须克服许多障碍,特别是在资源有限的情况下。

这篇文章也是我第一次在媒体上发表。在未来,我将尝试探索更多关于数据科学和机器学习技术在经济和金融领域的应用。感谢支持!!!

参考

  1. 阿苏托什·纳亚克。(2019).用 LSTM 预测股票价格
  2. Dhiraj K. (2019)。如何在 Keras 中创建自定义损失函数
  3. 埃亚尔·扎凯。(2019).高级 Keras——构建复杂的客户损失和指标

[## 用我的推荐链接加入媒体-哈德森高

如果你对我写的东西感兴趣,不要错过成为 Medium 会员的机会。您将可以完全访问所有…

medium.com](https://medium.com/@hudsonko/membership)

在 Matplotlib 中自定义多个子情节

原文:https://towardsdatascience.com/customizing-multiple-subplots-in-matplotlib-a3e1c2e099bc?source=collection_archive---------5-----------------------

Unsplash 上由 Aron 视觉拍摄的照片

入门

使用 subplot、add_subplot 和 GridSpec 在 Matplotlib 中创建复杂 subplot 的指南

在某些时候,我们需要将我们的数据可视化成复杂的图形,因为我们应该这样做或者制作一个伟大的图形。例如,您想在绘图中制作一个缩放效果,如图 1 所示。为了呈现它,你需要建立一个复杂的次要情节。图 1 由三个不同的轴构成:轴 1、轴 2 和轴 3。Axes1 在左上角的面板上,用绿色的绘图线显示数据,axes2 在右上角的面板上,用橙色的线显示数据,最大的 axes3 位于底部的面板上。

图一。Matplotlib 中的缩放效果(图片作者)。

在创建复杂的图之前,你需要知道 Matplotlib 中的术语之间的区别。为此,您可以了解 Matplotlib 中定义的图形的结构,如图 2 所示。

图二。Matplotlib 中图形和轴的区别(图片由作者提供)。

被定义为所有元素的主容器,如轴、图例、标题等。一个图形可以包含一些轴(我们将更深入地了解它)。在图 1 中,我们只有一个图形,它包含三个轴。如果您想在 Maptlotlib 中创建缩放效果,请访问此链接。

[## 使用 Matplotlib 可视化数据的 5 个强大技巧

如何使用 LaTeX 字体,创建缩放效果,发件箱图例,连续错误,以及调整框填充边距

towardsdatascience.com](/5-powerful-tricks-to-visualize-your-data-with-matplotlib-16bc33747e05)

使用子情节在图形中创建简单的轴

在这一节中,我们将学习 Matplotlib 中子情节的基本原理。我将展示给你的一些例子不是现实的情节,但它将成为理解支线剧情的好例子。

要创建轴,至少可以使用两种不同的方法。第一种可以使用语法 支线剧情 ,第二种是使用 gridspec。 在开始学习 支线剧情 的时候,我会给你看一个简单的支线剧情,如图 3。

图 3。Matplotlib 中的一个简单支线剧情(图片由作者提供)。

您可以使用以下代码生成图 3

import matplotlib.pyplot as pltfig = plt.figure()
coord = 111
plt.subplot(coord)
plt.annotate('subplot ' + str(coord), xy = (0.5, 0.5), va = 'center', ha = 'center')

理解 Matplotlib 中子绘图的一件重要事情是定义轴的坐标。上面代码中的变量 coord 是 111。它由代表行数、列数和轴序列的三个数字组成。 coord 111 的意思是,你生成一个由一行一列组成的图形,你在第一个序列轴中插入子情节。因为你只有一行一列(这意味着你只有一个单元格),你的轴是主要的图形。您也可以在没有子图语法的情况下生成图 3,因为您在一个图形中只生成一个轴。

下一步是在图形中创建两个水平轴,如图 4 所示。您可以使用这段代码来生成它

fig = plt.figure(figsize=(12, 4))
coord1 = 121
coord2 = 122plt.subplot(coord1)
plt.annotate('subplot ' + str(coord1), xy = (0.5, 0.5), va = 'center', ha = 'center')plt.subplot(coord2)
plt.annotate('subplot ' + str(coord2), xy = (0.5, 0.5), va = 'center', ha = 'center')

图 4。图中两个横轴(图片由作者提供)。

您需要定义图形大小来创建一个漂亮的两个水平轴。如果你不这样做,你会得到一个类似数字 5 的数字。

图 5。一个图形中的两个横轴,没有定义图形大小(图片由作者提供)。

如果要创建两个垂直轴,只需更改坐标 1 和坐标 2,如以下代码所示

fig = plt.figure(figsize=(6, 7))
coord1 = 211
coord2 = 212plt.subplot(coord1)
plt.annotate('subplot ' + str(coord1), xy = (0.5, 0.5), va = 'center', ha = 'center')plt.subplot(coord2)
plt.annotate('subplot ' + str(coord2), xy = (0.5, 0.5), va = 'center', ha = 'center')

现在,我将尝试使用循环在一个图形中创建更多的支线剧情。我将创建 2x4 轴,如图 6 所示。

图 6。在 Matplotlib 中使用循环创建一个简单的子情节(图片由作者提供)。

您可以使用这段代码重现图 6

fig = plt.figure(figsize=(16, 6))coord = []# create coord array from 241, 242, 243, ..., 248 
for i in range(1, 9): # in python, 9 is not included
    row = 2
    column = 4
    coord.append(str(row)+str(column)+str(i))

# create subplot 241, 242, 243, ..., 248
for i in range(len(coord)):
    plt.subplot(coord[i])
    plt.annotate('subplot ' + str(coord[i]), xy = (0.5, 0.5), va = 'center', ha = 'center')

因为你要创建 8 个轴(2 行 4 列),所以你需要做一个从 241 到 248 的数组。之后,使用与前面代码相同的过程创建子情节,但是将它放在循环语法中。

用 gridspec 在图形中创建简单轴

正如我之前提到的,除了使用 subplot 在图形中创建一些轴,还可以使用 gridspec。例如,如果您想用 gridspec 创建图 6(两行 4 列),您可以使用下面的代码

import matplotlib.pyplot as pltfig = plt.figure(figsize=(16, 6))rows = 2
columns = 4grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)for i in range(rows*columns):
    exec (f"plt.subplot(grid{[i]})")
    plt.annotate('subplot 24_grid[' + str(i) + ']', xy = (0.5, 0.5), va = 'center', ha = 'center')

要使用 gridspec 创建简单的子情节,首先要定义行数和列数。要将支线剧情嵌入到图中,你只需调用支线剧情的编号。在 gridspec 中,子情节的数量从 0 开始,而不是从 1 开始。所以,如果要使用 gridspec 在一个图中嵌入 8 列,需要从 0 到 7 调用它们,使用PLT . subplot(grid[0])直到PLT . subplot(grid[7])。在循环中,你会遇到一个问题,因为你想用[]调用网格号。要处理它,可以使用语法exec(f "…{[I]} "

图 7 是使用 gridspec 创建 8 个轴的结果

图 7。在 Matplotlib 中使用 gridspec + looping 创建一个简单的子情节(图片由作者提供)。

使用 gridspec 的一个好处是你可以用比只使用支线剧情更简单的方式创造更多支线剧情。例如,如果您想在一个图形中创建 10 个以上的支线剧情,您将定义最后一个坐标。子情节仅由三个数字组成,例如 111、428、439 等。一个支线剧情无法促成第四个。例如,您想在一个图形中创建 18 个轴(3 行 6 列)。如果只使用支线剧情,需要定义 361,362,263,…,3616。当你嵌入一个 3610 的支线剧情时,你将面临错误。要解决它,可以使用 gridspec。图 8 展示了使用 gridspec 创建 18 个轴。

图 8。在 Matplotlib 中使用 gridspec + looping 创建简单的 18 个支线剧情(图片由作者提供)。

您可以用这段代码创建图 8

fig = plt.figure(figsize=(22, 8))rows = 3
columns = 6grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)for i in range(rows*columns):
    exec (f"plt.subplot(grid{[i]})")
    plt.annotate('subplot 36_grid[' + str(i) + ']', xy = (0.5, 0.5), va = 'center', ha = 'center')

为了做一个更真实的例子,我将在图 8 中为每个轴插入一个图。所以,我需要为每个轴做 18 个不同的函数。它是由【sin(x^(i/9】)的函数编译而成,其中 i 是从 0 到 17 的网格数。您可以在图 9 中看到该图。

图九。Matplotlib 中更现实的支线剧情(图片由作者提供)。

要创建图 9,您可以使用下面的代码

fig = plt.figure(figsize=(25, 10))color = ['#00429d', '#2754a6', '#3a67ae', '#487bb7', '#548fc0', 
         '#5ea3c9', '#66b8d3', '#6acedd', '#68e5e9', '#ffe2ca', 
         '#ffc4b4', '#ffa59e', '#f98689', '#ed6976', '#dd4c65', 
         '#ca2f55', '#b11346', '#93003a']rows = 3
columns = 6grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)for i in range(rows*columns):
    np.random.seed(100)
    x = np.linspace(0., 5., 100)
    y = np.sin(x**(i / 9)) + np.random.random() * i

    exec (f"plt.subplot(grid{[i]})")

    plt.plot(x, y, color = color[i])

要用不同的颜色呈现,还需要定义 18 种不同的颜色。您可以使用这个链接来生成它。我已经在下面的链接中解释了如何使用它。

[## 用于科学绘图的 Matplotlib 样式

为您的科学数据可视化定制 Matplotlib

towardsdatascience.com](/matplotlib-styles-for-scientific-plotting-d023f74515b4)

用 add_subplot 在图形中创建复杂轴

在本节中,我们将学习如何使用 add_subplotGridSpec 定制复杂的轴。我提到的复杂轴如图 10 所示。

图 10。Matplotlib 中复杂的轴(图片由作者提供)。

示例 1 使用 add_subplot

我们将使用 add_subplot 语法创建 3 个轴(顶部 2 个,底部 1 个),如图 1 所示。您可以使用这段代码来创建它。

如果你分析代码,你会得到一个与子情节语法概念类似的概念。您需要定义三个坐标,例如(2,2,1)或(2,2,(3,4))。 sub1 轴位于 2 行 2 列图形的第一个轴(1)上。 sub2sub1 有类似的方案。其中重要的是轴 3 和轴 4 的组合 sub3、 。所以 sub3 的坐标是(2,2,(3,4))。如果您运行上面的代码,您将得到一个结果,如图 11 所示。

图 11。Matplotlib 中第一个使用 add_subplot 的复杂轴的例子(图片由作者提供)。

如果要为每个轴添加绘图,可以在定义 sub1、sub2 和 sub3 之后添加此代码。

sub1.plot(x, y)
sub2.plot(x, y)
sub3.plot(x, y)

完整的代码在这里。

全部

您将得到一个结果,如图 12 所示。

图 12。Matplotlib 中第一个使用 gridspec 的复杂轴的例子(图片由作者提供)。

示例 1 使用 gridspec

作为替代,您也可以使用 gridspec 语法创建图 12。下面是您可以用来创建它的代码。

该代码创建了 2 行 2 列。 sub1sub2 放在第一行第 0 列第 1 列(记住 gridspec 是从 0 索引开始的)。 sub3 放在第二行,取所有列,用 : 表示。如果您运行上面的代码,您将得到相同的图,如图 12 所示。

示例 2 使用 add_subplot

复杂轴的第二个例子如图 13 所示。

图十三。Matplotlib 中使用 gridspec 的复杂轴的第二个例子(图片由作者提供)。

您将在图形中生成 4 个轴:sub1、sub2、sub3 和 sub4,共 2 行 4 列。 sub1 取第一行的所有列。 sub2、sub3 和 sub4 放置在第二行的每一列上。要生成图 12,您可以使用以下代码。

示例 2 使用 gridspec

要使用 gridspec 创建图 12,可以使用下面的代码。

我觉得上面的代码已经足够清晰易懂了:d .代码会生成一个情节,如图 14 所示。

图 14。Matplotlib 中使用 gridspec 的复杂轴的第二个例子(图片由作者提供)。

示例 3 使用 add_subplot

第三个例子如图 15 所示。

图 15。Matplotlib 中复杂轴使用 add_subplot 的第三个例子(图片由作者提供)。

要创建图 15,您可以使用以下代码。

示例 3 使用 gridspec

要使用 gridspec 创建图 15,可以使用下面的代码。

结果如图 16 所示。

图 16。Matplotlib 中使用 gridspec 的复杂轴的第三个例子(图片由作者提供)。

示例 4 使用 add_subplot

在最后一个示例中,将指导您在图形中创建 6 个轴,行数为 4,列数为 2。如图 17 所示。

图 17。Matplotlib 中复杂轴使用 add_subplot 的第四个例子(图片由作者提供)。

要用 add_subplot 创建它,可以使用下面的代码。

示例 4 使用 gridspec

要用 gridspec 创建图 17,可以使用下面的代码。

你需要注意 sub4 ,放在 1:3 行 1 列。行 1:3 意味着 sub4 将采用行号 1 和 2。请记住,不包括第 3 行。代码将生成一个图,如图 17 所示。

图 18。Matplotlib 中使用 gridspec 的复杂轴的第四个例子(图片由作者提供)。

结论

处理复杂数据时,需要创建一个复杂的绘图来可视化数据。我希望这个故事可以帮助你从不同的角度来可视化你的数据。如果你需要用 Matplotlib 创建科学发表图,可以访问这个链接

如果你喜欢这篇文章,这里有一些你可能喜欢的其他文章:

[## 使用 Matplotlib 可视化数据的 5 个强大技巧

如何使用 LaTeX 字体,创建缩放效果,发件箱图例,连续错误,以及调整框填充边距

towardsdatascience.com](/5-powerful-tricks-to-visualize-your-data-with-matplotlib-16bc33747e05) [## 用于科学绘图的 Matplotlib 样式

为您的科学数据可视化定制 Matplotlib

towardsdatascience.com](/matplotlib-styles-for-scientific-plotting-d023f74515b4) [## 在 Matplotlib 中创建色彩映射表

从颜色列表中创建和定制自己的色彩映射表的指南

towardsdatascience.com](/creating-colormaps-in-matplotlib-4d4de78a04b8) [## 使用 Matplotlib 实现 Python 数据可视化—第 1 部分

完成了从基础到高级的 Python 绘图的 Matplotlib 教程,包含 90 多个示例

towardsdatascience.com](/visualizations-with-matplotlib-part-1-c9651008b6b8) [## Vaex 大数据简介—读取 12.5 亿行的简单代码

用 Python 高效读取和可视化 12.5 亿行星系模拟数据

towardsdatascience.com](/introduction-to-big-data-a-simple-code-to-read-1-25-billion-rows-c02f3f166ec9)

仅此而已。感谢您阅读这个故事。喜欢就评论分享。我还建议您关注我的帐户,以便在我发布新故事时收到通知。

在 u 盘上共享交互式 Jupyter 仪表盘

原文:https://towardsdatascience.com/cut-out-the-cloud-share-interactive-jupyter-dashboards-on-a-usb-stick-c196d01df3e4?source=collection_archive---------33-----------------------

当你从未想过要开发 web 应用程序时,如何向客户或同事交付交互式笔记本电脑…

许多数据科学可视化实际上是一次性的 web 应用程序,并不打算公开,甚至也不打算为私人用户提供基于云的服务。考虑到它们短暂的生命周期,锁定一个托管服务的基础设施(和安全风险)是不值得的。事实上,所采用的 web 技术实际上只是从云或互联网很重要的不同场景中“借用”来的。我们的可视化最初是用 web 风格的技术构建的,这只是偶然的……那么我们能不能改变我们的思维,让我们的头脑完全脱离云端呢?

您的概念验证数据科学项目的高潮是 Jupyter 笔记本中的美丽可视化。您甚至包括了一些滑块部件,以便您可以更改一些参数,并立即查看这对笔记本中间的绘图有何影响,以及您的模型的预测如何变化。

如果你能让你的客户在他们自己的时间里滑动滑块,你知道他们会完全理解你想要传达的东西——并为项目的其余部分开绿灯。

但是,让他们在自己的机器上访问您的可视化的最佳方式是什么呢?

一个简单的基于小部件的交互式笔记本

有一些很好的方法可以将笔记本发布为基于网络的云应用,包括 mybinder.org,如果你喜欢一切都公开的话。但是,如果您的笔记本使用的数据是机密的,并且您没有权限将其托管在任意基于云的服务上,该怎么办?

要求他们在自己的机器上安装 conda 并运行一系列终端命令来复制您的包环境,这将考验即使是最热衷于技术的客户的耐心。并且这些命令可能需要根据它们的操作系统和现有安装而变化。

简单的单个文件

你已经有了一个与客户共享普通文件的系统——也许 SharePoint 或 Dropbox 已经建立了协作,所以也许有一种方法可以利用这一点。

ContainDS Desktop 是用于 Windows 或 Mac 的软件,允许您在本地机器上运行隔离的 Jupyter 环境。现在,您可以将 Jupyter 工作区和软件包环境导出为一个独立的文件,这样就可以直接导入到在其他人的计算机上运行的 ContainDS Desktop 中,并向他们呈现已经在您自己的计算机上运行的确切环境和笔记本文件。

本文展示了如何创建一个交互式 Jupyter 可视化,然后将其导出并作为一个简单的文件与您的客户共享,这样他们就可以轻松地按预期运行它。

要安装 ContainDS Desktop 并启动一个简单的“容器”,为我们安装一些包和编写一些新笔记本做好准备,首先请遵循 ContainDS Desktop 入门教程。这也将指导您安装 Docker,它是由 ContainDS Desktop 在引擎盖下使用的。

新容器

如果您仔细阅读了入门教程,您应该已经拥有了一个新的 JupyterLab 环境,它应该在浏览器窗口中打开。如果您愿意或者继续使用现有的容器来创建一个新的容器,您可以使用它。

ContainDS Desktop 中的容器只是一个 Jupyter 包环境(例如,可以安装 numpy 和 pandas 的地方)和一个存放笔记本和其他数据的工作区。

在 ContainDS Desktop 中,单击“+ NEW”按钮查看一些可以用于新容器的起点。单击“最小笔记本”旁边的“选择”。

选择一个图像作为起点

在下一个屏幕上,将询问您希望如何存储工作区。为了确保您的笔记本文件可以轻松地从本地硬盘访问,请选择一个新文件夹—可能在您的个人文件夹中命名为“dsworkspace ”,但实际上这可以是您喜欢的任何位置。

指定存储工作区的文件夹

点击“创建”,然后新的容器将被启动,并在 ContainDS 桌面的左侧列出。如果需要先下载“最小笔记本”起点映像,可能需要一点时间。

容器现在正在运行

准备好后,点击“WEB”按钮启动 JupyterLab。

安装软件包

在 JupyterLab 中,单击终端图标打开一个新的命令 shell 选项卡。

要安装我们需要的软件包,请输入以下命令:

conda install -c anaconda numpy --yes
conda install -c anaconda ipywidgets --yes 
conda install -c anaconda matplotlib --yes
jupyter labextension install @jupyter-widgets/jupyterlab-manager

在 Jupyter 终端标签中安装软件包

安装好所有东西后,重新加载 Jupyter 实验室浏览器窗口,确保新安装的 Javascript 正在运行。

写我们的笔记本

单击“+”按钮,这次单击“Python 3”图标打开一个新的笔记本选项卡。

将我们的样本笔记本中的单元格复制并粘贴到 GitHub 的这里。记住,粘贴代码后,按 shift+enter 键运行每个单元格。

我们完成了 Jupyter 演示

笔记本提供了一个滑块,用户可以选择参数‘t’的不同值。当您改变数值时,sin(t*x)cos(t*x)图会根据系数‘t’移动。哇,这真的可以教人一些新的数学!如果你还没有遇到过,互动部件是 Jupyter 笔记本电脑的一个非常强大的可视化功能,可以真正让用户沉浸在数字中。

将 ipynb 笔记本保存为一个名为 Presentation.ipynb 的文件或任何适合您的文件。

导出为普通旧文件

好了,我们已经安装了我们需要的包,并创建了我们的交互式笔记本。现在我们来看这篇文章的要点。我们如何能直接与客户分享它,以便他们能在自己的机器上随心所欲地与之互动?

如果愿意,您可以关闭 JupyterLab 浏览器窗口。

回到 ContainDS 桌面应用程序,我们的容器仍然应该在左侧面板中突出显示。点击“共享”选项卡。“导出”子选项卡应该是可见的,要求一个文件夹位置。应该写入 containds 的文件。

设定共享文件的位置

你的下载文件夹的默认值应该没问题,所以只需点击“导出”。

在提交和导出容器时,您应该会看到一些输出。最后,保存的完整文件名。将显示“containds”文件。

在哪里。containds 文件已保存

分享给你的朋友!

最后一步保存的文件会很大(可能 5GB ),所以不能通过电子邮件发送。希望您已经设置了一个协作服务,可以用来共享。containds 的文件。如果你的组织批准,SharePoint,Dropbox,Google Drive 等都是合适的。或者,如果你想避开云服务,u 盘可能是最合适的。

您的收件人还需要安装 ContainDS Desktop。运行后,他们应该在“+新建”屏幕中单击“文件”选项卡。找到。包含您与他们共享的文件,然后单击“开始”。文件处理过程中会显示一些日志。

将 containds 文件导入到同事的机器中

一旦完成,容器将启动,ContainDS 桌面将向您显示新容器的日志屏幕。单击“WEB”在 JupyterLab 中打开笔记本,就像您离开时一样。

交互式 Jupyter 笔记本,就像我们保存它一样

您的同事或客户可以按照您的意愿与滑块进行互动!

结论

正如本文开头所讨论的,许多数据可视化首先并不真正适合 web 技术——我们在一次性应用程序中使用它们只是出于偶然和熟悉。

以上教程的重点是再现性——忠实地传输我们在自己的计算机上体验到的精确的计算环境、文件和数据。但是在这个过程中肯定有需要克服的缺点。

最明显的是,最终用户需要在他们自己的机器上安装一些软件:ContainDS Desktop,它也需要 Docker 在后台运行。

然后我们忽略了一个事实。containds 的文件本身是 5GB。

这些问题有潜在的解决方案。为了降低安装要求,值得注意的是 Docker 基于开源软件,可以简化并捆绑到 ContainDS 本身中——因此可能只需要一个安装程序,用户无需担心 Docker 是否在后台运行。

ContainDS Desktop 本身对于技术用户(如典型的数据科学家)来说是一个相对简单的 UI,但它比 Jupyter“web app”的非技术最终用户需要的功能更多。有可能建立一个精简的“容器浏览器”版本的软件,为最终用户简化事情。它还可以使用更友好的前端,如 Voilà ,这样最终用户就不需要担心代码单元格和通过笔记本按 shift+enter。

数据科学领域普及了这些类型的一次性 web 应用程序,随着学科范围的扩大,数据可视化工具也有了许多令人兴奋的发展。我期待听到您对本文中介绍的方法如何为您服务的想法。什么障碍阻止你与同事和客户轻松分享你的可视化?

关于 ContainDS Desktop 的任何问题或反馈,请通过我们的网站联系

伯特模型嵌入没有你想象的那么好

原文:https://towardsdatascience.com/cutting-edge-bert-nlp-model-bb0bfc8b7aec?source=collection_archive---------19-----------------------

面向多语言句子嵌入

Gaurav BayaUnsplash 上拍摄的原始照片。由 Daulet Nurmanbetov 修改

我以前写过关于脸书的激光嵌入系统,意思相似的句子会有相似的向量嵌入。更重要的是,激光嵌入是多语言的,这意味着不同语言的句子将映射到同一个向量!

具有一个将相同意思的不同语言的句子映射到相同向量的嵌入系统是有利的。拥有这样一个系统将允许我们抽象出输入的语言,转而关注句子的意思。

这意味着,一旦我们将一个句子转换成一个向量,我们就可以建立一个下游模型,它可以在任何输入语言上工作,用于任何下游任务。

想找出有毒的句子?带有下游分类器的多语言嵌入模型将能够识别任何语言中的有毒句子。

在新闻文章中寻找交易信号?带有下游分类器的多语言嵌入模型将能够识别任何语言的交易信号。你明白了…

因此,让我们来看看 LASER 如何与英语句子相似性的其他模型进行比较:

结果在 English only STS 任务上,STS 是自然语言处理中句子意义相似度的竞争。越高越好。

上表显示了英语语言的基准。然而,激光嵌入不仅适用于英语,还适用于多种语言

随着 NLP 的所有最新创新,特别是 BERT 和多语言 BERT (mBERT ),人们可能会认为他们会放弃激光业务。然而,有趣的是,对于纯英语句子相似性任务,RoBERTa 和 mBERT 的表现不如 LASER。

从表中可以看出,会说多种语言的伯特和 same 罗伯塔在将意思相似的句子映射到同一个向量方面表现不佳。此外,当您混合不同的输入语言来计算相似性时,性能会进一步下降。

像 mBERT 这样的模型预测单个标记的向量值,而不是句子。由于语言中的词汇差异,这导致句子聚合与向量错位。意味着 mBERT 和其他预先训练的多语言转换器不适合开箱即用的跨语言句子相似性。

人们一致认为,mBERT 的输出是针对特定语言进行微调的,当比较不同语言的单词时,它们的向量有所不同。奇怪的是,在 Transformer 的早期层中,大约在 mBERT 的第 8 层,跨语言的向量彼此更加相似。

多语言嵌入的新范例

我们可以得到一个灵感来创造真正的多语言嵌入优于激光是一个蒸馏方法。看看像 DistilBERT 这样的模型,用它们作为灵感来创建我们的师生设置,在那里我们“强迫”多语言转换器产生跨语言的相同向量。为此,我们当然需要一个能够产生良好向量的教师模型。一个这样的候选是作为教师模型的纯英语句子 BERT (SBERT)模型。而且我们可以拿一个像 ALBERT 这样的大型多语言模型,作为学生使用。

这里的老师是斯贝特,学生是艾伯特或其他多语言转换者。图片来自使用知识蒸馏使单语句子嵌入多语言

上面的教师模型总是预测英语句子,而学生模型是多语言的,并且在给定外语输入的情况下“被迫”产生类似于英语的向量。意味着两件事:

  1. 向量空间跨语言对齐,即不同语言中的相同句子被映射到同一点
  2. 来自教师模型 M 的原始源语言中的向量空间属性被采用并转移到其他语言

现在,一旦我们有了训练设置,我们就可以获得用于翻译的大型平行文本数据集。即,相同的句子但是不同的语言,其中两个句子具有相同的意思(彼此的翻译)。

使用师生设置,现在我们可以强制艾伯特模型学习句子的“正确”向量嵌入。

这意味着在我们在足够数量的并行语言上训练模型之后,我们将教会 ALBERT 为任何语言产生相同的向量。一旦我们有了这个训练好的艾伯特模型,我们就可以直接用它来产生矢量嵌入。这是这个新训练的设置在多语言测试中的比较。

以下是 STS 任务中 10 种语言的向量相似度结果。

在表中,当在 SBERT 的监督下训练时,蒸馏使用开始胜过激光。我们可以看到,XLM-罗伯塔和姆伯特在跨语言句子相似性方面很弱。

外语语义搜索

让我们看看如何使用一个经过提炼的多语言转换器。

首先,让我们创建几个样本句子,我们想用它们来衡量语义相似度—

**Sample Sentences:**
'A man is eating food.',
'A man is eating a piece of bread.',
'The girl is carrying a baby.',
'A man is riding a horse.',
'An elderly man is enjoying dinner.',
'Friends sharing wine at a restaurant.',
'A woman is playing violin.',
'A child is learning to play a base guitar.',
'Two men pushed carts through the woods.',
'A man is riding a white horse on an enclosed ground.',
'A monkey is playing drums.',
'A cheetah is running behind its prey.'**Query Sentences:** 'A man is eating pasta.',
'Someone in a gorilla costume is playing a set of drums.',
'A cheetah chases prey on across a field.'

现在让我们把一些句子翻译成外语。我们将使用意大利语、法语、德语和俄语。这里是翻译的句子和问题—

**Sample Sentences:**
*'Un homme mange de la nourriture.',* #FR
'A man is eating a piece of bread.',
*'Das Mädchen trägt ein Baby.',* #DE 
'A man is riding a horse.',
'An elderly man is enjoying dinner.',
*'Amis partageant du vin dans un restaurant.',* #FR 
'A woman is playing violin.',
'A child is learning to play a base guitar.',
*'Due uomini hanno spinto i carrelli attraverso i boschi.',* #IT 
'A man is riding a white horse on an enclosed ground.',
*'Una scimmia suona la batteria.',* #IT  
'A cheetah is running behind its prey.'**Query Sentences:**
'A man is eating pasta.', 
*'Кто-то в костюме гориллы играет на барабане',* #RU 
'Ein Gepard jagt Beute über ein Feld.'

通过我们的多语言转换器运行语义搜索会产生即时结果—

**======================** 
**Query**: A man is eating pasta.

**Top 3 most similar sentences in sample sentences**:
Un homme mange de la nourriture. (Score: 0.7051)
A man is eating a piece of bread. (Score: 0.6328)
An elderly man is enjoying dinner. (Score: 0.4780)

**======================** 
**Query**: Кто-то в костюме гориллы играет на барабане

**Top 3 most similar sentences in sample sentences**:
Una scimmia suona la batteria. (Score: 0.3803)
A woman is playing violin. (Score: 0.3392)
A child is learning to play a base guitar. (Score: 0.3148)

**======================** 
**Query**: Ein Gepard jagt Beute über ein Feld.

**Top 3 most similar sentences in sample sentences**:
A cheetah is running behind its prey. (Score: 0.3890)
A man is riding a white horse on an enclosed ground. (Score: 0.3078)
Due uomini hanno spinto i carrelli attraverso i boschi. (Score: 0.3035)

为了重现性,这是跨语言语义搜索的代码—

附加的代码将把每个句子转换成一个向量,并计算余弦相似度,为每个查询输出 3 个最接近的句子。

结论

使用跨语言句子嵌入模型,我们现在可以在为下游任务构建分类器时抽象输入语言。

这意味着,如果我们有一个只适用于英语文本的自然语言处理模型,我们现在可以将这个自然语言处理模型重新用于任何语言。

非常感谢 Nils Reimers,下面的库展示了如何提炼你自己的多语言句子模型,我鼓励你这么做。

参考

[1]尼尔斯·雷默斯和伊琳娜·古雷维奇。 制作单语句子嵌入多语使用知识蒸馏 arXiv (2020): 2004.09813。

前沿语义搜索和句子相似度

原文:https://towardsdatascience.com/cutting-edge-semantic-search-and-sentence-similarity-53380328c655?source=collection_archive---------10-----------------------

语义搜索是自然语言处理中一个值得解决的难题。

安东尼·马蒂诺在 Unsplash 上的照片

我们通常花费大量时间在大型文档中查找特定的信息。我们通常发现,如果使用 CTRL + F,即众所周知的 Google-fu,有效地在 Google 上搜索信息的艺术在 21 世纪的工作场所是一项有价值的技能。人类的所有知识对我们来说都是可用的,这是一个提出正确的问题,并知道如何浏览结果以找到相关答案的问题。

我们的大脑执行语义搜索,我们查看结果并找到与我们的搜索查询相似的句子。在金融和法律行业尤其如此,因为文档变得很长,我们不得不求助于搜索许多关键字来找到正确的句子或段落。时至今日,人类在发现上所花费的努力是惊人的。

自 NLP 出现以来,机器学习一直在试图解决语义搜索的这个问题。一个完整的研究领域——语义搜索出现了。最近,由于深度学习的进步,计算机能够在最少的人工参与下准确地向我们提供相关信息。

句子嵌入方法

自然语言处理(NLP)领域对此有一个术语,当提到一个词时,我们称之为“表面形式”,例如单词“president”本身就意味着国家的首脑。但根据背景和时间,这可能意味着特朗普或奥巴马。

NLP 的进步使我们能够有效地映射这些表面形式,并捕获这些单词的上下文,成为所谓的“嵌入”嵌入通常是具有某些特殊特征的数字向量。两个意思相似的单词会有相似的向量,这让我们可以计算向量相似度。

延伸这个想法,在向量空间中,我们应该能够计算任意两个句子之间的相似度。这就是句子嵌入模型所实现的。这些模型将任何给定的句子转换成向量,以便能够快速计算任何一对句子的相似性或不相似性。

最先进的语义搜索——寻找最相似的句子

这个想法并不新鲜,早在 2013 年,这篇论文就提出了用向量来表示单个单词。然而,从那以后,我们用 BERT 和其他基于 Transformer 的模型走了很长的路,使我们能够更有效地捕捉这些单词的上下文。

这里我们比较了最近的嵌入模型和过去的 word2vec 或 GloVe。

STS 是自然语言处理的句子意思相似度竞赛。越高越好。来自 SBERT paper 的表格

这些经过修改和微调的 BERT NLP 模型在识别相似句子方面相当出色,比更老的前辈好得多。让我们看看这在实际意义上意味着什么。

我有几篇 2020 年 4 月的文章标题,我希望找到与一组搜索词最相似的句子。

这是我的搜索词—

1\. The economy is more resilient and improving.
2\. The economy is in a lot of trouble.
3\. Trump is hurting his own reelection chances.

我的文章标题如下—

Coronavirus:
White House organizing program to slash development time for coronavirus vaccine by as much as eight months (Bloomberg)
Trump says he is pushing FDA to approve emergency-use authorization for Gilead's remdesivir (WSJ)
AstraZeneca to make an experimental coronavirus vaccine developed by Oxford University (Bloomberg)
Trump contradicts US intel, says Covid-19 started in Wuhan lab. (The Hill)
Reopening:
Inconsistent patchwork of state, local and business decision-making on reopening raising concerns about a second wave of the coronavirus (Politico)
White House risks backlash with coronavirus optimism if cases flare up again (The Hill)
Florida plans to start reopening on Monday with restaurants and retail in most areas allowed to resume business in most areas (Bloomberg)
California Governor Newsom plans to order closure of all state beaches and parks starting Friday due to concerns about overcrowding (CNN)
Japan preparing to extend coronavirus state of emergency, which is scheduled to end 6-May, by about another month (Reuters)
Policy/Stimulus:
Economists from a broad range of ideological backgrounds encouraging Congress to keep spending to combat the coronavirus fallout and don't believe now is time to worry about deficit (Politico)
Global economy:
China's official PMIs mixed with beat from services and miss from manufacturing (Bloomberg)
China's Beige Book shows employment situation in Chinese factories worsened in April from end of March, suggesting economy on less solid ground than government data (Bloomberg)
Japan's March factory output fell at the fastest pace in five months, while retail sales also dropped (Reuters)
Eurozone economy contracts by 3.8% in Q1, the fastest decline on record (FT)
US-China:
Trump says China wants to him to lose his bid for re-election and notes he is looking at different options in terms of consequences for Beijing over the virus (Reuters)
Senior White House official confident China will meet obligations under trad deal despite fallout from coronavirus pandemic (WSJ)
Oil:
Trump administration may announce plans as soon as today to offer loans to oil companies, possibly in exchange for a financial stake (Bloomberg)
Munchin says Trump administration could allow oil companies to store another several hundred million barrels (NY Times)
Norway, Europe's biggest oil producer, joins international efforts to cut supply for first time in almost two decades (Bloomberg)
IEA says coronavirus could drive 6% decline in global energy demand in 2020 (FT)
Corporate:
Microsoft reports strong results as shift to more activities online drives growth in areas from cloud-computing to video gams (WSJ)
Facebook revenue beats expectations and while ad revenue fell sharply in March there have been recent signs of stability (Bloomberg)
Tesla posts third straight quarterly profit while Musk rants on call about need for lockdowns to be lifted (Bloomberg)
eBay helped by online shopping surge though classifieds business hurt by closure of car dealerships and lower traffic (WSJ)
Royal Dutch Shell cuts dividend for first time since World War II and also suspends next tranche of buyback program (Reuters)
Chesapeake Energy preparing bankruptcy filing and has held discussions with lenders about a ~$1B loan (Reuters)
Amazon accused by Trump administration of tolerating counterfeit sales, but company says hit politically motivated (WSJ)

在运行每个查询与每个嵌入的相似性后,以下是我的每个搜索词的前 5 个相似句子:

======================
**Query: The economy is more resilient and improving**.Top 5 most similar sentences in corpus:
Microsoft reports strong results as shift to more activities online drives growth in areas from cloud-computing to video gams (WSJ) (Score: 0.5362)
Facebook revenue beats expectations and while ad revenue fell sharply in March there have been recent signs of stability (Bloomberg) (Score: 0.4632)
Senior White House official confident China will meet obligations under trad deal despite fallout from coronavirus pandemic (WSJ) (Score: 0.3558)
Economists from a broad range of ideological backgrounds encouraging Congress to keep spending to combat the coronavirus fallout and don't believe now is time to worry about deficit (Politico) (Score: 0.3052)
White House risks backlash with coronavirus optimism if cases flare up again (The Hill) (Score: 0.2885)
======================
**Query: The economy is in a lot of trouble.**Top 5 most similar sentences in corpus:
Inconsistent patchwork of state, local and business decision-making on reopening raising concerns about a second wave of the coronavirus (Politico) (Score: 0.4667)
eBay helped by online shopping surge though classifieds business hurt by closure of car dealerships and lower traffic (WSJ) (Score: 0.4338)
China's Beige Book shows employment situation in Chinese factories worsened in April from end of March, suggesting economy on less solid ground than government data (Bloomberg) (Score: 0.4283)
Eurozone economy contracts by 3.8% in Q1, the fastest decline on record (FT) (Score: 0.4252)
China's official PMIs mixed with beat from services and miss from manufacturing (Bloomberg) (Score: 0.4052)
======================
**Query: Trump is hurting his own reelection chances.**Top 5 most similar sentences in corpus:
Trump contradicts US intel, says Covid-19 started in Wuhan lab. (The Hill) (Score: 0.7472)
Amazon accused by Trump administration of tolerating counterfeit sales, but company says hit politically motivated (WSJ) (Score: 0.7408)
Trump says China wants to him to lose his bid for re-election and notes he is looking at different options in terms of consequences for Beijing over the virus (Reuters) (Score: 0.7111)
Inconsistent patchwork of state, local and business decision-making on reopening raising concerns about a second wave of the coronavirus (Politico) (Score: 0.6213)
White House risks backlash with coronavirus optimism if cases flare up again (The Hill) (Score: 0.6181)

你可以看到这个模型能够非常准确地挑出最相似的句子。

我使用的代码可以在下面找到—

上面的例子很简单,但是阐明了语义搜索的一个重要观点。人类需要几分钟才能找到最相似的句子。它让我们能够在没有人类参与的情况下找到文本中的特定信息,这意味着我们可以以计算机速度在成千上万的文档中搜索我们关心的短语。

这项技术已经被用来在两个文档中寻找相似的句子。或者季度收益报告中的关键信息。例如,通过这种语义搜索,我们可以轻松找到 Twitter、脸书、Snapchat 等所有社交公司的日活跃用户。尽管他们对 metic 的定义和称呼不同——日活跃用户(DAU)或月活跃用户(MAU)或货币化活跃用户(mMAU)。由 BERT 支持的语义搜索可以发现所有这些表面形式在语义上意味着相同的东西——一种性能的衡量标准,它能够从报告中提取出我们感兴趣的句子。

对冲基金正在利用语义搜索来解析和揭示季度报告(10-Q/10-K)中的指标,并在报告发布后立即将其作为定量交易信号,这并不是一个遥不可及的想法。

上面的实验显示了语义搜索在过去的一年中变得多么有效。

寻找相似句子——聚类

人们可以使用句子的这些向量嵌入的另一个主要方式是用于聚类。我们可以快速地将单个文档或多个文档中的句子聚集成相似的组。

使用上面的代码,人们可以利用 sklearn 的简单 k-means

from sklearn.cluster import KMeans
import numpy as npnum_clusters = 10
clustering_model = KMeans(n_clusters=num_clusters)
clustering_model.fit(corpus_embeddings)
cluster_assignment = clustering_model.labels_for i in range(10):
    print()
    print(f'Cluster {i + 1} contains:')
    clust_sent = np.where(cluster_assignment == i)
    for k in clust_sent[0]:
        print(f'- {corpus[k]}')

同样,结果对机器来说是精确的。这是几个集群—

**Cluster 2 contains:**
- AstraZeneca to make an experimental coronavirus vaccine developed by Oxford University (Bloomberg)
- Trump says he is pushing FDA to approve emergency-use authorization for Gilead's remdesivir (WSJ)

**Cluster 3 contains:**
- Chesapeake Energy preparing bankruptcy filing and has held discussions with lenders about a ~$1B loan (Reuters)
- Trump administration may announce plans as soon as today to offer loans to oil companies, possibly in exchange for a financial stake (Bloomberg)
- Munchin says Trump administration could allow oil companies to store another several hundred million barrels (NY Times)

**Cluster 4 contains:**
- Trump says China wants to him to lose his bid for re-election and notes he is looking at different options in terms of consequences for Beijing over the virus (Reuters)
- Amazon accused by Trump administration of tolerating counterfeit sales, but company says hit politically motivated (WSJ)
- Trump contradicts US intel, says Covid-19 started in Wuhan lab. (The Hill)

结论

有趣的是,elastics 现在每个都有一个密集的矢量场,行业中的其他公司也有能力快速比较两个矢量,如脸书的 faiss 。这项技术是尖端的,但操作性很强,可以在几周内推出。任何知道要寻找什么的人都可以找到尖端人工智能。

如果您有兴趣了解更多信息,请随时联系我,我随时为您提供电子咖啡。在外面注意安全。

感谢 Nils Reimers 关于拥抱脸讨论的内容丰富的帖子,这让我写了这篇文章。

带有 Matplotlib 的赛博朋克风格

原文:https://towardsdatascience.com/cyberpunk-style-with-matplotlib-f47404c9d4c5?source=collection_archive---------10-----------------------

为您的下一个数据可视化未来霓虹灯发光。

更新 2020–03–29:现在有一个 Python 包可以方便地应用这种风格,这里 。通过 pip install mplcyberpunk安装

1 —基础

让我们编一些数字,把它们放进熊猫的数据框里,并把它们画出来:

import pandas as pd
import matplotlib.pyplot as pltdf = pd.DataFrame({'A': [1, 3, 9, 5, 2, 1, 1],
                   'B': [4, 5, 5, 7, 9, 8, 6]})df.plot(marker='o')
plt.show()

2 —黑暗

还不错,但是有些普通。让我们通过使用 Seaborn 的深色风格以及更改背景和字体颜色来定制它:

plt.style.use("seaborn-dark")for param in ['figure.facecolor', 'axes.facecolor', 'savefig.facecolor']:
    plt.rcParams[param] = '#212946'  # bluish dark greyfor param in ['text.color', 'axes.labelcolor', 'xtick.color', 'ytick.color']:
    plt.rcParams[param] = '0.9'  # very light greyax.grid(color='#2A3459')  # bluish dark grey, but slightly lighter than background

3 —灯光

现在看起来更有趣了,但我们需要我们的颜色在深色背景下更加闪亮:

fig, ax = plt.subplots()
colors = [
    '#08F7FE',  # teal/cyan
    '#FE53BB',  # pink
    '#F5D300',  # yellow
    '#00ff41', # matrix green
]
df.plot(marker='o', ax=ax, color=colors)

4 —发光

现在,如何获得霓虹灯的外观?为了让它发亮,我们用低 alpha 值和略微增加的线宽多次重画线条。重叠产生发光效果。

n_lines = 10
diff_linewidth = 1.05
alpha_value = 0.03for n in range(1, n_lines+1): df.plot(marker='o',
            linewidth=2+(diff_linewidth*n),
            alpha=alpha_value,
            legend=False,
            ax=ax,
            color=colors)

5 —终点

为了更好的调整,我们给线下的区域着色(通过ax.fill_between)并调整轴的限制。

以下是完整的代码:

import pandas as pd
import matplotlib.pyplot as plt plt.style.use("dark_background")for param in ['text.color', 'axes.labelcolor', 'xtick.color', 'ytick.color']:
    plt.rcParams[param] = '0.9'  # very light greyfor param in ['figure.facecolor', 'axes.facecolor', 'savefig.facecolor']:
    plt.rcParams[param] = '#212946'  # bluish dark greycolors = [
    '#08F7FE',  # teal/cyan
    '#FE53BB',  # pink
    '#F5D300',  # yellow
    '#00ff41',  # matrix green
] df = pd.DataFrame({'A': [1, 3, 9, 5, 2, 1, 1],
                   'B': [4, 5, 5, 7, 9, 8, 6]})fig, ax = plt.subplots()df.plot(marker='o', color=colors, ax=ax)# Redraw the data with low alpha and slighty increased linewidth:
n_shades = 10
diff_linewidth = 1.05
alpha_value = 0.3 / n_shadesfor n in range(1, n_shades+1): df.plot(marker='o',
            linewidth=2+(diff_linewidth*n),
            alpha=alpha_value,
            legend=False,
            ax=ax,
            color=colors)# Color the areas below the lines:
for column, color in zip(df, colors):
    ax.fill_between(x=df.index,
                    y1=df[column].values,
                    y2=[0] * len(df),
                    color=color,
                    alpha=0.1)ax.grid(color='#2A3459')ax.set_xlim([ax.get_xlim()[0] - 0.2, ax.get_xlim()[1] + 0.2])  # to not have the markers cut off
ax.set_ylim(0)plt.show()

如果这对你有帮助,或者你有建设性的批评,我很乐意听听!请通过此处的或此处的联系我。谢谢!

基于集成机器学习的网络安全威胁预测

原文:https://towardsdatascience.com/cybersecurity-threat-prediction-using-ensemble-machine-learning-e1d61976664?source=collection_archive---------43-----------------------

使用多重插补处理缺失数据&实施集成学习算法来预测端点安全威胁。

马太·亨利Unsplash 上拍照

这个项目的数据集和代码可以在我的 GitHub 存储库中找到。在这个故事的结尾分享了相同的链接。

T 多年来,网络犯罪行业一直在发展壮大,尤其是由于越来越多的数据(个人和组织的)可以在数字媒体上获得。如今,网络犯罪带来的问题导致全球各地的公司损失了数百万美元。 在 Ponemon Institute 对 16 个国家和地区的 17 个行业的 507 个组织进行的一项研究 中,定义了 2019 年数据泄露的全球平均成本为 392 万美元,比 2018 年的估计值增加了 1.5%。世界各地的组织都在大力投资使用机器学习和人工智能的预测分析能力,以缓解这些挑战。

根据凯捷研究院(2019) 的一份报告,48%的组织表示他们在 2020 财年实施网络安全预测分析的预算将增加 29%。56%的高级管理人员表示,网络安全分析师超负荷工作,近四分之一的人无法成功调查所有确定的问题。64%的组织表示,预测分析降低了威胁检测和响应的成本,并将总体检测时间减少了多达 12%。

利亚姆·塔克在 Unsplash 拍摄的照片

考虑到上述情况,从长远来看,将预测分析应用于调查可能被恶意软件感染的终端对于组织来说变得势在必行。该研究利用组织端点(台式机、笔记本电脑、手机、服务器等)的某些硬件和软件方面的规格知识来探索这一目标。).

数据混合了分类变量和数字变量。在这项研究中,面临的主要挑战之一是数据集中存在大量缺失数据。进一步分析后的数据被归类为随机缺失(MAR)。数据集中的变量有:

缺失数据分类和多重插补技术

缺失数据或缺失值只不过是正在进行的研究中感兴趣的变量缺少数据值。在执行统计分析时,它会带来几个问题。

使用gif gif创建

大多数统计分析方法都剔除了缺失值,从而减少了要处理的数据集的大小。通常,没有足够的数据来处理所创建的模型产生的结果在统计上并不显著。此外,缺失的数据可能会导致结果误导。结果往往偏向于在人群中代表性过高的某个/某些细分市场。

缺失数据分类

缺失数据的分类最早是由 Rubin 在他的题为'推论和缺失数据'的论文中讨论的。根据他的理论,数据集中的每个数据点都有丢失的可能性。基于这种概率,Rubin 将缺失数据分为以下几种类型:

  1. 完全随机缺失(MCAR) :在这种情况下,数据的缺失与数据中的其他响应或信息无关。对于所有其他数据点,数据集中任何数据点缺失的概率保持不变。简而言之,数据缺失没有可识别的模式。与 MCAR 打交道时,需要注意的一件重要事情是,对 MCAR 的分析会产生公正的结果。
  2. 随机缺失(MAR) :与 MCAR 相比,MAR 是缺失数据的一种更广泛的分类,在某些方面也更现实。在 MAR 的情况下,对于为统计研究定义的某些数据子集,数据缺失的概率是相似的。数据的缺失可以归因于存在的其他数据,因此可以预测。同样,用更简单的话来说,在 MAR 的情况下,数据缺失是有模式的。
  3. 非随机缺失(NMAR) :不归入 MCAR 和火星的数据归入 NMAR。

使用小鼠的多重插补(通过链式方程的多元插补)

Rubin(1987)提出了估计缺失数据的多重插补方法。该方法从包含缺失值的数据集开始,然后使用线性回归等统计模型为缺失数据创建几组估算值。随后计算每个估算数据集的相关参数,最终汇集成一个估计值。下图显示了四阶多重插补方法的图示。

4 阶多重插补的步骤

单一插补方法,如均值插补、回归插补等。假设估算的估算值是真实值,忽略与估算值预测相关的不确定性。

与单一插补相比,使用多重插补的优势在于:

  1. 在单一插补技术情况下太小的标准误差通过使用多重插补得到很好的缓解。
  2. 多重插补不仅适用于 MCAR 数据,也适用于 MAR 数据。
  3. 通过多个估算数据集获得的数据的变化有助于抵消任何种类的偏差。这是通过添加单一插补技术中缺失的不确定性来实现的。这反过来提高了精度,并产生了稳健的统计数据,从而可以对数据进行更好的分析。

在 R 中进行多重插补的最流行方法之一是使用 MICE(通过链式方程进行多元插补)软件包。在我们的数据集上实现鼠标的代码共享如下:

library(mice)
library(caret)df = read.csv('Data.csv')
View(df)#checking for NAs in the data
sapply(df, function(x) sum(is.na(x)))##############converting into factors(categorical variables)
df$HasTpm = as.factor(df$HasTpm)
df$IsProtected = as.factor(df$IsProtected)
df$Firewall = as.factor(df$Firewall)
df$AdminApprovalMode = as.factor(df$AdminApprovalMode)
df$HasOpticalDiskDrive = as.factor(df$HasOpticalDiskDrive)
df$IsSecureBootEnabled = as.factor(df$IsSecureBootEnabled)
df$IsPenCapable = as.factor(df$IsPenCapable)
df$IsAlwaysOnAlwaysConnectedCapable = as.factor(df$IsAlwaysOnAlwaysConnectedCapable)
df$IsGamer = as.factor(df$IsGamer)
df$IsInfected = as.factor(df$IsInfected)str(df)
ncol(df)###############REMOVING MachineId FROM DATA FRAME
df = df[,-c(1)]##############IMPUTATION OF MISSING DATA USING MICE
init = mice(df, maxit=0) 
meth = init$method
predM = init$predictorMatrix#Excluding the output column IsInfected as a predictor for Imputation
predM[, c("IsInfected")]=0#Excluding these variables from imputation as they don't have null valuesmeth[c("ProductName","HasTpm","Platform","Processor","SkuEdition","DeviceType","HasOpticalDiskDrive","IsPenCapable","IsInfected")]=""#Specifying the imputation methods for the variables with missing data

meth[c("SystemVolumeTotalCapacity","PrimaryDiskTotalCapacity","TotalPhysicalRAM")]="cart" meth[c("Firewall","IsProtected","IsAlwaysOnAlwaysConnectedCapable","AdminApprovalMode","IsSecureBootEnabled","IsGamer")]="logreg" meth[c("PrimaryDiskTypeName","AutoUpdate","GenuineStateOS")]="polyreg"#Setting Seed for reproducibility 
set.seed(103)#Imputing the data
class(imputed)
imputed = mice(df, method=meth, predictorMatrix=predM, m=5)
imputed <- complete(imputed)sapply(imputed, function(x) sum(is.na(x)))sum(is.na(imputed))

集成学习方法

集成学习方法使用多个模型的组合计算能力来分类和解决手头的问题。当与只创建一个学习模型的普通学习算法相比时,集成学习方法创建多个这样的模型,并将它们组合起来,以形成最终的模型,从而进行更有效的分类。集成学习也被称为基于委员会的学习或学习多分类器系统。

集成学习方法被使用和赞赏,因为它们的能力可以提高弱学习者的表现,弱学习者通常被称为基础学习者。这反过来产生具有更高精度和更强泛化性能的预测。所创建的模型在本质上也更加稳健,并且对数据中的噪声反应良好。

Bagging 集成学习

Bagging 是 Bootstrap Aggregating 的缩写,用于解决分类和回归问题。装袋方法包括创建多个样本,这些样本在替换时是随机的。这些样本被用来创建模型,模型的结果被合并在一起。使用 Bagging 算法的优势在于,它们减少了预测模型过度拟合数据的机会。由于每个模型都建立在不同的数据集上,因此模型中可约误差的方差误差分量较低,这意味着模型可以很好地处理测试数据中的方差。 在这项研究中,我们使用了两种装袋算法,即装袋购物车算法和随机森林算法。

通用 Bagging 整体架构

推进集成学习

增强集成学习基于先前分类模型的性能,在调整训练数据集中存在的观察的权重的迭代方法上工作。如果分类不正确,则观察值的权重增加,如果分类正确,则权重减少。在可归约误差的偏差误差分量高的情况下,增强集成学习具有优势。升压减少了这种偏差误差,并有助于建立更强的预测模型。 在这项研究中,我们使用了两种 bagging 算法,即 C5.0 决策树 Boosting 算法&随机分级 Boosting 算法。

公共增强集成架构

所用各种型号的 R 代码如下所示:

# Example of Boosting Algorithms
control <- trainControl(method="repeatedcv", number=10, repeats=3, classProbs = TRUE, summaryFunction = twoClassSummary)
seed <- 7
metric <- "ROC"# C5.0
set.seed(seed)
fit.c50 <- train(IsInfected~., data=imputed, method="C5.0", metric=metric, trControl=control)# Stochastic Gradient Boosting
set.seed(seed)
fit.gbm <- train(IsInfected~., data=imputed, method="gbm", metric=metric, trControl=control, verbose=FALSE)# summarize results
boosting_results <- resamples(list(c5.0=fit.c50, gbm=fit.gbm))
summary(boosting_results)
dotplot(boosting_results)# Example of Bagging algorithmscontrol <- trainControl(method="repeatedcv", number=10, repeats=3, classProbs = TRUE, summaryFunction = twoClassSummary)seed <- 7metric <- "ROC"# Bagged CART
set.seed(seed)
fit.treebag <- train(IsInfected~., data=imputed, method="treebag", metric=metric, trControl=control)# Random Forest
set.seed(seed)
fit.rf <- train(IsInfected~., data=imputed, method="rf", metric=metric, trControl=control)# summarize results
bagging_results <- resamples(list(treebag=fit.treebag, rf=fit.rf))
summary(bagging_results)
dotplot(bagging_results)

结果呢

在应用各种集合模型之后,发现树深度为 3 且树数量为 100 的随机梯度增强模型给出了精确度和 ROC 曲线下面积的最佳值。

该研究旨在建立一个假设,即通过对组织端点规格的正确了解(包括软件和硬件),可以预测端点受恶意软件攻击和其他网络安全威胁感染的可能性。为了实现本研究的目的,我们面临了与数据相关的几个现实挑战,如了解缺失数据、使用多重插补技术对缺失数据进行插补、数据交叉验证的挑战以及模型的性能评估。

****本研究中用于构建模型的变量列表并非详尽无遗,可以根据各种组织的可用性和适用性添加一些新的指标和变量,以构建更准确、更稳健的模型。

Philipp Katzenberger 在 Unsplash 上的照片

邀请您查看 GitHub repo 进行上述分析!

** [## visha kha-b18/网络安全-威胁-预测

恶意软件行业的扩散是大量个人和机密信息的结果…

github.com](https://github.com/vishakha-b18/Cybersecurity-Threat-Prediction)

在 LinkedIn 上与我联系!

[## Vishakha Bhattacharjee -哥伦比亚商学院助教| LinkedIn

目前在纽约哥伦比亚大学攻读商业分析硕士学位。前商业情报分析师在…

www.linkedin.com](https://www.linkedin.com/in/vishakha-bhattacharjee/)**

用 PyTorch 循环 GAN

原文:https://towardsdatascience.com/cycle-gan-with-pytorch-ebe5db947a99?source=collection_archive---------19-----------------------

cycleGAN 的一般概念,展示了如何将输入斑马生成为马,然后循环返回并生成斑马。(图片由作者提供)

在这篇文章中,我将分享一个有趣的项目,我是其中的一部分,该项目的目标是建立一个循环甘,可以接受 A 类的图像,并将其转换为 B 类,在这种情况下,马和斑马。我将依次介绍以下主题:

  • 周期 GAN 描述,主要特性。
  • 在哪里以及如何找到图像数据。
  • PyTorch 中 GAN 循环的实现。
  • 结果介绍。

循环甘描述

圈 GAN(据我所知)在论文 中首次被介绍使用圈一致对抗网络 进行不成对的图像到图像翻译。(我推荐任何对计算机视觉感兴趣的人阅读这篇论文,因为它不是很长,并且提供了周期 GAN 背后的直觉以及损失函数的重要数学公式。)使循环 GAN 有趣的是,它是并行学习的两个神经网络之间的组合/游戏。这两个网络被称为接收真实图像并输出虚假图像的发生器和分类图像是真实还是虚假的鉴别器。目标是随着时间的推移,生成器将变得更擅长欺骗鉴别器,而鉴别器将变得更擅长不被欺骗。为了相应地优化发生器和鉴别器,总共引入了八个损失函数。可以使用各种损失函数,但在这个项目中,我们使用基于最小二乘法的 LSGAN 损失函数和绝对平均值的 L1 损失函数。

鉴别器:LSGAN 损耗

如前所述,鉴别器的目标是将真实图像分类为真实图像,将虚假图像分类为虚假图像,为了对此进行优化,使用了以下最小平方损失函数:

这里的直觉是,在真实图像的情况下,完美的鉴别器将输出全 1,并且从第一项得到零损失。在伪图像的情况下,完美的鉴别器将输出全零,并且也获得零损失。LSGAN 用于模型中的每个鉴别器一次。

发生器:特技鉴别器

生成器的目标之一是欺骗鉴别者相信假图像是真的。为了让生成器在欺骗鉴别器方面做得更好,鉴别器应该为生成的图像输出全 1。在这种情况下,发电机的损耗为零。为了实现这一点,定义了与上述略有不同的 LS 损失函数定义:

发电机:周期一致性

我们对生成器施加约束,称为周期一致性。我们希望生成器能够首先从一个类域映射到另一个类域,然后在不对图像进行任何更改的情况下返回到第一个类域。该约束是通过在真实图像和恢复图像之间的像素到像素级别上使用 L1 损失函数来施加的:

生成器:身份丢失

当提供目标域的实像样本时,单位损失意味着将生成器正则化为接近单位映射。换句话说,如果一个输入图像已经看起来像目标域,那么生成器不应该将它映射到不同的图像中(例如,马不应该被重构为马)。这种特性是通过身份损失强加的,并且基于如上所示的相同的 L1 损失函数。在最初的 Cycle GAN 论文的第 5.2 节中讨论了通过 L1 正则化利用恒等函数的概念。

发电机架构

发生器结构(尺寸取决于图像大小)。(图片由作者提供)

如上图所示,生成器有三个主要组件,编码阶段、转换和解码。

编码:

编码阶段通过多个卷积层将图像中的特征转换成潜在空间表示。

转型:

转换阶段由六个或九个 resnet 块组成,用于组合在编码阶段捕获的适当潜在特征。resnet 块还具有跳过连接的好处,这有助于避免深度网络中的消失梯度。

解码:

解码阶段与编码阶段相反,通过转置卷积组装潜在表示。

鉴别器架构

鉴别器结构。(图片由作者提供)

鉴别器仅仅是由卷积层组成的网络,并且具有执行二元分类的功能,即图像是真的还是假的。

查找图像数据

对于任何对图像数据执行模式识别任务感兴趣的人来说,轻松快速地找到大量特定区域的图像是非常重要的。大多数深度学习框架,如 tensorflow、keras 和 PyTorch,都具有让用户轻松访问 cifar 10、mnist fasion/ digits 等流行数据集的功能。然而,找到个人图像数据需要更多的努力,但仍然不是很困难。我发现下面这个话题的论坛讨论很有参考价值: 链接 。我个人发现 ImageNet 在抓取图像数据方面既简单又可靠。根据我的经验,ImageNet 可以提供给定对象(如草莓)的大约 1000 张图像,对于深度学习应用程序来说,这可能是也可能不是足够的数据。

这个项目使用的数据是大小为 256 X 256 的马和斑马的图像。马/斑马数据集(不是我自己收集的)可以在以下链接找到: [链接](https://drive.google.com/uc?id=1jPelB2jzNZJq3ZU9Uk Mkt4MJtF3DRgg) 。

使用 PyTorch 循环 GAN 实施

发电机网络定义如下。

鉴频器网络定义如下。

分别用于发生器和鉴别器网络的上述损耗函数如下所示实现。

用于训练网络的完整代码可以在下面的笔记本中找到。通过 google corroboratory 使用 GPU 训练网络。

结果

下图显示了从上述实现中接收到的一些结果图像。

周期 GAN 结果。(图片由作者提供)

当我们查看从模型生成的图像时,结果的质量相差很大。一些图像结果通常是好的,而其他图像质量较低,例如图像中不包含任何被改变的动物的部分。通常,当从马图像生成假斑马时,如果有一匹棕色的马,并且马的身体的全部或大部分出现在图片中,并且马覆盖了图像的大部分,则获得最佳结果。如果图像中有大量噪声,即马的身体占据了图像的一小部分,那么发生器通常很难改变所产生的噪声。为什么会是这种情况的假设是,模型将图像解释为斑马,并且在这种情况下,由于来自身份损失函数的约束,生成器模型不改变输入图像。

一般来说,当模型要把斑马变成马时,它的表现比相反的情况要差。较差的表现最有可能归因于马的外观比斑马变化更大。注意到的另一个方面是,即使在训练数据图像中存在白色和黑色的马,在斑马转换图像上看到的变化是只有棕色被添加到斑马身体的较大或较小部分。这是因为数据集很可能包含更多棕色马的图像,因此模型过度适合棕色。

简单英语中的循环一致对抗网络

原文:https://towardsdatascience.com/cyclegan-math-in-simple-english-d4cdd59f0f07?source=collection_archive---------72-----------------------

CycleGAN 背后的数学损失函数分析

图片由朱俊彦上传于 Github

CycleGAN 是一种不成对图像到图像翻译的方法。不幸的是,在没有完全理解或欣赏其中的数学知识的情况下使用 CycleGAN 是可能的。这真是太遗憾了。

在本文中,我将介绍周期一致的敌对网络背后的数学原理。请阅读论文获取更全面的解释。

不成对与成对

CycleGAN 的关键是我们没有前后图像。

让我们以上面显示的将斑马转换成马的例子为例(反之亦然)。

在配对的数据集中,马和斑马需要彼此“匹配”。我们实际上是把一匹马涂成黑色和白色。背景、闪电等。保持不变。

成对的数据集看起来像这样:

图片由朱俊彦Github 上拍摄

在不成对的数据集中,马和斑马不需要彼此“匹配”。这个数据集更容易创建。

不成对的数据集应该是这样的:

图片来自达拉斯马术中心

生成器和鉴别器

正如你可能对 GAN 的期望,我们有生成器和鉴别器。我们的生成器也被称为映射函数。

让我们列举几个变量:

马和斑马

  • X指斑马
  • Y指一匹马

发电机

  • G指的是将斑马转换成马的映射函数
  • F指的是将马转换成斑马的映射函数

鉴别器

  • Dx指善于识别斑马的鉴别器。
  • Dy指善于识别马匹的鉴别者

将所有这些放在一起,我们就有了这样的东西:

图片来自 CycleGAN 论文

循环一致性损失

论文中,循环一致性图表如下:

图片来自 CycleGAN paper

下面是正在发生的事情:我们把一匹马的图像转换成斑马。然后在这个新创建的斑马上运行鉴别器。然后我们把新创建的斑马变成一匹马。

我们将这匹新造的马与我们现有的马进行比较。这就是y^ vs y的本质含义。我们新创建的马应该看起来和原来的马几乎一样。

我制作了一个信息图来解释这是如何工作的。

作者图片

现在我们重复这个过程。除了这一次,我们采取了一个斑马的形象,并试图转换成一匹马。数学术语中的损失函数

数学术语中的损失函数

对于我们的损失函数,我们有对抗性损失和周期一致性损失。

对抗性损失:

对抗性损失的损失函数如下:

图片来自 CycleGAN paper

我们来分析一下。

左手边接收:

  • Dy(马识别者)
  • G(我们的斑马对马创作者)
  • X(一只斑马)
  • Y(一匹马)

RHS 包含以下术语:

图片来自 CycleGAN paper

这个术语测量我们识别我们创造的斑马是真是假的能力。我们从所有斑马中抽出一只斑马,让它通过鉴别器。

下一学期:

图片来自 CycleGAN paper

这个术语衡量我们把一匹马变成斑马的能力。我们从所有生成的马中抽出一匹马,并将其通过鉴别器。

现在我们做第一项加上第二项。这给了我们上面看到的对抗性损失等式。

周期一致性丧失:

这是循环一致性损失的损失函数:

图片来自 CycleGAN 论文

我们来看第一项:

图片来自 CycleGAN 论文

这意味着:

  1. 我们从斑马数据集中随机抽取一只斑马。(x~p(x))
  2. 我们将斑马通过生成器(G)来创建一匹马。
  3. 我们将生成的马通过另一个生成器(F)来创建斑马
  4. 我们将步骤 3 中创建的斑马纹与步骤 1 中的随机斑马纹进行比较,并取差值的绝对值之和。

全面目标:

完整的损失函数如下:

图片来自 CycleGAN paper

只是我们之前看到的对抗性损失函数和周期一致性损失函数的和。其中λ控制每个目标的相对重要性。

最终,我们希望实现以下目标:

图片来自 CycleGAN paper

我们试图最大化鉴频器的能力,最小化发电机的损耗。这使我们能够很好地区分斑马和马,同时也能很好地生成马和斑马。

结束

CycleGAN 背后的数学似乎有些令人生畏。但是我已经尝试在这篇文章中涵盖了大概的内容。我希望这能帮助到一些人。当我学习 CycleGAN 如何工作时,这篇文章肯定会对我有所帮助。

如果我犯了错误,请随时通过 twitter 联系我,我会尽快修复。

非常感谢《CycleGAN》的作者:朱俊彦朴泰成菲利普·伊索拉阿列克谢·a·埃夫罗斯。我认为值得阅读他们的论文来更详细地了解这种方法。

原载于 2020 年 8 月 31 日https://spiyer 99 . github . io

循环生成网络

原文:https://towardsdatascience.com/cyclic-generative-networks-cyclegans-9b9526b2731c?source=collection_archive---------24-----------------------

生成网络解释

“其他人在他们的智慧的帮助下,将一个黄色的点变成了太阳”——巴勃罗·毕加索

将马的原始镜头转换为斑马的循环生成网络。

本文旨在解释循环 gan 的内部工作原理,以及它们如何应用于解决现实世界的任务。

介绍

C 循环生成对抗网络(简称cycle gans)【1】是强大的计算机算法,具有改善数字生态系统的潜力。它们能够将信息从一种表示转换成另一种表示。例如,当给定一幅图像时,他们可以模糊它,给它着色(例如,如果它原本是黑色的&白色的),提高它的清晰度,或者填补缺失的空白。

它们比你传统的设计/生产/写作平台更强大。因为cycle gan是机器学习算法,它们原则上可以学习实现任何想要的转换。相反,传统的转换软件(如 Photoshop)通常是硬编码的,用于执行特定的任务。此外, CycleGans 可以实现比现有软件更高的性能,因为它们可以从数据中学习,并随着数据的收集而改进。

了解不同层次的 CycleGans 的工作方式和能力令人兴奋,并提供了人工智能如何以前所未有的方式影响我们日常生活的见解。

CycleGAN 基于 3d 草图渲染手绘图像

生成网络

在谈论 CycleGans 之前,我们先简单讨论一下正则生成对抗网络。

生成对抗网络(简称 GANs)[2]是能够创建数据的机器学习算法。当他们得到图像、声音或文本等信息时,他们会学习产生新的看起来/听起来相似的输出。例如:给定一组人脸图像,算法可以自学 ( 训练,用机器学习的行话来说)人脸长什么样,并且能够创造新的人脸。我鼓励你看一看 这篇文章 ,我在其中旨在解释 GANs 的基本面。

环状 GANs 是传统 GANs 的特殊变体。他们还可以创建新的数据样本,但他们是通过转换输入样本来实现的,而不是从头开始创建输出。换句话说,他们学习转换来自两个数据源的数据;为该算法提供数据集的科学家或开发人员可以选择这些分布。在两个数据源是狗的图片和猫的图片的情况下,该算法能够有效地将猫的图像转换成狗的图像,反之亦然。

他们是怎么做到的?

什么是 CycleGan?

CycleGan 是学习两个域之间的两个数据转换函数的神经网络。其中之一就是转型**G**(x)。它将给定的样本x ∈ X转换成域Y的元素。第二个是**F**(y),将样本元素y ∈ Y转换成域X 的元素。

变换函数 F 和 g 的定义。

两个甘,一个辛克莱甘

考虑阅读 这篇文章 了解更多关于甘斯的内容

为了学习**F****G**,使用了两个传统的甘。每个 GAN 内部都有一个发生器网络,学习如何根据需要转换数据。GAN 的第一个生成器学习计算**F**,GAN 的第二个生成器学习计算**G**

生成函数 G 和 f 的定义。

此外,每个发生器都与一个鉴别器相关联,该鉴别器学习区分真实数据y和合成数据**G**(x)

生成函数 G 和 f 的定义。

因此,CycleGAN 由学习变换函数**F****G**的两个发生器和两个鉴别器组成。该结构显示在下图中:

CycleGan 表示法。它由两个甘组成,甘学习两种转化。

单 GAN 损耗

每个 GAN 发生器将通过最小化损耗来学习其相应的变换函数(或者**F**或者**G**)。通过测量生成的数据与目标数据的不同程度(例如,生成的猫图像与真实的猫图像相比的不同程度)来计算发生器损耗。差距越大,发生器将受到的惩罚越高。

鉴别器损耗也用于训练鉴别器,使其善于区分真实数据和合成数据。

当这两个代理设置在一起时,它们将相互改进。生成器将被训练来欺骗鉴别器,而鉴别器将被训练来更好地从合成数据中区分真实数据。因此,生成器将变得非常擅长创建/转换所需的数据(学习所需的转换,例如**F** )。

总的来说,GAN 损耗如下:

单个 GAN 损耗的定义。d 是鉴别器功能,G 是发生器功能。

第二个发生器-鉴别器对也有类似的损耗:

作为学习所需转换**F****G**的一种方式,CycleGAN 将尝试最小化两个 GAN 损耗的总和。

循环转换一致性

理想情况下,我们希望我们的 CycleGAN 学习周期一致的转换函数**F****G**。这意味着,给定一个输入x,我们希望来回转换**F(G(**x**))=** x'准确地输出原始输入x。理论上这应该是可能的,因为在输入端x应用**G**将在Y域输出一个值,在输入端y应用**F**将在X域输出一个值。

循环一致性减少了这些网络可以学习的可能映射集,并迫使**F****G**成为相反的变换。想象一下,学会的函数**F**通过修改自己的耳朵将猫的图片转化为狗的图片,而**G** 通过修改自己的鼻子学会将狗的图片转化为猫的图片。虽然这些转换可以达到目标,但是它们并不协调,因为它们对数据应用了不同的更改。使用周期一致性迫使**F****G**彼此相反。这样猫的图片会通过修改耳朵转化为狗的图片,狗的图片会通过反过来修改耳朵转化为猫的图片。如果这两个函数是循环一致的,那么它们也是更有意义的映射。

左:输入 x 的循环一致性损失的直观表示。右:输入 y 的循环一致性损失的直观表示。

仅使用 GAN 损耗训练 CycleGAN 并不能保证保持周期一致性。因此,额外的周期一致性损失被用于实施该属性。这种损失被定义为输入值x与其前向周期预测值**F**(**G**(x))之间的绝对值差( L1 范数),以及输入值y与其前向周期预测值**G**(**F**(y))。差异越大,预测值与原始输入值的差距就越大。理想情况下,我们的网络会将这种损失降至最低。

循环一致性损失的定义。相当于上图中的可视化表示。

完全损失

用于训练网络的完整周期 Gan 损耗定义为两个 GAN 损耗和周期一致性损耗之和。

加权因子 ƛ (名为λ)用于控制周期一致性损失在全部损失中的权重。与其他损失相比,权重越高,减少循环一致性损失就越相关。

完全损失的定义

被优化以最小化该函数的 CycleGANs 将能够学习期望的变换FG。机器学习培训的细节将留到我的后续文章中。

结果

CycleGans 已经在几个任务的完成情况上进行了测试,并且已经能够成功地解决它们。这些任务的几个例子是:

图像变换

输入:鲜花原图。输出:应用了焦点和效果的改进的花卉图片。

照片增强:CycleGans 经过训练,可以生成专业的花卉照片,具有几个级别的聚焦和模糊,以及任何照片编辑工具。

输入:风景图片。输出:相同的风景,不同风格的艺术品。

图像风格转换: CycleGans 被训练来转换图片和艺术品的风格,例如,他们已经能够将照片转换成相同风景的梵高风格的画作。

风景图片从冬天变成了夏天。

季节转换:与风格转换类似,CycleGANs 已用于转换拍摄照片的季节。这里的结果令人惊讶,因为许多图像看起来像真实的照片。

音频转换

音乐类型转换:苏黎世 ETH 大学的研究人员已经能够训练 CycleGANs 人将古典流行音乐类型的歌曲转换成古典音乐作品[4]。

语音转换:日本 NTT 通信科学实验室的研究人员展示了令人印象深刻的结果,他们使用 CycleGANs 在不同性别的说话者之间转换语音注册表[5]。

这部作品的音频样本可以在他们的网站找到。

其他人

CycleGan paper 官方网站提供了在互联网不同地方发现的其他 CycleGan 用例的图库。我希望这些有趣的例子能鼓励您进一步了解 CycleGans,并提出更多有用和有趣的应用。

CycleGan 使用的图库可以在这个网站找到。

CycleGan 问题

尽管 CycleGANs 在上述许多任务中取得了明显的成功,但仍显示出 100%的成功率。以下是他们目前的一些陷阱:

  1. 当 CycleGans 输入的数据来自他们接受训练的数据时,可能会产生意想不到的结果(见下图)。
  2. 需要几何变化而不是颜色或对比度的任务对输入的影响很小。

用于变换马和斑马图像的 CycleGan 没有人类的输入,因此它可以生成任意的变换。

进一步的研究可能侧重于改进这些领域的工作。一些策略包括使用更广泛和更多样化的数据集,以及使用半监督学习方法。

最后的话

我要感谢并祝贺来自加州大学伯克利分校人工智能研究实验室的朱俊彦、朴泰成、菲利普·伊索拉和阿列克谢·a·埃夫罗斯为 CycleGans 所做的工作。在他们的网站你会找到更多与项目相关的信息。

我鼓励你去看看我的 GANs 库,在那里你会发现不同类型的 GANs 在 Python 中的实现,以及一个正在从头开始在 PyTorch 和 TensorFlow 中的 CycleGan 实现。我将通过媒体发布一个教程,一旦我完成了。

感谢阅读这篇文章直到最后。我希望你在学习这个主题的过程中获得了乐趣,我将在下一期节目中与你见面。🎊

参考

【1】【朱俊彦】朴泰成菲力普·伊索拉阿列克谢·阿弗罗斯 、不成对的图像到图像翻译使用循环一致的对抗网络、**

【2】伊恩·j·古德菲勒、让·普盖-阿巴迪、迈赫迪·米尔扎、徐炳、大卫·沃德-法利、谢尔吉尔·奥泽尔、亚伦·库维尔、约舒阿·本吉奥,《生成性对抗性网络》,2014 年,【https://arxiv.org/abs/1406.2661

【3】泰罗卡拉斯萨穆利莱恩米卡艾塔拉简内赫尔斯滕贾科莱蒂宁******

【4】吉诺·布鲁纳【王】罗杰·瓦滕霍夫苏穆·赵 【象征性音乐流派转移用 CycleGAN、******

金子拓广龟冈博和田中寇信厚北藏 。CycleGAN-VC2:改进的基于 CycleGAN 的非并行语音转换,https://arxiv.org/abs/1904.04631******

周期性特征编码,是时候了!

原文:https://towardsdatascience.com/cyclical-features-encoding-its-about-time-ce23581845ca?source=collection_archive---------4-----------------------

找到一种简单的技术来转换时间、星期、月份或季节等特征,同时仍然保留它们的循环意义。

Unsplash 上由 Fabrizio Verrecchia 拍摄的照片

我总是发现关于特征工程的讨论很吸引人,因为它们揭示了数据科学家如何通过增加提供给算法的信息来改善建模过程。

即使您是数据科学的新手,您也可能知道有些变量不能直接输入到模型中。是的,我肯定是在谈论需要诸如 one-hot 或 get_dummies 编码方法之类的技术的分类特征。

当您处理时间序列数据时,您的数据帧索引通常具有日期时间格式(YYYY-MM-DD HH:MM:SS ),除了数据点的升序之外,您不会从中提取太多信息。

但是,您的数据集中可能存在一些隐藏的模式,这些模式不会被常规要素显示出来。我这里说的是循环模式,比如一天中的几个小时、一周中的几天、几个月、几个季节等等。

问题是,当涉及到将这些信息转换成可解释的特征时,我们通常会面临一个挑战。

让我们以建立一个能源消耗预测模型为例。

马太·亨利Unsplash 上拍照

我们肯定地知道,一天中的时间将对这种消耗有很大的影响。

为了将时间编码为从 00:00 到 23:59,我们的第一个猜测可能是将其转换为从 00:00 开始经过的分钟数,从 0 到 1439:

这里的问题是,模型会将 23:58 和 00:02 之间的差异视为 1336 间隙,而它们之间仅相隔 4 分钟!

我们如何解决这个问题?

如果你还记得高中的一些事情,你可能知道一些具有循环行为的函数…最著名的是余弦,因为它根据 0-2π循环在-1 和 1 之间变化。

余弦函数()

所以让我们通过余弦转换我们的时间,我们很好,不是吗?

我们将在 0 到 2π之间归一化 x 后运行余弦函数,这相当于一个余弦周期。作为一张图表胜过千言万语,我们就用 Plotly 来看看相应的结果:

1440 分钟标准化并通过余弦转换

所以我们现在有了比以前更接近的 00:00 和 23:59 的值,它们都在 1 左右!

但是你看到我们创造的新问题了吗?

两个不同的时间会得到相同的值:

《采访》中的詹姆斯·弗兰科

解决这个新问题的最好方法是添加另一个循环信息来区分具有相同余弦值的两个时间。我们可以把它想象成一个双轴坐标系统。

这大概是给余弦的哥哥打电话的恰当时机:正弦!

0-2π周期上的余弦和正弦函数(y)

通过将原来的时间转换为它们对应的余弦和正弦值,我们现在可以为 00:00 到 23:59 之间的每个时刻分配不同的坐标,使它们具有唯一性!

这样一个系统的可视化使它变得更加明显:

我们创造的余弦-正弦坐标系统

为了举例,让我们在一段时间内随机绘制 15 个点:

这种编码体系是否完美?不幸的是没有,以下是一些原因:

  • 你正在将一个信息转换成两个特征,从算法的角度来看,这将在数学上赋予它更大的权重。
  • 基于决策树的算法(随机森林,梯度提升树,XGBoost)一次根据一个特征建立它们的分割规则。这意味着它们将无法同时处理这两个特征,而 cos/sin 值将被视为一个单一坐标系。

然而,权衡有时是游戏的一部分,这仍然是编码周期性特征的好方法。

值得一提的是,开源算法(如脸书的 Prophet)确实允许您从时间序列中自动提取周期性信息,如年、月或日模式:

摘自脸书的《先知快速入门指南》

[## 快速启动

Prophet 遵循 sklearn 模型 API。我们创建一个 Prophet 类的实例,然后调用它的 fit 和 predict…

facebook.github.io](https://facebook.github.io/prophet/docs/quick_start.html#python-api) [## 皮埃尔-路易·贝斯康德关于媒介的文章

数据科学、机器学习和创新

pl-bescond.medium.com](https://pl-bescond.medium.com/pierre-louis-besconds-articles-on-medium-f6632a6895ad)

Cynefin 和数据驱动的决策——了解您的领域

原文:https://towardsdatascience.com/cynefin-and-data-driven-decision-making-understand-your-domain-544174f90c0a?source=collection_archive---------35-----------------------

有两种方法可以做出数据驱动的决策,分析方法和实验方法,在任何给定的时刻,只有一种方法适合你!

Cynefin &数据驱动的决策。作者写的。

动机

我们需要更多的预测,更多的预测分析,通用的前后分析框架,更多的人工智能。然而 65%的经理报告说这些努力没有带来可见的价值。我认为失败的分析项目的一个重要组成部分是公司未能理解何时使用分析数据驱动的决策,以及何时使用实验数据驱动的决策

我认为,像网飞、Airbnb 和 Zynga 这样的公司非常成功,因为他们理解这两种“数据驱动”决策的方法,并且擅长于实验方法,而通常情况下,公司只关注分析方面。让我们来定义它们:

  • 分析:我们分析过去的数据,然后得出最优决策,然后我们“最优”行动。这通常就是“数据驱动的决策”的含义。但这只是硬币的一面。
  • 实验:考虑来自未来的数据。这是怎么回事?数据是产品的一部分,反馈是决策的一部分。对于两种产品的&决策,我们只是试探,我们不会“用我们所有的筹码行动”。我们感知数据反馈,推断模式,行动,然后一遍又一遍地重复这个紧密的循环,直到有一天我们可能会以分析方法而告终。

像网飞、Airbnb 和 Zynga 这样的公司更经常选择实验性的方法…

据我所知,像网飞、Airbnb 和 Zynga 这样的公司比其他公司更经常选择实验性方法。通过这样做,他们有效地导航 cynefin 框架,并决定他们是在事物的“复杂”还是“复杂”的一边。

因此,让我们来看看如何才能在这两种方法上都表现出色!

  1. 让我们看看为什么以及什么时候分析方法起作用。
  2. 让我们看看为什么和什么时候实验方法会起作用,而分析方法会是灾难性的。
  3. 让我们回顾一下 cynefin 框架,它为这一点提供了一个很好的背景,并且可以看到,根据不同的情况,你必须能够使用这两种方法。
  4. 让我们最后来看看,为什么 OKRs 与这两种方法配合得如此好,但是您也必须小心地了解您在 OKRs 中的领域!

分析数据驱动的决策制定

让我们考虑一个建造桥梁的建筑师。他今年 40 岁,迄今为止在他的职业生涯中已经建造了 50 座桥梁。现在,他决定思考如何更好地建造桥梁,以使它们更具可持续性。

他收集他的历史(过去)数据,检查他建造的所有桥梁,检查天气数据,交通数据,并弄清楚一些事情。通过分析过程,他能够将恶化分解为以下主要驱动因素:

  • 暴雨
  • 繁重的交通负荷

根据他的观察,以及这些潜在原因在可预见的未来可能不会改变的知识,这位建筑师现在可以做出一个完全基于数据的决策,并再次建造许多具有特定据点的桥梁,无论是天气(在有大量暴雨的地区)还是针对他怀疑的交通负荷。

建筑师通过分析过去,推断出他未来的蜜罐。他知道 A 比 B 更了解 C,所以他可以利用这一点。

这是一个分析数据驱动的决策。它非常适合这个领域,在这个领域我们确实需要一个专业的架构师和大量的数据来正确地分析&建造更好的桥梁,但是在这个领域我们有“已知的未知”。我们有明确的限制,比如未来 50 年地球上的典型天气,这些限制内的一切都是物理的,因此是相对“稳定的&可预测的”。

分析数据驱动的决策示例

那么什么样的决定属于这一类呢?事实证明,虽然 Airbnb 这样的公司以实验思维著称,但他们确实有整个数据科学家轨道转向分析数据驱动的决策。

所有属于“优化”范畴的东西都在这个领域。运营工作流程、搜索引擎优化、任何符合 5 sigma 思维模式的东西。所有这些事情都有明确的限制,我们都知道,而且是可以预测的。

产品负责人的日常业务也适用于此。从我的经验来看:我的团队经历了相当多的压力,抱怨太多的“冲刺阶段的噪音”。我们决定对此采取分析方法,获得了一系列“噪音”基准,在我们公司,噪音显然在 10–20%左右,并从我们的 sprints 中获得了一系列数据。根据观察结果,我们能够将“冲刺阶段的噪音”降低到 5–10%以下,这个数字到目前为止都保持得很好。这是一种经典的分析方法。

实验数据驱动的决策制定

外汇交易员在一个完全不同的领域工作。想象一个日内交易者。他持有大量头寸,然后平仓,分析数据,分析盈亏。然后,他确定完美的交易,分析推断主要驱动因素,预测它们,然后进行下一次交易。

却看到他的位置转向南方。

对建筑师有什么不同?建筑师和交易者之间的关键区别是,建筑师实际上可以推断出因果关系,而交易者只能推断出模式,因此不得不不断探索,这与建筑师非常不同,建筑师一旦推断出因果关系,就可以以完全相同的方式为未来 20 年建造伟大的桥梁。

建筑师推断出因果关系:

暴雨= >造成大量潮湿和喷雾损坏= >损坏桥梁的钢部件= >损坏桥梁的整体状态。

交易者不能。他当然可以事后推断出因果关系,但他不能用它来预测,因为未来的事情不会是同样的关系,甚至第二天也不会。离晚上还很远。

交易者努力成为建筑师。他认为 A = > C,并且花了很多钱,最后却糊涂了。

那么交易者能做什么呢?毕竟,有相当多的交易者在市场上赚钱,甚至像 Bridgewater Associates 和 Renaissance Technologies 这样的大型对冲基金甚至自动/通过算法进行交易。交易者能做的是推断模式。他可以不断探索,调整和完善成为他的交易策略的模式。事实上,这在某种程度上是雷伊·达里奥描述 Bridgewater capital 创始故事的方式。

但为此,交易者不必采取行动,而是一直探索,并根据探索采取行动。他的过程更像这样:

  • 探针 T=0: 尝试用一个 50 点的跟踪止损点&和一串均线的某个交叉点作为切入点,用 1%的资金。
  • 道岔 T=1: 工作正常,200 点后停止。交易者可以推断出一些模式,他可以推断出 NFP 数据发布后对美元的强劲反弹往往会持续成对。
  • 再次探测 T=2: 使用策略&继续探测,推导出更多模式,调整他的策略以包含这些模式。
  • 探索,感觉,行动,探索,…
  • T=5: 现在连续 3 次被止损,损失 50 点,注意这里没有硬消息数据。因此,他看到了一个与新闻数据和他交易的反弹相关的模式,并将其纳入了策略。

这真的是,你在许多当前的科技公司看到的。

实验数据驱动的决策实例

实验数据驱动工作的关键是“将数据构建到产品中”或“将反馈构建到决策中”,并以假设驱动的心态开始解决问题。

一个很好的例子是网飞个性化引擎,或者说今天的大多数机器学习产品。一个附有 CD4ML 的机器学习产品正是这样做的:它进行实验,而不做任何假设。它推导出模式,然后采取行动,部署新的模型。在网飞,没有人试图猜测向谁推荐什么,相反,他们依靠大量的实验来找出答案。

另一个很好的例子是 Zynga 公司的大部分工作。他们“在每一个决策中建立数据”,他们甚至为他们的游戏发明了一种新的跟踪方式(ZTrack)来从他们的游戏中获得反馈。在一项实验中,他们开始让用户为他们的“Ville”游戏中的构建工具的进度付费。然后他们评估数据,意识到用户并没有为所有事情付费,但是他们会为最后一部分的进展付费(这是一个模式*)。基于这种认识,Zynga 为鼓励这种行为的构建工具进行了优化。

当然,原型和 SCRUM 或敏捷的本质都是基于这种工作的。没有将这一点结合到产品中会阻碍这种框架在您公司的成功。我工作中的一个很好的例子是,我缺少关于我们正在开发的产品的数据。我们开始在我们所有的版本中加入“追踪用户”的故事。在得到越来越多的反馈后,我们通过几个“探针”来看看如何改变方向,结果相当不错。产品的新方向现在完全不同了。

Cynefin &决策制定

Cynefin 是由斯诺登和库尔茨开发的一个框架,发表在 2003 年的一篇文章中。Cynefin 大致是一个确定你“周围环境”的框架。它可以用在各种各样的环境中,但是我们关心的是这里的决策部分。

图片来自埃德温·斯托普

cyne fin 框架的四个关键要点是(有关更多详细信息,请阅读 论文 !):

  • 通常用于决策的三个假设并不总是有效,只是有时候:并不是所有涉及 人类&市场的事情都是有序的;人类的理性选择经常是一种错觉,尽管它在大多数时候是一个很好的近似;不是每个“眨眼”都是“眨眼”,不是某人的每个信号实际上都是信号。
  • 有五个领域管理着我们的世界,而不仅仅是上面通常假设的有序的“简单的&复杂的”领域,这意味着秩序。
  • 在所有这些方面,你都应该采取非常不同的方式。
  • 有很多方法可以将事物从一个领域推进到另一个领域,比如探索、开发等等。

混乱和简单的领域都不属于数据驱动的决策领域,然而复杂和复杂是我们感兴趣的两个领域。

什么时候用什么?

你的业务的一部分将落入未知领域,一部分将落入复杂领域。斯诺登和库尔茨在他们 2003 年的论文中描述了一种“情境练习”,这种练习将大致产生一种类似地图的东西,通过它你可以确定哪些决策应该是由分析数据驱动的,哪些应该是由实验数据驱动的。

一个会话的流程为:

  • 专注于一个背景,也许是你的公司,公司的一部分,等等。让一群人进入一个房间。给他们一些准备材料让他们进入环境。
  • 对你的“意义构建”过程中重要的事情进行一次有条理的头脑风暴。
  • 画出一个 Cynefin 框架,只要标出四个角。
  • 让小组成员一起将几乎不需要讨论的物品放在这些角落里。
  • 人们把所有其他物品放在广场的某个地方。
  • 人们一起划分界限,清楚地将事物划分到适当的领域;这将留下一个大的“无序”域,这将在下面讨论。
  • 人们讨论所有的无序项目,并“拉近”边界,直到只有严重争议的项目留在无序域中。

页(page 的缩写)472、库尔茨&斯诺登"战略的新动力:在复杂多变的世界中做出明智的选择

一旦你到了这里,你就知道用实验方法处理哪些部分,用分析方法处理哪些部分。等等,你在做 OKRs?让我们看看这是如何完美地融入这个框架的。

搭配 OKRs!

那么,这如何与基于数据的控制机制协同工作呢?我认为它配合得很好。例如,OKRs 作为一个关注更大目标的框架,当正确应用时,实际上为分析和实验决策留下了恰到好处的空间。在制定 OKR 的过程中,你只需要知道你在哪个领域行动。这里有一个例子:

典型的销售目标可能是:

目标分析:将产品 X 的销售收入增加 20%

KR1:大公司部门的销售收入增长了 5%

KR2:中小型公司市场增长 30%

KR3:每个销售代表都联系了 100 名 Q1 客户,询问产品 X

KR4:客户调查报告对产品 X 的满意度得分为 7.5+分

如果你经营公司已经有几年了,了解市场,并且有一个不错的销售团队,从某个特定产品中获得更多收入的问题可能会陷入复杂的领域。你可能会推断,要销售这样一个产品,你通常有 X%的成交率,所以你可以把事情分解成每个细分市场要联系的客户数量,最后可能还有一个质量指标。

另一方面,如果你的产品是新的,你不了解市场,客户是新的,或者你对它做了一些重大的改变,那么这个问题很可能会落入的复杂领域。目标有所改变,加入了探测&传感,但真正重要的变化是你应该定期进行的 OKR 检查!

目标实验:将产品 X 的销售收入提高 20%

KR1:在 Q1 的第 1-2 周,每个销售代表都联系了 10 个客户,询问产品 X

KR2:客户调查报告在产品 X 测试版上的推荐分数为 7.5+。

KR3:每个联系人都接受了关于产品利弊的调查。

KR4:我们有 500 名新客户使用产品 X

KR5:每个销售代表都联系了 Q1 的 500 个客户

看出区别了吗?实验性意味着我们不知道应该关注哪个细分市场,所以我们只是简单地估计新的客户数量(KR4 代替 KR1,KR2)。但这意味着我们必须探索,以快速获得紧密的反馈,这就是为什么我们现在有 KR1 & KR5。对于新产品,我们需要的是推荐,而不仅仅是质量,所以我们更换了 KR2。KR3 专注于获得更多反馈。

但是,OKR 进程并没有达到这个目标!与“客观分析”不同,在“客观实验”中,我们不知道要去哪里,要关注哪些客户,我们甚至不知道我们是否需要对产品 x 进行进一步的开发。因此,在这里,我们将每两周检查一次,并改变 kr,希望在季度末达到类似“客观分析”的水平,即我们知道的目标群体、紧密的细分市场和可靠的数字。但是,这需要在整个季度中不断探索和感知。

分析与实验目标。以相同的成功状态结束,但是在这之间表现非常不同。

现在轮到你了。你知道你的哪些问题&决策适合复杂或复杂的领域吗?去把它们画出来吧!你的 okr 能弥补差额吗?你的数据驱动决策方法反映了你领域的现实吗?

资源

cy thon——Python 函数的加速工具

原文:https://towardsdatascience.com/cython-a-speed-up-tool-for-your-python-function-9bab64364bfd?source=collection_archive---------8-----------------------

当调整你的算法得到小的改进时,你可能想用 Cython 获得额外的速度,cyt hon 是 Python 的 C 扩展。

动机

如果你读了我的文章如何用 Python 从头开始创建你自己的矩阵模块,你可能想用你自己的算法创建你自己的矩阵类。这是一个好主意,因为你可以灵活地创建你喜欢的模块。但是在创建多维数组函数之前,您可能想了解 Numpy 和 Python Matrix 类之间的区别。

从空闲编码中检索

你为一个矩阵创建一个函数。让我们测试一下

让我们从一个例子开始,帮助你理解 Numpy 和你用 Python 创建的模块之间的区别。

我们期望使用 Numpy 的矩阵乘法将给出与第一个相同的结果。让我们看看它们是否在相同的矩阵维数上给出相同的结果。

创建多个不同维度的矩阵:

nump= []
mult=[]
for i in range(0,500,100): nump.append(calculate(npAB,(i,i))) mult.append(calculate(mulAB,(i,i)))

Python 实现和 Numpy 之间的性能。在这里找到实现

我们创建了维度为 100x100、200x200、…、500x500 的矩阵。我们可以看到,随着维度的增加,我们的 Python 函数的时间量呈指数增长,而 Numpy 可以在几秒钟内完成计算。如果 Numpy 也是一个 Python 库,它的性能怎么会比我们的 Python 实现好这么多呢?

numpy——不完全是 Python 库

Numpy 集成了 C/C++和 Fortran 代码,在处理多维数组而不是使用纯 Python 时提供了高性能。

如果你不知道 C 和 Python 的区别,C 是编译语言,Python 是解释语言。虽然变量是在 C 中声明的,但变量不是在 Python 中声明的。这使得 Python 更容易编写,但也带来了成本,Python 需要在每次执行代码时解释变量。因此,对于多维数组,Python 的运行速度比 C 慢得多。

如果有一种语言能让你在实现 C 性能的同时使用 Python 语法,那会怎么样?Cython 可以帮助你做到这一点。

Cython 简介

Cython 是一个针对 Python 和扩展的 cy thon(T21)的优化静态编译器。最棒的是,它使得编写 C 扩展的语法像 Python** 本身一样简单。Cython 结合了 Python 和 C 的优势,让您可以高效地与大型数据集进行交互。由于 Cython 将代码降到了机器级别,因此加快了 Python 代码的执行速度。你可以在这里找到 Cython 文档。**

Cython 的编译扩展包含三个文件:

  • 主文件
  • 要在.pyx文件中编译的函数
  • 一个setup.py包含制作扩展模块的指令

用 Cython 创建函数文件

创建一个名为mult_fast.pyx的文件。.pyx扩展名用于 Cython 文件

通过在可读的 Python synta x 中添加静态类型声明,我们可以很容易地将 Python 代码调成普通的 C 性能。这可以简单地通过cdef type name = value来完成。另外,不要忘记在函数的参数中声明变量。

def mulAB( double[:,:] A , double[:,:] B):
 cdef int Am  = A.shape[0]
 cdef int An  = A.shape[1]
 cdef int Bm  = B.shape[0]
 cdef int Bn  = B.shape[1] cdef int i = 0
 cdef int j = 0
 cdef int k = 0 cdef double temp = 0.0 cdef double[:,:] C = np.empty((Am,Bn), dtype=np.double)

在我们的代码中声明变量之后,我们开始下一行with nogil.现在你只需要在这里复制并粘贴你之前创建的函数:

with nogil:
  for i in range(Am):
   for j in range(Bn):
    temp=0.0
    for k in range(An):
     temp += A[i,k] * B[k,j] 
    C[i,j] = temp

 return np.array(C)

将所有东西放在一起:

mult_fast.pyx文件

建立

将该文件另存为setup.py

setup.py

您可以复制并粘贴这个setup.py文件作为您未来的 Cython 文件。您唯一需要更改的是extensionssetup ( mult_fast & [“mult_fast.pyx”])中的文件名。

在命令行上,键入:

python3 setup.py build_ext --inplace

最后一次接触 Main.py 文件

导入mult_fast.py并写入main02.py文件

准备好了吗?让我们发射

我们可以看到 Cython 的性能几乎和 Numpy 一样好。您可能不会选择在小数据集中使用 Cython,但是在处理大数据集时,使用 Cython 来快速完成我们的计算是值得的

结论

通过在我们的 Python 代码中进行一点点修改来利用 Cython,我们已经使我们的函数运行得更快了。我希望这篇文章能给你一些想法,让你以更有效的方式创建自己的模块。在这个 Github repo 中,您可以随意使用本文的代码。

我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以通过 LinkedInTwitter 与我联系。

如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:

** [## 使用 Python 最大化您的生产力

你创建了一个待办事项清单来提高效率,但最终却把时间浪费在了不重要的任务上。如果你能创造…

towardsdatascience.com](/maximize-your-productivity-with-python-6110004b45f7) [## 如何从头开始构建矩阵模块

如果您一直在为矩阵运算导入 Numpy,但不知道该模块是如何构建的,本文将展示…

towardsdatascience.com](/how-to-build-a-matrix-module-from-scratch-a4f35ec28b56) [## 用 Python 选择要投资的股票

您计划在未来 3 年投资几只股票,每只股票的每一美元都有不同的预期回报…

towardsdatascience.com](/choose-stocks-to-invest-with-python-584892e3ad22)**

D&D:什么时候为更大的修改器选择更差的辊型

原文:https://towardsdatascience.com/d-d-when-to-choose-a-worse-roll-type-for-a-larger-modifier-b5a4eb37409d?source=collection_archive---------39-----------------------

一种利用 R 和概率的算法

在听 Matt Mercer DM 龙与地下城关于关键角色的时候,我有时会听到他给玩家提供一个选择:

  1. 使用自然滚动(一个 d20 并取值)+修改器,或
  2. 使用一个不利辊(两个 d20,取较低的值)+不同的修改器。

例如,如果你是一个试图攀爬大堆岩石的僧侣,你可以掷出一个顺子运动检定(选项 1。)把自己拉起来。DM 也可能提供你可以滚动一个杂技检查(你有一个更高的杂技调整值,因为你有一个很高的敏捷),不利条件是沿着岩石跳跃(选择 2。).成功通过检查所需的总值对于任何一次掷骰都是相同的:例如,15(该值称为 DC)。

你该如何选择?嗯,选择应该反映你的性格和他们做什么。

但是,如果您想最大化检查成功的机会,那么使用下面的算法。请注意,您也可以想象您可以在 I)优势(两个 d20,取较高值)和自然掷骰之间进行选择,或者 ii)优势和劣势掷骰,因此算法也会考虑这一点。

  1. 估计支票的 DC。作为一名玩家,你可能不知道 DC,但你可以猜测打开沉船上的腐烂木箱可能比打开国王军械库中的坚硬箱子更容易。一般的指导是,简单任务的 DC 在 10 左右(即使不熟练的人也有很大的成功机会),中等在 15 左右(熟练的人有很大的成功机会),困难在 20 左右(熟练的人仍然需要一些运气才能成功),非常困难在 25 左右(熟练的人仍然需要很多运气才能成功)。
  2. 获得调整后的 DC : 从检查的 DC 中减去较低的修正值(选择更好的辊型)。以蒙克为例,如果你的杂技成绩为+6,体育成绩为+3,从估计的 DC 15 减去较低的修正值(+3),得到调整后的 DC 为 12。
  3. 获得不同掷骰类型之间的修改值的差异:对于我们的僧侣来说是(+6)-(+3) = 3。
  4. 在下面的图表中查找最佳选择:要找到要查找的地方,首先进入描述你正在做什么决定的面板。例如,和尚正在决定自然掷骰和劣势,这是第三个面板。其次,在 x 轴(12)上找到上一步中计算的调整后的 DC。第三,找出 y 轴上修改器值的差异(3)。找到他们相遇的颜色(在我们的和尚例子中是红点),并在右边的图例中查找以确定最佳选择。此处为蓝色,表示自然竞技检查比有劣势的杂技检查更有可能成功。

一个很好的经验法则是,如果任务非常困难,你应该愿意降低一个(优势对自然或自然对劣势)或两个(优势对劣势)等级,因为没有额外的修正加成你就没有成功的机会。如果修改量相差 5 或更大,你也应该愿意降一级。

如果你想知道:“这个邪恶的魔法是什么:这个图表是如何创建的?”,请继续阅读。

R +概率=巫师魔法。

让我们从基础开始。当你掷出 d20 时,1 到 20 中的任何一个数字都有 5%的概率被掷出:掷出 d20 是从 1 到 20 之间的离散均匀分布中抽取的。这种分布如下图所示。

然而,我们真正关心的是我们成功的机会:大于或等于 DC 的总机会(例如,垂直红线右侧的条形总面积代表 DC 为 15)。数学上,我们真正关心的是:

如果右边< 0,它应该正好是 0,如果大于 100%,它应该是 100%

这是一个简单的滚动公式。对于两个卷,我们可以利用卷是独立的这一点(所以某件事在两个卷上发生的概率是它在一个卷上发生的概率的平方)代入简单的公式。

现在,我们可以在代码中使用这些公式来确定应该为每个修改器差异和调整后的 DC 选择哪种类型的滚转。

上面创建的数据集如下所示。前两列显示神奇图表的 x 轴和 y 轴(调整后的 DC 和修改器差异)。下面显示的接下来的 4 列是通过某种类型的滚动检查的概率。下面显示的最后 3 列告诉您选择哪种类型的掷骰子来最大化成功的概率。

然后,我们可以透视这些数据,使其更容易绘制。

最后,我们可以将数据送入图表。

神奇!

D3.js —如何用最强大的可视化库制作漂亮的条形图

原文:https://towardsdatascience.com/d3-js-how-to-make-a-beautiful-bar-chart-with-the-most-powerful-visualization-library-9bea4e00349a?source=collection_archive---------9-----------------------

让我们做一个你不会羞于展示的形象。

选择一个首选的数据可视化库比看起来要困难得多。有这么多可供选择,尤其是如果你考虑到不同的语言。我大部分时间都在使用 Python 中的 PlotlyMatplotlib ,但是今天我们将尝试一些不同的东西——D3 . js,用——你已经猜到了——Javascript编写。

Kelly SikkemaUnsplash 上拍摄的照片

让我们解决几件事情。首先,我不是一个 JavaScript 专家,所以没有必要指出有些东西没有被优化。第二,这个库非常冗长,我花了将近 100 行代码来制作一个看起来不错的条形图。

这并不一定是一件坏事,因为你可以定制每一个可视化的地狱。在继续之前,让我们快速看一下最终结果:

作者图片

这种颜色变化发生在悬停时,所以不,这不是任何类型的故障。可视化相当简单,但需要大量的工作。在继续编写代码之前,让我们稍微讨论一下 D3

那么,D3.js 是什么?

D3 代表数据驱动文档。以下是来自官方文档页面的声明:

D3 帮助您使用 HTML、SVG 和 CSS 将数据变得生动。D3 对 web 标准的重视使您可以获得现代浏览器的全部功能,而无需将自己束缚于专有框架,将强大的可视化组件和数据驱动的 DOM 操作方法结合起来。

厉害!那么,用它有什么意义呢?

我特别喜欢的一个特性是 D3 输出的是 SVG 而不是 Matplotlib 输出的 png。我的目的不是用三个字母的缩写来迷惑你,所以我不会深究 SVG 和 PNG 的区别。

这是你现在应该做的唯一一件事(首先)——SVG 用于绘制矢量图形,这意味着没有像素,这进一步意味着我们在缩放时不会损失质量。但巴布亚新几内亚的情况并非如此。

以这张图片为例:

来源:维基共享资源

图像说明了一切。

现在让我们制作图表。请注意,这将是一个很大的工作量。

让我们做一个图表

首先是数据。我们将以 JSON 格式存储一些虚拟数据。我把我的名字命名为sales.json,它看起来像这样:

[
  {“Period”: “Q1–2020”, “Amount”: 1000000},
  {“Period”: “Q2–2020”, “Amount”: 875000},
  {“Period”: “Q3–2020”, “Amount”: 920000},
  {“Period”: “Q4–2020”, “Amount”: 400000}
]

数据到此为止。接下来,我们需要 HTML 文件。如果你不知道 HTML ,不要担心,因为它相当简单,我们不会在它上面花太多时间。

为了简单起见,我决定将 CSSJavaScript 嵌入到 HTML 文件中,但是如果您愿意,可以随意将它们分开。我的档案名为barchart.html:

<!DOCTYPE html>
<html lang=”en”>
<head>
  <meta charset=”UTF-8">
  <meta name=”viewport” content=”width=device-width, initial-scale=1.0">
  <title>D3.JS Bar Chart</title>
</head>
  <style>
    rect.bar-rect { fill: #189ad3; }
    rect.bar-rect:hover { 
      fill: #107dac;
      transition: all .2s;
    }
  </style><body>
  <div class=”canvas”></div>
  <script src=”https://d3js.org/d3.v6.js"></script> <script>
    // Everything else will go here
  </script></body>
</html>

这是一个入门模板。不要担心 CSS ,我只是用它来给正常状态和悬停状态的条着色。

我们现在可以从图表本身开始了!

一点准备

让我们开始真正的交易。我们的图表部分需要一些维度信息,比如宽度和高度。此外,我们不想让图表占据整个图表部分,所以我们需要在顶部、右侧、底部和左侧添加一些边距。

为此,我们将设置几个常数:

const width = 1000;
const height = 600;
const margin = {‘top’: 20, ‘right’: 20, ‘bottom’: 100, ‘left’: 100};
const graphWidth = width — margin.left — margin.right;
const graphHeight = height — margin.top — margin.bottom;

我认为这些都是不言自明的。如果不是,这里有一个快速澄清:

  • 整个图表区将占据 1000 x 600 像素
  • 图表本身将位于图表区内,并且四周都有边距
  • 底部和左侧的边距较大,因为我们将把轴放在那里

就这么简单。我们继续吧。

初始设置

好了,我们准备好开始有趣的部分了。我们需要以某种方式选择类别为canvasdiv,因为我们的图表将存储在那里。在其中,我们将创建一个svg(记住 D3 输出 SVG)并将它的高度和宽度设置为之前声明的值。

接下来,我们可以将图形元素插入到svg元素中,并将其尺寸设置为之前声明的尺寸。我们不希望它从svg的左上角开始,所以我们需要相应地translate它。

最后,我们可以为 X 和 Y 轴组声明常量(暂时不用担心这些)。

代码如下:

const svg = d3.select(‘.canvas’)
  .append(‘svg’)
  .attr(‘width’, width)
  .attr(‘height’, height);const graph = svg.append(‘g’)
  .attr(‘width’, graphWidth)
  .attr(‘height’, graphHeight)
  .attr(‘transform’, `translate(${margin.left}, ${margin.top})`);const gXAxis = graph.append(‘g’)
  .attr(‘transform’, `translate(0, ${graphHeight})`);const gYAxis **=** graph.append('g')

如果你现在打开 HTML 文件,你什么也看不到,但这并不意味着什么也没发生。只需弹出控制台,进入元素检查器。以下是您应该看到的内容:

厉害!接下来让我们完成这件事。

绘制图表

现在你期待已久的时刻到了。我们还有很多事情要做,所以让我们开始吧。

首先,我们需要以某种方式读取我们的 JSON 数据。然后,我们将分别在常量xy中声明比例,这些是为了确保单个的条不会意外溢出svg容器。

接下来,我们需要为数据集中的每个条目创建一个rect元素(矩形)。每个矩形都有它的高度和宽度,X 和 Y 值,我们还为它添加了一个自定义类,这样就可以更容易地使用 CSS 进行样式化。

在完成enter功能后,需要做几乎相同的事情,然后我们可以按照自己的意愿设置轴。

我们的图表在 Y 轴上只有 5 个刻度,同一轴上的值将被格式化为货币。是的,轴标签大小设置为 14。

要写的代码很多,所以要花时间去理解每个部分的作用:

d3.json(‘sales.json’).then(*data* => {
  const y = d3.scaleLinear()
    .domain([0, d3.max(data, *d* => d.Amount)])
    .range([graphHeight, 0]); const x = d3.scaleBand()
    .domain(data.map(*item* => item.Period))
    .range([0, 500])
    .paddingInner(0.2)
    .paddingOuter(0.2); const rects = graph.selectAll(‘rect’)
    .data(data); rects.attr(‘width’, x.bandwidth)
    .attr(‘class’, ‘bar-rect’)
    .attr(‘height’, *d* => graphHeight — y(d.Amount))
    .attr(‘x’, *d* => x(d.Period))
    .attr(‘y’, *d* => y(d.Amount)); rects.enter()
    .append(‘rect’)
    .attr(‘class’, ‘bar-rect’)
    .attr(‘width’, x.bandwidth)
    .attr(‘height’, *d* => graphHeight — y(d.Amount))
    .attr(‘x’, *d* => x(d.Period))
    .attr(‘y’, *d* => y(d.Amount)); const xAxis = d3.axisBottom(x);
  const yAxis = d3.axisLeft(y)
    .ticks(5)
    .tickFormat(*d* => `USD ${d / 1000}K`); gXAxis.call(xAxis);
  gYAxis.call(yAxis); gXAxis.selectAll(‘text’)
    .style(‘font-size’, 14);

  gYAxis.selectAll(‘text’)
    .style(‘font-size’, 14);
});

如果您现在刷新 HTML 页面,您会看到页面上显示了一个图表。不仅如此,我们还增加了不同的颜色。不错!

今天到此为止。让我们在下一部分总结一下。

在你走之前

D3.js 需要大量代码——这一点毋庸置疑。但这正是它的特别之处——完全定制一切的能力。我们在这里仅仅触及了表面,调整的选项是无穷无尽的。

如果你喜欢这篇文章,请告诉我,因为我打算做一个关于图书馆的完整系列。

感谢阅读。

加入我的私人邮件列表,获得更多有用的见解。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

** [## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)**

基于随机森林的日客流量预测

原文:https://towardsdatascience.com/daily-footfall-prediction-with-random-forest-8c9ff5630a4c?source=collection_archive---------45-----------------------

探索时间序列预测 ML 模型的一种简单方法。

图片来源于期限

介绍

在搜索时间序列预测时,你一定遇到过许多传统的方法,如萨里玛,STLM,先知等。但是你知道吗,有强大的机器学习技术也可以很好地处理一些数据操作。

而随机森林和其他基于决策树的模型没有考虑时间序列数据的基本概念,如趋势、季节性等。,有一些方法可以生成捕捉这些模式的预测变量。

有无数的资源解释如何使用随机森林进行多步时间序列预测。在这篇博客中,我将解释(用简单的步骤)我如何使用特征工程和单变量时间序列数据的直接预测方法来实现我的项目目标——预测未来 91 天(即未来 13 周)零售店的客流量。我决定采用随机森林集合模型,因为它很健壮,在大多数情况下表现良好。

对于模型评估,我使用了两个误差指标——均方根误差(RMSE)和平均绝对百分比误差(MAPE)。

虽然 NDA 禁止我分享明确的数字结果和图表,但我将解释我采取的步骤,以建立一个工作模型,该模型后来包括在最终的预测工具中。

模型组成

数据处理

任何机器学习建模的第一步都是留出一个维持集。时间序列数据上的训练测试分割不能随机执行,因此我使用我的数据集中最近的 91 个日期作为测试数据,用于基于前述误差度量的最终评估。

RF 通过丢弃数据点或通过某种形式的插补来处理缺失值。平均似乎是一种自然的方式。然而,使用整个时间序列的平均值没有逻辑意义。因此,对于缺失值的处理,我使用了该周的平均客流量。

特征工程

时间序列预测使用按时间顺序排列的历史数据来预测未来可能的结果。我使用特征工程从历史数据中创建预测变量,这将帮助我捕捉数据中的趋势和季节性。

如图表所示,在零售商店数据中观察到年度和周末季节性,即周末客流量较高,节假日期间出现年度高峰(如预期)。

年度客流量趋势(示例),来源于作者

每周客流量趋势(示例),来源于作者

对在数据中观察到的这些模式进行编码的一种简单方法是建立一个学习函数模型,该学习函数将一周中任何给定的一天的预期客流量预测为过去 N 周中在该天观察到的客流量的函数。例如,为了计算未来“星期五”的预期客流量,使用了过去 N 个星期五的数据。可以相应地选择超参数 N 的接近最优的值。我使用了基于网格搜索的方法,并选择了给出最佳 RMSE 的 N 值。用于此目的的验证数据是训练集中最近 91 天的数据。以下是我为此模型创建的预测变量:

N-滞后周 :在历史数据中找到要查看的最佳周数后,我创建了滞后变量(lag1,lag2…,lagN)来表示每周的滞后。这有效地捕捉到了工作日/周末对商店客流量的影响。 N 的值越大,创建的滞后变量的数量就越多,这直接抵消了训练数据点的数量。因此,我们可以使用多大的 N 是一个权衡。

  1. 滞后的差异 :我也创建了差异变量。这些是上面定义的连续周滞后之间的差异。它们捕捉特定一天的几周内的运动,并帮助稳定时间序列数据的平均值和方差。示例— diff0 = lag2 — lag1,…。
  2. 滞后平均 :我计算了滞后变量的移动平均窗口,并将其作为独立变量,以描述特定日期的平均客流量。
  3. 年度滞后 :为了捕捉数据中的季节性,即一年中的时间对预测日的预期客流量的影响,我计算了可用历史数据的平均每周客流量。例如,如果预测了属于一年中第I周的某一天的客流量,则年度滞后对应于过去所有年份中第I周观察到的平均客流量。我使用了周平均值,而不是过去几年的确切日期,因为一周中的某一天不会保持不变,我们观察到了零售业的周末效应。
  4. 黑色星期五和感恩节虚拟变量 :这是零售业中两个非常重要的节日,从历史数据中,人们很容易得出结论,这些日期每年都是明显的异常值。因此,它们需要分开处理,以免扭曲模型预测。我使用二进制指示变量来表示这种异常行为,以便允许被训练的模型推断出所述相关性。

直接预测

对于这个多步预测问题,我使用了“直接预测”技术,而不是递归预测。在递归预测中,创建单个模型,并将来自前一步骤的预测用作输入,而在直接预测中,为未来的每个范围创建单独的模型,即 h 单独训练的随机森林模型,用于预测未来的 h 范围。

虽然直接预测在计算上是昂贵的(并且随着预测时间范围的增加而更加耗时),但是它不必处理预测误差的聚集或者在长时间范围内收敛到无条件的平均值。然而,建立一个直接预测模型并不简单。对于未来的每一步,都需要相应地设计培训数据,如下例所示:

对于 horizon = 1,我使用实际客流量作为目标结果,并使用其他变量以如下方式训练第一个模型:

训练矩阵示例(地平线=1),来源于作者

对于 horizon = 2,我从 actual footfall 列中删除了最顶端一周的目标值,并根据以下内容训练模型,从而有效地增加了基于 horizon 的前瞻:

训练矩阵示例(地平线=2),来源于作者

变量的这种移动背后的原因在于,通过用对应于新的范围步长的观察值,即在这种情况下下周的目标值,替换目标变量(actual_footfall ),来自一个模型(预测范围 h+1)的特征被用于训练下一个模型。

为每个层位重复创建预测值和目标变量的过程。为了便于使用,我在 13 个预测变量矩阵(x_train)和 13 个目标向量(y_train)上为 13 个层位中的每一个创建了迭代表。

为了预测未来的每个层位,还需要设计相应的测试数据集。直接预测的 X_test 矩阵特征保持不变(平均年度滞后除外),这是 x_train 矩阵的最后 7 行。我使用这些最新观察到的日期和创建的特征来预测所有未来的步骤。为了便于使用,我在 x_test 矩阵上创建了一个 iterable,它对应于只改变年度滞后变量(如前所述,它是针对一年中的每一周进行预处理的)的每个时间范围。

现在,训练和测试数据以方便的数据结构的形式准备好了,我循环这些数据,并为每个地平线训练了一个随机森林集合。然后,这些模型被用于预测 7 天内目标时间段的商店客流量,并在测试集上进行评估。

结论

这个模型是经过严格的验证和调整而创建的,同时始终牢记客户目标。每一步都设计有意义的特征并提高模型效率,这是一种很好的学习体验。我们最终的工作原型是一个集成学习模型,包括 RF 和传统的时间序列分析技术。这种模型在现实世界中的应用非常广泛。它不仅可以扩展到预测健身房和餐馆等商业场所的客流量,还可以预测网站/网络应用程序的活动和流量。

参考

使用深度学习的你最喜欢的作者的每日励志语录

原文:https://towardsdatascience.com/daily-inspirational-quotes-from-your-favorite-author-using-deep-learning-73534c55ed96?source=collection_archive---------26-----------------------

自然语言处理

这个字幕是从机器人的输入中生成的。你永远不知道你会得到什么!

机器人的印刷设计。更多详情请访问:https://radiomurakami.live/

我一直是日本文学的狂热爱好者,而村上春树作为当代最著名的日本作家在我脑海中浮现。

村上的故事经常有非常生动和巧妙的场景描述,尽管日常生活平淡无奇。这不仅体现在他的小说中,也体现在他的短篇小说和沉思中,比如他的系列丛书村上广播(巧合的是,我们的机器人名字的由来)。

对我来说,这是一种非常强烈的认同感:在他选择用来描述他的角色和他们所处的环境的词语中,有一种人性的本质。

让我思考的是他的风格是否可以被效仿。由于他的许多作品还没有被翻译成英语,尤其是他的幽默短文,如果我们能有一个机器人像你最喜欢的作者一样写作,每天都从谁那里得到灵感,那不是很好吗?如果村上自己能够发现自己的“日语风格”,用有限的一组单词和语法结构表达自己的感情和思想,但以熟练的方式有效地将它们联系起来,那么机器能从这种模式中学习并创作简单而美丽的短语吗?

我和我的朋友保罗·图恩(Paul Tune)认为,尝试使用 GPT 2 号来制作一个村上机器人,以捕捉他的语气和风格,这将是一个有趣的项目,所有这些都在 Twitter 的角色限制之内。

在介绍了这个想法的概述之后,在本文的剩余部分,我将详细介绍村上电台机器人的开发过程,从原始数据收集,使用 GPT-2 的训练,迭代和展示机器人的一些深刻和相关的推文。

还有,是真的:字幕是我们 bot 生成的!

村上春树小传

西方世界的大多数读者对村上春树并不熟悉。

村上于 1949 年出生在京都,当时正值二战后的经济繁荣时期。他一直热爱音乐,尤其是爵士乐,于是和妻子在东京开了一家爵士酒吧。他经营酒吧 7 年了。

作为一个孩子,村上阅读了许多西方作品,从卡夫卡,狄更斯到库尔特·冯内古特。他的短篇小说之一《恋爱中的萨姆莎》是卡夫卡的《T2》中的主人公格雷戈·萨姆莎的故事的续集。

村上的写作生涯在 29 岁才开始,正如他在文章《我成为小说家的那一刻》中描述的那样。1978 年 4 月一个晴朗的下午,在养乐多燕子队和广岛鲤鱼队的棒球比赛中,他说

“球棒碰到球时令人满意的爆裂声响彻整个金谷体育馆。我周围响起了零星的掌声。在那一瞬间,没有任何理由,也没有任何理由,我突然想到:我想我可以写一本小说了。”

比赛结束后,他去新宿买了信纸和钢笔。半年后,他的第一部小说《听风吟》于 1979 年出版。

村上只是在 1988 年的作品《挪威的森林》中有了重大突破,这首歌是对约翰·列侬同名歌曲的引用。它很受年轻日本人的欢迎,并最终被翻译成英语,面向西方观众。

准备数据

可以说,任何数据科学项目中最乏味和最具挑战性的部分是数据的准备。在这种情况下,这没有什么不同。

我们几乎搜索了整个网络,寻找任何可用的英文采访,因为我们希望机器人能够直接接触村上来说话和写作。我们拥有的培训数据包括:

  • 村上所有的小说都有,比如 1Q84 和著名的挪威的森林
  • 发表在纽约客上的短篇小说
  • 村上的采访(这样机器人可以学习第一人称视角)
  • 来自 Goodreads报价目录的 Twitter 格式报价(这是为了确保模型将学习适应 Twitter 风格的写作格式,而不是长格式文本)

这里有一个警告。村上的所有作品都被不同的人从日语翻译成英语。因此,日语中句子的原始含义和微妙的选词可能无法完全捕捉到,这可以说是日语的著名之处。

幸运的是,村上春树的风格比他的同行更西化,这意味着用英语捕捉意思可能不像其他日本作家那样困难。

为训练收集的整个数据集超过 10 MB,并通过从采访和引用中删除任何非英语、非村上相关的文本来进一步手动清理。Goodreads 上的用户选择的引用中也有很多重复,我们必须审查并删除。我们还有一套单独的培训报价,我们将在下面解释。

训练模型

这里我们使用由 OpenAI 开发的 GPT-2 模型,这是一个因果(单向)转换器,在 800 万个网页和来自普通抓取的超过 15 亿个参数的数据集上进行预训练。GPT-2 经过训练,目标是预测句子中的下一个单词,这与我们手机上的自动完成功能非常相似,但方式更复杂。

因果方向意味着模型可以通过预测给定单词的下一个单词来按顺序生成文本!完美的机器人。

与自动完成功能不同,GPT-2 可以处理句子上下文,这允许它知道一个单词在句子中使用时的差异。以下列句子中的单词 fly 为例,

“这只苍蝇掉进了餐馆的汤里。”

飞机的发明让人们能够飞行

在这种情况下,虽然单词 fly 拼写相同,但一个表示昆虫(名词),而另一个表示动作(动词)。通过对整个句子和段落的训练,GPT-2 学习上下文,允许它区分像 fly 这样的词在不同上下文中的使用。这是一个同音异义词的例子,这个词听起来一样,但意思不相关。基于单词的模型(如 Word2Vec)无法捕捉这样的上下文。

我们使用具有 345M 参数的中等大小的 GPT-2 来训练村上广播机器人。下图显示了不同尺寸的 GPT-2 模型之间的区别:

来源:http://jalammar.github.io/illustrated-gpt2/

模型训练中最难的部分已经在预训练的模型中完成了,GPT-2 已经很好地掌握了英语。它将文本输入作为一个符号序列,并预测序列中的下一个输出符号,每个符号都有一个概率作为权重,这样以一种自我监督的方式学习。如果你有兴趣了解更多关于该模型如何工作的信息,杰伊·阿拉姆马有一篇图文并茂的文章,可视化了 GPT-2 的底层机制。

最初,训练包括编写一个被 Max Woolf 的作品破坏的脚本,但是随着从拥抱脸变形金刚包中逐渐改进的功能,我们使用这个脚本进行训练。该包还具有使从训练模型中采样变得容易的功能。

训练模型很简单:我们所要做的就是将数据集加载到模型中。用了大约 8 个纪元左右,模型就被训练好了,可以部署了!

重复

其中一个主要的挑战是将报价降低到 Twitter 大小的报价。这比预期的要困难得多。一旦我们的初始模型在小说上得到训练,它就会学习如何从小说中生成散文,而不是我们想要的简洁的推文。

这是一个新训练模型的输出示例:

阳光照射下来,空气中弥漫着花香。我可以看到海岸平缓的曲线,白色的沙滩。海浪的声音,树叶的沙沙声,远处蝉的叫声。”

虽然这在村上小说中是一个很好的描述性填充,但它却是一个糟糕的引语生成器!我们必须生成、审查和管理更多的样本,以获得我们想要的使用这个初始模型的机器人。

为了做得更好,我们挑选了一组具有类似 tweet 特性的报价作为我们的数据集。通过在该数据集上训练模型,该模型能够产生更高质量的输出。在此之前,该模型用于生成看起来像村上小说中的散文样本的摘录。现在它产生了一个引用,有人会从小说中挑选出来。我们还通过将模型产生的最佳结果放入模型的下一次训练中进行了试验,这似乎有所帮助,尽管我们意识到了自我强化的偏差。

即便如此,要找到多少有些深刻的引语还是很难,更难的是要找到一个让村上引以为豪的引语。目前,我们仍然以人为本进行治疗,但目前仍在试验更先进的方法。

结果

目前,村上广播机器人的推文是由经过训练的 GPT-2 模型生成的。我们使用种子文本作为手动输入,然后由我们对完整的句子进行半策划。像村上一样,它在推特上发布有趣的日常生活描述和其他思考。

以下是我们最喜欢的一些:

来源:https://Twitter . com/radio _ Murakami/status/1223388001100804099

来源:https://Twitter . com/radio _ Murakami/status/1234984420278325248

来源:https://Twitter . com/radio _ Murakami/status/1225924725437804544

来源:https://Twitter . com/radio _ Murakami/status/1228823823916683264

它有时也能讨论时事,尽管是以一种微妙的方式:

来源:https://Twitter . com/radio _ Murakami/status/1265077706053554178

来源:https://Twitter . com/radio _ Murakami/status/125565622932074503

如果你想每天收到一些村上的美食,你可以点击这里的机器人🤖!

未来的工作

还有一些我们想看的东西—

  • 我们肯定可以在选择最佳推文方面实现更多自动化。做到这一点的一个方法是使用另一个模型,如 BERT 作为鉴别器来改进 tweet 生成模型。我们目前正在对此进行试验。
  • 我们将更具启发性的报价与设计捆绑在一起,这意味着必须引入与报价相关的图像,并相应地调整它们的大小。这需要一定程度的努力,但是这里的一些自动化也是可能的!
  • 如果你想参与这个项目,或者对机器人引用的设计师质量的印刷品感兴趣,请在这里注册在不久的将来获得更多更新!

另外,写这篇文章的时候,我正在欣赏这个 播放列表 。希望你也会喜欢🎧

这首曲子是和保罗·图恩合著的。你可以在 Twitter 上关注他,或者查看他的个人网站

参考

[1]a .,Wu J .,Child R .,Luan D .,Amodei D .,Sutskever I .,“语言模型是无监督的多任务学习器”,2019。(链接)

[2] Alammar J .,“图解 GPT-2(可视化变压器语言模型)”,2019。(链接)

[3] Anderson A .,Maystre L .,Mehrota R .,Anderson I .,Lalmas M .,“算法对 Spotify 上消费多样性的影响”,WWW '20,2020 年 4 月 20–24 日,台湾台北,第 2155–2165 页。(链接)

[4] Devlin J .,Chang M. W .,Lee K .,Toutanova K .,“BERT:用于语言理解的深度双向转换器的预训练”,2018。(链接)

数据科学家的日常生活:在家工作版

原文:https://towardsdatascience.com/daily-life-as-a-data-scientist-work-from-home-edition-84a895e71879?source=collection_archive---------20-----------------------

作为一名数据科学家,我们在家主要做什么

Unsplash 上由米米·蒂安拍摄的照片

嗯,我知道许多数据爱好者想知道我们作为数据科学家到底是做什么的。尤其是在疫情的情况下;“你在家做了什么?”、“有生产力吗?”“数据科学家是远程工作,对吗?”。这是我看到的典型问题。

在这里,我将分享我自己作为一名数据科学家在家中工作的经历。

工作设备

首先,我们数据科学家总是需要数据访问才能正常工作。这意味着无论我们处于什么样的工作条件下;最重要的事情是确保我们可以访问数据(无论是在数据库中还是只是一个文件中)。

我对数据访问工作设备很认真,因为我们的工作总是围绕着数据。当然,有时工作是关于创建一个好的演示或仪表板,但即使这样,那种工作仍然需要数据支持。

根据我的经验,要访问数据库,我首先需要从我的公司获得可靠的设备,因为数据是一件敏感的事情。比如笔记本电脑、VPN 接入、互联网接入等。如果队伍很长,或者我们住在公司以外的另一个城市/国家(就像我一样),这可能需要很长时间。

工作日程

依赖公司;一些公司的工作时间很灵活;例如,只要你每天工作八小时,你就可以随时工作,但是有些公司有固定的工作时间,比如朝九晚五。

我的时间是固定的,这意味着我在工作时需要遵守我的工作时间表。我从周一到周五每天都工作。

虽然我有一个固定的时间表是件好事,但作为一名数据科学家,有时我们不能指望遵循这个时间表。根据我的经验,我们可以期望在更早的时间开始工作,但是大多数时候,我们需要晚一点完成,比如晚到你可以休假。虽然,我猜每个职业都有这种情况。

工作活动

我想人们更想了解数据科学家的活动,而不是设备或时间表。这是我的活动。

所以,我有一半的时间都被项目会议或其他会议占满了。是的,令人惊讶,对不对?数据科学家不从事编码工作,而是开会?

嗯,因为远程工作条件实际上使会议进行起来更容易。现在只需按一下按钮,我们就可以召开多个会议。尽管我们为什么需要这么多会议?因为这是工业情况下的正常活动。

很多数据科学家项目不是基于你自己的喜好,而是基于公司的需求。这意味着我们需要就公司想要什么、如何实施项目、预期结果、时间表以及项目进展情况进行大量讨论。

编码和数据部分在哪里?在那之后。我每周工作的另一半是编码、数据分析和建模,你努力学习它们,尽管它总是在我们同意项目和目标之后。

是的,分析数据和创建预测模型是我们的主要工作,但我们的责任不止于此。虽然数据科学家的耻辱是一直与模型和数据打交道,但事实是你只有一半的时间与它打交道(至少对我来说)。

对于一个数据科学的追求者,我总是建议你适当地了解业务;为什么?你的大部分活动,无论是在家还是在办公室,都会被业务人员围绕着,并期待你的项目如何帮助公司业务。

我在上面提到过,有时我的工作超出了计划。这是因为业务人员不了解分析和创建一个像样的预测模型实际需要多长时间。这就是为什么大多数时候最后期限比我们预期的要严格,我们需要努力做得更多。

任何其他工作活动与远程工作的其他职业相似;培训、研讨会和讨论。

工作效率

数据科学家在家工作时是否也能高效工作?我会说是和不是。

为什么是的?我们可以专注于我们的安全环境,没有任何办公室干扰来分析数据和进行建模。虽然,为什么不呢?因为我在上面提到过,数据科学家与其他业务人员一起工作,这包括你的同事。在远程工作时,很难协调和得到关于你需要的东西的解释。这可能导致等待时间的浪费。

这就是为什么生产率会根据当前的情况而波动。数据科学家毕竟还是人类工作者。

结论

数据科学家可以在任何地方远程工作,因为我们的工作描述主要包括分析数据和创建预测模型。虽然在家工作意味着比在办公室工作有更多的会议活动,但我们需要远程调整许多项目。

生产力会波动,因为有时我们真的很有生产力,但是我们需要等待调整。

如果你喜欢我的内容,并想获得更多关于数据或作为数据科学家的日常生活的深入知识,请考虑在这里订阅我的时事通讯。

如果您没有订阅为中等会员,请考虑通过我的推荐订阅。

与星共舞

原文:https://towardsdatascience.com/dancing-with-the-stars-aded5e9b3f3c?source=collection_archive---------46-----------------------

从简单的计算规则中探索涌现行为

照片由 Unsplash 上的 Allef Vinicius 拍摄

对人类来说,星星是生活中最可靠的事实之一。我们的主星,太阳,在我们出生的时候就在那里,在我们死去的时候也会在那里。对于我们在夜空中可以观察到的几乎所有其他恒星来说,情况也是如此。是的,偶尔一颗恒星可能会“噗”的一声变成超新星,但总的来说,在我们的一生中,天空中的恒星不会有太大的变化。你可以用它们来设置你的时钟。

从更长的时间尺度来看,恒星会四处走动。每颗恒星都不断地被它周围的所有恒星轻微地推搡着。距离较近的恒星有很大的影响,但是距离较远的大量恒星也有影响。甚至神秘的“暗物质”也会影响恒星之间的相对运动。

几年前,Wolfram|Alpha 的天体物理学家兼研究程序员 Jeffrey Bryant 写了一篇博文,讲述了一个非常有趣的星系碰撞模拟,每个星系包含数十亿颗恒星。这篇文章包括完整的 Wolfram 语言代码,以重现这里显示的完整模拟:

碰撞星系是一种涌现行为的有趣例子,其中微小的个体物体对典型的微小外部影响做出反应。这种行为的另一个很好的例子是一群鸟,其中每只鸟单独对周围鸟的飞行方向的变化做出反应。

照片由Unsplash

用 Wolfram 语言编写非常简单的代码就可以模拟这些突发行为。我的 Wolfram 语言示例大致基于 Wolfram 社区西蒙·伍兹的帖子。它考虑了平面上的许多物体,姑且称之为粒子,它们相互作用。每个粒子都有一个“朋友”,无论它在平面上的什么地方,它总是想朝这个朋友的方向运动。每个粒子也有一个“敌人”,它总是想远离这个敌人。然后,每隔一段时间,一个粒子可能会随机得到一个新朋友和一个新敌人。这有助于保持突发行为的趣味性和动态性。最后,每个粒子都想慢慢漂移到平面中心。这个规则使粒子慢慢远离中心。

这有很多规则,但是一旦分解,用 Wolfram 语言编程就很简单。让我们从挑选粒子数开始,从 1000 开始:

n = 1000

接下来,我们在坐标范围为(-1,1) x ( -1,1)的平面上生成 n 个随机粒子:

x = RandomReal[{-1, 1}, {n, 2}]

每个粒子都有一个朋友和一个敌人。我们用下面一行代码一次性生成它们。列表 p 包含每个粒子的朋友列表,列表 q 包含敌人列表:

{p, q} = RandomInteger[{1, n}, {2, n}]

比如 p 可能以 {621,47,874,…} 开头表示 x 中的第一个粒子与 x 中的第 621 个粒子是好友等等。

吸引力或排斥力的大小取决于粒子和它的朋友或敌人之间的距离。以下函数 f 使用非常简洁的 Wolfram 语言符号一次性计算所有粒子的力:

f = Function[{x, i}, (#/(.01 + Sqrt[#.#])) & /@ (x[[i]] - x)]

为了更新一个时间步长的每个粒子,我们使用下面的代码。第一项 0.995 x 代表粒子向平面中心的漂移。第二项代表吸引力,参数 0.02 指定整体吸引力有多强。最后一项代表排斥力。它的作用与吸引力相同,但方向相反

x = 0.995 x + 0.02 f[x, p] - 0.01 f[x, q]

最后,每个时间步都运行下面的条件语句。大约有 10%的时间是正确的,当这种情况发生时,一个单独的粒子被指派一个新的朋友和敌人:

If[ RandomReal[] < 0.5,
 With[{r1 = RandomInteger[{1, n}]}, 
  p[[r1]] = RandomInteger[{1, n}];
  q[[r1]] = RandomInteger[{1, n}]
]]

为了将粒子可视化,我们使用一个基本的图形对象将粒子显示为白点。动态表达式检测其范围内是否有任何变量发生变化,如果有,它会重新评估。它本质上是一个智能的 while-true 循环,可以放在呈现的排版代码中的任何位置:

Graphics[{ White, PointSize[0.007],
 Dynamic[
  If[RandomReal[] < 0.1, 
   With[{r1 = RandomInteger[{1, n}]}, p[[r1]] = r; q[[r1]] = r]
  ];
  Point[x = 0.995 x + 0.02 f[x, p] - 0.01 f[x, q]]
 ]}, 
 PlotRange -> {{-1, 1}, {-1, 1}}, 
 Background -> Black,
 ImageSize -> 600
]

最终结果可以在 Wolfram 笔记本上直接看到(它会一直播放,直到你选择停止它),或者在下面我为 YouTube 制作的一分钟视频中看到:

很少的代码就能产生如此复杂的行为,这总是令人惊讶的。有很多有趣的方法来创造变化,我希望在未来的帖子中探索。例如,每个粒子可以有多个朋友和敌人,而不是用简单的白点来渲染,人们可以使用任意图形(圆形,多边形)来使事情看起来更奇怪。

丹尼尔·丹尼特的四种能力

原文:https://towardsdatascience.com/daniel-c-dennetts-four-competences-779648bdbabc?source=collection_archive---------31-----------------------

理解计算控制算法的一个有用的想法

2018 年,在安纳普尔纳赛道徒步旅行时,我读了丹尼尔·c·丹尼特(Daniel C. Dennett)的 从细菌到巴赫,再回到 我后来仔细研究了它,我期待着重读它。

在书中,丹尼特介绍了能力的四个等级。他们描述了四种逐渐胜任的智能,这四种智能通过连续的试错学习来学习。

这四种能力并不是这本书的中心思想。我在这里介绍它们,因为我发现它们对我理解计算控制算法非常有价值。

它们对教学也很有用。他们通过渐近性能和采样效率来组织计算控制算法。这四种能力还允许对细胞、动物或人类等与不太熟悉的计算算法相关的例子进行分类。

但是我们所说的能力到底指的是什么呢?

什么是能力?

能力就是表现良好的能力。它是一个代理与它的环境交互以实现目标的能力。

能力可以和理解力相对比,理解力是理解的能力。两者一起形成了一个有用的智能分解。

能力允许代理人进行控制——与系统交互并产生结果。这种能力的来源是通过试错从经验中学习。我们称之为进化学习。

进化学习

也许黑客应该表现得更像画家,定期从头开始

保罗·格拉厄姆

进化学习是试错学习。这是使用生成、测试、选择循环的迭代改进:

  • 使用前面步骤中的信息生成群体
  • 通过与环境的相互作用来测试人口
  • 为下一步选择当前世代的群体成员

它是我们宇宙中的驱动力,不依赖于底物。它发生在生物进化、商业、训练神经网络和个人发展中。

从进化学习中可以学到很多东西:

  • 低层次的失败推动更高层次的改进
  • 迭代改进的有效性
  • 二元(代理人和环境)观点的需要使它起作用,与非二元性的真理不一致

这些都是以后要探索的课程。目前,我们关注的是能力的四个等级。

四种能力

四种能力是进化学习的连续应用。每个代理都拥有能力较差的代理所拥有的所有能力。

第一等级是达尔文式的。该代理具有预先设计和固定的能力。它在其生命周期内不会改善。通过选择,通常基于单个数字,在代理的整个生命周期中聚合,改进在全局范围内发生。

生物学的例子包括细菌和病毒。计算实例包括 CEM ,进化算法如 CMA-ES 或遗传算法。

第二个是 Skinnerian 。这种代理通过学习对强化做出反应来改善其行为。

生物学的例子包括神经元和狗。计算实例包括无模型强化学习,如 DQN彩虹

第三个是波普尔主义。这个代理学习其环境的模型。改进是通过离线测试计划及其环境模型来实现的。

生物学的例子包括乌鸦和灵长类动物。计算示例基于模型的强化学习,如 AlphaZero世界模型和经典最优控制。

最后一级是公历。这个代理构建思维工具,如算术、约束优化、民主和计算机。改善是通过系统的探索和对精神搜索的高阶控制来实现的。

我们唯一拥有格里高利智能的生物学例子是人类。我不知道有哪种计算方法可以建立自己的思考工具。现在我们已经介绍了我们的四个代理商,我们可以对它们进行比较。

比较四种能力

有几个指标可以用来比较我们的智能代理。

渐近绩效衡量代理在给定的无限机会下如何表现,以获取经验。这是一个代理人在极限下能有多好,并随着我们的代理人获得更复杂的能力而提高。

样本效率衡量代理需要多少经验才能达到一定的绩效水平。随着我们的代理变得越来越复杂,这种情况也会得到改善。采样效率的重要性取决于计算成本。如果计算很便宜,你就不太关心采样效率。

四个代理中的每一个都与相同的环境交互。与代理交互允许代理通过经验生成数据。代理如何处理这些数据决定了它需要多少数据。代理从每次交互中挤出的越多,需要的数据就越少。

例如,达尔文主义者通过由单个数字决定的选择来改进。对于生物进化来说,这是动物交配的次数。对于计算进化来说,这是一个适应度,比如每集平均奖励。这些都是微弱的学习信号。这解释了具有达尔文能力的代理人的低样本效率。

与 Skinnerian 试剂相比,它可以通过选择和强化来提高。能够对强化作出反应使得终生学习成为可能。它有能力从环境的时间结构中学习。Skinnerian 代理使用这些数据来学习预测未来回报的函数。

波普尔代理可以在其生命周期内通过学习其世界的模型来进一步改进。从这些模型生成的数据可用于规划,或生成环境的低维表示。

这些维度(从哪些数据中学到了什么)有助于理解智能代理的不同方法。

摘要

在本文中,我们快速浏览了丹尼尔·c·丹尼特的四个能力等级。他们描述了四种逐渐胜任的智能,这四种智能通过连续的试错学习来学习。

这种思想将通过试错法学习的代理组织起来,并应用于生物学和计算方法。

它允许理解学习算法的渐近性能和样本效率。它强调了智能代理的两个有用的方面——他们使用什么数据以及他们从这些数据中学到什么。

在我们最能干的特工中,人类是唯一的生物样本。我们没有计算的例子。

感谢阅读!

原载于 2020 年 2 月 26 日【https://adgefficiency.com】

数据的阴暗面:隐私

原文:https://towardsdatascience.com/dark-side-of-data-privacy-ba2850de512?source=collection_archive---------35-----------------------

我们都很欣赏 AI机器学习的价值,但是 w 关于隐私方面呢?

一张盖着摄像头的照片

你认识最近在日常生活中使用谷歌眼镜的人吗?也许几年后这个问题会演变成一个新的问题问谁还记得它。关于谷歌眼镜的故事的普遍观点承认它是一个商业失败,如果我们不陷入忽视这一失败的隐私方面的错误,这是一个合理的推断。

与 10 年前相比,如今对个人数据隐私的关注程度更高,并且还在继续增加。但它是否达到了可以瓦解巨型公司的大量产品的水平,尽管它们的功能很有吸引力?

我非常怀疑社会中的隐私观念是否达到了令人满意的程度。技术发展很快,其后续影响在多年后才显现出来。我们都很欣赏 AI机器学习的价值,但是 w 关于所有这些数据的隐私方面呢?我称之为数据的阴暗面尤其是那些工作基于数据的人,在这件事上负有重大责任。

现代世界中的隐私

1890 年,沃伦·布兰代斯 T20 首次描述了隐私。在他们的文章中,隐私被定义为“不受打扰的权利”。在那个时代,世界是一个不同的地方,因此他们引用摄影设备和报纸,而主张这个定义。它今天仍然有效,但是它肯定不足以表达当代隐私概念的所有方面。

在现代社会,定义隐私要复杂得多。事实上,它比以往更加模糊。除了技术带来的好处之外,我们还面临着近期发展带来的副作用。正如在福柯纪律与惩罚:监狱的诞生 中所解释的那样,处于监视之下会使人们无法创造新的想法,并使人们质疑自己,在社会中发起自我审查运动,这有助于创造一个适当的环境,让暴虐的政权轻松地统治社会。

圆形监狱(杰里米·边沁设计的监狱,他启发了福柯)

那么,为了保护自己,我们应该停止使用技术吗?在这样一个技术成瘾的世界里做到这一点绝对不是那么简单的。让我们考虑一些例子,就侵犯隐私而言,您会如何应对以下设备:

  • 你家周围的闭路电视摄像头。-如果它阻止了恐怖袭击呢?
  • 移动设备中的位置跟踪器。如果它在自然灾害中救了你的命呢?
  • 手表中的心率测量器。如果它在心脏病发作前警告你怎么办?
  • 电视机上的一个音频收听器-如果它推荐了你正在搜索的产品呢?

是的,我知道最后一个看起来不是那么不可或缺,但每件事都有利弊,每个人都有不同的重要程度,要对自己的数据做出有意识的决定,必须有一定程度的意识。除了技术在我们日常生活中的众多优势,问题仍然存在:谁将保护我们的敏感个人数据免受自私的科技公司、令人不快的政府或功利主义黑客的侵害?

保护你的隐私是很难的,因为如果你失足一次,它将永远存在。

—艾伦·施瓦茨

很明显,最近的一些案例如剑桥分析有助于让社会关注数据的伦理方面。马特图尔克在他的 2019 数据&艾景观 报告中解释道:

或许比以往任何时候都更重要的是,隐私问题在 2019 年跃升至公共辩论的最前沿,现在处于前沿、左侧和中心位置。我们与隐私的关系仍然很复杂,充满了混杂的信号。人们说他们关心 的隐私,但是继续购买各种具有不确定隐私保护的连接设备。他们说他们对脸书的隐私泄露感到愤怒,但脸书继续增加用户并超出预期(2018 年第四季度和 2019 年 Q1)。

你的客户是谁?

上面这个奇特的标题是罗马诗人尤维纳利斯的,可以翻译成“谁看着守望者?”。我用这句话来强调政府和公共机构等隐私机构之间的相互依赖性。

在这一点上,各种数据相关的行动都以某种方式依赖于法律法规,如 GDPR ,可以肯定的是,这些立法是隐私保护工作的一大进步,但它们不是确切的解决方案。

另一方面,像Privacy International这样的基金会在组织人员和建立共同的数据伦理方面发挥着关键作用。此外,由于数据相关领域越来越受欢迎,一些其他机构正在发布自己的道德准则,以明确这种卡夫卡式的环境。

然而,这些致力于隐私权的机构和群众运动本身是不够的。在我看来,这些努力需要来自数据行业中间的人的实际和道义上的支持。所有类型的数据从业者都对他们在这个领域的工作负责。

Dj 帕蒂尔用 5 C 解释了 数据科学的伦理规则 :

  • 同意
  • 清楚
  • 一致性
  • 控制和透明度
  • 后果和危害

无论你涉及多少数据,关注这样的数据科学伦理是建立数据隐私和使你的工作尊重普遍人权的关键。

可信人工智能伦理准则欧盟报告强调人权的价值及其与人工智能的关系:

必须确保平等尊重所有人的道德价值和尊严。这超出了不歧视的范围,不歧视允许根据客观理由区分不同的情况。

此外,在同一份报告中还提到了人工智能的隐私方面:

人工智能系统必须在系统的整个生命周期中保证隐私和数据保护。…人类行为的数字记录可能让人工智能系统不仅可以推断个人的偏好,还可以推断他们的性取向、年龄、性别、宗教或政治观点。为了让个人信任数据收集过程,必须确保收集到的关于他们的数据不会被用于非法或不公平地歧视他们。

人类最古老最强烈的情感

在这篇文章中,我不打算提及侵犯隐私的危害,相反,我旨在提及一些有意识的人的道德责任。我知道很难确定哪种行为是道德的,因为它会因情况而异。无论如何,道德准则为我们提供了路线图,我们有责任让我们的工作尊重人权和数据隐私。我认为,这种责任优先于金钱,因此,如果有人要求你打破你的原则,你必须有能力拒绝。

人类最古老、最强烈的情感是恐惧,而最古老、最强烈的恐惧是对未知的恐惧

——惠普·洛夫克拉夫特

结论

我们都在使用强大的机器学习工具,访问大量的数据源,并轻松地充分利用这些技术机会。然而,应该记住,所有这些权力都伴随着责任,数据伦理是这个领域不可分割的一部分。这样我们就能最大限度地减少未知,并与最强烈的恐惧作斗争。

这一领域的一些其他来源:

DataViz 系列:仪表板 KPI 基本模板

原文:https://towardsdatascience.com/dashboard-kpi-essential-template-hands-on-tableau-b02703bceca6?source=collection_archive---------4-----------------------

Unsplash 上由 Austin Distel 拍摄的照片

实践教程

仪表板中 KPI 模板可视化的剖析。带 Tableau 的动手演示,从零开始。

关键绩效指标(KPI)是任何业务领域中任何仪表板的基石。制造这些砖块的一个聪明的方法是开发一个 KPI 模板,这是一组混合数据来解释业务的表达式和参数。好的,但是我们如何制作 KPI 模板呢?

介绍

在本文中,我将解释并展示如何在专业仪表板中开发干净的 KPI 可视化的底层对象。这个想法是建立一个可以应用于任何业务领域的 KPI 模板。

我将通过 Tableau 来完成,但它可以很容易地适应其他 dashboarding 工具,如 Qlik 或 Power BI。如果您希望以演示的方式重复这些步骤,您可能希望创建一个 Tableau 公共登录(免费),并下载我使用的数据集(链接)。

如果你读了我的另一篇文章“仪表板设计的灵感”(下面的链接),我将在这里解释如何准确地开发驾驶舱中显示的任何 KPI。

[## 仪表板设计的灵感来源

如何将业务指标和故事塑造成仪表板

medium.com](https://medium.com/analytics-vidhya/inspiring-ideas-for-dashboards-design-172b31ca9620)

关于 Tableau 的详细信息,我已经在下面链接的另一篇文章的“报告或仪表板:Tableau Public ”一节中谈到了它的公共版本

[## 在家创建“真实世界”的数据科学环境

我在家里的“真实世界”数据科学环境:数据库,ETL,数据分析,仪表板,9 个步骤。

medium.com](https://medium.com/analytics-vidhya/create-a-real-world-data-science-environment-at-home-7a4255ff6fa5)

KPI 要求

我们的目标是通过构建 KPI 的 3 个核心元素:KPI 值、趋势和绩效,来构建所有的对象,以制作一个标准的 KPI 模板。

例如,下面的可视化使用了我们将要开发的模板的 8 倍。

来自 Tableau Public 的截图

我们的 KPI 模板的输入是一个数据集,其中包含一个随时间变化的业务度量(例如,ID_DATE 上的月销售额)。

作者截图

我们希望 KPI 模板可视化能够动态响应时间和性能范围的选择器。

作者截图

KPI 模板的输出需要提供 3 个信息

a)所选期间内业务指标的 KPI 值

b) KPI 绩效定义为 KPI 值与基准

c) KPI 在一年滑动期内的趋势

作者截图

动手操作:Tableau 的 KPI 开发

在接下来的 6 个段落中,我将带您一步步地了解 KPI 模板可视化的实际开发过程。

1。创建数据源

你可以从这个链接下载源数据集。

作者截图

创建一个 Tableau 工作簿,并将“数据源”选项卡配置为连接到一个文本文件(该文件在示例中是一个. csv 文件)。

完成后,您应该会看到导入的数据:每一行都给出了一段时间内业务度量的值(例如,它可以是利润、利润,..,如果您处理销售领域、净推销商分数、参与度,..,在数字营销等方面。).

“值”是业务度量,“Id 日期”是它所引用的日期。

作者截图

数据类型是自动选择的,但是您总是需要检查它。

在这种情况下,它们是正确的:#表示数字列,Date 表示“Id Date”。您将始终需要检查这一点,以防手动更改数据类型。

我们现在需要创建所有的 Tableau 对象,它们将成为我们可视化的基础。这一切都是通过底部的选项卡创建一个 Tableau Sheet 开始的。

Tableau 表是 Tableau 中最详细的可视化级别。在这里您可以定义包含数据表达式(计算、转换、过滤等)的对象。)和可视化(图表、视图、地图等)。).通常,仪表板由几个 Tableau 表组成。

在左侧,您可以看到源文件的 3 列。Tableau 已经为它们添加了一些智能:它将“Id 日期”和“Id 行”归类为维度对象(蓝色),将“值”归类为度量(绿色)。

作者截图

2.构建参数和选择器

参数可用于向尺寸或度量对象传播值。在 Tableau 中(其他工具不同),使用参数的方法之一是通过选择器设置其值。另一种方法是存储一个常量值。对于我们的 KPI 模板,我们决定显示 3 个选择器:当前月份、年份和绩效范围。

  • C 当前月份:将其定义为整数列表,取值范围为 1 到 12。

作者截图

  • 当前年份:定义为整数列表,有你需要的年份(2018,2019,2020)。

作者截图

  • 性能范围:定义为一个字符串列表,包含您想要允许的性能。在此模板中,我们提供了显示 3 个范围,但您可能希望添加更多范围:

当前月份与目标值的比较

当月与上月相比

当前月份与去年当前月份的对比

作者截图

现在我们已经创建了 3 个参数,接下来我们可以构建实际的用户选择器:右键单击每个参数并选择“Show Parameter ”,这样它们就会出现在您的工作表中,并且可以被更改。

作者截图

要像我一样显示选择器,您需要右键单击参数并选择紧凑列表视图模式。

作者截图

最后,我们需要创建一个新参数来定义我们希望用于性能范围“当前月份与目标值”的目标值。我们可以将其定义为 10000(这可能代表期望的月销售利润、新客户数量或任何其他目标基准)。

作者截图

3.创建公用设施维度

基于上面定义的选择器“当前年份”和“当前月份”,我们需要通过构建一些维度来解释它们所代表的实际日期,我称之为效用维度。即使用户只选择一对“当前年份”和“当前月份”,这些维度也允许计算几个度量值,每个度量值在不同的时间段进行计算。

创建以下 4 个对象维度

作者截图

用下面的表达式

**Date Current Month - Current Year 
=** MAKEDATE([Current Year],[Current Month],1)**Date Current Month - Previous Year** 
= MAKEDATE([Current Year]-1,[Current Month],1)**Date Next Month** 
= DATEADD('month',1,[Date Current Month - Current Year])**Date Previous Month**
= DATEADD('month',-1,[Date Current Month - Current Year])

解释:函数 MAKEDATE 根据提供的年、月和日建立一个日期。在我们的模板中,年和月是我们的参数,日被设置为 1。

函数 DATEADD 递增(或递减)所提供的日期。在这里,我们通过在当前月份上加 1 来计算下个月的日期。

然后我们创建一些维度,以文本格式很好地显示日期,比如

作者截图

作者截图

为此,我们创建了以下两个维度

作者截图

由下面的表达式定义。

**Current Period Lable**
= LEFT(DATENAME(“month”, [Date Current Month — Current Year]),3)
 + “-” + RIGHT(DATENAME(“year”,[Date Current Month — Current Year]),2)**Performance Reference Lable**
= CASE [Performance Scope]
WHEN   'CurrentMonth_vs_PreviousMonth' THEN LEFT(DATENAME("month", [Date Previous Month]),3)
        + "-" + RIGHT(DATENAME("year",[Date Previous Month]),2)
WHEN 'CurrentMonth_vs_PreviousYear' THEN LEFT(DATENAME("month", [Date Current Month - Previous Year]),3)
        + "-" + RIGHT(DATENAME("year",[Date Current Month - Previous Year]),2)
WHEN 'CurrentMonth_vs_Target' THEN "Target" 
END

正如您所注意到的,它们基于我们之前构建的对象,而这些对象又是基于参数构建的。

4。在时间范围内建立 KPI 指标

这里是最有趣的部分:实际的 KPI 计算。对于任何 KPI,我们都需要两个成分:一个业务 度量,以及一个业务规则来将度量转化为 KPI。例如,来自电信公司:电话呼叫的持续时间将是业务度量,KPI“每日平均持续时间”的业务规则将是:每天电话呼叫的平均持续时间。

在我们的 KPI 模板中,我们的业务度量对应于 Tableau 对象“Value”,它表示名为 Value 的源列。我选择按月计算总值作为业务规则。

可以通过改变聚合函数来改变规则。例如,每笔交易的平均金额如下:

让我们构建相应的 Tableau 对象:

作者截图

为什么我们需要 3 个度量?因为我们考虑 3 个不同的时期:当月,上月,上年的当月。稍后当我们计算 KPI 绩效时,您会更好地理解原因。

他们的表达如下:

**KPI (Current Month)**
=SUM(IF (YEAR([Id Date]) = [Current Year] 
         AND MONTH([Id Date]) = [Current Month]) 
    THEN [Value]
    ELSE NULL
    END)**KPI (Previous Month)**
=SUM(IF (YEAR([Id Date]) = YEAR([Date Previous Month])
         AND MONTH([Id Date])= MONTH([Date Previous Month]) )
    THEN [Value]
    ELSE NULL
    END)**KPI (Current Month Previous Year)** =SUM(IF (YEAR([Id Date]) = [Current Year] - 1
         AND MONTH([Id Date]) = [Current Month]) 
    THEN [Value]
    ELSE NULL
    END)

让我们解释一下第一个表达式 KPI(当月),其他的遵循相同的概念。我们需要保留属于当前月份的源“,并在其他地方强制为空。

作者截图

这个过滤是由蓝色突出显示的表达式部分完成的,它逐行测试我们的数据源的日期(“Id Date”)是否属于“当前年份”和“当前月份”期间。

作者截图

例如,如果日期选择器设置为 2018 年 4 月,KPI 将只考虑绿色的源数据:

作者截图

下面突出显示的表达式的剩余部分聚合了 KPI 定义范围内的所有值(即 Sum)。

作者截图

作者截图

最后,我们可以构建另一个度量,读取之前构建的参数“性能范围”。创建对象

带着表情:

**KPI (Performance Scope)**
=CASE [Performance Scope]
WHEN 'CurrentMonth_vs_PreviousMonth' THEN  [KPI (Current Month)]
WHEN 'CurrentMonth_vs_PreviousYear' THEN  [KPI (Current Month)]
WHEN 'CurrentMonth_vs_Target' THEN  [KPI (Current Month)]
END

您可以看到,根据性能范围选择器,该对象充当一个开关,选择一个 KPI(t)。在我们的模板中,我们决定只查看当前月份,因此在任何情况下我们的开关都是“KPI(当前月份)”,但是您可能希望将其扩展到其他范围(例如,当前年度、季度、周等)。).

作者截图

为了可视化我们的 KPI 的趋势,我们希望显示它在滑动年份的值。为此,我们可以构建以下对象和表达式,它利用了我们之前计算的日期。

**KPI Sliding Year**
=SUM(IF ([Id Date] > [Date Current Month - Previous Year] 
         AND [Id Date] < [Date Next Month] )
    THEN [Value]
    ELSE NULL
    END)

5.构建参考度量

为了显示 KPI 性能,我们需要将一个时间范围内的 KPI 与一个基准进行比较。对于我们的 KPI 模板,我们设置了 3 个不同的基准:目标值、上个月的 KPI 值和上一年的同一个月。

作者截图

为了允许引用的动态行为,我们需要构建以下 4 个对象,我将在下面解释。

作者截图

**KPI Target**
=[Target]

这个对象只是从之前创建的参数 Target 派生而来。

**KPI Reference (Performance Scope)**
=CASE [Performance Scope]
WHEN 'CurrentMonth_vs_PreviousMonth' 
      THEN  [KPI (Previous Month)]
WHEN 'CurrentMonth_vs_PreviousYear' 
      THEN  [KPI (Current Month Previous Year)]
WHEN 'CurrentMonth_vs_Target' THEN  [KPI Target]
END

根据选择器绩效范围的值,选择三个基准 KPI(上月)、KPI(当月上年)KPI 目标中的一个作为参考。

**KPI vs Reference (Performance Scope)**
=[KPI (Performance Scope)] - [KPI Reference (Performance Scope)]

该对象通过计算差异,将所选范围的 KPI 与 KPI 参考(绩效范围)进行比较。在其他情况下,表达式也可以是比率或%。

然后,我们创建另一个(相同的)度量,该度量仅用于以不同的方式显示其值。当我们构建实际的可视化时,我们将看到如何配置一些额外的属性。

**KPI vs Reference (Performance Scope) Sign**
=[KPI (Performance Scope)] - [KPI Reference (Performance Scope)]

6。将一切放在一起:KPI 可视化

我们现在需要结合 Tableau 维度和度量来制作我们的动态 KPI 可视化。

简而言之:我们将把维度和度量合并到 5 个 Tableau 工作表中,定义如何可视化它们中的每一个,最后使用工作表组成一个仪表板部分来呈现 3 个 KPI 的基本元素:值、趋势和绩效。

作者截图

  • (1) KPI 值
  • (2)标题
  • (3)期间标签
  • (KPI 值与参考值的符号
  • (5) KPI 趋势

我将在下面介绍如何制作每张工作表。

(1) KPI 值

让我们从 KPI 值开始:您需要将对象 KPI (Performance Scope) 作为文本拖放(只需将其拖放到文本标记中,参见下面的黄色箭头)。

作者截图

要像我一样设置文本格式,您需要单击文本标记并设置如下属性

作者截图

有几种方法可以显示$符号。一种是右键单击 KPI(绩效范围)对象,格式化,并编辑数字格式如下:

作者截图

(2)字幕

标题区域显示 KPI 值与所选绩效值的比较。

您需要创建一个新的 Tableau 工作表,拖放 KPI vs Reference(绩效范围)Performance Reference Lable作为工具提示(只需将它们拖放到工具提示标记中,参见下面的橙色箭头)。

作者截图

使“标题”窗口在 Tableau 画布的底部可见,单击顶部菜单“工作表”,然后选择“显示标题”。

然后双击标题区域和“插入”,添加两个对象如下

作者截图

要设置为 KPI vs Reference(绩效范围)显示的格式,您需要编辑其格式,如下所示

作者截图

我用的表达是

▲ +$#;▼ -$#;=

(3)期间标签

周期标签显示了我们分析的周期和比较的基准。

要构建可视化,您需要创建一个新的工作表,并将对象绩效参考标签本期标签作为文本拖放

作者截图

(4)KPI 值与参考值的符号

为了直观地显示 KPI 值与参考值的比较,我们可以将其符号显示为彩色的▲或▼。它显示当前周期是比参考周期更好(绿色▲)还是更差(红色▼)。

要实现这一点,创建一个新的工作表,然后拖放对象KPI vs Reference(Performance Scope)Sign作为文本和颜色标记。

作者截图

要设置形状,请使用表达式编辑文本对象的格式

▲;▼;=

作者截图

要设置颜色,单击颜色选项卡,并选择红绿发散,以零为中心。这样正值将以绿色显示,负值以红色显示。

作者截图

(5) KPI 趋势

要显示去年的趋势,创建一个新的工作表,将 KPI 滑动年份拖放到区域行中,并在列中定义以下表达式。

DATETRUNC('month', [Id Date])

然后在标记编辑器中选择“区域”,你会看到类似下面的东西。

作者截图

然后,您应该自定义颜色和隐藏轴标签,以完全如上所示。

撰写仪表板节

您刚刚创建的所有工作表都可以合并到一个仪表板(部分)中。在真实的仪表板中,我们会一起显示许多 KPI 可视化,所有这些都基于相同的模板,以提供和谐和一致性,因此这里我们只使用一个 KPI 进行演示,以介绍这个概念。

让我们创建一个新的仪表板(通过单击下面的橙色框)并导入我们创建的所有工作表(参见黄色框),然后将它们排列如下

作者截图

如果您尝试更改选择器的值,您将看到 KPI 值和性能发生变化。

作者截图

努力

您可能认为仅仅为了一个 KPI 可视化,您就必须构建相当多的对象,对吗?。在真实的仪表板中,我们通常一起呈现许多 KPI(见下图),并且所有 KPI 共享相同的参数和效用维度。因此,您需要进行的实际开发不到我们在此演示中所做的一半。

此外,一旦您有了 KPI 模板,您可以通过复制我们通过 4 和 5 创建的度量来创建新的模板,如果基于不同的业务规则,只需替换基本的源度量和计算。这使得开发变得快速而简单,因此我毫不怀疑使用这个或类似的 temples 所带来的优势,而不是为每个可视化构建一组自定义的对象。

来自 Tableau Public 的截图

简而言之…

在这个故事中,我通过一个实际操作的场景,与您分享了我构建 KPI 模板可视化的方法。KPI 模板使得仪表板开发比非结构化开发更简单、更快速、更易于维护。

该方法可轻松应用于任何其他工具(例如 Qlik、Power BI 等)。)和业务领域,只要我们有一个随时间变化的度量标准。

我还提供了我使用的源数据,并一步一步地描述了我是如何实现 KPI 模板的每个部分的,这样,无论您的技能水平如何,如果您愿意,您都可以自己重做。

随时订阅我的《分享数据知识》简讯

仪表板教程(二):HTML,CSS,PHP 和 Heroku

原文:https://towardsdatascience.com/dashboard-tutorial-ii-html-css-php-and-heroku-e8bdb7f26783?source=collection_archive---------13-----------------------

照片由freepik.com拍摄

网页的布局通常是通过 CSS 选择器来显示内容的元素。通过 CSS,您可以确定文本颜色、内容显示以及网页背景和图像。当在服务器上部署 web 页面时,Heroku 通常是常见的部署平台。在 Heroku 平台,可以免费托管网站,管理多个 app 文件夹,轻松与终端协同工作。在这篇博客中,我们将浏览 web 布局、文件结构和到 Heroku 的 web 部署的 CSS 选择器。

在本文中,您将学习在 Heroku 服务器上创建一个基本的仪表板和部署:

(CSS 布局介绍

(HTML、Javascript 和 CSS 文件的文件夹结构

⑶部署到 Heroku

CSS 布局介绍

CSS 是一种装饰网页的样式表语言。CSS 使网页能够显示定制的演示文稿,包括块布局、边距、填充、字体等。在本教程中,我们将深入图表的布局。用导航条绘制 JS。

CSS 网格布局

CSS Grid 是一个带有水平线和垂直线的二维元素——一组定义列,另一组定义行。

首先,我们创建一个网格容器

通过声明display: griddisplay: inline-grid.该元素的所有直接子元素成为网格项目来创建网格容器。在下面的例子中,有 4 个单独的图表是用 canvas 标签和 h3 作为图的描述创建的。这 4 个图被包装在类包装器的< div >元素中,这些子元素成为网格项。

<div class="wrapper"><div><h3>Bar Chart of COVID active cases count in June</h3><canvas id="myChart" width="500" height="300"></canvas></div><div><h3>Line Chart of COVID cumulative cases in Canada</h3><canvas id="myChart1" width="500" height="300"></canvas></div><div><h3>Doughnut Chart of cumulative COVID cases count in Canada</h3><canvas id="myChart2" width="500" height="300"></canvas></div><div><h3>Bar Line Chart of COVID cases in Canada</h3><canvas id="myChart3" width="500" height="300"></canvas></div></div>

下面的例子展示了如何为网格容器创建一个包装器的选择器。接下来,我们定义网格轨迹,它是网格中显示的 2 条线的空间。在网格容器中,网格模板列网格模板行用于定义行和列。属性的grid-template-columns可以定义列轨道的大小。Grid-template-columns 设置为 800 像素宽的列轨道。另外,我在行和列上都创建了一个 50 像素的间隙。

 .wrapper {display: grid;grid-template-columns: 800px 800px;column-gap: 50px;row-gap: 50px;}

链接 CSS 文件和外部资源

下面的例子展示了在 CSS 文件中嵌入的方法。外部和内部 CSS 源都应该包含在元素中,元素需要放在<head></head>标签之间。因此,HTML 网页将从< link >元素链接到样式表。

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"><link rel="stylesheet" href="../static/styles/style.css">

HTML、Javascript 和 CSS 文件的文件夹结构

对于仪表板,有几个不同的文件,如数据集 CSV 文件、绘图 javascript 文件、样式表 CSS 文件和网页 HTML 文件。最好将不同的文件存放在项目主目录下的每个文件夹中。通常,子目录中有一个静态文件夹来存储各种文件。例如,我的所有数据集都存储在文件夹中,js 文件存储在 js 文件夹中,CSS 文件存储在 styles 文件夹中,HTML 文件存储在 template 文件夹中。

Javascript 和 HTML 文件的交互

下面显示了在 HTML 文件中创建的 ChartJS 图,其画布 id 为“myChart”。

<div><h3>Bar Chart of COVID active cases count in June </h3><canvas id="myChart" width="500" height="300"></canvas></div>

在 Javascript 文件中,我们将通过使用document . getelementbyid()函数调用调用“myChart”id 来呈现绘图。

var ctx = document.getElementById("myChart");

在 html 文件中,我们可以通过使用

<script src="../static/js/bar.js"></script><script src="../static/js/line_chart.js"></script><script src="../static/js/donut.js"></script><script src="../static/js/line_bar.js"></script>

CSS 文件选择器

现在,我们深入研究 CSS 选择的字体和文本。我们通过使用属性font-family.来定义文本的字体。文本对齐被指定为以text-align: center.为中心。也可以选择为网页指定字体大小为font-size: 10px;。就边距而言,它显示了文本周围的空间。使用margin: 0 0 0.1em,文本显示为上、下、左、右边距,后跟顺序。因为<body>是内容页面的父元素,所以它里面的所有元素都继承了相同的text-alignfont-family

body {font-family: Helvetica Neue, Arial, sans-serif;
text-align: center;
font-size: 10px;
margin: 0 0 0.1em 0;
color: rgb(89, 112, 240);}

接下来,我们研究 CSS 选择器中的块概念。在 HTML 文件中,我们使用标签<a>来定义一个超链接,用于从一个页面链接到另一个页面。在 CSS 文件中,block 元素可以应用边距和其他间距值。然而,<标签是一个没有边距值的内嵌元素。为了对超链接标签应用边距,我们需要添加显示参数display: block;。然后,我们可以通过margin-top: 50px;给出顶部的保证金值

a {margin-top: 50px;display: block;color: #3e95cd;}

Heroku 部署

要在 web 服务器而不是本地主机上部署仪表板,Heroku 通常是一个流行的部署选项。从 Heroku 开始,支持 Ruby,Node.js,Clojure,Python,Java,Gradle,Grails,Scala,Play,PHP,Go。然而,编程语言并不是为典型的 HTML、CSS、Javascript 语言提供的。好的解决方案是为网页构建一个 PHP 应用。我将向您介绍 Heroku 设置、git 设置、PHP 文件创建和项目部署到 Heroku 平台的步骤。和 tada,项目显示有一个 HTML 链接,外部访问可以共享该链接。

(1)注册一个帐户并安装 Heroku。( link1link2 )

(2)在终端中,输入 Heroku 登录所需的凭证。

(3)初始化一个本地 Git 存储库并提交您的应用程序代码。
在终端中,键入下面列出的命令行

cd your_project
git config --global user.email “you@example.com”
git config --global user.name "Your Name"

(4)准备 PHP 文件来呈现 HTML 页面。前往包含 index.html 的项目根目录

(5)在这个目录下,运行touch composer.json创建一个文件:composer.json,在 json 文件中,添加{}。

(6)在同一个目录下,运行touch index.php创建一个文件:index.php。在 PHP 文件中,添加<?php include_once("index.html"); ?>

(7)在终端,我们初始化 git 库,将项目文件夹推送到 Heroku 服务器进行部署。在终端中,键入下面列出的命令行

cd your_project
# Create a local git repository
git init 
# Add all your local files to repository
git add .
# Commit your files
git commit –m “First commit”
# Create an empty Heroku app, make sure the app name is unique with your own creation
heroku create php-dashboard-tutorial 
# push our application to Heroku
git push heroku master
# check one instance of the app is running
heroku ps:scale web=1

神奇的事情发生了。现在,您的仪表板已经成功部署到 Heroku 服务器上,并且可以通过外部 web 链接进行访问。

总之:

  • CSS 选择器可以用来设置用类定义的 HTML 标签元素的样式。网格容器可以显示网页项目的列和行的布局。元素用于在 HTML web 文件中嵌入内部和外部 CSS 样式表。
  • 最好将不同的文件存储在静态目录下的特定文件夹中。在 HTML 文件中,我们可以通过使用
  • Heroku 作为一个 web 服务器平台,支持 Ruby、Node.js、Clojure、Python、Java、Gradle、Grails、Scala、Play、PHP、Go。作为一种选择,带有 HTML、CSS、Javascript 的仪表板可以通过一个额外的 PHP 文件为 Heroku 部署工作。此外,Heroku 需要一个 git 存储库来将项目文件夹推送到 web 服务器。

我的简单 COVID 仪表盘链接: 【https://dd-dashboard-3.herokuapp.com/】

希望您能从教程中获得一个仪表板!

参考:

  1. CSS 基础知识:https://developer . Mozilla . org/en-US/docs/Learn/Getting _ started _ with _ web/CSS _ basics

2.网格布局的基本概念:https://developer . Mozilla . org/en-US/docs/Web/CSS/CSS _ Grid _ Layout/Basic _ Concepts _ of _ Grid _ Layout

3.将您的 Python web 应用程序部署到 Heroku cloud:https://Python how . com/deploying-your-web-application-to-the-cloud/

4.如何在 Heroku 上运行简单的 HTML/CSS/Javascript 应用:https://medium . com/@ Winnie Liang/how-to-Run-a-Simple-HTML-CSS-Javascript-Application-on-Heroku-4 e 664 c 541 b0b

5.Heroku 用 Git 部署:https://devcenter.heroku.com/articles/git

仪表板死了

原文:https://towardsdatascience.com/dashboards-are-dead-b9f12eeb2ad2?source=collection_archive---------0-----------------------

在过去的几十年中,仪表板一直是分发数据的首选武器,但它们并不是故事的结尾。为了让数据访问越来越民主化,我们需要重新思考,答案可能比你想象的更接近…!

你好仪表板,我的老朋友

当我开始职业生涯时,我在一家大型科技制造公司工作。该公司刚刚购买了第一个仪表板工具,我们的团队负责从疲惫的电子表格和 SSRS 报告到闪亮的新仪表板的激动人心的过渡。

对我们来说,从电子表格到仪表板的转变是分析成熟度的重大飞跃。仪表板的周到设计和交互性大大降低了数据的“准入成本”。突然,你会在办公室里走来走去,看到来自任何角色和背景的员工摆弄仪表板。这是数据爱好者的天堂,对吧?

不完全是。我们很快发现仪表板带来了一系列新问题:

  1. 你有仪表板,你有仪表板,你有仪表板!突然,仪表盘随处可见。工程师想要一些数据进行特别分析?这是一个仪表板。副总裁下周有一个演示,想要一些图表?她得到了一个仪表板。不,他们再也没有看他们一眼。一刀切的方法耗尽了我们团队的时间、资源和动力。这是一种独特的令人沮丧的感觉,看着你的仪表板又一次被抛弃,比你 2008 年的 Myspace 账户还快。
  2. 死于 1000 个过滤器:在一个仪表板上线后,我们立即被新视图、过滤器、字段、页面等各种请求所淹没(提醒我告诉你我曾见过一个 67 页的仪表板……#难以忘怀)。很明显,仪表板没有回答每个人的问题,这要么是仪表板设计步骤的失败,要么是其他工具在提供人们需要的答案方面的失败。更糟糕的是,我们发现人们使用所有这些过滤器将数据导出到 Excel 中,然后用它们做自己的事情🤦‍♀️.
  3. 不是我的仪表盘。仪表板炒作来得越快,它就开始消退。人们开始贬低仪表盘是“错误的”,并公然忽视它们。许多人认为这是对他们工作的威胁,如果他们看到他们没有预料到的数字,就把它归结为“坏数据”。我们有一个严重的信任问题,仪表板几乎没有提供机会来减轻他们的担忧。毕竟,我们不能把我们的 SQL 查询发送给他们;他们将无法阅读它们,更不用说理解它所反映的极其复杂的模式了。在每个团队创建他们自己的度量定义的情况下,我们不能给他们发送原始数据。我可能轻描淡写了…我们有一个巨大的、溃烂的、渗出的信任问题。

真实例子:吓人的红点里有什么?

为了进一步证明这一点,让我们考虑一个在当前冠状病毒危机中广泛流行的数据仪表板:约翰霍普金斯冠状病毒仪表板。

2020 年 4 月 7 日拍摄的 JHU 仪表盘截图

JHU 仪表板在视觉上很吸引人;红色和黑色唤起了这一刻应得的严肃感和紧迫感。当我们的目光扫过页面时,我们会遇到数字、各种大小的点,以及几乎总是越来越向右上方移动的图表。我们感觉情况很糟糕,而且似乎越来越糟。这个仪表板旨在以一种可访问且引人入胜的方式获取数据。它甚至可能被设计用来回答一些关键问题,如“今天我国有多少新病例?我的县?”需要明确的是,这是所以比他们仅仅发布一个表格或下载链接要好得多。

但是除了那些肤浅的发现,我们不能用这些数据采取行动。如果我们想将这些数据用于某个特定的目的,我们将缺乏必要的上下文来使这些数据变得有用——并相信它们是我们自己的(例如,社交距离测量在我的国家/县是什么时候开始的?在我的国家,检测的可用性如何?)即使我们设法获得了信任这些数字的必要背景,仪表板本身也缺乏进行我们需要的定制分析的能力灵活性

就像我在某个不知名的公司的经历一样,这个仪表板成功地让人们用数据做一些事情,但不一定是用数据做一些有意义的事情。在一家不知名的公司,我们试图通过添加越来越多的仪表板,然后添加越来越多的过滤器来解决这个问题,然后当这些仪表板毫无用处时,就将其删除。这种负反馈循环导致了对数据的严重不信任和团队间的分裂,如果消极进取的 LinkedIn 更新是可信的,我认为其中许多仍然存在。

仪表板为数据赋权做了大量工作(还有我的职业生涯!)但它们肯定不是数据协作和报告的最佳接口。谢天谢地,有一个竞争者你可能已经在用了…

数据进入肖像模式

从仪表板到笔记本的演变

像 Jupyter 这样的数据笔记本在过去几年里在数据科学领域变得非常流行。在进行数据分析和数据科学时,面向过程的本质已经被证明优于传统的脚本。这不仅有利于从事这项工作的分析师,也有助于不得不使用它的老板/同事/不情愿的朋友。

从根本上说,笔记本电脑提供了机会:

  1. 为了让大家信任这个过程(因为他们可以从字面上看到代码和作者的评论),
  2. 拥有回答任何问题的能力和灵活性(只要用户知道工具所用的语言),以及
  3. 一种让合作、展示以及与更广泛的受众分享这些决定的方式。

我当然不是第一个想将笔记本电脑的强大功能和灵活性应用到数据分析/商业智能领域的人。我们已经和许多使用笔记本电脑而不是仪表板的公司谈过了。有些人只使用 Jupyter 笔记本进行报告,其他人会将图表剪切并粘贴到文本编辑器中以达到类似的效果。这些都是不完美的解决方案,但标志着公司愿意超越精心制作的仪表板,实现笔记本电脑的优势。

我们只是需要一种方法来将这些原则扩展到数据科学之外,并使笔记本变得像仪表板一样易于访问。

面向大众的笔记本

Count ,我们对笔记本电脑的基本优势深信不疑,因此我们围绕它们建立了一个数据分析平台。这里没有仪表板!

为了在数据科学之外使用它们,我们不得不制作自己的版本,但基本原则仍然适用,但有一些额外的好处…

专为各种经验水平打造

  • 无需向团队中的每个人教授 Python 或 SQL,因为可以通过拖放、编写“笔记本 SQL”(见下文)或编写完整的 SQL 来构建查询。

Count 的笔记本 SQL 示例

  • 只需一次点击即可获得快速视觉效果,因此无需复杂的可视化软件包或软件。
  • 表和查询输出的自动连接,因此无需编写复杂的连接或尝试解释模式

已启用协同

  • 与队友、整个团队、整个公司或任何有链接的人共享笔记本
  • 添加注释和标注,使其真正成为共享文档

计数笔记本夹

通过以笔记本电脑为核心,Count 提供了团队所需的能力、透明度和协作,不仅可以为人们提供数字,还可以让他们获得所需的见解并与公司其他人分享。

由于我们一直在构建 Count,我们一直在与许多组织合作,以了解笔记本如何改变数据在团队中的使用方式。以下是我们的发现:

  1. 分析师使用笔记本而不是疯狂的 SQL 脚本来创建一些其他团队使用的基础表。任何人都可以查看(和解读)这些笔记本,所以没有人会因为不知道这些数字来自哪里而对其不屑一顾。
  2. 数据团队创建了一些基本报告。这些报告充满了评论,以帮助指导读者如何解释这些数字和任何需要考虑的问题。
  3. 然后,用户可以使用这些笔记本或创建自己的笔记本来回答他们的特别问题。他们与数据团队分享这些笔记本电脑,这样他们就可以帮助指导他们,然后他们将这些笔记本电脑展示出来,并与企业的其他部门分享。

由于每个人都可以消费所有东西,而且在一个地方,信任问题开始改善(或者,在现实中,只是变成了其他事情)。他们没有为不使用仪表板的人创建仪表板,也没有为满足各种需求而创建数以千计的过滤器,因为人们有更多的权力来创建他们真正需要的报告。他们描述的场景证明,从仪表板到笔记本的小小转变会对您的团队利用数据的方式产生巨大影响。

如果您想了解更多关于笔记本如何帮助您的团队更加数据驱动的信息,请在 hello@count.co 给我们写信,或者您可以在这里阅读更多!

这是我们“呼唤更好的分析工具”系列的文章之一。该系列的其他文章包括:

  • 分析工作流程中断 —为什么笔记本电脑正在取代标准分析工具集。
  • 数字不再足够 —为什么我们需要比图表更多的东西来改变世界。
  • 如何为您的组织带来笔记本电脑—如何一次一个数据请求地改变您组织的性能(即将推出)

报名参加我们的 快讯 获取最新帖子。

资源

[1] C 新冠肺炎冠状病毒全球病例由约翰·霍普金斯大学(JHU)系统科学与工程中心(CSSE)(2020)约翰·霍普金斯大学

使用 Dash 和 SQL 快速浏览圣诞歌曲

原文:https://towardsdatascience.com/dashing-through-christmas-songs-using-dash-and-sql-34ef2eb4d0cb?source=collection_archive---------50-----------------------

使用 SQL 数据库创建 Dash 仪表板的简单项目

塞巴斯蒂安·斯宾德勒在 Unsplash 上拍摄的照片

女士们先生们,宾·克罗斯比先生!TL;dr 在 GitHub 上找到网络应用的代码。

宾·克罗斯比和安德鲁斯姐妹演唱《铃儿响叮当》

本文概述了我使用破折号在 SQL 数据库上创建 web 应用程序的奋斗和成功。本文分为 4 个部分:创建 SQL 数据库、安装 Dash 环境、构建 web 应用程序、运行应用程序。我不熟悉 Dash 环境,这种灵活性给了我灵感。还有其他 web 应用程序创建引擎,如 Viola 也值得探索。Dash 令人耳目一新,因为它包含了可以显示不同对象的标签的独特功能。

用 python 将 CSV 文件转换成 SQL 数据库

我用维基百科上的美国圣诞歌曲表创建了一个 CSV 文件。经过一些手动格式化后,我有了一个包含 4 列的 CSV 文件[歌曲名、艺术家名、发行年份、其他信息]。在下面的脚本中将 CSV 转换为 SQL 数据库之前,Pandas 是唯一需要安装的库。模块 sqlite3 已经是我的 python 发行版的一部分。

import pandas as pd
import sqlite3conn = sqlite3.connect('Songs.db')
c = conn.cursor()# Create table with headers
c.execute('''CREATE TABLE Songs
             ([generated_id] INTEGER PRIMARY KEY,[Song_Name] text, 
             [Artist_Name] text, [Year] date, [Other] text)''')conn.commit()# Convert CSV to SQL
read_songs = pd.read_csv('Chrismas_Songs.csv')
read_songs.to_sql('Songs', conn, if_exists='append', index = False)

简而言之,该代码使用 execute 函数创建了一个 SQL 表,其中包含 SQL 命令。当我们将 CSV 文件导出到先前为空的 SQL 表中时,使用 Pandas 填充该表。现在我们的 SQL 数据库已经准备好了,接下来是安装 Dash 的时候了。

创建 Dash 环境

仪表板安装提示可在仪表板主页上找到。这个项目需要安装的包包括

## Install Plotly
pip install plotly## Install Pandas
pip install pandas## Install Dash and Components
pip install dash
pip install dash-bootstrap-components
pip install dash-html-components
pip install dash-table

Web 应用的构建结构

index.py
app.py
database/
|_ __init__.py
|_ Chrismas_Songs.csv
|_ Songs.db
|_ transforms.py
tabs/
|_ __init__.py
|_ sidepanel.py
|_ tab1.py
|_ tab2.py

我从数据库/和选项卡/文件夹中导入数据函数,所以我必须包含一个名为 init 的空白文件。py 让 python 知道这是一个模块。web 应用程序将从 index.py 运行,该文件调用包括 app.py 在内的所有其他 python 文件。

构建 Dash Web 应用程序

构建应用程序从 app.py 文件开始。下面,我们调用应用程序并将其连接到服务器(在索引文件中)

app.py

**import** dash
**import** dash_bootstrap_components **as** dbc

app = dash.Dash(__name__, external_stylesheets =[dbc.themes.BOOTSTRAP])
server = app.server
app.config.suppress_callback_exceptions = True

索引文件是奇迹发生的地方。这是您的 web 应用程序的四分卫。Dash 使用回调从客户端(web)获取数据,并在服务器端(后端)操作。下面是一个来自索引文件的例子,完整的索引文件见 GitHub

index.py

[不是完整的文件,从 Github 下载或复制完整的文件]

app.layout = sidepanel.layout

@app.callback(Output(**'tabs-content'**, **'children'**),
              [Input(**'tabs'**, **'value'**)])**def** render_content(tab):
    **if** tab == **'tab-1'**:
        **return** tab1.layout
    **elif** tab == **'tab-2'**:
        **return** tab2.layout@app.callback(Output(**'table-sorting-filtering'**, **'data'**)
, [Input(**'table-sorting-filtering'**, **"page_current"**)
, Input(**'table-sorting-filtering'**, **"page_size"**)
, Input(**'table-sorting-filtering'**, **'sort_by'**)
, Input(**'table-sorting-filtering'**, **'filter_query'**)
, Input(**'Last_Decade'**, **'value'**)
, Input(**'year-slider'**, **'value'**)
, Input(**'Artist-drop'**, **'value'**)]) **# function to filter data table 
def** update_table(page_current, page_size, sort_by, filter, yearcheck, prices, artists):
# insert function content here**if** __name__ == **'__main__'**:
    app.run_server(debug = True)

让我们从头开始分析一下。app.layout 使用用户输入创建侧栏,更多内容将在 sidepanel.py 分解中解释。@app.callback 既呈现选项卡(数据表和直方图),也调用用户选择的过滤。@app.callback 中的输入对应于下面函数中的参数。例如,在 first @app.callback 中,tabs 与 render_content 函数中的 tab 参数相同,Last_Decade 与 update_table 函数中的 yearcheck 相同。最后一部分是在 if name == 'main '函数中对应用服务器的调用。

Database/transforms.py

这个文件将 SQL 数据库连接到我们的索引文件和 web 应用程序。

**import** dash
**import** dash_bootstrap_components **as** dbc
**import** dash_core_components **as** dcc
**import** dash_html_components **as** html
**import** pandas **as** pd
**import** sqlite3
**import** dash
**from** dash.dependencies **import** Input, Output
**import** dash_table
**import** pandas **as** pd

conn = sqlite3.connect(**r"/Users/stronglab2/Documents/Datadolittle/Dashing_Through/database/Songs.db"**)c = conn.cursor()

df = pd.read_sql(**"select * from Songs"**, conn)

Tabs/tab1.py

[不是完整的文件,从 Github 下载或复制完整的文件]

Tab1.py 在第一个选项卡中创建数据表。该文件还包括单元格的格式选项。

## Load SQL Database into table
df = transforms.df

PAGE_SIZE = 50layout = html.Div(dash_table.DataTable(id='table-sorting-filtering',columns=[{**'name'**: i, **'id'**: i, **'deletable'**: True} **for** i **in** df[[**'Song_Name'**,**'Year', 'Artist_Name'**,**'Other'**]]], ..................

SQL 数据被加载到 pandas 数据框中,并显示为 dash 数据表。然后,我们为数据表创建列。定义列后的点表示整个文件中有更多的细节。

Tabs/tab2.py

[不是完整的文件,从 Github 下载或复制完整的文件]

Tab2.py 在第二个选项卡中创建直方图。该文件还包含@app.callbacks,用于根据用户选择进行更新。

df = transforms.df

layout = html.Div(
    id=**'table-paging-with-graph-container'**,
    className=**"five columns"** )

@app.callback(Output(**'table-paging-with-graph-container'**, **"children"**),
              [Input(**'Last_Decade'**, **'value'**)
                  , Input(**'year-slider'**, **'value'**)
                  , Input(**'Artist-drop'**, **'value'**)
               ])
**def** update_graph(yearcheck, prices, artists):
....................................................................
    graph_plotly = go.Histogram(x=dff[**'Year'**],
                      name=**"Histotest"** , opacity=0.7) **return** html.Div([dcc.Graph(id=**'histo-graphic',figure={'data':[graph_plotly], ..........**

直方图是通过 go 生成的。直方图功能,并通过 html 显示在标签页中。Dic([dcc。图表…

Tabs/sidepanel.py

[不是完整的文件,从 Github 下载或复制完整的文件]

侧面板允许用户与 web 应用程序交互。有三种相互作用。“最近十年”复选框(2009 年之后发行的歌曲)、“艺术家”下拉列表(可以选择多个艺术家)或发行日期范围(1910-2020)。表格和直方图根据选择进行更新。

layout = html.Div([
    html.H2(**'Filters'**)
    , dcc.Checklist(id=**'Last_Decade'** , options=[
            {**'label'**: **' Released this decade '**, **'value'**: **'Y'**}
        ])
        ,html.Div([html.P() ,html.H5(**'Artist'**), dcc.Dropdown(id = **'Artist-drop'** ,options=[
                     {**'label'**: i, **'value'**: i} **for** i **in** df[**'Artist_Name'**].unique()],
                value=[],
                multi=True
            )])
          ,html.Div([html.H5(**'Year Slider'**)
                   , dcc.RangeSlider(id=**'year-slider'...............**

这个文件创建了所有三个交互选项。每个选项由 html 分隔。Div 然后用交互类型调用 dash_core_components (dcc)。在 index.py 文件和 tab2.py 中调用 id 来更新表和直方图。

运行 Web 应用程序

对于那些希望看到工作示例的人,安装所需的包并从 GitHub 下载资源库。下面的屏幕截图显示了 web 应用程序。

数据表选项卡,过滤宾·克罗斯比和玛丽亚·凯莉的歌曲

宾·克罗斯比和玛丽亚·凯莉的歌曲直方图

要运行应用程序,只需在应用程序目录中键入python index.py。您可能会看到下面的提示,显示该应用程序正在您的本地计算机上运行。

Running on http://127.0.0.1:8050/Debugger PIN: 829-054-282* Serving Flask app "app" (lazy loading)* Environment: productionWARNING: Do not use the development server in a production environment.Use a production WSGI server instead.* Debug mode: onRunning on http://127.0.0.1:8050/Debugger PIN: 182-493-929

只需将http://127.0.0.1:8050/复制并粘贴到网络浏览器中,应用程序就启动了!

这是一个使用 Dash 和 SQL 构建的简单 web 应用程序。我的名字是科迪·格利克曼,可以在 LinkedIn 上找到我。请务必查看我在数据科学或 web 开发领域的一些其他文章。

[## 使用 GitHub 创建漂亮的静态网页

查找模板和为静态网页创建表单的位置

towardsdatascience.com](/building-a-beautiful-static-webpage-using-github-f0f92c6e1f02) [## 探索大学足球薪酬

按州和会议列出的每个学生的价格

medium.com](https://medium.com/swlh/exploring-college-football-salaries-dc472448684d) [## 机器学习中的什么或为什么

使用 Python 解释模型的综合指南

towardsdatascience.com](/what-or-why-in-machine-learning-e2a73da528c8)

DASK:使用并行化处理大型数据集的指南

原文:https://towardsdatascience.com/dask-a-guide-to-process-large-datasets-using-parallelization-c5554889abdb?source=collection_archive---------26-----------------------

理解大数据数据科学机器学习

Numpy、Pandas 和 Scikit-Learn 框架中大数据并行计算的简单数据分析解决方案

托马斯·詹森在 Unsplash 上拍摄的照片

介绍

如果您正在处理大量数据,并且您担心 Pandas 的数据框架无法加载它或者 NumPy 数组卡在中间,您甚至需要一个更好的并行化解决方案来处理您的数据和训练机器学习模型,那么 dask 为这个问题提供了一个解决方案。在深入研究之前,让我们看看 dask 到底是什么?

在潜入深海之前,你听说过懒惰装载吗?了解 Vaex 如何主导加载大型数据集的市场。

[## 现在,使用惰性计算在一秒钟内加载巨大的数据集😴用 Python?

厌倦了用熊猫加载数据集…了解 Vaex 如何帮助在几秒钟内加载大量数据…

towardsdatascience.com](/now-load-huge-datasets-within-a-second-using-lazy-computation-in-python-2698bdb02250)

dask 是什么?

Dask 是一个极其高效的开源项目,它使用现有的 Python Apis 和知识结构,使得在 Numpy、Pandas、Scikit-learn 之间进行修改成为它们的 Dask 支持的对等物变得简单。此外,Dask 的调度程序可以扩展到千节点集群,其算法在全球内最重要的号超级计算机上进行测试。

来源:使用 Dask 并行化扩展到集群

装置

quality 是预装在您的 Anaconda 中的,但是对于 pip,您可以使用以下命令获得完整的版本:

Dask 的 Conda 安装:

**!conda install dask**

Dask 的 pip 安装:

**!pip install “dask[complete]”**

达斯克是做什么的?

Dask 有助于并行化阵列、数据帧和机器学习,以处理大量数据,例如:

数组:并行化的 Numpy

**# Arrays implement the Numpy APIimport dask.array as da
x = da.random.random(size=(10000, 10000), chunks=(1000, 1000))
x + x.T - x.mean(axis=0)**

数据帧:平行熊猫

**# Dataframes implement the Pandas APIimport dask.dataframe as dd
df = dd.read_csv('financial_dataset.csv')
df.groupby(df.amount).balance.sum()**

机器 学习:并行化 Scikit-Learn

**# Dask-ML implements the Scikit-Learn APIfrom dask_ml.linear_model import LogisticRegression
lr = LogisticRegression()
lr.fit(train, test)**

Dask 中的数据帧

大多数 Dask API 与 Pandas API 非常相似,因此您可以使用非常相似的命令直接使用 Dusk 中 Pandas 的数据帧。要生成一个离散的数据帧,您可以像以前调用 Pandas 一样简单地调用**read_csv()**方法,或者轻松地将 Pandas 数据帧转换成 Dask 数据帧。

**import dask.dataframe as ddf
dd = ddf.from_pandas(df, npartitions=N)**

基准数据框架:熊猫 vs 达斯克

对于下面的基准测试,所用的机器具有标准的 4 核处理器,该处理器在测试两种框架时保持标准。

我做了一个非常简单而有趣的基准测试,来展示 Dask DataFrame 与传统的 Pandas DataFrame 相比,从一个包含 500 万条记录的. csv 文件中读取数据集的速度有多快。

为读取 CSV 数据帧对 Pandas 和 Dask 进行基准测试

结果 :读取一个大小超过 600MB5M 数据文件,Pandas DataFrame 大约需要 6.2 秒,而 Dask DataFrame 由于其令人印象深刻的并行化能力,执行同样的任务所需的时间远少于

:这个测试是在一个小数据集上进行的,但是随着数据量的增加,读取数据的时间差会成倍增加。

您可以使用下面的代码来改变更大数据集的基准测试。

基准阵列:Numpy 与 Dask

在这个基准测试中,我使用 Numpy 数组和 Dask 数组生成了一个1 万亿大小的随机数数组。

创建阵列的基准测试 Pandas vs Dask

结果 :正如所料,结果非常明显,因为 Numpy 数组的计算时间不到 8 秒,而 Dask 数组的计算时间可以忽略不计

您可以使用下面的代码尝试相同的基准测试

关键要点

Dask 有助于更快地进行数据分析,因为它并行化了现有的框架,如 Pandas、Numpy、Scikit-Learn,并使用机器 CPU 的全部潜力并行处理数据。你可以在这里尝试 Dask 的惊人功能

延迟加载与并行处理的结合确实是一个致命的组合,可以帮助您在任何需要的时候利用系统的全部潜力,要了解更多信息,您可以阅读这篇关于 Vaex 的文章。

数据科学家的进一步阅读:

**** [## 如何评价 Python 中机器学习模型性能?

一个实用的方法来计算模型的性能和在 Python 中的实现,涵盖了所有数学…

medium.com](https://medium.com/towards-artificial-intelligence/how-to-evaluate-machine-learning-model-performance-in-python-135b4ae27f7e) [## 如何在短短 1 年内把数据科学从初学者学到大师(我的亲身经历)

随着时间的推移,我的从初学者到大师学习数据科学的清单的完整汇编只需要一年时间…

towardsdatascience.com](/how-to-learn-data-science-from-beginners-to-masters-in-just-1-year-my-personal-experience-6152bedd8157)

谢谢!****

机器学习的 Dask 第一印象

原文:https://towardsdatascience.com/dask-for-machine-learning-first-impressions-64a91d333293?source=collection_archive---------50-----------------------

一种在服务器集群中扩展类似 numpy 的阵列、类似 pandas 的数据帧和 scikit-learn 模型的方法

出于研究大数据的不同机器学习工具的好奇心,我上周花了一些时间来熟悉 DaskDask-ML ,这是另一种在计算机集群上并行运行机器学习算法的替代工具。以下是对它的一些第一反应的简要总结。

图片来源:来自 pexels.com 的的免费库存照片

达斯克将军

Dask 是一个相当年轻的框架,根据官方记录,它的开发似乎在 2015 年左右就开始了。但它是由一个非常受信任的 NumPy、Pandas、Jupyter 和 Scikit-Learn 开发人员社区维护的,背后有强大的机构支持,并且它在机器学习从业者社区中获得了相当大的关注。

虽然我学习 Dask 的个人动机与机器学习有关,但 Dask 本身更普遍地是一个平台,它将帮助您在一个计算机节点集群上并行处理数据。对于一个有 python 经验的数据科学家或数据工程师来说,设计逻辑和结构看起来非常好,很容易掌握。如果你有任何使用 Hadoop MapReduce、Apache Spark 或 TensorFlow 的经验,那么你会立即认识到有向非循环任务图的惰性分布式执行的熟悉概念。如果您对 python 的 concurrent.futures 模块有任何经验,那么您会认识到正在使用的另一种模式。但对于 numpy/pandas/sklearn 用户来说,这一切都变得更容易理解、更容易和更自然,其数组和数据帧有效地将 numpy 的数组和 pandas 的数据帧纳入一个计算机集群。虽然在看起来非常熟悉的数组和数据帧的层次上学习可能感觉很容易,但是不仅直接进入 Dask-ML,而且熟悉所有一般层次的 Dask 概念和 API 也是值得的。

Dask-ML

Dask-ML 用两种不同的策略来处理机器学习任务的扩展:

  • Dask-ML + scikit-learn 组合。您可以使用 Dask 来跨集群扩展并行化的 scikit-learn 估计器和其他算法(具有 n_jobs 参数的算法)。Scikit-learn 本身能够在依赖 Joblib 的多核单台机器上并行化其大量算法,通过 Joblib,Dask 提供了一个替代后端,能够跨计算机集群执行并行作业。当处理的数据集和模型适合于单个节点内存时,这是一个强大而合适的设置,但是运行训练和预测对 CPU 来说太重,实际上无法在单台计算机上运行。
  • 估计器和其他算法的 Dask-ML 实现。这适用于不仅单节点 CPU 太慢,而且单节点内存太少无法加载整个数据集的用例。Dask-ML 自己的估算器实现将数据带到 Dask 的数组和数据帧中,这些数组和数据帧看起来非常像 numpy 数组和 pandas 数据帧,但它们将数据分布在计算机集群中,因此能够处理否则无法放入单机内存中的数据。

不幸的是,Dask-ML 中实现的估计器并不多。根据当前文档,Dask-ML 提供的算法集仅限于以下内容:

  • 预处理: MinMaxScaler、QuantileTransformer、StandardScaler、LabelEncoder、OneHotEncoder、RobustScaler、分类器、DummyEncoder、OrdinalEncoder、SimpleImputer、PCA、TruncatedSVD
  • 模型选择: train_test_split,ShuffleSplit,KFold,GridSearchCV,RandomizedSearchCV
  • 估计量:线性回归、逻辑回归、泊松回归
  • 元估计量: ParallelPostFit,增量
  • 度量: MAE,MSE,r2_score,accuracy_score,log_loss
  • 聚类:k 均值,PartialMiniBatchKMeans 均值,光谱聚类

差不多就是这样——Dask-ML API 参考点的完整列表。

然而,使 Dask-ML 仍然是一个强大的工具的是 scikit-learn 的并行化估计器列表(实现了 n_jobs 参数的列表),即 Dask 能够跨节点集群并行化的 scikit-learn 估计器列表,非常丰富。仅在 sklearn 中就有略多于 15 个这样的分类器,还不算回归器和其他算法。

摘要

Dask-ML 是一个很好的工具,可以将 scikit-learn 的并行估算器从在单台计算机上运行扩展到在计算机集群上运行,Dask 通常是处理大数据的一个很好的替代工具。

Dask 与 Vaex:大型数据处理中数据点的经验

原文:https://towardsdatascience.com/dask-vs-vaex-experience-of-a-data-point-on-large-data-processing-ca157b81846e?source=collection_archive---------39-----------------------

需要处理十亿行数据?我来和大家分享一下我使用 Dask 和 Vaex 的经验。

嗨,我是数据 N!

你好。很高兴见到你!😄我是 Data N(你可以叫我 N),今天,我想分享我作为 data point 与我的新经理 Dask 和 Vaex 一起工作的经验,以及一些与他们建立良好工作关系的技巧(wink)。

背景故事

背景故事是这样的…最近,我们公司有一个小的重组和我们的前经理,熊猫🐼,由两名新员工接管。官方给出的原因是熊猫转移到了新的机会,但我们所有内部人士都知道发生了什么。

嗯,事实是高层管理人员对熊猫最近的表现不满意。我们公司发展迅速,业务呈指数增长。熊猫最初做得很好,但逐渐发现自己无法应对不断增加的数据。当满载美国数据的卡车到达时,我们被证明对熊猫来说太多了。通常,我们会坐在一个名为硬盘的大型仓库中,但当我们需要处理时,有一个名为随机存取存储器(又名 RAM)的临时存储室,我们将被运送到那里进行进一步处理。问题就在这里:RAM 中没有足够的空间容纳我们所有人。

RAM 里没有足够的空间容纳我们所有的人

所以我们的猜测是,高层管理人员决定用 Dask 和 Vaex 替换 Pandas,以便进一步发展公司。这很可悲,但这只是生意。

介绍 Dask 和 Vaex…

自从两个新经理来了,他们每个人都部署了一个独特的伎俩来对付我们。

使用 Dask,我们被分成组(或者用他的话说,“分区”),并且一次处理一个到几个组。

有了 Vaex,我们每个人都提供了我们在仓库中的地址,当 Vaex 需要我们时,她会根据我们的地址调用那些需要来 RAM 的人(她将这种技术称为“内存映射”)。

不管怎样,好的一面是工作完成了,尽管我们太多了,无法一次全部放入 RAM,高层管理人员现在很高兴。

我如何适应 Dask 和 Vaex?

在一起工作了这么长时间后,我们已经很习惯熊猫的命令了,所以 Dask 和 Vaex 都试图用类似的命令来命令我们,这很有帮助。但是它们毕竟不是熊猫,所以还是有一些不同。

# Dask

Dask 喜欢一个关键词叫“计算”。在他说“计算”之前,我们不能完全处理。达斯克总是告诉我们做事要有目的。因此,他的程序通常会是一系列类似熊猫的命令,然后他会在最后一个主要命令中喊出“计算”,然后我们开始全面的实际工作。

以下面的简单代码为例:

import dask.dataframe as dddf_dask = dd.read_csv(’data.csv’)
df_dask.describe()

您得到的不是您期望得到的一般统计数据,而是这个(基本上没有显示任何数据):

发生的情况是,当执行dd.read_csv时,Dask 只从 CSV 文件的开头读入一个美国数据点样本。当调用describe()时,Dask 仅仅记录下要采取的步骤。

为了得到你从熊猫那里得到的通常的输出,你需要一个神奇的词“计算”:

# Vaex

对于 Vaex,她也有自己的风格。一个显著的区别是,她总是希望我们在任何处理完成之前执行列车测试拆分。

那是因为 Vaex 有一个巧妙的技巧。

假设我们对训练数据进行了一些转换:

通过下面两行代码,这些相同的转换可以很容易地应用于测试数据:

state = df_train.state_get()
df_test.state_set(state)

我问 Vaex 这个技巧背后的秘密,她告诉我实际上她的每个数据帧都包含一个状态,它基本上包含了应用于数据帧的所有转换的信息。

因此,我们在两行代码中所做的是获取包含在df_train状态中的转换信息,并将这个状态应用到df_test,所有的更改都将被传递。

如果你想知道,标准化转换在df_test上使用了df_train的平均值和标准偏差。

我猜她真的知道如何聪明地工作!

Dask 和 Vaex 对比如何?

这是一个敏感的话题…

老实说在我看来,就性能而言,Vaex 似乎比 Dask 更有能力。我们中的一些人喜欢 Dask,所以不要告诉别人我说了什么,否则他们可能会解雇我。你也不用信我的话,看看别人(这里这里)在说什么就知道了。

尽管是一个高水平的表演者,Vaex 还是有点害羞,所以她不适合和其他人相处,比如 Scikit-Learn,通常需要一些中介。然而,Dask 和许多其他人合作得很好,因为他经常和 Numpy,Pandas 和 Scikit-Learn 交往。

您可能还会注意到,Dask 擅长在集群环境中工作,而 Vaex 在单台机器上表现出色。

这就是我对我的新经理 Dask 和 Vaex 的所有分享!希望我的建议是有用的,你也将有一个与 Dask 和/或 Vaex 合作的好时光。😄

感谢听我的分享,如果你有任何问题或意见,请随时告诉我。

我的内部消息来源

[## 简介- Dask 教程文档

您可以在实时会话中运行该笔记本,也可以在 Github 上查看它。欢迎来到 Dask 教程。Dask 是平行的…

tutorial.dask.org](https://tutorial.dask.org/00_overview.html) [## Vaex 是什么?- vaex 3.0.0 文档

Vaex 是一个 python 库,用于懒惰的核外数据框架(类似于 Pandas),以可视化和探索大的表格…

vaex.readthedocs.io](https://vaex.readthedocs.io/en/latest/index.html)

数据获取、网络搜集和 KDD 过程:巴西新冠肺炎数据的实践研究

原文:https://towardsdatascience.com/data-acquisition-web-scraping-and-the-kdd-process-a-practical-study-with-covid-19-data-in-brazil-f7f397e814b7?source=collection_archive---------57-----------------------

你对数据科学感兴趣吗?你知道巴西的新冠肺炎的情况吗?在这篇文章中,我将探索数据获取的概念,并演示如何使用简单的网络搜集技术来获取疾病进展的官方数据。值得一提的是,通过对代码进行一些修改,这里使用的策略可以很容易地扩展到来自其他国家的数据,甚至扩展到其他应用程序。所以戴上你的面具,洗干净你的手,现在就开始读吧!

派人去葡萄牙任职。

我必须以向所有新冠肺炎受害者表达最诚挚的情感开始这篇文章。正是在他们的记忆中,我们必须寻找科学发展的动力,同时不要忘记,如果科学存在,那是因为有一种人性在支撑着它。关于数据科学,正是通过它,我们可以最大限度地减少假新闻,并以某种方式为一个更明智、更明智和更有思想的社会做出贡献。

几周前,当我意识到在官方基础上几乎没有关于巴西新冠肺炎病例数量的分层信息时,我开始了这个数据分析项目,例如世界卫生组织(世卫组织-世界卫生组织)或约翰·霍普斯金大学维持的小组的信息。作为分层,其实我们理解的是可以在不同层观察到的数据集。也就是说,对于像巴西这样的大陆规模的国家,了解该国的病例总数只能提供信息。为了使这些信息发挥作用,必须按照地区、州或城市进行分层。

为了提供问题的概述和指导分析的发展,我为这项研究列出了一些目标,希望读者也能采纳:

  • 获得 KDD 过程的概述,并理解数据采集在其中的位置。
  • 探索数据采集技术,以便类似的问题可以很容易地使用它们。
  • 从官方数据库获取巴西新冠肺炎病例和死亡人数,按州分类。

在接下来的几节中,我们将探索其中的每一项,以构建必要的概念并在 Python 开发环境中实现它们。准备好了吗?

KDD——数据库中的知识发现

数据库中的知识发现是人们从数据库中寻找全面的、有效的和相关的模式的过程。这是一个交互和迭代的过程,其中包括许多今天被称为数据科学的技术和方法。

然而,在探索 KDD 过程的主要阶段之前,有必要区分三个关键术语:数据、信息和知识。KDD 的每一步都与处理每一项有关,如图 1 中我们正在解决的问题所示。

图一。从数据到知识:KDD 的信息处理。

简而言之,数据都是与某种现象或事件相关的符号链,无论是否结构化。数据本身没有任何意义。看:408 万这个数字只是个基数。只有当我们赋予它这是新冠肺炎确诊病例数的感觉后,它才变得可怕。换句话说,只有当我们赋予数据意义时,我们才有信息。

正是通过对信息的处理,我们获得了知识,这与我们所说的“认知过程”密切相关——感知、语境化和学习——因此也与智力密切相关。

一旦理解了这三个概念,我们现在就可以进入 KDD 进程的三个基本阶段。这些无非是分别专用于获取和探索数据、信息和知识的任务集,如下图 2 所示:

图二。KDD 过程及其阶段(I)数据获取,(ii)信息处理,和(iii)知识提取。

KDD 流程由多个步骤组成,而这些步骤又是多个任务的组合。例如,数据挖掘任务是信息处理步骤的一部分。相比之下,那些与数据可视化、分析和决策制定相关的任务是最后一步的一部分,旨在进行知识提取。

在本文中,我们将只关注数据采集任务,这是任何 KDD 项目的基础。通常,没有预定义的方法来获取数据。中长期项目通常需要数据模型,以及用于收集和存储数据的健壮架构。反过来,短期项目大多需要立即可用的资源。

牢记这些基本概念,我们准备朝着我们的目标前进:获得巴西新冠肺炎病例数量的官方数据。

定义数据采集策略

正如我们所见,数据采集策略只有从完整的 KDD 过程的角度构建才有意义。也就是说,在我们开始收集数据之前,我们需要有一个明确的目的定义。我们试图解决或阐明的问题是什么?

CRISP-DM 参考模型如图 3 所示,在经历 KDD 过程时可用作指南针。你还记得我们之前定义 KDD 为一个互动和迭代的过程吗?

交互意味着两个或更多代理之间的相互或共享的动作。它既可以指持有数据和信息的人,也可以指阶段。在图 3 的第一步之间的两个方向上的短箭头表示该过程中必要的交互。我敢说,这是 KDD 或数据科学领域的新手面临的最大挑战:最初有一种错觉,认为这些步骤是连续不断的,这导致了一种做错事的感觉。恰恰相反,通过理解业务,我们使得理解数据成为可能,数据为我们收集关于业务的新见解,等等。

反过来,迭代与相同过程的重复相关联。图 3 中较大的箭头形成一个圆圈,象征着这种重复。它从第一步开始,经过开发之后,又回到第一步。KDD 项目永远不会停滞不前。

图 3。根据 CRISP-DM 参考模型的 KDD 流程阶段。(改编自维基共享资源。)

图 3 中突出显示的方框代表与数据采集过程相关的步骤。根据 CRISP-DM,第一步——理解业务——是整个项目成功的基础,包括(I)业务目标的定义;(二)对现状的评估,包括清单和风险分析,以及哪些数据和信息已经可用;㈢确定应用数据挖掘的目标,以及成功标准的定义;(四)项目计划的制定。

第二步——理解数据——包括(I)第一个数据样本和(ii)其详细描述;㈢数据的初步探索;以及(iv)对该数据质量的评估。请记住,这两个初始步骤是交互进行的,并且在理想情况下,涉及领域和业务专家。

第三步从发起人对项目计划的确认开始,其特点是准备数据。一般来说,这一阶段所需的工作变得更加昂贵,因此,他们的变化应该是温和的。这一步的主要任务包括数据的选择和清理、格式的构建和调整以及数据的合并。所有这些任务通常被称为数据预处理。

一旦你在理解业务(或问题)和跟踪可用数据之间有了第一次互动,你的数据获取策略就会开始被定义。为此,我主要考虑两种可能的情况:

  1. 有对数据源的控制:你可以以某种方式管理和控制生成数据的源(传感器、仪表、人员、数据库等)。).以护士长的活动为例:他可以监督、审计、建立协议,并记录他所在病房的所有患者数据。重要的是要注意,控制是针对数据的来源或注册,而不是针对与数据相关的事件。
    这种场景通常发生在高度复杂或持续时间长的项目中,在这些项目中,数据模型已经建立,并且有方法确保其一致性和完整性。
  2. 没有对数据源的控制:这是在短期项目或偶尔感兴趣的项目中,以及在使用或要求来自其他来源的数据的项目、分析或常年研究中最常见的情况。无论采取何种举措,数据采集策略都必须更加可靠,因为任何超出其控制范围的变化都会增加分析成本,甚至导致项目不可行。
    我们自己的研究说明了这种情况:如果我们无法控制这些数据的产生和传播,如何获得巴西新冠肺炎病例的分层数量?

期望在企业和机构中,或者在领导纵向研究或制造过程时,找到第一个场景。否则,您可能需要处理第二个问题。在这种情况下,您的策略可能包括订阅、数据分配协议,甚至是在获得适当许可后从互联网上搜索和编译此类数据的技术。Web 抓取是这些技术中的一种,我们接下来会看到。

通过网络搜集获取数据:通过巴西卫生部的官方小组获取数据

随着目标的确立——巴西新冠肺炎病例的分层数量——我的第一个行动是寻找可能的来源。2020 年 4 月中旬我咨询了巴西卫生部门户网站。当时,我还没有找到统一的、容易获取的信息,所以我增加了可能来源的粒度:州和市卫生部门。在这种情况下,挑战在于他们呈现数据的方式的异质性。在咨询一名公共卫生工作者时,她告诉我,这些数据已经整合到国家公报中,具体的需求应该向机构提出。因此,我的第一个策略是设计一种自动收集此类公告(PDF 格式)并开始提取所需数据的方法——部分结果可在这个 GitHub 资源库中获得。

然而,在 2020 年 5 月初,我有一个令人不快的惊喜:在新闻公告中,我用来提取数据的表格(对于那些好奇的人来说,pdf plumb库是一个极好的工具)被数字所取代,这使得我的提取方法不可行。

我特意详细阅读了上述段落,原因很简单:再次展示 KDD 数据采集步骤固有的交互过程。此外,当我们承担一个我们无法控制数据源的项目时,我想强调风险和不确定性。在这种情况下,最好有其他选择,建立合作关系或协议,并寻求建立自己的数据集。

当我在寻找新的策略时,巴西卫生部开始将数据整合到一个 CSV 文件中,几天后将格式改为 XLSX,并每天更改文件名。在下面的段落中,我将详细说明我是如何针对这种新情况调整我的过程和代码的。

顺便说一句,从互联网上可用的页面和内容中自动检索数据和信息被称为 web 抓取。这项技术可以通过 Python 库轻松实现,如图 4 所示。

图 4。使用 Google Chrome 检查工具和 Python 语言简化网页抓取过程的步骤。

我们终于到了这篇文章的实际部分——也许是最令人期待的部分。按照图 4 中定义的步骤,我们首先(1)访问冠状病毒小组,以及(2)通过点击页面右上角的“Arquivo CSV”按钮,确定我们感兴趣的数据。当我们激活 Google Chrome 页面检查工具(3)时,我们会找到与 HTML 页面上的项目相对应的代码,如图 5 所示。记住,检查工具是由检查菜单激活的,当我们右击页面的任何元素时,或者通过快捷键 ctrl+shift+I

图 5。通过谷歌 Chrome 检查工具看到的巴西卫生部冠状病毒门户网站。

下一步(4)是从我们的 Python 代码中访问这些数据,这可以通过 Jupyter 笔记本、脚本或 IDE 来完成。在任何情况下,这个想法都是通过使用 Selenium 库来模拟对所需门户的访问以及与 web 页面的交互。

在下面几行中,我开始创建一个虚拟环境来访问 Google Chrome 模拟器中的门户网站 URL:

# Initial statements 
from pyvirtualdisplay import Display 
from selenium import webdriver # Parameters definition 
url = 'https://covid.saude.gov.br' # Starts the virtual environment: 
display = Display(visible=0, size=(800,600)) display.start() # Opens the Chrome emulator in the desired URL: 
driver = webdriver.Chrome() # Reads and gets the page content encoded in UTF-8: 
driver.get(url) page = driver.page_source.encode('utf-8')

一旦我们读取了页面,我们就进入图 4 的步骤(5 ),在这里我们重复这个过程,直到我们保证数据是我们想要的形式。为此,我们可以首先检查加载页面的大小(例如,如果它为空,则意味着出现了问题)及其前几行:

# What is the length of the loaded page? 
print(len(page)) # What is the data type? 
print(type(page)) # What is the content of the first positions of the byte stream? print(page[:2000])

大多数情况下,下一步将是使用被称为解析器的工具来探索 HTML 内容——beautiful soup库是一个优秀的 Python 解析器。在我们的例子中,考虑到我们感兴趣的数据不在 web 页面上,而是来自这个页面上的一个操作,我们将继续只使用 Selenium 方法来模拟按钮上的点击,自动下载缺省系统文件夹中所需的文件:

## Path obtained from inspection in Chrome: 
xpathElement = '/html/body/app-root/ion-app/ion-router-outlet/app-home/ion-content/div[1]/div[2]/ion-button' ## Element corresponding to the "Arquivo CSV" button: 
dataDownloader = driver.find_element_by_xpath(xpathElement) 
## Download the file to the default system folder: dataDownloader.click()

下一步是验证文件下载是否正确。因为它的名字不是标准化的,所以我们通过 glob 库列出了最近的文件:

import os 
import glob ## Getting the last XLSX file name: 
list_of_files = glob.glob('/home/tbnsilveira/Downloads/*.xlsx')
latest_file = max(list_of_files, key=os.path.getctime)
print(latest_file)

至此,网页抓取任务完成,同时我们进入数据准备阶段(如有必要,查看图 3)。

假设我们感兴趣的是每个州的病例数、人口数、死亡率(死亡人数与病例数之比)和死亡率(死亡人数与人口数之比)。下面的代码行执行提供所需信息所需的预处理任务。

## Reading the data 
covidData = pd.read_excel(latest_file)
covidData.head(3) ## Getting the last registered date: 
lastDay = covidData.data.max() ## Selecting the dataframe with only the last day 
## and whose data is consolidated by state 
covidLastDay = covidData[(covidData.data == lastDay) & 
(covidData.estado.isna() == False) & (covidData.municipio.isna() == True) & (covidData.populacaoTCU2019.isna() == False)] ## Selecting only the columns of interest: 
covidLastDay = covidLastDay[['regiao', 'estado', 'data', 'populacaoTCU2019', 'casosAcumulado', 'obitosAcumulado']]

预处理步骤通过从预先存在的数据生成一些附加特征来完成:

## Copying the dataframe before handling it: 
normalCovid = covidLastDay.copy() ## Contamination rate (% of cases by the population of each state) normalCovid['contamRate'] = (normalCovid['casosAcumulado'] / normalCovid['populacaoTCU2019']) * 100 ## Fatality rate (% of deaths by the number of cases) normalCovid['lethality_pct'] = (normalCovid['obitosAcumulado'] / normalCovid['casosAcumulado']) * 100 ## Mortality rate (% of deaths by the population in each state) normalCovid['deathRate'] = (normalCovid['obitosAcumulado'] / normalCovid['populacaoTCU2019']) * 100

从这一点出发,我们可以在预处理的数据库中进行搜索:

normalCovid.query("obitosAcumulado > 1000")

数据采集阶段到此结束。如果我们遵循 CRISP-DM 方法,下一步可能是构建模型、分析或可视化。为了说明这一 KDD 过程的可能结论,图 6 展示了一个四象限图,该图将巴西不同州的病例百分比与致死率相关联(生成该图的代码可在 GitHub 上获得)。

图 6。根据卫生部 2020 年 5 月 22 日发布的数据,巴西各州新冠肺炎病例数与致死率之间的关系。

上图是我们到目前为止所介绍的整个过程的结果:数据是通过网络搜集获得的,信息是通过处理数据生成的,知识是通过结构化信息获得的。亚马孙州是每个居民感染人数最多的州,也是死亡率最高的州。圣保罗州是累计死亡人数最多的州,但就其总人口而言,感染人数相对较低。

最终考虑

在本文中,我试图概述 KDD 过程以及如何使用 web 抓取技术实现数据采集,尤其是在小型项目或分析的情况下。

您可能想知道访问门户网站并简单下载那里的可用数据是否会更容易。是的,会的!然而,数据科学项目期望数据获取尽可能自动化,为预测分析提供空间,预测分析的模型需要每天或不断更新。此外,对于相对更简单的问题,理解复杂的主题并获得对我们技术的信心变得更加有效——或许还很有趣。

最后,我必须提醒你,在获取和处理数据时,一定要遵守道德规范。自动收集公共领域的数据,不需要行政费用,是一种完全合法的活动。然而,如果你对何时允许或不允许使用这种算法有疑问,请不要犹豫,向专家甚至数据所有者咨询。

原载于 2020 年 5 月 23 日http://tbnsilveira . info

基于 R 的 IMDb 刮削数据的数据分析与可视化

原文:https://towardsdatascience.com/data-analysis-and-visualization-of-scraped-data-from-imdb-with-r-5d75e8191fc0?source=collection_archive---------43-----------------------

极客(也不那么极客)喜欢的电视剧

电视剧数据可视化仪表盘,文末链接

当然,你和我一样,在一天或一周中的任何时候,利用这个休息时间来摆脱日常事务、工作和问题,只是放松一下,在流媒体服务上、电视上看你最喜欢的电视连续剧,或者掸掉旧 DVD 上的灰尘。

我们享受那些娱乐的时刻,无论是单独还是与人一起,我们可以沉浸在一个吸引我们、感动我们、让我们反思或娱乐我们的故事中。这些电视连续剧中有许多以离奇的告别告终,而在其他情况下,它们的结局很糟糕,惹恼了它们的粉丝。无论如何,很多事情的发生并不是每个人都能看到的。

在这种动机下,我们将对一些最受欢迎的电视剧(尤其是在极客文化中)进行数据可视化和分析:《黑镜》、《西部世界》、《权力的游戏》、《瑞克与莫蒂》、《奇人异事》。

IMDb 数据的准备和提取

IMDb(互联网电影数据库)目前有一个更新的和广泛的在线数据库,包含关于电视剧、电影等的信息。它还根据世界各地用户的意见和投票,为它存储的每个主题保存评级。

我们将使用一个有趣而简单的脚本来准备我们将要使用的数据集。这个脚本使用 rvest 包从 IMDb 网站执行 Web 抓取(一种用于以自动化方式从网站提取信息的技术),不需要深入研究这个主题,稍后再详细描述。你所要做的就是更新文件" series_urls.csv" ,在这里你可以添加连续剧、电影或者任何你想包含在 IMDb 中的东西的标题以及它的标识符(例如对于《权力的游戏》来说,它的 URL 是https://www . IMDB . com/title/tt0944947/,其中“TT 0944947”是我们所关心的)。

在这篇文章中,考虑到所选的电视剧,CSV 文件看起来像这样:

分析电视剧《IMDb》——要分析的电视剧

一旦定义了这个 CSV 文件,就可以在根文件夹中运行 R 脚本,对每个系列的所有数据进行 Web 抓取(更新到最新)。

解析电视剧《IMDb——运行网络抓取脚本》

我们将获得什么数据?那么,它将在【data】文件夹中生成一个新的 CSV 文件,该文件由每部电视剧的以下变量组成:

连续剧 _ 名称 < chr >电视剧名称
连续剧 _ep < int >剧集编号
季号
季 _ep < int >季号
网址 < chr > IMDb 网址为剧集
剧集 <
用户投票 < dbl >评分票数
r1 < dbl >评分为 1 分的用户比例

r10评分为 10 分的用户比例

本文在 Web 抓取后获得的 CSV 文件如下所示:

分析电视剧《IMDb—IMDb 1》网络抓取后获得的 CSV 文件

分析电视剧《IMDb—IMDb 2》网络抓取后获得的 CSV

我知道,我知道……现在你看着我问:对于这一切,你说了那么多的剧本在哪里,索尔?我只是想先弄清楚它是如何工作的,在分享之前,你可以在作者的资源库中找到:https://github.com/nazareno/imdb-series。现在你只需要下载、定制并在本地运行。

让我们开始处理数据

好了,用 R 开始一个新的脚本,现在我们有了数据集,是时候做一点分析了。我们将首先加载我们将使用的库,以及先前通过 Web 抓取获得的数据集的 CSV。

library(tidyverse)
library(plotly)
library(kableExtra)
library(knitr)theme_set(theme_bw())# CSV READING GENERATED BY IMDB WEB SCRAPING 
series_imdb <- read_csv("series_imdb.csv")# EN CASO DE HABER GENERADO UN DATASET MÁS GRANDE, FILTRAR SÓLO ALGUNAS SERIES DEL CSV COMPLETO
mis_series <- series_imdb %>% filter(series_name %in% c("Black Mirror", "Game of Thrones", "Rick & Morty", "Stranger Things", "Westworld")) %>%
  mutate(series_name = factor(series_name)) %>%
  mutate(season = factor(season))# TV SERIES AND COLUMNS PREVIEW
levels(mis_series$series_name)
colnames(mis_series)

现在,我已经从 5 部电视剧中获得了 189 个观察值和 18 个可用变量。

浅析电视剧《IMDb》——电视剧与控制台中的变量

我们准备好回答问题了。丹妮莉丝的龙有性别吗?狄摩高根会继续伤害人类吗?。不,不幸的是不是这些类型的问题,但我们将能够获得相关的数据和回答问题,如哪个系列更成功?最不成功的几季或几集是什么?

用户评级变量概述

在本分析中,我们将用来回答问题的一个变量是用户评级,在下文中理解为指定评级。让我们来看看 5 部电视剧集的收视率分布情况。

# GLOBAL USER RATING HISTOGRAM
mis_series %>%
  ggplot(aes(UserRating)) +
  geom_histogram(binwidth = .1, fill = "#0196d7") +
  scale_x_continuous(breaks = seq(0, 10, 1)) +
  labs(y = "Número de ocurrencias", x = "Calificación de episodio") + 
  ggtitle("UserRating general de las 5 series", "Black Mirror, Westworld, Game of Thrones, Rick and Morty y Stranger Things.")

用户评分是用 0 到 10 分来衡量的。我们将获得下面的情节,其中我们可以看到,在这五个选定的电视连续剧的情况下,8 到 9 之间的分数占主导地位。一开始就必须承认,选择的五个系列都是制作相当精良的电视剧。

分析电视连续剧《IMDb》——普通用户评分

收视率最高的电视剧就是票数最多的电视剧吗?

IMDb 提供了 UserVotes 变量,通过它我们可以发现投票数和每部电视剧获得的收视率之间是否存在关系。

# RELATION BETWEEN RATING AND VOTES PER TV SERIES
series_votos <- mis_series %>% group_by(series_name) %>% summarise(rating = median(UserRating), totalvotos = sum(UserVotes))
series_votos %>% 
  ggplot(aes(x = reorder(series_name, totalvotos), y = totalvotos, fill = rating)) +
  geom_histogram(stat = "identity") +
  scale_fill_distiller(name="Calificación", palette = "Blues") +
  scale_y_continuous(labels = scales::comma) + 
  coord_flip() +
  xlab("Serie") + ylab("Número total de votos") + 
  ggtitle("Calificación de cada serie", "Relación entre calificación y número de votos")

通过获得的直方图,我们发现虽然收视率最高的电视剧是票数最高的电视剧,但与此相反,收视率最低的电视剧并不完全是票数最少的电视剧。所以我们可以说总票数和收视率没有太大关系。

电视连续剧《IMDb》的收视率和投票分析

每部电视剧从头到尾的接受度如何?

为了回答这个问题,我们将使用折线图。中位数用于衡量评估,因为它不受平均值等极值的影响。

# ACCEPTANCE OF EACH TV SERIES BASED ON ITS SEASON RATING
series_acep <- mis_series %>% group_by(series_name, season) %>% summarise(rating = median(UserRating))
series_acep %>% 
  ggplot(aes(x = as.numeric(season), y = rating, color = series_name)) +
  geom_line() +
  geom_point() +
  scale_x_continuous(breaks = 1:10) +
  scale_color_brewer(name = "Serie", palette = "Set1") +
  xlab("Temporada") + ylab("Calificación") + 
  ggtitle("Evolución de la aceptación de cada serie", "Calificación por temporada")
ggplotly()

随着剧情的展开,我们可以看到每一部电视剧的悲惨衰落,尤其是《黑镜》和《权力的游戏》(也许有充分的理由,他们给了我们一个多么精彩的大结局,对吗?).

电视剧《IMDb》各季收视率和接受度分析

每章是如何演变影响每部电视剧的季收视率的?

这是一个也许你们很多人也会有的问题。嗯,我们会用每一季的方框图来验证,用它也可以看到每集的收视率汇总。

# SEASON RATING BY EPISODES
series_temp <- mis_series %>%
  ggplot(aes(season, UserRating, color = season)) +
  geom_boxplot() +
  geom_jitter(width = .2) +
  facet_wrap(~series_name) +
  labs(x = "Temporada", y = "Calificación de episodio", color = "Temporada") + 
  ggtitle("Evolución de cada temporada por capítulo", "Calificación por episodio")

获得的剧情会让我们更深刻、更悲哀地看到,比如《权力的游戏》的没落,以及一些因收视率低得多而脱颖而出的剧集。

分析电视剧《IMDb》——每部电视剧的季集收视率

所选电视剧最好和最差的几集是什么?

你肯定会有另一个大问题。我们可以根据按升序和降序排列的用户评级所获得的最低和最高评级来查看哪些是最好的和最差的剧集。

# TOP OF BEST AND WORST EPISODES BASED ON THEIR RATING
mejores_ep <- knitr::kable(x = head(arrange(mis_series, desc(UserRating)) %>%
      select(series_name, Episode, ,season, UserRating), 7),
      col.names = c('Serie', 'Episodio', 'Temporada', 'Calificación'))
kable_styling(mejores_ep, "striped", position = "left", font_size = 12)peores_ep <- knitr::kable(x = head(arrange(mis_series, (UserRating)) %>%
       select(series_name, Episode, ,season, UserRating), 7),
      col.names = c('Serie', 'Episodio', 'Temporada', 'Calificación'))
kable_styling(peores_ep, "striped", position = "left", font_size = 12)

需要注意的是,相比其他电视剧,《权力的游戏》的集数和季数都更多。很明显,它很可能会出现在收视率最高和收视率最低的剧集中。

分析电视连续剧《IMDb》—收视率最高剧集的表格视图

分析电视连续剧《IMDb》——收视率最差剧集排行榜

你怎么想呢?你同意获得的前 7 名吗?如果你很想看看前 20 名,除了看到用 plotly 产生的稍微有点花哨的情节,我还分享了我为这篇文章整理的flex dashboard:https://rpubs.com/cosmoduende/imdb-tv-series-analysis-r

在这里你还可以找到完整的代码,如果你想用你最喜欢的电视剧进行分析:https://github . com/cosmoduende/r-analisis-exploratorio-TV-series-IMDB

我希望你有一个非常快乐的分析,你可以体验把它付诸实践,你玩,并惊讶于非常有趣的结果。

应不讲西班牙语的人的要求,这篇文章被翻译成了英文,这些人在小组和论坛上问我是否愿意用英文发表这篇文章。

谢谢你,下次再见。

使用 Jupyter 笔记本进行数据分析和可视化

原文:https://towardsdatascience.com/data-analysis-and-visualization-with-jupyter-notebook-22f6dcd25cc5?source=collection_archive---------7-----------------------

用 JS 库可视化 Jupyter 笔记本中的数据

丰富的交互计算体验是我最喜欢 Jupyter 笔记本的地方。此外,这是一个完美的基于网络的环境,用于执行探索性分析。

在本教程中,我将展示如何使用两个作为 JavaScript 库提供的交互式数据可视化工具来支持项目的探索阶段。本指南将花费最少的时间和步骤来完成。

我认为数据报告应该易于理解,比分析本身花费的时间更少。这就是为什么,在没有添加任何扩展的情况下,我们将在最短的时间内为 Jupyter 笔记本内的报道建立一个工作环境。

希望由此产生的笔记本模板将帮助每个处理数据的人回答重要的特定领域的问题,并以可理解的形式呈现数据分析见解。

开始吧!

数据

作为一个数据样本,我们将使用 Kaggle 的世界幸福报告来探索数据的空间和时间趋势。

工具

  • JupyterLab —我们的环境。你也可以使用 Jupyter 笔记本
  • WebDataRocks 数据透视表

这个数据透视表将处理所有与数据相关的计算:聚合、过滤和排序数据。它的主要特点是交互性和易用性。此外,它将作为我们的仪表板的引擎,处理数据并以汇总的形式将其传递给图表。

  • 谷歌图表

由于我们的大脑对图表的反应更快,我们可以将表格数据表示与交互式图表结合起来。为此,Google Charts 是一个不错的选择。这个 web 服务提供了所有的基本图表,这些图表可以根据我们的需要进行定制。

关键想法

让我们将本教程分解为构建数据报告解决方案的几个关键步骤:

  • 导入所需的库
  • 数据准备
  • 在笔记本中嵌入数据透视表和图表
  • 将数据发送到表
  • 配置报告
  • 将数据从表格发送到图表
  • 保存报告
  • 保存并共享笔记本

步骤 1:导入 Python 库

让我们弄清楚每个库代表什么功能:

1.IPython . display—IPython 中显示工具的 API

  1. json —用于序列化和反序列化 Python 对象的模块。

3.熊猫——数据处理和分析的主要图书馆

第二步:获取数据

首先,这一步取决于您如何存储和访问您的数据。

我使用 Google Sheets 将几个 CSV 文件中对应于各个年份的数据记录合并在一起。使用本教程中描述的方法,我将数据从 Google Sheets 导入到 pandas dataframe。

或者,您可以简单地使用 read_csv() 方法从文件系统导入数据。要合并几年的信息,可以使用“ concat 操作。

让我们看看我们的数据是什么样子的:

现在已经使用最适合您的方法将数据加载到 dataframe 中,使用指定的“records”方向将其转换为 JSON。生成的类似列表的结构是数据透视表理解的数据格式:

步骤 3:创建一个数据透视表,并向其输入数据

接下来,使用指定的报表配置定义数据透视表对象:

以下是我们到目前为止的配置:

  • 一个数据片——我们希望在网格上呈现的字段的子集。
  • 一个数据源及其类型。使用 json.loads()方法,我们将包含 json 文档的字符串反序列化为 Python 对象。
  • 可选视图相关设置:条件格式数字格式

接下来,让我们将 Python 字典表示的数据透视表转换为 JSON 格式的字符串:

步骤 4:以 HTML 呈现数据透视表和图表

最重要的一步来了。

让我们定义一个函数,它将在笔记本单元格中呈现数据透视表和图表。

这里,我们已经指定了 HTML 布局,它包含 Google Charts 和 WebDataRocks 的脚本、CSS 样式以及将呈现数据透视表和图表实例的容器。整个布局用三重引号括起来。

此外,我们传递一个参数,它代表执行定制的 JavaScript 代码。在这段代码中,我们实现了应该如何以及何时绘制图表的逻辑。只有当数据透视表完全呈现、加载了数据和本地化文件时,才会出现这种情况。我们可以通过“ reportcomplete ”事件来跟踪这一时刻。

下面的代码完成了从表中获取数据、创建图表以及将汇总数据传递给图表的所有繁重工作:

最后,让我们调用渲染函数并查看生成的仪表板:

结果

如您所见,数据透视表填充了数据,字段根据我们设置的报表规则显示和格式化。

请注意,仪表板本身是交互式的:您可以使用报告工具的不同元素,在网格上分割数据记录,对它们进行过滤和排序。此外,图表会对报告中的每个变化做出反应。

下一步是什么?

现在,您有了一个报告工具,可以从多个角度查看数据。花些时间探索数据:更改跟踪的指标,过滤数据。尝试添加其他可视化图表。

你可以尝试其他数据集,寻求真知灼见。我希望您会喜欢这个过程和结果,并通过这种方法提高您的笔记本电脑工作效率。完成数据分析后,保存笔记本并与朋友或同事分享。讲述你的数据故事。他们会喜欢的!

参考

网络安全 101 的数据分析:检测横向移动

原文:https://towardsdatascience.com/data-analysis-for-cyber-security-101-detecting-lateral-movement-2026216de439?source=collection_archive---------18-----------------------

这是一系列博客文章的第二部分。第一个可以在数据渗透上看。

这篇博文的结构如下:

  1. 介绍横向运动 (4 分钟):一个玩具例子来说明什么是横向运动
  2. 网络异常检测 (7 分钟) : 统计和机器学习技术检测横向移动
  3. CTF 挑战 (3 分钟) : 解决3 CTF 挑战关于寻找横向运动
  4. 违规报告 (4 分钟) : 真实的例子以及我们可以从中学到什么
  5. 可见度和传感器优势 (3 分钟) : 检查您的数据质量和可见度
  6. 黑暗空间和蜜罐 (2 分钟) : 要做的事情让检测横向移动变得更容易

前提

好看!您已经成功地检测并阻止了 数据泄露 ,但战斗还远未结束。我们仍然怀疑有坏人潜伏在你的网络中。作为一名负责任的网络安全管理员,你开始搜寻。 利用网络流量数据搜寻更多异常安全事件。

妥协的假设

作为一名网络安全管理员,一种健康的心态是假设您已经受到威胁,这样,您的目标就是找到对手的利用后活动的证据。

请记住,利用只是攻击者的第一步,他们还需要采取额外的步骤来实现他们的主要目标。

回想一下之前的博文,在最初的妥协之后,为了窃取你的数据,攻击者需要经历以下步骤:

(1)攻击者需要使用一些命令和控制(C2)通道与他们的立足点进行协调。

(2)使用 C2,攻击者需要通过网络导航和横向移动来到达数据

(3)一旦攻击者获得了数据,攻击者需要将这些数据从网络中泄漏出去。

在这篇博文中,我们将介绍一些检测横向移动的简单方法,以及一些关于如何设计可防御和可监控系统的注意事项,以便我们能够持续防御我们的网络。**

横向运动

玩具案例研究

当攻击者成功入侵主机时,很可能主机没有必要的凭证、权限和网络访问权来获取公司的机密数据。在这种情况下,攻击者必须利用他们现有的立足点来获得更高级别的访问权限。

在我们更深入地检测横向运动之前,让我们使用一个玩具案例研究,以便我们可以“描绘”到底发生了什么。

我们的网络中有两个主要部门:

  • 人力资源部:打开大量来自求职者的随机电子邮件。他们只能访问内部电子邮件服务器。
  • IT 团队:管理生产数据库和员工桌面

人力资源员工是坏人更容易攻击的目标,但是,即使人力资源员工被诱骗打开恶意 PDF,让攻击者访问人力资源机器,这种访问也不会立即让他访问生产数据。那现在怎么办?

下面,我们举例说明我们的玩具案例研究,以及攻击者如何能够在内部进行转换,以便最终能够访问生产数据。

玩具示例,从电子邮件到生产数据库

  1. 攻击者向发送了一封伪造的求职电子邮件,HR 打开了附件中的简历。这原来是一个恶意的 PDF** ,它帮助攻击者使用反向 shell 在 HR 子网中建立立足点。**
  2. 通过强力攻击,攻击者获得了 HR 机器的本地管理员凭证,并能够提升他的权限。
  3. 不幸的是,所有机器都有相同的本地管理员证书。使用这些凭证,他能够转到 IT 组子网中的主机。****
  4. ****通过 IT 组主机的隧道,他能够访问所有生产服务器。

我们如何检测这种横向运动?有些事情上图没有显示出来。想想攻击者是如何发现他所使用的不同帐户、主机和服务的。

主机发现 [1]

“我可以使用这台人力资源机器访问什么?”

在上述第 2 步和第 3 步之间,坏人必须以某种方式知道他可以转到 IT 子网中的哪个 IP 地址。他是怎么找到这个 IP 的?

一种方法是通过扫描可访问的 IP 进行网络扫描。如果扫描结束时枚举了子网中的所有主机,这可能会产生噪声,很容易被检测到。

****这种情况的一个迹象是一个单一的源主机试图建立到许多目的主机的连接。这是在 TCP、UDP 和 ICMP 中。

另请注意,在扫描可访问的主机时,防火墙可能不允许某些连接。如果您的防火墙记录这些放弃的尝试,那么这将为我们提供另一种检测网络扫描的方法。另一个危险信号是当防火墙丢弃来自单个源主机的大量不同连接时。****

****在某些情况下,单一掉线也是一个危险信号,尤其是在网络设置良好的情况下。例如,如果一个生产 web 服务器试图连接到一个内部主机,但被防火墙规则丢弃,可能会发生一些奇怪的事情。

服务发现【2】

“这是数据库吗?还是 web 服务器?”

现在,攻击者知道他可以到达哪些主机,下一个问题可能是,他们有什么服务?在第 3 步和第 4 步之间,攻击者可能首先发现在端口 5432 上运行着一个服务,这就是为什么他认为它可能是一个 PostgreSQL 服务器。

发现公开的正在运行的服务包括通过端口扫描尝试找到主机的开放端口。根据攻击者的目标,这也可能非常嘈杂。

默认情况下,nmap 扫描每个协议的 1000 个“感兴趣的”端口 [3】。然而,攻击者可能会选择扫描所有的 65535 端口,这将更加嘈杂。或者,攻击者可能更隐蔽,选择只扫描他关心的几个端口,例如用于 NetBIOS 服务扫描的端口 139 和 445。

对于更隐蔽的端口扫描,这更接近于寻找主机扫描的迹象。

对于有噪声的端口扫描,我们正在寻找试图连接到许多目的端口的源。相关日志是网络流日志或防火墙日志。

如果您为此设置了警报,您首先应该找到的是您的漏洞扫描器。如果你没有发现这些,那么你就是做错了。

端点到端点连接

您应该在网络中看到的最常见的连接是从一个端点到一个服务器或从一个服务器到另一个服务器。端点之间相互对话并不常见,从服务器到端点的连接就更不常见了。(尤其是当您不希望员工创建自己的文件共享时。)

端点到端点的良性连接的一个例子是从它到网络上不同主机的连接。这可能是为了维护或更新。

IT 机器与 HR 机器对话可能是正常的

然而,HR 机器直接与 IT 机器建立连接可能是不正常的。

HR 机器连接到 IT 机器可能不正常

你对你的网络了解得越“深入”,你就越能缩小可能异常的连接类型,以及哪些是真正重要的。

在 toy 示例中,我们可以为从 HR 机器到除电子邮件服务器之外的任何其他主机的任何连接尝试设置警报。我们甚至可以阻止 HR 与除邮件服务器之外的任何内部主机的任何连接。

网络异常检测

到目前为止,我们讨论的方法都是基于签名的。基于我们确定的横向移动可能如何发生的机制,我们定义业务规则并将它们编码为警报。有了这些,我们能够将尽可能多的领域专业知识和背景融入到我们的警报中。如果处理得当,这些可以为我们提供具有良好信噪比的警报。

尽管这些类型的规则对于保护我们的网络是必要的,但是它们可能不足以适当地保护我们的网络,因为:

  1. 网络复杂性的增长速度远远超过安全团队增加的人力
  2. 企业网络不是静态的,需要持续的监控和重新建立基准
  3. 业务规则在检测新型攻击方面不够稳健

如果您的网络相对较小,那么您可以使用基于规则的警报,因为您可以描述所有您期望看到的正常连接,并为那些您认为不正常的连接创建警报。这些主机应该只与 DNS 和代理服务器通信。此服务器应该只连接到此数据库。只有这些特定的主机应该连接到生产数据库……

然而,随着您的网络变得越来越大、越来越复杂,跟踪所有这些变得几乎不可能。这就是为什么我们想探索一些网络异常检测技术。

****假设是恶意主机会偏离典型行为。如果我们能够以某种方式自动捕捉“正常”的特征,那么希望我们能够通过筛选“异常”来捕捉恶意活动。

定义和模拟“正常”的好方法是一个正在进行的研究领域。在这篇博文中,我们将主要关注两种方法:

  1. 发现宿主行为特征中的异常值。
  2. 通过新的边/链路预测发现意外连接

主机行为特征中的异常值

这里的想法是将主机在给定时间间隔内的行为总结到一个向量中。有了所有这些主机矢量,我们就可以识别出与网络其余部分格格不入的主机。

特色工程

最重要的第一步是为网络中的每台主机构建功能。

我们应该得到什么特征?这取决于您能得到什么,以及您所在组织的安全领域专家有什么建议。

首先,我们来看看论文[13]使用了什么特征。他们总共使用了 23 项功能:

  • RDP 特色:SuccessfulLogonRDPPortCount,UnsuccessfulLogonRDPPortCount,RDPOutboundSuccessfulCount,RDPOutboundFailedCount,RDPInboundCount**
  • ****SQL 特性:UnsuccessfulLogonSQLPortCount、SQLOutboundSuccessfulCount、SQLOutboundFailedCount、SQLInboundCount
  • ****成功登录功能:SuccessfulLogonTypeInteractiveCount、SuccessfulLogonTypeNetworkCount、SuccessfulLogonTypeUnlockCount、successfullogontyperoteractivecount、SuccessfulLogonTypeOtherCount
  • ****未成功登录功能:UnsuccessfulLogonTypeInteractiveCount、UnsuccessfulLogonTypeNetworkCount、UnsuccessfulLogonTypeUnlockCount、unsuccessfullogontyperemoteeinteractivecount、unsuccessfullogontypoethercount
  • 其他: NtlmCount,DistinctSourceIPCount,DistinctDestinationIPCount

[14]中的其他特征示例有:

  • 过去 24 小时内是否至少有一个地址验证失败
  • 给予用户访问网站的 IP 地址的最大异常值
  • 从登录到结账的最短时间
  • 用户在过去 24 小时内访问网站的不同位置的数量。

有了这些特征向量,我们可以构建一个矩阵,并开始使用离群点检测技术。

主成分分析

我们从使用主成分分析【15】寻找异常值的经典方法开始,因为在我看来这是最直观的。

简单来说,你可以认为 PCA 是一种压缩和解压缩数据的方法,其中压缩过程中的数据丢失被最小化。

由于大多数数据应该是正态的,因此 PCA 的低秩近似将集中于正态数据。PCA 在异常值的情况下表现如何?

由于离群值不符合其余数据的相关结构,因此这些数据将具有较高的重建误差。一种形象化的方法是将“正常数据”视为网络的后台活动。

下面我们从 fast.ai [12]的数值线性代数课程中看到一个更直观的例子。他们从视频的不同帧中构建了一个矩阵。左边的图像是视频的一帧。中间的图像是使用鲁棒 PCA 的低秩近似。右边的图像是差异,重建误差。

fast . ai 的鲁棒 PCA 背景去除示例 [12]

在上面的例子中,视频的“主题”通常出现在重建误差中。同样,我们希望异常的宿主能从背景中突出出来,并具有较高的重建误差。

注意:经典的主成分分析可能对异常值敏感(不幸的是),因此使用[12]中讨论的健壮主成分分析可能更好

自动编码器

我不会详细介绍自动编码器,但是您可以将自动编码器视为 PCA 的非线性版本。

神经网络的构建使得中间存在信息瓶颈。通过迫使网络通过中间的少量节点,它迫使网络优先考虑最有意义的潜在变量,这就像 PCA 中的主成分。

类似于 PCA,如果自动编码器是在正常数据上训练的,那么它可能很难重构异常数据。重建误差可以用作“异常分数”。

PCA 和 autoencoder 是[14]用来以无人监管的方式检测恶意主机的一些组件。

隔离林等方法

发现异常主机的另一种流行方法是使用隔离森林,这种方法比其他方法表现更好[13]。就像许多基于树的算法一样,这可以处理数值和分类数据,并且对数据的分布和形状没有什么假设。

最后,我们希望使用我们的历史数据来学习一个可以帮助我们区分正常和不正常的函数。

使用 Py OD [16]从不同方法中学习到的示例决策边界

如果你想探索不同的离群点检测方法,我推荐你浏览一下PyOD【16】和他们引用的实现算法和论文。

如果你有兴趣了解更多这方面的知识,我推荐你观看异常检测:算法、解释、应用【17】。

新边缘/链路预测

这是对[11]的过度简化

不像以前的方法,我们试图找到恶意主机。在这里,我们试图找到异常边,其中边是客户端和服务器之间的连接,或者是源和目的地之间的连接。源/客户端也可以是用户名,边代表认证。

现在假设这是我们第一次看到这个边缘。我们可能会问,观察到这个新边缘的概率有多大?

对于上面的函数,我们需要客户端和服务器都有某种表示。我们可以有分类协变量,例如:

  • 主机的子网
  • 主机的类型(端点或服务器)
  • 用户的职务
  • 用户的位置

有了分类协变量,用二进制指示变量表示,我们可以使用源和目的地的相互作用来了解新边的可能性有多大。

获取源和目的地的嵌入

表示主机的另一种方式是生成某种嵌入。

让我们从历史数据中说,我们以前已经观察到以下优势。主机在某些连接中可以是源,在另一些连接中可以是目的。

由此,我们可以构建一个邻接矩阵,其中每个单元代表一条可能的边,而被观察到的边的值为 1。

邻接矩阵来自

使用这个矩阵,我们可以执行一些非负矩阵分解。这是我们在其他应用中看到的,比如推荐系统和协同过滤。通过因式分解,我们能够得到源和目的地的嵌入。

链接预测

文件[18]显示了如何能够因子分解,同时纳入分类协变量。这是通过泊松矩阵分解(PMF)完成的。

在估计嵌入和一些必要的系数之后,我们可以估计观察到新边缘的可能性。

PMF 模型下的概率函数【18】

我希望您对我们正在尝试做的事情有一个高层次的了解,但是当然,以一种计算高效的方式估计α、β和ɸ的值是问题的关键。详细可以看【18】还有。另一篇也是关于边缘预测的论文是[11]。

如果你对统计学在网络安全中的更多应用感兴趣,我建议你去看尼克·赫德的演讲网络安全中的数据科学和相关的统计挑战【19】。

CTF 挑战

以下是针对横向运动的 2019 趋势科技 CTF 中通配符 400 挑战的(很晚)部分演练。在这里尝试挑战,解决方案可以在这个内核中找到。

这里的数据是合成的,不模拟典型的网络协议和行为。因此,这些挑战不需要深入了解网络协议。

横向蛮力

问题 9:一旦一台机器被弹出,它通常被用来探索还能到达什么地方。一台主机被用来大声探测整个企业,试图找到企业中所有其它主机的方法。它的 IP 是什么?

我们看到主机正在扫描整个网络。这可能意味着我们在寻找主机扫描的迹象。

要做到这一点,我们需要获得具有许多唯一目的 IP 的源 IP 地址。

这里很明显13.42.70.40正在扫描并试图横向移动。为了完整起见,我们查看了它的网络活动,发现在非工作时间进行扫描会导致网络活动激增。

未节流的扫描噪音很大,会产生大量流量。因此,如果攻击者不试图隐藏他们的网络扫描,这是我们希望看到的。

横向间谍

问题 10:一台主机试图找到一条更安静地连接其他主机的途径。它的 IP 是什么?

这是一个更棘手的问题。排除 13.42.70.40 之后,很难找到任何其他主机在唯一目标 IP 或目标端口数量方面表现突出。

于是,下面的情节就没用了。坏主机正在与正常主机的后台活动融合在一起。

****

我们必须找到一种更有创造性的方法来发现扫描活动。如果我们有更多的网络背景,那么我们可以专注于:

  • 连接到网络中未使用的端口
  • 到端点的连接

这是我们从网络基线中了解到的情况,但我们的网络中没有这种环境。为了推断哪些端口是“正常的”,我们假设如果多个源主机连接到一个特定的 IP 地址和端口,那么它可能是正常的。

给定目标 IP 和端口的源 IP 列表

例如,我们看到多个主机连接到12.37.117.51:56,那么这可能是一个正常的连接。

对于12.32.36.56:68,我们看到只有12.49.123.62试图连接到它。这大概是不正常的。

过滤掉正常的目的 IP 和端口后,剩下的唯一源主机就是12.49.123.62。这是我们的烂 IP。

奖金(可选):内部 P2P

问题 5:有时我们的低度感染在其他方面也是可见的。一种特殊的病毒已经在许多机器中传播,这些机器现在被用来相互传递命令。恶意软件创建了一个内部 P2P 网络。在所有相互通信的主机中,最大的内部集团使用哪个唯一端口?

这与检测横向移动有关,但解决方案涉及使用图论中的分析技术。

这个问题很简单,因为这个问题直接问最大的集团。集团是一组彼此都有联系的主机。

每个圈都是网络中的一个主机。如果两个主机彼此有连接,我们在它们之间放置一个端点。

使用 NetworkX ,通过枚举所有派系并找到最大的一个,就可以得到确切的答案。然而,这并不能很好地扩展。

我们选择使用快速近似方法 large_clique_size(G)

**G = networkx.Graph()
G.add_nodes_from(internal_nodes)
for l, r **in** zip(internal_edges.src, internal_edges.dst):
    G.add_edge(l, r)        

_size = large_clique_size(G)**

使用上面的代码,我们可以获得特定端口的大集团,但这对于所有端口来说运行起来太慢了。为了加速搜索,我们过滤掉最大团保证很小的端口。

很容易证明,如果图G中存在一个规模为K的团,那么G中至少应该存在K个度大于或等于K-1的节点。鉴于这一事实,我们可以计算每个端口的团大小的上限。完成这项工作的代码在解决方案内核中。

这些是具有最高上限的端口

处理这些端口我们发现端口 83 有一个 264 的最大团。

违规报告

在这一节中,我们将回顾以前数据泄露造成的历史“灾难”。

2018 SingHealth 数据泄露 [5]

2018 年新加坡健康数据泄露事件中,新加坡卫生服务部门的 150 万名患者的数据被盗。这个事件最接近我们的玩具案例研究。

SingHealth 数据泄露事件报告中关键事件的图解摘要[5]

简而言之,关键事件包括:

  1. 尽管报告中并不清楚这是如何发生的,但我们知道攻击者能够通过网络钓鱼攻击在的*工作站上安装恶意软件。*****
  2. 通过访问工作站 A,攻击者能够危害多个端点和服务器。根据报告,攻击者可能已经侵入了 Windows 身份验证系统,并从域控制器获取了管理员和用户凭据。
  3. 最终,攻击者能够控制工作站 B,这是一个可以访问 SCM 应用程序的工作站。有了它,攻击者能够找到适当的凭证来破坏 SCM 系统****
  4. 在 SCM 数据库上运行了大量查询
  5. 通过工作站 A** 对数据进行了过滤**

以下是报告中确定的一些促成因素。

SGH 思杰服务器和配置管理数据库之间的网络连接是允许的。

允许 Citrix 服务器场与 SCM 数据库服务器之间的网络连接。对网络体系结构的基本安全审查可能已经表明,这种开放的网络连接产生了安全漏洞。

如果这两个系统是隔离的,攻击者就不能轻易地访问 SCM 数据库。

根据该报告,在两个系统之间保持这种开放网络连接的原因之一是为了提高操作效率。管理员希望能够使用 Citrix 服务器和安装在那里的工具来管理不同系统的多个数据库。

SGH 思杰服务器未能充分防范未经授权的访问

这里的许多因素都与身份验证和凭证管理有关,这超出了本文的范围。现在与我们相关的一个问题是,缺乏防火墙来防止使用 RDP 对 SGH Citrix 服务器进行未经授权的远程访问。

2018 年美国宇航局 JPL 违规事件【6】

2018 年美国宇航局 JPL 漏洞因标题为“美国宇航局因未经授权的树莓派被黑”而闻名。最终报告没有详细说明最初的进入点是什么,攻击者是如何获得树莓 pi 的访问权限的,以及树莓 pi 位于何处。

我觉得有趣的是发现“与外部合作伙伴共享的网络环境分割不充分”。****

应该限制第三方对内部网络的访问

****JPL 建立了一个网络网关,允许外部用户及其合作伙伴,包括外国航天局、承包商和教育机构,远程访问特定任务和数据的共享环境。然而, JPL 没有适当地隔离各个合作伙伴环境以将用户限制在他们已经批准访问的那些系统和应用……2018 年 4 月事件中的网络攻击者利用 JPL 网络缺乏分段性在连接到网关的各种系统之间移动,包括多个 JPL 任务操作和 DSN。

横向流动可能导致跨组织的访问。对外部各方实施严格的信任边界,并确保将他们对您网络的访问仅限于必要的连接。外部各方可能不像您的组织那样具有安全态势,并且可能是薄弱环节。确保微调您的 IDS 或 IPS,将来自这些子网的流量视为外部流量。

2017 年 Equifax 数据泄露 [7]

2017 年的 Equifax 泄露是一次数据泄露,导致大约 1.43 亿美国消费者的数据泄露。

切入点是 ACIS 应用程序,该应用程序没有为现在著名的关键 Apache Struts 漏洞打补丁。利用该漏洞,攻击者能够获得服务器上的 web 外壳并运行任意命令。

鉴于货物信息预报系统服务器已经受损,最好是将攻击的影响仅限于货物信息预报系统。网络或主机防火墙会阻止对外部资源的访问。

网络分割限制了爆炸半径

不幸的是,根据报告,Equifax 网络是平坦的!这是最坏的情况,因为任何主机的危害都可能导致网络中任何主机的危害。

扁平网络使得攻击非常高效

安全问题 1。在 Sun 应用服务器和 Equifax 网络的其余部分之间没有分割。从互联网获得应用服务器控制权的攻击者可以在全球范围内转向[Equifax]网络中的任何其他设备、数据库或服务器** …如果攻击者利用扁平、未分段的网络突破组织的网络边界,他们可以在整个网络中横向移动,并获得对关键系统或重要数据的访问权限。**

通过远程访问 ACIS web 服务器,攻击者能够:

  1. 装载包含未加密应用程序凭据的文件共享
  2. 在 51 个不同的数据库上运行 9,000 个查询。
  3. 泄露所有数据

具体来说,货物信息预报系统只使用了 3 个数据库,但可以通过网络访问 48 个不相关的数据库。如果货物信息预报系统被隔离在相关的数据库中,那么这个漏洞就不会那么严重。

网络分段

我们在所有不同的漏洞中看到的一个共同主题是,网络分段在防止横向移动方面起着重要作用。

如果网络被适当地分段,爆炸半径被限制在特定的系统内,攻击者将很难在网络中穿行。

然而,对于传统网络,非常精细的分段可能成本过高,并且您可能会受到网络物理拓扑的限制。但是对于云部署,因为一切都是虚拟化的并且可以自动化,我们可以将微分段应用到我们的系统中【4】。您可以基于每个工作负载隔离机器,而不是基于每个网络。

能见度和传感器优势

在设置警报和规则之前,您需要做的一项重要工作是检查您实际收集的日志。你和你的团队必须清楚你的可见性极限是什么。

  • 我从哪些数据源收集日志?
  • 我在每个数据源中启用了哪些类型的日志?
  • 我的数据源/传感器实际“看到”了什么?
  • 我测试过吗?

我从哪些数据源收集日志?

检查您从哪些数据源收集数据。

对于传统的内部部署,您可以列出来自您的设备和供应商的所有常用内容,包括 DNS、DHCP、Active Directory、防火墙、代理、SQL 等。也可以查一下安全洋葱。它是免费的,你可以利用围绕它发展起来的社区的知识和工具。

对于云部署,确保您正在收集您在云提供商中使用的关键服务的审计和访问日志。另外,收集网络流量日志。

我在每个数据源中启用了哪些类型的日志?

默认情况下,有些数据源不会保存所有必要的日志,您需要打开它。

您可能会发现,由于配置错误,一些防火墙规则没有被记录。“我关闭了 X 的所有日志记录,因为它正在填满磁盘。”

例如,在谷歌云平台中,防火墙日志、VPC 流日志和 GCS 数据访问日志在默认情况下是不打开的。

我的数据源/传感器实际“看到”了什么?

传感器的优势描述了传感器能够观察到的数据包。优势是由传感器的位置和网络的路由基础设施之间的相互作用决定的[8]。

并非所有连接对我们的传感器都可见

对于我们的玩具用例,可能是同一子网内的连接不需要通过防火墙。如果我们分析防火墙日志,我们看到的唯一连接来自两个不同子网中的主机。

一些企业可能有单独的外围防火墙和内部防火墙设备。假设您只从外围防火墙收集日志,那么很可能任何内部到内部的连接都不会出现在您的 SIEM 上。

小心这个。你必须知道你的盲点在哪里。使用不能让您充分了解网络的日志会给您一种虚假的安全感。你可能认为没有人在扫描网络,而事实上,有,只是你没有看到它!

对于云基础设施,这取决于您的云服务提供商能为您提供什么。因为一切都是虚拟化的,所以您不再受网络物理拓扑的限制,并且有可能在整个 IaaS 中实现统一的可见性。但是如果你使用 PaaS,特别是对于 SaaS 来说,你对得到什么样的日志有更少的控制。

我测试过吗?

确保您的数据源正在工作并且您正在获取日志的唯一方法是测试它!

根据您的威胁建模制定几个简单的场景并进行模拟。尝试在不同的子网上实际运行网络扫描,或者尝试使用某些 honey 凭据。看看这些是否会生成您想要的日志和警报。看看你的新机器学习模型是否会检测到这一点。

运行模拟时,您可以从日志收集、数据转换、SIEM 接收、规则和警报,甚至调查和事件响应等方面对您的检测系统进行端到端测试。

它还将让您有机会捕捉数据源失败或配置错误的实例。也许服务停止了,它的存储空间被填满了,或者它的许可证过期了。可能是防火墙配置的更改无意中禁用了一组防火墙规则的日志记录。

不要因为没有收到 NIDS 或 DLP 的警报就认为一切正常;如果 NIDS 主机在 3 个月前被意外关闭了呢?

Equifax 没有看到数据泄漏,因为用于监控 ACIS 网络流量的设备由于安全证书过期而已经停用了 19 个月。[7]

测试测试测试!

黑暗空间和蜜罐

这里有些东西可能对那些拥有更成熟的网络和安全状况的人有用。

暗区

未使用的地址或端口号称为暗空间,合法用户很少尝试访问暗空间。大多数用户不手动输入 IP 地址,通常依赖 DNS 或应用程序为他们连接。另一方面,当攻击者试图横向移动时,很可能最终会访问它们[8]。

我们可以对试图进入这些黑暗空间的内部主机发出警报。这可能很吵,但在某些情况下很容易调查。该警报的一个常见原因是地址错误或配置错误。

根据[8],这里有一些事情你可以做,使攻击者更有可能进入黑暗的空间,使它更容易被检测到:

  • ****重新排列地址:大多数扫描是线性/顺序的,重新排列地址使它们均匀地分散在网络中,或者在网络中留下大片空白是一种创造黑暗空间的简单方法。
  • ****移动目标:如果分配给一个服务的端口是非标准的,攻击者只有在枚举更多的端口后才能找到它,使它们更加可见。当然,这是有代价的,因为过多地改变端口可能会让每个人感到困惑。

蜂蜜制品

蜂蜜的事情类似于黑暗空间,我们不期望这些事情出现在我们的日志中。

与黑暗空间不同,这些东西确实存在于我们的网络中,但它们没有任何合法用途。正式员工不知道这些,也不应该需要使用或接触这些。另一方面,攻击者可能会在网络中移动时遇到这些东西,如果这些宝贝看起来有价值或有用,他们可能会尝试用它们做些什么。

这些例子有:

  • 蜂蜜证书:
  • 蜂蜜代币
  • 蜂蜜文件共享
  • 蜂蜜服务器

我们希望它们看起来有价值,一旦这些出现在我们的日志中,我们就会进行调查。蒂姆·梅丁在他最近的网络直播“ 肮脏的防御,做得极其便宜:让我的生活更艰难让你的生活更轻松【9】中对此进行了更详细的讨论。****

其他人

这是相关的,但我只会简单地提一下(因为这篇博文已经够长了,抱歉)。

虽然 NIDS 和 NIPS 有时部署在外围。如果位置和配置正确,它们可以帮助检测横向运动。它将能够检测网络上的客户端漏洞、可能的文件传输和不常见的未授权网络协议的使用。您还可以使用 NIDS 来检测网络上明文传输的蜜糖令牌。

检查它是否配置为忽略内部到内部的连接。

接下来:指挥与控制,信标

我们仅仅触及了表面。您可以使用诸如 Active Directory 之类的日志进行更深入的研究,以便更精确地搜索横向移动,但是我们现在必须继续。

在下一篇博文中,我们将讨论一些关于寻找命令和控制证据的问题。****

攻击者需要能够控制他们的立足点,以便在您的网络中导航。就像他们说的,杀一条蛇砍下它的头。

参考

[1] Nmap 参考指南,第 15 章,主机发现。

[2] Nmap 参考指南,第 15 章,服务和版本检测

丹尼尔·米斯勒,秘书。

[4] CSA 安全指南(v4),7.3.3 微分段和软件定义的边界。

[5] 调查委员会对新加坡医疗服务数据库网络攻击的公开报告。

喷气推进实验室的网络安全管理和监督。

[7]Equifax 数据泄露。

[8] M. Collins,通过数据分析实现网络安全(2014 年)

肮脏的防御,廉价的交易:让我的生活变得更艰难,让你的生活变得更轻松。

安全洋葱

[11] 梅泰利,s .,赫德,N. (2019)。计算机网络中的贝叶斯新边缘预测和异常检测。

[12] Rachel Thomas,Fast.ai 数值线性代数,第 3 课:鲁棒 PCA 背景去除。

[13] Siddiqui,Md Amran 等人,“使用异常检测和解释以及专家反馈来检测网络攻击。”

[14] Veeramachaneni,Kalyan 等人,《AI^ 2:训练大数据机器进行防御》

【15】徐美玲等.一种基于主成分分类器的新型异常检测方案.

PyOD:一个用于可伸缩异常检测的 Python 工具箱。

[17] 托曼·迪特里希。异常检测:算法,解释,应用。

帕西诺、弗朗切斯科·桑娜、梅丽莎·JM·特科特和尼古拉斯·a·赫德。"使用泊松矩阵分解的计算机网络中的图链接预测."

[19]尼克听说了。网络安全和相关统计挑战中的数据科学

照片由来自佩克斯阿尔特姆·萨拉宁、来自佩克斯丹尼斯·尤丁、来自佩克斯伊格纳西奥·帕莱斯、来自佩克斯汤姆·斯温嫩、来自伊戈尔·戈里亚切夫乌斯普拉什埃莉诺拉·帕特里科拉

MySQL 中的数据分析——关系数据库中的运算符、连接等

原文:https://towardsdatascience.com/data-analysis-in-mysql-operators-joins-and-more-in-relational-databases-26c0a968e61e?source=collection_archive---------5-----------------------

【Craig Dickson 的 SQL 教程

学习使用 SQL 和免费开源软件创建、更新和查询您自己的全功能关系数据库——第 3 部分

我们的国际语言学校数据库的实体关系图(ERD)

这是一个由 3 部分组成的系列文章的第 3 部分,从零开始,带您了解使用 MySQL 设计、编码、实现和查询关系数据库的过程。参见第一部分( 设计关系数据库并创建实体关系图 ) 此处 )和第二部分( 使用 MySQL)此处 )。

本教程的所有代码和信息都可以在相关的 GitHub 资源库 中找到。我使用了lucid chart来制作文章中显示的图表。

在本系列的第 12 部分中,我们已经经历了设计数据库、在 MySQL 中实现它以及用我们的数据填充它的步骤。在进入本文之前阅读这些是一个好主意,但是如果你想跳到这个分析部分,让你跟上进度的 SQL 代码都包含在相关的 GitHub 库中。

查询关系数据库

我们从头开始设计并实现了一个全功能的关系数据库。很棒的东西!但是现在呢?

如果我们从事数据分析师类型的工作,我们会希望开始分析这些数据。但是首先,我们需要知道如何到达它。本文将描述如何用 SQL(特别是 MySQL )编写查询,这将允许我们访问锁定在我们的 RDBMS 中的数据和关系。

正在设置

我们在本系列的第 2 部分的中介绍了安装 MySQL 社区服务器,所以我们应该有一个运行在我们系统上的实例。我们还将再次使用 PopSQL 的免费计划来运行我们的查询。

查询数据库

SQL 查询语句的主要形式如下:

SELECT *columns* FROM *table* WHERE *condition;*

例如,要从我们的教师表中选择所有的列,我们使用语句:

SELECT *
FROM teacher;

在这种情况下,星号(*)表示“所有列”。我们正在选择教师表,并且没有附加条件,这意味着我们将从该表中选择所有列和所有记录(即所有数据)。

不错!

如果我们只需要表中的特定属性,我们可以命名这些属性,而不是使用星号。

SELECT last_name, dob
FROM teacher;

使用条件

在大多数情况下,我们不想选择一个表中的所有记录,而是寻找满足某些条件的特定记录。在这些情况下,我们将需要使用一个 WHERE 子句。

请注意,在本文中,我们将在 SELECT 语句中使用 WHERE 子句,但是完全相同的语法和操作符也适用于 UPDATE、INSERT 或 DELETE 语句。WHERE 子句是所有需要掌握的 SQL风格的重要方面。

WHERE 子句允许我们设置一个条件,例如:

SELECT *
FROM course
WHERE language = 'ENG';

这将从课程表中选择语言为英语的课程的所有详细信息。

果不其然,确实如此

也许我们想对结果进行不同的排序,那么我们可以使用 ORDER BY 来做到这一点。

SELECT *
FROM course
WHERE language = 'ENG'
ORDER BY start_date;

默认情况下,MySQL 按升序排序。如果我们想让结果按降序排列,我们可以像这样添加 DESC:

SELECT *
FROM course
WHERE language = 'ENG'
ORDER BY start_date DESC;

我们也可以按顺序使用 ORDER BY,因此我们可以:

SELECT *
FROM course
WHERE language = 'ENG'
ORDER BY start_date DESC, client, teacher;

这将按照属性的层次结构,按照它们被指定的顺序,给出我们的结果。

AND、OR 和 NOT 运算符

我们也可以在 WHERE 子句中使用运算符。如果你熟悉任何其他编程语言,你很可能以前就遇到过这些逻辑操作符。在 SQL 中,它们完全按照您的预期工作。

SELECT *
FROM course
WHERE language = 'ENG' AND level = 'C1';

使用和给我们所有的课程,语言是英语和水平是 C1

使用 AND 运算符排除了所有不符合这两个条件的结果,因此只显示 C1 英语水平的课程——在国际语言学校数据库中,这给了我们一个结果。如果我们在同一个语句中使用 OR,我们会得到一些不同的结果。

SELECT *
FROM course
WHERE language = 'ENG' OR level = 'C1';

使用 OR 为我们提供所有英语课程,以及所有其他 C1 水平的课程

使用 OR 运算符包括满足任一条件的所有记录,因此现在我们有所有英语课程(因为这些课程满足 language = 'Eng '条件)加上一门 C1 级别的课程,高级俄语。

我们还可以在条件前使用 NOT 运算符,以排除符合该条件的所有记录,并包括所有其他记录。

SELECT *
FROM course
WHERE NOT language = 'ENG' OR level = 'C1';

使用 NOT 会给出表中不满足第一个条件的所有记录。此处包含课程 15,因为它满足第二个条件(级别= 'C1 ')。

当我们想要排除某些记录时,这非常有用。

比较运算符

还可以在 WHERE 子句中使用其他的比较操作符。这是我们可以在 MySQL 中使用的比较运算符的完整列表:

  • 等于:=
  • 不等于:<>!=
  • 小于:<
  • 小于或等于:<=
  • 大于:>
  • 大于或等于:>=

这给我们带来了许多可能性。一个非常简单的例子是识别 1990 年以前出生的所有教师的姓名和联系信息:

SELECT first_name, last_name, phone_no
FROM teacher
WHERE dob < '1990-01-01';

这些是我们的,我们可以说,更有经验的老师

BETWEEN 运算符

运算符之间的允许我们选择值在某个范围内的记录。我们可以使用以下代码来识别 2020 年 1 月开始的所有课程:

SELECT *
FROM course
WHERE start_date BETWEEN '2020-01-01' AND '2020-01-31';

只有 2020 年 1 月的一门新课程

在我们的示例中,我们比较的是日期,但是 BETWEEN 也可以用于查找特定范围内的任何值(销售额、订单数量等)。非常有用!

我们喜欢这样

LIKE 操作符允许我们搜索与指定模式匹配的值。我们可以使用两个通配符来构建我们的模式:

  • 此通配符代表零个、一个或多个字符
  • _该通配符仅代表一个字符

如果你熟悉正则表达式,那么这似乎对你来说很熟悉,因为 SQL 基本上实现了它们的简化版本。这允许我们构建模式,并让 RDBMS 找到符合这些模式的记录。

让我们看一个例子:

SELECT course_name
FROM course
WHERE course_name LIKE '%interm%';

我们找到了三个名字符合我们模式的课程

通过在模式的开头和结尾使用%通配符,我们指示 MySQL 识别出现在 course_name 属性中的字符序列‘interm’。这是一个非常有用的特性。

进入最佳状态

我们的下一个操作符是中的——这是许多 or 条件的有效简写,允许我们给 MySQL 一个我们想要使用的值的列表。

SELECT first_name, last_name
FROM participant
WHERE last_name IN ('Garcia', 'Nowak', 'Mustermann');

这里的输出与我们从查询中得到的输出相同:

SELECT first_name, last_name
FROM participant
WHERE last_name = 'Garcia' OR last_name = 'Nowak' OR last_name = 'Mustermann';

好处是我们不用重复写出列名。当我们的查询中包含很多值时,这是非常有益的。

为空

我们将在本节中讨论的最后一个运算符是为空,及其负表亲不为空。这允许我们识别特定属性(或一组属性)为空的记录。这对于用其他值更新它们、从数据集中排除它们或者出于各种其他原因可能是有用的。

在我们的数据库中,我们可以用这个来识别“只”用一种语言教学的教师:

SELECT * 
FROM teacher
WHERE language_2 IS NULL;

詹姆斯和斯蒂芬妮,这仍然令人印象深刻。继续努力吧!

或者,我们可以使用 IS NOT NULL 来查找用两种语言教学的教师:

SELECT * 
FROM teacher
WHERE language_2 IS NOT NULL;

然而,这更令人印象深刻

错认假频伪信号

有时,我们数据库中的数据以属性名称存储,这可能会使我们报告的受众感到困惑,或者只是以一种不吸引人的方式格式化。我们可以通过使用别名在查询阶段解决这个问题。

这里我们使用 AS 关键字来指示 MySQL 显示带有临时名称的特定列。例如:

SELECT course_name AS 'Course Name', course_length_weeks AS 'Length of Course (Weeks)'
FROM course
WHERE language = 'DEU';

哦,太棒了!

当我们为其他利益相关者准备报告并想让事情看起来更漂亮时,或者当一个列的名称在我们的特定查询的上下文中可能会引起混淆时,这可能是有用的。

汇总数据

在执行数据分析时,能够汇总我们的数据也很重要。MySQL 提供了许多方法来实现这一点,我们不会在这里一一介绍。这里有一个全面的列表供那些想深入了解的人使用。

我们想要执行的最常见的聚合之一是求平均值。在 MySQL 中,我们用 AVG() 聚合器来做这件事。如果我们想知道一门课程的平均长度,我们可以使用以下查询:

SELECT AVG(course_length_weeks)
FROM course;

平均疗程为 20.5556 周。有意思!

在使用聚合器时,通常会将它们与由语句组成的组合使用。这可以帮助我们超越基础,在数据库中找到真正有用的信息。

SELECT client, AVG(course_length_weeks)
FROM course
GROUP BY client;

这就更有趣了!

您可以看到我们如何使用 GROUP BY 和一些聚合器在我们的数据库中找到真正的见解。在这里,我们可能希望了解为什么客户 101 预订的课程平均比其他客户长得多,并看看我们是否可以在那里学到一些东西,让其他客户效仿。

另一个需要了解的重要聚合器是计数。这让我们可以计算表中特定值的实例数。

SELECT COUNT(*)
FROM course;

好的,很高兴知道

让我们说得更具体些。

SELECT COUNT(*)
FROM course
WHERE language = 'Eng';

哦,不错

但是我们可以使用 GROUP BY 使它更加有用。

SELECT language, COUNT(language)
FROM course
GROUP BY language;

非常好!

在 MySQL 中,我们还可以做更多的聚合数据的工作,但这已经足够让我们开始了。

嵌套查询

当我们开始在其他查询中嵌套查询时,事情会变得更加令人兴奋。这就是 SQL 真正展示其威力的地方。我们将通过一个简单的例子来演示这些原理,但是通过在查询中嵌套查询,编写真正复杂和强大的查询的可能性几乎是无限的。

让我们看看我们的教师表。

如果我们想要识别比我们老师的平均年龄更年轻的老师(一系列日期的平均年龄到底是多少是一个复杂的问题,但我们现在会忽略它)。我们可以用如下的嵌套查询来回答这个问题:

SELECT *
FROM teacher
WHERE dob > 
    (SELECT AVG(dob)
    FROM teacher);

这里发生的事情是,在我们的 WHERE 子句中,我们放置了另一个完整的 SQL 查询(在括号中)。这就是嵌套查询,一个完整的查询在另一个查询中使用。

这是一个基本的例子,但是希望这种查询的能力和潜力是显而易见的。这不会是我们的最后一个嵌套查询,所以我们以后会有更多的机会看到它是如何工作的。

请加入我们

关系数据库的全部好处是实体/表相互关联的方式,允许我们探索和分析各种实体之间的关系。到目前为止,我们所有的查询都是针对单个表的。这很好,但是我们错过了关系数据库的一些主要优势。让我们通过观察加入的奇妙世界来补救这一点。

如果您熟悉其他流行的数据分析工具,如针对 Python熊猫或针对 R、dplyr ,那么您可能已经熟悉了连接。MySQL 中的概念完全相同,但是语法当然有一点不同(首先是更多的大写字母)。

要将任何表连接到另一个表,我们需要在两个表中都有一个包含相同数据的列。在关系数据库中,这是外键的功能(或者对于 N 到 M 关系,是存储这些关系的表),这些连接使得关系数据库成为存储大量数据的强大而有效的方式。

SQL 中有三种类型的连接——一个内部连接(在 MySQL 中,当只使用连接时,这是默认的)和两种类型的外部连接——左连接和右连接和。我们将从最常见、也最容易理解的内部连接开始,在 SQL 中也称为普通连接。

内部联接

内部联接采用两个表,并基于它们共有的列将它们联接起来。这允许我们利用表之间存在的关系。让我们先看一个例子:

SELECT course.course_id, course.course_name, course.language, client.client_name, client.address
FROM course
JOIN client
ON course.client = client.client_id
WHERE course.in_school = FALSE;

我们第一次加入的产出!

这里我们从两个不同的表中选择了列。在 MySQL 中,当我们处理多个表时,有必要一起标识列和表。一般来说,这样做也是一种很好的做法,因为它可以让任何阅读您代码的人清楚地知道引用了哪些列。

这是使用上面看到的 table.column 语法完成的。在我们的查询中,我们从 course 表中选择 course_id、course_name 和 language 列,从 client 表中选择 client_name 和 address 列。

然后,像往常一样,我们使用 FROM 语句来标识我们的第一个表(在本例中,当然)。到目前为止,一切顺利。

接下来的几行变得有趣了。首先,我们通过使用 JOIN 关键字让 MySQL 知道我们想要做一个连接,然后是第二个表(Client)。我们必须指示 MySQL 哪个表包含共有的数据——不可能将两个没有共享数据的表连接在一起。

为此,我们使用 ON 关键字,后跟table 1 . column = table 2 . column,其中标识的列是包含公共数据的列(通常是一个表的主键和另一个表的外键)。

在我们的示例中,我们还使用了 WHERE 关键字来添加条件。我们只是在寻找不在国际语言学校进行的课程的详细信息和公司地址。这对我们的老师来说是有用的信息,这样他们就知道他们需要去哪里旅行!

也许我们想为我们的一位老师——在我们的例子中,让我们选择斯蒂芬妮·马丁——提供她必须在校外授课的班级的地址。使用连接,这很简单:

SELECT course.course_id, course.course_name, course.language, client.client_name, client.address
FROM course
JOIN client
ON course.client = client.client_id
WHERE course.in_school = FALSE AND course.teacher = 2;

斯蒂芬妮只有一门课是在客户的办公室教的

复杂的事情——嵌套查询的连接

通过将连接与嵌套查询结合起来,我们可以进一步提高强度,从而从数据库中获得更具体的见解。如果我们想知道所有参加由 Niamh Murphy 教授的课程的人的名字会怎么样?

使用两个连接和一个嵌套查询,我们可以立即从数据库中获得这些信息:

SELECT participant.first_name, participant.last_name
FROM participant
JOIN takes_course ON takes_course.participant_id = participant.participant_id 
JOIN course ON takes_course.course_id = course.course_id
WHERE takes_course.course_id = 
    (SELECT takes_course.course_id 
    WHERE course.teacher = 6);

瞧啊。

现在事情严重了!为了解构这一点,并了解更复杂的 SQL 查询中一般会发生什么,向后工作会非常有帮助(在构造自己的更复杂的查询时,这也是一个有用的技巧)。如果我们在这里这样做,我们可以看到我们有一个标识 course_id 的子查询,其中 teacher_id = 6 — Niamh 的 id 号。

(SELECT takes_course.course_idWHERE course.teacher = 6)

其结果将是 Niamh 教授的所有课程的 course_id 值,用于我们查询的 WHERE 条件中。因此,该条件可以用简单的英语表达为“该课程由 Niamh Murphy 教授”。

因为我们正在寻找的输出是参与者的名字,所以我们的最终目标是将课程表连接到参与者表。然而,由于这些表之间的关系是 N 对 M 的关系(一个参与者可以选修多门课程,一门课程可以由多个参与者选修),我们不能简单地使用典型的 1 对 N 关系的外键关系。

相反,我们需要连接我们创建的额外的 Takes_Course 表,以存储 Course 和 Participant 表之间的 N 对 M 关系。唷!

SELECT participant.first_name, participant.last_name
FROM participantJOIN takes_course 
ON takes_course.participant_id = participant.participant_idJOIN course 
ON takes_course.course_id = course.course_id

我们使用键 participant_id 将 Participant 表连接到 Takes_Course 表,然后立即使用 course_id 将其连接到 Course 表。这就是我们如何从存储在数据库中的这些更复杂的关系中提取信息。

起初,这似乎很复杂,有点令人生畏,但是如果我们花点时间思考一下,再看一下我们的 ERD,就会明白这就是我们如何解锁存储在这个结构中的数据的方法。整个过程完全符合逻辑,完全由我们放入查询中的代码驱动。

理解这一点的一个好方法是尝试编写我们自己的查询。看着这些数据,思考“我们怎样才能把这种联系从数据库中提取出来”,并尝试不同的组合。这总是习惯一项新技术的最好方法,尝试一下,看看会发生什么。另外,这是一个有趣的时间!

其他类型的连接

现在我们已经掌握了内部连接,让我们看看 MySQL 中不同种类的外部连接。当我们有一些信息没有包含在所有表中时,连接类型之间的差异就变得更加明显了。ILS 数据库被很好地组合在一起,但大部分包含完整的数据。遗憾的是,在现实生活中情况并非如此,我们需要知道如何应对。

这意味着是时候向我们的数据库添加一个新表了!激动人心的时刻!

国际语言学校的管理层正在进行一些市场调查。他们想知道新课程以哪些行业为目标,并咨询了商业出版社,整理了一份汇总表,展示了一些不同行业的预测前景。

显然,现在不是物流的好时机

让我们将它与我们的客户端表进行比较。

当我们比较每个表中的行业列时,我们注意到有些行业同时出现在两个表中(零售、物流),而有些则没有。

在我们继续之前,让我们将行业前景表添加到我们的数据库中。

CREATE TABLE industry_prospects (
  industry VARCHAR(20) PRIMARY KEY,
  outlook VARCHAR(20)
);INSERT INTO industry_prospects VALUES
('Retail', 'Good'),
('Hospitality', 'Poor'),
('Logistics', 'Terrible'),
('Tourism', 'Great'),
('Events', 'Good');

成功!

内部联接

到目前为止,我们一直在处理内部连接。这种类型的连接遵循下面的文氏图。

内部联接将只返回两个表都匹配的值,而不会返回只在一个表中正在执行联接的列中有值的任何记录。

因此,使用下面的代码对我们的客户和行业前景表执行内部连接,将得到两个表都有匹配条目的条目。

SELECT client.client_name, client.industry, industry_prospects.outlook
FROM client
JOIN industry_prospects
ON client.industry = industry_prospects.industry;

因为零售和物流都包含在这两个表中,所以我们只得到匹配的条目,没有空值。

左连接

一个左连接将给出左表中的所有值,以及右表中的匹配值。如果右边的表中没有匹配的值,我们将在输出中得到空值。

左连接的代码与我们的内连接代码相同,只是我们用左连接替换了连接,如下所示:

SELECT client.client_name, client.industry, industry_prospects.outlook
FROM client
LEFT JOIN industry_prospects
ON client.industry = industry_prospects.industry;

我们的输出现在包括来自客户端表的每个条目(它出现在我们的代码中的第一个位置,所以它是“左边”的表,但这纯粹是因为我们选择了对表进行排序的方式)。如果行业前景表中没有相应的条目,则返回空值。

当我们想从另一个表中引入数据,但又不想丢失主表中的任何数据时,左连接是很好的。这可能发生在大量的现实场景中,左连接是我们数据分析工具箱中的一个主要部分。

右连接

右连接是左连接的镜像,不常用。因为哪个表是左表,哪个是右表完全取决于编写查询的人,所以数据分析人员和查询编写人员倾向于将我们想要保存所有数据的表放在左边。但是,仍然有一些情况需要正确的连接,特别是在连接多个表的更复杂的查询中。

为了完整起见,让我们在表上执行一个右连接。

SELECT client.client_name, client.industry, industry_prospects.outlook
FROM client
RIGHT JOIN industry_prospects
ON client.industry = industry_prospects.industry;

我们的输出现在包括了来自行业前景表的所有条目,正如所预期的那样,空值现在出现在来自客户表的数据中。

这只是左连接的镜像,我们可以简单地通过交换代码中clientindustry_prospects的顺序来获得相同的输出。

还有另一种类型的连接,在其他 SQL 风格中也支持,即完全外部连接。这将合并左连接和右连接,并返回两个表中的所有条目,如果不匹配,则返回空值。

MySQL 中不支持这个,这里就不看了。它可以在 MySQL 中相对容易地被模拟,这就是(人们推测)为什么开发者没有选择包含它的原因。如果我们最终使用另一种风格的 SQL,了解这一点对我们很有好处。所以现在我们知道了!

哇!在本文中,我们已经讨论了很多基础知识,从学习 SQL 查询的基础知识到构建具有多个连接的复杂嵌套查询。希望 SQL 在数据库中创建、检查、更新和删除数据的能力比开始时更加清晰。

关系数据库和 SQL 是处理大型数据集的一些最广泛使用的技术,尽管它们可能不像 R 或 Python 中的最新库那样流行,但对于工作数据分析师来说,它们是一个必不可少的组件,理解起来非常有用。

我们在这里看到的查询已经从相当基本的到仍然相当基本的,但是希望我们可以看到如何组合不同的条件和操作符可以让我们产生真正令人敬畏的结果。勇往直前,负责任地使用这种新的力量!

这是我的三篇系列文章中的最后一篇,介绍如何使用 SQL 和免费开源软件创建、更新和查询自己的全功能关系数据库。我们一起讨论了很多问题,我希望这对您有所帮助。

我希望听到您的反馈,如果您有任何意见或问题,请通过我的网站联系我。如果你想了解我的项目,你可以在 Medium 上关注我,在 GitHub 上关注我,或者访问我的网站

谢谢你花时间和我在一起,下次再见!

更像这样?访问craigdoedata . de

python 中的数据分析:熊猫入门

原文:https://towardsdatascience.com/data-analysis-in-python-getting-started-with-pandas-8cbcc1500c83?source=collection_archive---------23-----------------------

Pandas 是一个广泛用于数据分析和操作的 python 工具。最近,我一直在使用具有大数据帧(> 50 米行)的 pandas,并通过 PyDataUK May Talks 和 exploring StackOverflow 线程发现了几个对优化我的分析非常有用的技巧。

本教程是一个系列的第一部分,旨在介绍熊猫和它在探索帕尔默企鹅数据集时提供的一些有用的功能。

在本文中,我们将介绍:

  • 如何安装和导入熊猫
  • 熊猫中的数据结构
  • 如何输入和输出数据
  • 检查数据
  • 数据清理入门

介绍帕尔默企鹅

虹膜数据集是数据科学中常用于可视化和模式识别的数据集。自从最近发现作者与优生学的联系后,一直在努力寻找其他数据集供使用。
这就是企鹅的用武之地,帕尔默企鹅数据集已经由克里斯汀·戈尔曼博士和艾利森·霍斯特根据 CC-0 许可收集并发布,作为可供探索的备选数据集!

它已经发布了供 R 使用的示例,但是我们将使用 python 包 pandas 来探索可以在 GitHub 上找到的原始数据集(注意原始 CSV 文件不再包含在主分支中,因为它是我第一次开始查看数据集时包含的,所以我在这里引用存储库中的一个旧提交。如果该文件被重新添加到主分支中,我将更新它)。

这些数据包含了对南极洲帕尔默群岛岛屿上三种不同企鹅物种的观察,我们可以使用这些数据来比较不同物种或岛屿之间的体重、鳍状肢长度或长度。

我们开始吧!

作品作者 @allison_horst

1.安装和导入熊猫

Pandas 可以使用 python 包管理器pip : pip install pandasPyPI 安装

或者将condaconda install pandas配合使用

安装完成后,我们可以导入熊猫,并为其分配一个别名pd,别名为:

import pandas as pd

2.数据结构

pandas 中有两种数据结构,Series 和 DataFrames。我最常用的结构是 DataFrame,这是一种带有标签的 2D 表格结构,类似于电子表格或 SQL 表。

另一种结构是一个序列,它是一个 1D 标记的数组,可以保存任何数据类型。每一行都标有索引。

数据帧可以用许多不同的方式构建,包括作为系列的字典,其中每个系列是数据帧中的一列。

本文将关注数据帧,我们将使用 CSV 作为数据帧的输入。

要进一步探索数据结构,请查看熊猫文档。

熊猫系列和数据框示例

3.输入输出数据

投入

数据框可以通过多种方式创建:

a)创建一个空的数据帧:df = pd.DataFrame()

b)输入数据:df = pd.DataFrame(data = data),其中输入数据data可以是多种不同的格式,这使得构建数据框架变得灵活和方便,因为您处理的数据可以是任意数量的结构,包括序列字典,如上图所示,并且可以用以下代码构建:

d = {'student1': pd.Series([85., 72.], index=['maths', 'science']),
   'student2': pd.Series([62., 70., 55.], index=['maths', 'science', 'english']),
   'student3': pd.Series([45., 48., 70.], index=['maths', 'science', 'english'])}
df = pd.DataFrame(d)
print(df.head())

c)来自文件或数据源的输入,我们将在此重点关注 Palmer Penguin 数据的原始 CSV。

与使用输入数据构建数据框架非常相似,当从文件或数据源创建数据框架时,可以接受许多输入格式。
这包括:

  • excel 电子表格
  • 结构化查询语言
  • 战斗支援车
  • JSON

查看熊猫文档获取完整列表。

这在数据存储方面提供了很大的灵活性,你可以读入存储在本地或远程的文件,甚至可以接受压缩文件。

我们感兴趣的 Palmer Penguin 文件存放在 GitHub 上,您可以下载该文件并阅读指定您机器上位置的 CSV 文件,或者我们可以提供原始文件的链接并使用一行代码打开它:

df = pd.read_csv('https://raw.githubusercontent.com/allisonhorst/palmerpenguins/1a19e36ba583887a4630b1f821e3a53d5a4ffb76/data-raw/penguins_raw.csv')

另一个常见的数据源是 SQL 数据库。有许多不同的 python 包可以连接到数据库,其中一个例子是pymysql,我们可以首先连接到 MySQL 数据库,然后使用read_sql将数据从查询加载到df。这提供了快速和容易地连接到远程数据库的灵活性!

注意:这只是一个如何读入 SQL 数据的例子,在教程中没有用到

# Example code: how to use read_sql
import pymysqlcon = pymysql.connect(host='localhost', user='test', password='', db='palmerpenguins')df = read_sql(f'''SELECT * FROM penguins''', con)

💡 Python 3 的 f 字符串在输入查询时使用起来很方便。

我们稍后可能会输入一个条件,该条件使用了我们之前定义的变量,我们可以直接在 f 字符串中包含该变量,而不是对该条件进行硬编码。

三重引号还允许在 f 字符串中使用单引号,而不使用转义字符,如下例所示。例如:

# Example code: f-string's and variables
region = tuple('Anvers')df = read_sql(f'''SELECT * FROM penguins WHERE Region IN {region} AND Date Egg > '2007-11-11' ''', con)

大型数据帧

在读取大型数据集时,通过指定选项chunksizeread_csvread_sql或其他输入函数,可以迭代文件并每次迭代读取有限的行数。然而,值得注意的是,这个函数现在返回一个TextFileReader而不是一个数据帧,并且需要进一步的步骤将块连接成一个数据帧。

df = read_csv('https://raw.githubusercontent.com/allisonhorst/palmerpenguins/1a19e36ba583887a4630b1f821e3a53d5a4ffb76/data-raw/penguins_raw.csv', chunksize = 10000)df_list = []
for df in df:
    df_list.append(df)df = pd.concat(df_list,sort=False)

在 Palmer Penguin 数据集上不一定要使用这一步,因为它只有几百行,但这里展示的是如何在一个大文件上使用这一步,一次读取 10k 行中的数据。

输出

正如我们可以以多种格式输入文件一样,将数据帧输出到文件也同样灵活和容易!

经过一些操作后,我们可以将数据帧写入 CSV,如果需要,可以选择压缩文件:

df.to_csv('output.csv', compression='gzip)

如果您的数据存储在 AWS 中,那么有一个用于 Python 的 AWS SDK,[boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html)可以用来连接到您的 AWS 服务。

4.检查数据的快速检查

在我们开始研究我们的数据之前,首先要检查它是否已经正确加载并包含我们所期望的内容。

数据帧的尺寸

我们可以首先通过检查行数是否大于 0 来检查数据帧是否为空,并使用以下函数进一步检查维度:

  • 获取行数:len(df)
  • 获取列数:len(df.columns)
  • 获取行数和列数:df.shape
  • 获取元素的数量(行数 X 列数):df.size
if len(df) > 0:
    print(f'Length of df {len(df)}, number of columns {len(df.columns)}, dimensions {df.shape}, number of elements {df.size}')else:
    print(f'Problem loading df, df is empty.')

这将返回:

Length of df 344, number of columns 17, dimensions (344, 17), number of elements 5848

我们的数据集已经正确加载,有 344 行和 17 列。这个数据帧包含什么?

数据类型和存储器

我们已经加载了数据帧,但是我们仍然不知道它包含什么类型的数据。我们可以用df.info()得到一个摘要——让我们看看它返回了哪些细节:

df.info()<class 'pandas.core.frame.DataFrame'>
RangeIndex: 344 entries, 0 to 343
Data columns (total 17 columns):
studyName              344 non-null object
Sample Number          344 non-null int64
Species                344 non-null object 
Region                 344 non-null object 
Island                 344 non-null object 
Stage                  344 non-null object 
Individual ID          344 non-null object 
Clutch Completion      344 non-null object 
Date Egg               344 non-null object 
Culmen Length (mm)     342 non-null float64 
Culmen Depth (mm)      342 non-null float64 
Flipper Length (mm)    342 non-null float64 
Body Mass (g)          342 non-null float64 
Sex                    334 non-null object 
Delta 15 N (o/oo)      330 non-null float64 
Delta 13 C (o/oo)      331 non-null float64 
Comments               54 non-null object 
dtypes: float64(6), int64(1), object(10) memory usage: 45.8+ K 

df.info()回报:

  • 索引数据类型(dtype)和范围,在本例中,pandas 数据帧有 344 个条目,用索引值 0-343 表示,
  • 每列的名称和数据类型,以及非空值的数量,
  • 内存使用情况

penguin 数据包含混合或字符串数据类型的列objects,整数int64和浮点数float64。下表总结了熊猫的数据类型。

熊猫类型

使用[df.info()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.info.html)默认情况下,内存使用量只是根据列数据类型和行数进行估计。
我们可以指定使用深度内省来计算实际内存使用量,这在处理大型数据帧时特别有用:

df.info(memory_usage='deep') <class 'pandas.core.frame.DataFrame'> 
RangeIndex: 344 entries, 0 to 343 
Data columns (total 17 columns): 
studyName              344 non-null object 
Sample Number          344 non-null int64 
Species                344 non-null object 
Region                 344 non-null object 
Island                 344 non-null object 
Stage                  344 non-null object 
Individual ID          344 non-null object 
Clutch Completion      344 non-null object 
Date Egg               344 non-null object 
Culmen Length (mm)     342 non-null float64 
Culmen Depth (mm)      342 non-null float64 
Flipper Length (mm)    342 non-null float64 
Body Mass (g)          342 non-null float64 
Sex                    334 non-null object 
Delta 15 N (o/oo)      330 non-null float64 
Delta 13 C (o/oo)      331 non-null float64 
Comments               54 non-null object 
dtypes: float64(6), int64(1), object(10) memory usage: 236.9 KB

我们还可以使用以下命令检查每列的内存使用情况:

print(df.memory_usage(deep=True))
Index                     80 
studyName              22016 
Sample Number           2752 
Species                31808 
Region                 21672 
Island                 21704 
Stage                  25800 
Individual ID          21294 
Clutch Completion      20604 
Date Egg               23048 
Culmen Length (mm)      2752 
Culmen Depth (mm)       2752 
Flipper Length (mm)     2752 
Body Mass (g)           2752 
Sex                    21021 
Delta 15 N (o/oo)       2752 
Delta 13 C (o/oo)       2752 
Comments               14311 
dtype: int64 

或者总内存使用量如下:

print(df.memory_usage(deep=True).sum())242622

我们可以看到,数字列明显小于包含对象的列。不仅如此,我们对分析中的所有列都不感兴趣。

这个原始文件包含已经收集的所有数据。如果我们要比较不同种类和不同岛屿上的企鹅的体重、鳍状肢长度和长度,那么我们可以清理数据,只保留相关的数据。

5.数据清理

要清理数据,我们可以采取几个步骤:

删除我们不感兴趣的列

让我们先看一下前几行数据:

print(df.head())

df.head()的输出

这个输出看起来不太对。我们知道有 17 列,但我们只能看到其中的 4 列以及这里的索引。根据您正在使用的控制台的大小,您可能会在这里看到更多的列,但可能不是全部 17 列。

为了查看所有的列,我们可以将display.max_columns的值设置为None

pd.set_option('display.max_columns', None)
print(df.head())

将最大列数设置为 None 后 df.head()的输出

查看数据样本,我们可以确定我们想要使用的列,并通过只指定我们想要保留的行和列来为df重新分配一个新值。我们可以用df.loc(rows, cols)来做到这一点。在 rows 参数中,冒号表示所有值,而 columns 可以指定我们感兴趣的列,它们是:物种、地区、岛屿、竿长(mm)、竿深(mm)、鳍长(mm)、体重(g)、性别

 keep_cols = ['Species', 'Region', 'Island', 'Culmen Length (mm)', 'Culmen Depth (mm)', 'Flipper Length (mm)', 'Body Mass (g)', 'Sex']df = df.loc[:, keep_cols] print(df.columns) >>> Index(['Species', 'Region', 'Island', 'Culmen Length (mm)',        'Culmen Depth (mm)', 'Flipper Length (mm)', 'Body Mass (g)', 'Sex'],       dtype='object'

现在,我们的数据帧中只存储了感兴趣的列。

替换或删除空值

我们可以再次检查df的内存使用情况,我们可以看到,通过删除不相关的列,它减少了一半。

df.info(memory_usage='deep')<class 'pandas.core.frame.DataFrame'> 
RangeIndex: 344 entries, 0 to 343 
Data columns (total 8 columns): 
Species                344 non-null object 
Region                 344 non-null object 
Island                 344 non-null object 
Culmen Length (mm)     342 non-null float64 
Culmen Depth (mm)      342 non-null float64 
Flipper Length (mm)    342 non-null float64 
Body Mass (g)          342 non-null float64 
Sex                    334 non-null object 
dtypes: float64(4), object(4) memory usage: 104.8 KB 

看看非空值的数量,大小数据有 2 个空值,性别有 10 个。我们也可以看到这一点:

print(df.isna().sum())  
Species                 0 
Region                  0 
Island                  0 
Culmen Length (mm)      2 
Culmen Depth (mm)       2 
Flipper Length (mm)     2 
Body Mass (g)           2 
Sex                    10 
dtype: int64

我们可以删除这些值,或者用另一个值替换它们,在函数中指定inplace=True来重新赋值。
在这种情况下,我们可以用Unknown替换Sex列的na值,并删除其他列的na值。

df['Sex'].fillna('Unknown', inplace=True) print(df.isna().sum()) Species                0 
Region                 0 
Island                 0 
Culmen Length (mm)     2 
Culmen Depth (mm)      2 
Flipper Length (mm)    2 
Body Mass (g)          2 
Sex                    0 
dtype: int64 df.dropna(inplace=True) print(df.isna().sum()) Species                0 
Region                 0 
Island                 0 
Culmen Length (mm)     0 
Culmen Depth (mm)      0 
Flipper Length (mm)    0 
Body Mass (g)          0 
Sex                    0 
dtype: int64

由于我们只移除了少数几个值,这不太可能影响内存使用,但有助于清理数据,并且在处理包含大量空值的大型数据帧时,可能会减少内存。

将对象转换为分类数据类型

清理数据的最后一步是检查每一列中唯一值的数量,以确定分类数据类型是否比使用对象更合适。

我们已经知道在我们的数据中有三种企鹅,但是这个列的 dtype 是一个object,所以让我们先检查这个列。

print(df['Species'].head()) 0    Adelie Penguin (Pygoscelis adeliae) 
1    Adelie Penguin (Pygoscelis adeliae) 
2    Adelie Penguin (Pygoscelis adeliae) 
4    Adelie Penguin (Pygoscelis adeliae) 
5    Adelie Penguin (Pygoscelis adeliae) 
Name: Species, dtype: object print(df['Species'].nunique()) 3 print(df['Species'].unique()) ['Adelie Penguin (Pygoscelis adeliae)' 'Gentoo penguin (Pygoscelis papua)'  'Chinstrap penguin (Pygoscelis antarctica)']

正如所料,这一列中只有 3 个唯一值,但每一行都包含一个企鹅种类的字符串,占用了大量内存。相反,我们可以将该列转换为类别数据类型,并检查这如何改变内存。

print(df.memory_usage(deep=True))Index                   2736
Species                31626
Region                 21546
Island                 21575
Culmen Length (mm)      2736
Culmen Depth (mm)       2736
Flipper Length (mm)     2736
Body Mass (g)           2736
Sex                    21213
dtype: int64df['Species'] = df['Species'].astype('category')print(df.memory_usage(deep=True))Index                   2736
Species                  702
Region                 21546
Island                 21575
Culmen Length (mm)      2736
Culmen Depth (mm)       2736
Flipper Length (mm)     2736
Body Mass (g)           2736
Sex                    21213
dtype: int64

这已经从 31626 字节变成了 702 字节,大大减小了大小!对于其他对象列、区域、岛和性别,可以采用相同的方法。

for col in ['Region','Island','Sex']:
    print(f'Column: {col}, number of unique values, {df[col].nunique()}, unique values: {df[col].unique()}')Column: Region, number of unique values, 1, unique values: ['Anvers']
Column: Island, number of unique values, 3, unique values: ['Torgersen' 'Biscoe' 'Dream']
Column: Sex, number of unique values, 4, unique values: ['MALE' 'FEMALE' 'Unknown' '.']

Region 只有一个值,此列可以删除,因为它不提供任何值。

df.drop(columns=['Region'], inplace=True)
print(df.columns)Index(['Species', 'Island', 'Culmen Length (mm)', 'Culmen Depth (mm)',
       'Flipper Length (mm)', 'Body Mass (g)', 'Sex'],
      dtype='object')

岛和性别可以像种一样转换成分类数据类型。在此之前,在句号的性别栏中有一个奇怪的值,让我们看看有多少个这样的值。

print((df['Sex']=='.').value_counts())False    341
True       1
Name: Sex, dtype: int64

因为只有 1 个值,所以让我们用替换空值的方法用Unknown替换它。

df['Sex'].replace('.','Unknown', inplace=True)
print((df['Sex']=='.').value_counts())False    342
Name: Sex, dtype: int64

现在我们对这些列感到满意,让我们将 Sex 和 Island 转换为类别,并检查最终的内存使用情况:

df['Sex'] = df['Sex'].astype('category')
df['Island'] = df['Island'].astype('category')print(df.memory_usage(deep=True))Index                  2736
Species                 702
Island                  613
Culmen Length (mm)     2736
Culmen Depth (mm)      2736
Flipper Length (mm)    2736
Body Mass (g)          2736
Sex                     610
dtype: int64print(df.memory_usage(deep=True).sum())15605

总的内存使用量从 242622 增加到了 15605。

df.info(memory_usage='deep')<class 'pandas.core.frame.DataFrame'>
Int64Index: 342 entries, 0 to 343
Data columns (total 7 columns):
Species                342 non-null category
Island                 342 non-null category
Culmen Length (mm)     342 non-null float64
Culmen Depth (mm)      342 non-null float64
Flipper Length (mm)    342 non-null float64
Body Mass (g)          342 non-null float64
Sex                    342 non-null category
dtypes: category(3), float64(4)
memory usage: 15.2 KB

将内存从 236.9 KB 减少到 15.2 KB。

任务完成!

到目前为止,我们已经介绍了如何开始将文件读入 pandas 并清理文件以优化性能。penguin 的数据已经有了很好的结构,与您可能从其他来源遇到的数据类型相比,只需要最少的清理。它也是一个相当小的数据集,从 200 KB 开始,当 pandas 可以处理 GBs 量级的文件时,这些快速提示可以显著提高性能。

这是系列教程的第 1 部分。在接下来的部分中,我们将定量和图形化地探索我们的数据,使用 pandas 和一些额外的 python 包(matplotlib 和 seaborn)创建数据可视化,并且我们将深入了解 pandas 的一些其他有用的特性!

本教程的完整代码可以在 GitHub 上找到!

你想知道更多关于熊猫的数据检查和清理功能吗?或者我错过了什么?让我知道

如果你喜欢这篇文章,你可以订阅我的每月简讯直接在你的收件箱里获得我的最新文章、我使用的资源和其他技巧!

想了解 web 抓取或学习资源,包括 python 中的数据科学课程,请查看我的一些其他文章:

[## 数据科学技能:使用 python 进行网络搜集

作为一名数据科学家,我在工作中接受的第一批任务之一就是网络搜集。这完全是…

towardsdatascience.com](/data-science-skills-web-scraping-using-python-d1a85ef607ed) [## 学习编码。学习 Python。

你想学习编码但是不知道从哪里开始吗?开始您的编码之旅,并决定 python 是否…

towardsdatascience.com](/learn-to-code-learn-python-efb037b248e8)

数据分析是数据科学的先决条件。原因如下。

原文:https://towardsdatascience.com/data-analysis-is-a-prerequisite-for-data-science-heres-why-ebd415d4049e?source=collection_archive---------47-----------------------

让数据科学家更深入地了解数据分析。

Jefferson Santos 在 Unsplash 上拍摄的照片

目录

  1. 介绍
  2. 数据分析
  3. 数据科学
  4. 为什么是先决条件?
  5. 摘要
  6. 参考

介绍

随着劳动力市场格局的变化,许多人在被解雇后要么改变职业,要么申请不同的公司。其中一些人是希望成为数据科学家的数据分析师,或者一些人是正在改变公司的数据科学家,他们需要花一些时间学习或更新他们的数据分析知识。

你可以假设数据分析已经在数据科学课程中教授了,但根据我的经验,我已经看到了直接跳到数据科学,或者更具体地说,机器学习算法。就像现在很容易假设数据科学家已经知道数据分析一样,一些大学或在线课程也是如此,它们直接进入了常见的机器学习概念。这种假设可能会导致一些数据科学家在数据分析中苦苦挣扎。虽然一开始看起来可能更简单,但数据分析是数据科学的基础。您必须了解您的业务、数据和指标。这些信息最终会为您的统计方法和数据科学模型提供信息。

下面,我将总结数据分析和数据科学,并举例说明为什么数据分析对数据科学如此重要。

数据分析

数据分析通常被称为商业智能、BI 开发或产品分析。这个领域几乎存在于每一家科技企业,也存在于大多数其他企业。在公司实践数据分析是至关重要的,以确保公司财务、客户数据和未来机器学习模型可以应用的改进领域的可见性。可以使用以下工具找到数据分析:

Tableau,Looker,Google Data Studio,SQL,Excel,有时候还有 Python。

数据分析的例子有:

  • 寻找产品的顶级用户
  • 收集这些用户的关键人口统计数据
  • 产品的汇总指标
  • 发现用户行为的季节性趋势
  • 突出财务异常

从上面的例子可以看出,所有这些都可以以某种方式应用于数据科学过程。这些示例也可以作为输入到模型中的特征或属性。

数据科学

数据科学作为许多人的职业道路越来越受欢迎。从本质上来说,这是一个使用编程语言和统计学来实现自动化的职业。它的基础是基于数据分析和数学。数据科学家可能会用到的常用工具有:

数据分析、SQL、Tableau、Python、R、SAS、Terminal、Jupyter Notebook、AWS、GCP、sklearn 和 TensorFlow 库(以及更多)。

数据科学中的整个过程有几个部分可以包括数据分析,例如数据形成/创建、数据清理、探索性数据分析(尤其是这一部分)、特征工程以及对建议/预测/结果的解释。

数据科学的例子可以是:

  • 客户行为聚类
  • 服装风格的分类
  • 人脸图像检测和分类
  • 一个利用自然语言处理(NLP)的聊天机器人
  • 欺诈的自动异常检测

这些示例中的大多数(如果不是全部的话)都基于第一手数据分析,以及数据科学过程之后的数据分析。

为什么是 Preqreuisite?

接下来,我们将探讨数据分析是数据科学先决条件的原因。下面我将讨论的主要原因列举出来。

  1. 商业知识
  2. 车型特点
  3. 机器学习结果的解释
  • 业务知识

—为了成为一名成功的数据科学家,您需要对您的业务了如指掌。你可以整天高精度地运行算法,但如果你不是在回答一个商业问题,那么你就错过了数据的要点。了解你的企业及其各自产品的主要功能是非常重要的。在你的新工作中运行你的第一个算法可能需要几周时间,因为你需要了解你的数据表、你公司的问题、自动化的可能重点,以及总体而言,数据科学模型的实施。

根据您的业务,一些监督模型可能比非监督模型更适用,反之亦然。例如,利用聚类模型将客户分组到不同的箱中,以便您可以向他们做不同的广告。然而,这个问题的基础不是数据科学,而是数据分析——这意味着您需要开发与客户及其人口统计相关的指标。有时,这些指标在公司中并不容易找到,通常情况下,您需要提出自己的指标,并轻松地分析数据。这种创建将来自 SQL 查询,包括子查询、公共表表达式以及更多有助于在 SQL 环境中立即开发的函数、子分组和聚合。这部分引出了我下面的下一个观点。

  • 模型特征

—再说一次,创建数据科学模型并不是从一个神奇的向导开始,向导会为您提供一个开发、清理和组织有序的数据集。您将不得不参考 API、参考业务、与利益相关者以及数据和软件工程师交流,以获得对输入到您的模型中的特性的最佳理解。

通过数据分析技能,您可以为您的机器学习模型开发最有效和最有用的数据集。在数据分析中,聚合和粒度至关重要,因此根据您将要使用的数据科学模型以及您试图解决的问题,数据分析可以帮助您将数据组织到具有正确和相关值的行中。

  • 解释机器学习结果

这一点可能会让一些人感到惊讶,但它与数据科学模型或项目的开始过程一样重要,即机器学习对数据科学结果的解释(预测和建议)。在合成数据、清理、训练和评估数据之后,您必须与利益相关者共享您的结果。

在数据科学流程的这一步中,数据分析技能至关重要,因为您需要执行不同的任务,而这些任务并不直接属于数据科学。这些任务包括:

* grouping model results from SQL querying* displaying visual metrics of your model’s accuracy * utilizing tools like Tableau or Looker to visualize* presenting in front of stakeholders* commutating data science model success to non-technical users

摘要

照片由诺德伍德主题Unsplash【2】上拍摄。

通过阅读这篇文章,我希望您现在已经理解了数据分析对数据科学的重要性,以及它最终如何成为数据科学的先决条件。为了开发您的数据并传达您的结果,作为一名数据科学家,数据分析是必须学习和实践的。

作为一名数据科学家,并不是每天都要使用网格搜索方法优化参数,但这可能需要从数据分析工具和函数中获取数据集。我做的三个要点是:业务知识,模型特征,机器学习结果解读。这些只是在您从事数据科学领域之前或期间学习数据分析的众多原因中的一部分。

我希望你觉得这篇文章既有趣又有用。感谢您的阅读,欢迎在下方评论!

参考

[1]照片由 Jefferson SantosUnsplash 上拍摄,(2017)

[2]照片由诺德伍德主题Unsplash(2017)拍摄

数据分析变得简单:Jupyter 笔记本的 text 2 代码

原文:https://towardsdatascience.com/data-analysis-made-easy-text2code-for-jupyter-notebook-5380e89bb493?source=collection_archive---------12-----------------------

运行中的插件示例

灵感:GPT-3

2020 年 6 月,OpenAI 推出了他们的新模型 GPT-3,它不仅具有未来的 NLP(自然语言处理)能力,还能够生成反应代码并简化命令行命令

观看这些演示对我们来说是一个巨大的鼓舞,我们意识到在进行数据分析时,很多时候,我们经常忘记不常用的熊猫或 plotly 语法,需要搜索它们。从 StackOverflow 复制代码需要相应地修改变量和列名。我们开始探索能够为人工查询生成现成代码的东西,比如:

在数据帧 df 的热图中显示降雨量和湿度

或者

按州对 df 进行分组,并获取用户年龄的平均值和最大值

Snippets 是我们使用了一段时间的一个扩展,但是在使用了一定数量的 Snippets 之后,UI 变得不直观了。虽然静态模板很好,但是我们需要更多的东西来处理用例的动态特性。

代码段扩展示例

为此,我们决定尝试建造一个新的 jupyter 扩展。不幸的是,我们没有 GPT-3 的测试版,所以使用那个神奇的模型不是一个选项。

简化任务:

我们希望构建一些可以在我们的桌面上运行的东西(使用 GPU)。我们最初试图将该问题视为聊天机器人问题,并从 Rasa 开始,但由于缺乏适当的训练数据,很快就停止了。

由于未能建立一个真正的生成模型,我们决定开发一个监督模型,该模型可以为培训管道中定义的用例工作,并且可以很容易地扩展。受 chatbot 管道的启发,我们决定将问题简化为以下几个部分:

  • 生成/收集培训数据
  • 意图匹配:用户想要做什么?
  • NER(命名实体识别):识别句子中的变量(实体)
  • 填充模板:使用固定模板中提取的实体来生成代码
  • 在 jupyter 扩展中换行

生成训练数据:

为了模拟最终“用户”将向系统查询什么,我们从一些我们认为自己用来描述英语命令的格式开始。例如:

\(varname** 开始,在 y 轴上显示 **\)colname ,在 x 轴上显示 $colname

然后,我们通过使用一个非常简单的生成器替换\(colname 和\)varname 来生成变体,以获得训练集中的变体。

一些示例(intent_id、ner 格式)

意图匹配:

在生成数据之后,该数据被映射为特定意图的唯一“intent_id ”,然后我们使用通用语句编码器来获得用户查询的嵌入,并找到与我们预定义的意图查询(生成的数据)的余弦相似性。Universal Sentence Encoder类似于生成嵌入的word2vec,但是是针对句子而不是单词。

意图匹配的示例

NER(命名实体识别):

然后,可以使用相同的生成数据来训练定制的实体识别模型,该模型可以检测列、变量、库名称。为此,我们探索了 HuggingFace 模型,但最终使用 Spacy 来训练一个定制模型,主要是因为 HuggingFace 模型是基于变压器的模型,与 Spacy 相比有点重。

实体识别示例

填充模板:

一旦实体被正确识别并且意图被正确匹配,填充模板就非常容易。例如,“显示 df 中的 5 行”查询将产生两个实体:一个变量和一个数字。这方面的模板代码写起来很简单。

df.head()或 df.head(5)

与 Jupyter 集成:

令人惊讶的是,这一个被证明是最复杂的,因为为 Jupyter 编写如此复杂的扩展有点棘手,而且几乎没有可用的文档或示例(与 HuggingFace 或 Spacy 等其他库相比)。经过一些尝试和错误,以及对现有扩展的一些复制粘贴,我们终于能够将所有东西打包成一个 python 包,可以通过pip install安装

我们必须创建一个前端和一个服务器扩展,当jupyter notebook被触发时,它就会被加载。前端将查询发送到服务器以获取生成的模板代码,然后将其插入到单元中并执行它。

演示:

演示视频由 Sanyam BhutaniChai Time 数据科学数据集上制作。

支持的命令的简短视频

局限性:

像许多 ML 模型一样,有时意图匹配和 NER 失败得很惨,即使意图对人眼来说是显而易见的。我们可以尝试改善这种情况的一些领域是:

  • 收集/生成更高质量的英语句子训练数据。是一种我们还没有尝试过的技术,可以产生不同的方式来说同一个句子。
  • 收集真实世界的变量名、库名,而不是随机生成它们。
  • 尝试用基于变压器的模型 NER。
  • 有了足够的数据,训练一个语言模型,像 GPT-3 那样直接做英语->代码,而不是在流水线中有单独的阶段。

那都是乡亲们!

我希望你喜欢读这篇文章。这个扩展的全部代码已经准备好安装在本地 GPU 机器上,在这里可以找到

Deepak 和我一起花了几个周末黑了这个。这些代码还不能用于生产,但是已经足够好了,人们可以自己修改和使用。我们希望听到反馈和改进意见。😃

AppleWatch 锻炼的数据分析

原文:https://towardsdatascience.com/data-analysis-of-your-applewatch-workouts-672fe0366e7c?source=collection_archive---------17-----------------------

你是一个用 Apple Watch 跟踪锻炼的运动和数据极客吗?那么现在可能是时候了解更多关于你在过去几年中的表现发展了。读完这篇文章后,你会知道如何深入了解你的锻炼和运动模式。如果这还不够,深入数据分析可能是一个不错的第一个项目:你将学习如何从你的跟踪设备(在这种情况下是 Apple watch)中提取数据,如何清理和转换数据集,最后用 Google Data Studio 可视化它。我们开始吧!

你的 Apple Watch 锻炼数据分析。

这篇文章分为三部分。首先,你 iPhone 上的 Apple Watch 数据需要导出。其次,在编程语言 Python 的帮助下,读取、转换和清理接收到的 XML 文件。结果是一个完美的 CSV 文件,可以插入到谷歌数据工作室。如何做到这一点我们将在第三部分解释。

我们使用的工具

正如已经提到的,我们正在使用 Python 和它惊人的开源库。首先,我们使用 Jupyter Notebook,这是一个用于实时编码的开源应用程序,它允许我们讲述一个故事,并使代码可复制。要启动和运行 python,推荐使用 Anaconda。这里的描述了如何设置和运行。对于数据可视化,您可以使用任何想要的工具。根据你的喜好,谷歌数据工作室的替代品是 Tableau、Grafana 或任何数据可视化工具。

用于数据分析的工具

1.从您的 Apple 设备导出数据

首先,我们需要知道你的 Apple Watch 收集的所有数据在哪里可以找到。因此,从主屏幕打开健康应用程序。在右上角,您可以访问您的个人资料。滚动到底部,导出所有数据。不要担心,这可能需要一段时间。

从 Apple 导出您的健康记录。

您将得到一个 XML 文件。XML 代表可扩展标记语言,这意味着您的数据以非预定义的结构和纯文本格式存储。因此,如果您想看一下文件的内容,可以用标准的文本编辑器打开它。XML 在互联网上被广泛用于数据传输。下一步,我们用 python 获取这个文件并处理数据集。

2.使用 Python 进行数据转换和清理

在导出你所有锻炼的 XML 文件后,它现在就在你的笔记本电脑上。我们做的第一件事是将文件加载到 Jupyter 笔记本中(您应该已经安装了 Python 和 Jupyter 笔记本。如果没有,试试 Anaconda,或者看看如何设置你的数据科学环境 mit Docker。)

为了读取 XML 文件,加载了包 xmltodict,并使用它来读取我们的导出。在这种情况下,我们一方面将手表的所有“记录”数据保存在“记录列表”中,另一方面将实际锻炼数据保存在“锻炼列表”中。虽然我们将只处理锻炼数据,但知道还有更多可用的数据仍然是有用的,您可以立即开始处理这些数据。

#Reading the file and converting it as a dict. import pandas as pd
import xmltodictinput_path = '/Users/apple_health_export/export.xml'
with open(input_path, 'r') as xml_file:
    input_data = xmltodict.parse(xml_file.read())#Records list for general health data & imported as Pandas Data Frame
records_list = input_data['HealthData']['Record']
df_records = pd.DataFrame(records_list)#Workout list for workout data
workouts_list = input_data['HealthData']['Workout']
df_workouts = pd.DataFrame(workouts_list)

接下来,一些列必须转换成不同的格式。一方面,持续时间、距离和消耗的能量应为数字,日期格式应用于日期

#Convert selected columns to numeric so we can do calcuations
# convert just columns "..." and "..."
df_workouts[["[@duration](http://twitter.com/duration)", "[@totalDistance](http://twitter.com/totalDistance)", "[@totalEnergyBurned](http://twitter.com/totalEnergyBurned)"]] = df_workouts[["[@duration](http://twitter.com/duration)", "[@totalDistance](http://twitter.com/totalDistance)", "[@totalEnergyBurned](http://twitter.com/totalEnergyBurned)"]].apply(pd.to_numeric)
df_workouts.dtypes#convert dates to actual datetime
format = '%Y-%m-%d %H:%M:%S %z'df_workouts['[@creationDate](http://twitter.com/creationDate)'] = pd.to_datetime(df_workouts['[@creationDate](http://twitter.com/creationDate)'],format=format)df_workouts['[@startDate](http://twitter.com/startDate)'] = pd.to_datetime(df_workouts['[@startDate](http://twitter.com/startDate)'], format=format)df_workouts['[@endDate](http://twitter.com/endDate)'] = pd.to_datetime(df_workouts['[@endDate](http://twitter.com/endDate)'],format=format)df_workouts.dtypes

对于我们的锻炼分析,我们不需要所有的列。以游泳为例,我们在最后一栏中分解为 100 米组。如果您想了解详细信息,这可能会很有用,但出于我们的目的,我们只选择前 12 列,并且只保留锻炼活动类型游泳、跑步和骑自行车。

#drop unnecessary columns (all rows and column 1 to 12)
df_workouts = df_workouts.iloc[:,0:12]
df_workouts.head()#Remove HKWorkoutActivityTypeWalking and HKWorkoutActivityTypeSnowSports
df_workouts=df_workouts[df_workouts['[@workoutActivityType](http://twitter.com/workoutActivityType)'] != 'HKWorkoutActivityTypeWalking']
df_workouts=df_workouts[df_workouts['[@workoutActivityType](http://twitter.com/workoutActivityType)'] != 'HKWorkoutActivityTypeSnowSports']

由于健身程序的名称很长,原来的健身程序名称(如“HKWorkoutActivityTypeCycling ”)将替换为简单的“Cycling”。跑步和游泳也是如此。

#Rename Activity Types to Running, Cycling and Swimming
df_workouts["[@workoutActivityType](http://twitter.com/workoutActivityType)"]= df_workouts["[@workoutActivityType](http://twitter.com/workoutActivityType)"].replace("HKWorkoutActivityTypeCycling", "Cycling")
df_workouts["[@workoutActivityType](http://twitter.com/workoutActivityType)"]= df_workouts["[@workoutActivityType](http://twitter.com/workoutActivityType)"].replace("HKWorkoutActivityTypeRunning", "Running")
df_workouts["[@workoutActivityType](http://twitter.com/workoutActivityType)"]= df_workouts["[@workoutActivityType](http://twitter.com/workoutActivityType)"].replace("HKWorkoutActivityTypeSwimming", "Swimming")df_workouts.head(15)

最后但同样重要的是,检查数据帧的头部。如果它看起来像你想要的样子,让我们做一个 CSV 导出,并准备好我们的最终分析数据集插入到 Google Data Studio。

#save as csv (Don't forget to add '.csv' at the end of the path)finalADS = df_workouts.to_csv(r'/Users/finalADS.csv', header=True) 

3.使用 Google Data Studio 创建仪表板

最后但同样重要的是,我们正在可视化导出的 CSV 数据集,以探索我们的锻炼数据。Google Data Studio 是首选工具,因为它对每个人都是免费的,并提供了一种快速可视化简单数据的方法。如果你已经有一个谷歌账户,访问 https://datastudio.google.com/,你就可以开始了。Google Data Studio 提供了一些示例报告,但是在这种情况下,我们从头开始,使用“空白报告”并添加我们的 CSV 作为数据源。

在 Data Studio 中创建空白报表

Google Data Studio 中的 CSV 上传

Google Data Studio 将确认您的 CSV 成功上传。在我的例子中,第一列没有被命名为“ID ”,而是被追溯标记。之后,您可以开始创建您想要的图表。下面不会解释每一个图表,但是在 Google Data Studio 中如何创建一个图表的三个基本步骤。

使用 Google Data Studio 创建图表

  1. 通过单击顶部导航栏上的概述按钮添加新图表。
  2. 选择所需的图表类型后,接下来选择要显示的数据。首先,选择我们的“finalADS.csv”作为数据源。其次,应该定义“日期范围维度”。在这种情况下,我们想比较这些年来我们的锻炼行为是如何发展的。第三,我们的“分解维度”选择为“@workoutActivityType”。这让我们可以在游泳、骑自行车和跑步中分解我们的训练
  3. 最后但同样重要的是,我们可以设计图表的样式。对于所有不同的图表,相同的颜色用于相同的锻炼活动类型。这样,我们可以轻松地将锻炼分配到相应的图表中。

谷歌数据工作室——铁人三项仪表板 I

谷歌数据工作室——铁人三项仪表板 II

结论

从运动的角度来看,从 2018 年到 2019 年,训练量几乎翻了一倍,另一方面,这些年来速度增加了,这是很惊人的。看起来运动的事情正朝着正确的方向发展,但你会发现这个项目更大的焦点是处理由 Apple Watch 设备创建的数据集。

虽然提取数据集非常容易,但要适应 XML 文件需要一些时间。但是我保证一旦你掌握了窍门,你会爱上它的。从那时起,这就是一个非常典型的数据分析过程,其中包含清理和转换的部分。最后但并非最不重要的是,我只能向不太复杂的项目推荐使用 Google Data Studio 进行数据可视化。它是免费的,它有大部分的选择,并且很容易共享。对于这个范围内的其他工具,你肯定要付出代价。


如果您有任何问题或需要一些数据分析方面的支持,请随时通过 LinkedIn、Instagram 或其他任何地方联系。


您可能也喜欢阅读的文章:

使用 Docker 设置您的数据环境

消除流失是增长黑客 2.0

用数据误导&统计

数据分析项目—电信客户流失

原文:https://towardsdatascience.com/data-analysis-project-telco-customer-churn-fe5c0144e708?source=collection_archive---------7-----------------------

这个项目的假想背景:我是一名数据分析师,在一家电信公司工作。我的经理让我分析她提供的数据集,以获得可操作的见解,从而留住客户并增加客户的终身价值。

蔡斯·沙佩尔Unsplash 拍摄的照片

从数据集中提取可行的见解。在评估数据集后,我列出了所有出现在我脑海中的问题,并试图对所有问题进行调查,以找到真知灼见:

1.为服务付费的未订阅用户通常会在服务中停留多长时间?他们的平均 LTV(生命时间价值)是多少?

2.退订和仍在订购的用户中有多少人使用了电话服务?

3.有多少人使用多线路电话服务给那些退订但仍在订购的人?

4.对于那些退订和订阅的人,有多少人使用了互联网服务?

5.对于那些退订和付费的用户,有多少人使用和正在使用互联网服务的每个子集?

6.对于那些仍然在用 LTV 高于泄露客户平均 LTV 的人来说,每个服务互联网服务有什么不同?

7.有多少人订阅了每一种合同,而那些退订的人仍然在为服务付费?

8.在“性别”、“伴侣”、“家属”、“电话服务”、“互联网服务”、“合同”和“支付方式”中,哪个变量对 LTV 的影响最大?

这个数据集是我在 Kaggle 建立的 IBM 样本数据集。

该数据集的简要说明:

每行代表一个客户;每一列都包含列元数据中描述的客户属性。

数据集包括以下信息:

  • 上个月内离开的客户—这一列称为流失。
  • 每位客户已注册的服务—电话、多条线路、互联网、在线安全、在线备份、设备保护、技术支持以及流媒体电视和电影
  • 客户账户信息——他们成为客户的时间、合同、支付方式、无纸化账单、每月费用和总费用
  • 客户的人口统计信息—性别、年龄范围,以及他们是否有伴侣和家属

让我们从解释我在这个项目中的整个数据分析步骤开始:

第一步:收集数据

第二步:评估和清理数据

第三步:进行探索性数据分析以回答问题&创建可视化( 最终可视化代码 )

第四步:理解语言障碍

第五步:汇总

第六步:可行的见解

从步骤 1 到步骤 3,你可以在这里看到完整的代码。

第一步:收集数据

对于stats models . API模块,由于我将对第 8 个问题使用多元线性回归分析,所以我包括在这里。

第二步:评估和清理数据

在这里,因为这篇文章的目的是展示我做了什么和我进行数据分析项目的过程,所以我不会重复每个细节。相反,我会选择我做过的最重要的程序。如果你真的想检查我做的每一个细节,请看这里。

评估:

通常,我喜欢一次查看所有的列,所以我使用 pandas.set_option 来做这件事:

****

df.describe()

df.Contract.value_counts()

逐月:一年:两年约为 2.5: 1: 1

*# show the distribution of tenure.*
plt.hist(data = df, x = 'tenure');

这显然不是正态分布。而且有两个高峰,所有客户中有两种极端的人,我会调查是什么服务让入住 70 个月以上的人最多。

评估报告:

这里没有整洁的问题,只有两个问题需要考虑一个非常干净的数据集。以下是 2 个质量问题:

  • “TotalCharges”的数据类型应该是 float64 类型,而不是 object 类型。
  • 许多行的“总费用”不等于每个月的费用。

首先,我们应该复制原始数据集:

df_copy = df.copy()

清理 1:“总费用”的数据类型应该是 float64 类型,而不是对象类型

操作:为所有行赋予 None 值,然后将其转换为 float64 的数据类型。(稍后我会重新计算)

df_copy.TotalCharges = **None**
df_copy.TotalCharges=df_copy.TotalCharges.astype(float)

测试结果:

df_copy.TotalCharges.dtype

输出:dtype('float64 ')

清洁 2:许多行的“总费用”不等于每个月的费用。

行动:重新计算,让每个任期乘以每月收费

df_copy.TotalCharges = df_copy.tenure * df_copy.MonthlyCharges

测试结果:

df_copy[df_copy.tenure * df_copy.MonthlyCharges != df_copy.TotalCharges].shape

输出:(0,21)

清理过程的最后一步:保存数据。

*# store the clean data*
df_copy.reset_index(drop=**True**)
df_copy.to_csv('Telco-Customer-Churn_clean.csv')

第三步:进行探索性数据分析以回答问题&创建可视化( 最终可视化代码 )

在编写任何可视化之前,我喜欢创建一个可重用的函数,这样我可以节省大量时间,而不必编写相同的代码:

研究问题 1:退订付费服务的人通常会在服务中停留多久?他们的平均 LTV(生命时间价值)是多少?

首先,我提取了那些取消订阅服务的人,并检查了任期的分布。

Churn_df = clean_df.query('Churn=="Yes"')
Churn_df.TotalCharges.describe()

让我们看看它的分布:

plt.hist(data = Churn_df, x = 'TotalCharges');

在查看了分布和 5 个数字的汇总后,我发现 80%左右的数据都非常高,所以我决定将它们分成 80%和剩下的 20%来查看每个数据的分布。(在现实生活中应用 80/20 法则。)

*#find the 80th percentile of the data in total charges*
Churn_df.TotalCharges.quantile(0.8)

产量:25000 万英镑 20000 万英镑 20001

*# Divide the data by the 80th percentile of the data, and show the distribution of its TotalCharges under 80th percentile* 
TotalCharges_under80 = Churn_df.query('TotalCharges<=2827.59')
TotalCharges_above80 = Churn_df.query('TotalCharges>2827.59')

让我们想象一下未订阅的客户按 80/20 分组的情况:

好了,现在,让我们来看看这张图,它综合了退订者和付费者。

注意:80%(低 LTV)的泄露客户仅停留在 10 个月以下。80%退订者的平均 LTV 是 750 美元。另一方面,未订阅的前 20%的平均 LTV 是 4750 美元。每组总 LTV 之和的比率为 750*4: 4750 = 1: 1.6,这表明我们应该专注于服务那些 LTV 高的 20%客户,这些客户为我们带来了来自泄露客户的 60%(1.6/2.6)的收入。

研究问题 2:退订和仍然订购的用户中使用电话服务的比例是多少?

注:100%的人带来了高 LTV 使用和正在使用互联网服务。

研究问题 3:对于那些退订并仍然订阅的人,使用多线路电话服务的人占多大比例?

注:81%带来高 ltv 的人倾向于二手线路。那些仍然在为服务付费的人和那些退订的人之间没有太大的区别。

研究问题 4:退订和订阅的人使用互联网服务的比例是多少?

注:那些携带高 ltv 的人喜欢使用光纤(75%-90%)和 DSL(10%-20%),他们中没有人使用互联网服务。而那些带来低 ltv 的人,就目前的客户而言,约 30%的人不使用互联网服务。

现在,让我们更深入地了解每个互联网服务子集的情况。

研究问题 5:对于那些退订并仍在为服务付费的人来说,使用每个互联网服务子集的人的比例是多少?

首先,提取使用互联网服务的 LTV 低的 80%,并将互联网服务子集的每个比例保存在变量“比例 _ 互联网 _ 子服务”中:

然后提取使用互联网服务的 LTV 高的 20%,并将互联网服务子集的每个比例保存在变量“比例 _ 互联网 _ 子服务 _ 高于 80”中

其次,提取使用互联网服务的 LTV 低的 80%,并将互联网服务子集的每个比例保存在变量“paying _ proportion _ internet _ sub _ service _ under 80”

然后 e 提取使用互联网服务的 LTV 高的 20%,并将互联网服务子集的每个比例保存在变量“paying _ proportion _ internet _ sub _ service _ above 80”

让我们想象一下:

注:在当前客户的 80%(低 LTVs)数据中,40%的人平等地使用互联网服务的所有子集。在 80%的现有客户(低 ltv)中,流媒体电影和流媒体电视是人们使用的互联网服务的两大子集,设备保护和在线备份排在第二位,技术支持和在线安全排在第三位,这两者之间的差距接近整个数据的 10%。

研究问题 6:对于那些仍在服务的 LTV 高于泄露客户平均 LTV 的客户,每个服务中的一般当前客户之间有什么差异?

首先,我提取了我想要调查的几组数据:

1.让我们来看看多线路的电话服务:

2.对于互联网服务:

注意:在 80%的当前客户中,LTV 超过 80%泄露客户的平均 LTV 的人使用多条线路和互联网服务的可能性比 80%的当前客户的平均水平高 10%。

研究问题 7:对于泄露且仍在支付服务的两组人,每组的每种合同的比例是多少?

注意:89%的泄露者使用月合同,而只有 42%的当前客户使用月合同。

研究问题 8:在“性别”、“伴侣”、“家属”、“电话服务”、“互联网服务”、“合同”和“支付方式”中,哪个变量对 LTV 的影响最大?

我对这些问题使用了多元线性回归,首先,因为它们大多数是分类变量,所以我需要将它们转换成虚拟变量:

使用多元线性回归:

注:人们是否使用互联网服务是创造高 LTV 的最重要因素,年度合同次之。

注意:在互联网服务的所有子集中,在线备份是创造高 LTV 的最重要因素

第四步:了解局限性

在得出任何结论之前,告知局限性总是更好的。在评估数据和进行探索性数据分析的过程中,我发现了一些局限性:

限制 1:在这个数据集中,我们只能看到每个变量的一种类型,而不是改变不同选项久而久之的真实世界情况,即在真实世界中,人们可能想尝试流媒体服务,但他们可能会改变主意,下个月使用技术支持。

局限性 2:我们不能将所有这些变量都视为客户离开的确切原因,因为他们可能会因为竞争对手提供的更好的价格或某个时候经济不景气等原因而离开。我们看不到他们泄露的时间,所以很难推断那些外部情况。

第五步:总结

  1. 80%(低 LTV)的泄露客户仅停留在 10 个月以下。他们的平均工资是 750 美元。另一方面,前 20%的泄密者的平均 LTV 是 4750 美元。每组总 LTV 之和的比率为 750*4: 4750 = 1: 1.6,这表明我们应该专注于服务 20%的高 LTV 客户,这些客户为我们带来了 60%(1.6/2.6)的来自泄露客户的收入
  2. 81%带来高 ltv 的人倾向于二手线路。那些仍然在为服务付费的人和那些退订的人之间没有太大的区别。
  3. 那些带来高 ltv 的人喜欢使用光纤(75%-90%)和 DSL(10%-20%),他们中没有人使用互联网服务。而那些带来低 ltv 的人,就目前的客户而言,约 30%的人不使用互联网服务。
  4. 在 80%(低 LTVs)的当前客户中,40%的人平等地使用互联网服务的所有子集。在 80%的现有客户(低 ltv)中,流媒体电影和流媒体电视是人们使用的互联网服务的两大子集,设备保护和在线备份排在第二位,技术支持和在线安全排在第三位,这两者之间的差距接近整个数据的 10%。
  5. 在 80%的当前客户中,那些 LTV 高于 80%泄露客户的平均 LTV 的人使用多条线路和互联网服务的可能性比 80%的当前客户高 10 %。****
  6. 89%的泄露者使用月合同,而只有 42%的当前客户使用月合同。
  7. 人们是否使用互联网服务是创造高 LTV 的最重要因素,年度合同次之。
  8. 在互联网服务的所有子集中,在线备份是创造高 LTV 的最重要因素。

第六步:可行的见解

为了留住客户:

  1. 开展营销活动,对目前在我们的其他互联网服务上订购流媒体电影和电视服务的用户进行追加销售。(根据 Q5 的图表,他们支付的互联网服务越多,他们停留的时间就越长。)

为了增加客户的终身价值:

  1. 增加我们的流媒体电影和电视服务的营销预算,因为这两个领域的差距最大,分别为 80%(低 LTV)和 20%(高 LTV)。(基于 Q5 的图表)
  2. 增加我们在线备份的营销预算,这是促成高 LTV 的最重要因素。(基于 Q8 的图表)
  3. 增加我们对那些想使用多条线路的用户的营销预算。(基于 Q6 的图表)

弗兰基·查马基在 Unsplash 上拍摄的照片

最后,数据有更好的想法,但你应该始终怀疑任何洞察力和数据在某种程度上是错误的或有一些偏见,无论谁提供给你的是专家或可信度高的人。

感谢您花时间阅读这篇文章。

如果你是想找数据分析师实习生的雇主,这是我的 LinkedIn 或者通过我的电子邮件(ychen596@insite.4cd.edu)联系我

如果你也在数据科学/商业分析领域工作,请随时通过 IG( @jchen_mmm )、电子邮件或下面的评论给我任何反馈!

数据分析项目——WeRateDogs

原文:https://towardsdatascience.com/data-analysis-project-weratedogs-16aad3f6c8c2?source=collection_archive---------22-----------------------

许多人都在为他们可爱的狗狗运营社交媒体账户。然而,他们中的大多数人通常不会很好地运营他们的社交媒体账户,因为他们不知道观众喜欢什么,也不知道是什么因素影响了他们的喜爱和转发量。

瓦莱丽·埃拉什在 Unsplash 上拍摄的照片

因此,我试图通过分析著名的狗评级 Twitter 帐户 @weratedog来调查以下这 2 个问题,帮助那些拥有或打算拥有狗宠物社交媒体帐户的人通过选择正确类型的狗来吸引更多观众(我有多无聊):

1.哪个阶段/尺寸的狗获得了最高的转发数和最喜欢的数?

2.转发次数最多的前三种狗是什么?

一个简短的介绍@weratedog 是一个推特账户,用一个关于狗的幽默评论给人们的狗打分。该账户由大学生马特·尼尔森于 2015 年创建。从那以后,这个账户已经吸引了 880 万以上的关注者。

让我们从解释我在这个项目中的整个数据分析步骤开始:

第一步:使用 Twitter API 收集数据(这里是完整代码

第二步:评估和清理数据(此处为的完整代码)

第三步:进行探索性数据分析以回答问题并创建可视化效果(完整代码在此处)

第四步:理解局限性

第五步:总结

第六步:可行的见解

步骤 1:使用 Twitter API 收集数据

在这个项目中,我使用了 Tweepy ,一个 Python 库,来查询 Twitter 的 API 以获取 WeRateDogs Twitter 数据。数据将包括转发次数和收藏次数。我将把这两条信息与我在做这个项目时参加的 Udacity 的数据分析师课程提供的额外数据结合起来。

而且,因为这篇文章的目的是展示我所做的,所以这不是一篇教程文章,所以如果你是一个初学者并且对如何使用 Tweepy 感兴趣,这是一篇适合初学者的文章。

Code:**import** **pandas** **as** **pd**
**import** **numpy** **as** **np**
**import** **os**

*#load twitter-archive-enhanced.csv into twitter_archive_df(*twitter-archive-enhanced.csv is the additional data provided by Udacity's course*)*
twitter_archive_df = pd.read_csv('twitter-archive-enhanced.csv')*#using Python's Tweepy library and store each tweet's entire set of JSON* 
*#data will be in a file called tweet_json.txt file.*

**import** **tweepy**#for the privacy, I put '...' instead of the real keys heehee
consumer_key = '...'  
consumer_secret = '...'
access_token = '...'
access_secret = '...'

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_secret)

api = tweepy.API(auth, wait_on_rate_limit=**True**, wait_on_rate_limit_notify=**True**)

**import** **json**

page_no_exist = []
retweet_count_and_favorite_count = []#Writing and Reading Twitter JSON
**with** open('tweet_json.txt', mode="w") **as** file:
    **for** i **in** list(twitter_archive_df.tweet_id):
        **try**:
            tweet = api.get_status(str(i))
            file.write(json.dumps(tweet._json))
            retweet_count_and_favorite_count.append({
                "tweet_id" : str(i),
                "retweet_count" : tweet._json['retweet_count'],
                "favorite_count" : tweet._json['favorite_count']
            })
        **except**:
            page_no_exist.append(i)retweet_count_and_favorite_count = pd.DataFrame(retweet_count_and_favorite_count, columns=["tweet_id",'retweet_count', 'favorite_count'])

第二步:评估和清理数据(这里是完整代码

在评估过程中,我发现了一些问题,并记录在两个部分:质量问题整洁问题:

为质量问题:

  • 冗余转发行
  • 多余的“回复用户推文”行
  • tweet_id 883482846933004288,778027034220126208 中的 rating _ 分子错误,给出了小数点后的数字而不是整数。
  • 没有名字的狗,取了“a”或“an”而不是“None”
  • 有些 rating_denominator 不是 10
  • “时间戳”、“tweet_id”的数据类型错误
  • 源列中的行有 95%以上是重复的。

为整洁问题

  • 同一类别的冗余列,现在分为["doggo "," flooter "," pupper "," puppo"]列,但是我们只需要一个" stage "列

在这里,我挑选了下面两个我认为最有趣的清洁来展示,但是如果你想看我为这个项目做的整个清洁过程,请在这里查看清洁过程的完整代码。

清洁 1:没有名字的狗,但被赋予“a”或“an”的名字,而不是“None”

操作:查找错误名称列表,并使用 for 循环给出单个名称“无”。

Code:wrong_name_list = list(twitter_clean_df.query('name == "a" or name == "an"').index)**for** i **in** wrong_name_list:     
    twitter_clean_df.name[i] = "None"

测试结果:

**for** i **in** wrong_name_list:
    **if** twitter_clean_df.name[i] != "None":
        print("wrong name")(nothing is shown.)

清洁 2。同一类别的冗余列。原始数据集包含“doggo”、“flooter”、“pupper”和“puppo”列,但我们只需要一个“stage”列来包含它们。

动作:将四列(“doggo”、“flooter”、“pupper”、“puppo”)转换为一个“stage”列,然后删除这四列。

Code:twitter_clean_df['stage']=**None** # I try to add all the values from the four columns together, and then drop the "None" after that.twitter_clean_df['stage'] = twitter_clean_df.doggo + twitter_clean_df.floofer + twitter_clean_df.pupper + twitter_clean_df.puppotwitter_clean_df['stage'].value_counts()

好了,现在我要去掉每行中所有的【无】

twitter_clean_df['stage'] = twitter_clean_df['stage'].map(**lambda** x: x.replace("None",""))twitter_clean_df['stage'].value_counts()

这大概是我想要的,但是我们可以看到一些狗被记录为两个阶段,所以让给他们在两个词之间的“,”符号。

(以“doggopupper”为例。我们应该把它写成“doggo,pupper”)

Code:
twitter_clean_df.loc[twitter_clean_df.stage == 'doggopupper', 'stage'] = 'doggo, pupper'
twitter_clean_df.loc[twitter_clean_df.stage == 'doggopuppo', 'stage'] = 'doggo, puppo'
twitter_clean_df.loc[twitter_clean_df.stage == 'doggofloofer', 'stage'] = 'doggo, floofer'

测试结果:

twitter_clean_df.stage.value_counts()

搞定了。

第三步:进行探索性数据分析,回答问题并创建可视化(完整代码在此)

让我们通过可视化来进行探索性的数据分析,从问题 1、2、3 开始!

研究问题 1:哪种类型的狗获得了最高的转发数和喜爱数?

# we only need the rows with stages
df_stage = df[df["stage"].isnull()==False]#visualization 'Average favorite counts by stages of dogs'by_stages = df_stage.query('stage=="pupper" or stage=="doggo" or stage=="puppo" or stage=="floofer"')favorite_counts_by_stages = pd.DataFrame(by_stages.groupby('stage').favorite_count.mean().sort_values())favorite_counts_by_stages['stages'] = favorite_counts_by_stages.indexfavorite_counts_by_stages.plot(x="stages",y='favorite_count',kind='barh',title="Average favorite counts by stages of dogs",color='r', alpha=0.6)

好了,就在完成所有的可视化之后,我发现 puppo 和 puppy 的意思是一样的 XDDD,都是小狗的意思。(我应该事先研究一下那些奇怪的术语...)而弗洛弗的意思是大狗,和人类一样大。doggo 是狗的正常尺寸。这里,我应该将阶段的名称改为“大小”,而不是使用阶段。

favorite_counts_by_stages.rename(columns={'stages':'size'}, inplace=True)favorite_counts_by_stages.plot(x="size",y='favorite_count',kind='barh',title="Average favorite counts by size of dogs",color='r', alpha=0.6)

#visualization 'Average retweet counts by the size of dogdf_size = df[df["size"].isnull()==False]by_size = df_size.query('size=="pupper" or size=="doggo" or size=="puppo" or size=="floofer"')retweet_count_by_sizes = pd.DataFrame(by_size.groupby('size').retweet_count.mean().sort_values())
retweet_count_by_sizes['size'] = retweet_count_by_sizes.index
retweet_count_by_sizes.plot(x="size",y='retweet_count',kind='barh',title="Average retweetcounts by size of dogs",color='r', alpha=0.6)

注意:它们看起来都像是小狗的转发数和喜爱数是其他狗的两倍。(既然 pupper 和 puppo 应该加在一起。)

研究问题 2:转发次数最多的前三种狗是什么?

由于 Udacity 提供的数据集有一个名为预测品种的列,有人使用了一个机器学习模型来预测每个帖子的狗图片。它包含了每个帖子的一些可能的品种的概率。

我的想法是从每个预测结果中选择最高的概率,看看哪个预测品种的平均转发数最高。

#extract data that has retweet_count and save them into variable "retweet_and_favorite_count"#get the index of ids with retweet_count
#create a column called 'predicted_breed' for putting the predicted breed later on.retweet_and_favorite_count = df[df["retweet_count"].isnull()==False]
id_with_retweet = list(retweet_and_favorite_count.tweet_id)
retweet_and_favorite_count['predicted_breed'] = Noneretweet_and_favorite_count.head()

好的,你可以看到最后一列叫做“预测品种”,包含“无”,用于以后存储预测品种。

我将使用 Udacity 提供的数据集“df_image”来查找包含预测品种的 id。

# find the ids that are also in the df_image, and save the id in has_data.has_data = []for i in id_with_retweet:
    if len(list(df_image[df_image['tweet_id']==i].p1_dog.index))!=0:
        has_data.append(i)

len(has_data)

输出:1643

我现在将使用 for 循环,通过选择每个预测品种的最高概率来确定它们的预测品种。

顺便说一下,Medium 中的代码格式很难阅读代码,如果你认为下面的结构有点复杂,请在这里查看原始的代码

for i in has_data: index = list(retweet_and_favorite_count[retweet_and_favorite_count['tweet_id']==i].index)[0]
    if list(df_image[df_image['tweet_id']==i].p1_dog.values)[0] == True:
        retweet_and_favorite_count.predicted_breed[index] = list(df_image[df_image['tweet_id']==i].p1.values)[0]
    elif list(df_image[df_image['tweet_id']==i].p2_dog.values)[0] == True:
        retweet_and_favorite_count.predicted_breed[index] = list(df_image[df_image['tweet_id']==i].p2.values)[0]
    elif list(df_image[df_image['tweet_id']==i].p3_dog.values)[0] == True:
        retweet_and_favorite_count.predicted_breed[index] = list(df_image[df_image['tweet_id']==i].p3.values)[0]

测试结果:

retweet_and_favorite_count[retweet_and_favorite_count["predicted_breed"].isnull()==False].sample(5)

*# assess the data*

retweet_and_favorite_count.retweet_count.describe()

通常,如果有一些数据超过平均值+- 3*std,意味着有一些异常值。在这种情况下,所有的品种都是预测的,所以我想创建一些标准来过滤掉离群值或不准确的数据。

我决定使用不保守的 3 个标准来提取结果:
1。品种应该至少有 10 个计数,因为数据会更稳定。
2。每个品种的标准差应低于 4447(整个数据集的标准差)
3。其均值大于 2534(整个数据集的均值)。

result_df = retweet_and_favorite_count.groupby('predicted_breed').retweet_count.describe()
result_df = result_df.query('count >= 10.0')
result_df = result_df[result_df['std'] < 4447]
result_df = result_df[result_df['mean'] > 2534]
result_df = result_df.sort_values(by=['mean'], ascending=**False**)

试验

result_df.head(3)

最后,我们来形象化一下。

*#visualization 'Top 3 highest average retweet counts by predicted breeds'*
locations = [1,2,3]
top3 = result_df.head(3)

mean_retweet_counts = list(top3['mean'])

labels =  list(top3.index)

plt.bar(locations, mean_retweet_counts, tick_label=labels)

plt.title('Top 3 highest average retweet counts by predicted breeds')
plt.xlabel('Breeds of dogs')
plt.ylabel('retweet counts');

注:大 Pyenees、羊毛衫和金毛寻回犬是预测品种中平均转发次数最高的前 3 名。而且,排名第一的品种比排名第二的品种平均多 600 个计数。

第四步:理解局限性

在得出任何结论之前,最好告知局限性,以及其他人为因素是否会影响数据源的参与。在评估数据和进行探索性数据分析的过程中,我发现我收集的数据和 Udacity 提供的数据集存在一些局限性。

限制:

  • 限制 1:只有 15%的数据记录大小。然而,我们没有进行置信区间或假设检验来测试我们对规模的结论是否可信,所以观众应该在某种程度上怀疑我们的见解。
  • 限制二:我不确定创造机器学习模型的人是如何预测品种的,所以预测的品种应该会受到观众一定程度的怀疑。我们的结论中没有 100%确定的事情。

第五步:总结

  1. 与 doggo 和 floofer 相比,Puppy 的转发数和喜爱数是其他尺寸的狗的两倍。(既然 pupper 和 puppo 应该加在一起。)
  2. 就品种而言,大白熊、羊毛衫和金毛寻回犬是预测品种中平均转发次数最高的前三种。而且,排名第一的品种比排名第二的品种平均多 600 个计数。

第六步:可行的见解

如果你想经营一个宠物社交媒体账户,并且你还没有决定哪种类型的狗是主角(如果你可以选择…),或者如果你已经有一个狗宠物账户,并且你想收养或购买更多的狗,这里有一些见解:

1.去找小狗:)

2.就品种而言,选择大白熊、卡迪根、金毛比其他狗更容易吸引观众的参与。

所以,结合这两个观点:

大白熊犬是你的首选!

克里斯蒂娜·安妮·科斯特洛在 Unsplash 上的照片

感谢您花时间阅读这篇文章。

如果你是想找数据分析师实习生的雇主,这是我的 LinkedIn 或者通过我的电子邮件联系我(ychen596@insite.4cd.edu

如果你也在数据科学/商业分析领域工作,请随时通过 IG( @jchen_mmm )、电子邮件或下面的评论给我任何反馈!

使用 Excel 进行数据分析

原文:https://towardsdatascience.com/data-analysis-using-excel-885f337c85c?source=collection_archive---------9-----------------------

学习有用的 Excel 技术,为探索性数据分析创建强大的仪表板

在 Tableau 和 PowerBI 等工具出现之前,Microsoft Excel 是所有行业用来处理数据的最重要的工具。即使在今天,Excel 也因其强大的数据分析功能而被广泛使用。

在本文中,我将向您介绍一些非常有用的 Excel 方法来分析数据,并准备一个视觉上吸引人的仪表板呈现给最终用户。在本节中,我使用了 Kaggle 中共享的空气质量数据。这是数据集的快照,

空气质量数据集

该数据针对印度各邦 2015 年至 2020 年的各种污染物水平,包括空气质量指数(AQI)。AQI 被定义为一个整体方案,该方案将单个空气污染相关参数(SO2、CO 等)的加权值进行转换。)转换成一个数字或一组数字。空气质量指数有助于公众以简单的方式了解空气质量。AQI 类别或桶用于根据值将 AQI 值分为六个类别,即:好(0-50)、满意(51-100)、中等(101-200)、差(201-300)、非常差(301-400)、严重(401-500)。

数据透视表

Excel 最重要也是最广泛使用的功能之一是数据透视表。这里我使用了一个数据透视表来根据年份和城市对数据进行分组。您可以选择整个数据,并从 Excel 的“插入”菜单中插入一个数据透视表

数据透视表

我按平均值汇总了值字段,因为我希望我的表显示每年的平均污染物水平。默认情况下,Excel 使用计数。您可以选择根据年、月或日过滤数据。使用数字格式选项减少小数位数或使其成为整数。数据透视表准备就绪后,您可以通过单击数据透视图选项,使用合适的数据透视表对数据进行可视化分析。这里我使用了堆积条形图来绘制数据。

我还尝试在数据透视表中使用不同的值和过滤选项。这些图表非常适合在仪表板中使用,出于演示目的,将在下面讨论这些图表。从图表中可以清楚地看到,由于 Covid19 锁定,印度所有邦的 AQI 在 2020 年都有所下降。

AQI 平均值和 AQI 类别计数

仪表盘

一旦所需的图表准备就绪,就该创建一个有吸引力的、自我解释和交互的仪表板了。在创建仪表板方面,Excel 与 Tableau 等任何其他分析工具一样出色。在一张新的纸上复制所有的图表。您可以从“页面布局”菜单中删除表单上的网格线。要使您的仪表板具有交互性并连接所有图表,您可以添加切片器。选择一个图表,并从“插入”菜单中为任何必填字段选择“切片器”。在这里,我为年份、日期、AQI 桶和城市选择了切片器。将切片器连接到所有图表,以便用户可以轻松地分析数据的各种组合。右键单击切片器并选择报告连接选项。选择所需的数据透视表以建立连接。这必须对所有切片器重复进行。通过这种方式,您可以在 Excel 中在几分钟内创建高度交互式的仪表板。

空气质量仪表板

接下来,我将向您展示一些真正有用的 Excel 特性,它们将有助于有效地管理大型数据集。我将使用 Kaggle 的 Covid19 数据集来解释这些特性。该数据探讨了印度各邦的医院数量及其应对 Covid19 的准备情况。这是数据集的快照,

Covid19 数据集

纵向查找函数

当数据集中有许多列和行时,Vlookup 是一个搜索特定数据的便捷功能。此外,该功能的另一个用途是,当许多用户处理特定数据集时,它可以用作一个简洁的查找表单。例如,在给定的数据集中,如果您想要快速找到某个特定州的公共卫生中心的数量,那么可以对该函数进行建模,以便从整个数据集中只提取所需的数据。

您可以从 Excel 的“公式”菜单中插入 vlookup 函数。vlookup()函数的格式如下:
=VLOOKUP(要查找的内容,要查找的位置,包含要返回的值的范围内的列号,返回近似或精确匹配—表示为 1/TRUE,或 0/FALSE)。例如,对于上面给定的数据集,我有下面的 vlookup 函数,=VLOOKUP(G47,B1:I38,8,FALSE)。这是我使用 vlookup 函数对数据创建的输出。

纵向查找函数

我在两个领域使用了 vlookup 函数,即公共卫生设施总量和人口。我使用的搜索字段是 State。因此,无论我想搜索哪个州的数据,我只需在 state 字段中输入,我的 vlookup 函数就会自动获取结果。这适用于任何数据集,如销售、财务等。用户可能希望在海量的行和表中搜索特定的数据。这种定制的数据搜索/查找可以在新的工作表中实现,并锁定公式的任何修改。用户可以像搜索表单一样简单地使用它,而不是搜索数据。

与 Vlookup()类似,Excel 中还有几个其他的查找函数,分别是 Hlookup()、lookup()和 Xlookup()。关于其使用的更多信息可以从微软门户获得。

下拉列表

Excel 的另一个很酷的功能是向分类数据字段添加一个下拉列表。这在多个用户处理数据时会很方便。例如,如果多个用户正在分析同一个工作表,并且他们正在输入一些状态,那么您可以添加一个包含他们所有姓名或状态的字段,他们可以很容易地从下拉列表中进行选择。

下拉列表

我在空气质量数据集中的 AQI 类别列中添加了一个下拉列表。首先,您需要在行或列中复制应该放入下拉列表的值集。接下来,选择要添加下拉列表的单元格,从数据菜单中选择数据有效性选项。在此,为“允许验证标准”选择“列表”,为“来源”选择您已输入要添加到列表中的分类值的行/列。瞧,你的列表准备好了,你可以把它复制到数据集中所有需要的单元格。用户只需从下拉列表中选择值,这反过来有助于您控制表中输入的内容。

重复删除和数据分割

数据清理是任何数据分析过程的关键要素。分析师的一项常见任务是消除数据中的重复值。在 Excel 中处理重复项,首先选择数据区域,然后从“数据”菜单中选择“删除重复项”选项。在这里,您可以选择数据验证要包括哪些列。单击“确定”按钮后,如果数据集中存在重复值,Excel 将显示已删除的重复值的数量。

删除重复项

Excel 中另一个有助于处理由分隔符分隔的数据的有用功能是文本到列。这在处理日期和时间时非常方便。使用它,你可以很容易地根据月、日、年、小时等划分日期和时间。首先,您需要选择要拆分的数据,然后从“数据”菜单中选择“文字到列”选项。拆分为列是一个三步过程。在第一步中,您可以选择分隔符或固定宽度选项。在第二步中,您必须选择分隔符的类型。我选择了拆分日期列,因此指定/作为分隔符。在第三步中,您可以选择希望 Excel 粘贴拆分数据的位置。如下图所示,日期将被分为三列,稍后您可以将其重命名为日、月和年。因此,没有太多的麻烦,数据是根据您的要求分裂。

文字分列

这些是一些最常用的 Excel 功能,对数据分析有很大帮助,在进行数据预处理和报告时节省了大量时间。我已经使用相同的数据集通过 Tableau 进行分析,并在 Kaggle 中编写了几个关于空气质量分析Covid19 影响的内核。

使用 JHU CSSE 新冠肺炎日报数据集进行数据分析

原文:https://towardsdatascience.com/data-analysis-using-jhu-csse-covid-19-daily-report-dataset-c8a9120ed23?source=collection_archive---------32-----------------------

数据分析使用 JHU CSSE 新冠肺炎数据。照片由 Pexelscottonbro 拍摄

数据科学实践指南

数据科学方法论中的疫情报表数据集查询

免责声明:本文中使用的数据集由约翰霍普金斯大学代表其工程系统科学中心在知识共享署名 4.0 国际版(CC BY 4.0)下授权。版权所有约翰·霍普金斯大学 2020 年

从头开始构建数据框可能有点乏味。因此,您通常要做的不是从一些数据序列创建数据框,而是导入数据。在本文中,您将通过从约翰霍普金斯大学 Github 页面导入新冠肺炎每日报告案例数据框来分析带有熊猫的数据集。

图 1:从 JHU CSSE 新冠肺炎数据导入 CSV 文件。图片作者作者

如图 1 所示,我们调用import pandas as pd来导入pandas库。接下来,您可以用read_csv导入 CSV 文件,并将其赋给一个变量。在这种情况下,我们使用covid_daily_report作为变量。

令人印象深刻的是,因为它现在在熊猫数据框中,我们可以利用熊猫提供的所有功能,并操纵查看和更改这些数据。

导入数据后,您可能希望修改并导出数据。让我们看看如何导出数据框。导入后,我们没有对数据框进行任何更改,但我们还是要将其导出。

图 2:将数据帧导出到本地磁盘。图片作者作者

如何导出数据帧的过程如图 2 所示。您将调用这个函数,covid_daily_report.to_csv,然后传递一个字符串名称作为备份文件。接下来,您应该通过创建一个新变量并调用read_csv函数来调用导出的 CSV 文件,从而尝试导入备份文件。

将数据导入 pandas 的典型方式是读取一个 CSV 文件,然后一旦您对其进行了更改或操作,您就可以将它作为一个修改过的数据集导出为一个 CSV 文件。

描述数据

为了描述数据框中的数据类型,我们可以使用dtypes属性。你会注意到,有些函数调用后有括号,有些没有。不带括号的是属性,比如dtypes,而带括号的是函数,比如covid_daily_report.to_csv()

图 3: dtypes 属性。图片作者作者

属性和函数的区别在于,函数将执行一些步骤,而属性dtypes只是存储的关于covid_daily_report数据帧的一些元信息。关于属性和函数之间的区别,这是需要记住的两件主要事情。

属性会告诉你一些关于基于列的数据的信息。这个属性将告诉我们每一列的类型(图 3)。让我们看看我们可以利用该数据框做些什么。covid_daily_report.columns,它是一个属性,因为它没有括号。这将告诉我们列名,并以列表的形式返回。

图 4:列属性。图片作者作者

您还可以将该列表存储到一个新的变量中,如图 4 所示,您可以对该列表执行一些操作,然后在以后使用它来操作您的数据框。这只是演示了如何从数据框中访问两种主要类型的属性。索引呢?可以叫covid_daily_report.index。这将返回索引的范围,从 0 开始,到 58 结束。

接下来,您将使用 describe 函数covid_daily_report.describe()从数据框中返回一些统计信息。您会注意到这个函数将只返回数字列,这意味着它只返回 float 和 int 数据类型。

图 5:索引和描述。图片作者作者

重要的是要记住,这些类型的描述函数和dtypes属性是您在开始探索一组新数据时可能会遇到的。

也许我们想从数据框中获取更多信息。您可以通过调用函数covid_daily_report.info()来完成此操作。它有点像结合了数据类型的索引。你必须开始运行像 info 和 describe 这样的功能,同时探索你的数据并获得一些相关信息。

图 6:数据帧的详细信息。图片由作者

您可以对您的数据框调用另一种统计分析,例如均值。covid_daily_report.mean(),它会给你你的数值列的平均值。

图 7:熊猫的平均功能。图片作者作者

接下来,covid_daily_report.sum()。它将对所有不同列的值求和。这实际上是数据框列中内容的组合。在整个数据框上调用它是没有用的,所以也许我们在单个列上这样做,例如:

covid_daily_report["Confirmed"].sum()
covid_daily_report["Deaths"].sum()
covid_daily_report["Recovered"].sum()
covid_daily_report["Active"].sum()

图 8:熊猫的求和函数。图片作者作者

最后,如果您想要关于数据框长度的最后一点信息,您可以通过将它传递给 len 来计算出您当前正在处理的数据框的长度,我们可以看到我们的数据框中有 58 行。

图 9:数据帧的长度。图片由作者

查看和选择数据

您已经了解了描述我们导入到数据框中的数据的几种不同方式。让我们来看看查看和选择数据的一些不同方法。

图 10:熊猫的头部功能。图片作者作者

您要做的第一件事是查看数据框的头部。你可以调用covid_daily_report.head(),记住这个后面有括号,所以它是一个函数。此函数将返回数据框前五行中的第一行。实际上,您可能会以某种方式操作数据框,然后经常调用 head。我们的数据框仅包含 58 行。因此,调用整个事情不是太糟糕,但想象一下,如果你有成千上万的这些。

head 所做的是在一个很小的空间内给你一个快速的快照,显示你的数据框所包含的内容。如果您在这里或那里进行了一些快速的更改,您可能想要查看前五行,如果五行不够呢?也许你想看看前八名。head 的美妙之处在于,你可以在这里输入一个数字,它会返回那么多行。

图 11:熊猫的尾巴功能。图片作者作者

出于某种原因,如果您需要返回数据框的底部,您可以使用.tail(),它将返回底部的行。如果您在数据框的底部而不是顶部进行修改,这将非常方便。变化只会出现在底部。

接下来我们要看的两个函数是lociloc。我们将在这里创建一个系列,以便详细演示lociloc之间的区别。我们要做一个叫cars的系列,在这里设置一些索引。默认情况下,如果我们创建了一个序列,索引将从 0 开始递增。然而,我们不会在这里这样做,因为我们想看看lociloc之间的区别。

图 12:pandas 系列中的 loc 和 iloc 示例。图片作者作者

我们这里有 7 个随机索引列表。如果我们调用cars.loc[6],它将返回两个列表,奔驰和福特,因为loc引用了一个索引号,并且两者的索引号都是 6。另一方面,如果我们调用cars.iloc[6],它只会返回马自达,因为它占据了 6 号位置。iloc指零分度法的位置。

图 13:数据帧中的 loc 和 iloc。图片由作者

关于lociloc有两个要点你要记住,iloc是指位置,loc是指索引。这件事的美妙之处在于,使用lociloc你可以使用切片。如果您曾经使用过 Python 列表,您可能对切片很熟悉。这和调用 head 函数是一样的。

图 14:在 loc 中切片,和熊猫的头部功能一样。图片作者作者

我们之前已经看到了这一点,但是让我重复一下关于列选择的信息。假设您想要选择一个特定的列。选择列的方法是在数据框名称旁边的方括号中输入其名称。您可能会看到两种方式,我希望您熟悉这两种选择列的方式,括号符号和点符号。

图 15:pandas 中带括号符号的列选择。图片由作者

图 16:pandas 中带点符号的列选择。图片由作者

关于点符号,你应该知道的一件事是,如果你的列名中有一个空格,点符号将不起作用。因此,您可以考虑使用括号符号。

图 17:列选择中的过滤器。图片作者作者

另一个有趣的部分是,您可以在列选择中放置一点过滤器,如图 17 所示。

图 18:熊猫视觉化的例子。图片作者作者

我们将在这里看一些可视化。你要打电话给covid_daily_report[“Active”].plot()。这将返回城市的活动案例的情节。熊猫的美妙之处在于,你可以通过给定的数据快速获得分析。获得可视化是快速理解正在发生的事情的好方法。

你想看的另一件事是另一种图,叫做直方图。这是观察分布的好方法。分布是一个关于数据传播的奇特词汇,您可以比较图 18 中的可视化。

操纵数据

作为数据科学家或机器学习工程师,研究的一部分是学习如何提出不同的问题。想想我如何利用这些数据,然后试着找出答案。话虽如此,我们还是来看看这里,如何用熊猫操纵数据。

一个真实的数据集通常在某一行包含缺失数据,称为NaN。只是说明那里没有价值。

如果你想用一些东西来填补这些缺失的值呢?

图 19:重新分配方法和就地参数方法。图片由作者

有一个函数叫做fillna,它用值填充这些,并且可以传递一些值并填充它。例如,您想用 0 填充“已确认”列中的一些缺失值。在 pandas 中有两种方法做同样的事情,重新赋值方法和就地参数。您可以在图 19 中看到重新分配和就地分配之间的区别。

图 20:熊猫的 dropna 功能。图片作者作者

例如,我们很高兴填写了“Confirmed”列,但是我们想忽略另一行的缺失值,因为缺失值对我们的数据分析没有帮助。事实上,它们可能是有用的,但是我们想知道如何摆脱它们。有一个功能叫dropna。您可以看到行数从 58 减少到 34 的结果(图 20)。

如果我们想要重新访问丢失的值,该怎么办?

由于我们在这里创建了一个新变量covid_daily_report_drop_missing
,您仍然可以通过调用covid_daily_report变量来访问原始数据帧。如果您弄乱了真实数据框,也可以重新导入 CSV 文件。向上滚动到文章的开头,查看如何重新导入图 1 中的 CSV。

图 21:从现有的列创建一个新的列。图片作者作者

接下来,我们如何从现有的列创建数据?Pandas 有几种不同的方法来生成数据,比如构建一个新列,或者用计算操作另一列中的现有数据。例如,您想计算出每个城市的恢复案例百分比。您可以创建一个名为“Recovered_Percentage”的新列,并从“Recovered”列进行一些计算,以获得百分比率,如图 21 所示。

图 22:在 pandas 中放置一列。图片由作者

也许你意识到你不再需要“Recovered_Percentage”列了。如果你想删除其中一列,你可以使用drop功能。它需要轴和原地参数。Axis 等于 1,因为 1 反映列,0 反映行。在这种情况下,您希望消除列,而不是行,所以我们在轴上放置 1。

随机抽样数据

当我们开始将机器学习算法应用于我们的数据时,他们最重要的步骤之一是创建一个训练验证和测试集。做到这一点的一个步骤是随机排列数据的顺序。因此,用一个sample函数来混合索引是一个很好的方法。

图 23:pandas 中的示例函数。图片作者作者

sample函数从数据帧中抽取一个样本,其中包含一个参数frac。参数是整数形式。例如,为了获得 50%的数据,我们将 0.5 放入参数中。因此,如果你想混洗所有东西,100%的数据样本,我们在参数中传递 1。这将返回数据的混排索引。

图 24:从数据帧中只选择 20%的样本。图片作者作者

实际上,您可能只需要 20%的数据。在frac参数中,可以传入 0.2 的值。这将从数据帧中返回混洗的 20%。这是您将来在项目中处理大量数据时必须考虑的问题。

一个问题是,我们如何让这些索引恢复秩序?有一个函数叫做reset_index,后面跟着两个参数dropinplace,如图 25 所示。

图 25:重置混洗索引。图片由作者

我们要看的最后一件事是如何对列应用函数。pandas 中的 Apply function 将允许您对特定的列应用一些函数,无论是 NumPy 还是 lambda。在图 26 中,您可以看到我们将 lambda 函数应用于“Active”列。这将把“活动”列的值与“死亡”列的值相加,并将其重新分配到“活动”列。

图 26:对列应用一个函数。图片作者作者

结论

您已经看到了 pandas 可以做的一些事情,特别是使用 Python 从某个数据集进行数据分析。是时候通过访问 Github 中的 analysis Jupyter 笔记本文件来练习您的技能了。

关于作者

Wie Kiang 是一名研究人员,负责收集、组织和分析意见和数据,以解决问题、探索问题和预测趋势。

他几乎在机器学习和深度学习的每个领域工作。他正在一系列领域进行实验和研究,包括卷积神经网络、自然语言处理和递归神经网络。

连接上LinkedIn

**Citation**Dong E, Du H, Gardner L. An interactive web-based dashboard to track COVID-19 in real time. Lancet Inf Dis. 20(5):533-534\. doi: 10.1016/S1473-3099(20)30120-1**References**#1 [COVID-19 Data Repository by the Center for Systems Science and Engineering (CSSE) at Johns Hopkins University](https://github.com/CSSEGISandData/COVID-19/tree/master/csse_covid_19_data/csse_covid_19_daily_reports_us)#2 [Github repositories for the analysis](https://github.com/wiekiang/covid-jhu-csse)

编者注: 迈向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

金融中的数据分析和可视化—使用 Python 对股票进行技术分析

原文:https://towardsdatascience.com/data-analysis-visualization-in-finance-technical-analysis-of-stocks-using-python-269d535598e4?source=collection_archive---------7-----------------------

如何使用 Pandas、Matplotlib 和 Seaborn 等 Python 库从日价量股市数据中获取洞察。

随着分析越来越多地渗透到我们生活的方方面面,金融业无疑是最早抓住这一趋势的行业之一。在本文中,我试图展示如何将数据分析和可视化技术融入金融领域。

1.关于数据

为了进行分析,我使用了在国家证券交易所(NSE) 上市的以下股票从 2018 年 2 月中旬到 2020 年 2 月的两年历史数据

  • HDFC 有限公司
  • 太阳制药工业有限公司
  • 塔塔咨询服务有限公司
  • 金达尔钢铁和电力有限公司
  • 喜洋洋食品厂有限公司

我之所以选择这些股票,是因为我在最近的实习期间研究过这些股票。你可以选择自己的股票组合和时间周期来进行分析。

我选择的股票来自不同的板块和市值。随着本文的深入,您将会看到它的优势。首先,我们将单独研究 HDFC 股票,然后进行综合分析。对于这一部分,我已经从雅虎财经下载了 HDFC 股票历史数据的 csv 文件。在下一节中,我们将使用一个非常棒的工具直接从网上提取股票价格。

2.了解数据和一般统计

导入必要的库—

import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import datetime
import warnings
warnings.filterwarnings('ignore')

csv 文件中读取数据并显示前几行—

HDFC_df = pd.read_csv(“HDFC.csv”) 
HDFC_df.head()

输出:

由于我们分析的时间范围很大,我们可以放宽对小数位数的考虑。

HDFC_df = HDFC_df.round(2)
HDFC_df.head(2)

输出:

更好!现在,让我们决定数据集的形状—

HDFC_df.shape

输出: (491,7)

我们的 HDFC 数据集有 491 行 7 列。接下来,我们检查数据集是否有空值—

HDFC_df.isnull().sum()

输出:

从数据集中删除空条目—

HDFC_df.dropna(inplace = True, axis = 0)

现在,让我们检查每一列的数据类型—

HDFC_df.dtypes

输出:

正如我们所看到的,'日期'列的格式不合适。Pandas 具有以更智能的方式处理时间序列数据的内置功能。但是为了利用 Pandas 的日期功能,我们需要确保' Date' 列的类型是' datetime64(ns)'。

HDFC_df['Date'] = pd.to_datetime(HDFC_df['Date'])
HDFC_df.head(2

为了得到我们进行分析的总持续时间——

HDFC_df[‘Date’].max() — HDFC_df[‘Date’].min()

输出:时间增量(' 729 天 00:00:00 ')

一年大约有 252 个交易日,平均每月 21 天,或每季度 63 天。在可能的 365 天中,有 104 天是周末(周六和周日),证券交易所不营业。

接下来,我们将使用 Pandas 的 describe() 函数来获得关于 HDFC 股票在过去几个月中表现的高级概述

HDFC_df.iloc[-90:].describe().astype(int)

输出:

在过去的 90 天里,HDFC 股票的平均收盘价约为₹2307.大约 75%的时间里,该股在₹2421 下方交易,最高价为₹2492.单日最大交易量为 8808006 股,中位数为 2776142 股。

3.股票价格的总体变化

在我们继续深入研究之前,我们将把‘Date’列设置为 dataframe 的索引。它使绘图变得容易。

HDFC_df.index = HDFC_df[‘Date’]

现在画出股票在 2 年期间的收盘价(调整后),以了解股票在给定期间的总体表现。

HDFC_df[‘Adj Close’].plot(figsize = (15,8))
plt.show()

输出:

在上面的图中,如果你注意到,在 2018 年 9 月左右的某个时候,股票价格急剧下降。除了“九月效应”,HDFC 股价的普遍下跌还可以归因于中美之间不断升级的关税战,这场战争对印度金融市场产生了连锁反应。

4.每日百分比变化(每日回报)

股票价格的每日百分比变化是根据连续两天收盘价之间的百分比变化计算的。假设股票昨天的收盘价是₹500,今天的收盘价是₹550.所以,百分比变化是 10%。即((550–500)/500)* 100。这里没有神秘!

因此,我们将引入一个新列' Day_Perc_Change ',表示股票价格的每日回报。这可以使用 python 中内置的 pct_change() 函数来完成。

HDFC_df[‘Day_Perc_Change’] = HDFC_df[‘Adj Close’].pct_change()*100
HDFC_df.head()

输出:

您会注意到在‘Day _ Perc _ Change’列中的第一个值是 NaN。我们将放弃这一行。

HDFC_df.dropna(axis = 0, inplace = True)

以图表的形式展示每日收益—

HDFC_df[‘Day_Perc_Change’].plot(figsize = (12, 6), fontsize = 12)

输出:

可以观察到,在大部分时间里,回报率在-2%到 2%之间,两侧都很少有超过 6%的峰值。

2018 年 9 月 24 日来自 BusinessLine 的新闻文章

同样,你可以找到股票价格大幅上涨/下跌时的类似新闻文章。

绘制每日回报分布直方图—

HDFC_df[‘Day_Perc_Change’].hist(bins = 50, figsize = (10,5)) 
plt.xlabel(‘Daily returns’)
plt.ylabel(‘Frequency’)
plt.show()#satistics
HDFC_df.Day_Perc_Change.describe()

输出:

日线回报直方图以原点为中心。在过去的两年里,平均日回报率约为 0.072,大部分时间日回报率低于 1%,这意味着 HDFC 股票在此期间波动较小。在此期间,观察到正方向的最高%变化为 6.46%,负方向为 6.56%。显然,我们没有任何“牛市”或“熊市”的例子!

5.趋势分析

接下来,我们添加一个新列' Trend ',其值基于我们上面计算的每日百分比变化。趋势由以下关系决定——

def trend(x):
  if x > -0.5 and x <= 0.5:
    return ‘Slight or No change’
  elif x > 0.5 and x <= 1:
    return ‘Slight Positive’
  elif x > -1 and x <= -0.5:
    return ‘Slight Negative’
  elif x > 1 and x <= 3:
    return ‘Positive’
  elif x > -3 and x <= -1:
    return ‘Negative’
  elif x > 3 and x <= 7:
    return ‘Among top gainers’
  elif x > -7 and x <= -3:
    return ‘Among top losers’
  elif x > 7:
    return ‘Bull run’
  elif x <= -7:
    return ‘Bear drop’HDFC_df[‘Trend’]= np.zeros(HDFC_df[‘Day_Perc_Change’].count())
HDFC_df[‘Trend’]= HDFC_df[‘Day_Perc_Change’].apply(lambda x:trend(x))HDFC_df.head()

输出:

我们希望看到股票在过去两年的走势。这可以想象成一个饼图,每个扇区代表每个趋势发生的天数百分比。我们将为‘趋势’列绘制一个饼图,以可视化每个趋势类别的相对频率。

为此,我们将使用带有趋势列的 groupby() 函数,在绘制饼图之前,将具有相同趋势的所有日期聚合到一个组中。

用饼图可视化趋势频率—

DFC_pie_data = HDFC_df.groupby('Trend')
pie_label = sorted([i for i in HDFC_df.loc[:, 'Trend'].unique()])
plt.pie(HDFC_pie_data['Trend'].count(), labels = pie_label, 
        autopct = '%1.1f%%', radius = 2)

plt.show()

输出:

从 2018 年 2 月中旬到 2020 年 2 月,HDFC 股票在大约 1.8%的时间里涨幅居前,在 1.6 %的时间里跌幅居前。在大约 12.4%的时间里,该股在某一天表现良好。同样,在大部分时间内(约 29.6%),股票价格变化很小。这些观察结果与我们在上一节看到的日收益率直方图一致。

6.每日回报和交易量

plt.stem(HDFC_df[‘Date’], HDFC_df[‘Day_Perc_Change’])
(HDFC_df[‘Volume’]/1000000).plot(figsize = (15, 7.5), 
                                 color = ‘green’, 
                                 alpha = 0.5)

输出:

(*每日交易量的规模已缩小,以匹配每日回报规模)

通过将每日交易量(绿色)与每日回报(蓝色)并列,观察到每当股票交易量高时,股票价格就会有相对较高的上涨或下跌,从而导致高回报。因此,在某一天,如果发生非常规的高交易量,那么人们可以预期市场会发生巨大的双向变化。股票交易量与股票价格的涨跌相结合,通常是交易者和投资者对特定公司信心的指标。

7.基于配对图和联合图的股票相关性分析

“永远不要把所有的鸡蛋放在一个篮子里”

每当我们寻求投资组合的多样化时,我们都不希望这些股票相互关联。数学上,任何一对股票之间的皮尔逊相关系数(也叫皮尔逊 R 值)应该接近于 0。背后的想法很简单——假设你的投资组合由高度相关的股票组成,那么如果一只股票下跌,其他股票也可能下跌,你就有可能失去所有投资!

我选择了上述股票进行相关性分析。所有这些股票都来自不同的行业和市值。你可以自由选择你感兴趣的股票。程序保持不变。

在上一节中,我们已经使用了预先下载的 csv 文件进行分析。在这一部分,我们将借助熊猫网络数据阅读器软件包提取股票价格。

# import package
import pandas_datareader.data as web# set start and end dates 
start = datetime.datetime(2018, 2, 15)
end = datetime.datetime(2020, 2, 14) # extract the closing price data
combined_df = web.DataReader([‘HDFC.NS’, ‘JINDALSTEL.NS’,    ‘JUBLFOOD.NS’,‘SUNPHARMA.NS’, ‘TCS.NS’, ‘^NSEI’],
‘yahoo’, start = start, end = end)[‘Adj Close’]

删除空值并显示前几行—

# drop null values
combined_df.dropna(inplace = True, axis = 0)# display first few rows
combined_df.head()

输出:

(^ NSEI 是国家证券交易所指数——nifty 50 的符号)

接下来,我们将使用 Seaborn pairplot 以成对方式分析不同股票之间的相关性。

# store daily returns of all above stocks in a new dataframe 
pct_chg_df = combined_df.pct_change()*100
pct_chg_df.dropna(inplace = True, how = ‘any’, axis = 0)# plotting pairplot  
import seaborn as sns
sns.set(style = ‘ticks’, font_scale = 1.25)
sns.pairplot(pct_chg_df)

输出:

请注意,相关性分析是针对股价的每日百分比变化(每日回报)而非股价进行的。

如果仔细观察,下三角形区域中的图与上三角形区域中的图是相同的,只是轴互换了。因此,分析这两组图就足够了。对角线代表直方图,就像上面看到的 HDFC 股票一样。

外卖:

HDFC、金达莱钢铁、喜洋洋食品、太阳医药和 TCS 的股票可以包含在一个投资组合中,因为没有两只股票显示任何显著的相关性。

缺点:

虽然配对图提供了一堆股票之间所有可能组合的非常好的可视化,但它没有提供任何详细的信息,如皮尔逊的 R 值或零假设 p 值来量化相关性。这就是联合阴谋的由来!

虽然 Pair plot 提供了对所有可能相关性的直观了解,但 Seaborn jointplot 提供了每对股票的详细信息,如皮尔逊 R 值(皮尔逊相关系数)。皮尔逊的 R 值范围从-1 到 1。负值表示变量之间的负线性关系,而正值表示正关系。皮尔逊的 R 值越接近 1(或-1)表示强相关,而值越接近 0 表示弱相关。

除了 Pearson 的 R 值之外,联合图还在边缘显示了各自的直方图以及零假设 p 值。

这是一个太阳医药和金达尔钢铁以及金达尔钢铁和 HDFC 股票的联合图表的例子

from scipy.stats import statssns.jointplot(‘SUNPHARMA.NS’, ‘JINDALSTEL.NS’, pct_chg_df, kind = ‘scatter’).annotate(stats.pearsonr)sns.jointplot(‘JINDALSTEL.NS’, ‘HDFC.NS’, pct_chg_df, kind = ‘scatter’).annotate(stats.pearsonr)plt.show()

输出:

外卖:

  • 金达尔钢铁公司诉太阳制药公司的皮尔逊 R 值为 0.24,非常小。这表明弱相关性。
  • 同样,在 HDFC 诉金达尔钢铁公司一案中,皮尔逊的 R 值为 0.29,表明 HDFC 和金达尔钢铁公司股票之间的相关性较弱。

上述来自联合图的结果为我们提供了数字,以确定我们先前通过目视观察联合图得出的见解。

当心!相关性并不是决定投资组合中包含哪些股票和删除哪些股票的唯一参数。还有其他几个因素在起作用。最好征求专家的意见,做出明智的决定。

9.波动性分析

波动性是金融市场最重要的支柱之一。如果一只股票的价值在短时间内发生剧烈变化,那么这只股票就具有高波动性。另一方面,较低的波动性意味着股票价值在一段时间内趋于相对稳定。这些运动是由几个因素造成的,包括需求和供给、情绪、公司行为、贪婪和恐惧等。从数学上来说,波动性是用一种叫做“标准差”的统计方法来衡量的,这种方法衡量的是资产与其平均值的偏离程度。

我们已经计算了 HDFC 股票和其他几只股票的日内回报。接下来,我们将计算每日回报的 7 天滚动平均值(也称为移动平均值),然后计算标准偏差(即方差的平方根)并绘制数值。放轻松,我们不用手动计算这一切;熊猫的‘rolling()’函数和‘STD()’函数只用一行代码就完成了我们的工作!

HDFC_vol = pct_chg_df[‘HDFC.NS’].rolling(7).std()*np.sqrt(7)
HDFC_vol.plot(figsize = (15, 7))

输出:

接下来我们将看到 HDFC 股票与太阳医药股票和 NIFTY50 指数的比较波动性分析。就像上面一样,我们用一行代码计算 7 天滚动平均值和标准差。熊猫确实使我们的生活变得容易!

volatility = pct_chg_df[['HDFC.NS', 'SUNPHARMA.NS', '^NSEI']].rolling(7).std()*np.sqrt(7)volatility.plot(figsize = (15, 7))

输出:

你可以观察到太阳医药的股票比 HDFC 的股票波动性高,而 Nifty 指数的波动性最小。这是意料之中的,因为阳光医药是一只中型股,与 HDFC 等大盘股相比,中型股通常具有更高的波动性。

许多交易者和投资者寻求更高波动性的投资,以获得更高的利润。如果一只股票不动,不仅波动性低,而且收益潜力低。另一方面,波动性非常高的股票或其他证券可能有巨大的利润潜力,但风险也同样高。

尾注

没有完全可靠的策略可以保证你的投资获利。在现实世界中,交易者在投资前会考虑很多因素。通过使用正确的策略和技术,我们只能增加我们的机会。我期待着在我的后续文章中介绍一些策略技术以及使用 python 的演示。

参考文献:

  1. 获取数据— 雅虎财经
  2. 对于金融技术细节— 投资媒介

———————— 免责声明 —本文纯属教育目的,不为任何公司或股票背书。在做任何买卖股票的决定之前,请咨询专家。
————

无需编程的数据分析

原文:https://towardsdatascience.com/data-analysis-without-programming-e2564ce7d3ae?source=collection_archive---------39-----------------------

如何使用 Excel 分析资产的价格变化

数据分析不一定是硬科学。从业者经常谈论如何看待数据,好像它是精通业务的从业者专有的某种秘密。今天我将向您展示如何使用 Microsoft Excel 来分析价格变化情况。当然,我们可以使用 Python 或其他高级语言,用几行代码来完成。然而,在这里您将了解这些行背后的内容——以及您在那里导入和使用的库。

杰森·斯特鲁尔在 Unsplash 上的照片

你可以阅读这篇文章,也可以把它作为一个教程。不管怎样,我希望它能直观有趣。我将模拟 S&P500 综合指数的价格变化。也就是说,我将向你们展示这些年来间谍百分比变化的分布情况。

用 Excel 分析间谍

首先,我会从雅虎财经下载关于间谍的历史数据。为了准确再现这个实验,你需要使用从 1993 年 1 月 28 日到 2020 年 10 月 3 日的数据,你可以在这里下载数据。如果您使用其他来源或其他时期的数据,您可能会获得稍微不同的结果。

Excel 中的间谍数据截图

打开后。csv 文件,您的数据应该看起来像左边的图像。我们将只使用该数据中的一个字段:Adj Close。通过单击标题并单击删除,可以随意删除列 A、B、C、D、E 和 G。

下一步是计算价格变化百分比(R)。这样做的公式是 R =(闭-开)/开。

百分比价格变化的 Excel 实现

我已经在左边的图片中包含了 excel 公式。简单地说,我们正在计算从昨天到今天价格变化了多少。

复制整个 B 列的公式,计算我们收集的 6971 天数据的值。接下来,我们将识别包含在我们刚刚计算的变更集合中的唯一值。我们将整个 B 列复制并粘贴到 E 列,我们将使用“数据”菜单下的“删除重复项”工具。

间谍多年来独特的价值观变化。

关于间谍价格的变化,我们已经有了一些有趣的见解。我们知道它在一天内的最大变化是+15%。我们还发现最大贬值幅度为-11%。这些见解带来了一个有趣的问题:“这些变化每隔多久发生一次?”。如果回答了这个问题,我们可以更深入地了解间谍每天的变化模式。

幸运的是,Excel 为我们提供了计算这些值出现次数的公式。=COUNTIF(RANGE,CONDITION)公式计算该范围内满足条件的次数。

计算值-11%发生了多少次

我在左图中演示了 COUNTIF 公式的用法。在那里,我统计了-11%的发生率。

如果我们将该公式应用于所有值,我们将获得刚刚收集的数据中每个值的计数。我们可以计算出每个事件的百分频率。有了这些数据,我们可以制作一个直方图。

价格变化发生概率

现在我们有了更多的见解:

  • 有将近 50%的概率价格完全不变。
  • 价格上涨 1%的概率高于价格下跌 1%的概率

这个分析有出错的空间:价格上涨 1%的概率是一个 孤立的 概率。这意味着我们刚刚计算了价格增加1%的变化。更多时候,我们感兴趣的是知道价格会上涨至少 1% 。同样,我们有兴趣知道价格何时会 下降至少 1%

为了计算这些合计值,我们可以简单地将相关事件的概率相加。例如,为了计算价格下降至少 10%的概率,我们可以将价格下降 11%的概率和价格下降 10%的概率相加。如果我们用这些计算来填充图表,我们将得到以下结果。

演示孤立概率和聚集概率的电子表格。

我们看到,价格以任何百分比下降的实际概率是 23.3%,而价格以任何百分比上升的概率是 28.4%。我们通过分别将小于零的变化概率和大于零的变化概率相加来获得这些值。为了改进我们的数据可视化,我们还应用了条件格式菜单中的色标。

这个分析可以用来做什么?

像这样简单的分析会非常有用。例如,一些交易者使用潜在的发生概率来运行蒙特卡罗模拟。其他人提供期权,可以奖励他们一个低赔钱概率的溢价。在其他领域,我们可以找到事件发生的潜在概率分布,比如公共汽车通常会晚点多长时间。

如果你喜欢这篇文章,不要忘记关注我,这样当我发布新内容时你会得到通知!你也可以在 TwitterLinkedIn 上关注我。直到下一个帖子!

你能想到上述分析的任何应用吗?你将如何进一步探索它?把它留在下面的回复中吧!

Data Analyst 3.0:数据工作流的下一次变革

原文:https://towardsdatascience.com/data-analyst-3-0-the-next-evolution-of-data-workflows-3f5939dd9b0a?source=collection_archive---------36-----------------------

随着云原生数据仓库和增强分析的进步,我们正在进入 BI 的第三阶段

像任何好的故事弧一样,自数据分析起源以来,我们已经走过了漫长的道路。BI 的第一阶段始于僵化的 IT 系统。第二阶段随之而来的是一波更加灵活、面向业务的工具,支持更加面向业务的数据分析师思维模式,以及一波漂亮、易于过滤但通常是静态的仪表盘。

如今,随着云原生数据仓库的兴起和可扩展推理方法的进步,我们正处于第三阶段的风口浪尖,这一阶段不仅能提供更好、更快的数据处理,还能让运营数据分析师以前所未有的方式影响业务决策。我把这个阶段称为数据分析师 3.0。

数据分析简史

在我们了解 Data Analyst 3.0 带来的因素之前,让我们先来看看我们已经取得了多大的进步。过去,It 团队中的一个人就可以获得成为“数据专家”所需的所有相关领域和技术技能数据不大也不广,这意味着人们可以获得新的数据技能(Excel、轻量级 SQL、SAS 等。)随着问题的出现,发送一个 CSV 来回答问题的过程运行得很好。

但是,从组织的角度来看,大多数数据请求在 IT 和业务之间的传递中失败了,因为技术人员不知道如何使他们的数据基础结构可供日常 Excel 用户使用。IT 团队提供的查询只能回答关于特定 KPI 的一个问题。这有两个主要问题:

  • 一个问题,一个答案。这些问题只有一个答案,避免了大多数业务用户在采取行动前所依赖的那种反复提问。在 1.0 IT 模型中,这意味着每一个新问题都需要排队等待,直到人们完全停止提问。
  • 数据和决策之间的鸿沟。拥有商业知识的人无法参与数据探索过程,而这正是所有发现发生的地方。因此,你得到的只是汇总的 KPI,而不是“啊哈”时刻。

幸运的是,随着更多以业务为中心的数据建模、BI 和可视化工具的兴起,这个系统在过去十年中已经基本消失了。这些现代工具定义了第二波 BI,并帮助 Data Analyst 2.0 成为团队中更加敏捷的成员。

在这些最终用户工具之下,第二波浪潮得到了多个平台的支持,这些平台使从我们存储的大量数据中获取价值变得更加容易。总的来说,这些工具构成了一个现代分析堆栈。

商业智能第二次浪潮的典型分析堆栈

这种分析堆栈的确切演变是一个有趣的话题,但我将把它留到另一篇文章中。

为了有效地导航和维护这个堆栈,企业需要的不仅仅是 IT 团队,因此出现了一些常见的角色:

  • 数据工程师负责准备数据。这意味着将不同来源的数据加载到一个数据仓库中,然后将原始数据转换成转换后的表格,以便分析师和数据科学家进行分析。
  • 数据分析师负责回答预期(报告)和意外(诊断)的业务问题。
  • 数据科学家,他们使用统计算法和 ML 技术来解决重点业务问题(“假设”)。

你可以思考这些角色的区别的一种方式是,他们是在收集数据之前行动还是在收集数据之后行动。数据工程师负责数据收集(和转换)前的运营,分析师和数据科学家负责数据收集后的运营。

你可以思考这些角色的区别的一种方式是,他们是在收集数据之前行动还是在收集数据之后行动。数据工程师负责数据收集(和转换)前的运营,分析师和数据科学家负责数据收集后的运营。

数据分析师是怎么成为二等公民的?

就像谷歌的 Cassie Korzykov 在她的一篇颇有见地的文章中提到的那样,如果你的主要技能最接近数据分析师的技能,那么你很可能会觉得自己的“技术”专长被数据科学同行甩在了后面。就连就业市场也认为数据科学家的角色比你高一级。只有少数人意识到这两种角色完全不同。

数据科学家为特定问题提供高强度的解决方案。如果他们处理的问题不值得解决,企业最终会浪费他们的时间。他们是思想狭隘的工人,所以有必要指出他们需要努力解决的问题。为了确保你很好地利用他们的时间,你需要确定你已经有了正确的问题,或者需要一个广泛而浅显的方法来找到一个。

这就是数据分析师可以帮助企业的地方。数据分析师的主要目标是快速浏览大量数据集,与业务利益相关方保持联系,并挖掘潜在的洞察力。速度是他们的最高美德。结果是:该公司抓住了自己的脉搏,看到了以前未知的未知。这激发了决策者为数据科学家选择最有价值的任务的灵感。

今天的数据分析师工具包:用勺子挖大峡谷

不幸的是,如今许多数据分析师陷入了两难境地。他们坐拥丰富、广泛的数据宝库,但他们经常在总结数据以报告关键指标和深入、全面的指标诊断任务的双重角色之间左右为难。

这些第二波 BI 工具装备精良,可以创建丰富的滚动仪表板来回答“发生了什么”然而,根据我们的经验,在企业需要分析师增加最大价值的精确时刻,这些仪表板往往会出现问题(比如周一早上的会议,销售副总裁问,“为什么上个月 EMEA 的销售额下降了 50%?”).

通常,这是因为这些视图建立在简化的、聚合的数据视图上,这给数据探索和诊断带来了困难。如果只对聚集进行操作,就无法详细探究。创建集合的一部分是预先假定人们会问什么问题——就好像他们是被铸在石头里的一样。因此,数据分析师预先承诺他们希望在仪表板的有限空间中显示的内容。

当然,分析师可以在仪表板上添加“过滤器”或启用“向下钻取”,但随着列和每列中的唯一值的增长,他们可以分割数据的方式也在激增(50 家商店* 100 个 SKUs * 5 个优惠券代码* 20 个城市…你懂的)。这就是为什么自助式分析的梦想被一千个过滤器变成了死亡。

当出现特殊问题时,数据分析师通常会从头开始诊断。这是一个手动过程,涉及 SQL 获取粒度数据,添加相关维度,最后使用 Python/R 挖掘洞察力。这个过程是被动的,每次都需要从头开始,并且阻碍了决策速度。结果:企业最终陷入了与第一波 BI 浪潮相似的境地——企业利益相关者排队买票,这次是为了得到他们“为什么”问题的答案。

Data Analyst 3.0 —自动找到“为什么”

数据分析师需要的是更快、更简单、更全面的方法来构建、监控和诊断精细的高维数据集,这是一种可以快速回答“为什么数据看起来是这样的?”的新范式以及“与上周相比有什么变化?”这种新的范式可以依托两项最新的技术进步:

1。 云原生存储和计算:今天,在云仓库中存储数据不仅比以往任何时候都更便宜,而且从大型平面非规范化表中查询数据的速度比星型模式快 25%-50% *,这要归功于大规模并行处理的进步。基于这一新的现实,分析师需要重新思考他们如何为数据诊断和数据报告建模。

为了快速的数据诊断,每个模型化的表应该绑定到一个值单元。例如,如果企业关心“平均交易值”和“订阅转化率”,那么您会希望分别在交易和用户粒度上创建模型化的表。另一件要记住的事情是数据的多样性。你应该在这些粒度表中包含每一个可能的维度,而不是挑选维度,这会导致人为偏见,并删除数据中可能的丰富信号。作为一名数据分析师,您并不知道您将被要求调查的所有后续问题,并且您希望能够追踪线索到任何地方。即使汇总导出可以回答您今天的顶级问题,相同的导出也不太可能回答您的后续问题。

2。主动分析方面的进步:分析师现在可以依靠【Sisu 等工具中可扩展推理方法的最新算法发展来探索数十亿个组合并确定最具影响力的事实,而不是手动使用仪表板过滤器和钻取来挖掘大表格中的见解。然后,由数据分析师根据他们能够获得的其他信息(如公司战略、业务背景和市场条件)来选择最佳答案。

在上面讨论的功能丰富的大表之上添加这种主动、自动的推理,使数据分析师能够:

  • 快速回答因您的综合 BI 数据而产生的特别问题,并以同样的努力多回答 10 倍的问题。
  • 让机器监控的智能警报处于自动驾驶状态,让他们高枕无忧,因为他们掌握着业务的脉搏,永远不会错过潜在的有用信息。

重要的是要记住,这个诊断数据层的目标不是取代 BI 工具,而是增强它。诊断数据层是智能“检查引擎”灯,以补充您的“速度表和煤气表”BI 仪表板。

一窥数据分析师的未来

这些进步从根本上改变了数据分析师在公司内部的工作方式。他们参加每周的业务会议,介绍所发生的事情(“照常营业”),分享业务的前瞻性解决方案。这个新发现的权威的中心是一个人工智能驱动的工作流程。

我们,Sisu 的,正在利用这些在数据仓库、数据建模和人工智能方面的进步,并为像三星UpworkHousecall Pro 这样的公司的分析师工作流程增压。这种转变一开始可能会有点吓人,但问问那些正在取得成功的公司,它们的情况如何。他们会告诉你他们感觉很好。

如果你想分享你对这篇文章的想法,或者想了解更多,请直接给我写信,地址是 sid@sisudata.com。

*five tran,2020。已检索,2020 年 6 月 30 日

本帖原载于 Sisu 数据博客

数据分析师墓地——死亡和绝望之谷

原文:https://towardsdatascience.com/data-analyst-graveyard-the-valley-of-death-and-despair-8eaaf520f574?source=collection_archive---------35-----------------------

这篇文章讲述了为什么数据分析师的工作会失去意义。

数据分析师的坟墓。来自 Unsplash肯尼·奥尔的照片。

在我最近的帖子 数据分析师入门 中,我详细阐述了对数据分析师的需求是如何增长的,并强调了你可以采取的步骤,以获得第一份入门级工作。

今天这篇文章的目的是提供一个不同的视角,一个悲观的观点来讨论为什么数据分析师的工作会感觉没有意义。

通常,对理想工作的期望会欺骗我们。分析师不得不承担大量令人不快的责任,将看似理想的职业与实际情况区分开来。

数据分析师的邓宁-克鲁格效应

缺乏技能和意识:难以认识到自己的无能导致自我评估膨胀。

邓宁-克鲁格效应图。图片作者作者

正如任何让你兴奋的闪亮的新技能或激情一样,通过谷歌搜索和在网上进行广泛的研究,你很容易对一个话题感到自信。新的分析师遇到了这个问题,他们对自己能够在组织中贡献的价值有着极高的期望。

这只是邓宁-克鲁格效应的另一个例子;缺乏工作经验导致对自己产生影响的能力过于自信。

绝望之谷

在埋头苦干并获得工作经验后,他们是否开始明白并不全是彩虹和阳光。无数的障碍出现了;没完没了的数据请求,缺乏分析的严谨性,非技术型的管理者,应有尽有。

新分析师由于粉碎的期望而陷入绝望的低谷,无法爬上开悟的斜坡。一种恐惧感开始袭来。然后你会怀疑这到底是不是适合你的职业。

坠入绝望的山谷。豪尔赫·依班娜在 Unsplash 上拍摄的照片。

你并不孤单。成为一名分析师可能是一份艰难且没有成就感的工作,通常是一个没有太多自主权的初级角色,你要工作 1-2 年才能找到更好的工作。

没有一份工作是没有起伏的,作为一名数据分析师也不例外。会有你喜欢的事情,也会有让你好奇的事情…为什么我会在这里?

组织层次结构

首先,你必须了解你在这个世界上的位置,才能理解为什么会出现这些问题。

技术领域工作不如意的根本原因通常是职业目标错位。加入一个不能提供你渴望的成长的错误团队,你会觉得自己的职业停滞不前,很快就会失去目标。

作为分析师,您的职责会有所不同,这取决于: (a) 数据团队是集中的还是分散的 < y 轴> ,以及*(b)您的团队/经理优先考虑哪些能力 < x 轴>。*

数据分析师—四个象限。图片由作者提供。

这些部门并不相互排斥,因此您可能会发现自己同时承担着分析工程师和 XFN 支持分析师的职责。选择一个不适合你职业抱负和技能发展的职位,意味着你在公司的时间会更加痛苦。

跨职能(XFN)支持分析师—集中的支持人员

集中式数据团队雇佣分析师作为集中式资源。分析师作为支持人员跨职能部门或产品团队工作。

到目前为止,这是希望投资数据分析的公司最常见的招聘方式。这并不奇怪,因为这是最具成本效益的选择,尤其是如果数据团队尚未证明其在发现业务洞察力方面的价值。

这个想法是雇佣一个或多个分析师同时接受来自多个团队的请求,如下图所示:

跨职能(XFN)支持分析师。图片来自作者

集中式数据团队对他们的分析师拥有完全的控制权和治理权,但是将他们分配给组织内的其他团队。因此,这些分析师直接向分析经理报告,同时向他们支持的其他团队成员报告。

一些公司在团队之间轮换他们的分析师,这样工作不会变得乏味,而拥有更多分析师资源的大公司将提供较少的业务职能之间的流动性。

优先考虑的能力包括软技能,如 影响力、讲故事、沟通和数据可视化。

统计知识和编程之类的技术技能很重要,因为它们有助于实现特定的业务目标,例如,找到杠杆来增加 xx%的收入。

出色的 XFN 支持分析师:

拥有商业和技术技能,但不确定自己的职业发展方向?这是最适合你去发现的角色。XFN 支持分析师满足了他们为不同团队分析数据的好奇心。

为商业领袖处理数据,吸收他们在某个特定领域的知识,是你找到自己想要专攻的业务领域的敲门砖。

另一方面,你可能会在探索之后决定更喜欢发展你的技术技能。因为您直接向分析经理汇报,所以有机会获得发展技术技能的机会,并成为高级数据分析师,指导其他初级员工。

就灵活性而言,这个角色是你职业生涯的最佳选择。它允许自由探索,而不会过早地将自己束缚在某个职业轨道上。

导致 XFN 支持分析师失去目标感的场景:

  1. 领域知识薄弱。分析师对问题的直觉有助于人们在杂乱的数据海洋中找到信号。然而,你的直觉可能不如职能领导发达,任何建议或见解都会被质疑和拒绝。分析师最终会回答业务用户提出的问题。分析师最终成为一只报告猴子 (见第 2 点)
  2. 举报猴。报告猴子响应数据请求,编写查询,为技术含量较低的业务用户构建仪表板。他们对 KPI 和部分业务的运行方式没有任何所有权,只是根据需要更改 SQL 或编程逻辑来回答另一个部门抛给他们的问题。
  3. 缺乏分析的严谨性。企业优先考虑快速行动和采取行动。因此,您将不可避免地简化统计概念,以便业务用户理解和接受您的分析。越复杂的分析,即使是完全合理和科学准确的,也很可能作为存档的建议被抛弃,这对于一些人来说是难以接受的。
  4. 非技术利益相关者。当业务领导要求刷新仪表板时,或者由于业务逻辑的变化导致数字不正确时,分析师必须全力以赴,手动强制自动刷新,并充当 IT 支持,完全由业务领导随心所欲。例外的是产品经理,他们通常更擅长技术,了解批处理和实时数据管道的局限性。
  5. 技术技能停滞。 XFN 支持希望在技术领导力方面有所发展的分析师关心如何利用技术高效地做事。示例包括编写高性能 SQL、版本控制以及使用各种工具和数据库。作为一名年轻的分析师,如果你的分析经理不重视你的技能发展,你可能会也可能不会有这样的机会。

职能分析师——在业务领导的直接领导下工作

不属于集中数据团队的数据分析师直接向职能部门主管报告。职能部门主管或产品经理可以自由聘用他们自己的分析师,并对他们的发展承担全部责任,如下图所示:

功能分析师组织图。图片来自作者。

如果你发现自己想要发展技能,并且经常使用新工具和新技术,离开。立刻。担任这种角色的分析师如果希望提高自己的技术技能,将会经历 XFN 支持分析师的所有痛苦,甚至更多。

这些角色并不强调技术专长,相反,他们的座右铭是快速行动,找到为企业创造最大成功的见解。

像这样的角色优先考虑的能力是类似于 XFN 支持分析师的软技能,但是技术知识可以退居二线。

因此,招聘的技术技能门槛低于 XFN 支持分析师。职能分析师应该是雇用他们的各自业务职能或产品团队的主题专家。

擅长职能分析师的分析师:

功能分析师是他们领域的专家。他们来自各种各样的背景,并在他们选择的领域磨练了他们的直觉,知道在杂乱的数据海洋中去哪里寻找洞察力。

如果你擅长说服和简化复杂问题的艺术,使用普通的结构化框架 (80/20 原则、四象限、公式、维恩图) ,你会觉得在这个角色中如鱼得水。

功能分析师更像艺术家,而不是科学家。他们擅长预测各自的经理会对哪些数据感兴趣,并采取行动。他们很有说服力,让复杂的概念对日常的商业领袖来说很容易理解。

他们还拥有一套特定于其领域的技能,这使他们能够更有效地跟上速度和推动业务影响。例如,营销分析师应该对谷歌分析平台 SEM 有专门的了解,并了解营销团队跟踪的常见 KPI。

导致职能分析师失去目标感的场景:

为了不重复我自己的话,我假设如果你得到了这个职位,你希望磨练自己思考商业的技能,并拥有敏锐的商业思维。

还是那句话,如果你有增长技能的雄心,那就马上离开。

  1. 集中职能分析师。为了节省成本,组织可以选择为一个业务职能 (如运营) 雇用分析师,并像上一节中描述的集中式数据团队一样运营。然后,功能分析师同时承担支持其他业务功能的责任。在这些场景中,职能分析师将经历 XFN 支持分析师所经历的第 1、3、4 点。**
  2. 分析麻痹。对于功能分析师来说,数据不是一种完全探索问题空间的方法,而只是一种讲述故事和检查他们直觉的方法。这未必是一件坏事。由于时间限制,检查每一列的洞察力和混杂效应是不切实际的。当分析师的直觉与经理的直觉相差甚远,以至于整个分析需要重新进行,导致多轮返工时,问题就出现了。这可能导致分析瘫痪,特别是如果分析师正在为长期战略规划做研究。

分析工程师—集中的技术专家

当需要一个更加可控的环境来进行数据分析时,专注于技术专业知识的集中团队中的数据分析师就会加入进来。

分析工程师引入工具、技术和代码实践 (数据管道测试、表命名约定、代码评审) 使其他分析师更加高效,他们的输出值得信赖。然而,这些角色并不多见,只是最近才作为 Fishtown Analytics 的革命性开源工具 dbt 出现。

优先考虑的能力包括 dbt、Gitlab、高级 SQL 知识、Python、Airflow、Fivetran、Stitch、ETL。

如果你发现自己厌倦了这样的角色,并希望与业务部门更紧密地合作,你可以成为一名分析经理,或者回到支持业务职能的分析师岗位。

擅长分析工程师的分析师:

如果你有办法让分析师的工作流程更有效率,并且关心自动化、版本控制和良好的文档等概念,你将会在这样的角色中表现出色。

分析工程师通常希望成长为强大的技术领导者,并喜欢使用新的创新工具和技术,而不太关注业务的底线。

导致分析工程师失去目标感的场景:

  1. 缺乏商业影响力。分析工程师在组织中的价值在于,他们能让周围的其他分析师更好、更高效地工作。这可能导致他们远离业务,以至于他们的工作在业务 KPI 上缺乏目的和意义。
  2. 没有得到商业利益相关者的认可。商业领袖通常看不到分析工程师的直接产出,因为他们不是深入分析商业问题的人。这可能会让人觉得分析工程师没有给公司增加任何价值,其他分析师得到了所有的荣誉,而分析工程师在后台默默工作。

数据分析师在组织内没有任何自主权。

数据分析师缺乏自主权。照片由诺亚·布舍尔Unsplash 上拍摄。

上述所有角色都有一个共同点,那就是缺乏自主性。

数据分析师很少能够领导数据驱动的变革,他们只是在构建别人认为是必须的分析和仪表盘。

数据分析师所能做出的最令人窒息的行为,就是完全按照更高权威的突发奇想来构建分析和报告。

分析师基本上是处于更高权力位置的人的直接支持人员。因此,他们对他们支持的业务功能的 KPI 没有决策权或所有权,没完没了地响应用户或管理人员的请求。

此外,对于你的分析是否被使用或被执行,你没有发言权。仅仅为了满足别人的好奇心而研究别人提出的问题的答案,可能是分析师所能做出的最没有灵魂的行为。

这就是为什么分析师通常被聘用在初级职位,只需要 1-2 年的经验。把刚从学校毕业的人塑造成你心目中的理想分析师更容易。

避免导致失去目标的场景

数据分析师失去目标。公路旅行照片,RajUnsplash 上。

尽管掌握了这些知识,我们还是无法避免上述所有情况。我们能做的是通过不担任与我们的职业发展预期不一致的角色,将噩梦场景最小化。

如果你不确定该何去何从,可以在一位关心你的成功、经验丰富的分析领导者手下跨职能工作。

对企业的特定功能感兴趣?寻找你尊敬的商业领袖,作为一名职能分析师跟踪他们。

或者,如果你只是喜欢技术,那么分析工程是你的职业道路。

在你加入任何组织之前,做一些调查,在面试阶段问一些关键问题,让你深入了解你将共事/支持的经理和同事,以及你可以学到的技能。确保它们符合你的职业发展预期。

  • 这个职位优先考虑哪些技能?
  • 我将与哪些职能团队一起工作/支持哪些职能团队?
  • 数据团队结构是什么样的?
  • 谁是我的经理和利益相关者?

您会发现,在寻求实施数据战略时,公司会利用我们讨论过的各种结构。

在同意一家公司之前,知道你向谁汇报,你服务的利益相关者,以及你可以向谁学习。如果公司不能提供你想要的成长,你会很痛苦,噩梦似乎永远不会结束。

隧道尽头的光

然而,并非所有的希望都破灭了。如果你坚持几年,你可以进入更高级的职位,在那里你有责任监督其他分析师,拥有数据平台的整个部分,或者如果你成为业务经理/领导者,负责特定的业务 KPI。

在这些角色中,你有空间支持自己的想法,并在组织中发挥杠杆作用,以你认为合适的方式将事情变得更好。

初级分析师在工作几年后,与现实达成妥协,学会妥协,就像邓宁-克鲁格一样,可以从绝望的山谷中崛起,站在美丽的高原上俯瞰地平线。

俯瞰地平线的高原。帕斯卡尔·阿梅兹Unsplash 上拍照。

数据分析师、数据科学家和机器学习工程师有什么区别?

原文:https://towardsdatascience.com/data-analyst-vs-data-scientist-2534fc1057c3?source=collection_archive---------19-----------------------

以田径运动会为例,探究这些常见职位之间的区别。

本文使用跟踪团队的比喻来区分数据分析师、数据科学家和机器学习工程师的角色。我们将从进行数据科学项目类似于跑接力赛的想法开始。希望这个类比能帮助你在教育、工作申请和项目人员安排方面做出更明智的选择。

🔵数据分析师

数据分析师能够从“起点”获取数据(即从存储中提取数据),进行数据清理和处理,并创建仪表板或报告等最终产品。数据分析师还可能负责转换数据以供数据科学家使用,这是一项我们稍后将探讨的任务。

数据分析师能够跑半圈

你可能会说,数据分析师非常有能力跑完比赛的第一部分,但不会跑得更远。

🔴数据科学家

数据科学家拥有数据分析师的所有技能,尽管他们可能不太精通仪表板,可能在报告写作方面有点生疏。不过,就应用统计方法创建复杂数据产品的能力而言,数据科学家比数据分析师跑得更远。

数据科学家能够跑完整圈…

这位数据科学家能够跑完整圈。这意味着他们拥有查询数据、探索特性以评估预测能力、选择合适的模型进行训练和测试、进行超参数调整,以及最终获得通过分类或预测提供商业价值的统计驱动模型所需的技能。然而,如果组织让数据科学家承担所有这些职责(从数据接收到数据建模),数据科学家将无法像只被要求跑完比赛的第二部分(专注于数据建模)那样跑得很好。

…如果数据科学家只负责跑完后半程,他会跑得更快

总的来说,如果业务分析师执行查询和数据清理步骤,允许数据科学家专注于统计建模,团队的绩效将会提高。

🔶机器学习工程师

机器学习工程师可以被认为是团队的秘密武器。你可能会把 MLE 理解为设计运动鞋的人,这种鞋能让其他跑步者以最高速度比赛。

机器学习工程师是一个多面手,能够开发先进的方法

机器学习工程师也可能专注于为数据科学团队带来最先进的解决方案。例如,与数据科学家的经典统计方法相比,MLE 可能更专注于深度学习技术。

机器学习工程师把它带到了一个新的高度。安德里亚·皮亚卡迪奥(Andrea Piacquadio)在像素上拍摄的照片。

随着统计学成为 Python 和 r 中易于实现的包的领域,这些职位之间的区别越来越模糊。不要误解我——对统计测试的基本理解在这个职业领域仍然是最重要的。然而,随着越来越多的频率,企业数据科学家被要求执行由深度学习驱动的模型。这是指由基于 GPU 的计算支持的数据科学领域,其中典型的模型包括神经网络,如 CNN、RNNs、LSTMs 和 transformers。

谷歌大脑OpenAIDeep Mind 等公司的机器学习研究人员设计新的算法方法,以在特定用例上实现最先进的性能,并最终实现构建人工通用智能的目标。

🚌ML 操作

另一个与数据科学相关的职称是 MLOps。这指的是生产模型的责任——换句话说,创建最终用户可以访问的模型版本。MLOps 专注于创建从数据摄取、预处理到模型推断(即,在现实世界中用于进行分类或预测)的强大管道。这个角色的职责与软件开发中 DevOps 从业者的职责密切相关。

MLOps 是公共汽车司机,负责把每个人送到田径运动会

摘要

我们探索了数据分析师、数据科学家和一些与机器学习相关的职位的职称,使用了跟踪团队的比喻。在将干净的数据传递给数据科学家进行建模之前,数据分析师可能会启动中继。机器学习工程师就像一个经验丰富的教练,专门从事深度学习。最后,MLOps 实践者就像负责带领团队参加田径运动会的公共汽车司机。

这是我在数据科学小组会议上笨拙地解释这些想法的一个短片。

关于另一个提升你的数据科学技能的视频,请查看我的关于在 Google Colab 中使用 Python 处理 GIS 数据的教程

数据分析|大数据|案例研究:大数据的 V

原文:https://towardsdatascience.com/data-analytics-big-data-case-study-vs-of-big-data-1d3dc5118759?source=collection_archive---------33-----------------------

我们来试着理解一下“大数据”中的大是多大!!

卢克·切瑟在 Unsplash 上的照片

大数据

术语“大数据”看起来是非常模糊的相对术语。所以还是用它不是什么来定义比较好。大数据不是常规数据。大数据不是常规业务数据。大数据不是一个经验丰富的数据分析师可以随时处理的事情。大数据不太适合熟悉的分析范式。大数据不适合 Excel 电子表格。大数据可能不适合你的普通电脑硬盘。

Doug Laney 在 2001 年的一篇关于大数据的文章中写道,描述大数据的方法之一是通过查看 的三个 V的量、速度和多样性。

大数据是指那些太大而无法在你的电脑上运行的数据。

摩尔定律的一般观点,计算机科学中一个众所周知的观察结果,即计算机的物理容量和性能大约每两年翻一番。这意味着在某个时间对一个系统来说很重要的东西在另一个时间对另一个系统来说却很平常。

https://www . mental loss . com/article/22332/was-Moores-law-accredible

例如,在 Excel 中,单个电子表格中的最大行数随着时间的推移而增加。之前是 65000。现在超过了一百万,这看起来很多,但是如果你记录的是每秒钟发生数千次的互联网活动,那么一百万行可以很快达到。

另一方面,如果我们考虑照片或视频,我们需要立即将所有信息存储在内存中,这将是一个完全不同的问题。一般来说,手机拍摄照片的速度是每张照片两三兆字节,拍摄视频的速度是每分钟 18 兆字节或每小时 1 千兆字节。对于高质量的摄像机,它可以达到每分钟 18g。很快它就变成了非常大的数据。

现在,有些人称之为大量数据,意思是这和我们通常习惯的数据是一样的,只是多了很多。这就涉及到速度和多样性的问题。

速度

对于速度而言,大数据是指数据以极快的速度流入。

在传统的科学研究中,从 200 个案例中收集数据可能需要几个月的时间,分析数据需要几周的时间,而发表研究则需要几年的时间。这种数据不仅收集起来很费时,而且一旦输入,通常也是静态的,不会改变。

作为一个例子,也许最熟悉的用于教授统计程序聚类分析的数据集是 Edgar Anderson 收集并由罗纳德·费雪分析的 Iris 数据,两人都在 1936 年发表了他们的论文。这个数据集包含四个测量值:三种鸢尾的花瓣和萼片的宽度和长度。它有大约 150 个案例,这个数据集每天都在使用。它是统计编程语言 R 中内置的数据集之一,近 80 年来没有改变过。

在天平的另一端,如果你对使用社交媒体平台的数据感兴趣,比如 Twitter,事实上,现在他们每秒钟在全球范围内处理超过 6000 条推文。这相当于每天大约 500,000,000 条推文,每年大约 200,000,000,000 条推文。事实上,一个简单的方法就是在网上设置一个实时计数器。在互联网直播统计中,它向我们展示了今天到目前为止大约有 355,000,000 条推文被发送,并且它们更新得非常快。即使一个简单的温度传感器通过串行连接连接到 Arduino 微处理器上,一次只发送一位数据,如果运行足够长的时间,最终也会淹没一台计算机。

https://www.internetlivestats.com/twitter-statistics/

现在,这种不断涌入的数据,更好地称为流数据,给分析带来了特殊的挑战,因为数据集本身是一个移动的目标。至少对于静态数据用户来说,流数据的要求和复杂性是非常令人望而生畏的。

品种

Forester Research 最近的一项研究表明,多样性是引领公司采用大数据解决方案的最大因素。

现在我们来看大数据的第三个方面,多样性。例如,多样性在这里的意思是,它不仅仅是电子表格中格式良好的数据集的行和列。相反,我们可以有许多不同格式的数据手册。我们可以有非结构化的文本,比如书籍、博客文章以及新闻文章和推文的评论。一位研究人员估计,80%的企业数据可能是非结构化的,因此这是常见的大多数情况。这也可以包括照片、视频和音频。类似地,数据集包括像网络图数据这样的东西,这就是社会关系数据。或者如果在所谓的 NoSQL 数据库中处理数据集,你可能会有社交关系的图表。它也可能有层次结构和文档。

https://cdn . ttgtmedia . com/rms/online images/business _ analytics-unstructured _ data _ desktop . png

不适合传统关系数据库或电子表格的行和列的任何数量的数据格式,那么它将面临一些非常严重的分析挑战。

结论

我们必须同时拥有三个 V——数量、速度和多样性,还是只有一个 V,才能拥有大数据?

这可能是真的,如果你同时拥有这三个 V,那么你就拥有了大数据,但其中任何一个都可能超出数据的标准方法。大数据意味着我们不能使用标准方法来处理它。因此,大数据会带来许多特殊的挑战。

参考

[1]兰尼博士,2015 年。大数据的 10 大愿景和战略问题。Gartner 博客。

[2]s . Sagiroglu 和 and Sinanc,2013 年 5 月。大数据:综述。在 2013 年国际协作技术与系统会议(CTS) (第 42–47 页)。IEEE。

数据分析|数据分析|用例研究:投资数据

原文:https://towardsdatascience.com/data-analytics-data-profiling-use-case-study-investment-data-adf872152db6?source=collection_archive---------23-----------------------

使用投资数据用例解释许多数据分析项目中涉及的主要阶段之一“数据剖析”。

D 数据概要分析是一个审查数据的过程,目的是更好地理解数据的结构、内容和内部关系,从而实现更高的数据质量。

Firmbee.com 在 Unsplash的照片

数据分析在以下方面非常重要:

  • 数据仓库和商业智能(DW/BI)项目。
  • 数据迁移项目。
  • 源系统数据质量项目。

没有正确格式化、标准化或与数据库的其余部分正确集成的数据可能会导致延迟和问题,从而导致错失机会、迷惑客户和错误决策。

让我们试着用通俗的语言来说这个吧!!

现在,让我们假设你正在为你的家人和同事举办一个晚宴。去买杂货,开始为晚餐准备食物。首先,你要试着列出可用的食品杂货,并根据将要到来的客人数量、儿童和成人的数量、素食者和非素食者的数量等来描述所需的食品杂货。这个清单除了数据分析外什么都没有,总可存储杂货是数据存储基础设施,总可用杂货现在将是数据库或数据仓库。

数据分析的类型

1.结构发现

克林特·王茂林在 Unsplash 上拍摄的照片

结构发现有助于确定数据是否一致以及格式是否正确。它使用基本统计数据来提供有关数据有效性的信息(如总和、最大值)。结构发现有助于了解数据的结构化程度,例如,pin 码的位数不正确的比例是多少。

2.内容发现

乔·塞拉斯Unsplash 拍摄的照片

内容发现关注数据质量。数据需要及时有效地格式化、标准化,并与现有数据正确集成。例如,如果电话号码的格式不正确,这可能意味着无法联系到某些客户。

3.关系发现

裘德·贝克在 Unsplash 上的照片

关系发现识别不同数据集之间的连接。发现数据的各个部分是如何相互关联的。例如,数据库表之间的键关系,电子表格中单元格或表之间的引用。理解关系对于重用数据至关重要。应该通过保留关系来导入相关的数据源。

数据剖析技术

1.列剖析

列分析扫描整个表,并计算每个值在每列中出现的次数。这种方法有助于发现一列数据中的频率分布和模式。

2.跨列剖析

跨列分析由两个过程组成:键分析和依赖性分析。键分析通过搜索可能的主键来检查属性值的集合。相关性分析是一个更复杂的过程,它确定数据集中是否嵌入了关系或结构。这两种技术都有助于分析同一个表中数据属性之间的依赖关系。

3.跨表剖析

跨表分析使用外键分析来检查不同表中列集的关系,外键分析是对孤立记录的识别以及语义和语法差异的确定。这有助于减少冗余,还可以识别可以映射在一起的数据值集。

4.数据规则验证

数据规则验证以主动的方式使用数据分析来验证数据实例和数据集是否符合预定义的规则。这个过程可以通过批量验证或持续验证服务来实现。

数据分析工具

开放源码

  • Talend 开放式数据质量工作室
  • 聚合分析器
  • Quadient 数据清除器

商业

  • 信息科学中的数据剖析
  • Oracle 企业数据质量
  • SAS 数据流

用例

背景

红利增长投资数据

马库斯·斯皮斯克在 Unsplash 上拍摄的照片

股息增长型投资已经存在了很长时间,并且一直是一种广受欢迎的获得被动收入的方式。与任何其他投资一样,需要做出选择股票的详细决策。和其他投资一样,风险越高,潜在回报也越高。这个数据集应该支持由数据驱动的投资组合选择的决策。

数据是使用 API 对 robinhood.com 所有可交易工具的快照。分析数据后可以解决的一些情况可能是“哪些股票确实具有最好的风险/回报比?”

投资数据集列描述

要求

交易经纪公司的数据治理部门希望基于这些数据构建报告和分析。因此,作为第一步,他们希望评估接收数据的质量。

他们想要回答的一些问题如下:

  • 数据集的所有列都填充了有效数据吗?
  • 特定属性的取值范围是什么?
  • 属性中特定值出现的频率是多少?

解决方案设计

我们使用 Talend Open Studio for Data Quality 对 CSV dump 生成的数据集进行数据剖析(您可以按照提供的 GitHub 链接中的步骤生成数据集)。

使用 Talend 可以完成许多不同类型的分析,但是我们将自己限制在这个简单的数据集上,其中大多数分析是柱状的。

我将尽可能用投资数据集的分析来解释每一部分。

Talend Open Studio 提供不同类型的数据质量分析|按作者分类的图片

结构分析

本节中可用的分析返回数据库内容的概述。它们为每个目录和/或模式等计算表的数量和每个表的行数。他们还计算索引和主键的数量,等等。

这将帮助您一目了然地看到哪个数据库包含的数据最多,哪些表是空的等等。

交叉表分析

该分析研究了几个表格。冗余分析是您想要检查两个表之间的关系的一个例子(也可以用作外键发现)。

表格分析

分析颗粒是行。例如,您想知道几行是否相同或相似。这将所有分析分组到“表格分析”文件夹下。行是属于所有列的一组单元格。在这种分析中,行是您分析的不可分割的元素。studio 允许用户选择关注哪些列。这里,您做了一个“部分”表分析,不可分割的元素不是一个完整的行,而是一组单元格(属于几列,但不是所有的列)。这种分析使您能够在选定的表上应用数据质量规则(DQ 规则)。

请注意,您可以创建 DQ 规则,并在稍后的分析准备阶段将它们分配给所创建的分析。

列分析

本节中的分析使您能够以列为基础分析数据。所有指标都是针对单个列计算的。与 excel 文件类似,焦点是一列并分析该列的每个单元格。

您可以从一个空的色谱柱分析开始,在这里您可以手动定义所有的设置,或者您可以使用一些预定义的分析,这些分析使用一组根据焦点选择的指示器。

或者,您可以使用语义感知分析向导,根据语义存储库中收集的信息自动配置列分析。以下是不同类型的列分析:

1.基本列分析

该向导生成一个空列分析,并打开分析编辑器。然后,您可以选择要分析的列,并在每个列上手动分配指标,例如空值数量、频率表、汇总统计、模式匹配指标等。

专栏“符号”|作者图片的基本专栏分析

2.名义值分析

这种分析使您能够分析名义数据。它创建了一个列分析,其中配置了适用于名义数据的指标。这种分析使用频率表和文本相关指标。

专栏“简单名称”|作者图片的标称值分析

3.离散数据分析

这种分析使您能够分析数字数据。它创建一个列分析,其中配置了适用于数字数据的指示器。这种分析使用 Bin 频率指示器,您可以进一步配置该指示器,以便根据您的需要离散化数据。

列“日交易比率”的离散数据分析图片作者

4.汇总统计分析

这种分析使您能够分析数字数据。它创建一个列分析,其中汇总统计指标自动添加到数字列中。这有助于您通过计算范围、四分位数范围以及平均值和中值来了解数值数据的形状。

“pe_ratio”栏的汇总统计分析 |作者图片

关联分析

此文件夹中的分析是探索性分析。它们帮助您探索列之间的关系,并可能帮助您发现数据中的其他质量问题。

结论

通过进行如上所示的分析,可以记录数据分析结果。稍后可以对其进行分析,以实现开发数据分析平台的复杂转换。

参考

Kaggle.com(2020 年)。股息增长投资数据。[在线]请访问:https://www . ka ggle . com/jonnylangefeld/dividend-growth-investment-data【2020 年 1 月 29 日访问】。

洞察,S. (2020)。什么是数据概要分析,它如何让大数据变得更简单?。[在线]Sas.com。可从以下网址获取:https://www . SAS . com/en _ au/insights/articles/data-management/what-is-data-profiling-and-how-it-make-big-data-easy . html【2020 年 1 月 29 日获取】。

电子商务零售中的数据分析

原文:https://towardsdatascience.com/data-analytics-in-e-commerce-retail-7ea42b561c2f?source=collection_archive---------3-----------------------

电子商务不是蛋糕上的樱桃,而是新蛋糕

电子商务零售中的分析概念和应用,带有简单的演示和有趣的业务示例

Unsplash 上拍照

[## 听听这篇文章。

▶](https://app.blogcast.host/embedly/2464)

简介

最近,我帮助高露洁棕榄公司优化了亚马逊网上目录的产品策略。我应用数据科学方法来预测电子商务销售,预测产品的盈利能力,并优化公司的利润。最后,该项目获得了公司电子商务洞察和分析团队的认可。

本文是通过该项目获得的经验和知识的延伸。我将探索数据分析在电子商务零售业中的不同应用途径,尤其是像联合利华、雀巢、P&G 等跨国消费品公司。我会用我标志性的简单易懂、易读的方式来做这件事。

用联合利华全球电子商务副总裁克莱尔·亨纳的话说,

“电子商务不再仅仅是面向未来的渠道。未来就在这里。”

我喜欢数字。所以,我先说一些数字。

2020 年第二季度,美国零售电子商务销售额从第一季度的 1604 亿美元飙升至 2115 亿美元。由新冠肺炎引起的封锁无疑促进了电子商务销售的增长。克莱尔说的很有道理,

“许多人都是第一次来网上购物,这推动了渗透率的上升。”

让我们看看过去 5 年中 Q2 电子商务销售额占美国零售总额的百分比,这样你就能很好地感受到电子商务潜力的增长。

图 1:过去 5 年,Q2 电子商务销售额占美国零售总额的百分比(图片由作者提供)

此外,到 2024 年,美国电子商务销售额将超过 1 万亿美元,占零售总额的 18.1%。

让我们来看看 2020 年迄今为止顶级 CPG 公司的表现,与去年相比,电子商务销售额占零售总额的百分比份额。

图 CPG 公司电子商务销售额占总零售额的百分比(图片由作者提供)

所以,现在你知道公司被赋予促进他们的电子商务销售的重要性。

现在,让我们深入探讨分析在帮助消费品公司扩大电子商务销售方面具有巨大潜力的不同途径。

1。产品推荐

米凯拉·安波洛在 Unsplash 上的照片

你还记得你去百货商店的时候,友好的店主或店员在整个购物过程中帮助你吗?他知道你买的食物,你买的洗衣粉,或者你孩子喜欢的冰淇淋。他知道你的购物预算,并会提出建议。你最终还是买了他多次推荐的东西。不是吗?

这种与客户的关系正是公司所需要的。

产品推荐引擎是解决方案。什么是推荐引擎?

它只是“友好的店主”的自动化形式。它是一种使用机器学习算法向客户推荐他们可能感兴趣的产品的工具。这些建议可以通过以下渠道提出:

  • 在网站内
  • 电子邮件活动
  • 在线广告

推荐引擎有两种类型:

a)非个性化推荐引擎:

这对于在不使用客户数据的情况下通过欢迎电子邮件或批量时事通讯发送建议非常有用。以下是一些有用的类别:

  • 新产品,比如最近推出的一款新巧克力冰淇淋
  • 潮流产品像一个快速销售的咖啡品牌,以帮助招募新客户
  • 滞销产品比如打折的豪华香皂

b)个性化推荐引擎:

这是金子!它使用客户数据来推荐最佳优惠和促销。它使用深度学习算法和自然语言处理(NLP)来使客户体验尽可能个性化。这些算法使用来自以下领域的数据:

  • 购买历史
  • 最近的活动
  • 在线行为
  • 社交媒体浏览

这些算法非常强大,可以通过以下方式极大地促进电子商务销售:

  • 提高转化率
  • 增加客户的平均购买价值
  • 降低跳出率和购物车废弃率

以下是目前亚马逊的推荐引擎给我展示的内容。看起来它知道我喜欢锻炼。

图 3 亚马逊推荐引擎(图片由作者提供)

麦肯锡报告称,顾客在亚马逊上购买的东西中,有 35%来自基于这种算法的产品推荐。

2。 购物篮分析

Unsplash 上由 Charisse Kenion 拍摄的照片

购物篮分析是一种识别一起购买的一对/一组产品之间关联强度的技术。简而言之,它基于这样一个概念:如果客户购买了一种产品,他们或多或少会购买另一种相关产品。购物篮分析也使用机器学习/深度学习算法,如产品推荐引擎。

我将用我前面提到的高露洁-棕榄公司项目中的一个例子来解释这一点。我将一款儿童牙刷(无利可图的产品)与一款除臭剂、一款爸爸的产品(快消产品)捆绑销售,能够将组合的周总利润提高 8%。

关联规则学习 是一种用于发现产品之间关联的机器学习方法。它不考虑购买产品的顺序。让我用一个演示来解释一下。

该分析是对数百万个篮子进行的,但我将用 7 个篮子进行演示,并解释所使用的 3 个重要指标。让我们探索一下洗发水和护发素之间的联系(第 1 栏):

图 4 CPG 电子商务商店上的七篮子顾客(图片由作者提供)

a)支架

定义:包含产品 x 和 y 的交易数量占交易总数的百分比

业务含义:表示两种产品一起购买的频率。

The association rule {shampoo} => {conditioner} has a support of 0.71 → Both products are bought together in 71% of the transactions

b)信心

定义:包含产品 x 和 y 的交易数与包含产品 x 的交易数之比

业务含义:表示关联规则为真的频率,即两种商品一起购买的频率。

The association rule {shampoo} => {conditioner} has a confidence of 0.83 → 83% of the times the customer buys shampoo, conditioner is bought as well

c)提升

定义:Lift 是置信度与预期置信度的比值。预期置信度就是产品 y 在篮子里的概率。

业务含义:规则的提升表明规则内的关联有多强,即规则在预测结果方面比一开始就假设结果要好多少。提升值越高,关联越强。

Lift = 1 → There’s no relation between the purchase of the products.Lift > 1 → The products are likely to be bought together. Higher the lift, the higher the chances.Lift < 1 → The products are unlikely to be bought together. They are substitutes.

The association rule {shampoo} => {conditioner} has a lift of 1.17 → The probability of buying a conditioner with the knowledge that shampoo is already present in the basket is much higher than the probability of buying a conditioner without the knowledge about the presence of shampoo.The presence of shampoo in the basket increases the probability of buying conditioner.

我知道托举有点棘手。但我希望你现在明白了。

并且在此之后,卡方分析对于确定关联规则的统计显著性是有用的。

3.价格优化

80%的人都说在网上电子商务商店购物最重要的方面是有竞争力的价格。

Unsplash 上的 Bermix 工作室拍摄的照片

所以,你知道设定最优价格并在客户满意度和公司利润之间取得平衡是多么重要。现在,让我们探讨与价格优化相关的 3 个重要概念:

图 5 价格优化的概念(图片由作者提供)

a)客户和产品的细分

这是价格优化的第一步,您将对相似的产品和客户进行分组。分类(监督)和聚类(非监督)算法对于这种分割是有用的。最佳技术取决于业务需求和数据类型。

顺便说一下,在我任职高露洁期间,我曾使用 K-均值聚类对具有相似销售趋势的产品进行分组。它帮助我为每个集群建立了一个预测模型,而不是许多模型。

并且,我在我的另一篇文章中已经提到了 RFM 客户细分。快速阅读一下!

[## A/B 测试:业务案例的 4 大错误及解决方法

在你发现这篇文章之前,你可能忽略了这些

towardsdatascience.com](/a-b-testing-top-4-mistakes-with-business-cases-fixes-85e76767dfde)

b)回归建模

一旦细分完成,围绕销售、转换率、季节性、产品属性、营销渠道等的各种数据点的回归模型。帮助确定产品的最优价格。

让我给你一个假设的 CPG 行业的商业例子。联合利华的分析团队为个人护理产品建立的回归模型可以帮助它预测多芬除臭剂价格下降 5%可以促进 15%的销售。

c)动态定价

你还记得上一次你最喜欢的产品在亚马逊大减价时降价,而其他电子商务商店也降价了吗?

这就是动态定价。它使用竞争对手的数据作为机器学习算法的输入,以确定不同时间的产品价格。这有助于产品在价格频繁波动的竞争市场中保持活力。

A/B 测试可以用来完善定价模型,但它需要大量的技术考虑,是一个完全不同的主题。改天再详细说。与此同时,你可能想看看我写的这篇关于 A/B 测试中出现的 大错误的文章,以及有趣的商业案例&修复

[## A/B 测试:业务案例的 4 大错误及解决方法

在你发现这篇文章之前,你可能忽略了这些

towardsdatascience.com](/a-b-testing-top-4-mistakes-with-business-cases-fixes-85e76767dfde)

4.请求预报

照片由克里斯·利维拉尼Unsplash 上拍摄

让我们想象一下本杰明·富兰克林亚伯拉罕·林肯是电子商务商业大亨。

富兰克林似乎警告过不要低估电子商务零售中需求预测的潜力,

"如果你没有计划,你就是在计划失败."

并且 Lincoln 似乎为你的电子商务公司提供了将需求预测纳入分析场景的完美策略。

“给我六个小时砍树,我会用前四个小时磨斧子。”

需求预测是指使用分析技术来预测产品需求和销售。如果你提前了解销售趋势,你就能在以下几个方面比你的竞争对手更有优势:

a)更好的库存管理

低估库存水平会导致库存缺货,从而引起客户不满。过高估计库存水平会导致库存积压,从而造成不必要的存储成本。

需求预测有助于制定明智的库存计划,避免畅销产品脱销和库存滞销造成的仓库空间浪费。

b)更好的现金流管理

因为这些钱不会被积压在滞销的存货中,所以它可以帮助你合理地计划预算,并最佳地使用现金。因此,它帮助你降低财务风险。

c)更好的定价策略

有效的需求预测也有助于改进定价策略。您可以对具有高需求预测的产品收取更多费用,反之亦然。您可以更好地规划营销预算、广告投资和折扣计划。

d)更好的客户服务

预先了解产品需求及其波动有助于规划更好的客户服务。是时候举个商业例子了。

布莱恩·安杰洛在 Unsplash 上的照片

亚马逊在 2013 年申请了【预期运输】专利,利用预测模型在你购买之前将产品运送给你。亚马逊的算法会预测你的购买,并把产品送到离你最近的仓库。然后,亚马逊会等到实际购买。亚马逊认为,这将极大地缩短从购买到实际交付的时间,并促进公司的整体销售。

结论

电子商务零售行业有更多的分析应用,但这些是对电子商务销售收入有直接影响的一些突出应用。我希望你喜欢读它。

乔尔·安德森(沃尔玛前首席执行官)强有力的信息结束,

“你不能只打开一个网站,就指望人们蜂拥而至。如果你真的想成功,你必须创造流量。”

注:如果你想看看我最近在高露洁棕榄做的项目,请在 我的 GitHub 账户 中找到代码和演示。根据 NDA 的要求,所有机密数据均已隐藏/匿名。

请随意看看我写的关于 SQL: 的其他文章

[## SQL 查询优化的索引

是时候开始你的查询游戏了!

towardsdatascience.com](/indexing-for-sql-query-optimization-139b57db9fc6) [## 7 必须知道 SQL 查询错误和修复

避免这些错误,提高你的查询技巧!

towardsdatascience.com](/7-must-know-sql-querying-mistakes-fixes-321ee292a251)

请随时提供反馈,并关注我以获取更多关于数据分析的有趣文章。在 LinkedIn 上与我联系。

posted @ 2024-10-15 13:43  绝不原创的飞龙  阅读(220)  评论(0)    收藏  举报