TowardsDataScience 博客中文翻译 2016~2018(二百九十四)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

2017 年大数据趋势点燃

原文:https://towardsdatascience.com/trends-out-of-2017s-big-data-ignite-2efaa93abbe9?source=collection_archive---------9-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A beautiful downtown view of Grand Rapids, Michigan from the Big Data Ignite conference

我有幸参加了在密歇根州大急流城举行的大数据点燃 2017 大会。为期三天的会议以“指数智能时代”为主题,并为我提供了一个机会,让我后退一步,更广泛地了解大数据和分析市场。我利用这段时间联系并向其他身处战壕的人学习,让这些大数据平台在西密歇根的几家大型企业中发挥作用。与了解各种平台供应商的人交谈并了解推动他们的物联网、数据和数据湖基础设施的工具选择是非常宝贵的。

在这三天里,一些主题固化成了一些有趣的趋势。

企业正在积极追求大数据和分析,而且不仅仅是从 IT 内部。

在会议期间,我观看了演示,并与来自梅耶尔Steelcase安利和许多其他公司的团队成员进行了多次走廊交谈。这些价值数十亿美元的企业正在努力寻找合适的人才,然后给他们试验的自由。希望这种自由将导致一个成功的大数据计划成为核心业务运营的中心。因此,这些团队正在推动其组织内端到端的变革,因为他们发现了哪些数据可用,如何最好地集中这些数据,并最终开放这些数据供其他人从中获取价值。这些“数据湖”和“企业数据集市”正在收集从系统日志到用户生成的社交内容和来自制造运营的物联网连接资产数据流的一切信息。

数字化转型的核心是由数据和分析驱动的。

今天,我们在报纸上听到了很多关于数字转型的报道。和许多重大趋势一样,这个词再次被滥用和误解。三天来,我们清楚地看到,任何数字化转型努力的核心都是对数据和分析的高度关注。这不仅仅是关于打造一个数字产品或者开辟一个新的数字频道。数字化转型是从公司的核心基础开始,将重点转移到收集和利用数据,以做出更好、更快、更明智的决策。我们与之交谈的进步公司正在考虑如何让组织中的任何人都可以访问数据。他们正在积极地从命令和控制型 IT 组织转变为支持型组织。Meijer 甚至发展到建立开发“沙箱”的程度,在沙箱中,公司内任何参加过他们的“数据训练营”的人都被允许使用生产级数据来评估假设或解决业务线问题。

模具市场错综复杂,充满了管道胶带。

当我坐在各种供应商演示和走廊对话中时,我开始看到更广阔的前景,并对涌入该领域的大量供应商有了更好的理解。我被你可以附加到你的 Hadoop 集群上的一些插件或者有多少类似 ETL 的工具可以让数据流入你的数据湖所震惊。如果你选择生活在微软 Azure 或亚马逊 AWS 生态系统中,事情会简化,但当你离开这些环境时,真相和选择是无穷的。在宏大的计划中,这个空间仍在发展,会有赢家和输家。我们将很快进入一个供应商整合的时期,这将有助于简化选项,但目前,新工具和零碎架构的空间仍然非常大。

每个人都还在试图解决这个问题。

大型企业仍处于采用和实施大数据基础架构以及提供企业级分析平台的早期阶段。我们已经走过了证明技术可以扩展的阶段,现在正在过渡到证明这些数据源可以为整个企业的底线增加指数级价值,而不仅仅是对统计书呆子(你们都还在摇滚!)在商业智能组内。随着这种转变的继续发展,我们开始看到围绕最佳实践出现了更多的问题。数据科学家应该在组织中“生活”在哪里?哪些数据在提供价值,哪些价值只是过度?最后,您如何转变和优化现有的产品和服务,以利用这些新发现的见解?

大数据和分析的范围正在帮助打破传统 IT 的孤岛,并帮助将更多价值提升到底线。在集体想法我们了解并相信在不久的将来,所有规模的公司都需要成为数据驱动型。他们的数据量、速度和多样性将成为其竞争优势的核心部分。你今天是如何开始的?

您如何看待贵公司采用大数据的速度,以及如何应对各种选择?我们希望收到您的来信——发推特给我们@ MAC fowler@ collective idea

排除 GCP + CUDA/NVIDIA + Docker 故障并保持其运行!

原文:https://towardsdatascience.com/troubleshooting-gcp-cuda-nvidia-docker-and-keeping-it-running-d5c8b34b6a4c?source=collection_archive---------4-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我有一个谷歌云平台(GCP)实例,一天前已经设置好并运行良好,它是在我的之前的教程之后设置的。

[## 设置 GCP 计算实例后会发生什么?使用 Tensorflow 运行自定义 Docker 容器

介绍

medium.com](https://medium.com/@thushv89/whats-after-setting-up-a-gcp-computing-instance-running-a-custom-docker-container-with-tensorflow-eb0f077983c6)

让我告诉你一些关于我的机器的事情,

  • Ubuntu: 16.04
  • GPU: 1 个 P100
  • CUDA: 9.1
  • 英伟达:387.xx

但是,当我昨天启动我的 GCP 实例并尝试运行 docker 容器时,发生了一些非常奇怪的事情,

sudo docker start <container_name>
sudo docker attach <container_name>

发生了什么事?

不,它不像我希望的那样工作,并把我带进了集装箱。相反,它给了我以下错误

Error response from daemon: linux runtime spec devices: error gathering device information while adding custom device “/dev/nvidiactl”: no such file or directory
Error: failed to start containers: x

这很可能已经发生了,因为我的 GCP 实例勇敢地决定继续下去并更新一切本身是完全没问题的,事情会神奇地变得更好!嗯,我有消息!不会这样的。所以如果 GCP 能给我们一个在初始设置时关闭自动更新的方法,我将不胜感激。事实上,已经有许多关于 NVIDIA 驱动程序发疯(或失踪)以及其他更新的报告(证据 123 )。

向下钻取…

好了,在进入故障诊断的细节之前,让我一步一步总结一下我要做的事情。

  • 检查机器是否(在物理上)识别了我的 GPU
  • 检查 NVIDIA 是否可以看到 GPU
  • 如果 NVIDIA 看不到 GPU,请查看您是否安装了 CUDA/NVIDIA 软件包,并检查 NVIDIA 驱动程序是否正确加载
  • 如果 CUDA/NVIDIA 软件包安装正确,尝试修复路径变量
  • 如果修复路径变量没有修复,卸载任何现有的 CUDA/NVIDIA 软件包,并尝试重新安装兼容的 CUDA 和 NVIDIA 软件包
  • 关闭自动更新,所以我会手动更新,而不会破坏一切。

我的 GPU 被机器识别了吗?

首先也是最重要的,在检查库是否正确安装之前,请通过键入,

lspci | grep 3D

这应该给出类似于,

00:04.0 3D controller: NVIDIA Corporation Device 15f8 (rev a1)

如果没有,这可能是由于 GPU 被拔掉或只是从插座中轻轻推出,因为你移动了机器或其他东西。

使用 NVIDIA 系统管理界面(NVIDIA-SMI)检查 GPU 的状态

首先要做的是,而不是妄下结论,并严格地开始输入sudo apt-get install <this-and-that> 希望得到最好的结果!事实上,在这种情况下,最好的事情(也是大多数人忽略的)是找出问题所在。首先让我们看看我们有什么。继续打字,

nvidia-smi

理想情况下,您应该得到这样的结果,

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 1: Output of nvidia-smi

那没用:(…

如果你得到这样的信息,

NVIDIA-SMI has failed because it couldn’t communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.

这可能是由于两个原因,

  • 您没有以 root 用户身份登录,因此 NVIDIA 无法通信(**解决方案:**键入sudo -s以 root 用户身份登录,然后再次尝试nvidia-smi
  • 您实际上没有安装兼容的 NVIDIA 驱动程序(或者配置已损坏)(解决方案需要更多工作)。这也是我在这里讨论的问题类型)

修复缺失的 CUDA/NVIDIA 库

因此,为了让 NVIDIA-SMI 正常工作,您需要一些适当的设置。他们是,

  • CUDA(包括 cuda- 、cuda-blas- 、cuda-nvcc- 、cuda-toolkit- 等。)
  • NVIDIA 库(包括 nvidia- 、nvidia-docker、nvidia-modprobe、nvidia-settings 等)。)

让我们检查一下是否安装了这些,试着键入

dpkg -l | grep nvidia

你应该得到

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 2: Output of dpkg -l | grep nvidia

下一次尝试,

dpkg -l | grep cuda

这应该给

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 3: Output of dpkg -l | grep cuda

请注意,实际列表要长得多。但是如果 CUDA 获得了相当多的点击,事情应该是好的。但是不要太舒服了!我遇到过即使安装了这些东西也无法工作的情况。

检查是否加载了 NVIDIA 内核模块

让我们再做一次检查,看看 NVIDIA 内核模块是否被正确加载,

dmesg | grep NVIDIA

理想情况下,你应该看到,

[ 2.261511] nvidia: module license ‘NVIDIA’ taints kernel.
[ 2.316304] NVRM: loading NVIDIA UNIX x86_64 Kernel Module 384.111 Tue Dec 19 23:51:45 PST 2017 (using threaded interrupts)
[ 2.319524] nvidia-modeset: Loading NVIDIA Kernel Mode Setting Driver for UNIX platforms 384.111 Tue Dec 19 22:56:18 PST 2017

如果你什么都看不到,那就有问题了!这意味着 NVIDIA 驱动程序没有被正确加载。

会不会是路径变量配置错误?

如果您得到如图所示的这两个输出,但不是正确的dmesg消息,那么您需要的东西都在机器中了。所以这可能是由于路径变量的一些简单的错误配置。所以打开.bashrc文件,在它后面添加下面两行。

PATH=/usr/local/cuda-9.1/bin${PATH:+:${PATH}}
LD_LIBRARY_PATH=/usr/local/cuda-9.1/lib64\                          ${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}

然后退出文本编辑器并运行,

source ~/.bashrc

重启机器,再次尝试nvidia-smi看看是否一切正常。(PS:记得用sudo权限试试)

没那么幸运?是时候手动重装了

如果你正在读这部分,你可能没有其他人那么幸运。好吧,让我们继续耕耘土地吧!在我看来,不值得再深入挖掘,试图在满是库的碗里找到一粒错误。事实上,如果我们移除当前损坏的库并从头开始正确安装,事情会容易得多。

找出正确的库版本

首先,我们需要弄清楚哪一个与哪一个相配。我的意思是,我们需要确保我们下载的特定(正确)版本的 CUDA 和 NVIDIA 驱动程序与您的显卡相匹配。所以让我们先去了解一下最新的情况。

转到,

[## 下载驱动程序| NVIDIA

下载 NVIDIA 产品的驱动程序,包括 GeForce 显卡、nForce 主板、Quadro 工作站和…

www.nvidia.com](http://www.nvidia.com/Download/index.aspx?lang=en-us)

并输入详细信息,

  • 显卡:我有一个英伟达特斯拉 P100
  • CUDA:我们用 9.x 吧

这是我得到的结果,

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 4: Driver/Library versions

现在,我们将确保在安装时坚持使用这些特定的版本,以避免任何差异。

移除现有的 CUDA/NVIDIA 库

首先让我们删除任何现有的 CUDA/NVIDIA 库,

sudo apt-get remove --purge cuda*
sudo apt-get remove --purge nvidia*

安装 CUDA/NVIDIA

首先获得 CUDA 工具包.deb,

wget [http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_9.1.85-1_amd64.deb](http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_9.1.85-1_amd64.deb)sudo dpkg -i cuda-repo-*sudo apt-get updatesudo apt-get install cuda -y

重启系统并尝试,

sudo dpkg -l | grep cuda
sudo dpkg -l | grep nvidia

您应该会看到如图 2 和图 3 所示的正确输出。

是时候进行一些黑客攻击了…

我刚刚意识到搭载 CUDA 9.1 的 NVIDIA 驱动程序 387.xx 在我的 NVIDIA Tesla P100 上不工作。所以我必须先卸载它,然后安装 NVIDIA 384.xx 。根据您实例中的 GPU 卡,这可能会有所不同。

你知道什么是怪异吗!如图 1 所示,我完全可以使用 CUDA 9.1 和 NVIDIA 387.xx。但是现在,NVIDIA 387.xx 不再与 CUDA 9.1 兼容。我不知道为什么,但希望能找到原因!

让我们这样做,

sudo apt-get remove --purge nvidia-*

现在,让我们手动安装 NVIDIA 384.xx 驱动程序,

sudo apt-get install nvidia-384
sudo apt-get install nvidia-modprobe

对于nvidia-docker,你将需要nvidia-modprobe 。现在快速检查一下路径变量,看看它们的设置是否正确

echo $PATH : You should have /usr/local/cuda-<version>/bin in this variable
echo $LD_LIBRARY_PATH : You should have/usr/local/cuda-<version>/lib64 in this variable

现在尝试nvidia-smi,您应该会看到类似于图 1 的内容,这意味着一切都恢复正常了(希望如此!).

关闭自动更新!

还有一件事,不要忘记是什么开始了这整个折磨。是自动更新。更新是重要的,以保持您的机器安全,从外部威胁和一切,但如果它将打破我的机器每 5 秒钟我更新,没有谢谢你!我自己手动更新。为此,请在文本编辑器中打开以下文件,

/etc/apt/apt.conf.d/10periodic

并设置

APT::Periodic::Update-Package-Lists “0”;

这将阻止那些“讨厌的”(然而,重要的)自动更新。但是记住要持续更新你的操作系统,因为你不希望有人侵入你的机器。

结论

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

pixabay.com

因此,在这篇文章中,我们讨论了如果您遇到配置损坏、驱动程序丢失等问题,如何对 GCP 实例进行故障诊断。我推荐的过程是,

  • 检查机器是否(在物理上)识别了我的 GPU
  • 检查 NVIDIA 是否可以看到 GPU
  • 如果 NVIDIA 看不到 GPU,请查看您是否安装了 CUDA/NVIDIA 软件包,并检查 NVIDIA 驱动程序是否正确加载
  • 如果 CUDA/NVIDIA 软件包安装正确,尝试修复路径变量
  • 如果修复路径变量没有修复,卸载任何现有的 CUDA/NVIDIA 软件包,并尝试重新安装兼容的 CUDA 和 NVIDIA 软件包
  • 关闭自动更新,所以我会手动更新,而不会破坏一切。

干杯!

特朗普,用他自己的话说

原文:https://towardsdatascience.com/trump-in-his-own-words-62af05ad76d4?source=collection_archive---------2-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对特朗普在 2016 年总统竞选过程中不断变化的优先事项的数据驱动研究

唐纳德·特朗普(Donald Trump)在 2016 年总统竞选过程中的优先事项发生了怎样的变化?随着竞选的临近,他在移民问题上变得更强硬了吗?还是他把重心转移到了经济上?他什么时候开始谈论希拉里的邮件的?

这些都是数据可以帮助我们回答的问题。加州大学圣巴巴拉分校的美国总统项目有一个庞大的目录,记录了几十年来几十位政治人物的文字记录。其中包括唐纳德·川普从 2015 年 6 月 16 日宣布参选到 2016 年 11 月 9 日接受提名的 60 篇竞选演讲。他们也有11 场共和党初选和 3 场大选辩论的抄本。

我冒昧地抓取了这些抄本,并把它们放在一个半结构化的数据库中,可以用于文本分析( GitHub repo )。对于辩论,我做了一些简单的处理,只包括了特朗普本人的部分文字记录。然后,我开始描绘特朗普在竞选过程中使用语言的演变过程。为此,我使用了相当简单的语言分析技术来确定特朗普在一段时间内提到某些话题的频率。我可以画出特朗普提到某些词的次数,但特朗普演讲的数量和长度都随着时间的推移而变化。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如所料,特朗普在竞选的最后几个月开始发表更多演讲。因此,与其绘制原始字数,我将向你展示特朗普使用某些词的频率图,作为我的文字记录中所有词的比例,在每月一次的水平上汇总。

数据不言自明

我们将从 2016 年竞选中一些常见的政策相关主题的相关单词开始。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Words counted (including variants): “economy”, “tax”, “GDP”, “jobs”, “employment”

特朗普在竞选中提到经济话题的频率似乎没有任何明显的时变趋势。然而,当我们谈到移民问题时,随着竞选活动的进行,似乎有一种轻微的负面趋势。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Words counted (including variants): “wall”, “mexico”, “immigration”, “illegals”

恐怖主义也是 2016 年竞选中的一个大话题,2016 年 6 月初发生了恐怖的 Pulse 夜总会枪击案。事件发生后的第二天,特朗普在新罕布什尔州发表了一个演讲,他在演讲中重点强调了恐怖主义的话题,下图中观察到的大幅飙升就证明了这一点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Words counted (including variants): “terror”, “terrorist”

我们还可以看看特朗普在整个竞选过程中提到某些人或实体的频率。我们从提到“奥巴马”开始,看下面的图表。特朗普在 2016 年 4 月发表了一次关于外交政策的演讲,他在演讲中花了很多时间批评巴拉克·奥巴马。除此之外,随着时间的推移,奥巴马的提及率似乎有微弱的上升趋势。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我还在下面画出了特朗普讨论“俄罗斯”和“普京”话题的频率。前两次高峰来自于讨论俄罗斯和外交政策的初选辩论。我们还看到,在 2016 年 9 月和 10 月,即维基解密发布波德斯塔电子邮件的时间附近,俄罗斯的提及率出现了飙升。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后,我们来看看特朗普提到他的民主党对手希拉里的频率。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如所料,特朗普在大选中比初选中更多地提到了希拉里(在初选中,他的主要对手将是其他共和党人)。特朗普在 2016 年 5 月 26 日获得了党内初选提名,希拉里在 2016 年 6 月 6 日获得了民主党提名,这与上文观察到的趋势中的明显转折点一致。

我们还可以锁定特朗普何时(以何种强度)开始讨论希拉里的电子邮件。在下面的图表中,我们看到了从六月到十一月非常明显的持续上升趋势。特朗普在 6 月份之前只提到过一次希拉里的电子邮件,但随着竞选活动的进行,他越来越关注电子邮件这个话题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这些都是有趣的趋势,尤其是最后一个趋势,因为人们对希拉里·克林顿电子邮件的关注度急剧上升。虽然我们通常无法确定是什么导致了一个峰值与另一个峰值的对比,但直接进入原始材料并应用一些简单的数据分析技术可以让我们获得一些经验主义的见解,了解特朗普的优先事项似乎是如何在他的竞选活动中演变的。

开型代码

想试试自己的分析吗?你可以在 GitHub 上的 Jupyter 笔记本中找到我用来生成这些图的代码版本。

合成图像

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

设计信任

原文:https://towardsdatascience.com/trust-by-design-a864f1062baa?source=collection_archive---------13-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

linh-dao

下一次工业革命的发动机不是数据,而是信任。

阿里巴巴没有库存…-谷歌没有创造专有内容,Airbnb 也没有房地产。让这些市场领导者在竞争中脱颖而出的不是数据量或分析的复杂程度,而是他们利用数据增强消费者信任的能力。当欧洲和海外的公司根据他们的数字战略评估 GDPR 时;他们忽略了一个关键点—数据永远不会比利益相关者对其数据实践的信心更有价值。

如果你的组织没有培养消费者的信任,你的市场份额将会萎缩。在过去的几年里,消费者信任的性质发生了很大的变化。几年前,Vanessa Hall 指出,基于对组织领导和产品的信任的“盲目信任”已经成为过去。【1】绝对信任已经被“情境信任”所取代,消费者信任专家,因为他们专注的洞察力和经验。今天,当面对多种数据来源和真相版本时,情境信任反过来让位于基于共同信念感知的“参考信任”。

*如果客户不相信技术能提供合理的价值水平,他们就不太可能深入一个组织的数字空间。*多项研究得出结论,消费者的信任度正处于历史最低点。三种趋势可以解释这种矛盾心理。基于“人是产品”哲学的商业模式越来越受到那些讨厌被分类然后被产品化的人的质疑。基于“越大越好”的数据囤积实践被证明是毫无意义的,因为它们具有潜在的危险。最后,公司对数据的感知需求超过对个人隐私的任何关注的零和经验理所当然地招致公众的鄙视。

消费者信任危机是欧盟通用数据保护条例 2016/679 的主旨。欧洲法规旨在鼓励数据控制者和处理者将隐私、安全和透明嵌入到他们的组织工作流程中。立法意图是对“小”而非“大”数据的使用进行限制。小数据是指允许组织清楚地识别个人的任何信息。它可能是一种生物特征、一种信仰或一种偏好,或者更多基于上下文的东西。这些文本旨在确保数字公民有权知道他们的数据是如何被使用的,有权根据需要访问、修改、删除和传输数据。也就是说,秉承 GDPR 精神只会有助于,而不是保证,消费者的信任。

*信任不是你拥有多少数据的数量的属性,而是消费者如何使用这些数据的结果。*多项举措有助于在您的客户和组织之间建立信任关系。第一步是让消费者对他们的数据有更多的控制权。第二步是将正确的数据交给他们处理——他们对您的产品和组织了解得越多,就越有机会做出更好的决策并应对他们面临的挑战。第三步是帮助他们将数据整合到有意义的故事中,帮助他们了解挑战的性质和手头的潜在解决方案。请记住,在客户的心目中,服务不是在网络上找到的,而是提供明显的方法来改善他们的生活方式。

在后 GDPR 时代,默认的隐私将很快被设计的信任所取代。“设计信任”包含大量数据实践,这些实践在运营流程的每个阶段都嵌入了增加消费者信任的机会。数据透明涉及清楚地传达您打算使用什么样的小数据,以及使用的原因、时间、持续时间和对象。Trust by Design 超越了对数据透明性的关注,实现了充分利用时间的愿景—组织可以使用数据和分析来积极影响客户与周围世界的互动方式。

正如 CareerFoundry 的 Raffaela Rein 所说,在可预见的未来,培养信任将是信息架构师和数据科学家的核心职责。【3】设计信任的影响不仅体现在您组织的设计实践和流程改进上,还体现在您将如何使用数据来帮助您的员工和客户成功应对日常生活的复杂性上。

我将在 11 月 8 日和 9 日的后 GDPR/FODP 峰会上讨论和发展这些主张。请不要犹豫,分享你的想法和建议头导致这一事件。我期待在柏林见到你。

李·施伦克博士

商业分析研究所

2018 年 9 月 15 日

Lee Schlenker 是商业分析和社区管理教授,也是 http://baieurope.com 商业分析研究所的负责人。他的 LinkedIn 个人资料可以在www.linkedin.com/in/leeschlenker.查看,你可以在https://twitter.com/DSign4Analytics的 Twitter 上关注白


【1】凡妮莎·霍尔,商业中信任的真相,2011,翡翠图书公司

【2】例如,参见Forrester 2018 年预测指南2017 年爱德曼信托晴雨表

【3】艾米丽·斯蒂文斯,通过 UX 建立信任,CareerFoundry,2018 年 1 月 22 日

“信任流程?”在线体育社区是如何被线下环境塑造的

原文:https://towardsdatascience.com/trust-the-process-the-interplay-between-online-sports-communities-and-offline-context-bc1b37a7ff74?source=collection_archive---------27-----------------------

本博客总结了我们的【CSCW】2018论文“‘这就是我们打球的原因”:NBA 各支球队 【网上球迷社区】由 贾森·吕钦**

( 交叉发布至 ACM CSCW )

许多在线社区不仅存在于虚拟世界中,而且也深深嵌入到线下环境中,吸引着具有类似线下兴趣的人。了解在线社区与线下环境的关联程度和方式是一个重要的研究问题。

职业体育提供了一个有趣的案例,因为在某种程度上,这些在线粉丝社区只是作为线下运动队和游戏的结果而存在。这种联系也突出了结合多种数据源来理解在线社交媒体中粉丝行为如何与他们感兴趣的主题的持续事件相关联的必要性。

在这里我们分享一个 Reddit 上的有趣故事。2018 年 2 月 7 日,NBA 球队菲尼克斯太阳队以 48 分之差输给圣安东尼奥马刺队,追平了球队历史上最糟糕的输球。在巨大的损失之后,当然,太阳队的球迷非常失望。但是,他们没有放弃团队,也没有抛弃团队子编辑,而是把这个体育子编辑变成了科学子编辑,开始讨论太阳系的太阳!那天晚上贴了很多搞笑的标题,比如这个:“你知道吗,太阳包含了太阳系所有质量的 99.86%?”

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

After the huge loss, the fans of the Phoenix Suns turned their team subreddit into a science subreddit, starting to talk about the Sun in the Solar System.

在我们新的CSCWT2 论文中,我们着迷于在线粉丝社区中的这种用户行为,我们从 Reddit 构建了一个大规模数据集,它结合了 NBA 相关社区(30 个球队子社区和/r/NBA)中的 150 万个帖子和 4300 万个评论,以及记录 NBA 球队表现的离线统计数据。我们在比赛层面和赛季层面研究了球队表现和球迷行为之间的相互作用。

用户活动与 NBA 赛季的结构密切相关。

首先,我们发现 NBA 赛季的结构驱动了 NBA 相关子区域的用户活动。如果我们按月使用/r/NBA 中生成的评论数来衡量用户活跃度,那么在每个休赛期(7 月-10 月中旬),用户活跃度都会急剧下降,因为在此期间没有比赛。在常规赛中(10 月下旬-次年 3 月),用户活跃度稳步上升。活动在五月和六月达到高峰,因为冠军赛在这两个月举行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

User activity in /r/NBA by month.

线上粉丝活动反映了线下的游戏玩法。

NBA 相关 subreddits 的一个重要特点就是支持游戏相关的讨论。实际上,每个游戏在相应的 team subreddit 中都有一个游戏线程。我们鼓励粉丝在游戏主题中发表与游戏相关的评论。通过比较 2017 赛季比赛当天每个小时在每个团队子编辑中发表评论的平均比例(根据一场比赛的开始时间进行归一化),我们观察到比赛时间是团队子编辑中最活跃的时间。用户活动在比赛开始前一个小时开始增加,在第二个小时达到峰值。这一趋势与持续约 2.5 小时的典型 NBA 比赛完全一致。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

User activity by hour on the game day.

粉丝都聊些什么?

接下来,我们使用主题建模来分析这些 NBA 相关子主题中的用户评论内容。权重最高的五个主题可以概括为:“个人观点”、“游戏策略”、“赛季前景”、“未来”和“游戏统计数据”我们稍后将回到这一点,看看团队绩效如何影响讨论。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The Top-5 topics discussed by fans in /r/NBA.

游戏层面的团队表现如何影响粉丝活跃度?

有人可能会假设,赢得一场比赛会在团队子编辑中引发更高水平的活动。然而,我们发现并非所有团队都是如此。我们的分层回归分析表明,顶级球队的球迷在输球后往往更活跃,而底层球队的球迷则表现出完全相反的趋势。使用 2017 和 2016 赛季的前 3 名和后 3 名球队,出现了一致的模式:

  • 在所有这些球队中,比赛日的平均评论数明显高于非比赛日;
  • 对于所有排名靠前的球队,输球日的平均评论数都高于赢球日,但对于排名靠后的球队,结果正好相反。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The top-3 team subreddits have more comments on losing days, while the bottom-3 team subreddits show the opposite trend.

顶级团队和底层团队之间的互动表明,“惊喜”可能是一个相当重要的因素。例如,在 2017 赛季,前三名球队的平均胜率在 75%以上。顶级球队的球迷可能习惯于他们支持的球队赢得比赛,在这种情况下,输掉比赛对他们来说是一件令人惊讶的事情。相比之下,倒数三名球队的平均胜率都在 30%以下。看着自己的球队获胜,这些球迷感到振奋。“惊喜”带来了额外的兴奋,可以刺激相应游戏线程中的更多评论。

关于本博客中提到的所有层次回归分析的细节,请参考我们的 论文

赛季级别的团队表现如何与团队子区域中的粉丝忠诚度相关联?

我们的结果表明,团队绩效(根据 FiveThirtyEight.com提供的 Elo 评级估算)对赛季级用户留存率和月度用户留存率都有显著的负面影响。再次使用 2017 和 2016 赛季的前 3 名和后 3 名球队,无论是赛季之间还是月份之间,垫底球队的用户留存率都比顶级球队高得多。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Fans of the top-3 teams are less loyal, and fans of the bottom-3 teams tend to stay.

职业体育中著名的“赶时髦”现象可能有助于解释这一现象:一些球迷可能会“赶时髦”,开始追随一支目前表现最好并卫冕冠军的运动队。只要团队开始表现不佳,他们就会跳下船,加入另一个表现更好的团队。相比之下,糟糕的团队表现可以作为忠诚度过滤器。经过一段时间的糟糕表现,只有铁杆粉丝会保持积极乐观。不管这个队表现得多差,他们都会继续支持他们。

赛季级别的团队表现如何影响团队子栏目中的讨论话题?

我们的结果表明,团队的表现也驱动着球迷们谈论的话题。“赛季展望”和“未来”话题与团队表现高度相关。好的球队更多讨论“赛季前景”,差的球队更多谈论“未来”如果我们对 2017 和 2016 赛季所有 30 支 NBA 球队进行“未来”和“赛季展望”的话题权重投影,可以看到前 3 名球队一致位于右下角(高“赛季展望”,低“未来”),后 3 名球队均位于左上角(低“赛季展望”,高“未来”)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Fans of the top-3 teams tend to discuss more “season prospects,” and fans of the bottom-3 teams discuss more “future.”

我们的结果呼应了体育管理中的一个早期发现:对于表现不佳的球队的球迷来说,框定未来是一种重要的策略,可以在最近缺乏成功的情况下保持积极的身份认同。结合我们之前对球队表现和球迷忠诚度的观察,这可能表明一支运动队的奋斗可以提供一个与忠诚球迷建立深厚感情的绝佳机会。某些球迷可能愿意与他们支持的球队一起经历几乎任何事情,包括多年的失败,以此来承认自己是铁杆球迷。通过这样做,当球队在未来取得成功时,他们获得了在粉丝群体中收获更多情感意义的感觉。

数据集和更多有趣的观察

本文的数据集可在 http://jasondarkblue.com/.获得文中还讨论了更多有趣的观察结果。例如,我们发现球队的市场价值、平均年龄、全明星球员的数量和比赛风格都在球迷活动中发挥着重要作用。

还有“这就是我们玩的原因!

合作者:吕钦

如何使用 Dask 数据帧在 Python 中运行并行数据分析

原文:https://towardsdatascience.com/trying-out-dask-dataframes-in-python-for-fast-data-analysis-in-parallel-aa960c18a915?source=collection_archive---------1-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Your mind on multi-cores. source: Pixabay

有时候,你打开一个包含 Python 的熊猫的大数据集,试图获得一些指标,整个事情就可怕地冻结了。
如果你从事大数据工作,你知道如果你使用熊猫,你可能会为一个系列的简单平均值等待整整一分钟,我们甚至不要调用应用。这只是几百万行的数据!当你达到数十亿时,你最好开始使用 Spark 或其他东西。

不久前我发现了这个工具:一种加速 Python 中数据分析的方法,而不必获得更好的基础设施或转换语言。如果你的数据集很大,它最终会感到有限,但它比普通的熊猫要好得多,可能正好适合你的问题——特别是如果你没有做大量的重新索引。

可以在 土星云 上马上免费使用 Dask!
土星云是一个端到端的数据科学+机器学习平台,允许数据科学家在云中使用 Dask 扩展他们的 Python 项目。

Dask 是什么?

Dask 是一个开源项目,它为您提供了对 NumPy 数组、Pandas 数据帧和常规列表的抽象,允许您使用多核处理对它们并行运行操作。

这里有一段直接来自教程的摘录:

Dask 提供了模拟 NumPy、lists 和 Pandas 的高级数组、Bag 和 DataFrame 集合,但可以在不适合主存的数据集上并行操作。对于大型数据集,Dask 的高级集合是 NumPy 和 Pandas 的替代方案。

听起来就很牛逼!我开始尝试本文的 Dask 数据框架,并对它们运行了几个基准测试。

(要查看 Dask 在机器学习中的更多应用,请查看我的 并行 k 均值聚类教程 )

阅读文档

我做的第一件事是阅读官方文档,看看在 Dask 的而不是常规数据帧中到底推荐做什么。以下是来自官方文件的相关部分:

  • 操作大型数据集,即使这些数据集不适合内存
  • 通过使用多个内核加速长时间计算
  • 使用标准的 Pandas 操作(如 groupby、join 和时序计算)对大型数据集进行分布式计算

接下来,它列出了一些使用 Dask 数据帧时速度非常快的东西:

  • 算术运算(乘法或加法)
  • 常见聚合(平均值、最小值、最大值、总和等。)
  • 调用 apply(只要它沿着索引-也就是说,不在 groupby('y ‘)之后,其中’ y '不是索引-)
  • 调用 value_counts()、drop_duplicates()或 corr()
  • locisin 过滤,行选择

Just a small brush up on filtering Dataframes, in case you find it useful.

如何使用 Dask 数据帧

Dask 数据帧与 Pandas 数据帧具有相同的 API,除了聚合和应用被延迟计算,并且需要通过调用计算方法来计算。为了生成 Dask 数据帧,你可以像在 Pandas 中一样简单地调用 read_csv 方法,或者,给定一个 Pandas 数据帧 df ,你可以只调用

dd = ddf.from_pandas(df, npartitions=N)

其中 ddf 是您导入 Dask 数据帧时使用的名称,而 npartitions 是告诉数据帧您想要如何对其进行分区的参数。

根据 StackOverflow 的说法,建议将数据帧划分为与计算机内核数量一样多的分区,或者是该数量的几倍,因为每个分区将在不同的线程上运行,如果数量太多,它们之间的通信将变得过于昂贵。

变脏:让我们进行基准测试!

我做了一个 Jupyter 笔记本来测试这个框架,并在 Github 上发布了这个框架,以防你想亲自测试或者运行它。

我运行的基准测试可在 Github 的笔记本中找到,但以下是主要的测试:

这里 df3 是一个普通的熊猫数据帧,有 2500 万行,使用我的熊猫教程中的脚本生成(列是姓名薪水,从列表中随机抽取)。我取了一个 50 行的数据集,并将其连接了 500000 次,因为我对分析本身并不太感兴趣,而只对运行它所花费的时间感兴趣。

dfn 就是基于 df3 的 Dask 数据帧。

第一批结果:不太乐观

我首先用 3 个分区进行了测试,因为我只有 4 个内核,不想让我的电脑超负荷工作。我在 Dask 上得到了非常糟糕的结果,也不得不等待很长时间才能得到它们,但我担心这可能是因为我做的分区太少了:

204.313940048 seconds for get_big_mean
39.7543280125 seconds for get_big_mean_old131.600986004 seconds for get_big_max
43.7621600628 seconds for get_big_max_old120.027213097 seconds for get_big_sum
7.49701309204 seconds for get_big_sum_old0.581165790558 seconds for filter_df
226.700095892 seconds for filter_df_old

你可以看到,当我使用 Dask 时,大多数操作都变慢了很多。这给了我暗示,我可能不得不使用更多的分区。生成惰性求值所花费的时间也可以忽略不计(在某些情况下不到半秒),所以如果我重用它们,它不会随着时间的推移而摊销。

我还用应用方法尝试了这个测试:

得到了非常相似的结果:

369.541605949 seconds for apply_random
157.643756866 seconds for apply_random_old

因此,一般来说,大多数操作变得比原来慢两倍,尽管过滤器快得多。我担心也许我也应该调用计算机来处理这个问题,所以对这个结果要有所保留。

更多分区:惊人的速度

在这样令人沮丧的结果之后,我认为可能是我没有使用足够的分区。毕竟,这样做的全部意义在于并行运行,所以也许我只需要更多的并行化?因此,我对 8 个分区进行了相同的测试,下面是我得到的结果(我省略了非并行数据帧的结果,因为它们基本相同):

3.08352184296 seconds for get_big_mean
1.3314101696 seconds for get_big_max
1.21639800072 seconds for get_big_sum
0.228978157043 seconds for filter_df112.135010004 seconds for apply_random
50.2007009983 seconds for value_count_test

没错!大多数操作比常规数据帧快十倍以上,甚至应用也变得更快了!我还运行了 value_count 测试,它只是在 salary 系列上调用了 value_count 方法。对于上下文,请记住,当我在常规数据帧上运行这个测试时,在等待了整整十分钟之后,我不得不终止这个进程。这次只用了 50 秒!
所以基本上我只是用错了工具,而且速度相当快。比普通的数据帧快得多。

最终外卖

鉴于我们刚刚在一台非常旧的 4 核电脑上一分钟内处理了 2500 万行数据,我可以想象这在行业内会有多么巨大。所以我的建议是,下次您必须在本地或从单个 AWS 实例处理数据集时,尝试一下这个框架。相当快。

我希望你觉得这篇文章有趣或有用!编写它花费的时间比我预期的要多得多,因为一些基准测试花费了这么长的时间。请告诉我在阅读本文之前您是否听说过 Dask,以及您是否在工作中或项目中使用过它。也请告诉我是否还有其他我没有提到的很酷的特性,或者我做错了什么!你的反馈和评论是我写作的最大原因,因为我也在从中学习。

数据科学家的进一步阅读:

关注我,获取更多 Python 教程、技巧和诀窍!如果您喜欢这篇文章,请查看我的网站 或关注我的微博

如果你想成为一名数据科学家,可以看看我推荐的机器学习书籍

试图改变职业生涯或从数据科学开始?

原文:https://towardsdatascience.com/trying-to-change-careers-or-get-your-start-in-data-science-3f74bc30b027?source=collection_archive---------16-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你想进入数据科学领域,有一些方法可以让你在求职过程中变得更好。

假设你已经积累了工作所需的技能,看看你是否能够利用这些技巧:

  • 针对你想要的工作(T1)优化你的简历(尽你所能),而不是你在 T2 做过的工作(T3)。
  • 尝试在当前的工作中积累经验(如果你想转行的话),或者在家做自己的数据科学项目。(持续学习是一大加分项)。
  • 开发一个杀手级电梯间推介。

为你想要的工作优化你的简历:

用一种显示你注重结果的方式来描述你的项目。

你想在简历上展示的要点需要兼顾:

  • 证明你理解一般的企业文化,展示你的协作、实现结果、解决问题和自我管理的能力。
  • 展示你作为数据科学家的技术能力。

第一点需要深思熟虑——列出工作职责确实很容易,但有效地重新措辞以突出你真正的优势并展示你所做的如何改善了业务却是另一回事。你的要点应该充满动作动词和结果,即使你需要在精神上努力去识别它们。

您是否实现了流程自动化,从而节省了手动执行任务的时间?节省的时间就是商业价值。

再次证明你已经跨职能工作或向企业展示了成果,这是你想要的新工作所需要的(数据科学家)。

阅读职位描述和了解公司在寻找什么是有帮助的,你会发现一致的主题。如果你仔细观察,你会发现这里列出了很多不一定是技术性的技能。在和这些软技能说话时,确保你光彩照人。但是当然,这些软技能需要以仍然展示一个动作和结果的方式来展示。不要只是在简历上放一个“软技能”部分,列出一堆没有上下文的单词。

“展示你作为数据科学家的技术能力”。这很简单。尽量使用你申请的工作的实际工作描述中的措辞。你可能想听起来很奇特,但是“经验贝叶斯三阶段层次模型”可能不在工作描述中。在简历中特别列出这一点不会帮助你通过 ATS(申请人跟踪系统),人力资源部门没有数据科学背景的人也不会知道这是否相关。再次强调,查看多份职位描述,并尝试判断在简历中使用哪种语言是有帮助的。

从当前工作或项目中获得经验:

如果你目前有工作,你有访问 SQL 的权限吗?你的公司有数据仓库或数据库吗?你能向服务台申请一张票来获得 SQL 吗?然后你能玩数据来制作你自己的项目吗?

您甚至可以更进一步,将数据库中的数据导入 R 或 Python。也许你做了一个很好的决策树来回答一个商业问题,然后把你的项目结果精彩而简洁地放在你的简历上。

试着自动化一项你定期做的可重复的任务。这是下一层次的简历内容。在这种情况下,您正在提高效率。

如果你已经独立完成了数据科学项目来完善你的简历,确保那些项目符号充满了动作动词和结果,动作动词和结果。我几乎想说第三遍。

SQL Lite 是开源的,R 是开源的,Python 是开源的,那里有大量的免费数据。这个世界真的可以是你的,但是你需要有效地推销这些积极进取的技能。

开发一个杀手级电梯间营销:

一份强有力的、目标明确的简历可能会打开这扇门,但你需要让这扇门一直开着,并且在门打开后继续对话。简历无非就是开门见山,仅此而已。

把你的简历交到合适的人手里有时会很困难。有效利用 LinkedIn 可以帮助弥合这一差距。如果你在 LinkedIn 上联系某人询问机会,我们该如何开始对话?

重要提示:当你主动联系 LinkedIn 上的人时,这应该是在你已经访问了公司网站,找到了一份你感兴趣并且(相当)胜任的工作,之后的,然后你联系了一个相关的人,向他传达了一个有针对性的信息。

如果你要联系的人在一家没有任何职位空缺的公司工作,那么不可能有很好的针对性。因为你没看职位描述。所以你无法推断业务的需求。数据科学是一个大领域,有许多专业,一刀切的方法是行不通的。

回到球场上。你注重结果,你有创新精神,你从商业的角度看待事物。

  • 我建议从一些对话开始,如果你发信息的人已经被请求淹没了,这将会有所帮助。对他们最近发表的一篇帖子的评论让你的联系看起来更真实。
  • 你发信息的原因:你对这个空缺职位感兴趣,你想把你的简历发给合适的人。
  • 然后简明扼要地提及一些在工作描述中特别提到的事情。基本上是在说“嗨,看看我,我很健康。”
  • 让他们知道,如果他们只是把你转给正确的人,你会非常感激(希望你发信息的人是正确的人,但也有可能不是正确的人,所以不要假设)。
  • 关闭强。你是来为公司增加价值的,而不是来谈论你的需求;暗示你知道你是来谈论如何满足业务需求的。

你好【姓名】,

我很喜欢你最近在【主题】上的帖子,我期待着阅读更多你的帖子。

我注意到[公司]正在招聘[职位名称],我希望我能把我的简历交到合适的人手里。我有统计学硕士学位,加上 7 年的实际建模经验。我是 SQL 高手,用 R 建模,接触过 Python。

我很高兴有机会与合适的人谈论空缺职位,并分享我如何通过使用统计方法为公司提供见解和附加值。

谢谢你,克里斯汀

现在你的背景可能和我很不一样。然而,你可以谈论你所受的教育(简明扼要),你所接触的建模,你的技术水平,以及你想要传递的价值。

我希望你能采纳其中的一些建议。我希望你在数据科学领域取得成功,收获颇丰。如果您对尝试改变数据科学有其他建议,我很想听听您的想法!我发布的下一篇文章将会涵盖如何为你的简历写一些有影响力的简洁内容,那篇文章在这里是

如果你在寻找数据科学领域工作的帮助,或者需要简历方面的帮助,我想推荐你去找凯尔。我很了解凯尔,这是他的人生目标!。他帮助数据科学家获得数据科学职位。你可以看他谈论这个话题的视频:这里

原载于 2018 年 8 月 22 日datamovesme.com*。*

地图数据的聚类

原文:https://towardsdatascience.com/tsne-clustering-for-map-data-507ba4e62b20?source=collection_archive---------9-----------------------

在这篇简短的博文中,我将向您展示如何在 Lat/Lng 坐标对上使用 tSNE 来创建地图数据的一维表示。这种表示有助于开发新的地图搜索算法。这对于诸如“这个 lat/lng 坐标对是在新泽西还是在纽约?”的查询可能是有用的或者“离我最近的披萨店在哪里?”。更快的地图搜索可能对优步、谷歌地图和方向、Yelp 等等非常有用。

在这篇文章中,我们将首先看看如何在真值表逻辑数据集上使用 tSNE 维度映射,然后我们将引入相同的概念来将 Lat/Lng 坐标映射到一维空间。有了一维表示后,我们就可以实现算法,用集合成员操作等方式进行常数时间搜索。

tSNE(t-分布式随机邻居嵌入)是一种聚类技术,其最终结果类似于 PCA(主成分分析)。PCA 使用线性代数概念来构建正交向量的新维度空间,而 tSNE 使用更简单的理解、排斥/吸引方法来将点从高维空间映射到低维空间。许多聚类算法的重点是在高维数据集中识别相似性,从而降低维数。tSNE 算法用于保持较高空间中的线性空间关系,而一些聚类算法,例如在径向基函数网络中使用的算法,试图增加空间关系,使得新空间是线性可分的,例如 XOR 逻辑问题的解决方案。

在 python 中使用 tSNE 的一个简单方法是使用 sklearn 包:

from sklearn.manifold import TSNE
# sample data set
X = np.array([[0,0],[0,1],[1,0],[1,1]])
X_embedded = TSNE(n_components=1).fit_transform(X)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Note to programmer: 1-Dimensional Line Plots can be created in Python by holding the y axis to a constant value using something like: plt.scatter(X_embedded,y=[1,1,1,1])

现在我们已经了解了 tSNE 如何将逻辑真值表映射到一维空间,让我们输入一个示例地图数据集,该数据集由波士顿、迈阿密和旧金山的 lat/lng 对组成。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Boston: [42.3601, -71.0589], 
Miami: [25.7617, -80.1918], 
SF: [37.7749, -122.4194]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

# This is done with the following code
from sklearn.manifold import TSNE
X = np.array([[42.3601, -71.0589], [25.7617, -80.1918], [37.7749, -122.4194]])
X_embedded = TSNE(n_components=1).fit_transform(X)

现在,我们已经将这些 Lat/Lng 对转换成一维空间

Boston: [42.3601, -71.0589]  -> 14,473.32
Miami:  [25.7617, -80.1918]  -> 3299.8037
SF:     [37.7749, -122.4194] -> -7838.6094

在与采样的高维空间相同的坐标空间中保存空间信息的同时,具有较低维度的空间表示有许多优点。我们可以对来自基本数据结构的数据使用所有一维排序和搜索算法。此外,将纬度/液化天然气维度减少到 1 维可以将距离计算所需的计算量减少一半。我们可以只取新的一维表示的差,而不是取 lat 和 lng 值之间的差。

如果您对更快的地图搜索算法感兴趣,请查看这篇文章,了解我们如何在二维空间中保持 Lat/Lng 坐标的同时加快搜索速度:

[## kMeans 对地图数据进行哈希搜索

kMeans 聚类算法作为一种“无监督的人工智能”非常受欢迎…

towardsdatascience.com](/kmeans-hash-search-map-search-in-o-n²lgn-33743ece434f)

感谢您的阅读!如果你认为这篇文章有什么问题、想法或问题,请留下评论。

CShorten

Connor Shorten 是佛罗里达大西洋大学计算机科学专业的学生。对数据科学、深度学习和软件工程感兴趣。主要用 Python,JavaScript,C++编码。请关注更多关于这些主题的文章。

周二生日问题

原文:https://towardsdatascience.com/tuesday-birthday-problem-2927e83e5af3?source=collection_archive---------5-----------------------

下面是关于孩子的一系列经典概率问题。它们开始时很温和,逐渐变得越来越难,直到与直觉相悖的程度。这些问题多年来困扰了足够多的人,以至于赢得了“男孩或女孩悖论”的称号。

首先,让我们陈述一些贯穿整个问题的假设。就像现实生活一样,一个孩子生下来是男孩还是女孩的概率是相等的,1/2。每个孩子的性别都是独立的。一个孩子同样有可能在一周中的任何一天出生,而这一天又是独立于他人和性别的。在统计符号中,孩子的性别~iid 伯努利 (1/2)和出生日期在七天内是一致的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.生男孩的概率有多大?

答案:1/2

在没有任何额外信息的情况下,我们参考给出的假设,即一个男孩出生有 1/2 的几率。

2.一个家庭有两个孩子。大的那个是个男孩。另一个也是男生的概率有多大?

答案:1/2

大孩子是男孩与小孩子的性别没有关系,因为每个孩子的性别都是独立的。

3.一个家庭有两个孩子。至少有一个孩子是男孩。另一个也是男生的概率有多大?

答案:1/3

惊讶于它不是 1/2?

我们可以从基本原理来解决这个问题。按出生顺序列举二孩家庭的四个等概率事件,得到{GG,GB,BG,BB},其中 B 代表男孩,G 代表女孩。由于问题陈述家庭至少有一个男孩,GG 情况被排除,只剩下 3 个同等概率事件{GB,BG,BB}。其中 1 有两个男孩,给出了 1/3 的答案。

这个问题和上一个类似,只是我们不再知道提到的男孩是哪个孩子。如果他是更小的孩子,两个可能的事件是{GB,BB}。如果他是年长的那个,也存在两种可能:{BG,BB}。看起来,综合起来,有 4 种可能性,其中 2 有两个男孩,但实际上 BB 的情况在两个集合之间是重复的。在合并它们时,我们必须小心不要重复计算。这一见解将在下一个问题中被证明是有用的。

另一种解决问题的方法是应用条件概率的定义:P(A|B) = P(A 和 B)|P(B),其中 P(A|B)是给定 B 已经发生的情况下 A 发生的概率。如果 B 是男生数,问题可以表述为:

P(B=2|B≥1) 
= P(B=2 and B≥1)/P(B≥1)
= P(B=2)/P(B≥1)
= P(B=2)/(P(B=1) + P(B=2)) 
= ((1/2)²)/(2 * (1/2)² + (1/2)²) 
= (1/4) / (3/4) 
= 1/3

4.一个家庭有两个孩子。至少有一个孩子是在星期二出生的男孩。另一个也是男生的概率有多大?

答案:13/27

为什么孩子出生的那一天很重要?给定的信息改变了样本空间,样本空间增长了 7 * 7 倍,现在每个孩子的出生日期是一个因素。

让“w”代表一周中任何一天的生日,而“t”代表星期二。

如果在星期二出生的男孩是更小的孩子,在给定的条件下有两种可能:{GwBt,BwBt}。如果他是年长的那个,那么也有两种可能:{BtBw,BtGw}。在合并这些集合时,我们必须小心地移除重复的 BtBt,它包含在 BwBt 和 BtBw 两种情况中。因此,组合集是:{GwBt,BwBt,BtBw,BtGw} - {BtBt}。该集合具有 7(GwBt)+7(BwBt)+7(BtBw)+7(BtGw)-1(BtBt)= 27 个元素。其中 7 (BwBt) + 7 (BtBw) - 1 (BtBt) =13 有两个男孩,给出 13/27。

13/27 ~ .48,更接近 1/2 而不是 1/3,上一个问题的答案。

5.概括:一个家庭有两个孩子。至少有一个孩子是男孩,其病情以概率 p 发生,另一个孩子也是男孩的概率是多少?

答案:(2-p)/(4-p)

让 B '是有这种情况的男孩的数量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果 p = 1,这意味着条件适用于每个男孩和女孩,因此它没有给出任何信息。我们恢复第三部分列出的“至少有一个是男孩”问题,以及它的概率(2-1)/(4-1) = 1/3。

在第 4 部分中,p = 1/7,其中条件是一周中的生日是星期二。它的概率是(2-(1/7)) / (4-(1/7)) = 13/27。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因为 p,患这种疾病的概率范围是从 0 到 1,一个家庭有两个男孩的概率是从 1/2 到 1/3。

这些问题说明了一种违反直觉的现象,即通常独立的两个变量,在给定某些其他信息的情况下,变得有条件依赖。

调音旅行推销员

原文:https://towardsdatascience.com/tuning-a-traveling-salesman-cadfd7d22e1c?source=collection_archive---------11-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The Traveling Salesman, a 1921 comedy with the right title for this article

介绍

几个月前,我发现了艾瑞克·斯托罗兹写的这篇关于遗传算法的文章,他写的这篇文章是为了找到旅行推销员问题的最优解。我觉得很有意思,为了更深入的理解,从头重写项目,对问题空间做了一点探索。

我将让读者参考原始帖子来了解算法的一般解释,但我确实做了一些更改:

  • 我在一些/很多/大部分代码中使用了 Python 的显式类型化功能,来感受一下
  • 我使功能更加灵活和模块化,并为每个功能编写了一个简短的单元测试,这样用户就可以看到幕后发生了什么
  • 我添加了一个可视化,这样用户就可以观看算法的运行

本来我开始这个项目是出于自己的学习和兴趣。然而,我发现了一些我认为值得分享的结果,因为它们突出了调整基因模型的容易和力量。此外,我发现选择一个项目并把它推向一个有趣的方向是多么容易。

调谐

作为一个基准,正常的第一代通常从 2100 到 2400 之间的总行驶距离开始。对于这里介绍的实验,城市的初始人口是相同的,但是第一代的初始顺序是随机的。除了动画之外,使用每代中最合适的个体(到达每个城市的最短距离)来生成图和数字。我在大多数实验中使用了 500 代,不是因为 500 是一个科学挑选的数字,而是它似乎为收敛提供了足够的时间,而没有为糟糕的超参数初始化提供足够的时间来收敛。方便的是,500 英镑也提供了合理的等待时间。

突变率

变异率如何影响种群中最佳个体的收敛时间和路径适应度?

  • 总的来说,似乎没有突变的试验以更长的路线结束,大约 1100-1300 的距离。我从未见过第 500 代跑完 1000 米的。没有突变,每一个连续的世代仅仅依靠繁殖和随机产生新的个体来改进。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 突变率为 0.01 的种群在 500 代中很少超过 1000。我怀疑这是最佳突变率的正确数量级。5 次连续运行的快照显示了一致性:890、939、998、880、953。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 突变率为 0.001 的人群表现良好,但结果的变化比突变率为 0.01 的人群更大。值为 0.001 时,似乎初始的起始路线对于最终的解决方案非常重要。如果起始路线是好的,它可以很快收敛到一个好的解决方案,否则,在没有太多基因变化的情况下,可能会花费更多代。5 次连续运行的快照:866、1046、996、880、1024。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 突变率为 0.1 的群体无法收敛。太多的个体经历突变,使得群体无法传递有用的遗传信息。对于交换变异,好路由和差路由之间的区别可能只是几个节点的一次交换。尽管下图中最终最佳个体的平均距离比最初一代的好几百点,但这是高初始路线距离的产物,我不相信有任何真正重大的进化发生。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

mutationRate: 0.1

精英人数

精英的数量如何影响种群的遗传多样性和保留率?

分析精英的影响需要比突变率更细微的差别。对于测试的每个“精英数量”,我进行了 10 次试验(我知道,不是很多),并记录了 500 代后种群中最佳个体的最终距离,保持其他超参数不变。取这些值的平均值和标准偏差,得出以下结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Total population is 100 individuals, Elites included

我敢说,在只有 5 个数据点的情况下,精英数量与均值和标准差之间的关系看起来大致呈抛物线状,趋势相似。当群体规模为 100 时,精英的最佳数量似乎接近 50。

精英的最佳数量不在任何一个极端,这有一定的直观意义。一些“基因搜索空间”(我肯定有一个技术术语)应该致力于在没有实质性变化的情况下在几代人之间传递好的基因。然而,太多的精英和你的遗传算法没有遇到足够的遗传多样性来快速进步。

群体大小

拥有一大群人会有规模效应吗?

在我所做的大多数试验中,我都在寻找 25 个城市之间的最佳路线,在每一代算法中,都有 100 条可能的路线。在这里,我们可以看到 100 是不是一个好的人口数量选择,或者多生几个会有很大的影响。这可以通过两种方式实现:保持精英的数量不变,或者占总人口的百分比不变。让我们两个都试试。

我运行算法的最大值为 20000 代,但是如果一代中最好的个体的距离小于 852(稍后将详细介绍),我会提前停止并打印这一代。结果是:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Elites = 50, mutationRate = 0.01

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Elites = 0.50 * popSize, mutationRate = 0.01

基于这些结果,我敢说将群体规模从 100 个个体增加到 1000 个个体会极大地提高算法的性能。此外,使用精英的数量是人口规模的高百分比,而不是低的、平坦的数字,允许算法一致地找到解决方案。我认为这比增加群体规模带来的性能提升更重要。

我认为值得注意的是,对于 100 popSize 组,有些试验完成得很快,有些试验需要 5000、10000 或超过 20000 代(在我砍掉它之前的最大值)。这个分布有一个长尾巴,这使得持续使用令人沮丧。

这些试验进行了很长时间。我不确定我是不是有记忆问题,还是真的花了很长时间。一些人口规模为 100 和 1000(只有 50 个精英)的试验超过了 20000 代,尽管很难对这种情况发生的频率有好的感觉,因为运行它们需要很长时间。此外,我试图查看 10000 人的人口规模,但在等待第一个解决方案 10 分钟后,我放弃了。对这些结果持保留态度(我没有使用超级计算机),但我确实认为总体趋势是成立的。即使 10000 人口所需的世代数减少了 75%,我觉得我们可能会达到收益递减点。

使用较大群体时需要考虑的一个问题是所需的计算量会增加。这在生产环境中可能非常重要,但这里不做分析。

溶液质量

最终解与最优解有多接近?

一般来说,遗传算法可以很快达到一个体面的次优解。可以在下面的 gif 中观看进化进度:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

50 elites, 0.01 mutation rate

然而,在许多情况下,当观看融合解决方案的静态帧时,人眼会立即看到明显的改进。会有交叉的路径,通常效率很低。经常会有两个不相连的城市紧挨着,解决方案倾向于将它们分开。后者很容易通过局部的、较小的路径交换来解决。

通常,到 500 代时,总距离不会有很多大的阶梯式下降,任何改善通常都是微小的。有趣的是,我还没有见过任何距离在 851 以下的解,我多次看到同一个数字(到~10 位小数),有多种设置,让我相信它是这些起点的最优解,或者至少是强局部极小值,所以在这种情况下,有时会找到正确的解。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我看着一大堆 10,000 代的运行完成,在大多数情况下,到 851 的最后一小步花了几代才最终发生。由此,我感觉在从随机初始条件中寻找巨大改进方面,遗传方法要比随机搜索好得多,但是寻找最优解主要是在已经很好的解的基础上进行大量的反复试验。

前进

总的来说,这个项目很有趣,感觉相对简单。仅仅几个小时的工作,我就在性能和一致性方面获得了几个数量级的提升。

有一个很好的调试,我经历了几代人以来最优秀的个体之间的巨大差距。这种现象产生了这样的训练曲线:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The final result is not the most fit individual for its generation.

尽管这通常不会影响算法的收敛,但有时会影响最终的解决方案,如上所示。这是因为在记录最佳个体之前,群体中的个体发生了变异。我肯定我不是第一个考虑到遗传算法的人群适应性令人不安的峰值的人,但我很高兴我找到了我的答案。

我还学到了其他一些东西:

  • 从一种非常自由的 Python 风格转变为一种所有内容都显式类型化的风格是很困难的,并且感觉这剥夺了 Python 的通用性。然而,当你越来越抽象的时候,它确实迫使你更多地思考背景中发生的事情。
  • Matplotlib 中的动画没有我预期的那么难,找到其他人的例子帮助很大,尤其是在使用多个艺术家时。
  • 遗传算法似乎适合于在搜索空间很大的情况下进行优化,并且这种改进具有随机性。
  • 我需要在做项目的时候开始写作,这样我就不会忘记我在工作中遇到的所有小片段。

我也有一些想法给那些希望在这方面有所改进的人:

  • 除了self.fitness = 1 / self.routeDistance()还要考虑健身功能。这可能会也可能不会产生有趣的结果,因为选择过程是单调的。
  • 为估计最佳超参数进行更稳健的实验设计。进行多次运行,改变变异率或精英的数量,并找到不同组合的平均值和标准偏差,并不需要太多时间。为了找到最佳的代数,可以使用诸如“120 代后 95%的运行达到最小值”的度量。
  • 调查不同的突变类型,或更多的局部突变。很多时候,会有一小群 3 到 4 个彼此相邻的点,有一个公认的最佳方式来遍历这些点。可能在一个频率上进行短距离交换,而在另一个频率上进行长距离交换。这可以使用基于提议的交换距离的惩罚变异率来合并。
  • 现在,代码使用了许多“for”循环。研究加速/并行化的方法。

我可以看到遗传算法在航班定价、拼车应用程序中匹配乘客和司机或城市规划等领域的潜在用例。目前,我正在阅读两篇论文:UberAI 实验室的深度神经进化进化出玩雅达利游戏的简单程序。我对在这个领域更深入一点或者复制论文很感兴趣,所以如果任何人有他们正在做的有趣的项目,请告诉我!

调整超参数(第一部分):成功减半

原文:https://towardsdatascience.com/tuning-hyperparameters-part-i-successivehalving-c6c602865619?source=collection_archive---------7-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by rawpixel on Unsplash

在这个系列中,我想讨论一些超参数优化技术,它们的优点/缺点等。我目前不打算遵循任何特定的时间顺序。每一部分都应该单独阅读。

介绍

为什么我们应该关心优化超参数?

当我们在机器学习中建立各种模型管道时,我们经常会发现自己有十个、二十个甚至更多的超参数需要我们做出决策。这个决策空间随着每个额外的超参数呈指数增长,使得仔细的分析不切实际,如果不是不可能的话。

为了加速项目的开发过程,我们可能希望将这部分工作自动化。

但是怎么做呢?

简单的网格搜索可能是我们的第一选择,但是正如我们所讨论的,由于维数灾难,这是效率最低(时间)的选择。

下一个最佳解决方案是随机采样超参数空间。这个解决方案是由 Bengio 等人提出的,并且已经被证明优于网格搜索。在这种情况下,通过超越,我的意思是随机搜索能够在更短的时间内使用更少的资源找到模型的更可靠和得分最高的超参数配置。为了理解这一点,让我们看一下图 1。摘自原文

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 1.: Grid Search vs Random Search

正如我们所见,这是经常发生的情况,一些超参数比其他更具决定性。在网格搜索的情况下,尽管采样了 9 次试验,但实际上我们只试验了一个重要参数的 3 个不同值。在随机搜索的情况下,9 次试验将仅测试 9 个不同的决定性参数。

我们能做的比随机搜索更好/更多吗?当然可以!但是*“如何”可能取决于我们所说的“更好*”的确切含义。

存在两种类型的算法,它们是对随机搜索的自然扩展。第一个是贝叶斯优化算法,如 Tree-Parzen Estimators ,它有助于找到统计上更稳健(可靠)和得分更高的配置。

第二种类型,例如成功减半超带,在资源分配上进行优化。在下一节中,我将讨论 成功减半 如何通过比随机搜索更有效地划分和选择随机生成的超参数配置来改进随机搜索,而无需对配置空间的性质做更多假设。更有效的资源分配,意味着给定相同的配置集,成功减半将比随机搜索更快地找到最优配置。

成功减半

那么,我们如何更有效地分配我们的资源呢?让我们来看看摘自本文的图 2。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 2: The validation loss as a function of total resources allocated for two configurations.

通常在实践中,相对于最差的配置,有希望的配置往往得分更高,甚至在过程的早期。

我们走吧!这就是成功减半的意义所在!下面是该算法如何利用这一假设:

  1. 随机抽样一组超参数配置
  2. 评估所有当前剩余配置的性能
  3. 抛出,最差得分配置的下半部分
  4. 回到 2。并重复直到剩下一个配置。

与其浪费大量的训练时间在毫无结果的配置上,不如尽快成功地将投掷减半。因此,可以将更多的训练时间(即资源)分配给更有潜在价值的模型。

实际上…

为了成功应用减半,我们需要找到机器学习库,它允许我们暂时停止模型的训练,最终保存模型,然后稍后重新加载模型并且继续训练

不幸的是,后一点是最有问题的一点。作为一名从业者,不幸的是,您没有时间/预算从头开发自己的库,并且经常依赖于开源云中的可用资源。不幸的是,实践中使用的一些算法缺少这个选项,但幸运的是,我们有很多强大和/或流行的算法!所有 Scikit-Learn 的“热启动”超参数实施都是如此,例如(Extreme)RandomForest、GradientBoosting 等

对于极端的梯度增强库,我只能找到 xgboost 的方法,而 LGBM 在提取增强器时产生了一个 bug。不幸的是,Catboost 没有这个选项,很可能是由于算法本身的性质,它试图通过移动数据来取消每次 boost 迭代的偏向。

对于深度学习,Pytorch,Keras 和 TensorFlow 仍然允许最大的灵活性,所以没有问题!

让我们一步一步来,看看如何在 SuccessiveHalving 的实现中包含所有这些库。

首先,我们需要这些模型的包装器,这迫使我们实现保存/加载模型的定义,更重要的是在重载后进一步训练模型。

下面的基类对此进行了描述:

下面是一个没有提前停止的 XGBOOST 示例:

在这种情况下,我们必须提取助推器并使用功能 API 来进一步训练。出于某种原因,这个类似的技巧会为 Lightgbm 产生一个错误。

借助热启动超参数,Scikit-learn 变得更加简单。

如果这个超参数不存在,恐怕您将不得不完全改装模型,从而损失重新分配资源所获得的时间。

现在我们有了 wapper,我们可以继续实施成功减半了!

变量“eta”是我们增加资源的速率,直到我们达到我们希望使用的资源的最大值。

例如,假设我们最终的 xgboost 模型在 200 个配置的样本中最多应该有 1000 棵树。我们将资源单位设置为 10,这样最初的一批配置将只训练 10 次提升。在每一步,我们用“eta ”= 1.93 倍的估计量来训练新的一批。

更多的例子和实现是可用的这里

没有灵丹妙药…

应用成功减半时的一个大问题是在总资源和配置总数之间找到合适的平衡。

较小的学习率通常与更多的资源、更多的树(在(极端)梯度提升的情况下)或更多的神经网络时期密切相关。

我们如何能调整这样一个选择? HyperBand 提出了一个解决方案,但这是下次的事了!

我写了更多精彩的东西!

@ 在 TensorFlow 中构建决策树

@tensor flow 中的自定义优化器

@XGBOOST 回归预测区间

参考资料:

  1. J.Bergstra 和 Y. Bengio,超参数优化的随机搜索,2011 年
  2. K.Jamieson,A. Talwalka,非随机最佳臂识别和超参数优化,2015 年
  3. 长度李、贾米森、德萨沃、罗斯塔米扎德、塔瓦尔卡尔。超带:基于 Bandit 的超参数优化新方法。arXiv 预印本 arXiv:1711.09784,2017 年
  4. Scikit-Learn,url,http://scikit-learn.org/stable/
  5. J.Bergstra,R. Bardenet,Y. Bengio,B. Kégl,超参数优化算法
  6. github:【https://github.com/benoitdescamps/Hyperparameters-tuning

把数据变成美元?

原文:https://towardsdatascience.com/turning-data-into-dollars-15fa2d0961af?source=collection_archive---------7-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image Credits: Managed Data Center News

上周在 DataWorks 峰会上接受采访时,Bill Schmarzo 提出了一个基本问题,即组织每次点击鼠标收集的数据的价值。【I】当面对“数据是新货币”【ii】以及组织应努力“将数据货币化”【iii】的主张时;应该指出数据的交换价值和使用价值之间的区别。我完全同意他的结论:“数据的价值来自于将其用于做出更好的决策。”正如我们之前所建议的,数据只不过是我们业务现实的代理,除了我们的同事、业务合作伙伴和外部利益相关者的客户体验之外,它没有任何内在价值。哪些类型的数据会突出这些不同的价值观?

*因为人们看待价值的角度不同,所以看待数据的角度也不一样。*几年前,我们与微软的 Kees Pronk 合作推出了 Business Value Matrix(BVM ),以强调手头数据的不同用途,从而强化客户故事。【v】BVM 认为数据提供了将业务挑战与其潜在解决方案联系起来的故事的构建模块。这个立方体用于沿着三个轴探索客户对价值的看法:他们如何使用数据来说明他们的挑战和机遇,他们使用什么类型的证据来证明问题,什么形式的数据将用于判断成功?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The Business Value Matrix™

第一个问题强调了每个利益相关者都有一个主要的信念,即把人、过程或技术作为企业价值的源泉。首先,利益相关者深信人才是企业价值的主要来源——管理层的角色是提高员工、业务合作伙伴和最终客户的知识和技能。在第二种思维模式中,人才不如组织良好的流程重要——业务的价值与组织优化与关键业务流程相关的活动的努力直接相关。最后,在第三种情况下,人们深信技术(信息和物理)的存在本身就足以提高底线。在每种情况下,涉众将收集和监控不同种类的数据,作为组织当前问题和未来机会的证据。

第二个问题说明了关于概念证明的可能性:利益相关者在个人、公司和市场层面寻找证明价值。那些相信个人可以改变公司表现的人;个人生产力的数据是组织成功的代表。对其他人来说,一个企业的好坏取决于它最薄弱的环节——在这里,关于组织如何运作的数据比衡量成功的个人标准更重要。最后,对于一定数量的经理或股东来说,唯一真正的证据是市场本身——组织指标被淡化,而倾向于客户满意度和市场份额的数据。这里,数据科学家需要考虑如何指定组织挑战、分析级别的难度以及哪些证据是可以直接观察到的。

第三个问题集中在利益相关者如何展望成功。对于一定数量的管理者来说,成功就是效率——数据需要关注相关活动的成本和收益。对许多人来说,有效性是比效率更好的成功衡量标准——数据需要衡量组织与其客户之间关系的质量。对于其他人来说,创新是关键指标,数据需要说明组织如何应对外部威胁和机遇。对于其他人来说,利用率是一个不同的指标,这表明当强调组织资源在一段时间内的利用情况时,成功是更好的衡量标准。在这里的每一种情况下,基本问题是数据如何转化为个人或集体行动。客户故事从他们自己在矩阵每个轴上的位置出现。

商业分析与其说是处理数据,不如说是过滤信息,以帮助客户在他们想要讲述的故事中取得成功。如果业务价值矩阵为利益相关方提供了一种工具来设想数据和客户价值之间的潜在桥梁,那么数据科学可以提供将描述性、预测性和规范性分析应用于组织的机制。在我们位于巴约纳的暑期学校,以及我们在欧洲的大师班,我们将帮助您发展您的分析技能。该研究所专注于数据科学在管理人员中的五个应用:在数字时代工作、数据驱动的决策、机器学习、社区管理和可视通信。数据驱动的决策会对你未来的工作和职业产生影响。

Lee Schlenker 是商业分析和社区管理教授,也是 http://baieurope.com 商业分析学院 的负责人。【www.linkedin.com/in/leeschlenker.】你可以在推特上关注我们https://twitter.com/DSign4Analytics

— — — — — — -

【我】艾伯特森,m .(2017)数据的价值?都是关于终结游戏,硅角度

【ii】摩根·l .(2016)8 种数据货币化的方式《信息周刊》

【iii】Wixom,b .和 Ross,J. (2017),如何将你的数据货币化,麻省理工斯隆管理评论

【iv】Schlenker,L. (2017),数据不仅仅是数据…,媒介

Schlenker,l .和 Pronk K. (2009),价值之旅,Goodfellow 出版社

用深度学习把堡垒之夜变成 PUBG(cycle gan)

原文:https://towardsdatascience.com/turning-fortnite-into-pubg-with-deep-learning-cyclegan-2f9d339dcdb0?source=collection_archive---------4-----------------------

理解用于图像风格转换的 CycleGAN 并探索其在游戏图形模块中的应用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A Neural Network’s attempt at recreating Fortnite in the visual style of PUBG.

如果你是一个游戏玩家,你一定听说过两个疯狂流行的皇家战役游戏,堡垒之夜和 PUBG。这是两个非常相似的游戏,100 名玩家在一个小岛上决一雌雄,直到只剩下一名幸存者。我喜欢堡垒之夜的游戏性,但倾向于更喜欢 PUBG 的更真实的视觉效果。这让我想到,我们能不能有游戏的图形模块,让我们可以选择我们喜欢的视觉效果,而不必依赖游戏开发商为我们提供这种选择?如果有一个 mod 可以在 PUBG 的视觉效果中渲染堡垒之夜的画面会怎么样?这就是我决定探索深度学习是否有所帮助的地方,我遇到了一种叫做 CycleGANs 的神经网络,它碰巧非常擅长图像风格转移。在本文中,我将介绍 CycleGANs 是如何工作的,然后训练它们将堡垒之夜视觉转换成 PUBG。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Fortnite (left) with it’s cartoonish visuals and PUBG (right) with its more realistic visuals.

什么是 CycleGANs?

CycleGANs 是一种用于跨域图像风格传递的生成对抗网络。他们可以被训练将一个领域的图像,比如堡垒之夜,转换成另一个领域的图像,比如 PUBG。这项任务是以无人监督的方式执行的,即,没有来自这两个域的图像的一对一映射。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Original Github implementation and its results can be found here.

网络能够理解原始域的图像中的对象,并应用必要的变换来匹配目标域的图像中的相同对象的外观。该算法的原始实现被训练成将马转换成斑马,将苹果转换成橙子,将照片转换成绘画,结果令人惊叹。

它们是如何工作的?

让我们以堡垒之夜为例,以 PUBG 为例,尝试理解 CycleGANs 是如何工作的。使用两个游戏的大量截图,我们训练了一对生成性对抗网络,其中一个网络学习堡垒之夜的视觉风格,另一个学习 PUBG 的视觉风格。这两个网络以循环的方式同时被训练,以便它们学会在两个游戏中的相同对象之间形成关系,从而进行适当的视觉转换。下图显示了这两个网络循环设置的一般架构。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Cycle from “Real Fortnite” to “Fake PUBG” to “Reconstructed Fortnite”.

我们从堡垒之夜的原始图像开始训练过程。我们将训练两个深度网络,一个生成器和一个鉴别器。随着时间的推移,鉴别者将学会区分堡垒之夜的真假图像。生成器将被训练为使用来自训练集的 PUBG 的随机截图将输入图像从原始域转换到目标域。

为了确保这个转换是有意义的,我们强加了一个重建条件。这意味着我们同时训练另一组生成器/鉴别器,该生成器/鉴别器从伪域重建原始域中的图像。我们强加了这样一个条件,即该重建必须与原始图像相似,给我们一个循环损失值,我们的目标是在训练过程中最小化该值。这类似于自动编码器,除了我们不是在中间步骤的潜在空间中寻找编码,而是在我们的目标域中寻找整个图像。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Overview of Generator F2P shown in the previous figure.

这里使用的发生器网络(F2P)由三个主要卷积模块组成。第一个在低维潜在空间中找到了堡垒之夜截图的编码。这种编码被转换成在相同的潜在空间中表示 PUBG 的编码。然后,解码器从转换后的编码构建输出图像,给我们看起来像 PUBG 的堡垒之夜图像。

在这个培训过程中,我面临的一个限制是,由于 GPU 内存的限制,我只能处理 256x256 的图像。这会显著影响结果,但是如果您的视频内存超过 8gb,您可以尝试生成多达 512x512 的图像。如果可以,请在这里告诉我

结果

经过 12 个小时的训练后,CycleGAN 生成的图像似乎很有希望。该网络成功地将堡垒之夜的天空、树木和草地的颜色转换成了 PUBG 的颜色。堡垒之夜过度饱和的颜色被转换成了 PUBG 更真实的颜色。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

天空看起来不那么蓝,草和树的卡通绿色看起来更接近在 PUBG 看到的。它甚至学会了用 PUBG 的枪和弹药指示器替换屏幕底部的生命计!在这两个领域中无法联系的是玩家的外观,这就是为什么它周围的像素有点模糊。总的来说,该网络在识别跨两个领域的对象并转换它们的外观方面做得不错。

要查看更长的结果,请查看下面嵌入的视频。如果你喜欢你所看到的,别忘了点击这里并订阅我的 YouTube 频道!

游戏中图形模块的应用

虽然结果对我来说很好,但很明显,在我可以用 PUBG graphics 真正玩堡垒之夜之前,我们还有很长的路要走。但是,一旦我们能够使用这些网络实时生成更高分辨率的图像,未来就有可能为游戏构建图形 mod 引擎,而不必依赖游戏开发者。我们可以使用我们喜欢的游戏的视觉风格,并将其应用到任何其他游戏中!

我将探索如何通过使用我在本文中讨论的相同技术将游戏视觉转换成现实生活中的照片来实现游戏中的照片真实感。如果你想保持跟踪,请在媒体或我的 YouTube 频道上关注我。感谢您的阅读!

编辑:这里是一些相同的更新结果。

升温:模型蒸馏的机制

原文:https://towardsdatascience.com/turning-up-the-heat-the-mechanics-of-model-distillation-25ca337b5c7c?source=collection_archive---------5-----------------------

当我第一次读到这篇论文时,我被两种冲动所触动。首先,我绝对应该写一个帖子来解释它,因为它的许多想法都是优雅而令人信服的——从它对网络存储信息意味着什么的思考,到对 softmax 正在做什么的更好的直观感受。第二,也许这样做是白费力气,因为原著本身写得太好了。

在这种情况下,我认为我无法给出比 Hinton,Vinyal & Dean 的原始论文更好的介绍了:

许多昆虫的幼虫形态最适合从环境中吸取能量和营养,而完全不同的成虫形态最适合完全不同的旅行和繁殖要求。…与昆虫的类比表明,如果能更容易地从数据中提取结构,我们应该愿意训练非常繁琐的模型。繁琐的模型可以是单独训练的模型的集合,或者是用非常强的正则化子(例如 dropout [9])训练的单个非常大的模型。一旦繁琐的模型被训练,我们就可以使用不同种类的训练,我们称之为“提炼”,将知识从繁琐的模型转移到更适合部署的小模型

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

乍一看,这似乎难以置信,违反直觉。提取信息意味着什么?如何使用简单模型的架构和参数结构来表示复杂模型学习到的函数?

一个对我有用的比喻——为简单和抽象道歉——是主模型本质上像一只母鸟,消化她的食物,以便更小、更简单的模型可以更容易地消耗它。最初,每个观察仅由其训练集标签表示:0 或 1(在两个类的情况下)。现实并没有告诉我们单个事件的概率,而是告诉我们表面下的结果有多大的可能性或边际性;我们只看到发生了什么。

但是,在学习决策边界的过程中,复杂模型隐含地开始捕捉更细微的信息。一个给定的例子显然是其类的中心代表,还是它是边缘的,接近决策边界,从而难以与备选类区分?如果我们在一个多种类的环境中操作,这个例子中最有可能的种类“哈士奇”是否更接近作为次优选择的“雪橇犬”或“吉娃娃”的决策界限?希望这些例子能给我们一些直觉,让我们知道在一个模型的输出分数中捕捉到的这类问题的答案,可以为复杂模型所学习到的内部表征提供线索。模型提炼的关键思想是:模仿这种学习到的表示应该比一开始就学习它要容易得多,这意味着(近似)模仿的任务可以通过更简单的模型来完成。

打开暖气

温度在(模型)蒸馏过程中的作用是将模型推到一个极端概率较小的区域,这样它们对我们的计算更有帮助。

为了理解这是怎么回事,我发现绕一圈了解一下 softmax 在做什么以及为什么要这么做是很有价值的。

直到我最近更深入地考虑它,我基本上把 softmax 作为“一个将实数输出压缩成概率分布的运算符”存储在我的脑海中。当然,它确实是这样做的:数学上很清楚,分子中所有类的 sigmas 加起来就是一,只是通过构造。但是我从来没有认真思考过“softmax”名字中的“max”部分。softmax 不仅仅是一个规范化操作符:它是一个规范化操作符,对较大的值有很强的特权。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当其他人第一次看到这个公式时,这可能是他们完全内化的东西,但我在这里找到了放大一些具体细节的价值。(术语注释:在上面的公式中,当您看到下标 x 值时,对于所有 j 类,我将这些值称为“logits ”,有点不精确地遵循输入到逻辑转换中的实数值的命名约定)。如果有(1,2,3)的 logit,那么在 logit 空间中,每对相邻的有序数之间有相等的间隙。然而,在指数空间中,差距随着 logit 的大小而变大。(2.7,7.38,20.08)是这些逻辑在被指数化后的翻译。当在指数空间中进行归一化时,得到的是(0.08,. 25,. 67),而不是仅归一化逻辑本身得到的(. 166,. 33,. 5)。如您所见,指数化的输出更接近于 argmax 函数,它将所有权重放在单个最高值上,而不是其他位置(这里的“argmax”指的是一个布尔函数,它指示哪个类包含某个输入的最高值)

从通常用于训练神经网络的交叉熵损失函数的角度来看,这种与 argmax 的相似性是有益的,因为该损失函数是真正对应于给定观察的类的对数模型分数的-1 倍。不关心精确校准的概率:它希望将尽可能多的概率放在真实类上。像这样的目标函数显然受益于 argmax 框架,而这正是 softmax 想要逼近的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The cross-entropy loss equation

但是,当您的目标不仅是与另一个模型交流您的最佳猜测类是什么,而且交流可能性较小的类的相对大小时,这种策略就不那么有益了。这是因为,除了夸大最可能类的值,softmax 还会将可能性较小的类的值推得更小、更接近。你可以首先想到两个简单的归一化(即每个值除以所有值的总和),一个是你的值为(1,6,10),另一个是你的值为(1,6,100)。前者的归一化值为(0.06,0.35,0.59)。对于后者,我们得到(0.009,0.056,0.934)。因此,在最大值相对于其他两个值非常大的世界中,较小值之间的相对差异被压缩并且大部分丢失,这两个次要类之间的差异从 0.294 到 0.047。这让我们更接近 arg max 的情况,其中模型只传达一个信号:它认为哪个类更有可能。

考虑到我们希望在模型提炼过程中传递的各种微妙信息,任何导致我们学习到的模型输出崩溃到 1/0,甚至更强烈地倾向于这种离散输出的东西,都是一种障碍。更具体地说,在交叉熵框架中,如果我们想象这些概率进行训练(也就是说:用概率替换 y-i 值),这些概率最终会在该类别的学习概率对你的总体损失的影响的线性组合中起作用。这意味着这种价值上的线性差异将对我们从这些二级课堂中学习信息的能力产生有意义的影响。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The e^x function: a good one to have in your head to build intuition here

Temperature 的工作原理是降低发送到 softmax 函数的逻辑值的绝对值,将它们除以固定的恒定温度值 T,然后对这些较小的值求幂并求和。简单地说,如果您考虑一下标度一端的逻辑值本身和另一端的指数逻辑值,温度可以用于在这两端之间进行插值,随着温度值变高,指数运算的 argmax 倾向会降低。这是因为,当您将 logits 划分为更小的值时,您会将所有指数化的类值进一步推向左侧,从而使给定输入的类输出之间的比例差异变得更接近线性。具体来说,如果你看上面的图,你可以很容易地说服自己,你从(2,1)的输入得到的相对差异与从(1,0.5)的输入产生的相对差异有意义,后者对应于温度 T=2。

这种方法是蒸馏框架的关键,它类似于:

  • 正常训练复杂模型(CM ),即温度为 1
  • 获取一些额外的数据集,并通过 CM 运行,但在 softmax 层中将 logits 转换为概率时使用大于 1 的温度。这个温度值在这里是一个超参数。这里有一个有趣的注意事项是,这个额外的数据集实际上不需要贴上基本事实标签:我们所关心的是了解复杂模型对给定观察的想法,而不是基本事实是什么。也就是说,如果你有基本事实标签,你通常可以通过使用它们来改进训练(为了简单起见,我不会在这里讨论)
  • 使用这些“软目标”概率来训练你的简单模型(SM),也是在温度> 1 的情况下。
  • 一旦你的提取模型被训练,在温度 1 下操作它,这样你得到的结果可能更 argmax-esque,因此可以更清楚地与使用典型 softmax 训练的模型进行比较

更好地在一起:整体应用

尽管该论文概述的提取策略适用于任何可以输出概率得分的分类器,但作者特别关注提取集成的价值。

集成是有效的,因为当你获取多个样本时——在这种情况下,这里的样本是一个模型,用一些不同的初始条件训练——并对它们进行平均,这相对于训练单个模型来说减少了方差。从理论上讲,方差和偏差是模型误差的两个来源,因此方差的减少是集成在许多机器学习应用中表现非常好的经验现实背后的理论证明。

出于解释或部署后勤方面的原因,可能需要将该集合所获得的信息压缩到一个模型中。但是,根据定义,如果您训练组成集成的任何模型的单一版本,您将只获得一个高方差估计点,而不是整个集成的好处。然而,如果你训练的是全体成员的平均值(也可以看作是概率得分),那么你就是在教二级模型学习所有成员的聚合意见,而不是简单地根据原始标签生成它自己的函数。

事实上,作者发现,当他们在语音识别数据集上测试他们的方法时,根据聚合集成输出训练的提取模型比简单地根据真实情况训练的单一模型做得更好。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A diagram from the paper; WER here corresponds to “Word Error Rate”

一些最后的想法

在我最喜欢的漫画《T1》中,主角认为最好的知识是产生有趣的新问题的知识,而不仅仅是答案。虽然我承认这有点浪漫,而不是务实的知识方法,但它对我很有吸引力。

所以,在这篇文章的最后,我将举起一杯从这篇论文留给我的问题中提炼出来的东西。(注意:完全有可能存在回答这些问题的范围研究:我没有对这个领域做全面的文献综述。如果你知道他们,一定要把他们送到我这里来!)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Raise a glass to freed-er, I mean, free parameters

  • 当问题的类别数量较少,因而可供学习的第二类信号不丰富时,蒸馏的有效性会下降到什么程度?
  • 有没有办法将这种温度/插值软目标框架推广到像随机森林这样不使用 softmax 来生成输出的技术?
  • 通过对复杂模型进行更多的剖析,并直接模拟复杂模型的表示空间,我们可以获得多大的性能提升?(即使用 softmax 之前的层的单位作为辅助信号)。

教程:通过手势识别字母——深度学习和 OpenCV 应用

原文:https://towardsdatascience.com/tutorial-alphabet-recognition-deeplearning-opencv-97e697b8fb86?source=collection_archive---------3-----------------------

注意:文章过时了。我更改了我的 GitHub 用户名,结果 GitHub 列表不显示。请在此访问项目代码。

这是一个关于如何构建深度学习应用程序的教程,该应用程序可以实时识别由感兴趣的对象(在这种情况下是瓶盖)书写的字母表。

项目描述

深度学习技术能力的一个流行演示是图像数据中的对象识别。

python 中的这个深度学习应用程序通过网络摄像头实时捕捉的手势来识别字母表。允许用户使用感兴趣的对象(在这种情况下是水瓶盖)在屏幕上书写字母表。

您可以访问完整的项目代码:

[## ACL 21/Alphabet _ Recognition _ 手势

更新]:我将不再关注与回购相关的问题或邮件,因为我目前非常忙…

github.com](https://github.com/acl21/Alphabet_Recognition_Gestures)

工作示例

代码要求

代码在 Python 版本中,使用 OpenCV 和 Keras 库。

跟随这篇中帖在 Python 3 中安装 OpenCV 和 Keras。

数据描述

机器学习和深度学习的对象识别的“扩展 Hello World”是用于手写字母识别的 EMNIST 数据集。它是 MNIST 数据集的扩展版本(物体识别的“Hello World”)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The letter ‘e’ is stored in a 28 x 28 numpy array as shown above.

代码解释

步骤 1:训练一个多层感知器模型

1.1 负载数据

我们使用 Python 的 mnist 库来加载数据。

现在让我们准备好数据,以供模型使用。将数据分成训练集和测试集,标准化图像和其他初步的东西。

1.2 定义模型

在 Keras 中,模型被定义为一系列层。我们首先初始化一个“序列模型”,然后添加包含各自神经元的层。下面的代码做了同样的事情。

正如预期的那样,该模型采用 28 x 28 像素(我们展平图像,并将每个像素传递到一维向量中)作为输入。模型的输出必须是对其中一个字母的决策,因此我们将输出层设置为 26 个神经元(决策是根据概率做出的)。

1.3 编译模型

既然模型已经定义好了,我们就可以编译它了。编译模型使用了后台(所谓的后端)的高效数值库,如 Theano 或 TensorFlow。

这里,我们指定了训练网络所需的一些属性。通过训练,我们试图找到最佳的权重集来对输入做出决策。我们必须指定用于评估一组权重的损失函数、用于搜索网络的不同权重的优化器以及我们希望在训练期间收集和报告的任何可选指标。

1.4 拟合模型

在这里,我们使用模型检查点来训练模型,这将帮助我们保存最佳模型(根据我们在上一步中定义的指标最佳)。

1.5 评估模型

该模型在 EMNIST 数据集上的测试精度为 91.1%

1.6 把所有东西放在一起

将所有步骤放在一起,我们得到了构建一个基于 EMNIST 数据的体面的 MLP 模型所需的完整代码。

步骤 2:训练卷积神经网络模型

2.1 和 2.2 —加载数据并定义模型

这两个步骤与我们在构建 MLP 模型时实施的步骤完全相同。

2.3 定义模型

出于超出本教程范围的原因,我定义了上面的 CNN 架构来解决手头的问题。要了解更多关于 CNN 的信息,请访问这个教程页面,它是最好的!

2.3 编译模型

Unlike the MLP model, this time I am using the ADADELTA optimizer

2.4 适合车型

要了解模型变量历元 如何影响出模型性能,请访问

2.5 评估模型

该模型在 EMNIST 数据集上的测试精度为 93.1%

2.6 把所有东西放在一起

将所有这些放在一起,我们得到了构建一个基于 EMNIST 数据训练的像样的 CNN 模型所需的完整代码。

第三步:初始化东西

在我们研究识别代码之前,让我们初始化一些东西。

首先,我们加载在前面步骤中构建的模型。然后我们创建一个字母字典, blueLowerblueUpper 边界来检测蓝色瓶盖,一个 kernal 来平滑沿途的事物,一个空的 黑板 来存储白色的文字(就像 EMNIST 数据集中的字母表),一个 deque 来存储所有的

第四步:捕捉文字

一旦我们开始逐帧读取输入的视频,我们就试图找到蓝色的瓶盖,并将其用作一支笔。我们使用 OpenCV 的 cv2。VideoCapture() 从视频文件或网络摄像头实时逐帧(使用 while 循环)读取视频的方法。在这种情况下,我们将 0 传递给方法以从网络摄像头读取数据。下面的代码演示了同样的情况。

一旦我们开始读取网络摄像头馈送,我们就会借助 cv2.inRange() 方法不断在帧中寻找蓝色对象,并使用事先初始化的 blueUpperblueLower 变量。一旦我们找到轮廓,我们做一系列的图像操作,并使其平滑。平滑只是让我们的生活更轻松。如果你想知道更多关于这些操作——侵蚀、变形和扩张,请查看这个

一旦我们找到轮廓(当找到轮廓时, if 条件通过),我们使用轮廓的中心(蓝色帽)在屏幕上绘制它的移动。下面的代码做了同样的事情。

上面的代码检查是否找到了轮廓,如果是,它取最大的一个(假设是瓶盖),使用**cv2 . minenclosingcircle()cv2.circle() 方法围绕它画一个圆,借助cv2 . moments()**方法得到找到的轮廓的中心。最后,中心被存储在一个名为 的 deque 中,这样我们就可以将它们全部连接起来,形成一个完整的文字。

我们在 框架黑板 上显示图纸。一个用于外部显示,另一个将其传递给模型。

注意:我已经写了一个关于建立一个绘图环境的简短教程,它允许我们像在一个画图应用程序中一样绘图,在这里查看以清楚地理解正在发生的事情。

第五步:刮掉书写内容,并将其传递给模型

一旦用户写完了,我们就把之前存储的点连接起来,放在黑板上,然后传给模型。

当我们停止书写时,控制进入这个 elif 块(因为没有检测到轮廓)。一旦我们验证了 deque 不为空,我们现在就可以确定写入已经完成。现在我们取 黑板 图像,再做一次快速轮廓搜索(刮掉字迹)。找到后,我们对其进行适当的剪切,调整其大小以满足我们构建的模型的输入尺寸要求,即 28 x 28 像素。然后传给两个模特。

步骤 6:显示模型预测

然后,我们在 窗口上显示我们的模型做出的预测。然后我们使用 cv2.imshow() 方法显示它。当我们进入 循环从网络摄像头读取数据时,脱离 后,我们释放摄像头并破坏所有窗口。

执行

1。下载数据

这里下载数据文件夹,放入你的项目目录。

2。建立 MLP 模型

**> python mlp_model_builder.py**

3。建立 CNN 模型

**> python cnn_model_builder.py**

4。运行引擎文件

**> python alphabet_recognition.py**

5。抓起蓝色瓶盖

玩得开心点。

结论

在本教程中,我们建立了两个深度学习模型,一个 MLP 模型和一个 CNN 模型,在著名的 EMNIST 数据上进行训练。并用这些模型来实时预测我们感兴趣的物体所写的字母。我鼓励你调整两个模型的架构,看看它们如何影响你的预测。

希望这个教程是有趣的。感谢阅读。

活也让别人活!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Amador Loureiro on Unsplash

教程:Python 中的异步语音识别

原文:https://towardsdatascience.com/tutorial-asynchronous-speech-recognition-in-python-b1215d501c64?source=collection_archive---------0-----------------------

一个(相当)简单的技术,用于使用 Google 有点儿有点儿令人困惑的语音识别 API

让我们面对它:它很难与谷歌的机器学习模型竞争。该公司拥有如此多的数据,以至于在准确性和质量方面彻底击败了竞争对手。不幸的是,谷歌在为其 API 提供易于理解和最新的文档方面做得不够好,这使得初级和中级程序员很难入门。

我最近在尝试使用其语音识别 API 转录大约 1,200 条新闻广播时遇到了这个问题。因为 Google 最近改变了它的云 API,所以我在网上找到的很多例子都不是很有帮助。甚至当我更新了云 SDK 的时候,我仍然在尝试运行他们的样本代码时遇到了问题。

一种替代方法是使用 SpeechRecognition 库,但是据我所知,它只适用于同步请求,同步请求的持续时间被限制在一分钟以内。也许一个更好的程序员可以在使用谷歌的 Python API 的同时找到解决方案,但是你被我卡住了。😃

要完成本教程,您需要以下工具:

  • Python 2.7
  • 一个谷歌账户
  • Sox
  • 一个 wav 文件(此处下载

激活云服务

前往谷歌云主页并注册免费试用。只要注册,你就可以获得 300 美元的免费积分。

1)创建一个“项目”来存储你的凭证和账单信息

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2)启用谷歌语音 API,按照提示激活计费。不要担心,在您升级到付费帐户之前,不会向您收费。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3)创建一个 API 密匙并保存起来以备后用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4)创建一个云存储“桶”。这是我们将要存放我们想要转录的文件的地方。不幸的是,为了使用异步服务,你不得不在谷歌存储器上托管文件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

安装 Sox

下一步是在我们的机器上安装 Sox。Sox 是一个非常容易使用的命令行工具,用于操作音频文件。

如果您使用的是 Mac ,您可以通过在终端中运行以下命令来使用 Homebrew 安装 Sox 及其依赖项:

brew install sox

如果你使用的是 Ubuntu ,你可以从终端运行以下命令:

sudo apt-get install libasound2-plugins libasound2-python libsox-fmt-all
sudo apt-get install sox

将音频转换为单声道

现在我们已经安装了 Sox,我们可以开始设置 Python 脚本了。因为 Google 的语音识别 API 只接受单通道音频,我们可能需要使用 Sox 来转换我们的文件。您可以通过查看计算机上的文件属性来进行检查:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果您的文件已经是单声道的,您可以跳过这一步。如果没有,我们可以使用 Sox 很容易地将其从 Python 转换过来。

  • 1)导入子进程库以访问我们的可执行程序
import subprocess
  • 2)编写并运行 Sox 命令来编写一个只有一个通道的新文件。
filename = "test/test.wav"
newfilename = "test/newtest.wav"
command = ['sox', filename, '-c', '1', newfilename] 
subprocess.Popen(command)
  • 3)验证我们新转换的文件是否正确。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

上传转换后的文件

随着我们的音频转换为单声道,我们需要做的就是将新的音频上传到谷歌存储,然后我们就可以开始我们的 Python 脚本了。虽然这可能是您希望使用 Google Storage API 模块以编程方式完成的事情,但这超出了本教程的范围。

相反,我们将只使用我们之前使用的基于 web 的 GUI。您需要选中“公开共享”选项,如图所示。请记住,这将对整个世界开放,直到您将其从 Google Storage 中删除或更改权限。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1)导入请求库,用于向 Google 的 API 和 json 库发出请求,以解析响应。

import requests
import json

2)定义我们在发出请求时将使用的 URL。您需要用您之前制作的 API 密钥来填充空白。

url = "https://speech.googleapis.com/v1/speech:longrunningrecognize?key=YOURAPIKEYHERE"

3)为我们的 JSON 请求创建参数。这些只是我们可以指定的几个可能的参数。你可以在这里 查看其他

payload = {
    "config": {
      "encoding": "LINEAR16",
      "sample_rate_hertz": 48000,
      "language_code": "en-US" },
    "audio": {
        "uri": "gs://BUCKETNAMEHERE/FILENAMEHERE.wav" }
}

发送请求并保存响应。

r = requests.post(url, data=json.dumps(payload))

响应应该包括一个数字标记,我们将使用它来访问我们的转录结果。输出将类似于这样:

Out[1]: {u'name': u'5284939751989548804'}

我们可以这样保存令牌:

json_resp = r.json()
token_resp = json_resp['name']

检索结果(你需要等待几秒钟)。

url = "https://speech.googleapis.com/v1/operations/" + str(token_resp) + "?key=YOURAPIKEYHERE"
content_response = requests.get(url)
content_json = content_response.json()

输出应该是这样的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

瞧啊。

您已经准备好为自己的项目构建语音识别管道。如果您有任何问题(或更可能的建议),请不要犹豫,发表评论。

教程:构建车道检测器

原文:https://towardsdatascience.com/tutorial-build-a-lane-detector-679fd8953132?source=collection_archive---------2-----------------------

Waymo 的自动驾驶出租车服务🚕本月刚刚上路——但是自动驾驶汽车是如何工作的呢?道路上画的线向人类驾驶员指示车道在哪里,并作为相应地驾驶车辆的方向的指导参考,以及车辆代理如何在道路上和谐互动的约定。同样,识别和跟踪车道的能力对于开发无人驾驶车辆的算法至关重要。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在本教程中,我们将学习如何使用计算机视觉技术建立一个跟踪道路车道的软件管道。我们将通过两种不同的方法来完成这项任务。

目录:

方法一:霍夫变换
方法二:空间 CNN

方法 1:霍夫变换

大多数车道设计得相对简单,不仅是为了鼓励有序,也是为了让人类驾驶员更容易以一致的速度驾驶车辆。因此,我们的直观方法可能是首先通过边缘检测和特征提取技术来检测相机馈送中的突出直线。我们将使用 OpenCV,一个计算机视觉算法的开源库来实现。下图概述了我们的管道。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在我们开始之前,这里是我们的成果演示:

1。设置您的环境

如果您尚未安装 OpenCV,请打开终端并运行:

pip install opencv-python

现在,通过运行以下命令克隆教程存储库:

git clone [https://github.com/chuanenlin/lane-detector.git](https://github.com/chuanenlin/lane-detector.git)

接下来,用文本编辑器打开detector.py。我们将在这个 Python 文件中编写本节的所有代码。

2。处理视频

我们将以一系列间隔为 10 毫秒的连续帧(图像)的形式输入车道检测的样本视频。我们也可以随时按“q”键退出程序。

3。应用 Canny 检测器

Canny 检测器是一种针对快速实时边缘检测而优化的多阶段算法。该算法的基本目标是检测亮度的急剧变化(大梯度),例如从白到黑的转变,并在给定一组阈值的情况下将它们定义为边缘。Canny 算法有四个主要阶段:

A .降噪

与所有边缘检测算法一样,噪声是一个至关重要的问题,经常导致错误检测。5x5 高斯滤波器用于卷积(平滑)图像,以降低检测器对噪声的灵敏度。这是通过使用正态分布数字的内核(在本例中为 5x5 内核)在整个图像上运行来实现的,将每个像素值设置为其相邻像素的加权平均值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5x5 Gaussian kernel. Asterisk denotes convolution operation.

B .强度梯度

然后,沿 x 轴和 y 轴对平滑后的图像应用 Sobel、Roberts 或 Prewitt 内核(Sobel 用于 OpenCV ),以检测边缘是水平的、垂直的还是对角线的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sobel kernel for calculation of the first derivative of horizontal and vertical directions

C .非最大抑制

非最大抑制应用于“薄”和有效锐化边缘。对于每个像素,检查该值是否是先前计算的梯度方向上的局部最大值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Non-maximum suppression on three points

a 在垂直方向的边上。由于梯度垂直于边缘方向,B 和 C 的像素值与 A 的像素值进行比较,以确定 A 是否是局部最大值。如果 A 是局部最大值,则测试下一点的非最大抑制。否则,A 的像素值被设置为零,并且 A 被抑制。

D .滞后阈值

在非最大值抑制之后,强像素被确认为在最终的边缘图中。但是,应该进一步分析弱像素,以确定它是构成边缘还是噪声。应用两个预定义的 minVal 和 maxVal 阈值,我们设置任何强度梯度高于 maxVal 的像素是边缘,任何强度梯度低于 minVal 的像素不是边缘并被丢弃。如果像素连接到强度梯度高于 maxVal 的像素,则强度梯度在 minVal 和 maxVal 之间的像素仅被视为边缘。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Hysteresis thresholding example on two lines

边 A 高于 maxVal,因此被视为边。边 B 位于 maxVal 和 minVal 之间,但不连接到 maxVal 之上的任何边,因此被丢弃。边 C 位于 maxVal 和 minVal 之间,并连接到边 A,即 maxVal 之上的边,因此被视为边。

对于我们的流水线,我们的帧首先被灰度化,因为我们只需要亮度通道来检测边缘,并且应用 5×5 高斯模糊来降低噪声以减少伪边缘。

4。分割车道区域

我们将手工制作一个三角形遮罩来分割车道区域,并丢弃帧中不相关的区域,以增加我们后期的有效性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The triangular mask will be defined by three coordinates, indicated by the green circles.

5。霍夫变换

在笛卡尔坐标系中,我们可以通过绘制 y 对 x 将直线表示为y = mx + b,然而,我们也可以通过绘制 b 对 m 将该直线表示为霍夫空间中的单个点,例如,具有方程y = 2x + 1的直线可以在霍夫空间中表示为(2, 1)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在,如果我们要在笛卡尔坐标系中画一个点,而不是一条线。有许多可能的线可以通过该点,每条线具有不同的参数 m 和 b 值。例如,点(2,12)可以通过y = 2x + 8y = 3x + 6y = 4x + 4y = 5x + 2y = 6x等等。这些可能的直线可以在霍夫空间中绘制为(2, 8)(3, 6)(4, 4)(5, 2)(6, 0)。注意,这在霍夫空间中产生了一条 m 对 b 坐标的线。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每当我们看到笛卡尔坐标系中的一系列点,并且知道这些点由一些线连接,我们就可以通过首先将笛卡尔坐标系中的每个点绘制到霍夫空间中的相应线,然后找到霍夫空间中的交点,来找到该线的方程。霍夫空间中的交点表示始终通过系列中所有点的 m 和 b 值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由于我们通过 Canny 检测器的帧可以简单地解释为表示图像空间中边缘的一系列白点,因此我们可以应用相同的技术来识别这些点中的哪些点与同一条线相连,如果它们相连,其方程是什么,以便我们可以在我们的帧上绘制这条线。

为了解释的简单,我们使用笛卡尔坐标来对应霍夫空间。然而,这种方法有一个数学缺陷:当直线是垂直的时,梯度是无穷大,不能用霍夫空间表示。为了解决这个问题,我们将使用极坐标来代替。过程还是一样的,只是除了在霍夫空间中绘制 m 对 b,我们将绘制 r 对θ。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

例如,对于极坐标系统上带有x = 8y = 6x = 4y = 9x = 12y = 3的点,我们可以绘制出相应的霍夫空间。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们看到霍夫空间中的线相交于θ = 0.925r = 9.6。由于极坐标系统中的一条线由r = xcosθ + ysinθ给出,我们可以推导出穿过所有这些点的单条线被定义为9.6 = xcos0.925 + ysin0.925

通常,在霍夫空间中相交的曲线越多,意味着由该交点表示的线对应的点越多。对于我们的实现,我们将在霍夫空间中定义最小阈值数量的交叉点来检测直线。因此,霍夫变换基本上跟踪帧中每个点的霍夫空间交点。如果交叉点的数量超过定义的阈值,我们用相应的θ和 r 参数识别一条线。

我们应用霍夫变换来识别两条直线,这两条直线将是我们的左右车道边界

6。可视化

车道被可视化为两个浅绿色的线性拟合多项式,它们将覆盖在我们的输入帧上。

现在,打开终端并运行python detector.py来测试您的简单车道检测器!如果您错过了任何代码,这里是完整的解决方案和注释:

方法 2:空间 CNN

方法 1 中的这种手工制作的传统方法似乎还不错……至少在笔直的道路上是这样。然而,很明显,这种方法在弯道或急转弯时会立即失效。此外,我们注意到车道上由直线组成的标记的存在,如彩色箭头标志,可能会不时干扰车道检测器,从演示渲染中的小故障可以明显看出。克服这个问题的一种方法是将三角形遮罩进一步细化为两个独立的、更精确的遮罩。然而,这些相当任意的掩模参数根本不能适应各种变化的道路环境。另一个缺点是,由于没有满足霍夫变换阈值的连续直线,车道检测器也会忽略具有虚线标记或根本没有清晰标记的车道。最后,影响线路可见度的天气和照明条件也可能是一个问题。

1。架构

虽然卷积神经网络(CNN)已被证明是有效的架构,既可以识别图像低层的简单特征(例如边缘、颜色梯度),也可以识别更深层次的复杂特征和实体(例如对象识别),但它们通常难以表示这些特征和实体的“姿态”——也就是说,CNN 在从原始像素中提取语义方面很棒,但在捕捉帧中像素的空间关系(例如旋转和平移关系)方面表现不佳。然而,这些空间关系对于车道检测的任务是重要的,其中存在强的形状先验但弱的外观一致性。

例如,仅通过提取语义特征很难确定交通杆,因为它们缺乏明显和连贯的外观线索,并且经常被遮挡。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The car to the right of the top left image and the motorbike to the right of the bottom left image occlude the right lane markings and negatively affect CNN results

然而,由于我们知道交通杆通常表现出类似的空间关系,例如垂直竖立,并放置在道路的左侧和右侧,我们看到了加强空间信息的重要性。类似的情况也适用于车道检测。

为了解决这个问题, Spatial CNN (SCNN)提出了一种架构,“将传统的深度逐层卷积推广到特征地图内的逐层卷积”。这是什么意思?在传统的逐层 CNN 中,每个卷积层接收来自其前一层的输入,应用卷积和非线性激活,并将输出发送到后续层。SCNN 更进一步,将单个特征图的行和列视为“层”,顺序应用相同的过程(其中顺序是指一个切片仅在接收到来自前面切片的信息后才将信息传递给后面的切片),允许同一层内神经元之间的像素信息的消息传递,有效地增加了对空间信息的重视。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

SCNN 相对较新,今年(2018 年)早些时候才发布,但已经超过了 ReNet (RNN)、 MRFNet (MRF+CNN)、更深层次的 ResNet 架构,并以 96.53%的准确率在 TuSimple 基准车道检测挑战中排名第一。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此外,在发表《SCNN》的同时,作者还发布了 CULane 数据集,这是一个大规模数据集,带有带立方刺的车道标注。CULane 数据集还包含许多具有挑战性的场景,包括遮挡和变化的光照条件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2。型号

车道检测需要精确的逐像素识别和车道曲线预测。SCNN 的作者没有直接训练车道线并在之后进行聚类,而是将蓝色、绿色、红色和黄色车道线作为四个独立的类别。该模型输出每条曲线的概率图(prob map ),类似于语义分割任务,然后通过一个小型网络传递该概率图,以预测最终的立方刺。该模型基于 DeepLab-LargeFOV 模型变体。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于每个存在值超过 0.5 的车道标志,以 20 个行间隔搜索相应的 probmap,以找到具有最高响应的位置。为了确定是否检测到车道标线,计算地面真实值(正确标签)和预测值之间的交集/并集 (IoU),其中高于设定阈值的 IoU 被评估为真阳性(TP)以计算精度和召回率。

3。测试和培训

你可以跟随这个库来重现 SCNN 论文中的结果,或者用 CULane 数据集测试你自己的模型。

**就这样!**🎉希望本教程向您展示了如何使用传统方法构建一个简单的车道检测器,其中涉及许多手工制作的功能和微调,并向您介绍了一种替代方法,这种方法遵循了解决几乎任何类型的计算机视觉问题的最新趋势:您可以添加一个卷积神经网络!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

*亡国?*🙂

教程:R 中的数据争论和映射

原文:https://towardsdatascience.com/tutorial-data-wrangling-and-mapping-in-r-ec828acc8073?source=collection_archive---------2-----------------------

揭露了推动布鲁克林中产阶级化的房东

我想我以前说过…但是我喜欢地图。几乎每个人都在使用它们,这使得地图成为一种惊人的即时交流大量数据的方式,而不用担心淹没你的观众。

我最喜欢的处理空间数据的工具之一是 r。除了非常适合处理数据之外,其广泛的用户基础意味着有许多软件包可以使定制地图制作变得超级快速和简单。

本教程旨在提供一个使用 R 操作和映射数据的粗略的端到端示例。目标是创建一幅地图,展示纽约布鲁克林区住宅建筑所有权的集中情况。

除了最近发布的制图包之外,我们还将使用来自纽约市 OpenData 门户网站的一些数据集。

要完成本教程,您需要以下工具:

设置环境和下载数据

1)克隆 GitHub 库

[git clone https://github.com/spnichol/mapping_tutorial.git](https://github.com/spnichol/mapping_tutorial.git)
cd mapping_tutorial

2)创建一个新的 R 脚本并设置你的工作目录

setwd("/home/you/mapping_tutorial")

3)安装软件包并加载前两个数据集

install.packages(c("cartography", "rgdal", "sp"))

#ownership registrations 
owners <- read.csv("data/owners.csv")

#building data 
bldgs <- read.csv("data/bldg.csv")

第一个文件是多处住所登记,一个有三个或更多单元的住宅建筑的登记。第二个是注册联系人,包含以前文件中与建筑物所有者相关的信息。

探索数据

我们这个项目的目标是了解布鲁克林建筑所有权的集中情况。因此,一个自然的起点是所有权文件。

让我们看几个记录来了解一下我们的情况。

head(owners)

您的输出应该如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看起来我们有两个 ID 变量: RegistrationContactIDRegistrationID 。第一个是指该行中列出的个人/公司,而第二个是指该个人/实体进行的特定建筑登记。

我们还有 CorporationName 栏,可以提供一些关于谁拥有什么的信息。让我们对 RegistrationContactIDCorporationName 使用aggregate函数。

owner_count <- aggregate(RegistrationID ~ RegistrationContactID, data=owners, FUN=length)
names(owner_count) <- c("RegistrationContactID", "Building_Count")
head(owner_count)
nrow(owner_count[owner_count$Building_Count > 2 ,])

您的输出应该如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在,我们有了一个列,其中包含每个唯一的 RegistrationContactID 以及与之对应的建筑数量。除了一些看起来很奇怪的 id(只是杂乱的数据),有点奇怪的是,我们只有 274 个拥有两栋以上建筑的业主。让我们试试公司名称

owner_count <- aggregate(org_agg <- aggregate(RegistrationID ~ CorporationName, data=owners, FUN=length)
names(org_agg) <- c("CorporationName", "Building_Count")
head(org_agg)
nrow(org_agg[org_agg$Building_Count > 2 ,])

输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

呀。建筑数量要好得多,但这些是一些令人讨厌的错别字。让我们通过删除所有非字母数字字符,然后设置子集以仅保留非空行来修复它们。

org_agg$CorporationName<- gsub("[^[:alnum:][:blank:]]", "", org_agg$CorporationName)
org_agg <- org_agg[org_agg$CorporationName !="" ,]
head(org_agg)
nrow(org_agg[org_agg$Building_Count > 2 ,])

输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

嗯嗯。公司名称看起来好一点,但我仍然不相信拥有两栋以上建筑的业主数量。这个数据集包括整个纽约市。这个城市有很多建筑,有很多房东。会不会是同一个房东或者管理公司用不同的名字/id 登记了不同的楼栋?

如果我们看看他们的邮寄地址呢?让我们假设一个用不同名字注册的房东仍然想只在一个办公室接收他/她的邮件。我们可以通过合并 BusinessHouseNumber 和 BusinessStreetName 列来创建一个新变量,并再次运行我们的聚合。

owners$RealID <- paste(owners$BusinessHouseNumber, owners$BusinessStreetName, sep=" ")
real_agg <- aggregate(RegistrationID ~ RealID, data=owners, FUN=length)
names(real_agg) <- c("RealID", "Building_Count")
nrow(real_agg[real_agg$Building_Count > 2 ,])

是的——这更有道理。我们不能 100%确定其中的一些实际上不是共享同一个邮件地址的不同房东,但是我认为我们可以假设这不是本教程的情况。

然而,有一个问题。如果您还没有注意到,许多注册 id包括多个联系人,每个联系人的类型的值都不同。在我们开始过滤它们之前,让我们先了解一下值的范围。

summary(owners$Type)

这是我们得到的结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们可以对数据帧进行子集化,只保留与所有者相关的角色类型。但这可能会导致一些问题,因为所有者不需要成为这类注册的“联系人”。

相反,让我们删除重复的 RegistrationID 并重新运行我们的aggregate函数。

owners <- owners[! duplicated(owners$RegistrationID) ,]
real_agg <- aggregate(RegistrationID ~ RealID, data=owners, FUN=length)
names(real_agg) <- c("RealID", "Building_Count")
nrow(real_agg[real_agg$Building_Count > 2 ,])

看起来,在删除重复的注册 id 后,我们有大约 5000 名拥有两栋以上建筑物的业主。

在我们进入教程的下一步之前,让我们将 Building_Count 列与主 owners 数据帧结合起来。我们可以用一个简单的merge来做这件事。

owners <- merge(x=owners, y=real_agg, by="RealID")

组合数据帧

既然我们有了如何定义建筑物所有权的策略,我们需要将最近更新的所有者数据框架与建筑物数据集合并。这将为我们提供教程的制图部分所需的 GIS 信息。

1)探索建筑数据框架的变量

head(bldgs)

我的输出如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

很好,看起来两个数据集共享了注册 ID 变量。这意味着该数据帧中的每个条目对应于所有者数据帧中的一个注册 ID。我们可以使用这个列作为merge函数的 ID。

2)注册 ID 合并

bldg_counts<- merge(x=bldgs, y=owners, by="RegistrationID")

合并成功了,但是我们丢失了几行。令人恼火的是,事实证明某些类型的属性被允许使用相同的注册 ID,即使它们有不同的地址。这在数据文档中有更详细的解释。

探索空间变量

现在是有趣的事情。我们需要弄清楚我们可以使用什么样的 GIS 变量来汇总和绘制这些信息。让我们再来看看我们最近合并的数据框架。

bldg_counts<- merge(x=bldgs, y=owners, by="RegistrationID")

输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看起来我们有两个地理变量的选择。第一个是建筑物地址,可以通过组合门牌号街道名称列得到。然而,为了绘制这些信息,我们必须首先对地址进行地理编码。工作太多。

我们还有批次变量。纽约市的街区编号是唯一的,这意味着我们可以汇总每个街区的建筑数量,因为房东拥有不止一栋建筑。该城市还提供带有块级多边形的形状文件,允许我们绘制数据。然而,布鲁克林有成千上万个街区,每个街区只有少数几栋建筑,所以这可能不会太有意义。

事实上,这些变量中没有一个能提供我们真正需要的。相反,我们来介绍一个新的数据集:冥王星。冥王星数据集是纽约市建筑统计的圣杯,包括从纬度和经度到财产价值的一切。

1)读入 PLUTO CSV 文件并探索变量

pluto_bk <- read.csv("data/pluto.csv")
names(pluto_bk)

输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

明白我的意思了吗?让我们只保留相关的列。

2)删除不必要的列

pluto_bk <- pluto_bk[, c(4, 5, 6, 58,71, 73, 74, 75)]

我们只剩下以下几列:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们有很多选择。我选择使用 Census tract,由 CT2010 和 Tract2010 变量以不同的形式表示。这似乎是一个很好的汇总水平,因为布鲁克林大约有 750 个人口普查区。此外,人口普查局提供区域级形状文件,使绘制地图变得轻而易举。

我们需要将这些信息与我们之前创建的建筑列表合并。不幸的是,PLUTO 没有我们之前使用的 RegistrationID 变量。相反,他们使用更常见的 BBL,代表“自治市、街区、地段”

我们的建筑物数据没有 BBL 变量,但是我们可以通过组合区、建筑物和地段列来创建一个变量。然而,首先,我们将使用sprintf函数填充我们的变量。

填充向小于特定位数的值添加额外的零。这使得我们最终的 BBL 长度为十位数,而不管组成它的组件的值。

我们还将借此机会对我们的建筑数据框架进行子集划分,仅包括布鲁克林的房产。我们使用3BoroID 来实现这一点。

3)在建筑物数据框中创建 BBL 变量

#subset dataframe for just Brooklyn 
bldg_counts  <- bldg_counts [bldg_counts $BoroID == 3 ,]#create new columns with padded values 
bldg_counts ["New_Block"] <- lapply(bldg_counts ["Block"], function(x) sprintf("%05d", x))
bldg_counts ["New_Lot"] <- lapply(bldg_counts ["Lot"], function(x) sprintf("%04d", x))#use paste function to combine everything into one variable 
bldg_counts ["BBL"] <- as.numeric(paste(bldg_counts $BoroID, bldg_counts $New_Block, bldg_counts $New_Lot, sep=""))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我觉得不错。让我们继续把这个数据帧和冥王星的数据合并。我们想要的只是每栋建筑的普查区域,因此我们可以相应地进行分组。

4)将区域信息与建筑物数据集合并

names(pluto_bk)
pluto_bk <- pluto_bk[, c(5, 2)]
nrow(bldg_counts)bldg_counts <- merge(x=bldg_counts, y=pluto_bk1, by="BBL")
nrow(bldg_counts)

我们丢失了几百行数据,不管是什么原因,它们都不在 PLUTO 数据集中。

关于 BBL s 的一个重要旁注:这个值实际上不是唯一的标识符——一些地段有不止一个建筑。这没什么大不了的,因为我们需要从冥王星数据帧中提取的只是人口普查区域,这对于位于同一地块上的建筑来说是一样的。

如果我们想要更精确,我们可以通过结合 BBL 和每栋建筑的街道号来创建一个唯一的 ID 变量。

5)按普查地区汇总

#aggregate by census tract 
multiple <- bldg_counts[bldg_counts$Building_Count > 2 ,]
tract_counts <- aggregate(Building_Count ~ CT2010, data=multiple, FUN=length )
names(tract_counts)[1] <- "CTLabel"
nrow(tract_counts)
length(unique(pluto_bk$CT2010))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

首先映入我眼帘的是,我们丢失了一些人口普查地图。解释很简单。虽然该区总共有 761 块土地,但其中一些要么 1)非常小,要么 2)几乎全部是平房,不需要在该市登记。由于这些地块没有“多层建筑”房东,它们不会出现在汇总列表中。

好吧。我们有每个普查区域的数据框架和“多层建筑”业主拥有的房产数量。数量少得惊人,但话说回来,人口普查区实际上并没有那么大。我们来绘制地图吧!

绘图

R 中任何映射项目的第一步都是读入我们的 shapefile。我们将在本教程中使用的 shapefile 来自纽约市规划局。虽然人口普查局通常是 shapefiles 的首选资源,但纽约市规划部的版本已经裁剪了水域,因此更加简洁。

1)加载形状文件

bk_shape <- readOGR(dsn = "shapefiles", layer = "nyct2010")
head(bk_shape@data)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以看到这个 shapefile 实际上有 2166 个不同的人口普查区域,因为它包括了所有的行政区。我们还可以看到,它有数据绑定到多边形,使其成为一个空间多边形数据帧(SPDF)。除了关于面本身的信息之外,该数据还包括人口普查区域标签。我们希望将数据绑定到 SPDF,但首先我们需要解决一些问题。

子集 SPDF
给 R 中的 SPDF 设置子集简单得荒谬。你可以像一个普通的数据帧那样做。

#remember "3" is the BoroCode for Brooklyn 
bk_shape <- bk_shape[bk_shape@data$BoroCode == "3" ,]
head(bk_shape@data)

3)将我们的数据与 SPDF 合并

在 R 中向多边形添加数据也很容易。在这种情况下,我们只需要确保 ID 变量有相同的名称,就可以了。

bk_shape <- merge(bk_shape, tract_counts, by="CTLabel")

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

好了,您可以看到,我们现在已经将数据绑定到了 SPDF,并准备好开始绘制地图。

4)绘制底图
这就是制图包的用武之地。为了开始绘制我们的地图,我们需要首先绘制地图的“范围”(即它将占据的空间区域),然后是陆地。

plot(bk_shape, border = NA, col = NA, bg = "#A6CAE0")
plot(bk_shape, col  = "#E3DEBF", border=NA, add=TRUE)

它应该是这样的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5)添加边界线
现在我们要添加第三层,这将是人口普查区域的边界。

plot(bk_shape, col = "grey60",border = "white", lwd=0.4, add=TRUE)

现在你应该有这个:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

6)选择调色板
制图包中有很多漂亮的预制调色板。我选择了简单的绿色,但你可以在第 4 页的这里看看其他的。我也选择使用 8 种不同的颜色,尽管这总是取决于你所使用的数据的分布。

cols <- carto.pal(pal1 = "green.pal" ,n1 = 8)

7)添加 choropleth 层
这个包有很多不同的显示数据的特性,但是我们将坚持使用一个简单的 choropleth 地图。

choroLayer(spdf = bk_shape, 
           df = bk_shape@data, 
           var = "Building_Count", 
           breaks = c(0, 10, 30, 50, 70, 90, 110, 150), 
           col = cols, 
           border = "grey40", 
           lwd = 0.5, 
           legend.pos = "left",
           legend.title.txt = "Number of Buildings", 
           legend.values.rnd = 10,
           add = TRUE)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

嘣。事实证明这很好,因为这非常符合我多年来与布鲁克林房东打交道的经验。深绿色区域也与经历了最大中产阶级化的区域非常接近。

我为布鲁克林公共图书馆制作的许多地图看起来非常相似,尤其是在观察中产阶级化前后收入和租金的变化时。

添加布局层
我们可以通过创建一个布局层来给地图添加一点元数据。

layoutLayer(title = "Census Tracts by Building Ownership Concentration", 
            author = "Pres Nichols",  
            sources = "Source: NYC OpenData", 
            scale = NULL, 
            col = NA, 
            coltitle = "black", 
            frame = FALSE,  
            bg = NA)

结论

有一个重要的方面我没有考虑到:如果地图上的北部地区,拥有更集中的所有权,只是总共有更多的建筑呢?

如果你正在学习这篇教程,我会让你自己去发现并报告你的发现!

注意:那些不熟悉布鲁克林地理的人可能会对地图上的白色区域有点担心。看起来比实际情况更糟。这是因为最大的白色区域(展望公园、格林伍德公墓和洛克威)实际上没有人居住。如果他们仍然困扰你,你可以随时给无人居住的地区一个不同的颜色。

如何匹配《突围》中 DeepMind 的深度 Q-Learning 评分

原文:https://towardsdatascience.com/tutorial-double-deep-q-learning-with-dueling-network-architectures-4c1b3fb7f756?source=collection_archive---------0-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你和我一样对深度 Q 学习着迷,但从来没有时间去理解或实现它,这是给你的:在一个 Jupyter 笔记本中,我将 1)简要解释强化学习与监督学习的不同,2)讨论深度 Q 网络(DQN)背后的理论,告诉你在哪里可以找到论文中相应的解释及其含义,以及 3)如何在 python 和 tensorflow 中实现使其工作所需的组件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2013 年,一家名为 DeepMind 的伦敦初创公司发表了一篇名为的开创性论文,在 arXiv 上用深度强化学习玩雅达利:作者提出了一种名为 Deep Q-Learning 的强化学习变体,它能够成功学习不同雅达利 2600 游戏的控制策略,只接收屏幕像素作为输入,并在游戏分数变化时获得奖励。在某些游戏中,代理甚至超越了人类专家玩家!这是一个惊人的结果,因为以前的“人工智能”通常局限于一个单一的游戏,例如国际象棋,而在这种情况下,在街机学习环境中的游戏的类型和内容变化很大,但不需要调整体系结构、学习算法或超参数。

难怪 DeepMind 被谷歌以 5 亿美元收购。该公司自此成为推进深度学习研究的领先机构之一,后来讨论 DQN 的文章发表在 Nature 上。

现在,五年后,甚至有了更先进的强化学习算法,但在我看来,深度 Q 学习仍然是一种非常令人印象深刻的方法,非常值得研究(更重要的是开始工作)。

我第一次观看 DeepMind 的视频时,我正在攻读理论天体物理学博士学位的第一年,视频显示一名 DQN 代理人正在学习玩游戏 Breakout,并发现它可以在墙后反弹,从而允许球击中砖块。我很快就被迷住了,并向自己承诺,一旦我有时间,我会努力重现这个结果。

现在,两年后,我实现了 DQN,学到了很多关于神经网络和强化学习的知识,因此决定写一个有希望的全面教程,介绍如何让它为像我一样着迷于深度学习的其他人工作。

深度 Q 学习需要几个组件来工作,如代理可以探索和学习的环境,Atari 游戏帧的预处理,两个卷积神经网络,探索-开发困境(e-greedy)的答案,更新神经网络参数的规则,错误剪辑和称为重放存储器的缓冲区,过去的游戏转换存储在该缓冲区中,并在学习时从中提取。

我详细描述了各个组件,紧接着是它们的实现。如果您想了解更多信息,请继续阅读笔记本:

[## fg91/深度 Q 学习

Deep-Q-Learning - Tensorflow 用决斗网络实现 Deepmind 的双重深度 Q-Learning

github.com](https://github.com/fg91/Deep-Q-Learning/blob/master/DQN.ipynb)

在这里,我现在将描述我使用笔记本进行的实验,更重要的是我在进行这些实验时发现的小细节,这些小细节被证明对 DQN 的良好工作至关重要:几个线程讨论了与 DeepMind 报告的分数匹配的问题(见这里、这里这里这里),我最初也在与类似的问题进行斗争。

让我们开始吧:乓

我用环境 Pong 开始了我的实验,因为对于一个 DQN 代理来说,学习起来相对容易和快速,因为它很简单:代理控制一个可以上下移动的球拍,目标是以一种对手无法触及的方式击球。一旦一名玩家得分达到 21 分,游戏就结束了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

After 30 minutes of training

笔记本中的实现在每个时期后创建一个 gif,这允许您观察代理学习。我个人从不厌倦看网络的进步,想到人类仅仅通过看着它们就知道如何让机器学会玩这些游戏,我感到惊讶。

在训练开始时,DQN 代理只执行随机动作,因此得到大约-20 的奖励(这意味着它无望地输了)。经过 30 到 45 分钟的训练,代理人已经学会了击球,并能够获得第一个分数。

实线示出了训练奖励(在过去 100 集内平均的训练集分数),虚线示出了评估分数(在 10,000 帧贪婪游戏之后的平均集分数)。一个时期相当于 50,000 次参数更新或 200,000 帧。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Training and evaluation reward for the environment Pong

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

DQN winning like a boss

评价分数很快达到最大值+21。由于在训练期间使用退火ε的 e-greedy 策略,训练分数保持较低。在左边的 gif 中,所有的分数都以几乎完全相同的方式计分,这意味着代理发现了一个几乎理想的策略。我很想看到两个 DQN 特工学会对战,但目前,OpenAi 的健身房不支持多人 Pong。

下一个:突破

让我们来看看 Breakout ,视频中显示的环境最初让我在看到代理人在屏幕旁边挖了一个隧道,让球通过在墙后反弹击中砖块后,想自己实现 DQN。

在《自然》杂志论文 Mnih 等人 2015 中,DeepMind 报告了《突围》的评估分数为 317。我连夜在笔记本上运行,希望得到类似的结果。在 Pong 取得初步成功后,第二天早上我兴奋地醒来检查代理的改进,却发现奖励在 35 左右达到了一个平台期,没有任何进一步的改进。这里报道了关于 DQN 和突围的同样问题(没有给出问题的最终答案): DQN 解决方案的结果在大约 35 奖励时达到峰值

在线课程的问题(这是我非常喜欢的,不要误会我的意思)是,一切都倾向于立即工作,只有当事情没有按计划进行,你需要找出原因时,事情才会变得真正令人兴奋(当然有时也会令人沮丧)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Breakout, first try

通过降低学习率,我得到的奖励达到了 50 左右,但仍然只有 DeepMind 报告的 15%左右。

在接下来的几个星期里,我继续有时对代码进行改进,通宵或更长时间地进行实验,并逐渐达到接近 300 的训练分数和大约 400 的最高评估分数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Breakout, first vs last try

王等 2016 报道突围得分 418.5(双人)和 345.3(决斗)分(表 2)。我在我的实验过程中看到的最好的评估集的分数是 421(如本文开头所示)。如果您想亲自尝试,可以克隆存储库并运行笔记本。网络的各个参数都包括在内,因为我使用确定性环境(BreakoutDeterministic-v4)训练了 Breakout,所以您应该会得到相同的分数。

实现这一改进需要哪些调整?

  1. 使用正确的初始化器!DQN 使用 Relu 激活函数,右初始值为 何等 2015 方程 10 ( 点击此处详解)。在 tensorflow 中使用tf.variance_scaling_initializerscale = 2
  2. 确保您正在以正确的频率更新目标网络:论文称,目标网络更新频率以参数更新的数量来衡量(每四帧发生一次,参见 Mnih et al. 2015 中的扩展数据表 1),而在 DeepMind 代码中,它以代理看到的动作选择/帧的数量来衡量。我们来看看 DeepMind 的代码:这里你可以看到默认情况下update_freq=4target_q=10000(第 14 行和第 31 行)。此处可以看到,默认情况下,参数更新每 4 步发生一次(self.numSteps%self.update_freq==0),而此处目标网络每 10.000 步更新一次(self.numSteps%self.target_q==1)——因此,目标网络更新频率是在numSteps中测量的,而不是在参数更新中测量的。
  3. 确保您的代理实际上正在尝试学习与 DeepMind 论文中相同的任务!
    我发现,当一个生命丢失时,将终端状态传递给重放记忆(如 DeepMind 所做的)会产生巨大的差异。这是有道理的,因为失去一条生命没有负面的回报,否则代理人不会“注意到失去一条生命是不好的”。
    DeepMind 在 Breakout 中使用了四个动作的最小集合( xitari ),OpenAi gym 的 Breakout 的几个版本有六个动作。额外的动作可以彻底改变代理试图学习的任务的难度! Breakout-v4Breakout deterministic-v4环境有四个动作(与env.unwrapped.get_action_meanings()核对)。
  4. 使用 Huber 损失函数( Mnih et al. 2013 称之为误差削波)来避免爆炸梯度。如果超过某个阈值,渐变会被修剪到该阈值。注意,与二次损失函数相比,下图中绿色曲线的导数对于 x > 1(或 x<1)没有增加(或减少)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Error clipping to avoid exploding gradients

随意玩笔记本。如果你投资 GPU 时间来优化超参数以获得更好的性能,或者如果你尝试在其他游戏中使用它,请在评论中给我写信,我会很高兴知道。

如果你想自己训练网络,在笔记本的第一个单元格中设置TRAINTrue

考虑让你的电脑可以远程访问,我在这篇博文中描述了这一点:远程访问你的深度学习站,并设置局域网唤醒。您可以使用jupyter-nbconvert --to script DQN.ipynb将笔记本转换为 python 脚本,然后在我在这里描述的 tmux 会话中运行它:tmux 中的 jupyter 和 tensor board。这样做的好处是,您可以从 tmux 会话中分离并远程重新连接到它,以便检查代理的进度或对代码进行更改,无论您在哪里。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Summaries in tensorboard

如果你想使用 tensorboard 来监控网络的改进,在激活相应虚拟环境的终端中输入tensorboard --logdir=summaries。打开浏览器,进入 http://localhost:6006 。这也可以远程操作。

我发现 DQN 开始工作很费劲。有许多小细节要做好,否则效果不好。除此之外,实验经常不得不通宵运行(至少),这意味着如果只有一个 GPU,调试和改进会很慢。

尽管如此,在我看来这是值得的,因为我学到了很多关于神经网络和强化学习的知识,特别是通过调试和改进。看看下面的 gif:在某一点上,代理开始直接瞄准两侧挖隧道,并从上面撞上石块——这正是两年前 DeepMind 的视频中引起我注意的东西,也是我想要复制的东西。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Observe how the agent starts to dig a tunnel at the side 😃

因此,我鼓励你尝试自己从头实现 DQN,必要时看看我的代码进行比较,找出我是如何实现不同组件的。当你需要澄清或提示时,请随时给我留言,我很乐意帮忙。

玩得开心:)

法比奥(男名)

教程:泰国的 ggplot2 热图和交通死亡

原文:https://towardsdatascience.com/tutorial-ggplot2-heatmaps-and-traffic-deaths-in-thailand-d5134908d77e?source=collection_archive---------10-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Dan Freeman on Unsplash

在本教程中,我们将根据每 100,000 名居民的交通死亡人数,绘制一张驾车最危险国家的热图。我们将使用 R 和 ggplot2 来可视化我们的结果。

在泰国开车真的有那么危险吗?

人们常说在泰国开车很危险。任何坐在狭窄的ตุ๊กตุ๊ก后座上的人都会明白我在说什么。交通执法的缺失以及出租车和小型货车司机的疯狂驾驶肯定无助于改善泰国作为一个道路危险国家的形象。但是我们来看看数据是否支持这种印象。

为了进行调查,我们将使用来自世卫组织和欧睿信息咨询公司的数据。如上所述,他们跟踪了 1985 年至 2008 年每 100,000 名居民的道路死亡人数,但对于许多国家来说,某些年份的数据缺失。为了保住泰国,我不得不牺牲,增加了很多缺失的价值观。

顺便说一下,我强烈推荐 Gapminder 组织的创始人写的《T2 真相》一书。不管是谁,让我们言归正传。

清理并读入数据

你可以在下面看到很多数据丢失了。

library(tidyverse)
library(RColorBrewer)
df **<-** readxl**::**read_xlsx('cars.xlsx')
colnames(df)[1] **<-** 'country'
head(glimpse(df))## Observations: 148
## Variables: 25
## $ country  <chr> "Albania", "Argentina", "Armenia", "Australia", "Aust...
## $ `1985.0` <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N...

## # A tibble: 6 x 25
##   country   `1985.0` `1986.0` `1987.0` `1988.0` `1989.0` `1990.0` `1991.0`
##   <chr>        <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
## 1 Albania         NA       NA       NA       NA       NA       NA       NA
## 2 Argentina       NA       NA       NA       NA       NA       NA       NA
## 3 Armenia         NA       NA       NA       NA       NA       NA       NA
## 4 Australia       NA       NA       NA       NA       NA       NA       NA
## 5 Austria         NA       NA       NA       NA       NA       NA       NA
## 6 Azerbaij~       NA       NA       NA       NA       NA       NA       NA

哪些数据缺失?

为了找出哪个国家缺少的数据最多,我们可以使用下面的命令来计算每行的 NAs。稍后当我们使用这个专栏过滤热图的结果时,这将会派上用场。如果我们愿意,我们也可以使用百分比缺失阈值。我们暂时保持简单。

df **<-** df**%>%**
  mutate(na_count **=** rowSums(**is.na**(.)))
head(cbind(df**$**country, df**$**na_count))##      [,1]         [,2]
## [1,] "Albania"    "23"
## [2,] "Argentina"  "13"
## [3,] "Armenia"    "23"
## [4,] "Australia"  "14"
## [5,] "Austria"    "14"
## [6,] "Azerbaijan" "23"

为我们的热图创建自定义调色板

让我们使用 colorRampPalette 函数为热图渐变创建 25 个级别的“橙色/红色”。为什么是二十五?我们可以从 glimpse()函数中看到,死亡人数的最高值在十万分之二十五左右。请注意,通常我们只能使用 9 种颜色的“OrRd”调色板,但是 colorRampPalette()允许我们将其扩展到任何数量。如果你做大量的可视化工作,这是一个非常有用的功能。

my_pal **<-** colorRampPalette(brewer.pal(11, "OrRd"))(25)## Warning in brewer.pal(11, "OrRd"): n too large, allowed maximum for palette OrRd is 9
## Returning the palette you asked for with that many colorsmy_pal##  [1] "#FFF7EC" "#FEF2E0" "#FEEDD4" "#FEE8C8" "#FDE1BA" "#FDDAAC" "#FDD49E"
##  [8] "#FDCB95" "#FDC38C" "#FDBB84" "#FCAB75" "#FC9C67" "#FC8D59" "#F77F53"
## [15] "#F3724D" "#EF6548" "#E7533A" "#DF412C" "#D7301F" "#CB2014" "#BF100A"
## [22] "#B30000" "#A10000" "#900000" "#7F0000"

现在我们准备绘制我们的热图

一个关键特征是,我们基本上是对包含少于 18 个 NA 值的国家进行子集划分。还要注意,我们将 scale_fill_gradientn 的颜色参数设置为我们之前创建的自定义颜色渐变。此外,我们设置 na.value='white ',以便绘图与白色背景融为一体。

如果您以前没有制作过热图,请记住,如果您使用 gather()函数将数据帧转换为长格式,效果会更好。

df**%>%**
  filter(na_count **<** 18)**%>%**
  select(1, 13**:**25)**%>%**
  gather(**-**country, key**=**'year', value**=**'deaths')**%>%**
  mutate(year **=** as.factor(**as.integer**(year)))**%>%**
  ggplot(aes(reorder(country,deaths), year, fill**=**deaths))**+**
  geom_tile()**+**
  coord_flip()**+**
  scale_fill_gradientn(colors **=** my_pal, na.value **=** 'white')**+**
  theme(plot.subtitle **=** element_text(hjust **=** 0.5), 
    plot.caption **=** element_text(vjust **=** 1), 
    axis.ticks **=** element_line(linetype **=** "blank"), 
    panel.grid.major **=** element_line(colour **=** **NA**, 
        linetype **=** "blank"), panel.grid.minor **=** element_line(linetype **=** "blank"), 
    axis.text **=** element_text(vjust **=** 0.25), 
    axis.text.x **=** element_text(size **=** 10, 
        vjust **=** 0, angle **=** 90),
    axis.text.y **=** element_text(size **=** 6),
    panel.background **=** element_rect(fill **=** **NA**),
    plot.title **=** element_text(hjust **=** 0.5))**+**
    labs(x**=**'', y**=**'', title**=**'Most Dangerous Roads', subtitle**=**'Car Deaths per 100,000',
         fill**=**'Deaths')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结果:坏的

所以看起来泰国确实是相对危险的驾车之地。1996 年,在这里列出的 58 个国家中,他们的死亡率最高。看起来驾驶在 2000 年代变得更安全了,但有很多数据缺失,所以很难确定。

有趣的是,多米尼加共和国、拉脱维亚、爱沙尼亚、立陶宛、卢森堡和冰岛(在某些年份)在司机安全方面表现不佳。美国和新西兰也做得不太好。我猜冰岛的高死亡率是由于某些年份的恶劣天气。就卢森堡而言,通过谷歌搜索,我发现它确实是欧洲人均交通死亡率最高的国家之一。那里有许多狭窄多风的道路吗?糟糕的司机?天气不好?

结果:好

从积极的一面来看,马耳他、新加坡、摩尔多瓦、智利、哥伦比亚、英国、瑞典和厄瓜多尔对司机来说似乎特别安全。

原载于 2018 年 7 月 29 日https://greenet 09 . github . io

教程:我们如何用 Stan 实现贝叶斯收入估计

原文:https://towardsdatascience.com/tutorial-how-we-productized-bayesian-revenue-estimation-with-stan-a10306437875?source=collection_archive---------6-----------------------

在线广告商正转向优化广告支出的总收入,而不仅仅是提高转化率或点击量。最大化收入是棘手的,因为单个用户带来的收入数量存在巨大的随机变化。如果没有考虑到这一点,很容易对错误的信号做出反应,并在不太成功的广告活动上浪费金钱。幸运的是, 贝叶斯推理 通过对观察到的数据中的变化进行建模,让我们能够在粒度级别上做出合理的决策。

概率编程语言,像 Stan ,让贝叶斯推理变得简单。Stan 提供了一种灵活的方式来定义模型和进行推理,并且它有很棒的诊断工具,如 ShinyStan 。概率编程语言对于贝叶斯建模与 TensorFlowKeras 对于深度学习是一样的。由于框架的发展,近年来深度学习已经被广泛采用。贝叶斯建模现在也是如此。

目前,Stan 主要用于对静态数据收集进行描述性分析。在生产中运行它是可能的,但具有挑战性。在这篇博文中,我们描述了让 Stan 投入生产的经验。我们还为我们的特定用例进行了基本建模:对每次购买的收入进行建模,以比较多个广告之间的性能。我们将详细讨论如何通过在 Stan in production 中使用贝叶斯多层建模来解决这个用例。

1.用例:最大化广告支出的收入

2.如何对收入建模?

  • 模拟每次购买的收入
  • 共享信息的多级建模
  • 分析收入模式

3.Stan 的贝叶斯建模经验

4.讨论

1.用例:最大化广告支出的收入

在线广告传统上侧重于获得印象和点击。近年来,大多数广告商已经转向直接优化他们的网页或移动应用程序的转换。广告中的转换可以意味着任何事情,从在线购买到完成游戏中的一个关卡。在这种情况下,广告商希望最大化他们获得的转化量,或者换句话说,在给定的预算下,最小化每次行动的成本(CPA)。

今天,我们看到广告商的目标是最大化来自转化的总收入,而不仅仅是增加转化数(这就是我们在这篇博文中讨论的)。在未来,广告商将能够最大化单次转换的预期终身价值:客户可能会在未来再次购买更多,或者吸引他们的朋友成为新客户。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们越深入漏斗,证明我们决策的数据就越少。例如,如果每天有 100,000 人看到您的广告,其中 1%的人会点击该广告,这将导致 1,000 次网站访问。在这些网站访问中,只有 1%导致购买。购买的这 10 个人的收入和终身价值可能会有很大差异。虽然只有很少的随机变化的数据,但你仍然需要决定明天把你的广告预算放在哪里。贝叶斯推理通过量化不确定性解决了这个问题。

在收入方面,最常见的指标是广告支出回报率(ROAS ),这意味着每笔广告支出的总收入。有趣的是,ROAS 可以分为两部分:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,要估计单个广告的 roa,您可以分别估计 CPA 和每转换级别的收入。类似地,CPA 可以进一步分为模拟每次花费的印象数、每次印象的点击数和每次点击的转化率。在比较广告之间的表现时,这些部分通常在行为上有很大不同(查看下面的转换漏斗)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 Smartly.io,我们已经为每个行动的成本部分建立了一个模型,该模型利用了这个漏斗并能够对变化做出快速反应。它被用作我们的预算分配的一部分,该预算分配基于贝叶斯多臂强盗,并根据其表现在多个广告集之间分配预算。为了改变我们的预测预算分配,以优化 roa 而不是 CPA,我们只需要插入多个广告(或脸书环境中的实际广告集,因为预算和目标受众是在该级别上定义的)的每次转换收入的平均分布的稳定估计值。

2.如何对收入建模?

模拟每次购买的收入

虽然每次转换的收入在单次购买之间会有很大的变化,但大多数变化通常是正常的随机变化,而不是由于广告集之间的差异。例如,如果你购买了 10 次,其中 9 次带来了 10 美元的收入,最后一次带来了 1000 美元,你每次转换的平均收入将接近 100 美元。如果没有那一单大额购买,平均价格将是 10 美元。如果您必须预测未来每次转换的平均收入,您会说它更接近 10 美元而不是 100 美元吗?如果你的第二个广告系列也有 10 次购买,但都带来了接近 20 美元的收入,你会把钱押在哪个广告系列上?

在大多数情况下,我们已经看到,尽管原始数据会显示出很大的差异,但广告组合带来的每次转化的平均收入并没有什么不同。要让广告系列在每次转化产生的收入方面真正有所不同,针对受众或报价的广告应该真正影响广告商的收入产生过程。例如,针对不同国家/地区的广告组合可以带来不同的每次转化收入。

好的,那么我们如何得到稳定的估计来比较广告组之间的性能呢?在这里,贝叶斯多级建模开始发挥作用。在多级建模中,你可以说广告集彼此相似,除非数据证明不是这样。让我们首先估算单个广告集的每次转化收入。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

收入通常遵循一个厚尾分布。这意味着大部分收入金额很小,但也可能有一些收入金额非常大的转换。上图是一个真实的例子,展示了电子商务广告账户中所有购买的收入分配。我们通过使用对数正态分布来模拟每次转换的收入。下面,是同样的对数变换分布。它非常接近正态分布,支持对数正态方法的可行性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,我们假设广告组 a 的单次转换 R_a 的收入遵循对数正态分布,位置和比例参数𝜃a和𝜎_ a 可以在广告组之间变化。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们没有从脸书获得每一次转换的数据,这让事情变得有点复杂。取而代之的是,我们每天或每小时获得广告集的总收入和转化率。我们可以用另一个对数正态分布来近似这些观察水平收入 R _ i ,其均值和方差与 n_i 个独立同分布对数正态随机变量之和的均值和方差相匹配(芬顿-威尔金森近似)。设 a_i 为观察值 i 的 ad 集合。然后

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有趣的是,对数正态分布随机变量 R_a 的均值并不直接与分布的众数和中位数 exp(𝜃_ a 相同,而是

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这就是为什么在估算收入平均值时,应包括罕见但大量的收入金额。

为了简化模型,我们假设每次转换的收入 R_a 不随时间变化。CPA 模型考虑了时间序列的变化。因此,我们将前两周的所有每小时收入数据集中到一个广告集中。我们使用每小时的数据来尽可能接近交易数据。

现在给定观察到的收入 r_i 和计数 n_i 我们可以通过在 Stan 中编写模型来直接估计对数正态参数𝜃_ a 和𝜎_ a 。我们对获得这些的点估计(最大后验概率,MAP)不感兴趣,而是从后验分布中获得样本,以捕捉估计中的不确定性。

对于一个完整的模型,我们需要一些合理的位置和比例参数的先验知识。如果排除了前科,Stan 会自动使用无信息前科。下面是一个简单的 Stan 代码,它实现了对收入建模的非层次估计。

data {
  int adsets;
  int observations;
  int observation_adset[observations];
  vector[observations] observation_conversion_count; // n_i
  vector[observations] observation_conversion_revenue; // r_i
}
parameters {
  vector[adsets] adset_mu; // theta_a
  vector[adsets] adset_sigma; // sigma_a
}
model {
  vector[observations] observation_mu; // theta_i
  vector[observations] observation_sigma; // sigma_i

  observation_sigma = sqrt(log(1 + (
      exp(square(adset_sigma[observation_adset])) - 1
    ) ./ observation_conversion_count));
  observation_mu = adset_mu[observation_adset] + 
    log(observation_conversion_count) + 0.5 * (
      square(adset_sigma[observation_adset]) - 
      square(observation_sigma)
    );

  observation_conversion_revenue ~ 
    lognormal(observation_mu, observation_sigma);
}
generated quantities {
  vector[adsets] adset_mean;
  adset_mean = exp(adset_mu + 0.5 * square(adset_sigma)); 
}

Stan 的好处在于,我们的模型定义几乎是一行一行地变成了最终代码。然而,让这个模型符合 Stan 是很困难的,因为我们还没有为变量指定任何限制,或者给出合理的先验。这个模型不适合。我们稍后将回到这一点。

共享信息的多级建模

第一种方法的问题是广告集估计将仅仅基于来自单个广告集的数据。在这种情况下,如果只有几十个转换事件(这是一种常见情况),一个随机的 1000 美元的大额购买可以从根本上影响单个广告集的平均估计。由于如此大的收入事件也可能发生在其他广告组中,我们可以通过在广告组之间共享信息来获得更好的估计。

通过多级建模,我们可以实现部分池化方法来共享信息。上面的第一个模型对应于无池方法。完全池化意味着将所有广告集的数据组合在一起,并为所有广告集生成一个共享的评估。如果数据很少,多水平模型产生的结果与完全汇集的结果相似。如果有大量数据,它会产生接近无池的结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Examples of different levels of pooling with two ad sets.

由于对数正态分布的收入事件非常不稳定,需要大量数据来进行稳定的估计,这使得部分池化很有吸引力。使用部分池,如果广告集没有足够的数据来估计其自身的参数,则估计被吸引向共享的平均值。

在我们的模型中,我们使用简单的脸书广告层级:广告账户>活动>广告系列。也就是说,一个活动中的广告集应该比客户中其他活动中的广告集更相似。为了指定这个层次,让 c_a 成为广告组 a 所属的活动。我们假设广告设置级别参数𝜃_ a 和𝜎_ a 先前具有共享的活动级别。让我们首先关注我们分三步建模的位置参数𝜃 _a :

  1. 𝜃_ a 的活动级别正常,参数为𝜇_ c 和 t_c
  2. 活动级别位置参数𝜇_ c 的帐户级别优先
  3. 帐户级别比例𝜆的对数比例不正确的统一先验

那么位置部分的多级模型看起来像

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,如果活动级别尺度 t_ c 小,则广告集级别均值𝜃 _a 预计接近活动级别均值𝜇_ c 。这给出了部分池。

接下来,我们应该为标度参数𝜎 _a 分配先验。这里,我们进一步简化模型,假设所有对数正态比例参数在帐户级别的广告集之间共享。这种简化对应于设置强先验。注意,由于最终模型是对数正态的,这些比例参数变成了相对差异,而不是绝对差异。因为我们主要对分布均值的差异感兴趣,所以这个假设是一个很好的起点,并解决了可能的随机大收入观察的主要问题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们对对数正态收入分布的主要尺度参数𝜎建模,以遵循参数为𝛼和𝛽.的逆伽马分布我们通过使用基于真实数据的参数值𝛼 = 6 和𝛽 = 4 来设置信息先验,使得𝜎的平均值大约为先验的 2/3,但是如果有足够的数据存在,允许它容易地变化。

对于一个完整的模型,我们只缺少多级模型中尺度参数 t_ c 和𝜙的超先验。为了再次简化,我们假设活动共享尺度参数 t_ c 。我们给他们两个一个单独的弱指数先验,峰值在 0,平均 1/𝛾在 0.05 左右。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

所以最后,定义一个多级模型有很多步骤,尽管我们在开始的时候做了很多简化。为了改进模型,我们也可以通过使用例如加性柯西先验来对分级尺度参数建模,如在陶曼,第 6 章中所解释的。对时序效应建模将是有益的,例如,通过使用贝叶斯结构时序模型。此外,t 分布被广泛用于允许更多的变化,而不是使用正常的多级先验。

然而,最好从一个简单的模型开始,因为我们的目标是得到一些我们可以以可伸缩的方式针对不同类型的数据自动运行的东西。只有在用真实数据验证性能的基础上,才能进行改进。具有新层次结构的更新后的 Stan 模型如下所示。此外,基于对数百个帐户的分析,对参数添加了严格的限制。此外,我们使用了标准的重新参数化来加速模型,更多细节参见标准手册,26.6,分层模型和非中心参数化

data {
  int<lower=0> adsets;
  int<lower=0> campaigns;
  int<lower=1> adset2campaign[adsets];
  int<lower=0> observations;
  int<lower=1> observation_adset[observations];
  vector<lower=1>[observations] observation_conversion_count; // n_i
  vector<lower=0>[observations] observation_conversion_revenue;//r_i
}
transformed data {
  vector[observations] log_observation_conversion_count = 
    log(observation_conversion_count);
  vector[observations] log_observation_conversion_revenue = 
    log(observation_conversion_revenue);
}
parameters {
  real<lower=-5, upper=20> account_mu; // lambda
  real<lower=0, upper=5> account_mu_sd; // phi
  vector[campaigns] campaign_mu_z;
  real<lower=0, upper=5> campaign_mu_sd; // tau
  vector[adsets] adset_mu_z;
  real<lower=0.001, upper=2.5> revenue_sigma; // sigma
}
transformed parameters {
  vector[campaigns] campaign_mu; // mu_c
  vector[adsets] adset_mu; // theta_a

  campaign_mu = account_mu + account_mu_sd * campaign_mu_z;
  adset_mu = campaign_mu[adset2campaign] + 
    campaign_mu_sd * adset_mu_z;
}
model {
  vector[observations] observation_mu; // theta_i
  vector[observations] observation_sigma; // sigma_i

  campaign_mu_z ~ normal(0, 1);
  adset_mu_z ~ normal(0, 1);

  account_mu_sd ~ exponential(1 / 0.05);
  campaign_mu_sd ~ exponential(1 / 0.05);

  revenue_sigma ~ inv_gamma(6, 4);

  observation_sigma = sqrt(log(1 + (
      exp(square(revenue_sigma)) - 1
    ) ./ observation_conversion_count));
  observation_mu = adset_mu[observation_adset] + 
    log_observation_conversion_count + 
    0.5 * (square(revenue_sigma) - square(observation_sigma));

  log_observation_conversion_revenue ~ 
    normal(observation_mu, observation_sigma);
}
generated quantities {
  vector[campaigns] campaign_mean;
  vector[adsets] adset_mean;
  campaign_mean = exp(campaign_mu + 0.5 * square(revenue_sigma));
  adset_mean = exp(adset_mu + 0.5 * square(revenue_sigma)); 
}

分析收入模式

最后,我们有一个模型,我们可以用 Stan 拟合并分析结果。我们得到每个广告集的收入分布估计。从这个输出中,我们对平均分布特别感兴趣。

通过基于拟合的模型生成新数据并将其与原始数据进行比较,检查我们的模型对数据的描述程度总是好的。这被称为后验预测检查。以下是原始广告集收入观察值(绿色)的后验预测检查结果,数据来自对数标度的模型(蓝色)。该模型似乎与数据吻合得很好。原始数据包含一个更大的峰值。举例来说,可能有一个单一的产品价格来解释这一点,但这没什么可担心的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们现在可以比较单个广告集的平均收入分布,以及如下所示的活动级别分布。同一活动中的广告系列共享同一颜色。在这种情况下,我们看到分布重叠了很多,单个活动中的广告集没有什么不同。有很多广告集,但每个广告集的数据很少。这些活动彼此略有不同。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个有趣的方面是将直接从观测值计算的原始平均值与从模型计算的平均值进行比较。下图以 95%的预测间隔对所有广告集进行了分析。原始平均值在 4.6 和 5.2 之间变化,这意味着在最小和最大的广告集之间,每次转换的观察收入要大 4 倍。在拟合模型中,我们最多只能得到大约 25%的较大估计。这是由于部分汇集效应,在图中几乎所有的点都在一条水平线上。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们对生产中的所有客户运行了类似的图,以检查模型是否合理。尽管有许多图需要手动检查,但这仍然是识别模型中问题的最简单、最快速的方法。后验预测数据应该与原始数据相匹配。如果数据很少或者确实没有任何差异,部分池应该会使结果变平。

在大多数情况下,我们观察到广告集大量集中在一起。然而,在有些情况下,广告集确实互不相同,并且不会发生池化。此外,与上面的图不同,有时活动层级不会带来额外的价值。

3.Stan 的贝叶斯建模经验

具有不同分布和参数的所有贝叶斯多级建模细节可能看起来很复杂——事实也确实如此。斯坦并没有让事情变得简单。阅读像约翰·k·克鲁施克的做贝叶斯数据分析或者盖尔曼等人贝叶斯数据分析这样的东西来了解更多关于贝叶斯数据分析的知识是很好的。

然而,当您熟悉了编写模型之后,Stan 是一种表达性语言,它不再需要编写定制优化或采样代码来适应您的模型。它允许您轻松地修改模型和增加复杂性。对于 CPA 建模方面,我们仍然使用 Python 中的定制模型,依赖于共轭分布和近似。它运行良好,但改变它有点麻烦。将来,我们也可以用 Stan 来做这个部分。

Stan 中的模型拟合基于采样和马尔可夫链。粗略地说,该过程从参数的随机初始值开始,并且在每一步中它们都被稍微修改。如果新的参数值更符合数据,则接受它们。如果更糟,他们被接受的概率由大都会-黑斯廷斯马尔可夫链蒙特卡罗 (MCMC)方法定义。预热一段时间后,我们从后验分布中获取样本。

简单的 MCMC 可能非常慢。斯坦使用先进的技术,如不掉头采样 (NUTS)和哈密顿蒙特卡罗 (HMC)来加速采样。对于较大的数据集,这通常仍然太慢。有各种其他的近似方法可以缓解这个问题。例如,您可以只计算最大后验概率 (MAP)点估计,这非常快,但通常不适用于多级模型,并且无法捕捉不确定性。

变分贝叶斯推断是另一种近似方法,其中后验分布由变分分布近似,通常为正态分布。如果模型相当简单,就像我们的例子一样,这就很好。Stan 实现了一个自动微分变分推理 (ADVI),于 2016 年底发布。

当前的 ADVI 实施仍处于早期阶段,在生产中使用它之前,最好确保它能产生与全采样类似的结果。ADVI 在 2017 年 4 月可用于 PyStan Python 接口,现在我们正在生产中使用它。我们已经评估了 Stan 和其他概率编程语言几次,但是它们从来没有扩展到我们的用例。ADVI 使我们能够在生产中使用 Stan。

然而,使用斯坦仍然是痛苦的。如果学习发散,模型拟合很容易崩溃。在大多数情况下,这可以通过为变量添加合理的限制和信息先验,并可能为参数添加自定义初始化来解决。分层模型也需要非中心参数化。

这些是在生产中运行模型的必备条件。您希望模型适合 100%的情况,而不仅仅是 90%的情况,这在交互模式下是很好的。然而,发现模型的问题是困难的。最好是从非常简单的模型开始,一步一步地添加东西。此外,针对各种数据集运行模型并自动生成后验图有助于尽早发现问题。要进一步优化标准代码,请参考第 26 节,效率优化标准代码

标准代码需要编译,这可能会很慢。可以通过缓存模型来避免。但是当你在开发和调试模型的时候,这真的很令人沮丧。尽管如此,它仍然是通过 PyStan 接口包装的编译后的 C++代码。界面需要更多的爱。离最常用的接口 RStan 还差得远。但是我们使用 Python ,因为它更适合产品化分析。

对于调度,我们使用芹菜,这是一个很好的分布式任务队列。我们还验证了阿兹卡班气流和其他常见的分析调度系统,但发现标准 Python 调度程序更容易使用。

4.讨论

贝叶斯建模正在成为许多应用领域的主流。应用它仍然需要很多关于分布和建模技术的知识,但是最近概率编程语言的发展已经使它变得更容易处理。Stan 是一种很有前途的语言,非常适合单一的分析案例。随着近似方法的改进,如果在定义和验证模型时小心谨慎,它可以扩展到生产级别。此处描述的模型是我们在生产中运行的模型的基础,并有各种附加的改进。

我们计划将 Stan 与其他概率编程语言进行比较,即 PyMC3Edward ,但是让 Stan 在我们的例子中工作已经足够具有挑战性了。我们希望将来能做这样的比较。幸运的是,鲍勃·卡彭特写了一篇关于同一主题的精彩的对比博文。简而言之,PyMC3 似乎提供了与 Python 最流畅的集成,但缺乏建模特性。另一方面,Edward 是建立在 TensorFlow 之上的非常低级的语言,支持最新的变分推理方法。这是一个非常前沿的技术,有很多突破性的变化,对于生产使用来说,这是一个有点冒险的选择。

我们现在每天晚上都在为数以千计的不同账户运行收入模型,这些账户包含不同数量的活动、广告设置和收入观察。最长的跑步需要几分钟。我们的大多数客户仍在使用转换优化,但正在过渡到使用收入优化功能。总的来说,我们的预测性预算拨款管理了约 100 万欧元的日常广告支出。将来,我们会看到 Stan 或其他概率编程语言在的优化特性中扮演重要角色。

Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档),个人经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以亲自搞定,主要针对计算机相关专业的正在做大作业的学生和需要项目实战练习的学习者,可作为毕业设计、课程设计、期末大作业,代码资料完整,下载可用。 Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的人脸识别系统 深度学习 (源码+文档)Python毕业设计-基于Python的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值