利用有限数据进行 Kaggle 图像分类的最新成功技术
关于如何防止模型在小数据集上过度拟合但仍能进行准确分类的教程
http://www.dakanarts.com/13-black-white/
在本文中,我将介绍我在课堂卡格尔挑战中使用的方法。我花了大约两周的时间进行挑战,最终提交分数为 0.97115 ,在最终排行榜上名列第二。我从借用的这篇文章开始,我也推荐这篇文章。
挑战攻略
提出的挑战是一个自然图像分类任务,有 13 和类。这项挑战的第一个困难是可用数据的稀缺:只有 3 859 张图像用于训练。挑战的规则是在训练中不使用外部数据。在数据很少的情况下,模型将更容易过度拟合,而不学习概括。
此外,由于这些图像处于灰度,它们包含的信息比 ImageNet 数据集等彩色图像少,因此彩色图像上的预训练模型不能直接应用于此任务。在进一步检查数据集时,许多类包含视觉上非常相似或包含相同元素的图像。混淆此类类别时,模型将失去准确性。
Some examples of images to classify
数据处理
首先,我们数据集中的图像并不都具有相同的尺寸,所以我们在将图像输入到模型之前,调整了所有图像的尺寸。一半以上的训练图像的尺寸为 256 x 256,因此我们将其他图像的尺寸调整或裁剪到这个尺寸。
我们还将应用规范化。最初,图像被表示为像素值范围从 0 到 255 的张量。我们简单地将每个值除以 255,以重新调整并获得神经网络首选的 0 到 1 之间的值。此外,我们将对比度拉伸应用于所有图像以增强图像。这将有助于模型更清楚地“看到”图像中的细节。
这些类也是不平衡的,这意味着每个类之间的数据量不相等。这将使模型或多或少地偏向某些类。为了解决这个问题,我们人为地添加更多的图像,使得每个类都有与最大类一样多的图像。为了对小班进行重采样,我们在图像中随机裁剪一个区域来创建一个新样本。这是基于这样的假设,即裁剪后的图像将包含作为该类特征的相同元素。
最后,随着深度网络在大量训练数据的情况下表现和概括得更好,我们执行了数据增强。我们的目标是人为地创造出包含同类特征的新图像。为此,我使用的技术可以总结如下:
在开始训练之前,我们将数据集分成训练集(80%)和验证集(20%)。除了仅在训练集上使用的图像增强之外,我们在两个集上都应用了上面讨论的所有处理技术。
迁移学习
因为我们的数据集包含的图像与 ImageNet 中的图像相似,所以我们将从一个已经在 ImageNet 上经过预训练的 CNN 模型开始。我们的想法是冻结预训练模型的较低层,这些模型可以捕捉通用特征,同时针对我们的特定领域对较高层进行微调。我们还重新定义了最后一层来输出 13 个值,每个类一个。
PyTorch 提供了几种不同架构的预训练模型。其中, ResNet18 是我采用的架构,因为在运行了 5 个时期的各种架构后,它在对我们的数据进行训练时给出了最佳的验证准确性。在对不同数量的冷冻层进行实验后,发现 7 是最好的。我还使用了 SGD 优化器和权重衰减来阻止过度拟合。
学习率调度
为了进一步改善结果并使模型收敛到全局最小值,我们希望调整学习率。我选择使用循环学习率调度,而不是通过实验来确定最佳学习率。这种方法使得学习速率循环变化,从而使模型能够收敛和逃离几个局部极小值。它还消除了“手动”寻找最佳学习率的需要。
快照集成
集成方法在提高模型整体性能方面非常强大。然而,为集成学习分别训练几个不同的模型在计算上也是昂贵的。这就是我选择使用快照集合和循环 LR 调度的原因。
快照集合在训练期间定期保存模型的参数**。想法是在循环 LR 调度期间,模型收敛到不同的局部最小值。因此,通过在不同的局部最小值保存模型参数,我们获得了一组模型,这些模型可以为我们的预测提供不同的见解。这使得我们可以在一个单一训练周期中集合一群模型。**
https://arxiv.org/abs/1704.00109
对于每个图像,我们连接每个“快照”模型的分类概率预测以形成新的数据点。这个新数据然后被输入到一个 XGBoost 模型中,根据快照模型给出一个预测。
子类决策
在检查单个模型的验证集上的混淆矩阵时,我们发现它经常将一个类与相同的另一个类混淆。事实上,我们发现的三个子类经常被混淆在一起:
- 【房间】:卧室、厨房、客厅、办公室
- “自然”:海岸、森林、山脉、野外、公路
- “城市”:城市、街道、高楼
此外,该模型已经非常善于区分这些子类(并找到郊区)。要获得良好的性能,剩下的就是让模型准确地识别子类中的分类。
为此,我们使用与之前相同的方法,在每个子类上训练三个新的独立模型。有些类的训练数据很少,所以我们增加数据扩充量。我们还发现了针对每个子类调整的新参数。
在预测过程中,我们首先使用在整个数据集上训练的模型。然后,对于得到的每个预测,如果类概率低于某个阈值,我们取相关子类模型预测的类来代替。
抗锯齿
大多数现代卷积网络,如 ResNet18,都不是移位不变的。网络输出可能会随着输入的微小偏移或转换而发生剧烈变化。这是因为卷积网络中的跨步操作忽略了奈奎斯特采样定理和混叠,从而破坏了移位等方差。****
我决定应用最近于 2019 年 4 月发表的论文中提出的反走样方法。这是通过在网络的卷积层之后简单地添加“模糊池”层来实现的,即模糊滤波器和子采样层。这种方法已被证明改善了图像的不同偏移之间的分类一致性,并且由于更好的概括而具有更高的分类准确度。
https://arxiv.org/abs/1904.11486
我使用预训练的抗锯齿 ResNet18 模型来微调挑战的数据集。通过反走样,我希望通过将模型推广到图像平移和移动来克服由于数据匮乏而导致的过度拟合。
如果你想更多地了解这种反走样方法,我在这里更详细地解释了“让卷积网络再次保持平移不变”这篇文章:
现代卷积网络有什么问题,如何修复?如果你使用 CNN,你可能想读这个。
towardsdatascience.com](/https-towardsdatascience-com-making-convolutional-networks-shift-invariant-again-f16acca06df2)
结果摘要
所用的方法可总结如下:
对 ResNet18 模型进行 5 个时期的数据微调,除了调整大小之外不进行任何处理,已经给出了 0.91442 的测试精度。这揭示了迁移学习的显著效率——用很少的数据和计算,该模型已经可以在相关任务上表现出良好的性能。
加上数据扩充和 10 个历元的较长训练,我们得到的测试精度为 0.93076 。这证实了拥有大型训练数据集和增强技术可扩展性的重要性。
增加类平衡和学习率调度,测试精度上升到 0.94230 。此外,混淆矩阵表明,平衡后,该模型以更高的精度预测代表性不足的类别。这也说明了学习率是模型收敛的一个重要参数。
然后,通过在所有数据上训练的模型上的快照集合,测试精度提高到 0.95000 。这说明了循环 LR 调度如何允许我们通过单个训练循环获得具有不同行为的模型,并且 XGBoost 元学习器可以从它们的预测中提取有用的信息。
通过对比拉伸所有图像以及特定子类上的训练模型并结合它们的预测,测试精度上升到 0.95865 。混淆矩阵显示了子类内精确分类的改进,特别是对于“城市”子类。开发在某些类上是“专家”的模型,并将它们与善于区分子类的模型一起使用,被证明是非常有效的。
最后,在反走样resnet 18 网络并结合训练集和验证集使用所有可用于训练的标注数据后,测试精度上升到 0.97115 。反走样是提高泛化能力的有力手段,在图像数据有限的情况下尤为重要。
Yay!
其他想法
以下是我为应对这一挑战而想出的一些其他主意,它们要么效果不好,要么我没有办法去尝试。
单通道图像
这些图像是灰度的,所以尽管它们在加载时被编码成三个通道,但它们可以被表示为单通道矩阵。我的想法是,这种降维可以加速训练,同时保留所有必要的信息,但通过实验,这种方法显示出在没有显著加速训练的情况下损失了准确性。
其他集成方法
我还尝试对通过其他方式检索的模型进行集成,例如在不同处理方法(有/没有类别平衡、不同图像增强技术、不同数据增强方法)之后对图像进行训练的模型,但是这些方法计算量更大,并且不能提供明显更好的准确性。
生成对抗网络
如前所述,数据扩充和类平衡在模型性能中起着关键作用。除了经典的图像处理,生成模型可以单独用于合成带注释的数据。例如,DAGAN 模型可用于数据扩充,而 BAGAN 可用于平衡。
灰度图像网络预训练
所提供的数据集中的图像具有与组成 ImageNet 数据集的自然图像相似的内容,不同之处在于我们的图像是黑白的。因此,在灰度图像上预先训练的模型将更适合于这个任务。
人工图像彩色化
如果我不能获得灰度图像的预训练模型,我的下一个想法是人工给图像着色,希望增加额外的信息。人工图像着色的预训练模型确实存在,并且是公开可用的,如果你尝试这种方法,请告诉我!**
感谢阅读,我希望你喜欢这篇文章!你可以在 GitHub 上找到我的方法的完整代码。
通过基础设施代码(Boto3、CloudFormation、Python)发布 AWS EMR 支持的 SageMaker 笔记本电脑
如今,云中的可扩展分析是游戏的名称。所有领先的云提供商都非常关注简化机器学习的端到端生命周期的供应服务。如今的趋势是在 data-lake 上获取数据(这需要自己的一套考虑因素),并通过 Spark 这样的大数据处理框架对其进行处理。一旦数据在 Data Lake 中以相当标准的格式可用(这样做是为了减轻 it 成为数据沼泽的风险),这些数据就被认为可供从数据分析师、数据科学家等多个类别的最终用户使用。由于数据湖中的数据量通常很大,如果想要将其用于分析目的,一个自然的选择是使用大数据原生工具集来执行探索性分析和随后的功能工程。此外,数据科学社区最喜欢的工具之一是 Jupyter notebook,它有助于提高工作效率和协作。因此,对于数据科学家来说,乌托邦或涅槃状态是能够使用 Jupyter(如云中的笔记本电脑)来消费数据湖中的数据,并且还能够无缝地使用 Spark 等大数据工具来进行功能工程。
如果您使用 AWS 堆栈来实现升级的结果,您可能最终会使用以下一组 AWS 本机服务:
- EMR(Elastic MapReduce)—AWS 中的托管 Hadoop 框架(特别是在 EMR(领先的内存和分布式计算引擎)中使用 Spark)
- SageMaker——AWS 中主要的机器学习服务之一
- 简单存储服务(S3)—AWS 提供的大规模可扩展对象存储服务,是构建数据湖的基础
因此,如果你在 S3 有数据,通过电子病历处理,如果你想执行机器学习任务,如探索性分析,特征工程;您很可能会使用 SageMaker 的托管笔记本(Jupyter)实例。通常这些笔记本用于特别分析,一旦你对你的分析和特征工程方法感到满意,你通常会通过其他工具集(如 Glue 或 EMR,尽管有些人仍然可以出于上述目的使用笔记本)来操作它的执行。
这一切看起来都很好,但当您打算将 SageMaker 笔记本与 EMR 结合使用时,就会遇到挑战。默认情况下,这两个组件不是开箱即用的,例如,您不能在启动时使用 SageMaker notebook 实例来运行 pyspark 查询。如前所述,如果您想要使用 sweet 托管笔记本电脑来执行大规模分析,而处理是由 EMR (Spark)在后端执行的,您必须在 SageMaker 笔记本电脑中为此进行一些配置。AWS 的 blogpost 强调了这样做的步骤,包括访问笔记本的外壳,从互联网下载“config.json ”,然后修改它以实现 EMR 集成。如果您为自己(不同尺寸)或不同用户反复启动笔记本电脑,这些手动配置任务会增加操作开销,并且容易出错。这就是如今你可以利用这个游戏的另一个名字的地方:“作为代码的基础设施”。
作为代码的基础设施(或简称为 IaC)是指以编程方式在您的平台(无论是本地还是云)中提供资源的方法。有各种特定于云的方法来实现这一点,例如 Azure 使用 ARM 模板,AWS 支持云形成。类似地,还有配置管理工具,比如 Ansible/Chef/Puppet/Terraform。进一步说,所有领先的云提供商都提供 SDK,您可以使用它们来实现类似的 IaC 功能。无论您使用哪种方法,它都能让您运行代码/脚本,并为您提供资源。它增强了部署的可重复性和一致性,还节省了大量时间。这正是本文的价值主张:
为您提供 IaC 功能,在 AWS 中配置集成 EMR 的 SageMaker 笔记本电脑。
如上所述,IaC 可以通过多种方式实现,在本文中,我将重点介绍几种方法的组合:
- AWS Boto3 SDK
- 云的形成
使用 Python。因此,没有进一步的到期,让我们开始编码,因为谈话是廉价的。
先决条件:
这篇文章假设:
- 您有 AWS 帐户
- 您已经在您的帐户中完成了基本的网络设置(VPC、子网等)
- 您知道如何配置 EMR 集群,并且已经有一个 EMR 集群在运行(至少有 Spark 和 Livy 服务)
- 您已经为 EMR 集群和 SageMaker 笔记本配置了安全组,并在 EMR 主节点的安全组中添加了 SageMaker 的安全组。参考 AWS 博客了解更多内容。
- 您已经在您的环境中为 SageMaker 和 EMR 配置了 IAM 角色
- 您已经在您的环境中为一个具有帐户管理员访问权限的用户配置了 IAM 配置文件(或者您可以让一个用户具有仅限于 SageMaker、EMR 和 CloudFormation 的权限)
- 你对 Python 有基本的了解
(我很想深入了解上面的细节,但是上面的每一个话题都需要深刻的理解,我已经把它排除在这篇文章的范围之外了。)
设置:
要跟进,您必须具备:
- Python 安装在您的系统中。理想情况下还带有一个 IDE。我更喜欢皮查姆。
- 您已经安装了 boto3(如果没有,在您的环境中运行:pip install boto3)
代码:
让我们从导入所需的库开始:
import boto3
import json
import sys
import base64
我更喜欢创建我将在程序中使用的参数的映射/字典。您可以选择不同的方法:
parameters =
{"SecurityGroupIds":["sg-<>"],
"SubnetId":"subnet-<>",
"VolumeSizeInGB":5,
"RoleArn":"arn:aws:iam::<>:role/service-role/<>",
"nb_instance_type":"<>",
"nb_instance_name":"<>"
"lifecycle_config_name":"<>"}
在上面的字典中,指定了以下参数:
- security group pids—您为 SageMaker 笔记本创建的安全组的 ID
- SubnetId —您将在其中置备笔记本的 subner 的 Id
- VolumeSizeInGB —您可以将 EBS 卷附加到笔记本上。您可以在这里指定以 GB 为单位的大小。我指定了 5GB。
- role arn—在 SageMaker 服务与您帐户中的其他 AWS 服务进行交互之前,您应该已经创建的 IAM 角色。在这篇文章中,这也被强调为一个先决条件。
- nb _ instance _ type—sage maker 笔记本的实例类型
- nb 实例名称 SageMaker 笔记本实例的名称
- 生命周期配置名称—将作为此代码的一部分创建的 SageMaker 生命周期配置的名称
现在让我们定义几个助手函数,我们很快就会用到:
正在获取 EMR 主节点的私有 IP:
def get_emr_master_pvt_ip(boto_client_emr, cluster_id):
emr_list_instance_rep = boto_client_emr.list_instances(
ClusterId=cluster_id,
InstanceGroupTypes=[
**'MASTER'**,
],
InstanceStates=[
**'RUNNING'**,
]
)
return emr_list_instance_rep[**"Instances"**][0][**"PrivateIpAddress"**]
这个函数的目的是获取 EMR 主节点的私有 IP,我们稍后将在 SageMaker 生命周期配置中使用它。更多细节:
- 这个函数需要一个 EMR boto 客户端(我们稍后将初始化)和一个 EMR 集群 ID(您可以从 AWS 控制台获得)
- 然后,它使用 EMR boto 客户端,通过 list_instances 函数列出 EMR 集群实例,并传递参数(指定您想要检索其详细信息的集群 ID,指定您想要主节点的详细信息,还指定您只想查询正在运行的实例。它返回一个字典,您可以从中检索所需的值(EMR _ list _ instance _ rep[" Instances "][0][" private IP address "])并将其返回。它返回一个字符串,表示指定的运行 EMR 实例的私有 IP。
呈现 SageMaker 生命周期配置脚本:
def render_emr_script(emr_master_ip):
emr_script = **'''** #!/bin/bash
set -e
# OVERVIEW
# This script connects an EMR cluster to the Notebook Instance using SparkMagic.
#
# Note that this script will fail if the EMR cluster's master node IP address not reachable
# 1\. Ensure that the EMR master node IP is resolvable from the Notebook Instance.
# - One way to accomplish this is having the Notebook Instance and the EMR cluster in the same subnet
# 2\. Ensure the EMR master node Security Groups provides inbound access from the Notebook Instance Security Group
# Type - Protocol - Port - Source
# Custom TCP - TCP - 8998 - $NOTEBOOK_SECURITY_GROUP
# 3\. Ensure the Notebook Instance has internet connectivity to fetch the SparkMagic example config
#
# https://aws.amazon.com/blogs/machine-learning/build-amazon-sagemaker-notebooks-backed-by-spark-in-amazon-emr/
# PARAMETERS
EMR_MASTER_IP={0}
cd /home/ec2-user/.sparkmagic
echo "Fetching SparkMagic example config from GitHub.."
wget https://raw.githubusercontent.com/jupyter-incubator/sparkmagic/master/sparkmagic/example_config.json
echo "Replacing EMR master node IP in SparkMagic config.."
sed -i -- "s/localhost/$EMR_MASTER_IP/g" example_config.json
mv example_config.json config.json
echo "Sending a sample request to Livy.."
curl "$EMR_MASTER_IP:8998/sessions" **'''**.format(emr_master_ip)
b64_encoded = base64.b64encode(emr_script.encode())
return b64_encoded.decode(**'**ascii**'**)
上述功能的主要目的是修改 SageMaker 生命周期配置脚本,以便在启动时,它指向正确的 EMR 主节点。这个 shell 脚本将在创建 SageMaker notebook 时执行,它执行以下步骤:
- 它导航到/home/ec2-user/。sparkmagic 目录
- 然后从一个 URL(https://raw . githubusercontent . com/jupyter-incubator/spark magic/master/spark magic/example _ config . json)下载一个示例 JSON
- 然后,Linux 的 sed 将“localhost”替换为 EMR 主节点的私有 IP,然后将 example_config.json 重命名为 config.json
- 作为最后一步,它卷曲 EMR 主节点,一旦成功互连,就应该成功。
基本前提是您配置 SageMaker 与 EMR 中的 Livy 服务对话,该服务可以配置为在 EMR 集群中运行,并支持 REST 上的交互。该机制用于实现 SageMaker 笔记本和 EMR 之间的集成。
5.在这个函数中,shell 脚本(以多行字符串的形式)被修改为替换值 EMR private IP。稍后将使用该脚本来创建 SageMaker 生命周期配置,该调用要求该脚本是 base64 编码的。这就是为什么您可能已经注意到在函数体中使用 base64.b64encode 等函数,这样做是为了确保它符合要求。
SageMaker 笔记本渲染云模板:
def render_cf_template():cf_template_dct = {
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "CloudFormation template to create simple sagemaker notebook in a subnet",
"Resources": {
"sagemakernotebook": {
"Type": "AWS::SageMaker::NotebookInstance",
"Properties": {
"DirectInternetAccess": "Enabled",
"InstanceType": "ml.t2.medium",
"LifecycleConfigName": "configName",
"NotebookInstanceName": "nbname",
"RoleArn": "<>",
"RootAccess": "Enabled",
"SecurityGroupIds": ["sg-<>"],
"SubnetId": "subnet-<>",
"Tags": core_tags.resource_group_tags,
"VolumeSizeInGB": 5
}
}
}
}
#user defined parameters:
cf_template_dct["Resources"]["sagemakernotebook"]["Properties"]["InstanceType"] = parameters["nb_instance_type"]
cf_template_dct["Resources"]["sagemakernotebook"]["Properties"]["NotebookInstanceName"] = parameters["nb_instance_name"]
cf_template_dct["Resources"]["sagemakernotebook"]["Properties"]["LifecycleConfigName"] = parameters["lifecycle_config_name"]
cf_template_dct["Resources"]["sagemakernotebook"]["Properties"]["RoleArn"] = parameters["RoleArn"]
cf_template_dct["Resources"]["sagemakernotebook"]["Properties"]["SecurityGroupIds"] = parameters["SecurityGroupIds"]
cf_template_dct["Resources"]["sagemakernotebook"]["Properties"]["SubnetId"] = parameters["SubnetId"]
cf_template_dct["Resources"]["sagemakernotebook"]["Properties"]["VolumeSizeInGB"] = parameters["VolumeSizeInGB"]
return json.dumps(cf_template_dct)
在上面的函数中:
- 我们首先以字典的形式指定 SageMaker 笔记本的云信息模板。
- 然后,我们根据参数字典中的值更新这个字典。具体来说,我们更新:
a.实例类型
b .实例名
c .生命周期配置名
d .角色 ARN
e .安全组
f .子网 Id
g .卷大小调整 b
SageMaker 笔记本的一部分,该部分将作为此代码的结果进行配置。
所有助手功能就绪后:
session = boto3.Session(profile_name="<>")
client_cf = session.client("cloudformation")
client_sm = session.client("sagemaker")
client_emr = session.client("emr")
我们使用您已经在系统中配置的 IAM 配置文件初始化 boto3 会话。确保与 IAM 配置文件对应的用户通过 IAM 策略(直接附加或附加到用户所属的组)拥有足够的权限来执行手头的任务。
然后,我们使用会话对象创建三个 boto3 客户端:
- 云的形成
- SageMaker
- (同 electromagneticriveting)电磁铆
因为它们很快就会被使用。
emr_master_pvt_ip = get_emr_master_pvt_ip(client_emr,parameters[**"emr_cluster_id"**])
然后我们调用 get_emr_master_pvt_ip 函数来获取 emr 主节点的私有 ip。这将以字符串的形式返回其 IP。
有了 EMR master 的私有知识产权,我们就有能力制定 SageMaker 的生命周期政策:
print(**"creating SM lifecycle config"**)
lc_config_rep = client_sm.create_notebook_instance_lifecycle_config(
NotebookInstanceLifecycleConfigName=parameters[**"lifecycle_config_name"**],
OnCreate=[
{
**'Content'**: render_emr_script(emr_master_pvt_ip)
},
]
)
我们使用 SageMaker boto 客户端(client_sm)及其函数(notebook _ instance _ life cycle _ config)来创建生命周期配置并传递所需的参数。特别是,对于 OnCreate 参数,我们调用 render_emr_script 函数,该函数将使用 base64 编码的 emr 主私有 IP 返回呈现的生命周期配置脚本。
运行该程序后,您应该能够验证已经在 SageMaker 中创建了一个生命周期:
您可以通过单击配置名称并单击“查看脚本”来进一步验证您的脚本是否已使用 EMR 主专用 IP 地址正确呈现(查找 EMR_MASTER_IP 变量的值):
现在创建了生命周期配置,让我们启动 SageMaker 笔记本。
rendered_cf_template = render_cf_template(parameters)
我们调用 render_cf_template 函数来根据需求渲染 CloudFormation 模板。这将给出一个字符串形式的 CloudFormation 模板,我们将在下一步中使用它:
create_stack_response = client_cf.create_stack(
StackName=parameters[**"stack_name"**],
TemplateBody=rendered_cf_template,
ResourceTypes=[
**'AWS::SageMaker::NotebookInstance'**,
],
OnFailure=**'ROLLBACK'**,
EnableTerminationProtection=False
)
因此,我们利用 CloudFormation boto3 客户端来创建一个堆栈(当您想要通过 CloudFormation 部署资源时,您可以创建一个堆栈)。在参数中,您可以注意到我们正在传递渲染的 CloudFormation 模板和一些其他方便的设置(例如,在失败时,我们希望回滚发生,并且终止保护设置为 false,以便可以通过编程直接终止)
执行后,需要一段时间才能完成,因为这将启动 SageMaker notebook 的启动过程。完成后,您会注意到 AWS 控制台中的 CloudFormation 部分将显示成功,如下所示:
关键时刻:您可以在 SageMaker 笔记本中验证它也成功地与 EMR 集成:
正如您所看到的,如果您推出一款采用 SparkMagic (PySpark)内核的笔记本电脑,您将能够成功使用 Spark API,并可以将这款笔记本电脑用于探索性分析和大规模特性工程,而 EMR (Spark)则在后端执行繁重的工作!
希望这篇文章有深刻的见解。如果你有兴趣了解更多关于 Spark 的知识,可以看看我在 Udemy 上最畅销的课程和最近推出的书籍。
在您的工作场所启动生产级人工智能
人工智能风靡一时,许多技术人员已经扩大了人工智能和人工智能知识的规模。然而,想出一个好的生产级工业人工智能完全是另一回事。我想我会分享一些我自己在这个主题上的学习,并给你一个框架,列出你需要解决问题的领域,然后让人工智能在你的工作场所发生
步骤 0
评估数据的质量。你的人工智能将基于你捕获的关于你的用户的独特数据集。你的数据是你的秘方,而不是你的人工智能算法。您需要提出自己独特的数据验证框架,从完整性(您的数据中是否有太多漏洞)、可信度(您存储在后端云中的位和字节是否与现实世界的证据相匹配)等方面评估您的数据集。提示:不要被数据集的大小所迷惑。如果你的数据集已经捕获了许多关于你正在解决的人工智能问题陈述的变化,千兆字节的数据集也是好的。
基于你对数据质量的评估,决定你是想要组织一个团队来破解人工智能还是继续以一种特别的方式做人工智能
第一步
扁平化您的事务/运营数据库,构建您的数据工程。让你的人工智能工程师从一个杠杆的位置工作。事务性数据库设计旨在实现高读/写吞吐量。并不意味着运行调查性查询来理解/探索数据洞察力。根据你计划解决的人工智能问题的类型,为你的人工智能数据模型建模,以简化和方便调查。这一步的一部分还包括弄清楚你的数据工程管道(Kafka/Airflow/ECS 等)和架构。
第二步
使用标准词汇注释数据。这有两个好处。首先,不同的源系统可以使用不同的语义标签来说同样的事情,但标准化可以确保你有一个统一的词汇来运行人工智能。其次,标准词汇表也可以与您所在行业的标准层次结构结合使用。基本上这个世界上没有什么是孤立存在的,你会想要在你的数据集中注入本体或领域知识,以推动更好的人工智能推理。
第三步
确定您的最终目标,以推动产品的关键业务指标。这是人工智能的标准产品路线图练习。
第四步
基于上述内容,确定抽象数据科学平台的目标。不要每次都从头分析。最好确定更广泛类别的人工智能问题陈述,并装备您的数据平台来处理此类情况。
第五步
基于以上选择人工智能问题的类别并构建->测试->部署->学习和重复。这一步的问题陈述的一部分也是弄清楚你的整个 ML DevOps 策略。
希望这有用。
机器学习领域的劳雷尔和哈迪
Source: Flickr
“好吧,你又给我惹了一个大麻烦!”
本周,我引用了更早的资料,一直追溯到 20 世纪 30 年代。万一一些千禧一代的读者只是想“OK Boomer”,我想澄清一下,我自己也是千禧一代。只是有时候旧时代的参考比现代的更有意义。
所以,对于那些不知道劳雷尔&哈代的人,我建议你们在继续阅读之前,先去 Youtube 上看几个视频。对于那些有幸经历过这一对搭档的人来说,我希望你能看到我接下来要说的相似之处。
机器学习的 Laurel & Hardy 被称为偏差和方差。就像劳雷尔和哈代一样,偏见和差异交织在一起。虽然两者都可能导致你的模型出现重大错误,但与 Laurel 和 Hardy 不同,他们理解错误在让人发笑方面的力量,在机器学习中,错误可不是闹着玩的。如果你不注意偏见和差异,它们会让你丢掉工作。
为了帮助你避免陷入困境,让我们看看为什么机器学习的 Laurel & Hardy 值得你关注。
差异
Stan Laurel, Source:Flickr
“你可以把马牵到水边,但必须牵着一支铅笔.”—劳雷尔
这部剧的粉丝会记得劳雷尔有真正好的想法。他会想出一个有趣的做事方法,并与哈代分享,然后哈代会去“再告诉我一遍”。这些话一出口,劳雷尔就会犯错误,第二次给出他的想法的一个完全荒谬的版本。
劳雷尔举例说明了机器学习中的差异。方差是你的模型的错误,当它不能推广到它以前没有见过的数据。如果你稍微改变一下数据,模型的预测就会完全偏离。就像劳雷尔的“再告诉我一遍”的每次迭代都会导致不同的答案一样,如果你的机器学习模型具有非常高的方差,也会发生同样的情况。
换句话说,你的模型将随着信号学习噪音,所以如果有一个从铅丢失,它将不能简单地分离东西!
偏向
Oliver Hardy, Source:Flickr
“你实际上在用你的大脑。这就是与我交往的结果。”—哈代
另一方面,当劳雷尔第一次分享他的想法时,他从来没有理解过劳雷尔,至少对观众来说,他的想法是清楚的。然而,哈代有一种不可思议的能力,能够理解劳雷尔第二次脱口而出的非荒谬的版本。
显然,哈迪很难将信号从噪音中分离出来,这就是偏见。简单来说,偏差可以定义为由于模型无法从训练数据中学习到任何东西而导致的错误。
换句话说,如果你只是简单地使用你的大脑,而不是使用一个有高度偏见的模型,你会看起来更聪明。
那又怎样?
老样子来了那又怎样?你为什么要关心这些可怕的强制类比呢?你必须关心它们,因为每个机器学习问题都是关于平衡两者之间的权衡。
Source: elitedatascience.com
如果你的模型有很高的偏差,那它就是学习得不够(或者根本没有学习),所以这就打败了机器学习的意义。例如,这可能会发生,因为您正在对非线性问题使用线性回归。所以,一个从耐寒到耐寒的方法是使用更复杂的模型。
如果你让你的模型变得太复杂,比如用一个复杂的反推 SVM,Laurel 开始产生铅笔和马的幻觉,就像我刚刚产生了模型名字的幻觉一样,所以你也要避免这种情况。
基本上,你需要做的是在两者之间找到一个平衡点,一个劳雷尔&哈代和你和谐相处的快乐之地。
直到你让自己陷入另一个烂摊子!但这就是数据科学家的生活,不是吗?
现在,如果你们中的任何人已经遭受了这种痛苦,下面我提供了一个链接,可以更好地解释偏差和方差的权衡,这可能会帮助你的大脑从刚刚阅读的内容中恢复过来:
https://elitedatascience.com/bias-variance-tradeoff
人工智能和法律技术的采用
Photo by @chrisyangchrisfilm
责任、不断增加的压力和量化律师
我们可以随心所欲地谈论道德,但在某一点上,政治中争论已久的对与错将会变成法律。微软等大型科技公司及其总裁辩称:“科技公司必须停止‘如果合法,那就是可以接受’的做法。”据《卫报》(Hern,2019)报道。微软现在是一家价值一万亿美元的公司。然而,不仅仅是科技公司必须三思而后行,在新法规出台前做到合法。适应得越快越好还是越差,法律职业在技术中会是什么样子?
法律技术 又称法律技术,是指利用技术和软件提供法律服务。
法律技术采用
英国法律协会于 2019 年 2 月发布了一份名为 LawTech 收养研究的报告。这份报告是由科技分析师 TechMarketView (TMV)撰写的。法律协会代表英格兰和威尔士 190,000 多名律师。
根据该报告:“近年来,法律科技公司的数量有所增加,但法律从业者采用法律科技的比率并没有加快。” (TechMarketView,2019)因此,技术创新似乎不会立即成为问题,但是,公司选择适应这种变化的方式可能是,而且确实是相关的。现在下结论可能太快了。
TechMarketView 发现并调查了 100 多家在英国运营的法律技术公司。许多是由律师或前律师提出的“单点解决方案”。其他法律技术供应商是技术提供商,最初服务于金融服务等其他行业,现在正转向法律市场。
“我发现初创企业很难打交道。我接触过的一些公司似乎是由一个心怀不满的律师建立的,他碰巧和一个 IT 人员一起去了大学。我只是觉得,他们中很少有人真正在做什么新的事情,他们往往分为三种主要类型:生成文档、审阅和分析文档或分析管理信息,如法律支出或工作流程。他们不一定是在重新发明轮子,而是希望提供一个更闪亮的新轮子”。
然而,尽管传统律师可能不同意或涉及现有的解决方案,但不同的行为者都有采用新技术的压力,这在同一份报告中有所概述。
Image by techMarketView in the report LawTech Adoption Research retrieved the 21st of September 2019.
我将列举这些不同报告中提出的几个要点:
- 客户 :应对客户收费压力的效率和生产力,以及律师展示他们如何为客户利益创新的需要。
- 一般委员会 期望在相同的预算内看到更多的尽职调查或电子发现。
- 对透明度的需求 。客户压力直接转化为法律技术采用的一个领域是法律成本透明度。计费有时很抽象和困难,这可能会改变。
- 对新工作方式的需求 。客户对律师事务所施加越来越大的压力,要求他们以更低的成本办事,在某些情况下,客户甚至要求律师事务所在其服务中加入特定的技术解决方案。
- 来自适应更快的会计服务提供商的竞争 。“英国所有的‘四大’会计服务提供商现在都有一个法律部门。2014 年初,普华永道的法律业务获得 ABS 资格,同年晚些时候,毕马威和 EY 获得 SRA 批准。2018 年 6 月,德勤英国被授予 ABS 资格。
- 炒作。与 lawtech(特别是人工智能和机器学习技术)相关的炒作和宣传对提高整个法律部门的认识产生了积极影响。
- 调控驱动 。已经为金融服务和银行业提供解决方案的所谓“regtech”公司已经开始转向法律领域
- 遗留 IT 系统 s .通过用机器人维护现有流程自动化,在某些情况下需要最终迁移到新系统上。
- 【律师事务所开业】 对技术和 IT 提出了更高的要求,以提供移动工作环境。
- 改变人口统计 。你可能会发现更多的人从大学选修了计算机科学模块和法律。越来越多的模块侧重于法律技术或法律技术。
- 缺少律师 。在某些情况下,缺乏律师,或者有些人无法接触律师。这在家庭法等领域可以有所改变(这些领域一直缺乏律师)。
- 云应用 。云计算降低了进入各种应用程序的成本和商业壁垒,随着传统案例管理系统或实践管理系统的生命周期结束,这些应用程序可以进入企业。
机器人流程自动化 (RPA)是用于部分或全部自动化人工、基于规则和重复的人类活动的软件工具的术语。
总法律顾问 ,首席法律顾问,或首席法务官(CLO)是法律部门的首席律师,通常在公司或政府部门。
定量律师
不久前,金融服务行业在其领域中创建了一个新的方向。他们被称为**‘quants’或数量统计学家** ,专门研究应用数学和统计方法解决金融和风险管理问题。
Khandani 在一篇论文中指出,通过间接手段,2007 年 8 月 6 日至 10 日的事件可能是一个或多个大型多空股票投资组合快速平仓的结果,最有可能的是最初的量化股票市场中性投资组合。因此,这可能是 2007-2008 年大规模金融危机的部分原因(Khandani,2007)。
如果定量统计、情感分析等正在进入法律领域,这是一个警告。如果律师或法律行业的其他人认为自己比金融行业更擅长管理风险,这可能是一个滑坡——相对较小的第一步会导致一系列相关事件,最终导致一些重大(通常是负面)影响。或许我们可以希望,正是考虑到这一点,法律行业在适应技术方面经历了如此艰难的时期,但我怀疑事实是否如此。
无论如何,这是很重要的,因为法律职业可能会变得与技术更加融合,法律从业者习惯于超越眼前的利益,看到潜在的风险。让我举几个假设。
- 想象一下,一份符合当地法规的合同为 100,000 人提供简单的保险索赔,您可以自己拍摄并发送。
- 维护社交媒体平台上数十亿用户的条款和条件。通过从政府法律公告中“抓取”在线文本,并根据当地参与者的分析进行预测,不断监控改革,以适应世界上大多数国家的当地法规。
- 在一家大型国际公司中整理 40,000 份文档,以找到支持诉讼的历史数据,同时在线运行情绪分析,以找到受影响的受害者。
在所有这些情况下:什么会变得糟糕透顶?在法律失控的最坏情况下,我们能期待看到什么?
在最好的情况下,利用技术的伟大法律实践会是什么样的呢?
法律中的人工智能
有人说,法律的核心是语言,所以长期以来,基于自然语言运行的软件在法律职业的一些领域发挥了作用,这并不奇怪。
自然语言处理: 通常简称为 NLP,是人工智能的一个分支,利用自然语言处理计算机与人类之间的交互。
关于法律技术的许多争论和宣传焦点都集中在人工智能上。这可能是由于客户在展示创新方面的压力(通常通过新闻稿分享)。许多人可能高估了人工智能增强运营的潜力。这些技术似乎首先被英国的大公司采用,后来被小公司采用。因此,你最终只能在价格上竞争。
技术并不能解决一切。吸收一份文件并提取出标准的东西是很容易的,但理解合同语言却不容易。因此,在法律背景下,要确信已经提取了所有关键数据点并不那么容易。几乎没有标准的合同语言或带有标签的信息保密示例,因此这带来了一些困难。
人工智能可以帮助降低风险,通常是通过在诉讼过程中协助律师。这也是非常重要的,因为只审查十分之一的文件会有什么样的风险?该报告问道:“十分之一由人类审阅的文档比婴儿人工智能系统查看每一份文档的风险低吗?”我非常确定这个问题的答案并不简单。
法律技术的三个领域
《法律技术应用研究报告》将法律服务细分为三个具有不同需求的领域。
- 企业对企业(B2B)律师事务所
- 企业对消费者(B2C)律师事务所
- 内部法律部门(主要在大型商业或公共部门组织中)。
法律技术领域
在英国的法律技术领域,有更多的参与者,他们在上述报告中得到了相对简洁的总结。
Image by techMarketView in the report LawTech Adoption Research retrieved the 21st of September 2019.
在过去的四年里,一小群公司已经在法律市场上站稳了脚跟。像 Kira、Luminance 和 RAVN(现在的 iManage )这样的供应商已经在 B2B 领域获得了牵引力。
Apperio正在帮助公司分析他们的法律支出,并在 2018 年年中在 A 轮融资中筹集了 1000 万美元(750 万英镑)。今年,Clarilis、Lexoo 和 Juro 等公司在 2000 万至 1000 万英镑之间进行了融资,这种情况在几年前还是闻所未闻的。
除此之外,还列出了具体的应用程序,以便更好地理解技术和应用程序可以集成或包含在哪里。这些也构成了研究的重点。
结论
在处理新问题时,我们必须确保不要制造太多的新问题。从某种程度上来说,法律行业在改变其做法上如此缓慢是不可避免的,也许这是更好的。这仍有待观察,因为法律公司可能会尝试在更大程度上用数学和统计学以及计算机科学来量化信息。英国市场上有大量的解决方案,在这个重要的领域可能会有一大批新的竞争者。
如果你有兴趣阅读更多关于 LawTech 的内容,我以前写过另一篇关于这个主题的文章:
人工智能领域的不同法律应用
medium.com](https://medium.com/dataseries/artificial-intelligence-and-lawtech-4d7181a03202)
一个响亮的旁注——存在气候危机
除了我们能与法律行业合作的令人兴奋的新技术方法之外,一个更相关的问题是这些创新者应该关注什么。一个可能的地点当然是当前的气候危机和这一领域的法律应用。超过 30 万人走上悉尼街头,但 9 月 20 日,数百万人走上街头抗议,要求我们更加严肃地对待气候危机,减少排放。哪个创新的律师会使用这些新技术来解决气候变化的问题?这是今天的一个深刻的旁注。
Sydney as shared by Greta Thunberg
参考
戴尔河(2019)。法律与词序:法律技术中的自然语言处理。自然语言工程, 25 (1),211–217。
鲍勃·古德曼(2014 年 12 月 16 日)。《聪明的创业公司颠覆法律的四个成熟领域》。今日法律技术。检索时间 2019 年 9 月 20 日。
Hern,A. (2019 年 9 月 20 日)。微软老板:科技公司必须停止“如果合法,就可以接受”的做法。检索自https://www . the guardian . com/technology/2019/sep/20/Microsoft-boss-tech-firms-must-stop-if-its-legal-its-acceptable-approach
汉达尼和罗(2007 年)。2007 年 8 月,宽客发生了什么?。可在 SSRN 1015987 处获得。
TechMarketView。(2019 年 2 月)。法律技术采用研究报告。检索自https://www . law society . org . uk/support-services/research-trends/law tech-adoption-report/
这是第 500 天的第 109 天。我目前第 101-200 天的重点主要是 Python 编程,但是今天我决定进入 lawtech,因为明天我将在一个黑客马拉松中与一个团队就这个具体问题进行合作。如果你喜欢这篇文章,请给我一个答复,因为我确实想提高我的写作或发现新的研究,公司和项目。
反向传播入门
训练一个神经网络不是一件容易的事,但理解它可能很简单
反向传播是调整神经网络的权重以提高预测精度的过程。神经网络中的信息流动有两个方向。
- **前向传播——也称为推理——**是指数据进入神经网络并弹出预测。
- 反向传播 —通过查看预测和实际结果之间的差异来调整权重的过程。
Photo by Pankaj Patel on Unsplash
反向传播是在神经网络准备部署到现场之前完成的。人们使用已知结果的训练数据来执行反向传播。一旦我们确信网络得到了充分的训练,我们就开始推理过程。
如今,反向传播就是使用无数工具中的一个命令。因为这些工具很容易训练神经网络,大多数人倾向于跳过理解反向传播背后的直觉。可以理解,当数学看起来像这样。
Andrew Ng’s Coursera course: https://www.coursera.org/learn/machine-learning
但是,在如此多的机器智能的核心过程背后获得一种直觉是非常有意义的。
权重在神经网络中的作用
在试图理解反向传播之前,让我们看看权重实际上如何影响输出,即预测。第一层的信号输入通过控制相邻层神经元之间连接强度的权重向前传播到网络中。
Source: http://tuxar.uk/brief-introduction-artificial-neural-networks/
训练网络意味着微调其权重以提高预测精度
调整权重
一开始,神经网络的权重是随机的,因此预测都是错误的。那么,我们如何改变权重,以便当给一只猫看时,神经网络以很高的可信度预测它是一只猫呢?
- 一次一个权重:训练网络的一个非常基本的方法是改变一个权重,同时保持其他权重不变。
- **权重组合:**另一种方法是在一个范围内(比如从 1 到 1000)随机设置所有权重。可以从全 1 开始,然后全 1 和一个 2 等等。组合看起来像这样— (1,1,1),(1,1,2),(1,2,1),(1,2,2),(2,2,2),(2,2,3)
为什么这两种方法都不好?
这是因为如果我们尝试 N 个权重的所有可能组合,每个组合的权重范围从 1 到 1000,这将花费大量的时间来筛选解空间。对于运行在 1GHz 的处理器,2 个神经元的网络需要 1⁰⁶/1⁰⁹ = 1 毫秒。对于 4 个神经元的网络,相应的处理时间将是 16 分钟,并且对于更大的网络,处理时间将保持指数增长。
The Curse of Dimensionality
对于 5 个神经元网络来说,这将是 11.5 天。这就是维度的诅咒。一个真正的神经网络将有 1000 个权重,需要几个世纪才能完成。
这就是反向传播的用处
一旦你对反向传播有了直观的认识,数学就很容易理解了。假设一家公司有 2 名销售人员、3 名经理和 1 名首席执行官。反向传播是首席执行官向中层管理人员提供反馈,他们反过来又向销售人员提供反馈。
每一层的员工都向所有后续层的经理汇报,用箭头的宽度表示不同的“强度”。因此,一些员工比其他人更经常向一位经理汇报工作。此外,CEO 认为设计经理(第二层的底层神经元)的意见比销售经理(自行车骑手)的意见更重要。
每次销售完成后,首席执行官都会计算预测结果和预期结果之间的差异。这位首席执行官稍微调整了一下,他希望对哪位经理的话给予多大的“权重”。经理汇报结构也根据首席执行官的指导方针而改变。每位经理都试图以一种让他/她更了解情况的方式重新调整权重。
Top Down: Backpropagation happening after CEO receives wrong inputs from Middle Management
首席执行官重新调整对中层管理人员的信任。
这种将反馈传播回前几层的过程就是它被称为反向传播的原因。
首席执行官不断改变他的信任级别,直到客户的反馈开始符合预期的结果。
一点点数学知识
Source: https://www.xkcd.com/435/
一撮数学 一个神经网络的成功是用代价函数来衡量的。花费越少,训练越好。目标是以最小化成本函数的方式修改权重。
所以两个重要的术语—
- 误差 =预期与现实之间的差异
- 成本函数的梯度 =改变权重时成本的变化。
反向传播包含单词“back”。这意味着我们从输出回到输入。我们看看错误是如何反向传播的。
看看δˡ是如何依赖δˡ⁺的
http://neuralnetworksanddeeplearning.com/chap2.html
如果你仔细观察,方程的第二项有一个 z。我们在那里测量 z 变化的速度。这告诉我们误差会变化多快,因为δˡ也依赖于 z =神经元的输出。
http://neuralnetworksanddeeplearning.com/chap2.html
右边的第一项只是衡量成本作为第 j 个输出激活的函数变化有多快。右边的第二项测量第 j 个神经元输出端的激活函数σ变化有多快。
结果向前流,错误向后流。由于我们反向传播误差,我们需要误差如何在两个相邻层之间流动的数值表示。成本相对于重量的变化率由下式给出
http://neuralnetworksanddeeplearning.com/chap2.html
有了这些基础,反向传播算法可以总结如下
http://neuralnetworksanddeeplearning.com/chap2.html
从机器学习的角度考虑实际问题
- 即使反向传播也需要时间。最好把输入的数据分批次。(随机梯度下降)。
- 训练数据越多,权重调整越好。通常,神经网络需要数千个预先标记的训练样本。
反向传播虽然现在很流行,但在引入时也遭到了反对。许多著名的科学家和认知心理学家(包括著名的英国认知心理学家 Geoff Hinton)都不相信反向传播。反向传播由于很多原因而面临反对,包括它不能代表大脑如何学习。
Quora answer
尽管如此,它仍然是一个非常广泛使用的和非常有效的训练神经网络的方法。目前,专门的硬件正在开发,以更有效地执行反向传播。
** [## 自我学习人工智能:这种新的受神经启发的计算机自我训练
来自比利时的一组研究人员认为他们已经接近扩展摩尔定律的预期终点,他们…
futurism.com](https://futurism.com/self-learning-ai-this-new-neuro-inspired-computer-trains-itself)**
外行人对 KNN 的介绍
k-最近邻算法是大多数人在开始机器学习时的起点。
kNN 代表 k-最近邻。它是一个监督学习算法。这意味着我们在监督下训练它。我们使用已有的标签数据来训练它。给定一个由观察值 ***(x,y)***组成的带标签的数据集,我们希望捕获 x —数据和 y —标签之间的关系。更正式地说,我们想要学习一个函数 g : X→Y 以便给定一个看不见的观察值 X , g(x) 可以自信地预测相应的输出 Y 。
Source: Edureka
kNN 实现起来非常简单,在任何机器学习设置中被广泛用作第一步。它通常被用作更复杂分类器的基准,如人工神经网络(ANN)和支持向量机(SVM)。尽管简单,k-NN 可以胜过更强大的分类器,并用于各种应用,如经济预测,数据压缩和遗传学。
- 遗传学
随着各种功能基因组学和蛋白质组学技术的出现,越来越需要…
bmcbioinformatics.biomedcentral.com](https://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-7-S1-S11)
- 农业
[## 用现场数据、航空数据估算火炬松人工林的林分高度和树木密度
准确的森林库存对于优化纸浆和造纸行业的整个供应链管理具有重要的经济意义
www.scielo.br](http://www.scielo.br/scielo.php?pid=S0001-37652018000100295&script=sci_arttext)
- 航空— 空中交通流量预测
[## 基于 k 近邻回归的空中交通流量预测
为了提高空中交通流量的预测精度,提出了将 k 近邻回归应用于空中交通流量预测的方法
ieeexplore.ieee.org](https://ieeexplore.ieee.org/abstract/document/8630470)
正如 20 世纪初的大多数技术进步一样,KNN 算法也诞生于为军队所做的研究。美国空军航空医学院的两个办公室——Fix 和 Hodges (1951) 写了一份技术报告,介绍了一种用于模式分类的非参数方法,这种方法后来成为流行的 k-最近邻(kNN)算法。
Source: DTIC — The Declassified Paper in full.
它是如何工作的?
假设我们有一个包含两种点的数据集,即标签 1 和标签 2。现在给定这个数据集中的一个新点,我们想找出它的标签。kNN 的做法是通过其最近的 k 个邻居的多数投票。k 可以取 1 到无穷大之间的任何值,但在大多数实际情况下,k 小于 30。
蓝色圆圈 v/s 橙色三角形
假设我们有两组点——蓝色圆圈和橙色三角形。我们要将测试点= *带问号的黑色圆圈,*归类为蓝色圆圈或橙色三角形。
目标:给黑圈贴标签。
对于 K = 1,我们将着眼于第一个最近的邻居。因为我们采取多数投票,并且只有一个投票人,所以我们将其标签分配给我们的黑色测试点。我们可以看到,对于 k=1,测试点将被归类为蓝色圆圈。
将我们的搜索半径扩大到 K=3 也保持了相同的结果,只是这次不是绝对多数,是 3 中的 2。仍然在 k=3 的情况下,测试点被预测为具有蓝圈类别→因为大多数点是蓝色的。
我们来看看 k=5 和 K =9 是怎么做的。为了查看最近的邻居,我们以测试点为中心画圆,当 5 个点落在圆内时停止。
当我们观察 5 以及随后的 K = 9 时,我们测试点的大多数最近邻都是橙色三角形。这表明测试点必须是一个橙色的三角形。
Left→K=5, Majority = Orange | Right→K =9, Majority = Orange
既然我们已经标记了这一个测试点,我们对所有未知点重复相同的过程(即测试集)。一旦使用 k-NN 标记了所有的测试点,我们尝试使用判定边界来分离它们。决策边界显示了训练集的分离程度。
k-NN Live!
这就是 k-NN 如何发生的要点。让我们从一个机器学习工程师大脑的角度来看。
首先他们会选择**k。**我们在上面已经看到,k 越大 k 的票数就越多。这意味着正确的几率更高。但是你说,代价是什么?
获得 k 个最近邻意味着对距离进行排序。那是一个昂贵的手术。需要非常高的处理能力,这意味着更长的处理时间或更昂贵的处理器。K 值越高,整个过程的成本越高。但是过低的 k 会导致过度拟合。
非常低的 k 将不能概括。非常高的 k 值是昂贵的。
K = 1, 5, 15. Source code below.
当我们达到更高的 K 值时,边界变得平滑。蓝色和红色区域大致分开。一些蓝红战士被留在了敌后。它们是附带损害。它们说明了训练准确性的损失,但是导致了更好的概括和高测试准确性,即新点的正确标记的高准确性。
相对于 K 绘制的验证误差图通常如下所示。我们可以看到,在 K = 8 左右,误差最小。它在任何一边上升。
Left : Training error increases with K | Right : Validation error is best for K = 8 | Source: AnalyticsVidhya
然后他们会尝试找出点与点之间的距离。我们如何决定哪些邻居是附近的,哪些不是?
- 欧几里德距离—最常见的距离度量
- 切比雪夫距离— L∞ 距离
- 曼哈顿距离-L1 距离:它们的坐标的(绝对)差之和。
在国际象棋中,棋盘上车的方格之间的距离用曼哈顿距离来度量;国王和王后使用切比雪夫距离——维基百科
All 3 distance metrics with their mathematical formulae. Source: Lyfat
一旦我们知道如何根据距离来比较点,我们就会训练我们的模型。**k-NN 最好的一点是没有明确的训练步骤。**我们已经知道了关于数据集的所有信息——它的标签。本质上,算法的训练阶段仅包括存储训练样本的 特征向量 和类别标签。
The Tinkersons, December 2, 2017
K-NN 是一个懒惰的学习器,因为它不从训练数据中学习判别函数,而是记忆训练数据集。
一个渴望学习的人有一个模型拟合或训练步骤。懒惰的学习者没有训练阶段。
最后,为什么是 k-NN?
- 快速实现:这也是它作为基准算法受欢迎的原因。
- 较少的培训时间:更快的周转时间
- 可比较的准确性:正如许多研究论文中指出的,它的预测准确性对于许多应用来说是相当高的。
当一个人必须快速交付一个具有相当准确结果的解决方案时,k-NN 是一个救命稻草。在大多数工具中,如 MATLAB、python、R,它是作为一个单行命令给出的。尽管如此,这是非常容易实现和有趣的尝试。
R 图的源代码
library(ElemStatLearn)
require(class)**#Data Extraction**
KVAL <- 15
x <- mixture.example$x
g <- mixture.example$y
xnew <- mixture.example$xnew**#KNN and boundary extraction**
mod15 <- knn(x, xnew, g, k=KVAL, prob=TRUE)
prob <- attr(mod15, "prob")
prob <- ifelse(mod15=="1", prob, 1-prob)
px1 <- mixture.example$px1
px2 <- mixture.example$px2
prob15 <- matrix(mod15, length(px1), length(px2))**#Plotting Boundary**
par(mar=rep(2,4))
contour(px1, px2, prob15, levels=0.5, labels="", xlab="x", ylab="y", main="", axes=TRUE)**#Plotting red and blue points**
points(x, pch = 20, col=ifelse(g==1, "coral", "cornflowerblue"))gd <- expand.grid(x=px1, y=px2)
points(gd, pch=".", cex=0.001, col=ifelse(prob15>0.5, "coral", "cornflowerblue"))
legend("topright", pch = c(19, 19), col = c( "red","blue"), legend = c( "Class 1", "Class 2"))
title(main="Boundary for K=15", sub="ii", xlab="Feature 1", ylab="Feature 2")
box()
线性回归入门
当你的数据遵循直线趋势时,线性回归是你的朋友
线性回归试图通过将线性方程(=直线)拟合到观察到的数据来模拟两个变量之间的关系。一个变量被认为是解释变量(如你的收入),另一个被认为是因变量(如你的支出)。
线性回归所做的就是简单地告诉我们一个任意的独立/解释变量的因变量**的值。**例如,基于 Twitter 用户数量的 Twitter 收入。
从机器学习的角度来看,这是可以在你的数据上尝试的最简单的模型。如果您预感到数据遵循直线趋势,线性回归可以给你快速且相当准确的结果。
简单的预测都是线性回归的情况。我们首先观察趋势,然后根据趋势预测,例如,你必须刹车的力度取决于你前面汽车的距离。然而,并非所有情况都遵循线性趋势。例如,从 2015 年到 2016 年,比特币的上涨是线性的,但在 2017 年,它突然变成了指数级的。因此,线性回归无法很好地预测 2017 年后的比特币
因此,重要的是要理解,即使线性回归可以是理解数据的第一次尝试,它也不总是理想的。
这是我们做线性回归的方法
- 我们将因变量(y 轴)与自变量(x 轴)相对照
- 我们试图绘制一条直线,并测量相关性
- 我们不断改变直线的方向,直到得到最佳相关性
- 我们从这条线推断出 y 轴上的新值
外推是基于“一些信息”来“做出预测”
这对于区分作为统计技术的线性回归和作为机器学习算法的线性回归是至关重要的。ML 更关心预测,统计更关心参数推断
术语方面
预测’ =因变量和
‘一些信息’ = 自变量。
线性回归为您提供了一条直线,让您推断因变量
示例—啤酒控制
线性回归的核心是一种寻找代表一条线的参数值的方法。
方程 Y=mX+C
根据坐标几何,如果因变量称为 Y ,自变量称为 X ,那么一条直线可以表示为 Y = m*X+c 。其中 m 和 c 是两个数字,线性回归试图计算出这两个数字来估计白线。
看下图。假设你决定意识到自己喝了多少酒。
你看到了什么?你每月大约喝多少啤酒?一个简单的观察显示你每个月大概喝 9-10 品脱(不错!).
你认为趋势线会是什么样子?年底有多少啤酒?
120 Beers in a year. Imagine that!
一个简单的线性回归显示了我们可以清楚地看到什么。Y = 10.027X + 0.0455 = > m=10.027,c = 0.0455
c 是一个很小的数,所以现在我们忽略它。看看这个直线方程告诉我们,每个月我们要喝 10.027 瓶啤酒。这就是趋势。我在 MS PowerPoint 中推导出了这个等式,但是我们如何用数学方法来推导呢?
机器学习工程师是如何做到这一点的?
线性回归的一般方程
请原谅我。这一部分有一点数学,但我们将轻松地通过它。
线性回归是监督学习的一种形式。监督学习涉及那些我们使用现有数据来训练机器的问题集。在啤酒的例子中,我们已经知道了前 10 个月的数据。我们只需要预测第 11 个月和第 12 个月的数据。
线性回归可能涉及多个独立变量。例如,房价(依赖)取决于位置(独立)和土地面积(独立),但其最简单的形式涉及一个独立变量。
在其通用形式中,它被写为
其中所有的阿尔法都是我们的机器学习算法需要计算的系数。x 是已知的,因为它们是独立的。我们可以给他们设定任何东西。我们需要找到的是 Y 。
对于单个独立变量,方程简化为
Simple Linear Regression
为简单起见,x0 设为等于 1,alpha0 命名为 c。x1 称为 x,alpha1 = m。它简化为:
Simple Linear Regression written slightly differently
行话
为了算出 mm和 c我们画了一条线,使用 m 和 c 的初始猜测通过我们已经有的一组点。我们计算这条线到这些点的距离。我们取这些距离 ( 成本函数)平方和的平方根。我们不断地改变 m 和 c,看看这个成本函数是否减少。当成本停止下降时,我们确定 m 和 c 为最终结果。得到的线是我们对数据的最佳线性拟合。现在对于任何新的 x,我们可以用这条线算出 y。**
这个行话的意思是,我们不断地重画这条线,直到它看起来最符合数据。这就是所有需要的行话。
机器学习
下面我们有一个人口与利润的数据集。我们画一个散点图,并试图拟合一条穿过它的直线。仔细观察最初的猜测(蓝线)如何向数据所遵循的趋势转变。还要看看需要多少次迭代才能达到 5.87 的稳定成本
它以 32 英镑的价格开始,最初的猜测差得很远!
从那时起,情况稳步改善。经过 200 次迭代后,成本已经减半。
400 次迭代后,成本是 1/3
在 600 次迭代时,猜测进一步提高
在 1000 次迭代之后,成本的降低已经减缓,并且拟合或多或少是稳定的
经过 3000 次迭代后,我们确信我们有一个很好的拟合
c = 0.02, m = 0.8
就这么简单!显而易见的是,线性回归是一种基于遵循线性趋势的数据进行预测的简单方法。因此,如果我们要拟合正弦曲线或圆形数据集,我们将会彻底失败。
最后,对于初学者来说,线性回归总是很好的第一步(如果数据在视觉上是线性的)。这绝对是一个很好的第一个学习目标!
来自我们数据科学团队初级成员的领导力课程
如果你知道如何去寻找,智慧无处不在
Photo by Annie Spratt on Unsplash
我们都从老板那里学到了领导力的课程。优秀的老板通过他们正面的榜样力量教会我们应该做什么。让我们对自己和自己在组织中的位置感觉良好的事情。我们满怀希望地认识到这些时刻是什么,并在心里记下“更像那样”或“在这种情况下为某人做那件事”。
我们也从坏老板的有力例子中学习。有时,这些问题更加突出,因为我们花了大量时间关注那些让我们不舒服或让我们感觉比互动前更糟糕的人和情况。
我们对这些时刻有着强烈的记忆,通常会详细了解那些老板应该采取不同的做法,或者没有做的事情,以及这些事情如何直接影响我们和公司(特别是当我们花时间与同事一起同情那个老板时)。)
但是有一天,我意识到我从观察我们数据科学团队初级成员的互动和行动中学到了多少。这是一个混合角色,充当入门级数据分析师和支持角色,帮助完成许多管理任务。
有时很容易忘记我们刚开始职业生涯时是什么样子。我们是多么兴奋,但也是如此天真。回想起来,我有时会想,我到底有多少次说错话了,或者因为兴奋多于经历而出丑了。但我也发现,我还是更希望我的团队里有具备这种组合的人,而不是那些把自己的入门级工作视为阻碍他们获得“实际上应得的”职位的人。
这里的教训是做好你的工作。花时间把它学好,而不是不停地去找你想要的工作。在你掌握了你面前的东西之后,你会有时间去做的。
几周前,我参加了一个由中层员工组成的领导小组。当我战胜自己的冒名顶替综合症,试图传达一些可能对他们的职业生涯有所帮助的有用建议时,我选定了一个我经常提到的主题:每个人都是自己故事中的英雄。
我不记得我是在哪里第一次遇到这个想法的,但它一直是我生活中一个有用的工具。本质是每个人都在做自己认为好的事情。每个人都在接近这个世界和他们的工作,好像他们是这个世界的中心。
此外,他们告诉自己关于他们周围世界的故事是一个他们是英雄的故事。在故事的特定情节中,他们的英雄可能是受害者、被误解的天才或白衣骑士……但他们不认为自己是小人物或坏人。
我坚信每个人都想把工作做好并产生积极的影响。我还不至于无知到相信他们总是这样做,或者相信他们的“正确”观念是每个人都认同的。但这个想法的简单本质是,很少有人带着做“坏事”的意图来到这个世界,考虑这种情况几乎是浪费时间。
相反,我认为一个人的每一个行动和努力都是因为他们认为那是“应该做的事情”。有时这是因为对世界的自私或受伤的理解,但关键是他们觉得在他们的思想中是合理的。
作为一名领导者,这意味着虽然我并不总是同意他们的行为和观点,但我至少应该试着理解他们的观点,这样我才有希望理解他们的动机。
我经常发现,对组织有害的行为和感觉源于缺乏共同的理解或目标。这些情况是最容易补救的,也是对所有领导人的一个很好的提醒,除了“是什么”之外,还要花更多的时间谈论政策或过程的“为什么”。
在某些情况下,个人和组织之间存在更基本的价值冲突,但这种情况非常罕见。在某些情况下,理解这一点可以导致更和谐的局面,经理和员工可以达成更好的共识。在其他情况下,最好是让员工跳槽到一个更符合他们价值观和动机的组织。快速发现这一点可以为团队节省很多困难和干扰。
本质上,这种方法让我不再认为我的团队成员和我有相同的热情和动机,而是更加流畅地尝试识别他们独特的动机。
这让我能够对我认为需要做的事情达成共识,并与他们产生共鸣。这也有助于我更好地识别机会和挑战,根据他们所处的位置、他们重视和喜欢的东西以及他们希望获得的经验来分配给不同的人。
前几天,当我看到我们的初级数据科学成员与同事互动时,我注意到了几件重要的事情,这就是为什么她是团队中一个优秀的人,并且提醒我们应该如何对待自己的工作和领导。
**看到更大的目标:**她很忙,但是当人们把他们的问题和工作带给她时,她总是礼貌地向他们表示感谢。她意识到他们并没有让她分心,而是为了实现组织的目标而必须做的事情。她当时的具体任务可能不同,但更大团队的需求是重要的工作。
**投入超越你的具体职位:**除此之外,她清楚地知道自己的职责是什么,但她会毫不犹豫地承担她认为需要完成的额外工作。
**培养你周围的人:**然而,她也认识到,当有人给她带东西时,她不一定要自己做。在这种情况下,她会花时间训练把它带给她的人,而不仅仅是做这件事。她知道这通常会在最初花费更多的时间,但从长远来看,这对她和公司都有好处。
没有自我:她很谦逊。非常强烈。对于她的职位来说,她受了过多的教育,资历过高,但是没有什么任务是她力所不及的。她知道有时即使是最高级的管理人员也需要复印或运行幻灯片。因此,如果被要求为演示整理图表,而不是研究新的机器学习模型,她连眼睛都不会眨一下。
不断学习:然而,她也意识到她需要学习的东西太多了。她总是渴望帮助完成一个项目,或者志愿做一些其他的事情,因为她知道这些都是学习一些关于组织和她的工作的新东西的机会。也许帮助构建一个非常大的 SQL 查询将允许她更好地学习数据库,并在组织中获得更多的领域知识。
她意识到,作为一个配角,你的时间就是别人的时间。事情不可能总是被安排得井井有条,并按照她能做到的方式处理。有时候,她需要在运行中重新确定优先级。根据我的经验,太多的领导者忘记了这也适用于他们。也许这意味着她每天花更多的时间来帮助获得供应品、软件或书籍旅行,而不是从事高调的数据分析。
如果我们花时间真正尝试通过别人的眼睛来看待这个世界,我们可以了解他们、这个世界和我们自己。作为一名领导者,在工作场所应用这一点将提高你的情商,并本能地将你拉出自己的观点和视角,以更好地了解你的团队。
除了学习如何支持他们并让他们为组织提供最好的帮助,你还将学习如何最好地领导团队,并更好地了解自己的行为如何影响他们的日常生活。
如果你还不是一个领导者,也许处于初级职位,你的观点是什么?你是否珍惜你现在的位置,并利用每一个机会去学习和获得更好的经验?或者你希望自己处于另一个位置,从事更高层次的项目?
态度很重要,我们对待工作的方式会引起经理和同事的共鸣。即使任务可以完成,也很少有组织目标可以通过个人努力来完成。因此,我们对团队的贡献至关重要。
当你不是数据科学家时,领导一个数据科学团队
这不仅仅是克服冒名顶替综合症,还有真正的价值。
Photo by Mubariz Mehdizadeh on Unsplash
我们很多人都很了解这种感觉。或者有一天你会的。你已经进入了一个全新的职位。你被雇用或提升是因为你在公司的不同部门工作。在许多情况下,你的第一个领导角色是领导一个由个人贡献者组成的团队,而你也曾经是其中的一员。很可能你在那里得到了晋升,学习了工作、文化和组织中的成员。
但是现在你被提升到一个不同的角色。您对这一部分有些熟悉,但并不真正了解。你不了解这个团队,你也不确切知道他们都做什么以及他们是如何做的。
你习惯于在任务上培训你的团队,因为你过去常常自己做任务…现在你不能这样做了。你甚至不能总是理解他们是如何做他们所做的事情的。
这是我在管理一个数据科学团队时的样子。我的背景是社会科学和政策。我以前从未在我的硕士学位的一些 Stata 之外编写过代码(在 Stata 中使用“编码”是有争议的),我的大多数数学和统计都是基于社会科学研究的。老实说,我通常在研究和工作中更倾向于定性方法。
现在,我正和一个团队坐在一起,试图了解他们是如何收集数据并将其编译到仪表板中的。我不仅需要尽快理解这一点,还需要帮助他们更好地完成工作,为组织增加价值。我真的不确定从哪里开始。
幸运的是,我最近开始了一个博士项目,对绩效评估、基于证据的政策和数据分析领域越来越感兴趣。这至少让我熟悉了“数据科学”这个术语。
此外,我对自己进入这个职位有一个很好的计划。我根据迈克尔·沃特金斯的《前 90 天》制定了这个计划。关键的一点是为自己制定一个学习计划。
这做了三件重要的事情。首先,它确保你有意识地了解你在新工作中需要学习的人、事和关系。第二个,它让你的新团队看到你是带着虚心向他们学习的态度来的,而不是认为你已经什么都知道了。最后一点,它给你一天中的时间和空间去真正了解你的团队在做什么以及他们是如何做的。
好好利用这段时间,它会在以后极大地帮助你。你还会惊讶地发现,通过这种方式,你会对团队和组织有更多的了解,而不仅仅是安排一对一的会议。真正利用优势,投入到工作中,努力做出实际贡献,而不是走过场。
在我自己的例子中,这就是我如何更熟悉团队使用的工具。SQL、R、Python 和 Tableau 以前对我来说都是陌生的。这也让我明白了我如何能够为团队增加价值。稍后会详细介绍。
在办公室之外,也为自己制定一个学习计划。有你应该读的书吗?你应该参加的会议或大会?你应该学的课程?
记住,你不需要成为技术专家…那不是你被提升的原因。但是你需要有足够的熟悉度来理解团队在做什么以及他们是如何做的。
当我完成新职位的学习计划时,我对团队的能力和未来工作的可能性有了更多的了解。
在我的博士项目研究中,我还专注于将数据分析、决策科学技术和机器学习过程应用于政府政策和项目。
不管是不是有意的,我在外面的研究和工作学习之间有了一个美丽的重叠。与基于大量优秀资源的一些数据科学优化建议相比,我还受益于对我团队组织结构的了解。
我们的团队有几个成员已经在这个组织工作了一段时间,他们主要致力于提供描述性的统计数据。我们也有几个新成员,他们是因为在一些涉及机器学习和预测分析的特殊项目中的技术技能而加入进来的。缺少的是团队的明确战略和我们可以为整个组织改进的关键领域。
这是我的“电灯泡”时刻。这发生在我开始工作的几个月后。这是我的主要观点:在开始一个新的职位时,如果不努力寻找早期和明确的成功,以向你的老板、你的团队和你自己展示你确实配得上你的角色,这真的很难!
然而,根据我的经验,作为一名领导者,你所做的有价值的工作需要的时间比你想象的要长。你需要时间来建立必要的理解和知识,以提供实际的战略愿景或洞察力。耐心做好工作,它会来的。
接下来的步骤也需要时间。仅仅因为你有一些战略洞察力或远见,并不意味着你会迅速重组团队,将他们转向所需的任务,并开始向这个新的方向推进。
作为一名高级领导,我学到的一件令人惊讶的事情是,我必须投入多少工作来“推销”我的愿景,并向团队中的其他人解释它。这不仅仅是买入,你头脑中如此坚定的愿景对其他人来说要难得多。我曾天真地认为,仅凭我的头衔就能为我完成这项工作。我错了。
在此阶段,有两个主要策略要遵循:
**指令。**你可以非常直接,简单地将组织或团队指向你的目标,并密切监控所有工作,以确保它符合设计。
许多人会将这种策略视为微观管理或独裁,但重要的是要注意,在某些情况下这是可行的和首选的。
例如,在一个组织的危机情况下,或者当有不灵活的需求和时间表时,这可能是一个非常有用的策略。史蒂夫·乔布斯因运用这一策略而闻名(或声名狼藉)。有时它会带来成功,但也会让他陷入低谷。小心这个策略!
**支持的。**另一种策略通常包括帮助团队作为一个小组来讨论和决定策略。这可以通过多种不同的方式来实现,但通常涉及促进小组工作,旨在确定成员对所需输出和内部约束的看法,以确定他们认为组织可以实现和合理的目标。
这将花费比指导更长的时间,但有利于在团队中建立基于他们所有观点的共同愿景。这也有助于领导者避免因忽视细微差别和团队掌握的信息而犯错误。
根据我的经验,在大多数情况下,支持策略是应该遵循的途径。请记住,虽然可能有一些关键的团队成员需要一些额外的指导推动,让他们中断他们的日常工作或承认盲点。这种情况通常发生在长期团队成员身上,但也常见于拥有深厚技术知识但缺乏领域知识或对组织缺乏了解的新成员。
当我们的团队一起工作来确定当前的工作需求和痛点时,他们达成了共识,即我们可以利用团队中的新工具和技能来改进和自动化数据报告需求。这将释放我们的资源,然后处理许多以前不可能的新项目。
我对团队的愿景和价值来自这里。我确保团队明白他们的努力是多么有价值,但也解释了他们如何能更好地生产工具,以他们不知道的方式帮助组织。
我已经对他们的知识和技能有了足够的了解,可以向他们解释机器学习项目的不同用例,这些用例与组织的首要任务直接相关。
此外,我还帮助他们了解我们需要如何向领导层展示数据分析的结果和信息,以便他们可以在决策中使用。
最后,我确保在我们着手这些新项目时,我用我的观点和理解来确保所有相关的利益相关者都参与进来,而不仅仅是那些与我们有良好工作关系的人。
在这长达数周的过程中,我还不断与我的老板沟通,以确保他们理解、同意并支持我们的战略。这确保了我们甚至在提交最终战略计划供他们批准之前就获得了他们的认可。
这次经历给了我一些宝贵的教训。
当你加入一个数据科学团队时,不要被自己知识的匮乏所淹没。即使你有数据科学背景,也有你不擅长而别人擅长的领域。有不同的技能组合和需要的角色。找到你的,并专注于在此基础上增加价值。作为一名领导者,你还需要专注于团队的目标,并确保你在团队中拥有不同的技能来实现这些目标。
**对自己要有耐心。**很多时候,当我们加入一个新团队时,我们会强烈地感到需要有所作为。作为领导者和个人,要认识到在投入生产之前花时间彻底学习的价值。你可能会觉得自己是团队的负担,但从长远来看,你会更有用。
**充当桥梁。**作为一名领导者,尤其是数据科学团队的领导者,确保将组织的观点和需求带到团队中。帮助他们看到优先事项和目标,然后挑战他们找到让他们的技能帮助实现这些目标的方法。在这里,我并不总是成功,但即使是那个错误也让我明白了这有多重要。
预测心脏病死亡率
深入分析
作为美国死亡的主要原因,我们使用机器学习来识别高危状态。
疾病控制中心(CDC)的国家健康统计中心(NCHS)维护着一个按年龄调整的死亡率数据库,并统计了全美十大死亡原因。按照原因、州和年份分组,数据可用于 1999 年至 2016 年,前 10 位死亡原因如下:
- 阿尔茨海默病
- 巨蟹星座
- 慢性下呼吸道疾病(CLRD)
- 糖尿病
- 心脏病
- 流感和肺炎
- 肾脏疾病
- 中风
- 自杀
- 意外伤害
通过 CDC 网站的 HTTP GET 请求访问完整的数据集。
Sample of 2016 data for New York.
因此,人口统计和人口数据可以得到适当的解释,死亡人数将被用来代替年龄调整率。为了计算人均死亡人数,纳入了来自 CDC 跨种族人口报告工具(WONDER) 的数据,该工具按年份、州、年龄组和性别对人口计数进行分组。将这个数据与死亡统计数据结合起来,人均死亡人数可以按州,按年计算,我们可以开始问一些问题。
目标
最终,目标是确定自 1999 年以来美国的主要死亡原因,然后确定 2019 年应被视为高风险的州。为了指导分析,需要回答四个具体问题:
- 在美国,导致死亡的主要原因是什么?
- 主要死亡原因的当前趋势是什么?
- 哪些因素对这些比率影响最大?
- 今天哪些州应该被视为高风险?
我们开始吧!
在美国,导致死亡的主要原因是什么?
如下图所示,根据 1999-2016 年的数据,美国的主要死亡原因是心脏病,占主要死亡原因的 34%。紧随其后的是癌症,占另外 30%。
然而,确实想到的一个问题是心脏病和癌症之间的差异是否有统计学意义。换句话说:*年率的正态方差解释这种差异的可能性有多大?*对这个问题进行了双尾学生 t 检验,得到的 p 值为 0.00008 表示 A 偶然遇到这样结果的概率小于万分之一。考虑到这一点,继续分析心脏病是安全的。
主要死亡原因的当前趋势是什么?
在州和国家两级审查了这方面的趋势。所有州和年份的最小和最大记录比率被用来限制结果,并获得一段时间内的相对变化。在下面的时间间隔中,绿色代表人均死亡人数最低,而红色代表最高。地图下方的图表显示了同一时期全国的死亡率变化。
由此可以很容易地观察到,总体比率一直在提高,大部分红色和橙色变成了绿色和黄色。国家一级的明显下降趋势进一步证实了这一点。这是个好消息,但是这种趋势是否会持续到未来还需要确定。
为了实现这一目标,研究对心脏病影响最大的因素是很重要的。
哪些因素对这些比率影响最大?
在对该主题进行了一些一般性研究后,决定将重点放在三个方面:
- 人口统计学(特别是年龄和性别)
- 饮酒
- 吸烟
明确地说,这些领域仅仅代表了可能性的一个子集,它们可能被合并到模型的未来版本中。
这里最大的挑战在于收集数据。虽然年龄和性别信息包含在疾病控制中心的人口数据中,但酒精和吸烟的数据还需要进一步挖掘。幸运的是,没有什么是一点研究和网络搜集不能处理的。
吸烟数据可从联合健康基金会获得,年度数据保存在单独的 CSV 文件中。吸烟率本身定义如下:
吸烟的成年人百分比(据报告一生中至少吸烟 100 支,目前每隔一天或几天吸烟一次)
通过网站 API 快速浏览相关年份,可以轻松访问这些数据。剩下的工作就是在本地保存每个文件,将数据连接到一个数据框架中,并执行一些基本的清理工作(删除全国汇总的行,检查数据类型,并选择相关的列)。
Sample of smoking rate data in New York.
很快就会出现问题的一件事是,人们意识到数据源在 2014 年发生了变化。进一步调查显示,收集数据的方法实际上在 2012 年发生了变化,新方法更加准确。然而,这也造成了一种错觉,即在此期间,美国的吸烟率突然飙升。出于本分析的目的,吸烟率的逐年变化比实际吸烟率本身更重要,因此决定解决差异的最佳方法是调整 2012 年及以后的数据,使其与前一年的趋势更加一致。全国范围内的结果如下。
关于酒精消费,可从国家酒精滥用和酒精中毒研究所获取数据。这里的酒精消耗量报告如下:
各州的人均乙醇消费量。[加仑乙醇,基于 14 岁及以上人口。]
此外,酒精消费按饮料类型(啤酒、葡萄酒和烈酒)进行细分。该组织网站上的数据分布在一个 16 页的表格中,因此需要一些漂亮的网页抓取。上面的链接指向数据的第一页,以给出结构的感觉,但 html 的截图和样本也应该有所帮助。
最上面一行使用 strong 标签来标识州名,后面是年份行,相关数据由 datagray 和 data 类标识。这个特定的行将每年重复 40 次,然后显示下一个州。然而,整个表也被包装起来,并用强标签标记,这意味着对于每个新页面,也将有一个表名而不是州名。下面的代码块用于解析所有的 html 并将结果保存到 dataframe 中。
既然困难的部分已经过去,数据可以与现有的吸烟、人口统计和疾病预防控制中心的数据结合起来开始分析。在这一点上有 20 个预测变量:每个年龄组、性别、吸烟率和饮酒率各有一个。另外两个更令人好奇的预测指标也包括在内:人均糖尿病死亡人数和人口密度。这些变量的重要性被证明是最小的,尽管后者至少提供了一个相关的见解,这将在后面触及。
所有数据都经过了缩放和对数转换,结果可以用平衡的百分比表示。结果分布如下所示:
虽然某些参数确实表现出一些偏斜,但总体上相当平衡,在稍后将数据输入预测模型时,没有表现出明显的问题。所以,现在终于有可能将数据输入回归模型,找出对死亡率影响最大的因素。在多重线性回归中使用了 4 个预测因子的所有可能组合,以寻找最高的调整 r 平方值。最终,四个变量被发现可以解释 83.4%的心脏病死亡率差异:吸烟率、75-79 岁年龄组、葡萄酒消费量和性别。这里至少有一个结果会让你大吃一惊。
最不令人惊讶的项目在底部:随着越来越多的人口达到 75-79 岁年龄段,越来越多的人口可能死于心脏病。从行为的角度来看,吸烟表现出同样类型的关系。
然而,更出乎意料的是,男性似乎比女性更不容易死于心脏病。这并不一定意味着男性较少患心脏病,只是意味着他们死于心脏病的可能性较小。根据疾病控制中心的说法,
尽管在过去几十年中人们的意识有所提高,但只有大约一半(56%)的女性认识到心脏病是她们的头号杀手。
所以,对于那些不知道的人来说,这是一个公共服务公告。
另一件令人惊讶的事情是,饮酒似乎对心脏病死亡率没有太大影响。事实上,数据表明,增加葡萄酒消费实际上可以降低这些比率。现在,在你跑出去买你最喜欢的一瓶红酒之前,提醒你一句:葡萄酒消费量的增加也被观察到与吸烟率的降低相关。因此,很可能不一定是葡萄酒消费,而是饮酒者吸烟率的降低导致了心脏病死亡率的降低。
这一点在下面的关联热图中得到了证实,其中深蓝色方块表示强烈的负关联,亮红色表示强烈的正关联。最左栏中的方块重申了回归模型中已知的内容。
今天哪些州应该被视为高风险?
我们几乎准备好建立一些模型并进行预测,但有两个问题需要解决。一、高危是怎么定义的?出于本分析的目的,高风险州将被定义为在所有数据范围内人均死亡人数处于所有比率前 33%的州。相反,低风险州是那些利率在底部 33%的州。将需要额外的领域专业知识来调整目标变量以反映行业标准,尽管这不应该降低模型本身的有效性,如果它们产生有希望的结果的话。
然而,第二个问题更具挑战性:我们的目标是对 2019 年进行预测,但只有 2016 年的数据。试图根据同一年获得的信息做出预测是不太现实的。虽然回顾过去有助于获得理解感,但展望未来却毫无用处。那么,解决办法是什么呢?时间滞后!
实际上,假设 2016 年的数据大约在 2017 年年中可用,但可以很容易地进行调整,以考虑这方面的差异。如果一个模型能够根据这些信息做出可靠的预测,那么组织将有一年半的时间来计划预期的变化。此外,该模型在进行预测时也不应该简单地忽略 2015 年和 2014 年的数据。所以,需要做的是使用 3 到 5 年的数据时滞,并将其作为当年死亡率的预测指标。结果将是预测变量的 3 倍,从 22 到 66。为了获得规模感,下面的关联热图突出了每个变量之间关系的性质。在这一点上,围绕多重共线性的问题将被搁置,这是因为预计会有相当数量的自相关。但是,也应该捕获 3 年窗口内的一致变化,这些变化是模型预测的主要关注点。
现在,试图用这么多预测变量建立一个模型将是非常低效的,尤其是在 13 英寸的笔记本电脑上。因此,进行了主成分分析(PCA ),以确定解释数据中 99%方差的最小特征组。因此,66 维的数据可以减少到 19 维。剩下的唯一事情就是建立模型,用最好的模型进行预测。
构建、训练和测试了六种不同的模型类型,出于测试目的保留了 20%的数据:
- 决策树分类
- 逻辑回归
- 支持向量机
- 随机森林分类
- adaboost 算法
- XGBoost
剩下的 80%使用 5 重交叉验证进行训练。此外,我们还对每个型号进行了网格搜索,以找出表现最佳的型号,结果产生了 1,413 种不同的型号变体。
除非在课堂回忆或精确度分数上有任何明显的不平衡,F1 分数被选为精确度/性能的主要衡量标准。最终,有一个模型在所有方面都明显优于其他模型:支持向量机。如下所示,它对所有截面的测试数据都达到了 90%的准确率。然而,当根据以前从未见过的测试数据进行预测时,该模型被证明更加有效,达到了几乎 92%的准确率。
另一项值得注意的是,该模型在精确度方面的表现确实优于召回率,这种差异在高风险状态的预测中最为突出。为什么这很重要?在进行这些类型的预测时,高估风险水平比低估风险水平要好。精确度和回忆分数表明这正是模型容易出错的地方。
完成所有这些后,现在可以使用 2014-2016 年的数据对 2019 年进行预测,并对预测的可靠性有所了解。在下图中,红色、黄色和绿色代表基于实际死亡率的 2016 年实际风险水平。红色代表高风险,绿色代表低风险。时间推移侧重于预计将改变风险水平的状态,并显示 2019 年的预期结果。
这里的结果有点复杂:四个状态从极端移动到中心,而两个状态从中心移动到极端。马萨诸塞州和马里兰州从低风险到中等风险,而密歇根州和宾夕法尼亚州从高风险到中等风险。伊利诺伊州和田纳西州走向相反的极端,分别从中等风险水平到低风险和高风险水平。但是有一个州特别突出:俄克拉荷马州。
俄克拉荷马州在 2016 年是一个高风险州,所以看到它这么快就被预测为低风险是一个很大的惊喜。经过更仔细的检查,很明显,这一变化的原因是吸烟率从 2010 年的 25.5%下降到 2015 年的约 19%,创历史新低。
目前尚不完全清楚这些结果是如何实现的,尽管该州卫生与公众服务部部长特里·克莱恩(Terry Cline)表示,这至少可以部分归因于该州的禁烟令,以及那些选择加入认证健康俄克拉荷马州计划的组织的商业地产。这绝对值得仔细看看他们在做什么,看看这些结果是否可以在其他地方复制。
再缩小,可以看到整个国家的 2019 年预测图。
最引人注目的是预测风险水平的地区差异。在这 9 个州中,有 8 个在 2016 年已经属于高风险类别,田纳西州今年被添加到列表中。那么,这些州能做些什么来降低各自社区的风险水平呢?
推荐
正如俄克拉荷马州所展示的,这些州所能做的最好的事情就是集中精力降低吸烟率。区域的接近性表明,如果俄克拉荷马州的项目在任何地方都有效,那将是在这些可能有相当多文化重叠的州。
此外,针对退休人员和女性的心脏病宣传活动也大有可为。数据中的另一项观察表明,在人口密集地区,妇女占人口的比例更大。因此,在城市中更加重视这些运动可能会产生更好的效果。
当然,看看这些结果是否可以进一步改善也是件好事,特别是在纳入种族数据和人群饮食习惯的情况下。可能性几乎是无穷无尽的,但潜力是显而易见的。
最后的想法
心脏病是一种在生活中的某个时刻影响到大多数人的疾病。也许你已经被折磨了。也许某个朋友或家人是幸存者,还在挣扎,或者已经去世。对我来说,那是一个两个月前因心脏病发作去世的叔叔,他还不到 60 岁。根据疾控中心:
- 在 2005 年的一项调查中,大多数受访者(92%)认为胸痛是心脏病发作的一种症状。只有 27% 的人知道所有的主要症状,并知道在有人心脏病发作时拨打 9-1-1。
- 大约 47% 的心源性猝死发生在医院外。这表明许多心脏病患者不会对早期预警信号采取行动。
如果只有一件事是你从这件事中学到的,我希望它是让你自己检查一下,让你自己意识到可能使你处于高风险水平的因素。
参考
Jupyter 笔记本和这个项目使用的所有资源都可以在 Github 上找到。
精益+数据科学
TL;dr
1。数据科学实践充满了浪费
2。明确的假设检验有助于微调想法
3。沟通是将数据科学家融入软件开发生命周期的关键
我加入这个领域是因为我们在发现新的数据模式时感到兴奋。然而,随着时间的推移,很明显,识别模式只是这个旅程的前半部分。还有一部分,是关于分享这个发现的。“分享”可以是展示的形式,可以是现有产品的改变,甚至是全新的产品。因此,这两个部分——从创意到产品的培育——是数据科学的完整堆栈。
在这篇文章中,我分享了我关于如何以有效的方式将机器学习模型构建到软件中的经验。在进入细节之前,让我们提出一些基本的假设:
- 产品开发需要钱。一些公司有更多,一些有更少,但是,他们都希望看到他们的投资回报。
- 产品开发需要时间。时间是普遍短缺的;因此,我们应该确保在我们突然用完的时候有一些投资回报。
- 产品开发天生具有不确定性。我不知道我们刚刚开始开发的产品的最终功能集会是什么,可能连客户都不知道。在这种情况下,我们可以做两件事:1)诚实,一起发现 2)假装我们知道市场想要什么(而且往往失败得很惨)。
数据科学中的精益产品开发
精益制造在多个行业都有良好的记录。尽管它最初是作为汽车工业的方法论而形成的,但是由于 Mary 和 Tom Poppendieck 的杰出工作,它已经扩展到软件开发中。精益的核心原则是减少过程中的浪费,以最大限度地提高生产率。Poppendiecks 指出了软件的七种浪费。他们在这里,锚定数据科学实践。
- 部分完成的工作。我认为大多数 Jupyter 笔记本是最好的例子。它们是部分完成的工作,因为您通常既不添加文档也不添加测试。重要的是,这不是过去的浪费:而是未来的浪费。每次有人想知道那本笔记本的用途时都浪费时间?浪费每次有人想建立它,结果是你离开了一个非线性运行的细胞。
- 额外功能。不久前,我们真的在推动一项功能的推出,因为我们想证明它是可行的。成功了。不幸的是,我们没有看到问题不是怀疑该功能从机器学习的角度来看是否可行,而是怀疑它在市场上是否可行。因为这个误会,我们浪费了两个星期的努力和时不时几个小时的维护。
- 重新学习。一个简单的例子是,每个人每次都从头开始编写代码,但是这些代码非常复杂,需要花两个小时来重新实现。想想读取数据,建立交叉验证等。
- 交接。这和重新学习有点不同,因为这是你无法避免的。不过,代码切换可以作为一个过程进行优化。我经常看到的一个重要的交接地点是在原型和产品数据团队之间。
- 任务切换。您很匆忙,这是通常的情况,所以您决定同时处理两个功能。也许你这样做是因为,否则,你会觉得你会花太多时间在一件事上,而没有时间做第二件事。
- 延期。预算、分配、等待 QA、等待模型训练、等待测试通过等等的批准时间。虽然在这种时候,如果人们能放松 10 分钟是最理想的,但通常这是不会发生的。相反,由于沮丧,他们开始解决它(例如,开始实现下一个特性)。
- 缺陷。损失去南;概率是 1.2;模型在不同版本中序列化,生产中缺少数据…等等。编写覆盖良好的代码并不意味着你不会面临缺陷,但是修复这些缺陷会容易得多。
我们很容易同意,减少这些浪费肯定有助于提供更可靠的输出。通常的问题是,是否有一种既省时又经济的方法来克服这些浪费。我认为关键是从第一天起就接受不确定性并为此进行设计。
拥抱不确定性
拥抱不确定性意味着接受我们不知道一切的事实。我们不知道 GAN 是否会比一些简单的仿射变换更好地用于数据生成,我们不知道我们现在的产品想法是否会引起真实客户的兴趣,我们不知道许多事情。然而,我们可以有好的实践来帮助我们在正确的时间以正确的方式回答这些问题。
Harry called everyone for a brainstorming meeting to do some market research. The aim of the meeting is to finetune the scope of the company’s next breakthrough product. Image from The Data Department
这些良好实践的基础是沟通和假设。在本系列的前一篇文章中,我已经谈到了假设的重要性。那一次是单位和系统层面的假设,在这里,我要谈谈业务单位层面假设的重要性。产品失败的最重要原因是不符合市场需求。数据科学产品经常发生的情况是,团队延迟发布,例如,模型在所有情况下都表现不佳。然后,当发布最终突然发生时,似乎没有人在乎。
这些故事背后的原因是一个错误的产品开发理念。在实现一个特性一年之前,我们首先要确定这个特性是需要的。让我们以 x.ai 是人工智能驱动的会议安排者为例。他们有关于如何用机器学习解决问题的想法,但他们没有首先从头开始实施,而是开始在人类会议安排者的帮助下测试这个概念。他们对市场需求了如指掌,正因为如此,现在他们的业务在不断增长。只有做出正确的选择,接受不确定性并减少浪费,在明确功能是否能为客户带来价值之前,不实施这些功能,这才是可能的。
数据科学的全部内容
我的一位资深同事在阅读了 TDD 帖子后问我,数据科学家的工资是多少,与他们互动的软件工程师的工资是多少,数据工程师的工资是多少。这个问题让我想到我是如何看待数据科学实践的。我认为数据科学团队是软件开发过程中的一个特殊部分。由于机器学习需要深入的数学知识(尤其是统计学),人们经常从各种非软件开发领域加入到团队中。这很好,因为这些技能传统上是软件工程研究中所缺少的。
Sometimes waste is hard to distinguish from the expertise. Image from The Data Department
然而,机器学习模型是软件的一部分,因此,它必须无缝集成。假设您已经构建了一个优秀的图像分类器,但是它不适合目标设备内存;流中的数据点没有按时间顺序到达;为了提供实时反馈,我们必须快速读取数据;模型的输出应该以一种有效且易于理解的方式显示。这意味着一名优秀的数据科学家还应该了解端到端流程。
如今,市场称这样的专业人士为全栈数据科学家(我们通常称之为独角兽)。我还可以在这里补充一点,一个人成为全栈数据科学家的最快方式是通过交流。你去软件开发人员的办公桌前问一问(同一件事连问两遍都没问题)。当 DevOps 同事解释他如何有效地解决模型部署时,您可以从他那里学到东西。你告诉数据工程师你对模型访问的新想法,也许她已经实现了那个特性或者知道它。幸运的是,我有几个同事通过这个简单的方法成为数据科学独角兽的例子。
最后,我相信在就业市场寻找独角兽之前,所有的公司都应该审视一下自己,看看是否能够培育它。答案可能是“是的,但我们没有时间做这些”,然而只有培养这种人才的文化才能发挥他们的全部潜力。
20 分钟熊猫高级功能综合指南
熊猫终极指南——第二部分
熊猫高级功能代码指南。
Red Panda — Photo by Linnea Herner on Unsplash
我大胆假设小熊猫比它们的黑白同胞更聪明,也更高级。因此,封面图片。
在这个熊猫系列的第一部**中,我们探索了熊猫的基础,**包括 :
- 如何加载数据;
- 如何检查、分类和过滤数据;
- 如何使用 and groupby/transform 分析数据
如果这些概念对你来说是新的,回到第一部分,快速复习一下。
[## 如何在 20 分钟内掌握 Python 的主要数据分析库
熊猫基本功能的代码指南。
towardsdatascience.com](/how-to-master-pandas-8514f33f00f6)
在今天的文章中,我们将讨论以下主题:
- 数据类型和转换
- 对某些数据类型有用的访问器方法
- 组合数据帧
- 重塑数据帧
先决条件
一个 Python 环境(建议 Jupyter 笔记本)。如果你还没有设置这个,不要担心。这是毫不费力的,不到 10 分钟。
到底是什么阻止了你?下面是如何开始!
towardsdatascience.com](/get-started-with-python-e50dc8c96589)
设置
Photo by dylan nolte on Unsplash
T21:在进行任何数据操作之前,让我们先获取一些数据。我们将使用一些虚构的销售数据。这个 GitHub Repo 保存了本文的数据和代码。
新建一个笔记本,导入熊猫(import pandas as pd
)。我倾向于这样调整我的笔记本设置:
from IPython.core.display import display, HTML
display(HTML("<style>.container {width:90% !important;}</style>"))
这些命令使笔记本变得更宽,从而利用更多的屏幕空间(通常笔记本的宽度是固定的,这与宽屏很不一样)。
加载数据
invoices = pd.read_csv('[https://raw.githubusercontent.com/FBosler/you-datascientist/master/invoices.csv'](https://raw.githubusercontent.com/FBosler/you-datascientist/master/invoices.csv'))
①数据类型和转换
Photo by Guillaume Bolduc on Unsplash
可用的数据类型
在开始研究数据之前,让我们快速总结一下所有可用的 Pandas 数据类型。总共有七种:
**object**
:该数据类型用于字符串(即字符序列)**int64**
:用于整数(整数,无小数)**float64**
:用于浮点数(即带小数/分数的数字)**bool**
:用于只能为真/假的值**datetime64**
:用于日期和时间值**timedelta**
:用来表示日期时间的差异**category**
:用于从有限数量的可用选项中选择一个选项的值(类别不是必须的,但可以有明确的排序)
显示数据类型
答在读取数据并运行快速invoices.sample(5)
后,我们观察到数据集似乎相当大,但结构良好。
为了对数据有所了解,我通常会先从sample
开始,然后是info
和describe
,但是我们在这里是为了学习数据类型,现在将跳过典型的探索步骤。毫不奇怪,有一个命令可以打印出数据帧的数据类型。
**IN:** invoices.dtypes**OUT:** Order Id object
Date object
Meal Id object
Company Id object
Date of Meal object
Participants object
Meal Price float64
Type of Meal object
Super Hero Present bool
dtype: object
我们在没有任何类型转换的情况下加载数据,所以 Pandas 在分配类型时做出了最好的猜测。我们可以看到,除了Meal Price
和Super Hero Present
之外,所有的列都是类型object
(即字符串)。根据我们之前的快速检查,似乎有些列可以被分配一个更明确的数据类型。所以让我们改变这一点。
转换数据类型
有两种转换 pandas 数据类型的标准方法:
<column>.astype(<desired type>)
- 转换辅助函数,如
pd.to_numeric
或pd.to_datetime
ⓐ原型
astype 速度很快,适用于干净的数据和直接转换,例如从 int64 转换到 float64(反之亦然)。
必须在要转换的列上直接调用 astype。像这样:
invoices['Type of Meal'] = invoices['Type of Meal'].astype('category')invoices['Date'] = invoices['Date'].astype('datetime64')invoices['Meal Price'] = invoices['Meal Price'].astype('int')
为了验证我们的类型转换的效果,我们再次运行invoices.dtypes
:
**OUT:** Order Id object
Date datetime64[ns]
Meal Id object
Company Id object
Date of Meal object
Participants object
Meal Price int64
Type of Meal category
Super Hero Present bool
dtype: object
**注:**熊猫版本有点差别。对于 Pandas 版本0.23.x
,可以使用.astype('datetime64')
转换Date of Meal
列,Pandas 将自动转换为 UTC 。UTC 格式很有用,因为它是一种标准化的时间格式,允许我们从其他日期中减去或加上日期。
然而,这对于 Pandas 版本0.25.x
不再有效,我们将得到一个 ValueError,让我们知道 Tz-aware(time zone-aware)datetime 在没有进一步调整的情况下不能被转换。
ⓑ转换辅助函数
有三个pd.to_<some_type>
函数,但对我来说,其中只有两个经常出现:
pd.to_numeric()
pd.to_datetime()
pd.to_timedelta()
(老实说,我不记得我是否用过这个)
与 **astype**
相比,它们的主要优势在于,可以指定遇到无法转换的值时的行为。
两个函数都接受一个额外的参数errors
,该参数定义了应该如何处理错误。我们可以选择通过传递errors='ignore'
来忽略错误,或者通过传递errors='coerce'
将有问题的值转化为np.nan
值。默认行为是引发错误。
我发现没有 cutty cutter 解决方案,我通常会在做出决定之前进行调查。与你观察到的数量相比,不合适的值越少,我就越有可能强迫它们。
**pd.to_numeric()**
为了便于讨论,让我们把数据稍微弄乱一点:
invoices.loc[45612,'Meal Price'] = 'I am causing trouble'
invoices.loc[35612,'Meal Price'] = 'Me too'
invoices['Meal Price'].astype(int)
现在将失败,并返回一个*值错误:以 10 为基数的 int()的文本无效:“我也是。”*因为没有明显的方法把字符串转换成整数。每当我遇到意外的转换错误时,我通常会显式地检查列的值,以便更好地理解奇怪值的大小。
**IN:**
invoices['Meal Price'].apply(lambda x: type(x)).value_counts()**OUT:** <class 'int'> 49972
<class 'str'> 2
Name: Meal Price
然后,您可以通过执行以下操作来识别违规的行:
**IN:** invoices['Meal Price'][invoices['Meal Price'].apply(
lambda x: isinstance(x,str)
)]**OUT:** 35612 Me too
45612 I am causing trouble
Name: Meal Price, dtype: object
从这里开始,可以快速修复这些值,或者做出明智的决定,决定如何处理失败的转换。
上面的例子是一个很好的例子,通过像这样将errors='coerce'
传递给pd.to_numeric()
来将值转换成np.nan
是非常合理的:
pd.to_numeric(invoices['Meal Price'], errors='coerce')
现在应该注意的是,您的数据中构造有两个np.nan
值,所以就地处理它们可能是个好主意。np.nan
s`的问题是整数列不知道如何处理它们。因此,该列将是一个浮动列。
**# convert the offending values into np.nan**
invoices['Meal Price'] = pd.to_numeric(invoices['Meal Price'],errors='coerce')**# fill np.nan with the median of the data**
invoices['Meal Price'] = invoices['Meal Price'].fillna(invoices['Meal Price'].median())**# convert the column into integer**
invoices['Meal Price'].astype(int)
**pd.to_datetime()**
顾名思义,该方法将字符串转换为日期时间格式。要在一个列上调用to_datetime
,你可以做:pd.to_datetime(invoices['Date of Meal'])
。Pandas 将猜测格式,并尝试从输入中解析日期。它做得非常好:
**IN:**
print(pd.to_datetime('2019-8-1'))
print(pd.to_datetime('2019/8/1'))
print(pd.to_datetime('8/1/2019'))
print(pd.to_datetime('Aug, 1 2019'))
print(pd.to_datetime('Aug - 1 2019'))
print(pd.to_datetime('August - 1 2019'))
print(pd.to_datetime('2019, August - 1'))
print(pd.to_datetime('20190108'))**OUT:**
2019-08-01 00:00:00
2019-08-01 00:00:00
2019-08-01 00:00:00
2019-08-01 00:00:00
2019-08-01 00:00:00
2019-08-01 00:00:00
2019-08-01 00:00:00
2019-01-08 00:00:00
然而,有时您可能会遇到一些非典型的格式,就像上面列表中的最后一个例子。在这种情况下,您可能希望提供一个自定义格式,您可以这样做:pd.to_datetime('20190108',format='%Y%d%m')
。可以把格式字符串看作一个掩码,用来检查日期字符串,如果这个掩码合适,转换就会发生。查看链接获取所有可能的日期格式组件列表。使用定制格式时,另一个值得注意的参数是exact=False
。print(pd.to_datetime('yolo 20190108', format='%Y%d%m', exact=False))
将会工作,但是如果没有确切的参数,它将会失败。Pandas 试图匹配日期字符串中任何位置的模式。
在继续之前,让我们转换我们的Date of Meal
列,像这样invoices['Date of Meal'] = pd.to_datetime(invoices['Date of Meal'], utc=True)
②对某些数据类型有用的访问器方法
Photo by Todd Quackenbush on Unsplash
如果你唯一的工具是锤子,那么每个问题看起来都像钉子。
把 Pandas 访问器看作是一个属性,它充当特定于你试图访问的类型的方法的接口。那些方法是高度专业化的。他们只为一项工作服务。然而,对于特定的工作来说,它们非常优秀而且非常简洁。
有三种不同的访问器:
dt
str
cat
通过在选择的列上调用.<accessor>.method
可以访问所有的方法,就像这样:invoices['Date of Meal'].dt.date
存取器— dt
我认为他的方法是最有用和最直接的访问器方法:
**date**
(返回日期时间的日期值),或者
**IN:** invoices['Date of Meal'].dt.date**OUT:** 0 2015-01-29
1 2017-10-30
...
49972 2017-09-06
49973 2015-08-20
Name: Date of Meal, Length: 49974, dtype: object
**weekday_name**
(返回当天的名称)、**month_name()**
(这种实现方式有些不一致,因为 weekday_name 是一个属性,而 month_name 是一个方法,需要用括号调用)
**IN:** invoices['Date of Meal'].dt.weekday_name**OUT:** 0 Thursday
1 Monday
...
49972 Wednesday
49973 Thursday
Name: Date of Meal, Length: 49974, dtype: object**IN:** invoices['Date of Meal'].dt.month_name()**OUT:** 0 January
1 October
...
49972 September
49973 August
Name: Date of Meal, Length: 49974, dtype: object
**days_in_month**
**IN:** invoices['Date of Meal'].dt.days_in_month**OUT:** 0 31
1 31
..
49972 30
49973 31
Name: Date of Meal, Length: 49974, dtype: int64
**nanosecond**
、**microsecond**
、**second**
、**minute**
、**hour**
、**day**
、**week**
、**month**
、**quarter**
、**year**
得到对应频率的整数。
**EXAMPLES: (same logic applies for** **nanosecond**, **microsecond**, **second**, **minute**, **hour)****IN:** invoices['Date of Meal'].dt.day**OUT:** 0 29
1 30
..
49972 6
49973 20
Name: Date of Meal, Length: 49974, dtype: int64**IN:** invoices['Date of Meal'].dt.week**OUT:** 0 5
1 44
..
49972 36
49973 34
Name: Date of Meal, Length: 49974, dtype: int64**IN:** invoices['Date of Meal'].dt.month**OUT:** 0 1
1 10
..
49972 9
49973 8
Name: Date of Meal, Length: 49974, dtype: int64**IN:** invoices['Date of Meal'].dt.quarter**OUT:** 0 1
1 4
..
49972 3
49973 3
Name: Date of Meal, Length: 49974, dtype: int64**IN:** invoices['Date of Meal'].dt.year**OUT:** 0 2015
1 2017
...
49972 2017
49973 2015
Name: Date of Meal, Length: 49974, dtype: int64
**is_leap_year**
、**is_month_start**
、**is_month_end**
、**is_quarter_start**
、**is_quarter_end**
、**is_year_start**
、**is_year_end**
分别为每个值返回 True 或 False。is_month_end
见下例
**IN:** invoices['Date of Meal'].dt.is_month_end**OUT:** 0 False
1 False
...
49972 False
49973 False
Name: Date of Meal, Length: 49974, dtype: bool
我们可以使用结果过滤我们的数据,只保留行,其中Date of Meal
在月末。
Invoices filtered for Date of Meal is_month_end
**to_pydatetime()**
,它将 Pandas datetime 转换成常规的 Python datetime 格式(有时您可能会用到),以及**to_period(<PERIOD>)**
【可用的周期有 W、M、Q 和 Y】,它将日期转换成周期。
**IN:** invoices['Date of Meal'].dt.to_pydatetime()**OUT:** array([datetime.datetime(2015, 1, 29, 8, 0),
datetime.datetime(2017, 10, 30, 20, 0),
datetime.datetime(2015, 2, 10, 11, 0), ...,
datetime.datetime(2017, 3, 7, 19, 0),
datetime.datetime(2017, 9, 6, 6, 0),
datetime.datetime(2015, 8, 20, 18, 0)], dtype=object)**IN:** invoices['Date of Meal'].dt.to_period('W')**OUT:** 0 2015-01-26/2015-02-01
1 2017-10-30/2017-11-05
...
49972 2017-09-04/2017-09-10
49973 2015-08-17/2015-08-23
Name: Date of Meal, Length: 49974, dtype: object
存取器—字符串
str 访问器也非常有用,不是因为它支持额外功能,而是因为它使代码更加可读。
**lower()**
/**upper()**
管理字符串的大小写
**IN:** invoices['Type of Meal'].str.lower()**OUT:** 0 breakfast
1 dinner
...
49972 breakfast
49973 dinner
Name: Type of Meal, Length: 49974, dtype: object**IN:** invoices['Type of Meal'].str.upper()**OUT:** 0 BREAKFAST
1 DINNER
...
49972 BREAKFAST
49973 DINNER
Name: Type of Meal, Length: 49974, dtype: object
**ljust(width)**
**rjust(width)**
**center(width)**
**zfill(width)**
来控制琴弦的定位。它们都将所需结果字符串的总宽度作为输入。ljust
、rjust
和center
用空格将差值填充至所需长度。添加许多前导零。ljust
是向左的,rjust
是向右的。****
******IN:** invoices['Type of Meal'].str.ljust(width=15)**OUT:** 0 Breakfast
1 Dinner
...
49972 Breakfast
49973 Dinner
Name: Type of Meal, Length: 49974, dtype: object**IN:** invoices['Type of Meal'].str.rjust(width=15)**OUT:** 0 Breakfast
1 Dinner
...
49972 Breakfast
49973 Dinner
Name: Type of Meal, Length: 49974, dtype: object**IN:** invoices['Type of Meal'].str.center(width=15)**OUT:** 0 Breakfast
1 Dinner
...
49972 Breakfast
49973 Dinner
Name: Type of Meal, Length: 49974, dtype: object**IN:** invoices['Type of Meal'].str.zfill(width=15)**OUT:** 0 000000Breakfast
1 000000000Dinner
...
49972 000000Breakfast
49973 000000000Dinner
Name: Type of Meal, Length: 49974, dtype: object****
**startswith(<substring>)**
、、**endswith(<substring>)**
、、**contains(<substring>)**
、、检查子串的存在
****IN:** invoices['Type of Meal'].str.endswith('ast')**OUT:** 0 True
1 False
...
49972 True
49973 False
Name: Type of Meal, Length: 49974, dtype: bool**
using str.contains to filter for rows that include ‘Bruce.’
- **
**swapcase()**
、、**、为、的拳打脚踢
****IN:** invoices['Type of Meal'].str.swapcase()**OUT:** 0 bREAKFAST
1 dINNER
...
49972 bREAKFAST
49973 dINNER
Name: Type of Meal, Length: 49974, dtype: object**IN:** invoices['Type of Meal'].str.repeat(2)**OUT:** 0 BreakfastBreakfast
1 DinnerDinner
...
49972 BreakfastBreakfast
49973 DinnerDinner
Name: Type of Meal, Length: 49974, dtype: object**
访问者— cat
在我看来是三个中最不强大的,或者至少是我最不常用的。cat
提供对几个类别操作的访问,如:
**ordered**
让您知道列是否有序
****IN:** invoices['Type of Meal'].cat.ordered**OUT:**
False**
**categories**
返回类别
****IN:** invoices['Type of Meal'].cat.categories**OUT:** Index(['Breakfast', 'Dinner', 'Lunch'], dtype='object')**
**codes**
用于将类别快速转换成其数值表示
****IN:**
invoices['Type of Meal'].cat.codes**OUT:** 0 0
1 1
2 2
3 2
4 2
..
49969 1
49970 2
49971 1
49972 0
49973 1
Length: 49974, dtype: int8**
**reorder_categories**
改变现有类别的顺序
****IN:**
invoices['Type of Meal'].cat.reorder_categories(
['Lunch','Breakfast','Dinner']
)**OUT:** 0 Breakfast
1 Dinner
2 Lunch
3 Lunch
4 Lunch
...
49969 Dinner
49970 Lunch
49971 Dinner
49972 Breakfast
49973 Dinner
Name: Type of Meal, Length: 49974, dtype: category
Categories (3, object): [Lunch, Breakfast, Dinner]**
③组合数据帧
连结
当你有相似的数据(结构上和内容上)分布在多个文件中时,oncatenating 就很方便了。您可以垂直连接数据(即,将数据堆叠在一起)或水平连接数据(即,将数据堆叠在一起)。
ⓐ串联—垂直堆叠
作为一个例子,假设一个客户每月或每年向你提供一个文件的数据(例如,因为他们的报告在月末运行)。这些文件在概念上是相同的,因此是垂直堆叠的主要例子。
A simplified example of vertical stacking
让我们看看如何用 Python 的熊猫来做这件事。让我们人为地把发票文件按年份分开。
****# Use dt accessor to count all the years
IN:** invoices['Date of Meal'].dt.year.value_counts().sort_index()**OUT:** 2013 38
2014 9988
2015 10060
2016 9961
2017 9964
2018 9931
2019 32
Name: Date of Meal, dtype: int64**# Split the data** y_2013 = invoices[invoices['Date of Meal'].dt.year == 2013].copy()
y_2014 = invoices[invoices['Date of Meal'].dt.year == 2014].copy()
y_2015 = invoices[invoices['Date of Meal'].dt.year == 2015].copy()
y_2016 = invoices[invoices['Date of Meal'].dt.year == 2016].copy()
y_2017 = invoices[invoices['Date of Meal'].dt.year == 2017].copy()
y_2018 = invoices[invoices['Date of Meal'].dt.year == 2018].copy()
y_2019 = invoices[invoices['Date of Meal'].dt.year == 2019].copy()**
我们使用.copy()
来确保生成的数据帧是数据的副本,而不仅仅是对原始数据帧的引用。
让我们验证一下拆分是否有效。
All Invoices where the date of the meal was in 2017
现在,为了将数据连接成一个统一的数据帧,我们将像这样调用pd.concat(<LIST OF DATAFRAMES>)
:
Stacking multiple DataFrames on top of each other
pd.concat
在您调用concat
的数据帧列表旁边,接受几个可选参数:
**axis**
:0
为垂直,1
为水平。**axis**
默认为**0**
**join**
:'inner'
为交集,'outer'
为非连接轴索引的并集。当我们使用axis=0
和join='inner'
时,我们将只考虑重叠的列。当使用axis=1
和join='inner'
时,我们只考虑重叠指数。在outer
的情况下,非重叠列/索引将用nan
值填充。**join**
默认为**outer**
**ignore_index**
:True
忽略预先存在的索引,而使用从 0 到 n-1 的标签作为结果数据帧。**ignore_index**
默认为**False**
- ****
**keys**
: 如果我们提供一个列表(必须与数据帧的数量相同的长度),一个层次索引将被构建。keys
默认为None
。以keys
为例,添加数据的来源。最好与名字连用。 **names**
: 假设您提供了键,那么这些名称将用于标记生成的层次索引。**names**
默认为**None**
。
Stacking multiple DataFrames on top of each other with keys
ⓑ串联—水平堆叠
水平堆叠的一个用例是指多个时间序列具有重叠但不相同的索引。在这种情况下,您不会希望最终得到一个可能有数千列的数据帧,而是一个有数千行的数据帧。
A simplified example of horizontal stacking
在 Python 中运行下面的代码片段将得到下面的屏幕截图:
**range_a = pd.date_range(
datetime.datetime(2019,1,2),
datetime.datetime(2019,1,8)
)
df_a = pd.DataFrame(
index=range_a,
data=np.random.randint(2,10,size=len(range_a)),
columns=['observations_A']
)range_b = pd.date_range(
datetime.datetime(2019,1,5),
datetime.datetime(2019,1,12)
)df_b = pd.DataFrame(
index=range_b,
data=np.random.randint(2,10,size=len(range_b)),
columns=['observations_B']
)pd.concat([df_a,df_b],axis=1)**
Horizontally stacked DataFrames
关于**Append**
: 你可能已经看到append
的用法和concat
一样的结尾。我建议不要使用 **append**
,因为它只是concat
的一个特例,并没有提供比串联更好的优势。
合并
与将数据帧连接在一起相反,合并允许我们以一种更传统的 SQL 查询方式将两个数据帧组合在一起。当合并数据帧时,大多数情况下,您希望一些信息来自一个源,另一些信息来自另一个源。而当连接数据帧时,它们在结构上和内容上非常相似,您希望将它们组合成一个统一的数据帧。
我喜欢在面试中使用的一个简单例子是这样的:
假设你有两张桌子。一个表包含员工姓名和位置 id,另一个表包含位置 id 和城市名称。你怎么能得到每个雇员的名单和他们工作的城市?
在 Pandas 中合并两个数据帧是用pd.merge
完成的。让我们来看看函数的签名(签名是指函数所有可能参数的列表,通常还包括输出)。我加粗了最相关的参数。
**pd.merge(
**left,
right,**
**how='inner',
on=None,**
**left_on=None,**
**right_on=None,**
**left_index=False,**
**right_index=False,**
sort=True,
**suffixes=('_x', '_y'),**
copy=True,
indicator=False,
validate=None
) -> pd.DataFrame**
让我们一个一个地检查参数:
**left/right**
:要合并的左、右数据帧**how**
:'left'
,'right'
,'outer'
,'inner'
。**how**
默认为**'inner'**
。下面是它们各自功能的示意图。稍后我们将讨论具体的例子。
Image from DataScienceMadeSimple
**left_index/right_index**
: 如果True
,使用左/右数据帧的索引合并。**left_index/right_index**
默认为False
**on**
: 要合并的列名。列名必须同时存在于左侧和右侧数据框架中。如果未通过且left_index
和right_index
为False
,两个数据帧中的列的交集将被推断为连接。- ****
**left_on/right_on**
: 左/右数据框中要连接的列名。典型用例:您正在连接的键在您的数据帧中有不同的标签。例如,您左侧数据帧中的location_id
可能是您右侧数据帧中的_id
。在这种情况下,你会做**left_on='**location_id', **right_on**='_id'
。 **suffixes**
:应用于重叠列的字符串后缀元组。**suffixes**
默认为('_x', '_y')
。我喜欢用('_base', '_joined')
。
合并—加载和检查新数据
理论够了,我们来看一些例子。为此,我们需要一些额外的数据来合并。
加载数据:
****# Load some additional Data**
order_data = pd.read_csv('[https://raw.githubusercontent.com/FBosler/you-datascientist/master/order_leads.csv', parse_dates=[3](https://raw.githubusercontent.com/FBosler/you-datascientist/master/order_leads.csv',parse_dates=[3)])**# Note the parse_dates? We need this to have consistent types with invoices, otherwise the subsequent merges would throw errors**sales_team = pd.read_csv('[https://raw.githubusercontent.com/FBosler/you-datascientist/master/sales_team.csv'](https://raw.githubusercontent.com/FBosler/you-datascientist/master/sales_team.csv'))**
检查数据:
Some overlapping (keys), some unique columns (features) spread out across three DataFrames
**我们马上就能看到,**Order ID**
、**Company ID**
、**、和**Date**
出现在多个数据帧中,因此是很好的合并对象。
合并—如何进行
让我们将**invoices**
与**order_data**
合并,并对参数进行一点试验。
- ****未提供参数:所有参数将使用其默认值。
合并将是一个内部合并(相当于**how='inner'**
)。
将对所有公共列进行合并,即**Date**
、**Order Id**
和**Company Id**
(相当于**on=['Date','Order Id','Company Id]**
)。
后缀是不相关的,因为所有公共列都将用于合并,所以不会剩下重复的列。
运行**pd.merge(order_data,invoices)**
:
Merge with no parameters. Defaults to inner, i.e., only rows where there is data in both tables. Note how this results in ~50k rows.
**how='left'**
:同样,合并基于所有公共列。后缀是不相关的,因为所有公共列都将用于合并,所以不会留下重复的列。
然而,这一次,我们与**how='left'**
合并,这意味着我们将从左侧帧中取出所有行,并且只添加右侧帧中我们找到的一些数据。运行**pd.merge(order_data,invoices,how='left')**
:
“left-sided” merge, i.e., we take all rows from the left DataFrame and combine data from the right DataFrame, where we find some. Note how this results in 100k rows.
**how='right'**
:同样,合并基于所有公共列。后缀是不相关的,因为所有公共列都将用于合并,所以不会留下重复的列。
然而,这一次,我们与**how='right'**
合并,这意味着我们将从右帧中取出所有行,并且只添加我们在左帧中找到的一些数据。这种情况相当于我们示例中的**'inner'**
,因为左侧数据帧中的每一行在右侧数据帧中都有相应的行。
运行**pd.merge(order_data,invoices,how='right')**
:
“right-sided” merge, i.e., we take all rows from the right DataFrame and add data from the left DataFrame, where we find some. Note how this results in ~50k rows
**how='outer'**
:同样,合并是基于所有公共列的。后缀是不相关的,因为所有公共列都将用于合并,所以不会留下重复的列。
然而,这一次,我们与**how='outer'.**
合并,我们从左侧或右侧数据帧中取出所有行,并在其他数据帧中找到的位置添加相应的数据。这种情况相当于我们示例中的**'left'**
,因为左侧数据帧中的每一行在右侧数据帧中都有相应的行。运行**pd.merge(order_data,invoices,how='outer')**
:
“outer” merge, i.e., we take all rows from both DataFrames and add data from the corresponding other DataFrame, where we find some. Note how this results in 100k rows.
合并—开/后缀
如果我们确实显式提供了一个**on**
参数,这将覆盖默认行为,并尝试在两个数据帧中找到所提供的列。未用于合并的剩余重复列将被加上后缀。
在下面的例子中,我们只在**Order Id**
进行合并。然而,由于**Date**
和**Company Id**
列同时出现在两个数据帧中。这些列足以表明它们来自哪个源数据帧,如下例所示。
运行:**pd.merge(order_data,invoices,on='Order Id')**
Merge on one common column, default suffixes
我们也可以像这样指定自定义后缀:
**pd.merge(order_data,invoices,on='Order Id',suffixes=('_base','_join'))**
Merge on one common column, custom suffixes (_base and _join)
合并—左开/右开
当两个数据帧中的列名称不同时,通常会使用**left_on**
和**right_on**
参数。
Contrived example, where we first rename “Order Id” to “New Id” to then use it as our right_on target column
**Join**
注: 你可能见过join
的用法跟merge
一个下场。join
默认情况下,合并两个数据帧的索引。我建议不要使用 **join**
,因为它只是merge
的一个特例,并不能提供比合并更好的好处。
地图
到结束关于组合数据帧的章节,我们应该快速讨论一下map
。map
可以在 DataFrame 列或其索引上调用,如下所示:
We create a new column based on the Sales Rep for the associated company by mapping the company column against a previously created lookup
map
的参数(在我们的例子中是lookup
)必须是一个序列或一个字典。虽然不完全相同,但熊猫系列和普通字典有很多共同的功能,并且经常可以互换使用。就像通过字典一样,你可以通过调用for k,v in series.items():
来循环遍历一个系列。
组合数据帧的摘要:
- 使用
**pd.concat**
将多个数据帧“堆叠”在一起。默认情况下,堆叠是垂直的。要覆盖默认设置,使用axis=1
。默认情况下,堆栈将覆盖所有列/索引。使用join='inner'
限制公共列/索引。 - 不要使用
**pd.DataFrame.append**
,因为它只是pd.concat
的一种特殊的、有限的情况,只会让你的代码不那么标准化,不那么连贯。而是使用pd.concat
。 - 使用
**pd.merge**
合并两个数据帧的信息。Merge 默认为内部连接,并将从数据帧中最大的公共列子集推断要合并的列。 - 不要使用
**pd.DataFrame.join**
,因为它只是pd.merge
的一种特殊的、有限的情况,只会让你的代码不那么标准化,不那么连贯。相反,使用pd.merge
。 - 使用
**pd.Series.map**
作为类似查找的功能,从序列/字典中获取特定索引/键的值。
④重塑数据帧(融合、旋转、转置、堆叠、拆分)
Photo by Chris Lawton on Unsplash
移项
T 转换数据帧意味着交换索引和列。换句话说,你是在围绕原点旋转数据帧。转置不会改变数据帧的内容。数据帧仅改变方向。让我们用一个例子来形象地说明这一点:
The first seven rows of invoices DataFrame and first seven rows of invoices DataFrame transposed
通过简单地调用数据帧上的.T
来转置数据帧,例如invoices.T
。
熔化
M elt 将数据帧从宽格式转换成长格式。Melt 为如何进行转换提供了灵活性。换句话说,melt 允许抓取列并将其转换为行,同时保持其他列不变。融化最好用一个例子来解释。让我们创建一些样本数据:
**melt_experiment = pd.merge(
invoices,
pd.get_dummies(invoices['Type of Meal']).mul(invoices['Meal Price'].values,axis=0),
left_index=True,
right_index=True
)
del melt_experiment['Type of Meal']
del melt_experiment['Meal Price']
melt_experiment**
melt_experiment (unpacked Type of Meal into columns)
诚然,这个例子有点做作,但说明了这一点。我们将Type of Meal
转换成列,并将价格分配到相应的行中。现在把它转换回一个版本,其中食物类型是一个列,值是价格,我们可以像这样使用pd.melt
:
**pd.melt(
frame=melt_experiment,
id_vars=['Order Id', 'Date', 'Meal Id', 'Company Id', 'Date of Meal','Participants', 'Heroes Adjustment'],
value_vars=['Breakfast', 'Dinner', 'Lunch'],
var_name='Type of Meal',
value_name='Expenses'
)**
导致:
“melted” DataFrame
Melt 有助于将数据帧转换成一种格式,其中一列或多列是标识符变量(id_vars
),而所有其他列,即测量变量(value_vars
),被移动到行轴,只留下两个非标识符列。对于我们融合的每一列(value_vars
),对应的现有行被复制,以适应将数据融合到一列中,并且我们的数据框架扩展。熔化后,我们的行数是之前的三倍(因为我们使用了三个value_vars
,因此每行三倍)。
分组依据
我们在上一篇文章中讨论过,但是在这里快速回顾一下是有意义的,特别是在堆叠和拆堆方面,我们将在后面讨论。其中转置和熔化保持数据帧的内容不变,并且“仅”重新排列外观分组,并且以下方法以一种或另一种形式聚集数据。Groupby 将产生一个具有新索引(分组所依据的列的值)的聚合数据帧。如果按多个值进行分组,得到的数据帧将具有多重索引。
**invoices.groupby(['Company Id','Type of Meal']).agg(
{'Meal Price':np.mean}
)**
groupby result with multi-index
从 pandas 版本 0.25.1 开始,也有了命名聚合,这使得 groupby 可读性更好一些。
**invoices.groupby(['Company Id','Type of Meal']).agg(
Avg_Price = pd.NamedAgg(column='Meal Price', aggfunc=np.mean)
)**
结果实际上与前面的计算相同。但是,该列在此过程中会被重命名。
groupby result with multi-index and renamed output column
在枢轴上转动
和 Excel 的数据透视表一样,andas 也包含了一个pivot_table
功能。但是我必须承认,我从来没有使用过pivot
,因为我看不出它比 groupby 操作有什么优势。总的来说,我认为使用你感到舒适的东西并坚持这样做是有意义的。我建议不要在没有必要的时候混合使用不同的方法。不过,pivot_table
有一个优势就是margin=True
**pd.pivot_table(
invoices,
index=['Company Id','Type of Meal'],
values='Meal Price',
aggfunc=np.mean,
margins=True
)**
result of pivot_table operation with margins=True
结果应该看起来有些熟悉,因为我们基本上重新创建了 groupby 功能。然而,除了单个组的结果之外,我们还获得了跨所有组的计算值的额外好处(如最后一行所示)。
我们还可以为数据透视表指定列:
**pd.pivot_table(
invoices,
index=['Company Id'],
columns=['Type of Meal'],
values='Meal Price',
aggfunc=np.mean,
margins=True
)**
Pivot table with index and columns specified
堆叠/拆分
重新排列列和索引时,Sstack 和 unstack 非常方便。默认情况下,将在索引的最外层调用 Unstack,正如在下面的示例中可以很好地看到的那样,调用unstack()
会将Heroes Adjustment
索引变成两列。
calling unstack() on three-level index DataFrame rotates the outmost index into columns
我们还可以拆分特定级别的索引,如下例所示,其中我们拆分了Type of Meal
列
另一方面,堆叠的作用正好相反。堆叠将列转化为行,但是也在这个过程中扩展了索引(与melt
相反)。让我们看一个例子。
我们必须首先构建一些数据,在这些数据中,堆叠会派上用场。执行下面的代码片段会产生一个多索引、多级别列的数据框架。
**stack_test = invoices.groupby(['Company Id','Type of Meal']).agg({
'Meal Price':[max,min,np.mean],
'Date of Meal':[max,min],
})
stack_test**
如果我们想要堆叠这个数据帧,我们将调用stack_test.stack()
并得到:
stacked groupby result
在这里,stack 使用了我们的多级列的最外层,并将其转换为一个索引。我们现在只有单层列。或者,我们也可以用level=0
调用 stack,得到如下结果:
stacked (on level=0) groupby result
摘要
在这篇文章中,你学会了如何成为一个真正的熊猫忍者。您了解了如何将数据转换成所需的类型以及在类型之间进行转换。您了解了如何为这些类型使用独特的方法来访问功能,否则需要一行又一行的代码。您学习了如何组合不同的数据帧,方法是将它们堆叠在一起,或者从数据帧中逻辑地提取信息,并将它们组合成更有意义的内容。你学会了如何翻转你的数据框,就像翻转煎饼一样。您学习了在其原点旋转、将列移入行、通过 pivot 或 groupby 聚合数据,然后堆叠和拆分结果。
干得好,感谢您的阅读!
通过拯救地球来合作学习人工智能
Omdena 和 Ciencia y Datos 合作举办了一场新的人工智能挑战赛,如果你想成为 50 名人工智能爱好者之一,通过解决一个有意义的全球性问题来获得实践技能,你需要阅读这篇文章。
Learn more here: https://www.cienciaydatos.org/educacion
和所有人争着解决一个问题不累吗?不要误解我的意思,竞争是重要的,并且推动创新,但是如果你想学习,也许这不是最好的方法。
这就是为什么当 omdena.com 大学的人联系我们 T2 科学与技术大学的人,与他们一起合作挑战人工智能学习时,我们说是的!!
在详细讨论挑战和如何应用之前,让我简单地谈谈协作学习。
协作学习
http://blog.fusemachines.com/ai-human-collaboration/
学习一个新的话题总是具有挑战性,但是有一些方法可以让它变得简单。不久前,在我关于人们在学习数据科学时犯的最大错误的文章中,我提到如果你想真正学到一些你需要实践的东西,要认真学习,而且最好与对同一领域感兴趣的其他人一起学习。
我不是说你需要和你的闺蜜们一起开始一门课程,但是你应该利用今天在线平台给我们的东西。
一个社区的形成是因为它的成员有共同的价值观、兴趣和目标。现在有很多人在学习人工智能。很多!有一个很好的理由:
AI 就是新电!
这是伟大的吴恩达 2 年前说的,现在比以往任何时候都更正确。
许多人以这样或那样的方式使用人工智能,称自己为数据科学家、机器学习工程师、人工智能工程师或类似的人。正如我在之前提出的:
数据科学家不是单独存在的,他们需要一个团队,这个团队将使开发智能解决方案成为可能。协作是科学的一大部分,数据科学也不应该例外。
协作学习是一个已被证实的事实,积极的、社交的、有背景的、吸引人的、学生拥有的教育体验会带来更深层次的学习。
学习是一个积极的、建设性的过程。为了学习新的信息、想法或技能,协作学习方法规定学生必须有目的地与他人积极合作。他们需要把这些新材料与他们已经知道的东西结合起来——或者用它来重新组织他们认为他们知道的东西。
此外,因为现实生活项目中的人有不同的背景、学习风格、经验和抱负,所以当我们一起工作时,我们可以直接了解我们和其他人是如何学习的,以及他们给工作带来了什么经验和想法。我们需要在学习时利用多样性。
人工智能可能非常复杂,但汇集更多的智慧,利用我们的差异和相似之处,将有助于以更有效的方式解决困难的问题。但是我们需要结构和指导。让我解释一下这个挑战是关于什么的。
人工智能挑战:在卫星图像上识别树木
如果你想阅读 Omdena 的完整故事以及他们在做什么,请看这篇文章:
一种新的建立人工智能解决方案的方式,通过形成组织、专家和学生的社区来合作…
medium.com](https://medium.com/omdena/why-community-and-collaboration-is-the-key-for-building-ethical-ai-e3389157b691)
你会怎么做?
你将参与一个全球范围的社会影响项目。最少的产出是有一个概念证明。根据你的技能,你将参与不同的角色,如定义项目范围,准备数据,建立人工智能模型。
该项目的目标是建立一个在卫星图像上识别树木的模型。该解决方案将防止因倒下的树木和风暴引发的停电和火灾。这将拯救生命,减少二氧化碳排放,并改善基础设施检查。
申请的要求是什么?
欢迎所有人申请挑战,但我们在这里寻找的是至少完成了一门机器学习或数据科学在线课程的人工智能爱好者。
以下是实际需求:
- 英语良好,能使用电脑上网
- 对计算机科学和/或数学有很好/非常好的理解
- 学生、初级开发人员或正在改变工作领域的开发人员
- 具有 C/C++、C#、Java、Python、R、Javascript 或类似语言的编程经验
- (基础)了解 ML 和深度学习算法。
- 通过或开始了机器学习/深度学习的在线课程。
- 每周约 7-15 小时的工作时间。
对我有什么好处?
您将与真实图像和一起工作,应用深度学习算法,同时与领先的导师合作,获得项目认证,并与世界各地志同道合的人一起提升您的技能。
但如果这还不够,我们还有一件事…
WAAAIIITTT FOR IIITTTTTT!!!
除了独特的学习经历,**成功完成挑战后,项目社区将获得 3000 美元的集体奖金。**这笔钱将由所有参与的社区成员平分,通过协作、社区和共享学习来解决问题。
如何申请?
超级简单,在这里申请就行:
【http://omdena.com/trees/
之后,我们将选择一组人工智能爱好者进行挑战。在项目结束时,成果将会呈现在世人面前。
重要提示:
挑战的空间有限,所以最多只能接受 50 人。不要犹豫,现在就申请吧!挑战下周开始!
项目伙伴关系
我们在sciencia y Datos很高兴能在这个项目中与 Omdena 合作,同时我们帮助建立世界上最大的平台,用于在人工智能、数据科学等领域学习和获得经验。
希望我们将在这个伟大的项目中一起工作,在那里你将学习,享受乐趣并帮助拯救地球,你还能要求什么呢?
如果您有任何问题,请在 Twitter 上添加我,我很乐意帮助您:
Favio Vázquez 的最新推文(@FavioVaz)。数据科学家。物理学家和计算工程师。我有一个…
twitter.com](https://twitter.com/faviovaz)