TowardsDataScience-博客中文翻译-2021-五十六-

TowardsDataScience 博客中文翻译 2021(五十六)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

通过 Docker 的交互式人脸识别应用

原文:https://towardsdatascience.com/interactive-face-recognition-application-through-docker-85e86ad0ffa6?source=collection_archive---------16-----------------------

一种同时利用相机设备、交互式 GUI、Docker、GPU 和深度学习的方法。

丹尼尔·库切列夫在 Unsplash 上拍摄的照片。

T 这篇文章将介绍如何开发一个交互式应用程序,利用 Adam Geitgey 的框架人脸识别,从一个人的相机或网络摄像头设备中识别人脸。为了创建一个交互式应用程序,我们将使用 Tkinter,并使用 Docker 来确保一个包含所有必要依赖项的隔离环境。这篇文章可以作为您自己项目的起点,因为使用哪个框架和库并不重要。了解如何通过 Docker 创建一个利用相机设备、GPU 加速和深度学习框架的交互式应用程序有许多可能性。

如果只是想通过 Docker 运行 GUI,我写了这篇文章,你可以参考:

如果您想立即运行应用程序,可以下载我的 Github 资源库,并遵循本文末尾的“运行应用程序”一节。

阅读指南

在整篇文章中,我们将介绍应用程序中的脚本,之后将介绍运行应用程序的指南。本文将遵循以下顺序。

目录

  1. 先决条件
  2. 应用概述
  3. 码头工人
  4. Tkinter
  5. 摄像设备
  6. 计算机视觉
  7. 命令过程
  8. 运行应用程序
  9. 结论

先决条件

这个应用程序只在 Linux 上测试过,但是,它应该和其他一些参数可能不同的操作系统一样工作,例如当运行 Docker 时。

对于先决条件,你应该有一个摄像头或网络摄像头,Docker,CUDA 和 CuDNN 安装。我已经使用以下工具测试了该应用程序:

  • 20.10.8
  • CUDA 11.4
  • CuDNN 8.2.2
  • 操作系统:Manjaro 21.1.2 Phavo
  • GPU:英伟达 GeForce GTX 1080 Ti
  • 摄像设备:罗技网络摄像头 C930e

目录结构

该项目的目录结构如下所示。你可以预先创建这些文件或者直接从我的 Github 库下载所有文件。此外,您需要在数据集目录中创建自己的目录,并插入所需的图像。在我的例子中,如下所示,我在 Kasper 目录中添加了四个图像。你添加的同一个人在不同场景下的图像越多,你的预测就越准确。关于脚本,它们的内容将贯穿整篇文章。

注:*encodings.pkl*会在后面自动生成。**

应用程序的目录结构。

应用概述

该应用程序包含一个 GUI,它有一个用于显示相机设备输出的面板。此外,还有一个启动/关闭面部识别的按钮。

当前打开人脸识别的应用程序。

码头工人

为了创建一个安装人脸识别、OpenCV、Dlib、Python 等的隔离环境,使用了 Docker 的以下代码。

docker 文件来创建我们的隔离环境。

Tkinter

为了创建可由用户控制的交互式 GUI 来启用和禁用人脸识别,使用了 Tkinter 库。下面的代码创建了之前显示的 GUI。

主脚本,它创建一个 GUI 并允许人脸识别。

摄像设备

为了从相机设备获取图像并更新 Tkinter GUI,可以使用以下脚本。在第 7 行,它使用了 OpenCV 的 VideoCapture 函数,其中的参数应该与您的设备相对应。默认的相机 id 通常是 0,但是,如果它不起作用,您可以尝试使用 1 或-1。如果您希望使用视频,您应该能够将设备 id 替换为视频路径,但是可能需要进行一些其他调整。在第 26 行,它在一毫秒后再次调用函数本身。

计算机视觉

与大多数计算机视觉应用相反,在大多数计算机视觉应用中,你可以通过提供数百个类别的示例来训练模型对所需的类别进行分类,而在人脸识别中,你可以使用深度度量学习。通过深度度量学习,你可以训练一个模型来描述所需的对象,而不是预测它是哪个类。在我们的例子中,我们用它来提供一个特征向量,一个 128 维的编码,用实数描述每张脸。教导模型来描述面部而不是预测特定的人是一个优点,因为如果想要识别一个新人,就不必重新训练模型。相反,我们应该简单地保存这个新的人的编码,这个编码对于这个模型来说是可以达到的。我们将在本文后面获得这些编码。有了人脸识别框架,我们不必从头开始训练模型,而是使用通过人脸识别提供的已经训练好的模型。如果希望进一步探索人脸识别领域,《人脸识别框架》的作者 Adam Geitgey 详细阐述了这个主题:

*https://medium.com/@ageitgey/machine-learning-is-fun-part-4-modern-face-recognition-with-deep-learning-c3cffc121d78

数据集和编码器

为了使模型能够识别人脸,需要一个包含人脸编码的 pickle 文件。为了实现这一点,正如前面在“目录结构”一节中提到的,您必须在目录数据集中创建一个具有所需人员姓名的目录。然后,编码器应该包含以下代码。在这段代码中,我们递归地获取数据集目录中每个人的所有图像。通过使用人脸识别框架,我们定位人脸并提取每个图像的编码。

构建一个 pickle 文件,其中包含来自数据集的编码。

人脸识别

为了识别人脸,将使用以下代码。总结一下代码,它使用来自我们相机设备的图像,检测人脸,为每个人脸提取 128 维编码,然后将新编码与我们的编码数据集进行比较。为了进行比较,它会检查新编码的要素与我们的编码数据集之间的距离,如果某个要素的距离低于容差参数,则该要素会获得投票。为了找到最佳匹配,我们只需选择票数最高的人。如果简单的解决方案不够,您可以实现一个更强的分类器。

更具体地说,VideoStream 为每一帧调用函数process_image,这个函数完成实现人脸识别的所有必要工作。在第 43–45 行,您可以调整用于比较的公差参数。公差越低,比较越严格。此外,在第 48–51 行中,也可以调整highest_vote来增加或减少严格性。

要获得关于面部识别功能的更多详细信息,请参考文档

计算机视觉部分,基于人脸识别框架。*

外壳脚本(警告)

为了使工作更简单,创建一个 shell 脚本,使用以下参数运行 xhost 和 Docker。对于 xhost,启用对每个人的访问,然后在分离 Docker 容器后禁用它。在这个 Docker 命令中,我们共享 GPU、用于查看 GUI 的显示器、用于持续开发的卷和网络摄像头设备。

警告:如果在本地运行,使用 xhost 和这些 Docker 参数应该不成问题。但是,如果用于生产,安全性应该得到加强,这是建议在这里

自动启用/禁用 xhost 并运行 Docker 容器。

运行应用程序

  1. 建立码头工人形象:docker build -t facerecognition_gui .
  2. 使 shell 脚本可执行:chmod +x ./run.sh
  3. 运行 shell 脚本:./run.sh
  4. 在 Docker 容器中,创建编码数据集(确保您的图像位于数据集目录下的某个目录中):python3 encoder.py
  5. 运行应用程序:python3 gui.py
  6. 您现在可以启用面部识别了。

注意: 要分离/退出 Docker 容器,请按 ctrl-D

结论

在本文中,您已经了解了 GUI、摄像设备、GPU 如何与 Docker 一起使用。知道如何将这些结合起来,提供了许多可以用于学术和商业目的的可能性。而且,与 etc 的策略相同。通过 Docker 共享设备,您应该能够利用其他库和框架,而不会遇到问题。

感谢阅读

一如既往,我们非常欢迎反馈。我故意排除了类型提示以减少代码。但是,如果你觉得类型提示有用,请告诉我。

爱沙尼亚塔尔图市常规运动 OD 矩阵互动流程图

原文:https://towardsdatascience.com/interactive-flow-map-with-an-od-matrix-of-regular-movements-in-tartu-estonia-3ac6b7738397?source=collection_archive---------23-----------------------

从呼叫详细记录(CDR)获得传单中的家庭-工作通勤的交互式可视化

图片由作者提供。塔尔图县通勤地图动画

城市发展与人口流动有着紧密的联系。城市规划者根据人口动态的功能做出决策。比方说,交通拥堵是一个明显的事实,即需要特定的道路来到达人们的重要位置(工作场所),然后城市规划者可以决定释放道路压力的选项,如改善公共交通。正如我们所理解的,人口是塑造城市的关键因素,空间维度的指标,如人口密度、年龄组的空间分布或老年人集中程度,有助于做出塑造宜居城市的决策。

由于信息和通信技术(ICT),追踪个人(匿名)成为可能。在世界范围内,手机在通信领域占据着强大的优势,根据统计数据,2021 年手机用户将超过 6 0 亿。移动电话呼叫会在天线网络中创建一个名为呼叫详细记录(CDR)的注册表,该注册表允许创建一个在空间覆盖和时间(纵向)上巨大的数据集。这些移动定位数据有助于研究人员、城市推广者、地方政府、私营公司或区域组织(EU)对城市进行建模。

最终地图动画在此!
储存库在这里!

简介

作为流动性研究的领先国家,爱沙尼亚已经连续收集了 12 年时间序列的 CDR 数据。塔尔图大学移动实验室 从多个角度对数据集进行了分析,例如旅游统计、种族隔离、社交网络、跨境移动(跨国主义)或空间移动等等。这些研究让人们理解了人的流动、有意义的地点和空间。移动定位数据揭示了人们的有意义的位置,例如家或工作(定位点/活动位置)[1],然后可以汇总位置之间的移动,并用于构建日常人流。这些研究在诸如长期活动空间、社会中的居住等级或交通等应用中非常广泛,但对于这种可视化实践,我们将基于 OD 矩阵,该矩阵代表每天从家到工作单位的通勤。您可以在爱沙尼亚地理学家 Anto Aasa 撰写的 移动实验室(OD 矩阵)页面 上扩展阅读关于 CDR 应用和数据集生成的内容。

数据

数据集[2]由电话运营商 Telia、 塔尔图大学地理系移动实验室 和一家分拆公司 Positium LBS 收集和分析。每月约有 420,000 名受访者注意到 锚点模型 应用于确定每月有意义的位置。数据集揭示了用户在社区之间的日常通勤(聚合的空间单位)。

这个数据集的创建是非常特别和令人着迷的,在非常高水平的分析和移动实验室多年的研究中,现在有可能理解城市中人们的通勤,并提供可行的数据来根据人口动态做出决策。

我很高兴我得到了 Anto Aasa 的许可,可以使用这个数据集来制作这个教材。该数据集可以在适当参考的情况下免费使用,不得用于商业目的。

在这里找到数据集

由于产生的线条(运动)的数量,OD 矩阵的可视化可能是压倒性的。在这里,您可以在流程图中直观地看到塔尔图县社区之间的日常通勤活动。正如我们所见,当地图越靠近市中心(塔尔图市)时,它可以显示更多的通勤者。但是,这个练习的主要目的是使这个流动贴图是交互的(动画的),所以有一个更好的观察运动的颗粒。如果您想查看更多关于 OD 矩阵可视化的信息,您可以查看文章“赫尔辛基的自行车共享系统运动:具有交互式流程图的聚合和可视化”

图片由作者提供。塔尔蒂县日常通勤家庭工作流程图

目标

这一可视化实践旨在创建一个互动的地图动画(网络地图),以传单的形式展示爱沙尼亚塔尔图的个人(OD-Matrix)在家和工作之间的移动。

练习

可视化练习分为两个部分: 1)基于 塔尔图县起点-终点的动作子集,Python 传单JavaScript中 OD-Matrix 的交互地图动画。

存储库仅包含常规数据的子集。但是您可以在自己的分析中重用这些代码。为了明确起见,一般数据集包含作为起点的所有邻域和作为目的地的所有邻域。总共有 847 个社区/街区,它们可以在下一张地图上看到:

图片由作者提供。爱沙尼亚的社区/街区

1)定义塔尔图县起点-终点数据集

我们希望在国家级可视化所有以塔尔图县为出发地的旅行和所有以塔尔图为目的地的旅行。

1.1 创建塔尔图县社区列表

我们将读取包含塔尔图县社区的图层,并获取包含所有社区的列表:

import geopandas as gpd
import pandas as pd
from pyproj import CRS
from shapely.geometry import Point# tartu communities
fp = r'data/Communities_Tartu.shp'
geodata_tartu = gpd.read_file(fp)# list with tartu communities for subset 
tartu_communities = geodata_tartu['KANT_nk'].to_list()

图片作者。塔尔图县的街区/社区

1.2 塔尔图县运动子集

这里,我们将使用列表tartu_communities只对 Tartu 县的出发地和目的地进行子集划分。请记住,整个数据集包含国家一级的运动。

# reading movement OD data
fp = r'data/OD_matrix_201708.csv'
movements = gpd.read_file(fp, encoding='Latin')# selecting all origins from Tartu County
origins = movements[movements['KANT_start'].isin(tartu_communities)]# selecting all destination from Tartu County origins
movements_tartu =  origins[origins['KANT_end'].isin(tartu_communities)]

我们在 geopandas 中读取它,因为我们需要在下一步中对列进行几何处理。

1.3 小叶向 WGS84 的坐标转换

在活页中,数据集必须以 WGS84 坐标显示。在这里,我使用了一个技巧。我将投影数据集两次。第一次是获取始发地 WGS84 中的经纬度,第二次是获取目的地的坐标。我投影两次,因为通过创建一个几何图形,它在爱沙尼亚投影中释放,然后我在 WGS84 中投影,然后我得到纬度和经度。像这样:

# create a geometry column of ORIGIN
movements_tartu = movements_tartu.copy()xorigins = movements_tartu['X_start'].to_list()
yorigins = movements_tartu['Y_start'].to_list()movements_tartu['geometry'] = [Point(float(xcoor), float(ycoor)) for xcoor, ycoor in zip(xorigins, yorigins)]# defining data in Estonian coordinate system
movements_tartu.crs = CRS.from_epsg(3301)# reprojecting to wgs84
movements_tartu = movements_tartu.to_crs(4326)# add coordinates in wgs82 for ORIGIN
movements_tartu['x_origin'] = [coordinate.x for coordinate in movements_tartu['geometry'].to_list()]
movements_tartu['y_origin'] = [coordinate.y for coordinate in movements_tartu['geometry'].to_list()]# update geometry for DESTINATION# adding geometry with ending point just to obtain coordinates
xdest = movements_tartu['X_end'].to_list()
ydest = movements_tartu['Y_end'].to_list()movements_tartu['geometry'] = [Point(float(xcoor), float(ycoor)) for xcoor, ycoor in zip(xdest, ydest)]# defining data in Estonian coordinate system
movements_tartu.crs = CRS.from_epsg(3301)# reprojecting to wgs84
movements_tartu = movements_tartu.to_crs(4326)# add coordinates in wgs82 DESTINATION
movements_tartu['x_dest'] = [coordinate.x for coordinate in movements_tartu['geometry'].to_list()]
movements_tartu['y_dest'] = [coordinate.y for coordinate in movements_tartu['geometry'].to_list()]# update geometry for origin
movements_tartu['geometry'] = [Point(float(xcoor), float(ycoor)) for xcoor, ycoor in zip(xorigins, yorigins)]# defining data in Estonian coordinate system
movements_tartu.crs = CRS.from_epsg(3301)# reprojecting to wgs84
movements_tartu = movements_tartu.to_crs(4326)

现在,我为 OD 可视化更新代码,并用 WGS84 坐标子集化所需的列。

# updating code of destinations
movements_tartu['end_kant_id'] = list(range(len(movements_tartu)))movements_tartu['start_kant_id'] = movements_tartu['start_kant_id'].astype(int)
movements_tartu['end_kant_id'] = movements_tartu['end_kant_id'].astype(int)# getting the needed columns
movements_tartu = movements_tartu[['KANT_start', 'KANT_end', 'start_kant_id', 'end_kant_id', 'route_id', 
                                   'Population', 'RegularMovers', 'x_origin', 'y_origin', 'x_dest', 'y_dest', 'geometry' ]]movements_tartu.to_file(r'data/movements_tartu.geojson', driver='GeoJSON')
movements_tartu.head()

图片由作者提供。塔尔图县运动数据集的最终结构

2)宣传单 中的日常通勤互动地图动画

现在,我们必须创建一个包含必要文件的存储库,以使地图动画工作。我们添加了一个名为css 的文件夹和另一个名为js.的文件夹,我们还添加了一个名为index.html的 HTML 文件,您可以通过在本地磁盘上克隆存储库来获得这些文件。因此,您的本地文件夹可能如下所示:

图片由作者提供。知识库结构。

注意在数据文件夹中已经有一个movements_tartu.geojson文件,它是步骤 1)的结果

要使用文件进行 web 映射,我推荐使用Atom**或者简单地使用 记事本++ **

首先,我们将下载并复制文件夹js.中用于 web 映射的 传单 API 另外,我们添加一个空的 JS 文件,在本例中命名为main-movements-tartu.js最后,我们包含了**CanvasFlowmapLayer.js**文件,该文件包含在资源库中,但也可以在jwalsilgeo Github中找到。该文件夹必须如下所示:

图片由作者提供。js 文件夹的结构

然后,在文件夹中,css 我们添加了来自传单的 CSS 文件和一个空文件,在本例中我们称之为map-style.css CSS 文件夹,如下所示:

图片由作者提供。CSS 文件夹的结构

2.1)将文件加载到 index.html

我们将使用 Atom 或 Notepad++打开index.html文件,并开始加载文件。它将包含一个头部和一个主体。在主体部分,我们包含了运行地图动画的主要文件,还有传单文件和数据文件。它包括 ESRI 的基本地图。

<!DOCTYPE HTML><html>
 <head>
  <meta charset="utf-8">
  <title>Daily commuting movements home to work - Tartu</title><!--link to stylesheet-->
  <link rel="stylesheet" href="css/map-style.css"><!-- link to leaflet stylesheet-->
  <link rel="stylesheet" href="css/leaflet.css">
 </head><body>
  <!--the sequence of elements called matters!-->
  <!-- title of your map-->
  <h1> Daily commuting movements home to work - Tartu </h1><!-- division div for the map -->
  <div id="map"></div><!-- link to leaflet javascript library-->
  <script src="js/leaflet-src.js"></script><!-- load Esri Leaflet because we want to use an Esri basemap -->
  <script src="[https://unpkg.com/esri-leaflet@2.3/dist/esri-leaflet.js](https://unpkg.com/esri-leaflet@2.3/dist/esri-leaflet.js)"></script><!-- Load animation tweening lib requirement for CanvasFlowMapLayer -->
  <script src="[https://unpkg.com/@tweenjs/tween.js@18.5.0/dist/tween.umd.js](https://unpkg.com/@tweenjs/tween.js@18.5.0/dist/tween.umd.js)"></script><!-- then load CanvasFlowMapLayer -->
  <script src="js/CanvasFlowmapLayer.js"></script><!--link to the files that contains geoJson data-->
  <script src="data/movements_tartu.geojson" > </script><!-- link to main javascript file -->
  <script src="js/main-movements-tartu.js"></script></body>
<html>

2.2)map-style . CSS 中的参数

我们必须样式化 HTML 文件,并简单地样式化对象:标题、正文、图例和地图。打开map-style.css,包含下一段代码:

h1{
 position: fixed;
 font-family: "Times New Roman", Times, serif;
 font-size: 24px;
  box-shadow: 2px 2px 3px 3px black;
 background: lightgray;
    color: black;
    margin-left:5%;
    margin-top: 0.6%;
    z-index: 2;
}
body{
 width: 100%;
 height: 100%;
 margin: 0px;
 font-family: "Times New Roman";
}
.info {
    padding: 6px 8px;
    font-family: "Times New Roman", Times, sans-serif;
    font-size: 16px;
    background: white;
    background: rgba(255,255,255,0.8);
    box-shadow: 0 0 15px rgba(0,0,0,0.2);
    border-radius: 5px;
}
.info h3 {
  font-size: 18px;
  font-family:  "Times New Roman", Times, serif;
  text-decoration: underline;
  text-shadow: 2px 2px 5px gray;
    margin: 0 0 5px;
    color: #282825   ;
}
.legend {
    line-height: 20px;
    color: #555;
}
.legend i {
    width: 25px;
    height: 18px;
    float: left;
    margin-right: 8px;
    opacity: 0.7;
}
#map {
 height:100%;
 width:100%;
 left:0%;
 overflow:hidden;
 position:fixed;
 border:1px #444 solid;
}

如果您在浏览器中打开 index.html,您可能会看到如下所示的空白画布:

图片由作者提供。空画布

2.3)定义数据移动中的变量-tartu.js

要在传单中包含运动数据集,您可能需要将其定义为一个变量。您需要打开数据文件,并包含var geoJsonFeatureCollection =因此,数据文件必须如下所示:

图片由作者提供。数据的变量定义

2.4)在 main-movement-Tartu . js中创建地图动画

在这里,我们将开始创建带有传单的地图,并制作塔尔图县附近的运动动画。我们一步一步来。你可以看一下 传单互动 Choropleth Map 的例子,我在建立 Map 变量和定义图例颜色时得到了一些帮助。

首先,我们为地图添加一个变量,定义缩放级别和中心。然后,我们添加一个 ESRI 底图。

//--- PART 1: ADDING BASE MAPS AND SCALE BAR ---// variable for the map
var map = L.map('map', {
 center: [58.57, 25.5],
 zoom: 8
});var esri = L.esri.basemapLayer('DarkGray');
 esri.addTo(map);L.control.scale({imperial:false, position:'bottomright'}).addTo(map);

图片作者。从传单和 ESRI 底图添加的地图对象

现在,我们用动画功能添加运动数据。

// — — PART 2: ADDING ANIMATION OF OD MATRIX WITH VARIABLE geoJsonFeatureCollection — -var oneToManyFlowmapLayer = L.canvasFlowmapLayer(geoJsonFeatureCollection, {
 originAndDestinationFieldIds: {
 originUniqueIdField: ‘start_kant_id’,
 originGeometry: {
 x: ‘x_origin’,
 y: ‘y_origin’
 },
 destinationUniqueIdField: ‘end_kant_id’,
 destinationGeometry: {
 x: ‘x_dest’,
 y: ‘y_dest’
 }
 },
 canvasBezierStyle: {
 type: ‘classBreaks’,
 field: ‘RegularMovers’,
 classBreakInfos: [{
 classMinValue: 0,
 classMaxValue: 24,
 symbol: {
 strokeStyle: ‘#fee8c8’,
 lineWidth: 0.5,
 lineCap: ‘round’,
 shadowColor: ‘#fee8c8’,
 shadowBlur: 2.0
 }
 }, {
 classMinValue: 25,
 classMaxValue: 100,
 symbol: {
 strokeStyle: ‘#fdbb84’,
 lineWidth: 1.5,
 lineCap: ‘round’,
 shadowColor: ‘#fdbb84’,
 shadowBlur: 2.0
 }
 }, {
 classMinValue: 101,
 classMaxValue: 10000000,
 symbol: {
 strokeStyle: ‘#e34a33’,
 lineWidth: 3,
 lineCap: ‘round’,
 shadowColor: ‘#e34a33’,
 shadowBlur: 2.0
 }
 }],
 defaultSymbol: {
 strokeStyle: ‘#e7e1ef’,
 lineWidth: 0.5,
 lineCap: ‘round’,
 shadowColor: ‘#e7e1ef’,
 shadowBlur: 1.5
 },
 },
 pathDisplayMode: ‘selection’,
 animationStarted: true
}).addTo(map);// Selection for dispaly
oneToManyFlowmapLayer.on('mouseover', function(e) {
 if (e.sharedOriginFeatures.length) {
 oneToManyFlowmapLayer.selectFeaturesForPathDisplay(e.sharedOriginFeatures, 'SELECTION_NEW');
 }
 if (e.sharedDestinationFeatures.length) {
 oneToManyFlowmapLayer.selectFeaturesForPathDisplay(e.sharedDestinationFeatures, 'SELECTION_NEW');
 }
});oneToManyFlowmapLayer.selectFeaturesForPathDisplayById('start_kant_id', 673, true, 'SELECTION_NEW');

如果你更新index.html,你已经可以看到动画了。

图片由作者提供。塔尔蒂县每日通勤回家工作的交互式流程图

我们已经定义了运动将通过mouseover 动作可视化。因此,与地图动画的交互只需要将鼠标悬停在元素周围。此外,我们定义了 3 个类以及起点和终点的坐标。最后,我们添加带有颜色的图例,如果你需要支持选择颜色,你可以使用 ColorBrewer 来绘制 :

//PART 3\. ADDING A LEGEND WITH COLORSfunction getColor(d) {
return d > 100  ? '#e34a33' :
       d > 24   ? '#fdbb84' :
                '#fee8c8' ;
}var legendcolor = L.control({position: 'bottomright'});legendcolor.onAdd = function (map) {
  var div = L.DomUtil.create('div', 'info legend'),
    grades = [0, 24, 100],
    labels = [];
    // loop through our density intervals and generate a label with a colored square for each interval
        for (var i = 0; i < grades.length; i++) {
            div.innerHTML +=
            '<i class ="line" style="background:' + getColor(grades[i] + 1) + '"></i> ' +
            grades[i] + (grades[i + 1] ? '&ndash;' + grades[i + 1] + '<br>' : '+');}    return div;
       };
legendcolor.addTo(map);

与传说看起来是这样的。

图片由作者提供。带图例的最终地图

推荐

如果你对网页地图的活页 JavaScript 有经验。您可以添加社区作为背景,或者添加一个带有社区名称的信息框。我把这个自由留给用户。但是现在,你有了塔尔图县的起点-终点矩阵的基础。

结论

塔尔图县在家工作运动的地图动画有助于城市规划者了解人口动态(空间流动性)。有了这个,运输就可以改善,尤其是旅行时间。当然,人们更喜欢开快车去上班。此外,本地投资可以是一个长期的选择,投资于房地产的办公室。如果人们是为了工作而迁移,这肯定是一个潜在的经济增长的地方。

如果您需要 OD 矩阵可视化或 Python 编码地图方面的支持,您可以在我的 LinkedIn 个人资料中找到我,或者在本文中发表评论。

参考文献

[1]阿哈斯,r .,西尔姆,s .,约尔夫,o .,萨卢维尔,e .,蒂鲁,M. (2010 年)。利用移动定位数据对手机用户有意义的位置进行建模。 卷十七。https://doi.org/10.1080/10630731003597306

[2] Aasa,A. (2019)。 【数据集】 爱沙尼亚日常规律运动 OD 矩阵。塔尔图大学移动实验室。https://doi.org/10.23659/UTMOBLAB-1

带有 GeoPandas 的交互式地理地图

原文:https://towardsdatascience.com/interactive-geographical-maps-with-geopandas-4586a9d7cc10?source=collection_archive---------5-----------------------

通过交互式可视化浏览地理空间数据

作者使用 GeoPandas 库创建的世界地图

如果地理是散文,地图就是图像学

地理空间一词由两个不同的术语组成。 Geo 的意思是地球, Spatial 的意思是关于或者占据空间。它共同指代与地球表面特定位置相关的基于时间的数据。GeoPandas 是一个流行的库,用于分析和处理 Python 中的地理空间数据。在最近的一次更新中,该库增加了支持交互式可视化的方法和实用程序。这是对一个已经很有用的库的一个很好的补充。

GeoPandas 库最新版本亮点:来源:https://geo pandas . readthe docs . io/en/latest/docs/changelog . html # version-0-10-0-10-3-2021

在本文中,我们将详细探讨 GeoPandas 的交互性。我们将从简单介绍 GeoPandas 开始,然后继续介绍它的一些可视化功能。

地质公园

GeoPandas 是一个广泛使用的开源库,用于在 Python 中操作地理空间数据。它扩展了 pandas data frame 的功能,从而使在 pandas 中处理空间数据成为可能,因此得名。在某种程度上,GeoPandas 结合了熊猫和 Shapley 的力量。 Shapley 是一个 Python 包,用于处理和分析笛卡尔平面中的几何对象。

装置

Geopandas 可以用condapip安装,也可以直接从source安装。然而,首选方法是使用 conda,因为它为所有平台(Windows、Mac、Linux)提供了预构建的二进制文件。

conda install -c conda-forge geopandas

此外,还需要 folium、matplotlib 和 mapclassify 包来实现交互性。您可以使用以下方式安装它们:

conda install -c conda-forge folium matplotlib mapclassifyorpip install folium matplotlib mapclassify

参考安装指南获取详细说明和疑难解答。

使用 GeoPandas 的第一步

如果这是你第一次听说 GeoPandas,我推荐你浏览一下这个简短教程。本教程将帮助您快速熟悉该库。简而言之,GeoPandas 建立在 Pandas 库的基础上,使其与地理空间数据兼容。

GeoPandas 建立在熊猫图书馆上|图片由作者提供

GeoPandas 使用GeoSeriesGeoDataFrame类型,它们分别是pandas.Seriespandas.DataFrame的子类。上图显示了两者之间的关系。

用 GeoPandas 绘制静态地图

在本节中,我们将了解 GeoPandas 的基本功能,即绘制静态地图。这一节为下一节打下了必要的基础,下一节涉及到创建交互式可视化。

🔗您可以从以下位置访问代码笔记本👇

https://github.com/parulnith/Data-Science-Articles/tree/main/Interactive Geographical maps with Geopandas

导入库

GeoPandas 成功安装后,我们可以导入它并验证我们的系统上是否安装了最新版本。

import geopandas
import matplotlib.pyplot as plt
print(geopandas.__version__)
------------------------------------------
0.10.2

读入数据

让我们使用内置的 GeoPandas 数据集进行演示。在本文的后面,我们还将学习如何处理我们自己的数据。GeoPandas 附带三个预制地图,可通过以下方式轻松访问:

geopandas.datasets.available
----------------------------------------
['naturalearth_cities', 'naturalearth_lowres', 'nybb']

在哪里

  • naturalearth_lowres → 国家轮廓
  • naturalearth_cities → 城市位置
  • nybb → 纽约行政区

让我们使用**naturalearth_lowres** 选项并显示数据集。

world_filepath = geopandas.datasets.get_path('naturalearth_lowres')
world = geopandas.read_file(world_filepath)
world.head()

作者的 GeoPandas 数据帧|图像

如上所述,我们得到一个 GeoPandas 数据帧,其中有一个独特的几何列。除此之外,还可以获得各个国家的 GDP 和人口等信息。

可视化数据

为了绘制活动几何图形,我们将调用[GeoDataFrame.plot()](https://geopandas.readthedocs.io/en/latest/docs/reference/api/geopandas.GeoSeries.plot.html#geopandas.GeoSeries.plot).。该方法使用 matplotlib 生成几何图形列的图形。

world.plot()

作者图片

输出是使用一行代码创建的世界地图。我们还可以利用可用的参数在获得的图中创建多种变化。

  • 特定列的颜色编码

假设我们想要以国家为单位来可视化世界人口。为此,我们将传递列*pop_est*,即数据帧中指定人口作为第一个参数的列。从技术上讲,几何列仍然被绘制,但是该图由*pop_est*列进行颜色编码。

world.plot('pop_est', legend=True,figsize=(12,8))
plt.title('World Population')

作者图片

人口最多的国家用黄色和浅绿色表示,而人口最少的国家用紫色表示。

  • 彩色地图

如果你不喜欢默认的地图颜色,你可以使用cmap属性轻松修改它。有关兼容选项的列表,请访问官方 matplotlib 网站。默认颜色图是viridis。让我们来看看更多的色彩映射表以及它们是如何渲染地图的:

🎨设置 2

cmap='Set2'
world.plot('pop_est', cmap=cmap, legend=True,figsize=(12,8))
plt.title(f'World Population with colormap: {cmap}')

作者图片

🎨 岩浆

cmap='magma'
world.plot('pop_est', cmap=cmap, legend=True,figsize=(12,8))
plt.title(f'World Population with colormap: {cmap}')

作者图片

  • 边界

也可以只显示地图边界。

world.boundary.plot(figsize=(12,8))

作者图片

绘制交互式地图

上一节所有的情节本质上都是静态的。这意味着我们无法通过缩放、平移、悬停或弹出窗口等功能与他们互动。然而,explore方法提供了将静态地图转换成交互式地图的能力。

句法

*GeoDataFrame.explore()*

用法上没有太大区别。explore()方法返回一个呈现交互式地图的folium.Map对象。让我们将上面创建的静态人口世界地图转换为交互式地图。

world.explore(column='pop_est',cmap='Set2')

作者图片

稍加修改,我们就有了一个完全交互式的图表。让我们创建一个只显示亚洲地区 GDP 的新图表。由于 GeoPandas 是 Pandas 的扩展,我们可以很容易地根据条件过滤列。

计算亚洲的 GDP

asia = world[world['continent'] =='Asia']
asia.explore(column='gdp_md_est',cmap='Set2')

作者图片

参数

在上面的例子中。我们只使用了两个参数,即columncmap。然而,explore()方法附带了许多有用的参数。一些有趣的例子如下:

  1. 工具提示

默认为Truetooltip参数显示悬停在对象上时的地理数据场属性。可以通过将其设置为 False 来禁用它。

asia = world[world['continent'] =='Asia']
asia.explore(column='gdp_md_est',cmap='Set2',tooltip=False)

我们还可以传递一个字符串或一个字符串列表来指定那些需要包含的列。在下面的地图中,我们只需要国家的名称及其对应的 GDP 值。因此,我们将在工具提示参数中指定相同的内容。

asia = world[world['continent'] =='Asia']
asia.explore(column='gdp_md_est',
             cmap='Set2',
             legend=False,
             **tooltip=['name','gdp_md_est']**)

作者图片

2.弹出

如果工具提示参数已启用,属性会在简单悬停时可见。另一个选项是使用弹出选项有选择地启用它们。使用弹出窗口的好处是属性信息只有在被点击时才会显示。在这里,我们也可以传递字符串或字符串列表来指定要包含的列。

asia = world[world['continent'] =='Asia']
asia.explore(column='gdp_md_est',
             cmap='Set2',
             legend=False,
             tooltip=False
             **popup=['name','gdp_md_est']**)

作者图片

3.瓷砖

此参数指定要使用的图块。内置选项包括:

OpenStreetMap,雄蕊地形,雄蕊调色剂,雄蕊水彩,CartoDB 正电子,CartoDB 暗物质 _ deafult 使用 OpenStreetMap 的地方。

asia = world[world['continent'] =='Asia']asia.explore(column='gdp_md_est',
             legend=False,
              **tiles**=<enter the name of the tile to be used>)

作者图片

4.图例

此参数决定是否在地图上显示图例。

  1. style_kwds

如果需要传递一些额外的样式,那么style_kwds就是要传递的参数。例如,是否在地图上绘制边界、边界的颜色、不透明度、填充选项可以由该参数控制。例如,假设我们想要显示亚洲 GDP 地图,其中边界是红色的,宽度= 0.2,不透明度为 0.1。

asia = world[world['continent'] =='Asia']
asia.explore(column='gdp_md_est',
             cmap='Set2',
             legend=False,
             style_kwds=dict(color="black",weight=3, opacity=0.4))

作者图片

使用你自己的数据

到目前为止,我们一直使用库预加载的自定义数据集。实际上,我们希望使用自己的数据集。包含一个latitude和一个longitude列的数据集可以很容易地转换成 GeoPandas 数据帧。为了演示这种技术,我借用了下面这篇文章中的数据集:

该数据集包括自 2018 年以来印度每次地震的日期、时间、位置、深度、震级和震源的记录。让我们导入数据并查看各种属性。

df = pd.read_csv('Indian_earthquake_data.csv')
df.head(10)

由于 dataframe 有一个纬度和经度列,因此可以很容易地将其转换为 GeoPandas Dataframe。

from geopandas import GeoDataFrame
from geopandas import points_from_xygeometry = points_from_xy(df['Latitude'],df['Longitude'])
df2 = GeoDataFrame(df, geometry=geometry)
df2.head()

作者图片

结论

本文介绍了通用的 GeoPandas 库,以及它在使用 Python 处理地理空间数据时的表现。我们首先学习了它的基本用法,然后转向更新的交互功能。我相信您会喜欢进一步探索这个库,并将其用于您自己的数据集来执行分析。地理空间分析是一个迷人的领域,GeoPandas 完成了主要的繁重工作,因此用户可以将注意力更多地放在手头的问题上,而不是工具上。

👉 对自己阅读其他文章感兴趣。这个 回购 包含了我写的所有文章,分类排序。

https://github.com/parulnith/Data-Science-Articles/blob/main/README.md

Jupyter 笔记本中的交互式地理空间人工智能可视化

原文:https://towardsdatascience.com/interactive-geospatial-ai-visualization-in-jupyter-notebook-f3223f534327?source=collection_archive---------25-----------------------

简化地理空间数据探索,构建强大的人工智能应用

了解您的数据是在生产中构建和部署健壮的 AI/ML 系统的关键。因此,在制定 AI/ML 解决方案之前,必须事先进行良好的探索性数据分析(EDA)。然而,在地理空间数据集上执行 EDA 可能会令人望而生畏,而且往往具有挑战性,尤其是当您必须在广阔的区域和许多数据层中导航以进行分析时。不要担心,通过充分的练习,你会掌握它的窍门,这篇文章有望帮助你开始学习!

美国宇航局在 Unsplash 拍摄的照片

目录:

  1. 装置
  2. 小部件简介
  3. 创建简单的地图
  4. 自定义您的地图
  5. 图层、栅格和矢量简介
  6. 添加层

装置

对于这个关于 Jupyter 笔记本中交互式地理空间数据可视化的教程,我们将安装 ipyleaflet 库。

conda install -c conda-forge ipyleaflet

什么是 ipyleaflet?

传单是最流行的可视化地理空间数据的 JavaScript 库之一。它被 OpenStreetMap 和 MapBox 等大型机构广泛采用。

如果您正在寻找 ipyleaflet 的替代方案,您可以考虑使用https://python-visualization.github.io/folium/python 包来帮助您可视化交互式传单地图。

小部件简介

现在我们已经讨论了设置阶段,让我们深入探讨这篇文章的主题。

Jupyter 中的交互可视化是什么意思?小部件如何实现这一点?最重要的是,什么是 widget?

这些问题在你开始看这个帖子的时候必然会蹦出来。对于熟悉的人,请快速复习下一部分。

交互可视化? 它仅仅意味着与你的视觉实时互动的能力。以下面这张 GIF 为例。你可以通过视觉方式与滑块互动。

交互式可视化(作者提供的 GIF)

Jupyter Widget? 它们被称为“特殊对象”,可以被初始化并显示在笔记本上。它们也是双向,这意味着一个小部件不只是显示,还可以接收用户输入,随后触发新的计算。最重要的是,它们是可扩展的。Jupyter 小部件允许其他库在其功能的基础上构建额外的特性,比如我们的 ipyleaflet。

创建简单的地图

现在,我们准备好处理 ipyleaflet 。首先,让我们展示一张基本的世界地图。

首先,我们需要导入 ipyleaflet 库及其 Map 对象。

*from ipyleaflet import Map*

然后,给定中心点的坐标和缩放级别,我们构建并可视化地图对象。

*Map(center = (60, -2.2), zoom = 2, min_zoom = 1, max_zoom = 20)*

简单互动图(作者 GIF)

在上面的 GIF 中,您可以通过滚动和平移输出图像来与新创建的地图进行交互。做得好!

自定义您的地图

例如,我们还可以通过对底图进行样式化来定制我们的地图。

首先,我们导入另一个名为底图的对象。

*from ipyleaflet import Map, basemaps*

然后,我们添加可视化到我们的地图对象,如下所示。

*map = Map(center=(60,-2.2), zoom=2, basemap=basemaps.Stamen.Terrain)*

自定义地图(作者提供的 GIF)

使用自定义地形底图后,地图变得更加漂亮。

有大量的定制可用。查看他们的 API 参考以获得更详细的解释。

图层、栅格和矢量简介

现在,这将是你大部分 EDA 发生的地方。我将展示如何添加层以及如何操作它们。

但是首先。

什么是层? 图层用于显示地理数据集。它们的目的是分离不同的地理信息,这些信息可能相互关联,也可能不相互关联。例如,为了展示一个城市的地图,您可能想要显示一个底图图层(之前高亮显示)、城市中的道路网络、住宅区、海拔高度以及水体娱乐区的存在。

现在,什么是光栅或者矢量?

下图为了解什么是图层以及栅格/矢量数据之间的区别提供了一个方便的图示。

解释图层、栅格和矢量数据(来源:SBCounty.gov)

如果你想对这个话题有更详细的解释,请看看我下面的另一篇博文。

*

添加图层

最后但同样重要的是,如果不能添加自己的图层,交互式地理空间地图是不完整的。

让我们首先通过调用 add_layer() 方法添加一个光栅图层。

from ipyleaflet import basemap_to_tiles as btt, basemaps, Map

raster = btt(basemaps.NASAGIBS.ModisTerraTrueColorCR, "2019-06-24")
map.add_layer(raster)map

添加图层(作者 GIF)

如果您选择移除这一层,那么您可以简单地调用 remove_layer()方法。

map.remove_layer(raster)map

移除图层(作者 GIF)

但是,如果您不想通过编写代码来不断添加或删除层,该怎么办呢?你可以在地图上添加一个图层控件来实现。

from ipyleaflet import LayersControlmap.add_control(LayersControl())

图层控件(GIF by Author)

你现在可以在地图上对你的图层有更多的控制了!

结论

这就是 Jupyter 笔记本上交互式地理空间可视化的介绍。我将很快创建第二部分来讨论更高级的技术,如地图分割,从 GeoJSON 和其他文件格式添加数据等。敬请期待!*

做订阅我的邮件简讯:https://tinyurl.com/2npw2fnz***在那里我定期用通俗易懂的语言和漂亮的可视化方式总结 AI 研究论文。*****

Unity 中的交互式线性回归

原文:https://towardsdatascience.com/interactive-linear-regression-in-unity-fc4db4a143d9?source=collection_archive---------29-----------------------

从实时模拟和游戏的机器学习开始

现代视频游戏引擎,如 Unity,已经成为各种模拟和建模的伟大工具。相反,大量的机器学习研究是在视频游戏上进行的。最后,机器学习将改变我们制作视频游戏的方式。本文探讨了如何使用 Unity 进行机器学习的基础知识。

在这篇文章中,我将解释如何使用交互式数据集在 Unity 中实现实时线性回归。生成的程序可以在下面的 gif 中看到。代码在 GitHub 上有。本教程需要 Unity 的基本知识——如果您没有 Unity 的经验,您可以通过本 入门教程 快速了解最新情况。

绿线不断地插入红点之间。随着点数的增加,它会自动调整。

场景设置

如果你不清楚如何使用下面的说明来设置场景,只需从GitHub中克隆项目。

该程序使用 2D 统一图形系统,所以我们从 2D 模板开始,并添加一个 UICanvas。

为了这个项目的目的,我决定绘制 10001000 像素的图形,设置界面分辨率为 19201080 像素。

然后,我们从图像组件创建绘图。绘图的背景是一个 10001000 px 的白色图像,两个黑色图像代表位于中心的 10001 px 和 11000 px 的线。插值线是 20003 px 的绿色图像。最后,我们添加一个按钮锚定到左上角,以清除我们已经添加的点。

完整的场景。所有的对象(图、轴、轴、线)都是具有特定颜色的清晰图像。

生成点

首先,我们创建代码来生成PointGenerator.cs组件中的点。对于给定的初始化,我们使用以下字段。

[SerializeField] private GameObject **pointPrefab**;

public List<GameObject> Points { get; private set; }

private void **Start**()
{
    Points = new List<GameObject>();
}

pointPrefab必须引用代表图上一点的对象。然后创建的点存储在点列表中。使用以下函数创建点:

private void AddPoint(Vector2 position)
{
    var point = Instantiate(pointPrefab, transform);
    point.transform.localPosition = position;
    Points.Add(point);
}

我们还创建了一个函数来清除这些点:

public void **ClearPoints**()
{
    Points.ForEach(Destroy);
    Points.Clear();
}

然而,最重要的是确定鼠标点击时在哪里创建新点的代码。我们根据鼠标点击时的鼠标位置来放置点,因此我们需要通过计算图的偏移来计算点在图中的位置。我们获得绘图和屏幕的大小(第 1-2 行),计算差异(第 3-4 行),然后定义从绘图中心的位置(第 5 行)并创建一个新点。

public void OnPointerDown(PointerEventData eventData)
{
    var plotSize = GetComponent<RectTransform>().sizeDelta;
    var screenSize = new Vector2(Screen.width, Screen.height);
    var offset = (screenSize - plotSize) / 2f;
    var imagePosition = eventData.position - offset;
    var plotPosition = imagePosition - plotSize / 2f;
    AddPoint(plotPosition);
}

最后,为了让OnPointeDown回调对鼠标点击做出反应,我们需要组件使用适当的接口:

public class **PointGenerator** : MonoBehaviour, IPointerDownHandler

现在把上面的代码组合起来,放在Plot对象上,并附加一个对Point预设的引用。您应该能够通过单击鼠标在绘图中创建点。

现在,您也可以将Clear按钮连接到图上,以便清除印刷机上的点:

插值函数

在正常的机器学习中,我们在执行过程中训练一次模型,运行一个优化步骤的循环(所谓的时期)。然而,Unity 作为一个游戏引擎,是建立在以连续的方式每秒多次执行小步骤的原则上的。然后,我们可以保持优化过程以固定的速率运行,就像我们在物理模拟中所做的那样。

我们创建一个名为LineFitter的新组件,并将其添加到Line游戏对象中。我们还需要引用PointGenerator来获得坐标。

public class **LineFitter** : MonoBehaviour
{
    [SerializeField] private PointGenerator **pointGenerator**;
}

我们优化器的目标(我们将使用线性回归常用的梯度下降)是尽可能地拟合曲线y = w * x + b。为此,我们将拟合参数w(权重)和b(偏差)。然后,我们使用以下函数进行拟合,将w转换为围绕z轴的相应旋转:

private void SetLine(double w, double b)
{
    double rad = Math.Atan(w);
    double deg = rad * 180 / Math.**PI**;
    transform.localPosition = new Vector3(0, (float) b, 0);
    transform.localRotation = Quaternion.Euler(0, 0, (float) deg);
}

我们将在每次FixedUpdate回调时优化并更新该行,这意味着每秒将发生 60 次。如果集合中没有点,我们只需将线重置到原始位置:

private double w, b;

private void **FixedUpdate**()
{
    if (!pointGenerator.Points.Any())
    {
        w = b = 0;
    }
    else
    {
        GradientDescent();
    }
    SetLine(w, b);
}

最后,我们定义了优化函数。我不会在这篇文章中推导优化过程,如果你有兴趣进一步,见例如这里。对于我们的实现来说,有趣的是第 1–4 行,其中 Unity 位置被转换成两个带有 X 和 Y 坐标的列表。一旦我们有了这些,我们就可以像往常一样计算参数wb的导数。

[SerializeField] private double **learningRate** = 0.000001;
[SerializeField] private double **normalize** = 1000;private void GradientDescent()
{
    var points = pointGenerator.Points;
    var positions = points.Select(p => p.transform.localPosition);
    var X = positions.Select(pos => pos.x);
    var Y = positions.Select(pos => pos.y);
    double n = points.Count;
    var Y_pred = X.Select(x => x * w + b);
    double dW = -2.0 / n * Y
        .Zip(Y_pred, (y, yPred) => y - yPred)
        .Zip(X, (y_p, x) => y_p * x)
        .Sum();
    double dB = -2.0 / n * Y
        .Zip(Y_pred, (y, yPred) => y - yPred)
        .Sum();
    w -= learningRate * dW;
    b -= learningRate * dB * normalize;
}

请注意,有两个公共参数。learningRate是一个常见的,但是我们也增加了一个归一化项。这是因为 Y 轴是 1000 个单位高,因此在一个小的步骤中,需要很长的时间来收敛。因此,我们将 Y 轴移动到一个单位范围,步长增加 1000 倍。

现在你可以把上面的代码组合起来,附加到Line GameObject 上。

具有 LineFitter 组件的 Line 对象。请注意,它引用了点生成器。

全部完成!

恭喜你,你已经创建了一个简单的,交互式的,实时的机器学习系统!虽然这只是一个演示最简单的 ML 算法之一的例子,但是 ML 方法在现代游戏和模拟系统中越来越多地被实施,以创建决策系统、创建内容、控制 NPC、平衡匹配等等。

如果你对游戏中更复杂的 ML 方法感兴趣,请随意查看我在 Unity 中基于 ML-Agents 技术的自动驾驶汽车教程,或者查看 Unity 在真实世界应用中的博文

利用 Streamlit 实现交互式机器学习和数据可视化

原文:https://towardsdatascience.com/interactive-machine-learning-and-data-visualization-with-streamlit-7108c5032144?source=collection_archive---------14-----------------------

我如何将我的 K-Means 聚类和 PCA 代码重新整合到一个时髦的 web 应用程序中,用于分析 Spotify 播放列表

在信息时代,漂亮的界面不仅仅是被推崇,更是被期待。 Spotify Wrapped 是一项年度活动,旨在为所有 Spotify 用户带来个性化的生活配乐见解。它完全由大数据和分析驱动,但将它从一份有趣的用户报告提升为今天的文化现象的是用鲜艳的颜色和令人难忘的字体包装的大而粗的数字。正是视觉效果和设计选择在观看和分享我们的音乐收听趋势和统计数据时引发了多巴胺热潮。可悲的事实是:对普通人来说,数字本身并不性感。

正如故事不仅通过内容和交付来评估,菜肴也通过味道和呈现来评估一样,机器学习和数据科学交汇处的研发不仅应该通过发现的见解的质量来评估,还应该通过将这些见解带给非技术人员的可视化来评估。

当我在思考我的上一篇文章时,我开始发现少了些什么。虽然我对我的工作很满意,对我的发现很满意,但我觉得工作的影响是有限的;这篇文章对技术数据科学的人来说有点太适合了,我真的只是解决了我自己的个人问题。我突然想到这个项目还没有完成。当 Jupyter 笔记本不再是一个游乐场,而是一个文档化的教程时,前进方向的下一步是构建一个时尚的 web 应用程序供所有人使用!

我希望人们能够与我的项目互动,并给我反馈,而不必阅读我的 11 分钟媒体文章。也就是说,本文旨在强调我用来构建 web 应用程序的框架 Streamlit 的一些功能。这不会是如何在 Streamlit 中构建应用程序的指南,但我会在最后为感兴趣的人提供一些技术细节。对于那些希望自己探索的人,滚动到底部找到应用程序和源代码的链接。

什么是 Streamlit?

Streamlit 是一个新工具,它允许工程师在几分钟内构建和分享高度互动的网络应用。它是免费和开源的,重点是 Python 脚本、交互式小部件和即时部署。

Streamlit 是否会导致 Flask 灭绝是一个激烈争论的话题。有些人认为这是苹果和橘子的比较,因为 Streamlit 是一个数据仪表板工具,而 Flask 是一个 web 框架。此外,这只是 web 应用和仪表板领域的两个竞争者。Plotly Dash、Shiny、Voila、Panel 和 Jupyter 都是这个领域的常用词。如果你对成熟度、流行度、简单性、适应性、专注度和语言支持方面的权衡感兴趣,我推荐你阅读“Streamlit vs . Dash vs . Shiny vs . Voila vs . Flask vs . Jupyter”。如果您想要一个内置许多方便组件的结构化数据仪表板,Streamlit 是一个不错的选择。为什么要重新发明轮子,对吗?

souce:Markus Schmitt 在 datarevenue 发表的“Streamlit vs . Dash vs . Shiny vs . Voila vs . Flask vs . Jupyter”

鉴于 Streamlit 最近的增长和牵引力,如上图所示,描绘了 Streamlit 在短时间内 GitHub 明星的暴涨——Streamlit 赢得了很多兴奋和期待。该平台的新扩展 Streamlit for Teams 即将推出,将提供企业级功能,如身份验证、日志记录、自动扩展和一键式部署。这是非常有前途的,可能会极大地有益于数据科学和机器学习领域。

播放列表混合

现在,请允许我带您参观一下我的新网络应用程序!Playlist Blendr 是一个 web 应用程序,它使用 k-means 聚类和主成分分析(PCA)按相似的音频特征对音乐进行聚类,以便用户可以培养一种有凝聚力的氛围来满足他们的音乐收听需求。作为一个使用案例,用户可以转到他们朋友最喜欢的播放列表,将相应的播放列表 URIs 复制并粘贴到 Playlist Blendr 中,然后识别所有高能量、高节奏的说唱歌曲,非常适合深夜驾车,也适合音乐发现目的。

web 应用程序,一目了然

目标是允许用户通过设置授权流,通过 Spotify API 向外部用户授予令牌,将同一集群中的曲目导出到用户 Spotify 库中的新播放列表,但这一授权功能在 Streamlit 中尚不可用。

在整个开发过程中,我不得不有意识地努力将所有本质上的 ML 细节隐藏在“引擎盖下”,这样应用程序的真正本质就像一个神奇的黑盒一样呈现在用户面前——一个只吐出交互式可视化内容的盒子。在接下来的几节中,我将介绍四个出色的 Streamlit 组件,它们已经融入了我的 web 应用程序。

补充报道

与任何 web 应用程序一样,为了将用户的注意力引向页面上的各个组件,布局非常重要。Streamlit 可以很容易地用 st.sidebar 在左面板侧边栏中组织你的小部件。此控制流适用于 Playlist Blendr,因为应用程序最初依赖于播放列表 URIs(统一资源指示符)形式的用户输入。虽然 Streamlit 应用程序非常兼容移动设备,但不幸的是,Spotify URIs 只能从 Spotify 桌面客户端找到。下面提供了如何检索播放列表 URI 的演示。

如何从 Spotify 桌面客户端检索播放列表 URI

在用户输入他们想要的播放列表 URIs 数并点击“运行算法”按钮之前,应用程序的主要部分什么都不会发生。

通过巴斯德的 Streamlit 数字输入小工具从用户处收集播放列表信息

Streamlit 侧栏配置的代码

在上面的代码中,调用了三个 Streamlit 方法: st.sidebar.number_inputst.sidebar.text_inputst.sidebar.button 。这些方法中的每一个对于构建简单的用户控制流都非常有用。

数据帧

Spotify 用户对我们所熟知和喜爱的播放列表、曲目和艺术家的数据类型几乎一无所知。因此,我知道必须以原始的表格格式显示数据,让用户自己探索。幸运的是,Streamlist 有一个 dataframe 方法,它输出一个交互式小部件,在顶部列出列名,在左侧显示索引。

数据框架探索小部件

上面的 GIF 还显示了一个很酷的特性,它使用户能够按照特定的列对所有数据进行排序,可以是升序,也可以是降序。在这种情况下,数据首先按照最高的“语音”值排序,说唱歌曲出现在表格的顶部,器乐歌曲出现在底部。然后数据帧按艺术家姓名的字母顺序排序。

Matplotlib 图表

在使用 PCA 的 k-means 聚类的实现中,有两个基本的小型实验必须被执行。其中一个决定了在特征矩阵中使用的组件的数量,另一个识别了最佳分离数据的聚类的数量。

从 web 应用程序中排除的静态 Matplotlib 折线图

虽然上面的图表对于具有数据科学和机器学习背景的读者来说信息丰富且有趣,但出于两个原因,它们应该从 web 应用程序中排除。首先,它们不是交互式的,因此,如果它们能在大约 10 秒或更短的时间内将相关信息传达给用户,它们才值得在页面上占有一席之地。第二,也是最重要的一点,它们太专业了,对于用户获得洞察力来说不是必要的。

“卓越的图形能够在最短的时间内,用最少的笔墨,在最小的空间里,向观众传达最多的思想。”—爱德华·塔夫特

另外,爱德华·塔夫特是数据可视化领域的知名先驱。他在信息设计和定量数据的可视化显示方面的著作对许多不太相关的领域产生了相当大的影响。在上面的引用中,Tufte 提到了他的一个关键原则,即“数据-墨水比率”。数据科学家被训练成相信越多越好——也就是说,更多的见解比更少的更强大、更有说服力。然而,当涉及到数据可视化时,这种直觉应该是相反的。Tufte 的许多原则植根于简单性,在为客户构建工具时,我们应该始终将这些原则放在首位。

Plotly 雷达图

在接下来的两个部分中,我将展示一个案例研究,其中包含两个从 Spotify 浏览页面中获取的预填充播放列表:“Sunday Scaries”和“park hangs”。每个播放列表有 50 首歌曲,正如你可能想象的那样,Sunday Scaries 由低能量的歌曲组成,而 park hangs 由更乐观的歌曲组成。

Plotly 是一个交互式图形库,通常集成到以数据为中心的应用程序中。在这个项目中,在对用户完全隐藏的情况下实现 k-means 聚类之后,我们希望将注意力吸引到每个结果聚类的关键特征上。

交互式绘图雷达图

从上面演示的与雷达图的交互中,用户可以了解到群集 1 的特征是声学音乐的显著流行。第二组以高能量和高舞蹈性而闻名。有趣的是,除了高速率之外,簇 0 在形状上几乎与簇 2 相同。因此,可以假设群集 0 可能比群集 2 包含更多的说唱音乐、嘻哈音乐和/或 R&B 音乐。最后,集群 3 的特点是其工具性和低能量。

包提供了一种叫做散点图的图形。在不深入细节的情况下,这样一个图的实现需要一个数据列表和一个代表相应变量的角度或辐条列表。在这种情况下,每个聚类由未填充的雷达轨迹表示,平均音频特征作为数据,音频特征的名称作为角度。强烈建议将数据标准化,使所有变量都处于相同的范围内。

牛郎星图表

Altair 是一个用于 Python 的声明式统计可视化库,基于 Vega 和 Vega-lite。它提供了一个强大而简洁的可视化语法,非常值得学习。关键思想是,作为程序员,您必须声明数据列和可视编码通道之间的链接。换句话说,您必须对您想要绘制的变量、它们的数据类型以及您想要如何对数据进行可视化编码有很强的理解。

对于那些从未通过精确数据类型引用数据的人,这里有一个简单的介绍:

  • quantitative (Q) :连续的实数值(如天气、加速度、人口)
  • 序数(O) :离散订购数量(例如,1-5 星用户评级,年份)
  • nominal (N) :离散无序类别(如品牌、颜色)
  • temporal (T) :时间或数据值
  • geojson (G) :地理形状

交互式牛郎星散点图

考虑到我们之前从 Plotly 雷达图中观察到的情况,有趣的是看到以高度器乐化歌曲而闻名的群集 3(粉红色)主要由“Sunday Scaries”(圆形标记)的歌曲组成,而具有高能量、高跳舞性和高语音的群集 0(蓝色)几乎完全由“park hangs”(菱形标记)的歌曲组成。集群 1 和集群 2 处于中间位置,因为它们在数据空间中无法清晰地分开。

由于上面的散点图实际上是在使用 PCA 执行 k-means 聚类之后分量 1 和分量 2 的表示,因此很难从变换后的数据值中推断出含义。我们可以求助于我们的朋友牛郎星来帮助我们进一步探索每个星团内的轨迹。

带有可选 y 轴的 Altair 条形图

就这样结束了!在未来,我希望有一个“导出到播放列表”按钮,这样人们就可以使用我的应用程序从朋友的播放列表中发现新的音乐,甚至只是更好地组织自己的音乐!

链接

下面提供了 web 应用程序和 GitHub 存储库的链接。请注意,所有 Streamlit 代码都位于一个文件中:app.py。要使用 Heroku 部署 Streamlit 应用程序,请查看“如何在 Heroku 上部署 Streamlit”

[## 播放列表混合

这个网络应用程序使用机器学习技术来根据相似的音频特征对音乐进行聚类,以便您可以培养一种有凝聚力的氛围来满足您的聆听需求!](https://playlist-blendr.herokuapp.com) https://github.com/sejaldua/music-clustering

要了解更多关于我的信息,请随时查看下面我的作品集网站。我正在为 2021 年寻找一些新鲜的灵感和新的项目。很想听听我的读者们在做些什么有趣的事情!

https://sejaldua.com

在 Plotly Express 中使用地理信息的交互式地图

原文:https://towardsdatascience.com/interactive-map-using-geographical-information-in-plotly-express-362081457600?source=collection_archive---------22-----------------------

可视化对于任何数据科学项目来说都是非常强大的工具。它有助于读者理解正在发生的事情。对于某些数据集来说,能够在地图上查看数据非常有助于在进行分析时展示见解。

有很多软件包可以实现这个目标,它们都有各自的优点和缺点。即叶子剧情地图框散景等等。

在这篇文章中,我将展示在使用 Plotly 分析带有地理信息的数据时,如何在地图上绘制数据。

在这个演示中,我使用加利福尼亚州旧金山的房屋租赁价格数据集。该数据集首先包含以下特征。

数据集中的要素。图片作者。

经过初步清理后,我想获得各个房屋的邮政编码信息。我用uszipcode包从经纬度数据中获取那些信息。此外,还使用了 pandas 和 Plotly express。这方面的代码如下:

# data manipulation
import pandas as pd# data cleaning
import re
import missingno# data visualization
import plotly.express as px

我用它按邮政编码对数据进行分组,以获得每个邮政编码的平均租赁价格,并在地图上可视化。这是最终的结果。

每个邮编的平均价格。图片作者。

代码:

这种方法利用包含美国邮政编码边界的 geojason 文件。这些都是由 OpenDataDE 提供的,文件可以在这里找到。为了获得那些在 plotly 中有用的信息,使用了下面这一行。

for feature in zipcode_data['features']:        
    feature['id'] = feature['properties']['ZCTA5CE10']

更多来自 plotly 文档的信息可以在这里找到。

为了在交互式地图上获得每所房子的位置,我使用了以下代码:

房子位置。图片作者。

更多来自 plotly 文档的信息可以在这里找到

对于静态输出,用这个代替使用fig.show()显示对象。您也可以通过修改输出类型将它保存为图像。

import plotly.io as plyIo
img_bytes = fig.to_image(format="png", width=1200, height=700, scale=1)
from IPython.display import Image
display(Image(img_bytes))

所有的工作和文件都可以在 GitHub 上的这里找到。可以在 Github 的这里找到使用这些数据的房价预测项目的扩展。

今天到此为止。下次见!

带有散景的交互式质谱

原文:https://towardsdatascience.com/interactive-mass-spectra-with-bokeh-3b9163881b12?source=collection_archive---------21-----------------------

在 Python 中创建动态的信息可视化

非 pythonic 式散景。亚历克斯·伊比在 Unsplash 上的照片

质谱(MS)数据在概念上很简单。简而言之,就是一个有强制质荷值 (m/z) 和对应的非强制信号强度、电荷状态等的表格。但是一名质谱分析人员内心深处渴望真正查看她的数据,在该领域的背景下,这意味着目视检查 m/z 和强度值的分布。质谱传统上被表示为离散光谱的一系列垂直线或未处理数据的平滑连续线,x 轴上的m/z和 y 轴上的强度。两个轴上的值的范围通常非常宽,因此在检查光谱时,缩放功能会很方便。准确的 m/z 值对观察者来说通常很重要,这使得数字标签很方便。

研究人员经常使用专有的供应商软件来查看质谱,但是拥有简单的开源选项不是很好吗?在 Python 发布的内容中, spectrum_utils [1]包提供了基于 Altair 可视化库显示交互式质谱的能力。在这篇文章中,我将分享使用散景绘制交互式 MS 可视化的方法,在我看来,它在创建交互式绘图和仪表板的简单性和灵活性之间提供了惊人的平衡。

散景可视化可以在 HTML 文档中嵌入所有必要的数据和交互功能(独立图),或者它们可以连接到正在运行的 Python 实例,提供对几乎无限的自定义数据处理的访问。独立的散景图可以保存并在网络浏览器中查看,或者嵌入到 Jupyter 笔记本中。如果你有 Bokeh (2.3.1)和 JupyterLab (3.0.14)的新版本(截至 2021 年 5 月),通过 pip 或 conda 安装 jupyter_bokeh 扩展应该足够了。有了扩展,只需调用 output_notebook(),一旦调用 show()命令,绘图就会出现在笔记本中。此外,如果要将绘图保存为 HTML 文件,请添加命令 output_file('file name.html ')。

让我们从加载库开始,打开带有与单个肽谱对应的 m/z 和强度值的表格。代码和数据示例可以在 GitHub repo 中找到。

(477, 2)

既然质谱传统上显示为一束垂直线,为什么我们不使用 vbar 绘图命令创建一个图呢?首先,我们将构造一个 ColumnDataSource,它是 Bokeh 中的一个强大结构,支持可视化之间的交互性和连接性。其次,我们应该指定工具提示,每当光标悬停在信号上时,该工具提示将显示强度和小数点后有 4 位数的 m/z 值。然后,我们使用定制的工具集创建所需尺寸的图形,包括限制在 x 轴上的平移和滚轮缩放,最后添加垂直条。下面我粘贴了动画 GIF 图像,展示了结果图的交互功能:

作者图片

看起来令人鼓舞,但有一些明显的不足之处。条形具有固定的宽度,我们希望用非常细的条形/线条来分隔一些非常接近但可区分的 m/z 值。这导致在现代超高分辨率屏幕上很难看到非常细的线条。我认为,不管缩放比例如何,光谱将受益于具有恒定厚度的更大线条。此外,悬停工具不能正常工作,因为条形非常细,即使我们已经正确指定了工具。

一个线图是另一个选项,但是我们需要稍微修改数据,以便得到垂直的条,而不是实验数据点之间的最短的线。让我们将强度为零的点添加到每个原始信号中,这将使它们看起来像一条垂直线:

我们现在可以把光谱表示成一条连续的线。让我们也介绍一下轴标签,并添加一条特殊的线来显示前体离子的 m/z 和电荷(参见我之前的博客文章关于前体和碎片),这是质谱学家会喜欢的一条附加信息:

作者图片

这样好多了!请注意悬停工具在所有缩放级别的表现,每当我们将光标移过该行时,都会显示注释。

如果信号有标注,用颜色突出标注的类别会很酷。我们可以通过为每个类别创建一个单独的行来实现这一点。此外,可以用 figure.legend.click_policy 属性指定交互行为,这样,当单击相应的图例项时,信号将静音或隐藏。让我们加载带注释的表格,将其转换为“垂直”信号,然后创建复合线图:

array(['Unknown', 'Identified', 'Contaminant'], dtype=object)

作者图片

结论

我们已经使用散景创建了一个交互式注释质谱。可视化可以作为 HTML 文档保存和共享,或者嵌入到 Jupyter 笔记本中。代码和数据示例可在GitHub repo中找到。

参考

[1] Wout Bittremieux。 spectrum_utils:用于质谱数据处理和可视化的 Python 包。分析化学(2020),92(1)659–661。

交互式网络可视化

原文:https://towardsdatascience.com/interactive-network-visualization-757af376621?source=collection_archive---------29-----------------------

使用 Pyviz 创建定制网络

来源:作者

Pyviz 是一个 python 模块,用于创建可以基于每个节点或每个边进行定制的网络。它包含不同的定制,如节点的大小,边缘,用户定义的标签。使用 pyviz 创建的图形是高度交互式的,允许拖动、悬停和选择不同的节点和边。

使用 Pyviz 创建的每个图形都可以有一个定制的布局,可以根据用户定义的需求进行调整。

Pyviz 是围绕令人惊叹的 VisJS 库构建的包装器。在本文中,我们将探索使用 python 创建网络图的 Pyviz。

让我们开始吧…

安装所需的库

像任何其他 python 库一样,我们将使用 pip 安装 Pyviz 库。其命令在下面给出。

pip install pyvis

导入所需的库

为了创建一个图形网络,我们将使用 Pyviz 的网络类实例,它可以使用下面给出的代码导入。

from pyvis.network import Network

向网络添加节点

现在我们已经导入了网络类实例,我们将开始通过添加节点来构建我们的图形网络。我们可以逐个添加节点,也可以创建节点列表。

net = Network()
#Adding node one by one
net.add_node(1, label="Node 1")
net.add_node(2) 
#Adding node as a list
nodes = ["a", "b", "c", "d"]
net.add_nodes(nodes) 
net.add_nodes("hello")

向网络添加边

接下来,我们将创建连接这些节点的边,并为每条边赋予特定的权重。其代码在下面给出。

net.add_edge(0, 1, weight=.87)

形象化

最后一步是将我们创建的图表可视化为一个静态 HTML 文件,因为我们知道这个文件将是高度交互式的。

net.toggle_physics(True)
net.show('mygraph.html')

来源:作者

添加配置用户界面

我们可以使用配置用户界面动态地改变我们网络的设置。它将向用户界面添加按钮。这样我们就可以调整我们的图表,找出最佳的物理参数和布局。

net.show_buttons(filter_=['physics'])

来源:作者

这就是你如何创建自己的图形网络可视化。请继续尝试,如果您在回复部分遇到任何问题,请告诉我。

本文与 皮尤什·英格尔 合作。

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

用于端到端 ML 模型的交互式管道和复合估算器

原文:https://towardsdatascience.com/interactive-pipeline-and-composite-estimators-for-your-ml-tasks-b739854500bf?source=collection_archive---------26-----------------------

训练和显示流水线、列变换器和链式估算器的基本指南

图片由来自 Pixabay埃里克·斯坦拍摄

数据科学模型开发管道涉及各种组件,包括数据注入、数据预处理、特征工程、特征缩放和建模。数据科学家需要为所有组件编写学习和推理代码。对于具有异构数据的机器学习项目,代码结构有时会变得更加混乱,难以为其他团队成员解释。

管道是一个非常方便的功能,它可以顺序地集合所有的模型开发组件。使用流水线,人们可以容易地在相对干净的代码结构中执行学习和推理任务。

在本文中,我们将讨论在开发端到端机器学习模型时,如何使用 scikit-learn 管道通过链接估计器和列转换器来构建您的代码。

什么是管道?

管道可以在干净的代码结构中顺序列出所有的数据处理和特征工程估算器。基本上,它将多个估算器连接成一个。使用管道进行学习和推理任务非常方便,并且可以避免数据泄漏。人们也可以一次对管道中所有估计器的参数执行网格搜索

我将为具有异构特征的二进制样本数据集开发一个端到端的机器学习模型。二进制样本数据集具有文本、数字和分类数据类型的 8 个独立特征。

(图片由作者提供),样本数据集快照

用法:

样本数据集包括文本特征(姓名)、分类特征(性别、已登机)和数字特征(PClass、年龄、SibSp、Parch、Fare)。

原始真实数据集可能包含大量缺失的数据值。我们可以使用 scikit-learn 包中的simple imputr函数来估算缺失值。对于分类特征,我们可以将一个独热编码器和一个 SVD 估计器连接起来进行特征分解。

对于文本特征,我们可以使用计数矢量器或 Tf-Idf 矢量器对文本进行矢量化,将文本数据转换为数字嵌入,然后使用降维估计器。

Pipeline 1 (For categoircal features):
1) Most Frequent value Imputer
2) One Hot Encoder
3) Truncated SVD decompositionPipeline 2 (For Text based features):
1) Tf-Idf Vectorizer
2) Truncated SVD decomposition

(作者代码)

异构数据的列转换器:

样本数据集包含从文本数据类型到浮点和对象数据类型的各种要素数据类型。因此,每种类型的特性都需要单独的特性工程策略。

Column Transformer 是一个 scikit-learn 功能,使开发人员能够针对不同的功能集执行不同的功能工程和数据转换步骤。列转换器的优点是可以在管道内执行数据转换,不会出现数据泄漏问题。

用法:

我对不同的特性集执行了不同的特性转换策略。

  • 管道 1 用于分类特征,如“性”和“已上船”
  • 管道 2 用于基于文本的功能,如“名称”
  • 数字特征“年龄”的平均估算值,因为它有许多缺失值。
  • 其余的数字特性不需要任何特性转换,因此可以使用“passthrough”关键字传递它

(作者代码)

建模管道:

在执行数据转换步骤之后,我们可以移动到模型组件。我将使用逻辑回归估计器来训练转换后的数据集。但是,在进入建模阶段之前,我们还可以包括一个 StandardScaler 估计器来标准化转换后的数据集。

(作者代码)

可视化管道:

整个管道的可视化表示很容易解释案例研究的端到端流程。Scikit-learn 提供了一个**set_config** 函数,使开发人员能够显示整个端到端管道的图形表示。

默认情况下,set_config显示参数为“文本”,显示整个管道的文本格式。更改为“图表”关键字将使其工作。

**from sklearn import set_config
set_config(display='diagram')**

(图片由作者提供),整个管道的图解说明

学习和推理:

可以使用**.fit()**函数训练模型管道,并使用**.predict()**函数进行推理。

(作者代码),整个实现

结论:

管道是一个非常方便的功能,它可以顺序地将所有的估算器组合成一个,并准备一个干净的、结构良好的代码。使用管道,学习和推理任务变得非常容易运行。您可以在可解释的表示中显示整个端到端管道。

参考资料:

[1] Scikit-learn 文档:https://scikit-learn.org/stable/modules/compose.html

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一小部分会员费,不需要你额外付费。

https://satyam-kumar.medium.com/membership

感谢您的阅读

在 Jupyter 中交互绘制著名的 RC 电路

原文:https://towardsdatascience.com/interactive-plotting-the-well-know-rc-circuit-in-jupyter-d153c0e9d3a?source=collection_archive---------22-----------------------

ipywidgets 和 matplotlib 的又一步

作者图片

记得使用右边的“关注”按钮来关注我→:你会收到新文章的通知,并帮助我达到 100 个关注者的目标:)

一阶微分方程最广为人知的例子之一是 RC 电路的例子。虽然这可能会让我们想起高中时的糟糕回忆,但这个微分方程有一个并不复杂的解析解,我们可以通过使用交互式小部件和 matplotlib 轻松探索它。

自本月(4 月 22 日)起,Medium 决定你的作品必须拥有至少 100 名追随者才能获得奖励。 如果你喜欢这篇文章,只要你按下那个“关注”按钮就对我意义重大 :)非常感谢,希望你喜欢这篇文章!

照片由哈里森·布罗德本特Unsplash 上拍摄

是的,即使是不太复杂的数学表达式也常常难以理解:如果我增加它,会发生什么?如果我降低这个值会怎么样?这篇文章是关于帮助我们的大脑理解解析方程和数值应用的。

Ipywidgets 允许您通过像滑块和按钮这样的小部件来交互式地控制值,这使得理解您的分析模型相对于其参数的行为变得非常容易。

我们将看到如何为一个InteractiveRC写一个类,它公开了一个漂亮的交互界面,有一个图和它的滑块。

如果你对方程及其解的物理发展不感兴趣,你可以跳过下一部分。

此外,这篇文章是在 ipywidgets 上的一篇文章之后发表的,在这篇文章中,我展示了如何使用 3D 矢量来可视化噪声分解, 检查嵌入的 gif 以获得剧透 :

RC 电路:建立方程及其解

用维基百科的话说:“RC 电路就是由电阻电容组成的电路。它可以由一个电压电流源 […]”驱动。在我们的例子中,我们将考虑一个理想电压源 e。

电路看起来像这样:

作者图片

我们现在回忆一下基本的电子方程,它让我们建立起 RC 微分方程。假设流过电容器的电流为

作者图片

其中 q 是电容器中的电荷。
另一方面,电容器边界内的电荷由下式给出:

作者图片

应用基尔霍夫电压定律,我们得到:

作者图片

假设电阻器的张力为

作者图片

我们可以替换基尔霍夫定律中的这个表达式:

作者图片

设时间常数τ= RC,我们得到微分方程的标准形式:

作者图片

现在这是我们的一阶线性非齐次常数第二成员方程。解决方案的形式如下:

作者图片

其中 A 和 B 是常数。当初始张力为 u_0 时,通过评估时间为 0 时的解方程,我们得到:

作者图片

并且在时间“无穷大”评估,电容器的张力趋向于源张力 E,所以:

作者图片

最后,我们将绘制的解决方案是:

作者图片

关于这个等式只有几句话:

  • 在 t=0 时,张力等于 u0
  • 在 t=oo 时,张力趋向于 E
  • t=0 时,斜率等于-(u0-E)/τ,斜率在τ时刻与 E 相交(取导数,在 t=0 时求值,说服自己)。

这些是关于解决方案的重要事实,我们将在我们的情节中强调,再次帮助我们的大脑确信那些有用的事实。

解决方案的互动探索

现在有趣的部分来了,“感觉”溶液如何基于 3 个参数表现:源张力 E,初始张力 u0,和时间常数τ。

我们将使用 ipywidgets 滑块来控制每个参数的值,并使用 matplotlib 行来相应地更新绘图。我们将使用一个类结构来很好地组织我们的代码。

我们首先创建一个“输出”小部件,它包含数字和轴,以及 3 个滑块来控制我们的参数值。我们还添加了一个滑块来控制我们想要绘制解决方案的“时间跨度”,以时间常数的数量来表示。然后,我们用“init_plot”设置绘图,并设置限制和轴标签。

然后,我们将编写一个 _update '回调函数,该函数将在每次滑块改变时被调用,以更新绘图。我们一会儿将回到这个函数。然后我们把所有东西都放在一个 ipyw.Hbox 中:滑块和情节。我们还定义了一个 repr `辅助函数来轻松显示我们的绘图和小部件。

我们在类中添加了一些属性,用一种很好的语法直接访问 sliders 值: self.u0 '将返回 u0 _ w slider 值——对于 e tau '和` n_tau '也是如此。我们还添加了一个“t_sample”属性,它依赖于“n_tau”滑块值来创建绘制解函数所需的时间样本。

现在我们要绘制 4 样东西:

  • 解函数张力,u(t)=(u0-E)e^(-t/tau)+E
  • 界定初始张力 u0 的水平线
  • 限定会聚张力 E 的水平线
  • 强调原点斜率和相应τ值(秒)的分段线

因此,我们添加了 4 种方法来生成绘制这些线所需的数据。

是时候填充我们之前使用的“init_plot”函数了。我们将做三件事:

  • 绘制直线:u、u0、E 和原点处的斜率
  • 添加一些文本对象,使我们的情节更加明确
  • 向轴添加网格和紧凑布局

注意,在绘图时,我们使用刚刚创建的数据方法将 x 和 y 发送给绘图函数。存储返回的“Line”对象引用,以便我们可以在以后更新它们的数据。“文本”对象也是如此。

最后,我们必须回到构造函数方法中定义的回调函数 _update。记住,这个函数将在每次滑块改变它的值时被调用,所以我们必须相应地更新绘图。

对于每一行,我们需要更新行数据、文本位置和文本的文本。同样,我们很好地利用了数据助手和滑块包装属性。

秀场

现在我们创建一个实例,让魔法休息一下:

你应该得到一个这样的界面

作者图片

玩滑块会更新情节:

作者图片

我们现在可以玩我们的模型,更好地“感受”每个参数在每个时间如何影响张力。

我们可以形象化地描述一些事情:

  • 增加初始张力 u0 会使曲线垂直“收缩”,使 E 处的收敛张力保持不变。当我们使 u0 更接近 E 时,张力达到 E 的“速度”(由原点处斜率的陡度表示)也会降低。
  • 增加源张力 E 垂直“扩展”曲线。初始张力不变,所以张力从 u0 达到 E 的斜率增大。
  • 增加时间常数τ水平地“扩展”曲线:曲线具有相同的形状,但是在时间上被“拉伸”。初始张力和收敛张力保持不变。
  • 关于时间常数的数量,绘制了张力:我们可以看到,在时间常数的五或六倍之后,张力非常接近于收敛张力 e。例如,这可以通过评估时间 t=5tau 时的解方程来分析证明。

同样,你将以图形方式看到的一切都是基于解方程,所以它可以通过分析来证明,这是一个很好的练习,可以让你的数学技能保持活力。

但是能够可视化这些变化也是非常有益的,有助于你的大脑直观地把握每个参数的影响。

如果你喜欢这篇文章,记得鼓掌并订阅!更多互动帖子来了。

PS:如果你不想处理 matplotlib 对象,直接进入交互式绘图,请查看 mpl_interactions

完整代码

使用 Tableau 和 Jupytab 进行交互式模拟

原文:https://towardsdatascience.com/interactive-simulation-with-tableau-and-jupytab-c26adb1be564?source=collection_archive---------3-----------------------

通过将 Tableau 直接连接到您的 Python Jupyter 笔记本,快速创建和部署模拟工具和仪表盘,并将您的时间花在数据上,而不是构建可视化

虹膜数据集的多维概述

概观

本文展示了如何让领先的交互式数据可视化工具 Tableau 访问动态数据,而不是静态数据。这开启了新的应用,例如可以显示实时数据的仪表板,或者用户显示由机器学习模型获得的动态预测的能力。

我们从通过 Tableau 的本地语言和 Python(通过分析扩展)对 Tableau 中的动态数据访问的简单介绍开始。由于这是一篇实践文章,我们描述如何安装必要的组件(Tableau,和 Jupyter 笔记本),然后说明如何配置它们,并快速获得一个 Tableau 仪表板,显示基于机器学习的动态数据。

(舞台上由人扮的)静态画面

Tableau 是一个被业界广泛使用的商业智能工具(与 PowerBI 和 QlikView 一起使用)。它允许非技术人员通过拖放界面来创建和部署 web 应用程序。

唯一的缺点是,默认情况下,数据需要在受支持的数据库中随时可用,而数据库本身不能通过界面更新。但是,您可以创建速度惊人的交互式仪表盘,连接到众多数据源,并快速获得大规模数据的概览。

Tableau 中的动态数据

Tableau 的脚本语言

Tableau 提供了一种类似 Excel 的语言,允许用户创建自定义计算并操作不同类型的数据(数字、字符串、布尔)。然而,这种脚本语言的局限性非常令人沮丧,因为没有像数据透视表那样的数据操作,甚至一些简单的转换(如将一个字段拆分成多列)也经常需要许多步骤。

Tableau 的脚本语言主要用于在单元级别转换值,或者对整个数据集进行操作,以进行过滤或计算聚合。也就是说,您的选择相当有限,您将不得不主要在 Tableau 之外准备您的数据,并创建一个预先计算的数据集来包含您想要显示的所有数据。

但是,如果您想要创建一个模拟或应用一些机器学习技术,并在更新一些参数后可视化产生的变化,该怎么办呢?Tableau 处理数据源的方式不允许这种操作,否则将迫使您在没有任何库的情况下编写算法,这是完全不切实际的。

分析扩展到救援

为了实现 Tableau 的实时分析,或者至少是使用自定义算法的即时计算,Tableau 的一个非常有趣的功能隐藏在帮助设置和性能管理分析扩展连接……。它允许你实现我们对 web 应用程序的期望。

分析扩展-按作者分类的图像

以下是分析扩展连接在 Tableau 数据生态系统中的位置:

Tableau 中的数据源-按作者分类的图像

Tableau 生态系统中的 Python

在 Tableau 中,我们可以期待 Python 代码的两个地方是数据源创建实时计算(基于显示的数据)。

数据源创建

数据源通常是现有的数据库。可以编写一个自定义的数据注入器来写入这个数据库。这种方法应该很快,但是它显然需要一个成熟的数据库,还需要一个定期调用数据注入程序的调度程序。

另一种方法是直接连接到自定义数据源。因此,Tableau 允许我们创建自定义 Web 数据连接器(WDC)并使用 WDC API。有相当数量的连接器可用,其中一些可能符合您的需求。如果不是这种情况,您将不得不创建一个自定义连接器,但是要注意:学习曲线很陡。

另一个选择是本文中所展示的:通过使用 Jupytab,你可以直接从 Jupyter 笔记本中导出你的熊猫数据帧到 Tableau。(这种方法使用了 WDC API,因此您不必与之争论。)通过使用 Jupytab,您还可以免费获得预定的数据刷新,因为您可以使用 Tableau 内部调度程序按需轮询数据。这种方法的一个小限制是数据源的最大大小:具有 10 亿行的数据集通常不容易放入 Pandas 数据框架中!

实时计算

除了 Jupytab,没有多少其他 Tableau 工具执行动态数据源创建和计算。然而,我们必须提到 TabPy ,这是 Tableau 自己的 Python 交互式分析工具。它创建了一个服务器,通过按需执行代码,允许您在 Tableau 中使用 Python 代码。

Jupytab 服务于完全相同的目的,但是有一些关键的区别:

  • 你所有的 Python 代码都来自一个笔记本:你创建数据源并且在那里为 Tableau 公开它。
  • 你不用 Tableau 写 Python 代码,你总是从你的笔记本里调用一个 Python 函数。
  • 可用库的集合被链接到笔记本。这意味着您可以使用不同的库集创建多个执行环境,并在 Tableau 中使用它们,可能是从多个笔记本中。

如果您的主要开发工具是带有熊猫和一些数据科学库的 Jupyter 笔记本,并且您希望快速创建用于生产的交互式仪表盘,那么 Jupytab 是一个值得一试的工具。

Jupytab 安装

我们假设你熟悉 Python、 Conda (或virtualenv)、Jupyter 并使用 Linux/macOS 进行开发。Jupytab 可以在 Windows 上运行,但是没有经过很好的测试——不过,使用 WSL(Linux 的 Windows 子系统)可以在本文中运行。我们将使用conda进行安装,但它也应该与pip一起工作。

Jupytab 有两个组件,jupytabjupytab-server,需要安装在它们自己的环境中:

  • jupytab :一个非常简单的 API,从一个笔记本中公开数据帧和自定义函数。它需要安装在笔记本环境中,并且只需要熊猫作为依赖。
  • jupytab-server :提供 Web 数据连接器,生成内核,管理配置等…不要将此组件安装在与笔记本相同的环境中,以免冲突。

在笔记本电脑方面

我们首先使用 Python 3.7 创建一个虚拟环境,以保持一切的整洁和可再现性(如果您准备在已经拥有的 Conda 环境中继续学习,也可以跳过这一部分):

(base) % conda create -n jupytab-notebook-env python=3.7
(base) % conda activate jupytab-notebook-env

然后我们安装最新的jupytab版本和ipykernel库,这样我们的 Jupyter 内核就可以在笔记本上使用了:

(jupytab-notebook-env) % conda install jupytab=0.9.11

然后我们在 Jupyter 中安装内核:

(jupytab-notebook-env) % conda install ipykernel
(jupytab-notebook-env) % python -m ipykernel install --user --name jupytab-simulation-demo

您现在可以在 Jupyter 中创建一个笔记本,它将使用新安装的内核。

Jupytab 模拟内核—图片由作者提供

最好通过检查其版本来检查 Jupytab 是否已正确安装,例如,通过执行以下操作:

import jupytab
print(jupytab.__version__)

【输出】 : 0.9.11

在服务器端

我们还基于 Python 3.7 创建了一个新的虚拟环境。您可以使用命令conda deactivate打开一个新的终端或者只是停用您以前的环境:

(base) % conda create -n jupytab-server-env python=3.7
(base) % conda activate jupytab-server-env

然后我们安装最新的 jupytab-server 版本,就这样!

(jupytab-server-env) % conda install jupytab-server=0.9.11

将 Tableau 连接到笔记本

写笔记本

激发本文灵感的笔记本和仪表盘是免费提供的:不要犹豫,下载它们并使用它们跟随。

对于我们的模拟,我们将只使用熊猫和 scikit-learn,但你当然可以安装自己的库。我们首先在 jupytab-notebook-env 中安装 scikit-learn(从基础环境开始,所以要么在新的终端中,要么在conda deactivate之后):

(base) % conda activate jupytab-notebook-env
# No need to install pandas, it is already installed with jupytab:
(jupytab-notebook-env) % conda install scikit-learn

我们创建一个名为jupytab-simulation-notebook的新笔记本

笔记本创作—作者图片

我们将使用众所周知的 iris 数据集,它包含在 scikit-learn 中,并加载 Pandas 数据帧中的所有内容:

import pandas as pd
import jupytab
from sklearn.datasets import load_irisiris = load_iris()iris_data_df = pd.DataFrame(columns=iris.feature_names, data=iris.data)
iris_target_df = pd.DataFrame(columns=['target'], data=iris.target)
iris_target_class_df = pd.DataFrame(columns=['target_name'], data=iris.target_names)iris_data_df.sample(2)

【输出】:

虹膜数据集中的萼片样本—图片由作者提供

然后,我们将 dataframe 加载到 Jupytab Tables字典中,以表明我们希望将这些数据公开给 Tableau:

tables = jupytab.Tables()tables['iris'] = jupytab.DataFrameTable("Iris DataSet", iris_data_df, include_index=True)
tables['iris_target'] = jupytab.DataFrameTable("Iris Classification Target", iris_target_df, include_index=True)
tables['iris_target_class'] = jupytab.DataFrameTable("Iris Classes", iris_target_class_df, include_index=True)

一个DataFrameTable定义了如何将数据暴露给 Tableau:

Jupytab 数据框架文档—作者图片

这里,我们简单地公开了静态数据帧及其索引。

为了允许jupytab-server检索数据,我们需要添加两个单元格。

第一个单元生成一个模式,声明我们所有的数据帧。它需要与下面的单元格完全一样(您可以直接在笔记本中复制并粘贴):

# GET /schema
tables.render_schema()

执行此单元格将打印导出到 Tableau 的模式。

【输出】 : [{"id": "iris "," alias": "Iris DataSet "," columns": [{"id": "index "," dataType": "int"},{"id": "sepal_length_cm_," dataType": "float"},{"id": "sepal_width_cm_," dataType": "float"},{"id": "petal_length_cm_," dataType": "float"},{"id " "

第二个单元格是数据导出的位置:

# GET /data
tables.render_data(REQUEST)

执行这个单元格会在笔记本中产生一个无害的错误:REQUEST变量只有在笔记本由 Jupytab 服务器执行时才可用;

【输出】:
name error trace back(最近一次调用 last)
<ipython-input-1-C5 E1 a 6 B1 cfcd>in<模块>
1 # GET/data
—→2 tables . render _ data(REQUEST)

如果不想在执行过程中得到错误,可以用一个简单的try块包装render_data():

# GET /data
try:
    tables.render_data(REQUEST)
except NameError:
    print("Not available outside jupytab context")

就是这样!您还可以在[jupitab-server/samples](https://github.com/CFMTech/Jupytab/tree/master/jupytab-server/samples) 目录下的 Jupytab GitHub 资源库中找到几个 Jupytab 笔记本示例。

配置并启动 Jupytab 服务器

在 Jupytab 服务器环境中,我们需要创建一个配置文件,允许我们配置一些参数,如服务器端口、秘密令牌,当然还有服务器必须公开的笔记本列表。

可以使用简单的cat命令(在 Unix 下)创建配置文件,或者使用任何文本编辑器编写一个config.ini文件:

(base) % conda activate jupytab-server-env
(jupytab-server-env) % cat << EOF > config.ini
[main]
listen_port = 8123
notebooks = JupytabSimulator

[JupytabSimulator]
path = /path/to/your/notebook/jupytab-simulation-notebook.ipynb
EOF

还提供更多配置选项

完成后,您只需要启动 Jupytab 服务器:

(jupytab-server-env) % jupytab --config=/path/to/your/config.ini
Starting Jupytab-Server 0.9.11
SSL not enabled
Start notebook /path/to/your/notebook/jupytab-simulation-notebook.ipynb on 127.0.0.1:35453
You have no defined token. Please note your process is not secured !
        Please open : [http://computer_name:8123](http://computer_name:8123)
INFO:[KernelGatewayApp] Kernel started: a6abe896-2cb8-403a-8661-3236e16d8def
INFO:[KernelGatewayApp] Registering resource: /schema, methods: (['GET'])
INFO:[KernelGatewayApp] Registering resource: /data, methods: (['GET'])
INFO:[KernelGatewayApp] Registering resource: /_api/spec/swagger.json, methods: (GET)
INFO:[KernelGatewayApp] Jupyter Kernel Gateway at [http://127.0.0.1:35453](http://127.0.0.1:35453)

这将运行笔记本并创建一个允许您访问它的服务器。

请注意,您需要等待您的笔记本资源的注册出现在日志中,否则您将无法从 Tableau 访问它。这是下面的部分:

INFO:[KernelGatewayApp] Registering resource: /schema, methods: (['GET'])
INFO:[KernelGatewayApp] Registering resource: /data, methods: (['GET'])

如果您的笔记本需要时间进行计算,这可能需要几分钟才能显示出来。

导入 Tableau 中的数据

如果你还没有安装 Tableau,你可以下载并免费试用。本文是用 Tableau 2020.2 测试的,所以您可能需要根据需要稍微修改一下说明。

从开始屏幕中选择 Web 数据连接器:

Tableau 连接器—作者图片

然后,您可以输入在终端中打印的 web 数据连接器 URL:

Web 数据连接器浏览器-作者图片

Start notebook /path/to/your/notebook/jupytab-simulation-notebook.ipynb on 127.0.0.1:35453
You have no defined token. Please note your process is not secured !
        Please open : http://computer_name:8123

您应该能够选择您的第一个笔记本并查看所有可用的操作:

Jupytab UI 的欢迎屏幕—作者图片

继续在 Tableau 中探索,并使用提供的表格创建您的数据集。注意表之间的顺序和连接:

Tableau 中的数据源关系—按作者分类的图像

我们现在有了一个数据集,它是从 Jupyter 笔记本中导入的。

创建虹膜模拟器

我们将创建一个基于虹膜数据集的 Tableau 模拟器。它经常被用作常见的机器学习示例。手头的任务包括仅根据四个维度(萼片和花瓣长度/宽度)对 3 种类型的鸢尾进行分类。

这个模拟器的目标仅仅是对使用 Tableau 创建仪表板有一个大概的了解。它们无需编写任何代码就可以创建,更重要的是,只需几分钟。

更新笔记本以添加预测功能

我们将使用一个多层感知器(MLP)分类器,并用数据集的全部内容训练它。我们的目标不是实现任何类型的高精度预测,而是展示如何通过 Jupytab 在 Tableau 中动态地进行预测。

正如我们对jupytab.Tables所做的那样,我们需要添加一个jupytab.Functions字典来注册我们的预测器方法:

from sklearn.neural_network import MLPClassifierclf = MLPClassifier(max_iter=600).fit(iris.data, iris.target)def predictor(sepal_length_cm, sepal_width_cm, petal_length_cm, petal_width_cm):
    class_predict = clf.predict([[sepal_length_cm, sepal_width_cm, petal_length_cm, petal_width_cm]])
    return iris.target_names[class_predict][0]  # We return the only predictionfunctions = jupytab.Functions()
functions['predict'] = jupytab.Function('A predictor for the Iris DataSet', predictor)predictor(0.5, 5, 4, 2)

【输出】 :《处女座》

我们还需要定义一个将由 Jupytab 服务器使用的新端点:

# POST /evaluate
try:
    functions.render_evaluate(REQUEST)
except NameError:
    print("Not available outside jupytab context")

【输出】 :在 jupytab 上下文之外不可用

然后,我们必须保存笔记本并从 Tableau 重新启动内核,以便 Tableau 能够考虑我们的更改。

笔记本可用的 Jupytab 操作-按作者排序的图片

在 Tableau 中动态预测

通过分析扩展连接到 Jupytab

在 Tableau 中使用 predictor 函数之前,我们需要将我们的 Jupytab 服务器注册为 Tableau 中的分析扩展。

这可以通过 Tableau 桌面菜单中的帮助设置和性能管理分析扩展连接项轻松完成。

分析扩展设置-按作者分类的图像

使用测试连接按钮检查一切正常:

成功连接分析扩展-按作者分类的图像

仪表板创建

为了显示每个样本的数据点,我们需要将 Iris 数据集索引转换为一个维度:

Tableau 桌面中的维度属性-按作者排序的图像

然后将该值作为详细信息删除:

Tableau 桌面中的标记版本—作者图片

我们得到以下结果:

带有索引维度的默认绘图-按作者排序的图像

然后,我们将显示一个网格来可视化所有维度之间的相互关系。从 Iris 数据集中选择所有测量:

度量选择-按作者排序的图像

和下拉列表:

Iris 数据集按列测量-按作者分类的图像

对行执行相同的操作:

Iris 数据集按行测量-按作者分类的图像

你的视觉化差不多准备好了!

Tableau 桌面中的多维情节—图片由作者提供

只需在颜色标记中删除虹膜类的目标名称。

使用彩色聚类的目标名称-按作者分类的图像

输出允许您将结果可视化为比较所有维度的网格图:

作者图片

现在,我们将检查我们的模型是否正确预测虹膜类型。我们希望为每个虹膜样本调用预测器,并在上图中显示错误分类的数据。为此,我们需要创建一个计算字段:

作者图片

以下公式返回预测的虹膜类型:

SCRIPT_STR("JupytabSimulator.predict", AVG([Sepal Length Cm]), AVG([Sepal Width Cm]), AVG([Petal Length Cm]), AVG([Petal Width Cm]))

Tableau 桌面中计算字段的代码编辑器-按作者排序的图像

**JupytabSimulator**是我们在config.ini文件中注册的笔记本的名称,**predict**是我们注册的函数的名称。两个值的结合是目标。这意味着您可以针对不同的笔记本电脑,每台笔记本电脑都使用自己的虚拟环境和一组库。

函数参数是您在预测函数中定义的四个参数,当然它们需要以相同的顺序插入。

我们还需要另一个函数,将实际虹膜类型与预测值进行比较,如果不匹配,则返回False。需要ATTR函数,因为虹膜预测器已经是一个聚集数据:

ATTR([Target Name]) = [Iris Predictor]

有效预测的布尔指示器-按作者排序的图像

然后,我们将使用预测匹配替换当前的聚类颜色,并选择圆形作为表示。

预测匹配用作颜色标记—作者图片

Tableau 将与 Jupytab 通信几分钟,因为它需要预测所有显示标记(即数据点)的虹膜类别:

对 Jupytab 的分析扩展请求—按作者排序的图像

这是 Tableau Analytics 扩展的重要一点:你需要尽量减少显示在仪表盘上的标记数量,以保证快速的结果和更具交互性的体验。

由于上面的预测匹配计算,错误的预测可能会显示出来:

可视化中的预测误差—作者提供的图像

通过将此图与上一个图进行比较,我们可以看到错误预测的虹膜类型是如何出现在虹膜组之间的边界上的。

一个只给我们错配数量的可视化,将极大地增加标记的数量,同时仍然提供一些重要的信息。我们只需要从列和行中删除所有度量,用我们的预测匹配计算来替换它们。这个新的可视化将在几秒钟内加载:

虹膜数据集的“花形图”——作者提供的图片

最后但同样重要的是,我们希望了解 MLP 培训的迭代次数如何影响我们的结果。这就需要我们使用 Tableau 的另一个很酷的特性:参数

我们首先更新笔记本中的预测函数,添加一个新的可选变量来训练(再次)我们的 MLP。我们只需要缓存结果,以避免在每次调用时进行相同次数的迭代训练:

from sklearn.neural_network import MLPClassifierlast_max_iter = 0
clf = Nonedef train(request_max_iter):
    global clf, last_max_iter
    if not clf or last_max_iter != request_max_iter:
        clf = MLPClassifier(max_iter=request_max_iter, random_state=1).fit(iris.data, iris.target)
        last_max_iter = request_max_iter
    return clfdef predictor(sepal_length_cm, sepal_width_cm, petal_length_cm, petal_width_cm, request_max_iter=1000):
    clf = train(request_max_iter)  # We now train as needed

    class_predict = clf.predict([[sepal_length_cm, sepal_width_cm, petal_length_cm, petal_width_cm]])
    return iris.target_names[class_predict][0]functions = jupytab.Functions()
functions['predict'] = jupytab.Function('A predictor for the Iris DataSet', predictor)predictor(0.5, 5, 4, 2)

【输出】:“弗吉尼亚”

不要忘记通过 Jupytab UI 在 Tableau 中重启内核,以便应用更改。

在 Tableau 端,我们将创建一个范围从 10 到 1000 的参数,以直观显示训练迭代次数对我们预测的影响:

Tableau 桌面中的参数创建—由作者创建的图像

参数设置—按作者分类的图像

然后,我们将这个参数添加到视图中:

在 Tableau 仪表板中查看参数—按作者分类的图像

我们现在可以动态地改变 MLP 的最大训练迭代次数:

MLP 最大迭代设置-按作者分类的图像

我们还需要更新虹膜预测值计算,并添加这个新参数:

SCRIPT_STR("JupytabSimulator.predict", AVG([Sepal Length Cm]), AVG([Sepal Width Cm]), AVG([Petal Length Cm]), AVG([Petal Width Cm]), [MLP Max Iteration])

用 MLP 最大迭代更新虹膜预测值计算——图片由作者提供

就在单击 apply 之后,结果会立即更新为默认值 10 次迭代。

MLP 训练 10 次迭代

MLP 训练 10 次迭代—作者图片

MLP 训练 100 次迭代

MLP 训练 100 次迭代—作者图片

结论

Tableau 是一个非常强大的数据可视化工具。使用 Jupyter 笔记本电脑计算数据并获得几乎即时的反馈非常方便。

我们几乎没有触及 Tableau 特性的表面,并且您可以在您的仪表板中创建的可视化和交互的种类几乎没有限制。

Jupytab 项目是开源的,可以在 MIT 许可下在 GitHub 上访问。

你也可以在网上阅读许多用 Tableau 制作的令人印象深刻的仪表盘。

感谢

这是我在 GitHub 上发布的第一个项目,如果没有 CFM 开源项目的大力支持和那里工作人员的帮助,它可能永远不会离开我的电脑。

我要特别感谢Jean-sébastien Dieu、Eric LebigotFlorent Zara 对 Jupytab 各方面的支持,并帮助我发表这篇文章。

使用 Python 和 API 的交互式时间序列:生成新加坡出租车的热图

原文:https://towardsdatascience.com/interactive-time-series-with-python-and-api-generating-heatmap-of-taxis-in-singapore-4d84adbd4c54?source=collection_archive---------12-----------------------

地理空间可视化是讲述故事的一种强大方法,尤其是在热图中。在这个例子中,我使用了一个时间序列热图,通过坐标和时间来表达出租车的移动。通过混合使用热图和来自 API 的实时数据,用户将能够分析实时出租车运动。

新加坡陆路交通管理局(LTA)有一个 API,显示所有出租车的实时坐标。这是一个相当酷的 API,显示实时的出租车运动,每 30 秒刷新一次。然而,在搜索了更多关于这个 API 的信息之后,人们对它做了很少的工作。因此,在本文中,我将介绍如何从这个 API 收集数据的步骤,并在下面的时间序列热图中使用 follow!

新加坡周五晚上的出租车运动

第一步:导入相关包

import folium
import folium.plugins as plugins
import pandas as pd
import json
import requests
import time
from folium.plugins import HeatMapWithTime
import datetime

第二步:从 API 提取数据并将其存储为数据集

我首先创建一个空的数据框,这样我就可以将动态数据追加到其中。

cumulative = pd.DataFrame()

接下来,使用一个简单的输入功能,我能够键入滑行运动的持续时间。这将决定循环运行的次数。

mins = input('How many mins do you want to see? ')
number_of_times = (int(mins)*60)/30

接下来,编写一个 for 循环,不断地从 API 中提取数据。因为 API 每 30 秒刷新一次,所以我使用 Python 时间模块每 30 秒重新运行一次脚本。同时,我只从 Geojson 对象中提取坐标和时间戳,并将其附加到我的 pandas 数据框中。这将允许我将过去的数据编译到一个数据框架中,以便于以后操作。

startTime = time.time()
for i in range(int(number_of_times)):
    url = ("[https://api.data.gov.sg/v1/transport/taxi-availability](https://api.data.gov.sg/v1/transport/taxi-availability)")
    response = requests.get(url)
    data = response.json()
    df = pd.io.json.json_normalize(data['features'])
    coordinateslist = df['geometry.coordinates'].tolist()
    df1 = pd.DataFrame(coordinateslist)
    result = df1.transpose()
    result.columns = ['coordinates']
    result['Timestamp'] = (df['properties.timestamp'][0])
    cumulative = cumulative.append(result) 
    time.sleep(30)
endTime = time.time()
elapsedTime = endTime - startTime
print("Elapsed Time = %s" % elapsedTime,'seconds')

步骤 3:与 for 循环的数据争论

现在是处理数据的时候了,这样我们就可以很容易地利用它。我首先将坐标分成纬度和经度两列。

cumulative['coordinates'] = cumulative['coordinates'].astype(str)
Latitude = []
Longitude = []
coordinates = []
for i in cumulative['coordinates']:
    i = i.split(", ")
    lat = i[1][:-1]
    long = i[0][1:]
    Latitude.append(lat)
    Longitude.append(long)
cumulative['Latitude'] = Latitude
cumulative['Longitude'] = Longitude

在我们将数据框处理成我们想要的格式以便将其绘制到 leav 之前,您的数据框应该类似于下图。

操作后产生的数据框

接下来,我们需要将纬度和经度放入一个嵌套列表中,以便我们使用folium.plugins.**HeatMapWithTime** 来生成时间序列热图。

lat_long_list = []
for i in cumulative['Timestamp'].unique():
    temp=[]
    for index, instance in cumulative[cumulative['Timestamp'] == i].iterrows():
        temp.append([instance['Latitude'],instance['Longitude']])
    lat_long_list.append(temp)

步骤 4:创建时间索引并格式化

接下来,我们必须将时间戳转换成 datetime 格式,这样我们就可以将其转换成更整洁、可读性更好的布局。这也将是播放按钮中用来显示时间和日期的索引。

#converting it to datetime format
cumulative['Timestamp']= pd.to_datetime(cumulative['Timestamp'])#creating a time index
time_index = []
for i in cumulative['Timestamp'].unique():
    time_index.append(i)#formatting the index
date_strings = [d.strftime('%d/%m/%Y, %H:%M:%S') for d in time_index]

第五步:绘制时间序列热图

终于可以生成地图了!我选择了一个深色主题的新加坡地图,这样热图看起来会更有活力。

#Choosing the map type 
m = folium.Map(location=[1.352083,103.819839],zoom_start = 11, tiles="[https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png](https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png)",attr="Stadia.AlidadeSmoothDark")#Plot it on the map
HeatMapWithTime(lat_long_list,radius=5,auto_play=True,position='bottomright',name="cluster",index=date_strings,max_opacity=0.7).add_to(m)# Display the map
m

你的地图完成了!可以放大看新加坡市区的动静。

总结

  • 步骤 1:导入相关的包
  • 步骤 2:从 API 提取数据并将其存储为数据集
  • 步骤 3:用 for 循环处理数据
  • 步骤 4:创建时间索引并格式化它
  • 步骤 5:绘制时间序列热图

请随意将其保存为 html 文件,以便发送给朋友和同事。你可以在我的 Github 上查看完整的代码。

用 BERTopic 进行交互式主题建模

原文:https://towardsdatascience.com/interactive-topic-modeling-with-bertopic-1ea55e7d73d8?source=collection_archive---------2-----------------------

图片由作者提供。

NLP — 入门

使用 BERTopic 进行主题建模的深入指南

每天,企业都要处理大量的非结构化文本。从电子邮件中的客户互动到在线反馈和评论。为了处理如此大量的文本,我们期待主题建模。一种通过识别重复出现的主题从文档中自动提取含义的技术。

几个月前,我写了一篇关于利用 BERT 进行主题建模的文章。它出乎意料地爆发了,我对我得到的积极反馈感到惊讶!

我决定专注于进一步开发本文所基于的主题建模技术,即 BERTopic。

ber topic是一种主题建模技术,它利用 BERT 嵌入和基于类的 TF-IDF 来创建密集的集群,从而允许轻松解释主题,同时保留主题描述中的重要单词。

我现在处在一个点上,BERTopic 已经获得了足够的牵引力和发展,我相信它可以取代或补充其他主题建模技术,如 LDA。

**https://github.com/MaartenGr/BERTopic/

本文的主要目的是向您深入介绍 BERTopic 的特性和教程,以及如何最好地将其应用于您自己的项目。

1.装置

和往常一样,我们从通过 pypi 安装包开始:

pip install bertopic

要使用可视化选项,请按如下方式安装 BERTopic:

pip install bertopic[visualization]

2.基本用法

使用 BERTopic 开箱即用非常简单。您将文档作为字符串列表加载,并简单地将其传递给fit_transform方法。

举个例子,下面我们将使用 20 个新闻组数据集:

生成了两个输出,topicsprobabilities。主题中的值只代表它被分配到的主题。另一方面,概率展示了文档落入任何可能主题的可能性。

接下来,我们可以访问根据其相对频率生成的主题:

在上面的输出中,似乎 Topic -1 最大。-1 表示没有分配主题的所有离群值。在主题中强制文档可能会导致性能下降。因此,我们忽略主题 1。

相反,让我们来看看第二个最频繁生成的主题,即主题 49 :

由于我创建了这个模型,我显然有偏见,但对我来说,这似乎是一个连贯和容易解释的主题!

语言

在幕后,BERTopic 正在使用sentence-transformers为您传递给它的文档创建嵌入。默认情况下,BERTopic 被设置为使用英语模型,但它支持任何存在嵌入模型的语言。

您可以通过简单地设置 BERTopic 中的language参数来选择语言:

当您选择一种语言时,相应的sentence-transformers模型将被加载。这是一个典型的支持多种语言的多语言模型。

话虽如此,如果您的文档中有多种语言,您可以使用BERTopic(language="multilingual")来选择支持 50 多种语言的模型!

嵌入模型

要选择不同的预训练嵌入模型,我们只需通过将变量embedding_model指向相应的句子变形模型来传递它:

点击此处查看支持的句子转换模型列表。

保存/加载 BERTopic 模型

我们可以通过调用save来轻松保存一个经过训练的 BERTopic 模型:

然后,我们可以在一行中加载模型:

3.形象化

现在,我们已经涵盖了基础知识并生成了我们的主题,我们将它们可视化!对主题有一个总体的了解,可以让我们对主题模型的质量产生一个内在的认识。

可视化主题

为了可视化我们的主题,我从 LDAvis 中获得了灵感,LDAvis 是一个可视化 LDA 主题模型的框架。它允许您交互式地探索主题和描述它们的词语。

为了在 BERTopic 中实现类似的效果,我使用 Umap 嵌入了我们在 2D 的主题的基于类的 TF-IDF 表示。然后,使用 Plotly 创建一个交互式视图,这是一个可视化维度的简单问题。

为此,只需调用model.visualize_topics()来可视化我们的主题:

图片由作者提供。

将生成一个交互式绘图图形,可按照上面动画中的指示使用。每个圆圈表示一个主题,其大小是该主题在所有文档中的出现频率。

要自己尝试一下,看一下文档这里你可以找到一个交互式版本!

想象概率

对于每个文档,我们还可以可视化该文档属于每个可能主题的概率。为此,我们在运行 BERTopic 后使用变量probabilities来了解该模型对于该实例的可信度。

由于要可视化的主题太多,我们可视化最可能的主题的概率分布:

对于这个文档,模型在选择正确的主题时似乎有一些困难,因为它们是多个彼此非常相似的主题。

4.话题缩减

正如我们之前看到的,可能会产生数百个主题。有时,这可能对您来说太难了,或者是一个太细粒度的解决方案。

幸运的是,我们可以通过合并彼此最相似的主题对来减少主题的数量,如 c-TF-IDF 向量之间的余弦相似性所示。

下面,我将介绍三种减少来自 BERTopic 的主题数量的方法。

手动主题缩减

在启动 BERTopic 模型时,您可能已经对文档中可能包含的主题数量有所了解。

通过设置nr_topics变量,BERTopic 将找到最相似的主题对,并将它们合并,从最不频繁的主题开始,直到我们达到nr_topics的值:

但是,建议保持一个合适的高值,比如 50,以防止不应该合并的主题被合并。

自动主题缩减

如上所述,如果您将主题合并到一个较低的nr_topics中,那么主题将被强制合并,即使它们实际上可能并不相似。

相反,只要找到一对超过最小相似度 0.9 的主题,我们就可以迭代地减少主题的数量。

要使用此选项,我们只需在训练模型之前将nr_topics设置为"auto":

训练后话题减少

如果在花了很多时间的培训后,你留下了太多的话题,该怎么办?如果只是为了试验主题的数量而不得不重新训练你的模型,那就太可惜了。

幸运的是,在训练了 BERTopic 模型之后,我们可以减少主题的数量。这样做的另一个好处是,您可以在知道实际创建了多少个主题后决定主题的数量:

使用上面的代码,在训练完模型后,我们将主题的数量减少到 30 个。这允许您根据您的用例来选择合适的主题数量!

5.主题表征

主题通常由一组单词表示。在 BERTopic 中,这些单词是使用基于类的 TF-IDF 从文档中提取的。

有时,您可能对创建的主题的表示不满意。当您选择仅使用 1-gram 单词作为表示时,这是可能的。也许您想尝试不同的 n-gram 范围,或者您有一个想要使用的自定义矢量器。

为了在训练后更新主题表示,我们可以使用函数update_topics用 c-TF-IDF 的新参数来更新主题表示:

我们也可以使用自定义的计数矢量器来代替:

6.自定义嵌入

为什么要将自己局限于公开可用的预训练嵌入?您可能有非常具体的数据,您已经为这些数据创建了一个嵌入模型,但是您无法找到可用的预训练模型。

变压器型号

要使用您自己训练的任何嵌入模型,您只需用该模型嵌入您的文档。然后,您可以传入嵌入,BERTopic 将完成剩下的工作:

正如您在上面看到的,我们使用了一个 SentenceTransformer 模型来创建嵌入。您也可以使用🤗 transformersDoc2Vec或任何其他嵌入方法。

TF-IDF

既然如此,为什么要局限于变形金刚模型呢?TF-IDF 等统计模型仍然存在是有原因的。它们开箱即用,无需太多调整!

正如您可能已经猜到的,也可以在文档上使用 TF-IDF,并将它们用作 BERTopic 的输入。我们简单地创建一个 TF-IDF 矩阵,并将其传递给fit_transform:

在这里,你可能会注意到创建嵌入非常快,而fit_transform非常慢。这是意料之中的,因为降低大型稀疏矩阵的维数需要一些时间。使用 transformer 嵌入的反过来也是正确的:创建嵌入很慢,而fit_transform非常快。

感谢您的阅读!

如果你和我一样,对人工智能、数据科学或心理学充满热情,请随时在 LinkedIn 上添加我,或者在 Twitter 上关注我。

您可以在下面找到 BERTopic 及其文档:

https://github.com/MaartenGr/BERTopic **

Plotly 和 Datapane 的交互式可视化

原文:https://towardsdatascience.com/interactive-visualization-with-plotly-and-datapane-97472017cb54?source=collection_archive---------15-----------------------

使用 Plotly 和 Datapane 从您的可视化中获得更多

Plotly 中的交互式烛台图(图片由作者提供)

可视化是任何分析的一个重要方面。但是静态图限制了我们理解数据的能力。Plotly 和 Datapane 解决了这个问题。

本文将展示如何创建交互式烛台时序图来可视化比特币的价格。但是,所提供的代码很容易修改以支持其他时间序列数据。

这篇文章分成几个部分:

  1. 用 Alpha Vantage 提取数据
  2. Matplotlib 中静态图的比较
  3. 用 Plotly 和 Datapane 嵌入图
  4. 具有高级功能的 Plotly 中的交互式绘图

阿尔法优势

Alpha vantage 是一个金融服务 API,支持多种编程语言,包括 Python、NodeJS、PDP、C#/。Net 和许多其他语言。一个强大的开源社区已经为 Alpha Vantage 开发了超过 600 个跨越这些编程语言的库。

Alpha Vantage 使程序员能够提取各种股票和加密货币的当天定价。该 API 易于使用,并允许很大的灵活性。因此,对于那些想要对大量数据进行回溯测试机器学习算法、创建可视化和执行财务分析的人来说,它是理想的选择。

如果你对在金融领域使用数据科学感兴趣,Alpha Vantage 是一个完美的工具。

要求

该工具需要一个个性化的 API 密钥来提取数据。注册一个免费帐户后就可以使用这个密钥,但是由于明显的原因,免费层中的呼叫次数是有限的。

您收到的 API 密匙允许每分钟最多 5 个请求,每天最多 500 个请求 —对于大量金融数据的实验来说绰绰有余。

但是,如果您确实需要更多财务数据,请考虑高级选项。该选项还允许附加历史数据。对于希望用更多数据对模型进行回溯测试的用户来说,这个选项可能更好。

提取数据

对于本文,我将使用 Python 中的 API。您将使用的主要功能可能是股票或加密的当天功能。

接下来,您可以使用相关的货币代码指定您选择的货币的价格。然后,使用 interval 命令设置数据间隔,其中选项为每分钟、5 分钟、15 分钟、30 分钟或 60 分钟。

最后,输出大小决定了您想要接收多少数据。在这里,我使用完整的输出大小来获取尽可能多的信息。

将比特币数据加载到 DataFrame 中(由作者编写代码)

确保用 API 键替换 API_KEY 变量。

API 返回元信息和价格信息。价格信息包括开盘价、收盘价、最高价和最低价。

使用 Matplotlib 的静态图

python 中最常见的绘图库可能是 Matplotlib。它是许多 python 教程的主要内容,并被集成到许多包中。然而,它有一些明显的缺点。首先,您必须指定轴的范围。虽然这最初看起来不像是 Matplotlib 的一个突出的贬损者,但当更多的不稳定数据出现时,它就成了一个问题。

当时间序列发生变化时,您只能选择一个较短的时间段进行详细观察,或者查看一个更重要的时间段并查看整体趋势。

mplfinance

我已经通过使用“mplfinance”包展示了这一点。这个包是建立在 Matplotlib 之上的,可以很容易地创建蜡烛图。虽然易于设置和使用,但轴范围被设置为传递给函数的数据帧的总范围。

Matplotlib 中的蜡烛图(作者代码)

基于 Matplotlib 的静态绘图(图由作者提供)

为了正确地研究不同时期的数据,你必须重建整个图。虽然金融数据的焦点通常是最近的数据,但深入历史数据对于回溯测试算法至关重要。只有通过密切观察数据,你才能看到你的算法崩溃的场景。

用数据面板嵌入图

Plotly 是一个漂亮的库,默认情况下提供交互式绘图。然而,简单地将这些情节插入到文章中并不会自动允许交互性。

相反,可以使用 Datapane 来管理这些图。

Datapane 是一个开源的 Python 库,允许用户快速构建交互式绘图。此外,Datapane 提供 Datapane Studio,这是免费的,将使您能够上传公共和私人报告。

使用 Datapane 的免费层,您可以使用电子邮件共享、无限公共报告托管和社交嵌入 API 创建五个私人报告。

本文使用社交嵌入 API 来展示 Plotly 图表。

注意: Plotly 确实允许写入 html,这样剧情的交互功能就可以持续。当您想保持交互方面的完整性时,将图发送给其他人时,此选项非常有用。

嵌入图

在数据面板上显示图表。首先安装 Datapane。接下来,使用注册时收到的令牌登录 Datapane。大概是这样的:

初始化数据面板(由作者编写代码)

简单地创建一个 Plotly 图表,并用 Datapane 报告功能将报告上传到 Datapane。这里,日期滑块被自动添加到绘图中,因为索引是日期时间类型。如果沿 x 轴看到日期时间值,则类型为字符串,并且无法生成日期滑块。

上传嵌入图表(作者代码)

要确保报告正确集成到介质中,您必须设置一个集成令牌。然后将这个令牌保存到您的 Datapane 帐户。这里有一个简单的演练:

https://docs.datapane.com/reports/publishing-and-sharing/export-to-medium

与 Plotly 的互动情节

默认情况下,Plotly 允许用户动态调整绘图的轴范围。此外,默认图允许缩放、保存图、添加或删除迹线、双击重置图以及尖峰线切换。

基本绘图图(作者代码)

基本 Plotly 时间序列(作者提供的图表)

虽然上面的图表无疑是一个进步,但还是有一些局限性。

首先,虽然您可以放大多个周期,但 y 轴保持不变。不幸的是,默认图表的这个属性使得烛台图表变得毫无意义,因为蜡烛变平了。

经过深入研究,我发现可以在更新时动态更新 y 轴。这次更新需要对以前的情节做一些改动。

首先是将图形对象导入从plotly . graph _ objects改为 plotly_graph_obs 。接下来是将你的人物对象初始化为一个 人物小部件 而不仅仅是一个人物。该导入要求安装 ipywidgets

使用活动 Python 内核动态调整 Y 轴(代码由作者编写)

第二个变化是取消了日期间隔。虽然比特币不需要这样做,但其他金融股票在时间序列上也有缺口。这种模式是由于市场关闭,可以掩盖情节。

为了避免这个问题,不存在值的日期将被删除。首先,为整个范围生成一个日期列表以防止此问题。则不存在值的日期将被删除。然后轴被更新以反映该变化。

删除日期差距代码(作者代码)

我做了最后的修改来改善烛台图:着色(使用 seaborn 主题)、格式改变和日期滑块按钮。这些更多的是生活质量的提高。由于日期滑块可能相当麻烦,日期按钮简化了日期范围的选择。

按钮遵循标准格式。“步骤”被指定为日期时间频率,如分钟、小时、天、月或年。那么“计数”被设置为指示范围的大小。这些按钮可以从日期时间图的起点或终点选择数据,支持自定义标签和自定义日期范围。

注意 Datapane 不支持上传 FigureWidgets,chart-studio(来自 Plotly 的 chart hosting)不提供内核来更新日期选择的 y 轴值。但是,在 Jupyter 笔记本中运行图表时,您可以看到动态的 y 轴变化。

详细 Plotly 时间序列图的代码(作者代码)

改进了 Plotly 中的蜡烛图(图由作者提供)

最后的想法

当利益相关者需要从分析或初始数据调查中获得一些有形的输出时,在整个数据科学项目中使用可视化。

然而,如果可视化工具过于死板,您可能会错过一些对数据的关键见解。交互式图表确保您的数据中令人兴奋的方面易于观察。

在这篇文章中,使用了比特币数据。但应该清楚的是,交互式绘图的好处适用于数据科学的许多不同领域。

这些图有助于传达故事、传递信息,并帮助我们调查数据。

Plotly 提供了一个开箱即用的解决方案来实现绘图交互性。与 Datapane 结合,您可以将完全交互式的图发送给相关的利益相关者,并揭示数据的复杂性。

如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 Medium 上关注我。

如果你对我的写作感兴趣,想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。

https://zjwarnes.medium.com/membership

用 Plotly 实现交互式气象数据可视化

原文:https://towardsdatascience.com/interactive-weather-data-visualizations-with-plotly-d304fe87b57f?source=collection_archive---------6-----------------------

理解大数据

使用 Python 探索 NOAA 全球地表概要

照片由迈克尔 DUnsplash 上拍摄

全球地表日摘要(GSOD)是从 1929 年开始的 9000 多个气象站的天气数据集。它由美国国家海洋和大气管理局(NOAA)创建和维护,生成 18 个气候变量(如平均露点、平均风速和最小/最大温度)的每小时地表测量的每日摘要。

这是一个用于实践可视化空间数据的很好的数据集,因为它在全球范围内有许多站点,具有相对较大的时间序列。它还每天更新,这使它成为使用仪表板练习的一个很好的候选。

虽然 Python 可能不是人们想到的第一种可视化空间数据的语言或工具,但有几个库能够创建奇妙的地理可视化。Plotly 已经成为一个非常全面的 Python 交互式绘图库,它的地理绘图功能在过去几年里已经有了长足的进步。因为它出色的文档和受欢迎的程度,在这篇文章中我将只关注 Plotly,但是请记住,还有其他可用的库。

这个数据集有点大,只有 4.2 GB,所以将它加载到 Python 需要一点努力;无论如何,它都不是一个海量数据集,但它比我们遇到的平均“实践”数据集要大。我们将从如何访问数据开始,然后探索如何使用 Plotly 在交互式地图上可视化处理后的数据。泡一杯咖啡,舒服一下,让我们处理更大的天气数据集,用 Plotly 可视化我们的发现。

文件结构

有多种方法可以获得这个数据集。从 Kaggle 可以获得一个易于下载的版本,但它不像 NOAA 仓库那样每天更新,而且 Kaggle 版本更难以用 Python 格式化。这是 NOAA 知识库的结构:

1929.tar.gz/
1930.tar.gz/
    03005099999.csv
    03026099999.csv
    ...
...

数据存储在每年压缩的 tarballs 中,其中包含。当年每个电台的 csv 文件。每一个。csv 文件根据其站点 ID 命名,站点 ID 由站点的 WMO 和 WBAN 编号组成。

NOAA CSV 文件结构(由作者创建)

Kaggle Gzip 文件结构(由作者创建)

WMO 编号

世界气象组织(WMO)是联合国负责天气、气候和水资源的机构。前两位数字是国家代码,接下来的三位数字由国家气象局(NMS)设定。如果最后一个数字是零,这意味着世界气象组织的数字是官方的,或者过去是官方的。

WBAN 数

WBAN 代表天气-天气-陆军-海军。WBAN 号是数字数据存储的标识符,最初是美国气象局、加拿大交通部和三大军事部门相互共享数据的一种方式。后来它扩展到包括一些德国和韩国的电台。

:需要记住的重要一点是,世界气象组织和 WBAN 的编号创建了一个唯一的气象站 ID,一旦加载到 pandas 中,这就是我们引用每个气象站的主要方式。

下载我们的数据

获取这些数据的最佳方式是直接从 NOAA 下载,你可以下载每年的 tarball,其中包含当年每个站点的 csv 文件。我包含了一个简单的 Python 模块,用于下载和处理所有数据,您可以在最后的文档部分找到这些数据。

用 Python 下载 GSOD 数据(由作者创建)

为了下载 NOAA 数据,我决定使用请求创建一个简单的抓取功能。它从数据集的主目录开始,使用 regex 从基本 URL 页面的文本中查找所有可用的年份。在列表中的每一年,很容易构建最终的 URL 并下载每个 tarball。请记住,所有这些代码都可以在 Github 上获得,并且可以作为 Python 中的本地模块导入。

数据处理

在加载大型数据集时,最重要的问题是,一旦将数据加载到数据帧中,您希望访问哪些数据。2020 年有超过 11,000 个站点,这意味着大约 10 年的每日数据将是相当多的信息。相反,您可能希望进行一些聚合。对于本文,我决定按月汇总数据,并且只保存每年一天的每日数据。按月汇总数据将极大地减少我们最终数据框架的大小,同时还能让我们发现相当长时间序列的趋势。

保持某一天不聚合看起来很奇怪,事实也的确如此!我们想要保存一天的数据的真正原因是,我们可以在未来的帖子中使用 Dash 将最近一天的数据加载到实时仪表板中。就目前而言,它对于创建与我们稍后将使用 Dash 探索的内容相似的情节仍然有用。

步骤 0:导入

由于处理这些数据比大多数实践数据集要复杂一些,所以我包含了一个 GitHub 存储库,其中有一个本地模块,可以本地导入到您的 Python 环境中。

import gsodpy.gsodProcess as gsod
import gsodpy.gsodDownloader as gsodDown
import datetime

为了像这样在本地导入模块,“gsodpy”目录必须在您的项目目录中。

步骤 1:定义时间序列

我们需要做的第一件事是决定包括多少年,以及哪一天我们将存储未聚合的数据。然后我们可以使用 regex 来创建我们想要的文件列表。

num_years = 10
target_day = datetime.datetime(2020,3,20)
years, files = get_years_files(num_years)

为我们的时间系列寻找 tarballs(由作者创建)

步骤 2:在时间范围内处理文件

一旦我们定义了时间序列,我们就可以开始破解 tarballs 并进行处理了。csv 文件!以下是我编写的解包数据的函数。

将 GSOD 数据处理成 Python(由作者创建)

为了节省您的时间,以下是该工作流的基本伪代码:

- Loop through each tarball (years)
    - Loop through each csv file stored in tarball (stations)
        - Open .csv file for current station/year with pandas 
        - Call process_df() to clean the dataframe
        - Append all data for this station on target_day to df_day
        - Aggregate data by month
        - Append monthly aggregate to df
- Call add_meta() to create metadata column on df and df_day
- Return completed df and df_day 

总的来说,这个过程并不复杂,如果给我更多的时间,我相信我可以让它更简洁。请记住,由于每年有大量的站点,加载所有这些数据需要相当长的时间。

我们可以继续调用处理函数来获取数据帧:

df, df_day = gsod.process_all_years(files, target_day)

注意:如果你注意到你的机器正在努力处理所有的数据,试着从一个短的时间序列(2-3 年)开始。如果您想要更长的时间序列,您也可以在 tarball 中选择一个随机的电台样本,以减少您需要处理的电台文件的数量。

步骤 3:保存处理过的数据

我强烈推荐酸洗你完成的数据帧,这样你以后可以更快地加载它们。

import pandas as pd# Save DataFrames to pickle in current directory
df.to_pickle("df_monthly.pkl")
df_day.to_pickle("df_daily.pkl")# Read them back in later:
df = pd.read_pickle("df_monthly.pkl")
df_day = pd.read_pickle("df_daily.pkl")

形象化

现在我们已经将一些有意义的数据加载到 Python 中,我们可以开始有趣的部分,开始用 Plotly 制作可视化效果了!

如果你使用免费版的 Plotly,你只能上传 512kb。如果你在本地制作你的地块,这不是一个问题。然而,对于我来说,在这里分享互动的情节,我需要使用 Plotly 的图表工作室上传到他们的云。这意味着我只能使用这个功能随机选择大约 300 个气象站:

基本地图

首先,让我们看一下时间序列中的一个月,看看我们的一些站点在地图上的位置。这是我们可以用 Plotly 和这些数据创建的基本地图;考虑到它的配置如此之少,我认为它看起来相当不错。

Plotly 的主要数据结构是figure,它是plotly.graph_objects.Figure类的一个实例。figure是使用 JavaScript 通过 Plotly.js 渲染的,这就是为什么我们能够用 Python 访问高质量的地图。

用 Plotly 创建基本的散点图(由作者创建)

带 Plotly 的基本散点图(由作者创建)

我喜欢用 Plotly 绘制空间数据,因为它的界面简洁、响应迅速,几乎可以嵌入到任何地方。我一直很难在 Python 包中找到高质量的底图,但 Plotly 的很棒。

虽然这个情节可能很好,但我绝对会对它进行一些风格上的改变。海岸线很突出,颜色比例需要调整。总的来说,它可以被改变,使我们的数据点更加突出。幸运的是,所有这些事情都很容易用 Plotly 完成!

风格图:给定日期的极端温度

我选择保留某一天的数据而不是只记录每月的汇总数据的一个原因是,这样我们可以看到某一天最暖和最冷的地方。

首先我们需要找到我们的极端温度:

从 df_day 中查找极端温度(由作者创建)

这个图使用了与第一个图相同的结构,但是我花了更多的时间来定制标记和图形属性。您会注意到,我能够将一个字典传递给某些参数,如marker,以便进一步定制它们。在大多数情况下,这些参数是由字典中的信息初始化的对象。例如,marker参数初始化一个plotly.graph_objects.scattergeo.Marker对象。虽然这增加了复杂性,但你可以从散射图中看到。标记文档这给了我们对图上标记的控制。

使用 Plotly 的散点图(由作者创建)

地图框集成

我一直很喜欢地图盒子。它有很棒的基本地图,而且反应超级快。Plotly 有限的地图框集成可以增强您的地理地块。特别是当放大时,你会注意到与基本绘图版本相比,基本地图中的细节数量令人满意。Mapbox 对 Plotly 地图的渲染方式有很多影响,所以我将在整个帖子中讨论 Mapbox 的集成。

带有 Plotly 的散点图框(由作者创建)

添加滑块:2012 年各月的平均温度

我非常喜欢 Plotly 的一个特性是,添加一个滑块来查看数据随时间的变化是多么容易。例如,让我们看看 2012 年的月平均气温。

你会注意到我使用了一个稍微不同的语法来格式化这个图。从技术上讲,这是用 Plotly 绘图的“旧”方法。但是对于像这样更复杂的图,能够单独格式化数据是很好的。

使用 Plotly 在 Geo Plot 上滑动(由作者创建)

创造这个情节看起来比其他的更复杂。但实际上,大部分代码只是简单地将数据按月分组,以便 Plotly 轻松地发送到它的 JavaScript 库。如果您曾经处理过 json 数据,您可能会看到字典列表是如何轻松地转换成 json 的。

包扎

在 Python 中,空间数据从来都不是最容易处理的。它是多维的,通常非常大,普通的 2d 绘图空间不太适合绘制地理坐标。Plotly 通过提供易于使用的高质量底图功能,消除了许多令人头痛的问题,几年前我通常不得不使用 javascript 来访问这些底图。说到用 Python 进行空间绘图,Ploty 一般是我的首选。

使用 Plotly 绘制空间数据需要学习的东西太多了,所以不要害怕浏览在线文档和示例。同样的开发人员还开发了 Dash,这是构建实时仪表板的一个很好的工具。

证明文件

如何用 NiFi ETL 管道连接气流

原文:https://towardsdatascience.com/interconnecting-airflow-with-a-nifi-etl-pipeline-8abea0667b8a?source=collection_archive---------8-----------------------

NiFi 和 Airflow 都是数据项目中经常使用的强大工具,但是同时使用它们并不容易。

计划数据加载—由作者创建的图像。

在本文中,我将展示一个结构,并介绍如何将一个 NiFi ETL 管道插入到一个 Airflow DAG 的计划流中。

所需的流程如下所示:

  1. 预定气流 DAG 执行准备任务,
  2. 气流触发了 Apache NiFi 中的处理器,
  3. NiFi 执行一个 ETL 过程,
  4. 气流等待 NiFi 完成,
  5. 气流继续执行其他任务。

为了理解本文,在任何需要的地方都会提供 Python 代码,但是您可以在 GitHub 上查看整个代码库(包括文章中没有显示的子功能)。

关于基础设施和关注点分离的想法

虽然 NiFi 可以选择用 CRON 字符串调度处理器,但是在 NiFi 内部调度作业通常不是一个好主意——除非您别无选择。使用 Airflow,我们可以在一个地方监控和调度我们所有的任务,无论它们可能在哪里,界面简单美观,可以访问日志和高度可定制的调度管道,它们可以相互交互、相互排斥或相互依赖。

类似地,虽然 Airflow 也可以执行 ETL 任务(例如用 Python 编码的),但理想情况下应该在 NiFi 中实现,你真的不应该使用 Airflow 来这样做。一方面,Airflow 是一个监控和调度软件,另一方面,我们将失去 NiFi 在数据提取、转换和加载方面的所有固有优势。

仅使用 Airflow 作为调度程序,让 NiFi 在我们的后端完成繁重的工作,我们可以两全其美:Airflow 能够利用 NiFi 的可扩展、强大和高度可配置的有向图来路由和转换数据,从而创作、调度和监控工作流。此外,如果您在 EC2 实例上执行用于调度任务的数据密集型任务时没有造成 100%的 CPU 利用率和过载的 RAM,您的同事也会感谢您。

总体结构

我们有两个主要的联系点:

  • 启动/触发:DAG 将触发 NiFi 的 ETL 管道的起点。
  • 等待完成:每当 NiFi 完成了它在整个管道中的部分,DAG 就需要得到一个信号。

系统的连接——作者创造的图像。

我们将在下一章从配置 NiFi 开始,这样一旦我们编写了气流 DAG 并需要指定处理器 id,我们就已经设置好了一切。

NiFi 配置

我们需要两个强制处理器:

  • 一个GenerateFlowFile处理器,作为我们管道的起始节点,可以由气流触发。
  • 一个UpdateAttribute处理器作为我们管道的终端节点,它的状态可以被气流查询。

我们在这两个处理器之间实现了我们的流水线,由我们想要的任意数量的处理器组成。为了使这个例子简短,我们使用一个单一的PutSQL处理器作为整个 ETL 管道的替身。

在默认模式下,当所有后续处理器都在运行时,启动节点应该关闭,准备好被流文件触发。除了GenerateFlowFile处理器,您还可以使用GenerateTableFetch处理器——或者任何其他一旦打开就创建流文件的处理器。

您在 NiFi 中的管道可能如下所示:

处理器设置—由作者创建的图像。

开始节点

为了能够从气流中触发我们的起始节点并创建恰好一个流文件(我们不想多次触发管道),我们必须如下配置处理器:

处理器配置—由作者创建的图像。

通过将Execution设置为主节点,我们确保只有一个节点执行处理器。通过将Run Schedule设置为 60 秒,我们在创建第二个流文件之前给气流 DAG 足够的时间来停止处理器。

端节点

UpdateAttribute处理器中

  • Store State设置为Store state locally
  • 添加一个名为last_tms的自定义属性,其值为${now()}

处理器配置—由作者创建的图像。

每当流文件通过处理器时,代码now()将被执行,其结果(时间戳)将被存储在处理器状态的属性last_tms中。

我们可以通过手动运行我们的管道来检查这一点(打开GenerateFlowFile处理器,等待创建一个流文件,然后再次关闭它),然后在our.cluster.adress.com:9443/nifi-api/processors/{id}/state下的浏览器中访问 NiFi-API。以下 JSON 示例向您展示了我们处理器的当前状态:

现在,我们在 NiFi 中拥有了我们需要的一切——一个 startnode 处理器、一个 endnode 处理器以及我们可能想要在两者之间打包的任何东西:数据提取、转换和/或加载任务。

气流配置

气流 DAG 将由四个任务组成:中间的两个任务与 Apache NiFi 的 API 交互。第一个和最后一个是其他操作的替身,我们可能希望从 Airflow 中调度/执行这些操作,以准备或完成任务。

气流任务相关性—图片由作者创建。

为了与 NiFi API 交互,你可以编写自己的代码和 API 调用(完整的 API 在这里有详细的说明),或者你可以使用像 nipyapi 这样的包。为了简洁并独立于任何包的实现,我为本文编写了自己的 API 调用。

初始任务

这仅仅是我们可能想要做的一些其他准备工作的替身——本质上这个任务也可以被省去。

启动任务

启动任务包括三个步骤

  • GenerateFlowFile NiFi 处理器设置为RUNNING
  • 等待 15 秒钟(让处理器有时间创建流文件)。
  • GenerateFlowFile NiFi 处理器设置为STOPPED

您可以通过使用来自/nifi-api/processors/{id}GET请求检索当前状态,在自定义 JSON 中本地设置状态,并使用PUT请求发送到/nifi-api/processors/{id}/run-status来更改处理器的状态

为了关注手头逻辑的基本结构,我从文章中排除了子功能,比如get_token()update_processor_status()——但是你可以在公开的 GitHub 库上找到它们。该任务的 python 代码如下:

等待任务

为了让 Airflow 注意到 NiFi 何时完成了 ETL 操作,我们需要不断地查询nifi-api/processors/{id}/state并解析结果 JSON 中的last_tms的值,直到状态发生变化。我们通过每 60 秒检查一次 API 在 while 循环中实现这一点:

parse_state()以及所有其他子功能可以在公共的 GitHub 库中找到。

延续任务

最后一个任务是在 NiFi 管道之后,替代您想要执行的任何代码。

气流 DAG

DAG 由上述函数组成,我们只需要配置它们的依赖关系。因为我们的任务应该一个接一个地运行,所以 DAG 就像箭一样直。

根据您的目的,您可能想要编辑 DAG 参数,但以下是一个好的开始:

概述和结束语

下图展示了我们脚本的程序流程以及系统之间的交互。在 Airflow 中的一些准备任务之后,我们的 NiFi 管道被触发,Airflow 等待管道完成,然后继续其他任务。

虽然还有其他连接气流和 NiFi 的方法,但这里介绍的是一种简单的方法,没有太多的开销。设置完成后,很容易扩展到其他用例,集成数据管道而不改变整体设置,在 Airflow 或 NiFi 中添加/删除额外部件而不干扰两个部件之间的连接。

互连和流程——作者创建的图像。

我们现在还可以将 NiFi 管道中的虚拟PutSQL处理器替换为我们需要的任何处理器——我们只需要确保当我们准备好让气流继续工作时,流文件到达UpdateAttribute处理器。同样,我们可以在 Airflow 中为初始任务或延续任务添加内容。

我希望这篇文章能帮助您将 NiFi 管道插入到您预定的气流 Dag 中。

完整的代码包括所有使用过但没有在本文中显示的子功能,可以在 GitHub 中找到。

一如既往,我们永远学不完。点击此处了解更多关于气流和 Nifi 的信息:

关注我,以后会有更多围绕数据工程工具和方法的文章!

Python 利率理论与实践—简单利率

原文:https://towardsdatascience.com/interest-rate-theory-and-practice-with-python-simple-interest-rate-50415c58eaca?source=collection_archive---------12-----------------------

使用 Python 的利率实用介绍。对利率的良好理解将有助于我们做出更明智的金融决策

照片由像素皮克斯拜拍摄

在金融中,利息是我们借钱的价格。良好的资金管理和财务决策在很大程度上取决于我们对利率及其对财务健康的影响的了解程度。

在这篇文章中,我们将研究简单利息是如何工作的。其实单纯的兴趣对我们来说并不少见。我将用我们日常生活中的一个例子如汽车贷款来说明这种兴趣背后的概念。很好地理解利息将有助于我们避免许多金融陷阱。

此外,我还将使用 Python 演示利息的计算。希望这能帮助你在做财务规划时重用代码来构建自己的财务计算器。

必备 Python 库

  1. 数字财政——https://numpy.org/numpy-financial/

开源代码库

本文中的原始完整源代码可以在我的 Github Repo 上获得。如果您希望使用它来关注我的文章,请随意下载它(simpleinterestrate . ipynb)。

单利(汽车贷款)

单利是一笔没有复利的贷款本身 单利来源于贷款的本金金额。基于单利的金融产品的一个典型例子是汽车贷款。

例如,我们购买一辆汽车,汽车贷款金额为 15000 美元,年利率为 4%,期限为 5 年。这里,我们有几个问题要回答:

五年内我们总共要付多少钱?(假设我们每月按时付款)

我们可以用下面的等式来解决这个问题:

作者准备的图像

现在,让我们试着把这个等式放到我们的第一个 Python 程序中。

第 1–2 行:导入 Python 库

第 5–7 行:为计算单利的所有变量定义并赋值。

第 8 行:应用单利方程得出 5 年后的应计支付额。

作者准备的图像

五年累计总支付金额(本金+利息)为 $18000

我们每月的分期付款是多少?

我们可以使用以下公式估算每月分期付款:

作者准备的图像

让我们再次尝试在 Python 脚本中应用该公式。我们可以利用 Python Numpy pmt 函数来计算每月的分期付款。

第 1–3 行:定义所有必需的参数(月利率、月数和贷款金额),并相应地为其赋值。

第 4 行:使用 Python Numpy pmt 函数计算每月分期付款。计算公式已经封装在函数中。(注意:原始结果值将是负值,这就是我们将该值乘以-1 以将其变为正值的原因。)

第 5 行:显示结果。

作者准备的图像

每月分期付款约为276.25 美元

C.我们每月要付多少本金和利息?

我们支付等额利息和本金的贷款(例如 138.125 美元(本金)+138.125 美元(利息)= 276.25 美元)。我们的贷款通过 分期偿还 支付,这是一个包括本金和利息的定期分期付款过程。对当前付款收取的利息是基于我们还欠多少贷款本金。

例如,在分期付款的第一个月,月利率适用于我们所借的全部贷款。对于第二个月和随后的几个月,利息费用将越来越少,因为当前的本金金额已经由上个月的分期付款支付(请参考下面的计算细节)。

作者准备的图像

基于上面显示的计算逻辑,我们可以使用 Python 为我们的每月分期付款构建一个摊销表。Python Numpy-Financial library 的 ipmt 和 ppmt 函数可以自动计算为我们支付的月利息和月本金。

第 1 行:将本金金额设置为 15000

第 2 行:创建一个包含 60 项(5 年* 12 个月)的 Numpy 数组

第 3–4 行:使用 Numpy-Financial ipmtppmt 函数计算每月支付的利息和本金。我们所需要的只是给函数分配正确的参数。

第 6–8 行:定义输出校准格式

第 10–11 行:应用第一个和第二个输出格式来显示表头和第一行记录。

第 13–16 行:创建一个 for 循环,并应用第三种输出格式来迭代显示已付本金、已付利息和剩余本金。

作者准备的图像

由此产生的分期偿还表将使我们清楚地了解我们每月分期付款所支付的每月利息和本金。

D.贷款期限如何影响利息费用?

我们目前的贷款期限是 5 年,年利率是 4%,每月分期付款是 276.25 美元。假设银行向我们提供了另一个 7 年期的贷款计划。同样利率 4%的 7 年期贷款将只需要我们每月支付 205.03 美元的分期付款。

这听起来像是一笔 7 年期贷款的好交易,因为它节省了我们每月对贷款的财务承诺。然而,让我们比较一下 5 年期和 7 年期贷款的累计利息。我们可以重用 Python Numpy-Financial ipmt 函数来分别计算 5 年和 8 年贷款的每月利息承诺。

第 2–5 行:重复上一节给出的类似代码,使用 Python Numpy-Financial ipmt 函数计算 5 年期贷款的月利息费用。

第 6 行:由于 interest_paids 是一个保存一系列每月利息费用的 Numpy 数组,我们可以使用内置函数 sum 来获得 5 年内支付的累计利息。

第 7 行:显示 5 年内累计支付的利息。

第 10–15 行:重复与第 2–7 行类似的步骤,获得 7 年内支付的累计利息并显示结果。

作者准备的图像

结果表明,在相同利率下,7 年期贷款的累计利息支付高于 5 年期贷款。没有免费的午餐,以较低的月供采取更长的贷款期限。虽然我们可以为 7 年期贷款支付较低的分期付款金额,但我们必须向银行支付更多的利息(额外的 647.83 美元)作为回报。

结束语

如上所述,单利总是适用于剩余的本金金额。我们不应该延迟付款,否则剩余的本金会产生额外的利息费用。

相反,降低利息费用的一种方法是进行计划外/额外的支付,这会降低我们的贷款余额。这将加快我们偿还贷款的速度。但是,这里有几个注意事项:

  1. 我们需要额外的现金来支付这笔额外的款项。在支付这笔款项之前,我们应该检查一下自己的财务状况。
  2. 即使我们有多余的现金,有没有更好的方法来花这笔钱?例如,这可能值得使用额外的现金来开始投资,以产生更多的额外收入。
  3. 或者,我们是否有其他贷款承诺,如信用卡,可能需要更优先关注?不要忘了一些债务,如信用卡未偿贷款会产生复利,这可能会更严重地影响我们的财务健康。

当我们对贷款利息有了足够的了解,我们就更容易为自己做出合理的财务决策。

我希望你喜欢阅读这篇文章。

如果你喜欢我以 Python 为财经话题的文章,可以随时 订阅 Medium 。我会坚持不懈地不时发表相关文章。

参考

  1. https://www.investopedia.com/terms/s/simple_interest.asp
  2. https://mytresl.com/blog/car-loan-interest/
  3. https://www . experian . com/blogs/ask-experian/can-you-pay-more-on-your-car-payment/

对决策智能感兴趣?从这里开始

原文:https://towardsdatascience.com/interested-in-decision-intelligence-start-here-30ed4fec81fa?source=collection_archive---------25-----------------------

探索数据科学

“决策智能是在任何规模下将信息转化为更好行动的学科。”

在这篇 14 分钟的综合报道中,谷歌决策智能主管凯西·科兹尔科夫邀请我们了解她专业领域的更多信息。在介绍了重要的术语和概念(从“什么是决策”到“计算和决策之间的区别是什么”)之后,Cassie 更深入地挖掘了这个迷人的主题,并展示了它与所有数据科学家的工作有多么相关。

对深度学习感兴趣?

原文:https://towardsdatascience.com/interested-in-deep-learning-d30241f6609?source=collection_archive---------16-----------------------

深度学习

本文包含针对初学者的深度学习和相关主题的介绍性信息。

摩根·豪斯尔在 Unsplash 上的照片

深度学习

深度学习是一个机器学习领域,它利用人工神经网络从数据中学习模式。

对深度学习工作方式的一个基本解释是,人工神经网络试图以某种形式模仿人脑的功能(尽管这将过于简化它的工作方式)。

人工神经网络的一个可能的限制因素是,它们被用于解决与用于训练人工神经网络的数据共享密切关联(相似模式)的任务。

深度学习的主要好处是,深度学习架构内的学习过程和特征提取是自动发生的。没有规定的要求。算法的预期数据的格式,或者利用特定领域的试探法来获得最终结果。

人工神经网络中的学习是由被称为神经元的逻辑单元驱动的,神经元被设计成模仿人脑中的生物神经元。

深度学习在多个行业和应用中普遍存在。本文包含对深度学习应用的评估,包括深度学习技术解决的问题类型。

机器学习

在我们进一步探索深度学习之前,让我们后退一步,参观机器学习,这是一个概括了教机器从数据中学习的努力的总体领域。

机器学习涉及开发自动学习的算法,而无需任何明确定义的关于如何“学习”的指令。在引入深度学习之前,传统的机器学习技术涉及非常动手的方法。

在深度学习被广泛采用之前,机器学习研究人员和工程师必须设计算法来检测要提取的特定特征。这些特征描述了图像中的对象并提供了上下文信息。例如,为了训练一个系统来识别猫,研究人员将明确定义猫之间的共同特征和属性,以便算法进行检测。

识别独特特征的过程很麻烦;本质上,传统机器学习算法中的特征工程任务是不可扩展的。

深度学习的出现带来了直接从输入数据中自动学习模式和特征的能力,而无需任何关于算法应该检测什么的事先指令。

深度学习的构建模块

作者图片

本节介绍了深度学习的组成部分,以及它们如何模拟人类中常见的学习。

感知器和神经元

大脑负责人类所有的认知功能;简而言之,大脑负责你学习、获取知识、保留信息和回忆知识的能力。

乔希·里默尔在 Unsplash 上的照片

大脑中学习系统的基本组成部分之一是生物神经元。神经元是一种负责向其他神经元传递信号的细胞,因此也负责向身体的其他部分传递信号。

研究人员以某种方式将生物神经元的功能复制到一个数学上有代表性的模型中,称为感知器。

需要注意的一点是,感知机和神经元这两个术语在机器学习中可以互换使用。

人工神经元是接收一些输入的处理单元,在对输入数据进行内部数学运算(激活函数)后,神经元提供输出。

神经元的内部运作

作者图片

如上图所示,神经元的输出来自不同的神经元组件。

传递给神经元的输入数据是数字的。诸如图像、视频、音频和文本的数字数据格式被转换成数字表示,作为输入数据提供给神经元。

下面是神经元内部工作的逐步过程。

  1. 进入神经元的输入数据乘以权重。权重是神经元内的突触,其呈现随机值,随后随着神经网络的训练和通过反向传播进行的权重更新而进行调整。
  2. 计算乘以数字输入数据的所有权重的总和。这个求和是由一个叫做加法器的神经元组件完成的。
  3. 权重和输入数据的总和也与偏差相结合。
  4. 然后将步骤 3 的结果传递给一个激活函数。激活函数的作用是强制神经元的输出落在一组值内,通常为-1,1 或 1,0。激活函数的例子有阈值逻辑单元、整流线性单元(ReLU)、泄漏 ReLU、tanh、sigmoid 等。

神经网络内的学习过程通过反向传播来促进。反向传播是一种计算成本函数相对于网络权重值的梯度的算法。有关反向传播及其在神经网络中所扮演角色的更多信息,请查看这个视频

深度神经网络

神经网络由多个神经元组成,这些神经元通常组织成层。典型的神经网络结构由输入和输出层组成。输入层是暴露给输入数据的第一层,而输出层关注分类结果或来自神经网络的期望输出。

当谈到深度神经网络(DNNs)时,我们通常指的是具有一个以上隐藏层的神经网络,即输入和输出层之间的神经元层。只有一层的神经网络称为浅层网络。

浅网络的描述

深度神经网络的描绘

如前所述,深度神经网络在神经元内包含一组权重,这些权重采用初始随机值,通过反向传播修改为将输入数据的特征映射到所需输出的值。权重值适于映射输入数据和输出结果之间的线性和复杂非线性关系。

在图像分类中,DNNs 可以从输入图像或一批训练数据中学习每个对象进行分类的概率。

你最有可能遇到的常见神经网络架构是递归神经网络(RNNs)卷积神经网络(CNN)

rnn 用于解决语言相关的任务,例如语言建模、自然语言处理、语言翻译和图像字幕。

细胞神经网络用于解决计算机视觉任务,如物体检测,手势识别,语义分割和姿态估计。

卷积神经网络

从图像和视频中提取场景理解的应用程序具有巨大的价值。此类应用的示例包括人脸检测系统、支持对象识别的设备、自动驾驶汽车等。

卷积神经网络是神经网络架构的标准形式,用于解决与图像相关的任务。

卷积神经网络(CNN)具有能够对通过网络馈送的图像的仿射变换(缩放、移位、旋转)保持不变的特性。这提供了识别图像中偏移、倾斜或轻微扭曲的图案的能力。

传统前馈神经网络中的神经元通常执行输入数据和权重之间的乘法运算。在 CNN 中,这种数学运算是一种卷积。

卷积是一个数学术语,描述两个函数的结果,其中一个修改另一个。卷积运算本身是两个函数乘积的积分,其中一个函数被反转和移位。

卷积运算作用于卷积层内的滤波器/内核和图像数据阵列。

如果你想探索更多关于 CNN 的介绍性话题,斯坦福大学的这个视频提供了一些关于 CNN 相关话题的有用信息。

卷积神经网络

CNN 架构

本节介绍两个对深度学习领域做出巨大贡献的关键 CNN 架构。它们被称为 LeNet-5 和 T2 Alex net。

LeNet 介绍了卷积神经网络在图像分类的计算机视觉任务中的应用。在 2012 年,卷积神经网络架构 AlexNet 引入了连续堆叠的卷积层的组成以及用图形处理单元(GPU)训练 CNN。

LeNet-5

LeNet 是由 Yann LeCunLeon BottouYoshua BengioPatrick Haffner 在 1998 年的研究论文“基于梯度的学习应用于文档识别”中介绍的。该论文的许多列出的作者继续为深度学习领域提供了几项重要的学术贡献。

它被称为 LeNet-5,因为它由三个卷积层和两个子采样层组成。它还有两个完全连接的层,一个输出层和一个输入层。

LeNet-5 架构图片来自原纸

1989 年,Yann LeCun 推出了 LeNet 架构的第一个变体,用于识别手写的邮政编码。1998 年,LeNet-5 被用于解决文档识别,开创了卷积神经网络应用于计算机视觉任务的时代。

AlexNet

AlexNet 卷积神经网络于 2012 年推出。从那时起,深度卷积神经网络的利用已经飙升到了几个机器学习解决方案利用深度 CNN 的地步。

AlexNet 卷积神经网络架构在论文 ImageNet 分类与深度卷积神经网络中提出。这篇论文由 Alex Krizhevsky、Ilya Sutskever 和深度学习的教父之一 Geoffery Hinton 撰写。

AlexNet 的创建者利用 GPU(图形处理单元)内的计算能力来训练 AlexNet 网络。当时用 GPU 训练神经网络并不是一种典型的方法。

简化的 AlexNet 神经网络多 GPU 架构

AlexNet 作者还利用各种技术来减少深度神经网络的常见问题(消失梯度、过拟合);这些技术是:数据增加,丢失,重新激活功能,局部反应正常化。

深度学习的优势

梁杰森Unsplash 上的照片

深度学习技术及其应用提供了明显的优势和好处。我们甚至认为这些好处是理所当然的,因为它们已经融入了我们的日常生活。

一些普遍的好处包括自动化机器人和物体检测使相机能够简化制造流水线,由于更好的图像处理能力和疾病和病毒药物的突破性发现,增加了对宇宙中可居住行星的检测。

对于 ML 从业者来说,下面是深度学习的一些优势。

  1. ML 从业者不再需要实现启发式算法来识别数据中的特定特征,因为神经网络会自动检测特征。
  2. 通过深度学习应用在行业内的快速采用和令人印象深刻的性能,基于计算机视觉的应用的利用率有所增加。
  3. 大多数计算机视觉任务的深度学习方法比传统的计算机视觉方法具有更高的准确性。
  4. 传统的计算机视觉方法对特定问题产生非常定制的解决方案。相比之下,深度学习允许通过微调和转移学习过程来解决不太特定于领域的任务。

深度学习的缺点

马库斯·温克勒在 Unsplash 上拍摄的照片

尽管我们可能会享受深度学习的好处,但在自动化过程中利用深度学习加剧了对未来失业的担忧。

由于技术的滥用和用于训练深度学习模型的数据中的固有偏见,面部识别已经受到公众的审视。

但是让我们退一步,从更技术性和领域相关的角度来探讨深度学习的缺点。

  1. 用更多的数据来提高模型训练的性能和准确性似乎是一个由于有限的数据源而不可探索的解决方案。
  2. 在任何计算机视觉任务中具有最先进性能的深度学习模型通常需要大量的计算资源来训练和评估模型。
  3. 在对象检测任务中,数据注释可能很麻烦,尤其是当需要大型数据集时。有标注工具、众包数据标注等解决方案。
  4. 深度学习模型的性能会受到模型训练阶段使用的图像或视频的分辨率的影响。更高分辨率的图像在识别图像中的更多特征方面是有效的。
  5. 深度学习模型通常缺乏可解释性和可解释性。神经网络做出决策所采取的步骤是神经网络本身无法追溯或解释的。这使得难以检测由神经网络做出的错误分类的内部原因。缺乏可解释性使得采用深度学习应用程序成为一种谨慎的行为,特别是在医疗保健和国防等领域。

研究人员和工程师目前正在研究上述问题的解决方案,因此在几年内,上述问题可能会得到解决。

想要更多吗?

  1. 订阅 在我发表文章时得到通知。
  2. 成为推荐媒介会员,支持我的写作
  3. 通过 LinkedIn 联系我
  4. 奥莱利 跟我学

选择熊猫数据帧列的有趣方法

原文:https://towardsdatascience.com/interesting-ways-to-select-pandas-dataframe-columns-b29b82bbfb33?source=collection_archive---------0-----------------------

克里斯汀娜·戈塔迪在 Unsplash 上的照片

在数据科学项目的探索性分析或预处理过程中,操作 pandas 数据框是一项常见任务。过滤和子设置数据也很常见。随着时间的推移,我发现自己需要根据不同的标准来选择列。希望读者找到这篇文章作为参考。

示例数据

如果您想使用我用来测试这些从 pandas 数据框中选择列的方法的数据,请使用下面的代码片段将 wine 数据集放入您的 IDE 或笔记本中。

from sklearn.datasets import load_wine
import pandas as pd
import numpy as np
import reX = load_wine()
df = pd.DataFrame(X.data, columns = X.feature_names)df.head()

Jupyter 笔记本中葡萄酒数据集的作者截图

现在,根据您想要做的事情,查看下面的每一个代码片段,并亲自尝试!

根据名称选择列

这是从数据帧中选择单个列的最基本方法,只需将列的字符串名称放在括号中。返回熊猫系列。

df['hue']

在括号中传递一个列表可以让您同时选择多个列。

df[['alcohol','hue']]

选择列表中找到的列的子集

与上一个示例类似,但这里您可以搜索数据帧中的所有列。

df[df.columns[df.columns.isin(['alcohol','hue','NON-EXISTANT COLUMN'])]]

基于列的差异选择列的子集

假设你知道你想要数据框架中的哪些列。将它们作为一个列表传递给 difference 方法,你将得到除它们之外的所有内容。

df[df.columns.difference([‘alcohol’,’hue’])]

选择不在列表中的列子集

返回一个数据框,其中的列不在您要搜索的列表中。

df[df.columns[~df.columns.isin(['alcohol','hue'])]]

基于列的数据类型选择列

数据类型包括“float64”和“object ”,是从传递给 dtypes 方法的列中推断出来的。通过匹配相同数据类型的列,您将得到一系列真/假。使用 values 方法只获取真/假值,而不获取索引。

df.loc[:,(df.dtypes=='float64').values]

根据包含子字符串的列名选择列

如果数据框中有大量列,并且它们的列名都有您感兴趣的相似子串,则可以返回名称中包含子串的列。在这里,我们需要包含“al”子字符串的所有内容。

df.loc[:,['al' in i for i in df.columns]]

根据包含字符串通配符的列名选择列

您可能有数百列,因此查找与某个模式匹配的列可能是有意义的。可以使用 re 包中的“search”函数来搜索与通配符匹配的列名(有关使用正则表达式包的更多详细信息,请参见参考部分中的链接)。

df.loc[:,[True if re.search('flava+',column) else False for column in df.columns]]

根据列名的开头选择列

如果希望选择名称以某个字符串开头的列,可以使用 startswith 方法,并将其传递到数据框位置的 columns 位置。

df.loc[:,df.columns.str.startswith('al')]

根据列名的结尾选择列

与上一个示例相同,但是查找名称以某种方式结尾的列。

df.loc[:,df.columns.str.endswith('oids')]

如果所有行都满足条件,则选择列

如果行满足条件,您可以选择列。这里,如果一列中的所有值都大于 14,我们将从数据框中返回该列。

df.loc[:,[(df[col] > 14).all() for col in df.columns]]

如果列中的任何一行满足条件,则选择列

这里,如果一列中的任何值大于 14,我们将从数据框中返回该列。

df.loc[:,[(df[col] > 14).any() for col in df.columns]]

如果列中的平均行数满足条件,则选择列

这里,如果一列中所有值的平均值满足某个条件,则返回该列。

df.loc[:,[(df[col].mean() > 7) for col in df.columns]]

感谢您的检查,并随时参考它。

参考

https://github.com/caseywhorton/medium-blog-code https://pandas.pydata.org/

Python 中使用标点符号的有趣方式

原文:https://towardsdatascience.com/interesting-ways-to-use-punctuations-in-python-43205a0bd67d?source=collection_archive---------13-----------------------

学习实用的编码技巧

你喜欢学习用 Python 编码时可以使用的小技巧吗?在这篇文章中,我分享了 Python 中标点符号有趣而实用的用法。

天一马Unsplash 上拍照

📍括号: ()或 b 反斜杠:\ 用于中断一长行代码

你是否有时发现你的代码行太长了?如果你想知道是否有办法把它分成多行,反斜杠和括号可以帮助你。让我们看一个例子。

首先,我们将导入必要的库并加载一个样本数据集:

# Import libraries
import pandas as pd
from seaborn import load_dataset# Load sample dataset
columns = ['species', 'island', 'body_mass_g', 'sex']
df = load_dataset('penguins', usecols=columns)
df

假设我们有以下查询,我们发现它有点太长:

df.query("species=='Adelie'").groupby(['island', 'sex'])['body_mass_g'].agg(['min', 'median', 'max']).unstack()

我们可以用括号将代码括起来,这样我们就可以像这样将它写在多行上,使它更具可读性:

(df.query("species=='Adelie'")
   .groupby(['island', 'sex'])['body_mass_g']
   .agg(['min', 'median', 'max'])
   .unstack())

或者,我们也可以使用反斜杠:

df.query("species=='Adelie'")\
  .groupby(['island', 'sex'])['body_mass_g']\
  .agg(['min', 'median', 'max'])\
  .unstack()

顺便说一句,PEP 8 风格指南建议将你的行长度控制在 79 个字符以内。下一次,如果你有一个太长的代码,你想把它分散到多行,你知道该怎么做!

📍星号:* &下划线:_ 拆包时

您可能熟悉使用list解包由enumerateziprange 等有用的内置函数返回的值:

example = ['a', 'b', 'c', 'd']
list(enumerate(example))

我们解包的第二行也可以用星号(*)表示:

[*enumerate(example)]

按照这种逻辑,以下是实现相同输出的两种方法:

list(zip(example, example[::-1]))
[*(zip(example, example[::-1]))]

下面是星号的另一个有用的应用:如果你想只给某个值赋值,而把中间所有的值赋给一个变量,我们可以使用一个星号表达式来实现,其中一个变量以星号为前缀:

first, *rest, last = example 
print(f"first: {first}")
print(f"rest: {rest}")
print(f"last: {last}")

在这个例子中,*rest是一个带星号的表达式。这里first 被指定为'a',last 被指定为'd',而rest 被指定为剩余值['b', 'c']。通过在变量前面添加一个星号,比如rest,我们让这个变量捕捉中间的所有值。我们也可以像这样使用带星号的表达式:

first, *rest = example # example A
*rest, last = example # example B

你大概可以猜到,在例子 A 中,first取值为'a'rest 取值为['b', 'c', 'd'],而在例子 b 中,rest取值为['a', 'b', 'c']last取值为'd'

有时,在解包时,您可能不想将所有的值都赋给一个变量。在这些情况下,我们可以使用下划线来忽略我们不需要分配的不必要的元素。

first, _, _, last = example
print(f"first: {first}")
print(f"last: {last}")

这里first'a'的值,last'd'的值,而其余的值不赋值。

希望有机会时你会用到这些小技巧。

📍赋值表达式 : :=赋值时

这是 Python 3.8 中引入的新特性。这也称为命名表达式或 walrus 运算符。如果你把头向左倾斜,你会看到它像一个可爱的海象表情符号。为了理解它的作用,让我们看一个简单的例子:

x = 10
print(x) # or x depending on the IDE

首先,我们将值 10 赋给 x,然后打印 x 的值。使用赋值表达式,上面的代码现在可以写成:

print(x := 10) # or (x := 10)

所以这个操作符赋值并返回值。如果您熟悉 R,您可能会注意到这类似于下面的 R 语法:

print((x = 10)) # or (x = 10)

虽然我不确定这两种编程语言的内部是否完全相同,但从表面上看,它们非常相似。

如果想了解更多, PEP 572 是它的官方文档。值得注意的是,关于 PEP572 的讨论引发了一些争议,并且潜在地影响了 Guido Van Rossum 从 Python 仁慈的终身独裁者的辞职。

Voila❕:今天到此为止。✨

照片由安朵斯·瓦斯Unsplash 拍摄

您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接成为会员,您的一部分会费将直接用于支持我。

感谢您阅读这篇文章。如果你感兴趣, 以下是我的一些其他帖子的链接:
◼️ 从零开始学习 Python 的 5 个技巧
◼️ 有用的 IPython 魔法命令
◼️Python 虚拟数据科学环境简介
◼️git 数据科学简介
◼️ 用这些技巧组织你的 Jupyter 笔记本
◼️ 你会发现有用的 python 中的简单数据可视化 为了更漂亮和定制的情节,◼️️给熊猫用户的 5 个建议◼️️用熊猫写高级 SQL 查询

再见🏃💨

互操作性数据-物联网:如何发送和接收数据并控制你的 Arduino,来自 R

原文:https://towardsdatascience.com/interoperability-data-iot-how-to-send-and-receive-data-and-take-control-of-your-arduino-from-r-eb83005bff87?source=collection_archive---------15-----------------------

如何通过两者之间的数据流建立 R 和 Arduino(数据和物联网)之间的互操作性

照片:在 RStudio 中接收来自 Arduino 的数据

当我们谈到 R 和 Arduino 时,除了它们都有一个字母 R 之外,我们还能谈论什么呢?让我们从头开始,以防你不熟悉, Arduino 是一个基于易于使用的硬件(Arduino 板)和软件(Arduino IDE)的开源电子平台。如果你有正确的数据类型和一组处理数据和执行后续操作的指令,你可以告诉这张流行的卡该做什么。Arduino 微控制器负责保存所有已编译的代码,并执行您指定的命令。另一方面,Arduino 软件是电路板的 IDE,用来编写控制电路板的指令集。如果这是你第一次使用 Arduino,我建议你回顾一下这个入门,了解继续本文中的例子的最低要求。

开始前

现在,如果你知道 R,你会知道这是一种优雅的语言,非常适合数据分析和数据科学。尽管如此,数据和物联网之间可以实现融合。这个例子非常简单,本文的目的是探索 R 和 Arduino 之间的互操作性,根据接收到的数据在两者之间建立数据流,并在电路板的微控制器中发出指令。在这个上下文中,R 将处理数据和与之相关的一切,并将其发送到 Arduino。另一方面,Arduino 会根据收到的数据触发外设。这怎么可能呢?使用 Arduino 通过串行端口直接编程的能力。

在我们开始之前,这里有一个演示 R 和 Arduino 之间互操作性的概述:

  • 首先,您将从 RStudio 向 Arduino 串行端口发送一系列定义 3 个 led 亮度的数据(范围为 0% — 100%)。
  • Arduino 脚本将等待串行数据可用,提取 3 个 led 的亮度值,将它们分配到模拟值(0–255),指示板载微控制器将这些值写入 led,然后将映射值(0–255)发送到 Rstudio-Arduino 串行接口。
  • Rstudio 将读取从 Arduino 发送到串行端口的值。然后,您将使用这些值(范围从 0 到 255)创建一个数据集来转动伺服电机,并将这些值传递到串行接口。
  • 一旦 Arduino 再次检测到有串行数据,它将读取串行接口上的每个值(0–255),将其分配给一个角度旋转值(0 到 180),旋转伺服,并将角度发送回串行接口。
  • 最后,您将读取电机的角度,并使用 Rstudio 中的“ggplot”完成可视化。

当所有这些都完成后,这就是你使用 R 和 Arduino 一起工作想要达到的效果:

展示 Arduino 和 R 之间互操作性的视频

要继续,您将需要 Arduino IDE 和一个 Arduino(在此示例中,我使用 Arduino UNO)、一个红色 LED、一个绿色 LED、一个蓝色 LED、一个伺服电机(SG90)和跳线。硬件组件的连接方式如下所示:

原理图互用性项目 Arduino & R

对于 RStudio 部分,我们将需要【tidy verse】【马格里特】【Plotly】【串行】包。Tidyverse 是一个 R 包集合,设计用于数据科学任务,如数据可视化和处理。串行允许在 RS232 / RS422 / RS485 或计算机的任何其他虚拟串行接口中读写二进制和 ASCII 数据。Plotly 将允许您从“gg plot 2”图形创建交互式网络图形。您可以按如下方式安装它们:

# PACKAGE INSTALLinstall.packages(c("tidyverse", "serial", "plotly", "magrittr"))

使用串行接口

在 R 中启动一个新的脚本,您将加载前面提到的库。要获得计算机上可用串行接口的列表,只需使用 listPorts() 函数。

# REQUIRED LIBRARIESlibrary(tidyverse)
library(serial)
library(magrittr)
library(plotly)listPorts()

您将在控制台中得到如下所示的输出。最有可能的是,如果你在 Windows 上工作,你会发现列出了更多的端口。

控制台上的输出,端口启用

配置串行接口

接下来,您将创建一个名为“myArduino”的端口对象,它代表一个串行客户端,用于与您的卡所连接的 USB 串行端口进行通信。但是你的 Arduino UNO 连接的是哪个端口呢?通过导航到工具/端口菜单查看适当的端口,运行 Arduino IDE 可以获得此信息。

Arduino IDE,Arduino UNO 连接的端口

在我的例子中,它所连接的 USB 串口对应的是“cu.usbmodem1421”。有了这些信息,您现在可以创建一个连接到板的串行接口。这通过使用串行连接()函数设置接口参数来实现。

# SERIAL CONNECTIONmyArduino <-  serialConnection(
  port = "cu.usbmodem1421",
  mode = "9600,n,8,1" ,
  buffering = "none",
  newline = TRUE,
  eof = "",
  translation = "cr",
  handshake = "none",
  buffersize = 4096
)

既然已经建立了接口,下一步就是初始化它,并保持它的开放状态以备后用,比如从其中写入和读取数据。一旦接口初始化,Arduino 板就会闪烁。这是因为一旦串行端口被打开以允许引导装载程序接收新的草图,板就会重新启动。

# OPEN AND TESTING THE CONNECTIONopen(myArduino)
isOpen(myArduino)

将数据从 RStudio 写入串行接口

现在,您可以向串行接口写入一些数据了。您将发送到接口的值将在 0 到 100 的范围内,表示所需的 LED 亮度百分比。此外,您将添加 R、G 和 B 字符来帮助 Arduino 区分哪个值被写入哪个 LED。

您必须创建一个包含 r、g 和 b 三列的数据集,并为其亮度值添加一个字母。

# MAKING RGB DATAn <-  30arduinoInput <- tibble(
  r = (sample(1:100, size = n, replace = T) %>%
         paste('R', sep = '')),
  g = (sample(1:100, size = n, replace = T) %>%
         paste('G', sep = '')),
  b = (sample(1:100, size = n, replace = T) %>%
         paste('B', sep = ''))
)# A GLIMPSE OF ARDUINO INPUTglimpse(arduinoInput)

你可以在控制台上浏览一下。

输出控制台,输入概述

您可以看到,将写入串行接口的 led 值是字符类型,这是串行通信所需的数据类型。

您将使用 write.serialConnection() 函数将 LED 值逐行写入串行端口。

# CLOSE THE OPEN CONNECTION AGAIN (BEST PRACTICE)close(myArduino)
open(myArduino)# GIVING TIME FOR THE BOARD TO RESET ONCE THE SERIAL INTERFACE IS INITIATEDSys.sleep(3)for (r in seq_len(n)){
  Sys.sleep(0.25)
  write.serialConnection(myArduino, paste(arduinoInput[r,], collapse = ''))
}

暂停!让我们去 Arduino IDE 看看会发生什么

你可能想知道,led 将如何点亮字符值?Arduino 上的脚本会处理这个问题。将以下草图从 Arduino IDE 上传到您的 Arduino。

// SETTING RGB LEDS 

int rLed = 0;
int gLed = 0;
int bLed = 0;
int serv = 0;int redLed = 6; // RED LED ON PIN 6
int greenLed = 5; // GREEN LED ON PIN 5
int blueLed = 3; // BLUE LED ON PIN 3void setup() {
  Serial.begin(9600);  

  // SETTING PINS AS OUTPUT

  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
  pinMode(blueLed, OUTPUT);void loop() {
  if (Serial.available()){

   // MAKING VARIABLE VISIBLE TO ONLY 1 FUNCTION
   // CALL AND PRESERVE THEIR VALUE

   static int t = 0;

   char myvalue = Serial.read();switch(myvalue){

    // MYVALUE IS A VARIABLE WHOSE VALUE TO COMPARE WITH VARIOUS CASES

    case '0'...'9':
      t = t * 10 + myvalue - '0';
      break;   

    case 'R':
    {
      rLed = map(t, 0, 100, 0, 255);
      analogWrite(redLed, rLed);
      Serial.println(rLed);  
    }
    t = 0;
    break;

    case 'G':
    {
      gLed = map(t, 0, 100, 0, 255);
      analogWrite(greenLed, gLed);
      Serial.println(gLed);
    }
    t = 0;
    break;case 'B':
    {
      bLed = map(t, 0, 100, 0, 255);
      analogWrite(blueLed, bLed);
      Serial.println(bLed);
    }
    t = 0;
    break;
   }
  }
}

Arduino 中的主循环等到串行数据可用,将数据作为字符向量 (myvalue) 存储在接口中,然后通过开关执行。特别是,开关将变量值与每个情况中指定的值进行比较。当发现一个事例的值与变量的值匹配时,就执行代码。

比如说,我们假设从 RStudio 发送的字符向量是 94R44G22B。第一个匹配的大小写是大小写“0”…“9”:通过减去零值字符将其转换为整数。

t ,代表 LED 在 0–100%范围内的亮度,首先初始化为 0。要读取的第一个值将是 9。因此,t 的值变成:

t = 0 * 10 + ('9' — '0')
t = 9

第二个值是 4,与第一种情况匹配。t 的新值变成:

t = 9 * 10 + ('4' — '0')
t = 94

读取的下一个值是与大小写“R”匹配的字母“R”。在这种情况下,t = 94 的值被重新分配为 0-255 范围内的模拟值,可用于 analogWrite() 功能。

如果您想知道为什么有必要重新分配传递给 analogWrite()函数的值,那是因为它是直接传递的。如果您只想闪烁并执行 LED 开启和关闭,您只需发送高电平(5v)或低电平(0v)。但是,如果您想产生不同于 0v 或 5v 的电压来改变 LED 的亮度,该怎么办呢?嗯,你不能,除非你用的是数模转换器(DAC)集成电路。

然而,使用一种叫做“脉宽调制”(PWM) 的技巧,你可以非常接近产生模拟输出值。每个 Arduino 上的选定引脚可以使用 analogWrite() 函数来生成 PWM 信号,当与某些外设一起使用时,该信号可以模拟纯模拟信号。这些针脚在卡片上标有~。在 Arduino UNO 上,引脚 3、5、6、9、10 和 11 是 PWM 引脚。

PWM 输出的值为 8 位。换句话说,你可以写从 0 到⁸-1,或者从 0 到 255 的值。对于我们的 LED 电路,将输出映射到 255 将产生全亮度,0 将导致 LED 关闭。,亮度在这两个值之间变化。

回到开关,在“R”的情况下,一旦一个模拟值被写入 LED,一个指令随之而来: Serial.println(rLed) 。这是 Arduino 告诉您将该值写入串行端口的方式。在这之后,t 的值被设置回 0,并且在随后的情况下执行随后的输入字符。

所有这些都说了,也做了,现在您可以返回 RStudio,运行您到目前为止的脚本,并观察 led 的行为。哦,是的,魔法!

读取 R 中的映射值

现在回到 R 问题,你可以通过 read.serialConnection() 读取 Arduino 发送给串口连接的映射值。

# READ MAPPED DATA SENT FROM MY ARDUINOdataFromArduino <- tibble(
  capture.output(cat(read.serialConnection(myArduino,n=0)))
)# SELECT FIRST NINE ROWS, ASSIGN VALUES TO THEIR LEDS AND RENAME FIRST COLUMNdataFromArduino %>% 
  slice_head(n = 9)

控制台输出,从 Arduino 发送的数据

现在您已经在 home️重新分配了数据!有趣的是read . serial connection()一次读取整个缓冲区。此外,数据具有长格式,因为读取是每行进行的。

现在您需要操作包含在 dataFromArduino 中的数据。

# ASSIGN VALUES TO LEDS AND CHANGE COLUMN NAMEdataFromArduino %<>% 
  tibble(ledNames = rep_along(seq_len(nrow(dataFromArduino)), 
                         c('rMapped','gMapped','bMapped'))) %>%
  rename("ledVal" = 1) %>%
  group_by(ledNames) %>%

   # ADD IDENTIFIERS REQUIRED BY PIVOT_WIDER FUNCTION AND CREATE NEW COLUMNS WITH 'LEDVAL' VALUES

  mutate(row = row_number()) %>%
  pivot_wider(names_from = ledNames, values_from = ledVal) %>%

  # DROPPING 'ROW' COLUMN AND CONVERT ALL COLUMNS TO DATA TYPE INTEGER 

  select(-row) %>%
  mutate_all(as.integer)dataFromArduino %>% 
  slice_head(n = 10)

您将能够在控制台上观察映射的数据。

控制台中的输出,映射数据

显示从 RStudio 发送到 Arduino 串行端口的 led 的初始值以及发送回的映射值的数据集,可以更好地进行交流。

# MERGE THE TWO DATA SETS,  DROP NON NUMERICAL CHARACTERS (R,G,B), AND REORDER COLUMNScombinedData <- as_tibble(cbind(arduinoInput, dataFromArduino)) %>%
  mutate(across(where(is.character), ~parse_number(.x)), across(where(is.double), as.integer)) %>% 
  select(c(1, 4, 2, 5, 3, 6))combinedData %>%
  slice_head(n = 10)

现在,您将能够在控制台中看到一个包含组合数据的数据集。

控制台输出,组合数据

最后一步:伺服

到目前为止,您已经将数据从 RStudio 发送到 Arduino,重新映射它,打开一些 led,并将重新映射的数据发送到 RStudio。现在,您将从接收到的重新分配值(0–255)创建一个新的数据集,添加一个终止字符,并将这些值写入 Arduino 串行端口。

# CREATING NEW DATA SET THAT SELECTS VALUES IN ORDER: MAXIMUM OF RECEIVED LED VALUES, THEN MINIMUM, AND SO IS REPEATEDrowMin <- tibble(inputMin = dataFromArduino %>% apply(1,min)) %>%

  # SELECT EVEN ROWS

  filter(row_number() %% 2 == 0)servoInput <- tibble(servoIn = dataFromArduino %>% 
                       apply(1,max))# REPLACE EVEN ROWS WITH A MINIMUM VALUE, AND APPENDING A TERMINATING CHARACTERservoInput[c(1:n)[c(F,T)],] <- rowMinservoInput %<>% 
  mutate(servoIn = servoIn %>% 
           paste('S', sep = ''))

您将在串行接口中写入这些值。

close(myArduino)
open(myArduino)Sys.sleep(1)for (r in seq_len(n)){
  Sys.sleep(1)
  write.serialConnection(myArduino, paste(servoInput[r,], collapse = ''))
}

再次暂停!让我们去 Arduino IDE 并完成伺服

是时候在 Arduino IDE 中完成你的草图了。Arduino 程序的主循环一直等到串行数据可用,提取整数值,将 0–255 范围内的值重新分配给伺服角度 0–179,并将该值写入伺服。然后映射的角度值打印在串行接口上。将粗体突出显示的部分添加到您的草图中,对应于伺服系统,并将更新的草图重新上传到您的 Arduino。

**# include <Servo.h>**// SETTING SERVO AND RGB LEDS 

int rLed = 0;
int gLed = 0;
int bLed = 0;
**int serv = 0;**int redLed = 6; // RED LED ON PIN 6
int greenLed = 5; // GREEN LED ON PIN 5
int blueLed = 3; // BLUE LED ON PIN 3
**int theServo = 9; // SERVO ON PIN 9****Servo myServo;**void setup() {
  Serial.begin(9600);  

  // SETTING PINS AS OUTPUT

  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
  pinMode(blueLed, OUTPUT);**// ATTACHING SERVO OBJECT**

 **myServo.attach(theServo);** }void loop() {
  if (Serial.available()){

   // MAKING VARIABLE VISIBLE TO ONLY 1 FUNCTION
   // CALL AND PRESERVE THEIR VALUE

   static int t = 0;

   char myvalue = Serial.read();switch(myvalue){

    // MYVALUE IS A a VARIABLE WHOSE VALUE TO COMPARE WITH VARIOUS CASES

    case '0'...'9':
      t = t * 10 + myvalue - '0';
      break;   

    case 'R':
    {
      rLed = map(t, 0, 100, 0, 255);
      analogWrite(redLed, rLed);
      Serial.println(rLed);  
    }
    t = 0;
    break;

    case 'G':
    {
      gLed = map(t, 0, 100, 0, 255);
      analogWrite(greenLed, gLed);
      Serial.println(gLed);
    }
    t = 0;
    break;case 'B':
    {
      bLed = map(t, 0, 100, 0, 255);
      analogWrite(blueLed, bLed);
      Serial.println(bLed);
    }
    t = 0;
    break;**case 'S':
    {

      // MAPPING ANALOGUE LED VALUE TO ANGLE FROM 0 TO 180 DEGREES

      serv = map(t, 0, 255, 0, 179);
      Serial.println(serv);
      delay(5);
      myServo.write (serv);
      delay(150);
    }
    t = 0;
    break;**
   }
  }
}

完成了这次更新,现在你可以回到 RStudio,运行脚本到目前为止,并观察伺服的行为。哦,对了,再来一次魔法!

R 中的伺服数据

现在,回到 RStudio,你可以得到 Arduino 给你的东西,并在你这样做的时候进行数据辩论。

# READ MAPPED ANGLES SENT FROM MY ARDUINO, RENAME FIRST COLUMNangleFromServo <- tibble(
  capture.output(cat(read.serialConnection(myArduino,n=0)))) %>%
  rename("servoAnglesMapped" = 1) %>% 
  mutate_all(as.integer)# SELECT FIRST TEN ROWSangleFromServo %>% 
  slice_head(n = 10)

您将能够在控制台上观察映射的数据。

控制台输出,映射伺服数据

您现在还可以观察您发送的内容与您接收的内容,合并两个数据集。

# WHAT WE SENT VS WHAT WE RECEIVED. MERGE THE TWO DATA SETS AND DROP NON NUMERIC CHARACTER 'S'combinedAngles <- as_tibble(
  cbind(servoInput, angleFromServo)) %>%
  mutate(across(where(is.character), ~parse_number(.x)),
         across(where(is.double), as.integer))combinedAngles %>%
  slice_head(n = 10)

控制台中的输出,从伺服系统发送的数据与接收的数据

servoIn 列显示我们发送给 Arduino 的数据,而 servoAnglesMapped 表示 Arduino 写入伺服并返回给我们的数据。

数据可视化

如果这还不够,您现在可以用数据可视化来结束,例如显示伺服系统在写入角度数据的每个实例中产生的变化。

# PLOT VARIATION OF SERVO ANGLEtheme_set(theme_light())myPlot <- angleFromServo %>%
  ggplot(mapping = aes(x = 1:nrow(angleFromServo), y = servoAnglesMapped)) +
  geom_line() +
  geom_smooth(se = F) +
  labs(x = "Count", y = "Servo angle",  title = "Servo angle variation at each count instance")+
  theme(plot.title = element_text(hjust = 0.5))ggplotly(myPlot)

结果,您将在 RStudio 查看器中看到如下图。

每次计数时的伺服角度变化图

在本文中,您演示了 RStudio 和 Arduino 之间的双向数据流。在每一个实例中,你发送到 Arduino 的数据被转换,触发一个外设,然后被重复。然后,您获得的数据经过一些修复,以正确的格式放置,以便 Arduino 在后续操作中执行。玩数据和物联网很有意思吧?

感谢您的阅读。我希望这已经让你熟悉了 Arduino 和 R,并激发了你探索这两个美人能做的惊人事情的真正兴趣。

我分享一下与【https://rpubs.com/cosmoduende/arduino-r】一起生成的剧情,更有美感一点:

在这里你可以找到完整的代码,包括用 R 编程的部分和 Arduino 草图:https://github.com/cosmoduende/r-arduino

感谢你坚持到最后,祝你分析非常愉快,可以把一切都付诸实践,对结果感到惊讶,和我一样开心!

Jupyter 笔记本中可互操作的 Python 和 SQL

原文:https://towardsdatascience.com/interoperable-python-and-sql-in-jupyter-notebooks-86245e711352?source=collection_archive---------4-----------------------

在 Pandas、Spark 和 Dask 上使用 SQL

先看 Jupyter 的 FugueSQL

注意:大部分代码片段都是图片,因为这是保持 SQL 语法突出显示的唯一方法。一个交互代码的例子,看看这个 Kaggle 笔记本

动机

FugueSQL 的目标是为数据专业人员提供一个增强的 SQL 界面(和体验),以便用类似 SQL 的语言执行端到端的数据计算工作流。借助 FugueSQL,SQL 用户可以在 Python 代码和 Jupyter 笔记本内的数据帧上执行完整的提取、转换、加载(ETL)工作流。SQL 被解析并映射到相应的 Pandas、Spark 或 Dask 代码。

这使得大量 SQL 用户能够利用 Spark 和 Dask 的能力,同时使用他们选择的语言来表达逻辑。此外,还添加了分布式计算关键字,如PREPARTITIONPERSIST,以便扩展标准 SQL 之外的功能。

在本文中,我们将介绍基本的 FugueSQL 特性,以及如何通过指定执行引擎在 Spark 或 Dask 上使用它。

对 ANSI SQL 的增强

在上面的 GIF 中看到的第一个变化是LOADSAVE关键词。除此之外,还有其他一些增强功能,提供了更友好的语法。用户还可以在 FugueSQL 中使用 Python 函数,创建一个强大的组合。

通过使用%%fsql单元格魔术,FugueSQL 用户可以在笔记本上拥有 SQL 单元格(后面会有更多的例子)。这也在 Jupyter 笔记本中提供了语法高亮。虽然这里没有演示,但是这些 SQL 单元可以在 Python 代码中与fsql()函数一起使用。

变量赋值

数据帧可以分配给变量。这类似于 SQL 临时表或公用表表达式(CTE)。虽然本教程中没有显示,但是这些数据帧也可以从 SQL 单元中取出,并在 Python 单元中使用。下面的例子显示了来自修改df的两个新数据帧。df是通过在 Python 单元中使用 Pandas 创建的(这是与第一个图像相同的 df)。两个新的数据帧连接在一起,创建一个名为final的数据帧。

数据帧的变量赋值

金贾模板

FugueSQL 可以通过 Jinja 模板与 Python 变量进行交互。这允许 Python 逻辑改变类似于 SQL 中的参数的 SQL 查询。

Python 函数

FugueSQL 还支持在 SQL 代码块中使用 Python 函数。在下面的例子中,我们使用seaborn来绘制数据帧的两列。我们使用 SQL 中的关键字OUTPUT调用该函数。

与 ipython-sql 的比较

神游标志

FugueSQL 旨在对已经加载到内存中的数据进行操作(尽管有一些方法可以使用 FugueSQL 从存储器中引入数据)。有一个名为 ipython-sql 的项目提供了%%sql单元格魔术命令。该命令旨在使用 SQL 将数据从数据库加载到 Python 环境中。

FugueSQL 的保证是,相同的 SQL 代码将在 Pandas、Spark 和 Dask 上工作,无需任何代码更改。FugueSQL 的重点是内存计算,而不是从数据库加载数据。

使用 Spark 和 Dask 的分布式计算

随着我们处理的数据量不断增加,Spark 和 Dask 等分布式计算引擎正被数据团队越来越广泛地采用。允许用户在相同的代码中使用这些更高性能的引擎。

在下面的代码片段中,我们将单元格魔术从%%fsql改为%%fsql spark,现在 SQL 代码将在 Spark 执行引擎上运行。类似地,%%fsql dask将在 Dask 执行引擎上运行 SQL 代码。

从迁移到分布式计算环境中获益的一个常见操作是获取每个组的中间值。在这个例子中,我们将展示PREPARTITION关键字以及如何对每个数据分区应用函数。

首先,我们定义一个 Python 函数,它接收一个数据帧并输出user_id和中位数measurement。该功能一次只能对一个user_id进行操作。即使在熊猫里定义了函数,在 Spark 和 Dask 上也能起作用。

熊猫的简单中值函数

然后,我们可以使用PREPARTITION关键字通过user_id对数据进行分区,并应用get_median函数。

预分割和火花以获得中间值

在这个例子中,我们得到了每个用户的中间值。随着数据变大,并行化将带来更多好处。在我们拥有的一个笔记本的例子中,Pandas 引擎的这个操作花费了大约 520 秒。对于 3.2 亿行的数据集,使用 Spark 引擎(在 4 个内核上并行化)需要大约 70 秒。

执行时间的差异是意料之中的。当数据变得太大而无法有效处理时,FugueSQL 允许 SQL 用户将工作流扩展到 Spark 和 Dask。

另一个常见的用例是 Dask 处理内存溢出和向磁盘写入数据。这意味着用户可以在遇到内存不足问题之前处理更多数据。

结论和更多示例

在本文中,我们探索了 FugueSQL 的基本特性,这些特性允许用户通过 Jupyter notebook 中的 SQL 单元格在 Pandas、Spark 和 Dask 数据帧上工作。

Fugue 将逻辑和执行解耦,使得用户可以在运行时轻松指定执行引擎。这使得大量 SQL 用户能够独立于计算框架来表达他们的逻辑。当情况需要时,他们可以轻松地将工作流迁移到 Spark 或 Dask。

有很多细节和功能无法在一篇博文中涵盖。有关端到端的示例,请访问我们为 Thinkful data analyst bootcamp 学生准备的 Kaggle 笔记本

笔记本中的设置

Fugue(和 FugueSQL)可以通过 PyPI 获得。它们可以使用 pip 安装(Dask 和 Spark 的安装是分开的)。

pip install fugue

在笔记本内部,运行setup功能后可以使用 FugueSQL 细胞魔法%%fsql。这也为 SQL 命令提供了语法突出显示。

from fugue_notebook import setup
setup()

联系我们

如果你对使用 FugueSQL 感兴趣,想给我们反馈,或者有任何问题,我们很乐意在 Slack 上聊天!我们还为对在数据工作流中应用 FugueSQL(或 Fugue)感兴趣的数据团队举办研讨会。

项目回购

松弛通道

FugueSQL 只是更广泛的河豚生态系统的一部分。Fugue 是一个抽象层,它允许用户用原生 Python 编写代码,然后在 Pandas、Spark 或 Dask 上执行代码,而无需在运行时更改代码。更多信息可以在上面的回购中找到。

星际预报

原文:https://towardsdatascience.com/interplanetary-forecasts-17b3fd05afc2?source=collection_archive---------33-----------------------

探测火星探测器好奇号的季节性天气模式

尼古拉斯·洛沃斯在 Unsplash 上的照片

自从人类仰望并记录移动的天空以来,这颗红色星球就充满了人类的想象力和神话故事。随着我们用来观察天空和太阳系中其他行星的眼睛变得越来越先进,一些起源可以追溯到我们看不到的更远的历史,而许多起源则更近。

在过去的几十年里,人类甚至让机器带着一系列相机和其他传感器降落在我们遥远的邻居身上,以收集信息并将其传回地球,以便我们能够更好地了解战神。我们最近送上火星的机器之一是“好奇号”。今天,我们要看看好奇号是否能告诉我们任何关于火星上天气模式的故事。

机器类的一大飞跃

好奇号是一辆汽车大小的漫游车,旨在探索盖尔陨石坑。好奇号于 2011 年 11 月从卡纳维拉尔角发射,9 个月后登陆火星,包含许多不同的科学仪器,重点是火星气候和地质。我们将着眼于 REMS 数据包的数据,探索当地天气的季节性变化。

火星车环境监测站,简称 REMS,包含的仪器旨在提供火星车周围气象条件的每日和季度报告。在 6 年的时间里,收集了最高和最低温度以及气压的数据。在这篇文章中,我们将看看通过分析这些数据,我们可以发现什么样的年度天气模式。

火星年

当我们从火星表面的漫游者上观察每年的天气模式时,它有助于对火星年有一个简要的概述。在地球上,我们的一年有 365 天多一点,分为 12 个月。火星也有 12 个月,但每个月都稍长一些,因为火星年大约是 687 个地球日(24 小时)。这 12 个月是通过测量太阳经度或火星-太阳角来计算的,火星-太阳角是从北半球测量的太阳到地球的角度。这种测量被称为 Ls。

理解 Ls 测量是很重要的,因为我们将把 Ls 作为一个指标来看,即数据是从年周期的哪里收集的,而不是地球日期/时间。Ls 变量给了我们一个很好的起始位置,0,并一直计数到360度,以指示我们的红色邻居在他们绕太阳旅行中的位置。作为下图中的一个例子,我们看到在 6 年的时间里,我们的 Ls 变量在 0 到 360 的范围内变化了 3 次,这是我们在大约 6 年的时间里,在不到两年的轨道上所预期的。

作者图片

上面我们可以看到,在将近 2000 sols 的过程中,或者说大约 6 年的时间里,我们看到我们的 ls 测量周期几乎是 360 度的 3 倍。这告诉我们,我们在数据中看到的任何年度天气模式,应该相当于围绕太阳的大约 3 个完整的轨道周期。

让我们看看一些数据,看看我们需要分析什么:

作者图片

你可能注意到的第一件事是,我们丢失了一些风速数据,更深入的分析表明,大气不透明度几乎全是晴天,或者不包含任何数据。这并不出人意料,因为虽然火星可能有季节性天气,但它并不以雷暴闻名。(然而,沙尘暴是另一回事)。这给我们留下了温度和压力数据。快速浏览一下我们记录的最高温度数据,会发现以下情况:

作者图片

我们也可以在上面的最高温度图中看到同样的 3 年模式。这个图表被我们的最小二乘测量着色,这样我们就可以看到火星在它的轨道上与温度读数相比的位置。你可能记得一个火星年大约是 687 天,这大致是我们在图表上看到的两个峰值之间的 sol 数,也是 ls 测量中两次转换之间的时间。

我们已经可以看到温度数据存在季节性波动,至少在好奇号读取数据的盖尔陨石坑是如此,但上面的图表可能很难预测任何给定年份特定月份的温度。下面我们将看看 12 个月中每个月的平均温度,让我们知道如果我们去拜访好奇号,不管我们到达的月份是哪个月,我们可能会遇到什么样的温度。

作者图片

正如我们所看到的,温度波动几乎是我们在地球上任何给定年份都会预料到的,至少在我们的北半球,最冷的月份是火星年的头几个月,或者在北分日之后,最热的月份是在南分日期间。在火星上很难用月份来测量时间,因为那里的月份长度变化比这里大得多。最短的一个月约 46 Sols,最长的一个月约 67 Sols。有人提到,好奇号降落在位于火星赤道上的盖尔陨石坑,因此我们可以预计这些温度比纬度更北或更南的地方要高得多。

压力低到你能感觉到

如果火星上的低温不足以阻止游客,那么极低的气压应该可以做到这一点。地球上的平均气压略高于 1000 毫巴,而火星上的平均气压约为 6-7 毫巴。这低于我们自身压力的 1%,这意味着任何有机游客都需要做好准备,因为暴露在这样的压力下会…不愉快。

好奇号上的 REMS 包一直在测量以帕斯卡为单位的气压,当我们观察好奇号停留期间绘制的气压时,一些有趣的事情凸显出来:

作者图片

真正有趣的是,我们可以看到我们的 3 火星年模式出现在我们的压力数据中。这是值得注意的,因为地球上的气压没有季节变化。火星上正在发生的事情是,随着天气变冷,天气冷到足以让二氧化碳从空气中冻结出来,导致地球周围的气压下降 30%之多!

你可能会注意到图表的双峰部分,在那里气压开始下降,只是再次上升,然后一直下降。虽然我无法证实这一点,但查看这些压力下降时的 Ls 测量结果,火星轨道的偏心率比地球轨道更接近椭圆形,这似乎导致了这种微小的季节性变化。

如果我们看一下每个月的平均压力,我们可以看到更详细的情况:

作者图片

如果我们将此与显示火星轨道的文章顶部的图像进行比较,我们可以看到,随着压力在一年的第二个月下降,火星正在向其轨道的远日点部分前进,或离太阳最远的位置,随着行星向其近日点位置移动,气压再次上升,然后继续重新开始这一过程。

不适宜居住的环境

简单浏览了一下好奇号火星车的天气数据后,我认为很明显火星上的天气有季节性变化。仅仅是好奇号所在的赤道上的温度波动,它们就从夏天的冰冻到冬天的致命。

除了寒冷的气温,令每个年轻的梦想家失望的是,由于气压极低,这不是一个对血肉生物友好的环境。气温的年最高值刚刚达到正数字,极低的气压意味着任何游客都必须穿上全套防护服,不管那天阳光多么明媚。

然而,任何运动中的系统都是可以修改的系统,也许有一天,随着足够的创造力和地形形成方面的进步,我们的人类后代将在火星的夜空下自由行走,仰望并梦想着来自太阳的第三块岩石。

原载于https://jeremyspradlin . github . io

内插纽约市自行车共享数据以发现再平衡运动

原文:https://towardsdatascience.com/interpolating-nyc-bike-share-data-to-discover-rebalancing-movements-6cf8a80eb902?source=collection_archive---------15-----------------------

使用 Pandas concat 重构花旗自行车出行数据

为了确保在需要时有自行车(和码头)可用,像大多数自行车共享系统一样,重新平衡或将自行车从过多的地方转移到需要的地方。Citi Bike 没有披露自行车何时何地被移动的数据,但事实证明这些移动是可以被发现的。

几乎空无一人的花旗自行车站——作者照片

本文是对花旗自行车提供的自行车份额数据的一系列探索的一部分。如果你觉得这篇文章很有趣,你可能也想看看:

探索纽约市自行车共享数据 —介绍数据准备和分析以及如何开始使用所使用的工具:Jupyter、Python、Pandas 和 Seaborn。

使用 NYC Bike Share 数据进行反向地理编码 —这是一个关于如何增加 Citi Bike 提供的区、社区和邮政编码数据的教程。

探索疫情对纽约市自行车共享使用的影响 —查看两年的数据以及在此期间骑行人数的变化。

下载花旗自行车旅行数据

Citi Bike 提供 tripdata 文件,这样任何人都可以分析该系统是如何使用的。花旗自行车系统数据页面描述了所提供的信息。每个文件包含一个月的数据;每条记录代表一次旅行。

对于这篇文章,我使用的是 2020 年 9 月的 tripdata 文件。在疫情最初几个月的下降之后,使用率已经恢复,这是迄今为止最繁忙的一个月。

在 Windows 上,使用上面的链接找到并下载纽约 9 月份的 tripdata 文件,然后将其放到一个bikeshare目录中。

在 Linux 上,从命令提示符下创建一个bikeshare目录,下载 tripdata 文件,将其解压缩,然后删除 zip 文件。

mkdir bikeshare && cd bikeshare 
wget [https://s3.amazonaws.com/tripdata/202009-citibike-tripdata.csv.zip](https://s3.amazonaws.com/tripdata/202003-citibike-tripdata.csv.zip)
unzip 202009-citibike-tripdata.csv.zip
rm 2020009-citibike-tripdata.csv.zip

导入库和数据

启动 Jupyter,从浏览器窗口在你的bikeshare目录下创建一个新的笔记本。本文中使用的带有 Python 代码的 Jupyter 笔记本在 GitHub 上的名称是 rebalancing.ipynb

导入常用库:用于分析的 Pandas 和用于图表的 Seaborn

import pandas as pd
from pandas import to_datetime
import seaborn as sns
import matplotlib.pyplot as plt

将花旗自行车旅行数据文件读入熊猫数据帧。对于这种分析,我们只需要开始和结束站 ID 和时间。

df = pd.read_csv('~/bikeshare/202009-citibike-tripdata.csv',\
     usecols=['starttime','start station id',\
              'stoptime','end station id','bikeid'],\
     parse_dates=['starttime','stoptime'])
df.info()

我看到 9 月份有将近 200 万人次。

所选列的 Tripdata 信息

幽灵骑士

Citi Bike 是一个传统系统,用户从一个站点取车,然后在另一个站点下车。

当分析行程数据文件时,如果我创建一个新的数据帧并按bikeidstarttime排序,我可以跟踪每辆自行车在系统中从一个站点到另一个站点的运动。

dfbike=df.sort_values(by=['bikeid','starttime'])
dfbike.head(10)

现在,我可以在一个月内跟踪自行车的行程。一次乘坐的end station id(几乎)总是下一次乘坐的start station id

按 bikeid 和开始时间排序的行程-按作者排序的图片

如果不一样,那么这辆自行车(不知何故)在两次骑行之间从一个站移动到了另一个站。

虽然我可以通过循环遍历数据帧并比较每次旅行和下一次旅行来找到这些“幽灵之旅”,但有近 200 万次旅行需要一段时间。

更好的方法是利用 Panda 的矢量运算,创建一个包含成对游乐设施的数据框架。

为此,我将创建一个带有单个虚拟记录的offset数据帧:

offset = pd.DataFrame({'starttime': pd.to_datetime('2010-09-01'),\
  'start station id':0,'stoptime': pd.to_datetime('2010-09-01'),\
  'end station id':0,'bikeid':0},index=[0])

然后创建两个新的数据帧,一个先使用偏移量,一个最后使用偏移量:

dfbike1 = pd.concat([offset,dfbike]).reset_index(drop=True)
dfbike2 = pd.concat([dfbike,offset]).reset_index(drop=True)

使用axis=1并排组合这两个数据帧

dfbike=pd.concat ([dfbike1[['bikeid','stoptime','end station id']]\
            ,dfbike2[['bikeid','starttime','start station id']] ],\
             axis=1 )
dfbike.head()

这里每条记录代表一辆自行车停靠的时间段。我可以看到一趟车在 388 站结束,下一趟车从同一个站开始。然后它停靠在 480 号站,依此类推。

作者图片

但是当我追踪这辆自行车的行程时,我发现有一天这辆自行车被移动了!它前一天停靠在 3906 站,第二天在 4123 站被取走。

作者图片

为了检测这些运动,我想创建一个这些“幽灵游乐设施”的数据框架,就好像它们是真实的游乐设施一样。这需要交换起止名称。然后我选择那些bikeid相同但station id值不同的记录。

dfbike.columns=['bikeid1','starttime','start station id',\
                'bikeid2','stoptime','end station id']
dfrebal = dfbike[['starttime','start station id',\
                  'stoptime','end station id']].\
           loc[(dfbike.bikeid1==dfbike.bikeid2) & \
          (dfbike['start station id'] != dfbike['end station id']) ]
dfrebal.reset_index(drop=True, inplace=True)
dfrebal

2020 年 9 月的再平衡运动—作者图片

这个数据帧的每一行都代表一辆自行车,出于重新平衡、维修或其他目的,这辆自行车不知何故从一个站点移动到了另一个站点。

现在我有了这个数据框架,我将把它保存为一个拼花文件,这样我就可以在我的下一篇文章中使用它,根据纽约市自行车共享数据估计自行车共享可用性。

这需要 pyarrow(安装者:conda install -c conda-forge pyarrow)

dfrebal.to_parquet('202009-citibike-reblance.parquet')

请注意,上面的报告显示,9 月份有近 4 万辆自行车被重新平衡。这个数字合理吗?

花旗自行车每月运营报告页面有每月运营报告的链接。对于 2020 年 9 月,它说:

九月份,花旗自行车员工重新平衡了总共 51,179 辆自行车…利用箱式卡车、货车、合同三轮车、铰接三轮车(“自行车列车”)、服务员和会员奖励(“自行车天使”)在全系统范围内重新分配自行车。

因此,尽管官方统计的超过 51179 人比我发现的要高,但这也包括“自行车天使”的骑行,他们是为了重新平衡而被激励骑自行车的成员。这些游乐设施将在 tripdata 文件中显示为“常规”游乐设施。我会说我的衍生计数足够接近政府工作

哪些站得到重新平衡?

现在我知道有多少自行车被重新平衡,我想知道哪些站有最多的重新平衡。

站名比数字站名更有意义,所以我将返回到 tripdata 文件并创建一个站名和站名的表。

dfstations = \
  pd.read_csv('~/bikeshare/202009-citibike-tripdata.csv',\
  usecols=['start station id','start station name']).\
  drop_duplicates()                
dfstations.columns=['station id','station name']
dfstations.set_index('station id',drop=True, inplace=True)

我将使用熊猫merge来获取起点和终点站名。

dfrebal = pd.merge(dfrebal, dfstations[['station name']],\
     how = 'left', left_on='start station id', right_on='stationid')
dfrebal = pd.merge(dfrebal, dfstations[['station name']],\
     how = 'left', left_on='end station id', right_on='stationid')

并根据生成的默认值重命名列名。

dfrebal.rename(columns = 
        {'station name_x':'start station name',\
         'station name_y':'end station name'},\
          inplace = True)

创建两个系列,前 20 个站点都有自行车进出。

rebalin = dfrebal['end station name'].value_counts()[:20]
rebalout = dfrebal['start station name'].value_counts()[:20]

使用barplot显示前 20 个站点中从移出的自行车总数,同样也显示移入的自行车总数。

plt.figure(figsize=(10,8))
plt.title('Citi Bike Rebalancing - September 2020\
 - Top 20 Stations bikes moved OUT'  ) 
plt.xlabel('Count of bikes moved') 
sns.barplot( x=rebalout.values, y=rebalout.index,  orient="h" ) ;

搬出的自行车数量-图片由作者提供

移入的自行车数量-图片由作者提供

在查看了按站点移动的自行车数量后,我意识到按街区查看数量会更有趣。Citi Bike 不按街区识别站点,但正如我在之前的文章中描述的,使用 NYC Bike Share 数据进行反向地理编码可以使用所提供的纬度和经度来实现。有关创建这些图表的步骤,请参见 Jupyter 笔记本 rebalancing.ipynb

邻域计数-按作者分类的图像

邻域计数-按作者分类的图像

图表显示,自行车更经常从市中心的车站移出,主要是商业区;而自行车被转移到住宅区和市中心区的车站。

按一天中的时间重新平衡

再平衡何时发生?花旗自行车无法提供这些信息,也无法从 tripdata 文件中确定。我知道在自行车被移动之前自行车被丢弃的时间,以及在自行车被移动之后第一次被取走的时间,但是实际的移动可能发生在两者之间的任何时间,甚至相隔几天。因为这是我所有的数据,所以我将使用它。

首先添加与记录时间相对应的小时栏。

dfrebal['starthour'],dfrebal['endhour'] = \
    dfrebal.starttime.dt.hour, dfrebal.stoptime.dt.hour

要创建一个显示每小时进出的自行车数量的条形图,我可以使用countplot但是没有每小时重新平衡,所以图表缺少了条形。相反,我可以先进行计数,当没有运动时,计数为零。

这让我可以看到一个宽格式的计数,每个站一行,一天中每个小时一列。

pd.set_option('display.max_columns', 24)
dfrebal.value_counts(subset=['start station id', 'starthour'])\
        .unstack().astype('Int64').fillna(0).head(10)

这里有很多东西需要解释,所以我将把它们分解开来:

  • .value_counts(subset=['start station id', 'starthour'])通过start station idstarthour统计行程次数。
  • .unstack()starthour从行转到列。当一个小时没有乘坐时,填写NaN(不是一个数字)。
  • .astype('Int64')每当有NaN值时,Pandas 会将数据转换为float64,这不适用于计数。这将数据转换回整数格式Int64,缺失值表示为<NA>
  • .fillna(0)用零替换缺失值或<NA>值。
  • .head(10)显示前十行。

该语句生成一个类似于这样的内容广泛的报告,由start station idstarthour组成。

一小时内按站点显示的重新平衡计数的详细报告-按作者显示的图片

最后一步是使用stack()将数据转换回长格式,我将为进出车站的自行车做这件事。

将数据从一个系列转换为一个数据帧,并添加一个新列Movement来指示移动的方向(向内或向外),并将两个数据帧连接成一个数据帧,以便在一个图表中轻松显示两种类型的移动。

startcounts = \
    dfrebal.value_counts(subset=['start station id','starthour'])\
   .unstack().astype('Int64').fillna(0).stack()
startcounts=pd.DataFrame(startcounts).assign(Movement='Out')endcounts = \
    dfrebal.value)counts(subset=['end station id', 'endhour'])\
   .size().astype('Int64').unstack().fillna(0).stack()
endcounts=pd.DataFrame(endcounts).assign(Movement='In')rebalcounts=pd.concat([startcounts, endcounts])
rebalcounts.columns=['Bike Count','Movement']

为了创建多个站点的图表,我将生成图表的代码放入一个函数中。它需要两个数据帧stationrebaldfstations,并以一个站名作为参数。

def stationrebal (stationname):
    plt.figure(figsize=(12,5))
    if stationname not in list(dfstations['station name']):
        raise RuntimeError("Station name not found.")
    plt.suptitle('Citi Bike Rebalanancing - ' +  stationname   )         
    ax=sns.barplot(data=rebalcounts.loc[station], \
                x=list(rebalcounts.loc[station].index),\
                y="Bike Count", hue="Movement" ,\
                palette=["darkred", "darkgreen"], edgecolor = 'w')  
    ax.set(xlabel="Hour of Day", ylabel = "Count of bikes moved") ;

这是为重新平衡而拆除自行车最多的车站的图表:

搬出去的自行车顶站——作者图片

这个车站位于苏荷区的中间,这里既是住宅区又是零售区。图表显示,自行车大多是从这个车站移出的,上午有一些,下午有很多。

这是增加自行车最多的车站:

搬进来的自行车顶站—作者图片

在这个主要的居民区,图表显示自行车在早上被移入车站,下午较少。

结论

尽管 Citi Bike 不提供出于重新平衡和其他目的手动移动自行车的信息,但可以通过查看单辆自行车的移动以及它们在没有骑行的情况下位置发生变化的情况,从 tripdata 中获得这些信息。

这些信息总体上(按邻域)比单个站点更有意义。

通过查看自行车何时被带走,我们可以大致了解自行车何时在车站被重新平衡。

用排列特征重要性解释你的黑盒 ML 模型

原文:https://towardsdatascience.com/interpret-your-black-box-ml-model-with-permutation-feature-importance-fc2b2a14ca7c?source=collection_archive---------11-----------------------

为训练过估计器计算全局特征重要性

图片由来自 PixabayTayeb MEZAHDIA 提供

建模是数据科学模型开发管道的重要组成部分。它使用机器学习算法来拟合训练处理过的数据,以便对看不见的点进行预测。一些模型(如 Logistics Regression 和 k-NN)很容易表示,但大多数数据科学模型都是臭名昭著的黑盒模型,因为很难理解和解释任何预测的见解和原因。

机器学习模型的解释是指解释做出任何预测的原因。模型解释使得风险承担者和业务领导更容易理解有助于做出任何预测的因素。一些机器学习模型更容易解释,但对于其他算法,有各种技术和开源包来解释。一些软件包包括:

所有这些软件包都涉及到各种算法来解释算法。一种流行的模型解释算法是基于排列的特征重要性。在本文中,我们将讨论如何使用排列特征重要性来解释该模型,以及它如何优于标准的 scikit-learn 特征重要性函数。

什么是排列特征重要性?

排列特征重要性是一种模型检查/解释技术,可用于解释任何拟合的黑盒机器学习模型。它为训练有素的估计器计算数据集的全局要素重要性,并帮助数据科学家了解高重要性要素和低重要性要素。

置换特征重要性算法通过任何特定特征的变化来测量模型性能的变化。有两种使用置换技术计算特征重要性的算法:

方法 1:特征移除和再训练:

  1. 在训练数据集上拟合估计量并计算性能。
  2. 从训练数据中移除一个特征并重新计算性能。
  3. 测量步骤 1 和步骤 2 中模型性能的退化。
  4. 添加步骤 2 中删除的特征。
  5. 对所有特征重复步骤 2、3 和 4。

删除某个功能后出现的性能下降决定了该功能的重要性。这种技术是昂贵的,因为需要为具有 n 个特征的数据集训练 n 个估计量。

我们有另一种置换特征重要性可解释性技术,它对测试数据的特征值进行置换,并且只训练估计器。

方法 2:特征值重组:

  1. 在训练数据集上拟合估计量并计算性能。
  2. 使用步骤 1 中的拟合估计值来计算测试数据的性能。
  3. 从测试数据集中随机抽取特定特征的特征值。
  4. 使用步骤 1 中的拟合估计量来计算步骤 2 中的混洗测试数据集的性能。
  5. 根据步骤 2 和步骤 4 的结果计算性能下降。
  6. 恢复步骤 3 中执行的随机更改。
  7. 对数据集中的要素重复步骤 2、3、4 和 5。

(图片由作者提供),特征重排示例:平均半径

使用方法 2,通过测量测试数据的性能恶化来计算特征重要性。这种技术的成本相对较低,因为它只适合估计器一次,并对测试数据和混洗测试数据进行 n+1 次预测。我们看到性能大幅下降的特性可以被视为重要特性,而性能几乎没有变化的特性可以被视为不太重要的特性。

实施:

Scikit-learn 和 ELI5 库在一行 Python 代码中提供了置换特征重要性算法的实现。

数据集:sci kit-learn 库开源的乳腺癌数据集将用于执行排列特征重要性的演示。

scikit-learn 包中的 permutation_importance 可用于实现该算法。

(作者代码)

置换特征重要性算法在第 8 行实现。**n_repeats**参数代表置换特征的次数。

结果:

现在让我们比较随机森林分类器的排列特征重要性和基于杂质的特征重要性。scikit-learn 中随机森林分类器的实现带有基于杂质的特征重要性,该特征重要性是根据从训练数据集导出的统计数据计算的。

(图片由作者提供),基于杂质的技术和基于排列的技术之间的特征重要性图的比较

结论:

置换特征重要性是一种全局特征解释技术,可用于解释表格数据集中的任何拟合估计量。这项技术通过打乱测试数据的特征值来衡量性能的下降。这是一个非常方便的技术来解释任何黑盒估计器,并解释这个特性对于一个特定的模型是多么重要。

对于多共线数据集,排列特征重要性可能无法解释相关特征。阅读 scikit-learn 文档以了解在使用排列特征重要性解释模型时如何处理多重共线性的情况。

参考资料:

[1] Scikit-learn 文档:https://sci kit-learn . org/stable/modules/permutation _ importance . html # outline-of-the-permutation-importance-algorithm

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一小部分会员费,不需要你额外付费。

https://satyam-kumar.medium.com/membership

感谢您的阅读

可解释的 K-Means:聚类特征重要性

原文:https://towardsdatascience.com/interpretable-k-means-clusters-feature-importances-7e516eeb8d3c?source=collection_archive---------0-----------------------

模型可解释性

通过提取每个聚类最重要的特征来理解 K 均值聚类。

[图片由作者制作]聚类的特征重要性方法

M 机器学习模型要经过许多阶段才能被认为是生产就绪的。一个关键阶段是关键时刻,在这一时刻,模型获得了科学的许可;模型评估。许多评估指标被指定用于不同的目的和问题规范,但是没有一个是完美的。因此,当选择使用哪个评估指标最适合手头的问题并作为机器学习项目的功能决策诱导值时,数据科学家有一个巨大的负担。

然而,一些评估度量值可能看起来不直观,并且不能用外行的术语来解释,尤其是在评估使用内部索引的无监督聚类算法时(不存在诸如真实标签之类的外部信息)。虽然这些测量对比较基准有很大的好处,但是将它们与解释结合起来对于独立、直观的验证和与利益相关者更容易的结果交流是至关重要的。

直觉与内部验证指标

当涉及到内部验证指标时,数据科学家往往会在评估过程中失去一个焦点,这就是对模型性能及其解释的直观“人类”理解。举个反例来说明,监督分类评价指标如准确率精度召回对外行和专家都有非常直观的解释。例如:

  • 准确性 : “我们已经正确地对所有样本中的这个百分比的样本进行了分类。”
  • 精度 : “我们已经正确分类了所有预测阳性中的阳性百分比。”
  • 回想一下 : “我们已经正确分类了所有实际阳性中的阳性百分比。”

另一方面,内部验证指标,如广泛使用的轮廓系数卡林斯基-哈拉巴斯指数戴维斯-波尔丁指数和许多其他指标,通常是比较使用,而不是固有的和独立的性能评估。这些测量值可以分解为每个聚类的紧密程度(聚类数据点彼此之间的相似程度)、聚类的分离程度(每个聚类的数据点与其他聚类的数据点之间的差异程度),或者两者都有。但是,这些度量并不容易解释,也不容易与您正在解决的集群问题联系起来。

尽管这些方法非常有价值,但是当作为一名数据科学家试图了解您的模型有多好,或者试图将您的结果深入地传达给利益相关者(其中大多数内部验证指标都没有通过 ELI5(解释为 I 'm 5)测试)时,获得模型的解释以及内部评估指标是至关重要的。本文将关注最流行的无监督聚类算法之一;的 K-手段,并提出了两种可能的技术来提取最重要的特征,为每个集群。文章的提纲如下:

  1. K-表示商业价值
  2. K-Means 如何工作
  3. 解读技巧
  4. 实战应用

如果您已经知道 K-Means 是如何工作的,请跳到 解释技术 部分,或者想访问本文的知识库并直接使用代码,请访问K Means-feature-importance

k-表示商业价值

假设你正在经营一家拥有成千上万客户的企业,你想更多地了解你的客户,尽管你有多少客户。举例来说,你不可能研究每一位顾客,并专门为他们制定营销活动。然而,您知道每个客户可能具有不同的人口统计(例如,年龄)、地理(例如,地区)、心理(例如,消费习惯)和行为(例如,参与度)属性。将他们分成多个相似的组将简化从每个组最普遍的属性来理解他们是谁。解决这个问题最流行的算法,我相信你也猜到了!是 K-Means;“K”将指可能的客户细分/群体/集群的数量,“手段”可以被认为是 K 个群体中每个群体的中心(与其群体成员最相似)的虚构人物。

K-Means 如何工作

K-Means 是一种无监督聚类算法,它将相似的数据样本与不相似的数据样本分组到一个组中。准确地说,它的目标是最小化类内平方和(WCSS),从而最大化类间平方和(BCSS)。K-Means 算法有不同的实现和概念变体,但是出于本文的考虑,我们将重点关注最常见的方法,即 Lloyd's 算法(Naive K-Means),它遵循一种迭代方法来寻找次优解。在开始之前,我们将准备一个简单的数据集进行解释,并看看它是什么样子的。

“df”数据框架视图

我们需要使用 K-Means 将上述数据点聚类成 K 个组的步骤是:

步骤 1 —选择组/簇的初始数量(K)

质心代表每个聚类;分配给该聚类所有数据点的平均值。选择初始组数等同于选择初始质心数 k。我们可以决定K = 3并从数据集中随机选择 3 个不同的数据点作为初始质心(有更好的方法来选择每个质心的初始坐标)。

[图片由作者制作]第一簇的质心初始化

步骤 2-将数据点分配给聚类质心

我们必须将数据集中的每个数据点分配到最近的质心。我们将通过以下步骤使用最常见的距离度量作为“接近”的定义:

1.对于每个第j个聚类质心C_j,以及一个具有d维度的数据集的一个点p,使用下面的公式计算每个质心和所有数据点之间的欧几里德距离。(我对 *C_j = u_c_j (u = average) = Cluster Centroid* 的使用只是一种简化,因为我将列出的方程都在单个聚类级别中)。

2.为了最小化 WCSS,我们将每个数据点分配到其最近的质心(最相似/最小距离)。这将是 WCSS 最小化步骤的原因来自于一个聚类的 WCSS 的等式,其中p_m 个点被分配给聚类质心C_j,其中分配给聚类质心的点的距离越短,其 WCSS 越低。

[图片由作者制作]数据点分配给聚类的质心

步骤 3-更新聚类质心的位置

最后一步是更新聚类质心的位置,因为不同的数据点被分配给每个聚类。我们必须通过以下方式将每个质心移动到分配给它的所有数据点的平均值:

  1. 计算每个聚类数据点的平均值
  2. 将新的聚类质心设置为每个聚类的新平均值
  3. 重复 步骤 2步骤 3 直到聚类质心(新的均值)不变

利用sklearn.cluster.KMean;我们将得出以下结论,例如,您可以采用Sample 0Sample 1特征,计算它们的平均值,然后检查它是否等于Cluster Centroid D1Cluster Centroid D2:

下图显示了 K-Means 如何对数据集进行聚类,其中每个质心位于分配给它的点的平均值处:

[图片由作者制作] K-Means 聚类应用于' df '数据框特征 1 和 2

解释技术

方法 1: WCSS 最小化

免责声明:作者开发了这个方法。请不要犹豫引用任何参考文献,如果发现或批评的方法。

这种方法是对每个质心的次优位置的直接分析。因为 K-Means 的目标是最小化组内平方和,并且假设所使用的距离度量是欧几里德距离:我们可以通过找到最大绝对质心维度移动来找到负责每个组的最高 WCSS 量(每个数据点到其组质心的距离的平方和)最小化的维度。

使用上面相同的解释示例,我们可以从sklearn.cluster.KMean拟合模型访问cluster_centers_;最终的簇形心位置。然后显示特征名称(尺寸d):

绘制群集及其位置将产生以下结果:

[图片由作者制作]K-表示'测向'数据帧聚类以及质心位置

现在,让我们取每个质心,并按维度轴对其进行排序,如果有负值的要素,请记住取绝对值。

之后,我们可以使用排序的权重(质心在特征平面上移动的距离)获得第一个质心的维度,并将其映射到特征名称,这将为我们提供以下假设的特征重要性:

因为质心在两个维度上移动了相等的距离,所以这些特征将具有同等的重要性。让我们在第一个维度上轻推最后两个样本(属于cluster 0)并重复相同的过程,然后绘制新的质心

[图片由作者制作] K-Means 聚类在第一维度(特征 1)上微移后用于聚类 0

我们现在将再次应用相同的方法并提取特征重要性。请注意,聚类 0 在要素 1 上的移动比要素 2 多得多,因此对 WCSS 最小化有更大的影响。

方法 2:从无监督到有监督

这种方法是模型不可知的;不排斥 K-Means,在 K-Means 中,我们使用易于解释的分类器(如基于树的模型)将无监督聚类问题转换为一对一监督分类问题。完成此操作的步骤如下:

  1. 将每个群集标签更改为一对一对所有二进制标签
  2. 训练分类器以区分每个分类和所有其他分类
  3. 从模型中提取特征重要性(我们将使用sklearn.ensemble.RandomForestClassifier

[图片由作者制作]无监督聚类问题转化为一对所有监督分类问题的转换

在步骤 1 之后,让我们将cluster 0标签设置为1,并将所有其他集群标签设置为0:

我们已经把这个问题转化为一个二元分类问题。剩下的就是训练一个分类器,并使用其在scikit-learn中实现的feature_importances_方法来获得在所有聚类和目标聚类之间具有最大区分能力的特征。我们还需要将它们映射到按权重排序的特性名称。

一个重要的注意事项是,这种方法发现了两个集群之间的区别,并且根本不是目标集群所固有的。此外,还有许多其他复杂的方法可以从基于树的模型和模型不可知的方法中提取最重要的特征,您可以尝试一下。

现实生活应用

我选择将解释技术应用于 NLP 问题,因为我们可以很容易地将特征重要性(英语单词)联系起来,这可以被认为是一种基于组的关键字提取技术,其中我们的目标是使用 K-Means 将相似的文档聚集在一起,然后应用上述技术。我将使用的数据集可以在这里找到 Kaggle BBC-News ,这提出了一个分类问题。我们将首先排除 category 列(体育、商业、政治、娱乐和技术新闻文章),稍后将其用作概念验证。

新闻类别在数据集中的分布如下:

[图片由作者制作] BBC News train.csv 数据集类别分布

由于本文不是特定于 NLP(自然语言处理)的,所以我不会深入讨论任何与 NLP 相关的任务。因此,快速转向预处理文本以准备特征。下面的代码对单词和过滤标记(单词和数字)进行规范化,这些单词和标记不具有区分能力,因此是多余的。然后计算整个数据集中提到最高的单词并绘制它们(你可以跳过代码):

[图片由作者制作 BBC 新闻数据集中提及率最高的词

使用 TF-IDF(文本表示技术),我们可以将分类变量(单词)转换成数字表示。我们不需要在这里缩放特征,因为 TF-IDF 在它的等式内归一化特征,并且它的输出应该以它的原始形式使用。如果对具有不同单位或范围的要素的数据集应用 K 均值,并且这种差异与问题无关,请记住缩放要素。

最后,现在是我们最在意的一步;我将上面的方法包装在一个继承自sklearn.cluster.KMean的类中,除了添加了feature_importances_ 属性之外,可以以同样的方式使用。在初始化时,您必须为修改后的类的ordered_feature_names参数提供与fit方法中的X参数排序相同的特性。

您可以在这里找到代码k means-feature-importance并简单地在您最喜欢的 CLI 中克隆它,或者简单地通过访问存储库中的 Colab 示例来完成:

git clone [https://github.com/YousefGh/kmeans-feature-importance.git](https://github.com/YousefGh/kmeans-feature-importance.git)

然后使用k =新闻数据集类别的数量来运行修改后的 KMeans 类,以便我们稍后可以将结果与实际类别进行比较。

让我们检查 K-Means 是否产生了类似于新闻数据集中的类别分布的聚类分布。

[图片由作者制作]类别和 K 均值聚类分布

这是一个足够接近的类别分布相似性,让我们继续下去。不要忘记通过使用不同的内部验证索引来确保 K-Means 已经产生了准确的结果(我不会仔细检查它们,因为这超出了范围),并且您可能没有真正的标签,所以如果 K 在问题领域知识中是未知的,您将需要选择 K-Means 中的最佳 K。

继续解释,我们可以像这样访问第二个集群cluster 1feature_importances_(这个例子是针对 WCSS 最小化者的):

方法比较

我们将使用KMeanInterp类中的feature_importance_method参数比较 WCSS 最小化方法和无监督到有监督问题转换方法。流程如下所示:

  • 用于与独特颜色进行比较的绘图类别分布
  • feature_importance_method参数设置为wcss_min,并绘制特征重要度
  • feature_importance_method参数设置为unsup2sup并绘制特征重要性
  • 使用最重要的特征推断每个聚类的类别

[图片由作者制作] BBC News train.csv 数据集类别分布。下面将使用颜色进行比较

WCSS 最小化器

[图片由作者制作]对每个聚类使用 WCSS 极小值法的最重要特征,并直观地将每个聚类映射到实际数据集中可能的类别(每个图的右上角)

[图片由作者制作]最重要的特征使用 WCSS 最小化器方法对每个聚类进行分析,并直观地将每个聚类映射到实际数据集中可能的类别(右上角)

无监督到有监督

[图片由作者制作]对每个聚类使用非监督到监督方法的最重要特征,并直观地将每个聚类映射到实际数据集中可能的类别(每个图的右上角)

[图片由作者制作]对每个聚类使用非监督到监督方法的最重要特征,并直观地将每个聚类映射到实际数据集中可能的类别(右上角)

结论

当事实标签在开发阶段不可用时,聚类的可解释性变得至关重要。由于内部验证指标的性质,它不仅阻止了数据科学家对聚类有效性的直接评估,还妨碍了向利益相关者简单直观地解释聚类性能。我们提出了两种可能的方法,旨在通过提取基于聚类的特征重要性来解决这一问题,这使我们能够知道为什么 K-Means 算法选择了每个聚类。该方法将其自身扩展到利益相关者通信、简单直观的评估、NLP 中基于聚类的关键词提取以及通用特征选择技术。

本文笔记本, *KMeansInterp* 类,连同 Colab 上的直接用法示例,可在这里找到https://github.com/YousefGh/kmeans-feature-importance* 快乐演绎!*

参考文献:

  1. Y.刘,李,熊,高,吴,“内部聚类验证方法的理解”,2010 年 IEEE 数据挖掘国际会议,2010 年,第 911-916 页,doi: 10.1109/ICDM.2010.35。
  2. 惠普克里格尔。运行时评估的(黑色)艺术:我们是在比较算法还是实现?。已知信息系统 52,341–378(2017 年)。https://doi.org/10.1007/s10115-016-1004-2
  3. Ng,a .,,皮赫,C. (2021)。CS221。检索于 2021 年 7 月 18 日,来自 https://stanford.edu/~cpiech/cs221/handouts/kmeans.html
  4. 伊斯梅利,乌迈马&勒梅尔,文森特&科尼埃·霍斯,安托万。(2014).测量变量对聚类贡献的监督方法。159–166.10.1007/978–3–319–12637–1_20.
  5. 2.3。聚类-sci kit-learn 0 . 24 . 2 文档,2021

可解释的机器学习

原文:https://towardsdatascience.com/interpretable-machine-learning-45b467dbe1af?source=collection_archive---------22-----------------------

为什么以及如何让你的机器学习模型具有可解释性

来源:作者

机器学习的批评者表示,它创造了“黑箱”模型:可以产生有价值的输出,但人类可能无法理解的系统。

那是一种误解。机器学习可以被解释,这意味着我们可以建立人类理解和信任的模型。精心构建的机器学习模型是可以验证和理解的。这就是为什么我们可以在医药和金融等高度监管的领域使用它们。

什么是可解释的模型?

当人类很容易理解机器学习模型做出的决策时,我们就有了“可解释的模型”。简而言之,我们想知道是什么导致了一个特定的决定。如果我们能知道一个模型是如何做出决定的,那么这个模型就是可解释的。

例如,我们可以训练一个随机森林机器学习模型来预测特定乘客是否在 1912 年泰坦尼克号沉没时幸存。该模型使用乘客的所有属性——如机票等级、性别和年龄——来预测他们是否幸存。

现在让我们假设我们的随机森林模型预测某个特定乘客有 93%的生存机会。是怎么得出这个结论的?

随机森林模型可以很容易地由成百上千的“树”组成。这使得几乎不可能理解他们的推理。

但是,我们可以借用博弈论的方法,让每个个体决策都是可解释的

SHAP 图显示了模型如何使用每个乘客属性并达到 93%(或 0.93)的预测。在下图中,我们可以看到模型考虑的最重要的属性。

  • 乘客不在三等舱:生存机会大大增加;
  • 乘客是女性:生存机会增加更多;
  • 乘客不在头等舱:生还几率略有下降。

性别和阶级是预测泰坦尼克号乘客生存几率的模型中最重要的特征。来源:作者

通过将这种解释与我们从历史中了解到的情况结合起来,我们可以看到该模型的表现符合预期:持有一等舱或二等舱船票的乘客优先登上救生艇,妇女和儿童先于男子弃船。

相比之下,许多其他机器学习模型目前还无法解释随着机器学习越来越多地用于医学和法律,理解为什么一个模型会做出一个特定的决定是很重要的。

我们从可解释的机器学习中获得了什么?

可解释的模型帮助我们达到机器学习项目的许多共同目标:

  • 公平:如果我们确保我们的预测是公正的,我们就防止了对代表不足的群体的歧视。
  • 稳健性:我们需要确信模型在每种环境下都能工作,并且输入的小变化不会导致输出的大变化或意想不到的变化。
  • 隐私:如果我们了解一个模特使用的信息,我们就可以阻止她访问敏感信息。
  • 因果关系:我们需要知道模型只考虑因果关系,不挑选虚假的相关性;
  • 信任:如果人们理解我们的模型是如何做出决定的,他们会更容易信任它。

有些算法比其他算法更容易理解吗?

像回归和决策树这样的简单算法通常比像神经网络这样的复杂模型更容易理解。话虽如此,许多因素会影响模型的可解释性,因此很难一概而论。

对于非常大的数据集,更复杂的算法往往证明更准确,所以在可解释性和准确性之间可能会有一个权衡。

更精确的模型通常更难解释。来源:作者

可解释性范围

通过查看范围,我们有了另一种方法来比较模型的可解释性。我们可以问一个模型是全局可解释的还是局部可解释的:

  • 全局可解释性是理解完整的模型如何工作;
  • 本地可解释性是理解一个决策是如何达成的。

如果一个模型足够小,足够简单,人类可以完全理解,那么它就是全局可解释的。如果一个人能够追溯一个单一的决策,并理解模型是如何得出那个决策的,那么这个模型就是局部可解释的。来源:作者

如果我们理解一个模型中的每一条规则,那么这个模型就是全局可解释的。例如,帮助银行决定住房贷款审批的简单模型可以考虑:

  • 申请人的月薪,
  • 存款的大小,以及
  • 申请人的信用等级。

人类可以很容易地评估相同的数据并得出相同的结论,但是一个完全透明和全球可解释的模型可以节省时间。

相比之下,一个复杂得多的模型可以考虑成千上万的因素,比如申请人住在哪里,在哪里长大,他们家庭的债务历史,以及他们的日常购物习惯。如果模型做出了一个有问题的决定,也许可以找出为什么一个家庭贷款被拒绝。但是由于模型的复杂性,我们一般不会完全理解它是如何做出决定的。这是一个本地可解释的模型。

机器学习模型的可解释性与可解释性

全球 ML 社区交替使用“可解释性”和“可解释性”,并且对于如何定义这两个术语没有达成共识。

也就是说,我们可以认为可解释性比可解释性更容易理解。

如果我们能够从根本上理解一个机器学习模型是如何在特定决策中到达的,那么它就是可解释的

如果我们能够理解复杂模型中的特定节点如何在技术上影响输出,那么模型就是可解释的

如果一个模型的每个组成部分都是可以解释的,并且我们可以同时跟踪每个解释,那么这个模型就是可解释的。

想象一下自动驾驶汽车系统。我们也许能够解释一些构成其决策的因素。下图显示了物体检测系统如何识别具有不同置信区间的物体。

自动驾驶汽车识别不同的对象:查看这些有助于我们解释具体的决定。来源:作者

这个模型至少是部分可解释的,因为我们了解它的一些内部工作。但是可能仍然无法解释 : 只有这个解释,我们无法理解为什么汽车决定加速或停止。

模型不可知的解释

因此,我们知道一些机器学习算法比其他算法更容易解释。但是也有一些技术可以帮助我们解释一个系统,而不管它使用的是什么算法。

例如,前面我们看了一个 SHAP 图。这种技术适用于许多模型,通过考虑每个特征对决策的贡献大小来解释决策(局部解释)。

我们可以用类似的方式使用其他方法,例如:

  • 部分相关图(PDP),
  • 累积局部效应(ALE),以及
  • 当地替代品(石灰)。

这些算法都有助于我们解释现有的机器学习模型,但学习使用它们需要一些时间。

更好的可解释性的“构建模块”

卷积神经网络这样的模型是由不同的层组成的。当用于图像识别时,每一层通常学习特定的特征,较高层学习更复杂的特征。

我们可以将网络学习到的概念与人类概念进行比较:例如,较高层可能会根据较低层学习到的较简单的特征(如“线”)来学习更复杂的特征(如“鼻子”)。

我们可以将这些特征中的每一个可视化,以了解网络“看到”的是什么,尽管仍然很难将网络如何“理解”图像与人类的理解进行比较。

图像识别 CNN 建立了概念上的“构建模块”,因此我们可以更好地解释模型作为一个整体是如何工作的。来源:奥拉赫等人

特征的层次结构

CNN 的不同层识别更简单或更复杂的特征,从简单的边缘检测到完整的对象。来源: Molnar:可解释机器学习

我们可以画出一个由简单到复杂的大致层次。为了解释完整的对象,CNN 首先需要学习如何识别:

  • 棱角,
  • 纹理,
  • 图案,和
  • 零件。

每一层都使用其下一层的累积学习。所以(全连接)顶层使用所有学习到的概念进行最终分类。

我们可以看看网络如何以类似于人类的方式将组块构建成层级,但永远不会有完全的同类比较。寻找机器学习模型的构建模块来提高模型的可解释性仍然是一个开放的研究领域。

基于示例的解释

在上面的 SHAP 图中,我们通过查看其特征来检查我们的模型。通过比较特征重要性,我们看到该模型使用年龄和性别来对特定预测进行分类。

解释模型的另一种方式是查看数据集中的特定实例。这里的区别可以通过在我们的数据集中的特定的(基于实例的解释)与特定的(基于特征的解释)来简化。

我们应该查看具体的实例,因为查看特征并不能解释不可预测的行为或失败,尽管特征可以帮助我们理解模型关心的是什么。

反事实的解释

我们可以通过给模型修改过的反事实输入来洞察模型是如何工作的。知道了模型对特定实例的预测,我们可以做一些小的改变,看看是什么影响了模型来改变它的预测。

在我们的泰坦尼克号的例子中,我们可以取模型预测会幸存的乘客的年龄,并慢慢地修改它,直到模型的预测改变。

通过“控制”模型的预测并理解如何改变输入以获得不同的输出,我们可以更好地解释模型作为一个整体是如何工作的,并更好地理解它的缺陷。

调试和审计可解释的模型

机器学习模型只有能够被解释,才能被调试和审计。如果一个模型预测错误,我们需要弄清楚这是如何发生的,为什么会发生,这样我们就可以修复这个系统。

想象一下,我们有一个模型,它看着动物的图片,并将它们归类为“狗”或“狼”看起来效果不错,但是后来把几只哈士奇误归类为狼。

如果我们可以解释这个模型,我们可能会知道这是由于造成的:这个模型已经知道狼的图片通常有雪作为背景。这在训练中很有效,但在现实世界中失败了,因为爱斯基摩犬也会出现在雪地环境中。

你的公司需要可解释的机器学习吗?

我们喜欢构建可以解释和验证的机器学习解决方案。如果你想谈论可解释的机器学习,请联系我们

可解释的机器学习:优势和劣势

原文:https://towardsdatascience.com/interpretable-machine-learning-advantages-and-disadvantages-901769f48c43?source=collection_archive---------14-----------------------

可解释的机器学习模型总是实用的吗?

来源:图片由 geraltPixabay 拍摄

在数据世界中,人们越来越重视可解释的机器学习

随着神经网络的使用变得越来越主流,以及今天正在分析的数据的庞大规模,模型变得越来越复杂。

在许多情况下,这种复杂的模型本身可能不适合人类解释。因此,一直在推动使模型可解释,从而使结果和实现这些结果的过程都被人类理解。

数据本身并不总是可以解释的

在我看来,可解释机器学习的一个缺点是,它在一定程度上假设输入模型的数据总是适合人类解释。不一定是这样的。

例如,假设一家公司正试图实现可解释的机器学习来设计一个信用评分模型,根据众多特征将潜在的信用卡申请分类为批准或拒绝。

出于隐私原因,这种数据通常是保密的。这方面的一个例子是在 UCI 机器学习知识库中可用的澳大利亚信贷审批数据集。

查看该数据集时,我们只知道存在 6 个数字特征和 8 个分类特征,以及一个类属性(大概类似于信用卡申请是否成功)。

来源:Jupyter 笔记本输出

从机器学习的角度来看,几乎不可避免的是,该模型将以某种黑盒的方式运行,由此匿名特征将用于生成分类分数。

然而,特征是匿名的这一事实意味着,从人类解释的角度来看,使用可解释的模型来理解每个特征对分类的相对贡献是没有意义的。

在这种情况下,最终用户所关心的是确保分类精度尽可能高。如果由于缺乏信息而无法促进理解,那么模型如何得出这一结果就无关紧要了。

可解释性是一切吗?

Cassie Kozyrkov 关于可解释人工智能的文章使用了一个非常有用的类比来打破可解释性与性能之间的权衡:人脑。

当我们在日常生活中做决定时,我们不知道导致我们做出这些决定的大脑中发生的确切过程。相反,我们只是简单地相信我们的大脑在正常工作,继续我们的工作!

让我们再次以信用评分为例。虽然我们可能无法解释为什么一个特定的模型以某种方式运行——在看不见的数据中重复测试并获得高分类性能意味着我们可以相信模型正在按照它应该的方式运行。

然而,正如可解释性不是全部,准确性也不是全部。

如果我们想要直接影响结果变量呢?在这种情况下,可解释性变得更加重要——因为如果不首先理解结果的驱动因素,就不可能影响结果。

去年,我在微软的 InterpretML 库上发布了一篇文章——特别是在生成各种反事实解释中骰子的使用。

DiCE 演示了如何分析酒店取消数据,以确定哪类客户更有可能取消酒店预订。这个模型的优点是可以详细分析反事实的解释。例如,假设某个特定细分市场和分销渠道的客户没有取消预订,如果结果变量是取消(即反事实),这些属性会如何变化?

在这种情况下,酒店经理可以更详细地分析反事实的例子,越来越多地瞄准不太可能取消预订的客户类型。

在这种情况下,特征和结果一样重要。对于信用评分的例子,不一定是这种情况。

结论

最终,我对可解释机器学习的解释(请原谅双关语)是,在实现这些模型时,需要考虑总体目标。

如果目标只是最大限度地提高模型的准确性,那么可解释性就受限于如何使用它来实现这一目标。一个显示出高精度(当然不是过度拟合)的模型可能在人类没有完全理解为什么会这样的情况下产生这样的精度。

然而,从商业的角度来看,在某些情况下,理解特性如何影响结果变量是非常重要的。在这种情况下,可解释性无疑是一个有价值的工具。

非常感谢您的阅读,您可以在michael-grogan.com找到更多我的数据科学内容。

免责声明:本文是在“原样”的基础上编写的,没有担保。它旨在提供数据科学概念的概述,不应被解释为专业建议。

使用 RuleFit 和 Scikit Learn 在 10 分钟内完成可解释的机器学习

原文:https://towardsdatascience.com/interpretable-machine-learning-in-10-minutes-with-rulefit-and-scikit-learn-da9ebb925795?source=collection_archive---------17-----------------------

第一部 | 第二部 | 第三部 |可解释的人工智能——第四部

使用 RuleFit|可解释的人工智能从经过训练的机器学习模型中提取有意义的规则组合

图一。照片由国家癌症研究所Unsplash 上拍摄

当然,你一直在训练机器学习模型,并旨在通过数据预处理、相关性分析和特征提取工作来最大限度地提高你的准确性,至少如果你没有专门使用神经网络的话。但是,模型性能不仅仅是准确性或低 RMSE 分数。

随着人工智能的广泛采用,特别是在敏感领域,人工智能系统的一个期望属性是可解释性。虽然一些机器学习模型本质上是透明的,但其中一些是需要额外步骤来解释的黑盒。

虽然神经网络或集成方法通常被视为黑盒模型,但更传统的算法,如线性回归、决策树或贝叶斯分类器,通常被视为透明端。

让我们快速比较一下透明模型和黑盒模型:

透明模型和黑盒模型的快速比较

越简单通常意味着性能越差

透明最大似然算法通常产生更简单的模型,它们往往表现更差,而神经网络通常优于所有其他最大似然算法。

不太稳定的透明模型

一些透明模型相对不太稳定。例如,决策树被认为是不稳定的,因为用稍有不同的子样本训练树会导致树的结构发生剧烈变化。这导致了集合方法的发展。

简单通常意味着潜在的假设

一些机器学习算法依赖于强大的假设,这些假设可能与现实生活中的事实不符。例如,线性回归总是假设响应变量和解释变量之间的基本关系是线性的。一旦我们对多项式基础关系使用线性回归,该模型将无法收敛于真实关系。

简单通常意味着没有交互作用

因为传统的 ML 算法更简单;它们需要先进的特征提取,研究人员需要采用方法来揭示相互作用的影响。例如,线性回归不能自动提取特征或检测交互影响,这可能导致模型性能差和显著性值不正确。

有一个模型可以解决上面提到的大部分问题:RuleFit。

让我们看看什么是 RuleFit 算法:

规则匹配算法

由 Friedman 和 Popescu 在 2008 年开发的 RuleFit 算法学习稀疏线性模型,该模型以决策规则的形式包含自动检测的交互影响。RuleFit 模型以决策规则的形式创建新功能,并使用这些功能构建透明模型。

示例:如果房间数> 2,房屋年龄< 15 THEN 1 ELSE 0 (lower than medium)

Here is how the RuleFit algorithm works:

第一步:算法训练一个基于树的模型来预测目标,并使用它来创建这些决策规则(结果:许多规则,并非都是信息性的);

第二步:然后它训练一个稀疏线性模型,比如套索,从原始和新创建的特征中选择最好的。

让我们来看看运行中的 RuleFit 算法:

波士顿房价数据集

波士顿房价数据集是一个相对较小的数据集,有 506 个样本和 13 个解释变量。响应变量自然是房屋的价格,目标是开发一个具有重要变量的模型,该模型可以使用给定的解释变量预测房屋。数据库中的每条记录都描述了波士顿的一个郊区或城镇。这些数据是在 70 年代从波斯顿标准大都市统计区(SMSA)创建的。属性定义如下:

  • 各城镇的人均犯罪率
  • ZN :面积超过 25,000 平方英尺的住宅用地比例。制成
  • INDUS :各镇非零售营业亩数比例
  • CHAS :查尔斯河虚拟变量(= 1,如果区域边界为河流;否则为 0)
  • NOX :氮氧化物浓度(百万分之一)
  • RM :每个住宅的平均房间数
  • 年龄:1940 年前建造的自住单位比例
  • DIS :到五个波士顿就业中心的加权距离
  • RAD :放射状公路可达性指标
  • :每万美元的全价值财产税
  • 比例:各城镇的师生比例
  • B:1000(Bk 0.63)2 其中 Bk 是城镇中黑人的比例
  • LSTAT : %较低的人口地位
  • MEDV:以千美元计的自有住房中值

让我们加载数据集:

加载数据集

我们可以使用 scikit-learn 轻松加载波士顿房价数据集。以下代码下载数据集并创建一个 pandas DataFrame 对象:

要点 1。加载数据集

这是数据帧的头部()。

还有,我们用 Plotly Express 看看房价:

要点 2。绘制目标分布图

这是房价分布的直方图:

图二。波士顿房价值的直方图

现在我们已经准备好了数据,我们可以构建和训练一个模型:

训练随机森林回归器

在应用 RuleFit 模型之前,我们需要训练一个基于树的模型,如决策树、随机森林或梯度推进树模型。对于本教程,我将使用 RandomForestRegressor:

要点三。训练随机森林回归器

下面是我们简单随机森林模型的总结:

RandomForestRegressor(bootstrap=True, ccp_alpha=0.0,   criterion='mse', max_depth=None, max_features='auto', max_leaf_nodes=None, max_samples=None, min_impurity_decrease=0.0,                       min_impurity_split=None, min_samples_leaf=1,                       min_samples_split=2, min_weight_fraction_leaf=0.0,                       n_estimators=50, n_jobs=-1, oob_score=False,                       random_state=42, verbose=0, warm_start=False)

评估随机森林

训练模型将持续几秒钟,以下是我们的 RMSE 计算线:

要点 4。评估经过训练的随机森林回归器

输出是:

1.2328287822419268

请注意,我们从未将数据集分为训练和测试。这样选择的原因是为了简化教程,因为我们现在不担心过度拟合。

特征重要性

既然我们已经有了一个训练好的模型,我们就可以通过使用随机森林模型的feature_importances_()函数对解释变量(即特征)进行排序和可视化,并绘图表示:

要点 5。列出并画出重要特征

下面是输出图:

图 3。基于重要程度列出特性的条形图

正如您可以轻松识别的,LSTAT 和 RM 是目前为止影响目标(即房价)的最重要的特征。现在我们已经有了一个训练好的模型,让我们创建我们的自定义规则来获得更多的可解释性和可解释性。

创建和培训规则匹配模型

我们需要先安装rulefit库。然后,我们需要将 RandomForestRegressor 输入到 RuleFit 模型中。不管上面的代码是什么,你都可以选择梯度推进或者决策树。以下代码安装并导入rulefit,使用 RandomForestRegressor 创建一个 RuleFit 模型,并使用数据集训练该模型:

要点 6。安装、导入、创建和训练规则拟合模型

以下是该模型的总结:

**RuleFit(Cs=None, cv=3, exp_rand_tree_size=True, lin_standardise=True, lin_trim_quantile=0.025, max_rules=2000, memory_par=0.01, model_type='rl', random_state=None, rfmode='regress', sample_fract='default', tree_generator=***RandomForestRegressor(bootstrap=True, ccp_alpha=0.0, criterion='mse', max_depth=None, max_features='auto', max_leaf_nodes=6, max_samples=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=563, n_jobs=None, oob_score=False, random_state=562, verbose=0, warm_start=False)***, tree_size=4)**

请注意,由于 RuleFit 模型正在生成数百个规则组合并对其进行测试,因此本培训将花费稍长的时间(仍不到一分钟)。

现在,我们可以用下面的代码评估我们的模型:

要点 7。评估已训练的规则拟合模型

输出:

1.6828402423155089

到目前为止,我们的 RandomForestRegressor 和 RuleFit 模型使用非常相似的代码工作。但是,在后台,我们的 RuleFit 模型生成了数百个潜在的规则组合。

让我们来看看这些规则:

RuleFit 规则

为了得到规则,我们可以使用。规则适配模型的 get_rules()函数。然后,我们可以使用下面的代码根据它们的支持值对它们进行排序:

要点 8。获取 RuleFit 模型创建的规则

以下是输出:

图 4。未过滤规则和功能数据框架的前 15 行

让我们看看我们的列名并描述它们:

  • 规则:特征名称或规则公式
  • 类型:现有特征线性,组合规则
  • coef :规则和特征的系数
  • 支持:规则/特性应用数据集的多大比例
  • 重要性:帮助识别对预测重要的线性项和规则。特征重要性是根据回归模型的权重计算的。

为了有更好的输出,我们应该

  • 消除现有特征;
  • 删除系数为 0.00 的规则,因为它们不重要;
  • 根据它们的支持值对它们进行排序;和
  • 消除最简单的规则以查看更复杂的规则(可选)。

以下是完成所有这些任务的代码行:

要点 9。过滤掉不太重要的规则和所有特征

下面是显示一些规则的输出:

图 5。过滤规则数据框架的前 5 行

正如我们所确定的,LSTAT 和 RM 是最重要的特征。因此,毫不奇怪,最重要的规则组合也大多包含这些特性。上面的第一个规则是一个虚拟变量。IF LSTAT ≤ 15.62 and RM ≤ 6.84, THEN 1 ELSE 0。如你所见,第二条规则与第一条非常相似。因此,合并/删除一些相似的规则以得到一组更易解释的规则可能是有意义的。因此,在理想情况下,我们需要应用一些 NLP 方法来对相似的规则进行分组,并创建一个更精简的模型,该模型将覆盖所有的交互作用,这将最终帮助我们理解我们训练的模型的工作机制。

最终注释

RuleFit 算法是理解特征之间关系的一个很好的解决方案。RuleFit 算法基于树模型和 LASSO 回归器的组合,它可以生成数百个候选规则,这些规则可以帮助我们更好地解释我们的预测。然而,它需要额外的过滤和组合来获得有意义的结果。

订阅邮件列表获取更多内容

除了我的最新内容,我还与我的订户分享我的 Google Colab 笔记本,其中包含我发表的每篇文章的完整代码。如果你想获得我在 Google Colab 上的其他教程文章的代码,并尽早获得我的最新内容,可以考虑订阅:✉️的邮件列表

现在就订阅

如果你对深度学习感兴趣,也可以看看我的人工智能内容指南:

https://blog.orhangaziyalcin.com/a-guide-to-my-content-on-artificial-intelligence-c70c9b4a3b17

如果你正在阅读这篇文章,我确信我们有着相似的兴趣,并且正在/将要从事相似的行业。那么我们就通过Linkedin来连线吧!请不要犹豫发送联系请求!Orhan g . Yal n—Linkedin

使用 SHAP 的可解释机器学习——理论和应用

原文:https://towardsdatascience.com/interpretable-machine-learning-using-shap-theory-and-applications-26c12f7a7f1a?source=collection_archive---------7-----------------------

SHAP 是一种越来越流行的用于可解释机器学习的方法。本文对 Shapley 附加值理论进行了分解,并用几个实例进行了说明。

Johannes Plenio 在 Unsplash 上拍摄的照片

介绍

XGBoost 等复杂的机器学习算法在预测问题上变得越来越流行。传统上,在解释和准确性之间有一个平衡,简单的模型,如线性回归,有时出于透明性和可解释性的原因是首选的。

但是 SHAP(或 Shapley Additive Values)是改变这一趋势的许多方法之一,我们正在逐步走向复杂、准确和可解释的模型。

这篇文章主要基于 Scott Lundberg 的演讲,我在下面的参考资料中提到了他的演讲。我将把重点放在 SHAP 的理论上,然后转移到一些应用上。因为代码和教程非常丰富,所以我将在源代码一节中链接一些。

(一)导致 SHAP 的理论

SHAP 的方法是解释机器学习模型的小部分复杂性。所以我们从解释单个预测开始,一次一个。

记住这一点很重要:我们正在解释每个特征对单个预测值的贡献。在线性回归中,我们通过构造(X*Beta)知道每个特征 X 的贡献,这些贡献的总和解释了结果 Y,导致对模型的直观解释(见图 1)。

图 1:线性模型中的贡献,其中 X 变量预测结果 Y,图片作者

SHAP 的想法是找到一个函数 Phi 来将功劳归于预测,就像线性模型中一样:

图 2:机器学习模型中的贡献,其中 X 变量预测结果 Y,作者图片

那么,我们如何获得钓鱼网站呢?(注意图 2 中 Phi 与数据 X 和机器学习模型 f 的相关性)

为了便于说明,让我们假设我们正在使用 XGBoost 算法,根据两个变量 X1 和 X2 来预测 Y,即未来住院的概率:

X1 :患者去年住院
X2 :患者去年去过急诊室

从这个算法中,我们得到的平均预测概率(未来住院)为 5%。

对于 SHAP,我们试图解释一个单独的预测。所以让我们以病人 A 为例,试着解释他们住院的概率。让我们想象一下,根据我们的机器学习模型,这个概率是 27%。我们可以问自己:我们是如何偏离平均模型预测(5%)而得到患者 A 的预测(27%)的?

图 3:患者 A 入院的预测概率,作者提供的图片

获得患者 A 的 Phi(对预测概率的贡献)的一种方法是根据观察到的特征值查看 f(X)的期望值。我们知道病人 A 在过去的一年里既住院又急诊,所以 X1 和 X2 都等于 1。

我们首先计算:

然后:

图 4:根据特征贡献分解的患者 A入院的预测概率,作者提供的图像

在这个例子中,我们从图 4 中看到,Phi1(变量 X1 的贡献)是:
20% -5% =15%

而φ2(变量 X2 的贡献)为:
27% -20% =7%

但是我们不能就此止步。事实证明,获得 Phi 并不那么简单,因为排序关系到计算它们(我们从哪个变量开始?).这是因为在存在相互作用的情况下,相互作用对最终预测的贡献会到达顺序中的最后一个变量。

例如,如果我们的变量 X1 和 X2 之间存在相互作用,使得如果它们都等于 1,则最终预测概率更高,当我们计算第二项时,相互作用的贡献将被第二有序变量 X2 吸收(或者简单地说,添加到第二有序变量的贡献中):

让我们通过颠倒条件作用的顺序来想象这一点。所以这一次,我们开始以 X2 而不是 X1 为条件。

图 5:患者 A 住院的预测概率,按特征贡献,作者提供的图像

现在我们从图 5 中看到 Phi1(变量 X1 的贡献)是:
27% -10% =17%(之前我们发现这是 15%)

而 Phi2(变量 X2 的贡献)是:
10% -5% =5%(前面我们发现这是 7%)

因此,通过顺序处理这个问题,我们看到,由于潜在的相互作用,我们会得到不稳定的 Phi 值,这取决于我们开始处理的变量。因此,问题变成了:有没有一种好的方法在一组输入中分配贡献,而不必考虑顺序?

解决方案来自博弈论,特别是沙普利勋爵在 20 世纪 50 年代提出的沙普利价值观。

在这种背景下,玩家(特征)一起玩一个游戏(一个观察)来赢得一个奖励(一个预测)。一些玩家在赢得游戏中比其他人贡献更多,但是玩家彼此互动(交互)来赢得游戏。那么,我们如何公平地分配奖金呢?

Shapley 建立了一些假设,定义了公平的属性,导致了奖金分配的唯一解决方案:“Shapley 值”。理论上,Shapley 值很容易计算,因为它们是所有可能的排序 N!(当 N 是特征的数量时)。但是在实践中这种方法计算量很大,因此作者找到了更快的方法来计算一类函数的 Shapley 值(例如树)。

在我们继续看一些插图之前,让我们注意一个主要的警告:

如果特征不是独立的,Phi 就不会完全准确

模型的一个主要假设是独立性,这有助于条件预期的计算。让我们看看怎么做。
我们以ε(f(X)| X1 = 1)为例,其计算公式如下:

(a)将感兴趣的特征固定到其值(在我们的示例中,X1=1)
(b)从其他特征随机采样值(在我们的示例中,从变量 X2 随机采样值)
(c)将从(a)和(b)生成的合成观测值(X1,X2)馈送到模型 f(X)中以获得预测
(d)取预测的平均值

这些步骤在理论上将近似ε(f(X)| X1 = 1,但是如果特征之间存在高度相关性,则显然步骤(b)会中断:通过在(a)中固定 X1,并且在(b)中随机采样 X2,我们中断了 X1 和 X2 之间的相关性。

现在我们已经讨论了一些理论,让我们看看我们能在实践中用 SHAP 做些什么!

(二)SHAP 实践中的几个例证

(a) SHAP 为每个单独的观察给出特征贡献

我们讨论了 SHAP 是如何主要关注于估计个人贡献的。一个 力 plo t 总结了每个特征如何对一个单独的预测做出贡献。

在下面的例子中,研究人员正在使用一个黑盒模型来预测手术室中低氧血症(低氧血症)的风险。红色要素显示对预测赔率有正面(增加)影响,而绿色要素显示对预测赔率有负面(减少)影响。

图 6:力图示例,来源:Scott Lundberg 的演示,如下所示

图 6 显示了特定患者的力图(记住,我们一次解释一个观察结果!).我们可以看到,他们的低潮气量(进出肺部的空气量)导致了低氧血症风险的增加(约 0.5)。

这些关系不一定是因果关系。特征影响可能是由于相关性。

(b) SHAP 给出了全局解释和特征重要性

(a)中描述的局部解释可以放在一起得到一个 全局解释 。由于 SHAP 的公理化假设,全球 SHAP 解释可能比基尼指数等其他指标更可靠。

SHAP 可以提供更好的特征选择能力

在下面的例子中,研究人员基于一组基线变量预测死亡率风险。图 7 显示了全局特征的重要性。一个简单的例子是,年龄是死亡最具预测性的变量。

图 7:特性重要性的例子,来源:下面列出的 Scott Lundberg 的演示

具有全球特征重要性的问题是流行与量级混合。这意味着:

罕见的高幅值效应不会出现在特征重要性图中。

让我们用斯科特·伦德伯格的例子来说明。图 7 中的“血液蛋白”是全球最不重要的特征。但是,当我们查看本地解释摘要(下图 8,右图)时,我们发现高血液蛋白水平对某些人来说是非常具有预测性的。

因此,尽管这一变量在预测平均死亡风险方面似乎不如年龄重要,但对少数人来说,它与死亡风险高度相关:因此 SHAP 值揭示了人口的异质性

图 8:本地解释摘要示例,来源:下面列出的 Scott Lundberg 的演示

(c) SHAP 揭示了异质性和相互作用

我们可以用 SHAP 值来进一步理解异质性的来源。一种方法是使用 SHAP 部分依赖图 (图 9)。部分相关图显示特定特征的 SHAP 值,并根据另一个特征对观察值进行着色。在本例中,SHAP 值是相对于收缩压绘制的,观察值根据其年龄进行着色。

让我们再来看一下局部解释摘要图(图 8,右图)。我们可以看到,较高的收缩压与较高的死亡风险相关。从下面图 9 中的部分相关性图,我们可以进一步说:高收缩压与更高的死亡风险相关,特别是如果它在年轻时开始。

图 9:SHAP 部分相关图的例子,来源:下面列出的 Scott Lundberg 的演示

总结这篇文章,注意除了前面提到的, SHAP 值有更多的应用。值得一提的是它们在部署后监控机器学习模型的有用性。例如,SHAP 值可以揭示由于源数据中的异常,一些变量突然导致机器学习模型中的更多损失。为了获得更多的见解,我鼓励任何人观看 Scott Lundberg 的演讲,链接如下。

未来的研究

根据作者的说法,未来的研究领域包括相关特征存在时的可解释性,以及将因果假设纳入 Shapley 解释。

【来源:】
(1)https://youtu.be/B-c8tIgchu0
(2)https://shap.readthedocs.io/en/latest/index.html
(3)https://christophm . github . io/interpretable-ml-book/shap . html
(4)https://towardsdatascience . com/interpretable-machine-learning-with-xgboost-9ec 80d 148 d27

PyTorch 可解释神经网络

原文:https://towardsdatascience.com/interpretable-neural-networks-with-pytorch-76f1c31260fe?source=collection_archive---------6-----------------------

可解释的人工智能

了解如何使用 PyTorch 构建可通过设计解释的前馈神经网络

Jan Schulz 拍摄#网页设计师 StuttgartUnsplash

有几种方法来评估机器学习模型,其中两种是准确性可解释性。一个高精度的模型就是我们通常所说的好的模型,它很好地学习了输入 X 和输出 y 之间的关系。

如果一个模型具有高度的可解释性或可解释性,我们就能理解该模型如何做出预测,以及我们如何通过改变输入特征来影响该预测。虽然很难说当我们增加或减少输入的某个特征时,深度神经网络的输出会如何表现,但对于线性模型来说,这是非常容易的:如果你增加一个特征,输出会增加该特征的系数。简单。

现在,你可能经常听到这样的话:

“有可解释的模型,也有表现良好的模型。”—一个更不了解它的人

但是,如果你看过我关于可解释的助推机 (EBM)的文章,那么你已经知道这不是真的。EBM 是一个模型的例子,它具有很好的性能,同时又是可解释的。

对于我以前的文章,我创建了下图,展示了我们如何在可解释性-准确性空间中放置一些模型。

图片由作者提供。

特别是,我将深层神经网络(省略了深层神经网络)更多地放置在非常准确但难以解释的区域。当然,您可以通过使用像 shaplime 这样的库在一定程度上缓解可解释性问题,但是这些方法都有自己的一套假设和问题。因此,让我们走另一条路,创建一个可以通过本文中的设计来解释的神经网络架构。

免责声明: 我即将呈现的架构刚刚浮现在脑海中。我不知道是否已经有关于它的文献,至少我找不到任何东西。不过, Krist Papas 指出,这个想法可以在论文 中找到:用神经网络进行可解释的机器学习【1】**作者 Rishabh Agarwal 等人感谢!

可解释的建筑理念

请注意,我希望你知道前馈神经网络是如何工作的。我不会在这里给出一个完整的介绍,因为已经有很多关于它的资源了。

考虑以下玩具神经网络,具有三个输入节点 x ₁、 x ₂、 x ₃、单个输出节点 ŷ ,以及三个各有六个节点的隐藏层。我在这里省略了偏差项。

图片由作者提供。

这种体系结构在可解释性方面的问题是,由于完全连接的层,输入完全混合在一起。每个单个输入节点都会影响所有隐藏层节点,随着我们深入网络,这种影响会变得更加复杂。

受树木的启发

基于树的模型通常也是如此,因为如果我们不加以限制,决策树可能会使用每个特征来创建分割。例如,标准的梯度增强及其派生,如 XGBoostLightGBMCatBoost 本身并不能真正解释。

然而,你可以通过使用只依赖于单个特征的决策树来使梯度增强变得可解释,就像 EBM 所做的那样(阅读我的相关文章!😎).

在许多情况下,像这样限制树不会对性能造成太大影响,但使我们能够像这样直观地看到功能影响:

的输出解释了的显示功能。图片由作者提供。

看一下有蓝线的图形的顶部。它显示了在某些回归问题中 feature_4 对输出的影响。在 x 轴上,可以看到 feature_4 的范围。 y 轴显示分数,它是输出改变多少的值。下面的直方图显示了 feature_4 的分布。

从图中我们可以看到以下内容:

  • 如果 feature_4 约为 0.62,则与 feature_4 为 0.6 或 0.65 相比,输出增加约 10 倍。
  • 如果 feature_4 大于 0.66,对输出的影响是负面的。
  • 将 feature_4 在 0.4 至 0.56 范围内改变一位确实会使输出发生很大变化。

然后,模型的最终预测只是不同特征分数的总和。此行为类似于 Shapley 值,但不需要计算它们。很好,对吧?现在,让我向你展示我们如何对神经网络做同样的事情。

移除边缘

因此,如果问题是神经网络的输入因为太多的边而分散在隐藏层周围,让我们只移除一些。特别是,我们必须删除允许信息从一个特征流向另一个特征的边。仅删除这些溢出边,上面的玩具神经网络变成:

图片由作者提供。

我们为三个输入变量创建了三个独立的模块,每个模块都是一个完全连接的网络,有一个单独的部分输出 ŷᵢ.最后一步,将这些 ŷᵢ 相加,加上一个偏置(图中省略)产生最终输出 ŷ

我们引入了部分输出,以便能够创建与 EBM 允许的相同类型的图。上图中的一个方块代表一个情节: xᵢ 进去,ŷᵢ 出来。我们将在后面看到如何做到这一点。

这里我们已经有了完整的架构!我认为理论上理解它是相当容易的,但是让我们也实施它。这样,你很高兴,因为你可以使用神经网络,企业也很高兴,因为神经网络是可解释的。

PyTorch 中的实现

我不指望你完全熟悉 PyTorch ,所以我会解释一些基础知识,帮助你理解我们的定制实现。如果你知道 PyTorch 的基础知识,你可以跳过完全连接层部分。如果您还没有安装 PyTorch,在这里选择您的版本

完全连接的层

这些层在 PyTorch 中也被称为线性密集Keras 中。它们使用具有乘法权重的 nm 边沿将 n 输入节点连接到 m 输出节点。这基本上是一个矩阵乘法加上一个偏差项,如下面两个代码片段所示:

import torch

torch.manual_seed(0) # keep things reproducible

x = torch.tensor([1., 2.]) # create an input array
linear_layer = torch.nn.Linear(2, 3) # define a linear layer

print(linear_layer(x)) # putting the input array into the layer

# Output:
# tensor([ 0.7393, -1.0621,  0.0441], grad_fn=<AddBackward0>)

这就是如何创建完全连接的层,并将其应用于 PyTorch 张量。您可以通过linear_layer.weight获得用于乘法的矩阵,通过linear_layer.bias获得用于偏置的矩阵。那你可以做

print(linear_layer.weight @ x + linear_layer.bias) # @ = matrix mult

# Output:
# tensor([ 0.7393, -1.0621,  0.0441], grad_fn=<AddBackward0>)

不错,是一样的!现在,PyTorch、Keras 和公司的伟大之处在于,你可以将许多层堆叠在一起,创建一个神经网络。在 PyTorch 中,你可以通过torch.nn.Sequential实现这种堆叠。要从上面重建密集网络,您可以做一个简单的

model = torch.nn.Sequential(
    torch.nn.Linear(3, 6),
    torch.nn.ReLU(),
    torch.nn.Linear(6, 6),
    torch.nn.ReLU(),
    torch.nn.Linear(6, 6),
    torch.nn.ReLU(),
    torch.nn.Linear(6, 1),
)

print(model(torch.randn(4, 3))) # feed it 4 random 3-dim. vectors

注: 我到目前为止还没有给你演示过如何训练这个网络,只是架构的定义,包括参数的初始化。但是你可以向网络提供三维输入,接收一维输出。

既然我们想创建自己的层,让我们先从简单的东西开始练习:重新创建 PyTorch 的Linear层。你可以这样做:

import torch
import math

class MyLinearLayer(torch.nn.Module):
    def __init__(self, in_features, out_features):
        super().__init__()
        self.in_features = in_features
        self.out_features = out_features

        # multiplicative weights
        weights = torch.Tensor(out_features, in_features)
        self.weights = torch.nn.Parameter(weights)
        torch.nn.init.kaiming_uniform_(self.weights) 

        # bias
        bias = torch.Tensor(out_features)
        self.bias = torch.nn.Parameter(bias)
        bound = 1 / math.sqrt(in_features)
        torch.nn.init.uniform_(self.bias, -bound, bound)

    def forward(self, x):
        return x @ self.weights.t() + self.bias

这段代码值得解释一下。我们通过以下方式引入线性层的权重

  1. 创建 PyTorch 张量(包含所有零,但这无关紧要)
  2. 将它注册为层的可学习参数,这意味着梯度下降可以在训练期间更新它,然后
  3. 初始化参数。

初始化神经网络的参数本身就是一个完整的主题,因此我们不会进入兔子洞。如果它太困扰你,你也可以用不同的方式初始化它,例如通过使用一个标准的正态分布torch.randn(out_features, in_features),但是那时训练可能会慢一些。无论如何,我们对偏差做同样的处理。

然后,该层需要知道它应该在forward方法中执行的数学运算。这只是线性运算,即矩阵乘法和偏差加法。

好了,现在我们已经准备好实现我们的可解释神经网络层了!

块线性图层

我们现在设计一个BlockLinear层,我们将以如下方式使用:首先,我们从 n 特征开始。然后BlockLinear层应该创建由 h 个隐藏神经元组成的 n 个块。为了简化,h 在每个块中是相同的,但是你当然可以推广这个。总的来说,第一个隐藏层将由 nh 神经元组成,但也只有 nh 边连接到它们(而不是 n h 用于完全连接的层)为了更好的理解,再看一遍上面的图片。这里, n = 3, h = 2。

图片由作者提供。

然后——在使用了 ReLU 这样的非线性之后——我们将在这个层之后放置另一个BlockLinear层,因为不同的块不应该再次合并。我们重复这个过程很多次,直到我们在最后用一个Linear层把所有的东西绑起来。

块线性层的实现

让我们来看看代码。它与我们定制的线性层非常相似,所以代码不应该太吓人。

class BlockLinear(torch.nn.Module):
    def __init__(self, n_blocks, in_features, out_features):
        super().__init__()
        self.n_blocks = n_blocks
        self.in_features = in_features
        self.out_features = out_features
        self.block_weights = []
        self.block_biases = []
        for i in range(n_blocks):
            block_weight = torch.Tensor(out_features, in_features)
            block_weight = torch.nn.Parameter(block_weight)
            torch.nn.init.kaiming_uniform_(block_weight)
            self.register_parameter(
                f'block_weight_{i}',
                block_weight
            )
            self.block_weights.append(block_weight)
            block_bias = torch.Tensor(out_features)
            block_bias = torch.nn.Parameter(block_bias)
            bound = 1 / math.sqrt(in_features)
            torch.nn.init.uniform_(block_bias, -bound, bound)
            self.register_parameter(
                f'block_bias_{i}',
                block_bias
            )
            self.block_biases.append(block_bias)

    def forward(self, x):
        block_size = x.size(1) // self.n_blocks
        x_blocks = torch.split(
            x,
            split_size_or_sections=block_size,
            dim=1
        )
        block_outputs = []
        for block_id in range(self.n_blocks):
            block_outputs.append(
                x_blocks[block_id] @ self.block_weights[block_id].t() + self.block_biases[block_id]
            )
        return torch.cat(block_outputs, dim=1)

第一行类似于我们在自制的线性图层中看到的,只是重复了n_blocks次。这为每个块创建了一个独立的线性层。

在正向方法中,我们得到一个作为单个张量的x,我们必须首先使用torch.split将它再次分割成块。举例来说,块大小为 2 会执行以下操作:[1, 2, 3, 4, 5, 6] -> [1, 2], [3, 4], [5, 6]。然后,我们将独立的线性变换应用于不同的块,并用torch.cat将结果粘合在一起。搞定了。

训练可解释的神经网络

现在,我们有了定义我们的可解释神经网络的所有要素。我们只需要首先创建一个数据集:

X = torch.randn(1000, 3)
y = 3*X[:, 0] + 2*X[:, 1]**2 + X[:, 2]**3 + torch.randn(1000)
y = y.reshape(-1, 1)

我们可以看到,我们处理的是一个由一千个样本组成的三维数据集。如果将要素 1 和要素 2 平方,真实的关系是线性的-这就是我们想要用模型恢复的!因此,让我们定义一个能够捕捉这种关系的小模型。

class Model(torch.nn.Module):
    def __init__(self):
        super().__init__()

        self.features = torch.nn.Sequential(
            BlockLinear(3, 1, 20),
            torch.nn.ReLU(),
            BlockLinear(3, 20, 20),
            torch.nn.ReLU(),
            BlockLinear(3, 20, 20),
            torch.nn.ReLU(),
            BlockLinear(3, 20, 1),
        )

        self.lr = torch.nn.Linear(3, 1)

    def forward(self, x):
        x_pre = self.features(x)
        return self.lr(x_pre)

model = Model()

我将模型分为两步:

  1. self.features计算部分输出 ŷᵢ ,然后
  2. 将最终预测 ŷ 计算为 ŷᵢself.lr的加权和。

这使得提取特征解释更加容易。在self.features的定义中,您可以看到我们创建了一个具有三个模块的神经网络,因为我们在数据集中有三个特征。对于每个块,我们创建许多隐藏层,每个块有 20 个神经元。

现在,我们可以创建一个简单的训练循环:

optimizer = torch.optim.Adam(model.parameters())
criterion = torch.nn.MSELoss()

for i in range(2000):
    optimizer.zero_grad()
    y_pred = model(X)
    loss = criterion(y, y_pred)
    loss.backward()
    optimizer.step()
    if i % 100 == 0:
        print(loss)

基本上,我们选择 Adam 作为优化器,MSE 作为损失,然后进行标准梯度下降,即使用optimzer.zero_grad()删除旧梯度,计算预测,计算损失,通过loss.backward()区分损失,并通过optimizer.step()更新模型参数。你可以看到培训损失随着时间的推移而下降。这里我们不关心验证或测试集。训练 r 结束时应大于 0.95。

我们现在可以通过以下方式打印模型说明

import matplotlib.pyplot as plt

x = torch.linspace(-5, 5, 100).reshape(-1, 1)
x = torch.hstack(3*[x])

for i in range(3):
    plt.plot(
        x[:, 0].detach().numpy(),
        model.get_submodule('lr').weight[0][i].item() * model.get_submodule('features')(x)[:, i].detach().numpy())
    plt.title(f'Feature {i+1}')
    plt.show()

然后得到

作者图片。

这看起来很整洁!该模型计算出特征 1 的影响是线性的,特征 2 的影响是二次的,特征 3 的影响是三次的。不仅如此,模型能够向我们展示,这是整个建筑的伟大之处!

你甚至可以抛开网络,仅凭这些图表就做出预测!

举个例子,让我们估算一下 x = (2,-2,0)的网络输出。

  • 基于第一个数字,x ₁ = 2 转化为预测的 +5
  • x ₂ = -2 转化为预测的 +9 ,基于第二个数字。
  • 根据第三个数字, x ₃ = 0 转换为预测的 +0
  • 仍然有一个偏差来自你可以通过model.get_submodule('lr').bias访问的最后一个线性层,这个也必须加上,但是应该很小。

总的来说,你的预测应该在ŷt23】≈5+9+0+偏差 14 左右,还算准确。

您还可以看到如何最小化输出:为功能 1 选择较小的值,为功能 2 选择接近零的值,为功能 3 选择较小的值。这是你通常不能仅仅通过看神经网络看到的,但是通过分数函数,我们可以。这是可解释性的一个巨大好处。

注意,从上面学习的得分函数只能对我们实际上有训练数据的区域有把握。在我们的数据集中,我们实际上只观察到每个特征的值在-3 和 3 之间。因此,我们可以看到,我们并没有得到边上完美的 xx 多项式。但是我认为图表的方向是正确的,这仍然令人印象深刻。为了充分理解这一点,将其与循证医学的结果进行比较:

作者图片。

曲线是块状的,向两边外推只是一条直线,这是基于树的方法的主要缺点之一。

结论

在本文中,我们讨论了模型的可解释性,以及神经网络和梯度推进如何无法实现这一点。虽然解释包的作者创建了 EBM,一种可解释的梯度推进算法,但我向您展示了一种创建可解释的神经网络的方法。

然后我们用 PyTorch 实现了它,代码有点多,但并不太疯狂。至于 EBM,我们可以提取每个特征的学习得分函数,我们甚至可以用它来进行预测。

实际训练的模型甚至不再需要,这使得在弱硬件上部署和使用它成为可能。这是因为我们只需为每个特征存储一个查找表,占用的内存很少。每个查找表使用 g 的网格大小导致只存储O(n_ features g*)元素,而不是潜在地存储数百万甚至数十亿的模型参数。做预测也很便宜:只需从查找表中添加一些数字。由于这具有仅O(n_ features)查找和加法的时间复杂度,所以它比通过网络的正向传递快得多。**

参考

[1] R. Agarwal,L. Melnick,N. Frosst,X. Zhang,B. Lengerich,R. Caruana 和 G. Hinton,神经加法模型:用神经网络进行可解释的机器学习 (2020)

我希望你今天学到了新的、有趣的、有用的东西。感谢阅读!

作为最后一点,如果你

  1. 想支持我多写点机器学习和
  2. 无论如何,计划获得一个中等订阅量,

为什么不做 通过这个环节 ?这将对我帮助很大!😊

透明地说,给你的价格不变,但大约一半的订阅费直接归我。

非常感谢,如果你考虑支持我的话!

如果有任何问题,请在 LinkedIn 上给我写信!

使用 DeepXF 以最少的编码实现可解释的临近预报

原文:https://towardsdatascience.com/interpretable-nowcasting-with-deepxf-using-minimal-code-6b16a76ca52f?source=collection_archive---------17-----------------------

非常短期的战略业务目标能否得到精确的未来洞察力的支持,从而快速做出决策?

在这篇博客中,我们将讨论一个非常重要的话题,这个话题与我们的现实世界息息相关。通过这篇文章,我们将重温适用于几乎所有商业场景的关键短期战略问题。我们将看到“-Deep-XF”一个 python 库如何被直观地用于轻松的临近预报任务,以及一个演示用例。此外,我们还将看到如何解释临近预报模型结果,以获得更好的见解。关于这个包的快速介绍请浏览这个博客 这里 。另外,从 这里 看一下预测的相关主题和动手演示教程。

概述:预报与临近预报

为直观详细解释时序检查 此处;并且,对于时间序列数据的无监督特征选择检查 这里

我们先简单通俗地了解一下预报临近预报的核心区别。

F 因此,简单的预测是对未来的预测或有根据的猜测。

另一方面,预测是在非常短的时间间隔内实时客观地确定趋势或趋势反转的科学。临近预报是基于事实的,关注已知和可知的事物,因此它避免预测。简而言之,临近预报是稳健决策过程的基础。

基于“期望最大化”算法的临近预报

一般来说,许多机器学习问题可以通过迭代的方式来解决。期望最大化 (EM)算法的一般原理也在于迭代,以及在估计具有未观察变量的统计模型的参数时看到观察数据的可能性的优化。你只需从最初的随机猜测开始,然后使用这些猜测来估计期望公式化,然后迭代地最大化,直到解决方案收敛。EM 算法被广泛使用的实时应用包括填充样本空间中的缺失数据、图像重建、预测马尔可夫模型参数、测量函数的高斯密度等等。

可解释的 ML 和可解释的 AI (XAI)

构建可解释模型背后的核心思想是,不再有机器学习模型,它们的推理对我们来说仍然是一个完整的“黑箱解决方案。通俗地说,模型的结果应该被我们以简单的人类可理解或可读的形式来理解、解释和信任。这就是可解释的 ML/可解释的 AI 科学进入画面的地方,它帮助你理解和解释机器学习模型生成的结果。

用例—天气临近预报问题

让我们通过一个针对经典气象学应用的多变量数据集进行动手演示。这里,我们将使用来自 这里 的加拿大气候数据集。这个数据集是从几个公共来源编译而来的。该数据集由加拿大 13 个中心的每日温度和降雨量组成。降水不是雨就是雪(冬天可能会下雪)。1940 年,13 个中心中有 7 个有每日数据,但到了 1960 年,所有 13 个中心都有每日数据,偶尔会有缺失值。我们有大约 80 年的记录(每日数据频率),我们想预测非常短期的未来。下面的分步插图将引导您完成演示用例。

一旦安装了库,我们导入库,然后导入数据,检查形状和属性数据类型,等等。接下来,我们使用库中的 missing () 函数来查找数据集的缺失值,然后输入/替换 NAN 值(如果数据集中有)。为了输入缺失值,我们使用 impute () 函数,该函数提供了几个输入值的选项,如填充零、平均值、中值、回填等。

接下来,一旦数据被预处理,我们用选择'期望最大化【T3]'算法的 set_model_config () 函数、输入定标器(例如:MinMaxScaler、StandardScaler、MaxAbsScaler、RobustScaler)和临近预报周期窗口来设置定制的临近预报模型参数。接下来, set_variables ()get_variables () 函数用于设置和解析时间戳索引,指定感兴趣的结果变量,对数据进行排序,删除重复项等。

此外,我们随后使用直观的 plot_dataset () 函数,通过交互式图表显示结果列 wrt 时间的趋势。然后,我们使用 nowcast () 函数训练 nowcast 模型,随后使用explable _ nowcast()函数获得 now cast 模型对未来数据点的推断结果的解释。人们还可以通过交互式绘图来可视化历史和当前预测值。此外,可解释性模块以 desc 重要性顺序显示了重要的贡献属性,用图表描绘。

对于库安装遵循以下步骤 此处 &对于手动先决条件安装勾选 此处

第一步:导入库

第二步:导入数据;检查数据集形状&属性信息

(29221, 27)

按作者分类的图像:获取属性信息

步骤 3: 检查整个数据集的缺失值

按作者分类的图像:打印数据集中缺失的值信息

步骤 4: 估算缺失值

步骤 5: 为临近预报模型设置自定义用户输入

步骤 6: 设置并解析时间戳、结果变量等

按作者分类的图像:查看显示单行的数据集

第 7 步:交互式绘图的数据可视化

作者图片:可视化交互式 plotly plot 与时间戳和预测栏

第八步:特征工程

步骤 9: 训练临近预报模型,并利用端点可视化绘制交互式临近预报未来预测

作者图片:训练临近预报模型直到收敛

作者提供的图像:具有历史和当前预测值的可视化交互式 plotly 地块

第十步:获取临近预报模型的预测解释

作者图片:可解释性模块图,按照 desc 重要性顺序显示重要属性

上面匀称的曲线是未来预测数据点的结果。可以看出,对结果列“平均温度温哥华”的相应模型推断有重大贡献的特征主要是由于属性,如“总降水量温哥华”,萨斯卡通、卡尔加里、蒙克顿气象站的平均温度,以及派生的日期、循环特征,特别是暗示日、周、月时间线重要性的特征。

结论

在这篇文章中,我们快速浏览了预测和临近预报的概述。我们讨论了 EM 算法,并且也看到了建立全局可解释模型的需要。我们在气象领域看到了一个经典临近预报用例问题。我们使用了 deep-xf 包来构建基于动态因子模型的临近预报器。利用这种'简单的'、易用的'和'低代码的'解决方案,人们还可以轻松地自动构建可解释的基于深度学习的预测模型。此外,还可以使用单行代码轻松地将模型结果作为平面 csv 文件以及交互式可视化绘图输出到磁盘。

这篇博文附带的完整笔记本可以在 这里 找到。

接触

你可以在 ajay.arunachalam08@gmail.com 找到我;与我联系— Linkedin

感谢阅读。干杯,继续学习:)

传记

我是 AWS 认证的机器学习专家和云解决方案架构师。我真的相信,在我们完全接受人工智能的力量之前,人工智能系统的不透明是当前的需要。考虑到这一点,我一直努力使人工智能民主化,并且更倾向于建立可解释的模型。我的兴趣是应用人工智能、机器学习、深度学习、深度强化学习和自然语言处理,特别是学习良好的表示。根据我处理现实世界问题的经验,我完全承认,找到良好的表示是设计系统的关键,该系统可以解决有趣的挑战性现实世界问题,超越人类水平的智能,并最终为我们解释我们不理解的复杂数据。为了实现这一点,我设想学习算法可以从未标记和标记的数据中学习特征表示,在有和/或没有人类交互的情况下被引导,并且在不同的抽象级别上,以便弥合低级数据和高级抽象概念之间的差距。

参考

https://en.wikipedia.org/wiki/Nowcasting_(meteorology) https://en.wikipedia.org/wiki/Time_series https://en.wikipedia.org/wiki/Shapley_value https://enterprisersproject.com/article/2019/5/what-explainable-ai http://aqua.upc.es/anywhere-catalogue-v2/?product=ravake-heavy-rainfall-nowcasting http://anywhere-h2020.eu/ https://github.com/slundberg/shap https://pytorch.org/ https://www.tensorflow.org/ https://hackerbits.com/data/expectation-maximization-em-data-mining-algorithm/ https://jonathan-hui.medium.com/machine-learning-expectation-maximization-algorithm-em-2e954cb76959

可解释的还是准确的?为什么不两者都要?

原文:https://towardsdatascience.com/interpretable-or-accurate-why-not-both-4d9c73512192?source=collection_archive---------18-----------------------

用 IntepretML 构建可解释的 Boosting 模型

图片由 Kingrise 来自 Pixabay

正如米勒所总结的,可解释性指的是人类能够理解决策原因的程度。机器学习社区中的一个常见概念是准确性和可解释性之间存在权衡。这意味着越精确的学习方法提供的可解释性越少,反之亦然。然而,最近,有很多的重点放在创造内在可解释的模型,并远离他们的黑盒对应。事实上,辛西娅·鲁丁认为可解释的黑盒应该完全避免用于对人类生活产生深远影响的高风险预测应用。所以,问题是一个模型是否可以在不牺牲可解释性的前提下具有更高的准确性?

EBMs 正是试图填补这一空白。EBM 代表可解释的 Boosting Machine ,是一种模型,其精确度可与随机森林和 Boosted Trees 等最先进的机器学习方法相媲美,同时具有高度的可理解性和可解释性。

本文将着眼于 EBM 背后的思想,并通过 InterpretML (机器学习可解释性的统一框架)将它们实现为一个人力资源案例研究。

机器学习的可解释性—初级读本

机器学习是一种强大的工具,正在越来越多地以多方面的方式应用于多个行业。人工智能模型越来越多地用于做出影响人们生活的决策。因此,预测必须是公平的,没有偏见或歧视。

在 pipeline | Image 中拥有机器学习可解释性的优势

在这种情况下,机器学习的可解释性起着至关重要的作用。可解释性不仅能让你发现模型的错误预测,还能分析和修复潜在的原因。可解释性可以帮助您调试您的模型,检测过度拟合和数据泄漏,最重要的是,通过给出解释来激发模型和人类之间的信任。

可解释性方法

根据机器学习模型的类型,用来解释模型预测的方法可以分为两大类。

1.玻璃盒模型与黑盒解释

被设计成可解释的算法被称为玻璃盒子模型。这些算法包括简单决策树、规则列表、线性模型等。玻璃箱方法通常提供精确或无损的可解释性。这意味着可以追踪和推理任何预测是如何做出的。GlassBox 模型的解释是特定于模型的,因为每种方法都基于一些特定的模型内部。例如,线性模型中的权重解释计入特定模型的解释

相反,黑盒解释者是模型不可知论者。它们可以应用于任何模型,并且本质上是事后的,因为它们是在模型被训练之后应用的。黑盒解释器通过将模型视为黑盒来工作,并假设他们只能访问模型的输入和输出。它们对于复杂的算法特别有用,比如提升树和深度神经网络。黑盒解释器通过反复扰动输入和分析模型输出的结果变化来工作。例子包括 SHAP石灰部分依赖图 s 等。,不一而足。

玻璃盒子与黑盒可解释方法|作者图片

2.本地与全球解释

另一类可能取决于解释的范围。局部解释旨在解释单个预测,而全局解释则解释整个模型行为。

既然我们对机器学习模型所采用的可解释性机制有了足够的直觉,让我们换个角度,更详细地理解 EBM。

可解释增压机

EBM是玻璃箱模型,其设计精度可与最先进的机器学习方法相媲美,而不会影响精度和可解释性

EBM 是一种广义加性模式 l 或简称 GAM。线性模型假设反应和预测之间存在线性关系。因此,他们无法捕捉数据中的非线性。

Linear Model: y = β0 + β1x1 + β2x2 + … + βn xn

为了克服这个缺点,在 80 年代后期,统计学家 Hastie & Tibshirani 开发了广义加法模型 (GAMs),它保持了加法结构,因此保持了线性模型的可解释性。因此,响应和预测变量之间的线性关系被几个非线性平滑函数 (f1,f2 等)所代替。)来模拟和捕捉数据中的非线性。gam 比简单的线性模型更精确,因为它们不包含特征之间的任何交互,用户也可以很容易地解释它们。

Additive Model: y = **f1**(x1) + **f2**(x2) + … + **fn** (xn)

EBM 是利用梯度推进和装袋等技术对 gam 的改进。EBM 包括成对的相互作用项,这进一步提高了它们的准确性。

EBMs: y = Ʃi **fi** (xi) + Ʃij **fij(xi , xj)** + Ʃijk **fijk (xi , xj , xk )**

EBM 的创始人理查德·卡鲁阿纳(Richard Caruana)的以下演讲深入探讨了算法背后的直觉。

解释背后的科学:可解释的助推机器

这里要注意的重要一点是,即使在所有这些改进之后,EBM 仍然保留了线性模型的可解释性,但通常与强大的黑盒模型的准确性相当,如下所示:

跨数据集(行、列)的模型分类性能|官方论文: InterpretML:机器学习可解释性的统一框架

案例研究:使用机器学习预测员工流失

这是代码笔记本的 nbviewer 链接,以防你想跟进。

来自皮沙贝的安德鲁·马丁

是时候把手弄脏了。在本节中,我们将训练一个 EBM 模型来预测员工流失。我们还将比较 EBMs 与其他算法的性能。最后,我们将尝试解释我们的模型在一个叫做 InterpretML 的工具的帮助下做出的预测。什么是 interpretML?让我们找出答案。

IntepretML:机器学习可解释性的统一框架

EBM 被打包在一个名为 [InterpretML](http://Unified Framework for Machine Learning Interpretability) 的机器学习可解释性工具包中。t 是一个用于训练可解释模型以及解释黑盒系统的开源包。在 InterpretML 中,可解释性算法被组织成两个主要部分,即玻璃盒模型黑盒解释。这意味着该工具不仅可以解释固有的可解释模型的决策,还可以为黑盒模型提供可能的推理。以下来自官方论文的代码架构很好地总结了这一点。

来自官方论文的代码架构|来源: InterpretML:机器学习可解释性的统一框架

按照作者的说法,InterpretML 遵循四个基本设计原则:

InterpretML 还提供了一个交互式可视化仪表板。仪表板提供了关于数据集性质、模型性能和模型解释的有价值的见解。

资料组

我们将使用公开发布的 IBM HR Analytics 员工流失&绩效数据集。该数据集包含关于雇员的年龄、部门、性别、教育水平等数据。,以及关于雇员是否离开公司的信息,由可变损耗表示。“否”表示没有离开公司的员工,“是”表示离开公司的员工。我们将使用该数据集构建一个分类模型来预测员工的流失概率。

这是数据集要素的快照。

数据集的特征|按作者分类的图像

如上所述,InterpretML 支持训练可解释模型(玻璃盒子),以及解释现有的 ML 管道(黑盒),并且跨 Windows、Mac 和 Linux 得到支持。目前,该软件包支持以下算法:

作者的解释图像支持的算法

探索数据集

第一项任务总是探索数据集并理解各列的分布。InterpretML 为分类问题提供了直方图可视化。

直方图可视化|作者提供的图像

训练模型

使用 InterpretML 训练 EBM 相对容易。在预处理我们的数据集并将其分成训练集和测试集之后,下面几行代码就完成了这项工作。InterpretML 符合大家熟悉的 scikit learn API。

一旦模型被训练,我们就可以从全局和局部的角度可视化和理解模型的行为。

全局解释

全局解释有助于更好地理解模型的整体行为和总体中的一般模型行为。

我们看到的第一张图表是汇总图,它表明Overtime变量是决定某人是否会离开公司的最关键因素。

查看全球解释|按作者分类的图片

我们还可以通过向下钻取更深入地查看每个特征图。

年龄对磨损的影响|作者图片

这里的分数指的是逻辑,因为这个问题是一个分类问题。你在 y 轴上的位置越高,你离开公司的几率就越高。然而,在 35 岁左右,这种行为改变了,你有更多的机会留在后面。

本地解释

局部解释有助于我们理解个别预测背后的原因,以及为什么会做出特定的预测。

查看本地解释|作者图片

与其他型号的性能比较

比较不同算法的性能并以仪表板格式显示结果也很容易。

比较仪表板|按作者分类的图像

训练黑盒模型

如果需要,InterpretML 还可以训练黑盒模型,并为预测提供解释。以下是在同一数据集上训练的随机森林分类器模型的示例,以及 LIME 随后提供的解释。从下图可以看出,EBM 的性能比随机森林好得多。

分析黑盒模型|作者图片

结论

本文展示了 EBM 如何成为创建可解释的和精确的模型的最佳选择。就个人而言,当机器学习模型用于高风险决策时,可解释性应该比损失几个点的准确性得到更高的优先考虑。不仅重要的是看一个模型是否有效,我们作为机器学习从业者也应该关心它是如何工作的,以及它是否没有任何故意的偏见。

参考

本文引用了大量的资源和论文,并在文章中进行了链接。然而,第一手资料来源是 InterpretML 的官方文件及其文档

👉有兴趣看我写的其他文章。这个 回购 包含了我分类写的所有文章。

基于隐马尔可夫模型的可解释时间序列相似性

原文:https://towardsdatascience.com/interpretable-time-series-similarity-with-hidden-markov-models-88fdf7ee4962?source=collection_archive---------18-----------------------

如何直观准确地找到相似之处,并增加了一个使用道琼斯 30 种股票的例子(包括代码)

马库斯·斯皮斯克在 Unsplash 上的照片

对于在数据科学和机器学习领域工作的许多专业人员来说,需要测量两个时间序列之间的距离是很常见的。从金融业到生态学,时间相关数据的收集无处不在,由于获得另一个数据点的唯一约束通常是时间,因此这种数据可能富含我们可以利用来获得新见解的信息。

在这一过程中经常遇到的垫脚石是衡量一个时间序列与另一个时间序列相似程度的能力。毕竟,如果我们能够确定两只股票或动物种群在时间上的行为相似,将会获得大量的洞察力,这里的关键因素是时间。大多数众所周知的相似性/距离度量,例如欧几里德距离、闵可夫斯基距离、汉明距离和 Jaccard 距离,只与单个数据点有关。然而,我们感兴趣的是找到一个数据点集合之间的距离度量,这些数据点都以一种非常有趣的方式(即时间)相互关联。毫不奇怪,有无数种方法可以做到这一点,每种方法都适用于特定的问题子集,但我在这里向您推荐的方法是使用隐马尔可夫模型 (HMMs)。这种方法侧重于从全局和贝叶斯的角度比较两个时间序列的时间动态。

时间序列距离逼近的 TLDR

基于形状的测量

这种类型的相似性度量通常寻求直接比较时间序列,因此具有相似形状的时间序列被分配较低的距离。基于形状的度量的典型例子是欧几里德距离。对于两个时间序列 X= ( X_1,X_2,…,X_n )和 Y= ( Y_1,Y_2,…,Y_n ),欧几里德距离由下式给出

请注意,时间序列必须具有相等的长度和相同的时间索引。如果 XY 具有相似的值,并且通过扩展具有相似的形状,那么距离将会很小。这些方法对于短时间序列来说很棒,并且很容易解释,但是它们通常必须解决噪声鲁棒性问题。例如,假设对于任意时间点 t_iY = 0,由 X = b * t_i 给出 X 。我们可以制作一个新的仅由高斯噪声组成的时间序列 Z = N (0,σ),使得 d(X,Y) = d(Y,Z) 。这个问题的严重程度当然取决于你手头的问题。

基于特征的度量

这种类型的距离度量试图用简单的距离度量(或度量)找到从时间序列空间到特征空间的映射。).一个很好的例子是安东尼亚迪斯等人的方法。阿尔[2]。其中他们使用离散小波变换将时间序列分解成时间-频率谱,并使用频率能量作为特征。

对于各种时间序列问题,这是一种很好的方法,特别是如果存在数据的直观或经过充分测试的特征表示,例如使用小波编码音频信号或使用傅立叶级数分解周期性产品需求。然而,它们仍然存在噪声敏感性问题,通常需要仔细选择超参数。

基于结构的度量

这种类型的测量试图识别时间序列的潜在结构和动态的差异,这就是我们的 HMM 方法所在。在我们的特殊情况下,我们的目标是找到准确描述时间序列的随机模型,然后将时间序列距离定义为模型之间的距离。我第一次接触到这个关于 HMMs 的想法是在 Ghassempour 等人的一篇论文中。艾尔。[2],但我不能确定它的起源。

隐马尔可夫模型上的一个非常短的 TLDR

最基本形式的隐马尔可夫模型简单地寻求使用由马尔可夫链有条件地给出的概率分布的集合来对数据建模。

作为一个例子,考虑对连续实值的单变量离散时间序列 Y 建模的任务,并且假设我们想要使用 HMM 来做这件事。该模型将由主要组件、隐藏状态排放分布组成。隐藏状态是一个有 N 个状态的马尔可夫链,这里我们要选择 N 。这意味着在每个时间 t ,模型可以处于属于状态集 S = { s _1, s _2,…, s _N}的单一状态 X_t ,并且X【T25 _ {t+1 }处于任何状态的概率简单地说,我们将这种独立性描述为马尔可夫属性

这允许我们定义一个转移概率矩阵A、其中

这里,我们将只考虑静态隐藏状态,这意味着转移概率在时间上是恒定的,这在大多数具有适当预处理的应用中是足够的。

为了获得对 Y_t 的估计,HMM 简单地从单变量高斯N(μ_tσ _ t )中采样,参数取决于状态 X_t 。这种结构允许 hmm 将时间序列 Y 的潜在行为分解成一系列 N 个可能状态,其中每个状态都遵循不同的高斯分布。

例如,如果 Y 是一个动物种群的增长率,我们可以设置 N =2 来尝试捕捉交配季节的影响,这样 X_t = s 1 对应于交配季节,其中Y _ t~N(μ 1, 而 X_t = s 2 对应的是一年的剩余时间Y _ t~N(μ 2、 σ _2)、 μ _2 非常小。

我们使用单变量高斯作为例子,但是 hmm 可以处理任何类型的分布以及这种分布的任何混合。因此,如果你有一个包含正态、分类和对数正态变量的多维时间序列,HMM 仍然可以很好地工作。参数估计过程相当冗长,所以我选择省略它,因为它可以被任何 HMM 包有效地处理。需要注意的一点是,我们可以很容易地定义这些模型的 AIC 和 BIC,这消除了在选择隐藏状态数的超参数时的一些偏差。

隐马尔可夫模型的距离度量

了解无限远处的行为

“好吧,这个 HMM 的东西很有趣,但是它和时间序列的相似性有什么关系呢?”

HMMs 的惊人之处在于,我们得到了一个随机过程,该过程对过去、现在和未来所有时间的数据的时间动态进行建模。因此,如果我们可以将 hmm 拟合到任何两个时间序列,我们可以将时间序列相似性等同于如果我们在未来对它们进行无限次采样,这两个 hmm 的输出看起来会有多相似

隐藏状态的马尔可夫特性让我们可以做到这一点。实际上,几乎所有的马尔可夫链在其状态上都有一个平稳分布 π,它给出了过程在任何时间处于任何状态的极限概率。我们可以这样表达

马氏链的一个非常方便的特性是,作为一个行向量,π是本征问题的解

其中 A 是我们的转移概率矩阵。因此,我们可以知道从我们的时间序列导出的过程在无穷远处如何表现,而不必去无穷远处本身!当然,我正在掩饰推导的细节,但是对于这些,我推荐你去看看一本关于随机过程的书。

距离度量

稳定分布是 Sahraeian 和 Yoon[3]创建的 HMM 距离度量的核心,在看到其定义后会更好理解。

设λ和λ是来自两个时间序列的两个 hmmYY ,分别具有转移概率矩阵 AA 和发射分布B={B_I}和 其中 b _i 和 b _ i 分别是λ的状态 i 和λ的状态 i 的分布。 我们将 ES (λ,λ)定义为所有可能状态对的预期概率分布,给出如下**

其中 S_e 是你选择的概率分布距离测度为 b _ ib* _ i *的正单调递减函数,如 KLD、JS 距离等。接下来,我们将对应矩阵 Q 定义为

该矩阵量化了任何 HMM 状态对的分布有多相似,并通过两个 HMM 达到这种状态对的可能性来对它们进行加权。因此,如果两个 hmm 很可能处于产生比通常更相似的排放输出的状态,那么对应矩阵 Q 将在几个条目上饱和,并且变得稀疏。否则,如果具有相似分布的状态对不太可能或者如果发射分布不相似,则相反地 Q 将不会在任何地方饱和,因此变得密集。有许多矩阵稀疏度的措施,但基尼指数是一个受欢迎的,几乎普遍通用的选择。因此,我们的时间序列相似性度量由下式给出

简而言之,直觉是,如果两个时间序列可以用很可能处于相似分布状态的隐马尔可夫模型建模,则该时间序列的相似度得分会更高。否则,如果 hmm 具有不同的动态或分布,分数将会更低

你可能要考虑的一些有用的属性/事物

  1. 对应矩阵不必是正方形,所以即使它们具有不同数量的隐藏状态,即不同的复杂性,我们仍然可以计算 HMM 相似性!
  2. 我们也可以比较在不同时间采样的时间序列,只要它们具有相同的采样频率。底层过程的随机结构毕竟是时间不变的。
  3. 如果您选择使用归一化基尼指数作为稀疏性度量,则该度量也介于 0 和 1 之间。相似度为 0 意味着时间序列毫无相似之处(比噪声更相似),而相似度为 1 意味着它们的确相似。
  4. 它对噪声很鲁棒。
  5. HMM 参数是用贝叶斯方法拟合的,所以非常短的时间序列会产生类似噪声的模型,这反映了我们无法肯定地将它们与噪声区分开来。这种做法的可取性很大程度上取决于你手头的问题。

使用道琼斯 30 指数的实际例子

为了举例说明这种 HMM 时间序列的相似性如何为我们提供有价值的见解,我们将使用它来构建一个道琼斯 30 种股票的网络,并使用它来识别 2020 年期间具有类似每日对数回报趋势的股票。所有数据都是使用tidyquant R 包从 Yahoo Finance 获取的。使用对数收益的目的与 ARIMA 的差分法相同,我们必须去除时间序列的趋势,并将其放在公共尺度上,以便我们可以适当地建模并与 hmm 进行比较。创建网络的过程可以总结如下。

  1. 对于道琼斯 30 指数成份股中的每一个对数收益率序列,我们用越来越多的隐藏状态来拟合单变量高斯 hmm,直到 AIC 开始增加,在这一点上我们停止。
  2. 我们计算所有模型之间的相似性度量,并将结果存储在邻接矩阵中。对于高斯排放分布相似性 S_e ,我们使用添加了ε的倒数 Fisher-Rao 距离以避免除以 0,对于稀疏性测量,我们使用 Sahraeian 和 Yoon 在其原始论文中定义的归一化基尼指数。
  3. 随着邻接矩阵的建立,我们将它导入 Gephi 来执行模块聚类并输出网络可视化。

结果是如下所示的网络。

每个节点标签根据其模块性聚类(即,最大化它们之间的总权重并且最小化相对于其他组的总权重的节点组)来着色,标签大小由其加权度来确定,并且对于更强的相似性权重,边被着色得更深更粗。这个网络已经很有用了,特别是如果你想用它作为空间模型的基础,但它很杂乱,我们对真正表现相似的股票更感兴趣,而不是有些相似。

因此,我们通过保留权重的前 75%来过滤网络边,并重新进行聚类。我们得到的是下面这个更容易解释的网络。

从这里你可以深入到数百种不同的分析中,但是如果我们没有使用 HMM 相似性这个神奇的工具,这一切都是不可能的。它利用 hmm 强大的理论基础,并通过比较时间序列的随机模型,将其与比较时间序列的直观思想相结合,从而产生一个易于解释的相似性度量。我希望这里的信息对你有用,也许你会在未来的项目中使用这个方法。这不是一个放之四海而皆准的解决方案,但是专业人员总是知道适合正确工作的正确工具。

参考

[1]a .安东尼亚迪斯、x .布罗萨特、j .库利亚里和 J. M .波吉(2013 年)。基于小波的函数数据聚类。《国际小波、多分辨率和信息处理杂志》11 (01),1350003。

[2] Ghassempour,s .,Girosi,f .,和 Maeder,A. (2014 年)。基于隐马尔可夫模型的多元时间序列聚类。《国际环境研究与公共卫生杂志》11 (3),2741–2763。

[3] Sahraeian,S. M. E .,& Yoon,B. J. (2010 年)。一种新的低复杂度 HMM 相似性度量。 IEEE 信号处理字母18 (2),87–90。

r 代码用于获取数据、查找相似性和构建网络矩阵

解释、插值和其他谎言|数据如何不言自明

原文:https://towardsdatascience.com/interpretation-interpolation-and-other-lies-how-data-speaks-not-for-itself-97904c73123e?source=collection_archive---------42-----------------------

为什么我们总是需要一个可信的原始数据解释层

你知道吗,到 2030 年,世界上 80%的人将通过社交媒体接收新闻。这里还有一个更令人吃惊的问题,10 个人中有 9 个人不会去检查他们读过的任何东西…

人们不处理事实,只处理对事实的解释。普通人不想知道数据中的细微差别,他们想要的是笑点。妙语销售,同行评议 50 页解释细节,不。

作者图片

所以经常听到“数据说话”。不,先生,不是的。

我在开场白中提到的两个统计数据完全是捏造的……很可能你很乐意接受这两个数据,并且在读到这一段时没有怀疑它们的准确性。

当世界各国领导人在宣布一项重大决定前引用统计数据时,我脑海中立即浮现出马克·吐温的话:“大多数人使用统计数据的方式就像一个醉汉使用灯柱一样,更多的是为了支持而不是为了启发。”显然,吐温是统计学的爱好者,他的观点更多的是解释为什么简单的统计学解释是不够的。也许我有污点,但从我的经验(在我的专业领域)来看,我知道解读数据有多难,因此我对在到达顶端之前必须经历的解读节点(理解为:对数据产生独特见解的人)的数量持悲观态度。

也许你是清白的,对世界有一个非常理想主义的看法,也许你应该停止阅读,因为我自己也不确定在这个话题上启蒙是不是一件好事。

好吧,你决定继续。我将试着强调数据可能被误解的几大类。

每当你看到斜体,这就是“解释者机器人”需要对正在讨论的概念给出一个简短的解释。

常见统计错误

有几个非常常见的统计错误可能看起来不明显,但如果你知道它们是什么,你会很容易发现它们。

  • 选择性使用平均值和中间值

意指又名平均。20 岁、25 岁、80 岁 3 个人的平均年龄为(20+25+80)/3 = 41.66 岁。中位数是位于中间的值,将下半部分与上半部分分开,在同一个示例中是 25。

你可以夸口说,一个国家的平均收入增长了 10%(由于我们惊人的政府政策),达到 40 000 兰特。但实际上,举例来说,工资中位数下降了 5%。这可能意味着(让我给你解释一下,别担心,你可以相信我)富人变得更富了,而穷人几乎没有什么变化。一个简单的省略中间值,而不是使用平均值,可以让你不说谎,但仍然看起来很好。

  • 樱桃采摘支持数据

樱桃采摘是当只有一个子集的结果,最好地代表了你试图实现的结果。例如,如果你想倡导一种投资模式,你可能只引用年份,比如说 2015-2020 年,它产生 20%的收益率。然而,如果你看看 2000 年至 2015 年间投资策略的表现,就会发现收益率为-7%。

  • 有偏样本

进行了一项在线调查,询问人们对互联网的一般可访问性。调查一致显示,互联网的使用已经有了很大的改善。嗯……在线调查的一个问题。样本从一开始就有偏差。

现在,在某些情况下,如果这些错误发生,可能是简单的人为错误造成的,但在其他情况下,人们会折磨数据,直到它告诉他们他们想听到的。

在《赤裸裸的统计》中,查尔斯·惠兰更详细地讲述了这些常见的错误是什么,以及人们如何容易地发现它们。

因果关系和相关性

相关性是两个或两个以上事物之间的相互关系或联系。

两个或更多事物之间的相互关系或联系并不意味着一个事物导致另一个事物。

光是这个话题就有书写了,我就不做太详细的阐述了。我更想做的是让你看看这有多糟糕。看看这个链接 ⁴.中提到的一些虚假相关性

其中一个例子表明,美国小姐的年龄与“蒸汽、热蒸汽和热物体谋杀”有很强的相关性。作为人类,我们可以立即感觉到这是纯粹的巧合,而计算机算法却不能。

吃冰淇淋与晒伤有关。我们过了一会儿才意识到,哦,可能是过多的阳光导致了这两种情况。

因果关系与相关性(作者图片)

这是光谱两边的两个明显的例子,简单地表明数据本身并不说话,相关性常常被误认为是因果关系。

在《人工智能 delusion⁵》中,Gary Smith 认为大数据加剧了这一问题,因为你添加了如此多可能存在关联的变量,所以不可避免地增加了虚假关联的数量。

如果我们让数据自己说话,我们会宣布离婚率主要是由人造黄油的人均消费引起的。⁴

错误数据

垃圾进,垃圾出。另一个常见的误解是,添加更多的数据会有所帮助,添加更多的数据并不能解决数据的质量问题,只会有更多的坏数据。

数据科学家被认为是 2020 年最性感的职业,他们花了大量时间寻找其他工作。⁶数据科学家希望创建推动洞察力的前沿算法,但大多数时候他们获得的数据都是垃圾,需要清理、结构化和大量工作来持续提供上述内容。

数据质量对于数据项目的成功至关重要,但数据并不是干净的。确保数据质量和一致性需要努力和资源,不能让数据自己说话。如果我们让数据自己说话,它会说普通话…倒过来…在水下。

道德偏见问题

当我们谈论训练数据时,“坏”数据可能仅仅意味着训练数据没有被很好地管理,并且其中可能有一些偏差。studies⁷最近的几项研究表明,用于训练图像识别人工智能的流行数据集包含性别偏见。例如,在厨房做饭的男人被误认为是女人,因为大部分女人的照片都是在厨房拍的。

机器学习或人工智能算法需要数据集来训练,即..训练数据。然后确定最符合数据的模型,并用于根据相似的数据集预测某些输出。

由于有偏见的训练数据,标签不准确(由杰森·布里斯科Unsplash 上拍摄)

我们生活在一个复杂的世界里,世界观不同,道德标准也随着时间的推移而变化。我们适应并改变它。我们处理信息的方式与算法处理 information⁵.的方式之间仍有很大差距

同样,关于这个主题的论文也很多,所以我会试着强调一些更糟糕的例子,这些例子应该能够说明算法是如何不考虑道德复杂性和后果的。它获取训练数据并产生输出。

  • Twitter 上的流氓能够在很短的时间内将微软聊天机器人变成种族主义者,因为在 place⁸.没有道德检查
  • 英国 Covid 评分示例——最大的受害者是来自劣势学校的高分学生,他们更有可能被降级,而来自富裕学校的学生更有可能被 raised⁹.降级

我要大胆地说,在可预见的未来,真实的人仍将参与人工智能过程。为什么?我们需要针对固有偏见主动采取应对措施。作为一个社会,我们无法在某些道德话题上达成一致,所以让机器来决定是不会让问题消失的。我不相信我们能够完全去除人工解释层。如果我错了……10 年后,我会简单地让我的私人机器人助手写一篇后续文章,为我的短视道歉,或者只是指示它删除我曾经发表过如此大胆言论的任何痕迹。

但与此同时,如果我们让数据自己说话,你会…嗯,你真的想要种族主义聊天机器人,性别歧视的图像识别和任何其他…ist 类型的行为吗?

接下来,如果你愿意,我想详细说明另一组原因,这与数据的粒度和语义有关。

数据在快速增长,从我们身上提取数据的方式也在快速增长。我确实看到了人工智能的大量使用案例和好处,但我也看到了整个领域对数据专业人员的需求日益增长,从采集(你晚上带着 Fitbit 睡觉)到根据洞察力采取行动(人工智能模型建议一张更舒适的床)。我不知道这是不是一个东西,可能需要申请专利。整个数据管道的复杂性并没有降低,而是变得越来越大(容量)、变化越来越快(速度)和越来越多变——窃取了大数据的 3 V,但符合类比。在我之前的文章中,我提到了对数据通才的需求,这些人将帮助跨越这个复杂的生态系统。

我想说的是,你需要相信解释的来源,因为如果不与原始数据真正搏斗,你就无法知道它是否被用来误导你。我们应该与数据搏斗,而不是折磨它。

当从不同的来源得出相同的结论时,它应该是真理的更好的指示。如果你发现自己引用了数百项研究中的一项,那么也许你应该问自己是否已经成为这些解释错误的牺牲品。

所以,是的,我确实同意马克·吐温的“谎言、该死的谎言和统计”,或者更确切地说,我那不太抄袭的书名

[1] *Mark Twain was a stats fan, anything else is a Damn Lie. - Aaron Fisher*. Available at: https://aaronjfisher.github.io/mark-twain-was-a-stats-fan.html
[2] Wheelan, C., 2014\. *Naked Statistics: Stripping the Dread from the Data*.
[3] Baker, L., 2018\. *Correlation Is Not Causation*.
[4] Tylervigen.com. 2021\. *15 Insane Things That Correlate With Each Other*. Available at: http://tylervigen.com/spurious-correlations 
[5] Smith, G., 2018\. *The AI delusion*.
[6] Brooks-Bartlett, J., 2021\. *Why so many data scientists are leaving their jobs*. Available at: https://towardsdatascience.com/why-so-many-data-scientists-are-leaving-their-jobs-a1f0329d7ea4> *[7]* Wiggers, K., 2021\. *Researchers show that computer vision algorithms pretrained on ImageNet exhibit multiple, distressing biases*. Available at: https://venturebeat.com/2020/11/03/researchers-show-that-computer-vision-algorithms-pretrained-on-imagenet-exhibit-multiple-distressing-biases/
[8] The Verge. 2021\. *Twitter taught Microsoft’s friendly AI chatbot to be a racist asshole in less than a day*. Available at: https://www.theverge.com/2016/3/24/11297050/tay-microsoft-chatbot-racist
[9]Walsh, B., 2021\. *How an AI grading system ignited a national controversy in the U.K.*. Axios. Available at: [https://www.axios.com/england-exams-algorithm-grading-4f728465-a3bf-476b-9127-9df036525c22.html](https://www.axios.com/england-exams-algorithm-grading-4f728465-a3bf-476b-9127-9df036525c22.html)

透过莱姆解读 LSTM

原文:https://towardsdatascience.com/interpreting-an-lstm-through-lime-e294e6ed3a03?source=collection_archive---------6-----------------------

了解如何通过 LIME 解释 Keras LSTM,并深入到文本分类器的 LIME 库的内部工作

格伦·卡丽在 Unsplash 拍摄的照片

概述

  • 我决定写这篇博客,因为我在那里找不到很多教如何在 Keras 模型中使用 LIME 的教程。当然,许多文章关注基于 Sci-kit learn 的模型,但是使用 LIME 和 Keras 需要我们编写一个额外的函数,正如我们将看到的。
  • 其次,我想解释一下 LIME 是如何适应文本分类问题的,这是我在阅读该库的文本解释器代码时才理解的。

现在来看内容,这是我将要讲述的内容

  1. 为什么我们需要解释模型
  2. 什么是石灰
  3. LIME 如何为文本工作
  4. 为分类问题构造 LSTM
  5. 通过奇特的视觉解释来解读莱姆的 LSTM

为什么我们需要解释我们的模型?

有时,特别是在医疗保健和金融等关键领域,我们希望知道模型预测背后的推理。当误差范围太窄时,我们希望确保我们的模型像人类一样思考并做出逻辑决策。仅仅得到正确的答案是不够的,我们想知道我们的模型是如何找到答案的。假设我们的分类器正在预测情感,在这种情况下,我们希望确定预测是基于指示情感的词,如“快乐”和“可怕”的词,而不是不相关的词,如某人的名字,这些词对情感没有贡献。更重要的是,解释我们的模型可以帮助减少偏见,例如,我们可以看到我们的模型是否偏向某人的种族甚至性别。帮助我们解释模型的算法属于可解释人工智能(XAI)的大范畴。

石灰背后的直觉

首先,我们根据可解释性对模型进行分类。像线性回归或(小)决策树这样的模型很容易被人类理解。然而,像神经网络和 LSTMs 这样的模型具有成千上万的权重和许多层,使得人类很难解释它们。

下面是 LIME 解决这个问题的方法。下面的图表是来自原来的 石灰 纸。

石灰是如何工作的,正如最初的石灰论文中提到的[1]

考虑上面是一个二元分类问题(红类和蓝类)

  1. 弯曲的红色和蓝色区域表示我们原始模型(我们称之为黑盒模型)的决策空间
  2. 假设我们想要解释我们的模型关于放大实例(用红色加号表示)的决定。首先,我们在这个红色实例中及其周围创建样本。
  3. 现在我们根据它们与我们想要解释的实例的接近程度对它们进行加权,然后使用我们的黑盒模型为这些实例生成预测。
  4. 现在我们有了新的本地合成数据和标签,我们在此数据上训练一个可解释的 (LIME 默认使用岭回归)模型。在训练时,我们更重视接近我们想要解释的实例的数据点
  5. 嘣!我们现在可以观察训练模型的权重,以获得关于影响黑盒模型预测的特征(及其值)的见解。

LIME 是如何处理文本数据的?

  1. 给定一个句子,我们首先为这个句子构造一个 单词包 (BoW)表示。
  2. 现在,该库从原始句子中随机选择单词,并操纵该句子,以新的单词组合/顺序生成 5000 个句子。
  3. 使用 余弦距离 对这些样本按照它们与原始句子的相似程度进行加权。
  4. 现在我们有了新的矢量化句子样本,并且知道了它们的接近度,LIME 遵循上一节提到的相同过程。

用石灰解读 LSTM

数据集

我们将致力于来自 Kaggle 的 Yelp 咖啡评论数据集。我对数据进行了预处理和清理,并使其适应二元分类任务。你可以在这里 查看全部代码。

这是预处理和清理后数据集的样子

模型

我使用了一个 LSTM 模型,它有 100 维的隐藏状态,前面有一个 32 维的嵌入层。你可以在这里看到模型摘要。

培训和结果

在仅仅训练了 2 个时期的模型之后,我们在训练数据上实现了非常高的准确度。此外,我们在测试数据上实现了类似的准确性,并获得了非常好的 F1 分数,这向我们表明,高准确性不仅仅是数据不平衡的结果。

使用石灰文本解释器解释模型

首先pip install lime

现在使用我们的类标签实例化文本解释器。

对于最重要的部分,由于我们的 Keras 模型不像 sci-kit learn 模型那样实现 predict_proba 函数,我们需要手动创建一个。这是你怎么做的。

只需使用预处理和标记化步骤,并使用模型的预测返回一个维度数组(输入大小 X num__target_classes [在我们的例子中为 2])

结果

对给定句子的解释(图片由作者提供)

首先,我们注意到的实际评分是 2/5,这不是一个很好的评价。 我们的模型正确地将带有负面情绪的输出分类为 0.82 。现在,当我们看到消极和积极的词语时,我们可以看到像 meh 和 pricing 这样的词语有助于消极情绪,而像 nice、vegan 和 fancy 这样的词语有助于积极情绪。您在这里看到的权重(针对每个突出显示的单词)是使用我们的本地(可解释)模型计算的。

结论

我们看到了如何通过自定义的 predict_proba 函数使用 LIME 解释 Keras 模型。然而,请注意,酸橙并非没有缺点,正如我们可以看到的, little 被误归类为阳性,而 food 被归类为阳性,而它根本不应该被突出显示。(至少在我看来)。LIME 仍然强大到足以解释像这样的简单问题,甚至可以用来生成全局解释(而不是单独解释每个实例)

查看我的 GitHub 其他一些项目。可以联系我 这里 感谢您的宝贵时间!

我将把它留给另一篇文章。如果你喜欢这个,这里还有一些!

参考

[1]里贝罗,M. T .,辛格,s .,& Guestrin,C. (2016 年 8 月)。“我为什么要相信你?”解释任何分类器的预测。《第 22 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集》(第 1135-1144 页)。

石灰码:https://github.com/marcotcr/lime

在假设检验中解释 AUROC

原文:https://towardsdatascience.com/interpreting-auroc-in-hypothesis-testing-a45f6f757a62?source=collection_archive---------27-----------------------

实践教程

你可能听说过统计能力,但你听说过统计能力下的面积吗?

二元决策出现在各个领域,从机器学习到假设检验。在二元分类的情况下,ROC(接收器工作特性)曲线展示了我们可能产生的两种错误之间的权衡。要将这条曲线转换成一个单一的指标,就要使用它下面的面积。这就是所谓的“ROC 曲线下面积”。它介于 01 之间,在特定概率方面有很好的解释。在假设检验中,ROC 曲线也被研究,但被称为“统计功效曲线”。然而,这条曲线下的面积并不常用作度量。

在本文中,我们将这条曲线下的面积解释为机器学习中使用的面积,并看看它如何转化为统计假设检验。我还将描述与 ROC 曲线属于同一家族的其他 7 条这样的曲线,以及它们下面的区域有什么解释。如果你使用二元分类模型,或者使用统计假设检验,或者是一个医疗从业者使用测试来诊断病人,或者只是在你的生活中做出二元决策,这篇文章将让你深入了解如何判断这些决策的质量。

I)二元决策

二元决策可能是最简单的决策。所以,有能力做决定的实体最终会一直做这些决定。战或逃大概是最古老的。

在现代世界中,二元决策并没有消失,而是出现在多个场景和领域中。例如(所有是非问题):

医学:

  1. 告诉你是否有疾病的医学检查(例如:诊断癌症的活组织检查)。

军事:

  1. 来自雷达的数据告诉你是否有飞机在你的领空。

机器学习(二元分类):

  1. 将像素块分类为包含或不包含汽车。
  2. 将电子邮件分类为垃圾邮件。(提示:支持向量机)

统计()

  1. 雄性企鹅的身高平均比雌性企鹅高吗?(提示:两个样本 t 检验)
  2. 接种疫苗的人访问 ICU 的比率是否低于未接种疫苗的人?(提示:二项式检验)
  3. 从一些真实世界过程中生成的数据是否符合特定的分布?(提示:卡方检验、Kolmogorov Smirnov 检验)

在本文中,我们将主要关注衡量做出这些二元决策的策略的质量。一旦我们对任何给定策略的表现有了一个客观的衡量标准,我们就可以将多个候选策略相互比较,并挑选出满足我们需求的“最佳”策略。从表面上看,这似乎是一个简单的问题,但在它背后有着令人惊讶的丰富的理论,在各自的领域中不断发展。我们将回顾其中的一些,试图将它们联系起来,并调查异花授粉的范围。

II)行业工具

II-A)混淆矩阵

当你做决定的时候,你可能是对的,也可能是错的。当你做二元决策时,你可能在两方面都是对的,也可能在两方面都是错的(取决于你做出的决定)。二元决策通常可以被框定为是/否问题。你的决策机制可能会做出“是”或“否”的决定。不管是哪种情况,做这个决定可能是对的,也可能是错的。对于任何二元决策的例子,假设正确的选择是“是”。我们将用 p 来表示这种可能性(表示肯定)。如果正确的选择是“否”,我们将用 n 来表示(表示否定)。当决策机制做出“是”决策时,我们用⍴(希腊语版的 p )来表示,当它做出“否”决策时,我们用 η (希腊语版的 n )来表示。如果做出的正确决定是“是”( p ),而我们的机制也说“是”(⍴),那就是真正的积极(TP)。另一方面,如果我们的机制说“不”( η ),那就是假阴性(FN)。另外两种可能性是假阳性(FP)和真阴性(TN)。我们的模型所说的和它应该说的四种组合的四种可能性(新⨉协议 2)。

这四种可能性最好用一个矩阵(一个“混淆矩阵”)来表示。列表示我们的机制做了什么,行表示它应该做什么。

图 1:计数的混淆矩阵。由作者创建。

我们从这个矩阵中的条目开始计数。但是我们也可以通过对各行进行标准化,将它们转化为概率(或“比率”)。然后计数成为比率(真阳性率或 TPR,假阳性率或 FPR,假阴性率或 FNR 和真阴性率或 TNR)。真正的否定率也叫做“召回率”。

请注意,这将使真阳性率和假阳性率不是之和为 1 (如果我们跨列进行标准化,就会发生这种情况)。参见 1 。跨列标准化为我们提供了四个额外的比率。[ 3 中所示的表格涵盖了所有这八种速率及其各种名称。

II-B)分数

与其做出“是”或“否”的艰难决定,不如我们的机制返回一个中间“分数”。这个分数越大(或者在某些情况下,越小),它应该越有信心表明正确的选择是“是”。

让我们通过一个简单的例子来说明。取下图中的绿点和红点。假设红色点表示“是”,绿色点表示“否”(举个经典的例子,这些点是雷达读数,红色标签表示敌机的存在)。

图 2:带有二进制标签(红色和绿色)的平面上的随机点。使用 pyray 创建。

对于区分这些点的简单机制,我们在中间画一条线(许多简单的机器学习模型,如支持向量机和逻辑回归,确实是这样的)。为了对一个新点进行二元决策,我们说,如果它在线的右上角,我们会说“是”,如果它在线的左下角,我们会说“否”。

图 3:根据颜色划分点的分隔线。我们的决策机制可以变成将线的一边标记为红色,另一边标记为绿色。请注意,这种机制确实会在某些方面出错。使用 pyray 创建。

在这个模型中,是什么让一个点“更绿”或“更红”?显著特征是任意点到直线的垂直距离( d )。

图 4:我们可以用点到直线的垂直距离作为分数来表示二进制标签。使用 pyray 创建。

注意,距离是矢量。大多数绿色点的矢量指向右上角,而红色点的矢量指向左下角。因为这些向量是到直线的垂直距离,它们只能有这两个可能的方向。我们可以将左下方的方向定义为正,右上方的方向定义为负。然后,我们可以对每个点的距离进行分类,并绘制成直方图,如下所示(中心线右侧为正,左侧为负)。

图 5:绘制直方图中的垂直距离。请注意,配色方案与前面的图略有不同,红色替换为黄色。希望这不会过多地分散对所演示要点的注意力。使用 pyray 创建。

上面的两个直方图是从有限数量的数据中构建的。它们只是两个连续分布的近似值。以正确答案为“否”为条件的分数分布和以正确答案为“是”为条件的分数分布。

让我们把正确答案为“否”的分数分布称为 A 并画成绿色,而正确答案为“是”的分数分布称为 B 并画成红色。

下面的图 6 显示了这一点,也显示了第 II-A 节中的混淆矩阵,这次的比率是通过对各行的条目进行标准化获得的。

在左下角绘制了两种错误率,假阴性率( FNR )和假阳性率( FPR ),而在右下角我们绘制了真阳性率( TPR=1-FNR ) 和 FPR。

图 6:显示了我们分数的两种分布,给出的正确答案是红色的“是”(A)和绿色的“否”(B)。使用 pyray 创建。

上面的图 6 是我们得到的决策规则,当我们从前面画的垂直线的距离为正时( d > 0 )说“是”,当 d < 0 说“否”。在这里画出的假设案例中,这恰好给了我们 16%的假阳性率和 25%的假阴性率。第二个数字意味着在我们天空中敌机的总数中,75%的时间我们会得到警报,而 25%的时间会从我们身边溜走。说我们在和平时期没意见。但是战争爆发了,25%的假阴性率变得不可接受。我们没有资源投资新的雷达。我们该怎么办?我们可以简单地修改决策规则,并说我们将在 d > -3 时警告敌机的存在(有效地将我们警告的阈值向左移动)。这将为我们提供更好的假阴性率。但是既然我们还在用同一个雷达,这其中一定有蹊跷。现在假阳性率更差了。这意味着我们现在会更频繁地被假警报(没有敌人,但雷达仍然发出嘟嘟声)所困扰。**

事实上,我们可以将分数 d (姑且称之为 𝛕 )的阈值移动到我们喜欢的任何值,这将为我们提供一系列决策规则。这些可以在下面的动画中看到,图 6 中的黄色点描绘出两条白色曲线。

图 7:改变分数的阈值会改变混淆矩阵中的四个比率。然后我们可以将其中任意两个绘制成曲线。在左下方,假阳性率与假阴性率一起绘制。这表明我们可以获得较低的假阳性率,但代价是较高的假阴性率。在右下角,我们用假阳性率绘制了真阳性率。这就是著名的 ROC 曲线。使用皮雷创建。

左边的曲线是假阳性到假阴性的权衡曲线。它向我们展示了,使用任何“雷达”或决策规则,我们都可以获得一系列错误率,这取决于我们希望在检测中有多积极。曲线的两个极端是点 (0,1) ,当我们无论如何都不说“是”时发生(因此没有假阳性,但假阴性率是 100% )和 (1,0) ,当我们无论如何都说“是”时发生。这两个极端显然是琐碎的,没有用的。这两个极端之间的曲线决定了我们决策机制的质量。曲线越靠近 x 轴,我们的“雷达”(或决策机制)质量就越好,因为这意味着错误率非常低。如果我们想用一个数字来表示我们的决策机制有多好,我们可以用这条曲线下的面积。曲线越靠近 x 轴,这个区域就越小,我们决策机制的质量就越好。最好的可能区域是 0 。在这篇文章的后面,我们将看到这个区域的解释是什么。

III) AUROC

假阳性对假阴性曲线下的面积越小,我们的决策机制就变得越好。当我们的决策机制变得更好时,如果我们想要一个更高的数字呢?我们可以绘制一条与假阳性到假阴性曲线类似的曲线,而不是在 y 轴上绘制真阳性率(即 1-FNR )。这给出了图 7 右下方的曲线,这就是著名的“接收机工作特性”或 ROC 曲线(这里的“接收机”是用来探测飞机的雷达)。就像我们考虑假阳性对假阴性曲线下的面积一样,我们也可以使用这条曲线下的面积作为我们决策机制质量的指标。这个区域被称为“接收机工作特性曲线下的区域”或 AUROC。很明显,最好的雷达是正负分数分布分离得非常好的雷达,AUROC 变成了一个单位正方形的面积,如下图所示 1

图 8:当分布被很好地分开时,AUROC 是 1。使用 pyray 创建。

另一方面,当正样本和负样本的分布变得相同时,可能出现最坏的值。这意味着我们的分数根本没有区分能力(无论天空中是否有飞机,雷达都产生相同的分数分布;换句话说,它不是很有用)。在这种情况下,我们可以看到绿色区域将代表 FPRTPR ,这意味着两者将变得相等,ROC 曲线将变成如下所示的 y=x 线。很明显这条线下面的面积现在是 0.5 (覆盖了正方形的一半面积)。这一定是我们的 AUROC 指标所能得到的最差的结果。

图 9:分布相同时的 ROC 曲线变为直线,其下方的面积变为 0.5。使用 pyray 创建。

红色区域是 FNR ,它将变成 1-FPR 。下面显示的是 ROC 曲线在两个分布之间分离时的行为。AUROC 的范围从其最佳值 1 到其最差值 0.5

图 10:当白色曲线变得接近直线时,AUROC 为 0.5。使用皮雷创建。

如果红色分布(阳性样本分布)位于绿色分布(阴性样本分布)的左侧,则 AUROC 降至 < 0.5 。然而,这将表明我们应该简单地改变我们说“是”的标准。当𝛕说“是”时,我们不说“是”。这个微小的变化将使我们的决策机制的性能更好,并使 AUROC 回到高于 0.5 的水平。

这个指标有许多优雅的解释。

III-A)解释

AUROC 有几种等价的解释:

  1. 期望一个随机的正数比一个随机的负数有更高的分数。
  2. 排在随机否定之前的肯定的预期比例。
  3. 如果排名在随机负数之前被拆分,则预期的真实正数比率。
  4. 排在随机肯定之后的否定的期望比例。
  5. 如果排名在随机阳性之后被拆分,则预期的假阳性率。

见[ 2 ]很多关于它是什么的精彩回答。

III-B)解释证据-1

如前所述,当正确答案为“是”时,我们会说 A 是分数分布( d ),而 B 是否定情况的分数分布, τ 是决定二元决策的阈值。ROC 曲线下的面积由下式给出:

等式 1:作为积分的 AUROC。

这里, x 是假阳性率。

为了求解这个积分,如果我们从 B 本身的分布中抽取 τ ,这将使我们的工作变得容易。这也很好地配合了解释#3。但如果我们这样做, x 就变成均匀分布在 (0,1)(标准均匀)之间。原因是 x 由下式给出:

即在 τ 处计算的分布 B 的生存函数。但是我们刚才说我们从 B 的分布中采样 τ 。由于采样一个随机变量并将其代入自己的生存函数会产生标准均匀分布,我们得到结论 x 是均匀的。我们证明了在 CDF ( F_X(x))的情况下,将随机变量插入到它自己的生存函数中;累积密度函数;随机值小于函数输入的概率);很容易对其进行修改,使其适用于生存函数,因为 CDF 和生存函数的总和为 1 :

首先,我们注意到 F_X(X) 的 CDF 与变量本身相同。

等式(2):证明将随机变量插入其自身的 CDF 或生存函数中会产生均匀分布的随机变量。

然后我们可以注意到,这只适用于标准的均匀随机变量。

将其插回到上面的 AUC 等式中,我们得到(将等式(1)中的1dx 解释为对均匀密度的积分):**

这就完成了证明。

III-C)目测 AUROC ≥ 0.5

我们之前提到过,AUROC 的最差可能值是 0.5 ,这种情况可能发生,例如,当分布 AB 完全相同时(我们将在本节描述发生这种情况时更一般的情况)。对于 AB 的任何其他分布,如果不是这种情况,我们将有一个 AUROC ≥ 0.5 或,切换我们的决定(当我们之前说“是”时说“否”,当我们之前说“否”时说“是”;以下称为“翻转策略”)将导致 AUROC > 0.5

这是因为“常规策略”(当 d > 𝛕 时说“是”,否则说“否”)和“翻转策略”(当 d < 𝛕时说“是”,否则说“否”)的 AUROC 总和为 1 。因此,当然,如果常规策略产生的 AUROC 为 0.4 ,的话,我们可以简单地切换到“翻转策略”,获得的 AUROC 为 0.6

然后我们要做的就是证明常规策略的 AUROC 和翻转策略的 AUROC 之和为 1

AB 可以是太阳下的任何分布时(我们在图中绘制的分布已经是很好的钟形曲线,但是想想有多个模式的难看的分布,向一侧倾斜,等等),这必须被显示出来。).我们将直观地展示这一点。

  1. 翻转策略用 CDF 交换生存函数

注意 ROC 曲线的 y 轴是: P(A > τ) ,x 轴是 P(B > τ) ,曲线被描绘为 τAB 的域上变化。这些被称为在 τ 处计算的 AB 的生存函数( S_A(τ)S_B(τ) )。对于翻转策略,这些会发生什么?让我们首先考虑假阳性率(FPR)。下图显示,当我们从常规策略切换到翻转策略时,误报率从 P(A > 𝛕) ,或𝛕a的生存函数到𝛕p(a<𝛕)acdf_a(𝛕】。****

图 11:翻转策略的假阳性率是使用 pyray 创建的分布 a 的 CDF。

类似地,真实正率从作为 B 的生存函数切换到作为 B 的 CDF。

图 12:翻转策略的真实正利率是使用 pyray 创建的分布 b 的 CDF。

现在我们知道了翻转策略的假阳性率和真阳性率,我们可以推断它是 AUROC。

2。翻转策略的 AUROC

首先,请注意下面图 13 中的红色和蓝色区域。红色区域就是 AUROC,它是 P(A > B) ,就像我们在上一节展示的那样。此外,蓝色和红色区域一起形成一个单位正方形。所以它们的组合面积是 1 。这意味着顶部切片的面积是 1-P(A > B) = P(A < B)。

图 AUROC 显示为红色,在它上面,蓝色区域填充了单位正方形的其余部分。使用 pyray 创建。

现在我们要绘制 CDF_A vs CDF_B 分别是 1-S_A1-S_B 。首先,我们得到了 -S_A-S_B. 的图。为此,我们否定了两个生存函数。当我们描绘出白色的 ROC 曲线 S_A vs S_B 时,我们也描绘出橙色的 -S_A vs -S_B 曲线。

图 14:从 x 轴上的 S_A 和 y 轴上的 S_B 移动到-S_A vs -S_B 曲线(橙色)。使用 pyray 创建。

现在我们有了 -S_A-S_B 的剧情。但是我们想用 1-S_B 来绘制 1-S_A 。如果我们一般有一个 y vs x 的图,想画 (y+b) vs (x+a) 的图,做法是把原点连同轴和坐标系一起移动到 (-a,-b)。这确保原点映射到新坐标系中的 (-a,-b) ,所有其他点线性映射。对于我们的 -S_A vs -S_B 曲线,我们将原点移动到 (-1,-1) ,如下图所示。

图 15:一旦我们有了-S_B vs -S_A 曲线,我们想要 1-S_B vs a-S_A 曲线,我们只需将原点连同整个坐标系一起移动到(-1,-1)。使用 pyray 创建。

这为我们提供了 CDF_A = 1-S_ACDF_B=1-S_B 的曲线图。现在,注意下面图 16 中蓝色阴影曲线下的区域。回头参考图 13,很容易看到它与蓝色区域相同,即 P(B > A)。这结束了翻转策略的 AUROC 是 P(B > A) 的事实的直观证明,这是常规策略的 1-AUROC。

图 16:以蓝色显示的 CDF_A 和 CDF_B 形成的曲线下的区域与图 13 中的蓝色区域相同。使用 pyray 创建。

注意:如果分布 AB 共享同一个中位数,并且都关于该中位数对称,那么 AUROC 必然是 0.5 。换句话说,来自 A 的样本大于来自 B 的样本的概率是 0.5 。一般来说,无论何时 P(A > B) 为 0.5(无论分布的形状有多复杂),AUROC 都是 0.5,这表明我们没有一个非常好的模型。

图 17:分布 A 和 B 的一些情况,其中 ROC 曲线改变,但其下的面积保持为 0.5。在所有这些情景中,P(A>B)=0.5。使用 pyray 创建。

III-D)其他曲线

虽然 AUROC 的解释在许多地方都有涉及,但它是 8 条此类曲线家族的一部分(我们可以在 x 轴上绘制 CDF 或生存函数,在 y 轴上绘制 CDF 或生存函数,然后在 x 轴或 y 轴上选择 A 得到 2⨉2⨉2=8 曲线),每条曲线下的区域都有类似的解释。其实所有这些区域要么是 P(A > B) 要么是 P(A < B)

我们看到 ROC 曲线只是 x 轴上分布 B 和 y 轴上分布 A 的生存函数。对我来说,假阳性对假阴性率曲线有更清晰直观的解释(在错误率权衡方面)。人们会在 x 轴上画出 B 的生存函数,在 y 轴上画出 A 的 CDF。这条曲线下的面积是P(B>A)= 1-P(A>B)。下面显示的是所有这些曲线。**

图 18:通过绘制比率混淆矩阵的不同条目,我们得到了 8 种不同的曲线。图片作者。

IV)在假设检验中

统计学与其他领域的区别在于强调产生数据的分布(例如:高斯分布、泊松过程等。)并试图理解顶层使用的模型的行为(用于做出二元决策或其他事情,如预测等。).

这是一把双刃剑。一方面,它带来了更多的可解释性、易处理性、直觉和对正在发生的事情的几乎端到端的把握,否则这是不可能的。另一方面,人们应该记住现实世界的数据很少遵循这些好的分布。人们有时会忘乎所以,忘记这一点。在某些情况下,这种与统计模型的偏差可能会严重影响模型的性能,但这并不总是一个问题。有些情况根本没什么大不了的,做二元决策就是其中之一。

IV-A)概率得分

对于一般的二元决策,我们只知道如何计算我们的分数, d (在假设检验的上下文中称为“检验统计量”),并将其与某个阈值, 𝛕 。当正确答案为“是”和“否”时,我们不一定需要知道分数的分布 AB

我们确实需要想出一个策略来选择一个适合我们用例的阈值。一种方法是简单地查看我们知道标签的过去的数据,并设置它以使我们得到的尽可能多的答案是正确的。

由于统计领域强调使用基础分布,我们在这里假设我们确实知道这两种分布。当不应该有来自模型的任何警报时,分布 B、是在所谓的“零假设”下的分数分布,当应该有警报时,分布 A 是在所谓的“替代假设”下的分数分布。这两种分布可以是世界上的任何分布,但在大多数研究的场景中,它们往往来自同一个家族(都是 t 分布,都是二项式分布,等等。).

使用分布允许我们将分数或“测试统计”转换成一个概率(“p 值”),该概率有一个很好的解释(在零假设下将观察到与测试统计相同或更极端的概率)。

使用 p 值的优势在于,我们可以对其设置阈值,而不是对原始分数设置阈值(称为“显著性阈值”)。这给了我们一个通用的、上下文无关的方法来定义这个阈值(一个非常流行的选择是 5% )。另一件好事是,如果 B 的真实世界分布确实接近我们用来将分数转换为 p 值的分布,那么我们得到的实际假阳性率将与显著性阈值相同。唯一的“危险”是,如果实际分布不同于我们假设用来计算 p 值的分布,那么实际的假阳性率就会偏离我们的显著性阈值。但这没什么大不了的,因为我们总是可以像以前一样依靠观察来校准阈值。

在这篇文章中,我们考虑的分数在 -∞∞之间。可以通过引入一个单调函数将其转换为概率,该函数将分数作为输入,并将其映射到一个介于 01 之间的数字。我们从 B-∞ 到∞上的分布开始,并将分数传递到累积分布函数(CDF 该分布小于分数的概率)。将分数( d) 转换为概率(p 值)的函数为:

q = P(B < d)

这对应于某种假设检验,在这种检验中,我们希望只有当检验统计量下降得很低时才得到警告(“单边”检验)。还有其他种类,这里就不赘述了。

对分布的不同选择, B 会给我们从分数到概率的不同映射。在下面的图 19 中,我们看到当我们假设 B 遵循正态分布和柯西分布时,分数或检验统计量是如何映射到 p 值的。

图 19:为了将分数或检验统计映射到 p 值(另一个从 0 到 1 变化的分数),我们可以使用不同分布的 CDF 或生存函数。但是,由于检验统计量在其范围内变化,所以无论选择何种分布,都将研究 0 到 1 之间所有可能的 p 值。使用皮雷创建。

由于分数或检验统计量在其范围(--∞)内变化,p 值从 0 变化到 1 。因此,ROC 曲线的形状(或上一节中的其他 8 条曲线中的任何一条)以及关于它们的其他一切都将保持不变,不管我们选择什么分布来映射 p 值。这将在[ 4 中进一步探讨。****

在假设检验的背景下,ROC 曲线被称为“统计功效”曲线。两者完全相同,x 轴为 FPR,y 轴为 TPR。

然而,在统计学的背景下,谈论“统计功效曲线下的面积”并将其用作衡量假设检验性能的方法并不常见。这样做是完全没问题的,但是,对这样一个区域的解释是,在零假设下进行的实验的检验统计量低于当备选项为真时进行的实验的检验统计量的概率。

作为一个例子,考虑一个测试,我们开始确定雄性企鹅是否比雌性企鹅平均高。我们集合了几十名男性和几十名女性,找出两组人的平均身高,并根据 t-test 转换成测试统计数据。功效曲线下的面积将是我们计算的检验统计(或“得分”)的概率(关于如何从两个样本中精确计算的详细信息,请参见维基百科关于 t 检验的文章这里)当没有差异时,将低于我们计算的(如果有差异的话)。

五)结论

总之,来自机器学习的 ROC 曲线映射到来自假设检验的统计功效曲线。机器学习中这条曲线下的面积是随机正样本比随机负样本获得更高分数的概率。在假设检验的情况下,统计功效曲线下的面积表示在替代假设下进行的实验比在零假设下进行的相同实验具有更高的检验统计量(或等价地,更低的 p 值)的概率。

_______________________________________________________

如果你喜欢这个故事,成为推荐会员:)

****【https://medium.com/@rohitpandey576/membership ****

参考

[1]为什么是 FPR+TPR!= 1https://stats . stack exchange . com/questions/144861/why-the-sum of-true-positive and-false-positive-not-have-to-be-equal-one

AUROC 代表什么,stats . stack exchangehttps://stats . stack exchange . com/questions/132777/What-does-AUC-stand-and-What-is-it/349646 # 349646

[3]接收器操作特性维基百科文章https://en . Wikipedia . org/wiki/Receiver _ operating _ character istic

[4]假设检验:空值的分布无关紧要https://towards data science . com/Hypothesis-testing-the-distribution-无关紧要-79882ba62f54

解读 CNN 模型

原文:https://towardsdatascience.com/interpreting-cnn-models-a11b1f720097?source=collection_archive---------28-----------------------

如何对我们的预测进行直观的解释

TL;DR —跳转到代码

Grad-CAM 为您的 CNN 模型的预测提供了一个区分类别的可视化解释。制导 Grad-CAM 也使可视化具有高分辨率。您可以在这里找到生成可视化效果的代码。

问题是

如今,机器学习模型被广泛用于自动化和决策制定。模型的可解释性对于调试这些模型以及在系统中建立信任都是至关重要的。当我们使用传统的机器学习解决方案,如基于树的模型时,有大量的工具可用于模型的可解释性。我们可以可视化单个的树,绘制部分相关图来理解不同特征对目标变量的影响,使用像形状值这样的技术来计算特征重要性或解释单个预测背后的因素,等等。

然而,深度学习模型通常被视为黑盒。我们投入大量数据,训练一个模型,希望它能起作用。在本文中,我们将一窥计算机视觉模型的黑箱内部——特别是,模型在进行预测时关注的是什么?是学习人类相似的直觉,看着正确的事物做出正确的预测吗?

通过 xkcd 进行机器学习

什么是好的直观解释?

对于图像分类,用于证明任何目标类别的来自模型的“好的”视觉解释应该满足两个特性:

  1. 类别区分 -它应该能够定位输入图像中的不同区域,这些区域对不同的输出类别有贡献。
  2. 高分辨率:应该能够捕捉到精细的细节。

Grad-CAM

梯度加权类激活映射(Grad-CAM)使用流入最终卷积层的任何目标概念(比如分类网络中的“狗”)的梯度来生成粗略定位图,突出显示图像中的
重要区域,用于预测概念。让我们来分解一下:

为什么要用最后的卷积层?

CNN 中更深的层捕捉更高层次的视觉结构。此外,卷积层自然保留了全连接层中丢失的空间信息(通常出现在 CNN 架构中的最后一个卷积层之后),因此我们可以预期最后一个卷积层在高级语义和详细空间信息之间具有最佳折衷。这些层中的神经元在图像中寻找特定于语义类别的信息(比如对象部分)。

生成类激活图

要生成类激活图,我们需要获取在最后一个卷积层中检测到的特征,并查看在预测输出概率时哪些特征最活跃。换句话说,我们可以将最后一个卷积层的特征图阵列中的每个通道乘以关于输出类的“该通道有多重要”,然后对所有通道求和,以获得图像中相关区域的热图。

CAM vs Grad-CAM

传统的 CAM 使用全局平均池权重来衡量最后一个卷积层的激活。CAM 的一个缺点是,它需要特征映射直接位于 softmax 层之前,因此它仅适用于在
预测之前对卷积映射执行全局平均池化的特定种类的 CNN 架构(即,conv 特征映射→全局平均池化
→ softmax 预测层)。

Grad-CAM 使用流入 CNN 最后一个卷积层的梯度信息来分配重要性值。Grad-CAM 适用于
种类繁多的 CNN 型号系列

观看 Grad-CAM 的运行

让我们拍摄一张包含一只猫和一只狗的输入图像,看看 Grad-CAM 的表现如何。

包含一只猫和一只狗的图像。(图片来自 Keras 示例在 Apache 许可下)

应用 Grad-CAM 会生成与卷积特征图大小相同的粗略热图

Grad-CAM 热图显示了最终卷积层神经元在预测中的重要性。(图片由作者提供)

然后可以调整该热图的大小,并将其叠加在原始图像上。我们可以看到,它能够非常准确地识别狗的区域和猫的区域。

对应于狗类的 Grad-CAM 热图。(图片来自 Keras 示例由作者编辑)

对应于 cat 类别的 Grad-CAM 热图。(图片来自 Keras 示例由作者编辑)

应用:使用 Grad-CAM 减少偏差

让我们离开猫和狗,看看一个更实际的用例。在有偏见的数据集上训练的模型可能无法推广到真实世界的场景,或者更糟的是,可能会延续偏见和刻板印象(性别、种族、年龄等。).以一个在图像搜索结果上训练以识别护士和医生的模型为例。

一个医生的形象。有偏模型预测这个是护士,无偏模型预测医生。我们使用 Grad-CAM 来可视化两个模型的预测。(图片来自 Grad-CAM 论文)

事实证明,搜索结果存在性别偏见——78%的医生图片是男性,93%的护士图片是女性。有偏见的模型通过看脸和发型做出了错误的预测(将医生误归类为护士)。我们使用 Grad-CAM 来可视化模型关注的区域。

使用从 Grad-CAM 可视化中获得的直觉,我们通过添加男护士和女医生的图像来减少训练集中的偏差,同时保持每个班级的图像数量与以前相同。看着白大褂和听诊器,无偏模型做出了正确的预测。这不仅对更好的推广很重要,而且对公平和道德的结果也很重要,因为在
社会中有更多的算法决策

更进一步:高分辨率

Grad-CAM 能够产生区分类别的可视化效果。但是,它会生成最终卷积层大小的热图,然后将最终卷积层的大小调整为输入图像的大小。因此,该热图是一个粗糙的低分辨率热图。

导向反向传播

如果我们对输入图像进行进一步的梯度处理,而不是停留在最终的卷积层,会怎么样?它可以生成细粒度的输入像素级热图。

这种反向传播可视化,通常称为显著图,可以通过获得损失相对于图像像素的梯度来生成。强烈影响损失的某些像素的变化将被明亮地显示。然而,这通常会产生噪声图像,并且已经表明在反向传播期间将梯度削波小于零(直观上只允许正面影响)会产生更清晰的图像。这类似于向前传播中的重新激活。这项技术被称为引导反向传播。

导向反向传播生成与输入图像大小相同的梯度热图。由于我们不需要将小特征地图的尺寸调整到输入图像的尺寸,这是构造高分辨率。然而,这里的缺点是可视化没有阶级区分。你可以看到图像中狗和猫的部分都亮了,这与狗的丢失相对应。

狗的引导反传可视化。(图片由作者提供)

但是请注意,这种可视化仍然非常有用。这只是图像大小的梯度,但它清楚地识别了猫区域、狗区域和背景区域。这可能表明,如果狗或猫的区域发生变化(比如猫显示得更突出或狗显示得不那么突出),它可以改变预测。

制导摄像机

我们可以通过合并 Grad-CAM 热图作为特征重要性来解决引导式反向传播可视化不具有类别区分性的事实。这给出了一个类区分和高分辨率的图像。

狗的引导 Grad-CAM 可视化。(图片由作者提供)

摘要

我们不要再把深度学习模型当成黑盒了。我们需要开发更多的工具和技术来窥视模型内部并理解它们。这对于验证模型不仅做出正确的预测,而且使用正确的信号做出预测是至关重要的。Grad-CAM 和引导 Grad-CAM 为理解 CNN 模型的预测提供了一种极好的方式。

这是一个包含代码的 colab 笔记本,用于生成 Grad-CAM、引导后向传播和引导 Grad-CAM 可视化。

参考

  1. Grad-CAM:通过基于梯度的定位来自深度网络的视觉解释, arXiv:1610.02391
  2. https://keras.io/examples/vision/grad_cam/
  3. https://github . com/ismailuddin/grad cam-tensor flow-2/blob/master/notebooks/grad cam . ipynb

解释令人困惑的多元线性回归结果

原文:https://towardsdatascience.com/interpreting-confusing-multiple-linear-regression-results-bd986254a939?source=collection_archive---------11-----------------------

你需要永远理解 MLR 系数的唯一技巧。

艾萨克·史密斯在 Unsplash 上拍摄的照片

多元线性回归(MLR)是数据科学家常用的工具。像 MLR 这样的推断统计工具用于推断仅从源数据无法得出的模式。在 MLR 的情况下,我们试图通过确定所有独立变量的组合与来自人口的样本的因变量之间的线性关系,来预测人口中与预测因子或独立变量变化相关的结果或因变量。要用文字说的话太多了,所以让我们快速看一些方程来保证我们的理解。首先,我们将从一个因变量的线性回归开始,其中拟合样本数据的直线具有以下方程

其中 y 是我们的结果, x1 是我们的预测值,b1 是我们的第一个系数,使得 x1 的值变化 1 导致 y 变化 b1,b0 是我们的 y 轴截距,或者当 x1 为零时直线与 y 轴相交的位置。在这种情况下,我们将使用该模型根据新的独立值 x1 来预测新的结果 y 。通过添加更多的系数独立变量*项,我们可以很容易地将它从单一线性回归扩展到多元线性回归,如下所示

除了五个独立变量和它们各自的系数,我们还有轴截距。从技术上来说,我们可以用与单一回归相同的方式轻松解释我们的系数 b1b5 ,但是,这需要一些假设,而这些假设对于现实世界中的数据并不总是完全正确的。多重和单一线性回归的主要假设是:

  1. 线性:结果和预测变量之间存在线性关系。
  2. 正态性:通过从实际值中减去预测值计算出的残差或误差遵循正态分布。
  3. 同方差:因变量的可变性对于自变量的所有值都是相等的。

除此之外,我们还经常为不完全符合这些标准的数据构建线性模型,因为在 MLR 中有许多独立变量,我们会遇到其他问题,如多重共线性,其中假设独立的变量彼此不同,以及分类变量的存在,如海洋温度被分类为冷、暖或热,而不是以度数量化。有多种方法可以处理多重共线性,例如从分析中删除两个共线预测值中的一个,但有时对于弱相关的要素,这会导致信息丢失,这对预测的影响大于帮助。您还可以将交互项添加到线性表达式中,通过将两个原始列相乘来创建新的预测值,但是解释交互项系数非常复杂。同样,分类列系数也很复杂,因为它们被解释为偏离您丢弃的类别值的变化(小心虚拟变量陷阱!).这些改进了你的 MLR 预测,但最终,使你的模型更加复杂,当你希望向你的团队成员传达你的模型已经阐明的关键要点和模式时,你不能简单地看上面方程中的系数。那么,有什么诀窍呢?当变量和分类变量之间存在交互作用时,我们如何解释单个变量对结果的影响?答案很简单:

尤达传达的信息更多的是相信你自己,你可以做任何你认为你能做的事情,但是我们要采取一个更懒惰的选择:不做。说真的,不要尝试!有一种更好的方法来观察一个预测变量的变化导致的结果变量的变化,而不是试图解释复杂模型中的系数,而就是诀窍。

让我们来看看 Kaggle 上的一个流行数据集的多元线性回归结果,King County USA 的房屋销售,这是一个关于 2014 年 5 月至 2015 年间在华盛顿州西雅图及其周围出售的房屋的信息集合,作为解释 MLR 预测的演示。回归希望预测销售价格,并有许多预测因素,包括卧室和浴室的数量,居住面积的平方英尺,楼层数,以及 15 个左右的其他因素。在良好的回归实践中,我们可以在清理数据集后消除其中一些,并使用 Pandas 数据框架构建基线普通最小二乘模型,如下所示:

虽然在观察它们与销售价格的关系时,这些列中的许多列不能满足上述假设,但是具有一些额外构造特征的最终 MLR 模型仍然产生了不错的结果。使用最终模型来预测下面虚拟房屋的价格,其中大多数预测值的列中值位于该县人口最多的邮政编码区,有三间卧室,最常见的质量等级为 7,我们估计为 559,299 美元。

其他三个在同一个邮政编码同一个县等级(N = 124)的卧室,均价 588888 美元。我们的预测相当不错!此外,误差计算表明,我们的 MLR 模型将在 95 %的时间内正确预测 75,000 美元范围内的房价。然而,这种准确性是通过添加两个相互作用项并将一些列更改为分类列来实现的,这是一种改进上面提到的 MLR 模型的技术,如果您不熟悉,我鼓励您进行研究。我不会告诉你最终数据框架的细节,但是与上面数据框架信息中显示的十几个预测器相比,最终模型使用了 117 个预测器!那么,我们如何运用我们的“不做”策略来观察,比如说,如果增加一间浴室,房子的价格会有什么变化呢?无论您是使用 sci-kit learn、statsmodels 还是任何其他库来生成 MLR 模型,您的模型类无疑都有一个 predict callable。因此,我们可以只改变一个预测参数,在这种情况下是一个家庭特征,然后看看新的预测结果是什么!例如,如果上面的房子有一个额外的浴室,新的价格预测将是 570,099 美元。多一间卧室,554796 美元。国王郡的成绩从 7 级提高到 8 级,607,850 美元。

如果我们想象一个商业案例,我们可以看到这是一种解释结果变化的有用方法,它与我们的独立变量的变化有关。假设你经营一家卖房子的公司;你想通过家居装修改变家居特征,影响卧室、卫生间、面积、等级评级等,找到能赚最多钱的家。使用这个模型,你可以预测你的房子的价格。然后,对输入预测值进行更改,看看价格预测如何变化!一个好的策略可能是在相对于静态独立变量合理的范围内改变单个变量,并根据预测结果绘制变化的变量。不需要根据 MLR 系数进行解释。当然,作为一名数据科学家,这仍然需要您做出一些解释。从上面看,我们看到,提高住宅的档次会大幅提高价格;更好的房子,更好的售价。我们还看到,增加一间卧室会降低价格。为什么会这样?嗯,其他一切都保持不变..尤其是房子的面积。这意味着你必须从其他房间拿走生活空间来创造这个新卧室。通过观察单个变量变化的结果变化,我们看到了多重共线性的影响(卧室数量通常随平方英尺而变化)和解释单个系数的挑战。在这种情况下,你会想通过增加或利用闲置空间以及增加一间卧室来增加面积,价格优势将在新的预测中反映出来。这样,我们可以使用 MLR 模型来告知我们如何在改造业务中最有效地从转手房屋中获利。

照片由米利沃伊·库哈尔Unsplash 上拍摄

因此,总的来说,当你的 MLR 模型变得复杂,你采取措施提高它们的有效性时,不要试图用系数来解释结果的变化,而不是单个预测因子的变化。在改变单一预测因子的同时创建预测,观察预测如何变化,并利用这些变化的性质来形成你的结论。

用石灰解释图像分类模型

原文:https://towardsdatascience.com/interpreting-image-classification-model-with-lime-1e7064a2f2e5?source=collection_archive---------6-----------------------

我们应该相信我们的图像分类器模型吗?

布雷特·乔丹在 Unsplash 上的照片

机器学习领域的发展速度和增长是疯狂的。如今,我们可以选择各种各样的机器学习模型来解决我们的问题。假设我们要解决一个分类任务,现在我们不仅有逻辑回归可供选择。我们也有决策树,随机森林,SVM,梯度推进,神经网络,等等,都可以做到这一点。

然而,在所有可用的机器学习模型中,我们可以同意大多数都是黑盒。这意味着大多数机器学习模型正在做一些非常复杂的事情,以至于我们再也不知道它们为什么会这样。换句话说,我们不知道我们的模型在预测某事时的思维过程。

作者图片

理解我们的机器学习模型的行为变得非常重要。仅仅根据模型的准确性来判断模型的性能是不够的,因为你的模型可能会欺骗你。让我们来看看下面的球分类器,它有一个主要的工作:将球分类为足球或篮球。

在上图中,我们的球分类器表现非常好。它正确地预测了所有六幅图像的类别。接下来,我们对此感到满意,并继续将此模型用于生产。然而,我们不知道我们的分类器已经成功地欺骗了我们。这是为什么呢?我们来看看下面的模型解释。

结果是,我们的分类器正确地预测了一个球是足球,因为人体部位,而不是因为球本身。所以我们的分类器不是试图在足球和篮球之间进行分类,而是在人体部位和篮球之间进行分类。显然,这不是我们想要的,因此,我们不应该仅仅基于它的准确性来信任我们的模型。

不幸的是,解释我们的黑盒模型的行为,就像深度神经网络一样,是一件非常困难的事情。

这就是我们需要石灰的地方。

什么是石灰,它是如何工作的

石灰代表 L 局部的 I 不可解释的 M 模型不可知的 E 解释。它是一个 Python 库,基于 Ribeiro 等人的论文来帮助你理解你的黑盒分类器模型的行为。目前,您可以将 LIME 用于对表格数据、图像或文本进行分类的分类器模型。

LIME 这个缩写本身应该会让你对其背后的核心思想有一个直觉。石灰是:

  • 模型不可知,这意味着 LIME 是模型独立的。换句话说,LIME 能够解释你能想到的任何黑盒分类器。
  • 可解释的,这意味着 LIME 为您提供了一个解决方案来理解为什么您的模型会有这样的行为。
  • 局部,这意味着 LIME 试图通过近似你的模型的局部线性行为来找到你的黑盒模型的解释。

让我们看看下面的图片,以了解更多关于石灰是当地的。

作者图片

假设你有一个非线性边界的特征空间,如左图所示。位于黑色曲线内的数据点将被归类为 A ,否则将被归类为 B 。现在我们想预测上图中用红星表示的数据点的类别。LIME 将进入红星点的邻近区域,而不是查看全局行为(左图),这样它就变得非常局部,线性分类器可以解释您的模型的预测(右图)。

接下来,我们来看看 LIME 是如何一步步解释模型的行为的。

石灰是如何工作的

在内部,LIME 试图通过以下四个步骤来解释黑盒模型:

1。输入数据排列

正如您在上面的图像中所看到的,假设我们想要 LIME 来解释为什么由红星表示的数据点被分类到一个类中而不是另一个类中。LIME 要做的第一步是创建几个人造数据点,这些数据点与红星表示的数据接近。

作者图片

如果我们的输入数据是一个图像,LIME 将通过打开和关闭图像的一些超像素来生成几个与我们的输入图像相似的样本。

2。预测每个人工数据点的类别

接下来,LIME 将预测使用我们的训练模型生成的每个人工数据点的类别。如果你的输入数据是一个图像,那么每个扰动图像的预测将在这个阶段生成。

3。计算每个人工数据点的权重

第三步,计算每个人工数据的权重,衡量其重要性。为此,首先通常应用余弦距离度量来计算每个人工数据点相对于原始输入数据的距离。接下来,将使用核函数将距离映射为 0 到 1 之间的值。距离越近,映射值越接近 1,因此权重越大。权重越大,某个人工数据点的重要性就越大。

如果输入数据是图像,那么将计算每个扰动图像和原始图像之间的余弦距离。扰动图像与原始图像之间的相似性越大,其权重和重要性就越大。

4。拟合一个线性分类器来解释最重要的特征

最后一步是使用加权的人工数据点拟合线性回归模型。在这一步之后,我们应该得到每个特征的拟合系数,就像通常的线性回归分析一样。现在,如果我们对系数进行排序,具有较大系数的特征是在确定我们的黑盒机器学习模型的预测中起重要作用的特征。

用石灰解释图像分类器

现在我们知道了 LIME 是如何工作的,让我们用它来解释我们的机器学习模型的行为。在本文中,我们将创建两个图像分类模型:一个使用自定义模型,另一个使用预训练的 InceptionV3 模型。

让我们先加载数据。

正在加载数据集

我们将要使用的数据集是你可以在 Kaggle 上免费下载的狗-猫-熊猫数据集。它总共包含了 3000 张狗、猫和熊猫的图片。

如果您刚刚下载了它,那么您需要解压缩文件。接下来,确保您的文件夹中有以下结构。

dog-cat-panda/

    dog/
      img_1.jpg
      img_2.jpg
      ..... cat/
      img_1.jpg
      img_2.jpg
      ......... panda/
      img_1.jpg
      img_2.jpg
      ...........

现在,我们可以使用 TensorFlow 的图像生成器来生成我们的训练和测试数据。在下面的代码中,我们希望将数据分成 80%的训练数据和 20%的测试数据。

就这样,我们成功地生成了数据!

创建自定义模型和预训练的 InceptionV3 模型

现在是我们创建自定义图像分类器模型的时候了。在展平之前,该模型由三个卷积层组成,一个全连接层作为模型的最后一层。

接下来,我们来编译和训练模型。对于本文,我们将使用 Adam 优化器、准确性指标,当然还有分类交叉熵损失函数。

太好了!在这个步骤之后,现在模型准备好对输入图像进行预测。但在此之前,我们先创建一个基于 InceptionV3 的预训练模型。我们可以用一行代码加载预训练的模型,如下所示。

from tensorflow.keras.applications import inception_v3 as inc_net

现在,让我们使用模型来预测我们的输入图像,看看 LIME 如何帮助我们理解模型的行为。

用石灰解释自定义模型的预测

假设我们希望我们的自定义模型对下面的熊猫图像进行预测:

第一步是将输入图像预处理成定制模型可以读取的格式。在读取和转换输入图像之后,我们可以使用我们的自定义模型来预测我们的输入图像。

而且我们的自定义模型正确预测了图像中的动物是熊猫!如你所见,我们的模型以合理的确定性预测,即 81%的概率。

但是正如前面提到的,我们并不确定为什么我们的模型将图像中的动物归类为熊猫。是什么让我们的模型认为我们形象中的动物是熊猫而不是狗或猫?这是我们使用石灰的地方。

在我们开始之前,如果您还没有安装 LIME,您可以通过键入下面的 pip 命令来安装。

pip install lime

接下来,我们需要导入所有必要的库。由于我们的输入数据是一个图像,我们将使用来自lime_imageLimeImageExplainer()方法。如果你的输入数据是表格数据,你需要使用lime_tabular中的LimeTabularExplainer()方法来代替。

现在是我们开始解释我们的定制模型的预测的时候了。我们需要做的就是从我们之前创建的explainer对象中调用explain_instance方法。

正如您在上面看到的,我们在那里传递了几个参数:

  • images —我们希望 LIME 解释的图像。
  • classifier_fn —您的图像分类器预测功能。
  • top_labels —您希望石灰显示的标签数量。如果是 3,那么它将只显示概率最高的前 3 个标签,而忽略其余的。
  • num_samples —确定 LIME 将生成的与我们的输入类似的人工数据点的数量。

接下来,我们可以将 LIME 提供的解释形象化。

现在我们知道为什么我们的模型把我们的图像归类为熊猫了!在左图中,我们可以看到只有熊猫可见的超像素被显示出来。这意味着我们的模型将我们的图像归类为熊猫,因为这些部分是超像素。

在右边的图像中,绿色的超像素区域增加了我们的图像属于熊猫类的概率,而红色的超像素区域降低了概率。

用石灰解释预训练模型的预测

现在我们想做和上面一样的步骤,但是使用预先训练好的 InceptionV3 模型。首先,我们来看看预训练的 InceptionV3 模型使用相同的输入图像的预测。下面是这样做的代码。

如你所见,预先训练好的 InceptionV3 模型也预测我们的形象是一只熊猫。准确地说是一只大熊猫。现在,让我们用与之前自定义模型相同的步骤来解释预训练模型的行为。

现在我们也知道为什么我们预先训练的模型将我们的图像分类为熊猫,而不是狗或猫。事实证明,由于熊猫的特定特征,自定义模型和预训练的 InceptionV3 模型都能够将我们的图像分类为熊猫,这是我们想要的。

暂时就这样了。希望现在你知道了 LIME 的基本方面,以及如何用它来解释我们的黑盒机器学习模型。

你可以在 这里找到本文 中涉及的完整 Jupyter 笔记本。

解读散文本:绘制文本的诱人工具

原文:https://towardsdatascience.com/interpreting-scattertext-a-seductive-tool-for-plotting-text-2e94e5824858?source=collection_archive---------31-----------------------

向下滚动查看如何解释一个伟大的工具创建的比较两个类及其语料库的情节。

下面我会告诉你如何解读这一点。-作者图片

有一些可视化文本数据的好方法,但也有很多可视化其他形式数据的好方法。文本数据是杂乱的,在被分析和可视化之前需要大量的清理工作。这并不全是坏事;在预处理阶段有大量的决策机会。有各种各样的工具和技术可以让您适应正在处理的数据。这种多样性可以让原本平淡无奇的过程变得非常有趣。然而,一旦你开始准备你的语料库数据的可视化,选项减少得相当快。在这个阶段,您通常只剩下很少的直观可视化来分析和呈现您的数据。如果你向非技术观众演示,这个问题会变得更加复杂。

幸运的是,作为数据科学领域相对较新的学生,我偶然发现了一个非常有用的工具,用于可视化和分析语料库中的文本。该工具专门用于分析两类数据。 散点图 是在散点图的基础上开发的工具,散点图是古老的笛卡尔坐标绘图工具,被许多人用来可视化两个变量之间的关系。分散文本是由T5 的杰森·凯斯勒 T7 创造的,他在开发这种资源的工作中获得了相当多的恶名。他通过许多商业展览和视频演示向对数据感兴趣的观众充分展示了分散文本的能力。他还就该主题编写了一份详细且易于阅读的白皮书,我发现这份白皮书非常有助于理解该工具,以及数据专业人员的工具包中包含该工具有多么强大。

补充说明:我发现这个资源是如此的新,这很不寻常。这是 Jason Kessler 三年前在 reddit 上发的帖子。他优雅地回应了一条评论,没有得到任何支持票。当时似乎没有足够多的人关注他的创作。在这里找到帖子

散点图(如下例)

下面是我创建的一个散点图,让你快速了解这个资源有多美。该图详细描述了来自两个独立子主题的文本: r/Homebrewingr/Winemaking 。数据被清理以移除空值、垃圾广告、重复的帖子和其中“[deleted]”或“[removed]”是帖子中的值的条目。数据也经过预处理,去除了符号、数字、空格和停用词。根据我对散文本的了解,这些步骤中有许多可能是不必要的,但我想确保我有好的数据输入,并在需要良好预处理的建模过程中使用这些数据。

图 1:散点图详细描述了r/家酿r/酿酒子页面中的帖子。注意,由杰森·凯斯勒设计,这个情节通常是互动的。在这种情况下,我只是提供了一个截图。我将在未来的某个时候部署一个交互式版本。你可以在 Jason Kessler 的 Github 页面上查看交互式散点图。在那里你会发现 Jupyter 笔记本Google Colab 笔记本,它们包含了部署分散文本的代码。-作者图片

如何解释散点图

它首先有助于理解情节。读到这里的大多数人已经知道,这个图使用了二维笛卡尔坐标系,其中每个点由两个坐标表示,一个来自 x 轴,一个来自 y 轴。这些点中的每一个点的坐标都是从每一类中的频率项中导出的。词频是词和短语的频率。如果你愿意的话,双字 n 元语法可以包含在分散文本中。y 轴代表酿酒类的术语频率,而 x 轴代表家酿类的术语频率。例如,图 1 右上角的单词“糖”在酿酒类中的词频为 195,在家酿类中的词频为 71。这些频率是它的绘图坐标(71,195),其中 71 是 x 坐标,195 是 y 坐标。在图的最右上方,您可以看到单词“sugar”所在的位置,这是两个类别的词频最高的区域。****

这里有更多的信息需要确定,所以我将展示更多的例子。看看图 1 右下角的单词“stout”。它一直在 y 轴的底部,但在 x 轴的最右边。坐标为(65,0)的这个单词在 beer 类中很常见,而在 wine 类中根本不存在。相反,单词“winemaking”的坐标是(0,95)。这个词在 Homebrewing 类中根本不存在。

精确

Kessler 在他的白皮书中指出:

精确度是一个词的辨别能力,不管它的频率如何。在分类语料库中出现一次的术语将具有完美的精确度。这(以及随后的度量)以平衡的类别分布为前提。分散文本中靠近 x 轴和 y 轴的词精度高。”

这些术语示例(‘黑啤酒’和‘葡萄酒酿造’)具有很高的精确度,并且很好地说明了凯斯勒允许我们在班级中展示区别特征的方式。

图 2:一个由我创建的图形,详细描述了具有高召回率、高精确度、高频率和高共享词比率的绘图区域。-作者图片

解读中间

代表酿酒的蓝色和代表家酿的红色提供了一个易于辨别的视觉,使观众能够快速识别文本中存在的差异。图上的黄色和橙色是识别这两个类中最常用的术语的简单方法。在这种情况下,当你走向图表的右上角时,你会发现最常用的术语,左下角是最不常用的术语。

回忆

毫不奇怪,凯斯勒在他的白皮书中也强调了召回。几乎就像他们和谐地结合在一起一样,如果不回忆起当时的情景,精确性往往无法得到强调。凯斯勒将回忆描述为“一个词在特定类别中出现的频率,或 P(词|类)”。他描述了精度的方差和回忆之间的关系,指出当我们看到回忆增加时,方差通常会减少。另一个让我顿悟的有趣发现是,他透露“回忆度极高的单词往往是停用词。对于那些需要看到停用词表有效性的人来说,这可能会产生奇迹。然而,对于该图的解释来说,最重要的是高回忆词倾向于图表的右上角(见图)。

仅仅通过这几个例子,你就可以看出散点图的绘制方式很像散点图。Kessler 使用的一项技术让它在视觉上如此吸引人,这项技术在散点图中用一种基于字母算法打破平局的方法取代了“抖动”功能。该方法更有效、更准确地使用图中的空白来显示两个类之间的关系。

正如你在这个图中看到的,你不仅可以解释词频和词频的物理相似性,还可以解释精确度和召回率等指标。当你把上面解释的所有特征结合起来,就会创造出一个易于阅读的可爱的视觉效果。

互动功能

当你完全实现散射文本时,它将具有交互功能。当你在飞机上滚动圆点时,你会看到一个带有统计数据的弹出窗口。统计数据包括两个类别每 25,000 个单词的词频。它还具有**标度 F 分数* 。词频指标真的很容易辨别。这个度量就是散射文本用作每个点的坐标。您可以看到下面用195:71/25k 单词表示的度量。*

图 3:在点上滚动时弹出-作者图片

这里的另一个指标是得分:0.06247。这被称为“分级 F 值”这个分数的确定涉及到一点数学,但是 Kessler 在这个 Github Repo 和这个 Jupyter 笔记本(也可以在 Repo 中找到) 中描述了数学,甚至强调了他在分数背后的推理。关于这个分数与你所绘制的图的关系的解释,最重要的是:

分数在-1 到 1 之间。接近零的分数在两个类别中都有相似的词频(这些是黄色和橙色的点)。接近 1 的分数的词频由阳性类别(蓝色)主导。接近-1 的分数的词频将由负类(红色)主导。红色或蓝色越深,表示分数越接近-1 或 1。

更多互动

滚动功能并不是唯一的交互性。在使用分散文本时,还有另一个非常令人满意的功能来补充您的分析。有一个“搜索图表”功能,可以以两种不同的方式使用。一种方法是使用图表左下方或右上方的查询框,这取决于浏览器的方向。另一种方法是简单地点击彩色坐标点。没有比绘图工具更直观的了。这是一个奇妙的功能。

输出才是这个特性真正有用的地方。当您使用查询框或点击单词点时,您会得到按每个单词频率细分的频率指标(如弹出窗口中所示),您还可以看到每 1000 个文档的频率(本例中的文档是 reddit 帖子)。但是等等,还有更多。此外,您还会看到一个格式良好的文档/帖子列表,其中提到了这个词。这是一个出色的工具,我想数据专业人员甚至可以为新手或非数据科学专业人员部署,用于他们自己的研究或好奇的探索。

这是使用“搜索图表”功能时实际提供的内容的简化视图。请记住,我删除了停用词,并对数据做了一些预处理,所以我的帖子不是很清晰。然而,这确实让您了解了这个特性有多有用。-作者图片

分散文本的其他亮点

正如你已经清楚看到的,散点图非常容易理解,是一种优雅的视觉效果,可以包含在各种与数据相关的演示中。关于分散文本有更深入的讨论,其中许多有趣的内容可以在 Jason Kessler 的 Github白皮书中找到。在那里你还可以找到关于使用和实现分散文本的编码笔记本和演示。我也可能会在 Medium 上发布更多关于这个话题的帖子,所以请关注我 @jamesopacich 或直接给我发消息了解更多信息。

从变压器模型解释语义文本相似性

原文:https://towardsdatascience.com/interpreting-semantic-text-similarity-from-transformer-models-ba1b08e6566c?source=collection_archive---------16-----------------------

实践教程

我们能想象搜索所使用的上下文吗?

照片由亨利·珀克斯Unsplash 拍摄

使用基于 transformer 的模型搜索文本文档非常棒;如今,使用 huggingface 库很容易实现,而且结果往往令人印象深刻。最近,我想了解为什么返回一个给定的结果——我最初的想法是各种论文和博客帖子,这些论文和博客帖子都与挖掘变形金刚内部的注意力机制有关,这似乎有点复杂。在这篇文章中,我测试了一个非常简单的方法,当使用一些简单的向量数学进行上下文搜索时,可以一瞥这些模型获得的上下文相似性。让我们试一试。

为了这篇文章的目的,我将使用来自[sentence-transformers](https://github.com/UKPLab/sentence-transformers)库的一个模型,它已经被专门优化用于进行语义文本相似性搜索。该模型实质上为传递给它的每个句子创建了 1024 维嵌入,然后可以通过相应的两个向量之间的余弦相似性来计算两个这样的句子之间的相似性。假设我们有两个问题 AB ,分别嵌入到 1024 维向量 AB 中,那么句子之间的余弦相似度计算如下:

也就是说,余弦相似度为 1 意味着问题是相同的(角度为 0),余弦相似度为-1 意味着问题非常不同。出于演示的目的,我嵌入了来自 ARC 问题分类数据集的 1700 个问题。完整的笔记本可以在 google colab 这里找到。在下面的代码片段中可以看到进行句子嵌入的基本部分:

作者代码片段

这样,我们可以很容易地在我们的问题数据库中进行搜索;假设我们有一个包含 1700 个问题的数据库,我们使用上面的代码片段将其嵌入到一个 1700×1024 的矩阵中。第一步是 L2 归一化每一行——这实质上意味着我们归一化每个问题向量,使其长度为 1,这简化了我们之前的等式,使得 AB 之间的余弦相似度只是两个向量的点积。根据前面代码片段中创建的嵌入,我们可以假设数据集中的第一个问题是我们的查询,并尝试从其余问题中找到最匹配的条目:

作者代码片段

在我的样本数据集中,第一个问题(查询)是“哪个因素最有可能导致一个人发烧?”而确定的最相似的问题是“哪个最能解释为什么一个被细菌感染的人可能会发烧?”。这是很好的搭配🙌—两个句子都与一个发烧的人有关。然而,我们如何知道算法选择特定匹配的原因不仅仅是因为它们都以单词“Which”开头?

需要记住的是,通过设计,transformer 模型实际上为我们的句子中的每个标记输出了一个 1024 维向量——这些标记嵌入被平均汇集以生成我们的句子嵌入。因此,为了获得关于用于在我们的搜索查询中找到匹配的上下文的更多信息,我们可以计算我们的查询中的每个标记和我们的搜索匹配之间的余弦距离,并绘制结果 2D 矩阵:

作者代码片段

这导致了下面的图:

作者创作的情节

现在我们可以看到查询中的每个标记和最佳搜索结果中的每个标记之间的余弦相似性。很明显,实际上“发烧”关键词被挑选出来,并且是导致搜索结果的“语义语境”的主要部分,然而,同样明显的是,有附加的成分进入语义语境,例如“开发 a”和“具有 a”与高余弦相似性分数相结合,并且关键词“人”也被挑选出来,而在两个句子中都存在的首词“which”不太重要。

这种计算所有标记嵌入之间的余弦相似性的简单技术提供了对每个标记对最终相似性得分的贡献的洞察,因此是解释模型在返回给定搜索结果时正在做什么的快速方式。必须注意的是,在进行实际搜索时,我们在计算不同句子嵌入之间的余弦相似度之前,取所有标记嵌入的平均值,这与我们在这里所做的不同——即使如此,查看查询中的每个标记嵌入如何与最佳匹配中的标记嵌入对齐,可以深入了解是什么组成了用于语义搜索的那些句子嵌入。

解释你的模型的另一种方式

原文:https://towardsdatascience.com/interpretml-another-way-to-explain-your-model-b7faf0a384f8?source=collection_archive---------6-----------------------

模型可解释性

InterpretML 包的概述,它在现有工具的基础上提供了新的可解释工具。

沃洛德梅尔·赫里先科Unsplash 上的照片

在实现 ML 模型时,可解释性是至关重要的。通过解释模型,客户可以获得对模型的信任并促进模型的采用。它还可能有助于调试您的模型,在某些情况下,您将需要为模型生成的预测提供解释。在我之前的博客文章中,我讨论了两种方法:石灰和 SHAP,我在戴尔的一个项目中使用过。

在这篇博客文章中,我将提供一个 InterpretML 包的概述,它包含一个新开发的可解释模型(可解释的助推机器),可以在全球和本地上下文中解释你的模型,以及现有的方法,如莱姆,SHAP,以及更多可以将你的模型的解释带到下一个级别的伟大的可视化。

本博客将涵盖以下内容:

  1. 解释性概述
  2. 可解释增压机(EBM)
  3. 例子
  4. 摘要
  5. 进一步阅读

1.解释性概述

InterpretML 是一个开源 Python 包,包含不同的可解释性算法,可供从业者和研究人员使用。这个包提供了两种类型的可解释性方法:玻璃盒子黑盒。glassbox 方法既包括可解释的模型,如线性回归、逻辑回归、可以作为软件包一部分训练的决策树,也包括相应的可解释工具。虽然黑盒模型只包括模型不可知的可解释性工具,如 LIME 和内核 SHAP,它们与包外训练的模型兼容,但 glassbox 模型提供了全局和局部解释,而黑盒模型只支持局部解释。此外,InterpretML 有一个内置的可视化平台,允许用户轻松地比较不同的方法。此外,由于 InterpretML 与 scikit-learn 兼容,glassbox 模型的超参数可以像其他 scikit-learn 模型一样进行调整。为了强调区别,在您的项目中使用 glassbox 模型将允许您使用 InterpretML 训练和可视化解释,而使用不同的模型将只允许您在用另一个包训练模型之后可视化由黑盒模型生成的解释。

玻璃盒子 vs 黑盒| 作者图片

最后,这个包还包括一个新的可解释模型——可解释的助推机器(EBM ),它是由微软研究人员开发的,将在下一节讨论。

2.可解释增压机(EBM)

EBM 是一个玻璃箱模型,具有与随机森林和增强树等机器学习模型相当的准确性以及可解释性能力。EBM 是一种广义加性模型(GAM ),与线性模型非常相似。在线性模型中,观测值 Y 和因变量 Xi 之间的关系用公式表示为:

Y = β0 + β1X1 + β2X2 + β3X3 + … + βnXn

而在广义加法模型中,该关系被形式化为:

Y = β0 + f(X1) + f(X2) + f(X3) + … + f(Xn)

因此,现在对预测器的每个贡献都是一些函数 f。EBM 对传统 gam 进行了一些改进:使用现代机器学习技术(如 bagging 和 boosting)来学习每个特征函数。训练在许多次迭代中进行,其中每次迭代包括为每个特征分别构建提升过程。因为这是在低学习速率下完成的,所以特征的顺序并不重要。大量的迭代旨在减轻共线的影响,以便最好地了解每个特征对模型预测的贡献。此外,EBM 可以自动检测和包含成对的交互项,这在保持其可解释性的同时增加了模型的准确性。由于 EBM 是一个附加模型,每个特征的贡献可以被捕获和可视化,因此增强了可解释性。

算法草图| 作者图片

作为进一步的解释,对于模型的每次迭代,顺序地构建小的树,并且每个树只能使用单个特征,以增强的方式更新残差,并且使用不同的特征构建新的树。这是在每次迭代中为每个特性所做的。训练完成后,我们可以查看由某个特征构建的所有树,并根据它们的预测构建一个图表,显示每个特征对预测的贡献。

3.例子

作为一个例子,我们将使用来自 Kaggle 的心力衰竭预测数据集。数据集包含 12 个可用于预测心力衰竭死亡率(死亡事件- 0/1)的特征。一些特征包括:年龄、性别、患者是否有贫血/糖尿病/高血压等。
我们将考察由 InterpretML 生成的以下模型和相应的解释:

  1. 玻璃箱

2.逻辑回归(玻璃箱)

3.使用石灰和 SHAP 的 LightGBM(黑盒)

代码的笔记本,包括交互式可视化可以在这里找到。

在进入示例之前,重要的是要注意,与莱姆和 SHAP 的实现不同,对于使用 EBM /逻辑回归的分类问题,特征的贡献被表示为对数优势而不是概率。事实上,正如在逻辑回归中所做的那样,为了得到概率,对数概率是通过一个 logit 链接函数传递的。分数显示在一个附加的对数优势空间中,因为它允许对每个特征的贡献进行公平的比较。这是由于对数比值和概率的非线性。更多信息请看这个 GitHub 问题

接下来,我将分享一些例子,说明除了可解释性之外,还可以用 InterpretML 做些什么。

循证医学

先看全局解释。

ebm_global = trained_ebm.explain_global()
show(ebm_global)

您可以查看功能的整体重要性,也可以单独查看每个功能/交互。

作者图片

每个特征的总体重要性是训练集中每个特征的绝对预测值的平均值。本质上,训练数据中的每个数据点一次使用一个特征来评分。对得分的绝对值进行平均,这将在摘要图中创建每个条形。

作者对特征 i | 图像的重要性计算

如前所述,您可以单独研究每个特性,看看特性的值如何影响得分。你还会注意到灰色标记,这些是误差线。这些是模型在特征的特定区域内的不确定性的估计。条形越宽,训练数据的微小变化的影响就越大。基于此,对这些数据点的解释应该谨慎。您可以使用以下代码访问误差线大小:

trained_ebm.term_standard_deviations_[4]

这将给出数据中第四个特征的标准偏差。

现在,让我们看看当地的解释。您可以使用以下代码一起检查几个观察结果:

ebm_local = trained_ebm.explain_local(X_test[10:15], y_test[10:15])
show(ebm_local)

作者图片

为了生成局部预测,模型使用为每个要素创建的图表作为查找表,并使用学习到的截距。

逻辑回归

让我们先来看看全局的解释:

lr_global = trained_lr.explain_global()
show(lr_global)

作者图片

这里,与循证医学相反,整体解释不仅提供了数量,还提供了符号。和以前一样,您也可以分别检查每个特性。

现在,让我们检查一下当地的解释:

作者图片

现在,您可以将 EBM 模型提供的本地解释与逻辑回归模型提供的本地解释进行比较。根据你的知识或在领域专家的帮助下,你可以决定哪一个更适合。

用石灰和 SHAP 照明

根据数据的不同,您可能希望使用 EBM 或逻辑回归之外的模型。这种原因的一个例子可能是数据中存在缺失值——虽然 LightGBM 能够处理缺失值的存在,但其他模型可能需要在训练之前填充缺失值。

与前面介绍的方法相反,使用 InterpretML 包,您不能为非 glassbox 模型生成全局解释。然而,直接使用 SHAP 将允许你这样做。另一个需要注意的要点是,通过 InterpretML 使用 SHAP,只提供了与模型无关的 KernalSHAP。直接使用 SHAP 提供了额外的解释器,如:TreeSHAP 和 DeepSHAP。

我们先来看看 SHAP:

from interpret.blackbox import ShapKernelshap = ShapKernel(predict_fn=trained_LGBM.predict_proba, data=X_train)
shap_local = shap.explain_local(X_test[10:15], y_test[10:15])show(shap_local)

作者图片

现在,让我们看看石灰:

lime = LimeTabular(predict_fn=trained_LGBM.predict_proba, data=X_train)
lime_local = lime.explain_local(X_test[10:15], y_test[10:15])show(lime_local)

作者图片

如您所见,glassbox 和 blackbox 模型的本地解释具有相同的格式。

请注意,如果数据中有一次性编码的分类要素,结果可能不完全可靠。这是因为 LIME 通过置换数据来创建解释。如果要素是热编码的,LIME 无法知道哪些列是同一原始要素的一部分,因此会创建与原始数据不一致的数据点。

要了解更多关于 SHAP、莱姆以及如何处理分类数据的信息,请查看我之前的博文

无法解释的解释

InterpretML 可用于对数据执行 EDA,该软件包使用 plotly 提供了一些基本的 EDA 功能。

from interpret import show
from interpret.provider import InlineProvider
from interpret import set_visualize_provider
set_visualize_provider(InlineProvider())
from interpret.data import ClassHistogramhist = ClassHistogram().explain_data(X_train, y_train, name="Train Data")
show(hist)

InterpretML EDA 功能|作者图片

您还可以对包中的模型进行 hypermeter 调谐。这里作为一个例子,我使用了 RandomizedSearchCV 和三重交叉验证。

from interpret.glassbox import ExplainableBoostingClassifier
from sklearn.model_selection import RandomizedSearchCVparam_test = {'learning_rate': [0.001,0.005,0.01,0.03],
              'interactions': [5,10,15],
              'max_interaction_bins': [10,15,20],
              'max_rounds': [5000,10000,15000,20000],
              'min_samples_leaf': [2,3,5],
              'max_leaves': [3,5,10]}n_HP_points_to_test=10
LGBM_clf = LGBMClassifier(random_state=314, n_jobs=-1)
LGBM_gs = RandomizedSearchCV(
    estimator=LGBM_clf,
    param_distributions=param_test,
    n_iter=n_HP_points_to_test,
    scoring="roc_auc",
    cv=3,
    refit=True,
    random_state=314,
    verbose=False,
)LGBM_gs.fit(X_train, y_train)

您可以使用以下代码通过绘制每个模型的 ROC 曲线来进一步比较结果:

from interpret import perfroc = perf.ROC(gs.best_estimator_.predict_proba, feature_names=X_train.columns)
roc_explanation = roc.explain_perf(X_test, y_test)show(roc_explanation)

作者图片

或者,通过在 show 中以列表的形式显示您希望查看的对象,您可以获得跨不同模型的结果或解释的统一视图。

show([hist, ebm_global, lr_global], share_tables=True)

您应该知道,如果您使用云环境,这是不受支持的。

4.摘要

InterpretML 提供了不同的解释方法。它还提供了 EDA 工具和强大的可视化功能,以支持对结果的更好理解,以及不同方法的比较。它绝对应该被认为是你的模型的一个可能的解释工具。软件包的 GitHub 页面(特别是 issues 选项卡)非常有用,帮助我在研究和撰写这篇博文时对软件包有了更深入的了解。

5.进一步阅读

以下是一些额外的阅读和观看建议:

1- InterpretML 文档

2- GitHub 页面

3- You Tube 视频- 解释背后的科学:可解释的助推机器

4- Paper- InterpretML:机器学习可解释性的统一框架

特别感谢 Or Herman-Saffar 和 Rachel Shalom 对这篇博文的评论和宝贵反馈。

区间估计:概述和实践者指南

原文:https://towardsdatascience.com/interval-estimation-an-overview-and-a-how-to-guide-for-practitioners-e2a0c4bcf108?source=collection_archive---------21-----------------------

米德兰海滩(来源:纽约公共图书馆数字馆藏——无限制免费使用

以及 Python 中关于如何估计总体均值区间的教程

假设你知道一个样本的平均值,你想用这个样本的平均值来估计总体平均值所在的区间。区间估计技术可用于在某个特定的置信水平下得出这一估计值。这种方法可以很容易地扩展到估计其他总体水平统计量(如方差)的区间。

举例来说,假设你在马萨诸塞州的波士顿随机调查了 100 户家庭,你发现他们的平均年收入为 65,713 美元。你能使用这个单一的数字,用一些可量化的信心衡量标准,比如 90%,来估计一下波士顿所有30 万个家庭的平均年收入范围吗?原来,你可以做到这一点!

下图说明了这种情况:

波士顿地区平均家庭收入(2021 年美元)的 90%置信区间63863,675902

在上图中,你可能会注意到,我们对波士顿所有 30 万家庭的年收入假设了某种概率分布(正态分布)。虽然对这种分布有所了解会有所帮助,但这并不是一个严格的要求。即使你完全不知道总体服从什么分布,你也可以得到未知总体均值的合理区间估计!

在现实生活决策中,区间估计比依赖点估计更有用。例如,下一次你听到一个新闻故事,说某种药物在治疗一些威胁文明的疾病时显示出 70%的疗效,你可能想检查一下药物制造商报告的 95%的置信区间。如果这个区间很宽,比如说 25%-90%,那么疗效的 70%点估计可能不能很好地反映药物的真实疗效。

估计总体均值的区间

让我们用一个真实的数据集来说明区间估计的过程。

我们将使用以下 23.7K 水样的数据集,这些水样取自 2005 年至 2021 年纽约市都会区的各个海滩。但是我们不使用整个数据集,我们将只使用纽约斯塔滕岛米德兰海滩的水样数据。

2005 年至 2021 年间从纽约市海滩采集的水质数据样本(来源: NYC OpenData 根据使用条款)(图片由作者提供)

你可以直接从 NYC OpenData 网站 下载数据,或者(最好)从 这里 下载数据集的策划版本。

我们将使用 Pandas 库将数据集加载到内存中。我们将从导入我们需要的所有 Python 包开始:

**import** math **import** pandas **as** pd
**import** numpy **as** np
**from** matplotlib **import** pyplot **as** plt
**from** scipy.stats **import** norm**#Load the data file**
df = pd.**read_csv**(**'DOHMH_Beach_Water_Quality_Data.csv'**, **header**=0, **infer_datetime_format**=True, **parse_dates**=[**'**Sample_Date**'**])

我们将重点关注为米德兰海滩收集的水质数据:

df_midland = df[df['Beach_Name']=='MIDLAND BEACH']**#print the data frame
print**(df_midland)

我们看到以下输出:

斯塔滕岛米德兰海滩的水质数据(图片由作者提供)

这是我们的样品。在我们继续下一步之前,请注意,数据框中包含微生物值的行中的 nan 太小,测量仪器无法检测。我们将用 0 替换所有这些 nan。

df_midland.**fillna**(***value=***0,**inplace**=True)

让我们打印出样本的汇总统计数据:

df_midland['Enterococci_Results'].**describe**()

米德兰海滩样本的统计摘要(图片由作者提供)

我们将打印出另一个统计数据,这是最常出现的值,也称为模式:

**print**(df_midland['Enterococci_Results'].**mode**())

我们得到该模式的值为 0,这意味着从米德兰海滩采集的大多数样品不含(或检测不到)肠球菌。

下图显示了样本值的频率分布:

plt.**hist**(df_midland['Enterococci_Results'], **bins**=100)
plt.**xlabel**('Number of Enterococci detected in the sample')
plt.**ylabel**('Number of samples')
plt.**show**()

米德兰海滩样本值的频率分布(图片由作者提供)

我们看到米德兰海滩的样本有很大的差异。

让我们回顾一下到目前为止我们所了解的数据:

  • 我们的样本量n是 969
  • 样本均值Y _ bar为 25.311042
  • 样本标准差S为 149.939190
  • 样本是高度倾斜的有利于零值(事实上它应该为任何维护良好的公共海滩!)
  • 样本有一条长尾巴。

我们不知道的是:

  • 人口的意思是,群体平均值是从 2005 年到 2021 年在米德兰海滩收集的理论上无限数量的样本中肠球菌计数的平均值。
  • 肠球菌计数的群体标准差 σ
  • 人口的频率分布

我们想知道的是:

我们能否对总体均值 可能所在的区间做一个概率估计?具体来说,我们是否可以确定一个区间[ _low,,high],使得总体均值以某种概率比如 95%位于[ _low,,high]内?

我们来看看如何估计这个区间。

我们将定义一个随机变量 Y 来表示我们要测量的量,即水样中的肠球菌数。

我们知道 Y 取值为 0、10、100、4、8 等。其单位为每 100 毫升 MPN(单位无关紧要,只要它们都采用相同的单位)。

给定一个给定的概率ρ,我们希望找出两个数 _low,high ,使得随机变量 Y 位于 _low_high 之间的概率是某个实数 ρ ,其中 0 ≤ ρ ≤1。

在符号方面,我们将这一要求表述如下:

随机变量 Y 的区间估计(图片由作者提供)

习惯上用符号 (1-α) 代替 ρ

随机变量 Y 的区间估计(图片由作者提供)

我们在这里说的是,我们想从 P 概率 D 分布 F 功能Y中划出一个区域,这样:

  1. 该区域的面积为 (1-α)
  2. 该区域从 X 轴上的开始延伸。

下图以随机变量 Y 的纯假设分布为背景说明了这种情况。记住,我们不知道人口的实际分布 Y !请注意,我们在下图中使用习惯符号 xf(x) ,因为在 X 轴上显示一个名为 Y 的变量可能会让人晕头转向!所以看到这个图中的 x 时,只要想到 Y

随机变量 x 的区间估计图(图片由作者提供)

我们再来看看下面这个表情:

随机变量 Y 的区间估计(图片由作者提供)

我们知道概率密度函数曲线下的总面积是 1.0。所以无阴影区域等于 α 。我们可以将上述等式重新表述如下:

总体平均值的置信区间(图片由作者提供)

我们可以沿着 PDF 曲线的 X 轴来回滑动 _low_high ,直到每个无阴影区域都有面积 α/2 。下图说明了这一点:

随机变量 x 的区间估计的重构(图片由作者提供)

因此,我们有:

Y 的区间估计用尾部概率 α/2【作者图片】

P(Y≤_ 低)和 P(Y≤_ 高)都是简单的累积概率,分别用C汇总* D 分配 Y 例如P(Y≤_ low)=F(_ low)=α/2。由此,我们有:*

表示为反向 CDFs 的区间界限 _low 和 _high

我们现在(暂时)假设 Y 遵循标准正态分布 N(0,1) ,即正态分布有一个零均值和一个单位标准差。

你可能会感到惊讶,我们假设 YN(0,1) 分布,因为我们已经看到 Y 远非正态分布,更不用说 N(0,1) 分布了!这里提醒一下样本【Y】的分布如何看起来像 :

米德兰海滩样本值 Y 的频率分布(图片由作者提供)

但是不用担心。

你会看到,我们将冒这个相当大胆的风险,我们仍然会逃脱!

现在,假设 Y ~ N(0,1) 的一个重要结果就是 Y CDF,即 F(。)成为φ表示的标准正态分布的 CDF(读作 Phi) 由此,F(x)=φ(【x】),因而我们有:**

根据 N(0,1)分布的逆 CDF 的高低区间估计(图片由作者提供)

让我们再跳一小步,定义一个实数 p 如下:

介绍 p 和α的关系(图片由作者提供)

由于 0≤ α ≤ 1 ,我们有: 0 ≤ p ≤ 1

接下来,我们定义一个量 z_p 如下:

使用 CDFφ(x)定义标准正态分布的 z 值(图片由作者提供)

在上面的定义中, (1-p) 解释为累积概率。例如:

p=0.95 时的 z 值(图片由作者提供)

这在下面的 N(0,1) 分布的 PDF 中有所说明:

p=0.95 时的 z 值(图片由作者提供)

类似地:

p=0.05 时的 z 值(图片由作者提供)

如下图所示:

p=0.05 时的 z 值(图片由作者提供)

因此,我们看到:

z 值的对称性(图片由作者提供)

或者,一般来说,由于围绕 0N(0,1) 分布的对称性,我们有:

对于给定的 p,两个相应的 z 值围绕 0 对称(图片由作者提供)

现在,回想一下:

根据 N(0,1)分布的逆 CDF 的高低区间估计(图片由作者提供)

因为:

在结合上述等式后,我们得到以下结果:

用 z 值表示的随机变量* Y 的高低区间值(图片由作者提供)*

我们现在可以用 z 值表示肠球菌计数 Y(1-α)100% 置信区间如下:*

用 z 值表示的随机变量* Y 的(1- α) 置信区间(图片由作者提供)*

下图显示了标准正态分布零均值附近 90%置信区间的两个 z 值:

对应于 N(0,1)分布 90%置信区间的 z 值(图片由作者提供)

让我们记住,以上所有假设肠球菌计数 Y 具有标准正态分布,尽管我们非常清楚它不是。我们必须找到解决这个致命弱点的方法。

冒着混淆一些隐喻的风险,我们现在将使用我们的黑桃 a 并通过以下两步“治愈”我们的致命弱点:

  • 我们将把 Y 重新定义为在 n 个样本中发现的肠球菌的平均计数。回想之前, Y 只是点估计,单个计数。现在,我们将 Y 重新定义为平均值,如下所示:

n 个样本的平均肠球菌计数(图片由作者提供)

这里, Y_1,Y_2,…Y_n 为样品 1,2,3,…n 中测定的肠球菌数。注意 Y_1,Y_2,…Y_n 本身是独立的,同分布的随机变量。也因此,重新定义的 YY_1,Y_2,…Y_n 的均值,也是一个随机变量。为了理解为什么平均计数也是一个随机变量,想象一下从米德兰海滩收集另一个大小为 n 的样本。它将产生不同的平均值。现在收集大小为 n 的第三个样本,你将得到第三个,可能是平均值的不同值,以此类推。因此, 的肠球菌平均计数 Y 本身就是一个随机变量 。因此,到目前为止我们得到的关于 Y 的置信区间的一切仍然成立。**

  • 现在,让我们定义另一个随机变量 Z 使得:

Z 作为 Y 的函数(图片由作者提供)

在上面的公式中:

  • n 是样本量(在我们的数据集中, n=969 )
  • σ 分别是总体均值和总体标准差。

可以看出,如果 n 是‘足够大’,那么由中心极限定理可知, Z 近似为 N(0,1)分布。

还可以看出,对于大的 n ,样本标准差 S 提供了一个总体标准差无偏估计值 简单来说,对于 Z ,我们可以将上面公式中的 σ 替换为 S

Z ~ N(0,1)(图片由作者提供)

就像 Y 一样,变量 Z 也是随机变量,但这一次, Z 有一个近似标准的正态分布。因此,我们可以将(1-α) 置信区间估计公式如下:

Z 用 Z 值表示的(1- α)置信区间估计值(图片由作者提供)

用公式代替上式中的 Z :

重新排列,我们有以下结果:

(1- α)总体均值的置信区间估计(图片由作者提供)

我们所完成的是在 (1-α) 置信水平下,得出总体均值的区间估计 [ _low,_high]

让我们使用上述公式计算在米德兰海滩收集的样本在 95% 置信水平下的区间估计值:

*****#sample size n***n = **len**(df_midland[**'Enterococci_Results'**])***#sample mean Y* Y** = df_midland[**'Enterococci_Results'**].**mean**()***#sample standard deviation*** S = df_midland[**'Enterococci_Results'**].**std**()***#significance alpha (1-alpha)*100 = 95%*** alpha = 0.05***#p-value for required alpha*** p = alpha / 2***#z value for the specified p-value*** z_p=norm.**ppf**(1-p)***#mu_low*** mu_low = **Y** - z_p*S/math.**sqrt**(n)***#mu_high*** mu_high = **Y** + z_p*S/math.**sqrt**(n)**print**(**'95% Confidence intervals for the population mean (mu)='**+str((mu_low, mu_high)))**

我们看到以下输出:

**95% Confidence intervals for the population mean (mu)=(**15.870403932430401**, **34.751680690892634**)**

相当宽的置信区间是由于样本值的高度偏斜分布,这反过来导致了较大的样本标准差 S=149.94

区间估计在回归建模中的适用性

当您训练一个回归模型时,回归变量的系数会获得它们的“拟合”值,如下所示:

观察值 Y_obs 是回归矩阵 X 的某个函数,拟合系数向量 β_cap 和回归残差 ε (图片由作者提供)

粗体符号表示这些值是矩阵。

例如,训练的线性回归模型的方程可以表示如下:

拟合线性回归模型的方程(图片由作者提供)

每个拟合系数 β_cap 都是随机变量。要了解原因,请想象该模型在另一个大小为 n 的训练样本上进行训练。在第二个样本上,拟合的系数可能呈现不同的向量值。在大小为 nβ_cap 的第三个训练样本上,将呈现另一个值向量,如此这般。因此,β_cap 中的每个 β_cap_j 都是具有某种未知分布的随机变量。

因此,每当您在训练数据集上训练您的回归模型时,您得到的仅仅是对 β_cap 的真实总体值的点估计。

在这种情况下,在某种置信水平下,知道 中每个 β_cap_j 的“真实”群体值位于哪个区间将是有用的。换句话说,在某个置信水平 (1-α)100% 下,知道β_ cap的区间估计是有用的。*

每当您训练回归模型时,您的建模软件通常会报告所有回归系数的这些置信区间。

让我们通过在肠球菌计数数据集上建立回归模型来快速演示区间估计的应用。

我们的变量如下:
Y=肠球菌 _ 结果 X=【样品 _ 位置,测量 _ 星期 _ 日,测量 _ 月】,即 3 个回归变量。

从导入所有必需的包开始:

****import** pandas **as** pd **from** patsy **import** dmatrices
**import** statsmodels.api **as** sm**

使用 Pandas 将数据集载入内存:

**df = pd.read_csv(**'DOHMH_Beach_Water_Quality_Data.csv'**, header=0, infer_datetime_format=**True**, parse_dates=[**'Sample_Date'**])**

为米德兰海滩开拓数据:

**df_midland = df[df[**'Beach_Name'**]==**'MIDLAND BEACH'**]**

添加虚拟变量:测量 _ 星期 _ 日,测量 _ 月

**df_midland['**MEASUREMENT_DAY_OF_WEEK**'] = df['**Sample_Date**'].dt.**dayofweek**
df_midland['**MEASUREMENT_MONTH**'] = df['**Sample_Date**'].dt.**month****

形成回归表达式:

***expr = 'Enterococci_Results ~ Sample_Location + MEASUREMENT_DAY_OF_WEEK + MEASUREMENT_MONTH'***

使用 Patsy 雕刻出 Xy 矩阵:

**y_train, X_train = **dmatrices**(expr, df_midland, **return_type**=**'**dataframe**'**)**

使用泊松链接函数建立并训练广义线性模型:

**poisson_training_results = sm.**GLM**(y_train, X_train, **family**=sm.families.Poisson()).**fit**()**

打印适合的模型摘要:

****print**(poisson_training_results.**summary**())**

我们看到以下输出。我已经强调了模型的拟合系数。还要注意的是 statsmodels 已经打印出 95%置信水平下系数的真实总体水平值的区间估计值:

GLM 泊松回归模型的训练输出显示了拟合系数和 95%置信水平下的相应区间估计值(图片由作者提供)

以下是本文中使用的完整源代码:

参考文献和版权

数据集

DOHMH 海滩水质数据取自 NYC OpenData 根据其使用条款

形象

横幅图片:**纽约公共图书馆美国历史、地方历史和家谱部的伊尔玛和保罗·米尔斯坦。“阳光和海水浴,米德兰海滩,斯塔滕岛,纽约[海滩上的人,远处的建筑和摩天轮。]" 纽约公共图书馆数字馆藏https://digital collections . nypl . org/items/510 d47 d9-c04b-a3d 9-e040-e00a 18064 a99自由使用,不受限制。

本文中所有其他图片的版权归 Sachin Date 所有,版权归 CC-BY-NC-SA 所有,除非图片下方提到了不同的来源和版权。

感谢阅读!如果你喜欢这篇文章,请 关注我 获取关于回归和时间序列分析的技巧、操作和编程建议。

面试系列第二部分:使用这些技巧通过行为面试

原文:https://towardsdatascience.com/interview-series-part-ii-use-these-tips-to-pass-behavioral-interviews-d6a38a2728f3?source=collection_archive---------27-----------------------

机器学习/数据科学面试系列—行为面试

照片由 LinkedIn 销售解决方案Unsplash 上拍摄

这是我在“机器学习/数据科学访谈”系列中的第二篇文章。我写的第一篇文章关注技术采访,可以在这里找到。在这篇文章中,我分享的是行为访谈。这不是一本烹饪指南,而是一本纯粹的指南,可以帮助那些将要面对行为回合的人导航。我打算清晰地表达我的学习,并与我的读者伙伴分享我在不同公司工作时获得的经验!

行为面试更加随意,他们想更多地了解你,以及你将如何融入这个组织。它可能不像技术回合那样咄咄逼人,但不应该被视为小菜一碟,这一点非常重要。这些看起来是简单的问题,但是我强烈建议你提前准备好。重要的是,你要展现出一个能顺利融入组织的伟大品格。他们真正评估你的一些事情是:

  • 你如何处理情况,你的领导能力,解决问题的能力,沟通,团队合作等。
  • 什么激励和驱使你。你过去的成就和价值观是什么?是什么让你对工作充满激情,这对公司有帮助。你足够自律和专注吗?
  • 你是一个多么好的团队成员,并且将会成为这个组织的一员。假设你有足够的同情心,并通过达成共识来容纳其他团队成员的意见。
  • 你的软技能怎么样?回答的时候有多自信,多有条理。试着更健谈,不要让它变成纯粹的独白。

它们通常持续 30-45 分钟。所有轮次的面试都直接/间接涉及到这一点,但这一轮面试的重点是行为技能。同样重要的是要知道,通常进行面试的人在大多数情况下通常是技术含量较低的人,如产品经理、项目经理、HR 等。现在,我有 3 个关于这类面试的一般和重要的提示:

准备好你的答案:如果你在谷歌上搜索,大多数问题都可以找到,95%的情况下你都会得到同样的问题。没有正确的答案,也没有解决特定问题的特定方式。但是,你必须根据你的经验来回答它们。如果你提前准备好了答案,你在面试中会显得天衣无缝。

列出你的故事:是的,根据你在网上找到的问题列出所有的故事很重要。故事可能基于你的领导能力、团队合作、紧迫的截止日期、与老板合作、压力管理等。尽可能用最好的方式表达和呈现这些情况。把相关的点写下来,这样可以提前练习,面试时被问到的时候也能流利。

要有耐心:养成倾听问题的习惯,并根据情况编一个更贴切的故事。不要急于直接回答。在回答面试官的问题之前花几秒钟是可以的,但是你的回答应该结构合理,切中要点!

除了上面所有的技巧,一个重要的框架是明星技巧。星号代表情况、任务、行动和结果。当回答特别基于情景的问题时,这是一个需要保持的重要结构。这有助于你保持简明扼要。它可以让你根据现实生活中的例子创建一个清晰的故事,而不是在不必要的细节上摸索。我将根据一个示例问题提供一个示例答案。例如,如果有人问你:“你能描述一下你的老板不在身边,你不得不处理紧急情况的时候吗?你做了什么?”

情况:

这部分主要是开始回答问题,把流程设置到你的行动和结果上。在这一部分花尽可能少的时间。例如,你可以说:“我记得有一次,我不得不在最后一刻为领导准备一份演示文稿,而我的老板不在办公室。”

任务:

开始提及你针对所描述的情况所做的具体任务。具体地说:“作为团队的高级成员,我有责任在其他团队成员的帮助下准备演示文稿。”

行动:

从 giphy.com 获得的 GIF

提及你为完成任务所采取的行动。我会说:“我安排了一次与所有团队成员的紧急会议,听取他们对如何完成演示的意见”。当谈论行动时,一件重要的事情是特别关注“我”而不是“我们”。面试官特别想知道你在那种特殊情况下做了什么。

结果:

你的回答应该说明所采取的行动发生了什么。我会说:“领导层对演示非常满意,给了他们一个关于产品下一步的好主意”。你也可以提到“他们真的为我的演讲鼓掌!通过准备演示文稿并释放我在如此短的时间内完成演示的潜力,我真的学到了很多东西。”也可以像这样:“我的项目帮助组织节省了 X 百万美元!”

从 giphy.com 获得的 GIF

记住行动和结果是最重要的!面试官想知道你做了什么,有多大影响。所以,如果可能的话,确保给出一个可量化的结果。如果无法量化,试着提供一个令人印象深刻的结果。

最后几分钟:

面试官会在最后留出 5-10 分钟来问你可能有的任何问题。还是那句话,这是一个和面试官好好交谈并更多了解公司的好时机。你应该问一些问题,表明你对这个组织有多大兴趣,并愿意了解更多。有些问题可能是这样的:

  • “你能帮我了解一下公司文化和价值观吗”?
  • “您如何展望组织未来 5-10 年的前景”。这表明你专注于成长,你想长期留下来!
  • “如何评估员工,提供哪些不同类型的计划来帮助职业发展”。

面试中的一些问题示例:

  • 告诉我一个你和同事发生冲突的时候,你做了什么?
  • 告诉我你对工作感到快乐的时候?
  • 告诉我你如何处理压力?
  • 告诉我你与你的老板意见不一致的时候?你是如何处理这种情况的?
  • 告诉我你不得不做出艰难决定的时候?
  • 说说你的 5 个缺点和 5 个优点。(不需要 STAR 方法)
  • 告诉我你对 5 年后的自己有什么看法。(不需要 STAR 方法)
  • 你为什么想为我们工作?(不需要 STAR 方法)

最后,我想在这篇文章的结尾提到,通过根据你过去的经验回答不同的行为和情境问题来练习它们。我曾经和我的另一半一起练习过。她的反馈对我即兴创作和形成我的答案帮助很大。这对我更好地交谈帮助很大。你会在网上找到很多这样的问题。请不要捏造事实。基于你过去的工作,尽可能地保持原创。他们可能会帮助你通过面试,但当你真的遇到这种情况时,你就会失败!

如果你有一个重要的观点或者你从你的经历中学到的东西,请不要犹豫地评论。感谢你抽出时间阅读这篇文章。我希望它能帮助你找到你梦想中的工作!更多这样的职位来了!敬请关注…..

推特LinkedIn 上关注我。你也可以通过 pratikkgandhi@gmail.com 联系我

面试系列第三部分:破解任何商业案例面试

原文:https://towardsdatascience.com/interview-series-part-iii-crack-any-business-case-interviews-f96679d4518d?source=collection_archive---------29-----------------------

机器学习/数据科学面试系列:你应该如何进行商业案例面试以进入下一阶段

Firmbee.comUnsplash 上拍照

这是我在“机器学习/数据科学访谈”系列中的第三篇文章。我写的第一篇文章关注的是技术采访,可以在这里找到。我写的第二篇文章关注的是行为面试,可以在这里找到。在这篇文章中,我写的是案例研究面试。

数据科学角色的一个重要前提是需要深入理解业务问题,以提供更好的、可行的、合适的解决方案。在案例研究面试中,候选人会得到一个需要使用数据解决的场景,同时牢记业务问题。问的问题通常是开放式的。目标是检查候选人在给定情况下的思维广度,利用他们的实际数据科学知识在有限的时间内提出合理的解决方案。一个人可能对业务的理解很肤浅,但却是经过深思熟虑的。

为什么是这次采访?

GIF 来自 giphy.com

进行这次面试的目的是了解你评估自己解决任何给定问题的方法的能力(将非常接近公司正在解决或过去已经解决的问题),以及你基于此得出的结论。这次面试将会模拟你在公司的主要职责。在这种类型的面试中,面试官通常会给应聘者一些分数:

  • 理解问题的能力。
  • 你是如何把问题转换成某种数学形式,然后用数据科学来解决的。
  • 考虑权衡、限制等的能力。
  • 最后,重要的一点是,如果需要,能够向非技术人员解释解决方案!

有许多候选人发现很难通过这一轮,导致面试的整体失败。毫无疑问,新手或应届毕业生不会接触到该行业的真实问题,只有在他们以某种身份工作后才能解决问题。我想说这绝对是所有面试中最困难的一轮。我在医疗保健行业工作,改变我的课程,从零售、金融和银行业的角度思考对我来说是一个挑战。我写这篇文章的目的是分享我所经历的过程,我的经验,以及一些我阅读和实施的技巧,这些可能会帮助你破解这一轮!

问了什么类型的问题:

  1. 优化指标:产品可能做得很好,但每个人都想提升自己的水平,目标完全相同。这是为了看看你是否能想出一些方法来临时制作产品。也许问题更多的是减少员工流失。可能会有这样的问题:
  • 如何让更多顾客使用沃尔玛的在线订购?
  • 你如何即兴创作亚马逊的应用程序?衡量其有效性的步骤是什么

2.实现特性:这类问题背后的想法是测试实现特性是否值得。基本上把它想成你在“测试阶段”会做什么。

  • 你如何理解网飞的一项新功能对顾客来说是否方便?
  • 在广告上多花 25%的美元会促进销售;你如何决定这是不是一个好主意?
  • 该公司销售情况良好。但该公司正考虑通过着手数字营销来临时改变策略。你会推荐什么?

这个问题主要是大量使用 A/B 测试进行营销、电子商务等的公司问的。

3.衡量成功:这比前一步前进了一步。这里的产品已经推出。现在的目标是衡量该特性/产品的成功。测量意味着可以量化的东西。这意味着需要定义与特定情况相关的成功标准。

  • 我们最近创建并推出了一个聊天机器人来帮助我们的客户。您如何确定它是否对组织和客户都有帮助?

4.诊断问题:由于某些原因,产品出现了负面趋势。面试会提供一个情况,要求你找出下降趋势的原因。

  • 拼车应用程序最近开始看到等待时间增加到 7 分钟,平均为 2-4 分钟。能是什么原因呢?
  • 上一次感恩节期间销量最高的商品类别销售额大幅下降了近 40%。这个地区是怎么回事?

战胜面试的 11 个技巧:

拉胡尔·戴伊在 Unsplash 上的照片

  1. 提出明确的问题:总是从明确问题是什么和需要完成什么开始。理解你试图解决的问题是很重要的。如果你正试图解决一个问题,推出一个功能或者你正试图增强一些东西。这将有助于你提前思考解决问题的方法。
  2. 说出你的想法:不要一有想法就抛出去。试着记下来,用一种友好的方式回答他们。这是非常重要的,你展示了一个结构化的方法来解决这个问题。来来回回表明你杂乱无章的想法不会帮助你坚持下去,解决问题。提示:在你提供一个可能的答案之前,你可以要求几分钟时间进行头脑风暴。
  3. 永远不要直截了当地说:直截了当地说从来都不是一个好主意,除非你已经处理过你试图解决的问题的数据。总是提出你的陈述“如果我们有这种类型的数据,这是可能的,等等。”面试官会注意到你在假设一些事情,并根据数据灵活地改变你的结论。
  4. 可行性:尽量想出一个实施起来简单又足够实用的方案。你要在 30 分钟左右给出一个解决方案,面试官也不指望你能给出什么特别的解决方案。不要想太多,尽量简单明了,这样才可能实现。
  5. 不要怕被卡住:碰到死胡同不要制造恐慌。和面试官交流你为什么和在哪里被卡住了。他们会在任何需要的时候提供提示。他们完全是来帮你的。
  6. 热情点:展示你的动机,为什么解决问题如此重要,以及你将如何解决它。尽你所能展示你的创造力和好奇心。
  7. 诚实是最好的策略:如果你不确定如何回答这个问题,就诚实一点。诚实远比对面试官说一些废话(抱歉,但这是真的)重要得多。
  8. 在你回答的时候,面试官可能会提出额外的问题来欺骗你。不要让曲线球使你偏离了方向。暂停片刻,重新振作起来。
  9. 大声说出你在想什么。面试官想知道你的思维过程是怎样的。不要安静!经常保持安静会引发危险信号。
  10. 友好的交谈:把它想象成和朋友或某人的一次谈话,你试图用专业的方式提供一个可行的问题解决方案。这将使你更加自信,你将能够充分发挥你的潜力。
  11. 了解公司:在参加任何面试之前,我们总是鼓励你详细了解公司的情况——他们关注的领域是什么,他们的优势是什么,最近的成就和新闻等等。尝试在他们的博客上找到任何项目;很多公司都建立了博客来分享他们的成功之路。这有助于理解公司的许多事情,并据此塑造你的大脑。

资源:

有很多阅读材料和网站可以用来准备案例研究面试。然而,YouTube 是我最喜欢学习的地方之一。以下是一些对我帮助很大的资源:

杰伊进行了一些非常出色的模拟面试。

Emma 是另一位出色的内容创作者,她分享了处理此类采访的技巧和见解。以下是我最喜欢的一些:

如果你有一个重要的观点或者你从你的经历中学到的东西,请不要犹豫地评论。感谢你抽出时间阅读这篇文章。我希望它能帮助你找到你梦想中的工作!更多这样的职位来了!敬请关注…..

推特LinkedIn 上关注我。你也可以通过 pratikkgandhi@gmail.com 联系我

想成为 中等会员 享受无限制阅读文章的乐趣,请注册成为会员。Medium 将与我分享一部分给使用以上链接注册的成员!谢了。

面试 ML 博士?下面是一些示例编码问题。

原文:https://towardsdatascience.com/interviewing-for-a-phd-in-ml-here-are-some-sample-coding-questions-a0d228155f3f?source=collection_archive---------20-----------------------

采访者和被采访者指南。

来源:https://pix abay . com/vectors/job-interview-career-conference-156130/

机器学习博士受访者通常会在各种维度上接受评估:人际关系、演示质量、技术基础和编码能力。

在博士期间,我有机会在 MPI-ISCLS 对几位博士项目候选人进行编码面试。在此之前,我首先开始在脸书公司主持编码面试,并从我的导师那里学到了不少东西(谢谢,KK!).在这篇博文中,我提出了一组问题样本,用来指导求职者完成整个过程。

问题从简单和立即可解决的进展到更微妙的。这些问题的设计方式既有直截了当的解决方案(可能不正确),也有更复杂(但不一定有效)的解决方案,为创造性讨论留下了充足的空间。

考生被鼓励写伪代码或使用他们更熟悉的语言语法;自然,鉴于这是机器学习面试,大部分考生直接用 python 写。

除了编写代码,面试还包括运行时和内存分析,涉及常用的数据结构(哈希映射和二叉树),以及基本的组合学。

不用说,大多数候选人在这组问题上表现得相当好,大多数都按时完成了(大约 40 分钟),并且似乎喜欢这种形式(我希望从我面试过的人那里得到反馈!)

让我们开始吧。

问题 1

def is_palindrome(s):
    ‘’’return True if `s` and its reverse are the same, False otherwise’’’

这个问题比较直白,无一例外,所有考生都在前 5 分钟解决。目的有两个。首先,它可以快速评估候选人,这样如果下一个问题很难回答,就可以相应地调整。更重要的是,这个问题对候选人来说是一个快速而轻松的胜利,增强了他们的信心,并为他们放松了谈话。

一些潜在的解决方案可能如下所示:

def is_palindrome(s):
    for i in range(len(s//2)): 
        if s[i] != s[-i-1]: 
            return False 
    return True

或者

def is_palindrome(s):
    return s == s[::-1]

最后,我询问运行时间,上面两个解决方案的运行时间都是 O(n)。同样,快速和轻松的胜利有助于候选人舒服地思考,就像他们在非面试环境中一样。有时,当候选人使用内置方法或库(例如,还原字符串)时,这暗示了经验,这将在接下来的问题中进一步表现出来。

问题 2

def is_anagram(a, b):
    ‘’’return True if string `a` and `b` are permutations of one another, False otherwise’’’

这是我最喜欢的问题之一,因为它有多种不同实现级别和运行时复杂性的解决方案。这鼓励了候选人的创造性思维,并经常导致有趣的讨论。

def is_anagram(a, b): 
    for c in a: 
        if c not in b: 
            return False 
    return True

这是一个简单而优雅的第一种解决方案,适用于某些输入对,例如{123,312}。但是它也错误地为{123,3124}对返回 True(试试看!).

那么我们该如何进行呢?一个看似简单的解决方法是断言 a 和 b 的长度相等,结果是:

def is_anagram(a, b): 
    assert len(a) == len(b) 
    for c in a: 
        if c not in b: 
            return False 
    return True

但是在对该解决方案进行更仔细的检查后(期望一个顶级候选人挑战他们自己的解决方案并测试极限情况),我们可以看到该解决方案并不足够,因为它对于其他对是失败的,例如,对于{122,123}错误地返回 True。

然后候选人注意到(或被提醒)输入参数 a 和 b 的顺序很重要。下一个简单的步骤是在另一个方向重复嵌套的 for 循环,结果是:

def is_anagram(a, b): 
    assert len(a) == len(b) 
    for c in a: 
        if c not in b: 
            return False 
    for c in b: 
        if c not in a: 
            return False 
    return True

在这一点上,我问候选人关于运行时间的问题。给定嵌套的 for 循环结构,这是 O(n)运行时。我还问他们是否认为解决方案是完整的,对此,大多数人给出了一个反例。特别是,下一个潜在的陷阱是如何处理重复。例如,即使使用断言和双向嵌套 For 循环,上面的代码对于{1233,1123}也是失败的。

同样,有多种方法可以解决这个问题。一旦候选人意识到他们应该考虑一个解决方案来处理重复,大多数人就开始想办法用单独的字符计数器来修改上面的代码;我很快引导他们不要从头开始实现这个,因为这很耗时,也不好玩!相反,我鼓励他们考虑可以自动存储这种计数器的数据结构。

在这里,大多数候选人指向一个散列图(字典),它除了记录重复次数之外,还记录所有独特的字符。然后,解决方案依赖于为每个输入字符串分别构造两个字典,即 char_counts_a 和 char_counts_b,然后比较这两个字典的键值对。这种解决方案与前一种解决方案相比需要更多的内存,但是,它的运行时间为 O(n ),并且可以成功地处理包含非唯一字符的字符串。

在这一点上,虽然我们已经确定了问题的解决方案,虽然答案似乎是最有效的(至少就我所知),面试可以通过评估候选人知识的其他方面继续进行。

在这里,我要求候选人创造性地思考解决这个问题的替代方法。下面是我们讨论面试中允许时间的两种额外方法。

几乎总是,当被要求创造性地思考时,候选人微笑,也许这是他们玩得开心的一个信号:)强烈鼓励!

首先,我让候选人重温一下变位词对的定义。我提醒考生,根据定义,变位词意味着两个字符串是彼此的排列。你认为基于排列的解决方案会是什么样的?提示:运行时:O(n * n!).big-O 的运行时间是相同的,有重复和没有重复,这是衡量基本组合学的另一个值得讨论的问题。

第二,我要求候选人考虑他们可能在计算机科学入门课程中学习过的替代方法(例如,排序)。你认为基于排列的解决方案会是什么样的?提示:运行时:O(n * log n)。

不言而喻,每个面试都有其独特之处,上面的回答顺序并不代表不同的候选人是如何思考和解决问题的。面试官角色的难度(是的,面试官也很难!)是在头脑中同时有许多可能的解决方案,以便帮助学生找到解决方案。评估候选人也不总是直截了当的,因为候选人在直截了当的问题上表现不佳的情况并不少见,但在更复杂的问题上很快就能看出细微差别和死角。很少有人能用一个问题来决定性地评估编码能力,因此我发现问许多小问题是加倍重要的。

问题 3

def fibonacci(n):
    ‘’’return the nth number (0-index) in the Fibonacci sequence (1,1,2,3,5,8,13), e.g., fibonacci(4) would return 5.’’’

候选人建议的一个常见的(也是好的)第一种解决方案包括对斐波那契数列数字进行 for 循环,如下所示:

def fibonacci(n): 
    fib_nums = [1,1] 
    for i in range(2,n): 
    fib_nums.append( 
        fib_nums[-1] + 
        fib_nums[-2]
    ) 
    return fib_nums[-1]

这个解决方案的运行时间为 O(n)。另一种常见的方法是递归,如下所示:

def fibonacci(n): 
    if i == 0 or i == 1: 
        return 1 
    return fibonacci(n-1) + fibonacci(n-2)

虽然这种解决方案看起来优雅而简洁,但不幸的是,它的运行时间呈指数级增长。与候选人一起完成这个运行时练习提供了许多好的信号。强有力的候选人不仅能快速识别出调用堆栈的缺陷,还能自如地使用数据结构(这里是二叉树)来导出最终的 O(2^n)run-time.最有经验的候选人也提出了改进的方法,通常诉诸于存储已经计算出的斐波那契数列的值,要么像第一个答案中那样显式地存储,要么通过缓存隐式地存储(例如,使用 python 中的 @Memoize 装饰器)。

重要的是,和许多面试一样,得出最终答案只是评估的一部分。即使候选人没有立即找到解决方案,这也是面试官评估候选人对新思想的接受程度和学习新概念的好奇心的一个机会。根据我的经验,候选人几乎总是带着这个问题愉快地离开。

最后,斐波那契数列有现有的闭合形式表达式,它依赖于黄金比例和一些相关的算术。这是一个最终的(cherry-on-top,但不是必需的)信号,候选人可以在第一个 O(n)解决方案(可以使用 8 位内存计算答案)和封闭形式的 O(1)(应该使用浮点运算运行)之间进行比较。

结论

希望你从这些面试问题样本中学到了一些东西。当然,这些问题不限于机器学习博士面试,可以更广泛地用于其他基于技术编码的面试。特别是对于 ML 职位,我认为超越最初的解决方案并精通在不同维度上衡量和对比解决方案是一项基本技能,因为我们很少遇到简单的无所不包的解决方案。这些问题(试图)评估这种能力,同时测试任何博士候选人都应该具备的快速原型制作技能的基本知识。最重要的是,这些问题是以这样一种方式构建的,即在一个平静和放松的环境中为候选人引导面试,从简单的建立信心到更困难的需要创造性思维的讨论。

在你的下一次面试中,你可以随意使用这些问题、修改后的问题或总体框架。如果你有反馈,一定要让我知道 @heikalkhan

既然我已经分享了我的秘密问题,我必须去寻找新的问题。再见!

第一份数据科学家工作的面试:期待什么以及如何准备

原文:https://towardsdatascience.com/interviewing-for-your-first-data-scientist-job-what-to-expect-and-how-to-prepare-1f3f9a977e14?source=collection_archive---------5-----------------------

办公时间数据科学面试

面试的过程、类型和成功的秘诀

艾玛丁藏加藤撰写

奥斯汀·迪斯特尔Unsplash 上拍摄的照片

如果你对如何开始成为一名数据科学家感到不知所措,你并不孤单。当你搜索“数据科学面试”时,呈现给你的是无尽的指针,包括 Python、R、统计学、A/B 测试、机器学习、大数据中的主题。你会得到阅读无数书籍的建议。令人尴尬的是,我也给过别人类似的宽泛建议。

在现实中,你不必为获得第一份数据科学工作做好一切准备。

在本帖中,我们将教你四个关键领域:

  1. 数据科学家角色的类型
  2. 你应该准备的面试类型
  3. 面试过程中会发生什么
  4. 面试官在评估什么

如果您认为我们能够以任何方式让您的旅程变得更轻松,您可以在这里联系我们!

让我们开始吧。

目录

浏览不同类型的数据科学角色

我们经常听到的一个痛点是职称令人困惑。头衔很多,产品数据科学家、机器学习数据科学家、数据科学工程师、数据分析师,名单还在不断增长。如果不熟悉行业,很难知道该报考哪些岗位。

一般来说,角色有四种类型: 分析统计数据 工程,算法。这种分类是基于拥有成熟数据科学团队的大公司(如脸书、Lyft、Airbnb、网飞)。

来源:图片由作者提供。

上面,我们描述了每个角色及其专业和示例标题。下面,我们进一步阐述。

  • **分析学。**该角色通过基于数据洞察提出建议来推动业务影响。职责包括帮助利益相关者做出基于数据的决策,执行探索性分析,定义业务指标,以及进行数据可视化(例如,仪表板)。
  • **统计。**该角色识别扩大实验规模的机会,并实施统计方法(如因果框架)来解决业务挑战。
  • 数据工程 。该角色构建可扩展的数据管道,以支持数据驱动的决策,通常面向精通数据的消费者(分析师和数据科学家)。这个角色类似于典型的数据工程师,但通常嵌入在数据科学团队中,而不是专注于服务更广泛的利益相关者(如工程师和产品经理)。
  • 算法 。这个角色通过开发统计、机器学习和优化模型来创造商业价值。通常,人们会执行探索性的数据分析,以获得对业务问题的更深入的理解,并生产模型。

尽管每个角色看起来都是独特的,但职责经常会有重叠。实际上,根据团队组成和业务需求(尤其是在较小的公司),身兼多个角色是很常见的。了解该职位的职责类型和项目对你来说很重要,在这个过程中尽早了解(通过询问招聘人员或招聘经理),这样你就能感觉到自己是否适合这个职位。

下图显示了就业市场上不同角色的分布情况。这一结果基于 2020 年 9 月至 11 月在 LinkedIn 上发布的约 1,000 个全职数据科学职位空缺。

来源:图片由作者提供。

很明显,占主导地位的是分析,而统计职位最少。因此,如果你处于数据科学职业生涯的早期, Analytics 将是一个很好的开始选择。

也就是说,哪个角色最符合你的技能、兴趣和角色可用性?选择一个,把你的注意力集中在这个角色需要的技能上,我们将在这篇文章的后面分享更多。

接下来,我们来走一遍面试过程中你应该期待的流程。

面试流程:5 个阶段

在这一部分,我们将讨论面试过程的典型阶段。请注意,虽然大多数公司都有类似的阶段,但顺序可能会有所不同。

下面,我们将深入探讨每个阶段,包括公司的目标和期望。在下一节中,我们将更详细地介绍每种类型的面试中会问到的问题类型。

来源:图片由作者提供。

1.在线评估

典型时长:30 分钟—1 小时采访类型:编码发生可能性:1/3

公司目标:公司使用在线评估来筛选出不感兴趣的候选人和没有最低技术技能的候选人。

在线评估通常在一个编码网站上完成(例如 HackerRank ),不涉及预定的面对面面试,因此它有助于更有效地选择候选人。

2.招聘人员电话屏幕

典型时长:30 分钟采访类型:行为&跨职能发生可能性:3/3

公司目标:招聘人员通常会确保职位、你的兴趣、时间表和要求(如签证)非常契合。这是一个突出候选人和公司潜在危险信号的机会。

招聘人员会从介绍公司、角色开始,有时还会介绍你面试的团队。之后,招聘人员可能会询问你的背景、时间表以及你对新职位的期望(包括薪酬)。这是一个提问的好时机,可以解决任何问题。

3.数据挑战

典型时长:1 天— 2 周采访类型:编码发生可能性:3 个中的 2 个

公司目标:数据挑战筛选出不感兴趣的候选人,并测试技术、解决问题和沟通技巧。

数据挑战通常要求您处理业务案例,并根据样本数据提供建议。有时,你会被要求写一份摘要文件或演示文稿。其他时候,会给你一系列问题来回答。您使用的方法通常很灵活,因为这一轮测试的是您解决问题的技能,而不是特定语言或工具的专业知识。也就是说,你可能使用的最常见的语言是 SQL、Python 和 r。一些公司要求你提交你的可交付成果,以确定你是否会继续前进,而其他公司可能不需要它。在这两种情况下,下一轮你被要求展示你的作品是很常见的。

4.技术电话屏幕

典型时长:30 分钟—1 小时采访类型:编码发生可能性:3 分之 2.5

公司目标:技术电话屏幕用于测试演示该角色所需的最低技术技能。

你通常会面试数据科学家或招聘经理。开始的时候,他们可能会让你介绍自己,或者谈谈你以前的经历。

之后,面试官可能会深入技术问题。问题的类型因角色而异,可能包括数据提取(SQL)、指标、统计和概率、机器学习和编码问题。通常,您最多会收到两种类型的问题。例如,如果你申请一个分析角色,你可能会得到一个数据提取和指标问题的组合。由于这种面试往往千差万别,我们建议在面试前问问你的招聘人员有什么期望。

5.现场(通常 4-6 轮)

典型时长:4-6 小时采访类型:所有发生可能性:3/3

公司目标:现场面试由多次面试组成,将测试职位所需的大部分技能。

现场面试是你获得工作机会前的最后一步,也是最重要的一步。现场采访通常比之前的采访更全面,因为它包含多次采访(通常为 4-6 次采访)。在新冠肺炎之前,大多数 onsites 都是托管在公司园区内,然而,现在它们都是虚拟的。根据你申请的职位类型,面试类型的组合可能会有所不同。例如,现场的分析角色可能有多个案例面试,而没有任何机器学习面试。我们将在下一节详细讨论这一点。

虽然上述流程描述了一般步骤,但该流程中的面试类型可能会有所不同。让我们潜入更深的地方。

7 种类型的面试

尼克·莫瑞森Unsplash 上拍摄的照片

在这一部分,我们将介绍 7 种常见的面试类型。我们还将介绍公司在寻找什么,以及如何表现出色的技巧。每次面试通常会评估 1-2 项技能和行为特征。有时候,招聘人员会明确告诉你应该关注什么,以便你做好准备。

面试可以分为技术性的和非技术性的。技术面试侧重于工作所需的“硬技能”,而非技术面试侧重于“软技能”(如沟通、领导能力)和团队配合。

下面,我们为每种类型的面试提供了简短的描述、示例问题和资源。

1.编码面试

这次面试涵盖了各种问题,如应用数据提取/操作问题、计算机科学基础(数据结构、算法和编程最佳实践)和机器学习算法。

根据角色的类型,问题可能会有所不同。几乎所有的角色都需要 SQL,所以它是一种非常通用的测试语言。

例题

  • 获取每个用户的平均购买量(SQL)。
  • 不使用中值或百分位数函数(SQL ),查找按国家分组的收入中值。
  • 寻找未排序数组的中间值(Python)
  • 编码一个经典的机器学习算法,例如 k-means,k 近邻(Python)。

顶级技巧

  • 在你开始编码之前,先和面试官一起完成你的计划,这样你就可以澄清问题并验证你的方法。
  • 你应该知道基础知识,但你不必记住所有的东西。

资源

  • 获得 SQL 面试的有用技巧(视频)。
  • 关于准备 Python 问题的综合指南(博文)。

2.数据挑战

该面试要求候选人分析样本数据集(通常以 CSV 文件形式提供),并提出解决业务问题的建议。因此,这通常要么在课后评估中完成,要么在你现场解决问题时被要求分享你的屏幕。问题的范围可以从探索性分析,到数据清理和提取(SQL)问题,到特征工程和建模练习(例如,预测或分割)。

例题

  • 给定一个客户行为数据集,定义客户流失并找出可能影响客户流失的因素。
  • 给定一个数据集购买行为,确定转化率的趋势,并提供改进建议。

顶级小贴士

  • 在开始研究领域之前,对业务问题有一个清晰的理解。提出专注于手头问题的解决方案。
  • 除非另有说明,否则不要假设数据是干净的。考虑检查边角案例,寻找异常值。如果你没有时间去查数据,明确的陈述你的假设。
  • 总结您的工作并提供后续步骤(例如,进一步探索的领域)。

资源

  • 解决各种数据挑战的在线社区( Kaggle )
  • 完成数据科学的家庭作业(博客)

3.度量(“案例”)面试

给定一个商业场景,讨论你解决问题的方法并提出建议。这些有多种形式,包括:诊断度量转变,如何衡量成功(例如,度量头脑风暴),如何权衡评估特性,以及如何改进产品。

例题

  • 您将如何调查利润的负指标变化?
  • 使用每日活跃用户(DAU)作为成功指标的利弊是什么?
  • 你会如何为 X 特性设计一个实验?
  • 如果 A/B 测试显示预期指标(即点击率)在上升,而另一个指标(即点击率)在下降,您将如何做出投放决策?

顶部提示

  • 在回答和询问澄清性问题之前,复述练习的背景和目标。
  • 问面试官几分钟,让你写下答案,并在说话前组织好你的交流。
  • 在给出完整的答案之前,先考虑简单地分享多种方法,并询问你的面试官在哪里可以分享更多的细节。

资源

4.概率统计面试

照片由斯科特·格雷厄姆Unsplash 上拍摄

这次面试将测试你对应用统计学(如实验)和概率(如贝叶斯定理)的理解。

例题

  • 你如何向一个 10 岁的孩子描述 p 值/置信区间?
  • 假设检测呈阳性,患病概率为 0.1%,那么一个人感染疾病的概率是多少?
  • 二项分布的均值和方差是什么?
  • 如何用公平币模拟偏向币?

顶部提示

  • 您可能不需要知道计算特定指标的确切公式。但是,您应该知道变量是什么以及它移动输出指标的方向(例如,置信区间随着方差的增加和样本量的减少而增加)。
  • 对于概率问题,你通常可以通过画出排列(例如,用一棵树)并将概率相加来回答问题。如果你没有得到准确的正确答案(例如,由于数学错误),尤其是如果你的方法是正确的。

资源

5.机器学习面试

这次面试包括关于机器学习基础知识和使用常用技术解决问题的问题。

例题

  • 什么是过度拟合?你如何克服过度拟合?
  • 如何处理不平衡的数据集?
  • 描述偏差与方差。
  • 描述随机森林分类器。
  • 你什么时候会使用 L1 对 L2 正则化?

顶尖技巧

  • 用 2 到 3 句话给出简明的定义。提供一两个例子,让面试官相信你既有理论知识又有经验。
  • 如有必要,提供一些常见的问题解决方案。

资源

  • 应对机器学习面试的终极指南
  • 数据科学访谈中的 4 种机器学习问题(视频)
  • 从头开始实现机器学习算法(播放列表)

6.体验面试

在这次面试中,你将与招聘经理或未来的同事讨论你以前的职业经历。这些问题大多是非技术性的行为问题。因为这种面试通常是由你面试的团队中的某个人来进行的,所以问题可能会针对团队中常见的痛点或情况。

例题

  • 告诉我一个你有重大影响的时候。背景是什么,你是如何实现的,你是如何克服挑战的?
  • 告诉我一次你解决冲突或说服利益相关者反对观点的经历。

顶部提示

  • 经常停下来,问面试官是否有任何问题,或者他们是否希望你分享某个特定话题的更多细节。
  • 在准备面试时,确定 3-5 个可以作为大多数行为面试范例的项目。写下背景、挑战、你的解决方案和影响,这样你就不必在面试时即兴发挥。

资源

7.跨职能/公司价值观面试

在这次面试中,你将被要求举例说明在以前的经历中你是如何合作的,以及在假设的情况下你会怎么做。面试的目的通常是找出非常适合公司文化的候选人。

例题

  • 告诉我一次你的建议与其他人不一致的时候。你是如何找到解决方案的?
  • 告诉我你不得不优先处理多个高紧急项目的时候。你是怎么克服的?

顶级技巧

  • 回顾“公司价值观”(通常在公司网站上)。准备一些你能体现这些价值观的情景。
  • 如果可能的话,事先调查一下你的面试官是谁。想象他们面临的挑战(例如,产品经理可能想知道你如何向利益相关者提供数据),并头脑风暴过去的经验,这些经验可能与这些情况有很好的关系。

资源

确定筹备工作重点领域的优先次序

这七种类型的面试会让人不知所措!在这一节中,我们将深入探讨如何对它们进行优先排序,以便在准备过程中保持条理和效率。

以下是一些通用提示:

  • 了解更多关于在准备过程中变得有条理的信息(视频)。
  • 在面试之前,询问招聘人员预期的面试类型(视频)。
  • 一旦你知道了这个过程,按照面试的顺序优先准备(例如,如果经验面试是第一个,那就做好准备)。如果你刚刚开始,优先考虑编码面试。

最后,根据你面试的职位类型,你应该比其他人更注重准备某些面试。下面的图表可以让你深入了解应该关注哪些领域。

来源:图片由作者提供。

您可能会注意到,编码和非技术面试是所有人都需要的,一些数据科学家不需要为每种类型的面试做充分准备。例如, Analytics 应该少关注机器学习,多关注度量(“案例”)面试。

这可以给你一个感觉,根据你的优势/劣势和你申请的职位类型,优先考虑哪里。

请记住:评估属性

虽然为硬技能做准备是有帮助的,但这通常是不够的。在整个过程中,我们会对你的其他品质进行评估。尽管每个公司都有评估这些技能的不同框架,但他们通常会寻找相同的品质。一般来说,公司希望应聘者在整个过程中能够在以下方面展现出自己的能力:

  • 沟通 —向技术和非技术受众进行有效口头和书面沟通的能力。这可以通过以连贯和逻辑的方式回答问题,以及使用例子和类比解释技术概念来证明。
  • 商业敏锐性/产品意识 —能够从实际和战略的角度思考更大的图景,以开发问题的解决方案,考虑主要的产品和业务因素,如经济、组织约束和利益相关者的观点。这可以通过在回答问题时将业务和组织背景考虑在内来证明。
  • 解决问题——将问题分解成关键部分并在给定问题约束的情况下实施适当解决方案的能力。这可以从你回答的广度和深度上看出来。
  • 协作&影响 —探索不同观点并与合作伙伴达成共识的能力。这可以通过你在面试中接受反馈的能力以及在你的回答中融入多种观点来证明。

这些属性很难准备,但是你可以通过更多的练习来展示它们。这里有三个建议:

  • 说话要考虑语境和受众:不同的受众关心的方面不同。例如,管理人员对高层次的想法和业务影响更感兴趣,而个人贡献者可能更关心技术细节。大多数受众需要对背景和上下文进行充分的阐述。
  • 不要急:花一分钟写下你的想法,把你的想法分成几组,用它们来交流。这将防止你东拉西扯,并帮助你的面试官了解你的思维过程。不要害怕和面试官交流。经常提问,让面试成为一场对话。
  • 通过分享你的个人见解来展示你对这家公司的兴趣。通过阅读公司使命陈述、营销材料和测试产品来证明你做了调查。说面试官的语言。

结束语和总结

在本文中,我们回顾了数据科学家角色的类型、常见面试、流程和成功秘诀。希望这能让你知道该期待什么,以及如何更好地寻找工作。

如果这是你旅程的开始,以下是你接下来的步骤:

  1. 选择一个要关注的角色,并对与该路径最相关的面试进行优先排序。如果你是这个领域的新手,我们推荐分析角色,优先准备编码(SQL 问题)和度量案例面试。
  2. 未雨绸缪。从你申请到录用,招聘过程通常需要 3 周多的时间。通常需要几个月。你应该争取同时收到多家公司的报价,以最大化你的选择和谈判能力。
  3. 准备好将时间投入到流程中。是的,找一份新工作就像从事第二份全职工作!
  4. 练习,练习练习。请业内朋友提供模拟面试和技巧。严格要求反馈以改进。

感谢阅读!

如果你喜欢这个帖子,想支持我…

* *

我走进森林

原文:https://towardsdatascience.com/into-the-forest-i-go-803dfbce07db?source=collection_archive---------23-----------------------

威斯特格特兰落叶松林蛾害的计算机视觉检测

瑞典的森林就像瑞士的山脉;整个国家都被它们覆盖了。瑞典近 70%的土地面积是森林,这是一个值得骄傲的民族。他们是少数几个能够在保持成功的伐木业的同时增加森林覆盖率的国家之一。

这并不是说瑞典的森林没有面临挑战。和世界上其他许多地方一样,入侵的害虫会对北欧的林地造成巨大的破坏。在德国西南部地区,落叶松鞘蛾,一种小的暗灰色蛾,造成了广泛的经济损失。雌性在落叶松的针叶上产卵。然后,幼虫通过这根针的内部和邻近的针吃掉它们,将先前被吃掉的针的外部变成一个保护壳(因此有“壳携带者”的绰号)。

幼虫大约 5 毫米长(对美国人来说,不到 1/5 英寸);看到一个的机会很小。如果只有一只或几只这样的生物落在一棵树上,它们可能永远不会被注意到。落叶松是大树,高达 45 米;任何那么大的生物都能对付一些微小的寄生虫。问题是这种蛾的数量远远不止几只。虽然昆虫本身是不可见的,但它们造成的损害是可见的。如果这是可见的,计算机视觉模型可以学习检测它。

瑞典森林机构发布了一个数据集,其中包含了威斯特格特兰五个地区落叶松林的无人机航拍照片。这些图像是在 2019 年 5 月 27 日和 8 月 19 日这两天拍摄的,拍摄地点是 vstergtland 的五个地区(Bebehojd、Ekbacka、Jallasvag、Kampe 和 Nordkap)。所有图像都带有由边界框坐标和标签组成的 XML 文件。标签指示包围在边界框中的树是落叶松还是其他物种(最有可能是云杉,尽管只有两个边界框被如此标记)。如果树是落叶松的话,五月图像的标签也包括由落叶松箱携带者造成的损害水平。伤害等级分为健康、低伤害和高伤害。

数据概要

落叶松占 5 月份数据中标记树木的近 80%,但只有 8 月份数据的 70%左右。八月份的数据包含的图片总数更少,698 对 836,但包含了 1900 多棵不是落叶松的树。

按地点划分,除了树木密度最高的 Kampe 和密度最低的 Ekbacka 之外,5 月图像中落叶松的百分比始终在四分之三到五分之四之间。

每个地区的落叶松百分比在 8 月份有相当大的变化,Jallasvag 下降幅度最大,其他地方下降幅度较小。这可能是在图片之间的三个月内剔除患病树木的结果,但这似乎不太可能,因为变化百分比最高的 Jallasvag 和变化百分比最低的 Kampe 拥有健康落叶松树的两个最高百分比。更有可能的是,在两次采集过程中对不同区域进行了采样。

欧洲落叶松不是针叶树中颜色最深的。即使在健康状态下,这些树的颜色也比它们的邻居要浅得多,针叶略带蓝色

左图:健康的落叶松林。右图:由其他树种组成的森林区域。请注意,即使是健康的落叶松也有浅色的针叶。来自落叶松案例库的原件。

随着携带病例的感染开始发生,落叶松外部的针叶开始变成褐色。

坎普地区的一片森林,由大部分受损较轻的落叶松组成。沿着树的边缘可以看到棕色的痕迹。来自落叶松案例库的原件。

当虫害达到高危害阶段时,树木留下的针叶已经变成褐色。

坎普的一片森林,由严重感染的落叶松构成。所剩无几的绿色大部分来自落叶松周围生长的小植物。来自落叶松案例库的原件。

目标检测模型将需要检测绿色的色调以区分落叶松和其他品种,以及区分表征不同程度的侵扰的绿色和棕色的色调。虽然树枝的形状和树的大小有细微差别,但颜色可能是最重要的因素。即使是一个相当简单的检测模型也能很好地解决这个问题。

建立模型

最后,EfficientDet 仍然是用于单次拍摄对象检测的最先进的模型架构。EfficientDet 由一系列对象检测模型组成,旨在顺利管理大小和效率之间的权衡。最小的模型可以用于手持或远程设备,包括监控森林的无人机,而最大的模型可以在 GPU 驱动的服务器上提供更高的精度。

无人机采集的图像都是 1500x1500。虽然这种一致性值得赞赏,但除了最大效率的 Det 型号之外,其他型号的尺寸都太大了。事实上,EfficientDet 模型对用于训练的输入大小相当挑剔。最小的 D0 为 512x512,第二大的 D1 为 640x640。经验表明,不根据这些大小调整输入必然会导致性能损失。

训练数据的白蛋白预处理。

幸运的是,裁剪和调整大小是深度学习预处理管道的标准部分。裁剪和调整大小通常伴随着适度的拉伸和挤压;以 4:3 和 3:4 之间的比例随机采集作物,然后重新调整为 1:1。这样的举动对于这个问题的价值值得商榷。树木图像可以被压缩成不真实的形状吗?可能不会有这样的高宽比;由此产生的图像可能仍然反映了树木在野外的自然外观。

树的长宽比从 4:3 拉伸到 1:1 的训练图像。扭曲不足以让树看起来不真实。来自落叶松案例库的原件。

用于训练的其他有用的预处理操作是翻转、水平和垂直、旋转和转置。由于颜色是如此重要的一个特征,而且由于不同地点的类别颜色相当相似,所以没有理由增加颜色。事实上,在现代架构中,颜色增强通常会导致精度略微下降。(参见 RandAugment 论文中的表 5。)

预处理验证数据是一件更简单的事情。由于图像已经是方形的,因此调整它们的大小以适合模型就足够了。所有预处理操作都通过白蛋白包完成。

验证数据的蛋白化预处理。

20%的数据,随机选择,但在五个位置分层,进行验证。

模型的训练参数相当标准。初始学习率为 2.56e-3,权重衰减的 Adam 优化器 4e-5 表现良好。余弦学习率衰减规则略优于指数衰减;似乎该模型需要一段时间内采取大的步骤来找到它的最优区域,但是之后学习速率需要迅速衰减。因为亚当被认为是在狭窄的山谷中找到最优解,所以这种行为并不奇怪。焦点损失是该 EfficientDet 实现的缺省值;这是幸运的,因为班级严重失衡。该模型被训练 200 个时期,在验证集上保存三个表现最好的时期。

模型的大小,或者更准确地说是 Colab 的内存限制,决定了批量大小。对于 EfficientDet0 和 EfficientDet1,批处理大小为 8,但对于 EfficientDet2,批处理大小必须减少到 4。最终结果是从 D1 到 D2 的准确性略有下降。

结果

总体识别结果良好,EfficientDet0 的 COCO 图为 48.6,EfficientDet1 的 COCO 图为 50.8。对于 EfficientDet2,该值下降到 50.1,因为培训中使用的批量较小。越实际,因为它反映了实际使用的预测,AP@50 对 D0 是 75.9,对 D1 是 79.0,对 D2 是 77.4。不同类别的分数随着类别频率的不同而不同,低损害最高,健康最低。

EfficientDet0 的平均精度

效率的平均精度 1

EfficientDet2 的平均精度

D2 模型准确性的下降主要是检测健康树木能力的下降。对低伤害的探测会略微上升,而高伤害大致保持不变。健康班也显示了从 D0 到 D1 的最大进步。由于从 D0 到 D1 的准确性确实全面提高,似乎没有什么理由在生产中使用 D0(除非 CPU 限制非常严格)。在 D1 和 D2 之间的选择是一个判断的问题,但是由于 D1 在不太频繁的课程上做得更好,它可能是更好的模型。

回忆是极好的。考虑到每幅图像有大量的地面实况观测数据,平均 65 个,像 AR@1 和 AR@10 这样的传统测量方法没有多大意义。AR@100 和所有检测的总平均召回率是有用的度量。D1 再次成为表现最好的模特。

有趣的是,当从 AR@100 移动到 AR 时,对高伤害的回忆超过了对其他伤害的回忆。由于其他类别最容易与其他三个类别区分开来,通常是更深的绿色阴影,因此在两者都出现的图像中,其他类别检测的排名可能高于高损害。

所有型号的平均召回率。

平均精度和平均召回率是模型性能的有效度量,但它们本身并不说明模型如何在实践中使用。为此还需要一个东西,门槛。阈值的简单选择是 0.5,所有高于阈值的检测将被保留,所有低于阈值的检测将被丢弃。在多类问题中,天真的选择几乎从来都不是正确的选择。要选择最佳阈值,请找到平衡精确度和召回率的阈值。没有明显的理由让一个优先于另一个;F1 分数适合于确定最佳阈值。

使用一系列阈值0.0:1.0:0.01计算每个阈值的 F1 分数。为每个类别独立计算 F1,然后取平均值。对于 D0 模型,最佳 F1 分数出现在 0.4,而对于 D1,最佳是 0.409。D2 模型的最佳阈值为 0.379。

用于图像的颜色代码。

有代表性的形象。左是地面真理;右是来自 D1 的探测。来自落叶松案例库的原件。

上图有贴图 56.2,略高于整体贴图 50.8。预测和现实显然非常接近。最明显的差异是预测倾向于过多计算除落叶松以外的树木。在某些情况下,不清楚是模型检测到了太多的树,还是注释器遗漏了一些树。左上方的三个绿色检测框应该只有两个,但是右边高伤害假阳性正下方的小绿色假阳性看起来确实像应该在地下真相中的树。就此而言,高损害假阳性似乎是一棵死亡或垂死的树;是否是落叶松有待商榷。

当模型落叶松树检测与地面真实数据的损害水平不匹配时,树通常表现为边界情况。被模型标记为高损害的低损害树通常比标记为低损害的低损害树看起来更差。类似地,高伤害树被标记为低伤害,在他们的类别中看起来是最健康的。上面图像中被模型标记为健康的那棵树可能是图像中最好看的落叶松。如果不知道更多关于基本事实注释过程的信息,我们能说的是有限的,但是这并不是第一次一个模型胜过人类注释者。很明显,该模型在三个落叶松类之间确定的阈值与人类注释者确定的阈值略有不同。

另一个清楚的事实是,图像中最常见的类别的准确度通常最高。一棵树的健康往往取决于它的邻居,这并不奇怪。这个模型似乎已经意识到了这一点。单幅图像的类别级映射与同一幅图像中的类别频率相关。这种相关性随着模型大小而略微降低(除了主要的低损伤等级),这表明较小的模型比数据保证的更有可能“聚集”更多的识别。

健康树木比例最高的图像。左是地面真理;右是来自 D1 的探测。来自落叶松案例库的原件。

上图的上半部分是聚类的一个例子。标记为低损害的少数树木被模型分类为健康的,或者在两个小树的情况下,被完全忽略。左下角的情况正好相反;四棵健康的树被标记为低损害。在这两种情况下,都不清楚模型或地面真相是否正确。

高伤害树木比例高的图像。左是地面真理;右是来自 D1 的探测。来自落叶松案例库的原件。

在以高伤害树为主的图像中也是如此。在上面的图片中,如果附近有其他高伤害的树,那么将这些树标注为高伤害会有一点偏向。在具有模型预测边界框的图像中,左下方的低损害树的集群较小,并且左中间的一些低损害树已经被丢弃或被一起标记为高损害。

关注预测误差很容易;它们在视觉上总是显而易见的,但是模型的准确性总体上保持良好。在足够大的批量上训练的更大的模型仍然会表现得更好,但是目前用 Colab 是不可能的。考虑到现有的工具,这种模式可以说是成功的。

样本代码

培训高效模特的笔记本

包含生成预测代码的笔记本。(仅用于解释目的。)

包含评估代码的笔记本。(仅用于解释目的。)

任何用户都可以运行用于训练模型的代码。预测和评估的代码需要调整一些引用,以指向用户生成的模型和输出文件。

许可证

直接引自数据仓库:

标签根据社区数据许可协议(许可变体)发布。

对于无人机图像,瑞典森林机构已经从 lantmteriet 获得了传播地理数据的许可,lantmteriet 是瑞典财政部下属的一个机构。

参考

谭明星,庞若明,郭伟民诉乐。EfficientDet:可扩展且高效的对象检测。2020 年 IEEE 计算机视觉和模式识别会议录。

瑞典林业局(2021):森林损害-落叶松案例 1.0。国家森林数据实验室数据集

走进“人员分析”的世界

原文:https://towardsdatascience.com/into-the-world-of-people-analytics-18580ff37e29?source=collection_archive---------30-----------------------

好奇的眼睛想要一瞥里面的东西

unsplashAmina 拍摄的照片

越来越多的公司开始意识到需要深入研究员工的数据,以发现可操作的见解,并利用这些见解潜在地影响业务战略和决策。在这里,雇员的数据可以与他们的人口统计特征相关联,如性别、年龄、国籍等。或雇佣定义,如自然减员、任期、薪酬、工作级别、角色、他们报告的组织等。,或定义为最高资格、大学等的教育。弄清楚这些数据可以帮助组织更好地了解员工的 DNA,例如,他们有多多样化,有助于推动招聘或保留等方面的指标目标。,实现企业里程碑。

照片由保罗unsplash 拍摄

有很多东西要消化?这实际上只是一个围绕人物分析的综合框架。此外,在我看来,这个领域仍然是一个利基领域,还没有充分嵌入到组织的人力资源/人员团队中,这(我认为)是好的,因为这为带来最大业务影响的领域提供了可塑造的范围。但是,对于那些有兴趣进入这个领域仅仅是为了探索,或者更严肃地说,以此为职业的人来说,范围一般是什么样的?需要什么工具/技能?从哪里开始?我将在这篇文章中详细阐述这些观点,希望能给你一些启发。

我是如何跳上这趟旅程的

安德鲁在像素上拍摄的照片

对我来说,它并不总是关于分析人的数据。获得工程学硕士学位,然后成为一名工程数据分析师,可能会为天生的“分析性思考”和对数字的怀疑、质疑和好奇奠定基础。然而,仅凭这一点还不足以在人员分析领域生存和发展。这是一个持续的学习过程和提升技能的过程,需要激情和勇气才能继续。

消除陈词滥调

围绕人员分析(可能也像数据分析一样)的一个流行的陈词滥调是,分析只是揭示洞察力的过程,简单地说,就是将数据转化为行动。但以我的经验来看,这已经是,而且更多,这真的取决于我能通过冒险进入新的领域来加深我的知识。在接下来的内容中,我在这里采用数据分析的上下文,因为在我看来,数据就是数据;区别在于我们用什么类型的数据进行分析。另一个免责声明是,无论下面分享什么,都不意味着希望进行人员分析的人必须知道所有信息,因为这真的很广泛,旨在概述人员数据可以做什么/可以做什么的最常见用例。你加入的公司可能会有专门的团队成员专注于某些领域。对于对公司来说完全陌生的情况,他们可能希望听到你如何增加价值。然后,有必要了解所有选项,并根据利益相关者的难点解决方案进行冒险。

unsplash 上由 Myriam 拍摄

在线研究显示,数据分析支柱(广义而言)包括对以下领域的关注。我另外列出了一些适用于它们的工具和技能。它们当然不是一个详尽的列表,但是大多数都是我在实际工作中用来完成任务的。

数据分析支柱—尝试“是什么”

在进入任何新奇的事物之前,Excel 的基础知识是如此的有用,我不能不大声说出来。Excel 如此漂亮地将数据结构化地放入行和列中,其友好的用户界面功能让您可以快速获得答案。我广泛使用的最常见的功能是旋转和 vlookup。

  1. 数据治理——高效的端到端数据管道管理

这是数据成型和可用的地方,通过理解涉众的需求,涉及标准化、自动化和维护的繁重工作。一些具体的例子可以是,当一个公司迁移到一个新的 HRIS(人力资源信息系统)时,开始了解当前和未来的数据需求,整理需求,访问新的 HRIS 的能力,并随着变化向前移动或遵循创建数据库或数据仓库的类似努力。

  • 工具——SQL(用于数据库),在公司选择的 HRIS 中导航
  • 技能——可能是项目(&供应商,如果适用)管理

2.分析—数据科学结合故事讲述来解决业务问题

对我来说,分析与报告的区别在于前者所需的数据科学知识。如果手头的任务只是可视化(转换数字来传达一个故事),那么使用仪表板工具就足够了。但是,必须深入人工智能领域的复杂分析属于数据科学领域

  • 工具——像 Python(这是我用的)或 R 这样的编程语言,
  • 技能——解决问题、统计&数学概念理解、讲故事、可视化、讲故事的艺术

3.报告(或仪表板)——对需要持续监控的数据进行脉冲检查

对于监控组织的关键指标(如记分卡)和快速数据可视化非常有用

  • 工具— tableau,power bi
  • 技能——视觉化,讲故事的艺术

4.(奖金)业务流程自动化——简单地说,这是重复任务的自动化
对我来说,这是对上述三个常规的奖励。这已经成为一种基于简单推销的流行趋势,特别是对于像人力资源这样的非技术人群(这仍然是市场上普遍认为的真理)。一个具体的例子是使用 RPA(机器人流程自动化)来创建针对重复的基于逻辑的任务的自动化工作流。

  • 工具— Ui Path 可能是 RPA 领域最受欢迎的软件,并被许多公司采用
  • 技能——理解 Ui 路径上常见构建活动的编程基础,包括变量赋值、循环等

从零开始?不要烦恼;你不是一个人!

安德里亚像素上拍摄的照片

实际上,我已经将这些结合起来,研究了市场上最广泛使用的工具,进行了自定进度的培训,以便在工作中实际使用它们,以及在手头有业务问题后研究完成任务的最佳工具/技能,然后选择该工具/技能并交付。一个结合的例子是,当我出于自动化任务的兴趣开始进行 Python 培训时,特别是针对数据争论,但后来终于有机会从事预测分析,因此要求我进行机器学习培训。通过在 Udemy 平台上回顾的基础培训,我已经学会了我在这个领域使用过的所有工具。

最终的底线

照片由马修unsplash 上拍摄

总而言之,我想说,对于那些对数字、统计、数学感到模糊,最重要的是,无法不断学习新技能的人来说,这肯定是一个遥远的镜头。从个人经验来看,我可以保证不会编码不会成为进入这个领域的障碍,因为编码就像我们最终擅长的其他事情一样,需要大量的实践。计算机科学或分析方面的教育背景肯定可以提供一个基础,但我从个人经验中强烈保证这绝不是强制性的。通过严格的练习和丰富的在线资源,工作仍然可以完成。因此,如果你正在寻找这种曲折的持续学习之旅,成为调查数据和报告见解的夏洛克·福尔摩斯,有强迫症将数据结构化并传达见解,对技术进步如何改变人力资源感到惊叹,那么,无论如何,跳上一生的冒险!☺

马尔可夫链多触点归因简介

原文:https://towardsdatascience.com/into-to-markov-chain-multi-touch-attribution-bb1968ff1f54?source=collection_archive---------1-----------------------

使用 R 进行模拟和建模

什么是归因建模?

归因建模是Digital Marketing中出现的一项任务。概括地说,归因建模的目标是改善驾驶Marketing Objectives中各种Advertising Channels的评估。在开始数据分析之前,让我们首先为Markov Chain Attribution建模解决的问题设置一个背景。

在这篇文章中,我的目标是涵盖以下内容:

  1. 什么是归因建模?
  2. 什么是多点触控归因?
  3. 马尔可夫链简介
  4. 使用 R 表示:
  • 从马尔可夫链模拟消费者旅程
  • 从消费者旅程估计马尔可夫链
  • 使用马尔可夫链进行数据驱动的归因

许多广告渠道

当营销人员在广告上花钱时,他们战略性地将预算分配给不同的活动,这些活动反过来使用大量的广告渠道。一些常见的广告渠道包括有线电视和流媒体电视、节目、社交、付费搜索、印刷品。这些是如何定义的,以及使用哪些媒体合作伙伴和平台来花费计划的预算各不相同,但广告商通过多种渠道进行沟通的事实仍然存在。

目标和 KPI

让我们记住,营销人员不是为了做广告而做广告。他们有特定的目标和目的,围绕这些目标和目的建立营销传播战略。Analytics的角色之一是帮助建立一个衡量计划,该计划将定义一组Key Performance Indicators (KPI)来衡量营销工作的成功。根据目标和技术能力,选择这些 KPI,并准备好测量它们的工具。例如,我们可能希望:

  • 产生对网站或网页的访问
  • 通过表单提交产生销售线索
  • 让用户在我们的网站上执行某些操作
  • 提高我们品牌的知名度
  • 或者只是推动销售

无论 KPI 是什么,完成的 KPI 的一个单元被称为Conversion

投资回报率和归因

在我们开展活动和花费预算时,我们需要回答一个关键问题:

我们如何评估不同渠道在推动 KPI 方面的重要程度?

显然,如果我们的目标是推动销售,但在其他条件相同的情况下,我们的销售没有增加,那么没有一个渠道工作得很好。但是,如果我们真的成功推动了增量销售,哪种渠道效果最好呢?换句话说,我们如何Attribute不同渠道的增量销售并计算我们的投资回报(ROI,有时被称为广告回报(ROAS))?我们是否应该因为其中一个渠道的表现不如预期而从战术上改变我们的计划?回答这些问题是单向的Analytics广告对Advertising的价值。

消费者路径中的最后一步

有了数字广告,我们衡量消费者何时以及如何与广告互动的能力变得更加容易。这种易处理性允许我们收集数据并分析Consumer PathConversion的部分。无论是否被跟踪,消费者的旅程都是存在的,没有人能够真正跟踪整个旅程。我们能追踪的是一些Media Touchpoints。往往AttributeConversions最简单的方法就是简单的看一下Consumer Path中的Last-Touch。这是因为默认情况下,这是我们看到的唯一接触点。对推动ConversionLast-Touch给予完全的信任将导致对我们媒体效果的不公平评估,并且不能解释混合渠道旨在创造的Synergy

幸运的是,如果做了足够的努力来跟踪我们的媒体,我们可以生成路径数据,并希望以一种更复杂的方式进行归因,即使用Multi-Touch Attribution ( MTA)。这使我们能够更好地判断所用渠道的有效性,并做出更好的投资决策。

多点触摸归因

MTA方法主要有两类;Rule-BasedData-Driven。当然,这两种方法都使用数据,但区别在于它们如何对消费者路径上的接触点赋予重要性。Rule-Based方法基于触摸点的位置启发式地为其分配权重。

Data-Driven方法采取不同的方式。他们不是根据位置分配任意的规则,而是在接触点和他们在驱动中的角色之间建立概率关系Conversions

马尔可夫链属性

Markov Chain Attribution是一种比较流行的数据驱动方法,顾名思义,它利用了Markov Chains。除非你在大学学过运筹学或数学,否则你可能不知道这些链是什么,所以让我们做一个高层次的介绍。

马尔可夫链

关于Markov Chains要记住的关键概念是Transition Matrix。它们本身是描述(随机)系统的概念工具。所有这一切意味着,当一个过程存在随机性或概率性成分时,Markov Chains可能是一个很好的工具来首先描述,然后分析这个过程。我们这里关注的过程是Customer Journeys走向Conversions

基本面

我们可以把一个Markov Chain想象成一个有向网络。每个节点都是一个State,消费者可以在其中沿着一条路径前进。每个箭头都是一个Transition,有了它,就有了关联的概率。因此,你可能有一组预先确定的接触点,但接下来会发生什么是不确定的。

转换和非转换节点有从所有通道指向它们的箭头,但没有从它们发出的箭头。这些被称为Absorbing States,对我们来说,它们意味着旅程的结束。当我们收集了从一个状态转移到下一个状态的所有概率时,我们将它们组织成一个正方形Transition Matrix

M = t(matrix(c(1,0,0,0,0,
               200,0,300,350,10,
               160,300,0,350,8,
               150,200,200,0,20,
               0,0,0,0,1), nrow = 5))M = M/rowSums(M) colnames(M) = c("Non-Conversion","Display",
"TV","Search", "Conversion")row.names(M) = c("Non-Conversion","Display",
"TV","Search","Conversion")

上面是一个例子Transition Matrix,我只是把它放在一起举例说明。为了更现实,我将转换概率设置为相对较低的值。稍后我们将使用此矩阵进行Simulation

要记住的一个重要属性是,行的总和等于 1,因为我们处理的是概率。行代表旅程中的当前状态,列代表下一个状态。

rowSums(M)## Non-Conversion Display   TV         Search     Conversion
   1              1         1          1          1

关于Markov Chains,还有一件更重要的事情需要了解,那就是Markov Property或者无记忆性。对某些人来说,这可能是 TMI,但这确实是用一个简单的Transition Matrix来概括整个过程的原因。该属性是一个简化的假设,即你转移到下一个地方的概率只取决于你现在的位置,而不取决于你的整个旅程历史。需要说明的是,这并不意味着旅程历史不重要。这绝对会影响归因结果。不影响的是概率。从数学的角度来看,这使得分析变得非常简单。

从链到路径(模拟)

在实践中,给定一个消费者路径的数据集(构建这个数据集是一个很大的任务,所以“给定”是一个很强的词),我们可以估计一个Transition Matrix。反之亦然。给定一个Transition Matrix,我们可以模拟一组消费者路径。事实上,模拟在得出每个通道的实际重要程度方面起着重要的作用,因此有必要了解一下这一过程的机制。

下面我们定义一个函数,它将与上面的样本矩阵 M 一起工作。给定这个矩阵和我们想要执行的num_sim步骤,我们执行以下操作:

  1. 从一组媒体接触点中随机选择一个起点。
  • 在实践中,我们实际上会估计起点概率。

2.对于每个步骤:

  • M 中选择一行与当前状态/触摸点相对应的概率。
  • 从概率设置为行的Multinomial分布中抽取一个样本。
  • 将样本设置为新的当前状态并重复。

3.如果我们点击了ConversionNon-Conversion,我们就结束了路径。

simulate_path = function(M, num_sim){
   num_sim = num_sim   
   path = vector(mode = "integer", length = num_sim)   
   path[1] = sample(2:(nrow(M)-1), 1) 

   for(i in 1:(num_sim-1)){
        p = M[path[i],]
        sn = which(rmultinom(1, 1, p) == 1)
        path[i+1] = sn     
        if(sn == 1 | sn == 5){
           break     
        }   
    }   
    return(path[path > 0]) 
}

模拟一条路径

让我们测试一下这个函数。第一个例子是非转换器。

set.seed(124) 
num_sim = 100 
path = simulate_path(M, num_sim) 
plot(seq_along(path),path ,type = "l",
     axes=FALSE, 
     ylim = c(1,5),
     main = "Non-Converter",
     ylab = "Channel Touchpoint",
     xlab = "Touchpoint Number") 
points(seq_along(path), path) 
axis(side = 2, at = 1:5) 
axis(side = 1, at = seq_along(path))

我们看到,我们从Display开始,移动到Search,然后TV,继续这个旅程,直到第 6 步,在这里我们没有转换就退出。

这是另一个例子,但这次我们有一个转换器。

set.seed(007) 
num_sim = 100 
path = simulate_path(M, num_sim) 
plot(seq_along(path),path ,type = "l",
     axes=FALSE, 
     ylim = c(1,5),
     main = "Non-Converter",
     ylab = "Channel Touchpoint",
     xlab = "Touchpoint Number") 
points(seq_along(path), path) 
axis(side = 2, at = 1:5) 
axis(side = 1, at = seq_along(path))

这一次,我们从TV开始,在第 8 步进行转换,将Search作为我们的最后一个接触点。

模拟完整的旅程数据集

我们现在可以简单地通过重复函数调用simulate_path来模拟一整套路径。随着更多的数据操作,我们有了一个pathdf。这里我将生成10,000路径。

num_sim = 100 
num_paths = 10000  
paths = purrr::map(1:num_paths, ~simulate_path(M, num_sim)) conversion = 
    purrr::map(paths, ~ data.frame(
    conversion = ifelse(.x[length(.x)] == 5, 
                        "converter", "non-converter"))) %>%     bind_rows(.id = "path_num") pathdf = 
   map(paths, ~data.frame(touchpoint = 1:length(.x), channel = .x)) %>% bind_rows(.id = "path_num") 
%>% left_join(conversion) %>% 
left_join(data.frame(channel_name = colnames(M), channel = 1:5)) 
head(pathdf,10) %>% 
       gt::gt() %>%
       gt::tab_header(title = "Simmulated Paths")

现在让我们将所有这些路径一个接一个地绘制出来,看看这个Markov Chain是如何工作的。

plotly::ggplotly(
    pathdf %>% 
      ggplot(aes(touchpoint, channel, color = conversion, 
                 group = path_num)) + geom_line() +   
      labs(x = "Touchpoint Number", 
           y = "Channel Touhcpoint") +  
      theme_minimal() 
)

从图中我们可以看到,更常见的是直线下降,这表示非转换器。这是意料之中的。我们可以看到模拟的转化率刚刚超过 8%。

table(conversion$conversion)/nrow(conversion)##     converter non-converter  
##        0.0808        0.9192

从道路到锁链

既然我们已经从我们的马尔可夫链 M 中模拟了一组消费者路径,我们可以尝试用它们来估计最初的 MM^ ,看看这种估计方法的效果如何。在这里,我将介绍大卫·阿尔托马雷创作的精彩的ChannelAttribution软件包。它是开源的,托管在 GitLab 这里。这个包包含一个名为transition_matrix的函数,它接收一组路径数据并估计Transition Matrix

数据准备

首要任务是按照要求的格式组织数据。首先,我们需要解析出每个路径中的最终接触点,因为它们代表一个conversion / non-conversion事件。然后,我们总结按路径分组的数据,并对观察到的每个唯一路径计数convertersnon-converters

named_paths =
      pathdf %>% group_by(path_num) %>% 
      group_split() %>% 
      map(~pull(.x,channel_name)) path_trim = 
 map(named_paths, ~.x[.x != "Non-Conversion" & .x != "Conversion"]) journeydf = as_tibble(
 cbind(
    as.data.frame(do.call(rbind,
       map(path_trim, ~str_c(.x, collapse = " > "))
       )
    ),conversion$conversion)
) names(journeydf) = c("path","conversion")  
journeydf = 
journeydf %>% 
group_by(path) %>% 
summarise(converters = 
    sum(if_else(conversion == "converter",1, 0)),             
          non_converters = 
     sum(if_else(conversion == "non-converter", 1, 0)
          )
) %>%  
arrange(-converters, -non_converters) head(journeydf, 15) %>% gt::gt() %>% 
gt::tab_header(
title = "Simmulated Journey Data (Top 15 Converters)"
)

下面是一些关于生成的路径数据的快速汇总统计。

data.frame(
metric = c("Converters",
           "Non Converters",
           "Number of Paths",
           "Conversion Rate %",
            "Unique Journeys"),
value = c(sum(journeydf$converters),
          sum(journeydf$non_converters),
          sum(journeydf$non_converters) + sum(journeydf$converters),
          100*sum(journeydf$converters) / num_paths,
          nrow(journeydf))) %>% 
gt::gt() %>%
gt::tab_header(title = "Summary")

还有许多其他方法来探索这种数据。一个快一个交集一个是path lengths的分布。

path_lengths = map_int(path_trim, ~length(.x)) 
summary(path_lengths)##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.  
##   1.000   2.000   3.000   4.002   5.000  31.000hist(path_lengths, main = "Path Length Distribution")

转移矩阵估计

最后,现在我们有了已知转移矩阵 m 的模拟数据集,我们现在可以看到如何通过估计和计算 M^从数据回到转移矩阵。这里我们将ChannelAttribution::transition_matrix()函数应用于我们的数据。该函数返回频道 id 的查找表和转移概率表。

library(ChannelAttribution)  
tM = transition_matrix(journeydf,
                       var_path = "path",
                       var_conv = "converters",
                       var_null = "non_converters") tM$transition_matrix %>% gt::gt() %>% 
gt::tab_header(title = "Transition Probabilities")

我们可以格式化表格并以某种方式输出,以便于我们比较估计的和真实的转移矩阵

我们可以看到,估计工作得很好,特别是对于较大的概率。因为转换事件非常罕见,所以对它们的估计有更大的可变性/更低的精度。

属性

到目前为止,我们以转移矩阵 M 的形式引入了一个理论Markov Chain,用它来模拟一个数据集Consumer Journeys,并通过估计 M^ 返回到一个Transition Matrix。现在是转换的时候了,继续实际的归因模型!

移除效应

Markov Chains作为Consumer Journeys的样板似乎是个好主意。但是我们如何使用它们来实现属性转换还不是很清楚。

这里的主要思想是计算Removal EffectsRemoval Effects测量如果从路径中省略/移除一个通道,观察到的转换会减少多少。如果我们对Markov Chain中的每个通道进行计算,那么Relative Removal Effects将是我们缩放总转换量的因子。

运行归因

正如我们刚刚了解到的,运行马尔可夫归因模型包括估计一个Transition Matrix,然后计算Removal Effects。为此,我们只需使用markov_model函数,它以准备好的格式获取数据。通过指定out_more = TRUE,除了属性结果之外,我们还可以获得transition matrixremoval effects

mm_res = markov_model(journeydf,
                       var_path = "path",
                       var_conv = "converters",
                       var_null = "non_converters",
                       out_more = TRUE)##  
## Number of simulations: 100000 - Convergence reached: 2.32% < 5.00% ##  ## Percentage of simulated paths that successfully end before maximum number of steps (32)

归因结果

首先,我们来看看结果。转换总数为808。下表显示了我们的Data-Driven模型是如何确定这些属性的。

mm_res$result %>% gt::gt()

我们看到,每个渠道的转换数量相似,但Search的转换数量最多。这并不奇怪,因为转移概率被导向Search,但只是轻微的。此外,在我们的模拟中,每个通道都同样有可能被选为第一接触点,而这在现实中是不会发生的。

为了显示如何从移除效果计算这些结果,下面是显式代码:

total_coversions = sum(journeydf$converters)
removal_effects =  mm_res$removal_effects$removal_effects
relative_removal_effects = removal_effects/sum(removal_effects)
attributed_conversions = total_coversions * relative_removal_effectsattributed_conversions## [1] 284.97 263.29 259.75

去除效果本身可以容易地被访问和解释

removal_effects## [1] 0.7806 0.7212 0.7115

从这些数字中,我们看到,如果移除Search,将会观察到约 78%的转换减少。对于这样一个小而相互关联的国家来说,这很有戏剧性,但并不奇怪。

与基于规则的模型进行快速比较

使用ChannelAttribution包也很容易获得一些基于规则的模型的结果,并将它们与数据驱动的结果进行比较。

heuristic_models(journeydf, 
                 var_path = "path", 
                 var_conv = "converters") %>% 
  left_join(mm_res$result) %>% 
  gt::gt()

我们可以清楚地看到Last-TouchMarkov Chain模型结果之间的差异,因为Display尤其是TV的重要性被大大低估了。Last-TouchMarkov Chain车型相比,50的电视转换率更低。这个例子清楚地说明了Markov Chain属性如何能够纠正Last-Touch属性的固有偏差。Linear Touch这里的结果是相似的,再次因为通道之间的转移概率相差不太远。

mta_res %>% 
  pivot_longer(-channel_name, 
         names_to = "MTA_Model", values_to = "Conversions") %>% 
  ggplot(aes(MTA_Model, Conversions, fill = channel_name)) + 
  geom_col(position = "dodge") +
  labs(title = "MTA Model Result Comparison")
  theme_minimal()

主要考虑事项

希望你和我一样对 MTA 和马尔可夫链归因这个话题感兴趣。尽管这篇介绍相当冗长,但这种类型的分析仍有许多方面需要考虑。下面是接下来需要考虑的几个关键问题:

  1. 数据是任何数据分析的关键要素,因此分析的质量取决于数据的质量。
  2. 数据质量取决于几个因素:
  • 可测量性——一个通道可以测量到什么程度?数字广告很容易衡量,而 OOH(街头横幅)很难追踪。
  • 衡量——仅仅因为某样东西容易衡量并不意味着它被很好地衡量了。如果没有实施、维护和管理适当的工具,就无法正确收集数据。
  • 数据管理—即使正确收集了数据,仍然需要对其进行管理,这意味着命名约定和数据分类必须到位。
  • 跨设备/跨平台(围墙花园)—为了将Customer Journey数据缝合在一起,我们需要能够识别跨不同平台和设备的用户,并通过这些平台和设备联系他们。这也许是今天 MTA 的最大局限。

3.如果需要频繁有效地交付 MTA 结果,数据工程方面是很重要的。灵活性越大,就会越复杂。

4.我们可能还想考虑是否有更好的方法来估计转移矩阵,例如使用贝叶斯方法。

简介:Go 中的 GraphQL

原文:https://towardsdatascience.com/intro-graphql-in-go-9fed8e2a3e18?source=collection_archive---------19-----------------------

什么是 GraphQL,为什么使用它,以及如何在 Golang 中使用它

GraphQL 作为 Go——Gopher 中的架构解决方案由上田拓也绘制,灵感来自勒内·弗伦奇(CC BY 3.0)的作品

在本文中,我们将使用 Go 内置的 GraphQL 服务器为地鼠构建一个雇佣代理 API。与其他介绍不同,我不会用一个简短的声明列出所有组件的名称。相反,我们将一步一步地构建一个应用程序,并解释每个步骤中发生的事情。希望这种方法能让你更容易避免信息泛滥。我不仅会介绍 GraphQL,还会介绍我在使用[graphql-go](https://github.com/graphql-go/graphql)时如何构建架构

我们需要澄清的第一件事是一个非常普遍的误解。

GraphQL 不是数据库!— 图表 QL

我觉得这个误解来源于名字,开发者习惯于听到所有的数据库名字MySQLPostgreSQL等。重要的是最后两个字母,QL。如果你已经有一段时间了,你可能知道这是Query Language的简称,但是我遇到的很多人只是把它和数据库联系起来。

因此,GraphQL 是一种查询语言,旨在使服务器和客户端之间的通信更加容易和可靠。我们需要马上解决的另一件事是,GraphQL 是数据库不可知的。这意味着它不关心正在使用的底层数据库。

本文中的所有图片均由珀西·博尔梅勒绘制,地鼠由拓也·上田绘制,灵感来自蕾妮·弗伦奇的作品。图像中的地鼠已被修改。

你问这怎么可能?那么,您应该将 GraphQL 视为数据库和客户端之间的中间件。您有一个 GraphQL 服务器,它接收查询格式的请求,查询精确地指定您想要返回什么数据,服务器返回请求中定义的数据。

在这里定义并记录了查询语言

这是搜索地鼠时查询的样子

这是示例查询的响应,请注意,只显示了需要的字段

如果你有任何关于 GraphQL 的问题,他们有一个非常好的 FAQFAQ

在这篇文章中,我们将涵盖基础知识,我们将建立一个应用程序来搜索和寻找地鼠雇用。我们不会涵盖 GraphQL 的所有方面,那会太长。

为什么以及何时应该使用 GraphQL

GraphQL —使用多个数据源,但只有一个响应和一个请求

我承认,当我第一次听说 GraphQL 时,我持怀疑态度。我知道很多人也是如此。听起来好像只是在 API 和调用者之间增加一层会使事情变得更复杂。

但事实并非如此,我希望能让你相信这一点。

我发现使用 GraphQL 的一个最好的原因是能够组合数据源。我是RepositoryPattern的忠实用户,你可以在我的领域驱动设计文章中找到讨论。

https://programmingpercy.tech/blog/how-to-domain-driven-design-ddd-golang/

简而言之,每个数据源都有一个存储库。对于我们正在构建的代理,我们将有存储地鼠的GopherRepository和存储工作的JobRepository。GraphQL 可以轻松地将这两种结构组合成一个输出,而无需耦合后端的数据源。在我们将要构建的服务器中,它看起来像是Gopher结构有Jobs与之相关,但它实际上将是两个不同的存储解决方案。

我喜欢 GraphQL 的第二个原因是,它允许用户精确地指定请求什么字段,从而避免了过度提取。您只发送一个请求,并且只获得您所请求的信息,没有未使用的额外字段。

GraphQL 的一个原则是开发过程应该从模式定义开始。这被称为Schema Driven Development,我不会在这里讨论它,但是基本上,我们从模式而不是业务逻辑开始。

在 GraphQL 中,你的 API 从定义所有类型、查询和变化的模式开始,它帮助其他人理解你的 API。这就像是服务器和客户端之间的契约。— GraphQL 网站

如何在 Go 中使用 GraphQL

下载所需的包并创建 go 模块

首先要做的是决定使用什么样的 Go 包。GraphQL 网站维护着所有可用包的列表

在本文中,我们将使用 graphql-go/graphql ,这是一个在官方 graphql-js 参考之后构建的包。这个包不读取 graphql 模式文件,而是在 go 代码中定义模式。定义模式的方式与 javascript 端使用的方式相同,这很好。

我们将从创建一个包并获得所需的库开始。我们将获取用于构建和定义模式的graphql-go/graphql,以及用于托管 graphql 服务器的graphql-go/handler

go mod init github.com/programmingpercy/gopheragency
go get github.com/graphql-go/graphql
go get github.com/graphql-go/handler
touch main.go

查询和解析器—提取数据

查询是对数据的请求,解析器处理业务逻辑来查找数据

查询是从服务器获取数据的操作。通过根据模式声明发送请求来执行查询。您在本文前面看到了一个示例查询,我们将以此为起点。响应中将只返回在query中使用的fields

在继续之前,我们需要了解两个关键词。

  • 字段 —某一数据类型的值,StringIntFloatBooleanID
  • 对象 —一个带fields的对象,把它想象成一个 struct。

我们展示查询中每个事物是什么的例子

要开始实现它,我们需要开始构建模式,记得Schema Driven Development吗?

我们将从创建可以查询的Gopher对象开始。创建一个schema文件夹,并在其中创建一个gopher.go

我们将从创建GopherType开始,它是一个可以使用 GraphQL 发送的object的声明。为了在graphql-go/graphql中创建一个新的object,我们使用了graphql.NewObject函数,NewObject的输入是一个ObjectConfig.

这个ObjectConfig 是一个用于配置如何定义object的结构。config 保存了一个graphql.Fields对象,它是map[string]*graphql.Fields的别名,记住Objects是一组Fields

schemas/Gopher . go-Gopher 对象类型的声明

现在我们已经定义了GopherType,我们必须设置并托管一个能够响应查询的 GraphQL 服务器。

为了拥有一个 GraphQL 服务器,我们需要一个[RootQuery](https://graphql.org/learn/execution/#root-fields-resolvers),它是每个查询的基础。根查询将在顶层保存所有可用的查询。

当请求到达服务器时,必须获取数据。获取数据由Resolvers完成,它是一个接受查询和所有arguments的函数。我们将创建一个简单的服务器,在添加GopherType之前先用一个简单的Hello进行响应。

main.go —一个简单的 graphQL 服务器,在端口 8080 上公开

更新 main.go 之后,在端口8080上托管服务器,然后访问 localhost:8080/graphql ,您将看到一个 UI,我们可以在其中测试当前的实现。

在左边你可以写下你的Query,在中间你可以看到来自Resolver的响应,在右边你可以看到一个可点击的树形结构,你可以用它来查看所有可用的查询。

GraphiQL——一个测试和实验查询的网站

尝试一下,看看你是否得到了正确的反应,以确保一切正常。

现在是时候实现一个真正的解析器了,我们将创建一个名为gopher的新文件夹,其中包含一个用于获取地鼠的Resolver。创建resolver.go文件,该文件将定义我们期望从地鼠数据存储中得到的所有Resolver函数。

记住,任何看起来像funcName(p graphql.ResolveParams) (interface{},error)的函数都可以用作解析器。

gopher/resolver.go —定义我们的 gopher 解析器的解析器接口

既然我们已经定义了一个解析器接口,我们需要实现它。让我们使用包含几个地鼠的内存数据存储。Gopher 结构必须有JSON标签来匹配定义的GopherType。如果标签不匹配,则不会返回响应。

创建一个gopher.go并填充该结构。

gopher/gopher . go-与 GopherType 对象匹配的 gopher 结构

让我们创建一个Repository来定义充当 Gopher 存储所需的函数。创建repository.go并插入以下要点。

gopher/repository.go —定义 gopher 存储的存储库接口

接下来,我们实现一个简单的内存数据存储库。我们将创建一个memory.go并填充超级简单的存储解决方案,为我们生成两个地鼠。

memory . go——内存地鼠的简单存储解决方案

很好,我们现在可以开始实现用于处理查询的Resolvers。让我们从简单开始,用所有可用的地鼠实现响应。我们将有一个实现Resolver接口的结构。我们采用这种结构的原因将在后面变得更加清楚,但是一个Resolver可以容纳许多Repositories来组合数据。

resolver.go 添加了一个 ResolveGophers 函数,可用作服务器根查询中的解析器

要开始使用来自GopherServiceResolveGophers,我们需要在main.go中创建一个服务,并让RootQuery返回一个GopherTypeList。记住GopherType是我们之前创建的自定义Object,而List是 GraphQL 中的一个数组。

main.go —更新了 GraphQL 根查询,以返回一个地鼠列表,并使用我们的 InMemoryRepository 解析它们

现在重启程序go run main.go并访问 localhost:8080/graphql ,看看 graphql 是如何让我们避免过度获取和不足获取的。

请记住,在 GraphQL 中,我们定义了在查询中返回哪些字段,因此只有您查询的字段会被返回。请看下面的两张图片,在我只获取地鼠名称中,第二张图片显示了如何获取所有可用的数据。

GraphiQL —只获取所有地鼠的名称的查询

GraphiQL —查询以获取对地鼠可用的所有值

在不耦合数据源的情况下组合查询中的数据

组合对象而不耦合它们

在我们继续之前,是时候展示如何使用多个存储库从许多来源获取数据了。这是 GraphQL 的另一个伟大特性。

每个graphql.Field都有一个Resolve字段,所以你可以给每个graphql.Field输入一个解析函数。通常,我们需要访问解析器中的存储库,最简单的方法是使用Service生成Schema,因为它拥有所有需要的访问权限。

让我们看看何时实现一个用于处理作业的JobRepository。我们将在GopherService中存储JobRepositoryGopherRepository,并在schema包中创建一个GenerateSchema函数,该函数接受服务作为输入,并创建我们可以用于 GraphQL 的模式。这种方法允许我们构建可以访问所有数据源的解析器,这样我们就可以组合它们。

首先创建一个job文件夹,并创建我们将在内部使用的job结构。我们还将为该作业创建一个Repository

job/job.go —后端域中使用的作业结构

接下来,我们需要一个作为存储库一部分的结构,这次也是一个内存解决方案。

job/memory.go —一个用于作业存储库的内存解决方案

在我们开始修复解析器之前,要做的最后一件事是升级Service,这样它就可以访问JobRepository

gopher/resolver . go-gopher 服务现在接受作业存储库

现在是时候关注这里发生的事情了。我们将添加一个ResolveJobs函数,在这个函数中我们将访问一个Source字段,这个字段是对象的Parent。当我们想要使用来自查询本身的数据时,这非常有用,就像在这种情况下,当我们搜索一个Job时,我们需要地鼠的ID

Source将是一个Gopher对象,所以我们需要对它进行类型转换。然后使用那个地鼠的 ID 到jobRepository

gopher/resolver . go-resolve jobs 希望父对象是 gopher

是时候开始构建模式了,这是我们可以组合来自GopherService的数据的地方。

创建 GraphQL 对象来表示schemas/factory.go中的JobType

schemas/factory . go-表示作业的 GraphQL 对象

让我们从固定Jobs数组的Field开始。请注意我们是如何将服务作为参数传递的,这样我们就可以到达所需的Resolver函数。

factory.go 构建作业字段,该字段是作业类型的列表

既然我们已经完成了Job字段,我们希望将其设置为Gopher类型的可用数据字段。我们将删除gopher.go文件并将内容移动到它的生成器函数中,因为我们再次需要GopherService的存在。记住Jobs字段将是Gopher的子字段,这使得Source是正确的。

factory.go —生成包含作业字段的 GopherType。

是时候完成 RootQuery 和导出到其他包的GenerateSchema中的模式了。

factory . go——generate schema 将所有部分链接成一个根查询

要实现这个功能,删除main.go中旧的main函数,使用新创建的存储库和模式生成器。

main . go——更简单的版本,不需要主函数的领域知识

重新启动应用程序并尝试查询作业。您应该看到,在每个 Gopher 下,都有一个 JSON 响应中呈现的作业列表。很神奇吧?

对 Gophers 查询的 JSON 响应

如果您想知道我们创建的job解析器和gopher解析器,那么我们为什么还没有实现它们是有原因的。我们不想每次都获取所有项目,但是我们希望能够只查询某些 Gophers。输入参数。

参数—指定搜索值的能力

使用参数指定要查询的特定数据

有一种搜索特定数据的方法是有意义的。这种方式是通过在查询中使用Arguments来实现的。参数是包含在查询中的命名值。

一个 GraphQL 字段可以有零个或多个可用参数。

可能实现它来学习更容易,所以让我们添加查询特定地鼠和作业的能力。

graphql.ResolveParams中,我们有一个Args字段,它将包含查询中发送的所有参数。

我们可以使用 Args 字段来搜索我们添加的任何参数。让我们先给Jobs解析器添加一个参数,其中我们要求一个公司参数。

更新JobRepository以接受另一个参数companyName

job/memory . go-更新 GetJobs 以获取公司名称

我们还修正了Repository来关联新的变化。

job/job . go-存储库更改

现在让我们修复ResolveJobs来检查参数。

gopher/Resolver . go-解析器现在接受参数 Company

我们需要做的最后一件事是让graphql.Field也接受参数。每个graphql.Field都有一个Args可以用来定义可能的参数,Args 是一个map[string]*ArgumentConfig,我们必须在其中设置名称和数据类型。让我们把它加到schemas/factory

模式/工厂-作业字段现在有一个参数

现在,您可以通过在查询中使用参数来请求某些公司。通过在字段后使用以下语法添加参数。

jobs(company: "value"){

该图显示了我们如何通过使用和参数来筛选某些作业

突变-修改数据

GraphQL 中的突变允许对数据进行更改

太好了,我们可以从服务器上查询数据。当我们想修改数据的时候呢?

这就是我们在 GraphQL 中拥有mutations的时候。突变是由一个RootMutation定义的,就像我们有一个 RootQuery 一样。因此,我们需要为所有可用的突变、它们的参数和可用的字段建立一个模式。

GraphQL 中的一个Mutation看起来非常像一个查询,事实上,它也将返回结果。因此,变异可以用于应用新值,也可以在应用新值后获取新值。就像查询一样,您定义了要返回什么值。

让我们允许JobRepository通过一个 ID 到GetJob并到Update该作业,这样我们可以稍后创建一个变异来修改作业的开始和结束日期。

job/job.go —用两个新函数更新存储库

然后打开memory.go并更新存储解决方案来处理这些新功能。

job/memory.go —用于处理作业更新的内存解决方案

接下来,我们需要给GopherService添加一个Resolver函数,我注意到 graphql-go 的一个特点是开销很大,因为我们要处理大量的interface{}。您可以通过创建助手函数来处理类型断言来避免很多开销,在下面的代码片段中,您可以看到一个用于提取字符串形式的 GraphQL 参数的grabStringArgument。变异解析器就像查询解析器一样,所以这里没有什么新东西。

gopher/resolver . go-添加了更新作业的突变解析器。

接下来,我们需要更新模式以进行突变。正如您可能已经注意到的,创建所有的graphql.Fields可能会变成相当多的代码,所以我通常会创建一个生成器函数来减少代码重复。

为了创建一个字段,我们需要一个Type,它是实现输出接口的任何东西,类似于下面的代码片段

type Output interface {
    Name() string
    Description() string
    String() string
    Error() error
}

第二个参数是解析器,它是别名FieldResolveFn func(p ResolveParams) (interface{},error),第三个是字符串描述,第四个是允许的参数映射。

schemas/factory . go-graph QL 字段的通用工厂

构建变异查询时,在schemas包中创建一个mutation.go文件。我们首先创建请求中可用的参数。我们希望突变请求有require两个参数,所以我们使用graphql.NewNonNull函数创建它们。使用NewNonNull将使 GraphQL 服务器在发送空值请求时触发一个错误。

schemas/mutation . go-可用于 Mutatejob 请求的参数。

我们需要创建包含新变异的RootMutation,就像创建查询一样。我们现在将使用generateGraphQLField来缩短代码。

schemas/mutation.go —构建根变异

在我们尝试变异之前要做的最后一件事是将 RootMutation 应用到factory.go中的模式

schemas/factory . go-将根变异添加到模式配置中。

打开 GraphiQL 试用一下。我们发送Mutation的方式与发送Query相同,只需替换关键字。

GraphiQL —发送变更请求以更改开始日期

结论

我们已经讨论了 GraphQL 的核心。在本文中,您了解了如何查询数据、对数据进行变异以及 GraphQL 的基本工作原理。您已经看到了我们如何将数据源组合成一个单一的输出,以及如何构建项目。

GraphQL 已经成长了很多,并且提供了更多。这里有一些你应该自己调查的主题,以增加你的知识。

  • 列举
  • 接口、片段和内联片段
  • 捐款

如果你想了解更多,我可以推荐 Robin Wieruch 的通往 GraphQL 之路。这本书并不关注 Go,而是从前端的角度关注 GraphQL。这本书将介绍如何使用 GraphQL 与节点后端进行交互。

完全披露——这本书的链接是一个附属链接,这意味着我有权获得一些销售收入。

你是否会使用 GraphQL?

你可以在 GitHub 上找到完整代码。

感谢您的阅读,并随时以任何可能的方式联系我,在 T witterInstagramLinkedin 上发表评论。

基于代理的建模介绍

原文:https://towardsdatascience.com/intro-to-agent-based-modeling-3eea6a070b72?source=collection_archive---------3-----------------------

Python 中基于代理的建模如何帮助确定超市柜台数量的例子

图片由皮克斯拜的 Gerd Altmann 提供

目录:

1-简介:为什么是基于代理的建模?

2-我们的超市排队问题

三模型设计

4-模型执行

5-结论

简介

基于代理的建模(ABM)是一种自下而上的模拟技术,其中我们通过其个体代理相互交互来分析系统。

假设我们想预测特定地区的 COVID 病例数,我们可以创建代表该地区人民的代理。

我们模拟了几个代理人(人)的行为,其中一些人可能戴着口罩,而其他人没有,一些人接种了疫苗,一些人非常喜欢社交,而其他人没有,等等。然后,我们模拟它们之间的相互作用以及相关的 COVID 被传输的概率…

Gif 由 statnet

运行模拟后,我们能够更好地了解整个系统……我们可以看到人群中的感染人数、康复人数、传播率、是否达到群体免疫等。我们还可以分析系统的情况(感染、恢复等)。)如果我们实施强制接种疫苗等措施。

ABM 的基石是理解微观行为中出现的宏观现象的能力。

在上面的例子中,使用 ABM 的替代方法是直接查看宏观级别的统计数据,如感染和恢复的数量,并直接分析这些统计数据的趋势。相反,ABM 强调个体代理的行为,这是一种更灵活、更精细的自下而上的方法,可以捕捉宏观模型无法捕捉的方面。

ABM 在生物学、社会科学、交通管理和供应链管理以及许多其他学科中都有应用。

这些代理的行为应该尽可能地代表现实(我们可以验证这一点),因此,例如,如果该地区 75%的人戴面具,那么我们创建的代理中有 75%被建模为戴面具的代理。

超市排队问题

假设我们正在管理一家超市的员工成本。

问题:对于一个特定的小时,我们预计会有 500 名顾客出现,我们想确定在那个小时我们应该开多少个柜台。

普通顾客价值 10 美元的毛利润,而操作一个柜台一小时的平均成本是 300 美元。

很不幸,此时此地由拍摄的图片结束了我在 Pixabay 的旅程

与标准的排队理论模型(M/M/1,M/G/1,M/M/c 等)不同。),基于代理的建模可以更容易地捕捉这种多排队、多服务器环境中的行为方面。

常见的行为包括排队犹豫(客户因为排队太长而不加入)反悔(客户加入队列但等待太久后离开)哄抢(客户从较长的队列移到较短的队列)。

我们将尝试使用反弹道导弹来解决这个问题。

模型设计

我们将基于以下假设构建一个简单的 ABM 模型:

1-我们正在优化这一小时的净利润。

在这一小时内,正好有 500 名顾客会到达超市。

3-每个顾客价值 10 美元。

4-每个柜台的运营成本为 300 美元。

基于 beta 分布,顾客在一天中的不同时间到达超市排队,这样他们更有可能在一小时的中间到达。

6-处理客户订单的平均时间为 45 秒,但处理时间因客户而异。它遵循泊松分布(为简单起见,并确保我们得到离散的非负数),平均值为 45。

7-每个顾客都有一个犹豫的容忍度,即顾客愿意加入的排队人数。如果排队的人多了,顾客就不会排队,我们就失去了销售。顾客的拒绝容忍度服从泊松分布。平均容忍度为 6,即如果队列中有 6 个或更多的其他顾客,大多数顾客会犹豫。

8-顾客选择排队最短的柜台。

注意在实际应用中,我们根据可用数据验证假设(或将其作为待优化的参数)。同样,在这个介绍性的例子中,犹豫是我们考虑的唯一行为。

我们运行 ABM 模拟 3600 步(滴答),代表一小时 3600 秒。下面是初始配置代码。

# Config
ticks = 3600 # 3600 ticks = 3600 seconds = 1 hour
no_customers = 500
avg_service_time = 45 # ticks/seconds per customer
gross_margin_per_customer = 10 # dollars
cost_per_counter = 300 # dollars

现在,我们使用 python 中的 Mesa 库来编码我们模型的其余部分。让我们从定义我们的客户类和所需的属性开始。客户类是我们将要打交道的两类代理之一,另一类是柜台。

from mesa import Agentclass Customer(Agent):
    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        # Time required to process the customer's transaction
        self.service_time = ss.poisson(45).rvs()
        # Time of arrival at queue
        self.entry_time = np.int(ss.beta(3, 3).rvs() * ticks) + 1
        self.balk_tolerance = ss.poisson(5).rvs() + 1
        # Whether or not the customer has arrived at the queue
        self._arrived = False
        self._chosen_counter = None
        self._q_entry = None
        self._q_exit = None
        # Start time when customer is being served
        self._service_entry = None
        # End time
        self._service_exit = None

我们还需要为我们的客户创建一个“分步”方法,描述他们在模拟的每一步(滴答/秒)做什么。

class Customer(Agent):
    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        # Time required to process the customer's transaction
        self.service_time = ss.poisson(45).rvs()
        # Time of arrival at queue
        self.entry_time = np.int(ss.beta(3, 3).rvs() * ticks) + 1
        self.balk_tolerance = ss.poisson(5).rvs() + 1
        # Whether or not the customer has arrived at the queue
        self._arrived = False
        self._chosen_counter = None
        self._q_entry = None
        self._q_exit = None
        # Start time when customer is being served
        self._service_entry = None
        # End time
        self._service_exit = None def select_counter(self):
        self._arrived = True
        # Queue at shortest counter
        self._chosen_counter_idx = np.argmin([
            len(counter.queue) for counter in self.model.counters])
        self._chosen_counter = self.model.counters[
            self._chosen_counter_idx]
        # Balk if there are too many people at the counter
        if len(self._chosen_counter.queue) < self.balk_tolerance:
            self._chosen_counter.queue.append(self)
            self._q_entry = self.model._current_tick def pay_n_leave(self):
        self._service_exit = self.model._current_tick
        self._chosen_counter.active_customer = None def step(self):
        if (self._arrived == False) & \
        (self.model._current_tick >= self.entry_time):
            self.select_counter()
        elif isinstance(self._service_entry, int):
            if self.model._current_tick - self._service_entry \
            == self.service_time:
                self.pay_n_leave()

在上面的代码中,在每个模拟步骤中,如果我们到达的模拟步骤/时间与客户的进入时间(他到达超市队列的时间)相匹配,那么我们运行 select_counter 方法,在该方法中,他选择具有最短队列的柜台,或者如果队列太长,他会停止。

如果顾客已经在柜台接受服务,我们检查是否已经运行了足够的步骤到达他的服务时间(处理他的交易所需的时间),然后我们运行 pay_n_leave 方法。

同样,下面的代码用于第二类代理,计数器。

class Counter(Agent):
    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.queue = []
        self.active_customer = None def dequeue(self):
        try:
            self.active_customer = self.queue.pop(0)
            self.active_customer._service_entry = self.model._current_tick
            self.active_customer._q_exit = self.model._current_tick
        except:
            pass def step(self):
        if self.active_customer is None:
            self.dequeue()

最后,我们创建一个 QueueModel 类,用于管理代理所属的整个模拟/系统。

from mesa import Model
from mesa.time import RandomActivationclass QueueModel(Model):
    """Queueing model with customers and counters as two
    types of agents that interact with each other
    """ def __init__(self, no_customers, no_counters, ticks):
        self.ticks = ticks
        self._current_tick = 1
        self.no_customers = no_customers
        self.no_counters = no_counters
        self.schedule = RandomActivation(self)
        # Create agents
        self.customers = []
        self.counters = []
        for i in range(self.no_customers):
            customer = Customer(i, self)
            self.schedule.add(customer)
            self.customers.append(customer)
        for i in range(self.no_counters):
            counter = Counter(i + no_customers, self)
            self.schedule.add(counter)
            self.counters.append(counter) def step(self):
        self.schedule.step()
        self._current_tick += 1

QueueModel 类可以用客户数量(在我们的示例中为 500)、计数器数量(这是我们试图确定的)和节拍(模拟步骤的数量,3600 代表一小时 3600 秒)来初始化。

我们有一个“schedule”属性,其中描述了哪些代理将在何时被激活。我们使用随机激活,以随机的顺序激活所有的代理。您可以阅读不同设置的台面文档

在初始化时,有两个 for 循环,我们在其中创建客户和计数器代理。我们还将它们添加到模型的时间表中。

还有一个“step”方法,它协调运行模拟的一个步骤,还触发作为时间表一部分的代理的“step”方法。

我们现在可以通过运行以下代码来运行模拟…

model = QueueModel(ticks=ticks,
    no_customers=no_customers, no_counters=no_counters)for i in range(ticks):
    model.step()

然而,我们也可以在 QueueModel 类中添加一个“数据收集器”,帮助我们跟踪感兴趣的指标。我们可以在模拟的每一步跟踪这些指标。

让我们跟踪 8 项指标:

1-到达的顾客数量。在 3600 个模拟步骤(代表 1 小时)结束时,我们应该有 500 个客户。

2-已经服务的客户数量。

3-到达队列但犹豫不决的顾客人数。我们失去了那些顾客。

4-所有计数器的平均队列大小。

5-顾客得到服务前的平均等待时间。

6-毛利润=服务的客户数量 x 每位客户 10 美元

7-运营成本=柜台数量 x 300 美元

8-利润总额=毛利率-运营成本

为了将指标添加到我们的 ABM 模型中,我们首先将它们创建为以我们的队列模型作为参数的函数…

def get_customers_arrived(model):
    customers_arrived = [
        customer._arrived for customer in model.customers]
    no_customers_arrived = np.sum(customers_arrived)
    return no_customers_arriveddef get_customers_served(model):
    customers_served = [not(customer._service_exit is None)
                        for customer in model.customers]
    no_customers_served = np.sum(customers_served)
    return no_customers_serveddef get_customers_balked(model):
    customers_arrived = [
        customer._arrived for customer in model.customers]
    # Customers who never joined a queue
    customers_no_q = np.array([
        customer._q_entry is None for customer in model.customers])
    no_customers_balked = np.sum(customers_arrived * customers_no_q)
    return no_customers_balkeddef get_avg_queue_size(model):
    queue_size = [len(counter.queue) for counter in model.counters]
    avg_queue_size = np.mean(queue_size)
    return avg_queue_sizedef get_avg_waiting_time(model):
    customers_wait = [np.nan if customer._q_exit is None else
                      customer._q_exit - customer._q_entry for customer in model.customers]
    avg_customer_wait = np.nanmean(customers_wait)
    return avg_customer_waitdef get_gross_margin(model):
    return gross_margin_per_customer * get_customers_served(model)def get_operating_costs(model):
    return cost_per_counter * no_countersdef get_total_profit(model):
    return get_gross_margin(model) - get_operating_costs(model)

最后,我们如下更新我们的 QueueModel 类…

from mesa.datacollection import DataCollectorclass QueueModel(Model):
    """Queueing model with customers and counters as two
    types of agents that interact with each other
    """ def __init__(self, no_customers, no_counters, ticks):
        self.ticks = ticks
        self._current_tick = 1
        self.no_customers = no_customers
        self.no_counters = no_counters
        self.schedule = RandomActivation(self)
        # Create agents
        self.customers = []
        self.counters = []
        for i in range(self.no_customers):
            customer = Customer(i, self)
            self.schedule.add(customer)
            self.customers.append(customer)
        for i in range(self.no_counters):
            counter = Counter(i + no_customers, self)
            self.schedule.add(counter)
            self.counters.append(counter)
        self.datacollector = DataCollector(
            model_reporters={
    'Customers Arrived': get_customers_arrived,                      
    'Customers Served': get_customers_served,
    'Customers Balked': get_customers_balked,
    'Average Waiting Time': get_avg_waiting_time,
    'Average Queue Size': get_avg_queue_size,
    'Gross Margin': get_gross_margin,
    'Operating Costs': get_operating_costs,
    'Total Profit': get_total_profit}) def step(self):
        self.datacollector.collect(self)
        self.schedule.step()
        self._current_tick += 1

我们现在准备运行我们的模型…

模型执行

让我们试着用 5 个计数器运行我们的模型…

no_counters = 5model = QueueModel(ticks=ticks,
    no_customers=no_customers, no_counters=no_counters)for i in range(ticks):
    model.step()

下面是结果和用来产生它们的代码…

run_stats = model.datacollector.get_model_vars_dataframe()fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1)
fig.figure.set_figwidth(12)
fig.figure.set_figheight(16)
fig.suptitle(f'Simulations stats using {no_counters} counters', fontsize=20)ax1.plot(run_stats[['Customers Arrived',
                'Customers Served',
                'Customers Balked',
               ]])
ax1.legend(['Customers Arrived',
            'Customers Served',
            'Customers Balked',
            ])
ax1.set_ylabel('Customers')
ax1.set_xlim(0)
ax1.set_ylim(0)ax2.plot(run_stats['Average Queue Size'], color='red')
ax2.legend(['Average Queue Size'])
ax2.set_ylabel('Customers')
ax2.set_xlim(0)
ax2.set_ylim(0)ax3.plot(run_stats['Average Waiting Time'], color='grey')
ax3.legend(['Average Waiting Time (across full hour)'])
ax3.set_ylabel('Seconds')
ax3.set_xlim(0)
ax3.set_ylim(0)ax4.plot(run_stats[['Gross Margin',
                'Operating Costs',
                'Total Profit'
               ]])
ax4.legend(['Gross Margin',
            'Operating Costs',
            'Total Profit'
            ])
ax4.set_ylabel('Dollars')
ax4.set_xlim(0)fig.show()

作者图片

x 轴代表我们正在模拟的 1 小时内的 3600 次滴答/秒。

第一个图表向我们展示了在大约 1200 秒(大约 20 分钟)后,由于太多的顾客到来,顾客开始犹豫。

在第二张图中,我们可以看到大约 10 分钟后,队列大小开始增加,并在一个小时的中间达到大约每个柜台 6 个客户的峰值。

第三张图向我们展示了平均等待时间(累积)是如何从一小时开始到一小时结束时增加的,因为许多客户在一小时中间到达,他们排着长队等待,从而推高了平均等待时间。

最后,第四张图表显示了我们的财务状况,在这一小时结束时,我们积累了 1500 多美元。

基于以上所述, 5 个柜台似乎太低了,因为我们可以看到,不到 200 名客户 (40%)拒绝并流失。

现在,让我们尝试使用 5–15 个计数器运行模拟,以确定理想的计数器数量…

full_stats = {}for no_counters in range (5, 16):
    model = QueueModel(ticks=ticks,
    no_customers=no_customers, no_counters=no_counters)
    for i in range(ticks):
        model.step()   
    run_stats = model.datacollector.get_model_vars_dataframe()
    full_stats[no_counters] = run_stats.iloc[-1]

pd.DataFrame(full_stats).transpose().astype(int)

在上面的代码中,我们用 5–15 个计数器运行模拟,并在每个模拟结束时查看统计数据(不是模拟的每个步骤)。dataframe 输出显示了不同计数器数量的结果…

作者图片

我们可以看到的总利润在 9 个柜台的情况下最大化为 2030 美元。

我们可以根据任何感兴趣的指标进行优化…即时利润不一定是最佳指标。

使用 9 个柜台的每个顾客的平均等待时间是 94 秒…通过增加一个额外的柜台,我们将等待时间减少了 33 秒,达到 61 秒,我们只损失了 90 美元(总利润是 1940 美元)。减少等待时间可能会创造更好的客户体验,从长远来看会带来更多利润。

结论

上述示例的目标是介绍基于代理的建模主题及其独特的优势,包括轻松捕捉不同代理行为的能力。通常,有人认为我们基于有限理性做出决策。

此外,另一个主要好处是能够看到微观行为如何影响整个系统。例如,我们看到,个体的阻碍容忍度如何决定不同的平均排队等待时间和不同的累积利润。

在随后的文章中,我们可以看看在根据可用数据和程式化事实进行验证之后,如何为模型选择最佳的模型假设和参数。

Julia 中的算法和构造函数介绍

原文:https://towardsdatascience.com/intro-to-algorithms-and-constructors-in-julia-562905d30071?source=collection_archive---------49-----------------------

朱莉娅综合教程

在 Julia 编程语言中一起使用类型和包的快速介绍。

(图片由作者提供)

本文视频:

SuperFrames.jl 存储库:

https://github.com/ChifiSource/SuperFrames.jl

介绍

在之前版本的 Julia 综合教程中,我们设置了新的包 SuperFrames.jl,并完成了一个 Project.toml 文件。虽然我们可能没有深入研究编码,但是在 Julia 语言中如何创建和分发包的知识在这里变得很重要。然而,对无聊的人来说幸运的是,今天我们实际上要编程并研究算法的第一部分,以创建我们新的超帧类型!

构造器

Julia 中的构造函数是一个完整的野兽,它们有自己的属性和品质,这使它们比其他编程语言中的解决方案更有价值。虽然大多数语言可能有简单的“结构”风格的构造函数,甚至“类”构造函数,但 Julia 的范例有点不同,它使用两个构造函数串联起来,使结构更适用于科学编程。

在 Julia 中,您将使用的大多数构造函数很可能是外部构造函数。您可能对外部构造函数很熟悉,因为它们是 Julia 中最基本的构造函数类型,并被移植到许多函数式编程语言中。创建新的构造类型的关键字是 struct,后跟一个定义,如下所示:

struct mytype

然后将该构造函数的数据类型放在它的下面,returns 是分隔这些参数的语法。

struct mytype
    data1
    data2end

如果我们希望在构造这种类型后数据是动态的,我们还可以在这个表达式中添加关键字“mutable ”:

mutable struct mytype
    data1
    data2
end

在我们的例子中,我们看到一个需要传递两个参数的结构:

  • columns:抽象向量的向量,可以基于矩阵位置调用它来提供适当的观察。
  • colindex:一种索引类型,我们已经从 DataFrames 中导入了它,它将接受更多的数据。
**mutable struct SuperFrame <: AbstractDataFrame
        columns::Vector{AbstractVector}
        colindex::Index
end**

这有什么不好?

这种类型的问题是,任何想要使用它的最终用户都需要通过创建自己的索引类型来调用它,然后创建向量的向量,最后通过这个构造函数来调用超帧。仅仅为了得到一个数据帧就要进行大量的编程工作,而这通常只需要一行代码就可以完成。

幸运的是,我们可以使用一个内部构造函数来创建更多的输入,并且输出与这个结构相同。为了创建一个内部构造函数,我们只需在这个构造函数中创建一个函数,它将接受相同名称下的不同类型,dispatch 将为我们处理其余的事情!

utable struct SuperFrame <: AbstractDataFrame
        columns::Vector{AbstractVector}
        colindex::Index
        function SuperFrame(dict::Dict)
        end
end

虽然这还不是一个构造函数,但它展示了这两者如何随机地一起为我们创建类型的基础。如果我们用一个向量的向量和一个索引来调用超帧构造函数,我们仍然可以创建超帧类型,但是如果我们想从字典中的数据创建一个新的超帧,我们可以传递它并调用内部构造函数,这个构造函数用来获取字典。也就是说,我们现在需要一种算法,能够将字典转化为向量的向量和索引。让我们从 DataFrames.jl 中的索引类型开始。

struct Index
    lookup::Dict
    names::Array{Symbol}end

从这个结构的外观来看,为了创建我们的新索引类型,我们需要一个字典 lookup,它将保存与整数相关的行计数的值,以及一个符号数组,我假设它将是我们的列的名称。当然,这些列名与我们字典中的键相关。

伟大的软件工程的一个关键支柱是一个叫做 MVP 的概念,或者最小可行产品。这个概念的意思是,最初每当程序员想要解决一个问题时,他们不应该担心细节——而应该只担心它开始工作。我认为这是一个伟大的编程策略,功能可以随着时间的推移而改变和优化,但如果我们没有一个可行的方法,那么我们甚至不能告诉你我们是否能够得到我们想要的结果,或者我们是否需要为我们的特定问题尝试一些不同的东西。

可以这样想——我们需要做一个函数,对我们将来可能使用的东西进行概念验证。考虑到这一点,虽然我们当然有可能以更简洁的方式做到这一点,但我认为在优化之前思考问题肯定是任何算法都要走的路。我们需要做一个相对基本的小算法来为一个查找字典枚举字典的值,并将我们的名字推到一个数组中,我们可以将这个数组传递给这个新类型。让我们首先考虑我们需要什么,一个字典和一个数组:

index = 0
names = []
lookup = Dict()

首先,我决定使用索引计数器——只是为了展示循环算法的可能性。在用循环填充数据类型时,定义要在循环中填充的内容是一种非常常见的编程实践。然而,有一些更深入的方法,我们将在未来改进这个函数,这些方法将成为解决我们现在要用一个计数器和两个空数组解决的问题的替代方法。

我将索引设置为等于零的整数数据类型,将名称设置为一个空数组,我们打算用符号填充该数组,最后查找具有相应枚举计数的 Dict 数据类型。现在让我们看看如何构造一个循环。在 Julia 中,我们对待多个输出就像对待 for 循环中的返回一样。但是,这些变量名必须包含在一个列表中,否则我们将得到

"无效的迭代规范"

扔给我们。该循环在头部看起来像这样,可以认为它类似于我们在本系列的循环重现中讨论的 zip()循环。

for (name, data) in dict
    append!(names, name)
    index += 1
    push!(lookup, name => index)
end

现在我认为谈论范围是很重要的。为什么我们要在这个循环之前初始化字典和列表数据类型?这是因为一个叫做作用域的概念,我们将在本系列的下一期更多地讨论这个概念。范围是一个重要的编程概念,它与应用程序不同级别的类型的保密性有关。这就是为什么我们可以在同一个文件中使用同一个变量名 100 次,只要使用不同的函数和类型。变量、数据和我们在这个函数中写的任何东西都是这个函数的私有范围。这意味着我们没有一个全局定义的等于零的变量 index。如果是这种情况,我们可以加载模块,然后变量将是可用的。

虽然函数、类型、模块和全局环境都有范围,但循环也有。也就是说,这个循环定义中的变量名专用于这个迭代任务。当循环返回 0 时,它们被销毁,并且除了知道函数正在保存一个执行 _ 和 _ 的循环之外,函数不会以任何方式保存它们。

最后,这个 for 循环相对简单,只需要将字典中包含的名称附加到新的名称符号数组中。然后我们在索引中添加一个,并把它作为一个对应的对放到我们正在循环的当前名称中。

这是我们创建索引类型所需的两种类型。现在所有这些都完成了,我们可以将它们插入 DataFrames.jl 中 Index 的外部构造函数,并创建一个索引:

names = Vector{Symbol}(names)
index = Index(lookup, names)

(我还将 Vector{Symbol}类型转换成了名称。不这样做可能会导致 methoderror,但是我先发制人地把它放在了那里。)

结论

我对这个项目感到非常兴奋!对于新的索引类型,我们已经完成了一半的工作,并且几乎准备好开始使用来自数据帧的方法。我保证在接下来的几集里,我们在这个包的基础上自动获得的扩展功能是值得的!我还想说,在这一集里,我还想回顾一些事情,所以不要担心,我们才进行了一半,我会继续解释,进一步解释和演示范围,并优化这个函数。

我特别激动,把这个简短的算法优化成只有几行,以显示朱莉娅的力量。如果你认为你有一个更好的方法,请随意在 Github 上分叉存储库,何乐而不为呢!我很乐意解释你的代码是如何工作的!我认为最好的方法是使用 enumerate()方法(我们还没有讨论过它,所以我没有使用它),或者按位置调用键,或者看看循环语法是否支持基于字典的键和值对以及枚举对来迭代 3 个元素。无论如何,我相信这将是一个有趣的朱利安实验步行!谢谢你的观看和阅读,它对我来说意味着整个世界!

AsterixDB 简介—第 1 部分

原文:https://towardsdatascience.com/intro-to-asterixdb-part-1-13b1f0fdff56?source=collection_archive---------35-----------------------

具有地理空间功能的“一刀切”大数据管理系统

纳斯蒂亚·杜尔希尔在 Unsplash 上的照片

介绍

AsterixDB 是一个可扩展的开源大数据管理系统(BDMS ),具有地理空间功能。在这里,你可以看到更多的特点,因此它被描述为“一个尺寸适合一群人”尽管如此,本教程不会太深入探讨 AsterixDB 的复杂性和潜力。相反,我将创建三篇博文,作为 AsterixDB 新手的通用实用教程,同时展示 AsterixDB 的新地理空间功能。帖子将按以下顺序排列:

  1. 准备并加载数据
  2. 执行空间查询
  3. 衡量绩效

在这篇博客中,我将讨论如何对现有数据执行空间查询。因此,我将解释如何下载数据、创建我们的模式(dataverse、datatypes 和 datasets)、加载我们的数据以及转换和插入我们的数据。此外,我们将使用不同的文件类型,以便学习如何使用 AsterixDB 以各种格式输入数据。在下一部分,我们将下载我们的数据。

选择数据

首先,我们需要找到包含地理空间属性的数据。为此,我们将访问 UCR 之星网站(大型空间数据集的免费可视化目录)。有各种各样的数据可供选择,欢迎您自由下载您想要的任何数据集(尽管在本教程之后这样做可能会更好)。然而,在我们的示例中,我们将使用 NE/urban_areas (城市地区)和Yin/insta gram-Twitter(insta gram-Twitter)数据集的子集。城市区域数据集利用多边形作为其地理空间属性来表示“人口密集居住”的区域。然而,Instagram-Twitter 数据集利用点数作为其地理空间属性来表示用户在 Twitter 上发推文或在 Instagram 上发帖的位置。我选择这些数据集是因为我想让我们对地理空间查询的理解简单而直观。因此,对于一个包含多边形的数据集(城市区域数据集)和另一个包含点的数据集(Twitter-Instagram 数据集),我们将创建可以分析多边形和点之间关系的查询,即我们希望计算出每个多边形中有多少个点。因此,我们希望在本教程结束时回答的一些问题包括:

  1. 我们的数据集中有多少城市地区和 Tweets & Instagram 帖子?
  2. 每个市区有多少条 Tweets & Instagram 帖子?
  3. 有多少 Tweets & Instagram 帖子不在市区范围内?
  4. 哪个城区的推特& Instagram 帖子最多/最少?
  5. 有多少条推文在近距离内?

为了简化数据量和减少查询时间,我们将只查看北美西海岸(的一部分)——从加拿大的不列颠哥伦比亚到墨西哥的下加利福尼亚。同样,这是城市地区Instagram-Twitter 的数据子集。这些链接会将您带到一个类似于下图的地图:

NE/urban_areas 数据集(左)和 yin/instagram-twitter(右)截图

在左下角,我们可以看到数据集的属性(除了几何属性)。单击“下载数据”查看您的下载格式选项。确保您位于“可见区域”选项卡上,而不是“完整数据集”选项卡上。对于城市区域数据集,选择 JSON+WKT 格式。如果您不认为这是一个选项,请刷新页面并重试。下载数据集的示例如下:

显示如何下载东北/城市区域数据集的 GIF

下载 Instagram-Twitter 数据集将是类似的,但是,选择 CSV 作为格式。需要注意的是,JSON+WKT 格式可以很好地与 AsterixDB 兼容。然而,CSV 不是这种情况,因此 CSV 将需要稍微多一点的努力来充分加载到 AsterixDB 中。在下一节中,我们将继续定义我们的数据模型。

定义数据模型

现在我们已经下载了文件,我们需要安装 AsterixDB。请看文档这里开始。下载完成后,启动示例集群。现在,随着集群的运行,在浏览器中打开 http://localhost:19006 来访问 AsterixDB 管理控制台。接下来,我们将通过输入以下 dataverse 和 datatype 定义来定义我们的数据模型:

DROP DATAVERSE PracticeData IF EXISTS; 
CREATE DATAVERSE PracticeData;
USE PracticeData;CREATE TYPE UrbanAreasType AS {
 id: UUID,
 g: geometry?,
 scalerank: int?,
 featurecla: string?,
 area_sqkm: double?,
 min_zoom: double?
};CREATE TYPE TempInstagramTwitterType AS {
 x: double,
 y: double,
 user_id: int,
 timestamp : int32
};CREATE TYPE InstagramTwitterType AS {
 id: UUID,
 geometry: geometry,
 user_id: int,
 timestamp: int32 
};

首先,我们将数据节命名为PracticeData。这基本上是所有东西存放的地方。因此,在继续运行您的查询之前,USE PracticeData;出现是很重要的。

现在,请仔细检查三种不同数据类型的模式。值得注意的是,每个数据类型中的每个属性的名称都是命名的,然后属性的数据类型在冒号后指定。此外,属性的名称必须与被加载的数据的属性相对应(我们将在后面的章节中讨论一个具体的例子)。

UrbanAreasType比较直截了当。我们用 UUID 类型定义了id,一个几何属性被标记为g,更重要的是,我们有 int 类型的scalerank、string 类型的featurecla、double 类型的area_sqkm和 double 类型的min_zoom。我还想指出的是,我们在定义数据类型之后添加了一个?来表示该属性是可选的。我们这样做是因为Urban Areas中的数据有一些行没有属性geometryscalerankfeatureclaarea_sqkmmin_zoom

至于其他两个数据集,我们将创建TempInstagramTwitterType作为临时数据类型来保存来自 CSV 文件的数据。然后,我们将把结果数据集中的数据转移和转换到将使用InstagramTwitterType的数据集中。我们这样做有多种原因:(1) CSV 缺乏对基本类型 geometry 的支持,以及(2)我们不希望通过在空间查询中创建几何来增加开销(我们将在后面的小节中讨论)。在TempInstagramTwitterType中举例说明了这一点,其中我们将属性标记为xy,数据类型为 double,但是在InstagramTwitterType中,我们将属性标记为geometry,数据类型为 geometry。我们最终将把前两个属性转换成一个几何属性,存储在使用InstagramTwitterType的数据集中。同样的推理也适用于TempInstagramTwitterType中缺少id属性的情况。我们的临时数据集不需要一个id属性,但是我们需要一个id属性(我们将自动生成)用于将使用InstagramTwitterType的数据集。

在下一节中,我们将创建数据集并加载数据。

创建和加载数据

在这里,我们将加载数据。所以,我们做了如下工作:

USE PracticeData;CREATE DATASET UrbanAreas (UrbanAreasType) PRIMARY KEY id AUTOGENERATED;LOAD DATASET UrbanAreas using localfs
(("path"="127.0.0.1:///Users/andretran/Downloads/NE_urban_areas.json"), ("format"="adm")); CREATE EXTERNAL DATASET TempInstagramTwitter
(TempInstagramTwitterType) using localfs (("path"="127.0.0.1:///Users/andretran/Downloads/yin_instagram-twitter.csv"), ("format"="delimited-text"), ("header"="true"));CREATE DATASET InstagramTwitter (InstagramTwitterType) primary key id autogenerated;

首先,我们再次确保我们使用的是 dataverse PracticeData

现在,对于第一个数据集,我们使用数据模型UrbanAreasType创建数据集UrbanAreas,我们将primary key设置为id,并指定它为autogenerated(这只是意味着 AsterixDB 将创建唯一的 id)。如果我们的数据集已经有一个带有唯一 id 的属性,我们可以省略autogenerated。然后,我们使用localfs在本地加载数据集。为此,AsterixDB 需要两个参数。首先,我们指定文件的路径。然后,我们需要指定我们的格式为adm,因为文件的格式是 JSON。设置了这两个参数后,数据应该可以正确加载了。

对于我们的第二个数据集TempInstagramTwitter,我们不会在本地创建数据集或加载该数据集。相反,我们将创建一个外部数据集,因为我们将把该数据转换成我们的第三个数据集— InstagramTwitter。这减少了加载文件的开销,因为这是一个临时数据集。加载该数据集需要三个参数。同样,我们指定路径。然后,我们指定格式为delimited-text,因为我们的文件格式是 CSV。最后,我们将header设置为true,这样我们就不会读取文件中的第一行。数据应该正确加载。

为了确保我们的数据已经加载,我们运行以下查询:

USE PracticeData;SELECT * 
FROM UrbanAreas

USE PracticeData;SELECT * 
FROM TempInstagramTwitter;

这些查询应该返回以下内容:

来自 UrbanAreas 数据集(左)和 TempInstagramTwitter 数据集(右)的查询数据的屏幕截图

有了这些信息,我们可以回答我们的第一个问题,即“我们的数据集中有多少城市地区和推文& Instagram 帖子?”正如我们在截图中看到的,我们的 UrbanAreas 数据集有 163 行,InstagramTwitter 数据集有 126263 行。

现在,将我们的两个文件加载到前两个数据集中,我们创建第三个数据集作为InstagramTwitter。同样,我们将我们的primary key设置为id,并且通过 AsterixDB 得到我们的 idautogenerated。我们故意不将任何数据加载到该数据集中,因为我们现在将转换我们的TempInstagramTwitter数据,并在下一节将其插入到该数据集中。

转换和插入数据

这里,我们将把数据从TempInstagramTwitter转换到InstagramTwitter。如前所述,CSV 缺乏对几何作为基本类型的支持。因此,我们将利用一个内置的空间函数st_make_pointTempInstagramTwitter获取geometry属性,并将其转换为原始类型的几何图形。此外,我们还需要将其他属性(user_idtimestamp)转移到数据集。我们通过查询来自TempInstagramTwitter的数据并将结果数据插入到InstagramTwitter数据集中来做到这一点。因此,我们的查询应该如下所示:

USE PracticeData;INSERT INTO InstagramTwitter
(
 SELECT st_make_point(x, y) AS geometry, user_id, timestamp
 FROM TempInstagramTwitter 
);

以下是对上述代码片段的一些补充说明。我们将转换后的几何图形属性的名称设置为geometry,以确保该属性具有正确的名称。如果我们不设置名称,AsterixDB 将把我们转换的几何数据作为一个没有名称的属性插入到InstagramTwitter数据集中。这将使得查询和保留没有任何数据的geometry属性变得几乎不可能。然后,运行下面的查询:

USE PracticeData;SELECT VALUE i 
FROM InstagramTwitter AS i;

该查询应返回以下内容:

InstagramTwitter 数据集的查询数据截图

从上面的截图中,我们可以通过检查我们之前从TempInstagramTwitter数据集获得的截图来验证我们的数据已经加载。同样,我们在转换后的数据集中有 126263 行,这意味着数据加载正确。我们还可以看到不再有xy属性。相反,我们有一个 geometry 类型的单个geometry属性,它保存来自xy属性的转换数据。

结论

随着第三个数据集的加载,我们终于完成了将数据加载到 AsterixDB 中。在下一部分中,我们将对包含几何属性的数据集执行空间查询。

参考

5 分钟 BlazingSQL 简介

原文:https://towardsdatascience.com/intro-to-blazingsql-in-5-minutes-172162d3a95?source=collection_archive---------17-----------------------

在几秒钟内在 GPU 上更快地查询您的数据

SQL 是数据世界中大量使用的基本工具。数据工程师、数据科学家、业务分析师使用 SQL 进行任何奇特的数据查询和操作。大多数行业正在接近这个有趣的转折点,每天产生的数据量是不可想象的。以更快的速度有效处理它们的需求成为一个挑战。BlazingSQL 前来救援的情况!

尼尔·马克·托马斯在 Unsplash 上拍摄的照片

什么是炽热的 SQL?

BlazingSQL 是一个 GPU 加速的 SQL 引擎,完全建立在 RAPIDS AI 之上。这是一个可扩展的非常直观的 SQL 接口,用于将大量数据集加载到 GPU 内存中。它是构建的分布式 SQL 引擎,可以无缝地工作,尤其是在 RAPIDS.ai 生态系统内部。下面是急流。人工智能堆栈:

图片来自罗德里戈的文章

BlazingSQL 运行在 Dask 上,Dask 是另一个并行化工作流、功能等的开源工具。,跨多个内核/机器。Dask 可以将任务分配到多个 GPU 上,使其速度快如闪电。当您听到 SQL 时,您会认为它需要一个数据库来存储数据,但事实是——对于 BlazingSQL,不需要任何数据库。

BlazingSQL 的诞生:

BlazingSQL 徽标

Felipe 和 Rodrigo Aramburu 是开发 BlazingSQL 的负责人。在为秘鲁财政部工作时,他们进行了大量的 SQL 操作,需要大约 30-40 个小时才能完成。他们看到了 GPU 的利用不足,并想到利用 GPU 的能力来执行 SQL 操作。花了 35 个小时的 SQL join 执行,用 GPU 只用了 30 秒,BlazingSQL 就这样诞生了。它于 2018 年首次发布,现在是 Apache 2.0 许可下的开源包。观看以下视频,了解有关 BlazingSQL 的更多信息:

安装:

GPU 是运行 BlazingSQL 的唯一最低要求。BlazingSQL 可以通过以下方式与 condo 一起安装:

作者创造的形象

用法:

使用 BlazingSQL 非常简单。如前所述,它使用 GPU 来执行更快的计算,因此建立在 RAPIDS 生态系统上。下面是如何将数据帧加载到 BlazingSQL 中,然后在其上执行所需操作的示例:

它还有其他几个重要的组件,可以用来增强 BlazingSQL 的使用并提高其灵活性和性能。

  1. 内存管理:它有一个界面,可以用来跟踪内存消耗。你可以在这里找到更多信息。
  2. 通信:BlazingSQL 有一个模块,允许使用 TCP 或 UCX 协议进行高性能的节点到节点通信。
  3. Interops: Interops 代表解释操作,这是一个强大的基于行的数据转换引擎。这里基于行的操作指的是以相同方式应用于所有行的任何转换,而与任何其他行无关。
  4. 数据结构:BlazingSQL 使用自己的方式通过燃烧表处理数据。Blazing Table 是 cudf 表的包装器。更多细节可以在这里找到。

比较:

Blazing SQL 的创始人已经写了几篇文章,展示了它与 Spark 等其他方法相比的速度。例如,从 Google Drive 加载 CSV 到 dataframes 的时间比 Apache Spark 快 71 倍。下面是从罗德里戈的文章中截取的速度对比截图:

图片来自 Rodrigo 关于速度比较的文章

优势:

  • 可用于不同的格式:Blazing SQL 的伟大之处在于它兼容多种数据格式,并且速度惊人。它们是:
  1. 战斗支援车
  2. 阿帕奇拼花地板
  3. GDF — GPU 数据框架
  4. 熊猫
  5. JSON
  • 与各种文件系统一起使用:BlazingSQL 不仅限于在本地集群上工作。它可以用于在亚马逊 S3、谷歌存储或 Hadoop 等云平台上外部查询数据。
  • 如果您的 groupby 函数需要花费很长时间,那么尝试使用 BlazingSQL 在创纪录的时间内完成这些情况。在大型数据集上需要几小时或几天的查询可以在几秒钟内完成。
  • 我觉得最大的优势是,即使你的笔记本电脑/系统上有一个小的 GPU,你也可以利用它来执行复杂的 SQL 查询。

局限性:

尽管我想到了一些限制:

  • 在处理较小的数据集时没有帮助。
  • 总是需要 GPU 来运行查询。
  • Spark 已经相当成熟,可能很难很快被取代。Spark 可以处理 HDFS、HBase、Cassandra、Hive 和任何 Hadoop InputFormat 中的数据,而 BlazingSQL 还不能处理这些数据。

结论:

BlazingSQL 是人工智能领域的游戏规则改变者。随着时间的推移,我确实相信它将取代许多其他工具,成为许多组织的工作马。感谢你抽出时间阅读这篇文章。

推特LinkedIn 上关注我。你也可以通过 pratikkgandhi@gmail.com 联系我

想成为 中等会员 享受无限制阅读文章的乐趣,请注册成为会员。Medium 将与我分享一部分给使用以上链接注册的成员!谢了。

介绍如何比较和分析多个间隔不均匀的时间序列信号

原文:https://towardsdatascience.com/intro-to-comparing-and-analyzing-multiple-unevenly-spaced-time-series-signals-e46b2347972a?source=collection_archive---------8-----------------------

分析多个时间序列信号的方法,这些信号发生在同一时间段,但具有不同的时间戳和时间间隔

照片由内森·杜姆劳Unsplash 上拍摄

假设我们有以下场景——我们有两个不同的传感器测量电池组上的电流和电压。现在,我们想对这些信号进行一些基本分析,即查看一段时间内的功耗(等于电流乘以电压),然后对该信号进行数值积分,以计算给定时间内经过的能量。然而,当您打开数据时,您会注意到尽管时间窗口相同,但数据点的各个时间戳并不匹配—我们现在该怎么办?

让我们从模拟这个场景开始。我们将为电流和电压创建两个时间序列数据集,电流在一小时内每 10 秒收集一次,电压在一小时内每 15 秒收集一次。更复杂的是,我们将为所有电压数据增加一个 3 秒的偏移。我们可以使用名为date_range()的内置pandas函数来创建时间范围,该函数接受开始时间、结束时间和频率。要添加常数时间偏移,我们可以使用pd.Timedelta()。最后,为了在我们的电流和电压测量中引入一些噪声,我们将使用np.random.random()通过numpy从-0.05 至 0.05(电流)或-0.1 至 0.1(电压)之间的均匀分布中进行采样。

**# Package Imports** import pandas as pd
import numpy as np
import matplotlib.pyplot as plt**# Current Data** np.random.seed(11)
t_current = pd.date_range("01:00:00", "02:00:00", freq="10s")
noise = 0.05 * (np.random.random(len(t_current)) - 0.5)
current = 5 + noise.cumsum()**# Voltage Data** np.random.seed(7)
t_voltage = pd.date_range("01:00:00", "02:00:00", freq="10s") + pd.Timedelta("3s")
noise = 0.05 * (np.random.random(len(t_voltage)) - 0.5)
voltage = 12 + noise.cumsum()

现在,让我们将这些数据集转换成pandas数据帧,并绘制出我们的两个信号:

**# Make current and voltage dataframes** df_current = pd.DataFrame({"timestamp": t_current, "current": current})
df_voltage = pd.DataFrame({"timestamp": t_voltage, "voltage": voltage})**# Plot two signals** plt.style.use("seaborn-darkgrid")
plt.rcParams["font.family"] = "Poppins"
plt.rcParams["font.size"] = 16**# Create subplots and plot** fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1, figsize=(12, 6))
ax1.plot(df_current["timestamp"], df_current["current"])
ax2.plot(df_voltage["timestamp"], df_voltage["voltage"])**# Edit x-tick time format** ax1.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
ax2.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))**# Add axis labels** ax1.set(ylabel="Current (A)")
ax2.set(ylabel="Voltage (V)")
plt.show()

原始电流和电压数据

现在,如果我们放大一小部分图,并在实际时间戳所在的线上添加标记,我们会注意到当我们试图将这两个信号相乘时会出现的问题:

**# Create subplots and plot** fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1, figsize=(12, 6))
ax1.plot(df_current["timestamp"], df_current["current"])
ax2.plot(df_voltage["timestamp"], df_voltage["voltage"])**# Edit x-tick time format** ax1.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
ax2.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))**# Add axis labels** ax1.set(ylabel="Current (A)", xlim=[pd.Timestamp("01:00:00"), pd.Timestamp("01:03:00")])
ax2.set(ylabel="Voltage (V)", xlim=[pd.Timestamp("01:00:00"), pd.Timestamp("01:03:00")])
plt.show()

原始数据的放大视图

两个信号之间的时间戳都不一致,那么我们如何将它们相乘呢?我们现在来看两种不同的策略来处理这个问题——填充值和重采样。

首先,让我们结合电流和电压数据帧。为此,我们将添加一个描述测量值的列sensor和一个包含传感器值的value列。这样,我们在两个数据帧之间就有了一致的模式,并且可以通过追加来轻松地组合它们。

**# Update dataframe schemas** df_current["sensor"] = "current"
df_current = df_current.rename(columns={"current": "value"})df_voltage["sensor"] = "voltage"
df_voltage = df_voltage.rename(columns={"voltage": "value"})**# Combine dataframes** df_sensor = df_current.append(df_voltage)

组合电流和电压数据框架

创建数据透视表

我们应该做的第一件事是透视我们新的组合数据框架— 我们希望我们的新列是sensor列的唯一值和它们相应的值。这将允许我们并排查看两个传感器的测量值。我们使用df_sensor.pivot()来实现这一点,它接受以下参数:

index —用作数据透视表索引的列

columns —我们将从中获取唯一值来创建新列的列

values —我们新栏目的价值

**# Pivot the dataframe** df_sensor_pivot = df_sensor.pivot(index="timestamp", columns="sensor", values="value")

传感器上带枢轴的数据框

这里我们可以直接看到我们的问题,没有来自两个传感器的值重叠的行——或者current或者voltage为空。我们将从填充值的策略开始。

向前或向后填充

我们可以做的最简单的事情就是简单地用它前面的值填充所有的空值——我们可以向前(ffill())或向后(bfill())这样做。一般来说,我们希望向前填充,因为向后填充是使用未来的信息来创建过去的数据。这种填充过程的结果是产生一个阶梯状信号,因为我们保持传感器值不变,直到它下一次改变。我们按如下方式进行,并绘制数据:

**# Forward fill data** df_sensor_pivot = df_sensor_pivot.ffill()**# Create subplots and plot** fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1, figsize=(12, 6))
ax1.plot(df_sensor_pivot["current"], marker="o")
ax2.plot(df_sensor_pivot["voltage"], marker="o")**# Edit x-tick time format** ax1.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
ax2.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))**# Add axis labels** ax1.set(ylabel="Current (A)", xlim=[pd.Timestamp("01:00:00"), pd.Timestamp("01:03:00")])
ax2.set(ylabel="Voltage (V)", xlim=[pd.Timestamp("01:00:00"), pd.Timestamp("01:03:00")])
plt.show()

正向填充时的电流和电压数据

我们看到应用正向填充如何产生突变的阶跃信号,特别是对于测量频率较低的电压。然而,我们仍然可以将这些值相乘来得到功率,因为我们现在有重叠的时间戳:

**# Calculate Power** df_sensor_pivot["power"] = df_sensor_pivot["current"] * df_sensor_pivot["voltage"]**# Create subplots and plot** fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, ncols=1, figsize=(12, 9))
ax1.plot(df_sensor_pivot["current"])
ax2.plot(df_sensor_pivot["voltage"])
ax3.plot(df_sensor_pivot["power"])**# Edit x-tick time format** ax1.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
ax2.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
ax3.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))**# Add axis labels** ax1.set(ylabel="Current (A)")
ax2.set(ylabel="Voltage (V)")
ax3.set(ylabel="Power (W)")
plt.show()

正向填充电流和电压信号以及计算功率

数据重采样

另一种选择是将数据完全重新采样到一个已知的时间间隔。然而,为了使其有效;我们希望对较低频率的数据进行重新采样,在本例中为 15 秒。我们现在的问题是,由于电流是每 10 秒收集一次,因此我们将在每个 15 秒窗口内收集多个电流数据点。因此,我们需要使用一个聚合函数来处理这个问题。一种常用的方法是取落入每个时间窗口的所有值的平均值,因此我们将这样做(假设df_sensor_pivot处于我们之前进行的向前填充之前的状态)。为了重新采样,我们必须确保我们的 dataframe 中有一个索引列,它是一个 datetime 对象(我们在执行 pivot 操作时设置了index参数,从而做到了这一点)。

**# Resample our dataframe to 15 seconds** df_sensor_pivot = df_sensor_pivot.resample("15s").mean()**# Create subplots and plot** fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1, figsize=(12, 6))
ax1.plot(df_sensor_pivot["current"], marker="o")
ax2.plot(df_sensor_pivot["voltage"], marker="o")**# Edit x-tick time format** ax1.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
ax2.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))**# Add axis labels** ax1.set(ylabel="Current (A)", xlim=[pd.Timestamp("01:00:00"), pd.Timestamp("01:03:00")])
ax2.set(ylabel="Voltage (V)", xlim=[pd.Timestamp("01:00:00"), pd.Timestamp("01:03:00")])
plt.show()

带重采样的电流和电压数据

现在,我们可以看到,通过重新采样,电流和电压信号中的点间隔均匀。现在,我们可以用与正向填充示例类似的方式来计算功率。

重新采样的电流和电压信号以及计算的功率

我们从两种方法中得到了相似的结果——现在,为了了解两种结果之间的差异,让我们来计算总能量,即功率的时间积分。我们将使用梯形积分,因此我们首先取连续值的平均值,乘以它们之间的时间间隔,然后将它们全部求和。

**# Reset index to get timestamp column** df_sensor_pivot = df_sensor_pivot.reset_index()**# Get average of consecutive values** df_sensor_pivot["midpoint"] = (df_sensor_pivot["power"] + df_sensor_pivot["power"].shift()) / 2**# Get the time difference between rows** df_sensor_pivot["time_diff"] = (df_sensor_pivot["timestamp"] - df_sensor_pivot["timestamp"].shift()).apply(lambda t: t.total_seconds())**# Calculate the area of the trapezoid** df_sensor_pivot["energy_kJ"] = df_sensor_pivot["midpoint"] * df_sensor_pivot["time_diff"] / 1000**# Get total energy** df_sensor_pivot["energy_kJ"].sum().round(3)

我们为这两个方法获取以下值:

正向填充:219.233 kJ
重采样: 219.229 kJ

误差仅为 0.004 kJ,因此在这种情况下,两种方法都能产生可接受的结果。一般来说,正向填充将导致更大的积分值,因为它保持相同的值,直到重新采样和聚集(在这种情况下)导致窗口中信号的平均值发生变化。如果足够频繁地获取数据点,这两种方法都应该工作得很好,并允许您处理来自多个不匹配的源的时间序列数据。

结论

感谢阅读这篇教程,学习如何在信号空间不均匀和不匹配的情况下进行时间序列分析。在这个 Github 资源库中可以找到一个笔记本,上面有本文中的例子。

感谢您的阅读!我感谢任何反馈,你可以在 Twitter 上找到我,并在 LinkedIn 上与我联系,以获取更多更新和文章。

自然语言处理中共指消解简介

原文:https://towardsdatascience.com/intro-to-coreference-resolution-in-nlp-19788a75adee?source=collection_archive---------10-----------------------

共指消解如何在不需要额外上下文的情况下获得大量信息。

作者pawemielniczukMarta malankowska

照片由 Richa Sharma 拍摄

介绍

自然语言处理(NLP)是指人类和机器之间的交流。NLP 是人工智能中最具挑战性的分支之一,这主要是因为我们的人类语言充满了计算机难以学习的例外和歧义。让他们更容易理解的一个方法是去掉任何需要上下文才能清楚理解的不精确的表达。一个很好的例子是代词(如 it,he,her),可以用它们所指的特定名词来替换。

但是现实世界的应用呢?

在为 LMS 平台开发问答系统的时候,我们遇到了几个问题。尤其是句子嵌入——文本的向量表示。有时一个句子会由许多代词组成。当没有提供足够的上下文时,这样的嵌入通常不能正确地反映原始句子。为了获得更丰富的嵌入,我们在管道中应用了共指解析。

什么是共指消解?

共指消解(CR)的任务是在一个给定的文本中找到所有语言表达式(称为提及),这些表达式指的是同一个现实世界的实体。在找到并分组这些提及之后,我们可以通过用名词短语替换代词来解决它们,如上所述。

共指消解是一个非常通用的工具,可以应用于各种 NLP 任务,如文本理解、信息抽取、机器翻译、情感分析或文档摘要。这是获得计算机更容易理解的明确句子的好方法。

共指与回指消解

应该注意的是,我们将共指消解称为寻找和解析文本中的引用的一般问题。然而,从技术上讲,有几种提法,它们的定义是有争议的。

与共指消解(CR)最不同的一种情况是回指消解(AR)。当一个术语指代另一个术语并决定第二个术语的一种解释时,回指关系就出现在语篇中。在下面的例子中,我们看到(1)和(2)直接指的是不同的现实世界的实体,但是它们在相同的上下文中使用,我们对(2)的解释依赖于(1)。这些提及并不共指,而是回指关系。

尽管回指消解不同于共指消解,但在大多数情况下,两者是等同的。还有更多这种差异的例子和各种其他类型的参考。然而,责任范围最广,涵盖绝大多数情况。为了简化这个主题,从现在开始,我们假设术语之间的所有类型的关系都是共指的。

不同类型的参考

即使我们假设可以把各种指称当作共指,术语之间仍然有许多不同形式的关系值得注意。这是因为每种类型都可以区别对待,大多数经典的自然语言处理算法都是针对特定类型的引用而设计的。[ 1

回指和下指

这些是我们话题的主要内容。主要区别是,回指出现在句子中它所指的词之后,下指出现在它之前。出现在回指之前的词叫做先行词,出现在下指之后的词叫做后置词。

分裂前因

这是一种回指表达,代词(2)指代不止一个先行词(1)。

指代名词短语

这也是一个照应的例子,其中第二个名词短语(2)是对一个表达式(1)的早期描述形式的引用。

预设/约束变量

一些人争论预设是否可以归类为共指(或任何其他“指称”)消解类型。这是因为代词(2)并不完全是指称的——在某种意义上,我们不能用量化的表达式(1)来代替它。然而,代词毕竟是一个受先行词[ 3 ]约束的变量。

误导的代词指代

也有某些情况会产生误导。当代词和文本中的其他词之间没有关系时,代词仍然存在。在创建 CR 算法时,我们需要特别注意这些类型的引用,因此了解我们在什么情况下会接触到它们是很好的。

使分开

分裂句被认为是一个复杂的表达,有一个更简单,更少欺骗性的替代。在这种情况下,代词“It”是多余的,我们可以很容易地找到一个意思相同但没有使用代词的句子。

冗长的“它”

这种提法在英语中很常见,所以需要强调。代词“it”不指任何其他术语,但它在句子中是必要的,以便组成一个语法表达式。

通过示例解决共指的步骤

最好是将一个想法形象化,并提供一个具体的例子,而不是仅仅对一个主题进行理论化。此外,我们将尝试解释并给出最常见术语的具体示例,这些术语与我们在文章和论文中可能遇到的共指消解相关。

应用共指消解的第一步是决定我们是希望使用单个单词/标记还是范围。

但是到底什么是跨度呢?最常见的情况是,我们想要交换的不是一个单词,而是多个相邻的标记。因此跨度是一个整体表达。你可能遇到的另一个名字是提词。它们经常互换使用。

在大多数现有技术解决方案中,只考虑跨度。之所以如此,是因为跨度在其中携带了更多的信息,而单个标记本身可能无法传达任何特定的细节。

步骤 1 —确定潜在跨度

下一步是以某种方式将跨度组合成组。

正如我们从 J.R.R .托尔金的名言中看到的,有几个潜在的跨度可以组合在一起。这里我们有像“Sam”或“his”这样的跨度,其中只有一个标记,但我们也看到跨度“一颗白星”由三个连续的单词组成。

组合项目被称为聚类或分组。顾名思义,这是一种将任意对象组合成簇/组的方法,在这些簇/组中,这些项目共享一个共同的主题。从自然语言处理中的单词,到网飞的电影分类,再到基于营养价值的食物分类。

有许多方法可以分组,但重要的是同一组中的事物应该具有相似的属性,并尽可能与其他组不同。

步骤 2 —组跨度

这里,我们正在寻找的“属性”是指同一个现实世界实体的跨度。

产生的组有[Sam,his,he,him]以及[a white star,it]。请注意,“山姆”和“一颗白星”被标记为实体。这是消解共指的关键一步。我们不仅需要识别相似的跨度,还需要确定它们中的哪一个是现实世界中的实体。

现实世界的实体没有单一的定义,但我们将简单地将其定义为一个任意的对象,不需要任何额外的上下文来阐明它是什么,在我们的示例中:“Sam,或“一颗白星”。另一方面,“他的”或“他”不是真实世界的实体,因为它们必须伴随着额外的背景信息。

第三步——用真实世界的实体替换代词

正如我们所看到的,[his,he,him]和[it]已经被替换为现实世界的实体,分别来自相应的组——“Sam”和“a white star”。结果,我们获得了一个没有任何代词的文本,同时在语法和语义上仍然有效。

摘要

共指消解的目的是找到、分组任何不明确的表达式,然后用它们所指的真实世界的实体替换它们。

我们已经讨论了共指和回指解析之间的区别,并展示和解释了一些与它们相关的常见问题。我们还设法通过一个例子介绍了 CR 的典型过程。

通过这样做,句子变得独立,计算机不需要额外的上下文来理解它们的意思。我们并不总是拥有定义良好的实体,但通常情况下,共指消解会带来信息增益。

这只是关于共指消解和自然语言处理系列的第一篇文章。在下一篇文章中,我们将展示我们已经测试过并最终决定在我们的系统中实现的最大深度学习解决方案的利弊。

更多类似的文章请看一下 神经系统博客

第 2 部分- 最流行的共指消解框架

参考

[1]: Rhea Sukthanker,Soujanya 茯苓,Erik Cambria,ram Kumar Thirunavukarasu(2020 年 7 月)回指和共指消解:综述

[2]: 沙丽德·洛艾西加,莲恩·吉尤,克里斯蒂安·哈德迈尔(2017 年 9 月)是什么?消除代词“it”的不同读法的歧义

[3]: 克里斯托弗·曼宁的斯坦福讲座(cs 224n)(2019)

数据结构介绍

原文:https://towardsdatascience.com/intro-to-data-structures-2615eadc343d?source=collection_archive---------5-----------------------

实践教程

优化您的代码,并拆除 FAANG 采访

乔尔·菲利普Unsplash 上拍摄的照片

想象一下,你开发了一个非常受欢迎的应用程序,它的用户数量正在迅速增长到一百万。(恭喜!)虽然用户喜欢这款应用,但他们抱怨这款应用变得越来越慢,以至于一些用户开始离开。您会注意到,主要的瓶颈是如何在身份验证期间检索用户信息:目前,您的应用程序搜索一个未排序的 Python 字典列表,直到找到请求的用户 ID。

诅咒你凌晨 3 点写的代码,你想知道如何解决这个问题。我们如何以一种让我们尽可能快地检索任何 ID 的方式存储用户 ID?对列表进行排序可能会有所帮助,但如果我们每次都从头开始搜索,拥有高编号 id 的新客户将需要数十万个步骤来进行身份验证。我们可以从列表的后面开始搜索,但是从一开始就和我们在一起的客户会受到惩罚。

你会意识到,一个更好的方法是将用户数据安排在一个https://en.wikipedia.org/wiki/Binary_search_tree二叉查找树中,这将允许我们平均在一个少得可怜的二十步中找到我们一百万个 id 中的任何一个。实际上,这种数据结构的一个版本是数据库索引记录的一种方式,以便进行闪电般的检索。悄悄地将用户信息迁移到数据库,你的应用程序的延迟下降,每个人都很高兴,你发誓永远不会告诉任何人你最初是如何存储数据的。

作者图片

这个例子强调了重要的一点:我们的程序使用的数据结构可以决定我们的代码是否会随着数据量的增长而伸缩,或者我们是否需要每六个月重写一次。从快速找到位置之间的最短路径,到始终为不断变化的列表中的最高优先级项目提供服务,到即时安全地确认输入的密码是否正确,选择正确的数据结构对于可伸缩代码至关重要。

在本帖中,我们将介绍一些常见的数据结构,讨论它们的优缺点以及何时使用它们。(例如,二叉查找树对于索引数据库非常有用,但是对于生成密码散列却很糟糕。)我们将用 Python 实现这些结构,然后用 Leetcode 问题演示一些用例。

即使您的日常工作从未涉及到低到担心内存管理的语言,您也将了解 R 和 Python 如何在幕后存储您的数据。更直白地说,这篇文章会给你 FAANG tech 面试的编码部分的基础知识,如果你感兴趣的话!

目录

  • 入门指南
  • 数组
  • 链接列表
  • 图表
  • 哈希表

入门指南

在我们开始使用任何数据结构之前,我们需要理解数据结构到底是什么,以及如何比较它们。我们将从区分工具(数据结构)和它们更广泛的用途(抽象数据类型)开始,然后讨论大 O 符号,这是一种比较数据结构操作速度的度量。然后,我们将快速浏览数据结构存储的基本数据类型。

最后,我们会定期重申没有“完美”的数据结构数据结构的效用完全取决于它的使用方式。因此,理解你的程序的需求以确定合适的工作工具是很重要的。

数据结构与抽象数据类型

无论是在编程中,还是在现实生活中!—完成一项任务通常有多种方式。比方说,你想在你的后院挖一个洞。你可以随意使用干草叉、锤子、锯子和铲子。每一个都可以被认为是一个“数据结构”,因为它们是完成你的任务的特定手段。

但是如果你把任务从你如何完成任务的*中分离出来,你可以看到这些特定的工具正在扮演“挖掘工具”的角色这个“挖掘工具”就是你的抽象数据类型:一种挖掘的手段。你实际上如何挖掘是数据结构。抽象数据类型是一个理论实体,而数据结构是该实体的一个实现*

这是另一个例子。假设你想去城市另一头拜访你的朋友。你可以自由支配你的自行车、汽车和双脚。这里的 vehicle 是抽象数据类型:一种交通工具。你实际上如何旅行是数据结构——你的自行车、汽车或脚。

作者图片

这个区别很重要,因为完成一项任务有多种方式,每种方式都有利弊,这取决于你的具体项目。在挖洞的情况下,铲子无疑是赢家。但是对于穿越城镇,“正确的”数据结构取决于外部环境:汽车行驶最快,但需要道路,而我们的脚步很慢,但可以穿过高高的草地和楼梯。

数据结构是我们开发人员所关心的,因为它是我们用来完成任务的特定工具。但是我们的用户只关心抽象数据类型。你的朋友不在乎你怎么去他们家,只在乎你准时到达。

再举一个例子来说明这一点。想象你需要收拾一些干净的衣物。写时间低而读时间高的数据结构将会是地上的一堆衣服。添加到这个堆中非常快,但检索任何特定的项目都很慢,因为您必须在未排序的堆中搜索。**

另一种方法是把你的衣服整齐地放在你的衣柜里。这种方法会有一个高的写时间但是低的读时间,因为它会花费更长的时间来放好你的衣服,但是你将能够更快地访问你搜索的任何物品。

作者图片

虽然这个例子听起来可能很傻,但它实际上与将数据转储到 AWS S3 而不是数据库的策略相差不远,或者在某种程度上将其存储在高度结构化的 SQL 而不是灵活的 NoSQL 数据库中。梳妆台和壁橱并不一定是最好的方法——电子商务商店的交易日志可能写得比读得多,因此将原始输出保存到 S3 的“一堆衣服”方法实际上可以很好地工作。

大 O 符号

虽然用铲子挖洞比用锤子容易是有道理的,但我们如何量化性能上的差异呢?挖掘所需的秒数是一个很好的度量,但是为了处理不同大小的洞,我们可能想要更接近每立方英尺

然而,这仅仅让我们了解了一部分——我们如何解释不同大小的铲子,或者进行挖掘的人?一个用锤子的健美运动员比一个蹒跚学步的小孩用铲子挖一个洞要快,但这并不意味着锤子是更好的挖掘工具。

作者图片

用计算机术语来说,这两个考虑因素可以重新定义为 正在处理的数据量 ,以及正在使用的

为此,我们可以求助于 大 o 符号 ,记为 O(⋅).大 O 是衡量“最坏情况”效率的指标,是完成一项任务需要多长时间(或者需要多少内存,我们在这里不讨论)的上限。例如,在未排序的列表中搜索一个元素是 O(n ),因为在最坏的情况下,您必须搜索整个列表。

这是另一个时间复杂度为 O(n)的运算的例子。打印 Python 列表中的每个元素需要更多的时间,这取决于列表中有多少元素。具体来说,花费的时间线性增长:如果元素数量加倍,显示所有元素的时间也会加倍。

如果我们打印数组中的每一对元素,同时,我们的复杂度变成 O(n)。4 个元素的数组需要 16 步,10 个元素的数组需要 100 步,依此类推。

O(n)算法并不好。理想情况下,我们想要一个在常数时间内工作的算法,或者 O(1),其中运行时间与数据量无关。例如,不管数组的大小如何,打印一个数组的随机值总是要花相同的时间。

我们可以在 Jupyter 笔记本中用%%timeit命令量化这些函数的效率。下面,我们已经看到 O(n ) print_pairs的执行时间显著增加。我们还看到了 O(1) print_idx的强大功能,它的执行时间在 0.153 ms 左右,不管数组的大小,也不管我们请求的是第一个还是最后一个元素。

作者图片

我们可以使用如下图来比较各种效率的算法是如何扩展的。绿色区域是最理想的——它们是可伸缩性最好的运行时,增长速度远远低于数据量。灰色很好,如果可以的话,避免橙色,尽可能避免红色区域。

作者图片

哪些问题可能需要红区中的算法?对于那些你需要知道问题的每一个可能答案的问题,红区算法通常是必要的。o(2ⁿ算法的一个例子是寻找一个数组的所有 子集 。集合中的每个元素可以 1)包含在子集中,也可以 2)排除在子集中。因此,像[A,B,C,D]这样的四个元素的集合将具有 2⁴,或者 16 个子集:

  • [][A][B][C][D]
  • [A,B][A,C][A,D][B,C][B,D][C,D]
  • [A,B,C][A,B,D][A,C,D][B,C,D]
  • [A,B,C,D]

但是更糟糕的运行时是 O(n!). 排列 是 n 阶乘复杂性的经典例子。为了找到[A, B, C, D]的每一种可能的排列,我们从第一个位置的四个字母中的一个开始,然后从第二个位置的其余三个中的一个开始,以此类推。因此,将有 4 * 3 * 2 * 1 或 24 种排列:

  • [A,B,C,D][A,B,D,C][A,C,B,D][A,C,D,B][A,D,B,C][A,D,C,B]
  • [B,A,C,D][B,A,D,C][B,C,A,D][B,C,D,A][B,D,C,A][B,D,A,C]
  • [C,A,B,D][C,A,D,B][C,B,A,D][C,B,D,A][C,D,B,A][C,D,A,B]
  • [D,A,B,C][D,A,C,B][D,B,A,C][D,B,C,A][D,C,A,B][D,C,B,A]

这些问题的运行时间以惊人的速度增长。10 个元素的阵列具有 1,024 个子集和 3,628,800 个排列。20 个元素的数组有 1,048,576 个子集和 2,432,902,008,176,640,000 种排列!

如果你的任务是找出一个输入数组的所有子集或排列,这就很难避免 O(2ⁿ)或 O(n!)运行时。但是,如果您不止一次地运行这个操作,并不是所有的希望都落空了——您可以使用一些架构技巧来减轻负担。[1]

数据类型

最后,我们应该简单提一下基本的数据类型。如果数据结构是数据的集合,那么在我们的结构中可以有哪些类型的数据?有一些跨编程语言通用的数据类型:

****整数是整数,像1-5256。在 Python 之外的语言中,可以更具体地定义整数的类型,比如有符号的(+ / -)或无符号的(只有+),以及整数可以容纳的位数。

****浮点数是带小数位的数字,像1.20.14。在 Python 中,这包括用科学符号定义的数字,比如1e5。像 C 或 Java 这样的低级语言有一个相关的 double 类型,指的是小数位数以外的额外精度。

****字符是字母,像abc。它们的集合是一个字符串(从技术上讲是一个字符数组)。数字和符号的字符串表示,如5?,也是字符。

Void 是 null,就像 Python 中的None一样。Voids 明确表示缺少数据,这在初始化将被填充的数组时是一个有用的缺省值,或者是一个执行动作但不返回任何内容的函数(例如发送电子邮件)。**

作者图片

有了抽象数据类型、大 O 符号和基础数据类型之后,让我们开始实际的数据结构吧!我们将首先讨论数组。

罗兰·罗斯林在 Unsplash 上的照片

数组

理论

数组是计算机科学中最基本的数据结构之一,它们内置于语言中,甚至是低级语言如 C 语言或汇编语言。一个数组是一组相同类型的元素,如[5, 8, -1]['a', 'b', 'c'],位于计算机内存的一个连续片上。因为数组元素在物理上彼此相邻,所以我们可以在 O(1)时间内访问任何索引——比如第一个、第三个或最后一个元素。[2]

作者图片

像 C 和 Java 这样的语言要求预先指定数组的大小和数据类型。Python 的list结构能够通过将数据存储为指向内存中元素位置的指针(它们不一定彼此相邻),并在空间耗尽时自动调整数组大小,来规避这些要求。

履行

我们可以用 Python 实现一个非常基本的Array类,它模仿了低级语言中数组的核心功能。主要限制包括:

  1. 一旦我们为一个数组分配了空间,如果不创建一个新数组,我们就无法获得更多空间。
  2. 数组中的所有值必须是同一类型。

我们现在可以和我们的Array班一起玩了。下面,我们创建一个实例,确认第一个索引中没有任何内容,用 char 填充那个槽,然后返回它。我们还确认我们的数组拒绝非字符值。这不是世界上最令人兴奋的代码,但它确实有效!

例子

如果你遇到一个涉及数组的问题,你很可能会想使用 Python 的内置listnumpy数组,而不是我们的Array类。但是本着使用不改变大小的数组的精神,让我们来看看 Leetcode 问题 LC 1089: 重复零。这个问题的目标是复制一个数组中的所有零,就地修改它,以便元素向下游移动并弹出,而不是增加数组大小或创建一个新的数组。

在英语中,我们迭代遍历列表,直到找到一个零。然后我们插入另一个零并弹出最后一个元素来保持数组的大小。

这里一个重要的细节是使用一个while循环,而不是for,因为我们在遍历数组时会修改数组。对索引i更好的控制让我们跳过插入的零,以避免重复计算。

照片由 Edge2Edge 媒体Unsplash 上拍摄

链接列表

理论

链表是计算机科学中另一个关键的数据结构。像数组一样,链表是一组值。但是与数组不同,链表中的值不一定是同一类型,我们也不需要提前指定列表大小。****

链表的核心元素是一个节点,它包含 1)一些数据,以及 2)一个指向内存中某个位置的指针。确切地说,内存中的任何位置。下面是一个值为[1, 'a', 0.3]的链表——注意元素大小是如何不同的(四个字节用于整数和浮点,一个字节用于字符),每个节点有一个四字节的指针,节点之间的距离不同,最后一个节点包含一个空指针指向空间。

作者图片

对数据类型和列表长度没有限制使得链表很有吸引力,但是这种灵活性是有代价的。典型地,只有列表的头被暴露给程序,这意味着我们必须遍历列表来找到任何其他节点。换句话说,对于除了第一个节点之外的任何元素,我们都失去了甜蜜的 O(1)检索。如果你请求第 100 个元素,需要 100 步才能到达:一个 O(n)模式。

我们可以通过添加指向节点的指针并暴露尾部,或者通过使列表循环,来使我们的链表更加通用。但是总的来说,选择链表而不是数组意味着要为灵活性付出代价。

履行

为了在 Python 中创建一个链表,我们从定义节点开始。我们只需要两部分:节点保存的数据和指向列表中下一个节点的指针。我们还添加了一个__repr__方法,以便更容易看到节点包含的内容。

我们现在可以和我们的ListNode类一起玩了。请注意列表的头部是我们的变量head,以及我们如何迭代地追加.next来访问更深的节点,因为我们不能键入像[1][2]这样的索引来访问它们。

我们可以编写一些函数来使添加一个节点到末尾和开头变得更容易。我们会这样做:

add_to_end中,我们创建了一个名为ptr(“指针”)的变量,它从head开始遍历列表,直到到达最后一个节点,它的.next属性是一个空指针。然后,我们简单地将该节点的.next值设置为新的ListNode。我们不需要返回任何东西来使我们的更改生效。

add_to_front更简单:我们创建一个新的头,然后设置它的.next指针指向我们现有链表的头。但是,我们需要用这个新节点手动更新函数外部的head,因为否则head仍然指向旧的头。

例子

链表的一个常见问题是返回中间节点。因为我们通常只有列表的头部,所以我们没有办法提前知道列表有多长。乍一看,我们似乎需要遍历列表两次:一次是为了找出列表有多长,另一次是为了中途遍历。

但是实际上有一个聪明的方法可以一次找到中间。之前,我们使用指针一次遍历列表中的一个节点,直到到达末尾。但是如果我们有两个指针,一个一次移动一个节点,另外两个一次移动两个节点,会怎么样呢?当快速指针到达列表的末尾时,我们的慢速指针会在中间。

下面是我们如何回答 LC 876: 链表中间

每当我做 Leetcode 问题时,我喜欢画出例子,并确保我在做我认为我在做的事情。例如,很难记住我们应该将fast初始化为head还是head.next。如果你画出一个简单的清单,你知道中间应该是什么,你可以很快确认head.next是正确的选择。

作者图片

LC 141: 链表循环是另一个使用快慢指针的例子。这里的想法是确定列表是否有循环,当一个节点的next指针指向列表中更早的节点时,就会发生循环。

遍历这个列表将永远继续,因为我们永远不会退出循环。第一种猜测可能是设置一些阈值,比如遍历运行了多长时间,或者在一段时间内我们看到了多少重复的模式,但是更简单的方法是再次使用两个指针。

我们不能再使用while fast and fast.next了,因为只有当我们到达列表的末尾时,它才计算为False。相反,我们将再次实例化第一个和第二个节点的slowfast,然后以不同的速度在列表中移动它们,直到它们匹配。如果我们到达列表的末尾,我们返回False;如果两个指针指向同一个节点,我们返回True

安妮·斯普拉特在 Unsplash 上的照片

理论

树扩展了链表的概念,允许节点有多个“下一个”节点。树节点可以有一个、两个或多个子节点,允许以灵活的分支模式表示数据。通过设置组织数据的规则,我们可以非常高效地存储和检索数据。

一种类型的树是二叉查找树树;在本文的开始,我们简要地提到了 BST 检索数据的效率。这种效率源于管理 BST 结构的两条重要规则:

  1. 一个节点最多可以有两个子节点。
  2. 左子树中的每个节点必须包含一个较小的值,而右子树中的每个节点必须包含一个较大的值。**

作者图片

在 BST 中搜索一个值最多需要 O(log n)时间[3],这意味着我们可以在数百万甚至数十亿条记录中非常快速地找到一个请求的值。假设我们正在搜索值为x的节点。我们可以使用下面的算法在 BST 中快速找到这个节点。

  1. 从树根开始。
  2. 如果 x =节点值:停止。
  3. 如果 x < the node value: go to the left child.
  4. If x >节点值:转到正确的子节点。
  5. 转到步骤 2。

如果我们不确定请求的节点是否存在于树中,如果我们试图访问一个不存在的子节点,我们只需修改步骤 3 和 4 来停止搜索。

履行

创建一个TreeNode几乎等同于创建一个ListNode。唯一的区别是,我们有了leftright属性,而不是一个next属性,它们指的是节点的左右子节点。(如果我们定义一个有两个以上孩子的树,我们可以将这些属性命名为child1child2child3等等。)

然后我们可以创建一个三层的树。注意,这个树只是一个二叉树,而不是 BST,因为值是不排序的。

例子

涉及二叉树的问题通常集中在遍历节点的不同方式上。遍历通常从根节点开始,然后按照一组步骤处理每个节点及其子节点。但是处理节点的顺序完全取决于我们处理父节点相对于子节点的顺序:之前(前序),在左右之间(依序),或者之后(后序)。下面的每个遍历都从根节点开始,但是节点被处理的顺序完全不同。

作者图片

这三种类型的遍历可以通过迭代(使用while循环和 堆栈 )或 递归 (使用调用自身的函数)来实现。还有第四种类型的遍历,级别排序,它利用了一个 队列 。在这篇文章中,我们不会讨论栈和队列,只是把它们想象成列表,你只能从末尾(栈)或开始(队列)删除它们。

作者图片

前三种遍历的模式几乎相同,所以我们只选择按顺序遍历。下面我们为 LC 94: 二叉树顺序遍历编写迭代和递归方法,从迭代版本开始。

在英语中,我们执行以下步骤:

  1. ****第 6–7 行:为我们的答案实例化一个列表(answer)和一个堆栈(stack),该堆栈包含我们的根节点的元组和表示我们还没有访问过这个节点的False
  2. ****第 9 行:开始一个while循环,只要stack中有元素存在,就执行。
  3. ****第 10–12 行:.pop移除堆栈的最后一个元素,然后检查node是否存在。(node对于没有子节点的节点,不会一直存在于以后的迭代中)。
  4. ****第 14–15 行:如果node存在,并且我们以前访问过这个节点,则将我们的节点值附加到答案中。
  5. 第 16–19 行:**如果我们还没有访问过这个节点,添加它的右边的子节点(用一个标志表示我们还没有看到它),当前节点(用一个标志表示我们已经看到了它),然后添加左边的子节点,用一个“还没有看到”标志。
  6. ****第 9–19 行:重复步骤 3–6,直到我们处理完所有节点。
  7. ****第 21 行:返回一个按顺序排序的节点值列表。

我们将节点添加到堆栈的方式(第 17–19 行)可能看起来有些混乱——左边的节点不是应该先出现吗?但是因为堆栈是后进先出,所以我们想要处理的第一个节点需要是我们添加到堆栈中的最后一个节点。因此我们先加右,再加左。

现在是递归方法:

在英语中,我们执行以下步骤:

  1. ****第 2–4 行:创建一个用我们的答案列表初始化的类(self.answer)。
  2. ****第 6–11 行:定义一个函数traverse_inorder,取一棵树的根节点,调用递归函数_traverse,然后返回self.answer
  3. ****第 13–22 行:定义了一个接受节点的递归函数_traverse。该函数在对节点的左侧子节点调用自身之前检查node是否存在,将节点的值附加到self.answer,然后对节点的右侧子节点调用自身。

我们如何从有序转变为前序或后序?对于这两种方法,我们简单地重新安排了node相对于其子节点的处理顺序。代码的其余部分保持不变。

照片由纳斯蒂亚·杜尔希尔Unsplash 拍摄

图表

理论

树通过允许每个节点有多个子节点来扩展链表的范围。有了图,我们通过放松树的严格父子关系来再次扩展范围。图中的节点没有明确的层次结构,任何节点都可以连接到任何其他节点。

作者图片

图通常被表示为邻接矩阵。例如上图,会有如下矩阵。

每行和每列代表一个节点。第 i 行和第 j 列的 1,或 A_{ij}=1 ,代表节点 i 和节点 j 之间的连接。A_{ij}=0 意味着节点 ij 没有连接。

该图中的节点都不与自身相连,这意味着矩阵对角线为 0。同样, A_{ij} = A_{ji} 因为连接是无向的:如果 A 连到 B,那么 B 连到 A,结果邻接矩阵是沿对角线对称的。

我发现矩阵中的一堆 1 和 0 有点难以理解,所以这是同样的图表和带颜色的矩阵。

作者图片

带有定向边的加权图看起来像这样。注意这些关系不再是对称的——例如,邻接矩阵的第二行现在是空的,因为 B 没有出站连接。我们也有介于 0 和 1 之间的数字,它们反映了连接的强度。例如,C 对 A 的反馈比 A 对 C 的反馈更强烈。

作者图片

履行

为了简单起见,让我们实现一个未加权且无向的图。我们类中的主要结构是一个列表列表:每个列表都是一行,列表中的索引代表列。实例化一个Graph对象需要指定节点的数量n,以创建我们的列表列表。然后我们可以通过self.graph[a][b]访问节点ab之间的连接。

我们可以像这样重新创建本节第一个示例中的图形:

例子

一个更棘手的图形问题是识别图形中连通分量或子簇的数量。例如,在下图中,我们可以识别三个不同的组件。

作者图片

为了回答 LC 323: 连通分量的数量,我们将检查图中的每个节点,访问它的邻居,它的邻居的邻居,等等,直到我们只遇到我们已经见过的节点。然后,我们将检查图中是否有我们没有访问过的节点——如果有,这意味着至少还有一个集群,因此我们获取一个新节点并重复这个过程。

在英语中:

  1. ****第 5–8 行:实例化一个队列(q)、节点列表(unseen)和组件数量(answer)。
  2. ****第 10 行:开始一个while循环,只要队列中有要处理的节点或者我们还没有访问的节点,这个循环就会执行。
  3. ****第 13–15 行:如果队列为空,从unseen中移除第一个节点,并增加组件数量。
  4. ****第 18–19 行:选择队列中的下一个可用节点(focal)。
  5. ****第 22 行:开始一个while循环,只要我们没有处理完所有剩余的节点,这个循环就会执行。
  6. ****第 23 行:命名我们当前所在的节点,使接下来的几行更加易读。
  7. ****第 28–30 行:如果我们所在的节点连接到focal,则将它添加到当前集群中的节点队列中,并将其从可能位于另一个集群中的节点列表中删除(unseen)。
  8. 第 31–32 行:**如果我们所在的节点没有连接到focal,继续到下一个潜在节点。

照片由拍摄于 Unsplash 上外 16 英里处

哈希表

理论

让我们用一个更基本的数据结构来结束这篇文章:散列表,也叫做散列表。 [4]当我们离开数组时,我们留下了令人羡慕的 O(1)检索时间,以获得数据类型和数组大小的灵活性。但是,如果我们能够再次获得那种闪电般的效率,即使数据的类型和存储位置不同,又会怎样呢?

这就是哈希表的用武之地。这些表中的数据与键-值对相关联——输入键,一个 散列函数 在 O(1)时间内将您带到相关联的值。哈希表实际上使用指针数组来达到这个速度;哈希函数的工作是识别数组中的索引,该索引包含指向键值的指针。

下面是我们之前的链表作为散列表的样子。绿色的盒子是我们的桌子,里面存放着钥匙key1key2key3。当用户将这些键中的一个传入表中时,该键通过散列函数发送,以在指针数组中找到一个索引(紫色)。然后指针把我们带到内存中存储实际值的区域。数组中的每个指针都是四个字节,而它们所指向的值的大小是可变的。

作者图片

该表的主要工作是散列函数,它在某个范围内将输入映射到输出以 Python 的hash函数为例,输出-9223372036854775808 和 9223372036854775807 之间的值。然后我们存储散列值——通常通过除以数组长度并取余数——返回指针数组中的一个索引。在上面的例子中,输出将是 0、1 或 2:指针数组的索引。

因为我们的数组不会有无限的索引,所以两个不同的输入可能会收到相同的散列输出。这种冲突意味着两个输入,比如用户 id10057789609217,都将落在返回Jane Reader的指针上,即使它们是不同的用户。我们不想那样!

第一个修正是确保我们的散列函数均匀地分布输出。每个数组索引被选中的概率应该是相等的——如果某些索引比其他索引更有可能被选中,我们就会比我们需要的更频繁地遇到冲突。

一个更复杂的解决方案是引入另一种数据结构:链表。不是让每个指针指向内存中的一个确切值,每个指针可以指向一个链表。如果我们试图保存一个新的键值对,其中散列的键与现有的键冲突,我们只需在内存中的那个位置向列表添加另一个节点。为遍历列表和知道何时停止添加一点逻辑,您就可以开始了!**

但是冲突本身也不是坏事——有时我们希望不同的输入得到相同的输出。如果你的酷酷的应用程序有四台服务器处理流量,你可以使用一个基本的哈希函数来平衡服务器之间的负载

履行

散列表听起来可能类似于 Python 字典,事实上 Python dict 就是散列表!但是如果我们必须从头创建一个,我们可以像下面这样做。

为了处理散列冲突,我们为self.array使用一个列表列表,然后在检索或添加值时遍历该列表。我们将键和值都存储在我们的列表中,以便能够识别我们正在寻找的键-值对,假设多个键将具有相同的数组索引。

下面,我们实现一个非常基本的登录系统。我们在用户密码存储在self.array[slot]之前对其进行哈希处理,这意味着即使密码被盗,破解密码所需的时间也可能给用户足够的时间来修改密码。(这个由电脑爱好者制作的精彩视频对此进行了深入探讨,它应该激励你永远不要使用像password这样的密码!)**

例子

为了结束这篇文章,让我们来回答经典的 Leetcode 问题 LC 1: 两个 Sum 。就像我们处理数组一样,我们将只使用 Python 内置的类(dict)。问题如下:给定一个整数数组和一个目标,返回对目标求和的两个数组元素的索引。假设只有一个答案。例如,对于数组[1, 2, 3]和目标4,我们将返回[0, 2],因为 1 + 3 = 4。**

这个问题有多种解决方法,幽默地概括在这个对技术面试的模仿中。第一种是蛮力比较每一对数字(例如1+21+32+3),这种方法肯定有效,但需要 O(n)时间。更好的方法是对数组进行排序,然后使用两个指针,一个在开始,一个在结束,如果它们的总和小于或大于目标,则分别迭代地移动左指针或右指针。由于排序的原因,这种方法需要 O(nlogn)时间。

但是我们实际上可以实现 O(n)时间,通过使用一个散列映射,访问每个元素最多一次。这里的关键概念是,对于每个数字num,我们需要查看是否有其他数字等于target-num。我们可以使用 Python 字典(即 hash map)来存储我们已经看到的数字,然后使用 sweet O(1)查找时间来查看我们是否已经看到匹配target-num的数字。如果匹配,我们返回两个数的索引。**

这是我们用目标4寻找数组[1, 2, 3]的方式。这里我们写出了for循环的每次迭代的逻辑。

照片由穆罕默德·里什法恩Unsplash 拍摄

结论

这篇文章承担了介绍数据结构的卑微任务,数据结构是编程语言存储数据的方式。我们从区分任务(抽象数据类型)和实现(数据结构)开始,使用大 O 符号来量化数据结构上的操作效率,最后是我们在结构中存储的数据类型。然后我们讲述了数组、链表、树、图和散列映射的理论,并用 Python 实现了每一个,并回答了一两个 Leetcode 问题。

尽管这篇文章非常庞大,但是关于数据结构还有很多东西需要学习。例如,树可以被重塑以解决几十个用例,如代表二维空间的,自动完成输入的字符串快速运行区间数据的计算等等。如果您感兴趣,请查看本页中的一些高级结构及其常见用例。

最后,再次区分数据结构抽象数据类型很重要。在这篇文章中,我们没有涉及堆栈、队列或堆,因为每种方法都有多种实现方式。例如,根据您的需要,可以用数组或链表来实现堆栈。请关注即将发布的关于这些更常见的抽象数据类型的文章。**

暂时就这样了。下次见!

最好,
马特

脚注

1.大 O 符号

对于第一个T21 用户请求特定阵列的所有排列,我们可能无能为力。但是我们可以将数组及其答案存储在哈希表中。对于随后的每个用户,我们可以检查我们的表,看看该数组是否已经被查询过。(我们希望对数组进行排序,删除空值,等等。否则会使相同的数组看起来不同。)如果用户请求一个排列已经被计算过的数组,我们可以以闪电般快的 O(1)运行时间来响应。如果没有…回到 O(n!).****

这个概念被称为缓存或记忆。这是 Python 中的样子。

另一种方法是动态编程,它涉及递归地将一个问题分解成尽可能小的部分,然后缓存这些部分的结果。例如,如果我们的问题稍微修改一下,返回排列的数量,而不是实际的排列,那么缓存像 5 这样的值会很有帮助!还是 10!以避免每次都必须计算它们。

2.理论

数组索引需要 O(1)时间,因为总是只需要三个步骤:

  1. 转到内存中数组开始的位置
  2. 确定数组中的数据类型(例如浮点型)
  3. array start + index * (size of data type)返回内存中的值

数据类型很重要,因为不同的数据类型需要不同的内存。char 是一个字节,例如,而 int 是四个字节。获取索引 3 处的元素意味着从字符串的开始处遍历三个字节,而从整数数组的开始处遍历十二个字节。

步骤 3 暗示了为什么这么多编程语言都是 0 索引的:数组的第一个元素距离开始处有 0 个元素。如果index * (size of data type)是零,那么返回这个值就很容易,我们可以在array start返回这个值。

3.理论

注意,O(logn)是 log₂,而不是 log₁₀或自然对数。这种模式在二叉树中很容易看到,因为我们在搜索中的每一步,我们都将剩余的节点减少一半。

4.理论

这个栈溢出帖子很好地解释了哈希映射和哈希表之间的区别。从技术上讲,哈希映射是一种抽象数据类型,但是这两个术语在很大程度上是可以互换的。

高斯过程回归

原文:https://towardsdatascience.com/intro-to-gaussian-process-regression-14f7c647d74d?source=collection_archive---------22-----------------------

概念指南

高斯过程(GPs)是一类灵活的非参数机器学习模型,通常用于空间和时间序列数据建模。GPs 的一个常见应用是回归。例如,给定不完整的地理天气数据,如温度或湿度,如何恢复未观测位置的值?如果有充分的理由相信数据是正态分布的,那么使用 GP 模型可能是明智的选择。在接下来的内容中,我们将介绍 GP 模型背后的机制,然后举例说明它在恢复丢失数据方面的用途。

GP 模型

形式上,GP 是一个随机过程,或者是函数的分布。前提是函数值本身是随机变量。当将函数建模为高斯过程时,假设任何有限数量的采样点形成多元正态分布。

为什么这个假设有用?事实证明,高斯分布很容易处理,因为它们易于处理。事实上,高斯家族是自共轭的,并且享有许多性质,例如在边缘化下是封闭的,在条件限制下是封闭的。因此,全球定位系统自然与贝叶斯机器学习相吻合,贝叶斯机器学习通常涉及先验的规范——在超参数上坚持自己的先验信念——并在参数上边缘化以获得后验预测分布。

回想一下多元正态分布的特征是一个均值向量和协方差矩阵。这些是 GP 建模的核心概念。

GP 推理/预测方程

在根据观察到的训练点对试验点进行预测时,假设如下的 ansatz。

这反映了前面的正态假设,除了这里我们区分训练点和测试点,后者用星号表示。我们还假设训练标签被高斯随机噪声破坏,因此修改了上面的核矩阵中左上的块。使用正态分布的特性,可以计算测试数据的条件分布:

(完整的推导见 GPML 书。)这些等式允许人们根据训练数据在测试点获得预测平均值和协方差。

GP 核函数

为了使用上面的等式,必须能够模拟训练和测试数据的所有组合之间的协方差和交叉协方差。粗略地说,协方差矩阵编码了训练值和测试值如何相互关联。为了能够明确地形成核矩阵,必须假设一个特定的核函数来模拟协方差。据说核是 GP 模型的核心,因为选择正确的核函数对于实现良好的模型拟合至关重要。

最常用的核函数是径向基函数(RBF ),它是通过取数据位置之间的比例平方欧几里得距离的指数而产生的。

例如,通过将核函数应用于每对数据位置(回想一下,每个数据点都与一个位置-值对相关联),可以在观察到的数据之间形成核矩阵。

注意,核函数(以及矩阵)包含未确定的超参数,以允许对一大类函数进行建模。在实践中,通过使用 MLE 和优化似然函数,或给定观察数据的超参数的概率,调整这些参数以拟合训练数据。更具体地,在给定训练标签的情况下,最小化超参数的负对数似然(NLL ):

一旦优化了超参数,就可以将核矩阵插入到测试数据的均值和协方差的预测方程中,以获得具体的结果。

GP 回归

GP 回归的前提是我们正在建模一个在有限数量的点上可访问的函数,然而我们对它在未被观察到的位置上的值感兴趣。降雨量是在地理上相隔很远的气象站测量的,海水盐度是沿着一定的轨迹测量的,森林中某种树木的密度也是在固定的地点采样的。GP 建模的核心是找到一个合适的核函数来对分布在空间中的这些数据点之间的相似性进行建模。一旦使用训练集优化了核函数参数,就可以使用预测方程对测试集进行预测。

为了说明这个过程,我们生成一个合成的高斯随机场,执行训练测试分割,并使用 GP 模型在未观察到的位置进行预测。

合成生成的马尔可夫随机场。图片作者。

随机二次抽样训练点。图片作者。

测试位置或未观察位置的 GP 预测平均值。该预测类似于原始高斯随机场的平滑版本。图片作者。

基本事实(左)、训练集(中)和预测(右)的比较。图片作者。

GP 软件包

GP 回归有很多软件包!可用流行语言实现,如 PythonPyTorchMatlabJulia

结论

GP 模型是一种非参数模型,它足够灵活,可以适应多种数据,包括地理空间和时间序列数据。GP 回归的核心是指定合适的核函数,或位置已知的数据点之间的相似性度量,这构成了模型选择(MO)步骤。高斯分布的易处理性意味着可以找到以训练数据为条件的后验预测分布的封闭形式的表达式。虽然已经很好地建立,GPs 是一个正在进行研究的领域:最近的发展跨越了多输出 GPs 、GP 回归的变分推断和可伸缩 GPs。

进一步阅读

自然语言处理导论——如何对单词的含义进行编码

原文:https://towardsdatascience.com/intro-to-natural-language-processing-how-to-encode-meaning-of-a-word-b1742d4beca2?source=collection_archive---------11-----------------------

实践教程

理解 Word2Vec 的数学和实现

作者图片

男人之于国王如同女人之于什么?

你如何训练一个机器学习算法来正确预测正确答案,“女王”?

在这篇文章中,我将谈论一种自然语言处理模型——word 2 vec——它可以用来进行这样的预测。

在 Word2Vec 模型中,词汇表中的每个单词都由一个向量表示。这个向量的长度是我们人类设定的一个超参数。在本文中我们用 100。

因为每个单词都是 100 个数字的向量,所以你可以把每个单词想象成 100 维空间中的一个点。

Word2Vec 的最终目标是相似的单词具有相似的向量,从而在这个 100 维空间中更紧密地组合在一起。

那么,你如何训练一个算法,使得相似的单词最终有相似的向量呢?这如何帮助解决类比问题“男人对国王就像女人对什么?”

第一部分。带梯度下降的训练字 2Vec

为了训练 Word2Vec,你需要一个大的文本语料库。比如棕色文集。NLTK 已经编译了一个可供访问的语料库的列表。

Word2Vec 的核心是预测一个单词出现在另一个单词附近的概率(在一个句子中)。

作者图片

上例:“…珍惜淡蓝色的小点,我们所知的唯一家园”,“蓝”是中心字,“淡”是或上下文字外的一个。我们希望算法预测“苍白”是“蓝色”的上下文单词的概率注意:在这篇文章中,我将在单词和上下文单词之外互换使用

我们计算在定义的窗口大小内的每个上下文单词的概率。如果窗口大小为 1,我们希望预测紧接在中心单词之前和之后的单词的概率。如果窗口大小是 2,我们想要预测紧接在中心单词之前和之后的 2 个单词的概率。

因此,对于算法,我们遍历语料库中的每个单词。在每个位置 t 处,给定位置 t 处的中心单词,我们计算窗口 w 内上下文单词的概率。

作者图片

好的模型将给出这些上下文单词的高概率,而坏的模型给出低概率。

实际值和预测值之间的差异被计入损失,在梯度下降中用于更新模型的参数(θ)。这就是许多监督学习算法的中心主题。

梯度下降

在 Word2Vec 中,theta 到底是什么?损失函数是什么?

Word2Vec 的参数和损失函数

回想一下,每个单词都由 100 个数字组成的向量表示。还记得每个单词都可以作为中心词或上下文词。因此,语料库中的每个唯一单词由两个向量表示:一个向量作为中心单词,另一个向量作为上下文单词。

参数θ

Word2Vec 的参数 theta 是语料库中所有唯一单词的中心和外部向量。theta 的维数是词汇行和 100 列长度的 2 倍。

在图片中,我用小写的 v 表示一个单词的中心词向量,小写的 u 表示一个单词的上下文词向量。因此,当斑马是中心单词时, v_zebra 是斑马的向量。当 zebra 是某个其他中心词的上下文词时,u_zebra 是 zebra 的向量。稍后,我将使用大写字母 U 来引用一个包含所有外部向量 u 的矩阵。

我们将使用的损失函数是负对数似然(NLL)损失。NLL 用于许多机器学习算法,如逻辑回归。

NLL 的计算公式为:

负对数似然损失函数

我们对唯一单词 T、的长度求和,并且在每个索引 t 处,我们对给定索引 t 处的中心单词的每个上下文单词(在窗口 w 内)的概率求和。

因此,给定一个中心单词,丢失一个上下文单词是:

你如何计算概率?我们使用 Softmax 方程。下面是在给定一个中心词(c)的情况下,如何计算上下文词(o)的概率。

命名符是上下文词 o 的上下文向量与中心词 c 的中心向量的点积的指数。分母是每个词汇单词的上下文向量与中心单词向量的点积的指数之和。哇,那是一口!

正如您可能已经猜到的那样,这个 naive-softmax 概率的计算成本很高,因为我们必须对整个词汇表求和。还有另一种更有效的方法来做亏损;稍后我会描述它。

在梯度下降法中,你对损失函数求关于参数的导数,以找到如何在每次迭代中更新参数。

对于给定的中心词,我们需要计算中心词向量的梯度以及所有上下文词向量的梯度。

计算梯度的损失函数导数

我不会在这里求导,但是为了计算中心向量的梯度,你要取 U 和(y_hat 减 y)的点积。正如我提到的,U 是整个词汇的所有外部向量的矩阵。为了计算外部向量的梯度,你取中心向量和(y_hat 减 y)的点积。这种情况下的 y_hat 是 U 和中心向量的点积的 Softmax。

总的来说,算法是这样工作的:

对于每次迭代:

  1. 计算小批量(如 50 号)的损耗和梯度。
  2. 像这样更新模型参数:

theta = theta — learning_rate * gradients

为了计算尺寸为 50 的小批量的梯度,您迭代 50 次,并且在每次迭代期间,您:

  1. 获取一个随机的中心词及其上下文词。
  2. 对于每个上下文单词,计算梯度(通过对损失函数求导)。
  3. 聚合上下文单词的所有梯度。

然后,小批量的聚集梯度被用于更新θ。

这里有一个 Github 的要点和一些相关的代码。注意:我已经排除了一些部分,如解析语料库和 Softmax 方程的代码。

我刚才描述的算法叫做跳格算法。在 Skip-Gram 中,给定一个中心词,预测上下文词的概率。还有另一种算法叫做 CBOW,根据上下文预测中心词的概率。

正如我提到的,我们使用的损失函数计算起来很昂贵。还有另一种训练 Word2Vec 的技术叫做“负采样”在负采样中,不是交叉熵损失(即 Softmax 函数的负对数似然),而是为一个真实对和几个噪声对训练二元逻辑回归。真正的对是一个中心词和它的上下文词之一。噪声对是相同的中心词和随机词。在负抽样中,损失函数更有效,因为你不是对整个词汇求和。

负采样的损失 fxn

第二部分。Word2Vec 如何解决类比问题

男人之于国王就像女人之于什么?

当你让 Word2Vec 算法来解决这个类比时,你实际上是在让它找出一个与“国王”和“女人”最相似,但与“男人”最不相似的词。这里的相似度是指两个向量的余弦相似度。

https://en.wikipedia.org/wiki/Cosine_similarity

因此,经过训练后,单词“女王”的向量与“国王”和“女人”的向量最相似,但与“男人”的向量不同

此外,因为相似的单词在高维空间中聚集在一起,所以您可以将“queen”的向量想象为“king”的向量减去“man”的向量加上“woman”的向量。

作者图片

这就是我们如何训练计算机解决类比问题!

查找相似词和解决类比只是 Word2Vec 的两个基本应用。Word2Vec 嵌入还可以用于更复杂的任务,比如情感分析。对于情感分析,特征将是句子中所有单词向量的平均值。标签当然是一种情绪(积极、消极、中性)。然后,您可以使用随机森林、Softmax 回归甚至神经网络等分类器进行多类分类!

敬请关注 NLP 的更多文章!

介绍使用 Sklearn 的岭和套索回归正则化

原文:https://towardsdatascience.com/intro-to-regularization-with-ridge-and-lasso-regression-with-sklearn-edcf4c117b7a?source=collection_archive---------8-----------------------

你还不如放弃线性回归

照片由 瑞秋克莱尔 像素

线性回归问题

线性回归又称普通最小二乘法,是最简单、应用最广泛的最大似然算法之一。但它有一个致命的缺陷——算法非常容易过度拟合训练数据。

对于最简单的情况-2D 数据,一切都很直观:最佳拟合线是最小化残差平方和(SSR)的线:

作者图片

公式也没那么难:

但是随着预测变量(或维数)的增加,系数 β_i 也会变得非常大。有了大的系数,就很容易预测几乎所有的事情——你只需要得到各个斜率的相关组合( β s)就可以得到答案。这就是为什么线性回归模型通常会过度拟合训练数据。

LR 的另一个问题是它不关心特征的权重。只要它们之间存在线性关系,你就会得到一个 OLS 最小化的模型。但是在现实中,您确实希望您的模型关心每个特征的权重。例如,如果您试图预测某个城镇的新生儿数量,一个显而易见的因素就是育龄妇女的数量。

然而,在那个特定的城镇里,鹳的数量是完全不相关的。但是,如果这些数字恰好代表一个线性关系,你用这两个数字进行线性回归,你会得到一个蹩脚的模型,但 OLS 仍然被最小化。

在实践中,这是一个真实而普遍的问题:今天的数据集包含许多对你试图预测的目标有用和无用的特征。

你可以在 Kaggle 上的这里运行这篇文章的笔记本。

https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

偏差和方差权衡

要了解岭回归是如何解决上述两个问题的,我们还得了解另外两个重要的话题:偏差方差

方差总是与模型在新的(测试)集上表现不佳有关。高方差会导致过度拟合,这是有意义的,因为过度拟合模型会为不同的数据集生成非常不同的不一致的结果。

相反,偏差是模型无法对训练数据进行归纳。一个有太多偏差的模型不能在训练集和测试集上都通用化。

理想情况下,完美的模型应该具有低偏差和低方差,但这说起来容易做起来难。因为,偏倚和方差在模型复杂度上是一种权衡关系。

作者图片

模型的复杂性是由输入到模型中的维数决定的,即特征的数量。

由于线性回归是无偏的(不关心预测值),它非常适合训练数据。但是拟合过于具体,导致模型具有非常高的方差,将线性回归置于模型复杂性图的最右侧:

作者图片

脊正则化

与偏差和过度拟合相关的两个问题都可以使用脊和套索回归优雅地解决。对于新的两个回归,最佳拟合线的等式仍然是相同的:

改变的是成本函数。岭回归和套索回归都为 OLS 引入了一个新的超参数——𝜆.我们先来看岭的成本函数:

除了 OLS(第一部分),岭回归对特征变量的每个单独的斜率进行平方,并通过一些数字𝜆.对它们进行缩放这被称为岭回归惩罚。这种惩罚本质上是收缩所有系数(斜率)。这种收缩具有双重效果:

  • 我们避免用较低的系数过度拟合。因为λ只是一个常数,所以它对所有系数都有相同的缩放效果。例如,通过为λ选择一个低值,如 0.1,我们可以缩放所有大的和小的系数。
  • 这种缩放还会给完全无偏的 LR 带来一些偏差。这么想吧——如果你对一个大数字求平方,你会得到一个更大的数字。通过选择一个像 0.01 这样的低值,你可以缩小这个数字很多。但是如果你平方小的数,比如小于 1 的数,你得到的不是一个更大的数,而是一个更小的数。乘以 0.01,你就能让它变得更小。通过这种方式,岭回归可以使重要的特征更加明显,而不重要的特征缩小到接近于 0,从而得到一个更加简化的模型。

您可能会说,缩放的平方斜率的总和会更大,这与训练数据以及简单的旧 OLS 不相符。这是真的,但从稍微差一点的拟合开始,从长远来看,山脊和套索提供了更好和更一致的预测。通过引入少量的偏差,我们得到了方差的显著下降。

让我们使用 Scikit-learn 来看看 Ridge 的运行情况。Ridge遵循与sklearn提供的任何其他模型相同的 API。我们将处理来自 Kaggle 的 Ames 住房数据集。使用要素的子集,我们将在本节中使用山脊预测房价,在下一节中使用套索预测房价。简而言之,我正在加载一个已经处理过的数据集(选择、缩放和估算的要素):

作者图片

首先,我们将拟合一个LinearRegression模型,并使用 MAE(平均绝对误差)将其性能与Ridge进行比较。在我们这样做之前,需要做一些预处理,比如缩放变量和填充缺失值。所以,我将创建一个简单的Pipeline实例来处理它们:

如果你想了解更多关于使用sklearnpipelines的信息,请查看 Kaggle 上的这篇文章笔记本

现在,让我们首先拟合一个线性回归方程:

如您所见,测试分数明显低于培训分数,这表明过度适应。现在,让我们试试山脊:

对于 Ridge,我们得到了几乎相同的结果,因为我们为alpha选择了太小的值。如果你回到岭的成本函数,你可以看到,如果我们设置λ为 0,我们得到平原老 OLS 回来:

注意在sklearn API 中,超参数lambda被给定为alpha。不要混淆。

现在,我们可以使用RidgeCV进行交叉验证,而不是盲目地为alpha尝试一堆值。RidgeCV 没有为alpha取一个单一的值,而是取一个可能 alphas 的列表,并使用交叉验证来尝试它们,就像 GridSearch 一样:

在 10 倍交叉验证下,我们通过了 1 到 100 范围内的alpha,步长为 5。拟合完成后,我们可以使用.alpha_属性获得最佳 alpha:

>>> ridge.alpha_86

最后,让我们用超参数评估一个脊,并与线性回归进行比较:

不幸的是,即使有了α的最佳值,我们也得到了与线性回归几乎相同的结果。(在撰写本文时,我意识到这是一个很晚才显示山脊和拉索的糟糕数据集😶).

套索回归正则化

套索回归也很像山脊。在成本函数中只有很小的差别:

Lasso 回归不是取每个系数的平方,而是取它们的绝对值。其余的几乎相同。让我们来看看回归变量在新数据集上的作用。我将加载来自 Seaborn 的内置钻石数据集:

diamonds = sns.load_dataset('diamonds')
diamonds.head()

利用所有的特征,我们将使用 Lasso 来预测价格:

Lasso 和 LassoCV 以同样的方式导入。我们将使用 CV 找到α的最佳值:

看起来选择一个非常低的 alpha 就足够好了。现在,让我们拟合该值并评估性能:

拉索回归做得相当不错。关于套索回归的一个很酷的事情是它可以用于特征选择。由于它在引擎盖下的工作方式,套索回归有能力将不重要的参数一直缩小到零。我们可以通过使用coef_属性绘制上面拟合的lasso系数来检查这一点:

正如你所看到的,除了克拉似乎是钻石价格的决定因素,所有其他系数都缩小到接近 0:

这就是山脊和套索的主要区别。Lasso 可以将系数缩小到 0,而 Ridge 则不能。

结论

总之,山脊和套索是两个最重要的正则化技术。它们都通过引入一些导致较低方差的偏差,从而避免过拟合,来解决简单的老式 LR 的问题。超参数lambda控制不同量级特征的正则化程度。

尽管我们涵盖了很多内容,但我们并没有深入研究支持这两种优雅算法的复杂数学。因此,我留下了一些可能有所帮助的参考资料:

强化学习简介:时间差异学习,SARSA 与 Q-学习

原文:https://towardsdatascience.com/intro-to-reinforcement-learning-temporal-difference-learning-sarsa-vs-q-learning-8b4184bb4978?source=collection_archive---------3-----------------------

钢管舞游戏中 SARSA 和 Q-learning 的温和解释与实现。

强化学习(RL)无疑是一个新兴领域,受到 AlphaZero(迄今为止最好的国际象棋引擎)性能的巨大影响。RL 是机器学习的一个子领域,它教导代理在一个环境中执行,以随着时间的推移最大化回报。

RL 的无模型方法中有时间差异(TD)学习,SARSA 和 Q 学习(QL)是两种最常用的算法。我选择探索萨莎和 QL,以强调政策学习和非政策学习之间的微妙差异,我们将在本文稍后讨论。

这篇文章假设你对 RL 范围内的代理、环境、行动和回报有基本的了解。这里可以找到的简要介绍。

这篇文章概要包括:

  • 时间差异学习
  • 因素
  • QL &萨尔萨公司
  • 比较
  • 履行
  • 结论

我们将通过钢管舞游戏的实现来比较这两种算法。本帖的代码可以在这里找到https://github.com/viethoangtranduong/reinforcement-learning/tree/main/SARSA vs QL****:QL 代码 萨尔萨代码 ,以及 全功能代码 (功能完整的代码已经实现了算法,并在推车杆游戏上进行了训练)

TD 的学习将有点数学化,但请随意浏览并直接跳到 QL 和萨莎。

时间差异学习

环境的一个问题是,回报通常不是立即可见的。例如,在井字游戏或其他游戏中,我们只知道最后一步棋的奖励(终端状态)。所有其他移动将有 0 立即奖励。

TD 学习是一种无监督的技术,用于预测状态序列中变量的期望值。TD 使用一个数学技巧,用一个简单的学习程序来代替对未来的复杂推理,这个简单的学习程序可以产生相同的结果。TD 不是计算未来的总回报,而是尝试预测即时回报和自己在下一时刻的回报预测的组合。(更多信息可在这里找到)

数学上,TD 学习的关键概念是折现回报:

其中时间 t 的奖励是未来贴现奖励的组合。这意味着未来的回报被低估了。 TD 误差是最终正确回报(V*_t)和我们当前预测(V_t)的差值。

并且和其他优化方法类似,当前值会被其值+ learning_rate * error 更新:

好了,今天的数学到此为止。上面的等式是 TD 学习的核心思想,它将帮助我们理解 QL 和 SARSA 码。

因素

Alpha (α):学习率。此参数显示了我们应该根据误差调整估计值的程度。学习率在 0 到 1 之间。大的学习率会积极地调整,并可能导致训练结果波动——而不是收敛。学习率小调整慢,需要更多时间收敛。

γ(γ):贴现率。我们对未来回报的重视程度。贴现率在 0 到 1 之间。贴现率越大,我们越重视未来的回报。

e(在下一节“e-greedy”政策中出现):反映勘探与开发的比率。我们以概率 e 探索新的选项,并以概率1-e停留在当前的最大值,更大的 e 意味着在训练时更多的探索。

QL &萨尔萨公司

QL 和萨莎都存储了当前状态的奖励和相应的动作,以便将来更新。一个状态通常由其组成部分的坐标来表示。如果环境是连续的,我们将有无限多的状态。为了解决这个问题,我们需要通过将它们分割成桶来离散化状态。

我这样做的方法是通过将连续空间分割成网格,并用单独的函数来离散它们(4 个变量,我将它们分割成 10 个盒子,每个盒子→我的权重矩阵中的 10⁴盒子)。对于更严格的应用,您可以将它们分割成更多的盒子(分割成 100 个盒子,而不是上面的 10 个)。盒子越多,模型可以学习的细节就越多,学习的时间就越长,内存空间也就越大。

小心你分割的盒子的数量。如果太小,你可以有一个表现不佳的模型。如果太大,就需要大的内存空间。还有,我建议限制游戏的区域。比如 OpenAI 的健身房里的推车杆子游戏,我忽略了图像上方的空白和边界附近的区域来限制我的状态空间。这些是你在制作模型时必须做出的一些设计选择。

由于它需要记忆状态空间,QL 和萨莎将最适合受约束和有限动作的游戏(如左右移动的钢管舞),而不太适合更复杂的游戏(如有许多可能走法的国际象棋)。为了避免为状态空间更大的游戏存储所有的状态空间,我们可以使用深 q 网络。这种方法结合了强化学习和神经网络。我们将在后面的帖子中更多地讨论这个深度 q 网络。现在,回到 QL 和莎莎。

快速定义:“策略”是代理用来追求目标的策略。贪心(选择最佳值)是一种策略。贪婪算法会使我们陷入局部极小值。因此,我们有“e-greedy”,这是一种策略,要求它将探索 e 机会,以及遵循最优路径的( 1-e) 机会。e-greedy 应用于平衡强化学习的探索和探索。(点击,了解更多关于探索与利用的信息)。在这个实现中,我们使用 e-greedy 作为策略。

回到 QL 和萨莎,它们都是使用上面的 TD 学习公式更新的,略有不同:( Q 是保存离散空间和动作的所有奖励的存储器, s 表示状态, a 表示动作)

查询语言

数学(“强化学习:简介”中的等式 6.8)

代码:

萨尔萨

数学(在“强化学习:简介”中的等式 6.7):

代码(电子贪婪策略):

差别

区别非常微妙:对于 QL,这是一个非策略算法,当把奖励从下一个状态(s_,a_)传递到当前状态时,它取新状态(s_)的最大可能奖励,并忽略我们正在使用的任何策略。对于基于策略的 SARSA,我们仍然遵循策略(e-greedy),计算下一个状态(a_),并将对应于确切 a_ 的奖励传递回上一步。

重申一下,如果你到达下一个州,QL 考虑的是最好的情况,而 SARSA 考虑的是如果我们在下一个州遵循当前政策的回报。因此,如果我们的政策是贪婪的,萨尔萨和 QL 将是一样的。但是我们这里用的是 e-greedy,所以略有不同。

比较

QL 和萨莎都是解决强化学习问题的优秀初始方法。选择何时使用 QL 或萨莎的一些关键注意事项:

  • 这两种方法都适用于有限环境(或离散连续环境)
  • QL 直接学习最优策略,而萨莎学习“接近”最优策略。QL 是一个更具侵略性的经纪人,而萨尔萨则更为保守。一个例子是在悬崖附近行走。QL 将选择最短的路径,因为它是最优的(有摔倒的风险),而萨莎将选择更长、更安全的路线(以避免意外摔倒)。
  • 实际上,如果你想在一个快速迭代的环境中快速,QL 应该是你的选择。然而,如果错误代价很高(意外的最小故障——机器人),那么 SARSA 是更好的选择。
  • 如果你的状态空间太大,可以尝试探索深 q 网络。我希望不久能写一篇关于这个话题的文章。敬请期待!

履行

对于钢管舞游戏,OpenAI 的健身房有一个预先构建的环境。这里列出了一些健身房的语法:(了解更多关于 OpenAI 健身房的信息这里

接下来,由于 QL 和萨莎在离散状态空间中工作得最好,并且推车杆游戏是连续的,我们将把他们离散化到更小的箱中。箱越多,性能越好。更多的箱将有助于模型考虑更多的特定状态空间,从而导致更好的整体性能。然而,更多的箱子将需要更多游戏的训练,消耗计算能力。如果时间、计算能力和存储空间是您的限制,请使用少量的容器。否则,欢迎您尝试更多的箱子。此外,在扩大规模之前,尝试使用少量的容器来检查性能。

放几张图展示我的算法的性能。请注意,在 OpenAI 的健身房推车杆游戏中,您可以达到的最大步数是 200(到那时游戏将自动终止)。

QL 培训:

SARSA 培训:

QL 测试:

SARSA 测试:

训练图显示了代理在多次游戏后的表现。x 轴表示我们训练的游戏数量,y 轴表示他们可以走的最大步数(由于 OpenAI gym 的设置,上限为 200 步)。
测试图显示了实施阶段的性能(在我们完成培训之后)。直方图显示了我们玩 1000 个游戏时每个模型的结果分布。
结果在意料之中,因为与 QL 相比,莎莎(通常)选择更安全的打法。因此,它可能会采取不太引人注目的步骤,导致更好的性能。这是莎莎表现优于 QL 的一个可能原因。

组合模型?为什么不呢?

随机想法:如果两个模型都不太好(如果我的 SARSA 没有那么好的话),我们可以尝试将两个模型结合起来。

决定将基于“贝塔 QL+(1-贝塔)萨尔萨”。**

在某些情况下,如果你能很好地调优“beta ”,它可能有助于提高性能。调整贝塔系数意味着改变贝塔系数,看看哪个结果最好。这种调优更多的是一种艺术,看哪个效果最好。您可以尝试遍历多个 beta 值,看看哪一个产生的结果最高。

我们的 SARSA 在这个用例中总是成功的,所以在这个特殊的用例中不需要聚合,但是在其他游戏中可能值得一试!如果这个组合版本比其他游戏中的单个模型更好,请在评论区告诉我!

结论

这里有一个 QL 和萨莎之间的快速介绍和比较。我希望它能帮助你更好地理解萨莎和 QL,并看到政策内学习和政策外学习的区别。

正如所承诺的,这里是所有算法和代理的代码(带有现有的 Q 表)。如果想看代理玩游戏的运行视频,就用 VS 代码运行,不要用 GG Colab。

如果你喜欢这篇文章并想看得更多,请随意给我的博客留下任何想法或问题的回复并关注!你也可以在 LinkedIn 上找到我。享受学习!**

参考文献: 1。阿什拉夫,M. (2018 年 12 月 3 日)。强化学习去神秘化:在多种武装强盗环境中的探索与利用。检索自https://towardsdatascience . com/强化-学习-揭秘-探索-vs-剥削-多臂-土匪-设定-be 950 D2 ee 9 f 6 2 .达伯尼,w .,&库尔特-尼尔森,z .(未注明)。多巴胺和时间差异学习:神经科学和人工智能之间富有成果的关系。检索自https://deep mind . com/blog/article/Dopamine-and-temporal-difference-learning-A-fruitable-relationship-between-neuroscience-and-AI 3 .李博士(2020 年 4 月 12 日)。强化学习,第 1 部分:简介。检索自https://medium.com/ai-理论-实践-商务/强化-学习-part-1-a-简介-a53a 849771 cf 4 .OpenAI。(未注明)。开发和比较强化学习算法的工具包。检索自https://gym.openai.com/docs/ 5。斯坦福 PDP 实验室。(2015 年 12 月 16 日)。第九章时差学习。检索自https://web . Stanford . edu/group/PDP lab/pdphandbook/handbook 10 . html 6 .萨顿,R. S .,&巴尔托,总检察长(2018)。强化学习:导论。剑桥(麻省。):麻省理工学院出版社。
7。塔博尔,P. (2020 年 6 月 23 日)。SARSA.py .检索自
https://github . com/Phil Tabor/Youtube-Code-Repository/blob/master/reinforcement learning/Fundamentals/sarsa . py

Scikit-learn 的 k 近邻分类器和回归器简介

原文:https://towardsdatascience.com/intro-to-scikit-learns-k-nearest-neighbors-classifier-and-regressor-4228d8d1cba6?source=collection_archive---------6-----------------------

了解掌握它们需要什么

照片由 苏珊娜 像素

什么是 KNN?

如果 kNN 是你在机器学习课程中学习的第一个算法,请举手,✋🤚

k 最近邻算法是机器学习中最常用的算法之一。由于它的简单性,很多初学者经常用这个算法开始自己的 ML 奇妙之旅。它是少数几个可以平稳地用于回归和分类的算法之一。

那么,是什么让 kNN 同时具有如此的通用性和易用性呢?答案就藏在引擎盖下它是如何工作的。

假设您有一个包含两个类别的变量,如下所示:

图片来自维基百科

给定一个新的未知样本,如何判断它属于哪一组?当然,你会看周围的点。但是结果真的取决于你看得多远。如果你只看最近的 3,(实心圆)绿点属于红色三角形。如果你进一步观察,(虚线圆圈)点将被归类为蓝色方块。

kNN 也是这样工作的。根据 k 的值,该算法通过分类中最近的 k 邻居的多数投票对新样本进行分类。对于预测新样本实际数值的回归,算法只取最近的 k 邻居的平均值。就是这样。就这么简单。

然而,在代码中使用该算法并成功生成预测并不那么简单。今天,我们将看看算法如何工作的本质细节,如何准备任何数据以使其与算法的内部一致,以及如何显著提高其性能(具体来说,从 80%提高到 95%)。

https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

引擎盖下的 k 近邻

关于 kNN 的内部,你应该知道的第一件事是,它是一个懒惰的算法。在机器学习行话中,这意味着该算法与其他算法相比没有训练阶段或训练阶段非常短。不要抱太大希望,因为快速训练有一个很大的缺点。

由于 kNN 查找最近邻的方式,生成预测会慢得多。在短暂的训练阶段,它会记住所有的数据点。为了进行预测,算法会找出新样本与数据集中每个数据点之间的距离。然后,它采用 k 最小距离,并根据其邻居的多数投票对新样本进行分类。

形象由 维基 组成

对人眼来说,标记绿点完全没有问题。但是,如果不计算每个点之间的距离,该算法就无法找到最近的邻居。

距离本身是使用 3 种距离度量之一计算的:

  • 欧几里德距离:x 和 y 分量之差的平方根:

作者图片

  • 曼哈顿距离:x 和 y 坐标分量之间的差值的绝对值之和:

作者图片

  • 闵可夫斯基距离是上述两种技术的推广。它有一个参数 p ,取值为 1 或 2。当 p=1 时,公式变为曼哈顿距离,而 p=2 为欧几里得距离:

作者图片

抱歉,公式太花哨了,但如果你打算进一步学习机器学习,你可能会习惯它。

缺少训练阶段也意味着算法没有一般化

其次,kNN 也是一种非参数算法——它对数据的形状和分布没有严格的要求。与假设要素和目标具有线性关系的线性回归不同,kNN 没有这样的假设。这就是为什么它被认为是最简单的模型之一,并且如果经过“适当”的数据训练,开箱即用就能很好地工作。(我将在后面的部分解释我所说的“适当”是什么意思)

点击阅读并编辑 Kaggle 上这篇文章的笔记本。

如何选择 k 的值

我想你已经意识到,算法的结果完全取决于 k 的值。因此,显而易见的问题是“我们如何选择 k 的最佳值?”

不幸的是,没有明确的答案。每个数据集的最佳值都会发生变化。你的工作是找出最大化你的性能指标的 k ,例如准确性。然而,你可以遵循一些总的趋势来为 k 的可能值做出明智的选择。

首先,选择小值的 k 会导致过拟合。例如,当 k=1 kNN 分类器用与最近邻相同的标签标记新样本。这种分类器在测试时表现很差。相反,选择较大的值会导致拟合不足,并且计算量很大。

你可以在真实邻居的背景下思考这个问题。一个叫杰克的家伙一生都住在他的家乡,并且很久以前就认识他的邻居了。如果他搬到一个新的城市,他突然变成一个完全陌生的人,没有办法很快了解他的新邻居。也就是某种意义上的过拟合。

相比之下,杰克的儿子乔恩只有 6 岁,对他们的邻居知之甚少。当他们家搬家时,乔恩既不了解他的老邻居,也不了解他的新邻居。这可以被认为是欠拟合,一种太愚蠢的算法,无法理解训练集和测试集中的趋势。

现在,有一个完全不同的人——布鲁斯,他非常友好,善于交际,经常旅行,懂多种语言。无论他走到哪里,他都很快和周围的人成为好朋友。在这个类比中,布鲁斯的品质可以被认为是算法的最佳参数。

这个例子可能对你来说没有任何意义,但是每个人都有自己的解释什么是过度适应和欠适应的版本。重要的是,当你使用不同的 k 值时,你要理解 kNN 的性能是如何变化的。

实际上,你可以使用像GridSearchCV这样的工具来选择邻居的数量,但是这超出了本文的范围。相反,我们将使用模型复杂性曲线直观地选择最佳数量。

用 KNeighborsClassifier 分类

如前所述,对于分类问题,一个新样本的标签是由最近的 k 个邻居中的多数票来识别的。让我们使用sklearnKNeighborsClassifier来看看算法的运行情况:

我们从sklearn.neighbors导入它和其他有用的函数。所有其他库都以标准别名导入。

对于数据集,我们将使用来自 Kaggle 的帕尔默群岛企鹅数据。该数据集包含三种企鹅的特征:阿德利企鹅、巴布亚企鹅和下颚带企鹅。我们将通过使用企鹅的身体测量来构建企鹅种类的 kNN 分类器:

penguins = pd.read_csv('data/penguins_size.csv').dropna()
penguins.head()

我提到过,kNN 对数据的分布不做任何假设。让我们构建第一个没有任何预处理的分类器。我们将只使用 3 列作为特征:库门长度和深度,脚蹼长度和身体质量指数:

为了简单起见,我只选择了数字列。创建了一个大小为 0.25 的测试预测,并用 3 个邻居拟合了一个分类器。让我们用accuracy_score来计算它的精度:

>>> accuracy_score(y_test, predictions)0.7722772277227723

我们获得了 77%的准确率,这并不理想,但对于开箱即用的模型来说,这是一个非常好的分数。

KNeighborsRegressor 回归

在预测连续值(不是标签)的回归任务中,kNN 取最近的 k 个邻居的平均值。回归器从sklearn.neighbors.KNeighborsRegressor开始就很容易得到:

from sklearn.neighbors import KNeighborsRegressor

这一次,我们将尝试使用企鹅的三个身体测量值来预测它们的体重指数(同样,只有数字特征,没有经过预处理):

将邻域数设置为 5 会产生 0.79 的决定系数。与其盲目地为 k 试随机数,不如采取更聪明的方法。

模型复杂性曲线

我们的想法是尝试不同的 k 值,并根据它绘制我们的性能指标的结果。这个你一看到就更有道理了。让我们从分类器开始:

我们创建了一个名为plot_complexity_curve的函数,它将邻居的可能数量、模型本身和数据作为参数。然后,对于每个 k ,它对训练集和测试集上的给定模型进行初始化、拟合和评分。在训练集和测试集上对模型进行评分会让您很好地了解哪些值会导致过度拟合和欠拟合:

在函数中,我引入了接受 x 和 y 值的[knn.score](https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html)函数。这只是使用predict生成预测并根据y_test进行评分的一个更简短的版本。我们重复选择数值作为特征的相同过程,并将它们插入到函数中:

从图中我们可以看到,3 或 4 个邻居是过度拟合(训练分数非常高,测试分数很低)和欠拟合(训练分数和测试分数都很低)之间的中间值。

现在,是回归者的时候了:

对于回归量,似乎 6 到 10 之间的任何数量的邻居都是一个好的超参数。请注意,精度以决定系数的形式给出— $R $。在 sklearn 的官方文档上阅读更多相关内容。

在这两种情况下,都有很大的改进空间。有一些预处理技术可以显著提高 kNN 的性能。让我们在下一节深入探讨它们!

提高 kNN 的性能,特征缩放

尽管我们在企鹅数据集上得到了相当好的分数,但 kNN 是一个非常繁琐的算法。它有一定的数据质量要求才能正常工作。

kNN 的第一个要求是数字特征要有相同的尺度。如果你注意的话,你会发现身体质量指数栏与所有其他身体测量数据的比例完全不同。通常,所有要素都应进行缩放,使其范围从 0 到 1。

这可以通过一种叫做最小最大缩放的方法来实现(称为归一化)。它为分布中的每个数据点减去最小值并除以(最大-最小):

Scikit-Learn 方便地提供了一个MinMaxScaler转换器,它对 pandas 数据帧中的数字列执行这种规范化:

from sklearn.preprocessing import MinMaxScaler

让我们对企鹅的所有数字特征进行缩放。一般语法如下:

在用MinMaxScaler启动缩放器后,我们调用返回转换数据的fit_transform方法:

我们将使用我们的 good-ol' plot_complexity_curve函数来寻找 k 的最佳值:

哇,现在所有分数都高于 95%。看看功能扩展对性能的提升有多大。查看图表,保持欠拟合和过拟合之间平衡的 k 的值是 12 或 13。

注意MinMaxScaler不是特征缩放的唯一选项。在异常值的情况下,不要使用MinMaxScaler。相反,使用StandardScaler,它通过减去平均值并除以标准偏差来缩放。更详细的指南见 sklearn 的用户指南

编码分类变量

即使我们得到了相当好的分数,我们也没有把分类变量包括进去。是时候让他们进来了。

大多数 ML 算法更喜欢数值,所以我们应该将所有文本/分类变量转换成数字。

对于大多数数据集,在将文本/分类值转换为数字之前,会有更多与它们相关的问题。这里我们只关注转换部分,但是你可以在这里查看我关于使用 pandas 清理文本数据的权威指南:

用数字编码分类值最流行的选项是 sklearn 的[OneHotEncoder](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html)LabelEncoder。我们今天只使用后者。

标签编码器为数据集中的每个唯一类别分配一个新的整数。例如,岛屿变量有 3 个独特的类别:

>>> penguins.island.unique()array(['Torgersen', 'Biscoe', 'Dream'], dtype=object)

性别分为两类:

>>> penguins['sex'].unique()array(['MALE', 'FEMALE', '.'], dtype=object)

啊哦,我们有一个不一致的类别—一个点。我们应该删除它:

标签编码器最适用于顺序变量,即有顺序的类别。即使我们在数据集中没有类别的排序,我们仍然可以使用它。

在我们进行编码之前,让我们构建特性和目标数组。记住这一次,我们将所有列作为特征:

现在,我们应该将分类和数字特征提取到单独的数组中,因为我们对它们应用了不同的转换器:

像以前一样,让我们用数字来表示特征:

作为一个额外的步骤,我们将缩放后的特性数组和它们的列名放回到一个数据帧中。

最后,我们对分类值进行编码:

LabelEncoder不像MinMaxScaler那样工作。我们不能同时将它应用于所有分类列。因此,我们循环遍历它们:

现在,我们的特征数据被分成预处理的数据帧,X_catX_num_scaled:

X_cat.head()

X_num_scaled.head()

让我们将它们一起添加到单个数据帧中:

转换引入了一些新的空值。我们应该从特性和目标数组中删除这些行:

现在,我们将使用前面的plot_complexity_curve函数找到预测企鹅种类的最佳模型:

什么?我们的测试分数比培训分数高?怎么会这样呢?这里面肯定有猫腻。让我们在下一部分深入探讨:

分层分裂

这个奇怪的事件发生在我们将分类值作为特征包含进来之后。在统计学中,有一个术语叫做抽样偏差。当你的样本不能代表真实人群时,就会出现这种情况。

例如,让我们想象你正在做一项全国性的调查。很明显,你不可能给全国每个人都发问卷,所以你抽取一个样本。在该国,女性占 54%,男性占 46%。为了不引入采样偏差,你必须尊重这个性别比例。如果你对 10000 人进行抽样,你必须确定其中 4600 人为男性,5400 人为女性。

让我们研究一下当我们进行常规训练/测试分割时会发生什么。更具体地说,我们将看看岛屿和性别类别的比例是否会保留:

看看完整数据中的性别比例:

看看训练数据中的性别比例:

看看测试数据中的比例:

正如你所看到的,我们得到了测试集非常不同的比例。让我们对这个岛做同样的尝试:

同样的事情也发生在这个岛上。使用 Scikit-learn 很容易防止这种情况。train_test_split函数有一个stratify参数,它的作用就是:保留类别的基本比例:

在分类的情况下,我们总是将y(目标)传递给stratify。因为我们并不真正关心保持特征的分布,而是目标数组。让我们使用plot_complexity_curve函数,现在使用分层分割。在我们做分割之前,我们将重复特征缩放和编码的最后步骤。我不会再提供代码,所以假设X_readyy现在是预处理数组:

现在一切都如预期的那样。所有训练分数都高于训练分数。解释该图,k 的最佳值可能是 7、8 或 9。

以前,我们的分离可能会为模型生成一个更合适的测试集。这就是我们得到那些奇怪分数的原因。

结束语

我想通过总结 kNN 的利弊来结束这篇文章。

优点:

  • 非常简单的算法,容易理解
  • 快速训练阶段
  • 不假设数据的基本分布
  • 通用-可用于回归和分类

缺点:

  • 非常缓慢的预测阶段
  • 大量内存使用,因为它存储所有数据
  • 对量值敏感-这就是为什么需要对要素进行缩放
  • 对异常值和噪声敏感
  • 遭受维数灾难

感谢阅读!

不知道接下来要读什么?在这里,我为你挑选了一些东西:

Julia 编程语言中的软件工程介绍

原文:https://towardsdatascience.com/intro-to-software-engineering-in-the-julia-programming-language-3c32411c5683?source=collection_archive---------36-----------------------

朱莉娅综合教程

Julia 语言中定义的目录和环境概述。

(图片由作者提供)

本文视频

开源代码库

https://github.com/emmettgb/JuliaLessons/tree/master/7

介绍

虽然 Julia 编程语言以其科学用途而闻名,但仍有一些包需要为此目的而开发。也就是说,在 Julia 中,软件工程可能不是这门语言最重要的技能,重要的是首先要有做科学的软件包。包是生态系统的重要组成部分,我个人认为不管科学目的如何,包总是保持你的算法技巧处于最佳状态的好方法!

对于本教程,我们将致力于一个非常令人兴奋的项目,实际上可能在未来派上用场!我们的项目名为 SuperFrame.jl,它将是现有包 DataFrames.jl 的扩展。因此,随着更多地了解如何使用 DataFrames.jl 之类的包,我们也将熟悉如何创建自己的优秀项目。考虑到这一点,我决定我们不妨把它正式化!让我们在 Github 上创建一个项目!如果这个项目真的有用,我们可以一起努力把它推到 Julia package registry,它可能会成为人们使用的东西——这很令人兴奋,因为我们正在一起努力!这是我创建的存储库!:

https://github.com/emmettgb/SuperFrame.jl/tree/main

按照惯例,提交应该改进提交中将要包含的内容的简要描述。也就是说,存储库对任何提交都是开放的,但您可能应该等到我们实际使用它时,才能理解我们将要使用的确切方法和标准化——按照惯例,当然是基于 DataFrames.jl 的。

文件结构

幸运的是,对于基于 Julia 的开发人员来说,开发一个包含完整环境的包实际上非常容易。我们可以用适当的 Project.toml 创建完整的文件结构,它将包含我们的虚拟环境,来自 Julia Pkg REPL。现在让我们进入一个合适的目录并运行 Julia。我个人用~/Projects。

cd ~/Projects
julia

现在我们将使用]键进入 Pkg REPL:

julia> ]
pkg>

最后,我们可以使用 activate 命令用 Project.toml 文件和 Manifest.toml 文件创建新的虚拟环境:

activate SuperFrame.jl

为了实际创建适当的文件和环境,我们需要用 add 命令添加一个依赖项。当然,因为我们正在创建 DataFrames.jl 扩展,所以我们将添加 DataFrames.jl:

add DataFrames

现在我们可以退格退出 PKG REPL,然后按 ctrl + D 退出朱莉娅 REPL。

Pro 提示:Julia 中的 pwd()函数会推送你的 REPL 的工作目录。实际上,这很有用。我认为这是一个可以利用的很好的功能,因为在 Julia 中很难判断你在文件系统中的位置。

创建模块

在结束这个快速介绍之前,我们今天要做的最后一件事是在 Julia 中创建一个基本模块。回头看一下模块 Compose.jl 的页面,我们看到我们需要一个 src 目录,所以让我们用 cd 进入包含新环境的文件夹,并创建一个新的 src 目录:

cd SuperFrame.jl
mkdir src
cd src

今天我只是用 nano 编辑了一小段文本,但将来我会使用带有 Juno 扩展的 Atom 文本编辑器。当然,我们还将回顾如何设置这个环境,这应该相对简单,所以不要担心。然而,这是我的偏好,所以如果有你想要使用的偏好的文本编辑器,请随意使用!

nano SuperFrame.jl

最后,我们要做的最后一件事是在 Julia 中创建一个模块对象。Julia 中模块的关键词是

组件

我称之为直接。我们在模块单词后面加上一个要导入的名称,对于这个例子,它当然是超帧。正如我们将在 Julia 中编写的其他内容一样,我们也需要编写**end**来完成我们的语句。

module SuperFrame
    using DataFramesend

我还添加了一个“使用数据框架”,这只是临时代码,因为为了更高效,我们将来可能会使用直接导入。也就是说,将它写入我们的硬盘将完成我们新软件包的初始设置!

结论

我非常兴奋能和我的读者和观察者一起创建这个包。这对我来说真的很有趣,我真的希望有人能做出贡献,因为这是我们一起的项目,我认为只要有一点指导,它会变得很棒,并提供一些非常有用的互动体验和学习。SuperFrame.jl 将成为一个支持多种不同数据格式的包,其类型比传统的基于 DataFrames.jl 的类型更好。

虽然 DataFrames.jl 是一个很棒的包,但如果能更精确地或以某种方式处理一些数据,那就更好了。当我们这样做的时候,我们还可以创建一些很酷的交互式可视化,并把这个包扩展到处理像图像数据框这样的东西。你对这个项目感到兴奋吗,因为我当然兴奋了!我也很高兴能参与到你们对这些编程概念的学习氛围中——因为编程很棒,也很有趣!非常感谢您的阅读,我很欣赏,并祝新年和 2021 年快乐!

应用拓扑数据分析简介

原文:https://towardsdatascience.com/intro-to-topological-data-analysis-and-application-to-nlp-training-data-for-financial-services-719495a111a4?source=collection_archive---------13-----------------------

应用于金融服务的 NLP 训练数据

拓扑数据分析,或称 TDA,是一套提供数据集额外洞察力的方法。它增强了其他形式的分析,如统计和几何方法,并对任何想要更完整地了解其数据的数据科学家都很有用。

本文描述了拓扑方法的实用性,概述了一个著名的 TDA 算法“mapper ”,并描述了如何使用一个名为 Scikit-TDA 的工具包应用于自然语言处理。最后,我们分享了将上述所有内容应用于机器学习管道的训练数据收集问题的细节,该管道涉及来自金融服务行业的文档。

为什么是拓扑?

拓扑学是关于连续对象的数学。不是大小和形状,而是连续性。它是关于事物是如何联系在一起的,差距在哪里。

一个简单的类比展示了为什么拓扑数据检查如此有用,那就是挂上节日灯。当负责在房子上安装节日灯时,首先从几何学和统计学的角度考虑这个问题是很自然的。

来源

几何回答了像房子有多长,屋顶有多高,插座在哪里,需要多少盏灯这样的问题。统计数据回答了一些问题,比如这些灯需要多少电流,它们的成本是多少,它们平均一天要亮几个小时。

安装完成后是第一次插上电灯的重要时刻,但是…什么也没有。突然间,长度、尺寸和颜色都变得不重要了。它们的价格和重量并不影响它们为什么不启动。相反,我们跳到故障排除模式,以完全不同的方式思考灯串。我们认为它们是电路。

并联(左)和串联(右)灯串的电气图。x 代表灯泡,插头在底部。来源

如果只有几个灯泡不亮,这串灯泡是并联的,我们只需更换那些坏了的灯泡。如果没有一盏灯亮着,它们可能都是串联的,我们必须找到一些坏了的灯泡。或者我们可以把串联的线插到并联的线上,串联在一起。还是水货!在任何情况下,我们现在都准备好开始调试上面的图片,记住原理图看起来一点也不像房子上的实际灯串。

看一个数据集的拓扑可视化就像看节日灯的电路图。我们有意忽略空间特征、点与点之间的巨大长度和短距离,而是只关注数据的连通性。我们问什么是相连的,什么是分开的,差距在哪里。这给了我们新的信息来回答棘手的问题。重要的是要记住,TDA 并没有取代几何和统计分析,而是补充了它们,就像在房子上挂上节日灯时电路图补充了卷尺一样。

简单地说,映射器算法

很多 优秀 入门 视频讲解 Carlsson、Memoli 和 Singh 在 2007 年发明的 mapper 算法。以下是概述,而不是试图复制这些资源:

  1. 从高维空间的数据开始。
  2. 创建重叠的数据仓。
  3. 在每个箱内,对数据进行聚类。
  4. 对于每个集群,在图中创建一个节点。
  5. 连接共享数据点的节点。

图片来自 Carlsson 等人,2013 年

在真实数据分析中,原始数据是高维的,并且不能像这里的初始数据点那样可视化。否则,我们就完了!生成的图形以节点和边的形式表示,使我们可以看到拓扑关系,而无需考虑初始数据向量的几何细节。

好的。怎么会?

答案:西基特-TDA

Scitkit-TDA 是一个 Python 包,为以前独立的算法提供了标准接口。像 scikit-learn 一样,.fit().fit_transform()系列中的方法用于执行算法和转换数据。一个例子看起来像

import kmapper as kmmapper = km.KeplerMapper(verbose=2)
projected_data = mapper.fit_transform(data, projection=TSNE())
graph = mapper.map(
    projected_data,
    clusterer=DBSCAN(),
    cover=km.Cover(35, 0.4),
)

其中TSNEDBSCAN可以通过它们自己的.fit().transform()方法与适当的类似 scikit 的对象交换。更多详细示例,参见 Scikit-TDA 示例页面

向 NLP 申请

从文本中创建向量对于机器学习模型来说非常重要,因为机器学习模型只知道如何对数字列表进行操作。最简单和最容易的方法之一是单词袋模型,其中数据集中的每个唯一单词在某个高维空间中有自己的方向,文档由它包含的单词的坐标表示。

遵循 Scikit-TDA 的开普勒映射器示例,我们使用 TFIDF 缩放对文档的文本进行矢量化,减少到二维,并使用聚类算法构建图表。

mapper = km.KeplerMapper(verbose=2)projected_X = mapper.fit_transform(term_count_matrix,
    projection=[TfidfTransformer(sublinear_tf=True),
                TruncatedSVD(n_components=100, random_state=0),
                Isomap(n_components=2, n_jobs=-1)],
    scaler=[None, None, MinMaxScaler()])

我们对文档中的例子做了一些调整。因为我们要处理如此多的大文件,所以我们使用一个定制的具有有限内存的并行术语计数器来构建一个术语矩阵,然后在管道中使用一个 TFIDF 转换器。我们还试验了不同形式的降维,如 PCA,以构建投影数据。

最后,为了构建图表:

graph = mapper.map(projected_X,
    clusterer=AgglomerativeClustering(
        n_clusters=3,
        linkage="complete",
        affinity="euclidean"),
    cover=km.Cover(n_cubes=12, perc_overlap=0.33))

同样,我们试验了不同的聚类算法,如 DBSCAN 和 HDBSCAN,并改变了亲和力和重叠参数。

应用于金融服务培训数据

财务文件是 S&P 全球许多工作流程的核心。在内部,机器学习分类模型用于为许多用例区分文档流的优先级。公司内部的内容专家定期提供训练数据,以确保模型以最佳性能运行。

训练数据收集过程的简化如下。对于给定的工作流,内容专家为每个摄取的文档提供一个“肯定”或“否定”标签。在训练时,我们检索每个文档的文本,并训练一个分类器来尝试基于模型置信度分数线性分离文档。当构建一个新的模型时,我们可能会在正面和负面文档之间看到相当多的(不希望的)重叠。

约 40,000 个文档的新模型的得分直方图。几乎所有得分低于-0.5 的文档都有一个“负面”标签,所有得分高于 2.0 的文档都有一个“正面”标签。中间的分数代表模型混乱。理想情况下,左边的灰色叶和右边的黄色叶是分开的。x 轴上的单位是任意的。

对于一个新的工作流,合理的解释是一个训练数据标注的问题。查看模型出错的文件,在中间的某个地方,是一个开始的好地方。对于规模感,在 x 轴上的分数 0.0 和 1.0 之间有大约 9000 个文档。

我们现在使用 TDA 根据它们的拓扑属性对文档进行分组,并寻找分类错误中的模式。我们想知道混淆模型的文档是否是拓扑连接的。如果是这样的话,我们可以使用具有高度混淆的集群节点作为候选,发送回内容专家进行额外的考虑。

如前一节所述,将 TDA 应用于文档,我们最终得到的是按平均文档混乱程度着色的节点和边。

在图像中,每个圆圈都是一组文档。最小的圆圈只代表几个文档,而最大的圆圈代表几千个文档。最亮的黄色球只包含被模型可靠地正确分类的文档,而深紫色球只包含错误分类的文档。从黄色到紫色的光谱范围是每个圆的“平均正确性”的连续体。

错误分类的文档组,即蓝色和紫色节点,似乎主要出现在图像的北部和西北部区域。我们可以从这些节点中选择所有文档,查找它们的模型置信度得分,并查看它们在模型置信度曲线上的位置。

来自蓝色/紫色 TDA 集群的文档标有绿线。

每个绿色竖条代表 TDA 输出的蓝色/紫色节点中的一个文档,较暗的绿色部分表示在该模型置信度得分下文档的浓度较高。TDA 标记了不到 500 个文档,大部分在 x 轴上的分数在 0.0 到 1.0 之间。

在 TDA 分析之前,我们有大约 9000 份文件要开始查看,以确定我们的数据收集是否有问题。现在已经缩减到不到 500 人。这并不是说我们不能用统计或几何方法获得收益,但我们确信我们发回的文件是相关的。幸运的话,我们的业务合作伙伴将在我们发送的文档中找到一个模式,并纠正培训数据收集中的系统错误,从而进行更好的第二轮模型培训。

结论

如果统计方法是数据科学家的卷尺,绘图是梯子,那么 TDA 就是万用表。它通过关注连接和间隙而不是大小和形状,提供了一种查看数据的正交方式。链接资源为刚刚开始使用 TDA 的数据科学家提供了快速入门和高效工作的机会。

录像

论文和网站

Ryan Duve 是标准普尔全球公司的数据科学家。他还是一名物理学家、Linux 黑客和一名糟糕的咖啡师。

介绍 Webhooks 以及如何用 Python 接收它们

原文:https://towardsdatascience.com/intro-to-webhooks-and-how-to-receive-them-with-python-d5f6dd634476?source=collection_archive---------3-----------------------

本教程将介绍 webhooks 的概念。我们还将构建一个简单的 Flask 服务器,它可以接收 GitHub webhooks。我们还将看到如何公开我们的本地主机。

照片由 Grace 到Unsplash

什么是 webhook?

在说 webhooks 之前,先说一下 API。下面是一个 API 的数据流。

作者创建的图像

您向 API 发出一个 GET/POST 请求,然后得到一个响应。如果你想学习更多关于使用 API 的知识,可以看看我关于使用 Python 使用API 的文章,或者我关于使用 JavaScript 使用API 的文章。

考虑一下 Github API,如果我们想构建一个 API,每当回购中出现新问题时,它都会发送一封电子邮件。一种方法是构建一个 API,每隔 1-2 分钟发出一个请求,检查是否有新的问题出现并通知我们。这个过程被称为轮询。基本上,我们必须定期请求检查新的问题。然而,这似乎是低效的。如果每当一个新问题产生时,GitHub 向我们的 API 发出请求,那该怎么办?这就是所谓的 webhook。我们不定期发出请求,我们只是给 Github 我们的 API 的端点,每当一个新的问题产生时,就会向我们给 GitHub 的端点发出请求。Webhooks 也被称为反向 API。下面是轮询和 webhooks 的比较。这张图片的灵感来自于这篇文章

由 Autho 创建的图像

正如你可能已经注意到的,很多请求被发出,根据我们发出请求的频率,在新问题被创建和我们的 API 得到通知之间可能会有一点延迟。

让我们创建一个 API,以便在 Github repo 中创建新问题时接收请求。

创建一个简单的 Flask 服务器

首先,让我们创建一个 hello world 端点。

现在我们需要创建一个端点来接收来自 GitHub API 的请求。这将是一个接受 POST 请求的标准端点。

我阅读了文档,知道 JSON 对象的关键。您可以使用不同的键来访问更多数据,如问题标签等。

现在你可以运行你的 flask 服务器了

python3 __init__.py

公开暴露我们的本地主机 URL

Webhooks 需要一个公共 API 端点,因为它们不能向端点发出请求,例如“ http://127.0.0.1:5000/ ”。一种方法是部署 API 并使用已部署 API 的 URL。另一种方法是将您的本地主机公开为一个公开可用的 URL。这是暂时的,只有在 Flask 服务器运行时才有效。对公共 URL 的任何请求也将被发送到您的本地主机 URL。

我们将使用 ngrok 来公开我们的本地主机 URL。你必须创建一个帐户。

ngrok 截图

为您的操作系统下载 ngrok 并解压缩。现在打开一个终端,cd 到解压后的 ngrok 文件所在的目录。在终端中键入以下命令

ngrok  http <PORT NUMBER>

例如:如果您的 flask 服务器运行在端口 5000 上,您必须键入以下内容

ngrok http 5000

终端截图

您应该在终端中看到类似的输出。公共 URL 是“转发”旁边的 URL。我的情况是http://35cc-69-58-102-156 . ngrok . io。如果您访问您的公共 URL,您应该看到与您访问您的本地主机 URL 时看到的一样的东西。

创建问题网络挂钩

选择任何你喜欢的 Github Repo。进入设置>网页挂钩>添加网页挂钩

回购截图

Webhook 创建的屏幕截图

输入您的端点,在我的例子中是http://35cc-69-58-102-156.ngrok.io/githubIssue

由于我们只希望在回购中创建问题时提出请求,因此选择“让我选择单个事件”向下滚动选择“问题”。一旦你下来,向下滚动并创建网页挂钩。

测试 Webhook

在回购中制造问题

问题截图

现在检查运行 flask 服务器的终端。我还添加了一个标签,并在创建问题后关闭了问题。

终端截图

结论

现在 Flask 服务器做不了什么。但是,您可以在它的基础上进行构建。除了打印收到的数据,您还可以使用这些数据发送推送通知或电子邮件。我希望这篇文章对你有所帮助。在 LinkedInTwitter 上与联系。

如果你喜欢我的文章并愿意支持我,请考虑使用我的推荐链接注册一个中级会员。您将能够访问付费墙后面的所有文章。如果你使用我的推荐,我将免费获得你每月订阅的一部分。

推出两款工具,将您的功耗提升 10 倍

原文:https://towardsdatascience.com/introducing-2-tools-to-speed-up-your-power-bi-10x-e354cce355ae?source=collection_archive---------36-----------------------

使用所解释的步骤进行自我诊断,以确定根本原因并加快报告速度

尼古拉斯·霍伊泽在 Unsplash 上拍摄的照片

咨询 Power BI 时,我收到的最常见的问题之一是关于性能的,例如“为什么运行一个仪表板需要这么长时间?”或者“我怎样才能让它更快?”

与性能相关的因素有很多。在开始讨论每一个问题或分享一系列建议之前,我想告诉你如何进行自我诊断,这样你就可以对可能的原因进行分类,找出根本原因,并专注于关键问题!

内容

  • 确定创建仪表板时的步骤
  • 在设定目标之前了解用户行为
  • 80/20 原则
  • 使用性能分析器识别问题
  • 使用 DAX Studio 进行进一步分析
  • 基于洞察力采取行动
  • 结论

首先,让我们概述一下创建仪表板的过程。

有三个步骤:

  • 导入
  • 询问
  • 形象化

在设定目标之前了解用户行为

多快才算够快?快和慢都是主观的。如果是 C 级的财务仪表板,期望可能会很高,因为仪表板通常在注意力短暂的通勤中消耗,例如在出租车上用手机查看仪表板。相反,在软件测试场景中,等待时间可能会更长,因为数据量很大,甚至刷新数据库也需要时间。BI 开发人员很忙,所以试着把注意力放在有影响力的事情上。

80/20 原则

在许多情况下,80%的延迟来自仪表板中不到 20%的视觉效果。性能分析器帮助我们识别这些。

使用性能分析器确定问题

打开 Power BI 桌面,点击顶部的视图。一旦选择性能分析器,您将看到该功能出现在右侧。点击开始记录后,分析仪记录刷新花费的时间。我建议在你换了一个新页面来模拟用户体验之后再录制。

在下图所示的示例中,最耗时的是在查询类别下,这意味着 DAX 中还有改进的空间。如果它在“视觉显示”类别下,您可能希望更改不同的视觉效果。在大多数情况下,Power BI 提供的原生视觉效果具有更好的性能。

下图演示了调整前后的情况。刷新一个控制面板需要 120 多秒。转完,用了不到 4 秒。

作者的 Power BI 图像(调整前)

作者的 Power BI 图像(调整后)

使用 DAX Studio 进行进一步分析

假设我们已经对在查询中花费最多的持续时间进行了分类。我推荐使用 DAX Studio 做进一步分析。DAX Studio 是一个在 Power BI、Excel 和分析服务表格中编写、执行和分析 DAX 查询的工具。更多详情,请点击查看

如果是第一次使用 DAX Studio,可以随意参考以下步骤进行连接。

下载 DAX Studio 后,请打开它并单击文件→打开以链接到 Power BI 报告。

作者的 DAX 工作室图像

点击所有查询

作者的 DAX 工作室图像

不要忘记将卡片拖到所有查询中。

作者的 DAX 工作室图像

将卡片拖到所有查询中。

作者的 DAX 工作室图像

现在,您已经准备好分析 Power BI 报告了。

从下图中,我们可以检查查询中的步骤和持续时间。它帮助我们识别最耗时的查询,并分析如何改进。

作者的 DAX 工作室图像

基于洞察力采取行动

DAX Studio 也计算每列的大小。请不要低估它的力量。我有一个客户觉得它很有见地。在实践中,数据库管理员和分析师拥有不同级别的权限,所以当分析师不知道列的大小并可能失去确定延迟根本原因的机会时,这并不奇怪。

下图显示了按大小排列的列列表。黄色标记的行很重,但在仪表板中没有使用。然后我让客户仔细检查需要多少列?原来 400 列中只有 30 列是需要的。在清理了数据并带来了他们所需要的东西后,文件大小已经大大减小了。它不仅使传输变得容易,而且性能也提高了。

作者的 DAX 工作室图像

结论

性能分析器DAX Studio 是我用来自我诊断的两个工具。我喜欢它们易于使用,并帮助我们专注于要深入研究的领域。毕竟,找出根本原因比简单地说“太慢了”更有帮助。

下一次,如果你面临类似的问题,问一些后续问题来分解问题,并用数据来支持。

一些示例问题:

  • 刷新一份报告需要多长时间?
  • 哪种视觉花费的时间最多?
  • 哪些步骤最耗时?导入、查询还是可视化?
  • 这种视觉效果对讲述故事有必要吗?
  • 我们需要将所有的列导入到数据集中吗?

最初发布于https://wanchunghuang . com/introducing-2-tools-to-speed-your-power-bi-10x/2021。

保持联系

  • 关注我在媒体上的更多类似的故事
  • LinkedIn 上连接
  • 你怎么想呢?留下评论

引入由 Prefect、AWS 和 Github Actions 支持的数据流管理系统

原文:https://towardsdatascience.com/introducing-a-dataflow-management-system-backed-up-by-prefect-aws-and-github-actions-3f8c0eef2eb2?source=collection_archive---------42-----------------------

该 Github 项目如何通过提供 AWS 和 Prefect 云基础设施将您的本地 Prefect 工作流提升到一个新的水平,以及作为其中一部分的重要角色 Github Actions

萨法尔萨法罗夫Unsplash 上拍摄的照片

TL;DR: 该项目建立了一个数据流管理系统,由总监AWS 提供动力。它的部署已经通过 Github Actions 完全自动化,此外还公开了一个可重用的接口以向 Prefect Cloud 注册工作流。

问题是

perfect 是一个开源工具,让团队能够用 Python 编排工作流。它的云解决方案- Prefect Cloud -在框架之上增加了一个管理层。这使得团队能够管理工作流,同时在保证执行层保持在用户一侧的混合模型下运行。

这么说的话,用户有责任启动并将执行层与 Prefect Cloud集成,这意味着需要一些工程工作来使解决方案端到端地启动和运行。

动机:当自动化需要自动化时

几个月前,我与 Prefect 和 Python 一起做了一个个人项目。当我完成工作流开发并向 Prefect Cloud 注册时,我注意到注册步骤与工作流定义不太匹配,对我来说变成了一个手动和重复的过程。然后,我决定为未来的工作设计一些通用的和可重用的东西。

我最初的方法是创建一个私有的助手项目,唯一的目的是自动化本地工作流和完美云之间的这个桥梁。然而,随着这个想法的成熟和它的价值变得更加清晰,代码库也逐渐涵盖了在云中运行执行环境的自动化。该项目的目的从狭隘的关注交付一个可重用的工作流注册工具发展到更大的东西,为希望在 AWS 上执行工作流并通过完美云管理它们的团队提供一个起点或模板。

解决方案:数据流-自动化-基础设施

作者图片

我将这个项目命名为data flow-automation-infrait现在已经达到了一个很好的状态,我自己或者任何遵循 README 文件的部署部分的人都可以毫无问题地将基础设施推到一个全新的环境中。**

该项目有三个主要特性,部署和自动化测试都是通过自动触发的 Github 动作(T21)管道来完成的。

1 -在 AWS 上自动创建执行环境

这加快了 AWS 环境执行工作流的速度。目前,有一个可用的环境运行在 ECS (弹性容器服务)和 Fargate 上。这种方法利用 AWS 计算服务,同时运行 100% 无服务器,不涉及任何管理。

这组执行环境可以很容易地扩展以适应新的需求。一个很好的例子就是包含一个 Kubernetes 执行环境。

2 -将执行环境与完美的云相集成

提督代理是一个长期运行的进程,它在云执行环境提督云之间架起了一座沟通的桥梁。该流程监听工作流运行请求,将它们委托给云提供商的执行环境,并不断将运行状态反馈给 Prefect Cloud。

在 Prefect 上有一些代理类型可用,但是由于贯穿整个项目的单一执行环境是在 ECS Fargate 上运行的,所以它目前提供了具有 ECS 代理类型的代理。提督代理作为一个任务在 ECS Fargate 上运行,在一个专门用于代理的集群上运行。

3 -提供注册工作流的界面

到目前为止,您已经知道 Github Actions 运行项目管道来创建 AWS 和完美的云环境。然而,你可能知道也可能不知道的是,Github Actions 也提供了一个市场,人们在那里发布他们自己的动作,以便其他开发者/存储库可以使用它们。

我利用这个特性创建了一个集中的、可重用的方法来向 Prefect Cloud 注册工作流。通过这个定制动作,任何人都可以从单独的存储库中发布工作流,同时能够在由 dataflow-automation-infra 部署的基础设施之上运行它们。

进一步开发和扩展

如上所述,该项目目前用它的完美代理建立了一个单一的执行环境。对于生产用例,这可以扩展到提供多种配置,既适合简单的用例,也适合更复杂的用例。例如:用于分析的简单数据摄取工作与训练资源密集型机器学习模型。

对于任何想要尝试的人来说,自述文件包含了详细的部署步骤。如果您有任何反馈或希望为项目做出贡献,请联系我们。下次见!

介绍一种新颖的垃圾填埋场和废物堆放场的甚高分辨率数据集

原文:https://towardsdatascience.com/introducing-a-very-high-resolution-dataset-of-landfills-and-waste-dumps-196d46d533fc?source=collection_archive---------14-----------------------

行业笔记

由来自德国、匈牙利、塞尔维亚、印度和巴西的垃圾填埋场的甚高分辨率多光谱卫星图像组成的新数据集

Pop &斑马Unsplash 上拍照

非法垃圾场和垃圾填埋场的威胁

废物处理是一个严重的问题,世界上大部分的废物都进入了东南亚和非洲国家的垃圾场。除了垃圾填埋场,废物还被非法弃置在河岸和海滩上。虽然其中一些垃圾填埋场可能是合法的,并有适当的回收和安全处置系统,但大型非法垃圾填埋场不仅在污染土壤、水和空气方面对环境构成威胁,而且对社区的健康有害。

对于政府和市政当局来说,跟踪这些迅速增长的垃圾填埋场以控制威胁是一项挑战。虽然这些垃圾填埋场可以通过无人机进行监测,但通过卫星图像使用地球观测(EO)的可能性可以让我们一次性监测更大的区域,从而形成更好的废物监测和管理系统。

利用地球观测探测垃圾填埋场的可能性

由于目前正在运行的大量空间卫星传感器程序的存在,各种分辨率(空间、时间和光谱)的卫星传感器数据量达到了 Pb 级。空间遥感传感器可分为成像和非成像传感器。如果只说成像传感器,还有光学、热、雷达成像传感器的太空计划。对这些传感器的详细描述超出了本文的范围。

下表列出了一些最流行和最广泛使用的卫星传感器。

各种卫星任务的技术规格表。除了雷达卫星和哨兵之外,所有的卫星传感器都是光学传感器。RADARSAT 和 Sentinel 包含合成孔径雷达(SAR)传感器。作者图片

因此,我们可以看到,在获取光电探测数据方面,我们确实有太多的选择,这使得研究利用光电探测填埋场的可能性成为一项值得进行的工作。光电技术已经有了一些应用,比如探测海洋中的船只(还记得被困在苏伊士运河的长赐号吗?),洪水的影响,毁林,非法采矿,铁路轨道监测等等。

虽然大多数可用的卫星数据都是开源的,并且免费用于研究,但一些商业程序,如 Maxar Technologies 的 WorldView,可以提供非常高分辨率的卫星图像,只需支付少量费用即可购买。

新型垃圾填埋场数据集的规格

在这一节中,我将讨论选择一组卫星图像来创建数据集的动机和过程。此外,我还讨论了为图像创建精确注释的方法。

创建数据集的过程

任何机器学习管道的最大和最关键的挑战是选择正确的数据集。所选数据集的可用性、大小和质量决定了机器学习架构以及最终用于解决手头问题的进一步技术和超参数。

对于这个项目,在没有任何公开可用的垃圾填埋场检测数据集的情况下,我不得不创建自己的数据集。虽然有几个可用的数据集,如 UC Merced 土地利用数据集[1]、DeepSat [2]、Urban Atlas [3]、BigEarthNet [4],但这些数据集主要提供关于土地、田地、森林等一般土地利用分类类别的广泛信息。BigEarthNet 确实为垃圾场提供了一个类,但是由于数据集是从低分辨率 Sentinel 卫星影像(参见上表)中创建的,因此不足以检测可能小于一米的小型垃圾填埋场。因此,该项目需要一个专门针对垃圾填埋场的定制数据集。值得注意的是,在项目的第一阶段,我没有根据废物的类型对垃圾填埋场进行分类。也就是说,为数据集创建选择的垃圾填埋场是废物不可知的。基于废物类型的分类可被视为该项目的未来改进。

最终,我决定使用空间分辨率分别为 46 厘米、30 厘米和 41 厘米的 WorldView-2 (WV-2)、WorldView-3 (WV-3)和 GeoEye-1 (GE-1)卫星程序的超高分辨率(VHR)光学图像。这些卫星节目的相应光谱分辨率分别为 8 个多光谱(ms)波段、8 个 MS 波段和 4 个 MS 波段,此外还有 1 个全色波段。此外,这些程序的时间分辨率在 1-5 天之间。这些参数使得从这些图像中创建的数据集非常适合从卫星图像中监测和检测垃圾填埋场。

与哨兵图像不同,这些 VHR 图像不是免费的。然而,欧洲航天局(欧空局)允许出于研究目的免费使用有限的储存库。一旦我最终确定了我将要使用的卫星程序,我就向欧空局索要图像拼图。为了获得这些图像拼图,我确定了欧洲、亚洲和南美洲的 13 个主要已知垃圾填埋场,并将它们发送给欧空局,欧空局反过来又让我获得了这些垃圾填埋场的非常高分辨率的图像。

欧空局通常以一组 GeoTIFF 文件的形式提供图像——1 幅黑白全色图像具有非常高的空间分辨率,例如 WV-3 为 30 厘米,但光谱分辨率较低(1 个光谱带), 1 幅多光谱图像具有高光谱分辨率,例如 WV-3 为 8 个光谱带,但空间分辨率较低,例如 WV-3 为 1.24 米。全色锐化是一种技术,其中全色和多光谱图像可以融合在一起,以获得具有高光谱和高空间分辨率的图像。WV-3 图像的空间分辨率为 30 厘米,光谱分辨率为 8 个波段。因此,全色锐化是一种两全其美的方法。虽然像插值这样的传统方法普遍用于全色锐化,但最近深度学习已被用于实现高分辨率多光谱图像。我对垃圾填埋场数据集执行全色锐化,以获得高分辨率的多光谱数据集。为了做到这一点,我在 QGIS [6]中使用了 Orfeo 工具箱[5]。因此,我实际上创建了 2 个垃圾填埋场数据集—一个仅包含多光谱图像,另一个包含全色锐化图像。

塞尔维亚 Vinca 的垃圾填埋场。a .)具有低空间分辨率但高光谱分辨率的多光谱图像。b)具有高空间分辨率但低光谱分辨率的全色图像。c)具有高空间和光谱分辨率的全色锐化图像。作者图片

下表提供了泛锐化前后这些地点的清单和欧空局提供的图像大小:

作者图片

一些用黑色标记垃圾填埋区的图片:

欧空局在印度和匈牙利提供的图片中用黑色标出的垃圾填埋场位置。可以看出,在整个图像区块中,对应于垃圾填埋场的像素数量远小于不包含垃圾填埋场信息的像素数量。图片作者。

欧空局提供的图像块的尺寸非常大。为此,我将这些拼贴分成 512x512 像素的小块。下表列出了为每个多光谱和全色锐化数据集获取的面片数。

数据集图像补丁率。作者图片

可以看出,尽管产生的斑块总数相当高,但具有填埋像素的斑块数量相当低,如下图所示。这导致了数据集中的不平衡。从下面绘制的比率可以推断,数据集是不平衡的,具有垃圾填埋像素的斑块较少。为此,为了训练模型,只考虑那些其中具有填埋像素的小块。这是因为即使是具有填埋像素的斑块,其背景像素也比填埋像素多。

显示多光谱和高分辨率全色锐化数据集的 512x512 斑块和带有垃圾填埋像素的斑块总数比率的图。作者图片

因此,创建的数据集由 55 个多光谱和 242 个 512x512 像素的全色锐化斑块组成,每个斑块都具有垃圾填埋信息,可以根据机器学习工程师的需要进一步划分为训练集、测试集和验证集,以训练他们的模型。

创建高度精确标签的过程

一旦图像补丁被创建,下一个最重要的任务是准确地标记垃圾填埋场,以便它可以作为地面真实数据。因为手头的任务是通过执行语义分割来检测垃圾填埋场,所以我在 QGIS 的帮助下创建了分割遮罩[6]。

准确的标签几乎和数据质量一样重要,甚至更重要。在任何机器学习流水线中,垃圾进就是垃圾出。因此,如果您的训练数据或相应的标签不正确,输出就不可能是理想的。即使是最好的架构也无法弥补不良数据。因此,创建准确的标签对这个项目至关重要。为此,我遵循了两步策略——目视检查和计算图像斑块的植被指数。

目视检查和 VIs 是一些传统的方法,已经在文献中用于垃圾填埋检测。但是它们已经被证明是不可靠的,同时也是乏味和耗时的,这就是为什么我们试图应用机器学习来找到问题的解决方案。但是,当我们试图创建地面真实标签时,传统的视觉检查和 VIs 方法恰好是一个相当有用的工具。以下小节讨论如何使用这些方法来创建标签:

外观检验

这是可用于标记的最简单的方法。在创建标签时,通过目视检查来识别对应于垃圾填埋场的区域是第一步。这种方法有助于排除不符合垃圾填埋场条件的区域,因为垃圾填埋场的位置是由我提供的,因此我知道它们的确切地理位置。

通过目视检查,我可以识别匈牙利 Erd 的垃圾填埋场,如下图中黑色矩形所示。

匈牙利 Erd 的垃圾填埋场。作者图片

植被指数(六)

虽然可以通过已知的地理位置来识别匈牙利 Erd 的垃圾填埋场,但不足以创建整个区域的分段标签。如果你仔细观察上图中用实体关系图标出的填埋区,你会发现填埋区内的一些区域被植被覆盖。同样,其他一些垃圾填埋场内也有建筑物或其他结构,不能归类为垃圾填埋场。将它们标记或标注为垃圾填埋场会混淆神经网络,导致不正确的预测。

为了更好地了解垃圾填埋区内的景观,并排除将植被区域标记为垃圾填埋区的可能性,我利用 VIs 进行了分析,这有助于我创建准确的标签。

从遥感图像获得的植被指数(VIs)是一种评估植被覆盖、健康和植被生长动态的简单方法。这些指数利用可见光辐射,特别是可见和不可见光谱中的绿色光谱区域来获得植被表面的量化。土壤、杂草和感兴趣的植物的混合组合使得简单 VI 的计算成为非常困难的任务。有许多可视信息提供有关植被覆盖的有用信息。其中包括 NDVI、SAVI 和 MSAVI。我在 QGIS [6]的帮助下计算了这些 VI,以深入了解垃圾填埋区。VIs 的详细描述和计算超出了本文的范围。

匈牙利 Erd 填埋场的 NDVI 计算如下所示。图像最右侧的 NDVI 等级代表 NDVI 等级,基本上表示 NDVI 的绿色越深(或 NDVI 值越大),景观中的植被越健康,反之亦然。从垃圾填埋区的 NDVI 地图中可以看出,并非整个区域都可以标记为垃圾填埋场,因为一些以绿色显示的区域代表垃圾填埋场内的植被。将这些区域标记为垃圾像素会导致机器学习模型的错误输出。

匈牙利 Erd 的垃圾填埋场以及相应的 NDVI 值和比例尺。作者图片

通过目视检查、计算和分析 VIs,我可以创建精确的分段遮罩。下图中显示了其中的一些,上面覆盖了垃圾填埋场斑块及其对应的遮罩。

带有重叠分段掩膜的垃圾填埋场块被用作地面实况。作者图片

如前所述,分段掩码是在 QGIS 的帮助下创建的。在数据集文件夹中,掩膜存储为 GeoJSON 文件,该文件由构成掩膜的面的每条边的坐标列表组成。每个垃圾填埋场都有一个相应的 GeoJSON 文件。修补程序名称以及相应的 GeoJSON 掩膜文件已在. csv 文件中列出。这个。csv 文件可用于在实施期间由数据加载器加载填埋补丁和相应的掩膜。

探测匈牙利的垃圾填埋场——一些结果

将用于语义分割的监督深度学习算法应用于来自垃圾填埋场数据集的验证集提供了一些有用的结果。深度学习模型成功地识别了几米大小的垃圾填埋场,这对于监控和检测非法垃圾填埋场非常有用,因为它们通常分布在较小的区域。垃圾填埋场的部分分割结果如下所示。

作者图片

作者图片

深度学习架构的规范以及相关参数和结果将在未来的文章中分享。然而,在这里可以找到一个简短的技术概述:https://www . euspace imaging . com/combining-vhr-satellite-imagery-and-deep-learning-to-detect-fills/

请求访问数据集的进程

本文的目的是提出一种新的垃圾填埋场数据集,由高质量的 VHR 图像和精确的分割模板组成。此外,我想讨论和分享我在选择适当的数据和工作流程的整个过程中的经验,以及我自己为这些数据创建注释或标签的想法。我希望新的机器学习工程师会发现这很有用。

将来,我会把数据集放在一个服务器上,从那里可以直接下载。但是,目前,如果您想要访问数据集,请遵循以下步骤:

  1. 在此位置启动项目回购:https://github . com/AnupamaRajkumar/填埋场检测 _SemanticSegmentation 。这使我能够跟踪请求访问数据集的人
  2. 在 anupamar228@gmail.com 给我写一封电子邮件,提供你的电子邮件地址,链接到你的 DropBox,我会让你访问目前存储在我个人 DropBox 中的知识库。

鸣谢和引用信息

我要感谢欧空局为研究目的免费提供 VHR 图像。他们有一个巨大的各种类型和规格的卫星图像库,这对地球观测研究是一个福音。

欧空局出于研究目的将数据集开源。但是,它受到版权法的约束。如果使用数据集中的图像,必须包括“DigitalGlobe,Inc. 2021,数据由欧洲航天局提供”,以避免侵犯版权。我已经把这个信息包含在数据集文件夹的 LicenseInfo.txt 里了,一定要用。

如果您决定使用该数据集中的图像,请不要忘记引用数据集文件夹中 ReadMe.txt 中提到的内容。

参考

[1]杨熠和肖恩·纽萨姆,“土地利用分类的视觉词汇包和空间扩展”,美国计算机学会地理信息系统进展国际会议,2010 年,http://weegee.vision.ucmerced.edu/datasets/landuse.html

[2] Saikat Basu、Sangram Ganguly、Supratik Mukhopadhyay、Robert DiBiano、Manohar Karki 和 Ramakrishna Nemani。deep sat——卫星图像学习框架,2015 年。

[3]城市地图集。https://land.copernicus.eu/local/urban-atlas.访问时间:2021–11–14。

[4] Gencer Sumbul,Marcela Charfuelan,Begüm 德米尔和 Volker Markl。Bigearthnet:遥感图像理解的大规模基准档案。在 IGARSS 2019–2019 IEEE 国际地球科学和遥感研讨会上,第 5901–5904 页,2019 年。

[5] Orfeo 工具箱。【https://www.orfeo-toolbox.org/CookBook/】T4Applications/app _ pan sharpening . html 访问时间:2021–11–15。

QGIS 开发人员指南。https://docs.qgis.org/3.16/en/docs/developers _ guide/index . html 访问时间:2021–11–15。

使用 PyOD 在 Python 中引入异常/离群点检测🔥

原文:https://towardsdatascience.com/introducing-anomaly-outlier-detection-in-python-with-pyod-40afcccee9ff?source=collection_archive---------4-----------------------

你认为那些讨厌的局外人能躲得过你吗?

约翰·施诺布里奇在 Unsplash 上的照片

您的旅程概述

  1. 设置舞台
  2. 什么是异常/异常值检测?
  3. 介绍 PyOD
  4. 熟悉数据
  5. 用于数据清洗的异常检测
  6. 用于预测的异常检测
  7. 包装

1 —搭建舞台

近年来,异常检测在机器学习社区变得更加流行。尽管如此,在异常检测上的资源肯定比经典的机器学习算法要少。因此,学习异常检测可能会比想象中更棘手。从概念的角度来看,异常检测实际上非常简单!

这篇博文的目的是给你一个异常/异常值检测的快速介绍。具体来说,我将向您展示如何使用包 PyOD — Python 异常检测在 Python 中实现异常检测。通过这种方式,您不仅会了解什么是异常/异常值检测,还会了解如何在 Python 中实现异常检测。

好消息是 PyOD 很容易应用——尤其是如果你已经有了使用 Scikit-Learn 的经验。事实上,PyOD 包试图与 Scikit-Learn API 接口非常相似。

先决条件:你应该对 Python 和熊猫有一些基本的熟悉。然而,不需要异常检测的知识😃

2 —什么是异常/异常值检测?

异常检测有许多名称;异常检测异常分析异常分析新奇检测。来自维基百科的简明描述如下描述了异常检测:

异常检测 是对罕见项目、事件或观察结果的识别,这些项目、事件或观察结果因与大多数数据显著不同而引起怀疑。

让我们试着解开以上陈述。假设您有一个由许多观察值组成的数据集。异常检测的目标是识别明显不同于其他观测的观测。你为什么想这么做?有两个主要原因:

用例 1 —数据清理

清理数据时,有时最好删除异常,因为它们歪曲了数据。让我们用一个具体的例子来说明这一点:假设你做了一个调查,问了一些关于受访者最喜欢的猫品种的问题😺

米哈伊尔·瓦西里耶夫Unsplash 上拍摄

您首先将调查交给 100 个人,每个人完成调查。现在,您需要估计参加调查所需的平均时间。为什么?您希望有 10,000 多人参加调查。指出新受访者的调查大概需要多长时间是很专业的。即使猫很牛逼,人也很忙!

假设您从前 100 个人那里获得了以下结果:

  • 3 分钟— 57 名受访者
  • 4 分钟— 33 名受访者
  • 5 分钟— 6 名受访者
  • 6 分钟— 3 名受访者
  • 480 分钟— 1 名受访者

最后一个是怎么回事?480 分钟就是 8 小时!经进一步检查,你发现被调查人在晚上 23:58 开始调查,然后从 00:00 一直站到 07:56。然后从 07:56 到 07:58 结束。你能看到发生了什么吗?

明明一个人开始调查,然后睡觉,然后早上起来就完成了调查。如果您保留这一结果,那么完成调查的平均时间将是

平均值=(3 * 57+4 * 33+5 * 6+6 * 3+1 * 480)/100 = 8.31

然而,说调查大约需要 8 分钟是不准确的。花了那么长时间的唯一原因是因为一个困倦的回答者😪

更准确的做法是把那个人从记录中去掉

平均值= (3 * 57 + 4 * 33 + 5 * 6 + 6 * 3)/99 = 3.54

为简单起见,调查可以写成这样的句子:调查的平均完成时间在 3 到 4 分钟之间。

这里,您已经手动删除了一个异常值,以清理数据,从而更好地代表现实。异常检测是实现自动检测异常值的算法。

注意:在上面的例子中,您已经删除了一个异常值,以更好地匹配调查长度与现实。异常检测不应该被用来人为地让一个产品看起来比它实际上更好。应该仔细考虑使用异常检测进行数据清理在道德上是否合适。

用例 2 —预测

在其他应用中,异常本身就是关注点。例如网络入侵、银行欺诈和某些结构缺陷。在这些应用中,异常代表了值得进一步研究的东西。

  • 网络入侵 —网络数据的异常可能表明某种网络攻击已经发生。
  • 银行欺诈 —交易数据的异常可能表明欺诈或可疑行为。
  • 结构缺陷 —异常可能表明您的硬件有问题。虽然在这种情况下通常可以使用更传统的监控软件,但是异常检测可以发现更奇怪的缺陷。

警告:在某些情况下,比如银行欺诈,并不总是单笔交易引起怀疑。应该考虑的是在上下文中看到的多次交易的频率和数量。为了解决这个问题,应该对数据进行适当的汇总。这超出了本博客的范围,但是您应该知道。

3 —介绍 PyOD

让我们描述一下帮助您进行异常检测的 Python 包 PyOD 。用 PyOD 文档的话说:

PyOD 是一个全面且可扩展的 Python 工具包,用于检测多元数据中的无关对象

简而言之,PyOD 为您提供了一系列执行异常检测的模型。一些值得一提的亮点是:

  • PyOD 包括 30 多种不同的算法。他们中的一些是经典作品(如 LOF),而另一些则是新晋作品(如科普德)。参见支持型号的完整列表
  • PyOD 通过使用 Numba 的 jit-decorator 优化了它的代码。如果你对此感兴趣,我已经在 Numba 上写了一篇博文。
  • PyOD 有统一的 API。因此,如果您熟悉 PyOD 中的一些模型,那么您可以轻松地学习其余的模型。我建议在你写完这篇博客后,看看 PyOD API 备忘单

如果您正在使用 PIP,那么您可以使用以下命令安装 PyOD:

pip install pyod

如果您之前已经安装了 PyOD,请确保使用 pip 命令更新它:

pip install --upgrade pyod

如果您使用的是 Conda 软件包管理器,那么您可以运行以下命令:

conda install -c conda-forge pyod

在这篇博文中,我将演示两种异常检测算法:KNN 和 LOC。你可能以前听说过 KNN(K-最近邻),而 LOC(本地离群因子)可能对你来说并不熟悉。让我们先来看看你将使用⚡️的数据

4 —熟悉数据

我们将使用经典的泰坦尼克号数据集。要将数据集加载到 Pandas 中,只需运行下面的代码:

import pandas as pd
titanic = pd.read_csv(
"[https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv](https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv)"
)

要检查数据集的第一行,使用head()方法:

titanic.head()

泰坦尼克号数据帧的前 5 行。

如您所见,有代表性别、年龄、票价、乘客级别、机票等的列。为简单起见,您将只使用以下四列:

# Selecting only the columns Survived, Pclass, Fare, and Sex
partial_titanic = titanic[["Survived", "Pclass", "Fare", "Sex"]]

partial_titanic中没有缺失值。然而,列Sex由字符串值malefemale组成。为了能够进行异常检测,您需要数值。您可以使用代码将这个二进制分类变量转换为值 0 和 1:

# Change the categorical value Sex to numeric values
partial_titanic["Sex"] = partial_titanic["Sex"].map({
"male": 0,
"female": 1
})

现在您已经准备好进行异常检测了😃

5 —用于数据清理的异常检测

现在让我们使用异常检测来清理您在上一节中创建的数据集partial_titanic。您将使用 KNN 模型来完成这项工作。KNN 模型检查数据并寻找远离其他数据点的数据点(行)。首先,您需要导入 KNN 模型,如下所示:

# Import the KNN
from pyod.models.knn import KNN

我们从提出一个 KNN 模型开始:

# Initiate a KNN model
KNN_model = KNN()

对于用于数据清理的异常检测方法,您可以对整个数据集进行如下拟合

# Fit the model to the whole dataset
KNN_model.fit(partial_titanic)**Output:**
KNN(algorithm='auto', contamination=0.1, leaf_size=30, method='largest', metric='minkowski', metric_params=None, n_jobs=1, n_neighbors=5, p=2, radius=1.0)

当运行上面的代码时,你会打印出很多默认值(例如contamination=0.1)。如果需要,可以进行调整。运行模型后,您可以访问两种类型的输出:

  • 标签:通过运行KNN_model.labels_,您可以找到观察值是否为异常值的二进制标签。数字0表示正常观察值,而数字1表示异常值。
  • 决策分数:通过运行KNN_model.decision_scores_,您可以得到某件事情有多异常的原始分数。这些值的范围从0到更高。较高的异常值表示数据点更像是异常值。

让我们来看看训练模型的标签:

# Find the labels
outlier_labels = KNN_model.labels_# Find the number of outliers
number_of_outliers = len(outlier_labels[outlier_labels == 1])
print(number_of_outliers)**Output:**
88

对于一个有 891 名乘客的数据集,有 88 个异常值是相当高的。为了减少这种情况,您可以将 KNN 模型中的参数contamination指定得更低。contamination表示异常值数据点的百分比。假设污染仅仅发生在1%:

# Initiate a KNN model
KNN_model = KNN(contamination=0.01)# Fit the model to the whole dataset
KNN_model.fit(partial_titanic)# Find the labels
outlier_labels = KNN_model.labels_# Find the number of outliers
number_of_outliers = len(outlier_labels[outlier_labels == 1])
print(number_of_outliers)**Output:** 
9

现在只有9离群!您可以查看它们:

# Finding the outlier passengers
outliers = partial_titanic.iloc[outlier_labels == 1]

如果你检查outliers变量,你会得到下表:

离群乘客

如果你看看上面的乘客,KNN 模型会发现他们的票价高得令人难以置信。所有乘客的平均票价很容易在熊猫身上找到:

# Average fare price
round(partial_titanic["Fare"].mean(), 3)**Output:**
32.204

KNN 算法已经成功地发现了 9 名在票价意义上是异常值的乘客。KNN 模型有许多可选参数供您选择,以满足您的特定需求🔥

如果您觉得异常值不能代表数据的总体感觉,那么现在可以从数据中删除这些异常值。如前所述,您应该仔细考虑用于数据清理的异常检测是否适合您的问题。

6 —用于预测的异常检测

在上一节中,您看到了用于数据清理的异常检测。在本节中,您将在预测的异常检测处取一个峰值。您将根据现有数据训练一个模型,然后使用该模型来预测新数据是否为异常值。

假设有谣言说沃森太太也乘坐了泰坦尼克号,但她的死亡从未被记录。根据传闻,沃森太太是一位富有的女士,她花了 1000 美元乘坐泰坦尼克号在一个非常高级的套房里旅行。

卢克·布拉斯韦尔在 Unsplash 上拍摄的照片

异常检测不能肯定地说谣言是真是假。然而,它可以根据其他乘客的信息来判断沃森太太是否是异常。如果她是一个异常,谣言应该半信半疑。

让我们用 PyOD 库中的另一个模型来测试 Watson 夫人的存在性;局部异常值因子(LOF) 。LOF 模型通过将数据点的局部密度与其相邻数据点的局部密度进行比较来测试数据点是否为异常值。关于这种方法的更多信息,你可以查看它的维基百科页面。

让我们开始编码吧!首先建立一个局部异常因素模型:

# Import the LOF
from pyod.models.lof import LOF# Initiate a LOF model
LOF_model = LOF()# Train the model on the Titanic data
LOF_model.fit(partial_titanic)

请注意,使用 LOF 模型与使用 KNN 模型是多么相似。

现在你可以把沃森太太表示成一个数据点:

# Represent Mrs. Watson as a data point
mrs_watson = [[0, 1, 1000, 1]]

mrs_watson中的值代表她的存活(0代表未存活)、乘客等级(1代表头等舱)、票价(1000$代表票价)、性别(1代表女性)。LOF 模型需要 2D 阵列,因此这就是在mrs_watson中增加一对括号[]的原因。

我们现在使用predict()方法来预测沃森太太是否是异常值:

outlier = LOF_model.predict(mrs_watson)
print(outlier)**Output:**
1

1表示沃森太太是异常值。这应该让你怀疑关于沃森太太的谣言是假的😮

7—总结

我已经向您展示了如何用 KNN 和 LOF 两种算法实现异常检测。正如你可能会怀疑的那样,PyOD 中有更多的算法可以使用。

异常检测对于清理数据和预测异常值都很重要。手边的应用程序应该确定是否需要应用异常检测。如果您计划在 Python 中应用异常检测,那么 PyOD 是一个可靠的选择。

喜欢我写的?查看我的其他帖子,了解更多 Python 内容:

如果你对数据科学、编程或任何介于两者之间的东西感兴趣,那么请随意在 LinkedIn 上添加我,并向✋问好

面向数据科学的 Azure Databricks 简介

原文:https://towardsdatascience.com/introducing-azure-databricks-for-data-science-547e2784fa49?source=collection_archive---------19-----------------------

了解 Azure Databricks 服务功能对于大数据处理和实施机器学习解决方案的重要性。

约翰·马特丘克在 Unsplash 上拍摄的照片

介绍

这篇文章将简要描述 Azure Databricks 托管服务的丰富特性及其功能。作为一名机器学习工程师,如果你配备了这个工具库,那么它将把你的开发技能带到新的高度。

让我们首先了解一下微软 Azure 的 Databricks 即服务产品是什么。

Azure Databricks 是微软 Azure 提供的全托管平台服务,简而言之,它是一个大数据和机器学习平台。它融合了 Apache Spark 和微软团队的共同努力。该服务是大数据处理和机器学习的单一平台。

Azure Databricks 使您作为数据工程师能够运行大规模 Spark 工作负载,因为 Azure 的底层大规模可扩展计算能力,因此它们可以通过自动扩展、缓存、索引和查询优化在云中匹配无与伦比的性能和成本效益。

本文假设您已经熟悉了 Spark 框架,并且掌握了 PySpark 知识。

https://www.linkedin.com/in/p-jainani/

Azure 数据块

Databricks 由 Apache Spark、Delta Lake 和 MLflow & Spark 创建,这是一个统一的处理引擎,可以使用 SQL、机器学习、图形处理或实时流分析来分析大数据。

Azure Databricks 架构 -自定义图像

Azure Databricks 架构的核心是 Databricks 运行时引擎,它针对优化的数据访问层引擎优化了 Spark 产品、Delta Lake 和 Databricks I/O。这一核心引擎为数据科学工作负载提供了强大的处理能力。它还提供了与不同 Azure 数据服务的原生集成能力,如 Azure Data Factory 和 Synapse Analytics。它还提供了各种 ML 运行时环境,比如tensor flow&py torch。笔记本可以与 MLFlow + Azure 机器学习服务集成。

引擎盖下——它的火花

Azure Databricks 服务是一个面向笔记本的 Apache Spark 即服务工作环境。它为大规模数据处理和机器学习提供了分析引擎。真正意义上,它可以处理大容量、高速度、多种多样的大数据。Apache Spark 集群是一组计算机,它们被视为一台计算机,处理从笔记本发出的命令的执行。这个集群有一个驱动来将任务分配给它的执行器,并通过可用的插槽来处理它们。此外,驱动程序将任务分配给执行程序来执行任务,并对其数据进行划分,该任务被划分为多个阶段并按顺序流执行。作业每个阶段的结果都会发送给驱动程序进行整合。这就是 Spark 处理架构的要点。

Spark Cluster:逻辑架构 —来源微软文档

作为一名 Azure Databricks 工程师,你只需要关注:

  • 我的数据被划分成多少个分区。
  • 我拥有的用于并行执行的槽数。
  • 我触发了多少工作?
  • 最后是这些工作被划分的阶段。

Azure Databricks 正在运行

假设您已经在订阅中创建了 Azure Databricks 工作区。

读取数据

作为开发人员,它使您能够从不同的来源提取任何格式的数据,CSV、JSON 或 parquet,并在并行、分布式和可伸缩的 spark 环境中处理它们。为此,它使用 scala、R 或 python APIs。

下面的代码片段使用 Spark 会话来创建一个使用read()函数的数据帧。它链接csv()函数从 CSV 文件中读取数据。

bostonDF = (spark.read
  .option("HEADER", True)
  .option("inferSchema", True)
  .csv("/mnt/training/bostonhousing/bostonhousing/bostonhousing.csv")
)display(bostonDF)

上一段代码的输出

添加新功能

如果作为一名开发人员,你是 Spark 的新手,那么你需要知道,Spark 不同于许多其他机器学习框架,因为我们在包含我们所有特征的向量的单个列上训练我们的模型。通过创建一个名为features的列来准备数据,该列包含平均房间数、犯罪率和贫困率。这是通过使用 PySpark 的 VectorAssembler 对象汇编器创建新的列特性来实现的,如下面的代码片段所示:

from pyspark.ml.feature import VectorAssemblerfeatureCols = ["indus", "age", "dis"]
assembler = VectorAssembler(inputCols=featureCols, outputCol="newFeatures")bostonFeaturizedDF2 = assembler.transform(bostonDF)display(bostonFeaturizedDF2)

上一段代码的输出

参见ml lib 文档了解更多关于features栏中稀疏向量符号的,这将在特征章节中详细介绍。

火车模型

一旦数据准备好了,我们就可以训练我们的模型了,这是通过下面的代码完成的,这是一个简单的线性回归模型:

from pyspark.ml.regression import LinearRegressionlrNewFeatures = LinearRegression(labelCol="medv", featuresCol="newFeatures")lrModelNew = lrNewFeatures.fit(bostonFeaturizedDF2)

获得预测

模型定型后,将按如下方式获取预测:

from pyspark.ml.linalg import Vectorsdata = [(Vectors.dense([11., 68., 4.]), ),
        (Vectors.dense([6., 35., 2.]), ),
        (Vectors.dense([19., 74., 8.]), )]
newDataDF = spark.createDataFrame(data, ["newFeatures"])
predictionsDF = lrModelNew.transform(newDataDF)
display(predictionsDF) 

lrModelNew是一个训练有素的估计器,我们可以使用它的.transform()方法转换数据,因此它也计算预测值。

上一段代码的输出

结论

简要描述 Azure Databricks 服务的本质、架构及其核心 Spark 引擎功能。我只是通过实现一个虚拟的 ML 模型给出了一个蹩脚的例子,试图触及表面。在随后的文章中,我会谈到 Azure Databricks 服务的另一个方面。

参考

[1]微软文档| Azure Databricks 服务
【2】Azure data bricks |入门
【3】Azure data bricks 笔记本

LinkedIn 上与我联系,进一步讨论

https://www.linkedin.com/in/p-jainani/

使用 Python 引入资本预算工具

原文:https://towardsdatascience.com/introducing-capital-budgeting-tools-with-python-e369ef23d5ac?source=collection_archive---------18-----------------------

资本预算在任何业务中都不是一个随机的猜测。在本文中,我们将使用 Python 来度量项目评估的 NPV 和 IRR。

凯利·西克玛在 Unsplash 上的照片

资本预算 是一个深思熟虑的计划过程,以确定一个或多个潜在投资项目是否值得通过公司的资本化结构获得现金资金。资本预算的最终目的是使决策者能够明智地选择能够为公司增值的项目,从而使股东受益。

本文将介绍两种最常用的资本预算方法。它们是:

  1. 净现值
  2. 内部收益率

净现值和内含报酬率在许多企业中被广泛使用,它们是相互关联的。我们将使用Python Numpy-Financial package来处理 NPV 和 IRR 所需的所有计算。

必备 Python 库

  1. 货币金融——https://numpy.org/numpy-financial/

开源代码库

本文中的原始完整源代码可以在我的 Github Repo 上获得。如果你想用它来关注我的文章,请随意下载它( NPV & IRR.ipynb )。

1.净现值

假设我们有一个项目,建议初始投资资本为 100,000 美元。我们预计该项目将在未来五年产生 10000 美元、18000 美元、25000 美元、32000 美元、35000 美元的收入。

作者准备的图像

这里的问题是五年后我们能从这个项目中获得多少利润?一个简单的计算可能只是简单地将第一年到第五年的所有收入相加,然后减去初始资本。

作者准备的图像

看起来这个项目是有利可图的,五年后我们可以获得 20000 美元。然而,简单计算的一个明显问题是,它没有考虑 贴现率

未来五年我们未来现金流的现值并不是恒定的,事实上,该值将逐年贴现。未来现金流贴现有两个主要原因:

  1. 投资风险。并非所有项目都有相同的风险水平。风险较高的项目获得现金流的概率往往较低。因此,对于风险较高的项目,应采用较高的贴现率。
  2. 金钱的时间价值。由于通货膨胀、利率和机会成本,钱越早收到越值钱。

我们需要一种更好的方法来评估一个项目的盈利能力,这就是如何将净现值(NPV) 考虑进去的。

净现值是与项目相关的所有现金流的现值之和。(来源:流明)

NPV 考虑了未来现金流的贴现率。净现值的公式如下:

作者准备的图像

我们可以使用 Python Numpy Financial npv 函数来计算上面项目示例的 npv。让我们假设贴现率是每年 5%。

第 1–2 行:导入库

第 4–5 行:将贴现率设为 5%,并创建一个未来现金流列表。列表中的第一项是初始投资金额,应该用负号表示。

第 6 行:使用 Numpy Financial npv 函数计算净现值。

作者准备的图像

结果显示净现值仅为 $1196.18 ,远低于$20000(不考虑折现率的现金流)。虽然该项目仍然有利可图,但由于利润相对较小,它可能仍然不是一个好的投资选择。

2。内部收益率

从上面的例子中,我们看到净现值只有 1196.18 美元,贴现率为 5%。如果我们将贴现率略微提高到 6%,我们可以预测 NPV 可能会变为负值。事实上,有一个正式的方法来衡量项目现金流的弹性。这种方法被称为内部收益率

IRR 是一种衡量使项目 NPV 为零的贴现率的方法。(来源: CFI )

内部收益率的公式如下:

作者准备的图像

以上面的例子为例,我们可以使用 Python Numpy 财务 irr 函数来计算项目的 IRR。

第 1 行:创建一个未来现金流的列表。列表中的第一项是初始投资金额,应该用负号表示。

第 2 行:使用 Numpy Financial irr 函数计算内部收益率。

作者准备的图像

由此得出的内部收益率为 5.36% 。这意味着当前项目的现金流弹性相对较低,因此可视为高风险项目。IRR 越低,项目的风险就越高。

3.重述 NPV 和 IRR

假设我们有第二个项目,预计未来五年的收入如下:

作者准备的图像

我们假设第二个项目的贴现率也是 5%。现在,我们将使用相同的 Python Numpy-Financial npv 和 irr 函数来计算第二个项目的 NPV 和 IRR。

作者准备的图像

净现值为47311.32 美元,内部收益率为 17.72% 。显然,第二个项目有更大的回报和更高的现金流弹性来抵御风险。通过比较第一个和第二个项目,第二个应该是一个更好的选择,可能会给所有股东带来理想的利润。

结论

在这篇文章中,我们已经经历了两个最常见的资本预算工具,即。净现值和内部收益率。事实上,它们是许多与净现值和内含报酬率一起使用的方法,如回收期、会计比率等。

实际上,没有一种资本预算工具能够保证项目盈利,因为所有的方法都旨在根据当前可用的信息和假设提供最佳预测。然而,它们绝对是有用的工具,可以帮助我们做出比随机猜测更合理的决定。

我希望你喜欢阅读这篇文章。

参考

  1. https://corporatefinanceinstitute . com/resources/knowledge/finance/internal-rate-return-IRR/
  2. https://courses . lumen learning . com/unlimited-finance/chapter/net-present-value/
  3. https://www.investopedia.com/terms/d/dcf.asp

介绍 Daeploy

原文:https://towardsdatascience.com/introducing-daeploy-the-tool-to-let-data-scientists-be-data-scientists-5e6ba3e8c6f4?source=collection_archive---------34-----------------------

让数据科学家成为数据科学家的工具!

Viking Analytics 是一家位于哥德堡的瑞典公司,提供预测性维护和智能状态监控解决方案。 Daeploy 是 4 年多来为行业提供机器学习解决方案的巅峰之作。这就是我们旅行和部署的故事!

一个 hello world 服务,用 23 行代码实现了 REST API、配置和通知!(作者创作)

面向工业 4.0 客户端的典型机器学习项目

客户经常带着他们希望通过利用他们的数据和机器学习的力量来缓解的痛点来找我们。一个典型的项目通常从发现阶段开始,在这个阶段,我们一起查看客户数据以理解数据并评估找到解决方案的可能性。

如果初始数据准备情况分析显示出潜力,则概念验证阶段开始,重点是证明解决方案的可行性。这一步选择的工具通常是 Jupyter 笔记本。

成功的概念验证之后是最小可行产品(MVP)。这就是挑战的开始,因为从数据到应用程序的项目是一项要求很高的任务,需要跨越多个技能集。虽然从数据到概念验证的过程通常是机器学习的过程,但 MVP 阶段需要广泛的其他技能,如软件开发和 DevOps。

从数据到应用的旅程(由作者创作)

理想情况下,一个人需要一个由数据科学家、软件开发人员、DevOps 工程师组成的团队,如果有必要,还需要 UI/UX 来成功完成应用程序之旅。然而,在实践中,数据科学家或 ML 工程师的任务是将他们的模型和算法转化为应用程序,这是很常见的。

我们的使命:让数据科学家成为数据科学家!

我们希望数据科学家能够专注于他们喜欢做的事情:处理和理解数据、模型训练、模型评估、模型优化,并在产品化和部署他们的解决方案上花费尽可能少的时间和精力。我们确定了需要解决的两个关键问题:

1.添加功能

正如“机器学习系统中隐藏的技术债务”这篇著名的文章[1]所示,ML 代码通常是 ML 项目的一小部分。要使 ML 代码能够可靠地传递其值,需要许多功能。

受“机器学习系统中隐藏的技术债务”启发的图片1

世界各地的数据科学家正花费数天甚至数周的时间向他们的模型添加功能,比如 REST API、配置和通知。

为了解决这个问题,我们开发了 Daeploy 软件开发工具包(SDK ),它提供了大量现成的功能。

2.部署

软件部署是将代码转换为在主机上运行的应用程序并使其可供使用的过程。这通常是 DevOps 工程师的领域。要成功部署解决方案,需要理解诸如访问、安全性和身份验证、代理、SSL 证书、CI/CD 管道、代码容器化、服务管理等概念。

潜在部署目标的多样性增加了 ML 部署的复杂性。目标可以在云上或内部。要在云上部署,必须熟悉各种云提供商、他们的术语以及他们的用户界面。内部部署取决于客户 IT 及其托管软件解决方案的准备情况。

我们利用 Daeploy manager 来解决部署难题,Daeploy manager 是一个 docker 映像,运行在您应用程序的目标上。目标可以是任何符合以下条件的机器:

  1. 能够运行 Docker
  2. 允许访问 Docker 守护程序。

如果满足上述要求,目标可以是任何具有任何操作系统的机器。它可以是你的个人电脑,工厂里的服务器,云中的虚拟机,或者是树莓 Pi。Daeploy manager 提供安全性和身份验证,并提供一个安全的 API 来部署您的代码、从运行的服务中提取日志、获取通知等等。

让我们仔细看看 Daeploy SDK 和 Daeploy manager 的一些特性。

Daeploy SDK

当编写应该作为服务运行的代码时,使用 Daeploy SDK。它作为 python 包安装在 Python 环境中,并努力使创建这些服务的过程尽可能简单。

$ pip install daeploy

创建 API

一个常见的用例是将经过训练的模型转换为预测服务,该服务具有可以接收数据并生成预测的 API。使用 Daeploy SDK,您可以用一个装饰器将任何 Python 函数转换成 API。

# Lets import what we need from daeploy SDK
from daeploy import service# decorate a python function with service.entrypoint to create an API endpoint!@service.entrypoint
def hello(name: str) -> str:
    logger.info(f"Greeting someone with the name: {name}")
    return f"hello {name}"

警报和通知

监控模型或一般运行的服务是创建可靠解决方案的一个重要方面。用例是无穷无尽的。一个常见的棘手问题是经过训练的模型随着时间的推移而退化。Daeploy SDK 带有内置的通知功能,因此您可以在经理仪表板上和您的电子邮件中获得通知。

@service.entrypoint
def hello(name: str) -> str:
    if name == "world":
        notify(
            msg="Someone is trying to greet the World!!",
            severity=Severity.WARNING,
            emails=["your@email.com"],
        )    
    logger.info(f"Greeting someone with the name: {name}")
return f"hello {name}"

使用微服务架构构建应用

创建应用程序通常需要多种服务,例如:

  • 数据库连接器服务:从专用数据库提取数据或将数据保存到专用数据库的服务。
  • 预测服务:获取数据作为输入并返回预测的服务。
  • 业务逻辑服务:包含业务相关逻辑的服务,负责将预测转换为业务相关动作。
  • 仪表板服务:提供可视化或与应用程序交互的服务。

使用微服务架构比单一应用程序有很多好处,例如灵活性、可伸缩性和关注点分离,等等。然而,也有缺点。管理服务之间的通信是微服务架构导致额外开销的一个例子。

如果使用 REST,需要为每个服务设置一个 Flask 服务器,创建和管理端点,并处理使用 REST API 可能发生的异常。Daeploy SDK 使得服务之间的通信像普通的 python 函数调用一样简单。下面是一个使用 call_service 并从另一个服务调用 hello 函数的示例:

# import call_service from communication package
from daeploy.communication import call_servicedef greet_the_world() -> str:
# No need for API call. Just call any entry point from other        # services using call_service function
    reponse = call_service(
        service_name="greeting_service",
        entrypoint_name="hello",
        arguments={"name": "world"}
     )
    logger.info(f"{reponse}")
return f"{reponse}"

部署经理

部署管理器旨在简化部署过程。让我们看看 Daeploy manager 如何简化部署服务的复杂性。

安全性和身份验证

处理访问、安全性和身份验证是在远程服务器上部署应用程序的基本部分,无论是在云上还是在客户场所。尤其是在处理业务敏感数据的时候。Daeploy manager 带有内置的基于令牌的身份验证和 HTTPS 功能。

用户可以直接与 Daeploy manager REST API 通信,或者使用 SDK 附带的命令行界面(CLI)。要使用 CLI,您所需要的只是一个安装了 Daeploy SDK 并激活了 Python 环境的终端。要与 Daeploy manager 通信,首先使用 login 命令进行身份验证:

$ daeploy login
Enter daeploy host: [https://your-host](http://localhost)
Logging in to Daeploy instance at [https://your-host](http://localhost)
Username: admin
Password: ***************
Changed host to https://your-host

您还可以使用 CLI 创建具有不同有效期的令牌。例如,您可以创建有效期为五天的令牌,如下所示:

$ daeploy token 5
Active host: [https://your-host](http://localhost)
Use the token in the header {"Authorization": "Bearer token"}, for further details see the docs
eyJ0eXAiOiJKV1QiLCJhb.....

集装箱化

使用 Docker 之类的容器部署服务正在成为行业标准。容器有几个优点,如可移植性、一致的操作,并且与虚拟机(VM)相比,它们更轻量级。
Daeploy manager 将 Python 代码转换成 Docker 映像,安装所有必需的依赖项,并作为服务运行,所有这些都只需一个命令:

$ daeploy deploy [options] <service-name> <version> <source>

源代码可以是您的本地开发文件夹、git repo,甚至是现有的 docker 映像!

影子部署

影子部署是一个方便的特性,它允许在不中断生产的情况下测试现有服务的新版本。在影子部署中,新版本与当前版本一起部署。新版本接收服务的所有入站流量,但忽略响应。

影子部署(来源:作者)

使用 assign 命令很容易切换服务的主版本。更多信息,请参见此处

$ daeploy assign <service-name> <version>

要了解关于启动管理器的更多信息,请查看入门文章

我们很高兴发布 Daeploy,并让社区免费获得。我们期待看到它如何帮助您将您的想法付诸实践。就业愉快!

参考资料:

[1] D .斯卡利,加里·霍尔特,丹尼尔·戈洛文,尤金·达维多夫,托德·菲利普斯,迪特马尔·埃布纳,维奈·乔德里,迈克尔·杨,江泽龙·克雷斯波,丹·丹尼森,“机器学习系统中隐藏的技术债务”,第 28 届神经信息处理系统国际会议论文集,2015 年 12 月

引入数据发音作为数据故事的核心原则

原文:https://towardsdatascience.com/introducing-data-sonification-as-a-core-principle-to-data-storytelling-9fa047fe773d?source=collection_archive---------34-----------------------

实践教程

重新思考数据可视化世界中的设计可及性。数据可视化的剖析和可视化的可访问性。

数据新闻是一个新兴领域,因为记者现在可以利用大量的开放数据来发现新的故事,提取见解和发现,并利用尖端技术制作一个强大的故事。正如《纽约时报》现任首席执行官梅雷迪思·列文所说,“我们生活在数字信息和高质量新闻结合的黄金时代。”今天我将分享这个领域的一个方面——数据故事。

目录

1\. Defining data storytelling. 2\. The anatomy of an accessible data visualization. 3\. Visualization for accessibility - data sonification with an example of representing the US population of young adults living below the poverty threshold. 

定义数据叙事

在数据化的世界中,有许多相互关联的术语和流行词汇,就像在人工智能的世界中一样。所以,我认为让它更清晰一点是有意义的。

在 Figma 上创建的关于数据故事的 Vienn 图。信用:数据新闻和可视化与免费工具

首先,有数据学术界和数据科学。那是我在加州大学伯克利分校的专业。它需要更多的研究导向,并需要统计/决策理论建模范式来设计像人-人工智能协作(即自动驾驶汽车)这样的系统。当我们谈论学术数据科学时,它通常包含复杂的图表,除非你知道研究的完整背景,否则无法理解。“在这种情况下,我们将数据可视化是因为我们想从中提取意义。从历史上看,这是因为科学家必须为他们论文中的每一个数字付费,这样他们才能塞进尽可能多的信息。这将使事情变得复杂。”(开罗)像这样:

学术界的数据各有千秋!

我在 RL 阅读人工智能研究论文中的数据来做研究

另一方面,还有数据艺术“数据往往看起来根本不像传统的图表或图形。相反,它看起来像是属于博物馆的东西。”(开罗)这是一个皇室家族的星座,在这里你可以看到所有皇室成员之间的家庭联系。这种数据艺术的另一个很好的例子是我去年在纽约的一个展览中看到的 Giorgia Lupi 的 Latour 项目。

皇家星座《伤痕——我们看不到的数据》

“数据讲故事本身就存在于两者的交汇点。它有时被描述为寓教于乐,因为它既有启发性又令人愉快。数据叙事的不同之处在于,的目标是接触尽可能多的受众,传达清晰的叙述和关键要点
数据可视化是一种讲述数据故事的工具,我们可以用它从电子表格中看到的数字中提取见解。”(开罗)

路透社报道

数据可视化将数据映射到对象上,如饼图、地图、条形图,甚至声音(阅读到最后!)之所以它最近变得强大,是因为它使我们能够发现某些模式、趋势,最终发现我们否则无法看到的故事。

可访问数据可视化的剖析

数据可视化必须对所有人开放。因此,它通常由几层内容组成,根据数据新闻和使用免费工具的可视化:

Figma 数据可视化的基础层。信用:数据新闻和可视化与免费工具

脚手架层

该图层包含支持标注、轴和比例等内容的要素。这是 2017 年华尔街日报制作的数据可视化, “追踪全国失业、工作岗位增加和工作岗位减少。”

“您可以看到右上角的颜色图例和轴上的小标签、图表轴上的小刻度线等。这是脚手架层。这基本上决定了内容将如何呈现,它将一切置于上下文理解中:“

来源:http://graphics.wsj.com/job-market-tracker/鸣谢:使用免费工具的数据新闻和可视化

编码层

这些对象的属性根据数据(表示数据的特征)而变化。在数据可视化中,我们使用许多不同种类的编码方法。“其中之一是高度或长度,就像条形图一样。这是一个重要的层面,因为它显示了一个变量随着时间的变化,对于新闻报道来说,这是一个非常有洞察力的指标。”(开罗)

这是我最近做的一个数据的例子,分析了 12 月份 billboard 2020 的历史数据。我用 x 轴代表这首歌在排行榜上的周数,y 轴代表在 billboard 上的位置(历史上的变化),圆圈的大小代表峰值位置(根据周的变化)。

我创作的广告牌 2020 年 12 月

标注图层

“注释层是我们添加到可视化中的文本元素,用于阐明数据或突出显示图表中的重要数据点,并将其放在上下文中。这很重要,因为它使我们能够有效地与公众沟通。”(开罗)

这里是由路透社制作的加州如何使用数十架飞机扑灭野火的可视化画面。这个项目的设计者不仅绘制了飞机的航线和标记的东西,还提供了可视化下面的注释。他们比较了飞机的载重量,以了解每种类型的飞机可以投放多少阻燃剂或水。

路透社报道加州如何使用数十架飞机扑灭野火

路透社报道加州如何使用数十架飞机扑灭野火

“我”层

这一层使人们能够体现数据并与之交互,这是一些个性化的时刻。其中一个例子是纽约时报“测验:让我们预测你是民主党人还是共和党人”预测你的政治倾向。

“这增加了参与度,它告诉你,通过告诉你你是错的或你是对的,它让你置身于你所展示的数据之中。”(开罗)

《纽约时报》的“测验:让我们预测你是民主党人还是共和党人”

可访问性的可视化-数据发音,以表示生活在贫困线以下的美国年轻人为例。

无论是传统的平面设计还是数字产品设计,其中一个重要的设计原则就是可访问性。随着我们在日常生活中看到越来越多的数据可视化,重要的是不仅要整合基本的 web 可访问性原则,还要考虑为盲人和视力受损者提供信息的新方法。

我想分享一下数据语音化的概念,基本上是将数据转换成声音,通过听觉来理解它。所以,我使用了联合国可持续发展开源数据,只过滤了美国的案例,做了一些基本的数据清理程序,开始玩数据,用我 8 年的音乐教育和工具玩声音。

数据发音的产生

这是一个生活在贫困线以下的 18 岁以下儿童的故事,他们生活在排名低于平均水平的各州,并以高中辍学率和入学率为背景。你可以听到背景中的钢琴代表 18 岁以下儿童生活在两倍贫困线以下的所有数据点,低音提琴代表学校入学率,振荡器代表高等教育的一般质量,钟琴代表高中辍学率。通过过滤一个学校升学率(低于平均水平)的数据,我只对代表的数值进行了发音,这就是为什么低音提琴不是一直演奏的原因。

结果如下:

https://soundcloud . com/Karina-ngu ien/data-sonization-the-us-population-of-young-成年人生活在贫困线以下的人口

感谢阅读!我目前在纽约时报做设计,在加州大学伯克利分校做研究。你也可以订阅我的 时事通讯 ,在那里我分享了更多关于新兴技术、产品设计和数据驱动调查的道德含义。了解更多关于我的作品 这里

引用的作品:

Datapane 简介:如何用 Python 创建交互式报告和可视化

原文:https://towardsdatascience.com/introducing-datapane-how-to-create-interactive-reports-and-visualizations-with-python-ebc40e02e748?source=collection_archive---------16-----------------------

从媒体文章到网站,在任何地方创建、发布和嵌入交互式数据可视化

贝卡·泰普特Unsplash 拍摄的照片

免责声明 :这不是一篇赞助文章。我与 Datapane 或它的创建者没有任何关系。这篇文章展示了该库的一个公正的概述,旨在使数据科学工具能够被更广泛的大众所使用。

您想让您的报告具有交互性吗?或者在你的博客中嵌入交互式数据可视化?如果是这样, Datapane 可能是您一直在寻找的银弹。今天,您将看到如何用几行 Python 代码创建、共享和嵌入交互式报告。

这篇文章的结构如下:

  • 数据面板—简介和环境设置
  • 使用 Altair 创建图表
  • 使用 Datapane 保存和发布报告
  • 最后的想法

数据面板—简介和环境设置

很多次,我花了几个小时构建一个交互式数据可视化,然后带着一个问题离开— 我如何才能与我的读者分享它?截图工具不行,gif 只是 meh ,但是 Datapane 可以扭转局面。

如果你想与世界分享任何分析报告,Datapane 就是为你准备的。该库使得以编程方式从图表和表格创建报告并将其包装在公共对象(如文本和图像)周围变得容易。

今天,您将看到如何获取、可视化和发布包含 S&P500 历史价格图表的报告。我们将使用 Altair 作为数据可视化库,但是您可以自由使用 Bokeh、Plotly 或 Folium 来代替。

首先,让我们为项目配置一个虚拟环境:

要使用 Datapane,你还必须在他们的网站上注册一个免费账户。这样做将为您提供一个 API 令牌,用于从 Python 脚本或笔记本中发布报告。

接下来让我们创建一些可视化。

使用 Altair 创建图表

如前所述,我们将构建历史 S&P500 价格的数据可视化。pandas_datareader库可用于直接下载财务数据。

以下代码片段导入库,下载 20 年的历史数据,并对其进行重新采样,以便只保留月平均值:

下面是前几行的样子:

图片 1-S&P 历史价格数据集的头部(图片由作者提供)

接下来让我们创建可视化。这将是一个显示 ETF 价格随时间变化的填充面积图。代码如下:

下面是图表的样子(在笔记本中):

图 2—S&P500 历史价格图表(图片由作者提供)

这就是我们保存和发布报告所需的全部内容。接下来让我们开始吧。

使用 Datapane 保存和发布报告

到目前为止,我们已经掌握了数据集和数据可视化。Datapane 可以很容易地将一个或多个元素导出到一个报告中,无论是在本地还是在他们的服务器上。

在继续之前,请使用以下命令登录到 Datapane 服务器:

图 3——登录 Datapane 服务器的过程(作者图片)

<your_api_token>换成注册后给你的字符串代码就行了。

接下来让我们做第一个报告。以下代码将把可视化和表格(加上一些文本元素)保存到本地计算机上的一个文件中:

它看起来是这样的:

图 4 —由 Datapane 生成的 HTML 报告(图片由作者提供)

这无疑是朝着正确方向迈出的一步,因为您可以轻松地共享报告文件,但是让我们更进一步。

下面的代码将只向 Datapane 服务器发布图表:

发布后,您可以点击“共享”按钮获得可共享的网址:

图 5 —共享已发布的数据面板报告(作者图片)

你可以与任何人分享它,甚至将其嵌入到你的媒体文章中——只需粘贴网址并点击输入:

非常管用!让我们用图表+表格报告做同样的事情:

在这里—嵌入式:

这就是与世界分享和嵌入定制可视化/报告的简单之处。接下来让我们总结一下。

最后的想法

今天您已经看到了 Datapane 的基础知识。然而,还有很多东西需要去发现,所以你可以自己去探索。最棒的是——它不会花你一分钱。Datapane 提供一些付费计划,但是如果你独立工作,你可能不需要它。

如需进一步了解,请参考官方文档。它还包含一个到 API 文档的链接,所以你可以在那里找到任何特性。

总的来说,Datapane 对于任何想要分享交互式可视化和报告的人来说都是一个优秀的服务。无论是您必须提交的每周销售报告还是博客帖子,交互性都为您的工作增添了新的维度。试一试吧——完全免费。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

了解更多信息

保持联系

介绍数据表- Python 数据表教程和练习

原文:https://towardsdatascience.com/introducing-datatableton-python-datatable-tutorials-exercises-a0887f4323b0?source=collection_archive---------19-----------------------

要测试的练习。要学的教程。

作者图片

Datatable 是一个用于操作表格数据的 python 库。它支持内存不足的数据集,多线程数据处理,并有一个灵活的 API。

如果这让你想起了 R 的数据表,那你就对了,因为 Python 的数据表包与 R 库密切相关,并受其启发。

2021 年 7 月 1 日 v1.0.0 发布,现在可能是开始探索这个包的好时机。

笔记本是了解软件包并深入研究它们的最好方式之一。它很方便,能够带来实际操作的体验,并且通常与清晰的文档密切相关。

Twitter 上关于学习新图书馆内容类型的投票

数据表顿:💯数据表练习

DatatableTon 是一个开源项目,包含 100 个不同部分的 Python 数据表练习,以课程或教程的形式为初学者、中间用户和专家进行教学。

✅结构化为练习&教程-选择你的风格
✅适合初学者,中级&专家-选择你的水平
✅可在 Colab,Kaggle,Binder & GitHub 上找到-选择你的平台

学问

data[data.f.set ≥ mylevel]

  • 对于希望从头开始学习 datatable 的初学者,建议从头开始按顺序浏览所有集合。它们的结构是为了让新人容易上手,快速学习。
  • 对于希望提高数据表技能的中间用户,建议从集合 5 或集合 6 开始,并按顺序浏览所有后续集合。
  • 对于希望练习更多 datatable 的专家来说,建议在最后两组测试自己:Set 9 和 Set 10。

教学

data[data.f.style == mystyle]

  • 对于查看练习以测试学生的教师,建议使用所有 练习 样式的练习集。
  • 对于查看教程进行演示或教学的教师,建议使用套件的所有 解决方案 样式。

内容

数据表顿集

DatatableTon 的每个部分都是一个 Jupyter 笔记本,旨在展示该包的特定功能,从基本设置和数据处理到机器学习模型和完整的项目。

Set 01 数据表简介初学者练习 1–10

  • 软件包的安装和设置
  • 创建和显示数据
  • 查看数据及其详细信息

创建框架

设置 02 文件和格式初学者练习 11–20

  • 读取/写入 csv、gz、jay、zip 文件或 URL
  • 集成熊猫,numpy,箭头格式
  • 在框架中使用列表、字典和元组

从熊猫转换成熊猫

Set 03 数据选择初学者练习 21–30

  • 选择行/列/切片/元素
  • 使用单个或多个试探法筛选行/列
  • 删除缺失的行/列,并删除重复项

选择列

设置 04 框架操作初学者练习 31–40

  • 更改列名和类型
  • 创建、更新、删除行/列
  • 估算和设置缺失值

设置缺失值

设置 05 列聚合初学者练习 41–50

  • 计算计数、总和、最小值、最大值、平均值、中值、众数、标准差、偏斜、库尔特
  • 列的协方差
  • 特征相关性和相关性矩阵

计算所有列的平均值

设置 06 分组方法中级练习 51–60

  • 按功能分组的聚合指标
  • 比较按功能分组的列统计信息
  • 将分组与筛选和排序结合起来

计算按其他列分组的列的中值

设置 07 多帧中级练习 61–70

  • 读取、rbind、cbind 多个帧
  • 使用单键或多键连接框架
  • 框架的并集、交集、差集

连接多个框架

设置 08 时间序列中级练习 71–80

  • 提取和创建日期/时间特征
  • 在组内/组外创建滞后和超前变量
  • 计算日期/时间戳的差异

创建滞后变量

Set 09 FTRL 本地专家练习 81–90

  • FTRL 模型的初始化和超参数
  • 对 FTRL 模型进行训练和评分
  • 执行 k 重交叉验证

训练 FTRL 模型

设置 10 个顶点项目专家练习 91–100

  • 多个数据集上的端到端工作流
  • Kaggle 竞赛数据集和实际提交
  • 探索您自己的数据集和用例

Kaggle 贸易转移竞赛的端到端实施

DatatableTon 是开源的,可以在 GitHub
上免费获得,特别感谢Parul Pandey&Shrinidhi Narasimhan的合作🙏

ETL 和 ELT 中断器 dbt 简介

原文:https://towardsdatascience.com/introducing-dbt-the-etl-elt-disrupter-4351adc34123?source=collection_archive---------14-----------------------

再见 ETL & ELT,你好 dbt!

图片来自 Pixabay 的 Peter H

每天,数 Pb 的数据被收集、操作和存储,用于全球范围内的各种分析目的。如果没有管道来获取这些数据并正确使用它们,大规模的数据科学根本不可能实现。传统上,被称为 ETL 和 ELT 的两个过程中的一个用于获取大量数据,挑选出重要的部分,然后将这些数据加载到数据湖或数据存储中。然而,这两种管道都有其缺点,到 2020 年,随着世界越来越依赖于分析和实时数据,ETL 和 ELT 不再是最锋利的剑。

在本文中,我将比较 ETL 和 ELT,总结两者的工作原理,它们在过去和现在是如何被常规使用的,以及为什么数据科学领域的大多数领导者认为它们已经过时了。

ELT,ETL,有什么区别?

经许可从普查中获取的图像

ELT 代表提取、加载、转换,而它的伙伴 ETL 同样表示提取、转换、加载。这三个步骤在任何重要的数据转换中都是至关重要的过程。不管你有没有意识到,它们被用于全球数百万的应用中。每当你从附近的杂货店购买一件商品,你的交易,无论是匿名的还是有身份的,都将被转移到这些金融和营销分析管道中的一个。让我们看看 ELT 如何与 ETL 相抗衡。

如果我们从各种来源收集数据,比如一个国家的多个商店,或者比方说水坝不同点的许多不同仪器,以给出一个科学示例,我们需要将所有这些数据收集在一起,然后只提取对我们想要创建的分析有影响的部分。这可能是每个商店的净销售额,在这种情况下,您需要对所有交易进行标准化和合计。或者,在大坝的例子中,可能需要列出所有的水压读数。这是转换过程,对于创建分析是必不可少的。具体来说,它允许我们使用商业智能工具,如 Tableau 或 Periscope。

当我们使用 ELT——即提取、加载、转换——时,我们的目的是通过在数据服务器上执行这些计算量很大的操作来节省我们的主机。我们不使用杂货店的计算机来合计交易,而是将原始数据发送到数据湖或其他存储机器,只有在那时,我们才执行转换阶段来获得整体利润——例如,合计交易和减去成本。

ELT 非常适合我们只做简单计算的大量数据,比如杂货店的例子。我们可以从所有来源提取数据,例如读卡器,将它们加载到我们的数据存储中,然后转换它们,以便我们可以轻松地进行分析。

另一方面,你有 ETL 。这在大坝的例子中效果更好。总的来说,我们不一定收集大量的数据,但有许多不同类型的读数,很可能你会想对它进行大量的计算,以进行深刻的分析。最好我们也希望这些数据实时,这样我们就可以防止任何洪水!在这种情况下,提取、转换、加载更合适。我们不是将原始数据发送到数据存储器,然后进行操作,而是在它们被发送到数据存储器时执行操作,这就是所谓的“转换阶段”。通过这种方式,我们可以建立一个连续的数据流,该数据流在被加载到数据存储器之前就已经被处理了!

这两个类比善于突出 ETL 与 ELT 的优缺点。有了 ELT,当您有大量的数据,比如数百个交易,但您只想执行一些相对简单的操作,比如计算利润,或者将销售额映射到一天中的时间时,它就非常有用。

与此同时,ETL 在实时情况下工作得更好,在这种情况下,我们没有大量的数据,但我们有许多需要正确排序的专门数据,因此需要更多的计算。

ETL 和 ELT 工具

对现代世界来说幸运的是,我们不再需要做大量的编程来为我们的数据创建一个流线型的管道!有许多 ETL 和 ELT 工具允许我们执行这些功能,从各种各样的数据源到各种各样的数据仓库或机器。

例如,Hevo 无编码数据管道在零售商和其他实体企业中广泛使用,他们希望收集销售数据或关于他们商店的活动信息。但它也非常适合实时数据,所以如果你想测量你的店面外面的客流量,并绘制一段时间的地图,你也可以使用 Hevo!

还有 Fivetran,它围绕预建的连接器和功能构建,提供“即插即用”的体验。

dbt —更好的方法!

ELT 和 ETL 听起来像是从 A 到 B 获取数据进行分析的非常合理的方法,但实际上它们本身都很不方便。使用 ELT 和 ETL,您必须在加载数据之前准确地知道您想要创建什么样的分析。幸运的是,它们与现代工具如 Fivetran 、Airflow、Stitch 等以及云仓库如 BigQuery、 Snowflake 和 Redshift 相比都很微不足道。

即使这样,困难的部分仍然留在变换层。转换层是数据管道中至关重要的元素,但如果它阻碍了您获得最相关的见解,那么一定有更好的方法。

然而,通过一些更先进的管道技术,我们可以增加我们的选择,并允许我们创建许多不同类型的分析,而不必通过管道重新发送数据并对其进行不同的转换!

经许可从普查中获取的图像

它被称为 dbt,或数据构建工具,它是一个超级灵活的命令行数据管道工具,允许我们非常快速、非常轻松地收集和转换数据进行分析!dbt 不需要完全重新编程您的管道。

dbt 仍然像传统数据库一样构建在 SQL 之上,但是它使用像 jinja 这样的模板引擎在其上构建了额外的功能。这有效地允许你带来更多的逻辑(如循环、函数等。)到您的 SQL 中,以访问、重新排列和组织您的数据。有点像对数据集编程,但有更多的灵活性和选项。

有了这些代码,您就可以使用 dbt 的 run 命令来编译这些代码,并在 SQL 数据上运行这些代码,从而准确地获得您所寻找的转换中需要的部分。它还可以快速编程、测试和修改,而无需等待它运行所有数据,这意味着您可以在紧张的时间表内创建新的、更好的程序版本。

dbt 不会完全取代 ELT 和,但它确实提供了更大的灵活性——它极大地增强了您的“T”转换层/阶段。使用 dbt,您可以一次又一次地聚合、规范化和排序数据,无论您喜欢什么方式,而无需不断更新您的管道和重新发送。

dbt 不是 ETL 和 ELT 的替代品,但是随着现代技术的发展,这些独立的管道方法已经过时了。无论您是遵循 ETL 还是 ELT,有一件事是肯定的,那就是在您能想到的每一个方面,dbt 对 T(转换)层都是一个巨大的改进。

感谢阅读!

我鼓励你去看看 dbt。您可以从这里的快速入门指南开始,并在这里加入他们的超级有用社区。相信我,当你开始使用 dbt 时,你会想你以前是怎么做数据建模工作的。

不确定接下来要读什么?我为你挑选了另一篇文章:

又一个!

</10-statistical-concepts-you-should-know-for-data-science-interviews-373f417e7d11>

特伦斯·申

  • 如果你喜欢这个, 跟我上媒 了解更多
  • 有兴趣合作吗?让我们连线上LinkedIn
  • 报名我的邮箱列表 这里

引入距离相关性,一种优越的相关性度量。

原文:https://towardsdatascience.com/introducing-distance-correlation-a-superior-correlation-metric-d569dc8900c7?source=collection_archive---------5-----------------------

这是一个解决皮尔逊相关性头号问题的现代指标

咖啡极客Unsplash 上的照片

目录

  1. 介绍
  2. 什么是距离相关性?
  3. 距离相关背后的数学
  4. 在 Python 中实现距离相关性

介绍

我想我们都同意,商业中最常用的衡量标准之一是相关性,更具体地说,是皮尔逊相关性。

概括地说,相关性衡量两个变量之间的线性关系,这本身已经是一个问题,因为有许多关系是非线性的。

因此,作为一个例子,你可能会得出结论,变量 X 和收入之间的关系是不相关的,而事实上它是相关的,只是不是线性的。

这就是距离相关性发挥作用的地方!

什么是距离相关性?

距离相关性是非线性随机变量之间关联强度的度量。它超越了皮尔森相关性,因为它不仅能发现线性关联,还能在多维度上发挥作用。距离相关性的范围从 0 到 1,其中 0 表示 X & Y 之间的独立性,1 表示 X & Y 的线性子空间相等。

下图显示了距离相关性测量与皮尔森相关性的比较。

距离相关性的公式如下:

距离相关公式

距离相关性不是距离本身之间的相关性,而是组成“双中心”矩阵的标量积之间的相关性。

如果这对你没有意义,让我们更深入地研究数学。

距离相关背后的数学

设(Xk,Yk),k = 1,2,…,n 是一对两个随机变量 X & Y 的统计样本。

首先,我们计算包含所有成对距离的 n 乘 n 距离矩阵(aj,k)和(bj,k)。

然后我们取双中心距离。

从视觉角度来看,通过采用双中心距离,我们将矩阵表示(左侧)转换为右侧的图表(双中心矩阵)。

作者创建的图像

我们为什么要这样做?

我们这样做的原因如下。任何一种协方差都是矩的叉积。因为距离不是力矩,我们必须把它们计算成力矩。为了计算这些力矩,你必须首先计算与平均值的偏差,这就是双重居中所实现的。

最后,我们计算乘积 A 和 B 的算术平均值,以得到平方的样本距离协方差:

距离协方差公式

距离方差就是两个相同变量的距离协方差。它是下列各项的平方根:

距离方差公式

在 Python 中实现距离相关性

确信这是你的标准?您很幸运,因为有一个距离关联库,使它非常容易实现。

下面是一个示例代码片段:

import dcordef distance_correlation(a,b):
    return dcor.distance_correlation(a,b)

利用这个函数,你可以很容易地计算出两个样本 a 和 b 的距离相关性。

感谢阅读!

我希望你觉得这很有趣!就我个人而言,我发现这在我的日常生活中非常有用,我希望你也能发现这很有用。

这个指标肯定有优点和缺点,我很想听听你的想法。如何看待一个可以检测非线性关系的相关性度量,但其范围只限于 0 和 1 之间?

一如既往,我祝你学习一切顺利!

不确定接下来该读什么?我为你挑选了另一篇文章:

</10-statistical-concepts-you-should-know-for-data-science-interviews-373f417e7d11>

又一个!

</21-tips-for-every-data-scientist-for-2021-3d4c28471a6c>

特伦斯·申

  • 如果你喜欢这个, 跟我上媒 了解更多
  • 有兴趣合作吗?让我们连线上LinkedIn
  • 报名我的邮箱列表 这里

FlowPy 简介-使用 python 在浏览器中处理数据!

原文:https://towardsdatascience.com/introducing-flowpy-an-intuitive-front-end-for-processing-data-with-python-a619ebe6bb9e?source=collection_archive---------13-----------------------

行业笔记

从您自己的浏览器舒适地操作熊猫数据框!

我们都喜欢处理数据,但有时将我们所做的传递给数据会很有挑战性。我希望构建一个应用程序,帮助人们定义数据流,同时提供一种直观而简单的方式来编辑这些数据流并与其他人共享。对于具有扎实技术背景的人来说,将数据管道编写为脚本是简单而有效的,但是如何向经理或利益相关者展示这一点呢?我决定是时候构建一个这样的应用程序了!作为一个额外的收获,我想这对那些不直接编码但理解他们想要对数据执行的步骤的人(例如,一个博士生)是有利的

我希望界面简单、直观、美观,以便在演示或会议期间使用,将处理步骤传递到其他业务领域。因为从概念上讲,我们是在实现一个有向无环图,所以我希望有一个画布,可以拖动节点,并通过拖放边来连接节点。下面的屏幕截图显示了一个简单的 DAG(流)的界面。

带有示例流的 FlowPy Studio 作者提供的图片

从上面的屏幕截图中,我们可以看到,这个特定的流获取一个 CSV(来自“/tmp/test.csv”),应用一个单独的过滤级(其中“id==2”),然后将数据帧写到磁盘(位于“/tmp/out.csv”)。

只有节点最重要的参数才会显示在流程中。重心图标用于查看和编辑所有参数。单击该图标将打开一个模式窗口,显示该节点的所有参数及其当前值。

展示节点参数示例的 FlowPy Studio 作者图片

单击该模式中的 play 按钮将导致后端运行该节点。最初采取依赖性解决步骤来检查在流中的当前节点之前定义的哪些节点已经运行并且包含最新数据。拥有最新的数据对不同的节点来说意味着不同的事情。例如,如果过滤器节点的过滤器参数已经更改,它将需要再次运行。但是,对于 CSV 输入节点,将比较输入文件的散列,以查看这是否是相同的数据;否则,将再次加载数据。一旦所有先决条件节点都是最新的,最初请求的节点就会运行。

显示当前节点运行状态的 FlowPyAPI 作者图片

目前,当一个节点运行时,前端没有任何指示。理想情况下,我设想界面上的交通灯系统显示红色表示从未运行,橙色表示运行但旧数据被缓存,绿色表示运行并更新。然后,当点击 cog 图标编辑节点参数时,我希望显示一组扩展的运行统计数据。我希望显示的关于节点运行的元数据类型是:

  • 节点运行的时间。
  • 消耗了多少内存。
  • 数据集中存在哪些列。

后端公开所有这些项目;我只是没有扩展前端来显示这些信息。

这个应用程序还可以处理多个流,并通过侧栏公开它们。我想把它扩展到基于个人和团队的安全和共享。

目前,这个应用程序还处于初级的 alpha 阶段。对于新手和有经验的开发人员来说,这是一个很有价值的软件。我想探索某种形式的自动管道部署以及文档和业务规则的生成。

我目前正在学习 react,我知道在前端有许多需要改进的地方。此外,后端需要明显的扩展来支持新功能。我现在已经公开了这个知识库,因为我相信它已经到了有人可以从目前存在的东西中理解我的愿景的地步。还有其他明显的扩展,如容器化的流运行器和 spark 集成,以及更好的调度支持。

我希望你能看到我用这个工具的最终目标。我找人提交一些问题和公关的。让我们像开源社区那样做,把它变成一个有用的工具,我知道这是可能的!

https://github.com/schlerp/flowpy

不久将会有一篇文章解释这方面的先驱应用程序,该文章着重于使用从一个非常相似的界面设计的 SQL 来执行 ELT!它被称为 PELT Studio,可以在下面的存储库中找到。

https://github.com/schlerp/pelt-studio

我需要特别提到一个类似的新兴产品,叫做数据块。在开始开发这个应用程序之后,在寻找用 react 处理 DAG 的优秀方法时,我遇到了 reactflow。Reactflow 是前端所基于的库,非常棒。在研究它的文档时,我找到了它所设计的产品的参考资料,这是一个非常相似的概念,但更成熟,并且基于 Javascript。我更喜欢 python 操作数据的生态系统,我相信我并不孤单,所以我仍然看到了 FlowPy 的空间。然而,如果您更喜欢 Javascript,请查看数据块!在我写这篇文章的时候,我仍然在等待进入 alpha,但是非常兴奋!

https://reactflow.dev/ https://datablocks.pro/

感谢您的阅读,请不要忘记查看我的其他文章,并在 medium 上关注我!

介绍 FugueSQL —用于 Pandas、Spark 和 Dask 数据帧的 SQL

原文:https://towardsdatascience.com/introducing-fuguesql-sql-for-pandas-spark-and-dask-dataframes-63d461a16b27?source=collection_archive---------1-----------------------

用于数据科学和分析的端到端 SQL 界面

动机

作为一名数据科学家,您可能对 Pandas 和 SQL 都很熟悉。然而,可能有一些查询和转换,您会觉得用 SQL 而不是 Python 来做比较舒服。

如果你能像下面这样查询熊猫的数据帧,那不是很好吗?

…使用 SQL?

作者图片

或者在 SQL 查询中使用 Python 函数?

这时,FugueSQL 就派上用场了。

什么是 FugueSQL?

FugueSQL 是一个 Python 库,允许用户组合 Python 代码和 SQL 命令。这使得用户可以在 Jupyter 笔记本或 Python 脚本中灵活地切换 Python 和 SQL。

要安装 FugueSQL,请键入:

pip install fugue[sql]

要在 Spark 或 Dask 执行引擎上运行,请键入:

pip install fugue[sql, spark] 
pip install fugue[sql, dask]
pip install fugue[all]

在本文中,我们将探索 FugueSQL 的一些实用程序,并将 FugueSQL 与 pandasql 等其他工具进行比较。

笔记本中的 FugueSQL

FugueSQL 附带了一个 Jupyter notebook 扩展,允许用户交互式地查询带有语法高亮显示的数据帧。

要使用它,从fugue_notebook导入setup函数来注册%%fsql细胞魔法。这目前只在经典笔记本上可用(JupyterLab 上不可用)。

为了理解%%fsql细胞是如何变魔术的,让我们从创建一个熊猫数据框架开始:

现在,您可以像在 SQL 中一样通过在单元格的开头添加%%fsql来进行查询。

作者图片—将代码复制到此处

上面的代码中,只有PRINT没有遵循标准 SQL。这类似于 pandas head()和 Spark show()操作来显示许多行。

GROUP BY这样的操作类似于标准的 SQL 语法。

作者图片—将代码复制到此处

增强的 SQL 界面

对于 SQL 用户来说,除了PRINT语句之外,上面显示的没有什么不寻常的。然而,Fugue 也为标准 SQL 添加了一些增强,允许它优雅地处理端到端的数据工作流。

处理临时表

SQL 用户经常不得不使用临时表或公用表表达式(CTE)来保存中间转换。幸运的是, FugueSQL 支持通过变量赋值来创建中间表。

例如,在转换df之后,我们可以将其赋给另一个名为df2的变量,并使用SAVE variable OVERWRITE file_namedf2保存到一个文件中。

作者图片—将代码复制到此处

现在,如果我们想对df2应用更多的变换,只需从我们之前保存的文件中加载它。

作者图片—将代码复制到此处

很酷,不是吗?

添加的关键字

SQL 的语法是为了查询,这意味着它缺少操纵数据的关键字。FugueSQL 为常见的 DataFrame 操作添加了一些关键字。例如:

作者图片—将代码复制到此处

  • 填充空参数

作者图片—将代码复制到此处

  • 样品

作者图片—将代码复制到此处

有关操作员的完整列表,请查看 FugueSQL 操作员文档

与 Python 集成

通过使用TRANSFORM,FugueSQL 还允许您在 SQL 查询中使用 Python 函数。

例如,要在 SQL 查询中使用函数str_concat:

…只需将以下组件添加到功能中:

  • 输出模式提示(作为注释)
  • 键入注释(pd.DataFrame)

酷!现在我们准备将它添加到 SQL 查询中:

图片由作者提供—将代码复制到此处

向大数据扩展

富格斯基火花

SQL 的一个美丽特性是它不知道数据的大小。该逻辑以一种与规模无关的方式表达,即使在 Pandas、Spark 或 Dask 上运行也将保持不变。

使用 FugueSQL,我们可以通过指定%%fsql spark在 Spark 执行引擎上应用相同的逻辑。我们甚至不需要编辑str_concat函数来将它带到 Spark,因为 Fugue 会负责移植它。

作者图片—将代码复制到此处

PREPARTITION BY

分布式计算的一个重要部分是分区。例如,要获得每个逻辑组中的中值,需要对数据进行分区,使每个逻辑组都位于同一个工作线程上。

为了描述这一点,FugueSQL 有了PREPARTITION BY关键字。神游的prepartition-transform语义相当于熊猫的groupby-apply。唯一的区别是prepartition-transform扩展到分布式设置,因为它规定了数据的位置。

作者图片—将代码复制到此处

注意,对于列col2中的每个不同值,上面的get_median函数都会被调用一次。因为数据是预先划分好的,所以我们只需取出第一个值col2就可以知道我们正在与哪个组一起工作。

生产中的 FugueSQL

要将 FugueSQL 从 Jupyter 笔记本中取出并放入 Python 脚本中,我们需要做的就是将 FugueSQL 查询包装在一个fsql类中。然后我们可以调用.run()方法并选择一个执行引擎。

FugueSQL 和 pandasql 有什么区别?

如果你了解 pandassql,你可能会想:如果 pandasql 已经允许你用 panda 运行 sql 了,为什么还要用 FugueSQL 呢?

pandasql 只有一个后端 SQLite。在 pandas 和 SQLite 之间传输数据会带来很大的开销。另一方面,FugueSQL 支持多个本地后端:pandas、DuckDB 和 SQLite。

当使用 pandas 后端时,Fugue 直接将 SQL 翻译成 pandas 操作,所以根本没有数据传输。DuckDB 有极好的 pandas 支持,所以数据传输的开销也可以忽略不计。Pandas 和 DuckDB 都是本地数据处理的首选 FugueSQL 后端。

Fugue 还支持 Spark、Dask 和 cuDF(通过 blazingSQL)作为后端。

结论

恭喜你!您刚刚学习了如何使用 FugueSQL 作为 SQL 接口来操作 Python 数据帧。使用 FugueSQL,您现在可以使用 SQL 语法来表达端到端的数据工作流,并无缝地扩展到分布式计算!

本文并没有详尽地介绍 FugueSQL 的特性。有关 Fugue 或 FugueSQL 的更多信息,请查看下面的参考资料。

随意发挥,并在这里叉这篇文章的源代码:

https://github.com/khuyentran1401/Data-science/blob/master/data_science_tools/fugueSQL.ipynb

我喜欢写一些基本的数据科学概念,并尝试不同的数据科学工具。你可以在 LinkedInTwitter 上和我联系。

如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:

💔-tools-to-track-and-visualize-the-execution-of-your-python-code-666a153e435e> [## 3 个跟踪和可视化 Python 代码执行的工具

towardsdatascience.com](/3-tools-to-track-and-visualize-the-execution-of-your-python-code-666a153e435e)

Ingestum 简介

原文:https://towardsdatascience.com/introducing-ingestum-dda1650857f4?source=collection_archive---------31-----------------------

一个可扩展、可伸缩、免费和开源的统一摄取框架,使创建和使用 NLP 程序变得更加容易

图片作者。

NLP 和其他基于语言的人工智能的市场正在爆炸式增长,估计每年增长超过 20%[1]。作为一家人工智能公司,我们很快意识到,简单地访问非结构化内容是一个重大的技术障碍。

根据 Gartner 2015 年的一项研究,80%的企业数据被锁定在非结构化文档中[2]。这些非结构化数据中的大部分相对容易获取,但麦肯锡认为最后的 20%在提取和机器可读方面特别具有挑战性[3]。NLP 的承诺在于以尽可能少的摩擦获得数据,我们永远不会因为客户有“错误”的文件而拒绝他们。

当我们寻找答案时,我们发现摄取软件市场高度分散,有几十个利基专家,没有一个解决方案能满足我们的需求。对于一家预算紧张、梦想远大的年轻初创公司来说,缺乏解决方案是一个巨大的挑战,也是一个额外的障碍。作为在开源社区有深厚根基的开发人员,我们对找不到开源解决方案感到失望。

因此,我们构建了自己的—一个可扩展、可伸缩且易于使用的统一内容摄取框架。我们称之为 Ingestum(“摄取它们”)。因为我们也不希望其他项目或初创公司受到阻碍,所以今天我们在免费/自由开源许可下发布它,供全世界使用。

最近,我们再次深入研究了市场,发现了 170 多家潜在供应商,并有了一些惊人的发现:

  • 市场极其分散。
  • 非常非常少的“纯玩家”只专注于摄取。
  • 至少有十几家人工智能供应商分别销售他们的摄取平台。
  • 有许多人工智能供应商将他们的摄入与他们的人工智能产品联系在一起。
  • 一种常见的方法是将所有内容转换成 PDF,然后应用光学字符识别(OCR)。
  • 几乎对一家公司来说,这种吸收是专有的,迫使每个进入市场的新公司重新发明轮子,减缓创新,并为有活力的年轻公司创造进入壁垒。

这不仅仅影响开发者。当选择一个人工智能产品时,用户被锁定在可用的摄取软件中。提前消化可能很难,尽管许多人工智能公司拥有出色的内部解决方案,但他们可能仍然难以处理复杂的 PDF 结构或其他文档,从而阻碍了他们的效率。更不用说来自新社交媒体或视频会议应用的快速激增的数据格式了。我们遇到的一些公司在谈到“数据准备”时,会掩饰这些挑战。但是,如果它简单、快速、可靠地吸收非结构化数据,就不会仍然是一个未解决的问题。

同样,在与客户的交谈中,我们了解到数据管理问题是一个反复出现的主题。一位维护企业药物警戒平台的客户告诉我们,“当我看到我们的安全平台时,我很尴尬,我需要计算我们有多少供应商、工具和连接点。这是一个巨大的,蔓延的建筑图。很尴尬。我都不会表现出来。”

在这种产品激增的情况下,我们找到了一个潜在的解决方案。我们意识到我们的摄取引擎框架首先需要具有可伸缩性和可扩展性。当面对一种不熟悉的格式时,我们可以在短短三个小时内创建一个新的修改器,然后能够真空处理该类型的每个文档。我们想要的是需要尽可能少的单点解决方案,这可能是一个完全全面的摄取平台—您需要的最后一个摄取解决方案。

现在是核心问题——那么,我们为什么要开源呢?如果这么多公司都在努力消化,而且我们相信我们有秘方,为什么我们要把配方发布到网上让所有人看呢(和如今大多数配方博客一样,还有一篇解释其来源的长篇背景文章)?

一个原因是我们对自己核心技术的信心。我们认为,我们的人工智能平台因其语言智能而足够差异化,因此我们不需要在摄取方面占据优势。另一个原因是我们知道开源项目的优势。摄取不是我们的核心业务,虽然创建一个新的修饰符只需要几个小时,但是随着我们公司的扩展,当我们遇到新的文档类型时,拥有一个大大扩展的修饰符库是很好的,此外还有吸引活跃的开发人员社区来不断完善和扩展产品的所有额外好处。

但最后,我们是开源的忠实信徒。像大多数工程团队一样,我们非常依赖于站在前人的肩膀上。Ingestum 的组件中有 Python 组件,如 Beautiful Soup、Camelot、PDFMiner、Pyexcel、Twython、Python-tesseract 和 Deep Speech。我们非常感谢开发人员社区创建了这些组件,从而使我们的工作变得更加容易,我们希望回报他们。此外,今天,人工智能公司没有利用这些伟大的项目。Ingestum 是第一个将这些项目整合在一起的免费/libre 开源框架。

我们的大部分工程团队也是通过开源社区走到一起的。我共同创建了 Sugar Labs,这是一个面向儿童的协作式免费/自由开源软件学习平台,还有 Music Blocks,这是一个以有趣的方式探索基本音乐概念的工具集。通过在 Sugar Labs 的工作,我认识了马丁·阿本特·拉哈耶,他是 Ingestum 的首席工程师。马丁和胡安·帕布鲁都是 GNOME 基金会的成员,为 GNOME 项目做出了贡献

我们都深信开源的使命。我们为我们创造 Ingestum 的工作感到非常自豪,我们希望它不辜负自由/开源软件产品的优良传统。

ingestum——从拉丁词到摄取——旨在应对三大挑战:

  • 便于编写脚本,从任意来源和格式中提取非结构化内容;
  • 提供一个从各种源格式中提取内容的框架;和
  • 允许在许多粒度级别上集成 Python 脚本和服务。

我们的文档[4] [5]中详细介绍了 Ingestum 方法,它有六个主要概念:

  1. Sources :源文件或数据流,转换成 Ingestum 文档,可扩展的 JSON 编码格式,以便进一步处理;
  2. 文档:应用修改符的中介,例如,表格数据、自由文本数据或收款文档;
  3. 修饰符:对其全部或部分输入的具体操作,返回一个输出文件;
  4. 管道&管道:管道是一系列修饰符,管道是管道的集合,这是屡试不爽的 UNIX 方法;
  5. 条件:选择性应用修饰语的逻辑条件;适用于复杂的非结构化数据,例如只提取表格或不带表格的文本;
  6. manifest:用 JSON 表示,描述了源代码和管道及其参数,简化了 Ingestum 的命令行调用。

这些组件形成了一个统一的框架,用于接收各种来源,如一家意外险公司的 PDF 数据表、Proquest 和 PubMed 的研究论文、美国政府机构的 XML 文档、电子邮件线程、Twitter feeds、一家制药公司的 XLS/XLSX 文件、Youtube 和 Vimeo 视频以及会议录音。现在,您可以对您的非结构化数据或您客户的非结构化数据使用 Ingestum 框架。

我们认为 Ingestum 为人工智能领域的任何人提供了一个令人信服的销售论据:它是免费的,非常容易安装、原型化、测试和部署。就其本质而言,处理非结构化数据需要一些实验和迭代。Ingestum 在这方面很出色,因为这个过程被分解成了小步骤。今天,GitLab 上的 Ingestum 库中有几十个示例管道,涵盖了广泛的来源。这些为构建新的定制管道提供了一个起点。(过多的管道示例简化了开发人员的入职,因为修改现有管道比创建新管道更容易。)修改器库覆盖面广,添加新的修改器通常只需几个小时的工作。Ingestum 可以通过 FastAPI 之类的服务框架获得,并集成到低代码和无代码环境中。

Ingestum 并不完美。默认的 OCR 库可能难以处理一些手写文档。可以改进默认的语音到文本的代码转换。但是通过 Ingestum 的插件机制可以很容易地添加一个首选库。Ingestum 的模块化架构意味着可以为所有类型的文档和流类型及格式添加修改器,并且该平台将随着部署而增长。

我们认为 Ingestum 在摄入市场上既是竞争者也是反竞争者。我们的意思是:它是免费的开源软件,所以你可以自由地评估它,并将其添加到你现有的工作流程中。相反,如果你相信(就像我们一样)Ingestum 可以在你的摄取过程中发挥核心作用,你现在使用的软件可以作为插件添加到 Ingestum 中。C++或 Java 模块中的代码?别担心,用 Python 绑定把它们放进去。如果您有不想发布的专有摄取代码,LGPL 允许您将代码作为插件添加到实现中。Ingestum 可以成为任何类型的非结构化数据和现有解决方案之间的桥梁,或者直接喂给 AI 处理。我们相信如果人工智能公司为框架贡献插件,所有的船都会上升。

我们对 Ingestum 的愿景是通过使非结构化文本易于自然语言处理(NLP)来推进人工智能,促进知识结构的创建,从而实现人工智能技术的进一步丰富。我们相信,通过消除最大的初始障碍,降低创新成本,Ingestum 将成为未来人工智能项目的福音。下载 Ingestum 自己看。

要了解更多关于 Ingestum 的信息或报名参加我们 4 月 27 日的网络研讨会,请点击这里

[1] 自然语言处理市场,按组件、类型(统计、混合)、应用程序(自动摘要、情感分析、风险&威胁检测)、部署模式、组织规模、垂直市场和区域划分—2026 年全球预测 (2020)、市场和市场

[2] A. Dayley,D. Logan,组织将需要应对三大挑战,以遏制非结构化数据过剩和忽视 (2015),Gartner Research

[3] M. Friesdorf,M. Hedwig,F. Niedermann,最佳数字文档处理:支付者视角 (2019),麦肯锡&公司

[4]https://sorcero.gitlab.io/community/ingestum/

[5]https://gitlab.com/sorcero/community/ingestum.git 的 git 克隆

Jaal 简介——轻松与网络互动

原文:https://towardsdatascience.com/introducing-jaal-interacting-with-network-made-easy-124173bb4fa?source=collection_archive---------13-----------------------

您的互动网络用 Python 可视化仪表盘

照片由艾拉·巴克斯特Unsplash 上拍摄

访问 包的 github 页面 获取代码和详细自述。还有,如果你喜欢,请不要羞于点击星星😏

👉前言

不久前,我发表了一篇文章,介绍了 Python 中的几种网络可视化工具。反响是惊人的。最精彩的部分是人们分享他们的经历、喜好和问题的信息。有趣的一点是,有多少人对其中一个选项感到兴奋,但它需要大量的样板代码才能开始。这个问题是 Jaal 的催化剂,在 Jaal 中,我试图使用 Dash 和 visdcc 去掉在 Python 中绘制网络所需的所有多余的东西。除此之外,我还尝试添加了一些我个人认为网络可视化工具应该具备的最常见的交互功能。所以,事不宜迟,让我们深入到 Jaal😄

👉什么是 Jaal

Jaal 是一个基于 python 的交互式网络可视化工具,使用 Dash 和 Visdcc 构建。由于它是使用 Dash 构建的,我们可以将其视为一个仪表板,而不是网络图。正因为如此,除了基本特性,Jaal 还提供了多种选项来处理网络数据,比如搜索、过滤,甚至给图中的节点和边着色。所有这些都在 2 行代码内:)

👉安装

安装 Jaal 非常简单,只需运行以下命令,

pip install jaal

你完了😆

注意,建议在安装之前创建一个虚拟环境。这可以很容易地通过使用python -m venv myenv来完成,然后激活我们运行的环境,

  1. (Windows) .\\myvenv\\Scripts\\activate.bat
  2. (Linux) source myvenv/bin/activate

👉入门指南

安装 Jaal 后,我们需要获取数据并调用 Jaal 中的plot函数。让我们通过玩软件包中包含的《权力的游戏》数据集来实现这一点。获取数据和绘图的完整代码如下:

这里我们首先导入Jaal主类和数据集加载函数load_got。后来,我们从包中加载了 get 数据集。这给了我们两个文件,

  1. edge_df :至少有fromto列的熊猫数据帧,表示实体之间的边关系
  2. node_df :这是一个熊猫数据帧,至少有id列,包含唯一的节点名

距离 edge_df(左)和 node_df(右)5 行。除了强制栏,重量和强度是边缘的特征。同样,性别也是节点的一个特征。

注意,edge_df 是强制的,node_df 是可选的。此外,我们可以在这些文件中包含额外的列,它们分别被自动视为边或节点特征。

接下来,我们将数据传递给 Jaal 并调用plot。这将导致控制台提示 Jaal 运行的默认本地主机地址(127:0.0.1:8050)。我们可以访问它来查看下面的仪表板,

Jaal dashboard,左边是设置面板,右边是图形。

特征

目前,仪表板由以下部分组成:

  1. 设置面板:这里我们有多个选项来玩图形数据。它还包含以下小节,
  • 搜索:可用于高亮显示图形中的一个节点
  • Filter :支持 pandas 查询语言,可用于基于节点或边特征过滤图形数据。
  • 颜色:可用于根据节点或边的分类特征对其进行着色。注意,目前只支持基数最大为 20 的特性。

2.图形:使用 visdcc 绘制的网络图。

👉例子

让我们一个接一个地看一下上面讨论的每个特性的例子。我们将使用得到的数据集。

1.搜索

第一个选项是搜索,我们可以在图中搜索特定的节点。它支持在节点标签上逐字符搜索。下面是一个我们试图搜索“Arya”的例子,

2.过滤

接下来,我们进行过滤。Jaal 支持在节点和边特性上进行搜索的选项。为此,我们提供了单独的文本区域。下面我们可以看到节点和边过滤查询的现场效果。

3.着色

最后,代替过滤,我们可能希望看到任何特征的总体分布。目前,Jaal 通过提供基于任何分类特征给节点或边着色的选项来处理这个问题。下面我们可以看到一个真人例子。

结论

本文的目的是介绍一个名为 Jaal 的新 python 包。这个包的灵感来自于几个志同道合的人最近在网络可视化上发布的消息、评论和反应。这是为了减轻我们在尝试可视化和处理网络数据时面临的一些棘手问题。希望这能有所帮助。另外,这只是 Jaal 的第一个版本,我还想添加更多的功能。为此,非常感谢任何合作或想法。下一集再见!

干杯。

LinkedIn 上与我联系,并在我的网站上阅读类似的文章。

介绍“清晰的声波梦”:用几行 Python 代码将 GAN 艺术与音乐同步!

原文:https://towardsdatascience.com/introducing-lucid-sonic-dreams-sync-gan-art-to-music-with-a-few-lines-of-python-code-b04f88722de1?source=collection_archive---------5-----------------------

让生成视听艺术变得简单和可定制

生成艺术在过去几年里取得了长足的进步。人们只需要看看互联网上发布的无数艺术品(例如这里的和这里的)就可以意识到,就艺术水平而言,机器可以说已经和人类不相上下了。这对艺术家的影响,向前发展,是值得讨论的——但我们都同意的一件积极的事情是,它为全新的视觉和听觉体验打开了大门。同样,它使得艺术创作即使是未经训练的人也能接触到。

因此,进入清醒的声波梦:一个 Python 包,只用几行代码就把艺术与音乐同步了!

宋:Saje 的覆盆子。由杰里米·托曼训练的模特举重。

重要链接

如果你想直接跳到重点,沉浸在清晰的声波梦中,这里有你需要的所有链接:

否则,如果您想进一步了解这个包是如何工作的,同时也想在这个过程中看到一些演示,请进一步阅读!

它是如何工作的

为了保持可访问性的精神,我将去掉大多数(但不是全部)解释生成模型的技术术语。相反,在准确理解音乐是如何操纵视觉效果的时候,我将关注最重要的细节。毕竟,对于那些感兴趣的人来说,网上有足够的资源来详细描述那些肮脏的细节。

通常,生成性艺术品是由一类称为生成性对抗网络(GAN)的深度学习框架产生的。Lucid Sonic Dreams 默认使用 StyleGAN2-ADA 架构——尽管这是可定制的,稍后你会看到。这些模型是在通常遵循某种“风格”的图像数据集上训练的。训练后,模型能够输出几乎无限数量的图像,这些图像与它们被训练的图像的风格相匹配。这个由贾斯汀·平克尼创作的知识库展示了来自众多预先训练好的 StyleGAN2 模型的样本输出,风格从脸型、艺术到……我的小马?

当我们深入研究这些图像是如何产生的,事情就变得有趣了。一个模型被输入一个决定输出图像的输入——在 StyleGAN2 的例子中,是一个包含 512 个数字的向量。相应地,对输入向量的微小改变将在输出图像中产生微小改变。现在,有趣的部分:如果我们从音乐中获得声波,从这些声波中提取数值(例如振幅),并将它们添加到输入向量中的值,会怎么样?清醒声波梦对视频中的每一帧都这样做,产生出随着听到的音乐而脉动和变形的艺术。

为了给予它应有的充分肯定,这个想法是由马特·西格尔曼深度音乐可视化器项目激发的。这是一个类似的 Python 实现,将音乐与由比根生成的图像同步。网上有一些其他的项目在尝试这个想法,但是没有一个(据我所知)是以 Python 包的形式出现的,也不像 Lucid Sonic Dreams 那样可以定制。

无论如何,这是对幕后发生的事情的基本概述。更多的技术细节将在下面的“调整参数”部分讨论!

使用软件包

清醒声波梦被特别设计成易于使用极其灵活。所有需要的是通常的 pip 安装…

pip install lucidsonicdreams

…后面是几行 Python 代码:

就这样,你完成了!这是用这段代码生成的一个示例视频;我建议至少看前一分半钟,看看单个组件的构建。

宋:化爱所基本上周六晚上

改变风格

只需运行以下命令,即可查看可用的默认样式:

这将打印一个完整的样式名称列表供您选择。这些风格是由之前提到的贾斯汀·平克尼[从](http://Justin Pinkney) awesome 资源库中提取的。也可以传递您自己的样式 GAN 权重,或者使用完全不同的 GAN 架构——稍后会有更多详细信息。

调谐参数

虽然这个包在默认设置下非常容易使用,但它实际上有许多参数——实际上有 30 多个——可以调整!Google Colab 上的教程笔记本详细列出了这些参数。然而,在本文中,我们将只讨论音乐操纵的基本组件,以及控制它们的最重要的参数。

用这个包,音乐控制 3 个主要的视觉组件:脉冲动作类。 Pulse,从字面上看,指的是视觉效果如何“脉动”音乐的打击乐元素。从数学上来说,这个脉冲是声波的振幅与输入矢量的临时相加的结果(即矢量在下一个视频帧中恢复正常)。同时,运动指的是视觉变形的速度。从数学上来说,这是输入向量的幅值累积相加的结果(即任何相加的都保持不变)。

“类”组件是一个有趣的组件。它指的是生成的图像中对象的标签。例如,在针对 WikiArt 图像训练的风格中,有 167 个类别,包括梵高、达芬奇、抽象画等。这些由音乐的音高控制,具体来说,12 个音高被映射到 12 个不同的类别。这些音高的单个振幅影响传递到第二个输入向量(“类别向量”)的数字,该向量确定模型生成的对象。这个想法是从前面提到的深度音乐可视化工具项目中获得的!

为了了解哪些参数是最重要的,让我们来布置完整的视频生成管道。首先,输入向量被初始化并在。这是视频的“基本动作”。参数 speed_fpm 控制该运动的速度,其中“fpm”代表“每分钟帧数”——本质上是每分钟初始化的矢量数量。对于每一个后续帧,参数 pulse_reactmotion_reactclass_react 控制音频对各个组件的操纵程度。

在模型从这些向量中生成图像后,这些图像被传递给一堆效果,这些效果也会对音乐做出反应。默认情况下,该软件包带有“对比”和“闪光”效果,与音频的打击乐元素同步。这些可以通过设置 对比度 _ 强度闪光 _ 强度 参数来切换。也可以创建你自己的自定义效果——稍后会有更多的细节。

下面是一些调整这些参数的示例代码。请注意 speed_fpm = 0 ,这样在歌曲的无声部分就没有运动。

宋:丁尼生的煎饼脚

使用您自己的风格和重量

如果您已经训练了自己的样式,或者您碰巧在网上遇到了模型权重,您可以将这些权重的文件路径作为样式参数值传递。我个人很兴奋地看到,有自己的模型权重的生成艺术家最终用这个包制作出了什么!

举个例子,你在这篇文章的标题视频中看到的(令人难以置信的惊人)视觉效果是由一个经过杰里米·托曼训练的模型生成的。这个线程描述了他的训练数据集,并包含一个权重文件的链接。以下是我用来生成视频的代码:

使用孤立的音轨

对于我的音乐同行们来说,你们很幸运,他们正在寻找一个音乐可视化工具。该软件包允许您上传孤立的音轨来控制脉冲,运动,类,对比度和闪光。如果您希望这些可视组件与特定的乐器同步,这是最理想的选择。您也可以使用这些孤立的轨道来定制效果,我们将在下一节中看到。

这是一些我用来可视化我自己制作的音乐曲目的代码。我用一个独立的打击音轨来控制脉冲,用一个独立的“合成和弦”音轨来控制类别。

你真正的音乐

创建自定义效果

除了内置的对比和闪光效果之外,Lucid Sonic Dreams 还允许您创建自己的反应式自定义效果。为此,只需创建一个接受至少 3 个参数的函数— 数组 ,它引用效果所应用到的图像; 力度 ,决定了它对音乐的反应程度;以及 振幅 ,指的是音乐在任意给定时间点的音量。然后,将这个自定义函数传递给一个effects generator对象。这里有一个非常实验性的可视化,利用了 scikit-image 的漩涡效果:

宋:叶卡捷琳娜

使用其他 GAN 架构

如果你更喜欢使用一些其他的 GAN 架构,Lucid Sonic Dreams 可以让你这样做。简单地定义一个函数,接受一批噪声向量和类别向量(NumPy 数组)作为输入,输出一批枕头图像。实际上,这个函数甚至不需要使用 GAN——它可以是将输入向量转换为图像的任何函数。

下面的代码通过使用 BigGAN 的 PyTorch 实现生成图像,复制了前面提到的深度音乐可视化工具。这是一个更加复杂的代码块,使用了一些额外的参数。注意,这需要您首先运行pip install pytorch_pretrained_biggan

歌曲:波特·罗宾逊《声音的海洋》

仅此而已!对于那些打算尝试这个包的人,我很期待看到你们创造的奇迹。

介绍米托——如何在编辑电子表格时生成熊猫代码

原文:https://towardsdatascience.com/introducing-mito-how-to-generate-pandas-code-while-editing-a-spreadsheet-96cf874b70c2?source=collection_archive---------13-----------------------

这个免费的熊猫点击式图形用户界面有什么好处吗?

Solaiman Hossen 在 Unsplash 上拍摄的照片

免责声明 :这不是一篇赞助文章。我与米托或这个库的创建者没有任何关系。这篇文章展示了该库的一个公正的概述,旨在使数据科学工具能够被更广泛的大众所使用。

数据科学工具和库的世界正在变得(或者已经)饱和。没有巨大的惊喜因素,任何新事物都很难获得关注。这就是米托引起我注意的地方。

这个库背后的想法很简单——你以电子表格的形式编辑数据集,米托自动生成 Python 熊猫代码。 有什么好的吗?嗯,是的,但是继续阅读以获得更深刻的概述。

这篇文章的结构如下:

  • 安装米托
  • 数据集加载
  • 添加和删除列
  • 过滤和排序数据
  • 汇总统计数据
  • 保存和加载分析
  • 判决

安装米托

米托方案有两个先决条件:

  • Python 3.6 或更新版本
  • Node.js

我假设你已经安装了 Python,但是节点可能是个问题。请花几分钟时间安装它,然后就可以继续了。

从这里开始,让我们为米托创建一个虚拟环境:

python3 -m venv mitoenv

现在让我们激活它:

source mitoenv/bin/activate

太好了!接下来,我们可以使用以下命令安装该软件包:

pip install mitosheet

差不多了—我们还需要 Jupyter 实验室推广经理:

jupyter labextension install [@jupyter](http://twitter.com/jupyter)-widgets/jupyterlab-manager@2

就是这样!您可以使用以下命令启动 Jupyter lab:

jupyter lab

让我们在下一节继续数据集加载。

数据集加载

加载 Jupyter 后,您可以执行以下代码来打开一个新的米托工作表:

import mitosheetmitosheet.sheet()

以下是结果输出:

图 1-创建新的米托工作表(图片由作者提供)

您必须输入您的电子邮件地址才能继续。完成后,您将看到一张空白表格:

图片 2 —新米托表(图片由作者提供)

您可以点击导入按钮加载数据集。在本文中,我们将使用著名的泰坦尼克号数据集。以下是初始加载后的样子:

图 3——米托表中的泰坦尼克号数据集(图片由作者提供)

加载一个 CSV 文件就是这么简单!米托自动在下面的单元格中编写熊猫代码。下图显示了它现在的样子:

图 4 —为数据集加载生成的 Pandas 代码(图片由作者提供)

接下来让我们看看如何添加和删除列。

添加和删除列

数据预处理中最基本的操作之一是添加和删除属性。米托通过顶部菜单中的添加列删除列按钮来实现。

让我们从添加列开始。单击 Add Col 按钮——这将在下表中添加一个任意名称的列(在我的例子中是 M )。要添加数据,您可以单击第一行并输入与 Excel 相同的公式!

下面是一个例子—如果Sex属性的值是男性,下面的公式将返回 1,否则返回 0:

图 5 —使用米托添加列(图片由作者提供)

您可以点击列名,将其更改为更合适的名称,比如IsMale。米托生成了下面的熊猫代码:

titanic_csv.insert(2, ‘M’, 0)titanic_csv[‘M’] = IF(titanic_csv[‘Sex’] == “male”, 1, 0)titanic_csv.rename(columns={“M”: “IsMale”}, inplace=True)

接下来让我们看看如何删除列。只需选择要删除的列,然后单击删除列按钮。将会出现一个类似这样的弹出窗口:

图 6 —删除带有米托的列(作者图片)

在那里,只需确认您想要删除该列。米托将为您生成以下代码:

titanic_csv.drop(‘PassengerId’, axis=1, inplace=True)

这就是添加和删除列是多么容易。接下来让我们看看如何对数据进行过滤和排序。

过滤和排序数据

很难想象没有某种过滤和排序操作的数据分析工作流。好消息是——这些在米托很容易做到。

先说过滤。当您选择一列时,会弹出一个侧菜单:

图 7-用米托过滤(图片由作者提供)

过滤器下,选择合适的选项。让我们只包括年龄列没有丢失,并且值在 40 到 42 之间的这些记录。您必须添加一个完整的组来拥有多个过滤条件,如下所示:

图 8 —米托的多重过滤条件(图片由作者提供)

这是米托在幕后写的代码:

titanic_csv = titanic_csv[((titanic_csv.Age.notnull()) & (titanic_csv[‘Age’] > 40) & (titanic_csv[‘Age’] <= 42))]titanic_csv = titanic_csv.reset_index(drop=True)

虽然有点乱,但它完成了任务。

接下来是分类。这是一个更容易实现的操作。您需要选择列并选择升序或降序选项。以下是如何根据 Fare 列对过滤后的数据集进行降序排序:

图 9 —用米托排序(图片由作者提供)

下面是生成的排序代码:

titanic_csv = titanic_csv.sort_values(by=’Fare’, ascending=False, na_position=’first’)titanic_csv = titanic_csv.reset_index(drop=True)

这就是基本的排序和过滤。接下来让我们看看另一个有趣的特性—汇总统计。

汇总统计数据

如果在任何数据分析工作负载中有一件事您会做得很多,那就是汇总统计。基本思想是打印一列最有趣的统计值,并可能显示一些数据可视化。

事实证明,米托自动做到了这一点。你所需要做的就是选择一个属性,然后点击右边菜单中的 Summary Stats 。让我们对年龄栏也这样做:

图 10-汇总统计数据-直方图(作者提供的图片)

如您所见,首先显示的是变量的分布,然后是汇总统计数据:

图 11 —汇总统计数据(作者提供的图片)

在今天结束之前,让我们再来看看米托的一个特色。

保存和加载分析

用 Excel 术语来说,用米托保存分析就像用 Python 记录宏一样。您可以通过点击顶部菜单中的保存按钮来保存任何分析。

它将弹出一个模态窗口,要求您命名分析并确认保存:

图 12 —使用米托保存分析(图片由作者提供)

要重复分析,点击重放按钮。它会要求您选择一个已保存的,如下所示:

图 13 —用米托回放分析(图片由作者提供)

如果你不想复制粘贴代码的话,重放特性可能对一些来自不同笔记本的重复操作很有用。

判决

这就足够了。我们已经讨论了最常见的特性,并在一个小数据集上进行了测试。问题仍然是——你应该使用米托吗?

作为一名数据科学家,我看不出你为什么不应该这样做,尤其是如果你精通 Excel 并想开始使用 Python 和 Pandas。米托可以让过渡过程变得容易得多。

自动代码生成功能对初级和中级 Pandas 用户也有好处,因为它让您知道是否有替代或更简单的方法来使用这个库。

总之——给米托一个机会。这是免费的,你不会有任何损失。我很想在下面的评论区听到你对这个库的看法。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

有用的链接

  1. 米托网站— https://trymito.io
  2. 米托文档—https://docs . try mito . io

了解更多信息

保持联系

使用 MongoDB 介绍 NoSQL 数据库

原文:https://towardsdatascience.com/introducing-nosql-databases-with-mongodb-d46c976da5bf?source=collection_archive---------13-----------------------

NoSQL 数据库实用指南

简·安东宁·科拉尔在 Unsplash 上拍摄的照片

MongoDB 是一个开源的非关系数据库解决方案,被归类为 NoSQL 系统,可用于 数据应用。MongoDB 于 2009 年首次推出,使用所谓的集合和文档,这些集合和文档又包含最终存储数据的各种键值对。

什么是 NoSQL 数据库?

NoSQL (“不仅仅是 SQL”)的原理最早出现在 2000 年代末,泛指所有不在关系表中存储数据的数据库,其查询语言不是 SQL 。除了 MongoDB 之外,NoSQL 数据库最著名的例子还有 Apache CassandraRedisNeo4j

由于其结构的原因,NoSQL 数据库的可伸缩性远远高于传统的 SQL 解决方案,因为它们还可以分布在不同的系统和计算机上。此外,大多数解决方案都是开源的,支持关系系统无法覆盖的数据库查询。

NoSQL 解决方案分为四类:

NoSQL 数据库分类|作者照片

  • 文档存储在一个文档中存储各种信息。例如,一个文档可以包含一天的所有数据。
  • 键值存储是非常简单的数据结构,其中每条记录都存储为一个具有唯一键的值。该键可用于检索特定信息。
  • 宽列存储将数据记录存储在列中,而不是通常的行中。它们已经过优化,可以在大型数据集中快速查找数据。
  • 图形数据库在所谓的节点和边中存储信息。这使得表示社交网络变得非常容易,例如,在社交网络中,人是个体节点,他们之间的关系被表示为边。

MongoDB 数据库的结构

MongoDB 包含了很多所谓的集合,可以和关系数据库的表相媲美。在一个集合中,可以有几个所谓的文档,它们依次对应于一个表中的记录,以此类推。真正令人兴奋和新奇的事情发生在文档本身。这就是为什么我们要仔细观察它们。

这些文档包含几个存储实际数据的键值对。这些值可以包含不同的数据类型(字符串、整数、浮点等。)同时,一个键在两个不同的文档中可以有两种不同的数据类型。在关系数据库数据模型中,这在两行一列中是不可能的。

在当前的实现中,MongoDB 只允许每个文档有 8MB 的数据大小。减去文件开销的存储空间后,没有太多的存储空间留给数据集。然而,MongoDB 使用基于 JSON 构建的二进制数据格式,这使得它比基于文本的文件格式更加内存友好。顾名思义,BSON,这种数据格式是基于它的起源(“二进制 JSON”)。

什么是 MongoDB 文件格式?

BSON 是 JSON 的二进制文件格式,并在某些方面进行了优化。原始文件格式,如 CSV、XML 或 JSON,是所谓的基于文本的格式。他们以纯文本形式存储数据。这使得它们对于我们人类来说很容易理解,但是需要相对较大的存储空间。随着近年来大数据项目变得更加突出,二进制数据格式也变得更加有趣。

这些以二进制符号存储部分甚至全部数据,使它们在存储的时间内对我们人类不可读。这意味着打开和保存这样的文件需要更多的时间,因为首先要处理信息,但是存储空间更小,查询有时更高效。BSON 文件将密钥存储为二进制值。然而,值仍然作为文本保存,而元数据以二进制存储,因此可以比文本键更快地读取。下面是一个简单的 JSON 字典和相应的 BSON 文件的例子:

正如我们所看到的,BSON 文件向原始格式添加了一些额外的元数据,比如数据类型。对于小文件来说,这可能看起来更加复杂,但是对于非常大的文件来说,通过降低读取速度,这证明了它的价值。

MongoDB 属于哪个 NoSQL 类别?

MongoDB 属于所谓的文档存储,它是 NoSQL 数据库的一个子类型。它们是非关系的,因为数据不是存储在行和列中,而是存储在文档中。与传统的关系数据库相比,文档存储是 NoSQL 中最流行的子类。该应用程序的优点包括:

  • 易于开发人员的适用性也是由于可理解的数据模型。
  • 灵活的数据模式,即使在最初创建数据库之后也可以很容易地更改。
  • 随着数据量或访问的增加,数据库的水平可伸缩性。

MongoDB 有什么优势?

与其他 NoSQL 解决方案一样,MongoDB 为大型数据集提供了许多优于传统关系数据库的优势:

  • 负载平衡:这些数据库可以分布在不同的虚拟机上,因此即使有大量的并发查询或大量数据,它们仍然保持相对较高的性能。另一方面,关系数据库由于其基本属性(ACID)而不能分布在多台机器上。因此,如果一台机器必须处理许多查询,它就必须变得更强大。在大多数情况下,这比将负载分散到一个系统上更昂贵、更复杂。
  • 灵活的数据格式:正如我们已经强调的,MongoDB 可以存储比关系数据库灵活得多的数据模式。理论上,每个键都可以有自己的数据格式。
  • 多种编程语言支持 : MongoDB 现在已经开发出来,支持多种编程语言,比如 Python、PHP、Ruby、Node.js、C++、Scala、JavaScript 等等。这使得为各种各样的应用程序项目集成数据库变得容易,并且使用他们的编程语言,而不必切换到另一种语言。

MongoDB 如何存储数据?

MongoDB 数据库实际上可以用于几乎所有可以用 JSON 格式存储数据的应用程序领域。这些可以相对容易地“翻译”成 BSON 格式并存储在 MongoDB 中。BSON 文件的结构不指定任何数据结构,并且可以存储灵活的模式。

如果我们想类比关系数据库,那么单个文档就是关系数据库中的行,即记录。BSON 文件中的字段包含某种数据类型的数据,因此最适合与表中的列进行比较。最后,具有相似信息内容和结构的文档存储在所谓的集合中,集合可以被认为是关系数据库中的表。

这方面的一个经典例子是网站上的用户移动数据。每个用户的旅程都是不同的,因此不提供固定的数据模式。例如,电子商务网站上的用户下订单并登录系统。另一方面,下一个用户会在公司的招聘栏中找到最新的工作机会。在 JSON 文件中,这可以通过键相对容易地映射,因此也存储在 MongoDB 中。在关系数据库中,相同的用例不容易映射。

其他可以想象的应用领域包括来自应用程序的后端数据,网站的内容管理系统,甚至是公司完整的数据仓库。

MongoDB 适合大数据应用吗?

如今,当试图描述这样一种现象时,每个人都在谈论大数据这个词,即公司和公共组织拥有越来越多的数据,这尤其将传统数据库推向了极限。

MongoDB 绝对是实现大数据应用的可能系统。在这种情况下,它首先给人的印象是前面提到的水平可伸缩性和灵活的数据模式。此外,它有一个存储引擎,可以非常有效地处理内存,例如压缩文档。

然而,主要的优点是 MongoDB 支持动态查询。简而言之,这意味着在查询开始之前不会创建数据查询语句。这提供了编写对当前情况做出反应的灵活程序的优势。假设您经营一家在线商店,一位客户正准备登录。只有在客户输入他的凭证并按下登录按钮后,程序才能决定在哪个文档中搜索关于客户的信息。

因此,当数据仍然需要在存储和查询之间进行更改(例如,聚合)时,MongoDB 特别适合大数据领域。

这是你应该带走的东西

  • MongoDB 是 NoSQL 数据库的一个应用。
  • 它存储所谓的集合,集合又包含以实际数据作为键值对的文档。
  • MongoDB 特别适合需要高可伸缩性、具有灵活的数据模式和存储大量数据的应用程序。

如果你喜欢我的作品,请在这里订阅https://medium.com/subscribe/@niklas_lang或者查看我的网站* 数据大本营 !还有,medium 允许你每月免费阅读 3 篇 。如果你希望有无限制的 访问我的文章和数以千计的精彩文章,不要犹豫,点击我的推荐链接:【https://medium.com/@niklas_lang/membership】每月花$5***获得会员资格**

* https://medium.com/@niklas_lang/understanding-the-backpropagation-algorithm-7a2e3cb4a69c *

介绍 notebookJS:计算笔记本中 Python 和 JavaScript 的无缝集成

原文:https://towardsdatascience.com/introducing-notebookjs-seamless-integration-between-python-and-javascript-in-computational-e654ec3fbd18?source=collection_archive---------2-----------------------

Unsplash 上由 Carlos Muza 拍摄的照片

你是否见过数据可视化,并认为在 Jupyter 笔记本中使用它会很棒?我知道我做过很多次。笔记本是试验数据可视化的最佳场所,因为它们可以在同一个地方包含所有的数据争论、预处理、图片和文档。然而,将 JavaScript 添加到 Python 笔记本中需要大量样板代码,这会变得繁琐和重复。更糟糕的是,不同的笔记本环境有不兼容的 API 用于 Python 和 JavaScript 之间的消息传递。例如,如果开发人员希望他们的库同时在 Jupyter 和 Colab 中运行,他们将不得不使用两种通信格式。

为了解决这些问题,我们创建了 notebookJS ,这是一个 Python 库,可以用一行代码集成 Python 和 JavaScript

在 Jupyter 笔记本中重用 D3 散点图代码。代码改编自https://www . D3-graph-gallery . com/graph/scatter _ animation _ start . html

背景

在您最喜欢的 web 堆栈(D3 和 React for me ❤)中编写可视化内容为开发人员提供了很大的灵活性。然而,在不同的数据集上测试代码可能会成为一个挑战。根据我的经验,我必须 1)硬编码数据集,或者 2)编写一个定制的服务器来管理数据。当试验数据集、预处理步骤或图表类型时,这些选项都不是很好。

在 Python 笔记本中进行实验很容易,因为所有的数据操作都可以内联完成,笔记本会自动跟踪计算步骤。在大多数情况下,像 Matplotlib 和 Altair 这样的 Python 库可以很容易地用来创建图表。然而,有时我们需要的可视化不能用现成的工具生成。例如,当我想探索 Auto-Sklearn 产生的 ML 管道时,我必须从头开始编写可视化。在笔记本中集成自定义可视化可能很麻烦,因为需要大量的样板代码来 1)在笔记本中运行可视化,2)在 Python 和 JavaScript 之间发送数据(详见本文 [1】)。

因为我们发现笔记本中的可视化非常有用,所以我们决定为它创建一个库。特别是,笔记本 JS :

  • 负责笔记本中所有 vis 的样板代码;
  • 从网上自动加载 JS 库
  • 支持代码分割成多个 JS 和 CSS 文件。

它是这样工作的:

笔记本

首先你要安装:

pip install notebookjs

notebookJS 的 API 非常简单。实际上,一个函数负责所有的事情: execute_js 方法执行一个 JavaScript 函数,并使用回调为 Python 和 JavaScript 之间的双向通信建立基础设施。

这些是参数:

  • library_list :字符串列表。字符串列表包含 1)JavaScript 库的 URL,2) JavaScript 代码,3) JavaScript
  • main_function : str。要调用的主函数的名称。该函数将使用两个参数调用:< div_id >,例如“#my_div”和< data_dict >。
  • 数据 _ 字典:字典。包含要传递给< main_function >的数据的字典
  • 试镜 : dict。{:}形式的字典。JavaScript 库可以使用回调与 python 对话。
  • css_list :字符串列表。包含 1)CSS 样式表的 URL 或 2) CSS 样式的字符串列表

main_function 是调用 execute_js 时运行的 JavaScript 函数。它有以下签名:

function main_function(div_id, data_dict)

举个简单的例子,我们可以使用 D3 向输出单元格添加一个圆:

加载本地库

正如我们所见,在 Python 笔记本中运行一个 JavaScript 函数只需要一行代码(不包括 JS 库定义)。我们注意到 JS 代码可以存储在一个单独的文件中,并从 Python 加载。数据也可以用 Python 加载,并使用字典结构传递给 JavaScript(内部转换为 JSON)。
例如,如果我们想要重用这个径向条形图,我们只需在 JS 文件中更改数据加载代码,然后使用 notebookJS :

Python 回调

我最喜欢的一个特性是设置 Python 回调的能力。在从事数据科学项目时,有些步骤在 JavaScript 中更容易完成(如前端和用户交互),有些步骤在 Python 中更好(数字处理、机器学习等)。有了 notebookJS ,我们可以两全其美。

让我们来看一个非常简单的例子:我们想制作一个动画,其中我们用一堆语言编写 Hello World。短语存储在 Python 中,Javascript 处理前端代码:

Javascript 绘图函数使用标识符“get_hello”每 1 秒向 Python 请求“Hello World”:

Python 等待 get_hello 并做出相应的响应:

回调函数使用回调参数“连接”到可视化:

限制

notebookJS 目前不支持 Javascript ES6 模块。这就是我们在例子中使用 D3 V3 的原因。

如果你需要 ES6,我们建议使用一个构建工具,比如 Webpack + Babel,把你的 JS 代码编译成一个文件,把 ES6 转换成老的 JS。随着项目的增长,这是管理多个库和创建优化代码的最简单的方法。有关代码捆绑的示例,请参见本页上的web pack 库设置。

最后的想法

notebookJS 是一个新工具,我们正在积极寻求关于我们应该支持哪些功能的反馈。如果您有任何问题或想要合作,请告诉我们!

我们的知识库中有更多的例子。如需现场演示,请查看我们的 Colab 笔记本

参考

[1] Jorge Piazentin Ono、Juliana Freire 和 Claudio T. Silva。"Jupyter 笔记本中的交互式数据可视化。"科学计算&工程23.2(2021):99–106。

介绍奇数帧:一维数据

原文:https://towardsdatascience.com/introducing-oddframes-jl-data-in-one-dimension-296e1389c27a?source=collection_archive---------39-----------------------

我厌倦了 DataFrames 的工作方式,所以我自己做了一个。

(图片由作者提供)

介绍

在我的数据科学经历中,有一点我一直在重复,那就是一维数据在科学计算中的实际价值。在许多情况下,采用一维方法处理数据的好处是,许多机器学习任务涉及塑造一维数据,而许多工具不喜欢采用多维数据。

也就是说,我发现维度是非常灵活的东西。取一个一维数组,在它下面放另一个一维数组,我们立刻得到(2,x)的维数。我在这里的观点是,尽管一维数组听起来更加困难,但它们同样灵活,因为它们是多维数学的构建模块。

此外,特征结构通常只是一维的。大多数时候,我发现自己在处理预测模型,这些模型需要一维输入,我认为这可能非常简单。

DataFrames.jl 无疑是处理数据的一个很好的包,但是由于这些经常遇到的一维问题,对于那些只想处理一维数据的人来说可能有点多。我喜欢将 DataFrames 看作是美化了的 JSON 数据,而 DataFrames.jl 包通过将 DataFrames 中的数据矩阵化和基于轴化,已经将 data frames . JL 包的形状和矩阵提升到了一个全新的水平。这是处理数据的一个很好的方法,因为如果需要的话,我们可以获得一维方法的优势和多维方法的灵活性。

然而,DataFrames.jl 对于这门语言的新手来说可能也不是一个容易上手的包。DataFrames.jl 是非常根深蒂固的,并集成到 Julian 生态系统和方法论中,通常遵循当今 Julia 包的许多典型语法和方法论。虽然像条件屏蔽和序列类型这样的好东西可能会丢失,但 DataFrames 通过使用在整个 Julia 中扩展的相同的内置方法来弥补它。如果你想了解更多关于如何使用 DataFrames.jl 的知识,我有一整篇文章,你可以在这里找到:

然而,我对这种方法的问题是,我认为它通常需要生态系统的开发,而不是单个软件包的开发。要明确的是,这并不奇怪或什么;这是一种常见的做法。然而,正因为如此,我们现在缺少了许多在 Julia 生态系统中有待进一步开发的特性。换句话说,在很多情况下,包都在等待实现新特性,直到其他包分支完成!

如果你想查看 OddFrames 库并了解更多,你可以在这里查看:

https://github.com/ChifiSource/OddFrames.jl

如果你想看一个有输出和索引的酷笔记本,你可以看看这里:

https://github.com/emmettgb/Emmetts-DS-NoteBooks/blob/master/Julia/OddFrames Output.ipynb

奇数帧类型

在我创建一个处理一维数据的伟大包的过程中,我希望它混合了许多概念,而且真正展示了 Dictionary 数据类型的威力。使用像字典这样的基本数据类型有很多不同的优点。一个很棒的事情是,类型的分派通常可以非常简单,只需将迭代器连接到字典子元素。

我认为这是处理这种带标签数据的一种非常酷的方式,因为它并没有脱离语言的核心,而是围绕语言的核心创建了一个包装器,以便更有效地处理数据。我将首先展示 OddFrame 类型的构造函数,它也包含一个内置的用于查看 OddFrame 的 _head()方法。这是从 Pandas 方法开始的地方,因为我还计划实现 tail()以便有效地查看数据。我们将从看构造函数开始,然后看一下 _head(),因为我想更多地谈论它。

mutable struct OddFrame{head} <: AbstractOddFrame
    lookup::Dict
    head::head
    function OddFrame(lookup::Dict)
        head(count; style = "classic") = _head(lookup, count, style = style)
        new{typeof(head)}(lookup, head)
    end

这基本上是一个在创建基本 OddFrame 类型之前允许传递字典的调用。这也将接收 head()方法,如下所示:

function _head(lookup::Dict, count::Int64 = 5; style::String = "classic")
    thead = "<thead>
<tr>"
    tbody = "<tbody>"
    [thead = string(thead, "<th>", string(name), "</th>") for name in keys(lookup)]
    thead = string(thead, "</thead>")
    cols = values(lookup)
    features = [push!(val) for val in cols]
    for i in 1:length(features[1])
        obs = [row[i] for row in features]
        tbody = string(tbody, "<tr>")
        [tbody = string(tbody, "<td>", observ, "</td>") for observ in obs]
        tbody = string(tbody, "</tr>")
    end
    tbody = string(tbody, "</tbody>")
    compisition = string(_css,"<table class = \"", style, "\">",
     thead, tbody,"</table>")
    display("text/html", compisition)
end

这基本上是一种算法,将这些值放入 HTML 表中。表格也有 CSS 样式,我认为看起来不错。在一个新的 OddFrame 上调用 head 输出,我们可以看到这是什么样子:

d = OddFrame(Dict(:A => [1, 2, 3, 4], :B => [5, 10, 15, 20], :C => [5, 10, 15, 20]))
d.head(5)

(图片由作者提供)

这种类型的课程附带了一些基本的方法和迭代器。现在可用的函数方法是 drop(),以及两个迭代器 eachcol()和 eachrow(),这两个方法都来自 DataFrames.jl。

索引

OddFrames.jl 包最初开发的很大一部分是索引。我发现 DataFrames.jl 中有一点特别烦人,那就是索引。此外,Python 的 Pandas 缺少一些我非常想念的方法,即条件屏蔽,这使得过滤比我习惯的方法有所下降。如您所料,您可以索引 OddFrame 的符号来调用查找字典中的键:

df[:B]

这个调用是这样分派的:

getindex(od::OddFrame, col::Symbol) = od.lookup[col]

与 DataFrames.jl 不同,这里还有字符串的语法,以避免必须做符号(“带空格的字符串”)的事情,我认为这很棒:

getindex(od::OddFrame, col::String) = od.lookup[Symbol(col)]

如前所述,我经常从 Pandas.py 模块中错过的东西是使用遮罩进行索引的能力。我觉得这太棒了,我第一次使用它时,它的力量让我惊叹不已。我最后用这个在奇数帧中复制了那个语法:

function getindex(od::OddFrame, mask::BitArray)
    [if mask[i] == 0 drop(od, i) end for i in 1:length(mask)]
end

这将需要一个 BitArray,它是跨向量或一维数组的条件运算符的返回。所以现在我们可以这样做一个数据帧:

d = OddFrame(Dict(:A => [1, 2, 3, 4], :B => [5, 10, 15, 20], :C => [5, 10, 15, 20]))

(图片由作者提供)

并使用任何基于元素的布尔运算符,例如。>:

d[d[:A] .> 2]

然后有这样的回报:

(图片由作者提供)

很酷,对吧?

我谈了很多为什么我喜欢这个,因为不久前我在一个熊猫倒计时中做了一个熊猫专题。你可以在这里查看:

</20-great-pandas-tricks-for-data-science-3a6daed71da0>

结论

jl 当然是一个很酷的概念,我对此非常兴奋!我认为它肯定会对美丽的 JuliaData 生态系统做出贡献,我认为像我这样的用户可能会发现这个包有用而且有趣。也就是说,我确实想在 OddFrames 包中实现许多新的东西,比如更好的显示、更多的调度、更多的功能,以及对已经提供的内容进行更多的简化。

介绍 open HAC——用于数字生物标记分析和机器学习的开源工具包

原文:https://towardsdatascience.com/introducing-openhac-an-open-source-toolkit-for-digital-biomarker-analysis-and-machine-learning-6e107c4524ad?source=collection_archive---------25-----------------------

用于人体活动分类研究和模型创建的新视频分析平台。

开放人类活动分类( OpenHAC )是一个开源用户界面,用于数字生物标记提取、分析和探索,并带有构建、评估和部署机器学习分类器的工具。它建立在现有的软件包上,用于量化行为特征和组装机器学习框架。我这个项目的目标是:1)让所有研究人员、开发人员、学者和公民科学家都可以进行数字生物标记研究,以推进健康的数字测量,并创建人类活动表型分析的新工具;2)创建一个个人社区,致力于为人类健康构建具有临床和学术意义的技术解决方案。

数字生物标记提取

OpenHAC 中可用的数字生物标记功能目前包括面部活动、眼球运动、运动模式、身体关键点和心率。

脸-头-凝视

面部、头部和凝视数据依赖于 OpenFace 进行测量,这些数据被前馈到 OpenDBM,以获得临床和学术相关的行为特征。

open face:【https://github.com/TadasBaltrusaitis/OpenFace

open DBM:https://github.com/AiCure/open_dbm

数据收集

输出

身体姿势

身体部位包括头部、手臂和腿部的定位,总共 15 个部位。OpenHAC 依赖于 OpenCV 的图像处理和 OpenPose 库中使用的预训练模型。

https://opencv.org/

打开姿势:https://github.com/CMU-Perceptual-Computing-Lab/openpose

数据收集:

输出

心率

OpenHAC 的心率测量基于 habom2310 的工作成果。使用心率功能将提取每分钟的心跳数和每帧的准确度。

使用摄像头测量心率:https://github . com/habom 2310/使用摄像头测量心率

数据收集

输出

人类活动分类

通过 OpenHAC,还可以使用其机器学习分类工具来创建、分析和提取新的数字生物标记特征。将行为特征与手动分类相结合,用户可以为诸如疼痛、困倦、活动水平和非典型运动等行为表现创建有效的分类器。

OpenHAC 使用由 Scicit-Learn 支持的 PyCaret 库来比较、创建、保存、加载和部署机器学习模型。使用 OpenHAC 的图形用户界面,创建人类活动分类器的过程简单明了。

设置数据并比较多个模型

OpenHAC 使用 PyCaret 的函数来初始化创建管道的训练环境。然后,它可以使用交叉验证来训练和评估 PyCaret 库中所有估计器的性能。

选择分类器并评估性能

OpenHAC 可以训练和评估 PyCaret 库中的任何模型。图用于分析和解释基于维持数据的模型。

预测并保存

OpenHAC 在整个数据集上训练模型,然后分配预测标签和分数(预测类的概率)。我们的转换管道和经过训练的模型对象被保存为 pickle 文件供以后使用。

对于对人类活动分类感兴趣的人来说,OpenHAC 可以是一个很好的工具。它仍在发展中,因此可以从那些愿意帮助它成长的人那里获益。如果你有兴趣参与 OpenHAC 项目,请通过hagencolej@gmail.com联系我。谢谢大家的支持!!

OpenHAC 的代码可以在 GitHub 上找到:https://github.com/chags1313/OpenHAC

OpenHAC 的 wiki 可以帮你入门:https://github.com/chags1313/OpenHAC/wiki

引入压缩 BERT,将自然语言处理的训练速度提高 2 倍

原文:https://towardsdatascience.com/introducing-packed-bert-for-2x-faster-training-in-natural-language-processing-eadb749962b1?source=collection_archive---------11-----------------------

思想和理论

用于更高效训练的新 BERT 打包算法

作者:马里奥·迈克尔·克雷尔博士马特伊·科塞克

图片作者。

通过使用一种新的打包算法,我们在训练 BERT-Large 时将自然语言处理的速度提高了 2 倍以上。我们的新打包技术消除了填充,从而显著提高了计算效率。

我们怀疑这也可以应用于基因组学和蛋白质折叠模型以及其他具有偏斜长度分布的模型,从而在不同的行业和应用中产生更广泛的影响。

我们在一篇新论文[1]中介绍了 Graphcore 的高效非负最小二乘直方图打包算法(或 NNLSHP)以及我们应用于打包序列的 BERT 算法。

由于序列填充造成的 NLP 中的计算浪费

在我们最近向 ml perf 提交的基准测试中,我们开始研究优化 BERT 训练的新方法。我们的目标是开发实用的优化方法,以便在实际应用中轻松采用。BERT 作为这些优化的重点模型之一是一个自然的选择,因为它广泛应用于工业和我们的许多客户。

我们惊讶地发现,在我们自己的使用维基百科数据集的 BERT-Large 训练应用程序中,数据集中 50%的标记是填充的——这导致了大量的计算浪费。

填充序列以使它们长度相等是 GPU 常用的方法,但我们认为值得尝试一种不同的方法。

序列的长度变化很大,原因有两个:

  1. 维基百科的基础数据显示了文档长度的巨大差异
  2. BERT 预处理本身随机减小被组合以生成训练序列的提取文档的大小

将长度填充到最大长度 512 会导致所有标记的 50%是填充标记。用实际数据替换 50%的填充数据可以在相同的计算量下多处理 50%的数据,从而在最佳条件下实现 2 倍的速度提升。

图 1:维基百科数据集分布。图片作者。

这是维基百科特有的吗?号码

好吧,那它是特定于语言的吗?号码

事实上,偏斜的长度分布无处不在:在语言、基因组学和蛋白质折叠中。图 2 和图 3 显示了 SQuAD 1.1 数据集和 GLUE 数据集的分布。

图 2:最大序列长度为 384 的 SQuAD 1.1 BERT 预训练数据集序列长度直方图。图片作者。

图 3:最大序列长度为 128 的粘合数据集序列长度直方图。图片作者。

我们如何在避免计算浪费的同时处理不同的长度?

当前的方法需要针对不同长度的不同计算内核,或者工程师需要通过编程移除填充,然后针对每个注意块和损失计算重复地添加回填充。通过放大代码并使其更复杂来节省计算并不吸引人,所以我们寻找更好的东西。难道我们不能把多个序列放在一个最大长度的包里一起处理吗?事实证明,我们可以!

这种方法需要三个关键因素:

  1. 一种有效的算法来决定将哪些样本放在一起以具有尽可能少的剩余填充
  2. 调整 BERT 模型以处理包装而不是序列
  3. 以及调整超参数

包装

起初,你似乎不太可能非常有效地打包像维基百科这样的大型数据集。这个问题通常被称为装箱问题。即使打包限制为三个或更少的序列,产生的问题仍然是强 NP 完全的,缺乏有效的算法解决方案。现有的启发式打包算法没有前途,因为它们的复杂性至少为 O ( n log ( n )),其中 n 是序列的数量(维基百科的大约 16M)。我们感兴趣的是可以扩展到数百万个序列的方法。

两个技巧帮助我们大幅降低了复杂性:

  1. 将一个包中的序列数量限制为三个(对于我们的第一个解决方案)
  2. 仅在序列长度的直方图上操作,每个出现的长度有一个仓

我们的最大序列长度是 512。因此,移动到直方图将维度和复杂性从 1600 万个序列减少到 512 个长度计数。允许一个包中最多有三个序列,将允许的长度组合数量减少到 22K。这已经包括了要求序列在包中按长度排序的技巧。那么为什么不试试 4 个序列呢?这将组合的数量从 22K 增加到 940K,这对我们的第一个建模方法来说太多了。此外,深度 3 已经实现了非常高的包装效率。

最初,我们认为在一个包中使用三个以上的序列会增加计算开销并影响训练期间的收敛行为。然而,为了支持推理等需要更快、实时打包的应用,我们开发了高效的非负最小二乘直方图打包(NNLSHP)算法。

非负最小二乘直方图打包

装箱经常被公式化为一个数学优化问题。然而,对于 1600 万(或更多)的序列,这是不实际的。光是问题变量就超过了大多数机器的内存。基于直方图的方法的数学程序非常简洁。为了简单起见,我们决定使用直方图矢量 b 的最小二乘法( Ax=b )。我们扩展了它,要求策略向量 x 为非负,并增加权重以允许少量填充。

棘手的部分是战略矩阵。每一列的最大和为 3,并编码哪些序列被打包在一起以精确匹配所需的总长度;我们的情况是 512。这些行对每个可能的组合进行编码,以达到总长度。策略向量 x 就是我们要找的,它描述了我们选择 20k 个组合的频率。有趣的是,最后只选出了 600 个左右的组合。为了得到一个精确的解,在 x 中的策略计数必须是正整数,但是我们意识到一个近似舍入的解,只要有非负的 x 就足够了。对于近似解,可以使用一个简单的开箱即用的求解器在 30 秒内得到结果。

图 4:序列长度 8 和包装深度 3 的策略矩阵示例。行代表打包在一起的长度为 1-8 的序列,列代表一个包中所有可能的长度组合,没有特定的顺序。图片作者。

最后,我们必须修复一些没有被分配策略的样本,但这些样本是最小的。我们还开发了一个变量求解器,它强制每个序列都被打包,可能带有填充,并且具有依赖于填充的权重。花费的时间长得多,解决方案也好不到哪里去。

最短包装优先直方图包装

NNLSHP 为我们提供了充分的包装方法。然而,我们想知道我们是否可以从理论上得到一个更快的在线方法,并消除只将 3 个序列放在一起的限制。

因此,我们从现有的打包算法中获得了一些灵感,但仍然专注于直方图。

我们的第一个算法,最短打包优先直方图打包(SPFHP)有四个组成部分:

  1. 从最长序列到最短序列对直方图的计数进行操作
  2. 如果当前序列长度不适合任何包,则开始一组新的包
  3. 如果有多个匹配,取序列长度之和最短的包装,分别修改计数
  4. 再次检查剩余计数是否合适

这种方法最容易实现,只需要 0.02 秒。

一种变型是取序列长度的最大和,而不是最短和分裂计数,以获得更完美的拟合。总的来说,这并没有改变效率,但是增加了代码的复杂性。

最短包装优先直方图包装的工作原理。作者制作的动画。

维基百科,1.1 小队,胶水包装结果

表 1、2 和 3 显示了我们提出的两种算法的装箱结果。打包深度描述了打包序列的最大数量。封装深度 1 是基线 BERT 实现。当没有设定限制时,最大出现填料深度用一个附加的“max”表示。包数描述了新打包数据集的长度。效率是打包数据集中真实令牌的百分比。填充系数描述了相对于填充深度 1 的潜在加速。

我们有四个主要观察结果:

  1. 分布越偏,包装的好处就越大。
  2. 所有数据集都受益于打包。有些甚至超过 2 倍。
  3. 当填充深度不受限制时,SPFHP 效率更高。
  4. 对于最多 3 个打包序列,NNLSHP 越复杂,效率越高(99.75 对 89.44)。

表 1:维基百科上推荐的打包算法(SPFHP 和 NNLSHP)的关键性能结果。图片作者。

表 2:为 SQUaD 1.1 BERT 预训练提出的打包算法的性能结果。图片作者。

表 3:为 GLUE 数据集提出的打包算法的性能结果。仅显示基线和 SPFHP 包装结果,不限制包装深度。图片作者。

伯特处理调整

关于 BERT 体系结构的有趣之处在于,大多数处理都发生在令牌级,这意味着它不会干扰我们的打包。只有四个部分需要调整:注意力屏蔽、MLM 损失、NSP 损失和准确度。

这四种处理不同数量序列的方法的关键是向量化和使用可以连接的最大数量的序列。为了引起注意,我们已经有了一个遮罩来处理填充。从下面的 TensorFlow 伪代码中可以看出,将此扩展到多个序列非常简单。这个概念是,我们确保注意力被限制在单独的序列上,不能超出这个范围。

注意掩码代码示例。

图 5:示例 0-1 掩码

对于损耗计算,原则上我们拆开序列并计算单独的损耗,最终获得序列(而不是包)的平均损耗。

对于 MLM 损失,代码如下所示:

损失计算代码示例。

对于 NSP 损耗和精确度,原理是相同的。在我们的公开示例中,您可以找到我们内部的 PopART 框架的相应代码。

维基百科开销和加速估计

对于我们对 BERT 的修改,我们有两个问题:

  1. 它会带来多少开销?
  2. 多少开销取决于放在一个包中的最大序列数?

由于 BERT 中的数据准备可能很麻烦,我们使用了一种快捷方式,针对多种不同的填充深度编译了代码,并比较了各自的(测量)周期。结果显示在表 4 中。使用开销,我们表示由于模型的改变而导致的吞吐量减少的百分比,以支持打包(例如用于引起注意的掩蔽方案和改变的损失计算)。实现的加速是由于打包导致的加速打包因子和由于开销导致的吞吐量下降的组合。

表 4:维基百科上建议的打包算法(SPFHP 和 NNLSHP)的估计加速比较。图片作者。

多亏了矢量化技术,开销出奇地小,而且将许多序列打包在一起也没有什么坏处。

超参数调整

有了包装,我们的有效批量(平均)翻了一番。这意味着我们需要调整训练超参数。一个简单的技巧是将梯度累积计数减半,以保持与训练前相同的有效平均批量。通过使用带有预训练检查点的基准设置,我们可以看到精度曲线完全匹配。

图 6:包装和非包装处理的学习曲线与包装方法的减少批量的比较。作者图片。

准确性匹配:MLM 训练损失一开始可能略有不同,但很快赶上。这种最初的差异可能来自于注意力层的轻微调整,这种调整可能在先前的训练中偏向于短序列。

为了避免减速,有时保持原来的批量大小不变,并将超参数调整到增加的有效批量大小(加倍)会有所帮助。要考虑的主要超参数是β参数和学习率。一种常见的方法是将批处理大小加倍,这在我们的例子中会降低性能。查看 LAMB 优化器的统计数据,我们可以证明将β参数提升到填充因子的幂对应于连续训练多个批次以保持动量和速度的可比性。

图 7:应用了试探法的打包和解包处理的学习曲线比较。作者图片。

我们的实验表明,将β取 2 的幂是一个很好的启发式方法。在这种情况下,不期望曲线匹配,因为增加批量大小通常会降低样本/时期意义上的收敛速度,直到达到目标准确度。

现在的问题是,如果在实际场景中,我们真的得到预期的加速吗?

图 8:在优化设置中包装和非包装加工的学习曲线对比。作者图片。

是的,我们有!我们获得了额外的加速,因为我们压缩了数据传输。

结论

将句子打包在一起可以节省计算工作量并保护环境。这项技术可以在任何框架中实现,包括 PyTorch 和 TensorFlow。我们获得了明显的 2 倍加速,同时,我们扩展了打包算法的技术水平。

我们感兴趣的其他应用是基因组学和蛋白质折叠,其中可以观察到类似的数据分布。视觉变形器也是一个有趣的领域,可以应用不同大小的打包图像。您认为哪些应用程序会运行良好?我们希望收到您的来信!

看报纸

访问 GitHub 上的代码

谢谢你

感谢我们在 Graphcore 应用工程团队的同事傅生和 Mrinal Iyer 对这项工作的贡献,感谢 Graphcore 研究团队的 Douglas Orr 提供的宝贵反馈。

参考

[1] M. Kosec,S. Fu,M. M. Krell,打包:朝向 2 倍 NLP BERT 加速 (2021),arXiv

推出 PyTorch 加速版

原文:https://towardsdatascience.com/introducing-pytorch-accelerated-6ba99530608c?source=collection_archive---------9-----------------------

一个简单但功能强大的库,用最少的样板文件训练 PyTorch 模型

pytorch-accelerated 是一个轻量级库,旨在通过提供一个最小但可扩展的训练循环(封装在单个 训练器 对象中)来加速训练 pytorch 模型的过程,该训练循环足够灵活,可以处理大多数用例,并且能够利用不同的硬件选项,而无需更改代码。pytorch 加速的提供了一个精简的特性集,并且非常强调的简单性的透明性,使用户能够准确地理解幕后发生的事情,而不必自己编写和维护样板文件!

的主要特征是:

  • 一个简单、包含但易于定制的训练循环,在简单的情况下可以开箱即用;可以使用继承和/或回调来定制行为。
  • 处理器件布局、混合精度、 DeepSpeed 集成、多 GPU 和分布式培训,无需更改代码。
  • 使用纯 PyTorch 组件,没有额外的修改或包装,并且可以轻松地与其他流行的库互操作,如 timmtransformerstorchmetrics
  • 一个小的、简化的 API 确保现有 PyTorch 用户的学习曲线最小。

为了确保库的每个部分——包括内部和外部组件——都尽可能的清晰和简单,使得定制、调试和理解每一步幕后发生的事情变得容易;培训师的大部分行为都包含在一个单独的类中!在 Python 的精神中,没有什么是隐藏的,一切都是可访问的。

本文的目的是介绍这个库,我决定将它命名为 pytorch-accelerated (原因将在后面变得显而易见!),描述创建它背后的一些动机,并演示如何使用它来加速您的 PyTorch 开发。这篇文章的目的是而不是来破坏或比较任何现有的解决方案,因为我坚信它们都有自己的位置,并且不会因为有人说他们更喜欢库 x 中的工作方式并且更喜欢使用它而生气!

如果你想直接进入主题,或者通过实践而不是阅读来学习更多内容,快速入门指南可在 这里 获得,文档可在 这里 获得,或者查看 GitHub 上的 示例。觉得有用别忘了加星!

使用 pytorch-accelerated 训练 MNIST。

为什么另一个 PyTorch 高级 API?

作为微软 CSE 的数据智能和设计团队的一部分,我们在许多不同的领域从事广泛的机器学习项目。由于这些问题的复杂性,我们的工作通常可以被描述为应用研究——从现有的艺术方法中获得灵感,以新的有趣的方式适应和应用这些方法——同时也强调强大的软件工程实践,如SOLID;确保代码尽可能简单和可维护。

随着深度学习的使用和受欢迎程度不断上升,我们的许多项目都涉及开发深度学习解决方案,PyTorch 是我在这些情况下的首选工具。因此,我们需要一个足够灵活的解决方案来处理大量的用例,同时易于扩展,但让我们尽快跟上速度;由于我们的许多项目非常大,我们通常需要能够从第一天就利用分布式培训!由于我们通常更喜欢利用预训练的模型或现有的架构,而不是每次都从头构建模型,所以我们使用的任何东西都需要能够轻松地与包含最先进模型的其他库互操作,我个人最喜欢的是 timmtransformers

在 CSE 工作模式中,我们'与我们的客户''一起编码,在项目期间作为一个团队工作。当我们与具有不同 ML 成熟度级别的团队一起工作时,我们的许多队友都是第一次被介绍到 PyTorch,所以我们需要确保学习曲线尽可能浅;不要让他们被大量的信息淹没,充分利用我们在项目中合作的时间。我们还必须注意,我们希望客户在没有我们的情况下继续维护任何产生的解决方案,因此我们必须尽可能保持事情简单易懂和易于维护。

尽管我是这一领域中几种不同解决方案的长期用户,但我反复发现自己在一些情况下,我正在使用的现有工具不太适合我的用例,或者是由于引入的复杂性水平,或者是由于必须学习 PyTorch 之上的新工具的复杂性,或者是发现定义抽象的方式与我试图做的事情不太一致。

因此,就我个人而言,我决定创建一个非常简单的通用培训循环,以方便客户使用 PyTorch 并加速开发,同时保持我们所需的灵活性水平;尽可能利用现有工具。这被有意设计成一个非常薄的抽象,具有流线型的特性集,使得理解、修改和调试变得容易。在收到来自客户和同事的积极反馈后,我被说服在 PyPI 上为任何可能发现这种解决方案有用的人提供这种解决方案。

pytorch 加速针对的是谁?

  • 熟悉 PyTorch 但希望避免编写通用训练循环样板文件以关注训练循环中有趣部分的用户。
  • 喜欢并习惯于选择和创建自己的模型、损失函数、优化器和数据集的用户。
  • 重视简单和流线型特性集的用户,其行为易于调试、理解和推理!

什么时候不应该用 pytorch 加速?

  • 如果你正在寻找一个端到端的解决方案,涵盖从加载数据到推断的一切,帮助你选择模型、优化器或损失函数,你可能会更适合 fastai 。pytorch-accelerated 只关注训练过程,其他所有问题都由用户负责。
  • 如果你想自己编写整个训练循环,只是没有所有的设备管理问题,你可能最适合使用拥抱脸加速!虽然可以定制 训练器 的每一部分,但训练循环基本上被分解成许多不同的方法,您必须覆盖这些方法。但是,在你走之前,写那些for循环真的重要到足以保证从头再来😉。
  • 如果您正在处理一个定制的、高度复杂的用例,它不适合通常的训练循环模式,并且想要在您选择的硬件上挤出最后一点性能,您可能最好坚持使用 vanilla PyTorch 任何高级 API 在高度专业化的情况下都会成为开销!

为什么 PyTorch 需要一个高级 API?

对于那些不熟悉 PyTorch 的人来说,你可能想知道,为什么 PyTorch 甚至需要一个高级 API?它真的如此复杂以至于所有这些不同的解决方案都必须建立在它的基础上吗?如果是这样,为什么还要使用它呢?!

由于其灵活性、易于调试以及与 Python OOP 实践一致的编码风格,PyTorch 正在迅速成为 Python 中机器学习研究的首选工具。然而,尽管 PyTorch 有很多优点,但它对日常从业者来说缺少一个东西——缺少一个通用的训练循环,或“fit”功能。由于这种缺失,一些图书馆试图用各种方法来填补这一空白。

虽然缺少通用循环经常被认为是一种优势,因为它迫使从业者对培训过程的所有部分负责,这导致在每个新项目的开始都需要类似的样板代码。这导致了实现错误,并且缺乏一个公共的结构导致了不同项目中的训练循环之间的不一致性;实现可能千差万别,这使得理解和维护代码库变得困难,除非您熟悉这个项目——即使您对 PyTorch 有很好的理解!

此外,虽然 PyTorch 为组件提供了良好、清晰的抽象,使简单的应用程序易于上手,但由于引入分布式和混合精度训练、度量计算和日志记录等因素,复杂性会迅速增加;模糊教程中经常出现的“简单”风格的循环。由于必须显式管理数据向设备的传输,这本身就增加了大量的样板文件!

虽然纯 PyTorch 无疑是高度复杂的、需要大量灵活性的定制任务的最佳方法,但对于“大多数”用例来说,这种粒度级别似乎太低了。

那么,为什么叫 pytorch 加速呢?

除了本库的主要目的是帮助您更快地提高 PyTorch 的工作效率之外,它还是对本库所基于的一个重要底层组件的敬意。

至少对我来说,使用高级工具的主要动机是由于设备管理,以及在设置分布式培训时这可能导致的潜在问题。需要明确的是,在纯 PyTorch 中这样做并不太复杂,但这确实涉及到对训练脚本进行多处修改,例如:在模型周围添加不同的包装器,在进程之间同步和收集结果,确保在每个节点上设置特定的环境变量,以及使用专门的启动命令开始训练运行。

然而,2021 年 4 月,抱抱脸发布了优秀的 accelerate,将所有这些关注点封装到一个加速器对象中。这使得利用分布式培训变得非常容易,而不必将所有的专家代码引入到您的脚本中;对其如何运作保持合理的透明度。

你可能已经猜到了,我是一个即时粉丝,几乎立刻就采用了它。但是,根据设计,accelerate 不提供任何其他功能,需要用户编写和维护自己的训练循环。在一些用例之后,我注意到我的大多数加速脚本开始看起来非常相似,我开始越来越多地注意到我脑海中的一个小小的声音,它不断地提醒我,通过复制和粘贴上一个项目的代码来启动每个新项目可能不是最好的方法…

对我来说,这是巩固这些知识和创建我自己的图书馆所需要的最后一击!

pytorch-accelerated 自豪而透明地建立在 Hugging Face Accelerate 之上,后者负责设备之间的数据移动、DeepSpeed 集成以及训练配置的启动。

现在所有的问题都解决了,让我们开始吧!

入门:在 MNIST 上训练分类器

让我们从一个非常简单的例子开始,使用 MNIST,因为如果我们不这样做,我们真的会做深度学习吗?!

首先要做的是安装软件包。为了帮助我们开始,我们还包括了运行示例可能需要的任何包:

pip install pytorch-accelerated[examples]

创建培训脚本

现在,让我们创建我们的培训脚本。

首先,我们需要下载数据。在这一点上,MNIST 实际上是深度学习的对等物 Hello,World ,我们可以直接从 torchvision 做这件事;它甚至有一个内置的数据集!

import osfrom torch.utils.data import random_split
from torchvision import transforms
from torchvision.datasets import MNISTdataset = MNIST(os.getcwd(), download=True, transform=transforms.ToTensor())train_dataset, validation_dataset, test_dataset = random_split(
    dataset, [50000, 5000, 5000]
)

这里,我们使用一个标准的转换将数据转换为 PyTorch 张量,然后将数据集随机分为训练集、验证集和测试集。

现在,我们已经准备好了数据,我们需要就模型架构、损失函数和优化器达成一致。由于这是一个非常简单的任务,让我们定义一个简单的前馈神经网络,并使用 SGD 和 momentum 作为我们的优化器。由于这是一个分类任务,让我们使用交叉熵作为我们的损失函数。注意,由于交叉熵包括 SoftMax 计算,我们不需要将它作为模型架构的一部分。

from torch import nn, optimclass MNISTModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.main = nn.Sequential(
            nn.Linear(in_features=784, out_features=128),
            nn.ReLU(),
            nn.Linear(in_features=128, out_features=64),
            nn.ReLU(),
            nn.Linear(in_features=64, out_features=10),
        )

    def forward(self, x):
        return self.main(x.view(x.shape[0], -1))model = MNISTModel()
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
loss_func = nn.CrossEntropyLoss()

这通常是我们开始考虑编写训练循环的时候。然而,多亏了 pytorch 加速,我们解决了这个问题!要开始,我们所要做的就是导入训练器

from pytorch_accelerated import Trainertrainer = Trainer(
    model,
    loss_func=loss_func,
    optimizer=optimizer,
)

训练器设计用于封装特定任务的整个训练循环,将模型、损失函数和优化器结合在一起,并为训练过程的每个步骤提供要执行的行为规范。

训练器的主要入口是训练方法,它将在我们提供的数据集上运行训练和评估循环。这也是我们为训练运行设置特定配置的地方,比如训练多少个时期以及使用多少批。这也是我们管理任何问题的地方,例如学习率计划、调整我们的数据加载器或累积梯度,但由于这是一个简单的例子,我们现在将跳过这些!

trainer.train(
    train_dataset=train_dataset,
    eval_dataset=validation_dataset,
    num_epochs=2,
    per_device_batch_size=32,
)

此外, pytorch 加速的支持分布式评估,所以在我们的训练运行结束后,让我们在测试集上评估模型。由于我们在评估过程中不会计算任何梯度,所以让我们将批量加倍。

trainer.evaluate(
    dataset=test_dataset,
    per_device_batch_size=64,
)

现在我们已经看到了所需的所有关键步骤,让我们将所有这些步骤合并到一个培训脚本中:

启动培训

既然我们已经编写了培训脚本,剩下要做的就是启动培训。如上所述,我们将利用拥抱脸加速。Accelerate 提供了 accelerate CLI ,因此无论我们的底层硬件设置如何,我们都可以使用一致的命令来启动培训。

首先,我们需要为我们的培训创建一个配置。这可以通过两种方式之一来实现;我们可以为我们的系统存储一个本地配置,也可以创建一个配置文件。为了透明,我更喜欢用后者。我们可以使用以下命令来实现这一点:

accelerate config --config_file train_mnist.yaml

该命令将询问一系列问题,这些问题将用于生成配置文件。

加速配置命令的输出

回答上述问题会生成以下配置文件:

accelerate config-config _ file train_mnist.yaml生成的 train _ Mn ist . YAML 配置文件

注意:要更改此配置,建议再次运行命令,而不是直接编辑此文件!

现在,要启动培训,我们可以使用以下命令:

accelerate launch --config_file train_mnist.yaml train_mnist.py

这将产生如下所示的输出:

运行培训脚本时产生的输出

根据所使用的回调,可以定制输出的确切内容。在这里,我们只是使用训练师的默认值。

这就是我们使用 2 个 GPU 训练一个模型所需要做的一切!

关于训练循环中执行顺序的更多信息,请参见: 训练器内部发生了什么?T9

跟踪指标

您可能已经注意到,默认情况下,训练器跟踪的唯一值是每个时期的损失。这是因为适当的度量标准严重依赖于任务!让我们看看如何跟踪其他指标。

为了计算我们的指标,我们将使用torch metrics,它们是分布式培训兼容的,这样我们就不需要在计算指标之前收集来自不同流程的结果。

为此,我们可以采取两种不同的方法:

  1. 训练员的子类化
  2. 使用回调

决定采用哪种方法很大程度上取决于用户的偏好。文件中给出了以下指南:

建议使用回调来包含“基础结构”代码,这对于训练循环的操作(如日志记录)来说并不重要,但这一决定由用户根据具体的用例来判断。

由于计算指标并不影响我们的训练代码,它可能很适合回调,这意味着我们不必子类化训练器。然而,由于回调是按顺序执行的,我们必须确保这个回调会在指标被打印之前被调用!

让我们比较一下这两种方法。

训练员的子类化

虽然训练器应该在简单的用例中开箱即用,但是子类化训练器并覆盖其方法是有意的,也是被鼓励的——把基础实现想象成一组'合理的缺省值'!

训练器 有很多不同的方法可以被覆盖,在文档 这里 中有描述。要记住的主要事情是,以动词为前缀的方法,例如 create calculate 期望返回一个值,所有其他方法都用于设置内部状态(例如 optimizer.step() )

让我们创建一个训练器 的子类,它跟踪一组分类指标。在这里,我们可以看到,在每个评估批次结束时,我们更新我们的指标——为了避免重写实际的评估逻辑,我们刚刚为此调用了默认实现——然后在每个评估周期结束时计算它们。

训练器 维护一个运行历史,默认情况下用于跟踪损失,我们可以用它来跟踪我们计算的指标。当然,我们可以手动管理跟踪,但是这种方法有一个额外的好处,即包含在运行历史中的任何指标将在每个时期结束时被记录!

在我们的脚本中使用我们的新教练,我们的脚本现在看起来像这样:

使用以下方式启动:

*accelerate launch --config_file train_mnist.yaml train_with_metrics_in_loop.py*

我们可以看到,度量是在每个时期的末尾打印出来的!

在循环中运行带有指标的培训脚本时产生的输出

使用回调

对于这样一个小的调整,比如添加度量,你可能会觉得子类化训练器有点过分,并且更喜欢使用基本实现。在这种情况下,我们可以使用回调来扩展默认训练器的行为。

要创建一个新的回调,我们可以子类化 TrainerCallback 并覆盖相关的方法;这些在的文档中有描述。为了避免与训练器的方法混淆,所有回调方法都带有前缀_on

让我们创建一个新的回调来跟踪我们的分类指标:

在这里,我们可以看到代码几乎与我们在前一个例子中添加到训练器的代码相同。唯一的区别是,我们需要在培训或评估开始时手动将指标移动到正确的设备上。幸运的是,训练器通过根据上下文返回正确的设备,让我们变得简单!

要使用它,我们需要做的就是在创建时将它包含在我们传递给我们的训练师的回调列表中。因为我们想保留默认行为,所以我们在所有默认回调之前包含了这个行为。

*trainer = Trainer(
    model,
    loss_func=loss_func,
    optimizer=optimizer,
    callbacks=(
        ClassificationMetricsCallback(
            num_classes=num_classes,
        ),
        *DEFAULT_CALLBACKS,
    ),
)*

现在,我们可以将它整合到我们的培训脚本中:

像以前一样启动它:

*accelerate launch --config_file train_mnist.yaml train_with_metrics_in_callback.py*

我们将观察到与上一个示例相同的输出。

结论

希望这已经提供了关于 pytorch 加速的的介绍和足够的信息来演示如何开始你自己的用例。要了解更多信息,文档可在此处获得,更复杂的培训示例可在 GitHub 上获得。觉得有用别忘了加星!

期待更多的帖子来涵盖如何处理一些更高级的用例,以及如何在培训期间应用一些我最喜欢的 PyTorch 技巧和诀窍。

承认

pytorch-accelerated 的设计和特性背后的许多方面都受到了许多优秀库和框架的极大启发,如 fastaitimmPyTorch-lightning 和抱抱脸 accelerate 。这些工具中的每一个都对这个库和机器学习社区产生了巨大的影响,他们的影响是不言而喻的!

pytorch-accelerated 仅从这些工具中获得灵感,并且包含的所有功能都是从零开始实现的,对本库有益。唯一的例外是 examples 文件夹中的一些脚本,为了展示 pytorch-accelerated 的特性,这些脚本中的现有资源被提取和修改;这些案例都有明确的标记,并注明原作者。

我还要感谢我所有出色的 CSE 同事,他们为 pytorch 加速版提供了反馈,并就一个好的解决方案提供了一些想法!

克里斯·休斯上的是 领英

介绍 SAYN:一个简单而强大的数据处理框架

原文:https://towardsdatascience.com/introducing-sayn-a-simple-yet-powerful-data-processing-framework-ce1c89af0e47?source=collection_archive---------20-----------------------

我们新的开源框架进一步提高了数据工程工作流程的效率

那么,SAYN 是什么?简单来说,SAYN 是一个开源数据处理框架。我们(173Tech 的团队)将它建成了最简单的框架,同时保持了充分的灵活性。用户可以从多个预定义的任务类型中进行选择,并构建自己的 ETL 流程。SAYN 真的是独一无二的,不像你以前见过的任何东西。想了解更多?接着读下去!

现代分析:背景

在我们谈论更多关于 SAYN 的内容之前,让我们先快速回顾一下背景。现代分析基础设施通常围绕数据仓库组织,使用五个核心层,如下图所示:

现代分析基础架构层

关键是要有一个高效的、可伸缩的数据流程,能够轻松地支持数百个任务及其依赖项的创建和维护。有两种常见的方法来解决这个问题:

  • 使用技术工作流管理框架,如 Airflow,这可能非常复杂,需要更多的维护。
  • 采用使用 Stitch + DBT 等工具的轻量级方法,这种方法缺乏灵活性,因为它没有为定制提取或数据科学模型等 Python 流程提供流程。

如果您希望在大规模分析过程中保持高度灵活性,同时保持简单,该怎么办?事实证明,我们从未找到有效解决这些问题的数据处理框架。所以我们建造了它!

塞恩:创世纪

我们认为,在大规模维护管道时,简单性至关重要。然而,我们也认为简单不应以牺牲灵活性为代价。这就是为什么我们建立了自己的开源数据处理框架: SAYNSAYN 旨在通过简单、灵活和集中来增强分析团队的能力。它使分析团队内部对数据流程的贡献民主化,实现充分的灵活性,并通过自动化帮助节省大量时间。

SAYN 是围绕任务的概念构建的,目前为您预建了以下任务类型:

  • sql :对数据库执行 sql 查询。
  • autosql :自动化数据转换过程。您编写一个 SELECT 语句,SAYN 会为您处理表/视图的创建。它也可用于增量载荷。
  • python :执行 python 代码。
  • 复制:自动将数据从一个数据库复制到另一个数据库。
  • 更多的将会到来!

下图显示了我们通常如何在现代分析堆栈中使用 SAYN。蓝线是由 SAYN 精心设计的:

现代分析基础架构层(带 SAYN)

塞恩哲学

SAYN 是围绕三个核心信念设计的,即现代数据处理框架应该通过简单、灵活和集中来增强数据工程师和分析师的能力。这就是 SAYN 如何实现这一承诺:

简单

  • 项目结构和任务是用 YAML 定义的,这是一种非常简单的语言,通常用于配置。这具有显著的优势,每个分析师或工程师都可以轻松地为管道做出贡献,并添加新的数据流程。
  • 您可以使用命令 sayn run 执行任务的任意组合,包括您的 Python 任务,从而实现流畅高效的工作流。
  • SAYN 通过其任务类型(例如,将 SELECT 语句自动转换为表/视图,将数据从一个数据库复制到另一个数据库)和其 API(例如,预构建的数据库连接和在 Python 代码中访问的凭证选择)提供了大量自动化并降低了数据工程的复杂性。您的团队可以专注于编写逻辑代码,而不是管道代码。
  • 只需两行 YAML 和要执行的代码就可以定义任务。一般来说,你可以非常快速地与 SAYN 相处!

灵活

  • SAYN 使您能够使用 SQL 和 Python,这意味着您可以在分析领域做任何事情:数据提取、建模和数据科学。
  • SAYN 由 Jinja 提供支持,允许您轻松地使您的代码动态化。例如,在生产和开发环境之间切换。
  • 你可以定义任何你喜欢的数据库结构,SAYN 不会强迫你默认任何特定的设计。

集中

  • SAYN 可以跨整个管道使用,使您能够集中和版本控制您的 SAYN 项目中的所有分析代码。
  • 任务定义集中在 YAML 文件中,这些文件构成了 SAYN 编排的主干。

SAYN 如何工作

要了解 SAYN 有多棒,最好的方法就是实际尝试一下!SAYN 分布在 PyPi 上,使用命令行工作。使用 sayn run 命令执行。你可以用下面四行文字在两分钟内开始:

$ pip install sayn
$ sayn init test_sayn
$ cd test_sayn
$ sayn run

这将安装 sayn 包,创建一个名为 test_sayn 的 sayn 项目,将您移至项目目录,然后执行 SAYN。您应该会看到以下情况:

SAYN 运行的执行

如前所述,SAYN 项目是围绕任务概念组织的:

  • 任务定义了你的数据过程和它们之间的关系,SAYN 然后自动为你建立一个有向无环图(DAG)。
  • SAYN 支持多种任务类型。您只需通过选择一个类型来定义您的任务,定义所需的属性(如果有的话),并指定要运行的代码。
  • 可以在不同的 YAML 文件(被认为是“任务组”)中分离任务,以分离数据流程(例如,核心、营销、数据科学),并在扩展时保持项目有序。

以下是 SAYN 的一些使用案例:

  • 使用 autosql 任务的仓库内自动数据转换。这对于计算营销投资回报率等数据建模过程来说非常强大。
  • 自动将数据从运行数据库副本复制到分析集群。
  • 当提取器缺失或提取效率低下时,使用 Python 任务来补充提取工具,如 Stitch(如果不想使用第三方提取工具,则构建自己的提取管道)。
  • 使用 Python 任务创建 LTV 预测数据科学模型并将结果加载到数据仓库中。

如果你想更多地了解 SAYN 是如何工作的,可以浏览我们的教程,这是一个很好的起点。

想了解更多?

我们正在积极开发 SAYN 并且它正在一天比一天变得更好!SAYN 让我们在 173Tech 的生活变得更加轻松,它真正释放了我们的分析能力。您的团队也可以从中受益!此外,我们希望获得反馈,帮助我们将框架做得更好,所以请联系我们,我们很友好:)您可以通过 sayn@173tech.com联系我们关于 SAYN 的问题或建议。快点说!

— — — — —

这个故事最初发表于:https://www.173tech.com/insights/introducing-sayn/

介绍 Scalecast:预测库。一

原文:https://towardsdatascience.com/introducing-scalecast-a-forecasting-library-pt-1-33b556d9b019?source=collection_archive---------10-----------------------

实践教程

用许多模型按比例进行预测

约书亚·富勒在 Unsplash 拍摄的照片

在这个由三部分组成的系列中,我们将探索一个 Python 预测库,该库使用最少的代码来检查时间序列,并使用流行和众所周知的机器学习模型进行预测。其优势包括:

  • 具有自回归项的动态预测/测试集预测过程,可防止数据泄漏
  • 许多解释季节性的方法
  • 无论系列是否有差异,均可轻松获得水平结果和误差指标

第 1 部分使用这个框架来预测单个序列。第 2 部分将该方法扩展到 100 多个系列。第 3 部分回归到一个系列,但是展示了在不同集成级别上建模的灵活性。如果这是一个你喜欢并有兴趣参与和/或维护的项目,请联系 mikekeith52@gmail.com。在 GitHub 上看到它:

https://github.com/mikekeith52/scalecast

首先,要安装:

pip install --upgrade scalecast

现在,到代码。导入预测器对象:

from scalecast.Forecaster import Forecaster

接下来,导入数据并保存到 predictor 对象中。我们将使用 HOUSTNSA 系列,它衡量自 1959 年以来美国每月的新屋开工数。要将时间序列数据加载到我们称为f的预测器对象中,请使用以下代码:

import matplotlib.pyplot as plt
import pandas_datareader as pdr
df = pdr.get_data_fred('HOUSTNSA',start='1900-01-01',end='2021-05-01')
f = Forecaster(y=df['HOUSTNSA'],current_dates=df.index)

我们将在 2021 年 5 月结束该系列,以使结果具有可重复性。让我们画出时间序列。

f.plot()

作者图片

预测的一个重要部分是检查时间序列的统计特性。当前值与过去值有多大关联?数据的季节性是什么?数据是静态的吗?我们使用自相关函数(ACF)图、偏自相关函数(PACF)图和季节分解图来检验这些问题。首先,让我们看看 ACF 和 PACF 的情节。

f.plot_acf()
f.plot_pacf()
plt.show()

作者图片

作者图片

这些数据表明,当前值和过去值之间存在大量的相关性,也称为自相关,最长可达 25 个周期。第一个图是对这种相关性的简单检验;第二个图控制术语之间的相关性。

当这种模式出现时,这是一个强有力的指标,表明该序列不是静止的(其均值不会保持恒定),这使得预测变得困难,因为它部分遵循“随机行走”模式,似乎随机上下移动。解决这个问题的一种方法是转换数据,使每个值都是序列中前一个值和当前值的差。让我们来看看 ACF 和 PACF 图,这次使用diffy=True将差异数据传递给函数。

f.plot_acf(diffy=True)
f.plot_pacf(diffy=True)
plt.show()

作者图片

作者图片

虽然仍然有大量的自相关,但已经不那么多了。我们还注意到在 12 个月和 24 个月左右会出现一些季节性高峰。让我们进一步检查差异数据的季节性:

f.seasonal_decompose(diffy=True).plot()
plt.show()

作者图片

从这张图中我们可以看出,存在月度季节性,因此过去的一月份彼此相似,二月份也是如此,以此类推。残差似乎也是随机分布的。当考虑如何预处理模型和使用什么样的回归变量时,这些都是很好的信息,我们将很快对此进行讨论。

拿出一大块数据集来测试最终预测的准确性非常重要。让我们用 12 个月的时间来做这件事。我们还想预测未来 24 个月的情况。

f.set_test_length(12)
f.generate_future_dates(24)

您可能想知道调用这些方法会返回什么。实际上,它们不返回任何东西,只是简单地将信息保存在对象本身中。我喜欢这样,因为我们不必跟踪几个数据集或熊猫数据框架;所有相关信息都存储在对象中,以后可以很容易地访问。

让我们决定将哪些回归量添加到预测器对象中。从 ACF 图中,我们可以看到几个时期的现值和未来值之间存在显著的相关性;现在让我们使用 4 个过去的值(也称为滞后或自回归项)。我们也可以用第 12 和第 24 个滞后来捕捉一些季节性。

f.add_ar_terms(4) # 4 AR terms
f.add_AR_terms((2,12)) # 2 seasonal AR terms

在我们的对象中,这些回归量分别存储为“AR1”、“AR2”、“AR3”、“AR4”、“AR12”和“AR24”。本模块的美妙之处在于,所有使用 AR 术语的预测和预测制定都使用一个动态过程,用当前预测填充未来值。这防止了在其他预测应用中出现的过度拟合和数据泄漏,同时允许预测是动态的。然而,这也意味着由于在源代码中自由使用循环,一些模型评估是缓慢的。不要因此而气馁!

现在让我们对物体内的级数求差,使其静止。我们还运行了一个名为增强的迪克·富勒的统计测试来进一步检验平稳性,然后重新绘制数据。

>>> f.diff()
>>> f.adf_test(quiet=False)
>>> f.plot()
series appears to be stationary

作者图片

当像这样绘制时,该系列似乎不太容易解释,但它将比使用其原始水平更容易有效地预测。更重要的是,根据统计测试,它现在是稳定的。

除了主序列之外,diff()方法将区分所有自回归项(它识别为以“AR”标签开头的变量)。也就是说,现在让我们添加捕捉月和年的影响的回归变量。

f.add_seasonal_regressors('month',raw=False,sincos=True)
f.add_seasonal_regressors('year')

这个方法依赖于pandas.Series.dt属性和pandas.Series.dt.isocalendar()方法。默认情况下,将返回一系列整数类型,使用诸如“月”、“周”、“日”、“星期”等标签(见此处)。由于我们不一定看到任何给定年份的月份与我们的序列中的值的高低之间的直接线性关系,我们可以选择不使用月份的整数值(raw=False),而是将值转换为正弦和余弦波函数(sincos=True),这提供了一种更具周期性的模式来模拟数据,并且应该会提高准确性。另外还有dummy=True,它从回归变量中创建虚拟变量。所有这些转换都有其优缺点,我们鼓励您尝试不同的方法来指定您自己的模型。到目前为止,我们的回归变量包括前面提到的 ar 术语和三个新术语“monthsin”、“monthcos”和“year”。

我们还要添加一个 COVID19 回归量、时间趋势、与 COVID19 的组合时间趋势以及 2 和 3 次方的多项式时间趋势。

f.add_covid19_regressor() # called 'COVID19' by default
f.add_time_trend() # called 't' by default
f.add_combo_regressors('t','COVID19') # 't_COVID19'
f.add_poly_terms('t',pwr=3) # 't^2' and 't^3'

默认的 COVID19 回归变量日期范围是从华特·迪士尼世界(和许多其他知名企业)在美国关闭的那一天到 CDC 取消对接种疫苗者的口罩建议的时候,但这些日期以及以这种方式添加的大多数变量的名称都可以调整。

既然已经添加了所有的回归变量,我们就可以建模了。scalecast 模块的另一个有用部分是它能够自动调整一组不同的模型。最简单的方法是在工作目录中创建一个 Grids.py 文件。在那里,我们可以以 Python 字典的形式指定模型验证网格。每个模型将在一组验证数据上运行,这组验证数据是我们选择的正好发生在测试集周期之前的一段时间。对于给定的模型,将尝试写入网格文件的所有组合,并将推荐在验证集上具有最佳性能的组合,我们可以通过auto_forecast()方法使用它们。在 Grids.py 文件中,可以添加以下内容:

创建一个 Grids.py 文件,并将其保存在工作目录中以优化模型

请注意,对于每个要优化的模型,至少需要一个网格。

我们运行以下代码来指定一个 6 周期的验证集,并优化 8 个不同的模型:

循环调整和预测 8 个模型

我们现在已经使用多元线性回归、K-最近邻、支持向量回归、极端梯度提升树、梯度提升树、Elasticnet、多层感知器和 Prophet 模型进行了调整和预测。这些都来自流行的机器学习库:Scikit-Learn、XGBoost 和脸书先知,因此关于每一个库的文档都很丰富。

下一段代码将这些模型组合起来,以创建两个额外的预测:根据优化过程对前 3 个执行预测进行简单平均,并对所有模型进行加权平均,其中权重是根据每个模型在优化过程中各自的性能自动分配的。我们鼓励您尝试自己的组合建模,因为有很多方法可以做到这一点。

您可以组合模型来制作新模型

现在,我们有一组 10 个高度优化的模型,对这个时间序列进行预测。然而,这并不意味着它们都是好的。其中一些肯定会有一点不确定——尝试这么多的目的是找到至少两个有效的。所以,让我们根据他们各自在测试集上的均方根误差( RMSE )表现,来画出前 5 名最好的,看看他们看起来怎么样。让我们也向控制台打印一些关于每个评估模型的有趣信息(见这里为所有可能的值打印):

f.plot(models='top_5',order_by='TestSetRMSE')

这很好,我们可以看到,根据我们选择的误差度量标准,prophet 模型是最好的,但这些预测实际上告诉了我们关于住房的什么信息?没有什么明显的,因为我们区别我们的数据和单位是根据房屋逐月的变化,而不是总的新房子。让这些预测揭示任何有意义的东西需要努力。是吗?在这个模块中,实际上非常简单。让我们再看一遍这个图,除了现在我们想要水平预测,所以我们通过了level=True。我们还根据它们的水平测试集平均绝对百分比误差( MAPE )值对它们进行排序,并将更多有用的信息打印到控制台:

f.plot(models='top_5',order_by='LevelTestSetMAPE',level=True)

哇!真正的、可用的预测就是这样,考虑到我们从中获得了多少分析,而不是很多代码。根据 MAPE(K-最近邻)水平,我们最准确的模型在测试集数据上每个周期平均只偏离大约 8%。根据我们选择的两个误差指标,前 3 个模型是相同的,并且这三个模型看起来都是合理的。现在让我们将结果导出到 Excel ( 下载)。

f.export(
    to_excel=True,
    determine_best_by='LevelTestSetMAPE',
    excel_name='housing_results.xlsx'
)

总之,我们有一个 Excel 工作簿和图表,其中包含在差异和非差异水平上评估的所有预测、每个模型的统计信息、最佳预测的规范,以及测试集预测与实际值的比较。过度拟合的可能性极小,因为我们所有的预测都是动态的、经过充分验证的。使用本模块,您可以做更多的事情。请务必阅读官方 scalecast 文档并查看第 2 部分

注意:这篇博文最初是基于 scalecast 早期版本的功能编写的。我试图在这篇文章中更新代码,但有些代码可能无法在最新版本中使用。见 scalecast 最新介绍笔记本

介绍 Skippa

原文:https://towardsdatascience.com/introducing-skippa-bab260acf6a7?source=collection_archive---------9-----------------------

sci kit-了解熊猫的预处理管道

Marco MidmoreUnsplash 上拍摄的照片

摘要

任何一个数据科学家大概都很熟悉pandasscikit-learn。通常的工作流程需要在 pandas 中清理数据,并再次使用pandasscikit-learn转换器如StandardScalerOneHotEncoder等进行进一步的预处理。之后,机器学习算法被拟合(再次来自scikit-learn)。

这种方法存在一些问题:

1.开发工作流相当复杂,需要大量代码😰

2.很难在部署中重现预测工作流😩

3.减轻这些问题的现有解决方案根本不够好😞

Skippa 是一款旨在:

  • 大幅简化开发
  • 📦将所有数据清理、预处理以及模型算法打包/序列化到一个管道文件中
  • 😌重用您已经熟悉的pandas & scikit-learn中的接口/组件

Skippa 帮助您在pandas DataFrame上轻松定义数据清理和预处理操作,并将其与scikit-learn模型/算法组合成一个可执行的管道。它大致是这样工作的:

from skippa import Skippa, columns
from sklearn.linear_model import LogisticRegressionX, y = get_training_data(...)pipeline = (
    Skippa()
    .impute(columns(dtype_include='object'), strategy='most_frequent')
    .impute(columns(dtype_include='number'), strategy='median')
    .scale(columns(dtype_include='number'), type='standard')
    .onehot(columns(['category1', 'category2']))
    .model(LogisticRegression())
)
pipeline.fit(X, y)predictions = pipeline.predict_proba(X)

☝️·斯基帕并不假定能解决所有问题,也不涵盖你可能需要的所有功能,也不是一个高度可扩展的解决方案,但它应该能够为超过 80%的常规基于 pandas/sklearn 的机器学习项目提供大规模简化。

链接

跳过短文直接上趣味 par t

为什么需要 Skippa

问题 1:代码太多…

对于概念上非常简单的任务—输入缺失值、一次性编码分类值、选择列的子集、缩放等。—你需要相当多的代码。如果通常您从一个由各种数据类型的列组成的pandas数据帧开始,那么您需要对不同的列进行不同的转换,并且您的许多代码涉及选择列子集和合并转换后的数据。

你想要的基本上是一组步骤,你说:我想把这个转换应用到这些列中。要是有一个软件包能让你用这样的习惯用法编码就好了…

问题 2:复制和部署

如果您想要部署您的模型,您需要能够重现您的预处理代码,以便在预测上下文中使用。此外,除了您的酸洗模型文件,您还需要为您的拟合定标器、拟合一键编码器和其他可能的转换生成酸洗文件,因为它们是生成新数据预测所必需的!这很快变得难以维持。如果您能将所有这些逻辑保存到一个文件中就好了…

作者图片

问题 3:现有的解决方案不够好

现在,在这个课题上已经做了很多工作。在scikit-learn你有

  • 你可以用这个Pipeline将某些变形金刚链接到你的算法中
  • ColumnTransformer,您可以用它来定义不同列组上变压器的管道。

虽然我觉得这很麻烦。看看这个例子:

import numpy as np
import pandas as pd

from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
from sklearn.tree import DecisionTreeClassifier

*# this is the input dataframe*
df **=** pd**.**DataFrame({
    'favorite_color':['blue','green','red','green','blue'],
    'age': [10,15,10,np**.**nan,10],
    'target':[1,0,1,0,1]
})

*# define individual transformers in a pipeline*
categorical_preprocessing **=** Pipeline([('ohe', OneHotEncoder())])
numerical_preprocessing **=** Pipeline([('imputation', SimpleImputer())])

*# define which transformer applies to which columns*
preprocess **=** ColumnTransformer([
    ('categorical_preprocessing', categorical_preprocessing, ['favorite_color']),
    ('numerical_preprocessing', numerical_preprocessing, ['age'])
])

*# create the final pipeline with preprocessing steps and* 
*# the final classifier step*
pipeline **=** Pipeline([
    ('preprocess', preprocess),
    ('clf', DecisionTreeClassifier())
])

*# now fit the pipeline using the whole dataframe*
df_features **=** df[['favorite_color','age']]
df_target **=** df['target']

*# call fit on the dataframes*
pipeline**.**fit(df_features, df_target)

这确实有用,但是

  • 使用起来相当复杂和麻烦
  • 如果需要对多组列进行串行转换,就会遇到限制,因为每个转换器的输出是一个numpy数组,而不是一个pandas数据帧

有一个包[sklearn-pandas](https://github.com/scikit-learn-contrib/sklearn-pandas)是一个高尚的努力来补救这些问题。虽然它确实解决了一些问题,但我并不满意。

斯基帕的设计和原则

skippa 最重要的设计原则是转换的输出总是一个pandas DataFrame。为什么?因为从概念上讲,您从一个DataFrame开始,它由不同数据类型的不同列组成,需要不同的转换。使用 sklearn,转换的输出是一个numpy数组。这通常意味着您丢失了列名和数据类型(一切都变成了浮点型)。从概念上讲,当将管道链接在一起时,您希望使用列的名称和/或数据类型来引用列。只有当DataFrame在整个管道中始终用作中央数据表示时,这才是可能的。

Skippa 通过实现现有转换的定制版本来实现这个结果。现在,这种方法当然有一个缺点:这些转换不能直接使用,需要实现一个特定的包装器。这总是意味着开发成本和可维护性成本。我希望 Skippa 提供的好处能够抵消这个成本。

其他设计考虑:

  • Skippa 的目标是拥有一种语法,它是定义转换的最简单的方式。
  • Skippa 并不支持您可能需要的所有功能。目的是为大多数用例提供附加值,不是所有用例。但是仍然有一个后备方法来定义任意转换!
  • 是的,你需要学习一种稍微新的“语言”(即Skippa方法),但是我觉得这很简单,对于任何熟悉pandasscikit-learn的人来说都很容易学会。

Skippa 的工作原理

所以,在所有这些抱怨和自以为聪明之后,让我们展示一下 Skippa 的能力吧!

安装只是通过 pypi :

$ pip install skippa

导入Skippa对象和columns辅助函数:

from skippa import Skippa, columns

这个想法是你从一个pandas DataFrame开始。然后启动一个 Skippa 管道,然后使用链接命令来定义需要应用于某些列的转换。最后一步通常是来自scikit-learn的模型估计器(如分类器、回归器、聚类器)。

X, y = get_training_data(...)pipeline = (
    Skippa()
    .*<transformation-1>*(*<column-definition>*, *<optional-args>*)
    .*<transformation-2>*(*<column-definition>*, *<optional-args>*)
    ...
    .model(*<model-estimator>*(*<optional-args>*))
)
pipeline.fit(X, y)
pipeline.save('./models/mypipeline')

好,现在举个具体的例子。我们有一个pandas DataFrame X有 10 列:

  • 4 个浮点列、2 个整数列、3 个分类列和 1 个日期列
  • 浮点列和分类列中有缺失值

我们有一组标签y(0 或 1)

X 和 y 的控制台输出(图片由作者提供)

我们想做的如下

  • 删除一堆我们不需要的列
  • 估算缺失值(数值列的中值,分类列的最常见值)
  • 一键编码分类列
  • 缩放数字列
  • 拟合逻辑回归模型

我们可以用几行代码来实现:

pipe = (
    Skippa()
    .select(columns(exclude=['a', 'f', 'i', 'j']))
    .impute(columns(dtype_include='number'), strategy='median')
    .impute(columns(dtype_include='object'), strategy='most_frequent')
    .scale(columns(dtype_include='number'), type='standard')
    .onehot(columns(['g', 'h']))
    .model(LogisticRegression())
)
pipe.fit(X, y)
pipeline.save('./models/mypipeline')

我们保存的文件是一个SkippaPipeline,它是scikit-learnPipeline的子类。它包含预处理和逻辑回归的整个流水线。易于部署和重用:

df_scoring = get_scoring_data(...)my_pipeline = Skippa.load_pipeline('./models/mypipeline')predictions = my_pipeline.predict_proba(df_scoring)

因为 Skippa 管道是一个常规的scikit-learn Pipeline对象,所以你可以使用所有的标准方法,比如.fit.transform.predict.predict_proba等等。

如果我只想要预处理呢?

如果您只是对处理数据感兴趣,而不希望用建模算法完成流水线,这是完全可行的。或者,您可能只是想检查进入算法的最终数据集。使用.build()方法是可能的:

pipe = (
    Skippa()
    .select(columns(exclude=['a', 'f', 'i', 'j']))
    .impute(columns(dtype_include='number'), strategy='median')
    .impute(columns(dtype_include='object'), strategy='most_frequent')
    .scale(columns(dtype_include='number'), type='standard')
    .onehot(columns(['g', 'h']))
    .build()
)
df_processed = pipe.fit_transform(X)
df_processed.info()

关于选择列

使用columns()函数来定义转换的列子集。有几种方法可以使用它。例如,包括或排除列名列表:

  • columns(['a', 'b'])简单定义一个列名列表
  • columns(include=['a', 'b'])这相当于
  • columns(exclude=['a', 'b'])类似地,您可以取消选择列

您也可以使用sklearnmake_column_selector()功能中的dtype_includedtype_excludepattern

  • columns(dtype_include='float')选择所有浮动列
  • columns(dtype_exclude='number')取消选择所有数字列
  • columns(pattern='myprefix_*')选择从myprefix_开始的所有列

还可以加减多个列选择器!

  • columns(dtype_include='object') — columns(['c', ‘d'])选择除cd之外的所有对象列。

支持的变压器

这些是 Skippa 支持的转换。如果需要的话,它们可以是现有的scikit-learn转换器、现有的pandas.DataFrame方法或者定制实现的包装器。

  • .impute()
    sklearn 的SimpleImputer周围的包装纸。
    例子:.impute(columns(dtype_include='int'), method='medium')
  • .scale()
    包裹住 sklearn 的StandardScaler(如果type='standard')或者MinMaxScaler(如果type='minmax')。
    举例:.scale(columns(dtype_include='numeric'), 'minmax')
  • .onehot()
    sk learn 的OneHotEncoder周围的 Wrapper。
    例如:.onehot(columns(dtype_include='category'))
  • .encode_date()
    自定义转换器,用于创建特性的过时值。它应用 pandas 的pd.to_datetime()并使用结果.dt对象的属性。
    示例:.encode_date(columns(['mydate']), {'year': False, 'month': True, 'day': True})
  • .cast()T42pandas.DataFrame.astype()裹尸布。它有别名.astype().as_type()
    例如:.cast(columns(dtype_include='int'), 'float')
  • .rename()
    外裹pandas.DataFrame.rename()
    注意:没有有列说明符吗!
    例如:.rename({'a': 'name', 'b': 'age'})
  • .assign()
    外裹pandas.DataFrame.assign()
    注意:不是有列说明符吗!
    例如:.assign(y_sq=lambda df: df['y']*df['y'])
  • .apply()
    包装轮pandas.DataFrame.apply()
    例如:.apply(np.log)
  • .select()
    简单地选择列的子集。
    举例:.select(columns(dtype_exclude='object'))
  • .model()
    不是变压器而是估算器。只能作为你管道的最后一步。提供一个sklearn估算器作为参数。
    例子:.model(RandomForestClassifier(n_estimators=200, max_depth=5))
  • .concat()
    将另一个并行管道连接到当前管道。这将连接这些管线的结果要素集。
    例如:

☝️:我们的想法是继续添加变形器来获得额外的功能,但是对于任何不被支持的功能,总是可以选择使用.assign.apply方法来应用任何变形。

我渴望收到关于您的体验、意见和功能需求的反馈,所以请在 Github 中留下您的反馈或创建一个问题!

跳绳快乐!

链接

将统计学习引入传统方法

原文:https://towardsdatascience.com/introducing-statistical-learning-to-conventional-methods-d9cd77ed9ddc?source=collection_archive---------40-----------------------

采用使用 R 的数据驱动方法的防火墙动作分类

弗兰基·查马基在 Unsplash 上拍摄的照片

现在是为了行动而卷起的过去,过去是为了理解而展开的现在——威尔·杜兰特。

数据科学正在席卷技术前沿,我们逐渐见证了它在网络安全领域的影响。随着世界朝着数据驱动的方法发展,知道这是否是您问题的答案、从哪里开始以及如何着手是很重要的。

当您具备以下条件时,数据科学就会胜出:

  • 足够的历史数据可以推动准确的预测。
  • 许多因素影响结果,使得配置确定性的基于规则的算法变得繁琐。
  • 在扩展解决方案时资源短缺。

由于在网络安全和数据科学方面有一些专业经验,我对将统计学习和预测方法应用于公共防火墙日志数据集的想法很感兴趣。这个博客描述了过程、观察、推理和结果。

问题是

人们应该问的第一个问题是,一个问题是否需要机器学习来解决。机器学习并不总是解决问题的答案,有时没有数据驱动的方法也能更好地解决问题。

什么是防火墙?简单地说,防火墙保护它所驻留的服务器。防火墙的基本功能是根据一组预先配置的规则,通过检查请求的属性(如源/目标 IP 和端口、数据包和字节数、持续时间等)来阻止来自可疑网络的请求。防火墙上手动配置的规则

  1. 容易出现漏洞,事故也并不少见。
  2. 需要领域知识在防火墙上配置所有必要的规则,以保护服务器免受任何已知威胁。
  3. 需要不止一个人的时间和精力来覆盖每个潜在可疑网络的规则。

配置一组经常重叠的确定性规则变得繁琐,并且更难适应日益复杂的决策。当我们有一个识别模式的算法,而不是根据一组预先配置的规则做出决策时,零日威胁的几率会更低。

如果第一个问题的答案是肯定的,那么接下来要问的问题是,这个问题是否可以用机器学习来解决。只有拥有正确的数据和足够多的数据,才能应用机器学习。

每个防火墙通常会记录数百万条请求数据。这些日志可以潜在地用于训练机器学习模型,以学习特定的行为,该行为随后基于那些历史决策来驱动行动。

数据

我们使用来自 UCI 机器学习库的互联网防火墙日志数据集。防火墙是一个关键系统,如果操作不当,可能会导致灾难性的后果。记住这一点,我们将使用这个数据集进行实验,并找出我们是否可以实际使用它来使防火墙在没有硬编码规则的情况下采取数据驱动的行动。

关于数据集

预测器(端口、数据包、字节和运行时间)和目标(动作)的层次结构

任务是根据11 个预测器对请求进行有效分类。目标变量 Action 有四个类。

  1. 允许 —良好的流量,让它击中服务器
  2. 拒绝 —阻止请求并向发送者回复拒绝访问
  3. 放弃 —悄悄地放弃请求
  4. reset-both —请求被阻止,RST 被发送以结束连接

数据准备

1.平衡等级

在正常情况下,防火墙通常允许请求通过。结果,我们可以看到 57%的请求只属于允许类,和低至 0.0008%的请求属于重置-两者都属于类。

平衡前的类别分布和混淆矩阵

从随机森林分类器中提取的混淆矩阵显示,第四类rest-both(0.77)的误分类率比其他类高很多。我们的模型将超过 75%的重置错误分类——两个请求都被拒绝,这非常糟糕!

这是不平衡类问题的一个副作用,算法没有足够的数据来学习一个应该被归类为重置的请求是什么样子的。**

合成少数过采样技术(SMOTE) :

一种从少数类中合成新样本的数据扩充过程。该算法在特征空间中随机选择一个点 A ,并找到它的 k 个最近邻。再次随机选取这些邻居 B 中的一个,并画一条线。然后在特征空间中沿着这条线创建合成样本。

在这个过程之后,我们看到这些类在某种程度上是平衡的。我认为进一步对 action 类进行欠采样以避免任何潜在的模型偏差可能是个好主意。注意重置-平衡等级后错误分类误差从 0.77 下降到 0.13!

平衡后的类别分布和混淆矩阵

可以看出,否定的误分类误差却略有增加。欠采样会导致信息丢失,其结果是误差会有所增加。但是我们将关注于使我们的模型能够同样好地理解所有的类。

2.特征缩放

缩放前的功能摘要

像数据包(平均值约为 21.8)和字节(平均值约为 17614)这样的特征是完全不同的。像 KNN 和 SVM 这样基于距离的算法受特征范围的影响最大。因此,标准化(sd=1)非常重要,以确保距离不受不同比例的要素的影响,并且所有要素对结果的贡献都是相同的。

缩放后的功能摘要

3.特征重要性

了解哪些特性会影响动作,哪些不会,这可能会有所帮助。相关矩阵有助于我们了解这些特征中是否有高度相关的,甚至是分层的和冗余的。

字节这样的一些特性与字节高度相关(> 0.9)。已发送和字节。收到个数据包,和个数据包。发送了数据包。收到。为了避免噪声而涉及所有这些相关的特征可能是没有意义的。

特征相关性

来自随机森林分类器的特征重要性

一个随机森林分类器认为目的地。端口是最重要的特性。字节字节。派出的*和 E 失效了。时间似乎也有助于预测。请注意,在此处的预测中并未实际使用所有的重叠要素。*

有趣的是,其中一些观察结果与领域知识非常吻合。UDP 泛洪(DoS)通常通过监控不规则端口上的流量来识别。为了防止这种情况发生,防火墙被配置为只允许某些预先确定的端口上的流量。

数据建模

没有一种模式适合所有问题。因此,我们将继续在几个众所周知的分类算法上测试我们的数据,比较它们,并选择最好的一个。

我们将从简单的算法开始,如 KNN、逻辑回归、线性判别分析、朴素贝叶斯,然后将重点转移到越来越复杂的算法,如基于树的分类器、SVM 和神经网络。

1.搜索超参数范围

为了执行我们的超参数搜索,我们将不使用交叉验证,而是以 75:25 的比例随机分割数据作为训练集和验证集。找到一个能很好地拆分数据的种子是很重要的(验证误差通常略高于训练误差)。

K-最近邻居:

调谐 KNN

根据 一个标准误差规则 (mis⋍0.15).

众所周知,KNN 在高维空间中挣扎,所以最好排除不必要的特征。然而,在这种情况下,消除高度相关的特征并不影响测试误差。

随机森林:

调整随机森林

  • 使用 mtry=(2,4,6,8,10)和 nodesize=(2,4,6,8,10)的网格调谐,在列车分离时使用重复的 RF 交叉验证 OOB 误差。
  • 相对 OOB 误差箱线图表明较低的 mtry 值(<=4) and higher values of nodesize (> =4)效果不佳。用 mtry>6 和 nodesize <6.

Fine-tuning Random Forest

  • Fine-tuned again using a grid of mtry=(6,8,9,10,12) and nodesize=(2,3,4,5,6) using repeated cross validation on the train split.
  • mtry along (8,9,10,12) are doing well with nodesize=2.

The best parameters seem to be around mtry=8 and nodesize=2

神经网络再次重复这个过程是一个好主意

调谐神经网络

  • 使用大小=(2,6,9,12)和衰减=(0,0.001,0.01,0.1)的网格进行调整,并在列车分割上使用重复的交叉验证。
  • 在这种情况下,decay=0.1 显然不是一个好的选择。

最佳参数集似乎是大小=9,衰减=0.001

支持向量机:

调谐 SVM

  • 使用 cost=(10⁰,10,10,10,10⁴,10⁵)和 sigma=(10-⁵,10-⁴,10-,10-,10- ,10⁰)的网格调谐,使用列车拆分的交叉验证。
  • 成本=1 显然效果不好。(图中 10 的幂)

cost=10⁵和 sigma=10⁰周围的参数似乎是最好的选择。

2.型号选择

使用交叉验证对多次分割的误差进行平均以减少错误分类率的可变性是很重要的。考虑到模型不是在一次随机分割中选择的,而是在多次分割的过程中选择的,这确保了模型选择的更大置信度。

交叉验证也使用每个数据点在过程中的不同时间进行训练和评估。当数据集很小时,这尤其有用。

10 重交叉验证在每一重中都包括以下步骤:

  1. 对每个模型的训练数据进行内部交叉验证。这对于确保为该分割选择每个模型的最佳参数以确保公平比较非常重要。
  2. 评估折叠的测试数据,并注意分割的测试误差。
  3. 对 10 次拆分中的每一次重复这两个步骤。

相对交叉验证错误分类率的箱线图

对于这个问题,随机森林显然是表现最好的模型,而朴素贝叶斯是最差的选择。KNN 和特里斯的平均值相当,但模型可变性稍高。

3.结果

所有模型的错误分类率

随机森林——成功的模式

随机森林的混淆矩阵

  • 第一类 allow 似乎是最容易预测的,零误分类。
  • 在识别属于重置的类之间存在一些不确定性都否认
  • 拒绝作为允许的小误分类错误尤其会影响用于关键服务器的防火墙。

结论

随机森林分类器的结果非常有希望,因为这只是一个开始,是人工智能在网络安全领域可以做什么的前奏。预测可以用大质量数据集进一步改进,该数据集可能包括高级特征,如验证码失败、地理定位、请求类型加密、标题等。

该项目的 R 代码可以在 GitHub这里找到。请在 Twitter 上分享您的想法、投稿或联系。

介绍损失景观动画 Python 包

原文:https://towardsdatascience.com/introducing-the-loss-landscape-animation-python-package-2bf091a68734?source=collection_archive---------36-----------------------

从动画到直觉

作者图片

在我之前的文章可视化神经网络的优化轨迹中,我展示了一些动画图来演示神经网络的训练过程。从那以后,一些读者表达了对代码的兴趣,所以我把它移植到一个 Python 包中,并在 PyPI 上发表了它。有了这个包,您可以轻松地生成类似的绘图,开箱即用地试验默认数据集和默认模型,或者通过以 PyTorch Lightning 的风格实现一个接口来绘制您自己的数据模块和/或模型。

装置

从 PyPI 直接安装

pip install loss-landscape-anim

或者您可以直接从源代码安装。我推荐用诗词。如果你不知道什么是诗,我强烈推荐你去看看。这是一个非常简洁的依赖管理器,会让你的生活变得更加简单。一旦您克隆了这个 repo 并安装了 poem,只需在项目目录中运行下面的命令来安装依赖项。

poetry shell
poetry install

pip install -r requirements.txt没有诗,也要工作。

基本示例

使用提供的螺旋数据集和默认的多层感知器(MLP)模型,您可以直接调用 loss_landscape_anim 来获得一个示例动画 GIF,如下所示:

from loss_landscape_anim import loss_landscape_anim# Use default MLP model and sample spirals dataset
loss_landscape_anim(n_epochs=300)

在终端中以脚本的形式运行这段代码,您会看到如下内容:

作者图片

您也可以在 Jupyter 笔记本上运行它。结果应该是这样的:

作者图片

请注意,如果您在笔记本中使用它,不要忘记在顶部包含以下行:

%matplotlib notebook

这是另一个例子——MNIST 数据集上的 LeNet5 卷积网络。您可以调整许多杠杆:学习速率、批量大小、时期、GIF 输出的每秒帧数、可重复结果的种子、是否从训练好的模型加载等等。查看函数签名了解更多细节。

from loss_landscape_anim import (
    loss_landscape_anim, MNISTDataModule, LeNet
)bs = 16
lr = 1e-3
datamodule = MNISTDataModule(batch_size=bs, n_examples=3000)
model = LeNet(learning_rate=lr)

optim_path, loss_steps, accu_steps = loss_landscape_anim(
    n_epochs=10,
    model=model,
    datamodule=datamodule,
    optimizer="adam",
    giffps=15,
    seed=180102,
    load_model=False,
    output_to_file=True,
    return_data=True,  # Optional return values if you need them
    gpus=1  # Enable GPU training if available
)

MNIST 数据集上 LeNet5 的输出如下所示:

作者图片

随机和自定义方向

在我之前的文章中,我提到了为什么选择 PCA 作为优化轨迹可视化的降维方法。虽然这是一个很好的方法,但是如果您需要更多的控制并设定自己的方向,软件包也允许您这样做。你可以设置任意两个方向,可以是随机生成的,也可以是你提供的。

对于 2 个随机方向,将reduction_method设置为"random",例如

loss_landscape_anim(
    n_epochs=300, load_model=False, reduction_method="random"
)

对于您选择的两个固定方向,将reduction_method设置为"custom",例如

import numpy as np

n_params = ... # number of parameters your model has
u_gen = np.random.normal(size=n_params)
u = u_gen / np.linalg.norm(u_gen)
v_gen = np.random.normal(size=n_params)
v = v_gen / np.linalg.norm(v_gen)

loss_landscape_anim(
    n_epochs=300,
    load_model=False,
    reduction_method="custom",
    custom_directions=(u, v)
)

这是一个由两个随机方向产生的样本(与 PC 方向不同,你可以在这个高维路径的 2D 投影中看到一个奇怪的曲线):

作者图片

默认,reduction_method="pca"

自定义数据集和模型

要使用您自己的数据集和模型,请执行以下步骤:

  1. 准备好你的DataModule。参考 datamodule.py 获取示例。
  2. 定义继承了model.GenericModel的定制模型。参见 model.py 获取示例。
  3. 一旦您正确设置了您的自定义DataModulemodel,调用如下所示的函数来训练模型并绘制损失景观动画。
seed = ...
bs = ...
lr = ...
datamodule = YourDataModule(batch_size=bs)
model = YourModel(learning_rate=lr)

loss_landscape_anim(
    n_epochs=10,
    model=model,
    datamodule=datamodule,
    optimizer="adam",
    seed=seed,
    load_model=False,
    output_to_file=True
)

比较不同的优化器

正如论文可视化神经网络的损失景观中提到的,优化路径通常落入一个非常低维的空间,随机 2D 投影很可能看起来像随机行走。另一方面,不同的优化器可以在高维空间中采取非常不同的路径。因此,很难选择两个方向来有效地比较不同的优化器。

以亚当的最优值为中心。作者图片

在这个例子中,我让adam, sgd, adagrad, rmsprop从相同的权重开始。下面的两个图形共享相同的两个随机方向,但是以不同的局部最小值为中心。第一个图形以 Adam 找到的图形为中心,第二个图形以 RMSprop 找到的图形为中心。从本质上讲,这两个平面是损失情况的两个平行的 2D 切片。

第一幅图显示,当以 Adam 路径的末端为中心时,看起来 RMSprop 要去一个损失值更大的地方。但是那是一种错觉。如果你检查 RMSprop,的损失值,它实际上找到了一个比 Adam 的损失更低的局部最优值。

以 RMSprop 的最优值为中心。作者图片

这很好地提醒了我们,等高线只是一个非常高维的损失景观中的 2D 切片,等高线实际上并不反映实际路径的损失值(除了中心点,因为我故意使用它作为锚点来定位 2D 切片)。

然而,我们可以看到,在这两种特殊情况下,无论它以哪里为中心,轮廓都是凸的。这或多或少反映了优化器应该不难找到一个相对较好的局部最小值。为了更严格地度量凸性,文中提到了一种更好的方法——使用主曲率,即 Hessian 的特征值。查看论文第 6 部分的结尾,了解更多细节。

为数学概念制作动画情节是获得直觉的好方法。通过更改模型配置和数据集,您可以随意使用这里的代码。对于大型模型,损失网格的生成可能计算量很大。你可以尝试使用图形处理器,并调整损失网格的分辨率。

这里是我的一些其他文章,你可能会感兴趣

关注我并订阅我的电子邮件列表以获取新文章的更新。

感谢阅读!

介绍机器学习再现性量表

原文:https://towardsdatascience.com/introducing-the-machine-learning-reproducibility-scale-fb4b8e7f16f4?source=collection_archive---------39-----------------------

罗伯特·索林在 Unsplash 上的照片

量化机器学习的可重复性,并提出一个统一的项目可重复性排名系统

机器学习项目的可重复性是一个反复出现的话题,在许多不同的背景下被提出来——在学术界和工业界都有。有很多意见,主要集中在工具上,这很好,但会导致关注特性而不是解决具体问题。与此同时,似乎还没有做很多工作来提供一种量化给定项目的可再现性的方法,这意味着许多这些讨论仍然是抽象的,并且对于寻求一种方法来评估他们的工作并决定如何在可再现性方面改进它的从业者来说可能不太有用。

很多时候,评估重现一个给定项目的难易程度是一个巨大的挑战。这阻碍了人们在现有工作的基础上进行构建,导致轮子的重新发明,并导致对开源机器学习项目的不信任。

但不一定非要这样。在这篇文章中,我将尝试提供一个具体的 5 星级排名系统,以及一个可以添加到机器学习项目的报告,该报告可以帮助其他人了解重现他们感兴趣的项目应该有多容易。

两种不同类型的再现性

一般来说,再现性是一个来自科学领域的术语,它被定义为:

研究结果的可再现性是指当研究被复制(重复)时,通过实验或观察性研究或数据集的统计分析获得的结果应具有高度的可靠性。

在我们的例子中,我们可以将其分为两种不同类型的再现性:

  • 技术再现性
  • 科学再现性

在这里,技术再现性意味着通过运行项目的内容,我们实现了相同的输出,而科学再现性意味着实验的主张也被运行的输出所验证。

我们应该区分这些,因为在某些情况下,科学再现性可能更具定性,例如 GAN 项目,在该项目中,很难对结果进行定量比较,并且许多论文依赖于“目测”输出的质量。

另一方面,技术再现性纯粹是定量的。在 GAN 的例子中,技术再现性意味着生成运行将产生具有相同权重的模型。这可以通过比较权重来明确评估。

这凸显了另一个不同之处——技术再现性通常需要记录或硬编码随机种子来获得相同的结果。科学再现性有些相反——如果你不能用不同的随机种子得到相同的科学结果,它就不是科学可再现的。

这篇文章将关注技术的可复制性。

五星体系

五星体系为 ML 项目的可重复性设定了明确的标准。它由以下组件组成:

  1. 密码
  2. 配置
  3. 数据(+工件)
  4. 环境
  5. 估价

我认为这个顺序也与实现每个阶段的难度相对应,尽管很明显,这是有待商榷的。

可扩展性的金字塔。鸣谢:作者(DagsHub)

让我们深入了解每个阶段。

代码⭐️

含义:你的代码可以接收一个输入,端到端地运行,并产生预期的输出。这里的输入通常是数据集,但有时也可能是其他东西,比如可解释性项目中的模型。输出通常是一个模型或一些图表或指标形式的“洞察力”。

具体标准:

  1. 当接收到正确的输入时,您的代码运行无误
  2. 您有一个代码可以在其上运行的示例输入,例如,如果您的项目是一个对象检测项目,您有一些已保存或已下载的数据集,模型将在其上运行而不会出错。
  3. 对于上面的输入,多次运行代码将产生相同的输出。

有用的工具:

  1. 饭桶

实际上,许多(但不是所有)发布代码的项目都遵循这个阶段。他们有一个示例数据集,以及在该数据集上运行并返回一个包含指标的文件的代码,这些指标显示模型已经了解了它应该了解的内容。

配置⭐️⭐️

含义:您有一个明确定义的配置文件,它与您的代码一起提交,并为给定的运行定义可配置的参数。代码使用这个配置文件来设置运行中的参数,它们不是以特别的方式编写的。

具体标准:

  1. 您有一个或多个配置文件(这些文件可以是YAMLJSON或其他文件),它们包含了实验的所有可配置的参数。重要说明:这并不意味着所有的模型参数都必须出现在这个文件中,而是您特别配置的任何参数都必须出现在这里,这样就可以很容易地看到哪些参数被试验过,并且可以在现有项目的基础上修改它们。
  2. 所有非确定性函数都有一个在配置文件中设置的种子(即随机种子必须出现在配置文件中)。
  3. 该代码使用配置文件提取参数,并将它们输入到各自的函数中。这意味着,如果您有一个名为epochs的参数,其值为 5,它保存了训练模型的历元数。如果该值更改为 6,模型现在应该为另一个时期进行训练。这不一定是 Python 代码,可以通过创建 Makefile 来解决,该 Makefile 将配置参数作为命令行参数传递给代码。
  4. 相同配置的多次运行会产生相同的结果。这是对第一阶段的扩展,因为这意味着该项目对于任何一组配置参数都是可再现的,而不仅仅是在发布版本中使用的选定参数。

有用的工具:

  1. 水螅
  2. 饭桶
  3. 实验跟踪工具(例如 MLflow)

这一步并不总是作为典型项目的一部分。在许多情况下,配置是在项目的发布位置之外进行跟踪的,这意味着很难将使用的配置与直接联系起来,并且无法评估未成功生成最终结果的配置,这些配置可能会永久隐藏。

数据(+工件)⭐️⭐️⭐️

含义:你所依赖的数据和你的代码一起被管理。可以很容易地修改它,用其他数据集测试模型。如果您的项目有大量的资源需求,并且可以分成离散的步骤(例如,数据处理、培训等。)然后还跟踪每个阶段的工件,以便能够单独测试每个阶段的可再现性。

具体标准:

  1. 数据集与代码一起管理。在某些情况下,这意味着它是预先下载的,或者它可能是流式的,但是它应该存在于项目的上下文中,以这样一种方式,您可以很容易地检索它来运行端到端的实验。
  2. 记录数据集结构和要求。这意味着数据接口是清晰的,以这种方式构建其他数据集来运行实验应该是一个简单的过程。
  3. 数据很容易修改。这意味着您可以用符合标准 2 的其他数据集替换本文中使用的数据集。,并成功运行该模型。
  4. 对于资源密集型项目——项目管道被分割,中间工件与代码一起被跟踪和管理。这意味着,如果您有一个预处理步骤和一个训练步骤,那么一个协作者只能运行这两个步骤中的一个,并接收可测试的输出。

对于仅追加但历史数据从不更改的表格数据,保存生成用于定型的数据子集的查询和时间过滤器可能就足够了。中央日志记录或点击流数据就是一个很好的例子。但是在你写下这一步之前, 记住,很多时候看起来永远不会被修改的数据最终会被修改

有用的工具:

  1. DVC
  2. 莱克夫斯
  3. 哑弹
  4. Dolt —仅用于表格数据
  5. TerminusDB 仅用于表格数据

⭐️⭐️⭐️⭐️环境部

含义:您的环境以这样一种方式被跟踪和记录,即可以下载所使用的特定软件版本,并且可以设置特定硬件以实现与原始实验运行时相同的设置。实验环境是指实验运行时使用的所有软件和硬件版本。例如 PIP 包、您的 Python 版本、您使用的操作系统以及您在哪个 GPU 上运行实验。

具体标准:

  1. 你有一个使用过的所有软件包的列表。在 Python 的情况下,包可以记录在一个requirements.txt文件中。
  2. 您有一个示例环境,在该环境中项目运行时没有出现错误。实现这一点的最简单的方法是使用 Docker 映像,它也包含特定的操作系统和 Python 版本常量之类的内容。请注意,在某些情况下,尤其是在深度学习中,Docker 可能不够,您需要描述所使用的具体硬件和驱动程序版本(例如在 GPU 的情况下),因为 Docker 不是实际的 VM
  3. 如果您的项目依赖于特定的硬件,那么应该提供安装文档。这个很简单。

有用的工具:

  1. 码头工人
  2. pip freeze
  3. conda env export
  4. Python-dotenv

评估⭐️⭐️⭐️⭐️⭐️

含义:你可以很容易地试验运行结果。如果项目的产出是可操作的,即一个预测/生成产出的模型,这一点尤其重要。这可以从一个简单的 API 到一个完整的 UI,但它应该能够以一种能够在运行结果之间进行定性比较的方式处理再现的输出。

具体标准:

  1. 您可以轻松地使用项目输出模型来预测/生成来自自定义用户输入的结果。
  2. 您可以轻松地对不同数据或配置设置下不同项目运行的输出性能进行定性比较。

有用的工具:

  1. 细流
  2. 格拉迪欧

ML 再现性报告

ML 再现性报告是一个可添加到项目(另存为REPRODUCIBILITY.md)中的降价文件,提供关于项目再现性状态的简明文档。你可以从这里复制或者从这个链接下载。

再现性报告,从此处下载。鸣谢:作者(DagsHub)

# Machine Learning Reproducibility Report
This document helps provide a concise representation of the project's reproducibility ranking. ## 1\. Code 
* [ ] Runnable code for the project exists in the following project: https://dagshub.com/{user}/{project_name}/ 
* [ ] The example input is located in this link: {link_to_input} (this must be a proper link, ideally tracked as part of the project). Note: using this input in a project run should achieve the stated results without errors. ## 2\. Configuration 
* [ ] The following files include all relevant configuration parameters for the project: 
    - {params_1}.yml 
    - {params_2}.yml 
    - ... Note: make sure that changing the parameters in these files will modify the project's actual run parameters. ## 3\. Data (+ Artifacts) 
* [ ] All project data and artifacts can be found here: {link_to_project_data}. 
* [ ] The structure/schema of input data is the following: {Add data structure/schema here}. 
* [ ] If running the project is resource intensive - the project consists of the following steps: 
    1\. Data preprocessing: 
    - Code: {link to code for data processing step} 
    - Outputs: {link to output 1}, {link to output 2} 
    2\. Model training: 
    - Code: ... 
    - Outputs: ... 
    3\. ... ## 4\. Environment 
* [ ] Software package documentation: {link to `reuiqrements.txt` or equivalent file} 
* [ ] Example environment: {link to docker hub or other container registry with the environment docker image} 
* [ ] If the project uses specific hardware - the hardware needed to run the project properly: 
    - 2 V100 GPUs 
    - At least 32GB RAM 
    - ... ## 5\. Evaluation 
* [ ] To evaluate the model go to: {link to hosted Streamlit app or Google Colab notebook that enables users to perform predictions on arbitrary inputs} 
* [ ] Evaluation app code: 
    - {link to file with Streamlit app code} 
    - In order to run this locally: {link to instructions on running the streamlit app}

摘要

这篇文章试图提供具体的、可操作的步骤,任何项目所有者都可以采取这些步骤来显著提高他们项目的可重复性。我们提供的报告使其他人能够快速验证项目的再现性状态,以便根据再现性得分筛选项目。希望听到您对结构的反馈,以及对流程本身的想法

介绍合成数据社区

原文:https://towardsdatascience.com/introducing-the-synthetic-data-community-9db08d8679ed?source=collection_archive---------19-----------------------

一个充满活力的社区开创了数据科学的基本工具包

迪伦·吉利斯在 Unsplash 上的照片

根据 2017 年哈佛商业评论的一项研究,只有 3%的公司数据符合基本质量标准。根据 2020 年 YData 研究,数据科学家面临的最大问题是无法获得高质量的数据。

尽管知道数据是新的石油和最有价值的资源,但并不是每个公司、研究人员和学生都能像一些科技巨头那样获得最有价值的数据。随着机器学习算法、编码框架的快速发展,可以说人工智能中最稀缺的资源是大规模的高质量数据。

合成数据社区旨在为数据科学团队、研究人员和初学者打破障碍,释放合成数据的力量。我们相信拥有高质量的数据是真正的游戏规则改变者。

如果我们可以创建类似于最初无法访问的真实世界数据的高质量数据,会怎么样?这会开启多少无限的可能性?

什么是合成数据,为什么我们应该关注它

作者创作—原始照片由 Rawpixel 提供

在深入了解之前,让我们先了解基本的构建模块,以及为什么它们在我们的数据科学工具包中至关重要。

合成数据是人工生成的数据,不是从现实世界的事件中收集的。它复制实际数据的统计成分,不包含任何可识别的信息,确保个人隐私。如果使用得当,它可以为每个人提供大规模的高质量数据访问。

Unity 的 AI 和 ML 高级副总裁 Danny Lange,声称合成数据可以解决组织面临的最重要的问题:收集正确的数据,构建数据,清理数据,并确保数据无偏见且符合隐私法。我们完全同意。

它不仅有利于组织,也有利于个体数据科学家和研究人员。正在构建投资组合的自我驱动的数据科学家可以从大规模高质量数据的可用性中受益

合成数据比真实数据更好,因为我们可以控制我们所创造的东西:平衡、无偏见、隐私合规、无限扩张的数据。

最先进的合成器和开源软件

在合成数据社区,我们不仅宣扬合成数据的重要性;我们采取行动打破重要新兴技术的所有进入壁垒。

生成对抗网络(GAN)是一种基于深度神经网络的生成模型,是生成与真实数据集难以区分的人工数据集的有力工具。最常见的数据科学问题需要表格和时间序列数据,因此我们使用 GANs 来创建合成的表格和时间序列数据。

我们没有重新发明轮子,而是参考了在合成数据领域发表的领先的最先进的研究论文,实现了合成器,并将它们放在一个包中以方便使用。我们参考的一些研究包括:

我们说开源了吗?是的,你没听错。我们所做的所有工作都是开源的,当我们致力于向该库添加更多功能时,我们邀请您做出贡献,使该库变得更好。

无限的可能性

对研究内容不感兴趣——告诉我如何开始?

当然,打开你的终端,输入以下内容:

pip install ydata-synthetic

就是这样。您可以在一个命令中安装所有的合成器。现在,为了让您了解各种库的用法,我们包含了多个以 jupyter 笔记本和 python 脚本形式呈现的示例。

我们推荐从这个例子开始,Google Colab notebook ,它综合了信用卡欺诈数据集的少数类。

有什么问题吗?加入我们专门的 合成数据社区 Slack 空间,问走一切。我们是一群友好的人,希望互相学习,并在这个过程中成长。

你了解合成数据及其重要性。只需一行命令,您就可以使用最先进的合成器。你有一大堆例子来引导你。你有一个充满活力、充满热情的社区来共同学习和成长。

你知道这意味着什么吗?无限可能。

当所有高质量数据的壁垒都被打破,我们能完成的事情是无穷无尽的。女士们、先生们,介绍合成数据社区 —加入我们这一激动人心的旅程。

法比亚娜 是 CDOy data

用改进的数据加速 AI。

YData 为数据科学团队提供第一个数据开发平台。

用 Python 介绍金钱的时间价值

原文:https://towardsdatascience.com/introducing-the-time-value-of-money-with-python-20520ee51dfc?source=collection_archive---------17-----------------------

金钱和时间总是相互关联的。在本文中,我们将使用 Python Numpy Financial 来演示货币的时间价值示例。

迈克尔·朗米尔在 Unsplash 上的照片

金钱的时间价值是一个基本的金融概念,它告诉我们,我们今天拥有的一美元比未来承诺的一美元更有价值。这是因为我们今天可以用手头的一美元进行投资,赚取利息/资本利得。

在本文中,我将通过以下几个主题来介绍货币的时间价值:

  • 未来值
  • 现值
  • 贴现现金流
  • 现金流量折现法在年金估值中的应用

我将演示我们如何使用Python NumPy-Financial来执行所有需要的计算。

必备 Python 库

  1. NumPy-Financial——【https://numpy.org/numpy-financial/】

开源代码库

本文中的原始完整源代码可以在我的 Github Repo 上获得。如果你想用它来跟踪我的文章,请随意下载。

1.未来值

首先让我们检查一下金融环境中未来价值的定义。

未来价值是一项投资在一个或多个复利期后将增长到的价值。[来源: IFT

假设我们在银行有一笔 1000 美元的存款,年利率为 3%。1 年后,我们的存款的未来价值是多少?计算如下:

**future value (after end of 1 year) = 1000 * (1 + 0.03)**

2 年结束后的未来价值呢?

**future value (after end of 2 years) = 1000 * (1 + 0.03) * (1 + 0.03)**

因此,未来值 FV 可以表示为

作者准备的图像

让我们假设现在我们想要估计 10 年后的未来值 FV。我们可以使用Python NumPy-Financial Fv函数来处理计算。

fv 函数接受按顺序排列的四个参数:

  1. 利率——利率
  2. nper-复利数
  3. pmt —付款
  4. PV-现值

结果如下:

作者准备的图像

注意: 你可能会注意到结果有一个负号。这是因为 Numpy-Financial 函数遵循 Microsoft Excel 符号约定,该约定总是表示正的未来值,导致负的现值,反之亦然。

通过一行 Python 命令(不包括导入库),我们可以得知 10 年结束后的未来值 FV 约为 $1343.92

2.现值

现在,让我们调整一下我们的问题:如果我们计划在 10 年后有 1500 美元,年利率为 3%,我们今天应该存多少?在这里,我们寻求 1500 美元的未来付款的现值(T21)。

现值是基于特定收益率的预期收入流的当前值。(来源:维基百科)

在这种情况下,我们得到一个未来值 1500 美元,年利率为 3%。我们只需要调整我们的未来价值公式 FV,来估算现值 PV。现值的计算公式如下:

作者准备的图像

我们可以使用Python NumPy-Financial PV函数来处理计算。

由此得出的现值表明,为了在 10 年后将我们的资本增加到 1500 美元(假设年利率保持不变,为 3%),我们今天应该存入 1116.14 美元。

3.贴现现金流

现在,我们将在投资环境中扩展现值的概念。假设我们正在计划投资(如股票、债券或抵押贷款等),这将在 20 年后给我们带来 100,000 美元的未来现金流。这里的问题是,20 年后 10 万美元的未来现金价值是多少?我们应该投入多少资金来实现我们的目标?

我们所需要的只是将未来的现金流贴现为从 19 年、18 年、17 年到今天的现值。这将导致一系列贴现现金流,最后一个值是现值。

作者准备的图像

幸运的是,我们可以在一行代码中使用相同的Python NumPy-Financial Fv函数来估算 20 年后 10 万美元的未来投资现金流的现值,从而避免复杂的计算。我们假定定期利率为每年 5%。

作者准备的图像

结果显示 100,000 美元的未来现金流以每年 5%的利率贴现为 37688.95 美元的现值。

现在,让我们通过将 20 年改为 30 年来调整我们的年数。

作者准备的图像

期限越长,现值越小(23137.74 美元)。

让我们再做一次调整,将周期利率从 5%改为 10%,但周期数仍为 20 年。

作者准备的图像

随着更大的期间利率为 10%,现值已大幅下降到只有 14864.36 美元。

在任何投资中,期数和回报率是根据我们的风险承受能力和财务目标决定我们初始投资额的重要因素。

值得注意的是,虽然较高的回报率承诺我们在固定时间框架内实现财务目标的初始投资额较低,但它总是伴随着较高的风险,需要对我们的投资工具进行更彻底的研究。

4.DCF 在年金估值中的应用****

贴现现金流总是用于投资资产的估值。这里我们举一个年金估值的例子。

年金是为一个人的一生或特定时期提供固定收入流的保险合同。(来源:Annuity.org)

假设你正在考虑一个保险公司的退休年金计划。你希望退休并在接下来的 25 年里每月获得 2000 美元。如果年贴现率是 2.5%,购买这份年金需要多少钱?

****第 1–3 行:将年贴现率转换为月贴现率,因为支付是按月进行的。

****第 5–9 行:生成从第 1 个月到第 300 个月的贴现现金流(或当前现值)序列。

作者准备的图像

****第 11–12 行:合计每个月的所有现值,得到年金成本。

作者准备的图像

计算出的年金成本为 447229.15 美元。给定每年 2.5%的贴现率,你将不得不为退休年金计划支付大约 450000 美元,该计划可以在 25 年内每月支付 2000 美元。

结论

对金钱时间价值的理解有助于塑造我们的思维,尽早开始我们的财务和投资规划。通过对投资的良好管理,我们可以用最小的成本获得最大的利润。

我希望你喜欢阅读这篇文章。

参考

  1. https://ift . world/concept 1/concept-1-calculating-PV-Fv-different-cash-flow/
  2. https://en.wikipedia.org/wiki/Present_value
  3. **【https://www.annuity.org/annuities/ **
  4. https://www.investopedia.com/terms/d/dcf.asp

介绍 TigerGraph 3.2 的新地理空间布局功能:绘制新冠肺炎旅游事件地图

原文:https://towardsdatascience.com/introducing-tigergraph-3-2s-new-geospatial-layout-feature-mapping-covid-19-travel-events-fe05b2b1d1e9?source=collection_archive---------38-----------------------

如何在新冠肺炎初学者工具包中使用 TigerGraph 3.2 的地理空间布局

导言和概述

老虎图 3.2

截至 9 月 30 日,TigerGraph 已经正式发布了 3.2 版本,现在 3.2 也同样适用于 TG Cloud!要了解更多关于该版本的信息,请查看发布说明。

https://docs.tigergraph.com/v/3.2/faqs/release-notes-tigergraph-3.2

基本原理

浏览图形数据时,可以使用地图坐标数据。TigerGraph 3.2 最近发布了一个全新的地理空间可视化功能,以帮助您轻松了解您的大部分数据位于何处,并识别可能存在的任何异常。

使用的工具

  • 老虎图云
  • TigerGraph 新冠肺炎入门套件

旅程

  • 第一部分:创建您的 TigerGraph 3.2 解决方案
  • 第二部分:准备你的图表
  • 第三部分:使用地理空间可视化功能

第一部分:创建您的 TigerGraph 3.2 解决方案

首先,我们将在 TigerGraph Cloud 上设置一个 TigerGraph 3.2 解决方案。为此,导航至 https://tgcloud.io/的,并创建您的免费账户(如果您还没有的话)。

登录后,导航至“我的解决方案”选项卡,然后单击蓝色的“创建解决方案”按钮。

选择“我的解决方案”,然后单击蓝色的“创建解决方案”按钮。

您将被引导至一个四步流程来设置您的解决方案。在第一页上,确保您的 TigerGraph 版本为 3.2,然后单击初学者工具包的“新冠肺炎分析 3.2.0 版”图标。完成后,向下滚动并按“下一步”

选择 3.2 作为版本,选择“新冠肺炎分析”作为入门套件。

像往常一样,如果你想创建一个免费的解决方案,不要为第二页编辑任何东西。在第三页上,为您的解决方案定制选项。

不要更改此页面上的任何内容!

为您的解决方案定制此页面!

在最后一页,验证您输入的信息是正确的,然后按提交!设置可能需要几分钟时间。

检查一切都好,并提交

第二部分:准备图表

在开始可视化数据之前,我们需要通过 GraphStudio 加载数据。为此,在您的解决方案旁边有一个绿点之后,按下四个小框(“应用”)并选择 GraphStudio。

等到你的状态显示“准备好”

选择四个小框(“应用”),然后从下拉列表中选择“GraphStudio”

您将被重定向到 GraphStudio。登录后,点击左上角的“全局视图”,然后从下拉列表中选择“我的图表”。

在“我的图形”中,选择“加载数据”选项卡。您可以通过按下播放按钮来加载所有文件,或者只选择 PatientRoute.csv 并按下播放按钮来只加载该文件,因为我们将只显示该博客的 TravelEvent 顶点。

按左上角的播放按钮

等到它说“完成”,然后你将设置!

已成功加载 PatientRoute.csv。

注意:我们使用 TravelEvent 顶点是因为地理空间布局需要属性为纬度经度顶点

第三部分:使用地理空间可视化功能

现在你有了数据,是时候可视化它了。点击进入“浏览图表”选项卡。

单击“浏览图表”选项卡

接下来,只选择“旅行事件”顶点,并选择其中的 100 个,按下“选择顶点”按钮。

接下来,在右下角的下拉列表中选择“地理空间”。

点击右下角的“地理空间”。

瞧,顶点现在在地图上了。

已映射的 TravelEvent 顶点

恭喜+后续步骤

恭喜你。您现在可以正式使用 TigerGraph Cloud 中的最新布局功能了!既然您已经将它用于初学者工具包,请尝试将其添加到您自己的数据和解决方案中。

如果您有任何问题,请不要犹豫,在社区论坛上发表。

https://community.tigergraph.com/

再者,如果你想和其他 TigerGraph 开发者聊天,一定要加入不和。

https://discord.gg/gRHWBZNpxW

介绍变形金刚解释——变形金刚的可解释人工智能

原文:https://towardsdatascience.com/introducing-transformers-interpret-explainable-ai-for-transformers-890a403a9470?source=collection_archive---------11-----------------------

2 行中任何变压器型号的型号说明。

艾米丽·莫特在 Unsplash 上的照片

TL:DR: 《变形金刚解释》只用两行代码就把可解释的人工智能带到了《变形金刚》包中。它允许你简单地获得单词属性和这些属性的可视化。现在这个包支持所有带有序列分类头的 transformer 模型。

点击这里查看项目:https://github.com/cdpierse/transformers-interpret

介绍

模型可解释性和最先进的研究似乎一直在进行一场拔河比赛。复杂的模型很难解释,而简单的模型往往更容易理解。

可解释的人工智能是当今机器学习中最重要的新兴子领域之一。出于道德、实践和——在企业界——法律的原因,我们必须能够解释所谓的“黑箱”模型的内部工作方式,这对于人工智能在我们生活中的长期成功至关重要。

对可解释人工智能的研究正在进行中,有许多了不起的项目和小组正在做着工作。构建 transformers interpret 的库名为 Captum ,这是一个为 pytorch 中的模型可解释性而设计的包。我喜欢 Captum 的一点是,它有效地将可解释人工智能领域的所有领先研究整合到一个包中,当然,它针对 pytorch 进行了优化,这是一大优势。虽然 transformers interpret 只专注于 NLP,但 Captum 是多模态的,可以处理文本、计算机视觉和表格数据。Captum 的团队也做了出色的工作,给出了他们在整个软件包中使用的所有算法,如果你有兴趣了解 transformers interpret 的内部,这当然值得一试。

变形金刚解读入门

很像《拥抱脸变形金刚》背后的设计哲学,《变形金刚解读》的包装设计在最前沿就是易于使用。它在选择归因方法和如何总结归因方面固执己见。所有这些都允许终端用户只需 2 行代码就能获得他们模型输出的文字属性和可视化效果。目前,该软件包支持所有具有序列分类头的模型——因此(应该)适用于所有分类模型。计划支持问答模型和 NER 模型。

让我们来看一个动手的例子。要安装软件包,请执行以下操作:

pip install transformers-interpret

安装好这个包之后,我们将从实例化一个 transformers 模型和 tokenizer 开始。我选择了distilbert-base-un cased-fine tuned-SST-2-English这是一个针对情感分析任务进行了微调的 distil Bert 模型,我选择这个模型主要是因为与其他一些大型模型相比,它很受欢迎且轻量级。

from transformers import AutoModelForSequenceClassification, AutoTokenizermodel_name = "distilbert-base-uncased-finetuned-sst-2-english"model = AutoModelForSequenceClassification.from_pretrained(model_name)tokenizer = AutoTokenizer.from_pretrained(model_name)

有了模型和标记器,我们现在可以开始创建一个解释器,这非常简单:

from transformers_interpret import SequenceClassificationExplainer
cls_explainer = SequenceClassificationExplainer("I love you, I like you", model, tokenizer)

这就够了。要获得句子“我爱你,我喜欢你”的定语,我们只需调用:

attributions = cls_explainer()

如果我们想知道哪个类被预测:

>>> cls_explainer.predicted_class_name'POSITIVE'

要查看原始数字属性:

>>> attributions.word_attributions[('BOS_TOKEN', 0.0),('I', 0.46820529249283205),('love', 0.46061853275727177),('you', 0.566412765400519),(',', -0.017154456486408547),('I', -0.053763869433472),('like', 0.10987746237531228),('you', 0.48221682341218103),('EOS_TOKEN', 0.0)]

有趣的是,我们可以看到,模型将大量注意力放在了“我爱你”上,而“我喜欢你”则不那么重要。考虑到自我关注是如何工作的,这似乎与直觉相符,即“love”这个词正在增加其上下文周围单词的重要性。

数字定语可能很难读,尤其是对于长得多的句子。该软件包还有一个内置的可视化方法,建立在 Captums 的可视化之上,以提供易于理解的单词属性的可视化解释。

如果您在 jupyter 笔记本中工作,调用该方法将以内联方式显示可视化效果,如果您从脚本运行,只需传递一个 html 文件名,您就可以在浏览器中查看输出文件。

cls_explainer.visualize("distilbert_example.html")

这将产生如下所示的输出:

归因可视化

如果你想生成更多的属性,没有必要创建另一个解释器,你可以简单地传递一些新的文本给现有的解释器,新的属性就会被创建

attributions = cls_explainer("I hate you, I dislike you")

您并不局限于为预测类生成属性,这是默认行为,但可以通过传递您想要属性的类的类名或索引来覆盖:

attributions = cls_explainer(class_name="NEGATIVE")

这对于多类分类模型特别有用。

如需更详细的例子,请查看本多类分类笔记本

完整的工作示例

下面是上述代码的完整工作示例。

单词属性和可视化的完整工作示例。

未来工作和解释者

在编写的时候,这个包只支持分类模型。然而,问答模式也很有可能像 NER 模式一样实现,这两种模式都是目前计划中的功能。

我还对探索因果语言模型和多项选择模型解释的可行性感兴趣。

Captum 有多种归因方法,transformers interpret 中默认的是层综合渐变,归因得分实际上是各层归因的汇总或平均。Captum 最近增加了对在变压器的特定层上执行层集成渐变的支持,所以我希望为用户添加一个选项,以逐层获得属性,这将允许更深入地检查模型的内部。

查看回购,了解未来版本的任何更新。

如果您有任何问题、建议或希望做出贡献(请😁)请联系。

如果你对模型的可解释性和可解释性感兴趣,我也强烈建议你去看看 Captum。他们正在做着惊人而重要的工作。

感谢阅读!

向您介绍 OOP 的世界——面向对象编程

原文:https://towardsdatascience.com/introducing-you-to-the-world-of-oop-object-oriented-programming-95c33ae4df2?source=collection_archive---------41-----------------------

本文向您介绍了面向对象编程背后的基本直觉,以及它的四个支柱:抽象、封装、继承和多态。我们开始吧!

来源

面向对象编程(OOP)是一种编程范式或编程方式,它使用类和对象来解决问题。类只是定义任何有形事物的属性和功能的一种方式。但是,类不能直接使用。我们需要一个对象,它是类的实例,来访问类中定义的属性和方法。因此,创建类并使用它们的对象来解决任何给定问题的编程范式被称为 OOP。

我给你举个例子。如果让您找出不同类型的车辆在一个月内的总油耗。在一个面向对象的编程范例中,你将创建一个名为“Vehicle”的抽象类,它包含所有车辆共有的基本属性,如 VIN 号、颜色、注册号、类型、燃料类型、平均燃料消耗量等。您还可以创建输入、显示或处理这些属性值的函数或方法。现在,你可以实例化同一类“车辆”的不同对象,如本田、特斯拉、马鲁蒂、日产等,并相应地设置它们的属性。接下来,你只需要一个函数来计算一种车辆的总油耗,瞧!你的问题解决了!

描述类的图像,以及上面例子中的对象

现在,我们理解了什么是面向对象编程。让我们讨论一下支撑 OOP 世界的四大支柱。

它们是:

数据提取或数据隐藏

数据封装

继承

多态性

让我逐一解释这些概念!

数据抽象更通俗的说法是数据隐藏。这是一个原则,即我们只向用户显示相关的细节,而隐藏可能与用户不相关的背景细节。例如,当你开车时,你只需要担心方向盘、离合器、油门、刹车和齿轮。你很少或者根本不知道它们是如何在后端机械地工作的。这是数据抽象的一个例子。你只是向用户展示诸如方向盘、离合器等细节,而不是让用户担心所有这些内部工作的细节。

抽象的例子

数据抽象是隐藏背景细节,只向用户显示相关细节的过程。

数据封装是将所有元素包装在一起形成一个内聚单元的过程。数据封装通常会导致内部的数据抽象。我给你举个例子。当你坐在车里时,你有没有想过有多少不同的系统同时工作来使汽车发挥功能?空气冷却系统、发动机、汽车的其他不同部件,如座椅、结构、头枕等都集成在一辆汽车中,共同为您提供舒适的整体体验。这是封装的一个例子。具有不同特性的不同部件组合在一起形成一个整体,也就是汽车。此外,你只能看到相关的细节,但看不到他们的内部工作。这只不过是数据抽象。因此,封装通常会导致抽象。就编程而言,数据封装的一个很好的例子是类。由于一个类有这么多不同的属性和方法对应于不同的组件,它们是将数据封装到一个内聚单元中的完美例子。

封装示例

数据封装是将所有元素包装在一起形成一个内聚单元的过程。

OOP 世界中下一个最重要的概念或原则是继承。继承顾名思义,继承你的父类的属性和方法(大部分是公共的和受保护的)。这允许子类或从另一个类(父类)继承的类利用父类的现有特性,而不必再次重写它们。

我给你举个例子。假设你在一家电子商务公司工作,你被要求建立他们的系统。您可以从创建一个名为“User”的类开始,该类包含所有使用该接口的人都会有的基本属性和方法。比如姓名、性别、年龄、住址、出生日期等公共属性。但是,可以有多种类型的用户,如客户和卖家。现在,要解决这个问题,您可以简单地创建一个继承类“User”的子类 Customer 和 Seller。因此,“用户”成为父类,“客户”和“销售者”成为它们的子类。现在,这两个类都将拥有其父类的所有属性,并且它们可以将自己的属性添加到从其父类继承的属性中。例如,子类“客户”可以有额外的属性,如送货地址、首选商品类型、购买历史等。类似地,另一个子类“卖方”可以具有其他属性,例如卖方 Id、卖方项目列表、卖方历史等。下图总结了这一点。

描述从父类到子类的继承的图片[图片由作者提供]

继承是子类从父类继承属性和方法的过程。

接下来,我们来谈谈 OOP 的第四个也是最后一个支柱:多态性。多态是指代码能够根据所处的环境改变自身,而不会对其性能产生太大影响。换句话说,它是一个实体改变成生存和继续表现所必需的任何形式的能力。

让我给你一个真实的例子。在任何时候,你都是一个人,一个公司/网站/服务的用户,一个组织的员工,一个女儿/儿子,一个姐妹/兄弟,一个人。看到了吗?作为一个人,你根据情况和环境适应多少形式和角色。你是多态性的完美例子。你在人生的不同阶段扮演着不同的角色,尽管你可能会因为每个角色而稍有改变,但从本质上来说,你还是原来的你。因此,我们根据情况变化成各种不同的形式,从而在我们的日常生活中实现多态性。

在编程方面,假设你做了一个软件。现在,你的软件应该适应操作系统的变化,计算能力的变化,其他工作条件的变化,并且仍然保持运行。因此,你的软件需要有执行多态性的能力。

多态是一个实体根据它所处的环境改变或适应自己而不影响其性能的能力。

因此,如果任何编程范式都基于使用类和对象,并遵循四个原则:数据抽象、封装、继承和多态,那么它就是众所周知的面向对象编程方法。

我希望这篇文章能帮助你理解 OOP 背后的直觉和它的四个支柱。如果你喜欢这篇文章,那么请喜欢,评论,并关注我!

非常感谢您的阅读!😊

为社会公益介绍人工智能

原文:https://towardsdatascience.com/introduction-to-ai-for-social-good-875a8260c60f?source=collection_archive---------8-----------------------

从太空计数企鹅,打击偷猎,通过社交媒体监测心理健康,以及许多其他应用程序。

“每当我听到人们说人工智能将在未来伤害人类时,我就会想,是的,技术通常总是可以用来做好事和坏事,你需要小心你如何构建它……如果你反对人工智能,那么你就是在反对不会发生事故的更安全的汽车,你是在反对能够更好地诊断生病的人。” 马克·扎克伯格,首席执行官

新技术本身没有好坏之分。这完全取决于人们如何选择使用它。——大卫·王,杜克大学哲学教授

人工智能造福社会——一个相对较新的研究领域,位于人工智能和许多其他领域的交叉点。来源

从常见的媒体言论中,人们很容易将人工智能(AI)视为一种技术,这种技术将使我们所有人失业,使歧视永久化,加剧分裂,并可能最终导致人类的灭亡。然而,我们必须学会将技术本身与其应用分开。如果不进入技术是否在道德上中立的哲学领域(有很好的论据支持这种说法,也有很好的论据反对这种说法),从根本上说,技术是我们可以使用的工具。

一项技术的存在仅仅告诉我们有什么可能(也就是说,我能用它做什么),但是没有什么能告诉我们应该用它做什么。这是大卫·休谟著名的 是——应该的陈述 。只有透过人类视角的玫瑰色眼镜,才能得出任何规范价值,不管哲学家们是否认为这是技术固有的。核武器应该在战争中使用吗?应该实施广泛的监控以使公众更安全吗?是否应该常规使用基因编辑来根除某些先天性疾病?科学无法告诉我们。

自然地,一些技术可能比其他技术更容易被负面地利用。例如,核武器比计算机有更多的负面联想(通过使用单词"武器",这一点变得很明显)。然而,支撑核武器的技术——核裂变——也给了我们一种产生基本无碳能源的新途径。我们必须认识到好坏的概念不是来自工具本身,而是如何使用它。AI 也不例外。

在这篇文章中,我将向读者介绍新兴的研究领域“https://www.nature.com/articles/s41467-020-15871-z”人工智能,也称为“ 人工智能对社会的影响 ”,以及一些旨在解决当今存在的一些最重要的社会、环境和公共健康挑战的新颖应用。

为什么 AI 会被污名化为不道德?

人工智能是计算机科学的一个分支学科。计算机科学家经常被批评缺乏对其研究的潜在伦理和社会影响的考虑。自从 深度学习革命信息爆炸 以来,这种批评在近年来愈演愈烈,这两者都增加了计算技术对社会的影响和力量。

这种批评基本上是有道理的。第二次世界大战结束后,《世界人权宣言》诞生了,它概述了每个人都应该毫无例外地享有的基本自由。1978 年发布的贝尔蒙特报告概述了从事人体研究的个人必须遵守的伦理原则和准则,这对医学和社会科学的研究方法产生了深远的影响。

旁注: 贝尔蒙特报告说了什么? 它引入了三个支配未来人类受试者研究的首要原则: 尊重人 :要求参与者知情同意,不得欺骗。
【2】**:使研究对象的利益最大化,风险最小化。
(3)
正义 :通过合理的、合理化的程序对受试者的公平对待。

相比之下,计算机科学在很大程度上不受其研究方法限制的影响。从历史上看,大多数计算机科学课程很少或根本不强调伦理教育。这种不重视可能不是故意的,而是因为计算机科学家创造的技术对普通大众的生活影响相对较小。

情况不再是这样了。计算机科学家现在处理大型数据集,如(1)医疗数据,创建算法来检测和诊断癌症等疾病,并对疾病的传播进行建模;(2)社交媒体数据,创建改进的推荐系统和其他算法,通过提高消费者参与度来增加收入;(3)金融数据,创建算法来决定哪些个人将获得贷款,甚至人们应该投资哪些公司。这种创造对社会的影响已经显著增加,但仍然很少有正式的要求被引入来强制实施这一领域的道德实践。

这种权力的迅速增加自然会导致相互冲突的制约因素的加剧。这一法律立场基于法律先例,它着眼于过去类似的案件是如何判决的,以及这一裁决如何适用于新的情况。与任何新技术一样,目前几乎没有先例,这使得该领域在很大程度上不受监管。因此,技术上可行的不一定与被认为合法的一致。这两种观点都不一定符合组织想要追求的,或者公众认为是“道德的”。此外,这些限制的目标总是在变化。我们能希望做的最好的事情是改变这些标杆,使它们开始更紧密地重叠,而不是进一步分开。

与人工智能相关的重叠约束。来源: IBM 大数据和分析伦理报告

直到最近几年,人们才开始大声疾呼,阐明不受约束的计算机科学研究可能存在的危险。因此,我们看到了一股推动道德计算机科学实践的潮流,其重点是透明度和问责制。

哈佛等机构已经开始将伦理道德嵌入计算机科学课程,我们已经看到一些著名的研究期刊,如 【自然】科学 已经将公开数据集和分析作为一项要求,还说明了数据的出处(例如,是否获得了知情同意)。像“神经信息处理系统会议” (NeurIPS)这样的会议也要求计算机科学论文提供更广泛的影响声明,表明他们的研究工作的任何伦理或社会影响。这种审查类似于政府倡议或大学和资助机构的机构审查委员会进行的审查。

显然,这些措施没有解决更大的问题。目前,它们很少,可能被选择性地应用,或者仅仅作为批准的橡皮图章,但它们是一个以前没有的对话的开始。解决大规模数据集中的个人隐私问题,如重新识别、信息泄露、不利影响或公众对人工智能缺乏信任的风险,将需要更广泛的措施。在医学和社会科学中已经实现了类似的措施,而没有严重阻碍研究目标,因此这不应该阻止计算机科学社区的重大障碍。

什么是对社会有益的人工智能?

人工智能造福社会(AI4SG) 是一个相对较新的研究领域,专注于利用人工智能解决当今存在的重要社会、环境和公共健康挑战。最初,这听起来像是一个噱头,试图颠覆传统上对人工智能的负面看法,但它不仅仅如此。为了简单起见,我们可以将 AI4SG 视为 AI 与社会科学以及环境科学的交集。

AI4SG 与 AI 的传统用例不同,它更多地使用了一种 自顶向下的方法 。该领域的重点是根据联合国第 17 个可持续发展目标中概述的优先事项产生积极的社会影响,如下所示。

联合国的 17 个可持续发展目标。资料来源:联合国

相对于文本翻译等传统的人工智能应用,我们可能更感兴趣的是模拟无家可归者的社交网络,以试图对抗艾滋病毒的传播,这种疾病对艾滋病毒的影响不成比例。

与有住所的人相比,无家可归的人受到艾滋病毒的影响更大。

虽然文本翻译可以产生积极的社会影响,但它通常不被视为 AI4SG 的一部分。大多数商业智能应用程序也是如此,比如库存计划、推荐系统等。

AI4SG 的许多应用程序利用的是 博弈论 的方法:它们可以使用代理和对手之间的博弈进行数学建模。基于博弈论的 AI 模型属于 强化学习 范式,由于它们需要使用多个智能体,因此通常被描述为 多智能体系统 。这是一个完全独立的领域,很可能会改变社会和工业 4.0 的游戏规则。

例如,洛杉矶国际机场实施了一个博弈论人工智能模型来帮助创建巡逻队,以最佳方式防御恐怖袭击和毒品走私者。该系统着眼于现有的巡逻策略,对手能够利用低效率。相比之下,代理能够注意到这些低效率,并构建一个巡逻策略,通过从根本上消除这些低效率,最大限度地降低对手利用低效率的可能性。这一结果是通过使用贝叶斯 Stackelberg 游戏获得的,该游戏提供了一种看似随机的策略,能够最佳地抵御对手。

为了帮助更详细地阐明 AI4SG 需要什么,我们将查看研究文献中的几个定义。

Floridi 等人 (2020)概述了对 AI4SG 应用至关重要的七个因素,如下所示。这些原则与贝尔蒙特和门洛报告中概述的原则相吻合,但密切关注人工智能和滥用或恶意使用该技术的可能性。

支持人工智能造福社会的七个因素和相应的最佳实践总结。来源:如何为社会公益设计 AI:七大要素

托马舍夫等人 (2020)为 AI4SG 提供了一套类似的指南,涉及人工智能技术的整体使用(G1、G2、G3)、应用(G4、G5、G6、G7、G8)和数据处理(G9、G10)。

特定的应用并不总是能够对所有 17 个可持续发展目标产生积极的影响。事实上,一些技术可能对其中一个目标产生积极影响,而对另一个目标产生消极影响。为了应对这一点,应用程序应该致力于对尽可能多的 SDG 产生最大的净积极效应,同时不对其他 SDG 造成可避免的伤害。

人工智能促进协会 (AAAI)在 2019 年的年会上创造了 AI4SG 作为一个新兴话题,并从那时起概述了 AI4SG 应用所需的几个标准:

  • 问题的意义。所考虑的社会影响问题是重大的,并且到目前为止还没有被人工智能社区充分解决。
  • 方法新颖。引入新模型或对现有模型、数据收集技术、算法和/或数据分析技术进行重大改进。
  • 社会影响的范围和承诺。解决方案产生社会影响的可能性很高,可能正在实践中使用或可以立即使用。
  • 对尖端人工智能技术的依赖和/或进步。介绍适合正在解决的问题的新颖或最新的人工智能技术。

下面列出了目前 AI4SG 最常用的技术,其中一些已经在前面讨论过了。使用博弈论网络理论多臂土匪马尔可夫决策过程强化学习决策聚焦学习都是利用人工智能和多智能体系统领域的常见建模方法。

近几年 AI4SG 论文中发现的常见话题。

尽管 AI4SG 的形式还不成熟,但它已经取得了一些令人印象深刻的成果,其中一些我们将在下一节讨论。

AI4SG 的应用

在本节中,我们讨论 AI4SG 的六个应用以及这些应用如何影响联合国的可持续发展目标。这些应用包括(1)从太空计数企鹅,(2)打击偷猎大象,(3)预防药物滥用,(4)疫情预测全球免疫观察,(5)心理健康监测的社交媒体分析,以及(6)谷歌的 Euphonia 项目。

(1)从太空数企鹅

这可能是一个奇怪的例子,但这是一个非常有趣的应用,可以用于非侵入性监测和保护目的,并扩展到其他动物物种,属于 SDG 的 13-15。

研究员希瑟·林奇获得了 T2 青年科学家奖,因为她通过检查企鹅的“粪便”从太空中数出了企鹅。它们的鸟粪是浅粉色的,这使得它很容易被诸如 Landsat-7 这样的卫星看到。虽然由于空间分辨率有限,很难从太空中发现单个企鹅的排泄物,但发现整个企鹅群的粪便足迹是可能的。

这项技术在一种基于对象的图像分析方法中进行了概述,用于在非常高的空间分辨率卫星图像中检测企鹅粪便希瑟·林奇就是这样能够监测南极半岛上各种企鹅物种的聚居地和数量,以及它们的迁移模式。她的工作提高了对半岛上阿德利企鹅数量的估计,其中目前最好的估计是 379 万对。**

现存阿德利企鹅聚居地的地图,以及在图像中找不到并推测已经灭绝的企鹅聚居地。来源:阿德利企鹅第一次全球普查

林奇教授也对生活在南极半岛的帽带企鹅进行了估计,估计在 375 个企鹅聚居地中有 342 万对企鹅在繁殖。

CCAMLR 分区所有现存帽带企鹅聚居地的地图。来源:全球帽带企鹅种群评估

这种技术和类似的技术可以用来监测特别易受气候变化影响的物种的种群和人口统计数据的变化。这对于企鹅来说相对简单,因为覆盖在南极半岛上的雪和企鹅群的粪便之间形成了鲜明的对比,但类似的生物标志物可能会使这在未来成为其他物种的一种可能性。

(2)世界野生动物基金会打击非洲偷猎大象的行为

反偷猎努力强调了一个重要的博弈论模型子集,即所谓的“绿色安全游戏”,它有助于解决 SDG 的 1、11、15 和 16。

偷猎在乌干达是一个特别棘手的问题。在 20 世纪 70-80 年代的政治动荡期间,偷猎者将乌干达的大象数量从大约 30,000 头减少到不到 800 头。在伊丽莎白女王国家公园,诸如增加护林员巡逻和蜂巢围栏等保护项目的努力已经使大象数量回升到大约 3000 头,但是人象冲突仍然是该地区的一个问题。在卡塔拉,一些农民用毒死大象的方法来防止大象践踏他们的庄稼,而另一些则被偷猎者为了象牙或肉而猎杀。相当多的护林员在与偷猎者的争吵中被杀害,这导致该地区丧偶妇女的增加,使她们陷入贫困,无法养活家人。

护林员只有有限的资源来监控公园里的大象,因此需要明智地组织这些资源,让他们有最好的机会来打击该地区的偷猎行为,这就是我们的绿色安全游戏发挥作用的地方。

我们的绿色安全游戏基于 Stackelberg 安全游戏,专注于威胁预测,首先将伊丽莎白女王国家公园(Queen Elizabeth National Park)这一 2000 平方公里的区域划分为 1 公里 x 1 公里的网格单元。

伊丽莎白女王国家公园(左上)被划分为 1 公里 x 1 公里的网格单元,用于建模。

安全游戏将涉及根据从 12 年来公园约 1000 起偷猎案件的先前数据中获得的各种因素,确定陷阱被放置在某个网格正方形中的概率。

然后,人工智能模型设计一种新的巡逻方案,以最大化这些陷阱被抓住的可能性。这是反复执行的,使用过去的犯罪数据来预测未来陷阱放置的近似空间位置。

来源: AI for Earth: AI 保护野生动物、森林、鱼类

当这种方法最初在公园两个 9 平方公里的区域实施一个月时,他们的陷阱命中率高于历史上所有先前月份的 91%。在此之后,在 6 个月的时间里,在公园内 9 平方公里的 27 个区域进行了更大规模的实地测试,并显示出非常积极的结果,捕捉到创纪录数量的陷阱,甚至有一名偷猎者在公园内被当场抓获。

自从这些实地实验以来,这些利用人工智能的绿色安全游戏已经被野生动物保护协会扩展到 Murchison Falls 国家公园,以及乌干达的其他地区,甚至被世界野生动物基金会扩展到柬埔寨,以防止偷猎大象。近年来,大象作为某些中草药的一种成分变得很受欢迎。当在柬埔寨的 Srepok 野生动物保护区进行测试时,在实施绿色安全游戏的第一个月,有 521 个陷阱被捕获,而该地区的护林员通常只发现 101 个陷阱。

类似的绿色安全游戏可以扩展用于边境巡逻、防止恐怖主义、保护珊瑚礁,甚至防止亚马逊雨林中的非法金矿开采等任务。

(3)预防药物滥用

解决联合国可持续发展目标 1 和 3,药物滥用预防一直是 AI4SG 研究人员的主要关注领域之一。药物滥用是一个重要的公共卫生问题,可能会产生广泛的负面社会影响,并可能增加精神和身体问题的发病率。

青年是最容易滥用药物的群体,某些青年群体使用药物的比例很高,例如无家可归的青年。社会科学研究表明,偏差训练可能是有用的,但通常基于同伴的干预是最有效的。

无家可归人群药物滥用预防统计概述。资料来源:预防药物滥用 AI

执行基于同伴的干预与出于营销目的选择影响者非常相似。选择社交网络中节点的子集,其具有将信息传播给目标人群中最大可能受众的最高概率。这已经在无家可归的人群中进行了研究,并被发现对打击各种异常行为有效,包括物质滥用。

想象一下,我们有一个社交网络, G ,如下图所示,并且能够选择 K 个节点作为同伴领袖。一旦近似的社会网络,假设一个独立的级联模型的信息传播,我们可以优化我们的算法,以最大化的影响节点的预期数量。

显然,由于各种原因,该过程在实践中更加混乱和不确定,包括退出该过程的同行领导,以及传播概率和社会网络结构的不确定性。

为了处理这种不确定性, Wilder 等人(2017) 开发了鲁棒影响最大化,其使用部分观察的马尔可夫决策过程来迭代地选择社交网络中的最佳对等领导组,以实现最大的信息传播。

本质上,如果一个对等领导“没有出现”,那么这个对等领导被另一个最优选择的对等领导替换,以提供剩余网络的最大覆盖。

这种提供基于同伴的干预的技术可以应用于涉及通过社交网络传播的广泛任务,因此随着我们的生活越来越多地涉及越来越大的社交网络,这种技术可能会受到越来越多的关注。

(4)疫情预测全球免疫观察站

在新冠肺炎疫情期间,哈佛大学公共卫生学院的教授迈克尔·米娜提出了一个激进的新想法,他创造了“全球免疫观察站”,其作用类似于“大流行的天气预报”。

虽然这一目标尚未实现,但其潜在影响可能是深远的。通过查看整个人群样本的血清学指标,如血液中的抗体(即每次进行常规血液测试),可以确定血清学指纹,然后将其添加到国家数据库中。然后可以对其进行分析,以检测当地人群中的任何异常情况。这可以用来在新疫情扩散到其他地区之前发现异常症状、感染和血液标志物,从而降低未来疫情或大流行的可能性。

来源:全球免疫观察站(GIO)迎接大流行时代。

鉴于自 1900 年以来,我们已经经历了三次大流行,以及近 12 次来自 SARS、MERS、猪流感和禽流感等疾病的疫情威胁,拥有一个大流行预警系统将有助于协助和简化公共卫生工作。

虽然这一想法仍处于萌芽阶段,但如果将来真的付诸实施,取样的方式将不得不在很大程度上代表当地人口,而且很可能是嘈杂和稀疏的。因此,必须开发智能和稳健的采样方案,这些方案几乎肯定会利用机器学习技术。

(5)心理健康的社会媒体分析

也许是迄今为止所有应用中最切实的,AI4SG 正在开发使用社交媒体监测精神健康的新方法。特别是,从社交媒体帖子中预测抑郁症已经受到了很多关注。

每年有数千万人患有抑郁症,但其中只有一小部分人接受治疗。 Choudhury 等人 (2013 年)使用了来自 Twitter 用户的一年数据,这些用户报告在抑郁发作前被诊断为临床抑郁,以开发一种能够估计个体抑郁风险的统计分类器。这包括社会参与、语言、语言风格、自我网络和推特话题等方面的变化。他们发现,社交媒体为描述抑郁症的发作提供了有用的信号。

这种工具可以在未来被医疗机构用来介入并提供帮助,以主动预防全面抑郁症的发生。研究人员建议,在不久的将来,可以使用类似的技术来标记其他心理障碍的发作或存在,特别是因为心理健康的重要性正在获得公众越来越多的认可。

同样,产后情绪和行为的变化也通过 Twitter 帖子进行了评估。 Choudhury 等人 (2013 年)发现,根据他们之前的社交媒体互动,他们有 71%的时间能够预测到孩子出生后母亲的情绪和行为状态会如何改变。这些信息可能有助于确定处于产后抑郁症高风险中的母亲。

除了抑郁症, Thorstad 和 Wolff (2019) 分析了来自 Reddit 的信息,并能够从临床子主题上使用的词语中区分不同形式的精神疾病,如多动症、双相情感障碍和抑郁症。有趣的是,作者分析了非临床子主题,如涉及烹饪和旅行的子主题,发现他们能够使用这些子主题上的帖子预测某人是否可能向临床子主题发帖。

在研究 1 中学到的 100 个最能预测抑郁的单词。在使用 t-SNE 降维之后,基于单词的文档向量,将单词投影到二维空间中。颜色表示由 DBSCAN 分配的簇。灰色 Y 形标记表示 DBSCAN 没有分配给任何聚类的“噪声”点。在每个聚类中,前三个最具预测性的单词被标记。标记大小也随着预测等级线性缩放,其中较大的标记指示更多的预测单词。

这些结果表明,我们的整体精神状态,以及任何精神疾病,都会影响我们在网上使用的词语,并且在不久的将来可能会被 AI4SG 模型破译。

(6)谷歌项目 Euphonia

谷歌的 Euphonia 项目或许应该成为人工智能增强包容性的光辉典范。该项目是一项正在进行的工作,包括获取大量构音障碍语音的原始数据。也就是说,来自患有严重语言障碍的人的语音使他们难以沟通,这可能源于疾病,如肌萎缩侧索硬化症

根据这些数据,谷歌创建了一种[机器学习算法](http://Personalizing ASR for Dysarthric and Accented Speech with Limited Data),能够将这种构音障碍语音翻译成典型的语音,尽管仍处于早期阶段,但这种努力已经大大减少了许多人在日常生活中的交流障碍。在一个远程工作和在线会议越来越占主导地位的世界,将 Project Euphonia 等插件纳入 Zoom 和 Skype 等平台可以从根本上改善患有严重语言障碍的个人的包容性。

为了了解更多关于 Euphonia 项目的信息或者看到它的实际应用,我在下面提供了一些链接。


其他项目

虽然还有大量其他主题可以讨论,但我认为以上 6 个主题涵盖了人工智能令人兴奋的非传统应用,可用于改善个人、社会和环境福祉,与传统的人工智能叙事相反。我在下面为感兴趣的读者留下了其他 AI4SG 应用程序的链接:

潜在问题

正如任何学科一样,尤其是那些宣扬改善社会的学科,在应用中可能会有意想不到的后果。这也是为什么有人提出了更广泛的影响陈述的概念的部分原因,这样,发明者就可以清楚地列出特定技术的利弊。然而,AI4SG 仍然有可能在改善社会影响的幌子下被使用,同时对其他社区产生负面影响。幸运的是,SDG 的目标之一是减少不平等,让坏人更难从伦理角度证明这一方法的合理性。

为了做到完全透明,我还包含了一些文章的链接,这些文章展示了该领域的不同观点,概述了 AI4SG 实际上可能如何对社会有害。如果时间允许,我鼓励读者通读这些内容,并对 AI4SG 以及今后应该如何使用它提出自己的判断。这仍然是一个相对较新的领域,所以现在是参与讨论的好时机。

最后的话

数据缺口削弱了我们确定资源目标、制定政策和追踪责任的能力。没有好的数据,我们是盲目的。看不到就解决不了。 —联合国前秘书长科菲·安南

AI4SG 在某种程度上与计算机科学领域相反,更接近于工程学科而不是计算学科。这是一种趋势,我们越来越开始看到它的出现,就像微型机器学习领域一样。在某些方面,AI 似乎是一个原型工程学科,类似于化学和电磁学,逐渐演变为化学和电气工程。像 Neuralink 这样的应用,以及像优化民主这样的研究工作,很可能会继续产生新的子领域。

我们生活在令人兴奋(也令人担忧)的时代,是时候开始拥抱和利用人工智能的力量来改善每个人的生活了。然而,我们应该谨慎地这样做,设置类似于在医学和社会科学中遇到的约束,以帮助管理和提供对计算机科学领域及其萌芽后代的问责。

鉴于大多数人工智能人才都被隔离在行业或学术界,鼓励研究人员为 AI4SG 计划贡献一定比例的时间可能会有成效,就像法律界的公益工作一样。现实世界挑战的复杂性实际上有助于促进对现有方法的理解,并在最重要的地方展示影响。

进一步阅读和参考

[1]弗洛里迪,l;考尔斯,j。金,T.C .和轩辕洛尹,M. 如何为社会公益设计 AI:七大要素 。科学伦理。2020 年 6 月;26(3):1771–1796.doi:10.1007/s 11948–020–00213–5。Epub 2020 年 4 月 3 日 PMID:32246245;PMCID: PMC7286860。

[2]托马舍夫;科尔内比斯,j。Hutter,f .et al .AI for social good:解锁机会产生积极影响11、* 2468 (2020)。https://doi.org/10.1038/s41467-020-15871-z***

[3] Chessell,M. IBM 的大数据与分析伦理报告 。2014.

[4]安南,K. 数据可以帮助终结非洲各地的营养不良 性质 555 ,7 (2018)。https://doi.org/10.1038/d41586-018-02386-3

[5] Jean,n .等结合卫星图像和机器学习预测贫困 理科353 ,6301 (2016)。https://doi.org/10.1126/science.aaf7894

[6]m .德乔杜里、m .加蒙、Counts、s .和 h orvitz e .(2013 年)。 通过社交媒体预测抑郁症 网络与社交媒体国际 AAAI 会议论文集7 (1)。从 https://ojs.aaai.org/index.php/ICWSM/article/view/14432取回

[7]吉布尼,E. 在世界上最大的机器学习会议 上为道德人工智能而战。性质 577 、609 (2020)。https://doi.org/10.1038/d41586-020-00160-y

[8]吉尔曼,M. 旨在根除福利欺诈的人工智能算法往往以惩罚穷人而告终 对话(2020)。

【9】Latonero,M. 观点:AI 为善往往是坏 连线(2019)。

用 PyCaret 介绍 Python 中的异常检测

原文:https://towardsdatascience.com/introduction-to-anomaly-detection-in-python-with-pycaret-2fecd7144f87?source=collection_archive---------3-----------------------

一步一步,初学者友好的教程,用于使用 PyCaret 的无监督异常检测任务

卢卡·斯拉普尼卡在 Unsplash 上拍摄的照片

1.介绍

PyCaret 是一个用 Python 编写的开源、低代码的机器学习库,可以自动化机器学习工作流。这是一个端到端的机器学习和模型管理工具,可以成倍地加快实验周期,提高您的工作效率。

与其他开源机器学习库相比,PyCaret 是一个替代的低代码库,可以用来用几行代码替换数百行代码。这使得实验快速有效。PyCaret 本质上是几个机器学习库和框架的 Python 包装器,比如 scikit-learn、XGBoost、LightGBM、CatBoost、spaCy、Optuna、Hyperopt、Ray 等等。

PyCaret 的设计和简单性受到了公民数据科学家这一新兴角色的启发,这是 Gartner 首先使用的术语。公民数据科学家是超级用户,他们可以执行简单和中等复杂的分析任务,这些任务在以前需要更多的技术专业知识。

想了解更多关于 PyCaret 的信息,可以查看官方网站或者 GitHub

2.辅导的目的

在本教程中,我们将学习:

  • 获取数据:如何从 PyCaret 资源库导入数据。
  • 设置环境:如何在 PyCaret 中设置无监督的异常检测实验。
  • 创建模型:如何创建模型并将异常标签分配给数据集进行分析。
  • 图模型:如何使用各种图分析模型性能。
  • 预测模型:如何根据训练好的模型给新的/看不见的数据集分配异常标签?
  • 保存/加载模型:如何保存/加载模型以备将来使用?

3.正在安装 PyCaret

安装很容易,只需几分钟。PyCaret 从 pip 的默认安装只安装在 requirements.txt 文件中列出的硬依赖项。

pip install pycaret

要安装完整版:

pip install pycaret[full]

4.什么是异常检测?

异常检测是通过与大多数数据显著不同来识别引起怀疑的罕见项目、事件或观察结果的任务。通常,异常项目会转化为某种问题,如银行欺诈、结构缺陷、医疗问题或文本中的错误。存在三大类异常检测技术:

  • 无监督异常检测:无监督异常检测技术在假设数据集中的大多数实例是正常的情况下,通过寻找似乎最不适合数据集剩余部分的实例来检测未标记测试数据集中的异常。
  • 监督异常检测:这种技术需要一个已经被标记为“正常”和“异常”的数据集,并且涉及训练一个分类器。
  • 半监督异常检测:这种技术从给定的正常训练数据集构建一个代表正常行为的模型,然后测试由学习的模型生成测试实例的可能性。

5.PyCaret 中异常检测模块概述

PyCaret 的异常检测模块 ( pycaret.anomaly)是一个无监督的机器学习模块,它执行识别罕见项目、事件或观察结果的任务,这些项目、事件或观察结果通过与大多数数据显著不同而引起怀疑。

PyCaret 异常检测模块提供了几个预处理功能,可以在初始化设置时通过setup功能进行配置。它有超过 12 种算法和一些图表来分析异常检测的结果。PyCaret 的异常检测模块还实现了一个独特的功能tune_model,允许您调整异常检测模型的超参数,以优化监督学习目标,例如用于分类的AUC或用于回归的R2

6.教程的数据集

在本教程中,我们将使用来自 UCI 的名为 小鼠蛋白质表达 的数据集。数据集由 77 种蛋白质的表达水平组成,这些蛋白质在皮质的细胞核部分产生可检测的信号。该数据集包含每种蛋白质总共 1080 次测量。每次测量可以被认为是一个独立的样本(鼠标)。

数据集引用:

Higuera C,Gardiner KJ,CIO KJ(2015)自组织特征图确定了唐氏综合征小鼠模型中对学习至关重要的蛋白质。PLoS ONE 10(6): e0129126。[网页链接] journal.pone.0129126

您可以从这里找到的原始数据源https://archive.ics.uci.edu/ml/datasets/Mice+Protein+Expression下载数据,并使用 pandas (了解如何使用) 加载数据,或者您可以使用 PyCaret 的数据存储库使用get_data()函数加载数据(这将需要互联网连接)。

许可证:

这个数据集是在知识共享署名 4.0 国际 (CC BY 4.0)许可下许可的。

这允许为任何目的共享和改编数据集,只要给予适当的信任。(来源)

from pycaret.datasets import get_data
dataset = get_data('mice')

**# check the shape of data**
dataset.shape
>>> (1080, 82)

为了演示对看不见的数据使用predict_model函数,从原始数据集中保留了 5% (54 条记录)的样本,用于实验结束时的预测。

data = dataset.sample(frac=0.95, random_state=786)
data_unseen = dataset.drop(data.index)

data.reset_index(drop=True, inplace=True)
data_unseen.reset_index(drop=True, inplace=True)

print('Data for Modeling: ' + str(data.shape))
print('Unseen Data For Predictions: ' + str(data_unseen.shape))**>>> Data for Modeling: (1026, 82)
>>> Unseen Data For Predictions: (54, 82)**

7.在 PyCaret 中设置环境

PyCaret 中的setup函数初始化环境,并为建模和部署创建转换管道。在 pycaret 中执行任何其他函数之前,必须调用setup。它只需要一个强制参数:熊猫数据帧。所有其他参数都是可选的,可用于定制预处理管道。

当执行setup时,PyCaret 的推理算法将根据某些属性自动推断出所有特征的数据类型。应该可以正确推断出数据类型,但情况并非总是如此。为了处理这个问题,一旦执行了setup,PyCaret 就会显示一个提示,要求确认数据类型。如果所有数据类型都正确,您可以按 enter 键或键入quit退出设置。

确保数据类型正确在 PyCaret 中非常重要,因为它会自动执行多个特定于类型的预处理任务,这些任务对于机器学习模型来说是必不可少的。

或者,您也可以使用setup中的numeric_featurescategorical_features参数来预定义数据类型。

from pycaret.anomaly import *

exp_ano101 = setup(data, normalize = True, 
                   ignore_features = ['MouseID'],
                   session_id = 123)

输出

成功执行设置后,它会显示信息网格,其中包含一些关于实验的重要信息。大部分信息与执行setup时构建的预处理流水线有关。这些特性的大部分超出了本教程的范围,但是,有一些重要的事情需要注意:

  • session_id: 一个伪随机数,作为种子分布在所有函数中,以便以后再现。如果没有通过session_id,则自动生成一个随机数,并分配给所有函数。在这个实验中,session_id 被设置为123,以便以后再现。
  • ****缺失值:当原始数据中存在缺失值时,会显示为True。请注意,上面信息网格中的Missing ValuesTrue,因为数据包含缺失值,对于数字特征使用mean自动估算,对于类别特征使用constant自动估算。可以使用setup中的numeric_imputationcategorical_imputation参数改变插补方法。
  • ****原始数据:显示数据集的原始形状。在这个实验中,( 1026,82)意味着 1026 个样本和 82 个特征。
  • ****转换数据:显示转换数据集的形状。请注意,原始数据集的形状(1026,82)被转换为(1026,91)。由于数据集中分类要素的编码,要素的数量有所增加。
  • ****数字特征:推断为数字的特征数量。在该数据集中,82 个要素中有 77 个被推断为数值型。
  • ****分类特征:推断为分类的特征数量。在该数据集中,82 个要素中有 5 个被推断为分类要素。另外,请注意,我们使用ignore_feature参数忽略了一个分类特征,即MouseID

请注意执行建模所必需的一些任务是如何自动处理的,例如缺失值插补、分类编码等。setup功能中的大多数参数是可选的,用于定制预处理流水线。这些参数超出了本教程的范围,但是我将在后面写更多关于它们的内容。

8.创建模型

在 PyCaret 中创建异常检测模型很简单,与在 PyCaret 的监督模块中创建模型的方式类似。使用create_model函数创建异常检测模型,该函数采用一个强制参数,即模型名称作为字符串。这个函数返回一个训练好的模型对象。请参见下面的示例:

iforest = create_model('iforest')
print(iforest)**>>> OUTPUT** IForest(behaviour='new', bootstrap=False, contamination=0.05, max_features=1.0, max_samples='auto', n_estimators=100, n_jobs=-1, random_state=123, verbose=0)

我们已经使用create_model创建了一个隔离森林模型。请注意,contamination参数被设置为0.05,当您没有传递fraction参数时,这是默认值。fraction参数决定了数据集中离群值的比例。在下面的例子中,我们将用0.025部分创建One Class Support Vector Machine模型。

svm = create_model('svm', fraction = 0.025)
print(svm)**>>> OUTPUT** OCSVM(cache_size=200, coef0=0.0, contamination=0.025, degree=3, gamma='auto',kernel='rbf', max_iter=-1, nu=0.5, shrinking=True, tol=0.001, verbose=False)

要查看模型库中可用模型的完整列表,请查阅文档或使用models功能。

models()

9.指定模型

现在我们已经创建了一个模型,我们希望将异常标签分配给我们的数据集(1080 个样本)来分析结果。我们将通过使用assign_model函数来实现这一点。

iforest_results = assign_model(iforest)
iforest_results.head()

注意,两列AnomalyScore被添加到末尾。0 代表内部因素,1 代表外部因素/异常情况。Anomaly_Score是算法计算出的值。离群值被赋予较大的异常分值。请注意,iforest_results还包括我们在setup中删除的MouseID。它不用于模型,仅在您使用assign_model时附加到数据集。

10.绘制模型

plot_model函数可用于分析不同方面的异常检测模型。此函数接受一个经过训练的模型对象并返回一个绘图。

10.1T-分布式随机邻居嵌入(t-SNE)

plot_model(iforest, plot = 'tsne')

10.2 均匀流形近似和投影

plot_model(iforest, plot = 'umap')

11.根据看不见的数据预测

predict_model函数用于将异常标签分配给一个新的看不见的数据集。我们现在将使用我们训练好的iforest模型来预测存储在data_unseen中的数据。该变量是在本教程开始时创建的,包含来自原始数据集的 54 个样本,这些样本从未暴露给 PyCaret。

unseen_predictions = predict_model(iforest, data=data_unseen)
unseen_predictions.head()

Anomaly列表示异常值(1 =异常值,0 =内部值)。Anomaly_Score是算法计算出的值。离群值被赋予较大的异常分值。您也可以使用predict_model功能来标记训练数据。

data_predictions = predict_model(iforest, data = data)
data_predictions.head()

12.保存模型

我们现在已经完成了实验,使用我们的iforest模型来预测看不见的数据上的标签。

这使我们的实验接近尾声,但仍有一个问题要问:当你有更多的新数据要预测时,会发生什么?你必须再次经历整个实验吗?答案是否定的,PyCaret 的内置函数save_model允许您保存模型和整个转换管道以备后用。

save_model(iforest,’Final IForest Model 25Nov2020')

为了将来在相同或不同的环境中加载已保存的模型,我们将使用 PyCaret 的load_model函数,然后轻松地将已保存的模型应用于新的未知数据进行预测。

saved_iforest = load_model('Final IForest Model 25Nov2020')
new_prediction = predict_model(saved_iforest, data=data_unseen)
new_prediction.head()

12.总结/后续步骤?

我们只讲述了 PyCaret 的异常检测模块的基础知识。在下面的教程中,我们将更深入地探讨高级预处理技术,这些技术允许您完全定制您的机器学习管道,并且是任何数据科学家的必备知识。

感谢您阅读🙏

重要链接

教程py caret 新手?查看我们的官方笔记本!
📋社区创建的示例笔记本
📙博客投稿人的教程和文章。
📚文档py caret 的详细 API 文档
📺视频教程我们的视频教程来自各种赛事。
📢讨论有疑问?与社区和贡献者互动。
🛠️ 变更日志变更和版本历史。
🌳路线图 PyCaret 的软件和社区开发计划。

作者:

我写的是 PyCaret 及其在现实世界中的用例,如果你想自动得到通知,你可以在媒体LinkedInTwitter 上关注我。

使用维基百科的 EventStreams 服务介绍阿帕奇卡夫卡

原文:https://towardsdatascience.com/introduction-to-apache-kafka-with-wikipedias-eventstreams-service-d06d4628e8d9?source=collection_archive---------20-----------------------

概念和实践示例

若昂·布兰科在 Unsplash 上的照片

介绍

在这篇文章中,我们通过基本概念,构成了阿帕奇卡夫卡。我们利用维基百科提供的名为事件流的真实事件流,将它们发送到一个卡夫卡主题。

本教程旨在让读者熟悉 Apache Kafka,这是一个用于与 Kafka 交互的 Python 客户端库,也是进一步实验的平台。这种设置意味着在本地系统上运行,不考虑安全性和可伸缩性问题,使用的配置很少。

阿帕奇卡夫卡

Apache Kafka 可能是最著名的发布/订阅消息系统,它被各行各业过度采用是有充分理由的。在过去的几年里,由于对实时数据开发(分析、处理、可视化)的需求不断增长,它变得越来越流行。

已经写了许多电子书和文章来解释什么是阿帕奇卡夫卡以及它是如何工作的。在本文中,我将尝试对您需要了解的最重要的几点做一个简短的概述,并为您提供一些参考信息。我已经突出了最重要的关键词。

生态系统

Kafka 中的数据单元称为消息。一条消息只是一个字节数组,它还可以包含一个名为 key 的元数据位,这也是一个字节数组。根据用例的不同,可以使用或不使用键,它们提供了一种以更可控的方式填充主题分区的方法。消息也可以被称为键值对;您可以将它们视为传统 SQL 数据库中的记录。

在大多数情况下,消息需要有某种结构,可以很容易地从其他系统中解释出来(模式)。最流行的格式是 JSON、XML 和 Avro。

在 Kafka 中,生态系统消息是以的方式产生的,目的是将消息在网络内部往返的开销降至最低。

消息被分类到不同的主题中,以便根据一些属性将它们分开。主题也可以分成分区,这提供了额外的可伸缩性和性能,因为它们可以被托管在不同的服务器上。您可以将主题视为一个仅附加的日志,只能从头到尾读取。在 SQL 世界中,主题就是我们的表。

有两种类型的客户端:出版商消费者。顾名思义,发布者向主题发送消息,消费者阅读它们。

一个 Kafka 节点被称为代理。代理负责从生产者那里获取消息,将它们存储在磁盘中,并响应消费者的请求。许多经纪人组成一个集群。分区只能由一个称为 leader 的代理拥有。

卡夫卡主要成分概述

关键特征

使 Apache Kafka 脱颖而出的一些关键特性:

  • 多个制作者可以同时发布消息到相同的主题。
  • 多个用户可以独立于其他用户读取数据,也可以在共享流的一组用户中读取数据,并确保每条消息在整个组中只被读取一次。
  • 保留,发布到集群的数据可以按照给定的规则在磁盘上保留。
  • 可伸缩性,Kafka 被设计为完全可伸缩的,因为它是一个分布式系统,运行在不同地理区域的多个代理集群上,支持多个发行商和消费者。
  • 性能,除了上面提到的特性之外,Kafka 即使在数据负载很重的情况下也非常快,从发布一条消息到可供消费之间的延迟为亚秒级。

在本教程中,我们将设置一个具有单个节点的 Kafka 集群作为概念验证。在生产环境场景中,为了充分利用 Kafka 的潜力,建议设置一个包含多个节点(至少三个)的集群。这将为实现跨节点的数据复制奠定基础,从而构建一个容错系统。

如果你想更深入地了解卡夫卡的生态系统,我建议你阅读卡夫卡权威指南以及其他电子书,你可以在卡夫卡的官方网站上免费找到。这本书将提供你理解 Kafka 如何工作所需要的所有低级知识,同时也提供在生产环境中部署的指南和建议。

卡夫卡-巨蟒

这个项目使用 kafka-python 库发布事件到 kafka 主题,因为它使用简单。当然,也有像 Confluent 的官方pykafka 这样的替代品,你可以用它们来代替 kafka-python。

当然,您也可以从不同的编程语言中使用许多客户端库。用 Java 和 Scala 编写的客户端库可以被认为更适合生产环境,因为当需要完成更复杂的任务时,使用 Kafka 的母语将提供更多的选择。而且,那些库比用 Python 写的更成熟。

事件流

正如简介中提到的, EventStreams 是一个 web 服务,它使用分块传输编码,遵循服务器发送事件 (SSE)协议,通过 HTTP 公开连续的事件流。这些事件与维基百科用户改变现有维基百科网页状态(编辑和分类)的行为有关,也与添加新网页(网页)有关。

在这个项目中,我们只对与现有网页编辑相关的事件感兴趣,因此我们相应地过滤来自 EventsStreams 服务的事件。编辑事件包含编辑日期、编辑者的用户名、标志值(取决于是机器人还是人进行了编辑/更改)、文章标题和更多元数据等信息。出于本教程的考虑,我们选择只保留其中一些变量来发布给 Kafka 然而,您可以根据您想要模拟的用例来创建您自己的消息模式。

编辑事件带有不同名称空间,用于标识不同类型的文章类别。这些名称空间在从 EventStreams 中使用时是整数,但是我们根据这个将它们映射到它们的 id 名称。

我们的消息的最终 JSON 模式示例如下:

{
    "id": 1426354584, 
    "domain": "www.wikidata.org", 
    "namespace": "main namespace", 
    "title": "articles_title", 
    "timestamp": "2021-03-14T21:55:14Z", 
    "user_name": "a_user_name", 
    "user_type": "human", 
    "old_length": 6019, 
    "new_length": 8687
}

设置项目

项目概述

在本地启动 Kafka 代理

打开一个新的终端来启动 Zookeeper 集群管理器。默认情况下,端口 2181 将用于以下机器:

bin/zookeeper-server-start.sh config/zookeeper.properties

在第二个终端中,在本地启动一个 Kafka 代理。默认情况下,它将在端口 9092 运行。

bin/kafka-server-start.sh config/server.properties

打开第三个终端,以便与卡夫卡互动。首先列出本地主机代理中当前可用的主题。

bin/kafka-topics.sh --list --zookeeper localhost:2181

创建一个新的卡夫卡主题,将其命名为 wikipedia-events 。在本主题中,我们将传播(发布)来自 EventStreams 服务的所有编辑事件。

变量复制因子分区是可选的。第一个选项指的是本主题应该初始化的不同节点的数量,这个选项帮助您实现前面提到的容错,并且只在具有多个代理的集群中有意义。分区还提供跨多个代理的可伸缩性;在这种情况下,1(一)以外的值实际上没有意义。

bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic wikipedia-events

再次列出我们的主题,wikipedia-events 应该在控制台中打印出来。

设置 Python 环境

首先将 GitHub 项目克隆到您的本地机器上。

git clone [https://github.com/ZisisFl/kafka-wikipedia-data-stream.git](https://github.com/ZisisFl/kafka-wikipedia-data-stream.git)

克隆完成后,导航到项目文件夹。

首先,我们需要创建一个新的 Python 3 虚拟环境(这不是强制性的,但是强烈推荐)。我们将这个环境命名为 kafka_env。这个项目所需的所有库都包含在 requirements.txt 文件中。如果你想自己安装必要的库,小心使用 pip installKafka-python而不是 pip install kafka 。(以下命令可能不适用于 Windows 操作系统。)

python3 -m venv kafka_venv
source kafka_venv/bin/activate
pip install -r requirements.txt

使用以下命令,执行 Python 脚本" Wikipedia _ events _ kafka _ producer . py "并打开一个新的终端,以便通过终端使用来自 Kafka 主题的消息。选项 from-beginning 不是必需的,使用时会提供已经发布到目标主题的消息的全部历史;否则,从执行以下命令的那一刻起,您将消耗消息。

bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic wikipedia-events --from-beginning

控制台中应该打印出多个 JSON 对象!

实验建议

  • 创建处理不同类型事件的多个生成器,并通过不同或相同的主题发送它们。
  • 创建将数据成批存储到数据库或将其提供给任何其他系统的消费者。
  • 创建一组消费者,他们将分担并行使用消息的工作,以提高性能。

应用线性代数导论:范数和距离

原文:https://towardsdatascience.com/introduction-to-applied-linear-algebra-norms-distances-2451e6325925?source=collection_archive---------8-----------------------

来自佩克斯扬·克鲁科夫的照片

目标:本文介绍了向量范数、向量距离及其在数据科学领域的应用

为什么要学:向量范数和距离用来描述向量的属性以及不同向量之间的相互关系。它广泛应用于聚类等机器学习技术中。

目录

  • 什么是规范?
  • 距离
  • 使用距离的示例
  • 使聚集

什么是定额?

为了理解向量的范数,让我们回忆一下向量是一个有序的有限数字列表,如下所示:

本例中的向量 x 有两个元素,因此我们可以很容易地在 2D 平面中绘制向量,如下所示:

作者图片

在上图中,向量的第一个元素对应于 x 值,向量的第二个元素对应于 y 值。很高兴知道向量的元素对应什么,但是向量的下列属性是什么?

作者图片

正如你在图中看到的,向量的进一步特征是它的范数,也就是向量在 x,y = 0 时离原点的距离,以及它的角度。定额是这样计算的:

在 Python 中,您可以像这样计算范数:

如果一个向量的范数是一个小的数,那么它就是小的;如果它的范数是一个大的数,那么它就是大的。(符合小或大的标准的数值取决于特定的应用和环境。)

为完整起见,角度θ计算如下:

观察 53 度以上的图是有意义的,因为我们比平分线(45 度)略高。但是尽管如此,我们不会关注向量的角度,因为这篇文章是关于范数和距离的。

距离

我们可以用范数来定义两个向量 ab 之间的欧氏距离作为它们差的范数:

使用距离的数据科学示例:

  • 特征距离:如果向量表示两个对象的特征,我们可以计算距离,如上所述,以获得特征距离,这是对对象差异程度的度量。举一个具体的例子,假设我们正处于疫情疫情中(比方说 Covid19),我们拥有与医院中的患者相关的向量,条目包括体重、年龄、胸痛、呼吸困难和病毒测试结果。我们可以使用特征向量距离来判断一个患者病例是否与另一个相似(至少在特征方面)。
  • 文档相异度:假设我们有两个向量,其中包含两个文档的单词出现的直方图(频率)。那么两个向量的距离代表两个文档的不相似性的度量。如果我们看的是同一类型或同一作者的文档,我们可能会期望距离更小,如果我们比较的是不同的作者和类型,我们可能会期望距离更大。

使聚集

作为一名数据科学家,如果您想解决聚类问题,向量距离的计算是至关重要的。这里,您将获得数据,在这种情况下,这些数据将是与感兴趣的实体(例如,医院中的患者)的特征相对应的多个向量。如果您有一个包含两个特征的矢量数据集,您可以将数据可视化为散点图,其中每个数据点对应一个矢量:

作者图片

在聚类中,目标是将向量分组,使得一个组中的向量彼此靠近,比如最小化彼此之间的距离,如下所示:

作者图片

本例中使用的聚类算法称为 k-means 聚类,基本上是基于本文中学习到的向量距离的计算。

今天就到这里,非常感谢您的阅读!如果你想了解未来的文章,请跟我来,如果你喜欢这篇文章,请鼓掌!

应用线性代数导论:向量

原文:https://towardsdatascience.com/introduction-to-applied-linear-algebra-vectors-29ff7e0539?source=collection_archive---------23-----------------------

来自 PexelsMax Fischer 的照片

目标:本文介绍了向量、向量运算及其在数据科学领域的应用

为什么要学习它:无论是预测、分类还是聚类,它都是几乎所有机器学习技术从数据中学习的基础

目录:

  • 什么是向量?
  • 向量加法
  • 标量向量乘法
  • 点积
  • 线性组合

什么是向量?

向量是有序的有限数字列表。它们通常是这样写的:

向量可以写在括号或圆括号中

向量的元素是该向量中的值。python 等效物是 numpy 数组。向量的大小(或长度)是其元素的数量:

示例:

  • 特征向量:在许多应用中,向量收集单个实体的不同特征。这些特征可以是对象的测量值,例如医院中患者的年龄、身高、体重、血压。
  • 时间序列:向量可以表示时间序列或信号,即某个量在不同时间的值。例如,时间序列可以表示股票市场的股票价值,也可以表示某个地区每小时的降雨量。
  • 客户购买:向量也可以表示特定客户从企业购买的记录,向量的条目表示客户在特定产品上花费的金额。

矢量加法

向量加法通过逐元素加法工作:

类似地,向量减法通过逐元素减法来工作:

示例:

  • 字数:如果向量 ab 是字数,表示给定单词在两个对应文档 AB 中的出现频率,那么 a + b 之和就是这两个文档的组合。同样,差异 a-b 给出了每个单词在文档 A 中出现的次数多于在 B 中出现的次数。
  • 时间序列:如果 ab 代表相同数量的时间序列,例如两家店的月利润,那么 a+b 之和代表两家店的月总利润的时间序列。
  • 投资组合交易:假设我们有两个向量。首先,原始投资组合向量 s ,其条目表示投资组合中给定资产的份额数量。第二,交易向量 b ,正条目给出购买的资产数量,负条目给出出售的资产数量。然后我们最终的投资组合由 s +b 给出。

标量向量乘法

另一个重要的向量运算是将向量与标量相乘(这只是“数字”的一个时髦说法),这是通过将向量的每个元素与标量相乘来完成的:

例子:

  • 材料需求:假设向量 q 是生产某种产品的一个单位的材料清单,例如一部手机。那么 q 的条目就是生产一部手机所需的原料量。为了生产 300 台手机,我们需要 300 q 给出的原材料。
  • 音频缩放:如果一个矢量 v 表示一个音频信号(正如我们所了解的,它是一个时间序列),如果我们取标量倍数 3 v ,信号的音量可以增加 3 倍。

点积

现在,这是线性代数中最重要的运算之一,设法出现在与数据科学相关的所有领域,从[线性回归](http://Linear regression)到神经网络。两个向量的点积是通过将向量的每个对应元素相乘并将所得乘积相加来计算的。自己看:

例子:

  • Sum:如果我们取向量 ab 的点积,其中 a 仅由 1 组成,并且长度与 b 相同,我们得到 sum 运算。
  • 平均:如果我们取向量 ab 的点积,其中 a 仅由 1/n 个条目组成(n =向量的共享长度),我们得到向量 b 的平均值。
  • 同现:假设向量 ab 是相同长度的向量,其中条目只能是 0 或 1,那么 ab 的点积给出两个向量都显示为 1 的条目总数。这可能意味着在某些情况下,我们有相同的预测或特征。
  • 情感分析:文本分析中的一个具体问题是给定文本的情感(情感极性)是积极的、消极的还是中性的。我们可以通过创建两个向量来初步解决这个问题。首先,长度为 n 的向量 x 表示文本中 n 个单词的出现频率。第二,相同长度的向量 w ,代表给定单词的极性,条目为-1(表示‘不好’或‘可怕’之类的否定词)、0(表示‘和’之类的中性词)或 1(表示‘好’或‘awsome’之类的肯定性词)。然后 xw 的点积给出了文本中情感的第一个(粗略的)度量。

线性组合

点积的一种特殊解释是,我们将一个矢量 x 乘以另一个矢量 β 称为 x 的线性组合:

这里将 β的元素称为系数。x 的线性组合构成了预测连续量的最流行的统计工具之一的支柱——线性回归。例如,它用于房价预测,其中我们有一个特征向量 x ,并希望通过回归系数 β 找到这些特征的最佳权重,以便在给定房屋特征(例如,房屋面积(平方英尺)、卧室数量等)的情况下预测房价。)

今天就到这里,非常感谢您的阅读!如果你想了解未来的文章,请跟我来,如果你喜欢这篇文章,请鼓掌!

时间序列预测的 ARIMA 介绍

原文:https://towardsdatascience.com/introduction-to-arima-for-time-series-forecasting-ee0bc285807a?source=collection_archive---------6-----------------------

了解用于时间序列预测的一种比较流行的 ML 算法。

自回归综合移动平均(ARIMA)模型是时间序列预测中较为流行和广泛使用的统计方法之一。它是一类统计算法,捕捉时间序列数据特有的标准时间依赖性。在本帖中,我将向您介绍 ARIMA 的基本原理,并展示一个用 Python 开发用于时间序列预测的 ARIMA 的实践教程。

托马斯·博尔曼斯在 Unsplash 上的照片

**Table of Content:** 1\. What is ARIMA?
2\. Introduction to the Dataset
3\. Implementing ARIMA model in Python
4\. Forecasting using ARIMA**Notes before we begin**:
1\. Download the [rainfall CSV dataset here](https://drive.google.com/file/d/1CL1l38xkg9NJTxUpq-i7CeMNjkp3BKIh/view)
2\. Install dependencies: 
  - *pip install statsmodels* OR *conda install statsmodels
  - pip install patsy OR conda install patsy*

什么是 ARIMA?

关键词:平稳性和自相关性

在我们深入 ARIMA 的正式数学定义之前,让我向你介绍一下平稳性的概念。平稳性仅仅意味着不依赖于时间的观察。对于依赖于时间的数据(如季节性降雨),平稳性条件可能不成立,因为不同的时间将产生不同的观测值。

理解 ARIMA 的另一个重要概念是自相关。它与典型的相关性有何不同?首先,相关性涉及两组不同的观察值(如房价和可用公共设施的数量),而自相关涉及同一组观察值,但跨越不同的时间(如夏季与秋季的降雨量)。

现在让我们来分解 ARIMA 的不同组成部分:自回归(AR)、综合(I)和移动平均线(MA)

IMA 的自回归:自回归

正如您可能已经猜到的,自回归(AR)回归模型建立在自相关概念的基础上,其中因变量取决于其自身的过去值(例如,今天的降雨量可能取决于昨天的降雨量,等等)。一般等式是:

ARIMA 的自回归模型

如图所示,在时间 tYt的观察Y取决于Yt-1, Yt-2, ..., Yt-p。为什么是Yt-p而不是Y0(即。初始值)?这里的 p 称为滞后阶数,表示我们在模型中包括的先前滞后观测的数量(例如,我们可能排除了当前时间之前 5 天以上的观测,因为这些较早的降雨观测可能不相关)。

AR[I]MA 中的 I:综合

回想一下我们对平稳性的解释。ARIMA 的积分部分试图将时间序列数据的非平稳性转换成稍微平稳一点的东西。我们如何做到这一点?通过对任意两对观测值之间的进行预测,而不是直接对数据本身进行预测。

ARIMA 的差异

请注意,根据我们在训练 ARIMA 模型时设置的超参数 d ,我们如何多次执行差分运算(Y→Z和 Z→Q)。

移动平均线

现在 ARIMA 的最后一块是移动平均线。它试图通过对你过去的观测值进行某种聚合操作,以残差ε(读作:ε)来减少我们的时间序列数据中的噪声。

ARIMA 移动平均线

ε项表示来自聚合函数的残差,这里的 q 是另一个超参数,与p相同,但不是识别时间序列数据本身的时间窗口(p),q指定移动平均值残差的时间窗口。

现在让我们用 Python 来实现 ARIMA。

数据集简介

如果您尚未下载数据集,请在此处下载。

让我们对数据集进行一些基本的探索。

import pandas as pddf = pd.read_csv('rainfall.csv')
df

降雨时间序列(图片由作者提供)

我们的数据集是从 2010 年 1 月 1 日到 2020 年 5 月 1 日的日降雨量时间序列数据(单位为毫米)。

让我们画出降雨量数据如何随时间变化的图(为了便于说明,我们以一个月为例)。

import matplotlib.pyplot as plt# First 30 days
first_30 = df[:30]first_30.plot.line(x='date', y='rainfall')

第一个月的降雨量数据(图片由作者提供)

我们还可以检查数据集中可能出现的任何自相关。

from pandas.plotting import autocorrelation_plotautocorrelation_plot(first_30['rainfall'])

自相关(图片由作者提供)

当滞后时间很短(0-5 天)和足够长(20-25 天)时,似乎有轻微的相关性,但不在中间值之间。

我们接下来可以从 ARIMA 的实施中获得有价值的信息!

用 Python 实现 ARIMA 模型

首先,我们需要导入statsmodels库。

from statsmodels.tsa.arima_model import ARIMA

然后,我们用这些初始超参数为 p,d,q 定义模型(如之前在什么是 ARIMA?节)。

# fit modelp,d,q = 5,1,0model = ARIMA(first_30['rainfall'], order=(p,d,q))
model_fit = model.fit()

让我们看看结果摘要。

print(model_fit.summary())

ARIMA 模式总结(图片由作者提供)

注意顶部的 AIC、BIC 和 HQIC 指标?这些值越低,模型的拟合度越好。所以可以进行进一步的超参数调优或者数据预处理,以达到更好的效果!

我们有了第一个 ARIMA 的工作模型。最后一节将带您了解如何根据我们训练好的模型进行未来预测。

使用 ARIMA 进行预测

让我们首先扩展我们的数据集,以包括365天而不是30

data = df[:365]['rainfall'].values
  1. 然后,我们将数据分为训练集(66%)和测试集(34%)。
train_size = int(len(data) * 0.66)
train, test = data[0:train_size], data[train_size:len(data)]

2.并初始化历史值和预测值用于比较目的

history = [x for x in train]
predictions = list()

3.现在,我们训练模型,并根据存储在测试数据中的信息进行未来预测

for t in range(len(test)): model = ARIMA(history, order=(5,1,0))
    model_fit = model.fit()
    pred = model_fit.forecast()
    yhat = pred[0]
    predictions.append(yhat) # Append test observation into overall record
    obs = test[t]
    history.append(obs)

4.让我们评估一下我们的表现

from sklearn.metrics import mean_squared_error
from math import sqrtrmse = sqrt(mean_squared_error(test, predictions))print('Test RMSE: %.3f' % rmse)
>>> Test RMSE: 20.664

相当大的 RMSE!毫无疑问,这里还有改进的空间。

我们还可以画出观察和预测之间的差异,并比较两者是如何相似的(或不同的!)

评价(图片由作者提供)

不算太差!我们的预测(红色)与某些天的观测(蓝色)非常相似(除了具有明显高峰的极端降雨情况)。

离别的思念

就是这样!到目前为止,我们已经讨论了 ARIMA 的基本原理以及如何用 Python 实现它。ARIMA 的一个关键特征,就像任何其他 ML 模型一样,是它对超参数调整的依赖。因此,请务必执行这些步骤!除了微调之外,良好的工作领域知识也是产生高性能 ARIMA 模型的关键。你觉得 ARIMA 怎么样?

https://tinyurl.com/2npw2fnz】我会定期通过我的电子邮件简讯用通俗易懂的语言和漂亮的可视化方式总结人工智能研究论文。

使用 Tensorflow 介绍人工智能、机器学习和深度学习

原文:https://towardsdatascience.com/introduction-to-artificial-intelligence-machine-learning-and-deep-learning-with-tensorflow-b5fa20477e89?source=collection_archive---------25-----------------------

机器学习和张量流的起点

蒙大拿的野花。作者图片

这是我希望做的关于高级机器学习的一长系列的第一部分。Tensorflow 最近推出了 2.x,它与 Keras 的集成使它成为一种真正易于使用和学习的功能性语言。在这一点上,Tensorflow 和 PyTorch 非常相似,因此学习其中任何一种都将在参与人工智能复兴中为您提供很好的服务。

这并不意味着是一个数学演练,而是一个更实际的演练-这将帮助您自己开始使用 Tensorflow。也就是说,如果你想学习,我会添加一些解释来解释某些概念。

本文将假设您了解一些 Python。

目录

  1. 一种新的编程模式
  2. 这是怎么回事?
  3. 预测波士顿房价数据集中房屋的中值

一种新的编程模式

为了达成共识,这里澄清了一些定义。

什么是人工智能、机器学习、深度学习?

人工智能:计算机系统对人类智能的模拟。人工智能可以包括硬件和软件系统,它专注于 3 个认知过程:学习、推理和自我纠正。作为一个社会,我们目前处于人工智能的基础形式——人工狭义智能。这实质上意味着人工智能主要是复杂、非结构化数据集的非凡模式匹配器,因此,它最常见的应用是自然语言处理、计算机视觉和语音识别。

机器学习:通常被称为人工智能的一个子领域,机器学习是从数据中看到的例子中学习的实践。它采用带有答案的例子,并学习在给定数据的情况下产生这些答案的规则(模式)。ML 模型建立在统计学的基础之上,ML 优化器(他们如何学习这些模式)建立在微积分的基础上,高效的 ML 编程建立在线性代数的基础上。

深度学习:机器学习的一个子领域,是构建多层神经网络的实践。深度学习的常见用例是图像分类、时间序列预测和欺诈检测。

注意,深度学习只是代表了一套与复杂数据集的神经网络相关的方法;它们不是 ML 的灵丹妙药,也不是每个场景中的最佳建模选择。他们兴奋的一个重要原因是,他们已经能够学习获取数据并为各种非结构化任务创造答案的规则。

在解开更多关于深度学习和神经网络的事情之前,我们先来看一个例子。

开始简单

假设您想要预测一栋 7 居室房屋的价格。因此,想象一下,如果房屋定价很简单,每间卧室的价格为 50k + 50k,那么一间一居室的房屋价格为 100k,一间两居室的房屋价格为 150k,等等。你出去收集一些房子的数据,获得它们的卧室数量和价格。

为了在我们的模型中创造稳定性,我们可以适当地将数据缩小到单个数字(并以几十万来解释答案)。

作者图片

构建最简单的神经网络

作者图片

这将打印出:

作者图片

本质上,我们在网络中有一层一个节点/神经元。密集是一种识别其中有神经元的层的方法,连续的层通过顺序定义(在这种情况下,我们只有一个神经元和一个层)。

允许神经网络学习

现在,网络创建完毕,但我们需要为它提供两样东西:

  1. 学习的方法
  2. 学什么

作者图片

编译行包括两个非常重要的概念:

  1. 优化器:这代表了一种方法,在这种方法中,神经网络遍历一个可能的领域,找到代表数据的最佳模式集,从而产生一组答案
  2. 损失函数:这代表了告诉神经网络它是否朝着正确的方向前进的度量。

把这想象成我们建立的模型,穿越一系列的山丘,试图找到地形的最低点。它可以按线性顺序一次执行多个步骤,也可以随机执行巨大的跳跃(或者其他更聪明的技术)——这是优化器的基础。“sgd”代表随机梯度下降,这实质上是模型在地形上随机跳跃以找到最低点的地方。这个优化器非常有用,因为它可以防止模型陷入局部极小值,而这个极小值实际上并不是整个全局的底部,即全局极小值。

损失函数惩罚向错误方向迈出一步的模型,因此它知道它是否正在接近底部,也称为收敛。均方差是用于回归任务的常见损失函数,因为它预测连续值。它实际上是找到残差(实际预测值),对其求平方,对所有平方误差求和,然后除以值的计数,得到一个度量值。

第二条线符合我们收集的数据的模型,并运行 500 个时期。历元表示模型将经历训练循环的次数。训练循环是模型“猜测”一个值,然后测量该值与实际值的接近程度,并对其进行迭代,直到尽可能好为止的过程。

预测新值

现在我们可以预测 7 间卧室。

作者图片

[3.9685223]

你可能会有点困惑,因为我们的数据直接映射到一个线性方程:y=.5x+.5,如果我们为 x 输入 7,我们应该得到 4——那么为什么我们得到~3.97 呢?

这是因为包括神经网络在内的 ML 模型的基础是概率。这些模型不会在确定性的世界中运行,我们实际上也不想让它们运行。机器学习的整个目标是建立模型,这些模型可以准确地、合乎道德地归纳出看不见的数据。如果它能“明确地”识别模式,这是不可能的——它需要考虑概率因素。此外,我们只有 9 个数据点来训练模型,这些数据点可以显著影响结果与规则的“真实公式”的接近程度。

机器学习的整个目标是建立模型,这些模型可以准确地、合乎道德地归纳出看不见的数据。

这是怎么回事?

神经网络结构

神经网络由 3 层组成:

  1. 输入层:在我们的例子中,我们只有卧室,但是当我们扩展我们的数据集(邮政编码、平方英尺、财富等)时,每个新节点都会被添加一个额外的特征。)
  2. 隐藏层:我们只有一个包含一个神经元的隐藏层,但是对于深度神经网络,神经元功能保持不变。每个神经元找到其特征的某种线性组合,然后对其应用非线性激活函数。
  3. 输出层:这是我们的房价。它也可以是分类输出图层,但我们会希望通过不同的损失函数进行测量。

深度神经网络(或多层感知器),深度学习的面包和黄油,利用了两个以上的隐藏层。

作者图片

神经网络至少需要这些东西才能正常工作(适当地推广到新数据):

  1. 大量数据(因此痴迷于大数据)
  2. 敏感激活函数
  3. 有效且高效的优化算法
  4. 适当损失函数

当我们谈论大量数据时,我们通常指的是数据应该具有大容量和多样性。如果模型希望有效地学习示例并归纳出新数据,它需要一组有代表性的示例来学习。

每个优化算法和损失函数如何工作的技术细节有点超出了本文的范围,但是我将介绍它们的用途和常见选择。

激活功能

激活函数是每个节点非线性转换数据以找到更复杂模式的一种方式。以下是一些最受欢迎的:

激活函数示例。维基百科

确定哪一个最适合您的模型的好方法是真正了解您的数据和您的目标。例如:ReLU 是一个常见的选择,如果我们要建立一个完整的房价预测模型,我们可能会使用它,但是为什么呢?ReLU 将< 0 到 0 的值截断,这很好地模拟了我们的产出价格,因为我们的模型预测房子的价格为负数是没有意义的。

有趣的事实:如果你在激活函数中认出一个熟悉的名字(逻辑),那不是偶然的。逻辑回归是神经网络在最简单的尺度上所做的一个极好的例子。它采用各种输入,线性组合它们以学习各自的权重,然后将它们分解成一个 sigmoid 函数,以产生一个介于 0 和 1 之间的输出。

最优化算法

神经网络学习的方式是通过它们的优化技术。梯度下降是这方面的主要算法,但 GD 的变体已被提出,它们工作得非常好。这里有几个流行的:

  1. 随机梯度下降
  2. RMSProp
  3. 圣经》和《古兰经》传统中)亚当(人类第一人的名字

本质上,每一个都试图提出不同的方法来遍历广阔的领域以找到最低点——全局最小值——并且根据您的用例,不同的优化可能是有价值的。

红线是试图找到最小值的优化算法的一个例子。维基百科

损失函数

损失函数很大程度上取决于我们要做的任务。如果我们预测一个实数值(回归),常见的损失函数是均方误差。如果我们预测一个分类变量(分类),常见的损失函数是二元交叉熵(对于多分类是稀疏分类交叉熵)。

但是实际上发生了什么呢?

当该模型通过网络向前传播信息(向前传播)时,它猜测并学习与沿途增量损失相对应的权重。随着模型的每次前进,它也反向传播信息以重新更新权重,并在下一次变得“更聪明”(反向传播)。这是梯度下降背后的功能思想,也是数学如何如此完美地将所有这些部分联系在一起。

作者图片

导数在更新权重的过程中学习。作者图片

预测波士顿房价数据集中房屋的中值

我们可以使用波士顿房价数据集(这里是的描述)并尝试建立一个更深层次的神经网络来评估性能,而不是使用一个人为的 9 个值的列表。

作者图片

作者图片

我们正在预测“MEDV”值,因此我们可以将数据集分为 X 和 y,然后使用 sklearn 的 train_test_split()通过 75/25 拆分将我们的数据分为训练集和测试集。这允许模型适合训练数据,然后在测试数据上验证其性能。这样做是为了创建一个能够推广到新的、看不见的数据的模型。

作者图片

如果我们想让模型在精确度(或我们想要的任何其他度量)达到某个点时停止训练,会怎么样?本质上,如果模型能够根据我们选择衡量的指标更快地学习数据集中的模式,我们就不需要模型为我们设置的所有时期保持训练。

我们可以建立一个回调日志,如下图所示,当均方差小于 1 时停止训练。由于目标值字段是在 1000 美元左右,这将意味着模型何时能够预测在大约 31 美元以内。

我们也可以很容易地添加多层来扩展我们的网络;这与我们的激活功能相结合,允许每一层学习更复杂的模式。如果增加更多能够学习更复杂的模式,为什么不只是用无止境的层和节点使网络超载呢?在您的设计选择中,至少有几个需要慎重考虑的原因:

  1. 当您过度复杂的模型架构时,过度拟合很容易发生。如果模型能够在任何事物中找到模式,它也很容易将噪声作为信号,这妨碍了它推广到看不见的数据的能力。
  2. 计算成本是真实存在的。用大量数据训练大规模网络会占用大量计算资源。
  3. 奥卡姆剃刀是机器学习的一个基本支柱。更容易理解、设计和解释的简单解决方案通常是更好的实现选择。这显然不适用于每一个问题,但它适用于大多数问题,并且肯定适用于这个问题。

奥卡姆剃刀,“简约原则或简约法则是‘实体不应被乘以超过必要性’的解题原则……”

此外,我们可以通过将“sgd”更改为“adam”来轻松更改优化器。这可能会对结果产生影响,因此如果您正在进行试验,请确保尝试多种实现。

作者图片

作者图片

根据训练数据,该模型似乎做得不错,但肯定不是最好的。让我们根据测试数据进行评估。

作者图片

作者图片

模型在测试集上表现明显更差,很明显过度拟合正在发生。一个可能的原因是,我们的模型对于一个有 500 行的数据集来说太复杂了(而训练集只有其中的 75%)。尽管如此,当涉及到神经网络时,我们也没有应用通用技术来减轻过度拟合(丢弃、正则化等。).更不用说梯度增强树通常在结构化数据上表现得更好,但那是不同的日子。

如果我们确实想在这个数据集上改进这个模型,下面是我们可以尝试的一些关键事情:

  1. 超参数调整:有许多超参数会显著影响模型性能。一些关键因素包括学习速度、批量大小、节点数量等。
  2. 改变优化算法:随机梯度下降可能是比 Adam 更好的选择,但它也可能是 Adam 需要的调整。
  3. 交叉验证(Cross Validation ):一种将训练集和测试集分层的技术,允许更严格地根据看不见的数据评估模型。这也因此给了模型较少的数据来训练。
  4. 丢弃/正则化/其他过度拟合技术:这些技术中的每一种都可能真正有助于惩罚模型过于接近我们数据集中的噪声。

免责声明:我最近(在发表后)发现,这个数据集随意地假设人们更喜欢在种族隔离的街区购买住房;如果我事先知道这一点,我就不会在这个例子中使用它。除了教授职业道德实践之外,请谨慎使用该数据集。

下次请继续收听

今天到此为止!这是对处理神经网络和张量流的机器学习“深”端的探索,但这真的只是开始,这个世界真的如此迷人。

如果您对学习计算机视觉、自然语言处理、序列模型、图形机器学习等感兴趣,请务必关注/订阅!

参考文献

[1]深度学习。人工智能、神经网络和深度学习

【2】深度学习。AI,改进深度神经网络:超参数调整、正则化和优化

【3】深度学习。人工智能、机器学习和深度学习的 TensorFlow 简介

Python 异步编程简介

原文:https://towardsdatascience.com/introduction-to-asynchronous-programming-in-python-3cd190748cd5?source=collection_archive---------5-----------------------

异步|编程| PYTHON

编写更具响应性和性能的程序指南

Unsplash 上由 Max Duzij 拍照

在同步环境中,程序执行遵循一组顺序操作。执行流将开始处理一个步骤,并在继续下一个步骤之前等待它返回结果。通过异步编程,我们可以使用操作所需的滞后时间来处理并返回一个结果,以继续处理其他任务。

我们之前已经讨论了并发的概念及其在 Python 中的用法。如果你喜欢,可以在这里看看。

在本帖中,我们将进一步讨论异步编程的话题,并介绍 Python 中的 asyncio 库。

单线程异步

单线程异步是一种编程模型,它只使用一个线程通过交错执行几个任务来实现并发。在这种编程模型中,单线程按顺序执行不同的任务。

为了同时处理,我们需要初始化一组线程或进程。让我们假设一组 2 个任务—【T1,。在执行 T1 时,主线程可以暂时暂停线程中 T1 的执行,开始处理 T2 ,然后返回 T1 完成。

单线程异步的最佳用例是执行 I/O 绑定任务,因为它们通常有很长的空闲时间。我们触发一个 I/O 任务,在其空闲时间,线程可以开始执行另一个任务。

为了管理执行流,我们通常使用事件循环。事件循环负责维护事件队列,为所述队列收集项目,并处理它们。我们将在下面展示实际的例子。

合作多任务

当事件循环遇到 I/O 任务或其他长时间运行的操作时,事件循环中运行的任何任务都必须暂停。

在 Python 中,这些任务会自动挂起自己,并通过将控制权交给事件循环来允许其他操作运行。I/O 操作完成后,任务将通过事件循环恢复到其原始状态(暂停前)。

我们可以通过协程对象实现这种行为。在 Python 中,我们可以在函数定义之前使用 async 关键字来实现这一点。这个协程的执行产生一个协程对象。

async def this_is_a_coroutine_func():
     # .....

协程函数

协程函数是一个异步函数,它能够放弃对调用者的控制,而不会丢失其原始状态。必须使用 await 关键字来等待协程函数。它可以等待事件,在完成时返回各自的结果,或者引发异常。

当 Python 遇到一个 await 时,它会在该点暂停协程的执行,并将控制权交给事件循环。当诸如超时事件或完成事件之类的事件发生时,事件循环将把控制传递回协程。

对于要执行的协程对象,需要将其包装在 Future 对象中,并传递给正在运行的事件循环。

我们可以在事件循环中执行一个协程,如下所示:

loop.run_until_complete(some_coroutine_task)

让我们编写第一个异步程序。

在上面的程序中,我们将我们的协程对象 say_hello() 定义为打印 Hello ,等待 1 秒,然后打印 World 的函数。注意,我们使用 async def 关键字来定义协程。在我们的协程内部,我们也在调用另一个协程(asyncio . sleep);因此,我们需要 等待 这个协程。

我们定义事件循环,并在事件循环中执行我们的协程,直到它完成。当事件循环开始执行时,我们将看到显示的第一条打印语句。当执行到达休眠步骤时,事件循环暂停执行并等待其完成。在此期间,事件循环可以开始处理另一个任务。

完成 asyncio.sleep 操作后,事件循环将任务恢复到其原始状态,并通过执行最后一条打印语句继续执行。

总而言之:

  • 事件循环被初始化
  • 协程作为未来对象提交给事件循环
  • 未来对象的状态被设置为待定
  • 事件循环开始执行
  • 协程执行第一次打印和异步休眠
  • 协程状态变为挂起,控制传递给事件循环
  • 1 秒钟后,协程恢复
  • 执行下一个打印,协程完成
  • 控制返回到事件循环

未来物体

未来是控制一个函数并在完成时返回其结果的对象。未来对象使我们能够使用几个控制操作来管理协程。一些可用的功能包括:

  • cancel()-取消待定的将来
  • done()-如果未来已完成或已取消,则返回 True
  • result()-返回未来的结果
  • exception() —返回未来执行期间发生的任何异常
  • add_done_callback() —在将来完成时执行回调函数

工作

任务是 Future 的子类,用于管理事件循环中协程的执行。

协程必须包装在任务中,然后才能在事件循环中执行。我们可以使用asyncio . create _ task()来实现这一点。

我们也可以使用 asyncio.wait 等待一个任务/一组任务完成。这为我们提供了在继续之前等待所有传递的协程完成的功能。

在上面的程序中,我们创建了一个任务列表,然后使用 asyncio.wait 函数在一个事件循环中执行它们。在任何时候,我们都可以访问所有已经完成的任务和尚未完成的任务。

等待 功能也提供了超时功能。使用超时参数,我们可以指定等待协程完成的时间。如果超时后任何协程没有完成,事件循环将暂停它,它将保持挂起状态。

我们可以访问挂起的任务并调用 cancel() 函数来杀死它们。此外,我们还可以使用asyncio . wait _ for()函数,该函数也在超时的情况下等待协程,但是在相应的超时过去之后自动取消任何未完成的任务。

在多线程中运行

同样的代码结构也可以用于通过多线程执行多个协同程序。

我们创建执行我们的逻辑的阻塞目标函数(在这种情况下,我们对每个数字求平方)。我们创建了一个接受事件循环的协程对象和一个使用多线程执行多个协程的线程池。

在本例中,我们使用的是asyncio . gather,而不是 asyncio.wait 。gather 函数更高级,主要用于对结果进行分组。等待功能不会直接给出结果,相反,我们必须使用 手动收集结果。结果()函数。

结论

异步编程一开始可能会令人生畏,尤其是对新开发人员来说。尽管如此,Python 提供了几个库来帮助我们在程序中构建、交互和集成异步操作。在这篇文章中,我们介绍并讨论了异步编程的基本概念,以帮助您入门。围绕 Python 中的 asyncawait 关键字还有更高级的概念和功能。我强烈建议您继续阅读这个主题,并使用您自己的用例进行实践。

你喜欢这篇文章吗?如果是的话,也许你可以考虑成为会员来支持我和你其他喜欢的作家。

https://david-farrugia.medium.com/membership

想给我买杯咖啡吗?

https://paypal.me/itsdavidfarrugia?country.x=MT&locale.x=en_US

想联系吗?

我很想听听你对这个话题的想法,或者其他什么。如果你想联系我,请发邮件到 davidfarrugia53@gmail.com给我。

Linkedin——Twitter

注意机制互动指南

原文:https://towardsdatascience.com/introduction-to-attention-mechanism-8d044442a29?source=collection_archive---------13-----------------------

理解 ML

注意力是如何产生的?为什么它会起作用,为什么它现在是 ML 中最重要的事情之一?

介绍

注意机制是机器学习中最重要的发明之一,目前(2021 年)它被用于在几乎每个领域取得令人印象深刻的成果,今天我想解释它的来源和工作原理。

在开始解释注意力之前,我们必须回过头来看看注意力应该解决的问题。在 2015 年之前,当输入序列非常长时,RNN 会出现问题。

图 1:基于 “序列对序列神经网络学习”、NeurIPS 2014 论文、 UMich 设计的 RNN 序列对序列

注意
这只是原图的截图,不幸的是我不能在介质上包含应用程序的一部分。如果你想玩它请直接去这个链接

只要句子很短,这种解决方案就很好。在解码器完成其工作后,我们剩下了上下文向量c初始解码器状态s0。这两个向量必须“汇总”整个输入序列,因为我们要将它们送入模型的解码器部分。你可以把上下文向量看作是在编码序列和解码序列之间传递信息的东西。

长句问题

对于长句,像 T=100 ,很可能我们的上下文向量 c 不能够保存来自编码序列的所有有意义的信息。想想这句话:

“在某种程度上,人工智能比我们想象的更近也更远。AI 更接近于能够做比大多数人预期的更强大的事情——驾驶汽车、治疗疾病、发现行星、理解媒体。这些都将对世界产生重大影响,但我们仍在研究什么是真正的智能。”——马克·扎克伯格【建筑贾维斯】

将第一句话压缩成上下文向量要比对整个引用做同样的事情容易得多。我们可以创建越来越长的上下文向量,但因为 rnn 是连续的,不会按比例增加。这就是注意力机制发挥作用的地方。

想法是在解码器的每个时间步长创建一个新的上下文向量,其不同地关注编码序列。****

图 2:与 RNN 的序列对序列(注意),基于 【神经机器 transla$on 通过联合学习对齐和翻译】,NeurIPS 2015 论文, UMich 设计

这次我们在解码器的每一步都计算一个额外的上下文向量。让我们通过一个完整的步骤来解释正在发生的事情。

1.计算比对分数

图 3:t = 1, 的比对分数来源:erdem.pl

t =1 时,我们将使用解码器状态s _ t-1来计算比对分数。为了计算每个编码器状态的校准分数,我们使用了一个名为校准函数的函数,但它只是一个 MLP(多层感知器)。每个校准分数可以被视为“在状态 s 0 下,有多少 h 1 对预测输出有用”。alignment 函数输出一个标量值,它是一个实数,我们不能就这样使用它,我们必须使用 softmax 函数来规范化这些值。

2.计算注意力权重

图 4:t = 1, 的注意力权重来源:erdem.pl

softmax 函数的输出被归一化,因此所有数字的总和为 1。这些输出被称为注意力权重,顾名思义,它们向模型显示“它应该关注相应的隐藏状态多少”。

3.计算上下文向量

图 5:t = 1 的上下文向量计算, 来源:erdem.pl

现在发生了很多事情(上图中的 3 个步骤)。首先,我们将每个注意力权重乘以相应的隐藏状态( a 1,1 × h 1,1, a 1,2 × h 1,2……)。然后,将所有结果相加以用作上下文向量 c 1** 。**

注意: 你可能已经注意到,在这一点上“上下文向量”实际上是一个“上下文标量”但这只是因为我们决定只输出 1D(现在更容易展示和理解)。当我们开始将注意力抽象到它自己的层面时,我将切换到向量。

4.计算第一个输出

图 6:t = 1 时解码器的输出, 来源:erdem.pl

在第一个时间步长结束时,我们最终可以计算解码器的第一个输出。使用上下文向量 c 1、先前解码器的状态 s 0 和开始标记 y 0 来计算该输出。有趣的是,在整个过程中,我们不必将 f_att 作为一个单独的模型来训练。整个过程是可微的,所以我们可以通过计算图反向传播。

5.并重复…

图 7:t = 2 的新上下文向量, 来源:erdem.pl

在时间步长 t=2 时,我们唯一要做的事情是改变输入以计算从 s 0 到 s 1** 的比对分数。使用相同的过程,我们计算新的分数( e2,1,e2,1……)和注意力权重( a2,1,a2,1……)。然后将新的注意力权重和编码器的隐藏状态相乘,以计算新的上下文向量 c 2。此时,整个过程只是在循环中运行,直到解码器产生【停止】 token(有时也叫【EOS】token,eng。句尾)。**

注意力权重可视化

图 8:英语到法语翻译的注意力权重,来源: 通过联合学习对齐和翻译的神经机器翻译

在原论文中,有一个简单的可视化的注意力权重 ai,j 是在翻译英文句子“关于欧洲经济区的协议于 1992 年 8 月签署”时生成的译成法语“1992 年 8 月签署的欧洲经济区协议”。这个可视化向我们展示了一些有趣的事情。

第一件事是一个对角线模式,它告诉我们,模型把更多的注意力放在来自相同位置的相应法语单词上。第二件事更有趣,它是短语“欧洲经济区”,在法语中有相反的顺序“欧洲经济区”。我们可以看到,当生成la令牌时,模型更关注theArea,那么当生成zone令牌时,它关注AreaEconomic(忽略European)。另一个有趣的观察是 "a été signé" ,其中当生成aété令牌时,模型同时考虑wassigned(这在法语中是有意义的,因为我们需要知道单词étre的确切变体)。

这个热图很重要,因为我们没有告诉模型它应该注意哪些单词,它是自己学习的。此外,我们还得到了模型决策的某种可解释性。

注意力不知道输入是一个序列

您可能已经开始担心上一步我的信息发生了什么:

“我们没有利用 h 向量是有序序列的事实。它被用作无序集。为了解决这个问题,我们必须给每个元素添加一个位置编码

我已经单独写了一篇关于位置编码的文章,因为这篇文章包含了太多的信息。如果你感兴趣,请查看了解变形金刚中的位置编码。

这仍然是一个东西,但不是解决这个问题,而是利用它来抽象注意力机制,并将其用于不同于文本序列的东西。用注意力描述图像呢?同年有一篇名为 “展示、参与、讲述:具有视觉注意力的神经图像字幕生成” 的论文,该论文在 RNN 解码器的帮助下,利用对 CNN 嵌入的注意力来生成图像字幕。

图 9:带注意的图像字幕(仍为 RNN),基于 【展示、出席、讲述:带视觉注意的神经图像字幕生成】论文, UMich 设计

注意
这只是原图的截图,不幸的是我不能在介质上包含应用程序的一部分。如果你想玩它请直接去这个链接

在本文中,作者提出了一种基于卷积特征提取的解决方案,而不是标准的 RNN 编码器网络。我们使用 CNN 的这些功能来计算状态,然后计算 RNN 解码器每个时间步长的对齐分数。和前面的例子一样,我将带你经历整个过程,但是你可能会根据上面的交互图理解它:)

图 10:提取特征的比对分数计算, 来源:erdem.pl

我们假设 CNN 已经被训练并产生了我们的 3x3 网格。我们将使用初始网格来预测初始隐藏状态(有时它可以随机生成,甚至设置为 0)。现在,我们必须将相同的网格和 s 0 传递给对齐函数,以计算网格的每个值的相应对齐分数

这给了我们 t=1 时间步长的对齐分数。和前面的例子一样,每个比对分数都是一个标量,它告诉我们“给定特征在当前时间步长中有多重要”。

图 11:注意力权重, 来源:erdem.pl

计算出比对分数后,我们需要应用 softmax 将分数归一化为某个概率分布,其总和为 1。

图 12:计算上下文向量并生成第一个输出, 来源:erdem.pl

现在,我们所要做的就是计算哈达玛乘积(逐元素乘法,…)并对所有内容求和以获得上下文向量 c 1。其余部分的工作方式与前面的示例完全相同,因此我们使用上下文向量 c 1、起始令牌 y 0 和初始解码器状态 s 0,并通过 gU 函数来计算 s 1 状态,并获得一些输出令牌 y 1。

注意 此时不需要求和,我这样做只是为了让上下文向量的形状和上一个例子一样。我们可以很容易地使用一个 3x3 的矩阵作为函数的输入。

图 14:第二个时间步长(t=2), 来源:erdem.pl

与之前相同,我们使用新生成的 s 1 状态来计算新的对齐分数 e_ 2、 ij ,然后使用 softmax 对其进行归一化,并将其计算到上下文向量 c 2 中。当解码器产生【停止】令牌作为输出时,该过程停止。

注意力权重的可视化

与序列到序列的翻译一样,在这种情况下,我们能够可视化注意力权重。我将使用作者提供的一个例子。

图 15:图像注意力可视化,白色区域具有较高的注意力权重值,来源: 显示、出席、讲述:具有视觉注意力的神经图像字幕生成

正如你所看到的,这不是一个解释模型的理想解决方案,但是仍然可以给你一种关于正在发生的事情的直觉。尤其是当我们看到像frisbeepark这样的记号时,当模型关注那些确切的对象时。在令牌woman的情况下,图像上的两个人节省了相似的注意力权重,但这仍然没问题,因为模型可以决定哪个是主题以及如何命名那个人。

还有一种类型的注意力叫做硬注意力,我们不使用 softmax 函数,而是选择一个具有最高对齐分数的特征,并使用该特征的值作为上下文。这需要在训练过程中进行一些改变,我现在不打算讨论这些。这里有一个努力关注的例子。

图 16:硬注意可视化,白色区域为模型注意的区域,来源: 展示、注意、讲述:视觉注意的神经图像字幕生成

如您所见,标题已经更改。现在它在说“一个男人和一个女人在田野里玩飞盘。”取而代之的是“一个女人在公园里扔飞盘。”。当生成标记frisbee模型关注孩子时,注意区域不完全与生成的标记相关(如在软注意中)。

让我们抽象一下注意力

现在,当你知道注意力是什么的时候,我们可以开始抽象这个想法来创建所谓的“注意力层】。首先,让我们总结一下我们现在所拥有的:

目前,我们的相似性函数是 f_att,,这是基于早期关注论文的正确结果,但是为了推广,我们可以将其改为 qX 向量之间的点积。这只是更有效地计算点积,但它创建了一个具有最终结果的乘积。正如你们所记得的,当计算两个向量的点积时,结果是这样的

当向量的维数很大时,这可能会导致问题。为什么会有问题?看下一步和 softmax 功能。这是一个很好的函数,但是当一个元素的值非常大,并且我们的值大小随着输入维度的增加而增加时,它会导致渐变消失的问题。这就是为什么你不仅仅使用点积,而是使用比例点积,这样我们的新公式看起来就像

如果你不理解为什么点积会产生一个高维向量的大数,请查看 3Blue1Brown 的Youtube 上关于这个主题的视频

此外,我们希望能够使用不止一个查询向量 q 。对于解码器的每个时间戳有一个单独的查询向量是很好的,但是当我们同时使用它们时会简单得多,所以我们将向量改为向量 Q (形状 NQ × DQ )。这也影响相似性得分和注意力的输出形状:

你可能想知道为什么 softmax 要计算在 dim=1 之上?这是因为我们希望获得每个查询向量在输入向量上的概率分布。您应该注意的另一件事是,相似性得分的计算简化为矩阵乘法。

图 17:注意力和自我注意力层层叠加,演职员表: 《注意力就是你所需要的一切》 乌米奇 插图变压器

注意
这只是原图的截图,不幸的是我不能在介质上包含部分应用程序。如果你想玩它请直接去这个链接

现在我们进入有趣的话题。图表的第一步是注意力的标准方法。我们只有我们的查询向量输入向量。我们使用输入两次,一次是在计算相似度时,第二次是在计算输出向量时。我们可能想以稍微不同的方式使用这些向量,这就是的想法的来源。

图 18:键和值分离,来源: 关注层图

你可能想知道这些向量是什么,为什么它们很重要?我在 stackexchange 上发现了查询/值/键的一般概念背后的一个直觉:

键/值/查询概念来自检索系统。比如你在 Youtube 上键入一个查询搜索某个视频,搜索引擎会将你的 查询 映射到一组 (视频标题、描述等)。)与数据库中的候选视频相关联,然后呈现给你最匹配的视频( )。

如果我们从可用性的角度来看,它们允许模型决定如何使用输入数据。通过创建可训练权重(WK 和 WV ),我们可以调整输入以适应不同的任务。

注意 刚好我所有的向量都有相同的长度,确切的形状要匹配(看描述中显示的形状),但不一定要一样。

这时我们的注意层准备好了!我们能做得更好吗?是啊!!!

自我关注层

图 19:自我关注层结构,来源: 关注层图

一直以来,当使用关注层时,我们创建单独的查询向量,这在自我关注方法中已经改变。这次我们添加了另一个权重矩阵(WQ ),它将用于计算新的查询向量。这样,我们就能让我们的模型自己学习输入向量的转换。

我们这里有所谓的自我关注层,这是一个通用层,你可以在你的模型中使用。它接受输入向量并输出输出向量。整个层是排列等变****

这意味着当你置换输入向量时,输出将是相同的,但被置换。

最后,我需要解释为什么我改变了颜色。原因是为了匹配图文并茂的变形金刚博文中使用的颜色。

图 19:自关注层矩阵计算,设计来自: 图示变压器

结论

从这一点开始,我们可以使用自我关注层来创建一个变压器,但是这篇文章已经太长了。你应该对注意力机制如何工作以及为什么工作有一个直觉。我将写另一篇关于设计变形金刚多头注意力的文章,但现在请参考图解变形金刚

Jay Alammar 很好地解释了变压器的工作原理,还有一个矢量计算的例子。我的文章试图解释关注和自我关注的概念是如何产生的,因为你们中的很多人是在阅读了那篇博客文章后来到这里的,所以我希望你们对色彩模式感到熟悉。

我希望你喜欢这些图表,如果你有任何问题,请随时提问。

参考资料:

最初发布于https://erdem . pl**

2021 年自动驾驶简介

原文:https://towardsdatascience.com/introduction-to-autonomous-driving-in-2021-7e0281c0d929?source=collection_archive---------23-----------------------

自动驾驶汽车目前面临哪些挑战?

从肉电脑到芯片电脑的转变。图片由作者启发而来[3]。

上个月,在 2011 年 CVPR 期间,自动驾驶(AD) 一些最热门的公司在 WAD(自动驾驶研讨会)上分享了他们对未来移动性的看法。IEEE 计算机视觉和模式识别会议(CVPR)是计算机视觉领域的三大学术会议之一(与 ECCV 和 ICCV 并列)。

今年,他们从自动驾驶领域最热门公司的 R&D 实验室中精心挑选了令人难以置信的主题演讲人: Waymo (谷歌)特斯拉丰田高级开发研究所(TRI-AD)英伟达英特尔极光WayveWaabiArgo

自动驾驶涉及解决各种挑战,如障碍物和自由空间检测、车道跟踪、传感器融合、驾驶员凝视监控、十字路口的运动规划、行人姿态和行为预测等。其中,CVPR 2021 在广告中突出了 2021 年的趋势。

我已经为你总结了自动驾驶汽车目前面临的最大挑战!

关键 1)端到端模式是王道

使用数据创建端到端模型。

国王模型。图片由 @ivanana 提供。

软件 2.0

特斯拉的 AI 高级总监安德烈·卡帕西(Andrej Karpathy)不断重申,软件行业应该走向软件 2.0

首先,什么是软件 1.0 和 2.0?

软件 1.0 代表经典栈:“它由程序员写给计算机的明确指令【1】。相比之下,软件 2.0 不遵循任何明确的配方或状态机。它使用优化来寻找哪种配方最适合实现其预期目标,而无需明确的指令。与人类类似,软件 2.0 接收数据和标签,并学习数据中的模式,以自行预测标签。

软件 2.0 基本上是人工智能推动的软件。

看 2021 年为 AD 发表的论文,很明显 2021 年是软件 2.0 年。

2021 年

传统顺序与 DL 端到端方法。图片由作者提供。

大多数 R&D 和行业报纸现在都在使用端到端模型。

亚历克斯·肯德尔( Wayve 首席执行官)写道,他的广告模式:“没有手写的规则。仅仅是纯粹的智力【5】。这是可能的,因为大多数最近的广告模型由一个联合感知、预测和运动规划模型组成。

输入仅仅是原始传感器测量(照相机、激光雷达、雷达),输出是方向盘控制命令。在中间层块之间可访问可解释的表示。

特斯拉

特斯拉专注于其模块化架构的灵活性。尽管是端到端的,但每个特斯拉人工智能工程师都可以在他们网络的一个特定模块上并行贡献/微调,而不会破坏联合网络的任何其他模块。

在实践中,所有传感器测量值都被转换为特征,然后被馈送到递归神经网络架构(transformer ),该架构随时间融合所有相机特征。一旦融合完成,他们就使用分支结构。多头网络被分成分支网络。每个分支输出一个期望的矢量,如轨迹检测等。

关键 2)传感器警告

自动驾驶汽车面临两大预测挑战:

  • 感知:理解环境和其他行动者。
  • 动作规划:通过该环境确定行动路线。

他们仍然很难决定哪些传感器最适合这项任务。

相机 VS 激光雷达。静止在运动中的形象(unsplash.com)

解决感知问题的经典方法是融合相机、激光雷达(激光),有时是雷达(微波)传感器。但是这些天,关于哪些传感器相关的争论正在激烈地进行着。

尤其是今年,一些公司宣布他们将不再使用激光或雷达,而只使用摄像机。

语境

2019 年 4 月 22 日特斯拉声称全自动驾驶既不需要激光雷达(光线探测和测距),也不需要高清地图就能成功【2】。埃隆·马斯克挑衅地说,使用激光雷达是一件“愚蠢的差事】、不必要的昂贵传感器”。虽然即使在遮挡、雨、雾和雪的情况下,激光雷达也能准确地进行 3D 检测,但它确实很贵。

汽车上的激光雷达。图像矢量点组成。

激光雷达优势:

  • 准确度和精确度
  • 生成 3D 图像和深度图。
  • 在能见度低的情况下(日落、有雾的情况下)也能看见
  • 立即给出深度,无需计算处理

激光雷达缺点:

  • 扩展成本高(谷歌 Waymo 专有系统约为 75,000 美元,而最近初创公司制造的激光雷达可能需要约 1000 美元)
  • 两辆自带激光雷达的车辆之间可能存在干扰和堵塞
  • 激光脉冲可能对环境和健康造成的危害。
  • 激光雷达无法读取标志或颜色。
  • 美学(在前置激光雷达的情况下可以隐藏)

2021 年

特斯拉在 2021 年 5 月的一份新声明中表示,从现在起他们将完全依靠视觉,在他们的汽车周围使用八个摄像头(这意味着他们也停止使用雷达)。他们有一个独特的人工智能团队:视觉团队。

从 2021 年 5 月开始交付,为北美市场制造的 Model 3 和 Model Y 车辆将不再配备雷达。—特斯拉官网【4】

当 AD(自动驾驶)正在摸索寻找硬件-软件的完美匹配时,特斯拉并不是唯一一家放弃地图融合传统方法的公司。斯巴鲁也在赌视觉系统。Wayve 的首席执行官兼联合创始人 Alex Kendall 强调“劳动密集型的高清地图和手工编码的规则很难适应新的复杂的驾驶领域”[7]。

为什么他们选择相机而不是激光雷达?

  • 比较便宜的
  • 雷达和照相机测量之间存在差异。
  • 可靠性:雷达有时会输出随机噪声测量值

他们得出结论,当雷达和视觉不一致时,他们应该相信视觉的准确性。

关键 3)感知和运动规划

我写了一篇技术文章,解释了模型如何学习预测其环境行为。

它需要计算机视觉和深度学习基础知识。

关键 4)数据为王

为了训练广告模型,你需要大量的数据。

你需要大量的图像记录!图片由 @konstandy 提供。

要训练端到端多任务多模态模型,您需要以下数据:

  • (百万视频)
  • 清洁(标注数据)
  • 多样(很多边缘案例)

最大的瓶颈是多样性。Cruise(广告初创公司)ML 工程师之一最近承认,穿着精心制作的万圣节服装的行人无法被识别,因为这些数据不存在于训练数据集中[7]。

舰队学习系统

特斯拉

特斯拉用自动贴标机对其车队私有数据的自动标签系统进行了升级。因为他们的预测没有时间限制(离线),他们可以使用高延迟集合模型、额外的传感器、跟踪、未来帧(后见之明)来从车队视频中获得准确的注释。他们手动开发了 221 个触发器,将在客户车队中激活。他们的模型部署在特斯拉汽车中,目前在当前的特斯拉汽车中以阴影模式运行。例如,当摄像头和雷达不匹配时,当用户决策和模型控制预测相差太大时,会向 Tesla 发送一个触发器来分析数据,自动标记它们并将其用于训练(闭环 AI)。

英伟达

为了挖掘他们庞大的数据集, NVIDIA 使用集成模型来预测标签及其不确定性。不确定性由不同网络之间的不一致来量化。当不确定性高时,图像在训练数据中被上采样[5]。

使用模拟

模拟驾驶。图片由 @samuele_piccarini

为了加速 AV 开发和访问大规模验证, NVIDIA 正在使用模拟。他们将模拟用于:

  • 感觉
  • 规划和控制
  • 完整的 AV 堆栈
  • 检查驾驶体验

…在各种情况下。

他们使用他们的 NVIDIA Omniverse 模拟器进行精确渲染。当他们在现实世界中的预测失败时,他们狡猾地使用他们的模拟器。当它发生时,他们在模拟器中生成类似事件的多个场景,并重新训练他们的模型。

Waadi 使用 LidarSim (CVPR 2020)模拟激光雷达原始数据和周围驾驶员真实行为的任意场景。

从哪里获取语义标签? TRI-AD 提供答案:在模拟中!他们大量使用模拟来生成他们的语义标签。他们努力缩小模拟和真实世界数据之间的领域差距[11]。他们的模型将模拟和真实世界的数据都作为输入。然后,他们可以学习如何提取这两个空间中的共同数据特征。在这种情况下,真实世界的数据标签是自我监督的,而模拟数据当然是由模拟器标记的。

开源数据集

你可以免费使用几个开源数据集(Lyft、NuScenes、Waymo 开放数据集、Argoverse、TRI-AD 的 DDAD)。它们本质上是用来衡量每篇新研究论文的准确性。创建生产级别的系统将是低效的:例如,特斯拉在发布他们的模型时使用了 1.5 的训练数据。

关键 5)人工智能安全问题:

在与生死相关的人工智能系统中,很多意识正在上升:医疗保健、军事、移动等。

当这些技术出错时,它们可能会杀死某个人。因此,系统的安全性和稳定性至关重要。恶意设计的数据或模式可以用来欺骗 AI 系统。我们把这些欺骗的附加称为“对抗性攻击”。

到目前为止,AVs 还远非万无一失。一些研究人员已经表明,地面上的一些小贴纸可能会导致自动驾驶汽车驶入对面的车道[8]。

对车辆感知障碍的敌对攻击示例如下所示,其中所有图像都被错误分类为“限速 45”。

贴纸和遮挡导致将停车标志误归类为限速标志。文献[6]的结果。图片由作者提供。

该模型无法识别许多不同配置(遮挡、贴纸等)的停车标志,而人类可以清楚地看到它。如果机器检测到限速而不是停车标志,后果可能很可怕。

来自安全学习实验室(伊利诺伊州)【10】的李博对当前 AD 系统的弱点提出了警告:如果 AD 仅依赖于数据(如在端到端系统中),它将更容易受到潜在的敌对攻击。

可能的解决方案:

  • 不同传感器的融合是解决方案之一。很难在同时攻击每个传感器的同时保持它们之间的逻辑关系。
  • 不同模型的融合(集合模型)
  • ML 鲁棒性增强及其认证(参见认证鲁棒性排行榜
  • 构建识别攻击的系统。[9]
  • 另一种方法是停止纯粹的数据驱动的端到端管道,并向 ML 管道添加一些知识领域。例如,添加以检查停车标志是否为写有“STOP”的八角形。)

结论

自动驾驶是一个非常令人兴奋的领域。行业将部署和研究与部分开源资源联系起来。我们可以欣赏社区为构建移动未来所做的独特努力。广告不缺乏挑战,最好的还在后面!

当前挑战

  • 泛化(在训练空间之外创建健壮的模型)
  • 适应性(针对不同的汽车、不断变化的地点、传感器配置、用例、道路政策)
  • 世界建模和缩放(理解复杂、动态的世界,联合预测)
  • 不确定性(什么不确定性小到我的模型是安全的?)
  • 可解释性(有哪些因果因素)
  • 应对路上很少发生的疯狂事件的长尾。
  • 互动(我应该在其他车辆移动之前移动还是等待?).
  • 计算能力(监控共“感知”车外所见,“测绘”车在何处,“规划”汽车运动,“内部传感”监控司机)。
  • 安全

感谢您的阅读!

中上关注我 推特 !😃

参考

[1]https://karpathy.medium.com/software-2-0-a64152b37c35

[2]https://TechCrunch . com/2019/04/22/任何依赖激光雷达的人都注定要失败——埃隆-马斯克-赛义德/

https://www.youtube.com/watch?v=g6bOwQdCJrc 安德烈·卡帕西·CVPR 2021ab _ channel = WADatCVPR

[4]https://www.tesla.com/support/transitioning-tesla-vision

[5]https://youtu.be/eOL_rCK59ZI CVPR WAD 2021

[6]对深度学习模型的强大物理世界攻击,https://arxiv.org/pdf/1707.08945.pdf CVPR 2018

[7]https://towards data science . com/自驾-汽车-过去-现在-未来-71532430346

[8]https://keen lab . Tencent . com/en/whites/Experimental _ Security _ Research _ of _ Tesla _ auto pilot . pdf

[9]https://venturebeat . com/2020/02/24/Google-ai-detects-adversarial-attack-against-image-classifiers/

https://secure-ai.github.io/

【11】语义分割的几何无监督域自适应https://arxiv.org/abs/2103.16694熊伟·圭齐利尼等人

BanditPAM 简介

原文:https://towardsdatascience.com/introduction-to-banditpam-1217ee457927?source=collection_archive---------14-----------------------

实践教程

如何将多臂土匪问题与聚类算法联系起来

照片由克里斯塔普斯·格伦德斯坦斯Unsplash 上拍摄

介绍会;展示会

BanditPAM 是一种聚类算法,它的名字没有它著名的兄弟 KMeans 那么令人回味。它属于 KMedoids 算法家族,并在 2020 年 NeurIPS 大会上发表(论文链接)
在深入细节之前,让我们先解释一下与 KMeans 的区别。

主要区别来自于“手段”“水母”但结构是一样的。

作者图片

如图所示,KMeans 通过最小化到同一个簇中每个点的欧几里德距离来定位其簇的中心(即其质心)。因此,它是其簇中的点的平均值 ( K 表示)。在其一侧,KMedoids 将其群集的中心定位在数据集的一个点上,从而最小化与同一群集的其他点的距离。我们称这些中心为水母

换句话说,每个 KMedoids 聚类的中心必然是数据集中存在的点(与 K-Means 相反)

那又怎样?

在一些问题中,考虑 medoids 允许对结果有更好的理解和可解释性,以及对所谓的“结构化”对象(通常是数据表)的聚类的改进

为什么现在?

KMeans 一直主导着聚类算法的主题,因为它的操作简单,尤其是因为它的低复杂度。事实上,KMeans 的复杂度通常是线性的,取决于数据集中的点数 n、聚类数 k 和维度数。对于类水母来说,这是一个不同的故事,因为即使是被称为 PAM (用于围绕类水母进行分区)的最新技术也具有二次复杂度

正是在这一点上,该研究论文通过实现 BanditPAM 而闻名,根据该研究论文,这是 PAM 从二次复杂度到“准线性”复杂度的改进(精确到 O[nlog(n)]

BanditPAM 基于 2 算法:

  • PAM —围绕水母分区
  • 多臂土匪

围绕 Medoids(或 PAM)的分区

1。演示文稿 与所有聚类算法一样,PAM 的目标是获得所执行的聚类的最佳质量。

通过注意 d(。, .)距离度量(欧几里德距离、余弦相似度……)和在 medoids** 的集合中,这个质量是通过这个成本函数获得的:**

作者图片

换句话说,PAM 的目标是找到一组kme doid,允许最小化点到其最近的 medoid 的距离。

该算法基于与 KMeans 相当的 2 步。

2。构建(初始化阶段)

在这个阶段,PAM 根据特定的规则初始化它的 k medoids。

在已经初始化了 N 个点L 个 medoids的情况下,我们根据以下关系找到下一个 medoidsm *:

作者图片

让我们通过一个例子来说明这个步骤:

作者图片

让我们考虑 6 点(A、B、C、D、E、F),让我们试着根据上面定义的构建步骤来定义 2 medoids

对于这个例子,我们将两点之间的距离定义为欧几里德距离的平方。****

作者图片

因此,我们获得这个距离矩阵,其中所有进一步的计算都将参考这个矩阵

1.a 定义第一个 medoid

因为它是我们希望计算的第一个 medoid,所以我们得到下面的关系:

作者图片

这里我们注意到关系是不同的,因为不存在最小值。这是因为在这个阶段集合 M** 是空的,因此第二个最小值没有被定义。**

1.b 定义第二个 medoid

这一步可能更难理解,因为我们使用的是整体关系:

作者图片

再次取矩阵,我们得到以下结果:

作者图片

由于我们已经将自己设置为 2 medoids ,初始化步骤是超过。已经选择了 a 和 C,并且成本函数** n 是:**

作者图片

我们已经按照预期定义了 2 个 medoids,因此初始化已经完成。让我们进入交换阶段——优化阶段。****

2。SWAP(优化阶段)

再次意图最小化目标函数,该步骤试图用非 medoids** 交换一些 medoids。换句话说,一个 medoid 成为一个“正常”点,一个“正常”点成为一个 medoid。“正常”点是指而不是med oid 的点。在所有可能的配对中,选定的配对遵循以下关系:**

作者图片

一旦 m和 x找到,x就变成了一个 medoid,m又变成了一个“正常”点。

作者图片

提醒一下,我们有这个距离矩阵,但是现在有了 A 和 C** ,两个初始化的 medoids。**

通过应用上面的交换关系,我们得到:

作者图片

在这种情况下,最小值是 medoid A 和点 d 之间的连接。****

当且仅当以 A 和 D 为中间点的成本函数低于以 A 和 c 计算的成本函数时,A 成为非中间点,D 成为中间点。****

但是在这里:

作者图片

当 39 > 23 时,A 和 D 不反转,假设收敛。算法停止。

如果值小于 23 ,我们将反转 A & D,交换过程将重复进行,直到收敛(即成本函数不再降低)

3。问题

在具有 n 个点和 k 个 medoids 的更一般的例子中,复杂度是二次

为什么会这样?

构建步骤中,对于的每一个 medoid** ,我们感兴趣的是的 n 个点中的每一个。对每个点,进行 n 次求和(见构建关系)。因此,复杂度是 n*n ,因此是二次的。现实中既然有 k 个 medoids,复杂度为 O(knn) 。**

同样的推理也适用于互换。

因此,该算法的一般复杂度是的二次方

为了克服这个问题,BanditPAM 使用多臂 Bandit** 算法将复杂度从二次改为 n*log(n) 。**

多臂土匪(或 MAB)

多臂强盗是一个涉及两难境地的问题:探索与开发。有必要简要解释一下这种困境。

1。问题的背景

让我们想象一下 Pierre ,一个年轻的工人和他的父母在巴黎生活了一年。不幸的是,皮埃尔并不擅长烹饪,他习惯于独自在家时外出就餐。到了选择的时候,彼得总是面临同样的困境:“我是回到已经让我满意的餐馆,还是冒险尝试一家新餐馆?

这个问题说明了多臂土匪:

几个行动是可能的(餐馆),每个行动提供一个奖励(对食物、风格、服务的满意程度…),可以是正面的,也可以是负面的。然而,对同一行为的回报不是恒定的,例如,如果彼得在两个不同的时间去餐馆,他可能一次喜欢它,另一次讨厌它。

2。可能的策略

那么采取什么样的策略才是最好的呢?

  • 继续执行给予最佳奖励的相同动作
  • 冒着不断选择新行动的风险,希望这些行动能提供比以前更好的回报?

第一种策略叫做剥削。一个人利用一个行动,却不知道其他行动的回报。如果彼得遵循这个策略,他会选择他最喜欢的餐馆(即有最好回报的餐馆)并坚持下去,而不会去其他地方吃饭…

另一种策略叫做探索。这包括始终探索其他行动,以获取尽可能多的信息,最终选择最佳行动。

3。现有算法

幸运的是,这个问题已经有了解决方案。

ε贪婪算法在于以概率ε探索可能的动作。如果是这种情况,探索是随机进行的。否则,选择最佳动作。

如果彼得在选择他的餐馆时遵循这种“ε-贪婪”策略,他有随机选择新餐馆的概率ε(例如 0.05 或 5%)。因此,他有 95%的机会回到他最喜欢的餐馆。

有了多臂大盗,这种探索不是随机的而是被认为更聪明。具体来说,在每一步,所选择的行动都是由一种称为 UCB 的算法来决定置信上限
(请注意,除了研究论文中提到的 UCB 之外,还有其他算法)

4。UCB 概述

随机探索的问题是,有可能遇到你在之前已经遇到过的坏行为。****

提醒一下,每家餐厅的奖励不是固定值,而是取决于给定时刻的。通过包含评级的概念,Peter 可能会去一家他已经欣赏到 5 颗中的 4 颗星的餐厅吃饭,但是一个月后他的第二次尝试以 5 颗中的 1 颗星结束。因此,这种类型的餐厅具有高度的不确定性,不像其他餐厅,Pierre 每次光顾都以大致相同的“分数”结束。

UCB 的算法是偏好非常不确定的动作。否则,避免具有一致奖励历史的动作。目标是支持探索更有潜力获得最佳回报的行动。****

与彼得的情况类似,如果他遵循 UCB 策略,他会选择一家在不同的访问中他的评价非常不同的餐馆。因此,如果他已经去过一个餐馆四次,并且评级总是相对相同,那么第五次,这个餐馆不太可能成为最好的。****

在选择第 t 家餐馆时,选择尊重以下关系:

作者图片

作者图片

换句话说,选择的行动是最大化行动和第二项 u 的回报历史平均值的行动。

很简单,相同的动作执行得越多,Nt(a)增加得越多,因此 Ut(a)减少。动作“a”不太可能被选中。

在彼得的例子中,他选择同一家餐馆越多,Nt(a)越高,Q + U 项减少越多,选择该行动的可能性越小。

Bandit + PAM = BanditPAM

PAM 算法中多臂 Bandit 的存在允许我们从计算问题转移到统计问题。

事实上,MAB 可以很容易地插入到交换和构建步骤中。

对于交换步骤,类比如下:

  • 简单地考虑一个 medoid/non-medoid 对作为一个可能的动作,并且相关的奖励是要最小化的成本函数的值。代价函数越接近 0 ,奖励越高。

因此,PAM 避免计算所有可能的对(n(n-k)),而是通过 PAM 算法选择最佳对。这样一来,复杂度就变成了 **nlog(n)。****

对于构建步骤,类比如下:

  • 每个可能的候选者是一个动作,回报是交换步骤的成本函数的计算,但仅针对数据的随机样本。这允许对于测试的同一候选人,按照 PAM 算法,奖励的值是不同的****

BanditPAM 的使用是通过 Python 实现的。
GitHub举例:https://github.com/ThrunGroup/BanditPAM/

结论

对 BanditPAM 的介绍让我们可以独立地观察两种算法。在 KMedoids 算法中加入统计模型(PAM)提高了复杂度,同时保持了相对较好的聚类质量。

在研究论文中提供了更多关于如何将多臂强盗纳入 PAM 的细节。这种处理不是很明显,我邀请所有好奇的人来看看原始文件。

感谢您阅读我的第一篇文章,如果您喜欢,请随时支持、评论和分享。

来源

基本 Excel R 工具包(BERT)简介

原文:https://towardsdatascience.com/introduction-to-basic-excel-r-toolkit-bert-de44f309e3d2?source=collection_archive---------21-----------------------

使用 BERT 插件向 Excel 用户开放过多的 R 功能。

卢卡斯·布拉塞克在 Unsplash 上的照片

过去三十年来,xcel 一直是企业首选的数据分析工具。Excel 提供内置工具来进行统计分析、创建预算、预测、仪表板、数据绘图等。然后还有插件来填补分析空白或提高性能。

对我来说,Excel 是一个很好的工具,但我在使用它时有两个问题:第一,当处理大型数据文件(> 50MB)时,Excel 偶尔会死机;第二,生成的默认图质量很差,需要大量的润色。这些就是过渡到 MATLAB(授权软件)和 R(开源)的原因。

我在这里不是要说服人们离开 Excel 并过渡到 R 或任何编程语言,而是要为那些 Excel 用户提供一个利用 基本 Excel R 工具包(BERT) 插件的解决方案。正如数据科学专业圈子里流行的说法:

数据科学的关键是利用不同的工具来解决问题,而不是掌握一种工具。

伯特是什么?

Basic Excel R Toolkit 或 BERT 是一个插件,用于运行 Excel 电子表格单元格中的内置 R 函数。伯特自由了!BERT 提供了两个特性:

  1. Excel 的用户自定义 R 函数:用户可以在 R 中定义自己的函数,BERT 会将这些函数转换成 Excel 函数。
  2. 从 R 控制 Excel:用户可以使用 R 与 Excel 电子表格实时交互。

BERT 的另一个优点是它与 VBA 兼容。

安装 BERT

因此,要开始,首先我们需要安装插件。文件可以从这里下载。BERT 的 当前限制 是,它只适用于 2003 年以后的 Excel 版本的 Windows 用户和 64 位 Windows。

安装完成后,BERT 插件将出现在 Excel 的 Add-ins 选项卡中,BERT 控制台将打开。如果控制台没有打开,则单击加载项中的控制台选项打开 BERT 控制台。

作者图片

BERT 控制台由两部分组成。左半部分是带有三个打开标签的编辑器,右半部分是 R 控制台。

作者图片

BERT 控制台上的选项卡“ excel-scripting.r ”用于与 excel 实时交互。您可以尝试运行 excel-scripting.r 选项卡上的命令,方法是选择代码块并按下 F9 来执行,或者使用 Ctrl+Shift+F9 来执行完整的代码。

只有在同名的工作表不存在的情况下,从该选项卡运行整个代码块才会在 Excel 中创建名为“R data set”的新工作表。有关这方面的更多详细信息,请参见此处提供的文档。

我对第二个选项卡“ functions.r ”很感兴趣,我将尝试详细说明我们可以利用的不同功能。

在 Excel 中使用 R 函数

BERT 有一种预定义的编写函数的方式,类似于 r。

function_name <- function(arg1,arg2,...){
...
}

安装 BERT 时定义了两个默认函数。它们是实测值和特征值。这些函数可作为 R.function_name 访问。因此,在 Excel 中,可以通过输入 R.TestAdd 和 R .特征值来访问它们。

要访问这些功能,我们先按下 Shift+F3 打开插入功能对话框。从类别的下拉菜单中选择 导出 R 功能

书写功能

现在我们对如何加载 R 函数有了一个大致的概念,所以让我们获得一些实践经验。

这里我将基于一些基本的 R 函数来定义函数,创建图的函数,以及线性回归的函数。编写完函数后,将其保存为默认设置,以便在 Excel 中使用。

基本 R 函数: 这里我定义了四个函数使用 R %in%运算符,使用 rbind()或 cbind()函数组合向量,通过组合 2 个向量创建一个数据帧。更多预定义功能可在这里找到。

# matching vectors using %in%
match <- function(vec1,vec2){
vec1 %in% vec2
} # combine 2 matrices wrt rows
row_combine <- function(mat1, mat2){
rbind(mat1,mat2)
} # combine 2 matrices wrt columns
col_combine <- function(mat1, mat2){
cbind(mat1,mat2)
}# create data frame
data.frame <- function(x,y){
as.data.frame(cbind(x,y))
}

作者图片

R 的基绘图: 接下来,我定义了一个函数来使用 R 的基绘图,这里是为绘制直方图和散点图定义的两个函数。

绘制直方图的代码:

graph.histogram <- function(data, main="Histogram", xlabel="Data"){# passing cell=T means "use the cell address as a unique
# identifier". otherwise, use the name parameter to identify
# the target shape.BERT.graphics.device(cell=T);# scrub the data (slightly) then generate a histogramx <- unlist( as.numeric( data ));hist( x, xlab=xlabel, main=main, col="pink", breaks=13, font.main=1);# we're done with the graphics device; we can shut it off.
# this isn't strictly necessary, but there's a limit of 63
# active devices so it's a good idea.dev.off();# returning TRUE indicates everything succeeded.
T}

绘制散点图的代码:

graph.scatter <- function(x,y,main="Scatter plot"){BERT.graphics.device(cell=T);plot(x,y)dev.off();
}

作者图片

这些函数的有趣之处在于,输入值的变化会实时反映在图中。除此之外,图的质量远远优于 Excel 的默认图,如下图所示。

安装包: 这里出于演示的目的,我使用了内置函数 draw.map()。该函数绘制世界地图,为此,它需要 地图包

draw.map <- function( countries, values, title ){
library(maps);
BERT.graphics.device(cell=T);# allow nulls in countries; map to values and ensure zeros.
c2 <- unlist(countries[!is.na(countries)]);
values <- as.numeric(values);
values[is.na(values)] <- 0;
v2 <- unlist(values[!is.na(countries)]);# for colors, reduce to a color space of 32 (?) levels. scale values.
n <- 32;
scaled.values <- round((1-((v2-min(v2))/(max(v2) - min(v2))))*(n-1))+1;
heatcolors <- heat.colors(n);
margins = c(0, 0, 0, 0);if( !missing(title)){ margins[3] <- .6; }# fill doesn't work properly (or at least as one would expect)
# when a country has multiple polygons, so do this in separate passes...
# 1: space out the map
par(mai=margins);
map("world", c2, fill=F, lty=0);# 2: fill in countries
sapply( c2, function(country){
map( "world", country, fill=T, lty=0, add=T,
col=heatcolors[scaled.values[[which(c2==country)]]] );
});# 3: draw lines on top
map("world", c2, fill=F, col="#cccccc", add=T );# add title
if(!missing(title)){ title( main=title, font.main=1 ); }dev.off();T;}

要在 BERT 中安装软件包,我们必须在 BERT 控制台上选择 Packages 选项卡-> Install packages。

作者图片

这将提示你选择克兰镜

作者图片

之后,您可以选择要安装的软件包。

作者图片

软件包安装完成后,定义的函数就可以使用了。

作者图片

结束语

BERT 是一个非常强大的插件,可以使 Excel 用户社区受益。上述演示清楚地强调了一个事实,即大多数 R 功能(只有 CRAN 包可用)即使不是全部都可以通过 BERT 获得。

我认为使用 BERT 的主要优势是:

  1. R 函数的清晰兼容性
  2. 易于定制或构建您自己的功能
  3. 优质地块
  4. 反映在图中的实时变化

伯特的缺点是:

  1. 绘图中的更改不会像默认 Excel 绘图那样反映在 PowerPoint 中。

除了上面提到的缺点,我目前不明白为什么 BERT 不能成为一个好的工具。

如果你是一个 Excel 用户,那么试试 BERT,看看它是否能给你的工作增加价值。

参考:

  1. https://bert-toolkit.com/

您可以在 LinkedInTwitter 上与我联系,跟随我的数据科学和数据可视化之旅。

posted @ 2024-10-18 09:27  绝不原创的飞龙  阅读(334)  评论(0)    收藏  举报