科恩的卡帕:它是什么,什么时候使用它,以及如何避免它的陷阱
当整体准确性有偏差时的替代方案,但不要盲目相信统计数据
介绍
科恩的 kappa 是一个常用于评估两个评分者之间的一致程度的指标。它还可以用来评估分类模型的性能。
例如,如果我们有两个银行家,我们要求他们将 100 名客户分为两类进行信用评级,即好和坏,基于他们的信用价值,我们可以通过科恩的 kappa 来衡量他们的同意程度。
类似地,在分类模型的背景下,我们可以使用 Cohen 的 kappa 来比较机器学习模型预测和人工建立的信用评级。
像许多其他评估指标一样,科恩的 kappa 是基于混淆矩阵计算的。然而,与计算整体准确性相反,科恩的 kappa 考虑了类别分布的不平衡,因此解释起来可能更复杂。
在本文中,我们将指导您计算和解释 Cohen 的 Kappa 值,特别是与总体精度值进行比较。我们将表明,在由于类别分布的巨大不平衡而导致整体准确性失败的情况下,Cohen 的 kappa 可能会提供对模型性能的更客观的描述。一路上,我们还将介绍几个在解读科恩的 kappa 价值观时需要牢记的小技巧!
衡量不平衡数据集上的性能改进
让我们使用由 UCI 机器学习库提供的德国信用数据来关注银行贷款的分类任务。在该数据集中,根据银行的标准,银行客户被分配了“坏”信用评级(30%)或“好”信用评级(70%)。出于本文的目的,我们通过 bootstrapping 夸大了目标类信用评级的不平衡,给出了 10%的“坏”信用评级和 90%的“好”信用评级:这是一个高度不平衡的数据集。夸大不平衡有助于我们在这篇文章中更清楚地区分“整体准确性”和“科恩的 kappa”。
让我们在目标列上使用分层抽样将数据划分为训练集(70%)和测试集(30%),然后训练一个简单的模型,例如决策树。鉴于这两个阶层之间的高度不平衡,该模型的表现不会太好。然而,让我们将它的性能作为本次研究的基准。
图 1 显示了这个基线模型的混淆矩阵和准确性统计。该模型的总体精度相当高(87%),暗示该模型的性能是可接受的。然而,在混淆矩阵中,我们可以看到,该模型在 30 个信用评级不佳的信用客户中,只能正确地对 9 个进行分类。这也可以从“坏”类的低敏感度值(仅为 30%)看出。基本上,决策树对大多数“好”客户进行了正确分类,而忽略了少数“坏”客户的必要表现。类别先验概率中的不平衡补偿了分类中的这种草率。现在让我们注意一下,Cohen 的 kappa 值仅为 0.244,在其范围[-1,+1]内。
图 1:基线模型的混淆矩阵和准确性统计,即在高度不平衡的训练集上训练的决策树模型。总体准确率相对较高(87%),尽管该模型只检测到少数信用评级不佳的客户(敏感度仅为 30%)。
让我们通过强迫模型承认少数类的存在来改善模型性能。我们这次在训练集上训练相同的模型,其中少数类已经使用 SMOTE 技术过采样,两个类的类比例都达到 50%。
为了提供关于该模型的混淆矩阵的更多细节,具有“坏”信用评级的 30 个客户中的 18 个被该模型检测到,导致新的敏感度值为 60%,而不是之前的 30%。对于该模型,Cohen 的 kappa 统计值现在是 0.452,与之前的值 0.244 相比有显著的增加。但是整体的准确性呢?对于第二个模型,它是 89%,与之前的值 87%没有太大区别。
当总结时,我们得到两个非常不同的图片。从整体精度来看,模型性能根本没有太大变化。然而,根据科恩的 kappa 很多都变了!哪种说法是正确的?
图 2:改进模型的混淆矩阵和准确性统计。决策树模型在更平衡的训练集上训练,其中少数类已被过采样。总体准确性几乎与基线模型相同(89%对 87%)。然而,Cohen 的 kappa 值显示出从 0.244 到 0.452 的显著增加。
从混淆矩阵中的数字来看,似乎 Cohen 的 kappa 对模型在使用不平衡数据时的表现有更现实的看法。为什么科恩的 kappa 更关注少数民族阶层?实际是如何计算的?我们来看看吧!
科恩的卡帕
Cohen 的 kappa 通过以下公式计算[1]:
其中,p_0 是模型的总体精度,而 p_e 是模型预测和实际类值之间的一致性的度量,就好像是偶然发生的一样。
在像我们这样的二元分类问题中,p_e 是 p_e1 和 p_e2 的和,p _ E1 是预测值偶然与第 1 类(“好”)的实际值一致的概率,p _ E2 是预测值偶然与第 2 类(“坏”)的实际值一致的概率。假设两个分类器(模型预测和实际类值)是独立的,这些概率 p _ e2 和 p_e2 是通过乘以实际类的比例和预测类的比例来计算的。
将“坏”视为阳性类别,基线模型(图 1)将 9%的记录(假阳性加真阳性)归入“坏”类别,将 91%的记录(真阴性加假阴性)归入“好”类别。因此 p_e 为:
因此科恩的 kappa 统计数据:
该值与图 1 中报告的值相同。
实际上,科恩的 kappa 排除了分类器和随机猜测一致的可能性,并测量了它做出的无法用随机猜测解释的预测的数量。此外,Cohen 的 kappa 试图通过考虑随机猜测的正确分类来纠正评估偏差。
科恩卡帕的痛点
在这一点上,我们知道 Cohen 的 kappa 在处理不平衡数据时是一个有用的评估指标。然而,科恩的卡帕也有一些缺点。让我们一个一个来看看。
全范围[-1,+1],但不相等
如果目标阶层分布均衡,则更容易达到更高的科恩卡帕值。
对于基线模型(图 1),预测类的分布紧密跟随目标类的分布:27 个预测为“差”对 273 个预测为“好”,30 个实际为“差”对 270 个实际为“好”。
对于改进的模型(图 2),两个类别分布之间的差异更大:40 预测为“差”对 260 预测为“好”,30 实际为“差”对 270 实际为“好”。
如最大 Cohen kappa 的公式所示,预测和实际目标类别的分布差异越大,最大可达 Cohen kappa 值越低。最大 Cohen kappa 值表示混淆矩阵中假阴性或假阳性的数量为零的边缘情况,即所有具有良好信用评级的客户,或者所有具有不良信用评级的客户都被正确预测。
其中,p_max 是给定目标类和预测类的分布时,模型可达到的最大总精度:
对于基线模型,我们得到 p_max 的以下值:
而对于改进的模型,它是:
Cohen kappa 的最大值是基线模型的:
对于改进的模型,它是:
结果表明,实际目标类别和预测目标类别之间的分布差异较大的改进模型只能达到高达 0.853 的 Cohen kappa 值。而基线模型可以达到值 0.942,尽管性能更差。
对于平衡的数据,Cohen 的 kappa 更高
当我们计算 Cohen 的 kappa 时,我们强烈假设目标类和预测类的分布是独立的,并且目标类不影响正确预测的概率。在我们的例子中,这意味着具有良好信用评级的信用客户与具有不良信用评级的信用客户获得正确预测的机会相等。然而,因为我们知道我们的基线模型偏向于大多数“好”类,所以违反了这个假设。
如果这个假设没有被违反,就像在目标类平衡的改进模型中一样,我们可以达到更高的 Cohen kappa 值。这是为什么呢?我们可以把 Cohen 的 kappa 公式改写为正类概率的函数,当正类概率为 0.5 时函数达到最大值[1]。我们通过将相同的改进模型(图 2)应用于不同的测试集来测试这一点,其中积极的“坏”类的比例在 5%和 95%之间变化。我们通过引导原始测试数据为每个类分布创建 100 个不同的测试集,并根据结果计算平均 Cohen kappa 值。
图 3 显示了平均 Cohen 的 kappa 值与正类概率的对比——是的!当模型应用于平衡数据时,Cohen 的 kappa 确实达到了最大值!
图 3。Cohen 的 kappa 值(在 y 轴上)是在测试数据(在 x 轴上)中具有不同正类概率的相同模型中获得的。y 轴上的 Cohen kappa 值被计算为所有 Cohen kappa 的平均值,该平均值是通过对固定类别分布的原始测试集进行 100 次自举而获得的。该模型是在平衡数据上训练的决策树模型,在文章开始时介绍过(图 2)。
科恩的 kappa 很少提到预期的预测准确性。
Cohen 的 kappa 的分子,(p_0 - p_e),讲的是模型的观测整体精度和偶然可以得到的整体精度的差别。公式的分母(1- p_e)表示这个差值的最大值。
对于一个好的模型,观测差和最大差接近,Cohen 的 kappa 接近 1。对于一个随机模型来说,整体的精度都是因为随机的偶然性,分子是 0,科恩的 kappa 是 0。科恩的 kappa 理论上也可能是负数。那么,模型的整体准确性将会比通过随机猜测获得的更低。
鉴于上面的解释,科恩的 kappa 不容易按照预期的准确性来解释,并且通常不建议遵循任何口头类别作为解释。例如,如果您有 100 个客户和一个总体准确率为 87 %的模型,那么您可以预期正确预测 87 个客户的信用评级。科恩的 kappa 值 0.244 并没有给你提供这么容易的解读。
摘要
在本文中,我们解释了如何使用和解释 Cohen 的 kappa 来评估分类模型的性能。虽然 Cohen 的 kappa 可以在处理不平衡数据时纠正整体准确性的偏差,但它有一些缺点。因此,下次您查看模型的评分标准时,请记住:
- 在处理不平衡数据时,Cohen 的 kappa 比整体准确性更能提供信息。在比较或优化分类模型时,请记住这一点!
- 看看混淆矩阵中的行和列的总数。目标/预测类的分布相似吗?如果不是,最大可达 Cohen kappa 值将会更低。
- 同一个模型对于不平衡的测试数据会给出比平衡的测试数据更低的 Cohen kappa 值。
- 科恩的 kappa 很少提到单个预测的预期准确性
这项研究使用的工作流程如图 4 所示。在工作流程中,我们训练、应用和评估两个决策树模型,这两个模型预测信用客户的信用价值。在顶部分支中,我们训练基线模型,而在底部分支中,我们使用 SMOTE 技术在自举训练集上训练模型。该工作流程可从 KNIME Hub 上的 Cohen 的 Kappa 评估分类模型页面下载。
图 4:这个 KNIME 工作流训练了两个决策树来预测客户的信用评分。在顶部分支中,基线模型根据不平衡的训练数据进行训练(90%“好”对 10%“坏”的类记录)。在底部分支中,在新的训练数据集上训练改进的模型,其中少数类已经过采样(SMOTE)。用于评估分类模型的工作流 Cohen’s Kappa 可在 KNIME Hub 上获得。
参考
[1]布兰德,马丁。"科恩的卡帕"约克大学健康科学系https://www-users . York . AC . uk/~ mb55/MSC/clin met/week 4/kappa _ text . pdf。【2020 年 5 月 29 日访问】 (2008)。
如最初发表于 的《新闻报》 。
类固醇上的 Colab:带 SSH 访问和 Visual Studio 代码服务器的免费 GPU 实例
一步一步地引导 SSH 进入 Google Colab 提供的免费 GPU 实例,并安装 Visual Studio Code Server。
正如你们大多数人已经知道的,谷歌研究提供了免费的 Jupyter 笔记本环境实例,带有 T2 图形处理器和 TPU,完全在云中运行。该平台名为(简称“Colab”),当你想进行快速实验或构建新的机器学习模型时,它是一个很好的资源,因为不需要设置:你需要的只是一个浏览器!
图片作者。与 GPU 的 Colab 会话
然而,当事情变得棘手时,一个简单的 Jupyter 笔记本界面可能会相当有限:我们可能需要有一个 SSH 会话!我们开始吧!
第一步。从 ngrok 获取令牌
在 ngrok 上免费注册,从左侧的认证设置中获取一个 Authtoken。
图片作者。从 ngrok 获取免费令牌。
第二步。在 Colab 上安装并运行 ngrok
在 Colab 的一个笔记本单元格内,复制并粘贴下面的代码,插入来自 ngrok 的令牌并运行单元格。
# Install useful stuff
! apt install --yes ssh screen nano htop ranger git > /dev/null# SSH setting
! echo "root:carbonara" | chpasswd
! echo "PasswordAuthentication yes" > /etc/ssh/sshd_config
! echo "PermitUserEnvironment yes" >> /etc/ssh/sshd_config
! echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
! service ssh restart > /dev/null# Download ngrok
! wget -q -c -nc [https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip](https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip)
! unzip -qq -n ngrok-stable-linux-amd64.zip# Run ngrok
authtoken = "PUT_YOUR_TOKEN_HERE"
get_ipython().system_raw('./ngrok authtoken $authtoken && ./ngrok tcp 22 &')
! sleep 3# Get the address for SSH
import requests
from re import sub
r = requests.get('[http://localhost:4040/api/tunnels'](http://localhost:4040/api/tunnels'))
str_ssh = r.json()['tunnels'][0]['public_url']
str_ssh = sub("tcp://", "", str_ssh)
str_ssh = sub(":", " -p ", str_ssh)
str_ssh = "ssh root@" + str_ssh
print(str_ssh)
图片作者。用 ngrok 在 Colab 中启动一个 SSH 会话。
作为输出,您应该会收到如下内容(地址和端口可能不同):
ssh [root@0.tcp.ngrok.io](mailto:root@0.tcp.ngrok.io) -p 14407
将它复制并粘贴到您喜欢的终端模拟器中,当需要密码时插入 carbonara 并享受您的 SSH 会话!当然,你可以随心所欲地修改密码!
图片作者。SSH 会话:在 Colab 实例内部
不习惯 Linux 命令行?查看这篇文章:每个数据科学家都应该知道的基本 Linux 控制台命令。
第三步。运行 Visual Studio 代码服务器
SSH 很好,但是直接在浏览器中拥有一个完整的代码编辑器更好!现在让我们看看如何在 Colab 实例中安装 Visual Studio 代码。
首先,我们需要安装我们的 Google Drive。
# Mount Google Drive and make some folders for vscode
from google.colab import drive
drive.mount('/googledrive')
! mkdir -p /googledrive/My\ Drive/colabdrive
! mkdir -p /googledrive/My\ Drive/colabdrive/root/.local/share/code-server
! ln -s /googledrive/My\ Drive/colabdrive /
! ln -s /googledrive/My\ Drive/colabdrive/root/.local/share/code-server /root/.local/share/
系统将提示您通过插入在第二个页面上生成的令牌来授权访问。
图片作者。在 Colab 上安装 Google Drive
现在,让我们下载、安装并运行 Visual Studio 代码的服务器版本。
! curl -fsSL [https://code-server.dev/install.sh](https://code-server.dev/install.sh) | sh > /dev/null
! code-server --bind-addr 127.0.0.1:9999 --auth none &
图片作者。在 Colab 上下载并安装 Visual Studio 代码服务器
让我们用端口转发启动另一个 SSH 会话(用您的地址和端口替换 ngrok 地址和端口):
ssh -L 9999:localhost:9999 [root@0.tcp.ngrok.io](mailto:root@0.tcp.ngrok.io) -p 14407
然后在打开浏览器 http://127.0.0.1:9999
图片作者。运行在 Colab 上的 Visual Studio 代码服务器
由于我们之前已经安装了 Google Drive,设置、Visual Studio 代码的扩展和项目文件(如果保存在/colabdrive 下)将通过会话保持不变。
享受 Colab 中的 Visual Studio 代码!
参考
- https://gist . github . com/yashkumaratri/204755 a 85977586 cebb 58 DC 971496 da
- https://stack overflow . com/questions/48459804/how-can-I-ssh-to-Google-co laboratory-VM
- https://medium . com/@ meet _ Patel/how-to-ssh-into-Google-colab-and-run-scripts-from-terminal-notebook-3931 f 2674258
Colab Pro:物有所值吗?
10 美元有多大作用?我们做了测试。你做阅读。
Google Colab 已经推出有一段时间了,但最近我们有一个升级到 Pro 版本的选项,这可能会让你获得更快的 GPU、更长的运行时间和更多的 RAM。但是差别有多大呢?值 10 美元/月吗?让我们找出答案。
我们已经写了关于 Google Colab(免费版)的文章,所以如果你还没有:
[## Google Colab:它与支持 GPU 的笔记本电脑相比如何?
Colab 简介、运行时、性能比较…以及疑难解答
towardsdatascience.com](/google-colab-how-does-it-compare-to-a-gpu-enabled-laptop-851c1e0a2ca9)
为了进行测试,我们使用了免费版和专业版的服务,在肺炎数据集上执行深度学习任务。数据集由大约5000 张肺部 x 光图像组成,非常适合这类任务。
这篇文章的结构如下:
- 一般差异
- GPU 比较
- RAM 比较
- 案例:模型训练时间比较
- 判决
所以事不宜迟,让我们开始吧!
一般差异
本节的目标是讨论免费版和专业版服务之间的一般差异,如 CPU、可用磁盘空间和运行时。我不认为这 3 个会对你的购买决定产生太大影响(也许最后一个除外),因为我在免费版中没有遇到过这些问题。
话虽如此,以下是 CPU 之间的比较:
- Colab(免费) —英特尔至强 CPU @ 2.20GHz
- Colab (Pro) —英特尔至强 CPU @ 2.30GHz
所以在这里没有太大的区别——但是再一次,你可能没有使用 Colab 作为它的 CPU,所以这部分真的没有那么重要。
至于磁盘大小,我在两者上都获得了相同的 34GB 可用内存——这有点奇怪——但这对于 99.99%的用户来说已经足够了。运行时间可能会让你吃惊。以下是谷歌的官方声明:
使用 Colab Pro,您的笔记本电脑可以保持连接长达 24 小时,空闲超时相对宽松。尽管不能保证持续时间,但空闲超时有时可能会有所不同。[1]
对于免费版本,我们最多有 12 个小时的运行时间,空闲超时更严格。尽管有避免这种情况的方法,本文中描述了一种可能的解决方案。
好了,我们现在知道了一些基本的区别。在接下来的部分中,我们将探索 RAM 和 GPU 的不同之处,之后,我们还将在真实数据集上比较训练持续时间。
GPU 比较
Google Colab 最重要的一个方面是 GPU。无论您的笔记本电脑有多强大,您都可以使用现代化的强大 GPU。下面是您可以在免费层和专业层使用的 GPU:
- Colab(免费) —特斯拉 K80
- Colab (Pro) —特斯拉 P100-PCIE-16GB
如果你不知道这些 GPU 之间有什么不同,那也没关系。这就是为什么我们准备了一张图表来比较可用的 GPU 内存:
不要担心高 RAM 运行时,这将在下一节讨论。从这一点上,你可以看到,使用 Pro 层,你可以获得大约 5GB 更多的 GPU 内存,这在理论上意味着神经网络训练过程应该更快(我们会看到这一点)。
RAM 比较
Colab 的 Pro 版本将让您访问一个高 RAM 运行时环境。理论上,这个运行时应该给我们更多的内存,以防标准的 12GB 不够用。我的大部分深度学习工作都是在“玩具”例子上,数据集只有几个 GB 大小,所以我从来没有遇到过 RAM 问题。
如果您需要更多的工作内存,您可以转到**运行时—更改运行时类型:**来更改运行时
但是 Pro 版默认给你的 RAM 多吗?
我很高兴你问了。让我们看看下一个可视化:
在启用高 RAM 环境之前,Pro 和免费版本完全相同。在你的项目中请记住这一点,但我发现 12.8GB 对于大多数情况来说已经足够了。
案例:模型训练时间比较
现在是你期待已久的时候了。在这里,我们将最后比较谷歌 Colab 的免费和专业层的培训时间的差异。如前所述,该模型是在肺炎数据集上训练的。
为同一个数据集准备了两种架构,第一种是自定义 CNN 架构,第二种是 DenseNet201 预训练网络,最后一层修改为输出两个类。您可以在下面看到自定义架构:
此外,以下是一些您可能会觉得有用的附加规范:
- 图像尺寸: 224x224
- 批量大小: 32
- 学习率: 0.001
- 历元: 20
- 优化器:亚当
- **标准:**斜视
所以这里的一切都很标准,但我想分享这些信息,以防你想复制结果。
在训练期间,我记录了训练持续时间,该信息显示在下图中:
正如你所看到的,在免费版本中, DenseNet201 架构的培训过程持续了 50%的时间,而定制架构的培训时间减少并不显著。请记住这一点,因为您将在大多数时间使用预先训练的架构。
我想现在你已经有了做决定所需的所有信息。下一节我来说说我的看法。
判决
我们看到,在免费版本中,预构建架构的培训过程持续时间延长了 50%。 但这对你真的有意义吗?
请记住,即使是专业版,您最多只能运行 24 小时。对于一些企业来说,24 小时仍然不够,因为培训过程要持续几天甚至几周。
如果你是一个仍在学习数据科学和深度学习的人,那么我认为专业版没有实际好处,因为免费版将处理你会遇到的所有数据集。专业版将提供速度改进,但对大多数用户来说并不显著。
如果你绝对需要提高速度,那就去做吧——每月只需 10 美元。如果没有,把钱存起来做别的事情——你不会错过任何特别的事情。
你有什么想法?你们国家的 Pro 版速度快吗? 通知我。
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
[## 通过我的推荐链接加入 Medium-Dario rade ci
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@radecicdario/membership)
参考
[1]https://colab.research.google.com/signup#
数据科学家 GitHub:提交
GitHub 的权威指南:提交
了解提交的组成部分、提交、重置或删除提交。
路易斯·尤西比奥(https://unsplash.com/@lceusebio)的照片
本文是 GitHub 协作后续系列的一部分。本文将尝试详细理解提交,比如提交的组成部分,在推送之前和之后删除提交,或者重置提交。
对于初学者来说,强烈推荐快速阅读这篇文章,像 Pro: Part1 一样在 GitHub 上协作。
这个系列,像 pro 一样在 GitHub 上协作,关注特定的主题:
- GitHub 入门 : 像 Pro 一样在 GitHub 上协作: Part1
- 分支: 像 Pro 一样在 GitHub 上协作: Part2
- **提交:**像 Pro 一样在 GitHub 上协作:提交
什么是提交?
提交是用 git commit 命令创建的,用于捕获项目的状态。Git 存储一个提交对象,该对象指向快照暂存内容(已索引)。请参见下面红框中突出显示的提交阶段。
提交流程图
提交的组成部分:
让我们看一下提交对象,如下所示。提交中的三个主要组件包括哈希、头、和分支(主),如下所述。
提交对象
散列:每次提交都会为各自的提交创建一个唯一的散列。稍后使用这些散列恢复到以前的版本,或者查找有关提交的详细信息。只需要前七个字符来查找各自的提交。
头:显示当前工作分支。在上图中,头指向主分支,这意味着当前的工作分支在主分支上。
**分支:**默认情况下,开发的第一行(分支)命名为主。不同分支上的所有先前的工作被合并到 master。
要进一步理解这个概念,请参考这篇博客的帖子。
三次提交后主分支
切换到特定提交
基于用例,有多种方法可以检验特定的提交,比如进行临时或永久的切换,后退几步添加一个特性。
临时开关
要临时切换到第一次提交(7d8d1af)并从特定提交进行少量提交,请运行以下命令。
$ cd autos/ (git project root)
$ git checkout 7d8d1af (Use hash if you know it, else)
$ git checkout HEAD~3 (Use number of commits to go back, our case 3)$ git checkout -b new-branch 7d8d1af (create new branch on the commit)
$ git checkout branch_name (to go back to respective branch)
当签出提交时,头被分离。分离的头意味着该头没有指向最近的提交;相反,它指向签出时的提交。
临时提交签出流程
永久开关
要永久删除提交,使用 Git reset 。Git 复位主要有五种模式:软、混合、合并、硬、保持。有关详细信息和不同的解决方案,请参考堆栈溢出。
- Git reset — hard 将更改磁头、索引(阶段)和工作目录。记得运行 git status 来检查工作树是否干净,否则所有未提交的更改都将丢失。
- Git 复位—软将改变磁头,不改变索引(阶段)或工作目录。这是最安全的选择。
例如,我们希望重置到第一次提交(7d8d1af)。处理这种情况有两种方法。
- 提交未推送到远程
总是运行 git status 来检查工作树是否干净。要仅删除当前提交,但保留文件并对其进行索引,请使用 soft。
$ cd autos/ (git project root)
$ git reset --soft HEAD~3
“工作树是干净的”意味着没有你可以失去的未提交的工作。在这种情况下,安全地使用硬。
$ cd autos/ (git project root)
$ git reset --hard 7d8d1af (Use hash if you know it, else)
$ git reset HEAD~3 (Use number of commits to go back, our case 3)
在“工作树是而不是干净的”的情况下,你知道如果你直接使用 hard 可能会丢失一些未提交的工作,在命令 hard 之前运行“stash”来保存你的本地更改。
$ cd autos/ (git project root)
$ git stash
$ git reset --hard 7d8d1af
$ git stash pop
2。提交推送到远程
$ git revert --no-commit 7d8d1af HEAD
$ git commit
$ git push# To abort the above steps
git revert --abort
要了解更多关于 git 重置/恢复和返回到 Git 中先前状态的信息,请参考这篇写得很好的博客,有关代码,请参考 GitHub 库。
参考:
面向数据科学家的 GitHub:第 1 部分
权威 GitHub 指南:Git 添加— Git 提交— Git 推送
了解版本控制、git 配置、创建和克隆存储库以及提交。
本文是 GitHub 协作后续系列的第一部分。本文旨在解释两个或更多的人如何在 GitHub 上为数据科学项目协作、版本控制和校对他们的代码。
我们将讨论特定主题,如:
- GitHub 入门:像 Pro 一样在 GitHub 上协作: Part1
- 分支: 像 Pro 一样在 GitHub 上协作: Part2
- 提交: 像 Pro 一样在 GitHub 上协作:提交
在这些文章中,我们将有两个人在 GitHub 上合作。让我们给他们取两个假名,Sofi 和 Alec。
目录:
计划的任务
由于这不是一篇关于数据清理的文章,我们将重点写几个函数来看看协作和版本控制是如何工作的。我们将使用二手车数据集。点击从下载数据集。
**Sofi and Alec**: *are working on a data cleaning project named “autos“. Sofi takes the initiative of gathering data, creating required .py, .ipynb files for the project.*
这篇文章展示了该项目的 EDA。这个项目的任务是基于 EDA 报告构建的。在本文中,我们将只看三个任务。
Sofi 创建一个项目文件夹(…/autos),其中包含两个文件:auto.csv 和 autos_analysis.ipynb。
现阶段 Sofi 的工作目录
**Sofi and Alec**: *Before starting the project, they browse through the different version control systems to find the one suitable for their project.*
版本控制系统(VCS)
在 软件工程 , 版本控制 (也称为 修订控制 , 源代码控制 ,或 源代码管理 )是一类负责管理变更的系统版本控制是 软件配置管理 的一个组件。
有许多版本控制系统。通常它们被分为两类:“集中式”和“分布式”。
【CVCS】
CVCS 基于这样的想法,即在某个地方(可能在服务器上)有一个项目的单一“中心”副本,程序员将他们的更改“提交”到这个中心副本。最受欢迎的 CVCS 是颠覆。
中央版本控制系统
【DVCS】
DVCS 不一定依赖中央服务器来存储项目文件的所有版本。相反,每个开发人员都“克隆”一个存储库的副本,并在他们自己的硬盘上拥有该项目的完整历史。这个副本(或“克隆”)具有原始副本的所有元数据。Git 和 Mercurial 是最流行的 DVCS。
分布式版本控制系统
****Sofi and Alec**: They decide to go *ahead with the popular distributed version control system GitHub. With the distributed system, branching and merging are much easier to achieve, and connecting to the network is not required.***
开源代码库
GitHub 的核心是 Git,这是一个由 Linux 创建者 Linus Torvalds 发起的开源项目。GitHub 是一个 Git 存储库托管服务,但是它增加了许多特性。虽然 Git 是一个命令行工具,但 GitHub 提供了一个基于 Web 的图形界面。它还提供了访问控制和一些协作功能,例如 wikis 和每个项目的基本任务管理工具。
****Sofi and Alec**: They configured Git following the below steps. Sofi created a git repository for Alec to clone.**
首次 Git 配置遵循以下步骤
**$ git config --global user.name "Sofi Sue"
$ git config --global user.email "sofi.sue@examplemail.com"
$ git config --global color.ui auto
$ git config --global core.editor VimAfter configuring git check settings:
$ git config --list**
Sofi:创建本地 git 存储库
**Add below files in the project folder (../autos/)1) **'.gitignore'** with the list of file names of the files to be ignored
2) **'ReadMe'** file as plain text or Markdown describing the project**
运行以下命令。
**$ cd autos/
$ git init
$ git add . *(adds all the files except the ones listed in .gitignore)*
$ *git commit — m ‘add a comment’***
如果没有要忽略的文件,则保留。git 忽略文件空白,随着项目的进展添加文件名。
现阶段 Sofi 的工作目录
恭喜你完成了你的第一次承诺!
犯罪
提交是用 git commit 命令创建的,用于捕获项目的状态。当您提交时,Git 存储提交对象,该对象包含指向您暂存的内容快照的指针。在上面的提交对象映像中,我们可以看到三个主要组件,hash、master 和 head。
提交对象
Hash :每次提交都会为各自的提交创建一个惟一的 Hash。在后面的阶段使用这七个字符作为这些散列,以恢复到该版本并找到提交的详细信息。
Master: 默认情况下,开发第一线(分支)的名称为 Master。不同分支上的所有先前的工作被合并到 master。
头:显示当前工作分支。上面的图像头指向主分支,这意味着当前的工作分支是主分支。
要进一步理解这个概念,请参考这篇博客帖子。
第一次提交后。Alphanum 是第一次提交的哈希的前 7 个字符。
在这个阶段,Sofi 决定将另一个文件 autos.py 添加到她的工作目录中。请注意,此文件不会被暂存,将显示为未跟踪的文件。要将它添加到存储库中,运行 git add autos.py。
现阶段 Sofi 的工作目录
Sofi:将本地 git 存储库连接到 GitHub
按照此处给出的说明在 GitHub 帐户中创建一个存储库。不要创建。gitignore”或“ReadMe”文件,因为我们已经在项目文件夹中创建了它。将链接复制到 git repo,然后返回到终端,用下面的命令将您的本地存储库连接到 Github。在这里找到 GitHub 库。
**$ git remote add origin [https://github.com/snehalnair/collaborate-github.git](https://github.com/snehalnair/collaborate-github.git)
$ git push -u origin master**
恭喜你,你第一次推送了远程 GitHub 服务器!
添加→提交→推送
下面的流程图总结了项目到目前为止所遵循的步骤
git-log —显示提交日志
每次提交后,根据用例检查提交细节。例如,要查看所有提交摘要,运行 git log-online。下面提到的是一些有用的 git 命令,它们可以在您或合作者每次提交后方便地检查细节。这里给出了详细的解释。
**$ git show
$ git log
$ git log —oneline
$ git log —stat
$ git log -p
$ git log -p --stat
$ git log --decorate**
Alec:将 git 存储库克隆到他的本地机器上
要获得现有 Git 存储库的副本,请在终端中运行下面的命令。
**$ git clone [https://github.com/snehalnair/collaborate-github.git](https://github.com/snehalnair/collaborate-github.git) autos
$ git pull**
该命令创建一个名为…/autos 的目录,在其中初始化一个. gitdirectory,从该存储库的最新版本中提取所有数据。导航到文件夹…/autos,查找存储库中的所有文件。
亚历克克隆的工作目录。注意,Alec 的工作目录只包含被跟踪的文件。autos.py 文件不是 Alec 目录的一部分,因为 Sofi 没有添加、提交和推送该文件。
****Sofi to Alec**: I forgot to add autos.py and the ReadMe file. Let me push autos.py file to the server first and then create a ReadMe file**Alec to Sofi**: I have worked on the ReadMe file already. Let me add it to the folder and push, and you can push autos.py in the after.**
Alec :运行以下命令创建并提交自述文件
**$ cd autos/
$ touch ReadMe
$ git pull
$ git add ReadMe
$ git commit -m ‘add ReadMe file’$ git push -u origin master**
在第二次提交后
Sofi :运行以下命令提交并推送 autos.py 文件
**$ cd autos/
$ git pull
$ git add autos.py
$ git commit -m ‘add autos.py file’$ git push -u origin master**
第三次提交后
工作目录
上述活动显示了在添加和推送文件之前运行 git pull 的重要性。Git pull 确保您拥有最新的存储库。这是 Sofi 和 Alec 当前的工作目录。
****Sofi and Alec**: The repository is ready for us to work. But we need to isolate our work, else we will start overwriting each others work/codes. Lets learn about branches before we proceed.**
对于接下来的步骤,请参考本文的下一部分,Sofi 和 Alec 将创建分支,并为他们的项目选择合适的分支工作流。参考 GitHub 库获取代码。
要了解更多关于 GitHub 的信息,请阅读这个博客。
参考:
https://www . atlassian . com/blog/software-teams/version-control-centralized-DVCs
https://en.wikipedia.org/wiki/Software_engineerin克
面向数据科学家的 GitHub:第 2 部分
了解分支,使用 git 的不同分支工作流。
照片由诺亚·罗森菲尔德(https://unsplash.com/s/photos/noah-rosenfield)拍摄
这是 GitHub 协作后续系列的第二部分。在《T2》第一部中,两个同事 Sofi 和 Alec 开始着手一个数据清理项目,他们在彼此之间分配任务,创建和克隆存储库,并首次提交。
我们将讨论特定主题,如:
- GitHub 入门 : 像 Pro 一样在 GitHub 上协作: Part1
- **Git 分支:**像 Pro 一样在 GitHub 上协作: Part2
- 提交 Git: 像 Pro 一样在 GitHub 上协作:提交
在这些文章中,我们将有两个人在 GitHub 上合作。我们给他们取两个假名吧,Sofi 和 Alec。
目录:
**Sofi and Alec**: The repository is ready for us to work. But we need to isolate our work, else we will start overwriting each others work/codes. Lets learn about branches before we proceed.
分支
在进入分支工作流之前,让我们试着理解分支的概念。分支获取它所分支的提交的最新版本的副本。因此,您可以在一个隔离的环境中处理您的任务,而无需直接在主分支中进行更改。一旦任务完成,这个分支就可以合并到主分支中。让我们创建一个分支来更好地理解这个概念。
创建分支
要创建一个新的分支(test-branch ),运行下面的命令。
$ git branch test-branch
git 分支测试-分支命令增加了一个新的分支测试-分支
结账处
运行上面的命令添加了一个新的分支,但是,要移动到该分支,也就是说,要将头指向该分支,您必须运行 checkout git 命令。
$ git checkout test-branch
头指向测试分支
在一个命令中创建和检出新分支。
git checkout -b test-branch
强制删除分支
让我们删除这个分支,因为它们只是为了我们的理解。除非运行如下所示的强制删除命令,否则不能删除标题所指向的分支。
$ git branch -D test-branch
签出并删除分支
要删除一个分支而不强制删除,请签出到其他分支并运行 delete 命令。
$ git checkout master
$ git branch -d test-branch
**Sofi and Alec**: Now that we have a better understanding of branching technique. Lets find out if there is a suitable branching workflow that we can use.
Git 的分支工作流
对于 Git 用户来说,有许多流行的分支工作流适合他们各自的开发周期。
以下是最受欢迎的工作流程:
- Git 流
- GitHub 流
- GitLab 流程
- 一个流程
要了解更多关于这些分支工作流的信息,请阅读这篇[博客文章](http://4 branching workflows for Git)。
GitHub 流
这是最适合我们用例的分支工作流。GitHub flow 是一个轻量级的、基于分支的工作流,支持定期进行部署的团队和项目。要了解有关这一特定工作流程的更多信息,请参考此链接。
GitHub 流程:所有的提交都在特性分支上进行,并合并到主分支上。主分支总是可部署的。
那么它是如何工作的呢?
master
分支中的任何东西都是可部署的- 为了做一些新的事情,创建一个描述性命名的
master
分支(例如:new-oauth2-scopes
) - 在本地提交到那个分支,并定期将您的工作推送到服务器上相同的命名分支
- 当您需要反馈或帮助时,或者您认为该分支机构已经准备好进行合并时,打开一个拉动请求
- 在其他人已经审查并签署了该特性之后,您可以将它合并到 master 中(git merge master)
- 一旦它被合并并被推送到“主节点”,你可以并且应该立即部署(git push -u origin master)
使用 GitHub Flow 工作流开始协作
概述项目状态:Sofi 和 Alec 正在进行一个名为“autos”的数据清理项目。基于初步的分析,他们之间分配了以下任务。
**Sofi and Alec**: Lets create task based branches based on the GitHub Flow workflow instructions.
Sofi runs the below command in her computer
$ git checkout -b numcols-2-numdtypeAlec runs the below command in his computer
$ git checkout -b find-outliers
这就是分支在现阶段 Sofi 和 Alec 的电脑上的样子。它们看不到彼此的分支,因为它们尚未推送至服务器。
Sofi :在 autos.py 文件中输入以下功能
def numcol2numdtype(data, cols):
for col in cols:
data[col].str.replace('[^0-9]', '').astype('float')
return data
在更新了 autos.py 文件之后,是时候提交并提出一个拉请求了。**注意:**提交前和推送前总是运行 git pull 将最新版本的文件推送到存储库中。
$ git pull
$ git commit -m 'remove non-numeric from numCol, convert to num dtype'
$ git pull
$ git push --set-upstream origin numcols-2-numdtype
您只需要在第一次从新分支推送时添加参数---set-upstream origin my-branch
。
拉取请求
将更改推送到新分支后,您可以在 GitHub 页面上看到分支和 compare & pull 请求,如下所示。点击“比较和提取请求”,这将带您到另一个页面,写评论,如果有的话,然后点击“提取请求”。
请求将发送给 repo 维护者或所有者进行代码审查,在我们的例子中,repo 维护者或所有者可以在 Sofi 和 Alec 之间交替进行代码审查。回购维护者或所有者将审查代码,并将其合并到主分支,在我们的例子中是主分支。
将出现 Alec 的 pull 请求,这可以在下面的步骤中处理。
Alec :在 autos.py 文件中输入以下函数
def outliers_IQR(data, col):
lower_quartile = data[col].quantile(0.25)
upper_quartile = data[col].quantile(0.75)
IQR = upper_quartile - lower_quartile
outlier_thresh = 1.5 * IQR
return data[data[col].between((lower_quartile - outlier_thresh), (upper_quartile + outlier_thresh))]
完成上述步骤后,运行以下命令。
$ git add autos.py
$ git commit -m 'remove outliers based on IQR technique'
$ git pull
$ git push --set-upstream origin find-outliers
创建一个拉取请求:由于 Sofi 和 Alec 正在处理同一个文件,他们已经覆盖了彼此的代码,产生了合并冲突(如突出显示的)。
合并冲突
将出现 sofi 的拉取请求。因为存在合并冲突,所以需要在合并之前解决它。
要解决冲突,请单击上面突出显示的解决冲突,这将带您进入解决页面。
合并冲突指示器说明
编辑器具有以下合并冲突指示器:
<<<<<<< find-outliers
从这条指示线到下一条指示线显示当前分支上的代码=======
是原始行的结尾,随后的所有内容(直到下一个指示器)是正在合并的分支上的内容>>>>>>> master
是正在被合并的分支(在本例中是master
分支)的结束指示器
解决合并冲突
检查代码,修复冲突,删除合并冲突指示器,点击“已解决”,然后点击“提交合并”。
我会推荐你像 Pro:part 1****f一样阅读 Collaborate on GitHub 或者更好的理解这个练习。代码可以在 GitHub 库中找到。
要了解更多关于 GitHub 的信息,请点击这里。
参考文献
http://help.github.com/send-pull-requests/
无需 web 开发技能,就可在 R 生成的结果上进行协作
介绍 dstack,一种发布、跟踪和共享数据的工具
对于统计计算来说,r 是一种漂亮的编程语言。它支持一组扩展的库,这些库支持允许用户探索特定领域数据分析的统计算法。r 还提供了广泛的图形工具,允许用户构建丰富的动态可视化。出于这些原因以及更多原因,R 是统计学家、分析师和数据科学家的热门选择,尤其是在构建统计模型和仪表板的原型时。
然而,当涉及到与组织或客户的其余部分共享和协作结果时,R 用户仍然面临许多问题。为了让非技术用户参与到数据中来,许多用户依赖于使用本地网络驱动器或电子邮件来分享他们的结果的繁琐过程。即使有了 Shiny 之类的 R 包,用户仍然需要熟悉 CSS 主题、HTML 小部件和 JS 动作。此外,组织必须承担额外的成本来维护支持应用程序的后端基础设施,如果您不熟悉 r,这将更加繁琐。
dstack 提供的解决方案正是为了解决这些问题。在这篇博文中,我们将展示 R 的用户如何使用 dstack.ai 的特性在 R 生成的数据可视化和数据集的结果上进行协作
- 发布和共享数据可视化和数据集
- 跟踪已发布数据的修订
- 协作处理您发布的数据
入门指南
让我们从建立一个档案开始。这需要您在 https://dstack.ai. 创建一个帐户。一旦您有了帐户,您就可以登录并从设置中复制您的令牌。令牌和您的 dstack 用户名用于通过命令行实用程序配置您的配置文件。
您可以通过使用 install.packages()函数从 CRAN 访问 dstack 包。
install.packages("dstack")
一旦您安装了软件包,您应该配置您的配置文件。这可以通过包中的configure
函数来完成:
dstack::configure(user = "<USER>", token = "<TOKEN>", persist = "global")
现在可以使用数据堆栈库了。
与其他人共享您的交互式可视化和数据集
一旦您准备好代码,dstack 提供 API 来发布您的结果,这些结果可以方便地共享,也可以对每个修订进行跟踪。一般来说,你会
- 使用 dstack APIs 发布结果。
- 使用 dstack UI 分享结果。
这些 API 支持 R 中最流行的库,包括 tidyverse、ggplot2 和 Plotly。这些 API 也可以在任何地方使用——笔记本、脚本或应用程序。通过这种方式,您不需要将您的报告嵌入到 HTML 报告中以通过电子邮件共享,或者自己承担学习服务器端脚本的麻烦。
假设您有一个数据集,在这种情况下,是美国中西部各县的人口统计数据,您希望分析人口密度,并以数据可视化的形式与他人共享您的结果。
您可以在 docs.dstack.ai 了解更多关于使用其他可视化库的信息
注意,在这个例子中,您使用了 dstack 库中的三个方法。
- create_frame 定义一个值“中西部 _ 分析”
- 提交,它包含可视化数据所需的参数
- 按下,将可视化推至 dstack UI
可以通过 URL 访问发布的图表
[https://dstack.ai/<username>/](https://dstack.ai/riwaj/plotlyR)Midwest_analysis
请注意缩放、滚动等功能是如何巧妙实现的。也可以在可视化中使用
注意 URL 和函数 create _frame 都包含一个值“Midwest_analysis”,我们称之为堆栈。
本质上,
- 堆栈是一种独特的数据流,它可以有许多帧,但指向被推送到发布的最新帧。
- 框架是对已发布数据的修订,可以由一系列附件组成。
- 附件可以是绘图、图表或图形,甚至可以是具有自己的参数集的数据框。
现在,如果您还想与他人共享数据集,以实现刚刚共享的数据可视化,该怎么办呢?
堆栈、框架和附件等 dstack 抽象结构使您能够以发布数据可视化的相同方式提交数据集。
添加参数(View="Data ")允许您在同一堆栈中的数据集和可视化之间切换
这样,您可以在同一个堆栈中获得交互式数据集和可视化。
您可以在dstack.ai/riwaj/Midwest_analysis?a=1查看发布的堆栈
发布堆栈后,现在您可以使用 URL、用户名或通过电子邮件地址发送邀请,与您的同行和客户共享堆栈。
任何人都可以通过链接查看公共堆栈
使用其他人的数据集
设想一个场景,您希望使用由其他人托管在 dstack 上并可供您使用的数据集。在这种情况下,您有两种选择来获取数据集以使用它。
- 从 dstack UI 下载数据集作为 CSV 文件
- 使用 dstack API 将数据集作为数据框提取
登录 dstack web 应用程序,通过 dstack API 下载或获取数据集
作为一名 R 用户,您可能会发现简单地使用 dstack API 来获取数据集很方便。下面是一个使用 pull API 获取 dstack 上托管的数据集的代码片段。
跟踪结果的修订
现在这里有一个很酷的部分!可以使用 dstack web 应用程序上的一个按钮来获取已发布堆栈的每个修订版及其所有参数。通过这种方式,您可以获得您的堆栈在工作过程中如何发展的历史记录,而不管它是可视化还是数据集。
本质上,这就是它的工作方式。
- 使用 dstack APIs 将栈的每个新版本推送到同一个栈。
- 登录到 dstack web 应用程序,并转到您的堆栈的 URL 地址。
- 在堆栈名称的下方,例如 Midwest_analysis,您会看到小部件。
- 点击它可以找到数据集的所有版本,以及最新的一个,称为 Head。
每个修订历史由时间戳表示
协作处理您的结果
dstack 是为协作数据探索而构建的。
发布的数据集和可视化可以通过 URL 与其他人轻松共享,即,即使非技术用户也可以使用 web 浏览器在 dstack.ai 托管的前端应用程序上查看和访问发布的堆栈。发布不存在多租户问题,即多个并发用户可以在同一时间就您发布的报表进行交互和协作,而不需要修改代码。
评论功能可以让你参与讨论(想想脸书的 Instagram)。要添加注释,您必须登录到您的 dstack.ai 帐户,并拥有在 dstack 中发布数据集的人在堆栈上进行协作的权限。
在 dstack 中,共享和评论权限的管理方式如下。
- 每个用户都可以使用设置菜单来选择默认情况下是将一个新堆栈设为私有还是公共。
2.发布堆栈后,发布者可以选择共享堆栈的对象。或者,即使默认设置被选择为私有,堆栈也可以被公开。
您不需要 dstack 帐户来查看公共共享的堆栈,但是您需要一个帐户来进行注释
如果您登录 dstack,您将会看到自己创建的堆栈和其他人共享给您的堆栈。
数据堆栈帐户中堆栈的概述,包括自己创建的堆栈和他人共享的堆栈
所有的服务也可以从移动电话上获得,以方便地查看更新的堆栈。
立即尝试!
dstack.ai 可以在您的笔记本、脚本、工作甚至应用程序中使用,我们免费提供上述所有服务。
你认为我们错过了一些用例和特性吗?这是我们的产品路线图,您可以投票选出您希望在未来看到的功能。
https://trello.com/b/CJOnEjrr/public-roadmap
请注册并给我们反馈和建议。我们很想听听你的想法。
谢谢您们。
反馈调查:【https://forms.gle/6MSLAGaHJFvvpB5Q6
报名:【https://dstack.ai/auth/signup
了解更多 https://dstack.ai
文档: docs.dstack.ai
反馈邮件: team@dstack.ai
免责声明和限制:
- 数据集管理功能处于测试版,欢迎早期用户尝试。
- 除非法律要求,否则我们不会与第三方共享数据。
- 我们不强制检查数据的真实性和来源,而是依赖用户。如果您发现侵权案件,请向我们报告。
- 如果我们发现数据结果的共享损害了任何一方或违反了任何法律,我们将有义务立即删除这些数据。
- 您可以保护对数据的访问,例如,通过更改堆栈设置或更改帐户设置的默认值,将数据限制为选定的用户。
在 GitHub 上合作
数据科学家必须了解的工具
照片由 Richy Great 在 Unsplash 上拍摄
在的最后一个教程中,我们学习了 GitHub 的基础知识。在本教程中,所有这些基础知识将汇集在一起,我们将体验 GitHub 的真正力量,它来自于协作。请注意,在本教程中,我们将频繁使用像克隆,推,拉,分支,大师等词。因此,如果你对这些都不清楚,请先通读上一篇教程。
定义协作
要理解解决方案,重要的是理解问题。通读以下内容,理解 GitHub 可以派上用场的场景。
你是一名首席数据科学家,与一组初级数据科学家一起从事机器学习项目。由于您是项目所有者,因此您负责维护项目代码的“ 主”版本。
在您的团队中,每个数据科学家都在独立工作,以改进模型预测。因此,他们创建了自己的本地版本或主版本的备用分支。
让我们假设你已经对你的代码的""版本做了一些编辑***,并且你的团队中的一个成员拿出了他自己的编辑版本**,并且声称他已经极大地改进了模型预测。这个场景的视觉效果如下:*
示例场景(图片由作者提供)
你现在想更新" master "版本的代码,但是可能会出现一些冲突。下面举几个例子:
- 您对"**" master "**版本所做的编辑可能不在您的团队成员的分支版本中
- 与“ 【主】 代码相比,分支版本可能有一些不同的变量处理
这意味着简单地用代码的分支版本覆盖主代码可能不符合项目的最佳利益。为了解决这样的冲突,GitHub 派上了用场**
求解时间
我确信上面的场景一定让你意识到了眼前的问题。问题是,GitHub 将如何提供帮助?
重要的事情先来
在我们开始讨论解决方案之前,让我们先了解一些我们将在本教程中使用的基本术语:
- 合作者——被正式添加到项目存储库并被授予推送访问权限(修改存储库内容的访问权限)的开发人员被称为贡献者或合作者
- Fork — 在 GitHub 中 Forking 就像把别人的库复制到你的账户中。一般来说,当你想使用某个其他开发者创建的开源项目并且你不是贡献者时,你派生**它并获得对他们的库的访问权。**
- 分支 —通常开发者使用不同的分支来维护项目的不同模块。另一个允许使用分支的常见场景是当团队的多个成员想要处理同一段代码时。这时每个人都可以有自己的分支。默认情况下,每个新创建的存储库都有一个名为 主 分支的中央分支。
- 拉取请求——创建一个拉取请求,将一个分支与“主”分支合并。请求直接发送给项目所有者,他/她可以与分支贡献者一起接受/拒绝编辑。
情节
为了解决上面定义的问题,我们将介绍两个场景,您在 GitHub 上积极协作时会遇到这两个场景:
- 在第一个场景中,我们假设您想要对一个存储库(项目)做出贡献,而您没有被添加为贡献者。在这个场景中,我们将假设在您分叉了项目之后,没有对主分支进行任何编辑(在上面显示的示例场景图中,版本 2 和 3 的黄色框不存在)。****
- 第二个场景假设您是项目组的一部分,并且作为贡献者被添加到项目存储库中。在这个场景中,我们将假设在您创建了自己的分支之后,对“主”分支进行了编辑(在上面显示的示例场景图中,版本 2 和 3 的黄色框存在**)。**
让我们来看看上述场景的工作流程。
情景 1 —不是贡献者
当你不是一个库的贡献者时,你不被允许从你的本地系统推送编辑到 GitHub。在这种情况下进行协作的工作流程步骤如下:
- 派生存储库— 因为我们不是存储库的合作者,我们将首先派生存储库。要派生存储库,请登录您的帐户并搜索您感兴趣的存储库。进入资源库 GitHub 页面,点击 叉按钮 ,如下图所示:
分叉(作者图片)
在上面的 4 张截图中,我们正在搜索资源库** (D2WAP/Test)。我们转到存储库页面,并按下右上角的叉按钮。分叉过程发生了,我们的账户中的库被分叉。**
- 克隆存储库— 完成后,您可以克隆分叉的存储库,使其内容在您的系统上可用。这一过程在上一个教程中有解释。由于分叉库是你的帐户的一部分,你将有推送权限,你可以将你的编辑推送到分叉库。请注意,在这种情况下,克隆应该在分叉之后完成,因为如果在分叉之前完成,您的本地克隆库将指向其他开发者的帐户,在那里您将没有推送访问权限。
- 修改代码,提交并推送 —下一步是编辑克隆库中的代码,提交更改,和将它们推送到您的分叉库。假设你有一个分支,你可以直接将编辑推送到“主”分支或者也可以创建一个新分支。建议我们只在新的分支中进行编辑,但是为了简化这个场景,我们将编辑直接推送到“ 主 ”分支。我们将在场景 2 中查看新分支的创建。为了演示这个过程,我编辑了分叉库的 read me 文件 。从下面的截图可以看出分叉的存储库和原始存储库之间的区别:
编辑自述文件(图片由作者提供)
- 创建新的拉取请求— 现在您已经对代码进行了必要的编辑( read me file 在我们的例子中),是时候创建一个拉取请求了。**点击拉动请求选项**,进入拉动请求屏幕。在屏幕右上方点击 新拉取请求。**
创建新的拉取请求(作者图片)
- 选择基地和头库 —点击 新拉取请求 ,将进入选择基地和头库以及对应分支的页面。将 base 视为目的存储库,将 head 视为分叉存储库。由于我们已经直接对分叉存储库的“”主分支进行了编辑,因此对于头分支和基础分支都选择“”。一旦做出选择,GitHub 将向您展示您试图合并的两个版本之间的比较。再次点击 创建拉式请求。****
选择源和目标存储库(按作者排列的图片)
- 添加注释 —一旦您点击了“ 创建拉式请求 ,您将到达注释页面,在这里您可以为源代码库开发人员添加适当的注释。再次**点击创建拉取请求**,你的拉取请求将被发送给源开发者。注意来自 GitHub 的消息说没有冲突。这验证了我们的假设,即在我们分叉存储库之后,没有在源代码中进行任何编辑。**
评论部分(作者图片)
- 按作者合并 —一旦您提交了拉请求,作者就会收到,如果没有冲突,他/她可以立即批准。要合并,作者将转到“拉请求”选项卡,并单击“ 合并拉请求”。就这样,您已经成功地对源存储库做出了贡献
合并审批流程(作者图片)
场景 2 —你是一名贡献者
因为在这个场景中,我们假设您被存储库所有者添加为贡献者,所以您将拥有将编辑内容直接推送到源存储库的访问权限。基于这一假设,我们来看一下工作流程:
- 克隆——因为你现在可以直接将编辑推送到主存储库,所以不需要分叉。继续克隆存储库。这个过程在上一个教程中有解释
- 源文件被编辑 —参考下面的截图,查看对源文件和分支文件的编辑。出于演示目的,我们正在修改 自述文件 。
编辑自述文件(图片由作者提供)
- 拖拽&放下 —假设你已经做了必要的编辑,你可以到 GitHub 上的原始存储库页面,拖拽&放下页面上编辑过的文件。添加截图供您参考:
拖放(作者图片)
- 创建新分支 —一旦您将编辑过的文件放到存储库页面上,您将获得直接编辑“ 主 ”分支或创建新分支的选项。在这个场景中,我们将按照推荐的方法创建一个新的分支。当相应的单选按钮将被选中时,GitHub 将要求您命名分支。一旦命名,点击 提出修改 。每当你想备份或版本控制你的工作,你可以做这一步。只要确保如果您在生成 pull 请求之前继续对编辑进行版本控制(在下一步中解释),您是在同一个分支上进行的。截图补充如下,供大家参考:
创建新分支(作者图片)
- 创建新的拉式请求——一旦您提出了变更,您就可以像场景 1 中解释的那样创建一个拉式请求。请注意,因为我们已经直接对源存储库进行了编辑,所以您不需要选择基本存储库和主存储库,而只需要选择要合并的分支。此外,由于这两个分支在合并时被并行编辑,GitHub 引发了冲突。添加截图供您参考:
有冲突的拉取请求(图片由作者提供)
- 解决冲突 —这是存储库所有者和分支协作者可以进行讨论并一起解决冲突的地方。在 GitHub 上,这可以通过点击“ 解决冲突 来完成,并且可以由存储库所有者或分支所有者发起。在下面的截图中,请注意导致冲突的编辑。哪些编辑要保留,哪些要拒绝,可以通过相互讨论来解决。编辑完成后,点击屏幕右上角的标记为已解决**。添加截图以供参考:**
解决冲突(作者图片)
- 合并拉取请求 —冲突解决后,您将进入拉取请求屏幕,冲突消息将被合并拉取请求所取代。点击" 【合并拉取请求】 ,然后点击" 【确认合并 】以及任何想要记录的信息。就这样,你的编辑被合并到“ 主 ”分支中。添加截图供您参考:
合并拉取请求(作者图片)
- 重新检查"主"分支-一旦合并,您将看到""分支随着分支的编辑而更新。**
结束语
git & GitHub 还有很多其他相关的功能,但那是以后的事了。
有了这些知识,与你的项目团队合作,把版本控制的烦恼留给 GitHub。希望这篇教程对你有所帮助,并且你学到了一些新的东西。
会在以后的教程中尝试并带来更多有趣的话题。
快乐学习!!!
协作将释放人工智能的商业价值
对于人工智能来说,协作就是今天,相当于 20 世纪 60 年代的计算能力
1990 年,经济学家保罗·大卫在他的文章《美国经济评论》中分享了-
由于充分利用技术需要补充投资,生产率的提高需要很长时间。~保罗·大卫
对于我们这个世纪的技术机遇——人工智能(AI),他的见解在今天同样真实。为了从人工智能驱动的创新中为社会和商业带来最大利益,开发必要的补充是至关重要的。这些补充之一是在数据上的合作,甚至是竞争对手之间的合作。
竞争格局已经彻底改变。
对数据的竞争非常激烈,因为它是推动机器学习和人工智能增长的原材料。电信运营商不再仅仅与其他此类运营商竞争。它与谷歌和脸书等公司争夺消费者数据;它与零售业竞争消费者在哪里购物等数据。大家都是做数据生意的,我们都是竞争对手。然而,在这场积累和分析越来越多数据的竞赛中,数据越多就越好吗?我认为并非如此。数据的边际收益递减。更多的数据不一定会转化为新的信息。相反,它有时可能会掩盖信息,或者只是用来证实现有的偏见。那么,我们到哪里去寻找更好的、更新鲜的、令人惊讶的见解呢?
跨行业洞察是下一个前沿。
关键是要超越行业孤岛,寻找新的数据和见解。毕竟我们都在为同一个客户服务。我有一次在多伦多参加年度机器学习会议。我在寻找与其他行业组织的潜在合作伙伴,提议我们将他们来自电信行业以外的数据集与我们的移动使用数据集相结合,共同执行高级分析,跨越我们的行业孤岛。出乎意料的是,我发现自己在和著名的物理学家和作家杰弗里·韦斯特教授交谈。就在他的主题演讲前,我无意中提到他的弦理论背景,“通常,解决方案都在学科的交叉点上,不是吗?”他温和地纠正了我——“解决方案总是跨学科的。”
解决方案总是跨学科的。~杰弗里·韦斯特
合作的三大支柱
在实践中实现这种合作需要三大支柱——数据评估、隐私机制和长期思考。
估值
在我工作的过程中,我对一个框架进行了广泛的调查,这个框架可以让组织评估他们的数据集值多少钱?然而,在大多数情况下,这种方法是启发式的。那么,组织如何评估与第三方共享的数据的价值呢?例如,开发预测客户流失的机器学习模型的人工智能初创公司仍然必须在专有数据上训练他们的算法。数据在特定环境中的价值直接影响到这些第三方合作的性质,包括从供应商关系到合资企业的所有形式。在没有这种模型的情况下,组织只能模糊地了解哪些数据集可能最有价值。从商业角度来看,高度受限的数据集并不总是最有用的。
隐私
即使我们可以对数据进行价值评估,为跨行业分析而共享这些数据的实际挑战依然存在。这方面的大部分工作来自法律学科。然而,我更感兴趣的是探索隐私背后的经济理论,以及允许在数据共享中保护隐私的模型。有必要探讨一些问题,如隐私是否是一项普遍权利,以及是否所有人口统计数据都同样重视隐私。例如,哈佛大学伯克曼·克莱恩中心研究员 Velislava Hillman 关于嵌入式人工智能的观察将学生从他们热爱的职业推向他们擅长的职业。
允许这种共享的隐私模型是需要的——诸如差分隐私和加密方法(私有集合交集、分散分析)的方法。以统计和加密方法为补充的隐私法律框架将允许在跨组织共享数据时保护隐私。有时,当数据不共享时,这些是必要的,但仍然要以分散的方式进行分析。
长期思考
除了在那些以数据为主要收入来源的科技巨头中,该行业的其他公司都过度青睐那些能直接提高盈利能力或节省成本的模型或方法。因此,大多数公司最终只使用最基本和最明显的模型。由于这些也很容易被业内其他人获得,它们无论如何都没有提供什么竞争优势。然而,如果这种与商业目标的联系需要一点点信心,决策者往往会回避。这种商业决策的传统视角不适合推动先进机器学习和人工智能的长期发展,即使这些发展将为行业带来巨大利润。我们不仅要跳出框框思考,还要超越我们有限的时间范围。
简而言之,每个公司都必须认识到数据是一种战略资产。在这个独特的竞争环境中,与和我们有共同道德观的人合作,将会比传统的竞争带来更大的收益。系统地评估这一资产,确保其安全性和质量,并超越短期目标,将推动必要的合作,以释放我们这个世纪的技术——人工智能——的全部价值。不这样做很可能会把我们带回 20 世纪 60 年代,当时缺乏必要的补充,廉价的计算能力使人工智能创新陷入停滞。
利用 dstack.ai 探索新冠肺炎对空气质量的影响
来源https://unsplash.com/photos/3LsocYqXWpM
作为一名被禁闭的数据科学家,我决定花一些时间进行数据探索和尝试新事物。我想知道格里塔·图恩伯格和其他人是否会感谢冠状病毒通过让人们呆在家里来清洁我们的空气。
我想做得又快又脏,看看实际的趋势,并轻松地与人们分享。以下是我得到的信息:
https://dstack . ai/oti pita/d/2710328 b-393 a-456 a-907 a-0595761 af 188
一开始有两个问题——用什么数据来评估空气状况,用什么工具来可视化。大家来翻翻我的回答和整体开发流程。
数据收集
我一直在寻找有关空气状况的“实时”信息,以便以一种良好的格式轻松获取数据,几乎可以随时进行分析。世界上有十几个数据库,每个国家都有不同的信息,但大多数数据库获取和整合数据的时间都有很大的延迟。通常情况下,他们会在第二年的第一季度发布上一年的信息,这不是我想要的。所以当我发现 https://waqi.info/的时候我很开心。该网站有许多国家的信息,这些信息一天更新几次,涵盖广泛的指标。尽管他们有一个可用的 API,但也发布了为可能的新冠肺炎分析提取的历史数据。一个只需要电子邮件验证,就可以获得从 2015 年到目前为止 22 个指标的国家每日数据。虽然少数国家报告了一些指标,但几乎所有国家都有 10 项指标。我们列出了一氧化碳、露水、二氧化氮、臭氧、PM10、PM25、二氧化硫的测量指标,并删除了温度、湿度和压力等其他指标。
技术堆栈
我通常使用 Python、Excel、Power BI 或 Tableau 进行数据可视化。在这个分析中,我选择了 Python,因为我想要一个完全开放的堆栈。所以我用 pandas 进行数据收集和处理,Plotly 进行可视化。
分析数据后的最后步骤是:
- 将我的所有视觉效果合并到一个仪表板中
- 在线发布仪表板并共享它
- 组织反馈以进一步改进仪表板
我想知道如何又快又容易地做这件事。最近,我了解到一个新工具可以如何帮助我的视觉效果组合、部署、共享和进一步协作。我决定试一试。
发展
dstack.ai 仪表板由两部分组成:滤镜面板和视觉效果(堆栈)。数据预处理和转换见 Jupyter 笔记本。
我们可以将数据按国家分组,以检查 2019 年 1-5 月、2020 年 1-5 月的中值指标衡量,以及这两个时期的实际差异。所以我从 2020 年和 2019 年的 NO2 差异图开始绘制。
2020 年 1 月至 5 月空气中二氧化氮日均值与 2019 年的差异
def map_plot(data, kpi, year, title):
data = data[(data["Specie"]==kpi)]
fig = px.choropleth(data, locations="Country3",
color=year,
hover_name="CountryName",
color_continuous_scale=px.colors.diverging.Geyser)
return figfig = map_plot(data_grouped, 'o3', 'difference', 'World map')
fig.show()
一旦我绘制出了想要的可视化效果,dstack.ai 的使用比 GitHub 更容易。为了将可视化发布到 dstack 前端,它提供了三种方法,即创建-提交-推送。
# Creation of map stack
frame = create_frame("world_map")for kpi in kpis:
for year in ['median2020', 'median2019', 'difference']:
frame.commit(map_plot(data_grouped, kpi, year, 'Air Indicator Map'), f"World map colored by {kpi}", {"Air Indicator": kpi, "Measure": year})frame.push()
另一种观察空气质量的方法是在雷达图上一次标出特定国家的所有指标。我第一次尝试是在中国。2020 年与 2019 年相比没有太大变化,除了 PM25 和 PM10 指标。
def radar_plot(data, country):
data = data[(data["CountryName"]==country)]
fig = px.line_polar(data, r="median", theta="Specie",
color="Year", line_close=True,
hover_name="CountryName",
color_discrete_sequence=["#3deb34","#eb4034"])
return figfig = radar_plot(data_grouped_time, 'China')
fig.show()
要创建带有国家参数的堆栈,我们需要重复帧创建-提交-推送操作:
# Creation of radar stack
frame = create_frame("radar_chart")for country in data_grouped_time['CountryName'].sort_values().unique():
frame.commit(radar_plot(data_grouped_time, country),
f"Air quality measure for {country}", {"Country": country})frame.push()
我还创建了一个折线图来查看 2020 年与 2019 年的每日动态,以及一个条形图,显示指标下降的主要国家。你可以在 GitHub 查看完整代码。
用 dstack 将视觉效果组合成一个仪表板非常容易。您只需选择要添加到仪表板中的堆栈,对它们重新排序,然后选择所需的布局/标题。瞧,动态仪表板几分钟后就准备好了。
对我来说,最大的惊喜是在单个可视化上设置的参数/过滤器会在需要时自动组合(没有重复)。此外,一旦我在单个堆栈中做了一些更改,它们就会随着最新的更新出现在仪表盘上。此外,每个堆栈可以最大化为全屏视图。
在协作特性方面,我发现任何被允许在 dstack 前端查看图表的人都可以留下他们对图表的反馈。我喜欢这种直观的协作方式。我必须说,现在没有太多花哨的功能,但它非常适合我的需要,并以一种方便的方式加快了我“准备就绪”的时间,以获取其他人的想法。
结果
经过几个小时的工作,我能够与我的朋友和同事分享我的仪表板,并开始探索仪表板。有一些有趣的发现,肯定需要进一步探索,以了解原因。
与 2019 年相比,除沙特阿拉伯和伊朗外,大多数国家 2020 年 1 月至 5 月的所有指标都略有下降。
一些国家如丹麦、瑞典、挪威、斯洛伐克在减少空气中二氧化硫和二氧化氮方面名列前茅,没有在疫情期间引入严格的封锁。
查看你所在的国家的空气状况,保持健康,并通过 dstack.ai 轻松分享可视化效果。
Pyspark 中的协同过滤
入门
基于交替最小二乘(ALS)算法的协同过滤及其在 Pyspark 中的实现
你有没有想过 Spotify 是如何每周在“发现周刊”上发布一个歌曲列表,而你最终因为喜欢这些歌曲而将其中一些添加到你的播放列表中的?因为你昨天看了一个特别的节目,网飞推荐给你的那些节目怎么样?这些科技巨头怎么这么聪明?答案是推荐系统。
推荐系统基于用户的历史行为,如观看、搜索或购买历史,进行预测。推荐系统的两种常见方法是基于内容的 和协同过滤,本文将深入探讨后者。
什么是协同过滤?
协作过滤是一种数学方法,用于根据其他相似用户的评级来预测用户如何对特定项目进行评级。典型的协同过滤包括 4 个不同的阶段:
- 数据收集—收集用户行为和相关数据项
- 数据处理—处理收集的数据
- 建议计算—根据处理的数据计算推荐
- 结果推导-提取相似性并返回前 N 个结果
显性和隐性反馈
那么,在协同过滤的第一阶段,收集的是什么类型的数据呢?有两种不同类别的数据(称为反馈),可以是显性或隐性。
显式反馈的一个例子是用户给出的评级,网飞收集这些评级是为了在客户对他们观看的电影进行评级后向他们提供建议。隐式反馈不那么直接,因为它基于用户与平台的互动,包括点击、观看、喜欢和购买。Spotify 利用隐式反馈来实现它的推荐系统。
计算相似度
一旦收集和处理了数据,就需要一些数学公式来进行相似性计算。两种最常见的方法是:
- 欧几里德距离——两个用户之间偏好的距离。如果距离小,则两个用户之间的相似性高
- 皮尔逊相关-如果两个用户之间的余弦值(入射角)一致,则两个用户之间的相似性很高
作者图片—余弦和欧几里德距离向量空间
Pyspark 中的实现
库包 spark.ml 目前支持基于模型的协同过滤,其中用户和产品由一小组潜在因素描述,这些因素可用于进行预测。它使用交替最小二乘(ALS)算法来学习这些潜在因素。
我们将使用来自 https://www.last.fm/api/的数据集,其中包含 3 个文件:
- user_artist_data.txt 3 列:userid artistid playcount
- artistid artist_name
- artist_alias.txt 2 列:badid,goodid[已知拼写错误的艺术家和正确的艺术家 id]
首先,我们用下面的代码设置 Spark。
# import librariesfrom pyspark import SparkContext
from pyspark.ml.recommendation import ALS
from pyspark.sql import SparkSession ,RowappName="Collaborative Filtering with PySpark"
# initialize the spark session
spark = SparkSession.builder.appName(appName).getOrCreate()
# get sparkcontext from the sparksession
sc = spark.sparkContext
然后,我们定义数据结构并将弹性分布式数据帧转换成数据帧。
from pyspark.sql.types import StructType,StructField,IntegerType,StringType,LongType
from pyspark.sql.functions import col#Define the schema for the datasets
schema_artist = StructType([StructField("artistId",StringType(),True),StructField("artistName",StringType(),True)])schema_user_artist = StructType([StructField("userId",StringType(),True),StructField("artistId",StringType(),True),StructField("playCount",StringType(),True)])schema_alias = StructType([StructField("badId",StringType(),True),StructField("goodId",StringType(),True)])#Convert RDDs into Dataframes
artistRDD = rawArtistData.map(lambda k: k.split("\t"))artist_df = spark.createDataFrame(artistRDD,schema_artist,['artistId','artistName'])userArtistRDD = rawUserArtistData.map(lambda k: k.split())user_artist_df = spark.createDataFrame(userArtistRDD,['userId','artistId','playCount'])aliasRDD = rawArtistAlias.map(lambda k: k.split())alias_df = spark.createDataFrame(aliasRDD,['badId', 'goodId'])#First for convenience, we can create aliases for each dataframes
ua = user_artist_df.alias('ua')
ub = artist_df.alias('ub')
一旦数据集被处理,我们可以继续训练我们的 ALS 模型。在此之前,我们应该将数据集分成训练和测试数据,这样我们就可以知道我们的模型执行得有多好。
# dataset split into training and testing set
(training, test) = ua.randomSplit([0.8, 0.2])# training the model
als = ALS(maxIter=5, implicitPrefs=True,userCol="userId", itemCol="artistId", ratingCol="playCount",coldStartStrategy="drop")
model = als.fit(training)# predict using the testing datatset
predictions = model.transform(test)
predictions.show()
作者图片—测试预测的 Pyspark 输出
我们可以尝试使用该模型来找到为每个用户推荐的顶级艺术家。我们可以使用 ALS 模型中的recommended for allusers函数来获取每个用户的首选推荐列表。
下面的函数将 userId 和 limit 作为输入。对于给定的用户 Id ,它获得当前最受欢迎艺术家的列表(基于播放计数)。让我们尝试为用户(2062243)显示最喜欢的艺术家。
def currentLikes(ua,ub,userId,limit):
df = ua.join(ub,ua.artistId==ub.artistId)\
.filter(ua.userId==userId)\
.sort(ua.playCount.desc())\
.select(ua.userId,ua.playCount,ub.artistName)\
.limit(limit)
return df# display top 10 liked artists for user 2062243
currentLikes(ua,ub,2062243,10).show(truncate=False)
按作者分类的图片 Pyspark 为用户 2062243 输出的最受欢迎的艺术家
然后,下面的函数使用该模型为每个用户给出艺术家的最佳推荐。我们试着为同一个用户(2062243)显示推荐的艺术家。
def recommendedArtists(userId,limit):
test = model.recommendForAllUsers(limit).filter(col('userId')==userId).select("recommendations").collect()
topArtists = []
for item in test[0][0]:
topArtists.append(item.artistId)
schema = StructType([StructField("artistId",IntegerType(),True)])
artists = spark.createDataFrame(topArtists,IntegerType())
final=artists.join(ub,artists.value==ub.artistId).select(ub.artistId,ub.artistName)
return final# display top 10 recommended artists for user 2062243
recommendedArtists(2062243,10).show(truncate=False)
按作者分类的图片-为用户 2062243 推荐的艺术家的 Pyspark 输出
摘要
在这篇文章中,我们介绍了什么是协同过滤,以及它的 4 个不同阶段。协同过滤收集的两类数据,主要是隐式和显式反馈,使用欧氏距离或皮尔逊系数计算相似度。最后,简要介绍了使用 spark 中内置的交替最小二乘(ALS)算法在 Pyspark 中实现协同过滤的过程。希望你们对推荐系统的工作原理有一个简单的了解,下次在网上冲浪和使用 Spotify/Amazon 时,看到好的推荐,不要感到惊讶,干杯!
Pytorch 中的协同过滤
构建用于电影推荐的嵌入神经网络
协同过滤是公司越来越多地使用的工具。网飞用它来推荐节目给你看。脸书用它来推荐你应该和谁交朋友。 Spotify 用它来推荐播放列表和歌曲。它在向顾客推荐产品时非常有用。
在这篇文章中,我构建了一个嵌入的协同过滤神经网络来理解用户对某些电影的感受。由此可以推荐电影给他们看。
数据集取自此处的。这段代码大致基于 fastai 笔记本。
首先,让我们去掉烦人的复杂用户 id。我们可以用普通的旧整数来凑合。它们更容易处理。
import pandas as pd
ratings = pd.read_csv('ratings.csv')
movies = pd.read_csv('movies.csv')
然后我们将对电影 id 做同样的事情。
u_uniq = ratings.userId.unique()
user2idx = {o:i for i,o in enumerate(u_uniq)}
ratings.userId = ratings.userId.apply(lambda x: user2idx[x])
我们需要获得用户数量和电影数量。
n_users=int(ratings.userId.nunique())
n_movies=int(ratings.movieId.nunique())
首先,让我们创建一些随机权重。我们需要打电话。这允许我们避免显式调用基类。这使得代码更易于维护。
这些权重将在 0 和 0.05 之间均匀分布。uniform_
末尾的_
操作符表示在位操作。
接下来,我们添加我们的嵌入矩阵和潜在因素。
我们正在为我们的用户 id 和电影 id 创建一个嵌入矩阵。嵌入基本上是一种数组查找。当我们将我们的一次性编码用户 id 乘以我们的权重时,大多数计算都取消了0
(0 * number = 0)
。我们只剩下权重矩阵中的某一行。这基本上就是一个数组查找。
所以我们不需要矩阵乘法,也不需要独热编码数组。相反,我们可以只做一个数组查找。这减少了内存使用并加速了神经网络。它还揭示了分类变量的内在属性。这个想法在最近的一次 Kaggle 比赛中得到了应用获得了第三名。
这些嵌入矩阵的大小将由 n 个因子决定。这些因素决定了数据集中潜在因素的数量。
潜在因素在我们的网络中非常有用。它们减少了对特征工程的需求。比如User_id
554
喜欢Tom cruise``Tom cruise
出现在一部电影里。用户554
可能会喜欢这部电影。出现在电影中会是一个潜在的特征。我们在培训前没有具体说明。它就这么出现了。我们很高兴它做到了。
最后,我们需要添加我们的forward
函数。
正如这个类的名字所暗示的,我们正在做嵌入矩阵的点积。
给我们一个用户和电影的小批量。我们只看嵌入的分类变量。conts
指连续变量。
这个小批量大小将由您设置的批量大小决定。根据这篇文章,大批量实际上会损害模型的质量。但是根据这篇论文,大批量增加了模型的质量。目前还没有达成共识。许多人都在报道矛盾的结果。所以你可以随意选择批量大小进行实验。
从这个迷你批处理中,我们想要在我们的嵌入矩阵中进行数组查找。
允许我们进行数组查找。这种查找比一位热码编码矩阵和加权矩阵矩阵乘法计算量小。
(u*m).sum(1).view(-1, 1)
是用户和电影嵌入的叉积,返回一个数字。这是那部电影的预测分级。
接下来,我们需要创建一个ColumnarModelData
对象
那我就设置一个乐观器。对此我将使用随机梯度下降法。optim.SGD
实现随机梯度下降。随机梯度下降在计算上不如梯度下降密集。这是因为当选择数据点计算导数时,我们引入了随机性。
我们也可以使用optim.Adam
。实现 rmsprop 和动量。反过来,这导致了自适应的学习速率。但是这篇论文表明从 SGD 得到的解比从 Adam 得到的解更一般化。另外,反正训练也不需要那么长时间,所以 SGD 也不是个坏选择。
然后我们适合一个3
时代。
fit(model, data, 3, opt, F.mse_loss)
MSE 损失就是简单的均方误差损失。这是自动计算的。
Fastai 在幕后自动创建一个神经网络。您可以调用一个[collab_learner](https://docs.fast.ai/collab.html#collab_learner)
,它会自动创建一个用于协同过滤的神经网络。Fastai 还可以通过这个协作学习器引入偏差和辍学。
偏见是很有用的。我们需要找到用户偏见和电影偏见。用户偏见可以解释那些对每部电影都给予高评价的人。电影偏见可以解释那些倾向于给某类电影高评级的人。Fastai 自动添加偏差。
使用 fastai,我们可以轻松创建协作学习者:
偏见是很有用的。我们需要找到用户偏见和电影偏见。用户偏见可以解释那些对每部电影都给予高评价的人。电影偏见可以解释那些倾向于给某类电影高评级的人。Fastai 自动添加偏差。
有趣的是,fastai 指出你应该稍微增加y_range
。 sigmoid 函数用于确保最终输出在y_range
中指定的数字之间。问题是一个 sigmoid 函数似乎。所以我们需要稍微增加我们的y_range
。Fastai 建议增加0.5
。
图片来自 ResearchGate
作者图片
我这里用的是建议的学习率,有少量的重量衰减。这是我发现非常有效的组合。
作者图片
我们可以多训练一些
作者图片
作者图片
我们终于得到了一个0.784105
的 MSE。但这是一段非常颠簸的旅程。我们的损失上下波动很大。也就是说0.784105
实际上比 LibRec 系统的协同过滤得分更高。他们得到了 MSE。
它实际上也比 fastai 在他们的协作过滤课程中创建的模型略好。他们越来越小。
丰富
- 我们可以通过发送一个名为
emb_szs
的字典来调整嵌入的大小。这可能是一个需要调整的有用参数。 - 基于内容的推荐。协同过滤只是建立推荐系统的一种方法。其他方法可能更有用。基于内容的系统是我一直铭记在心的。它可以查看演员、工作人员、流派和导演等元数据来做出推荐。我认为某种混合解决方案将是最佳的。这将结合基于内容的推荐系统和协作过滤系统。
- 协同过滤在很大程度上被冷启动问题所破坏。为了克服这个问题,我们可能会查看用户元数据。例如,我们可以查看诸如:性别、年龄、城市、他们访问网站的时间等。只是他们在报名表上输入的所有内容。在这些数据的基础上建立一个模型可能会很棘手,但是如果效果好的话,它可能会很有用。
原载于 2020 年 7 月 12 日https://spiyer 99 . github . io。
基于 fastai2 的动漫数据集协同过滤
去看或去看什么
这篇文章旨在描述什么是协同过滤(在整篇文章中简称为 CF ),并随后阐述如何使用 fastai2 构建一个模型来执行这项任务。本帖涵盖的主题如下
- 简介
- CF 背后的基本直觉
- CF in fastai2
-嵌入点偏差模型
-神经网络模型 - 模型解读&提出建议
- 参考文献
单击主题,导航到相应的部分。
查尔斯·德鲁维奥在 Unsplash 上拍摄的照片
介绍
在当今世界,数据就是石油,利用数据的一种方式是为个人执行建议/推荐任务。在这个快节奏的世界里,内容以惊人的速度被创造出来,观众喜欢看到与他们以前看过的内容相似的内容。
为了做到这一点,选择,喜欢,口味等。以评级或分数的形式记录用户,通常限定在一个有限的范围内(最常见的是 0-5 或 0-10),其中 0 表示用户非常不喜欢该内容,5 或 10 表示用户认为该内容非常有趣并符合他的喜好。
使用这些数据来找出下一步向用户建议什么是协同过滤的全部内容。代替用户动画或用户电影的可以是任何东西,比如消费产品或用户新闻文章或用户社交媒体帖子等等。
从用户那里获得的反馈越多,建议就变得越相关,因为算法能够更好地理解个人的口味。
有几种方法来执行协同过滤,今天,我们将讨论其中的两种。我们将使用 fastai2 ,这是一个由西尔万·古格和杰瑞米·霍华德构建的库,这是一个基于 PyTorch 构建的令人敬畏的界面,用于执行深度学习实验。所以,事不宜迟,我们先从理解 CF 背后的直觉开始。
协同过滤背后的基本直觉
为了执行协同过滤,用户/订户/消费者和项目/物品/产品都被表示为矩阵。(这里的术语是特定于应用程序的,但是因为我们处理的是动画数据,所以我们将分别把用户称为查看者,把项目称为动画。)
更准确地说,每个用户都被表示为一个数值向量,每个动画也是如此。这些值由算法学习以最小化损失函数,该损失函数通常是均方误差损失(MSE)。
为用户和动画向量学习的值对应于抽象的 n 维空间,实际上没有人类解释的意义。但是为了理解到底发生了什么,我们可以这样想。考虑我们正在处理的数据集,即观众-动画数据集。
罗曼·杰尼申科在 Unsplash 上拍摄的照片
假设每部动漫都由 5 个部分组成——爱情、喜剧、生活片段、后宫和动作。那么动画可以在 5 维的向量空间中表示,每个维度是上述维度之一。
在那个五维世界里,Oregairu 和 Hyouka 会离得更近,而东京食尸鬼会离他们相对远一些。因此,这种方法创建了一个 n 维空间,其中所有具有相似组件的动画将比具有不同组件的动画更接近地分组。
现在,想想观众。另一方面,观众向量将表示每个维度中用户所重视的部分。假设用户是浪漫和生活切片的粉丝,那么该用户的向量表示将沿着那些维度具有高数值,并且沿着剩余维度具有较小的数值。
为了整合来自观众和动画的信息,我们求助于使用点积,这是沿着各自的向量维度的简单乘法,然后是聚合。让我用上面我们挑剔的这三部动漫的例子来解释一下。
图片由 Vinayak 提供
这些列表示动画的名称,并且它们中的每一个都被表示为一个 5 维向量,每个分量/维度表示一个特定的类型,如上所示。
正如我们所看到的,Hyouka 和 Oregairu 在所有维度上都有相似的值,而东京食尸鬼在所有维度上都有非常不同的值。
图片由 Vinayak 提供
观众 1 更喜欢动作和生活片段,而不是其他部分,所以,让我们计算观众 1 与所有三部动画的点积。我将在下面手动演示一次计算,您可以类似地计算其他点积。
图片由 Vinayak 提供
我们取两个向量 Oregairu 和观众 1,并将各自的分量相乘,如上面的快照中所示,即,将 Oregairu 的浪漫维度与观众 1 的浪漫维度相乘,将 Oregairu 的喜剧维度与观众 1 的喜剧维度相乘,等等。最后,通过求和将这些乘积聚合成一个值。
一旦我们对所有三部动画都这样做,我们观察到观众 1 的点积分别是 29.2、26 和 31.8。这意味着观众 1 最喜欢东京食尸鬼,这确实是高行动。
另一方面,观众 2 喜欢浪漫和后宫。他和这三部动漫的点积分别是 47.5,35.5,22.5,这意味着他最喜欢《俄勒冈》这部青少年爱情喜剧!由纪之下,汤滨,伊希基,甚至他的老师静香,似乎都对八幡很感兴趣;你敢告诉我你在这部动漫里忽略了后宫…
在宅男话题之后,回到手头的主题,我们可以看到如何将观众和动漫表示为一个向量,这可以证明有助于确定观众对所有动漫的喜欢程度或哪些用户会喜欢特定的动漫,这是网飞等流媒体公司正在利用的非常有价值的洞察力。
对于观众和动画载体来说,还有一个额外的因素叫做偏见。它是一个量,用来分别表示特定用户或特定动漫的唯一信息。因此,如果有一个用户平均给所有动漫都打了高分,或者有一部动漫是所有/大多数观众最喜欢的,而不管他们通常的口味如何,这样的信息就被称为偏见。所以,每一个观众和每一部动画都用一个 n 维向量和一个偏差项来表示。
fastai2 中的协同过滤
fastai2 提供了一个包含 CF 可以利用的函数的子包fastai.collab
,在你的系统上安装 fastai2 之后(这里的指令,你可以按照下面的步骤进行操作。
图片由 Vinayak 提供
大多数情况下,数据是以这种方式存储或表示的。虽然这不是一种非常直观的方式,但它是一种非常有效的存储数据的方式。这是因为大部分观众没看过大部分动漫。
在这种情况下,如果我们试图将其存储为观众 v/s 动画的矩阵,将会有很多零。这样的矩阵称为稀疏矩阵。也有有效的方法来存储这样的矩阵,但是我们暂时让它过去。让我们现在专注于手头的任务。
这里的-1 代表用户看过动漫但没有评价。这是一个常见的场景,主要是因为在现实中,那些看动画的人并不一定会给动画评分。有数据总是比估算好,但是因为我们现在没有数据,我们可以删除有这种评级的行或者估算相同的值。有两种方法可以进行插补:
- 用用户的平均评分估算评分。
- 用动漫的平均评分来估算评分。
两者都有不同的解读。当我们根据一个用户的平均评分进行估算时,我们没有注意到该动漫与特定用户看过的其他动漫相比的相对特征,同样,当我们根据该动漫的平均评分进行估算时,我们忽略了该用户相对于其他用户的相对评分。这可能会在我们的观察中引入轻微的偏差,但我们会接受,因为评级有回归均值的趋势。如果我们选择忽略这些条目,我们最终会丢弃大量对分析有害的数据。
我们将选择估算动漫的平均评分,而不是观众,因为我们已经在 anime.csv 文件中获得了每部动漫的平均评分。这是收视率的最终分布情况
维纳亚克动漫的用户评分
我们可以看到,平均而言,人们倾向于慷慨地为动漫提供评级。他们中的大多数人给出了 7 分或更高的评分,这给我们留下了一个左偏分布,如上图所示。
现在,我们需要加载特定格式的数据,以便将其输入神经网络。fastai 的collab
子包包含一个名为CollabDataLoaders
的模块,我们可以使用它来加载数据。
特别是因为我们正在从 pandas dataframe 加载数据,我们将使用from_df
工厂方法来加载数据。
所以我们在上面创建了一个数据加载器。因为列的名称可能是特定于应用程序的,所以我们需要分别指定用户、项目和评级列的名称。
参数 valid_pct 代表验证数据百分比。一旦我们建立了一个模型,它的实际神圣性是由它在这些数据上的表现来衡量的。我们的模型将使用 90%的可用数据进行训练,并在这 10%的从未见过的验证数据上进行测试。只有当我们的模型在训练集和验证集上都表现良好时,我们才能说我们已经做得很好了。
有了这个dloader
物体,我们可以看到它所包含的一切。
Vinayak 的图像查看器数据加载器的统计数据
在数据集中有许多动漫只有很少甚至没有人给它们评分。不包括这些动漫是有道理的,因为它们弊大于利。这是因为它们已经非常稀疏,这意味着相对于它们的更新非常少,因此学习也很少。很自然地,为这样的动画生成的嵌入将是不合标准的,因此保存它们没有任何意义。
嵌入点偏差模型
这个模型是一个简单的模型,就像我们在上面的The basis
部分讨论的一样。观众和动画都被表示为向量,我们得到相同的矩阵,因为有许多观众和动画。接下来,我们对它们进行点积,并使用我们旨在减少的损失函数均方误差,将它们与我们的实际观众评级进行比较。最终,这个模型将变得善于在这个 n 维空间中表现观众和动画。
让我们创建一个简单的嵌入点偏差模型并训练它。
Vinayak 的学习率查找器
fastai2 的学习者对象的lr_find
方法真的很方便。我们可以使用它来计算出我们应该在培训中使用的学习率。它与元组的含义相同。第一个值是最小 lr,这将确保进行一些训练,第二个值是 LR,即损失下降最大的地方。在建议的 lr 中选择一个最接近 lr_min 的 lr 是很好的,最好稍微低一点以保守(个人观察)。
Vinayak 的培训总结
在训练模型之后,我们应该看到每次迭代的损失都在减少。如果遇到过度拟合的迹象,我们可以求助于早期停止(这里可能有一个,因为在第五个时期,训练损失增加了),所以保持时期的初始数量较小是好的。一旦你看到了训练和验证失败的趋势,你就可以决定是继续训练还是结束训练。
神经网络模型
在嵌入点偏差模型的基础上,我们可以通过添加完全连接的层来构建 MLP,以提高模型的复杂性。基本上,用户和电影向量被连接在一起,并在获得最终点积之前通过一系列神经网络。虽然在大多数情况下,前者表现得相当好,但这种神经网络模型在一些其他情况下也确实工作得很好。
这是一个执行试验和寻找最佳执行网络评估验证数据的问题,我们可以得出哪个模型执行得更好的结论。让我们也使用神经网络建立一个模型,并测试它的性能。
Vinayak 的学习率查找器
学习率查找器返回有些类似的结果,但是由于我们增加了深度,我们可以看到所需的 min_lr 已经下降。根据我的经验,当我们增加网络的深度时,可以观察到建议的 lr_min 降低。对于更深的网络,我们通常必须更加保守,因为收敛更容易受到学习速率值的影响。
Vinayak 的培训总结。
培训日志放在一边。似乎在最后添加两个 FC 层真的没有什么不同,因为与嵌入点偏差模型相比,损耗进一步增加了。
模型解释和提出建议
现在我们已经有了一个模型,让我们试着解释它,使用它,并提出一些建议/推荐。
理解动漫偏见和权重/嵌入
让我们试着理解嵌入点偏差模型的动画嵌入。首先,让我们看看模型中的所有层是什么。
learn.model
图片由 Vinayak 提供
如前所述,观众和动画分别有两个分量,一个是矢量,另一个是偏差项。
让我们按排名最高的动画排序(不是排名很高,而是排名最高,即观众观看并评价了动画)。
图片由 Vinayak 提供
让我们检查这些动画的偏见,并与这些动画的评级进行比较。同样,让我们检查评分最低的动画的偏见,并将它们与相同的评分进行比较。为了便于理解,我们来比较一下这其中排名前 5 位和后 5 位的情况,看看结果。
bias_rating_data.sort_values(by = ["Ratings"], ascending = False).head()bias_rating_data.sort_values(by = ["Ratings"], ascending = True).head()
Vinayak 评出的“收视率最高的动漫”
评价高的动漫通常有很高的偏见。这与上面的观点是一致的,即所有观众都喜欢动漫,而不管他们的品味如何。
Vinayak 的“评价最低的动画”
评级低的动漫一般偏向性很低。这与上面的观点是一致的,即对于所有观众都不喜欢的动画,不管他们的品味如何,这种偏见是很小的。
接下来,正如我们所讨论的,权重只不过是模型学习到的向量。让我们找出前 100 名动画的权重,对它们应用主成分分析以减少它们的维度,然后在二维图上进行视觉比较。PCA 是一种用于压缩向量/矩阵的降维技术,特别是当我们必须可视化大规模数据时,或者当我们面临具有大量特征或列的数据集中的维数灾难问题时,通常会用到它。
用主成分绘制动画
可以看出,像《东京食尸鬼》和《攻击泰坦》这样动作性很强的动漫高于 y=0.5 线,而像《Clannad》、《K-On》、《Ouran Host Club》这样的爱情/生活片段动漫则低于 y = 0.5 线,尽管有一些例外。
此外,沿着 x 轴向右,浪漫和生活片段似乎越来越占主导地位,例如,Clannad After Story 位于 Clannad 和 K-on 的右侧,Ouran Host Club 位于右侧。
这是数据的压缩版本,因此这里没有描述大量丢失的信息。我们已经将嵌入向量的维数从 60 减少到 2,但是我们仍然可以看到数据的一些结构,这是非常棒的。由于人类只能感知三维的物质世界,我们无法想象 60 维的嵌入空间,因此有了这个近似值。
现在我们已经收到了所有动漫的嵌入(真嵌入),让我们来比较一下 Oregairu,东京食尸鬼和 Hyouka 之间的距离。
维纳亚克的《东京食尸鬼》、《兵库》与《奥雷盖鲁》之比较
我们可以确认,正如我们之前讨论的,Hyouka 和 Oregairu 确实彼此更接近,因为它们的点积在三者中是最高的。此外,Hyouka 和 Oregairu 与东京食尸鬼的点积距离几乎相等。这意味着该算法做了一件相当不错的工作,尽管它并不真正知道现实中的三部动画属于哪种类型。
了解用户权重/嵌入
为了理解用户权重,我们将从我们的集合中随机抽样一个用户,然后在剩余的语料库中,根据称为余弦相似性的特定距离度量,挑选一个离这个随机抽样的用户最近的用户和一个最远的用户。
基本上,我们将在整个用户语料库的跨度中取那个用户、离他近的用户和离他最远的用户的点积,然后查看各自的动画以查看差异。
维纳亚克的《比较用户》
我们发现,我们随机抽样的用户喜欢动作和虚构成分高的动漫,并涉及一些戏剧/爱情/生活片段的元素。最相似的用户也喜欢高度动作和虚构的类型。
可以看出,最相似的用户选择了几乎所有的动漫,这些动漫与那个随机的家伙喜欢的动漫相同,而最不同的动漫具有更高程度的剧情/生活片段。
CF 的一个缺点&潜在的解决方案
现在,我们看了数据库中已经存在的用户推荐。如果我们有一个新用户进来,我们没有任何建议给他,因为他没有评价任何动画/电影。
这就是通常所说的冷启动问题。
为了解决这个问题,新用户被问了几个问题,这些问题与他对我们目录中的动漫的喜欢和不喜欢有关。这使得系统推荐一些动漫,并且随着用户更频繁地参与平台并给出反馈,推荐变得越来越精炼,以适合观众的口味和喜欢。
协作过滤或推荐系统已经存在,并帮助观众/用户/消费者/订户获得适合他们喜好和品味的内容。希望这篇文章能帮助你快速了解快乐学习!如果你想深入研究,我在参考资料部分推荐了一些文章。
参考资料和进一步阅读
collatz——你不完全理解的最简单的程序
用 Wolfram 语言进行计算探索
大约 10 分钟后,一个人看着 Collatz 程序的照片,由 Unsplash 上的 Sebastian Herrmann 拍摄
我喜欢认为自己无所不知,尤其是在编程方面。而且,很长一段时间以来,我认为如果我观察一段代码足够长的时间,我就能够完全理解它的行为。只需逐行阅读代码,并仔细考虑 if 语句和 for 循环的可能情况。只要有足够的时间和耐心,所有代码都是完全可以理解的。
然而,我写的代码并没有像预期的那样运行。事实上,这种情况发生了很多。通常情况下,我写一段新代码的前十次尝试中,有九次都是谦逊编码的经历。但是,我仍然把这归因于输入错误、编写不完整的代码,以及在输入实际代码之前不耐烦和没有充分考虑事情。
有一天,有人向我展示了一段实现了 Collatz 算法的 Wolfram 语言代码,这一切都改变了。这个想法非常简单:编写一个接受正整数作为唯一参数的函数。如果数字是 1,就完成了,从函数中返回 1。如果数字大于 1,则有两个分支:如果数字是偶数,则除以 2 并返回该数字。如果数字是奇数,则返回该数字的三倍加 1。
collatz[1] = 1
collatz[n_Integer /; n>1 ] := If[ EvenQ[n], n/2, 3n+1 ]
到目前为止,一切顺利。你可以用不同的整数试一下,一切都很好:
collatz[5] --> 16
collatz[8] --> 4
但是当你写一个程序来计算下面的序列时,曲线球就出现了:
collatz[16] --> 8
collatz[8] --> 4
collatz[4] --> 2
collatz[1] --> 1 (* done! *)
在 Wolfram 语言中实现这一点的一个简单方法是使用 NestWhileList :
collatzSequence[n_Integer /; n > 0] :=
NestWhileList[collatz, n, # != 1 &]
n=16 的例子给出:
collatzSequence[16] --> {16, 8, 4, 2, 1}
这看起来很简单,但是有一个小问题:当你遇到一个奇数的时候,下一个数字将会大三倍(加一)。下一个数字也将是偶数,这意味着之后的数字将再次减半。这里有一个例子,当你从一个奇数开始:
collatzSequence[17] --> {17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1}
数字序列首先上升到 52,但随后又迅速回落到 1。显然,这最终会发生在每一个数字上?不幸的是,我们不得不考虑这样一种可能性,即有些数字产生的序列永远不会达到 1。例如,可能有一个序列,其中的数字随着时间的推移慢慢反弹,变得越来越大。阅读代码在这里没有太大帮助。下面是一个起始数的示例,其中序列不会快速变为 1:
collatzSequence[63728127]
(图片由作者提供)
这是这个数列的图表:
(图片由作者提供)
尽管我们可以阅读代码并理解任何数字的每一步会发生什么,但我们无法知道程序是否会终止(甚至不知道给定数字的序列长度)。仔细研究过这个问题的人推测(但没有证明)每个数字都有一个以 1 结尾的序列。这个猜想被称为科勒兹猜想以第一个提出这个问题的洛萨科勒兹命名。
对于这个问题,人们已经有了很多有趣的发现和可视化,而没有实际解决猜想本身。一个非常有趣的视觉效果是一个由许多起点以及这些序列如何最终相遇并融合在一起的图:
(图片由作者提供)
或者一个更简单的图形显示不同的 Collatz 序列如何合并并最终在数字 1 处相遇:
(图片由作者提供)
我得到的教训是,即使是最简单的程序也不一定能理解。因此,当我看到一个文档记录很差的巨大的源代码文件时,我也不会感觉很糟糕。在许多情况下,你所能做的最好的事情就是运行一个有许多不同输入的程序来开发直觉和推测,并使用它来迭代你的代码到一个点,在这个点上它的行为大部分是你所期望的。也许有一天,有人会为 Collatz 序列找到一个不以零结尾的起始数。但我觉得这就是那种可能永远解不开的编程难题!
收集和可视化新冠肺炎数据
网络抓取和探索性数据分析初学者指南
不用说,每个人都很清楚新冠肺炎对整个世界的毁灭性影响。有数不清的数据集可用于捕捉这种病毒在全球传播的趋势。
就我个人而言,我更感兴趣的是分析我的家乡宾夕法尼亚州(美国)的新冠肺炎案例。我偶然发现了宾夕法尼亚州卫生部网站,该网站公布了宾夕法尼亚州按县分列的每日新冠肺炎病例。不幸的是,每天的更新都以 HTML 表格的形式呈现在单独的部分中。当我们浏览这个网页时,很难在脑海中形成每日趋势的图像。因此,我决定接受挑战来解决这个问题。我开始了一个周末迷你项目来实施解决以下问题的方法:
- 从网页中提取数据
- 执行数据分析
- 创建数据可视化
结果显示在我的 GitHub Repo 中的 Jupyter 笔记本中。不幸的是,GitHub 无法渲染交互式数据图,如果您希望查看,请访问 Jupyter NBViewer 。
事不宜迟,我们开始吧!我将向你详细介绍我的学习历程。
我们将从如何将 html 表格转换成数据集开始,然后是数据操作、绘图和图表。最后,我们将创建一个交互式地图,按县显示确诊病例。
通过网络抓取提取数据
我想简单介绍一下我是如何从每天更新的 PA 卫生部网页中提取数据集的。当您滚动页面时,您会注意到每个每日部分都以日期标题开始(例如:2020 年 4 月 8 日)。我对汇总以下两个表中的数据感兴趣,即总计数表和按县的总计数表。
**总计数表:**显示迄今为止的阴性、阳性病例和死亡总数。
**County Total Counts by County 表:**显示宾夕法尼亚州各县迄今为止的阳性病例和死亡总数。
下面是网络抓取策略的概要,完整的源代码可以在我的 GitHub 库中找到。
您需要安装这些依赖项:
pip install beautifulsoup4
pip install lxml
**第一步。**提取< h4 >标题之间的日期并存储一个列表。
**第二步。**提取每个总计数表中的数据,并将其与步骤 1 中的日期匹配。输出文件的示例如下所示。
**pa_summary.csv:** Date,Negative,Positive,Deaths
2020–04–08,82299,16239,309
2020–04–07,76719,14559,240
第三步。 提取各县总计数表中的数据,并将其与步骤 1 中的日期进行匹配。输出文件的示例如下所示。
**pa_county.csv:** Date,County,Cases,Deaths
2020–04–08,Adams,33,0
2020–04–08,Allegheny,720,1
**第四步。**调用 MapQuest 地理编码 API 获取各县的纬度和经度。你可以建立一个每月 15K 交易的免费账户。从 MapQuest 获取 API 密钥,并更新 data_extractor_pa.py 中的 API_KEY 值。输出文件的示例如下所示:
**pa_county_geolocation.csv**
County,Latitude,Longitude
Bradford,41.774669,-76.526461
Butler,40.861021,-79.895225
**第五步(可选)。**如果您希望获得最新数据,请运行提取程序重新生成 CSV 文件。
python data_extractor_pa.py
进行探索性数据分析
有了这三个数据集,让我们启动 Jupyter 笔记本。
首先,导入这些依赖项:
import datetime as dt
import matplotlib.pyplot as plt
from matplotlib import style
import pandas as pd
将汇总数据集加载到 Panda 数据框架中:
df = pd.read_csv("pa_summary.csv")
df.head(5)
计算测试总数和阴性/阳性/死亡百分比:
df['Tested'] = df['Positive'] + df['Negative']
# Percentages
df['Positive_Percent'] = round(100*df['Positive']/df['Tested'], 1)
df['Negative_Percent'] = round(100*df['Negative']/ df['Tested'], 1)
df['Death_Percent'] = round(100*df['Deaths']/ df['Tested'], 3)
# sort by date
df = df.sort_values('Date', ascending = True)
df.head(5)
绘制迄今为止的总测试数、阳性数、阴性数和死亡数:
测试人群中阳性与阴性的百分比是多少?
也许观察每天的变化更有意义。
以下代码片段显示了如何利用 panda 中可用的 diff 函数来计算案例的每日变化。注意,我们需要在第一行填入 0 以避免得到 NaN。
看着县细目
df_counties = pd.read_csv("pa_county.csv")
df_counties.head()
费城的确诊病例趋势如何?
# Filter Data for a County
county_name = 'Philadelphia'
df_county = df_counties[df_counties['County']== county_name]
df_county = df_county.sort_values('Date', ascending = True)# Line Plot
style.use('ggplot')
ax = plt.gca()
df_county.plot(kind='line',x='Date',y='Cases', color='green', ax=ax, figsize=(20,10))
plt.title('Number of Cases In ' + county_name +' County')
plt.xlabel('Date')
plt.ylabel('Cases')
plt.show()
创建交互式数据地图
让我们开始准备一个数据框架,以便在交互式地图中按县显示确诊病例。
我们如何在地图上指出每个县?
首先,加载包含每个县的纬度/经度对的县地理定位数据集
df_geo = pd.read_csv("pa_county_geolocation.csv")
df_geo.head()
执行左外连接,将 lat/long 列添加到 county 数据框架中。
df_county_with_geo = df_counties.merge(df_geo, how='left', on=['County'])
df_county_with_geo.head()
最后,我们只想保留最新日期的记录。
df_latest_county = df_county_with_geo[df_county_with_geo['Date'] == df_county_with_geo['Date'].max()]# drop unnecessary columns
del df_latest_county['Date']
del df_latest_county['Deaths']df_latest_county.head()
我们已经准备好创建一个交互式地图
我选的是 Folium,它有丰富的渲染交互式地图的功能。这不是一个关于叶子的教程。请访问这里了解更多信息。
在继续之前,您需要安装 need。
pip install folium
只需几行代码,我们就可以构建一个非常棒的交互式数据地图,显示宾夕法尼亚州各县的新冠肺炎确诊病例。
让我们走一遍我们正在做的事情
- 将地图置于某个位置的中心,以便在查看区域内可以看到大多数数据点。
- 函数 get_icon_color()根据正例的值确定在地图上显示的图标的颜色。
- 创建一个具有中心点和适当缩放级别的地图。
- 将每个县的数据点装饰成彩色编码的图标和弹出文本,以显示计数和县的名称。
- 创建图例部分以显示颜色的含义。这篇关于如何给叶子地图添加图例的博客文章值得称赞。
那都是乡亲们!!
这篇文章的代码可以在 GitHub 上找到。我希望这能激励你走出你的舒适区去学习新的东西。直到下一次,继续学习,每天都变得更好。
资源:
使用 Python 和 Ally Financial API 轻松收集股票和期权数据— 3 个示例查询
简短的备忘单
由 pikrepo 提供
尝试交易
在我生命中的一段时间里,我痴迷于金融市场,想成为一名日间交易者。我晚上工作,所以早上很容易被电脑显示器包围,显示器上显示着从股票、期权、新闻到交易聊天室的一切。剧透…我放弃了日内交易,但没有放弃投资。最终,我知道我喜欢分析数据胜过交易,然后我让自己走上了学习数据分析和进入数据科学的道路。
当我在探索收集股票和期权数据的方法时,我查看了我的一个经纪人 Ally Financial 提供的 API。它可以免费使用并且易于编码。这是我为使用 Ally Financial API 收集以下信息而整理的备忘单:
- 股票的时间和销售
- 期权市场深度
- 选项扩展报价
如果你不熟悉 API,看看这些资源。通过它们的 API 实现交易自动化是可能的,但我从未深入研究过。探索文档中的所有功能。
构建您的应用程序,连接到我们的投资平台和与之相连的 250,000 名交易者…
www.ally.com](https://www.ally.com/api/invest/documentation/getting-started/)
你可以在文章底部或者我的 GitHub 上找到完整的备忘单!
Ally Financial API 入门。通过创建一个帐户,为 bendgame/Ally-API-Cheat-Sheet 开发做出贡献…
github.com](https://github.com/bendgame/Ally-API-Cheat-Sheet)
继续编码!
导入依赖项
连接到 API 使用 OAuth1 。你可以在 OAuth 网站这里找到 OAuth 客户列表。我使用 OAuth 库 requests_oauthlib 。根据需要使用 pip 安装请求-oauthlib 。
import requests
from requests_oauthlib import OAuth1
from config import (api_key, secret, oath_token, oath_secret)
import pandas as pd
import sqlalchemy
import numpy as np
import sqlite3
from sqlite3 import Error
import matplotlib.pyplot as plt
import datetime as dt
注意,我使用一个配置文件来导入 api_key、secret、oath_token、oath_secret 。这样,我就不需要在代码中包含那些个人令牌。
*#authentication*
auth = OAuth1(api_key, secret, oath_token, oath_secret)
我把进口令牌递给oauth 1。这将在我们向 API 发出请求时使用。
股票的时间和销售示例
这个 API 调用将根据作为查询参数传递的符号返回时间和销售报价数据。有关所有查询参数的列表,请查阅文档。示例 URL 由 基础 url 、 api 路由 和 查询 组成。
基础网址:https://api.tradeking.com/
路线:v1/market/timesales . JSON
查询:?symbols=MSFT &开始日期= 2019–05–03&间隔= 1 分钟
文档:https://www . ally . com/API/invest/Documentation/market-timesales-get/
*#url call to the api*
url = 'https://api.tradeking.com/v1/market/timesales.json?symbols=MSFT&startdate=2019-05-03&interval=1min'*#api request*
response = requests.get(url, auth = auth).json()
注意,我将 URL 和 oAuth 值传递给请求,并将响应作为 json 返回。这是一个响应示例:
我将报价数据放入 Panda 的数据帧中,并格式化数据类型。
*#send to data frame and format data types*
df = pd.DataFrame(response["response"]["quotes"]["quote"])
df = df.sort_values(['datetime'], ascending = **False**)
df['date'] = pd.to_datetime(df['date'])df['datetime'] = pd.to_datetime(df['datetime'], utc=**False**).dt.tz_convert('US/Central')df['hi'] = df["hi"].astype(float)
df['incr_vol'] = df["incr_vl"].astype(float)
df['last'] = df["last"].astype(float)
df['lo'] = df["lo"].astype(float)
df['opn'] = df["opn"].astype(float)
df['vl'] = df['vl'].astype(float)df.head()
示例数据
日期时间值需要转换,以便能够对其进行重新采样。重采样允许您操纵时间序列的频率。根据文档,对象必须有一个类似于 datetime 的索引( DatetimeIndex 、 PeriodIndex 或 TimedeltaIndex ),或者将类似于 datetime - 的值传递给 on 或 level 关键字。
*#resample the time value to be greater than 1 min as needed. Example: 30 min resample for last price*
df.set_index(df['datetime'], inplace = **True**)
df.head()
df_resample30 = df.resample(rule = '30min', label = 'right').last()
df_resample30.head()
重采样数据帧
请注意, 日期时间 在重采样后增加了 30 分钟,而不是 1 分钟。
选项搜索示例
由 pxfuel 提供
这个 api 调用为选项提供了市场深度。该调用将返回给定符号的可用选项击的完整列表。虽然这种请求类型是 GET,但是也可以使用 POST,并且推荐用于较长的查询。
文档:https://www . ally . com/API/invest/Documentation/market-options-search-get-post/
基地网址:https://api.tradeking.com/
路线:v1/market/timesales . JSON
查询:?symbol = MSFT&query = xy ear-eq % 3a 2019% 20 and % 20x month-eq % 3a 06% 20 and % 20 strike price-eq % 3a 140
查询细分:
到期年份等于 2019 年 :
xyear-eq%3A 2019
和:
%20 和% 20
到期月份等于 06 :
xmonth-eq%3A 06
和执行价格等于 140:
%20 和% 20 执行价格-eq%3A 140
操作员:
lt :小于
gt :大于
gte :大于等于
lte :小于等于
eq :等于
url = 'https://api.tradeking.com/v1/market/options/search.json?symbol=MSFT&query=xyear-eq%3A2019%20AND**%20x**month-eq%3A06%20AND**%20s**trikeprice-eq%3A140'#api call
response = requests.get(url, auth = auth).json()#load the response into the dataframe
df = pd.DataFrame(response["response"]["quotes"]["quote"])
df
扩展报价示例(可选)
这条路线适用于股票,但这是一个期权看涨的例子,因为它们有点复杂。该调用将返回作为查询参数传递的符号或符号列表的引号。
文档:https://www . ally . com/API/invest/Documentation/market-ext-quotes-get-post/
基础网址【https://api.tradeking.com/】:
路线:v1/market/ext/quotes . JSON
查询:?symbols=MSFT190607C00140000
选项符号命名约定:
图片来自文档
基础符号— MSFT
2 位到期年份— 19
2 位到期月份— 06
2 位到期日—07
“C”代表买入或“P”代表卖出— C
8 位执行价格— 00140000
根据需要使用 fids 在查询中指定所需字段:
即 fids=ask、bid、vol
尽管命名约定有几个组成部分,但通过几个例子就可以看出它相当简单。同时,使用文档或备忘单中提供的示例图像!
url = 'https://api.tradeking.com/v1/market/ext/quotes.json?symbols=MSFT190607C00140000'#api call
response = requests.get(url, auth = auth).json()#load the response into the dataframe
df = pd.DataFrame(response["response"]["quotes"]["quote"], index = [0])
df
扩展报价示例
将这些点连接起来
使用 Pandas,很容易将数据保存到 CSV 或 SQL 数据库中。如果你不熟悉 SQLite ,它非常容易使用。引用文档:
SQLite 是一个 C 库,它提供了一个轻量级的基于磁盘的数据库,不需要单独的服务器进程,并允许使用 SQL 查询语言的非标准变体来访问数据库。
conn = sqlite3.connect('stockdata.sqlite')
df.to_sql(table_name, conn)
完全码
使用这三个查询,很容易开始使用 Ally Financial API 收集股票和期权数据。将数据放入 Panda 的 dataframe 中可以很容易地理解 JSON 信息并将数据存储为 CSV 或 SQLite 文件。如果您想探索股票数据的其他 API,也可以查看一下 Alphavantage 。
import requests
from requests_oauthlib import OAuth1
from config import (api_key, secret, oath_token, oath_secret)
import pandas as pd
import sqlalchemy
import numpy as np
import sqlite3
from sqlite3 import Error
import matplotlib.pyplot as plt
import datetime as dt*#authentication*
auth = OAuth1(api_key, secret, oath_token, oath_secret)*#url*
url = 'https://api.tradeking.com/v1/market/timesales.json?symbols=MSFT&startdate=2019-05-03&interval=1min'*#api request*
response = requests.get(url, auth = auth).json()*#send to data frame and format data types*
df = pd.DataFrame(response["response"]["quotes"]["quote"])
df = df.sort_values(['datetime'], ascending = **False**)
df['date'] = pd.to_datetime(df['date'])
df['datetime'] = pd.to_datetime(df['datetime'], utc=**False**).dt.tz_convert('US/Central')
df['hi'] = df["hi"].astype(float)
df['incr_vol'] = df["incr_vl"].astype(float)
df['last'] = df["last"].astype(float)
df['lo'] = df["lo"].astype(float)
df['opn'] = df["opn"].astype(float)
df['vl'] = df['vl'].astype(float)
df.head()*#resample the time value to be greater than 1 min as needed. Example: 30 min resample for last price*
df.set_index(df['datetime'], inplace = **True**)
df.head()
df_resample30 = df.resample(rule = '30min', label = 'right').last()
df_resample30.head()#Options Search Exampleurl = 'https://api.tradeking.com/v1/market/options/search.json?symbol=MSFT&query=xyear-eq%3A2019%20AND**%20x**month-eq%3A06%20AND**%20s**trikeprice-eq%3A140' response = requests.get(url, auth = auth).json()
df = pd.DataFrame(response["response"]["quotes"]["quote"])
df.head()#Extended Quote Exampleurl = 'https://api.tradeking.com/v1/market/ext/quotes.json?symbols=MSFT190607C00140000'response = requests.get(url, auth = auth).json()df = pd.DataFrame(response["response"]["quotes"]["quote"], index = [0])
df.head()
谢谢大家!
- 如果你喜欢这个, 跟我上 Medium 了解更多
- 通过订阅 获得完全访问权限并帮助支持我的内容
- 我们连线上LinkedIn
- 用 Python 分析数据?查看我的 网站
查看我的其他教程,了解更多 python 和 sql!
[## 学习 SQL 技术:在 SQL Server 中选择数据和更多内容
SQL 语句介绍和查找重复数据的查询。学习 SQL
medium.com](https://medium.com/@erickleppen01/learn-sql-techniques-selecting-data-and-more-in-sql-server-624f81dd16b2) [## Python 中的仪表盘,适用于初学者和使用 Dash 的其他人
使用 Python 中的 Dash 初学者教程构建一个基本的和高级的仪表板
medium.com](https://medium.com/swlh/dashboards-in-python-for-beginners-and-everyone-else-using-dash-f0a045a86644)